ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/3ds2mgf.c
Revision: 1.1
Committed: Thu Feb 8 11:08:03 1996 UTC (28 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

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