19 |
|
int |
20 |
|
findName(const char *nm, const char **nmlist, int n) |
21 |
|
{ |
22 |
< |
register int i; |
22 |
> |
int i; |
23 |
|
|
24 |
|
for (i = n; i-- > 0; ) |
25 |
|
if (!strcmp(nmlist[i], nm)) |
259 |
|
repl_tex[0] = -1; |
260 |
|
for (f = sc->vert[repl].vflist; f != NULL; f = f->v[j].fnext) { |
261 |
|
/* make sure prev isn't in there */ |
262 |
< |
for (j = 0; j < f->nv; j++) |
262 |
> |
for (j = f->nv; j-- > 0; ) |
263 |
|
if (f->v[j].vid == prev) |
264 |
|
return(0); |
265 |
< |
for (j = 0; j < f->nv; j++) |
265 |
> |
for (j = f->nv; j-- > 0; ) |
266 |
|
if (f->v[j].vid == repl) |
267 |
|
break; |
268 |
< |
if (j >= f->nv) |
268 |
> |
if (j < 0) |
269 |
|
goto linkerr; |
270 |
|
if (f->v[j].tid < 0) |
271 |
|
continue; |
290 |
|
/* get replacement normals */ |
291 |
|
repl_norm[0] = -1; |
292 |
|
for (f = sc->vert[repl].vflist; f != NULL; f = f->v[j].fnext) { |
293 |
< |
for (j = 0; j < f->nv; j++) |
293 |
> |
for (j = f->nv; j-- > 0; ) |
294 |
|
if (f->v[j].vid == repl) |
295 |
|
break; |
296 |
|
if (f->v[j].nid < 0) |
315 |
|
} |
316 |
|
/* replace occurrences of vertex */ |
317 |
|
for (f = sc->vert[prev].vflist; f != NULL; f = f->v[j].fnext) { |
318 |
< |
for (j = 0; j < f->nv; j++) |
318 |
> |
for (j = f->nv; j-- > 0; ) |
319 |
|
if (f->v[j].vid == prev) |
320 |
|
break; |
321 |
< |
if (j >= f->nv) |
321 |
> |
if (j < 0) |
322 |
|
goto linkerr; |
323 |
|
/* XXX doesn't allow for multiple references to prev in face */ |
324 |
|
f->v[j].vid = repl; /* replace vertex itself */ |
325 |
< |
if (faceArea(sc, f, NULL) <= FTINY) |
325 |
> |
if (faceArea(sc, f, NULL) <= FTINY*FTINY) |
326 |
|
f->flags |= FACE_DEGENERATE; |
327 |
|
if (f->v[j].tid >= 0) /* replace texture if appropriate */ |
328 |
|
for (i = 0; repl_tex[i] >= 0; i++) { |
432 |
|
/* look for duplicates */ |
433 |
|
for (f1 = sc->vert[vid].vflist; f1 != NULL; |
434 |
|
f1 = f1->v[j].fnext) { |
435 |
< |
for (j = 0; j < f1->nv; j++) |
435 |
> |
for (j = f1->nv; j-- > 0; ) |
436 |
|
if (f1->v[j].vid == vid) |
437 |
|
break; |
438 |
< |
if (j >= f1->nv) |
438 |
> |
if (j < 0) |
439 |
|
break; /* missing link! */ |
440 |
|
if (f1 == f) |
441 |
|
continue; /* shouldn't happen */ |
460 |
|
++nfound; |
461 |
|
} |
462 |
|
} |
463 |
+ |
if (verbose) |
464 |
+ |
fprintf(stderr, "Found %d duplicate faces\n", nfound); |
465 |
|
return(nfound); |
466 |
|
} |
467 |
|
|
488 |
|
continue; |
489 |
|
} |
490 |
|
while (vf != NULL) { |
491 |
< |
for (j = 0; j < vf->nv; j++) |
491 |
> |
for (j = vf->nv; j-- > 0; ) |
492 |
|
if (vf->v[j].vid == vid) |
493 |
|
break; |
494 |
< |
if (j >= vf->nv) |
494 |
> |
if (j < 0) |
495 |
|
break; /* error */ |
496 |
|
if (vf->v[j].fnext == ftst) { |
497 |
|
vf->v[j].fnext = |
549 |
|
sc->descr[sc->ndescr++] = savqstr((char *)comment); |
550 |
|
} |
551 |
|
|
552 |
+ |
/* Find index for comment containing the given string (starting from n) */ |
553 |
+ |
int |
554 |
+ |
findComment(Scene *sc, const char *match, int n) |
555 |
+ |
{ |
556 |
+ |
if (n >= sc->ndescr) |
557 |
+ |
return(-1); |
558 |
+ |
n *= (n > 0); |
559 |
+ |
while (n < sc->ndescr) |
560 |
+ |
if (strstr(sc->descr[n], match) != NULL) |
561 |
+ |
return(n); |
562 |
+ |
return(-1); |
563 |
+ |
} |
564 |
+ |
|
565 |
|
/* Clear comments */ |
566 |
|
void |
567 |
|
clearComments(Scene *sc) |
588 |
|
for ( ; ; ) { /* else find position */ |
589 |
|
if (fp == f) |
590 |
|
return; /* already in list */ |
591 |
< |
for (j = 0; j < fp->nv; j++) |
591 |
> |
for (j = fp->nv; j-- > 0; ) |
592 |
|
if (fp->v[j].vid == vid) |
593 |
|
break; |
594 |
< |
if (j >= fp->nv) |
594 |
> |
if (j < 0) |
595 |
|
error(CONSISTENCY, "Link error in add2facelist()"); |
596 |
|
if (fp->v[j].fnext == NULL) |
597 |
|
break; /* reached the end */ |
614 |
|
return(sc); |
615 |
|
} |
616 |
|
|
617 |
< |
/* Duplicate a scene */ |
617 |
> |
/* Add a vertex to a scene */ |
618 |
> |
int |
619 |
> |
addVertex(Scene *sc, double x, double y, double z) |
620 |
> |
{ |
621 |
> |
sc->vert = chunk_alloc(Vertex, sc->vert, sc->nverts); |
622 |
> |
sc->vert[sc->nverts].p[0] = x; |
623 |
> |
sc->vert[sc->nverts].p[1] = y; |
624 |
> |
sc->vert[sc->nverts].p[2] = z; |
625 |
> |
sc->vert[sc->nverts].vflist = NULL; |
626 |
> |
return(sc->nverts++); |
627 |
> |
} |
628 |
> |
|
629 |
> |
/* Add a texture coordinate to a scene */ |
630 |
> |
int |
631 |
> |
addTexture(Scene *sc, double u, double v) |
632 |
> |
{ |
633 |
> |
sc->tex = chunk_alloc(TexCoord, sc->tex, sc->ntex); |
634 |
> |
sc->tex[sc->ntex].u = u; |
635 |
> |
sc->tex[sc->ntex].v = v; |
636 |
> |
return(sc->ntex++); |
637 |
> |
} |
638 |
> |
|
639 |
> |
/* Add a surface normal to a scene */ |
640 |
> |
int |
641 |
> |
addNormal(Scene *sc, double xn, double yn, double zn) |
642 |
> |
{ |
643 |
> |
FVECT nrm; |
644 |
> |
|
645 |
> |
nrm[0] = xn; nrm[1] = yn; nrm[2] = zn; |
646 |
> |
if (normalize(nrm) == .0) |
647 |
> |
return(-1); |
648 |
> |
sc->norm = chunk_alloc(Normal, sc->norm, sc->nnorms); |
649 |
> |
VCOPY(sc->norm[sc->nnorms], nrm); |
650 |
> |
return(sc->nnorms++); |
651 |
> |
} |
652 |
> |
|
653 |
> |
/* Set current (last) group */ |
654 |
> |
void |
655 |
> |
setGroup(Scene *sc, const char *nm) |
656 |
> |
{ |
657 |
> |
sc->lastgrp = findName(nm, (const char **)sc->grpname, sc->ngrps); |
658 |
> |
if (sc->lastgrp >= 0) |
659 |
> |
return; |
660 |
> |
sc->grpname = chunk_alloc(char *, sc->grpname, sc->ngrps); |
661 |
> |
sc->grpname[sc->lastgrp=sc->ngrps++] = savqstr((char *)nm); |
662 |
> |
} |
663 |
> |
|
664 |
> |
/* Set current (last) material */ |
665 |
> |
void |
666 |
> |
setMaterial(Scene *sc, const char *nm) |
667 |
> |
{ |
668 |
> |
sc->lastmat = findName(nm, (const char **)sc->matname, sc->nmats); |
669 |
> |
if (sc->lastmat >= 0) |
670 |
> |
return; |
671 |
> |
sc->matname = chunk_alloc(char *, sc->matname, sc->nmats); |
672 |
> |
sc->matname[sc->lastmat=sc->nmats++] = savqstr((char *)nm); |
673 |
> |
} |
674 |
> |
|
675 |
> |
/* Add new face to a scene */ |
676 |
> |
Face * |
677 |
> |
addFace(Scene *sc, VNDX vid[], int nv) |
678 |
> |
{ |
679 |
> |
Face *f; |
680 |
> |
int i; |
681 |
> |
|
682 |
> |
if (nv < 3) |
683 |
> |
return(NULL); |
684 |
> |
f = (Face *)emalloc(sizeof(Face)+sizeof(VertEnt)*(nv-3)); |
685 |
> |
f->flags = 0; |
686 |
> |
f->nv = nv; |
687 |
> |
f->grp = sc->lastgrp; |
688 |
> |
f->mat = sc->lastmat; |
689 |
> |
for (i = 0; i < nv; i++) { /* add each vertex */ |
690 |
> |
int j; |
691 |
> |
f->v[i].vid = vid[i][0]; |
692 |
> |
f->v[i].tid = vid[i][1]; |
693 |
> |
f->v[i].nid = vid[i][2]; |
694 |
> |
f->v[i].fnext = NULL; |
695 |
> |
for (j = i; j-- > 0; ) |
696 |
> |
if (f->v[j].vid == vid[i][0]) |
697 |
> |
break; |
698 |
> |
if (j < 0) { /* first occurrence? */ |
699 |
> |
f->v[i].fnext = sc->vert[vid[i][0]].vflist; |
700 |
> |
sc->vert[vid[i][0]].vflist = f; |
701 |
> |
} else if (nv == 3) /* degenerate triangle? */ |
702 |
> |
f->flags |= FACE_DEGENERATE; |
703 |
> |
} |
704 |
> |
f->next = sc->flist; /* push onto face list */ |
705 |
> |
sc->flist = f; |
706 |
> |
sc->nfaces++; |
707 |
> |
/* check face area */ |
708 |
> |
if (!(f->flags & FACE_DEGENERATE) && faceArea(sc, f, NULL) <= FTINY*FTINY) |
709 |
> |
f->flags |= FACE_DEGENERATE; |
710 |
> |
return(f); |
711 |
> |
} |
712 |
> |
|
713 |
> |
/* Duplicate a scene, optionally selecting faces */ |
714 |
|
Scene * |
715 |
< |
dupScene(const Scene *osc) |
715 |
> |
dupScene(const Scene *osc, int flreq, int flexc) |
716 |
|
{ |
717 |
+ |
int fltest = flreq | flexc; |
718 |
|
Scene *sc; |
719 |
|
const Face *fo; |
720 |
|
Face *f; |
763 |
|
sc->nnorms = osc->nnorms; |
764 |
|
} |
765 |
|
for (fo = osc->flist; fo != NULL; fo = fo->next) { |
766 |
+ |
if ((fo->flags & fltest) != flreq) |
767 |
+ |
continue; |
768 |
|
f = (Face *)emalloc(sizeof(Face) + |
769 |
|
sizeof(VertEnt)*(fo->nv-3)); |
770 |
|
memcpy((void *)f, (const void *)fo, sizeof(Face) + |
775 |
|
sc->flist = f; |
776 |
|
sc->nfaces++; |
777 |
|
} |
778 |
+ |
deleteUnreferenced(sc); /* jetsam */ |
779 |
|
return(sc); |
780 |
|
} |
781 |
|
|
667 |
– |
/* Transform entire scene */ |
782 |
|
#define MAXAC 100 |
783 |
+ |
|
784 |
+ |
/* Transform entire scene */ |
785 |
|
int |
786 |
+ |
xfScene(Scene *sc, int xac, char *xav[]) |
787 |
+ |
{ |
788 |
+ |
char comm[24+MAXAC*8]; |
789 |
+ |
char *cp; |
790 |
+ |
XF myxf; |
791 |
+ |
FVECT vec; |
792 |
+ |
int i; |
793 |
+ |
|
794 |
+ |
if ((sc == NULL) | (xac <= 0) | (xav == NULL)) |
795 |
+ |
return(0); |
796 |
+ |
/* compute matrix */ |
797 |
+ |
if (xf(&myxf, xac, xav) < xac) |
798 |
+ |
return(0); |
799 |
+ |
/* transform vertices */ |
800 |
+ |
for (i = 0; i < sc->nverts; i++) { |
801 |
+ |
VCOPY(vec, sc->vert[i].p); |
802 |
+ |
multp3(vec, vec, myxf.xfm); |
803 |
+ |
VCOPY(sc->vert[i].p, vec); |
804 |
+ |
} |
805 |
+ |
/* transform normals */ |
806 |
+ |
for (i = 0; i < sc->nnorms; i++) { |
807 |
+ |
VCOPY(vec, sc->norm[i]); |
808 |
+ |
multv3(vec, vec, myxf.xfm); |
809 |
+ |
vec[0] /= myxf.sca; vec[1] /= myxf.sca; vec[2] /= myxf.sca; |
810 |
+ |
VCOPY(sc->norm[i], vec); |
811 |
+ |
} |
812 |
+ |
/* add comment */ |
813 |
+ |
cp = strcpy(comm, "Transformed by:"); |
814 |
+ |
for (i = 0; i < xac; i++) { |
815 |
+ |
while (*cp) cp++; |
816 |
+ |
*cp++ = ' '; |
817 |
+ |
strcpy(cp, xav[i]); |
818 |
+ |
} |
819 |
+ |
addComment(sc, comm); |
820 |
+ |
return(xac); /* all done */ |
821 |
+ |
} |
822 |
+ |
|
823 |
+ |
/* Ditto, using transform string rather than pre-parsed words */ |
824 |
+ |
int |
825 |
|
xfmScene(Scene *sc, const char *xfm) |
826 |
|
{ |
827 |
|
char *xav[MAXAC+1]; |
828 |
|
int xac, i; |
674 |
– |
XF myxf; |
675 |
– |
FVECT vec; |
829 |
|
|
830 |
|
if ((sc == NULL) | (xfm == NULL)) |
831 |
|
return(0); |
832 |
< |
while (isspace(*xfm)) /* find first word */ |
832 |
> |
/* skip spaces at beginning */ |
833 |
> |
while (isspace(*xfm)) |
834 |
|
xfm++; |
835 |
|
if (!*xfm) |
836 |
|
return(0); |
837 |
< |
/* break into words for xf() */ |
837 |
> |
/* parse string into words */ |
838 |
|
xav[0] = strcpy((char *)malloc(strlen(xfm)+1), xfm); |
839 |
|
xac = 1; i = 0; |
840 |
|
for ( ; ; ) { |
845 |
|
xav[0][i++] = '\0'; |
846 |
|
if (!xfm[i]) |
847 |
|
break; |
848 |
< |
if (xac >= MAXAC-1) |
849 |
< |
goto bad_xform; |
848 |
> |
if (xac >= MAXAC-1) { |
849 |
> |
free(xav[0]); |
850 |
> |
return(0); |
851 |
> |
} |
852 |
|
xav[xac++] = xav[0] + i; |
853 |
|
} |
854 |
|
xav[xac] = NULL; |
855 |
< |
if (xf(&myxf, xac, xav) < xac) |
700 |
< |
goto bad_xform; |
855 |
> |
i = xfScene(sc, xac, xav); |
856 |
|
free(xav[0]); |
857 |
< |
/* transform vertices */ |
858 |
< |
for (i = 0; i < sc->nverts; i++) { |
859 |
< |
VCOPY(vec, sc->vert[i].p); |
860 |
< |
multp3(vec, vec, myxf.xfm); |
861 |
< |
VCOPY(sc->vert[i].p, vec); |
857 |
> |
return(i); |
858 |
> |
} |
859 |
> |
#undef MAXAC |
860 |
> |
|
861 |
> |
/* Delete unreferenced vertices, normals, texture coords */ |
862 |
> |
void |
863 |
> |
deleteUnreferenced(Scene *sc) |
864 |
> |
{ |
865 |
> |
int *vmap; |
866 |
> |
Face *f; |
867 |
> |
int nused, i; |
868 |
> |
/* allocate index map */ |
869 |
> |
if (!sc->nverts) |
870 |
> |
return; |
871 |
> |
i = sc->nverts; |
872 |
> |
if (sc->ntex > i) |
873 |
> |
i = sc->ntex; |
874 |
> |
if (sc->nnorms > i) |
875 |
> |
i = sc->nnorms; |
876 |
> |
vmap = (int *)emalloc(sizeof(int)*i); |
877 |
> |
/* remap positions */ |
878 |
> |
for (i = nused = 0; i < sc->nverts; i++) { |
879 |
> |
if (sc->vert[i].vflist == NULL) { |
880 |
> |
vmap[i] = -1; |
881 |
> |
continue; |
882 |
> |
} |
883 |
> |
if (nused != i) |
884 |
> |
sc->vert[nused] = sc->vert[i]; |
885 |
> |
vmap[i] = nused++; |
886 |
|
} |
887 |
< |
/* transform normals */ |
888 |
< |
for (i = 0; i < sc->nnorms; i++) { |
889 |
< |
VCOPY(vec, sc->norm[i]); |
890 |
< |
multv3(vec, vec, myxf.xfm); |
891 |
< |
vec[0] /= myxf.sca; vec[1] /= myxf.sca; vec[2] /= myxf.sca; |
892 |
< |
VCOPY(sc->norm[i], vec); |
887 |
> |
if (nused == sc->nverts) |
888 |
> |
goto skip_pos; |
889 |
> |
sc->vert = (Vertex *)erealloc((char *)sc->vert, |
890 |
> |
sizeof(Vertex)*(nused+(CHUNKSIZ-1))); |
891 |
> |
sc->nverts = nused; |
892 |
> |
for (f = sc->flist; f != NULL; f = f->next) |
893 |
> |
for (i = f->nv; i--; ) |
894 |
> |
if ((f->v[i].vid = vmap[f->v[i].vid]) < 0) |
895 |
> |
error(CONSISTENCY, |
896 |
> |
"Link error in del_unref_verts()"); |
897 |
> |
skip_pos: |
898 |
> |
/* remap texture coord's */ |
899 |
> |
if (!sc->ntex) |
900 |
> |
goto skip_tex; |
901 |
> |
memset((void *)vmap, 0, sizeof(int)*sc->ntex); |
902 |
> |
for (f = sc->flist; f != NULL; f = f->next) |
903 |
> |
for (i = f->nv; i--; ) |
904 |
> |
if (f->v[i].tid >= 0) |
905 |
> |
vmap[f->v[i].tid] = 1; |
906 |
> |
for (i = nused = 0; i < sc->ntex; i++) { |
907 |
> |
if (!vmap[i]) |
908 |
> |
continue; |
909 |
> |
if (nused != i) |
910 |
> |
sc->tex[nused] = sc->tex[i]; |
911 |
> |
vmap[i] = nused++; |
912 |
|
} |
913 |
< |
return xac; /* finito */ |
914 |
< |
bad_xform: |
915 |
< |
free(xav[0]); |
916 |
< |
return(0); |
913 |
> |
if (nused == sc->ntex) |
914 |
> |
goto skip_tex; |
915 |
> |
sc->tex = (TexCoord *)erealloc((char *)sc->tex, |
916 |
> |
sizeof(TexCoord)*(nused+(CHUNKSIZ-1))); |
917 |
> |
sc->ntex = nused; |
918 |
> |
for (f = sc->flist; f != NULL; f = f->next) |
919 |
> |
for (i = f->nv; i--; ) |
920 |
> |
if (f->v[i].tid >= 0) |
921 |
> |
f->v[i].tid = vmap[f->v[i].tid]; |
922 |
> |
skip_tex: |
923 |
> |
/* remap normals */ |
924 |
> |
if (!sc->nnorms) |
925 |
> |
goto skip_norms; |
926 |
> |
memset((void *)vmap, 0, sizeof(int)*sc->nnorms); |
927 |
> |
for (f = sc->flist; f != NULL; f = f->next) |
928 |
> |
for (i = f->nv; i--; ) |
929 |
> |
if (f->v[i].nid >= 0) |
930 |
> |
vmap[f->v[i].nid] = 1; |
931 |
> |
for (i = nused = 0; i < sc->nnorms; i++) { |
932 |
> |
if (!vmap[i]) |
933 |
> |
continue; |
934 |
> |
if (nused != i) |
935 |
> |
memcpy((void *)sc->norm[nused], |
936 |
> |
(void *)sc->norm[i], |
937 |
> |
sizeof(Normal)); |
938 |
> |
vmap[i] = nused++; |
939 |
> |
} |
940 |
> |
if (nused == sc->nnorms) |
941 |
> |
goto skip_norms; |
942 |
> |
sc->norm = (Normal *)erealloc((char *)sc->norm, |
943 |
> |
sizeof(Normal)*(nused+(CHUNKSIZ-1))); |
944 |
> |
sc->nnorms = nused; |
945 |
> |
for (f = sc->flist; f != NULL; f = f->next) |
946 |
> |
for (i = f->nv; i--; ) |
947 |
> |
if (f->v[i].nid >= 0) |
948 |
> |
f->v[i].nid = vmap[f->v[i].nid]; |
949 |
> |
skip_norms: |
950 |
> |
/* clean up */ |
951 |
> |
efree((char *)vmap); |
952 |
|
} |
720 |
– |
#undef MAXAC |
953 |
|
|
954 |
|
/* Free a scene */ |
955 |
|
void |