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 # include "config.h"
28
29 /* math2oogl: convert Mathematica graphics object to OOGL format.
30 SurfaceGraphics and MeshGraphics => MESH, Graphics3D => OFF,
31 BezierPatch => BEZuvn.
32
33 Note that we expect the graphics objects to have been processed as
34 in OOGL.m, i.e. provide dimension and meshrange information and
35 print out the colors before the points for SurfaceGraphics objects,
36 and convert the characters "(){}, " to a newline.
37
38 Original converter by Nils McCarthy,
39 Geomview pipefitting by Stuart Levy
40 SurfaceGraphics converter additions by Tamara Munzner.
41 MeshGraphics and BezierPatch converter additions by Silvio Levy
42 */
43
44
45
46 /*
47 * Pipe fitting for linking Mathematica to geomview.
48 * Starts geomview if not already running.
49 */
50
51
52 #include <stdio.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #if defined(unix) || defined(__unix) || defined(__unix__)
56 #include <signal.h>
57 #include <sys/file.h>
58 #include <sys/socket.h>
59 #include <sys/un.h>
60 #endif
61 #include <sys/errno.h>
62 #include <string.h>
63 #include <stdlib.h>
64 #include <ctype.h>
65
66 #ifdef AIX
67 #define _BSD 1 /* Get FNDELAY from <fcntl.h> */
68 #endif
69 #include <fcntl.h>
70
71 #ifdef NeXT
72 #include <bsd/libc.h>
73 #else /* any other reasonable unix */
74 #include <unistd.h>
75 #endif
76
77 #ifdef SVR4 /* What should this be called? */
78 #include <sys/systeminfo.h>
79 #endif
80
81 #ifndef FNDELAY
82 # define FNDELAY O_NDELAY
83 #endif
84
85 #ifndef FNONBLK /* Next 3.0 lacks these in <sys/fcntl.h> */
86 # define FNONBLK FNDELAY
87 #endif
88
89 #ifndef O_NONBLOCK
90 # define O_NONBLOCK FNONBLK
91 #endif
92
93 #ifndef FD_CLOEXEC
94 #define FD_CLOEXEC 1
95 #endif
96
97 extern int errno;
98
99 char *todir = "/tmp/geomview";
100 char *toname = "Mathematica";
101
102 char giveup[] = "Geomview graphics: math2oogl: Couldn't start geomview on ";
103
104 /* Fool some Linux distros which are too eager to improve the quality
105 * of source code and turn on FORTIFY_SOURCE by default for the
106 * C-compiler gcc.
107 */
ign_write(int fd,void * buffer,size_t size)108 static int ign_write(int fd, void *buffer, size_t size)
109 {
110 return write(fd, buffer, size);
111 }
112
ign_dup(int fd)113 static int ign_dup(int fd)
114 {
115 return dup(fd);
116 }
117
interrupt(int sig)118 static void interrupt(int sig) {
119 char myname[1024];
120 ign_write(2, giveup, sizeof(giveup));
121
122 #ifdef SVR4
123 /* jkirk@keck.tamu.edu reports no gethostname() in Solaris (SVR4).
124 * Use sysinfo() instead.
125 */
126 sysinfo(SI_HOSTNAME, myname, sizeof(myname));
127 #else
128 gethostname(myname, sizeof(myname));
129 #endif
130
131 ign_write(2, myname, strlen(myname));
132 ign_write(2, "\n", 1);
133 exit(1);
134 }
135
start_gv(char ** gvpath,char * pipename,char * toname)136 void start_gv(char **gvpath, char *pipename, char *toname)
137 {
138 char *args[1024];
139 int i = 0;
140 char **gvp;
141
142 signal(SIGALRM, interrupt);
143 args[i++] = gvpath[0];
144
145 #ifdef NeXT
146 args[i++] = "-Mc"; args[i++] = toname;
147 #else /* sgi */
148 args[i++] = "-c"; args[i++] = pipename;
149 #endif
150 /* Copy remaining args through trailing NULL */
151 for(gvp = gvpath; (args[i++] = *++gvp); )
152 ;
153
154 if(fork() == 0) {
155 int savederr = dup(2);
156 static char whynot[] = "Geomview graphics: math2oogl: Couldn't find ";
157
158 fcntl(savederr, F_SETFD, FD_CLOEXEC); /* close this on exec */
159 close(0); close(1); close(2);
160
161
162 open("/dev/null", O_RDWR); /* Open /dev/null as file descriptors */
163 ign_dup(0); ign_dup(0); /* 0(stdin), 1(stdout) and 2(stderr) */
164 /* (Could just close them, but that seems to poison geomview
165 * if it tries to report an error.)
166 */
167
168 #if SETPGRP_VOID
169 setpgrp();
170 #else
171 setpgrp(0,getpid());
172 #endif
173 execvp(gvpath[0], &args[0]);
174 ign_write(savederr, whynot, sizeof(whynot));
175 ign_write(savederr, gvpath[0], strlen(gvpath[0]));
176 ign_write(savederr, "\n", 1);
177 execvp("geomview", &args[0]);
178 execvp("gv", &args[0]);
179
180 dup2(savederr, 2);
181 kill(getppid(), SIGALRM);
182 interrupt(0);
183 _exit(1);
184 }
185 }
186
startgv(char ** gvpath)187 void startgv(char **gvpath)
188 {
189 int usesock;
190 int n, fd = -1;
191 char pipename[BUFSIZ];
192 struct sockaddr_un un;
193
194 if(access(todir, W_OK) < 0) {
195 mkdir(todir, 0777);
196 chmod(todir, 0777);
197 }
198 sprintf(pipename, "%s/%s", todir, toname);
199
200 #ifdef NeXT
201 usesock = 1;
202 #else
203 usesock = 0;
204 #endif
205
206 if(usesock) {
207 strncpy(un.sun_path, pipename, sizeof(un.sun_path)-1);
208 un.sun_family = AF_UNIX;
209 fd = socket(PF_UNIX, SOCK_STREAM, 0);
210 if(connect(fd, (struct sockaddr *)(&un), sizeof(un)) < 0) {
211 if(errno != ECONNREFUSED && errno != ENOENT) {
212 fprintf(stderr, "togeomview: Can't connect to ");
213 perror(pipename);
214 exit(1);
215 }
216
217 start_gv(gvpath, pipename, toname);
218 for(n = 0; connect(fd, (struct sockaddr *)(&un), sizeof(un)) < 0; n++) {
219 if(n == 60)
220 interrupt(0);
221 sleep(1);
222 }
223 }
224 } else {
225 /* Use named pipe */
226 if(access(pipename, 0) < 0) {
227 mknod(pipename, S_IFIFO, 0);
228 chmod(pipename, 0666);
229 }
230 fd = open(pipename, O_WRONLY|O_NONBLOCK);
231 if(fd >= 0) {
232 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~(FNDELAY|FNONBLK|O_NONBLOCK));
233 } else if(errno == ENXIO) {
234 start_gv(gvpath, pipename, toname);
235 alarm(60);
236 fd = open(pipename, O_WRONLY);
237 alarm(0);
238 }
239 }
240 if(fd < 0) {
241 fprintf(stderr, "Can't open pipe to geomview: ");
242 perror(pipename);
243 exit(1);
244 }
245
246 /* Now stdout writes to pipe. */
247 dup2(fd, 1);
248 }
249
250
251 /*
252 * Mathematica->OOGL conversion
253 */
254
255 typedef float Color[3];
256
257 #define ismajor isupper
258
259 /*
260 * The following table should always obey the convention that "major"
261 * tokens (corresponding to the cases in the big switch below)
262 * are represented by capitals
263 */
264
265 enum st {
266 IGNORE='i',
267 POLYGON='p',
268 LINE='l',
269 COLOR='c',
270 NUMBER='n',
271 MESH='m',
272 MESHRANGE='k',
273 DIMENSIONS='d',
274 SG='S',
275 MG='M',
276 G3='G',
277 BG='B'
278 };
279
280 struct line {
281 char *data;
282 enum st token;
283 struct line *next;
284 };
285
286 struct line *lines=NULL;
287 int size[2];
288 float range[4];
289
usage()290 void usage()
291 {
292 fprintf(stderr,"Usage: math2oogl [-togeomview <objectname>]");
293 exit(1);
294 }
295
main(int ac,char ** av)296 int main(int ac,char **av)
297 {
298 int togv = 0;
299 struct line *lastline=NULL;
300 struct line *prev=NULL;
301 char buf[1024];
302 int npolypoints=0, npolys=0, npolycolors=0;
303 int nvectpoints=0, nvects=0, nvectcolors=0;
304 struct line *curline, *globline;
305 int numnums=0;
306 int numcols=0;
307 enum st state=IGNORE;
308 Color **colors = NULL;
309 int i,j,q,ok;
310 float xincr, yincr;
311 int complex = 0, toss = 0;
312
313 if (ac >= 4 && (!strcmp(av[1],"-togeomview"))) {
314 startgv(&av[3]);
315 printf("(geometry %s\n", av[2]);
316 togv=1;
317 } else if (ac > 1) usage();
318
319 for(;;) {
320 int c;
321 char *k;
322 /* Swallow all delimiters, " (){},\n\r".
323 * It's not strictly correct to ignore {} nesting, but...
324 */
325 for(k = buf; (c = getchar()) > ' ' && c != ',' && c != '(' && c != ')'
326 && c != '{' && c != '}' && k < buf+sizeof(buf)-1;
327 k++) {
328 /* Handle escaped newlines, which Mathematica inserts just rarely
329 * enough to be hard to notice!
330 */
331 if(c == '\\') {
332 if((c = getchar()) == '\n') {
333 while((c = getchar()) == ' ' || c == '\t')
334 ;
335 }
336 }
337 *k = c;
338 }
339 if(c == EOF)
340 break;
341 *k = '\0';
342 if (k == buf || !strcmp(buf,"List"))
343 continue;
344
345 if (!lastline)
346 lastline = lines = malloc(sizeof(struct line));
347 else {
348 if (toss) lastline = prev;
349 toss = 0;
350 prev = lastline;
351 lastline = lastline->next = malloc (sizeof(struct line));
352 }
353 lastline->next = NULL;
354 lastline->data = malloc(strlen(buf)+1);
355
356 strcpy (lastline->data, buf);
357 if (isalpha(*lastline->data)) {
358 if (!strcmp(lastline->data, "Graphics3D"))
359 lastline->token = G3;
360 else if (!strcmp(lastline->data, "SurfaceGraphics"))
361 lastline->token = SG;
362 else if (!strcmp(lastline->data, "MeshGraphics"))
363 lastline->token = MG;
364 else if (!strcmp(lastline->data, "BezierPatch")||
365 !strcmp(lastline->data, "BezierGraphics`BezierPatch"))
366 lastline->token = BG;
367 else if (!strcmp(lastline->data, "Polygon"))
368 lastline->token = POLYGON;
369 else if (!strcmp(lastline->data, "Point"))
370 lastline->token = LINE; /* degenerate vector */
371 else if (!strcmp(lastline->data, "Line"))
372 lastline->token = LINE;
373 else if (!strcmp(lastline->data, "RGBColor"))
374 lastline->token = COLOR;
375 else if (!strcmp(lastline->data, "MeshRange"))
376 lastline->token = MESHRANGE;
377 else if (!strcmp(lastline->data, "Dimensions"))
378 lastline->token = DIMENSIONS;
379 else if (!strcmp(lastline->data, "Complex")) {
380 lastline->token = IGNORE;
381 complex = 1;
382 toss = 1;
383 } else {
384 lastline->token = IGNORE;
385 }
386 } else if (isdigit(*lastline->data) || '-'==*lastline->data) {
387 lastline->token = NUMBER;
388 /* grab real part, toss imaginary part */
389 if (complex) {
390 if (complex == 1) {
391 complex++;
392 } else if (complex == 2) {
393 lastline->token = IGNORE;
394 complex = 0;
395 toss = 1;
396 }
397 }
398 }
399 }
400
401 /* we might have multiple graphics objects */
402 printf ("{ LIST\n\n");
403
404 ok = 1;
405 globline = lines;
406 for (globline = lines;globline;) {
407 switch (globline->token) {
408 case SG: /* SurfaceGraphics */
409 globline=globline->next;
410 if (globline->token == DIMENSIONS) {
411 globline=globline->next;
412 for (i = 0; i < 2 && ok; i++, globline = globline->next)
413 if (globline->token == NUMBER)
414 size[i] = atoi(globline->data);
415 else ok = 0;
416 } else
417 ok = 0;
418 if (!ok) {
419 fprintf(stderr, "can't read mesh dimensions!\n");
420 return 1;
421 }
422 if (globline->token == MESHRANGE) {
423 globline=globline->next;
424 for (i = 0; i < 4 && ok; i++, globline = globline->next) {
425 if (globline->token == NUMBER)
426 range[i] = atof(globline->data);
427 else ok = 0;
428 }
429 } else ok = 0;
430 if (!ok) {
431 fprintf(stderr, "can't read mesh range!\n");
432 return 1;
433 }
434
435 /*
436 in SurfaceGraphics object, first we get all the colors,
437 then all the points: they're not interleaved as in
438 the Graphics3D object. so we need to store them.
439
440 points array is size[0] x size[1],
441 color array is size[0]-1 x size[1]-1 (per face not per vertex)
442 so repeat the face color for the extra vertices.
443
444 */
445
446 /* if there are colors, store them off */
447 if (globline->token == COLOR) {
448 numcols = (size[0]-1) * (size[1]-1);
449 colors = malloc((size[0]-1)*sizeof(Color*));
450 for (i = 0; i < size[0]-1;i++)
451 colors[i] = malloc((size[1]-1)*sizeof(Color));
452 ok = 1;
453 for (i = 0; i < size[0]-1; i++) {
454 for (j=0; j < size[1]-1; j++) {
455 while (globline->token == COLOR && ok)
456 for (q=0; q < 3 && ok; q++) {
457 globline = globline->next;
458 if (globline->token != NUMBER) {
459 ok = 0;
460 break;
461 } else {
462 colors[i][j][q]=atof(globline->data);
463 }
464 }
465 globline=globline->next;
466 }
467 }
468 if (!ok) {
469 fprintf(stderr, "can't read mesh color array!\n");
470 return 1;
471 }
472 }
473 /* Each number we get is just the z coordinate.
474 Figure out x and y values based on meshrange and size.
475 We don't use a ZMESH because the grid isn't necessarily
476 an array starting at 0,0: it depends on meshrange
477 */
478 xincr = (range[1] - range[0]) / (size[0]-1);
479 yincr = (range[3] - range[2]) / (size[1]-1);
480
481 if (numcols)
482 printf("\n\n{ CMESH \n");
483 else
484 printf("\n\n{ MESH \n");
485 printf("\n%d %d\n",size[0], size[1]);
486 ok = 1;
487 for (i = 0; i < size[0]; i++){
488 for (j = 0; j < size[1]; j++) {
489 if (globline->token!=NUMBER) {
490 ok = 0; break;
491 }
492 printf(" %f ", range[0] + xincr*j); /* x */
493 printf(" %f ", range[2] + yincr*i); /* y */
494 printf(" %s ", globline->data); /* z */
495 /* MESH vertices need RGBA colors
496 since OOGL MESHes have per-vertex colors, repeat some.
497 repeat last i index, first j index.
498 */
499 if (numcols) {
500 printf(" %f %f %f 1\n", colors[i<size[0]-1?i:i-1][j?j-1:0][0],
501 colors[i<size[0]-1?i:i-1][j?j-1:0][1],
502 colors[i<size[0]-1?i:i-1][j?j-1:0][2]);
503 } else printf("\n");
504 globline=globline->next;
505 }
506 }
507 if (!ok) {
508 fprintf(stderr, "can't read mesh points array!\n");
509 return 1;
510 } else
511 printf("} #end of MESH\n");
512 break;
513 case MG: /* MeshGraphics */
514 globline=globline->next;
515 if (globline->token == DIMENSIONS) {
516 globline=globline->next;
517 for (i = 0; i < 2 && ok; i++, globline = globline->next)
518 if (globline->token == NUMBER)
519 size[i] = atoi(globline->data);
520 else ok = 0;
521 } else
522 ok = 0;
523 if (!ok) {
524 fprintf(stderr, "can't read mesh dimensions!\n");
525 return 1;
526 }
527
528 /*
529 in MeshGraphics object, first we get all the colors,
530 then all the points: they're not interleaved as in
531 the Graphics3D object. so we need to store them.
532
533 points array is size[0] x size[1],
534 color array is size[0]-1 x size[1]-1 (per face not per vertex)
535 so repeat the face color for the extra vertices.
536
537 */
538
539 /* if there are colors, store them off */
540 if (globline->token == COLOR) {
541 numcols = (size[0]-1) * (size[1]-1);
542 colors = malloc((size[0]-1)*sizeof(Color*));
543 for (i = 0; i < size[0]-1;i++)
544 colors[i] = malloc((size[1]-1)*sizeof(Color));
545 ok = 1;
546 for (i = 0; i < size[0]-1; i++) {
547 for (j=0; j < size[1]-1; j++) {
548 while (globline->token == COLOR && ok)
549 for (q=0; q < 3 && ok; q++) {
550 globline = globline->next;
551 if (globline->token != NUMBER) {
552 ok = 0;
553 break;
554 } else {
555 colors[i][j][q]=atof(globline->data);
556 }
557 }
558 globline=globline->next;
559 }
560 }
561 if (!ok) {
562 fprintf(stderr, "can't read mesh color array!\n");
563 return 1;
564 }
565 }
566 /* Each number we get is just the x,y or z coordinate.
567 We don't use a ZMESH because the grid isn't necessarily
568 an array starting at 0,0: it depends on meshrange
569 */
570
571 if (numcols)
572 printf("\n\n{ CMESH \n");
573 else
574 printf("\n\n{ MESH \n");
575 printf("\n%d %d\n",size[0], size[1]);
576 ok = 1;
577 for (i = 0; i < size[0]; i++){
578 for (j = 0; j < size[1]; j++) {
579 if (globline->token!=NUMBER) {
580 ok = 0; break;
581 }
582 printf(" %s ", globline->data); /* x */
583 globline=globline->next;
584 if (globline->token!=NUMBER) {
585 ok = 0; break;
586 }
587 printf(" %s ", globline->data); /* y */
588 globline=globline->next;
589 if (globline->token!=NUMBER) {
590 ok = 0; break;
591 }
592 printf(" %s ", globline->data); /* z */
593 /* MESH vertices need RGBA colors
594 since OOGL MESHes have per-vertex colors, repeat some.
595 repeat last i index, first j index.
596 */
597 if (numcols) {
598 printf(" %f %f %f 1\n", colors[i<size[0]-1?i:i-1][j?j-1:0][0],
599 colors[i<size[0]-1?i:i-1][j?j-1:0][1],
600 colors[i<size[0]-1?i:i-1][j?j-1:0][2]);
601 } else printf("\n");
602 globline=globline->next;
603 }
604 }
605 if (!ok) {
606 fprintf(stderr, "can't read mesh points array!\n");
607 return 1;
608 } else
609 printf("} #end of MESH\n");
610 break;
611 case BG: /* BezierGraphics */
612 globline=globline->next;
613 if (globline->token == DIMENSIONS) {
614 globline=globline->next;
615 for (i = 0; i < 2 && ok; i++, globline = globline->next)
616 if (globline->token == NUMBER)
617 size[i] = atoi(globline->data);
618 else ok = 0;
619 } else
620 ok = 0;
621 if (!ok) {
622 fprintf(stderr, "can't read Bezier patch dimensions!\n");
623 return 1;
624 }
625
626 /*
627 in BezierGraphics object, first we get all the colors,
628 then all the points.
629
630 points array is size[0] x size[1],
631 color array is 2x2.
632
633 */
634
635 /* if there are colors, store them off */
636 if (globline->token == COLOR) {
637 numcols = 2*2;
638 colors = malloc(2*sizeof(Color*));
639 for (i = 0; i < 2;i++)
640 colors[i] = malloc(2*sizeof(Color));
641 ok = 1;
642 for (i = 0; i < 2; i++) {
643 for (j=0; j < 2; j++) {
644 while (globline->token == COLOR && ok)
645 for (q=0; q < 3 && ok; q++) {
646 globline = globline->next;
647 if (globline->token != NUMBER) {
648 ok = 0;
649 break;
650 } else {
651 colors[i][j][q]=atof(globline->data);
652 }
653 }
654 globline=globline->next;
655 }
656 }
657 if (!ok) {
658 fprintf(stderr, "can't read mesh color array!\n");
659 return 1;
660 }
661 }
662 /* Each number we get is just the x,y or z coordinate. */
663
664 if (numcols)
665 printf("\n\n{ CBEZ");
666 else
667 printf("\n\n{ BEZ");
668 printf("%d%d3\n",size[1]-1, size[0]-1); /* reverse order */
669 ok = 1;
670 for (i = 0; i < size[0]; i++){
671 for (j = 0; j < size[1]; j++) {
672 if (globline->token!=NUMBER) {
673 ok = 0; break;
674 }
675 printf(" %s ", globline->data); /* x */
676 globline=globline->next;
677 if (globline->token!=NUMBER) {
678 ok = 0; break;
679 }
680 printf(" %s ", globline->data); /* y */
681 globline=globline->next;
682 if (globline->token!=NUMBER) {
683 ok = 0; break;
684 }
685 printf(" %s ", globline->data); /* z */
686 /* print colors */
687 if (numcols) {
688 printf(" %f %f %f 1\n", colors[i][j][0], colors[i][j][1],
689 colors[i][j][2]);
690 } else printf("\n");
691 globline=globline->next;
692 }
693 }
694 if (!ok) {
695 fprintf(stderr, "can't read control points array!\n");
696 return 1;
697 } else
698 printf("} #end of BEZ\n");
699 break;
700 case G3: /* Graphics3D */
701 globline=globline->next;
702 npolypoints=npolys=npolycolors=0;
703 nvectpoints=nvects=nvectcolors=0;
704 numnums=numcols=0;
705 state = IGNORE;
706 for (curline=globline;;curline=curline->next) {
707 if (!curline || (curline->token != NUMBER)) {
708
709 if (state == LINE) {
710 nvects++;
711 nvectpoints += numnums/3;
712 if (numcols)
713 nvectcolors++;
714 numcols = 0;
715 } else if (state == POLYGON) {
716 npolys++;
717 npolypoints += numnums/3;
718 if (numcols)
719 npolycolors++;
720 }
721 if (!curline || ismajor(curline->token))
722 break; /* go back to main loop */
723
724 if (curline->token == COLOR)
725 numcols++;
726
727 state=curline->token;
728 numnums=0;
729 } else /* it's a number */
730 numnums++;
731 }
732 if (npolys) {
733
734 printf ("\n{ = OFF\n");
735 printf ("%d %d %d\n",npolypoints, npolys, 0);
736
737 { /* vertex list */
738 struct line *curline;
739 enum st state=IGNORE;
740 char coordnum=0;
741
742 for (curline=globline; curline && !ismajor(curline->token);
743 curline=curline->next) {
744 if (curline->token != NUMBER) {
745 state = curline->token;
746 coordnum=0;
747 printf("\n");
748 } else
749 if (state == POLYGON) {
750 printf("%s",curline->data);
751 if(coordnum++%3 == 2)
752 printf("\n");
753 else
754 printf(" ");
755 }
756 }
757 }
758 { /* face list (maybe includes color) */
759 Color c;
760 char hascolor = 0; /* so far. */
761 char thiscolor=1; /* if this polygon has had its color
762 * tacked on. */
763 char cnum=3; /* 3 == not doing color now. */
764 struct line *curline;
765 enum st state=IGNORE;
766 int pointnum=0;
767
768 c[0] = c[1] = c[2] = 0;
769 for (curline=globline;;curline=curline->next) {
770 if (!thiscolor && hascolor &&
771 (!curline || curline->token != NUMBER)) {
772 /* OFF faces need just RGB colors, no alpha! */
773 printf(" %f %f %f",c[0],c[1],c[2]);
774 thiscolor = 1;
775 }
776 if (!curline || ismajor(curline->token))
777 break; /* back to main loop */
778 switch (curline->token) {
779 case COLOR:
780 cnum = 0;
781 state = COLOR;
782 hascolor = 1;
783 break;
784 case POLYGON:
785 {
786 struct line *countline;
787 int numvert=0;
788
789 thiscolor = !hascolor;
790
791 cnum = 3;
792 state = POLYGON;
793 for (countline = curline->next; countline; countline=countline->next) {
794 if (countline->token != NUMBER)
795 break;
796 numvert++;
797 }
798
799 printf("\n%d",numvert/3);
800 }
801 break;
802 case NUMBER:
803 if (state == POLYGON) {
804 if (pointnum++%3 == 2)
805 printf(" %d",pointnum/3-1);
806 } else if (state==COLOR) {
807 if (cnum<3)
808 c[(int)cnum++] = atof(curline->data);
809 }
810 break;
811 default:
812 state = curline->token;
813 break;
814 }
815 }
816 }
817 printf("\n\n} #end of OFF\n");
818 }
819 if (nvects) {
820 printf("\n{ = VECT\n");
821 printf("%d %d %d\n",nvects, nvectpoints, nvectcolors);
822 {
823 struct line *curline;
824 enum st state=IGNORE;
825 int numvert=0, numcol=0;
826 for (curline=globline;;curline=curline->next) {
827 if (numvert && (!curline || curline->token != NUMBER)) {
828 printf("%d ",numvert/3);
829 numvert = 0;
830 }
831 if (!curline || ismajor(curline->token))
832 break; /* back to main loop */
833 if(curline->token == NUMBER && state==LINE)
834 numvert++;
835 else
836 state=curline->token;
837 }
838 printf("\n\n");
839 for (curline=globline; curline && !ismajor(curline->token);
840 curline=curline->next) {
841 if (curline->token == LINE) {
842 printf("%d ",numcol?1:0);
843 numcol = 0;
844 }
845 if(curline->token == COLOR)
846 numcol++;
847 }
848 printf("\n\n");
849 }
850 {
851 struct line *curline;
852 enum st state=IGNORE;
853 int coordno=0;
854 for (curline=globline; curline && !ismajor(curline->token);
855 curline=curline->next) {
856 if (curline->token != NUMBER)
857 state = curline->token;
858 else
859 if (state == LINE) {
860 printf("%s%c",curline->data,((++coordno)%3)?' ':'\n');
861 }
862 }
863 }
864 {
865 struct line *curline;
866 Color c;
867 char hascolor=0;
868 char cnum=3;
869
870 c[0] = c[1] = c[2] = 0;
871
872 for (curline=globline; curline && !ismajor(curline->token);
873 curline=curline->next) {
874 if (curline->token == NUMBER) {
875 if (cnum<3) {
876 c[(int)cnum++]=atof(curline->data);
877 hascolor = 1;
878 }
879 } else if (curline->token == LINE) {
880 /* note VECTs need RGBA colors */
881 if(hascolor)
882 printf("%f %f %f 1\n",c[0],c[1],c[2]);
883 hascolor = 0;
884 } else if (curline->token == COLOR)
885 cnum = 0;
886
887 }
888 }
889 printf("\n} #end of VECT\n");
890 }
891 globline = curline;
892 break;
893 default:
894 fprintf(stderr, "math2oogl: unexpected data: %s\n", globline->data);
895 return 1;
896 } /* end switch (globline->token) */
897 }
898 printf ("\n} #end of LIST\n");
899 if (togv) { /* end our (geometry */
900 printf("\n)\n");
901 }
902 return 0;
903 }
904