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