Overhauled graphics system

Along with being more accurate to the original, this fixes switching out
of fullscreen causing textures to disappear. This was caused by DirectX
destroying textures that are marked as render-targets when a device-loss
occurs. SDL2 doesn't do anything to recover them, unlike regular
textures, so my solution is just to avoid render-target textures
entirely.

On the upside, this should make drawing text to surfaces much faster,
since we're not reading back bitmaps from the GPU.
This commit is contained in:
Clownacy 2019-01-30 14:56:17 +00:00
parent ba13b8aeea
commit 4f7db164d6
4 changed files with 233 additions and 220 deletions

View file

@ -64,101 +64,157 @@ bool Flip_SystemTask()
return true; return true;
} }
bool StartDirectDraw() static bool IsEnableBitmap(SDL_RWops *fp)
{ {
//Create renderer char str[16];
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE); const char *extra_text = "(C)Pixel";
return true;
}
void EndDirectDraw() const size_t len = strlen(extra_text);
{
//Release all surfaces fp->seek(fp, -len, RW_SEEK_END);
for (int i = 0; i < SURFACE_ID_MAX; i++) fp->read(fp, str, 1, len);
{ fp->seek(fp, 0, RW_SEEK_SET);
if (surf[i].texture) return memcmp(str, extra_text, len) == 0;
{
SDL_DestroyTexture(surf[i].texture);
surf[i].texture = NULL;
}
}
} }
void ReleaseSurface(int s) void ReleaseSurface(int s)
{ {
//Release the surface we want to release //Release the surface we want to release
if (surf[s].texture) if (surf[s].in_use)
{ {
SDL_DestroyTexture(surf[s].texture); SDL_DestroyTexture(surf[s].texture);
surf[s].texture = NULL; SDL_FreeSurface(surf[s].surface);
surf[s].in_use = false;
} }
} }
bool MakeSurface(SDL_RWops *fp, int surf_no) bool MakeSurface_Generic(int bxsize, int bysize, int surf_no)
{ {
//Check if surf_no can be used bool success = false;
if (surf_no > SURFACE_ID_MAX)
{
printf("Tried to create surface with invalid id %d\n", surf_no);
return false;
}
if (surf[surf_no].texture)
{
printf("Tried to create surface at id %d, but there's already a texture there\n", surf_no);
return false;
}
//Load surface from file
SDL_Surface *surface = SDL_LoadBMP_RW(fp, 1);
if (!surface)
{
printf("Couldn't load bitmap for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
return false;
}
//Make sure surface has color key on
SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, 0, 0, 0));
//Get texture from surface
SDL_Texture *texture = SDL_CreateTextureFromSurface(gRenderer, surface);
if (!texture)
{
printf("Failed to convert SDL_Surface to SDL_Texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
return false;
}
//Create real texture, and copy loaded texture here (has texture target access)
int w, h;
SDL_QueryTexture(texture, NULL, NULL, &w, &h);
SDL_Texture *textureAccessible = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, w * gWindowScale, h * gWindowScale); #ifdef FIX_BUGS
if (surf_no >= SURFACE_ID_MAX)
if (!textureAccessible) #else
if (surf_no > SURFACE_ID_MAX) // OOPS (should be '>=')
#endif
{ {
printf("Failed to create real texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError()); printf("Tried to create drawable surface at invalid slot (%d - maximum is %d)\n", surf_no, SURFACE_ID_MAX);
return false;
} }
else
SDL_SetTextureBlendMode(textureAccessible, SDL_BLENDMODE_BLEND); {
if (surf[surf_no].in_use == true)
SDL_SetRenderTarget(gRenderer, textureAccessible); {
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0); printf("Tried to create drawable surface at occupied slot (%d)\n", surf_no);
SDL_RenderClear(gRenderer); }
SDL_RenderCopy(gRenderer, texture, NULL, NULL); else
SDL_SetRenderTarget(gRenderer, NULL); {
//Create surface
//Set surface's metadata surf[surf_no].surface = SDL_CreateRGBSurfaceWithFormat(0, bxsize * gWindowScale, bysize * gWindowScale, 0, SDL_PIXELFORMAT_RGBA32);
surf[surf_no].texture = textureAccessible;
if (surf[surf_no].surface == NULL)
//Free surface and texture {
SDL_DestroyTexture(texture); printf("Failed to create drawable surface %d (SDL_CreateRGBSurfaceWithFormat)\nSDL Error: %s\n", surf_no, SDL_GetError());
SDL_FreeSurface(surface); }
else
printf(" ^ Successfully loaded\n"); {
return true; surf[surf_no].texture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, bxsize * gWindowScale, bysize * gWindowScale);
if (surf[surf_no].texture == NULL)
{
printf("Failed to create drawable surface %d (SDL_CreateTexture)\nSDL Error: %s\n", surf_no, SDL_GetError());
SDL_FreeSurface(surf[surf_no].surface);
}
else
{
surf[surf_no].in_use = true;
success = true;
}
}
}
}
return success;
} }
bool MakeSurface_File(const char *name, int surf_no) static void FlushSurface(int surf_no)
{
unsigned char *raw_pixels;
int pitch;
SDL_LockTexture(surf[surf_no].texture, NULL, (void**)&raw_pixels, &pitch);
unsigned char (*src_pixels)[surf[surf_no].surface->pitch / 4][4] = (unsigned char (*)[surf[surf_no].surface->pitch/ 4][4])surf[surf_no].surface->pixels;
unsigned char (*dst_pixels)[pitch / 4][4] = (unsigned char (*)[pitch/ 4][4])raw_pixels;
for (unsigned int h = 0; h < surf[surf_no].surface->h; ++h)
{
for (unsigned int w = 0; w < surf[surf_no].surface->w; ++w)
{
dst_pixels[h][w][0] = src_pixels[h][w][0];
dst_pixels[h][w][1] = src_pixels[h][w][1];
dst_pixels[h][w][2] = src_pixels[h][w][2];
if (src_pixels[h][w][0] || src_pixels[h][w][1] || src_pixels[h][w][2]) // Colour-key
dst_pixels[h][w][3] = 0xFF;
else
dst_pixels[h][w][3] = 0;
}
}
SDL_UnlockTexture(surf[surf_no].texture);
}
static bool LoadBitmap(SDL_RWops *fp, int surf_no, bool create_surface)
{
bool success = false;
if (surf_no >= SURFACE_ID_MAX)
{
printf("Tried to load bitmap at invalid slot (%d - maximum is %d\n", surf_no, SURFACE_ID_MAX);
}
else
{
if (create_surface && surf[surf_no].in_use)
{
printf("Tried to create drawable surface at occupied slot (%d)\n", surf_no);
}
else
{
SDL_Surface *surface = SDL_LoadBMP_RW(fp, 1);
if (surface == NULL)
{
printf("Couldn't load bitmap for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
}
else
{
if (create_surface == false || MakeSurface_Generic(surface->w, surface->h, surf_no))
{
SDL_Surface *converted_surface = SDL_ConvertSurface(surface, surf[surf_no].surface->format, 0);
if (converted_surface == NULL)
{
printf("Couldn't convert bitmap to surface format (surface id %d)\nSDL Error: %s\n", surf_no, SDL_GetError());
}
else
{
SDL_Rect dst_rect = {0, 0, converted_surface->w * gWindowScale, converted_surface->h * gWindowScale};
SDL_BlitScaled(converted_surface, NULL, surf[surf_no].surface, &dst_rect);
SDL_FreeSurface(converted_surface);
surf[surf_no].needs_updating = true;
printf(" ^ Successfully loaded\n");
success = true;
}
}
SDL_FreeSurface(surface);
}
}
}
return success;
}
static bool LoadBitmap_File(const char *name, int surf_no, bool create_surface)
{ {
char path[PATH_LENGTH]; char path[PATH_LENGTH];
SDL_RWops *fp; SDL_RWops *fp;
@ -168,9 +224,16 @@ bool MakeSurface_File(const char *name, int surf_no)
fp = SDL_RWFromFile(path, "rb"); fp = SDL_RWFromFile(path, "rb");
if (fp) if (fp)
{ {
printf("Loading surface (as .pbm) from %s for surface id %d\n", path, surf_no); if (!IsEnableBitmap(fp))
if (MakeSurface(fp, surf_no)) {
return true; printf("Tried to load bitmap to surface %d, but it's missing the '(C)Pixel' string\n", surf_no);
}
else
{
printf("Loading surface (as .pbm) from %s for surface id %d\n", path, surf_no);
if (LoadBitmap(fp, surf_no, create_surface))
return true;
}
} }
//Attempt to load BMP //Attempt to load BMP
@ -178,23 +241,31 @@ bool MakeSurface_File(const char *name, int surf_no)
fp = SDL_RWFromFile(path, "rb"); fp = SDL_RWFromFile(path, "rb");
if (fp) if (fp)
{ {
printf("Loading surface (as .bmp) from %s for surface id %d\n", path, surf_no); if (!IsEnableBitmap(fp))
if (MakeSurface(fp, surf_no)) {
return true; printf("Tried to load bitmap to surface %d, but it's missing the '(C)Pixel' string\n", surf_no);
}
else
{
printf("Loading surface (as .bmp) from %s for surface id %d\n", path, surf_no);
if (LoadBitmap(fp, surf_no, create_surface))
return true;
}
} }
printf("Failed to open file %s\n", name); printf("Failed to open file %s\n", name);
return false; return false;
} }
bool MakeSurface_Resource(const char *res, int surf_no) static bool LoadBitmap_Resource(const char *res, int surf_no, bool create_surface)
{ {
SDL_RWops *fp = FindResource(res); SDL_RWops *fp = FindResource(res);
if (fp) if (fp)
{ {
printf("Loading surface from resource %s for surface id %d\n", res, surf_no); printf("Loading surface from resource %s for surface id %d\n", res, surf_no);
if (MakeSurface(fp, surf_no)) if (LoadBitmap(fp, surf_no, create_surface))
return true; return true;
} }
@ -202,34 +273,24 @@ bool MakeSurface_Resource(const char *res, int surf_no)
return false; return false;
} }
bool MakeSurface_File(const char *name, int surf_no)
{
return LoadBitmap_File(name, surf_no, true);
}
bool MakeSurface_Resource(const char *res, int surf_no)
{
return LoadBitmap_Resource(res, surf_no, true);
}
bool ReloadBitmap_File(const char *name, int surf_no) bool ReloadBitmap_File(const char *name, int surf_no)
{ {
ReleaseSurface(surf_no); return LoadBitmap_File(name, surf_no, false);
return MakeSurface_File(name, surf_no);
} }
bool ReloadBitmap_Resource(const char *res, int surf_no) bool ReloadBitmap_Resource(const char *res, int surf_no)
{ {
ReleaseSurface(surf_no); return LoadBitmap_Resource(res, surf_no, false);
return MakeSurface_Resource(res, surf_no);
}
bool MakeSurface_Generic(int bxsize, int bysize, int surf_no)
{
//Delete old surface
ReleaseSurface(surf_no);
//Create surface
surf[surf_no].texture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, bxsize * gWindowScale, bysize * gWindowScale);
if (!surf[surf_no].texture)
{
printf("Failed to create drawable surface %d\nSDL Error: %s\n", surf_no, SDL_GetError());
return false;
}
SDL_SetTextureBlendMode(surf[surf_no].texture, SDL_BLENDMODE_BLEND);
return true;
} }
SDL_Rect RectToSDLRect(RECT *rect) SDL_Rect RectToSDLRect(RECT *rect)
@ -246,42 +307,27 @@ void BackupSurface(int surf_no, RECT *rect)
//Get texture of what's currently rendered on screen //Get texture of what's currently rendered on screen
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, SDL_PIXELFORMAT_RGBA32); SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, SDL_PIXELFORMAT_RGBA32);
SDL_RenderReadPixels(gRenderer, nullptr, SDL_PIXELFORMAT_RGBA32, surface->pixels, surface->pitch); SDL_RenderReadPixels(gRenderer, NULL, SDL_PIXELFORMAT_RGBA32, surface->pixels, surface->pitch);
SDL_Texture *screenTexture = SDL_CreateTextureFromSurface(gRenderer, surface);
//Free surface
SDL_FreeSurface(surface);
//Get rects //Get rects
SDL_Rect frameRect = RectToSDLRect(rect); SDL_Rect frameRect = RectToSDLRect(rect);
frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale}; frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale};
SDL_Texture *textureAccessible = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, frameRect.w, frameRect.h); SDL_BlitSurface(surface, &frameRect, surf[surf_no].surface, &frameRect);
surf[surf_no].needs_updating = true;
if (!textureAccessible)
{ //Free surface
printf("Failed to create real texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError()); SDL_FreeSurface(surface);
return;
}
SDL_SetTextureBlendMode(textureAccessible, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(gRenderer, textureAccessible);
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0);
SDL_RenderClear(gRenderer);
SDL_RenderCopy(gRenderer, screenTexture, &frameRect, NULL);
SDL_SetRenderTarget(gRenderer, NULL);
//Set surface's metadata
surf[surf_no].texture = textureAccessible;
//Free stuff
SDL_DestroyTexture(screenTexture);
} }
void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transparency static void DrawBitmap(RECT *rcView, int x, int y, RECT *rect, int surf_no, bool transparent)
{ {
if (surf[surf_no].needs_updating)
{
FlushSurface(surf_no);
surf[surf_no].needs_updating = false;
}
//Get SDL_Rects //Get SDL_Rects
SDL_Rect clipRect = RectToSDLRect(rcView); SDL_Rect clipRect = RectToSDLRect(rcView);
@ -295,6 +341,8 @@ void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transpare
clipRect = {clipRect.x * gWindowScale, clipRect.y * gWindowScale, clipRect.w * gWindowScale, clipRect.h * gWindowScale}; clipRect = {clipRect.x * gWindowScale, clipRect.y * gWindowScale, clipRect.w * gWindowScale, clipRect.h * gWindowScale};
SDL_RenderSetClipRect(gRenderer, &clipRect); SDL_RenderSetClipRect(gRenderer, &clipRect);
SDL_SetTextureBlendMode(surf[surf_no].texture, transparent ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
//Draw to screen //Draw to screen
if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0) if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0)
printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError()); printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError());
@ -303,36 +351,14 @@ void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transpare
SDL_RenderSetClipRect(gRenderer, NULL); SDL_RenderSetClipRect(gRenderer, NULL);
} }
void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transparency
{
DrawBitmap(rcView, x, y, rect, surf_no, true);
}
void PutBitmap4(RECT *rcView, int x, int y, RECT *rect, int surf_no) //No Transparency void PutBitmap4(RECT *rcView, int x, int y, RECT *rect, int surf_no) //No Transparency
{ {
//Get SDL_Rects DrawBitmap(rcView, x, y, rect, surf_no, false);
SDL_Rect clipRect = RectToSDLRect(rcView);
SDL_Rect frameRect = RectToSDLRect(rect);
frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale};
//Get dest rect
SDL_Rect destRect = {x * gWindowScale, y * gWindowScale, frameRect.w, frameRect.h};
//Set cliprect
clipRect = {clipRect.x * gWindowScale, clipRect.y * gWindowScale, clipRect.w * gWindowScale, clipRect.h * gWindowScale};
SDL_RenderSetClipRect(gRenderer, &clipRect);
//Get original drawing colour
uint8_t origR, origG, origB, origA;
SDL_GetRenderDrawColor(gRenderer, &origR, &origG, &origB, &origA);
//Draw black behind texture
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0xFF);
SDL_RenderFillRect(gRenderer, &destRect);
//Draw texture
if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0)
printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError());
//Restore original colour, and undo cliprect
SDL_RenderSetClipRect(gRenderer, NULL);
SDL_SetRenderDrawColor(gRenderer, origR, origG, origB, origA);
} }
void Surface2Surface(int x, int y, RECT *rect, int to, int from) void Surface2Surface(int x, int y, RECT *rect, int to, int from)
@ -341,22 +367,9 @@ void Surface2Surface(int x, int y, RECT *rect, int to, int from)
SDL_Rect rcSet = {x * gWindowScale, y * gWindowScale, (rect->right - rect->left) * gWindowScale, (rect->bottom - rect->top) * gWindowScale}; SDL_Rect rcSet = {x * gWindowScale, y * gWindowScale, (rect->right - rect->left) * gWindowScale, (rect->bottom - rect->top) * gWindowScale};
SDL_Rect frameRect = RectToSDLRect(rect); SDL_Rect frameRect = RectToSDLRect(rect);
frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale}; frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale};
//Target surface SDL_BlitSurface(surf[from].surface, &frameRect, surf[to].surface, &rcSet);
if (!surf[to].texture) surf[to].needs_updating = true;
{
printf("Tried to draw to surface %d, which doesn't exist\n", to);
return;
}
SDL_SetRenderTarget(gRenderer, surf[to].texture);
//Draw texture
if (SDL_RenderCopy(gRenderer, surf[from].texture, &frameRect, &rcSet) < 0)
printf("Failed to draw texture %d to %d\nSDL Error: %s\n", from, to, SDL_GetError());
//Stop targetting surface
SDL_SetRenderTarget(gRenderer, NULL);
} }
void CortBox(RECT *rect, uint32_t col) void CortBox(RECT *rect, uint32_t col)
@ -375,27 +388,12 @@ void CortBox2(RECT *rect, uint32_t col, int surf_no)
//Get rect //Get rect
SDL_Rect destRect = RectToSDLRect(rect); SDL_Rect destRect = RectToSDLRect(rect);
destRect = {destRect.x * gWindowScale, destRect.y * gWindowScale, destRect.w * gWindowScale, destRect.h * gWindowScale}; destRect = {destRect.x * gWindowScale, destRect.y * gWindowScale, destRect.w * gWindowScale, destRect.h * gWindowScale};
//Target surface
if (!surf[surf_no].texture)
{
printf("Tried to draw a rectangle to surface %d, which doesn't exist\n", surf_no);
return;
}
SDL_SetRenderTarget(gRenderer, surf[surf_no].texture);
const unsigned char col_red = (col & 0xFF0000) >> 16; const unsigned char col_red = (col & 0xFF0000) >> 16;
const unsigned char col_green = (col & 0x00FF00) >> 8; const unsigned char col_green = (col & 0x00FF00) >> 8;
const unsigned char col_blue = col & 0x0000FF; const unsigned char col_blue = col & 0x0000FF;
const unsigned char col_alpha = (col_red || col_green || col_blue) ? 0xFF : 0; SDL_FillRect(surf[surf_no].surface, &destRect, SDL_MapRGB(surf[surf_no].surface->format, col_red, col_green, col_blue));
surf[surf_no].needs_updating = true;
//Set colour and draw
SDL_SetRenderDrawColor(gRenderer, col_red, col_green, col_blue, col_alpha);
SDL_RenderFillRect(gRenderer, &destRect);
//Stop targetting surface
SDL_SetRenderTarget(gRenderer, NULL);
} }
#ifdef WINDOWS #ifdef WINDOWS
@ -491,12 +489,24 @@ void InitTextObject(const char *font_name)
void PutText(int x, int y, const char *text, uint32_t color) void PutText(int x, int y, const char *text, uint32_t color)
{ {
DrawText(gFont, gRenderer, NULL, x * gWindowScale, y * gWindowScale, color, text, strlen(text)); int surface_width, surface_height;
SDL_GetRendererOutputSize(gRenderer, &surface_width, &surface_height);
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, surface_width, surface_height, 0, SDL_PIXELFORMAT_RGBA32);
SDL_RenderReadPixels(gRenderer, NULL, SDL_PIXELFORMAT_RGBA32, surface->pixels, surface->pitch);
DrawText(gFont, surface, x * gWindowScale, y * gWindowScale, color, text, strlen(text));
SDL_Texture *screen_texture = SDL_CreateTextureFromSurface(gRenderer, surface);
SDL_FreeSurface(surface);
SDL_RenderCopy(gRenderer, screen_texture, NULL, NULL);
SDL_DestroyTexture(screen_texture);
} }
void PutText2(int x, int y, const char *text, uint32_t color, int surf_no) void PutText2(int x, int y, const char *text, uint32_t color, int surf_no)
{ {
DrawText(gFont, gRenderer, surf[surf_no].texture, x * gWindowScale, y * gWindowScale, color, text, strlen(text)); DrawText(gFont, surf[surf_no].surface, x * gWindowScale, y * gWindowScale, color, text, strlen(text));
surf[surf_no].needs_updating = true;
} }
void EndTextObject() void EndTextObject()
@ -505,3 +515,17 @@ void EndTextObject()
UnloadFont(gFont); UnloadFont(gFont);
gFont = nullptr; gFont = nullptr;
} }
bool StartDirectDraw()
{
//Create renderer
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
return true;
}
void EndDirectDraw()
{
//Release all surfaces
for (int i = 0; i < SURFACE_ID_MAX; i++)
ReleaseSurface(i);
}

View file

@ -45,6 +45,9 @@ enum Surface_Ids
struct SURFACE struct SURFACE
{ {
bool in_use;
bool needs_updating;
SDL_Surface *surface;
SDL_Texture *texture; SDL_Texture *texture;
}; };

View file

@ -175,20 +175,12 @@ FontObject* LoadFont(const char *font_filename, unsigned int cell_width, unsigne
return font_object; return font_object;
} }
void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, unsigned long colour, const char *string, size_t string_length) void DrawText(FontObject *font_object, SDL_Surface *surface, int x, int y, unsigned long colour, const char *string, size_t string_length)
{ {
if (font_object != NULL) if (font_object != NULL)
{ {
const unsigned char colours[3] = {(unsigned char)(colour >> 16), (unsigned char)(colour >> 8), (unsigned char)colour}; const unsigned char colours[3] = {(unsigned char)(colour >> 16), (unsigned char)(colour >> 8), (unsigned char)colour};
SDL_Texture *old_render_target = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, texture);
int surface_width, surface_height;
SDL_GetRendererOutputSize(renderer, &surface_width, &surface_height);
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, surface_width, surface_height, 0, SDL_PIXELFORMAT_RGBA32);
SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_RGBA32, surface->pixels, surface->pitch);
unsigned char (*surface_buffer)[surface->pitch / 4][4] = (unsigned char (*)[surface->pitch / 4][4])surface->pixels; unsigned char (*surface_buffer)[surface->pitch / 4][4] = (unsigned char (*)[surface->pitch / 4][4])surface->pixels;
FT_Face face = font_object->face; FT_Face face = font_object->face;
@ -238,11 +230,11 @@ void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *text
const int letter_x = x + pen_x + face->glyph->bitmap_left; const int letter_x = x + pen_x + face->glyph->bitmap_left;
const int letter_y = y + ((FT_MulFix(face->ascender, face->size->metrics.y_scale) + (64 - 1)) / 64) - (face->glyph->metrics.horiBearingY / 64); const int letter_y = y + ((FT_MulFix(face->ascender, face->size->metrics.y_scale) + (64 - 1)) / 64) - (face->glyph->metrics.horiBearingY / 64);
for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + converted.rows, surface_height); ++iy) for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + converted.rows, surface->h); ++iy)
{ {
if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD)
{ {
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width / 3, surface_width); ++ix) for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width / 3, surface->w); ++ix)
{ {
const unsigned char (*font_buffer)[converted.pitch / 3][3] = (unsigned char (*)[converted.pitch / 3][3])converted.buffer; const unsigned char (*font_buffer)[converted.pitch / 3][3] = (unsigned char (*)[converted.pitch / 3][3])converted.buffer;
@ -263,7 +255,7 @@ void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *text
} }
else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
{ {
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface_width); ++ix) for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface->w); ++ix)
{ {
unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer; unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer;
@ -282,7 +274,7 @@ void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *text
} }
else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
{ {
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface_width); ++ix) for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface->w); ++ix)
{ {
unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer; unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer;
@ -303,12 +295,6 @@ void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *text
pen_x += face->glyph->advance.x / 64; pen_x += face->glyph->advance.x / 64;
} }
SDL_Texture *screen_texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);
SDL_RenderCopy(renderer, screen_texture, NULL, NULL);
SDL_DestroyTexture(screen_texture);
SDL_SetRenderTarget(renderer, old_render_target);
} }
} }

View file

@ -8,5 +8,5 @@ typedef struct FontObject FontObject;
FontObject* LoadFontFromData(const unsigned char *data, size_t data_size, unsigned int cell_width, unsigned int cell_height); FontObject* LoadFontFromData(const unsigned char *data, size_t data_size, unsigned int cell_width, unsigned int cell_height);
FontObject* LoadFont(const char *font_filename, unsigned int cell_width, unsigned int cell_height); FontObject* LoadFont(const char *font_filename, unsigned int cell_width, unsigned int cell_height);
void DrawText(FontObject *font_object, SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, unsigned long colour, const char *string, size_t string_length); void DrawText(FontObject *font_object, SDL_Surface *surface, int x, int y, unsigned long colour, const char *string, size_t string_length);
void UnloadFont(FontObject *font_object); void UnloadFont(FontObject *font_object);