add truetype support
This commit is contained in:
parent
37e4822ed5
commit
85e534f2d7
|
@ -95,6 +95,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||||
"src/file_utils.h"
|
"src/file_utils.h"
|
||||||
"src/font_manager.cc"
|
"src/font_manager.cc"
|
||||||
"src/font_manager.h"
|
"src/font_manager.h"
|
||||||
|
"src/freetype_manager.cc"
|
||||||
|
"src/freetype_manager.h"
|
||||||
"src/game_config.cc"
|
"src/game_config.cc"
|
||||||
"src/game_config.h"
|
"src/game_config.h"
|
||||||
"src/game_dialog.cc"
|
"src/game_dialog.cc"
|
||||||
|
@ -374,6 +376,19 @@ target_include_directories(${EXECUTABLE_NAME} PRIVATE ${ZLIB_INCLUDE_DIRS})
|
||||||
target_link_libraries(${EXECUTABLE_NAME} ${SDL2_LIBRARIES})
|
target_link_libraries(${EXECUTABLE_NAME} ${SDL2_LIBRARIES})
|
||||||
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${SDL2_INCLUDE_DIRS})
|
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${SDL2_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
add_subdirectory("third_party/freetype")
|
||||||
|
target_link_libraries(${EXECUTABLE_NAME} ${FREETYPE_LIBRARIES})
|
||||||
|
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${FREETYPE_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
add_subdirectory("third_party/iconv")
|
||||||
|
target_link_libraries(${EXECUTABLE_NAME} ${ICONV_LIBRARIES})
|
||||||
|
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${ICONV_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
message(status "${ZLIB_INCLUDE_DIRS}")
|
||||||
|
message(status "${SDL2_INCLUDE_DIRS}")
|
||||||
|
message(status "${FREETYPE_INCLUDE_DIRS}")
|
||||||
|
message(status "${ICONV_INCLUDE_DIRS}")
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
if(IOS)
|
if(IOS)
|
||||||
install(TARGETS ${EXECUTABLE_NAME} DESTINATION "Payload")
|
install(TARGETS ${EXECUTABLE_NAME} DESTINATION "Payload")
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "memory_manager.h"
|
#include "memory_manager.h"
|
||||||
|
#include "word_wrap.h"
|
||||||
|
|
||||||
// The maximum number of interface fonts.
|
// The maximum number of interface fonts.
|
||||||
#define INTERFACE_FONT_MAX (16)
|
#define INTERFACE_FONT_MAX (16)
|
||||||
|
@ -63,6 +64,7 @@ FontManager gModernFontManager = {
|
||||||
interfaceFontGetLetterSpacingImpl,
|
interfaceFontGetLetterSpacingImpl,
|
||||||
interfaceFontGetBufferSizeImpl,
|
interfaceFontGetBufferSizeImpl,
|
||||||
interfaceFontGetMonospacedCharacterWidthImpl,
|
interfaceFontGetMonospacedCharacterWidthImpl,
|
||||||
|
leagcyWordWrap,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 0x586838
|
// 0x586838
|
||||||
|
|
|
@ -0,0 +1,592 @@
|
||||||
|
#include "font_manager.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "color.h"
|
||||||
|
#include "db.h"
|
||||||
|
#include "memory_manager.h"
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_GLYPH_H
|
||||||
|
#include FT_BITMAP_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "word_wrap.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include "iconv.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
// The maximum number of interface fonts.
|
||||||
|
#define FT_FONT_MAX (16)
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
typedef struct FtFontGlyph {
|
||||||
|
short width;
|
||||||
|
short rows;
|
||||||
|
short left;
|
||||||
|
short top;
|
||||||
|
unsigned char* buffer;
|
||||||
|
} FtFontGlyph;
|
||||||
|
|
||||||
|
typedef struct FtFontDescriptor {
|
||||||
|
FT_Library library;
|
||||||
|
FT_Face face;
|
||||||
|
|
||||||
|
unsigned char* filebuffer;
|
||||||
|
|
||||||
|
int maxHeight;
|
||||||
|
int letterSpacing;
|
||||||
|
int wordSpacing;
|
||||||
|
int lineSpacing;
|
||||||
|
int heightOffset;
|
||||||
|
int warpMode;
|
||||||
|
char encoding[64];
|
||||||
|
|
||||||
|
std::map<uint32_t, FtFontGlyph> map;
|
||||||
|
} FtFontDescriptor;
|
||||||
|
|
||||||
|
static int FtFontLoad(int font);
|
||||||
|
static void FtFontSetCurrentImpl(int font);
|
||||||
|
static int FtFontGetLineHeightImpl();
|
||||||
|
static int FtFontGetStringWidthImpl(const char* string);
|
||||||
|
static int FtFontGetCharacterWidthImpl(int ch);
|
||||||
|
static int FtFontGetMonospacedStringWidthImpl(const char* string);
|
||||||
|
static int FtFontGetLetterSpacingImpl();
|
||||||
|
static int FtFontGetBufferSizeImpl(const char* string);
|
||||||
|
static int FtFontGetMonospacedCharacterWidthImpl();
|
||||||
|
static void FtFontDrawImpl(unsigned char* buf, const char* string, int length, int pitch, int color);
|
||||||
|
|
||||||
|
static int FtFonteWordWrapImpl(const char* string, int width, short* breakpoints, short* breakpointsLengthPtr);
|
||||||
|
// 0x518680
|
||||||
|
static bool gFtFontsInitialized = false;
|
||||||
|
|
||||||
|
// 0x518684
|
||||||
|
static int gFtFontsLength = 0;
|
||||||
|
|
||||||
|
static int knobWidth = 5;
|
||||||
|
static int knobHeight = 7;
|
||||||
|
|
||||||
|
static unsigned char knobDump[35] = {
|
||||||
|
0x34, 0x82, 0xb6, 0x82,
|
||||||
|
0x34, 0x82, 0xb6, 0xb6,
|
||||||
|
0xb6, 0x82, 0xb6, 0xb6,
|
||||||
|
0xb6, 0xb6, 0xb6, 0x82,
|
||||||
|
0xb6, 0xb6, 0xb6, 0x82,
|
||||||
|
0x34, 0x82, 0xb6, 0x82,
|
||||||
|
0x34, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0
|
||||||
|
};
|
||||||
|
|
||||||
|
// 0x518688
|
||||||
|
FontManager gFtFontManager = {
|
||||||
|
100,
|
||||||
|
110,
|
||||||
|
FtFontSetCurrentImpl,
|
||||||
|
FtFontDrawImpl,
|
||||||
|
FtFontGetLineHeightImpl,
|
||||||
|
FtFontGetStringWidthImpl,
|
||||||
|
FtFontGetCharacterWidthImpl,
|
||||||
|
FtFontGetMonospacedStringWidthImpl,
|
||||||
|
FtFontGetLetterSpacingImpl,
|
||||||
|
FtFontGetBufferSizeImpl,
|
||||||
|
FtFontGetMonospacedCharacterWidthImpl,
|
||||||
|
FtFonteWordWrapImpl,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 0x586838
|
||||||
|
static FtFontDescriptor gFtFontDescriptors[FT_FONT_MAX];
|
||||||
|
|
||||||
|
// 0x58E938
|
||||||
|
static int gCurrentFtFont;
|
||||||
|
|
||||||
|
// 0x58E93C
|
||||||
|
static FtFontDescriptor* current;
|
||||||
|
|
||||||
|
static uint32_t output[1024] = {
|
||||||
|
0x0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int LtoU(const char* input, size_t charInPutLen)
|
||||||
|
{
|
||||||
|
if (input[0] == '\x95') {
|
||||||
|
size_t output_size = 1024;
|
||||||
|
iconv_t cd = iconv_open("UCS-4-INTERNAL", current->encoding);
|
||||||
|
char* tmp = (char*)(output + 1);
|
||||||
|
const char* tmp2 = (const char *)(input + 1);
|
||||||
|
charInPutLen -= 1;
|
||||||
|
iconv(cd, &tmp2, &charInPutLen, &tmp, &output_size);
|
||||||
|
iconv_close(cd);
|
||||||
|
|
||||||
|
output[0] = '\x95';
|
||||||
|
return (1024 - output_size) / 4 + 1;
|
||||||
|
} else {
|
||||||
|
size_t output_size = 1024;
|
||||||
|
iconv_t cd = iconv_open("UCS-4-INTERNAL", current->encoding);
|
||||||
|
char* tmp = (char*)output;
|
||||||
|
iconv(cd, &input, &charInPutLen, &tmp, &output_size);
|
||||||
|
iconv_close(cd);
|
||||||
|
|
||||||
|
return (1024 - output_size) / 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UtoL(const char* input, size_t charInPutLen)
|
||||||
|
{
|
||||||
|
size_t output_size = 1024;
|
||||||
|
iconv_t cd = iconv_open(current->encoding, "UCS-4-INTERNAL");
|
||||||
|
char* tmp = (char*)output;
|
||||||
|
iconv(cd, &input, &charInPutLen, &tmp, &output_size);
|
||||||
|
iconv_close(cd);
|
||||||
|
|
||||||
|
return (1024 - output_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FtFontGlyph GetFtFontGlyph(uint32_t unicode)
|
||||||
|
{
|
||||||
|
if (current->map.count(unicode) > 0) {
|
||||||
|
return current->map[unicode];
|
||||||
|
} else {
|
||||||
|
if (unicode == '\x95') {
|
||||||
|
current->map[unicode].left = 0;
|
||||||
|
current->map[unicode].top = current->maxHeight / 2;
|
||||||
|
current->map[unicode].width = knobWidth;
|
||||||
|
current->map[unicode].rows = knobHeight;
|
||||||
|
current->map[unicode].buffer = knobDump;
|
||||||
|
} else {
|
||||||
|
FT_Load_Glyph(current->face, FT_Get_Char_Index(current->face, unicode), FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP);
|
||||||
|
FT_Render_Glyph(current->face->glyph, FT_RENDER_MODE_NORMAL);
|
||||||
|
|
||||||
|
current->map[unicode].left = current->face->glyph->bitmap_left;
|
||||||
|
current->map[unicode].top = current->face->glyph->bitmap_top;
|
||||||
|
current->map[unicode].width = current->face->glyph->bitmap.width;
|
||||||
|
current->map[unicode].rows = current->face->glyph->bitmap.rows;
|
||||||
|
|
||||||
|
int count = current->face->glyph->bitmap.width * current->face->glyph->bitmap.rows;
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
current->map[unicode].buffer = (unsigned char*)internal_malloc_safe(count, __FILE__, __LINE__); // FONTMGR.C, 259
|
||||||
|
memcpy(current->map[unicode].buffer, current->face->glyph->bitmap.buffer, count);
|
||||||
|
} else {
|
||||||
|
current->map[unicode].buffer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current->map[unicode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x441C80
|
||||||
|
int FtFontsInit()
|
||||||
|
{
|
||||||
|
int currentFont = -1;
|
||||||
|
|
||||||
|
for (int font = 0; font < FT_FONT_MAX; font++) {
|
||||||
|
if (FtFontLoad(font) == -1) {
|
||||||
|
gFtFontDescriptors[font].maxHeight = 0;
|
||||||
|
gFtFontDescriptors[font].filebuffer = NULL;
|
||||||
|
} else {
|
||||||
|
++gFtFontsLength;
|
||||||
|
|
||||||
|
if (currentFont == -1) {
|
||||||
|
currentFont = font;
|
||||||
|
}
|
||||||
|
|
||||||
|
gFtFontManager.maxFont = gFtFontsLength + 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentFont == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gFtFontsInitialized = true;
|
||||||
|
|
||||||
|
FtFontSetCurrentImpl(currentFont + 100);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x441CEC
|
||||||
|
void FtFontsExit()
|
||||||
|
{
|
||||||
|
for (int font = 0; font < FT_FONT_MAX; font++) {
|
||||||
|
if (gFtFontDescriptors[font].filebuffer != NULL) {
|
||||||
|
internal_free_safe(gFtFontDescriptors[font].filebuffer, __FILE__, __LINE__); // FONTMGR.C, 124
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: clean up
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x441D20
|
||||||
|
static int FtFontLoad(int font_index)
|
||||||
|
{
|
||||||
|
char string[56];
|
||||||
|
FtFontDescriptor* desc = &(gFtFontDescriptors[font_index]);
|
||||||
|
|
||||||
|
Config config;
|
||||||
|
if (!configInit(&config)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(string, "fonts/%s/font.ini", settings.system.language.c_str());
|
||||||
|
if (!configRead(&config, string, false)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(string, "font%d", font_index);
|
||||||
|
|
||||||
|
if (!configGetInt(&config, string, "maxHeight", &desc->maxHeight)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!configGetInt(&config, string, "lineSpacing", &desc->lineSpacing)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!configGetInt(&config, string, "wordSpacing", &desc->wordSpacing)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!configGetInt(&config, string, "letterSpacing", &desc->letterSpacing)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!configGetInt(&config, string, "heightOffset", &desc->heightOffset)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!configGetInt(&config, string, "warpMode", &desc->warpMode)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char* encoding = NULL;
|
||||||
|
if (!configGetString(&config, string, "encoding", &encoding)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(desc->encoding, encoding);
|
||||||
|
|
||||||
|
char *fontFileName = NULL;
|
||||||
|
if (!configGetString(&config, string, "fileName", &fontFileName)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(string, "fonts/%s/%s", settings.system.language.c_str(), fontFileName);
|
||||||
|
|
||||||
|
File* stream = fileOpen(string, "rb");
|
||||||
|
if (stream == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fileSize = fileGetSize(stream); //19647736
|
||||||
|
|
||||||
|
desc->filebuffer = (unsigned char*)internal_malloc_safe(fileSize, __FILE__, __LINE__); // FONTMGR.C, 259
|
||||||
|
|
||||||
|
int readleft = fileSize;
|
||||||
|
unsigned char* ptr = desc->filebuffer;
|
||||||
|
|
||||||
|
while (readleft > 10000) {
|
||||||
|
int readsize = fileRead(ptr, 1, 10000, stream);
|
||||||
|
if (readsize != 10000) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
readleft -= 10000;
|
||||||
|
ptr += 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileRead(ptr, 1, readleft, stream) != readleft) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Init_FreeType(&(desc->library));
|
||||||
|
FT_New_Memory_Face(desc->library, desc->filebuffer, fileSize, 0, &desc->face);
|
||||||
|
|
||||||
|
FT_Select_Charmap(desc->face, FT_ENCODING_UNICODE);
|
||||||
|
FT_Set_Pixel_Sizes(desc->face, desc->maxHeight, desc->maxHeight);
|
||||||
|
|
||||||
|
fileClose(stream);
|
||||||
|
configFree(&config);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x442120
|
||||||
|
static void FtFontSetCurrentImpl(int font)
|
||||||
|
{
|
||||||
|
if (!gFtFontsInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
font -= 100;
|
||||||
|
|
||||||
|
if (gFtFontDescriptors[font].filebuffer != NULL) {
|
||||||
|
gCurrentFtFont = font;
|
||||||
|
current = &(gFtFontDescriptors[font]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x442168
|
||||||
|
static int FtFontGetLineHeightImpl()
|
||||||
|
{
|
||||||
|
if (!gFtFontsInitialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current->lineSpacing + current->maxHeight + current->heightOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x442188
|
||||||
|
static int FtFontGetStringWidthImpl(const char* string)
|
||||||
|
{
|
||||||
|
if (!gFtFontsInitialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(string) == 1 && string[0] < 0) {
|
||||||
|
return current->wordSpacing;
|
||||||
|
} else {
|
||||||
|
int count;
|
||||||
|
int width = 0;
|
||||||
|
|
||||||
|
count = LtoU((char*)string, strlen(string));
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
uint32_t ch = output[i];
|
||||||
|
|
||||||
|
if (ch == L'\n' || ch == L'\r') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '\x95') {
|
||||||
|
FtFontGlyph g = GetFtFontGlyph(ch);
|
||||||
|
width += g.width + current->letterSpacing + 2;
|
||||||
|
} else if (ch == L' ' || (ch < 256 && ch > 128)) {
|
||||||
|
width += current->wordSpacing + current->letterSpacing;
|
||||||
|
} else {
|
||||||
|
FtFontGlyph g = GetFtFontGlyph(ch);
|
||||||
|
width += g.width + current->letterSpacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x4421DC
|
||||||
|
static int FtFontGetCharacterWidthImpl(int ch)
|
||||||
|
{
|
||||||
|
if (!gFtFontsInitialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current->wordSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x442210
|
||||||
|
static int FtFontGetMonospacedStringWidthImpl(const char* str)
|
||||||
|
{
|
||||||
|
return FtFontGetStringWidthImpl(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x442240
|
||||||
|
static int FtFontGetLetterSpacingImpl()
|
||||||
|
{
|
||||||
|
if (!gFtFontsInitialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current->letterSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x442258
|
||||||
|
static int FtFontGetBufferSizeImpl(const char* str)
|
||||||
|
{
|
||||||
|
if (!gFtFontsInitialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FtFontGetStringWidthImpl(str) * (current->lineSpacing + current->maxHeight + current->heightOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x442278
|
||||||
|
static int FtFontGetMonospacedCharacterWidthImpl()
|
||||||
|
{
|
||||||
|
if (!gFtFontsInitialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current->lineSpacing + current->maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x4422B4
|
||||||
|
static void FtFontDrawImpl(unsigned char* buf, const char* string, int length, int pitch, int color)
|
||||||
|
{
|
||||||
|
if (!gFtFontsInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((color & FONT_SHADOW) != 0) {
|
||||||
|
color &= ~FONT_SHADOW;
|
||||||
|
// NOTE: Other font options preserved. This is different from text font
|
||||||
|
// shadows.
|
||||||
|
FtFontDrawImpl(buf + pitch + 1, string, length, pitch, (color & ~0xFF) | _colorTable[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* palette = _getColorBlendTable(color & 0xFF);
|
||||||
|
int count = LtoU((char*)string, strlen(string));
|
||||||
|
int maxTop = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
uint32_t ch = output[i];
|
||||||
|
|
||||||
|
FtFontGlyph g = GetFtFontGlyph(ch);
|
||||||
|
if (maxTop < g.top)
|
||||||
|
maxTop = g.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
maxTop = current->maxHeight - maxTop;
|
||||||
|
|
||||||
|
unsigned char* ptr = buf;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
uint32_t ch = output[i];
|
||||||
|
|
||||||
|
FtFontGlyph g = GetFtFontGlyph(ch);
|
||||||
|
|
||||||
|
int characterWidth;
|
||||||
|
if (ch == L'\n' || ch == L'\r') {
|
||||||
|
continue;
|
||||||
|
} else if (ch == L' ') {
|
||||||
|
characterWidth = current->wordSpacing;
|
||||||
|
} else if (ch == '\x95') {
|
||||||
|
characterWidth = g.width + 2;
|
||||||
|
} else {
|
||||||
|
characterWidth = g.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* end = ptr + characterWidth + current->letterSpacing;
|
||||||
|
if (end - buf > length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += (current->maxHeight - g.top - maxTop) * pitch;
|
||||||
|
|
||||||
|
unsigned char* glyphDataPtr = g.buffer;
|
||||||
|
|
||||||
|
for (int y = 0; y < g.rows && y < current->maxHeight; y++) {
|
||||||
|
for (int x = 0; x < g.width; x++) {
|
||||||
|
unsigned char byte = *glyphDataPtr++;
|
||||||
|
byte /= 26;
|
||||||
|
|
||||||
|
*ptr++ = palette[(byte << 8) + *ptr];
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += pitch - g.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((color & FONT_UNDERLINE) != 0) {
|
||||||
|
int length = ptr - buf;
|
||||||
|
unsigned char* underlinePtr = buf + pitch * (current->maxHeight - 1);
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
|
*underlinePtr++ = color & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_freeColorBlendTable(color & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int FtFonteWordWrapImpl(const char* string, int width, short* breakpoints, short* breakpointsLengthPtr)
|
||||||
|
{
|
||||||
|
breakpoints[0] = 0;
|
||||||
|
*breakpointsLengthPtr = 1;
|
||||||
|
|
||||||
|
for (int index = 1; index < WORD_WRAP_MAX_COUNT; index++) {
|
||||||
|
breakpoints[index] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontGetStringWidth(string) < width) {
|
||||||
|
breakpoints[*breakpointsLengthPtr] = (short)strlen(string);
|
||||||
|
*breakpointsLengthPtr += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int accum = 0;
|
||||||
|
int prevSpaceOrHyphen = -1;
|
||||||
|
|
||||||
|
int count = LtoU((char*)string, strlen(string));
|
||||||
|
|
||||||
|
int PreCharIndex;
|
||||||
|
|
||||||
|
int uint32Index;
|
||||||
|
int CharIndex = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < count;)
|
||||||
|
{
|
||||||
|
const uint32_t ch = output[i];
|
||||||
|
|
||||||
|
if (ch == L'\n' || ch == L'\r') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FtFontGlyph g = GetFtFontGlyph(ch);
|
||||||
|
|
||||||
|
PreCharIndex = CharIndex;
|
||||||
|
|
||||||
|
if (ch == L' ' || (ch > 128 && ch < 256)) {
|
||||||
|
accum += current->letterSpacing + current->wordSpacing;
|
||||||
|
CharIndex += 1;
|
||||||
|
} else {
|
||||||
|
if (ch == '\x95')
|
||||||
|
accum += current->letterSpacing + g.width + 2;
|
||||||
|
else
|
||||||
|
accum += current->letterSpacing + g.width;
|
||||||
|
|
||||||
|
if ((ch > 0 && ch < 128) || ch == '\x95')
|
||||||
|
CharIndex += 1;
|
||||||
|
else
|
||||||
|
CharIndex += UtoL((char*)(&(output[i])), sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accum <= width) {
|
||||||
|
// NOTE: quests.txt #807 uses extended ascii.
|
||||||
|
if (ch == L' ' || ch == L'-') {
|
||||||
|
prevSpaceOrHyphen = CharIndex;
|
||||||
|
uint32Index = i;
|
||||||
|
} else if (current->warpMode == 1) {
|
||||||
|
prevSpaceOrHyphen = -1;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
if (*breakpointsLengthPtr == WORD_WRAP_MAX_COUNT) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevSpaceOrHyphen != -1) {
|
||||||
|
// Word wrap.
|
||||||
|
breakpoints[*breakpointsLengthPtr] = prevSpaceOrHyphen;
|
||||||
|
|
||||||
|
i = uint32Index + 1;
|
||||||
|
CharIndex = prevSpaceOrHyphen + 1;
|
||||||
|
} else {
|
||||||
|
// Character wrap.
|
||||||
|
breakpoints[*breakpointsLengthPtr] = PreCharIndex;
|
||||||
|
CharIndex = PreCharIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
*breakpointsLengthPtr += 1;
|
||||||
|
prevSpaceOrHyphen = -1;
|
||||||
|
accum = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*breakpointsLengthPtr == WORD_WRAP_MAX_COUNT) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
breakpoints[*breakpointsLengthPtr] = CharIndex;
|
||||||
|
*breakpointsLengthPtr += 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fallout
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef FREETYPE_MANAGER_H
|
||||||
|
#define FREETYPE_MANAGER_H
|
||||||
|
|
||||||
|
#include "text_font.h"
|
||||||
|
|
||||||
|
namespace fallout {
|
||||||
|
|
||||||
|
extern FontManager gFtFontManager;
|
||||||
|
|
||||||
|
int FtFontsInit();
|
||||||
|
void FtFontsExit();
|
||||||
|
|
||||||
|
} // namespace fallout
|
||||||
|
|
||||||
|
#endif /* FONT_MANAGER_H */
|
10
src/game.cc
10
src/game.cc
|
@ -21,6 +21,7 @@
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "endgame.h"
|
#include "endgame.h"
|
||||||
#include "font_manager.h"
|
#include "font_manager.h"
|
||||||
|
#include "freetype_manager.h"
|
||||||
#include "game_dialog.h"
|
#include "game_dialog.h"
|
||||||
#include "game_memory.h"
|
#include "game_memory.h"
|
||||||
#include "game_mouse.h"
|
#include "game_mouse.h"
|
||||||
|
@ -168,8 +169,14 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
||||||
showSplash();
|
showSplash();
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaceFontsInit();
|
if (!FtFontsInit()) {
|
||||||
|
fontManagerAdd(&gFtFontManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!interfaceFontsInit()) {
|
||||||
fontManagerAdd(&gModernFontManager);
|
fontManagerAdd(&gModernFontManager);
|
||||||
|
}
|
||||||
|
|
||||||
fontSetCurrent(font);
|
fontSetCurrent(font);
|
||||||
|
|
||||||
screenshotHandlerConfigure(KEY_F12, gameTakeScreenshot);
|
screenshotHandlerConfigure(KEY_F12, gameTakeScreenshot);
|
||||||
|
@ -461,6 +468,7 @@ void gameExit()
|
||||||
wmWorldMap_exit();
|
wmWorldMap_exit();
|
||||||
partyMembersExit();
|
partyMembersExit();
|
||||||
endgameDeathEndingExit();
|
endgameDeathEndingExit();
|
||||||
|
FtFontsExit();
|
||||||
interfaceFontsExit();
|
interfaceFontsExit();
|
||||||
_windowClose();
|
_windowClose();
|
||||||
messageListRepositoryExit();
|
messageListRepositoryExit();
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "platform_compat.h"
|
#include "platform_compat.h"
|
||||||
|
|
||||||
|
#include "word_wrap.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
// The maximum number of text fonts.
|
// The maximum number of text fonts.
|
||||||
|
@ -62,6 +64,7 @@ FontManager gTextFontManager = {
|
||||||
textFontGetLetterSpacingImpl,
|
textFontGetLetterSpacingImpl,
|
||||||
textFontGetBufferSizeImpl,
|
textFontGetBufferSizeImpl,
|
||||||
textFontGetMonospacedCharacterWidthImpl,
|
textFontGetMonospacedCharacterWidthImpl,
|
||||||
|
leagcyWordWrap,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 0x51E3B0
|
// 0x51E3B0
|
||||||
|
@ -94,6 +97,7 @@ FontManagerGetBufferSizeProc* fontGetBufferSize = NULL;
|
||||||
// 0x51E3D4
|
// 0x51E3D4
|
||||||
FontManagerGetMonospacedCharacterWidth* fontGetMonospacedCharacterWidth = NULL;
|
FontManagerGetMonospacedCharacterWidth* fontGetMonospacedCharacterWidth = NULL;
|
||||||
|
|
||||||
|
FontManageWordWrapProc* wordWrap = NULL;
|
||||||
// 0x6ADB08
|
// 0x6ADB08
|
||||||
static TextFontDescriptor gTextFontDescriptors[TEXT_FONT_MAX];
|
static TextFontDescriptor gTextFontDescriptors[TEXT_FONT_MAX];
|
||||||
|
|
||||||
|
@ -281,6 +285,7 @@ void fontSetCurrent(int font)
|
||||||
fontGetLetterSpacing = fontManager->getLetterSpacingProc;
|
fontGetLetterSpacing = fontManager->getLetterSpacingProc;
|
||||||
fontGetBufferSize = fontManager->getBufferSizeProc;
|
fontGetBufferSize = fontManager->getBufferSizeProc;
|
||||||
fontGetMonospacedCharacterWidth = fontManager->getMonospacedCharacterWidthProc;
|
fontGetMonospacedCharacterWidth = fontManager->getMonospacedCharacterWidthProc;
|
||||||
|
wordWrap = fontManager->wordWrap;
|
||||||
|
|
||||||
gCurrentFont = font;
|
gCurrentFont = font;
|
||||||
|
|
||||||
|
@ -427,5 +432,4 @@ static int textFontGetMonospacedCharacterWidthImpl()
|
||||||
|
|
||||||
return width + gCurrentTextFontDescriptor->letterSpacing;
|
return width + gCurrentTextFontDescriptor->letterSpacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
|
@ -13,6 +13,8 @@ typedef int FontManagerGetLetterSpacingProc();
|
||||||
typedef int FontManagerGetBufferSizeProc(const char* string);
|
typedef int FontManagerGetBufferSizeProc(const char* string);
|
||||||
typedef int FontManagerGetMonospacedCharacterWidth();
|
typedef int FontManagerGetMonospacedCharacterWidth();
|
||||||
|
|
||||||
|
typedef int FontManageWordWrapProc(const char* string, int width, short* breakpoints, short* breakpointsLengthPtr);
|
||||||
|
|
||||||
typedef struct FontManager {
|
typedef struct FontManager {
|
||||||
int minFont;
|
int minFont;
|
||||||
int maxFont;
|
int maxFont;
|
||||||
|
@ -25,6 +27,8 @@ typedef struct FontManager {
|
||||||
FontManagerGetLetterSpacingProc* getLetterSpacingProc;
|
FontManagerGetLetterSpacingProc* getLetterSpacingProc;
|
||||||
FontManagerGetBufferSizeProc* getBufferSizeProc;
|
FontManagerGetBufferSizeProc* getBufferSizeProc;
|
||||||
FontManagerGetMonospacedCharacterWidth* getMonospacedCharacterWidthProc;
|
FontManagerGetMonospacedCharacterWidth* getMonospacedCharacterWidthProc;
|
||||||
|
|
||||||
|
FontManageWordWrapProc* wordWrap;
|
||||||
} FontManager;
|
} FontManager;
|
||||||
|
|
||||||
#define FONT_SHADOW (0x10000)
|
#define FONT_SHADOW (0x10000)
|
||||||
|
@ -43,6 +47,8 @@ extern FontManagerGetLetterSpacingProc* fontGetLetterSpacing;
|
||||||
extern FontManagerGetBufferSizeProc* fontGetBufferSize;
|
extern FontManagerGetBufferSizeProc* fontGetBufferSize;
|
||||||
extern FontManagerGetMonospacedCharacterWidth* fontGetMonospacedCharacterWidth;
|
extern FontManagerGetMonospacedCharacterWidth* fontGetMonospacedCharacterWidth;
|
||||||
|
|
||||||
|
extern FontManageWordWrapProc* wordWrap;
|
||||||
|
|
||||||
int textFontsInit();
|
int textFontsInit();
|
||||||
void textFontsExit();
|
void textFontsExit();
|
||||||
int textFontLoad(int font);
|
int textFontLoad(int font);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
// 0x4BC6F0
|
// 0x4BC6F0
|
||||||
int wordWrap(const char* string, int width, short* breakpoints, short* breakpointsLengthPtr)
|
extern int leagcyWordWrap(const char* string, int width, short* breakpoints, short* breakpointsLengthPtr)
|
||||||
{
|
{
|
||||||
breakpoints[0] = 0;
|
breakpoints[0] = 0;
|
||||||
*breakpointsLengthPtr = 1;
|
*breakpointsLengthPtr = 1;
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace fallout {
|
||||||
|
|
||||||
#define WORD_WRAP_MAX_COUNT (64)
|
#define WORD_WRAP_MAX_COUNT (64)
|
||||||
|
|
||||||
int wordWrap(const char* string, int width, short* breakpoints, short* breakpointsLengthPtr);
|
extern int leagcyWordWrap(const char* string, int width, short* breakpoints, short* breakpointsLengthPtr);
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
SET(BUILD_SHARED_LIBS FALSE)
|
||||||
|
SET(FT_DISABLE_HARFBUZZ ON)
|
||||||
|
SET(FT_DISABLE_PNG ON)
|
||||||
|
SET(FT_DISABLE_BROTLI ON)
|
||||||
|
SET(FT_DISABLE_BZIP2 ON)
|
||||||
|
SET(FT_DISABLE_ZLIB ON)
|
||||||
|
SET(FT_CONFIG_OPTION_USE_ZLIB OFF)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(freetype
|
||||||
|
GIT_REPOSITORY "https://github.com/freetype/freetype"
|
||||||
|
GIT_TAG "VER-2-12-1"
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_GetProperties(freetype)
|
||||||
|
if (NOT freetype_POPULATED)
|
||||||
|
FetchContent_Populate(freetype)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(${freetype_SOURCE_DIR} ${freetype_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
set(FREETYPE_LIBRARIES "freetype" PARENT_SCOPE)
|
||||||
|
set(FREETYPE_INCLUDE_DIRS ${freetype_SOURCE_DIR} ${freetype_BINARY_DIR} PARENT_SCOPE)
|
||||||
|
|
||||||
|
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/ftoption.h" ORIGINAL_FTOPTION_H)
|
||||||
|
file(WRITE "${freetype_BINARY_DIR}/include/freetype/config/ftoption.h" "${ORIGINAL_FTOPTION_H}")
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(iconv
|
||||||
|
GIT_REPOSITORY "https://github.com/sonilyan/libiconv_for_fallout2ce.git"
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_GetProperties(iconv)
|
||||||
|
if (NOT iconv_POPULATED)
|
||||||
|
FetchContent_Populate(iconv)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(${iconv_SOURCE_DIR} ${iconv_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
set(ICONV_LIBRARIES "iconv-static" PARENT_SCOPE)
|
||||||
|
set(ICONV_INCLUDE_DIRS ${iconv_SOURCE_DIR} ${iconv_BINARY_DIR}/include PARENT_SCOPE)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue