shithub: cstory

Download patch

ref: 90ef30becef2e3ff4bdbaf3f3abd2ad9517d7802
parent: 004d5adf7bef6f20e05b5df6a7b76eceeb9c620c
author: Clownacy <[email protected]>
date: Tue Jan 29 05:18:34 EST 2019

Added option for fonts to be loaded from Windows

This restores some compatibility with Config.dat's font settings.

--- a/Makefile
+++ b/Makefile
@@ -20,8 +20,12 @@
 CXXFLAGS += -DFIX_BUGS
 endif
 
-ifeq ($(CONSOLE), 1)
-CXXFLAGS += -mconsole
+ifeq ($(WINDOWS), 1)
+	ifeq ($(CONSOLE), 1)
+	CXXFLAGS += -mconsole
+	endif
+CXXFLAGS += -DWINDOWS
+LIBS += -lkernel32
 endif
 
 CXXFLAGS += `sdl2-config --cflags` `pkg-config freetype2 --cflags`
--- a/src/Draw.cpp
+++ b/src/Draw.cpp
@@ -4,6 +4,18 @@
 #include <stdio.h>
 #include <stdint.h>
 
+#ifdef WINDOWS
+#define RECT WINRECT
+#define FindResource WinFindResource	// All these damn name collisions...
+#define DrawText WinDrawText
+#define LoadFont WinLoadFont
+#include <windows.h>
+#undef LoadFont
+#undef DrawText
+#undef FindResource
+#undef RECT
+#endif
+
 #include <SDL_render.h>
 #include <SDL_rwops.h>
 #include <SDL_timer.h>
@@ -388,8 +400,55 @@
 	SDL_SetRenderTarget(gRenderer, NULL);
 }
 
-void InitTextObject()
+#ifdef WINDOWS
+static unsigned char* GetFontFromWindows(size_t *data_size, const char *font_name, unsigned int fontWidth, unsigned int fontHeight)
 {
+	unsigned char* buffer = NULL;
+
+#ifdef JAPANESE
+	const DWORD charset = SHIFTJIS_CHARSET;
+#else
+	const DWORD charset = DEFAULT_CHARSET;
+#endif
+
+	HFONT hfont = CreateFontA(fontHeight, fontWidth, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, charset, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_DONTCARE, font_name);
+
+	if (hfont == NULL)
+		hfont = CreateFontA(fontHeight, fontWidth, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, charset, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_DONTCARE, NULL);
+
+	if (hfont != NULL)
+	{
+		HDC hdc = CreateCompatibleDC(NULL);
+
+		if (hdc != NULL)
+		{
+			SelectObject(hdc, hfont);
+			const DWORD size = GetFontData(hdc, 0, 0, NULL, 0);
+
+			if (size != GDI_ERROR)
+			{
+				buffer = new unsigned char[size];
+
+				if (data_size != NULL)
+					*data_size = size;
+
+				if (GetFontData(hdc, 0, 0, buffer, size) != size)
+				{
+					delete[] buffer;
+					buffer = NULL;
+				}
+			}
+
+			DeleteDC(hdc);
+		}
+	}
+
+	return buffer;
+}
+#endif
+
+void InitTextObject(const char *font_name)
+{
 	//Get font size
 	unsigned int fontWidth, fontHeight;
 	if (gWindowScale == 1)
@@ -403,6 +462,24 @@
 		fontHeight = 10 * gWindowScale;
 	}
 	
+#ifdef WINDOWS
+	// Actually use the font Config.dat specifies
+	size_t data_size;
+	unsigned char *data = GetFontFromWindows(&data_size, font_name, fontWidth, fontHeight);
+
+	if (data != NULL)
+	{
+		gFont = LoadFontFromData(data, data_size, fontWidth, fontHeight);
+
+		delete[] data;
+
+		if (gFont)
+			return;
+	}
+#endif
+	// Fall back on the built-in fonts
+	(void)font_name;
+
 	//Open Font.ttf
 	char path[PATH_LENGTH];
 #ifdef JAPANESE
@@ -411,7 +488,7 @@
 	sprintf(path, "%s/cour.ttf", gDataPath);
 #endif
 
-	gFont = LoadFont(fontWidth, fontHeight, path);
+	gFont = LoadFont(path, fontWidth, fontHeight);
 }
 
 void PutText(int x, int y, const char *text, uint32_t color)
--- a/src/Draw.h
+++ b/src/Draw.h
@@ -66,7 +66,7 @@
 void Surface2Surface(int x, int y, RECT *rect, int to, int from);
 void CortBox(RECT *rect, uint32_t col);
 void CortBox2(RECT *rect, uint32_t col, int surf_no);
-void InitTextObject();
+void InitTextObject(const char *font_name);
 void PutText(int x, int y, const char *text, uint32_t color);
 void PutText2(int x, int y, const char *text, uint32_t color, int surf_no);
 void EndTextObject();
--- a/src/Font.cpp
+++ b/src/Font.cpp
@@ -2,7 +2,9 @@
 
 #include <stdbool.h>
 #include <stddef.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #ifdef JAPANESE
 #include <iconv.h>
@@ -27,6 +29,7 @@
 {
 	FT_Library library;
 	FT_Face face;
+	unsigned char *data;
 #ifndef DISABLE_FONT_ANTIALIASING
 	bool lcd_mode;
 #endif
@@ -89,7 +92,7 @@
 	return charcode;
 }
 
-FontObject* LoadFont(unsigned int cell_width, unsigned int cell_height, char *font_filename)
+FontObject* LoadFontFromData(const unsigned char *data, size_t data_size, unsigned int cell_width, unsigned int cell_height)
 {
 	FontObject *font_object = (FontObject*)malloc(sizeof(FontObject));
 
@@ -99,10 +102,19 @@
 	font_object->lcd_mode = FT_Library_SetLcdFilter(font_object->library, FT_LCD_FILTER_DEFAULT) != FT_Err_Unimplemented_Feature;
 #endif
 
-	FT_New_Face(font_object->library, font_filename, 0, &font_object->face);
+	font_object->data = (unsigned char*)malloc(data_size);
+	memcpy(font_object->data, data, data_size);
 
-	unsigned int best_cell_width = 0;
-	unsigned int best_cell_height = 0;
+	FT_Error error = FT_New_Memory_Face(font_object->library, font_object->data, data_size, 0, &font_object->face);
+
+	if (error)
+	{
+		free(font_object->data);
+		FT_Done_FreeType(font_object->library);
+		free(font_object);
+		return NULL;
+	}
+
 	unsigned int best_pixel_width = 0;
 	unsigned int best_pixel_height = 0;
 
@@ -120,15 +132,10 @@
 		else
 		{
 			if (current_cell_width <= cell_width)
-			{
 				best_pixel_width = i;
-				best_cell_width = current_cell_width;
-			}
+
 			if (current_cell_height <= cell_height)
-			{
 				best_pixel_height = i;
-				best_cell_height = current_cell_height;
-			}
 		}
 	}
 
@@ -145,145 +152,176 @@
 	return font_object;
 }
 
+FontObject* LoadFont(const char *font_filename, unsigned int cell_width, unsigned int cell_height)
+{
+	FontObject *font_object = NULL;
+
+	FILE *file = fopen(font_filename, "rb");
+
+	if (file != NULL)
+	{
+		fseek(file, 0, SEEK_END);
+		const size_t file_size = ftell(file);
+		rewind(file);
+		unsigned char *file_buffer = (unsigned char*)malloc(file_size);
+		fread(file_buffer, 1, file_size, file);
+		fclose(file);
+
+		font_object = LoadFontFromData(file_buffer, file_size, cell_width, cell_height);
+
+		free(file_buffer);
+	}
+
+	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)
 {
-	const unsigned char colours[3] = {(unsigned char)(colour >> 16), (unsigned char)(colour >> 8), (unsigned char)colour};
+	if (font_object != NULL)
+	{
+		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);
+		SDL_Texture *old_render_target = SDL_GetRenderTarget(renderer);
+		SDL_SetRenderTarget(renderer, texture);
 
-	int surface_width, surface_height;
-	SDL_GetRendererOutputSize(renderer, &surface_width, &surface_height);
+		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;
+		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;
 
-	FT_Face face = font_object->face;
+		FT_Face face = font_object->face;
 
-	unsigned int pen_x = 0;
+		unsigned int pen_x = 0;
 
-	const unsigned char *string_pointer = (unsigned char*)string;
-	const unsigned char *string_end = (unsigned char*)string + string_length;
+		const unsigned char *string_pointer = (unsigned char*)string;
+		const unsigned char *string_end = (unsigned char*)string + string_length;
 
-	while (string_pointer != string_end)
-	{
+		while (string_pointer != string_end)
+		{
 #ifdef JAPANESE
-		size_t out_size = 4;
-		unsigned char out_buffer[4];	// Max UTF-8 length is four bytes
-		unsigned char *out_pointer = out_buffer;
+			size_t out_size = 4;
+			unsigned char out_buffer[4];	// Max UTF-8 length is four bytes
+			unsigned char *out_pointer = out_buffer;
 
-		size_t in_size = ((*string_pointer >= 0x81 && *string_pointer <= 0x9F) || (*string_pointer >= 0xE0 && *string_pointer <= 0xEF)) ? 2 : 1;
-		unsigned char in_buffer[2];
-		unsigned char *in_pointer = in_buffer;
+			size_t in_size = ((*string_pointer >= 0x81 && *string_pointer <= 0x9F) || (*string_pointer >= 0xE0 && *string_pointer <= 0xEF)) ? 2 : 1;
+			unsigned char in_buffer[2];
+			unsigned char *in_pointer = in_buffer;
 
-		for (size_t i = 0; i < in_size; ++i)
-			in_buffer[i] = string_pointer[i];
+			for (size_t i = 0; i < in_size; ++i)
+				in_buffer[i] = string_pointer[i];
 
-		string_pointer += in_size;
-	
-		iconv(font_object->conv, (char**)&in_pointer, &in_size, (char**)&out_pointer, &out_size);
+			string_pointer += in_size;
 
-		const unsigned long val = UTF8ToCode(out_buffer, NULL);
+			iconv(font_object->conv, (char**)&in_pointer, &in_size, (char**)&out_pointer, &out_size);
+
+			const unsigned long val = UTF8ToCode(out_buffer, NULL);
 #else
-		unsigned int bytes_read;
-		const unsigned long val = UTF8ToCode(string_pointer, &bytes_read);
-		string_pointer += bytes_read;
+			unsigned int bytes_read;
+			const unsigned long val = UTF8ToCode(string_pointer, &bytes_read);
+			string_pointer += bytes_read;
 #endif
 
-		unsigned int glyph_index = FT_Get_Char_Index(face, val);
+			unsigned int glyph_index = FT_Get_Char_Index(face, val);
 
 #ifndef DISABLE_FONT_ANTIALIASING
-		FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | (font_object->lcd_mode ? FT_LOAD_TARGET_LCD : 0));
+			FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | (font_object->lcd_mode ? FT_LOAD_TARGET_LCD : 0));
 #else
-		FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
+			FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
 #endif
 
-		FT_Bitmap converted;
-		FT_Bitmap_New(&converted);
-		FT_Bitmap_Convert(font_object->library, &face->glyph->bitmap, &converted, 1);
+			FT_Bitmap converted;
+			FT_Bitmap_New(&converted);
+			FT_Bitmap_Convert(font_object->library, &face->glyph->bitmap, &converted, 1);
 
-		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_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);
 
-		for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + converted.rows, surface_height); ++iy)
-		{
-			if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD)
+			for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + converted.rows, surface_height); ++iy)
 			{
-				for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width / 3, surface_width); ++ix)
+				if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD)
 				{
-					const unsigned char (*font_buffer)[converted.pitch / 3][3] = (unsigned char (*)[converted.pitch / 3][3])converted.buffer;
+					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width / 3, surface_width); ++ix)
+					{
+						const unsigned char (*font_buffer)[converted.pitch / 3][3] = (unsigned char (*)[converted.pitch / 3][3])converted.buffer;
 
-					const unsigned char *font_pixel = font_buffer[iy][ix];
-					unsigned char *surface_pixel = surface_buffer[letter_y + iy][letter_x + ix];
+						const unsigned char *font_pixel = font_buffer[iy][ix];
+						unsigned char *surface_pixel = surface_buffer[letter_y + iy][letter_x + ix];
 
-					if (font_pixel[0] || font_pixel[1] || font_pixel[2])
-					{
-						for (unsigned int j = 0; j < 3; ++j)
+						if (font_pixel[0] || font_pixel[1] || font_pixel[2])
 						{
-							const double alpha = pow((font_pixel[j] / 255.0), 1.0 / 1.8);			// Gamma correction
-							surface_pixel[j] = (colours[j] * alpha) + (surface_pixel[j] * (1.0 - alpha));	// Alpha blending
-						}
+							for (unsigned int j = 0; j < 3; ++j)
+							{
+								const double alpha = pow((font_pixel[j] / 255.0), 1.0 / 1.8);			// Gamma correction
+								surface_pixel[j] = (colours[j] * alpha) + (surface_pixel[j] * (1.0 - alpha));	// Alpha blending
+							}
 
-						surface_pixel[3] = 0xFF;
+							surface_pixel[3] = 0xFF;
+						}
 					}
 				}
-			}
-			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)
+				else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
 				{
-					unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer;
+					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface_width); ++ix)
+					{
+						unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer;
 
-					const double alpha = pow((double)font_buffer[iy][ix] / (converted.num_grays - 1), 1.0 / 1.8);			// Gamma-corrected
+						const double alpha = pow((double)font_buffer[iy][ix] / (converted.num_grays - 1), 1.0 / 1.8);			// Gamma-corrected
 
-					unsigned char *surface_pixel = surface_buffer[letter_y + iy][letter_x + ix];
+						unsigned char *surface_pixel = surface_buffer[letter_y + iy][letter_x + ix];
 
-					if (alpha)
-					{
-						for (unsigned int j = 0; j < 3; ++j)
-							surface_pixel[j] = (colours[j] * alpha) + (surface_pixel[j] * (1.0 - alpha));	// Alpha blending
+						if (alpha)
+						{
+							for (unsigned int j = 0; j < 3; ++j)
+								surface_pixel[j] = (colours[j] * alpha) + (surface_pixel[j] * (1.0 - alpha));	// Alpha blending
 
-						surface_pixel[3] = 0xFF;
+							surface_pixel[3] = 0xFF;
+						}
 					}
 				}
-			}
-			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)
+				else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
 				{
-					unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer;
+					for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, surface_width); ++ix)
+					{
+						unsigned char (*font_buffer)[converted.pitch] = (unsigned char (*)[converted.pitch])converted.buffer;
 
-					unsigned char *surface_pixel = surface_buffer[letter_y + iy][letter_x + ix];
+						unsigned char *surface_pixel = surface_buffer[letter_y + iy][letter_x + ix];
 
-					if (font_buffer[iy][ix])
-					{
-						for (unsigned int j = 0; j < 3; ++j)
-							surface_pixel[j] = colours[j];
+						if (font_buffer[iy][ix])
+						{
+							for (unsigned int j = 0; j < 3; ++j)
+								surface_pixel[j] = colours[j];
 
-						surface_pixel[3] = 0xFF;
+							surface_pixel[3] = 0xFF;
+						}
 					}
 				}
 			}
-		}
 
-		FT_Bitmap_Done(font_object->library, &converted);
+			FT_Bitmap_Done(font_object->library, &converted);
 
-		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);
+		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);
+	}
 }
 
 void UnloadFont(FontObject *font_object)
 {
+	if (font_object != NULL)
+	{
 #ifdef JAPANESE
-	iconv_close(font_object->conv);
+		iconv_close(font_object->conv);
 #endif
-	FT_Done_Face(font_object->face);
-	FT_Done_FreeType(font_object->library);
+		FT_Done_Face(font_object->face);
+		free(font_object->data);
+		FT_Done_FreeType(font_object->library);
+		free(font_object);
+	}
 }
--- a/src/Font.h
+++ b/src/Font.h
@@ -6,6 +6,7 @@
 
 typedef struct FontObject FontObject;
 
-FontObject* LoadFont(unsigned int cell_width, unsigned int cell_height, char *font_filename);
+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, SDL_Renderer *renderer, SDL_Texture *texture, int x, int y, unsigned long colour, const char *string, size_t string_length);
 void UnloadFont(FontObject *font_object);
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -284,7 +284,7 @@
 				}
 				
 				//Initialize stuff
-				InitTextObject();
+				InitTextObject(config.font_name);
 				InitTriangleTable();
 				
 				//Run game code