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 <GL/gl.h>
14 
15 #include "../include/fio.h"
16 #include "../include/string.h"
17 #include "../include/strexp.h"
18 #include "../include/disk.h"
19 
20 #include "gw.h"
21 #include "cp.h"
22 #include "sfm.h"
23 #include "sarreality.h"
24 #include "obj.h"
25 #include "objsound.h"
26 #include "objutils.h"
27 #include "objio.h"
28 #include "messages.h"
29 #include "simmanage.h"
30 #include "simcb.h"
31 #include "simutils.h"
32 #include "weather.h"
33 #include "sar.h"
34 #include "sarfio.h"
35 #include "sceneio.h"
36 #include "config.h"
37 
38 
39 void SARSceneDestroy(
40 	sar_core_struct *core_ptr,
41 	sar_scene_struct *scene,
42 	sar_object_struct ***ptr, int *total
43 );
44 void SARSceneLoadLocationsToList(
45 	sar_core_struct *core_ptr, sar_menu_struct *m,
46 	sar_menu_list_struct *list, int list_num,
47 	const char *filename
48 );
49 int SARSceneAddPlayerObject(
50 	sar_core_struct *core_ptr, sar_scene_struct *scene,
51 	const char *model_file,
52 	sar_position_struct *pos, sar_direction_struct *dir
53 );
54 int SARSceneLoadFromFile(
55 	sar_core_struct *core_ptr,
56 	sar_scene_struct *scene,
57 	const char *filename,
58 	const char *weather_preset_name,
59 	void *client_data,
60 	int (*progress_func)(void *, long, long)
61 );
62 
63 
64 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
65 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
66 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
67 
68 #define RADTODEG(r)     ((r) * 180 / PI)
69 #define DEGTORAD(d)     ((d) * PI / 180)
70 
71 #define ISCOMMENT(c)	((c) == SAR_COMMENT_CHAR)
72 #define ISCR(c)		(((c) == '\n') || ((c) == '\r'))
73 
74 #define STRDUP(s)	(((s) != NULL) ? strdup(s) : NULL)
75 
76 
77 /*
78  *	Deletes all resources on the scene structure and all
79  *	objects on the given objects pointer array.
80  *
81  *	Does not delete the scene structure itself, but the
82  *	scene structure will be reset.
83  */
SARSceneDestroy(sar_core_struct * core_ptr,sar_scene_struct * scene,sar_object_struct *** ptr,int * total)84 void SARSceneDestroy(
85 	sar_core_struct *core_ptr, sar_scene_struct *scene,
86 	sar_object_struct ***ptr, int *total
87 )
88 {
89 	int i;
90 	const sar_option_struct *opt = &core_ptr->option;
91 
92 	if(opt->runtime_debug)
93 	    printf("SARSceneDestroy(): Destroying scene...\n");
94 
95 
96 	/* Check if total objects is not NULL (which implies ptr is not
97 	 * NULL)
98 	 */
99 	if(total != NULL)
100 	{
101 	    /* Delete objects pointer array from last to first */
102 	    for(i = (*total) - 1; i >= 0; i--)
103 	        SARObjDelete(core_ptr, ptr, total, i);
104 	    *total = 0;
105 	}
106 	if(ptr != NULL)
107 	{
108 	    free(*ptr);
109 	    *ptr = NULL;
110 	}
111 
112 
113 	/* Delete scene */
114 	if(scene != NULL)
115 	{
116 	    sar_scene_base_struct *base = &scene->base;
117 	    sar_scene_horizon_struct *horizon_ptr = &scene->horizon;
118 
119 	    /* Title */
120 	    free(scene->title);
121 	    scene->title = NULL;
122 
123 	    /* Ground base */
124 	    /* Visual model simple (far away) */
125 	    SARVisualModelUnref(scene, base->visual_model_simple);
126 	    base->visual_model_simple = NULL;
127 	    /* Visual model complex (close up) */
128 	    SARVisualModelUnref(scene, base->visual_model_close);
129 	    base->visual_model_close = NULL;
130 
131 	    /* Cloud Layers */
132 	    for(i = 0; i < scene->total_cloud_layers; i++)
133 		SARCloudLayerDelete(scene, scene->cloud_layer[i]);
134 	    free(scene->cloud_layer);
135 	    scene->cloud_layer = NULL;
136 	    scene->total_cloud_layers = 0;
137 
138 	    /* Cloud BillBoards */
139 	    for(i = 0; i < scene->total_cloud_bbs; i++)
140 		SARCloudBBDelete(scene->cloud_bb[i]);
141 	    free(scene->cloud_bb);
142 	    scene->cloud_bb = NULL;
143 	    scene->total_cloud_bbs = 0;
144 
145 	    /* Horizon */
146 	    horizon_ptr = &scene->horizon;
147 	    for(i = 0; i < horizon_ptr->total_textures; i++)
148 		V3DTextureDestroy(horizon_ptr->texture[i]);
149 	    free(horizon_ptr->texture);
150 	    horizon_ptr->texture = NULL;
151 	    horizon_ptr->total_textures = 0;
152 
153 
154 	    /* Ground objects list, delete only the pointer array and
155 	     * not each object
156 	     */
157 	    free(scene->ground_object);
158 	    scene->ground_object = NULL;
159 	    scene->total_ground_objects = 0;
160 
161 	    /* Humans that need rescue list */
162 	    free(scene->human_need_rescue_object);
163 	    scene->human_need_rescue_object = NULL;
164 	    scene->total_human_need_rescue_objects = 0;
165 
166 	    /* Visual models, all visual models should have been
167 	     * unref'ed by now. So here we actually delete
168 	     * and destroy the GL lists
169 	     */
170 	    SARVisualModelDeleteAll(scene);
171 
172 	    /* Delete all textures */
173 	    for(i = 0; i < scene->total_texture_refs; i++)
174 		V3DTextureDestroy(scene->texture_ref[i]);
175 	    free(scene->texture_ref);	/* Free pointer array */
176 	    scene->texture_ref = NULL;
177 	    scene->total_texture_refs = 0;
178 
179 	    /* Reset texture reference indices for special textures */
180 	    scene->texnum_sun = -1;
181 	    scene->texnum_moon = -1;
182 	    scene->texnum_spotlightcast = -1;
183 
184 	    /* Delete all sound sources */
185 	    for(i = 0; i < scene->total_sndsrcs; i++)
186 		SARSoundSourceDelete(scene->sndsrc[i]);
187 	    free(scene->sndsrc);
188 	    scene->sndsrc = NULL;
189 	    scene->total_sndsrcs = 0;
190 
191 	    /* Control panel */
192 	    CPDelete(
193 		(ControlPanel *)scene->player_control_panel
194 	    );
195 	    scene->player_control_panel = NULL;
196 
197 
198 	    /* Messages */
199 	    strlistfree(scene->message, scene->total_messages);
200 	    scene->message = NULL;
201 	    scene->total_messages = 0;
202 
203 	    /* Sticky banner message */
204 	    strlistfree(
205 		scene->sticky_banner_message,
206 		scene->total_sticky_banner_messages
207 	    );
208 	    scene->sticky_banner_message = NULL;
209 	    scene->total_sticky_banner_messages = 0;
210 
211 	    /* Camera reference name/description title string */
212 	    free(scene->camera_ref_title);
213 	    scene->camera_ref_title = NULL;
214 
215 	    /* FDM Realm */
216 	    if(scene->realm != NULL)
217 		SFMShutdown(scene->realm);
218 
219 	    /* Reset the rest of the scene structure */
220 	    memset(scene, 0x00, sizeof(sar_scene_struct));
221 	}
222 
223 	if(opt->runtime_debug)
224 	    printf("SARSceneDestroy(): Scene destroyed.\n");
225 }
226 
227 /*
228  *	Loads the list of Registered Locations from the specified
229  *	scene file to the specified List.
230  */
SARSceneLoadLocationsToList(sar_core_struct * core_ptr,sar_menu_struct * m,sar_menu_list_struct * list,int list_num,const char * filename)231 void SARSceneLoadLocationsToList(
232 	sar_core_struct *core_ptr, sar_menu_struct *m,
233 	sar_menu_list_struct *list, int list_num,
234 	const char *filename
235 )
236 {
237 	int i, ptype, total_parms;
238 	void *p, **parm;
239 
240 	if(list == NULL)
241 	    return;
242 
243 	/* Delete existing items in the List */
244 	for(i = 0; i < list->total_items; i++)
245 	    SARDeleteListItemData(list->item[i]);
246 	SARMenuListDeleteAllItems(m, list_num);
247 
248 	/* Load all SAR_PARM_REGISTER_LOCATION parameters from the
249 	 * scene file
250 	 */
251 	if(SARParmLoadFromFile(
252 	    filename, SAR_FILE_FORMAT_SCENE,
253 	    &parm, &total_parms,
254 	    SAR_PARM_REGISTER_LOCATION,		/* Filter */
255 	    NULL, NULL
256 	))
257 	    return;
258 
259 	/* Iterate through loaded parms */
260 	for(i = 0; i < total_parms; i++)
261 	{
262 	    p = parm[i];
263 	    if(p == NULL)
264 		continue;
265 
266 	    ptype = *(int *)p;
267 	    if(ptype == SAR_PARM_REGISTER_LOCATION)
268 	    {
269 		int n;
270 		sar_menu_list_item_data_struct *d;
271 		sar_parm_register_location_struct *pv =
272 		    (sar_parm_register_location_struct *)p;
273 
274 		/* Allocate a new list item data */
275 		d = SAR_MENU_LIST_ITEM_DATA(calloc(
276 		    1, sizeof(sar_menu_list_item_data_struct)
277 		));
278 		if(d != NULL)
279 		{
280 		    /* Position */
281 		    memcpy(
282 			&d->pos,
283 			&pv->pos,
284 			sizeof(sar_position_struct)
285 		    );
286 
287 		    /* Direction */
288 		    memcpy(
289 			&d->dir,
290 			&pv->dir,
291 			sizeof(sar_direction_struct)
292 		    );
293 
294 		    /* Name */
295 		    d->name = STRDUP(pv->name);
296 
297 		    /* Add this location to the menu's list object */
298 		    n = SARMenuListAppendItem(
299 			m, list_num,
300 			d->name, d,
301 			0
302 		    );
303 		    if(n < 0)
304 		    {
305 			fprintf(
306 			    stderr,
307  "Error appending list item for starting location `%s'\n",
308 			    d->name
309 			);
310 
311 			free(d->filename);
312 			free(d->name);
313 			free(d);
314 		    }
315 		    d = NULL;
316 		}
317 	    }
318 	}
319 
320 	/* Delete loaded parms */
321 	SARParmDeleteAll(&parm, &total_parms);
322 }
323 
324 
325 /*
326  *	Adds a player object to the scene using the specified model
327  *	file and initial position & direction.
328  *
329  *	Updates the player object references on the scene.
330  *
331  *	All inputs must be valid (except for pos and dir).
332  *
333  *	Returns non-zero on error.
334  */
SARSceneAddPlayerObject(sar_core_struct * core_ptr,sar_scene_struct * scene,const char * model_file,sar_position_struct * pos,sar_direction_struct * dir)335 int SARSceneAddPlayerObject(
336 	sar_core_struct *core_ptr, sar_scene_struct *scene,
337 	const char *model_file,
338 	sar_position_struct *pos, sar_direction_struct *dir
339 )
340 {
341 	int obj_num;
342 	sar_object_struct *obj_ptr;
343 	sar_object_aircraft_struct *obj_aircraft_ptr;
344 	sar_position_struct lpos;
345 	sar_direction_struct ldir;
346 
347 
348 	if((core_ptr == NULL) || (scene == NULL) || (model_file == NULL))
349 	    return(-1);
350 
351 	/* Create player object on to scene */
352 	obj_num = SARObjNew(
353 	    scene, &core_ptr->object, &core_ptr->total_objects,
354 	    SAR_OBJ_TYPE_AIRCRAFT
355 	);
356 	obj_ptr = (obj_num > -1) ? core_ptr->object[obj_num] : NULL;
357 	if(obj_ptr == NULL)
358 	    return(-1);
359 
360 	/* Update player object references on scene structure (this
361 	 * must be done immediately after creating of the player object
362 	 * so that SARObjLoadFromFile() can tell this is the player
363 	 * object
364 	 */
365 	scene->player_obj_num = obj_num;
366 	scene->player_obj_ptr = obj_ptr;
367 
368 	/* Load player object model file */
369 	SARObjLoadFromFile(core_ptr, obj_num, model_file);
370 
371 	/* Set object name to "player", this will override the name
372 	 * of this object specified in the model file.  This needs to
373 	 * be set so that subsequent configurations can reffer to
374 	 * this object by the name of "player" in order to match it
375 	 * (ie in mission files)
376 	 */
377 	free(obj_ptr->name);
378 	obj_ptr->name = STRDUP("player");
379 
380 
381 	/* Set local position structure */
382 	if(pos != NULL)
383 	    memcpy(&lpos, pos, sizeof(sar_position_struct));
384 	else
385 	    memset(&lpos, 0x00, sizeof(sar_position_struct));
386 
387 	/* Adjust ground_elevation_msl so that it's at the position of
388 	 * the player object, this way the player won't suddenly drop
389 	 * and be destroyed
390 	 */
391 	obj_ptr->ground_elevation_msl = lpos.z;
392 
393 	/* Move player up from ground level so that it does not added into
394 	 * the scene while embedded in the ground (which may cause a
395 	 * crash if the given pos is ontop of a building)
396 	 */
397 	obj_aircraft_ptr = SAR_OBJ_GET_AIRCRAFT(obj_ptr);
398 	if(obj_aircraft_ptr != NULL)
399 	{
400 	    lpos.z += (float)MAX(obj_aircraft_ptr->belly_height, 0.0);
401 	    lpos.z += (float)MAX(obj_aircraft_ptr->gear_height, 0.0);
402 	}
403 
404 /* Add other object types that need their position modified here */
405 
406 	/* Set local direction structure */
407 	if(dir != NULL)
408 	    memcpy(&ldir, dir, sizeof(sar_direction_struct));
409 	else
410 	    memset(&ldir, 0x00, sizeof(sar_direction_struct));
411 
412 	/* Move player object to starting location and attitude */
413 	SARSimWarpObject(scene, obj_ptr, &lpos, &ldir);
414 
415 	return(0);
416 }
417 
418 /*
419  *	Opens the Scene from the specified file.
420  *
421  *	All default values for the Scene will be allocated/created/set
422  *	and any existing values will be deleted/reset.
423  *
424  */
SARSceneLoadFromFile(sar_core_struct * core_ptr,sar_scene_struct * scene,const char * filename,const char * weather_preset_name,void * client_data,int (* progress_func)(void *,long,long))425 int SARSceneLoadFromFile(
426 	sar_core_struct *core_ptr,
427 	sar_scene_struct *scene,
428 	const char *filename,
429 	const char *weather_preset_name,
430 	void *client_data,
431 	int (*progress_func)(void *, long, long)
432 )
433 {
434 	void *p, **parm;
435 	int i, status, ptype, total_parms;
436 	int obj_num = -1, *total;
437 	gw_display_struct *display;
438 	sar_direction_struct *dir;
439 	sar_color_struct *c;
440 	sar_object_struct *obj_ptr = NULL, ***ptr;
441 	sar_object_aircraft_struct *obj_aircraft_ptr = NULL;
442 	sar_object_ground_struct *obj_ground_ptr = NULL;
443 	sar_object_helipad_struct *obj_helipad_ptr = NULL;
444 	sar_object_runway_struct *obj_runway_ptr = NULL;
445 	sar_object_human_struct *obj_human_ptr = NULL;
446 	sar_object_smoke_struct *obj_smoke_ptr = NULL;
447 	sar_object_fire_struct *obj_fire_ptr = NULL;
448 	sar_scene_horizon_struct *horizon_ptr;
449 	struct stat stat_buf;
450 
451 	sar_parm_version_struct *p_version;
452 	sar_parm_name_struct *p_name;
453 	sar_parm_description_struct *p_description;
454 	sar_parm_player_model_file_struct *p_player_model_file;
455 	sar_parm_weather_struct *p_weather;
456 	sar_parm_register_location_struct *p_register_location;
457 	sar_parm_scene_gps_struct *p_scene_gps;
458 	sar_parm_scene_map_struct *p_scene_map;
459 	sar_parm_scene_elevation_struct *p_scene_elevation;
460 	sar_parm_scene_cant_struct *p_scene_cant;
461 	sar_parm_scene_ground_flags_struct *p_scene_ground_flags;
462 	sar_parm_scene_ground_tile_struct *p_scene_ground_tile;
463 	sar_parm_texture_base_directory_struct *p_texture_base_directory;
464 	sar_parm_texture_load_struct *p_texture_load;
465 	sar_parm_new_object_struct *p_new_object;
466 	sar_parm_new_helipad_struct *p_new_helipad;
467 	sar_parm_new_runway_struct *p_new_runway;
468 	sar_parm_new_human_struct *p_new_human;
469 	sar_parm_new_smoke_struct *p_new_smoke;
470 	sar_parm_new_fire_struct *p_new_fire;
471 	sar_parm_new_premodeled_struct *p_new_premodeled;
472 	sar_parm_model_file_struct *p_model_file;
473 	sar_parm_range_struct *p_range;
474 	sar_parm_range_far_struct *p_range_far;
475 	sar_parm_translate_struct *p_translate;
476 	sar_parm_translate_random_struct *p_translate_random;
477 	sar_parm_rotate_struct *p_rotate;
478 	sar_parm_no_depth_test_struct *p_no_depth_test;
479 	sar_parm_polygon_offset_struct *p_polygon_offset;
480 	sar_parm_contact_bounds_spherical_struct *p_contact_bounds_spherical;
481 	sar_parm_contact_bounds_cylendrical_struct *p_contact_bounds_cylendrical;
482 	sar_parm_contact_bounds_rectangular_struct *p_contact_bounds_rectangular;
483 	sar_parm_ground_elevation_struct *p_ground_elevation;
484 	sar_parm_object_name_struct *p_object_name;
485 	sar_parm_object_map_description_struct *p_object_map_description;
486 	sar_parm_fuel_struct *p_fuel;
487 	sar_parm_hitpoints_struct *p_hitpoints;
488 	sar_parm_engine_state_struct *p_engine_state;
489 	sar_parm_passengers_struct *p_passengers;
490 	sar_parm_runway_approach_lighting_north_struct *p_runway_applight_n;
491 	sar_parm_runway_approach_lighting_south_struct *p_runway_applight_s;
492 	sar_parm_human_message_enter_struct *p_human_message_enter;
493 	sar_parm_human_reference_struct *p_human_reference;
494 
495 
496 /* Resets object substructure pointers to NULL */
497 #define DO_RESET_SUBSTRUCTURE_PTRS	{	\
498  obj_aircraft_ptr = NULL;			\
499  obj_ground_ptr = NULL;				\
500  obj_helipad_ptr = NULL;			\
501  obj_runway_ptr = NULL;				\
502  obj_human_ptr = NULL;				\
503  obj_smoke_ptr = NULL;				\
504  obj_fire_ptr = NULL;				\
505 }
506 
507 
508 	if((core_ptr == NULL) || (scene == NULL) || (filename == NULL))
509 	    return(-1);
510 
511 	display = core_ptr->display;
512 
513 	ptr = &core_ptr->object;
514 	total = &core_ptr->total_objects;
515 
516 	/* Check if the file exists and get its stats */
517 	if(stat(filename, &stat_buf))
518 	{
519 	    char *s = STRDUP(strerror(errno));
520 	    if(s == NULL)
521 		s = STRDUP("no such file");
522 	    *s = toupper(*s);
523 	    fprintf(
524 		stderr,
525 		"%s: %s.\n",
526 		filename, s
527 	    );
528 	    free(s);
529 	    return(-1);
530 	}
531 
532 	/* Load all parameters from file */
533 	status = SARParmLoadFromFile(
534 	    filename, SAR_FILE_FORMAT_SCENE,
535 	    &parm, &total_parms,
536 	    -1,			/* No filter */
537 	    NULL, NULL
538 	);
539 	if(status)
540 	{
541 	    fprintf(
542 		stderr,
543 		"%s: Error loading scene.\n",
544 		filename
545 	    );
546 	    return(-1);
547 	}
548 
549 
550 	/* Delete the specified Scene and all its objects */
551 	SARSceneDestroy(core_ptr, scene, ptr, total);
552 
553 
554 	/* Reset Scene values */
555 	scene->tod = (12 * 3600);		/* Noon */
556 	scene->tod_code = SAR_TOD_CODE_DAY;
557 	scene->cant_angle = (float)(0.0 * PI);
558 	scene->base_flags = 0;
559 	scene->msl_elevation = 0.0f;
560 
561 	scene->dms_x_offset = 0;
562 	scene->dms_y_offset = 0;
563 	scene->planet_radius = SAR_DEF_PLANET_RADIUS;
564 
565 	scene->visual_model = NULL;
566 	scene->total_visual_models = 0;
567 
568 	c = &scene->sky_nominal_color;
569 	c->a = 1.0f;
570 	c->r = 1.0f;
571 	c->g = 1.0f;
572 	c->b = 1.0f;
573 	c = &scene->sky_brighten_color;
574 	c->a = 1.0f;
575 	c->r = 1.0f;
576 	c->g = 1.0f;
577 	c->b = 1.0f;
578 	c = &scene->sky_darken_color;
579 	c->a = 1.0f;
580 	c->r = 1.0f;
581 	c->g = 1.0f;
582 	c->b = 1.0f;
583 
584 	c = &scene->star_low_color;
585 	c->a = 1.0f;
586 	c->r = 1.0f;
587 	c->g = 1.0f;
588 	c->b = 1.0f;
589 	c = &scene->star_high_color;
590 	c->a = 1.0f;
591 	c->r = 1.0f;
592 	c->g = 1.0f;
593 	c->b = 1.0f;
594 
595 	c = &scene->sun_low_color;
596 	c->a = 1.0f;
597 	c->r = 1.0f;
598 	c->g = 1.0f;
599 	c->b = 1.0f;
600 	c = &scene->sun_high_color;
601 	c->a = 1.0f;
602 	c->r = 1.0f;
603 	c->g = 1.0f;
604 	c->b = 1.0f;
605 
606 	c = &scene->moon_low_color;
607 	c->a = 1.0f;
608 	c->r = 1.0f;
609 	c->g = 1.0f;
610 	c->b = 1.0f;
611 	c = &scene->moon_high_color;
612 	c->a = 1.0f;
613 	c->r = 1.0f;
614 	c->g = 1.0f;
615 	c->b = 1.0f;
616 
617 	scene->moon_visibility_hint = 0;
618 	scene->rain_density_coeff = 0.0f;
619 
620 	scene->player_obj_num = -1;
621 	scene->player_obj_ptr = NULL;
622 	scene->player_has_crashed = False;
623 
624 	scene->ground_object = NULL;
625 	scene->total_ground_objects = 0;
626 
627 	scene->human_need_rescue_object = NULL;
628 	scene->total_human_need_rescue_objects = 0;
629 
630 	scene->camera_ref = SAR_CAMERA_REF_COCKPIT;
631 	scene->camera_fovz = (float)SFMDegreesToRadians(40.0);
632 	dir = &scene->camera_cockpit_dir;
633 	dir->heading = (float)(0.0f * PI);
634 	dir->pitch = (float)(0.0f * PI);
635 	dir->bank = (float)(0.0f * PI);
636 	dir = &scene->camera_spot_dir;
637 	dir->heading = (float)(1.25f * PI);
638 	dir->pitch = (float)(1.92f * PI);
639 	dir->bank = (float)(0.0f * PI);
640 	scene->camera_spot_dist = 20.0f;
641 	dir = &scene->camera_hoist_dir;
642 	dir->heading = (float)(0.75f * PI);
643 	dir->pitch = (float)(1.92f * PI);
644 	dir->bank = (float)(0.0f * PI);
645 	scene->camera_hoist_dist = 20.0f;
646 	scene->camera_target = -1;
647 
648 	memset(
649 	    scene->camera_rotmatrix,
650 	    0x00,
651 	    SAR_CAMERA_ROTMATRIX_MAX * (3 * 3) * sizeof(double)
652 	);
653 	scene->camera_rotmatrix_count = 0;
654 
655 	scene->light_visibility_hint = 0;
656 	scene->light_xc = -2.0f;		/* Not in camera view */
657 	scene->light_yc = -2.0f;
658 
659 	scene->cloud_layer = NULL;
660 	scene->total_cloud_layers = 0;
661 
662 	scene->cloud_bb = NULL;
663 	scene->total_cloud_bbs = 0;
664 	scene->pri_lightening_coeff = 0.0f;
665 
666 	scene->texture_ref = NULL;
667 	scene->total_texture_refs = 0;
668 
669 	scene->texnum_sun = -1;
670 	scene->texnum_moon = -1;
671 	scene->texnum_spotlightcast = -1;
672 
673 	scene->sndsrc = NULL;
674 	scene->total_sndsrcs = 0;
675 
676 	scene->player_control_panel = NULL;
677 
678 	/* Reset initial GL states */
679 	if(display != NULL)
680 	{
681 	    StateGLResetAll(&display->state_gl);
682 	    StateGLEnable(&display->state_gl, GL_CULL_FACE);
683 	    StateGLFrontFace(&display->state_gl, GL_CCW);
684 	    StateGLShadeModel(&display->state_gl, GL_FLAT);
685 	}
686 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
687 	glPixelStorei(GL_PACK_ALIGNMENT, 1);
688 
689 
690 	/* Allocate the Messages List */
691 	scene->total_messages = 6;	/* Maximum of 6 at one time */
692 	free(scene->message);
693 	scene->message = (char **)calloc(
694 	    scene->total_messages, sizeof(char *)
695 	);
696 	if(scene->message == NULL)
697 	    scene->total_messages = 0;
698 
699 	scene->message_display_until = 0;
700 	scene->camera_ref_title_display_until = 0;
701 
702 	/* Allocate the FDM Realm */
703 	scene->realm = SFMInit(0, NULL);
704 	if(scene->realm == NULL)
705 	{
706 	    fprintf(
707 		stderr,
708 "SARSceneLoadFromFile(): Error: Unable to create FDM Realm.\n"
709 	    );
710 	}
711 	else
712 	{
713 	    SFMRealmStruct *realm = scene->realm;
714 
715 	    /* Set up FDM realm values */
716 	    realm->lapsed_time = 0;
717 	    realm->time_compensation = 1.0f;
718 	    realm->time_compression = 1.0f;
719 
720 	    realm->gravity = SFMDefaultGravity;
721 
722 	    /* Set up realm callback data and callback function ptrs */
723 	    realm->init_model_cb_client_data = core_ptr;
724 	    realm->init_model_cb = SARSimInitModelCB;
725 	    realm->destroy_model_cb_client_data = core_ptr;
726 	    realm->destroy_model_cb = SARSimDestroyModelCB;
727 	    realm->airborne_cb_client_data = core_ptr;
728 	    realm->airborne_cb = SARSimAirborneCB;
729 	    realm->touch_down_cb_client_data = core_ptr;
730 	    realm->touch_down_cb = SARSimTouchDownCB;
731 	    realm->overspeed_cb_client_data = core_ptr;
732 	    realm->overspeed_cb = SARSimOverspeedCB;
733 	    realm->collision_cb_client_data = core_ptr;
734 	    realm->collision_cb = SARSimCollisionCB;
735 	}
736 
737 #define APPEND_TEXTURE(_t_)	{				\
738  const int n = MAX(scene->total_texture_refs, 0);		\
739  scene->total_texture_refs = n + 1;				\
740  scene->texture_ref = (v3d_texture_ref_struct **)realloc(	\
741   scene->texture_ref,						\
742   scene->total_texture_refs * sizeof(v3d_texture_ref_struct *)	\
743  );								\
744  if(scene->texture_ref == NULL) {				\
745   scene->total_texture_refs = 0;				\
746   return(-3);							\
747  }								\
748  scene->texture_ref[n] = (_t_);					\
749 }
750 
751 	/* Render built in textures */
752 	if(True)
753 	{
754 #if 0
755 	    v3d_texture_ref_struct *t = SARCreateBladeBlurTexture(
756 		SAR_STD_TEXNAME_ROTOR_BLADE_BLUR, 0.98f
757 	    );
758 	    APPEND_TEXTURE(t);
759 #endif
760 	}
761 
762 
763 	/* Load all textures specified in the global Textures List */
764 	if(True)
765 	{
766 	    const char *name, *path;
767 	    char *full_path;
768 	    const sar_texture_name_struct *tn;
769 	    const int tex_fmt = V3D_TEX_FORMAT_RGBA;
770 
771 	    /* Iterate through each Texture Name in the Textures List */
772 	    for(i = 0; i < core_ptr->total_texture_list; i++)
773 	    {
774 		tn = core_ptr->texture_list[i];
775 		if(tn == NULL)
776 		    continue;
777 
778 		name = tn->name;
779 		path = tn->filename;
780 		if((name == NULL) || (path == NULL))
781 		    continue;
782 
783 		if(ISPATHABSOLUTE(path))
784 		{
785 		    full_path = STRDUP(path);
786 		}
787 		else
788 		{
789 		    full_path = STRDUP(PrefixPaths(
790 			dname.local_data, path
791 		    ));
792  		    if((full_path != NULL) ? stat(full_path, &stat_buf) : True)
793 		    {
794 			free(full_path);
795 			full_path = STRDUP(PrefixPaths(
796 			    dname.global_data, path
797 			));
798 		    }
799 		}
800 		if(full_path != NULL)
801 		{
802 		    v3d_texture_ref_struct *t = V3DTextureLoadFromFile2DPreempt(
803 			full_path, name, tex_fmt
804 		    );
805 		    V3DTexturePriority(t, tn->priority);
806 		    APPEND_TEXTURE(t);
807 		    free(full_path);
808 		}
809 		else
810 		{
811 		    fprintf(
812 			stderr,
813 "%s: Warning: Unable to complete texture \"%s\" path \"%s\".\n",
814 			filename, name, path
815 		    );
816 		}
817 	    }
818 	}
819 
820 	/* Set references to frequently used global textures */
821 	if(True)
822 	{
823 	    scene->texnum_sun = SARGetTextureRefNumberByName(
824 		scene, SAR_STD_TEXNAME_SUN
825 	    );
826 	    scene->texnum_moon = SARGetTextureRefNumberByName(
827 		scene, SAR_STD_TEXNAME_MOON
828 	    );
829 	    scene->texnum_spotlightcast = SARGetTextureRefNumberByName(
830 		scene, SAR_STD_TEXNAME_SPOTLIGHTCAST
831 	    );
832 
833 	}
834 
835 #undef APPEND_TEXTURE
836 
837 	/* Create default global sound sources list */
838 	if(True)
839 	{
840 #define LOAD_SNDSRC(name,filename,filename_far,range,range_far)	\
841 {								\
842  i = MAX(scene->total_sndsrcs, 0);				\
843  scene->total_sndsrcs = i + 1;					\
844  scene->sndsrc = (sar_sound_source_struct **)realloc(		\
845   scene->sndsrc,						\
846   scene->total_sndsrcs * sizeof(sar_sound_source_struct *)	\
847  );								\
848  if(scene->sndsrc == NULL)					\
849  {								\
850   scene->total_sndsrcs = 0;					\
851  }								\
852  else								\
853  {								\
854   char *s, *full_path, *full_path_far;				\
855 								\
856   /* Complete Filenames */					\
857   s = STRDUP(PrefixPaths(dname.local_data, filename));		\
858   if((s != NULL) ? stat(s, &stat_buf) : True) {			\
859    free(s);							\
860    s = STRDUP(PrefixPaths(dname.global_data, filename));	\
861   }								\
862   full_path = s;						\
863 								\
864   s = STRDUP(PrefixPaths(dname.local_data, filename_far));	\
865   if((s != NULL) ? stat(s, &stat_buf) : True) {			\
866    free(s);							\
867    s = STRDUP(PrefixPaths(dname.global_data, filename_far));	\
868   }								\
869   full_path_far = s;						\
870 								\
871   /* Check if file exists */					\
872   if((full_path != NULL) ? stat(full_path, &stat_buf) : True)	\
873    fprintf(stderr,						\
874 "SARSceneLoadFromFile(): Warning: Unable to find sound file \"%s\"\n",\
875     filename							\
876    );								\
877   if((full_path_far != NULL) ? stat(full_path_far, &stat_buf) : True) \
878    fprintf(stderr,						\
879 "SARSceneLoadFromFile(): Warning: Unable to find sound file \"%s\"\n",\
880     filename_far						\
881    );								\
882 								\
883   /* Create sound source */					\
884   scene->sndsrc[i] = SARSoundSourceNew(				\
885    name, full_path, full_path_far,				\
886    range, range_far,						\
887    NULL, 0.0f, NULL,						\
888    0			/* Sample rate limit in Hz */		\
889   );								\
890 								\
891   free(full_path);						\
892   free(full_path_far);						\
893  }								\
894 }
895 
896 	    /* Gound Contact Sounds */
897 	    LOAD_SNDSRC(
898 		"land_wheel_skid",
899 		SAR_DEF_SOUND_LAND_WHEEL_SKID,
900 		SAR_DEF_SOUND_LAND_WHEEL_SKID,
901 		600.0f,
902 		400.0f
903 	    );
904 	    LOAD_SNDSRC(
905 		"land_ski_skid",
906 		SAR_DEF_SOUND_LAND_SKI_SKID,
907 		SAR_DEF_SOUND_LAND_SKI_SKID,
908 		600.0f,
909 		400.0f
910 	    );
911 	    LOAD_SNDSRC(
912 		"land_ski",
913 		SAR_DEF_SOUND_LAND_SKI,
914 		SAR_DEF_SOUND_LAND_SKI,
915 		600.0f,
916 		400.0f
917 	    );
918 	    LOAD_SNDSRC(
919 		"land_belly",
920 		SAR_DEF_SOUND_LAND_BELLY,
921 		SAR_DEF_SOUND_LAND_BELLY,
922 		1200.0f,
923 		900.0f
924 	    );
925 
926 	    /* Thud Sounds */
927 	    LOAD_SNDSRC(
928 		"thud_light",
929 		SAR_DEF_SOUND_THUD_LIGHT,
930 		SAR_DEF_SOUND_THUD_LIGHT,
931 		600.0f,
932 		400.0f
933 	    );
934 	    LOAD_SNDSRC(
935 		"thud_medium",
936 		SAR_DEF_SOUND_THUD_MEDIUM,
937 		SAR_DEF_SOUND_THUD_MEDIUM,
938 		600.0f,
939 		400.0f
940 	    );
941 	    LOAD_SNDSRC(
942 		"thud_heavy",
943 		SAR_DEF_SOUND_THUD_HEAVY,
944 		SAR_DEF_SOUND_THUD_HEAVY,
945 		600.0f,
946 		400.0f
947 	    );
948 
949 	    /* Crash & Collision Sounds */
950 	    LOAD_SNDSRC(
951 		"crash_obstruction",
952 		SAR_DEF_SOUND_CRASH_OBSTRUCTION,
953 		SAR_DEF_SOUND_CRASH_OBSTRUCTION,
954 		3300.0f,	/* About 2 miles */
955 		2500.0f
956 	    );
957 	    LOAD_SNDSRC(
958 		"crash_ground",
959 		SAR_DEF_SOUND_CRASH_GROUND,
960 		SAR_DEF_SOUND_CRASH_GROUND,
961 		3300.0f,	/* About 2 miles */
962 		2500.0f
963 	    );
964 	    LOAD_SNDSRC(
965 		"splash_aircraft",
966 		SAR_DEF_SOUND_SPLASH_AIRCRAFT,
967 		SAR_DEF_SOUND_SPLASH_AIRCRAFT,
968 		2500.0f,	/* About 1.5 miles */
969 		2000.0f
970 	    );
971 	    LOAD_SNDSRC(
972 		"splash_human",
973 		SAR_DEF_SOUND_SPLASH_HUMAN,
974 		SAR_DEF_SOUND_SPLASH_HUMAN,
975 		600.0f,
976 		400.0f
977 	    );
978 
979 #undef LOAD_SNDSRC
980 	}
981 
982 	/* Create the Horizon */
983 	horizon_ptr = &scene->horizon;
984 	horizon_ptr->last_tod = -1;	/* Reset to -1 so horizon gets updated */
985 	horizon_ptr->texture = NULL;
986 	horizon_ptr->total_textures = 0;
987 
988 
989 	/* Generate weather settings from the specified Weather Data
990 	 * Entry
991 	 */
992 	SARWeatherSetScenePreset(
993 	    core_ptr->weather_data,
994 	    scene,
995 	    weather_preset_name
996 	);
997 
998 	/* Iterate through loaded parms */
999 	for(i = 0; i < total_parms; i++)
1000 	{
1001 	    p = parm[i];
1002 	    if(p == NULL)
1003 		continue;
1004 
1005 	    ptype = *(int *)p;
1006 
1007 	    if(progress_func != NULL)
1008 	    {
1009 		if(progress_func(client_data, i + 1, total_parms))
1010 		    break;
1011 	    }
1012 
1013 	    /* Handle by parm type */
1014 	    switch(ptype)
1015 	    {
1016 	      case SAR_PARM_VERSION:
1017 		p_version = (sar_parm_version_struct *)p;
1018 		if((p_version->major > PROG_VERSION_MAJOR) ||
1019 		   (p_version->minor > PROG_VERSION_MINOR) ||
1020 		   (p_version->release > PROG_VERSION_RELEASE)
1021 		)
1022 		{
1023 		    int need_warn = 0;
1024 		    if(p_version->major > PROG_VERSION_MAJOR)
1025 			need_warn = 1;
1026 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
1027 			    (p_version->minor > PROG_VERSION_MINOR)
1028 		    )
1029 			need_warn = 1;
1030 		    else if((p_version->major == PROG_VERSION_MAJOR) &&
1031 			    (p_version->minor == PROG_VERSION_MINOR) &&
1032 			    (p_version->release == PROG_VERSION_RELEASE)
1033 		    )
1034 			need_warn = 1;
1035 		    if(need_warn)
1036 			fprintf(
1037 			    stderr,
1038 "%s: Warning: File format version %i.%i.%i is newer than program\
1039  version %i.%i.%i.",
1040 			    filename,
1041 			    p_version->major, p_version->minor,
1042 			    p_version->release, PROG_VERSION_MAJOR,
1043 			    PROG_VERSION_MINOR, PROG_VERSION_RELEASE
1044 			);
1045 		}
1046 		break;
1047 
1048 	      case SAR_PARM_NAME:
1049 		p_name = (sar_parm_name_struct *)p;
1050 		free(scene->title);
1051 		scene->title = STRDUP(p_name->name);
1052 		break;
1053 
1054 	      case SAR_PARM_DESCRIPTION:
1055 		p_description = (sar_parm_description_struct *)p;
1056 		break;
1057 
1058 	      case SAR_PARM_PLAYER_MODEL_FILE:
1059 		p_player_model_file = (sar_parm_player_model_file_struct *)p;
1060 		break;
1061 
1062 	      case SAR_PARM_WEATHER:
1063 		p_weather = (sar_parm_weather_struct *)p;
1064 		break;
1065 
1066 	      case SAR_PARM_REGISTER_LOCATION:
1067 		p_register_location = (sar_parm_register_location_struct *)p;
1068 		break;
1069 
1070 	      case SAR_PARM_SCENE_GPS:
1071 		p_scene_gps = (sar_parm_scene_gps_struct *)p;
1072 		scene->dms_x_offset = p_scene_gps->dms_x_offset;
1073 		scene->dms_y_offset = p_scene_gps->dms_y_offset;
1074 		scene->planet_radius = p_scene_gps->planet_radius;
1075 		break;
1076 
1077 	      case SAR_PARM_SCENE_MAP:
1078 		p_scene_map = (sar_parm_scene_map_struct *)p;
1079 		break;
1080 
1081 	      case SAR_PARM_SCENE_ELEVATION:
1082 		p_scene_elevation = (sar_parm_scene_elevation_struct *)p;
1083 		scene->msl_elevation = p_scene_elevation->elevation;
1084 		break;
1085 
1086 	      case SAR_PARM_SCENE_CANT:
1087 		p_scene_cant = (sar_parm_scene_cant_struct *)p;
1088 		scene->cant_angle = p_scene_cant->cant;
1089 		break;
1090 
1091 	      case SAR_PARM_SCENE_GROUND_FLAGS:
1092 		p_scene_ground_flags = (sar_parm_scene_ground_flags_struct *)p;
1093 		scene->base_flags = (sar_scene_base_flags)p_scene_ground_flags->flags;
1094 		break;
1095 
1096 	      case SAR_PARM_SCENE_GROUND_TILE:
1097 		p_scene_ground_tile = (sar_parm_scene_ground_tile_struct *)p;
1098 		if(True)
1099 		{
1100 		    float min, max;
1101 		    GLuint list;
1102 		    sar_visual_model_struct **vmodel;
1103 		    v3d_texture_ref_struct *t = NULL;
1104 
1105 		    /* Close range tiling size and range */
1106 		    scene->base.tile_width = ((p_scene_ground_tile->tile_width > 0) ?
1107 			p_scene_ground_tile->tile_width : SAR_DEF_GROUND_BASE_TILE_WIDTH
1108 		    );
1109 		    scene->base.tile_height = ((p_scene_ground_tile->tile_height > 0) ?
1110 			p_scene_ground_tile->tile_height : SAR_DEF_GROUND_BASE_TILE_HEIGHT
1111 		    );
1112 		    scene->base.close_range = ((p_scene_ground_tile->close_range > 0) ?
1113 			p_scene_ground_tile->close_range : SAR_DEF_GROUND_BASE_TILE_CLOSE_RANGE
1114 		    );
1115 		    /* Far solid color */
1116 		    memcpy(
1117 		        &scene->base.color, &p_scene_ground_tile->color,
1118 		        sizeof(sar_color_struct)
1119 		    );
1120 
1121 		    /* Select texture */
1122 		    t = SARGetTextureRefByName(scene, p_scene_ground_tile->texture_name);
1123 
1124 		    /* Create the simple/far Ground Base Visual Model
1125 		     * as needed
1126 		     */
1127 		    vmodel = &scene->base.visual_model_simple;
1128 		    if(*vmodel != NULL)
1129 		    {
1130 			fprintf(
1131 			    stderr,
1132 "%s: Warning: Ground base simple/far visual model is already defined.\n",
1133 			    filename
1134 			);
1135 		    }
1136 		    else
1137 		    {
1138 			/* Create new visual model */
1139 			*vmodel = SARVisualModelNew(
1140 			    scene, NULL, NULL
1141 			);
1142 
1143 			/* (Re)generate GL list on visual model structure */
1144 			list = (GLuint)SARVisualModelNewList(*vmodel);
1145 			if(list != 0)
1146 			{
1147 			    /* Mark visual model as loading */
1148 			    (*vmodel)->load_state = SAR_VISUAL_MODEL_LOADING;
1149 
1150 			    /* Begin recording new list */
1151 			    glNewList(list, GL_COMPILE);
1152 			    {
1153 				/* Far (big) ground base tiles */
1154 				min = -(SAR_MAX_VISIBILITY_DISTANCE +
1155 				    (0.25 * SAR_MAX_VISIBILITY_DISTANCE));
1156 				max = (SAR_MAX_VISIBILITY_DISTANCE +
1157 				    (0.25 * SAR_MAX_VISIBILITY_DISTANCE));
1158 				SARObjGenerateTilePlane(
1159 				    min, max,               /* Min and max */
1160 				    (float)(max / 4),         /* Tile width and height */
1161 				    (float)(max / 4)
1162 				);
1163 			    }
1164 			    glEndList();
1165 
1166 			    /* Mark visual model as done loading */
1167 			    (*vmodel)->load_state = SAR_VISUAL_MODEL_LOADED;
1168 			}
1169 		    }
1170 
1171 		    /* Create the detailed/near Ground Base Visual Model
1172 		     * as needed
1173 		     */
1174 		    vmodel = &scene->base.visual_model_close;
1175 		    if(*vmodel != NULL)
1176 		    {
1177 			fprintf(
1178 			    stderr,
1179 "%s: Warning: Ground base detailed/near visual model is already defined.\n",
1180 			    filename
1181 			);
1182 		    }
1183 		    else
1184 		    {
1185 			/* Create new visual model */
1186 			*vmodel = SARVisualModelNew(
1187 			    scene, NULL, NULL
1188 			);
1189 
1190 			/* (Re)generate GL list on visual model structure */
1191 			list = (GLuint)SARVisualModelNewList(*vmodel);
1192 			if(list != 0)
1193 			{
1194 			    /* Mark visual model as loading */
1195 			    (*vmodel)->load_state = SAR_VISUAL_MODEL_LOADING;
1196 
1197 			    /* Begin recording new list */
1198 			    glNewList(list, GL_COMPILE);
1199 			    {
1200 				/* Select tiled ground texture if defined, if
1201 				 * no texture then a texture unselect will be
1202 				 * recorded.
1203 				 */
1204 				V3DTextureSelect(t);
1205 
1206 				/* Generate close range textured tiles */
1207 				SARObjGenerateTilePlane(
1208 				    -scene->base.close_range,       /* Min */
1209 				    scene->base.close_range,        /* Max */
1210 				    (float)scene->base.tile_width,         /* Tile width */
1211 				    (float)scene->base.tile_height         /* Tile height */
1212 				);
1213 			    }
1214 			    glEndList();
1215 
1216 			    /* Mark visual model as done loading */
1217 			    (*vmodel)->load_state = SAR_VISUAL_MODEL_LOADED;
1218 			}
1219 		    }
1220 		}
1221 		break;
1222 
1223 	      case SAR_PARM_TEXTURE_BASE_DIRECTORY:
1224 		p_texture_base_directory = (sar_parm_texture_base_directory_struct *)p;
1225 		break;
1226 
1227 	      case SAR_PARM_TEXTURE_LOAD:
1228 		p_texture_load = (sar_parm_texture_load_struct *)p;
1229 		SARObjLoadTexture(
1230 		    core_ptr, scene, p_texture_load
1231 		);
1232 		break;
1233 
1234 	      /* Skip mission parms */
1235 
1236 	      case SAR_PARM_NEW_OBJECT:
1237 		p_new_object = (sar_parm_new_object_struct *)p;
1238 		obj_num = SARObjNew(
1239 		    scene, ptr, total,
1240 		    p_new_object->object_type
1241 		);
1242 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
1243 
1244 		/* Reset all substructure type pointers */
1245 		DO_RESET_SUBSTRUCTURE_PTRS
1246 
1247 		if(obj_ptr != NULL)
1248 		{
1249 		    /* Get pointer to substructure */
1250 		    switch(obj_ptr->type)
1251 		    {
1252 		      case SAR_OBJ_TYPE_GARBAGE:
1253 		      case SAR_OBJ_TYPE_STATIC:
1254 		      case SAR_OBJ_TYPE_AUTOMOBILE:
1255 		      case SAR_OBJ_TYPE_WATERCRAFT:
1256 			break;
1257 		      case SAR_OBJ_TYPE_AIRCRAFT:
1258 		        obj_aircraft_ptr = SAR_OBJ_GET_AIRCRAFT(obj_ptr);
1259 		        break;
1260 		      case SAR_OBJ_TYPE_GROUND:
1261 		        obj_ground_ptr = SAR_OBJ_GET_GROUND(obj_ptr);
1262 		        break;
1263 		      case SAR_OBJ_TYPE_RUNWAY:
1264 		      case SAR_OBJ_TYPE_HELIPAD:
1265 		      case SAR_OBJ_TYPE_HUMAN:
1266 		      case SAR_OBJ_TYPE_SMOKE:
1267 		      case SAR_OBJ_TYPE_FIRE:
1268 		      case SAR_OBJ_TYPE_EXPLOSION:
1269 		      case SAR_OBJ_TYPE_CHEMICAL_SPRAY:
1270 		      case SAR_OBJ_TYPE_FUELTANK:
1271 		      case SAR_OBJ_TYPE_PREMODELED:
1272 			break;
1273 		    }
1274 		}
1275 		break;
1276 
1277 	      case SAR_PARM_NEW_HELIPAD:
1278 		p_new_helipad = (sar_parm_new_helipad_struct *)p;
1279 		DO_RESET_SUBSTRUCTURE_PTRS
1280 		obj_num = SARObjLoadHelipad(
1281 		    core_ptr, scene, p_new_helipad
1282 		);
1283 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
1284 		obj_helipad_ptr = SAR_OBJ_GET_HELIPAD(obj_ptr);
1285 		break;
1286 
1287 	      case SAR_PARM_NEW_RUNWAY:
1288 		p_new_runway = (sar_parm_new_runway_struct *)p;
1289 		DO_RESET_SUBSTRUCTURE_PTRS
1290 		obj_num = SARObjLoadRunway(
1291 		    core_ptr, scene, p_new_runway
1292 		);
1293 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
1294 		obj_runway_ptr = SAR_OBJ_GET_RUNWAY(obj_ptr);
1295 		break;
1296 
1297 	      case SAR_PARM_NEW_HUMAN:
1298 		p_new_human = (sar_parm_new_human_struct *)p;
1299 		DO_RESET_SUBSTRUCTURE_PTRS
1300 		obj_num = SARObjLoadHuman(
1301 		    core_ptr, scene, p_new_human
1302 		);
1303 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
1304 		obj_human_ptr = SAR_OBJ_GET_HUMAN(obj_ptr);
1305 		break;
1306 
1307 	      case SAR_PARM_NEW_FIRE:
1308 		p_new_fire = (sar_parm_new_fire_struct *)p;
1309 		DO_RESET_SUBSTRUCTURE_PTRS
1310 		obj_num = SARObjLoadFire(
1311 		    core_ptr, scene, p_new_fire
1312 		);
1313 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
1314 		obj_fire_ptr = SAR_OBJ_GET_FIRE(obj_ptr);
1315 		break;
1316 
1317 	      case SAR_PARM_NEW_SMOKE:
1318 		p_new_smoke = (sar_parm_new_smoke_struct *)p;
1319 		DO_RESET_SUBSTRUCTURE_PTRS
1320 		obj_num = SARObjLoadSmoke(
1321 		    core_ptr, scene, p_new_smoke
1322 		);
1323 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
1324 		obj_smoke_ptr = SAR_OBJ_GET_SMOKE(obj_ptr);
1325 		break;
1326 
1327 	      case SAR_PARM_NEW_PREMODELED:
1328 		p_new_premodeled = (sar_parm_new_premodeled_struct *)p;
1329 		DO_RESET_SUBSTRUCTURE_PTRS
1330 		obj_num = SARObjPremodeledNew(
1331 		    core_ptr, scene,
1332 		    p_new_premodeled->model_type,
1333 		    p_new_premodeled->argc,
1334 		    p_new_premodeled->argv
1335 		);
1336 		obj_ptr = (obj_num > -1) ? (*ptr)[obj_num] : NULL;
1337 		break;
1338 
1339 	      case SAR_PARM_MODEL_FILE:
1340 		p_model_file = (sar_parm_model_file_struct *)p;
1341 		if((p_model_file->file != NULL) && (obj_ptr != NULL))
1342 		    SARObjLoadFromFile(core_ptr, obj_num, p_model_file->file);
1343 		break;
1344 
1345 	      case SAR_PARM_RANGE:
1346 		p_range = (sar_parm_range_struct *)p;
1347 		if(obj_ptr != NULL)
1348 		{
1349 		    obj_ptr->range = (float)MAX(p_range->range, 0.0);
1350 		}
1351 		break;
1352 
1353 	      case SAR_PARM_RANGE_FAR:
1354 		p_range_far = (sar_parm_range_far_struct *)p;
1355 		if(obj_ptr != NULL)
1356 		{
1357 		    obj_ptr->range_far = (float)MAX(p_range_far->range_far, 0.0);
1358 		}
1359 		break;
1360 
1361 	      case SAR_PARM_TRANSLATE:
1362 		p_translate = (sar_parm_translate_struct *)p;
1363 		SARObjLoadTranslate(
1364 		    core_ptr, scene,
1365 		    obj_ptr, p_translate
1366 		);
1367 		break;
1368 
1369 	      case SAR_PARM_TRANSLATE_RANDOM:
1370 		p_translate_random = (sar_parm_translate_random_struct *)p;
1371 /* Ignore this, for missions only) */
1372 		break;
1373 
1374 	      case SAR_PARM_ROTATE:
1375 		p_rotate = (sar_parm_rotate_struct *)p;
1376 		if(obj_ptr != NULL)
1377 		{
1378 		    SARSimWarpObject(
1379 			scene, obj_ptr,
1380 			NULL, &p_rotate->rotate
1381 		    );
1382 		}
1383 		break;
1384 
1385 	      case SAR_PARM_NO_DEPTH_TEST:
1386 		p_no_depth_test = (sar_parm_no_depth_test_struct *)p;
1387 		if(obj_ptr != NULL)
1388 		{
1389 		    obj_ptr->flags |= SAR_OBJ_FLAG_NO_DEPTH_TEST;
1390 		}
1391 		break;
1392 
1393 	      case SAR_PARM_POLYGON_OFFSET:
1394 		p_polygon_offset = (sar_parm_polygon_offset_struct *)p;
1395 		if(obj_ptr != NULL)
1396 		{
1397 		    obj_ptr->flags |= p_polygon_offset->flags;
1398 		}
1399 		break;
1400 
1401 	      case SAR_PARM_CONTACT_BOUNDS_SPHERICAL:
1402 		p_contact_bounds_spherical = (sar_parm_contact_bounds_spherical_struct *)p;
1403 		if(obj_ptr != NULL)
1404 		{
1405 		    sar_contact_bounds_struct *cb = obj_ptr->contact_bounds;
1406 		    SARObjAddContactBoundsSpherical(
1407 			obj_ptr,
1408 			(cb != NULL) ? cb->crash_flags : 0,
1409 			(cb != NULL) ? cb->crash_type : 0,
1410 			p_contact_bounds_spherical->radius
1411 		    );
1412 		}
1413 		break;
1414 
1415 	      case SAR_PARM_CONTACT_BOUNDS_CYLENDRICAL:
1416 		p_contact_bounds_cylendrical = (sar_parm_contact_bounds_cylendrical_struct *)p;
1417 		if(obj_ptr != NULL)
1418 		{
1419 		    sar_contact_bounds_struct *cb = obj_ptr->contact_bounds;
1420 		    SARObjAddContactBoundsCylendrical(
1421 			obj_ptr,
1422 			(cb != NULL) ? cb->crash_flags : 0,
1423 			(cb != NULL) ? cb->crash_type : 0,
1424 			p_contact_bounds_cylendrical->radius,
1425 			p_contact_bounds_cylendrical->height_min,
1426 			p_contact_bounds_cylendrical->height_max
1427 		    );
1428 		}
1429 		break;
1430 
1431 	      case SAR_PARM_CONTACT_BOUNDS_RECTANGULAR:
1432 		p_contact_bounds_rectangular = (sar_parm_contact_bounds_rectangular_struct *)p;
1433 		if(obj_ptr != NULL)
1434 		{
1435 		    sar_contact_bounds_struct *cb = obj_ptr->contact_bounds;
1436 		    SARObjAddContactBoundsRectangular(
1437 			obj_ptr,
1438 			(cb != NULL) ? cb->crash_flags : 0,
1439 			(cb != NULL) ? cb->crash_type : 0,
1440 			p_contact_bounds_rectangular->x_min,
1441 			p_contact_bounds_rectangular->x_max,
1442 			p_contact_bounds_rectangular->y_min,
1443 			p_contact_bounds_rectangular->y_max,
1444 			p_contact_bounds_rectangular->z_min,
1445 			p_contact_bounds_rectangular->z_max
1446 		    );
1447 		}
1448 		break;
1449 
1450 	      case SAR_PARM_GROUND_ELEVATION:
1451 		p_ground_elevation = (sar_parm_ground_elevation_struct *)p;
1452 		if(obj_ground_ptr != NULL)
1453 		{
1454 		    obj_ground_ptr->elevation = p_ground_elevation->elevation;
1455 		}
1456 		else
1457 		{
1458 		    fprintf(
1459 			stderr,
1460 "%s: Warning:\
1461  Unable to set ground elevation for object not of type \"%i\".\n",
1462  			filename, SAR_OBJ_TYPE_GROUND
1463 		    );
1464 		}
1465 		break;
1466 
1467 	      case SAR_PARM_OBJECT_NAME:
1468 		p_object_name = (sar_parm_object_name_struct *)p;
1469 		if(obj_ptr != NULL)
1470 		{
1471 		    free(obj_ptr->name);
1472 		    obj_ptr->name = STRDUP(p_object_name->name);
1473 		}
1474 		break;
1475 
1476 	      case SAR_PARM_OBJECT_MAP_DESCRIPTION:
1477 		p_object_map_description = (sar_parm_object_map_description_struct *)p;
1478 		if(obj_ptr != NULL)
1479 		{
1480 /* Ignore this */
1481 		}
1482 		break;
1483 
1484 	      case SAR_PARM_FUEL:
1485 		p_fuel = (sar_parm_fuel_struct *)p;
1486 		if(obj_aircraft_ptr != NULL)
1487 		{
1488 		    /* Set current fuel */
1489 		    obj_aircraft_ptr->fuel = p_fuel->fuel;
1490 
1491 		    /* Set max only if not negative */
1492 		    if(p_fuel->fuel_max >= 0.0)
1493 			obj_aircraft_ptr->fuel_max = p_fuel->fuel_max;
1494 
1495 		    /* Sanitize current */
1496 		    if(obj_aircraft_ptr->fuel > obj_aircraft_ptr->fuel_max)
1497 			obj_aircraft_ptr->fuel = obj_aircraft_ptr->fuel_max;
1498 		}
1499 		break;
1500 
1501 	      case SAR_PARM_HITPOINTS:
1502 		p_hitpoints = (sar_parm_hitpoints_struct *)p;
1503 		if(obj_ptr != NULL)
1504 		{
1505 		    /* Set current hit points */
1506 		    obj_ptr->hit_points = p_hitpoints->hitpoints;
1507 
1508 		    /* Set max only if not negative */
1509 		    if(p_hitpoints->hitpoints_max >= 0.0)
1510 			obj_ptr->hit_points_max = p_hitpoints->hitpoints_max;
1511 
1512 		    /* Sanitize current */
1513 		    if(obj_ptr->hit_points > obj_ptr->hit_points_max)
1514 			obj_ptr->hit_points = obj_ptr->hit_points_max;
1515 		}
1516 		break;
1517 
1518 	      case SAR_PARM_ENGINE_STATE:
1519 		p_engine_state = (sar_parm_engine_state_struct *)p;
1520 /* TODO Work on this later */
1521 		break;
1522 
1523 	      case SAR_PARM_PASSENGERS:
1524 		p_passengers = (sar_parm_passengers_struct *)p;
1525 /* TODO Work on this later */
1526 		break;
1527 
1528 	      case SAR_PARM_RUNWAY_APPROACH_LIGHTING_NORTH:
1529 		p_runway_applight_n =
1530 		    (sar_parm_runway_approach_lighting_north_struct *)p;
1531 		if((obj_ptr != NULL) && (obj_runway_ptr != NULL))
1532 		{
1533 		    obj_runway_ptr->north_approach_lighting_flags =
1534 			p_runway_applight_n->flags;
1535 		}
1536 		break;
1537 
1538 	      case SAR_PARM_RUNWAY_APPROACH_LIGHTING_SOUTH:
1539 		p_runway_applight_s =
1540 		    (sar_parm_runway_approach_lighting_south_struct *)p;
1541 		if((obj_ptr != NULL) && (obj_runway_ptr != NULL))
1542 		{
1543 		    obj_runway_ptr->south_approach_lighting_flags =
1544 			p_runway_applight_s->flags;
1545 		}
1546 		break;
1547 
1548 	      case SAR_PARM_HUMAN_MESSAGE_ENTER:
1549 		p_human_message_enter = (sar_parm_human_message_enter_struct *)p;
1550 		if((obj_ptr != NULL) && (obj_human_ptr != NULL))
1551 		{
1552 		    free(obj_human_ptr->mesg_enter);
1553 		    obj_human_ptr->mesg_enter = STRDUP(
1554 			p_human_message_enter->message
1555 		    );
1556 		}
1557 		break;
1558 
1559 	      case SAR_PARM_HUMAN_REFERENCE:
1560 		p_human_reference = (sar_parm_human_reference_struct *)p;
1561 		if((obj_ptr != NULL) && (obj_human_ptr != NULL) &&
1562 		   (p_human_reference->reference_name != NULL)
1563 		)
1564 		{
1565 		    int human_ref_obj_num = -1;
1566 		    const char *ref_name = (const char *)p_human_reference->reference_name;
1567 
1568 		    /* Run towards? */
1569 		    if(p_human_reference->flags & SAR_HUMAN_FLAG_RUN_TOWARDS)
1570 		    {
1571 			obj_human_ptr->flags |= SAR_HUMAN_FLAG_RUN_TOWARDS;
1572 		    }
1573 		    /* Run away? */
1574 		    else if(p_human_reference->flags & SAR_HUMAN_FLAG_RUN_AWAY)
1575 		    {
1576 			obj_human_ptr->flags |= SAR_HUMAN_FLAG_RUN_AWAY;
1577 		    }
1578 
1579 		    /* Handle reference object name */
1580 		    if(!strcasecmp(ref_name, "player"))
1581 		    {
1582 			/* Set special intercept code to intercept the player */
1583 			obj_human_ptr->intercepting_object = -2;
1584 		    }
1585 		    else
1586 		    {
1587 			/* All else match by object name */
1588 			SARObjMatchPointerByName(
1589 			    scene, *ptr, *total,
1590 			    ref_name, &human_ref_obj_num
1591 			);
1592 			obj_human_ptr->intercepting_object = human_ref_obj_num;
1593 		    }
1594 		}
1595 		break;
1596 
1597 	    }	/* Handle by parm type */
1598 	}	/* Iterate through loaded parms */
1599 
1600 
1601 	/* Delete loaded parms */
1602 	SARParmDeleteAll(&parm, &total_parms);
1603 
1604 #undef DO_RESET_SUBSTRUCTURE_PTRS
1605 
1606 	return(0);
1607 }
1608