1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Vector and matrix manipulation routines.
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include <math.h>
20 
21 #include "allegro.h"
22 
23 
24 
25 #define FLOATSINCOS(x, s, c)  _AL_SINCOS((x) * AL_PI / 128.0, s ,c)
26 #define floattan(x)           tan((x) * AL_PI / 128.0)
27 
28 
29 
30 MATRIX identity_matrix =
31 {
32    {
33       /* 3x3 identity */
34       { 1<<16, 0,     0     },
35       { 0,     1<<16, 0     },
36       { 0,     0,     1<<16 },
37    },
38 
39    /* zero translation */
40    { 0, 0, 0 }
41 };
42 
43 
44 
45 MATRIX_f identity_matrix_f =
46 {
47    {
48       /* 3x3 identity */
49       { 1.0, 0.0, 0.0 },
50       { 0.0, 1.0, 0.0 },
51       { 0.0, 0.0, 1.0 },
52    },
53 
54    /* zero translation */
55    { 0.0, 0.0, 0.0 }
56 };
57 
58 
59 
60 /* get_translation_matrix:
61  *  Constructs a 3d translation matrix. When applied to the vector
62  *  (vx, vy, vx), this will produce (vx+x, vy+y, vz+z).
63  */
get_translation_matrix(MATRIX * m,fixed x,fixed y,fixed z)64 void get_translation_matrix(MATRIX *m, fixed x, fixed y, fixed z)
65 {
66    ASSERT(m);
67    *m = identity_matrix;
68 
69    m->t[0] = x;
70    m->t[1] = y;
71    m->t[2] = z;
72 }
73 
74 
75 
76 /* get_translation_matrix_f:
77  *  Floating point version of get_translation_matrix().
78  */
get_translation_matrix_f(MATRIX_f * m,float x,float y,float z)79 void get_translation_matrix_f(MATRIX_f *m, float x, float y, float z)
80 {
81    ASSERT(m);
82    *m = identity_matrix_f;
83 
84    m->t[0] = x;
85    m->t[1] = y;
86    m->t[2] = z;
87 }
88 
89 
90 
91 /* get_scaling_matrix:
92  *  Constructs a 3d scaling matrix. When applied to the vector
93  *  (vx, vy, vx), this will produce (vx*x, vy*y, vz*z).
94  */
get_scaling_matrix(MATRIX * m,fixed x,fixed y,fixed z)95 void get_scaling_matrix(MATRIX *m, fixed x, fixed y, fixed z)
96 {
97    ASSERT(m);
98    *m = identity_matrix;
99 
100    m->v[0][0] = x;
101    m->v[1][1] = y;
102    m->v[2][2] = z;
103 }
104 
105 
106 
107 /* get_scaling_matrix_f:
108  *  Floating point version of get_scaling_matrix().
109  */
get_scaling_matrix_f(MATRIX_f * m,float x,float y,float z)110 void get_scaling_matrix_f(MATRIX_f *m, float x, float y, float z)
111 {
112    ASSERT(m);
113    *m = identity_matrix_f;
114 
115    m->v[0][0] = x;
116    m->v[1][1] = y;
117    m->v[2][2] = z;
118 }
119 
120 
121 
122 /* get_x_rotate_matrix:
123  *  Constructs a 3d transformation matrix, which will rotate points around
124  *  the x axis by the specified amount (given in the Allegro fixed point,
125  *  256 degrees to a circle format).
126  */
get_x_rotate_matrix(MATRIX * m,fixed r)127 void get_x_rotate_matrix(MATRIX *m, fixed r)
128 {
129    fixed c = fixcos(r);
130    fixed s = fixsin(r);
131    ASSERT(m);
132 
133    *m = identity_matrix;
134 
135    m->v[1][1] = c;
136    m->v[1][2] = -s;
137 
138    m->v[2][1] = s;
139    m->v[2][2] = c;
140 }
141 
142 
143 
144 /* get_x_rotate_matrix_f:
145  *  Floating point version of get_x_rotate_matrix().
146  */
get_x_rotate_matrix_f(MATRIX_f * m,float r)147 void get_x_rotate_matrix_f(MATRIX_f *m, float r)
148 {
149    float c, s;
150    ASSERT(m);
151 
152    FLOATSINCOS(r, s, c);
153    *m = identity_matrix_f;
154 
155    m->v[1][1] = c;
156    m->v[1][2] = -s;
157 
158    m->v[2][1] = s;
159    m->v[2][2] = c;
160 }
161 
162 
163 
164 /* get_y_rotate_matrix:
165  *  Constructs a 3d transformation matrix, which will rotate points around
166  *  the y axis by the specified amount (given in the Allegro fixed point,
167  *  256 degrees to a circle format).
168  */
get_y_rotate_matrix(MATRIX * m,fixed r)169 void get_y_rotate_matrix(MATRIX *m, fixed r)
170 {
171    fixed c = fixcos(r);
172    fixed s = fixsin(r);
173    ASSERT(m);
174 
175    *m = identity_matrix;
176 
177    m->v[0][0] = c;
178    m->v[0][2] = s;
179 
180    m->v[2][0] = -s;
181    m->v[2][2] = c;
182 }
183 
184 
185 
186 /* get_y_rotate_matrix_f:
187  *  Floating point version of get_y_rotate_matrix().
188  */
get_y_rotate_matrix_f(MATRIX_f * m,float r)189 void get_y_rotate_matrix_f(MATRIX_f *m, float r)
190 {
191    float c, s;
192    ASSERT(m);
193 
194    FLOATSINCOS(r, s, c);
195    *m = identity_matrix_f;
196 
197    m->v[0][0] = c;
198    m->v[0][2] = s;
199 
200    m->v[2][0] = -s;
201    m->v[2][2] = c;
202 }
203 
204 
205 
206 /* get_z_rotate_matrix:
207  *  Constructs a 3d transformation matrix, which will rotate points around
208  *  the z axis by the specified amount (given in the Allegro fixed point,
209  *  256 degrees to a circle format).
210  */
get_z_rotate_matrix(MATRIX * m,fixed r)211 void get_z_rotate_matrix(MATRIX *m, fixed r)
212 {
213    fixed c = fixcos(r);
214    fixed s = fixsin(r);
215    ASSERT(m);
216 
217    *m = identity_matrix;
218 
219    m->v[0][0] = c;
220    m->v[0][1] = -s;
221 
222    m->v[1][0] = s;
223    m->v[1][1] = c;
224 }
225 
226 
227 
228 /* get_z_rotate_matrix_f:
229  *  Floating point version of get_z_rotate_matrix().
230  */
get_z_rotate_matrix_f(MATRIX_f * m,float r)231 void get_z_rotate_matrix_f(MATRIX_f *m, float r)
232 {
233    float c, s;
234    ASSERT(m);
235 
236    FLOATSINCOS(r, s, c);
237    *m = identity_matrix_f;
238 
239    m->v[0][0] = c;
240    m->v[0][1] = -s;
241 
242    m->v[1][0] = s;
243    m->v[1][1] = c;
244 }
245 
246 
247 
248 /* magical formulae for constructing rotation matrices */
249 #define MAKE_ROTATION(x, y, z)                  \
250    fixed sin_x = fixsin(x);                     \
251    fixed cos_x = fixcos(x);                     \
252 						\
253    fixed sin_y = fixsin(y);                     \
254    fixed cos_y = fixcos(y);                     \
255 						\
256    fixed sin_z = fixsin(z);                     \
257    fixed cos_z = fixcos(z);                     \
258 						\
259    fixed sinx_siny = fixmul(sin_x, sin_y);      \
260    fixed cosx_siny = fixmul(cos_x, sin_y);
261 
262 
263 
264 #define MAKE_ROTATION_f(x, y, z)                \
265    float sin_x, cos_x;				\
266    float sin_y, cos_y;				\
267    float sin_z, cos_z;				\
268    float sinx_siny, cosx_siny;			\
269 						\
270    FLOATSINCOS(x, sin_x, cos_x);		\
271    FLOATSINCOS(y, sin_y, cos_y);		\
272    FLOATSINCOS(z, sin_z, cos_z);		\
273 						\
274    sinx_siny = sin_x * sin_y;			\
275    cosx_siny = cos_x * sin_y;
276 
277 
278 
279 #define R00 (fixmul(cos_y, cos_z))
280 #define R10 (fixmul(sinx_siny, cos_z) - fixmul(cos_x, sin_z))
281 #define R20 (fixmul(cosx_siny, cos_z) + fixmul(sin_x, sin_z))
282 
283 #define R01 (fixmul(cos_y, sin_z))
284 #define R11 (fixmul(sinx_siny, sin_z) + fixmul(cos_x, cos_z))
285 #define R21 (fixmul(cosx_siny, sin_z) - fixmul(sin_x, cos_z))
286 
287 #define R02 (-sin_y)
288 #define R12 (fixmul(sin_x, cos_y))
289 #define R22 (fixmul(cos_x, cos_y))
290 
291 
292 
293 #define R00_f (cos_y * cos_z)
294 #define R10_f ((sinx_siny * cos_z) - (cos_x * sin_z))
295 #define R20_f ((cosx_siny * cos_z) + (sin_x * sin_z))
296 
297 #define R01_f (cos_y * sin_z)
298 #define R11_f ((sinx_siny * sin_z) + (cos_x * cos_z))
299 #define R21_f ((cosx_siny * sin_z) - (sin_x * cos_z))
300 
301 #define R02_f (-sin_y)
302 #define R12_f (sin_x * cos_y)
303 #define R22_f (cos_x * cos_y)
304 
305 
306 
307 /* get_rotation_matrix:
308  *  Constructs a 3d transformation matrix, which will rotate points around
309  *  all three axis by the specified amounts (given in the Allegro fixed
310  *  point, 256 degrees to a circle format).
311  */
get_rotation_matrix(MATRIX * m,fixed x,fixed y,fixed z)312 void get_rotation_matrix(MATRIX *m, fixed x, fixed y, fixed z)
313 {
314    MAKE_ROTATION(x, y, z);
315    ASSERT(m);
316 
317    m->v[0][0] = R00;
318    m->v[0][1] = R01;
319    m->v[0][2] = R02;
320 
321    m->v[1][0] = R10;
322    m->v[1][1] = R11;
323    m->v[1][2] = R12;
324 
325    m->v[2][0] = R20;
326    m->v[2][1] = R21;
327    m->v[2][2] = R22;
328 
329    m->t[0] = m->t[1] = m->t[2] = 0;
330 }
331 
332 
333 
334 /* get_rotation_matrix_f:
335  *  Floating point version of get_rotation_matrix().
336  */
get_rotation_matrix_f(MATRIX_f * m,float x,float y,float z)337 void get_rotation_matrix_f(MATRIX_f *m, float x, float y, float z)
338 {
339    MAKE_ROTATION_f(x, y, z);
340    ASSERT(m);
341 
342    m->v[0][0] = R00_f;
343    m->v[0][1] = R01_f;
344    m->v[0][2] = R02_f;
345 
346    m->v[1][0] = R10_f;
347    m->v[1][1] = R11_f;
348    m->v[1][2] = R12_f;
349 
350    m->v[2][0] = R20_f;
351    m->v[2][1] = R21_f;
352    m->v[2][2] = R22_f;
353 
354    m->t[0] = m->t[1] = m->t[2] = 0;
355 }
356 
357 
358 
359 /* get_align_matrix:
360  *  Aligns a matrix along an arbitrary coordinate system.
361  */
get_align_matrix(MATRIX * m,fixed xfront,fixed yfront,fixed zfront,fixed xup,fixed yup,fixed zup)362 void get_align_matrix(MATRIX *m, fixed xfront, fixed yfront, fixed zfront, fixed xup, fixed yup, fixed zup)
363 {
364    fixed xright, yright, zright;
365    ASSERT(m);
366 
367    xfront = -xfront;
368    yfront = -yfront;
369    zfront = -zfront;
370 
371    normalize_vector(&xfront, &yfront, &zfront);
372    cross_product(xup, yup, zup, xfront, yfront, zfront, &xright, &yright, &zright);
373    normalize_vector(&xright, &yright, &zright);
374    cross_product(xfront, yfront, zfront, xright, yright, zright, &xup, &yup, &zup);
375    /* No need to normalize up here, since right and front are perpendicular and normalized. */
376 
377    m->v[0][0] = xright;
378    m->v[0][1] = xup;
379    m->v[0][2] = xfront;
380 
381    m->v[1][0] = yright;
382    m->v[1][1] = yup;
383    m->v[1][2] = yfront;
384 
385    m->v[2][0] = zright;
386    m->v[2][1] = zup;
387    m->v[2][2] = zfront;
388 
389    m->t[0] = m->t[1] = m->t[2] = 0;
390 }
391 
392 
393 
394 /* get_align_matrix_f:
395  *  Floating point version of get_align_matrix().
396  */
get_align_matrix_f(MATRIX_f * m,float xfront,float yfront,float zfront,float xup,float yup,float zup)397 void get_align_matrix_f(MATRIX_f *m, float xfront, float yfront, float zfront, float xup, float yup, float zup)
398 {
399    float xright, yright, zright;
400    ASSERT(m);
401 
402    xfront = -xfront;
403    yfront = -yfront;
404    zfront = -zfront;
405 
406    normalize_vector_f(&xfront, &yfront, &zfront);
407    cross_product_f(xup, yup, zup, xfront, yfront, zfront, &xright, &yright, &zright);
408    normalize_vector_f(&xright, &yright, &zright);
409    cross_product_f(xfront, yfront, zfront, xright, yright, zright, &xup, &yup, &zup);
410    /* No need to normalize up here, since right and front are perpendicular and normalized. */
411 
412    m->v[0][0] = xright;
413    m->v[0][1] = xup;
414    m->v[0][2] = xfront;
415 
416    m->v[1][0] = yright;
417    m->v[1][1] = yup;
418    m->v[1][2] = yfront;
419 
420    m->v[2][0] = zright;
421    m->v[2][1] = zup;
422    m->v[2][2] = zfront;
423 
424    m->t[0] = m->t[1] = m->t[2] = 0;
425 }
426 
427 
428 
429 /* get_vector_rotation_matrix:
430  *  Constructs a 3d transformation matrix, which will rotate points around
431  *  the specified x,y,z vector by the specified angle (given in the Allegro
432  *  fixed point, 256 degrees to a circle format), in a clockwise direction.
433  */
get_vector_rotation_matrix(MATRIX * m,fixed x,fixed y,fixed z,fixed a)434 void get_vector_rotation_matrix(MATRIX *m, fixed x, fixed y, fixed z, fixed a)
435 {
436    MATRIX_f rotation;
437    int i, j;
438    ASSERT(m);
439 
440    get_vector_rotation_matrix_f(&rotation, fixtof(x), fixtof(y), fixtof(z), fixtof(a));
441 
442    for (i=0; i<3; i++)
443       for (j=0; j<3; j++)
444 	 m->v[i][j] = ftofix(rotation.v[i][j]);
445 
446    m->t[0] = m->t[1] = m->t[2] = 0;
447 }
448 
449 
450 
451 /* get_vector_rotation_matrix_f:
452  *  Floating point version of get_vector_rotation_matrix().
453  */
get_vector_rotation_matrix_f(MATRIX_f * m,float x,float y,float z,float a)454 void get_vector_rotation_matrix_f(MATRIX_f *m, float x, float y, float z, float a)
455 {
456    float c, s, cc;
457    ASSERT(m);
458 
459    FLOATSINCOS(a, s, c);
460    cc = 1 - c;
461    normalize_vector_f(&x, &y, &z);
462 
463    m->v[0][0] = (cc * x * x) + c;
464    m->v[0][1] = (cc * x * y) + (z * s);
465    m->v[0][2] = (cc * x * z) - (y * s);
466 
467    m->v[1][0] = (cc * x * y) - (z * s);
468    m->v[1][1] = (cc * y * y) + c;
469    m->v[1][2] = (cc * z * y) + (x * s);
470 
471    m->v[2][0] = (cc * x * z) + (y * s);
472    m->v[2][1] = (cc * y * z) - (x * s);
473    m->v[2][2] = (cc * z * z) + c;
474 
475    m->t[0] = m->t[1] = m->t[2] = 0;
476 }
477 
478 
479 
480 /* get_transformation_matrix:
481  *  Constructs a 3d transformation matrix, which will rotate points around
482  *  all three axis by the specified amounts (given in the Allegro fixed
483  *  point, 256 degrees to a circle format), scale the result by the
484  *  specified amount (itofix(1) for no change of scale), and then translate
485  *  to the requested x, y, z position.
486  */
get_transformation_matrix(MATRIX * m,fixed scale,fixed xrot,fixed yrot,fixed zrot,fixed x,fixed y,fixed z)487 void get_transformation_matrix(MATRIX *m, fixed scale, fixed xrot, fixed yrot, fixed zrot, fixed x, fixed y, fixed z)
488 {
489    MAKE_ROTATION(xrot, yrot, zrot);
490    ASSERT(m);
491 
492    m->v[0][0] = fixmul(R00, scale);
493    m->v[0][1] = fixmul(R01, scale);
494    m->v[0][2] = fixmul(R02, scale);
495 
496    m->v[1][0] = fixmul(R10, scale);
497    m->v[1][1] = fixmul(R11, scale);
498    m->v[1][2] = fixmul(R12, scale);
499 
500    m->v[2][0] = fixmul(R20, scale);
501    m->v[2][1] = fixmul(R21, scale);
502    m->v[2][2] = fixmul(R22, scale);
503 
504    m->t[0] = x;
505    m->t[1] = y;
506    m->t[2] = z;
507 }
508 
509 
510 
511 /* get_transformation_matrix_f:
512  *  Floating point version of get_transformation_matrix().
513  */
get_transformation_matrix_f(MATRIX_f * m,float scale,float xrot,float yrot,float zrot,float x,float y,float z)514 void get_transformation_matrix_f(MATRIX_f *m, float scale, float xrot, float yrot, float zrot, float x, float y, float z)
515 {
516    MAKE_ROTATION_f(xrot, yrot, zrot);
517    ASSERT(m);
518 
519    m->v[0][0] = R00_f * scale;
520    m->v[0][1] = R01_f * scale;
521    m->v[0][2] = R02_f * scale;
522 
523    m->v[1][0] = R10_f * scale;
524    m->v[1][1] = R11_f * scale;
525    m->v[1][2] = R12_f * scale;
526 
527    m->v[2][0] = R20_f * scale;
528    m->v[2][1] = R21_f * scale;
529    m->v[2][2] = R22_f * scale;
530 
531    m->t[0] = x;
532    m->t[1] = y;
533    m->t[2] = z;
534 }
535 
536 
537 
538 /* get_camera_matrix:
539  *  Constructs a camera matrix for translating world-space objects into
540  *  a normalised view space, ready for the perspective projection. The
541  *  x, y, and z parameters specify the camera position, xfront, yfront,
542  *  and zfront is an 'in front' vector specifying which way the camera
543  *  is facing (this can be any length: normalisation is not required),
544  *  and xup, yup, and zup is the 'up' direction vector. Up is really only
545  *  a 1.5d vector, since the front vector only leaves one degree of freedom
546  *  for which way up to put the image, but it is simplest to specify it
547  *  as a full 3d direction even though a lot of the information in it is
548  *  discarded. The fov parameter specifies the field of view (ie. width
549  *  of the camera focus) in fixed point, 256 degrees to the circle format.
550  *  For typical projections, a field of view in the region 32-48 will work
551  *  well. Finally, the aspect ratio is used to scale the Y dimensions of
552  *  the image relative to the X axis, so you can use it to correct for
553  *  the proportions of the output image (set it to 1 for no scaling).
554  */
get_camera_matrix(MATRIX * m,fixed x,fixed y,fixed z,fixed xfront,fixed yfront,fixed zfront,fixed xup,fixed yup,fixed zup,fixed fov,fixed aspect)555 void get_camera_matrix(MATRIX *m, fixed x, fixed y, fixed z, fixed xfront, fixed yfront, fixed zfront, fixed xup, fixed yup, fixed zup, fixed fov, fixed aspect)
556 {
557    MATRIX_f camera;
558    int i, j;
559    ASSERT(m);
560 
561    get_camera_matrix_f(&camera,
562 		       fixtof(x), fixtof(y), fixtof(z),
563 		       fixtof(xfront), fixtof(yfront), fixtof(zfront),
564 		       fixtof(xup), fixtof(yup), fixtof(zup),
565 		       fixtof(fov), fixtof(aspect));
566 
567    for (i=0; i<3; i++) {
568       for (j=0; j<3; j++)
569 	 m->v[i][j] = ftofix(camera.v[i][j]);
570 
571       m->t[i] = ftofix(camera.t[i]);
572    }
573 }
574 
575 
576 
577 /* get_camera_matrix_f:
578  *  Floating point version of get_camera_matrix().
579  */
get_camera_matrix_f(MATRIX_f * m,float x,float y,float z,float xfront,float yfront,float zfront,float xup,float yup,float zup,float fov,float aspect)580 void get_camera_matrix_f(MATRIX_f *m, float x, float y, float z, float xfront, float yfront, float zfront, float xup, float yup, float zup, float fov, float aspect)
581 {
582    MATRIX_f camera, scale;
583    float xside, yside, zside, width, d;
584    ASSERT(m);
585 
586    /* make 'in-front' into a unit vector, and negate it */
587    normalize_vector_f(&xfront, &yfront, &zfront);
588    xfront = -xfront;
589    yfront = -yfront;
590    zfront = -zfront;
591 
592    /* make sure 'up' is at right angles to 'in-front', and normalize */
593    d = dot_product_f(xup, yup, zup, xfront, yfront, zfront);
594    xup -= d * xfront;
595    yup -= d * yfront;
596    zup -= d * zfront;
597    normalize_vector_f(&xup, &yup, &zup);
598 
599    /* calculate the 'sideways' vector */
600    cross_product_f(xup, yup, zup, xfront, yfront, zfront, &xside, &yside, &zside);
601 
602    /* set matrix rotation parameters */
603    camera.v[0][0] = xside;
604    camera.v[0][1] = yside;
605    camera.v[0][2] = zside;
606 
607    camera.v[1][0] = xup;
608    camera.v[1][1] = yup;
609    camera.v[1][2] = zup;
610 
611    camera.v[2][0] = xfront;
612    camera.v[2][1] = yfront;
613    camera.v[2][2] = zfront;
614 
615    /* set matrix translation parameters */
616    camera.t[0] = -(x*xside  + y*yside  + z*zside);
617    camera.t[1] = -(x*xup    + y*yup    + z*zup);
618    camera.t[2] = -(x*xfront + y*yfront + z*zfront);
619 
620    /* construct a scaling matrix to deal with aspect ratio and FOV */
621    width = floattan(64.0 - fov/2);
622    get_scaling_matrix_f(&scale, width, -aspect*width, -1.0);
623 
624    /* combine the camera and scaling matrices */
625    matrix_mul_f(&camera, &scale, m);
626 }
627 
628 
629 
630 /* qtranslate_matrix:
631  *  Adds a position offset to an existing matrix.
632  */
qtranslate_matrix(MATRIX * m,fixed x,fixed y,fixed z)633 void qtranslate_matrix(MATRIX *m, fixed x, fixed y, fixed z)
634 {
635    ASSERT(m);
636    m->t[0] += x;
637    m->t[1] += y;
638    m->t[2] += z;
639 }
640 
641 
642 
643 /* qtranslate_matrix_f:
644  *  Floating point version of qtranslate_matrix().
645  */
qtranslate_matrix_f(MATRIX_f * m,float x,float y,float z)646 void qtranslate_matrix_f(MATRIX_f *m, float x, float y, float z)
647 {
648    ASSERT(m);
649    m->t[0] += x;
650    m->t[1] += y;
651    m->t[2] += z;
652 }
653 
654 
655 
656 /* qscale_matrix:
657  *  Adds a scaling factor to an existing matrix.
658  */
qscale_matrix(MATRIX * m,fixed scale)659 void qscale_matrix(MATRIX *m, fixed scale)
660 {
661    int i, j;
662    ASSERT(m);
663 
664    for (i=0; i<3; i++)
665       for (j=0; j<3; j++)
666 	 m->v[i][j] = fixmul(m->v[i][j], scale);
667 }
668 
669 
670 
671 /* qscale_matrix_f:
672  *  Floating point version of qscale_matrix().
673  */
qscale_matrix_f(MATRIX_f * m,float scale)674 void qscale_matrix_f(MATRIX_f *m, float scale)
675 {
676    int i, j;
677    ASSERT(m);
678 
679    for (i=0; i<3; i++)
680       for (j=0; j<3; j++)
681 	 m->v[i][j] *= scale;
682 }
683 
684 
685 
686 /* matrix_mul:
687  *  Multiplies two matrices, storing the result in out (this must be
688  *  different from the two input matrices). The resulting matrix will
689  *  have the same effect as the combination of m1 and m2, ie. when
690  *  applied to a vector v, (v * out) = ((v * m1) * m2). Any number of
691  *  transformations can be concatenated in this way.
692  */
matrix_mul(AL_CONST MATRIX * m1,AL_CONST MATRIX * m2,MATRIX * out)693 void matrix_mul(AL_CONST MATRIX *m1, AL_CONST MATRIX *m2, MATRIX *out)
694 {
695    MATRIX temp;
696    int i, j;
697    ASSERT(m1);
698    ASSERT(m2);
699    ASSERT(out);
700 
701    if (m1 == out) {
702       temp = *m1;
703       m1 = &temp;
704    }
705    else if (m2 == out) {
706       temp = *m2;
707       m2 = &temp;
708    }
709 
710    for (i=0; i<3; i++) {
711       for (j=0; j<3; j++) {
712 	 out->v[i][j] = fixmul(m1->v[0][j], m2->v[i][0]) +
713 			fixmul(m1->v[1][j], m2->v[i][1]) +
714 			fixmul(m1->v[2][j], m2->v[i][2]);
715       }
716 
717       out->t[i] = fixmul(m1->t[0], m2->v[i][0]) +
718 		  fixmul(m1->t[1], m2->v[i][1]) +
719 		  fixmul(m1->t[2], m2->v[i][2]) +
720 		  m2->t[i];
721    }
722 }
723 
724 
725 
726 /* matrix_mul_f:
727  *  Floating point version of matrix_mul().
728  */
matrix_mul_f(AL_CONST MATRIX_f * m1,AL_CONST MATRIX_f * m2,MATRIX_f * out)729 void matrix_mul_f(AL_CONST MATRIX_f *m1, AL_CONST MATRIX_f *m2, MATRIX_f *out)
730 {
731    MATRIX_f temp;
732    int i, j;
733    ASSERT(m1);
734    ASSERT(m2);
735    ASSERT(out);
736 
737    if (m1 == out) {
738       temp = *m1;
739       m1 = &temp;
740    }
741    else if (m2 == out) {
742       temp = *m2;
743       m2 = &temp;
744    }
745 
746    for (i=0; i<3; i++) {
747       for (j=0; j<3; j++) {
748 	 out->v[i][j] = (m1->v[0][j] * m2->v[i][0]) +
749 			(m1->v[1][j] * m2->v[i][1]) +
750 			(m1->v[2][j] * m2->v[i][2]);
751       }
752 
753       out->t[i] = (m1->t[0] * m2->v[i][0]) +
754 		  (m1->t[1] * m2->v[i][1]) +
755 		  (m1->t[2] * m2->v[i][2]) +
756 		  m2->t[i];
757    }
758 }
759 
760 
761 
762 /* vector_length:
763  *  Computes the length of a vector, using the son of the squaw...
764  */
vector_length(fixed x,fixed y,fixed z)765 fixed vector_length(fixed x, fixed y, fixed z)
766 {
767    x >>= 8;
768    y >>= 8;
769    z >>= 8;
770 
771    return (fixsqrt(fixmul(x,x) + fixmul(y,y) + fixmul(z,z)) << 8);
772 }
773 
774 
775 
776 /* vector_lengthf:
777  *  Floating point version of vector_length().
778  */
vector_length_f(float x,float y,float z)779 float vector_length_f(float x, float y, float z)
780 {
781    return sqrt(x*x + y*y + z*z);
782 }
783 
784 
785 
786 /* normalize_vector:
787  *  Converts the specified vector to a unit vector, which has the same
788  *  orientation but a length of one.
789  */
normalize_vector(fixed * x,fixed * y,fixed * z)790 void normalize_vector(fixed *x, fixed *y, fixed *z)
791 {
792    fixed length = vector_length(*x, *y, *z);
793 
794    *x = fixdiv(*x, length);
795    *y = fixdiv(*y, length);
796    *z = fixdiv(*z, length);
797 }
798 
799 
800 
801 /* normalize_vectorf:
802  *  Floating point version of normalize_vector().
803  */
normalize_vector_f(float * x,float * y,float * z)804 void normalize_vector_f(float *x, float *y, float *z)
805 {
806    float length = 1.0 / vector_length_f(*x, *y, *z);
807 
808    *x *= length;
809    *y *= length;
810    *z *= length;
811 }
812 
813 
814 
815 /* cross_product:
816  *  Calculates the cross product of two vectors.
817  */
cross_product(fixed x1,fixed y1,fixed z1,fixed x2,fixed y2,fixed z2,fixed * xout,fixed * yout,fixed * zout)818 void cross_product(fixed x1, fixed y1, fixed z1, fixed x2, fixed y2, fixed z2, fixed *xout, fixed *yout, fixed *zout)
819 {
820    ASSERT(xout);
821    ASSERT(yout);
822    ASSERT(zout);
823 
824    *xout = fixmul(y1, z2) - fixmul(z1, y2);
825    *yout = fixmul(z1, x2) - fixmul(x1, z2);
826    *zout = fixmul(x1, y2) - fixmul(y1, x2);
827 }
828 
829 
830 
831 /* cross_productf:
832  *  Floating point version of cross_product().
833  */
cross_product_f(float x1,float y1,float z1,float x2,float y2,float z2,float * xout,float * yout,float * zout)834 void cross_product_f(float x1, float y1, float z1, float x2, float y2, float z2, float *xout, float *yout, float *zout)
835 {
836    ASSERT(xout);
837    ASSERT(yout);
838    ASSERT(zout);
839 
840    *xout = (y1 * z2) - (z1 * y2);
841    *yout = (z1 * x2) - (x1 * z2);
842    *zout = (x1 * y2) - (y1 * x2);
843 }
844 
845 
846 
847 /* polygon_z_normal:
848  *  Helper function for backface culling: returns the z component of the
849  *  normal vector to the polygon formed from the three vertices.
850  */
polygon_z_normal(AL_CONST V3D * v1,AL_CONST V3D * v2,AL_CONST V3D * v3)851 fixed polygon_z_normal(AL_CONST V3D *v1, AL_CONST V3D *v2, AL_CONST V3D *v3)
852 {
853    ASSERT(v1);
854    ASSERT(v2);
855    ASSERT(v3);
856    return (fixmul(v2->x-v1->x, v3->y-v2->y) - fixmul(v3->x-v2->x, v2->y-v1->y));
857 }
858 
859 
860 
861 /* polygon_z_normal_f:
862  *  Floating point version of polygon_z_normal().
863  */
polygon_z_normal_f(AL_CONST V3D_f * v1,AL_CONST V3D_f * v2,AL_CONST V3D_f * v3)864 float polygon_z_normal_f(AL_CONST V3D_f *v1, AL_CONST V3D_f *v2, AL_CONST V3D_f *v3)
865 {
866    ASSERT(v1);
867    ASSERT(v2);
868    ASSERT(v3);
869    return ((v2->x-v1->x) * (v3->y-v2->y)) - ((v3->x-v2->x) * (v2->y-v1->y));
870 }
871 
872 
873 
874 /* scaling factors for the perspective projection */
875 fixed _persp_xscale = 160 << 16;
876 fixed _persp_yscale = 100 << 16;
877 fixed _persp_xoffset = 160 << 16;
878 fixed _persp_yoffset = 100 << 16;
879 
880 float _persp_xscale_f = 160.0;
881 float _persp_yscale_f = 100.0;
882 float _persp_xoffset_f = 160.0;
883 float _persp_yoffset_f = 100.0;
884 
885 
886 
887 /* set_projection_viewport:
888  *  Sets the viewport used to scale the output of the persp_project()
889  *  function.
890  */
set_projection_viewport(int x,int y,int w,int h)891 void set_projection_viewport(int x, int y, int w, int h)
892 {
893    ASSERT(w > 0);
894    ASSERT(h > 0);
895 
896    _persp_xscale = itofix(w/2);
897    _persp_yscale = itofix(h/2);
898    _persp_xoffset = itofix(x + w/2);
899    _persp_yoffset = itofix(y + h/2);
900 
901    _persp_xscale_f = w/2;
902    _persp_yscale_f = h/2;
903    _persp_xoffset_f = x + w/2;
904    _persp_yoffset_f = y + h/2;
905 }
906 
907