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