This commit was manufactured by cvs2svn to create tag 'd2x-0_1_2'.
[btb/d2x.git] / main / morph.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 #ifdef HAVE_CONFIG_H
15 #include <conf.h>
16 #endif
17
18 #ifdef RCS
19 static char rcsid[] = "$Id: morph.c,v 1.2 2001-01-31 15:17:54 bradleyb Exp $";
20 #endif
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "fix.h"
27 #include "vecmat.h"
28 #include "gr.h"
29 #include "texmap.h"
30 #include "error.h"
31
32 #include "inferno.h"
33 #include "morph.h"
34 #include "polyobj.h"
35 #include "game.h"
36 #include "lighting.h"
37 #include "newdemo.h"
38 #include "piggy.h"
39
40 #include "mono.h"
41 #include "bm.h"
42
43 morph_data morph_objects[MAX_MORPH_OBJECTS];
44
45 //returns ptr to data for this object, or NULL if none
46 morph_data *find_morph_data(object *obj)
47 {
48         int i;
49
50         #ifdef NEWDEMO
51         if (Newdemo_state == ND_STATE_PLAYBACK) {
52                 morph_objects[0].obj = obj;
53                 return &morph_objects[0];
54         }
55         #endif
56
57         for (i=0;i<MAX_MORPH_OBJECTS;i++)
58                 if (morph_objects[i].obj == obj)
59                         return &morph_objects[i];
60
61         return NULL;
62 }
63
64
65 //takes pm, fills in min & max
66 void find_min_max(polymodel *pm,int submodel_num,vms_vector *minv,vms_vector *maxv)
67 {
68         ushort nverts;
69         vms_vector *vp;
70         ushort *data,type;
71
72         data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
73
74         type = *data++;
75
76         Assert(type == 7 || type == 1);
77
78         nverts = *data++;
79
80         if (type==7)
81                 data+=2;                //skip start & pad
82
83         vp = (vms_vector *) data;
84
85         *minv = *maxv = *vp++; nverts--;
86
87         while (nverts--) {
88                 if (vp->x > maxv->x) maxv->x = vp->x;
89                 if (vp->y > maxv->y) maxv->y = vp->y;
90                 if (vp->z > maxv->z) maxv->z = vp->z;
91
92                 if (vp->x < minv->x) minv->x = vp->x;
93                 if (vp->y < minv->y) minv->y = vp->y;
94                 if (vp->z < minv->z) minv->z = vp->z;
95
96                 vp++;
97         }
98
99 }
100
101 #define MORPH_RATE (f1_0*3)
102
103 fix morph_rate = MORPH_RATE;
104
105 void init_points(polymodel *pm,vms_vector *box_size,int submodel_num,morph_data *md)
106 {
107         ushort nverts;
108         vms_vector *vp;
109         ushort *data,type;
110         int i;
111
112         //printf("initing %d ",submodel_num);
113
114         data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
115
116         type = *data++;
117
118         Assert(type == 7 || type == 1);
119
120         nverts = *data++;
121
122         md->n_morphing_points[submodel_num] = 0;
123
124         if (type==7) {
125                 i = *data++;            //get start point number
126                 data++;                         //skip pad
127         }
128         else
129                 i = 0;                          //start at zero
130
131         Assert(i+nverts < MAX_VECS);
132
133         md->submodel_startpoints[submodel_num] = i;
134
135         vp = (vms_vector *) data;
136
137         while (nverts--) {
138                 fix k,dist;
139
140                 if (box_size) {
141                         fix t;
142
143                         k = 0x7fffffff;
144
145                         if (vp->x && f2i(box_size->x)<abs(vp->x)/2 && (t = fixdiv(box_size->x,abs(vp->x))) < k) k=t;
146                         if (vp->y && f2i(box_size->y)<abs(vp->y)/2 && (t = fixdiv(box_size->y,abs(vp->y))) < k) k=t;
147                         if (vp->z && f2i(box_size->z)<abs(vp->z)/2 && (t = fixdiv(box_size->z,abs(vp->z))) < k) k=t;
148
149                         if (k==0x7fffffff) k=0;
150
151                 }
152                 else
153                         k=0;
154
155                 vm_vec_copy_scale(&md->morph_vecs[i],vp,k);
156
157                 dist = vm_vec_normalized_dir_quick(&md->morph_deltas[i],vp,&md->morph_vecs[i]);
158
159                 md->morph_times[i] = fixdiv(dist,morph_rate);
160
161                 if (md->morph_times[i] != 0)
162                         md->n_morphing_points[submodel_num]++;
163
164                 vm_vec_scale(&md->morph_deltas[i],morph_rate);
165
166                 vp++; i++;
167
168         }
169
170         //printf("npoints = %d\n",n_morphing_points[submodel_num]);
171
172 }
173
174 void update_points(polymodel *pm,int submodel_num,morph_data *md)
175 {
176         ushort nverts;
177         vms_vector *vp;
178         ushort *data,type;
179         int i;
180
181         //printf("updating %d ",submodel_num);
182
183         data = (ushort *) &pm->model_data[pm->submodel_ptrs[submodel_num]];
184
185         type = *data++;
186
187         Assert(type == 7 || type == 1);
188
189         nverts = *data++;
190
191         if (type==7) {
192                 i = *data++;            //get start point number
193                 data++;                         //skip pad
194         }
195         else
196                 i = 0;                          //start at zero
197
198         vp = (vms_vector *) data;
199
200         while (nverts--) {
201
202                 if (md->morph_times[i])         //not done yet
203                 {
204
205                         if ((md->morph_times[i] -= FrameTime) <= 0) {
206                                 md->morph_vecs[i] = *vp;
207                                 md->morph_times[i] = 0;
208                                 md->n_morphing_points[submodel_num]--;
209                         }
210                         else
211                                 vm_vec_scale_add2(&md->morph_vecs[i],&md->morph_deltas[i],FrameTime);
212                 }
213
214                 vp++; i++;
215         }
216
217         //printf("npoints = %d\n",n_morphing_points[submodel_num]);
218 }
219
220
221 //process the morphing object for one frame
222 void do_morph_frame(object *obj)
223 {
224         int i;
225         polymodel *pm;
226         morph_data *md;
227
228         md = find_morph_data(obj);
229
230         if (md == NULL) {                                       //maybe loaded half-morphed from disk
231                 obj->flags |= OF_SHOULD_BE_DEAD;                //..so kill it
232                 return;
233         }
234
235         pm = &Polygon_models[md->obj->rtype.pobj_info.model_num];
236
237         //printf("morph_frame active = ");
238         //for (i=0;i<pm->n_models;i++)
239         //      printf("%d ",submodel_active[i]);
240         //printf("\n");
241
242
243         for (i=0;i<pm->n_models;i++)
244                 if (md->submodel_active[i]==1) {
245
246                         update_points(pm,i,md);
247
248                         if (md->n_morphing_points[i] == 0) {            //maybe start submodel
249                                 int t;
250
251                                 md->submodel_active[i] = 2;             //not animating, just visible
252
253                                 md->n_submodels_active--;               //this one done animating
254
255                                 for (t=0;t<pm->n_models;t++)
256                                         if (pm->submodel_parents[t] == i) {             //start this one
257
258                                                 init_points(pm,NULL,t,md);
259                                                 md->n_submodels_active++;
260                                                 md->submodel_active[t] = 1;
261
262                                         }
263                         }
264
265                 }
266
267         if (!md->n_submodels_active) {                  //done morphing!
268
269                 md->obj->control_type = md->morph_save_control_type;
270                 md->obj->movement_type = md->morph_save_movement_type;
271
272                 md->obj->render_type = RT_POLYOBJ;
273
274                 md->obj->mtype.phys_info = md->morph_save_phys_info;
275
276                 md->obj = NULL;
277         }
278
279 }
280
281 vms_vector morph_rotvel = {0x4000,0x2000,0x1000};
282
283 void init_morphs()
284 {
285         int i;
286
287         for (i=0;i<MAX_MORPH_OBJECTS;i++)
288                 morph_objects[i].obj = NULL;
289 }
290
291
292 //make the object morph
293 void morph_start(object *obj)
294 {
295         polymodel *pm;
296         vms_vector pmmin,pmmax;
297         vms_vector box_size;
298         int i;
299         morph_data *md;
300
301         for (i=0;i<MAX_MORPH_OBJECTS;i++)
302                 if (morph_objects[i].obj == NULL || morph_objects[i].obj->type==OBJ_NONE  || morph_objects[i].obj->signature!=morph_objects[i].Morph_sig)
303                         break;
304
305         if (i==MAX_MORPH_OBJECTS)               //no free slots
306                 return;
307
308         md = &morph_objects[i];
309
310         Assert(obj->render_type == RT_POLYOBJ);
311
312         md->obj = obj;
313         md->Morph_sig = obj->signature;
314
315         md->morph_save_control_type = obj->control_type;
316         md->morph_save_movement_type = obj->movement_type;
317         md->morph_save_phys_info = obj->mtype.phys_info;
318
319         Assert(obj->control_type == CT_AI);             //morph objects are also AI objects
320
321         obj->control_type = CT_MORPH;
322         obj->render_type = RT_MORPH;
323         obj->movement_type = MT_PHYSICS;                //RT_NONE;
324
325         obj->mtype.phys_info.rotvel = morph_rotvel;
326
327         pm = &Polygon_models[obj->rtype.pobj_info.model_num];
328
329         find_min_max(pm,0,&pmmin,&pmmax);
330
331         box_size.x = max(-pmmin.x,pmmax.x) / 2;
332         box_size.y = max(-pmmin.y,pmmax.y) / 2;
333         box_size.z = max(-pmmin.z,pmmax.z) / 2;
334
335         for (i=0;i<MAX_VECS;i++)                //clear all points
336                 md->morph_times[i] = 0;
337
338         for (i=1;i<MAX_SUBMODELS;i++)           //clear all parts
339                 md->submodel_active[i] = 0;
340
341         md->submodel_active[0] = 1;             //1 means visible & animating
342
343         md->n_submodels_active = 1;
344
345         //now, project points onto surface of box
346
347         init_points(pm,&box_size,0,md);
348
349 }
350
351 void draw_model(polymodel *pm,int submodel_num,vms_angvec *anim_angles,fix light,morph_data *md)
352 {
353         int i,mn;
354         int facing;
355         int sort_list[MAX_SUBMODELS],sort_n;
356
357
358         //first, sort the submodels
359
360         sort_list[0] = submodel_num;
361         sort_n = 1;
362
363         for (i=0;i<pm->n_models;i++)
364
365                 if (md->submodel_active[i] && pm->submodel_parents[i]==submodel_num) {
366
367                         facing = g3_check_normal_facing(&pm->submodel_pnts[i],&pm->submodel_norms[i]);
368
369                         if (!facing)
370
371                                 sort_list[sort_n++] = i;
372
373                         else {          //put at start
374                                 int t;
375
376                                 for (t=sort_n;t>0;t--)
377                                         sort_list[t] = sort_list[t-1];
378
379                                 sort_list[0] = i;
380
381                                 sort_n++;
382
383
384                         }
385
386                 }
387         
388
389         //now draw everything
390
391         for (i=0;i<sort_n;i++) {
392
393                 mn = sort_list[i];
394
395                 if (mn == submodel_num) {
396                         int i;
397
398                         for (i=0;i<pm->n_textures;i++)          {
399                                 texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]];
400                                 texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[pm->first_texture+i]].index];
401                         }
402
403 #ifdef PIGGY_USE_PAGING                 
404                         // Make sure the textures for this object are paged in...
405                         piggy_page_flushed = 0;
406                         for (i=0;i<pm->n_textures;i++)  
407                                 PIGGY_PAGE_IN( texture_list_index[i] );
408                         // Hmmm... cache got flushed in the middle of paging all these in,
409                         // so we need to reread them all in.
410                         if (piggy_page_flushed) {
411                                 piggy_page_flushed = 0;
412                                 for (i=0;i<pm->n_textures;i++)  
413                                         PIGGY_PAGE_IN( texture_list_index[i] );
414                         }
415                         // Make sure that they can all fit in memory.
416                         Assert( piggy_page_flushed == 0 );
417 #endif
418
419
420                         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]]);
421
422                 }
423                 else {
424
425                         vms_matrix orient;
426
427                         vm_angles_2_matrix(&orient,&anim_angles[mn]);
428
429                         g3_start_instance_matrix(&pm->submodel_offsets[mn],&orient);
430
431                         draw_model(pm,mn,anim_angles,light,md);
432
433                         g3_done_instance();
434
435                 }
436         }
437
438 }
439
440 void draw_morph_object(object *obj)
441 {
442 //      int save_light;
443         polymodel *po;
444         fix light;
445         morph_data *md;
446
447         md = find_morph_data(obj);
448         Assert(md != NULL);
449
450         Assert(obj->rtype.pobj_info.model_num < N_polygon_models);
451
452         po=&Polygon_models[obj->rtype.pobj_info.model_num];
453
454         light = compute_object_light(obj,NULL);
455
456         g3_start_instance_matrix(&obj->pos,&obj->orient);
457         g3_set_interp_points(robot_points);
458
459         draw_model(po,0,obj->rtype.pobj_info.anim_angles,light,md);
460
461         g3_done_instance();
462
463         #ifdef NEWDEMO
464         if (Newdemo_state == ND_STATE_RECORDING)
465                 newdemo_record_morph_frame(md);
466         #endif
467
468 }
469