mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-21 23:00:44 +00:00
67b1963e7c
There are effectively two states - the one in the backend and a local one in the drawer for the render list which is supposed to eliminate some of the more costly repeated calls. This higher level state was cached globally, which did not work anymore because the real render state could be changed elsewhere without this code realizing it. All this means that the render list drawer must create a new state cache for each call and also must apply its current pending render state before leaving to ensure that everything is properly reset.
1224 lines
34 KiB
C++
1224 lines
34 KiB
C++
//--------------------------------------- VOX LIBRARY BEGINS ---------------------------------------
|
|
|
|
#ifdef USE_OPENGL
|
|
|
|
#include "compat.h"
|
|
#include "build.h"
|
|
#include "pragmas.h"
|
|
#include "baselayer.h"
|
|
#include "engine_priv.h"
|
|
#include "polymost.h"
|
|
#include "mdsprite.h"
|
|
#include "v_video.h"
|
|
#include "flatvertices.h"
|
|
#include "hw_renderstate.h"
|
|
#include "texturemanager.h"
|
|
|
|
#include "palette.h"
|
|
#include "../../glbackend/glbackend.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;
|
|
|
|
class FStaticImage : public FImageSource
|
|
{
|
|
TArray<uint8_t> buffer;
|
|
|
|
public:
|
|
FStaticImage(int w, int h, TArray<uint8_t>& srcbuffer)
|
|
{
|
|
Width = w;
|
|
Height = h;
|
|
buffer = std::move(srcbuffer);
|
|
bUseGamePalette = false;
|
|
}
|
|
|
|
int CopyPixels(FBitmap* bmp, int conversion) override
|
|
{
|
|
*bmp = FBitmap(buffer.Data(), 4*Width, Width, Height);
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
//pitch must equal xsiz*4
|
|
static FGameTexture *gloadtex(const int32_t *picbuf, int32_t xsiz, int32_t ysiz, int32_t is8bit, const PalEntry *paldata)
|
|
{
|
|
// Correct for GL's RGB order; also apply gamma here:
|
|
const coltype *const pic = (const coltype *)picbuf;
|
|
TArray<uint8_t> buffer(xsiz * ysiz * sizeof(PalEntry));
|
|
PalEntry* pic2 = (PalEntry*)buffer.Data();
|
|
|
|
if (!is8bit)
|
|
{
|
|
for (int i=xsiz*ysiz-1; i>=0; i--)
|
|
{
|
|
pic2[i].r = pic[i].r;
|
|
pic2[i].g = pic[i].g;
|
|
pic2[i].b = pic[i].b;
|
|
pic2[i].a = 255;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i=xsiz*ysiz-1; i>=0; i--)
|
|
{
|
|
const int32_t ii = pic[i].a;
|
|
|
|
pic2[i].r = paldata[ii].r;
|
|
pic2[i].g = paldata[ii].g;
|
|
pic2[i].b = paldata[ii].b;
|
|
pic2[i].a = 255;
|
|
}
|
|
}
|
|
auto tt = MakeGameTexture(new FImageTexture(new FStaticImage(xsiz, ysiz, buffer)), "", ETextureType::Special);
|
|
TexMan.AddGameTexture(tt, false);
|
|
return tt;
|
|
}
|
|
|
|
static int32_t getvox(int32_t x, int32_t y, int32_t z)
|
|
{
|
|
z += x*yzsiz + y*voxsiz.z;
|
|
|
|
for (x=vcolhashead[(z*214013LL)&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*214013LL)&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 (bssize_t yy=0; yy<y; yy++, lptr+=gvox->mytexx)
|
|
for (bssize_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 (bssize_t yy=VOXBORDWIDTH; yy<y+VOXBORDWIDTH; yy++)
|
|
for (bssize_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 (bssize_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 (bssize_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));
|
|
}
|
|
|
|
static 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 (bssize_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 (bssize_t y=0; y<voxsiz.y; y++)
|
|
for (bssize_t x=0; x<=voxsiz.x; x++)
|
|
for (bssize_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 (bssize_t z=0; z<voxsiz.z; z++)
|
|
for (bssize_t x=0; x<=voxsiz.x; x++)
|
|
for (bssize_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 (bssize_t x=0; x<voxsiz.x; x++)
|
|
for (bssize_t y=0; y<=voxsiz.y; y++)
|
|
for (bssize_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 (bssize_t y=gmaxy; y; y--)
|
|
for (bssize_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 (bssize_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
|
|
{
|
|
Xfree(zbit);
|
|
|
|
//Re-generate shp[].x/y (box sizes) from shcnt (now head indices) for next pass :/
|
|
j = 0;
|
|
|
|
for (bssize_t y=gmaxy; y; y--)
|
|
for (bssize_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));
|
|
}
|
|
}
|
|
|
|
Xfree(shp); Xfree(zbit); Xfree(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(FileReader &fil, int32_t pal[256])
|
|
{
|
|
fil.Seek(-768, FileReader::SeekEnd);
|
|
|
|
for (bssize_t i=0; i<256; i++)
|
|
{
|
|
char c[3];
|
|
fil.Read(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)
|
|
{
|
|
auto fil = fileSystem.OpenFileReader(filnam);
|
|
if (!fil.isOpen())
|
|
return -1;
|
|
|
|
fil.Read(&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));
|
|
|
|
fil.Seek(12, FileReader::SeekSet);
|
|
for (bssize_t x=0; x<voxsiz.x; x++)
|
|
for (bssize_t y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
|
|
{
|
|
fil.Read(tbuf, voxsiz.z);
|
|
|
|
for (bssize_t z=voxsiz.z-1; z>=0; z--)
|
|
if (tbuf[z] != 255)
|
|
{
|
|
const int32_t i = j+z;
|
|
vbit[i>>5] |= (1<<SHIFTMOD32(i));
|
|
}
|
|
}
|
|
|
|
fil.Seek(12, FileReader::SeekSet);
|
|
for (bssize_t x=0; x<voxsiz.x; x++)
|
|
for (bssize_t y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
|
|
{
|
|
fil.Read(tbuf, voxsiz.z);
|
|
|
|
for (bssize_t z=0; z<voxsiz.z; z++)
|
|
{
|
|
if (tbuf[z] == TRANSPARENT_INDEX)
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
Xfree(tbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32_t loadkvx(const char *filnam)
|
|
{
|
|
int32_t i, mip1leng;
|
|
|
|
auto fil = fileSystem.OpenFileReader(filnam);
|
|
if (!fil.isOpen())
|
|
return -1;
|
|
|
|
fil.Read(&mip1leng, 4); mip1leng = B_LITTLE32(mip1leng);
|
|
fil.Read(&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
|
|
fil.Read(&i, 4); voxpiv.x = (float)B_LITTLE32(i)*(1.f/256.f);
|
|
fil.Read(&i, 4); voxpiv.y = (float)B_LITTLE32(i)*(1.f/256.f);
|
|
fil.Read(&i, 4); voxpiv.z = (float)B_LITTLE32(i)*(1.f/256.f);
|
|
fil.Seek((voxsiz.x+1)<<2, FileReader::SeekCur);
|
|
|
|
const int32_t ysizp1 = voxsiz.y+1;
|
|
i = voxsiz.x*ysizp1*sizeof(int16_t);
|
|
|
|
uint16_t *xyoffs = (uint16_t *)Xmalloc(i);
|
|
fil.Read(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();
|
|
|
|
fil.Seek(28+((voxsiz.x+1)<<2)+((ysizp1*voxsiz.x)<<1), FileReader::SeekSet);
|
|
|
|
i = fil.GetLength() - fil.Tell();
|
|
char *const tbuf = (char *)Xmalloc(i);
|
|
|
|
fil.Read(tbuf, i);
|
|
|
|
char *cptr = tbuf;
|
|
|
|
for (bssize_t x=0; x<voxsiz.x; x++) //Set surface voxels to 1 else 0
|
|
for (bssize_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 (bssize_t z=z0; z<z1; z++)
|
|
putvox(x, y, z, pal[*cptr++]);
|
|
}
|
|
}
|
|
|
|
Xfree(tbuf);
|
|
Xfree(xyoffs);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32_t loadkv6(const char *filnam)
|
|
{
|
|
int32_t i;
|
|
|
|
auto fil = fileSystem.OpenFileReader(filnam);
|
|
if (!fil.isOpen())
|
|
return -1;
|
|
|
|
fil.Read(&i, 4);
|
|
if (B_LITTLE32(i) != 0x6c78764b)
|
|
{
|
|
return -1;
|
|
} //Kvxl
|
|
|
|
fil.Read(&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
|
|
fil.Read(&i, 4); voxpiv.x = (float)B_LITTLE32(i);
|
|
fil.Read(&i, 4); voxpiv.y = (float)B_LITTLE32(i);
|
|
fil.Read(&i, 4); voxpiv.z = (float)B_LITTLE32(i);
|
|
|
|
int32_t numvoxs;
|
|
fil.Read(&numvoxs, 4); numvoxs = B_LITTLE32(numvoxs);
|
|
|
|
uint16_t *const ylen = (uint16_t *)Xmalloc(voxsiz.x*voxsiz.y*sizeof(int16_t));
|
|
|
|
fil.Seek(32+(numvoxs<<3)+(voxsiz.x<<2), FileReader::SeekSet);
|
|
fil.Read(ylen, voxsiz.x*voxsiz.y*sizeof(int16_t));
|
|
for (i=voxsiz.x*voxsiz.y-1; i>=0; i--)
|
|
ylen[i] = B_LITTLE16(ylen[i]);
|
|
|
|
fil.Seek(32, FileReader::SeekSet);
|
|
|
|
alloc_vbit();
|
|
|
|
for (vcolhashsizm1=4096; vcolhashsizm1<numvoxs; vcolhashsizm1<<=1)
|
|
{
|
|
/* do nothing */
|
|
}
|
|
vcolhashsizm1--;
|
|
alloc_vcolhashead();
|
|
|
|
for (bssize_t x=0; x<voxsiz.x; x++)
|
|
for (bssize_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];
|
|
fil.Read(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;
|
|
}
|
|
}
|
|
|
|
Xfree(ylen);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void voxfree(voxmodel_t *m)
|
|
{
|
|
if (!m)
|
|
return;
|
|
|
|
DO_FREE_AND_NULL(m->mytex);
|
|
DO_FREE_AND_NULL(m->quad);
|
|
Xfree(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->texture = nullptr;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
voxmodel_t *loadkvxfrombuf(const char *kvxbuffer, int32_t length)
|
|
{
|
|
int32_t i, mip1leng;
|
|
|
|
if (!kvxbuffer)
|
|
return NULL;
|
|
|
|
char *buffer = (char*)Xmalloc(length);
|
|
if (!buffer)
|
|
return NULL;
|
|
|
|
Bmemcpy(buffer, kvxbuffer, length);
|
|
|
|
int32_t *longptr = (int32_t*)buffer;
|
|
|
|
mip1leng = *longptr++; mip1leng = B_LITTLE32(mip1leng);
|
|
if (mip1leng > length - 4)
|
|
{
|
|
// Invalid KVX file
|
|
Xfree(buffer);
|
|
return NULL;
|
|
}
|
|
memcpy(&voxsiz, longptr, sizeof(vec3_t));
|
|
longptr += 3;
|
|
#if B_BIG_ENDIAN != 0
|
|
voxsiz.x = B_LITTLE32(voxsiz.x);
|
|
voxsiz.y = B_LITTLE32(voxsiz.y);
|
|
voxsiz.z = B_LITTLE32(voxsiz.z);
|
|
#endif
|
|
i = *longptr++; voxpiv.x = (float)B_LITTLE32(i)*(1.f/256.f);
|
|
i = *longptr++; voxpiv.y = (float)B_LITTLE32(i)*(1.f/256.f);
|
|
i = *longptr++; voxpiv.z = (float)B_LITTLE32(i)*(1.f/256.f);
|
|
longptr += voxsiz.x+1;
|
|
|
|
const int32_t ysizp1 = voxsiz.y+1;
|
|
i = voxsiz.x*ysizp1*sizeof(int16_t);
|
|
uint16_t *xyoffs = (uint16_t*)longptr;
|
|
|
|
for (i=i/sizeof(int16_t)-1; i>=0; i--)
|
|
xyoffs[i] = B_LITTLE16(xyoffs[i]);
|
|
|
|
const char *paloff = buffer+length-768;
|
|
int32_t pal[256];
|
|
|
|
for (bssize_t i=0; i<256; i++)
|
|
{
|
|
const char *c = &paloff[i*3];
|
|
//#if B_BIG_ENDIAN != 0
|
|
pal[i] = B_LITTLE32((c[0]<<18) + (c[1]<<10) + (c[2]<<2) + (i<<24));
|
|
//#endif
|
|
}
|
|
|
|
alloc_vbit();
|
|
|
|
for (vcolhashsizm1=4096; vcolhashsizm1<(mip1leng>>1); vcolhashsizm1<<=1)
|
|
{
|
|
/* do nothing */
|
|
}
|
|
vcolhashsizm1--; //approx to numvoxs!
|
|
alloc_vcolhashead();
|
|
|
|
const char *cptr = buffer+28+((voxsiz.x+1)<<2)+((ysizp1*voxsiz.x)<<1);
|
|
|
|
for (bssize_t x=0; x<voxsiz.x; x++) //Set surface voxels to 1 else 0
|
|
for (bssize_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 (bssize_t z=z0; z<z1; z++)
|
|
putvox(x, y, z, pal[*cptr++]);
|
|
}
|
|
}
|
|
|
|
voxmodel_t *const vm = vox2poly();
|
|
|
|
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 = 1;
|
|
}
|
|
|
|
DO_FREE_AND_NULL(shcntmal);
|
|
DO_FREE_AND_NULL(vbit);
|
|
DO_FREE_AND_NULL(vcol);
|
|
vnum = vmax = 0;
|
|
DO_FREE_AND_NULL(vcolhashead);
|
|
Xfree(buffer);
|
|
|
|
return vm;
|
|
}
|
|
|
|
//Draw voxel model as perfect cubes
|
|
// Note: This is a hopeless mess that totally forfeits any chance of using a vertex buffer with its messy coordinate adjustments. :(
|
|
int32_t polymost_voxdraw(voxmodel_t *m, tspriteptr_t const tspr)
|
|
{
|
|
// float clut[6] = {1.02,1.02,0.94,1.06,0.98,0.98};
|
|
float f, g, k0, zoff;
|
|
|
|
if ((intptr_t)m == (intptr_t)(-1)) // hackhackhack
|
|
return 0;
|
|
|
|
if ((tspr->cstat&48)==32)
|
|
return 0;
|
|
|
|
polymost_outputGLDebugMessage(3, "polymost_voxdraw(m:%p, tspr:%p)", m, tspr);
|
|
|
|
//updateanimation((md2model *)m,tspr);
|
|
|
|
vec3f_t m0 = { m->scale, m->scale, m->scale };
|
|
vec3f_t a0 = { 0, 0, m->zadd*m->scale };
|
|
|
|
k0 = m->bscale / 64.f;
|
|
f = (float) tspr->xrepeat * (256.f/320.f) * k0;
|
|
if ((sprite[tspr->owner].cstat&48)==16)
|
|
{
|
|
f *= 1.25f;
|
|
a0.y -= tspr->xoffset*sintable[(spriteext[tspr->owner].angoff+512)&2047]*(1.f/(64.f*16384.f));
|
|
a0.x += tspr->xoffset*sintable[(spriteext[tspr->owner].angoff)&2047]*(1.f/(64.f*16384.f));
|
|
}
|
|
|
|
if (globalorientation&8) { m0.z = -m0.z; a0.z = -a0.z; } //y-flipping
|
|
if (globalorientation&4) { m0.x = -m0.x; a0.x = -a0.x; a0.y = -a0.y; } //x-flipping
|
|
|
|
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+spriteext[tspr->owner].position_offset.z);
|
|
f = ((globalorientation&8) && (sprite[tspr->owner].cstat&48)!=0) ? -4.f : 4.f;
|
|
k0 -= (tspr->yoffset*tspr->yrepeat)*f*m->bscale;
|
|
zoff = m->siz.z*.5f;
|
|
if (!(tspr->cstat&128))
|
|
zoff += m->piv.z;
|
|
else if ((tspr->cstat&48) != 48)
|
|
{
|
|
zoff += m->piv.z;
|
|
zoff -= m->siz.z*.5f;
|
|
}
|
|
if (globalorientation&8) zoff = m->siz.z-zoff;
|
|
|
|
f = (65536.f*512.f) / ((float)xdimen*viewingrange);
|
|
g = 32.f / ((float)xdimen*gxyaspect);
|
|
|
|
int const shadowHack = !!(tspr->clipdist & TSPR_FLAGS_MDHACK);
|
|
|
|
m0.y *= f; a0.y = (((float)(tspr->x+spriteext[tspr->owner].position_offset.x-globalposx)) * (1.f/1024.f) + a0.y) * f;
|
|
m0.x *=-f; a0.x = (((float)(tspr->y+spriteext[tspr->owner].position_offset.y-globalposy)) * -(1.f/1024.f) + a0.x) * -f;
|
|
m0.z *= g; a0.z = (((float)(k0 -globalposz - shadowHack)) * -(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 (shadowHack)
|
|
{
|
|
GLInterface.SetDepthFunc(DF_LEqual);
|
|
}
|
|
|
|
|
|
int winding = ((grhalfxdown10x >= 0) ^ ((globalorientation & 8) != 0) ^ ((globalorientation & 4) != 0)) ? Winding_CW : Winding_CCW;
|
|
GLInterface.SetCull(Cull_Back, winding);
|
|
|
|
float pc[4];
|
|
|
|
pc[0] = pc[1] = pc[2] = 1.f;
|
|
|
|
|
|
if (!shadowHack)
|
|
{
|
|
pc[3] = (tspr->cstat & 2) ? glblend[tspr->blend].def[!!(tspr->cstat & 512)].alpha : 1.0f;
|
|
pc[3] *= 1.0f - spriteext[tspr->owner].alpha;
|
|
|
|
SetRenderStyleFromBlend(!!(tspr->cstat & 2), tspr->blend, !!(tspr->cstat & 512));
|
|
|
|
if (!(tspr->cstat & 2) || spriteext[tspr->owner].alpha > 0.f || pc[3] < 1.0f)
|
|
GLInterface.EnableBlend(true); // else GLInterface.EnableBlend(false);
|
|
}
|
|
else pc[3] = 1.f;
|
|
GLInterface.SetShade(std::max(0, globalshade), numshades);
|
|
//------------
|
|
|
|
//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] + zoff*mat[8]);
|
|
mat[13] -= (m->piv.x*mat[1] + m->piv.y*mat[5] + zoff*mat[9]);
|
|
mat[14] -= (m->piv.x*mat[2] + m->piv.y*mat[6] + zoff*mat[10]);
|
|
//
|
|
//Let OpenGL (and perhaps hardware :) handle the matrix rotation
|
|
mat[3] = mat[7] = mat[11] = 0.f; mat[15] = 1.f;
|
|
|
|
for (int i = 0; i < 15; i++) mat[i] *= 1024.f;
|
|
|
|
GLInterface.SetMatrix(Matrix_Model, 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 1
|
|
int palId = TRANSLATION(Translation_Remap + curbasepal, globalpal);
|
|
auto palette = GPalette.TranslationToTable(palId);
|
|
if (!m->texIds) m->texIds = new TMap<int, FGameTexture*>;
|
|
auto pTex = m->texIds->CheckKey(palId);
|
|
FGameTexture* htex;
|
|
if (!pTex)
|
|
{
|
|
htex = gloadtex(m->mytex, m->mytexx, m->mytexy, m->is8bit, palette->Palette);
|
|
m->texIds->Insert(palId, htex);
|
|
}
|
|
else
|
|
{
|
|
htex = *pTex;
|
|
}
|
|
|
|
GLInterface.SetPalswap(globalpal);
|
|
// The texture here is already translated.
|
|
GLInterface.SetTexture(-1, htex, 0/*TRANSLATION(Translation_Remap + curbasepal, globalpal)*/, CLAMP_NOFILTER_XY);
|
|
|
|
// This must be done after setting up the texture.
|
|
auto& h = lookups.tables[globalpal];
|
|
if (h.tintFlags & (TINTF_USEONART|TINTF_ALWAYSUSEART))
|
|
GLInterface.SetTinting(h.tintFlags, h.tintColor, h.tintColor);
|
|
else
|
|
GLInterface.SetTinting(-1, 0xffffff, 0xffffff);
|
|
|
|
#endif
|
|
|
|
auto data = screen->mVertexData->AllocVertices(m->qcnt * 6);
|
|
auto vt = data.first;
|
|
|
|
int qstart = data.second;
|
|
int qdone = 0;
|
|
for (bssize_t i=0, fi=0; i<m->qcnt; i++)
|
|
{
|
|
if (i == m->qfacind[fi])
|
|
{
|
|
f = 1 /*clut[fi++]*/;
|
|
if (qdone > 0)
|
|
{
|
|
GLInterface.Draw(DT_Triangles, qstart, qdone * 6);
|
|
qstart += qdone * 6;
|
|
qdone = 0;
|
|
}
|
|
GLInterface.SetColor(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 (bssize_t jj=0; jj<6; jj++, vt++)
|
|
{
|
|
static uint8_t trix[] = { 0, 1, 2, 0, 2, 3 };
|
|
int j = trix[jj];
|
|
#if (VOXBORDWIDTH == 0)
|
|
vt->SetTexCoord(((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
|
|
vt->SetTexCoord(((float)vptr[j].u)*ru, ((float)vptr[j].v)*rv);
|
|
#endif
|
|
vt->SetVertex(
|
|
((float)vptr[j].x) - phack[xx > vptr[j].x * 2] + phack[xx < vptr[j].x * 2],
|
|
((float)vptr[j].y) - phack[yy > vptr[j].y * 2] + phack[yy < vptr[j].y * 2],
|
|
((float)vptr[j].z) - phack[zz > vptr[j].z * 2] + phack[zz < vptr[j].z * 2]);
|
|
}
|
|
qdone++;
|
|
}
|
|
|
|
GLInterface.Draw(DT_Triangles, qstart, qdone * 6);
|
|
//------------
|
|
GLInterface.SetCull(Cull_None);
|
|
|
|
if (shadowHack)
|
|
{
|
|
GLInterface.SetDepthFunc(DF_Less);
|
|
}
|
|
GLInterface.SetIdentityMatrix(Matrix_Model);
|
|
GLInterface.SetFadeDisable(false);
|
|
GLInterface.SetTinting(-1, 0xffffff, 0xffffff);
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
//---------------------------------------- VOX LIBRARY ENDS ----------------------------------------
|