1 /* QuesoGLC
2 * A free implementation of the OpenGL Character Renderer (GLC)
3 * Copyright (c) 2002, 2004-2008, Bertrand Coconnier
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 /* $Id: ofont.c 848 2008-11-02 12:56:00Z bcoconni $ */
20
21 /* Defines the methods of an object that is intended to managed fonts */
22
23 /** \file
24 * defines the object __GLCfont which manage the fonts
25 */
26
27 #include <math.h>
28 #include "internal.h"
29
30
31
32 /* Constructor of the object : it allocates memory and initializes the member
33 * of the new object.
34 * The user must give the master 'inParent' which the font will instantiate.
35 */
__glcFontCreate(GLint inID,__GLCmaster * inMaster,__GLCcontext * inContext,GLint inCode)36 __GLCfont* __glcFontCreate(GLint inID, __GLCmaster* inMaster,
37 __GLCcontext* inContext, GLint inCode)
38 {
39 __GLCfont *This = NULL;
40
41 assert(inContext);
42
43 This = (__GLCfont*)__glcMalloc(sizeof(__GLCfont));
44 if (!This) {
45 __glcRaiseError(GLC_RESOURCE_ERROR);
46 return NULL;
47 }
48
49 if (inMaster) {
50 /* At font creation, the default face is the first one.
51 * glcFontFace() can change the face.
52 */
53 This->faceDesc = __glcFaceDescCreate(inMaster, NULL, inContext, inCode);
54 if (!This->faceDesc) {
55 __glcFree(This);
56 return NULL;
57 }
58
59 This->charMap = __glcFaceDescGetCharMap(This->faceDesc, inContext);
60 if (!This->charMap) {
61 __glcFaceDescDestroy(This->faceDesc, inContext);
62 __glcFree(This);
63 return NULL;
64 }
65
66 This->parentMasterID = __glcMasterGetID(inMaster, inContext);
67 }
68 else {
69 /* Creates an empty font (used by glcGenFontID() to reserve font IDs) */
70 This->faceDesc = NULL;
71 This->charMap = NULL;
72 This->parentMasterID = 0;
73 }
74
75 This->id = inID;
76
77 return This;
78 }
79
80
81
82 /* Destructor of the object */
__glcFontDestroy(__GLCfont * This,__GLCcontext * inContext)83 void __glcFontDestroy(__GLCfont *This, __GLCcontext* inContext)
84 {
85 if (This->charMap)
86 __glcCharMapDestroy(This->charMap);
87
88 if (This->faceDesc)
89 __glcFaceDescDestroy(This->faceDesc, inContext);
90
91 __glcFree(This);
92 }
93
94
95
96 /* Extract from the font the glyph which corresponds to the character code
97 * 'inCode'.
98 */
__glcFontGetGlyph(__GLCfont * This,GLint inCode,__GLCcontext * inContext)99 __GLCglyph* __glcFontGetGlyph(__GLCfont *This, GLint inCode,
100 __GLCcontext* inContext)
101 {
102 /* Try to get the glyph from the character map */
103 __GLCglyph* glyph = __glcCharMapGetGlyph(This->charMap, inCode);
104
105 if (!glyph) {
106 /* If it fails, we must extract the glyph from the face */
107 glyph = __glcFaceDescGetGlyph(This->faceDesc, inCode, inContext);
108 if (!glyph)
109 return NULL;
110
111 /* Update the character map so that the glyph will be cached */
112 __glcCharMapAddChar(This->charMap, inCode, glyph);
113 }
114
115 return glyph;
116 }
117
118
119
120 /* Get the bounding box of a glyph according to the size given by inScaleX and
121 * inScaleY. The result is returned in outVec. 'inCode' contains the character
122 * code for which the bounding box is requested.
123 */
__glcFontGetBoundingBox(__GLCfont * This,GLint inCode,GLfloat * outVec,__GLCcontext * inContext,GLfloat inScaleX,GLfloat inScaleY)124 GLfloat* __glcFontGetBoundingBox(__GLCfont *This, GLint inCode,
125 GLfloat* outVec, __GLCcontext* inContext,
126 GLfloat inScaleX, GLfloat inScaleY)
127 {
128 /* Get the glyph from the font */
129 __GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
130
131 assert(outVec);
132
133 if (!glyph)
134 return NULL;
135
136 /* If the bounding box of the glyph is cached then copy it to outVec and
137 * return.
138 */
139 if (glyph->boundingBoxCached && inContext->enableState.glObjects) {
140 memcpy(outVec, glyph->boundingBox, 4 * sizeof(GLfloat));
141 return outVec;
142 }
143
144 /* Otherwise, we must extract the bounding box from the face file */
145 if (!__glcFaceDescGetBoundingBox(This->faceDesc, glyph->index, outVec,
146 inScaleX, inScaleY, inContext))
147 return NULL;
148
149 /* Special case for glyphes which have no bounding box (i.e. spaces) */
150 if ((fabs(outVec[0] - outVec[2]) < GLC_EPSILON)
151 || (fabs(outVec[1] - outVec[3]) < GLC_EPSILON)) {
152 GLfloat advance[2] = {0.f, 0.f};
153
154 if (__glcFontGetAdvance(This, inCode, advance, inContext, inScaleX,
155 inScaleY)) {
156 if (fabs(outVec[0] - outVec[2]) < GLC_EPSILON)
157 outVec[2] += advance[0];
158
159 if (fabs(outVec[1] - outVec[3]) < GLC_EPSILON)
160 outVec[3] += advance[1];
161 }
162 }
163
164 /* Copy the result to outVec and return */
165 if (inContext->enableState.glObjects) {
166 memcpy(glyph->boundingBox, outVec, 4 * sizeof(GLfloat));
167 glyph->boundingBoxCached = GL_TRUE;
168 }
169
170 return outVec;
171 }
172
173
174
175 /* Get the advance of a glyph according to the size given by inScaleX and
176 * inScaleY. The result is returned in outVec. 'inCode' contains the character
177 * code for which the advance is requested.
178 */
__glcFontGetAdvance(__GLCfont * This,GLint inCode,GLfloat * outVec,__GLCcontext * inContext,GLfloat inScaleX,GLfloat inScaleY)179 GLfloat* __glcFontGetAdvance(__GLCfont* This, GLint inCode, GLfloat* outVec,
180 __GLCcontext* inContext, GLfloat inScaleX,
181 GLfloat inScaleY)
182 {
183 /* Get the glyph from the font */
184 __GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
185
186 assert(outVec);
187
188 if (!glyph)
189 return NULL;
190
191 /* If the advance of the glyph is cached then copy it to outVec and
192 * return.
193 */
194 if (glyph->advanceCached && inContext->enableState.glObjects) {
195 memcpy(outVec, glyph->advance, 2 * sizeof(GLfloat));
196 return outVec;
197 }
198
199 /* Otherwise, we must extract the advance from the face file */
200 if (!__glcFaceDescGetAdvance(This->faceDesc, glyph->index, outVec, inScaleX,
201 inScaleY, inContext))
202 return NULL;
203
204 /* Copy the result to outVec and return */
205 if (inContext->enableState.glObjects) {
206 memcpy(glyph->advance, outVec, 2 * sizeof(GLfloat));
207 glyph->advanceCached = GL_TRUE;
208 }
209
210 return outVec;
211 }
212
213
214
215 /* Get the kerning information of a pair of glyph according to the size given by
216 * inScaleX and inScaleY. The result is returned in outVec. 'inCode' contains
217 * the current character code and 'inPrevCode' the character code of the
218 * previously displayed character.
219 */
__glcFontGetKerning(__GLCfont * This,GLint inCode,GLint inPrevCode,GLfloat * outVec,__GLCcontext * inContext,GLfloat inScaleX,GLfloat inScaleY)220 GLfloat* __glcFontGetKerning(__GLCfont* This, GLint inCode, GLint inPrevCode,
221 GLfloat* outVec, __GLCcontext* inContext,
222 GLfloat inScaleX, GLfloat inScaleY)
223 {
224 __GLCglyph* glyph = __glcFontGetGlyph(This, inCode, inContext);
225 __GLCglyph* prevGlyph = __glcFontGetGlyph(This, inPrevCode, inContext);
226
227 if (!glyph || !prevGlyph)
228 return NULL;
229
230 return __glcFaceDescGetKerning(This->faceDesc, glyph->index, prevGlyph->index,
231 inScaleX, inScaleY, outVec, inContext);
232 }
233
234
235
236 /* This internal function tries to open the face file which name is identified
237 * by 'inFace'. If it succeeds, it closes the previous face and stores the new
238 * face attributes in the __GLCfont object "inFont". Otherwise, it leaves the
239 * font unchanged. GL_TRUE or GL_FALSE are returned to indicate if the function
240 * succeeded or not.
241 */
__glcFontFace(__GLCfont * This,const GLCchar8 * inFace,__GLCcontext * inContext)242 GLboolean __glcFontFace(__GLCfont* This, const GLCchar8* inFace,
243 __GLCcontext *inContext)
244 {
245 __GLCfaceDescriptor *faceDesc = NULL;
246 __GLCmaster *master = NULL;
247 __GLCcharMap* newCharMap = NULL;
248
249 /* TODO : Verify if the font has already the required face activated */
250
251 master = __glcMasterCreate(This->parentMasterID, inContext);
252 if (!master)
253 return GL_FALSE;
254
255 /* Get the face descriptor of the face identified by the string inFace */
256 faceDesc = __glcFaceDescCreate(master, inFace, inContext, 0);
257 if (!faceDesc) {
258 __glcMasterDestroy(master);
259 return GL_FALSE;
260 }
261
262 newCharMap = __glcFaceDescGetCharMap(faceDesc, inContext);
263 if (!newCharMap) {
264 __glcFaceDescDestroy(faceDesc, inContext);
265 __glcMasterDestroy(master);
266 return GL_FALSE;
267 }
268
269 __glcMasterDestroy(master);
270
271 #ifndef GLC_FT_CACHE
272 /* If the font belongs to GLC_CURRENT_FONT_LIST then open the font file */
273 if (FT_List_Find(&inContext->currentFontList, This)) {
274
275 /* Open the new face */
276 if (!__glcFaceDescOpen(faceDesc, inContext)) {
277 __glcFaceDescDestroy(faceDesc, inContext);
278 __glcCharMapDestroy(newCharMap);
279 return GL_FALSE;
280 }
281
282 /* Close the current face */
283 __glcFontClose(This);
284 }
285 #endif
286
287 /* Destroy the current charmap */
288 if (This->charMap)
289 __glcCharMapDestroy(This->charMap);
290
291 This->charMap = newCharMap;
292
293 __glcFaceDescDestroy(This->faceDesc, inContext);
294 This->faceDesc = faceDesc;
295
296 return GL_TRUE;
297 }
298
299
300
301 /* Load a glyph of the current font face and stores the corresponding data in
302 * the corresponding face. The size of the glyph is given by inScaleX and
303 * inScaleY. 'inGlyphIndex' contains the index of the glyph in the font file.
304 */
__glcFontPrepareGlyph(__GLCfont * This,__GLCcontext * inContext,GLfloat inScaleX,GLfloat inScaleY,GLCulong inGlyphIndex)305 GLboolean __glcFontPrepareGlyph(__GLCfont* This, __GLCcontext* inContext,
306 GLfloat inScaleX, GLfloat inScaleY,
307 GLCulong inGlyphIndex)
308 {
309 GLboolean result = __glcFaceDescPrepareGlyph(This->faceDesc, inContext,
310 inScaleX, inScaleY,
311 inGlyphIndex);
312 #ifndef GLC_FT_CACHE
313 __glcFaceDescClose(This->faceDesc);
314 #endif
315
316 return result;
317 }
318