diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbfa574 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# common +*.pyc +*.swp + +# vs +ipch +*.sdf +*.opensdf +Debug +Release + +# dev libs +lib \ No newline at end of file diff --git a/SDL_FontCache.c b/SDL_FontCache.cpp similarity index 89% rename from SDL_FontCache.c rename to SDL_FontCache.cpp index e98fb3a..ac22771 100644 --- a/SDL_FontCache.c +++ b/SDL_FontCache.cpp @@ -409,14 +409,28 @@ struct FC_Font #ifndef FC_USE_SDL_GPU SDL_Renderer* renderer; #endif - - TTF_Font* ttf_source; // TTF_Font source of characters + + TTF_Font* ttf_source; // TTF_Font source of characters Uint8 owns_ttf_source; // Can we delete the TTF_Font ourselves? FC_FilterEnum filter; - - SDL_Color default_color; + + // foreground + SDL_Color default_color; Uint16 height; + // outline + SDL_Color default_outline_color; + Uint16 outline; + // texture + Uint32 *texture_foreground; + Uint16 textureWidth, textureHeight; + Uint32 *texture_outline; + Uint16 textureOutlineWidth, textureOutlineHeight; + // fallback + FC_Font *fallback; + // style + int style; + int thickness; Uint16 maxWidth; Uint16 baseline; @@ -782,6 +796,67 @@ Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer) return result; } +Uint16 FC_GetCodepoint16FromUTF8(const char** c) { + size_t i = 0; + int utf8size = strlen(*c); + Uint16 uni = 0; + size_t todo; + bool error = false; + unsigned char ch = (*c)[i++]; + + if (ch <= 0x7F) + { + uni = ch; + todo = 0; + } + else if (ch <= 0xBF) + { + return -1; + } + else if (ch <= 0xDF) + { + uni = ch & 0x1F; + todo = 1; + } + else if (ch <= 0xEF) + { + uni = ch & 0x0F; + todo = 2; + } + else if (ch <= 0xF7) + { + uni = ch & 0x07; + todo = 3; + } + else + { + return 0; + } + for (size_t j = 0; j < todo; ++j) + { + if (i == utf8size) + return -1; + unsigned char ch = (*c)[i++]; + if (ch < 0x80 || ch > 0xBF) + return -1; + uni <<= 6; + uni += ch & 0x3F; + } + if (uni >= 0xD800 && uni <= 0xDFFF) + return -1; + if (uni > 0x10FFFF) + return -1; + + /* + * this shouldn't be happened + if (uni > 0xFFFF) { + uni -= 0x10000; + utf16 += (wchar_t)((uni >> 10) + 0xD800); + utf16 += (wchar_t)((uni & 0x3FF) + 0xDC00); + } + */ + return uni; +} void FC_SetLoadingString(FC_Font* font, const char* string) { @@ -1040,14 +1115,79 @@ FC_Font* FC_CreateFont(void) return font; } +SDL_Surface* FC_GetSurface(FC_Font* font, const char* source_string) +{ + // the first thing we should check if there's glyph in this font + // if not, we check for fallback for that glyph. + // if there's no fallback, there's nothing we could do. just go on. + if (TTF_GlyphIsProvided(font->ttf_source, FC_GetCodepoint16FromUTF8(&source_string)) == 0) { + if (font->fallback) + return FC_GetSurface(font->fallback, source_string); + } + + SDL_Surface *glyph_surf, *glyph_surf_outline; + // render basic font first + // this should NOT have outline + TTF_SetFontStyle(font->ttf_source, font->style & ~TTF_STYLE_OUTLINE); + TTF_SetFontOutline(font->ttf_source, 0); + glyph_surf = TTF_RenderUTF8_Blended(font->ttf_source, source_string, font->default_color); + // if original font has thickness + // then none_outline also should be rendered + if (font->thickness) { + TTF_SetFontStyle(font->ttf_source, font->style); + TTF_SetFontOutline(font->ttf_source, font->thickness); + SDL_Surface *glyph_border = TTF_RenderUTF8_Blended(font->ttf_source, source_string, font->default_color); + SDL_Rect src = { 0, 0, glyph_surf->w, glyph_surf->h }; + SDL_Rect dst = { font->thickness / 2 + 1, font->thickness / 2 + 1, glyph_surf->w, glyph_surf->h }; + SDL_BlitSurface(glyph_surf, &src, glyph_border, &dst); + SDL_FreeSurface(glyph_surf); + glyph_surf = glyph_border; + } + // if font has texture then render texture (texture is repeating) + if (font->texture_foreground) { + SDL_LockSurface(glyph_surf); + Uint32 *p = (Uint32*)glyph_surf->pixels; + int tx = 0, ty = 0; + for (int x = 0; x < glyph_surf->w; x++) { + for (int y = 0; y < glyph_surf->h; y++) { + tx = x % font->textureWidth; + ty = y % font->textureHeight; + p[x + y * glyph_surf->w] = + ((p[x + y * glyph_surf->w] & 0xff000000) | (font->texture_foreground[tx + ty * font->textureWidth] & 0x00ffffff)); + } + } + SDL_UnlockSurface(glyph_surf); + } + // if font has outline then render it also + if (font->outline > 0) { + int outlinestyle = font->style | TTF_STYLE_OUTLINE; + int origoutline = TTF_GetFontOutline(font->ttf_source); + TTF_SetFontStyle(font->ttf_source, outlinestyle); + TTF_SetFontOutline(font->ttf_source, origoutline + font->outline); + glyph_surf_outline = TTF_RenderUTF8_Blended(font->ttf_source, source_string, font->default_outline_color); + TTF_SetFontStyle(font->ttf_source, font->style); + TTF_SetFontOutline(font->ttf_source, origoutline); + + + if (glyph_surf_outline) { + // copy glyph_surf to outline surface + SDL_Rect src = { 0, 0, glyph_surf->w, glyph_surf->h }; + SDL_Rect dst = { font->outline / 2 + 1, font->outline / 2 + 1, glyph_surf->w, glyph_surf->h }; + SDL_BlitSurface(glyph_surf, &src, glyph_surf_outline, &dst); + SDL_FreeSurface(glyph_surf); + glyph_surf = glyph_surf_outline; + } + } + return glyph_surf; +} // Assume this many will be enough... #define FC_LOAD_MAX_SURFACES 10 #ifdef FC_USE_SDL_GPU -Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color) +Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, FC_Style *style) #else -Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color) +Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, FC_Style *style) #endif { if(font == NULL || ttf == NULL) @@ -1070,21 +1210,44 @@ Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, S font->renderer = renderer; #endif - - font->ttf_source = ttf; - + + font->ttf_source = ttf; + font->default_color = style->color; + if (style->texture) { + font->texture_foreground = (Uint32*)malloc(sizeof(Uint32) * style->textureWidth * style->textureHeight); + memcpy(font->texture_foreground, style->texture, sizeof(Uint32) * style->textureWidth * style->textureHeight); + font->textureWidth = style->textureWidth; + font->textureHeight = style->textureHeight; + } + font->outline = style->outline; + font->style = style->style; + font->thickness = style->thickness; + font->fallback = style->fallback; + + /* + * before we get height and other attributes, + * set font thickness to get correct font spec + */ + int style_outline; + if (style->thickness || style->outline) { + style_outline = (style->style | TTF_STYLE_OUTLINE); + TTF_SetFontStyle(ttf, style->style); + TTF_SetFontOutline(ttf, style->thickness + style->outline); + } + else { + style_outline = (style->style & ~TTF_STYLE_OUTLINE); + TTF_SetFontStyle(ttf, 0); + } + //font->line_height = TTF_FontLineSkip(ttf); - font->height = TTF_FontHeight(ttf); + font->height = TTF_FontHeight(ttf); font->ascent = TTF_FontAscent(ttf); font->descent = -TTF_FontDescent(ttf); font->baseline = font->height - font->descent; - - font->default_color = color; { SDL_Color white = {255, 255, 255, 255}; - SDL_Surface* glyph_surf; char buff[5]; const char* buff_ptr = buff; const char* source_string; @@ -1108,10 +1271,11 @@ Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, S for(; *source_string != '\0'; source_string = U8_next(source_string)) { if(!U8_charcpy(buff, source_string, 5)) - continue; - glyph_surf = TTF_RenderUTF8_Blended(ttf, buff, white); - if(glyph_surf == NULL) - continue; + continue; + SDL_Surface *glyph_surf = FC_GetSurface(font, buff); + if (glyph_surf == NULL) { + continue; + } // Try packing. If it fails, create a new surface for the next cache level. packed = (FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces-1]->w, surfaces[num_surfaces-1]->h) != NULL); @@ -1172,34 +1336,55 @@ Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL Uint8 FC_LoadFont(FC_Font* font, FC_Target* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style) #endif { - SDL_RWops* rwops; - - if(font == NULL) - return 0; - - rwops = SDL_RWFromFile(filename_ttf, "rb"); - - if(rwops == NULL) - { - FC_Log("Unable to open file for reading: %s \n", SDL_GetError()); - return 0; - } - - #ifdef FC_USE_SDL_GPU - return FC_LoadFont_RW(font, rwops, 1, pointSize, color, style); - #else - return FC_LoadFont_RW(font, renderer, rwops, 1, pointSize, color, style); - #endif + FC_Style FCstyle; + memset(&FCstyle, 0, sizeof(FC_Style)); + FCstyle.style = style; + FCstyle.fontSize = pointSize; + FCstyle.color = color; +#ifdef FC_USE_SDL_GPU + return FC_LoadFontFromStyle(font, filename_ttf, &FCstyle); +#else + return FC_LoadFontFromStyle(font, renderer, filename_ttf, &FCstyle); +#endif } +/* + * custom edit + */ #ifdef FC_USE_SDL_GPU -Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style) +Uint8 FC_LoadFontFromStyle(FC_Font* font, const char* filename_ttf, FC_Style* style) #else -Uint8 FC_LoadFont_RW(FC_Font* font, FC_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style) +Uint8 FC_LoadFontFromStyle(FC_Font* font, FC_Target* renderer, const char* filename_ttf, FC_Style* style) +#endif +{ + SDL_RWops* rwops; + + if (font == NULL) + return 0; + + rwops = SDL_RWFromFile(filename_ttf, "rb"); + + if (rwops == NULL) + { + FC_Log("Unable to open file for reading: %s \n", SDL_GetError()); + return 0; + } + +#ifdef FC_USE_SDL_GPU + return FC_LoadFont_RW(font, rwops, 1, style); +#else + return FC_LoadFont_RW(font, renderer, rwops, 1, style); +#endif +} + +#ifdef FC_USE_SDL_GPU +Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, FC_Style* style) +#else +Uint8 FC_LoadFont_RW(FC_Font* font, FC_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, FC_Style* style) #endif { Uint8 result; - TTF_Font* ttf; + TTF_Font *ttf; Uint8 outline; if(font == NULL) @@ -1213,28 +1398,21 @@ Uint8 FC_LoadFont_RW(FC_Font* font, FC_Target* renderer, SDL_RWops* file_rwops_t return 0; } - ttf = TTF_OpenFontRW(file_rwops_ttf, own_rwops, pointSize); + ttf = TTF_OpenFontRW(file_rwops_ttf, own_rwops, style->fontSize); - if(ttf == NULL) + if (ttf == NULL) { FC_Log("Unable to load TrueType font: %s \n", TTF_GetError()); if(own_rwops) SDL_RWclose(file_rwops_ttf); return 0; } - - outline = (style & TTF_STYLE_OUTLINE); - if(outline) - { - style &= ~TTF_STYLE_OUTLINE; - TTF_SetFontOutline(ttf, 1); - } - TTF_SetFontStyle(ttf, style); + #ifdef FC_USE_SDL_GPU - result = FC_LoadFontFromTTF(font, ttf, color); + result = FC_LoadFontFromTTF(font, ttf, style); #else - result = FC_LoadFontFromTTF(font, renderer, ttf, color); + result = FC_LoadFontFromTTF(font, renderer, ttf, style); #endif // Can only load new (uncached) glyphs if we can keep the SDL_RWops open. @@ -1292,6 +1470,8 @@ void FC_FreeFont(FC_Font* font) // Release resources if(font->owns_ttf_source) TTF_CloseFont(font->ttf_source); + if (font->texture_foreground) + free(font->texture_foreground); // Delete glyph map FC_MapFree(font->glyphs); @@ -1386,7 +1566,7 @@ Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint) SDL_QueryTexture(cache_image, NULL, NULL, &w, &h); #endif - surf = TTF_RenderUTF8_Blended(font->ttf_source, buff, white); + surf = FC_GetSurface(font, buff); //TTF_RenderUTF8_Blended(font->ttf_source, buff, white); if(surf == NULL) { return 0; @@ -1522,7 +1702,8 @@ FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* fo FC_EXTRACT_VARARGS(fc_buffer, formatted_text); - set_color_for_all_caches(font, font->default_color); + /* We don't going to reset texture color */ + //set_color_for_all_caches(font, font->default_color); return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer); } @@ -2203,8 +2384,8 @@ Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...) FC_EXTRACT_VARARGS(fc_buffer, formatted_text); const char* c; - Uint16 width = 0; - Uint16 bigWidth = 0; // Allows for multi-line strings + int width = 0; + int bigWidth = 0; // Allows for multi-line strings for (c = fc_buffer; *c != '\0'; c++) { @@ -2218,11 +2399,12 @@ Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...) FC_GlyphData glyph; Uint32 codepoint = FC_GetCodepointFromUTF8(&c, 1); if(FC_GetGlyphData(font, &glyph, codepoint) || FC_GetGlyphData(font, &glyph, ' ')) - width += glyph.rect.w; + width += glyph.rect.w + font->letterSpacing; } bigWidth = bigWidth >= width? bigWidth : width; + if (bigWidth < 0) bigWidth = 0; - return bigWidth; + return bigWidth - (*fc_buffer ? font->letterSpacing : 0); } // If width == -1, use no width limit @@ -2537,8 +2719,18 @@ void FC_SetDefaultColor(FC_Font* font, SDL_Color color) font->default_color = color; } +void FC_SetFallback(FC_Font* font, FC_Font* fallback) { + font->fallback = fallback; +} +void FC_SetAlphaMod(FC_Font *font, Uint8 a) { + for (int i = 0; i < font->glyph_cache_count; i++) { + SDL_SetTextureAlphaMod(font->glyph_cache[i], a); + } +} - - - +void FC_SetColorMod(FC_Font *font, Uint8 r, Uint8 g, Uint8 b) { + for (int i = 0; i < font->glyph_cache_count; i++) { + SDL_SetTextureColorMod(font->glyph_cache[i], r, g, b); + } +} \ No newline at end of file diff --git a/SDL_FontCache.h b/SDL_FontCache.h index cd0d0e5..6fb5b97 100644 --- a/SDL_FontCache.h +++ b/SDL_FontCache.h @@ -108,7 +108,24 @@ typedef struct FC_GlyphData } FC_GlyphData; +/* + * Color/Texture setting + */ +typedef struct FC_Style +{ + // basic + Uint32 fontSize; + int style; + Uint16 outline; + SDL_Color color; + SDL_Color outline_color; + // advanced + Uint32 *texture; + Uint16 textureWidth, textureHeight; + FC_Font *fallback; + int thickness; +} FC_Style; // Object creation @@ -132,15 +149,19 @@ FC_Font* FC_CreateFont(void); #ifdef FC_USE_SDL_GPU Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style); -Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color); +Uint8 FC_LoadFontFromStyle(FC_Font* font, const char* filename_ttf, FC_Style* style); + +Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, FC_Style* style); -Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style); +Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, TTF_Font *ttf_outline, FC_Style* style); #else Uint8 FC_LoadFont(FC_Font* font, SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style); -Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color); +Uint8 FC_LoadFontFromStyle(FC_Font* font, SDL_Renderer* renderer, const char* filename_ttf, FC_Style* style); -Uint8 FC_LoadFont_RW(FC_Font* font, SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style); +Uint8 FC_LoadFont_RW(FC_Font* font, SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, FC_Style* style); + +Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, FC_Style* style); #endif void FC_ClearFont(FC_Font* font); @@ -167,6 +188,8 @@ Returns the Uint32 codepoint (not UTF-32) parsed from the given UTF-8 string. */ Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer); +Uint16 FC_GetCodepoint16FromUTF8(const char** c); + /*! Parses the given codepoint and stores the UTF-8 bytes in 'result'. The result is NULL terminated. \param result A memory buffer for the UTF-8 values. Must be at least 5 bytes long. @@ -236,8 +259,11 @@ Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint); /*! Sets the glyph data for the given codepoint. Duplicates are not checked. Returns a pointer to the stored data. */ FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data); +FC_GlyphData* FC_SetTextureGlyph(SDL_Texture *texture, SDL_Rect *src, Uint32 codepoint, FC_GlyphData glyph_data); + // Rendering +SDL_Surface* FC_GetSurface(FC_Font* font, const char* source_string); FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...); FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...); @@ -287,6 +313,9 @@ void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter); void FC_SetSpacing(FC_Font* font, int LetterSpacing); void FC_SetLineSpacing(FC_Font* font, int LineSpacing); void FC_SetDefaultColor(FC_Font* font, SDL_Color color); +void FC_SetFallback(FC_Font *font, FC_Font *fallback); +void FC_SetAlphaMod(FC_Font *font, Uint8 a); +void FC_SetColorMod(FC_Font *font, Uint8 r, Uint8 g, Uint8 b); #ifdef __cplusplus diff --git a/SDL_FontCache.sln b/SDL_FontCache.sln new file mode 100644 index 0000000..17f39c0 --- /dev/null +++ b/SDL_FontCache.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL_FontCache", "SDL_FontCache.vcxproj", "{9E9CA300-AEE4-4377-8F60-7F49C2005CCE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9E9CA300-AEE4-4377-8F60-7F49C2005CCE}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E9CA300-AEE4-4377-8F60-7F49C2005CCE}.Debug|Win32.Build.0 = Debug|Win32 + {9E9CA300-AEE4-4377-8F60-7F49C2005CCE}.Release|Win32.ActiveCfg = Release|Win32 + {9E9CA300-AEE4-4377-8F60-7F49C2005CCE}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/SDL_FontCache.v12.suo b/SDL_FontCache.v12.suo new file mode 100644 index 0000000..92b452c Binary files /dev/null and b/SDL_FontCache.v12.suo differ diff --git a/SDL_FontCache.vcxproj b/SDL_FontCache.vcxproj new file mode 100644 index 0000000..2b82ef0 --- /dev/null +++ b/SDL_FontCache.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {9E9CA300-AEE4-4377-8F60-7F49C2005CCE} + Win32Proj + SDL_FontCache + + + + DynamicLibrary + true + v120 + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\lib\$(Configuration)\ + + + false + $(SolutionDir)\lib\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;SDL_FONTCACHE_EXPORTS;%(PreprocessorDefinitions) + ..\SDL\include + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;SDL_FONTCACHE_EXPORTS;%(PreprocessorDefinitions) + ..\SDL\include + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/fonts/NanumGothic.ttf b/test/fonts/NanumGothic.ttf new file mode 100644 index 0000000..009887a Binary files /dev/null and b/test/fonts/NanumGothic.ttf differ diff --git a/test/main.c b/test/main.cpp similarity index 59% rename from test/main.c rename to test/main.cpp index 055ba24..d043ca9 100644 --- a/test/main.c +++ b/test/main.cpp @@ -19,46 +19,46 @@ SDL_Renderer* renderer; void draw_rect(FC_Rect rect, SDL_Color color) { - #ifdef SDL_GPU_VERSION_MAJOR +#ifdef SDL_GPU_VERSION_MAJOR GPU_Rectangle(screen, rect.x, rect.y, rect.x + rect.w - 1, rect.y + rect.h - 1, color); - #else +#else SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); SDL_RenderDrawRect(renderer, &rect); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - #endif +#endif } void fill_rect(FC_Rect rect, SDL_Color color) { - #ifdef SDL_GPU_VERSION_MAJOR +#ifdef SDL_GPU_VERSION_MAJOR GPU_RectangleFilled(screen, rect.x, rect.y, rect.x + rect.w - 1, rect.y + rect.h - 1, color); - #else +#else SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); SDL_RenderFillRect(renderer, &rect); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - #endif +#endif } void set_clip(FC_Rect rect) { - #ifdef SDL_GPU_VERSION_MAJOR +#ifdef SDL_GPU_VERSION_MAJOR GPU_SetClipRect(screen, rect); - #else +#else SDL_RenderSetClipRect(renderer, &rect); - #endif +#endif } void unset_clip() { - #ifdef SDL_GPU_VERSION_MAJOR +#ifdef SDL_GPU_VERSION_MAJOR GPU_UnsetClip(screen); - #else +#else SDL_RenderSetClipRect(renderer, NULL); - #endif +#endif } char* get_string_from_file(const char* filename) @@ -67,24 +67,24 @@ char* get_string_from_file(const char* filename) int size = 0; int i; SDL_RWops* rwops = SDL_RWFromFile(filename, "r"); - + char c; - while(SDL_RWread(rwops, &c, 1, 1) > 0) + while (SDL_RWread(rwops, &c, 1, 1) > 0) { ++size; } - - result = (char*)malloc(size+1); - memset(result, 0, size+1); + + result = (char*)malloc(size + 1); + memset(result, 0, size + 1); SDL_RWseek(rwops, 0, RW_SEEK_SET); - + i = 0; - while(SDL_RWread(rwops, &c, 1, 1) > 0) + while (SDL_RWread(rwops, &c, 1, 1) > 0) { result[i] = c; ++i; } - + SDL_RWclose(rwops); return result; } @@ -94,32 +94,60 @@ void loop_drawSomeText() FC_Font* font = FC_CreateFont(); FC_Font* font2 = FC_CreateFont(); FC_Font* font3 = FC_CreateFont(); - + FC_Font* font_texture = FC_CreateFont(); + FC_Font* font_fallback = FC_CreateFont(); + //FC_SetLoadingString(font, FC_GetStringASCII_Latin1()); - - #ifdef SDL_GPU_VERSION_MAJOR - FC_LoadFont(font, "fonts/FreeSans.ttf", 20, FC_MakeColor(0,0,0,255), TTF_STYLE_NORMAL); - FC_LoadFont(font2, "fonts/FreeSans.ttf", 18, FC_MakeColor(0,200,0,255), TTF_STYLE_NORMAL); - FC_LoadFont(font3, "fonts/FreeSans.ttf", 22, FC_MakeColor(0,0,200,255), TTF_STYLE_NORMAL); - #else - FC_LoadFont(font, renderer, "fonts/FreeSans.ttf", 20, FC_MakeColor(0,0,0,255), TTF_STYLE_NORMAL); - FC_LoadFont(font2, renderer, "fonts/FreeSans.ttf", 18, FC_MakeColor(0,200,0,255), TTF_STYLE_NORMAL); - FC_LoadFont(font3, renderer, "fonts/FreeSans.ttf", 22, FC_MakeColor(0,0,200,255), TTF_STYLE_NORMAL); - #endif + +#ifdef SDL_GPU_VERSION_MAJOR + FC_LoadFont(font, "fonts/FreeSans.ttf", 20, FC_MakeColor(0, 0, 0, 255), TTF_STYLE_NORMAL); + FC_LoadFont(font2, "fonts/FreeSans.ttf", 18, FC_MakeColor(0, 200, 0, 255), TTF_STYLE_NORMAL); + FC_LoadFont(font3, "fonts/FreeSans.ttf", 22, FC_MakeColor(0, 0, 200, 255), TTF_STYLE_NORMAL); +#else + FC_LoadFont(font, renderer, "fonts/FreeSans.ttf", 20, FC_MakeColor(0, 0, 0, 255), TTF_STYLE_NORMAL); + FC_LoadFont(font2, renderer, "fonts/FreeSans.ttf", 18, FC_MakeColor(0, 200, 0, 255), TTF_STYLE_NORMAL); + FC_LoadFont(font3, renderer, "fonts/FreeSans.ttf", 22, FC_MakeColor(0, 0, 200, 255), TTF_STYLE_NORMAL); + + Uint32 t[16] = { 0xffffffff, + 0xffeeffff, + 0xffddffff, + 0xffccffff, + 0xffbbffff, + 0xffaaffff, + 0xff99ffff, + 0xff88ffff, + 0xff77ffff, + 0xff66ffff, + 0xff55ffff, + 0xff44ffff, + 0xff33ffff, + 0xff22ffff, + 0xff11ffff, + 0xff00ffff }; + FC_Style style; + memset(&style, 0, sizeof(FC_Style)); + style.fontSize = 22; style.color = FC_MakeColor(255, 255, 255, 255); style.style = TTF_STYLE_NORMAL; + style.outline = 1; style.outline_color = FC_MakeColor(120, 120, 120, 255); style.thickness = 1; + style.texture = t; style.textureWidth = 1; style.textureHeight = 16; + FC_LoadFontFromStyle(font_texture, renderer, "./fonts/NanumGothic.ttf", &style); + FC_SetSpacing(font_texture, -2); + + FC_LoadFont(font_fallback, renderer, "fonts/NanumGothic.ttf", 18, FC_MakeColor(0, 200, 0, 255), TTF_STYLE_NORMAL); +#endif char* utf8_string = get_string_from_file("utf8_sample.txt"); char input_text[2048]; sprintf(input_text, "Edit this text."); int input_position = U8_strlen(input_text); FC_Rect input_rect; int mode = 0; - - + + float target_w, target_h; - #ifdef SDL_GPU_VERSION_MAJOR +#ifdef SDL_GPU_VERSION_MAJOR GPU_Target* target = screen; target_w = target->w; target_h = target->h; - #else +#else SDL_Renderer* target = renderer; { int w, h; @@ -127,217 +155,224 @@ void loop_drawSomeText() target_w = w; target_h = h; } - #endif - - FC_Rect leftHalf = {0, 0, 3*target_w/4.0f, target_h}; - FC_Rect rightHalf = {leftHalf.w, 0, target_w/4.0f, target_h}; - - FC_Rect box1 = {215, 50, 150, 150}; - FC_Rect box2 = {215, box1.y + box1.h + 50, 150, 150}; - FC_Rect box3 = {215, box2.y + box2.h + 50, 150, 150}; - - SDL_Color black = {0, 0, 0, 255}; - SDL_Color white = {255, 255, 255, 255}; - SDL_Color gray = {0x77, 0x77, 0x77, 255}; - SDL_Color blue = {0, 0, 127, 255}; - +#endif + + FC_Rect leftHalf = { 0, 0, 3 * target_w / 4.0f, target_h }; + FC_Rect rightHalf = { leftHalf.w, 0, target_w / 4.0f, target_h }; + + FC_Rect box1 = { 215, 50, 150, 150 }; + FC_Rect box2 = { 215, box1.y + box1.h + 50, 150, 150 }; + FC_Rect box3 = { 215, box2.y + box2.h + 50, 150, 150 }; + + SDL_Color black = { 0, 0, 0, 255 }; + SDL_Color white = { 255, 255, 255, 255 }; + SDL_Color gray = { 0x77, 0x77, 0x77, 255 }; + SDL_Color blue = { 0, 0, 127, 255 }; + int scroll = 0; - + const Uint8* keystates = SDL_GetKeyboardState(NULL); - + input_rect = FC_MakeRect(rightHalf.x, 175, rightHalf.w, 500); - + SDL_StartTextInput(); - + Uint8 done = 0; - SDL_Event event; - while(!done) - { - while(SDL_PollEvent(&event)) - { - if(event.type == SDL_QUIT) + SDL_Event event; + while (!done) + { + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) done = 1; - else if(event.type == SDL_KEYDOWN) - { - if(event.key.keysym.sym == SDLK_ESCAPE) + else if (event.type == SDL_KEYDOWN) + { + if (event.key.keysym.sym == SDLK_ESCAPE) done = 1; - if(event.key.keysym.sym == SDLK_BACKSPACE) + if (event.key.keysym.sym == SDLK_BACKSPACE) { - U8_strdel(input_text, input_position-1); - + U8_strdel(input_text, input_position - 1); + --input_position; - if(input_position < 0) + if (input_position < 0) input_position = 0; } - else if(event.key.keysym.sym == SDLK_F1) + else if (event.key.keysym.sym == SDLK_F1) { mode++; - if(mode > 1) + if (mode > 1) mode = 0; } - else if(event.key.keysym.sym == SDLK_RETURN) + else if (event.key.keysym.sym == SDLK_RETURN) { U8_strinsert(input_text, input_position, "\n", 2048); input_position++; } - else if(event.key.keysym.sym == SDLK_LEFT) + else if (event.key.keysym.sym == SDLK_LEFT) { --input_position; - if(input_position < 0) + if (input_position < 0) input_position = 0; } - else if(event.key.keysym.sym == SDLK_RIGHT) + else if (event.key.keysym.sym == SDLK_RIGHT) { ++input_position; int len = U8_strlen(input_text); - if(input_position >= len) + if (input_position >= len) input_position = len; } - } - else if(event.type == SDL_TEXTINPUT) - { - if(U8_strinsert(input_text, input_position, event.text.text, 2048)) + } + else if (event.type == SDL_TEXTINPUT) + { + if (U8_strinsert(input_text, input_position, event.text.text, 2048)) input_position += U8_strlen(event.text.text); - } - else if(event.type == SDL_MOUSEBUTTONDOWN) - { - if(FC_InRect(event.button.x, event.button.y, input_rect)) + } + else if (event.type == SDL_MOUSEBUTTONDOWN) + { + if (FC_InRect(event.button.x, event.button.y, input_rect)) { input_position = FC_GetPositionFromOffset(font, event.button.x - input_rect.x, event.button.y - input_rect.y, input_rect.w, FC_ALIGN_LEFT, "%s", input_text); } - } - } - - if(keystates[SDL_SCANCODE_UP]) + } + } + + if (keystates[SDL_SCANCODE_UP]) scroll--; - else if(keystates[SDL_SCANCODE_DOWN]) + else if (keystates[SDL_SCANCODE_DOWN]) scroll++; - - - if(mode == 0 || mode == 1) + + + if (mode == 0 || mode == 1) { fill_rect(leftHalf, white); fill_rect(rightHalf, gray); - + FC_Draw(font2, target, 0, 0, "UTF-8 text: %s", utf8_string); - + FC_SetFallback(font_fallback, font2); + FC_Draw(font_fallback, target, 0, 20, "UTF-8 text(fallback): %s", utf8_string); + FC_SetFallback(font_fallback, 0); + FC_DrawAlign(font, target, rightHalf.x, 5, FC_ALIGN_LEFT, "draw align LEFT"); FC_DrawAlign(font, target, rightHalf.x, 25, FC_ALIGN_CENTER, "draw align CENTER"); FC_DrawAlign(font, target, rightHalf.x, 45, FC_ALIGN_RIGHT, "draw align RIGHT"); - - float time = SDL_GetTicks()/1000.0f; - - FC_DrawColor(font, target, rightHalf.x, 65, FC_MakeColor(128 + 127*sin(time), 128 + 127*sin(time/2), 128 + 127*sin(time/4), 128 + 127*sin(time/8)), "Dynamic colored text"); + + float time = SDL_GetTicks() / 1000.0f; + + FC_DrawColor(font, target, rightHalf.x, 65, FC_MakeColor(128 + 127 * sin(time), 128 + 127 * sin(time / 2), 128 + 127 * sin(time / 4), 128 + 127 * sin(time / 8)), "Dynamic colored text"); FC_Draw(font, target, rightHalf.x, 85, "Multi\nline\ntext"); - + FC_DrawBox(font, target, input_rect, "%s", input_text); draw_rect(FC_MakeRect(input_rect.x, input_rect.y + FC_GetLineHeight(font), FC_GetWidth(font, "%s", input_text), 2), black); - + FC_Rect input_cursor_pos = FC_GetCharacterOffset(font, input_position, input_rect.w, "%s", input_text); - if(SDL_GetTicks()%1000 < 500) + if (SDL_GetTicks() % 1000 < 500) fill_rect(FC_MakeRect(input_rect.x + input_cursor_pos.x, input_rect.y + input_cursor_pos.y, input_cursor_pos.w, input_cursor_pos.h), FC_MakeColor(0, 0, 0, 255)); - + FC_DrawColumn(font, target, 0, 50, 200, "column align LEFT\nColumn text wraps at the width of the column and has no maximum height."); FC_DrawColumnAlign(font, target, 100, 250, 200, FC_ALIGN_CENTER, "column align CENTER\nColumn text wraps at the width of the column and has no maximum height."); FC_DrawColumnAlign(font, target, 200, 450, 200, FC_ALIGN_RIGHT, "column align RIGHT\nColumn text wraps at the width of the column and has no maximum height."); - - + + draw_rect(box1, black); draw_rect(box2, black); draw_rect(box3, black); - + set_clip(box1); - FC_Rect box1a = {box1.x, box1.y - scroll, box1.w, box1.h + scroll}; + FC_Rect box1a = { box1.x, box1.y - scroll, box1.w, box1.h + scroll }; FC_DrawBox(font, target, box1a, "box align LEFT\nBox text wraps at the width of the box and is clipped to the maximum height."); - + set_clip(box2); - FC_Rect box2a = {box2.x, box2.y - scroll, box2.w, box2.h + scroll}; + FC_Rect box2a = { box2.x, box2.y - scroll, box2.w, box2.h + scroll }; FC_DrawBoxAlign(font, target, box2a, FC_ALIGN_CENTER, "box align CENTER\nBox text wraps at the width of the box and is clipped to the maximum height."); - + set_clip(box3); - FC_Rect box3a = {box3.x, box3.y - scroll, box3.w, box3.h + scroll}; + FC_Rect box3a = { box3.x, box3.y - scroll, box3.w, box3.h + scroll }; FC_DrawBoxAlign(font, target, box3a, FC_ALIGN_RIGHT, "box align RIGHT\nBox text wraps at the width of the box and is clipped to the maximum height."); - + unset_clip(); + + FC_Draw(font_texture, target, 400, 450, "Outline & Textured Text"); } - - if(mode == 1) + + if (mode == 1) { fill_rect(leftHalf, blue); fill_rect(rightHalf, blue); - - #ifdef SDL_GPU_VERSION_MAJOR + +#ifdef SDL_GPU_VERSION_MAJOR GPU_Image* image = FC_GetGlyphCacheLevel(font, 0); GPU_SetRGBA(image, 255, 255, 255, 255); - GPU_Blit(image, NULL, screen, image->w/2, image->h/2); - #else + GPU_Blit(image, NULL, screen, image->w / 2, image->h / 2); +#else SDL_Texture* image = FC_GetGlyphCacheLevel(font, 0); - SDL_Rect destrect = {0, 0, 0, 0}; + SDL_Rect destrect = { 0, 0, 0, 0 }; SDL_QueryTexture(image, NULL, NULL, &destrect.w, &destrect.h); SDL_SetTextureColorMod(image, 255, 255, 255); SDL_SetTextureAlphaMod(image, 255); SDL_RenderCopy(renderer, image, NULL, &destrect); - #endif +#endif } - - #ifdef SDL_GPU_VERSION_MAJOR - GPU_Flip(screen); - #else - SDL_RenderPresent(renderer); - #endif - - SDL_Delay(1); - } - - SDL_StopTextInput(); - - free(utf8_string); - FC_FreeFont(font); - FC_FreeFont(font2); - FC_FreeFont(font3); + +#ifdef SDL_GPU_VERSION_MAJOR + GPU_Flip(screen); +#else + SDL_RenderPresent(renderer); +#endif + + SDL_Delay(1); + } + + SDL_StopTextInput(); + + free(utf8_string); + FC_FreeFont(font); + FC_FreeFont(font2); + FC_FreeFont(font3); + FC_FreeFont(font_texture); + FC_FreeFont(font_fallback); } int main(int argc, char* argv[]) { int w = 800; int h = 600; - - #ifdef SDL_GPU_VERSION_MAJOR + +#ifdef SDL_GPU_VERSION_MAJOR screen = GPU_Init(w, h, GPU_DEFAULT_INIT_FLAGS); - if(screen == NULL) - { + if (screen == NULL) + { GPU_LogError("Failed to initialize SDL_gpu.\n"); return 1; } - #else - if(SDL_Init(SDL_INIT_VIDEO) < 0) +#else + if (SDL_Init(SDL_INIT_VIDEO) < 0) { SDL_Log("Failed to initialize SDL.\n"); return 1; } - + window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_SHOWN); - if(window == NULL) + if (window == NULL) { SDL_Log("Failed to create window.\n"); return 2; } - + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC); - if(renderer == NULL) + if (renderer == NULL) { SDL_Log("Failed to create renderer.\n"); return 3; } - #endif - - loop_drawSomeText(); - - #ifdef SDL_GPU_VERSION_MAJOR +#endif + + loop_drawSomeText(); + +#ifdef SDL_GPU_VERSION_MAJOR GPU_Quit(); - #else - SDL_Quit(); - #endif - - return 0; +#else + SDL_Quit(); +#endif + + return 0; } diff --git a/test/utf8_sample.txt b/test/utf8_sample.txt index 910a52a..e9b0cbe 100644 --- a/test/utf8_sample.txt +++ b/test/utf8_sample.txt @@ -1 +1 @@ -Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. \ No newline at end of file +Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.아에이오우あえいおうabcde \ No newline at end of file