ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/3ds2mgf.c
Revision: 1.5
Committed: Fri Jan 16 10:47:27 1998 UTC (26 years, 3 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 1.4: +2 -2 lines
Log Message:
changed M_PI definition to ward off long double problems

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