amd64 fixes
[btb/d2x.git] / 3d / interp.c
1 /* $Id: interp.c,v 1.17 2005-03-16 01:56:24 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.17 2005-03-16 01:56:24 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 #ifdef FADE_FLATPOLY
364                                         short c;
365                                         unsigned char cc;
366                                         int l;
367 #endif
368
369 //                                      DPH: Now we treat this color as 15bpp
370 //                                      gr_setcolor(w(p+28));
371                                         
372 #ifndef FADE_FLATPOLY
373                                         gr_setcolor(gr_find_closest_color_15bpp(w(p + 28)));
374 #else
375                                         //l = (32 * model_light) >> 16;
376                                         l = f2i(fixmul(i2f(32), model_light));
377                                         if (l<0) l = 0;
378                                         else if (l>32) l = 32;
379                                         cc = gr_find_closest_color_15bpp(w(p+28));
380                                         c = gr_fade_table[(l<<8)|cc];
381                                         gr_setcolor(c);
382 #endif
383
384                                         for (i=0;i<nv;i++)
385                                                 point_list[i] = Interp_point_list + wp(p+30)[i];
386
387                                         g3_draw_poly(nv,point_list);
388                                 }
389
390                                 p += 30 + ((nv&~1)+1)*2;
391                                         
392                                 break;
393                         }
394
395                         case OP_TMAPPOLY: {
396                                 int nv = w(p+2);
397                                 g3s_uvl *uvl_list;
398
399                                 Assert( nv < MAX_POINTS_PER_POLY );
400                                 if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) {
401                                         int i;
402                                         fix light;
403
404                                         //calculate light from surface normal
405
406                                         if (glow_num < 0) {                     //no glow
407
408                                                 light = -vm_vec_dot(&View_matrix.fvec,vp(p+16));
409                                                 light = f1_0/4 + (light*3)/4;
410                                                 light = fixmul(light,model_light);
411                                         }
412                                         else {                          //yes glow
413                                                 light = glow_values[glow_num];
414                                                 glow_num = -1;
415                                         }
416
417                                         //now poke light into l values
418
419                                         uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2);
420
421                                         for (i=0;i<nv;i++)
422                                                 uvl_list[i].l = light;
423
424                                         for (i=0;i<nv;i++)
425                                                 point_list[i] = Interp_point_list + wp(p+30)[i];
426
427                                         g3_draw_tmap(nv,point_list,uvl_list,model_bitmaps[w(p+28)]);
428                                 }
429
430                                 p += 30 + ((nv&~1)+1)*2 + nv*12;
431                                         
432                                 break;
433                         }
434
435                         case OP_SORTNORM:
436
437                                 if (g3_check_normal_facing(vp(p+16),vp(p+4)) > 0) {             //facing
438
439                                         //draw back then front
440
441                                         g3_draw_polygon_model(p+w(p+30),model_bitmaps,anim_angles,model_light,glow_values);
442                                         g3_draw_polygon_model(p+w(p+28),model_bitmaps,anim_angles,model_light,glow_values);
443
444                                 }
445                                 else {                  //not facing.  draw front then back
446
447                                         g3_draw_polygon_model(p+w(p+28),model_bitmaps,anim_angles,model_light,glow_values);
448                                         g3_draw_polygon_model(p+w(p+30),model_bitmaps,anim_angles,model_light,glow_values);
449                                 }
450
451                                 p += 32;
452
453                                 break;
454
455
456                         case OP_RODBM: {
457                                 g3s_point rod_bot_p,rod_top_p;
458
459                                 g3_rotate_point(&rod_bot_p,vp(p+20));
460                                 g3_rotate_point(&rod_top_p,vp(p+4));
461
462                                 g3_draw_rod_tmap(model_bitmaps[w(p+2)],&rod_bot_p,w(p+16),&rod_top_p,w(p+32),f1_0);
463
464                                 p+=36;
465                                 break;
466                         }
467
468                         case OP_SUBCALL: {
469                                 vms_angvec *a;
470
471                                 if (anim_angles)
472                                         a = &anim_angles[w(p+2)];
473                                 else
474                                         a = &zero_angles;
475
476                                 g3_start_instance_angles(vp(p+4),a);
477
478                                 g3_draw_polygon_model(p+w(p+16),model_bitmaps,anim_angles,model_light,glow_values);
479
480                                 g3_done_instance();
481
482                                 p += 20;
483
484                                 break;
485
486                         }
487
488                         case OP_GLOW:
489
490                                 if (glow_values)
491                                         glow_num = w(p+2);
492                                 p += 4;
493                                 break;
494
495                         default:
496                                 Error("invalid polygon model\n");
497                 }
498         return 1;
499 }
500
501 #ifndef NDEBUG
502 int nest_count;
503 #endif
504
505 //alternate interpreter for morphing object
506 bool g3_draw_morphing_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,fix model_light,vms_vector *new_points)
507 {
508         ubyte *p = model_ptr;
509         fix *glow_values = NULL;
510
511         glow_num = -1;          //glow off by default
512
513         while (w(p) != OP_EOF)
514
515                 switch (w(p)) {
516
517                         case OP_DEFPOINTS: {
518                                 int n = w(p+2);
519
520                                 rotate_point_list(Interp_point_list,new_points,n);
521                                 p += n*sizeof(struct vms_vector) + 4;
522
523                                 break;
524                         }
525
526                         case OP_DEFP_START: {
527                                 int n = w(p+2);
528                                 int s = w(p+4);
529
530                                 rotate_point_list(&Interp_point_list[s],new_points,n);
531                                 p += n*sizeof(struct vms_vector) + 8;
532
533                                 break;
534                         }
535
536                         case OP_FLATPOLY: {
537                                 int nv = w(p+2);
538                                 int i,ntris;
539
540                                 gr_setcolor(w(p+28));
541                                 
542                                 for (i=0;i<2;i++)
543                                         point_list[i] = Interp_point_list + wp(p+30)[i];
544
545                                 for (ntris=nv-2;ntris;ntris--) {
546
547                                         point_list[2] = Interp_point_list + wp(p+30)[i++];
548
549                                         g3_check_and_draw_poly(3,point_list,NULL,NULL);
550
551                                         point_list[1] = point_list[2];
552
553                                 }
554
555                                 p += 30 + ((nv&~1)+1)*2;
556                                         
557                                 break;
558                         }
559
560                         case OP_TMAPPOLY: {
561                                 int nv = w(p+2);
562                                 g3s_uvl *uvl_list;
563                                 g3s_uvl morph_uvls[3];
564                                 int i,ntris;
565                                 fix light;
566
567                                 //calculate light from surface normal
568
569                                 if (glow_num < 0) {                     //no glow
570
571                                         light = -vm_vec_dot(&View_matrix.fvec,vp(p+16));
572                                         light = f1_0/4 + (light*3)/4;
573                                         light = fixmul(light,model_light);
574                                 }
575                                 else {                          //yes glow
576                                         light = glow_values[glow_num];
577                                         glow_num = -1;
578                                 }
579
580                                 //now poke light into l values
581
582                                 uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2);
583
584                                 for (i=0;i<3;i++)
585                                         morph_uvls[i].l = light;
586
587                                 for (i=0;i<2;i++) {
588                                         point_list[i] = Interp_point_list + wp(p+30)[i];
589
590                                         morph_uvls[i].u = uvl_list[i].u;
591                                         morph_uvls[i].v = uvl_list[i].v;
592                                 }
593
594                                 for (ntris=nv-2;ntris;ntris--) {
595
596                                         point_list[2] = Interp_point_list + wp(p+30)[i];
597                                         morph_uvls[2].u = uvl_list[i].u;
598                                         morph_uvls[2].v = uvl_list[i].v;
599                                         i++;
600
601                                         g3_check_and_draw_tmap(3,point_list,uvl_list,model_bitmaps[w(p+28)],NULL,NULL);
602
603                                         point_list[1] = point_list[2];
604                                         morph_uvls[1].u = morph_uvls[2].u;
605                                         morph_uvls[1].v = morph_uvls[2].v;
606
607                                 }
608
609                                 p += 30 + ((nv&~1)+1)*2 + nv*12;
610
611                                 break;
612                         }
613
614                         case OP_SORTNORM:
615
616                                 if (g3_check_normal_facing(vp(p+16),vp(p+4)) > 0) {             //facing
617
618                                         //draw back then front
619
620                                         g3_draw_morphing_model(p+w(p+30),model_bitmaps,anim_angles,model_light,new_points);
621                                         g3_draw_morphing_model(p+w(p+28),model_bitmaps,anim_angles,model_light,new_points);
622
623                                 }
624                                 else {                  //not facing.  draw front then back
625
626                                         g3_draw_morphing_model(p+w(p+28),model_bitmaps,anim_angles,model_light,new_points);
627                                         g3_draw_morphing_model(p+w(p+30),model_bitmaps,anim_angles,model_light,new_points);
628                                 }
629
630                                 p += 32;
631
632                                 break;
633
634
635                         case OP_RODBM: {
636                                 g3s_point rod_bot_p,rod_top_p;
637
638                                 g3_rotate_point(&rod_bot_p,vp(p+20));
639                                 g3_rotate_point(&rod_top_p,vp(p+4));
640
641                                 g3_draw_rod_tmap(model_bitmaps[w(p+2)],&rod_bot_p,w(p+16),&rod_top_p,w(p+32),f1_0);
642
643                                 p+=36;
644                                 break;
645                         }
646
647                         case OP_SUBCALL: {
648                                 vms_angvec *a;
649
650                                 if (anim_angles)
651                                         a = &anim_angles[w(p+2)];
652                                 else
653                                         a = &zero_angles;
654
655                                 g3_start_instance_angles(vp(p+4),a);
656
657                                 g3_draw_polygon_model(p+w(p+16),model_bitmaps,anim_angles,model_light,glow_values);
658
659                                 g3_done_instance();
660
661                                 p += 20;
662
663                                 break;
664
665                         }
666
667                         case OP_GLOW:
668
669                                 if (glow_values)
670                                         glow_num = w(p+2);
671                                 p += 4;
672                                 break;
673                 }
674
675         return 1;
676 }
677
678 void init_model_sub(ubyte *p)
679 {
680         Assert(++nest_count < 1000);
681
682         while (w(p) != OP_EOF) {
683
684                 switch (w(p)) {
685
686                         case OP_DEFPOINTS: {
687                                 int n = w(p+2);
688                                 p += n*sizeof(struct vms_vector) + 4;
689                                 break;
690                         }
691
692                         case OP_DEFP_START: {
693                                 int n = w(p+2);
694                                 p += n*sizeof(struct vms_vector) + 8;
695                                 break;
696                         }
697
698                         case OP_FLATPOLY: {
699                                 int nv = w(p+2);
700
701                                 Assert(nv > 2);         //must have 3 or more points
702
703 //                              *wp(p+28) = (short)gr_find_closest_color_15bpp(w(p+28));
704
705                                 p += 30 + ((nv&~1)+1)*2;
706                                         
707                                 break;
708                         }
709
710                         case OP_TMAPPOLY: {
711                                 int nv = w(p+2);
712
713                                 Assert(nv > 2);         //must have 3 or more points
714
715                                 if (w(p+28) > highest_texture_num)
716                                         highest_texture_num = w(p+28);
717
718                                 p += 30 + ((nv&~1)+1)*2 + nv*12;
719                                         
720                                 break;
721                         }
722
723                         case OP_SORTNORM:
724
725                                 init_model_sub(p+w(p+28));
726                                 init_model_sub(p+w(p+30));
727                                 p += 32;
728
729                                 break;
730
731
732                         case OP_RODBM:
733                                 p += 36;
734                                 break;
735
736
737                         case OP_SUBCALL: {
738                                 init_model_sub(p+w(p+16));
739                                 p += 20;
740                                 break;
741
742                         }
743
744                         case OP_GLOW:
745                                 p += 4;
746                                 break;
747                         default:
748                                 Error("invalid polygon model\n");
749                 }
750         }
751 }
752
753 //init code for bitmap models
754 void g3_init_polygon_model(void *model_ptr)
755 {
756         #ifndef NDEBUG
757         nest_count = 0;
758         #endif
759
760         highest_texture_num = -1;
761
762         init_model_sub((ubyte *) model_ptr);
763 }
764
765 //uninit code for bitmap models
766 void g3_uninit_polygon_model(void *model_ptr)
767 {
768         // not required, the above g3_init_polygon_model doesn't change the data
769         model_ptr = model_ptr;
770 }