diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile index f8cc31888..4962f6b49 100644 --- a/polymer/eduke32/Makefile +++ b/polymer/eduke32/Makefile @@ -258,6 +258,7 @@ UTILS= \ mkpalette \ unpackssi \ bsuite \ + map2stl \ GAMEUTILS= \ ivfrate \ diff --git a/polymer/eduke32/build/src/util/map2stl.c b/polymer/eduke32/build/src/util/map2stl.c new file mode 100644 index 000000000..e61c7d3d5 --- /dev/null +++ b/polymer/eduke32/build/src/util/map2stl.c @@ -0,0 +1,415 @@ + +#include +#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>1);g;g>>=1) + for (i=0;i=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 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 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=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= (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 + 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>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 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 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 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 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; +}