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