ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/3ds2mgf.c
Revision: 1.9
Committed: Wed Sep 5 02:41:19 2007 UTC (16 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R9
Changes since 1.8: +2 -5 lines
Log Message:
More copyright fixes

File Contents

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