ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/3ds2mgf.c
Revision: 1.7
Committed: Sat Nov 15 17:54:06 2003 UTC (20 years, 5 months ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P1, rad3R6, rad3R6P1, rad3R8, rad3R7P2
Changes since 1.6: +4 -2 lines
Log Message:
Continued ANSIfication and reduced compile warnings.

File Contents

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