]> icculus.org git repositories - btb/d2x.git/blob - main/polyobj.c
change u_int*_t to C99 standard uint*_t
[btb/d2x.git] / main / polyobj.c
1 /* $Id: polyobj.c,v 1.22 2005-07-30 07:46:03 chris 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  * Hacked-in polygon objects
18  *
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <conf.h>
24 #endif
25
26 #ifdef RCS
27 static char rcsid[] = "$Id: polyobj.c,v 1.22 2005-07-30 07:46:03 chris Exp $";
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 // -- I hate this warning in make depend! -- #ifdef DRIVE
35 // -- I hate this warning in make depend! -- #include "drive.h"
36 // -- I hate this warning in make depend! -- #else
37 #include "inferno.h"
38 // -- I hate this warning in make depend! -- #endif
39
40 #include "polyobj.h"
41
42 #include "vecmat.h"
43 #include "interp.h"
44 #include "error.h"
45 #include "mono.h"
46 #include "u_mem.h"
47 #include "args.h"
48 #include "byteswap.h"
49
50 #ifndef DRIVE
51 #include "texmap.h"
52 #include "bm.h"
53 #include "textures.h"
54 #include "object.h"
55 #include "lighting.h"
56 #include "cfile.h"
57 #include "piggy.h"
58 #endif
59
60 #ifdef OGL
61 #include "ogl_init.h"
62 #endif
63
64 polymodel Polygon_models[MAX_POLYGON_MODELS];   // = {&bot11,&bot17,&robot_s2,&robot_b2,&bot11,&bot17,&robot_s2,&robot_b2};
65
66 int D1Share_Polymodel_map[] = {
67         0, 1, 2, 3, 4,
68         5, 6, 7, 8, 9,
69         23, 24, 26, 27, 28,
70         29, 30, 31, 32, 33,
71         34, 93, 94, -1, -1,
72         108, 109, 110, 111, 112,
73         113, 114, 115, 116, 117,
74         118, 119, 120, 121, 122,
75         123, 124, 125, 126, 127,
76         128, 129, 130, 133, 134,
77         136, 137, 138, 139, 140,
78         141, -1, -1, -1, -1,
79         -1, -1, -1, -1, -1,
80         -1, -1, -1, -1, -1,
81         -1, -1, -1, -1, -1,
82         -1, -1, -1, -1, -1,
83         -1, -1, -1, -1, -1,
84 };
85
86 int D1_Polymodel_map[] = {
87         0, 1, 2, 4, 5,
88         6, 7, 8, 9, 10,
89         11, 12, 13, 14, 15,
90         16, 17, 18, 19, 20,
91         21, 22, 23, 24, 25,
92         26, 27, 28, 29, 30,
93         31, 32, 33, 34, 35,
94         36, 37, 38, 39, 93,
95         94, -1, -1, 108, 109,
96         110, 111, 112, 113, 114,
97         115, 116, 117, 118, 119,
98         120, 121, 122, 123, 124,
99         125, 126, 127, 128, 129,
100         130, 131, 132, 133, 134,
101         135, 136, 137, 138, 139,
102         140, 141, 142, -1, -1,
103         -1, -1, -1, -1, -1,
104 };
105
106 int D2Demo_Polymodel_map[] = {
107         41, 42, 47, 48, 49,
108         49, 51, 54, 56, 57,
109         58, 59, 60, 61, 62,
110         63, 65, 66, 74, 74,
111         97, 98, 107, 108, 109,
112         110, -1, -1, 111, 112,
113         113, 114, 115, 116, 117,
114         118, 119, 120, 121, 122,
115         123, 124, 125, 126, 127,
116         128, 129, 130, 133, 134,
117         136, 137, 138, 139, 140,
118         141, 143, 144, 145, 146,
119         147, 148, 149, 150, 151,
120         152, 155, 156, 157, 158,
121         159, -1, -1, -1, -1,
122         -1, -1, -1, -1, -1,
123         -1, -1, -1, -1, -1,
124 };
125
126 int N_polygon_models = 0;
127
128 #define MAX_POLYGON_VECS 1000
129 g3s_point robot_points[MAX_POLYGON_VECS];
130
131 #define PM_COMPATIBLE_VERSION 6
132 #define PM_OBJFILE_VERSION 8
133
134 int     Pof_file_end;
135 int     Pof_addr;
136
137 #define MODEL_BUF_SIZE  32768
138
139 void _pof_cfseek(int len,int type)
140 {
141         switch (type) {
142                 case SEEK_SET:  Pof_addr = len; break;
143                 case SEEK_CUR:  Pof_addr += len;        break;
144                 case SEEK_END:
145                         Assert(len <= 0);       //      seeking from end, better be moving back.
146                         Pof_addr = Pof_file_end + len;
147                         break;
148         }
149
150         if (Pof_addr > MODEL_BUF_SIZE)
151                 Int3();
152 }
153
154 #define pof_cfseek(_buf,_len,_type) _pof_cfseek((_len),(_type))
155
156 int pof_read_int(ubyte *bufp)
157 {
158         int i;
159
160         i = *((int *) &bufp[Pof_addr]);
161         Pof_addr += 4;
162         return INTEL_INT(i);
163
164 //      if (cfread(&i,sizeof(i),1,f) != 1)
165 //              Error("Unexpected end-of-file while reading object");
166 //
167 //      return i;
168 }
169
170 size_t pof_cfread(void *dst, size_t elsize, size_t nelem, ubyte *bufp)
171 {
172         if (Pof_addr + nelem*elsize > Pof_file_end)
173                 return 0;
174
175         memcpy(dst, &bufp[Pof_addr], elsize*nelem);
176
177         Pof_addr += elsize*nelem;
178
179         if (Pof_addr > MODEL_BUF_SIZE)
180                 Int3();
181
182         return nelem;
183 }
184
185 // #define new_read_int(i,f) cfread(&(i),sizeof(i),1,(f))
186 #define new_pof_read_int(i,f) pof_cfread(&(i),sizeof(i),1,(f))
187
188 short pof_read_short(ubyte *bufp)
189 {
190         short s;
191
192         s = *((short *) &bufp[Pof_addr]);
193         Pof_addr += 2;
194         return INTEL_SHORT(s);
195 //      if (cfread(&s,sizeof(s),1,f) != 1)
196 //              Error("Unexpected end-of-file while reading object");
197 //
198 //      return s;
199 }
200
201 void pof_read_string(char *buf,int max_char, ubyte *bufp)
202 {
203         int     i;
204
205         for (i=0; i<max_char; i++) {
206                 if ((*buf++ = bufp[Pof_addr++]) == 0)
207                         break;
208         }
209
210 //      while (max_char-- && (*buf=cfgetc(f)) != 0) buf++;
211
212 }
213
214 void pof_read_vecs(vms_vector *vecs,int n,ubyte *bufp)
215 {
216 //      cfread(vecs,sizeof(vms_vector),n,f);
217
218         memcpy(vecs, &bufp[Pof_addr], n*sizeof(*vecs));
219         Pof_addr += n*sizeof(*vecs);
220
221 #ifdef WORDS_BIGENDIAN
222         while (n > 0)
223                 vms_vector_swap(&vecs[--n]);
224 #endif
225
226         if (Pof_addr > MODEL_BUF_SIZE)
227                 Int3();
228 }
229
230 void pof_read_angs(vms_angvec *angs,int n,ubyte *bufp)
231 {
232         memcpy(angs, &bufp[Pof_addr], n*sizeof(*angs));
233         Pof_addr += n*sizeof(*angs);
234
235 #ifdef WORDS_BIGENDIAN
236         while (n > 0)
237                 vms_angvec_swap(&angs[--n]);
238 #endif
239
240         if (Pof_addr > MODEL_BUF_SIZE)
241                 Int3();
242 }
243
244 #define ID_OHDR 0x5244484f // 'RDHO'  //Object header
245 #define ID_SOBJ 0x4a424f53 // 'JBOS'  //Subobject header
246 #define ID_GUNS 0x534e5547 // 'SNUG'  //List of guns on this object
247 #define ID_ANIM 0x4d494e41 // 'MINA'  //Animation data
248 #define ID_IDTA 0x41544449 // 'ATDI'  //Interpreter data
249 #define ID_TXTR 0x52545854 // 'RTXT'  //Texture filename list
250
251 #ifdef DRIVE
252 #define robot_info void
253 #else
254 vms_angvec anim_angs[N_ANIM_STATES][MAX_SUBMODELS];
255
256 //set the animation angles for this robot.  Gun fields of robot info must
257 //be filled in.
258 void robot_set_angles(robot_info *r,polymodel *pm,vms_angvec angs[N_ANIM_STATES][MAX_SUBMODELS]);
259 #endif
260
261 #define DEBUG_LEVEL CON_NORMAL
262
263 #ifdef WORDS_NEED_ALIGNMENT
264 ubyte * old_dest(chunk o) // return where chunk is (in unaligned struct)
265 {
266         return o.old_base + INTEL_SHORT(*((short *)(o.old_base + o.offset)));
267 }
268 ubyte * new_dest(chunk o) // return where chunk is (in aligned struct)
269 {
270         return o.new_base + INTEL_SHORT(*((short *)(o.old_base + o.offset))) + o.correction;
271 }
272 /*
273  * find chunk with smallest address
274  */
275 int get_first_chunks_index(chunk *chunk_list, int no_chunks)
276 {
277         int i, first_index = 0;
278         Assert(no_chunks >= 1);
279         for (i = 1; i < no_chunks; i++)
280                 if (old_dest(chunk_list[i]) < old_dest(chunk_list[first_index]))
281                         first_index = i;
282         return first_index;
283 }
284 #define SHIFT_SPACE 500 // increase if insufficent
285
286 void align_polygon_model_data(polymodel *pm)
287 {
288         int i, chunk_len;
289         int total_correction = 0;
290         ubyte *cur_old, *cur_new;
291         chunk cur_ch;
292         chunk ch_list[MAX_CHUNKS];
293         int no_chunks = 0;
294         int tmp_size = pm->model_data_size + SHIFT_SPACE;
295         ubyte *tmp = d_malloc(tmp_size); // where we build the aligned version of pm->model_data
296
297         Assert(tmp != NULL);
298         //start with first chunk (is always aligned!)
299         cur_old = pm->model_data;
300         cur_new = tmp;
301         chunk_len = get_chunks(cur_old, cur_new, ch_list, &no_chunks);
302         memcpy(cur_new, cur_old, chunk_len);
303         while (no_chunks > 0) {
304                 int first_index = get_first_chunks_index(ch_list, no_chunks);
305                 cur_ch = ch_list[first_index];
306                 // remove first chunk from array:
307                 no_chunks--;
308                 for (i = first_index; i < no_chunks; i++)
309                         ch_list[i] = ch_list[i + 1];
310                 // if (new) address unaligned:
311                 if ((uint32_t)new_dest(cur_ch) % 4L != 0) {
312                         // calculate how much to move to be aligned
313                         short to_shift = 4 - (uint32_t)new_dest(cur_ch) % 4L;
314                         // correct chunks' addresses
315                         cur_ch.correction += to_shift;
316                         for (i = 0; i < no_chunks; i++)
317                                 ch_list[i].correction += to_shift;
318                         total_correction += to_shift;
319                         Assert((uint32_t)new_dest(cur_ch) % 4L == 0);
320                         Assert(total_correction <= SHIFT_SPACE); // if you get this, increase SHIFT_SPACE
321                 }
322                 //write (corrected) chunk for current chunk:
323                 *((short *)(cur_ch.new_base + cur_ch.offset))
324                   = INTEL_SHORT(cur_ch.correction
325                                 + INTEL_SHORT(*((short *)(cur_ch.old_base + cur_ch.offset))));
326                 //write (correctly aligned) chunk:
327                 cur_old = old_dest(cur_ch);
328                 cur_new = new_dest(cur_ch);
329                 chunk_len = get_chunks(cur_old, cur_new, ch_list, &no_chunks);
330                 memcpy(cur_new, cur_old, chunk_len);
331                 //correct submodel_ptr's for pm, too
332                 for (i = 0; i < MAX_SUBMODELS; i++)
333                         if (pm->model_data + pm->submodel_ptrs[i] >= cur_old
334                             && pm->model_data + pm->submodel_ptrs[i] < cur_old + chunk_len)
335                                 pm->submodel_ptrs[i] += (cur_new - tmp) - (cur_old - pm->model_data);
336         }
337         d_free(pm->model_data);
338         pm->model_data_size += total_correction;
339         pm->model_data = d_malloc(pm->model_data_size);
340         Assert(pm->model_data != NULL);
341         memcpy(pm->model_data, tmp, pm->model_data_size);
342         d_free(tmp);
343 }
344 #endif //def WORDS_NEED_ALIGNMENT
345
346 //reads a binary file containing a 3d model
347 polymodel *read_model_file(polymodel *pm,char *filename,robot_info *r)
348 {
349         CFILE *ifile;
350         short version;
351         int id,len, next_chunk;
352         int anim_flag = 0;
353         ubyte *model_buf;
354
355         model_buf = (ubyte *)d_malloc( MODEL_BUF_SIZE * sizeof(ubyte) );
356         if (!model_buf)
357                 Error("Can't allocate space to read model %s\n", filename);
358
359         if ((ifile=cfopen(filename,"rb"))==NULL)
360                 Error("Can't open file <%s>",filename);
361
362         Assert(cfilelength(ifile) <= MODEL_BUF_SIZE);
363
364         Pof_addr = 0;
365         Pof_file_end = cfread(model_buf, 1, cfilelength(ifile), ifile);
366         cfclose(ifile);
367
368         id = pof_read_int(model_buf);
369
370         if (id!=0x4f505350) /* 'OPSP' */
371                 Error("Bad ID in model file <%s>",filename);
372
373         version = pof_read_short(model_buf);
374         
375         if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION)
376                 Error("Bad version (%d) in model file <%s>",version,filename);
377
378         if ( FindArg( "-bspgen" ))
379                 printf( "bspgen -c1" );
380
381         while (new_pof_read_int(id,model_buf) == 1) {
382                 id = INTEL_INT(id);
383                 //id  = pof_read_int(model_buf);
384                 len = pof_read_int(model_buf);
385                 next_chunk = Pof_addr + len;
386
387                 switch (id) {
388
389                         case ID_OHDR: {         //Object header
390                                 vms_vector pmmin,pmmax;
391
392                                 //con_printf(DEBUG_LEVEL, "Got chunk OHDR, len=%d\n",len);
393
394                                 pm->n_models = pof_read_int(model_buf);
395                                 pm->rad = pof_read_int(model_buf);
396
397                                 Assert(pm->n_models <= MAX_SUBMODELS);
398
399                                 pof_read_vecs(&pmmin,1,model_buf);
400                                 pof_read_vecs(&pmmax,1,model_buf);
401
402                                 if ( FindArg( "-bspgen" ))      {
403                                         vms_vector v;
404                                         fix l;
405                                 
406                                         vm_vec_sub(&v, &pmmax, &pmmin );
407                                         l = v.x;
408                                         if ( v.y > l ) l = v.y;                                 
409                                         if ( v.z > l ) l = v.z;                                 
410                                                                                                         
411                                         printf( " -l%.3f", f2fl(l) );
412                                 }
413
414                                 break;
415                         }
416                         
417                         case ID_SOBJ: {         //Subobject header
418                                 int n;
419
420                                 anim_flag++;
421
422                                 //con_printf(DEBUG_LEVEL, "Got chunk SOBJ, len=%d\n",len);
423
424                                 n = pof_read_short(model_buf);
425
426                                 Assert(n < MAX_SUBMODELS);
427
428                                 pm->submodel_parents[n] = pof_read_short(model_buf);
429
430                                 pof_read_vecs(&pm->submodel_norms[n],1,model_buf);
431                                 pof_read_vecs(&pm->submodel_pnts[n],1,model_buf);
432                                 pof_read_vecs(&pm->submodel_offsets[n],1,model_buf);
433
434                                 pm->submodel_rads[n] = pof_read_int(model_buf);         //radius
435
436                                 pm->submodel_ptrs[n] = pof_read_int(model_buf); //offset
437
438                                 break;
439
440                         }
441                         
442                         #ifndef DRIVE
443                         case ID_GUNS: {         //List of guns on this object
444
445                                 //con_printf(DEBUG_LEVEL, "Got chunk GUNS, len=%d\n",len);
446
447                                 if (r) {
448                                         int i;
449                                         vms_vector gun_dir;
450                                         ubyte gun_used[MAX_GUNS];
451
452                                         r->n_guns = pof_read_int(model_buf);
453
454                                         if ( r->n_guns )
455                                                 anim_flag++;
456
457                                         Assert(r->n_guns <= MAX_GUNS);
458
459                                         for (i=0;i<r->n_guns;i++)
460                                                 gun_used[i] = 0;
461
462                                         for (i=0;i<r->n_guns;i++) {
463                                                 int id;
464
465                                                 id = pof_read_short(model_buf);
466                                                 Assert(id < r->n_guns);
467                                                 Assert(gun_used[id] == 0);
468                                                 gun_used[id] = 1;
469                                                 r->gun_submodels[id] = pof_read_short(model_buf);
470                                                 Assert(r->gun_submodels[id] != 0xff);
471                                                 pof_read_vecs(&r->gun_points[id],1,model_buf);
472
473                                                 if (version >= 7)
474                                                         pof_read_vecs(&gun_dir,1,model_buf);
475                                         }
476                                 }
477                                 else
478                                         pof_cfseek(model_buf,len,SEEK_CUR);
479
480                                 break;
481                         }
482                         
483                         case ID_ANIM:           //Animation data
484                                 //con_printf(DEBUG_LEVEL, "Got chunk ANIM, len=%d\n",len);
485
486                                 anim_flag++;
487
488                                 if (r) {
489                                         int n_frames,f,m;
490
491                                         n_frames = pof_read_short(model_buf);
492
493                                         Assert(n_frames == N_ANIM_STATES);
494
495                                         for (m=0;m<pm->n_models;m++)
496                                                 for (f=0;f<n_frames;f++)
497                                                         pof_read_angs(&anim_angs[f][m], 1, model_buf);
498
499
500                                         robot_set_angles(r,pm,anim_angs);
501                                 
502                                 }
503                                 else
504                                         pof_cfseek(model_buf,len,SEEK_CUR);
505
506                                 break;
507                         #endif
508                         
509                         case ID_TXTR: {         //Texture filename list
510                                 int n;
511                                 char name_buf[128];
512
513                                 //con_printf(DEBUG_LEVEL, "Got chunk TXTR, len=%d\n",len);
514
515                                 n = pof_read_short(model_buf);
516                                 //con_printf(DEBUG_LEVEL, "  num textures = %d\n",n);
517                                 while (n--) {
518                                         pof_read_string(name_buf,128,model_buf);
519                                         //con_printf(DEBUG_LEVEL, "<%s>\n",name_buf);
520                                 }
521
522                                 break;
523                         }
524                         
525                         case ID_IDTA:           //Interpreter data
526                                 //con_printf(DEBUG_LEVEL, "Got chunk IDTA, len=%d\n",len);
527
528                                 pm->model_data = d_malloc(len);
529                                 pm->model_data_size = len;
530
531                                 pof_cfread(pm->model_data,1,len,model_buf);
532
533                                 break;
534
535                         default:
536                                 //con_printf(DEBUG_LEVEL, "Unknown chunk <%c%c%c%c>, len = %d\n",id,id>>8,id>>16,id>>24,len);
537                                 pof_cfseek(model_buf,len,SEEK_CUR);
538                                 break;
539
540                 }
541                 if ( version >= 8 )             // Version 8 needs 4-byte alignment!!!
542                         pof_cfseek(model_buf,next_chunk,SEEK_SET);
543         }
544
545 //      for (i=0;i<pm->n_models;i++)
546 //              pm->submodel_ptrs[i] += (int) pm->model_data;
547
548         if ( FindArg( "-bspgen" )) {
549                 char *p = strchr( filename, '.' );
550                 *p = 0;
551
552                 if ( anim_flag > 1 )
553                         printf( " -a" );
554
555                 printf( " %s.3ds\n", filename );
556                 *p = '.';
557         }
558         
559         d_free(model_buf);
560
561 #ifdef WORDS_NEED_ALIGNMENT
562         align_polygon_model_data(pm);
563 #endif
564 #ifdef WORDS_BIGENDIAN
565         swap_polygon_model_data(pm->model_data);
566 #endif
567         //verify(pm->model_data);
568
569         return pm;
570 }
571
572 //reads the gun information for a model
573 //fills in arrays gun_points & gun_dirs, returns the number of guns read
574 int read_model_guns(char *filename,vms_vector *gun_points, vms_vector *gun_dirs, int *gun_submodels)
575 {
576         CFILE *ifile;
577         short version;
578         int id,len;
579         int n_guns=0;
580         ubyte   *model_buf;
581
582         model_buf = (ubyte *)d_malloc( MODEL_BUF_SIZE * sizeof(ubyte) );
583         if (!model_buf)
584                 Error("Can't allocate space to read model %s\n", filename);
585
586         if ((ifile=cfopen(filename,"rb"))==NULL)
587                 Error("Can't open file <%s>",filename);
588
589         Assert(cfilelength(ifile) <= MODEL_BUF_SIZE);
590
591         Pof_addr = 0;
592         Pof_file_end = cfread(model_buf, 1, cfilelength(ifile), ifile);
593         cfclose(ifile);
594
595         id = pof_read_int(model_buf);
596
597         if (id!=0x4f505350) /* 'OPSP' */
598                 Error("Bad ID in model file <%s>",filename);
599
600         version = pof_read_short(model_buf);
601
602         Assert(version >= 7);           //must be 7 or higher for this data
603
604         if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION)
605                 Error("Bad version (%d) in model file <%s>",version,filename);
606
607         while (new_pof_read_int(id,model_buf) == 1) {
608                 id = INTEL_INT(id);
609                 //id  = pof_read_int(model_buf);
610                 len = pof_read_int(model_buf);
611
612                 if (id == ID_GUNS) {            //List of guns on this object
613
614                         //con_printf(DEBUG_LEVEL, "Got chunk GUNS, len=%d\n",len);
615
616                         int i;
617
618                         n_guns = pof_read_int(model_buf);
619
620                         for (i=0;i<n_guns;i++) {
621                                 int id,sm;
622
623                                 id = pof_read_short(model_buf);
624                                 sm = pof_read_short(model_buf);
625                                 if (gun_submodels)
626                                         gun_submodels[id] = sm;
627                                 else if (sm!=0)
628                                         Error("Invalid gun submodel in file <%s>",filename);
629                                 pof_read_vecs(&gun_points[id],1,model_buf);
630
631                                 pof_read_vecs(&gun_dirs[id],1,model_buf);
632                         }
633
634                 }
635                 else
636                         pof_cfseek(model_buf,len,SEEK_CUR);
637
638         }
639
640         d_free(model_buf);
641         
642         return n_guns;
643 }
644
645 //free up a model, getting rid of all its memory
646 void free_model(polymodel *po)
647 {
648         d_free(po->model_data);
649 }
650
651 grs_bitmap *texture_list[MAX_POLYOBJ_TEXTURES];
652 bitmap_index texture_list_index[MAX_POLYOBJ_TEXTURES];
653
654 int Simple_model_threshhold_scale=5;            //switch when this times radius far away
655
656
657 //draw a polygon model
658
659 void draw_polygon_model(vms_vector *pos,vms_matrix *orient,vms_angvec *anim_angles,int model_num,int flags,fix light,fix *glow_values,bitmap_index alt_textures[])
660 {
661         polymodel *po;
662         int i;
663
664         Assert(model_num < N_polygon_models);
665
666         po=&Polygon_models[model_num];
667
668         //check if should use simple model
669         if (po->simpler_model )                                 //must have a simpler model
670                 if (flags==0)                                                   //can't switch if this is debris
671                         //!!if (!alt_textures) {                                //alternate textures might not match
672                         //alt textures might not match, but in the one case we're using this
673                         //for on 11/14/94, they do match.  So we leave it in.
674                         {
675                                 int cnt=1;
676                                 fix depth;
677         
678                                 depth = g3_calc_point_depth(pos);               //gets 3d depth
679
680                                 while (po->simpler_model && depth > cnt++ * Simple_model_threshhold_scale * po->rad)
681                                         po = &Polygon_models[po->simpler_model-1];
682                         }
683
684         if (alt_textures)
685    {
686                 for (i=0;i<po->n_textures;i++)  {
687                         texture_list_index[i] = alt_textures[i];
688                         texture_list[i] = &GameBitmaps[alt_textures[i].index];
689                 }
690    }
691         else
692    {
693                 for (i=0;i<po->n_textures;i++)  {
694                         texture_list_index[i] = ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]];
695                         texture_list[i] = &GameBitmaps[ObjBitmaps[ObjBitmapPtrs[po->first_texture+i]].index];
696                 }
697    }
698
699 #ifdef PIGGY_USE_PAGING
700         // Make sure the textures for this object are paged in...
701         piggy_page_flushed = 0;
702         for (i=0;i<po->n_textures;i++)  
703                 PIGGY_PAGE_IN( texture_list_index[i] );
704         // Hmmm... cache got flushed in the middle of paging all these in,
705         // so we need to reread them all in.
706         if (piggy_page_flushed) {
707                 piggy_page_flushed = 0;
708                 for (i=0;i<po->n_textures;i++)  
709                         PIGGY_PAGE_IN( texture_list_index[i] );
710         }
711         // Make sure that they can all fit in memory.
712         Assert( piggy_page_flushed == 0 );
713 #endif
714
715         g3_start_instance_matrix(pos,orient);
716
717         g3_set_interp_points(robot_points);
718
719         if (flags == 0)         //draw entire object
720
721                 g3_draw_polygon_model(po->model_data,texture_list,anim_angles,light,glow_values);
722
723         else {
724                 int i;
725         
726                 for (i=0;flags;flags>>=1,i++)
727                         if (flags & 1) {
728                                 vms_vector ofs;
729
730                                 Assert(i < po->n_models);
731
732                                 //if submodel, rotate around its center point, not pivot point
733         
734                                 vm_vec_avg(&ofs,&po->submodel_mins[i],&po->submodel_maxs[i]);
735                                 vm_vec_negate(&ofs);
736                                 g3_start_instance_matrix(&ofs,NULL);
737         
738                                 g3_draw_polygon_model(&po->model_data[po->submodel_ptrs[i]],texture_list,anim_angles,light,glow_values);
739         
740                                 g3_done_instance();
741                         }       
742         }
743
744         g3_done_instance();
745 }
746
747 void free_polygon_models()
748 {
749         int i;
750
751         for (i=0;i<N_polygon_models;i++) {
752                 free_model(&Polygon_models[i]);
753         }
754
755 }
756
757 void polyobj_find_min_max(polymodel *pm)
758 {
759         ushort nverts;
760         vms_vector *vp;
761         ushort *data,type;
762         int m;
763         vms_vector *big_mn,*big_mx;
764         
765         big_mn = &pm->mins;
766         big_mx = &pm->maxs;
767
768         for (m=0;m<pm->n_models;m++) {
769                 vms_vector *mn,*mx,*ofs;
770
771                 mn = &pm->submodel_mins[m];
772                 mx = &pm->submodel_maxs[m];
773                 ofs= &pm->submodel_offsets[m];
774
775                 data = (ushort *)&pm->model_data[pm->submodel_ptrs[m]];
776         
777                 type = *data++;
778         
779                 Assert(type == 7 || type == 1);
780         
781                 nverts = *data++;
782         
783                 if (type==7)
784                         data+=2;                //skip start & pad
785         
786                 vp = (vms_vector *) data;
787         
788                 *mn = *mx = *vp++; nverts--;
789
790                 if (m==0)
791                         *big_mn = *big_mx = *mn;
792         
793                 while (nverts--) {
794                         if (vp->x > mx->x) mx->x = vp->x;
795                         if (vp->y > mx->y) mx->y = vp->y;
796                         if (vp->z > mx->z) mx->z = vp->z;
797         
798                         if (vp->x < mn->x) mn->x = vp->x;
799                         if (vp->y < mn->y) mn->y = vp->y;
800                         if (vp->z < mn->z) mn->z = vp->z;
801         
802                         if (vp->x+ofs->x > big_mx->x) big_mx->x = vp->x+ofs->x;
803                         if (vp->y+ofs->y > big_mx->y) big_mx->y = vp->y+ofs->y;
804                         if (vp->z+ofs->z > big_mx->z) big_mx->z = vp->z+ofs->z;
805         
806                         if (vp->x+ofs->x < big_mn->x) big_mn->x = vp->x+ofs->x;
807                         if (vp->y+ofs->y < big_mn->y) big_mn->y = vp->y+ofs->y;
808                         if (vp->z+ofs->z < big_mn->z) big_mn->z = vp->z+ofs->z;
809         
810                         vp++;
811                 }
812
813 //              printf("Submodel %d:  (%8x,%8x) (%8x,%8x) (%8x,%8x)\n",m,mn->x,mx->x,mn->y,mx->y,mn->z,mx->z);
814         }
815
816 //      printf("Whole model: (%8x,%8x) (%8x,%8x) (%8x,%8x)\n",big_mn->x,big_mx->x,big_mn->y,big_mx->y,big_mn->z,big_mx->z);
817
818 }
819
820 extern short highest_texture_num;       //from the 3d
821
822 char Pof_names[MAX_POLYGON_MODELS][FILENAME_LEN];
823
824 //returns the number of this model
825 #ifndef DRIVE
826 int load_polygon_model(char *filename,int n_textures,int first_texture,robot_info *r)
827 #else
828 int load_polygon_model(char *filename,int n_textures,grs_bitmap ***textures)
829 #endif
830 {
831         #ifdef DRIVE
832         #define r NULL
833         #endif
834
835         Assert(N_polygon_models < MAX_POLYGON_MODELS);
836         Assert(n_textures < MAX_POLYOBJ_TEXTURES);
837
838         //      MK was real tired of those useless, slow mprintfs...
839         if (N_polygon_models > MAX_POLYGON_MODELS - 10)
840                 mprintf(( 0, "Used %d/%d polygon model slots\n", N_polygon_models+1, MAX_POLYGON_MODELS ));
841
842         Assert(strlen(filename) <= 12);
843         strcpy(Pof_names[N_polygon_models],filename);
844
845         read_model_file(&Polygon_models[N_polygon_models],filename,r);
846
847         polyobj_find_min_max(&Polygon_models[N_polygon_models]);
848
849         g3_init_polygon_model(Polygon_models[N_polygon_models].model_data);
850
851         if (highest_texture_num+1 != n_textures)
852                 Error("Model <%s> references %d textures but specifies %d.",filename,highest_texture_num+1,n_textures);
853
854         Polygon_models[N_polygon_models].n_textures = n_textures;
855         Polygon_models[N_polygon_models].first_texture = first_texture;
856         Polygon_models[N_polygon_models].simpler_model = 0;
857
858 //      Assert(polygon_models[N_polygon_models]!=NULL);
859
860         N_polygon_models++;
861
862         return N_polygon_models-1;
863
864 }
865
866
867 void init_polygon_models()
868 {
869         N_polygon_models = 0;
870
871         atexit((void (*)())free_polygon_models);
872
873 }
874
875 //compare against this size when figuring how far to place eye for picture
876 #define BASE_MODEL_SIZE 0x28000
877
878 #define DEFAULT_VIEW_DIST 0x60000
879
880 //draws the given model in the current canvas.  The distance is set to
881 //more-or-less fill the canvas.  Note that this routine actually renders
882 //into an off-screen canvas that it creates, then copies to the current
883 //canvas.
884 void draw_model_picture(int mn,vms_angvec *orient_angles)
885 {
886         vms_vector      temp_pos=ZERO_VECTOR;
887         vms_matrix      temp_orient = IDENTITY_MATRIX;
888 #ifndef OGL
889         grs_canvas      *save_canv = grd_curcanv,*temp_canv;
890 #endif
891
892         Assert(mn>=0 && mn<N_polygon_models);
893
894 #ifdef OGL
895         ogl_start_offscreen_render(0, 0, grd_curcanv->cv_bitmap.bm_w, grd_curcanv->cv_bitmap.bm_h);
896 #else
897         temp_canv = gr_create_canvas(save_canv->cv_bitmap.bm_w,save_canv->cv_bitmap.bm_h);
898         gr_set_current_canvas(temp_canv);
899 #endif
900         gr_clear_canvas( BM_XRGB(0,0,0) );
901
902         g3_start_frame();
903         g3_set_view_matrix(&temp_pos,&temp_orient,0x9000);
904
905         if (Polygon_models[mn].rad != 0)
906                 temp_pos.z = fixmuldiv(DEFAULT_VIEW_DIST,Polygon_models[mn].rad,BASE_MODEL_SIZE);
907         else
908                 temp_pos.z = DEFAULT_VIEW_DIST;
909
910         vm_angles_2_matrix(&temp_orient, orient_angles);
911
912         draw_polygon_model(&temp_pos,&temp_orient,NULL,mn,0,f1_0,NULL,NULL);
913
914         g3_end_frame();
915
916 #ifdef OGL
917         ogl_end_offscreen_render();
918 #else
919         gr_set_current_canvas(save_canv);
920
921         gr_bitmap(0,0,&temp_canv->cv_bitmap);
922
923         gr_free_canvas(temp_canv);
924 #endif
925 }
926
927 #ifndef FAST_FILE_IO
928 /*
929  * reads a polymodel structure from a CFILE
930  */
931 extern void polymodel_read(polymodel *pm, CFILE *fp)
932 {
933         int i;
934
935         pm->n_models = cfile_read_int(fp);
936         pm->model_data_size = cfile_read_int(fp);
937         pm->model_data = (ubyte *)cfile_read_int(fp); // garbage, read it anyway just for consistency
938         for (i = 0; i < MAX_SUBMODELS; i++)
939                 pm->submodel_ptrs[i] = cfile_read_int(fp);
940         for (i = 0; i < MAX_SUBMODELS; i++)
941                 cfile_read_vector(&(pm->submodel_offsets[i]), fp);
942         for (i = 0; i < MAX_SUBMODELS; i++)
943                 cfile_read_vector(&(pm->submodel_norms[i]), fp);
944         for (i = 0; i < MAX_SUBMODELS; i++)
945                 cfile_read_vector(&(pm->submodel_pnts[i]), fp);
946         for (i = 0; i < MAX_SUBMODELS; i++)
947                 pm->submodel_rads[i] = cfile_read_fix(fp);
948         cfread(pm->submodel_parents, MAX_SUBMODELS, 1, fp);
949         for (i = 0; i < MAX_SUBMODELS; i++)
950                 cfile_read_vector(&(pm->submodel_mins[i]), fp);
951         for (i = 0; i < MAX_SUBMODELS; i++)
952                 cfile_read_vector(&(pm->submodel_maxs[i]), fp);
953         cfile_read_vector(&(pm->mins), fp);
954         cfile_read_vector(&(pm->maxs), fp);
955         pm->rad = cfile_read_fix(fp);
956         pm->n_textures = cfile_read_byte(fp);
957         pm->first_texture = cfile_read_short(fp);
958         pm->simpler_model = cfile_read_byte(fp);
959 }
960
961 /*
962  * reads n polymodel structs from a CFILE
963  */
964 extern int polymodel_read_n(polymodel *pm, int n, CFILE *fp)
965 {
966         int i, j;
967
968         for (i = 0; i < n; i++) {
969                 pm[i].n_models = cfile_read_int(fp);
970                 pm[i].model_data_size = cfile_read_int(fp);
971                 pm->model_data = (ubyte *)cfile_read_int(fp); // garbage, read it anyway just for consistency
972                 for (j = 0; j < MAX_SUBMODELS; j++)
973                         pm[i].submodel_ptrs[j] = cfile_read_int(fp);
974                 for (j = 0; j < MAX_SUBMODELS; j++)
975                         cfile_read_vector(&(pm[i].submodel_offsets[j]), fp);
976                 for (j = 0; j < MAX_SUBMODELS; j++)
977                         cfile_read_vector(&(pm[i].submodel_norms[j]), fp);
978                 for (j = 0; j < MAX_SUBMODELS; j++)
979                         cfile_read_vector(&(pm[i].submodel_pnts[j]), fp);
980                 for (j = 0; j < MAX_SUBMODELS; j++)
981                         pm[i].submodel_rads[j] = cfile_read_fix(fp);
982                 cfread(pm[i].submodel_parents, MAX_SUBMODELS, 1, fp);
983                 for (j = 0; j < MAX_SUBMODELS; j++)
984                         cfile_read_vector(&(pm[i].submodel_mins[j]), fp);
985                 for (j = 0; j < MAX_SUBMODELS; j++)
986                         cfile_read_vector(&(pm[i].submodel_maxs[j]), fp);
987                 cfile_read_vector(&(pm[i].mins), fp);
988                 cfile_read_vector(&(pm[i].maxs), fp);
989                 pm[i].rad = cfile_read_fix(fp);
990                 pm[i].n_textures = cfile_read_byte(fp);
991                 pm[i].first_texture = cfile_read_short(fp);
992                 pm[i].simpler_model = cfile_read_byte(fp);
993         }
994         return i;
995 }
996 #endif
997
998
999 /*
1000  * routine which allocates, reads, and inits a polymodel's model_data
1001  */
1002 void polygon_model_data_read(polymodel *pm, CFILE *fp)
1003 {
1004         pm->model_data = d_malloc(pm->model_data_size);
1005         Assert(pm->model_data != NULL);
1006         cfread(pm->model_data, sizeof(ubyte), pm->model_data_size, fp );
1007 #ifdef WORDS_NEED_ALIGNMENT
1008         align_polygon_model_data(pm);
1009 #endif
1010 #ifdef WORDS_BIGENDIAN
1011         swap_polygon_model_data(pm->model_data);
1012 #endif
1013         //verify(pm->model_data);
1014         g3_init_polygon_model(pm->model_data);
1015 }