home *** CD-ROM | disk | FTP | other *** search
- /* merge.c - optimize an object by removing common points and edges
- * - Written by Glenn M. Lewis - 3/10/92
- */
-
- #include <stdio.h>
- #include "t3dlib.h"
- #ifdef __STDC__
- #include <stdlib.h>
- #include <strings.h>
- #include "merge_protos.h"
- #endif
-
- static char rcs_id[] = "$Id: merge.c,v 1.10 1993/01/30 23:43:03 glewis Exp $";
-
- void merge_object();
-
- void merge_World(world)
- WORLD *world;
- {
- OBJECT *o;
-
- for (o=world->object; o; o=o->next)
- merge_object(o);
- }
-
- void remove_point(desc, p)
- register DESC *desc;
- int p;
- {
- register UWORD *e;
- register int i;
-
- if (p >= desc->pcount-1) { /* No need to do anything */
- desc->pcount--;
- return;
- }
-
- /* First, move all the points closer to the front of the list */
- bcopy((char*)&desc->pnts[p+1], (char*)&desc->pnts[p],
- (unsigned)(desc->pcount-p-1)*sizeof(XYZ_st));
- desc->pcount--;
- /* Next, decrement all Point indices that are equal to or greater than "p" */
- for (i=desc->ecount,e=desc->edge; i--; e+=2) {
- if (e[0] >= p) e[0]--;
- if (e[1] >= p) e[1]--;
- }
- }
-
- void remove_edge(desc, e)
- register DESC *desc;
- int e;
- {
- register UWORD *f;
- register int i;
-
- if (e >= desc->ecount-1) { /* No need to do anything */
- desc->ecount--;
- return;
- }
- /* First, move all the edges closer to the front of the list */
- bcopy((char*)&desc->edge[(e+1)<<1], (char*)&desc->edge[e<<1],
- (unsigned)(desc->ecount-e-1)*2*sizeof(UWORD));
- desc->ecount--;
- /* Next, decrement all Edge indices that are equal to or greater than "e" */
- for (i=desc->fcount,f=desc->face; i--; f+=3) {
- if (f[0] >= e) f[0]--;
- if (f[1] >= e) f[1]--;
- if (f[2] >= e) f[2]--;
- }
- }
-
- void merge_points(desc, p1, p2)
- register DESC *desc;
- int p1, p2;
- {
- register UWORD *e;
- register int i;
-
- /* First, check all edges, and those that point to "p2" make point to "p1" */
- for (e=desc->edge,i=0; i<desc->ecount; i++,e+=2) {
- if (e[0] == p2) e[0] = p1;
- if (e[1] == p2) e[1] = p1;
- /* If the two points in the edge are the same point, remove the edge! */
- if (e[0] == e[1]) { remove_edge(desc, i); i--; e-=2; }
- }
- /* Next, remove the duplicate point and adjust *all* the pointers */
- remove_point(desc, p2);
- }
-
- void merge_edges(desc, e1, e2)
- register DESC *desc;
- int e1, e2;
- {
- register UWORD *f;
- register int i;
-
- /* First, check all faces, and those that point to "e2" make point to "e1" */
- for (f=desc->face,i=0; i<desc->fcount; i++,f+=3) {
- if (f[0] == e2) f[0] = e1;
- if (f[1] == e2) f[1] = e1;
- if (f[2] == e2) f[2] = e1;
- }
- /* Next, remove the duplicate edge and adjust *all* the pointers */
- remove_edge(desc, e2);
- }
-
- void merge_object(obj)
- OBJECT *obj;
- {
- register DESC *desc;
- XYZ_st *p1, *p2;
- UWORD *e1, *e2;
- register int i, j;
-
- if (obj->child) merge_object(obj->child);
-
- if (!(desc = obj->desc) || !desc->pcount || !desc->ecount) return;
- /* Merge duplicate points */
- /* DO NOT ATTEMPT TO OPTIMIZE THE LOOPS, AS THE VARIABLE REFERENCES *MUST*
- * BE PERFORMED EACH TIME THROUGH THE LOOP SINCE THE STRUCTURE IS CHANGING!
- */
- /* Start at end and work back */
-
- #ifdef DEBUG
- fprintf(stderr, "Removing unused edges...\n");
- #endif
-
- /* Remove unused edges */
- /* Start at end and work back */
- for (i=desc->ecount; i--; ) {
- #ifdef DEBUG
- fprintf(stderr, "i:%4d:%4d\n", i, desc->ecount);
- #endif
- for (j=desc->fcount; j--; ) {
- if (desc->face[3*j]==i ||
- desc->face[3*j+1]==i ||
- desc->face[3*j+2]==i) break; /* Yup, it is used. */
- }
- if (j<0) /* Edge is not referenced in any face. Delete. */
- remove_edge(desc, i);
- }
-
- #ifdef DEBUG
- fprintf(stderr, "Removing unused points...\n");
- #endif
-
- for (i=desc->pcount; i--; ) {
- #ifdef DEBUG
- fprintf(stderr, "i:%4d:%4d\n", i, desc->pcount);
- #endif
- for (j=desc->ecount; j--; ) {
- if (desc->edge[j<<1]==i ||
- desc->edge[(j<<1)+1]==i) break; /* Yup, it is used. */
- }
- if (j<0) /* Point is not referenced in any edge. Delete. */
- remove_point(desc, i);
- }
-
- #ifdef DEBUG
- fprintf(stderr, "Merging duplicate edges...\n");
- #endif
-
- /* Merge duplicate edges */
- /* Start at end and work back */
- for (i=desc->ecount-1; i--; ) {
- e1 = &desc->edge[i<<1];
- #ifdef DEBUG
- fprintf(stderr, "i:%4d:%4d\n", i, desc->ecount);
- #endif
- for (j=i+1; j<desc->ecount; j++) {
- e2 = &desc->edge[j<<1];
- if ((e1[0] == e2[0] && e1[1] == e2[1]) ||
- (e1[0] == e2[1] && e1[1] == e2[0])) {
- /* Yep, the edges are identical. Merge them. */
- merge_edges(desc, i, j);
- j--;
- }
- }
- }
-
- #ifdef DEBUG
- fprintf(stderr, "Merging duplicate points...\n");
- #endif
-
- for (i=desc->pcount-1; i--; ) {
- p1 = &desc->pnts[i];
- #ifdef DEBUG
- fprintf(stderr, "i:%4d:%4d\n", i, desc->pcount);
- #endif
- for (j=i+1; j<desc->pcount; j++) {
- p2 = &desc->pnts[j];
- if (p1->x == p2->x && p1->y == p2->y && p1->z == p2->z) {
- /* Yep, the points are identical. Merge them. */
- merge_points(desc, i, j);
- j--;
- }
- }
- }
- }
-