ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/3ds2mgf.c
Revision: 2.1
Committed: Fri Feb 18 00:40:25 2011 UTC (13 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R2, rad4R2P2, rad5R0, rad5R1, rad4R2, rad4R1, rad4R2P1, rad5R3, HEAD
Log Message:
Major code reorg, moving mgflib to common and introducing BSDF material

File Contents

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