raze-gles/polymer/eduke32/build/src/voxmodel.c
terminx 7eec6b36a5 Sprite sorting changes:
-Sort by owner now occurs only when two sprites have matching x/y coordinates.
-Cstat 1024 now activates a special drawing mode that indicates a sprite should be drawn without depth after all other sprites have been drawn. The previous cstat 1024 functionality, an internal hack for shadows cast by models in Polymost, has been moved to bit 1 of a new graphical effects bitfield stored in a tsprite's .extra member.

git-svn-id: https://svn.eduke32.com/eduke32@5400 1a8010ca-5511-0410-912e-c29ae57300e0
2015-10-21 19:54:14 +00:00

1069 lines
30 KiB
C

//--------------------------------------- VOX 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 <math.h>
//For loading/conversion only
static vec3_t voxsiz;
static int32_t yzsiz, *vbit = 0; //vbit: 1 bit per voxel: 0=air,1=solid
static vec3f_t voxpiv;
static int32_t *vcolhashead = 0, vcolhashsizm1;
typedef struct { int32_t p, c, n; } voxcol_t;
static voxcol_t *vcol = 0; int32_t vnum = 0, vmax = 0;
typedef struct { int16_t x, y; } spoint2d;
static spoint2d *shp;
static int32_t *shcntmal, *shcnt = 0, shcntp;
static int32_t mytexo5, *zbit, gmaxx, gmaxy, garea, pow2m1[33];
static voxmodel_t *gvox;
//pitch must equal xsiz*4
uint32_t gloadtex(int32_t *picbuf, int32_t xsiz, int32_t ysiz, int32_t is8bit, int32_t dapal)
{
const char *const cptr = &britable[gammabrightness ? 0 : curbrightness][0];
// Correct for GL's RGB order; also apply gamma here:
const coltype *const pic = (const coltype *)picbuf;
coltype *pic2 = (coltype *)Xmalloc(xsiz*ysiz*sizeof(coltype));
if (!is8bit)
{
for (int32_t i=xsiz*ysiz-1; i>=0; i--)
{
pic2[i].b = cptr[pic[i].r];
pic2[i].g = cptr[pic[i].g];
pic2[i].r = cptr[pic[i].b];
pic2[i].a = 255;
}
}
else
{
if (palookup[dapal] == NULL)
dapal = 0;
for (int32_t i=xsiz*ysiz-1; i>=0; i--)
{
const int32_t ii = palookup[dapal][pic[i].a] * 3;
pic2[i].b = cptr[palette[ii+2]*4];
pic2[i].g = cptr[palette[ii+1]*4];
pic2[i].r = cptr[palette[ii+0]*4];
pic2[i].a = 255;
}
}
uint32_t rtexid;
bglGenTextures(1, (GLuint *) &rtexid);
bglBindTexture(GL_TEXTURE_2D, rtexid);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
bglTexImage2D(GL_TEXTURE_2D, 0, 4, xsiz, ysiz, 0, GL_RGBA, GL_UNSIGNED_BYTE, (char *) pic2);
Bfree(pic2);
return rtexid;
}
static int32_t getvox(int32_t x, int32_t y, int32_t z)
{
z += x*yzsiz + y*voxsiz.z;
for (x=vcolhashead[(z*214013)&vcolhashsizm1]; x>=0; x=vcol[x].n)
if (vcol[x].p == z)
return vcol[x].c;
return 0x808080;
}
static void putvox(int32_t x, int32_t y, int32_t z, int32_t col)
{
if (vnum >= vmax)
{
vmax = max(vmax<<1, 4096);
vcol = (voxcol_t *)Xrealloc(vcol, vmax*sizeof(voxcol_t));
}
z += x*yzsiz + y*voxsiz.z;
vcol[vnum].p = z; z = (z*214013)&vcolhashsizm1;
vcol[vnum].c = col;
vcol[vnum].n = vcolhashead[z]; vcolhashead[z] = vnum++;
}
//Set all bits in vbit from (x,y,z0) to (x,y,z1-1) to 0's
#if 0
static void setzrange0(int32_t *lptr, int32_t z0, int32_t z1)
{
if (!((z0^z1)&~31)) { lptr[z0>>5] &= ((~(-1<<SHIFTMOD32(z0)))|(-1<<SHIFTMOD32(z1))); return; }
int32_t z = (z0>>5), ze = (z1>>5);
lptr[z] &=~(-1<<SHIFTMOD32(z0)); for (z++; z<ze; z++) lptr[z] = 0;
lptr[z] &= (-1<<SHIFTMOD32(z1));
}
#endif
//Set all bits in vbit from (x,y,z0) to (x,y,z1-1) to 1's
static void setzrange1(int32_t *lptr, int32_t z0, int32_t z1)
{
if (!((z0^z1)&~31)) { lptr[z0>>5] |= ((~(-1<<SHIFTMOD32(z1)))&(-1<<SHIFTMOD32(z0))); return; }
int32_t z = (z0>>5), ze = (z1>>5);
lptr[z] |= (-1<<SHIFTMOD32(z0)); for (z++; z<ze; z++) lptr[z] = -1;
lptr[z] |=~(-1<<SHIFTMOD32(z1));
}
static int32_t isrectfree(int32_t x0, int32_t y0, int32_t dx, int32_t dy)
{
#if 0
int32_t i, j, x;
i = y0*gvox->mytexx + x0;
for (dy=0; dy; dy--, i+=gvox->mytexx)
for (x=0; x<dx; x++) { j = i+x; if (zbit[j>>5]&(1<<SHIFTMOD32(j))) return(0); }
#else
int32_t i = y0*mytexo5 + (x0>>5);
dx += x0-1;
const int32_t c = (dx>>5) - (x0>>5);
int32_t m = ~pow2m1[x0&31];
const int32_t m1 = pow2m1[(dx&31)+1];
if (!c)
{
for (m &= m1; dy; dy--, i += mytexo5)
if (zbit[i]&m)
return 0;
}
else
{
for (; dy; dy--, i += mytexo5)
{
if (zbit[i]&m)
return 0;
int32_t x;
for (x=1; x<c; x++)
if (zbit[i+x])
return 0;
if (zbit[i+x]&m1)
return 0;
}
}
#endif
return(1);
}
static void setrect(int32_t x0, int32_t y0, int32_t dx, int32_t dy)
{
#if 0
int32_t i, j, y;
i = y0*gvox->mytexx + x0;
for (y=0; y<dy; y++, i+=gvox->mytexx)
for (x=0; x<dx; x++) { j = i+x; zbit[j>>5] |= (1<<SHIFTMOD32(j)); }
#else
int32_t i = y0*mytexo5 + (x0>>5);
dx += x0-1;
const int32_t c = (dx>>5) - (x0>>5);
int32_t m = ~pow2m1[x0&31];
const int32_t m1 = pow2m1[(dx&31)+1];
if (!c)
{
for (m &= m1; dy; dy--, i += mytexo5)
zbit[i] |= m;
}
else
{
for (; dy; dy--, i += mytexo5)
{
zbit[i] |= m;
int32_t x;
for (x=1; x<c; x++)
zbit[i+x] = -1;
zbit[i+x] |= m1;
}
}
#endif
}
static void cntquad(int32_t x0, int32_t y0, int32_t z0, int32_t x1, int32_t y1, int32_t z1,
int32_t x2, int32_t y2, int32_t z2, int32_t face)
{
UNREFERENCED_PARAMETER(x1);
UNREFERENCED_PARAMETER(y1);
UNREFERENCED_PARAMETER(z1);
UNREFERENCED_PARAMETER(face);
int32_t x = labs(x2-x0), y = labs(y2-y0), z = labs(z2-z0);
if (x == 0)
x = z;
else if (y == 0)
y = z;
if (x < y) { z = x; x = y; y = z; }
shcnt[y*shcntp+x]++;
if (x > gmaxx) gmaxx = x;
if (y > gmaxy) gmaxy = y;
garea += (x+(VOXBORDWIDTH<<1)) * (y+(VOXBORDWIDTH<<1));
gvox->qcnt++;
}
static void addquad(int32_t x0, int32_t y0, int32_t z0, int32_t x1, int32_t y1, int32_t z1,
int32_t x2, int32_t y2, int32_t z2, int32_t face)
{
int32_t i;
int32_t x = labs(x2-x0), y = labs(y2-y0), z = labs(z2-z0);
if (x == 0) { x = y; y = z; i = 0; }
else if (y == 0) { y = z; i = 1; }
else i = 2;
if (x < y) { z = x; x = y; y = z; i += 3; }
z = shcnt[y*shcntp+x]++;
int32_t *lptr = &gvox->mytex[(shp[z].y+VOXBORDWIDTH)*gvox->mytexx +
(shp[z].x+VOXBORDWIDTH)];
int32_t nx = 0, ny = 0, nz = 0;
switch (face)
{
case 0:
ny = y1; x2 = x0; x0 = x1; x1 = x2; break;
case 1:
ny = y0; y0++; y1++; y2++; break;
case 2:
nz = z1; y0 = y2; y2 = y1; y1 = y0; z0++; z1++; z2++; break;
case 3:
nz = z0; break;
case 4:
nx = x1; y2 = y0; y0 = y1; y1 = y2; x0++; x1++; x2++; break;
case 5:
nx = x0; break;
}
for (int32_t yy=0; yy<y; yy++, lptr+=gvox->mytexx)
for (int32_t xx=0; xx<x; xx++)
{
switch (face)
{
case 0:
if (i < 3) { nx = x1+x-1-xx; nz = z1+yy; } //back
else { nx = x1+y-1-yy; nz = z1+xx; }
break;
case 1:
if (i < 3) { nx = x0+xx; nz = z0+yy; } //front
else { nx = x0+yy; nz = z0+xx; }
break;
case 2:
if (i < 3) { nx = x1-x+xx; ny = y1-1-yy; } //bot
else { nx = x1-1-yy; ny = y1-1-xx; }
break;
case 3:
if (i < 3) { nx = x0+xx; ny = y0+yy; } //top
else { nx = x0+yy; ny = y0+xx; }
break;
case 4:
if (i < 3) { ny = y1+x-1-xx; nz = z1+yy; } //right
else { ny = y1+y-1-yy; nz = z1+xx; }
break;
case 5:
if (i < 3) { ny = y0+xx; nz = z0+yy; } //left
else { ny = y0+yy; nz = z0+xx; }
break;
}
lptr[xx] = getvox(nx, ny, nz);
}
//Extend borders horizontally
for (int32_t yy=VOXBORDWIDTH; yy<y+VOXBORDWIDTH; yy++)
for (int32_t xx=0; xx<VOXBORDWIDTH; xx++)
{
lptr = &gvox->mytex[(shp[z].y+yy)*gvox->mytexx + shp[z].x];
lptr[xx] = lptr[VOXBORDWIDTH];
lptr[xx+x+VOXBORDWIDTH] = lptr[x-1+VOXBORDWIDTH];
}
//Extend borders vertically
for (int32_t yy=0; yy<VOXBORDWIDTH; yy++)
{
Bmemcpy(&gvox->mytex[(shp[z].y+yy)*gvox->mytexx + shp[z].x],
&gvox->mytex[(shp[z].y+VOXBORDWIDTH)*gvox->mytexx + shp[z].x],
(x+(VOXBORDWIDTH<<1))<<2);
Bmemcpy(&gvox->mytex[(shp[z].y+y+yy+VOXBORDWIDTH)*gvox->mytexx + shp[z].x],
&gvox->mytex[(shp[z].y+y-1+VOXBORDWIDTH)*gvox->mytexx + shp[z].x],
(x+(VOXBORDWIDTH<<1))<<2);
}
voxrect_t *const qptr = &gvox->quad[gvox->qcnt];
qptr->v[0].x = x0; qptr->v[0].y = y0; qptr->v[0].z = z0;
qptr->v[1].x = x1; qptr->v[1].y = y1; qptr->v[1].z = z1;
qptr->v[2].x = x2; qptr->v[2].y = y2; qptr->v[2].z = z2;
for (int32_t j=0; j<3; j++)
{
qptr->v[j].u = shp[z].x+VOXBORDWIDTH;
qptr->v[j].v = shp[z].y+VOXBORDWIDTH;
}
if (i < 3)
qptr->v[1].u += x;
else
qptr->v[1].v += y;
qptr->v[2].u += x;
qptr->v[2].v += y;
qptr->v[3].u = qptr->v[0].u - qptr->v[1].u + qptr->v[2].u;
qptr->v[3].v = qptr->v[0].v - qptr->v[1].v + qptr->v[2].v;
qptr->v[3].x = qptr->v[0].x - qptr->v[1].x + qptr->v[2].x;
qptr->v[3].y = qptr->v[0].y - qptr->v[1].y + qptr->v[2].y;
qptr->v[3].z = qptr->v[0].z - qptr->v[1].z + qptr->v[2].z;
if (gvox->qfacind[face] < 0)
gvox->qfacind[face] = gvox->qcnt;
gvox->qcnt++;
}
static inline int32_t isolid(int32_t x, int32_t y, int32_t z)
{
if ((uint32_t)x >= (uint32_t)voxsiz.x) return 0;
if ((uint32_t)y >= (uint32_t)voxsiz.y) return 0;
if ((uint32_t)z >= (uint32_t)voxsiz.z) return 0;
z += x*yzsiz + y*voxsiz.z;
return vbit[z>>5] & (1<<SHIFTMOD32(z));
}
FORCE_INLINE int isair(int32_t i)
{
return !(vbit[i>>5] & (1<<SHIFTMOD32(i)));
}
static voxmodel_t *vox2poly()
{
int32_t i, j;
gvox = (voxmodel_t *)Xmalloc(sizeof(voxmodel_t));
memset(gvox, 0, sizeof(voxmodel_t));
{
//x is largest dimension, y is 2nd largest dimension
int32_t x = voxsiz.x, y = voxsiz.y, z = voxsiz.z;
if (x < y && x < z)
x = z;
else if (y < z)
y = z;
if (x < y)
{
z = x;
x = y;
y = z;
}
shcntp = x;
i = x*y*sizeof(int32_t);
}
shcntmal = (int32_t *)Xmalloc(i);
memset(shcntmal, 0, i);
shcnt = &shcntmal[-shcntp-1];
gmaxx = gmaxy = garea = 0;
if (pow2m1[32] != -1)
{
for (i=0; i<32; i++)
pow2m1[i] = (1u<<i)-1;
pow2m1[32] = -1;
}
for (i=0; i<7; i++)
gvox->qfacind[i] = -1;
i = (max(voxsiz.y, voxsiz.z)+1)<<2;
int32_t *const bx0 = (int32_t *)Xmalloc(i<<1);
int32_t *const by0 = (int32_t *)(((intptr_t)bx0)+i);
int32_t ov, oz=0;
for (int32_t cnt=0; cnt<2; cnt++)
{
void (*daquad)(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) =
cnt == 0 ? cntquad : addquad;
gvox->qcnt = 0;
memset(by0, -1, (max(voxsiz.y, voxsiz.z)+1)<<2);
int32_t v = 0;
for (i=-1; i<=1; i+=2)
for (int32_t y=0; y<voxsiz.y; y++)
for (int32_t x=0; x<=voxsiz.x; x++)
for (int32_t z=0; z<=voxsiz.z; z++)
{
ov = v; v = (isolid(x, y, z) && (!isolid(x, y+i, z)));
if ((by0[z] >= 0) && ((by0[z] != oz) || (v >= ov)))
{
daquad(bx0[z], y, by0[z], x, y, by0[z], x, y, z, i>=0);
by0[z] = -1;
}
if (v > ov) oz = z;
else if ((v < ov) && (by0[z] != oz)) { bx0[z] = x; by0[z] = oz; }
}
for (i=-1; i<=1; i+=2)
for (int32_t z=0; z<voxsiz.z; z++)
for (int32_t x=0; x<=voxsiz.x; x++)
for (int32_t y=0; y<=voxsiz.y; y++)
{
ov = v; v = (isolid(x, y, z) && (!isolid(x, y, z-i)));
if ((by0[y] >= 0) && ((by0[y] != oz) || (v >= ov)))
{
daquad(bx0[y], by0[y], z, x, by0[y], z, x, y, z, (i>=0)+2);
by0[y] = -1;
}
if (v > ov) oz = y;
else if ((v < ov) && (by0[y] != oz)) { bx0[y] = x; by0[y] = oz; }
}
for (i=-1; i<=1; i+=2)
for (int32_t x=0; x<voxsiz.x; x++)
for (int32_t y=0; y<=voxsiz.y; y++)
for (int32_t z=0; z<=voxsiz.z; z++)
{
ov = v; v = (isolid(x, y, z) && (!isolid(x-i, y, z)));
if ((by0[z] >= 0) && ((by0[z] != oz) || (v >= ov)))
{
daquad(x, bx0[z], by0[z], x, y, by0[z], x, y, z, (i>=0)+4);
by0[z] = -1;
}
if (v > ov) oz = z;
else if ((v < ov) && (by0[z] != oz)) { bx0[z] = y; by0[z] = oz; }
}
if (!cnt)
{
shp = (spoint2d *)Xmalloc(gvox->qcnt*sizeof(spoint2d));
int32_t sc = 0;
for (int32_t y=gmaxy; y; y--)
for (int32_t x=gmaxx; x>=y; x--)
{
i = shcnt[y*shcntp+x]; shcnt[y*shcntp+x] = sc; //shcnt changes from counter to head index
for (; i>0; i--)
{
shp[sc].x = x;
shp[sc].y = y;
sc++;
}
}
for (gvox->mytexx=32; gvox->mytexx<(gmaxx+(VOXBORDWIDTH<<1)); gvox->mytexx<<=1)
/* do nothing */;
for (gvox->mytexy=32; gvox->mytexy<(gmaxy+(VOXBORDWIDTH<<1)); gvox->mytexy<<=1)
/* do_nothing */;
while (gvox->mytexx*gvox->mytexy*8 < garea*9) //This should be sufficient to fit most skins...
{
skindidntfit:
if (gvox->mytexx <= gvox->mytexy)
gvox->mytexx <<= 1;
else
gvox->mytexy <<= 1;
}
mytexo5 = gvox->mytexx>>5;
i = ((gvox->mytexx*gvox->mytexy+31)>>5)<<2;
zbit = (int32_t *)Xmalloc(i);
memset(zbit, 0, i);
v = gvox->mytexx*gvox->mytexy;
for (int32_t z=0; z<sc; z++)
{
const int32_t dx = shp[z].x + (VOXBORDWIDTH<<1);
const int32_t dy = shp[z].y + (VOXBORDWIDTH<<1);
i = v;
int32_t x0, y0;
do
{
#if (VOXUSECHAR != 0)
x0 = ((rand()&32767)*(min(gvox->mytexx, 255)-dx))>>15;
y0 = ((rand()&32767)*(min(gvox->mytexy, 255)-dy))>>15;
#else
x0 = ((rand()&32767)*(gvox->mytexx+1-dx))>>15;
y0 = ((rand()&32767)*(gvox->mytexy+1-dy))>>15;
#endif
i--;
if (i < 0) //Time-out! Very slow if this happens... but at least it still works :P
{
Bfree(zbit);
//Re-generate shp[].x/y (box sizes) from shcnt (now head indices) for next pass :/
j = 0;
for (int32_t y=gmaxy; y; y--)
for (int32_t x=gmaxx; x>=y; x--)
{
i = shcnt[y*shcntp+x];
for (; j<i; j++)
{
shp[j].x = x0;
shp[j].y = y0;
}
x0 = x;
y0 = y;
}
for (; j<sc; j++)
{
shp[j].x = x0;
shp[j].y = y0;
}
goto skindidntfit;
}
} while (!isrectfree(x0, y0, dx, dy));
while (y0 && isrectfree(x0, y0-1, dx, 1))
y0--;
while (x0 && isrectfree(x0-1, y0, 1, dy))
x0--;
setrect(x0, y0, dx, dy);
shp[z].x = x0; shp[z].y = y0; //Overwrite size with top-left location
}
gvox->quad = (voxrect_t *)Xmalloc(gvox->qcnt*sizeof(voxrect_t));
gvox->mytex = (int32_t *)Xmalloc(gvox->mytexx*gvox->mytexy*sizeof(int32_t));
}
}
Bfree(shp); Bfree(zbit); Bfree(bx0);
return(gvox);
}
static void alloc_vcolhashead(void)
{
vcolhashead = (int32_t *)Xmalloc((vcolhashsizm1+1)*sizeof(int32_t));
memset(vcolhashead, -1, (vcolhashsizm1+1)*sizeof(int32_t));
}
static void alloc_vbit(void)
{
yzsiz = voxsiz.y*voxsiz.z;
int32_t i = ((voxsiz.x*yzsiz+31)>>3)+1;
vbit = (int32_t *)Xmalloc(i);
memset(vbit, 0, i);
}
static void read_pal(int32_t fil, int32_t pal[256])
{
klseek(fil, -768, SEEK_END);
for (int32_t i=0; i<256; i++)
{
char c[3];
kread(fil, c, 3);
//#if B_BIG_ENDIAN != 0
pal[i] = B_LITTLE32((c[0]<<18) + (c[1]<<10) + (c[2]<<2) + (i<<24));
//#endif
}
}
static int32_t loadvox(const char *filnam)
{
const int32_t fil = kopen4load(filnam, 0);
if (fil < 0)
return -1;
kread(fil, &voxsiz, sizeof(vec3_t));
#if B_BIG_ENDIAN != 0
voxsiz.x = B_LITTLE32(voxsiz.x);
voxsiz.y = B_LITTLE32(voxsiz.y);
voxsiz.z = B_LITTLE32(voxsiz.z);
#endif
voxpiv.x = (float)voxsiz.x * .5f;
voxpiv.y = (float)voxsiz.y * .5f;
voxpiv.z = (float)voxsiz.z * .5f;
int32_t pal[256];
read_pal(fil, pal);
pal[255] = -1;
vcolhashsizm1 = 8192-1;
alloc_vcolhashead();
alloc_vbit();
char *const tbuf = (char *)Xmalloc(voxsiz.z*sizeof(uint8_t));
klseek(fil, 12, SEEK_SET);
for (int32_t x=0; x<voxsiz.x; x++)
for (int32_t y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
{
kread(fil, tbuf, voxsiz.z);
for (int32_t z=voxsiz.z-1; z>=0; z--)
if (tbuf[z] != 255)
{
const int32_t i = j+z;
vbit[i>>5] |= (1<<SHIFTMOD32(i));
}
}
klseek(fil, 12, SEEK_SET);
for (int32_t x=0; x<voxsiz.x; x++)
for (int32_t y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
{
kread(fil, tbuf, voxsiz.z);
for (int32_t z=0; z<voxsiz.z; z++)
{
if (tbuf[z] == 255)
continue;
if (!x || !y || !z || x == voxsiz.x-1 || y == voxsiz.y-1 || z == voxsiz.z-1)
{
putvox(x, y, z, pal[tbuf[z]]);
continue;
}
const int32_t k = j+z;
if (isair(k-yzsiz) || isair(k+yzsiz) ||
isair(k-voxsiz.z) || isair(k+voxsiz.z) ||
isair(k-1) || isair(k+1))
{
putvox(x, y, z, pal[tbuf[z]]);
continue;
}
}
}
Bfree(tbuf);
kclose(fil);
return 0;
}
static int32_t loadkvx(const char *filnam)
{
int32_t i, mip1leng;
const int32_t fil = kopen4load(filnam, 0);
if (fil < 0)
return -1;
kread(fil, &mip1leng, 4); mip1leng = B_LITTLE32(mip1leng);
kread(fil, &voxsiz, sizeof(vec3_t));
#if B_BIG_ENDIAN != 0
voxsiz.x = B_LITTLE32(voxsiz.x);
voxsiz.y = B_LITTLE32(voxsiz.y);
voxsiz.z = B_LITTLE32(voxsiz.z);
#endif
kread(fil, &i, 4); voxpiv.x = (float)B_LITTLE32(i)*(1.f/256.f);
kread(fil, &i, 4); voxpiv.y = (float)B_LITTLE32(i)*(1.f/256.f);
kread(fil, &i, 4); voxpiv.z = (float)B_LITTLE32(i)*(1.f/256.f);
klseek(fil, (voxsiz.x+1)<<2, SEEK_CUR);
const int32_t ysizp1 = voxsiz.y+1;
i = voxsiz.x*ysizp1*sizeof(int16_t);
uint16_t *xyoffs = (uint16_t *)Xmalloc(i);
kread(fil, xyoffs, i);
for (i=i/sizeof(int16_t)-1; i>=0; i--)
xyoffs[i] = B_LITTLE16(xyoffs[i]);
int32_t pal[256];
read_pal(fil, pal);
alloc_vbit();
for (vcolhashsizm1=4096; vcolhashsizm1<(mip1leng>>1); vcolhashsizm1<<=1)
{
/* do nothing */
}
vcolhashsizm1--; //approx to numvoxs!
alloc_vcolhashead();
klseek(fil, 28+((voxsiz.x+1)<<2)+((ysizp1*voxsiz.x)<<1), SEEK_SET);
i = kfilelength(fil)-ktell(fil);
char *const tbuf = (char *)Xmalloc(i);
kread(fil, tbuf, i);
kclose(fil);
char *cptr = tbuf;
for (int32_t x=0; x<voxsiz.x; x++) //Set surface voxels to 1 else 0
for (int32_t y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
{
i = xyoffs[x*ysizp1+y+1] - xyoffs[x*ysizp1+y];
if (!i)
continue;
int32_t z1 = 0;
while (i)
{
const int32_t z0 = cptr[0];
const int32_t k = cptr[1];
cptr += 3;
if (!(cptr[-1]&16))
setzrange1(vbit, j+z1, j+z0);
i -= k+3;
z1 = z0+k;
setzrange1(vbit, j+z0, j+z1); // PK: oob in AMC TC dev if vbit alloc'd w/o +1
for (int32_t z=z0; z<z1; z++)
putvox(x, y, z, pal[*cptr++]);
}
}
Bfree(tbuf);
Bfree(xyoffs);
return 0;
}
static int32_t loadkv6(const char *filnam)
{
int32_t i;
const int32_t fil = kopen4load(filnam, 0);
if (fil < 0)
return -1;
kread(fil, &i, 4);
if (B_LITTLE32(i) != 0x6c78764b)
{
kclose(fil);
return(-1);
} //Kvxl
kread(fil, &voxsiz, sizeof(vec3_t));
#if B_BIG_ENDIAN != 0
voxsiz.x = B_LITTLE32(voxsiz.x);
voxsiz.y = B_LITTLE32(voxsiz.y);
voxsiz.z = B_LITTLE32(voxsiz.z);
#endif
kread(fil, &i, 4); voxpiv.x = (float)B_LITTLE32(i);
kread(fil, &i, 4); voxpiv.y = (float)B_LITTLE32(i);
kread(fil, &i, 4); voxpiv.z = (float)B_LITTLE32(i);
int32_t numvoxs;
kread(fil, &numvoxs, 4); numvoxs = B_LITTLE32(numvoxs);
uint16_t *const ylen = (uint16_t *)Xmalloc(voxsiz.x*voxsiz.y*sizeof(int16_t));
klseek(fil, 32+(numvoxs<<3)+(voxsiz.x<<2), SEEK_SET);
kread(fil, ylen, voxsiz.x*voxsiz.y*sizeof(int16_t));
for (i=voxsiz.x*voxsiz.y-1; i>=0; i--)
ylen[i] = B_LITTLE16(ylen[i]);
klseek(fil, 32, SEEK_SET);
alloc_vbit();
for (vcolhashsizm1=4096; vcolhashsizm1<numvoxs; vcolhashsizm1<<=1)
{
/* do nothing */
}
vcolhashsizm1--;
alloc_vcolhashead();
for (int32_t x=0; x<voxsiz.x; x++)
for (int32_t y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
{
int32_t z1 = voxsiz.z;
for (i=ylen[x*voxsiz.y+y]; i>0; i--)
{
char c[8];
kread(fil, c, 8); //b,g,r,a,z_lo,z_hi,vis,dir
const int32_t z0 = B_LITTLE16(B_UNBUF16(&c[4]));
if (!(c[6]&16))
setzrange1(vbit, j+z1, j+z0);
vbit[(j+z0)>>5] |= (1<<SHIFTMOD32(j+z0));
putvox(x, y, z0, B_LITTLE32(B_UNBUF32(&c[0]))&0xffffff);
z1 = z0+1;
}
}
Bfree(ylen);
kclose(fil);
return 0;
}
void voxfree(voxmodel_t *m)
{
if (!m)
return;
DO_FREE_AND_NULL(m->mytex);
DO_FREE_AND_NULL(m->quad);
DO_FREE_AND_NULL(m->texid);
Bfree(m);
}
voxmodel_t *voxload(const char *filnam)
{
int32_t is8bit, ret;
const int32_t i = Bstrlen(filnam)-4;
if (i < 0)
return NULL;
if (!Bstrcasecmp(&filnam[i], ".vox")) { ret = loadvox(filnam); is8bit = 1; }
else if (!Bstrcasecmp(&filnam[i], ".kvx")) { ret = loadkvx(filnam); is8bit = 1; }
else if (!Bstrcasecmp(&filnam[i], ".kv6")) { ret = loadkv6(filnam); is8bit = 0; }
//else if (!Bstrcasecmp(&filnam[i],".vxl")) { ret = loadvxl(filnam); is8bit = 0; }
else return NULL;
voxmodel_t *const vm = (ret >= 0) ? vox2poly() : NULL;
if (vm)
{
vm->mdnum = 1; //VOXel model id
vm->scale = vm->bscale = 1.f;
vm->siz.x = voxsiz.x; vm->siz.y = voxsiz.y; vm->siz.z = voxsiz.z;
vm->piv.x = voxpiv.x; vm->piv.y = voxpiv.y; vm->piv.z = voxpiv.z;
vm->is8bit = is8bit;
vm->texid = (uint32_t *)Xcalloc(MAXPALOOKUPS, sizeof(uint32_t));
}
DO_FREE_AND_NULL(shcntmal);
DO_FREE_AND_NULL(vbit);
DO_FREE_AND_NULL(vcol);
vnum = vmax = 0;
DO_FREE_AND_NULL(vcolhashead);
return vm;
}
//Draw voxel model as perfect cubes
int32_t polymost_voxdraw(voxmodel_t *m, const tspritetype *tspr)
{
// float clut[6] = {1.02,1.02,0.94,1.06,0.98,0.98};
float f, g, k0;
if ((intptr_t)m == (intptr_t)(-1)) // hackhackhack
return 0;
if ((tspr->cstat&48)==32)
return 0;
//updateanimation((md2model *)m,tspr);
vec3f_t m0 = { m->scale, m->scale, m->scale };
vec3f_t a0 = { 0, 0, ((globalorientation&8) ? -m->zadd : m->zadd)*m->scale };
//if (globalorientation&8) //y-flipping
//{
// m0.z = -m0.z; a0.z = -a0.z;
// //Add height of 1st frame (use same frame to prevent animation bounce)
// a0.z += m->zsiz*m->scale;
//}
//if (globalorientation&4) { m0.y = -m0.y; a0.y = -a0.y; } //x-flipping
k0 = m->bscale / 64.f;
f = (float) tspr->xrepeat * (256.f/320.f) * k0;
if ((sprite[tspr->owner].cstat&48)==16)
f *= 1.25f;
m0.x *= f; a0.x *= f; f = -f;
m0.y *= f; a0.y *= f;
f = (float) tspr->yrepeat * k0;
m0.z *= f; a0.z *= f;
k0 = (float) tspr->z;
if (globalorientation&128) k0 += (float) ((tilesiz[tspr->picnum].y*tspr->yrepeat)<<1);
f = (65536.f*512.f) / ((float)xdimen*viewingrange);
g = 32.f / ((float)xdimen*gxyaspect);
m0.y *= f; a0.y = (((float)(tspr->x-globalposx)) * (1.f/1024.f) + a0.y) * f;
m0.x *=-f; a0.x = (((float)(tspr->y-globalposy)) * -(1.f/1024.f) + a0.x) * -f;
m0.z *= g; a0.z = (((float)(k0 -globalposz)) * -(1.f/16384.f) + a0.z) * g;
float mat[16];
md3_vox_calcmat_common(tspr, &a0, f, mat);
//Mirrors
if (grhalfxdown10x < 0)
{
mat[0] = -mat[0];
mat[4] = -mat[4];
mat[8] = -mat[8];
mat[12] = -mat[12];
}
if (tspr->extra&TSPR_EXTRA_MDHACK)
{
bglDepthFunc(GL_LESS); //NEVER,LESS,(,L)EQUAL,GREATER,(NOT,G)EQUAL,ALWAYS
// bglDepthRange(0.0, 0.9999);
}
// 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);
float pc[4];
pc[0] = pc[1] = pc[2] =
(float)(numshades-min(max((globalshade * shadescale)+m->shadeoff, 0), numshades)) / (float)numshades;
hictinting_apply(pc, globalpal);
if (tspr->cstat&2)
pc[3] = !(tspr->cstat&512) ? 0.66f : 0.33f;
else
pc[3] = 1.0f;
pc[3] *= 1.0f - spriteext[tspr->owner].alpha;
if ((tspr->cstat&2) || spriteext[tspr->owner].alpha > 0.f || pc[3] < 1.0f)
bglEnable(GL_BLEND); //else bglDisable(GL_BLEND);
//------------
//transform to Build coords
float omat[16];
Bmemcpy(omat, mat, sizeof(omat));
f = 1.f/64.f;
g = m0.x*f; mat[0] *= g; mat[1] *= g; mat[2] *= g;
g = m0.y*f; mat[4] = omat[8]*g; mat[5] = omat[9]*g; mat[6] = omat[10]*g;
g =-m0.z*f; mat[8] = omat[4]*g; mat[9] = omat[5]*g; mat[10] = omat[6]*g;
//
mat[12] -= (m->piv.x*mat[0] + m->piv.y*mat[4] + (m->piv.z+m->siz.z*.5f)*mat[8]);
mat[13] -= (m->piv.x*mat[1] + m->piv.y*mat[5] + (m->piv.z+m->siz.z*.5f)*mat[9]);
mat[14] -= (m->piv.x*mat[2] + m->piv.y*mat[6] + (m->piv.z+m->siz.z*.5f)*mat[10]);
//
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);
const float ru = 1.f/((float)m->mytexx);
const float rv = 1.f/((float)m->mytexy);
#if (VOXBORDWIDTH == 0)
uhack[0] = ru*.125; uhack[1] = -uhack[0];
vhack[0] = rv*.125; vhack[1] = -vhack[0];
#endif
const float phack[2] = { 0, 1.f/256.f };
if (!m->texid[globalpal])
m->texid[globalpal] = gloadtex(m->mytex, m->mytexx, m->mytexy, m->is8bit, globalpal);
else
bglBindTexture(GL_TEXTURE_2D, m->texid[globalpal]);
bglBegin(GL_QUADS); // {{{
for (int32_t i=0, fi=0; i<m->qcnt; i++)
{
if (i == m->qfacind[fi])
{
f = 1 /*clut[fi++]*/;
bglColor4f(pc[0]*f, pc[1]*f, pc[2]*f, pc[3]*f);
}
const vert_t *const vptr = &m->quad[i].v[0];
const int32_t xx = vptr[0].x + vptr[2].x;
const int32_t yy = vptr[0].y + vptr[2].y;
const int32_t zz = vptr[0].z + vptr[2].z;
for (int32_t j=0; j<4; j++)
{
vec3f_t fp;
#if (VOXBORDWIDTH == 0)
bglTexCoord2f(((float)vptr[j].u)*ru + uhack[vptr[j].u!=vptr[0].u],
((float)vptr[j].v)*rv + vhack[vptr[j].v!=vptr[0].v]);
#else
bglTexCoord2f(((float)vptr[j].u)*ru, ((float)vptr[j].v)*rv);
#endif
fp.x = ((float)vptr[j].x) - phack[xx>vptr[j].x*2] + phack[xx<vptr[j].x*2];
fp.y = ((float)vptr[j].y) - phack[yy>vptr[j].y*2] + phack[yy<vptr[j].y*2];
fp.z = ((float)vptr[j].z) - phack[zz>vptr[j].z*2] + phack[zz<vptr[j].z*2];
bglVertex3fv((float *)&fp);
}
}
bglEnd(); // }}}
//------------
bglDisable(GL_CULL_FACE);
// bglPopAttrib();
if (tspr->extra&TSPR_EXTRA_MDHACK)
{
bglDepthFunc(GL_LESS); //NEVER,LESS,(,L)EQUAL,GREATER,(NOT,G)EQUAL,ALWAYS
// bglDepthRange(0.0, 0.99999);
}
bglLoadIdentity();
return 1;
}
#endif
//---------------------------------------- VOX LIBRARY ENDS ----------------------------------------