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, 10 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: cvmesh.c,v 2.7 2003/09/18 16:53:53 greg Exp $";
3 #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 #include "tmesh.h"
14
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 RREAL vc[3][2]; /* uv coords. */
28 } TRIDATA;
29
30 #define tdsize(fl) ((fl)&MT_UV ? sizeof(TRIDATA) : \
31 (fl)&MT_N ? sizeof(TRIDATA)-6*sizeof(RREAL) : \
32 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 ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = FHUGE;
62 ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = -FHUGE;
63 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 cvpoly(mo, n, vp, vn, vc) /* convert a polygon to extended triangles */
74 OBJECT mo;
75 int n;
76 FVECT *vp;
77 FVECT *vn;
78 RREAL (*vc)[2];
79 {
80 int tcnt = 0;
81 int flags;
82 RREAL *tn[3], *tc[3];
83 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 return(cvtri(mo, vp[0], vp[1], vp[2],
103 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 tcnt += cvtri(mo, vp[ord[0]], vp[ord[1]], vp[ord[2]],
120 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 RREAL vc[2];
138 {
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 cvtri(mo, vp1, vp2, vp3, vn1, vn2, vn3, vc1, vc2, vc3)
160 OBJECT mo;
161 FVECT vp1, vp2, vp3;
162 FVECT vn1, vn2, vn3;
163 RREAL vc1[2], vc2[2], vc3[2];
164 {
165 static OBJECT fobj = OVOID;
166 char buf[32];
167 int flags;
168 TRIDATA *ts;
169 FACE *f;
170 OBJREC *fop;
171 int j;
172
173 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 if (vc1 != NULL && vc2 != NULL && vc3 != NULL)
198 flags |= MT_UV;
199 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 fop->oargs.farg = (RREAL *)malloc(9*sizeof(RREAL));
210 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 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 f = getface(fop);
224 if (f->area == 0.) {
225 free_os(fop);
226 return(0);
227 }
228 if (fop->os != (char *)f)
229 error(CONSISTENCY, "code error 2 in cvtri");
230 /* 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 fobj = OVOID; /* we used this one */
257 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 ts->obj = addmeshtri(ourmesh, vert, o->omod);
295 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 if (meshbounds[0][i] > meshbounds[1][i])
311 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 if (ourmesh->uvlim[0][0] > ourmesh->uvlim[1][0]) {
322 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 double marg; /* expand past endpoints */
327 marg = (2./(1L<<(8*sizeof(uint16)))) *
328 (ourmesh->uvlim[1][i] -
329 ourmesh->uvlim[0][i]);
330 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 }