voxmodel.cpp 35 KB
Newer Older
1
2
3
4
5
//--------------------------------------- VOX LIBRARY BEGINS ---------------------------------------

#ifdef USE_OPENGL

#include "baselayer.h"
6
7
8
#include "build.h"
#include "cache1d.h"
#include "compat.h"
9
#include "engine_priv.h"
10
#include "glad/glad.h"
11
12
#include "hightile.h"
#include "kplib.h"
13
#include "mdsprite.h"
14
#include "palette.h"
15
16
17
#include "polymost.h"
#include "pragmas.h"
#include "texcache.h"
18
19
#include "vfs.h"

20
21
22
23
//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;
24

25
26
27
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;
28

29
static vec2_u16_t *shp;
30
static int32_t *shcntmal, *shcnt = 0, shcntp;
31

32
33
static int32_t mytexo5, *zbit, gmaxx, gmaxy, garea, pow2m1[33];
static voxmodel_t *gvox;
34
35
static voxrect_t *gquad;
static int32_t gqfacind[7];
36

37

38
//pitch must equal xsiz*4
39
40
41
42
43
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));

44
    for (int i=0; i < ysiz; i++)
45
    {
46
        for (int j=0; j < xsiz; j++)
47
48
49
50
51
52
53
54
        {
            pic2[j*ysiz+i] = pic[i*xsiz+j].a;
        }
    }

    uint32_t rtexid;

    glGenTextures(1, (GLuint *) &rtexid);
55
    buildgl_bindTexture(GL_TEXTURE_2D, rtexid);
56
57
58
59
    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);
60
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
61
62
63

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

64
    Xfree(pic2);
65
66
67
68

    return rtexid;
}

69
uint32_t gloadtex(const int32_t *picbuf, int32_t xsiz, int32_t ysiz, int32_t is8bit, int32_t dapal)
70
71
72
73
{
    const char *const cptr = &britable[gammabrightness ? 0 : curbrightness][0];

    // Correct for GL's RGB order; also apply gamma here:
74
75
    const coltype *const pic = (const coltype *)picbuf;
    coltype *pic2 = (coltype *)Xmalloc(xsiz*ysiz*sizeof(coltype));
76
77
78

    if (!is8bit)
    {
79
        for (int i=xsiz*ysiz-1; i>=0; i--)
80
        {
81
82
83
84
85
86
            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;

87
            hictinting_applypixcolor(&tcol, dapal, false);
88
89
90
91
92
93
94
        }
    }
    else
    {
        if (palookup[dapal] == NULL)
            dapal = 0;

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

99
100
101
            pic2[i].b = cptr[curpalette[ii].b];
            pic2[i].g = cptr[curpalette[ii].g];
            pic2[i].r = cptr[curpalette[ii].r];
102
103
104
105
            pic2[i].a = 255;
        }
    }

106
107
    uint32_t rtexid;

108
    glGenTextures(1, (GLuint *) &rtexid);
109
    buildgl_bindTexture(GL_TEXTURE_2D, rtexid);
110
111
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
112
113
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
114
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsiz, ysiz, 0, GL_RGBA, GL_UNSIGNED_BYTE, (char *) pic2);
115

116
    Xfree(pic2);
117
118
119
120
121
122
123

    return rtexid;
}

static int32_t getvox(int32_t x, int32_t y, int32_t z)
{
    z += x*yzsiz + y*voxsiz.z;
124

Richard Gobeille's avatar
Richard Gobeille committed
125
    for (x=vcolhashead[(z*214013LL)&vcolhashsizm1]; x>=0; x=vcol[x].n)
126
127
128
129
        if (vcol[x].p == z)
            return vcol[x].c;

    return 0x808080;
130
131
132
133
}

static void putvox(int32_t x, int32_t y, int32_t z, int32_t col)
{
134
135
136
137
138
    if (vnum >= vmax)
    {
        vmax = max(vmax<<1, 4096);
        vcol = (voxcol_t *)Xrealloc(vcol, vmax*sizeof(voxcol_t));
    }
139
140

    z += x*yzsiz + y*voxsiz.z;
141

Richard Gobeille's avatar
Richard Gobeille committed
142
    vcol[vnum].p = z; z = (z*214013LL)&vcolhashsizm1;
143
144
145
146
147
148
149
150
    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)
{
151
    if (!((z0^z1)&~31)) { lptr[z0>>5] &= ((~-(1<<SHIFTMOD32(z0)))|-(1<<SHIFTMOD32(z1))); return; }
152
    int32_t z = (z0>>5), ze = (z1>>5);
153
154
155
    lptr[z] &=~-(1<<SHIFTMOD32(z0));
    for (z++; z<ze; z++) lptr[z] = 0;
    lptr[z] &= -(1<<SHIFTMOD32(z1));
156
157
158
159
160
}
#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)
{
161
    if (!((z0^z1)&~31)) { lptr[z0>>5] |= ((~-(1<<SHIFTMOD32(z1)))&-(1<<SHIFTMOD32(z0))); return; }
162
    int32_t z = (z0>>5), ze = (z1>>5);
163
164
165
    lptr[z] |= -(1<<SHIFTMOD32(z0));
    for (z++; z<ze; z++) lptr[z] = -1;
    lptr[z] |=~-(1<<SHIFTMOD32(z1));
166
167
}

168
static bool isrectfree(int32_t x0, int32_t y0, int32_t dx, int32_t dy)
169
{
170
171
172
173
174
175
    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];
176

177
178
179
180
181
182
    if (!c)
    {
        for (m &= m1; dy; dy--, i += mytexo5)
            if (zbit[i]&m)
                return 0;
    }
183
184
    else
    {
185
        for (; dy; dy--, i += mytexo5)
186
        {
187
188
189
190
191
192
193
194
195
196
            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;
197
198
        }
    }
Richard Gobeille's avatar
Richard Gobeille committed
199
    return 1;
200
201
202
203
}

static void setrect(int32_t x0, int32_t y0, int32_t dx, int32_t dy)
{
204
205
206
207
208
209
    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];
210

211
212
213
214
215
    if (!c)
    {
        for (m &= m1; dy; dy--, i += mytexo5)
            zbit[i] |= m;
    }
216
217
    else
    {
218
        for (; dy; dy--, i += mytexo5)
219
220
        {
            zbit[i] |= m;
221
222
223
224
225

            int32_t x;
            for (x=1; x<c; x++)
                zbit[i+x] = -1;

226
227
228
229
230
            zbit[i+x] |= m1;
        }
    }
}

231
232
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)
233
234
235
236
237
238
{
    UNREFERENCED_PARAMETER(x1);
    UNREFERENCED_PARAMETER(y1);
    UNREFERENCED_PARAMETER(z1);
    UNREFERENCED_PARAMETER(face);

239
240
241
242
243
244
245
    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;

246
    if (x < y) { z = x; x = y; y = z; }
247

248
    shcnt[y*shcntp+x]++;
249

250
251
    if (x > gmaxx) gmaxx = x;
    if (y > gmaxy) gmaxy = y;
252
253

    garea += (x+(VOXBORDWIDTH<<1)) * (y+(VOXBORDWIDTH<<1));
254
255
256
    gvox->qcnt++;
}

257
258
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)
259
{
260
261
    int32_t i;
    int32_t x = labs(x2-x0), y = labs(y2-y0), z = labs(z2-z0);
262

263
264
    if (x == 0) { x = y; y = z; i = 0; }
    else if (y == 0) { y = z; i = 1; }
265
    else i = 2;
266

267
    if (x < y) { z = x; x = y; y = z; i += 3; }
268

269
    z = shcnt[y*shcntp+x]++;
270
271
272
273
    int32_t *lptr = &gvox->mytex[(shp[z].y+VOXBORDWIDTH)*gvox->mytexx +
                                 (shp[z].x+VOXBORDWIDTH)];
    int32_t nx = 0, ny = 0, nz = 0;

274
275
276
    switch (face)
    {
    case 0:
277
278
279
        ny = y1; x2 = x0; x0 = x1; x1 = x2;
        for (int yy=0; yy<y; yy++, lptr+=gvox->mytexx)
            for (int xx=0; xx<x; xx++)
280
281
282
            {
                if (i < 3) { nx = x1+x-1-xx; nz = z1+yy; } //back
                else { nx = x1+y-1-yy; nz = z1+xx; }
283
284
285
286
287
288
289
290
                lptr[xx] = getvox(nx, ny, nz);
            }
        break;
    case 1:
        ny = y0; y0++; y1++; y2++;
        for (int yy=0; yy<y; yy++, lptr+=gvox->mytexx)
            for (int xx=0; xx<x; xx++)
            {
291
292
                if (i < 3) { nx = x0+xx;     nz = z0+yy; } //front
                else { nx = x0+yy;     nz = z0+xx; }
293
294
295
296
297
298
299
300
                lptr[xx] = getvox(nx, ny, nz);
            }
        break;
    case 2:
        nz = z1; y0 = y2; y2 = y1; y1 = y0; z0++; z1++; z2++;
        for (int yy=0; yy<y; yy++, lptr+=gvox->mytexx)
            for (int xx=0; xx<x; xx++)
            {
301
302
                if (i < 3) { nx = x1-x+xx;   ny = y1-1-yy; } //bot
                else { nx = x1-1-yy;   ny = y1-1-xx; }
303
304
305
306
307
308
309
310
                lptr[xx] = getvox(nx, ny, nz);
            }
        break;
    case 3:
        nz = z0;
        for (int yy=0; yy<y; yy++, lptr+=gvox->mytexx)
            for (int xx = 0; xx < x; xx++)
            {
311
312
                if (i < 3) { nx = x0+xx;     ny = y0+yy; } //top
                else { nx = x0+yy;     ny = y0+xx; }
313
314
315
316
317
318
319
320
                lptr[xx] = getvox(nx, ny, nz);
            }
        break;
    case 4:
        nx = x1; y2 = y0; y0 = y1; y1 = y2; x0++; x1++; x2++;
        for (int yy=0; yy<y; yy++, lptr+=gvox->mytexx)
            for (int xx = 0; xx < x; xx++)
            {
321
322
                if (i < 3) { ny = y1+x-1-xx; nz = z1+yy; } //right
                else { ny = y1+y-1-yy; nz = z1+xx; }
323
324
325
326
327
328
329
330
                lptr[xx] = getvox(nx, ny, nz);
            }
        break;
    case 5:
        nx = x0;
        for (int yy=0; yy<y; yy++, lptr+=gvox->mytexx)
            for (int xx = 0; xx < x; xx++)
            {
331
332
                if (i < 3) { ny = y0+xx;     nz = z0+yy; } //left
                else { ny = y0+yy;     nz = z0+xx; }
333
                lptr[xx] = getvox(nx, ny, nz);
334
            }
335
336
        break;
    }
337
338

    //Extend borders horizontally
339
340
    for (int xx=0; xx<VOXBORDWIDTH; xx++)
        for (int yy=VOXBORDWIDTH; yy<y+VOXBORDWIDTH; yy++)
341
        {
342
343
344
            lptr = &gvox->mytex[(shp[z].y+yy)*gvox->mytexx + shp[z].x];
            lptr[xx] = lptr[VOXBORDWIDTH];
            lptr[xx+x+VOXBORDWIDTH] = lptr[x-1+VOXBORDWIDTH];
345
        }
346

347
    //Extend borders vertically
348
    for (int yy=0; yy<VOXBORDWIDTH; yy++)
349
    {
350
351
352
353
354
355
        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);
356
357
    }

358
    voxrect_t *const qptr = &gquad[gvox->qcnt];
359

360
361
362
    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;
363

364
365
366
367
    constexpr vec2_u16_t vbw = { VOXBORDWIDTH, VOXBORDWIDTH };
    
    for (int j=0; j<3; j++)
        qptr->v[j].uv = shp[z]+vbw;
368
369
370
371
372
373
374
375

    if (i < 3)
        qptr->v[1].u += x;
    else
        qptr->v[1].v += y;

    qptr->v[2].u += x;
    qptr->v[2].v += y;
376

377
378
    qptr->v[3].uv  = qptr->v[0].uv  - qptr->v[1].uv  + qptr->v[2].uv;
    qptr->v[3].xyz = qptr->v[0].xyz - qptr->v[1].xyz + qptr->v[2].xyz;
379

380
381
    if (gqfacind[face] < 0)
        gqfacind[face] = gvox->qcnt;
382
383

    gvox->qcnt++;
384
385
386
387
}

static inline int32_t isolid(int32_t x, int32_t y, int32_t z)
{
388
389
    if (((uint32_t)x >= (uint32_t)voxsiz.x) | ((uint32_t)y >= (uint32_t)voxsiz.y) | ((uint32_t)z >= (uint32_t)voxsiz.z))
        return 0;
390
391
392

    z += x*yzsiz + y*voxsiz.z;

393
    return (vbit[z>>5] & (1<<SHIFTMOD32(z))) != 0;
394
395
}

396
static FORCE_INLINE int isair(int const i)
397
398
{
    return !(vbit[i>>5] & (1<<SHIFTMOD32(i)));
399
400
}

401
#ifdef USE_GLEXT
402
void voxvboalloc(voxmodel_t *vm)
403
404
405
406
{
    glGenBuffers(1, &vm->vbo);
    glGenBuffers(1, &vm->vboindex);

Richard Gobeille's avatar
Richard Gobeille committed
407
    GLint prevVBO = 0;
408
    glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevVBO);
409
    buildgl_bindBuffer(GL_ELEMENT_ARRAY_BUFFER, vm->vboindex);
410
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * 3 * 2 * vm->qcnt, vm->index, GL_STATIC_DRAW);
411
    buildgl_bindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevVBO);
412

Richard Gobeille's avatar
Richard Gobeille committed
413
    prevVBO = 0;
414
    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prevVBO);
415
    buildgl_bindBuffer(GL_ARRAY_BUFFER, vm->vbo);
416
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 5 * 4 * vm->qcnt, vm->vertex, GL_STATIC_DRAW);
417
    buildgl_bindBuffer(GL_ARRAY_BUFFER, prevVBO);
418
}
419
420
421

void voxvbofree(voxmodel_t *vm)
{
422
423
    if (!vm->vbo)
        return;
424
425
    glDeleteBuffers(1, &vm->vbo);
    glDeleteBuffers(1, &vm->vboindex);
426
    vm->vbo = 0;
427
}
428
429
#endif

430
431
static voxmodel_t *vox2poly()
{
432
    gvox = (voxmodel_t *)Xcalloc(1, sizeof(voxmodel_t));
433

434
    //x is largest dimension, y is 2nd largest dimension
435
    auto vdim = voxsiz;
436

437
438
439
440
    if (vdim.x < vdim.y && vdim.x < vdim.z)
        vdim.x = vdim.z;
    else if (vdim.y < vdim.z)
        vdim.y = vdim.z;
441

442
443
    if (vdim.x < vdim.y)
        vdim = { vdim.y, vdim.z, vdim.x };
444

445
446
    shcntp = vdim.x;
    int32_t i = vdim.x*vdim.y*sizeof(int32_t);
447

448
449
450
451
    shcntmal = (int32_t *)Xmalloc(i);
    memset(shcntmal, 0, i);
    shcnt = &shcntmal[-shcntp-1];

452
453
    gmaxx = gmaxy = garea = 0;

454
455
456
457
458
459
    if (pow2m1[32] != -1)
    {
        for (i=0; i<32; i++)
            pow2m1[i] = (1u<<i)-1;
        pow2m1[32] = -1;
    }
460

461
    for (i=0; i<7; i++)
462
        gqfacind[i] = -1;
463

464
465
466
467
468
469
    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;

470
    for (int cnt=0; cnt<2; cnt++)
471
    {
472
473
474
        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;

475
476
        gvox->qcnt = 0;

477
478
        memset(by0, -1, (max(voxsiz.y, voxsiz.z)+1)<<2);
        int32_t v = 0;
479
480

        for (i=-1; i<=1; i+=2)
481
482
483
            for (int y=0; y<voxsiz.y; y++)
                for (int x=0; x<=voxsiz.x; x++)
                    for (int z=0; z<=voxsiz.z; z++)
484
                    {
485
486
487
488
489
490
491
492
493
                        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; }
494
495
496
                    }

        for (i=-1; i<=1; i+=2)
497
498
499
            for (int z=0; z<voxsiz.z; z++)
                for (int x=0; x<=voxsiz.x; x++)
                    for (int y=0; y<=voxsiz.y; y++)
500
                    {
501
502
503
504
505
506
507
508
509
                        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; }
510
511
512
                    }

        for (i=-1; i<=1; i+=2)
513
514
515
            for (int x=0; x<voxsiz.x; x++)
                for (int y=0; y<=voxsiz.y; y++)
                    for (int z=0; z<=voxsiz.z; z++)
516
                    {
517
518
519
520
521
522
523
524
525
                        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; }
526
527
528
529
                    }

        if (!cnt)
        {
530
            shp = (vec2_u16_t *)Xmalloc(gvox->qcnt*sizeof(vec2_u16_t));
531

532
533
            int32_t sc = 0;

534
535
            for (int y=gmaxy; y; y--)
                for (int x=gmaxx; x>=y; x--)
536
                {
537
538
539
540
541
542
543
544
                    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++;
                    }
545
546
                }

547
548
549
550
551
552
            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 */;

553
554
            while (gvox->mytexx*gvox->mytexy*8 < garea*9) //This should be sufficient to fit most skins...
            {
555
556
557
558
559
skindidntfit:
                if (gvox->mytexx <= gvox->mytexy)
                    gvox->mytexx <<= 1;
                else
                    gvox->mytexy <<= 1;
560
561
            }

562
563
564
565
            mytexo5 = gvox->mytexx>>5;

            i = ((gvox->mytexx*gvox->mytexy+31)>>5)<<2;
            zbit = (int32_t *)Xmalloc(i);
566
567
568
            memset(zbit, 0, i);

            v = gvox->mytexx*gvox->mytexy;
569
570
571
            constexpr vec2_u16_t vbw = { (VOXBORDWIDTH<<1), (VOXBORDWIDTH<<1) };
            
            for (int z=0; z<sc; z++)
572
            {
573
                auto d = shp[z] + vbw;
574
575
576
577
                i = v;

                int32_t x0, y0;

578
579
580
                do
                {
#if (VOXUSECHAR != 0)
581
582
                    x0 = ((rand()&32767)*(min(gvox->mytexx, 255)-d.x))>>15;
                    y0 = ((rand()&32767)*(min(gvox->mytexy, 255)-d.y))>>15;
583
#else
584
585
                    x0 = ((rand()&32767)*(gvox->mytexx+1-d.x))>>15;
                    y0 = ((rand()&32767)*(gvox->mytexy+1-d.y))>>15;
586
587
588
589
#endif
                    i--;
                    if (i < 0) //Time-out! Very slow if this happens... but at least it still works :P
                    {
590
                        Xfree(zbit);
591
592

                        //Re-generate shp[].x/y (box sizes) from shcnt (now head indices) for next pass :/
593
                        int j = 0;
594

595
596
                        for (int y=gmaxy; y; y--)
                            for (int x=gmaxx; x>=y; x--)
597
                            {
598
599
600
601
602
603
604
605
606
607
                                i = shcnt[y*shcntp+x];

                                for (; j<i; j++)
                                {
                                    shp[j].x = x0;
                                    shp[j].y = y0;
                                }

                                x0 = x;
                                y0 = y;
608
                            }
609
610
611
612
613
614

                        for (; j<sc; j++)
                        {
                            shp[j].x = x0;
                            shp[j].y = y0;
                        }
615
616
617

                        goto skindidntfit;
                    }
618
                } while (!isrectfree(x0, y0, d.x, d.y));
619

620
                while (y0 && isrectfree(x0, y0-1, d.x, 1))
621
                    y0--;
622
                while (x0 && isrectfree(x0-1, y0, 1, d.y))
623
624
                    x0--;

625
                setrect(x0, y0, d.x, d.y);
626
627
628
                shp[z].x = x0; shp[z].y = y0; //Overwrite size with top-left location
            }

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

634
635
636
637
638
639
640
641
642
643
644
645
646
647
    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++)
    {
648
649
        auto const vptr = &gquad[i].v[0];
        auto const vsum = vptr[0].xyz + vptr[2].xyz;
650
651
652

        for (int j=0; j<4; j++)
        {
653
654
655
            gvox->vertex[((i<<2)+j)*5+0] = ((float)vptr[j].x) - phack[vsum.x>(vptr[j].x<<1)] + phack[vsum.x<(vptr[j].x<<1)];
            gvox->vertex[((i<<2)+j)*5+1] = ((float)vptr[j].y) - phack[vsum.y>(vptr[j].y<<1)] + phack[vsum.y<(vptr[j].y<<1)];
            gvox->vertex[((i<<2)+j)*5+2] = ((float)vptr[j].z) - phack[vsum.z>(vptr[j].z<<1)] + phack[vsum.z<(vptr[j].z<<1)];
656
657
658
659
660
661
662
663
664
665
666
667
668

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

670
671
    DO_FREE_AND_NULL(gquad);
    
Richard Gobeille's avatar
Richard Gobeille committed
672
    return gvox;
673
674
}

675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
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);
}

690
static void read_pal(buildvfs_kfd fil, int32_t pal[256])
691
692
693
{
    klseek(fil, -768, SEEK_END);

694
    for (int i=0; i<256; i++)
695
696
697
698
699
700
701
702
703
    {
        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
    }
}

704
705
static int32_t loadvox(const char *filnam)
{
706
707
    const buildvfs_kfd fil = kopen4load(filnam, 0);
    if (fil == buildvfs_kfd_invalid)
708
        return -1;
709
710
711
712
713
714
715

    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
716
717
718
    voxpiv.x = (float)voxsiz.x * .5f;
    voxpiv.y = (float)voxsiz.y * .5f;
    voxpiv.z = (float)voxsiz.z * .5f;
719

720
721
    int32_t pal[256];
    read_pal(fil, pal);
722
723
724
    pal[255] = -1;

    vcolhashsizm1 = 8192-1;
725
726
    alloc_vcolhashead();
    alloc_vbit();
727

728
    char *const tbuf = (char *)Xmalloc(voxsiz.z*sizeof(uint8_t));
729
730

    klseek(fil, 12, SEEK_SET);
731
732
    for (int x=0; x<voxsiz.x; x++)
        for (int y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
733
        {
734
735
            kread(fil, tbuf, voxsiz.z);

736
            for (int z=voxsiz.z-1; z>=0; z--)
737
738
739
740
741
                if (tbuf[z] != 255)
                {
                    const int32_t i = j+z;
                    vbit[i>>5] |= (1<<SHIFTMOD32(i));
                }
742
743
744
        }

    klseek(fil, 12, SEEK_SET);
745
746
    for (int x=0; x<voxsiz.x; x++)
        for (int y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
747
        {
748
749
            kread(fil, tbuf, voxsiz.z);

750
            for (int z=0; z<voxsiz.z; z++)
751
            {
752
753
754
                if (tbuf[z] == 255)
                    continue;

755
                if (!x | !y | !z | (x == voxsiz.x-1) | (y == voxsiz.y-1) | (z == voxsiz.z-1))
756
757
758
759
760
761
762
                {
                    putvox(x, y, z, pal[tbuf[z]]);
                    continue;
                }

                const int32_t k = j+z;

763
764
765
                if (isair(k-yzsiz) | isair(k+yzsiz) |
                    isair(k-voxsiz.z) | isair(k+voxsiz.z) |
                    isair(k-1) | isair(k+1))
766
767
768
769
                {
                    putvox(x, y, z, pal[tbuf[z]]);
                    continue;
                }
770
771
772
            }
        }

773
    Xfree(tbuf);
774
775
776
    kclose(fil);

    return 0;
777
778
779
780
}

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

783
784
    const buildvfs_kfd fil = kopen4load(filnam, 0);
    if (fil == buildvfs_kfd_invalid)
785
        return -1;
786
787
788
789
790
791
792
793

    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
794
795
796
    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);
797
798
    klseek(fil, (voxsiz.x+1)<<2, SEEK_CUR);

799
    const int32_t ysizp1 = voxsiz.y+1;
800
801
    i = voxsiz.x*ysizp1*sizeof(int16_t);

802
803
    uint16_t *xyoffs = (uint16_t *)Xmalloc(i);
    kread(fil, xyoffs, i);
804

805
806
807
808
809
810
811
    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();
812
813
814
815
816
817

    for (vcolhashsizm1=4096; vcolhashsizm1<(mip1leng>>1); vcolhashsizm1<<=1)
    {
        /* do nothing */
    }
    vcolhashsizm1--; //approx to numvoxs!
818
    alloc_vcolhashead();
819
820
821
822

    klseek(fil, 28+((voxsiz.x+1)<<2)+((ysizp1*voxsiz.x)<<1), SEEK_SET);

    i = kfilelength(fil)-ktell(fil);
823
    char *const tbuf = (char *)Xmalloc(i);
824

825
826
827
828
829
    kread(fil, tbuf, i);
    kclose(fil);

    char *cptr = tbuf;

830
831
    for (int x=0; x<voxsiz.x; x++) //Set surface voxels to 1 else 0
        for (int y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
832
        {
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
            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

853
                for (int z=z0; z<z1; z++)
854
855
                    putvox(x, y, z, pal[*cptr++]);
            }
856
857
        }

858
859
    Xfree(tbuf);
    Xfree(xyoffs);
860
861

    return 0;
862
863
864
865
}

static int32_t loadkv6(const char *filnam)
{
866
867
    int32_t i;

868
869
    const buildvfs_kfd fil = kopen4load(filnam, 0);
    if (fil == buildvfs_kfd_invalid)
870
871
872
873
874
875
        return -1;

    kread(fil, &i, 4);
    if (B_LITTLE32(i) != 0x6c78764b)
    {
        kclose(fil);
Richard Gobeille's avatar
Richard Gobeille committed
876
        return -1;
877
    } //Kvxl
878
879
880
881
882
883
884

    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
885
886
887
    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;
888
889

    int32_t numvoxs;
890
891
    kread(fil, &numvoxs, 4); numvoxs = B_LITTLE32(numvoxs);

892
    uint16_t *const ylen = (uint16_t *)Xmalloc(voxsiz.x*voxsiz.y*sizeof(int16_t));
893
894

    klseek(fil, 32+(numvoxs<<3)+(voxsiz.x<<2), SEEK_SET);
895
896
897
898
    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]);

899
900
    klseek(fil, 32, SEEK_SET);

901
    alloc_vbit();
902
903
904
905
906
907

    for (vcolhashsizm1=4096; vcolhashsizm1<numvoxs; vcolhashsizm1<<=1)
    {
        /* do nothing */
    }
    vcolhashsizm1--;
908
    alloc_vcolhashead();
909

910
911
    for (int x=0; x<voxsiz.x; x++)
        for (int y=0, j=x*yzsiz; y<voxsiz.y; y++, j+=voxsiz.z)
912
        {
913
914
915
916
917
918
919
            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

920
                const int32_t z0 = B_LITTLE16(B_UNBUF16(&c[4]));
921
922
923
924
925
926

                if (!(c[6]&16))
                    setzrange1(vbit, j+z1, j+z0);

                vbit[(j+z0)>>5] |= (1<<SHIFTMOD32(j+z0));

927
                putvox(x, y, z0, B_LITTLE32(B_UNBUF32(&c[0]))&0xffffff);
928
929
                z1 = z0+1;
            }
930
        }
931

932
    Xfree(ylen);
933
934
935
    kclose(fil);

    return 0;
936
937
938
939
}

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

943
944
    voxvbofree(m);

945
    DO_FREE_AND_NULL(m->mytex);
946
947
    DO_FREE_AND_NULL(m->vertex);
    DO_FREE_AND_NULL(m->index);
948
    DO_FREE_AND_NULL(m->texid);
949

950
    Xfree(m);
951
952
953
954
}

voxmodel_t *voxload(const char *filnam)
{
955
956
957
958
959
    int32_t is8bit, ret;

    const int32_t i = Bstrlen(filnam)-4;
    if (i < 0)
        return NULL;
960
961
962
963
964
965

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

967
968
    voxmodel_t* vm = NULL;
    if (ret >= 0)
969
    {
970
971
972
973
974
975
976
        // 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);
977

978
979
980
981
982
983
984
985
986
987
988
        // 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;
989
990
            vm->siz = voxsiz;
            vm->piv = voxpiv;
991
992
993
994
            vm->is8bit = is8bit;

            vm->texid = (uint32_t*)Xcalloc(MAXPALOOKUPS, sizeof(uint32_t));
        }
995
    }
996

997
998
999
1000
    DO_FREE_AND_NULL(shcntmal);
    DO_FREE_AND_NULL(vbit);
    DO_FREE_AND_NULL(vcol);
    vnum = vmax = 0;
For faster browsing, not all history is shown. View entire blame