]> icculus.org git repositories - btb/d2x.git/blob - 3d/interp.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / 3d / interp.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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Polygon object interpreter
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <conf.h>
22 #endif
23
24 #include <stdlib.h>
25 #include "dxxerror.h"
26 #include "3d.h"
27 #include "globvars.h"
28 #include "gr.h"
29 #include "byteswap.h"
30 #include "u_mem.h"
31
32
33 #define OP_EOF          0   //eof
34 #define OP_DEFPOINTS    1   //defpoints
35 #define OP_FLATPOLY     2   //flat-shaded polygon
36 #define OP_TMAPPOLY     3   //texture-mapped polygon
37 #define OP_SORTNORM     4   //sort by normal
38 #define OP_RODBM        5   //rod bitmap
39 #define OP_SUBCALL      6   //call a subobject
40 #define OP_DEFP_START   7   //defpoints with start
41 #define OP_GLOW         8   //glow value for next poly
42
43 //#define N_OPCODES (sizeof(opcode_table) / sizeof(*opcode_table))
44
45 #define MAX_POINTS_PER_POLY 25
46
47 short highest_texture_num;
48 int g3d_interp_outline;
49
50 g3s_point *Interp_point_list = NULL;
51
52 #define MAX_INTERP_COLORS 100
53
54 //this is a table of mappings from RGB15 to palette colors
55 struct {short pal_entry,rgb15;} interp_color_table[MAX_INTERP_COLORS];
56
57 int n_interp_colors=0;
58
59 //gives the interpreter an array of points to use
60 void g3_set_interp_points(g3s_point *pointlist)
61 {
62         Interp_point_list = pointlist;
63 }
64
65 #define w(p)  (*((short *) (p)))
66 #define wp(p)  ((short *) (p))
67 #define fp(p)  ((fix *) (p))
68 #define vp(p)  ((vms_vector *) (p))
69
70 void rotate_point_list(g3s_point *dest,vms_vector *src,int n)
71 {
72         while (n--)
73                 g3_rotate_point(dest++,src++);
74 }
75
76 vms_angvec zero_angles = {0,0,0};
77
78 g3s_point *point_list[MAX_POINTS_PER_POLY];
79
80 int glow_num = -1;
81
82 #ifdef WORDS_BIGENDIAN
83 void short_swap(short *s)
84 {
85         *s = SWAPSHORT(*s);
86 }
87
88 void fix_swap(fix *f)
89 {
90         *f = (fix)SWAPINT((int)*f);
91 }
92
93 void vms_vector_swap(vms_vector *v)
94 {
95         fix_swap(fp(&v->x));
96         fix_swap(fp(&v->y));
97         fix_swap(fp(&v->z));
98 }
99
100 void fixang_swap(fixang *f)
101 {
102         *f = (fixang)SWAPSHORT((short)*f);
103 }
104
105 void vms_angvec_swap(vms_angvec *v)
106 {
107         fixang_swap(&v->p);
108         fixang_swap(&v->b);
109         fixang_swap(&v->h);
110 }
111
112 void swap_polygon_model_data(ubyte *data)
113 {
114         int i;
115         short n;
116         g3s_uvl *uvl_val;
117         ubyte *p = data;
118
119         short_swap(wp(p));
120
121         while (w(p) != OP_EOF) {
122                 switch (w(p)) {
123                         case OP_DEFPOINTS:
124                                 short_swap(wp(p + 2));
125                                 n = w(p+2);
126                                 for (i = 0; i < n; i++)
127                                         vms_vector_swap(vp((p + 4) + (i * sizeof(vms_vector))));
128                                 p += n*sizeof(struct vms_vector) + 4;
129                                 break;
130
131                         case OP_DEFP_START:
132                                 short_swap(wp(p + 2));
133                                 short_swap(wp(p + 4));
134                                 n = w(p+2);
135                                 for (i = 0; i < n; i++)
136                                         vms_vector_swap(vp((p + 8) + (i * sizeof(vms_vector))));
137                                 p += n*sizeof(struct vms_vector) + 8;
138                                 break;
139
140                         case OP_FLATPOLY:
141                                 short_swap(wp(p+2));
142                                 n = w(p+2);
143                                 vms_vector_swap(vp(p + 4));
144                                 vms_vector_swap(vp(p + 16));
145                                 short_swap(wp(p+28));
146 #ifdef MACINTOSH
147                                 // swap the colors 0 and 255 here!!!!
148                                 if (w(p+28) == 0)
149                                         w(p+28) = 255;
150                                 else if (w(p+28) == 255)
151                                         w(p+28) = 0;
152 #endif
153                                 for (i=0; i < n; i++)
154                                         short_swap(wp(p + 30 + (i * 2)));
155                                 p += 30 + ((n&~1)+1)*2;
156                                 break;
157
158                         case OP_TMAPPOLY:
159                                 short_swap(wp(p+2));
160                                 n = w(p+2);
161                                 vms_vector_swap(vp(p + 4));
162                                 vms_vector_swap(vp(p + 16));
163                                 for (i=0;i<n;i++) {
164                                         uvl_val = (g3s_uvl *)((p+30+((n&~1)+1)*2) + (i * sizeof(g3s_uvl)));
165                                         fix_swap(&uvl_val->u);
166                                         fix_swap(&uvl_val->v);
167                                 }
168                                 short_swap(wp(p+28));
169                                 for (i=0;i<n;i++)
170                                         short_swap(wp(p + 30 + (i * 2)));
171                                 p += 30 + ((n&~1)+1)*2 + n*12;
172                                 break;
173
174                         case OP_SORTNORM:
175                                 vms_vector_swap(vp(p + 4));
176                                 vms_vector_swap(vp(p + 16));
177                                 short_swap(wp(p + 28));
178                                 short_swap(wp(p + 30));
179                                 swap_polygon_model_data(p + w(p+28));
180                                 swap_polygon_model_data(p + w(p+30));
181                                 p += 32;
182                                 break;
183
184                         case OP_RODBM:
185                                 vms_vector_swap(vp(p + 20));
186                                 vms_vector_swap(vp(p + 4));
187                                 short_swap(wp(p+2));
188                                 fix_swap(fp(p + 16));
189                                 fix_swap(fp(p + 32));
190                                 p+=36;
191                                 break;
192
193                         case OP_SUBCALL:
194                                 short_swap(wp(p+2));
195                                 vms_vector_swap(vp(p+4));
196                                 short_swap(wp(p+16));
197                                 swap_polygon_model_data(p + w(p+16));
198                                 p += 20;
199                                 break;
200
201                         case OP_GLOW:
202                                 short_swap(wp(p + 2));
203                                 p += 4;
204                                 break;
205
206                         default:
207                                 Error("invalid polygon model\n"); //Int3();
208                 }
209                 short_swap(wp(p));
210         }
211 }
212 #endif
213
214 #ifdef WORDS_NEED_ALIGNMENT
215 void add_chunk(ubyte *old_base, ubyte *new_base, int offset,
216                chunk *chunk_list, int *no_chunks)
217 {
218         Assert(*no_chunks + 1 < MAX_CHUNKS); //increase MAX_CHUNKS if you get this
219         chunk_list[*no_chunks].old_base = old_base;
220         chunk_list[*no_chunks].new_base = new_base;
221         chunk_list[*no_chunks].offset = offset;
222         chunk_list[*no_chunks].correction = 0;
223         (*no_chunks)++;
224 }
225
226 /*
227  * finds what chunks the data points to, adds them to the chunk_list, 
228  * and returns the length of the current chunk
229  */
230 int get_chunks(ubyte *data, ubyte *new_data, chunk *list, int *no)
231 {
232         short n;
233         ubyte *p = data;
234
235         while (INTEL_SHORT(w(p)) != OP_EOF) {
236                 switch (INTEL_SHORT(w(p))) {
237                 case OP_DEFPOINTS:
238                         n = INTEL_SHORT(w(p+2));
239                         p += n*sizeof(struct vms_vector) + 4;
240                         break;
241                 case OP_DEFP_START:
242                         n = INTEL_SHORT(w(p+2));
243                         p += n*sizeof(struct vms_vector) + 8;
244                         break;
245                 case OP_FLATPOLY:
246                         n = INTEL_SHORT(w(p+2));
247                         p += 30 + ((n&~1)+1)*2;
248                         break;
249                 case OP_TMAPPOLY:
250                         n = INTEL_SHORT(w(p+2));
251                         p += 30 + ((n&~1)+1)*2 + n*12;
252                         break;
253                 case OP_SORTNORM:
254                         add_chunk(p, p - data + new_data, 28, list, no);
255                         add_chunk(p, p - data + new_data, 30, list, no);
256                         p += 32;
257                         break;
258                 case OP_RODBM:
259                         p+=36;
260                         break;
261                 case OP_SUBCALL:
262                         add_chunk(p, p - data + new_data, 16, list, no);
263                         p+=20;
264                         break;
265                 case OP_GLOW:
266                         p += 4;
267                         break;
268                 default:
269                         Error("invalid polygon model\n");
270                 }
271         }
272         return p + 2 - data;
273 }
274 #endif //def WORDS_NEED_ALIGNMENT
275
276 void verify(ubyte *data)
277 {
278         short n;
279         ubyte *p = data;
280
281         while (w(p) != OP_EOF) {
282                 switch (w(p)) {
283                 case OP_DEFPOINTS:
284                         n = (w(p+2));
285                         p += n*sizeof(struct vms_vector) + 4;
286                         break;
287                 case OP_DEFP_START:
288                         n = (w(p+2));
289                         p += n*sizeof(struct vms_vector) + 8;
290                         break;
291                 case OP_FLATPOLY:
292                         n = (w(p+2));
293                         p += 30 + ((n&~1)+1)*2;
294                         break;
295                 case OP_TMAPPOLY:
296                         n = (w(p+2));
297                         p += 30 + ((n&~1)+1)*2 + n*12;
298                         break;
299                 case OP_SORTNORM:
300                         verify(p + w(p + 28));
301                         verify(p + w(p + 30));
302                         p += 32;
303                         break;
304                 case OP_RODBM:
305                         p+=36;
306                         break;
307                 case OP_SUBCALL:
308                         verify(p + w(p + 16));
309                         p+=20;
310                         break;
311                 case OP_GLOW:
312                         p += 4;
313                         break;
314                 default:
315                         Error("invalid polygon model\n");
316                 }
317         }
318 }
319
320
321 //calls the object interpreter to render an object.  The object renderer
322 //is really a seperate pipeline. returns true if drew
323 bool g3_draw_polygon_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,fix model_light,fix *glow_values)
324 {
325         ubyte *p = model_ptr;
326
327         glow_num = -1;          //glow off by default
328
329         while (w(p) != OP_EOF)
330
331                 switch (w(p)) {
332
333                         case OP_DEFPOINTS: {
334                                 int n = w(p+2);
335
336                                 rotate_point_list(Interp_point_list,vp(p+4),n);
337                                 p += n*sizeof(struct vms_vector) + 4;
338
339                                 break;
340                         }
341
342                         case OP_DEFP_START: {
343                                 int n = w(p+2);
344                                 int s = w(p+4);
345
346                                 rotate_point_list(&Interp_point_list[s],vp(p+8),n);
347                                 p += n*sizeof(struct vms_vector) + 8;
348
349                                 break;
350                         }
351
352                         case OP_FLATPOLY: {
353                                 int nv = w(p+2);
354
355                                 Assert( nv < MAX_POINTS_PER_POLY );
356                                 if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) {
357                                         int i;
358 #ifdef FADE_FLATPOLY
359                                         short c;
360                                         unsigned char cc;
361                                         int l;
362 #endif
363
364 //                                      DPH: Now we treat this color as 15bpp
365 //                                      gr_setcolor(w(p+28));
366                                         
367 #ifndef FADE_FLATPOLY
368                                         gr_setcolor(gr_find_closest_color_15bpp(w(p + 28)));
369 #else
370                                         //l = (32 * model_light) >> 16;
371                                         l = f2i(fixmul(i2f(32), model_light));
372                                         if (l<0) l = 0;
373                                         else if (l>32) l = 32;
374                                         cc = gr_find_closest_color_15bpp(w(p+28));
375                                         c = gr_fade_table[(l<<8)|cc];
376                                         gr_setcolor(c);
377 #endif
378
379                                         for (i=0;i<nv;i++)
380                                                 point_list[i] = Interp_point_list + wp(p+30)[i];
381
382                                         g3_draw_poly(nv,point_list);
383                                 }
384
385                                 p += 30 + ((nv&~1)+1)*2;
386                                         
387                                 break;
388                         }
389
390                         case OP_TMAPPOLY: {
391                                 int nv = w(p+2);
392                                 g3s_uvl *uvl_list;
393
394                                 Assert( nv < MAX_POINTS_PER_POLY );
395                                 if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) {
396                                         int i;
397                                         fix light;
398
399                                         //calculate light from surface normal
400
401                                         if (glow_num < 0) {                     //no glow
402
403                                                 light = -vm_vec_dot(&View_matrix.fvec,vp(p+16));
404                                                 light = f1_0/4 + (light*3)/4;
405                                                 light = fixmul(light,model_light);
406                                         }
407                                         else {                          //yes glow
408                                                 light = glow_values[glow_num];
409                                                 glow_num = -1;
410                                         }
411
412                                         //now poke light into l values
413
414                                         uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2);
415
416                                         for (i=0;i<nv;i++)
417                                                 uvl_list[i].l = light;
418
419                                         for (i=0;i<nv;i++)
420                                                 point_list[i] = Interp_point_list + wp(p+30)[i];
421
422                                         g3_draw_tmap(nv,point_list,uvl_list,model_bitmaps[w(p+28)]);
423                                 }
424
425                                 p += 30 + ((nv&~1)+1)*2 + nv*12;
426                                         
427                                 break;
428                         }
429
430                         case OP_SORTNORM:
431
432                                 if (g3_check_normal_facing(vp(p+16),vp(p+4)) > 0) {             //facing
433
434                                         //draw back then front
435
436                                         g3_draw_polygon_model(p+w(p+30),model_bitmaps,anim_angles,model_light,glow_values);
437                                         g3_draw_polygon_model(p+w(p+28),model_bitmaps,anim_angles,model_light,glow_values);
438
439                                 }
440                                 else {                  //not facing.  draw front then back
441
442                                         g3_draw_polygon_model(p+w(p+28),model_bitmaps,anim_angles,model_light,glow_values);
443                                         g3_draw_polygon_model(p+w(p+30),model_bitmaps,anim_angles,model_light,glow_values);
444                                 }
445
446                                 p += 32;
447
448                                 break;
449
450
451                         case OP_RODBM: {
452                                 g3s_point rod_bot_p,rod_top_p;
453
454                                 g3_rotate_point(&rod_bot_p,vp(p+20));
455                                 g3_rotate_point(&rod_top_p,vp(p+4));
456
457                                 g3_draw_rod_tmap(model_bitmaps[w(p+2)],&rod_bot_p,w(p+16),&rod_top_p,w(p+32),f1_0);
458
459                                 p+=36;
460                                 break;
461                         }
462
463                         case OP_SUBCALL: {
464                                 vms_angvec *a;
465
466                                 if (anim_angles)
467                                         a = &anim_angles[w(p+2)];
468                                 else
469                                         a = &zero_angles;
470
471                                 g3_start_instance_angles(vp(p+4),a);
472
473                                 g3_draw_polygon_model(p+w(p+16),model_bitmaps,anim_angles,model_light,glow_values);
474
475                                 g3_done_instance();
476
477                                 p += 20;
478
479                                 break;
480
481                         }
482
483                         case OP_GLOW:
484
485                                 if (glow_values)
486                                         glow_num = w(p+2);
487                                 p += 4;
488                                 break;
489
490                         default:
491                                 Error("invalid polygon model\n");
492                 }
493         return 1;
494 }
495
496 #ifndef NDEBUG
497 int nest_count;
498 #endif
499
500 //alternate interpreter for morphing object
501 bool g3_draw_morphing_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,fix model_light,vms_vector *new_points)
502 {
503         ubyte *p = model_ptr;
504         fix *glow_values = NULL;
505
506         glow_num = -1;          //glow off by default
507
508         while (w(p) != OP_EOF)
509
510                 switch (w(p)) {
511
512                         case OP_DEFPOINTS: {
513                                 int n = w(p+2);
514
515                                 rotate_point_list(Interp_point_list,new_points,n);
516                                 p += n*sizeof(struct vms_vector) + 4;
517
518                                 break;
519                         }
520
521                         case OP_DEFP_START: {
522                                 int n = w(p+2);
523                                 int s = w(p+4);
524
525                                 rotate_point_list(&Interp_point_list[s],new_points,n);
526                                 p += n*sizeof(struct vms_vector) + 8;
527
528                                 break;
529                         }
530
531                         case OP_FLATPOLY: {
532                                 int nv = w(p+2);
533                                 int i,ntris;
534
535                                 gr_setcolor(w(p+28));
536                                 
537                                 for (i=0;i<2;i++)
538                                         point_list[i] = Interp_point_list + wp(p+30)[i];
539
540                                 for (ntris=nv-2;ntris;ntris--) {
541
542                                         point_list[2] = Interp_point_list + wp(p+30)[i++];
543
544                                         g3_check_and_draw_poly(3,point_list,NULL,NULL);
545
546                                         point_list[1] = point_list[2];
547
548                                 }
549
550                                 p += 30 + ((nv&~1)+1)*2;
551                                         
552                                 break;
553                         }
554
555                         case OP_TMAPPOLY: {
556                                 int nv = w(p+2);
557                                 g3s_uvl *uvl_list;
558                                 g3s_uvl morph_uvls[3];
559                                 int i,ntris;
560                                 fix light;
561
562                                 //calculate light from surface normal
563
564                                 if (glow_num < 0) {                     //no glow
565
566                                         light = -vm_vec_dot(&View_matrix.fvec,vp(p+16));
567                                         light = f1_0/4 + (light*3)/4;
568                                         light = fixmul(light,model_light);
569                                 }
570                                 else {                          //yes glow
571                                         light = glow_values[glow_num];
572                                         glow_num = -1;
573                                 }
574
575                                 //now poke light into l values
576
577                                 uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2);
578
579                                 for (i=0;i<3;i++)
580                                         morph_uvls[i].l = light;
581
582                                 for (i=0;i<2;i++) {
583                                         point_list[i] = Interp_point_list + wp(p+30)[i];
584
585                                         morph_uvls[i].u = uvl_list[i].u;
586                                         morph_uvls[i].v = uvl_list[i].v;
587                                 }
588
589                                 for (ntris=nv-2;ntris;ntris--) {
590
591                                         point_list[2] = Interp_point_list + wp(p+30)[i];
592                                         morph_uvls[2].u = uvl_list[i].u;
593                                         morph_uvls[2].v = uvl_list[i].v;
594                                         i++;
595
596                                         g3_check_and_draw_tmap(3,point_list,uvl_list,model_bitmaps[w(p+28)],NULL,NULL);
597
598                                         point_list[1] = point_list[2];
599                                         morph_uvls[1].u = morph_uvls[2].u;
600                                         morph_uvls[1].v = morph_uvls[2].v;
601
602                                 }
603
604                                 p += 30 + ((nv&~1)+1)*2 + nv*12;
605
606                                 break;
607                         }
608
609                         case OP_SORTNORM:
610
611                                 if (g3_check_normal_facing(vp(p+16),vp(p+4)) > 0) {             //facing
612
613                                         //draw back then front
614
615                                         g3_draw_morphing_model(p+w(p+30),model_bitmaps,anim_angles,model_light,new_points);
616                                         g3_draw_morphing_model(p+w(p+28),model_bitmaps,anim_angles,model_light,new_points);
617
618                                 }
619                                 else {                  //not facing.  draw front then back
620
621                                         g3_draw_morphing_model(p+w(p+28),model_bitmaps,anim_angles,model_light,new_points);
622                                         g3_draw_morphing_model(p+w(p+30),model_bitmaps,anim_angles,model_light,new_points);
623                                 }
624
625                                 p += 32;
626
627                                 break;
628
629
630                         case OP_RODBM: {
631                                 g3s_point rod_bot_p,rod_top_p;
632
633                                 g3_rotate_point(&rod_bot_p,vp(p+20));
634                                 g3_rotate_point(&rod_top_p,vp(p+4));
635
636                                 g3_draw_rod_tmap(model_bitmaps[w(p+2)],&rod_bot_p,w(p+16),&rod_top_p,w(p+32),f1_0);
637
638                                 p+=36;
639                                 break;
640                         }
641
642                         case OP_SUBCALL: {
643                                 vms_angvec *a;
644
645                                 if (anim_angles)
646                                         a = &anim_angles[w(p+2)];
647                                 else
648                                         a = &zero_angles;
649
650                                 g3_start_instance_angles(vp(p+4),a);
651
652                                 g3_draw_polygon_model(p+w(p+16),model_bitmaps,anim_angles,model_light,glow_values);
653
654                                 g3_done_instance();
655
656                                 p += 20;
657
658                                 break;
659
660                         }
661
662                         case OP_GLOW:
663
664                                 if (glow_values)
665                                         glow_num = w(p+2);
666                                 p += 4;
667                                 break;
668                 }
669
670         return 1;
671 }
672
673 void init_model_sub(ubyte *p)
674 {
675         Assert(++nest_count < 1000);
676
677         while (w(p) != OP_EOF) {
678
679                 switch (w(p)) {
680
681                         case OP_DEFPOINTS: {
682                                 int n = w(p+2);
683                                 p += n*sizeof(struct vms_vector) + 4;
684                                 break;
685                         }
686
687                         case OP_DEFP_START: {
688                                 int n = w(p+2);
689                                 p += n*sizeof(struct vms_vector) + 8;
690                                 break;
691                         }
692
693                         case OP_FLATPOLY: {
694                                 int nv = w(p+2);
695
696                                 Assert(nv > 2);         //must have 3 or more points
697
698 //                              *wp(p+28) = (short)gr_find_closest_color_15bpp(w(p+28));
699
700                                 p += 30 + ((nv&~1)+1)*2;
701                                         
702                                 break;
703                         }
704
705                         case OP_TMAPPOLY: {
706                                 int nv = w(p+2);
707
708                                 Assert(nv > 2);         //must have 3 or more points
709
710                                 if (w(p+28) > highest_texture_num)
711                                         highest_texture_num = w(p+28);
712
713                                 p += 30 + ((nv&~1)+1)*2 + nv*12;
714                                         
715                                 break;
716                         }
717
718                         case OP_SORTNORM:
719
720                                 init_model_sub(p+w(p+28));
721                                 init_model_sub(p+w(p+30));
722                                 p += 32;
723
724                                 break;
725
726
727                         case OP_RODBM:
728                                 p += 36;
729                                 break;
730
731
732                         case OP_SUBCALL: {
733                                 init_model_sub(p+w(p+16));
734                                 p += 20;
735                                 break;
736
737                         }
738
739                         case OP_GLOW:
740                                 p += 4;
741                                 break;
742                         default:
743                                 Error("invalid polygon model\n");
744                 }
745         }
746 }
747
748 //init code for bitmap models
749 void g3_init_polygon_model(void *model_ptr)
750 {
751         #ifndef NDEBUG
752         nest_count = 0;
753         #endif
754
755         highest_texture_num = -1;
756
757         init_model_sub((ubyte *) model_ptr);
758 }
759
760 //uninit code for bitmap models
761 void g3_uninit_polygon_model(void *model_ptr)
762 {
763         // not required, the above g3_init_polygon_model doesn't change the data
764 }