1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17* misrepresented as being the original software.
18* 3. This notice may not be removed or altered from any source distribution.
19**/
20
21#pragma once
22
23// STD
24#include <unordered_map>
25#include <string>
26#include <vector>
27#include <stddef.h>
28
29// LOVE
30#include "common/config.h"
31#include "common/Object.h"
32#include "common/Matrix.h"
33#include "common/Vector.h"
34
35#include "font/Rasterizer.h"
36#include "Image.h"
37#include "vertex.h"
38#include "Volatile.h"
39
40namespace love
41{
42namespace graphics
43{
44
45class Graphics;
46
47class Font : public Object, public Volatile
48{
49public:
50
51 static love::Type type;
52
53 typedef std::vector<uint32> Codepoints;
54 typedef vertex::XYf_STus_RGBAub GlyphVertex;
55
56 static const vertex::CommonFormat vertexFormat;
57
58 enum AlignMode
59 {
60 ALIGN_LEFT,
61 ALIGN_CENTER,
62 ALIGN_RIGHT,
63 ALIGN_JUSTIFY,
64 ALIGN_MAX_ENUM
65 };
66
67 struct ColoredString
68 {
69 std::string str;
70 Colorf color;
71 };
72
73 struct IndexedColor
74 {
75 Colorf color;
76 int index;
77 };
78
79 struct ColoredCodepoints
80 {
81 std::vector<uint32> cps;
82 std::vector<IndexedColor> colors;
83 };
84
85 struct TextInfo
86 {
87 int width;
88 int height;
89 };
90
91 // Used to determine when to change textures in the generated vertex array.
92 struct DrawCommand
93 {
94 Texture *texture;
95 int startvertex;
96 int vertexcount;
97 };
98
99 Font(love::font::Rasterizer *r, const Texture::Filter &filter);
100
101 virtual ~Font();
102
103 std::vector<DrawCommand> generateVertices(const ColoredCodepoints &codepoints, const Colorf &constantColor, std::vector<GlyphVertex> &vertices,
104 float extra_spacing = 0.0f, Vector2 offset = {}, TextInfo *info = nullptr);
105
106 std::vector<DrawCommand> generateVerticesFormatted(const ColoredCodepoints &text, const Colorf &constantColor, float wrap, AlignMode align,
107 std::vector<GlyphVertex> &vertices, TextInfo *info = nullptr);
108
109 static void getCodepointsFromString(const std::string &str, Codepoints &codepoints);
110 static void getCodepointsFromString(const std::vector<ColoredString> &strs, ColoredCodepoints &codepoints);
111
112 /**
113 * Draws the specified text.
114 **/
115 void print(graphics::Graphics *gfx, const std::vector<ColoredString> &text, const Matrix4 &m, const Colorf &constantColor);
116 void printf(graphics::Graphics *gfx, const std::vector<ColoredString> &text, float wrap, AlignMode align, const Matrix4 &m, const Colorf &constantColor);
117
118 /**
119 * Returns the height of the font.
120 **/
121 float getHeight() const;
122
123 /**
124 * Returns the width of the passed string.
125 *
126 * @param str A string of text.
127 **/
128 int getWidth(const std::string &str);
129
130 /**
131 * Returns the width of the passed glyph.
132 **/
133 int getWidth(uint32 glyph);
134
135 /**
136 * Returns the maximal width of a wrapped string
137 * and optionally the number of lines
138 *
139 * @param text The input text
140 * @param wraplimit The number of pixels to wrap at
141 * @param max_width Optional output of the maximum width
142 * Returns a vector with the lines.
143 **/
144 void getWrap(const std::vector<ColoredString> &text, float wraplimit, std::vector<std::string> &lines, std::vector<int> *line_widths = nullptr);
145 void getWrap(const ColoredCodepoints &codepoints, float wraplimit, std::vector<ColoredCodepoints> &lines, std::vector<int> *line_widths = nullptr);
146
147 /**
148 * Sets the line height (which should be a number to multiply the font size by,
149 * example: line height = 1.2 and size = 12 means that rendered line height = 12*1.2)
150 * @param height The new line height.
151 **/
152 void setLineHeight(float height);
153
154 /**
155 * Returns the line height.
156 **/
157 float getLineHeight() const;
158
159 void setFilter(const Texture::Filter &f);
160 const Texture::Filter &getFilter() const;
161
162 // Extra font metrics
163 int getAscent() const;
164 int getDescent() const;
165 float getBaseline() const;
166
167 bool hasGlyph(uint32 glyph) const;
168 bool hasGlyphs(const std::string &text) const;
169
170 float getKerning(uint32 leftglyph, uint32 rightglyph);
171 float getKerning(const std::string &leftchar, const std::string &rightchar);
172
173 void setFallbacks(const std::vector<Font *> &fallbacks);
174
175 float getDPIScale() const;
176
177 uint32 getTextureCacheID() const;
178
179 // Implements Volatile.
180 bool loadVolatile() override;
181 void unloadVolatile() override;
182
183 static bool getConstant(const char *in, AlignMode &out);
184 static bool getConstant(AlignMode in, const char *&out);
185 static std::vector<std::string> getConstants(AlignMode);
186
187 static int fontCount;
188
189private:
190
191 struct Glyph
192 {
193 Texture *texture;
194 int spacing;
195 GlyphVertex vertices[4];
196 };
197
198 struct TextureSize
199 {
200 int width;
201 int height;
202 };
203
204 void createTexture();
205
206 TextureSize getNextTextureSize() const;
207 love::font::GlyphData *getRasterizerGlyphData(uint32 glyph, float &dpiscale);
208 const Glyph &addGlyph(uint32 glyph);
209 const Glyph &findGlyph(uint32 glyph);
210 void printv(Graphics *gfx, const Matrix4 &t, const std::vector<DrawCommand> &drawcommands, const std::vector<GlyphVertex> &vertices);
211
212 std::vector<StrongRef<love::font::Rasterizer>> rasterizers;
213
214 int height;
215 float lineHeight;
216
217 int textureWidth;
218 int textureHeight;
219
220 std::vector<StrongRef<love::graphics::Image>> images;
221
222 // maps glyphs to glyph texture information
223 std::unordered_map<uint32, Glyph> glyphs;
224
225 // map of left/right glyph pairs to horizontal kerning.
226 std::unordered_map<uint64, float> kerning;
227
228 PixelFormat pixelFormat;
229
230 Texture::Filter filter;
231
232 float dpiScale;
233
234 int textureX, textureY;
235 int rowHeight;
236
237 bool useSpacesAsTab;
238
239 // ID which is incremented when the texture cache is invalidated.
240 uint32 textureCacheID;
241
242 // 1 pixel of transparent padding between glyphs (so quads won't pick up
243 // other glyphs), plus one pixel of transparent padding that the quads will
244 // use, for edge antialiasing.
245 static const int TEXTURE_PADDING = 2;
246
247 // This will be used if the Rasterizer doesn't have a tab character itself.
248 static const int SPACES_PER_TAB = 4;
249
250 static StringMap<AlignMode, ALIGN_MAX_ENUM>::Entry alignModeEntries[];
251 static StringMap<AlignMode, ALIGN_MAX_ENUM> alignModes;
252
253}; // Font
254
255} // graphics
256} // love
257