ref: fe76fe6dea65ef192b634d71fbe73e2a5eaff9be
parent: febeb1b692f7d3c31a780fe3b6a33de257077165
author: Clownacy <Clownacy@users.noreply.github.com>
date: Wed Sep 16 16:42:11 EDT 2020
Big scary messy unfinished font overhaul This is currently hardcoded to 640x480 English builds. What I've done is temporarily gutted the FreeType2 font renderer, and instead introduced a system where the font is read from a pre-rendered font atlas. This allows me to get 100% accurate font rendering to Windows XP... because I literally created these atlases with Windows XP. So not only does this eliminate the issue of FreeType producing misshapen glyphs, but it also works around the copyright issue regarding bundling the Courier New and MS Gothic fonts with CSE2. You see, font files can be copyrighted like any old software, however typefaces have a lot less protection - they're basically fair-game. IANAL, of course - look it up yourself. I don't really want to throw away the FreeType font system since I spent a ton of time working on it, it allows you to use other font files, and I'll probably wind up needing it for CSE2EX. I guess I'll just have to find some way to either have the two systems coexist, or make it so one or the other can be selected at compile-time.
binary files /dev/null b/game_english/data/Font/couriernew1.PNG differ
binary files /dev/null b/game_english/data/Font/couriernew1.dat differ
binary files /dev/null b/game_english/data/Font/couriernew2.PNG differ
binary files /dev/null b/game_english/data/Font/couriernew2.dat differ
binary files /dev/null b/game_japanese/data/Font/msgothic1.PNG differ
binary files /dev/null b/game_japanese/data/Font/msgothic1.dat differ
binary files /dev/null b/game_japanese/data/Font/msgothic2.PNG differ
binary files /dev/null b/game_japanese/data/Font/msgothic2.dat differ
--- a/src/Backends/Rendering.h
+++ b/src/Backends/Rendering.h
@@ -25,7 +25,7 @@
void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBackend_Rect *rect, unsigned char red, unsigned char green, unsigned char blue);
RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height);
void RenderBackend_DestroyGlyphAtlas(RenderBackend_GlyphAtlas *atlas);
-void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height);
+void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height, size_t pitch);
void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue);
void RenderBackend_DrawGlyph(long x, long y, size_t glyph_x, size_t glyph_y, size_t glyph_width, size_t glyph_height);
void RenderBackend_HandleRenderTargetLoss(void);
--- a/src/Backends/Rendering/SDLTexture.cpp
+++ b/src/Backends/Rendering/SDLTexture.cpp
@@ -341,7 +341,7 @@
free(atlas);
}
-void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height)
+void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height, size_t pitch)
{
unsigned char *buffer = (unsigned char*)malloc(width * height * 4);
@@ -348,14 +348,18 @@
if (buffer != NULL)
{
unsigned char *destination_pointer = buffer;
- const unsigned char *source_pointer = pixels;
- for (size_t i = 0; i < width * height; ++i)
+ for (size_t iy = 0; iy < height; ++iy)
{
- *destination_pointer++ = 0xFF;
- *destination_pointer++ = 0xFF;
- *destination_pointer++ = 0xFF;
- *destination_pointer++ = *source_pointer++;
+ const unsigned char *source_pointer = &pixels[iy * pitch];
+
+ for (size_t ix = 0; ix < width; ++ix)
+ {
+ *destination_pointer++ = 0xFF;
+ *destination_pointer++ = 0xFF;
+ *destination_pointer++ = 0xFF;
+ *destination_pointer++ = *source_pointer++;
+ }
}
SDL_Rect rect;
--- a/src/Bitmap.cpp
+++ b/src/Bitmap.cpp
@@ -6,6 +6,7 @@
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_STATIC
#define STBI_ONLY_BMP
+#define STBI_ONLY_PNG
#define STBI_NO_LINEAR
#define STBI_NO_STDIO
#include "../external/stb_image.h"
@@ -12,10 +13,10 @@
#include "File.h"
-unsigned char* DecodeBitmap(const unsigned char *in_buffer, size_t in_buffer_size, size_t *width, size_t *height)
+unsigned char* DecodeBitmap(const unsigned char *in_buffer, size_t in_buffer_size, size_t *width, size_t *height, unsigned int bytes_per_pixel)
{
int int_width, int_height;
- unsigned char *image_buffer = stbi_load_from_memory(in_buffer, in_buffer_size, &int_width, &int_height, NULL, 3);
+ unsigned char *image_buffer = stbi_load_from_memory(in_buffer, in_buffer_size, &int_width, &int_height, NULL, bytes_per_pixel);
*width = int_width;
*height = int_height;
@@ -23,7 +24,7 @@
return image_buffer;
}
-unsigned char* DecodeBitmapFromFile(const char *path, size_t *width, size_t *height)
+unsigned char* DecodeBitmapFromFile(const char *path, size_t *width, size_t *height, unsigned int bytes_per_pixel)
{
size_t file_size;
unsigned char *file_buffer = LoadFileToMemory(path, &file_size);
@@ -30,7 +31,7 @@
if (file_buffer != NULL)
{
- unsigned char *image_buffer = DecodeBitmap(file_buffer, file_size, width, height);
+ unsigned char *image_buffer = DecodeBitmap(file_buffer, file_size, width, height, bytes_per_pixel);
free(file_buffer);
--- a/src/Bitmap.h
+++ b/src/Bitmap.h
@@ -2,6 +2,6 @@
#include <stddef.h>
-unsigned char* DecodeBitmap(const unsigned char *in_buffer, size_t in_buffer_size, size_t *width, size_t *height);
-unsigned char* DecodeBitmapFromFile(const char *path, size_t *width, size_t *height);
+unsigned char* DecodeBitmap(const unsigned char *in_buffer, size_t in_buffer_size, size_t *width, size_t *height, unsigned int bytes_per_pixel);
+unsigned char* DecodeBitmapFromFile(const char *path, size_t *width, size_t *height, unsigned int bytes_per_pixel);
void FreeBitmap(unsigned char *buffer);
--- a/src/Draw.cpp
+++ b/src/Draw.cpp
@@ -212,7 +212,7 @@
return FALSE;
size_t width, height;
- unsigned char *image_buffer = DecodeBitmap(data, size, &width, &height);
+ unsigned char *image_buffer = DecodeBitmap(data, size, &width, &height, 3);
if (image_buffer == NULL)
return FALSE;
@@ -271,7 +271,7 @@
}
size_t width, height;
- unsigned char *image_buffer = DecodeBitmapFromFile(path.c_str(), &width, &height);
+ unsigned char *image_buffer = DecodeBitmapFromFile(path.c_str(), &width, &height, 3);
if (image_buffer == NULL)
{
@@ -318,7 +318,7 @@
return FALSE;
size_t width, height;
- unsigned char *image_buffer = DecodeBitmap(data, size, &width, &height);
+ unsigned char *image_buffer = DecodeBitmap(data, size, &width, &height, 3);
if (!ScaleAndUploadSurface(image_buffer, width, height, surf_no))
{
@@ -356,7 +356,7 @@
}
size_t width, height;
- unsigned char *image_buffer = DecodeBitmapFromFile(path.c_str(), &width, &height);
+ unsigned char *image_buffer = DecodeBitmapFromFile(path.c_str(), &width, &height, 3);
if (image_buffer == NULL)
{
@@ -705,7 +705,11 @@
#endif
}
- font = LoadFont(path.c_str(), width, height);
+// font = LoadFont(path.c_str(), width, height);
+
+ std::string bitmap_path = gDataPath + "/Font/couriernew2.PNG";
+ std::string metadata_path = gDataPath + "/Font/couriernew2.dat";
+ font = LoadBitmapFont(bitmap_path.c_str(), metadata_path.c_str());
}
void PutText(int x, int y, const char *text, unsigned long color)
--- a/src/Font.cpp
+++ b/src/Font.cpp
@@ -9,6 +9,7 @@
#include FT_FREETYPE_H
#include FT_BITMAP_H
+#include "Bitmap.h"
#include "File.h"
#include "Backends/Rendering.h"
@@ -45,9 +46,18 @@
typedef struct Font
{
+ unsigned char *image_buffer;
+ size_t image_buffer_width;
+ size_t image_buffer_height;
+ size_t glyph_slot_width;
+ size_t glyph_slot_height;
+ size_t total_local_glyphs;
+ Glyph *local_glyphs;
+/*
FT_Library library;
FT_Face face;
unsigned char *data;
+*/
Glyph glyphs[TOTAL_GLYPH_SLOTS];
Glyph *glyph_list_head;
RenderBackend_GlyphAtlas *atlas;
@@ -989,6 +999,34 @@
// Couldn't find glyph - overwrite the old at the end.
// The one at the end hasn't been used in a while anyway.
+ for (size_t i = 0; i < font->total_local_glyphs; ++i)
+ {
+ if (font->local_glyphs[i].unicode_value == unicode_value)
+ {
+ glyph->unicode_value = font->local_glyphs[i].unicode_value;
+ glyph->width = font->local_glyphs[i].width;
+ glyph->height = font->local_glyphs[i].height;
+ glyph->x_offset = font->local_glyphs[i].x_offset;
+ glyph->y_offset = font->local_glyphs[i].y_offset;
+ glyph->x_advance = font->local_glyphs[i].x_advance;
+
+ RenderBackend_UploadGlyph(font->atlas, glyph->x, glyph->y, &font->image_buffer[font->local_glyphs[i].y * font->image_buffer_width + font->local_glyphs[i].x], glyph->width, glyph->height, font->image_buffer_width);
+
+ *glyph_pointer = glyph->next;
+ glyph->next = font->glyph_list_head;
+ font->glyph_list_head = glyph;
+
+ return glyph;
+ }
+ }
+
+
+
+
+
+
+
+/*
unsigned int glyph_index = FT_Get_Char_Index(font->face, unicode_value);
#ifdef ENABLE_FONT_ANTIALIASING
@@ -1053,10 +1091,12 @@
FT_Bitmap_Done(font->library, &bitmap);
}
+*/
return NULL;
}
+/*
Font* LoadFontFromData(const unsigned char *data, size_t data_size, size_t cell_width, size_t cell_height)
{
Font *font = (Font*)malloc(sizeof(Font));
@@ -1133,7 +1173,97 @@
return font;
}
+*/
+Font* LoadBitmapFont(const char *bitmap_path, const char *metadata_path)
+{
+ Font *font = NULL;
+
+ size_t bitmap_width, bitmap_height;
+ unsigned char *image_buffer = DecodeBitmapFromFile(bitmap_path, &bitmap_width, &bitmap_height, 1);
+
+ if (image_buffer != NULL)
+ {
+ size_t metadata_size;
+ unsigned char *metadata_buffer = LoadFileToMemory(metadata_path, &metadata_size);
+
+ if (metadata_buffer != NULL)
+ {
+ font = (Font*)malloc(sizeof(Font));
+
+ if (font != NULL)
+ {
+ font->glyph_slot_width = (metadata_buffer[0] << 8) | metadata_buffer[1];
+ font->glyph_slot_height = (metadata_buffer[2] << 8) | metadata_buffer[3];
+ font->total_local_glyphs = (metadata_buffer[4] << 8) | metadata_buffer[5];
+
+ font->local_glyphs = (Glyph*)malloc(sizeof(Glyph) * font->total_local_glyphs);
+
+ if (font->local_glyphs != NULL)
+ {
+ for (size_t i = 0; i < font->total_local_glyphs; ++i)
+ {
+ font->local_glyphs[i].unicode_value = (metadata_buffer[6 + i * 4 + 0] << 8) | metadata_buffer[6 + i * 4 + 1];
+
+ font->local_glyphs[i].x = (i % (bitmap_width / font->glyph_slot_width)) * font->glyph_slot_width;
+ font->local_glyphs[i].y = (i / (bitmap_width / font->glyph_slot_width)) * font->glyph_slot_height;
+
+ font->local_glyphs[i].width = font->glyph_slot_width;
+ font->local_glyphs[i].height = font->glyph_slot_height;
+
+ font->local_glyphs[i].x_offset = 0;
+ font->local_glyphs[i].y_offset = 0;
+
+ font->local_glyphs[i].x_advance = (metadata_buffer[6 + i * 4 + 2] << 8) | metadata_buffer[6 + i * 4 + 3];
+
+ font->local_glyphs[i].next = NULL;
+ }
+
+ size_t atlas_entry_width = font->glyph_slot_width;
+ size_t atlas_entry_height = font->glyph_slot_height;
+
+ size_t atlas_columns = ceil(sqrt(atlas_entry_width * atlas_entry_height * TOTAL_GLYPH_SLOTS) / atlas_entry_width);
+ size_t atlas_rows = (TOTAL_GLYPH_SLOTS + (atlas_columns - 1)) / atlas_columns;
+
+ font->atlas_row_length = atlas_columns;
+
+ font->atlas = RenderBackend_CreateGlyphAtlas(atlas_columns * atlas_entry_width, atlas_rows * atlas_entry_height);
+
+ if (font->atlas != NULL)
+ {
+ // Initialise the linked-list
+ for (size_t i = 0; i < TOTAL_GLYPH_SLOTS; ++i)
+ {
+ font->glyphs[i].next = (i == 0) ? NULL : &font->glyphs[i - 1];
+
+ font->glyphs[i].x = (i % font->atlas_row_length) * atlas_entry_width;
+ font->glyphs[i].y = (i / font->atlas_row_length) * atlas_entry_height;
+ }
+
+ font->glyph_list_head = &font->glyphs[TOTAL_GLYPH_SLOTS - 1];
+
+ font->image_buffer = image_buffer;
+ font->image_buffer_width = bitmap_width;
+ font->image_buffer_height = bitmap_height;
+
+ free(metadata_buffer);
+
+ return font;
+ }
+ }
+
+ free(font);
+ }
+
+ free(metadata_buffer);
+ }
+
+ FreeBitmap(image_buffer);
+ }
+
+ return font;
+}
+
void DrawText(Font *font, RenderBackend_Surface *surface, int x, int y, unsigned long colour, const char *string)
{
if (font != NULL && surface != NULL)
@@ -1176,9 +1306,11 @@
{
RenderBackend_DestroyGlyphAtlas(font->atlas);
- FT_Done_Face(font->face);
- free(font->data);
- FT_Done_FreeType(font->library);
+ FreeBitmap(font->image_buffer);
+
+// FT_Done_Face(font->face);
+// free(font->data);
+// FT_Done_FreeType(font->library);
free(font);
}
}
--- a/src/Font.h
+++ b/src/Font.h
@@ -6,7 +6,8 @@
typedef struct Font Font;
-Font* LoadFontFromData(const unsigned char *data, size_t data_size, size_t cell_width, size_t cell_height);
-Font* LoadFont(const char *font_filename, size_t cell_width, size_t cell_height);
+//Font* LoadFontFromData(const unsigned char *data, size_t data_size, size_t cell_width, size_t cell_height);
+//Font* LoadFont(const char *font_filename, size_t cell_width, size_t cell_height);
+Font* LoadBitmapFont(const char *bitmap_path, const char *metadata_path);
void DrawText(Font *font, RenderBackend_Surface *surface, int x, int y, unsigned long colour, const char *string);
void UnloadFont(Font *font);
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -295,7 +295,7 @@
if (window_icon_resource_data != NULL)
{
size_t window_icon_width, window_icon_height;
- unsigned char *window_icon_rgb_pixels = DecodeBitmap(window_icon_resource_data, window_icon_resource_size, &window_icon_width, &window_icon_height);
+ unsigned char *window_icon_rgb_pixels = DecodeBitmap(window_icon_resource_data, window_icon_resource_size, &window_icon_width, &window_icon_height, 3);
if (window_icon_rgb_pixels != NULL)
{
@@ -312,7 +312,7 @@
if (cursor_resource_data != NULL)
{
size_t cursor_width, cursor_height;
- unsigned char *cursor_rgb_pixels = DecodeBitmap(cursor_resource_data, cursor_resource_size, &cursor_width, &cursor_height);
+ unsigned char *cursor_rgb_pixels = DecodeBitmap(cursor_resource_data, cursor_resource_size, &cursor_width, &cursor_height, 3);
if (cursor_rgb_pixels != NULL)
{