1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <ctype.h>
6 #include <sys/stat.h>
7 #include <math.h>
8
9 #ifdef __MSW__
10 # include <windows.h>
11 #endif
12
13 #include "../include/string.h"
14 #include "../include/fio.h"
15 #include "../include/disk.h"
16
17 #include "gw.h"
18 #include "x3d.h"
19 #include "text3d.h"
20 #include "sfm.h"
21 #include "v3dhf.h"
22 #include "v3dtex.h"
23 #include "v3dmh.h"
24 #include "v3dmp.h"
25 #include "v3dmodel.h"
26 #include "v3dfio.h"
27
28 #include "cp.h"
29 #include "cpfio.h"
30 #include "sarreality.h"
31 #include "obj.h"
32 #include "sar.h"
33 #include "smoke.h"
34 #include "fire.h"
35 #include "weather.h"
36 #include "sartime.h"
37 #include "sarfio.h"
38 #include "simutils.h"
39 #include "simop.h"
40 #include "objsound.h"
41 #include "objutils.h"
42 #include "objio.h"
43 #include "config.h"
44
45 #include "runway/runway_displaced_threshold.x3d"
46 #include "runway/runway_midway_markers.x3d"
47 #include "runway/runway_td_markers.x3d"
48 #include "runway/runway_threshold.x3d"
49
50
51 /* Utilities */
52 static const char *NEXT_ARG(const char *s);
53 static const char *GET_ARG_S(const char *s, char **v);
54 static const char *GET_ARG_B(const char *s, Boolean *v);
55 static const char *GET_ARG_I(const char *s, int *v);
56 static const char *GET_ARG_F(const char *s, float *v);
57 static const char *GET_ARG_RGBA(const char *s, sar_color_struct *v);
58 static const char *GET_ARG_POS(const char *s, sar_position_struct *v);
59 static const char *GET_ARG_DIR(const char *s, sar_direction_struct *v);
60
61 /* Object Postload Checking */
62 static int SARObjLoadPostLoadCheck(
63 int obj_num, sar_object_struct *obj_ptr,
64 const char *filename
65 );
66
67 /* Visual Model Loading */
68 sar_visual_model_struct *SARObjLoadX3DDataVisualModel(
69 sar_core_struct *core_ptr, sar_scene_struct *scene,
70 char **x3d_data,
71 const sar_scale_struct *scale
72 );
73 sar_visual_model_struct *SARObjLoadTextVisualModel(
74 sar_core_struct *core_ptr, sar_scene_struct *scene,
75 float font_width, float font_height, /* In meters */
76 float character_spacing, /* In meters */
77 const char *s,
78 float *string_width /* In meters */
79 );
80
81 /* Parameter Loading */
82 int SARObjLoadTranslate(
83 sar_core_struct *core_ptr, sar_scene_struct *scene,
84 sar_object_struct *obj_ptr, sar_parm_translate_struct *p_translate
85 );
86 int SARObjLoadTranslateRandom(
87 sar_core_struct *core_ptr, sar_scene_struct *scene,
88 sar_object_struct *obj_ptr,
89 sar_parm_translate_random_struct *p_translate_random
90 );
91 static int SARObjLoadSoundSource(
92 sar_scene_struct *scene,
93 sar_sound_source_struct ***list, int *total,
94 const char *line, const char *filename, int line_num
95 );
96 int SARObjLoadTexture(
97 sar_core_struct *core_ptr, sar_scene_struct *scene,
98 sar_parm_texture_load_struct *p_texture_load
99 );
100 int SARObjLoadHelipad(
101 sar_core_struct *core_ptr, sar_scene_struct *scene,
102 sar_parm_new_helipad_struct *p_new_helipad
103 );
104 int SARObjLoadRunway(
105 sar_core_struct *core_ptr, sar_scene_struct *scene,
106 sar_parm_new_runway_struct *p_new_runway
107 );
108 int SARObjLoadHuman(
109 sar_core_struct *core_ptr, sar_scene_struct *scene,
110 sar_parm_new_human_struct *p_new_human
111 );
112 int SARObjLoadFire(
113 sar_core_struct *core_ptr, sar_scene_struct *scene,
114 sar_parm_new_fire_struct *p_new_fire
115 );
116 int SARObjLoadSmoke(
117 sar_core_struct *core_ptr, sar_scene_struct *scene,
118 sar_parm_new_smoke_struct *p_new_smoke
119 );
120 int SARObjLoadHeightField(
121 sar_core_struct *core_ptr,
122 int obj_num, sar_object_struct *obj_ptr,
123 sar_visual_model_struct *vmodel,
124 void *p, const char *filename, int line_num,
125 GLuint list
126 );
127
128 static void SARObjLoadProcessVisualPrimitive(
129 sar_core_struct *core_ptr,
130 int obj_num, sar_object_struct *obj_ptr,
131 sar_visual_model_struct *vmodel,
132 void *p, const char *filename, int line_num
133 );
134 static void SARObjLoadProcessVisualModel(
135 sar_core_struct *core_ptr,
136 int obj_num, sar_object_struct *obj_ptr,
137 sar_visual_model_struct *vmodel,
138 v3d_model_struct *v3d_model,
139 Boolean process_as_ir,
140 const char *filename, int line_num
141 );
142
143 static void SARObjLoadLine(
144 sar_core_struct *core_ptr,
145 int obj_num, sar_object_struct *obj_ptr,
146 const char *line, const char *filename, int line_num
147 );
148
149 int SARObjLoadFromFile(
150 sar_core_struct *core_ptr, int obj_num, const char *filename
151 );
152
153
154 #ifndef SAR_COMMENT_CHAR
155 # define SAR_COMMENT_CHAR '#'
156 #endif
157
158
159 #define ATOI(s) (((s) != NULL) ? atoi(s) : 0)
160 #define ATOL(s) (((s) != NULL) ? atol(s) : 0)
161 #define ATOF(s) (((s) != NULL) ? (float)atof(s) : 0.0f)
162 #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL)
163
164 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
165 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
166 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
167 #define STRLEN(s) (((s) != NULL) ? (int)strlen(s) : 0)
168 #define STRISEMPTY(s) (((s) != NULL) ? (*(s) == '\0') : 1)
169
170 #define RADTODEG(r) ((r) * 180.0 / PI)
171 #define DEGTORAD(d) ((d) * PI / 180.0)
172
173 #define ISCOMMENT(c) ((c) == SAR_COMMENT_CHAR)
174 #define ISCR(c) (((c) == '\n') || ((c) == '\r'))
175
176
177 static int last_begin_primitive_type;
178
179
180 /*
181 * Texture plane orientation codes:
182 */
183 #define TEX_ORIENT_NONE 0
184 #define TEX_ORIENT_XY 1
185 #define TEX_ORIENT_YZ 2
186 #define TEX_ORIENT_XZ 3
187
188 static Boolean tex_on;
189 static int tex_orient; /* One of TEX_ORIENT_* */
190
191 typedef struct {
192 float i, j; /* Position of `upper left' in meters */
193 float w, h; /* Size `to lower right' in meters */
194 } tex_coord_struct;
195 static tex_coord_struct tex_coord;
196
197
198 /*
199 * Seeks s past the current argument (if any) then past any blank
200 * characters until the next argument or end of string is reached.
201 */
NEXT_ARG(const char * s)202 static const char *NEXT_ARG(const char *s)
203 {
204 if(STRISEMPTY(s))
205 return(s);
206
207 while(!ISBLANK(*s) && (*s != '\0'))
208 s++;
209 while(ISBLANK(*s))
210 s++;
211
212 return(s);
213 }
214
215 /*
216 * Gets the argument at the current position of the string s, the
217 * return value will be a dynamically allocated string.
218 *
219 * Returns the pointer to the next argument or NULL if the end of
220 * the string is reached.
221 */
GET_ARG_S(const char * s,char ** v)222 static const char *GET_ARG_S(const char *s, char **v)
223 {
224 if(STRISEMPTY(s))
225 return(s);
226
227 if(*s == '\"')
228 {
229 int len;
230 const char *end = s + 1;
231
232 s++; /* Skip first quote character */
233
234 /* Calculate length of word in quotes, seek until next
235 * unescaped quote character or end of string
236 */
237 while((*end != '\"') && (*end != '\0'))
238 {
239 if(*end == '\\')
240 {
241 end++;
242 if(*end != '\0')
243 end++;
244 }
245 else
246 end++;
247 }
248 len = end - s;
249
250 if(len > 0)
251 {
252 char *s2 = (char *)malloc(len + 1);
253 memcpy(s2, s, len);
254 s2[len] = '\0';
255
256 free(*v);
257 *v = s2;
258 }
259
260 return(NEXT_ARG(end));
261 }
262 else
263 {
264 int len;
265 const char *end = s;
266
267 /* Calculate length of word, seek until next blank character
268 * or end of string
269 */
270 while(!ISBLANK(*end) && (*end != '\0'))
271 end++;
272 len = end - s;
273
274 if(len > 0)
275 {
276 char *s2 = (char *)malloc(len + 1);
277 memcpy(s2, s, len);
278 s2[len] = '\0';
279
280 free(*v);
281 *v = s2;
282 }
283
284 return(NEXT_ARG(s));
285 }
286 }
287
288 /*
289 * Gets the argument at the current position of the string s, the
290 * return value will a Boolean.
291 *
292 * Returns the pointer to the next argument or NULL if the end of
293 * the string is reached.
294 */
GET_ARG_B(const char * s,Boolean * v)295 static const char *GET_ARG_B(const char *s, Boolean *v)
296 {
297 if(STRISEMPTY(s))
298 return(s);
299
300 if(*s == '\"')
301 {
302 char c = s[1];
303 const char *end = s + 1;
304
305 s++; /* Skip first quote character */
306
307 /* Calculate length of word in quotes, seek until next
308 * unescaped quote character or end of string
309 */
310 while((*end != '\"') && (*end != '\0'))
311 {
312 if(*end == '\\')
313 {
314 end++;
315 if(*end != '\0')
316 end++;
317 }
318 else
319 end++;
320 }
321
322 /* Zero? */
323 if(c == '0')
324 *v = False;
325 /* No? */
326 else if(toupper(c) == 'N')
327 *v = False;
328 /* On or off? */
329 else if(toupper(c) == 'O')
330 *v = (toupper(s[1]) == 'N') ? True : False;
331 /* All else assume true */
332 else
333 *v = True;
334
335 return(NEXT_ARG(end));
336 }
337 else
338 {
339 char c = *s;
340
341 /* Zero? */
342 if(c == '0')
343 *v = False;
344 /* No? */
345 else if(toupper(c) == 'N')
346 *v = False;
347 /* On or off? */
348 else if(toupper(c) == 'O')
349 *v = (toupper(s[1]) == 'N') ? True : False;
350 /* All else assume true */
351 else
352 *v = True;
353
354 return(NEXT_ARG(s));
355 }
356 }
357
358 /*
359 * Gets the argument at the current position of the string s, the
360 * return value will an int.
361 *
362 * Returns the pointer to the next argument or NULL if the end of
363 * the string is reached.
364 */
GET_ARG_I(const char * s,int * v)365 static const char *GET_ARG_I(const char *s, int *v)
366 {
367 if(STRISEMPTY(s))
368 return(s);
369
370 if(*s == '\"')
371 {
372 const char *end = s + 1;
373
374 s++; /* Skip first quote character */
375
376 /* Calculate length of word in quotes, seek until next
377 * unescaped quote character or end of string
378 */
379 while((*end != '\"') && (*end != '\0'))
380 {
381 if(*end == '\\')
382 {
383 end++;
384 if(*end != '\0')
385 end++;
386 }
387 else
388 end++;
389 }
390
391 *v = ATOI(s);
392 return(NEXT_ARG(end));
393 }
394 else
395 {
396 *v = ATOI(s);
397 return(NEXT_ARG(s));
398 }
399 }
400
401 /*
402 * Gets the argument at the current position of the string s, the
403 * return value will an float.
404 *
405 * Returns the pointer to the next argument or NULL if the end of
406 * the string is reached.
407 */
GET_ARG_F(const char * s,float * v)408 static const char *GET_ARG_F(const char *s, float *v)
409 {
410 if(STRISEMPTY(s))
411 return(s);
412
413 if(*s == '\"')
414 {
415 const char *end = s + 1;
416
417 s++; /* Skip first quote character */
418
419 /* Calculate length of word in quotes, seek until next
420 * unescaped quote character or end of string
421 */
422 while((*end != '\"') && (*end != '\0'))
423 {
424 if(*end == '\\')
425 {
426 end++;
427 if(*end != '\0')
428 end++;
429 }
430 else
431 end++;
432 }
433
434 *v = ATOF(s);
435 return(NEXT_ARG(end));
436 }
437 else
438 {
439 *v = ATOF(s);
440 return(NEXT_ARG(s));
441 }
442 }
443
444 /*
445 * Gets the argument at the current position of the string s, the
446 * return value will a sar_color_struct.
447 *
448 * Returns the pointer to the next argument or NULL if the end of
449 * the string is reached.
450 */
GET_ARG_RGBA(const char * s,sar_color_struct * v)451 static const char *GET_ARG_RGBA(const char *s, sar_color_struct *v)
452 {
453 if(STRISEMPTY(s))
454 return(s);
455
456 if(*s == '\"')
457 {
458 s++;
459
460 if(*s == '#')
461 {
462 unsigned int r, g, b, a;
463 const char *end = s + 1;
464
465 s++; /* Skip '#' character */
466
467 /* Calculate length of word in quotes, seek until next
468 * unescaped quote character or end of string
469 */
470 while((*end != '\"') && (*end != '\0'))
471 {
472 if(*end == '\\')
473 {
474 end++;
475 if(*end != '\0')
476 end++;
477 }
478 else
479 end++;
480 }
481
482 sscanf(
483 s,
484 "%2x%2x%2x%2x",
485 &a, &r, &g, &b
486 );
487
488 v->a = (float)a / (float)0xff;
489 v->r = (float)r / (float)0xff;
490 v->g = (float)g / (float)0xff;
491 v->b = (float)b / (float)0xff;
492
493 return(NEXT_ARG(end));
494 }
495 else
496 {
497 s--;
498
499 s = GET_ARG_F(s, &v->r);
500 s = GET_ARG_F(s, &v->g);
501 s = GET_ARG_F(s, &v->b);
502 s = GET_ARG_F(s, &v->a);
503
504 return(s);
505 }
506 }
507 else
508 {
509 s = GET_ARG_F(s, &v->r);
510 s = GET_ARG_F(s, &v->g);
511 s = GET_ARG_F(s, &v->b);
512 s = GET_ARG_F(s, &v->a);
513
514 return(s);
515 }
516 }
517
518 /*
519 * Gets the argument at the current position of the string s, the
520 * return value will a sar_position_struct.
521 *
522 * Returns the pointer to the next argument or NULL if the end of
523 * the string is reached.
524 */
GET_ARG_POS(const char * s,sar_position_struct * v)525 static const char *GET_ARG_POS(const char *s, sar_position_struct *v)
526 {
527 if(STRISEMPTY(s))
528 return(s);
529
530 s = GET_ARG_F(s, &v->x);
531 s = GET_ARG_F(s, &v->y);
532 s = GET_ARG_F(s, &v->z);
533
534 return(s);
535 }
536
537 /*
538 * Gets the argument at the current position of the string s, the
539 * return value will a sar_direction_struct.
540 *
541 * Returns the pointer to the next argument or NULL if the end of
542 * the string is reached.
543 */
GET_ARG_DIR(const char * s,sar_direction_struct * v)544 static const char *GET_ARG_DIR(const char *s, sar_direction_struct *v)
545 {
546 float d = 0.0f;
547
548 if(STRISEMPTY(s))
549 return(s);
550
551 s = GET_ARG_F(s, &d);
552 v->heading = (float)DEGTORAD(d);
553 s = GET_ARG_F(s, &d);
554 v->pitch = (float)DEGTORAD(d);
555 s = GET_ARG_F(s, &d);
556 v->bank = (float)DEGTORAD(d);
557
558 return(s);
559 }
560
561 /*
562 * Completes the specified path by checking of the object that
563 * the path refers to exists locally or globally.
564 *
565 * Returns the full path to the object, the returned pointer must
566 * be deleted by the calling function.
567 */
COMPLETE_PATH(const char * path)568 char *COMPLETE_PATH(const char *path)
569 {
570 char *full_path;
571
572 if(path == NULL)
573 return(NULL);
574
575 if(ISPATHABSOLUTE(path))
576 {
577 full_path = STRDUP(path);
578 }
579 else
580 {
581 const char *s = PrefixPaths(dname.local_data, path);
582 struct stat stat_buf;
583 if((s != NULL) ? stat(s, &stat_buf) : True)
584 s = PrefixPaths(dname.global_data, path);
585 full_path = STRDUP(s);
586 }
587
588 return(full_path);
589 }
590
591
592 /*
593 * Object postload checking
594 *
595 * Returns number of errors.
596 */
SARObjLoadPostLoadCheck(int obj_num,sar_object_struct * obj_ptr,const char * filename)597 static int SARObjLoadPostLoadCheck(
598 int obj_num, sar_object_struct *obj_ptr,
599 const char *filename
600 )
601 {
602 int warnings = 0,
603 errors = 0;
604 sar_object_aircraft_struct *aircraft;
605 sar_object_ground_struct *ground;
606
607 if(obj_ptr == NULL)
608 {
609 errors++;
610 return(errors);
611 }
612
613 /* Invalid object type? */
614 if(obj_ptr->type < 0)
615 {
616 warnings++;
617 fprintf(
618 stderr,
619 "%s: Warning: Invalid object type \"%i\".\n",
620 filename, obj_ptr->type
621 );
622 }
623
624 /* No type specific data allocated? */
625 if(obj_ptr->data == NULL)
626 {
627 /* Ignore */
628 }
629
630 /* No standard visual model? */
631 if(obj_ptr->visual_model == NULL)
632 {
633 warnings++;
634 fprintf(
635 stderr,
636 "%s: Warning: Visual model \"standard\" not defined.\n",
637 filename
638 );
639 }
640
641 /* Check object type specific values */
642 switch(obj_ptr->type)
643 {
644 case SAR_OBJ_TYPE_GARBAGE:
645 case SAR_OBJ_TYPE_STATIC:
646 case SAR_OBJ_TYPE_AUTOMOBILE:
647 case SAR_OBJ_TYPE_WATERCRAFT:
648 break;
649 case SAR_OBJ_TYPE_AIRCRAFT:
650 #define PTR aircraft
651 PTR = SAR_OBJ_GET_AIRCRAFT(obj_ptr);
652 /* No flight dynamics model? */
653 if(PTR->fdm == NULL)
654 {
655 errors++;
656 fprintf(
657 stderr,
658 "%s: Error: Flight dynamics model was not created.\n",
659 filename
660 );
661 }
662 /* No cockpit visual model? */
663 if(PTR->visual_model_cockpit == NULL)
664 {
665 warnings++;
666 fprintf(
667 stderr,
668 "%s: Warning: Visual model \"cockpit\" not defined.\n",
669 filename
670 );
671 }
672 #undef PTR
673 break;
674
675 case SAR_OBJ_TYPE_GROUND:
676 #define PTR ground
677 PTR = SAR_OBJ_GET_GROUND(obj_ptr);
678
679 #undef PTR
680 break;
681 case SAR_OBJ_TYPE_RUNWAY:
682 case SAR_OBJ_TYPE_HELIPAD:
683 case SAR_OBJ_TYPE_HUMAN:
684 case SAR_OBJ_TYPE_SMOKE:
685 case SAR_OBJ_TYPE_FIRE:
686 case SAR_OBJ_TYPE_EXPLOSION:
687 case SAR_OBJ_TYPE_CHEMICAL_SPRAY:
688 case SAR_OBJ_TYPE_FUELTANK:
689 case SAR_OBJ_TYPE_PREMODELED:
690 break;
691 }
692
693
694 return(errors);
695 }
696
697 /*
698 * Loads a visual model from the given X3D data.
699 */
SARObjLoadX3DDataVisualModel(sar_core_struct * core_ptr,sar_scene_struct * scene,char ** x3d_data,const sar_scale_struct * scale)700 sar_visual_model_struct *SARObjLoadX3DDataVisualModel(
701 sar_core_struct *core_ptr, sar_scene_struct *scene,
702 char **x3d_data,
703 const sar_scale_struct *scale
704 )
705 {
706 sar_visual_model_struct *vmodel;
707 X3DInterpValues v;
708
709 if(x3d_data == NULL)
710 return(NULL);
711
712 /* Set up X3D data values */
713 v.flags = X3D_VALUE_FLAG_COORDINATE_SYSTEM |
714 ((scale != NULL) ? X3D_VALUE_FLAG_SCALE : 0) |
715 X3D_VALUE_FLAG_SKIP_TRANSLATES |
716 X3D_VALUE_FLAG_SKIP_ROTATES;
717 v.coordinate_system = X3D_COORDINATE_SYSTEM_XYZ;
718 if(scale != NULL)
719 {
720 v.scale_x = scale->x;
721 v.scale_y = scale->y;
722 v.scale_z = scale->z;
723 }
724
725 /* Create a new SAR visual model */
726 vmodel = SARVisualModelNew(
727 scene,
728 NULL, NULL /* No file or model name (so not shared) */
729 );
730 /* New visual model must not be shared */
731 if(SARVisualModelGetRefCount(vmodel) == 1)
732 {
733 GLuint list = (GLuint)SARVisualModelNewList(vmodel);
734 if(list != 0)
735 {
736 vmodel->load_state = SAR_VISUAL_MODEL_LOADING;
737 glNewList(list, GL_COMPILE);
738 X3DOpenDataGLOutput(
739 x3d_data, &v, NULL, 0
740 );
741 glEndList();
742 vmodel->load_state = SAR_VISUAL_MODEL_LOADED;
743 }
744 }
745
746 return(vmodel);
747 }
748
749 /*
750 * Loads a SAR visual model displaying the string s in 3d.
751 *
752 * Origin is in lower left corner of 3d string.
753 */
SARObjLoadTextVisualModel(sar_core_struct * core_ptr,sar_scene_struct * scene,float font_width,float font_height,float character_spacing,const char * s,float * string_width)754 sar_visual_model_struct *SARObjLoadTextVisualModel(
755 sar_core_struct *core_ptr, sar_scene_struct *scene,
756 float font_width, float font_height, /* In meters */
757 float character_spacing, /* In meters */
758 const char *s,
759 float *string_width /* In meters */
760 )
761 {
762 sar_visual_model_struct *vmodel;
763
764 if(string_width != NULL)
765 *string_width = 0.0f;
766
767 if((scene == NULL) || STRISEMPTY(s))
768 return(NULL);
769
770 /* Create a new SAR visual model */
771 vmodel = SARVisualModelNew(
772 scene,
773 NULL, NULL /* No filename or model name, so never shared */
774 );
775 /* Really a new (not shared) visual model? */
776 if(SARVisualModelGetRefCount(vmodel) == 1)
777 {
778 GLuint list = (GLuint)SARVisualModelNewList(vmodel);
779 if(list != 0)
780 {
781 vmodel->load_state = SAR_VISUAL_MODEL_LOADING;
782 glNewList(list, GL_COMPILE);
783 Text3DStringOutput(
784 font_width, font_height,
785 character_spacing,
786 s,
787 string_width
788 );
789 glEndList();
790 vmodel->load_state = SAR_VISUAL_MODEL_LOADED;
791 }
792 }
793
794 return(vmodel);
795 }
796
797 /*
798 * Handles a translate parameter with respect to the given inputs.
799 *
800 * Returns non-zero on error.
801 */
SARObjLoadTranslate(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_object_struct * obj_ptr,sar_parm_translate_struct * p_translate)802 int SARObjLoadTranslate(
803 sar_core_struct *core_ptr, sar_scene_struct *scene,
804 sar_object_struct *obj_ptr, sar_parm_translate_struct *p_translate
805 )
806 {
807 sar_position_struct new_pos;
808
809 if((obj_ptr == NULL) || (p_translate == NULL))
810 return(-1);
811
812 memcpy(&new_pos, &p_translate->translate, sizeof(sar_position_struct));
813
814 /* Check certain objects that need their position offsetted
815 * internally
816 */
817 if(obj_ptr->type == SAR_OBJ_TYPE_HUMAN)
818 {
819 /* Human objects fall at a constant rate, so we need to move
820 * it up twice the fall rate cycle to ensure that it
821 * `stays up' any hollow contact surfaces
822 */
823 new_pos.z -= (float)(2.0 * SAR_DEF_HUMAN_FALL_RATE);
824 }
825
826
827 /* Update the ground elevation (for more information on usage,
828 * see SARSimApplyArtificialForce() on how it uses
829 * SARSimFindGround()
830 */
831
832 /* Check objects of types that need to know about ground
833 * elevation
834 */
835 if((obj_ptr->type == SAR_OBJ_TYPE_AIRCRAFT) ||
836 (obj_ptr->type == SAR_OBJ_TYPE_HUMAN) ||
837 (obj_ptr->type == SAR_OBJ_TYPE_FIRE) ||
838 (obj_ptr->type == SAR_OBJ_TYPE_FUELTANK)
839 )
840 {
841 float ground_elevation = 0.0f;
842
843 ground_elevation += SARSimFindGround(
844 scene,
845 core_ptr->object, core_ptr->total_objects,
846 &new_pos /* Position of our object */
847 );
848 // if (obj_ptr->type == SAR_OBJ_TYPE_FIRE)
849 // printf("Setting up fire at %f\n", ground_elevation);
850
851 obj_ptr->ground_elevation_msl = ground_elevation;
852 }
853
854 /* Realize the new position */
855 SARSimWarpObject(
856 scene, obj_ptr,
857 &new_pos, NULL
858 );
859
860 return(0);
861 }
862
863 /*
864 * Translates the object to a random position.
865 *
866 * Returns non-zero on error.
867 */
SARObjLoadTranslateRandom(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_object_struct * obj_ptr,sar_parm_translate_random_struct * p_translate_random)868 int SARObjLoadTranslateRandom(
869 sar_core_struct *core_ptr, sar_scene_struct *scene,
870 sar_object_struct *obj_ptr,
871 sar_parm_translate_random_struct *p_translate_random
872 )
873 {
874 float rand_coeff = SARRandomCoeff(0);
875 float r = p_translate_random->radius_bound;
876 float z = p_translate_random->z_bound;
877 sar_position_struct *pos;
878
879 /* Calculate a random direction based on the random
880 * coefficient
881 */
882 float rand_theta = (float)SFMSanitizeRadians(rand_coeff * (2.0 * PI));
883
884 if((obj_ptr == NULL) || (p_translate_random == NULL))
885 return(-1);
886
887 pos = &obj_ptr->pos;
888
889 pos->x += (float)(sin(rand_theta) * rand_coeff * r);
890 pos->y += (float)(cos(rand_theta) * rand_coeff * r);
891 pos->z += (float)(rand_coeff * z);
892
893 /* Realize position */
894 SARSimWarpObject(scene, obj_ptr, pos, NULL);
895
896 return(0);
897 }
898
899 /*
900 * Loads a sound source.
901 *
902 * The string line should point to the argument portion.
903 */
SARObjLoadSoundSource(sar_scene_struct * scene,sar_sound_source_struct *** list,int * total,const char * line,const char * filename,int line_num)904 static int SARObjLoadSoundSource(
905 sar_scene_struct *scene,
906 sar_sound_source_struct ***list, int *total,
907 const char *line, const char *filename, int line_num
908 )
909 {
910 int i, sample_rate_limit;
911 const char *arg;
912 float range, range_far, cutoff;
913 char *s,
914 *name = NULL,
915 *sndobj_filename = NULL,
916 *sndobj_filename_far = NULL;
917 sar_position_struct pos;
918 sar_direction_struct dir;
919 sar_sound_source_struct *sndobj;
920
921 #define FREE_ALL { \
922 free(name); \
923 free(sndobj_filename); \
924 free(sndobj_filename_far); \
925 }
926
927 if(STRISEMPTY(line))
928 {
929 FREE_ALL
930 return(-1);
931 }
932
933 /* Format:
934 *
935 * <name>
936 * <range> <range_far>
937 * <x> <y> <z>
938 * <cutoff>
939 * <heading> <pitch> <bank>
940 * <sample_rate_limit>
941 * <sndobj_filename> <sndobj_filename_far>
942 */
943
944 /* Begin parsing argument */
945 arg = line;
946 while(ISBLANK(*arg))
947 arg++;
948
949 /* Name */
950 arg = GET_ARG_S(arg, &name);
951
952 /* Range */
953 arg = GET_ARG_F(arg, &range);
954
955 /* Range Far */
956 arg = GET_ARG_F(arg, &range_far);
957
958 /* Position */
959 arg = GET_ARG_POS(arg, &pos);
960
961
962 /* Cutoff */
963 arg = GET_ARG_F(arg, &cutoff);
964 cutoff = (float)DEGTORAD(cutoff);
965
966 /* Direction */
967 arg = GET_ARG_DIR(arg, &dir);
968
969 /* Sample Rate Limit */
970 arg = GET_ARG_I(arg, &sample_rate_limit);
971
972 /* SndObj Filename */
973 arg = GET_ARG_S(arg, &sndobj_filename);
974
975 /* SndObj Filename Far */
976 arg = GET_ARG_S(arg, &sndobj_filename_far);
977
978
979 /* Warn if sndobj_filename was not given */
980 s = sndobj_filename;
981 if(STRISEMPTY(s))
982 fprintf(stderr,
983 "%s: Line %i: Warning:\
984 Value for sound_source_new argument sndobj_filename was not given.\n",
985 filename, line_num
986 );
987 /* Do not warn for sndobj_filename_far */
988
989
990 /* Complete file names */
991 s = COMPLETE_PATH(sndobj_filename);
992 free(sndobj_filename);
993 sndobj_filename = s;
994
995 s = COMPLETE_PATH(sndobj_filename_far);
996 free(sndobj_filename_far);
997 sndobj_filename_far = s;
998
999
1000 /* Check if the sound files exist */
1001 s = sndobj_filename;
1002 if(!STRISEMPTY(s))
1003 {
1004 struct stat stat_buf;
1005 if(stat(s, &stat_buf))
1006 {
1007 char *s2 = STRDUP(strerror(errno));
1008 if(s2 == NULL)
1009 s2 = STRDUP("no such file");
1010 *s2 = toupper(*s2);
1011 fprintf(
1012 stderr,
1013 "%s: Line %i: Warning:\
1014 Sound source \"%s\" sndobj_filename \"%s\": %s.\n",
1015 filename, line_num,
1016 name, s, s2
1017 );
1018 free(s2);
1019 }
1020 }
1021 s = sndobj_filename_far;
1022 if(!STRISEMPTY(s))
1023 {
1024 struct stat stat_buf;
1025 if(stat(s, &stat_buf))
1026 {
1027 char *s2 = STRDUP(strerror(errno));
1028 if(s2 == NULL)
1029 s2 = STRDUP("no such file");
1030 *s2 = toupper(*s2);
1031 fprintf(
1032 stderr,
1033 "%s: Line %i: Warning:\
1034 Sound source \"%s\" sndobj_filename_far \"%s\": %s.\n",
1035 filename, line_num,
1036 name, s, s2
1037 );
1038 free(s2);
1039 }
1040 }
1041
1042
1043 /* Create new sound source */
1044 i = MAX(*total, 0);
1045 *total = i + 1;
1046 *list = (sar_sound_source_struct **)realloc(
1047 *list,
1048 (*total) * sizeof(sar_sound_source_struct *)
1049 );
1050 if(*list == NULL)
1051 {
1052 *total = 0;
1053 FREE_ALL
1054 return(-1);
1055 }
1056
1057 (*list)[i] = sndobj = SARSoundSourceNew(
1058 name,
1059 sndobj_filename,
1060 sndobj_filename_far,
1061 range,
1062 range_far,
1063 &pos, cutoff, &dir,
1064 sample_rate_limit
1065 );
1066
1067 FREE_ALL
1068 return(0);
1069 #undef FREE_ALL
1070 }
1071
1072
1073 /*
1074 * Loads a new texture specified by the values in p_texture_load
1075 * and stores it on the scene structure.
1076 *
1077 * If the scene structure already has a texture loaded that matches
1078 * the texture reference name specified in p_texture_load then
1079 * nothing will be done and 0 is returned.
1080 *
1081 * If the texture reference name specified in p_texture_load is
1082 * NULL or an empty string then a new texture will be loaded
1083 * implicitly.
1084 *
1085 * Returns non-zero on error.
1086 */
SARObjLoadTexture(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_parm_texture_load_struct * p_texture_load)1087 int SARObjLoadTexture(
1088 sar_core_struct *core_ptr, sar_scene_struct *scene,
1089 sar_parm_texture_load_struct *p_texture_load
1090 )
1091 {
1092 char *name, *path, *full_path;
1093 v3d_texture_ref_struct *t;
1094
1095 if((scene == NULL) || (p_texture_load == NULL))
1096 return(-1);
1097
1098 if(STRISEMPTY(p_texture_load->file))
1099 return(-1);
1100
1101 name = STRDUP(p_texture_load->name);
1102 path = STRDUP(p_texture_load->file);
1103
1104 /* Check if a texture with he same name is already loaded */
1105 if(STRISEMPTY(name))
1106 t = NULL;
1107 else
1108 t = SARGetTextureRefByName(scene, name);
1109 /* Is there a texture with the same name already loaded? */
1110 if(t != NULL)
1111 return(0);
1112
1113 /* Get the full path to the texture file */
1114 full_path = COMPLETE_PATH(path);
1115
1116 /* Load texture */
1117 t = V3DTextureLoadFromFile2DPreempt(
1118 full_path, name, V3D_TEX_FORMAT_RGBA
1119 );
1120 if(t != NULL)
1121 {
1122 /* Add this texture to the scene's list of textures */
1123 int i = MAX(scene->total_texture_refs, 0);
1124 scene->total_texture_refs = i + 1;
1125
1126 scene->texture_ref = (v3d_texture_ref_struct **)realloc(
1127 scene->texture_ref,
1128 scene->total_texture_refs * sizeof(v3d_texture_ref_struct *)
1129 );
1130 if(scene->texture_ref == NULL)
1131 {
1132 V3DTextureDestroy(t);
1133 free(full_path);
1134 free(path);
1135 free(name);
1136 return(-3);
1137 }
1138 scene->texture_ref[i] = t;
1139
1140 /* Set texture priority */
1141 V3DTexturePriority(t, p_texture_load->priority);
1142
1143 free(full_path);
1144 free(path);
1145 free(name);
1146 return(0);
1147 }
1148 else
1149 {
1150 /* Could not load texture */
1151 free(full_path);
1152 free(path);
1153 free(name);
1154 return(-1);
1155 }
1156 }
1157
1158 /*
1159 * Loads a helipad object from the given argument line string.
1160 *
1161 * Returns the newly created human object number or -1 on error.
1162 */
SARObjLoadHelipad(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_parm_new_helipad_struct * p_new_helipad)1163 int SARObjLoadHelipad(
1164 sar_core_struct *core_ptr, sar_scene_struct *scene,
1165 sar_parm_new_helipad_struct *p_new_helipad
1166 )
1167 {
1168 const char *s;
1169 int obj_num = -1;
1170 sar_object_struct *obj_ptr;
1171 sar_object_helipad_struct *helipad;
1172 const char *ref_obj_name;
1173 const char *tex_name = SAR_STD_TEXNAME_HELIPAD_PAVED;
1174 int ref_obj_num = -1;
1175 sar_object_struct *ref_obj_ptr = NULL;
1176
1177
1178 if((scene == NULL) || (p_new_helipad == NULL))
1179 return(obj_num);
1180
1181 /* Create a new Helipad */
1182 obj_num = SARObjNew(
1183 scene, &core_ptr->object, &core_ptr->total_objects,
1184 SAR_OBJ_TYPE_HELIPAD
1185 );
1186 obj_ptr = (obj_num > -1) ? core_ptr->object[obj_num] : NULL;
1187 if(obj_ptr == NULL)
1188 {
1189 obj_num = -1;
1190 return(obj_num);
1191 }
1192 helipad = SAR_OBJ_GET_HELIPAD(obj_ptr);
1193 if(helipad == NULL)
1194 return(obj_num);
1195
1196 /* Begin setting values */
1197
1198 /* Helipad flags */
1199 helipad->flags = p_new_helipad->flags;
1200
1201 /* Range */
1202 obj_ptr->range = SAR_HELIPAD_DEF_RANGE;
1203
1204 /* Style */
1205 s = p_new_helipad->style;
1206 if(!STRISEMPTY(s))
1207 {
1208 if(!strcasecmp(s, "ground_paved") ||
1209 !strcasecmp(s, "standard") ||
1210 !strcasecmp(s, "default")
1211 )
1212 {
1213 helipad->style = SAR_HELIPAD_STYLE_GROUND_PAVED;
1214 tex_name = SAR_STD_TEXNAME_HELIPAD_PAVED;
1215 }
1216 else if(!strcasecmp(s, "ground_bare"))
1217 {
1218 helipad->style = SAR_HELIPAD_STYLE_GROUND_BARE;
1219 tex_name = SAR_STD_TEXNAME_HELIPAD_BARE;
1220 }
1221 else if(!strcasecmp(s, "building"))
1222 {
1223 helipad->style = SAR_HELIPAD_STYLE_BUILDING;
1224 tex_name = SAR_STD_TEXNAME_HELIPAD_BUILDING;
1225 }
1226 else if(!strcasecmp(s, "vehicle"))
1227 {
1228 helipad->style = SAR_HELIPAD_STYLE_VEHICLE;
1229 tex_name = SAR_STD_TEXNAME_HELIPAD_VEHICLE;
1230 }
1231 else
1232 {
1233 fprintf(
1234 stderr,
1235 "Object #%i: Warning:\
1236 Unsupported helipad style \"%s\".\n",
1237 obj_num, s
1238 );
1239 helipad->style = SAR_HELIPAD_STYLE_GROUND_PAVED;
1240 tex_name = SAR_STD_TEXNAME_HELIPAD_PAVED;
1241 }
1242 }
1243 else
1244 {
1245 /* Set default style */
1246 helipad->style = SAR_HELIPAD_STYLE_GROUND_PAVED;
1247 tex_name = SAR_STD_TEXNAME_HELIPAD_PAVED;
1248 }
1249
1250 /* Size */
1251 helipad->length = (float)MAX(p_new_helipad->length, 1.0);
1252 helipad->width = (float)MAX(p_new_helipad->width, 1.0);
1253 helipad->recession = (float)MAX(p_new_helipad->recession, 0.0);
1254
1255 /* Specify contact bounds so that the helipad is landable */
1256 SARObjAddContactBoundsRectangular(
1257 obj_ptr, SAR_CRASH_FLAG_SUPPORT_SURFACE, 0,
1258 -(helipad->width / 2),
1259 (helipad->width / 2),
1260 -(helipad->length / 2),
1261 (helipad->length / 2),
1262 0.0f, 0.0f
1263 );
1264
1265 /* Label */
1266 s = p_new_helipad->label;
1267 helipad->label = STRDUP(s);
1268 if(!STRISEMPTY(s))
1269 {
1270 /* Generate visual model for label using 3d text */
1271 int len = MAX(STRLEN(s), 1);
1272 float font_height = (float)(
1273 MIN(helipad->width, helipad->length) *
1274 0.7 / len
1275 );
1276 float font_width = (float)(font_height * 0.8);
1277 helipad->label_vmodel = SARObjLoadTextVisualModel(
1278 core_ptr, scene,
1279 font_width, font_height,
1280 (float)(font_width * 0.05),
1281 s,
1282 &helipad->label_width
1283 );
1284 }
1285 else
1286 {
1287 /* No label */
1288 helipad->label_vmodel = NULL;
1289 helipad->label_width = 0;
1290 }
1291
1292 /* Light spacing */
1293 helipad->light_spacing = helipad->length / 10;
1294
1295 /* Texture reference number from scene */
1296 helipad->tex_num = SARGetTextureRefNumberByName(
1297 scene, tex_name
1298 );
1299
1300 /* Match reference object? */
1301 ref_obj_name = p_new_helipad->ref_obj_name;
1302 if((ref_obj_name != NULL) ? (*ref_obj_name != '\0') : False)
1303 {
1304 ref_obj_ptr = SARObjMatchPointerByName(
1305 scene, core_ptr->object, core_ptr->total_objects,
1306 ref_obj_name, &ref_obj_num
1307 );
1308 if(ref_obj_ptr != NULL)
1309 {
1310
1311 }
1312 else
1313 {
1314 fprintf(
1315 stderr,
1316 "Object #%i: Warning:\
1317 Unable to match reference object \"%s\" for helipad.\n",
1318 obj_num, ref_obj_name
1319 );
1320 }
1321 }
1322 /* Set reference object */
1323 helipad->ref_object = ref_obj_num;
1324 /* Make sure reference object is not this object */
1325 if(ref_obj_ptr == obj_ptr)
1326 {
1327 ref_obj_num = -1;
1328 ref_obj_ptr = NULL;
1329
1330 helipad->flags &= ~SAR_HELIPAD_FLAG_REF_OBJECT;
1331 helipad->flags &= ~SAR_HELIPAD_FLAG_FOLLOW_REF_OBJECT;
1332
1333 helipad->ref_object = -1;
1334 }
1335
1336 /* Set reference offset relative to the reference object */
1337 memcpy(
1338 &helipad->ref_offset,
1339 &p_new_helipad->ref_offset,
1340 sizeof(sar_position_struct)
1341 );
1342
1343 /* Set reference direction relative to the reference object */
1344 memcpy(
1345 &helipad->ref_dir,
1346 &p_new_helipad->ref_dir,
1347 sizeof(sar_direction_struct)
1348 );
1349
1350 /* Realize new position if there is a reference object */
1351 if((helipad->flags & SAR_HELIPAD_FLAG_REF_OBJECT) &&
1352 (helipad->flags & SAR_HELIPAD_FLAG_FOLLOW_REF_OBJECT)
1353 )
1354 SARSimWarpObjectRelative(
1355 scene, obj_ptr,
1356 core_ptr->object, core_ptr->total_objects, ref_obj_num,
1357 &helipad->ref_offset,
1358 &helipad->ref_dir
1359 );
1360
1361 return(obj_num);
1362 }
1363
1364 /*
1365 * Loads a runway object from the given argument line string.
1366 *
1367 * Returns the newly created human object number or -1 on error.
1368 */
SARObjLoadRunway(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_parm_new_runway_struct * p_new_runway)1369 int SARObjLoadRunway(
1370 sar_core_struct *core_ptr, sar_scene_struct *scene,
1371 sar_parm_new_runway_struct *p_new_runway
1372 )
1373 {
1374 const char *s;
1375 int obj_num = -1;
1376 sar_object_struct *obj_ptr;
1377 sar_object_runway_struct *runway;
1378
1379
1380 if((scene == NULL) || (p_new_runway == NULL))
1381 return(obj_num);
1382
1383 /* Create a new runway object */
1384 obj_num = SARObjNew(
1385 scene, &core_ptr->object, &core_ptr->total_objects,
1386 SAR_OBJ_TYPE_RUNWAY
1387 );
1388 obj_ptr = (obj_num > -1) ? core_ptr->object[obj_num] : NULL;
1389 if(obj_ptr == NULL)
1390 {
1391 obj_num = -1;
1392 return(obj_num);
1393 }
1394 runway = SAR_OBJ_GET_RUNWAY(obj_ptr);
1395 if(runway == NULL)
1396 return(obj_num);
1397
1398 /* Begin setting values */
1399
1400 /* Flags */
1401 runway->flags |= p_new_runway->flags;
1402
1403 /* Range */
1404 obj_ptr->range = p_new_runway->range;
1405
1406 /* Size */
1407 runway->length = p_new_runway->length;
1408 runway->width = p_new_runway->width;
1409
1410 /* Surface type */
1411 runway->surface_type = p_new_runway->surface_type;
1412
1413 /* Set contact bounds to ensure that the object is landable */
1414 SARObjAddContactBoundsRectangular(
1415 obj_ptr,
1416 SAR_CRASH_FLAG_SUPPORT_SURFACE, 0,
1417 -(runway->width / 2),
1418 (runway->width / 2),
1419 -(runway->length / 2),
1420 (runway->length / 2),
1421 0.0f, 0.0f
1422 );
1423
1424 /* Label */
1425 runway->north_label = STRDUP(p_new_runway->north_label);
1426 runway->south_label = STRDUP(p_new_runway->south_label);
1427
1428 /* Create visual models for labels using 3d text */
1429 s = p_new_runway->north_label;
1430 if(!STRISEMPTY(s))
1431 {
1432 int len = MAX(STRLEN(s), 1);
1433 float font_height = (float)(runway->width * 0.8 / len);
1434 float font_width = (float)(font_height * 0.8);
1435
1436 runway->north_label_vmodel = SARObjLoadTextVisualModel(
1437 core_ptr, scene,
1438 font_width, font_height,
1439 (float)(font_width * 0.15),
1440 s,
1441 &runway->north_label_width
1442 );
1443 }
1444 else
1445 {
1446 runway->north_label_vmodel = NULL;
1447 runway->north_label_width = 0;
1448 }
1449 s = p_new_runway->south_label;
1450 if(!STRISEMPTY(s))
1451 {
1452 int len = STRLEN(s);
1453 float font_height = (float)(runway->width * 0.8 / len);
1454 float font_width = (float)(font_height * 0.8);
1455
1456 runway->south_label_vmodel = SARObjLoadTextVisualModel(
1457 core_ptr, scene,
1458 font_width, font_height,
1459 (float)(font_width * 0.15),
1460 s,
1461 &runway->south_label_width
1462 );
1463 }
1464 else
1465 {
1466 runway->south_label_vmodel = NULL;
1467 runway->south_label_width = 0;
1468 }
1469
1470 /* Dashes */
1471 runway->dashes = (p_new_runway->dashes > 0) ?
1472 p_new_runway->dashes : 10;
1473
1474 /* Displaced thresholds */
1475 runway->north_displaced_threshold =
1476 p_new_runway->north_displaced_threshold;
1477 runway->south_displaced_threshold =
1478 p_new_runway->south_displaced_threshold;
1479
1480 /* Edge lighting */
1481 runway->edge_light_spacing = (float)(
1482 (p_new_runway->edge_light_spacing > 0.0f) ?
1483 p_new_runway->edge_light_spacing :
1484 (runway->length / 50)
1485 );
1486
1487 /* Approach lighting */
1488 runway->north_approach_lighting_flags = 0;
1489 runway->south_approach_lighting_flags = 0;
1490
1491 runway->tracer_anim_pos = 0;
1492 runway->tracer_anim_rate = (sar_grad_anim_t)(
1493 ((sar_grad_anim_t)-1) * 0.5
1494 );
1495
1496 /* Get texture number from scene */
1497 runway->tex_num = SARGetTextureRefNumberByName(
1498 scene, SAR_STD_TEXNAME_RUNWAY
1499 );
1500
1501 /* Begin loading visual models for runway decorations */
1502 /* Threshold */
1503 if(runway->flags & SAR_RUNWAY_FLAG_THRESHOLDS)
1504 {
1505 sar_scale_struct scale;
1506 scale.x = runway->width;
1507 scale.y = 50.0f;
1508 scale.z = 1.0f;
1509 runway->threshold_vmodel = SARObjLoadX3DDataVisualModel(
1510 core_ptr, scene,
1511 runway_threshold_x3d,
1512 &scale
1513 );
1514 }
1515 /* Touchdown markers */
1516 if(runway->flags & SAR_RUNWAY_FLAG_TD_MARKERS)
1517 {
1518 sar_scale_struct scale;
1519 scale.x = runway->width;
1520 scale.y = 30.0f;
1521 scale.z = 1.0f;
1522 runway->td_marker_vmodel = SARObjLoadX3DDataVisualModel(
1523 core_ptr, scene,
1524 runway_td_markers_x3d,
1525 &scale
1526 );
1527 }
1528 /* Midway markers */
1529 if(runway->flags & SAR_RUNWAY_FLAG_MIDWAY_MARKERS)
1530 {
1531 sar_scale_struct scale;
1532 scale.x = runway->width;
1533 scale.y = (float)(runway->length * 0.05);
1534 scale.z = 1.0f;
1535 runway->midway_marker_vmodel = SARObjLoadX3DDataVisualModel(
1536 core_ptr, scene,
1537 runway_midway_markers_x3d,
1538 &scale
1539 );
1540 }
1541 /* North displaced threshold */
1542 if(runway->north_displaced_threshold > 0.0f)
1543 {
1544 sar_scale_struct scale;
1545 scale.x = runway->width;
1546 scale.y = runway->north_displaced_threshold;
1547 scale.z = 1.0f;
1548 runway->north_displaced_threshold_vmodel =
1549 SARObjLoadX3DDataVisualModel(
1550 core_ptr, scene,
1551 runway_displaced_threshold_x3d,
1552 &scale
1553 );
1554 }
1555 /* South displaced threshold */
1556 if(runway->south_displaced_threshold > 0.0f)
1557 {
1558 sar_scale_struct scale;
1559 scale.x = runway->width;
1560 scale.y = runway->south_displaced_threshold;
1561 scale.z = 1.0f;
1562 runway->south_displaced_threshold_vmodel =
1563 SARObjLoadX3DDataVisualModel(
1564 core_ptr, scene,
1565 runway_displaced_threshold_x3d,
1566 &scale
1567 );
1568 }
1569
1570 return(obj_num);
1571 }
1572
1573 /*
1574 * Loads a human object from the given argument line string.
1575 *
1576 * Returns the newly created human object number or -1 on error.
1577 */
SARObjLoadHuman(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_parm_new_human_struct * p_new_human)1578 int SARObjLoadHuman(
1579 sar_core_struct *core_ptr, sar_scene_struct *scene,
1580 sar_parm_new_human_struct *p_new_human
1581 )
1582 {
1583 int obj_num = -1;
1584
1585 if((scene == NULL) || (p_new_human == NULL))
1586 return(obj_num);
1587
1588 /* Create new human object */
1589 obj_num = SARHumanCreate(
1590 core_ptr->human_data,
1591 scene, &core_ptr->object, &core_ptr->total_objects,
1592 p_new_human->flags,
1593 p_new_human->type_name
1594 );
1595
1596 return(obj_num);
1597 }
1598
1599 /*
1600 * Loads a fire object from the given argument line string.
1601 *
1602 * Returns the newly created fire object number or -1 on error.
1603 */
SARObjLoadFire(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_parm_new_fire_struct * p_new_fire)1604 int SARObjLoadFire(
1605 sar_core_struct *core_ptr, sar_scene_struct *scene,
1606 sar_parm_new_fire_struct *p_new_fire
1607 )
1608 {
1609 int obj_num = -1;
1610 sar_object_struct *obj_ptr;
1611 sar_object_fire_struct *fire;
1612 sar_position_struct pos;
1613
1614
1615 if((scene == NULL) || (p_new_fire == NULL))
1616 return(obj_num);
1617
1618 memset(&pos, 0x00, sizeof(sar_position_struct));
1619
1620 /* Create new fire object */
1621 obj_num = FireCreate(
1622 core_ptr, scene,
1623 &core_ptr->object, &core_ptr->total_objects,
1624 &pos, p_new_fire->radius, p_new_fire->height,
1625 -1,
1626 SAR_STD_TEXNAME_FIRE, SAR_STD_TEXNAME_FIRE_IR
1627 );
1628 obj_ptr = (obj_num > -1) ? core_ptr->object[obj_num] : NULL;
1629 if(obj_ptr == NULL)
1630 {
1631 obj_num = -1;
1632 return(obj_num);
1633 }
1634 fire = SAR_OBJ_GET_FIRE(obj_ptr);
1635 if(fire == NULL)
1636 return(obj_num);
1637
1638 /* Begin setting values */
1639
1640 /* Animation repeats */
1641 fire->total_frame_repeats = -1; /* Infinate */
1642
1643 obj_ptr->life_span = 0;
1644
1645 return(obj_num);
1646 }
1647
1648 /*
1649 * Loads a smoke object from the given argument line string.
1650 *
1651 * Returns the newly created fire object number or -1 on error.
1652 */
SARObjLoadSmoke(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_parm_new_smoke_struct * p_new_smoke)1653 int SARObjLoadSmoke(
1654 sar_core_struct *core_ptr, sar_scene_struct *scene,
1655 sar_parm_new_smoke_struct *p_new_smoke
1656 )
1657 {
1658 int obj_num = -1;
1659 sar_object_struct *obj_ptr;
1660 sar_position_struct pos;
1661 const char *tex_name = NULL;
1662
1663
1664 if((scene == NULL) || (p_new_smoke == NULL))
1665 return(obj_num);
1666
1667 memset(&pos, 0x00, sizeof(sar_position_struct));
1668
1669 /* Get name of smoke texture to use from the color code */
1670 switch(p_new_smoke->color_code)
1671 {
1672 case 0: /* Light */
1673 tex_name = SAR_STD_TEXNAME_SMOKE_LIGHT;
1674 break;
1675 case 1: /* Medium */
1676 tex_name = SAR_STD_TEXNAME_SMOKE_MEDIUM;
1677 break;
1678 case 2: /* Dark */
1679 tex_name = SAR_STD_TEXNAME_SMOKE_DARK;
1680 break;
1681 }
1682
1683 /* Create new smoke trail object */
1684 obj_num = SmokeCreate(
1685 scene, &core_ptr->object, &core_ptr->total_objects,
1686 SAR_SMOKE_TYPE_SMOKE, /* Smoke type */
1687 &pos, &p_new_smoke->offset, /* Position and unit spawn offset */
1688 p_new_smoke->radius_start,
1689 p_new_smoke->radius_max,
1690 p_new_smoke->radius_rate, /* May be -1.0 for autocalc */
1691 p_new_smoke->hide_at_max,
1692 p_new_smoke->total_units,
1693 p_new_smoke->respawn_int,
1694 tex_name,
1695 -1, /* No reference object */
1696 0 /* No limit on life span */
1697 );
1698 obj_ptr = (obj_num > -1) ? core_ptr->object[obj_num] : NULL;
1699 if(obj_ptr == NULL)
1700 {
1701 obj_num = -1;
1702 return(obj_num);
1703 }
1704
1705 /* Begin setting values */
1706
1707
1708
1709 return(obj_num);
1710 }
1711
1712 /*
1713 * Loads heightfield primitive p for the specified object.
1714 *
1715 * If the GL display list is 0 then no GL commands will be issued
1716 * and only the z height points will be recorded on the object.
1717 */
SARObjLoadHeightField(sar_core_struct * core_ptr,int obj_num,sar_object_struct * obj_ptr,sar_visual_model_struct * vmodel,void * p,const char * filename,int line_num,GLuint list)1718 int SARObjLoadHeightField(
1719 sar_core_struct *core_ptr,
1720 int obj_num, sar_object_struct *obj_ptr,
1721 sar_visual_model_struct *vmodel,
1722 void *p, const char *filename, int line_num,
1723 GLuint list /* Can be 0 */
1724 )
1725 {
1726 int status, grid_points_total;
1727 float x_length, y_length, z_length;
1728 int num_grids_x, num_grids_y;
1729 double grid_space_x, grid_space_y;
1730 double *zpoints = NULL;
1731
1732 char *full_path;
1733 sar_object_ground_struct *ground = NULL;
1734 mp_heightfield_load_struct *mp_heightfield_load =
1735 (mp_heightfield_load_struct *)p;
1736 v3d_hf_options_struct hfopt;
1737
1738 if(STRISEMPTY(mp_heightfield_load->path))
1739 return(-1);
1740
1741 ground = SAR_OBJ_GET_GROUND(obj_ptr);
1742
1743 /* Get the full path to the heightfield file */
1744 full_path = COMPLETE_PATH(mp_heightfield_load->path);
1745
1746 /* Begin loading the heightfield */
1747
1748 /* Get size of heightfield from heightfield load primitive */
1749 x_length = (float)mp_heightfield_load->x_length;
1750 y_length = (float)mp_heightfield_load->y_length;
1751 z_length = (float)mp_heightfield_load->z_length;
1752 if((x_length <= 0.0f) ||
1753 (y_length <= 0.0f) ||
1754 (z_length <= 0.0f)
1755 )
1756 {
1757 free(full_path);
1758 return(-2);
1759 }
1760
1761 glPushMatrix();
1762 {
1763 /* Translate */
1764 glTranslated(
1765 mp_heightfield_load->x,
1766 mp_heightfield_load->z,
1767 -mp_heightfield_load->y
1768 );
1769
1770 /* No rotations */
1771
1772 /* Set up heightfield options */
1773 hfopt.flags = (V3D_HF_OPT_FLAG_WINDING |
1774 V3D_HF_OPT_FLAG_SET_NORMAL | V3D_HF_OPT_FLAG_SET_TEXCOORD
1775 );
1776 hfopt.winding = V3D_HF_WIND_CCW;
1777 hfopt.set_normal = V3D_HF_SET_NORMAL_STREATCHED;
1778 hfopt.set_texcoord = V3D_HF_SET_TEXCOORD_ALWAYS;
1779
1780 /* Load heightfield */
1781 status = V3DHFLoadFromFile(
1782 full_path,
1783 x_length, y_length, z_length, /* Scaling in meters */
1784 &num_grids_x, &num_grids_y, /* Number of grids */
1785 &grid_space_x, &grid_space_y, /* Grid spacing in meters */
1786 &zpoints, /* Heightfield points return */
1787 (void *)list, /* GL display list */
1788 &hfopt
1789 );
1790 if(status)
1791 {
1792 /* Error loading heightfield */
1793 free(zpoints);
1794 free(full_path);
1795 return(-1);
1796 }
1797 }
1798 glPopMatrix();
1799
1800 /* Calculate total number of points */
1801 grid_points_total = num_grids_x * num_grids_y;
1802
1803 /* Calculate statistics */
1804 if((vmodel != NULL) && (list != 0))
1805 {
1806 vmodel->mem_size += grid_points_total * (
1807 (2 * 3 * 8 * sizeof(GLfloat)) +
1808 (3 * sizeof(GLuint))
1809 );
1810 vmodel->statements += (grid_points_total * 8) + 2;
1811 vmodel->primitives += grid_points_total * 2;
1812 }
1813
1814 /* Set newly loaded values to object */
1815 if(ground != NULL)
1816 {
1817 ground->x_trans = (float)mp_heightfield_load->x;
1818 ground->y_trans = (float)mp_heightfield_load->y;
1819 ground->z_trans = (float)mp_heightfield_load->z;
1820
1821 ground->x_len = (float)x_length;
1822 ground->y_len = (float)y_length;
1823
1824 ground->grid_points_x = num_grids_x;
1825 ground->grid_points_y = num_grids_y;
1826 ground->grid_points_total = grid_points_total;
1827
1828 ground->grid_x_spacing = (float)grid_space_x;
1829 ground->grid_y_spacing = (float)grid_space_y;
1830 ground->grid_z_spacing = (float)z_length;
1831
1832 /* Replace old heightfield z point data on ground object
1833 * structure with the newly allocated one
1834 */
1835 free(ground->z_point_value);
1836 ground->z_point_value = zpoints;
1837 zpoints = NULL; /* Reset zpoints to mark it as transfered */
1838 }
1839
1840 free(zpoints);
1841 free(full_path);
1842
1843 return(0);
1844 }
1845
1846 /*
1847 * Called by SARObjLoadProcessVisualModel().
1848 *
1849 * Parses and handles the specified V3D primitive p with the
1850 * specified values.
1851 */
SARObjLoadProcessVisualPrimitive(sar_core_struct * core_ptr,int obj_num,sar_object_struct * obj_ptr,sar_visual_model_struct * vmodel,void * p,const char * filename,int line_num)1852 static void SARObjLoadProcessVisualPrimitive(
1853 sar_core_struct *core_ptr,
1854 int obj_num, sar_object_struct *obj_ptr,
1855 sar_visual_model_struct *vmodel,
1856 void *p, const char *filename, int line_num
1857 )
1858 {
1859 int i, ptype, v_total = 0;
1860 Boolean need_end_primitive = False;
1861 mp_vertex_struct *ns = NULL, **nd = NULL;
1862 mp_vertex_struct *vs = NULL, **vd = NULL;
1863 mp_vertex_struct *tcs = NULL, **tcd = NULL;
1864
1865 mp_point_struct *mp_point;
1866 mp_line_struct *mp_line;
1867 mp_line_strip_struct *mp_line_strip;
1868 mp_line_loop_struct *mp_line_loop;
1869 mp_triangle_struct *mp_triangle;
1870 mp_triangle_strip_struct *mp_triangle_strip;
1871 mp_triangle_fan_struct *mp_triangle_fan;
1872 mp_quad_struct *mp_quad;
1873 mp_quad_strip_struct *mp_quad_strip;
1874 mp_polygon_struct *mp_polygon;
1875 mp_vertex_struct *first_normal_ptr = NULL, *n_ptr;
1876
1877 float x = 0.0f, y = 0.0f, z = 0.0f;
1878 float tx = 0.0f, ty = 0.0f;
1879
1880
1881 /* Handle by primitive type */
1882 ptype = V3DMPGetType(p);
1883 switch(ptype)
1884 {
1885 case V3DMP_TYPE_POINT:
1886 mp_point = (mp_point_struct *)p;
1887 if(last_begin_primitive_type != ptype)
1888 {
1889 vmodel->statements++;
1890 vmodel->mem_size += 2 * sizeof(GLuint);
1891 glBegin(GL_POINTS);
1892 last_begin_primitive_type = ptype;
1893 }
1894 ns = &mp_point->n[0];
1895 vs = &mp_point->v[0];
1896 tcs = &mp_point->tc[0];
1897 v_total = V3DMP_POINT_NVERTEX;
1898 break;
1899
1900 case V3DMP_TYPE_LINE:
1901 mp_line = (mp_line_struct *)p;
1902 if(last_begin_primitive_type != ptype)
1903 {
1904 vmodel->statements++;
1905 vmodel->mem_size += 2 * sizeof(GLuint);
1906 glBegin(GL_LINES);
1907 last_begin_primitive_type = ptype;
1908 }
1909 ns = &mp_line->n[0];
1910 vs = &mp_line->v[0];
1911 tcs = &mp_line->tc[0];
1912 v_total = V3DMP_LINE_NVERTEX;
1913 break;
1914
1915 case V3DMP_TYPE_LINE_STRIP:
1916 mp_line_strip = (mp_line_strip_struct *)p;
1917 vmodel->statements++;
1918 vmodel->mem_size += 2 * sizeof(GLuint);
1919 glBegin(GL_LINE_STRIP);
1920 need_end_primitive = True;
1921 nd = mp_line_strip->n;
1922 vd = mp_line_strip->v;
1923 tcd = mp_line_strip->tc;
1924 v_total = mp_line_strip->total;
1925 break;
1926
1927 case V3DMP_TYPE_LINE_LOOP:
1928 mp_line_loop = (mp_line_loop_struct *)p;
1929 vmodel->statements++;
1930 vmodel->mem_size += 2 * sizeof(GLuint);
1931 glBegin(GL_LINE_LOOP);
1932 need_end_primitive = True;
1933 nd = mp_line_loop->n;
1934 vd = mp_line_loop->v;
1935 tcd = mp_line_loop->tc;
1936 v_total = mp_line_loop->total;
1937 break;
1938
1939 case V3DMP_TYPE_TRIANGLE:
1940 mp_triangle = (mp_triangle_struct *)p;
1941 if(last_begin_primitive_type != ptype)
1942 {
1943 vmodel->statements++;
1944 vmodel->mem_size += 2 * sizeof(GLuint);
1945 glBegin(GL_TRIANGLES);
1946 last_begin_primitive_type = ptype;
1947 }
1948 ns = &mp_triangle->n[0];
1949 vs = &mp_triangle->v[0];
1950 tcs = &mp_triangle->tc[0];
1951 v_total = V3DMP_TRIANGLE_NVERTEX;
1952 break;
1953
1954 case V3DMP_TYPE_TRIANGLE_STRIP:
1955 mp_triangle_strip = (mp_triangle_strip_struct *)p;
1956 vmodel->statements++;
1957 vmodel->mem_size += 2 * sizeof(GLuint);
1958 glBegin(GL_TRIANGLE_STRIP);
1959 need_end_primitive = True;
1960 nd = mp_triangle_strip->n;
1961 vd = mp_triangle_strip->v;
1962 tcd = mp_triangle_strip->tc;
1963 v_total = mp_triangle_strip->total;
1964 break;
1965
1966 case V3DMP_TYPE_TRIANGLE_FAN:
1967 mp_triangle_fan = (mp_triangle_fan_struct *)p;
1968 vmodel->statements++;
1969 vmodel->mem_size += 2 * sizeof(GLuint);
1970 glBegin(GL_TRIANGLE_FAN);
1971 need_end_primitive = True;
1972 nd = mp_triangle_fan->n;
1973 vd = mp_triangle_fan->v;
1974 tcd = mp_triangle_fan->tc;
1975 v_total = mp_triangle_fan->total;
1976 break;
1977
1978 case V3DMP_TYPE_QUAD:
1979 mp_quad = (mp_quad_struct *)p;
1980 if(last_begin_primitive_type != ptype)
1981 {
1982 vmodel->statements++;
1983 vmodel->mem_size += 2 * sizeof(GLuint);
1984 glBegin(GL_QUADS);
1985 last_begin_primitive_type = ptype;
1986 }
1987 ns = &mp_quad->n[0];
1988 vs = &mp_quad->v[0];
1989 tcs = &mp_quad->tc[0];
1990 v_total = V3DMP_QUAD_NVERTEX;
1991 break;
1992
1993 case V3DMP_TYPE_QUAD_STRIP:
1994 mp_quad_strip = (mp_quad_strip_struct *)p;
1995 vmodel->statements++;
1996 vmodel->mem_size += 2 * sizeof(GLuint);
1997 glBegin(GL_QUAD_STRIP);
1998 need_end_primitive = True;
1999 nd = mp_quad_strip->n;
2000 vd = mp_quad_strip->v;
2001 tcd = mp_quad_strip->tc;
2002 v_total = mp_quad_strip->total;
2003 break;
2004
2005 case V3DMP_TYPE_POLYGON:
2006 mp_polygon = (mp_polygon_struct *)p;
2007 vmodel->statements++;
2008 vmodel->mem_size += 2 * sizeof(GLuint);
2009 glBegin(GL_POLYGON);
2010 need_end_primitive = True;
2011 nd = mp_polygon->n;
2012 vd = mp_polygon->v;
2013 tcd = mp_polygon->tc;
2014 v_total = mp_polygon->total;
2015 break;
2016 }
2017
2018
2019 /* Get pointer to first normal */
2020 i = 0;
2021 if(nd != NULL)
2022 first_normal_ptr = nd[i];
2023 else if(ns != NULL)
2024 first_normal_ptr = &ns[i];
2025 else
2026 first_normal_ptr = NULL;
2027
2028 /* Iterate through each vertex start from last to first,
2029 * becuase the winding stored on V3D model file is clockwise
2030 * and we need to handle it counter-clockwise
2031 */
2032 for(i = v_total - 1; i >= 0; i--)
2033 {
2034 /* Get vertex values but do not set just yet, we only need
2035 * the coordinates for now in order to set the texcoord
2036 * first (in case the texture is being plane oriented)
2037 */
2038 if((vd != NULL) ? (vd[i] != NULL) : False)
2039 {
2040 const mp_vertex_struct *v = vd[i];
2041 x = (float)v->x;
2042 y = (float)v->y;
2043 z = (float)v->z;
2044 }
2045 else if(vs != NULL)
2046 {
2047 const mp_vertex_struct *v = &vs[i];
2048 x = (float)v->x;
2049 y = (float)v->y;
2050 z = (float)v->z;
2051 }
2052
2053 /* Get normal and make sure it is not a zero vector, if it
2054 * is then use the first normal (if any).
2055 */
2056 if(nd != NULL)
2057 {
2058 n_ptr = nd[i];
2059 if((n_ptr->x == 0.0) && (n_ptr->y == 0.0) && (n_ptr->z == 0.0))
2060 n_ptr = first_normal_ptr;
2061 }
2062 else if(ns != NULL)
2063 {
2064 n_ptr = &ns[i];
2065 if((n_ptr->x == 0.0) && (n_ptr->y == 0.0) && (n_ptr->z == 0.0))
2066 n_ptr = first_normal_ptr;
2067 }
2068 else
2069 {
2070 n_ptr = first_normal_ptr; /* All elese use first normal */
2071 }
2072
2073 /* Got valid normal? */
2074 if(n_ptr != NULL)
2075 {
2076 vmodel->statements++;
2077 vmodel->mem_size += sizeof(GLuint) + (3 * sizeof(GLfloat));
2078 glNormal3d(n_ptr->x, n_ptr->z, -n_ptr->y);
2079 }
2080
2081 /* Texture enabled? */
2082 if(tex_on)
2083 {
2084 /* Set texture coordinates */
2085 switch(tex_orient)
2086 {
2087 case TEX_ORIENT_XY:
2088 if(tex_coord.w > 0.0f)
2089 tx = (x - tex_coord.i) / tex_coord.w;
2090 else
2091 tx = 0.0f;
2092 if(tex_coord.h > 0.0f)
2093 ty = (y - tex_coord.j) / tex_coord.h;
2094 else
2095 ty = 0.0f;
2096 vmodel->statements++;
2097 vmodel->mem_size += sizeof(GLuint) + (2 * sizeof(GLfloat));
2098 glTexCoord2f(tx, 1.0f - ty);
2099 break;
2100
2101 case TEX_ORIENT_YZ:
2102 if(tex_coord.w > 0.0f)
2103 tx = -(y - tex_coord.i) / tex_coord.w;
2104 else
2105 tx = 0.0f;
2106 if(tex_coord.h > 0.0f)
2107 ty = (z - tex_coord.j) / tex_coord.h;
2108 else
2109 ty = 0.0f;
2110 vmodel->statements++;
2111 vmodel->mem_size += sizeof(GLuint) + (2 * sizeof(GLfloat));
2112 glTexCoord2f(tx, 1.0f - ty);
2113 break;
2114
2115 case TEX_ORIENT_XZ:
2116 if(tex_coord.w > 0.0f)
2117 tx = (x - tex_coord.i) / tex_coord.w;
2118 else
2119 tx = 0.0f;
2120 if(tex_coord.h > 0.0f)
2121 ty = (z - tex_coord.j) / tex_coord.h;
2122 else
2123 ty = 0.0f;
2124 vmodel->statements++;
2125 vmodel->mem_size += sizeof(GLuint) + (2 * sizeof(GLfloat));
2126 glTexCoord2f(tx, 1.0f - ty);
2127 break;
2128
2129 default:
2130 if(tcd != NULL)
2131 {
2132 if(tcd[i] != NULL)
2133 {
2134 tx = (float)tcd[i]->x;
2135 ty = (float)tcd[i]->y;
2136 }
2137 }
2138 else if(tcs != NULL)
2139 {
2140 tx = (float)tcs[i].x;
2141 ty = (float)tcs[i].y;
2142 }
2143
2144 vmodel->statements++;
2145 vmodel->mem_size += sizeof(GLuint) + (2 * sizeof(GLfloat));
2146 glTexCoord2f(tx, 1.0f - ty);
2147 break;
2148 }
2149 }
2150
2151 /* Set vertex */
2152 vmodel->statements++;
2153 vmodel->mem_size += sizeof(GLuint) + (3 * sizeof(GLfloat));
2154 glVertex3d(x, z, -y);
2155 }
2156
2157 /* End primitive as needed */
2158 if(need_end_primitive)
2159 {
2160 vmodel->statements++;
2161 vmodel->mem_size += sizeof(GLuint);
2162 glEnd();
2163 need_end_primitive = False;
2164 }
2165 }
2166
2167 /*
2168 * Called by SARObjLoadFromFile().
2169 *
2170 * Processes the visual primitives in the V3D Visual Model into GL
2171 * commands (suitable for GL list recording).
2172 *
2173 * The vmodel's memory size statistics will be updated.
2174 */
SARObjLoadProcessVisualModel(sar_core_struct * core_ptr,int obj_num,sar_object_struct * obj_ptr,sar_visual_model_struct * vmodel,v3d_model_struct * v3d_model,Boolean process_as_ir,const char * filename,int line_num)2175 static void SARObjLoadProcessVisualModel(
2176 sar_core_struct *core_ptr,
2177 int obj_num, sar_object_struct *obj_ptr,
2178 sar_visual_model_struct *vmodel,
2179 v3d_model_struct *v3d_model,
2180 Boolean process_as_ir,
2181 const char *filename, int line_num
2182 )
2183 {
2184 int pn, ptype;
2185 void *p;
2186
2187 StateGLBoolean blend_state = False;
2188
2189 GLuint list = (GLuint)vmodel->data;
2190 gw_display_struct *display = core_ptr->display;
2191 state_gl_struct *state_gl = &display->state_gl;
2192 sar_scene_struct *scene = core_ptr->scene;
2193
2194
2195 /* Reset GL states */
2196 V3DTextureSelect(NULL);
2197 tex_on = False;
2198 tex_orient = TEX_ORIENT_NONE;
2199 /* Do not reset color, model file should set it, if not then it means
2200 * it relys on other code to set it
2201 *
2202 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
2203 */
2204
2205 /* Reset last begin primitive type */
2206 last_begin_primitive_type = -1;
2207
2208 /* Set initial GL states for IR processing? */
2209 if(process_as_ir)
2210 {
2211
2212 }
2213
2214 /* Iterate through each V3D model primitive */
2215 for(pn = 0; pn < v3d_model->total_primitives; pn++)
2216 {
2217 p = v3d_model->primitive[pn];
2218 if(p == NULL)
2219 continue;
2220
2221 /* Get primitive type */
2222 ptype = V3DMPGetType(p);
2223
2224 /* Check if last begin primitive differs from this one
2225 *
2226 * If it does then glEnd() needs to be called to end the
2227 * first glBegin() that was not ended
2228 */
2229 if((last_begin_primitive_type != ptype) &&
2230 (last_begin_primitive_type > -1)
2231 )
2232 {
2233 glEnd();
2234 vmodel->mem_size += sizeof(GLuint);
2235 vmodel->statements++;
2236 last_begin_primitive_type = -1;
2237 }
2238
2239 switch(ptype)
2240 {
2241 const mp_comment_struct *mp_comment;
2242 const mp_color_struct *mp_color;
2243 const mp_texture_select_struct *mp_texture_select;
2244 const mp_texture_orient_xy_struct *mp_texture_xy;
2245 const mp_texture_orient_yz_struct *mp_texture_yz;
2246 const mp_texture_orient_xz_struct *mp_texture_xz;
2247 const mp_heightfield_load_struct *mp_heightfield_load;
2248
2249 case V3DMP_TYPE_COMMENT:
2250 mp_comment = (mp_comment_struct *)p;
2251 /* Ignore comment lines in V3D visual models */
2252 break;
2253
2254 case V3DMP_TYPE_POINT:
2255 case V3DMP_TYPE_LINE:
2256 case V3DMP_TYPE_LINE_STRIP:
2257 case V3DMP_TYPE_LINE_LOOP:
2258 case V3DMP_TYPE_TRIANGLE:
2259 case V3DMP_TYPE_TRIANGLE_STRIP:
2260 case V3DMP_TYPE_TRIANGLE_FAN:
2261 case V3DMP_TYPE_QUAD:
2262 case V3DMP_TYPE_QUAD_STRIP:
2263 case V3DMP_TYPE_POLYGON:
2264 vmodel->primitives++;
2265 SARObjLoadProcessVisualPrimitive(
2266 core_ptr, obj_num, obj_ptr, vmodel,
2267 p, filename, 0
2268 );
2269 break;
2270
2271 case V3DMP_TYPE_COLOR:
2272 mp_color = (mp_color_struct *)p;
2273 if(process_as_ir)
2274 break;
2275 vmodel->mem_size += 4 * sizeof(GLfloat);
2276 vmodel->statements++;
2277 glColor4f(
2278 (GLfloat)mp_color->r,
2279 (GLfloat)mp_color->g,
2280 (GLfloat)mp_color->b,
2281 (GLfloat)mp_color->a
2282 );
2283 /* Enable GL_BLEND if alpha is less than 1.0 */
2284 if(mp_color->a < 1.0f)
2285 {
2286 if(!blend_state)
2287 {
2288 vmodel->mem_size += (3 * sizeof(GLuint)) +
2289 (2 * sizeof(GLuint));
2290 vmodel->statements += 3;
2291 StateGLEnableF(state_gl, GL_BLEND, GL_TRUE);
2292 glBlendFunc(
2293 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
2294 );
2295 StateGLDisableF(
2296 state_gl, GL_ALPHA_TEST, GL_TRUE
2297 );
2298 blend_state = True;
2299 }
2300 }
2301 else
2302 {
2303 if(blend_state)
2304 {
2305 vmodel->mem_size += 2 * sizeof(GLuint);
2306 vmodel->statements += 2;
2307 StateGLDisableF(state_gl, GL_BLEND, GL_TRUE);
2308 StateGLEnableF(
2309 state_gl, GL_ALPHA_TEST, GL_TRUE
2310 );
2311 blend_state = False;
2312 }
2313 }
2314 break;
2315
2316 case V3DMP_TYPE_TEXTURE_SELECT:
2317 mp_texture_select = (mp_texture_select_struct *)p;
2318 if(!process_as_ir)
2319 {
2320 const char *texture_name = mp_texture_select->name;
2321 vmodel->mem_size += 2 * sizeof(GLuint);
2322 vmodel->statements++;
2323 if(STRISEMPTY(texture_name))
2324 {
2325 /* Empty string implies unselect texture */
2326 V3DTextureSelect(NULL);
2327 tex_on = False;
2328 tex_orient = TEX_ORIENT_NONE;
2329 }
2330 else
2331 {
2332 /* Select texture */
2333 v3d_texture_ref_struct *t = SARGetTextureRefByName(
2334 scene, texture_name
2335 );
2336 if(t == NULL)
2337 {
2338 fprintf(
2339 stderr,
2340 "%s: Warning: Texture \"%s\" not defined (on the model or globally).\n",
2341 filename, texture_name
2342 );
2343 tex_on = False;
2344 tex_orient = TEX_ORIENT_NONE;
2345 }
2346 else
2347 {
2348 tex_on = True;
2349 V3DTextureSelect(t);
2350 }
2351 }
2352 }
2353 break;
2354
2355 case V3DMP_TYPE_TEXTURE_ORIENT_XY:
2356 mp_texture_xy = (mp_texture_orient_xy_struct *)p;
2357 if(process_as_ir)
2358 break;
2359 tex_orient = TEX_ORIENT_XY;
2360 tex_coord.i = (float)mp_texture_xy->x;
2361 tex_coord.j = (float)mp_texture_xy->y;
2362 tex_coord.w = (float)mp_texture_xy->dx;
2363 tex_coord.h = (float)mp_texture_xy->dy;
2364 break;
2365
2366 case V3DMP_TYPE_TEXTURE_ORIENT_YZ:
2367 mp_texture_yz = (mp_texture_orient_yz_struct *)p;
2368 if(process_as_ir)
2369 break;
2370 tex_orient = TEX_ORIENT_YZ;
2371 tex_coord.i = (float)mp_texture_yz->y;
2372 tex_coord.j = (float)mp_texture_yz->z;
2373 tex_coord.w = (float)mp_texture_yz->dy;
2374 tex_coord.h = (float)mp_texture_yz->dz;
2375 break;
2376
2377 case V3DMP_TYPE_TEXTURE_ORIENT_XZ:
2378 mp_texture_xz = (mp_texture_orient_xz_struct *)p;
2379 if(process_as_ir)
2380 break;
2381 tex_orient = TEX_ORIENT_XZ;
2382 tex_coord.i = (float)mp_texture_xz->x;
2383 tex_coord.j = (float)mp_texture_xz->z;
2384 tex_coord.w = (float)mp_texture_xz->dx;
2385 tex_coord.h = (float)mp_texture_xz->dz;
2386 break;
2387
2388 case V3DMP_TYPE_TEXTURE_OFF:
2389 if(process_as_ir)
2390 break;
2391 vmodel->mem_size += 2 * sizeof(GLuint);
2392 vmodel->statements++;
2393 V3DTextureSelect(NULL);
2394 tex_on = False;
2395 tex_orient = TEX_ORIENT_NONE;
2396 break;
2397
2398 case V3DMP_TYPE_HEIGHTFIELD_LOAD:
2399 mp_heightfield_load = (mp_heightfield_load_struct *)p;
2400 SARObjLoadHeightField(
2401 core_ptr, obj_num, obj_ptr, vmodel,
2402 p, filename, 0,
2403 list
2404 );
2405 break;
2406 }
2407 } /* Iterate through each V3D model primitive */
2408
2409 /* Check if last_begin_primitive_type is valid, if it is then
2410 * that means we need to call glEnd() to end a previous
2411 * glBegin()
2412 */
2413 if(last_begin_primitive_type > -1)
2414 {
2415 vmodel->mem_size += sizeof(GLuint);
2416 vmodel->statements++;
2417 glEnd();
2418 last_begin_primitive_type = -1;
2419 }
2420
2421 /* Check if blending is still enabled */
2422 if(blend_state)
2423 {
2424 vmodel->mem_size += 2 * sizeof(GLuint);
2425 vmodel->statements += 2;
2426 StateGLDisableF(state_gl, GL_BLEND, GL_TRUE);
2427 StateGLEnableF(state_gl, GL_ALPHA_TEST, GL_TRUE);
2428 blend_state = False;
2429 }
2430
2431 /* End GL display list */
2432 glEndList();
2433
2434 /* Mark this SAR Visual Model as finished loading */
2435 vmodel->load_state = SAR_VISUAL_MODEL_LOADED;
2436
2437 }
2438
2439
2440 /*
2441 * Called by SARObjLoadFromFile().
2442 *
2443 * Handles "other data" lines from V3D Models.
2444 */
SARObjLoadLine(sar_core_struct * core_ptr,int obj_num,sar_object_struct * obj_ptr,const char * line,const char * filename,int line_num)2445 static void SARObjLoadLine(
2446 sar_core_struct *core_ptr,
2447 int obj_num, sar_object_struct *obj_ptr,
2448 const char *line, const char *filename, int line_num
2449 )
2450 {
2451 char *s;
2452 char parm[256];
2453 const char *arg;
2454
2455 sar_object_aircraft_struct *aircraft = NULL;
2456 sar_object_ground_struct *ground = NULL;
2457 sar_obj_rotor_struct *rotor = NULL;
2458 sar_obj_part_struct *aileron_left_ptr = NULL,
2459 *aileron_right_ptr = NULL,
2460 *rudder_top_ptr = NULL,
2461 *rudder_bottom_ptr = NULL,
2462 *elevator_ptr = NULL,
2463 *cannard_ptr = NULL,
2464 *aileron_elevator_left_ptr = NULL,
2465 *aileron_elevator_right_ptr = NULL,
2466 *flap_ptr = NULL,
2467 *abrake_ptr = NULL,
2468 *door_ptr = NULL,
2469 *lgear_ptr = NULL;
2470 sar_external_fueltank_struct *eft_ptr = NULL;
2471 sar_scene_struct *scene = core_ptr->scene;
2472 Boolean is_player = (scene->player_obj_ptr == obj_ptr) ? True : False;
2473
2474 if(STRISEMPTY(line))
2475 return;
2476
2477 /* Seek past spaces */
2478 while(ISBLANK(*line))
2479 line++;
2480
2481 /* Skip comments */
2482 if(ISCOMMENT(*line))
2483 return;
2484
2485 /* Get object type specific values */
2486 switch(obj_ptr->type)
2487 {
2488 case SAR_OBJ_TYPE_GARBAGE:
2489 case SAR_OBJ_TYPE_STATIC:
2490 case SAR_OBJ_TYPE_AUTOMOBILE:
2491 case SAR_OBJ_TYPE_WATERCRAFT:
2492 break;
2493 case SAR_OBJ_TYPE_AIRCRAFT:
2494 aircraft = SAR_OBJ_GET_AIRCRAFT(obj_ptr);
2495 if(aircraft != NULL)
2496 {
2497 int i = aircraft->total_rotors;
2498 if(i > 0)
2499 rotor = aircraft->rotor[i - 1];
2500 }
2501 break;
2502 case SAR_OBJ_TYPE_GROUND:
2503 ground = SAR_OBJ_GET_GROUND(obj_ptr);
2504 break;
2505 case SAR_OBJ_TYPE_RUNWAY:
2506 case SAR_OBJ_TYPE_HELIPAD:
2507 case SAR_OBJ_TYPE_HUMAN:
2508 case SAR_OBJ_TYPE_SMOKE:
2509 case SAR_OBJ_TYPE_FIRE:
2510 case SAR_OBJ_TYPE_EXPLOSION:
2511 case SAR_OBJ_TYPE_CHEMICAL_SPRAY:
2512 case SAR_OBJ_TYPE_FUELTANK:
2513 case SAR_OBJ_TYPE_PREMODELED:
2514 break;
2515 }
2516 /* Get pointers to last (newest) object parts of each type */
2517 if(True)
2518 {
2519 sar_obj_part_struct *part;
2520
2521 #define GET_PART(_type_) { \
2522 int i = 0; \
2523 sar_obj_part_struct *p; \
2524 part = NULL; \
2525 while(True) { \
2526 p = SARObjGetPartPtr(obj_ptr, (_type_), i); \
2527 if(p != NULL) { \
2528 part = p; i++; \
2529 } else { \
2530 break; \
2531 } \
2532 } \
2533 }
2534 GET_PART(SAR_OBJ_PART_TYPE_AILERON_LEFT);
2535 aileron_left_ptr = part;
2536
2537 GET_PART(SAR_OBJ_PART_TYPE_AILERON_RIGHT);
2538 aileron_right_ptr = part;
2539
2540 GET_PART(SAR_OBJ_PART_TYPE_RUDDER_TOP);
2541 rudder_top_ptr = part;
2542
2543 GET_PART(SAR_OBJ_PART_TYPE_RUDDER_BOTTOM);
2544 rudder_bottom_ptr = part;
2545
2546 GET_PART(SAR_OBJ_PART_TYPE_ELEVATOR);
2547 elevator_ptr = part;
2548
2549 GET_PART(SAR_OBJ_PART_TYPE_CANNARD);
2550 cannard_ptr = part;
2551
2552 GET_PART(SAR_OBJ_PART_TYPE_AILERON_ELEVATOR_LEFT);
2553 aileron_elevator_left_ptr = part;
2554
2555 GET_PART(SAR_OBJ_PART_TYPE_AILERON_ELEVATOR_RIGHT);
2556 aileron_elevator_right_ptr = part;
2557
2558 GET_PART(SAR_OBJ_PART_TYPE_FLAP);
2559 flap_ptr = part;
2560
2561 GET_PART(SAR_OBJ_PART_TYPE_LANDING_GEAR);
2562 lgear_ptr = part;
2563
2564 GET_PART(SAR_OBJ_PART_TYPE_DOOR_RESCUE);
2565 door_ptr = part;
2566
2567 #undef GET_PART
2568 }
2569
2570
2571 /* Begin parsing line */
2572
2573 /* Get parameter */
2574 strncpy(parm, line, 256);
2575 parm[256 - 1] = '\0';
2576 s = parm;
2577 while(!ISBLANK(*s) && (*s != '\0'))
2578 s++;
2579 *s = '\0';
2580
2581 /* Seek to start of argument(s) in the line */
2582 arg = line;
2583 while(!ISBLANK(*arg) && (*arg != '\0'))
2584 arg++;
2585 while(ISBLANK(*arg))
2586 arg++;
2587
2588 /* Begin handling parameter */
2589 if(True)
2590 {
2591 /* Texture Base Directory */
2592 if(!strcasecmp(parm, "texture_base_directory") ||
2593 !strcasecmp(parm, "texture_base_dir")
2594 )
2595 {
2596 /* Ignore since it is loaded from the V3D header */
2597 }
2598 /* Texture Load */
2599 else if(!strcasecmp(parm, "texture_load"))
2600 {
2601 /* Ignore since it is loaded from the V3D header */
2602 }
2603 /* Version */
2604 else if(!strcasecmp(parm, "version"))
2605 {
2606 /* Arguments:
2607 *
2608 * <major> <minor> <release>
2609 */
2610 int major = 0,
2611 minor = 0,
2612 release = 0;
2613
2614 arg = GET_ARG_I(arg, &major);
2615 arg = GET_ARG_I(arg, &minor);
2616 arg = GET_ARG_I(arg, &release);
2617
2618 if((major > PROG_VERSION_MAJOR) ||
2619 (minor > PROG_VERSION_MINOR) ||
2620 (release > PROG_VERSION_RELEASE)
2621 )
2622 {
2623 Boolean need_warn = False;
2624 if(major > PROG_VERSION_MAJOR)
2625 need_warn = True;
2626 else if((major == PROG_VERSION_MAJOR) &&
2627 (minor > PROG_VERSION_MINOR)
2628 )
2629 need_warn = True;
2630 else if((major == PROG_VERSION_MAJOR) &&
2631 (minor == PROG_VERSION_MINOR) &&
2632 (release == PROG_VERSION_RELEASE)
2633 )
2634 need_warn = True;
2635 if(need_warn)
2636 fprintf(
2637 stderr,
2638 "%s: Line %i: Warning:\
2639 File format version %i.%i.%i is newer than\
2640 program version %i.%i.%i.\n",
2641 filename, line_num,
2642 major, minor, release,
2643 PROG_VERSION_MAJOR, PROG_VERSION_MINOR, PROG_VERSION_RELEASE
2644 );
2645 }
2646 }
2647 /* Name */
2648 else if(!strcasecmp(parm, "name"))
2649 {
2650 /* Arguments:
2651 *
2652 * <name>
2653 */
2654 char *name = NULL;
2655
2656 arg = GET_ARG_S(arg, &name);
2657
2658 free(obj_ptr->name);
2659 obj_ptr->name = name;
2660 }
2661 /* Description */
2662 else if(!strcasecmp(parm, "desc") ||
2663 !strcasecmp(parm, "description")
2664 )
2665 {
2666 /* Ignore */
2667 }
2668 /* Type */
2669 else if(!strcasecmp(parm, "type"))
2670 {
2671 /* Ignore since the object type should already be set
2672 * prior to calling this function
2673 */
2674 }
2675 /* Range */
2676 else if(!strcasecmp(parm, "range"))
2677 {
2678 /* Arguments:
2679 *
2680 * <range>
2681 */
2682 float range = 0.0f;
2683
2684 arg = GET_ARG_F(arg, &range);
2685
2686 if(range < 0.0f)
2687 fprintf(stderr,
2688 "%s: Line %i: Warning:\
2689 Value for %s argument range=%f should not be negative.\n",
2690 filename, line_num,
2691 parm, range
2692 );
2693
2694 obj_ptr->range = (float)MAX(range, 0.0);
2695 }
2696 /* Range Far */
2697 else if(!strcasecmp(parm, "range_far"))
2698 {
2699 /* Arguments:
2700 *
2701 * <range_far>
2702 */
2703 float range_far = 0.0f;
2704
2705 arg = GET_ARG_F(arg, &range_far);
2706
2707 if(range_far < 0.0f)
2708 fprintf(stderr,
2709 "%s: Line %i: Warning:\
2710 Value for %s argument range_far=%f should not be negative.\n",
2711 filename, line_num,
2712 parm, range_far
2713 );
2714
2715 obj_ptr->range_far = (float)MAX(range_far, 0.0);
2716 }
2717 /* No Depth Test */
2718 else if(!strcasecmp(parm, "no_depth_test"))
2719 {
2720 obj_ptr->flags |= SAR_OBJ_FLAG_NO_DEPTH_TEST;
2721 }
2722 /* Smooth Shading */
2723 else if(!strcasecmp(parm, "shade_model_smooth"))
2724 {
2725 obj_ptr->flags |= SAR_OBJ_FLAG_SHADE_MODEL_SMOOTH;
2726 }
2727 /* Flat Shading */
2728 else if(!strcasecmp(parm, "shade_model_flat"))
2729 {
2730 obj_ptr->flags &= ~SAR_OBJ_FLAG_SHADE_MODEL_SMOOTH;
2731 }
2732 /* Offset Polygons */
2733 else if(!strcasecmp(parm, "offset_polygons"))
2734 {
2735 obj_ptr->flags |= SAR_OBJ_FLAG_POLYGON_OFFSET;
2736 }
2737 /* Show Night Model At Dawn */
2738 else if(!strcasecmp(parm, "show_night_model_at_dawn"))
2739 {
2740 obj_ptr->flags |= SAR_OBJ_FLAG_NIGHT_MODEL_AT_DAWN;
2741 }
2742 /* Show Night Model At Dusk */
2743 else if(!strcasecmp(parm, "show_night_model_at_dusk"))
2744 {
2745 obj_ptr->flags |= SAR_OBJ_FLAG_NIGHT_MODEL_AT_DUSK;
2746 }
2747 /* Show Far Model Day Only */
2748 else if(!strcasecmp(parm, "show_far_day_only"))
2749 {
2750 obj_ptr->flags |= SAR_OBJ_FLAG_FAR_MODEL_DAY_ONLY;
2751 }
2752 /* Crash Flags */
2753 else if(!strcasecmp(parm, "crash_flags"))
2754 {
2755 /* Arguments:
2756 *
2757 * <can_crash?> <causes_crash?> <support_surface?>
2758 * <crash_type>
2759 */
2760 sar_contact_bounds_struct *cb = obj_ptr->contact_bounds;
2761 Boolean can_crash = False,
2762 causes_crash = False,
2763 support_surface = False;
2764 int crash_type;
2765
2766 arg = GET_ARG_B(arg, &can_crash);
2767 arg = GET_ARG_B(arg, &causes_crash);
2768 arg = GET_ARG_B(arg, &support_surface);
2769 arg = GET_ARG_I(arg, &crash_type);
2770
2771 /* Create contact bounds as needed */
2772 if(cb == NULL)
2773 obj_ptr->contact_bounds = cb = SAR_CONTACT_BOUNDS(
2774 calloc(1, sizeof(sar_contact_bounds_struct))
2775 );
2776
2777 if(cb != NULL)
2778 {
2779 cb->crash_flags = 0; /* Must reset flags */
2780
2781 /* Crash into other objects? */
2782 if(can_crash)
2783 cb->crash_flags |= SAR_CRASH_FLAG_CRASH_OTHER;
2784
2785 /* Causes crash? */
2786 if(causes_crash)
2787 cb->crash_flags |= SAR_CRASH_FLAG_CRASH_CAUSE;
2788
2789 /* Support surface? */
2790 if(support_surface)
2791 cb->crash_flags |= SAR_CRASH_FLAG_SUPPORT_SURFACE;
2792
2793 /* Crash type code */
2794 cb->crash_type = crash_type;
2795 }
2796 }
2797 /* Contact Bounds Spherical */
2798 else if(!strcasecmp(parm, "contact_spherical"))
2799 {
2800 /* Arguments:
2801 *
2802 * <radius>
2803 */
2804 sar_contact_bounds_struct *cb = obj_ptr->contact_bounds;
2805 float radius = 0.0f;
2806
2807 arg = GET_ARG_F(arg, &radius);
2808
2809 if(radius < 0.0f)
2810 fprintf(stderr,
2811 "%s: Line %i: Warning:\
2812 Value for %s argument radius=%f should not be negative.\n",
2813 filename, line_num,
2814 parm, radius
2815 );
2816
2817 SARObjAddContactBoundsSpherical(
2818 obj_ptr,
2819 (cb != NULL) ? cb->crash_flags : 0,
2820 (cb != NULL) ? cb->crash_type : 0,
2821 radius
2822 );
2823 }
2824 /* Contact Bounds Cylendical */
2825 else if(!strcasecmp(parm, "contact_cylendrical"))
2826 {
2827 /* Arguments:
2828 *
2829 * <radius> <height_min> <height_max>
2830 */
2831 sar_contact_bounds_struct *cb = obj_ptr->contact_bounds;
2832 float radius = 0.0f,
2833 height_min = 0.0f,
2834 height_max = 0.0f;
2835
2836 arg = GET_ARG_F(arg, &radius);
2837 arg = GET_ARG_F(arg, &height_min);
2838 arg = GET_ARG_F(arg, &height_max);
2839
2840 if(radius < 0.0f)
2841 fprintf(stderr,
2842 "%s: Line %i: Warning:\
2843 Value for %s argument radius=%f should not be negative.\n",
2844 filename, line_num,
2845 parm, radius
2846 );
2847 if(height_min > height_max)
2848 fprintf(stderr,
2849 "%s: Line %i: Warning:\
2850 Value for %s argument height_min=%f is greater than height_max=%f.\n",
2851 filename, line_num,
2852 parm, height_min, height_max
2853 );
2854
2855 SARObjAddContactBoundsCylendrical(
2856 obj_ptr,
2857 (cb != NULL) ? cb->crash_flags : 0,
2858 (cb != NULL) ? cb->crash_type : 0,
2859 radius, height_min, height_max
2860 );
2861 }
2862 /* Contact Bounds Rectangular */
2863 else if(!strcasecmp(parm, "contact_rectangular"))
2864 {
2865 /* Arguments:
2866 *
2867 * <x_min> <x_max>
2868 * <y_min> <y_max>
2869 * <z_min> <z_max>
2870 */
2871 sar_contact_bounds_struct *cb = obj_ptr->contact_bounds;
2872 float x_min = 0.0f,
2873 x_max = 0.0f,
2874 y_min = 0.0f,
2875 y_max = 0.0f,
2876 z_min = 0.0f,
2877 z_max = 0.0f;
2878
2879 arg = GET_ARG_F(arg, &x_min);
2880 arg = GET_ARG_F(arg, &x_max);
2881 arg = GET_ARG_F(arg, &y_min);
2882 arg = GET_ARG_F(arg, &y_max);
2883 arg = GET_ARG_F(arg, &z_min);
2884 arg = GET_ARG_F(arg, &z_max);
2885
2886 if(x_min > x_max)
2887 fprintf(stderr,
2888 "%s: Line %i: Warning:\
2889 Value for %s argument x_min=%f is greater than x_max=%f.\n",
2890 filename, line_num,
2891 parm, x_min, x_max
2892 );
2893 if(y_min > y_max)
2894 fprintf(stderr,
2895 "%s: Line %i: Warning:\
2896 Value for %s argument y_min=%f is greater than y_max=%f.\n",
2897 filename, line_num,
2898 parm, y_min, y_max
2899 );
2900 if(z_min > z_max)
2901 fprintf(stderr,
2902 "%s: Line %i: Warning:\
2903 Value for %s argument z_min=%f is greater than z_max=%f.\n",
2904 filename, line_num,
2905 parm, z_min, z_max
2906 );
2907
2908 SARObjAddContactBoundsRectangular(
2909 obj_ptr,
2910 (cb != NULL) ? cb->crash_flags : 0,
2911 (cb != NULL) ? cb->crash_type : 0,
2912 x_min, x_max,
2913 y_min, y_max,
2914 z_min, z_max
2915 );
2916 }
2917 /* Temperature */
2918 else if(!strcasecmp(parm, "temperature"))
2919 {
2920 /* Arguments:
2921 *
2922 * <temperature_day> <temperature_dusk/dawn>
2923 * <temperature_night>
2924 */
2925 float temperature_day = SAR_DEF_TEMPERATURE,
2926 temperature_dusk = SAR_DEF_TEMPERATURE,
2927 temperature_night = SAR_DEF_TEMPERATURE;
2928 arg = GET_ARG_F(arg, &temperature_day);
2929 arg = GET_ARG_F(arg, &temperature_dusk);
2930 arg = GET_ARG_F(arg, &temperature_night);
2931
2932 if((temperature_day < 0.0f) || (temperature_day > 1.0f))
2933 fprintf(stderr,
2934 "%s: Line %i: Warning:\
2935 Value for %s argument temperature_day=%f is out of range (0.0 to 1.0).\n",
2936 filename, line_num,
2937 parm, temperature_day
2938 );
2939 if((temperature_dusk < 0.0f) || (temperature_dusk > 1.0f))
2940 fprintf(stderr,
2941 "%s: Line %i: Warning:\
2942 Value for %s argument temperature_dusk=%f is out of range (0.0 to 1.0).\n",
2943 filename, line_num,
2944 parm, temperature_dusk
2945 );
2946 if((temperature_night < 0.0f) || (temperature_night > 1.0f))
2947 fprintf(stderr,
2948 "%s: Line %i: Warning:\
2949 Value for %s argument temperature_night=%f is out of range (0.0 to 1.0).\n",
2950 filename, line_num,
2951 parm, temperature_night
2952 );
2953
2954 obj_ptr->temperature = CLIP(temperature_day, 0.0f, 1.0f);
2955 }
2956 /* Speed */
2957 else if(!strcasecmp(parm, "speed"))
2958 {
2959 /* Arguments:
2960 *
2961 * <speed_stall> <speed_max>
2962 * <min_drag>
2963 * <overspeed_expected> <overspeed>
2964 */
2965 float speed_stall = 0.0f,
2966 speed_max = 0.0f,
2967 min_drag = 0.0f,
2968 overspeed_expected = 0.0f,
2969 overspeed = 0.0f;
2970
2971 arg = GET_ARG_F(arg, &speed_stall);
2972 arg = GET_ARG_F(arg, &speed_max);
2973 arg = GET_ARG_F(arg, &min_drag);
2974 arg = GET_ARG_F(arg, &overspeed_expected);
2975 arg = GET_ARG_F(arg, &overspeed);
2976
2977 if(speed_max < 0.0f)
2978 fprintf(stderr,
2979 "%s: Line %i: Warning:\
2980 Value for %s argument speed_max=%f should not be negative.\n",
2981 filename, line_num,
2982 parm, speed_max
2983 );
2984 if(min_drag < 0.0f)
2985 fprintf(stderr,
2986 "%s: Line %i: Warning:\
2987 Value for %s argument min_drag=%f should not be negative.\n",
2988 filename, line_num,
2989 parm, min_drag
2990 );
2991 if(overspeed_expected > overspeed)
2992 fprintf(stderr,
2993 "%s: Line %i: Warning:\
2994 Value for %s argument overspeed_expected=%f should not be\
2995 greater than the value for speed argument overspeed=%f.\n",
2996 filename, line_num,
2997 parm, overspeed_expected, overspeed
2998 );
2999
3000 if(aircraft != NULL)
3001 {
3002 aircraft->speed_stall = (float)SFMMPHToMPC(speed_stall);
3003 aircraft->speed_max = (float)SFMMPHToMPC(speed_max);
3004 aircraft->min_drag = (float)SFMMPHToMPC(min_drag);
3005 aircraft->overspeed_expected = (float)SFMMPHToMPC(overspeed_expected);
3006 aircraft->overspeed = (float)SFMMPHToMPC(overspeed);
3007 }
3008 }
3009 /* Air Brakes */
3010 else if(!strcasecmp(parm, "air_brakes"))
3011 {
3012 /* Arguments:
3013 *
3014 * <drag_rate>
3015 */
3016 float drag_rate = 0.0f;
3017
3018 arg = GET_ARG_F(arg, &drag_rate);
3019
3020 if(aircraft != NULL)
3021 {
3022 aircraft->air_brakes_rate = (float)SFMMPHToMPC(drag_rate);
3023 if(aircraft->air_brakes_rate <= 0.0f)
3024 aircraft->air_brakes_state = -1;
3025 else
3026 aircraft->air_brakes_state = 0;
3027 }
3028 }
3029
3030 /* Helicopter Acceleration Responsiveness */
3031 else if(!strcasecmp(parm, "helicopter_accelresp") ||
3032 !strcasecmp(parm, "helicopter_acceleration_responsiveness")
3033 )
3034 {
3035 /* Arguments:
3036 *
3037 * <i> <j> <k>
3038 */
3039 sar_position_struct a;
3040
3041 arg = GET_ARG_POS(arg, &a);
3042
3043 if(a.x <= 0.0f)
3044 fprintf(stderr,
3045 "%s: Line %i: Warning:\
3046 Value for %s argument i=%f is not positive.\n",
3047 filename, line_num,
3048 parm, a.x
3049 );
3050 if(a.y <= 0.0f)
3051 fprintf(stderr,
3052 "%s: Line %i: Warning:\
3053 Value for %s argument j=%f is not positive.\n",
3054 filename, line_num,
3055 parm, a.y
3056 );
3057 if(a.z <= 0.0f)
3058 fprintf(stderr,
3059 "%s: Line %i: Warning:\
3060 Value for %s argument k=%f is not positive.\n",
3061 filename, line_num,
3062 parm, a.z
3063 );
3064
3065 if(aircraft != NULL)
3066 memcpy(
3067 &aircraft->accel_responsiveness,
3068 &a,
3069 sizeof(sar_position_struct)
3070 );
3071 }
3072 /* Airplane Acceleration Responsiveness */
3073 else if(!strcasecmp(parm, "airplane_accelresp") ||
3074 !strcasecmp(parm, "airplane_acceleration_responsiveness")
3075 )
3076 {
3077 /* Arguments:
3078 *
3079 * <i> <j> <k>
3080 */
3081 sar_position_struct a;
3082
3083 arg = GET_ARG_POS(arg, &a);
3084
3085 if(a.x <= 0.0f)
3086 fprintf(stderr,
3087 "%s: Line %i: Warning:\
3088 Value for %s argument i=%f is not positive.\n",
3089 filename, line_num,
3090 parm, a.x
3091 );
3092 if(a.y <= 0.0f)
3093 fprintf(stderr,
3094 "%s: Line %i: Warning:\
3095 Value for %s argument j=%f is not positive.\n",
3096 filename, line_num,
3097 parm, a.y
3098 );
3099 if(a.z <= 0.0f)
3100 fprintf(stderr,
3101 "%s: Line %i: Warning:\
3102 Value for %s argument k=%f is not positive.\n",
3103 filename, line_num,
3104 parm, a.z
3105 );
3106
3107 if(aircraft != NULL)
3108 memcpy(
3109 &aircraft->airplane_accel_responsiveness,
3110 &a,
3111 sizeof(sar_position_struct)
3112 );
3113 }
3114 /* Cockpit Offset */
3115 else if(!strcasecmp(parm, "cockpit_offset"))
3116 {
3117 /* Arguments:
3118 *
3119 * <x> <y> <z>
3120 */
3121 sar_position_struct pos;
3122
3123 arg = GET_ARG_POS(arg, &pos);
3124
3125 if(aircraft != NULL)
3126 memcpy(
3127 &aircraft->cockpit_offset_pos,
3128 &pos,
3129 sizeof(sar_position_struct)
3130 );
3131 }
3132 /* Control Panel */
3133 else if(!strcasecmp(parm, "control_panel") &&
3134 is_player
3135 )
3136 {
3137 /* Arguments:
3138 *
3139 * <x> <y> <z>
3140 * <heading> <pitch> <bank>
3141 * <width> <height>
3142 * <path>
3143 *
3144 * Note that position and size units are in centimeters
3145 * The <path> specifies the control panel directory
3146 * (not the instruments file)
3147 */
3148 sar_position_struct pos;
3149 sar_direction_struct dir;
3150 float width = 0.0f,
3151 height = 0.0f;
3152 char *path = NULL;
3153 arg = GET_ARG_POS(arg, &pos);
3154 arg = GET_ARG_DIR(arg, &dir);
3155 arg = GET_ARG_F(arg, &width);
3156 arg = GET_ARG_F(arg, &height);
3157 arg = GET_ARG_S(arg, &path);
3158
3159 if(!STRISEMPTY(path))
3160 {
3161 ControlPanel *cp = CPNew(core_ptr->display);
3162 CPDelete((ControlPanel *)scene->player_control_panel);
3163 scene->player_control_panel = cp;
3164 if(cp != NULL)
3165 {
3166 CPLoadFromFile(cp, path);
3167 CPSetPosition(cp, pos.x, pos.y, pos.z);
3168 CPSetDirection(cp, dir.heading, dir.pitch, dir.bank);
3169 CPSetSize(cp, width, height);
3170 }
3171 }
3172 else
3173 {
3174 fprintf(stderr,
3175 "%s: Line %i: Warning:\
3176 Value for %s argument path is not given.\n",
3177 filename, line_num,
3178 parm
3179 );
3180 }
3181
3182 free(path);
3183 }
3184 /* Belly Height */
3185 else if(!strcasecmp(parm, "belly_height"))
3186 {
3187 /* Arguments:
3188 *
3189 * <height>
3190 */
3191 float height = 0.0f;
3192
3193 arg = GET_ARG_F(arg, &height);
3194
3195 if(aircraft != NULL)
3196 aircraft->belly_height = height;
3197 }
3198 /* Landing Gear Height */
3199 else if(!strcasecmp(parm, "gear_height"))
3200 {
3201 /* Arguments:
3202 *
3203 * <height>
3204 */
3205 float height = 0.0f;
3206
3207 arg = GET_ARG_F(arg, &height);
3208
3209 if(height < 0.0f)
3210 fprintf(stderr,
3211 "%s: Line %i: Warning:\
3212 Value for %s argument height=%f should not be negative.\n",
3213 filename, line_num,
3214 parm, height
3215 );
3216
3217 if(aircraft != NULL)
3218 aircraft->gear_height = height;
3219 }
3220 /* Ground Turning */
3221 else if(!strcasecmp(parm, "ground_turning"))
3222 {
3223 /* Arguments:
3224 *
3225 * <turn_rad> <turn_vel_opt> <turn_vel_max>
3226 *
3227 * All units are in miles per hour
3228 */
3229 float turn_rad = 0.0f,
3230 turn_vel_opt = 0.0f,
3231 turn_vel_max = 0.0f;
3232
3233 arg = GET_ARG_F(arg, &turn_rad);
3234 arg = GET_ARG_F(arg, &turn_vel_opt);
3235 arg = GET_ARG_F(arg, &turn_vel_max);
3236
3237 if(aircraft != NULL)
3238 {
3239 /* Turn radius in meters, distance from farthest
3240 * non-turnable wheel to turnable wheel
3241 *
3242 * Can be negative
3243 *
3244 * A value of 0 specifies no turning
3245 */
3246 aircraft->gturn_radius = turn_rad;
3247
3248 /* Optimul ground turning velocity along
3249 * aircraft's y axis in meters per cycle
3250 */
3251 aircraft->gturn_vel_opt =
3252 (float)SFMMPHToMPC(turn_vel_opt);
3253
3254 /* Maximum ground turning velocity along
3255 * aircraft's y axis in meters per cycle
3256 */
3257 aircraft->gturn_vel_max =
3258 (float)SFMMPHToMPC(turn_vel_max);
3259 }
3260 }
3261 /* Dry Mass */
3262 else if(!strcasecmp(parm, "dry_mass"))
3263 {
3264 /* Arguments:
3265 *
3266 * <mass>
3267 */
3268 float mass = 0.0f;
3269
3270 arg = GET_ARG_F(arg, &mass);
3271
3272 if(mass < 0)
3273 fprintf(stderr,
3274 "%s: Line %i: Warning:\
3275 Value for %s argument mass=%f should not be negative.\n",
3276 filename, line_num,
3277 parm, mass
3278 );
3279
3280 if(aircraft != NULL)
3281 aircraft->dry_mass = mass;
3282 }
3283 /* Fuel */
3284 else if(!strcasecmp(parm, "fuel"))
3285 {
3286 /* Arguments:
3287 *
3288 * <consumption_rate>
3289 * <initial> <max>
3290 *
3291 * Units for <consumption_rate> are in kg per second
3292 * Units for <fuel_init> and <fuel_max> are in kg.
3293 */
3294 float consumption_rate = 0.0f,
3295 initial = 0.0f,
3296 max = 0.0f;
3297
3298 arg = GET_ARG_F(arg, &consumption_rate);
3299 arg = GET_ARG_F(arg, &initial);
3300 arg = GET_ARG_F(arg, &max);
3301
3302 if(consumption_rate < 0.0f)
3303 fprintf(stderr,
3304 "%s: Line %i: Warning:\
3305 Value for %s argument consumption_rate=%f should not be negative.\n",
3306 filename, line_num,
3307 parm, consumption_rate
3308 );
3309 if(initial < 0.0f)
3310 fprintf(stderr,
3311 "%s: Line %i: Warning:\
3312 Value for %s argument initial=%f should not be negative.\n",
3313 filename, line_num,
3314 parm, initial
3315 );
3316 if(max < 0.0f)
3317 fprintf(stderr,
3318 "%s: Line %i: Warning:\
3319 Value for %s argument max=%f should not be negative.\n",
3320 filename, line_num,
3321 parm, max
3322 );
3323
3324 if(aircraft != NULL)
3325 {
3326 /* Convert fuel rate from (kg / sec) to (kg / cycle) */
3327 aircraft->fuel_rate = (float)MAX(
3328 consumption_rate * SAR_SEC_TO_CYCLE_COEFF, 0.0
3329 );
3330
3331 /* Fuel in kg */
3332 aircraft->fuel = (float)MAX(initial, 0.0);
3333 aircraft->fuel_max = (float)MAX(max, 0.0);
3334 }
3335 }
3336 /* Crew */
3337 else if(!strcasecmp(parm, "crew"))
3338 {
3339 /* Arguments:
3340 *
3341 * <crew>
3342 * <passengers> <passengers_max>
3343 */
3344 int crew = 0,
3345 passengers = 0,
3346 passengers_max = 0;
3347
3348 arg = GET_ARG_I(arg, &crew);
3349 arg = GET_ARG_I(arg, &passengers);
3350 arg = GET_ARG_I(arg, &passengers_max);
3351
3352 if(crew < 0)
3353 fprintf(stderr,
3354 "%s: Line %i: Warning:\
3355 Value for %s argument crew=%i should not be negative.\n",
3356 filename, line_num,
3357 parm, crew
3358 );
3359 if(passengers < 0)
3360 fprintf(stderr,
3361 "%s: Line %i: Warning:\
3362 Value for %s argument passengers=%i should not be negative.\n",
3363 filename, line_num,
3364 parm, passengers
3365 );
3366 if(passengers_max < 0)
3367 fprintf(stderr,
3368 "%s: Line %i: Warning:\
3369 Value for %s argument passengers_max=%i should not be negative.\n",
3370 filename, line_num,
3371 parm, passengers_max
3372 );
3373
3374 if(aircraft != NULL)
3375 {
3376 aircraft->crew = crew;
3377 aircraft->passengers = passengers;
3378 aircraft->passengers_max = passengers_max;
3379 }
3380 }
3381 /* Engine */
3382 else if(!strcasecmp(parm, "engine"))
3383 {
3384 /* Arguments:
3385 *
3386 * <can_pitch?> <initial_pitch>
3387 * <power>
3388 * <collective_range>
3389 *
3390 * Power from units of kg * m / cycle^2.
3391 */
3392 Boolean can_pitch = False;
3393 int initial_pitch = 0;
3394 float power = 0.0f,
3395 collective_range = 0.0f;
3396
3397 arg = GET_ARG_B(arg, &can_pitch);
3398 arg = GET_ARG_I(arg, &initial_pitch);
3399 arg = GET_ARG_F(arg, &power);
3400 arg = GET_ARG_F(arg, &collective_range);
3401
3402 if(power < 0.0f)
3403 fprintf(stderr,
3404 "%s: Line %i: Warning:\
3405 Value for %s argument power=%f should not be negative.\n",
3406 filename, line_num,
3407 parm, power
3408 );
3409 if((collective_range < 0.0f) || (collective_range > 1.0f))
3410 fprintf(stderr,
3411 "%s: Line %i: Warning:\
3412 Value for %s argument collective_range=%f is out of range [0.0, 1.0].\n",
3413 filename, line_num,
3414 parm, collective_range
3415 );
3416
3417 if(aircraft != NULL)
3418 {
3419 /* Can pitch? */
3420 aircraft->engine_can_pitch = can_pitch;
3421
3422 /* Initial rotor pitch state, this determines the
3423 * the value for member flight_model_type
3424 */
3425 switch(initial_pitch)
3426 {
3427 case 1:
3428 aircraft->flight_model_type =
3429 SAR_FLIGHT_MODEL_AIRPLANE;
3430 break;
3431 case 0:
3432 aircraft->flight_model_type =
3433 SAR_FLIGHT_MODEL_HELICOPTER;
3434 break;
3435 default:
3436 fprintf(stderr,
3437 "%s: Line %i: Warning:\
3438 Value for %s argument init_pitch=%i is not supported.\n",
3439 filename, line_num,
3440 parm, initial_pitch
3441 );
3442 break;
3443 }
3444
3445 /* Explicitly set previous flight model type to the
3446 * same type as the current one since this is the
3447 * first time this is being set for this object
3448 */
3449 aircraft->last_flight_model_type =
3450 aircraft->flight_model_type;
3451
3452 /* Engine power (in kg * m / cycle^2) */
3453 aircraft->engine_power = (float)MAX(
3454 power, 0.0
3455 );
3456
3457 /* Collective range coefficient (from 0.0 to 1.0) */
3458 aircraft->collective_range = (float)CLIP(
3459 collective_range, 0.0, 1.0
3460 );
3461 }
3462 }
3463 /* Service Ceiling */
3464 else if(!strcasecmp(parm, "service_ceiling"))
3465 {
3466 /* Arguments:
3467 *
3468 * <altitude>
3469 */
3470 float altitude = 0.0f;
3471
3472 arg = GET_ARG_F(arg, &altitude);
3473
3474 if(aircraft != NULL)
3475 aircraft->service_ceiling =
3476 (float)SFMFeetToMeters(altitude);
3477 }
3478 /* Attitude Change Rates */
3479 else if(!strcasecmp(parm, "attitude_change_rate"))
3480 {
3481 /* Arguments:
3482 *
3483 * <heading> <pitch> <bank>
3484 *
3485 * Units are in degrees per second
3486 */
3487 sar_direction_struct a;
3488
3489 arg = GET_ARG_DIR(arg, &a);
3490
3491 a.heading *= (float)SAR_SEC_TO_CYCLE_COEFF;
3492 a.pitch *= (float)SAR_SEC_TO_CYCLE_COEFF;
3493 a.bank *= (float)SAR_SEC_TO_CYCLE_COEFF;
3494
3495 if(aircraft != NULL)
3496 memcpy(
3497 &aircraft->attitude_change_rate,
3498 &a,
3499 sizeof(sar_direction_struct)
3500 );
3501 }
3502 /* Attitude Leveling */
3503 else if(!strcasecmp(parm, "attitude_leveling"))
3504 {
3505 /* Arguments:
3506 *
3507 * <heading> <pitch> <bank>
3508 *
3509 * Units are in degrees per second
3510 */
3511 sar_direction_struct a;
3512
3513 arg = GET_ARG_DIR(arg, &a);
3514
3515 a.heading *= (float)SAR_SEC_TO_CYCLE_COEFF;
3516 a.pitch *= (float)SAR_SEC_TO_CYCLE_COEFF;
3517 a.bank *= (float)SAR_SEC_TO_CYCLE_COEFF;
3518
3519 if(aircraft != NULL)
3520 {
3521 aircraft->pitch_leveling = a.pitch;
3522 aircraft->bank_leveling = a.bank;
3523 }
3524 }
3525 /* Ground Pitch Offset */
3526 else if(!strcasecmp(parm, "ground_pitch_offset"))
3527 {
3528 /* Arguments:
3529 *
3530 * <ground_pitch_offset>
3531 */
3532 float ground_pitch_offset;
3533
3534 arg = GET_ARG_F(arg, &ground_pitch_offset);
3535 ground_pitch_offset = (float)DEGTORAD(ground_pitch_offset);
3536
3537 if(aircraft != NULL)
3538 aircraft->ground_pitch_offset = ground_pitch_offset;
3539 }
3540 /* New Light */
3541 else if(!strcasecmp(parm, "light_new"))
3542 {
3543 /* Arguments:
3544 *
3545 * <x> <y> <z>
3546 * <r> <g> <b> <a>
3547 * <radius>
3548 * <init_on?> <type> <int_on> <int_off>
3549 * <int_on_delay>
3550 *
3551 * Units for <radius> are in pixels
3552 * Units for <int_*> are in milliseconds
3553 */
3554 sar_light_struct *light;
3555 sar_position_struct pos;
3556 sar_color_struct c;
3557 int radius = 0;
3558 Boolean init_on = False;
3559 int type = 0,
3560 int_on = 0,
3561 int_off = 0,
3562 int_on_delay = 0;
3563
3564 arg = GET_ARG_POS(arg, &pos);
3565 arg = GET_ARG_RGBA(arg, &c);
3566 arg = GET_ARG_I(arg, &radius);
3567 arg = GET_ARG_B(arg, &init_on);
3568 arg = GET_ARG_I(arg, &type);
3569 arg = GET_ARG_I(arg, &int_on);
3570 arg = GET_ARG_I(arg, &int_off);
3571 arg = GET_ARG_I(arg, &int_on_delay);
3572
3573 if(radius < 0)
3574 fprintf(stderr,
3575 "%s: Line %i: Warning:\
3576 Value for %s argument radius=%i should not be negative (use 0 for default).\n",
3577 filename, line_num,
3578 parm, radius
3579 );
3580 if(int_on < 0)
3581 fprintf(stderr,
3582 "%s: Line %i: Warning:\
3583 Value for %s argument int_on=%i should not be negative (use 0 for none).\n",
3584 filename, line_num,
3585 parm, int_on
3586 );
3587 if(int_off < 0)
3588 fprintf(stderr,
3589 "%s: Line %i: Warning:\
3590 Value for %s argument int_off=%i should not be negative (use 0 for none).\n",
3591 filename, line_num,
3592 parm, int_off
3593 );
3594 if(int_on_delay < 0)
3595 fprintf(stderr,
3596 "%s: Line %i: Warning:\
3597 Value for %s argument int_on_delay=%i should not be negative (use 0 for none).\n",
3598 filename, line_num,
3599 parm, int_on_delay
3600 );
3601
3602 /* Create new light */
3603 light = SARObjLightNew(
3604 scene,
3605 &obj_ptr->light, &obj_ptr->total_lights
3606 );
3607 if(light != NULL)
3608 {
3609 /* Position */
3610 memcpy(&light->pos, &pos, sizeof(sar_position_struct));
3611
3612 /* Color */
3613 memcpy(&light->color, &c, sizeof(sar_color_struct));
3614
3615 /* Radius */
3616 light->radius = (int)MAX(radius, 0);
3617
3618 /* Initially on? */
3619 if(init_on)
3620 light->flags |= SAR_LIGHT_FLAG_ON;
3621
3622 /* Type of light */
3623 switch(type)
3624 {
3625 case 2: /* Spot light */
3626 light->flags |= SAR_LIGHT_FLAG_ATTENUATE;
3627 break;
3628 case 1: /* Strobe */
3629 light->flags |= SAR_LIGHT_FLAG_STROBE;
3630 break;
3631 case 0:
3632 break;
3633 default:
3634 fprintf(stderr,
3635 "%s: Line %i: Warning:\
3636 Value for %s argument type=%i is not supported [0 | 1 | 2].\n",
3637 filename, line_num,
3638 parm, type
3639 );
3640 break;
3641 }
3642
3643 /* Strobe on and off intervals */
3644 light->int_on = (time_t)int_on;
3645 light->int_off = (time_t)int_off;
3646 light->int_delay_on = (time_t)int_on_delay;
3647 }
3648 }
3649 /* New Sound Source */
3650 else if(!strcasecmp(parm, "sound_source_new"))
3651 {
3652 SARObjLoadSoundSource(
3653 scene,
3654 &obj_ptr->sndsrc, &obj_ptr->total_sndsrcs,
3655 arg, filename, line_num
3656 );
3657 }
3658 /* New Rotor */
3659 else if(!strcasecmp(parm, "rotor_new") ||
3660 !strcasecmp(parm, "propellar_new")
3661 )
3662 {
3663 /* Arguments:
3664 *
3665 * <nblades>
3666 * <x> <y> <z>
3667 * <heading> <pitch> <bank>
3668 * <radius> <has_prop_wash?> <follow_controls?>
3669 * <blur_criteria>
3670 * <can_pitch?> <no_pitch_landed?> <no_rotate?>
3671 * <blades_offset>
3672 */
3673 int nblades = 0;
3674 sar_position_struct pos;
3675 sar_direction_struct dir;
3676 float radius = 0.0f;
3677 Boolean has_prop_wash = False,
3678 follow_controls = False;
3679 int blur_criteria = 0;
3680 Boolean can_pitch = False,
3681 no_pitch_landed = False,
3682 no_rotate = False;
3683 float blades_offset = 0.0f;
3684
3685 arg = GET_ARG_I(arg, &nblades);
3686 arg = GET_ARG_POS(arg, &pos);
3687 arg = GET_ARG_DIR(arg, &dir);
3688 arg = GET_ARG_F(arg, &radius);
3689 arg = GET_ARG_B(arg, &has_prop_wash);
3690 arg = GET_ARG_B(arg, &follow_controls);
3691 arg = GET_ARG_I(arg, &blur_criteria);
3692 arg = GET_ARG_B(arg, &can_pitch);
3693 arg = GET_ARG_B(arg, &no_pitch_landed);
3694 arg = GET_ARG_B(arg, &no_rotate);
3695 arg = GET_ARG_F(arg, &blades_offset);
3696
3697 if(radius < 0.0f)
3698 fprintf(stderr,
3699 "%s: Line %i: Warning:\
3700 Value for %s argument radius=%f should not be negative.\n",
3701 filename, line_num,
3702 parm, radius
3703 );
3704
3705 rotor = NULL;
3706 if(aircraft != NULL)
3707 {
3708 int n = SARObjRotorNew(
3709 scene,
3710 &aircraft->rotor,
3711 &aircraft->total_rotors
3712 );
3713 rotor = (n > -1) ?
3714 aircraft->rotor[n] : NULL;
3715 }
3716 if(rotor != NULL)
3717 {
3718 /* Total blades */
3719 rotor->total_blades = nblades;
3720
3721 /* Position */
3722 memcpy(&rotor->pos, &pos, sizeof(sar_position_struct));
3723
3724 /* Direction */
3725 memcpy(&rotor->dir, &dir, sizeof(sar_direction_struct));
3726
3727 /* Radius of blades */
3728 rotor->radius = (float)MAX(radius, 0.0f);
3729
3730 /* Has rotor wash? */
3731 if(has_prop_wash)
3732 rotor->wash_tex_num = SARGetTextureRefNumberByName(
3733 scene, SAR_STD_TEXNAME_ROTOR_WASH
3734 );
3735 else
3736 rotor->wash_tex_num = -1;
3737
3738 /* Follow controls for pitch and bank? */
3739 if(follow_controls)
3740 rotor->flags |= SAR_ROTOR_FLAG_FOLLOW_CONTROLS;
3741
3742 /* Blur criteria */
3743 switch(blur_criteria)
3744 {
3745 case 2: /* Blur always */
3746 rotor->flags |= SAR_ROTOR_FLAG_BLUR_ALWAYS;
3747 break;
3748 case 1: /* Blur when spinning fast */
3749 rotor->flags |= SAR_ROTOR_FLAG_BLUR_WHEN_FAST;
3750 break;
3751 case 0: /* Never blur */
3752 break;
3753 default:
3754 fprintf(stderr,
3755 "%s: Line %i: Warning:\
3756 Value for %s argument blur_criteria=%i is not supported [0 | 1 | 2].\n",
3757 filename, line_num,
3758 parm, blur_criteria
3759 );
3760 break;
3761 }
3762
3763 /* Can pitch? */
3764 if(can_pitch)
3765 rotor->flags |= SAR_ROTOR_FLAG_CAN_PITCH;
3766
3767 /* No pitching of rotors when landed? */
3768 if(no_pitch_landed)
3769 rotor->flags |= SAR_ROTOR_FLAG_NO_PITCH_LANDED;
3770
3771 /* No rotate? */
3772 if(!no_rotate)
3773 rotor->flags |= SAR_ROTOR_FLAG_SPINS;
3774
3775 /* Blades offset */
3776 rotor->blades_offset = blades_offset;
3777
3778 /* Rotor blur texture */
3779 rotor->blade_blur_tex_num = SARGetTextureRefNumberByName(
3780 scene, SAR_STD_TEXNAME_ROTOR_BLADE_BLUR
3781 );
3782 }
3783 else
3784 {
3785 fprintf(stderr,
3786 "%s: Line %i: Error: Unable to create rotor (check object type).\n",
3787 filename, line_num
3788 );
3789 }
3790 }
3791 /* Rotor Blur Color */
3792 else if(!strcasecmp(parm, "rotor_blur_color") ||
3793 !strcasecmp(parm, "propellar_blur_color")
3794 )
3795 {
3796 /* Arguments:
3797 *
3798 * <r> <b> <g> <a>
3799 */
3800 sar_color_struct c;
3801
3802 arg = GET_ARG_RGBA(arg, &c);
3803
3804 if(rotor != NULL)
3805 {
3806 if((rotor->flags & SAR_ROTOR_FLAG_BLUR_WHEN_FAST) ||
3807 (rotor->flags & SAR_ROTOR_FLAG_BLUR_ALWAYS)
3808 )
3809 {
3810 memcpy(
3811 &rotor->blades_blur_color,
3812 &c,
3813 sizeof(sar_color_struct)
3814 );
3815 }
3816 else
3817 {
3818 fprintf(
3819 stderr,
3820 "%s: Line %i: Warning:\
3821 Rotor blur_criteria is set to never blur (rotor_blur_color ignored).\n",
3822 filename, line_num
3823 );
3824 }
3825 }
3826 }
3827 /* Rotor Blade Blur Texture */
3828 else if(!strcasecmp(parm, "rotor_blade_blur_texture"))
3829 {
3830 /* Arguments:
3831 *
3832 * <name>
3833 */
3834 char *name = NULL;
3835
3836 arg = GET_ARG_S(arg, &name);
3837
3838 if(rotor != NULL)
3839 {
3840 rotor->blade_blur_tex_num = SARGetTextureRefNumberByName(
3841 scene, name
3842 );
3843 }
3844
3845 free(name);
3846 }
3847 /* New Air Brake */
3848 else if(!strcasecmp(parm, "air_brake_new"))
3849 {
3850 /* Arguments:
3851 *
3852 * <x> <y> <z>
3853 * <heading> <pitch> <bank>
3854 * <dep_dheading> <dep_dpitch> <dep_dbank>
3855 * <deployed?> <anim_rate>
3856 * <visible_when_retracted?>
3857 */
3858 sar_position_struct pos;
3859 sar_direction_struct dir,
3860 dep_dir;
3861 Boolean deployed = False;
3862 int anim_rate = 0;
3863 Boolean visible_when_retracted = False;
3864
3865 arg = GET_ARG_POS(arg, &pos);
3866 arg = GET_ARG_DIR(arg, &dir);
3867 arg = GET_ARG_DIR(arg, &dep_dir);
3868 arg = GET_ARG_B(arg, &deployed);
3869 arg = GET_ARG_I(arg, &anim_rate);
3870 arg = GET_ARG_B(arg, &visible_when_retracted);
3871
3872 abrake_ptr = NULL;
3873 if(aircraft != NULL)
3874 abrake_ptr = SARObjAirBrakeNew(
3875 scene,
3876 &aircraft->part,
3877 &aircraft->total_parts
3878 );
3879 if(abrake_ptr != NULL)
3880 {
3881 abrake_ptr->flags = 0; /* Must reset flags */
3882
3883 /* Position */
3884 memcpy(
3885 &abrake_ptr->pos_min,
3886 &pos,
3887 sizeof(sar_position_struct)
3888 );
3889 memcpy(
3890 &abrake_ptr->pos_cen,
3891 &pos,
3892 sizeof(sar_position_struct)
3893 );
3894 memcpy(
3895 &abrake_ptr->pos_max,
3896 &pos,
3897 sizeof(sar_position_struct)
3898 );
3899
3900 /* Direction */
3901 memcpy(
3902 &abrake_ptr->dir_min,
3903 &dir,
3904 sizeof(sar_direction_struct)
3905 );
3906 memcpy(
3907 &abrake_ptr->dir_cen,
3908 &dir,
3909 sizeof(sar_direction_struct)
3910 );
3911
3912 /* Deployed direction */
3913 memcpy(
3914 &abrake_ptr->dir_max,
3915 &dep_dir,
3916 sizeof(sar_direction_struct)
3917 );
3918
3919 /* Air brake initially deployed? */
3920 if(deployed)
3921 {
3922 /* Air brake initially deployed */
3923 abrake_ptr->anim_pos = (sar_grad_anim_t)-1;
3924 abrake_ptr->flags |= SAR_OBJ_PART_FLAG_STATE;
3925 }
3926 else
3927 {
3928 /* Air brake initially retracted */
3929 abrake_ptr->anim_pos = 0;
3930 abrake_ptr->flags &= ~SAR_OBJ_PART_FLAG_STATE;
3931 }
3932
3933 /* Animation rate */
3934 abrake_ptr->anim_rate = (sar_grad_anim_t)anim_rate;
3935
3936 /* Air brake visible when retracted? */
3937 if(!visible_when_retracted)
3938 abrake_ptr->flags |= SAR_OBJ_PART_FLAG_HIDE_MIN;
3939
3940 abrake_ptr->temperature = obj_ptr->temperature * 0.5f;
3941 }
3942 else
3943 {
3944 fprintf(stderr,
3945 "%s: Line %i: Error:\
3946 Unable to create air brake (check object type).\n",
3947 filename, line_num
3948 );
3949 }
3950 }
3951 /* New Landing Gear */
3952 else if(!strcasecmp(parm, "landing_gear_new"))
3953 {
3954 /* Arguments:
3955 *
3956 * <x> <y> <z>
3957 * <heading> <pitch> <bank>
3958 * <anim_rate> <up?> <fixed?> <skis?> <floats?>
3959 */
3960 sar_position_struct pos;
3961 sar_direction_struct dir;
3962 int anim_rate = 0;
3963 Boolean up = False,
3964 fixed = False,
3965 skis = False,
3966 floats = False;
3967
3968 arg = GET_ARG_POS(arg, &pos);
3969 arg = GET_ARG_DIR(arg, &dir);
3970 arg = GET_ARG_I(arg, &anim_rate);
3971 arg = GET_ARG_B(arg, &up);
3972 arg = GET_ARG_B(arg, &fixed);
3973 arg = GET_ARG_B(arg, &skis);
3974 arg = GET_ARG_B(arg, &floats);
3975
3976 lgear_ptr = NULL;
3977 if(aircraft != NULL)
3978 lgear_ptr = SARObjLandingGearNew(
3979 scene,
3980 &aircraft->part,
3981 &aircraft->total_parts
3982 );
3983 if(lgear_ptr != NULL)
3984 {
3985 lgear_ptr->flags = 0; /* Must reset flags */
3986
3987 memcpy(&lgear_ptr->pos_min, &pos, sizeof(sar_position_struct));
3988 memcpy(&lgear_ptr->pos_cen, &pos, sizeof(sar_position_struct));
3989 memcpy(&lgear_ptr->pos_max, &pos, sizeof(sar_position_struct));
3990
3991 memset(&lgear_ptr->dir_min, 0x00, sizeof(sar_direction_struct));
3992 memset(&lgear_ptr->dir_cen, 0x00, sizeof(sar_direction_struct));
3993 memcpy(&lgear_ptr->dir_max, &dir, sizeof(sar_direction_struct));
3994
3995 lgear_ptr->anim_rate = (sar_grad_anim_t)anim_rate;
3996
3997 /* Landing gear up or down? */
3998 if(up)
3999 {
4000 /* Landing gear initially up */
4001 lgear_ptr->anim_pos = (sar_grad_anim_t)-1;
4002 lgear_ptr->flags &= ~SAR_OBJ_PART_FLAG_STATE;
4003 }
4004 else
4005 {
4006 /* Landing gear initially down */
4007 lgear_ptr->anim_pos = 0;
4008 lgear_ptr->flags |= SAR_OBJ_PART_FLAG_STATE;
4009 }
4010
4011 /* Landing gear fixed? */
4012 if(fixed)
4013 {
4014 /* Fixed */
4015 lgear_ptr->anim_pos = 0;
4016 lgear_ptr->flags |= SAR_OBJ_PART_FLAG_STATE;
4017 lgear_ptr->flags |= SAR_OBJ_PART_FLAG_LGEAR_FIXED;
4018 }
4019 else
4020 {
4021 /* Retractable */
4022 lgear_ptr->flags &= ~SAR_OBJ_PART_FLAG_LGEAR_FIXED;
4023 }
4024
4025 /* Skis? */
4026 if(skis)
4027 lgear_ptr->flags |= SAR_OBJ_PART_FLAG_LGEAR_SKI;
4028 else
4029 lgear_ptr->flags &= ~SAR_OBJ_PART_FLAG_LGEAR_SKI;
4030
4031 /* Floats? */
4032 if(floats)
4033 lgear_ptr->flags |= SAR_OBJ_PART_FLAG_LGEAR_FLOATS;
4034 else
4035 lgear_ptr->flags &= ~SAR_OBJ_PART_FLAG_LGEAR_FLOATS;
4036
4037 /* Landing gears are always hidden when retracted
4038 * Maximum position is considered retracted
4039 */
4040 lgear_ptr->flags |= SAR_OBJ_PART_FLAG_HIDE_MAX;
4041
4042 /* Need to update landing gear state on aircraft */
4043 if(lgear_ptr->flags & SAR_OBJ_PART_FLAG_LGEAR_FIXED)
4044 aircraft->landing_gear_state = 2;
4045 else
4046 aircraft->landing_gear_state = 1;
4047 if(!(lgear_ptr->flags & SAR_OBJ_PART_FLAG_LGEAR_SKI))
4048 aircraft->wheel_brakes_state = 0;
4049
4050 lgear_ptr->temperature = obj_ptr->temperature * 0.5f;
4051 }
4052 else
4053 {
4054 fprintf(
4055 stderr,
4056 "%s: Line %i: Error:\
4057 Unable to create landing gear (check object type).\n",
4058 filename, line_num
4059 );
4060 }
4061 }
4062 /* Aileron left, aileron right, rudder top, rudder bottom,
4063 * elevator, cannard, aileron/elevator left, or
4064 * aileron/elevator right
4065 */
4066 else if(!strcasecmp(parm, "aileron_left_new") ||
4067 !strcasecmp(parm, "aileron_right_new") ||
4068 !strcasecmp(parm, "rudder_top_new") ||
4069 !strcasecmp(parm, "rudder_bottom_new") ||
4070 !strcasecmp(parm, "elevator_new") ||
4071 !strcasecmp(parm, "cannard_new") ||
4072 !strcasecmp(parm, "aileron_elevator_left_new") ||
4073 !strcasecmp(parm, "aileron_elevator_right_new") ||
4074 !strcasecmp(parm, "flap_new")
4075 )
4076 {
4077 sar_obj_part_type part_type = -1;
4078 sar_obj_part_struct **part_ptr = NULL;
4079
4080 /* Arguments:
4081 *
4082 * <x> <y> <z>
4083 * <heading> <pitch> <bank>
4084 * <t_min> <t_max>
4085 */
4086 sar_position_struct pos;
4087 sar_direction_struct dir;
4088 float t_min = 0.0f,
4089 t_max = 0.0f;
4090
4091 arg = GET_ARG_POS(arg, &pos);
4092 arg = GET_ARG_DIR(arg, &dir);
4093 arg = GET_ARG_F(arg, &t_min);
4094 arg = GET_ARG_F(arg, &t_max);
4095
4096 /* Determine the part type and get part pointer */
4097 if(!strcasecmp(parm, "aileron_left_new"))
4098 {
4099 part_type = SAR_OBJ_PART_TYPE_AILERON_LEFT;
4100 part_ptr = &aileron_left_ptr;
4101 }
4102 else if(!strcasecmp(parm, "aileron_right_new"))
4103 {
4104 part_type = SAR_OBJ_PART_TYPE_AILERON_RIGHT;
4105 part_ptr = &aileron_right_ptr;
4106 }
4107 else if(!strcasecmp(parm, "rudder_top_new"))
4108 {
4109 part_type = SAR_OBJ_PART_TYPE_RUDDER_TOP;
4110 part_ptr = &rudder_top_ptr;
4111 }
4112 else if(!strcasecmp(parm, "rudder_bottom_new"))
4113 {
4114 part_type = SAR_OBJ_PART_TYPE_RUDDER_BOTTOM;
4115 part_ptr = &rudder_bottom_ptr;
4116 }
4117 else if(!strcasecmp(parm, "elevator_new"))
4118 {
4119 part_type = SAR_OBJ_PART_TYPE_ELEVATOR;
4120 part_ptr = &elevator_ptr;
4121 }
4122 else if(!strcasecmp(parm, "cannard_new"))
4123 {
4124 part_type = SAR_OBJ_PART_TYPE_CANNARD;
4125 part_ptr = &cannard_ptr;
4126 }
4127 else if(!strcasecmp(parm, "aileron_elevator_left_new"))
4128 {
4129 part_type = SAR_OBJ_PART_TYPE_AILERON_ELEVATOR_LEFT;
4130 part_ptr = &aileron_elevator_left_ptr;
4131 }
4132 else if(!strcasecmp(parm, "aileron_elevator_right_new"))
4133 {
4134 part_type = SAR_OBJ_PART_TYPE_AILERON_ELEVATOR_RIGHT;
4135 part_ptr = &aileron_elevator_right_ptr;
4136 }
4137 else if(!strcasecmp(parm, "flap_new"))
4138 {
4139 part_type = SAR_OBJ_PART_TYPE_FLAP;
4140 part_ptr = &flap_ptr;
4141 }
4142
4143 /* Got valid part type? */
4144 if(part_ptr != NULL)
4145 {
4146 /* Create new part */
4147 if(aircraft != NULL)
4148 *part_ptr = SARObjPartNew(
4149 scene,
4150 &aircraft->part,
4151 &aircraft->total_parts,
4152 part_type
4153 );
4154 if(*part_ptr != NULL)
4155 {
4156 sar_obj_part_struct *part = *part_ptr;
4157 sar_direction_struct *dir_min = &part->dir_min,
4158 *dir_cen = &part->dir_cen,
4159 *dir_max = &part->dir_max;
4160
4161 /* Minimum position */
4162 memset(&part->pos_min, 0x00, sizeof(sar_position_struct));
4163
4164 /* Center position */
4165 memcpy(&part->pos_cen, &pos, sizeof(sar_position_struct));
4166
4167 /* Maximum position */
4168 memset(&part->pos_max, 0x00, sizeof(sar_position_struct));
4169
4170
4171 /* Minimum direction */
4172 memset(dir_min, 0x00, sizeof(sar_direction_struct));
4173
4174 /* Center direction */
4175 memcpy(dir_cen, &dir, sizeof(sar_direction_struct));
4176
4177 /* Maximum direction */
4178 memset(dir_max, 0x00, sizeof(sar_direction_struct));
4179
4180 /* Set values specific to the part's type */
4181 switch(part_type)
4182 {
4183 case SAR_OBJ_PART_TYPE_AILERON_LEFT:
4184 case SAR_OBJ_PART_TYPE_AILERON_RIGHT:
4185 dir_min->pitch += (float)DEGTORAD(t_min);
4186 dir_max->pitch += (float)DEGTORAD(t_max);
4187 break;
4188 case SAR_OBJ_PART_TYPE_RUDDER_TOP:
4189 case SAR_OBJ_PART_TYPE_RUDDER_BOTTOM:
4190 dir_min->heading += (float)DEGTORAD(t_min);
4191 dir_max->heading += (float)DEGTORAD(t_max);
4192 break;
4193 case SAR_OBJ_PART_TYPE_ELEVATOR:
4194 case SAR_OBJ_PART_TYPE_CANNARD:
4195 dir_min->pitch += (float)DEGTORAD(t_min);
4196 dir_max->pitch += (float)DEGTORAD(t_max);
4197 break;
4198 case SAR_OBJ_PART_TYPE_AILERON_ELEVATOR_LEFT:
4199 case SAR_OBJ_PART_TYPE_AILERON_ELEVATOR_RIGHT:
4200 dir_min->pitch += (float)DEGTORAD(t_min);
4201 dir_max->pitch += (float)DEGTORAD(t_max);
4202 break;
4203 case SAR_OBJ_PART_TYPE_FLAP:
4204 dir_min->pitch += (float)DEGTORAD(t_min);
4205 dir_max->pitch += (float)DEGTORAD(t_max);
4206 break;
4207 case SAR_OBJ_PART_TYPE_AIR_BRAKE:
4208 break;
4209 case SAR_OBJ_PART_TYPE_DOOR:
4210 break;
4211 case SAR_OBJ_PART_TYPE_DOOR_RESCUE:
4212 break;
4213 case SAR_OBJ_PART_TYPE_CANOPY:
4214 break;
4215 case SAR_OBJ_PART_TYPE_LANDING_GEAR:
4216 break;
4217 }
4218
4219 part->temperature = obj_ptr->temperature * 0.5f;
4220
4221 }
4222 else
4223 {
4224 fprintf(
4225 stderr,
4226 "%s: Line %i: Error:\
4227 Unable to create part type %i (check object type).\n",
4228 filename, line_num,
4229 (int)part_type
4230 );
4231 }
4232 }
4233 }
4234
4235 /* New External Fuel Tank */
4236 else if(!strcasecmp(parm, "fueltank_new") ||
4237 !strcasecmp(parm, "fuel_tank_new")
4238 )
4239 {
4240 /* Arguments:
4241 *
4242 * <x> <y> <z>
4243 * <radius>
4244 * <dry_mass> <fuel> <fuel_max>
4245 * <droppable?>
4246 */
4247 sar_position_struct pos;
4248 float radius = 0.0f,
4249 belly_to_center_height = 0.0f,
4250 dry_mass = 0.0f,
4251 fuel = 0.0f,
4252 fuel_max = 0.0f;
4253 Boolean droppable = False;
4254
4255 arg = GET_ARG_POS(arg, &pos);
4256 arg = GET_ARG_F(arg, &radius);
4257 arg = GET_ARG_F(arg, &belly_to_center_height);
4258 arg = GET_ARG_F(arg, &dry_mass);
4259 arg = GET_ARG_F(arg, &fuel);
4260 arg = GET_ARG_F(arg, &fuel_max);
4261 arg = GET_ARG_B(arg, &droppable);
4262
4263 if(radius < 0.0f)
4264 fprintf(stderr,
4265 "%s: Line %i: Warning:\
4266 Value for %s argument radius=%f should not be negative.\n",
4267 filename, line_num,
4268 parm, radius
4269 );
4270 if(dry_mass < 0.0f)
4271 fprintf(stderr,
4272 "%s: Line %i: Warning:\
4273 Value for %s argument dry_mass=%f should not be negative.\n",
4274 filename, line_num,
4275 parm, dry_mass
4276 );
4277 if(fuel < 0.0f)
4278 fprintf(stderr,
4279 "%s: Line %i: Warning:\
4280 Value for %s argument fuel=%f should not be negative.\n",
4281 filename, line_num,
4282 parm, fuel
4283 );
4284 if(fuel_max < 0.0f)
4285 fprintf(stderr,
4286 "%s: Line %i: Warning:\
4287 Value for %s argument fuel_max=%f should not be negative.\n",
4288 filename, line_num,
4289 parm, fuel_max
4290 );
4291 if(fuel > fuel_max)
4292 fprintf(stderr,
4293 "%s: Line %i: Warning:\
4294 Value for %s argument fuel=%f is greater than fuel_max=%f.\n",
4295 filename, line_num,
4296 parm, fuel, fuel_max
4297 );
4298
4299 eft_ptr = NULL;
4300 if(aircraft != NULL)
4301 {
4302 int n = SARObjExternalFuelTankNew(
4303 scene,
4304 &aircraft->external_fueltank,
4305 &aircraft->total_external_fueltanks
4306 );
4307 eft_ptr = (n > -1) ?
4308 aircraft->external_fueltank[n] : NULL;
4309 }
4310 if(eft_ptr != NULL)
4311 {
4312 /* Position */
4313 memcpy(&eft_ptr->offset_pos, &pos, sizeof(sar_position_struct));
4314
4315 /* Size */
4316 eft_ptr->radius = (float)MAX(radius, 0.0f);
4317
4318 /* Belly to center height */
4319 eft_ptr->belly_to_center_height = belly_to_center_height;
4320
4321 /* Mass, fuel, and fuel max */
4322 eft_ptr->dry_mass = (float)MAX(dry_mass, 0.0f);
4323 eft_ptr->fuel_max = (float)MAX(fuel_max, 0.0f);
4324 eft_ptr->fuel = (float)CLIP(fuel, 0.0f, eft_ptr->fuel_max);
4325
4326 /* Dropable? */
4327 if(droppable)
4328 eft_ptr->flags |= SAR_EXTERNAL_FUELTANK_FLAG_FIXED;
4329 else
4330 eft_ptr->flags &= ~SAR_EXTERNAL_FUELTANK_FLAG_FIXED;
4331
4332 /* Mark as initially on board */
4333 eft_ptr->flags |= SAR_EXTERNAL_FUELTANK_FLAG_ONBOARD;
4334
4335 eft_ptr->temperature = obj_ptr->temperature * 0.5f;
4336 }
4337 else
4338 {
4339 fprintf(
4340 stderr,
4341 "%s: Line %i: Error:\
4342 Unable to create fuel tank (check object type).\n",
4343 filename, line_num
4344 );
4345 }
4346 }
4347 /* Rescue Door */
4348 else if(!strcasecmp(parm, "rescue_door_new"))
4349 {
4350 /* Arguments:
4351 *
4352 * <x_closed> <y_closed> <z_closed>
4353 * <x_opened> <y_opened> <z_opened>
4354 * <h_opened> <p_opened> <b_opened>
4355 * <x_thres> <y_thres> <z_thres>
4356 * <anim_rate> <opened?>
4357 */
4358 sar_position_struct pos_closed,
4359 pos_opened;
4360 sar_direction_struct dir_opened;
4361 sar_position_struct pos_thres;
4362 int anim_rate = 0;
4363 Boolean opened = False;
4364
4365 arg = GET_ARG_POS(arg, &pos_closed);
4366 arg = GET_ARG_POS(arg, &pos_opened);
4367 arg = GET_ARG_DIR(arg, &dir_opened);
4368 arg = GET_ARG_POS(arg, &pos_thres);
4369 arg = GET_ARG_I(arg, &anim_rate);
4370 arg = GET_ARG_B(arg, &opened);
4371
4372 door_ptr = NULL;
4373 if(aircraft != NULL)
4374 door_ptr = SARObjDoorRescueNew(
4375 scene,
4376 &aircraft->part,
4377 &aircraft->total_parts
4378 );
4379 if(door_ptr != NULL)
4380 {
4381 door_ptr->flags = 0; /* Must reset flags */
4382
4383 /* Closed position */
4384 memcpy(&door_ptr->pos_min, &pos_closed, sizeof(sar_position_struct));
4385
4386 /* Opened position */
4387 memcpy(&door_ptr->pos_max, &pos_opened, sizeof(sar_position_struct));
4388
4389 /* Opened direction */
4390 memcpy(&door_ptr->dir_max, &dir_opened, sizeof(sar_direction_struct));
4391
4392 /* Threshold position */
4393 memcpy(&door_ptr->pos_cen, &pos_thres, sizeof(sar_position_struct));
4394
4395 /* Animation rate */
4396 door_ptr->anim_rate = (sar_grad_anim_t)anim_rate;
4397
4398 /* Initially opened? */
4399 if(opened)
4400 {
4401 /* Door initially open */
4402 door_ptr->anim_pos = (sar_grad_anim_t)-1;
4403 door_ptr->flags |= SAR_OBJ_PART_FLAG_STATE;
4404 door_ptr->flags |= SAR_OBJ_PART_FLAG_DOOR_STAY_OPEN;
4405 }
4406 else
4407 {
4408 /* Door initially closed */
4409 door_ptr->anim_pos = 0;
4410 door_ptr->flags &= ~SAR_OBJ_PART_FLAG_STATE;
4411 }
4412
4413 door_ptr->temperature = obj_ptr->temperature;
4414 }
4415 else
4416 {
4417 fprintf(stderr,
4418 "%s: Line %i: Error:\
4419 Unable to create rescue door (check object type).\n",
4420 filename, line_num
4421 );
4422 }
4423 }
4424 /* Hoist */
4425 else if(!strcasecmp(parm, "hoist"))
4426 {
4427 /* Arguments:
4428 *
4429 * <x> <y> <z>
4430 * <rope_max> <rope_rate> <capacity>
4431 * <radius> <z_min> <z_max>
4432 * <basket?> <diver?> <hook?>
4433 */
4434 sar_obj_hoist_struct *hoist;
4435 sar_position_struct pos;
4436 float rope_max = 0.0f,
4437 rope_rate = 0.0f,
4438 capacity = 0.0f,
4439 radius = 0.0f,
4440 z_min = 0.0f,
4441 z_max = 0.0f;
4442 Boolean basket = False,
4443 diver = False,
4444 hook = False;
4445
4446 arg = GET_ARG_POS(arg, &pos);
4447 arg = GET_ARG_F(arg, &rope_max);
4448 arg = GET_ARG_F(arg, &rope_rate);
4449 arg = GET_ARG_F(arg, &capacity);
4450 arg = GET_ARG_F(arg, &radius);
4451 arg = GET_ARG_F(arg, &z_min);
4452 arg = GET_ARG_F(arg, &z_max);
4453 arg = GET_ARG_B(arg, &basket);
4454 arg = GET_ARG_B(arg, &diver);
4455 arg = GET_ARG_B(arg, &hook);
4456
4457 if(rope_max < 0.0f)
4458 fprintf(stderr,
4459 "%s: Line %i: Warning:\
4460 Value for %s argument rope_max=%f should not be negative.\n",
4461 filename, line_num,
4462 parm, rope_max
4463 );
4464 if(rope_rate < 0.0f)
4465 fprintf(stderr,
4466 "%s: Line %i: Warning:\
4467 Value for %s argument rope_rate=%f should not be negative.\n",
4468 filename, line_num,
4469 parm, rope_rate
4470 );
4471 if(capacity < 0.0f)
4472 fprintf(stderr,
4473 "%s: Line %i: Warning:\
4474 Value for %s argument capacity=%f should not be negative.\n",
4475 filename, line_num,
4476 parm, capacity
4477 );
4478 if(radius < 0.0f)
4479 fprintf(stderr,
4480 "%s: Line %i: Warning:\
4481 Value for %s argument radius=%f should not be negative.\n",
4482 filename, line_num,
4483 parm, radius
4484 );
4485 if(z_min > z_max)
4486 fprintf(stderr,
4487 "%s: Line %i: Warning:\
4488 Value for %s argument z_min=%f is greater than z_max=%f.\n",
4489 filename, line_num,
4490 parm, z_min, z_max
4491 );
4492
4493 /* Create hoist as needed */
4494 if(aircraft != NULL)
4495 {
4496 if(aircraft->hoist == NULL)
4497 aircraft->hoist = SAR_OBJ_HOIST(calloc(
4498 1, sizeof(sar_obj_hoist_struct)
4499 ));
4500 }
4501 hoist = SARObjGetHoistPtr(obj_ptr, 0, NULL);
4502 if(hoist != NULL)
4503 {
4504 const sar_human_data_entry_struct *human_data;
4505
4506 /* Position */
4507 memcpy(&hoist->offset, &pos, sizeof(sar_position_struct));
4508
4509 /* Rope length and movement rate */
4510 hoist->rope_max = rope_max;
4511 hoist->rope_rate = (float)(rope_rate * SAR_SEC_TO_CYCLE_COEFF);
4512
4513 /* Capacity, in kg */
4514 hoist->capacity = capacity;
4515
4516 /* Cylendrical contact size */
4517 hoist->contact_radius = radius;
4518 hoist->contact_z_min = z_min;
4519 hoist->contact_z_max = z_max;
4520
4521 /* Deployment type */
4522 hoist->deployments = (basket ? SAR_HOIST_DEPLOYMENT_BASKET : 0) |
4523 (diver ? SAR_HOIST_DEPLOYMENT_DIVER : 0) |
4524 (hook ? SAR_HOIST_DEPLOYMENT_HOOK : 0);
4525 /* Set initial deployment */
4526 if(hoist->deployments & SAR_HOIST_DEPLOYMENT_BASKET)
4527 hoist->cur_deployment = SAR_HOIST_DEPLOYMENT_BASKET;
4528 else if(hoist->deployments & SAR_HOIST_DEPLOYMENT_DIVER)
4529 hoist->cur_deployment = SAR_HOIST_DEPLOYMENT_DIVER;
4530 else if(hoist->deployments & SAR_HOIST_DEPLOYMENT_HOOK)
4531 hoist->cur_deployment = SAR_HOIST_DEPLOYMENT_HOOK;
4532
4533 /* Get hoist texture reference numbers from scene */
4534 hoist->side_tex_num =
4535 SARGetTextureRefNumberByName(
4536 scene, SAR_STD_TEXNAME_BASKET_SIDE
4537 );
4538 hoist->end_tex_num =
4539 SARGetTextureRefNumberByName(
4540 scene, SAR_STD_TEXNAME_BASKET_END
4541 );
4542 hoist->bottom_tex_num =
4543 SARGetTextureRefNumberByName(
4544 scene, SAR_STD_TEXNAME_BASKET_BOTTOM
4545 );
4546 hoist->water_ripple_tex_num =
4547 SARGetTextureRefNumberByName(
4548 scene, SAR_STD_TEXNAME_WATER_RIPPLE
4549 );
4550
4551 /* Diver color */
4552 human_data = SARHumanMatchEntryByName(
4553 core_ptr->human_data, SAR_HUMAN_PRESET_NAME_DIVER
4554 );
4555 if(human_data == NULL)
4556 human_data = SARHumanMatchEntryByName(
4557 core_ptr->human_data, SAR_HUMAN_PRESET_NAME_STANDARD
4558 );
4559 if(human_data != NULL)
4560 memcpy(
4561 hoist->diver_color,
4562 human_data->color,
4563 SAR_HUMAN_COLORS_MAX * sizeof(sar_color_struct)
4564 );
4565
4566 /* Animation position */
4567 hoist->anim_pos = 0;
4568 hoist->anim_rate = SAR_HUMAN_ANIM_RATE;
4569 /* TODO (using numan animation rate for now) */
4570 }
4571 else
4572 {
4573 fprintf(stderr,
4574 "%s: Line %i: Error:\
4575 Unable to create hoist (check object type).\n",
4576 filename, line_num
4577 );
4578 }
4579 }
4580 /* Ground Elevation */
4581 else if(!strcasecmp(parm, "ground_elevation"))
4582 {
4583 /* Arguments:
4584 *
4585 * <altitude>
4586 */
4587 float altitude = 0.0f;
4588
4589 arg = GET_ARG_F(arg, &altitude);
4590
4591 if(altitude < 0.0f)
4592 fprintf(
4593 stderr,
4594 "%s: Line %i: Warning:\
4595 Value for %s argument altitude=%f should not be negative.\n",
4596 filename, line_num,
4597 parm, altitude
4598 );
4599
4600 if(ground != NULL)
4601 {
4602 ground->elevation =
4603 (float)SFMFeetToMeters(altitude);
4604 }
4605 else
4606 {
4607 fprintf(
4608 stderr,
4609 "%s: Line %i: Warning:\
4610 Unable to set %s for object type %i (must be type %i).\n",
4611 filename, line_num,
4612 parm, obj_ptr->type, SAR_OBJ_TYPE_GROUND
4613 );
4614 }
4615 }
4616
4617 /* Unsupported Parameter */
4618 else
4619 {
4620 fprintf(
4621 stderr,
4622 "%s: Line %i: Warning:\
4623 Unsupported parameter \"%s\".\n",
4624 filename, line_num,
4625 parm
4626 );
4627 }
4628 }
4629 }
4630
4631 /*
4632 * Loads a V3D model file specified by filename and applies the
4633 * loaded data to the object specified by obj_num.
4634 */
SARObjLoadFromFile(sar_core_struct * core_ptr,int obj_num,const char * filename)4635 int SARObjLoadFromFile(
4636 sar_core_struct *core_ptr, int obj_num, const char *filename
4637 )
4638 {
4639 int status, line_num, *total;
4640 char *full_path;
4641 const char *v3d_model_name;
4642 FILE *fp;
4643
4644 void **v3d_h = NULL;
4645 void *h;
4646 int hn, htype, total_v3d_h = 0;
4647
4648 v3d_model_struct *v3d_model_ptr, **v3d_model = NULL;
4649 int v3d_model_num, total_v3d_models = 0;
4650
4651 gw_display_struct *display = core_ptr->display;
4652 sar_scene_struct *scene = core_ptr->scene;
4653 sar_object_struct ***ptr, *obj_ptr;
4654 sar_object_aircraft_struct *aircraft = NULL;
4655 sar_object_ground_struct *ground = NULL;
4656
4657 int total_rotors = 0;
4658 sar_obj_rotor_struct *rotor = NULL;
4659
4660 int total_aileron_lefts = 0;
4661 sar_obj_part_struct *aileron_left_ptr = NULL;
4662 int total_aileron_rights = 0;
4663 sar_obj_part_struct *aileron_right_ptr = NULL;
4664 int total_rudder_tops = 0;
4665 sar_obj_part_struct *rudder_top_ptr = NULL;
4666 int total_rudder_bottoms = 0;
4667 sar_obj_part_struct *rudder_bottom_ptr = NULL;
4668 int total_elevators = 0;
4669 sar_obj_part_struct *elevator_ptr = NULL;
4670 int total_cannards = 0;
4671 sar_obj_part_struct *cannard_ptr = NULL;
4672 int total_aileron_elevator_lefts = 0;
4673 sar_obj_part_struct *aileron_elevator_left_ptr = NULL;
4674 int total_aileron_elevator_rights = 0;
4675 sar_obj_part_struct *aileron_elevator_right_ptr = NULL;
4676 int total_flaps = 0;
4677 sar_obj_part_struct *flap_ptr = NULL;
4678 int total_abrakes = 0;
4679 sar_obj_part_struct *abrake_ptr = NULL;
4680 int total_lgears = 0;
4681 sar_obj_part_struct *lgear_ptr = NULL;
4682 int total_doors = 0;
4683 sar_obj_part_struct *door_ptr = NULL;
4684 int total_external_fueltanks = 0;
4685 sar_external_fueltank_struct *eft_ptr = NULL;
4686
4687 sar_direction_struct *dir;
4688 sar_position_struct *pos;
4689 char *sar_vmodel_name;
4690 sar_visual_model_struct **sar_vmodel, **sar_vmodel_ir;
4691
4692 struct stat stat_buf;
4693
4694
4695 if(STRISEMPTY(filename) || (display == NULL) || (scene == NULL))
4696 return(-1);
4697
4698 ptr = &core_ptr->object;
4699 total = &core_ptr->total_objects;
4700
4701 /* Get pointer to object */
4702 obj_ptr = (SARObjIsAllocated(*ptr, *total, obj_num)) ?
4703 (*ptr)[obj_num] : NULL;
4704 if(obj_ptr == NULL)
4705 return(-1);
4706
4707 pos = &obj_ptr->pos;
4708 dir = &obj_ptr->dir;
4709
4710 /* Get the full path to the object file */
4711 full_path = COMPLETE_PATH(filename);
4712 if(full_path == NULL)
4713 {
4714 fprintf(
4715 stderr,
4716 "%s: Unable to complete path.\n",
4717 filename
4718 );
4719 return(-2);
4720 }
4721
4722 /* Set filename as the full path */
4723 filename = full_path;
4724
4725 /* Check if file exists and get file stats */
4726 if(stat(filename, &stat_buf))
4727 {
4728 char *s = STRDUP(strerror(errno));
4729 if(s == NULL)
4730 s = STRDUP("no such file");
4731 *s = toupper(*s);
4732 fprintf(
4733 stderr,
4734 "%s: %s.\n",
4735 filename, s
4736 );
4737 free(s);
4738
4739 free(full_path);
4740 return(-1);
4741 }
4742 #ifdef S_ISDIR
4743 /* File is a directory? */
4744 if(S_ISDIR(stat_buf.st_mode))
4745 {
4746 fprintf(
4747 stderr,
4748 "%s: Is a directory.\n",
4749 filename
4750 );
4751
4752 free(full_path);
4753 return(-2);
4754 }
4755 #endif /* S_ISDIR */
4756
4757 /* Open the V3D model file for reading */
4758 fp = FOpen(filename, "rb");
4759 if(fp == NULL)
4760 {
4761 fprintf(
4762 stderr,
4763 "%s: Unable to open the V3D Model file for reading.\n",
4764 filename
4765 );
4766
4767 free(full_path);
4768 return(-1);
4769 }
4770
4771
4772 /* Do preload procedure */
4773
4774 /* Reset object values */
4775 if(True)
4776 {
4777 /* Flags */
4778 obj_ptr->flags |= SAR_OBJ_FLAG_HIDE_DAWN_MODEL |
4779 SAR_OBJ_FLAG_HIDE_DUSK_MODEL |
4780 SAR_OBJ_FLAG_HIDE_NIGHT_MODEL;
4781
4782
4783 /* Begin resetting object type specific values */
4784
4785 /* Aircraft */
4786 aircraft = SAR_OBJ_GET_AIRCRAFT(obj_ptr);
4787 if(aircraft != NULL)
4788 {
4789 sar_direction_struct *dir;
4790
4791 aircraft->z_accel = 0.0f;
4792
4793 aircraft->air_worthy_state = SAR_AIR_WORTHY_FLYABLE;
4794 aircraft->engine_state = SAR_ENGINE_ON;
4795 aircraft->next_engine_on = 0;
4796
4797 aircraft->ground_pitch_offset = (float)(0.0 * PI);
4798
4799 dir = &aircraft->spotlight_dir;
4800 dir->heading = (float)SFMDegreesToRadians(
4801 SAR_DEF_SPOTLIGHT_HEADING
4802 );
4803 dir->pitch = (float)SFMDegreesToRadians(
4804 SAR_DEF_SPOTLIGHT_PITCH
4805 );
4806 dir->bank = (float)SFMDegreesToRadians(
4807 SAR_DEF_SPOTLIGHT_BANK
4808 );
4809
4810 aircraft->landed = 1;
4811
4812 aircraft->landing_gear_state = -1;
4813 aircraft->air_brakes_state = -1;
4814 aircraft->wheel_brakes_state = -1;
4815
4816 obj_ptr->temperature = SAR_DEF_TEMPERATURE_AIRCRAFT;
4817 }
4818 /* Ground */
4819 ground = SAR_OBJ_GET_GROUND(obj_ptr);
4820 if(ground != NULL)
4821 {
4822
4823
4824 }
4825 }
4826
4827 /* Begin reading V3D model file */
4828 status = V3DLoadModel(
4829 NULL, fp,
4830 &v3d_h, &total_v3d_h,
4831 &v3d_model, &total_v3d_models,
4832 NULL, NULL
4833 );
4834
4835 /* Close the V3D model file, it is no longer needed */
4836 FClose(fp);
4837 fp = NULL;
4838
4839 /* Error loading V3D model file? */
4840 if(status)
4841 {
4842 /* Error encountered while loading the visual model file,
4843 * delete V3D header items, model primitives, and return
4844 * indicating error
4845 */
4846 V3DMHListDeleteAll(&v3d_h, &total_v3d_h);
4847 V3DModelListDeleteAll(&v3d_model, &total_v3d_models);
4848 free(full_path);
4849 return(-1);
4850 }
4851
4852
4853 /* Iterate through V3D header items */
4854 for(hn = 0; hn < total_v3d_h; hn++)
4855 {
4856 h = v3d_h[hn];
4857 if(h == NULL)
4858 continue;
4859
4860 /* Handle by header item type */
4861 htype = V3DMHGetType(h);
4862 switch(htype)
4863 {
4864 const mh_comment_struct *mh_comment;
4865 const mh_texture_base_directory_struct *mh_tbd;
4866 const mh_texture_load_struct *mh_texture_load;
4867 const mh_color_specification_struct *mh_color_spec;
4868 sar_parm_texture_load_struct *p_texture_load;
4869
4870 case V3DMH_TYPE_COMMENT:
4871 mh_comment = (mh_comment_struct *)h;
4872 /* Ignore comments */
4873 break;
4874
4875 case V3DMH_TYPE_TEXTURE_BASE_DIRECTORY:
4876 mh_tbd = (mh_texture_base_directory_struct *)h;
4877 /* Ignore */
4878 break;
4879
4880 case V3DMH_TYPE_TEXTURE_LOAD:
4881 mh_texture_load = (mh_texture_load_struct *)h;
4882 p_texture_load = (sar_parm_texture_load_struct *)SARParmNew(
4883 SAR_PARM_TEXTURE_LOAD
4884 );
4885 if(p_texture_load != NULL)
4886 {
4887 /* Copy data from model header item to sar parm */
4888 free(p_texture_load->name);
4889 p_texture_load->name = STRDUP(mh_texture_load->name);
4890 free(p_texture_load->file);
4891 p_texture_load->file = STRDUP(mh_texture_load->path);
4892 p_texture_load->priority = (float)mh_texture_load->priority;
4893 /* Load texture using the sar parm */
4894 SARObjLoadTexture(
4895 core_ptr, scene,
4896 p_texture_load
4897 );
4898 /* Deallocate sar parm for loading texture, not needed
4899 * anymore.
4900 */
4901 SARParmDelete(p_texture_load);
4902 }
4903 break;
4904
4905 case V3DMH_TYPE_COLOR_SPECIFICATION:
4906 mh_color_spec = (mh_color_specification_struct *)h;
4907 /* Ignore */
4908 break;
4909 }
4910 }
4911
4912
4913 /* Iterate through V3D models */
4914 for(v3d_model_num = 0; v3d_model_num < total_v3d_models; v3d_model_num++)
4915 {
4916 v3d_model_ptr = v3d_model[v3d_model_num];
4917 if(v3d_model_ptr == NULL)
4918 continue;
4919
4920 /* Get pointers to the object's parts for use with this
4921 * V3D model, the pointers must be obtained for each
4922 * V3D model since each V3D model may create a new object
4923 * part
4924 */
4925 if(aircraft != NULL)
4926 {
4927 /* Rotors */
4928 total_rotors = aircraft->total_rotors;
4929 rotor = ((total_rotors > 0) ?
4930 aircraft->rotor[total_rotors - 1] : NULL
4931 );
4932
4933 /* External fuel tanks */
4934 total_external_fueltanks = aircraft->total_external_fueltanks;
4935 eft_ptr = ((total_external_fueltanks > 0) ?
4936 aircraft->external_fueltank[total_external_fueltanks - 1]
4937 : NULL
4938 );
4939 }
4940 /* Add fetching of substructure pointers support for other object
4941 * types here
4942 */
4943 else
4944 {
4945 /* Rotors */
4946 total_rotors = 0;
4947 rotor = NULL;
4948
4949 /* External fuel tanks */
4950 total_external_fueltanks = 0;
4951 eft_ptr = NULL;
4952 }
4953
4954 /* Get pointers to the object's parts */
4955 if(True)
4956 {
4957 int i;
4958 sar_obj_part_struct *part;
4959
4960 #define GET_PART(_type_) { \
4961 sar_obj_part_struct *p; \
4962 i = 0; \
4963 part = NULL; \
4964 while(True) { \
4965 p = SARObjGetPartPtr(obj_ptr, (_type_), i); \
4966 if(p != NULL) { \
4967 part = p; i++; \
4968 } else { \
4969 break; \
4970 } \
4971 } \
4972 }
4973 GET_PART(SAR_OBJ_PART_TYPE_AILERON_LEFT);
4974 total_aileron_lefts = i;
4975 aileron_left_ptr = part;
4976
4977 GET_PART(SAR_OBJ_PART_TYPE_AILERON_RIGHT);
4978 total_aileron_rights = i;
4979 aileron_right_ptr = part;
4980
4981 GET_PART(SAR_OBJ_PART_TYPE_RUDDER_TOP);
4982 total_rudder_tops = i;
4983 rudder_top_ptr = part;
4984
4985 GET_PART(SAR_OBJ_PART_TYPE_RUDDER_BOTTOM);
4986 total_rudder_bottoms = i;
4987 rudder_bottom_ptr = part;
4988
4989 GET_PART(SAR_OBJ_PART_TYPE_ELEVATOR);
4990 total_elevators = i;
4991 elevator_ptr = part;
4992
4993 GET_PART(SAR_OBJ_PART_TYPE_CANNARD);
4994 total_cannards = i;
4995 cannard_ptr = part;
4996
4997 GET_PART(SAR_OBJ_PART_TYPE_AILERON_ELEVATOR_LEFT);
4998 total_aileron_elevator_lefts = i;
4999 aileron_elevator_left_ptr = part;
5000
5001 GET_PART(SAR_OBJ_PART_TYPE_AILERON_ELEVATOR_RIGHT);
5002 total_aileron_elevator_rights = i;
5003 aileron_elevator_right_ptr = part;
5004
5005 GET_PART(SAR_OBJ_PART_TYPE_FLAP);
5006 total_flaps = i;
5007 flap_ptr = part;
5008
5009 GET_PART(SAR_OBJ_PART_TYPE_AIR_BRAKE);
5010 total_abrakes = i;
5011 abrake_ptr = part;
5012
5013 GET_PART(SAR_OBJ_PART_TYPE_LANDING_GEAR);
5014 total_lgears = i;
5015 lgear_ptr = part;
5016
5017 GET_PART(SAR_OBJ_PART_TYPE_DOOR_RESCUE);
5018 total_doors = i;
5019 door_ptr = part;
5020 #undef GET_PART
5021 }
5022
5023
5024 /* Iterate through each "other data" line on this V3D
5025 * model, these "other data" lines will specify values that
5026 * are specific to SAR objects
5027 */
5028 for(line_num = 0; line_num < v3d_model_ptr->total_other_data_lines; line_num++)
5029 {
5030 const char *s = v3d_model_ptr->other_data_line[line_num];
5031 if(s == NULL)
5032 continue;
5033
5034 SARObjLoadLine(
5035 core_ptr, obj_num, obj_ptr,
5036 s, filename, line_num
5037 );
5038 }
5039
5040 /* Do not continue the handling of this V3D model if it
5041 * does not contain primitives (if this V3D model is not of
5042 * type V3D_MODEL_TYPE_STANDARD)
5043 */
5044 if(v3d_model_ptr->type != V3D_MODEL_TYPE_STANDARD)
5045 continue;
5046
5047 /* Create model by the V3D model's name, the name must
5048 * be defined or else we will not be able to know what
5049 * this V3D model is suppose to represent
5050 */
5051 v3d_model_name = v3d_model_ptr->name;
5052 if(STRISEMPTY(v3d_model_name))
5053 continue;
5054
5055 /* Reset the SAR visual model & name pointers */
5056 sar_vmodel = NULL;
5057 sar_vmodel_ir = NULL;
5058 sar_vmodel_name = NULL;
5059
5060 /* Get the sar_vmodel & sar_vmodel_name by the V3D model's
5061 * name
5062 */
5063 /* Standard */
5064 if(!strcasecmp(v3d_model_name, "standard"))
5065 {
5066 sar_vmodel = &obj_ptr->visual_model;
5067 sar_vmodel_ir = &obj_ptr->visual_model_ir;
5068 free(sar_vmodel_name);
5069 sar_vmodel_name = STRDUP("standard");
5070 }
5071 /* Standard Far */
5072 else if(!strcasecmp(v3d_model_name, "standard_far"))
5073 {
5074 sar_vmodel = &obj_ptr->visual_model_far;
5075 free(sar_vmodel_name);
5076 sar_vmodel_name = STRDUP("standard_far");
5077 }
5078 /* Standard Dusk */
5079 else if(!strcasecmp(v3d_model_name, "standard_dusk"))
5080 {
5081 sar_vmodel = &obj_ptr->visual_model_dusk;
5082 free(sar_vmodel_name);
5083 sar_vmodel_name = STRDUP("standard_dusk");
5084 }
5085 /* Standard Night */
5086 else if(!strcasecmp(v3d_model_name, "standard_night"))
5087 {
5088 sar_vmodel = &obj_ptr->visual_model_night;
5089 free(sar_vmodel_name);
5090 sar_vmodel_name = STRDUP("standard_night");
5091 }
5092 /* Standard Dawn */
5093 else if(!strcasecmp(v3d_model_name, "standard_dawn"))
5094 {
5095 sar_vmodel = &obj_ptr->visual_model_dawn;
5096 free(sar_vmodel_name);
5097 sar_vmodel_name = STRDUP("standard_dawn");
5098 }
5099 /* Rotor */
5100 else if(!strcasecmp(v3d_model_name, "rotor") ||
5101 !strcasecmp(v3d_model_name, "propellar")
5102 )
5103 {
5104 if(rotor != NULL)
5105 {
5106 char s[80];
5107 sprintf(s, "rotor%i", total_rotors - 1);
5108
5109 sar_vmodel = &rotor->visual_model;
5110 sar_vmodel_ir = &rotor->visual_model_ir;
5111 free(sar_vmodel_name);
5112 sar_vmodel_name = STRDUP(s);
5113 }
5114 }
5115 /* Aileron Left */
5116 else if(!strcasecmp(v3d_model_name, "aileron_left"))
5117 {
5118 if(aileron_left_ptr != NULL)
5119 {
5120 char s[80];
5121 sprintf(s, "aileron_left%i", total_aileron_lefts - 1);
5122
5123 sar_vmodel = &aileron_left_ptr->visual_model;
5124 sar_vmodel_ir = &aileron_left_ptr->visual_model_ir;
5125 free(sar_vmodel_name);
5126 sar_vmodel_name = STRDUP(s);
5127 }
5128 }
5129 /* Aileron Right */
5130 else if(!strcasecmp(v3d_model_name, "aileron_right"))
5131 {
5132 if(aileron_right_ptr != NULL)
5133 {
5134 char s[80];
5135 sprintf(s, "aileron_right%i", total_aileron_rights - 1);
5136
5137 sar_vmodel = &aileron_right_ptr->visual_model;
5138 sar_vmodel_ir = &aileron_right_ptr->visual_model_ir;
5139 free(sar_vmodel_name);
5140 sar_vmodel_name = STRDUP(s);
5141 }
5142 }
5143 /* Rudder Top */
5144 else if(!strcasecmp(v3d_model_name, "rudder_top"))
5145 {
5146 if(rudder_top_ptr != NULL)
5147 {
5148 char s[80];
5149 sprintf(s, "rudder_top%i", total_rudder_tops - 1);
5150
5151 sar_vmodel = &rudder_top_ptr->visual_model;
5152 sar_vmodel_ir = &rudder_top_ptr->visual_model_ir;
5153 free(sar_vmodel_name);
5154 sar_vmodel_name = STRDUP(s);
5155 }
5156 }
5157 /* Rudder Bottom */
5158 else if(!strcasecmp(v3d_model_name, "rudder_bottom"))
5159 {
5160 if(rudder_bottom_ptr != NULL)
5161 {
5162 char s[80];
5163 sprintf(s, "rudder_bottom%i", total_rudder_bottoms - 1);
5164
5165 sar_vmodel = &rudder_bottom_ptr->visual_model;
5166 sar_vmodel_ir = &rudder_bottom_ptr->visual_model_ir;
5167 free(sar_vmodel_name);
5168 sar_vmodel_name = STRDUP(s);
5169 }
5170 }
5171 /* Elevator */
5172 else if(!strcasecmp(v3d_model_name, "elevator"))
5173 {
5174 if(elevator_ptr != NULL)
5175 {
5176 char s[80];
5177 sprintf(s, "elevator%i", total_elevators - 1);
5178
5179 sar_vmodel = &elevator_ptr->visual_model;
5180 sar_vmodel_ir = &elevator_ptr->visual_model_ir;
5181 free(sar_vmodel_name);
5182 sar_vmodel_name = STRDUP(s);
5183 }
5184 }
5185 /* Cannard */
5186 else if(!strcasecmp(v3d_model_name, "cannard"))
5187 {
5188 if(cannard_ptr != NULL)
5189 {
5190 char s[80];
5191 sprintf(s, "cannard%i", total_cannards - 1);
5192
5193 sar_vmodel = &cannard_ptr->visual_model;
5194 sar_vmodel_ir = &cannard_ptr->visual_model_ir;
5195 free(sar_vmodel_name);
5196 sar_vmodel_name = STRDUP(s);
5197 }
5198 }
5199 /* Aileron Elevator Left */
5200 else if(!strcasecmp(v3d_model_name, "aileron_elevator_left"))
5201 {
5202 if(aileron_elevator_left_ptr != NULL)
5203 {
5204 char s[80];
5205 sprintf(s, "aileron_elevator_left%i", total_aileron_elevator_lefts - 1);
5206
5207 sar_vmodel = &aileron_elevator_left_ptr->visual_model;
5208 sar_vmodel_ir = &aileron_elevator_left_ptr->visual_model_ir;
5209 free(sar_vmodel_name);
5210 sar_vmodel_name = STRDUP(s);
5211 }
5212 }
5213 /* Aileron Elevator Right */
5214 else if(!strcasecmp(v3d_model_name, "aileron_elevator_right"))
5215 {
5216 if(aileron_elevator_right_ptr != NULL)
5217 {
5218 char s[80];
5219 sprintf(s, "aileron_elevator_right%i", total_aileron_elevator_rights - 1);
5220
5221 sar_vmodel = &aileron_elevator_right_ptr->visual_model;
5222 sar_vmodel_ir = &aileron_elevator_right_ptr->visual_model_ir;
5223 free(sar_vmodel_name);
5224 sar_vmodel_name = STRDUP(s);
5225 }
5226 }
5227 /* Flap */
5228 else if(!strcasecmp(v3d_model_name, "flap"))
5229 {
5230 if(flap_ptr != NULL)
5231 {
5232 char s[80];
5233 sprintf(s, "flap%i", total_flaps - 1);
5234
5235 sar_vmodel = &flap_ptr->visual_model;
5236 sar_vmodel_ir = &flap_ptr->visual_model_ir;
5237 free(sar_vmodel_name);
5238 sar_vmodel_name = STRDUP(s);
5239 }
5240 }
5241 /* Air Brake */
5242 else if(!strcasecmp(v3d_model_name, "air_brake"))
5243 {
5244 if(abrake_ptr != NULL)
5245 {
5246 char s[80];
5247 sprintf(s, "air_brake%i", total_abrakes - 1);
5248
5249 sar_vmodel = &abrake_ptr->visual_model;
5250 sar_vmodel_ir = &abrake_ptr->visual_model_ir;
5251 free(sar_vmodel_name);
5252 sar_vmodel_name = STRDUP(s);
5253 }
5254 }
5255 /* Landing Gear */
5256 else if(!strcasecmp(v3d_model_name, "landing_gear"))
5257 {
5258 if(lgear_ptr != NULL)
5259 {
5260 char s[80];
5261 sprintf(s, "landing_gear%i", total_lgears - 1);
5262
5263 sar_vmodel = &lgear_ptr->visual_model;
5264 sar_vmodel_ir = &lgear_ptr->visual_model_ir;
5265 free(sar_vmodel_name);
5266 sar_vmodel_name = STRDUP(s);
5267 }
5268 }
5269 /* Door */
5270 else if(!strcasecmp(v3d_model_name, "door"))
5271 {
5272 if(door_ptr != NULL)
5273 {
5274 char s[80];
5275 sprintf(s, "door%i", total_doors - 1);
5276
5277 sar_vmodel = &door_ptr->visual_model;
5278 sar_vmodel_ir = &door_ptr->visual_model_ir;
5279 free(sar_vmodel_name);
5280 sar_vmodel_name = STRDUP(s);
5281 }
5282 }
5283 /* External Fuel Tank */
5284 else if(!strcasecmp(v3d_model_name, "fueltank") ||
5285 !strcasecmp(v3d_model_name, "fuel_tank")
5286 )
5287 {
5288 if(eft_ptr != NULL)
5289 {
5290 char s[80];
5291 sprintf(s, "fueltank%i", total_external_fueltanks - 1);
5292
5293 sar_vmodel = &eft_ptr->visual_model;
5294 sar_vmodel_ir = &eft_ptr->visual_model_ir;
5295 free(sar_vmodel_name);
5296 sar_vmodel_name = STRDUP(s);
5297 }
5298 }
5299 /* Cockpit */
5300 else if(!strcasecmp(v3d_model_name, "cockpit"))
5301 {
5302 if(aircraft != NULL)
5303 {
5304 sar_vmodel = &aircraft->visual_model_cockpit;
5305 free(sar_vmodel_name);
5306 sar_vmodel_name = STRDUP("cockpit");
5307 }
5308 }
5309 /* Shadow */
5310 else if(!strcasecmp(v3d_model_name, "shadow"))
5311 {
5312 sar_vmodel = &obj_ptr->visual_model_shadow;
5313 free(sar_vmodel_name);
5314 sar_vmodel_name = STRDUP("shadow");
5315 }
5316
5317 /* If sar_vmodel is NULL then it means that the V3D model's
5318 * name did not match a SAR visual model that is supported
5319 */
5320 if(sar_vmodel == NULL)
5321 {
5322 /* The V3D model's name is not one that we support */
5323 fprintf(
5324 stderr,
5325 "%s: Warning:\
5326 V3D model type \"%s\" is not supported on this object (check object type).\n",
5327 filename, v3d_model_name
5328 );
5329
5330 /* Delete SAR visual model name */
5331 free(sar_vmodel_name);
5332 sar_vmodel_name = NULL;
5333
5334 continue; /* Do not create this SAR Visual Model */
5335 }
5336
5337 /* Is this SAR Visual Model already created? */
5338 if(*sar_vmodel != NULL)
5339 {
5340 /* Warn about redefining this SAR Visual Model and then
5341 * unref it
5342 */
5343 fprintf(
5344 stderr,
5345 "%s: Warning:\
5346 V3D model type \"%s\" redefined.\n",
5347 filename, v3d_model_name
5348 );
5349 SARVisualModelUnref(scene, *sar_vmodel);
5350 *sar_vmodel = NULL;
5351 }
5352 /* Is this IR SAR Visual Model already created? */
5353 if((sar_vmodel_ir != NULL) ? (*sar_vmodel_ir != NULL) : False)
5354 {
5355 /* Unref this IR SAR Visual Model */
5356 SARVisualModelUnref(scene, *sar_vmodel_ir);
5357 *sar_vmodel_ir = NULL;
5358 }
5359
5360 /* Create a new or return existing SAR Visual Model */
5361 *sar_vmodel = SARVisualModelNew(
5362 scene, filename, sar_vmodel_name
5363 );
5364 /* Is this a "new" Visual Model? */
5365 if(SARVisualModelGetRefCount(*sar_vmodel) == 1)
5366 {
5367 /* Create GL display list on the Visual Model */
5368 sar_visual_model_struct *vmodel = *sar_vmodel;
5369 GLuint list = (GLuint)SARVisualModelNewList(vmodel);
5370 if(list != 0)
5371 {
5372 /* Mark SAR Visual Model as loading and begin
5373 * recording the GL display list
5374 */
5375 vmodel->load_state = SAR_VISUAL_MODEL_LOADING;
5376 glNewList(list, GL_COMPILE);
5377
5378 /* Process this V3D model into GL commands */
5379 SARObjLoadProcessVisualModel(
5380 core_ptr, obj_num, obj_ptr,
5381 vmodel,
5382 v3d_model_ptr,
5383 False, /* Not not process as IR */
5384 filename, 0
5385 );
5386
5387 /* End recording GL display list and mark the SAR
5388 * Visual Model as finished loading
5389 */
5390 glEndList();
5391 vmodel->load_state = SAR_VISUAL_MODEL_LOADED;
5392 }
5393 }
5394 else
5395 {
5396 /* This SAR Visual Model already has more than one ref
5397 * count which implies it is shared
5398 *
5399 * Check for V3D Model primitives that still need to be
5400 * loaded, all of the primitives handled here should
5401 * not produce any GL commands
5402 */
5403 int pn, ptype;
5404 void *p;
5405 sar_visual_model_struct *vmodel = *sar_vmodel;
5406
5407 for(pn = 0; pn < v3d_model_ptr->total_primitives; pn++)
5408 {
5409 p = v3d_model_ptr->primitive[pn];
5410 if(p == NULL)
5411 continue;
5412
5413 ptype = V3DMPGetType(p);
5414 switch(ptype)
5415 {
5416 const mp_heightfield_load_struct *mp_heightfield_load;
5417 case V3DMP_TYPE_HEIGHTFIELD_LOAD:
5418 mp_heightfield_load = (mp_heightfield_load_struct *)p;
5419 /* Need to load z points for height field but
5420 * not issue any GL commands for it (by
5421 * passing the GL list as 0)
5422 */
5423 SARObjLoadHeightField(
5424 core_ptr, obj_num, obj_ptr, vmodel,
5425 p, filename, 0,
5426 0 /* No GL display list */
5427 );
5428 break;
5429 }
5430
5431 }
5432 }
5433
5434 /* Create IR SAR Visual Model? */
5435 if((sar_vmodel_ir != NULL) &&
5436 ((obj_ptr->type == SAR_OBJ_TYPE_STATIC) ||
5437 (obj_ptr->type == SAR_OBJ_TYPE_AUTOMOBILE) ||
5438 (obj_ptr->type == SAR_OBJ_TYPE_WATERCRAFT) ||
5439 (obj_ptr->type == SAR_OBJ_TYPE_AIRCRAFT)
5440 )
5441 )
5442 {
5443 char *sar_vmodel_name_ir = STRDUP(sar_vmodel_name);
5444
5445 /* Format the IR SAR Visual Model name */
5446 sar_vmodel_name_ir = strinsstr(
5447 sar_vmodel_name_ir, -1, "_ir"
5448 );
5449
5450 /* Create a new or return existing IR SAR Visual Model */
5451 *sar_vmodel_ir = SARVisualModelNew(
5452 scene, filename, sar_vmodel_name_ir
5453 );
5454 /* Is this a "new" Visual Model? */
5455 if(SARVisualModelGetRefCount(*sar_vmodel_ir) == 1)
5456 {
5457 /* Create GL display list on the Visual Model */
5458 sar_visual_model_struct *vmodel = *sar_vmodel_ir;
5459 GLuint list = (GLuint)SARVisualModelNewList(vmodel);
5460 if(list != 0)
5461 {
5462 /* Mark SAR Visual Model as loading and begin
5463 * recording the GL display list
5464 */
5465 vmodel->load_state = SAR_VISUAL_MODEL_LOADING;
5466 glNewList(list, GL_COMPILE);
5467
5468 /* Process this V3D model into GL commands */
5469 SARObjLoadProcessVisualModel(
5470 core_ptr, obj_num, obj_ptr,
5471 vmodel,
5472 v3d_model_ptr,
5473 True, /* Process as IR */
5474 filename, 0
5475 );
5476
5477 /* End recording GL display list and mark the
5478 * IR SAR Visual Model as finished loading
5479 */
5480 glEndList();
5481 vmodel->load_state = SAR_VISUAL_MODEL_LOADED;
5482 }
5483 }
5484
5485 free(sar_vmodel_name_ir);
5486 }
5487
5488
5489 /* Delete the SAR Visual Model name */
5490 free(sar_vmodel_name);
5491 sar_vmodel_name = NULL;
5492 }
5493
5494
5495 /* Delete V3D models and V3D header items (no longer needed) */
5496 V3DMHListDeleteAll(&v3d_h, &total_v3d_h);
5497 V3DModelListDeleteAll(&v3d_model, &total_v3d_models);
5498
5499
5500 /* Create flight dynamics model if object is an aircraft */
5501 if(aircraft != NULL)
5502 {
5503 if(scene->realm == NULL)
5504 {
5505 fprintf(
5506 stderr,
5507 "%s: Warning: Unable to create SFM for NULL realm on scene\n",
5508 filename
5509 );
5510 }
5511 else
5512 {
5513 /* Create new flight dynamics model and reset its
5514 * values to defaults
5515 */
5516 SFMModelStruct *fdm = SFMModelAllocate();
5517 if(fdm != NULL)
5518 {
5519 fdm->landed_state = True;
5520
5521 SFMModelAdd(scene->realm, fdm);
5522 }
5523 aircraft->fdm = fdm;
5524 }
5525 }
5526
5527
5528 /* Need to realize translation and rotation values on object */
5529 SARSimWarpObject(
5530 scene, obj_ptr,
5531 &obj_ptr->pos, &obj_ptr->dir
5532 );
5533
5534 /* Do postload check on object */
5535 SARObjLoadPostLoadCheck(
5536 obj_num, obj_ptr,
5537 filename
5538 );
5539
5540
5541 free(full_path);
5542
5543 return(0);
5544 }
5545