1 /* QuesoGLC
2 * A free implementation of the OpenGL Character Renderer (GLC)
3 * Copyright (c) 2002, 2004-2007, 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: transform.c 621 2007-03-31 18:05:49Z bcoconni $ */
20
21 /** \file
22 * defines the so-called "Transformation commands" described in chapter 3.9
23 * of the GLC specs.
24 */
25
26 /** \defgroup transform Transformation commands
27 * The GLC transformation commands modify the value of \b GLC_BITMAP_MATRIX.
28 * Glyph coordinates are defined in the em coordinate system. When the value
29 * of \b GLC_RENDER_STYLE is \b GLC_BITMAP, GLC uses the 2x2
30 * \b GLC_BITMAP_MATRIX to transform layouts from the em coordinate system to
31 * the GL raster coordinate system in which bitmaps are drawn.
32 *
33 * When the value of the variable \b GLC_RENDER_STYLE is not \b GLC_BITMAP,
34 * GLC performs no transformations on glyph coordinates. In this case, GLC
35 * uses em coordinates directly as GL world coordinates when drawing a layout,
36 * and it is the responsibility of the GLC client to issue GL commands that
37 * set up the appropriate GL transformations.
38 *
39 * There is a stack of matrices for \b GLC_BITMAP_MATRIX, the stack depth is
40 * at least 32 (that is, there is a stack of at least 32 matrices). Matrices
41 * can be pushed or popped in the stack with glcPushMatrixQSO() and
42 * glcPopMatrixQSO(). The maximum depth is implementation specific but can be
43 * retrieved by calling glcGeti() with \b GLC_MAX_MATRIX_STACK_DEPTH_QSO. The
44 * number of matrices that are currently stored in the stack can be retrieved
45 * by calling glcGeti() with \b GLC_MATRIX_STACK_DEPTH_QSO.
46 */
47
48 #include <math.h>
49 #include "internal.h"
50
51 #define GLC_PI 3.1415926535
52
53
54
55 /** \ingroup transform
56 * This command assigns the value [1 0 0 1] to the floating point vector
57 * variable \b GLC_BITMAP_MATRIX.
58 * \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
59 * \sa glcLoadMatrix()
60 * \sa glcMultMatrix()
61 * \sa glcRotate()
62 * \sa glcScale()
63 */
glcLoadIdentity(void)64 void APIENTRY glcLoadIdentity(void)
65 {
66 __GLCcontext *ctx = NULL;
67
68 GLC_INIT_THREAD();
69
70 /* Check if the current thread owns a context state */
71 ctx = GLC_GET_CURRENT_CONTEXT();
72 if (!ctx) {
73 __glcRaiseError(GLC_STATE_ERROR);
74 return;
75 }
76
77 ctx->bitmapMatrix[0] = 1.;
78 ctx->bitmapMatrix[1] = 0.;
79 ctx->bitmapMatrix[2] = 0.;
80 ctx->bitmapMatrix[3] = 1.;
81 }
82
83
84
85 /** \ingroup transform
86 * This command assigns the value [inMatrix[0] inMatrix[1] inMatrix[2]
87 * inMatrix[3]] to the floating point vector variable \b GLC_BITMAP_MATRIX.
88 *
89 * \param inMatrix The value to assign to \b GLC_BITMAP_MATRIX
90 * \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
91 * \sa glcLoadIdentity()
92 * \sa glcMultMatrix()
93 * \sa glcRotate()
94 * \sa glcScale()
95 */
glcLoadMatrix(const GLfloat * inMatrix)96 void APIENTRY glcLoadMatrix(const GLfloat *inMatrix)
97 {
98 __GLCcontext *ctx = NULL;
99
100 GLC_INIT_THREAD();
101
102 assert(inMatrix);
103
104 /* Check if the current thread owns a context state */
105 ctx = GLC_GET_CURRENT_CONTEXT();
106 if (!ctx) {
107 __glcRaiseError(GLC_STATE_ERROR);
108 return;
109 }
110
111 memcpy(ctx->bitmapMatrix, inMatrix, 4 * sizeof(GLfloat));
112 }
113
114
115
116 /** \ingroup transform
117 * This command multiply the floating point vector variable
118 * \b GLC_BITMAP_MATRIX by the incoming matrix \e inMatrix.
119 *
120 * \param inMatrix A pointer to a 2x2 matrix stored in column-major order
121 * as 4 consecutives values.
122 * \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
123 * \sa glcLoadIdentity()
124 * \sa glcLoadMatrix()
125 * \sa glcRotate()
126 * \sa glcScale()
127 */
glcMultMatrix(const GLfloat * inMatrix)128 void APIENTRY glcMultMatrix(const GLfloat *inMatrix)
129 {
130 __GLCcontext *ctx = NULL;
131 GLfloat tempMatrix[4];
132
133 GLC_INIT_THREAD();
134
135 assert(inMatrix);
136
137 /* Check if the current thread owns a context state */
138 ctx = GLC_GET_CURRENT_CONTEXT();
139 if (!ctx) {
140 __glcRaiseError(GLC_STATE_ERROR);
141 return;
142 }
143
144 memcpy(tempMatrix, ctx->bitmapMatrix, 4 * sizeof(GLfloat));
145
146 ctx->bitmapMatrix[0] = tempMatrix[0] * inMatrix[0]
147 + tempMatrix[2] * inMatrix[1];
148 ctx->bitmapMatrix[1] = tempMatrix[1] * inMatrix[0]
149 + tempMatrix[3] * inMatrix[1];
150 ctx->bitmapMatrix[2] = tempMatrix[0] * inMatrix[2]
151 + tempMatrix[2] * inMatrix[3];
152 ctx->bitmapMatrix[3] = tempMatrix[1] * inMatrix[2]
153 + tempMatrix[3] * inMatrix[3];
154 }
155
156
157
158 /** \ingroup transform
159 * This command assigns the value [a b c d] to the floating point vector
160 * variable \b GLC_BITMAP_MATRIX, where \e inAngle is measured in degrees,
161 * \f$ \theta = inAngle * \pi / 180 \f$ and \n
162 * \f$ \left [ \begin {array}{ll} a & b \\ c & d \\ \end {array} \right ]
163 * = \left [ \begin {array}{ll} GLC\_BITMAP\_MATRIX[0] & GLC\_BITMAP\_MATRIX[2]
164 * \\ GLC\_BITMAP\_MATRIX[1] & GLC\_BITMAP\_MATRIX[3] \\ \end{array}
165 * \right ]
166 * \left [ \begin {array}{ll} cos \theta & sin \theta \\
167 * -sin \theta & cos\theta \\ \end{array} \right ]
168 * \f$
169 * \param inAngle The angle of rotation around the Z axis, in degrees.
170 * \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
171 * \sa glcLoadIdentity()
172 * \sa glcLoadMatrix()
173 * \sa glcMultMatrix()
174 * \sa glcScale()
175 */
glcRotate(GLfloat inAngle)176 void APIENTRY glcRotate(GLfloat inAngle)
177 {
178 GLfloat tempMatrix[4];
179 GLfloat radian = inAngle * GLC_PI / 180.;
180 GLfloat sine = sin(radian);
181 GLfloat cosine = cos(radian);
182
183 tempMatrix[0] = cosine;
184 tempMatrix[1] = sine;
185 tempMatrix[2] = -sine;
186 tempMatrix[3] = cosine;
187
188 glcMultMatrix(tempMatrix);
189 }
190
191
192
193 /** \ingroup transform
194 * This command produces a general scaling along the \b x and \b y
195 * axes, that is, it assigns the value [a b c d] to the floating point
196 * vector variable \b GLC_BITMAP_MATRIX, where \n
197 * \f$ \left [ \begin {array}{ll} a & b \\ c & d \\ \end {array} \right ]
198 * = \left [ \begin {array}{ll} GLC\_BITMAP\_MATRIX[0] & GLC\_BITMAP\_MATRIX[2]
199 * \\ GLC\_BITMAP\_MATRIX[1] & GLC\_BITMAP\_MATRIX[3] \\ \end{array}
200 * \right ]
201 * \left [ \begin {array}{ll} inX & 0 \\
202 * 0 & inY \\ \end{array} \right ]
203 * \f$
204 * \param inX The scale factor along the \b x axis
205 * \param inY The scale factor along the \b y axis
206 * \sa glcGetfv() with argument \b GLC_BITMAP_MATRIX
207 * \sa glcLoadIdentity()
208 * \sa glcLoadMatrix()
209 * \sa glcMultMatrix()
210 * \sa glcRotate()
211 */
glcScale(GLfloat inX,GLfloat inY)212 void APIENTRY glcScale(GLfloat inX, GLfloat inY)
213 {
214 GLfloat tempMatrix[4];
215
216 tempMatrix[0] = inX;
217 tempMatrix[1] = 0.;
218 tempMatrix[2] = 0.;
219 tempMatrix[3] = inY;
220
221 glcMultMatrix(tempMatrix);
222 }
223
224
225
226 /** \ingroup transform
227 * This command pushes the stack down by one, duplicating the current
228 * \b GLC_BITMAP_MATRIX in both the top of the stack and the entry below it.
229 * Pushing a matrix onto a full stack generates the error
230 * \b GLC_STACK_OVERFLOW_QSO.
231 * \sa glcPopMatrixQSO()
232 * \sa glcGeti() with argument \b GLC_MATRIX_STACK_DEPTH_QSO
233 * \sa glcGeti() with argument \b GLC_MAX_MATRIX_STACK_DEPTH_QSO
234 */
glcPushMatrixQSO(void)235 void APIENTRY glcPushMatrixQSO(void)
236 {
237 __GLCcontext *ctx = NULL;
238
239 GLC_INIT_THREAD();
240
241 /* Check if the current thread owns a context state */
242 ctx = GLC_GET_CURRENT_CONTEXT();
243 if (!ctx) {
244 __glcRaiseError(GLC_STATE_ERROR);
245 return;
246 }
247
248 if (ctx->bitmapMatrixStackDepth >= GLC_MAX_MATRIX_STACK_DEPTH) {
249 __glcRaiseError(GLC_STACK_OVERFLOW_QSO);
250 return;
251 }
252
253 memcpy(ctx->bitmapMatrix+4, ctx->bitmapMatrix, 4*sizeof(GLfloat));
254 ctx->bitmapMatrix += 4;
255 ctx->bitmapMatrixStackDepth++;
256 return;
257 }
258
259
260
261 /** \ingroup transform
262 * This command pops the top entry off the stack, replacing the current
263 * \b GLC_BITMAP_MATRIX with the matrix that was the second entry in the
264 * stack.
265 * Popping a matrix off a stack with only one entry generates the error
266 * \b GLC_STACK_OVERFLOW_QSO.
267 * \sa glcPushMatrixQSO()
268 * \sa glcGeti() with argument \b GLC_MATRIX_STACK_DEPTH_QSO
269 * \sa glcGeti() with argument \b GLC_MAX_MATRIX_STACK_DEPTH_QSO
270 */
glcPopMatrixQSO(void)271 void APIENTRY glcPopMatrixQSO(void)
272 {
273 __GLCcontext *ctx = NULL;
274
275 GLC_INIT_THREAD();
276
277 /* Check if the current thread owns a context state */
278 ctx = GLC_GET_CURRENT_CONTEXT();
279 if (!ctx) {
280 __glcRaiseError(GLC_STATE_ERROR);
281 return;
282 }
283
284 if (ctx->bitmapMatrixStackDepth <= 1) {
285 __glcRaiseError(GLC_STACK_UNDERFLOW_QSO);
286 return;
287 }
288
289 ctx->bitmapMatrix -= 4;
290 ctx->bitmapMatrixStackDepth--;
291 return;
292 }
293