ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/3ds2mgf.c
Revision: 1.5
Committed: Fri Jan 16 10:47:27 1998 UTC (26 years, 3 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 1.4: +2 -2 lines
Log Message:
changed M_PI definition to ward off long double problems

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