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