ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/3ds2mgf.c
Revision: 1.1
Committed: Thu Feb 8 11:08:03 1996 UTC (28 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# User Rev Content
1 greg 1.1 /*
2     3DS2POV.C Copyright (c) 1996 Steve Anger and Jeff Bowermaster
3     MGF output added by Greg Ward
4    
5     Reads a 3D Studio .3DS file and writes a POV-Ray, Vivid,
6     Polyray, MGF or raw scene file.
7    
8     Version 2.0 Written Feb/96
9    
10     Compiled with MSDOS GNU C++ 2.4.1 or generic ANSI-C compiler
11     */
12    
13     #ifndef lint
14     static char SCCSid[] = "$SunId$ LBL";
15     #endif
16    
17     #include <stdio.h>
18     #include <stdlib.h>
19     #include <math.h>
20     #include <string.h>
21     #include <ctype.h>
22     #include "vect.h"
23     #include "rayopt.h"
24    
25     #ifdef __TURBOC__
26     #include <alloc.h>
27     extern unsigned _stklen = 16384;
28     #endif
29    
30    
31     #define FALSE 0
32     #define TRUE 1
33    
34     /* Internal bounding modes */
35     #define OFF 0
36     #define ON 1
37     #define AUTO 2
38    
39     #define MAX_LIB 10
40     #define ASPECT 1.333
41    
42     /* Output formats */
43     #define POV10 0
44     #define POV20 1
45     #define VIVID 2
46     #define POLYRAY 3
47     #define MGF 4
48     #define RAW 99
49    
50     #define DEG(x) ((180.0/M_PI)*(x))
51     #define RAD(x) ((M_PI/180.0)*(x))
52    
53     #ifndef M_PI
54     #define M_PI (3.14159265358979323846)
55     #endif
56    
57     #ifndef MAXFLOAT
58     #define MAXFLOAT (1e37)
59     #endif
60     /* RGB chromaticity definitions for MGF */
61     #define CIE_x_r 0.640
62     #define CIE_y_r 0.330
63     #define CIE_x_g 0.290
64     #define CIE_y_g 0.600
65     #define CIE_x_b 0.150
66     #define CIE_y_b 0.060
67     /* computed luminances from above */
68     #define CIE_Y_r 0.265
69     #define CIE_Y_g 0.670
70     #define CIE_Y_b 0.065
71    
72     /* A generic list type */
73     #define LIST_INSERT(root, node) list_insert ((List **)&root, (List *)node)
74     #define LIST_FIND(root, name) list_find ((List **)&root, name)
75     #define LIST_DELETE(root, node) list_delete ((List **)&root, (List *)node)
76     #define LIST_KILL(root) list_kill ((List **)&root)
77    
78     #define LIST_FIELDS \
79     char name[80]; \
80     void *next;
81    
82    
83     typedef unsigned char byte;
84     typedef unsigned short word;
85     typedef unsigned long dword;
86    
87     typedef struct {
88     LIST_FIELDS
89     } List;
90    
91    
92     typedef struct {
93     int a, b, c;
94     } Face;
95    
96    
97     typedef struct {
98     float red, green, blue;
99     } Colour;
100    
101    
102     /* Transformation command */
103     typedef struct {
104     LIST_FIELDS
105    
106     Matrix matrix;
107     } Transform;
108    
109    
110     /* Morph command */
111     typedef struct {
112     LIST_FIELDS
113    
114     int count; /* Number of objects in morph */
115     char names[4][80]; /* Name of n'th object in average */
116     float weight[4]; /* Weight applied to n'th object */
117    
118     Matrix matrix;
119     } Morph;
120    
121    
122     /* Omni light command */
123     typedef struct {
124     LIST_FIELDS
125    
126     Vector pos; /* Light position */
127     Colour col; /* Light colour */
128     } OmniLight;
129    
130    
131     /* Spotlight command */
132     typedef struct {
133     LIST_FIELDS
134    
135     Vector pos; /* Spotlight position */
136     Vector target; /* Spotlight target location */
137     Colour col; /* Spotlight colour */
138     float hotspot; /* Hotspot angle (degrees) */
139     float falloff; /* Falloff angle (degrees) */
140     int shadow_flag; /* Shadow flag (not used) */
141     } Spotlight;
142    
143    
144     /* Camera command */
145     typedef struct {
146     LIST_FIELDS
147    
148     Vector pos; /* Camera location */
149     Vector target; /* Camera target */
150     float bank; /* Banking angle (degrees) */
151     float lens; /* Camera lens size (mm) */
152     } Camera;
153    
154    
155     /* Material list */
156     typedef struct {
157     LIST_FIELDS
158    
159     int external; /* Externally defined material? */
160     } Material;
161    
162    
163     /* Object summary */
164     typedef struct {
165     LIST_FIELDS
166    
167     Vector center; /* Min value of object extents */
168     Vector lengths; /* Max value of object extents */
169     } Summary;
170    
171    
172     /* Material property */
173     typedef struct {
174     LIST_FIELDS
175    
176     Colour ambient;
177     Colour diffuse;
178     Colour specular;
179     float shininess;
180     float transparency;
181     float reflection;
182     int self_illum;
183     int two_side;
184     char tex_map[40];
185     float tex_strength;
186     char bump_map[40];
187     float bump_strength;
188     } MatProp;
189    
190    
191     /* Default material property */
192     MatProp DefaultMaterial = { "Default", NULL, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0},
193     {1.0, 1.0, 1.0}, 70.0, 0.0, 0.0, FALSE, FALSE };
194    
195     /* A mesh object */
196     typedef struct {
197     LIST_FIELDS
198    
199     int vertices; /* Number of vertices */
200     Vector *vertex; /* List of object vertices */
201    
202     int faces; /* Number of faces */
203     Face *face; /* List of object faces */
204     Material **mtl; /* Materials for each face */
205    
206     Matrix matrix; /* Local mesh matrix */
207     Matrix invmatrix;
208     Vector center; /* Center of object */
209     Vector lengths; /* Dimensions of object */
210    
211     int hidden; /* Hidden flag */
212     int shadow; /* Shadow flag */
213     } Mesh;
214    
215    
216     typedef struct {
217     dword start;
218     dword end;
219     dword length;
220     word tag;
221     } Chunk;
222    
223    
224     typedef struct {
225     byte red;
226     byte green;
227     byte blue;
228     } Colour_24;
229    
230    
231     Colour Black = {0.0, 0.0, 0.0};
232    
233     OmniLight *omni_list = NULL;
234     Spotlight *spot_list = NULL;
235     Camera *cam_list = NULL;
236     Mesh *mesh_list = NULL;
237     Transform *trans_list = NULL;
238     Morph *morph_list = NULL;
239     Material *mtl_list = NULL;
240     List *excl_list = NULL;
241     List *box_list = NULL;
242     MatProp *mprop_list = NULL;
243     Summary *summary = NULL;
244    
245    
246     FILE *in;
247     FILE *out;
248     char inname[80];
249     char outname[80];
250     char vuename[80];
251     char obj_name[80] = "";
252     Colour fog_colour = {0.0, 0.0, 0.0};
253     Colour col = {0.0, 0.0, 0.0};
254     Colour global_amb = {0.1, 0.1, 0.1};
255     Vector pos = {0.0, 0.0, 0.0};
256     Vector target = {0.0, 0.0, 0.0};
257     float fog_distance = 0.0;
258     float hotspot = -1;
259     float falloff = -1;
260     Mesh *mesh = NULL;
261     int frame = -1;
262     char libname[MAX_LIB][80];
263     float smooth = 60.0;
264     int bound = 0;
265     int verbose = 0;
266     int format = POV20;
267     int internal_bounding = AUTO;
268     int box_all = FALSE;
269     int cameras = 0;
270     int libs = 0;
271     float vue_version = 1.0;
272     Matrix *ani_matrix = NULL;
273    
274    
275     void process_args (int argc, char *argv[]);
276     void parse_option (char *option);
277     void list_insert (List **root, List *new_node);
278     void *list_find (List **root, char *name);
279     void list_delete (List **root, List *node);
280     void list_kill (List **root);
281     Material *update_materials (char *new_material, int ext);
282     MatProp *create_mprop (void);
283     void read_library (char *fname);
284     void write_intro (FILE *f);
285     void write_summary (FILE *f);
286     void write_bgsolid (FILE *f, Colour col);
287     void write_light (FILE *f, char *name, Vector pos, Colour col);
288     void write_spot (FILE *f, char *name, Vector pos, Vector target, Colour col,
289     float hotspot, float falloff);
290     void write_fog (FILE *f, Colour col, float dist);
291     void write_camera (FILE *f, char *name, Vector pos, Vector target, float lens,
292     float bank);
293     void write_material (FILE *f, char *mat);
294     void write_pov10_material (FILE *f, MatProp *m);
295     void write_pov20_material (FILE *f, MatProp *m);
296     void write_vivid_material (FILE *f, MatProp *m);
297     void write_polyray_material (FILE *f, MatProp *m);
298     void write_mgf_material (FILE *f, MatProp *m);
299     void write_mesh (FILE *f, Mesh *mesh);
300     Transform *parse_transform (char *string);
301     Morph *parse_morph (char *string);
302     OmniLight *parse_omnilight (char *string);
303     Spotlight *parse_spotlight (char *string);
304     Camera *parse_camera (char *string);
305     void read_frame (char *filename, int frame_no);
306     void find_frame (FILE *f, int frame_no);
307     void save_animation (void);
308     Mesh *create_mesh (char *name, int vertices, int faces);
309     Mesh *copy_mesh (Mesh *mesh);
310     void free_mesh_data (Mesh *mesh);
311     void update_limits (Mesh *mesh);
312     char *before (char *str, char *target);
313     char *after (char *str, char *target);
314     char *between (char *str, char *target1, char *target2);
315     char *parse_string (char *str);
316     char upcase (char c);
317     float colour_intens (Colour *colour);
318     void parse_file (void);
319     void parse_3ds (Chunk *mainchunk);
320     void parse_mdata (Chunk *mainchunk);
321     void parse_fog (Chunk *mainchunk);
322     void parse_fog_bgnd (void);
323     void parse_mat_entry (Chunk *mainchunk);
324     char *parse_mapname (Chunk *mainchunk);
325     void parse_named_object (Chunk *mainchunk);
326     void parse_n_tri_object (Chunk *mainchunk);
327     void parse_point_array (void);
328     void parse_face_array (Chunk *mainchunk);
329     void parse_msh_mat_group (void);
330     void parse_smooth_group (void);
331     void parse_mesh_matrix (void);
332     void parse_n_direct_light (Chunk *mainchunk);
333     void parse_dl_spotlight (void);
334     void parse_n_camera (void);
335     void parse_colour (Colour *colour);
336     void parse_colour_f (Colour *colour);
337     void parse_colour_24 (Colour_24 *colour);
338     float parse_percentage (void);
339     short parse_int_percentage (void);
340     float parse_float_percentage (void);
341     void start_chunk (Chunk *chunk);
342     void end_chunk (Chunk *chunk);
343     byte read_byte (void);
344     word read_word (void);
345     dword read_dword (void);
346     float read_float (void);
347     void read_point (Vector v);
348     char *read_string (void);
349     float findfov (float lens);
350     int read_mgfmatname (char *s, int n, FILE *f);
351    
352    
353     int main (int argc, char *argv[])
354     {
355     Material *m;
356     int i;
357    
358     process_args (argc, argv);
359    
360     if (format != RAW) {
361     opt_set_format (format);
362     opt_set_dec (4);
363     opt_set_bound (bound);
364     opt_set_smooth (smooth);
365     opt_set_quiet (!verbose);
366     opt_set_fname (outname, "");
367     }
368    
369     if ((in = fopen (inname, "rb")) == NULL) {
370     printf ("Cannot open input file %s!\n", inname);
371     exit (1);
372     }
373    
374     if ((out = fopen (outname, "w")) == NULL) {
375     printf ("Cannot open output file %s!\n", outname);
376     exit (1);
377     }
378    
379     /* Load the names of pre-defined materials */
380     for (i = 0; i < MAX_LIB; i++) {
381     if (strlen(libname[i]) > 0)
382     read_library (libname[i]);
383     }
384    
385     /* Load the instructions for the current frame */
386     if (strlen(vuename) > 0)
387     read_frame (vuename, frame);
388    
389     printf("Output to: %s\n", outname);
390    
391     if (frame >= 0)
392     printf ("Generating frame #%d\n", frame);
393    
394     printf("\nPlease wait; Processing...\n");
395    
396     write_intro(out);
397    
398     parse_file();
399    
400     fclose(in);
401    
402     for (m = mtl_list; m != NULL; m = m->next) {
403     if (!m->external)
404     write_material (out, m->name);
405     }
406    
407     if (frame >= 0)
408     save_animation();
409    
410     if (format != RAW) {
411     write_summary (out);
412     fflush (out);
413    
414     opt_finish();
415     }
416    
417     fclose (out);
418    
419     LIST_KILL (omni_list);
420     LIST_KILL (spot_list);
421     LIST_KILL (cam_list);
422     LIST_KILL (mesh_list);
423     LIST_KILL (trans_list);
424     LIST_KILL (morph_list);
425     LIST_KILL (mtl_list);
426     LIST_KILL (excl_list);
427     LIST_KILL (box_list);
428     LIST_KILL (mprop_list);
429     LIST_KILL (summary);
430    
431     return 0;
432     }
433    
434    
435     /* Handle the command line args */
436     void process_args (int argc, char *argv[])
437     {
438     int i;
439     char *progname;
440     char *env_opt, *option;
441    
442     printf("\n\nAutodesk 3D Studio to Raytracer file Translator. Feb/96\n");
443     printf("Version 2.0 Copyright (c) 1996 Steve Anger and Jeff Bowermaster\n");
444     #ifdef __GNUC__
445     printf ("32 bit version. DOS extender Copyright (c) 1991 DJ Delorie\n");
446     #endif
447     printf ("\n");
448    
449     if (argc < 2) {
450     printf ("Usage: %s inputfile[.3ds] [outputfile] [options]\n\n", argv[0]);
451     printf ("Options: -snnn - Smooth triangles with angles < nnn\n");
452     printf (" -l<filename> - Specifies native material library\n");
453     printf (" -a<filename> - Use animation information in specified file\n");
454     printf (" -fnnn - Generate frame nnn of animation\n");
455     printf (" -x<object> - Exclude this object from conversion\n");
456     printf (" -b<object> - Convert this object as a box\n");
457     printf (" +i, -i - Turn internal bounding on or off\n");
458     printf (" +v, -v - Turn verbose status messages on or off\n");
459     printf (" -op - Output to POV-Ray 2.0 format (default)\n");
460     printf (" -op1 - Output to POV-Ray 1.0 format\n");
461     printf (" -ov - Output to Vivid format\n");
462     printf (" -ol - Output to poLyray format\n");
463     printf (" -om - Output to MGF\n");
464     printf (" -or - Output to RAW triangle format\n\n");
465     printf ("ex. %s birdshow +v -lmaterials.inc\n\n", argv[0]);
466     exit(1);
467     }
468     /* figure default format from name */
469     progname = strrchr(argv[0], '/');
470     if (progname == NULL) progname = argv[0];
471     else progname++;
472     if (!strcmp(progname, "3ds2pov"))
473     format = POV20;
474     else if (!strcmp(progname, "3ds2viv"))
475     format = VIVID;
476     else if (!strcmp(progname, "3ds2pi"))
477     format = POLYRAY;
478     else if (!strcmp(progname, "3ds2mgf"))
479     format = MGF;
480     else if (!strcmp(progname, "3ds2raw"))
481     format = RAW;
482     else
483     format = MGF; /* default if program name strange */
484    
485     strcpy (inname, "");
486     strcpy (outname, "");
487     strcpy (vuename, "");
488    
489     for (i = 0; i < MAX_LIB; i++)
490     strcpy (libname[i], "");
491    
492     frame = -1;
493     smooth = 70.0;
494     bound = 0;
495     verbose = 0;
496     internal_bounding = AUTO;
497     box_all = FALSE;
498     libs = 0;
499    
500     /* Parse the enviroment string options */
501     env_opt = getenv ("3DS2POV");
502    
503     if (env_opt != NULL) {
504     option = parse_string (env_opt);
505    
506     while (strlen(option) > 0) {
507     parse_option (option);
508     option = parse_string (NULL);
509     }
510     }
511    
512     /* Parse the command line options */
513     for (i = 1; i < argc; i++)
514     parse_option (argv[i]);
515    
516     if (strlen(inname) == 0)
517     abortmsg ("No input file specified", 1);
518    
519     if (strlen(outname) == 0)
520     strcpy (outname, inname);
521    
522     switch (format) {
523     case POV10:
524     case POV20: add_ext (outname, "pov", 1); break;
525     case VIVID: add_ext (outname, "v", 1); break;
526     case POLYRAY: add_ext (outname, "pi", 1); break;
527     case MGF: add_ext (outname, "mgf", 1); break;
528     case RAW: add_ext (outname, "raw", 1); break;
529     }
530    
531     switch (internal_bounding) {
532     case OFF: bound = 2; break;
533     case ON: bound = 0; break;
534     case AUTO: bound = (format == POV10) ? 0 : 2; break;
535     }
536    
537     if ((strlen(vuename) > 0) != (frame >= 0))
538     abortmsg ("The -a and -f parameters must be used together", 1);
539     }
540    
541    
542     void parse_option (char *option)
543     {
544     List *excl, *box;
545     char name[80];
546    
547     if (option[0] == '-' || option[0] == '+') {
548     switch (upcase(option[1])) {
549     case 'A': strcpy (vuename, &option[2]);
550     break;
551    
552     case 'B': strcpy (name, parse_string (&option[2]));
553     if (strlen(name) == 0)
554     box_all = TRUE;
555     else {
556     cleanup_name (name);
557    
558     box = malloc (sizeof (*box));
559     strcpy (box->name, name);
560    
561     LIST_INSERT (box_list, box);
562     }
563     break;
564    
565     case 'F': if (option[2] != '\0')
566     frame = atoi (&option[2]);
567     break;
568    
569     case 'I': if (option[0] == '-')
570     internal_bounding = OFF;
571     else
572     internal_bounding = ON;
573     break;
574    
575     case 'L': if (libs == MAX_LIB)
576     abortmsg ("Too many libraries specified", 1);
577    
578     strcpy (libname[libs++], &option[2]);
579     break;
580    
581     case 'O': switch (upcase(option[2])) {
582     case 'P': if (option[3] == '1')
583     format = POV10;
584     else
585     format = POV20;
586     break;
587    
588     case 'V': format = VIVID;
589     break;
590    
591     case 'L': format = POLYRAY;
592     break;
593    
594     case 'R': format = RAW;
595     break;
596    
597     case 'M': format = MGF;
598     break;
599    
600     default: printf ("Invalid output format %s specified\n", option);
601     exit(1);
602     }
603     break;
604    
605     case 'S': if (option[2] != '\0')
606     smooth = atof (&option[2]);
607     break;
608    
609     case 'U': printf ("Warning: -u parameter no long has any effect\n");
610     printf (" use +i or -i instead.\n");
611     break;
612    
613     case 'V': if (option[0] == '-')
614     verbose = 0;
615     else
616     verbose = 1;
617     break;
618    
619     case 'X': strcpy (name, parse_string (&option[2]));
620     cleanup_name (name);
621    
622     excl = malloc (sizeof (*excl));
623     strcpy (excl->name, name);
624    
625     LIST_INSERT (excl_list, excl);
626     break;
627    
628     default : printf ("\nInvalid option %s specified\n", option);
629     exit (1);
630     }
631     }
632     else if (strlen (inname) == 0) {
633     strcpy (inname, option);
634     add_ext (inname, "3ds", 0);
635     }
636     else if (strlen (outname) == 0)
637     strcpy (outname, option);
638     else
639     abortmsg ("Too many file names specified.\n", 1);
640     }
641    
642    
643     /* Insert a new node into the list */
644     void list_insert (List **root, List *new_node)
645     {
646     new_node->next = *root;
647    
648     *root = new_node;
649     }
650    
651    
652     /* Find the node with the specified name */
653     void *list_find (List **root, char *name)
654     {
655     List *p;
656    
657     for (p = *root; p != NULL; p = p->next) {
658     if (strcmp (p->name, name) == 0)
659     break;
660     }
661    
662     return (void *)p;
663     }
664    
665    
666     /* Delete the indicated node from the list */
667     void list_delete (List **root, List *node)
668     {
669     List *prev;
670    
671     prev = *root;
672     while (prev != NULL && prev->next != node)
673     prev = prev->next;
674    
675     if (prev == NULL)
676     *root = node->next;
677     else
678     prev->next = node->next;
679    
680     free (node);
681     }
682    
683    
684     /* Delete the entire list */
685     void list_kill (List **root)
686     {
687     List *temp;
688    
689     while (*root != NULL) {
690     temp = *root;
691     *root = (*root)->next;
692     free (temp);
693     }
694     }
695    
696    
697     /* Add a new material to the material list */
698     Material *update_materials (char *new_material, int ext)
699     {
700     Material *p;
701    
702     p = LIST_FIND (mtl_list, new_material);
703    
704     if (p == NULL) {
705     p = malloc (sizeof (*p));
706    
707     if (p == NULL)
708     abortmsg ("Out of memory adding material", 1);
709    
710     strcpy (p->name, new_material);
711     p->external = ext;
712    
713     LIST_INSERT (mtl_list, p);
714     }
715    
716     return p;
717     }
718    
719    
720     MatProp *create_mprop()
721     {
722     MatProp *new_mprop;
723    
724     new_mprop = malloc (sizeof(*new_mprop));
725     if (new_mprop == NULL)
726     abortmsg ("Out of memory adding material", 1);
727    
728     strcpy (new_mprop->name, "");
729     new_mprop->ambient = Black;
730     new_mprop->diffuse = Black;
731     new_mprop->specular = Black;
732     new_mprop->shininess = 0.0;
733     new_mprop->transparency = 0.0;
734     new_mprop->reflection = 0.0;
735     new_mprop->self_illum = FALSE;
736     new_mprop->two_side = FALSE;
737    
738     strcpy (new_mprop->tex_map, "");
739     new_mprop->tex_strength = 0.0;
740    
741     strcpy (new_mprop->bump_map, "");
742     new_mprop->bump_strength = 0.0;
743    
744     return new_mprop;
745     }
746    
747    
748     /* Load in any predefined materials */
749     void read_library (char *fname)
750     {
751     FILE *lib;
752     char string[256], name[80];
753    
754     if ((lib = fopen (fname, "r")) == NULL) {
755     printf ("Cannot open texture library file %s!\n", fname);
756     exit(1);
757     }
758    
759     switch (format) {
760     case POV10:
761     case POV20:
762     while (fgets (string, 256, lib) != NULL) {
763     if (strstr (string, "#declare")) {
764     strcpy (name, between (string, "#declare", "="));
765     cleanup_name (name);
766     (void)update_materials (name, TRUE);
767     }
768     }
769     break;
770    
771     case VIVID:
772     while (fgets (string, 256, lib) != NULL) {
773     if (strstr (string, "#define")) {
774     (void)parse_string (string);
775     strcpy (name, parse_string (NULL));
776     cleanup_name (name);
777     (void)update_materials (name, TRUE);
778     }
779     }
780     break;
781    
782     case POLYRAY:
783     while (fgets (string, 256, lib) != NULL) {
784     if (strstr (string, "define")) {
785     (void)parse_string (string);
786     strcpy (name, parse_string (NULL));
787     cleanup_name (name);
788     (void)update_materials (name, TRUE);
789     }
790     }
791     break;
792    
793     case MGF:
794     while (read_mgfmatname(name, 80, lib))
795     (void)update_materials (name, TRUE);
796     break;
797     }
798    
799     fclose (lib);
800     }
801    
802    
803     /* parse the next MGF material name from f, return FALSE if EOF */
804     int read_mgfmatname (char *s, int n, FILE *f)
805     {
806     char inpline[128];
807     register char *cp, *cp2;
808     register int i;
809     /* find material */
810     while (fgets(inpline, sizeof(inpline), f) != NULL) {
811     for (cp = inpline; isspace(*cp); cp++)
812     ;
813     if (*cp++ != 'm' || !isspace(*cp++))
814     continue;
815     while (isspace(*cp))
816     cp++;
817     if (!*cp)
818     continue;
819     for (i=n, cp2=s; *cp && !isspace(*cp); cp++) /* get name */
820     if (--i > 0)
821     *cp2++ = *cp;
822     *cp2 = '\0';
823     while (isspace(*cp))
824     cp++;
825     if (*cp++ != '=' || !isspace(*cp)) /* not defined? */
826     continue;
827     return TRUE;
828     }
829     return FALSE;
830     }
831    
832    
833     void write_intro (FILE *f)
834     {
835     int i;
836    
837     switch (format) {
838     case POV10:
839     case POV20:
840     fprintf (f, "#include \"colors.inc\"\n");
841     fprintf (f, "#include \"shapes.inc\"\n");
842     fprintf (f, "#include \"textures.inc\"\n");
843    
844     for (i = 0; i < MAX_LIB; i++) {
845     if (strlen(libname[i]) > 0)
846     fprintf (f, "#include \"%s\"\n", libname[i]);
847     }
848    
849     fprintf (f, "\n");
850     break;
851    
852     case VIVID:
853     fprintf (f, "#include color.vc\n");
854    
855     for (i = 0; i < MAX_LIB; i++) {
856     if (strlen(libname[i]) > 0)
857     fprintf (f, "#include %s\n", libname[i]);
858     }
859    
860     fprintf (f, "\n");
861     break;
862    
863     case POLYRAY:
864     fprintf (f, "include \"colors.inc\"\n");
865    
866     for (i = 0; i < MAX_LIB; i++) {
867     if (strlen(libname[i]) > 0)
868     fprintf (f, "include \"%s\"\n", libname[i]);
869     }
870    
871     fprintf (f, "\n");
872     break;
873    
874     case MGF:
875     fprintf (f, "c R =\n\tcxy %.3f %.3f\n", CIE_x_r, CIE_y_r);
876     fprintf (f, "c G =\n\tcxy %.3f %.3f\n", CIE_x_g, CIE_y_g);
877     fprintf (f, "c B =\n\tcxy %.3f %.3f\n", CIE_x_b, CIE_y_b);
878    
879     for (i = 0; i < MAX_LIB; i++) {
880     if (strlen(libname[i]) > 0)
881     fprintf (f, "i %s\n", libname[i]);
882     }
883    
884     fprintf (f, "\n");
885     break;
886     }
887     }
888    
889    
890     /* Write the object summary */
891     void write_summary (FILE *f)
892     {
893     char *comstr;
894     Summary *s;
895    
896     if (summary == NULL)
897     return;
898    
899     switch (format) {
900     case POV10:
901     case POV20:
902     case VIVID:
903     case POLYRAY:
904     comstr = "//";
905     break;
906     case MGF:
907     comstr = "# ";
908     break;
909     }
910     fprintf (f, "%s Object CenterX CenterY CenterZ LengthX LengthY LengthZ\n", comstr);
911     fprintf (f, "%s ---------- ---------- ---------- ---------- ---------- ---------- ----------\n", comstr);
912    
913     for (s = summary; s != NULL; s = s->next) {
914     fprintf (f, "%s %-10s%11.2f%11.2f%11.2f%11.2f%11.2f%11.2f\n",
915     comstr, s->name, s->center[X], s->center[Y], s->center[Z],
916     s->lengths[X], s->lengths[Y], s->lengths[Z]);
917     }
918    
919     fprintf (f, "\n");
920     }
921    
922    
923     /* Write background solid colour */
924     void write_bgsolid (FILE *f, Colour col)
925     {
926     switch (format) {
927     case POV10:
928     fprintf (f, "/* Background colour */\n");
929     fprintf (f, "object {\n");
930     fprintf (f, " sphere { <0.0 0.0 0.0> 1e6 }\n");
931     fprintf (f, " texture {\n");
932     fprintf (f, " ambient 1.0\n");
933     fprintf (f, " diffuse 0.0\n");
934     fprintf (f, " color red %4.2f green %4.2f blue %4.2f\n",
935     col.red, col.green, col.blue);
936     fprintf (f, " }\n");
937     fprintf (f, "}\n\n");
938     break;
939    
940     case POV20:
941     fprintf (f, "background { color red %4.2f green %4.2f blue %4.2f }\n\n",
942     col.red, col.green, col.blue);
943     break;
944    
945     case POLYRAY:
946     fprintf (f, "background <%4.2f, %4.2f, %4.2f>\n\n",
947     col.red, col.green, col.blue);
948     break;
949     }
950     }
951    
952    
953     void write_light (FILE *f, char *name, Vector pos, Colour col)
954     {
955     switch (format) {
956     case POV10:
957     fprintf (f, "/* Light: %s */\n", name);
958     fprintf (f, "object {\n");
959     fprintf (f, " light_source { <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f }\n",
960     pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
961     fprintf (f, "}\n\n");
962     break;
963    
964     case POV20:
965     fprintf (f, "/* Light: %s */\n", name);
966     fprintf (f, "light_source {\n");
967     fprintf (f, " <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
968     pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
969     fprintf (f, "}\n\n");
970     break;
971    
972     case VIVID:
973     fprintf (f, "/* Light: %s */\n", name);
974     fprintf (f, "light {\n");
975     fprintf (f, " type point\n");
976     fprintf (f, " position %.4f %.4f %.4f\n",
977     pos[X], pos[Y], pos[Z]);
978     fprintf (f, " color %4.2f %4.2f %4.2f\n",
979     col.red, col.green, col.blue);
980     fprintf (f, "}\n\n");
981     break;
982    
983     case POLYRAY:
984     fprintf (f, "// Light: %s\n", name);
985     fprintf (f, "light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>\n\n",
986     col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
987     break;
988    
989     case MGF:
990     fprintf (f, "\n# Light\n");
991     if (name[0]) fprintf (f, "o %s\n", name);
992     fprintf (f, "m\n\tsides 1\n\tc\n\t\t\tcmix %.3f R %.3f G %.3f B\n\ted %e\n",
993     CIE_Y_r*col.red, CIE_Y_g*col.green, CIE_Y_b*col.blue,
994     10000.0*(CIE_Y_r*col.red + CIE_Y_g*col.green + CIE_Y_b*col.blue));
995     fprintf (f, "v c =\n\tp %.4f %.4f %.4f\nsph c .01\n",
996     pos[X], pos[Y], pos[Z]);
997     if (name[0]) fprintf (f, "o\n");
998     fprintf (f, "\n");
999     break;
1000     }
1001     }
1002    
1003    
1004     void write_spot (FILE *f, char *name, Vector pos, Vector target, Colour col,
1005     float hotspot, float falloff)
1006     {
1007     switch (format) {
1008     case POV10:
1009     fprintf (f, "/* Spotlight: %s */\n", name);
1010     fprintf (f, "object {\n");
1011     fprintf (f, " light_source {\n");
1012     fprintf (f, " <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f\n",
1013     pos[X], pos[Y], pos[Z],
1014     col.red, col.green, col.blue);
1015     fprintf (f, " spotlight\n");
1016     fprintf (f, " point_at <%.4f %.4f %.4f>\n",
1017     target[X], target[Y], target[Z]);
1018     fprintf (f, " tightness 0\n");
1019     fprintf (f, " radius %.2f\n", 0.5*hotspot);
1020     fprintf (f, " falloff %.2f\n", 0.5*falloff);
1021     fprintf (f, " }\n");
1022     fprintf (f, "}\n\n");
1023     break;
1024    
1025     case POV20:
1026     fprintf (f, "/* Spotlight: %s */\n", name);
1027     fprintf (f, "light_source {\n");
1028     fprintf (f, " <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
1029     pos[X], pos[Y], pos[Z],
1030     col.red, col.green, col.blue);
1031     fprintf (f, " spotlight\n");
1032     fprintf (f, " point_at <%.4f, %.4f, %.4f>\n",
1033     target[X], target[Y], target[Z]);
1034     fprintf (f, " tightness 0\n");
1035     fprintf (f, " radius %.2f\n", 0.5*hotspot);
1036     fprintf (f, " falloff %.2f\n", 0.5*falloff);
1037     fprintf (f, "}\n\n");
1038     break;
1039    
1040     case VIVID:
1041     fprintf (f, "/* Spotlight: %s */\n", name);
1042     fprintf (f, "light {\n");
1043     fprintf (f, " type spot\n");
1044     fprintf (f, " position %.4f %.4f %.4f\n",
1045     pos[X], pos[Y], pos[Z]);
1046     fprintf (f, " at %.4f %.4f %.4f\n",
1047     target[X], target[Y], target[Z]);
1048     fprintf (f, " color %4.2f %4.2f %4.2f\n",
1049     col.red, col.green, col.blue);
1050     fprintf (f, " min_angle %.2f\n", hotspot);
1051     fprintf (f, " max_angle %.2f\n", falloff);
1052     fprintf (f, "}\n\n");
1053     break;
1054    
1055     case POLYRAY:
1056     fprintf (f, "// Spotlight: %s\n", name);
1057     fprintf (f, "spot_light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>,\n",
1058     col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
1059     fprintf (f, " <%.4f, %.4f, %.4f>, 0.0, %.2f, %.2f\n\n",
1060     target[X], target[Y], target[Z], hotspot/2.0, falloff/2.0);
1061     break;
1062    
1063     case MGF:
1064     fprintf (f, "\n# Spotlight\n");
1065     if (name[0]) fprintf (f, "o %s\n", name);
1066     fprintf (f, "# hotspot: %.2f\n# falloff: %.2f\n", hotspot, falloff);
1067     fprintf (f, "m\n\tsides 1\n\tc\n\t\t\tcmix %.3f R %.3f G %.3f B\n\ted %e\n",
1068     CIE_Y_r*col.red, CIE_Y_g*col.green, CIE_Y_b*col.blue,
1069     10000.0*(CIE_Y_r*col.red + CIE_Y_g*col.green + CIE_Y_b*col.blue));
1070     fprintf (f, "v c =\n\tp %.4f %.4f %.4f\n\tn %.4f %.4f %.4f\n",
1071     pos[X], pos[Y], pos[Z],
1072     target[X]-pos[X], target[Y]-pos[Y], target[Z]-pos[Z]);
1073     fprintf (f, "ring c 0 .01\n");
1074     if (name[0]) fprintf (f, "o\n");
1075     fprintf (f, "\n");
1076     break;
1077     }
1078     }
1079    
1080    
1081     void write_fog (FILE *f, Colour col, float dist)
1082     {
1083     if (dist <= 0.0)
1084     return;
1085    
1086     switch (format) {
1087     case POV10:
1088     fprintf (f, "fog {\n");
1089     fprintf (f, " color red %4.2f green %4.2f blue %4.2f %.4f\n",
1090     col.red, col.green, col.blue, dist/2.0);
1091     fprintf (f, "}\n\n");
1092     break;
1093    
1094     case POV20:
1095     fprintf (f, "fog {\n");
1096     fprintf (f, " color red %4.2f green %4.2f blue %4.2f distance %.4f\n",
1097     col.red, col.green, col.blue, dist/2.0);
1098     fprintf (f, "}\n\n");
1099     break;
1100     }
1101     }
1102    
1103    
1104     void write_camera (FILE *f, char *name, Vector pos, Vector target,
1105     float lens, float bank)
1106     {
1107     float fov;
1108    
1109     cameras++;
1110    
1111     fov = findfov (lens);
1112    
1113     switch (format) {
1114     case POV10:
1115     /* Comment out multiple cameras */
1116     if (cameras > 1)
1117     fprintf (f, "/*\n");
1118    
1119     fprintf (f, "/* Camera: %s */\n", name);
1120     fprintf (f, "camera {\n");
1121     fprintf (f, " location <%.4f %.4f %.4f>\n",
1122     pos[X], pos[Y], pos[Z]);
1123     fprintf (f, " direction <0 %.3f 0>\n", 0.60/tan(0.5*RAD(fov)) );
1124     fprintf (f, " up <0 0 1>\n");
1125     fprintf (f, " sky <0 0 1>\n");
1126     fprintf (f, " right <%.3f 0 0>\n", ASPECT);
1127     fprintf (f, " look_at <%.4f %.4f %.4f>\n",
1128     target[X], target[Y], target[Z]);
1129     if (bank != 0.0)
1130     fprintf (f, " /* Bank angle = %.2f */\n", bank);
1131    
1132     fprintf (f, "}\n");
1133    
1134     if (cameras > 1)
1135     fprintf (f, "*/\n");
1136    
1137     fprintf (f, "\n");
1138     break;
1139    
1140     case POV20:
1141     /* Comment out multiple cameras */
1142     if (cameras > 1)
1143     fprintf (f, "/*\n");
1144    
1145     fprintf (f, "/* Camera: %s */\n", name);
1146     fprintf (f, "camera {\n");
1147     fprintf (f, " location <%.4f, %.4f, %.4f>\n",
1148     pos[X], pos[Y], pos[Z]);
1149     fprintf (f, " direction <0, %.3f, 0>\n", 0.60/tan(0.5*RAD(fov)) );
1150     fprintf (f, " up <0, 0, 1>\n");
1151     fprintf (f, " sky <0, 0, 1>\n");
1152     fprintf (f, " right <%.3f, 0, 0>\n", ASPECT);
1153     fprintf (f, " look_at <%.4f, %.4f, %.4f>\n",
1154     target[X], target[Y], target[Z]);
1155     if (bank != 0.0)
1156     fprintf (f, " /* Bank angle = %.2f */\n", bank);
1157    
1158     fprintf (f, "}\n");
1159    
1160     if (cameras > 1)
1161     fprintf (f, "*/\n");
1162    
1163     fprintf (f, "\n");
1164     break;
1165    
1166     case VIVID:
1167     fprintf (f, "/* Camera: %s */\n", name);
1168    
1169     if (cameras > 1)
1170     fprintf (f, "/*\n");
1171    
1172     fprintf (f, "studio {\n");
1173     fprintf (f, " from %.4f %.4f %.4f\n",
1174     pos[X], pos[Y], pos[Z]);
1175     fprintf (f, " at %.4f %.4f %.4f\n",
1176     target[X], target[Y], target[Z]);
1177     fprintf (f, " up 0 0 1\n");
1178     fprintf (f, " angle %.2f\n", 1.1*fov);
1179     fprintf (f, " aspect %.3f\n", ASPECT);
1180     fprintf (f, " resolution 320 200\n");
1181     fprintf (f, " antialias none\n");
1182     fprintf (f, "}\n");
1183    
1184     if (cameras > 1)
1185     fprintf (f, "*/\n");
1186    
1187     fprintf (f, "\n");
1188     break;
1189    
1190     case POLYRAY:
1191     if (cameras == 1) {
1192     fprintf (f, "// Camera: %s\n", name);
1193     fprintf (f, "viewpoint {\n");
1194     fprintf (f, " from <%.4f, %.4f, %.4f>\n",
1195     pos[X], pos[Y], pos[Z]);
1196     fprintf (f, " at <%.4f, %.4f, %.4f>\n",
1197     target[X], target[Y], target[Z]);
1198     fprintf (f, " up <0, 0, 1>\n");
1199     fprintf (f, " angle %.2f\n", 0.85*fov);
1200     fprintf (f, " aspect %.3f\n", -(ASPECT));
1201     fprintf (f, " resolution 320, 200\n");
1202     fprintf (f, "}\n");
1203     }
1204    
1205     fprintf (f, "\n");
1206     break;
1207    
1208     case MGF:
1209     fprintf (f, "# Camera %s\n", name);
1210     fprintf (f, "# from: %.4f %.4f %.4f\n", pos[X], pos[Y], pos[Z]);
1211     fprintf (f, "# to: %.4f %.4f %.4f\n", target[X], target[Y], target[Z]);
1212     fprintf (f, "# lens length: %.2f\n", lens);
1213     fprintf (f, "# bank: %.2f\n", bank);
1214     break;
1215     }
1216     }
1217    
1218    
1219     void write_material (FILE *f, char *mat)
1220     {
1221     MatProp *mprop = LIST_FIND (mprop_list, mat);
1222    
1223     if (mprop == NULL) {
1224     mprop = &DefaultMaterial;
1225     (void)strcpy(mprop->name, mat);
1226     }
1227    
1228     switch (format) {
1229     case POV10:
1230     write_pov10_material (f, mprop);
1231     break;
1232    
1233     case POV20:
1234     write_pov20_material (f, mprop);
1235     break;
1236    
1237     case VIVID:
1238     write_vivid_material (f, mprop);
1239     break;
1240    
1241     case POLYRAY:
1242     write_polyray_material (f, mprop);
1243     break;
1244    
1245     case MGF:
1246     write_mgf_material (f, mprop);
1247     break;
1248     }
1249     }
1250    
1251    
1252     void write_pov10_material (FILE *f, MatProp *m)
1253     {
1254     float amb = 0.1, dif = 0.9, spec = 1.0;
1255     float dist_white, dist_diff, phong, phong_size;
1256     float red, green, blue;
1257    
1258     /* amb = get_ambient (m); */
1259    
1260     if (m->self_illum) {
1261     amb = 0.9;
1262     dif = 0.1;
1263     }
1264    
1265     dist_white = fabs(1.0 - m->specular.red) +
1266     fabs(1.0 - m->specular.green) +
1267     fabs(1.0 - m->specular.blue);
1268    
1269     dist_diff = fabs(m->diffuse.red - m->specular.red) +
1270     fabs(m->diffuse.green - m->specular.green) +
1271     fabs(m->diffuse.blue - m->specular.blue);
1272    
1273    
1274     phong_size = 0.7*m->shininess;
1275     if (phong_size < 1.0) phong_size = 1.0;
1276    
1277     if (phong_size > 30.0)
1278     phong = 1.0;
1279     else
1280     phong = phong_size/30.0;
1281    
1282     fprintf (f, "#declare %s = texture {\n", m->name);
1283     fprintf (f, " ambient %.2f\n", amb);
1284     fprintf (f, " diffuse %.2f\n", dif);
1285     fprintf (f, " phong %.2f\n", phong);
1286     fprintf (f, " phong_size %.1f\n", phong_size);
1287    
1288     if (dist_diff < dist_white)
1289     fprintf (f, " metallic\n");
1290    
1291     if (m->reflection > 0.0) {
1292     spec = (m->specular.red + m->specular.green + m->specular.blue)/3.0;
1293     fprintf (f, " reflection %.3f\n", spec * m->reflection);
1294     }
1295    
1296     if (m->transparency > 0.0) {
1297     red = m->diffuse.red;
1298     green = m->diffuse.green;
1299     blue = m->diffuse.blue;
1300    
1301     /* Saturate the colour towards white as the transparency increases */
1302     red = ((1.0 - m->transparency) * red) + m->transparency;
1303     green = ((1.0 - m->transparency) * green) + m->transparency;
1304     blue = ((1.0 - m->transparency) * blue) + m->transparency;
1305    
1306     fprintf (f, " color red %.3f green %.3f blue %.3f alpha %.3f\n",
1307     red, green, blue, m->transparency);
1308     fprintf (f, " ior 1.1\n");
1309     fprintf (f, " refraction 1.0\n");
1310     }
1311     else
1312     fprintf (f, " color red %.3f green %.3f blue %.3f\n",
1313     m->diffuse.red, m->diffuse.green, m->diffuse.blue);
1314    
1315     if (strlen (m->tex_map) > 0) {
1316     fprintf (f, " /* Image map: %s, Strength: %.2f */\n",
1317     m->tex_map, m->tex_strength);
1318     }
1319    
1320     if (strlen (m->bump_map) > 0) {
1321     fprintf (f, " /* Bump map: %s, Strength: %.2f */\n",
1322     m->bump_map, m->bump_strength);
1323     }
1324    
1325     fprintf (f, "}\n\n");
1326     }
1327    
1328    
1329     void write_pov20_material (FILE *f, MatProp *m)
1330     {
1331     float amb = 0.1, dif = 0.9, spec = 1.0;
1332     float dist_white, dist_diff, phong, phong_size;
1333     float red, green, blue;
1334    
1335     /* amb = get_ambient (m); */
1336    
1337     if (m->self_illum) {
1338     amb = 0.9;
1339     dif = 0.1;
1340     }
1341    
1342     dist_white = fabs(1.0 - m->specular.red) +
1343     fabs(1.0 - m->specular.green) +
1344     fabs(1.0 - m->specular.blue);
1345    
1346     dist_diff = fabs(m->diffuse.red - m->specular.red) +
1347     fabs(m->diffuse.green - m->specular.green) +
1348     fabs(m->diffuse.blue - m->specular.blue);
1349    
1350     phong_size = 0.7*m->shininess;
1351     if (phong_size < 1.0) phong_size = 1.0;
1352    
1353     if (phong_size > 30.0)
1354     phong = 1.0;
1355     else
1356     phong = phong_size/30.0;
1357    
1358     fprintf (f, "#declare %s = texture {\n", m->name);
1359     fprintf (f, " finish {\n");
1360     fprintf (f, " ambient %.2f\n", amb);
1361     fprintf (f, " diffuse %.2f\n", dif);
1362     fprintf (f, " phong %.2f\n", phong);
1363     fprintf (f, " phong_size %.1f\n", phong_size);
1364    
1365     if (dist_diff < dist_white)
1366     fprintf (f, " metallic\n");
1367    
1368     if (m->reflection > 0.0) {
1369     spec = (m->specular.red + m->specular.green + m->specular.blue)/3.0;
1370     fprintf (f, " reflection %.3f\n", spec * m->reflection);
1371     }
1372    
1373     if (m->transparency > 0.0) {
1374     fprintf (f, " ior 1.1\n");
1375     fprintf (f, " refraction 1.0\n");
1376     }
1377    
1378     fprintf (f, " }\n");
1379    
1380     if (m->transparency > 0.0) {
1381     red = m->diffuse.red;
1382     green = m->diffuse.green;
1383     blue = m->diffuse.blue;
1384    
1385     /* Saturate the colour towards white as the transparency increases */
1386     red = ((1.0 - m->transparency) * red) + m->transparency;
1387     green = ((1.0 - m->transparency) * green) + m->transparency;
1388     blue = ((1.0 - m->transparency) * blue) + m->transparency;
1389    
1390     fprintf (f, " pigment { rgbf <%.3f, %.3f, %.3f, %.3f> }\n",
1391     red, green, blue, m->transparency);
1392     }
1393     else
1394     fprintf (f, " pigment { rgb <%.3f, %.3f, %.3f> }\n",
1395     m->diffuse.red, m->diffuse.green, m->diffuse.blue);
1396    
1397     if (strlen (m->tex_map) > 0) {
1398     fprintf (f, " /* Image map: %s, Strength: %.2f */\n",
1399     m->tex_map, m->tex_strength);
1400     }
1401    
1402     if (strlen (m->bump_map) > 0) {
1403     fprintf (f, " /* Bump map: %s, Strength: %.2f */\n",
1404     m->bump_map, m->bump_strength);
1405     }
1406    
1407     fprintf (f, "}\n\n");
1408     }
1409    
1410    
1411     void write_vivid_material (FILE *f, MatProp *m)
1412     {
1413     float amb = 0.1, dif = 0.9;
1414    
1415     /* amb = get_ambient (m); */
1416    
1417     if (m->self_illum) {
1418     amb = 0.9;
1419     dif = 0.1;
1420     }
1421    
1422     if (m->transparency > 0.0) {
1423     dif = dif - m->transparency;
1424     if (dif < 0.0) dif = 0.0;
1425     }
1426    
1427     fprintf (f, "#define %s \\ \n", m->name);
1428     fprintf (f, " surface { \\ \n");
1429     fprintf (f, " ambient %.3f %.3f %.3f \\ \n",
1430     amb*m->ambient.red, amb*m->ambient.green, amb*m->ambient.blue);
1431    
1432     fprintf (f, " diffuse %.3f %.3f %.3f \\ \n",
1433     dif*m->diffuse.red, dif*m->diffuse.green, dif*m->diffuse.blue);
1434    
1435     fprintf (f, " shine %.1f %.3f %.3f %.3f \\ \n",
1436     0.7*m->shininess, m->specular.red, m->specular.green, m->specular.blue);
1437    
1438     if (m->transparency > 0.0) {
1439     fprintf (f, " transparent %.3f*white \\ \n", 1.0 - (1.0 - m->transparency)/14.0);
1440     fprintf (f, " ior 1.1 \\ \n");
1441     }
1442    
1443     if (m->reflection > 0.0)
1444     fprintf (f, " specular %.3f*white \\ \n", m->reflection);
1445    
1446     if (strlen (m->tex_map) > 0) {
1447     fprintf (f, " /* Image map: %s, Strength: %.2f */ \\ \n",
1448     m->tex_map, m->tex_strength);
1449     }
1450    
1451     if (strlen (m->bump_map) > 0) {
1452     fprintf (f, " /* Bump map: %s, Strength: %.2f */ \\ \n",
1453     m->bump_map, m->bump_strength);
1454     }
1455    
1456     fprintf (f, " }\n\n");
1457     }
1458    
1459    
1460     void write_polyray_material (FILE *f, MatProp *m)
1461     {
1462     float amb = 0.1, dif = 0.9, spec;
1463    
1464     /* amb = get_ambient (m); */
1465    
1466     if (m->self_illum) {
1467     amb = 0.9;
1468     dif = 0.1;
1469     }
1470    
1471     if (m->transparency > 0.0) {
1472     dif = dif - m->transparency;
1473     if (dif < 0.0) dif = 0.0;
1474     }
1475    
1476     if (m->shininess == 0.0)
1477     m->shininess = 0.1;
1478    
1479     if (m->shininess > 40.0)
1480     spec = 1.0;
1481     else
1482     spec = m->shininess/40.0;
1483    
1484     fprintf (f, "define %s\n", m->name);
1485     fprintf (f, "texture {\n");
1486     fprintf (f, " surface {\n");
1487     fprintf (f, " ambient <%.3f, %.3f, %.3f>, %.1f\n",
1488     m->ambient.red, m->ambient.green, m->ambient.blue, amb);
1489    
1490     fprintf (f, " diffuse <%.3f, %.3f, %.3f>, %.1f\n",
1491     m->diffuse.red, m->diffuse.green, m->diffuse.blue, dif);
1492    
1493     fprintf (f, " specular <%.3f, %.3f, %.3f>, %.2f\n",
1494     m->specular.red, m->specular.green, m->specular.blue, spec);
1495    
1496     fprintf (f, " microfacet Reitz %.1f\n", 400.0/m->shininess);
1497    
1498     if (m->transparency > 0.0)
1499     fprintf (f, " transmission %.3f, 1.1\n", m->transparency);
1500    
1501     if (m->reflection > 0.0)
1502     fprintf (f, " reflection %.3f\n", m->reflection);
1503    
1504     if (strlen (m->tex_map) > 0) {
1505     fprintf (f, " // Image map: %s, Strength: %.2f\n",
1506     m->tex_map, m->tex_strength);
1507     }
1508    
1509     if (strlen (m->bump_map) > 0) {
1510     fprintf (f, " // Bump map: %s, Strength: %.2f\n",
1511     m->bump_map, m->bump_strength);
1512     }
1513    
1514     fprintf (f, " }\n");
1515     fprintf (f, "}\n\n");
1516     }
1517    
1518    
1519     void write_mgf_material (FILE *f, MatProp *m)
1520     {
1521     float dmag, smag, rdmag, rsmag, tdmag, tsmag, total;
1522    
1523     fprintf (f, "m %s =\n", m->name);
1524     fprintf (f, "\tsides %d\n", m->two_side ? 2 : 1);
1525     dmag = CIE_Y_r*m->diffuse.red + CIE_Y_g*m->diffuse.green
1526     + CIE_Y_b*m->diffuse.blue;
1527     smag = CIE_Y_r*m->specular.red + CIE_Y_g*m->specular.green
1528     + CIE_Y_b*m->specular.blue;
1529     rdmag = dmag;
1530     rsmag = smag * m->reflection;
1531     tdmag = 0.0;
1532     tsmag = m->transparency;
1533     total = rdmag + rsmag + tdmag + tsmag;
1534     if (total > 0.99) {
1535     total = 0.9/total;
1536     dmag *= total;
1537     smag *= total;
1538     rdmag *= total;
1539     rsmag *= total;
1540     tdmag *= total;
1541     tsmag *= total;
1542     total = 0.9;
1543     }
1544     if (dmag > 0.005) {
1545     fprintf (f, "\tc\n\t\tcmix %.3f R %.3f G %.3f B\n",
1546     CIE_Y_r*m->diffuse.red,
1547     CIE_Y_g*m->diffuse.green,
1548     CIE_Y_b*m->diffuse.blue);
1549     if (rdmag > 0.005)
1550     fprintf (f, "\trd %.4f\n", rdmag);
1551     if (tdmag > 0.005)
1552     fprintf (f, "\ttd %.4f\n", tdmag);
1553     if (m->self_illum)
1554     fprintf (f, "\ted %.4f\n", dmag);
1555     }
1556     if (m->shininess > 1.1 && rsmag > 0.005) {
1557     fprintf (f, "\tc\n\t\tcmix %.3f R %.3f G %.3f B\n",
1558     CIE_Y_r*m->specular.red,
1559     CIE_Y_g*m->specular.green,
1560     CIE_Y_b*m->specular.blue);
1561     fprintf (f, "\trs %.4f %.4f\n", rsmag, 0.6/sqrt(m->shininess));
1562     }
1563     if (tsmag > 0.005)
1564     fprintf (f, "\tc\n\tts %.4f 0\n", tsmag);
1565    
1566     if (strlen (m->tex_map) > 0) {
1567     fprintf (f, "# image map: %s, strength: %.2f\n",
1568     m->tex_map, m->tex_strength);
1569     }
1570    
1571     if (strlen (m->bump_map) > 0) {
1572     fprintf (f, "# bump map: %s, strength: %.2f\n",
1573     m->bump_map, m->bump_strength);
1574     }
1575    
1576     fprintf (f, "\n");
1577     }
1578    
1579    
1580     /* Write a mesh file */
1581     void write_mesh (FILE *f, Mesh *mesh)
1582     {
1583     int i;
1584     Vector va, vb, vc;
1585     Summary *new_summary;
1586     Matrix obj_matrix;
1587    
1588     if (mesh->hidden || LIST_FIND (excl_list, mesh->name))
1589     return;
1590    
1591     /* Add this object's stats to the summary */
1592     new_summary = malloc (sizeof(*new_summary));
1593     if (new_summary == NULL)
1594     abortmsg ("Out of memory adding summary", 1);
1595    
1596     strcpy (new_summary->name, mesh->name);
1597     vect_copy (new_summary->center, mesh->center);
1598     vect_copy (new_summary->lengths, mesh->lengths);
1599    
1600     LIST_INSERT (summary, new_summary);
1601    
1602     /* Compute the object transformation matrix for animations */
1603     if (ani_matrix != NULL) {
1604     mat_copy (obj_matrix, *ani_matrix);
1605     if (vue_version > 2.0)
1606     mat_mult (obj_matrix, mesh->invmatrix, obj_matrix);
1607     }
1608    
1609     switch (format) {
1610     case POV10:
1611     case POV20:
1612     case VIVID:
1613     case POLYRAY:
1614     case MGF:
1615     opt_set_vert (mesh->vertices);
1616    
1617     for (i = 0; i < mesh->faces; i++) {
1618     vect_copy (va, mesh->vertex[mesh->face[i].a]);
1619     vect_copy (vb, mesh->vertex[mesh->face[i].b]);
1620     vect_copy (vc, mesh->vertex[mesh->face[i].c]);
1621    
1622     opt_set_texture (mesh->mtl[i]->name);
1623    
1624     opt_add_tri (va[X], va[Y], va[Z], vc[X], vc[Y], vc[Z],
1625     vb[X], vb[Y], vb[Z]);
1626     }
1627    
1628     fflush (f);
1629    
1630     if (ani_matrix != NULL)
1631     opt_set_transform (obj_matrix);
1632    
1633     if (box_all || LIST_FIND (box_list, mesh->name))
1634     opt_write_box (mesh->name);
1635     else
1636     opt_write_file (mesh->name);
1637    
1638     break;
1639    
1640     case RAW:
1641     fprintf (f, "%s\n", mesh->name);
1642    
1643     for (i = 0; i < mesh->faces; i++) {
1644     vect_copy (va, mesh->vertex[mesh->face[i].a]);
1645     vect_copy (vb, mesh->vertex[mesh->face[i].b]);
1646     vect_copy (vc, mesh->vertex[mesh->face[i].c]);
1647    
1648     if (ani_matrix != NULL) {
1649     vect_transform (va, va, obj_matrix);
1650     vect_transform (vb, vb, obj_matrix);
1651     vect_transform (vc, vc, obj_matrix);
1652     }
1653    
1654     fprintf (f, "%f %f %f %f %f %f %f %f %f\n",
1655     va[X], va[Y], va[Z], vb[X], vb[Y], vb[Z],
1656     vc[X], vc[Y], vc[Z]);
1657     }
1658    
1659     break;
1660     }
1661     }
1662    
1663    
1664     /* Parses an object transformation and returns a pointer to the
1665     newly allocated transformation */
1666     Transform *parse_transform (char *string)
1667     {
1668     Transform *t;
1669     char *token;
1670     int token_no;
1671    
1672     t = (Transform *)malloc (sizeof(*t));
1673     if (t == NULL)
1674     abortmsg ("Out of memory allocating transform", 1);
1675    
1676     mat_identity (t->matrix);
1677    
1678     token = parse_string (string);
1679     token_no = 0;
1680    
1681     while (strlen(token) > 0) {
1682     switch (token_no) {
1683     case 0: break;
1684     case 1: strcpy (t->name, token); break;
1685     case 2: t->matrix[0][0] = atof(token); break;
1686     case 3: t->matrix[0][1] = atof(token); break;
1687     case 4: t->matrix[0][2] = atof(token); break;
1688     case 5: t->matrix[1][0] = atof(token); break;
1689     case 6: t->matrix[1][1] = atof(token); break;
1690     case 7: t->matrix[1][2] = atof(token); break;
1691     case 8: t->matrix[2][0] = atof(token); break;
1692     case 9: t->matrix[2][1] = atof(token); break;
1693     case 10: t->matrix[2][2] = atof(token); break;
1694     case 11: t->matrix[3][0] = atof(token); break;
1695     case 12: t->matrix[3][1] = atof(token); break;
1696     case 13: t->matrix[3][2] = atof(token); break;
1697    
1698     default: abortmsg ("Error parsing transform", 1);
1699     }
1700    
1701     token = parse_string (NULL);
1702     token_no++;
1703     }
1704    
1705     t->matrix[0][3] = 0.0;
1706     t->matrix[1][3] = 0.0;
1707     t->matrix[2][3] = 0.0;
1708     t->matrix[3][3] = 1.0;
1709    
1710     cleanup_name (t->name);
1711    
1712     return t;
1713     }
1714    
1715    
1716     /* Parses a morph command and returns a pointer to the
1717     newly allocated morph */
1718     Morph *parse_morph (char *string)
1719     {
1720     Morph *m;
1721     char *token;
1722     int i, token_no;
1723    
1724     m = (Morph *)malloc (sizeof(*m));
1725     if (m == NULL)
1726     abortmsg ("Out of memory allocating morph", 1);
1727    
1728     mat_identity (m->matrix);
1729    
1730     token = parse_string (string);
1731    
1732     token = parse_string (NULL);
1733     strcpy (m->name, token);
1734    
1735     token = parse_string (NULL);
1736     m->count = atoi (token);
1737    
1738     if (strlen (m->name) == 0 || m->count < 1 || m->count > 4)
1739     abortmsg ("Error parsing morph command", 1);
1740    
1741     cleanup_name (m->name);
1742    
1743     for (i = 0; i < m->count; i++) {
1744     token = parse_string (NULL);
1745     strcpy (m->names[i], token);
1746    
1747     token = parse_string (NULL);
1748     m->weight[i] = atof (token);
1749    
1750     if (strlen (m->names[i]) == 0)
1751     abortmsg ("Error parsing morph command", 1);
1752    
1753     cleanup_name (m->names[i]);
1754     }
1755    
1756     token = parse_string (NULL);
1757     token_no = 0;
1758    
1759     while (strlen(token) > 0) {
1760     switch (token_no) {
1761     case 0: m->matrix[0][0] = atof(token); break;
1762     case 1: m->matrix[0][1] = atof(token); break;
1763     case 2: m->matrix[0][2] = atof(token); break;
1764     case 3: m->matrix[1][0] = atof(token); break;
1765     case 4: m->matrix[1][1] = atof(token); break;
1766     case 5: m->matrix[1][2] = atof(token); break;
1767     case 6: m->matrix[2][0] = atof(token); break;
1768     case 7: m->matrix[2][1] = atof(token); break;
1769     case 8: m->matrix[2][2] = atof(token); break;
1770     case 9: m->matrix[3][0] = atof(token); break;
1771     case 10: m->matrix[3][1] = atof(token); break;
1772     case 11: m->matrix[3][2] = atof(token); break;
1773    
1774     default: abortmsg ("Error parsing morph command", 1);
1775     }
1776    
1777     token = parse_string (NULL);
1778     token_no++;
1779     }
1780    
1781     m->matrix[0][3] = 0.0;
1782     m->matrix[1][3] = 0.0;
1783     m->matrix[2][3] = 0.0;
1784     m->matrix[3][3] = 1.0;
1785    
1786     return m;
1787     }
1788    
1789    
1790     /* Parses an omni light and returns a pointer to the
1791     newly allocated light */
1792     OmniLight *parse_omnilight (char *string)
1793     {
1794     OmniLight *o;
1795     char *token;
1796     int token_no;
1797    
1798     o = (OmniLight *)malloc (sizeof(*o));
1799     if (o == NULL)
1800     abortmsg ("Out of memory allocating omnilight", 1);
1801    
1802     token = parse_string (string);
1803     token_no = 0;
1804    
1805     while (strlen(token) > 0) {
1806     switch (token_no) {
1807     case 0: break;
1808     case 1: strcpy (o->name, token); break;
1809     case 2: o->pos[X] = atof (token); break;
1810     case 3: o->pos[Y] = atof (token); break;
1811     case 4: o->pos[Z] = atof (token); break;
1812     case 5: o->col.red = atof (token); break;
1813     case 6: o->col.green = atof (token); break;
1814     case 7: o->col.blue = atof (token); break;
1815    
1816     default: abortmsg ("Error parsing omnilight", 1);
1817     }
1818    
1819     token = parse_string (NULL);
1820     token_no++;
1821     }
1822    
1823     cleanup_name (o->name);
1824    
1825     return o;
1826     }
1827    
1828    
1829     /* Parses a spotlight and returns a pointer to the
1830     newly allocated spotlight */
1831     Spotlight *parse_spotlight (char *string)
1832     {
1833     Spotlight *s;
1834     char *token;
1835     int token_no;
1836    
1837     s = (Spotlight *)malloc (sizeof(*s));
1838     if (s == NULL)
1839     abortmsg ("Out of memory allocating spotlight", 1);
1840    
1841     token = parse_string (string);
1842     token_no = 0;
1843    
1844     while (strlen(token) > 0) {
1845     switch (token_no) {
1846     case 0: break;
1847     case 1: strcpy (s->name, token); break;
1848     case 2: s->pos[X] = atof (token); break;
1849     case 3: s->pos[Y] = atof (token); break;
1850     case 4: s->pos[Z] = atof (token); break;
1851     case 5: s->target[X] = atof (token); break;
1852     case 6: s->target[Y] = atof (token); break;
1853     case 7: s->target[Z] = atof (token); break;
1854     case 8: s->col.red = atof (token); break;
1855     case 9: s->col.green = atof (token); break;
1856     case 10: s->col.blue = atof (token); break;
1857     case 11: s->hotspot = atof (token); break;
1858     case 12: s->falloff = atof (token); break;
1859     case 13: break;
1860    
1861     default: abortmsg ("Error parsing spotlight", 1);
1862     }
1863    
1864     token = parse_string (NULL);
1865     token_no++;
1866     }
1867    
1868     cleanup_name (s->name);
1869    
1870     return s;
1871     }
1872    
1873    
1874     /* Parses a camera command and returns a pointer to the
1875     newly allocated camera */
1876     Camera *parse_camera (char *string)
1877     {
1878     Camera *c;
1879     char *token;
1880     int token_no;
1881    
1882     c = (Camera *)malloc (sizeof(*c));
1883     if (c == NULL)
1884     abortmsg ("Out of memory allocating camera", 1);
1885    
1886     token = parse_string (string);
1887     token_no = 0;
1888    
1889     while (strlen(token) > 0) {
1890     switch (token_no) {
1891     case 0: break;
1892     case 1: c->pos[X] = atof (token); break;
1893     case 2: c->pos[Y] = atof (token); break;
1894     case 3: c->pos[Z] = atof (token); break;
1895     case 4: c->target[X] = atof (token); break;
1896     case 5: c->target[Y] = atof (token); break;
1897     case 6: c->target[Z] = atof (token); break;
1898     case 7: c->bank = atof (token); break;
1899     case 8: c->lens = atof (token); break;
1900    
1901     default: abortmsg ("Error parsing camera", 1);
1902     }
1903    
1904     token = parse_string (NULL);
1905     token_no++;
1906     }
1907    
1908     return c;
1909     }
1910    
1911    
1912     /* Load the transforms, camera movements, etc for the specified frame */
1913     void read_frame (char *filename, int frame_no)
1914     {
1915     FILE *f;
1916     char fname[80];
1917     char string[256];
1918     char *token;
1919    
1920     /* Open the .vue file */
1921     strcpy (fname, filename); /* Make a copy we can mess with */
1922     add_ext (fname, "vue", 0);
1923    
1924     f = fopen (fname, "r");
1925     if (f == NULL) {
1926     printf ("Error opening file '%s'\n", fname);
1927     exit(1);
1928     }
1929    
1930     /* Load the specified frame */
1931     find_frame (f, frame_no);
1932    
1933     while (fgets (string, 256, f) != NULL) {
1934     token = parse_string (string);
1935    
1936     if (strcmp (token, "frame") == 0)
1937     break;
1938     else if (strcmp (token, "transform") == 0) {
1939     LIST_INSERT (trans_list, parse_transform (string));
1940     }
1941     else if (strcmp (token, "morph") == 0) {
1942     LIST_INSERT (morph_list, parse_morph (string));
1943     }
1944     else if (strcmp (token, "light") == 0) {
1945     LIST_INSERT (omni_list, parse_omnilight (string));
1946     }
1947     else if (strcmp (token, "spotlight") == 0) {
1948     LIST_INSERT (spot_list, parse_spotlight (string));
1949     }
1950     else if (strcmp (token, "camera") == 0) {
1951     if (cam_list != NULL)
1952     abortmsg ("ERROR - Multiple cameras in .vue file", 1);
1953    
1954     LIST_INSERT (cam_list, parse_camera (string));
1955     }
1956     else if (strcmp (token, "top") == 0)
1957     abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
1958     else if (strcmp (token, "bottom") == 0)
1959     abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
1960     else if (strcmp (token, "left") == 0)
1961     abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
1962     else if (strcmp (token, "right") == 0)
1963     abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
1964     else if (strcmp (token, "front") == 0)
1965     abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
1966     else if (strcmp (token, "back") == 0)
1967     abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
1968     else if (strcmp (token, "user") == 0)
1969     abortmsg ("ERROR - User viewports are not supported", 1);
1970     }
1971    
1972     fclose(f);
1973     }
1974    
1975    
1976     void find_frame (FILE *f, int frame_no)
1977     {
1978     char string[256];
1979     char *token;
1980     int frame = 0;
1981    
1982     /* Search the .vue file for the required frame */
1983     while (1) {
1984     /* Read the next line in the file */
1985     if (fgets (string, 256, f) == NULL) {
1986     printf ("Unable to locate frame #%d in .vue file\n", frame_no);
1987     exit(1);
1988     }
1989    
1990     token = parse_string (string);
1991    
1992     if (strcmp (token, "frame") == 0) {
1993     token = parse_string (NULL);
1994    
1995     if (strlen(token) == 0) {
1996     printf ("Unable to locate frame #%d in .vue file\n", frame_no);
1997     exit(1);
1998     }
1999    
2000     frame = atoi (token);
2001    
2002     if (frame == frame_no)
2003     break;
2004     }
2005     else if (strcmp (token, "VERSION") == 0) {
2006     token = parse_string (NULL);
2007    
2008     vue_version = atoi(token) / 100.0;
2009     }
2010     }
2011     }
2012    
2013    
2014     void save_animation()
2015     {
2016     Mesh *mesh, *master;
2017     Transform *t;
2018     Morph *m;
2019     Vector temp;
2020     int i, j;
2021    
2022     printf ("\n");
2023    
2024     for (t = trans_list; t != NULL; t = t->next) {
2025     printf ("Transforming object: %s\n", t->name);
2026    
2027     ani_matrix = &(t->matrix);
2028    
2029     mesh = LIST_FIND (mesh_list, t->name);
2030    
2031     if (mesh == NULL) {
2032     printf ("Unable to locate mesh object %s\n", t->name);
2033     exit(1);
2034     }
2035    
2036     write_mesh (out, mesh);
2037     }
2038    
2039     for (m = morph_list; m != NULL; m = m->next) {
2040     printf ("Morphing object: %s\n", m->name);
2041    
2042     ani_matrix = &(m->matrix);
2043    
2044     mesh = LIST_FIND (mesh_list, m->name);
2045     if (mesh == NULL) {
2046     printf ("Unable to locate mesh object %s\n", m->name);
2047     exit(1);
2048     }
2049    
2050     /* Make a copy to mess with */
2051     master = copy_mesh (mesh);
2052     master->hidden = FALSE;
2053    
2054     strcpy (master->name, m->name);
2055    
2056     for (i = 0; i < master->vertices; i++)
2057     vect_init (master->vertex[i], 0.0, 0.0, 0.0);
2058    
2059     for (i = 0; i < m->count; i++) {
2060     mesh = LIST_FIND (mesh_list, m->names[i]);
2061     if (mesh == NULL) {
2062     printf ("Unable to locate mesh object %s\n", m->names[0]);
2063     exit(1);
2064     }
2065    
2066     if (mesh->vertices != master->vertices)
2067     abortmsg ("Morphed objects do not contain the same number of vertices", 1);
2068    
2069     if (mesh->faces != master->faces)
2070     abortmsg ("Morphed objects do not contain the same number of faces", 1);
2071    
2072     for (j = 0; j < master->vertices; j++) {
2073     vect_transform (temp, mesh->vertex[j], mesh->invmatrix);
2074     vect_scale (temp, temp, m->weight[i]);
2075     vect_add (master->vertex[j], master->vertex[j], temp);
2076     }
2077     }
2078    
2079     for (i = 0; i < master->vertices; i++)
2080     vect_transform (master->vertex[i], master->vertex[i], master->matrix);
2081    
2082     write_mesh (out, master);
2083    
2084     free_mesh_data (master);
2085     free (master);
2086     }
2087    
2088     for (mesh = mesh_list; mesh != NULL; mesh = mesh->next)
2089     free_mesh_data (mesh);
2090     }
2091    
2092    
2093     /* Create a new mesh */
2094     Mesh *create_mesh (char *name, int vertices, int faces)
2095     {
2096     Mesh *new_mesh;
2097    
2098     new_mesh = malloc (sizeof(*new_mesh));
2099     if (new_mesh == NULL)
2100     abortmsg ("Out of memory allocating mesh", 1);
2101    
2102     strcpy (new_mesh->name, name);
2103    
2104     new_mesh->vertices = vertices;
2105    
2106     if (vertices <= 0)
2107     new_mesh->vertex = NULL;
2108     else {
2109     new_mesh->vertex = malloc (vertices * sizeof(*new_mesh->vertex));
2110     if (new_mesh->vertex == NULL)
2111     abortmsg ("Out of memory allocating mesh", 1);
2112     }
2113    
2114     new_mesh->faces = faces;
2115    
2116     if (faces <= 0) {
2117     new_mesh->face = NULL;
2118     new_mesh->mtl = NULL;
2119     }
2120     else {
2121     new_mesh->face = malloc (faces * sizeof(*new_mesh->face));
2122     if (new_mesh->face == NULL)
2123     abortmsg ("Out of memory allocating mesh", 1);
2124    
2125     new_mesh->mtl = malloc (faces * sizeof(*new_mesh->mtl));
2126     if (new_mesh->mtl == NULL)
2127     abortmsg ("Out of memory allocating mesh", 1);
2128     }
2129    
2130     vect_init (new_mesh->center, 0.0, 0.0, 0.0);
2131     vect_init (new_mesh->lengths, 0.0, 0.0, 0.0);
2132    
2133     mat_identity (new_mesh->matrix);
2134     mat_identity (new_mesh->invmatrix);
2135    
2136     new_mesh->hidden = FALSE;
2137     new_mesh->shadow = TRUE;
2138    
2139     return new_mesh;
2140     }
2141    
2142    
2143     /* Creates a duplicate copy of a mesh */
2144     Mesh *copy_mesh (Mesh *mesh)
2145     {
2146     Mesh *new_mesh;
2147     int i;
2148    
2149     new_mesh = create_mesh (mesh->name, mesh->vertices, mesh->faces);
2150    
2151     if (new_mesh == NULL)
2152     abortmsg ("Out of memory allocating mesh", 1);
2153    
2154     for (i = 0; i < mesh->vertices; i++)
2155     vect_copy (new_mesh->vertex[i], mesh->vertex[i]);
2156    
2157     for (i = 0; i < mesh->faces; i++) {
2158     new_mesh->face[i] = mesh->face[i];
2159     new_mesh->mtl[i] = mesh->mtl[i];
2160     }
2161    
2162     mat_copy (new_mesh->matrix, mesh->matrix);
2163     mat_copy (new_mesh->invmatrix, mesh->invmatrix);
2164    
2165     vect_copy (new_mesh->center, mesh->center);
2166     vect_copy (new_mesh->lengths, mesh->lengths);
2167    
2168     new_mesh->hidden = mesh->hidden;
2169     new_mesh->shadow = mesh->shadow;
2170    
2171     return new_mesh;
2172     }
2173    
2174    
2175     /* Free all data associated with mesh object */
2176     void free_mesh_data (Mesh *mesh)
2177     {
2178     if (mesh->vertex != NULL)
2179     free (mesh->vertex);
2180    
2181     if (mesh->face != NULL)
2182     free (mesh->face);
2183    
2184     if (mesh->mtl != NULL)
2185     free (mesh->mtl);
2186     }
2187    
2188    
2189     /* Updates the center (pivot) point of the mesh */
2190     void update_limits (Mesh *mesh)
2191     {
2192     Vector vmin = {+MAXFLOAT, +MAXFLOAT, +MAXFLOAT};
2193     Vector vmax = {-MAXFLOAT, -MAXFLOAT, -MAXFLOAT};
2194     int i;
2195    
2196     for (i = 0; i < mesh->vertices; i++) {
2197     vect_min (vmin, vmin, mesh->vertex[i]);
2198     vect_max (vmax, vmax, mesh->vertex[i]);
2199     }
2200    
2201     vect_add (mesh->center, vmin, vmax);
2202     vect_scale (mesh->center, mesh->center, 0.5);
2203    
2204     vect_sub (mesh->lengths, vmax, vmin);
2205     }
2206    
2207    
2208     /* Return the sub-string of 'str' that is before 'target' */
2209     char *before (char *str, char *target)
2210     {
2211     static char result[256];
2212     char *search;
2213    
2214     strncpy (result, str, 256);
2215     result[255] = '\0';
2216    
2217     search = strstr (result, target);
2218    
2219     if (search != NULL)
2220     *search = '\0';
2221    
2222     return result;
2223     }
2224    
2225    
2226     /* Return the sub-string of 'str' that is after 'target' */
2227     char *after (char *str, char *target)
2228     {
2229     static char result[256];
2230     char *search;
2231    
2232     search = strstr (str, target);
2233    
2234     if (search == NULL)
2235     strncpy (result, "", 256);
2236     else
2237     strncpy (result, search + strlen(target), 256);
2238    
2239     result[255] = '\0';
2240    
2241     return result;
2242     }
2243    
2244    
2245     /* Return the sub-string of 'str' that is between 'target1' and 'target2' */
2246     char *between (char *str, char *target1, char *target2)
2247     {
2248     static char result[256];
2249    
2250     strcpy (result, after (str, target1));
2251     strcpy (result, before (result, target2));
2252    
2253     return result;
2254     }
2255    
2256    
2257     /* Works like the C strtok() function except that it can handle */
2258     /* tokens enclosed in double quotes */
2259     char *parse_string (char *str)
2260     {
2261     static char result[256];
2262     static char *p;
2263     char QUOTE = '\"';
2264     int index;
2265    
2266     strcpy (result, "");
2267     index = 0;
2268    
2269     if (str != NULL)
2270     p = str;
2271    
2272     /* Find the start of the next token */
2273     while (isspace (*p))
2274     p++;
2275    
2276     if (*p == QUOTE) {
2277     p++;
2278    
2279     while (*p != '\0' && *p != QUOTE)
2280     result[index++] = *p++;
2281    
2282     if (*p == QUOTE)
2283     p++;
2284     }
2285     else {
2286     while (*p != '\0' && !isspace(*p))
2287     result[index++] = *p++;
2288     }
2289    
2290     result[index] = '\0';
2291    
2292     return result;
2293     }
2294    
2295    
2296     /* Convert character 'c' to upper case */
2297     char upcase (char c)
2298     {
2299     if (c >= 'a' && c <= 'z')
2300     c = c - 'a' + 'A';
2301    
2302     return c;
2303     }
2304    
2305    
2306     float colour_intens (Colour *colour)
2307     {
2308     return sqrt (colour->red * colour->red +
2309     colour->green * colour->green +
2310     colour->blue * colour->blue);
2311     }
2312    
2313    
2314     void parse_file()
2315     {
2316     Chunk chunk;
2317    
2318     start_chunk(&chunk);
2319    
2320     if (chunk.tag == 0x4D4D)
2321     parse_3ds (&chunk);
2322     else
2323     abortmsg ("Error: Input file is not .3DS format", 1);
2324    
2325     end_chunk (&chunk);
2326     }
2327    
2328    
2329     void parse_3ds (Chunk *mainchunk)
2330     {
2331     Chunk chunk;
2332    
2333     do {
2334     start_chunk (&chunk);
2335    
2336     if (chunk.end <= mainchunk->end) {
2337     switch (chunk.tag) {
2338     case 0x3D3D: parse_mdata (&chunk);
2339     break;
2340     }
2341     }
2342    
2343     end_chunk (&chunk);
2344     } while (chunk.end <= mainchunk->end);
2345     }
2346    
2347    
2348     void parse_mdata (Chunk *mainchunk)
2349     {
2350     Chunk chunk;
2351     Colour bgnd_colour;
2352    
2353     do {
2354     start_chunk (&chunk);
2355    
2356     if (chunk.end <= mainchunk->end) {
2357     switch (chunk.tag) {
2358     case 0x2100: parse_colour (&global_amb);
2359     break;
2360     case 0x1200: parse_colour (&bgnd_colour);
2361     break;
2362     case 0x1201: write_bgsolid (out, bgnd_colour);
2363     break;
2364     case 0x2200: parse_fog (&chunk);
2365     break;
2366     case 0x2210: parse_fog_bgnd();
2367     break;
2368     case 0x2201: write_fog (out, fog_colour, fog_distance);
2369     break;
2370     case 0xAFFF: parse_mat_entry (&chunk);
2371     break;
2372     case 0x4000: parse_named_object (&chunk);
2373     break;
2374     }
2375     }
2376    
2377     end_chunk (&chunk);
2378     } while (chunk.end <= mainchunk->end);
2379     }
2380    
2381    
2382     void parse_fog (Chunk *mainchunk)
2383     {
2384     Chunk chunk;
2385    
2386     (void)read_float();
2387     (void)read_float();
2388     fog_distance = read_float();
2389     (void)read_float();
2390    
2391     parse_colour (&fog_colour);
2392    
2393     do {
2394     start_chunk (&chunk);
2395    
2396     if (chunk.end <= mainchunk->end) {
2397     switch (chunk.tag) {
2398     case 0x2210: parse_fog_bgnd();
2399     break;
2400     }
2401     }
2402    
2403     end_chunk (&chunk);
2404     } while (chunk.end <= mainchunk->end);
2405     }
2406    
2407    
2408     void parse_fog_bgnd()
2409     {
2410    
2411     }
2412    
2413    
2414     void parse_mat_entry (Chunk *mainchunk)
2415     {
2416     Chunk chunk;
2417     MatProp *mprop;
2418    
2419     mprop = create_mprop();
2420    
2421     do {
2422     start_chunk (&chunk);
2423    
2424     if (chunk.end <= mainchunk->end) {
2425     switch (chunk.tag) {
2426     case 0xA000: strcpy (mprop->name, read_string());
2427     cleanup_name (mprop->name);
2428     break;
2429    
2430     case 0xA010: parse_colour (&mprop->ambient);
2431     break;
2432    
2433     case 0xA020: parse_colour (&mprop->diffuse);
2434     break;
2435    
2436     case 0xA030: parse_colour (&mprop->specular);
2437     break;
2438    
2439     case 0xA040: mprop->shininess = 100.0*parse_percentage();
2440     break;
2441    
2442     case 0xA050: mprop->transparency = parse_percentage();
2443     break;
2444    
2445     case 0xA080: mprop->self_illum = TRUE;
2446     break;
2447    
2448     case 0xA081: mprop->two_side = TRUE;
2449     break;
2450    
2451     case 0xA220: mprop->reflection = parse_percentage();
2452     (void)parse_mapname (&chunk);
2453     break;
2454    
2455     case 0xA310: if (mprop->reflection == 0.0)
2456     mprop->reflection = 1.0;
2457     break;
2458    
2459     case 0xA200: mprop->tex_strength = parse_percentage();
2460     strcpy (mprop->tex_map, parse_mapname (&chunk));
2461     break;
2462    
2463     case 0xA230: mprop->bump_strength = parse_percentage();
2464     strcpy (mprop->bump_map, parse_mapname (&chunk));
2465     break;
2466     }
2467     }
2468    
2469     end_chunk (&chunk);
2470     } while (chunk.end <= mainchunk->end);
2471    
2472     LIST_INSERT (mprop_list, mprop);
2473     }
2474    
2475    
2476     char *parse_mapname (Chunk *mainchunk)
2477     {
2478     static char name[80] = "";
2479     Chunk chunk;
2480    
2481     do {
2482     start_chunk (&chunk);
2483    
2484     if (chunk.end <= mainchunk->end) {
2485     switch (chunk.tag) {
2486     case 0xA300: strcpy (name, read_string());
2487     break;
2488     }
2489     }
2490    
2491     end_chunk (&chunk);
2492     } while (chunk.end <= mainchunk->end);
2493    
2494     return name;
2495     }
2496    
2497    
2498     void parse_named_object (Chunk *mainchunk)
2499     {
2500     Chunk chunk;
2501    
2502     strcpy (obj_name, read_string());
2503     cleanup_name (obj_name);
2504    
2505     printf ("Working on: %s\n", obj_name);
2506    
2507     mesh = NULL;
2508    
2509     do {
2510     start_chunk (&chunk);
2511    
2512     if (chunk.end <= mainchunk->end) {
2513     switch (chunk.tag) {
2514     case 0x4100: parse_n_tri_object (&chunk);
2515     break;
2516     case 0x4600: parse_n_direct_light (&chunk);
2517     break;
2518     case 0x4700: parse_n_camera();
2519     break;
2520     case 0x4010: if (mesh != NULL) mesh->hidden = TRUE;
2521     break;
2522     case 0x4012: if (mesh != NULL) mesh->shadow = FALSE;
2523     break;
2524     }
2525     }
2526    
2527     end_chunk (&chunk);
2528     } while (chunk.end <= mainchunk->end);
2529    
2530     if (mesh != NULL) {
2531     update_limits (mesh);
2532    
2533     if (frame >= 0)
2534     LIST_INSERT (mesh_list, mesh);
2535     else {
2536     write_mesh (out, mesh);
2537    
2538     free_mesh_data (mesh);
2539     free (mesh);
2540     }
2541     }
2542     }
2543    
2544    
2545     void parse_n_tri_object (Chunk *mainchunk)
2546     {
2547     Chunk chunk;
2548    
2549     mesh = create_mesh (obj_name, 0, 0);
2550    
2551     do {
2552     start_chunk (&chunk);
2553    
2554     if (chunk.end <= mainchunk->end) {
2555     switch (chunk.tag) {
2556     case 0x4110: parse_point_array();
2557     break;
2558     case 0x4120: parse_face_array (&chunk);
2559     break;
2560     case 0x4160: parse_mesh_matrix();
2561     break;
2562     }
2563     }
2564    
2565     end_chunk (&chunk);
2566     } while (chunk.end <= mainchunk->end);
2567     }
2568    
2569    
2570     void parse_point_array()
2571     {
2572     int i;
2573    
2574     mesh->vertices = read_word();
2575     mesh->vertex = malloc (mesh->vertices * sizeof(*(mesh->vertex)));
2576     if (mesh->vertex == NULL)
2577     abortmsg ("Out of memory allocating mesh", 1);
2578    
2579     for (i = 0; i < mesh->vertices; i++)
2580     read_point (mesh->vertex[i]);
2581     }
2582    
2583    
2584     void parse_face_array (Chunk *mainchunk)
2585     {
2586     Chunk chunk;
2587     int i;
2588    
2589     mesh->faces = read_word();
2590     mesh->face = malloc (mesh->faces * sizeof(*(mesh->face)));
2591     if (mesh->face == NULL)
2592     abortmsg ("Out of memory allocating mesh", 1);
2593    
2594     mesh->mtl = malloc (mesh->faces * sizeof(*(mesh->mtl)));
2595     if (mesh->mtl == NULL)
2596     abortmsg ("Out of memory allocating mesh", 1);
2597    
2598     for (i = 0; i < mesh->faces; i++) {
2599     mesh->face[i].a = read_word();
2600     mesh->face[i].b = read_word();
2601     mesh->face[i].c = read_word();
2602     (void)read_word();
2603    
2604     mesh->mtl[i] = NULL;
2605     }
2606    
2607     do {
2608     start_chunk (&chunk);
2609    
2610     if (chunk.end <= mainchunk->end) {
2611     switch (chunk.tag) {
2612     case 0x4130: parse_msh_mat_group();
2613     break;
2614     case 0x4150: parse_smooth_group();
2615     break;
2616     }
2617     }
2618    
2619     end_chunk (&chunk);
2620     } while (chunk.end <= mainchunk->end);
2621    
2622     for (i = 0; i < mesh->faces; i++) {
2623     if (mesh->mtl[i] == NULL)
2624     mesh->mtl[i] = update_materials ("Default", 0);
2625     }
2626     }
2627    
2628    
2629     void parse_msh_mat_group()
2630     {
2631     Material *new_mtl;
2632     char mtlname[80];
2633     int mtlcnt;
2634     int i, face;
2635    
2636     strcpy (mtlname, read_string());
2637     cleanup_name (mtlname);
2638    
2639     new_mtl = update_materials (mtlname, 0);
2640    
2641     mtlcnt = read_word();
2642    
2643     for (i = 0; i < mtlcnt; i++) {
2644     face = read_word();
2645     mesh->mtl[face] = new_mtl;
2646     }
2647     }
2648    
2649    
2650     void parse_smooth_group()
2651     {
2652    
2653     }
2654    
2655    
2656     void parse_mesh_matrix()
2657     {
2658     int i, j;
2659    
2660     if (mesh != NULL) {
2661     for (i = 0; i < 4; i++) {
2662     for (j = 0; j < 3; j++)
2663     mesh->matrix[i][j] = read_float();
2664     }
2665    
2666     mat_inv (mesh->invmatrix, mesh->matrix);
2667     }
2668     }
2669    
2670    
2671     void parse_n_direct_light (Chunk *mainchunk)
2672     {
2673     Chunk chunk;
2674     Spotlight *s;
2675     OmniLight *o;
2676     int light_off = FALSE;
2677     int spot_flag = FALSE;
2678    
2679     read_point (pos);
2680     parse_colour (&col);
2681    
2682     do {
2683     start_chunk (&chunk);
2684    
2685     if (chunk.end <= mainchunk->end) {
2686     switch (chunk.tag) {
2687     case 0x4620: light_off = TRUE;
2688     break;
2689     case 0x4610: parse_dl_spotlight();
2690     spot_flag = TRUE;
2691     break;
2692     }
2693     }
2694    
2695     end_chunk (&chunk);
2696     } while (chunk.end <= mainchunk->end);
2697    
2698     if (light_off)
2699     return;
2700    
2701     if (!spot_flag) {
2702     if (frame >= 0) {
2703     o = LIST_FIND (omni_list, obj_name);
2704    
2705     if (o != NULL) {
2706     pos[X] = o->pos[X];
2707     pos[Y] = o->pos[Y];
2708     pos[Z] = o->pos[Z];
2709     col = o->col;
2710     }
2711     }
2712    
2713     write_light (out, obj_name, pos, col);
2714     }
2715     else {
2716     if (frame >= 0) {
2717     s = LIST_FIND (spot_list, obj_name);
2718    
2719     if (s != NULL) {
2720     pos[X] = s->pos[X];
2721     pos[Y] = s->pos[Y];
2722     pos[Z] = s->pos[Z];
2723     target[X] = s->target[X];
2724     target[Y] = s->target[Y];
2725     target[Z] = s->target[Z];
2726     col = s->col;
2727     hotspot = s->hotspot;
2728     falloff = s->falloff;
2729     }
2730     }
2731    
2732     if (falloff <= 0.0)
2733     falloff = 180.0;
2734    
2735     if (hotspot <= 0.0)
2736     hotspot = 0.7*falloff;
2737    
2738     write_spot (out, obj_name, pos, target, col, hotspot, falloff);
2739     }
2740     }
2741    
2742    
2743     void parse_dl_spotlight()
2744     {
2745     read_point (target);
2746    
2747     hotspot = read_float();
2748     falloff = read_float();
2749     }
2750    
2751    
2752     void parse_n_camera()
2753     {
2754     float bank;
2755     float lens;
2756    
2757     read_point (pos);
2758     read_point (target);
2759     bank = read_float();
2760     lens = read_float();
2761    
2762     if (frame >= 0 && cam_list != NULL) {
2763     pos[X] = cam_list->pos[X];
2764     pos[Y] = cam_list->pos[Y];
2765     pos[Z] = cam_list->pos[Z];
2766     target[X] = cam_list->target[X];
2767     target[Y] = cam_list->target[Y];
2768     target[Z] = cam_list->target[Z];
2769     lens = cam_list->lens;
2770     bank = cam_list->bank;
2771     }
2772    
2773     write_camera (out, obj_name, pos, target, lens, bank);
2774     }
2775    
2776    
2777     void parse_colour (Colour *colour)
2778     {
2779     Chunk chunk;
2780     Colour_24 colour_24;
2781    
2782     start_chunk (&chunk);
2783    
2784     switch (chunk.tag) {
2785     case 0x0010: parse_colour_f (colour);
2786     break;
2787    
2788     case 0x0011: parse_colour_24 (&colour_24);
2789     colour->red = colour_24.red/255.0;
2790     colour->green = colour_24.green/255.0;
2791     colour->blue = colour_24.blue/255.0;
2792     break;
2793    
2794     default: abortmsg ("Error parsing colour", 1);
2795     }
2796    
2797     end_chunk (&chunk);
2798     }
2799    
2800    
2801     void parse_colour_f (Colour *colour)
2802     {
2803     colour->red = read_float();
2804     colour->green = read_float();
2805     colour->blue = read_float();
2806     }
2807    
2808    
2809     void parse_colour_24 (Colour_24 *colour)
2810     {
2811     colour->red = read_byte();
2812     colour->green = read_byte();
2813     colour->blue = read_byte();
2814     }
2815    
2816    
2817     float parse_percentage()
2818     {
2819     Chunk chunk;
2820     float percent = 0.0;
2821    
2822     start_chunk (&chunk);
2823    
2824     switch (chunk.tag) {
2825     case 0x0030: percent = parse_int_percentage()/100.0;
2826     break;
2827    
2828     case 0x0031: percent = parse_float_percentage();
2829     break;
2830    
2831     default: printf ("WARNING: Error parsing percentage");
2832     }
2833    
2834     end_chunk (&chunk);
2835    
2836     return percent;
2837     }
2838    
2839    
2840     short parse_int_percentage()
2841     {
2842     word percent = read_word();
2843    
2844     return percent;
2845     }
2846    
2847    
2848     float parse_float_percentage()
2849     {
2850     float percent = read_float();
2851    
2852     return percent;
2853     }
2854    
2855    
2856     void start_chunk (Chunk *chunk)
2857     {
2858     chunk->start = ftell(in);
2859     chunk->tag = read_word();
2860     chunk->length = read_dword();
2861     if (chunk->length < sizeof(word)+sizeof(dword))
2862     chunk->length = sizeof(word) + sizeof(dword);
2863     chunk->end = chunk->start + chunk->length;
2864     }
2865    
2866    
2867     void end_chunk (Chunk *chunk)
2868     {
2869     fseek (in, chunk->end, 0);
2870     }
2871    
2872    
2873     byte read_byte()
2874     {
2875     byte data;
2876    
2877     data = fgetc (in);
2878    
2879     return data;
2880     }
2881    
2882    
2883     word read_word()
2884     {
2885     word data;
2886    
2887     data = fgetc (in);
2888     data |= fgetc (in) << 8;
2889    
2890     return data;
2891     }
2892    
2893    
2894     dword read_dword()
2895     {
2896     dword data;
2897    
2898     data = read_word();
2899     data |= read_word() << 16;
2900    
2901     return data;
2902     }
2903    
2904    
2905     float read_float()
2906     {
2907     dword data;
2908    
2909     data = read_dword();
2910    
2911     return *(float *)&data;
2912     }
2913    
2914    
2915     void read_point (Vector v)
2916     {
2917     v[X] = read_float();
2918     v[Y] = read_float();
2919     v[Z] = read_float();
2920     }
2921    
2922    
2923     char *read_string()
2924     {
2925     static char string[80];
2926     int i;
2927    
2928     for (i = 0; i < 80; i++) {
2929     string[i] = read_byte();
2930    
2931     if (string[i] == '\0')
2932     break;
2933     }
2934    
2935     return string;
2936     }
2937    
2938    
2939     float findfov (float lens)
2940     {
2941     static float lens_table[13] =
2942     { 15.0, 17.0, 24.0, 35.0, 50.0, 85.0, 100.0, 135.0, 200.0,
2943     500.0, 625.0, 800.0, 1000.0 };
2944     static float fov_table[13] =
2945     { 115.0, 102.0, 84.0, 63.0, 46.0, 28.0, 24.0, 18.0,
2946     12.0, 5.0, 4.0, 3.125, 2.5 };
2947    
2948     float fov, f1, f2, l1, l2;
2949     int i;
2950    
2951     if (lens < 15.0)
2952     lens = 15.0;
2953     else if (lens > 1000.0)
2954     lens = 1000.0;
2955    
2956     for (i = 0; i < 13; i++)
2957     if (lens < lens_table[i])
2958     break;
2959    
2960     if (i == 13)
2961     i = 12;
2962     else if (i == 0)
2963     i = 1;
2964    
2965     f1 = fov_table[i-1];
2966     f2 = fov_table[i];
2967     l1 = lens_table[i-1];
2968     l2 = lens_table[i];
2969    
2970     fov = f1 + (lens - l1) * (f2 - f1) / (l2 - l1);
2971    
2972     return fov;
2973     }
2974    
2975