]> icculus.org git repositories - taylor/freespace2.git/blob - src/globalincs/systemvars.cpp
clean up and simplify effects and updating
[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 int game_busy_callback( void (*callback)(int count), int delta_step )
294 {
295         if ( !callback ) {
296
297                 // Call it once more to finalize things
298                 cf_in_callback++;
299                 (*cf_callback)(-1);
300                 cf_in_callback--;
301
302                 cf_timestamp = -1;
303                 cf_callback = NULL;
304         } else {
305                 cb_counter = 0;
306                 cb_last_counter = 0;
307                 cb_delta_step = delta_step;
308                 cf_timestamp = timer_get_milliseconds()+(1000/10);
309                 cf_callback = callback;
310
311                 // Call it once
312                 cf_in_callback++;
313                 (*cf_callback)(0);              // pass 0 first time!
314                 cf_in_callback--;
315         
316         }
317
318         return cb_counter;
319 }
320
321 // Call whenever loading to display cursor
322 void game_busy()
323 {
324         if ( cf_in_callback != 0 ) return;      // don't call callback if we're already in it.
325         if ( cf_timestamp < 0 ) return;
326         if ( !cf_callback ) return;
327
328         cb_counter++;
329
330 //      mprintf(( "CB_COUNTER=%d\n", cb_counter ));
331
332         int t1 = timer_get_milliseconds();
333
334         if ( (t1 > cf_timestamp) || ((cb_counter>cb_last_counter+155)&&(cb_delta_step>0)) )     {
335                 cb_last_counter = cb_counter;
336                 cf_in_callback++;
337                 (*cf_callback)(cb_counter);
338                 cf_in_callback--;
339                 cf_timestamp = t1 + +(1000/10);
340         }
341 }
342
343 //======================== CODE TO MONITOR EVENTS ======================
344
345 #ifndef NDEBUG
346
347 #define MAX_MONITORS 64
348
349 static int Num_monitors = 0;
350 static monitor *Monitor[MAX_MONITORS];
351
352 monitor::monitor( const char *_name )
353 {
354         int i;
355
356         if ( Num_monitors >= MAX_MONITORS )     {
357                 Int3();                 // Too many monitor variables!! Increase MAX_MONITORS!!
358                 return;
359         }
360
361         for (i=0; i<Num_monitors; i++ ) {
362                 int ret  = SDL_strcasecmp( Monitor[i]->name, _name );
363
364                 if ( ret == 0)  {
365                         Int3();         // This monitor variable already exists!!!! 
366                         return;
367                 } else if ( ret > 0 )   {
368                         break;          // Insert it here
369
370                 } else if ( ret < 0 )   {
371                         // do nothing
372                 }
373         }
374
375         if ( i < Num_monitors ) {
376                 // Insert it at element i
377                 int j;
378                 for (j=Num_monitors; j>i; j-- ) {
379                         Monitor[j] = Monitor[j-1];
380                 }
381                 Monitor[i] = this;              
382                 Num_monitors++;
383         } else {
384                 Monitor[Num_monitors] = this;           
385                 Num_monitors++;
386         }
387
388         name = (char*)_name;
389         value = 0;
390 }
391
392
393 int Monitor_inited = 0;
394 char Monitor_filename[128];
395 fix monitor_last_time = -1;
396
397 DCF(monitor,"Monitors game performace")
398 {
399         if ( Dc_command )       {
400                 dc_get_arg(ARG_STRING|ARG_NONE);
401                 if ( Dc_arg_type == ARG_NONE )  {
402                         if ( Monitor_inited )   {
403                                 Monitor_inited = 0;
404
405 /*
406                                 FILE *fp = fopen( Monitor_filename, "at" );
407                                 if ( fp )       {
408                                         fprintf( fp, "\n\n" );
409                                         fprintf( fp, "Name\tMin\tMax\tAvg\n" );
410                                         for (int i=0; i<Num_monitors; i++ )     {
411                                                 if ( Monitor[i]->cnt > 0 )      {
412                                                         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  );
413                                                 } else {
414                                                         fprintf( fp, "%s\t%d\t%d\t?\n", Monitor[i]->name, Monitor[i]->min, Monitor[i]->max );
415                                                 }
416                                         }
417                                         fclose(fp);
418                                 }
419 */
420
421                                 dc_printf( "Monitor to file '%s' turned off\n", Monitor_filename );
422                         } else {
423                                 dc_printf( "Monitor isn't on\n" );
424                         }
425                 } else {
426                         if ( Monitor_inited )   {
427                                 dc_printf( "Monitor already on\n" );
428                         } else {
429                                 Monitor_inited = 1;
430
431                                 SDL_strlcpy( Monitor_filename, Dc_arg, SDL_arraysize(Monitor_filename) );
432
433                                 // Reset them all
434                                 int i;
435                                 for (i=0; i<Num_monitors; i++ ) {
436                                         Monitor[i]->value = 0;
437                                         Monitor[i]->sum = 0;
438                                         Monitor[i]->cnt = 0;
439                                         Monitor[i]->min = 0;
440                                         Monitor[i]->max = 0;
441                                 }
442
443                                 FILE *fp = fopen( Monitor_filename, "wt" );
444                                 if ( fp )       {
445                                         for (i=0; i<Num_monitors; i++ ) {
446                                                 if ( i > 0 )    {
447                                                         fprintf( fp, "\t" );
448                                                 }
449                                                 fprintf( fp, "%s", Monitor[i]->name );
450                                         
451                                         }
452                                         fprintf( fp, "\n" );
453                                         fclose(fp);
454                                 }
455                                 dc_printf( "Monitor outputting to file '%s'\n", Monitor_filename );
456                                 monitor_last_time = -1;
457                         }
458                 }
459         }
460         if ( Dc_help )  {
461                 dc_printf( "Usage: monitor filename\nOutputs monitoring info to filename. No filename turns it off\n" );
462         }
463         
464 }
465
466
467 MONITOR(FrameRateX100);
468
469 void monitor_update()
470 {
471         int i;
472         FILE * fp;
473
474         fix this_time = timer_get_fixed_seconds();
475         fix frametime;
476
477         if ( monitor_last_time != -1 )  {
478                 frametime = this_time - monitor_last_time;
479         } else {
480                 frametime = 0;
481         }
482
483         if ( frametime > 0 )    {
484                 MONITOR_INC(FrameRateX100, (F1_0*100) / frametime );
485         } else {
486                 MONITOR_INC(FrameRateX100, 0 );
487         }
488
489                 
490         if ( !Monitor_inited )  {
491                 return;
492         }
493
494         if ( frametime != 0 )   {
495                 fp = fopen( Monitor_filename, "at" );
496                 if ( fp )       {
497
498                         for (i=0; i<Num_monitors; i++ ) {
499                                 if (i>0) fprintf( fp, "\t" );
500                                 fprintf( fp, "%d", Monitor[i]->value );
501                         }
502                         fprintf( fp, "\n" );
503                         fclose(fp);
504                 }
505
506                 for (i=0; i<Num_monitors; i++ ) {
507
508                         // Record stats
509                         Monitor[i]->sum += Monitor[i]->value;
510
511                         if ( (Monitor[i]->cnt < 1)  || (Monitor[i]->value < Monitor[i]->min ))  {
512                                 Monitor[i]->min = Monitor[i]->value;
513                         }
514
515                         if ( (Monitor[i]->cnt < 1)  || (Monitor[i]->value > Monitor[i]->max ))  {
516                                 Monitor[i]->max = Monitor[i]->value;
517                         }
518
519                         Monitor[i]->cnt++;
520
521                         //      Reset the value
522                         Monitor[i]->value = 0;
523                 }
524         } else {
525                 for (i=0; i<Num_monitors; i++ ) {
526                         //      Reset the value
527                         Monitor[i]->value = 0;
528                 }
529         }
530
531         monitor_last_time = timer_get_fixed_seconds();
532
533 }
534 #endif  //NDEBUG
535
536
537 #if MAX_DETAIL_LEVEL != 4
538 #error MAX_DETAIL_LEVEL is assumed to be 4 in SystemVars.cpp
539 #endif
540
541 #if NUM_DEFAULT_DETAIL_LEVELS != 4
542 #error NUM_DEFAULT_DETAIL_LEVELS is assumed to be 4 in SystemVars.cpp
543 #endif
544
545 // Detail level stuff
546 detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
547 #ifdef MAKE_FS1
548         {                               // Low
549                 0,                      // setting
550                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
551                 0,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
552                 0,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest
553                 0,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
554                 0,                      //  weapon_detail;                              // 0=min number, MAX_DETAIL_LEVEL=max number
555                 0,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
556                 0,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
557                 0,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
558                 0,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
559                 1,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max
560                 0,                      // unknown_slider;
561
562                                         // ====  Booleans ====
563                 0,                      //      targetview_model;                       // 0=off, 1=on
564                 0,                      //      planets_suns;                           // 0=off, 1=on
565                 0,                      //  unknown_boolean1;
566                 0,                      //  unknown_boolean2;
567                 0,                      //  engine_glow;                                // 0=off, 1=on
568                 0,                      //  alpha_effects;                              // 0=off, 1=on
569         },
570         {                               // Medium
571                 1,                      // setting
572                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
573                 1,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
574                 1,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest
575                 1,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
576                 2,                      //  weapon_detail;                              // 0=min number, MAX_DETAIL_LEVEL=max number
577                 2,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
578                 2,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
579                 2,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
580                 1,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
581                 2,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max
582                 1,                      // unknown_slider;
583
584                                         // ====  Booleans ====
585                 1,                      //      targetview_model;                       // 0=off, 1=on
586                 1,                      //      planets_suns;                           // 0=off, 1=on
587                 1,                      //  unknown_boolean1;
588                 1,                      //  unknown_boolean2;
589                 1,                      //  engine_glow;                                // 0=off, 1=on
590                 0,                      //  alpha_effects;                              // 0=off, 1=on
591         },
592         {                               // High
593                 2,                      // setting
594                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
595                 2,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
596                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest
597                 2,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
598                 4,                      //  weapon_detail;                              // 0=min number, MAX_DETAIL_LEVEL=max number
599                 4,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
600                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
601                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
602                 2,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
603                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max
604                 2,                      // unknown_slider;
605
606                                         // ====  Booleans ====
607                 1,                      //      targetview_model;                       // 0=off, 1=on
608                 1,                      //      planets_suns;                           // 0=off, 1=on
609                 1,                      //  unknown_boolean1;
610                 1,                      //  unknown_boolean2;
611                 1,                      //  engine_glow;                                // 0=off, 1=on
612                 1,                      //  alpha_effects;                              // 0=off, 1=on
613         },
614         {                               // Highest
615                 3,                      // setting
616                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
617                 3,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
618                 4,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest
619                 3,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
620                 4,                      //  weapon_detail;                              // 0=min number, MAX_DETAIL_LEVEL=max number
621                 4,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
622                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
623                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
624                 4,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
625                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max
626                 4,                      // unknown_slider;
627
628                                         // ====  Booleans ====
629                 1,                      //      targetview_model;                       // 0=off, 1=on
630                 1,                      //      planets_suns;                           // 0=off, 1=on
631                 1,                      //  unknown_boolean1;
632                 1,                      //  unknown_boolean2;
633                 1,                      //  engine_glow;                                // 0=off, 1=on
634                 1,                      //  alpha_effects;                              // 0=off, 1=on
635         },
636 #else
637         {                               // Low
638                 0,                      // setting
639                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
640                 0,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
641                 0,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
642                 0,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
643                 0,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
644                 0,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
645                 0,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
646                 0,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
647                 2,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
648
649                                         // ====  Booleans ====
650                 0,                      //      targetview_model;                       // 0=off, 1=on          
651                 0,                      //      planets_suns;                           // 0=off, 1=on          
652                 0,                      // weapon_extras
653         },
654         {                               // Medium
655                 1,                      // setting
656                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
657                 1,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
658                 1,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
659                 1,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
660                 2,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
661                 2,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
662                 2,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
663                 1,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
664                 3,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
665
666                 // ====  Booleans ====
667                 1,                      //      targetview_model;                       // 0=off, 1=on          
668                 1,                      //      planets_suns;                           // 0=off, 1=on
669                 1,                      // weapon extras                                
670         },
671         {                               // High level
672                 2,                      // setting
673                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
674                 2,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
675                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
676                 3,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
677                 3,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
678                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
679                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
680                 3,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
681                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
682
683                                                                                 // ====  Booleans ====
684                 1,                      //      targetview_model;                       // 0=off, 1=on          
685                 1,                      //      planets_suns;                           // 0=off, 1=on
686                 1,                      // weapon_extras
687         },
688         {                               // Highest level
689                 3,                      // setting
690                                         // ===== Analogs (0-MAX_DETAIL_LEVEL) ====
691                 3,                      // nebula_detail;                               // 0=lowest detail, MAX_DETAIL_LEVEL=highest detail
692                 3,                      // detail_distance;                     // 0=lowest MAX_DETAIL_LEVEL=highest            
693                 4,                      //      hardware_textures;                      // 0=max culling, MAX_DETAIL_LEVEL=no culling
694                 4,                      //      num_small_debris;                       // 0=min number, MAX_DETAIL_LEVEL=max number
695                 3,                      //      num_particles;                          // 0=min number, MAX_DETAIL_LEVEL=max number
696                 4,                      //      num_stars;                                      // 0=min number, MAX_DETAIL_LEVEL=max number
697                 4,                      //      shield_effects;                 // 0=min, MAX_DETAIL_LEVEL=max
698                 4,                      // lighting;                                    // 0=min, MAX_DETAIL_LEVEL=max          
699
700                                                                                 // ====  Booleans ====
701                 1,                      //      targetview_model;                       // 0=off, 1=on          
702                 1,                      //      planets_suns;                           // 0=off, 1=on
703                 1,                      // weapon_extras
704         },
705 #endif
706 };
707
708
709 // Global used to access detail levels in game and libs
710 detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS-1];
711
712 // Call this with:
713 // 0 - lowest
714 // NUM_DETAIL_LEVELS - highest
715 // To set the parameters in Detail to some set of defaults
716 void detail_level_set(int level)
717 {
718         if ( level < 0 )        {
719                 Detail.setting = -1;
720                 return;
721         }
722         SDL_assert( level >= 0 );
723         SDL_assert( level < NUM_DEFAULT_DETAIL_LEVELS );
724
725         Detail = Detail_defaults[level];
726
727         // reset nebula stuff
728         neb2_set_detail_level(level);
729 }
730
731 // Returns the current detail level or -1 if custom.
732 int current_detail_level()
733 {
734 //      return Detail.setting;
735         int i;
736         int match = -1;
737
738         for (i=0; i<NUM_DEFAULT_DETAIL_LEVELS; i++ )    {
739                 if ( Detail.setting == -1 ) {
740                         // in the case of a custom detail level, return it's closest match
741 #ifdef MAKE_FS1
742                         if ( (Detail.nebula_detail >= Detail_defaults[i].nebula_detail) &&
743                                  (Detail.detail_distance >= Detail_defaults[i].detail_distance) &&
744                                  (Detail.weapon_detail >= Detail_defaults[i].weapon_detail) &&
745                                  (Detail.hardware_textures >= Detail_defaults[i].hardware_textures) &&
746                                  (Detail.shield_effects >= Detail_defaults[i].shield_effects) &&
747                                  (Detail.lighting >= Detail_defaults[i].lighting) &&
748                                  (Detail.planets_suns == Detail_defaults[i].planets_suns) &&
749                                  (Detail.engine_glows == Detail_defaults[i].engine_glows) &&
750                                  (Detail.alpha_effects == Detail_defaults[i].alpha_effects) )
751 #else
752                         if ( (Detail.nebula_detail >= Detail_defaults[i].nebula_detail) &&
753                                  (Detail.detail_distance >= Detail_defaults[i].detail_distance) &&
754                                  (Detail.hardware_textures >= Detail_defaults[i].hardware_textures) &&
755                                  (Detail.shield_effects >= Detail_defaults[i].shield_effects) &&
756                                  (Detail.lighting >= Detail_defaults[i].lighting) &&
757                                  (Detail.planets_suns == Detail_defaults[i].planets_suns) &&
758                                  (Detail.weapon_extras == Detail_defaults[i].weapon_extras) )
759 #endif
760                         {
761                                 match = i; // we will keep whatever the highest value is
762                         }
763                 } else if ( memcmp( &Detail, &Detail_defaults[i], sizeof(detail_levels) )==0 )  {
764                         return i;
765                 }
766         }
767
768         return match;
769 }
770
771 #ifndef NDEBUG
772 DCF(detail_level,"Change the detail level")
773 {
774         if ( Dc_command )       {
775                 dc_get_arg(ARG_INT|ARG_NONE);
776                 if ( Dc_arg_type & ARG_NONE )   {
777                         Game_detail_level = 0;
778                         dc_printf( "Detail level reset\n" );
779                 }
780                 if ( Dc_arg_type & ARG_INT )    {
781                         Game_detail_level = Dc_arg_int;
782                 }
783         }
784
785         if ( Dc_help )  
786                 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" );
787
788         if ( Dc_status )                                
789                 dc_printf("Detail level set to %d\n", Game_detail_level);
790 }
791
792 DCF(detail, "Turns on/off parts of the game for speed testing" )
793 {
794         if ( Dc_command )       {
795                 dc_get_arg(ARG_INT|ARG_NONE);
796                 if ( Dc_arg_type & ARG_NONE )   {
797                         if ( Game_detail_flags == DETAIL_DEFAULT )      {
798                                 Game_detail_flags = DETAIL_FLAG_CLEAR;
799                                 dc_printf( "Detail flags set lowest (except has screen clear)\n" );
800                         } else {
801                                 Game_detail_flags = DETAIL_DEFAULT;
802                                 dc_printf( "Detail flags set highest\n" );
803                         }
804                 }
805                 if ( Dc_arg_type & ARG_INT )    {
806                         Game_detail_flags ^= Dc_arg_int;
807                 }
808         }
809
810         if ( Dc_help )  {
811                 dc_printf( "Usage: detail [n]\nn is detail bit to toggle.\n" );
812                 dc_printf( "   1: draw the stars\n" );
813                 dc_printf( "   2: draw the nebulas\n" );
814                 dc_printf( "   4: draw the motion debris\n" );
815                 dc_printf( "   8: draw planets\n" );
816                 dc_printf( "  16: draw models not as blobs\n" );
817                 dc_printf( "  32: draw lasers not as pixels\n" );
818                 dc_printf( "  64: clear screen background after each frame\n" );
819                 dc_printf( " 128: draw hud stuff\n" );
820                 dc_printf( " 256: draw fireballs\n" );
821                 dc_printf( " 512: do collision detection\n" );
822         }
823
824         if ( Dc_status )        {
825                 dc_printf("Detail flags set to 0x%08x\n", Game_detail_flags);
826                 dc_printf( "   1: draw the stars: %s\n", (Game_detail_flags&1?"on":"off") );
827                 dc_printf( "   2: draw the nebulas: %s\n", (Game_detail_flags&2?"on":"off") );
828                 dc_printf( "   4: draw the motion debris: %s\n", (Game_detail_flags&4?"on":"off")  );
829                 dc_printf( "   8: draw planets: %s\n", (Game_detail_flags&8?"on":"off")  );
830                 dc_printf( "  16: draw models not as blobs: %s\n", (Game_detail_flags&16?"on":"off")  );
831                 dc_printf( "  32: draw lasers not as pixels: %s\n", (Game_detail_flags&32?"on":"off")  );
832                 dc_printf( "  64: clear screen background after each frame: %s\n", (Game_detail_flags&64?"on":"off")  );
833                 dc_printf( " 128: draw hud stuff: %s\n", (Game_detail_flags&128?"on":"off")  );
834                 dc_printf( " 256: draw fireballs: %s\n", (Game_detail_flags&256?"on":"off")  );
835                 dc_printf( " 512: do collision detection: %s\n", (Game_detail_flags&512?"on":"off")  );
836         }
837 }
838 #endif