1 // Copyright (c) Charles J. Cliffe
2 // SPDX-License-Identifier: GPL-2.0+
3 
4 #pragma once
5 
6 #include <map>
7 #include <string>
8 #include <sstream>
9 #include <mutex>
10 #include <atomic>
11 #include "lodepng.h"
12 #include "wx/glcanvas.h"
13 #include "wx/filename.h"
14 #include "wx/stdpaths.h"
15 
16 #include "SpinMutex.h"
17 
18 class GLFontStringCache {
19 public:
20     GLFontStringCache();
21     int drawlen;
22     int vpx, vpy;
23     int pxHeight = 0;
24     float msgWidth = 0.0f;
25     std::atomic_int gc;
26     std::vector<float> gl_vertices;
27     std::vector<float> gl_uv;
28 };
29 
30 class GLFontChar {
31 public:
32     GLFontChar();
33     ~GLFontChar();
34 
35     void setId(int idval);
36 
37     // Returns the code point of the 16bit character, supposely Unicode.
38     int getId() const;
39 
40     void setXOffset(int xofs);
41     int getXOffset();
42 
43     void setYOffset(int yofs);
44     int getYOffset();
45 
46     void setX(int xpos);
47     int getX();
48 
49     void setY(int ypos);
50     int getY();
51 
52     void setWidth(int w);
53     int getWidth();
54 
55     void setHeight(int h);
56     int getHeight() const;
57 
58     void setXAdvance(int xadv);
59     int getXAdvance();
60 
61     float getAspect() const;
62 
63     void setIndex(unsigned int idx);
64     int getIndex() const;
65 
66 private:
67     // this is the code point of the 16bit character, supposly Unicode.
68     int id;
69     int x, y, width, height;
70     int xoffset, yoffset;
71     int xadvance;
72     float aspect;
73     int index;
74 };
75 
76 
77 
78 class GLFont {
79 public:
80 
81     enum Align {
82         GLFONT_ALIGN_LEFT, GLFONT_ALIGN_RIGHT, GLFONT_ALIGN_CENTER, GLFONT_ALIGN_TOP, GLFONT_ALIGN_BOTTOM
83     };
84     enum GLFontSize {
85         GLFONT_SIZE12,
86         GLFONT_SIZE16,
87         GLFONT_SIZE18,
88         GLFONT_SIZE24,
89         GLFONT_SIZE27, //new
90         GLFONT_SIZE32,
91         GLFONT_SIZE36, //new
92         GLFONT_SIZE48,
93         GLFONT_SIZE64, //new
94         GLFONT_SIZE72, //new
95         GLFONT_SIZE96, //new
96         GLFONT_SIZE_MAX
97     };
98 
99     enum GLFontScale {
100         GLFONT_SCALE_NORMAL,
101         GLFONT_SCALE_MEDIUM, // x1.5
102         GLFONT_SCALE_LARGE,  // x2
103         GLFONT_SCALE_MAX
104     };
105 
106     GLFont(GLFontSize size, std::wstring fontFileName);
107     ~GLFont();
108 
109 
110     //Called to change the scale of the rendered fonts
111     static void setScale(GLFontScale scale);
112 
113     static GLFontScale getScale();
114 
115     //Mean current scale factor: 1.0 in normal, 1.5 medium, 2.0 for large
116     static double getScaleFactor();
117 
118     //Return a valid font px height given the font size and scale factor
119     static int getScaledPx(int basicFontSize, double scaleFactor);
120 
121 
122 private:
123 
124     std::wstring nextParam(std::wistringstream &str);
125     std::wstring getParamKey(const std::wstring& param_str);
126     std::wstring getParamValue(const std::wstring& param_str);
127 
128     //Repository of all loaded fonts
129     static GLFont fonts[GLFontSize::GLFONT_SIZE_MAX];
130 
131     static std::atomic<GLFontScale> currentScale;
132 
133     //load a given font file, (lazy loading)
134     void loadFontOnce();
135 
136     //private drawing font, 16 bit char version, called by Drawer object
137     void drawString(const std::wstring& str, int pxHeight, float xpos, float ypos, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx = 0, int vpy = 0, bool cacheable = false);
138 
139     //private drawing font, 8 bit char version, called by Drawer object
140     void drawString(const std::string& str, int pxHeight, float xpos, float ypos, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx = 0, int vpy = 0, bool cacheable = false);
141 
142     GLFontStringCache *cacheString(const std::wstring& str, int pxHeight, int vpx, int vpy);
143     void drawCacheString(GLFontStringCache *fc, float xpos, float ypos, Align hAlign, Align vAlign) const;
144 
145     void doCacheGC();
146     void clearCache();
147 
148     //force GC of all available fonts
149     static void clearAllCaches();
150 
151     float getStringWidth(const std::wstring& str, float size, float viewAspect);
152 
153     //the string cache is per-front (internal font)
154     std::map<std::wstring, GLFontStringCache * > stringCache;
155 
156     int lineHeight;
157     int base;
158     int imageWidth, imageHeight, pixHeight;
159     bool loaded;
160     GLFontSize fontSizeClass;
161 
162     std::map<int, GLFontChar *> characters;
163 
164     std::vector<float> gl_vertices;
165     std::vector<float> gl_uv;
166 
167     //The font name as written in the def file.
168     std::wstring fontName;
169 
170     //The full path font PNG filename
171     std::wstring imageFile;
172 
173     //the real path location of the font definition file
174     std::wstring fontDefFileSource;
175 
176     GLuint texId;
177     int gcCounter;
178     SpinMutex cache_busy;
179 
180 public:
181 
182     //Proxy class computing and caching the selection of the underlying fonts
183     //depending of the user input and requested scale for the fonts.
184     class Drawer {
185 
186     private:
187 
188         //result of the computation
189         int renderingFontIndex = 0;
190 
191         double renderingFontScaleFactor = 1.0;
192 
193     public:
194 
195         Drawer(int basicFontSize, double scaleFactor);
196 
197         //Public drawing font, 16 bit char version.
198         void drawString(const std::wstring& str, float xpos, float ypos, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx = 0, int vpy = 0, bool cacheable = false) const;
199 
200         //Public drawing font, 8 bit char version.
201         void drawString(const std::string& str, float xpos, float ypos, Align hAlign = GLFONT_ALIGN_LEFT, Align vAlign = GLFONT_ALIGN_TOP, int vpx = 0, int vpy = 0, bool cacheable = false) const;
202 
203     }; //end class Drawer
204 
205     //The User request a font of size requestedSize to display, with an additional
206     //optional scale factor scaleFactor.
207     static GLFont::Drawer getFont(int requestedSize, double scaleFactor = 1.0);
208 
209 };
210