1 /* Copyright (C) 1992-1998 The Geometry Center
2 * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3 *
4 * This file is part of Geomview.
5 *
6 * Geomview is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * Geomview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Geomview; see the file COPYING. If not, write
18 * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
19 * USA, or visit http://www.gnu.org.
20 */
21
22 #if 0
23 static char copyright[] = "Copyright (C) 1992-1998 The Geometry Center\n\
24 Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips";
25 #endif
26
27 /* OOGL to VRML converter
28 * by Tamara Munzner
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include "geom.h"
34 #include "transform.h"
35 #include "polylistP.h"
36 #include "vectP.h"
37 #include "sphere.h"
38 #include "commentP.h"
39 #include "plutil.h"
40
41 #ifdef DEBUG
42 # undef DEBUG
43 # define DEBUG(expr) (expr)
44 #else
45 # define DEBUG(expr) /*nothing*/
46 #endif
47
48 FILE *f = NULL;
49 Appearance *ap = NULL;
50 int bezdice = 0;
51
52 struct linkap {
53 Appearance *ap;
54 struct linkap *prev;
55 };
56
57 struct linkap *toplap;
58
59 void
faceindex(PolyList * plist)60 faceindex(PolyList *plist) {
61 int i,j;
62 Poly *pl = NULL;
63 Vertex *base = plist->vl;
64 for (i = 0, pl = plist->p; i < plist->n_polys; i++, pl++) {
65 for (j = 0; j < pl->n_vertices; j++) {
66 fprintf(f, " %d, ", (int) (pl->v[j]-base) );
67 }
68 fprintf(f, " -1,\n ");
69 }
70 }
71
72 void
plisttoindface(Geom * pgeom)73 plisttoindface(Geom *pgeom)
74 {
75 PolyList *plist = (PolyList *)pgeom;
76 Poly *pl = NULL;
77 Vertex *v = NULL;
78 int i;
79 int shading = toplap->ap->shading;
80
81 /* Vertices */
82 fprintf(f, " Coordinate3 { point [\n");
83 for (i = 0, v = plist->vl; i < plist->n_verts; i++, v++) {
84 fprintf(f, " %g %g %g, ", v->pt.x, v->pt.y, v->pt.z);
85 }
86 fprintf(f, "] } \n");
87
88 /* Normals */
89 if (shading == APF_FLAT) {
90 PolyListComputeNormals(plist, PL_HASPN);
91 fprintf(f, "NormalBinding { value PER_FACE }\n");
92 DEBUG(fprintf(stderr, " per face normals! \n"));
93 fprintf(f, " Normal { vector [ ");
94 for (i = 0, pl= plist->p; i < plist->n_polys; i++, pl++) {
95 fprintf(f, " %g %g %g, ", pl->pn.x, pl->pn.y, pl->pn.z);
96 }
97 fprintf(f, "] }\n");
98 } else if (shading == APF_SMOOTH) {
99 PolyListComputeNormals(plist, PL_HASVN);
100 fprintf(f, "NormalBinding { value PER_VERTEX_INDEXED }\n");
101 DEBUG(fprintf(stderr, " per vertex normals! \n"));
102 fprintf(f, " Normal { vector [ ");
103 for (i = 0, v = plist->vl; i < plist->n_verts; i++, v++) {
104 fprintf(f, " %g %g %g, ", v->vn.x, v->vn.y, v->vn.z);
105 }
106 fprintf(f, "] }\n");
107 }
108
109 /* Colors */
110 if (plist->geomflags & PL_HASVCOL && plist->geomflags & PL_HASPCOL) {
111 if (shading == APF_FLAT) { plist->geomflags &= ~PL_HASVCOL; }
112 else { plist->geomflags &= ~PL_HASPCOL; }
113 }
114 /* Appearance diffuse color overrides object colors */
115
116 /* We don't rely on the override bit, since Geomview never sets it
117 when saving files.
118 */
119
120 if (toplap->ap->mat && toplap->ap->mat->valid & MTF_DIFFUSE) {
121 plist->geomflags &= ~(PL_HASPCOL|PL_HASVCOL);
122 }
123
124 if (plist->geomflags & PL_HASPCOL) {
125 fprintf(f, "MaterialBinding { value PER_FACE }\n");
126 fprintf(f, " Material { diffuseColor [ ");
127 for (i = 0, pl= plist->p; i < plist->n_polys; i++, pl++) {
128 fprintf(f, " %g %g %g, ", pl->pcol.r, pl->pcol.g, pl->pcol.b);
129 }
130 fprintf(f, "] }\n");
131 } else if (plist->geomflags & PL_HASVCOL) {
132 fprintf(f, "MaterialBinding { value PER_VERTEX_INDEXED }\n");
133 fprintf(f, " Material { diffuseColor [ ");
134 for (i = 0, v = plist->vl; i < plist->n_verts; i++, v++) {
135 fprintf(f, " %g %g %g, ", v->vcol.r, v->vcol.g, v->vcol.b);
136 }
137 fprintf(f, "] }\n");
138 } else if (toplap->ap->mat && toplap->ap->mat->valid & MTF_DIFFUSE) {
139 /* reset color to backstop */
140 fprintf(f, "Material { diffuseColor [ %g %g %g ] } ",
141 toplap->ap->mat->diffuse.r, toplap->ap->mat->diffuse.g,
142 toplap->ap->mat->diffuse.b);
143 }
144
145 /* Connectivity */
146 /* wish we could DEF fields not just nodes, then wouldn't
147 waste bandwidth with 3 chunks of identical numbers */
148 fprintf(f," IndexedFaceSet {\n ");
149 fprintf(f, " coordIndex [ \n");
150 faceindex(plist);
151 fprintf(f, " ] # end coordIndex \n ");
152 if (shading != APF_FLAT) {
153 fprintf(f, " normalIndex [ \n");
154 faceindex(plist);
155 fprintf(f, " ] # end normalIndex \n ");
156 if (plist->geomflags & PL_HASVCOL) {
157 fprintf(f, " materialIndex [ \n");
158 faceindex(plist);
159 fprintf(f, " ] # end materialIndex \n ");
160 }
161 }
162 fprintf(f, " } # end IndexedFaceSet \n ");
163 }
164
lineindex(Vect * pline)165 void lineindex(Vect *pline)
166 {
167 int i,j;
168 int n = 0;
169 for (i = 0; i < pline->nvec; i++) {
170 for (j = 0; j < pline->vnvert[i]; j++) {
171 fprintf(f, " %d, ", n++);
172 }
173 fprintf(f, " -1,\n ");
174 }
175 }
176
177 void
plinetoindline(Geom * pgeom)178 plinetoindline(Geom *pgeom)
179 {
180 Vect *pline = (Vect *)pgeom;
181 HPoint3 *v = NULL;
182 int i, j, n;
183
184 /* Vertices */
185 fprintf(f, " Coordinate3 { point [\n");
186 for (i = 0, v = pline->p; i < pline->nvert; i++, v++) {
187 fprintf(f, " %g %g %g, ", v->x, v->y, v->z);
188 }
189 fprintf(f, "] } \n");
190
191
192 /* Colors */
193 if (toplap->ap->mat && toplap->ap->mat->valid & MTF_EDGECOLOR)
194 pline->ncolor = 0;
195 if (pline->ncolor >= 1) {
196 if (pline->ncolor > 1)
197 fprintf(f, " MaterialBinding { value PER_VERTEX_INDEXED } ");
198 fprintf(f, " Material { diffuseColor [ ");
199 for (i = 0; i < pline->ncolor; i++) {
200 fprintf(f, " %g %g %g, ", pline->c[i].r, pline->c[i].g, pline->c[i].b);
201 }
202 fprintf(f, "] }\n");
203 } else if (toplap->ap && toplap->ap->mat &&
204 toplap->ap->mat->valid & MTF_EDGECOLOR) {
205 fprintf(f, " Material { diffuseColor [ %g %g %g ] }\n",
206 toplap->ap->mat->edgecolor.r, toplap->ap->mat->edgecolor.g,
207 toplap->ap->mat->edgecolor.b);
208 }
209
210 /* Connectivity */
211 fprintf(f," IndexedLineSet {\n ");
212 fprintf(f, " coordIndex [ \n");
213 lineindex(pline);
214 fprintf(f, " ] # end coordIndex \n ");
215 /* appearance edgecolor overrides per-vertex colors */
216 if (pline->ncolor > 1) {
217 fprintf(f, " materialIndex [\n");
218 n = -1;
219 for (i = 0; i < pline->nvec; i++) {
220 if (pline->vncolor[i] == 1) n++;
221 for (j = 0; j < pline->vnvert[i]; j++) {
222 fprintf(f, " %d, ", n);
223 if (pline->vncolor[i] > 1) n++;
224 }
225 fprintf(f, " -1,\n ");
226 }
227 fprintf(f, " ] # end materialIndex \n ");
228 }
229 fprintf(f, " } # end IndexedLineSet \n ");
230 }
231
printxform(Transform T)232 void printxform(Transform T)
233 {
234 if (T && memcmp(T, TM_IDENTITY, sizeof(Transform)) != 0) {
235 fprintf(f, " MatrixTransform { matrix \n");
236 fputtransform(f, 1, &T[0][0], 0);
237 fprintf(f, " } \n");
238 }
239 }
240
doap(Appearance * a)241 void doap(Appearance *a)
242 {
243 if (a->mat && a->mat->valid) {
244 Material *m = a->mat;
245 float ka, kd, ks;
246 ka = (m->valid & MTF_Ka) ? m->ka : 1.0;
247 kd = (m->valid & MTF_Kd) ? m->kd : 1.0;
248 ks = (m->valid & MTF_Ks) ? m->ks : 1.0;
249 fprintf(f, "Material { ");
250 if (m->valid & MTF_EMISSION)
251 fprintf(f, "emissiveColor %g %g %g \n",
252 m->emission.r, m->emission.g, m->emission.b);
253 if (m->valid & MTF_AMBIENT)
254 fprintf(f, "ambientColor %g %g %g \n",
255 ka*m->ambient.r, ka*m->ambient.g, ka*m->ambient.b);
256 if (m->valid & MTF_DIFFUSE)
257 fprintf(f, "diffuseColor %g %g %g \n",
258 kd*m->diffuse.r, kd*m->diffuse.g, kd*m->diffuse.b);
259 if (m->valid & MTF_SPECULAR)
260 fprintf(f, "specularColor %g %g %g \n",
261 ks*m->specular.r, ks*m->specular.g, ks*m->specular.b);
262 if (m->valid & MTF_SHININESS)
263 fprintf(f, "shininess %g ", m->shininess);
264 if (m->valid & MTF_ALPHA)
265 fprintf(f, "transparency %g ", 1.0 - m->diffuse.a);
266 fprintf(f, "} #end Material \n");
267 }
268 if (a->lighting) {
269 LtLight **lp, *l;
270 int i;
271 LM_FOR_ALL_LIGHTS(a->lighting, i,lp) {
272 l = *lp;
273 fprintf(f, "PointLight { on TRUE ");
274 fprintf(f, "color %g %g %g ",
275 l->color.r * l->intensity,
276 l->color.g * l->intensity,
277 l->color.b * l->intensity);
278 fprintf(f, "location %g %g %g }\n",
279 l->position.x,l->position.y,l->position.z);
280 }
281 }
282 }
283
284 void
pushap(Appearance * nap)285 pushap(Appearance *nap)
286 {
287 struct linkap *newlap = (struct linkap *) malloc(1 * sizeof(struct linkap));
288 newlap->ap = NULL;
289 newlap->ap = ApCopy(nap, newlap->ap);
290 newlap->prev = toplap;
291 toplap = newlap;
292 }
293
294 void
popap()295 popap()
296 {
297 struct linkap *oldlap = toplap;
298 toplap = oldlap->prev;
299 ApDelete(oldlap->ap);
300 free(oldlap);
301 }
302
303 static void
traverse(Geom * where)304 traverse(Geom *where)
305 {
306 Geom *new = NULL;
307 Geom *tlist = NULL;
308 Appearance *a, *nap = NULL;
309 Transform T;
310 char usename[16];
311 char *name = NULL;
312 static int unique = -1;
313
314 if (!where) return;
315
316 /* Appearances: We need certain values for our own internal use
317 (shading, diffuse material) so we have to keep a stack of
318 appearances around. But we refrain from printing out the entire
319 contents of the appearance on top of the stack at every level to
320 save both cycles and bandwidth. So we just print out new
321 appearances in doap, secure that Separator nodes will isolate
322 their effects. */
323 GeomGet(where, CR_APPEAR, &a);
324 if (a) {
325 fprintf(f, "Separator {\n");
326 doap(a);
327 nap = ApMerge(a, toplap->ap, 0);
328 pushap(nap);
329 }
330
331 name = GeomName(where);
332 if (!strcmp(name, "polylist")) {
333
334 /* Might have internal Materials, isolate with Separator */
335 fprintf(f, "Separator {\n");
336 plisttoindface(where);
337 fprintf(f, " } # end Separator \n");
338
339
340 } else if (!strcmp(name, "vect")) {
341
342 /* Might have internal Materials, isolate with Separator */
343 fprintf(f, "Separator {\n");
344 plinetoindline(where);
345 fprintf(f, " } # end Separator \n");
346
347 } else if (!strcmp(name, "sphere")) {
348 fprintf(f, " Sphere { radius %g }\n", SphereRadius( (Sphere *)where));
349
350 } else if (!strcmp(name, "comment")) {
351 if (!strcmp(((Comment *)where)->type, "WWWInline")) {
352 fprintf(f, "WWWInline { name \"%s\" bboxSize 0 0 0 bboxCenter 0 0 0 }\n",
353 ((Comment *)where)->data);
354
355 } else if (!strcmp(((Comment *)where)->type, "HREF")) {
356 /* no-op. we've already dealt with it at level of its
357 list or inst parent. */
358 }
359
360 } else if (!strcmp(name, "list")) {
361 /* must lookahead due to fundamental structural difference
362 between weboogl and vrml:
363 in weboogl, anchors affect siblings and parent.
364 in vrml, anchors affect children.
365 immediate child might be HREF comment,
366 in which case we need to write out a WWWAnchor node up here
367 not down inside of list when we would normally come across it.
368 */
369 Geom *child = NULL;
370 char *newname;
371 int anchor = 0;
372 new = where;
373 while(new) {
374 GeomGet(new, CR_CAR, &child);
375 newname = GeomName(child);
376 if (newname && !strcmp(newname, "comment") &&
377 !strcmp( ((Comment *)child)->type, "HREF")) {
378 fprintf(f, "WWWAnchor { name \"%s\"\n", ((Comment *)child)->data);
379 anchor = 1;
380 }
381 GeomGet(new, CR_CDR, &child);
382 new = child;
383 }
384
385 /* done with lookahead, now really go through the list */
386 new = where;
387 while(new) {
388 GeomGet(new, CR_CAR, &child);
389 traverse(child);
390 GeomGet(new, CR_CDR, &child);
391 new = child;
392 }
393 if (anchor) fprintf(f, " } # end WWWAnchor \n");
394
395 } else if (!strcmp(name, "inst")) {
396 GeomGet(where, CR_GEOM, &new);
397 if (!new) return;
398 GeomGet(where, CR_TLIST, &tlist);
399 if (!tlist) {
400
401 /* a single xform */
402 fprintf(f, "Separator { \n");
403 GeomGet(where, CR_AXIS, &T);
404 printxform(T);
405 traverse(new);
406 fprintf(f, "} #end Separator\n");
407
408 } else {
409
410 /* multiple xforms
411 We'll DEF the geometry for multiple USEs, but
412 we must output the first xform before DEFing the geometry.
413 NextTransform loops through the list of xforms, after the
414 cryptic but crucial set-up call to GeomIterate.
415 */
416
417 GeomIter *it = GeomIterate( (Geom *)tlist, DEEP );
418 NextTransform( it, T );
419 fprintf(f, "Separator { \n");
420 printxform(T);
421 sprintf(usename, "instgeom%d", ++unique);
422 fprintf(f, " DEF %s Separator { ", usename);
423 traverse(new);
424 fprintf(f, " } #end DEF \n } #end Separator \n");
425
426 while(NextTransform( it, T )) {
427 fprintf(f, "Separator { \n");
428 printxform(T);
429 fprintf(f, " USE %s\n } #end Separator \n", usename);
430 }
431 }
432
433 } else {
434 if ((!strcmp(name, "bezier") || !strcmp(name, "bezierlist")) && bezdice)
435 GeomDice(where, bezdice, bezdice);
436 /* Convert to all other geometric primitives to OFF. */
437 new = AnyToPL(where, TM_IDENTITY);
438 /* Might have internal Materials, isolate with Separator */
439 fprintf(f, "Separator { \n");
440 plisttoindface(new);
441 fprintf(f, " } # end Separator \n");
442 }
443
444 if (a) {
445 fprintf(f, " } # end Separator \n");
446 popap();
447 }
448 }
449
450
main(int argc,char * argv[])451 int main(int argc, char *argv[])
452 {
453 Geom *g;
454 int flat = 1;
455
456 f = stdout;
457
458 while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
459 if (argv[1][1] == 'b') {
460 bezdice = atoi(argv[2]); argc--; argv++;
461 } else if (argv[1][1] == 's') {
462 flat = 0;
463 }
464 argc--; argv++;
465 }
466
467 if(argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
468 fprintf(stderr, "\
469 Usage: %s [filename] -- convert OOGL file to VRML format\n\
470 Writes to standard output. Reads from stdin if no file specified.\n",
471 argv[0]);
472 exit(1);
473 }
474 pushap(ApCreate(AP_SHADING, flat ? APF_FLAT : APF_SMOOTH, AP_END));
475 if(argc <= 1) {
476 argv[1] = "-";
477 }
478 g = strcmp(argv[1], "-") ?
479 GeomLoad(argv[1]) : GeomFLoad(iobfileopen(stdin), "standard input");
480 fprintf(f, "#VRML V1.0 ascii\n");
481 fprintf(f, "Separator {\n");
482 fprintf(f, " ShapeHints {vertexOrdering COUNTERCLOCKWISE faceType CONVEX}\n");
483 traverse(g);
484 fprintf(f, "} # end final Separator\n");
485
486 return 0;
487 }
488