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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: 3ds2mgf.c,v 1.6 2003/02/28 20:11:29 greg Exp $";
3 #endif
4 /*
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 #define DEG(x) ((double)(180.0/M_PI)*(x))
50 #define RAD(x) ((double)(M_PI/180.0)*(x))
51
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 int no_opt = FALSE;
273 FILE *meshf = NULL;
274
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 char *progname;
354
355
356 int main (int argc, char *argv[])
357 {
358 char meshfname[128];
359 Material *m;
360 int i;
361
362 process_args (argc, argv);
363
364 if (!no_opt) {
365 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 } 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 }
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 if (!no_opt) {
426 write_summary (out);
427 fflush (out);
428
429 opt_finish();
430 } else if (meshf != NULL) {
431 fclose(meshf);
432 fprintf (out, "i %s\n", meshfname);
433 }
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 printf (" -op - Output to POV-Ray 2.0 format\n");
477 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 format = POV20; /* default if program name strange */
501
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
557 if (format == RAW || (format == MGF && smooth < 0.1))
558 no_opt = TRUE;
559 }
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 default:
930 printf ("Illegal format in write_summary() '%c'\n", format);
931 exit(1);
932 }
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 100000.0*(CIE_Y_r*col.red + CIE_Y_g*col.green + CIE_Y_b*col.blue));
1018 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 100000.0*(CIE_Y_r*col.red + CIE_Y_g*col.green + CIE_Y_b*col.blue));
1093 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 char curmat[80];
1608 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 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 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 if (feof(in)) {
2382 fprintf(stderr, "%s: unexpected EOF\n", progname);
2383 break;
2384 }
2385 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