1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program 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
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 //
20 // $Source: r:/prj/lib/src/3d/RCS/instance.asm $
21 // $Revision: 1.8 $
22 // $Author: jaemz $
23 // $Date: 1994/10/24 01:05:30 $
24 //
25 // Instancing routines
26 //
27 // $Log: instance.asm $
28 // Revision 1.8  1994/10/24  01:05:30  jaemz
29 // Fixed inverted pitch problem by saving state of ecx
30 //
31 // Revision 1.7  1994/10/12  01:09:06  jaemz
32 // Inverted wtoo_matrix to make it correct
33 // for lighting
34 //
35 // Revision 1.6  1994/09/20  13:32:48  jaemz
36 // Lighting support
37 //
38 // Revision 1.5  1994/08/18  03:46:57  jaemz
39 // Changed stereo glob names to have underscore for c
40 //
41 // Revision 1.4  1994/07/15  14:13:28  jaemz
42 // Added _view_position with an underscore to make it c readable
43 //
44 // Revision 1.3  1993/08/10  22:54:12  dc
45 // add _3d.inc to includes
46 //
47 // Revision 1.2  1993/06/22  18:35:32  kaboom
48 // Changed g3_matrix_x_matrix to g3_matrix_x_matrix_ so it's callable
49 // from watcom C w/register passing.
50 //
51 // Revision 1.1  1993/05/04  17:39:49  matt
52 // Initial revision
53 //
54 //
55 
56 #include "3d.h"
57 #include "GlobalV.h"
58 #include "lg.h"
59 
60 // externs
61 extern void angles_2_matrix(g3s_angvec *angles, g3s_matrix *view_matrix, int rotation_order);
62 
63 // prototypes
64 uchar instance_x(fixang tx);
65 uchar instance_y(fixang ty);
66 uchar instance_z(fixang tz);
67 void instance_matrix(g3s_matrix *src, g3s_matrix *dest);
68 uchar save_context(void);
69 uchar g3_start_object_angles_zy(g3s_vector *p, fixang ty, fixang tz, int rotation_order);
70 uchar start_obj_common(g3s_vector *p, g3s_angvec *o, int rotation_order);
71 
72 #define MAX_INSTANCE_DEPTH 5
73 
74 #define CONTEXT_SIZE (sizeof(g3s_matrix) + sizeof(g3s_vector))
75 
76 // stack for pushed context while instanced
77 char context_stack[MAX_INSTANCE_DEPTH * CONTEXT_SIZE];
78 char *cstack_ptr = context_stack;
79 
80 long cstack_depth;
81 
82 // takes esi=position. No orientation, just offset
g3_start_object(g3s_vector * p)83 uchar g3_start_object(g3s_vector *p) // position only (no orientation)
84 {
85     if (save_context())
86         return 0;
87 
88     // compute new view position
89     _view_position.gX -= p->gX;
90     _view_position.gY -= p->gY;
91     _view_position.gZ -= p->gZ;
92 
93     return -1; // success
94 }
95 
96 // takes esi=position, ecx=rotation order, angles=eax,ebx,edx
g3_start_object_angles_xyz(g3s_vector * p,fixang tx,fixang ty,fixang tz,int rotation_order)97 uchar g3_start_object_angles_xyz(g3s_vector *p, fixang tx, fixang ty, fixang tz, int rotation_order) {
98     g3s_angvec temp_angles;
99 
100     if (save_context())
101         return 0;
102 
103     temp_angles.tx = tx;
104     temp_angles.ty = ty;
105     temp_angles.tz = tz;
106 
107     return (start_obj_common(p, &temp_angles, rotation_order));
108 }
109 
110 // takes esi=position, edi=orientation vector, ecx=rotation order
g3_start_object_angles_v(g3s_vector * p,g3s_angvec * o,int rotation_order)111 uchar g3_start_object_angles_v(g3s_vector *p, g3s_angvec *o, int rotation_order) {
112     if (save_context())
113         return 0;
114     return (start_obj_common(p, o, rotation_order));
115 }
116 
117 // takes esi=position, edi=orientation vector, ecx=rotation order
start_obj_common(g3s_vector * p,g3s_angvec * o,int rotation_order)118 uchar start_obj_common(g3s_vector *p, g3s_angvec *o, int rotation_order) {
119     g3s_matrix temp_matrix;
120 
121     // compute new context
122     _view_position.gX -= p->gX;
123     _view_position.gY -= p->gY;
124     _view_position.gZ -= p->gZ;
125 
126     // copy obj offset to world to obj structure
127     // used for lighting, dude
128     _wtoo_position = *p;
129 
130     angles_2_matrix(o, &temp_matrix, rotation_order);
131 
132     // rotate view vector through instance matrix
133     g3_vec_rotate(&_view_position, &_view_position, &temp_matrix);
134 
135     // save off to the obj_to_world matrix
136     // untransposed, to get inverse
137     _wtoo_matrix = temp_matrix;
138 
139     g3_transpose(&temp_matrix); // transpose esi in place
140     instance_matrix(&temp_matrix, &view_matrix);
141 
142     return -1; // ok!
143 }
144 
145 // dest=c1*s1+c2*s2
update_m(fix c1,fix s1,fix c2,fix s2)146 fix update_m(fix c1, fix s1, fix c2, fix s2) {
147     int64_t r = fix64_mul(c1, s1) + fix64_mul(c2, s2);
148     return fix64_to_fix(r);
149 }
150 
151 // dest=c1*s1-c2*s2
update_ms(fix c1,fix s1,fix c2,fix s2)152 fix update_ms(fix c1, fix s1, fix c2, fix s2) {
153     int64_t r = fix64_mul(c1, s1) - fix64_mul(c2, s2);
154     return fix64_to_fix(r);
155 }
156 
157 // rotate around the specified axis. angle = ebx
158 // takes esi=position,
g3_start_object_angles_y(g3s_vector * p,fixang ty)159 uchar g3_start_object_angles_y(g3s_vector *p, fixang ty) {
160     if (save_context())
161         return 0;
162 
163     // compute new view position
164     _view_position.gX -= p->gX;
165     _view_position.gY -= p->gY;
166     _view_position.gZ -= p->gZ;
167 
168     return (instance_y(ty));
169 }
170 
171 // get sin & cos - angles still in ebx
instance_y(fixang ty)172 uchar instance_y(fixang ty) {
173     fix sin_y, cos_y;
174     fix temp1, temp2, temp3;
175     int64_t r;
176 
177     fix_sincos(ty, &sin_y, &cos_y);
178 
179     // rotate viewer vars
180     r = fix64_mul(_view_position.gX, cos_y) - fix64_mul(_view_position.gZ, sin_y);
181     temp1 = fix64_to_fix(r);
182 
183     r = fix64_mul(_view_position.gX, sin_y) + fix64_mul(_view_position.gZ, cos_y);
184 
185     _view_position.gX = temp1;
186     _view_position.gZ = fix64_to_fix(r);
187 
188     // now modify matrix
189     temp1 = update_ms(cos_y, vm1, sin_y, vm7);
190     temp2 = update_ms(cos_y, vm2, sin_y, vm8);
191     temp3 = update_ms(cos_y, vm3, sin_y, vm9);
192     vm7 = update_m(sin_y, vm1, cos_y, vm7);
193     vm8 = update_m(sin_y, vm2, cos_y, vm8);
194     vm9 = update_m(sin_y, vm3, cos_y, vm9);
195     vm1 = temp1;
196     vm2 = temp2;
197     vm3 = temp3;
198 
199     // we're done
200     return -1; // ok!
201 }
202 
203 // rotate around the specified axis. angle = ebx
204 // takes esi=position,
g3_start_object_angles_x(g3s_vector * p,fixang tx)205 uchar g3_start_object_angles_x(g3s_vector *p, fixang tx) {
206     if (save_context())
207         return 0;
208 
209     // compute new view position
210     _view_position.gX -= p->gX;
211     _view_position.gY -= p->gY;
212     _view_position.gZ -= p->gZ;
213 
214     return (instance_x(tx));
215 }
216 
217 // get sin & cos - angles still in ebx
instance_x(fixang tx)218 uchar instance_x(fixang tx) {
219     fix temp1, temp2, temp3;
220     fix sin_x, cos_x;
221     int64_t r;
222 
223     fix_sincos(tx, &sin_x, &cos_x);
224 
225     // rotate viewer vars
226     r = fix64_mul(_view_position.gZ, sin_x) + fix64_mul(_view_position.gY, cos_x);
227     temp1 = fix64_to_fix(r);
228 
229     r = fix64_mul(_view_position.gZ, cos_x) - fix64_mul(_view_position.gY, sin_x);
230     _view_position.gY = temp1;
231     _view_position.gZ = fix64_to_fix(r);
232 
233     // now modify matrix
234 
235     temp1 = update_m(cos_x, vm4, sin_x, vm7);
236     temp2 = update_m(cos_x, vm5, sin_x, vm8);
237     temp3 = update_m(cos_x, vm6, sin_x, vm9);
238     vm7 = update_ms(cos_x, vm7, sin_x, vm4);
239     vm8 = update_ms(cos_x, vm8, sin_x, vm5);
240     vm9 = update_ms(cos_x, vm9, sin_x, vm6);
241     vm4 = temp1;
242     vm5 = temp2;
243     vm6 = temp3;
244 
245     // we're done
246     return -1; // ok!
247 }
248 
249 // rotate around the specified axis. angle = ebx
250 // takes esi=position,
g3_start_object_angles_z(g3s_vector * p,fixang tz)251 uchar g3_start_object_angles_z(g3s_vector *p, fixang tz) {
252     if (save_context())
253         return 0;
254 
255     // compute new view position
256     _view_position.gX -= p->gX;
257     _view_position.gY -= p->gY;
258     _view_position.gZ -= p->gZ;
259 
260     return (instance_z(tz));
261 }
262 
263 // get sin & cos - angles still in ebx
instance_z(fixang tz)264 uchar instance_z(fixang tz) {
265     fix temp1, temp2, temp3;
266     fix sin_z, cos_z;
267     int64_t r;
268 
269     fix_sincos(tz, &sin_z, &cos_z);
270 
271     // rotate viewer vars
272     r = fix64_mul(_view_position.gY, sin_z) + fix64_mul(_view_position.gX, cos_z);
273     temp1 = fix64_to_fix(r);
274 
275     r = fix64_mul(_view_position.gY, cos_z) - fix64_mul(_view_position.gX, sin_z);
276     _view_position.gX = temp1;
277     _view_position.gY = fix64_to_fix(r);
278 
279     // now modify matrix
280     temp1 = update_m(cos_z, vm1, sin_z, vm4);
281     temp2 = update_m(cos_z, vm2, sin_z, vm5);
282     temp3 = update_m(cos_z, vm3, sin_z, vm6);
283     vm4 = update_ms(cos_z, vm4, sin_z, vm1);
284     vm5 = update_ms(cos_z, vm5, sin_z, vm2);
285     vm6 = update_ms(cos_z, vm6, sin_z, vm3);
286     vm1 = temp1;
287     vm2 = temp2;
288     vm3 = temp3;
289 
290     // we're done
291     return -1; // ok!
292 }
293 
294 // rotate around the specified axes. angles = ebx edx. esi=position
g3_start_object_angles_xy(g3s_vector * p,fixang tx,fixang ty,int rotation_order)295 uchar g3_start_object_angles_xy(g3s_vector *p, fixang tx, fixang ty, int rotation_order) {
296     if (save_context())
297         return 0;
298 
299     // compute new view position
300     _view_position.gX -= p->gX;
301     _view_position.gY -= p->gY;
302     _view_position.gZ -= p->gZ;
303 
304     if ((rotation_order & 1) == 0) // check xy order
305     {
306         instance_x(tx);
307         return (instance_y(ty));
308     } else {
309         instance_y(ty);
310         return (instance_x(tx));
311     }
312 }
313 
314 // rotate around the specified axes. angles = ebx edx. esi=position
g3_start_object_angles_xz(g3s_vector * p,fixang tx,fixang tz,int rotation_order)315 uchar g3_start_object_angles_xz(g3s_vector *p, fixang tx, fixang tz, int rotation_order) {
316     if (save_context())
317         return 0;
318 
319     // compute new view position
320     _view_position.gX -= p->gX;
321     _view_position.gY -= p->gY;
322     _view_position.gZ -= p->gZ;
323 
324     if ((rotation_order & 2) == 0) // check xz order
325     {
326         instance_x(tx);
327         return (instance_z(tz));
328     } else {
329         instance_z(tz);
330         return (instance_x(tx));
331     }
332 }
333 
334 // rotate around the specified axes. angles = ebx edx. esi=position
g3_start_object_angles_yz(g3s_vector * p,fixang ty,fixang tz,int rotation_order)335 uchar g3_start_object_angles_yz(g3s_vector *p, fixang ty, fixang tz, int rotation_order) {
336     if (save_context())
337         return 0;
338 
339     // compute new view position
340     _view_position.gX -= p->gX;
341     _view_position.gY -= p->gY;
342     _view_position.gZ -= p->gZ;
343 
344     if ((rotation_order & 4) == 0) // check yz order
345     {
346         instance_y(ty);
347         return (instance_z(tz));
348     } else {
349         instance_z(tz);
350         return (instance_y(ty));
351     }
352 }
353 
354 // rotate around the specified axes. angles = ebx edx. esi=position
g3_start_object_angles_zy(g3s_vector * p,fixang ty,fixang tz,int rotation_order)355 uchar g3_start_object_angles_zy(g3s_vector *p, fixang ty, fixang tz, int rotation_order) {
356     if (save_context())
357         return 0;
358 
359     // compute new view position
360     _view_position.gX -= p->gX;
361     _view_position.gY -= p->gY;
362     _view_position.gZ -= p->gZ;
363 
364     instance_z(tz);
365     return (instance_y(ty));
366 }
367 
368 // takes esi=position, edi=object matrix
g3_start_object_matrix(g3s_vector * p,g3s_matrix * m)369 uchar g3_start_object_matrix(g3s_vector *p, g3s_matrix *m) {
370     g3s_matrix temp_matrix;
371 
372     if (save_context())
373         return 0;
374 
375     // compute new view position
376     _view_position.gX -= p->gX;
377     _view_position.gY -= p->gY;
378     _view_position.gZ -= p->gZ;
379 
380     // rotate view vector through instance matrix
381     g3_vec_rotate(&_view_position, &_view_position, m);
382 
383     // copy to temp matrix, since instance routine transposes in place
384     g3_copy_transpose(&temp_matrix, m);
385     instance_matrix(&temp_matrix, &view_matrix);
386 
387     return -1; // ok!
388 }
389 
390 // save the current view matrix + view position.
391 // returns carry set if cannot save. saves all regs
save_context(void)392 uchar save_context(void) {
393     if (cstack_depth == MAX_INSTANCE_DEPTH)
394         return 1;
395 
396     cstack_depth++;
397 
398     // save current context
399     *(g3s_matrix *)cstack_ptr = view_matrix;
400     cstack_ptr += sizeof(g3s_matrix);
401     *(g3s_vector *)cstack_ptr = _view_position;
402     cstack_ptr += sizeof(g3s_vector);
403 
404     return 0;
405 }
406 
407 // scales an object within an object context
408 // argument in eax per c convention
409 // trashes ecx edx and eax
g3_scale_object(fix s)410 void g3_scale_object(fix s) {
411     // scale vm by scale, and divide view_position
412     // down by scale
413 
414     _view_position.gX = fix_div(_view_position.gX, s);
415     _view_position.gY = fix_div(_view_position.gY, s);
416     _view_position.gZ = fix_div(_view_position.gZ, s);
417 
418     // scale vm up by scale
419     vm1 = fix_mul(vm1, s);
420     vm2 = fix_mul(vm2, s);
421     vm3 = fix_mul(vm3, s);
422     vm4 = fix_mul(vm4, s);
423     vm5 = fix_mul(vm5, s);
424     vm6 = fix_mul(vm6, s);
425     vm7 = fix_mul(vm7, s);
426     vm8 = fix_mul(vm8, s);
427     vm9 = fix_mul(vm9, s);
428 }
429 
g3_end_object(void)430 void g3_end_object(void) {
431     if (cstack_depth == 0)
432         return;
433 
434     cstack_depth--;
435 
436     cstack_ptr -= sizeof(g3s_vector);
437     _view_position = *(g3s_vector *)cstack_ptr;
438     cstack_ptr -= sizeof(g3s_matrix);
439     view_matrix = *(g3s_matrix *)cstack_ptr;
440 }
441 
442 // edi = esi * edi.  esi should be transposed before calling
instance_matrix(g3s_matrix * src,g3s_matrix * dest)443 void instance_matrix(g3s_matrix *src, g3s_matrix *dest) {
444     g3s_matrix temp_matrix2;
445 
446     // do multiply
447     g3_matrix_x_matrix(&temp_matrix2, src, dest);
448 
449     // copy to real dest
450     *dest = temp_matrix2;
451 }
452