1 /* QuesoGLC
2 * A free implementation of the OpenGL Character Renderer (GLC)
3 * Copyright (c) 2002, 2004-2009, 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: render.c 853 2009-01-10 14:02:37Z bcoconni $ */
20
21 /** \file
22 * defines the so-called "Rendering commands" described in chapter 3.9 of the
23 * GLC specs.
24 */
25
26 /** \defgroup render Rendering commands
27 * These are the commands that render characters to a GL render target. Those
28 * commands gather glyph datas according to the parameters that has been set in
29 * the state machine of GLC, and issue GL commands to render the characters
30 * layout to the GL render target.
31 *
32 * When it renders a character, GLC finds a font that maps the character code
33 * to a character such as LATIN CAPITAL LETTER A, then uses one or more glyphs
34 * from the font to create a graphical layout that represents the character.
35 * Finally, GLC issues a sequence of GL commands to draw the layout. Glyph
36 * coordinates are defined in EM units and are transformed during rendering to
37 * produce the desired mapping of the glyph shape into the GL window coordinate
38 * system.
39 *
40 * If GLC cannot find a font that maps the character code in the list
41 * \b GLC_CURRENT_FONT_LIST, it attemps to produce an alternate rendering. If
42 * the value of the boolean variable \b GLC_AUTO_FONT is set to \b GL_TRUE, GLC
43 * searches for a font that has the character that maps the character code. If
44 * the search succeeds, the font's ID is appended to \b GLC_CURRENT_FONT_LIST
45 * and the character is rendered.
46 *
47 * If there are fonts in the list \b GLC_CURRENT_FONT_LIST, but a match for
48 * the character code cannot be found in any of those fonts, GLC goes through
49 * these steps :
50 * -# If the value of the variable \b GLC_REPLACEMENT_CODE is nonzero,
51 * GLC finds a font that maps the replacement code, and renders the character
52 * that the replacement code is mapped to.
53 * -# If the variable \b GLC_REPLACEMENT_CODE is zero, or if the replacement
54 * code does not result in a match, GLC checks whether a callback function is
55 * defined. If a callback function is defined for \b GLC_OP_glcUnmappedCode,
56 * GLC calls the function. The callback function provides the character code to
57 * the user and allows loading of the appropriate font. After the callback
58 * returns, GLC tries to render the character code again.
59 * -# Otherwise, the command attemps to render the character sequence
60 * <em>\\\<hexcode\></em>, where \\ is the character REVERSE SOLIDUS (U+5C),
61 * \< is the character LESS-THAN SIGN (U+3C), \> is the character GREATER-THAN
62 * SIGN (U+3E), and \e hexcode is the character code represented as a sequence
63 * of hexadecimal digits. The sequence has no leading zeros, and alphabetic
64 * digits are in upper case. The GLC measurement commands treat the sequence
65 * as a single character.
66 *
67 * The rendering commands raise \b GLC_PARAMETER_ERROR if the callback function
68 * defined for \b GLC_OP_glcUnmappedCode is called and the current string type
69 * is \b GLC_UTF8_QSO.
70 *
71 * \note Some rendering commands create and/or use display lists and/or
72 * textures. The IDs of those display lists and textures are stored in the
73 * current GLC context but the display lists and the textures themselves are
74 * managed by the current GL context. In order not to impact the performance of
75 * error-free programs, QuesoGLC does not check if the current GL context is
76 * the same than the one where the display lists and the textures were actually
77 * created. If the current GL context has changed meanwhile, the result of
78 * commands that refer to the corresponding display lists or textures is
79 * undefined.
80 *
81 * As a reminder, the render commands may issue GL commands, hence a GL context
82 * must be bound to the current thread such that the GLC commands produce the
83 * desired result. It is the responsibility of the GLC client to set up the
84 * underlying GL implementation.
85 */
86
87 #include "internal.h"
88
89 #if defined __APPLE__ && defined __MACH__
90 #include <OpenGL/glu.h>
91 #else
92 #include <GL/glu.h>
93 #endif
94 #include <math.h>
95
96 #include "texture.h"
97
98
99
100 /* This internal function renders a glyph using the GLC_BITMAP format */
101 /* TODO : Render Bitmap fonts */
__glcRenderCharBitmap(__GLCfont * inFont,__GLCcontext * inContext,GLfloat scale_x,GLfloat scale_y,GLfloat * advance,GLboolean inIsRTL)102 static void __glcRenderCharBitmap(__GLCfont* inFont, __GLCcontext* inContext,
103 GLfloat scale_x, GLfloat scale_y,
104 GLfloat* advance, GLboolean inIsRTL)
105 {
106 GLfloat *transform = inContext->bitmapMatrix;
107 GLint pixWidth = 0, pixHeight = 0;
108 GLubyte* pixBuffer = NULL;
109 GLint pixBoundingBox[4] = {0, 0, 0, 0};
110
111 __glcFontGetBitmapSize(inFont, &pixWidth, &pixHeight, scale_x, scale_y, 0,
112 pixBoundingBox, inContext);
113
114 pixBuffer = (GLubyte *)__glcMalloc(pixWidth * pixHeight);
115 if (!pixBuffer) {
116 __glcRaiseError(GLC_RESOURCE_ERROR);
117 return;
118 }
119
120 /* render the glyph */
121 if (!__glcFontGetBitmap(inFont, pixWidth, pixHeight, pixBuffer, inContext)) {
122 __glcFree(pixBuffer);
123 return;
124 }
125
126 /* Do the actual GL rendering */
127 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
128 glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
129 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
130 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
131 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
132 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
133
134 if (inIsRTL) {
135 glBitmap(0, 0, 0, 0,
136 advance[1] * transform[2] - advance[0] * transform[0],
137 advance[1] * transform[3] - advance[0] * transform[1],
138 NULL);
139 glBitmap(pixWidth, pixHeight, -pixBoundingBox[0] >> 6,
140 -pixBoundingBox[1] >> 6, 0., 0., pixBuffer);
141 }
142 else
143 glBitmap(pixWidth, pixHeight, -pixBoundingBox[0] >> 6,
144 -pixBoundingBox[1] >> 6,
145 advance[0] * transform[0] + advance[1] * transform[2],
146 advance[0] * transform[1] + advance[1] * transform[3],
147 pixBuffer);
148
149 glPopClientAttrib();
150
151 __glcFree(pixBuffer);
152 }
153
154
155
156 /* Internal function that is called to do the actual rendering :
157 * 'inCode' must be given in UCS-4 format
158 */
__glcRenderChar(GLint inCode,GLint inPrevCode,GLboolean inIsRTL,__GLCfont * inFont,__GLCcontext * inContext,void * GLC_UNUSED_ARG (inData),GLboolean GLC_UNUSED_ARG (inMultipleChars))159 static void* __glcRenderChar(GLint inCode, GLint inPrevCode, GLboolean inIsRTL,
160 __GLCfont* inFont, __GLCcontext* inContext,
161 void* GLC_UNUSED_ARG(inData),
162 GLboolean GLC_UNUSED_ARG(inMultipleChars))
163 {
164 GLfloat transformMatrix[16];
165 GLfloat scale_x = GLC_POINT_SIZE;
166 GLfloat scale_y = GLC_POINT_SIZE;
167 __GLCglyph* glyph = NULL;
168 GLfloat sx64 = 0., sy64 = 0.;
169 GLfloat advance[2] = {0., 0.};
170
171 assert(inFont);
172
173 __glcGetScale(inContext, transformMatrix, &scale_x, &scale_y);
174
175 if ((fabs(scale_x) < GLC_EPSILON) || (fabs(scale_y) < GLC_EPSILON))
176 return NULL;
177
178 #ifndef GLC_FT_CACHE
179 if (!__glcFontOpen(inFont, inContext))
180 return NULL;
181 #endif
182
183 if (inPrevCode && inContext->enableState.kerning) {
184 GLfloat kerning[2];
185 GLint leftCode = inIsRTL ? inCode : inPrevCode;
186 GLint rightCode = inIsRTL ? inPrevCode : inCode;
187
188 if (__glcFontGetKerning(inFont, leftCode, rightCode, kerning, inContext,
189 scale_x, scale_y)) {
190 if (inIsRTL)
191 kerning[0] = -kerning[0];
192
193 if (inContext->renderState.renderStyle == GLC_BITMAP)
194 glBitmap(0, 0, 0, 0,
195 kerning[0] * inContext->bitmapMatrix[0]
196 + kerning[1] * inContext->bitmapMatrix[2],
197 kerning[0] * inContext->bitmapMatrix[1]
198 + kerning[1] * inContext->bitmapMatrix[3],
199 NULL);
200 else
201 glTranslatef(kerning[0], kerning[1], 0.f);
202 }
203 }
204
205 if (!__glcFontGetAdvance(inFont, inCode, advance, inContext, scale_x,
206 scale_y)) {
207 #ifndef GLC_FT_CACHE
208 __glcFontClose(inFont);
209 #endif
210 return NULL;
211 }
212
213 /* Get and load the glyph which unicode code is identified by inCode */
214 glyph = __glcFontGetGlyph(inFont, inCode, inContext);
215
216 if (inContext->enableState.glObjects
217 && !__glcFontPrepareGlyph(inFont, inContext, scale_x, scale_y,
218 glyph->index)) {
219 #ifndef GLC_FT_CACHE
220 __glcFontClose(inFont);
221 #endif
222 return NULL;
223 }
224
225 sx64 = 64. * scale_x;
226 sy64 = 64. * scale_y;
227
228 if (inContext->renderState.renderStyle != GLC_BITMAP) {
229 if (inIsRTL)
230 glTranslatef(-advance[0], advance[1], 0.f);
231
232 /* If the outline contains no point then the glyph represents a space
233 * character and there is no need to continue the process of rendering.
234 */
235 if (!__glcFontOutlineEmpty(inFont)) {
236 /* Update the advance and return */
237 if (!inIsRTL)
238 glTranslatef(advance[0], advance[1], 0.f);
239 if (inContext->enableState.glObjects)
240 glyph->isSpacingChar = GL_TRUE;
241 #ifndef GLC_FT_CACHE
242 __glcFontClose(inFont);
243 #endif
244 return NULL;
245 }
246
247 /* coordinates are given in 26.6 fixed point integer hence we
248 * divide the scale by 2^6
249 */
250 if (!inContext->enableState.glObjects)
251 glScalef(1. / sx64, 1. / sy64, 1.f);
252 }
253
254 /* Call the appropriate function depending on the rendering mode. It first
255 * checks if a display list that draws the desired glyph has already been
256 * defined
257 */
258 switch(inContext->renderState.renderStyle) {
259 case GLC_BITMAP:
260 __glcRenderCharBitmap(inFont, inContext, scale_x, scale_y, advance,
261 inIsRTL);
262 break;
263 case GLC_TEXTURE:
264 __glcRenderCharTexture(inFont, inContext, scale_x, scale_y, glyph);
265 break;
266 case GLC_LINE:
267 __glcRenderCharScalable(inFont, inContext, transformMatrix, scale_x,
268 scale_y, glyph);
269 break;
270 case GLC_TRIANGLE:
271 __glcRenderCharScalable(inFont, inContext, transformMatrix, scale_x,
272 scale_y, glyph);
273 break;
274 default:
275 __glcRaiseError(GLC_PARAMETER_ERROR);
276 }
277
278 if (inContext->renderState.renderStyle != GLC_BITMAP) {
279 if (!inContext->enableState.glObjects)
280 glScalef(sx64, sy64, 1.);
281 if (!inIsRTL)
282 glTranslatef(advance[0], advance[1], 0.f);
283 }
284 #ifndef GLC_FT_CACHE
285 __glcFontClose(inFont);
286 #endif
287 return NULL;
288 }
289
290
291
292 /* This internal function is used by both glcRenderString() and
293 * glcRenderCountedString(). The string 'inString' must be sorted in visual
294 * order and stored using UCS4 format.
295 */
__glcRenderCountedString(__GLCcontext * inContext,GLCchar32 * inString,GLboolean inIsRightToLeft,GLint inCount)296 static void __glcRenderCountedString(__GLCcontext* inContext,
297 GLCchar32* inString,
298 GLboolean inIsRightToLeft,GLint inCount)
299 {
300 GLint listIndex = 0;
301 GLint i = 0;
302 GLCchar32* ptr = NULL;
303 __GLCglState GLState;
304 __GLCcharacter prevCode = {0, NULL, NULL, {0.f, 0.f}};
305 GLboolean saveGLObjects = GL_FALSE;
306 GLint shift = 1;
307 __GLCcharacter* chars = NULL;
308
309 /* Disable the internal management of GL objects when the user is currently
310 * building a display list.
311 */
312 glGetIntegerv(GL_LIST_INDEX, &listIndex);
313 if (listIndex) {
314 saveGLObjects = inContext->enableState.glObjects;
315 inContext->enableState.glObjects = GL_FALSE;
316 }
317
318 if (inContext->enableState.glObjects
319 && inContext->renderState.renderStyle != GLC_BITMAP) {
320 chars = (__GLCcharacter*)__glcMalloc(inCount * sizeof(__GLCcharacter));
321 if (!chars) {
322 __glcRaiseError(GLC_RESOURCE_ERROR);
323 return;
324 }
325 }
326
327 /* Save the value of the GL parameters */
328 __glcSaveGLState(&GLState, inContext, GL_FALSE);
329
330 if (inContext->renderState.renderStyle == GLC_LINE ||
331 inContext->renderState.renderStyle == GLC_TRIANGLE) {
332 glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
333 glEnableClientState(GL_VERTEX_ARRAY);
334 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
335 glDisableClientState(GL_COLOR_ARRAY);
336 glDisableClientState(GL_INDEX_ARRAY);
337 glDisableClientState(GL_NORMAL_ARRAY);
338 glDisableClientState(GL_EDGE_FLAG_ARRAY);
339 }
340
341 /* Set the texture environment if the render style is GLC_TEXTURE */
342 if (inContext->renderState.renderStyle == GLC_TEXTURE) {
343 /* Set the new values of the parameters */
344 glEnable(GL_BLEND);
345 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
346 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
347 if (inContext->enableState.glObjects) {
348 if (inContext->atlas.id)
349 glBindTexture(GL_TEXTURE_2D, inContext->atlas.id);
350 if (GLEW_ARB_vertex_buffer_object) {
351 glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
352 if (inContext->atlas.bufferObjectID) {
353 glBindBufferARB(GL_ARRAY_BUFFER_ARB, inContext->atlas.bufferObjectID);
354 glInterleavedArrays(GL_T2F_V3F, 0, NULL);
355 }
356 }
357 }
358 else if (inContext->texture.id) {
359 glBindTexture(GL_TEXTURE_2D, inContext->texture.id);
360 if (GLEW_ARB_pixel_buffer_object && inContext->texture.bufferObjectID)
361 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER,
362 inContext->texture.bufferObjectID);
363 }
364 }
365
366 /* Render the string */
367 ptr = inString;
368 if (inIsRightToLeft) {
369 ptr += inCount - 1;
370 shift = -1;
371 }
372
373 if (inContext->enableState.glObjects
374 && inContext->renderState.renderStyle != GLC_BITMAP) {
375 __GLCfont* font = NULL;
376 __GLCglyph* glyph = NULL;
377 int length = 0;
378 int j = 0;
379 GLuint GLObjectIndex = inContext->renderState.renderStyle - 0x101;
380 FT_ListNode node = NULL;
381 float resolution = (inContext->renderState.resolution < GLC_EPSILON ?
382 72. : inContext->renderState.resolution) / 72.;
383
384 if (inContext->renderState.renderStyle == GLC_TRIANGLE
385 && inContext->enableState.extrude)
386 GLObjectIndex++;
387
388 for (i = 0; i < inCount; i++) {
389 if (*ptr >= 32) {
390 for (node = inContext->currentFontList.head; node ; node = node->next) {
391 font = (__GLCfont*)node->data;
392 glyph = __glcCharMapGetGlyph(font->charMap, *ptr);
393
394 if (glyph) {
395 if (!glyph->glObject[GLObjectIndex] && !glyph->isSpacingChar)
396 continue;
397
398 if (!glyph->isSpacingChar
399 && (inContext->renderState.renderStyle == GLC_TEXTURE))
400 FT_List_Up(&inContext->atlasList,
401 (FT_ListNode)glyph->textureObject);
402
403 chars[length].glyph = glyph;
404 chars[length].advance[0] = glyph->advance[0];
405 chars[length].advance[1] = glyph->advance[1];
406
407 if (inContext->enableState.kerning) {
408 if (prevCode.code && prevCode.font == font) {
409 GLfloat kerning[2];
410 GLint leftCode = inIsRightToLeft ? *ptr : prevCode.code;
411 GLint rightCode = inIsRightToLeft ? prevCode.code : *ptr;
412
413 if (__glcFontGetKerning(font, leftCode, rightCode, kerning,
414 inContext, GLC_POINT_SIZE,
415 GLC_POINT_SIZE)) {
416 if (!length) {
417 if (inIsRightToLeft)
418 glTranslatef(-kerning[0], kerning[1], 0.f);
419 else
420 glTranslatef(kerning[0], kerning[1], 0.f);
421 }
422 else {
423 if (inIsRightToLeft)
424 chars[length - 1].advance[0] -= kerning[0];
425 else
426 chars[length - 1].advance[0] += kerning[0];
427
428 chars[length - 1].advance[1] += kerning[1];
429 }
430 }
431 }
432 }
433
434 prevCode.font = font;
435 prevCode.code = *ptr;
436
437 if (glyph->isSpacingChar)
438 chars[length].code = 32;
439 else
440 chars[length].code = *ptr;
441
442 length++;
443 break;
444 }
445 }
446 }
447
448 if(!node || (i == inCount-1)) {
449 glScalef(resolution, resolution, 1.f);
450
451 for (j = 0; j < length; j++) {
452 if (inIsRightToLeft)
453 glTranslatef(-chars[j].advance[0], chars[j].advance[1], 0.);
454 if (chars[j].code != 32) {
455 glyph = chars[j].glyph;
456
457 switch(inContext->renderState.renderStyle) {
458 case GLC_TEXTURE:
459 if (GLEW_ARB_vertex_buffer_object) {
460 glNormal3f(0.f, 0.f, 1.f);
461 glDrawArrays(GL_QUADS, glyph->textureObject->position * 4, 4);
462 }
463 else
464 glCallList(glyph->glObject[1]);
465 break;
466 case GLC_LINE:
467 if (GLEW_ARB_vertex_buffer_object && glyph->glObject[0]) {
468 int k = 0;
469
470 glBindBufferARB(GL_ARRAY_BUFFER_ARB, glyph->glObject[0]);
471 glVertexPointer(2, GL_FLOAT, 0, NULL);
472 glNormal3f(0.f, 0.f, 1.f);
473 for (k = 0; k < glyph->nContour; k++)
474 glDrawArrays(GL_LINE_LOOP, glyph->contours[k],
475 glyph->contours[k+1] - glyph->contours[k]);
476 break;
477 }
478 glCallList(glyph->glObject[0]);
479 break;
480 case GLC_TRIANGLE:
481 glCallList(glyph->glObject[GLObjectIndex]);
482 break;
483 }
484 }
485 if (!inIsRightToLeft)
486 glTranslatef(chars[j].advance[0], chars[j].advance[1], 0.);
487 }
488
489 if (!node)
490 __glcProcessChar(inContext, *ptr, &prevCode, inIsRightToLeft,
491 __glcRenderChar, NULL);
492
493 glScalef(1./resolution, 1./resolution, 1.f);
494 length = 0;
495 }
496
497 ptr += shift;
498 }
499 }
500 else {
501 for (i = 0; i < inCount; i++) {
502 if (*ptr >= 32)
503 __glcProcessChar(inContext, *ptr, &prevCode, inIsRightToLeft,
504 __glcRenderChar, NULL);
505 ptr += shift;
506 }
507 }
508
509 /* Restore the values of the GL state if needed */
510 __glcRestoreGLState(&GLState, inContext, GL_FALSE);
511
512 if (inContext->renderState.renderStyle != GLC_BITMAP) {
513 if (inContext->enableState.glObjects)
514 __glcFree(chars);
515 if (inContext->renderState.renderStyle != GLC_TEXTURE)
516 glPopClientAttrib();
517 else if (inContext->enableState.glObjects && GLEW_ARB_vertex_buffer_object)
518 glPopClientAttrib();
519 }
520
521 if (listIndex)
522 inContext->enableState.glObjects = saveGLObjects;
523 }
524
525
526
527 /** \ingroup render
528 * This command renders the character that \e inCode is mapped to.
529 * \param inCode The character to render
530 * \sa glcRenderString()
531 * \sa glcRenderCountedString()
532 * \sa glcReplacementCode()
533 * \sa glcRenderStyle()
534 * \sa glcCallbackFunc()
535 */
glcRenderChar(GLint inCode)536 void APIENTRY glcRenderChar(GLint inCode)
537 {
538 __GLCcontext *ctx = NULL;
539 GLint code = 0;
540
541 GLC_INIT_THREAD();
542
543 /* Check if the current thread owns a context state */
544 ctx = GLC_GET_CURRENT_CONTEXT();
545 if (!ctx) {
546 __glcRaiseError(GLC_STATE_ERROR);
547 return;
548 }
549
550 /* Get the character code converted to the UCS-4 format */
551 code = __glcConvertGLintToUcs4(ctx, inCode);
552 if (code < 32)
553 return; /* Skip control characters and unknown characters */
554
555 __glcRenderCountedString(ctx, (GLCchar32*)&code, GL_FALSE, 1);
556 }
557
558
559
560 /** \ingroup render
561 * This command is identical to the command glcRenderChar(), except that it
562 * renders a string of characters. The string comprises the first \e inCount
563 * elements of the array \e inString, which need not be followed by a zero
564 * element.
565 *
566 * The command raises \b GLC_PARAMETER_ERROR if \e inCount is less than zero.
567 * \param inCount The number of elements in the string to be rendered
568 * \param inString The array of characters from which to render \e inCount
569 * elements.
570 * \sa glcRenderChar()
571 * \sa glcRenderString()
572 */
glcRenderCountedString(GLint inCount,const GLCchar * inString)573 void APIENTRY glcRenderCountedString(GLint inCount, const GLCchar *inString)
574 {
575 __GLCcontext *ctx = NULL;
576 GLCchar32* UinString = NULL;
577 GLboolean isRightToLeft = GL_FALSE;
578
579 GLC_INIT_THREAD();
580
581 /* Check if inCount is positive */
582 if (inCount < 0) {
583 __glcRaiseError(GLC_PARAMETER_ERROR);
584 return;
585 }
586
587 /* Check if the current thread owns a context state */
588 ctx = GLC_GET_CURRENT_CONTEXT();
589 if (!ctx) {
590 __glcRaiseError(GLC_STATE_ERROR);
591 return;
592 }
593
594 /* If inString is NULL then there is no point in continuing */
595 if (!inString)
596 return;
597
598 /* Creates a Unicode string based on the current string type. Basically,
599 * that means that inString is read in the current string format.
600 */
601 UinString = __glcConvertCountedStringToVisualUcs4(ctx, &isRightToLeft,
602 inString, inCount);
603 if (!UinString)
604 return;
605
606
607 __glcRenderCountedString(ctx, UinString, isRightToLeft, inCount);
608 }
609
610
611
612 /** \ingroup render
613 * This command is identical to the command glcRenderCountedString(), except
614 * that \e inString is zero terminated, not counted.
615 * \param inString A zero-terminated string of characters.
616 * \sa glcRenderChar()
617 * \sa glcRenderCountedString()
618 */
glcRenderString(const GLCchar * inString)619 void APIENTRY glcRenderString(const GLCchar *inString)
620 {
621 __GLCcontext *ctx = NULL;
622 GLCchar32* UinString = NULL;
623 GLboolean isRightToLeft = GL_FALSE;
624 GLint length = 0;
625
626 GLC_INIT_THREAD();
627
628 /* Check if the current thread owns a context state */
629 ctx = GLC_GET_CURRENT_CONTEXT();
630 if (!ctx) {
631 __glcRaiseError(GLC_STATE_ERROR);
632 return;
633 }
634
635 /* If inString is NULL then there is no point in continuing */
636 if (!inString)
637 return;
638
639 /* Creates a Unicode string based on the current string type. Basically,
640 * that means that inString is read in the current string format.
641 */
642 UinString = __glcConvertToVisualUcs4(ctx, &isRightToLeft, &length, inString);
643 if (!UinString)
644 return;
645
646 __glcRenderCountedString(ctx, UinString, isRightToLeft, length);
647 }
648
649
650
651 /** \ingroup render
652 * This command assigns the value \e inStyle to the variable
653 * \b GLC_RENDER_STYLE. Legal values for \e inStyle are defined in the table
654 * below :
655 * <center>
656 * <table>
657 * <caption>Rendering styles</caption>
658 * <tr>
659 * <td>Name</td> <td>Enumerant</td>
660 * </tr>
661 * <tr>
662 * <td><b>GLC_BITMAP</b></td> <td>0x0100</td>
663 * </tr>
664 * <tr>
665 * <td><b>GLC_LINE</b></td> <td>0x0101</td>
666 * </tr>
667 * <tr>
668 * <td><b>GLC_TEXTURE</b></td> <td>0x0102</td>
669 * </tr>
670 * <tr>
671 * <td><b>GLC_TRIANGLE</b></td> <td>0x0103</td>
672 * </tr>
673 * </table>
674 * </center>
675 * \param inStyle The value to assign to the variable \b GLC_RENDER_STYLE.
676 * \sa glcGeti() with argument \b GLC_RENDER_STYLE
677 */
glcRenderStyle(GLCenum inStyle)678 void APIENTRY glcRenderStyle(GLCenum inStyle)
679 {
680 __GLCcontext *ctx = NULL;
681
682 GLC_INIT_THREAD();
683
684 /* Check if inStyle has a legal value */
685 switch(inStyle) {
686 case GLC_BITMAP:
687 case GLC_LINE:
688 case GLC_TEXTURE:
689 case GLC_TRIANGLE:
690 break;
691 default:
692 __glcRaiseError(GLC_PARAMETER_ERROR);
693 return;
694 }
695
696 /* Check if the current thread owns a current state */
697 ctx = GLC_GET_CURRENT_CONTEXT();
698 if (!ctx) {
699 __glcRaiseError(GLC_STATE_ERROR);
700 return;
701 }
702
703 /* Stores the rendering style */
704 ctx->renderState.renderStyle = inStyle;
705 return;
706 }
707
708
709
710 /** \ingroup render
711 * This command assigns the value \e inCode to the variable
712 * \b GLC_REPLACEMENT_CODE. The replacement code is the code which is used
713 * whenever glcRenderChar() can not find a font that owns a character which
714 * the parameter \e inCode of glcRenderChar() maps to.
715 * \param inCode An integer to assign to \b GLC_REPLACEMENT_CODE.
716 * \sa glcGeti() with argument \b GLC_REPLACEMENT_CODE
717 * \sa glcRenderChar()
718 */
glcReplacementCode(GLint inCode)719 void APIENTRY glcReplacementCode(GLint inCode)
720 {
721 __GLCcontext *ctx = NULL;
722 GLint code = 0;
723
724 GLC_INIT_THREAD();
725
726 /* Check if the current thread owns a current state */
727 ctx = GLC_GET_CURRENT_CONTEXT();
728 if (!ctx) {
729 __glcRaiseError(GLC_STATE_ERROR);
730 return;
731 }
732
733 /* Get the replacement character converted to the UCS-4 format */
734 code = __glcConvertGLintToUcs4(ctx, inCode);
735 if (code < 0)
736 return;
737
738 /* Stores the replacement code */
739 ctx->stringState.replacementCode = code;
740 return;
741 }
742
743
744
745 /** \ingroup render
746 * This command assigns the value \e inVal to the variable \b GLC_RESOLUTION.
747 * It is used to compute the size of characters in pixels from the size in
748 * points.
749 *
750 * The resolution is given in \e dpi (dots per inch). If \e inVal is zero, the
751 * resolution defaults to 72 dpi.
752 *
753 * The command raises \b GLC_PARAMETER_ERROR if \e inVal is negative.
754 * \param inVal A floating point number to be used as resolution.
755 * \sa glcGeti() with argument GLC_RESOLUTION
756 */
glcResolution(GLfloat inVal)757 void APIENTRY glcResolution(GLfloat inVal)
758 {
759 __GLCcontext *ctx = NULL;
760 FT_ListNode node = NULL;
761
762 GLC_INIT_THREAD();
763
764 /* Negative resolutions are illegal */
765 if (inVal < 0) {
766 __glcRaiseError(GLC_PARAMETER_ERROR);
767 return;
768 }
769
770 /* Check if the current thread owns a current state */
771 ctx = GLC_GET_CURRENT_CONTEXT();
772 if (!ctx) {
773 __glcRaiseError(GLC_STATE_ERROR);
774 return;
775 }
776
777 /* Stores the resolution */
778 ctx->renderState.resolution = inVal;
779
780 /* Force the measurement caches to be updated */
781 for (node = ctx->fontList.head; node; node = node->next) {
782 __GLCfont* font = (__GLCfont*)node->data;
783 __GLCfaceDescriptor* faceDesc = font->faceDesc;
784 FT_ListNode glyphNode = NULL;
785
786 for (glyphNode = faceDesc->glyphList.head; glyphNode;
787 glyphNode = glyphNode->next) {
788 __GLCglyph* glyph = (__GLCglyph*)glyphNode->data;
789
790 glyph->advanceCached = GL_FALSE;
791 glyph->boundingBoxCached = GL_FALSE;
792 }
793 }
794 }
795