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