1 //------------------------------------- MD2/MD3 LIBRARY BEGINS -------------------------------------
2 
3 #ifdef USE_OPENGL
4 
5 #include "compat.h"
6 #include "build.h"
7 #include "glad/glad.h"
8 #include "pragmas.h"
9 #include "baselayer.h"
10 #include "engine_priv.h"
11 #include "hightile.h"
12 #include "polymost.h"
13 #include "texcache.h"
14 #include "mdsprite.h"
15 #include "cache1d.h"
16 #include "kplib.h"
17 #include "common.h"
18 #include "palette.h"
19 
20 #include "vfs.h"
21 
22 static int32_t curextra=MAXTILES;
23 
24 #define MIN_CACHETIME_PRINT 10
25 
26 
addtileP(int32_t model,int32_t tile,int32_t pallet)27 static int32_t addtileP(int32_t model,int32_t tile,int32_t pallet)
28 {
29     // tile >= 0 && tile < MAXTILES
30 
31     UNREFERENCED_PARAMETER(model);
32     if (curextra==MAXTILES+EXTRATILES-1)
33     {
34         initprintf("warning: max EXTRATILES reached\n");
35         return curextra;
36     }
37 
38     if (tile2model[tile].modelid==-1)
39     {
40         tile2model[tile].pal=pallet;
41         return tile;
42     }
43 
44     if (tile2model[tile].pal==pallet)
45         return tile;
46 
47     while (tile2model[tile].nexttile!=-1)
48     {
49         tile=tile2model[tile].nexttile;
50         if (tile2model[tile].pal==pallet)
51             return tile;
52     }
53 
54     tile2model[tile].nexttile=curextra;
55     tile2model[curextra].pal=pallet;
56 
57     return curextra++;
58 }
59 
Ptile2tile(int32_t tile,int32_t palette)60 int32_t Ptile2tile(int32_t tile,int32_t palette)
61 {
62     int t = tile;
63     while ((tile = tile2model[tile].nexttile) != -1)
64         if (tile2model[tile].pal == palette)
65         {
66             t = tile;
67             break;
68         }
69     return t;
70 }
71 
72 #define MODELALLOCGROUP 256
73 static int32_t nummodelsalloced = 0;
74 
75 static int32_t maxmodelverts = 0, allocmodelverts = 0;
76 static int32_t maxmodeltris = 0, allocmodeltris = 0;
77 static vec3f_t *vertlist = NULL; //temp array to store interpolated vertices for drawing
78 
79 #ifdef USE_GLEXT
80 static int32_t allocvbos = 0, curvbo = 0;
81 static GLuint *vertvbos = NULL;
82 static GLuint *indexvbos = NULL;
83 #endif
84 
85 #ifdef POLYMER
86 static int32_t *tribuf = NULL;
87 static int32_t tribufverts = 0;
88 #endif
89 
90 static mdmodel_t *mdload(const char *);
91 static void mdfree(mdmodel_t *);
92 int32_t globalnoeffect=0;
93 
94 #ifdef USE_GLEXT
md_freevbos()95 void md_freevbos()
96 {
97     int32_t i;
98 
99     for (i=0; i<nextmodelid; i++)
100         if (models[i]->mdnum == 3)
101         {
102             md3model_t *m = (md3model_t *)models[i];
103             if (m->vbos)
104             {
105                 //            OSD_Printf("freeing model %d vbo\n",i);
106                 glDeleteBuffers(m->head.numsurfs, m->vbos);
107                 DO_FREE_AND_NULL(m->vbos);
108             }
109         }
110 
111     if (allocvbos)
112     {
113         glDeleteBuffers(allocvbos, indexvbos);
114         glDeleteBuffers(allocvbos, vertvbos);
115         allocvbos = 0;
116     }
117 }
118 #endif
119 
freeallmodels()120 void freeallmodels()
121 {
122     int32_t i;
123 
124     if (models)
125     {
126         for (i=0; i<nextmodelid; i++) mdfree(models[i]);
127         DO_FREE_AND_NULL(models);
128         nummodelsalloced = 0;
129         nextmodelid = 0;
130     }
131 
132     Bmemset(tile2model,-1,sizeof(tile2model));
133     for (i=0; i<MAXTILES; i++)
134         Bmemset(tile2model[i].hudmem, 0, sizeof(tile2model[i].hudmem));
135 
136     curextra=MAXTILES;
137 
138     if (vertlist)
139     {
140         DO_FREE_AND_NULL(vertlist);
141         allocmodelverts = maxmodelverts = 0;
142         allocmodeltris = maxmodeltris = 0;
143     }
144 
145 #ifdef USE_GLEXT
146     md_freevbos();
147 #endif
148 #ifdef POLYMER
149     DO_FREE_AND_NULL(tribuf);
150 #endif
151 }
152 
153 
154 // Skin texture names can be aliased! This is ugly, but at least correct.
nullskintexids(GLuint texid)155 static void nullskintexids(GLuint texid)
156 {
157     int32_t i, j;
158 
159     for (i=0; i<nextmodelid; i++)
160     {
161         mdmodel_t *m = models[i];
162 
163         if (m->mdnum == 2 || m->mdnum == 3)
164         {
165             mdskinmap_t *sk;
166             md2model_t *m2 = (md2model_t *)m;
167 
168             for (j=0; j < m2->numskins * HICTINT_MEMORY_COMBINATIONS; j++)
169                 if (m2->texid[j] == texid)
170                     m2->texid[j] = 0;
171 
172             for (sk=m2->skinmap; sk; sk=sk->next)
173                 for (j=0; j < HICTINT_MEMORY_COMBINATIONS; j++)
174                     if (sk->texid[j] == texid)
175                         sk->texid[j] = 0;
176         }
177     }
178 }
179 
clearskins(int32_t type)180 void clearskins(int32_t type)
181 {
182     int32_t i, j;
183 
184     for (i=0; i<nextmodelid; i++)
185     {
186         mdmodel_t *m = models[i];
187 
188         if (m->mdnum == 1)
189         {
190             voxmodel_t *v = (voxmodel_t *)m;
191 
192             for (j=0; j<MAXPALOOKUPS; j++)
193                 if (v->texid[j])
194                 {
195                     glDeleteTextures(1, &v->texid[j]);
196                     v->texid[j] = 0;
197                 }
198         }
199         else if ((m->mdnum == 2 || m->mdnum == 3) && type == INVALIDATE_ALL)
200         {
201             mdskinmap_t *sk;
202             md2model_t *m2 = (md2model_t *)m;
203 
204             for (j=0; j < m2->numskins * HICTINT_MEMORY_COMBINATIONS; j++)
205                 if (m2->texid[j])
206                 {
207                     GLuint otexid = m2->texid[j];
208 
209                     glDeleteTextures(1, &m2->texid[j]);
210                     m2->texid[j] = 0;
211 
212                     nullskintexids(otexid);
213                 }
214 
215             for (sk=m2->skinmap; sk; sk=sk->next)
216                 for (j=0; j < HICTINT_MEMORY_COMBINATIONS; j++)
217                     if (sk->texid[j])
218                     {
219                         GLuint otexid = sk->texid[j];
220 
221                         glDeleteTextures(1, &sk->texid[j]);
222                         sk->texid[j] = 0;
223 
224                         nullskintexids(otexid);
225                     }
226         }
227     }
228 
229     for (i=0; i<MAXVOXELS; i++)
230     {
231         voxmodel_t *v = voxmodels[i];
232         if (!v) continue;
233 
234         for (j=0; j<MAXPALOOKUPS; j++)
235             if (v->texid[j])
236             {
237                 glDeleteTextures(1, &v->texid[j]);
238                 v->texid[j] = 0;
239             }
240         if (v->texid8bit)
241         {
242             glDeleteTextures(1, &v->texid8bit);
243             v->texid8bit = 0;
244         }
245     }
246 }
247 
mdinit()248 void mdinit()
249 {
250     freeallmodels();
251     mdinited = 1;
252 }
253 
md_loadmodel(const char * fn)254 int32_t md_loadmodel(const char *fn)
255 {
256     mdmodel_t *vm, **ml;
257 
258     if (!mdinited) mdinit();
259 
260     if (nextmodelid >= nummodelsalloced)
261     {
262         ml = (mdmodel_t **)Xrealloc(models,(nummodelsalloced+MODELALLOCGROUP)*sizeof(void *));
263         models = ml; nummodelsalloced += MODELALLOCGROUP;
264     }
265 
266     vm = mdload(fn); if (!vm) return -1;
267     models[nextmodelid++] = vm;
268     return nextmodelid-1;
269 }
270 
md_setmisc(int32_t modelid,float scale,int32_t shadeoff,float zadd,float yoffset,int32_t flags)271 int32_t md_setmisc(int32_t modelid, float scale, int32_t shadeoff, float zadd, float yoffset, int32_t flags)
272 {
273     mdmodel_t *m;
274 
275     if (!mdinited) mdinit();
276 
277     if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
278     m = models[modelid];
279     m->bscale = scale;
280     m->shadeoff = shadeoff;
281     m->zadd = zadd;
282     m->yoffset = yoffset;
283     m->flags = flags;
284 
285     return 0;
286 }
287 
framename2index(mdmodel_t * vm,const char * nam)288 static int32_t framename2index(mdmodel_t *vm, const char *nam)
289 {
290     int32_t i = 0;
291 
292     switch (vm->mdnum)
293     {
294     case 2:
295     {
296         md2model_t *m = (md2model_t *)vm;
297         md2frame_t *fr;
298         for (i=0; i<m->numframes; i++)
299         {
300             fr = (md2frame_t *)&m->frames[i*m->framebytes];
301             if (!Bstrcmp(fr->name, nam)) break;
302         }
303     }
304     break;
305     case 3:
306     {
307         md3model_t *m = (md3model_t *)vm;
308         for (i=0; i<m->numframes; i++)
309             if (!Bstrcmp(m->head.frames[i].nam,nam)) break;
310     }
311     break;
312     }
313     return i;
314 }
315 
md_defineframe(int32_t modelid,const char * framename,int32_t tilenume,int32_t skinnum,float smoothduration,int32_t pal)316 int32_t md_defineframe(int32_t modelid, const char *framename, int32_t tilenume, int32_t skinnum, float smoothduration, int32_t pal)
317 {
318     md2model_t *m;
319     int32_t i;
320 
321     if (!mdinited) mdinit();
322 
323     if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
324     if ((uint32_t)tilenume >= (uint32_t)MAXTILES) return -2;
325     if (!framename) return -3;
326 
327     tilenume=addtileP(modelid,tilenume,pal);
328     m = (md2model_t *)models[modelid];
329     if (m->mdnum == 1)
330     {
331         tile2model[tilenume].modelid = modelid;
332         tile2model[tilenume].framenum = tile2model[tilenume].skinnum = 0;
333         return 0;
334     }
335 
336     i = framename2index((mdmodel_t *)m,framename);
337     if (i == m->numframes) return -3;   // frame name invalid
338 
339     tile2model[tilenume].modelid = modelid;
340     tile2model[tilenume].framenum = i;
341     tile2model[tilenume].skinnum = skinnum;
342     tile2model[tilenume].smoothduration = Blrintf((float)UINT16_MAX * smoothduration);
343 
344     return i;
345 }
346 
md_defineanimation(int32_t modelid,const char * framestart,const char * frameend,int32_t fpssc,int32_t flags)347 int32_t md_defineanimation(int32_t modelid, const char *framestart, const char *frameend, int32_t fpssc, int32_t flags)
348 {
349     md2model_t *m;
350     mdanim_t ma, *map;
351     int32_t i;
352 
353     if (!mdinited) mdinit();
354 
355     if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
356 
357     Bmemset(&ma, 0, sizeof(ma));
358     m = (md2model_t *)models[modelid];
359     if (m->mdnum < 2) return 0;
360 
361     //find index of start frame
362     i = framename2index((mdmodel_t *)m,framestart);
363     if (i == m->numframes) return -2;
364     ma.startframe = i;
365 
366     //find index of finish frame which must trail start frame
367     i = framename2index((mdmodel_t *)m,frameend);
368     if (i == m->numframes) return -3;
369     ma.endframe = i;
370 
371     ma.fpssc = fpssc;
372     ma.flags = flags;
373 
374     map = (mdanim_t *)Xmalloc(sizeof(mdanim_t));
375 
376     Bmemcpy(map, &ma, sizeof(ma));
377 
378     map->next = m->animations;
379     m->animations = map;
380 
381     return 0;
382 }
383 
384 #if 0
385 // FIXME: CURRENTLY DISABLED: interpolation may access frames we consider 'unused'?
386 int32_t md_thinoutmodel(int32_t modelid, uint8_t *usedframebitmap)
387 {
388     md3model_t *m;
389     md3surf_t *s;
390     mdanim_t *anm;
391     int32_t i, surfi, sub, usedframes;
392     static int16_t otonframe[1024];
393 
394     if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
395     m = (md3model_t *)models[modelid];
396     if (m->mdnum != 3) return -2;
397 
398     for (anm=m->animations; anm; anm=anm->next)
399     {
400         if (anm->endframe <= anm->startframe)
401         {
402 //            initprintf("backward anim %d-%d\n", anm->startframe, anm->endframe);
403             return -3;
404         }
405 
406         for (i=anm->startframe; i<anm->endframe; i++)
407             usedframebitmap[i>>3] |= pow2char[i&7];
408     }
409 
410     sub = 0;
411     for (i=0; i<m->numframes; i++)
412     {
413         if (!(usedframebitmap[i>>3]&pow2char[i&7]))
414         {
415             sub++;
416             otonframe[i] = -1;
417             continue;
418         }
419 
420         otonframe[i] = i-sub;
421     }
422 
423     usedframes = m->numframes - sub;
424     if (usedframes==0 || usedframes==m->numframes)
425         return usedframes;
426 
427     //// THIN OUT! ////
428 
429     for (i=0; i<m->numframes; i++)
430     {
431         if (otonframe[i]>=0 && otonframe[i] != i)
432         {
433             if (m->muladdframes)
434                 Bmemcpy(&m->muladdframes[2*otonframe[i]], &m->muladdframes[2*i], 2*sizeof(vec3f_t));
435             Bmemcpy(&m->head.frames[otonframe[i]], &m->head.frames[i], sizeof(md3frame_t));
436         }
437     }
438 
439     for (surfi=0; surfi < m->head.numsurfs; surfi++)
440     {
441         s = &m->head.surfs[surfi];
442 
443         for (i=0; i<m->numframes; i++)
444             if (otonframe[i]>=0 && otonframe[i] != i)
445                 Bmemcpy(&s->xyzn[otonframe[i]*s->numverts], &s->xyzn[i*s->numverts], s->numverts*sizeof(md3xyzn_t));
446     }
447 
448     ////// tweak frame indices in various places
449 
450     for (anm=m->animations; anm; anm=anm->next)
451     {
452         if (otonframe[anm->startframe]==-1 || otonframe[anm->endframe-1]==-1)
453             initprintf("md %d WTF: anm %d %d\n", modelid, anm->startframe, anm->endframe);
454 
455         anm->startframe = otonframe[anm->startframe];
456         anm->endframe = otonframe[anm->endframe-1];
457     }
458 
459     for (i=0; i<MAXTILES+EXTRATILES; i++)
460         if (tile2model[i].modelid == modelid)
461         {
462             if (otonframe[tile2model[i].framenum]==-1)
463                 initprintf("md %d WTF: tile %d, fr %d\n", modelid, i, tile2model[i].framenum);
464             tile2model[i].framenum = otonframe[tile2model[i].framenum];
465         }
466 
467     ////// realloc & change "numframes" everywhere
468 
469     if (m->muladdframes)
470         m->muladdframes = Xrealloc(m->muladdframes, 2*sizeof(vec3f_t)*usedframes);
471     m->head.frames = Xrealloc(m->head.frames, sizeof(md3frame_t)*usedframes);
472 
473     for (surfi=0; surfi < m->head.numsurfs; surfi++)
474     {
475         m->head.surfs[surfi].numframes = usedframes;
476         // CAN'T do that because xyzn is offset from a larger block when loaded from md3:
477 //        m->head.surfs[surfi].xyzn = Xrealloc(m->head.surfs[surfi].xyzn, s->numverts*usedframes*sizeof(md3xyzn_t));
478     }
479 
480     m->head.numframes = usedframes;
481     m->numframes = usedframes;
482 
483     ////////////
484     return usedframes;
485 }
486 #endif
487 
md_defineskin(int32_t modelid,const char * skinfn,int32_t palnum,int32_t skinnum,int32_t surfnum,float param,float specpower,float specfactor,int32_t flags)488 int32_t md_defineskin(int32_t modelid, const char *skinfn, int32_t palnum, int32_t skinnum, int32_t surfnum, float param, float specpower, float specfactor, int32_t flags)
489 {
490     mdskinmap_t *sk, *skl;
491     md2model_t *m;
492 
493     if (!mdinited) mdinit();
494 
495     if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
496     if (!skinfn) return -2;
497     if ((unsigned)palnum >= (unsigned)MAXPALOOKUPS) return -3;
498 
499     m = (md2model_t *)models[modelid];
500     if (m->mdnum < 2) return 0;
501     if (m->mdnum == 2) surfnum = 0;
502 
503     skl = NULL;
504     for (sk = m->skinmap; sk; skl = sk, sk = sk->next)
505         if (sk->palette == (uint8_t)palnum && skinnum == sk->skinnum && surfnum == sk->surfnum)
506             break;
507     if (!sk)
508     {
509         sk = (mdskinmap_t *)Xcalloc(1,sizeof(mdskinmap_t));
510 
511         if (!skl) m->skinmap = sk;
512         else skl->next = sk;
513     }
514     else Xfree(sk->fn);
515 
516     sk->palette = (uint8_t)palnum;
517     sk->flags = (uint8_t)flags;
518     sk->skinnum = skinnum;
519     sk->surfnum = surfnum;
520     sk->param = param;
521     sk->specpower = specpower;
522     sk->specfactor = specfactor;
523     sk->fn = Xstrdup(skinfn);
524 
525     return 0;
526 }
527 
md_definehud(int32_t modelid,int32_t tilex,vec3f_t add,int32_t angadd,int32_t flags,int32_t fov)528 int32_t md_definehud(int32_t modelid, int32_t tilex, vec3f_t add, int32_t angadd, int32_t flags, int32_t fov)
529 {
530     if (!mdinited) mdinit();
531 
532     if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
533     if ((uint32_t)tilex >= (uint32_t)MAXTILES) return -2;
534 
535     tile2model[tilex].hudmem[(flags>>2)&1] = (hudtyp *)Xmalloc(sizeof(hudtyp));
536 
537     hudtyp * const hud = tile2model[tilex].hudmem[(flags>>2)&1];
538 
539     hud->add = add;
540     hud->angadd = ((int16_t)angadd)|2048;
541     hud->flags = (int16_t)flags;
542     hud->fov = (int16_t)fov;
543 
544     return 0;
545 }
546 
md_undefinetile(int32_t tile)547 int32_t md_undefinetile(int32_t tile)
548 {
549     if (!mdinited) return 0;
550     if ((unsigned)tile >= (unsigned)MAXTILES) return -1;
551 
552     tile2model[tile].modelid = -1;
553     tile2model[tile].nexttile = -1;
554     DO_FREE_AND_NULL(tile2model[tile].hudmem[0]);
555     DO_FREE_AND_NULL(tile2model[tile].hudmem[1]);
556     return 0;
557 }
558 
559 /* this function is problematic, it leaves NULL holes in model[]
560  * (which runs from 0 to nextmodelid-1) */
md_undefinemodel(int32_t modelid)561 int32_t md_undefinemodel(int32_t modelid)
562 {
563     int32_t i;
564     if (!mdinited) return 0;
565     if ((uint32_t)modelid >= (uint32_t)nextmodelid) return -1;
566 
567     for (i=MAXTILES+EXTRATILES-1; i>=0; i--)
568         if (tile2model[i].modelid == modelid)
569         {
570             tile2model[i].modelid = -1;
571             DO_FREE_AND_NULL(tile2model[i].hudmem[0]);
572             DO_FREE_AND_NULL(tile2model[i].hudmem[1]);
573         }
574 
575     if (models)
576     {
577         mdfree(models[modelid]);
578         models[modelid] = NULL;
579     }
580 
581     return 0;
582 }
583 
hicfxmask(size_t pal)584 static inline int32_t hicfxmask(size_t pal)
585 {
586     return globalnoeffect ? 0 : (hictinting[pal].f & HICTINT_IN_MEMORY);
587 }
hicfxid(size_t pal)588 static inline int32_t hicfxid(size_t pal)
589 {
590     return globalnoeffect ? 0 : ((hictinting[pal].f & (HICTINT_GRAYSCALE|HICTINT_INVERT|HICTINT_COLORIZE)) | ((hictinting[pal].f & HICTINT_BLENDMASK)<<3));
591 }
592 
mdloadskin_notfound(char * const skinfile,char const * const fn)593 static int32_t mdloadskin_notfound(char * const skinfile, char const * const fn)
594 {
595     OSD_Printf("Skin \"%s\" not found.\n", fn);
596 
597     skinfile[0] = 0;
598     return 0;
599 }
600 
mdloadskin_failed(char * const skinfile,char const * const fn)601 static int32_t mdloadskin_failed(char * const skinfile, char const * const fn)
602 {
603     OSD_Printf("Failed loading skin file \"%s\".\n", fn);
604 
605     skinfile[0] = 0;
606     return 0;
607 }
608 
609 //Note: even though it says md2model, it works for both md2model&md3model
mdloadskin(md2model_t * m,int32_t number,int32_t pal,int32_t surf)610 int32_t mdloadskin(md2model_t *m, int32_t number, int32_t pal, int32_t surf)
611 {
612     int32_t i;
613     char *skinfile = NULL, fn[BMAX_PATH];
614     GLuint *texidx = NULL;
615     mdskinmap_t *sk, *skzero = NULL;
616     int32_t doalloc = 1;
617 
618     if (m->mdnum == 2)
619         surf = 0;
620 
621     if ((unsigned)pal >= (unsigned)MAXPALOOKUPS)
622         return 0;
623 
624     i = -1;
625     for (sk = m->skinmap; sk; sk = sk->next)
626     {
627         if (sk->palette == pal && sk->skinnum == number && sk->surfnum == surf)
628         {
629             skinfile = sk->fn;
630             texidx = &sk->texid[hicfxid(pal)];
631             Bstrncpyz(fn, skinfile, BMAX_PATH);
632             //OSD_Printf("Using exact match skin (pal=%d,skinnum=%d,surfnum=%d) %s\n",pal,number,surf,skinfile);
633             break;
634         }
635         //If no match, give highest priority to number, then pal.. (Parkar's request, 02/27/2005)
636         else if ((sk->palette ==   0) && (sk->skinnum == number) && (sk->surfnum == surf) && (i < 5)) { i = 5; skzero = sk; }
637         else if ((sk->palette == pal) && (sk->skinnum ==      0) && (sk->surfnum == surf) && (i < 4)) { i = 4; skzero = sk; }
638         else if ((sk->palette ==   0) && (sk->skinnum ==      0) && (sk->surfnum == surf) && (i < 3)) { i = 3; skzero = sk; }
639         else if ((sk->palette ==   0) && (sk->skinnum == number) && (i < 2)) { i = 2; skzero = sk; }
640         else if ((sk->palette == pal) && (sk->skinnum ==      0) && (i < 1)) { i = 1; skzero = sk; }
641         else if ((sk->palette ==   0) && (sk->skinnum ==      0) && (i < 0)) { i = 0; skzero = sk; }
642     }
643 
644     if (!sk)
645     {
646         if (pal >= (MAXPALOOKUPS - RESERVEDPALS))
647             return 0;
648 
649         if (skzero)
650         {
651             skinfile = skzero->fn;
652             texidx = &skzero->texid[hicfxid(pal)];
653             Bstrncpyz(fn, skinfile, BMAX_PATH);
654             //OSD_Printf("Using def skin 0,0 as fallback, pal=%d\n", pal);
655         }
656         else
657             return 0;
658 #if 0
659         {
660             // fall back to the model-defined texture
661             if ((unsigned)number >= (unsigned)m->numskins)
662                 number = 0;
663 
664             // m->skinfn is undefined when md3model_t is cast to md2model_t --> crash
665             skinfile = m->skinfn + number*64;
666             texidx = &m->texid[number * HICTINT_MEMORY_COMBINATIONS + hicfxid(pal)];
667             Bstrncpyz(fn, m->basepath, BMAX_PATH);
668             if ((Bstrlen(fn) + Bstrlen(skinfile)) < BMAX_PATH)
669                 Bstrcat(fn,skinfile);
670             //OSD_Printf("Using MD2/MD3 skin (%d) %s, pal=%d\n",number,skinfile,pal);
671         }
672 #endif
673     }
674 
675     if (skinfile == NULL || !skinfile[0])
676         return 0;
677 
678     if (*texidx)
679         return *texidx;
680 
681     // possibly fetch an already loaded multitexture :_)
682     if (pal >= (MAXPALOOKUPS - RESERVEDPALS))
683         for (i=0; i<nextmodelid; i++)
684             for (skzero = ((md2model_t *)models[i])->skinmap; skzero && sk; skzero = skzero->next)
685                 if (!Bstrcasecmp(skzero->fn, sk->fn) && skzero->texid[hicfxid(pal)])
686                 {
687                     size_t f = hicfxid(pal);
688 
689                     sk->texid[f] = skzero->texid[f];
690                     return sk->texid[f];
691                 }
692 
693     // for sk->flags below
694     if (!sk)
695         sk = skzero;
696 
697     *texidx = 0;
698 
699     buildvfs_kfd filh;
700     if ((filh = kopen4load(fn, 0)) == buildvfs_kfd_invalid)
701         return mdloadskin_notfound(skinfile, fn);
702 
703 
704     int32_t picfillen = kfilelength(filh);
705     kclose(filh);	// FIXME: shouldn't have to do this. bug in cache1d.c
706 
707     int32_t startticks = timerGetTicks(), willprint = 0;
708 
709     char hasalpha;
710     texcacheheader cachead;
711     char texcacheid[BMAX_PATH];
712     texcache_calcid(texcacheid, fn, picfillen, pal<<8, hicfxmask(pal));
713     int32_t gotcache = texcache_readtexheader(texcacheid, &cachead, 1);
714     vec2_t siz = { 0, 0 }, tsiz = { 0, 0 };
715 
716     if (gotcache && !texcache_loadskin(&cachead, &doalloc, texidx, &siz))
717     {
718         tsiz.x = cachead.xdim;
719         tsiz.y = cachead.ydim;
720         hasalpha = !!(cachead.flags & CACHEAD_HASALPHA);
721 
722         if (pal < (MAXPALOOKUPS - RESERVEDPALS))
723             m->usesalpha = hasalpha;
724     }
725     else
726     {
727         polytintflags_t const effect = hicfxmask(pal);
728 
729         // CODEDUP: gloadtile_hi
730 
731         int32_t isart = 0;
732 
733         gotcache = 0;	// the compressed version will be saved to disk
734 
735         int32_t const length = kpzbufload(fn);
736         if (length == 0)
737             return mdloadskin_notfound(skinfile, fn);
738 
739         // tsizx/y = replacement texture's natural size
740         // xsiz/y = 2^x size of replacement
741 
742 #ifdef WITHKPLIB
743         kpgetdim(kpzbuf,picfillen,&tsiz.x,&tsiz.y);
744 #endif
745 
746         if (tsiz.x == 0 || tsiz.y == 0)
747         {
748             if (artCheckUnitFileHeader((uint8_t *)kpzbuf, picfillen))
749                 return mdloadskin_failed(skinfile, fn);
750 
751             tsiz.x = B_LITTLE16(B_UNBUF16(&kpzbuf[16]));
752             tsiz.y = B_LITTLE16(B_UNBUF16(&kpzbuf[18]));
753 
754             if (tsiz.x == 0 || tsiz.y == 0)
755                 return mdloadskin_failed(skinfile, fn);
756 
757             isart = 1;
758         }
759 
760         if (!glinfo.texnpot)
761         {
762             for (siz.x=1; siz.x<tsiz.x; siz.x+=siz.x) { }
763             for (siz.y=1; siz.y<tsiz.y; siz.y+=siz.y) { }
764         }
765         else
766             siz = tsiz;
767 
768         if (isart)
769         {
770             if (tsiz.x * tsiz.y + ARTv1_UNITOFFSET > picfillen)
771                 return mdloadskin_failed(skinfile, fn);
772         }
773 
774         int32_t const bytesperline = siz.x * sizeof(coltype);
775         coltype *pic = (coltype *)Xcalloc(siz.y, bytesperline);
776 
777         static coltype *lastpic = NULL;
778         static char *lastfn = NULL;
779         static int32_t lastsize = 0;
780 
781         if (lastpic && lastfn && !Bstrcmp(lastfn,fn))
782         {
783             willprint=1;
784             Bmemcpy(pic, lastpic, siz.x*siz.y*sizeof(coltype));
785         }
786         else
787         {
788             if (isart)
789             {
790                 artConvertRGB((palette_t *)pic, (uint8_t *)&kpzbuf[ARTv1_UNITOFFSET], siz.x, tsiz.x, tsiz.y);
791             }
792 #ifdef WITHKPLIB
793             else
794             {
795                 if (kprender(kpzbuf,picfillen,(intptr_t)pic,bytesperline,siz.x,siz.y))
796                 {
797                     Xfree(pic);
798                     return mdloadskin_failed(skinfile, fn);
799                 }
800             }
801 #endif
802 
803             willprint=2;
804 
805             if (hicprecaching)
806             {
807                 lastfn = fn;  // careful...
808                 if (!lastpic)
809                 {
810                     lastpic = (coltype *)Xmalloc(siz.x*siz.y*sizeof(coltype));
811                     lastsize = siz.x*siz.y;
812                 }
813                 else if (lastsize < siz.x*siz.y)
814                 {
815                     Xfree(lastpic);
816                     lastpic = (coltype *)Xmalloc(siz.x*siz.y*sizeof(coltype));
817                 }
818                 if (lastpic)
819                     Bmemcpy(lastpic, pic, siz.x*siz.y*sizeof(coltype));
820             }
821             else if (lastpic)
822             {
823                 DO_FREE_AND_NULL(lastpic);
824                 lastfn = NULL;
825                 lastsize = 0;
826             }
827         }
828 
829         char *cptr = britable[gammabrightness ? 0 : curbrightness];
830 
831         polytint_t const & tint = hictinting[pal];
832         int32_t r = (glinfo.bgra) ? tint.r : tint.b;
833         int32_t g = tint.g;
834         int32_t b = (glinfo.bgra) ? tint.b : tint.r;
835 
836         char al = 255;
837         char onebitalpha = 1;
838 
839         for (bssize_t y = 0, j = 0; y < tsiz.y; ++y, j += siz.x)
840         {
841             coltype tcol, *rpptr = &pic[j];
842 
843             for (bssize_t x = 0; x < tsiz.x; ++x)
844             {
845                 tcol.b = cptr[rpptr[x].b];
846                 tcol.g = cptr[rpptr[x].g];
847                 tcol.r = cptr[rpptr[x].r];
848                 al &= tcol.a = rpptr[x].a;
849                 onebitalpha &= tcol.a == 0 || tcol.a == 255;
850 
851                 if (effect & HICTINT_GRAYSCALE)
852                 {
853                     tcol.g = tcol.r = tcol.b = (uint8_t) ((tcol.b * GRAYSCALE_COEFF_RED) +
854                                                           (tcol.g * GRAYSCALE_COEFF_GREEN) +
855                                                           (tcol.r * GRAYSCALE_COEFF_BLUE));
856                 }
857 
858                 if (effect & HICTINT_INVERT)
859                 {
860                     tcol.b = 255 - tcol.b;
861                     tcol.g = 255 - tcol.g;
862                     tcol.r = 255 - tcol.r;
863                 }
864 
865                 if (effect & HICTINT_COLORIZE)
866                 {
867                     tcol.b = min((int32_t)((tcol.b) * r) >> 6, 255);
868                     tcol.g = min((int32_t)((tcol.g) * g) >> 6, 255);
869                     tcol.r = min((int32_t)((tcol.r) * b) >> 6, 255);
870                 }
871 
872                 switch (effect & HICTINT_BLENDMASK)
873                 {
874                     case HICTINT_BLEND_SCREEN:
875                         tcol.b = 255 - (((255 - tcol.b) * (255 - r)) >> 8);
876                         tcol.g = 255 - (((255 - tcol.g) * (255 - g)) >> 8);
877                         tcol.r = 255 - (((255 - tcol.r) * (255 - b)) >> 8);
878                         break;
879                     case HICTINT_BLEND_OVERLAY:
880                         tcol.b = tcol.b < 128 ? (tcol.b * r) >> 7 : 255 - (((255 - tcol.b) * (255 - r)) >> 7);
881                         tcol.g = tcol.g < 128 ? (tcol.g * g) >> 7 : 255 - (((255 - tcol.g) * (255 - g)) >> 7);
882                         tcol.r = tcol.r < 128 ? (tcol.r * b) >> 7 : 255 - (((255 - tcol.r) * (255 - b)) >> 7);
883                         break;
884                     case HICTINT_BLEND_HARDLIGHT:
885                         tcol.b = r < 128 ? (tcol.b * r) >> 7 : 255 - (((255 - tcol.b) * (255 - r)) >> 7);
886                         tcol.g = g < 128 ? (tcol.g * g) >> 7 : 255 - (((255 - tcol.g) * (255 - g)) >> 7);
887                         tcol.r = b < 128 ? (tcol.r * b) >> 7 : 255 - (((255 - tcol.r) * (255 - b)) >> 7);
888                         break;
889                 }
890 
891                 rpptr[x] = tcol;
892             }
893         }
894 
895         hasalpha = (al != 255);
896 
897         // mdloadskin doesn't duplicate npow2 texture pixels
898 
899         if (!glinfo.bgra)
900         {
901             for (bssize_t j = siz.x*siz.y - 1; j >= 0; j--)
902                 swapchar(&pic[j].r, &pic[j].b);
903         }
904 
905         if (pal < (MAXPALOOKUPS - RESERVEDPALS))
906             m->usesalpha = hasalpha;
907         if ((doalloc&3)==1)
908             glGenTextures(1, texidx);
909 
910         glBindTexture(GL_TEXTURE_2D, *texidx);
911 
912         //gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,xsiz,ysiz,GL_BGRA_EXT,GL_UNSIGNED_BYTE,(char *)fptr);
913 
914         int32_t const texfmt = glinfo.bgra ? GL_BGRA : GL_RGBA;
915 
916         uploadtexture((doalloc&1), siz, texfmt, pic, tsiz,
917                       DAMETH_HI | DAMETH_MASK |
918                       TO_DAMETH_NODOWNSIZE(sk->flags) |
919                       TO_DAMETH_NOTEXCOMPRESS(sk->flags) |
920                       TO_DAMETH_ARTIMMUNITY(sk->flags) |
921                       (onebitalpha ? DAMETH_ONEBITALPHA : 0) |
922                       (hasalpha ? DAMETH_HASALPHA : 0));
923 
924         Xfree(pic);
925     }
926 
927     if (!m->skinloaded)
928     {
929         if (siz.x != tsiz.x || siz.y != tsiz.y)
930         {
931             float fx, fy;
932             fx = ((float)tsiz.x)/((float)siz.x);
933             fy = ((float)tsiz.y)/((float)siz.y);
934             if (m->mdnum == 2)
935             {
936                 int32_t *lptr;
937                 for (lptr=m->glcmds; (i=*lptr++);)
938                     for (i=labs(i); i>0; i--,lptr+=3)
939                     {
940                         ((float *)lptr)[0] *= fx;
941                         ((float *)lptr)[1] *= fy;
942                     }
943             }
944             else if (m->mdnum == 3)
945             {
946                 md3model_t *m3 = (md3model_t *)m;
947                 md3surf_t *s;
948                 int32_t surfi;
949                 for (surfi=0; surfi<m3->head.numsurfs; surfi++)
950                 {
951                     s = &m3->head.surfs[surfi];
952                     for (i=s->numverts-1; i>=0; i--)
953                     {
954                         s->uv[i].u *= fx;
955                         s->uv[i].v *= fy;
956                     }
957                 }
958             }
959         }
960         m->skinloaded = 1+number;
961     }
962 
963     int32_t const filter = (sk->flags & HICR_FORCEFILTER) ? TEXFILTER_ON : gltexfiltermode;
964 
965     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,glfiltermodes[filter].mag);
966     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,glfiltermodes[filter].min);
967 #ifdef USE_GLEXT
968     if (glinfo.maxanisotropy > 1.0)
969         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_ANISOTROPY_EXT,glanisotropy);
970 #endif
971     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
972     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
973 
974 #if defined USE_GLEXT && !defined EDUKE32_GLES
975     if (!gotcache && glinfo.texcompr && glusetexcache && !(sk->flags & HICR_NOTEXCOMPRESS) &&
976         (glusetexcompr == 2 || (glusetexcompr && !(sk->flags & HICR_ARTIMMUNITY))))
977         {
978             const int32_t nonpow2 = check_nonpow2(siz.x) || check_nonpow2(siz.y);
979 
980             // save off the compressed version
981             cachead.quality = (sk->flags & (HICR_NODOWNSIZE|HICR_ARTIMMUNITY)) ? 0 : r_downsize;
982             cachead.xdim = tsiz.x>>cachead.quality;
983             cachead.ydim = tsiz.y>>cachead.quality;
984 
985             cachead.flags = nonpow2*CACHEAD_NONPOW2 | (hasalpha ? CACHEAD_HASALPHA : 0) |
986                             ((sk->flags & (HICR_NODOWNSIZE|HICR_ARTIMMUNITY)) ? CACHEAD_NODOWNSIZE : 0);
987 
988 ///            OSD_Printf("Caching \"%s\"\n",fn);
989             texcache_writetex_fromdriver(texcacheid, &cachead);
990 
991             if (willprint)
992             {
993                 int32_t etime = timerGetTicks()-startticks;
994                 if (etime>=MIN_CACHETIME_PRINT)
995                     OSD_Printf("Load skin: p%d-e%d \"%s\"... cached... %d ms\n", pal, hicfxmask(pal), fn, etime);
996                 willprint = 0;
997             }
998             else
999                 OSD_Printf("Cached skin \"%s\"\n", fn);
1000         }
1001 #endif
1002 
1003     if (willprint)
1004     {
1005         int32_t etime = timerGetTicks()-startticks;
1006         if (etime>=MIN_CACHETIME_PRINT)
1007             OSD_Printf("Load skin: p%d-e%d \"%s\"... %d ms\n", pal, hicfxmask(pal), fn, etime);
1008     }
1009 
1010     return (*texidx);
1011 }
1012 
1013 //Note: even though it says md2model, it works for both md2model&md3model
updateanimation(md2model_t * m,tspriteptr_t tspr,uint8_t lpal)1014 void updateanimation(md2model_t *m, tspriteptr_t tspr, uint8_t lpal)
1015 {
1016     if (m->numframes < 2)
1017     {
1018         m->interpol = 0;
1019         return;
1020     }
1021 
1022     int32_t const tile = Ptile2tile(tspr->picnum,lpal);
1023     m->cframe = m->nframe = tile2model[tile].framenum;
1024 
1025 #ifdef DEBUGGINGAIDS
1026     if (m->cframe >= m->numframes)
1027         OSD_Printf("1: c > n\n");
1028 #endif
1029 
1030     int32_t const smoothdurationp = (r_animsmoothing && (tile2model[tile].smoothduration != 0));
1031     spritesmooth_t * const smooth = &spritesmooth[((unsigned)tspr->owner < MAXSPRITES+MAXUNIQHUDID) ? tspr->owner : MAXSPRITES+MAXUNIQHUDID-1];
1032     spriteext_t * const sprext = &spriteext[((unsigned)tspr->owner < MAXSPRITES+MAXUNIQHUDID) ? tspr->owner : MAXSPRITES+MAXUNIQHUDID-1];
1033 
1034     const mdanim_t *anim;
1035     for (anim = m->animations; anim && anim->startframe != m->cframe; anim = anim->next)
1036     {
1037         /* do nothing */;
1038     }
1039 
1040     int32_t i, j, k;
1041     int32_t fps;
1042 
1043     if (!anim)
1044     {
1045         if (!smoothdurationp || ((smooth->mdoldframe == m->cframe) && (smooth->mdcurframe == m->cframe)))
1046         {
1047             m->interpol = 0;
1048             return;
1049         }
1050 
1051         // assert(smoothdurationp && ((smooth->mdoldframe != m->cframe) || (smooth->mdcurframe != m->cframe)))
1052 
1053         if (smooth->mdoldframe != m->cframe)
1054         {
1055             if (smooth->mdsmooth == 0)
1056             {
1057                 sprext->mdanimtims = mdtims;
1058                 m->interpol = 0;
1059                 smooth->mdsmooth = 1;
1060                 smooth->mdcurframe = m->cframe;
1061             }
1062             else if (smooth->mdcurframe != m->cframe)
1063             {
1064                 sprext->mdanimtims = mdtims;
1065                 m->interpol = 0;
1066                 smooth->mdsmooth = 1;
1067                 smooth->mdoldframe = smooth->mdcurframe;
1068                 smooth->mdcurframe = m->cframe;
1069             }
1070         }
1071         else  // if (smooth->mdcurframe != m->cframe)
1072         {
1073             sprext->mdanimtims = mdtims;
1074             m->interpol = 0;
1075             smooth->mdsmooth = 1;
1076             smooth->mdoldframe = smooth->mdcurframe;
1077             smooth->mdcurframe = m->cframe;
1078         }
1079     }
1080     else if (/* anim && */ sprext->mdanimcur != anim->startframe)
1081     {
1082         //if (sprext->flags & SPREXT_NOMDANIM) OSD_Printf("SPREXT_NOMDANIM\n");
1083         //OSD_Printf("smooth launched ! oldanim %i new anim %i\n", sprext->mdanimcur, anim->startframe);
1084         sprext->mdanimcur = (int16_t)anim->startframe;
1085         sprext->mdanimtims = mdtims;
1086         m->interpol = 0;
1087 
1088         if (!smoothdurationp)
1089         {
1090             m->cframe = m->nframe = anim->startframe;
1091 #ifdef DEBUGGINGAIDS
1092             if (m->cframe >= m->numframes)
1093                 OSD_Printf("2: c > n\n");
1094 #endif
1095             goto prep_return;
1096         }
1097 
1098         m->nframe = anim->startframe;
1099         m->cframe = smooth->mdoldframe;
1100 #ifdef DEBUGGINGAIDS
1101         if (m->cframe >= m->numframes)
1102             OSD_Printf("3: c > n\n");
1103 #endif
1104         smooth->mdsmooth = 1;
1105         goto prep_return;
1106     }
1107 
1108     fps = smooth->mdsmooth ? Blrintf((1.0f / ((float)tile2model[tile].smoothduration * (1.f / (float)UINT16_MAX))) * 66.f)
1109                                    : anim ? anim->fpssc : 1;
1110 
1111     i = (mdtims - sprext->mdanimtims) * ((fps * timerGetClockRate()) / 120);
1112 
1113     j = (smooth->mdsmooth || !anim) ? 65536 : ((anim->endframe + 1 - anim->startframe) << 16);
1114 
1115     // XXX: Just in case you play the game for a VERY long time...
1116     if (i < 0) { i = 0; sprext->mdanimtims = mdtims; }
1117     //compare with j*2 instead of j to ensure i stays > j-65536 for MDANIM_ONESHOT
1118     if (anim && (i >= j+j) && (fps) && !mdpause) //Keep mdanimtims close to mdtims to avoid the use of MOD
1119         sprext->mdanimtims += j/((fps*timerGetClockRate())/120);
1120 
1121     k = i;
1122 
1123     if (anim && (anim->flags&MDANIM_ONESHOT))
1124         { if (i > j-65536) i = j-65536; }
1125     else { if (i >= j) { i -= j; if (i >= j) i %= j; } }
1126 
1127     if (r_animsmoothing && smooth->mdsmooth)
1128     {
1129         m->nframe = anim ? anim->startframe : smooth->mdcurframe;
1130         m->cframe = smooth->mdoldframe;
1131 #ifdef DEBUGGINGAIDS
1132         if (m->cframe >= m->numframes)
1133             OSD_Printf("4: c > n\n");
1134 #endif
1135         //OSD_Printf("smoothing... cframe %i nframe %i\n", m->cframe, m->nframe);
1136         if (k > 65535)
1137         {
1138             sprext->mdanimtims = mdtims;
1139             m->interpol = 0;
1140             smooth->mdsmooth = 0;
1141             m->cframe = m->nframe; // = anim ? anim->startframe : smooth->mdcurframe;
1142 #ifdef DEBUGGINGAIDS
1143             if (m->cframe >= m->numframes)
1144                 OSD_Printf("5: c > n\n");
1145 #endif
1146             smooth->mdoldframe = m->cframe;
1147             //OSD_Printf("smooth stopped !\n");
1148             goto prep_return;
1149         }
1150     }
1151     else
1152     {
1153         if (anim)
1154             m->cframe = (i>>16)+anim->startframe;
1155 
1156 #ifdef DEBUGGINGAIDS
1157         if (m->cframe >= m->numframes)
1158             OSD_Printf("6: c > n\n");
1159 #endif
1160         m->nframe = m->cframe+1;
1161 
1162         if (anim && m->nframe > anim->endframe)  // VERIFY: (!(r_animsmoothing && smooth->mdsmooth)) implies (anim!=NULL) ?
1163             m->nframe = anim->startframe;
1164 
1165         smooth->mdoldframe = m->cframe;
1166         //OSD_Printf("not smoothing... cframe %i nframe %i\n", m->cframe, m->nframe);
1167     }
1168 
1169     m->interpol = ((float)(i&65535))/65536.f;
1170     //OSD_Printf("interpol %f\n", m->interpol);
1171 
1172 prep_return:
1173     if (m->cframe >= m->numframes)
1174         m->cframe = 0;
1175     if (m->nframe >= m->numframes)
1176         m->nframe = 0;
1177 }
1178 
1179 #ifdef USE_GLEXT
1180 // VBO generation and allocation
mdloadvbos(md3model_t * m)1181 static void mdloadvbos(md3model_t *m)
1182 {
1183     int32_t     i;
1184 
1185     m->vbos = (GLuint *)Xmalloc(m->head.numsurfs * sizeof(GLuint));
1186     glGenBuffers(m->head.numsurfs, m->vbos);
1187 
1188     i = 0;
1189     while (i < m->head.numsurfs)
1190     {
1191         glBindBuffer(GL_ARRAY_BUFFER, m->vbos[i]);
1192         glBufferData(GL_ARRAY_BUFFER, m->head.surfs[i].numverts * sizeof(md3uv_t), m->head.surfs[i].uv, GL_STATIC_DRAW);
1193         i++;
1194     }
1195     glBindBuffer(GL_ARRAY_BUFFER, 0);
1196 }
1197 #endif
1198 
1199 //--------------------------------------- MD2 LIBRARY BEGINS ---------------------------------------
md2free(md2model_t * m)1200 static void md2free(md2model_t *m)
1201 {
1202     if (!m)
1203         return;
1204 
1205     Xfree(m->texid);
1206     Xfree(m->skinfn);
1207     Xfree(m->basepath);
1208     Xfree(m->uv);
1209     Xfree(m->tris);
1210     Xfree(m->glcmds);
1211     Xfree(m->frames);
1212     Xfree(m);
1213 }
1214 
md2load(buildvfs_kfd fil,const char * filnam)1215 static md2model_t *md2load(buildvfs_kfd fil, const char *filnam)
1216 {
1217     md2model_t *m;
1218     md3model_t *m3;
1219     md3surf_t *s;
1220     md2frame_t *f;
1221     md2head_t head;
1222     char st[BMAX_PATH];
1223     int32_t i, j, k;
1224 
1225     int32_t ournumskins, ournumglcmds;
1226 
1227     m = (md2model_t *)Xcalloc(1,sizeof(md2model_t));
1228     m->mdnum = 2; m->scale = .01f;
1229 
1230     if (kread_and_test(fil,(char *)&head,sizeof(md2head_t))) { Xfree(m); return nullptr; }
1231 
1232 #if B_BIG_ENDIAN != 0
1233     head.id = B_LITTLE32(head.id);                 head.vers = B_LITTLE32(head.vers);
1234     head.skinxsiz = B_LITTLE32(head.skinxsiz);     head.skinysiz = B_LITTLE32(head.skinysiz);
1235     head.framebytes = B_LITTLE32(head.framebytes); head.numskins = B_LITTLE32(head.numskins);
1236     head.numverts = B_LITTLE32(head.numverts);     head.numuv = B_LITTLE32(head.numuv);
1237     head.numtris = B_LITTLE32(head.numtris);       head.numglcmds = B_LITTLE32(head.numglcmds);
1238     head.numframes = B_LITTLE32(head.numframes);   head.ofsskins = B_LITTLE32(head.ofsskins);
1239     head.ofsuv = B_LITTLE32(head.ofsuv);           head.ofstris = B_LITTLE32(head.ofstris);
1240     head.ofsframes = B_LITTLE32(head.ofsframes);   head.ofsglcmds = B_LITTLE32(head.ofsglcmds);
1241     head.ofseof = B_LITTLE32(head.ofseof);
1242 #endif
1243 
1244     if ((head.id != IDP2_MAGIC) || (head.vers != 8)) { Xfree(m); return 0; } //"IDP2"
1245 
1246     ournumskins = head.numskins ? head.numskins : 1;
1247     ournumglcmds = head.numglcmds ? head.numglcmds : 1;
1248 
1249     m->numskins = head.numskins;
1250     m->numframes = head.numframes;
1251     m->numverts = head.numverts;
1252     m->numglcmds = head.numglcmds;
1253     m->framebytes = head.framebytes;
1254 
1255     m->frames = (char *)Xmalloc(m->numframes*m->framebytes);
1256     m->glcmds = (int32_t *)Xmalloc(ournumglcmds*sizeof(int32_t));
1257     m->tris = (md2tri_t *)Xmalloc(head.numtris*sizeof(md2tri_t));
1258     m->uv = (md2uv_t *)Xmalloc(head.numuv*sizeof(md2uv_t));
1259 
1260     klseek(fil,head.ofsframes,SEEK_SET);
1261     if (kread_and_test(fil,(char *)m->frames,m->numframes*m->framebytes)) { md2free(m); return nullptr; }
1262     if (m->numglcmds > 0)
1263     {
1264         klseek(fil, head.ofsglcmds, SEEK_SET);
1265         if (kread_and_test(fil, (char *)m->glcmds, m->numglcmds * sizeof(int32_t))) { md2free(m); return nullptr; }
1266     }
1267 
1268     klseek(fil, head.ofstris, SEEK_SET);
1269     if (kread_and_test(fil, (char *)m->tris, head.numtris * sizeof(md2tri_t))) { md2free(m); return nullptr; }
1270     klseek(fil, head.ofsuv, SEEK_SET);
1271     if (kread_and_test(fil, (char *)m->uv, head.numuv * sizeof(md2uv_t))) { md2free(m); return nullptr; }
1272 #if B_BIG_ENDIAN != 0
1273     {
1274         char *f = (char *)m->frames;
1275         int32_t *l,j;
1276         md2frame_t *fr;
1277 
1278         for (i = m->numframes-1; i>=0; i--)
1279         {
1280             fr = (md2frame_t *)f;
1281             l = (int32_t *)&fr->mul;
1282             for (j=5; j>=0; j--) l[j] = B_LITTLE32(l[j]);
1283             f += m->framebytes;
1284         }
1285 
1286         for (i = m->numglcmds-1; i>=0; i--)
1287         {
1288             m->glcmds[i] = B_LITTLE32(m->glcmds[i]);
1289         }
1290         for (i = head.numtris-1; i>=0; i--)
1291         {
1292             m->tris[i].v[0] = B_LITTLE16(m->tris[i].v[0]);
1293             m->tris[i].v[1] = B_LITTLE16(m->tris[i].v[1]);
1294             m->tris[i].v[2] = B_LITTLE16(m->tris[i].v[2]);
1295             m->tris[i].u[0] = B_LITTLE16(m->tris[i].u[0]);
1296             m->tris[i].u[1] = B_LITTLE16(m->tris[i].u[1]);
1297             m->tris[i].u[2] = B_LITTLE16(m->tris[i].u[2]);
1298         }
1299         for (i = head.numuv-1; i>=0; i--)
1300         {
1301             m->uv[i].u = B_LITTLE16(m->uv[i].u);
1302             m->uv[i].v = B_LITTLE16(m->uv[i].v);
1303         }
1304     }
1305 #endif
1306 
1307     Bstrcpy(st,filnam);
1308     for (i=strlen(st)-1; i>0; i--)
1309         if ((st[i] == '/') || (st[i] == '\\')) { i++; break; }
1310     if (i<0) i=0;
1311     st[i] = 0;
1312     m->basepath = (char *)Xmalloc(i+1);
1313     Bstrcpy(m->basepath, st);
1314 
1315     m->skinfn = (char *)Xmalloc(ournumskins*64);
1316     if (m->numskins > 0)
1317     {
1318         klseek(fil,head.ofsskins,SEEK_SET);
1319         if (kread_and_test(fil,m->skinfn,64*m->numskins)) { md2free(m); return nullptr; }
1320     }
1321 
1322     m->texid = (GLuint *)Xcalloc(ournumskins, sizeof(GLuint) * HICTINT_MEMORY_COMBINATIONS);
1323 
1324     maxmodelverts = max(maxmodelverts, m->numverts);
1325     maxmodeltris = max(maxmodeltris, head.numtris);
1326 
1327     //return m;
1328 
1329     // the MD2 is now loaded internally - let's begin the MD3 conversion process
1330     //OSD_Printf("Beginning md3 conversion.\n");
1331     m3 = (md3model_t *)Xcalloc(1, sizeof(md3model_t));
1332     m3->mdnum = 3; m3->texid = 0; m3->scale = m->scale;
1333     m3->head.id = IDP3_MAGIC; m3->head.vers = 15;
1334 
1335     m3->head.flags = 0;
1336 
1337     m3->head.numframes = m->numframes;
1338     m3->head.numtags = 0; m3->head.numsurfs = 1;
1339     m3->head.numskins = 0;
1340 
1341     m3->numskins = m3->head.numskins;
1342     m3->numframes = m3->head.numframes;
1343 
1344     m3->head.frames = (md3frame_t *)Xcalloc(m3->head.numframes, sizeof(md3frame_t));
1345     m3->muladdframes = (vec3f_t *)Xcalloc(m->numframes * 2, sizeof(vec3f_t));
1346 
1347     f = (md2frame_t *)(m->frames);
1348 
1349     // frames converting
1350     i = 0;
1351     while (i < m->numframes)
1352     {
1353         f = (md2frame_t *)&m->frames[i*m->framebytes];
1354         Bstrcpy(m3->head.frames[i].nam, f->name);
1355         //OSD_Printf("Copied frame %s.\n", m3->head.frames[i].nam);
1356         m3->muladdframes[i*2] = f->mul;
1357         m3->muladdframes[i*2+1] = f->add;
1358         i++;
1359     }
1360 
1361     m3->head.tags = NULL;
1362 
1363     m3->head.surfs = (md3surf_t *)Xcalloc(1, sizeof(md3surf_t));
1364     s = m3->head.surfs;
1365 
1366     // model converting
1367     s->id = IDP3_MAGIC; s->flags = 0;
1368     s->numframes = m->numframes; s->numshaders = 0;
1369     s->numtris = head.numtris;
1370     s->numverts = head.numtris * 3; // oh man talk about memory effectiveness :((((
1371     // MD2 is actually more accurate than MD3 in term of uv-mapping, because each triangle has a triangle counterpart on the UV-map.
1372     // In MD3, each vertex unique UV coordinates, meaning that you have to duplicate vertices if you need non-seamless UV-mapping.
1373 
1374     maxmodelverts = max(maxmodelverts, s->numverts);
1375 
1376     Bstrcpy(s->nam, "Dummy surface from MD2");
1377 
1378     s->shaders = NULL;
1379 
1380     s->tris = (md3tri_t *)Xcalloc(head.numtris, sizeof(md3tri_t));
1381     s->uv = (md3uv_t *)Xcalloc(s->numverts, sizeof(md3uv_t));
1382     s->xyzn = (md3xyzn_t *)Xcalloc(s->numverts * m->numframes, sizeof(md3xyzn_t));
1383 
1384     //memoryusage += (s->numverts * m->numframes * sizeof(md3xyzn_t));
1385     //OSD_Printf("Current model geometry memory usage : %i.\n", memoryusage);
1386 
1387     //OSD_Printf("Number of frames : %i\n", m->numframes);
1388     //OSD_Printf("Number of triangles : %i\n", head.numtris);
1389     //OSD_Printf("Number of vertices : %i\n", s->numverts);
1390 
1391     // triangle converting
1392     i = 0;
1393     while (i < head.numtris)
1394     {
1395         j = 0;
1396         //OSD_Printf("Triangle : %i\n", i);
1397         while (j < 3)
1398         {
1399             // triangle vertex indexes
1400             s->tris[i].i[j] = i*3 + j;
1401 
1402             // uv coords
1403             s->uv[i*3+j].u = (float)(m->uv[m->tris[i].u[j]].u) / (float)(head.skinxsiz);
1404             s->uv[i*3+j].v = (float)(m->uv[m->tris[i].u[j]].v) / (float)(head.skinysiz);
1405 
1406             // vertices for each frame
1407             k = 0;
1408             while (k < m->numframes)
1409             {
1410                 f = (md2frame_t *)&m->frames[k*m->framebytes];
1411                 s->xyzn[(k*s->numverts) + (i*3) + j].x = (int16_t) (((f->verts[m->tris[i].v[j]].v[0] * f->mul.x) + f->add.x) * 64.f);
1412                 s->xyzn[(k*s->numverts) + (i*3) + j].y = (int16_t) (((f->verts[m->tris[i].v[j]].v[1] * f->mul.y) + f->add.y) * 64.f);
1413                 s->xyzn[(k*s->numverts) + (i*3) + j].z = (int16_t) (((f->verts[m->tris[i].v[j]].v[2] * f->mul.z) + f->add.z) * 64.f);
1414 
1415                 k++;
1416             }
1417             j++;
1418         }
1419         //OSD_Printf("End triangle.\n");
1420         i++;
1421     }
1422     //OSD_Printf("Finished md3 conversion.\n");
1423 
1424     {
1425         mdskinmap_t *sk;
1426 
1427         sk = (mdskinmap_t *)Xcalloc(1,sizeof(mdskinmap_t));
1428         sk->palette = 0;
1429         sk->skinnum = 0;
1430         sk->surfnum = 0;
1431 
1432         if (m->numskins > 0)
1433         {
1434             sk->fn = (char *)Xmalloc(strlen(m->basepath)+strlen(m->skinfn)+1);
1435             Bstrcpy(sk->fn, m->basepath);
1436             Bstrcat(sk->fn, m->skinfn);
1437         }
1438         m3->skinmap = sk;
1439     }
1440 
1441     m3->indexes = (uint16_t *)Xmalloc(sizeof(uint16_t) * s->numtris);
1442     m3->vindexes = (uint16_t *)Xmalloc(sizeof(uint16_t) * s->numtris * 3);
1443     m3->maxdepths = (float *)Xmalloc(sizeof(float) * s->numtris);
1444 
1445     m3->vbos = NULL;
1446 
1447     // die MD2 ! DIE !
1448     md2free(m);
1449 
1450     return ((md2model_t *)m3);
1451 }
1452 //---------------------------------------- MD2 LIBRARY ENDS ----------------------------------------
1453 
1454 // DICHOTOMIC RECURSIVE SORTING - USED BY MD3DRAW
partition(uint16_t * indexes,float * depths,int32_t f,int32_t l)1455 int32_t partition(uint16_t *indexes, float *depths, int32_t f, int32_t l)
1456 {
1457     int32_t up = f, down = l;
1458     float piv = depths[f];
1459     uint16_t piv2 = indexes[f];
1460     do
1461     {
1462         while ((up < l) && (depths[up] <= piv))
1463             up++;
1464         while ((depths[down] > piv) && (down > f))
1465             down--;
1466         if (up < down)
1467         {
1468             swapfloat(&depths[up], &depths[down]);
1469             swapshort(&indexes[up], &indexes[down]);
1470         }
1471     }
1472     while (down > up);
1473     depths[f] = depths[down];
1474     depths[down] = piv;
1475     indexes[f] = indexes[down];
1476     indexes[down] = piv2;
1477     return down;
1478 }
1479 
quicksort(uint16_t * indexes,float * depths,int32_t first,int32_t last)1480 static inline void quicksort(uint16_t *indexes, float *depths, int32_t first, int32_t last)
1481 {
1482     int32_t pivIndex;
1483     if (first >= last) return;
1484     pivIndex = partition(indexes, depths, first, last);
1485     if (first < (pivIndex-1)) quicksort(indexes, depths, first, (pivIndex-1));
1486     if ((pivIndex+1) >= last) return;
1487     quicksort(indexes, depths, (pivIndex+1), last);
1488 }
1489 // END OF QUICKSORT LIB
1490 
1491 //--------------------------------------- MD3 LIBRARY BEGINS ---------------------------------------
1492 static void md3free(md3model_t *m);
1493 
md3load(buildvfs_kfd fil)1494 static md3model_t *md3load(buildvfs_kfd fil)
1495 {
1496     int32_t i, surfi, ofsurf, offs[4], leng[4];
1497     int32_t maxtrispersurf;
1498     md3model_t *m;
1499     md3surf_t *s;
1500 
1501     m = (md3model_t *)Xcalloc(1,sizeof(md3model_t));
1502     m->mdnum = 3; m->texid = 0; m->scale = .01f;
1503 
1504     m->muladdframes = NULL;
1505 
1506     if (kread_and_test(fil, &m->head, SIZEOF_MD3HEAD_T)) { md3free(m); return nullptr; }
1507 
1508 #if B_BIG_ENDIAN != 0
1509     m->head.id = B_LITTLE32(m->head.id);             m->head.vers = B_LITTLE32(m->head.vers);
1510     m->head.flags = B_LITTLE32(m->head.flags);       m->head.numframes = B_LITTLE32(m->head.numframes);
1511     m->head.numtags = B_LITTLE32(m->head.numtags);   m->head.numsurfs = B_LITTLE32(m->head.numsurfs);
1512     m->head.numskins = B_LITTLE32(m->head.numskins); m->head.ofsframes = B_LITTLE32(m->head.ofsframes);
1513     m->head.ofstags = B_LITTLE32(m->head.ofstags); m->head.ofssurfs = B_LITTLE32(m->head.ofssurfs);
1514     m->head.eof = B_LITTLE32(m->head.eof);
1515 #endif
1516 
1517     if ((m->head.id != IDP3_MAGIC) && (m->head.vers != 15)) { md3free(m); return nullptr; }
1518 
1519     m->numskins = m->head.numskins; //<- dead code?
1520     m->numframes = m->head.numframes;
1521 
1522     ofsurf = m->head.ofssurfs;
1523 
1524     klseek(fil,m->head.ofsframes,SEEK_SET); i = m->head.numframes*sizeof(md3frame_t);
1525     m->head.frames = (md3frame_t *)Xmalloc(i);
1526     if (kread_and_test(fil,m->head.frames,i)) { md3free(m); return nullptr; }
1527 
1528     if (m->head.numtags == 0) m->head.tags = NULL;
1529     else
1530     {
1531         klseek(fil,m->head.ofstags,SEEK_SET); i = m->head.numtags*sizeof(md3tag_t);
1532         m->head.tags = (md3tag_t *)Xmalloc(i);
1533         if (kread_and_test(fil,m->head.tags,i)) { md3free(m); return nullptr; }
1534     }
1535 
1536     klseek(fil,m->head.ofssurfs,SEEK_SET);
1537     m->head.surfs = (md3surf_t *)Xcalloc(m->head.numsurfs, sizeof(md3surf_t));
1538     // NOTE: We assume that NULL is represented by all-zeros.
1539     // surfs[0].geometry is for POLYMER_MD_PROCESS_CHECK (else: crashes).
1540     // surfs[i].geometry is for FREE_SURFS_GEOMETRY.
1541     Bassert(m->head.surfs[0].geometry == NULL);
1542 
1543 #if B_BIG_ENDIAN != 0
1544     {
1545         int32_t j, *l;
1546 
1547         for (i = m->head.numframes-1; i>=0; i--)
1548         {
1549             l = (int32_t *)&m->head.frames[i].min;
1550             for (j=3+3+3+1-1; j>=0; j--) l[j] = B_LITTLE32(l[j]);
1551         }
1552 
1553         for (i = m->head.numtags-1; i>=0; i--)
1554         {
1555             l = (int32_t *)&m->head.tags[i].p;
1556             for (j=3+3+3+3-1; j>=0; j--) l[j] = B_LITTLE32(l[j]);
1557         }
1558     }
1559 #endif
1560 
1561     maxtrispersurf = 0;
1562 
1563     for (surfi=0; surfi<m->head.numsurfs; surfi++)
1564     {
1565         s = &m->head.surfs[surfi];
1566         klseek(fil,ofsurf,SEEK_SET);
1567         if (kread_and_test(fil,s,SIZEOF_MD3SURF_T)) { md3free(m); return nullptr; }
1568 
1569 #if B_BIG_ENDIAN != 0
1570         {
1571             int32_t j, *l;
1572             s->id = B_LITTLE32(s->id);
1573             l =	(int32_t *)&s->flags;
1574             for	(j=1+1+1+1+1+1+1+1+1+1-1; j>=0; j--) l[j] = B_LITTLE32(l[j]);
1575         }
1576 #endif
1577 
1578         offs[0] = ofsurf+s->ofstris;
1579         offs[1] = ofsurf+s->ofsshaders;
1580         offs[2] = ofsurf+s->ofsuv;
1581         offs[3] = ofsurf+s->ofsxyzn;
1582 
1583         leng[0] = s->numtris*sizeof(md3tri_t);
1584         leng[1] = s->numshaders*sizeof(md3shader_t);
1585         leng[2] = s->numverts*sizeof(md3uv_t);
1586         leng[3] = s->numframes*s->numverts*sizeof(md3xyzn_t);
1587 
1588         //memoryusage += (s->numverts * s->numframes * sizeof(md3xyzn_t));
1589         //OSD_Printf("Current model geometry memory usage : %i.\n", memoryusage);
1590 
1591         s->tris = (md3tri_t *)Xmalloc((leng[0] + leng[1]) + (leng[2] + leng[3]));
1592 
1593         s->shaders = (md3shader_t *)(((intptr_t)s->tris)+leng[0]);
1594         s->uv      = (md3uv_t *)(((intptr_t)s->shaders)+leng[1]);
1595         s->xyzn    = (md3xyzn_t *)(((intptr_t)s->uv)+leng[2]);
1596 
1597         klseek(fil,offs[0],SEEK_SET); if (kread_and_test(fil,s->tris   ,leng[0])) { md3free(m); return nullptr; }
1598         klseek(fil,offs[1],SEEK_SET); if (kread_and_test(fil,s->shaders,leng[1])) { md3free(m); return nullptr; }
1599         klseek(fil,offs[2],SEEK_SET); if (kread_and_test(fil,s->uv     ,leng[2])) { md3free(m); return nullptr; }
1600         klseek(fil,offs[3],SEEK_SET); if (kread_and_test(fil,s->xyzn   ,leng[3])) { md3free(m); return nullptr; }
1601 
1602 #if B_BIG_ENDIAN != 0
1603         {
1604             int32_t j, *l;
1605 
1606             for (i=s->numtris-1; i>=0; i--)
1607             {
1608                 for (j=2; j>=0; j--) s->tris[i].i[j] = B_LITTLE32(s->tris[i].i[j]);
1609             }
1610             for (i=s->numshaders-1; i>=0; i--)
1611             {
1612                 s->shaders[i].i = B_LITTLE32(s->shaders[i].i);
1613             }
1614             for (i=s->numverts-1; i>=0; i--)
1615             {
1616                 l = (int32_t *)&s->uv[i].u;
1617                 l[0] = B_LITTLE32(l[0]);
1618                 l[1] = B_LITTLE32(l[1]);
1619             }
1620             for (i=s->numframes*s->numverts-1; i>=0; i--)
1621             {
1622                 s->xyzn[i].x = (int16_t)B_LITTLE16((uint16_t)s->xyzn[i].x);
1623                 s->xyzn[i].y = (int16_t)B_LITTLE16((uint16_t)s->xyzn[i].y);
1624                 s->xyzn[i].z = (int16_t)B_LITTLE16((uint16_t)s->xyzn[i].z);
1625             }
1626         }
1627 #endif
1628         maxmodelverts = max(maxmodelverts, s->numverts);
1629         maxmodeltris = max(maxmodeltris, s->numtris);
1630         maxtrispersurf = max(maxtrispersurf, s->numtris);
1631         ofsurf += s->ofsend;
1632     }
1633 
1634     m->indexes = (uint16_t *)Xmalloc(sizeof(uint16_t) * maxtrispersurf);
1635     m->vindexes = (uint16_t *)Xmalloc(sizeof(uint16_t) * maxtrispersurf * 3);
1636     m->maxdepths = (float *)Xmalloc(sizeof(float) * maxtrispersurf);
1637 
1638     m->vbos = NULL;
1639 
1640     return m;
1641 }
1642 
1643 #ifdef POLYMER
invertmatrix(const float * m,float * out)1644 static inline void  invertmatrix(const float *m, float *out)
1645 {
1646     float det;
1647 
1648     det  = (m[0] * (m[4]*m[8] - m[5] * m[7]))
1649          - (m[1] * (m[3]*m[8] - m[5] * m[6]))
1650          + (m[2] * (m[3]*m[7] - m[4] * m[6]));
1651 
1652     if (det == 0.0f)
1653     {
1654         Bmemset(out, 0, sizeof(float) * 9);
1655         out[8] = out[4] = out[0] = 1.f;
1656         return;
1657     }
1658 
1659     det = 1.0f / det;
1660 
1661     out[0] = det * (m[4] * m[8] - m[5] * m[7]);
1662     out[1] = det * (m[2] * m[7] - m[1] * m[8]);
1663     out[2] = det * (m[1] * m[5] - m[2] * m[4]);
1664     out[3] = det * (m[5] * m[6] - m[3] * m[8]);
1665     out[4] = det * (m[0] * m[8] - m[2] * m[6]);
1666     out[5] = det * (m[2] * m[3] - m[0] * m[5]);
1667     out[6] = det * (m[3] * m[7] - m[1] * m[6]);
1668     out[7] = det * (m[1] * m[6] - m[0] * m[7]);
1669     out[8] = det * (m[0] * m[4] - m[1] * m[3]);
1670 }
1671 
normalize(float * vec)1672 static inline void  normalize(float *vec)
1673 {
1674     float norm;
1675 
1676     if ((norm = vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]) == 0.f)
1677         return;
1678 
1679     norm = polymost_invsqrt_approximation(norm);
1680     vec[0] *= norm;
1681     vec[1] *= norm;
1682     vec[2] *= norm;
1683 }
1684 #endif
1685 
md3postload_common(md3model_t * m)1686 static void      md3postload_common(md3model_t *m)
1687 {
1688     int         framei, surfi, verti;
1689     md3frame_t  *frame;
1690     md3xyzn_t   *frameverts;
1691     float       dist, vec1[3];
1692 
1693     // apparently we can't trust loaded models bounding box/sphere information,
1694     // so let's compute it ourselves
1695 
1696     framei = 0;
1697 
1698     while (framei < m->head.numframes)
1699     {
1700         frame = &m->head.frames[framei];
1701 
1702         Bmemset(&frame->min, 0, sizeof(vec3f_t));
1703         Bmemset(&frame->max, 0, sizeof(vec3f_t));
1704 
1705         frame->r        = 0.0f;
1706 
1707         surfi = 0;
1708         while (surfi < m->head.numsurfs)
1709         {
1710             frameverts = &m->head.surfs[surfi].xyzn[framei * m->head.surfs[surfi].numverts];
1711 
1712             verti = 0;
1713             while (verti < m->head.surfs[surfi].numverts)
1714             {
1715                 if (!verti && !surfi)
1716                 {
1717                     md3xyzn_t const & framevert = frameverts[0];
1718 
1719                     frame->min.x    = framevert.x;
1720                     frame->min.y    = framevert.y;
1721                     frame->min.z    = framevert.z;
1722 
1723                     frame->max      = frame->min;
1724                 }
1725                 else
1726                 {
1727                     md3xyzn_t const & framevert = frameverts[verti];
1728 
1729                     if (frame->min.x > framevert.x)
1730                         frame->min.x = framevert.x;
1731                     if (frame->max.x < framevert.x)
1732                         frame->max.x = framevert.x;
1733 
1734                     if (frame->min.y > framevert.y)
1735                         frame->min.y = framevert.y;
1736                     if (frame->max.y < framevert.y)
1737                         frame->max.y = framevert.y;
1738 
1739                     if (frame->min.z > framevert.z)
1740                         frame->min.z = framevert.z;
1741                     if (frame->max.z < framevert.z)
1742                         frame->max.z = framevert.z;
1743                 }
1744 
1745                 ++verti;
1746             }
1747 
1748             ++surfi;
1749         }
1750 
1751         frame->cen.x = (frame->min.x + frame->max.x) * .5f;
1752         frame->cen.y = (frame->min.y + frame->max.y) * .5f;
1753         frame->cen.z = (frame->min.z + frame->max.z) * .5f;
1754 
1755         surfi = 0;
1756         while (surfi < m->head.numsurfs)
1757         {
1758             md3surf_t const & surf = m->head.surfs[surfi];
1759 
1760             frameverts = &surf.xyzn[framei * surf.numverts];
1761 
1762             verti = 0;
1763             while (verti < surf.numverts)
1764             {
1765                 md3xyzn_t const & framevert = frameverts[verti];
1766 
1767                 vec1[0] = framevert.x - frame->cen.x;
1768                 vec1[1] = framevert.y - frame->cen.y;
1769                 vec1[2] = framevert.z - frame->cen.z;
1770 
1771                 dist = vec1[0] * vec1[0] + vec1[1] * vec1[1] + vec1[2] * vec1[2];
1772 
1773                 if (dist > frame->r)
1774                     frame->r = dist;
1775 
1776                 ++verti;
1777             }
1778 
1779             ++surfi;
1780         }
1781 
1782         frame->r = Bsqrtf(frame->r);
1783 
1784         ++framei;
1785     }
1786 }
1787 
1788 #ifdef POLYMER
1789 // pre-check success of conversion since it must not fail later.
1790 // keep in sync with md3postload_polymer!
md3postload_polymer_check(md3model_t * m)1791 static int md3postload_polymer_check(md3model_t *m)
1792 {
1793     ssize_t surfi, trii;
1794     md3surf_t   *s;
1795 
1796     surfi = 0;
1797     while (surfi < m->head.numsurfs)
1798     {
1799         s = &m->head.surfs[surfi];
1800 
1801         uint32_t const numverts = s->numverts;
1802 
1803         trii = 0;
1804         while (trii < s->numtris)
1805         {
1806             uint32_t const * const u = (uint32_t const *)s->tris[trii].i;
1807 
1808             // let the vertices know they're being referenced by a triangle
1809             if (u[0] >= numverts || u[1] >= numverts || u[2] >= numverts)
1810             {
1811                 // corrupt model
1812                 OSD_Printf("%s: Triangle index out of bounds!\n", m->head.nam);
1813                 return 1;
1814             }
1815 
1816             ++trii;
1817         }
1818 
1819         ++surfi;
1820     }
1821 
1822     return 0;
1823 }
1824 
1825 // Precalculated cos/sin arrays.
1826 static float g_mdcos[256], g_mdsin[256];
1827 static int32_t mdtrig_init = 0;
1828 
init_mdtrig_arrays(void)1829 static void init_mdtrig_arrays(void)
1830 {
1831     int32_t i;
1832 
1833     for (i=0; i<256; i++)
1834     {
1835         float ang = i * (2.f * fPI) * (1.f/255.f);
1836         g_mdcos[i] = cosf(ang);
1837         g_mdsin[i] = sinf(ang);
1838     }
1839 
1840     mdtrig_init = 1;
1841 }
1842 #endif
1843 
md3postload_polymer(md3model_t * m)1844 int      md3postload_polymer(md3model_t *m)
1845 {
1846 #ifdef POLYMER
1847     int         framei, surfi, verti, trii;
1848     float       vec1[5], vec2[5], mat[9], r;
1849 
1850     // POLYMER_MD_PROCESS_CHECK
1851     if (m->head.surfs[0].geometry)
1852         return -1;  // already postprocessed
1853 
1854     if (!mdtrig_init)
1855         init_mdtrig_arrays();
1856 
1857     // let's also repack the geometry to more usable formats
1858 
1859     surfi = 0;
1860     while (surfi < m->head.numsurfs)
1861     {
1862         handleevents();
1863 
1864         md3surf_t *const s = &m->head.surfs[surfi];
1865 #ifdef DEBUG_MODEL_MEM
1866         i = (m->head.numframes * s->numverts * sizeof(float) * 15);
1867         if (i > 1<<20)
1868             initprintf("size %d (%d fr, %d v): md %s surf %d/%d\n", i, m->head.numframes, s->numverts,
1869                        m->head.nam, surfi, m->head.numsurfs);
1870 #endif
1871         s->geometry = (float *)Xcalloc(m->head.numframes * s->numverts * 15, sizeof(float));
1872 
1873         if (s->numverts > tribufverts)
1874         {
1875             tribuf = (int32_t *) Xrealloc(tribuf, s->numverts * sizeof(int32_t));
1876             tribufverts = s->numverts;
1877         }
1878 
1879         Bmemset(tribuf, 0, s->numverts * sizeof(int32_t));
1880 
1881         verti = 0;
1882         while (verti < (m->head.numframes * s->numverts))
1883         {
1884             md3xyzn_t const & xyzn = s->xyzn[verti];
1885 
1886             // normal extraction from packed spherical coordinates
1887             // FIXME: swapping lat and lng because of npherno's compiler
1888             uint8_t lat = xyzn.nlng;
1889             uint8_t lng = xyzn.nlat;
1890             size_t verti15 = (size_t)verti * 15;
1891 
1892             s->geometry[verti15 + 0] = xyzn.x;
1893             s->geometry[verti15 + 1] = xyzn.y;
1894             s->geometry[verti15 + 2] = xyzn.z;
1895 
1896             s->geometry[verti15 + 3] = g_mdcos[lat] * g_mdsin[lng];
1897             s->geometry[verti15 + 4] = g_mdsin[lat] * g_mdsin[lng];
1898             s->geometry[verti15 + 5] = g_mdcos[lng];
1899 
1900             ++verti;
1901         }
1902 
1903         uint32_t numverts = s->numverts;
1904 
1905         trii = 0;
1906         while (trii < s->numtris)
1907         {
1908             int32_t const * const i = s->tris[trii].i;
1909             uint32_t const * const u = (uint32_t const *)i;
1910 
1911             // let the vertices know they're being referenced by a triangle
1912             if (u[0] >= numverts ||u[1] >= numverts || u[2] >= numverts)
1913             {
1914                 // corrupt model
1915                 return 0;
1916             }
1917             tribuf[u[0]]++;
1918             tribuf[u[1]]++;
1919             tribuf[u[2]]++;
1920 
1921             uint32_t const tris15[] = { u[0] * 15, u[1] * 15, u[2] * 15 };
1922 
1923 
1924             framei = 0;
1925             while (framei < m->head.numframes)
1926             {
1927                 const uint32_t verti15 = framei * s->numverts * 15;
1928 
1929                 vec1[0] = s->geometry[verti15 + tris15[1]]     - s->geometry[verti15 + tris15[0]];
1930                 vec1[1] = s->geometry[verti15 + tris15[1] + 1] - s->geometry[verti15 + tris15[0] + 1];
1931                 vec1[2] = s->geometry[verti15 + tris15[1] + 2] - s->geometry[verti15 + tris15[0] + 2];
1932                 vec1[3] = s->uv[u[1]].u - s->uv[u[0]].u;
1933                 vec1[4] = s->uv[u[1]].v - s->uv[u[0]].v;
1934 
1935                 vec2[0] = s->geometry[verti15 + tris15[2]]     - s->geometry[verti15 + tris15[1]];
1936                 vec2[1] = s->geometry[verti15 + tris15[2] + 1] - s->geometry[verti15 + tris15[1] + 1];
1937                 vec2[2] = s->geometry[verti15 + tris15[2] + 2] - s->geometry[verti15 + tris15[1] + 2];
1938                 vec2[3] = s->uv[u[2]].u - s->uv[u[1]].u;
1939                 vec2[4] = s->uv[u[2]].v - s->uv[u[1]].v;
1940 
1941                 r = (vec1[3] * vec2[4] - vec2[3] * vec1[4]);
1942                 if (r != 0.0f)
1943                 {
1944                     r = 1.f/r;
1945 
1946                     // tangent
1947                     mat[0] = (vec2[4] * vec1[0] - vec1[4] * vec2[0]) * r;
1948                     mat[1] = (vec2[4] * vec1[1] - vec1[4] * vec2[1]) * r;
1949                     mat[2] = (vec2[4] * vec1[2] - vec1[4] * vec2[2]) * r;
1950 
1951                     normalize(&mat[0]);
1952 
1953                     // bitangent
1954                     mat[3] = (vec1[3] * vec2[0] - vec2[3] * vec1[0]) * r;
1955                     mat[4] = (vec1[3] * vec2[1] - vec2[3] * vec1[1]) * r;
1956                     mat[5] = (vec1[3] * vec2[2] - vec2[3] * vec1[2]) * r;
1957 
1958                     normalize(&mat[3]);
1959                 }
1960                 else
1961                     Bmemset(mat, 0, sizeof(float) * 6);
1962 
1963                 // T and B are shared for the three vertices in that triangle
1964                 size_t const offs = (framei * numverts * 15) + 6;
1965                 size_t j = 0;
1966                 do
1967                 {
1968                     size_t const offsi = offs + j;
1969                     s->geometry[offsi + tris15[0]] += mat[j];
1970                     s->geometry[offsi + tris15[1]] += mat[j];
1971                     s->geometry[offsi + tris15[2]] += mat[j];
1972                 }
1973                 while (++j < 6);
1974 
1975                 ++framei;
1976             }
1977 
1978             ++trii;
1979         }
1980 
1981         // now that we accumulated the TBNs, average and invert them for each vertex
1982         int verti_end = m->head.numframes * s->numverts;
1983 
1984         verti = 0;
1985         while (verti < verti_end)
1986         {
1987             const int32_t curnumtris = tribuf[verti % s->numverts];
1988             uint32_t const verti15 = verti * 15;
1989 
1990             if (curnumtris > 0)
1991             {
1992                 const float rfcurnumtris = 1.f/(float)curnumtris;
1993                 size_t i = 6;
1994                 do
1995                     s->geometry[i + verti15] *= rfcurnumtris;
1996                 while (++i < 12);
1997             }
1998 #ifdef DEBUG_MODEL_MEM
1999             else if (verti == verti%s->numverts)
2000             {
2001                 OSD_Printf("%s: vert %d is unused\n", m->head.nam, verti);
2002             }
2003 #endif
2004             // copy N over
2005             Bmemcpy(&s->geometry[verti15 + 12], &s->geometry[verti15 + 3], sizeof(float) * 3);
2006             invertmatrix(&s->geometry[verti15 + 6], mat);
2007             Bmemcpy(&s->geometry[verti15 + 6], mat, sizeof(float) * 9);
2008 
2009             ++verti;
2010         }
2011 
2012         ++surfi;
2013     }
2014 
2015 #else
2016     UNREFERENCED_PARAMETER(m);
2017 #endif
2018 
2019     return 1;
2020 }
2021 
2022 
md3_vox_calcmat_common(tspriteptr_t tspr,const vec3f_t * a0,float f,float mat[16])2023 void md3_vox_calcmat_common(tspriteptr_t tspr, const vec3f_t *a0, float f, float mat[16])
2024 {
2025     float g;
2026     float k0, k1, k2, k3, k4, k5, k6, k7;
2027 
2028     k0 = ((float)(tspr->x+spriteext[tspr->owner].mdposition_offset.x-globalposx))*f*(1.f/1024.f);
2029     k1 = ((float)(tspr->y+spriteext[tspr->owner].mdposition_offset.y-globalposy))*f*(1.f/1024.f);
2030     f = gcosang2*gshang/gvrcorrection;
2031     g = gsinang2*gshang/gvrcorrection;
2032     k4 = (float)sintable[(tspr->ang+spriteext[tspr->owner].mdangoff+1024)&2047] * (1.f/16384.f);
2033     k5 = (float)sintable[(tspr->ang+spriteext[tspr->owner].mdangoff+ 512)&2047] * (1.f/16384.f);
2034     k2 = k0*(1-k4)+k1*k5;
2035     k3 = k1*(1-k4)-k0*k5;
2036     k6 = f*gstang - gsinang*gctang; k7 = g*gstang + gcosang*gctang;
2037     mat[0] = k4*k6 + k5*k7; mat[4] = gchang*gstang; mat[ 8] = k4*k7 - k5*k6; mat[12] = k2*k6 + k3*k7;
2038     k6 = f*gctang + gsinang*gstang; k7 = g*gctang - gcosang*gstang;
2039     mat[1] = k4*k6 + k5*k7; mat[5] = gchang*gctang; mat[ 9] = k4*k7 - k5*k6; mat[13] = k2*k6 + k3*k7;
2040     k6 =           gcosang2*gchang; k7 =           gsinang2*gchang;
2041     mat[2] = k4*k6 + k5*k7; mat[6] =-gshang*gvrcorrection; mat[10] = k4*k7 - k5*k6; mat[14] = k2*k6 + k3*k7;
2042 
2043     mat[12] = (mat[12] + a0->y*mat[0]) + (a0->z*mat[4] + a0->x*mat[ 8]);
2044     mat[13] = (mat[13] + a0->y*mat[1]) + (a0->z*mat[5] + a0->x*mat[ 9]);
2045     mat[14] = (mat[14] + a0->y*mat[2]) + (a0->z*mat[6] + a0->x*mat[10]);
2046 }
2047 
md3draw_handle_triangles(const md3surf_t * s,uint16_t * indexhandle,int32_t texunits,const md3model_t * M)2048 static void md3draw_handle_triangles(const md3surf_t *s, uint16_t *indexhandle,
2049                                             int32_t texunits, const md3model_t *M)
2050 {
2051     int32_t i;
2052 
2053     if (r_vertexarrays)
2054     {
2055         int32_t k = 0;
2056 
2057         if (M == NULL)
2058         {
2059             for (i=s->numtris-1; i>=0; i--, k+=3)
2060             {
2061                 indexhandle[k]   = s->tris[i].i[0];
2062                 indexhandle[k+1] = s->tris[i].i[1];
2063                 indexhandle[k+2] = s->tris[i].i[2];
2064             }
2065             return;
2066         }
2067 
2068 
2069         for (i=s->numtris-1; i>=0; i--, k+=3)
2070         {
2071             uint16_t tri = M->indexes[i];
2072 
2073             indexhandle[k]   = s->tris[tri].i[0];
2074             indexhandle[k+1] = s->tris[tri].i[1];
2075             indexhandle[k+2] = s->tris[tri].i[2];
2076         }
2077         return;
2078     }
2079 
2080     glBegin(GL_TRIANGLES);
2081     for (i=s->numtris-1; i>=0; i--)
2082     {
2083         uint16_t tri = M ? M->indexes[i] : i;
2084         int32_t j;
2085 
2086         for (j=0; j<3; j++)
2087         {
2088             int32_t k = s->tris[tri].i[j];
2089 
2090 #ifdef USE_GLEXT
2091             if (texunits > GL_TEXTURE0)
2092             {
2093                 int32_t l = GL_TEXTURE0;
2094                 while (l <= texunits)
2095                     glMultiTexCoord2f(l++, s->uv[k].u, s->uv[k].v);
2096             }
2097             else
2098 #endif
2099                 glTexCoord2f(s->uv[k].u, s->uv[k].v);
2100 
2101             glVertex3fv((float *) &vertlist[k]);
2102         }
2103     }
2104     glEnd();
2105 
2106 #ifndef USE_GLEXT
2107     UNREFERENCED_PARAMETER(texunits);
2108 #endif
2109 }
2110 
polymost_md3draw(md3model_t * m,tspriteptr_t tspr)2111 static int32_t polymost_md3draw(md3model_t *m, tspriteptr_t tspr)
2112 {
2113     vec3f_t m0, m1, a0;
2114     md3xyzn_t *v0, *v1;
2115     int32_t i, surfi;
2116     float f, g, k0, k1, k2=0, k3=0, mat[16];  // inits: compiler-happy
2117     GLfloat pc[4];
2118     int32_t texunits = GL_TEXTURE0;
2119 
2120     const int32_t owner = tspr->owner;
2121     const spriteext_t *const sext = &spriteext[((unsigned)owner < MAXSPRITES+MAXUNIQHUDID) ? owner : MAXSPRITES+MAXUNIQHUDID-1];
2122     const uint8_t lpal = ((unsigned)owner < MAXSPRITES) ? sprite[tspr->owner].pal : tspr->pal;
2123     const int32_t sizyrep = tilesiz[tspr->picnum].y*tspr->yrepeat;
2124 
2125     polymost_outputGLDebugMessage(3, "polymost_md3draw(m:%p, tspr:%p)", m, tspr);
2126 
2127 #ifdef USE_GLEXT
2128     if (r_vbos && (m->vbos == NULL))
2129         mdloadvbos(m);
2130 #endif
2131 
2132     //    if ((tspr->cstat&48) == 32) return 0;
2133 
2134     updateanimation((md2model_t *)m, tspr, lpal);
2135 
2136     //create current&next frame's vertex list from whole list
2137 
2138     f = m->interpol; g = 1.f - f;
2139 
2140     if (m->interpol < 0.f || m->interpol > 1.f ||
2141         (unsigned)m->cframe >= (unsigned)m->numframes ||
2142             (unsigned)m->nframe >= (unsigned)m->numframes)
2143     {
2144 #ifdef DEBUGGINGAIDS
2145         OSD_Printf("%s: mdframe oob: c:%d n:%d total:%d interpol:%.02f\n",
2146                    m->head.nam, m->cframe, m->nframe, m->numframes, m->interpol);
2147 #endif
2148 
2149         m->interpol = fclamp(m->interpol, 0.f, 1.f);
2150         m->cframe = clamp(m->cframe, 0, m->numframes-1);
2151         m->nframe = clamp(m->nframe, 0, m->numframes-1);
2152     }
2153 
2154     m0.z = m0.y = m0.x = g *= m->scale * (1.f/64.f);
2155     m1.z = m1.y = m1.x = f *= m->scale * (1.f/64.f);
2156 
2157     a0.x = a0.y = 0;
2158     a0.z = m->zadd * m->scale;
2159 
2160     // Parkar: Moved up to be able to use k0 for the y-flipping code
2161     k0 = (float)tspr->z+spriteext[tspr->owner].mdposition_offset.z;
2162     f = ((globalorientation&8) && (sprite[tspr->owner].cstat&48)!=0) ? -4.f : 4.f;
2163     k0 -= (tspr->yoffset*tspr->yrepeat)*f;
2164     if ((globalorientation&128) && !((globalorientation&48)==32))
2165         k0 += (float)(sizyrep<<1);
2166 
2167     // Parkar: Changed to use the same method as centeroriented sprites
2168     if (globalorientation&8) //y-flipping
2169     {
2170         m0.z = -m0.z; m1.z = -m1.z; a0.z = -a0.z;
2171         k0 -= (float)(sizyrep<<2);
2172     }
2173     if (globalorientation&4) { m0.y = -m0.y; m1.y = -m1.y; a0.y = -a0.y; } //x-flipping
2174 
2175     // yoffset differs from zadd in that it does not follow cstat&8 y-flipping
2176     a0.z += m->yoffset*m->scale;
2177 
2178     f = ((float)tspr->xrepeat) * (1.f/64.f) * m->bscale;
2179     m0.x *= f; m0.y *= -f;
2180     m1.x *= f; m1.y *= -f;
2181     a0.x *= f; a0.y *= -f;
2182     f = ((float)tspr->yrepeat) * (1.f/64.f) * m->bscale;
2183     m0.z *= f; m1.z *= f; a0.z *= f;
2184 
2185     // floor aligned
2186     k1 = (float)tspr->y+spriteext[tspr->owner].mdposition_offset.y;
2187     if ((globalorientation&48)==32)
2188     {
2189         m0.z = -m0.z; m1.z = -m1.z; a0.z = -a0.z;
2190         m0.y = -m0.y; m1.y = -m1.y; a0.y = -a0.y;
2191         f = a0.x; a0.x = a0.z; a0.z = f;
2192         k1 += (float)(sizyrep>>3);
2193     }
2194 
2195     // Note: These SCREEN_FACTORS will be neutralized in axes offset
2196     // calculations below again, but are needed for the base offsets.
2197     f = (65536.f*512.f)/(fxdimen*fviewingrange);
2198     g = 32.f/(fxdimen*gxyaspect);
2199     m0.y *= f; m1.y *= f; a0.y = (((float)(tspr->x+spriteext[tspr->owner].mdposition_offset.x-globalposx))*  (1.f/1024.f) + a0.y)*f;
2200     m0.x *=-f; m1.x *=-f; a0.x = ((k1     -fglobalposy) * -(1.f/1024.f) + a0.x)*-f;
2201     m0.z *= g; m1.z *= g; a0.z = ((k0     -fglobalposz) * -(1.f/16384.f) + a0.z)*g;
2202 
2203     md3_vox_calcmat_common(tspr, &a0, f, mat);
2204 
2205     // floor aligned
2206     if ((globalorientation&48)==32)
2207     {
2208         f = mat[4]; mat[4] = mat[8]*16.f; mat[8] = -f*(1.f/16.f);
2209         f = mat[5]; mat[5] = mat[9]*16.f; mat[9] = -f*(1.f/16.f);
2210         f = mat[6]; mat[6] = mat[10]*16.f; mat[10] = -f*(1.f/16.f);
2211     }
2212 
2213     //Mirrors
2214     if (grhalfxdown10x < 0) { mat[0] = -mat[0]; mat[4] = -mat[4]; mat[8] = -mat[8]; mat[12] = -mat[12]; }
2215 
2216     //------------
2217     // TSPR_FLAGS_MDHACK is an ugly hack in game.c:G_DoSpriteAnimations() telling md2sprite
2218     // to use Z-buffer hacks to hide overdraw problems with the flat-tsprite-on-floor shadows,
2219     // also disabling detail, glow, normal, and specular maps.
2220 
2221     if (tspr->clipdist & TSPR_FLAGS_MDHACK)
2222     {
2223 #ifdef __arm__ // GL ES has a glDepthRangef and the loss of precision is OK there
2224         float f = (float) (tspr->owner + 1) * (std::numeric_limits<float>::epsilon() * 8.0);
2225         if (f != 0.0) f *= 1.f/(float) (sepldist(globalposx - tspr->x, globalposy - tspr->y)>>5);
2226 #else
2227         double f = (double) (tspr->owner + 1) * (std::numeric_limits<double>::epsilon() * 8.0);
2228         if (f != 0.0) f *= 1.0/(double) (sepldist(globalposx - tspr->x, globalposy - tspr->y)>>5);
2229 //        glBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR);
2230 #endif
2231         glDepthFunc(GL_LEQUAL);
2232 //        glDepthRange(0.0 - f, 1.0 - f);
2233     }
2234 
2235 //    glPushAttrib(GL_POLYGON_BIT);
2236     if ((grhalfxdown10x >= 0) ^((globalorientation&8) != 0) ^((globalorientation&4) != 0)) glFrontFace(GL_CW); else glFrontFace(GL_CCW);
2237     glEnable(GL_CULL_FACE);
2238     glCullFace(GL_BACK);
2239 
2240     // tinting
2241     pc[0] = pc[1] = pc[2] = ((float)numshades - min(max((globalshade * shadescale) + m->shadeoff, 0.f), (float)numshades)) / (float)numshades;
2242     polytintflags_t const tintflags = hictinting[globalpal].f;
2243     if (!(tintflags & HICTINT_PRECOMPUTED))
2244     {
2245         if (!(m->flags&1))
2246             hictinting_apply(pc, globalpal);
2247         else globalnoeffect=1;
2248     }
2249 
2250     // global tinting
2251     if (have_basepal_tint())
2252         hictinting_apply(pc, MAXPALOOKUPS-1);
2253 
2254     pc[3] = (tspr->cstat&2) ? glblend[tspr->blend].def[!!(tspr->cstat&512)].alpha : 1.0f;
2255     pc[3] *= 1.0f - sext->alpha;
2256 
2257     handle_blend(!!(tspr->cstat & 2), tspr->blend, !!(tspr->cstat & 512));
2258 
2259     if (m->usesalpha) //Sprites with alpha in texture
2260     {
2261         //      glEnable(GL_BLEND);// glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
2262         //      glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER,0.32);
2263         //      float al = 0.32;
2264         // PLAG : default cutoff removed
2265         float al = 0.0;
2266         if (alphahackarray[globalpicnum] != 0)
2267             al=alphahackarray[globalpicnum] * (1.f/255.f);
2268         glEnable(GL_BLEND);
2269         // glEnable(GL_ALPHA_TEST);
2270         glAlphaFunc(GL_GREATER,al);
2271     }
2272     else
2273     {
2274         if ((tspr->cstat&2) || sext->alpha > 0.f || pc[3] < 1.0f)
2275             glEnable(GL_BLEND); //else glDisable(GL_BLEND);
2276     }
2277     glColor4f(pc[0],pc[1],pc[2],pc[3]);
2278     //if (MFLAGS_NOCONV(m))
2279     //    glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
2280     //------------
2281 
2282     // PLAG: Cleaner model rotation code
2283     if (sext->mdpitch || sext->mdroll)
2284     {
2285         float f = 1.f/((fxdimen * fviewingrange) * (256.f/(65536.f*128.f)) * (m0.x+m1.x));
2286         Bmemset(&a0, 0, sizeof(a0));
2287 
2288         if (sext->mdpivot_offset.x)
2289             a0.x = (float) sext->mdpivot_offset.x * f;
2290 
2291         if (sext->mdpivot_offset.y)  // Compare with SCREEN_FACTORS above
2292             a0.y = (float) sext->mdpivot_offset.y * f;
2293 
2294         if ((sext->mdpivot_offset.z) && !(tspr->clipdist & TSPR_FLAGS_MDHACK))  // Compare with SCREEN_FACTORS above
2295             a0.z = (float)sext->mdpivot_offset.z / (gxyaspect * fxdimen * (65536.f/128.f) * (m0.z+m1.z));
2296 
2297         k0 = (float)sintable[(sext->mdpitch+512)&2047] * (1.f/16384.f);
2298         k1 = (float)sintable[sext->mdpitch&2047] * (1.f/16384.f);
2299         k2 = (float)sintable[(sext->mdroll+512)&2047] * (1.f/16384.f);
2300         k3 = (float)sintable[sext->mdroll&2047] * (1.f/16384.f);
2301     }
2302 
2303     float const xpanning = (float)sext->xpanning * (1.f/256.f);
2304     float const ypanning = (float)sext->ypanning * (1.f/256.f);
2305 
2306     char prevClamp = polymost_getClamp();
2307     polymost_setClamp(0);
2308     polymost_usePaletteIndexing(false);
2309     polymost_setTexturePosSize({ 0.f, 0.f, 1.f, 1.f });
2310 
2311     for (surfi=0; surfi<m->head.numsurfs; surfi++)
2312     {
2313         //PLAG : sorting stuff
2314 #ifdef USE_GLEXT
2315         void               *vbotemp;
2316         vec3f_t            *vertexhandle = NULL;
2317 #endif
2318         uint16_t           *indexhandle;
2319         vec3f_t fp;
2320 
2321         const md3surf_t *const s = &m->head.surfs[surfi];
2322 
2323         v0 = &s->xyzn[m->cframe*s->numverts];
2324         v1 = &s->xyzn[m->nframe*s->numverts];
2325 
2326 #ifdef USE_GLEXT
2327         if (r_vertexarrays && r_vbos)
2328         {
2329             if (++curvbo >= r_vbocount)
2330                 curvbo = 0;
2331 
2332             glBindBuffer(GL_ARRAY_BUFFER, vertvbos[curvbo]);
2333             vbotemp = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
2334             vertexhandle = (vec3f_t *)vbotemp;
2335         }
2336 #endif
2337 
2338         if (sext->mdpitch || sext->mdroll)
2339         {
2340             vec3f_t fp1, fp2;
2341 
2342             for (i=s->numverts-1; i>=0; i--)
2343             {
2344                 fp.z = v0[i].x + a0.x;
2345                 fp.x = v0[i].y + a0.y;
2346                 fp.y = v0[i].z + a0.z;
2347 
2348                 fp1.x = fp.x*k2 +       fp.y*k3;
2349                 fp1.y = fp.x*k0*(-k3) + fp.y*k0*k2 + fp.z*(-k1);
2350                 fp1.z = fp.x*k1*(-k3) + fp.y*k1*k2 + fp.z*k0;
2351 
2352                 fp.z = v1[i].x + a0.x;
2353                 fp.x = v1[i].y + a0.y;
2354                 fp.y = v1[i].z + a0.z;
2355 
2356                 fp2.x = fp.x*k2 +       fp.y*k3;
2357                 fp2.y = fp.x*k0*(-k3) + fp.y*k0*k2 + fp.z*(-k1);
2358                 fp2.z = fp.x*k1*(-k3) + fp.y*k1*k2 + fp.z*k0;
2359                 fp.z = (fp1.z - a0.x)*m0.x + (fp2.z - a0.x)*m1.x;
2360                 fp.x = (fp1.x - a0.y)*m0.y + (fp2.x - a0.y)*m1.y;
2361                 fp.y = (fp1.y - a0.z)*m0.z + (fp2.y - a0.z)*m1.z;
2362 
2363 #ifdef USE_GLEXT
2364                 if (r_vertexarrays && r_vbos)
2365                     vertexhandle[i] = fp;
2366 #endif
2367 
2368                 vertlist[i] = fp;
2369             }
2370         }
2371         else
2372         {
2373             for (i=s->numverts-1; i>=0; i--)
2374             {
2375                 fp.z = v0[i].x*m0.x + v1[i].x*m1.x;
2376                 fp.y = v0[i].z*m0.z + v1[i].z*m1.z;
2377                 fp.x = v0[i].y*m0.y + v1[i].y*m1.y;
2378 
2379 #ifdef USE_GLEXT
2380                 if (r_vertexarrays && r_vbos)
2381                     vertexhandle[i] = fp;
2382 #endif
2383 
2384                 vertlist[i] = fp;
2385             }
2386         }
2387 
2388 #ifdef USE_GLEXT
2389         if (r_vertexarrays && r_vbos)
2390         {
2391             glUnmapBuffer(GL_ARRAY_BUFFER);
2392             glBindBuffer(GL_ARRAY_BUFFER, 0);
2393         }
2394 #endif
2395 
2396         glMatrixMode(GL_MODELVIEW); //Let OpenGL (and perhaps hardware :) handle the matrix rotation
2397         mat[3] = mat[7] = mat[11] = 0.f; mat[15] = 1.f; glLoadMatrixf(mat);
2398         // PLAG: End
2399 
2400         i = mdloadskin((md2model_t *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,globalpal,surfi);
2401         if (!i)
2402             continue;
2403         //i = mdloadskin((md2model *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,surfi); //hack for testing multiple surfaces per MD3
2404         glBindTexture(GL_TEXTURE_2D, i);
2405 
2406         glMatrixMode(GL_TEXTURE);
2407         glLoadIdentity();
2408         glTranslatef(xpanning, ypanning, 1.0f);
2409         glMatrixMode(GL_MODELVIEW);
2410 
2411         if (!(tspr->clipdist & TSPR_FLAGS_MDHACK))
2412         {
2413 #ifdef USE_GLEXT
2414             //POGOTODO: if we add support for palette indexing on model skins, the texture for the palswap could be setup here
2415             texunits += 4;
2416 
2417             i = r_detailmapping ? mdloadskin((md2model_t *) m, tile2model[Ptile2tile(tspr->picnum, lpal)].skinnum, DETAILPAL, surfi) : 0;
2418 
2419             if (i)
2420             {
2421                 mdskinmap_t *sk;
2422 
2423                 polymost_useDetailMapping(true);
2424                 polymost_setupdetailtexture(GL_TEXTURE3, i);
2425 
2426                 for (sk = m->skinmap; sk; sk = sk->next)
2427                     if ((int32_t) sk->palette == DETAILPAL && sk->skinnum == tile2model[Ptile2tile(tspr->picnum, lpal)].skinnum && sk->surfnum == surfi)
2428                         f = sk->param;
2429 
2430                 glMatrixMode(GL_TEXTURE);
2431                 glLoadIdentity();
2432                 glTranslatef(xpanning, ypanning, 1.0f);
2433                 glScalef(f, f, 1.0f);
2434                 glMatrixMode(GL_MODELVIEW);
2435             }
2436 
2437             i = r_glowmapping ? mdloadskin((md2model_t *) m, tile2model[Ptile2tile(tspr->picnum, lpal)].skinnum, GLOWPAL, surfi) : 0;
2438 
2439             if (i)
2440             {
2441                 polymost_useGlowMapping(true);
2442                 polymost_setupglowtexture(GL_TEXTURE4, i);
2443 
2444                 glMatrixMode(GL_TEXTURE);
2445                 glLoadIdentity();
2446                 glTranslatef(xpanning, ypanning, 1.0f);
2447                 glMatrixMode(GL_MODELVIEW);
2448             }
2449 
2450             if (r_vertexarrays && r_vbos)
2451             {
2452                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexvbos[curvbo]);
2453                 vbotemp = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
2454                 indexhandle = (uint16_t *) vbotemp;
2455             }
2456             else
2457 #endif
2458                 indexhandle = m->vindexes;
2459 
2460             //PLAG: delayed polygon-level sorted rendering
2461 
2462             if (m->usesalpha)
2463             {
2464                 for (i=0; i<=s->numtris-1; ++i)
2465                 {
2466                     vec3f_t const vlt[3] = { vertlist[s->tris[i].i[0]], vertlist[s->tris[i].i[1]], vertlist[s->tris[i].i[2]] };
2467 
2468                     // Matrix multiplication - ugly but clear
2469                     vec3f_t const fp[3] = { { (vlt[0].x * mat[0]) + (vlt[0].y * mat[4]) + (vlt[0].z * mat[8]) + mat[12],
2470                                               (vlt[0].x * mat[1]) + (vlt[0].y * mat[5]) + (vlt[0].z * mat[9]) + mat[13],
2471                                               (vlt[0].x * mat[2]) + (vlt[0].y * mat[6]) + (vlt[0].z * mat[10]) + mat[14] },
2472 
2473                                             { (vlt[1].x * mat[0]) + (vlt[1].y * mat[4]) + (vlt[1].z * mat[8]) + mat[12],
2474                                               (vlt[1].x * mat[1]) + (vlt[1].y * mat[5]) + (vlt[1].z * mat[9]) + mat[13],
2475                                               (vlt[1].x * mat[2]) + (vlt[1].y * mat[6]) + (vlt[1].z * mat[10]) + mat[14] },
2476 
2477                                             { (vlt[2].x * mat[0]) + (vlt[2].y * mat[4]) + (vlt[2].z * mat[8]) + mat[12],
2478                                               (vlt[2].x * mat[1]) + (vlt[2].y * mat[5]) + (vlt[2].z * mat[9]) + mat[13],
2479                                               (vlt[2].x * mat[2]) + (vlt[2].y * mat[6]) + (vlt[2].z * mat[10]) + mat[14] } };
2480 
2481                     f = (fp[0].x * fp[0].x) + (fp[0].y * fp[0].y) + (fp[0].z * fp[0].z);
2482                     g = (fp[1].x * fp[1].x) + (fp[1].y * fp[1].y) + (fp[1].z * fp[1].z);
2483 
2484                     if (f > g)
2485                         f = g;
2486 
2487                     g = (fp[2].x * fp[2].x) + (fp[2].y * fp[2].y) + (fp[2].z * fp[2].z);
2488 
2489                     if (f > g)
2490                         f = g;
2491 
2492                     m->maxdepths[i] = f;
2493                     m->indexes[i]   = i;
2494                 }
2495 
2496                 // dichotomic recursive sorting - about 100x less iterations than bubblesort
2497                 quicksort(m->indexes, m->maxdepths, 0, s->numtris - 1);
2498             }
2499 
2500             md3draw_handle_triangles(s, indexhandle, texunits, m->usesalpha ? m : NULL);
2501         }
2502         else
2503         {
2504 #ifdef USE_GLEXT
2505             if (r_vertexarrays && r_vbos)
2506             {
2507                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexvbos[curvbo]);
2508                 vbotemp = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
2509                 indexhandle = (uint16_t *) vbotemp;
2510             }
2511             else
2512 #endif
2513                 indexhandle = m->vindexes;
2514 
2515             md3draw_handle_triangles(s, indexhandle, texunits, NULL);
2516         }
2517 
2518         if (r_vertexarrays)
2519         {
2520 #ifdef USE_GLEXT
2521             int32_t l;
2522 
2523             if (r_vbos)
2524             {
2525                 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
2526                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2527                 glBindBuffer(GL_ARRAY_BUFFER, m->vbos[surfi]);
2528 
2529                 l = GL_TEXTURE0;
2530                 do
2531                 {
2532                     glClientActiveTexture(l++);
2533                     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2534                     glTexCoordPointer(2, GL_FLOAT, 0, 0);
2535                 } while (l <= texunits);
2536 
2537                 glBindBuffer(GL_ARRAY_BUFFER, vertvbos[curvbo]);
2538                 glVertexPointer(3, GL_FLOAT, 0, 0);
2539 
2540                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexvbos[curvbo]);
2541                 glDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_SHORT, 0);
2542 
2543                 glBindBuffer(GL_ARRAY_BUFFER, 0);
2544                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2545             }
2546             else // r_vbos
2547             {
2548                 l = GL_TEXTURE0;
2549                 do
2550                 {
2551                     glClientActiveTexture(l++);
2552                     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2553                     glTexCoordPointer(2, GL_FLOAT, 0, &(s->uv[0].u));
2554                 } while (l <= texunits);
2555 
2556                 glVertexPointer(3, GL_FLOAT, 0, &(vertlist[0].x));
2557 
2558                 glDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_SHORT, m->vindexes);
2559             } // r_vbos
2560 
2561             while (texunits > GL_TEXTURE0)
2562             {
2563                 glMatrixMode(GL_TEXTURE);
2564                 glLoadIdentity();
2565                 glMatrixMode(GL_MODELVIEW);
2566                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.0f);
2567                 glDisable(GL_TEXTURE_2D);
2568                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2569                 glClientActiveTexture(texunits - 1);
2570                 glActiveTexture(--texunits);
2571             }
2572 #else
2573             glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2574             glTexCoordPointer(2, GL_FLOAT, 0, &(s->uv[0].u));
2575 
2576             glVertexPointer(3, GL_FLOAT, 0, &(vertlist[0].x));
2577 
2578             glDrawElements(GL_TRIANGLES, s->numtris * 3, GL_UNSIGNED_SHORT, m->vindexes);
2579 #endif
2580         }
2581 #ifdef USE_GLEXT
2582         else // r_vertexarrays
2583         {
2584             while (texunits > GL_TEXTURE0)
2585             {
2586                 glMatrixMode(GL_TEXTURE);
2587                 glLoadIdentity();
2588                 glMatrixMode(GL_MODELVIEW);
2589                 glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.0f);
2590                 glDisable(GL_TEXTURE_2D);
2591                 glActiveTexture(--texunits);
2592             }
2593         } // r_vertexarrays
2594 
2595         polymost_useDetailMapping(false);
2596         polymost_useGlowMapping(false);
2597 #endif
2598     }
2599     //------------
2600 
2601     // if (m->usesalpha) glDisable(GL_ALPHA_TEST);
2602 
2603     glDisable(GL_CULL_FACE);
2604 //    glPopAttrib();
2605 
2606     glMatrixMode(GL_TEXTURE);
2607     glLoadIdentity();
2608     glMatrixMode(GL_MODELVIEW);
2609     glLoadIdentity();
2610 
2611     polymost_setClamp(prevClamp);
2612     polymost_usePaletteIndexing(true);
2613     polymost_resetVertexPointers();
2614 
2615     globalnoeffect=0;
2616     return 1;
2617 }
2618 
md3free(md3model_t * m)2619 static void md3free(md3model_t *m)
2620 {
2621     mdanim_t *anim, *nanim = NULL;
2622     mdskinmap_t *sk, *nsk = NULL;
2623 
2624     if (!m) return;
2625 
2626     for (anim=m->animations; anim; anim=nanim)
2627     {
2628         nanim = anim->next;
2629         Xfree(anim);
2630     }
2631     for (sk=m->skinmap; sk; sk=nsk)
2632     {
2633         nsk = sk->next;
2634         Xfree(sk->fn);
2635         Xfree(sk);
2636     }
2637 
2638     if (m->head.surfs)
2639     {
2640         for (bssize_t surfi=m->head.numsurfs-1; surfi>=0; surfi--)
2641         {
2642             md3surf_t *s = &m->head.surfs[surfi];
2643             Xfree(s->tris);
2644             Xfree(s->geometry);  // FREE_SURFS_GEOMETRY
2645         }
2646         Xfree(m->head.surfs);
2647     }
2648     Xfree(m->head.tags);
2649     Xfree(m->head.frames);
2650 
2651     Xfree(m->texid);
2652 
2653     Xfree(m->muladdframes);
2654 
2655     Xfree(m->indexes);
2656     Xfree(m->vindexes);
2657     Xfree(m->maxdepths);
2658 
2659 #ifdef USE_GLEXT
2660     if (m->vbos)
2661     {
2662         glDeleteBuffers(m->head.numsurfs, m->vbos);
2663         DO_FREE_AND_NULL(m->vbos);
2664     }
2665 #endif
2666 
2667     Xfree(m);
2668 }
2669 
2670 //---------------------------------------- MD3 LIBRARY ENDS ----------------------------------------
2671 //--------------------------------------- MD LIBRARY BEGINS  ---------------------------------------
2672 
mdload(const char * filnam)2673 mdmodel_t *mdload(const char *filnam)
2674 {
2675     mdmodel_t *vm;
2676     int32_t i;
2677 
2678     vm = (mdmodel_t *)voxload(filnam);
2679     if (vm) return vm;
2680 
2681     buildvfs_kfd fil = kopen4load(filnam,0);
2682 
2683     if (fil == buildvfs_kfd_invalid)
2684         return NULL;
2685 
2686     kread(fil,&i,4);
2687     klseek(fil,0,SEEK_SET);
2688 
2689     switch (B_LITTLE32(i))
2690     {
2691     case IDP2_MAGIC:
2692 //        initprintf("Warning: model \"%s\" is version IDP2; wanted version IDP3\n",filnam);
2693         vm = (mdmodel_t *)md2load(fil,filnam);
2694         break; //IDP2
2695     case IDP3_MAGIC:
2696         vm = (mdmodel_t *)md3load(fil);
2697         break; //IDP3
2698     default:
2699         vm = NULL;
2700         break;
2701     }
2702 
2703     kclose(fil);
2704 
2705     if (vm)
2706     {
2707         md3model_t *vm3 = (md3model_t *)vm;
2708 
2709         // smuggle the file name into the model struct.
2710         // head.nam is unused as far as I can tell
2711         Bstrncpyz(vm3->head.nam, filnam, sizeof(vm3->head.nam));
2712 
2713         md3postload_common(vm3);
2714 
2715 #ifdef POLYMER
2716         if (glrendmode != REND_POLYMER)
2717             if (md3postload_polymer_check(vm3))
2718             {
2719                 mdfree(vm);
2720                 vm = NULL;
2721             }
2722 #endif
2723     }
2724 
2725     return vm;
2726 }
2727 
2728 #ifdef USE_GLEXT
md_allocvbos(void)2729 void md_allocvbos(void)
2730 {
2731     int32_t i;
2732 
2733     indexvbos = (GLuint *) Xrealloc(indexvbos, sizeof(GLuint) * r_vbocount);
2734     vertvbos = (GLuint *) Xrealloc(vertvbos, sizeof(GLuint) * r_vbocount);
2735 
2736     if (r_vbocount != allocvbos)
2737     {
2738         glGenBuffers(r_vbocount - allocvbos, &(indexvbos[allocvbos]));
2739         glGenBuffers(r_vbocount - allocvbos, &(vertvbos[allocvbos]));
2740 
2741         i = allocvbos;
2742         while (i < r_vbocount)
2743         {
2744             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexvbos[i]);
2745             glBufferData(GL_ELEMENT_ARRAY_BUFFER, maxmodeltris * 3 * sizeof(uint16_t), NULL, GL_STREAM_DRAW);
2746             glBindBuffer(GL_ARRAY_BUFFER, vertvbos[i]);
2747             glBufferData(GL_ARRAY_BUFFER, maxmodelverts * sizeof(vec3f_t), NULL, GL_STREAM_DRAW);
2748             i++;
2749         }
2750 
2751         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2752         glBindBuffer(GL_ARRAY_BUFFER, 0);
2753 
2754         allocvbos = r_vbocount;
2755     }
2756 }
2757 #endif
2758 
polymost_mddraw(tspriteptr_t tspr)2759 int32_t polymost_mddraw(tspriteptr_t tspr)
2760 {
2761 #ifdef USE_GLEXT
2762     if (r_vbos && (r_vbocount > allocvbos))
2763         md_allocvbos();
2764 #endif
2765 
2766     if (maxmodelverts > allocmodelverts)
2767     {
2768         vertlist = (vec3f_t *) Xrealloc(vertlist, sizeof(vec3f_t)*maxmodelverts);
2769         allocmodelverts = maxmodelverts;
2770     }
2771 
2772     mdmodel_t *const vm = models[tile2model[Ptile2tile(tspr->picnum,
2773     (tspr->owner >= MAXSPRITES) ? tspr->pal : sprite[tspr->owner].pal)].modelid];
2774     if (vm->mdnum == 1)
2775         return polymost_voxdraw((voxmodel_t *)vm,tspr);
2776     else if (vm->mdnum == 3)
2777         return polymost_md3draw((md3model_t *)vm,tspr);
2778     return 0;
2779 }
2780 
mdfree(mdmodel_t * vm)2781 void mdfree(mdmodel_t *vm)
2782 {
2783     if (vm->mdnum == 1) { voxfree((voxmodel_t *)vm); return; }
2784     if (vm->mdnum == 2 || vm->mdnum == 3) { md3free((md3model_t *)vm); return; }
2785 }
2786 
2787 #endif
2788 
2789 //---------------------------------------- MD LIBRARY ENDS  ----------------------------------------
2790