code:
//--------------------------------------- VOX LIBRARY BEGINS ---------------------------------------

#ifdef USE_OPENGL

#include "baselayer.h"
#include "build.h"
#include "cache1d.h"
#include "compat.h"
#include "engine_priv.h"
#include "glad/glad.h"
#include "hightile.h"
#include "kplib.h"
#include "mdsprite.h"
#include "palette.h"
#include "polymost.h"
#include "pragmas.h"
#include "texcache.h"
#include "vfs.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;
static voxrect_t *gquad;
static int32_t gqfacind[7];

//pitch must equal xsiz*4
uint32_t gloadtex_indexed(const int32_t *picbuf, int32_t xsiz, int32_t ysiz)
{
    const coltype *const pic = (const coltype *)picbuf;
    char *pic2 = (char *)Xmalloc(xsiz*ysiz*sizeof(char));

    for (bssize_t i=0; i < ysiz; i++)
    {
        for (bssize_t j=0; j < xsiz; j++)
        {
            pic2[j*ysiz+i] = pic[i*xsiz+j].a;
        }
    }

    uint32_t rtexid;

    glGenTextures(1, (GLuint *) &rtexid);
    buildgl_bindTexture(GL_TEXTURE_2D, rtexid);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, ysiz, xsiz, 0, GL_RED, GL_UNSIGNED_BYTE, (char *) pic2);

    Xfree(pic2);

    return rtexid;
}

uint32_t gloadtex(const 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 (bssize_t i=xsiz*ysiz-1; i>=0; i--)
        {
            coltype &tcol = pic2[i];
            tcol.b = cptr[pic[i].r];
            tcol.g = cptr[pic[i].g];
            tcol.r = cptr[pic[i].b];
            tcol.a = 255;

            hictinting_applypixcolor(&tcol, dapal, false);
        }
    }
    else
    {
        if (palookup[dapal] == NULL)
            dapal = 0;

        for (bssize_t i=xsiz*ysiz-1; i>=0; i--)
        {
            const int32_t ii = palookup[dapal][pic[i].a];

            pic2[i].b = cptr[curpalette[ii].b];
            pic2[i].g = cptr[curpalette[ii].g];
            pic2[i].r = cptr[curpalette[ii].r];
            pic2[i].a = 255;
        }
    }

    uint32_t rtexid;

    glGenTextures(1, (GLuint *) &rtexid);
    buildgl_bindTexture(GL_TEXTURE_2D, rtexid);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsiz, ysiz, 0, GL_RGBA, GL_UNSIGNED_BYTE, (char *) pic2);

    Xfree(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*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 = &gquad[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 (gqfacind[face] < 0)
        gqfacind[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)));
}

#ifdef USE_GLEXT
void voxvboalloc(voxmodel_t *vm)
{
    glGenBuffers(1, &vm->vbo);
    glGenBuffers(1, &vm->vboindex);

    GLint prevVBO = 0;
    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevVBO);
    buildgl_bindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->vboindex);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * 3 * 2 * vm->qcnt, vm->index, GL_STATIC_DRAW);
    buildgl_bindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevVBO);

    prevVBO = 0;
    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevVBO);
    buildgl_bindBuffer(GL_ARRAY_BUFFER, vm->vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 5 * 4 * vm->qcnt, vm->vertex, GL_STATIC_DRAW);
    buildgl_bindBuffer(GL_ARRAY_BUFFER, prevVBO);
}

void voxvbofree(voxmodel_t *vm)
{
    if (!vm->vbo)
        return;
    glDeleteBuffers(1, &vm->vbo);
    glDeleteBuffers(1, &vm->vboindex);
    vm->vbo = 0;
}
#endif

static voxmodel_t *vox2poly()
{
    gvox = (voxmodel_t *)Xcalloc(1, 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;
    int32_t 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++)
        gqfacind[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 :/
                        int j = 0;

                        for (int y=gmaxy; y; y--)
                            for (int 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
            }

            gquad = (voxrect_t *)Xrealloc(gquad, gvox->qcnt*sizeof(voxrect_t));
            gvox->mytex = (int32_t *)Xmalloc(gvox->mytexx*gvox->mytexy*sizeof(int32_t));
        }
    }

    Xfree(shp);
    Xfree(zbit);
    Xfree(bx0);

    const float phack[2] = { 0, 1.f / 256.f };

    gvox->vertex = (GLfloat *)Xmalloc(sizeof(GLfloat) * 5 * 4 * gvox->qcnt);
    gvox->index = (GLuint *)Xmalloc(sizeof(GLuint) * 3 * 2 * gvox->qcnt);

    const float ru = 1.f / ((float)gvox->mytexx);
    const float rv = 1.f / ((float)gvox->mytexy);

    for (int i = 0; i < gvox->qcnt; i++)
    {
        const vert_t *const vptr = &gquad[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 (int j=0; j<4; j++)
        {
            gvox->vertex[((i<<2)+j)*5+0] = ((float)vptr[j].x) - phack[xx>vptr[j].x*2] + phack[xx<vptr[j].x*2];
            gvox->vertex[((i<<2)+j)*5+1] = ((float)vptr[j].y) - phack[yy>vptr[j].y*2] + phack[yy<vptr[j].y*2];
            gvox->vertex[((i<<2)+j)*5+2] = ((float)vptr[j].z) - phack[zz>vptr[j].z*2] + phack[zz<vptr[j].z*2];

            gvox->vertex[((i<<2)+j)*5+3] = ((float)vptr[j].u)*ru;
            gvox->vertex[((i<<2)+j)*5+4] = ((float)vptr[j].v)*rv;
        }

        gvox->index[(i<<1)*3+0] = (i<<2)+0;
        gvox->index[(i<<1)*3+1] = (i<<2)+1;
        gvox->index[(i<<1)*3+2] = (i<<2)+2;

        gvox->index[((i<<1)+1)*3+0] = (i<<2)+0;
        gvox->index[((i<<1)+1)*3+1] = (i<<2)+2;
        gvox->index[((i<<1)+1)*3+2] = (i<<2)+3;
    }

    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(buildvfs_kfd fil, int32_t pal[256])
{
    klseek(fil, -768, SEEK_END);

    for (bssize_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 buildvfs_kfd fil = kopen4load(filnam, 0);
    if (fil == buildvfs_kfd_invalid)
        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 (bssize_t x=0; x<voxsiz.x; x++)
        for (bssize_t y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
        {
            kread(fil, 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));
                }
        }

    klseek(fil, 12, SEEK_SET);
    for (bssize_t x=0; x<voxsiz.x; x++)
        for (bssize_t y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
        {
            kread(fil, tbuf, voxsiz.z);

            for (bssize_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;
                }
            }
        }

    Xfree(tbuf);
    kclose(fil);

    return 0;
}

static int32_t loadkvx(const char *filnam)
{
    int32_t i, mip1leng;

    const buildvfs_kfd fil = kopen4load(filnam, 0);
    if (fil == buildvfs_kfd_invalid)
        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 (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;

    const buildvfs_kfd fil = kopen4load(filnam, 0);
    if (fil == buildvfs_kfd_invalid)
        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); i = B_LITTLE32(i); voxpiv.x = *(float*)&i;
    kread(fil, &i, 4); i = B_LITTLE32(i); voxpiv.y = *(float*)&i;
    kread(fil, &i, 4); i = B_LITTLE32(i); voxpiv.z = *(float*)&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 (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];
                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;
            }
        }

    Xfree(ylen);
    kclose(fil);

    return 0;
}

void voxfree(voxmodel_t *m)
{
    if (!m)
        return;

    voxvbofree(m);

    DO_FREE_AND_NULL(m->mytex);
    DO_FREE_AND_NULL(m->vertex);
    DO_FREE_AND_NULL(m->index);
    DO_FREE_AND_NULL(m->texid);

    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* vm = NULL;
    if (ret >= 0)
    {
        // file presence is guaranteed
        buildvfs_kfd filh = kopen4load(filnam, 0);
        int32_t const filelen = kfilelength(filh);
        kclose(filh);

        char voxcacheid[BMAX_PATH];
        texcache_calcid(voxcacheid, filnam, filelen, -1, -1);

        // static variable 'gvox' is normally defined by 'vox2poly' -- do same here for safety
        if (!(gvox = vm = voxcache_fetchvoxmodel(voxcacheid)))
        {
            vm = vox2poly();
            voxcache_writevoxmodel(voxcacheid, vm);
        }

        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;
}

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;

        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);
    Xfree(buffer);

    return vm;
}

//Draw voxel model as perfect cubes
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;

    buildgl_outputDebugMessage(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].mdangoff+512)&2047]*(1.f/(64.f*16384.f));
    a0.x += tspr->xoffset*sintable[(spriteext[tspr->owner].mdangoff)&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].mdposition_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].mdposition_offset.x-globalposx)) * (1.f/1024.f) + a0.y) * f;
    m0.x *=-f; a0.x = (((float)(tspr->y+spriteext[tspr->owner].mdposition_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)
    {
        buildgl_setDepthFunc(GL_LEQUAL); //NEVER,LESS,(,L)EQUAL,GREATER,(NOT,G)EQUAL,ALWAYS
//        glDepthRange(0.0, 0.9999);
    }

//    glPushAttrib(GL_POLYGON_BIT);

    if ((grhalfxdown10x >= 0) ^ ((globalorientation&8) != 0) ^ ((globalorientation&4) != 0))
        glFrontFace(GL_CW);
    else
        glFrontFace(GL_CCW);

    buildgl_setEnabled(GL_CULL_FACE);
    glCullFace(GL_BACK);

    float pc[4];

    pc[0] = pc[1] = pc[2] = ((float)numshades - min(max((globalshade * shadescale) + m->shadeoff, 0.f), (float)numshades)) / (float)numshades;
    polytintflags_t const tintflags = hictinting[globalpal].f;
    if (!(tintflags & HICTINT_PRECOMPUTED))
    {
        if (!(m->flags & 1))
            hictinting_apply(pc, globalpal);
        else globalnoeffect = 1;
    }

    // global tinting
    if (have_basepal_tint())
        hictinting_apply(pc, MAXPALOOKUPS - 1);

    if (!shadowHack && (voxflags[tiletovox[tspr->picnum]] & VF_NOTRANS) != VF_NOTRANS)
    {
        pc[3] = (tspr->cstat & CSTAT_SPRITE_TRANSLUCENT) ? glblend[tspr->blend].def[!!(tspr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT)].alpha : 1.0f;
        pc[3] *= 1.0f - spriteext[tspr->owner].alpha;

        handle_blend(!!(tspr->cstat & CSTAT_SPRITE_TRANSLUCENT), tspr->blend, !!(tspr->cstat & CSTAT_SPRITE_TRANSLUCENT_INVERT));

        if (!(tspr->cstat & CSTAT_SPRITE_TRANSLUCENT) || spriteext[tspr->owner].alpha > 0.f || pc[3] < 1.0f)
            buildgl_setEnabled(GL_BLEND);  // else buildgl_setDisabled(GL_BLEND);
    }
    else pc[3] = 1.f;
    //------------

    //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]);
    //
    glMatrixMode(GL_MODELVIEW); //Let OpenGL (and perhaps hardware :) handle the matrix rotation
    mat[3] = mat[7] = mat[11] = 0.f; mat[15] = 1.f;

    glLoadMatrixf(mat);

    char prevClamp = polymost_getClamp();
    polymost_setClamp(0);
    polymost_setFogEnabled(false);

    if (m->is8bit && polymost_useindexedtextures())
    {
        if (!m->texid8bit)
            m->texid8bit = gloadtex_indexed(m->mytex, m->mytexx, m->mytexy);
        else
            buildgl_bindTexture(GL_TEXTURE_2D, m->texid8bit);

        buildgl_bindSamplerObject(0, PTH_INDEXED);

        int visShade = int(fabsf(((tspr->x-globalposx)*gcosang+(tspr->y-globalposy)*gsinang)*globvis2*(1.f/(64.f*1024.f*2.f))));

        if (polymost_usetileshades())
        {
            globalshade = max(min(globalshade+visShade, numshades-1), 0);
            pc[0] = pc[1] = pc[2] = 1.f;
        }
        polymost_usePaletteIndexing(true);
        polymost_updatePalette();
        polymost_setTexturePosSize({ 0.f, 0.f, 1.f, 1.f });
        polymost_setHalfTexelSize({ 0.f, 0.f });
        polymost_setVisibility(0.f);
    }
    else
    {
        if (!m->texid[globalpal])
            m->texid[globalpal] = gloadtex(m->mytex, m->mytexx, m->mytexy, m->is8bit, globalpal);
        else
            buildgl_bindTexture(GL_TEXTURE_2D, m->texid[globalpal]);

        buildgl_bindSamplerObject(0, PTH_CLAMPED);

        polymost_usePaletteIndexing(false);
        polymost_setTexturePosSize({ 0.f, 0.f, 1.f, 1.f });
    }

    glColor4f(pc[0], pc[1], pc[2], pc[3]);
    buildgl_bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->vboindex);
    buildgl_bindBuffer(GL_ARRAY_BUFFER, m->vbo);

    glVertexPointer(3, GL_FLOAT, 5*sizeof(float), 0);

    glClientActiveTexture(GL_TEXTURE0);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), (GLvoid*) (3*sizeof(float)));

    glDrawElements(GL_TRIANGLES, m->qcnt*2*3, GL_UNSIGNED_INT, 0);

    buildgl_bindBuffer(GL_ARRAY_BUFFER, 0);
    buildgl_bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    polymost_setClamp(prevClamp);
    polymost_usePaletteIndexing(true);
    if (!nofog) polymost_setFogEnabled(true);
    polymost_resetVertexPointers();

    //------------
    buildgl_setDisabled(GL_CULL_FACE);
//    glPopAttrib();
    if (shadowHack)
    {
        buildgl_setDepthFunc(GL_LESS); //NEVER,LESS,(,L)EQUAL,GREATER,(NOT,G)EQUAL,ALWAYS
//        glDepthRange(0.0, 0.99999);
    }
    glLoadIdentity();

    globalnoeffect = 0;

    return 1;
}
#endif

//---------------------------------------- VOX LIBRARY ENDS ----------------------------------------


code:
#include "wiibits.h"
#include "baselayer.h"
#include "common.h"

#include <ogc/system.h>
#include <ogc/video.h>
#include <ogc/video_types.h>
#include <ogc/gx.h>
#include <ogc/pad.h>
#include <ogc/consol.h>
#include <ogc/lwp.h>
#include <ogc/lwp_watchdog.h>
#include <ogc/lwp_threads.h>
#include <ogc/ios.h>
#include <ogc/color.h>
#include <gctypes.h> // for bool

#include "vfs.h"

#ifdef __cplusplus
extern "C" {
#endif

extern buildvfs_FILE osdlog;

extern void L2Enhance();
extern void CON_EnableGecko(int channel,int safe);
extern bool fatInit(uint32_t cacheSize, bool setAsDefaultDevice);

extern void WII_InitVideoSystem(void);

extern unsigned char *xfb;
extern GXRModeObj *vmode;

#ifdef __cplusplus
}
#endif

enum
{
    Black = 0,
    Red = 1,
    Green = 2,
    Yellow = 3,
    Blue = 4,
    Magenta = 5,
    Cyan = 6,
    White = 7
};

static void ConsoleColor(uint8_t bgcolor, uint8_t bgbold, uint8_t fgcolor, uint8_t fgbold)
{
    Bprintf("\x1b[%u;%dm\x1b[%u;%dm", fgcolor + 30, fgbold, bgcolor + 40, bgbold);
}

static void print_centered(const int32_t width, const char *part1, const char *part2)
{
    const int32_t length = Bstrlen(part1) + Bstrlen(part2) + 1;
    const int32_t leftbuf = (width-1 - length) / 2;
    const int32_t rightbuf = width-1 - leftbuf - length;

    Bprintf("%*s%s %s%*s\n", leftbuf, " ", part1, part2, rightbuf, " ");
}

void wii_open(void)
{
    struct { int x, y; } ConsoleExtent;

    L2Enhance();
    CON_EnableGecko(1, 1);
    Bprintf("Console started\n");
    fatInit(28, true);

    // init the console for the title bar
    CON_InitEx(vmode, 0, 12, vmode->viWidth, 68);
    ConsoleColor(Blue, 0, White, 0);

    CON_GetMetrics(&ConsoleExtent.x, &ConsoleExtent.y);
    print_centered(ConsoleExtent.x, AppProperName, s_buildRev);
    print_centered(ConsoleExtent.x, "Built", s_buildTimestamp);

    VIDEO_WaitVSync();
    if (vmode->viTVMode&VI_NON_INTERLACE)
        VIDEO_WaitVSync();

    // reinit console below the title bar
    CON_InitEx(vmode, 8, 50, vmode->viWidth - 16, vmode->viHeight - 62);
    ConsoleColor(Black, 0, White, 0);
}

// Reset the video system to remove the startup console.
void wii_initgamevideo(void)
{
    WII_InitVideoSystem();
}

/*
 *  linux/lib/vsprintf.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
 * Wirzenius wrote this portably, Torvalds fucked it up :-)
 */

/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')

static int skip_atoi(const char **s)
{
    int i=0;

    while (is_digit(**s))
        i = i*10 + *((*s)++) - '0';
    return i;
}

#define ZEROPAD 1       /* pad with zero */
#define SIGN    2       /* unsigned/signed long */
#define PLUS    4       /* show plus */
#define SPACE   8       /* space if plus */
#define LEFT    16      /* left justified */
#define SPECIAL 32      /* 0x */
#define LARGE   64      /* use 'ABCDEF' instead of 'abcdef' */

#define do_div(n,base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res; })

static char * number(char * str, long num, int base, int size, int precision
    ,int type)
{
    char c,sign,tmp[66];
    const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
    int i;

    if (type & LARGE)
        digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    if (type & LEFT)
        type &= ~ZEROPAD;
    if (base < 2 || base > 36)
        return 0;
    c = (type & ZEROPAD) ? '0' : ' ';
    sign = 0;
    if (type & SIGN) {
        if (num < 0) {
            sign = '-';
            num = -num;
            size--;
        } else if (type & PLUS) {
            sign = '+';
            size--;
        } else if (type & SPACE) {
            sign = ' ';
            size--;
        }
    }
    if (type & SPECIAL) {
        if (base == 16)
            size -= 2;
        else if (base == 8)
            size--;
    }
    i = 0;
    if (num == 0)
        tmp[i++]='0';
    else while (num != 0)
        tmp[i++] = digits[do_div(num,base)];
    if (i > precision)
        precision = i;
    size -= precision;
    if (!(type&(ZEROPAD+LEFT)))
        while(size-->0)
            *str++ = ' ';
    if (sign)
        *str++ = sign;
    if (type & SPECIAL) {
        if (base==8)
            *str++ = '0';
        else if (base==16) {
            *str++ = '0';
            *str++ = digits[33];
        }
    }
    if (!(type & LEFT))
        while (size-- > 0)
            *str++ = c;
    while (i < precision--)
        *str++ = '0';
    while (i-- > 0)
        *str++ = tmp[i];
    while (size-- > 0)
        *str++ = ' ';
    return str;
}

static int exception_vsprintf(char *buf, const char *fmt, va_list args)
{
    int len;
    unsigned long num;
    int i, base;
    char * str;
    const char *s;

    int flags;      /* flags to number() */

    int field_width;    /* width of output field */
    int precision;      /* min. # of digits for integers; max
                   number of chars for from string */
    int qualifier;      /* 'h', 'l', or 'L' for integer fields */

    for (str=buf ; *fmt ; ++fmt) {
        if (*fmt != '%') {
            *str++ = *fmt;
            continue;
        }

        /* process flags */
        flags = 0;
        repeat:
            ++fmt;      /* this also skips first '%' */
            switch (*fmt) {
                case '-': flags |= LEFT; goto repeat;
                case '+': flags |= PLUS; goto repeat;
                case ' ': flags |= SPACE; goto repeat;
                case '#': flags |= SPECIAL; goto repeat;
                case '0': flags |= ZEROPAD; goto repeat;
                }

        /* get field width */
        field_width = -1;
        if (is_digit(*fmt))
            field_width = skip_atoi(&fmt);
        else if (*fmt == '*') {
            ++fmt;
            /* it's the next argument */
            field_width = va_arg(args, int);
            if (field_width < 0) {
                field_width = -field_width;
                flags |= LEFT;
            }
        }

        /* get the precision */
        precision = -1;
        if (*fmt == '.') {
            ++fmt;
            if (is_digit(*fmt))
                precision = skip_atoi(&fmt);
            else if (*fmt == '*') {
                ++fmt;
                /* it's the next argument */
                precision = va_arg(args, int);
            }
            if (precision < 0)
                precision = 0;
        }

        /* get the conversion qualifier */
        qualifier = -1;
        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
            qualifier = *fmt;
            ++fmt;
        }

        /* default base */
        base = 10;

        switch (*fmt) {
        case 'c':
            if (!(flags & LEFT))
                while (--field_width > 0)
                    *str++ = ' ';
            *str++ = (unsigned char) va_arg(args, int);
            while (--field_width > 0)
                *str++ = ' ';
            continue;

        case 's':
            s = va_arg(args, char *);
            if (!s)
                s = "<NULL>";

            len = strnlen(s, precision);

            if (!(flags & LEFT))
                while (len < field_width--)
                    *str++ = ' ';
            for (i = 0; i < len; ++i)
                *str++ = *s++;
            while (len < field_width--)
                *str++ = ' ';
            continue;

        case 'p':
            if (field_width == -1) {
                field_width = 2*sizeof(void *);
                flags |= ZEROPAD;
            }
            str = number(str,
                (unsigned long) va_arg(args, void *), 16,
                field_width, precision, flags);
            continue;

        case 'n':
            if (qualifier == 'l') {
                long * ip = va_arg(args, long *);
                *ip = (str - buf);
            } else {
                int * ip = va_arg(args, int *);
                *ip = (str - buf);
            }
            continue;

        case '%':
            *str++ = '%';
            continue;

        /* integer number formats - set up the flags and "break" */
        case 'o':
            base = 8;
            break;

        case 'X':
            flags |= LARGE;
        case 'x':
            base = 16;
            break;

        case 'd':
        case 'i':
            flags |= SIGN;
        case 'u':
            break;

        default:
            *str++ = '%';
            if (*fmt)
                *str++ = *fmt;
            else
                --fmt;
            continue;
        }
        if (qualifier == 'l')
            num = va_arg(args, unsigned long);
        else if (qualifier == 'h') {
            num = (unsigned short) va_arg(args, int);
            if (flags & SIGN)
                num = (short) num;
        } else if (flags & SIGN)
            num = va_arg(args, int);
        else
            num = va_arg(args, unsigned int);
        str = number(str, num, base, field_width, precision, flags);
    }
    *str = '\0';
    return str-buf;
}

#define DOUTBUFSIZE 256

static int exception_output;

static void exception_printf(const char *str, ...)
{
    char outstr[DOUTBUFSIZE];

    int len;

    va_list args;

    va_start(args, str);
    len = exception_vsprintf(outstr, str, args);
    va_end(args);

    if (exception_output)
        Bfputs(outstr, osdlog);
    else
        Bwrite(2, outstr, len);
}

/*-------------------------------------------------------------

exception.c -- PPC exception handling support

Copyright (C) 2004
Michael Wiedenbauer (shagkur)
Dave Murphy (WinterMute)

Copyright (C) 2014
Modified for EDuke32

This software is provided 'as-is', without any express or implied
warranty.  In no event will the authors be held liable for any
damages arising from the use of this software.

Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:

1.  The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.

2.  Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.

3.  This notice may not be removed or altered from any source
distribution.

-------------------------------------------------------------*/

//#define _EXC_DEBUG

#define CPU_STACK_TRACE_DEPTH       10

typedef struct _framerec {
    struct _framerec *up;
    void *lr;
} frame_rec, *frame_rec_t;

static void *exception_xfb = (void*)0xC1700000;         //we use a static address above ArenaHi.

#ifdef __cplusplus
extern "C" {
#endif

extern void udelay(int us);
extern void __reload();
extern void VIDEO_SetFramebuffer(void *);
extern void __console_init(void *framebuffer,int xstart,int ystart,int xres,int yres,int stride);

extern void __wrap_c_default_exceptionhandler(frame_context *pCtx);

#ifdef __cplusplus
}
#endif

static const char *exception_name[NUM_EXCEPTIONS] = {
        "System Reset", "Machine Check", "DSI", "ISI",
        "Interrupt", "Alignment", "Program", "Floating Point",
        "Decrementer", "System Call", "Trace", "Performance",
        "IABR", "Reserved", "Thermal"};

extern void __wrap_c_default_exceptionhandler(frame_context *pCtx);

static void _cpu_print_stack(void *pc,void *lr,void *r1)
{
    u32 i = 0;
    frame_rec_t l,p = (frame_rec_t)lr;

    l = p;
    p = (frame_rec_t)r1;
    if(!p) __asm__ __volatile__("mr %0,%%r1" : "=r"(p));

    exception_printf("\n\tSTACK DUMP:");

    for(i=0;i<CPU_STACK_TRACE_DEPTH-1 && p->up;p=p->up,i++) {
        if(i%4) exception_printf(" --> ");
        else {
            if(i>0) exception_printf(" -->\n\t");
            else exception_printf("\n\t");
        }

        switch(i) {
            case 0:
                if(pc) exception_printf("%p",pc);
                break;
            case 1:
                if(!l) l = (frame_rec_t)mfspr(8);
                exception_printf("%p",(void*)l);
                break;
            default:
                exception_printf("%p",(void*)(p->up->lr));
                break;
        }
    }
}

static void waitForReload(void)
{
    u32 level;

    exception_printf("\tPress the Reset button to return to loader.\n\n");

    while ( 1 )
    {
        if( SYS_ResetButtonDown() )
        {
            exception_printf("\tReturning to loader...\n");
            _CPU_ISR_Disable(level);
            __reload ();
        }

        udelay(20000);
    }
}

void __wrap_c_default_exceptionhandler(frame_context *pCtx)
{
    GX_AbortFrame();
    VIDEO_SetFramebuffer(exception_xfb);
    __console_init(exception_xfb,20,20,640,574,1280);
    CON_EnableGecko(1, true);

    exception_printf("\n\n\n");

    if (osdlog && osdlogfn)
    {
        exception_printf("\tAn unrecoverable error has occurred.\n\tPlease submit \"%s\" to the %s developers.\n\n", osdlogfn, AppProperName);
        exception_output = 1;
    }

    exception_printf("\tException: %s\n\n", exception_name[pCtx->EXCPT_Number]);
    exception_printf("\tGPR00 %08X GPR08 %08X GPR16 %08X GPR24 %08X\n",pCtx->GPR[0], pCtx->GPR[8], pCtx->GPR[16], pCtx->GPR[24]);
    exception_printf("\tGPR01 %08X GPR09 %08X GPR17 %08X GPR25 %08X\n",pCtx->GPR[1], pCtx->GPR[9], pCtx->GPR[17], pCtx->GPR[25]);
    exception_printf("\tGPR02 %08X GPR10 %08X GPR18 %08X GPR26 %08X\n",pCtx->GPR[2], pCtx->GPR[10], pCtx->GPR[18], pCtx->GPR[26]);
    exception_printf("\tGPR03 %08X GPR11 %08X GPR19 %08X GPR27 %08X\n",pCtx->GPR[3], pCtx->GPR[11], pCtx->GPR[19], pCtx->GPR[27]);
    exception_printf("\tGPR04 %08X GPR12 %08X GPR20 %08X GPR28 %08X\n",pCtx->GPR[4], pCtx->GPR[12], pCtx->GPR[20], pCtx->GPR[28]);
    exception_printf("\tGPR05 %08X GPR13 %08X GPR21 %08X GPR29 %08X\n",pCtx->GPR[5], pCtx->GPR[13], pCtx->GPR[21], pCtx->GPR[29]);
    exception_printf("\tGPR06 %08X GPR14 %08X GPR22 %08X GPR30 %08X\n",pCtx->GPR[6], pCtx->GPR[14], pCtx->GPR[22], pCtx->GPR[30]);
    exception_printf("\tGPR07 %08X GPR15 %08X GPR23 %08X GPR31 %08X\n",pCtx->GPR[7], pCtx->GPR[15], pCtx->GPR[23], pCtx->GPR[31]);
    exception_printf("\tLR %08X SRR0 %08x SRR1 %08x MSR %08x\n", pCtx->LR, pCtx->SRR0, pCtx->SRR1,pCtx->MSR);
    exception_printf("\tDAR %08X DSISR %08X\n", mfspr(19), mfspr(18));

    _cpu_print_stack((void*)pCtx->SRR0,(void*)pCtx->LR,(void*)pCtx->GPR[1]);

    if((pCtx->EXCPT_Number==EX_DSI) || (pCtx->EXCPT_Number==EX_FP)) {
        u32 i;
        u32 *pAdd = (u32*)pCtx->SRR0;
        exception_printf("\n\n\tCODE DUMP:\n");
        for (i=0; i<12; i+=4)
            exception_printf("\t%p:  %08X %08X %08X %08X\n",
            &(pAdd[i]),pAdd[i], pAdd[i+1], pAdd[i+2], pAdd[i+3]);
    }

    if (exception_output)
    {
        exception_output = 0;
        MAYBE_FCLOSE_AND_NULL(osdlog);
    }
    else
    {
        exception_printf("\n");
    }

    waitForReload();

    return;
}

repo_name: orochi/nblood

license: mit


code:
// Windows layer-independent code
// (c) EDuke32 developers and contributors. All rights reserved. ;)

#include "winbits.h"

#include "baselayer.h"
#include "build.h"
#include "cache1d.h"
#include "compat.h"
#include "osd.h"
#include "renderlayer.h"

#include <mmsystem.h>
#include <winnls.h>
#include <winternl.h>

#include <system_error>

#ifdef BITNESS64
# define EBACKTRACEDLL "ebacktrace1-64.dll"
#else
# define EBACKTRACEDLL "ebacktrace1.dll"
#endif

int32_t    win_priorityclass;
char       win_silentvideomodeswitch;
static int win_silentfocuschange;

static HANDLE  g_singleInstanceSemaphore = nullptr;
static int32_t win_togglecomposition;
static int32_t win_systemtimermode;
static int32_t win_performancemode;

static OSVERSIONINFOEX osv;
static FARPROC ntdll_wine_get_version;
static char const *enUSLayoutString = "00000409";

DWM_TIMING_INFO timingInfo;

static HMODULE hPOWRPROF;
static GUID *systemPowerSchemeGUID;

typedef DWORD(WINAPI *PFNPOWERGETACTIVESCHEME)(HKEY, GUID **);
typedef DWORD(WINAPI *PFNPOWERSETACTIVESCHEME)(HKEY, CONST GUID *);

static PFNPOWERGETACTIVESCHEME powrprof_PowerGetActiveScheme;
static PFNPOWERSETACTIVESCHEME powrprof_PowerSetActiveScheme;

void windowsSetupTimer(int const useNtTimer)
{
    if (ntdll_wine_get_version)
        return;

    typedef HRESULT(NTAPI* PFNSETTIMERRESOLUTION)(ULONG, BOOLEAN, PULONG);
    typedef HRESULT(NTAPI* PFNQUERYTIMERRESOLUTION)(PULONG, PULONG, PULONG);

    TIMECAPS timeCaps;

    if (timeGetDevCaps(&timeCaps, sizeof(TIMECAPS)) == MMSYSERR_NOERROR)
    {
#if defined RENDERTYPESDL && SDL_MAJOR_VERSION >= 2
        int const onBattery = (SDL_GetPowerInfo(NULL, NULL) == SDL_POWERSTATE_ON_BATTERY);
#else
        static constexpr int const onBattery = 0;
#endif
        static int     timePeriod;
        static ULONG   ntTimerRes;
        static HMODULE hNTDLL = GetModuleHandle("ntdll.dll");

        static PFNQUERYTIMERRESOLUTION ntdll_NtQueryTimerResolution;
        static PFNSETTIMERRESOLUTION   ntdll_NtSetTimerResolution;

        if (useNtTimer)
        {
            if (!onBattery)
            {
                ntdll_NtQueryTimerResolution = (PFNQUERYTIMERRESOLUTION) (void(*))GetProcAddress(hNTDLL, "NtQueryTimerResolution");
                ntdll_NtSetTimerResolution   = (PFNSETTIMERRESOLUTION)   (void(*))GetProcAddress(hNTDLL, "NtSetTimerResolution");

                if (ntdll_NtQueryTimerResolution == nullptr || ntdll_NtSetTimerResolution == nullptr)
                {
                    LOG_F(ERROR, "NtQueryTimerResolution or NtSetTimerResolution symbols missing from ntdll.dll!");
                    goto failsafe;
                }

                ULONG minRes, maxRes, actualRes;

                ntdll_NtQueryTimerResolution(&minRes, &maxRes, &actualRes);

                if (ntTimerRes != 0)
                {
                    if (ntTimerRes == actualRes)
                        return;

                    ntdll_NtSetTimerResolution(actualRes, FALSE, &actualRes);
                }

                ntdll_NtSetTimerResolution(maxRes, TRUE, &actualRes);

                ntTimerRes = actualRes;
                timePeriod = 0;

                if (!win_silentfocuschange)
                    LOG_F(INFO, "Initialized %.1fms system timer", actualRes / 10000.0);

                return;
            }
            else if (!win_silentfocuschange)
                LOG_F(WARNING, "Low-latency timer mode not supported on battery power!");
        }
        else if (ntTimerRes != 0)
        {
            ntdll_NtSetTimerResolution(ntTimerRes, FALSE, &ntTimerRes);
            ntTimerRes = 0;
        }

failsafe:
        int const newPeriod = min(max(timeCaps.wPeriodMin, 1u << onBattery), timeCaps.wPeriodMax);

        if (timePeriod != 0)
        {
            if (timePeriod == newPeriod)
                return;

            timeEndPeriod(timePeriod);
        }

        timeBeginPeriod(newPeriod);

        timePeriod = newPeriod;
        ntTimerRes = 0;

        if (!win_silentfocuschange)
            LOG_F(INFO, "Initialized %ums system timer", newPeriod);

        return;
    }

    LOG_F(ERROR, "Unable to configure system timer!");
}

//
// CheckWinVersion() -- check to see what version of Windows we happen to be running under
//
BOOL windowsGetVersion(void)
{
    HMODULE hNTDLL = GetModuleHandle("ntdll.dll");

    if (hNTDLL)
        ntdll_wine_get_version = GetProcAddress(hNTDLL, "wine_get_version");

    ZeroMemory(&osv, sizeof(osv));
    osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    if (GetVersionEx((LPOSVERSIONINFOA)&osv)) return TRUE;

    osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

    if (GetVersionEx((LPOSVERSIONINFOA)&osv)) return TRUE;

    return FALSE;
}

static void windowsPrintVersion(void)
{
    const char *ver = "";

    switch (osv.dwPlatformId)
    {
        case VER_PLATFORM_WIN32_WINDOWS:
            if (osv.dwMinorVersion < 10)
                ver = "95";
            else if (osv.dwMinorVersion < 90)
                ver = "98";
            else
                ver = "ME";
            break;

        case VER_PLATFORM_WIN32_NT:
            switch (osv.dwMajorVersion)
            {
                case 5:
                    switch (osv.dwMinorVersion)
                    {
                        case 0: ver = "2000"; break;
                        case 1: ver = "XP"; break;
                        case 2: ver = osv.wProductType == VER_NT_WORKSTATION ? "XP x64" : "Server 2003"; break;
                    }
                    break;

                case 6:
                    {
                        static const char *client[] = { "Vista", "7", "8", "8.1" };
                        static const char *server[] = { "Server 2008", "Server 2008 R2", "Server 2012", "Server 2012 R2" };
                        ver = ((osv.wProductType == VER_NT_WORKSTATION) ? client : server)[osv.dwMinorVersion % ARRAY_SIZE(client)];
                    }
                    break;

                case 10:
                    switch (osv.wProductType)
                    {
                        case VER_NT_WORKSTATION: ver = "10"; break;
                        default: ver = "Server"; break;
                    }
                    break;
            }
            break;
    }

    char *buf = (char *)Xcalloc(1, 256);
    int len;

    if (ntdll_wine_get_version)
        len = Bsprintf(buf, "Wine %s, identifying as Windows %s", (char *)ntdll_wine_get_version(), ver);
    else
    {
        len = Bsprintf(buf, "Windows %s", ver);

        if (osv.dwPlatformId != VER_PLATFORM_WIN32_NT || osv.dwMajorVersion < 6)
        {
            Bstrcat(buf, " (UNSUPPORTED)");
            len = Bstrlen(buf);
        }
    }

    // service packs
    if (osv.szCSDVersion[0])
    {
        buf[len] = 32;
        Bstrcat(&buf[len], osv.szCSDVersion);
    }

    LOG_F(INFO, "OS: %s (build %lu.%lu.%lu)", buf, osv.dwMajorVersion, osv.dwMinorVersion, osv.dwBuildNumber);
    Xfree(buf);
}

//
// win_checkinstance() -- looks for another instance of a Build app
//
int windowsCheckAlreadyRunning(void)
{
    if (!g_singleInstanceSemaphore) return 1;
    return (WaitForSingleObject(g_singleInstanceSemaphore,0) != WAIT_TIMEOUT);
}

typedef void (*dllSetString)(const char*);

//
// win_open(), win_init(), win_setvideomode(), win_close() -- shared code
//
int windowsPreInit(void)
{
    if (!windowsGetVersion())
    {
        windowsShowError("This version of Windows is not supported.");
        return -1;
    }

    windowsGetSystemKeyboardLayout();
    windowsGetSystemKeyboardLayoutName();

#ifdef DEBUGGINGAIDS
    HMODULE ebacktrace = LoadLibraryA(EBACKTRACEDLL);
    if (ebacktrace)
    {
        dllSetString SetTechnicalName = (dllSetString)(void(*))GetProcAddress(ebacktrace, "SetTechnicalName");
        dllSetString SetProperName = (dllSetString)(void(*))GetProcAddress(ebacktrace, "SetProperName");

        if (SetTechnicalName)
            SetTechnicalName(AppTechnicalName);

        if (SetProperName)
            SetProperName(AppProperName);
    }
#endif

    g_singleInstanceSemaphore = CreateSemaphore(NULL, 1,1, WindowClass);

    return 0;
}

static int osdcmd_win_systemtimermode(osdcmdptr_t parm)
{
    int const r = osdcmd_cvar_set(parm);

    if (r != OSDCMD_OK)
        return r;

    windowsSetupTimer(win_systemtimermode);

    return OSDCMD_OK;
}

void windowsPlatformInit(void)
{
    static osdcvardata_t cvars_win[] = {
        { "win_togglecomposition", "disables Windows Vista/7 DWM composition", (void *)&win_togglecomposition, CVAR_BOOL, 0, 1 },

        { "win_priorityclass",
          "Windows process priority class:\n"
          "  -1: do not alter process priority\n"
          "   0: HIGH when game has focus, NORMAL when interacting with other programs\n"
          "   1: NORMAL when game has focus, IDLE when interacting with other programs",
          (void *)&win_priorityclass, CVAR_INT, -1, 1 },

        { "win_performancemode",
          "Windows performance mode:\n"
          "   0: do not alter performance mode\n"
          "   1: use HIGH PERFORMANCE power plan when game has focus",
          (void *)&win_performancemode, CVAR_BOOL, 0, 1 },

    };

    static osdcvardata_t win_timer_cvar = { "win_systemtimermode",
                                            "Windows timer interrupt resolution:\n"
                                            "   0: 1.0ms\n"
                                            "   1: 0.5ms low-latency"
#if defined RENDERTYPESDL && SDL_MAJOR_VERSION >= 2
                                            "\nThis option has no effect when running on battery power.",
#else
                                            ,
#endif
                                            (void *)&win_systemtimermode, CVAR_BOOL, 0, 1 };

    OSD_RegisterCvar(&win_timer_cvar, osdcmd_win_systemtimermode);

    for (int i=0; i<ARRAY_SSIZE(cvars_win); i++)
        OSD_RegisterCvar(&cvars_win[i], osdcmd_cvar_set);

    windowsPrintVersion();
    windowsSetupTimer(0);

    if (osv.dwMajorVersion >= 6)
    {
        if (!hPOWRPROF && (hPOWRPROF = GetModuleHandle("powrprof.dll")))
        {
            powrprof_PowerGetActiveScheme = (PFNPOWERGETACTIVESCHEME)(void(*))GetProcAddress(hPOWRPROF, "PowerGetActiveScheme");
            powrprof_PowerSetActiveScheme = (PFNPOWERSETACTIVESCHEME)(void(*))GetProcAddress(hPOWRPROF, "PowerSetActiveScheme");

            if (powrprof_PowerGetActiveScheme == nullptr || powrprof_PowerSetActiveScheme == nullptr)
                LOG_F(ERROR, "PowerGetActiveScheme or PowerSetActiveScheme symbols missing from powrprof.dll!");
            else if (!systemPowerSchemeGUID)
                powrprof_PowerGetActiveScheme(NULL, &systemPowerSchemeGUID);
        }
    }
}

typedef UINT D3DKMT_HANDLE;
typedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;

typedef struct _D3DKMT_OPENADAPTERFROMHDC
{
    HDC           hDc;
    D3DKMT_HANDLE hAdapter;
    LUID          AdapterLuid;

    D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
} D3DKMT_OPENADAPTERFROMHDC;

typedef struct _D3DKMT_CLOSEADAPTER
{
    D3DKMT_HANDLE hAdapter;
} D3DKMT_CLOSEADAPTER;

typedef struct _D3DKMT_WAITFORVERTICALBLANKEVENT
{
    D3DKMT_HANDLE hAdapter;
    D3DKMT_HANDLE hDevice;

    D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;
} D3DKMT_WAITFORVERTICALBLANKEVENT;

typedef NTSTATUS(APIENTRY *PFND3DKMTOPENADAPTERFROMHDC)(D3DKMT_OPENADAPTERFROMHDC *);
typedef NTSTATUS(APIENTRY *PFND3DKMTCLOSEADAPTER)(D3DKMT_CLOSEADAPTER *);
typedef NTSTATUS(APIENTRY *PFND3DKMTWAITFORVERTICALBLANKEVENT)(D3DKMT_WAITFORVERTICALBLANKEVENT *);

typedef HRESULT(WINAPI *PFNDWMENABLECOMPOSITION)(UINT);
typedef HRESULT(WINAPI *PFNDWMGETCOMPOSITIONTIMINGINFO)(HWND, DWM_TIMING_INFO *);
typedef HRESULT(WINAPI *PFNDWMISCOMPOSITIONENABLED)(BOOL *);
typedef HRESULT(WINAPI *PFNDWMFLUSH)(void);

static HMODULE hDWMApi;
static PFNDWMFLUSH dwmapi_DwmFlush;
static PFNDWMISCOMPOSITIONENABLED dwmapi_DwmIsCompositionEnabled;

void windowsWaitForVBlank(void)
{
    // if we don't have these, we aren't going to have the WDDM functions below either, so bailing here is fine.
    if (osv.dwMajorVersion < 6 || !dwmapi_DwmFlush || !dwmapi_DwmIsCompositionEnabled)
        return;

    static int useDWMsync;

    // here comes the voodoo bullshit ;)
    static HMODULE hGDI32;
    static PFND3DKMTOPENADAPTERFROMHDC        gdi32_D3DKMTOpenAdapterFromHdc;
    static PFND3DKMTCLOSEADAPTER              gdi32_D3DKMTCloseAdapter;
    static PFND3DKMTWAITFORVERTICALBLANKEVENT gdi32_D3DKMTWaitForVBlank;

    if (!hGDI32 && (hGDI32 = GetModuleHandle("gdi32.dll")))
    {
        gdi32_D3DKMTOpenAdapterFromHdc = (PFND3DKMTOPENADAPTERFROMHDC)        (void(*))GetProcAddress(hGDI32, "D3DKMTOpenAdapterFromHdc");
        gdi32_D3DKMTCloseAdapter       = (PFND3DKMTCLOSEADAPTER)              (void(*))GetProcAddress(hGDI32, "D3DKMTCloseAdapter");
        gdi32_D3DKMTWaitForVBlank      = (PFND3DKMTWAITFORVERTICALBLANKEVENT) (void(*))GetProcAddress(hGDI32, "D3DKMTWaitForVerticalBlankEvent");
    }

    if (useDWMsync || !fullscreen || !gdi32_D3DKMTOpenAdapterFromHdc || !gdi32_D3DKMTCloseAdapter || !gdi32_D3DKMTWaitForVBlank)
    {
dwm:
        // if we don't have the better APIs but composition is enabled, this is sometimes good enough
        BOOL compositionEnabled = false;

        if (SUCCEEDED(dwmapi_DwmIsCompositionEnabled(&compositionEnabled)) && compositionEnabled && dwmapi_DwmFlush() != S_OK)
            LOG_F(ERROR, "Failed flushing DWM!");

        return;
    }

    MONITORINFOEX mi = {};
    mi.cbSize = sizeof(mi);
    GetMonitorInfo(MonitorFromWindow(win_gethwnd(), MONITOR_DEFAULTTONULL), &mi);

    D3DKMT_OPENADAPTERFROMHDC activeAdapter = {};
    activeAdapter.hDc = CreateDC(mi.szDevice, mi.szDevice, nullptr, nullptr);

    if (activeAdapter.hDc == nullptr)
    {
        LOG_F(ERROR, "null device context for display: %s windowx: %d windowy: %d.", mi.szDevice, g_windowPos.x, g_windowPos.y);
        useDWMsync = 1;
        goto dwm;
    }

    auto status = gdi32_D3DKMTOpenAdapterFromHdc(&activeAdapter);
    DeleteDC(activeAdapter.hDc);

    if (NT_SUCCESS(status))
    {
        D3DKMT_WAITFORVERTICALBLANKEVENT vBlankEvent = { activeAdapter.hAdapter, 0, activeAdapter.VidPnSourceId };

        if (NT_SUCCESS(status = gdi32_D3DKMTWaitForVBlank(&vBlankEvent)))
        {
            // the D3DKMT_CLOSEADAPTER struct only contains one member, and it's
            // the same as the first member in D3DKMT_WAITFORVERTICALBLANKEVENT
            if (NT_SUCCESS(status = gdi32_D3DKMTCloseAdapter((D3DKMT_CLOSEADAPTER *)&vBlankEvent)))
                return;
            else
                LOG_F(ERROR, "D3DKMTCloseAdapter() FAILED! NTSTATUS: 0x%x.", (unsigned)status);
        }
        else
            LOG_F(ERROR, "D3DKMTWaitForVerticalBlankEvent() FAILED! NTSTATUS: 0x%x.", (unsigned)status);
    }
    else
        LOG_F(ERROR, "D3DKMTOpenAdapterFromHdc() FAILED! NTSTATUS: 0x%x.", (unsigned)status);

    LOG_F(ERROR, "Unable to use D3DKMT, falling back to DWM sync.");

    useDWMsync = 1;
    goto dwm;
}

void windowsDwmSetupComposition(int const compEnable)
{
    if (osv.dwMajorVersion < 6)
        return;

    static PFNDWMENABLECOMPOSITION        dwmapi_DwmEnableComposition;
    static PFNDWMGETCOMPOSITIONTIMINGINFO dwmapi_DwmGetCompositionTimingInfo;

    if (!hDWMApi && (hDWMApi = GetModuleHandle("dwmapi.dll")))
    {
        dwmapi_DwmEnableComposition        = (PFNDWMENABLECOMPOSITION)        (void(*))GetProcAddress(hDWMApi, "DwmEnableComposition");
        dwmapi_DwmFlush                    = (PFNDWMFLUSH)                    (void(*))GetProcAddress(hDWMApi, "DwmFlush");
        dwmapi_DwmGetCompositionTimingInfo = (PFNDWMGETCOMPOSITIONTIMINGINFO) (void(*))GetProcAddress(hDWMApi, "DwmGetCompositionTimingInfo");
        dwmapi_DwmIsCompositionEnabled     = (PFNDWMISCOMPOSITIONENABLED)     (void(*))GetProcAddress(hDWMApi, "DwmIsCompositionEnabled");
    }

    if (dwmapi_DwmGetCompositionTimingInfo)
    {
        timingInfo = {};
        timingInfo.cbSize = sizeof(DWM_TIMING_INFO);

        // the HWND parameter was deprecated in Windows 8.1 because DWM always syncs to the primary monitor's refresh...

        HRESULT result = dwmapi_DwmGetCompositionTimingInfo(nullptr, &timingInfo);

        if (FAILED(result))
            LOG_F(ERROR, "DwmGetCompositionTimingInfo() FAILED! HRESULT: %s (0x%x).",
                         std::system_category().message(result).c_str(), (unsigned)result);
    }

    if (win_togglecomposition && dwmapi_DwmEnableComposition && osv.dwMinorVersion < 2)
    {
        dwmapi_DwmEnableComposition(compEnable);

        if (!win_silentvideomodeswitch)
            VLOG_F(LOG_GFX, "%sabling DWM desktop composition", (compEnable) ? "En" : "Dis");
    }
}

void windowsPlatformCleanup(void)
{
    if (g_singleInstanceSemaphore)
        CloseHandle(g_singleInstanceSemaphore);

    windowsSetKeyboardLayout(windowsGetSystemKeyboardLayoutName());

    if (systemPowerSchemeGUID)
    {
        powrprof_PowerSetActiveScheme(NULL, systemPowerSchemeGUID);
        LocalFree(systemPowerSchemeGUID);
    }
}

//
// GetWindowsErrorMsg() -- gives a pointer to a static buffer containing the Windows error message
//
LPTSTR windowsGetErrorMessage(DWORD code)
{
    static TCHAR lpMsgBuf[1024];

    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL, code,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPTSTR)lpMsgBuf, 1024, NULL);

    return lpMsgBuf;
}

// Keyboard layout switching

static char const * windowsDecodeKeyboardLayoutName(char const * keyboardLayout)
{
    int const   localeID = Bstrtol(keyboardLayout, NULL, 16);
    static char localeName[16];

    int const result = GetLocaleInfo(MAKELCID(localeID, SORT_DEFAULT), LOCALE_SNAME, localeName, ARRAY_SIZE(localeName));

    if (!result)
    {
        LOG_F(ERROR, "Unable to decode name for locale ID '%d': %s.", localeID, windowsGetErrorMessage(GetLastError()));
        return keyboardLayout;
    }

    return localeName;
}

void windowsSetKeyboardLayout(char const *layout, int focusChanged /*= 0*/)
{
    char layoutName[KL_NAMELENGTH];

    GetKeyboardLayoutName(layoutName);

    if (!Bstrcmp(layoutName, layout))
        return;

    //if (!win_silentfocuschange)
    {
        if (focusChanged)
            VLOG_F(LOG_GFX, "Window focus changed");

        if (layout == enUSLayoutString)
            VLOG_F(LOG_INPUT, "Loaded %s keyboard layout", windowsDecodeKeyboardLayoutName(layout));
        else
            VLOG_F(LOG_INPUT, "Restored %s keyboard layout", windowsDecodeKeyboardLayoutName(layout));
    }

    static int enUSLoaded;
    static HKL enUSLayout;

    if (layout == enUSLayoutString)
    {
        if (enUSLoaded)
            ActivateKeyboardLayout(enUSLayout, KLF_SETFORPROCESS);
        else if ((enUSLayout = LoadKeyboardLayout(enUSLayoutString, KLF_ACTIVATE | KLF_SETFORPROCESS | KLF_SUBSTITUTE_OK)))
            enUSLoaded = true;
    }
    else
        ActivateKeyboardLayout(windowsGetSystemKeyboardLayout(), KLF_SETFORPROCESS);
}

char *windowsGetSystemKeyboardLayoutName(void)
{
    static char systemLayoutName[KL_NAMELENGTH];
    static int layoutSaved;

    if (!layoutSaved)
    {
        if (!GetKeyboardLayoutName(systemLayoutName))
            LOG_F(ERROR, "Error determining system keyboard layout: %s.", windowsGetErrorMessage(GetLastError()));

        layoutSaved = true;
    }

    return systemLayoutName;
}

HKL windowsGetSystemKeyboardLayout(void)
{
    static HKL systemLayout;
    static int layoutSaved;

    if (!layoutSaved)
    {
        systemLayout = GetKeyboardLayout(0);
        layoutSaved  = true;
    }

    return systemLayout;
}

void windowsHandleFocusChange(int const appactive)
{
#ifndef DEBUGGINGAIDS
    win_silentfocuschange = true;
#endif

    if (appactive)
    {
        if (win_priorityclass != -1)
            SetPriorityClass(GetCurrentProcess(), win_priorityclass ? BELOW_NORMAL_PRIORITY_CLASS : HIGH_PRIORITY_CLASS);

        windowsSetupTimer(win_systemtimermode);
        windowsSetKeyboardLayout(enUSLayoutString, true);

        if (win_performancemode && systemPowerSchemeGUID)
            powrprof_PowerSetActiveScheme(NULL, &GUID_MIN_POWER_SAVINGS);
    }
    else
    {
        if (win_priorityclass != -1)
            SetPriorityClass(GetCurrentProcess(), win_priorityclass ? IDLE_PRIORITY_CLASS : ABOVE_NORMAL_PRIORITY_CLASS);

        windowsSetupTimer(0);
        windowsSetKeyboardLayout(windowsGetSystemKeyboardLayoutName(), true);

        if (systemPowerSchemeGUID)
            powrprof_PowerSetActiveScheme(NULL, systemPowerSchemeGUID);
    }

    win_silentfocuschange = false;
}

//
// ShowErrorBox() -- shows an error message box
//
void windowsShowError(const char *m)
{
    TCHAR msg[1024];

    wsprintf(msg, "%s: %s", m, windowsGetErrorMessage(GetLastError()));
    MessageBox(0, msg, apptitle, MB_OK|MB_ICONSTOP);
}

//
// Miscellaneous
//
int windowsGetCommandLine(char **argvbuf)
{
    int buildargc = 0;

    *argvbuf = Bstrdup(GetCommandLine());

    if (*argvbuf)
    {
        char quoted = 0, instring = 0, swallownext = 0;
        char *wp;
        for (const char *p = wp = *argvbuf; *p; p++)
        {
            if (*p == ' ')
            {
                if (instring)
                {
                    if (!quoted)
                    {
                        // end of a string
                        *(wp++) = 0;
                        instring = 0;
                    }
                    else
                        *(wp++) = *p;
                }
            }
            else if (*p == '"' && !swallownext)
            {
                if (instring)
                {
                    if (quoted && p[1] == ' ')
                    {
                        // end of a string
                        *(wp++) = 0;
                        instring = 0;
                    }
                    quoted = !quoted;
                }
                else
                {
                    instring = 1;
                    quoted = 1;
                    buildargc++;
                }
            }
            else if (*p == '\\' && p[1] == '"' && !swallownext)
                swallownext = 1;
            else
            {
                if (!instring)
                    buildargc++;

                instring = 1;
                *(wp++) = *p;
                swallownext = 0;
            }
        }
        *wp = 0;
    }

    return buildargc;
}