Пример #1
0
IDriverDependantBitmap* prepare_screen_for_transition_in()
{
    if (saved_viewport_bitmap == NULL)
        quit("Crossfade: buffer is null attempting transition");

    saved_viewport_bitmap = ReplaceBitmapWithSupportedFormat(saved_viewport_bitmap);
    const Rect &viewport = play.GetMainViewport();
    if (saved_viewport_bitmap->GetHeight() < viewport.GetHeight())
    {
        Bitmap *enlargedBuffer = BitmapHelper::CreateBitmap(saved_viewport_bitmap->GetWidth(), viewport.GetHeight(), saved_viewport_bitmap->GetColorDepth());
        enlargedBuffer->Blit(saved_viewport_bitmap, 0, 0, 0, (viewport.GetHeight() - saved_viewport_bitmap->GetHeight()) / 2, saved_viewport_bitmap->GetWidth(), saved_viewport_bitmap->GetHeight());
        delete saved_viewport_bitmap;
        saved_viewport_bitmap = enlargedBuffer;
    }
    else if (saved_viewport_bitmap->GetHeight() > viewport.GetHeight())
    {
        Bitmap *clippedBuffer = BitmapHelper::CreateBitmap(saved_viewport_bitmap->GetWidth(), viewport.GetHeight(), saved_viewport_bitmap->GetColorDepth());
        clippedBuffer->Blit(saved_viewport_bitmap, 0, (saved_viewport_bitmap->GetHeight() - viewport.GetHeight()) / 2, 0, 0, saved_viewport_bitmap->GetWidth(), saved_viewport_bitmap->GetHeight());
        delete saved_viewport_bitmap;
        saved_viewport_bitmap = clippedBuffer;
    }
    saved_viewport_bitmap->Acquire();
    IDriverDependantBitmap *ddb = gfxDriver->CreateDDBFromBitmap(saved_viewport_bitmap, false);
    return ddb;
}
Пример #2
0
// a simple function that applies a blur effect on a bitmap
//  - Bitmap &bmp: the input bitmap
//  - int radius:  blur radius
void MAS::Cursor::Blur(Bitmap &bmp, int radius) {
   int x, y;
   int i, j;
   int r,g,b;
   
   int div = (2*radius+1)*(2*radius+1);

   Bitmap tmp2(bmp.w(), bmp.h(), Bitmap::MEMORY);
   tmp2.Clear(Color::transparent);
   bmp.Blit(tmp2, 0, 0, 0, 0, bmp.w(), bmp.h());

   Bitmap tmp(Size(bmp.w() + 2*radius, bmp.h() + 2*radius), Bitmap::MEMORY);
   tmp.Clear(Color::black);
   bmp.Blit(tmp, Point(0,0), Point(radius, radius), bmp.size());

   for (y=radius; y<tmp.h()-radius; y++) {
      for (x=radius; x<tmp.w()-radius; x++) {
         r = g = b = 0;
         for (j=-radius; j<=radius; j++) {
            for (i=-radius; i<=radius; i++) {
               Color col = tmp.Getpixel(Point(x+i, y+j));
               r += col.r();
               g += col.g();
               b += col.b();
            }
         }
         
         tmp2.Putpixel(Point(x-radius, y-radius), Color(r/div, g/div, b/div));
      }
   }

   bmp.Clear();
   tmp2.Blit(bmp, 0, 0, 0, 0, bmp.w(), bmp.h());
}
Пример #3
0
void show_preload () {
    // ** Do the preload graphic if available
    color temppal[256];
	Bitmap *splashsc = BitmapHelper::CreateRawObjectOwner( load_pcx("preload.pcx",temppal) );
    if (splashsc != NULL) {
        if (splashsc->GetColorDepth() == 8)
            wsetpalette(0,255,temppal);
		Bitmap *screen_bmp = BitmapHelper::GetScreenBitmap();
        Bitmap *tsc = BitmapHelper::CreateBitmap(splashsc->GetWidth(),splashsc->GetHeight(),screen_bmp->GetColorDepth());
        tsc->Blit(splashsc,0,0,0,0,tsc->GetWidth(),tsc->GetHeight());
		screen_bmp->Clear();
        screen_bmp->StretchBlt(tsc, RectWH(0, 0, scrnwid,scrnhit), Common::kBitmap_Transparency);

        gfxDriver->ClearDrawList();

        if (!gfxDriver->UsesMemoryBackBuffer())
        {
            IDriverDependantBitmap *ddb = gfxDriver->CreateDDBFromBitmap(screen_bmp, false, true);
            gfxDriver->DrawSprite(0, 0, ddb);
            render_to_screen(screen_bmp, 0, 0);
            gfxDriver->DestroyDDB(ddb);
        }
        else
			render_to_screen(screen_bmp, 0, 0);

        delete splashsc;
        delete tsc;
        platform->Delay(500);
    }
}
Пример #4
0
void DrawingSurface_DrawSurface(ScriptDrawingSurface* target, ScriptDrawingSurface* source, int translev) {
    if ((translev < 0) || (translev > 99))
        quit("!DrawingSurface.DrawSurface: invalid parameter (transparency must be 0-99)");

    Bitmap *ds = target->StartDrawing();
    Bitmap *surfaceToDraw = source->GetBitmapSurface();

    if (surfaceToDraw == target->GetBitmapSurface())
        quit("!DrawingSurface.DrawSurface: cannot draw surface onto itself");

    if (translev == 0) {
        // just draw it over the top, no transparency
        ds->Blit(surfaceToDraw, 0, 0, 0, 0, surfaceToDraw->GetWidth(), surfaceToDraw->GetHeight());
        target->FinishedDrawing();
        return;
    }

    if (surfaceToDraw->GetColorDepth() <= 8)
        quit("!DrawingSurface.DrawSurface: 256-colour surfaces cannot be drawn transparently");

    // Draw it transparently
    GfxUtil::DrawSpriteWithTransparency(ds, surfaceToDraw, 0, 0,
        GfxDef::Trans100ToAlpha255(translev));
    target->FinishedDrawing();
}
Пример #5
0
ScriptDynamicSprite* DynamicSprite_CreateFromDrawingSurface(ScriptDrawingSurface *sds, int x, int y, int width, int height) 
{
    int gotSlot = spriteset.findFreeSlot();
    if (gotSlot <= 0)
        return NULL;

    // use DrawingSurface resolution
    sds->MultiplyCoordinates(&x, &y);
    sds->MultiplyCoordinates(&width, &height);

    Bitmap *ds = sds->StartDrawing();

    if ((x < 0) || (y < 0) || (x + width > ds->GetWidth()) || (y + height > ds->GetHeight()))
        quit("!DynamicSprite.CreateFromDrawingSurface: requested area is outside the surface");

    int colDepth = ds->GetColorDepth();

    Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, colDepth);
    if (newPic == NULL)
        return NULL;

    newPic->Blit(ds, x, y, 0, 0, width, height);

    sds->FinishedDrawingReadOnly();

    add_dynamic_sprite(gotSlot, newPic, (sds->hasAlphaChannel != 0));
    ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(gotSlot);
    return new_spr;
}
Пример #6
0
// RawRestoreScreen: copy backup bitmap back to screen; we
// deliberately don't free the Bitmap *cos they can multiple restore
// and it gets freed on room exit anyway
void RawRestoreScreen() {
    if (raw_saved_screen == NULL) {
        debug_log("RawRestoreScreen: unable to restore, since the screen hasn't been saved previously.");
        return;
    }
    Bitmap *deston = thisroom.ebscene[play.bg_frame];
    deston->Blit(raw_saved_screen, 0, 0, 0, 0, deston->GetWidth(), deston->GetHeight());
    invalidate_screen();
    mark_current_background_dirty();
}
Пример #7
0
void polygonLoop( Bitmap& pointer )
{

	LineStrip polygon;
	Line line( 0,0,0,0 );

	global_pressed = false;
	global_released = false;

	bool drawing = false;

	while( !keypressed())
	{

		Canvas::Fill( Rgba::BLACK );

		polygon.Draw( Rgba::WHITE );
		if( drawing )
		{
			line.end = Vec2D( mouse_x, mouse_y );
			line.Draw( Rgba::WHITE );
		}
		pointer.Blit( mouse_x, mouse_y );
		Canvas::Refresh();


		if( global_pressed )
		{
			if( !polygon.GetNumOfVertices())
				polygon.AddToEnd( Vec2D( mouse_x, mouse_y ));
			line.start = polygon.GetVertex( polygon.GetNumOfVertices() - 1 );
			global_pressed = false;
			drawing = true;
		}

		if( global_released )
		{
			polygon.AddToEnd( Vec2D( mouse_x, mouse_y ));
			global_released = false;
			drawing = false;
		}






		rest(1);
	}


}
Пример #8
0
IDriverDependantBitmap* prepare_screen_for_transition_in()
{
    if (temp_virtual == NULL)
        quit("Crossfade: buffer is null attempting transition");

    temp_virtual = gfxDriver->ConvertBitmapToSupportedColourDepth(temp_virtual);
    if (temp_virtual->GetHeight() < scrnhit)
    {
        Bitmap *enlargedBuffer = BitmapHelper::CreateBitmap(temp_virtual->GetWidth(), scrnhit, temp_virtual->GetColorDepth());
        enlargedBuffer->Blit(temp_virtual, 0, 0, 0, (scrnhit - temp_virtual->GetHeight()) / 2, temp_virtual->GetWidth(), temp_virtual->GetHeight());
        delete temp_virtual;
        temp_virtual = enlargedBuffer;
    }
    else if (temp_virtual->GetHeight() > scrnhit)
    {
        Bitmap *clippedBuffer = BitmapHelper::CreateBitmap(temp_virtual->GetWidth(), scrnhit, temp_virtual->GetColorDepth());
        clippedBuffer->Blit(temp_virtual, 0, (temp_virtual->GetHeight() - scrnhit) / 2, 0, 0, temp_virtual->GetWidth(), temp_virtual->GetHeight());
        delete temp_virtual;
        temp_virtual = clippedBuffer;
    }
    temp_virtual->Acquire();
    IDriverDependantBitmap *ddb = gfxDriver->CreateDDBFromBitmap(temp_virtual, false);
    return ddb;
}
Пример #9
0
IDriverDependantBitmap* prepare_screen_for_transition_in()
{
    if (temp_virtual == NULL)
        quit("Crossfade: buffer is null attempting transition");

    temp_virtual = ReplaceBitmapWithSupportedFormat(temp_virtual);
    if (temp_virtual->GetHeight() < play.viewport.GetHeight())
    {
        Bitmap *enlargedBuffer = BitmapHelper::CreateBitmap(temp_virtual->GetWidth(), play.viewport.GetHeight(), temp_virtual->GetColorDepth());
        enlargedBuffer->Blit(temp_virtual, 0, 0, 0, (play.viewport.GetHeight() - temp_virtual->GetHeight()) / 2, temp_virtual->GetWidth(), temp_virtual->GetHeight());
        delete temp_virtual;
        temp_virtual = enlargedBuffer;
    }
    else if (temp_virtual->GetHeight() > play.viewport.GetHeight())
    {
        Bitmap *clippedBuffer = BitmapHelper::CreateBitmap(temp_virtual->GetWidth(), play.viewport.GetHeight(), temp_virtual->GetColorDepth());
        clippedBuffer->Blit(temp_virtual, 0, (temp_virtual->GetHeight() - play.viewport.GetHeight()) / 2, 0, 0, temp_virtual->GetWidth(), temp_virtual->GetHeight());
        delete temp_virtual;
        temp_virtual = clippedBuffer;
    }
    temp_virtual->Acquire();
    IDriverDependantBitmap *ddb = gfxDriver->CreateDDBFromBitmap(temp_virtual, false);
    return ddb;
}
Пример #10
0
// creates a cursor shadow from a cursor bitmap
void MAS::Cursor::MakeShadow() {
   int x, y, i;

   Point pOffset(PADDING, PADDING);
   Point pOrigin(0,0);
   for (i=0; i<frameCount; i++) {
      Bitmap bmp;

      if (MAS::Settings::mouseShadow) {
         bmp.Create(Size(sprite[i]->w() + 2*PADDING, sprite[i]->h() + 2*PADDING), Bitmap::MEMORY);
      
         // create the alpha channel for the shadow by masking the cursor and bluring the results
         Bitmap alpha(bmp.size(), Bitmap::MEMORY);
         alpha.Clear(Color::transparent);
         sprite[i]->Blit(alpha, pOrigin, pOffset, sprite[i]->size());

         for (y=0; y<bmp.h(); y++) {
            for (x=0; x<bmp.w(); x++) {
               Point p(x,y);
               if (alpha.Getpixel(p) == Color::transparent)
                  alpha.Putpixel(p, Color::black);
               else
                  alpha.Putpixel(p, Color::white);
            }
         }

         Blur(alpha, PADDING);

         // write the alpha channel to the shadow bitmap
         for (y=0; y<bmp.h(); y++) {
            for (x=0; x<bmp.w(); x++) {
               Point p(x,y);
               bmp.Putpixel(p, Color(shadowColor.r(), shadowColor.g(), shadowColor.b(), alpha.Getpixel(p).r()));
            }
         }
      
         alpha.Destroy();
      }
      else {
         bmp.Create(1, 1);
         bmp.Putpixel(0, 0, Color::transparent);
      }

      Bitmap *result = new Bitmap(bmp.w(), bmp.h());
	  bmp.Blit(*result, 0, 0, 0, 0, bmp.w(), bmp.h());
      shadow.push_back(result);
   }
}
Пример #11
0
void DynamicSprite_ChangeCanvasSize(ScriptDynamicSprite *sds, int width, int height, int x, int y) 
{
    if (sds->slot == 0)
        quit("!DynamicSprite.ChangeCanvasSize: sprite has been deleted");
    if ((width < 1) || (height < 1))
        quit("!DynamicSprite.ChangeCanvasSize: new size is too small");

    multiply_up_coordinates(&x, &y);
    multiply_up_coordinates(&width, &height);

    Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
    // blit it into the enlarged image
    newPic->Blit(spriteset[sds->slot], 0, 0, x, y, spritewidth[sds->slot], spriteheight[sds->slot]);

    delete spriteset[sds->slot];

    // replace the bitmap in the sprite set
    add_dynamic_sprite(sds->slot, newPic, (game.spriteflags[sds->slot] & SPF_ALPHACHANNEL) != 0);
}
Пример #12
0
  Bitmap *wnewblock(Common::Bitmap *src, int x1, int y1, int x2, int y2)
  {
    Bitmap *tempbitm;
    int twid = (x2 - x1) + 1, thit = (y2 - y1) + 1;

    if (twid < 1)
      twid = 1;

    if (thit < 1)
      thit = 1;

    tempbitm = BitmapHelper::CreateBitmap(twid, thit);

    if (tempbitm == NULL)
      return NULL;

    tempbitm->Blit(src, x1, y1, 0, 0, tempbitm->GetWidth(), tempbitm->GetHeight());
    return tempbitm;
  }
Пример #13
0
void DynamicSprite_Crop(ScriptDynamicSprite *sds, int x1, int y1, int width, int height) {
    if ((width < 1) || (height < 1))
        quit("!DynamicSprite.Crop: co-ordinates do not make sense");
    if (sds->slot == 0)
        quit("!DynamicSprite.Crop: sprite has been deleted");

    multiply_up_coordinates(&x1, &y1);
    multiply_up_coordinates(&width, &height);

    if ((width > spritewidth[sds->slot]) || (height > spriteheight[sds->slot]))
        quit("!DynamicSprite.Crop: requested to crop an area larger than the source");

    Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, spriteset[sds->slot]->GetColorDepth());
    // blit it cropped
    newPic->Blit(spriteset[sds->slot], x1, y1, 0, 0, newPic->GetWidth(), newPic->GetHeight());

    delete spriteset[sds->slot];

    // replace the bitmap in the sprite set
    add_dynamic_sprite(sds->slot, newPic, (game.spriteflags[sds->slot] & SPF_ALPHACHANNEL) != 0);
}
Пример #14
0
ScriptDynamicSprite* DynamicSprite_CreateFromBackground(int frame, int x1, int y1, int width, int height) {

    if (frame == SCR_NO_VALUE) {
        frame = play.bg_frame;
    }
    else if ((frame < 0) || (frame >= thisroom.num_bscenes))
        quit("!DynamicSprite.CreateFromBackground: invalid frame specified");

    if (x1 == SCR_NO_VALUE) {
        x1 = 0;
        y1 = 0;
        width = play.room_width;
        height = play.room_height;
    }
    else if ((x1 < 0) || (y1 < 0) || (width < 1) || (height < 1) ||
        (x1 + width > play.room_width) || (y1 + height > play.room_height))
        quit("!DynamicSprite.CreateFromBackground: invalid co-ordinates specified");

    multiply_up_coordinates(&x1, &y1);
    multiply_up_coordinates(&width, &height);

    int gotSlot = spriteset.findFreeSlot();
    if (gotSlot <= 0)
        return NULL;

    // create a new sprite as a copy of the existing one
    Bitmap *newPic = BitmapHelper::CreateBitmap(width, height, thisroom.ebscene[frame]->GetColorDepth());
    if (newPic == NULL)
        return NULL;

    newPic->Blit(thisroom.ebscene[frame], x1, y1, 0, 0, width, height);

    // replace the bitmap in the sprite set
    add_dynamic_sprite(gotSlot, newPic);
    ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(gotSlot);
    GlobalReturnValue.SetDynamicObject(new_spr, new_spr);
    return new_spr;
}
Пример #15
0
void draw_text_window_and_bar(Bitmap **text_window_ds, bool should_free_ds,
                              int*xins,int*yins,int*xx,int*yy,int*wii,color_t *set_text_color,int ovrheight, int ifnum) {

    draw_text_window(text_window_ds, should_free_ds, xins, yins, xx, yy, wii, set_text_color, ovrheight, ifnum);

    if ((topBar.wantIt) && (text_window_ds && *text_window_ds)) {
        // top bar on the dialog window with character's name
        // create an enlarged window, then free the old one
        Bitmap *ds = *text_window_ds;
        Bitmap *newScreenop = BitmapHelper::CreateBitmap(ds->GetWidth(), ds->GetHeight() + topBar.height, game.GetColorDepth());
        newScreenop->Blit(ds, 0, 0, 0, topBar.height, ds->GetWidth(), ds->GetHeight());
        delete *text_window_ds;
        *text_window_ds = newScreenop;
        ds = *text_window_ds;

        // draw the top bar
        color_t draw_color = ds->GetCompatibleColor(play.top_bar_backcolor);
        ds->FillRect(Rect(0, 0, ds->GetWidth() - 1, topBar.height - 1), draw_color);
        if (play.top_bar_backcolor != play.top_bar_bordercolor) {
            // draw the border
            draw_color = ds->GetCompatibleColor(play.top_bar_bordercolor);
            for (int j = 0; j < play.top_bar_borderwidth; j++)
                ds->DrawRect(Rect(j, j, ds->GetWidth() - (j + 1), topBar.height - (j + 1)), draw_color);
        }

        // draw the text
        int textx = (ds->GetWidth() / 2) - wgettextwidth_compensate(topBar.text, topBar.font) / 2;
        color_t text_color = ds->GetCompatibleColor(play.top_bar_textcolor);
        wouttext_outline(ds, textx, play.top_bar_borderwidth + 1, topBar.font, text_color, topBar.text);

        // don't draw it next time
        topBar.wantIt = 0;
        // adjust the text Y position
        yins[0] += topBar.height;
    }
    else if (topBar.wantIt)
        topBar.wantIt = 0;
}
Пример #16
0
ScriptDynamicSprite* DynamicSprite_CreateFromExistingSprite(int slot, int preserveAlphaChannel) {

    int gotSlot = spriteset.findFreeSlot();
    if (gotSlot <= 0)
        return NULL;

    if (!spriteset.doesSpriteExist(slot))
        quitprintf("DynamicSprite.CreateFromExistingSprite: sprite %d does not exist", slot);

    // create a new sprite as a copy of the existing one
    Bitmap *newPic = BitmapHelper::CreateBitmap(spritewidth[slot], spriteheight[slot], spriteset[slot]->GetColorDepth());
    if (newPic == NULL)
        return NULL;

    newPic->Blit(spriteset[slot], 0, 0, 0, 0, spritewidth[slot], spriteheight[slot]);

    bool hasAlpha = (preserveAlphaChannel) && ((game.spriteflags[slot] & SPF_ALPHACHANNEL) != 0);

    // replace the bitmap in the sprite set
    add_dynamic_sprite(gotSlot, newPic, hasAlpha);
    ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(gotSlot);
    GlobalReturnValue.SetDynamicObject(new_spr, new_spr);
    return new_spr;
}
Пример #17
0
void Text::Draw(Bitmap& dest, int x, int y, int color, std::string const& text, Text::Alignment align) {
    if (text.length() == 0) return;

    FontRef font = dest.GetFont();
    Rect dst_rect = Font::Default()->GetSize(text);

    switch (align) {
    case Text::AlignCenter:
        dst_rect.x = x - dst_rect.width / 2;
        break;
    case Text::AlignRight:
        dst_rect.x = x - dst_rect.width;
        break;
    case Text::AlignLeft:
        dst_rect.x = x;
        break;
    default:
        assert(false);
    }

    dst_rect.y = y;
    dst_rect.width += 1;
    dst_rect.height += 1; // Need place for shadow
    if (dst_rect.IsOutOfBounds(dest.GetWidth(), dest.GetHeight())) return;

    BitmapRef text_surface; // Complete text will be on this surface
    text_surface = Bitmap::Create(dst_rect.width, dst_rect.height, true);
    text_surface->SetTransparentColor(dest.GetTransparentColor());
    text_surface->Clear();

    // Load the system file for the shadow and text color
    BitmapRef system = Cache::System(Data::system.system_name);
    // Load the exfont-file
    BitmapRef exfont = Cache::Exfont();

    // Get the Shadow color
    Color shadow_color(Cache::system_info.sh_color);
    // If shadow is pure black, increase blue channel
    // so it doesn't become transparent
    if ((shadow_color.red == 0) &&
            (shadow_color.green == 0) &&
            (shadow_color.blue == 0) ) {

        if (text_surface->bytes() >= 3) {
            shadow_color.blue++;
        } else {
            shadow_color.blue += 8;
        }
    }

    // Where to draw the next glyph (x pos)
    int next_glyph_pos = 0;

    // The current char is an exfont
    bool is_exfont = false;

    // This loops always renders a single char, color blends it and then puts
    // it onto the text_surface (including the drop shadow)
    for (boost::u8_to_u32_iterator<std::string::const_iterator>
            c(text.begin(), text.begin(), text.end()),
            end(text.end(), text.begin(), text.end()); c != end; ++c) {
        Rect next_glyph_rect(next_glyph_pos, 0, 0, 0);

        boost::u8_to_u32_iterator<std::string::const_iterator> next_c_it = boost::next(c);
        uint32_t const next_c = std::distance(c, end) > 1? *next_c_it : 0;

        // ExFont-Detection: Check for A-Z or a-z behind the $
        if (*c == '$' && std::isalpha(next_c)) {
            int exfont_value = -1;
            // Calculate which exfont shall be rendered
            if (islower(next_c)) {
                exfont_value = 26 + next_c - 'a';
            } else if (isupper(next_c)) {
                exfont_value = next_c - 'A';
            } else {
                assert(false);
            }
            is_exfont = true;

            BitmapRef mask = Bitmap::Create(12, 12, true);

            // Get exfont from graphic
            Rect const rect_exfont((exfont_value % 13) * 12, (exfont_value / 13) * 12, 12, 12);

            // Create a mask
            mask->Clear();
            mask->Blit(0, 0, *exfont, rect_exfont, 255);

            // Get color region from system graphic
            Rect clip_system(8+16*(color%10), 4+48+16*(color/10), 6, 12);

            BitmapRef char_surface = Bitmap::Create(mask->GetWidth(), mask->GetHeight(), true);
            char_surface->SetTransparentColor(dest.GetTransparentColor());
            char_surface->Clear();

            // Blit gradient color background (twice because of full glyph)
            char_surface->Blit(0, 0, *system, clip_system, 255);
            char_surface->Blit(6, 0, *system, clip_system, 255);

            // Blit mask onto background
            char_surface->MaskBlit(0, 0, *mask, mask->GetRect());

            BitmapRef char_shadow = Bitmap::Create(mask->GetWidth(), mask->GetHeight(), true);
            char_shadow->SetTransparentColor(dest.GetTransparentColor());
            char_shadow->Clear();

            // Blit solid color background
            char_shadow->Fill(shadow_color);
            // Blit mask onto background
            char_shadow->MaskBlit(0, 0, *mask, mask->GetRect());

            // Blit first shadow and then text
            text_surface->Blit(next_glyph_rect.x + 1, next_glyph_rect.y + 1, *char_shadow, char_shadow->GetRect(), 255);
            text_surface->Blit(next_glyph_rect.x, next_glyph_rect.y, *char_surface, char_surface->GetRect(), 255);
        } else { // Not ExFont, draw normal text
            font->Render(*text_surface, next_glyph_rect.x, next_glyph_rect.y, *system, color, *c);
        }

        // If it's a full size glyph, add the size of a half-size glypth twice
        if (is_exfont) {
            is_exfont = false;
            next_glyph_pos += 12;
            // Skip the next character
            ++c;
        } else {
            std::string const glyph(c.base(), next_c_it.base());
            next_glyph_pos += Font::Default()->GetSize(glyph).width;
        }
    }

    BitmapRef text_bmp = Bitmap::Create(*text_surface, text_surface->GetRect());

    Rect src_rect(0, 0, dst_rect.width, dst_rect.height);
    int iy = dst_rect.y;
    if (dst_rect.height > text_bmp->GetHeight()) {
        iy += ((dst_rect.height - text_bmp->GetHeight()) / 2);
    }
    int ix = dst_rect.x;

    dest.Blit(ix, iy, *text_bmp, src_rect, 255);
}