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