1 /*
2 * FTGL - OpenGL font library
3 *
4 * Copyright (c) 2001-2004 Henry Maddocks <ftgl@opengl.geek.nz>
5 * Copyright (c) 2008 Sam Hocevar <sam@hocevar.net>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 #include "config.h"
28
29 #include <cassert>
30 #include <string> // For memset
31
32 #include "FTGL/ftgl.h"
33
34 #include "FTInternals.h"
35
36 #include "../FTGlyph/FTTextureGlyphImpl.h"
37 #include "./FTTextureFontImpl.h"
38 #include "FTGL/FTLibrary.h"
39
40
41 //
42 // FTTextureFont
43 //
44
45
FTTextureFont(char const * fontFilePath)46 FTTextureFont::FTTextureFont(char const *fontFilePath) :
47 FTFont(new FTTextureFontImpl(this, fontFilePath))
48 {}
49
50
FTTextureFont(const unsigned char * pBufferBytes,size_t bufferSizeInBytes)51 FTTextureFont::FTTextureFont(const unsigned char *pBufferBytes,
52 size_t bufferSizeInBytes) :
53 FTFont(new FTTextureFontImpl(this, pBufferBytes, bufferSizeInBytes))
54 {}
55
56
~FTTextureFont()57 FTTextureFont::~FTTextureFont()
58 {}
59
60
MakeGlyph(FT_GlyphSlot ftGlyph)61 FTGlyph* FTTextureFont::MakeGlyph(FT_GlyphSlot ftGlyph)
62 {
63 FTTextureFontImpl *myimpl = dynamic_cast<FTTextureFontImpl *>(impl);
64 if(!myimpl)
65 {
66 return NULL;
67 }
68
69 return myimpl->MakeGlyphImpl(ftGlyph);
70 }
71
72
73 //
74 // FTTextureFontImpl
75 //
76
77
ClampSize(GLuint in,GLuint maxTextureSize)78 static inline GLuint ClampSize(GLuint in, GLuint maxTextureSize)
79 {
80 // Find next power of two
81 --in;
82 in |= in >> 16;
83 in |= in >> 8;
84 in |= in >> 4;
85 in |= in >> 2;
86 in |= in >> 1;
87 ++in;
88
89 // Clamp to max texture size
90 return in < maxTextureSize ? in : maxTextureSize;
91 }
92
93
FTTextureFontImpl(FTFont * ftFont,const char * fontFilePath)94 FTTextureFontImpl::FTTextureFontImpl(FTFont *ftFont, const char* fontFilePath)
95 : FTFontImpl(ftFont, fontFilePath),
96 maximumGLTextureSize(0),
97 textureWidth(0),
98 textureHeight(0),
99 glyphHeight(0),
100 glyphWidth(0),
101 padding(3),
102 xOffset(0),
103 yOffset(0)
104 {
105 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
106 remGlyphs = numGlyphs = face.GlyphCount();
107 }
108
109
FTTextureFontImpl(FTFont * ftFont,const unsigned char * pBufferBytes,size_t bufferSizeInBytes)110 FTTextureFontImpl::FTTextureFontImpl(FTFont *ftFont,
111 const unsigned char *pBufferBytes,
112 size_t bufferSizeInBytes)
113 : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes),
114 maximumGLTextureSize(0),
115 textureWidth(0),
116 textureHeight(0),
117 glyphHeight(0),
118 glyphWidth(0),
119 padding(3),
120 xOffset(0),
121 yOffset(0)
122 {
123 load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
124 remGlyphs = numGlyphs = face.GlyphCount();
125 }
126
127
~FTTextureFontImpl()128 FTTextureFontImpl::~FTTextureFontImpl()
129 {
130 if(textureIDList.size())
131 {
132 glDeleteTextures((GLsizei)textureIDList.size(),
133 (const GLuint*)&textureIDList[0]);
134 }
135 }
136
137
MakeGlyphImpl(FT_GlyphSlot ftGlyph)138 FTGlyph* FTTextureFontImpl::MakeGlyphImpl(FT_GlyphSlot ftGlyph)
139 {
140 glyphHeight = static_cast<int>(charSize.Height() + 0.5f);
141 glyphWidth = static_cast<int>(charSize.Width() + 0.5f);
142
143 if(glyphHeight < 1) glyphHeight = 1;
144 if(glyphWidth < 1) glyphWidth = 1;
145
146 if(textureIDList.empty())
147 {
148 textureIDList.push_back(CreateTexture());
149 xOffset = yOffset = padding;
150 }
151
152 if(xOffset > (textureWidth - glyphWidth))
153 {
154 xOffset = padding;
155 yOffset += glyphHeight;
156
157 if(yOffset > (textureHeight - glyphHeight))
158 {
159 textureIDList.push_back(CreateTexture());
160 yOffset = padding;
161 }
162 }
163
164 FTTextureGlyph* tempGlyph = new FTTextureGlyph(ftGlyph, textureIDList[textureIDList.size() - 1],
165 xOffset, yOffset, textureWidth, textureHeight);
166 xOffset += static_cast<int>(tempGlyph->BBox().Upper().X() - tempGlyph->BBox().Lower().X() + padding + 0.5);
167
168 --remGlyphs;
169
170 return tempGlyph;
171 }
172
173
CalculateTextureSize()174 void FTTextureFontImpl::CalculateTextureSize()
175 {
176 if(!maximumGLTextureSize)
177 {
178 maximumGLTextureSize = 1024;
179 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&maximumGLTextureSize);
180 assert(maximumGLTextureSize); // Indicates an invalid OpenGL context
181 }
182
183 // Texture width required for numGlyphs glyphs. Will probably not be
184 // large enough, but we try to fit as many glyphs in one line as possible
185 textureWidth = ClampSize(glyphWidth * numGlyphs + padding * 2,
186 maximumGLTextureSize);
187
188 // Number of lines required for that many glyphs in a line
189 int tmp = (textureWidth - (padding * 2)) / glyphWidth;
190 tmp = tmp > 0 ? tmp : 1;
191 tmp = (numGlyphs + (tmp - 1)) / tmp; // round division up
192
193 // Texture height required for tmp lines of glyphs
194 textureHeight = ClampSize(glyphHeight * tmp + padding * 2,
195 maximumGLTextureSize);
196 }
197
198
CreateTexture()199 GLuint FTTextureFontImpl::CreateTexture()
200 {
201 CalculateTextureSize();
202
203 int totalMemory = textureWidth * textureHeight;
204 unsigned char* textureMemory = new unsigned char[totalMemory];
205 memset(textureMemory, 0, totalMemory);
206
207 GLuint textID;
208 glGenTextures(1, (GLuint*)&textID);
209
210 glBindTexture(GL_TEXTURE_2D, textID);
211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
212 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
213 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
214 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
215
216 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, textureWidth, textureHeight,
217 0, GL_ALPHA, GL_UNSIGNED_BYTE, textureMemory);
218
219 delete [] textureMemory;
220
221 return textID;
222 }
223
224
FaceSize(const unsigned int size,const unsigned int res)225 bool FTTextureFontImpl::FaceSize(const unsigned int size, const unsigned int res)
226 {
227 if(!textureIDList.empty())
228 {
229 glDeleteTextures((GLsizei)textureIDList.size(), (const GLuint*)&textureIDList[0]);
230 textureIDList.clear();
231 remGlyphs = numGlyphs = face.GlyphCount();
232 }
233
234 return FTFontImpl::FaceSize(size, res);
235 }
236
237
238 template <typename T>
RenderI(const T * string,const int len,FTPoint position,FTPoint spacing,int renderMode)239 inline FTPoint FTTextureFontImpl::RenderI(const T* string, const int len,
240 FTPoint position, FTPoint spacing,
241 int renderMode)
242 {
243 // Protect GL_TEXTURE_2D and optionally GL_BLEND
244 glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TEXTURE_ENV_MODE);
245
246 if(FTLibrary::Instance().GetLegacyOpenGLStateSet())
247 {
248 glEnable(GL_BLEND);
249 /*
250 * Note: This is the historic legacy behaviour.
251 *
252 * A better blending function (see
253 * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=742469) is:
254 *
255 * glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
256 * GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
257 *
258 * To use it, set
259 *
260 * FTLibrary::Instance().LegacyOpenGLState(false);
261 *
262 * and set GL_BLEND and the blending function yourself.
263 */
264 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
265 }
266
267 glEnable(GL_TEXTURE_2D);
268 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
269
270 FTTextureGlyphImpl::ResetActiveTexture();
271
272 FTPoint tmp = FTFontImpl::Render(string, len,
273 position, spacing, renderMode);
274
275 glPopAttrib();
276
277 return tmp;
278 }
279
280
Render(const char * string,const int len,FTPoint position,FTPoint spacing,int renderMode)281 FTPoint FTTextureFontImpl::Render(const char * string, const int len,
282 FTPoint position, FTPoint spacing,
283 int renderMode)
284 {
285 return RenderI(string, len, position, spacing, renderMode);
286 }
287
288
Render(const wchar_t * string,const int len,FTPoint position,FTPoint spacing,int renderMode)289 FTPoint FTTextureFontImpl::Render(const wchar_t * string, const int len,
290 FTPoint position, FTPoint spacing,
291 int renderMode)
292 {
293 return RenderI(string, len, position, spacing, renderMode);
294 }
295
296