| 5 | 
  | 
 * Mesh support routines | 
| 6 | 
  | 
 */ | 
| 7 | 
  | 
 | 
| 8 | 
– | 
#include <string.h> | 
| 9 | 
– | 
 | 
| 8 | 
  | 
#include "rtio.h" | 
| 9 | 
  | 
#include "rtmath.h" | 
| 10 | 
  | 
#include "rterror.h" | 
| 50 | 
  | 
cvcmp(const char *vv1, const char *vv2)         /* compare encoded vertices */ | 
| 51 | 
  | 
{ | 
| 52 | 
  | 
        const MCVERT    *v1 = (const MCVERT *)vv1, *v2 = (const MCVERT *)vv2; | 
| 53 | 
+ | 
 | 
| 54 | 
  | 
        if (v1->fl != v2->fl) | 
| 55 | 
  | 
                return(1); | 
| 56 | 
  | 
        if (v1->xyz[0] != v2->xyz[0]) | 
| 72 | 
  | 
 | 
| 73 | 
  | 
 | 
| 74 | 
  | 
MESH * | 
| 75 | 
< | 
getmesh(                                /* get new mesh data reference */ | 
| 75 | 
> | 
getmesh(                                /* get mesh data reference */ | 
| 76 | 
  | 
        char    *mname, | 
| 77 | 
  | 
        int     flags | 
| 78 | 
  | 
) | 
| 82 | 
  | 
 | 
| 83 | 
  | 
        flags &= IO_LEGAL; | 
| 84 | 
  | 
        for (ms = mlist; ms != NULL; ms = ms->next) | 
| 85 | 
< | 
                if (!strcmp(mname, ms->name)) { | 
| 87 | 
< | 
                        ms->nref++;     /* increase reference count */ | 
| 85 | 
> | 
                if (!strcmp(mname, ms->name)) | 
| 86 | 
  | 
                        break; | 
| 87 | 
< | 
                } | 
| 90 | 
< | 
        if (ms == NULL) {               /* load first time */ | 
| 87 | 
> | 
        if (ms == NULL) {               /* new mesh entry? */ | 
| 88 | 
  | 
                ms = (MESH *)calloc(1, sizeof(MESH)); | 
| 89 | 
  | 
                if (ms == NULL) | 
| 90 | 
  | 
                        error(SYSTEM, "out of memory in getmesh"); | 
| 91 | 
  | 
                ms->name = savestr(mname); | 
| 95 | 
– | 
                ms->nref = 1; | 
| 92 | 
  | 
                ms->mcube.cutree = EMPTY; | 
| 93 | 
  | 
                ms->next = mlist; | 
| 94 | 
  | 
                mlist = ms; | 
| 95 | 
  | 
        } | 
| 96 | 
+ | 
        ms->nref++;                     /* bump reference count */ | 
| 97 | 
+ | 
        if (!(flags &= ~ms->ldflags))   /* nothing to load? */ | 
| 98 | 
+ | 
                return(ms); | 
| 99 | 
  | 
        if ((pathname = getpath(mname, getrlibpath(), R_OK)) == NULL) { | 
| 100 | 
  | 
                sprintf(errmsg, "cannot find mesh file \"%s\"", mname); | 
| 101 | 
< | 
                error(USER, errmsg); | 
| 101 | 
> | 
                error(SYSTEM, errmsg); | 
| 102 | 
  | 
        } | 
| 103 | 
< | 
        flags &= ~ms->ldflags; | 
| 105 | 
< | 
        if (flags) | 
| 106 | 
< | 
                readmesh(ms, pathname, flags); | 
| 103 | 
> | 
        readmesh(ms, pathname, flags); | 
| 104 | 
  | 
        return(ms); | 
| 105 | 
  | 
} | 
| 106 | 
  | 
 | 
| 145 | 
  | 
        MESH *mp | 
| 146 | 
  | 
) | 
| 147 | 
  | 
{ | 
| 151 | 
– | 
        int             advance = 1; | 
| 148 | 
  | 
        int             pn; | 
| 149 | 
  | 
        MESHPATCH       *pp; | 
| 150 | 
  | 
 | 
| 151 | 
< | 
        if (*tip == OVOID) {                    /* check for first index */ | 
| 156 | 
< | 
                *tip = 0; | 
| 157 | 
< | 
                advance = 0; | 
| 158 | 
< | 
        } | 
| 159 | 
< | 
        pn = *tip >> 10; | 
| 151 | 
> | 
        pn = ++(*tip) >> 10;                    /* next triangle (OVOID init) */ | 
| 152 | 
  | 
        while (pn < mp->npatches) { | 
| 153 | 
  | 
                pp = &mp->patch[pn]; | 
| 154 | 
  | 
                if (!(*tip & 0x200)) {          /* local triangle? */ | 
| 155 | 
< | 
                        if ((*tip & 0x1ff) < pp->ntris - advance) { | 
| 164 | 
< | 
                                *tip += advance; | 
| 155 | 
> | 
                        if ((*tip & 0x1ff) < pp->ntris) | 
| 156 | 
  | 
                                return(1); | 
| 166 | 
– | 
                        } | 
| 157 | 
  | 
                        *tip &= ~0x1ff;         /* move on to single-joiners */ | 
| 158 | 
  | 
                        *tip |= 0x200; | 
| 169 | 
– | 
                        advance = 0; | 
| 159 | 
  | 
                } | 
| 160 | 
  | 
                if (!(*tip & 0x100)) {          /* single joiner? */ | 
| 161 | 
< | 
                        if ((*tip & 0xff) < pp->nj1tris - advance) { | 
| 173 | 
< | 
                                *tip += advance; | 
| 161 | 
> | 
                        if ((*tip & 0xff) < pp->nj1tris) | 
| 162 | 
  | 
                                return(1); | 
| 175 | 
– | 
                        } | 
| 163 | 
  | 
                        *tip &= ~0xff;          /* move on to double-joiners */ | 
| 164 | 
  | 
                        *tip |= 0x100; | 
| 178 | 
– | 
                        advance = 0; | 
| 165 | 
  | 
                } | 
| 166 | 
< | 
                if ((*tip & 0xff) < pp->nj2tris - advance) { | 
| 181 | 
< | 
                        *tip += advance; | 
| 166 | 
> | 
                if ((*tip & 0xff) < pp->nj2tris) | 
| 167 | 
  | 
                        return(1); | 
| 183 | 
– | 
                } | 
| 168 | 
  | 
                *tip = ++pn << 10;              /* first in next patch */ | 
| 185 | 
– | 
                advance = 0; | 
| 169 | 
  | 
        } | 
| 170 | 
  | 
        return(0);                              /* out of patches */ | 
| 171 | 
  | 
} | 
| 283 | 
  | 
        OBJECT  mo | 
| 284 | 
  | 
) | 
| 285 | 
  | 
{ | 
| 286 | 
< | 
        if (mo < mp->mat0 || mo >= mp->mat0 + mp->nmats) | 
| 286 | 
> | 
        if ((mo < mp->mat0) | (mo >= mp->mat0 + mp->nmats)) | 
| 287 | 
  | 
                error(INTERNAL, "modifier out of range in getmeshpseudo"); | 
| 288 | 
  | 
        if (mp->pseudo == NULL) { | 
| 289 | 
  | 
                int     i; | 
| 324 | 
  | 
 | 
| 325 | 
  | 
int32 | 
| 326 | 
  | 
addmeshvert(                    /* find/add a mesh vertex */ | 
| 327 | 
< | 
        MESH    *mp, | 
| 327 | 
> | 
        MESH            *mp, | 
| 328 | 
  | 
        MESHVERT        *vp | 
| 329 | 
  | 
) | 
| 330 | 
  | 
{ | 
| 331 | 
< | 
        LUENT           *lvp; | 
| 332 | 
< | 
        MCVERT          cv; | 
| 331 | 
> | 
        LUENT   *lvp; | 
| 332 | 
> | 
        MCVERT  cv; | 
| 333 | 
  | 
        int     i; | 
| 334 | 
  | 
 | 
| 335 | 
  | 
        if (!(vp->fl & MT_V)) | 
| 370 | 
  | 
                goto nomem; | 
| 371 | 
  | 
        if (lvp->key == NULL) { | 
| 372 | 
  | 
                lvp->key = (char *)malloc(sizeof(MCVERT)+sizeof(int32)); | 
| 373 | 
< | 
                memcpy((void *)lvp->key, (void *)&cv, sizeof(MCVERT)); | 
| 373 | 
> | 
                memcpy(lvp->key, &cv, sizeof(MCVERT)); | 
| 374 | 
  | 
        } | 
| 375 | 
  | 
        if (lvp->data == NULL) {        /* new vertex */ | 
| 376 | 
  | 
                MESHPATCH       *pp; | 
| 381 | 
  | 
                                goto nomem; | 
| 382 | 
  | 
                        mp->npatches = 1; | 
| 383 | 
  | 
                } else if (mp->patch[mp->npatches-1].nverts >= 256) { | 
| 384 | 
+ | 
                        if (mp->npatches >= 1L<<22) | 
| 385 | 
+ | 
                                error(INTERNAL, "too many mesh patches"); | 
| 386 | 
  | 
                        if (mp->npatches % MPATCHBLKSIZ == 0) { | 
| 387 | 
< | 
                                mp->patch = (MESHPATCH *)realloc( | 
| 388 | 
< | 
                                                (void *)mp->patch, | 
| 389 | 
< | 
                                        (mp->npatches + MPATCHBLKSIZ)* | 
| 390 | 
< | 
                                                sizeof(MESHPATCH)); | 
| 406 | 
< | 
                                memset((void *)(mp->patch + mp->npatches), '\0', | 
| 387 | 
> | 
                                mp->patch = (MESHPATCH *)realloc(mp->patch, | 
| 388 | 
> | 
                                                (mp->npatches + MPATCHBLKSIZ)* | 
| 389 | 
> | 
                                                        sizeof(MESHPATCH)); | 
| 390 | 
> | 
                                memset((mp->patch + mp->npatches), '\0', | 
| 391 | 
  | 
                                        MPATCHBLKSIZ*sizeof(MESHPATCH)); | 
| 392 | 
  | 
                        } | 
| 393 | 
< | 
                        if (mp->npatches++ >= 1L<<22) | 
| 410 | 
< | 
                                error(INTERNAL, "too many mesh patches"); | 
| 393 | 
> | 
                        mp->npatches++; | 
| 394 | 
  | 
                } | 
| 395 | 
  | 
                pp = &mp->patch[mp->npatches-1]; | 
| 396 | 
  | 
                if (pp->xyz == NULL) { | 
| 436 | 
  | 
        OBJECT          mo | 
| 437 | 
  | 
) | 
| 438 | 
  | 
{ | 
| 439 | 
< | 
        int32                   vid[3], t; | 
| 440 | 
< | 
        int                     pn[3], i; | 
| 439 | 
> | 
        int32           vid[3], t; | 
| 440 | 
> | 
        int             pn[3], i; | 
| 441 | 
  | 
        MESHPATCH       *pp; | 
| 442 | 
  | 
 | 
| 443 | 
  | 
        if (!(tv[0].fl & tv[1].fl & tv[2].fl & MT_V)) | 
| 456 | 
  | 
                        error(INTERNAL, "modifier range error in addmeshtri"); | 
| 457 | 
  | 
        } | 
| 458 | 
  | 
                                /* assign triangle */ | 
| 459 | 
< | 
        if (pn[0] == pn[1] && pn[1] == pn[2]) { /* local case */ | 
| 459 | 
> | 
        if ((pn[0] == pn[1]) & (pn[1] == pn[2])) {      /* local case */ | 
| 460 | 
  | 
                pp = &mp->patch[pn[0]]; | 
| 461 | 
  | 
                if (pp->tri == NULL) { | 
| 462 | 
  | 
                        pp->tri = (struct PTri *)malloc( | 
| 482 | 
  | 
                                pp->trimat[pp->ntris] = mo; | 
| 483 | 
  | 
                        return(pn[0] << 10 | pp->ntris++); | 
| 484 | 
  | 
                } | 
| 485 | 
< | 
        } | 
| 503 | 
< | 
        if (pn[0] == pn[1]) { | 
| 485 | 
> | 
        } else if (pn[0] == pn[1]) { | 
| 486 | 
  | 
                t = vid[2]; vid[2] = vid[1]; vid[1] = vid[0]; vid[0] = t; | 
| 487 | 
  | 
                i = pn[2]; pn[2] = pn[1]; pn[1] = pn[0]; pn[0] = i; | 
| 488 | 
  | 
        } else if (pn[0] == pn[2]) { | 
| 506 | 
  | 
                } | 
| 507 | 
  | 
        } | 
| 508 | 
  | 
                                                /* double link */ | 
| 509 | 
< | 
        pp = &mp->patch[pn[2]]; | 
| 509 | 
> | 
        pp = &mp->patch[pn[i=0]]; | 
| 510 | 
> | 
        if (mp->patch[pn[1]].nj2tris < pp->nj2tris) | 
| 511 | 
> | 
                pp = &mp->patch[pn[i=1]]; | 
| 512 | 
> | 
        if (mp->patch[pn[2]].nj2tris < pp->nj2tris) | 
| 513 | 
> | 
                pp = &mp->patch[pn[i=2]]; | 
| 514 | 
> | 
        if (pp->nj2tris >= 256) | 
| 515 | 
> | 
                error(INTERNAL, "too many patch triangles in addmeshtri"); | 
| 516 | 
  | 
        if (pp->j2tri == NULL) { | 
| 517 | 
  | 
                pp->j2tri = (struct PJoin2 *)malloc( | 
| 518 | 
  | 
                                        256*sizeof(struct PJoin2)); | 
| 519 | 
  | 
                if (pp->j2tri == NULL) | 
| 520 | 
  | 
                        goto nomem; | 
| 521 | 
  | 
        } | 
| 534 | 
– | 
        if (pp->nj2tris >= 256) | 
| 535 | 
– | 
                error(INTERNAL, "too many patch triangles in addmeshtri"); | 
| 536 | 
– | 
        pp->j2tri[pp->nj2tris].v1j = vid[0]; | 
| 537 | 
– | 
        pp->j2tri[pp->nj2tris].v2j = vid[1]; | 
| 538 | 
– | 
        pp->j2tri[pp->nj2tris].v3 = vid[2] & 0xff; | 
| 522 | 
  | 
        pp->j2tri[pp->nj2tris].mat = mo; | 
| 523 | 
< | 
        return(pn[2] << 10 | 0x300 | pp->nj2tris++); | 
| 523 | 
> | 
        switch (i) { | 
| 524 | 
> | 
        case 0: | 
| 525 | 
> | 
                pp->j2tri[pp->nj2tris].v3 = vid[0] & 0xff; | 
| 526 | 
> | 
                pp->j2tri[pp->nj2tris].v1j = vid[1]; | 
| 527 | 
> | 
                pp->j2tri[pp->nj2tris].v2j = vid[2]; | 
| 528 | 
> | 
                return(pn[0] << 10 | 0x300 | pp->nj2tris++); | 
| 529 | 
> | 
        case 1: | 
| 530 | 
> | 
                pp->j2tri[pp->nj2tris].v2j = vid[0]; | 
| 531 | 
> | 
                pp->j2tri[pp->nj2tris].v3 = vid[1] & 0xff; | 
| 532 | 
> | 
                pp->j2tri[pp->nj2tris].v1j = vid[2]; | 
| 533 | 
> | 
                return(pn[1] << 10 | 0x300 | pp->nj2tris++); | 
| 534 | 
> | 
        case 2: | 
| 535 | 
> | 
                pp->j2tri[pp->nj2tris].v1j = vid[0]; | 
| 536 | 
> | 
                pp->j2tri[pp->nj2tris].v2j = vid[1]; | 
| 537 | 
> | 
                pp->j2tri[pp->nj2tris].v3 = vid[2] & 0xff; | 
| 538 | 
> | 
                return(pn[2] << 10 | 0x300 | pp->nj2tris++); | 
| 539 | 
> | 
        } | 
| 540 | 
  | 
nomem: | 
| 541 | 
  | 
        error(SYSTEM, "out of memory in addmeshtri"); | 
| 542 | 
  | 
        return(OVOID); | 
| 548 | 
  | 
{ | 
| 549 | 
  | 
        static char     embuf[128]; | 
| 550 | 
  | 
        int             nouvbounds = 1; | 
| 551 | 
< | 
        int     i; | 
| 551 | 
> | 
        int             i, j; | 
| 552 | 
  | 
                                        /* basic checks */ | 
| 553 | 
  | 
        if (mp == NULL) | 
| 554 | 
  | 
                return("NULL mesh pointer"); | 
| 570 | 
  | 
                if (isempty(mp->mcube.cutree)) | 
| 571 | 
  | 
                        error(WARNING, "empty mesh octree"); | 
| 572 | 
  | 
        } | 
| 573 | 
< | 
                                        /* check scene data */ | 
| 573 | 
> | 
                                        /* check patch data */ | 
| 574 | 
  | 
        if (mp->ldflags & IO_SCENE) { | 
| 575 | 
+ | 
                MESHVERT        mv; | 
| 576 | 
  | 
                if (!(mp->ldflags & IO_BOUNDS)) | 
| 577 | 
  | 
                        return("unbounded scene in mesh"); | 
| 578 | 
  | 
                if (mp->mat0 < 0 || mp->mat0+mp->nmats > nobjects) | 
| 579 | 
  | 
                        return("bad mesh modifier range"); | 
| 580 | 
+ | 
                if (mp->nmats > 0)      /* allocate during preload_objs()! */ | 
| 581 | 
+ | 
                        getmeshpseudo(mp, mp->mat0); | 
| 582 | 
  | 
                for (i = mp->mat0+mp->nmats; i-- > mp->mat0; ) { | 
| 583 | 
  | 
                        int     otyp = objptr(i)->otype; | 
| 584 | 
  | 
                        if (!ismodifier(otyp)) { | 
| 600 | 
  | 
                                if (nouvbounds && pp->uv != NULL) | 
| 601 | 
  | 
                                        return("unreferenced uv coordinates"); | 
| 602 | 
  | 
                        } | 
| 603 | 
< | 
                        if (pp->ntris > 0 && pp->tri == NULL) | 
| 604 | 
< | 
                                return("missing patch triangle list"); | 
| 605 | 
< | 
                        if (pp->nj1tris > 0 && pp->j1tri == NULL) | 
| 606 | 
< | 
                                return("missing patch joiner triangle list"); | 
| 607 | 
< | 
                        if (pp->nj2tris > 0 && pp->j2tri == NULL) | 
| 608 | 
< | 
                                return("missing patch double-joiner list"); | 
| 603 | 
> | 
                        if (pp->ntris > 0) { | 
| 604 | 
> | 
                                struct PTri     *tp = pp->tri; | 
| 605 | 
> | 
                                if (tp == NULL) | 
| 606 | 
> | 
                                        return("missing patch triangle list"); | 
| 607 | 
> | 
                                if (mp->nmats <= 0) | 
| 608 | 
> | 
                                        j = -1; | 
| 609 | 
> | 
                                else if (pp->trimat == NULL) | 
| 610 | 
> | 
                                        j = ((pp->solemat < 0) | (pp->solemat >= mp->nmats)) - 1; | 
| 611 | 
> | 
                                else | 
| 612 | 
> | 
                                        for (j = pp->ntris; j--; ) | 
| 613 | 
> | 
                                                if ((pp->trimat[j] < 0) | | 
| 614 | 
> | 
                                                                (pp->trimat[j] >= mp->nmats)) | 
| 615 | 
> | 
                                                        break; | 
| 616 | 
> | 
                                if (j >= 0) | 
| 617 | 
> | 
                                        return("bad local triangle material"); | 
| 618 | 
> | 
                                for (j = pp->ntris; j--; tp++) | 
| 619 | 
> | 
                                        if ((tp->v1 >= pp->nverts) | (tp->v2 >= pp->nverts) | | 
| 620 | 
> | 
                                                        (tp->v3 >= pp->nverts)) | 
| 621 | 
> | 
                                                return("bad local triangle index"); | 
| 622 | 
> | 
                        } | 
| 623 | 
> | 
                        if (pp->nj1tris > 0) { | 
| 624 | 
> | 
                                struct PJoin1   *j1p = pp->j1tri; | 
| 625 | 
> | 
                                if (j1p == NULL) | 
| 626 | 
> | 
                                        return("missing patch joiner triangle list"); | 
| 627 | 
> | 
                                for (j = pp->nj1tris; j--; j1p++) { | 
| 628 | 
> | 
                                        if (mp->nmats > 0 && | 
| 629 | 
> | 
                                                        (j1p->mat < 0) | (j1p->mat >= mp->nmats)) | 
| 630 | 
> | 
                                                return("bad j1 triangle material"); | 
| 631 | 
> | 
                                        if (!getmeshvert(&mv, mp, j1p->v1j, MT_V)) | 
| 632 | 
> | 
                                                return("bad j1 triangle joiner"); | 
| 633 | 
> | 
                                        if ((j1p->v2 >= pp->nverts) | (j1p->v3 >= pp->nverts)) | 
| 634 | 
> | 
                                                return("bad j1 triangle local index"); | 
| 635 | 
> | 
                                } | 
| 636 | 
> | 
                        } | 
| 637 | 
> | 
                        if (pp->nj2tris > 0) { | 
| 638 | 
> | 
                                struct PJoin2   *j2p = pp->j2tri; | 
| 639 | 
> | 
                                if (j2p == NULL) | 
| 640 | 
> | 
                                        return("missing patch double-joiner list"); | 
| 641 | 
> | 
                                for (j = pp->nj2tris; j--; j2p++) { | 
| 642 | 
> | 
                                        if (mp->nmats > 0 && | 
| 643 | 
> | 
                                                        (j2p->mat < 0) | (j2p->mat >= mp->nmats)) | 
| 644 | 
> | 
                                                return("bad j2 triangle material"); | 
| 645 | 
> | 
                                        if (!getmeshvert(&mv, mp, j2p->v1j, MT_V) | | 
| 646 | 
> | 
                                                        !getmeshvert(&mv, mp, j2p->v2j, MT_V)) | 
| 647 | 
> | 
                                                return("bad j2 triangle joiner"); | 
| 648 | 
> | 
                                        if (j2p->v3 >= pp->nverts) | 
| 649 | 
> | 
                                                return("bad j2 triangle local index"); | 
| 650 | 
> | 
                                } | 
| 651 | 
> | 
                        } | 
| 652 | 
  | 
                } | 
| 653 | 
  | 
        } | 
| 654 | 
< | 
        return(NULL);                   /* seems OK */ | 
| 654 | 
> | 
        return(NULL);                   /* seems to be self-consistent */ | 
| 655 | 
  | 
} | 
| 656 | 
  | 
 | 
| 657 | 
  | 
 | 
| 768 | 
  | 
                MESHPATCH       *pp = ms->patch + ms->npatches; | 
| 769 | 
  | 
                while (pp-- > ms->patch) { | 
| 770 | 
  | 
                        if (pp->j2tri != NULL) | 
| 771 | 
< | 
                                free((void *)pp->j2tri); | 
| 771 | 
> | 
                                free(pp->j2tri); | 
| 772 | 
  | 
                        if (pp->j1tri != NULL) | 
| 773 | 
< | 
                                free((void *)pp->j1tri); | 
| 773 | 
> | 
                                free(pp->j1tri); | 
| 774 | 
  | 
                        if (pp->tri != NULL) | 
| 775 | 
< | 
                                free((void *)pp->tri); | 
| 775 | 
> | 
                                free(pp->tri); | 
| 776 | 
  | 
                        if (pp->uv != NULL) | 
| 777 | 
< | 
                                free((void *)pp->uv); | 
| 777 | 
> | 
                                free(pp->uv); | 
| 778 | 
  | 
                        if (pp->norm != NULL) | 
| 779 | 
< | 
                                free((void *)pp->norm); | 
| 779 | 
> | 
                                free(pp->norm); | 
| 780 | 
  | 
                        if (pp->xyz != NULL) | 
| 781 | 
< | 
                                free((void *)pp->xyz); | 
| 781 | 
> | 
                                free(pp->xyz); | 
| 782 | 
> | 
                        if (pp->trimat != NULL) | 
| 783 | 
> | 
                                free(pp->trimat); | 
| 784 | 
  | 
                } | 
| 785 | 
< | 
                free((void *)ms->patch); | 
| 785 | 
> | 
                free(ms->patch); | 
| 786 | 
  | 
        } | 
| 787 | 
  | 
        if (ms->pseudo != NULL) | 
| 788 | 
< | 
                free((void *)ms->pseudo); | 
| 789 | 
< | 
        free((void *)ms); | 
| 788 | 
> | 
                free(ms->pseudo); | 
| 789 | 
> | 
        free(ms); | 
| 790 | 
  | 
} | 
| 791 | 
  | 
 | 
| 792 | 
  | 
 | 
| 796 | 
  | 
        if (o->os == NULL) | 
| 797 | 
  | 
                return; | 
| 798 | 
  | 
        freemesh((*(MESHINST *)o->os).msh); | 
| 799 | 
< | 
        free((void *)o->os); | 
| 799 | 
> | 
        free(o->os); | 
| 800 | 
  | 
        o->os = NULL; | 
| 801 | 
  | 
} |