mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 03:00:46 +00:00
aa04307ad1
git-svn-id: https://svn.eduke32.com/eduke32@6074 1a8010ca-5511-0410-912e-c29ae57300e0
413 lines
15 KiB
C++
413 lines
15 KiB
C++
#include "compat.h"
|
|
|
|
#define PI 3.141592653589793
|
|
|
|
typedef struct { float x, y; } point2d;
|
|
typedef struct { float x, y, z; } point3d;
|
|
typedef struct { float x, y, z; int32_t n; } kgln_t;
|
|
typedef struct { int32_t w, s; } vertlist_t;
|
|
typedef struct { float x, y; int32_t n, ns, nw; } wall_t;
|
|
typedef struct { float z[2]; point2d grad[2]; wall_t *wall; int32_t n; } sect_t;
|
|
static int32_t numsects;
|
|
static sect_t *sec;
|
|
|
|
//Build1 format variables:
|
|
typedef struct { int16_t picnum, heinum; int8_t shade; uint8_t pal, xpanning, ypanning; } build7surf_t;
|
|
typedef struct
|
|
{
|
|
int16_t wallptr, wallnum;
|
|
int32_t z[2]; int16_t stat[2]; build7surf_t surf[2];
|
|
uint8_t visibility, filler;
|
|
int16_t lotag, hitag, extra;
|
|
} build7sect_t;
|
|
typedef struct
|
|
{
|
|
int32_t x, y;
|
|
int16_t point2, nextwall, nextsect, cstat, picnum, overpicnum;
|
|
int8_t shade;
|
|
uint8_t pal, xrepeat, yrepeat, xpanning, ypanning;
|
|
int16_t lotag, hitag, extra;
|
|
} build7wall_t;
|
|
static build7sect_t b7sec;
|
|
static build7wall_t b7wal;
|
|
|
|
static void checknextwalls (void)
|
|
{
|
|
float x0, y0, x1, y1;
|
|
int32_t s0, w0, w0n, s1, w1, w1n;
|
|
|
|
//Clear all nextsect/nextwalls
|
|
for (s0=0;s0<numsects;s0++)
|
|
for (w0=0;w0<sec[s0].n;w0++) sec[s0].wall[w0].ns = sec[s0].wall[w0].nw = -1;
|
|
|
|
for (s1=1;s1<numsects;s1++)
|
|
for (w1=0;w1<sec[s1].n;w1++)
|
|
{
|
|
x0 = sec[s1].wall[w1].x; y0 = sec[s1].wall[w1].y; w1n = sec[s1].wall[w1].n+w1;
|
|
x1 = sec[s1].wall[w1n].x; y1 = sec[s1].wall[w1n].y;
|
|
for (s0=0;s0<s1;s0++)
|
|
for (w0=0;w0<sec[s0].n;w0++)
|
|
if ((sec[s0].wall[w0].x == x1) && (sec[s0].wall[w0].y == y1))
|
|
{
|
|
w0n = sec[s0].wall[w0].n+w0;
|
|
if ((sec[s0].wall[w0n].x == x0) && (sec[s0].wall[w0n].y == y0))
|
|
{
|
|
sec[s1].wall[w1].ns = s0;
|
|
sec[s1].wall[w1].nw = w0;
|
|
sec[s0].wall[w0].ns = s1;
|
|
sec[s0].wall[w0].nw = w1;
|
|
goto cnw_break2;
|
|
}
|
|
}
|
|
cnw_break2:;
|
|
}
|
|
}
|
|
|
|
static void shellsrt (float *a, int32_t n)
|
|
{
|
|
float t;
|
|
int32_t i, j, g;
|
|
|
|
for (g=(n>>1);g;g>>=1)
|
|
for (i=0;i<n-g;i++)
|
|
for (j=i;(j>=0)&&(a[j]>a[j+g]);j-=g)
|
|
{ t = a[j]; a[j] = a[j+g]; a[j+g] = t; }
|
|
}
|
|
|
|
static float getslopez (sect_t *s, int32_t i, float x, float y)
|
|
{
|
|
wall_t *wal = s->wall;
|
|
return (wal[0].x-x)*s->grad[i].x + (wal[0].y-y)*s->grad[i].y + s->z[i];
|
|
}
|
|
|
|
typedef struct { float x[4], y[2]; wall_t * pwal[2]; } zoid_t;
|
|
static int32_t sect2trap (wall_t *wal, int32_t n, zoid_t **retzoids, int32_t *retnzoids)
|
|
{
|
|
zoid_t *zoids = 0;
|
|
float f, x0, y0, x1, y1, sy0, sy1, cury, *secy = NULL, *trapx0 = NULL, *trapx1 = NULL;
|
|
int32_t i, j, g, s, secn, ntrap, tot, zoidalloc;
|
|
wall_t * k;
|
|
wall_t ** pwal = NULL;
|
|
|
|
(*retzoids) = 0; (*retnzoids) = 0; if (n < 3) return 0;
|
|
|
|
secy = (float *)malloc(n*sizeof(secy[0])); if (!secy) goto badret;
|
|
trapx0 = (float *)malloc(n*sizeof(trapx0[0])); if (!trapx0) goto badret;
|
|
trapx1 = (float *)malloc(n*sizeof(trapx1[0])); if (!trapx1) goto badret;
|
|
pwal = (wall_t **)malloc(n*sizeof(pwal[0])); if (!pwal) goto badret;
|
|
|
|
for (i=n-1;i>=0;i--) secy[i] = wal[i].y;
|
|
shellsrt(secy,n);
|
|
for (i=0,secn=0,cury=-1e32f;i<n;i++) //remove dups
|
|
if (secy[i] > cury) { secy[secn++] = cury = secy[i]; }
|
|
|
|
zoidalloc = secn*2; //just a guess (not guaranteed to fit)
|
|
zoids = (zoid_t *)malloc(zoidalloc*sizeof(zoid_t)); if (!zoids) goto badret;
|
|
|
|
tot = 0;
|
|
for (s=0;s<secn-1;s++)
|
|
{
|
|
sy0 = secy[s]; sy1 = secy[s+1]; ntrap = 0;
|
|
for (i=0;i<n;i++) //FIX:optimize
|
|
{
|
|
x0 = wal[i].x; y0 = wal[i].y; j = wal[i].n+i;
|
|
x1 = wal[j].x; y1 = wal[j].y;
|
|
if (y0 > y1)
|
|
{
|
|
f = x0; x0 = x1; x1 = f;
|
|
f = y0; y0 = y1; y1 = f;
|
|
}
|
|
if ((y0 >= sy1) || (y1 <= sy0)) continue;
|
|
if (y0 < sy0) x0 = (sy0-wal[i].y)*(wal[j].x-wal[i].x)/(wal[j].y-wal[i].y) + wal[i].x;
|
|
if (y1 > sy1) x1 = (sy1-wal[i].y)*(wal[j].x-wal[i].x)/(wal[j].y-wal[i].y) + wal[i].x;
|
|
trapx0[ntrap] = x0; trapx1[ntrap] = x1; pwal[ntrap] = &wal[i]; ntrap++;
|
|
}
|
|
for (g=(ntrap>>1);g;g>>=1)
|
|
for (i=0;i<ntrap-g;i++)
|
|
for (j=i;j>=0;j-=g)
|
|
{
|
|
if (trapx0[j]+trapx1[j] <= trapx0[j+g]+trapx1[j+g]) break;
|
|
f = trapx0[j]; trapx0[j] = trapx0[j+g]; trapx0[j+g] = f;
|
|
f = trapx1[j]; trapx1[j] = trapx1[j+g]; trapx1[j+g] = f;
|
|
k = pwal[j]; pwal[j] = pwal[j+g]; pwal[j+g] = k;
|
|
}
|
|
|
|
if (tot+ntrap > zoidalloc)
|
|
{
|
|
zoidalloc <<= 1; if (tot+ntrap > zoidalloc) zoidalloc = tot+ntrap;
|
|
zoids = (zoid_t *)realloc(zoids,zoidalloc*sizeof(zoid_t)); if (!zoids) goto badret;
|
|
}
|
|
for (i=0;i<ntrap;i=j+1)
|
|
{
|
|
j = i+1; if ((trapx0[i+1] <= trapx0[i]) && (trapx1[i+1] <= trapx1[i])) continue;
|
|
while ((j+2 < ntrap) && (trapx0[j+1] <= trapx0[j]) && (trapx1[j+1] <= trapx1[j])) j += 2;
|
|
zoids[tot].x[0] = trapx0[i]; zoids[tot].x[1] = trapx0[j]; zoids[tot].y[0] = sy0;
|
|
zoids[tot].x[3] = trapx1[i]; zoids[tot].x[2] = trapx1[j]; zoids[tot].y[1] = sy1;
|
|
zoids[tot].pwal[0] = pwal[i]; zoids[tot].pwal[1] = pwal[j];
|
|
tot++;
|
|
}
|
|
}
|
|
(*retzoids) = zoids; (*retnzoids) = tot; return 1;
|
|
badret:;
|
|
free(secy);
|
|
free(trapx0);
|
|
free(trapx1);
|
|
free(pwal);
|
|
free(zoids);
|
|
return 0;
|
|
}
|
|
|
|
static int32_t getwalls (int32_t s, int32_t w, vertlist_t *ver, int32_t maxverts)
|
|
{
|
|
vertlist_t tver;
|
|
wall_t *wal, *wal2;
|
|
float fx, fy;
|
|
int32_t i, j, k, bs, bw, nw, vn;
|
|
|
|
wal = sec[s].wall; bs = wal[w].ns;
|
|
if ((unsigned)bs >= (unsigned)numsects) return 0;
|
|
|
|
vn = 0; nw = wal[w].n+w; bw = wal[w].nw;
|
|
do
|
|
{
|
|
wal2 = sec[bs].wall; i = wal2[bw].n+bw; //Make sure it's an opposite wall
|
|
if ((wal[w].x == wal2[i].x) && (wal[nw].x == wal2[bw].x) &&
|
|
(wal[w].y == wal2[i].y) && (wal[nw].y == wal2[bw].y))
|
|
{ if (vn < maxverts) { ver[vn].s = bs; ver[vn].w = bw; vn++; } }
|
|
bs = wal2[bw].ns;
|
|
bw = wal2[bw].nw;
|
|
} while (bs != s);
|
|
|
|
//Sort next sects by order of height in middle of wall (crap sort)
|
|
fx = (wal[w].x+wal[nw].x)*.5f;
|
|
fy = (wal[w].y+wal[nw].y)*.5f;
|
|
for (k=1;k<vn;k++)
|
|
for (j=0;j<k;j++)
|
|
if (getslopez(&sec[ver[j].s],0,fx,fy) + getslopez(&sec[ver[j].s],1,fx,fy) >
|
|
getslopez(&sec[ver[k].s],0,fx,fy) + getslopez(&sec[ver[k].s],1,fx,fy))
|
|
{ tver = ver[j]; ver[j] = ver[k]; ver[k] = tver; }
|
|
return(vn);
|
|
}
|
|
|
|
static int32_t wallclip (kgln_t *pol, kgln_t *npol)
|
|
{
|
|
float f, dz0, dz1;
|
|
|
|
dz0 = pol[3].z-pol[0].z; dz1 = pol[2].z-pol[1].z;
|
|
if (dz0 > 0.0) //do not include null case for rendering
|
|
{
|
|
npol[0] = pol[0];
|
|
if (dz1 > 0.0) //do not include null case for rendering
|
|
{
|
|
npol[1] = pol[1];
|
|
npol[2] = pol[2];
|
|
npol[3] = pol[3];
|
|
npol[0].n = npol[1].n = npol[2].n = 1; npol[3].n = -3;
|
|
return 4;
|
|
}
|
|
else
|
|
{
|
|
f = dz0/(dz0-dz1);
|
|
npol[1].x = (pol[1].x-pol[0].x)*f + pol[0].x;
|
|
npol[1].y = (pol[1].y-pol[0].y)*f + pol[0].y;
|
|
npol[1].z = (pol[1].z-pol[0].z)*f + pol[0].z;
|
|
npol[2] = pol[3];
|
|
npol[0].n = npol[1].n = 1; npol[2].n = -2;
|
|
return 3;
|
|
}
|
|
}
|
|
if (dz1 <= 0.0) return 0; //do not include null case for rendering
|
|
f = dz0/(dz0-dz1);
|
|
npol[0].x = (pol[1].x-pol[0].x)*f + pol[0].x;
|
|
npol[0].y = (pol[1].y-pol[0].y)*f + pol[0].y;
|
|
npol[0].z = (pol[1].z-pol[0].z)*f + pol[0].z;
|
|
npol[1] = pol[1];
|
|
npol[2] = pol[2];
|
|
npol[0].n = npol[1].n = 1; npol[2].n = -2;
|
|
return 3;
|
|
}
|
|
|
|
// //STL binary format:
|
|
//char filler[80];
|
|
//uint32_t numtris;
|
|
//for (i=0;i<numtris;i++)
|
|
//{
|
|
// point3d norm, v[3]; //vertices are CCW and must be + coords
|
|
// int16_t filler;
|
|
//}
|
|
static void saveasstl (char const * filnam)
|
|
{
|
|
#define MAXVERTS 256 //WARNING:not dynamic
|
|
vertlist_t verts[MAXVERTS];
|
|
kgln_t pol[4], npol[4];
|
|
point3d fp[3], fp2;
|
|
point2d *grad;
|
|
wall_t *wal;
|
|
zoid_t *zoids;
|
|
FILE *fil;
|
|
float f, fz;
|
|
int32_t i, j, k, n, w, s, nw, wn, vn, s0, cf0, s1, cf1, isflor, nzoids;
|
|
int32_t numtris;
|
|
char tbuf[80];
|
|
|
|
fil = fopen(filnam,"wb"); if (!fil) return;
|
|
memset(tbuf,0,80);
|
|
fwrite(tbuf,80,1,fil); //header ignored in STL
|
|
numtris = 0;
|
|
fwrite(&numtris,4,1,fil); //dummy write
|
|
|
|
for (s=0;s<numsects;s++)
|
|
{
|
|
//draw sector filled
|
|
for (isflor=0;isflor<2;isflor++)
|
|
{
|
|
wal = sec[s].wall; fz = sec[s].z[isflor]; grad = &sec[s].grad[isflor]; n = sec[s].n;
|
|
|
|
if (!sect2trap(wal,n,&zoids,&nzoids)) continue;
|
|
|
|
for (i=0;i<nzoids;i++)
|
|
{
|
|
for (j=0,n=0;j<4;j++)
|
|
{
|
|
pol[n].x = zoids[i].x[j];
|
|
pol[n].y = zoids[i].y[j>>1];
|
|
if ((!n) || (pol[n].x != pol[n-1].x) || (pol[n].y != pol[n-1].y))
|
|
{
|
|
pol[n].z = (wal[0].x-pol[n].x)*grad->x + (wal[0].y-pol[n].y)*grad->y + fz;
|
|
pol[n].n = 1; n++;
|
|
}
|
|
}
|
|
if (n < 3) continue;
|
|
pol[n-1].n = 1-n;
|
|
|
|
fp[0].x = pol[0].x; fp[0].y = pol[0].y; fp[0].z = pol[0].z;
|
|
for (j=2;j<n;j++)
|
|
{
|
|
k = j-isflor; fp[1].x = pol[k].x; fp[1].y = pol[k].y; fp[1].z = pol[k].z;
|
|
k = j-1+isflor; fp[2].x = pol[k].x; fp[2].y = pol[k].y; fp[2].z = pol[k].z;
|
|
//fp2 = unit norm
|
|
fp2.x = (fp[1].y-fp[0].y)*(fp[2].z-fp[0].z) - (fp[1].z-fp[0].z)*(fp[2].y-fp[0].y);
|
|
fp2.y = (fp[1].z-fp[0].z)*(fp[2].x-fp[0].x) - (fp[1].x-fp[0].x)*(fp[2].z-fp[0].z);
|
|
fp2.z = (fp[1].x-fp[0].x)*(fp[2].y-fp[0].y) - (fp[1].y-fp[0].y)*(fp[2].x-fp[0].x);
|
|
f = fp2.x*fp2.x + fp2.y*fp2.y + fp2.z*fp2.z; if (f > 0.f) f = -1.f/sqrtf(f);
|
|
fp2.x *= f; fp2.y *= f; fp2.z *= f; fwrite(&fp2,4*3,1,fil);
|
|
fwrite(fp,4*3*3,1,fil); fwrite(tbuf,2,1,fil); //2 bytes of filler
|
|
numtris++;
|
|
}
|
|
}
|
|
free(zoids);
|
|
}
|
|
|
|
wal = sec[s].wall; wn = sec[s].n;
|
|
for (w=0;w<wn;w++)
|
|
{
|
|
nw = wal[w].n+w; vn = getwalls(s,w,verts,MAXVERTS);
|
|
pol[0].x = wal[ w].x; pol[0].y = wal[ w].y; pol[0].n = 1;
|
|
pol[1].x = wal[nw].x; pol[1].y = wal[nw].y; pol[1].n = 1;
|
|
pol[2].x = wal[nw].x; pol[2].y = wal[nw].y; pol[2].n = 1;
|
|
pol[3].x = wal[ w].x; pol[3].y = wal[ w].y; pol[3].n =-3;
|
|
for (k=0;k<=vn;k++) //Warning: do not reverse for loop!
|
|
{
|
|
if (k > 0) { s0 = verts[k-1].s; cf0 = 1; } else { s0 = s; cf0 = 0; }
|
|
if (k < vn) { s1 = verts[k ].s; cf1 = 0; } else { s1 = s; cf1 = 1; }
|
|
|
|
pol[0].z = getslopez(&sec[s0],cf0,pol[0].x,pol[0].y);
|
|
pol[1].z = getslopez(&sec[s0],cf0,pol[1].x,pol[1].y);
|
|
pol[2].z = getslopez(&sec[s1],cf1,pol[2].x,pol[2].y);
|
|
pol[3].z = getslopez(&sec[s1],cf1,pol[3].x,pol[3].y);
|
|
i = wallclip(pol,npol); if (!i) continue;
|
|
|
|
fp[0].x = npol[0].x; fp[0].y = npol[0].y; fp[0].z = npol[0].z;
|
|
for (j=2;j<i;j++)
|
|
{
|
|
fp[1].x = npol[j-1].x; fp[1].y = npol[j-1].y; fp[1].z = npol[j-1].z;
|
|
fp[2].x = npol[j ].x; fp[2].y = npol[j ].y; fp[2].z = npol[j ].z;
|
|
//fp2 = unit norm
|
|
fp2.x = (fp[1].y-fp[0].y)*(fp[2].z-fp[0].z) - (fp[1].z-fp[0].z)*(fp[2].y-fp[0].y);
|
|
fp2.y = (fp[1].z-fp[0].z)*(fp[2].x-fp[0].x) - (fp[1].x-fp[0].x)*(fp[2].z-fp[0].z);
|
|
fp2.z = (fp[1].x-fp[0].x)*(fp[2].y-fp[0].y) - (fp[1].y-fp[0].y)*(fp[2].x-fp[0].x);
|
|
f = fp2.x*fp2.x + fp2.y*fp2.y + fp2.z*fp2.z; if (f > 0.f) f = -1.f/sqrtf(f);
|
|
fp2.x *= f; fp2.y *= f; fp2.z *= f; fwrite(&fp2,4*3,1,fil);
|
|
fwrite(fp,4*3*3,1,fil); fwrite(tbuf,2,1,fil); //2 bytes of filler
|
|
numtris++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
i = ftell(fil);
|
|
fseek(fil,80,SEEK_SET); fwrite(&numtris,4,1,fil);
|
|
fseek(fil,i,SEEK_SET);
|
|
fclose(fil);
|
|
}
|
|
|
|
static int32_t loadmap (char *filnam)
|
|
{
|
|
float f, fx, fy;
|
|
int32_t i, j, k;
|
|
int16_t s;
|
|
FILE *fil;
|
|
|
|
fil = fopen(filnam,"rb"); if (!fil) return 0;
|
|
fread(&i,4,1,fil); if (i != 0x00000007) return 0; //not Build1 .MAP format 7
|
|
fseek(fil,20,SEEK_SET);
|
|
|
|
fread(&s,2,1,fil); numsects = (int32_t)s;
|
|
sec = (sect_t *)malloc(numsects*sizeof(sect_t));
|
|
memset(sec,0,numsects*sizeof(sect_t));
|
|
for (i=0;i<numsects;i++)
|
|
{
|
|
fread(&b7sec,sizeof(b7sec),1,fil);
|
|
sec[i].n = b7sec.wallnum;
|
|
sec[i].wall = (wall_t *)realloc(sec[i].wall,sec[i].n*sizeof(wall_t));
|
|
memset(sec[i].wall,0L,sec[i].n*sizeof(wall_t));
|
|
for (j=0;j<2;j++)
|
|
{
|
|
sec[i].z[j] = ((float)b7sec.z[j])*(1.f/(512.f*16.f));
|
|
sec[i].grad[j].x = sec[i].grad[j].y = 0;
|
|
if (b7sec.stat[j]&2) //Enable slopes flag
|
|
sec[i].grad[j].y = ((float)b7sec.surf[j].heinum)*(1.f/4096.f);
|
|
}
|
|
}
|
|
|
|
fread(&s,2,1,fil); //numwalls
|
|
for (i=k=0;i<numsects;i++)
|
|
{
|
|
for (j=0;j<sec[i].n;j++,k++)
|
|
{
|
|
fread(&b7wal,sizeof(b7wal),1,fil);
|
|
sec[i].wall[j].x = ((float)b7wal.x)*(1.f/512.f);
|
|
sec[i].wall[j].y = ((float)b7wal.y)*(1.f/512.f);
|
|
sec[i].wall[j].n = b7wal.point2-k;
|
|
}
|
|
|
|
fx = sec[i].wall[1].y-sec[i].wall[0].y;
|
|
fy = sec[i].wall[0].x-sec[i].wall[1].x;
|
|
f = fx*fx + fy*fy; if (f > 0.f) f = 1.f/sqrtf(f); fx *= f; fy *= f;
|
|
for (j=0;j<2;j++)
|
|
{
|
|
sec[i].grad[j].x = fx*sec[i].grad[j].y;
|
|
sec[i].grad[j].y = fy*sec[i].grad[j].y;
|
|
}
|
|
}
|
|
|
|
checknextwalls();
|
|
fclose(fil);
|
|
return 1;
|
|
}
|
|
|
|
int main (int argc, char **argv)
|
|
{
|
|
if (argc != 3)
|
|
{
|
|
printf("map2stl [in:Build .MAP (v7)] [out:STL file] by Ken Silverman (05/15/2009)");
|
|
return 1;
|
|
}
|
|
if (!loadmap(argv[1]))
|
|
{
|
|
printf("error loading map\n");
|
|
return 2;
|
|
}
|
|
saveasstl(argv[2]);
|
|
return 0;
|
|
}
|