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