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