ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/ot/cvmesh.c
Revision: 2.8
Committed: Thu Jan 29 22:21:34 2004 UTC (20 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.7: +26 -4 lines
Log Message:
Improved behavior to remove normals from flat triangles and reverse vertices

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.8 static const char RCSid[] = "$Id: cvmesh.c,v 2.7 2003/09/18 16:53:53 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Radiance triangle mesh conversion routines
6     */
7    
8     #include "copyright.h"
9     #include "standard.h"
10     #include "cvmesh.h"
11     #include "otypes.h"
12     #include "face.h"
13 greg 2.8 #include "tmesh.h"
14 greg 2.1
15     /*
16     * We need to divide faces into triangles and record auxiliary information
17     * if given (surface normal and uv coordinates). We do this by extending
18     * the face structure linked to the OBJREC os member and putting our
19     * auxiliary after it -- a bit sly, but it works.
20     */
21    
22     /* Auxiliary data for triangle */
23     typedef struct {
24     int fl; /* flags of what we're storing */
25     OBJECT obj; /* mesh triangle ID */
26     FVECT vn[3]; /* normals */
27 schorsch 2.6 RREAL vc[3][2]; /* uv coords. */
28 greg 2.1 } TRIDATA;
29    
30     #define tdsize(fl) ((fl)&MT_UV ? sizeof(TRIDATA) : \
31 schorsch 2.6 (fl)&MT_N ? sizeof(TRIDATA)-6*sizeof(RREAL) : \
32 greg 2.1 sizeof(int)+sizeof(OBJECT))
33    
34     #define OMARGIN (10*FTINY) /* margin around global cube */
35    
36     MESH *ourmesh = NULL; /* our global mesh data structure */
37    
38     FVECT meshbounds[2]; /* mesh bounding box */
39    
40    
41     MESH *
42     cvinit(nm) /* initialize empty mesh */
43     char *nm;
44     {
45     /* free old mesh, first */
46     if (ourmesh != NULL) {
47     freemesh(ourmesh);
48     ourmesh = NULL;
49     freeobjects(0, nobjects);
50     donesets();
51     }
52     if (nm == NULL)
53     return(NULL);
54     ourmesh = (MESH *)calloc(1, sizeof(MESH));
55     if (ourmesh == NULL)
56     goto nomem;
57     ourmesh->name = savestr(nm);
58     ourmesh->nref = 1;
59     ourmesh->ldflags = 0;
60     ourmesh->mcube.cutree = EMPTY;
61 greg 2.2 ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = FHUGE;
62     ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = -FHUGE;
63 greg 2.1 meshbounds[0][0] = meshbounds[0][1] = meshbounds[0][2] = FHUGE;
64     meshbounds[1][0] = meshbounds[1][1] = meshbounds[1][2] = -FHUGE;
65     return(ourmesh);
66     nomem:
67     error(SYSTEM, "out of memory in cvinit");
68     return(NULL);
69     }
70    
71    
72     int
73 greg 2.3 cvpoly(mo, n, vp, vn, vc) /* convert a polygon to extended triangles */
74     OBJECT mo;
75 greg 2.1 int n;
76     FVECT *vp;
77     FVECT *vn;
78 schorsch 2.6 RREAL (*vc)[2];
79 greg 2.1 {
80     int tcnt = 0;
81     int flags;
82 schorsch 2.6 RREAL *tn[3], *tc[3];
83 greg 2.1 int *ord;
84     int i, j;
85    
86     if (n < 3) /* degenerate face */
87     return(0);
88     flags = MT_V;
89     if (vn != NULL) {
90     tn[0] = vn[0]; tn[1] = vn[1]; tn[2] = vn[2];
91     flags |= MT_N;
92     } else {
93     tn[0] = tn[1] = tn[2] = NULL;
94     }
95     if (vc != NULL) {
96     tc[0] = vc[0]; tc[1] = vc[1]; tc[2] = vc[2];
97     flags |= MT_UV;
98     } else {
99     tc[0] = tc[1] = tc[2] = NULL;
100     }
101     if (n == 3) /* output single triangle */
102 greg 2.3 return(cvtri(mo, vp[0], vp[1], vp[2],
103 greg 2.1 tn[0], tn[1], tn[2],
104     tc[0], tc[1], tc[2]));
105    
106     /* decimate polygon (assumes convex) */
107     ord = (int *)malloc(n*sizeof(int));
108     if (ord == NULL)
109     error(SYSTEM, "out of memory in cvpoly");
110     for (i = n; i--; )
111     ord[i] = i;
112     while (n >= 3) {
113     if (flags & MT_N)
114     for (i = 3; i--; )
115     tn[i] = vn[ord[i]];
116     if (flags & MT_UV)
117     for (i = 3; i--; )
118     tc[i] = vc[ord[i]];
119 greg 2.3 tcnt += cvtri(mo, vp[ord[0]], vp[ord[1]], vp[ord[2]],
120 greg 2.1 tn[0], tn[1], tn[2],
121     tc[0], tc[1], tc[2]);
122     /* remove vertex and rotate */
123     n--;
124     j = ord[0];
125     for (i = 0; i < n-1; i++)
126     ord[i] = ord[i+2];
127     ord[i] = j;
128     }
129     free((void *)ord);
130     return(tcnt);
131     }
132    
133    
134     static void
135     add2bounds(vp, vc) /* add point and uv coordinate to bounds */
136     FVECT vp;
137 schorsch 2.6 RREAL vc[2];
138 greg 2.1 {
139     register int j;
140    
141     for (j = 3; j--; ) {
142     if (vp[j] < meshbounds[0][j])
143     meshbounds[0][j] = vp[j];
144     if (vp[j] > meshbounds[1][j])
145     meshbounds[1][j] = vp[j];
146     }
147     if (vc == NULL)
148     return;
149     for (j = 2; j--; ) {
150     if (vc[j] < ourmesh->uvlim[0][j])
151     ourmesh->uvlim[0][j] = vc[j];
152     if (vc[j] > ourmesh->uvlim[1][j])
153     ourmesh->uvlim[1][j] = vc[j];
154     }
155     }
156    
157    
158     int /* create an extended triangle */
159 greg 2.3 cvtri(mo, vp1, vp2, vp3, vn1, vn2, vn3, vc1, vc2, vc3)
160     OBJECT mo;
161 greg 2.1 FVECT vp1, vp2, vp3;
162     FVECT vn1, vn2, vn3;
163 schorsch 2.6 RREAL vc1[2], vc2[2], vc3[2];
164 greg 2.1 {
165 greg 2.3 static OBJECT fobj = OVOID;
166     char buf[32];
167     int flags;
168     TRIDATA *ts;
169     FACE *f;
170     OBJREC *fop;
171     int j;
172 greg 2.1
173 greg 2.8 flags = MT_V; /* check what we have */
174     if (vn1 != NULL && vn2 != NULL && vn3 != NULL) {
175     RREAL *rp;
176     switch (flat_tri(vp1, vp2, vp3, vn1, vn2, vn3)) {
177     case ISBENT:
178     flags |= MT_N;
179     /* fall through */
180     case ISFLAT:
181     break;
182     case RVBENT:
183     flags |= MT_N;
184     rp = vn1; vn1 = vn3; vn3 = rp;
185     /* fall through */
186     case RVFLAT:
187     rp = vp1; vp1 = vp3; vp3 = rp;
188     rp = vc1; vc1 = vc3; vc3 = rp;
189     break;
190     case DEGEN:
191     error(WARNING, "degenerate triangle");
192     return(0);
193     default:
194     error(INTERNAL, "bad return from flat_tri()");
195     }
196     }
197 greg 2.1 if (vc1 != NULL && vc2 != NULL && vc3 != NULL)
198     flags |= MT_UV;
199 greg 2.3 if (fobj == OVOID) { /* create new triangle object */
200     fobj = newobject();
201     if (fobj == OVOID)
202     goto nomem;
203     fop = objptr(fobj);
204     fop->omod = mo;
205     fop->otype = OBJ_FACE;
206     sprintf(buf, "t%d", fobj);
207     fop->oname = savqstr(buf);
208     fop->oargs.nfargs = 9;
209 schorsch 2.6 fop->oargs.farg = (RREAL *)malloc(9*sizeof(RREAL));
210 greg 2.3 if (fop->oargs.farg == NULL)
211     goto nomem;
212     } else { /* else reuse failed one */
213     fop = objptr(fobj);
214     if (fop->otype != OBJ_FACE || fop->oargs.nfargs != 9)
215     error(CONSISTENCY, "code error 1 in cvtri");
216     }
217 greg 2.1 for (j = 3; j--; ) {
218     fop->oargs.farg[j] = vp1[j];
219     fop->oargs.farg[3+j] = vp2[j];
220     fop->oargs.farg[6+j] = vp3[j];
221     }
222     /* create face record */
223 greg 2.3 f = getface(fop);
224     if (f->area == 0.) {
225     free_os(fop);
226 greg 2.1 return(0);
227     }
228     if (fop->os != (char *)f)
229 greg 2.3 error(CONSISTENCY, "code error 2 in cvtri");
230 greg 2.1 /* follow with auxliary data */
231     f = (FACE *)realloc((void *)f, sizeof(FACE)+tdsize(flags));
232     if (f == NULL)
233     goto nomem;
234     fop->os = (char *)f;
235     ts = (TRIDATA *)(f+1);
236     ts->fl = flags;
237     ts->obj = OVOID;
238     if (flags & MT_N)
239     for (j = 3; j--; ) {
240     ts->vn[0][j] = vn1[j];
241     ts->vn[1][j] = vn2[j];
242     ts->vn[2][j] = vn3[j];
243     }
244     if (flags & MT_UV)
245     for (j = 2; j--; ) {
246     ts->vc[0][j] = vc1[j];
247     ts->vc[1][j] = vc2[j];
248     ts->vc[2][j] = vc3[j];
249     }
250     else
251     vc1 = vc2 = vc3 = NULL;
252     /* update bounds */
253     add2bounds(vp1, vc1);
254     add2bounds(vp2, vc2);
255     add2bounds(vp3, vc3);
256 greg 2.3 fobj = OVOID; /* we used this one */
257 greg 2.1 return(1);
258     nomem:
259     error(SYSTEM, "out of memory in cvtri");
260     return(0);
261     }
262    
263    
264     static OBJECT
265     cvmeshtri(obj) /* add an extended triangle to our mesh */
266     OBJECT obj;
267     {
268     OBJREC *o = objptr(obj);
269     TRIDATA *ts;
270     MESHVERT vert[3];
271     int i, j;
272    
273     if (o->otype != OBJ_FACE)
274     error(CONSISTENCY, "non-face in mesh");
275     if (o->oargs.nfargs != 9)
276     error(CONSISTENCY, "non-triangle in mesh");
277     if (o->os == NULL)
278     error(CONSISTENCY, "missing face record in cvmeshtri");
279     ts = (TRIDATA *)((FACE *)o->os + 1);
280     if (ts->obj != OVOID) /* already added? */
281     return(ts->obj);
282     vert[0].fl = vert[1].fl = vert[2].fl = ts->fl;
283     for (i = 3; i--; )
284     for (j = 3; j--; )
285     vert[i].v[j] = o->oargs.farg[3*i+j];
286     if (ts->fl & MT_N)
287     for (i = 3; i--; )
288     for (j = 3; j--; )
289     vert[i].n[j] = ts->vn[i][j];
290     if (ts->fl & MT_UV)
291     for (i = 3; i--; )
292     for (j = 2; j--; )
293     vert[i].uv[j] = ts->vc[i][j];
294 greg 2.3 ts->obj = addmeshtri(ourmesh, vert, o->omod);
295 greg 2.1 if (ts->obj == OVOID)
296     error(INTERNAL, "addmeshtri failed");
297     return(ts->obj);
298     }
299    
300    
301     void
302     cvmeshbounds() /* set mesh boundaries */
303     {
304     int i;
305    
306     if (ourmesh == NULL)
307     return;
308     /* fix coordinate bounds */
309     for (i = 0; i < 3; i++) {
310 greg 2.5 if (meshbounds[0][i] > meshbounds[1][i])
311 greg 2.1 error(USER, "no polygons in mesh");
312     meshbounds[0][i] -= OMARGIN;
313     meshbounds[1][i] += OMARGIN;
314     if (meshbounds[1][i]-meshbounds[0][i] > ourmesh->mcube.cusize)
315     ourmesh->mcube.cusize = meshbounds[1][i] -
316     meshbounds[0][i];
317     }
318     for (i = 0; i < 3; i++)
319     ourmesh->mcube.cuorg[i] = (meshbounds[1][i]+meshbounds[0][i] -
320     ourmesh->mcube.cusize)*.5;
321 greg 2.2 if (ourmesh->uvlim[0][0] > ourmesh->uvlim[1][0]) {
322 greg 2.1 ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = 0.;
323     ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = 0.;
324     } else {
325     for (i = 0; i < 2; i++) {
326 greg 2.7 double marg; /* expand past endpoints */
327     marg = (2./(1L<<(8*sizeof(uint16)))) *
328     (ourmesh->uvlim[1][i] -
329     ourmesh->uvlim[0][i]);
330 greg 2.1 ourmesh->uvlim[0][i] -= marg;
331     ourmesh->uvlim[1][i] += marg;
332     }
333     }
334     ourmesh->ldflags |= IO_BOUNDS;
335     }
336    
337    
338     static OCTREE
339     cvmeshoct(ot) /* convert triangles in subtree */
340     OCTREE ot;
341     {
342     int i;
343    
344     if (isempty(ot))
345     return(EMPTY);
346    
347     if (isfull(ot)) {
348     OBJECT oset1[MAXSET+1];
349     OBJECT oset2[MAXSET+1];
350     objset(oset1, ot);
351     oset2[0] = 0;
352     for (i = oset1[0]; i > 0; i--)
353     insertelem(oset2, cvmeshtri(oset1[i]));
354     return(fullnode(oset2));
355     }
356    
357     for (i = 8; i--; )
358     octkid(ot, i) = cvmeshoct(octkid(ot, i));
359     return(ot);
360     }
361    
362    
363     MESH *
364     cvmesh() /* convert mesh and octree leaf nodes */
365     {
366     if (ourmesh == NULL)
367     return(NULL);
368     /* convert triangles in octree nodes */
369     ourmesh->mcube.cutree = cvmeshoct(ourmesh->mcube.cutree);
370     ourmesh->ldflags |= IO_SCENE|IO_TREE;
371    
372     return(ourmesh);
373     }