--- ray/src/common/mesh.c 2003/03/12 17:26:58 2.3 +++ ray/src/common/mesh.c 2020/07/14 23:13:50 2.34 @@ -1,22 +1,25 @@ #ifndef lint -static const char RCSid[] = "$Id: mesh.c,v 2.3 2003/03/12 17:26:58 greg Exp $"; +static const char RCSid[] = "$Id: mesh.c,v 2.34 2020/07/14 23:13:50 greg Exp $"; #endif /* * Mesh support routines */ -#include "standard.h" +#include "rtio.h" +#include "rtmath.h" +#include "rterror.h" +#include "paths.h" #include "octree.h" #include "object.h" +#include "otypes.h" #include "mesh.h" -#include "lookup.h" /* An encoded mesh vertex */ typedef struct { int fl; - uint4 xyz[3]; - int4 norm; - uint4 uv[2]; + uint32 xyz[3]; + int32 norm; + uint32 uv[2]; } MCVERT; #define MPATCHBLKSIZ 128 /* patch allocation block size */ @@ -27,9 +30,9 @@ static MESH *mlist = NULL; /* list of loaded meshes * static unsigned long -cvhash(cvp) /* hash an encoded vertex */ -MCVERT *cvp; +cvhash(const char *p) /* hash an encoded vertex */ { + const MCVERT *cvp = (const MCVERT *)p; unsigned long hval; if (!(cvp->fl & MT_V)) @@ -44,9 +47,10 @@ MCVERT *cvp; static int -cvcmp(v1, v2) /* compare encoded vertices */ -register MCVERT *v1, *v2; +cvcmp(const char *vv1, const char *vv2) /* compare encoded vertices */ { + const MCVERT *v1 = (const MCVERT *)vv1, *v2 = (const MCVERT *)vv2; + if (v1->fl != v2->fl) return(1); if (v1->xyz[0] != v2->xyz[0]) @@ -68,23 +72,21 @@ register MCVERT *v1, *v2; MESH * -getmesh(mname, flags) /* get mesh data */ -char *mname; -int flags; +getmesh( /* get new mesh data reference */ + char *mname, + int flags +) { char *pathname; - register MESH *ms; + MESH *ms; flags &= IO_LEGAL; for (ms = mlist; ms != NULL; ms = ms->next) if (!strcmp(mname, ms->name)) { - if ((ms->ldflags & flags) == flags) { - ms->nref++; - return(ms); /* loaded */ - } - break; /* load the rest */ + ms->nref++; /* increase reference count */ + break; } - if (ms == NULL) { + if (ms == NULL) { /* load first time */ ms = (MESH *)calloc(1, sizeof(MESH)); if (ms == NULL) error(SYSTEM, "out of memory in getmesh"); @@ -94,9 +96,9 @@ int flags; ms->next = mlist; mlist = ms; } - if ((pathname = getpath(mname, getlibpath(), R_OK)) == NULL) { + if ((pathname = getpath(mname, getrlibpath(), R_OK)) == NULL) { sprintf(errmsg, "cannot find mesh file \"%s\"", mname); - error(USER, errmsg); + error(SYSTEM, errmsg); } flags &= ~ms->ldflags; if (flags) @@ -106,11 +108,12 @@ int flags; MESHINST * -getmeshinst(o, flags) /* create mesh instance */ -OBJREC *o; -int flags; +getmeshinst( /* create mesh instance */ + OBJREC *o, + int flags +) { - register MESHINST *ins; + MESHINST *ins; flags &= IO_LEGAL; if ((ins = (MESHINST *)o->os) == NULL) { @@ -128,71 +131,121 @@ int flags; ins->msh = NULL; o->os = (char *)ins; } - if (ins->msh == NULL || (ins->msh->ldflags & flags) != flags) + if (ins->msh == NULL) ins->msh = getmesh(o->oargs.sarg[0], flags); + else if ((flags &= ~ins->msh->ldflags)) + readmesh(ins->msh, + getpath(o->oargs.sarg[0], getrlibpath(), R_OK), + flags); return(ins); } int -getmeshtrivid(tvid, mp, ti) /* get triangle vertex ID's */ -int4 tvid[3]; -register MESH *mp; -OBJECT ti; +nextmeshtri( /* get next triangle ID */ + OBJECT *tip, + MESH *mp +) { + int pn; + MESHPATCH *pp; + + pn = ++(*tip) >> 10; /* next triangle (OVOID init) */ + while (pn < mp->npatches) { + pp = &mp->patch[pn]; + if (!(*tip & 0x200)) { /* local triangle? */ + if ((*tip & 0x1ff) < pp->ntris) + return(1); + *tip &= ~0x1ff; /* move on to single-joiners */ + *tip |= 0x200; + } + if (!(*tip & 0x100)) { /* single joiner? */ + if ((*tip & 0xff) < pp->nj1tris) + return(1); + *tip &= ~0xff; /* move on to double-joiners */ + *tip |= 0x100; + } + if ((*tip & 0xff) < pp->nj2tris) + return(1); + *tip = ++pn << 10; /* first in next patch */ + } + return(0); /* out of patches */ +} + +int +getmeshtrivid( /* get triangle vertex ID's */ + int32 tvid[3], + OBJECT *mo, + MESH *mp, + OBJECT ti +) +{ int pn = ti >> 10; + MESHPATCH *pp; if (pn >= mp->npatches) return(0); + pp = &mp->patch[pn]; ti &= 0x3ff; if (!(ti & 0x200)) { /* local triangle */ struct PTri *tp; - if (ti >= mp->patch[pn].ntris) + if (ti >= pp->ntris) return(0); - tp = &mp->patch[pn].tri[ti]; + tp = &pp->tri[ti]; tvid[0] = tvid[1] = tvid[2] = pn << 8; tvid[0] |= tp->v1; tvid[1] |= tp->v2; tvid[2] |= tp->v3; + if (pp->trimat != NULL) + *mo = pp->trimat[ti]; + else + *mo = pp->solemat; + if (*mo != OVOID) + *mo += mp->mat0; return(1); } ti &= ~0x200; if (!(ti & 0x100)) { /* single link vertex */ struct PJoin1 *tp1; - if (ti >= mp->patch[pn].nj1tris) + if (ti >= pp->nj1tris) return(0); - tp1 = &mp->patch[pn].j1tri[ti]; + tp1 = &pp->j1tri[ti]; tvid[0] = tp1->v1j; tvid[1] = tvid[2] = pn << 8; tvid[1] |= tp1->v2; tvid[2] |= tp1->v3; + if ((*mo = tp1->mat) != OVOID) + *mo += mp->mat0; return(1); } ti &= ~0x100; { /* double link vertex */ struct PJoin2 *tp2; - if (ti >= mp->patch[pn].nj2tris) + if (ti >= pp->nj2tris) return(0); - tp2 = &mp->patch[pn].j2tri[ti]; + tp2 = &pp->j2tri[ti]; tvid[0] = tp2->v1j; tvid[1] = tp2->v2j; tvid[2] = pn << 8 | tp2->v3; + if ((*mo = tp2->mat) != OVOID) + *mo += mp->mat0; } return(1); } int -getmeshvert(vp, mp, vid, what) /* get triangle vertex from ID */ -MESHVERT *vp; -register MESH *mp; -int4 vid; -int what; +getmeshvert( /* get triangle vertex from ID */ + MESHVERT *vp, + MESH *mp, + int32 vid, + int what +) { int pn = vid >> 8; MESHPATCH *pp; double vres; - register int i; + int i; vp->fl = 0; if (pn >= mp->npatches) @@ -226,35 +279,60 @@ int what; } +OBJREC * +getmeshpseudo( /* get mesh pseudo object for material */ + MESH *mp, + OBJECT mo +) +{ + if ((mo < mp->mat0) | (mo >= mp->mat0 + mp->nmats)) + error(INTERNAL, "modifier out of range in getmeshpseudo"); + if (mp->pseudo == NULL) { + int i; + mp->pseudo = (OBJREC *)calloc(mp->nmats, sizeof(OBJREC)); + if (mp->pseudo == NULL) + error(SYSTEM, "out of memory in getmeshpseudo"); + for (i = mp->nmats; i--; ) { + mp->pseudo[i].omod = mp->mat0 + i; + mp->pseudo[i].otype = OBJ_FACE; + mp->pseudo[i].oname = "M-Tri"; + } + } + return(&mp->pseudo[mo - mp->mat0]); +} + + int -getmeshtri(tv, mp, ti, what) /* get triangle vertices */ -MESHVERT tv[3]; -MESH *mp; -OBJECT ti; -int what; +getmeshtri( /* get triangle vertices */ + MESHVERT tv[3], + OBJECT *mo, + MESH *mp, + OBJECT ti, + int wha +) { - int4 tvid[3]; + int32 tvid[3]; - if (!getmeshtrivid(tvid, mp, ti)) + if (!getmeshtrivid(tvid, mo, mp, ti)) return(0); - getmeshvert(&tv[0], mp, tvid[0], what); - getmeshvert(&tv[1], mp, tvid[1], what); - getmeshvert(&tv[2], mp, tvid[2], what); + getmeshvert(&tv[0], mp, tvid[0], wha); + getmeshvert(&tv[1], mp, tvid[1], wha); + getmeshvert(&tv[2], mp, tvid[2], wha); return(tv[0].fl & tv[1].fl & tv[2].fl); } -int4 -addmeshvert(mp, vp) /* find/add a mesh vertex */ -register MESH *mp; -MESHVERT *vp; +int32 +addmeshvert( /* find/add a mesh vertex */ + MESH *mp, + MESHVERT *vp +) { - LUTAB *ltp; - LUENT *lvp; - MCVERT cv; - register int i; + LUENT *lvp; + MCVERT cv; + int i; if (!(vp->fl & MT_V)) return(-1); @@ -264,11 +342,11 @@ MESHVERT *vp; return(-1); if (vp->v[i] >= mp->mcube.cuorg[i] + mp->mcube.cusize) return(-1); - cv.xyz[i] = (uint4)(4294967296. * + cv.xyz[i] = (uint32)(4294967296. * (vp->v[i] - mp->mcube.cuorg[i]) / mp->mcube.cusize); } - if (vp->fl & MT_N) + if (vp->fl & MT_N) /* assumes normalized! */ cv.norm = encodedir(vp->n); if (vp->fl & MT_UV) for (i = 0; i < 2; i++) { @@ -276,33 +354,28 @@ MESHVERT *vp; return(-1); if (vp->uv[i] >= mp->uvlim[1][i]) return(-1); - cv.uv[i] = (uint4)(4294967296. * + cv.uv[i] = (uint32)(4294967296. * (vp->uv[i] - mp->uvlim[0][i]) / (mp->uvlim[1][i] - mp->uvlim[0][i])); } cv.fl = vp->fl; - ltp = (LUTAB *)mp->cdata; /* get lookup table */ - if (ltp == NULL) { - ltp = (LUTAB *)calloc(1, sizeof(LUTAB)); - if (ltp == NULL) + if (mp->lut.tsiz == 0) { + mp->lut.hashf = cvhash; + mp->lut.keycmp = cvcmp; + mp->lut.freek = free; + if (!lu_init(&mp->lut, 50000)) goto nomem; - ltp->hashf = cvhash; - ltp->keycmp = cvcmp; - ltp->freek = free; - if (!lu_init(ltp, 50000)) - goto nomem; - mp->cdata = (char *)ltp; } /* find entry */ - lvp = lu_find(ltp, (char *)&cv); + lvp = lu_find(&mp->lut, (char *)&cv); if (lvp == NULL) goto nomem; if (lvp->key == NULL) { - lvp->key = (char *)malloc(sizeof(MCVERT)+sizeof(int4)); - bcopy((void *)&cv, (void *)lvp->key, sizeof(MCVERT)); + lvp->key = (char *)malloc(sizeof(MCVERT)+sizeof(int32)); + memcpy(lvp->key, &cv, sizeof(MCVERT)); } if (lvp->data == NULL) { /* new vertex */ - register MESHPATCH *pp; + MESHPATCH *pp; if (mp->npatches <= 0) { mp->patch = (MESHPATCH *)calloc(MPATCHBLKSIZ, sizeof(MESHPATCH)); @@ -310,20 +383,20 @@ MESHVERT *vp; goto nomem; mp->npatches = 1; } else if (mp->patch[mp->npatches-1].nverts >= 256) { + if (mp->npatches >= 1L<<22) + error(INTERNAL, "too many mesh patches"); if (mp->npatches % MPATCHBLKSIZ == 0) { - mp->patch = (MESHPATCH *)realloc( - (void *)mp->patch, - (mp->npatches + MPATCHBLKSIZ)* - sizeof(MESHPATCH)); - bzero((void *)(mp->patch + mp->npatches), + mp->patch = (MESHPATCH *)realloc(mp->patch, + (mp->npatches + MPATCHBLKSIZ)* + sizeof(MESHPATCH)); + memset((mp->patch + mp->npatches), '\0', MPATCHBLKSIZ*sizeof(MESHPATCH)); } - if (mp->npatches++ >= 1L<<22) - error(INTERNAL, "too many mesh patches"); + mp->npatches++; } pp = &mp->patch[mp->npatches-1]; if (pp->xyz == NULL) { - pp->xyz = (uint4 (*)[3])calloc(256, 3*sizeof(int4)); + pp->xyz = (uint32 (*)[3])calloc(256, 3*sizeof(int32)); if (pp->xyz == NULL) goto nomem; } @@ -331,7 +404,7 @@ MESHVERT *vp; pp->xyz[pp->nverts][i] = cv.xyz[i]; if (cv.fl & MT_N) { if (pp->norm == NULL) { - pp->norm = (int4 *)calloc(256, sizeof(int4)); + pp->norm = (int32 *)calloc(256, sizeof(int32)); if (pp->norm == NULL) goto nomem; } @@ -339,8 +412,8 @@ MESHVERT *vp; } if (cv.fl & MT_UV) { if (pp->uv == NULL) { - pp->uv = (uint4 (*)[2])calloc(256, - 2*sizeof(uint4)); + pp->uv = (uint32 (*)[2])calloc(256, + 2*sizeof(uint32)); if (pp->uv == NULL) goto nomem; } @@ -349,9 +422,9 @@ MESHVERT *vp; } pp->nverts++; lvp->data = lvp->key + sizeof(MCVERT); - *(int4 *)lvp->data = (mp->npatches-1) << 8 | (pp->nverts-1); + *(int32 *)lvp->data = (mp->npatches-1) << 8 | (pp->nverts-1); } - return(*(int4 *)lvp->data); + return(*(int32 *)lvp->data); nomem: error(SYSTEM, "out of memory in addmeshvert"); return(-1); @@ -359,13 +432,15 @@ nomem: OBJECT -addmeshtri(mp, tv) /* add a new mesh triangle */ -MESH *mp; -MESHVERT tv[3]; +addmeshtri( /* add a new mesh triangle */ + MESH *mp, + MESHVERT tv[3], + OBJECT mo +) { - int4 vid[3], t; - int pn[3], i; - register MESHPATCH *pp; + int32 vid[3], t; + int pn[3], i; + MESHPATCH *pp; if (!(tv[0].fl & tv[1].fl & tv[2].fl & MT_V)) return(OVOID); @@ -375,8 +450,15 @@ MESHVERT tv[3]; return(OVOID); pn[i] = vid[i] >> 8; } + /* normalize material index */ + if (mo != OVOID) { + if ((mo -= mp->mat0) >= mp->nmats) + mp->nmats = mo+1; + else if (mo < 0) + error(INTERNAL, "modifier range error in addmeshtri"); + } /* assign triangle */ - if (pn[0] == pn[1] && pn[1] == pn[2]) { /* local case */ + if ((pn[0] == pn[1]) & (pn[1] == pn[2])) { /* local case */ pp = &mp->patch[pn[0]]; if (pp->tri == NULL) { pp->tri = (struct PTri *)malloc( @@ -388,10 +470,21 @@ MESHVERT tv[3]; pp->tri[pp->ntris].v1 = vid[0] & 0xff; pp->tri[pp->ntris].v2 = vid[1] & 0xff; pp->tri[pp->ntris].v3 = vid[2] & 0xff; + if (pp->ntris == 0) + pp->solemat = mo; + else if (pp->trimat == NULL && mo != pp->solemat) { + pp->trimat = (int16 *)malloc( + 512*sizeof(int16)); + if (pp->trimat == NULL) + goto nomem; + for (i = pp->ntris; i--; ) + pp->trimat[i] = pp->solemat; + } + if (pp->trimat != NULL) + pp->trimat[pp->ntris] = mo; return(pn[0] << 10 | pp->ntris++); } - } - if (pn[0] == pn[1]) { + } else if (pn[0] == pn[1]) { t = vid[2]; vid[2] = vid[1]; vid[1] = vid[0]; vid[0] = t; i = pn[2]; pn[2] = pn[1]; pn[1] = pn[0]; pn[0] = i; } else if (pn[0] == pn[2]) { @@ -410,33 +503,123 @@ MESHVERT tv[3]; pp->j1tri[pp->nj1tris].v1j = vid[0]; pp->j1tri[pp->nj1tris].v2 = vid[1] & 0xff; pp->j1tri[pp->nj1tris].v3 = vid[2] & 0xff; + pp->j1tri[pp->nj1tris].mat = mo; return(pn[1] << 10 | 0x200 | pp->nj1tris++); } } /* double link */ - pp = &mp->patch[pn[2]]; + pp = &mp->patch[pn[i=0]]; + if (mp->patch[pn[1]].nj2tris < pp->nj2tris) + pp = &mp->patch[pn[i=1]]; + if (mp->patch[pn[2]].nj2tris < pp->nj2tris) + pp = &mp->patch[pn[i=2]]; + if (pp->nj2tris >= 256) + error(INTERNAL, "too many patch triangles in addmeshtri"); if (pp->j2tri == NULL) { pp->j2tri = (struct PJoin2 *)malloc( 256*sizeof(struct PJoin2)); if (pp->j2tri == NULL) goto nomem; } - if (pp->nj2tris >= 256) - error(INTERNAL, "too many patch triangles in addmeshtri"); - pp->j2tri[pp->nj2tris].v1j = vid[0]; - pp->j2tri[pp->nj2tris].v2j = vid[1]; - pp->j2tri[pp->nj2tris].v3 = vid[2] & 0xff; - return(pn[2] << 10 | 0x300 | pp->nj2tris++); + pp->j2tri[pp->nj2tris].mat = mo; + switch (i) { + case 0: + pp->j2tri[pp->nj2tris].v3 = vid[0] & 0xff; + pp->j2tri[pp->nj2tris].v1j = vid[1]; + pp->j2tri[pp->nj2tris].v2j = vid[2]; + return(pn[0] << 10 | 0x300 | pp->nj2tris++); + case 1: + pp->j2tri[pp->nj2tris].v2j = vid[0]; + pp->j2tri[pp->nj2tris].v3 = vid[1] & 0xff; + pp->j2tri[pp->nj2tris].v1j = vid[2]; + return(pn[1] << 10 | 0x300 | pp->nj2tris++); + case 2: + pp->j2tri[pp->nj2tris].v1j = vid[0]; + pp->j2tri[pp->nj2tris].v2j = vid[1]; + pp->j2tri[pp->nj2tris].v3 = vid[2] & 0xff; + return(pn[2] << 10 | 0x300 | pp->nj2tris++); + } nomem: error(SYSTEM, "out of memory in addmeshtri"); return(OVOID); } +char * +checkmesh(MESH *mp) /* validate mesh data */ +{ + static char embuf[128]; + int nouvbounds = 1; + int i; + /* basic checks */ + if (mp == NULL) + return("NULL mesh pointer"); + if (!mp->ldflags) + return("unassigned mesh"); + if (mp->name == NULL) + return("missing mesh name"); + if (mp->nref <= 0) + return("unreferenced mesh"); + /* check boundaries */ + if (mp->ldflags & IO_BOUNDS) { + if (mp->mcube.cusize <= FTINY) + return("illegal octree bounds in mesh"); + nouvbounds = (mp->uvlim[1][0] - mp->uvlim[0][0] <= FTINY || + mp->uvlim[1][1] - mp->uvlim[0][1] <= FTINY); + } + /* check octree */ + if (mp->ldflags & IO_TREE) { + if (isempty(mp->mcube.cutree)) + error(WARNING, "empty mesh octree"); + } + /* check scene data */ + if (mp->ldflags & IO_SCENE) { + if (!(mp->ldflags & IO_BOUNDS)) + return("unbounded scene in mesh"); + if (mp->mat0 < 0 || mp->mat0+mp->nmats > nobjects) + return("bad mesh modifier range"); + if (mp->nmats > 0) /* allocate during preload_objs()! */ + getmeshpseudo(mp, mp->mat0); + for (i = mp->mat0+mp->nmats; i-- > mp->mat0; ) { + int otyp = objptr(i)->otype; + if (!ismodifier(otyp)) { + sprintf(embuf, + "non-modifier in mesh (%s \"%s\")", + ofun[otyp].funame, objptr(i)->oname); + return(embuf); + } + } + if (mp->npatches <= 0) + error(WARNING, "no patches in mesh"); + for (i = 0; i < mp->npatches; i++) { + MESHPATCH *pp = &mp->patch[i]; + if (pp->nverts <= 0) + error(WARNING, "no vertices in patch"); + else { + if (pp->xyz == NULL) + return("missing patch vertex list"); + if (nouvbounds && pp->uv != NULL) + return("unreferenced uv coordinates"); + } + if (pp->ntris > 0 && pp->tri == NULL) + return("missing patch triangle list"); + if (pp->nj1tris > 0 && pp->j1tri == NULL) + return("missing patch joiner triangle list"); + if (pp->nj2tris > 0 && pp->j2tri == NULL) + return("missing patch double-joiner list"); + } + } + return(NULL); /* seems OK */ +} + + static void -tallyoctree(ot, ecp, lcp, ocp) /* tally octree size */ -OCTREE ot; -int *ecp, *lcp, *ocp; +tallyoctree( /* tally octree size */ + OCTREE ot, + int *ecp, + int *lcp, + int *ocp +) { int i; @@ -457,9 +640,10 @@ int *ecp, *lcp, *ocp; void -printmeshstats(ms, fp) /* print out mesh statistics */ -MESH *ms; -FILE *fp; +printmeshstats( /* print out mesh statistics */ + MESH *ms, + FILE *fp +) { int lfcnt=0, lecnt=0, locnt=0; int vcnt=0, ncnt=0, uvcnt=0; @@ -469,7 +653,7 @@ FILE *fp; tallyoctree(ms->mcube.cutree, &lecnt, &lfcnt, &locnt); for (i = 0; i < ms->npatches; i++) { - register MESHPATCH *pp = &ms->patch[i]; + MESHPATCH *pp = &ms->patch[i]; vcnt += pp->nverts; if (pp->norm != NULL) { for (j = pp->nverts; j--; ) @@ -488,11 +672,12 @@ FILE *fp; t2cnt += pp->nj2tris; } fprintf(fp, "Mesh statistics:\n"); + fprintf(fp, "\t%ld materials\n", (long)ms->nmats); fprintf(fp, "\t%d patches (%.2f MBytes)\n", ms->npatches, (ms->npatches*sizeof(MESHPATCH) + - vcnt*3*sizeof(uint4) + - nscnt*sizeof(int4) + - uvscnt*2*sizeof(uint4) + + vcnt*3*sizeof(uint32) + + nscnt*sizeof(int32) + + uvscnt*2*sizeof(uint32) + tcnt*sizeof(struct PTri) + t1cnt*sizeof(struct PJoin1) + t2cnt*sizeof(struct PJoin2))/(1024.*1024.)); @@ -510,8 +695,7 @@ FILE *fp; void -freemesh(ms) /* free mesh data */ -MESH *ms; +freemesh(MESH *ms) /* free mesh data */ { MESH mhead; MESH *msp; @@ -537,37 +721,39 @@ MESH *ms; /* free mesh data */ freestr(ms->name); octfree(ms->mcube.cutree); - if (ms->cdata != NULL) - lu_done((LUTAB *)ms->cdata); + lu_done(&ms->lut); if (ms->npatches > 0) { - register MESHPATCH *pp = ms->patch + ms->npatches; + MESHPATCH *pp = ms->patch + ms->npatches; while (pp-- > ms->patch) { if (pp->j2tri != NULL) - free((void *)pp->j2tri); + free(pp->j2tri); if (pp->j1tri != NULL) - free((void *)pp->j1tri); + free(pp->j1tri); if (pp->tri != NULL) - free((void *)pp->tri); + free(pp->tri); if (pp->uv != NULL) - free((void *)pp->uv); + free(pp->uv); if (pp->norm != NULL) - free((void *)pp->norm); + free(pp->norm); if (pp->xyz != NULL) - free((void *)pp->xyz); + free(pp->xyz); + if (pp->trimat != NULL) + free(pp->trimat); } - free((void *)ms->patch); + free(ms->patch); } - free((void *)ms); + if (ms->pseudo != NULL) + free(ms->pseudo); + free(ms); } void -freemeshinst(o) /* free mesh instance */ -OBJREC *o; +freemeshinst(OBJREC *o) /* free mesh instance */ { if (o->os == NULL) return; freemesh((*(MESHINST *)o->os).msh); - free((void *)o->os); + free(o->os); o->os = NULL; }