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