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