| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  | MIT License | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Copyright (c) 2024 - 2025 tobid7 | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  | of this software and associated documentation files (the "Software"), to deal | 
					
						
							|  |  |  | in the Software without restriction, including without limitation the rights | 
					
						
							|  |  |  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
					
						
							|  |  |  | copies of the Software, and to permit persons to whom the Software is | 
					
						
							|  |  |  | furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The above copyright notice and this permission notice shall be included in all | 
					
						
							|  |  |  | copies or substantial portions of the Software. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
					
						
							|  |  |  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
					
						
							|  |  |  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 
					
						
							|  |  |  | SOFTWARE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  | #include <pd/lithium/font.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Due to Limitations of Shared Lib Stuff */ | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  | #ifdef PD_LITHIUM_BUILD_SHARED
 | 
					
						
							|  |  |  | #define STB_TRUETYPE_IMPLEMENTATION
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include <pd/external/stb_truetype.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <pd/lithium/renderer.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-14 20:37:55 +02:00
										 |  |  | #ifdef PD_LI_INCLUDE_FONTS
 | 
					
						
							|  |  |  | #include <pd/lithium/fonts.hpp>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  | namespace PD { | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  | namespace Li { | 
					
						
							| 
									
										
										
										
											2025-08-14 20:37:55 +02:00
										 |  |  | PD_LITHIUM_API void Font::LoadDefaultFont(int id, int pixel_height) { | 
					
						
							|  |  |  | #ifdef PD_LI_INCLUDE_FONTS
 | 
					
						
							|  |  |  |   if (id < pNumFonts) { | 
					
						
							|  |  |  |     auto font = pFontData[id]; | 
					
						
							|  |  |  |     LoadTTF(std::vector<u8>(&pFontsDataRaw[font.StartOff], | 
					
						
							|  |  |  |                             &pFontsDataRaw[font.StartOff + font.Size]), | 
					
						
							|  |  |  |             pixel_height); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  | PD_LITHIUM_API void Font::LoadTTF(const std::string &path, int height) { | 
					
						
							| 
									
										
										
										
											2025-08-14 20:37:55 +02:00
										 |  |  |   /**
 | 
					
						
							|  |  |  |    * Just use LoadFile2Mem which looks way cleaner | 
					
						
							|  |  |  |    * and helps not having the font loading code twice | 
					
						
							|  |  |  |    * when adding LoadTTF with mem support | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |   TT::Scope st("LI_LoadTTF_" + path); | 
					
						
							| 
									
										
										
										
											2025-08-14 20:37:55 +02:00
										 |  |  |   auto font = PD::IO::LoadFile2Mem(path); | 
					
						
							|  |  |  |   LoadTTF(font, height); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  | PD_LITHIUM_API void Font::pMakeAtlas(bool final, std::vector<u8> &font_tex, | 
					
						
							|  |  |  |                                      int texszs, PD::Li::Texture::Ref tex) { | 
					
						
							|  |  |  |   auto t = | 
					
						
							|  |  |  |       Gfx::LoadTex(font_tex, texszs, texszs, Texture::RGBA32, Texture::LINEAR); | 
					
						
							|  |  |  |   tex->CopyFrom(t); | 
					
						
							|  |  |  |   Textures.push_back(tex); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-14 20:37:55 +02:00
										 |  |  | PD_LITHIUM_API void Font::LoadTTF(const std::vector<u8> &data, int height) { | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |   /**
 | 
					
						
							|  |  |  |    * Some additional Info: | 
					
						
							|  |  |  |    * Removed the stbtt get bitmapbox as we dont need to place | 
					
						
							|  |  |  |    * the glyps nicely in the tex. next step would be using the free | 
					
						
							|  |  |  |    * space on the y axis to get mor glyphs inside | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   PixelHeight = height; | 
					
						
							|  |  |  |   int texszs = PD::BitUtil::GetPow2(height * 16); | 
					
						
							|  |  |  |   if (texszs > 1024) { | 
					
						
							|  |  |  |     texszs = 1024;  // Max size
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |   stbtt_fontinfo inf; | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |   if (!stbtt_InitFont(&inf, data.data(), 0)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |   float scale = stbtt_ScaleForPixelHeight(&inf, PixelHeight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int ascent, descent, lineGap; | 
					
						
							|  |  |  |   stbtt_GetFontVMetrics(&inf, &ascent, &descent, &lineGap); | 
					
						
							|  |  |  |   int baseline = static_cast<int>(ascent * scale); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |   // Cache to not render same codepoint tex twice
 | 
					
						
							|  |  |  |   std::map<u32, int> buf_cache; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |   std::vector<u8> font_tex(texszs * texszs * 4, 0); | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |   auto tex = Texture::New(); | 
					
						
							|  |  |  |   fvec2 off; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |   bool empty = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (u32 ii = 0x0000; ii <= 0xFFFF; ii++) { | 
					
						
							|  |  |  |     int gi = stbtt_FindGlyphIndex(&inf, ii); | 
					
						
							|  |  |  |     if (gi == 0) continue; | 
					
						
							|  |  |  |     if (stbtt_IsGlyphEmpty(&inf, gi)) continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     int w = 0, h = 0, xo = 0, yo = 0; | 
					
						
							|  |  |  |     unsigned char *bitmap = | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |         stbtt_GetCodepointBitmap(&inf, scale, scale, ii, &w, &h, &xo, &yo); | 
					
						
							|  |  |  |     if (!bitmap || w <= 0 || h <= 0) { | 
					
						
							|  |  |  |       if (bitmap) free(bitmap); | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     u32 hashed_map = IO::HashMemory(std::vector<u8>(bitmap, bitmap + (w * h))); | 
					
						
							|  |  |  |     if (buf_cache.find(hashed_map) != buf_cache.end()) { | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |       Codepoint c = GetCodepoint(buf_cache[hashed_map]); | 
					
						
							|  |  |  |       c.pCodepoint = ii; | 
					
						
							|  |  |  |       CodeMap[ii] = c; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |       free(bitmap); | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |       buf_cache[hashed_map] = ii; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |     // Next row
 | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     if (off.x + w > texszs) { | 
					
						
							|  |  |  |       off.y += PixelHeight; | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |       off.x = 0.0f; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Bake cause we go out of the tex
 | 
					
						
							|  |  |  |     if (off.y + PixelHeight > texszs) { | 
					
						
							|  |  |  |       pMakeAtlas(false, font_tex, texszs, tex); | 
					
						
							|  |  |  |       tex = Texture::New(); | 
					
						
							|  |  |  |       off = 0; | 
					
						
							|  |  |  |       std::fill(font_tex.begin(), font_tex.end(), 0); | 
					
						
							|  |  |  |       empty = true; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |     // UVs & Codepoint
 | 
					
						
							|  |  |  |     Codepoint c; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     fvec4 uvs; | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |     // cast the ints to floats and not the floats...
 | 
					
						
							|  |  |  |     // dont know where my mind was when creating the code
 | 
					
						
							|  |  |  |     uvs.x = off.x / static_cast<float>(texszs); | 
					
						
							|  |  |  |     uvs.y = off.y / static_cast<float>(texszs); | 
					
						
							|  |  |  |     uvs.z = (off.x + w) / static_cast<float>(texszs); | 
					
						
							|  |  |  |     uvs.w = (off.y + h) / static_cast<float>(texszs); | 
					
						
							|  |  |  |     // Flip if needed
 | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |     if (Gfx::Flags() & LiBackendFlags_FlipUV_Y) { | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |       uvs.y = 1.f - uvs.y; | 
					
						
							|  |  |  |       uvs.w = 1.f - uvs.w; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     c.SimpleUV = uvs; | 
					
						
							|  |  |  |     c.Tex = tex; | 
					
						
							|  |  |  |     c.Size = fvec2(w, h); | 
					
						
							|  |  |  |     c.Offset = baseline + yo; | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |     c.pCodepoint = ii; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (int y = 0; y < h; ++y) { | 
					
						
							|  |  |  |       for (int x = 0; x < w; ++x) { | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |         int map_pos = ((static_cast<int>(off.y) + y) * texszs + | 
					
						
							|  |  |  |                        (static_cast<int>(off.x) + x)) * | 
					
						
							|  |  |  |                       4; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |         font_tex[map_pos + 0] = 255; | 
					
						
							|  |  |  |         font_tex[map_pos + 1] = 255; | 
					
						
							|  |  |  |         font_tex[map_pos + 2] = 255; | 
					
						
							|  |  |  |         font_tex[map_pos + 3] = bitmap[x + y * w]; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |     empty = false; | 
					
						
							|  |  |  |     CodeMap[ii] = c; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     free(bitmap); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |     // offset by 1 (prevents visual glitches i had)
 | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     off.x += w + 1; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (!empty) { | 
					
						
							|  |  |  |     pMakeAtlas(true, font_tex, texszs, tex); | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PD_LITHIUM_API Font::Codepoint &Font::GetCodepoint(u32 cp) { | 
					
						
							|  |  |  |   // Check if codepoijt exist or return a static invalid one
 | 
					
						
							|  |  |  |   auto res = CodeMap.find(cp); | 
					
						
							|  |  |  |   if (res == CodeMap.end()) { | 
					
						
							|  |  |  |     static Codepoint invalid; | 
					
						
							|  |  |  |     invalid.pInvalid = true; | 
					
						
							|  |  |  |     return invalid; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return res->second; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PD_LITHIUM_API fvec2 Font::GetTextBounds(const std::string &text, float scale) { | 
					
						
							|  |  |  |   // Use wstring for exemple for german äöü
 | 
					
						
							|  |  |  |   auto wtext = Strings::MakeWstring(text); | 
					
						
							|  |  |  |   // Create a temp position and offset as [0, 0]
 | 
					
						
							|  |  |  |   fvec2 res; | 
					
						
							|  |  |  |   float x = 0; | 
					
						
							|  |  |  |   // Curent Font Scale
 | 
					
						
							|  |  |  |   float cfs = (DefaultPixelHeight * scale) / (float)PixelHeight; | 
					
						
							|  |  |  |   float lh = (float)PixelHeight * cfs; | 
					
						
							|  |  |  |   size_t index = 0; | 
					
						
							|  |  |  |   for (auto &it : wtext) { | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |     if (it == L'\0') { | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     index++; | 
					
						
							|  |  |  |     auto cp = GetCodepoint(it); | 
					
						
							|  |  |  |     if (cp.pInvalid && it != '\n' && it != '\t' && it != ' ') { | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     switch (it) { | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |       case L'\n': | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |         res.y += lh; | 
					
						
							|  |  |  |         res.x = std::max(res.x, x); | 
					
						
							|  |  |  |         x = 0.f; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |       case L'\t': | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |         x += 16 * cfs; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |       case L' ': | 
					
						
							| 
									
										
										
										
											2025-10-21 08:55:51 +02:00
										 |  |  |         x += 4 * cfs; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |       // Fall trough here to get the same result as in
 | 
					
						
							|  |  |  |       // TextCommand if/else Section
 | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         x += cp.Size.x * cfs; | 
					
						
							|  |  |  |         if (index != wtext.size()) { | 
					
						
							|  |  |  |           x += 2 * cfs; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   res.x = std::max(res.x, x); | 
					
						
							|  |  |  |   res.y += lh; | 
					
						
							|  |  |  |   return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  | PD_LITHIUM_API void Font::CmdTextEx(std::vector<Command::Ref> &cmds, | 
					
						
							|  |  |  |                                     const fvec2 &pos, u32 color, float scale, | 
					
						
							|  |  |  |                                     const std::string &text, LiTextFlags flags, | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |                                     const fvec2 &box) { | 
					
						
							|  |  |  |   fvec2 off; | 
					
						
							|  |  |  |   float cfs = (DefaultPixelHeight * scale) / (float)PixelHeight; | 
					
						
							|  |  |  |   float lh = (float)PixelHeight * cfs; | 
					
						
							|  |  |  |   fvec2 td; | 
					
						
							|  |  |  |   fvec2 rpos = pos; | 
					
						
							|  |  |  |   fvec2 rbox = box; | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |   if (flags & (LiTextFlags_AlignMid | LiTextFlags_AlignRight)) { | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     td = GetTextBounds(text, scale); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |   if (flags & LiTextFlags_AlignMid) { | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     rpos = rbox * 0.5 - td * 0.5 + pos; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |   if (flags & LiTextFlags_AlignRight) { | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     rpos.x = rpos.x - td.x; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::vector<std::string> lines; | 
					
						
							|  |  |  |   std::istringstream iss(text); | 
					
						
							|  |  |  |   std::string tmp; | 
					
						
							|  |  |  |   while (std::getline(iss, tmp)) { | 
					
						
							|  |  |  |     lines.push_back(tmp); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (auto &it : lines) { | 
					
						
							|  |  |  |     /*if (flags & LITextFlags_Short) {
 | 
					
						
							|  |  |  |       fvec2 tmp_dim; | 
					
						
							|  |  |  |       it = ShortText(it, box.x() - pos.x(), tmp_dim); | 
					
						
							|  |  |  |     }*/ | 
					
						
							|  |  |  |     auto wline = Strings::MakeWstring(it); | 
					
						
							|  |  |  |     auto cmd = Command::New(); | 
					
						
							|  |  |  |     auto Tex = GetCodepoint(wline[0]).Tex; | 
					
						
							|  |  |  |     cmd->Tex = Tex; | 
					
						
							|  |  |  |     for (auto &jt : wline) { | 
					
						
							|  |  |  |       auto cp = GetCodepoint(jt); | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |       if ((cp.pInvalid && jt != L' ' && jt != L'\n' && jt != L'\t') && | 
					
						
							|  |  |  |           jt != L'\r') { | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (Tex != cp.Tex) { | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |         cmds.push_back(std::move(cmd)); | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |         cmd = Command::New(); | 
					
						
							|  |  |  |         Tex = cp.Tex; | 
					
						
							|  |  |  |         cmd->Tex = Tex; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |       if (jt == L'\t') { | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |         off.x += 16 * cfs; | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |         if (jt != L' ') { | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |           if (flags & LiTextFlags_Shaddow) { | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |             // Draw
 | 
					
						
							|  |  |  |             Rect rec = Renderer::PrimRect( | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |                 rpos + vec2(off.x + 1, off.y + (cp.Offset * cfs)) + 1, | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |                 cp.Size * cfs, 0.f); | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |             Renderer::CmdQuad(cmd.get(), rec, cp.SimpleUV, 0xff111111); | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |           } | 
					
						
							|  |  |  |           // Draw
 | 
					
						
							|  |  |  |           Rect rec = Renderer::PrimRect( | 
					
						
							|  |  |  |               rpos + off + fvec2(0, (cp.Offset * cfs)), cp.Size * cfs, 0.f); | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |           Renderer::CmdQuad(cmd.get(), rec, cp.SimpleUV, color); | 
					
						
							| 
									
										
										
										
											2025-08-28 21:06:19 +02:00
										 |  |  |           off.x += cp.Size.x * cfs + 2 * cfs; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2025-10-21 08:55:51 +02:00
										 |  |  |           off.x += 4 * cfs; | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  |     cmds.push_back(std::move(cmd)); | 
					
						
							| 
									
										
										
										
											2025-04-24 16:39:24 +02:00
										 |  |  |     off.y += lh; | 
					
						
							|  |  |  |     off.x = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-06-22 21:05:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | }  // namespace Li
 | 
					
						
							| 
									
										
										
										
											2025-10-21 08:55:51 +02:00
										 |  |  | }  // namespace PD
 |