//------------------------------------- MD2/MD3 LIBRARY BEGINS -------------------------------------
#ifdef USE_OPENGL
#include "compat.h"
#include "build.h"
#include "glbuild.h"
#include "pragmas.h"
#include "baselayer.h"
#include "engine_priv.h"
#include "hightile.h"
#include "polymost.h"
#include "texcache.h"
#include "mdsprite.h"
#include "cache1d.h"
#include "kplib.h"
#include "common.h"
#include <math.h>
#include <float.h>
static int32_t curextra
=MAXTILES
;
#define MIN_CACHETIME_PRINT 10
static void QuitOnFatalError
(const char *msg
)
{
if (msg
)
initprintf
("%s\n", msg
);
uninitengine
();
Bexit
(1);
}
static int32_t addtileP
(int32_t model
,int32_t tile
,int32_t pallet
)
{
// tile >= 0 && tile < MAXTILES
UNREFERENCED_PARAMETER
(model
);
if (curextra
==MAXTILES
+EXTRATILES
-1)
{
initprintf
("warning: max EXTRATILES reached\n");
return curextra
;
}
if (tile2model
[tile
].
modelid==-1)
{
tile2model
[tile
].
pal=pallet
;
return tile
;
}
if (tile2model
[tile
].
pal==pallet
)
return tile
;
while (tile2model
[tile
].
next!=-1)
{
tile
=tile2model
[tile
].
next;
if (tile2model
[tile
].
pal==pallet
)
return tile
;
}
tile2model
[tile
].
next=curextra
;
tile2model
[curextra
].
pal=pallet
;
return curextra
++;
}
int32_t Ptile2tile
(int32_t tile
,int32_t pallet
)
{
int32_t t
=tile
;
// if(tile>=1550&&tile<=1589){initprintf("(%d, %d)\n",tile,pallet);pallet=0;}
while ((tile
=tile2model
[tile
].
next)!=-1)
if (tile2model
[tile
].
pal==pallet
)
return tile
;
return t
;
}
#define MODELALLOCGROUP 256
static int32_t nummodelsalloced
= 0;
static int32_t maxmodelverts
= 0, allocmodelverts
= 0;
static int32_t maxmodeltris
= 0, allocmodeltris
= 0;
static vec3f_t
*vertlist
= NULL
; //temp array to store interpolated vertices for drawing
static int32_t allocvbos
= 0, curvbo
= 0;
static GLuint
*vertvbos
= NULL
;
static GLuint
*indexvbos
= NULL
;
#ifdef POLYMER
static int32_t *tribuf
= NULL
;
static int32_t tribufverts
= 0;
#endif
static mdmodel_t
*mdload
(const char *);
static void mdfree
(mdmodel_t
*);
int32_t globalnoeffect
=0;
extern int32_t timerticspersec
;
void md_freevbos
()
{
int32_t i
;
for (i
=0; i
<nextmodelid
; i
++)
if (models
[i
]->mdnum
== 3)
{
md3model_t
*m
= (md3model_t
*)models
[i
];
if (m
->vbos
)
{
// OSD_Printf("freeing model %d vbo\n",i);
bglDeleteBuffersARB
(m
->head.
numsurfs, m
->vbos
);
Bfree
(m
->vbos
);
m
->vbos
= NULL
;
}
}
if (allocvbos
)
{
bglDeleteBuffersARB
(allocvbos
, indexvbos
);
bglDeleteBuffersARB
(allocvbos
, vertvbos
);
allocvbos
= 0;
}
}
void freeallmodels
()
{
int32_t i
;
if (models
)
{
for (i
=0; i
<nextmodelid
; i
++) mdfree
(models
[i
]);
Bfree
(models
); models
= NULL
;
nummodelsalloced
= 0;
nextmodelid
= 0;
}
memset(tile2model
,-1,sizeof(tile2model
));
curextra
=MAXTILES
;
if (vertlist
)
{
Bfree
(vertlist
);
vertlist
= NULL
;
allocmodelverts
= maxmodelverts
= 0;
allocmodeltris
= maxmodeltris
= 0;
}
md_freevbos
();
#ifdef POLYMER
DO_FREE_AND_NULL
(tribuf
);
#endif
}
// Skin texture names can be aliased! This is ugly, but at least correct.
static void nullskintexids
(GLuint texid
)
{
int32_t i
, j
;
for (i
=0; i
<nextmodelid
; i
++)
{
mdmodel_t
*m
= models
[i
];
if (m
->mdnum
== 2 || m
->mdnum
== 3)
{
mdskinmap_t
*sk
;
md2model_t
*m2
= (md2model_t
*)m
;
for (j
=0; j
<m2
->numskins
*(HICEFFECTMASK
+1); j
++)
if (m2
->texid
[j
] == texid
)
m2
->texid
[j
] = 0;
for (sk
=m2
->skinmap
; sk
; sk
=sk
->next
)
for (j
=0; j
<(HICEFFECTMASK
+1); j
++)
if (sk
->texid
[j
] == texid
)
sk
->texid
[j
] = 0;
}
}
}
void clearskins
()
{
int32_t i
, j
;
for (i
=0; i
<nextmodelid
; i
++)
{
mdmodel_t
*m
= models
[i
];
if (m
->mdnum
== 1)
{
voxmodel_t
*v
= (voxmodel_t
*)m
;
for (j
=0; j
<MAXPALOOKUPS
; j
++)
if (v
->texid
[j
])
{
bglDeleteTextures
(1, &v
->texid
[j
]);
v
->texid
[j
] = 0;
}
}
else if (m
->mdnum
== 2 || m
->mdnum
== 3)
{
mdskinmap_t
*sk
;
md2model_t
*m2
= (md2model_t
*)m
;
for (j
=0; j
<m2
->numskins
*(HICEFFECTMASK
+1); j
++)
if (m2
->texid
[j
])
{
GLuint otexid
= m2
->texid
[j
];
bglDeleteTextures
(1, &m2
->texid
[j
]);
m2
->texid
[j
] = 0;
nullskintexids
(otexid
);
}
for (sk
=m2
->skinmap
; sk
; sk
=sk
->next
)
for (j
=0; j
<(HICEFFECTMASK
+1); j
++)
if (sk
->texid
[j
])
{
GLuint otexid
= sk
->texid
[j
];
bglDeleteTextures
(1, &sk
->texid
[j
]);
sk
->texid
[j
] = 0;
nullskintexids
(otexid
);
}
}
}
for (i
=0; i
<MAXVOXELS
; i
++)
{
voxmodel_t
*v
= voxmodels
[i
];
if (!v
) continue;
for (j
=0; j
<MAXPALOOKUPS
; j
++)
if (v
->texid
[j
])
{
bglDeleteTextures
(1, &v
->texid
[j
]);
v
->texid
[j
] = 0;
}
}
}
void mdinit
()
{
memset(hudmem
,0,sizeof(hudmem
));
freeallmodels
();
mdinited
= 1;
}
int32_t md_loadmodel
(const char *fn
)
{
mdmodel_t
*vm
, **ml
;
if (!mdinited
) mdinit
();
if (nextmodelid
>= nummodelsalloced
)
{
ml
= (mdmodel_t
**)Xrealloc
(models
,(nummodelsalloced
+MODELALLOCGROUP
)*sizeof(void *));
models
= ml
; nummodelsalloced
+= MODELALLOCGROUP
;
}
vm
= mdload
(fn
); if (!vm
) return(-1);
models
[nextmodelid
++] = vm
;
return(nextmodelid
-1);
}
int32_t md_setmisc
(int32_t modelid
, float scale
, int32_t shadeoff
, float zadd
, float yoffset
, int32_t flags
)
{
mdmodel_t
*m
;
if (!mdinited
) mdinit
();
if ((uint32_t)modelid
>= (uint32_t)nextmodelid
) return -1;
m
= models
[modelid
];
m
->bscale
= scale
;
m
->shadeoff
= shadeoff
;
m
->zadd
= zadd
;
m
->yoffset
= yoffset
;
m
->flags
= flags
;
return 0;
}
static int32_t framename2index
(mdmodel_t
*vm
, const char *nam
)
{
int32_t i
= 0;
switch (vm
->mdnum
)
{
case 2:
{
md2model_t
*m
= (md2model_t
*)vm
;
md2frame_t
*fr
;
for (i
=0; i
<m
->numframes
; i
++)
{
fr
= (md2frame_t
*)&m
->frames
[i
*m
->framebytes
];
if (!Bstrcmp
(fr
->name
, nam
)) break;
}
}
break;
case 3:
{
md3model_t
*m
= (md3model_t
*)vm
;
for (i
=0; i
<m
->numframes
; i
++)
if (!Bstrcmp
(m
->head.
frames[i
].
nam,nam
)) break;
}
break;
}
return(i
);
}
int32_t md_defineframe
(int32_t modelid
, const char *framename
, int32_t tilenume
, int32_t skinnum
, float smoothduration
, int32_t pal
)
{
md2model_t
*m
;
int32_t i
;
if (!mdinited
) mdinit
();
if ((uint32_t)modelid
>= (uint32_t)nextmodelid
) return(-1);
if ((uint32_t)tilenume
>= (uint32_t)MAXTILES
) return(-2);
if (!framename
) return(-3);
tilenume
=addtileP
(modelid
,tilenume
,pal
);
m
= (md2model_t
*)models
[modelid
];
if (m
->mdnum
== 1)
{
tile2model
[tilenume
].
modelid = modelid
;
tile2model
[tilenume
].
framenum = tile2model
[tilenume
].
skinnum = 0;
return 0;
}
i
= framename2index
((mdmodel_t
*)m
,framename
);
if (i
== m
->numframes
) return(-3); // frame name invalid
tile2model
[tilenume
].
modelid = modelid
;
tile2model
[tilenume
].
framenum = i
;
tile2model
[tilenume
].
skinnum = skinnum
;
tile2model
[tilenume
].
smoothduration = smoothduration
;
return i
;
}
int32_t md_defineanimation
(int32_t modelid
, const char *framestart
, const char *frameend
, int32_t fpssc
, int32_t flags
)
{
md2model_t
*m
;
mdanim_t ma
, *map
;
int32_t i
;
if (!mdinited
) mdinit
();
if ((uint32_t)modelid
>= (uint32_t)nextmodelid
) return(-1);
Bmemset
(&ma
, 0, sizeof(ma
));
m
= (md2model_t
*)models
[modelid
];
if (m
->mdnum
< 2) return 0;
//find index of start frame
i
= framename2index
((mdmodel_t
*)m
,framestart
);
if (i
== m
->numframes
) return -2;
ma.
startframe = i
;
//find index of finish frame which must trail start frame
i
= framename2index
((mdmodel_t
*)m
,frameend
);
if (i
== m
->numframes
) return -3;
ma.
endframe = i
;
ma.
fpssc = fpssc
;
ma.
flags = flags
;
map
= (mdanim_t
*)Xmalloc
(sizeof(mdanim_t
));
Bmemcpy
(map
, &ma
, sizeof(ma
));
map
->next
= m
->animations
;
m
->animations
= map
;
return(0);
}
#if 0
// FIXME: CURRENTLY DISABLED: interpolation may access frames we consider 'unused'?
int32_t md_thinoutmodel
(int32_t modelid
, uint8_t *usedframebitmap
)
{
md3model_t
*m
;
md3surf_t
*s
;
mdanim_t
*anm
;
int32_t i
, surfi
, sub
, usedframes
;
static int16_t otonframe
[1024];
if ((uint32_t)modelid
>= (uint32_t)nextmodelid
) return -1;
m
= (md3model_t
*)models
[modelid
];
if (m
->mdnum
!= 3) return -2;
for (anm
=m
->animations
; anm
; anm
=anm
->next
)
{
if (anm
->endframe
<= anm
->startframe
)
{
// initprintf("backward anim %d-%d\n", anm->startframe, anm->endframe);
return -3;
}
for (i
=anm
->startframe
; i
<anm
->endframe
; i
++)
usedframebitmap
[i
>>3] |= (1<<(i
&7));
}
sub
= 0;
for (i
=0; i
<m
->numframes
; i
++)
{
if (!(usedframebitmap
[i
>>3]&(1<<(i
&7))))
{
sub
++;
otonframe
[i
] = -1;
continue;
}
otonframe
[i
] = i
-sub
;
}
usedframes
= m
->numframes
- sub
;
if (usedframes
==0 || usedframes
==m
->numframes
)
return usedframes
;
//// THIN OUT! ////
for (i
=0; i
<m
->numframes
; i
++)
{
if (otonframe
[i
]>=0 && otonframe
[i
] != i
)
{
if (m
->muladdframes
)
Bmemcpy
(&m
->muladdframes
[2*otonframe
[i
]], &m
->muladdframes
[2*i
], 2*sizeof(vec3f_t
));
Bmemcpy
(&m
->head.
frames[otonframe
[i
]], &m
->head.
frames[i
], sizeof(md3frame_t
));
}
}
for (surfi
=0; surfi
< m
->head.
numsurfs; surfi
++)
{
s
= &m
->head.
surfs[surfi
];
for (i
=0; i
<m
->numframes
; i
++)
if (otonframe
[i
]>=0 && otonframe
[i
] != i
)
Bmemcpy
(&s
->xyzn
[otonframe
[i
]*s
->numverts
], &s
->xyzn
[i
*s
->numverts
], s
->numverts
*sizeof(md3xyzn_t
));
}
////// tweak frame indices in various places
for (anm
=m
->animations
; anm
; anm
=anm
->next
)
{
if (otonframe
[anm
->startframe
]==-1 || otonframe
[anm
->endframe
-1]==-1)
initprintf
("md %d WTF: anm %d %d\n", modelid
, anm
->startframe
, anm
->endframe
);
anm
->startframe
= otonframe
[anm
->startframe
];
anm
->endframe
= otonframe
[anm
->endframe
-1];
}
for (i
=0; i
<MAXTILES
+EXTRATILES
; i
++)
if (tile2model
[i
].
modelid == modelid
)
{
if (otonframe
[tile2model
[i
].
framenum]==-1)
initprintf
("md %d WTF: tile %d, fr %d\n", modelid
, i
, tile2model
[i
].
framenum);
tile2model
[i
].
framenum = otonframe
[tile2model
[i
].
framenum];
}
////// realloc & change "numframes" everywhere
if (m
->muladdframes
)
m
->muladdframes
= Xrealloc
(m
->muladdframes
, 2*sizeof(vec3f_t
)*usedframes
);
m
->head.
frames = Xrealloc
(m
->head.
frames, sizeof(md3frame_t
)*usedframes
);
for (surfi
=0; surfi
< m
->head.
numsurfs; surfi
++)
{
m
->head.
surfs[surfi
].
numframes = usedframes
;
// CAN'T do that because xyzn is offset from a larger block when loaded from md3:
// m->head.surfs[surfi].xyzn = Xrealloc(m->head.surfs[surfi].xyzn, s->numverts*usedframes*sizeof(md3xyzn_t));
}
m
->head.
numframes = usedframes
;
m
->numframes
= usedframes
;
////////////
return usedframes
;
}
#endif
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
)
{
mdskinmap_t
*sk
, *skl
;
md2model_t
*m
;
if (!mdinited
) mdinit
();
if ((uint32_t)modelid
>= (uint32_t)nextmodelid
) return -1;
if (!skinfn
) return -2;
if ((unsigned)palnum
>= (unsigned)MAXPALOOKUPS
) return -3;
m
= (md2model_t
*)models
[modelid
];
if (m
->mdnum
< 2) return 0;
if (m
->mdnum
== 2) surfnum
= 0;
skl
= NULL
;
for (sk
= m
->skinmap
; sk
; skl
= sk
, sk
= sk
->next
)
if (sk
->palette
== (uint8_t)palnum
&& skinnum
== sk
->skinnum
&& surfnum
== sk
->surfnum
)
break;
if (!sk
)
{
sk
= (mdskinmap_t
*)Xcalloc
(1,sizeof(mdskinmap_t
));
if (!skl
) m
->skinmap
= sk
;
else skl
->next
= sk
;
}
else if (sk
->fn
) Bfree
(sk
->fn
);
sk
->palette
= (uint8_t)palnum
;
sk
->skinnum
= skinnum
;
sk
->surfnum
= surfnum
;
sk
->param
= param
;
sk
->specpower
= specpower
;
sk
->specfactor
= specfactor
;
sk
->fn
= Xstrdup
(skinfn
);
return 0;
}
int32_t md_definehud
(int32_t modelid
, int32_t tilex
, float xadd
, float yadd
, float zadd
, int32_t angadd
, int32_t flags
, int32_t fov
)
{
if (!mdinited
) mdinit
();
if ((uint32_t)modelid
>= (uint32_t)nextmodelid
) return -1;
if ((uint32_t)tilex
>= (uint32_t)MAXTILES
) return -2;
hudmem
[(flags
>>2)&1][tilex
].
add.
x = xadd
;
hudmem
[(flags
>>2)&1][tilex
].
add.
y = yadd
;
hudmem
[(flags
>>2)&1][tilex
].
add.
z = zadd
;
hudmem
[(flags
>>2)&1][tilex
].
angadd = ((int16_t)angadd
)|2048;
hudmem
[(flags
>>2)&1][tilex
].
flags = (int16_t)flags
;
hudmem
[(flags
>>2)&1][tilex
].
fov = (int16_t)fov
;
return 0;
}
int32_t md_undefinetile
(int32_t tile
)
{
if (!mdinited
) return 0;
if ((unsigned)tile
>= (unsigned)MAXTILES
) return -1;
tile2model
[tile
].
modelid = -1;
tile2model
[tile
].
next=-1;
hudmem
[0][tile
].
angadd = 0;
hudmem
[1][tile
].
angadd = 0;
return 0;
}
/* this function is problematic, it leaves NULL holes in model[]
* (which runs from 0 to nextmodelid-1) */
int32_t md_undefinemodel
(int32_t modelid
)
{
int32_t i
;
if (!mdinited
) return 0;
if ((uint32_t)modelid
>= (uint32_t)nextmodelid
) return -1;
for (i
=MAXTILES
+EXTRATILES
-1; i
>=0; i
--)
if (tile2model
[i
].
modelid == modelid
)
tile2model
[i
].
modelid = -1;
if (models
)
{
mdfree
(models
[modelid
]);
models
[modelid
] = NULL
;
}
return 0;
}
static int32_t daskinloader
(int32_t filh
, intptr_t *fptr
, int32_t *bpl
, int32_t *sizx
, int32_t *sizy
,
int32_t *osizx
, int32_t *osizy
, char *hasalpha
, int32_t pal
, char effect
)
{
int32_t picfillen
, j
,y
,x
;
char *picfil
,*cptr
,al
=255;
coltype
*pic
;
int32_t xsiz
, ysiz
, tsizx
, tsizy
;
int32_t r
, g
, b
;
picfillen
= kfilelength
(filh
);
picfil
= (char *)Xmalloc
(picfillen
+1);
kread
(filh
, picfil
, picfillen
);
// tsizx/y = replacement texture's natural size
// xsiz/y = 2^x size of replacement
kpgetdim
(picfil
,picfillen
,&tsizx
,&tsizy
);
if (tsizx
== 0 || tsizy
== 0) { Bfree
(picfil
); return -2; }
if (!glinfo.
texnpot)
{
for (xsiz
=1; xsiz
<tsizx
; xsiz
+=xsiz
);
for (ysiz
=1; ysiz
<tsizy
; ysiz
+=ysiz
);
}
else
{
xsiz
= tsizx
;
ysiz
= tsizy
;
}
*osizx
= tsizx
; *osizy
= tsizy
;
pic
= (coltype
*)Xmalloc
(xsiz
*ysiz
*sizeof(coltype
));
memset(pic
,0,xsiz
*ysiz
*sizeof(coltype
));
if (kprender
(picfil
,picfillen
,(intptr_t)pic
,xsiz
*sizeof(coltype
),xsiz
,ysiz
))
{ Bfree
(picfil
); Bfree
(pic
); return -2; }
Bfree
(picfil
);
cptr
= &britable
[gammabrightness
? 0 : curbrightness
][0];
r
=(glinfo.
bgra)?hictinting
[pal
].
b:hictinting
[pal
].
r;
g
=hictinting
[pal
].
g;
b
=(glinfo.
bgra)?hictinting
[pal
].
r:hictinting
[pal
].
b;
for (y
=0,j
=0; y
<tsizy
; y
++,j
+=xsiz
)
{
coltype
*rpptr
= &pic
[j
], tcol
;
for (x
=0; x
<tsizx
; x
++)
{
tcol.
b = cptr
[rpptr
[x
].
b];
tcol.
g = cptr
[rpptr
[x
].
g];
tcol.
r = cptr
[rpptr
[x
].
r];
if (effect
& HICTINT_GRAYSCALE
)
{
tcol.
g = tcol.
r = tcol.
b = (uint8_t)((tcol.
r * GRAYSCALE_COEFF_RED
) + (tcol.
g * GRAYSCALE_COEFF_GREEN
) +
(tcol.
b * GRAYSCALE_COEFF_BLUE
));
}
if (effect
& HICTINT_INVERT
)
{
tcol.
b = 255-tcol.
b;
tcol.
g = 255-tcol.
g;
tcol.
r = 255-tcol.
r;
}
if (effect
& HICTINT_COLORIZE
)
{
tcol.
b = min
((int32_t)(tcol.
b)*b
/64,255);
tcol.
g = min
((int32_t)(tcol.
g)*g
/64,255);
tcol.
r = min
((int32_t)(tcol.
r)*r
/64,255);
}
rpptr
[x
].
b = tcol.
b;
rpptr
[x
].
g = tcol.
g;
rpptr
[x
].
r = tcol.
r;
al
&= rpptr
[x
].
a;
}
}
if (!glinfo.
bgra)
{
for (j
=xsiz
*ysiz
-1; j
>=0; j
--)
{
swapchar
(&pic
[j
].
r, &pic
[j
].
b);
}
}
*sizx
= xsiz
;
*sizy
= ysiz
;
*bpl
= xsiz
;
*fptr
= (intptr_t)pic
;
*hasalpha
= (al
!= 255);
return 0;
}
static inline int32_t hicfxmask
(int32_t pal
)
{
return globalnoeffect
? 0 : (hictinting
[pal
].
f & HICEFFECTMASK
);
}
//Note: even though it says md2model, it works for both md2model&md3model
int32_t mdloadskin
(md2model_t
*m
, int32_t number
, int32_t pal
, int32_t surf
)
{
int32_t i
, bpl
, osizx
, osizy
, texfmt
= GL_RGBA
, intexfmt
= GL_RGBA
;
char *skinfile
, hasalpha
, fn
[BMAX_PATH
];
GLuint
*texidx
= NULL
;
mdskinmap_t
*sk
, *skzero
= NULL
;
int32_t doalloc
= 1, filh
;
int32_t gotcache
, picfillen
;
texcacheheader cachead
;
int32_t startticks
, willprint
=0;
vec2_t siz
= { 0, 0 };
if (m
->mdnum
== 2)
surf
= 0;
if ((unsigned)pal
>= (unsigned)MAXPALOOKUPS
)
return 0;
i
= -1;
for (sk
= m
->skinmap
; sk
; sk
= sk
->next
)
{
if (sk
->palette
== pal
&& sk
->skinnum
== number
&& sk
->surfnum
== surf
)
{
skinfile
= sk
->fn
;
texidx
= &sk
->texid
[hicfxmask
(pal
)];
Bstrncpyz
(fn
, skinfile
, BMAX_PATH
);
//OSD_Printf("Using exact match skin (pal=%d,skinnum=%d,surfnum=%d) %s\n",pal,number,surf,skinfile);
break;
}
//If no match, give highest priority to number, then pal.. (Parkar's request, 02/27/2005)
else if ((sk
->palette
== 0) && (sk
->skinnum
== number
) && (sk
->surfnum
== surf
) && (i
< 5)) { i
= 5; skzero
= sk
; }
else if ((sk
->palette
== pal
) && (sk
->skinnum
== 0) && (sk
->surfnum
== surf
) && (i
< 4)) { i
= 4; skzero
= sk
; }
else if ((sk
->palette
== 0) && (sk
->skinnum
== 0) && (sk
->surfnum
== surf
) && (i
< 3)) { i
= 3; skzero
= sk
; }
else if ((sk
->palette
== 0) && (sk
->skinnum
== number
) && (i
< 2)) { i
= 2; skzero
= sk
; }
else if ((sk
->palette
== pal
) && (sk
->skinnum
== 0) && (i
< 1)) { i
= 1; skzero
= sk
; }
else if ((sk
->palette
== 0) && (sk
->skinnum
== 0) && (i
< 0)) { i
= 0; skzero
= sk
; }
}
if (!sk
)
{
if (pal
>= (MAXPALOOKUPS
- RESERVEDPALS
))
return (0);
if (skzero
)
{
skinfile
= skzero
->fn
;
texidx
= &skzero
->texid
[hicfxmask
(pal
)];
Bstrncpyz
(fn
, skinfile
, BMAX_PATH
);
//OSD_Printf("Using def skin 0,0 as fallback, pal=%d\n", pal);
}
else
return 0;
#if 0
{
// fall back to the model-defined texture
if ((unsigned)number
>= (unsigned)m
->numskins
)
number
= 0;
// m->skinfn is undefined when md3model_t is cast to md2model_t --> crash
skinfile
= m
->skinfn
+ number
*64;
texidx
= &m
->texid
[number
*(HICEFFECTMASK
+1) + hicfxmask
(pal
)];
Bstrncpyz
(fn
, m
->basepath
, BMAX_PATH
);
if ((Bstrlen
(fn
) + Bstrlen
(skinfile
)) < BMAX_PATH
)
Bstrcat
(fn
,skinfile
);
//OSD_Printf("Using MD2/MD3 skin (%d) %s, pal=%d\n",number,skinfile,pal);
}
#endif
}
if (!skinfile
[0])
return 0;
if (*texidx
)
return *texidx
;
// possibly fetch an already loaded multitexture :_)
if (pal
>= (MAXPALOOKUPS
- RESERVEDPALS
))
for (i
=0; i
<nextmodelid
; i
++)
for (skzero
= ((md2model_t
*)models
[i
])->skinmap
; skzero
; skzero
= skzero
->next
)
if (!Bstrcasecmp
(skzero
->fn
, sk
->fn
) && skzero
->texid
[hicfxmask
(pal
)])
{
int32_t f
= hicfxmask
(pal
);
sk
->texid
[f
] = skzero
->texid
[f
];
return sk
->texid
[f
];
}
*texidx
= 0;
if ((filh
= kopen4load
(fn
, 0)) < 0)
{
OSD_Printf
("Skin \"%s\" not found.\n",fn
);
skinfile
[0] = 0;
return 0;
}
picfillen
= kfilelength
(filh
);
kclose
(filh
); // FIXME: shouldn't have to do this. bug in cache1d.c
startticks
= getticks
();
gotcache
= texcache_readtexheader
(fn
, picfillen
, pal
<<8, hicfxmask
(pal
), &cachead
, 1);
if (gotcache
&& !texcache_loadskin
(&cachead
, &doalloc
, texidx
, &siz.
x, &siz.
y))
{
osizx
= cachead.
xdim;
osizy
= cachead.
ydim;
hasalpha
= (cachead.
flags & CACHEAD_HASALPHA
) ? 1 : 0;
if (pal
< (MAXPALOOKUPS
- RESERVEDPALS
))
m
->usesalpha
= hasalpha
;
//kclose(filh); // FIXME: uncomment when cache1d.c is fixed
}
else
{
int32_t ret
;
intptr_t fptr
=0;
gotcache
= 0; // the compressed version will be saved to disk
if ((filh
= kopen4load
(fn
, 0)) < 0)
return -1;
ret
= daskinloader
(filh
,&fptr
,&bpl
,&siz.
x,&siz.
y,&osizx
,&osizy
,&hasalpha
,pal
,hicfxmask
(pal
));
if (ret
)
{
kclose
(filh
);
OSD_Printf
("Failed loading skin file \"%s\": error %d\n", fn
, ret
);
if (ret
==-1)
QuitOnFatalError
("OUT OF MEMORY in daskinloader!");
skinfile
[0] = 0;
return(0);
}
else kclose
(filh
);
willprint
= 1;
if (pal
< (MAXPALOOKUPS
- RESERVEDPALS
))
m
->usesalpha
= hasalpha
;
if ((doalloc
&3)==1)
bglGenTextures
(1, texidx
);
bglBindTexture
(GL_TEXTURE_2D
, *texidx
);
//gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,xsiz,ysiz,GL_BGRA_EXT,GL_UNSIGNED_BYTE,(char *)fptr);
if (glinfo.
texcompr && glusetexcompr
)
intexfmt
= hasalpha
? GL_COMPRESSED_RGBA_ARB
: GL_COMPRESSED_RGB_ARB
;
else if (!hasalpha
)
intexfmt
= GL_RGB
;
if (glinfo.
bgra)
texfmt
= GL_BGRA
;
uploadtexture
((doalloc
&1), siz
, intexfmt
, texfmt
, (coltype
*)fptr
, siz
, DAMETH_HI
);
Bfree
((void *)fptr
);
}
if (!m
->skinloaded
)
{
if (siz.
x != osizx
|| siz.
y != osizy
)
{
float fx
, fy
;
fx
= ((float)osizx
)/((float)siz.
x);
fy
= ((float)osizy
)/((float)siz.
y);
if (m
->mdnum
== 2)
{
int32_t *lptr
;
for (lptr
=m
->glcmds
; (i
=*lptr
++);)
for (i
=labs(i
); i
>0; i
--,lptr
+=3)
{
((float *)lptr
)[0] *= fx
;
((float *)lptr
)[1] *= fy
;
}
}
else if (m
->mdnum
== 3)
{
md3model_t
*m3
= (md3model_t
*)m
;
md3surf_t
*s
;
int32_t surfi
;
for (surfi
=0; surfi
<m3
->head.
numsurfs; surfi
++)
{
s
= &m3
->head.
surfs[surfi
];
for (i
=s
->numverts
-1; i
>=0; i
--)
{
s
->uv
[i
].
u *= fx
;
s
->uv
[i
].
v *= fy
;
}
}
}
}
m
->skinloaded
= 1+number
;
}
bglTexParameteri
(GL_TEXTURE_2D
,GL_TEXTURE_MAG_FILTER
,glfiltermodes
[gltexfiltermode
].
mag);
bglTexParameteri
(GL_TEXTURE_2D
,GL_TEXTURE_MIN_FILTER
,glfiltermodes
[gltexfiltermode
].
min);
#ifndef EDUKE32_GLES
if (glinfo.
maxanisotropy > 1.0)
bglTexParameteri
(GL_TEXTURE_2D
,GL_TEXTURE_MAX_ANISOTROPY_EXT
,glanisotropy
);
#endif
bglTexParameteri
(GL_TEXTURE_2D
,GL_TEXTURE_WRAP_S
,GL_REPEAT
);
bglTexParameteri
(GL_TEXTURE_2D
,GL_TEXTURE_WRAP_T
,GL_REPEAT
);
if (glinfo.
texcompr && glusetexcompr
&& glusetexcache
)
if (!gotcache
)
{
const int32_t nonpow2
= check_nonpow2
(siz.
x) || check_nonpow2
(siz.
y);
// save off the compressed version
cachead.
quality = r_downsize
;
cachead.
xdim = osizx
>>cachead.
quality;
cachead.
ydim = osizy
>>cachead.
quality;
cachead.
flags = nonpow2
*CACHEAD_NONPOW2
| (hasalpha
? CACHEAD_HASALPHA
: 0);
/// OSD_Printf("Caching \"%s\"\n",fn);
texcache_writetex
(fn
, picfillen
, pal
<<8, hicfxmask
(pal
), &cachead
);
if (willprint
)
{
int32_t etime
= getticks
()-startticks
;
if (etime
>=MIN_CACHETIME_PRINT
)
OSD_Printf
("Load skin: p%d-e%d \"%s\"... cached... %d ms\n", pal
, hicfxmask
(pal
), fn
, etime
);
willprint
= 0;
}
else
OSD_Printf
("Cached skin \"%s\"\n", fn
);
}
if (willprint
)
{
int32_t etime
= getticks
()-startticks
;
if (etime
>=MIN_CACHETIME_PRINT
)
OSD_Printf
("Load skin: p%d-e%d \"%s\"... %d ms\n", pal
, hicfxmask
(pal
), fn
, etime
);
}
return(*texidx
);
}
//Note: even though it says md2model, it works for both md2model&md3model
void updateanimation
(md2model_t
*m
, const tspritetype
*tspr
, uint8_t lpal
)
{
const mdanim_t
*anim
;
int32_t i
, j
, k
;
int32_t fps
;
int32_t tile
, smoothdurationp
;
spritesmooth_t
*smooth
;
spriteext_t
*sprext
;
if (m
->numframes
< 2)
{
m
->interpol
= 0;
return;
}
tile
= Ptile2tile
(tspr
->picnum
,lpal
);
m
->cframe
= m
->nframe
= tile2model
[tile
].
framenum;
#ifdef DEBUGGINGAIDS
if (m
->cframe
>= m
->numframes
)
OSD_Printf
("1: c > n\n");
#endif
smoothdurationp
= (r_animsmoothing
&& (tile2model
[tile
].
smoothduration != 0));
smooth
= ((unsigned)tspr
->owner
< MAXSPRITES
+MAXUNIQHUDID
) ? &spritesmooth
[tspr
->owner
] : NULL
;
sprext
= ((unsigned)tspr
->owner
< MAXSPRITES
+MAXUNIQHUDID
) ? &spriteext
[tspr
->owner
] : NULL
;
for (anim
= m
->animations
; anim
&& anim
->startframe
!= m
->cframe
; anim
= anim
->next
)
{
/* do nothing */;
}
if (!anim
)
{
if (!smoothdurationp
|| ((smooth
->mdoldframe
== m
->cframe
) && (smooth
->mdcurframe
== m
->cframe
)))
{
m
->interpol
= 0;
return;
}
// assert(smoothdurationp && ((smooth->mdoldframe != m->cframe) || (smooth->mdcurframe != m->cframe)))
if (smooth
->mdoldframe
!= m
->cframe
)
{
if (smooth
->mdsmooth
== 0)
{
sprext
->mdanimtims
= mdtims
;
m
->interpol
= 0;
smooth
->mdsmooth
= 1;
smooth
->mdcurframe
= m
->cframe
;
}
if (smooth
->mdcurframe
!= m
->cframe
)
{
sprext
->mdanimtims
= mdtims
;
m
->interpol
= 0;
smooth
->mdsmooth
= 1;
smooth
->mdoldframe
= smooth
->mdcurframe
;
smooth
->mdcurframe
= m
->cframe
;
}
}
else // if (smooth->mdcurframe != m->cframe)
{
sprext
->mdanimtims
= mdtims
;
m
->interpol
= 0;
smooth
->mdsmooth
= 1;
smooth
->mdoldframe
= smooth
->mdcurframe
;
smooth
->mdcurframe
= m
->cframe
;
}
}
else if (/* anim && */ sprext
->mdanimcur
!= anim
->startframe
)
{
//if (sprext->flags & SPREXT_NOMDANIM) OSD_Printf("SPREXT_NOMDANIM\n");
//OSD_Printf("smooth launched ! oldanim %i new anim %i\n", sprext->mdanimcur, anim->startframe);
sprext
->mdanimcur
= (int16_t)anim
->startframe
;
sprext
->mdanimtims
= mdtims
;
m
->interpol
= 0;
if (!smoothdurationp
)
{
m
->cframe
= m
->nframe
= anim
->startframe
;
#ifdef DEBUGGINGAIDS
if (m
->cframe
>= m
->numframes
)
OSD_Printf
("2: c > n\n");
#endif
return;
}
m
->nframe
= anim
->startframe
;
m
->cframe
= smooth
->mdoldframe
;
#ifdef DEBUGGINGAIDS
if (m
->cframe
>= m
->numframes
)
OSD_Printf
("3: c > n\n");
#endif
smooth
->mdsmooth
= 1;
return;
}
fps
= smooth
->mdsmooth
? Blrintf
((1.0f / (float) (tile2model
[tile
].
smoothduration)) * 66.
f) : anim
->fpssc
;
i
= (mdtims
- sprext
->mdanimtims
)*((fps
*timerticspersec
)/120);
if (smooth
->mdsmooth
)
j
= 65536;
else
j
= ((anim
->endframe
+1-anim
->startframe
)<<16);
// XXX: Just in case you play the game for a VERY long time...
if (i
< 0) { i
= 0; sprext
->mdanimtims
= mdtims
; }
//compare with j*2 instead of j to ensure i stays > j-65536 for MDANIM_ONESHOT
if (anim
&& (i
>= j
+j
) && (fps
) && !mdpause
) //Keep mdanimtims close to mdtims to avoid the use of MOD
sprext
->mdanimtims
+= j
/((fps
*timerticspersec
)/120);
k
= i
;
if (anim
&& (anim
->flags
&MDANIM_ONESHOT
))
{ if (i
> j
-65536) i
= j
-65536; }
else { if (i
>= j
) { i
-= j
; if (i
>= j
) i
%= j
; } }
if (r_animsmoothing
&& smooth
->mdsmooth
)
{
m
->nframe
= anim
? anim
->startframe
: smooth
->mdcurframe
;
m
->cframe
= smooth
->mdoldframe
;
#ifdef DEBUGGINGAIDS
if (m
->cframe
>= m
->numframes
)
OSD_Printf
("4: c > n\n");
#endif
//OSD_Printf("smoothing... cframe %i nframe %i\n", m->cframe, m->nframe);
if (k
> 65535)
{
sprext
->mdanimtims
= mdtims
;
m
->interpol
= 0;
smooth
->mdsmooth
= 0;
m
->cframe
= m
->nframe
; // = anim ? anim->startframe : smooth->mdcurframe;
#ifdef DEBUGGINGAIDS
if (m
->cframe
>= m
->numframes
)
OSD_Printf
("5: c > n\n");
#endif
smooth
->mdoldframe
= m
->cframe
;
//OSD_Printf("smooth stopped !\n");
return;
}
}
else
{
m
->cframe
= (i
>>16)+anim
->startframe
;
#ifdef DEBUGGINGAIDS
if (m
->cframe
>= m
->numframes
)
OSD_Printf
("6: c > n\n");
#endif
m
->nframe
= m
->cframe
+1;
if (m
->nframe
> anim
->endframe
) // VERIFY: (!(r_animsmoothing && smooth->mdsmooth)) implies (anim!=NULL) ?
m
->nframe
= anim
->startframe
;
smooth
->mdoldframe
= m
->cframe
;
//OSD_Printf("not smoothing... cframe %i nframe %i\n", m->cframe, m->nframe);
}
m
->interpol
= ((float)(i
&65535))/65536.
f;
//OSD_Printf("interpol %f\n", m->interpol);
}
// VBO generation and allocation
static void mdloadvbos
(md3model_t
*m
)
{
int32_t i
;
m
->vbos
= (GLuint
*)Xmalloc
(m
->head.
numsurfs * sizeof(GLuint
));
bglGenBuffersARB
(m
->head.
numsurfs, m
->vbos
);
i
= 0;
while (i
< m
->head.
numsurfs)
{
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, m
->vbos
[i
]);
bglBufferDataARB
(GL_ARRAY_BUFFER_ARB
, m
->head.
surfs[i
].
numverts * sizeof(md3uv_t
), m
->head.
surfs[i
].
uv, GL_STATIC_DRAW_ARB
);
i
++;
}
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, 0);
}
//--------------------------------------- MD2 LIBRARY BEGINS ---------------------------------------
static md2model_t
*md2load
(int32_t fil
, const char *filnam
)
{
md2model_t
*m
;
md3model_t
*m3
;
md3surf_t
*s
;
md2frame_t
*f
;
md2head_t head
;
char st
[BMAX_PATH
];
int32_t i
, j
, k
;
int32_t ournumskins
, ournumglcmds
;
m
= (md2model_t
*)Xcalloc
(1,sizeof(md2model_t
));
m
->mdnum
= 2; m
->scale
= .01f;
kread
(fil
,(char *)&head
,sizeof(md2head_t
));
#if B_BIG_ENDIAN != 0
head.
id = B_LITTLE32
(head.
id); head.
vers = B_LITTLE32
(head.
vers);
head.
skinxsiz = B_LITTLE32
(head.
skinxsiz); head.
skinysiz = B_LITTLE32
(head.
skinysiz);
head.
framebytes = B_LITTLE32
(head.
framebytes); head.
numskins = B_LITTLE32
(head.
numskins);
head.
numverts = B_LITTLE32
(head.
numverts); head.
numuv = B_LITTLE32
(head.
numuv);
head.
numtris = B_LITTLE32
(head.
numtris); head.
numglcmds = B_LITTLE32
(head.
numglcmds);
head.
numframes = B_LITTLE32
(head.
numframes); head.
ofsskins = B_LITTLE32
(head.
ofsskins);
head.
ofsuv = B_LITTLE32
(head.
ofsuv); head.
ofstris = B_LITTLE32
(head.
ofstris);
head.
ofsframes = B_LITTLE32
(head.
ofsframes); head.
ofsglcmds = B_LITTLE32
(head.
ofsglcmds);
head.
ofseof = B_LITTLE32
(head.
ofseof);
#endif
if ((head.
id != IDP2_MAGIC
) || (head.
vers != 8)) { Bfree
(m
); return(0); } //"IDP2"
ournumskins
= head.
numskins ? head.
numskins : 1;
ournumglcmds
= head.
numglcmds ? head.
numglcmds : 1;
m
->numskins
= head.
numskins;
m
->numframes
= head.
numframes;
m
->numverts
= head.
numverts;
m
->numglcmds
= head.
numglcmds;
m
->framebytes
= head.
framebytes;
m
->frames
= (char *)Xmalloc
(m
->numframes
*m
->framebytes
);
m
->glcmds
= (int32_t *)Xmalloc
(ournumglcmds
*sizeof(int32_t));
m
->tris
= (md2tri_t
*)Xmalloc
(head.
numtris*sizeof(md2tri_t
));
m
->uv
= (md2uv_t
*)Xmalloc
(head.
numuv*sizeof(md2uv_t
));
klseek
(fil
,head.
ofsframes,SEEK_SET
);
if (kread
(fil
,(char *)m
->frames
,m
->numframes
*m
->framebytes
) != m
->numframes
*m
->framebytes
)
{ Bfree
(m
->uv
); Bfree
(m
->tris
); Bfree
(m
->glcmds
); Bfree
(m
->frames
); Bfree
(m
); return(0); }
if (m
->numglcmds
> 0)
{
klseek
(fil
,head.
ofsglcmds,SEEK_SET
);
if (kread
(fil
,(char *)m
->glcmds
,m
->numglcmds
*sizeof(int32_t)) != (int32_t)(m
->numglcmds
*sizeof(int32_t)))
{ Bfree
(m
->uv
); Bfree
(m
->tris
); Bfree
(m
->glcmds
); Bfree
(m
->frames
); Bfree
(m
); return(0); }
}
klseek
(fil
,head.
ofstris,SEEK_SET
);
if (kread
(fil
,(char *)m
->tris
,head.
numtris*sizeof(md2tri_t
)) != (int32_t)(head.
numtris*sizeof(md2tri_t
)))
{ Bfree
(m
->uv
); Bfree
(m
->tris
); Bfree
(m
->glcmds
); Bfree
(m
->frames
); Bfree
(m
); return(0); }
klseek
(fil
,head.
ofsuv,SEEK_SET
);
if (kread
(fil
,(char *)m
->uv
,head.
numuv*sizeof(md2uv_t
)) != (int32_t)(head.
numuv*sizeof(md2uv_t
)))
{ Bfree
(m
->uv
); Bfree
(m
->tris
); Bfree
(m
->glcmds
); Bfree
(m
->frames
); Bfree
(m
); return(0); }
#if B_BIG_ENDIAN != 0
{
char *f
= (char *)m
->frames
;
int32_t *l
,j
;
md2frame_t
*fr
;
for (i
= m
->numframes
-1; i
>=0; i
--)
{
fr
= (md2frame_t
*)f
;
l
= (int32_t *)&fr
->mul
;
for (j
=5; j
>=0; j
--) l
[j
] = B_LITTLE32
(l
[j
]);
f
+= m
->framebytes
;
}
for (i
= m
->numglcmds
-1; i
>=0; i
--)
{
m
->glcmds
[i
] = B_LITTLE32
(m
->glcmds
[i
]);
}
for (i
= head.
numtris-1; i
>=0; i
--)
{
m
->tris
[i
].
v[0] = B_LITTLE16
(m
->tris
[i
].
v[0]);
m
->tris
[i
].
v[1] = B_LITTLE16
(m
->tris
[i
].
v[1]);
m
->tris
[i
].
v[2] = B_LITTLE16
(m
->tris
[i
].
v[2]);
m
->tris
[i
].
u[0] = B_LITTLE16
(m
->tris
[i
].
u[0]);
m
->tris
[i
].
u[1] = B_LITTLE16
(m
->tris
[i
].
u[1]);
m
->tris
[i
].
u[2] = B_LITTLE16
(m
->tris
[i
].
u[2]);
}
for (i
= head.
numuv-1; i
>=0; i
--)
{
m
->uv
[i
].
u = B_LITTLE16
(m
->uv
[i
].
u);
m
->uv
[i
].
v = B_LITTLE16
(m
->uv
[i
].
v);
}
}
#endif
Bstrcpy
(st
,filnam
);
for (i
=strlen(st
)-1; i
>0; i
--)
if ((st
[i
] == '/') || (st
[i
] == '\\')) { i
++; break; }
if (i
<0) i
=0;
st
[i
] = 0;
m
->basepath
= (char *)Xmalloc
(i
+1);
Bstrcpy
(m
->basepath
, st
);
m
->skinfn
= (char *)Xmalloc
(ournumskins
*64);
if (m
->numskins
> 0)
{
klseek
(fil
,head.
ofsskins,SEEK_SET
);
if (kread
(fil
,m
->skinfn
,64*m
->numskins
) != 64*m
->numskins
)
{ Bfree
(m
->glcmds
); Bfree
(m
->frames
); Bfree
(m
); return(0); }
}
m
->texid
= (GLuint
*)Xcalloc
(ournumskins
, sizeof(GLuint
) * (HICEFFECTMASK
+1));
maxmodelverts
= max
(maxmodelverts
, m
->numverts
);
maxmodeltris
= max
(maxmodeltris
, head.
numtris);
//return(m);
// the MD2 is now loaded internally - let's begin the MD3 conversion process
//OSD_Printf("Beginning md3 conversion.\n");
m3
= (md3model_t
*)Xcalloc
(1, sizeof(md3model_t
));
m3
->mdnum
= 3; m3
->texid
= 0; m3
->scale
= m
->scale
;
m3
->head.
id = IDP3_MAGIC
; m3
->head.
vers = 15;
m3
->head.
flags = 0;
m3
->head.
numframes = m
->numframes
;
m3
->head.
numtags = 0; m3
->head.
numsurfs = 1;
m3
->head.
numskins = 0;
m3
->numskins
= m3
->head.
numskins;
m3
->numframes
= m3
->head.
numframes;
m3
->head.
frames = (md3frame_t
*)Xcalloc
(m3
->head.
numframes, sizeof(md3frame_t
));
m3
->muladdframes
= (vec3f_t
*)Xcalloc
(m
->numframes
* 2, sizeof(vec3f_t
));
f
= (md2frame_t
*)(m
->frames
);
// frames converting
i
= 0;
while (i
< m
->numframes
)
{
f
= (md2frame_t
*)&m
->frames
[i
*m
->framebytes
];
Bstrcpy
(m3
->head.
frames[i
].
nam, f
->name
);
//OSD_Printf("Copied frame %s.\n", m3->head.frames[i].nam);
m3
->muladdframes
[i
*2] = f
->mul
;
m3
->muladdframes
[i
*2+1] = f
->add
;
i
++;
}
m3
->head.
tags = NULL
;
m3
->head.
surfs = (md3surf_t
*)Xcalloc
(1, sizeof(md3surf_t
));
s
= m3
->head.
surfs;
// model converting
s
->id
= IDP3_MAGIC
; s
->flags
= 0;
s
->numframes
= m
->numframes
; s
->numshaders
= 0;
s
->numtris
= head.
numtris;
s
->numverts
= head.
numtris * 3; // oh man talk about memory effectiveness :((((
// MD2 is actually more accurate than MD3 in term of uv-mapping, because each triangle has a triangle counterpart on the UV-map.
// In MD3, each vertex unique UV coordinates, meaning that you have to duplicate vertices if you need non-seamless UV-mapping.
maxmodelverts
= max
(maxmodelverts
, s
->numverts
);
Bstrcpy
(s
->nam
, "Dummy surface from MD2");
s
->shaders
= NULL
;
s
->tris
= (md3tri_t
*)Xcalloc
(head.
numtris, sizeof(md3tri_t
));
s
->uv
= (md3uv_t
*)Xcalloc
(s
->numverts
, sizeof(md3uv_t
));
s
->xyzn
= (md3xyzn_t
*)Xcalloc
(s
->numverts
* m
->numframes
, sizeof(md3xyzn_t
));
//memoryusage += (s->numverts * m->numframes * sizeof(md3xyzn_t));
//OSD_Printf("Current model geometry memory usage : %i.\n", memoryusage);
//OSD_Printf("Number of frames : %i\n", m->numframes);
//OSD_Printf("Number of triangles : %i\n", head.numtris);
//OSD_Printf("Number of vertices : %i\n", s->numverts);
// triangle converting
i
= 0;
while (i
< head.
numtris)
{
j
= 0;
//OSD_Printf("Triangle : %i\n", i);
while (j
< 3)
{
// triangle vertex indexes
s
->tris
[i
].
i[j
] = i
*3 + j
;
// uv coords
s
->uv
[i
*3+j
].
u = (float)(m
->uv
[m
->tris
[i
].
u[j
]].
u) / (float)(head.
skinxsiz);
s
->uv
[i
*3+j
].
v = (float)(m
->uv
[m
->tris
[i
].
u[j
]].
v) / (float)(head.
skinysiz);
// vertices for each frame
k
= 0;
while (k
< m
->numframes
)
{
f
= (md2frame_t
*)&m
->frames
[k
*m
->framebytes
];
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);
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);
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);
k
++;
}
j
++;
}
//OSD_Printf("End triangle.\n");
i
++;
}
//OSD_Printf("Finished md3 conversion.\n");
{
mdskinmap_t
*sk
;
sk
= (mdskinmap_t
*)Xcalloc
(1,sizeof(mdskinmap_t
));
sk
->palette
= 0;
sk
->skinnum
= 0;
sk
->surfnum
= 0;
if (m
->numskins
> 0)
{
sk
->fn
= (char *)Xmalloc
(strlen(m
->basepath
)+strlen(m
->skinfn
)+1);
Bstrcpy
(sk
->fn
, m
->basepath
);
Bstrcat
(sk
->fn
, m
->skinfn
);
}
m3
->skinmap
= sk
;
}
m3
->indexes
= (uint16_t *)Xmalloc
(sizeof(uint16_t) * s
->numtris
);
m3
->vindexes
= (uint16_t *)Xmalloc
(sizeof(uint16_t) * s
->numtris
* 3);
m3
->maxdepths
= (float *)Xmalloc
(sizeof(float) * s
->numtris
);
m3
->vbos
= NULL
;
// die MD2 ! DIE !
Bfree
(m
->texid
); Bfree
(m
->skinfn
); Bfree
(m
->basepath
); Bfree
(m
->uv
); Bfree
(m
->tris
); Bfree
(m
->glcmds
); Bfree
(m
->frames
); Bfree
(m
);
return((md2model_t
*)m3
);
}
//---------------------------------------- MD2 LIBRARY ENDS ----------------------------------------
// DICHOTOMIC RECURSIVE SORTING - USED BY MD3DRAW
int32_t partition
(uint16_t *indexes
, float *depths
, int32_t f
, int32_t l
)
{
int32_t up
= f
, down
= l
;
float piv
= depths
[f
];
uint16_t piv2
= indexes
[f
];
do
{
while ((depths
[up
] <= piv
) && (up
< l
))
up
++;
while ((depths
[down
] > piv
) && (down
> f
))
down
--;
if (up
< down
)
{
swapfloat
(&depths
[up
], &depths
[down
]);
swapshort
(&indexes
[up
], &indexes
[down
]);
}
}
while (down
> up
);
depths
[f
] = depths
[down
], depths
[down
] = piv
;
indexes
[f
] = indexes
[down
], indexes
[down
] = piv2
;
return down
;
}
static inline void quicksort
(uint16_t *indexes
, float *depths
, int32_t first
, int32_t last
)
{
int32_t pivIndex
;
if (first
>= last
) return;
pivIndex
= partition
(indexes
, depths
, first
, last
);
if (first
< (pivIndex
-1)) quicksort
(indexes
, depths
, first
, (pivIndex
-1));
if ((pivIndex
+1) >= last
) return;
quicksort
(indexes
, depths
, (pivIndex
+1), last
);
}
// END OF QUICKSORT LIB
//--------------------------------------- MD3 LIBRARY BEGINS ---------------------------------------
static md3model_t
*md3load
(int32_t fil
)
{
int32_t i
, surfi
, ofsurf
, offs
[4], leng
[4];
int32_t maxtrispersurf
;
md3model_t
*m
;
md3surf_t
*s
;
m
= (md3model_t
*)Xcalloc
(1,sizeof(md3model_t
));
m
->mdnum
= 3; m
->texid
= 0; m
->scale
= .01f;
m
->muladdframes
= NULL
;
kread
(fil
,&m
->head
,SIZEOF_MD3HEAD_T
);
#if B_BIG_ENDIAN != 0
m
->head.
id = B_LITTLE32
(m
->head.
id); m
->head.
vers = B_LITTLE32
(m
->head.
vers);
m
->head.
flags = B_LITTLE32
(m
->head.
flags); m
->head.
numframes = B_LITTLE32
(m
->head.
numframes);
m
->head.
numtags = B_LITTLE32
(m
->head.
numtags); m
->head.
numsurfs = B_LITTLE32
(m
->head.
numsurfs);
m
->head.
numskins = B_LITTLE32
(m
->head.
numskins); m
->head.
ofsframes = B_LITTLE32
(m
->head.
ofsframes);
m
->head.
ofstags = B_LITTLE32
(m
->head.
ofstags); m
->head.
ofssurfs = B_LITTLE32
(m
->head.
ofssurfs);
m
->head.
eof = B_LITTLE32
(m
->head.
eof);
#endif
if ((m
->head.
id != IDP3_MAGIC
) && (m
->head.
vers != 15)) { Bfree
(m
); return(0); } //"IDP3"
m
->numskins
= m
->head.
numskins; //<- dead code?
m
->numframes
= m
->head.
numframes;
ofsurf
= m
->head.
ofssurfs;
klseek
(fil
,m
->head.
ofsframes,SEEK_SET
); i
= m
->head.
numframes*sizeof(md3frame_t
);
m
->head.
frames = (md3frame_t
*)Xmalloc
(i
);
kread
(fil
,m
->head.
frames,i
);
if (m
->head.
numtags == 0) m
->head.
tags = NULL
;
else
{
klseek
(fil
,m
->head.
ofstags,SEEK_SET
); i
= m
->head.
numtags*sizeof(md3tag_t
);
m
->head.
tags = (md3tag_t
*)Xmalloc
(i
);
kread
(fil
,m
->head.
tags,i
);
}
klseek
(fil
,m
->head.
ofssurfs,SEEK_SET
);
m
->head.
surfs = (md3surf_t
*)Xcalloc
(m
->head.
numsurfs, sizeof(md3surf_t
));
// NOTE: We assume that NULL is represented by all-zeros.
// surfs[0].geometry is for POLYMER_MD_PROCESS_CHECK (else: crashes).
// surfs[i].geometry is for FREE_SURFS_GEOMETRY.
Bassert
(m
->head.
surfs[0].
geometry == NULL
);
#if B_BIG_ENDIAN != 0
{
int32_t j
, *l
;
for (i
= m
->head.
numframes-1; i
>=0; i
--)
{
l
= (int32_t *)&m
->head.
frames[i
].
min;
for (j
=3+3+3+1-1; j
>=0; j
--) l
[j
] = B_LITTLE32
(l
[j
]);
}
for (i
= m
->head.
numtags-1; i
>=0; i
--)
{
l
= (int32_t *)&m
->head.
tags[i
].
p;
for (j
=3+3+3+3-1; j
>=0; j
--) l
[j
] = B_LITTLE32
(l
[j
]);
}
}
#endif
maxtrispersurf
= 0;
for (surfi
=0; surfi
<m
->head.
numsurfs; surfi
++)
{
s
= &m
->head.
surfs[surfi
];
klseek
(fil
,ofsurf
,SEEK_SET
); kread
(fil
,s
,SIZEOF_MD3SURF_T
);
#if B_BIG_ENDIAN != 0
{
int32_t j
, *l
;
s
->id
= B_LITTLE32
(s
->id
);
l
= (int32_t *)&s
->flags
;
for (j
=1+1+1+1+1+1+1+1+1+1-1; j
>=0; j
--) l
[j
] = B_LITTLE32
(l
[j
]);
}
#endif
offs
[0] = ofsurf
+s
->ofstris
;
offs
[1] = ofsurf
+s
->ofsshaders
;
offs
[2] = ofsurf
+s
->ofsuv
;
offs
[3] = ofsurf
+s
->ofsxyzn
;
leng
[0] = s
->numtris
*sizeof(md3tri_t
);
leng
[1] = s
->numshaders
*sizeof(md3shader_t
);
leng
[2] = s
->numverts
*sizeof(md3uv_t
);
leng
[3] = s
->numframes
*s
->numverts
*sizeof(md3xyzn_t
);
//memoryusage += (s->numverts * s->numframes * sizeof(md3xyzn_t));
//OSD_Printf("Current model geometry memory usage : %i.\n", memoryusage);
s
->tris
= (md3tri_t
*)Xmalloc
((leng
[0] + leng
[1]) + (leng
[2] + leng
[3]));
s
->shaders
= (md3shader_t
*)(((intptr_t)s
->tris
)+leng
[0]);
s
->uv
= (md3uv_t
*)(((intptr_t)s
->shaders
)+leng
[1]);
s
->xyzn
= (md3xyzn_t
*)(((intptr_t)s
->uv
)+leng
[2]);
klseek
(fil
,offs
[0],SEEK_SET
); kread
(fil
,s
->tris
,leng
[0]);
klseek
(fil
,offs
[1],SEEK_SET
); kread
(fil
,s
->shaders
,leng
[1]);
klseek
(fil
,offs
[2],SEEK_SET
); kread
(fil
,s
->uv
,leng
[2]);
klseek
(fil
,offs
[3],SEEK_SET
); kread
(fil
,s
->xyzn
,leng
[3]);
#if B_BIG_ENDIAN != 0
{
int32_t j
, *l
;
for (i
=s
->numtris
-1; i
>=0; i
--)
{
for (j
=2; j
>=0; j
--) s
->tris
[i
].
i[j
] = B_LITTLE32
(s
->tris
[i
].
i[j
]);
}
for (i
=s
->numshaders
-1; i
>=0; i
--)
{
s
->shaders
[i
].
i = B_LITTLE32
(s
->shaders
[i
].
i);
}
for (i
=s
->numverts
-1; i
>=0; i
--)
{
l
= (int32_t *)&s
->uv
[i
].
u;
l
[0] = B_LITTLE32
(l
[0]);
l
[1] = B_LITTLE32
(l
[1]);
}
for (i
=s
->numframes
*s
->numverts
-1; i
>=0; i
--)
{
s
->xyzn
[i
].
x = (int16_t)B_LITTLE16
((uint16_t)s
->xyzn
[i
].
x);
s
->xyzn
[i
].
y = (int16_t)B_LITTLE16
((uint16_t)s
->xyzn
[i
].
y);
s
->xyzn
[i
].
z = (int16_t)B_LITTLE16
((uint16_t)s
->xyzn
[i
].
z);
}
}
#endif
maxmodelverts
= max
(maxmodelverts
, s
->numverts
);
maxmodeltris
= max
(maxmodeltris
, s
->numtris
);
maxtrispersurf
= max
(maxtrispersurf
, s
->numtris
);
ofsurf
+= s
->ofsend
;
}
m
->indexes
= (uint16_t *)Xmalloc
(sizeof(uint16_t) * maxtrispersurf
);
m
->vindexes
= (uint16_t *)Xmalloc
(sizeof(uint16_t) * maxtrispersurf
* 3);
m
->maxdepths
= (float *)Xmalloc
(sizeof(float) * maxtrispersurf
);
m
->vbos
= NULL
;
return(m
);
}
static inline void invertmatrix
(float *m
, float *out
)
{
float det
;
det
= (m
[0] * (m
[4]*m
[8] - m
[5] * m
[7]))
- (m
[1] * (m
[3]*m
[8] - m
[5] * m
[6]))
+ (m
[2] * (m
[3]*m
[7] - m
[4] * m
[6]));
if (det
== 0.0f)
{
Bmemset
(out
, 0, sizeof(float) * 9);
out
[8] = out
[4] = out
[0] = 1.
f;
return;
}
det
= 1.0f / det
;
out
[0] = det
* (m
[4] * m
[8] - m
[5] * m
[7]);
out
[1] = det
* (m
[2] * m
[7] - m
[1] * m
[8]);
out
[2] = det
* (m
[1] * m
[5] - m
[2] * m
[4]);
out
[3] = det
* (m
[5] * m
[6] - m
[3] * m
[8]);
out
[4] = det
* (m
[0] * m
[8] - m
[2] * m
[6]);
out
[5] = det
* (m
[2] * m
[3] - m
[0] * m
[5]);
out
[6] = det
* (m
[3] * m
[7] - m
[1] * m
[6]);
out
[7] = det
* (m
[1] * m
[6] - m
[0] * m
[7]);
out
[8] = det
* (m
[0] * m
[4] - m
[1] * m
[3]);
}
static inline void normalize
(float *vec
)
{
float norm
;
if ((norm
= vec
[0] * vec
[0] + vec
[1] * vec
[1] + vec
[2] * vec
[2]) == 0.
f)
return;
norm
= polymost_invsqrt_approximation
(norm
);
vec
[0] *= norm
;
vec
[1] *= norm
;
vec
[2] *= norm
;
}
static void md3postload_common
(md3model_t
*m
)
{
int framei
, surfi
, verti
;
md3frame_t
*frame
;
md3xyzn_t
*frameverts
;
// apparently we can't trust loaded models bounding box/sphere information,
// so let's compute it ourselves
framei
= 0;
do // while (++framei < m->head.numframes);
{
frame
= &m
->head.
frames[framei
];
Bmemset
(&frame
->min
, 0, sizeof(vec3f_t
) * 2);
frame
->r
= 0.0f;
surfi
= 0;
do // while (++surfi < m->head.numsurfs);
{
frameverts
= &m
->head.
surfs[surfi
].
xyzn[framei
* m
->head.
surfs[surfi
].
numverts];
verti
= 0;
if (!surfi
)
{
frame
->min.
x = (float)frameverts
[0].
x;
frame
->min.
y = (float)frameverts
[0].
y;
frame
->min.
z = (float)frameverts
[0].
z;
frame
->max
= frame
->min
;
}
do // while(++verti < m->head.surfs[surfi].numverts);
{
vec3f_t f
= { (float)frameverts
[verti
].
x, (float)frameverts
[verti
].
y, (float)frameverts
[verti
].
z };
if (!verti
&& !surfi
)
continue;
frame
->min.
x = max
(frame
->min.
x, f.
x);
frame
->min.
y = max
(frame
->min.
y, f.
y);
frame
->min.
z = max
(frame
->min.
z, f.
z);
frame
->max.
x = max
(frame
->max.
x, f.
x);
frame
->max.
y = max
(frame
->max.
y, f.
y);
frame
->max.
z = max
(frame
->max.
z, f.
z);
}
while(++verti
< m
->head.
surfs[surfi
].
numverts);
}
while (++surfi
< m
->head.
numsurfs);
frame
->cen.
x = (frame
->min.
x + frame
->max.
x) * .5f;
frame
->cen.
y = (frame
->min.
y + frame
->max.
y) * .5f;
frame
->cen.
z = (frame
->min.
z + frame
->max.
z) * .5f;
surfi
= 0;
do // while (++surfi < m->head.numsurfs);
{
float vec1
[4];
frameverts
= &m
->head.
surfs[surfi
].
xyzn[framei
* m
->head.
surfs[surfi
].
numverts];
verti
= 0;
do // while (++verti < m->head.surfs[surfi].numverts);
{
vec1
[0] = frameverts
[verti
].
x - frame
->cen.
x;
vec1
[1] = frameverts
[verti
].
y - frame
->cen.
y;
vec1
[2] = frameverts
[verti
].
z - frame
->cen.
z;
vec1
[3] = (vec1
[0] * vec1
[0]) + (vec1
[1] * vec1
[1]) + (vec1
[2] * vec1
[2]);
frame
->r
= max
(vec1
[3], frame
->r
);
}
while (++verti
< m
->head.
surfs[surfi
].
numverts);
}
while (++surfi
< m
->head.
numsurfs);
frame
->r
= Bsqrtf
(frame
->r
);
}
while (++framei
< m
->head.
numframes);
}
#ifdef POLYMER
// pre-check success of conversion since it must not fail later.
// keep in sync with md3postload_polymer!
static int md3postload_polymer_check
(md3model_t
*m
)
{
uint32_t surfi
, trii
;
md3surf_t
*s
;
surfi
= 0;
do
{
s
= &m
->head.
surfs[surfi
];
trii
= 0;
do
{
// let the vertices know they're being referenced by a triangle
if ((unsigned)s
->tris
[trii
].
i[0] >= (unsigned)s
->numverts
||
(unsigned)s
->tris
[trii
].
i[1] >= (unsigned)s
->numverts
||
(unsigned)s
->tris
[trii
].
i[2] >= (unsigned)s
->numverts
)
{
// corrupt model
OSD_Printf
("%s: Triangle index out of bounds!\n", m
->head.
nam);
return 1;
}
}
while (++trii
< (unsigned)s
->numtris
);
}
while (++surfi
< (unsigned)m
->head.
numsurfs);
return 0;
}
// Precalculated cos/sin arrays.
static float g_mdcos
[256], g_mdsin
[256];
static int32_t mdtrig_init
= 0;
static void init_mdtrig_arrays
(void)
{
int32_t i
;
static const float acc
= ((2.
f * (float)PI
) * (1.
f/255.
f));
float ang
= 0.
f;
for (i
=0; i
<256; i
++)
{
g_mdcos
[i
] = cosf
(ang
);
g_mdsin
[i
] = sinf
(ang
);
ang
+= acc
;
}
mdtrig_init
= 1;
}
#endif
int md3postload_polymer
(md3model_t
*m
)
{
#ifdef POLYMER
int framei
, surfi
, verti
, trii
, i
;
float vec1
[5], vec2
[5], mat
[9], r
;
// POLYMER_MD_PROCESS_CHECK
if (m
->head.
surfs[0].
geometry)
return -1; // already postprocessed
if (!mdtrig_init
)
init_mdtrig_arrays
();
// let's also repack the geometry to more usable formats
surfi
= 0;
do // while (++surfi < m->head.numsurfs)
{
handleevents
();
md3surf_t
*const s
= &m
->head.
surfs[surfi
];
#ifdef DEBUG_MODEL_MEM
i
= (m
->head.
numframes * s
->numverts
* sizeof(float) * 15);
if (i
> 1<<20)
initprintf
("size %d (%d fr, %d v): md %s surf %d/%d\n", i
, m
->head.
numframes, s
->numverts
,
m
->head.
nam, surfi
, m
->head.
numsurfs);
#endif
s
->geometry
= (float *)Xcalloc
(m
->head.
numframes * s
->numverts
* 15, sizeof(float));
if (s
->numverts
> tribufverts
)
{
tribuf
= (int32_t *) Xrealloc
(tribuf
, s
->numverts
* sizeof(int32_t));
Bmemset
(tribuf
, 0, s
->numverts
* sizeof(int32_t));
tribufverts
= s
->numverts
;
}
verti
= 0;
do // while (++verti < (m->head.numframes * s->numverts))
{
// normal extraction from packed spherical coordinates
// FIXME: swapping lat and lng because of npherno's compiler
uint8_t lat
= s
->xyzn
[verti
].
nlng;
uint8_t lng
= s
->xyzn
[verti
].
nlat;
uint32_t verti15
= (verti
<<4)-verti
;
s
->geometry
[verti15
+ 0] = s
->xyzn
[verti
].
x;
s
->geometry
[verti15
+ 1] = s
->xyzn
[verti
].
y;
s
->geometry
[verti15
+ 2] = s
->xyzn
[verti
].
z;
s
->geometry
[verti15
+ 3] = g_mdcos
[lat
] * g_mdsin
[lng
];
s
->geometry
[verti15
+ 4] = g_mdsin
[lat
] * g_mdsin
[lng
];
s
->geometry
[verti15
+ 5] = g_mdcos
[lng
];
}
while (++verti
< (m
->head.
numframes * s
->numverts
));
trii
= 0;
do // while (++trii < s->numtris)
{
uint32_t tris15
[3];
// let the vertices know they're being referenced by a triangle
if ((unsigned) s
->tris
[trii
].
i[0] >= (unsigned) s
->numverts
||
(unsigned) s
->tris
[trii
].
i[1] >= (unsigned) s
->numverts
||
(unsigned) s
->tris
[trii
].
i[2] >= (unsigned) s
->numverts
)
{
// corrupt model
return 0;
}
tribuf
[s
->tris
[trii
].
i[0]]++;
tribuf
[s
->tris
[trii
].
i[1]]++;
tribuf
[s
->tris
[trii
].
i[2]]++;
tris15
[0] = (s
->tris
[trii
].
i[0]<<4)-s
->tris
[trii
].
i[0];
tris15
[1] = (s
->tris
[trii
].
i[1]<<4)-s
->tris
[trii
].
i[1];
tris15
[2] = (s
->tris
[trii
].
i[2]<<4)-s
->tris
[trii
].
i[2];
framei
= 0;
do // while (++framei < m->head.numframes)
{
const uint32_t verti15
= framei
* s
->numverts
* 15;
vec1
[0] = s
->geometry
[verti15
+ tris15
[1]] - s
->geometry
[verti15
+ tris15
[0]];
vec1
[1] = s
->geometry
[verti15
+ tris15
[1] + 1] - s
->geometry
[verti15
+ tris15
[0] + 1];
vec1
[2] = s
->geometry
[verti15
+ tris15
[1] + 2] - s
->geometry
[verti15
+ tris15
[0] + 2];
vec1
[3] = s
->uv
[s
->tris
[trii
].
i[1]].
u - s
->uv
[s
->tris
[trii
].
i[0]].
u;
vec1
[4] = s
->uv
[s
->tris
[trii
].
i[1]].
v - s
->uv
[s
->tris
[trii
].
i[0]].
v;
vec2
[0] = s
->geometry
[verti15
+ tris15
[2] ] - s
->geometry
[verti15
+ tris15
[1]];
vec2
[1] = s
->geometry
[verti15
+ tris15
[2] + 1] - s
->geometry
[verti15
+ tris15
[1] + 1];
vec2
[2] = s
->geometry
[verti15
+ tris15
[2] + 2] - s
->geometry
[verti15
+ tris15
[1] + 2];
vec2
[3] = s
->uv
[s
->tris
[trii
].
i[2]].
u - s
->uv
[s
->tris
[trii
].
i[1]].
u;
vec2
[4] = s
->uv
[s
->tris
[trii
].
i[2]].
v - s
->uv
[s
->tris
[trii
].
i[1]].
v;
r
= (vec1
[3] * vec2
[4] - vec2
[3] * vec1
[4]);
if (r
!= 0.0f)
{
r
= 1.
f/r
;
// tangent
mat
[0] = (vec2
[4] * vec1
[0] - vec1
[4] * vec2
[0]) * r
;
mat
[1] = (vec2
[4] * vec1
[1] - vec1
[4] * vec2
[1]) * r
;
mat
[2] = (vec2
[4] * vec1
[2] - vec1
[4] * vec2
[2]) * r
;
normalize
(&mat
[0]);
// bitangent
mat
[3] = (vec1
[3] * vec2
[0] - vec2
[3] * vec1
[0]) * r
;
mat
[4] = (vec1
[3] * vec2
[1] - vec2
[3] * vec1
[1]) * r
;
mat
[5] = (vec1
[3] * vec2
[2] - vec2
[3] * vec1
[2]) * r
;
normalize
(&mat
[3]);
}
else Bmemset
(mat
, 0, sizeof(float) * 6);
// T and B are shared for the three vertices in that triangle
i
= 0;
do
{
const uint32_t offs
= (framei
* s
->numverts
* 15) + i
+ 6;
s
->geometry
[offs
+ tris15
[0]] += mat
[i
];
s
->geometry
[offs
+ tris15
[1]] += mat
[i
];
s
->geometry
[offs
+ tris15
[2]] += mat
[i
];
}
while (++i
< 6);
}
while (++framei
< m
->head.
numframes);
}
while (++trii
< s
->numtris
);
// now that we accumulated the TBNs, average and invert them for each vertex
verti
= (m
->head.
numframes * s
->numverts
)-1;
do // while (verti-- > 0)
{
const int32_t curnumtris
= tribuf
[verti
% s
->numverts
];
const uint32_t verti15
= (verti
<<4) - verti
;
if (curnumtris
> 0)
{
const float rfcurnumtris
= 1.
f/(float)curnumtris
;
i
= 6;
do {
s
->geometry
[verti15
+ i
] *= rfcurnumtris
;
} while (++i
< 12);
}
#ifdef DEBUG_MODEL_MEM
else if (verti
== verti
%s
->numverts
)
{
OSD_Printf
("%s: vert %d is unused\n", m
->head.
nam, verti
);
}
#endif
// copy N over
Bmemcpy
(&s
->geometry
[verti15
+ 12], &s
->geometry
[verti15
+ 3], sizeof(float) * 3);
invertmatrix
(&s
->geometry
[verti15
+ 6], mat
);
Bmemcpy
(&s
->geometry
[verti15
+ 6], mat
, sizeof(float) * 9);
}
while (verti
-- > 0);
}
while (++surfi
< m
->head.
numsurfs);
#else
UNREFERENCED_PARAMETER
(m
);
#endif
return 1;
}
void md3_vox_calcmat_common
(const tspritetype
*tspr
, const vec3f_t
*a0
, float f
, float mat
[16])
{
float g
;
float k0
, k1
, k2
, k3
, k4
, k5
, k6
, k7
;
k0
= ((float)(tspr
->x
-globalposx
))*f
*(1.
f/1024.
f);
k1
= ((float)(tspr
->y
-globalposy
))*f
*(1.
f/1024.
f);
f
= gcosang2
*gshang
;
g
= gsinang2
*gshang
;
k4
= (float)sintable
[(tspr
->ang
+spriteext
[tspr
->owner
].
angoff+1024)&2047] * (1.
f/16384.
f);
k5
= (float)sintable
[(tspr
->ang
+spriteext
[tspr
->owner
].
angoff+ 512)&2047] * (1.
f/16384.
f);
k2
= k0
*(1-k4
)+k1
*k5
;
k3
= k1
*(1-k4
)-k0
*k5
;
k6
= f
*gstang
- gsinang
*gctang
; k7
= g
*gstang
+ gcosang
*gctang
;
mat
[0] = k4
*k6
+ k5
*k7
; mat
[4] = gchang
*gstang
; mat
[ 8] = k4
*k7
- k5
*k6
; mat
[12] = k2
*k6
+ k3
*k7
;
k6
= f
*gctang
+ gsinang
*gstang
; k7
= g
*gctang
- gcosang
*gstang
;
mat
[1] = k4
*k6
+ k5
*k7
; mat
[5] = gchang
*gctang
; mat
[ 9] = k4
*k7
- k5
*k6
; mat
[13] = k2
*k6
+ k3
*k7
;
k6
= gcosang2
*gchang
; k7
= gsinang2
*gchang
;
mat
[2] = k4
*k6
+ k5
*k7
; mat
[6] =-gshang
; mat
[10] = k4
*k7
- k5
*k6
; mat
[14] = k2
*k6
+ k3
*k7
;
mat
[12] = (mat
[12] + a0
->y
*mat
[0]) + (a0
->z
*mat
[4] + a0
->x
*mat
[ 8]);
mat
[13] = (mat
[13] + a0
->y
*mat
[1]) + (a0
->z
*mat
[5] + a0
->x
*mat
[ 9]);
mat
[14] = (mat
[14] + a0
->y
*mat
[2]) + (a0
->z
*mat
[6] + a0
->x
*mat
[10]);
}
static void md3draw_handle_triangles
(const md3surf_t
*s
, uint16_t *indexhandle
,
int32_t texunits
, const md3model_t
*M
)
{
int32_t i
;
if (r_vertexarrays
)
{
int32_t k
= 0;
if (M
== NULL
)
{
for (i
=s
->numtris
-1; i
>=0; i
--, k
+=3)
{
indexhandle
[k
] = s
->tris
[i
].
i[0];
indexhandle
[k
+1] = s
->tris
[i
].
i[1];
indexhandle
[k
+2] = s
->tris
[i
].
i[2];
}
return;
}
for (i
=s
->numtris
-1; i
>=0; i
--, k
+=3)
{
uint16_t tri
= M
->indexes
[i
];
indexhandle
[k
] = s
->tris
[tri
].
i[0];
indexhandle
[k
+1] = s
->tris
[tri
].
i[1];
indexhandle
[k
+2] = s
->tris
[tri
].
i[2];
}
return;
}
bglBegin
(GL_TRIANGLES
);
for (i
=s
->numtris
-1; i
>=0; i
--)
{
uint16_t tri
= M
? M
->indexes
[i
] : i
;
int32_t j
;
for (j
=0; j
<3; j
++)
{
int32_t k
= s
->tris
[tri
].
i[j
];
if (texunits
> GL_TEXTURE0_ARB
)
{
int32_t l
= GL_TEXTURE0_ARB
;
while (l
<= texunits
)
bglMultiTexCoord2fARB
(l
++, s
->uv
[k
].
u, s
->uv
[k
].
v);
}
else
bglTexCoord2f
(s
->uv
[k
].
u, s
->uv
[k
].
v);
bglVertex3fv
((float *) &vertlist
[k
]);
}
}
bglEnd
();
}
static int32_t polymost_md3draw
(md3model_t
*m
, const tspritetype
*tspr
)
{
vec3f_t m0
, m1
, a0
;
md3xyzn_t
*v0
, *v1
;
int32_t i
, surfi
;
float f
, g
, k0
, k1
, k2
=0, k3
=0, mat
[16]; // inits: compiler-happy
GLfloat pc
[4];
int32_t texunits
= GL_TEXTURE0_ARB
;
const int32_t owner
= tspr
->owner
;
// PK: XXX: These owner bound checks are redundant because sext is
// dereferenced unconditionally below anyway.
const spriteext_t
*const sext
= ((unsigned)owner
< MAXSPRITES
+MAXUNIQHUDID
) ? &spriteext
[owner
] : NULL
;
const uint8_t lpal
= ((unsigned)owner
< MAXSPRITES
) ? sprite
[tspr
->owner
].
pal : tspr
->pal
;
const int32_t sizyrep
= tilesiz
[tspr
->picnum
].
y*tspr
->yrepeat
;
if (r_vbos
&& (m
->vbos
== NULL
))
mdloadvbos
(m
);
// if ((tspr->cstat&48) == 32) return 0;
updateanimation
((md2model_t
*)m
, tspr
, lpal
);
//create current&next frame's vertex list from whole list
f
= m
->interpol
; g
= 1.
f - f
;
if (m
->interpol
< 0.
f || m
->interpol
> 1.
f ||
(unsigned)m
->cframe
>= (unsigned)m
->numframes
||
(unsigned)m
->nframe
>= (unsigned)m
->numframes
)
{
#ifdef DEBUGGINGAIDS
OSD_Printf
("%s: mdframe oob: c:%d n:%d total:%d interpol:%.02f\n",
m
->head.
nam, m
->cframe
, m
->nframe
, m
->numframes
, m
->interpol
);
#endif
m
->interpol
= fclamp
(m
->interpol
, 0.
f, 1.
f);
m
->cframe
= clamp
(m
->cframe
, 0, m
->numframes
-1);
m
->nframe
= clamp
(m
->nframe
, 0, m
->numframes
-1);
}
m0.
z = m0.
y = m0.
x = g
= m
->scale
* g
* (1.
f/64.
f);
m1.
z = m1.
y = m1.
x = f
= m
->scale
* f
* (1.
f/64.
f);
a0.
x = a0.
y = 0;
a0.
z = m
->zadd
* m
->scale
;
// Parkar: Moved up to be able to use k0 for the y-flipping code
k0
= (float)tspr
->z
;
if ((globalorientation
&128) && !((globalorientation
&48)==32))
k0
+= (float)(sizyrep
<<1);
// Parkar: Changed to use the same method as centeroriented sprites
if (globalorientation
&8) //y-flipping
{
m0.
z = -m0.
z; m1.
z = -m1.
z; a0.
z = -a0.
z;
k0
-= (float)(sizyrep
<<2);
}
if (globalorientation
&4) { m0.
y = -m0.
y; m1.
y = -m1.
y; a0.
y = -a0.
y; } //x-flipping
// yoffset differs from zadd in that it does not follow cstat&8 y-flipping
a0.
z += m
->yoffset
*m
->scale
;
f
= ((float)tspr
->xrepeat
) * (1.
f/64.
f) * m
->bscale
;
m0.
x *= f
; m0.
y *= -f
;
m1.
x *= f
; m1.
y *= -f
;
a0.
x *= f
; a0.
y *= -f
;
f
= ((float)tspr
->yrepeat
) * (1.
f/64.
f) * m
->bscale
;
m0.
z *= f
; m1.
z *= f
; a0.
z *= f
;
// floor aligned
k1
= (float)tspr
->y
;
if ((globalorientation
&48)==32)
{
m0.
z = -m0.
z; m1.
z = -m1.
z; a0.
z = -a0.
z;
m0.
y = -m0.
y; m1.
y = -m1.
y; a0.
y = -a0.
y;
f
= a0.
x; a0.
x = a0.
z; a0.
z = f
;
k1
+= (float)(sizyrep
>>3);
}
// Note: These SCREEN_FACTORS will be neutralized in axes offset
// calculations below again, but are needed for the base offsets.
f
= (65536.
f*512.
f)/(fxdimen
*fviewingrange
);
g
= 32.
f/(fxdimen
*gxyaspect
);
m0.
y *= f
; m1.
y *= f
; a0.
y = (((float)(tspr
->x
-globalposx
))* (1.
f/1024.
f) + a0.
y)*f
;
m0.
x *=-f
; m1.
x *=-f
; a0.
x = ((k1
-fglobalposy
) * -(1.
f/1024.
f) + a0.
x)*-f
;
m0.
z *= g
; m1.
z *= g
; a0.
z = ((k0
-fglobalposz
) * -(1.
f/16384.
f) + a0.
z)*g
;
md3_vox_calcmat_common
(tspr
, &a0
, f
, mat
);
// floor aligned
if ((globalorientation
&48)==32)
{
f
= mat
[4]; mat
[4] = mat
[8]*16.
f; mat
[8] = -f
*(1.
f/16.
f);
f
= mat
[5]; mat
[5] = mat
[9]*16.
f; mat
[9] = -f
*(1.
f/16.
f);
f
= mat
[6]; mat
[6] = mat
[10]*16.
f; mat
[10] = -f
*(1.
f/16.
f);
}
//Mirrors
if (grhalfxdown10x
< 0) { mat
[0] = -mat
[0]; mat
[4] = -mat
[4]; mat
[8] = -mat
[8]; mat
[12] = -mat
[12]; }
//------------
// Bit 10 is an ugly hack in game.c:G_DoSpriteAnimations() telling md2sprite
// to use Z-buffer hacks to hide overdraw problems with the
// flat-tsprite-on-floor shadows.
// is this still needed?
if (tspr
->cstat
&CSTAT_SPRITE_MDHACK
)
{
#ifdef __arm__ // GL ES has a glDepthRangef and the loss of precision is OK there
float f
= (float) (tspr
->owner
+ 1) * (FLT_EPSILON
* 8.0);
if (f
!= 0.0) f
*= 1.
f/(float) (sepldist
(globalposx
- tspr
->x
, globalposy
- tspr
->y
)>>5);
#else
double f
= (double) (tspr
->owner
+ 1) * (FLT_EPSILON
* 8.0);
if (f
!= 0.0) f
*= 1.0/(double) (sepldist
(globalposx
- tspr
->x
, globalposy
- tspr
->y
)>>5);
// bglBlendFunc(GL_SRC_ALPHA, GL_DST_COLOR);
#endif
bglDepthFunc
(GL_LEQUAL
);
// bglDepthRange(0.0 - f, 1.0 - f);
}
// bglPushAttrib(GL_POLYGON_BIT);
if ((grhalfxdown10x
>= 0) ^((globalorientation
&8) != 0) ^((globalorientation
&4) != 0)) bglFrontFace
(GL_CW
); else bglFrontFace
(GL_CCW
);
bglEnable
(GL_CULL_FACE
);
bglCullFace
(GL_BACK
);
bglEnable
(GL_TEXTURE_2D
);
pc
[0] = pc
[1] = pc
[2] = ((float)(numshades
-min
(max
((globalshade
* shadescale
)+m
->shadeoff
,0),numshades
)))/((float)numshades
);
if (!(hictinting
[globalpal
].
f & HICTINT_COLORIZE
))
{
if (!(m
->flags
&1) || (((unsigned)owner
< MAXSPRITES
) && sector
[sprite
[owner
].
sectnum].
floorpal!=0))
{
hictinting_apply
(pc
, globalpal
);
if (have_basepal_tint
())
hictinting_apply
(pc
, MAXPALOOKUPS
-1);
}
else globalnoeffect
=1;
}
if (tspr
->cstat
&2) { if (!(tspr
->cstat
&512)) pc
[3] = 0.66f; else pc
[3] = 0.33f; }
else pc
[3] = 1.0f;
pc
[3] *= 1.0f - sext
->alpha
;
if (m
->usesalpha
) //Sprites with alpha in texture
{
// bglEnable(GL_BLEND);// bglBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// bglEnable(GL_ALPHA_TEST); bglAlphaFunc(GL_GREATER,0.32);
// float al = 0.32;
// PLAG : default cutoff removed
float al
= 0.0;
if (alphahackarray
[globalpicnum
] != 0)
al
=alphahackarray
[globalpicnum
] * (1.
f/255.
f);
bglEnable
(GL_BLEND
);
bglEnable
(GL_ALPHA_TEST
);
bglAlphaFunc
(GL_GREATER
,al
);
}
else
{
if ((tspr
->cstat
&2) || sext
->alpha
> 0.
f || pc
[3] < 1.0f) bglEnable
(GL_BLEND
); //else bglDisable(GL_BLEND);
}
bglColor4f
(pc
[0],pc
[1],pc
[2],pc
[3]);
//if (MFLAGS_NOCONV(m))
// bglColor4f(0.0f, 0.0f, 1.0f, 1.0f);
//------------
// PLAG: Cleaner model rotation code
if (sext
->pitch
|| sext
->roll
)
{
float f
= 1.
f/(fxdimen
* fviewingrange
) * (m0.
x+m1.
x) * (2560.
f * (1.
f/(65536.
f*1280.
f)));
Bmemset
(&a0
, 0, sizeof(a0
));
if (sext
->offset.
x)
a0.
x = (float) sext
->offset.
x * f
;
if (sext
->offset.
y) // Compare with SCREEN_FACTORS above
a0.
y = (float) sext
->offset.
y * f
;
if ((sext
->offset.
z) && !(tspr
->cstat
&CSTAT_SPRITE_MDHACK
)) // Compare with SCREEN_FACTORS above
a0.
z = (float)sext
->offset.
z / (655360.
f * (m0.
z+m1.
z) * (gxyaspect
*fxdimen
*(1.
f/1280.
f)));
k0
= (float)sintable
[(sext
->pitch
+512)&2047] * (1.
f/16384.
f);
k1
= (float)sintable
[sext
->pitch
&2047] * (1.
f/16384.
f);
k2
= (float)sintable
[(sext
->roll
+512)&2047] * (1.
f/16384.
f);
k3
= (float)sintable
[sext
->roll
&2047] * (1.
f/16384.
f);
}
for (surfi
=0; surfi
<m
->head.
numsurfs; surfi
++)
{
//PLAG : sorting stuff
void *vbotemp
;
vec3f_t
*vertexhandle
= NULL
;
uint16_t *indexhandle
;
vec3f_t fp
;
const md3surf_t
*const s
= &m
->head.
surfs[surfi
];
v0
= &s
->xyzn
[m
->cframe
*s
->numverts
];
v1
= &s
->xyzn
[m
->nframe
*s
->numverts
];
if (r_vertexarrays
&& r_vbos
)
{
if (++curvbo
>= r_vbocount
)
curvbo
= 0;
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, vertvbos
[curvbo
]);
vbotemp
= bglMapBufferARB
(GL_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
);
vertexhandle
= (vec3f_t
*)vbotemp
;
}
if (sext
->pitch
|| sext
->roll
)
{
vec3f_t fp1
, fp2
;
for (i
=s
->numverts
-1; i
>=0; i
--)
{
fp.
z = v0
[i
].
x + a0.
x;
fp.
x = v0
[i
].
y + a0.
y;
fp.
y = v0
[i
].
z + a0.
z;
fp1.
x = fp.
x*k2
+ fp.
y*k3
;
fp1.
y = fp.
x*k0
*(-k3
) + fp.
y*k0
*k2
+ fp.
z*(-k1
);
fp1.
z = fp.
x*k1
*(-k3
) + fp.
y*k1
*k2
+ fp.
z*k0
;
fp.
z = v1
[i
].
x + a0.
x;
fp.
x = v1
[i
].
y + a0.
y;
fp.
y = v1
[i
].
z + a0.
z;
fp2.
x = fp.
x*k2
+ fp.
y*k3
;
fp2.
y = fp.
x*k0
*(-k3
) + fp.
y*k0
*k2
+ fp.
z*(-k1
);
fp2.
z = fp.
x*k1
*(-k3
) + fp.
y*k1
*k2
+ fp.
z*k0
;
fp.
z = (fp1.
z - a0.
x)*m0.
x + (fp2.
z - a0.
x)*m1.
x;
fp.
x = (fp1.
x - a0.
y)*m0.
y + (fp2.
x - a0.
y)*m1.
y;
fp.
y = (fp1.
y - a0.
z)*m0.
z + (fp2.
y - a0.
z)*m1.
z;
if (r_vertexarrays
&& r_vbos
)
vertexhandle
[i
] = fp
;
vertlist
[i
] = fp
;
}
}
else
{
for (i
=s
->numverts
-1; i
>=0; i
--)
{
fp.
z = v0
[i
].
x*m0.
x + v1
[i
].
x*m1.
x;
fp.
y = v0
[i
].
z*m0.
z + v1
[i
].
z*m1.
z;
fp.
x = v0
[i
].
y*m0.
y + v1
[i
].
y*m1.
y;
if (r_vertexarrays
&& r_vbos
)
vertexhandle
[i
] = fp
;
vertlist
[i
] = fp
;
}
}
if (r_vertexarrays
&& r_vbos
)
{
bglUnmapBufferARB
(GL_ARRAY_BUFFER_ARB
);
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, 0);
}
bglMatrixMode
(GL_MODELVIEW
); //Let OpenGL (and perhaps hardware :) handle the matrix rotation
mat
[3] = mat
[7] = mat
[11] = 0.
f; mat
[15] = 1.
f; bglLoadMatrixf
(mat
);
// PLAG: End
i
= mdloadskin
((md2model_t
*)m
,tile2model
[Ptile2tile
(tspr
->picnum
,lpal
)].
skinnum,globalpal
,surfi
);
if (!i
)
continue;
//i = mdloadskin((md2model *)m,tile2model[Ptile2tile(tspr->picnum,lpal)].skinnum,surfi); //hack for testing multiple surfaces per MD3
bglBindTexture
(GL_TEXTURE_2D
, i
);
if (!(tspr
->cstat
&CSTAT_SPRITE_MDHACK
))
{
#ifndef EDUKE32_GLES
i
= r_detailmapping
? mdloadskin
((md2model_t
*) m
, tile2model
[Ptile2tile
(tspr
->picnum
, lpal
)].
skinnum, DETAILPAL
, surfi
) : 0;
if (i
)
{
mdskinmap_t
*sk
;
polymost_setupdetailtexture
(++texunits
, i
);
for (sk
= m
->skinmap
; sk
; sk
= sk
->next
)
if ((int32_t) sk
->palette
== DETAILPAL
&& sk
->skinnum
== tile2model
[Ptile2tile
(tspr
->picnum
, lpal
)].
skinnum && sk
->surfnum
== surfi
)
f
= sk
->param
;
bglMatrixMode
(GL_TEXTURE
);
bglLoadIdentity
();
bglScalef
(f
, f
, 1.0f);
bglMatrixMode
(GL_MODELVIEW
);
}
i
= r_glowmapping
? mdloadskin
((md2model_t
*) m
, tile2model
[Ptile2tile
(tspr
->picnum
, lpal
)].
skinnum, GLOWPAL
, surfi
) : 0;
if (i
)
polymost_setupglowtexture
(++texunits
, i
);
#endif
if (r_vertexarrays
&& r_vbos
)
{
bglBindBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, indexvbos
[curvbo
]);
vbotemp
= bglMapBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
);
indexhandle
= (uint16_t *) vbotemp
;
}
else
indexhandle
= m
->vindexes
;
//PLAG: delayed polygon-level sorted rendering
if (m
->usesalpha
)
{
vec3f_t fp
, fp1
, fp2
, vlt0
, vlt1
, vlt2
;
for (i
=s
->numtris
-1; i
>=0; i
--)
{
vlt0
= vertlist
[s
->tris
[i
].
i[0]];
vlt1
= vertlist
[s
->tris
[i
].
i[1]];
vlt2
= vertlist
[s
->tris
[i
].
i[2]];
// Matrix multiplication - ugly but clear
fp.
x = (vlt0.
x * mat
[0]) + (vlt0.
y * mat
[4]) + (vlt0.
z * mat
[8]) + mat
[12];
fp.
y = (vlt0.
x * mat
[1]) + (vlt0.
y * mat
[5]) + (vlt0.
z * mat
[9]) + mat
[13];
fp.
z = (vlt0.
x * mat
[2]) + (vlt0.
y * mat
[6]) + (vlt0.
z * mat
[10]) + mat
[14];
fp1.
x = (vlt1.
x * mat
[0]) + (vlt1.
y * mat
[4]) + (vlt1.
z * mat
[8]) + mat
[12];
fp1.
y = (vlt1.
x * mat
[1]) + (vlt1.
y * mat
[5]) + (vlt1.
z * mat
[9]) + mat
[13];
fp1.
z = (vlt1.
x * mat
[2]) + (vlt1.
y * mat
[6]) + (vlt1.
z * mat
[10]) + mat
[14];
fp2.
x = (vlt2.
x * mat
[0]) + (vlt2.
y * mat
[4]) + (vlt2.
z * mat
[8]) + mat
[12];
fp2.
y = (vlt2.
x * mat
[1]) + (vlt2.
y * mat
[5]) + (vlt2.
z * mat
[9]) + mat
[13];
fp2.
z = (vlt2.
x * mat
[2]) + (vlt2.
y * mat
[6]) + (vlt2.
z * mat
[10]) + mat
[14];
f
= (fp.
x * fp.
x) + (fp.
y * fp.
y) + (fp.
z * fp.
z);
g
= (fp1.
x * fp1.
x) + (fp1.
y * fp1.
y) + (fp1.
z * fp1.
z);
if (f
> g
)
f
= g
;
g
= (fp2.
x * fp2.
x) + (fp2.
y * fp2.
y) + (fp2.
z * fp2.
z);
if (f
> g
)
f
= g
;
m
->maxdepths
[i
] = f
;
m
->indexes
[i
] = i
;
}
// dichotomic recursive sorting - about 100x less iterations than bubblesort
quicksort
(m
->indexes
, m
->maxdepths
, 0, s
->numtris
- 1);
}
md3draw_handle_triangles
(s
, indexhandle
, texunits
, m
->usesalpha
? m
: NULL
);
}
else
{
if (r_vertexarrays
&& r_vbos
)
{
bglBindBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, indexvbos
[curvbo
]);
vbotemp
= bglMapBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, GL_WRITE_ONLY_ARB
);
indexhandle
= (uint16_t *) vbotemp
;
}
else
indexhandle
= m
->vindexes
;
md3draw_handle_triangles
(s
, indexhandle
, texunits
, NULL
);
}
if (r_vertexarrays
)
{
int32_t l
;
if (r_vbos
)
{
bglUnmapBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
);
bglBindBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, m
->vbos
[surfi
]);
l
= GL_TEXTURE0_ARB
;
do
{
bglClientActiveTextureARB
(l
++);
bglEnableClientState
(GL_TEXTURE_COORD_ARRAY
);
bglTexCoordPointer
(2, GL_FLOAT
, 0, 0);
} while (l
<= texunits
);
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, vertvbos
[curvbo
]);
bglVertexPointer
(3, GL_FLOAT
, 0, 0);
bglBindBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, indexvbos
[curvbo
]);
bglDrawElements
(GL_TRIANGLES
, s
->numtris
* 3, GL_UNSIGNED_SHORT
, 0);
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, 0);
bglBindBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
}
else // r_vbos
{
l
= GL_TEXTURE0_ARB
;
do
{
bglClientActiveTextureARB
(l
++);
bglEnableClientState
(GL_TEXTURE_COORD_ARRAY
);
bglTexCoordPointer
(2, GL_FLOAT
, 0, &(s
->uv
[0].
u));
} while (l
<= texunits
);
bglVertexPointer
(3, GL_FLOAT
, 0, &(vertlist
[0].
x));
bglDrawElements
(GL_TRIANGLES
, s
->numtris
* 3, GL_UNSIGNED_SHORT
, m
->vindexes
);
} // r_vbos
while (texunits
> GL_TEXTURE0_ARB
)
{
bglMatrixMode
(GL_TEXTURE
);
bglLoadIdentity
();
bglMatrixMode
(GL_MODELVIEW
);
bglTexEnvf
(GL_TEXTURE_ENV
, GL_RGB_SCALE_ARB
, 1.0f);
bglDisable
(GL_TEXTURE_2D
);
bglDisableClientState
(GL_TEXTURE_COORD_ARRAY
);
bglClientActiveTextureARB
(texunits
- 1);
bglActiveTextureARB
(--texunits
);
}
}
else // r_vertexarrays
{
while (texunits
> GL_TEXTURE0_ARB
)
{
bglMatrixMode
(GL_TEXTURE
);
bglLoadIdentity
();
bglMatrixMode
(GL_MODELVIEW
);
bglTexEnvf
(GL_TEXTURE_ENV
, GL_RGB_SCALE_ARB
, 1.0f);
bglDisable
(GL_TEXTURE_2D
);
bglActiveTextureARB
(--texunits
);
}
} // r_vertexarrays
}
//------------
if (m
->usesalpha
) bglDisable
(GL_ALPHA_TEST
);
bglDisable
(GL_CULL_FACE
);
// bglPopAttrib();
bglLoadIdentity
();
globalnoeffect
=0;
return 1;
}
static void md3free
(md3model_t
*m
)
{
mdanim_t
*anim
, *nanim
= NULL
;
mdskinmap_t
*sk
, *nsk
= NULL
;
if (!m
) return;
for (anim
=m
->animations
; anim
; anim
=nanim
)
{
nanim
= anim
->next
;
Bfree
(anim
);
}
for (sk
=m
->skinmap
; sk
; sk
=nsk
)
{
nsk
= sk
->next
;
Bfree
(sk
->fn
);
Bfree
(sk
);
}
if (m
->head.
surfs)
{
for (int surfi
=m
->head.
numsurfs-1; surfi
>=0; surfi
--)
{
md3surf_t
*s
= &m
->head.
surfs[surfi
];
Bfree
(s
->tris
);
Bfree
(s
->geometry
); // FREE_SURFS_GEOMETRY
}
Bfree
(m
->head.
surfs);
}
if (m
->head.
tags) Bfree
(m
->head.
tags);
if (m
->head.
frames) Bfree
(m
->head.
frames);
if (m
->texid
) Bfree
(m
->texid
);
if (m
->muladdframes
) Bfree
(m
->muladdframes
);
if (m
->indexes
) Bfree
(m
->indexes
);
if (m
->vindexes
) Bfree
(m
->vindexes
);
if (m
->maxdepths
) Bfree
(m
->maxdepths
);
if (m
->vbos
)
{
bglDeleteBuffersARB
(m
->head.
numsurfs, m
->vbos
);
Bfree
(m
->vbos
);
m
->vbos
= NULL
;
}
Bfree
(m
);
}
//---------------------------------------- MD3 LIBRARY ENDS ----------------------------------------
//--------------------------------------- MD LIBRARY BEGINS ---------------------------------------
mdmodel_t
*mdload
(const char *filnam
)
{
mdmodel_t
*vm
;
int32_t fil
;
int32_t i
;
vm
= (mdmodel_t
*)voxload
(filnam
);
if (vm
) return vm
;
fil
= kopen4load
((char *)filnam
,0);
if (fil
< 0)
return NULL
;
kread
(fil
,&i
,4);
klseek
(fil
,0,SEEK_SET
);
switch (B_LITTLE32
(i
))
{
case IDP2_MAGIC
:
// initprintf("Warning: model \"%s\" is version IDP2; wanted version IDP3\n",filnam);
vm
= (mdmodel_t
*)md2load
(fil
,filnam
);
break; //IDP2
case IDP3_MAGIC
:
vm
= (mdmodel_t
*)md3load
(fil
);
break; //IDP3
default:
vm
= NULL
;
break;
}
kclose
(fil
);
if (vm
)
{
md3model_t
*vm3
= (md3model_t
*)vm
;
// smuggle the file name into the model struct.
// head.nam is unused as far as I can tell
Bstrncpyz
(vm3
->head.
nam, filnam
, sizeof(vm3
->head.
nam));
md3postload_common
(vm3
);
#ifdef POLYMER
if (glrendmode
!= REND_POLYMER
)
if (md3postload_polymer_check
(vm3
))
{
mdfree
(vm
);
vm
= NULL
;
}
#endif
}
return vm
;
}
void md_allocvbos
(void)
{
int32_t i
;
indexvbos
= (GLuint
*) Xrealloc
(indexvbos
, sizeof(GLuint
) * r_vbocount
);
vertvbos
= (GLuint
*) Xrealloc
(vertvbos
, sizeof(GLuint
) * r_vbocount
);
if (r_vbocount
!= allocvbos
)
{
bglGenBuffersARB
(r_vbocount
- allocvbos
, &(indexvbos
[allocvbos
]));
bglGenBuffersARB
(r_vbocount
- allocvbos
, &(vertvbos
[allocvbos
]));
i
= allocvbos
;
while (i
< r_vbocount
)
{
bglBindBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, indexvbos
[i
]);
bglBufferDataARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, maxmodeltris
* 3 * sizeof(uint16_t), NULL
, GL_STREAM_DRAW_ARB
);
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, vertvbos
[i
]);
bglBufferDataARB
(GL_ARRAY_BUFFER_ARB
, maxmodelverts
* sizeof(vec3f_t
), NULL
, GL_STREAM_DRAW_ARB
);
i
++;
}
bglBindBufferARB
(GL_ELEMENT_ARRAY_BUFFER_ARB
, 0);
bglBindBufferARB
(GL_ARRAY_BUFFER_ARB
, 0);
allocvbos
= r_vbocount
;
}
}
int32_t polymost_mddraw
(const tspritetype
*tspr
)
{
mdmodel_t
*vm
;
if (r_vbos
&& (r_vbocount
> allocvbos
))
md_allocvbos
();
if (maxmodelverts
> allocmodelverts
)
{
vertlist
= (vec3f_t
*) Xrealloc
(vertlist
, sizeof(vec3f_t
)*maxmodelverts
);
allocmodelverts
= maxmodelverts
;
}
vm
= models
[tile2model
[Ptile2tile
(tspr
->picnum
,(tspr
->owner
>= MAXSPRITES
) ? tspr
->pal
: sprite
[tspr
->owner
].
pal)].
modelid];
if (vm
->mdnum
== 1) { return polymost_voxdraw
((voxmodel_t
*)vm
,tspr
); }
if (vm
->mdnum
== 3) { return polymost_md3draw
((md3model_t
*)vm
,tspr
); }
return 0;
}
void mdfree
(mdmodel_t
*vm
)
{
if (vm
->mdnum
== 1) { voxfree
((voxmodel_t
*)vm
); return; }
if (vm
->mdnum
== 2 || vm
->mdnum
== 3) { md3free
((md3model_t
*)vm
); return; }
}
#endif
//---------------------------------------- MD LIBRARY ENDS ----------------------------------------