ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/ot/cvmesh.c
Revision: 2.12
Committed: Fri Jan 24 01:26:44 2014 UTC (10 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R2, rad4R2P2, rad5R0, rad5R1, rad4R2, rad4R2P1, rad5R3, HEAD
Changes since 2.11: +1 -64 lines
Log Message:
Hopeful fix to triangulation code for obj2mesh with N-sided polygons

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: cvmesh.c,v 2.11 2011/02/18 19:00:43 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 static void add2bounds(FVECT vp, RREAL vc[2]);
41 static OBJECT cvmeshtri(OBJECT obj);
42 static OCTREE cvmeshoct(OCTREE ot);
43
44
45
46 MESH *
47 cvinit( /* initialize empty mesh */
48 char *nm
49 )
50 {
51 /* free old mesh, first */
52 if (ourmesh != NULL) {
53 freemesh(ourmesh);
54 ourmesh = NULL;
55 freeobjects(0, nobjects);
56 donesets();
57 }
58 if (nm == NULL)
59 return(NULL);
60 ourmesh = (MESH *)calloc(1, sizeof(MESH));
61 if (ourmesh == NULL)
62 goto nomem;
63 ourmesh->name = savestr(nm);
64 ourmesh->nref = 1;
65 ourmesh->ldflags = 0;
66 ourmesh->mcube.cutree = EMPTY;
67 ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = FHUGE;
68 ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = -FHUGE;
69 meshbounds[0][0] = meshbounds[0][1] = meshbounds[0][2] = FHUGE;
70 meshbounds[1][0] = meshbounds[1][1] = meshbounds[1][2] = -FHUGE;
71 return(ourmesh);
72 nomem:
73 error(SYSTEM, "out of memory in cvinit");
74 return(NULL);
75 }
76
77
78 static void
79 add2bounds( /* add point and uv coordinate to bounds */
80 FVECT vp,
81 RREAL vc[2]
82 )
83 {
84 register int j;
85
86 for (j = 3; j--; ) {
87 if (vp[j] < meshbounds[0][j])
88 meshbounds[0][j] = vp[j];
89 if (vp[j] > meshbounds[1][j])
90 meshbounds[1][j] = vp[j];
91 }
92 if (vc == NULL)
93 return;
94 for (j = 2; j--; ) {
95 if (vc[j] < ourmesh->uvlim[0][j])
96 ourmesh->uvlim[0][j] = vc[j];
97 if (vc[j] > ourmesh->uvlim[1][j])
98 ourmesh->uvlim[1][j] = vc[j];
99 }
100 }
101
102
103 int /* create an extended triangle */
104 cvtri(
105 OBJECT mo,
106 FVECT vp1,
107 FVECT vp2,
108 FVECT vp3,
109 FVECT vn1,
110 FVECT vn2,
111 FVECT vn3,
112 RREAL vc1[2],
113 RREAL vc2[2],
114 RREAL vc3[2]
115 )
116 {
117 static OBJECT fobj = OVOID;
118 char buf[32];
119 int flags;
120 TRIDATA *ts;
121 FACE *f;
122 OBJREC *fop;
123 int j;
124
125 flags = MT_V; /* check what we have */
126 if (vn1 != NULL && vn2 != NULL && vn3 != NULL) {
127 RREAL *rp;
128 switch (flat_tri(vp1, vp2, vp3, vn1, vn2, vn3)) {
129 case ISBENT:
130 flags |= MT_N;
131 /* fall through */
132 case ISFLAT:
133 break;
134 case RVBENT:
135 flags |= MT_N;
136 rp = vn1; vn1 = vn3; vn3 = rp;
137 /* fall through */
138 case RVFLAT:
139 rp = vp1; vp1 = vp3; vp3 = rp;
140 rp = vc1; vc1 = vc3; vc3 = rp;
141 break;
142 case DEGEN:
143 error(WARNING, "degenerate triangle");
144 return(0);
145 default:
146 error(INTERNAL, "bad return from flat_tri()");
147 }
148 }
149 if (vc1 != NULL && vc2 != NULL && vc3 != NULL)
150 flags |= MT_UV;
151 if (fobj == OVOID) { /* create new triangle object */
152 fobj = newobject();
153 if (fobj == OVOID)
154 goto nomem;
155 fop = objptr(fobj);
156 fop->omod = mo;
157 fop->otype = OBJ_FACE;
158 sprintf(buf, "t%ld", (long)fobj);
159 fop->oname = savqstr(buf);
160 fop->oargs.nfargs = 9;
161 fop->oargs.farg = (RREAL *)malloc(9*sizeof(RREAL));
162 if (fop->oargs.farg == NULL)
163 goto nomem;
164 } else { /* else reuse failed one */
165 fop = objptr(fobj);
166 if (fop->otype != OBJ_FACE || fop->oargs.nfargs != 9)
167 error(CONSISTENCY, "code error 1 in cvtri");
168 }
169 for (j = 3; j--; ) {
170 fop->oargs.farg[j] = vp1[j];
171 fop->oargs.farg[3+j] = vp2[j];
172 fop->oargs.farg[6+j] = vp3[j];
173 }
174 /* create face record */
175 f = getface(fop);
176 if (f->area == 0.) {
177 free_os(fop);
178 return(0);
179 }
180 if (fop->os != (char *)f)
181 error(CONSISTENCY, "code error 2 in cvtri");
182 /* follow with auxliary data */
183 f = (FACE *)realloc((void *)f, sizeof(FACE)+tdsize(flags));
184 if (f == NULL)
185 goto nomem;
186 fop->os = (char *)f;
187 ts = (TRIDATA *)(f+1);
188 ts->fl = flags;
189 ts->obj = OVOID;
190 if (flags & MT_N)
191 for (j = 3; j--; ) {
192 ts->vn[0][j] = vn1[j];
193 ts->vn[1][j] = vn2[j];
194 ts->vn[2][j] = vn3[j];
195 }
196 if (flags & MT_UV)
197 for (j = 2; j--; ) {
198 ts->vc[0][j] = vc1[j];
199 ts->vc[1][j] = vc2[j];
200 ts->vc[2][j] = vc3[j];
201 }
202 else
203 vc1 = vc2 = vc3 = NULL;
204 /* update bounds */
205 add2bounds(vp1, vc1);
206 add2bounds(vp2, vc2);
207 add2bounds(vp3, vc3);
208 fobj = OVOID; /* we used this one */
209 return(1);
210 nomem:
211 error(SYSTEM, "out of memory in cvtri");
212 return(0);
213 }
214
215
216 static OBJECT
217 cvmeshtri( /* add an extended triangle to our mesh */
218 OBJECT obj
219 )
220 {
221 OBJREC *o = objptr(obj);
222 TRIDATA *ts;
223 MESHVERT vert[3];
224 int i, j;
225
226 if (o->otype != OBJ_FACE)
227 error(CONSISTENCY, "non-face in mesh");
228 if (o->oargs.nfargs != 9)
229 error(CONSISTENCY, "non-triangle in mesh");
230 if (o->os == NULL)
231 error(CONSISTENCY, "missing face record in cvmeshtri");
232 ts = (TRIDATA *)((FACE *)o->os + 1);
233 if (ts->obj != OVOID) /* already added? */
234 return(ts->obj);
235 vert[0].fl = vert[1].fl = vert[2].fl = ts->fl;
236 for (i = 3; i--; )
237 for (j = 3; j--; )
238 vert[i].v[j] = o->oargs.farg[3*i+j];
239 if (ts->fl & MT_N)
240 for (i = 3; i--; )
241 for (j = 3; j--; )
242 vert[i].n[j] = ts->vn[i][j];
243 if (ts->fl & MT_UV)
244 for (i = 3; i--; )
245 for (j = 2; j--; )
246 vert[i].uv[j] = ts->vc[i][j];
247 ts->obj = addmeshtri(ourmesh, vert, o->omod);
248 if (ts->obj == OVOID)
249 error(INTERNAL, "addmeshtri failed");
250 return(ts->obj);
251 }
252
253
254 void
255 cvmeshbounds(void) /* set mesh boundaries */
256 {
257 int i;
258
259 if (ourmesh == NULL)
260 return;
261 /* fix coordinate bounds */
262 for (i = 0; i < 3; i++) {
263 if (meshbounds[0][i] > meshbounds[1][i])
264 error(USER, "no polygons in mesh");
265 meshbounds[0][i] -= OMARGIN;
266 meshbounds[1][i] += OMARGIN;
267 if (meshbounds[1][i]-meshbounds[0][i] > ourmesh->mcube.cusize)
268 ourmesh->mcube.cusize = meshbounds[1][i] -
269 meshbounds[0][i];
270 }
271 for (i = 0; i < 3; i++)
272 ourmesh->mcube.cuorg[i] = (meshbounds[1][i]+meshbounds[0][i] -
273 ourmesh->mcube.cusize)*.5;
274 if (ourmesh->uvlim[0][0] > ourmesh->uvlim[1][0]) {
275 ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = 0.;
276 ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = 0.;
277 } else {
278 for (i = 0; i < 2; i++) {
279 double marg; /* expand past endpoints */
280 marg = (2./(1L<<(8*sizeof(uint16)))) *
281 (ourmesh->uvlim[1][i] -
282 ourmesh->uvlim[0][i]) + FTINY;
283 ourmesh->uvlim[0][i] -= marg;
284 ourmesh->uvlim[1][i] += marg;
285 }
286 }
287 ourmesh->ldflags |= IO_BOUNDS;
288 }
289
290
291 static OCTREE
292 cvmeshoct( /* convert triangles in subtree */
293 OCTREE ot
294 )
295 {
296 int i;
297
298 if (isempty(ot))
299 return(EMPTY);
300
301 if (isfull(ot)) {
302 OBJECT oset1[MAXSET+1];
303 OBJECT oset2[MAXSET+1];
304 objset(oset1, ot);
305 oset2[0] = 0;
306 for (i = oset1[0]; i > 0; i--)
307 insertelem(oset2, cvmeshtri(oset1[i]));
308 return(fullnode(oset2));
309 }
310
311 for (i = 8; i--; )
312 octkid(ot, i) = cvmeshoct(octkid(ot, i));
313 return(ot);
314 }
315
316
317 MESH *
318 cvmesh(void) /* convert mesh and octree leaf nodes */
319 {
320 if (ourmesh == NULL)
321 return(NULL);
322 /* convert triangles in octree nodes */
323 ourmesh->mcube.cutree = cvmeshoct(ourmesh->mcube.cutree);
324 ourmesh->ldflags |= IO_SCENE|IO_TREE;
325
326 return(ourmesh);
327 }