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