--- ray/src/gen/genbox.c 2021/04/08 15:13:08 2.10 +++ ray/src/gen/genbox.c 2021/04/09 01:48:20 2.11 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: genbox.c,v 2.10 2021/04/08 15:13:08 greg Exp $"; +static const char RCSid[] = "$Id: genbox.c,v 2.11 2021/04/09 01:48:20 greg Exp $"; #endif /* * genbox.c - generate a parallelepiped. @@ -8,35 +8,79 @@ static const char RCSid[] = "$Id: genbox.c,v 2.10 2021 */ #include "rtio.h" +#include "rtmath.h" +#include "objutil.h" #include -#include +char *progname; + +int verbose = 0; + char let[]="0123456789._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -char *cmtype; /* ppd material type */ +char *cmtype; /* ppd material type */ -char *cname; /* ppd name */ +char *cname; /* ppd name */ -double size[3]; /* ppd size */ +double size[3]; /* ppd size */ -double bevel = 0.0; /* bevel amount */ +int rounde = 0; /* round edges? (#segments = 2^rounde) */ -int rounde = 0; /* boolean true for round edges */ +double bevel = 0.0; /* bevel amount or round edge radius */ -int reverse = 0; /* boolean true for reversed normals */ +int rev = 0; /* boolean true for reversed normals */ +Scene *obj = NULL; /* save as .OBJ scene if not NULL */ +int vid[0100]; /* vertex ID's for .OBJ scene */ + + +static int +overtex(int v) /* index a .OBJ vertex */ +{ + double vpos[3]; + int i; + + if (vid[v] >= 0) /* already have this vertex? */ + return(vid[v]); + /* else create new ID */ + for (i = 0; i < 3; i++) + if (v>>i & 010) + vpos[i] = (v>>i & 01)^rev ? size[i]-bevel : bevel; + else + vpos[i] = (v>>i & 01)^rev ? size[i] : 0.0; + + return(vid[v] = addVertex(obj, vpos[0], vpos[1], vpos[2])); +} + + +static int +onormal(int vid1, int vid2, int vid3) /* index a .OBJ normal */ +{ + double *p1 = obj->vert[vid1].p; + double *p2 = obj->vert[vid2].p; + double *p3 = obj->vert[vid3].p; + FVECT sv1, sv2, nrm; + + VSUB(sv1, p2, p1); + VSUB(sv2, p3, p2); + VCROSS(nrm, sv1, sv2); + + return(addNormal(obj, nrm[0], nrm[1], nrm[2])); +} + + static void -vertex(int v) +vertex(int v) /* print a Radiance vertex */ { int i; for (i = 0; i < 3; i++) { if (v & 010) - printf("\t%18.12g", (v&01)^reverse ? size[i]-bevel : bevel); + printf("\t%18.12g", (v&01)^rev ? size[i]-bevel : bevel); else - printf("\t%18.12g", (v&01)^reverse ? size[i] : 0.0); + printf("\t%18.12g", (v&01)^rev ? size[i] : 0.0); v >>= 1; } fputc('\n', stdout); @@ -46,6 +90,20 @@ vertex(int v) static void side(int a, int b, int c, int d) /* generate a rectangular face */ { + if (obj != NULL) { /* working on .OBJ? */ + VNDX quadv[4]; + memset(quadv, 0xff, sizeof(quadv)); + quadv[0][0] = overtex(a); + quadv[1][0] = overtex(b); + quadv[2][0] = overtex(c); + quadv[3][0] = overtex(d); + if (rounde) /* add normal if rounded */ + quadv[0][2] = quadv[1][2] = quadv[2][2] = quadv[3][2] + = onormal(quadv[0][0], quadv[1][0], quadv[2][0]); + addFace(obj, quadv, 4); + return; + } + /* Radiance output */ printf("\n%s polygon %s.%c%c%c%c\n", cmtype, cname, let[a], let[b], let[c], let[d]); printf("0\n0\n12\n"); @@ -59,6 +117,16 @@ side(int a, int b, int c, int d) /* generate a rectan static void corner(int a, int b, int c) /* generate a triangular face */ { + if (obj != NULL) { /* working on .OBJ? */ + VNDX triv[3]; + memset(triv, 0xff, sizeof(triv)); + triv[0][0] = overtex(a); + triv[1][0] = overtex(b); + triv[2][0] = overtex(c); + addFace(obj, triv, 3); + return; + } + /* Radiance output */ printf("\n%s polygon %s.%c%c%c\n", cmtype, cname, let[a], let[b], let[c]); printf("0\n0\n9\n"); @@ -69,9 +137,71 @@ corner(int a, int b, int c) /* generate a triangular static void -cylinder(int v0, int v1) /* generate a cylinder */ +cylinder(int v0, int v1) /* generate a rounded edge */ { - printf("\n%s cylinder %s.%c%c\n", cmtype, cname, v0+'0', v1+'0'); + if (obj != NULL) { /* segmenting for .OBJ? */ + const int nsgn = 1 - 2*rev; + const int nseg = 1<vert[vid0].p); + VCOPY(p1, obj->vert[vid1].p); + + memset(axis, 0, sizeof(axis)); + + switch ((v0 ^ v1) & 07) { + case 01: /* edge along X-axis */ + axis[1][1] = bevel*(1. - 2.*(p1[1] < .5*size[1])); + axis[0][2] = bevel*(1. - 2.*(p1[2] < .5*size[2])); + break; + case 02: /* edge along Y-axis */ + axis[0][0] = bevel*(1. - 2.*(p1[0] < .5*size[0])); + axis[1][2] = bevel*(1. - 2.*(p1[2] < .5*size[2])); + break; + case 04: /* edge along Z-axis */ + axis[0][1] = bevel*(1. - 2.*(p1[1] < .5*size[1])); + axis[1][0] = bevel*(1. - 2.*(p1[0] < .5*size[0])); + break; + } + previd[0] = addVertex(obj, p0[0]+axis[0][0], + p0[1]+axis[0][1], p0[2]+axis[0][2]); + previd[1] = addVertex(obj, p1[0]+axis[0][0], + p1[1]+axis[0][1], p1[2]+axis[0][2]); + prenid = addNormal(obj, axis[0][0]*nsgn, + axis[0][1]*nsgn, axis[0][2]*nsgn); + for (i = 1; i <= nseg; i++) { + memset(quadv, 0xff, sizeof(quadv)); + quadv[0][0] = previd[0]; + quadv[1][0] = previd[1]; + quadv[0][2] = quadv[1][2] = prenid; + coef[0] = cos(astep*i); + coef[1] = sin(astep*i); + for (j = 0; j < 3; j++) + voff[j] = coef[0]*axis[0][j] + coef[1]*axis[1][j]; + previd[0] = quadv[3][0] + = addVertex(obj, p0[0]+voff[0], + p0[1]+voff[1], p0[2]+voff[2]); + previd[1] = quadv[2][0] + = addVertex(obj, p1[0]+voff[0], + p1[1]+voff[1], p1[2]+voff[2]); + prenid = quadv[2][2] = quadv[3][2] + = addNormal(obj, voff[0]*nsgn, + voff[1]*nsgn, voff[2]*nsgn); + addFace(obj, quadv, 4); + } + return; + } + /* Radiance output */ + printf("\n%s cylinder %s.%c%c\n", cmtype, cname, let[v0], let[v1]); printf("0\n0\n7\n"); vertex(v0); vertex(v1); @@ -79,10 +209,62 @@ cylinder(int v0, int v1) /* generate a cylinder */ } +static void /* recursive corner subdivision */ +osubcorner(const FVECT orig, const FVECT c0, const FVECT c1, const FVECT c2, int lvl) +{ + if (lvl-- <= 0) { /* reached terminal depth? */ + const int nsgn = 1 - 2*rev; + FVECT vpos; + VNDX triv[3]; /* output smoothed triangle */ + VSUM(vpos, orig, c0, bevel); + triv[0][0] = addVertex(obj, vpos[0], vpos[1], vpos[2]); + triv[0][2] = addNormal(obj, c0[0]*nsgn, c0[1]*nsgn, c0[2]*nsgn); + VSUM(vpos, orig, c1, bevel); + triv[1][0] = addVertex(obj, vpos[0], vpos[1], vpos[2]); + triv[1][2] = addNormal(obj, c1[0]*nsgn, c1[1]*nsgn, c1[2]*nsgn); + VSUM(vpos, orig, c2, bevel); + triv[2][0] = addVertex(obj, vpos[0], vpos[1], vpos[2]); + triv[2][2] = addNormal(obj, c2[0]*nsgn, c2[1]*nsgn, c2[2]*nsgn); + triv[0][1] = triv[1][1] = triv[2][1] = -1; + addFace(obj, triv, 3); + } else { /* else subdivide 4 subcorners */ + FVECT m01, m12, m20; + VADD(m01, c0, c1); normalize(m01); + VADD(m12, c1, c2); normalize(m12); + VADD(m20, c2, c0); normalize(m20); + osubcorner(orig, c0, m01, m20, lvl); + osubcorner(orig, c1, m12, m01, lvl); + osubcorner(orig, c2, m20, m12, lvl); + osubcorner(orig, m01, m12, m20, lvl); + } +} + + static void -sphere(int v0) /* generate a sphere */ +sphere(int v0) /* generate a rounded corner */ { - printf("\n%s sphere %s.%c\n", cmtype, cname, v0+'0'); + if (obj != NULL) { /* segmenting for .OBJ? */ + FVECT orig, cdir[3]; + int i; + memset(cdir, 0, sizeof(cdir)); + for (i = 0; i < 3; i++) + cdir[i][i] = 2*((v0>>i & 01)^rev) - 1; + switch (v0 & 07) { + case 0: + case 3: + case 5: + case 6: + VCOPY(orig, cdir[0]); + VCOPY(cdir[0], cdir[1]); + VCOPY(cdir[1], orig); + } + i = overtex(v0); + VCOPY(orig, obj->vert[i].p); /* realloc remedy */ + osubcorner(orig, cdir[0], cdir[1], cdir[2], rounde); + return; + } + /* Radiance output */ + printf("\n%s sphere %s.%c\n", cmtype, cname, let[v0]); printf("0\n0\n4\n"); vertex(v0); printf("\t%18.12g\n", bevel); @@ -92,8 +274,12 @@ sphere(int v0) /* generate a sphere */ int main(int argc, char *argv[]) { + int nsegs = 1; + int objout = 0; int i; - + + progname = argv[0]; + if (argc < 6) goto userr; @@ -109,30 +295,46 @@ main(int argc, char *argv[]) if (argv[i][0] != '-') goto userr; switch (argv[i][1]) { - case 'i': - reverse = 1; + case 'o': /* requesting .OBJ output */ + objout = 1; break; - case 'r': + case 'i': /* invert surface normals */ + rev = 1; + break; + case 'r': /* rounded edges/corners */ rounde = 1; /* fall through */ - case 'b': + case 'b': /* beveled edges */ bevel = atof(argv[++i]); - if (bevel > 0.0) - break; - /* fall through on error */ + if (bevel <= 0.0) + goto userr; + break; + case 'n': /* #segments for rounding */ + nsegs = atoi(argv[++i]); + if (nsegs <= 0) + goto userr; + break; default: goto userr; } } - if (rounde & reverse) - fprintf(stderr, "%s: warning - option -i ignored with -r\n", - argv[0]); - - fputs("# ", stdout); + if ((objout|rev) & (nsegs==1)) /* default to 32 segments/edge */ + nsegs = 32; + if (rounde) { /* rounding edges/corners? */ + --nsegs; + while ((nsegs >>= 1)) /* segmentation requested? */ + ++rounde; + } + if (rounde > 1 || objout) { /* save as .OBJ scene? */ + obj = newScene(); + setMaterial(obj, cmtype); + setGroup(obj, cname); + memset(vid, 0xff, sizeof(vid)); + } + fputs("# ", stdout); /* write command as comment */ printargs(argc, argv, stdout); - if (bevel > 0.0) { - /* minor faces */ + if (bevel > 0.0) { /* minor faces */ side(051, 055, 054, 050); side(064, 066, 062, 060); side(032, 033, 031, 030); @@ -140,8 +342,7 @@ main(int argc, char *argv[]) side(065, 061, 063, 067); side(036, 034, 035, 037); } - if (bevel > 0.0 && !rounde) { - /* bevel faces */ + if (bevel > 0.0 && !rounde) { /* bevel faces */ side(031, 051, 050, 030); side(060, 062, 032, 030); side(050, 054, 064, 060); @@ -154,7 +355,7 @@ main(int argc, char *argv[]) side(065, 067, 037, 035); side(055, 051, 061, 065); side(034, 054, 055, 035); - /* bevel corners */ + /* bevel corners */ corner(030, 050, 060); corner(051, 031, 061); corner(032, 062, 052); @@ -164,8 +365,7 @@ main(int argc, char *argv[]) corner(053, 063, 033); corner(037, 067, 057); } - if (bevel > 0.0 && rounde) { - /* round edges */ + if (bevel > 0.0 && rounde) { /* round edges */ cylinder(070, 071); cylinder(070, 074); cylinder(070, 072); @@ -178,7 +378,7 @@ main(int argc, char *argv[]) cylinder(076, 072); cylinder(076, 074); cylinder(076, 077); - /* round corners */ + /* round corners */ sphere(070); sphere(071); sphere(072); @@ -188,8 +388,7 @@ main(int argc, char *argv[]) sphere(076); sphere(077); } - if (bevel == 0.0) { - /* only need major faces */ + if (bevel == 0.0) { /* only need major faces */ side(1, 5, 4, 0); side(4, 6, 2, 0); side(2, 3, 1, 0); @@ -197,10 +396,19 @@ main(int argc, char *argv[]) side(5, 1, 3, 7); side(6, 4, 5, 7); } + if (obj != NULL) { /* need to write output? */ + if (objout) { + coalesceVertices(obj, 2.*FTINY); + if (toOBJ(obj, stdout) <= 0) + return(1); + } else if (toRadiance(obj, stdout, 0, 0) <= 0) + return(1); + /* freeScene(obj); we're exiting, anyway... */ + } return(0); userr: fprintf(stderr, "Usage: %s ", argv[0]); fprintf(stderr, "material name xsize ysize zsize "); - fprintf(stderr, "[-i] [-b bevel | -r round]\n"); + fprintf(stderr, "[-i] [-b bevel | -r round [-n nsegs]] [-o]\n"); return(1); }