ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/ot/cvmesh.c
Revision: 2.1
Committed: Tue Mar 11 17:08:55 2003 UTC (21 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
First working version of new "mesh" primitive, obj2mesh converter

File Contents

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