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