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