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