1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8  */
9 
10 #include "globalincs/systemvars.h"
11 
12 #include "debugconsole/console.h"
13 #include "globalincs/pstypes.h"
14 #include "graphics/2d.h"
15 #include "io/timer.h"
16 #include "nebula/neb.h"
17 #include "options/Option.h"
18 
19 fix Missiontime;
20 fix Skybox_timestamp;
21 fix Frametime;
22 int	Framecount=0;
23 
24 int Game_mode;
25 
26 int Game_restoring = 0;		// If set, this means we are restoring data from disk
27 
28 int	Viewer_mode;		//	Viewer's mode, see VM_xxxx flags.
29 
30 //CUTSCENE STUFF
31 //Cutscene flags
32 int Cutscene_bar_flags = CUB_NONE;
33 //Time for gradual change in seconds
34 float Cutscene_delta_time = 1.0f;
35 //How far along a change is (0 to 1)
36 float Cutscene_bars_progress = 1.0f;
37 
38 //FADEIN STUFF
39 shader Viewer_shader;
40 FadeType Fade_type = FI_NONE;
41 int Fade_start_timestamp = 0;
42 int Fade_end_timestamp = 0;
43 
44 // The detail level.  Anything below zero draws simple models earlier than it
45 // should.   Anything above zero draws higher detail models longer than it should.
46 // -2=lowest
47 // -1=low
48 // 0=normal (medium)
49 // 1=high
50 // 2=extra high
51 int Game_detail_level = 0;
52 uint Game_detail_flags = DETAIL_DEFAULT;	// see systemvars.h for explanation
53 
54 angles	Viewer_slew_angles;			//	Angles of viewer relative to forward.
55 vei		Viewer_external_info;		//	Viewer angles to ship in external view.
56 vci		Viewer_chase_info;			// View chase camera information
57 vec3d leaning_position;
58 
59 int Is_standalone;
60 
61 int Interface_last_tick = -1;			// last timer tick on flip
62 
63 #ifndef NDEBUG
64 // for debugging, used to print the currently processing filename on the loading screen
65 char Processing_filename[MAX_PATH_LEN];
66 #endif
67 
68 // override states to skip rendering of certain elements, but without disabling them completely
69 bool Basemap_override = false;
70 bool Envmap_override = false;
71 bool Specmap_override = false;
72 bool Normalmap_override = false;
73 bool Heightmap_override = false;
74 bool Glowpoint_override = false;
75 bool Glowpoint_use_depth_buffer = true;
76 bool PostProcessing_override = false;
77 bool Shadow_override = false;
78 bool Trail_render_override = false;
79 
80 bool Basemap_color_override_set = false;
81 float Basemap_color_override[4] = {0.0f, 0.0f, 0.0f, 1.0f};
82 
83 bool Glowmap_color_override_set = false;
84 float Glowmap_color_override[3] = {0.0f, 0.0f, 0.0f};
85 
86 bool Specmap_color_override_set = false;
87 float Specmap_color_override[3] = {0.0f, 0.0f, 0.0f};
88 
89 bool Gloss_override_set = false;
90 float Gloss_override = 0.0f;
91 
92 // Values used for noise for thruster animations
93 float Noise[NOISE_NUM_FRAMES] = {
94 	0.468225f,
95 	0.168765f,
96 	0.318945f,
97 	0.292866f,
98 	0.553357f,
99 	0.468225f,
100 	0.180456f,
101 	0.418465f,
102 	0.489958f,
103 	1.000000f,
104 	0.468225f,
105 	0.599820f,
106 	0.664718f,
107 	0.294215f,
108 	0.000000f
109 };
110 
111 // Variables for the loading callback hooks
112 static int cf_timestamp = -1;
113 static void (*cf_callback)(int count) = NULL;
114 static int cf_in_callback = 0;
115 static int cb_counter = 0;
116 static int cb_last_counter = 0;
117 static int cb_delta_step = -1;
118 
119 // Call this with the name of a function.  That function will
120 // then get called around 10x per second.  The callback function
121 // gets passed a 'count' which is how many times game_busy has
122 // been called since the callback was set.   It gets called
123 // one last time with count=-1 when you turn off the callback
124 // by calling game_busy_callback(NULL).   Game_busy_callback
125 // returns the current count, so you can tell how many times
126 // game_busy got called.
game_busy_callback(void (* callback)(int count),int delta_step)127 int game_busy_callback( void (*callback)(int count), int delta_step )
128 {
129 	if ( !callback ) {
130 
131 		// Call it once more to finalize things
132 		cf_in_callback++;
133 		(*cf_callback)(-1);
134 		cf_in_callback--;
135 
136 		cf_timestamp = -1;
137 		cf_callback = NULL;
138 	} else {
139 		cb_counter = 0;
140 		cb_last_counter = 0;
141 		cb_delta_step = delta_step;
142 		cf_timestamp = timer_get_milliseconds()+(1000/10);
143 		cf_callback = callback;
144 
145 		// Call it once
146 		cf_in_callback++;
147 		(*cf_callback)(0);		// pass 0 first time!
148 		cf_in_callback--;
149 
150 	}
151 
152 	return cb_counter;
153 }
154 
155 // Call whenever loading to display cursor
game_busy(const char * filename)156 void game_busy(const char *filename)
157 {
158 	if ( cf_in_callback != 0 ) return;	// don't call callback if we're already in it.
159 	if ( cf_timestamp < 0 ) return;
160 	if ( !cf_callback ) return;
161 
162 	cb_counter++;
163 
164 //	mprintf(( "CB_COUNTER=%d\n", cb_counter ));
165 
166 #ifndef NDEBUG
167 	if (filename != NULL)
168 		strcpy_s(Processing_filename, filename);
169 #endif
170 
171 	int t1 = timer_get_milliseconds();
172 
173 	if ( (t1 > cf_timestamp) || ((cb_counter > cb_last_counter+155) && (cb_delta_step > 0)) )	{
174 		cb_last_counter = cb_counter;
175 		cf_in_callback++;
176 		(*cf_callback)(cb_counter);
177 		cf_in_callback--;
178 		cf_timestamp = t1 + (1000/10);
179 	}
180 }
181 
182 #if MAX_DETAIL_LEVEL != 4
183 #error MAX_DETAIL_LEVEL is assumed to be 4 in SystemVars.cpp
184 #endif
185 
186 #if NUM_DEFAULT_DETAIL_LEVELS != 4
187 #error NUM_DEFAULT_DETAIL_LEVELS is assumed to be 4 in SystemVars.cpp
188 #endif
189 
190 // Detail level stuff
191 detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
192 	{				// Low
193 		0,			// setting
194 					// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
195 		0,			// nebula_detail;				// 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
196 		0,			// detail_distance;			// 0=lowest MAX_DETAIL_LEVEL=highest
197 		0,			//	hardware_textures;			// 0=max culling, MAX_DETAIL_LEVEL=no culling
198 		0,			//	num_small_debris;			// 0=min number, MAX_DETAIL_LEVEL=max number
199 		0,			//	num_particles;				// 0=min number, MAX_DETAIL_LEVEL=max number
200 		0,			//	num_stars;					// 0=min number, MAX_DETAIL_LEVEL=max number
201 		0,			//	shield_effects;			// 0=min, MAX_DETAIL_LEVEL=max
202 		2,			// lighting;					// 0=min, MAX_DETAIL_LEVEL=max
203 
204 					// ====  Booleans ====
205 		0,			//	targetview_model;			// 0=off, 1=on
206 		0,			//	planets_suns;				// 0=off, 1=on
207 		0,			// weapon_extras
208 	},
209 	{				// Medium
210 		1,			// setting
211 					// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
212 		2,			// nebula_detail;				// 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
213 		2,			// detail_distance;			// 0=lowest MAX_DETAIL_LEVEL=highest
214 		2,			//	hardware_textures;			// 0=max culling, MAX_DETAIL_LEVEL=no culling
215 		2,			//	num_small_debris;			// 0=min number, MAX_DETAIL_LEVEL=max number
216 		2,			//	num_particles;				// 0=min number, MAX_DETAIL_LEVEL=max number
217 		2,			//	num_stars;					// 0=min number, MAX_DETAIL_LEVEL=max number
218 		2,			//	shield_effects;			// 0=min, MAX_DETAIL_LEVEL=max
219 		3,			// lighting;					// 0=min, MAX_DETAIL_LEVEL=max
220 
221 		// ====  Booleans ====
222 		1,			//	targetview_model;			// 0=off, 1=on
223 		1,			//	planets_suns;				// 0=off, 1=on
224 		1,			// weapon extras
225 	},
226 	{				// High level
227 		2,			// setting
228 					// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
229 		2,			// nebula_detail;				// 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
230 		2,			// detail_distance;			// 0=lowest MAX_DETAIL_LEVEL=highest
231 		3,			//	hardware_textures;			// 0=max culling, MAX_DETAIL_LEVEL=no culling
232 		3,			//	num_small_debris;			// 0=min number, MAX_DETAIL_LEVEL=max number
233 		3,			//	num_particles;				// 0=min number, MAX_DETAIL_LEVEL=max number
234 		4,			//	num_stars;					// 0=min number, MAX_DETAIL_LEVEL=max number
235 		3,			//	shield_effects;			// 0=min, MAX_DETAIL_LEVEL=max
236 		4,			// lighting;					// 0=min, MAX_DETAIL_LEVEL=max
237 
238 										// ====  Booleans ====
239 		1,			//	targetview_model;			// 0=off, 1=on
240 		1,			//	planets_suns;				// 0=off, 1=on
241 		1,			// weapon_extras
242 	},
243 	{				// Highest level
244 		3,			// setting
245 					// ===== Analogs (0-MAX_DETAIL_LEVEL) ====
246 		3,			// nebula_detail;				// 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
247 		3,			// detail_distance;			// 0=lowest MAX_DETAIL_LEVEL=highest
248 		4,			//	hardware_textures;			// 0=max culling, MAX_DETAIL_LEVEL=no culling
249 		4,			//	num_small_debris;			// 0=min number, MAX_DETAIL_LEVEL=max number
250 		4,			//	num_particles;				// 0=min number, MAX_DETAIL_LEVEL=max number
251 		4,			//	num_stars;					// 0=min number, MAX_DETAIL_LEVEL=max number
252 		4,			//	shield_effects;			// 0=min, MAX_DETAIL_LEVEL=max
253 		4,			// lighting;					// 0=min, MAX_DETAIL_LEVEL=max
254 
255 										// ====  Booleans ====
256 		1,			//	targetview_model;			// 0=off, 1=on
257 		1,			//	planets_suns;				// 0=off, 1=on
258 		1,			// weapon_extras
259 	},
260 };
261 
262 // Global used to access detail levels in game and libs
263 detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS - 1];
264 
265 const SCP_vector<std::pair<int, SCP_string>> DetailLevelValues = {{ 0, "Minimum" },
266                                                                   { 1, "Low" },
267                                                                   { 2, "Medium" },
268                                                                   { 3, "High" },
269                                                                   { 4, "Ultra" }, };
270 
271 const auto ModelDetailOption =
272 	options::OptionBuilder<int>("Graphics.Detail", "Model Detail", "Detail level of models").importance(8).category(
__anonedd452780102(int val, bool) 273 		"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
274 		Detail.detail_distance = val;
275 		return true;
276 	}).finish();
277 
278 const auto TexturesOption = options::OptionBuilder<int>("Graphics.Texture",
279                                                         "3D Hardware Textures",
280                                                         "Level of detail of textures").importance(6).category("Graphics").values(
__anonedd452780202(int val, bool) 281 	DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
282 	Detail.hardware_textures = val;
283 	return true;
284 }).finish();
285 
286 const auto ParticlesOption = options::OptionBuilder<int>("Graphics.Particles",
287                                                          "Particles",
288                                                          "Level of detail for particles").importance(5).category(
__anonedd452780302(int val, bool) 289 	"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
290 	Detail.num_particles = val;
291 	return true;
292 }).finish();
293 
294 const auto SmallDebrisOption =
295 	options::OptionBuilder<int>("Graphics.SmallDebris", "Impact Effects", "Level of detail of impact effects").category(
296 		"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).importance(4).change_listener([](int val,
__anonedd452780402(int val, bool) 297 	                                                                                                         bool) {
298 		Detail.num_small_debris = val;
299 		return true;
300 	}).finish();
301 
302 const auto ShieldEffectsOption = options::OptionBuilder<int>("Graphics.ShieldEffects",
303                                                              "Shield Hit Effects",
304                                                              "Level of detail of shield impacts").importance(3).category(
__anonedd452780502(int val, bool) 305 	"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
306 	Detail.shield_effects = val;
307 	return true;
308 }).finish();
309 
310 const auto StarsOption =
311 	options::OptionBuilder<int>("Graphics.Stars", "Stars", "Number of stars in the mission").importance(2).category(
__anonedd452780602(int val, bool) 312 		"Graphics").values(DetailLevelValues).default_val(MAX_DETAIL_LEVEL).change_listener([](int val, bool) {
313 		Detail.num_stars = val;
314 		return true;
315 	}).finish();
316 
317 // Call this with:
318 // 0 - lowest
319 // NUM_DETAIL_LEVELS - highest
320 // To set the parameters in Detail to some set of defaults
detail_level_set(int level)321 void detail_level_set(int level)
322 {
323 	if ( level < 0 )	{
324 		Detail.setting = -1;
325 		return;
326 	}
327 	Assert( level >= 0 );
328 	Assert( level < NUM_DEFAULT_DETAIL_LEVELS );
329 
330 	Detail = Detail_defaults[level];
331 }
332 
333 // Returns the current detail level or -1 if custom.
current_detail_level()334 int current_detail_level()
335 {
336 //	return Detail.setting;
337 	int i;
338 
339 	for (i=0; i<NUM_DEFAULT_DETAIL_LEVELS; i++ )	{
340 		if ( memcmp( &Detail, &Detail_defaults[i], sizeof(detail_levels) )==0 )	{
341 			return i;
342 		}
343 	}
344 	return -1;
345 }
346 
347 #ifndef NDEBUG
348 DCF(detail_level,"Change the detail level")
349 {
350 	int value;
351 
352 	if (dc_optional_string_either("help", "--help")) {
353 		dc_printf( "Usage: detail_level [n]\n");
354 		dc_printf("[n]  -- is detail level.\n");
355 			dc_printf("\t0 is 'normal' detail,\n");
356 			dc_printf("\tnegative values are lower, and\n");
357 			dc_printf("\tpositive values are higher.\n\n");
358 
359 		dc_printf("No parameter resets it to default.\n");
360 		return;
361 	}
362 
363 	if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
364 		dc_printf("Detail level set to %d\n", Game_detail_level);
365 		return;
366 	}
367 
368 	if (dc_maybe_stuff_int(&value)) {
369 		Game_detail_level = value;
370 		dc_printf("Detail level set to %i\n", Game_detail_level);
371 
372 	} else {
373 		Game_detail_level = 0;
374 		dc_printf("Detail level reset\n");
375 	}
376 }
377 
378 DCF(detail, "Turns on/off parts of the game for speed testing" )
379 {
380 	int value;
381 
382 	if (dc_optional_string_either("help", "--help")) {
383 		dc_printf( "Usage: detail [n]\n");
384 		dc_printf("[n] is detail bit to toggle:\n" );
385 		dc_printf( "   1: draw the stars\n" );
386 		dc_printf( "   2: draw the nebulas\n" );
387 		dc_printf( "   4: draw the motion debris\n" );
388 		dc_printf( "   8: draw planets\n" );
389 		dc_printf( "  16: draw models not as blobs\n" );
390 		dc_printf( "  32: draw lasers not as pixels\n" );
391 		dc_printf( "  64: clear screen background after each frame\n" );
392 		dc_printf( " 128: draw hud stuff\n" );
393 		dc_printf( " 256: draw fireballs\n" );
394 		dc_printf( " 512: do collision detection\n\n" );
395 
396 		dc_printf("No argument will toggle between highest/lowest detail settings\n");
397 		return;
398 	}
399 
400 	if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
401 		dc_printf("Detail flags set to 0x%08x\n", Game_detail_flags);
402 		dc_printf( "   1: draw the stars: %s\n", ((Game_detail_flags & 1) ? "on" : "off"));
403 		dc_printf( "   2: draw the nebulas: %s\n", ((Game_detail_flags & 2)?"on" : "off"));
404 		dc_printf( "   4: draw the motion debris: %s\n", ((Game_detail_flags & 4) ? "on" : "off"));
405 		dc_printf( "   8: draw planets: %s\n", ((Game_detail_flags & 8) ? "on" : "off"));
406 		dc_printf( "  16: draw models not as blobs: %s\n", ((Game_detail_flags & 16) ? "on" : "off"));
407 		dc_printf( "  32: draw lasers not as pixels: %s\n", ((Game_detail_flags & 32) ? "on" : "off"));
408 		dc_printf( "  64: clear screen background after each frame: %s\n", ((Game_detail_flags & 64) ? "on" : "off"));
409 		dc_printf( " 128: draw hud stuff: %s\n", ((Game_detail_flags & 128) ? "on" : "off"));
410 		dc_printf( " 256: draw fireballs: %s\n", ((Game_detail_flags & 256) ? "on" : "off"));
411 		dc_printf( " 512: do collision detection: %s\n", ((Game_detail_flags & 512) ? "on" : "off"));
412 		return;
413 	}
414 
415 	if (dc_maybe_stuff_int(&value)) {
416 		Game_detail_flags ^= value;
417 
418 	} else {
419 		if (Game_detail_flags == DETAIL_DEFAULT) {
420 			Game_detail_flags = DETAIL_FLAG_CLEAR;
421 			dc_printf( "Detail flags set lowest (except has screen clear)\n" );
422 		} else {
423 			Game_detail_flags = DETAIL_DEFAULT;
424 			dc_printf( "Detail flags set highest\n" );
425 		}
426 	}
427 }
428 #endif
429 
430 // Goober5000
431 // (Taylor says that for optimization purposes malloc/free should be used rather than vm_malloc/vm_free here)
432 // NOTE: Because this uses memcpy, it should only be used to sort POD elements!
insertion_sort(void * array_base,size_t array_size,size_t element_size,int (* fncompare)(const void *,const void *))433 void insertion_sort(void *array_base, size_t array_size, size_t element_size, int (*fncompare)(const void *, const void *))
434 {
435 	int i, j;
436 	void *current;
437 	char *array_byte_base;
438 
439 	// this is used to avoid having to cast array_base to (char *) all the time
440 	array_byte_base = (char *) array_base;
441 
442 	// allocate space for the element being moved
443 	current = malloc(element_size);
444 	if (current == NULL)
445 	{
446 		Int3();
447 		return;
448 	}
449 
450 	// loop
451 	for (i = 1; (unsigned) i < array_size; i++)
452 	{
453 		// grab the current element
454 		memcpy(current, array_byte_base + (i * element_size), element_size);
455 
456 		// bump other elements toward the end of the array
457 		for (j = i - 1; (j >= 0) && (fncompare(array_byte_base + (j * element_size), current) > 0); j--)
458 		{
459 			memcpy(array_byte_base + ((j + 1) * element_size), array_byte_base + (j * element_size), element_size);
460 		}
461 
462 		// insert the current element at the correct place
463 		memcpy(array_byte_base + ((j + 1) * element_size), current, element_size);
464 	}
465 
466 	// free the allocated space
467 	free(current);
468 }
469 
470 // Stuff that can't be included in vmallocator.h
471 
472 std::locale SCP_default_locale("");
473 
SCP_tolower(char * str)474 void SCP_tolower(char *str)
475 {
476 	for (; *str != '\0'; ++str)
477 		*str = SCP_tolower(*str);
478 }
479 
SCP_toupper(char * str)480 void SCP_toupper(char *str)
481 {
482 	for (; *str != '\0'; ++str)
483 		*str = SCP_toupper(*str);
484 }
485