--- ray/src/common/objutil.c 2021/04/07 03:02:00 2.14 +++ ray/src/common/objutil.c 2021/04/23 18:31:45 2.19 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: objutil.c,v 2.14 2021/04/07 03:02:00 greg Exp $"; +static const char RCSid[] = "$Id: objutil.c,v 2.19 2021/04/23 18:31:45 greg Exp $"; #endif /* * Basic .OBJ scene handling routines. @@ -604,20 +604,6 @@ add2facelist(Scene *sc, Face *f, int i) fp->v[j].fnext = f; /* append new face */ } -/* Allocate an empty scene */ -Scene * -newScene(void) -{ - Scene *sc = (Scene *)ecalloc(1, sizeof(Scene)); - /* default group & material */ - sc->grpname = chunk_alloc(char *, sc->grpname, sc->ngrps); - sc->grpname[sc->ngrps++] = savqstr("DEFAULT_GROUP"); - sc->matname = chunk_alloc(char *, sc->matname, sc->nmats); - sc->matname[sc->nmats++] = savqstr("DEFAULT_MATERIAL"); - - return(sc); -} - /* Add a vertex to a scene */ int addVertex(Scene *sc, double x, double y, double z) @@ -714,6 +700,103 @@ addFace(Scene *sc, VNDX vid[], int nv) return(f); } +/* Get neighbor vertices: malloc array with valence in index[0] */ +int * +getVertexNeighbors(Scene *sc, int vid) +{ + int *varr; + Face *f; + int j=0; + + if (sc == NULL || (vid < 0) | (vid >= sc->nverts) || + (f = sc->vert[vid].vflist) == NULL) + return(NULL); + + varr = (int *)emalloc(sizeof(int)*CHUNKSIZ); + varr[0] = 0; /* add unique neighbors */ + for ( ; f != NULL; f = f->v[j].fnext) { + int i, cvi; + for (j = f->nv; j--; ) /* find ourself in poly */ + if (f->v[j].vid == vid) + break; + if (j < 0) /* this is an error */ + break; + if (f->nv < 3) /* also never happens */ + continue; + /* check previous neighbor */ + cvi = f->v[ (j > 0) ? j-1 : f->nv-1 ].vid; + for (i = varr[0]+1; --i; ) /* making sure not in list */ + if (varr[i] == cvi) + break; + if (!i) { /* new neighbor? */ + varr = chunk_alloc(int, varr, varr[0]+1); + varr[++varr[0]] = cvi; + } + /* check next neighbor */ + cvi = f->v[ (j < f->nv-1) ? j+1 : 0 ].vid; + for (i = varr[0]+1; --i; ) + if (varr[i] == cvi) + break; + if (!i) { + varr = chunk_alloc(int, varr, varr[0]+1); + varr[++varr[0]] = cvi; + } + } + if (!varr[0]) { + efree((char *)varr); /* something went awry */ + return(NULL); + } + /* tighten array & return */ + return((int *)erealloc((char *)varr, sizeof(int)*(varr[0]+1))); +} + +/* Callback for growBoundingBox() */ +static int +addBBox(Scene *sc, Face *f, void *p) +{ + double (*bbox)[3] = (double (*)[3])p; + int i, j; + + for (i = f->nv; i-- > 0; ) { + double *p3 = sc->vert[f->v[i].vid].p; + for (j = 3; j--; ) { + if (p3[j] < bbox[0][j]) + bbox[0][j] = p3[j]; + if (p3[j] > bbox[1][j]) + bbox[1][j] = p3[j]; + } + } + return(1); +} + +/* Expand bounding box min & max (initialize bbox to all zeroes) */ +int +growBoundingBox(Scene *sc, double bbox[2][3], int flreq, int flexc) +{ + if (sc == NULL || sc->nfaces <= 0 || bbox == NULL) + return(0); + + if (VABSEQ(bbox[0], bbox[1])) { /* first run */ + bbox[0][0] = bbox[0][1] = bbox[0][2] = FHUGE; + bbox[1][0] = bbox[1][1] = bbox[1][2] = -FHUGE; + } + return(foreachFace(sc, addBBox, flreq, flexc, bbox)); +} + +/* Allocate an empty scene */ +Scene * +newScene(void) +{ + Scene *sc = (Scene *)ecalloc(1, sizeof(Scene)); + /* default group & material */ + sc->grpname = chunk_alloc(char *, sc->grpname, sc->ngrps); + sc->grpname[sc->ngrps++] = savqstr("DEFAULT_GROUP"); + sc->matname = chunk_alloc(char *, sc->matname, sc->nmats); + sc->matname[sc->nmats++] = savqstr("DEFAULT_MATERIAL"); + + return(sc); +} + /* Duplicate a scene, optionally selecting faces */ Scene * dupScene(const Scene *osc, int flreq, int flexc) @@ -729,25 +812,24 @@ dupScene(const Scene *osc, int flreq, int flexc) sc = newScene(); for (i = 0; i < osc->ndescr; i++) addComment(sc, osc->descr[i]); - if (osc->ngrps) { - sc->grpname = (char **)emalloc(sizeof(char *) * - (osc->ngrps+(CHUNKSIZ-1))); - for (i = 0; i < osc->ngrps; i++) + if (osc->ngrps > 1) { + sc->grpname = (char **)erealloc((char *)sc->grpname, + sizeof(char *) * (osc->ngrps+(CHUNKSIZ-1))); + for (i = 1; i < osc->ngrps; i++) sc->grpname[i] = savqstr(osc->grpname[i]); sc->ngrps = osc->ngrps; } - if (osc->nmats) { - sc->matname = (char **)emalloc(sizeof(char *) * - (osc->nmats+(CHUNKSIZ-1))); - for (i = 0; i < osc->nmats; i++) + if (osc->nmats > 1) { + sc->matname = (char **)erealloc((char *)sc->matname, + sizeof(char *) * (osc->nmats+(CHUNKSIZ-1))); + for (i = 1; i < osc->nmats; i++) sc->matname[i] = savqstr(osc->matname[i]); sc->nmats = osc->nmats; } if (osc->nverts) { sc->vert = (Vertex *)emalloc(sizeof(Vertex) * (osc->nverts+(CHUNKSIZ-1))); - memcpy((void *)sc->vert, (const void *)osc->vert, - sizeof(Vertex)*osc->nverts); + memcpy(sc->vert, osc->vert, sizeof(Vertex)*osc->nverts); sc->nverts = osc->nverts; for (i = 0; i < sc->nverts; i++) sc->vert[i].vflist = NULL; @@ -755,24 +837,20 @@ dupScene(const Scene *osc, int flreq, int flexc) if (osc->ntex) { sc->tex = (TexCoord *)emalloc(sizeof(TexCoord) * (osc->ntex+(CHUNKSIZ-1))); - memcpy((void *)sc->tex, (const void *)osc->tex, - sizeof(TexCoord)*osc->ntex); + memcpy(sc->tex, osc->tex, sizeof(TexCoord)*osc->ntex); sc->ntex = osc->ntex; } if (osc->nnorms) { sc->norm = (Normal *)emalloc(sizeof(Normal) * (osc->nnorms+CHUNKSIZ)); - memcpy((void *)sc->norm, (const void *)osc->norm, - sizeof(Normal)*osc->nnorms); + memcpy(sc->norm, osc->norm, sizeof(Normal)*osc->nnorms); sc->nnorms = osc->nnorms; } for (fo = osc->flist; fo != NULL; fo = fo->next) { if ((fo->flags & fltest) != flreq) continue; - f = (Face *)emalloc(sizeof(Face) + - sizeof(VertEnt)*(fo->nv-3)); - memcpy((void *)f, (const void *)fo, sizeof(Face) + - sizeof(VertEnt)*(fo->nv-3)); + f = (Face *)emalloc(sizeof(Face) + sizeof(VertEnt)*(fo->nv-3)); + memcpy(f, fo, sizeof(Face) + sizeof(VertEnt)*(fo->nv-3)); for (i = 0; i < f->nv; i++) add2facelist(sc, f, i); f->next = sc->flist; @@ -789,8 +867,8 @@ addScene(Scene *scdst, const Scene *scsrc) { VNDX my_vlist[4]; int *vert_map = NULL; - int *norm_map = NULL; - int *tex_map = NULL; + int tex_off = 0; + int norm_off = 0; VNDX *vlist = my_vlist; int vllen = sizeof(my_vlist)/sizeof(VNDX); int cur_mat = 0; @@ -804,7 +882,7 @@ addScene(Scene *scdst, const Scene *scsrc) if (scsrc->nfaces <= 0) return(0); /* map vertices */ - vert_map = (int *)emalloc(sizeof(int *)*scsrc->nverts); + vert_map = (int *)emalloc(sizeof(int)*scsrc->nverts); for (i = 0; i < scsrc->nverts; i++) { const Vertex *v = scsrc->vert + i; if (v->vflist == NULL) { @@ -813,17 +891,19 @@ addScene(Scene *scdst, const Scene *scsrc) } vert_map[i] = addVertex(scdst, v->p[0], v->p[1], v->p[2]); } - if (scsrc->ntex > 0) /* map texture coords */ - tex_map = (int *)emalloc(sizeof(int *)*scsrc->ntex); - for (i = 0; i < scsrc->ntex; i++) { - const TexCoord *t = scsrc->tex + i; - tex_map[i] = addTexture(scdst, t->u, t->v); + tex_off = scdst->ntex; /* append texture coords */ + if (scsrc->ntex > 0) { + scdst->tex = (TexCoord *)erealloc((char *)scdst->tex, + sizeof(TexCoord)*(tex_off+scsrc->ntex+(CHUNKSIZ-1))); + memcpy(scdst->tex+tex_off, scsrc->tex, + sizeof(TexCoord)*scsrc->ntex); } - if (scsrc->nnorms > 0) /* map normals */ - norm_map = (int *)emalloc(sizeof(int *)*scsrc->nnorms); - for (i = 0; i < scsrc->nnorms; i++) { - const float *n = scsrc->norm[i]; - norm_map[i] = addNormal(scdst, n[0], n[1], n[2]); + norm_off = scdst->nnorms; /* append normals */ + if (scsrc->nnorms > 0) { + scdst->norm = (Normal *)erealloc((char *)scdst->norm, + sizeof(Normal)*(norm_off+scsrc->nnorms+(CHUNKSIZ-1))); + memcpy(scdst->norm+norm_off, scsrc->norm, + sizeof(Normal)*scsrc->nnorms); } /* add faces */ scdst->lastgrp = scdst->lastmat = 0; @@ -833,28 +913,24 @@ addScene(Scene *scdst, const Scene *scsrc) if (f->mat != cur_mat) setMaterial(scdst, scsrc->matname[cur_mat = f->mat]); if (f->nv > vllen) { - if (vlist == my_vlist) - vlist = (VNDX *)emalloc( - sizeof(VNDX)*(vllen = f->nv)); - else - vlist = (VNDX *)erealloc((char *)vlist, - sizeof(VNDX)*(vllen = f->nv)); + vlist = (VNDX *)( vlist == my_vlist ? + emalloc(sizeof(VNDX)*f->nv) : + erealloc((char *)vlist, sizeof(VNDX)*f->nv) ); + vllen = f->nv; } memset(vlist, 0xff, sizeof(VNDX)*f->nv); for (i = f->nv; i-- > 0; ) { if (f->v[i].vid >= 0) vlist[i][0] = vert_map[f->v[i].vid]; if (f->v[i].tid >= 0) - vlist[i][1] = tex_map[f->v[i].tid]; + vlist[i][1] = f->v[i].tid + tex_off; if (f->v[i].nid >= 0) - vlist[i][2] = norm_map[f->v[i].nid]; + vlist[i][2] = f->v[i].nid + norm_off; } fcnt += (addFace(scdst, vlist, f->nv) != NULL); } /* clean up */ if (vlist != my_vlist) efree((char *)vlist); - if (norm_map != NULL) efree((char *)norm_map); - if (tex_map != NULL) efree((char *)tex_map); efree((char *)vert_map); return(fcnt); } @@ -1012,9 +1088,7 @@ skip_tex: if (!vmap[i]) continue; if (nused != i) - memcpy((void *)sc->norm[nused], - (void *)sc->norm[i], - sizeof(Normal)); + memcpy(sc->norm[nused], sc->norm[i], sizeof(Normal)); vmap[i] = nused++; } if (nused == sc->nnorms)