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