whitespace
[btb/d2x.git] / main / morph.c
1 /* $Id: morph.c,v 1.3 2003-01-02 23:31:50 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Morphing code
18  *
19  * Old Log:
20  * Revision 1.5  1995/08/23  21:36:10  allender
21  * mcc compiler warnings fixed
22  *
23  * Revision 1.4  1995/08/12  11:34:19  allender
24  * removed #ifdef NEWDEMO -- always in
25  *
26  * Revision 1.3  1995/07/28  15:39:51  allender
27  * removed fixdiv thing
28  *
29  * Revision 1.2  1995/07/28  15:21:23  allender
30  * inverse magnitude fixup thing
31  *
32  * Revision 1.1  1995/05/16  15:28:05  allender
33  * Initial revision
34  *
35  * Revision 2.1  1995/02/27  18:26:33  john
36  * Fixed bug that was caused by externing Polygon_models, and I had
37  * changed the type of it in polyobj.c, thus causing page faults.
38  *
39  * Revision 2.0  1995/02/27  11:27:44  john
40  * New version 2.0, which has no anonymous unions, builds with
41  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
42  *
43  * Revision 1.35  1995/02/22  14:45:37  allender
44  * remove anonymous unions from object structure
45  *
46  * Revision 1.34  1995/01/14  19:16:52  john
47  * First version of new bitmap paging code.
48  *
49  * Revision 1.33  1995/01/03  20:38:36  john
50  * Externed MAX_MORPH_OBJECTS
51  *
52  * Revision 1.32  1994/11/17  15:34:04  matt
53  * Attempt #4 to fix morph bug
54  *
55  * Revision 1.31  1994/11/15  10:57:14  matt
56  * Tried again to fix morph
57  *
58  * Revision 1.30  1994/11/14  14:06:45  matt
59  * Fixed stupid bug
60  *
61  * Revision 1.29  1994/11/14  11:55:13  matt
62  * Added divide overflow check
63  *
64  * Revision 1.28  1994/09/26  17:28:14  matt
65  * Made new multiple-object morph code work with the demo system
66  *
67  * Revision 1.27  1994/09/26  15:39:56  matt
68  * Allow multiple simultaneous morphing objects
69  *
70  * Revision 1.26  1994/09/11  22:44:59  mike
71  * quick on vecmat function.
72  *
73  * Revision 1.25  1994/08/26  15:36:00  matt
74  * Made eclips usable on more than one object at a time
75  *
76  * Revision 1.24  1994/07/25  00:02:46  matt
77  * Various changes to accomodate new 3d, which no longer takes point numbers
78  * as parms, and now only takes pointers to points.
79  *
80  * Revision 1.23  1994/07/12  12:39:58  matt
81  * Revamped physics system
82  *
83  * Revision 1.22  1994/06/28  11:54:51  john
84  * Made newdemo system record/play directly to/from disk, so
85  * we don't need the 4 MB buffer anymore.
86  *
87  * Revision 1.21  1994/06/27  15:53:01  john
88  * #define'd out the newdemo stuff
89  *
90  *
91  * Revision 1.20  1994/06/16  14:30:19  matt
92  * Moved morph record data call to reder routine
93  *
94  * Revision 1.19  1994/06/16  13:57:23  matt
95  * Added support for morphing objects in demos
96  *
97  * Revision 1.18  1994/06/16  12:24:23  matt
98  * Made robot lighting not mess with Lighting_on so robots now night
99  * according to this variable.
100  *
101  * Revision 1.17  1994/06/14  16:55:01  matt
102  * Got rid of physics_object speed field
103  *
104  * Revision 1.16  1994/06/08  21:16:29  matt
105  * Made objects spin while morphing
106  *
107  * Revision 1.15  1994/06/08  18:21:53  matt
108  * Made morphing objects light correctly
109  *
110  * Revision 1.14  1994/06/07  16:50:49  matt
111  * Made object lighting work correctly; changed name of Ambient_light to
112  * Dynamic_light; cleaned up polygobj object rendering a little.
113  *
114  * Revision 1.13  1994/06/01  16:33:59  yuan
115  * Fixed bug.
116  *
117  *
118  * Revision 1.12  1994/06/01  16:29:08  matt
119  * If morph_frame called on object this isn't the morph object, kill it.
120  *
121  * Revision 1.11  1994/06/01  12:46:34  matt
122  * Added needed include
123  *
124  * Revision 1.10  1994/05/31  22:12:41  matt
125  * Set lighting for morph objects
126  * Don't let another object start morph while one is morphing, unless
127  * that one dies.
128  *
129  * Revision 1.9  1994/05/31  18:49:53  john
130  * Took out debugging printf's that Matt left in.
131  *
132  * Revision 1.8  1994/05/30  22:50:22  matt
133  * Added morph effect for robots
134  *
135  */
136
137 #ifdef HAVE_CONFIG_H
138 #include <conf.h>
139 #endif
140
141 #ifdef RCS
142 static char rcsid[] = "$Id: morph.c,v 1.3 2003-01-02 23:31:50 btb Exp $";
143 #endif
144
145 #include <stdio.h>
146 #include <stdlib.h>
147 #include <string.h>
148
149 #include "fix.h"
150 #include "vecmat.h"
151 #include "gr.h"
152 #include "texmap.h"
153 #include "error.h"
154
155 #include "inferno.h"
156 #include "morph.h"
157 #include "polyobj.h"
158 #include "game.h"
159 #include "lighting.h"
160 #include "newdemo.h"
161 #include "piggy.h"
162
163 #include "mono.h"
164 #include "bm.h"
165 #include "interp.h"
166
167 morph_data morph_objects[MAX_MORPH_OBJECTS];
168
169 //returns ptr to data for this object, or NULL if none
170 morph_data *find_morph_data(object *obj)
171 {
172         int i;
173
174         #ifdef NEWDEMO
175         if (Newdemo_state == ND_STATE_PLAYBACK) {
176                 morph_objects[0].obj = obj;
177                 return &morph_objects[0];
178         }
179         #endif
180
181         for (i=0;i<MAX_MORPH_OBJECTS;i++)
182                 if (morph_objects[i].obj == obj)
183                         return &morph_objects[i];
184
185         return NULL;
186 }
187
188
189 //takes pm, fills in min & max
190 void find_min_max(polymodel *pm,int submodel_num,vms_vector *minv,vms_vector *maxv)
191 {
192         ushort nverts;
193         vms_vector *vp;
194         ushort *data,type;
195
196         data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
197
198         type = *data++;
199
200         Assert(type == 7 || type == 1);
201
202         nverts = *data++;
203
204         if (type==7)
205                 data+=2;                //skip start & pad
206
207         vp = (vms_vector *) data;
208
209         *minv = *maxv = *vp++; nverts--;
210
211         while (nverts--) {
212                 if (vp->x > maxv->x) maxv->x = vp->x;
213                 if (vp->y > maxv->y) maxv->y = vp->y;
214                 if (vp->z > maxv->z) maxv->z = vp->z;
215
216                 if (vp->x < minv->x) minv->x = vp->x;
217                 if (vp->y < minv->y) minv->y = vp->y;
218                 if (vp->z < minv->z) minv->z = vp->z;
219
220                 vp++;
221         }
222
223 }
224
225 #define MORPH_RATE (f1_0*3)
226
227 fix morph_rate = MORPH_RATE;
228
229 void init_points(polymodel *pm,vms_vector *box_size,int submodel_num,morph_data *md)
230 {
231         ushort nverts;
232         vms_vector *vp;
233         ushort *data,type;
234         int i;
235
236         //printf("initing %d ",submodel_num);
237
238         data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
239
240         type = *data++;
241
242         Assert(type == 7 || type == 1);
243
244         nverts = *data++;
245
246         md->n_morphing_points[submodel_num] = 0;
247
248         if (type==7) {
249                 i = *data++;            //get start point number
250                 data++;                         //skip pad
251         }
252         else
253                 i = 0;                          //start at zero
254
255         Assert(i+nverts < MAX_VECS);
256
257         md->submodel_startpoints[submodel_num] = i;
258
259         vp = (vms_vector *) data;
260
261         while (nverts--) {
262                 fix k,dist;
263
264                 if (box_size) {
265                         fix t;
266
267                         k = 0x7fffffff;
268
269                         if (vp->x && f2i(box_size->x)<abs(vp->x)/2 && (t = fixdiv(box_size->x,abs(vp->x))) < k) k=t;
270                         if (vp->y && f2i(box_size->y)<abs(vp->y)/2 && (t = fixdiv(box_size->y,abs(vp->y))) < k) k=t;
271                         if (vp->z && f2i(box_size->z)<abs(vp->z)/2 && (t = fixdiv(box_size->z,abs(vp->z))) < k) k=t;
272
273                         if (k==0x7fffffff) k=0;
274
275                 }
276                 else
277                         k=0;
278
279                 vm_vec_copy_scale(&md->morph_vecs[i],vp,k);
280
281                 dist = vm_vec_normalized_dir_quick(&md->morph_deltas[i],vp,&md->morph_vecs[i]);
282
283                 md->morph_times[i] = fixdiv(dist,morph_rate);
284
285                 if (md->morph_times[i] != 0)
286                         md->n_morphing_points[submodel_num]++;
287
288                 vm_vec_scale(&md->morph_deltas[i],morph_rate);
289
290                 vp++; i++;
291
292         }
293
294         //printf("npoints = %d\n",n_morphing_points[submodel_num]);
295
296 }
297
298 void update_points(polymodel *pm,int submodel_num,morph_data *md)
299 {
300         ushort nverts;
301         vms_vector *vp;
302         ushort *data,type;
303         int i;
304
305         //printf("updating %d ",submodel_num);
306
307         data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
308
309         type = *data++;
310
311         Assert(type == 7 || type == 1);
312
313         nverts = *data++;
314
315         if (type==7) {
316                 i = *data++;            //get start point number
317                 data++;                         //skip pad
318         }
319         else
320                 i = 0;                          //start at zero
321
322         vp = (vms_vector *) data;
323
324         while (nverts--) {
325
326                 if (md->morph_times[i])         //not done yet
327                 {
328
329                         if ((md->morph_times[i] -= FrameTime) <= 0) {
330                                 md->morph_vecs[i] = *vp;
331                                 md->morph_times[i] = 0;
332                                 md->n_morphing_points[submodel_num]--;
333                         }
334                         else
335                                 vm_vec_scale_add2(&md->morph_vecs[i],&md->morph_deltas[i],FrameTime);
336                 }
337
338                 vp++; i++;
339         }
340
341         //printf("npoints = %d\n",n_morphing_points[submodel_num]);
342 }
343
344
345 //process the morphing object for one frame
346 void do_morph_frame(object *obj)
347 {
348         int i;
349         polymodel *pm;
350         morph_data *md;
351
352         md = find_morph_data(obj);
353
354         if (md == NULL) {                                       //maybe loaded half-morphed from disk
355                 obj->flags |= OF_SHOULD_BE_DEAD;                //..so kill it
356                 return;
357         }
358
359         pm = &Polygon_models[md->obj->rtype.pobj_info.model_num];
360
361         //printf("morph_frame active = ");
362         //for (i=0;i<pm->n_models;i++)
363         //      printf("%d ",submodel_active[i]);
364         //printf("\n");
365
366
367         for (i=0;i<pm->n_models;i++)
368                 if (md->submodel_active[i]==1) {
369
370                         update_points(pm,i,md);
371
372                         if (md->n_morphing_points[i] == 0) {            //maybe start submodel
373                                 int t;
374
375                                 md->submodel_active[i] = 2;             //not animating, just visible
376
377                                 md->n_submodels_active--;               //this one done animating
378
379                                 for (t=0;t<pm->n_models;t++)
380                                         if (pm->submodel_parents[t] == i) {             //start this one
381
382                                                 init_points(pm,NULL,t,md);
383                                                 md->n_submodels_active++;
384                                                 md->submodel_active[t] = 1;
385
386                                         }
387                         }
388
389                 }
390
391         if (!md->n_submodels_active) {                  //done morphing!
392
393                 md->obj->control_type = md->morph_save_control_type;
394                 md->obj->movement_type = md->morph_save_movement_type;
395
396                 md->obj->render_type = RT_POLYOBJ;
397
398                 md->obj->mtype.phys_info = md->morph_save_phys_info;
399
400                 md->obj = NULL;
401         }
402
403 }
404
405 vms_vector morph_rotvel = {0x4000,0x2000,0x1000};
406
407 void init_morphs()
408 {
409         int i;
410
411         for (i=0;i<MAX_MORPH_OBJECTS;i++)
412                 morph_objects[i].obj = NULL;
413 }
414
415
416 //make the object morph
417 void morph_start(object *obj)
418 {
419         polymodel *pm;
420         vms_vector pmmin,pmmax;
421         vms_vector box_size;
422         int i;
423         morph_data *md;
424
425         for (i=0;i<MAX_MORPH_OBJECTS;i++)
426                 if (morph_objects[i].obj == NULL || morph_objects[i].obj->type==OBJ_NONE  || morph_objects[i].obj->signature!=morph_objects[i].Morph_sig)
427                         break;
428
429         if (i==MAX_MORPH_OBJECTS)               //no free slots
430                 return;
431
432         md = &morph_objects[i];
433
434         Assert(obj->render_type == RT_POLYOBJ);
435
436         md->obj = obj;
437         md->Morph_sig = obj->signature;
438
439         md->morph_save_control_type = obj->control_type;
440         md->morph_save_movement_type = obj->movement_type;
441         md->morph_save_phys_info = obj->mtype.phys_info;
442
443         Assert(obj->control_type == CT_AI);             //morph objects are also AI objects
444
445         obj->control_type = CT_MORPH;
446         obj->render_type = RT_MORPH;
447         obj->movement_type = MT_PHYSICS;                //RT_NONE;
448
449         obj->mtype.phys_info.rotvel = morph_rotvel;
450
451         pm = &Polygon_models[obj->rtype.pobj_info.model_num];
452
453         find_min_max(pm,0,&pmmin,&pmmax);
454
455         box_size.x = max(-pmmin.x,pmmax.x) / 2;
456         box_size.y = max(-pmmin.y,pmmax.y) / 2;
457         box_size.z = max(-pmmin.z,pmmax.z) / 2;
458
459         for (i=0;i<MAX_VECS;i++)                //clear all points
460                 md->morph_times[i] = 0;
461
462         for (i=1;i<MAX_SUBMODELS;i++)           //clear all parts
463                 md->submodel_active[i] = 0;
464
465         md->submodel_active[0] = 1;             //1 means visible & animating
466
467         md->n_submodels_active = 1;
468
469         //now, project points onto surface of box
470
471         init_points(pm,&box_size,0,md);
472
473 }
474
475 void draw_model(polymodel *pm,int submodel_num,vms_angvec *anim_angles,fix light,morph_data *md)
476 {
477         int i,mn;
478         int facing;
479         int sort_list[MAX_SUBMODELS],sort_n;
480
481
482         //first, sort the submodels
483
484         sort_list[0] = submodel_num;
485         sort_n = 1;
486
487         for (i=0;i<pm->n_models;i++)
488
489                 if (md->submodel_active[i] && pm->submodel_parents[i]==submodel_num) {
490
491                         facing = g3_check_normal_facing(&pm->submodel_pnts[i],&pm->submodel_norms[i]);
492
493                         if (!facing)
494
495                                 sort_list[sort_n++] = i;
496
497                         else {          //put at start
498                                 int t;
499
500                                 for (t=sort_n;t>0;t--)
501                                         sort_list[t] = sort_list[t-1];
502
503                                 sort_list[0] = i;
504
505                                 sort_n++;
506
507
508                         }
509
510                 }
511         
512
513         //now draw everything
514
515         for (i=0;i<sort_n;i++) {
516
517                 mn = sort_list[i];
518
519                 if (mn == submodel_num) {
520                         int i;
521
522                         for (i=0;i<pm->n_textures;i++)          {
523                                 texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]];
524                                 texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]].index];
525                         }
526
527 #ifdef PIGGY_USE_PAGING                 
528                         // Make sure the textures for this object are paged in...
529                         piggy_page_flushed = 0;
530                         for (i=0;i<pm->n_textures;i++)  
531                                 PIGGY_PAGE_IN( texture_list_index[i] );
532                         // Hmmm... cache got flushed in the middle of paging all these in,
533                         // so we need to reread them all in.
534                         if (piggy_page_flushed) {
535                                 piggy_page_flushed = 0;
536                                 for (i=0;i<pm->n_textures;i++)  
537                                         PIGGY_PAGE_IN( texture_list_index[i] );
538                         }
539                         // Make sure that they can all fit in memory.
540                         Assert( piggy_page_flushed == 0 );
541 #endif
542
543
544                         g3_draw_morphing_model(&pm->model_data[pm->submodel_ptrs[submodel_num]],texture_list,anim_angles,light,&md->morph_vecs[md->submodel_startpoints[submodel_num]]);
545
546                 }
547                 else {
548
549                         vms_matrix orient;
550
551                         vm_angles_2_matrix(&orient,&anim_angles[mn]);
552
553                         g3_start_instance_matrix(&pm->submodel_offsets[mn],&orient);
554
555                         draw_model(pm,mn,anim_angles,light,md);
556
557                         g3_done_instance();
558
559                 }
560         }
561
562 }
563
564 void draw_morph_object(object *obj)
565 {
566 //      int save_light;
567         polymodel *po;
568         fix light;
569         morph_data *md;
570
571         md = find_morph_data(obj);
572         Assert(md != NULL);
573
574         Assert(obj->rtype.pobj_info.model_num < N_polygon_models);
575
576         po=&Polygon_models[obj->rtype.pobj_info.model_num];
577
578         light = compute_object_light(obj,NULL);
579
580         g3_start_instance_matrix(&obj->pos,&obj->orient);
581         g3_set_interp_points(robot_points);
582
583         draw_model(po,0,obj->rtype.pobj_info.anim_angles,light,md);
584
585         g3_done_instance();
586
587         #ifdef NEWDEMO
588         if (Newdemo_state == ND_STATE_RECORDING)
589                 newdemo_record_morph_frame(md);
590         #endif
591
592 }
593