ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/3ds2mgf.c
Revision: 1.10
Committed: Mon Nov 10 19:08:18 2008 UTC (15 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R0
Changes since 1.9: +15 -2 lines
Log Message:
Changed ".pic" extension to ".hdr" throughout

File Contents

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