]> icculus.org git repositories - taylor/freespace2.git/blob - src/globalincs/systemvars.cpp
make loading screen and title screen work with emterpreter async
[taylor/freespace2.git] / src / globalincs / systemvars.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/GlobalIncs/SystemVars.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Variables and constants common to FreeSpace and Fred.
16  *
17  * $Log$
18  * Revision 1.5  2005/10/01 21:42:07  taylor
19  * if we are using a custom detail level then give the closest relative to the defaults when we request
20  *   the current detail level (needed to be fixed for one FS1 thing in particular)
21  *
22  * Revision 1.4  2003/05/25 02:30:42  taylor
23  * Freespace 1 support
24  *
25  * Revision 1.3  2002/06/09 04:41:17  relnev
26  * added copyright header
27  *
28  * Revision 1.2  2002/05/07 03:16:45  theoddone33
29  * The Great Newline Fix
30  *
31  * Revision 1.1.1.1  2002/05/03 03:28:09  root
32  * Initial import.
33  *
34  * 
35  * 12    9/09/99 8:53p Dave
36  * Fixed multiplayer degenerate orientation case problem. Make sure warp
37  * effect never goes lower than LOD 1. 
38  * 
39  * 11    9/06/99 11:25a Mikek
40  * Decrease some settings for High detail level.
41  * 
42  * 10    8/05/99 2:05a Dave
43  * Whee.
44  * 
45  * 9     7/29/99 10:47p Dave
46  * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
47  * 
48  * 8     7/29/99 12:05a Dave
49  * Nebula speed optimizations.
50  * 
51  * 7     6/22/99 7:03p Dave
52  * New detail options screen.
53  * 
54  * 6     6/16/99 4:06p Dave
55  * New pilot info popup. Added new draw-bitmap-as-poly function.
56  * 
57  * 5     5/24/99 5:45p Dave
58  * Added detail levels to the nebula, with a decent speedup. Split nebula
59  * lightning into its own section.
60  * 
61  * 4     11/30/98 1:07p Dave
62  * 16 bit conversion, first run.
63  * 
64  * 3     10/07/98 6:27p Dave
65  * Globalized mission and campaign file extensions. Removed Silent Threat
66  * special code. Moved \cache \players and \multidata into the \data
67  * directory.
68  * 
69  * 2     10/07/98 10:52a Dave
70  * Initial checkin.
71  * 
72  * 1     10/07/98 10:48a Dave
73  * 
74  * 38    9/21/98 8:46p Dave
75  * Put in special check in fred for identifying unknown ships.
76  * 
77  * 37    8/17/98 5:07p Dave
78  * First rev of corkscrewing missiles.
79  * 
80  * 36    5/13/98 11:34p Mike
81  * Model caching system.
82  * 
83  * 35    4/25/98 4:06p John
84  * Made defaults make a little more sense
85  * 
86  * 34    4/20/98 8:41p John
87  * Made debris culling actually reduce Glide texture resolution.
88  * 
89  * 33    4/12/98 9:56a John
90  * Made lighting detail flags work.   Made explosions cast light on
91  * highest.
92  * 
93  * 32    4/08/98 8:34p Lawrance
94  * Fix up how custom button works on the detail tab.
95  * 
96  * 31    4/01/98 5:34p John
97  * Made only the used POFs page in for a level.   Reduced some interp
98  * arrays.    Made custom detail level work differently.
99  * 
100  * 30    3/31/98 5:18p John
101  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
102  * bunch of debug stuff out of player file.  Made model code be able to
103  * unload models and malloc out only however many models are needed.
104  *  
105  * 
106  * 29    3/30/98 2:38p Mike
107  * Add asteroid_density to detail level support.
108  * No force explosion damage in training missions.
109  * Make cargo deathrolls shorter.
110  * 
111  * 28    3/24/98 8:16a John
112  * made highest detail different than next one down
113  * 
114  * 27    3/23/98 5:19p John
115  * Upped number of default detail levels to 4
116  * 
117  * 26    3/22/98 4:11p Andsager
118  * Remove global Freespace_running
119  * 
120  * 25    3/22/98 3:28p John
121  * Added in stippled alpha for lower details.  Made medium detail use
122  * engine glow.
123  * 
124  * 24    3/22/98 2:41p John
125  * Added lighting into the detail structure.
126  * 
127  * 23    3/22/98 11:06a John
128  * Changed default detail levels
129  * 
130  * 22    3/22/98 11:02a John
131  * Made a bunch of the detail levels actually do something
132  * 
133  * 21    3/22/98 9:53a John
134  * Added in first stage of new detail level stuff
135  * 
136  * 20    3/09/98 12:13a Andsager
137  * Add code to help find jumps in position.
138  * 
139  * 19    2/28/98 7:03p Lawrance
140  * get slew working in any view
141  * 
142  * 18    2/16/98 4:16p John
143  * Added loading animation
144  * 
145  * 17    2/10/98 9:06a John
146  * Added variables for restoring
147  * 
148  * 16    2/05/98 9:27p John
149  * took out ending min/max etc on monitor
150  * 
151  * 15    2/05/98 9:21p John
152  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
153  * game.
154  * 
155  * 14    2/03/98 9:25p John
156  * Upgraded Direct3D code to new version 5.0 code.  Separated the D3D code
157  * more.  Added a global variable D3D_enabled flag.
158  * 
159  * 13    1/17/98 12:17p John
160  * fixed erroneous print
161  * 
162  * 12    1/17/98 12:14p John
163  * Added loading... bar to freespace.
164  * 
165  * 11    1/11/98 2:15p John
166  * Changed a lot of stuff that had to do with bitmap loading.   Made cfile
167  * not do callbacks, I put that in global code.   Made only bitmaps that
168  * need to load for a level load.
169  * 
170  * 10    12/16/97 6:20p Hoffoss
171  * Added more debugging code for demos, and fixed a bug in demo
172  * recording/playback.
173  * 
174  * 9     12/05/97 3:46p John
175  * made ship thruster glow scale instead of being an animation.
176  * 
177  * 8     8/05/97 10:18a Lawrance
178  * my_rand() being used temporarily instead of rand()
179  * 
180  * 7     8/04/97 10:21a Dave
181  * Added Is_standalone global var
182  * 
183  * 6     6/24/97 6:21p John
184  * added detail flags.
185  * sped up motion debris system a bit.
186  * 
187  * 5     4/15/97 11:28p Mike
188  * External view system
189  * 
190  * 4     4/15/97 4:00p Mike
191  * Intermediate checkin caused by getting other files.  Working on camera
192  * slewing system.
193  * 
194  * 3     4/08/97 8:47a John
195  * Added a global varible for detail level
196  * 
197  * 2     4/01/97 11:07p Mike
198  * Clean up game sequencing functions.  Get rid of Multiplayer and add
199  * Game_mode.  Add SystemVars.cpp
200  * 
201  * 1     4/01/97 10:59p Mike
202  *
203  * $NoKeywords: $
204  */
205
206 #include "pstypes.h"
207 #include "systemvars.h"
208 #include "timer.h"
209 #include "neb.h"
210
211 fix Missiontime;
212 fix Frametime;
213 int     Framecount=0;
214
215 int Game_mode;
216
217 int Game_restoring = 0;         // If set, this means we are restoring data from disk
218
219 int     Viewer_mode;            //      Viewer's mode, see VM_xxxx flags.
220
221 // The detail level.  Anything below zero draws simple models earlier than it
222 // should.   Anything above zero draws higher detail models longer than it should.
223 // -2=lowest
224 // -1=low
225 // 0=normal (medium)    
226 // 1=high
227 // 2=extra high
228 int Game_detail_level = 0;
229 uint Game_detail_flags = DETAIL_DEFAULT;        // see systemvars.h for explanation
230
231 angles  Viewer_slew_angles;                     //      Angles of viewer relative to forward.
232 vei             Viewer_external_info;           //      Viewer angles to ship in external view.
233 vci             Viewer_chase_info;                      // View chase camera information
234
235 int Is_standalone;
236 int Rand_count;
237
238 int Interface_last_tick = -1;                   // last timer tick on flip
239
240 // for notifying players of unknown ship types
241 int Fred_found_unknown_ship_during_parsing = 0;
242
243 // Values used for noise for thruster animations
244 float Noise[NOISE_NUM_FRAMES] = { 
245         0.468225f,
246         0.168765f,
247         0.318945f,
248         0.292866f,
249         0.553357f,
250         0.468225f,
251         0.180456f,
252         0.418465f,
253         0.489958f,
254         1.000000f,
255         0.468225f,
256         0.599820f,
257         0.664718f,
258         0.294215f,
259         0.000000f
260 };
261
262
263 int myrand()
264 {
265         int rval;
266 #if MY_RAND_MAX != RAND_MAX
267         rval = rand() % (MY_RAND_MAX+1);
268 #else
269         rval = rand();
270 #endif
271         Rand_count++;
272 //      nprintf(("Alan","RAND: %d\n", rval));
273         return rval;
274 }
275
276
277 // Variables for the loading callback hooks
278 static int cf_timestamp = -1;
279 static void (*cf_callback)(int count) = NULL;
280 static int cf_in_callback = 0;  
281 static int cb_counter = 0;
282 static int cb_last_counter = 0;
283 static int cb_delta_step = -1;
284
285 // Call this with the name of a function.  That function will
286 // then get called around 10x per second.  The callback function
287 // gets passed a 'count' which is how many times game_busy has
288 // been called since the callback was set.   It gets called
289 // one last time with count=-1 when you turn off the callback
290 // by calling game_busy_callback(NULL).   Game_busy_callback
291 // returns the current count, so you can tell how many times
292 // game_busy got called.
293 extern "C"
294 int game_busy_callback( void (*callback)(int count), int delta_step )
295 {
296         if ( !callback ) {
297
298                 // Call it once more to finalize things
299                 cf_in_callback++;
300                 (*cf_callback)(-1);
301                 cf_in_callback--;
302
303                 cf_timestamp = -1;
304                 cf_callback = NULL;
305         } else {
306                 cb_counter = 0;
307                 cb_last_counter = 0;
308                 cb_delta_step = delta_step;
309                 cf_timestamp = timer_get_milliseconds()+(1000/10);
310                 cf_callback = callback;
311
312                 // Call it once
313                 cf_in_callback++;
314                 (*cf_callback)(0);              // pass 0 first time!
315                 cf_in_callback--;
316         
317         }
318
319         return cb_counter;
320 }
321
322 // Call whenever loading to display cursor
323 extern "C"
324 void game_busy()
325 {
326         if ( cf_in_callback != 0 ) return;      // don't call callback if we're already in it.
327         if ( cf_timestamp < 0 ) return;
328         if ( !cf_callback ) return;
329
330         cb_counter++;
331
332 //      mprintf(( "CB_COUNTER=%d\n", cb_counter ));
333
334         int t1 = timer_get_milliseconds();
335
336         if ( (t1 > cf_timestamp) || ((cb_counter>cb_last_counter+155)&&(cb_delta_step>0)) )     {
337                 cb_last_counter = cb_counter;
338                 cf_in_callback++;
339                 (*cf_callback)(cb_counter);
340                 cf_in_callback--;
341                 cf_timestamp = t1 + +(1000/10);
342         }
343 }
344
345 //======================== CODE TO MONITOR EVENTS ======================
346
347 #ifndef NDEBUG
348
349 #define MAX_MONITORS 64
350
351 static int Num_monitors = 0;
352 static monitor *Monitor[MAX_MONITORS];
353
354 monitor::monitor( const char *_name )
355 {
356         int i;
357
358         if ( Num_monitors >= MAX_MONITORS )     {
359                 Int3();                 // Too many monitor variables!! Increase MAX_MONITORS!!
360                 return;
361         }
362
363         for (i=0; i<Num_monitors; i++ ) {
364                 int ret  = SDL_strcasecmp( Monitor[i]->name, _name );
365
366                 if ( ret == 0)  {
367                         Int3();         // This monitor variable already exists!!!! 
368                         return;
369                 } else if ( ret > 0 )   {
370                         break;          // Insert it here
371
372                 } else if ( ret < 0 )   {
373                         // do nothing
374                 }
375         }
376
377         if ( i < Num_monitors ) {
378                 // Insert it at element i
379                 int j;
380                 for (j=Num_monitors; j>i; j-- ) {
381                         Monitor[j] = Monitor[j-1];
382                 }
383                 Monitor[i] = this;              
384                 Num_monitors++;
385         } else {
386                 Monitor[Num_monitors] = this;           
387                 Num_monitors++;
388         }
389
390         name = (char*)_name;
391         value = 0;
392 }
393
394
395 int Monitor_inited = 0;
396 char Monitor_filename[128];
397 fix monitor_last_time = -1;
398
399 DCF(monitor,"Monitors game performace")
400 {
401         if ( Dc_command )       {
402                 dc_get_arg(ARG_STRING|ARG_NONE);
403                 if ( Dc_arg_type == ARG_NONE )  {
404                         if ( Monitor_inited )   {
405                                 Monitor_inited = 0;
406
407 /*
408                                 FILE *fp = fopen( Monitor_filename, "at" );
409                                 if ( fp )       {
410                                         fprintf( fp, "\n\n" );
411                                         fprintf( fp, "Name\tMin\tMax\tAvg\n" );
412                                         for (int i=0; i<Num_monitors; i++ )     {
413                                                 if ( Monitor[i]->cnt > 0 )      {
414                                                         fprintf( fp, "%s\t%d\t%d\t%d\n", Monitor[i]->name, Monitor[i]->min, Monitor[i]->max, Monitor[i]->sum / Monitor[i]->cnt  );
415                                                 } else {
416                                                         fprintf( fp, "%s\t%d\t%d\t?\n", Monitor[i]->name, Monitor[i]->min, Monitor[i]->max );
417                                                 }
418                                         }
419                                         fclose(fp);
420                                 }
421 */
422
423                                 dc_printf( "Monitor to file '%s' turned off\n", Monitor_filename );
424                         } else {
425                                 dc_printf( "Monitor isn't on\n" );
426                         }
427                 } else {
428                         if ( Monitor_inited )   {
429                                 dc_printf( "Monitor already on\n" );
430                         } else {
431                                 Monitor_inited = 1;
432
433                                 SDL_strlcpy( Monitor_filename, Dc_arg, SDL_arraysize(Monitor_filename) );
434
435                                 // Reset them all
436                                 int i;
437                                 for (i=0; i<Num_monitors; i++ ) {
438                                         Monitor[i]->value = 0;
439                                         Monitor[i]->sum = 0;
440                                         Monitor[i]->cnt = 0;
441                                         Monitor[i]->min = 0;
442                                         Monitor[i]->max = 0;
443                                 }
444
445                                 FILE *fp = fopen( Monitor_filename, "wt" );
446                                 if ( fp )       {
447                                         for (i=0; i<Num_monitors; i++ ) {
448                                                 if ( i > 0 )    {
449                                                         fprintf( fp, "\t" );
450                                                 }
451                                                 fprintf( fp, "%s", Monitor[i]->name );
452                                         
453                                         }
454                                         fprintf( fp, "\n" );
455                                         fclose(fp);
456                                 }
457                                 dc_printf( "Monitor outputting to file '%s'\n", Monitor_filename );
458                                 monitor_last_time = -1;
459                         }
460                 }
461         }
462         if ( Dc_help )  {
463                 dc_printf( "Usage: monitor filename\nOutputs monitoring info to filename. No filename turns it off\n" );
464         }
465         
466 }
467
468
469 MONITOR(FrameRateX100);
470
471 void monitor_update()
472 {
473         int i;
474         FILE * fp;
475
476         fix this_time = timer_get_fixed_seconds();
477         fix frametime;
478
479         if ( monitor_last_time != -1 )  {
480                 frametime = this_time - monitor_last_time;
481         } else {
482                 frametime = 0;
483         }
484
485         if ( frametime > 0 )    {
486                 MONITOR_INC(FrameRateX100, (F1_0*100) / frametime );
487         } else {
488                 MONITOR_INC(FrameRateX100, 0 );
489         }
490
491                 
492         if ( !Monitor_inited )  {
493                 return;
494         }
495
496         if ( frametime != 0 )   {
497                 fp = fopen( Monitor_filename, "at" );
498                 if ( fp )       {
499
500                         for (i=0; i<Num_monitors; i++ ) {
501                                 if (i>0) fprintf( fp, "\t" );
502                                 fprintf( fp, "%d", Monitor[i]->value );
503                         }
504                         fprintf( fp, "\n" );
505                         fclose(fp);
506                 }
507
508                 for (i=0; i<Num_monitors; i++ ) {
509
510                         // Record stats
511                         Monitor[i]->sum += Monitor[i]->value;
512
513                         if ( (Monitor[i]->cnt < 1)  || (Monitor[i]->value < Monitor[i]->min ))  {
514                                 Monitor[i]->min = Monitor[i]->value;
515                         }
516
517                         if ( (Monitor[i]->cnt < 1)  || (Monitor[i]->value > Monitor[i]->max ))  {
518                                 Monitor[i]->max = Monitor[i]->value;
519                         }
520
521                         Monitor[i]->cnt++;
522
523                         //      Reset the value
524                         Monitor[i]->value = 0;
525                 }
526         } else {
527                 for (i=0; i<Num_monitors; i++ ) {
528                         //      Reset the value
529                         Monitor[i]->value = 0;
530                 }
531         }
532
533         monitor_last_time = timer_get_fixed_seconds();
534
535 }
536 #endif  //NDEBUG
537
538
539 #if MAX_DETAIL_LEVEL != 4
540 #error MAX_DETAIL_LEVEL is assumed to be 4 in SystemVars.cpp
541 #endif
542
543 #if NUM_DEFAULT_DETAIL_LEVELS != 4
544 #error NUM_DEFAULT_DETAIL_LEVELS is assumed to be 4 in SystemVars.cpp
545 #endif
546
547 // Detail level stuff
548 detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
549 #ifdef MAKE_FS1
550         {                               // Low
551                 0,                      // setting
552                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
553                 0,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
554                 0,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest
555                 0,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
556                 0,                      //  weapon_detail;                              // 0=min number, MAX_DETAIL_LEVEL=max number
557                 0,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
558                 0,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
559                 0,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
560                 0,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
561                 1,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max
562                 0,                      // unknown_slider;
563
564                                         // ====  Booleans ====
565                 0,                      //      targetview_model;                       // 0=off, 1=on
566                 0,                      //      planets_suns;                           // 0=off, 1=on
567                 0,                      //  unknown_boolean1;
568                 0,                      //  unknown_boolean2;
569                 0,                      //  engine_glow;                                // 0=off, 1=on
570                 0,                      //  alpha_effects;                              // 0=off, 1=on
571         },
572         {                               // Medium
573                 1,                      // setting
574                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
575                 1,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
576                 1,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest
577                 1,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
578                 2,                      //  weapon_detail;                              // 0=min number, MAX_DETAIL_LEVEL=max number
579                 2,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
580                 2,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
581                 2,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
582                 1,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
583                 2,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max
584                 1,                      // unknown_slider;
585
586                                         // ====  Booleans ====
587                 1,                      //      targetview_model;                       // 0=off, 1=on
588                 1,                      //      planets_suns;                           // 0=off, 1=on
589                 1,                      //  unknown_boolean1;
590                 1,                      //  unknown_boolean2;
591                 1,                      //  engine_glow;                                // 0=off, 1=on
592                 0,                      //  alpha_effects;                              // 0=off, 1=on
593         },
594         {                               // High
595                 2,                      // setting
596                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
597                 2,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
598                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest
599                 2,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
600                 4,                      //  weapon_detail;                              // 0=min number, MAX_DETAIL_LEVEL=max number
601                 4,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
602                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
603                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
604                 2,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
605                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max
606                 2,                      // unknown_slider;
607
608                                         // ====  Booleans ====
609                 1,                      //      targetview_model;                       // 0=off, 1=on
610                 1,                      //      planets_suns;                           // 0=off, 1=on
611                 1,                      //  unknown_boolean1;
612                 1,                      //  unknown_boolean2;
613                 1,                      //  engine_glow;                                // 0=off, 1=on
614                 1,                      //  alpha_effects;                              // 0=off, 1=on
615         },
616         {                               // Highest
617                 3,                      // setting
618                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
619                 3,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
620                 4,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest
621                 3,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
622                 4,                      //  weapon_detail;                              // 0=min number, MAX_DETAIL_LEVEL=max number
623                 4,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
624                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
625                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
626                 4,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
627                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max
628                 4,                      // unknown_slider;
629
630                                         // ====  Booleans ====
631                 1,                      //      targetview_model;                       // 0=off, 1=on
632                 1,                      //      planets_suns;                           // 0=off, 1=on
633                 1,                      //  unknown_boolean1;
634                 1,                      //  unknown_boolean2;
635                 1,                      //  engine_glow;                                // 0=off, 1=on
636                 1,                      //  alpha_effects;                              // 0=off, 1=on
637         },
638 #else
639         {                               // Low
640                 0,                      // setting
641                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
642                 0,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
643                 0,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
644                 0,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
645                 0,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
646                 0,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
647                 0,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
648                 0,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
649                 2,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
650
651                                         // ====  Booleans ====
652                 0,                      //      targetview_model;                       // 0=off, 1=on          
653                 0,                      //      planets_suns;                           // 0=off, 1=on          
654                 0,                      // weapon_extras
655         },
656         {                               // Medium
657                 1,                      // setting
658                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
659                 1,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
660                 1,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
661                 1,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
662                 2,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
663                 2,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
664                 2,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
665                 1,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
666                 3,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
667
668                 // ====  Booleans ====
669                 1,                      //      targetview_model;                       // 0=off, 1=on          
670                 1,                      //      planets_suns;                           // 0=off, 1=on
671                 1,                      // weapon extras                                
672         },
673         {                               // High level
674                 2,                      // setting
675                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
676                 2,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
677                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
678                 3,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
679                 3,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
680                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
681                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
682                 3,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
683                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
684
685                                                                                 // ====  Booleans ====
686                 1,                      //      targetview_model;                       // 0=off, 1=on          
687                 1,                      //      planets_suns;                           // 0=off, 1=on
688                 1,                      // weapon_extras
689         },
690         {                               // Highest level
691                 3,                      // setting
692                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
693                 3,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
694                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
695                 4,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
696                 4,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
697                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
698                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
699                 4,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
700                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
701
702                                                                                 // ====  Booleans ====
703                 1,                      //      targetview_model;                       // 0=off, 1=on          
704                 1,                      //      planets_suns;                           // 0=off, 1=on
705                 1,                      // weapon_extras
706         },
707 #endif
708 };
709
710
711 // Global used to access detail levels in game and libs
712 detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS-1];
713
714 // Call this with:
715 // 0 - lowest
716 // NUM_DETAIL_LEVELS - highest
717 // To set the parameters in Detail to some set of defaults
718 void detail_level_set(int level)
719 {
720         if ( level < 0 )        {
721                 Detail.setting = -1;
722                 return;
723         }
724         SDL_assert( level >= 0 );
725         SDL_assert( level < NUM_DEFAULT_DETAIL_LEVELS );
726
727         Detail = Detail_defaults[level];
728
729         // reset nebula stuff
730         neb2_set_detail_level(level);
731 }
732
733 // Returns the current detail level or -1 if custom.
734 int current_detail_level()
735 {
736 //      return Detail.setting;
737         int i;
738         int match = -1;
739
740         for (i=0; i<NUM_DEFAULT_DETAIL_LEVELS; i++ )    {
741                 if ( Detail.setting == -1 ) {
742                         // in the case of a custom detail level, return it's closest match
743 #ifdef MAKE_FS1
744                         if ( (Detail.nebula_detail >= Detail_defaults[i].nebula_detail) &&
745                                  (Detail.detail_distance >= Detail_defaults[i].detail_distance) &&
746                                  (Detail.weapon_detail >= Detail_defaults[i].weapon_detail) &&
747                                  (Detail.hardware_textures >= Detail_defaults[i].hardware_textures) &&
748                                  (Detail.shield_effects >= Detail_defaults[i].shield_effects) &&
749                                  (Detail.lighting >= Detail_defaults[i].lighting) &&
750                                  (Detail.planets_suns == Detail_defaults[i].planets_suns) &&
751                                  (Detail.engine_glows == Detail_defaults[i].engine_glows) &&
752                                  (Detail.alpha_effects == Detail_defaults[i].alpha_effects) )
753 #else
754                         if ( (Detail.nebula_detail >= Detail_defaults[i].nebula_detail) &&
755                                  (Detail.detail_distance >= Detail_defaults[i].detail_distance) &&
756                                  (Detail.hardware_textures >= Detail_defaults[i].hardware_textures) &&
757                                  (Detail.shield_effects >= Detail_defaults[i].shield_effects) &&
758                                  (Detail.lighting >= Detail_defaults[i].lighting) &&
759                                  (Detail.planets_suns == Detail_defaults[i].planets_suns) &&
760                                  (Detail.weapon_extras == Detail_defaults[i].weapon_extras) )
761 #endif
762                         {
763                                 match = i; // we will keep whatever the highest value is
764                         }
765                 } else if ( memcmp( &Detail, &Detail_defaults[i], sizeof(detail_levels) )==0 )  {
766                         return i;
767                 }
768         }
769
770         return match;
771 }
772
773 #ifndef NDEBUG
774 DCF(detail_level,"Change the detail level")
775 {
776         if ( Dc_command )       {
777                 dc_get_arg(ARG_INT|ARG_NONE);
778                 if ( Dc_arg_type & ARG_NONE )   {
779                         Game_detail_level = 0;
780                         dc_printf( "Detail level reset\n" );
781                 }
782                 if ( Dc_arg_type & ARG_INT )    {
783                         Game_detail_level = Dc_arg_int;
784                 }
785         }
786
787         if ( Dc_help )  
788                 dc_printf( "Usage: detail_level [n]\nn is detail level. 0 normal, - lower, + higher, -2 to 2 usually\nNo parameter resets it to default.\n" );
789
790         if ( Dc_status )                                
791                 dc_printf("Detail level set to %d\n", Game_detail_level);
792 }
793
794 DCF(detail, "Turns on/off parts of the game for speed testing" )
795 {
796         if ( Dc_command )       {
797                 dc_get_arg(ARG_INT|ARG_NONE);
798                 if ( Dc_arg_type & ARG_NONE )   {
799                         if ( Game_detail_flags == DETAIL_DEFAULT )      {
800                                 Game_detail_flags = DETAIL_FLAG_CLEAR;
801                                 dc_printf( "Detail flags set lowest (except has screen clear)\n" );
802                         } else {
803                                 Game_detail_flags = DETAIL_DEFAULT;
804                                 dc_printf( "Detail flags set highest\n" );
805                         }
806                 }
807                 if ( Dc_arg_type & ARG_INT )    {
808                         Game_detail_flags ^= Dc_arg_int;
809                 }
810         }
811
812         if ( Dc_help )  {
813                 dc_printf( "Usage: detail [n]\nn is detail bit to toggle.\n" );
814                 dc_printf( "   1: draw the stars\n" );
815                 dc_printf( "   2: draw the nebulas\n" );
816                 dc_printf( "   4: draw the motion debris\n" );
817                 dc_printf( "   8: draw planets\n" );
818                 dc_printf( "  16: draw models not as blobs\n" );
819                 dc_printf( "  32: draw lasers not as pixels\n" );
820                 dc_printf( "  64: clear screen background after each frame\n" );
821                 dc_printf( " 128: draw hud stuff\n" );
822                 dc_printf( " 256: draw fireballs\n" );
823                 dc_printf( " 512: do collision detection\n" );
824         }
825
826         if ( Dc_status )        {
827                 dc_printf("Detail flags set to 0x%08x\n", Game_detail_flags);
828                 dc_printf( "   1: draw the stars: %s\n", (Game_detail_flags&1?"on":"off") );
829                 dc_printf( "   2: draw the nebulas: %s\n", (Game_detail_flags&2?"on":"off") );
830                 dc_printf( "   4: draw the motion debris: %s\n", (Game_detail_flags&4?"on":"off")  );
831                 dc_printf( "   8: draw planets: %s\n", (Game_detail_flags&8?"on":"off")  );
832                 dc_printf( "  16: draw models not as blobs: %s\n", (Game_detail_flags&16?"on":"off")  );
833                 dc_printf( "  32: draw lasers not as pixels: %s\n", (Game_detail_flags&32?"on":"off")  );
834                 dc_printf( "  64: clear screen background after each frame: %s\n", (Game_detail_flags&64?"on":"off")  );
835                 dc_printf( " 128: draw hud stuff: %s\n", (Game_detail_flags&128?"on":"off")  );
836                 dc_printf( " 256: draw fireballs: %s\n", (Game_detail_flags&256?"on":"off")  );
837                 dc_printf( " 512: do collision detection: %s\n", (Game_detail_flags&512?"on":"off")  );
838         }
839 }
840 #endif