ref: 6d385e674fac76cb443d84210269f588d2ea1155
parent: 90f29377fea8c34ec8b58e5198be322440d564ef
author: Clownacy <Clownacy@users.noreply.github.com>
date: Tue Jul 23 12:38:04 EDT 2019
Font refactor part 1: Software With this, font blitting is handled by the rendering backend, paving the way for hardware-accelerated font drawing in the accelerated backends.
--- a/src/Backends/Rendering.h
+++ b/src/Backends/Rendering.h
@@ -4,9 +4,15 @@
#include "../WindowsWrapper.h"
-#include "../Font.h"
+enum
+{
+ FONT_PIXEL_MODE_LCD,
+ FONT_PIXEL_MODE_GRAY,
+ FONT_PIXEL_MODE_MONO,
+};
typedef struct Backend_Surface Backend_Surface;
+typedef struct Backend_Glyph Backend_Glyph;
BOOL Backend_Init(SDL_Window *window);
void Backend_Deinit(void);
@@ -20,7 +26,9 @@
void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue);
void Backend_ColourFillToScreen(const RECT *rect, unsigned char red, unsigned char green, unsigned char blue);
void Backend_ScreenToSurface(Backend_Surface *surface, const RECT *rect);
-void Backend_DrawText(Backend_Surface *surface, FontObject *font, int x, int y, const char *text, unsigned long colour);
-void Backend_DrawTextToScreen(FontObject *font, int x, int y, const char *text, unsigned long colour);
+Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, unsigned short total_greys, unsigned char pixel_mode);
+void Backend_UnloadGlyph(Backend_Glyph *glyph);
+void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours);
+void Backend_DrawGlyphToScreen(Backend_Glyph *glyph, long x, long y, const unsigned char *colours);
void Backend_HandleDeviceLoss(void);
void Backend_HandleWindowResize(void);
--- a/src/Backends/Rendering/Software.cpp
+++ b/src/Backends/Rendering/Software.cpp
@@ -7,7 +7,10 @@
#include "../../WindowsWrapper.h"
-#include "../../Font.h"
+#undef MIN
+#undef MAX
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
typedef struct Backend_Surface
{
@@ -17,6 +20,16 @@
unsigned int pitch;
} Backend_Surface;
+typedef struct Backend_Glyph
+{
+ unsigned char *pixels;
+ unsigned int width;
+ unsigned int height;
+ int pitch;
+ unsigned short total_greys;
+ unsigned char pixel_mode;
+} Backend_Glyph;
+
static SDL_Window *window;
static SDL_Surface *window_surface;
static SDL_Surface *screen_surface;
@@ -242,14 +255,107 @@
Backend_Blit(&framebuffer, rect, surface, rect->left, rect->top, FALSE);
}
-void Backend_DrawText(Backend_Surface *surface, FontObject *font, int x, int y, const char *text, unsigned long colour)
+Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, unsigned short total_greys, unsigned char pixel_mode)
{
- DrawText(font, surface->pixels, surface->pitch, surface->width, surface->height, x, y, colour, text, strlen(text));
+ Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph));
+
+ if (glyph == NULL)
+ return NULL;
+
+ glyph->pixels = (unsigned char*)malloc(pitch * height);
+
+ if (glyph->pixels == NULL)
+ {
+ free(glyph);
+ return NULL;
+ }
+
+ memcpy(glyph->pixels, pixels, pitch * height);
+
+ glyph->width = width;
+ glyph->height = height;
+ glyph->pitch = pitch;
+ glyph->total_greys = total_greys;
+ glyph->pixel_mode = pixel_mode;
+
+ return glyph;
}
-void Backend_DrawTextToScreen(FontObject *font, int x, int y, const char *text, unsigned long colour)
+void Backend_UnloadGlyph(Backend_Glyph *glyph)
{
- Backend_DrawText(&framebuffer, font, x, y, text, colour);
+ free(glyph->pixels);
+ free(glyph);
+}
+
+void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)
+{
+ switch (glyph->pixel_mode)
+ {
+ case FONT_PIXEL_MODE_LCD:
+ for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy)
+ {
+ for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width / 3, surface->width); ++ix)
+ {
+ const unsigned char *font_pixel = glyph->pixels + iy * glyph->pitch + ix * 3;
+
+ if (font_pixel[0] || font_pixel[1] || font_pixel[2])
+ {
+ unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3;
+
+ for (unsigned int j = 0; j < 3; ++j)
+ {
+ const double alpha = pow((font_pixel[j] / 255.0), 1.0 / 1.8); // Gamma correction
+ bitmap_pixel[j] = (unsigned char)((colours[j] * alpha) + (bitmap_pixel[j] * (1.0 - alpha))); // Alpha blending
+ }
+ }
+ }
+ }
+
+ break;
+
+ case FONT_PIXEL_MODE_GRAY:
+ for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy)
+ {
+ for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, surface->width); ++ix)
+ {
+ const unsigned char font_pixel = glyph->pixels[iy * glyph->pitch + ix];
+
+ if (font_pixel)
+ {
+ const double alpha = pow((double)font_pixel / (glyph->total_greys - 1), 1.0 / 1.8); // Gamma-corrected
+
+ unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3;
+
+ for (unsigned int j = 0; j < 3; ++j)
+ bitmap_pixel[j] = (unsigned char)((colours[j] * alpha) + (bitmap_pixel[j] * (1.0 - alpha))); // Alpha blending
+ }
+ }
+ }
+
+ break;
+
+ case FONT_PIXEL_MODE_MONO:
+ for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy)
+ {
+ for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, surface->width); ++ix)
+ {
+ if (glyph->pixels[iy * glyph->pitch + ix])
+ {
+ unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3;
+
+ for (unsigned int j = 0; j < 3; ++j)
+ bitmap_pixel[j] = colours[j];
+ }
+ }
+ }
+
+ break;
+ }
+}
+
+void Backend_DrawGlyphToScreen(Backend_Glyph *glyph, long x, long y, const unsigned char *colours)
+{
+ Backend_DrawGlyph(&framebuffer, glyph, x, y, colours);
}
void Backend_HandleDeviceLoss(void)
--- a/src/Draw.cpp
+++ b/src/Draw.cpp
@@ -16,12 +16,6 @@
#include "Tags.h"
#include "Backends/Rendering.h"
-struct SURFACE
-{
- BOOL in_use;
- Backend_Surface *backend;
-};
-
SDL_Window *gWindow;
static SDL_PixelFormat *rgb24_pixel_format; // Needed because SDL2 is stupid
@@ -32,6 +26,12 @@
int magnification;
BOOL fullscreen;
+struct SURFACE
+{
+ BOOL in_use;
+ Backend_Surface *backend;
+};
+
SURFACE surf[SURFACE_ID_MAX];
FontObject *gFont;
@@ -559,12 +559,12 @@
void PutText(int x, int y, const char *text, unsigned long color)
{
- Backend_DrawTextToScreen(gFont, x * magnification, y * magnification, text, color);
+ DrawText(gFont, NULL, x * magnification, y * magnification, color, text, strlen(text));
}
void PutText2(int x, int y, const char *text, unsigned long color, Surface_Ids surf_no)
{
- Backend_DrawText(surf[surf_no].backend, gFont, x * magnification, y * magnification, text, color);
+ DrawText(gFont, surf[surf_no].backend, x * magnification, y * magnification, color, text, strlen(text));
}
void EndTextObject()
--- a/src/Font.cpp
+++ b/src/Font.cpp
@@ -12,7 +12,9 @@
#include "WindowsWrapper.h"
+#include "Draw.h"
#include "File.h"
+#include "Backends/Rendering.h"
// Cave Story wasn't intended to use font anti-aliasing. It's only because Microsoft enabled it
// by default from Windows Vista onwards that the game started using it.
@@ -25,19 +27,13 @@
#define DISABLE_FONT_ANTIALIASING
#endif
-#undef MIN
-#undef MAX
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-
typedef struct CachedGlyph
{
unsigned long unicode_value;
- FT_Bitmap bitmap;
- unsigned char pixel_mode;
int x;
int y;
int x_advance;
+ Backend_Glyph *backend;
struct CachedGlyph *next;
} CachedGlyph;
@@ -1737,12 +1733,33 @@
#endif
glyph->unicode_value = unicode_value;
- FT_Bitmap_New(&glyph->bitmap);
- FT_Bitmap_Convert(font_object->library, &font_object->face->glyph->bitmap, &glyph->bitmap, 1);
- glyph->pixel_mode = font_object->face->glyph->bitmap.pixel_mode;
glyph->x = font_object->face->glyph->bitmap_left;
glyph->y = (FT_MulFix(font_object->face->ascender, font_object->face->size->metrics.y_scale) - font_object->face->glyph->metrics.horiBearingY + (64 / 2)) / 64;
glyph->x_advance = font_object->face->glyph->advance.x / 64;
+
+ FT_Bitmap bitmap;
+ FT_Bitmap_New(&bitmap);
+ FT_Bitmap_Convert(font_object->library, &font_object->face->glyph->bitmap, &bitmap, 1);
+
+ unsigned char pixel_mode;
+ switch (font_object->face->glyph->bitmap.pixel_mode)
+ {
+ case FT_PIXEL_MODE_LCD:
+ pixel_mode = FONT_PIXEL_MODE_LCD;
+ break;
+
+ case FT_PIXEL_MODE_GRAY:
+ pixel_mode = FONT_PIXEL_MODE_GRAY;
+ break;
+
+ case FT_PIXEL_MODE_MONO:
+ pixel_mode = FONT_PIXEL_MODE_MONO;
+ break;
+ }
+
+ glyph->backend = Backend_LoadGlyph(bitmap.buffer, bitmap.width, bitmap.rows, bitmap.pitch, bitmap.num_grays, pixel_mode);
+
+ FT_Bitmap_Done(font_object->library, &bitmap);
}
return glyph;
@@ -1755,7 +1772,7 @@
{
CachedGlyph *next_glyph = glyph->next;
- FT_Bitmap_Done(font_object->library, &glyph->bitmap);
+ Backend_UnloadGlyph(glyph->backend);
free(glyph);
glyph = next_glyph;
@@ -1838,7 +1855,7 @@
return font_object;
}
-void DrawText(FontObject *font_object, unsigned char *bitmap_buffer, size_t bitmap_pitch, int bitmap_width, int bitmap_height, int x, int y, unsigned long colour, const char *string, size_t string_length)
+void DrawText(FontObject *font_object, Backend_Surface *surface, int x, int y, unsigned long colour, const char *string, size_t string_length)
{
if (font_object != NULL)
{
@@ -1866,67 +1883,12 @@
const int letter_x = x + pen_x + glyph->x;
const int letter_y = y + glyph->y;
- switch (glyph->pixel_mode)
+ if (glyph->backend)
{
- case FT_PIXEL_MODE_LCD:
- for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)glyph->bitmap.rows, bitmap_height); ++iy)
- {
- for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)glyph->bitmap.width / 3, bitmap_width); ++ix)
- {
- const unsigned char *font_pixel = glyph->bitmap.buffer + iy * glyph->bitmap.pitch + ix * 3;
-
- if (font_pixel[0] || font_pixel[1] || font_pixel[2])
- {
- unsigned char *bitmap_pixel = bitmap_buffer + (letter_y + iy) * bitmap_pitch + (letter_x + ix) * 3;
-
- for (unsigned int j = 0; j < 3; ++j)
- {
- const double alpha = pow((font_pixel[j] / 255.0), 1.0 / 1.8); // Gamma correction
- bitmap_pixel[j] = (unsigned char)((colours[j] * alpha) + (bitmap_pixel[j] * (1.0 - alpha))); // Alpha blending
- }
- }
- }
- }
-
- break;
-
- case FT_PIXEL_MODE_GRAY:
- for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)glyph->bitmap.rows, bitmap_height); ++iy)
- {
- for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)glyph->bitmap.width, bitmap_width); ++ix)
- {
- const unsigned char font_pixel = glyph->bitmap.buffer[iy * glyph->bitmap.pitch + ix];
-
- if (font_pixel)
- {
- const double alpha = pow((double)font_pixel / (glyph->bitmap.num_grays - 1), 1.0 / 1.8); // Gamma-corrected
-
- unsigned char *bitmap_pixel = bitmap_buffer + (letter_y + iy) * bitmap_pitch + (letter_x + ix) * 3;
-
- for (unsigned int j = 0; j < 3; ++j)
- bitmap_pixel[j] = (unsigned char)((colours[j] * alpha) + (bitmap_pixel[j] * (1.0 - alpha))); // Alpha blending
- }
- }
- }
-
- break;
-
- case FT_PIXEL_MODE_MONO:
- for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)glyph->bitmap.rows, bitmap_height); ++iy)
- {
- for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)glyph->bitmap.width, bitmap_width); ++ix)
- {
- if (glyph->bitmap.buffer[iy * glyph->bitmap.pitch + ix])
- {
- unsigned char *bitmap_pixel = bitmap_buffer + (letter_y + iy) * bitmap_pitch + (letter_x + ix) * 3;
-
- for (unsigned int j = 0; j < 3; ++j)
- bitmap_pixel[j] = colours[j];
- }
- }
- }
-
- break;
+ if (surface)
+ Backend_DrawGlyph(surface, glyph->backend, letter_x, letter_y, colours);
+ else
+ Backend_DrawGlyphToScreen(glyph->backend, letter_x, letter_y, colours);
}
pen_x += glyph->x_advance;
--- a/src/Font.h
+++ b/src/Font.h
@@ -2,9 +2,11 @@
#include <stddef.h>
+#include "Backends/Rendering.h"
+
typedef struct FontObject FontObject;
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);
-void DrawText(FontObject *font_object, unsigned char *bitmap_buffer, size_t bitmap_pitch, int bitmap_width, int bitmap_height, int x, int y, unsigned long colour, const char *string, size_t string_length);
+void DrawText(FontObject *font_object, Backend_Surface *surface, int x, int y, unsigned long colour, const char *string, size_t string_length);
void UnloadFont(FontObject *font_object);