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