--- ray/src/common/objutil.c 2020/05/02 00:12:45 2.5 +++ ray/src/common/objutil.c 2022/01/15 02:00:21 2.21 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: objutil.c,v 2.5 2020/05/02 00:12:45 greg Exp $"; +static const char RCSid[] = "$Id: objutil.c,v 2.21 2022/01/15 02:00:21 greg Exp $"; #endif /* * Basic .OBJ scene handling routines. @@ -19,7 +19,7 @@ static const char RCSid[] = "$Id: objutil.c,v 2.5 2020 int findName(const char *nm, const char **nmlist, int n) { - register int i; + int i; for (i = n; i-- > 0; ) if (!strcmp(nmlist[i], nm)) @@ -31,7 +31,7 @@ findName(const char *nm, const char **nmlist, int n) void clearSelection(Scene *sc, int set) { - Face *f; + Face *f; for (f = sc->flist; f != NULL; f = f->next) if (set) @@ -44,8 +44,8 @@ clearSelection(Scene *sc, int set) void selectGroup(Scene *sc, const char *gname, int invert) { - int gid = findName(gname, (const char **)sc->grpname, sc->ngrps); - Face *f; + int gid = getGroupID(sc, gname); + Face *f; if (gid < 0) return; @@ -62,8 +62,8 @@ selectGroup(Scene *sc, const char *gname, int invert) void selectMaterial(Scene *sc, const char *mname, int invert) { - int mid = findName(mname, (const char **)sc->matname, sc->nmats); - Face *f; + int mid = getMaterialID(sc, mname); + Face *f; if (mid < 0) return; @@ -80,7 +80,7 @@ selectMaterial(Scene *sc, const char *mname, int inver void invertSelection(Scene *sc) { - Face *f; + Face *f; for (f = sc->flist; f != NULL; f = f->next) f->flags ^= FACE_SELECTED; @@ -90,8 +90,8 @@ invertSelection(Scene *sc) int numberSelected(Scene *sc) { - int nsel = 0; - Face *f; + int nsel = 0; + Face *f; for (f = sc->flist; f != NULL; f = f->next) nsel += ((f->flags & FACE_SELECTED) != 0); @@ -103,9 +103,9 @@ int foreachFace(Scene *sc, int (*cb)(Scene *, Face *, void *), int flreq, int flexc, void *c_data) { - int fltest = flreq | flexc; - int sum = 0; - Face *f; + const int fltest = flreq | flexc; + int sum = 0; + Face *f; if ((sc == NULL) | (cb == NULL)) return(0); @@ -123,8 +123,8 @@ foreachFace(Scene *sc, int (*cb)(Scene *, Face *, void static int remFaceTexture(Scene *sc, Face *f, void *dummy) { - int hadTexture = 0; - int i; + int hadTexture = 0; + int i; for (i = f->nv; i-- > 0; ) { if (f->v[i].tid < 0) @@ -146,8 +146,8 @@ removeTexture(Scene *sc, int flreq, int flexc) static int remFaceNormal(Scene *sc, Face *f, void *dummy) { - int hadNormal = 0; - int i; + int hadNormal = 0; + int i; for (i = f->nv; i-- > 0; ) { if (f->v[i].nid < 0) @@ -169,7 +169,8 @@ removeNormals(Scene *sc, int flreq, int flexc) static int chngFaceGroup(Scene *sc, Face *f, void *ptr) { - int grp = *(int *)ptr; + int grp = *(int *)ptr; + if (f->grp == grp) return(0); f->grp = grp; @@ -180,7 +181,8 @@ chngFaceGroup(Scene *sc, Face *f, void *ptr) int changeGroup(Scene *sc, const char *gname, int flreq, int flexc) { - int grp = findName(gname, (const char **)sc->grpname, sc->ngrps); + int grp = getGroupID(sc, gname); + if (grp < 0) { sc->grpname = chunk_alloc(char *, sc->grpname, sc->ngrps); sc->grpname[grp=sc->ngrps++] = savqstr((char *)gname); @@ -192,7 +194,8 @@ changeGroup(Scene *sc, const char *gname, int flreq, i static int chngFaceMaterial(Scene *sc, Face *f, void *ptr) { - int mat = *(int *)ptr; + int mat = *(int *)ptr; + if (f->mat == mat) return(0); f->mat = mat; @@ -203,7 +206,8 @@ chngFaceMaterial(Scene *sc, Face *f, void *ptr) int changeMaterial(Scene *sc, const char *mname, int flreq, int flexc) { - int mat = findName(mname, (const char **)sc->matname, sc->nmats); + int mat = getMaterialID(sc, mname); + if (mat < 0) { sc->matname = chunk_alloc(char *, sc->matname, sc->nmats); sc->matname[mat=sc->nmats++] = savqstr((char *)mname); @@ -248,10 +252,10 @@ norm_diff(const Normal n1, const Normal n2, double eps static int replace_vertex(Scene *sc, int prev, int repl, double eps) { - int repl_tex[10]; - int repl_norm[10]; - Face *f, *flast=NULL; - int i, j=0; + int repl_tex[10]; + int repl_norm[10]; + Face *f, *flast=NULL; + int i, j=0; /* check to see if it's even used */ if (sc->vert[prev].vflist == NULL) return(0); @@ -259,13 +263,13 @@ replace_vertex(Scene *sc, int prev, int repl, double e repl_tex[0] = -1; for (f = sc->vert[repl].vflist; f != NULL; f = f->v[j].fnext) { /* make sure prev isn't in there */ - for (j = 0; j < f->nv; j++) + for (j = f->nv; j-- > 0; ) if (f->v[j].vid == prev) return(0); - for (j = 0; j < f->nv; j++) + for (j = f->nv; j-- > 0; ) if (f->v[j].vid == repl) break; - if (j >= f->nv) + if (j < 0) goto linkerr; if (f->v[j].tid < 0) continue; @@ -290,7 +294,7 @@ replace_vertex(Scene *sc, int prev, int repl, double e /* get replacement normals */ repl_norm[0] = -1; for (f = sc->vert[repl].vflist; f != NULL; f = f->v[j].fnext) { - for (j = 0; j < f->nv; j++) + for (j = f->nv; j-- > 0; ) if (f->v[j].vid == repl) break; if (f->v[j].nid < 0) @@ -315,14 +319,14 @@ replace_vertex(Scene *sc, int prev, int repl, double e } /* replace occurrences of vertex */ for (f = sc->vert[prev].vflist; f != NULL; f = f->v[j].fnext) { - for (j = 0; j < f->nv; j++) + for (j = f->nv; j-- > 0; ) if (f->v[j].vid == prev) break; - if (j >= f->nv) + if (j < 0) goto linkerr; /* XXX doesn't allow for multiple references to prev in face */ f->v[j].vid = repl; /* replace vertex itself */ - if (faceArea(sc, f, NULL) <= FTINY) + if (faceArea(sc, f, NULL) <= FTINY*FTINY) f->flags |= FACE_DEGENERATE; if (f->v[j].tid >= 0) /* replace texture if appropriate */ for (i = 0; repl_tex[i] >= 0; i++) { @@ -360,12 +364,12 @@ linkerr: int coalesceVertices(Scene *sc, double eps) { - int nelim = 0; - LUTAB myLookup; - LUENT *le; - char vertfmt[32], vertbuf[64]; - double d; - int i; + int nelim = 0; + LUTAB myLookup; + LUENT *le; + char vertfmt[32], vertbuf[64]; + double d; + int i; if (eps >= 1.) return(0); @@ -412,11 +416,11 @@ coalesceVertices(Scene *sc, double eps) int findDuplicateFaces(Scene *sc) { - int nchecked = 0; - int nfound = 0; - Face *f, *f1; - int vid; - int i, j; + int nchecked = 0; + int nfound = 0; + Face *f, *f1; + int vid; + int i, j; /* start fresh */ for (f = sc->flist; f != NULL; f = f->next) f->flags &= ~FACE_DUPLICATE; @@ -432,10 +436,10 @@ findDuplicateFaces(Scene *sc) /* look for duplicates */ for (f1 = sc->vert[vid].vflist; f1 != NULL; f1 = f1->v[j].fnext) { - for (j = 0; j < f1->nv; j++) + for (j = f1->nv; j-- > 0; ) if (f1->v[j].vid == vid) break; - if (j >= f1->nv) + if (j < 0) break; /* missing link! */ if (f1 == f) continue; /* shouldn't happen */ @@ -460,6 +464,8 @@ findDuplicateFaces(Scene *sc) ++nfound; } } + if (verbose) + fprintf(stderr, "Found %d duplicate faces\n", nfound); return(nfound); } @@ -467,10 +473,10 @@ findDuplicateFaces(Scene *sc) int deleteFaces(Scene *sc, int flreq, int flexc) { - int fltest = flreq | flexc; - int orig_nfaces = sc->nfaces; - Face fhead; - Face *f, *ftst; + const int fltest = flreq | flexc; + int orig_nfaces = sc->nfaces; + Face fhead; + Face *f, *ftst; fhead.next = sc->flist; f = &fhead; @@ -486,10 +492,10 @@ deleteFaces(Scene *sc, int flreq, int flexc) continue; } while (vf != NULL) { - for (j = 0; j < vf->nv; j++) + for (j = vf->nv; j-- > 0; ) if (vf->v[j].vid == vid) break; - if (j >= vf->nv) + if (j < 0) break; /* error */ if (vf->v[j].fnext == ftst) { vf->v[j].fnext = @@ -547,6 +553,19 @@ addComment(Scene *sc, const char *comment) sc->descr[sc->ndescr++] = savqstr((char *)comment); } +/* Find index for comment containing the given string (starting from n) */ +int +findComment(Scene *sc, const char *match, int n) +{ + if (n >= sc->ndescr) + return(-1); + n *= (n > 0); + while (n < sc->ndescr) + if (strstr(sc->descr[n], match) != NULL) + return(n); + return(-1); +} + /* Clear comments */ void clearComments(Scene *sc) @@ -554,6 +573,7 @@ clearComments(Scene *sc) while (sc->ndescr > 0) freeqstr(sc->descr[--sc->ndescr]); efree((char *)sc->descr); + sc->descr = NULL; sc->ndescr = 0; } @@ -573,10 +593,10 @@ add2facelist(Scene *sc, Face *f, int i) for ( ; ; ) { /* else find position */ if (fp == f) return; /* already in list */ - for (j = 0; j < fp->nv; j++) + for (j = fp->nv; j-- > 0; ) if (fp->v[j].vid == vid) break; - if (j >= fp->nv) + if (j < 0) error(CONSISTENCY, "Link error in add2facelist()"); if (fp->v[j].fnext == NULL) break; /* reached the end */ @@ -585,20 +605,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) @@ -625,7 +631,7 @@ addTexture(Scene *sc, double u, double v) int addNormal(Scene *sc, double xn, double yn, double zn) { - FVECT nrm; + FVECT nrm; nrm[0] = xn; nrm[1] = yn; nrm[2] = zn; if (normalize(nrm) == .0) @@ -639,7 +645,7 @@ addNormal(Scene *sc, double xn, double yn, double zn) void setGroup(Scene *sc, const char *nm) { - sc->lastgrp = findName(nm, (const char **)sc->grpname, sc->ngrps); + sc->lastgrp = getGroupID(sc, nm); if (sc->lastgrp >= 0) return; sc->grpname = chunk_alloc(char *, sc->grpname, sc->ngrps); @@ -650,7 +656,7 @@ setGroup(Scene *sc, const char *nm) void setMaterial(Scene *sc, const char *nm) { - sc->lastmat = findName(nm, (const char **)sc->matname, sc->nmats); + sc->lastmat = getMaterialID(sc, nm); if (sc->lastmat >= 0) return; sc->matname = chunk_alloc(char *, sc->matname, sc->nmats); @@ -661,8 +667,8 @@ setMaterial(Scene *sc, const char *nm) Face * addFace(Scene *sc, VNDX vid[], int nv) { - Face *f; - int i; + Face *f; + int i; if (nv < 3) return(NULL); @@ -690,15 +696,113 @@ addFace(Scene *sc, VNDX vid[], int nv) sc->flist = f; sc->nfaces++; /* check face area */ - if (!(f->flags & FACE_DEGENERATE) && faceArea(sc, f, NULL) <= FTINY) + if (!(f->flags & FACE_DEGENERATE) && faceArea(sc, f, NULL) <= FTINY*FTINY) f->flags |= FACE_DEGENERATE; return(f); } -/* Duplicate a scene */ +/* 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(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 * -dupScene(const Scene *osc) +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) +{ + int fltest = flreq | flexc; Scene *sc; const Face *fo; Face *f; @@ -709,25 +813,24 @@ dupScene(const Scene *osc) 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(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(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; @@ -735,35 +838,112 @@ dupScene(const Scene *osc) 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) { - f = (Face *)emalloc(sizeof(Face) + - sizeof(VertEnt)*(fo->nv-3)); - memcpy((void *)f, (const void *)fo, sizeof(Face) + - sizeof(VertEnt)*(fo->nv-3)); + if ((fo->flags & fltest) != flreq) + continue; + 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; sc->flist = f; sc->nfaces++; } + deleteUnreferenced(sc); /* jetsam */ return(sc); } +/* Add one scene to another, not checking for redundancies */ +int +addScene(Scene *scdst, const Scene *scsrc) +{ + VNDX my_vlist[4]; + int *vert_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; + int cur_grp = 0; + int fcnt = 0; + const Face *f; + int i; + + if ((scdst == NULL) | (scsrc == NULL)) + return(-1); + if (scsrc->nfaces <= 0) + return(0); + /* map vertices */ + 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) { + vert_map[i] = -1; + continue; + } + vert_map[i] = addVertex(scdst, v->p[0], v->p[1], v->p[2]); + } + tex_off = scdst->ntex; /* append texture coords */ + if (scsrc->ntex > 0) { + scdst->tex = (TexCoord *)erealloc(scdst->tex, + sizeof(TexCoord)*(tex_off+scsrc->ntex+(CHUNKSIZ-1))); + memcpy(scdst->tex+tex_off, scsrc->tex, + sizeof(TexCoord)*scsrc->ntex); + } + norm_off = scdst->nnorms; /* append normals */ + if (scsrc->nnorms > 0) { + scdst->norm = (Normal *)erealloc(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; + for (f = scsrc->flist; f != NULL; f = f->next) { + if (f->grp != cur_grp) + setGroup(scdst, scsrc->grpname[cur_grp = f->grp]); + if (f->mat != cur_mat) + setMaterial(scdst, scsrc->matname[cur_mat = f->mat]); + if (f->nv > vllen) { + vlist = (VNDX *)( vlist == my_vlist ? + emalloc(sizeof(VNDX)*f->nv) : + erealloc(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] = f->v[i].tid + tex_off; + if (f->v[i].nid >= 0) + vlist[i][2] = f->v[i].nid + norm_off; + } + fcnt += (addFace(scdst, vlist, f->nv) != NULL); + } + /* clean up */ + if (vlist != my_vlist) efree(vlist); + efree(vert_map); + return(fcnt); +} + +#define MAXAC 100 + /* Transform entire scene */ int xfScene(Scene *sc, int xac, char *xav[]) { + char comm[24+MAXAC*8]; + char *cp; XF myxf; FVECT vec; int i; @@ -786,11 +966,18 @@ xfScene(Scene *sc, int xac, char *xav[]) vec[0] /= myxf.sca; vec[1] /= myxf.sca; vec[2] /= myxf.sca; VCOPY(sc->norm[i], vec); } + /* add comment */ + cp = strcpy(comm, "Transformed by:"); + for (i = 0; i < xac; i++) { + while (*cp) cp++; + *cp++ = ' '; + strcpy(cp, xav[i]); + } + addComment(sc, comm); return(xac); /* all done */ } /* Ditto, using transform string rather than pre-parsed words */ -#define MAXAC 100 int xfmScene(Scene *sc, const char *xfm) { @@ -805,7 +992,7 @@ xfmScene(Scene *sc, const char *xfm) if (!*xfm) return(0); /* parse string into words */ - xav[0] = strcpy((char *)malloc(strlen(xfm)+1), xfm); + xav[0] = savqstr((char *)xfm); xac = 1; i = 0; for ( ; ; ) { while (!isspace(xfm[++i])) @@ -816,18 +1003,109 @@ xfmScene(Scene *sc, const char *xfm) if (!xfm[i]) break; if (xac >= MAXAC-1) { - free(xav[0]); + freeqstr(xav[0]); return(0); } xav[xac++] = xav[0] + i; } xav[xac] = NULL; i = xfScene(sc, xac, xav); - free(xav[0]); + freeqstr(xav[0]); return(i); } #undef MAXAC +/* Delete unreferenced vertices, normals, texture coords */ +void +deleteUnreferenced(Scene *sc) +{ + int *vmap; + Face *f; + int nused, i; + /* allocate index map */ + if (!sc->nverts) + return; + i = sc->nverts; + if (sc->ntex > i) + i = sc->ntex; + if (sc->nnorms > i) + i = sc->nnorms; + vmap = (int *)emalloc(sizeof(int)*i); + /* remap positions */ + for (i = nused = 0; i < sc->nverts; i++) { + if (sc->vert[i].vflist == NULL) { + vmap[i] = -1; + continue; + } + if (nused != i) + sc->vert[nused] = sc->vert[i]; + vmap[i] = nused++; + } + if (nused == sc->nverts) + goto skip_pos; + sc->vert = (Vertex *)erealloc(sc->vert, + sizeof(Vertex)*(nused+(CHUNKSIZ-1))); + sc->nverts = nused; + for (f = sc->flist; f != NULL; f = f->next) + for (i = f->nv; i--; ) + if ((f->v[i].vid = vmap[f->v[i].vid]) < 0) + error(CONSISTENCY, + "Link error in del_unref_verts()"); +skip_pos: + /* remap texture coord's */ + if (!sc->ntex) + goto skip_tex; + memset((void *)vmap, 0, sizeof(int)*sc->ntex); + for (f = sc->flist; f != NULL; f = f->next) + for (i = f->nv; i--; ) + if (f->v[i].tid >= 0) + vmap[f->v[i].tid] = 1; + for (i = nused = 0; i < sc->ntex; i++) { + if (!vmap[i]) + continue; + if (nused != i) + sc->tex[nused] = sc->tex[i]; + vmap[i] = nused++; + } + if (nused == sc->ntex) + goto skip_tex; + sc->tex = (TexCoord *)erealloc(sc->tex, + sizeof(TexCoord)*(nused+(CHUNKSIZ-1))); + sc->ntex = nused; + for (f = sc->flist; f != NULL; f = f->next) + for (i = f->nv; i--; ) + if (f->v[i].tid >= 0) + f->v[i].tid = vmap[f->v[i].tid]; +skip_tex: + /* remap normals */ + if (!sc->nnorms) + goto skip_norms; + memset((void *)vmap, 0, sizeof(int)*sc->nnorms); + for (f = sc->flist; f != NULL; f = f->next) + for (i = f->nv; i--; ) + if (f->v[i].nid >= 0) + vmap[f->v[i].nid] = 1; + for (i = nused = 0; i < sc->nnorms; i++) { + if (!vmap[i]) + continue; + if (nused != i) + memcpy(sc->norm[nused], sc->norm[i], sizeof(Normal)); + vmap[i] = nused++; + } + if (nused == sc->nnorms) + goto skip_norms; + sc->norm = (Normal *)erealloc(sc->norm, + sizeof(Normal)*(nused+(CHUNKSIZ-1))); + sc->nnorms = nused; + for (f = sc->flist; f != NULL; f = f->next) + for (i = f->nv; i--; ) + if (f->v[i].nid >= 0) + f->v[i].nid = vmap[f->v[i].nid]; +skip_norms: + /* clean up */ + efree(vmap); +} + /* Free a scene */ void freeScene(Scene *sc) @@ -840,16 +1118,16 @@ freeScene(Scene *sc) clearComments(sc); for (i = sc->ngrps; i-- > 0; ) freeqstr(sc->grpname[i]); - efree((char *)sc->grpname); + efree(sc->grpname); for (i = sc->nmats; i-- > 0; ) freeqstr(sc->matname[i]); - efree((char *)sc->matname); - efree((char *)sc->vert); - efree((char *)sc->tex); - efree((char *)sc->norm); + efree(sc->matname); + efree(sc->vert); + efree(sc->tex); + efree(sc->norm); while ((f = sc->flist) != NULL) { sc->flist = f->next; - efree((char *)f); + efree(f); } - efree((char *)sc); + efree(sc); }