]> icculus.org git repositories - taylor/freespace2.git/blob - src/starfield/starfield.cpp
warning cleanup
[taylor/freespace2.git] / src / starfield / starfield.cpp
1 /*
2  * $Logfile: /Freespace2/code/Starfield/StarField.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code to handle and draw starfields, background space image bitmaps, floating
8  * debris, etc.
9  *
10  * $Log$
11  * Revision 1.3  2002/06/02 04:26:34  relnev
12  * warning cleanup
13  *
14  * Revision 1.2  2002/05/07 03:16:52  theoddone33
15  * The Great Newline Fix
16  *
17  * Revision 1.1.1.1  2002/05/03 03:28:10  root
18  * Initial import.
19  *
20  * 
21  * 34    9/07/99 4:01p Dave
22  * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
23  * does everything properly (setting up address when binding). Remove
24  * black rectangle background from UI_INPUTBOX.
25  * 
26  * 33    9/01/99 10:14a Dave
27  * Pirate bob.
28  * 
29  * 32    8/30/99 5:01p Dave
30  * Made d3d do less state changing in the nebula. Use new chat server for
31  * PXO.
32  * 
33  * 31    8/19/99 10:59a Dave
34  * Packet loss detection.
35  * 
36  * 30    7/27/99 3:52p Dave
37  * Make star drawing a bit more robust to help lame D3D cards.
38  * 
39  * 29    7/21/99 8:10p Dave
40  * First run of supernova effect.
41  * 
42  * 28    7/13/99 2:01p Dave
43  * Don't draw background bitmaps in the nebula.
44  * 
45  * 27    6/08/99 2:34p Jasenw
46  * Made perspective bitmaps render in Fred.
47  * 
48  * 26    6/04/99 1:18p Dave
49  * Fixed briefing model rendering problems. Made show background option in
50  * fred toggle nebula rendering.
51  * 
52  * 25    6/03/99 6:37p Dave
53  * More TNT fun. Made perspective bitmaps more flexible.
54  * 
55  * 24    5/28/99 1:45p Dave
56  * Fixed up perspective bitmap drawing.
57  * 
58  * 23    5/20/99 7:00p Dave
59  * Added alternate type names for ships. Changed swarm missile table
60  * entries.
61  * 
62  * 22    5/11/99 10:03a Dave
63  * Put a bunch of stuff into tables.
64  * 
65  * 21    5/11/99 9:10a Dave
66  * Move default sun position.
67  * 
68  * 20    5/09/99 6:00p Dave
69  * Lots of cool new effects. E3 build tweaks.
70  * 
71  * 19    4/26/99 8:49p Dave
72  * Made all pof based nebula stuff full customizable through fred.
73  * 
74  * 18    4/25/99 7:43p Dave
75  * Misc small bug fixes. Made sun draw properly.
76  * 
77  * 17    4/23/99 5:53p Dave
78  * Started putting in new pof nebula support into Fred.
79  * 
80  * 16    4/07/99 6:22p Dave
81  * Fred and Freespace support for multiple background bitmaps and suns.
82  * Fixed link errors on all subprojects. Moved encrypt_init() to
83  * cfile_init() and lcl_init(), since its safe to call twice.
84  * 
85  * 15    3/31/99 8:24p Dave
86  * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
87  * and background nebulae. Added per-ship non-dimming pixel colors.
88  * 
89  * 14    3/20/99 5:09p Dave
90  * Fixed release build fred warnings and unhandled exception.
91  * 
92  * 13    3/20/99 3:46p Dave
93  * Added support for model-based background nebulae. Added 3 new
94  * sexpressions.
95  * 
96  * 12    3/20/99 2:04p Dave
97  * Removed unnecessary planet rendering.
98  * 
99  * 11    3/19/99 9:51a Dave
100  * Checkin to repair massive source safe crash. Also added support for
101  * pof-style nebulae, and some new weapons code.
102  * 
103  * 12    3/15/99 6:45p Daveb
104  * Put in rough nebula bitmap support.
105  * 
106  * 11    3/11/99 5:53p Dave
107  * More network optimization. Spliced in Dell OEM planet bitmap crap.
108  * 
109  * 10    2/03/99 11:44a Dave
110  * Fixed d3d transparent textures.
111  * 
112  * 9     12/09/98 7:34p Dave
113  * Cleanup up nebula effect. Tweaked many values.
114  * 
115  * 8     12/01/98 10:32a Johnson
116  * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
117  * starfield problem.
118  * 
119  * 7     12/01/98 8:06a Dave
120  * Temporary checkin to fix some texture transparency problems in d3d.
121  * 
122  * 6     11/14/98 5:33p Dave
123  * Lots of nebula work. Put in ship contrails.
124  * 
125  * 5     11/05/98 5:55p Dave
126  * Big pass at reducing #includes
127  * 
128  * 4     10/13/98 9:29a Dave
129  * Started neatening up freespace.h. Many variables renamed and
130  * reorganized. Added AlphaColors.[h,cpp]
131  * 
132  * 3     10/07/98 11:16a Dave
133  * Remove warning.
134  * 
135  * 2     10/07/98 10:54a Dave
136  * Initial checkin.
137  * 
138  * 1     10/07/98 10:51a Dave
139  * 
140  * 106   5/23/98 4:14p John
141  * Added code to preload textures to video card for AGP.   Added in code
142  * to page in some bitmaps that weren't getting paged in at level start.
143  * 
144  * 105   5/13/98 2:53p John
145  * Made subspace effect work under software.  Had to add new inner loop to
146  * tmapper.  Added glows to end of subspace effect.  Made subspace effect
147  * levels use gamepalette-subspace palette.
148  * 
149  * 104   5/13/98 10:28a John
150  * made subpsace forward sliding 40% faster.
151  * 
152  * 103   5/10/98 4:18p John
153  * Reversed the subspace effect direction
154  * 
155  * 102   5/08/98 8:38p John
156  * Subspace tweaks.  Made two layers rotate independentyl.  
157  * 
158  * 101   5/08/98 1:32p John
159  * Added code for using two layered subspace effects.
160  * 
161  * 100   5/06/98 5:30p John
162  * Removed unused cfilearchiver.  Removed/replaced some unused/little used
163  * graphics functions, namely gradient_h and _v and pixel_sp.   Put in new
164  * DirectX header files and libs that fixed the Direct3D alpha blending
165  * problems.
166  * 
167  * 99    4/22/98 4:09p John
168  * String externalization
169  * 
170  * 98    4/22/98 3:28p John
171  * Fixed XSTR bug
172  * 
173  * 97    4/13/98 4:54p John
174  * Made uv rotate independently on subspace effect. Put in DCF function
175  * for setting subspace speeds.
176  * 
177  * 96    4/12/98 5:55p John
178  * Made models work with subspace.  Made subspace rotate also.
179  * 
180  * 95    4/11/98 6:53p John
181  * Added first rev of subspace effect.
182  * 
183  * 94    4/08/98 11:31a Dave
184  * AL: Fix syntax error for non-demo
185  * 
186  * 93    4/08/98 10:46a Lawrance
187  * #ifdef out asteroid check for demo
188  * 
189  * 92    4/08/98 9:25a John
190  * Made asteroid missions not show suns
191  * 
192  * 91    4/07/98 4:17p John
193  * Made Fred be able to move suns.  Made suns actually affect the lighting
194  * in the game.
195  * 
196  * 90    4/07/98 11:19a Hoffoss
197  * Changed code to only use Sun01 for a bitmap by default, as John
198  * requested.
199  *
200  * $NoKeywords: $
201  */
202
203 #include "pstypes.h"
204 #include "floating.h"
205 #include "vecmat.h"
206 #include "3d.h"
207 #include "2d.h"
208 #include "starfield.h"
209 #include "bmpman.h"
210 #include "key.h"
211 #include "freespace.h"  
212 #include "timer.h"
213 #include "nebula.h"
214 #include "linklist.h"
215 #include "lighting.h"
216 #include "asteroid.h"
217 #include "missionparse.h"
218 #include "neb.h"
219 #include "alphacolors.h"
220 #include "supernova.h"
221
222 #define MAX_DEBRIS_VCLIPS       4
223 #define DEBRIS_ROT_MIN                          10000
224 #define DEBRIS_ROT_RANGE                        8
225 #define DEBRIS_ROT_RANGE_SCALER 10000
226 #define RND_MAX_MASK    0x3fff
227 #define HALF_RND_MAX 0x2000
228
229 typedef struct debris_vclip {
230         int     bm;
231         int     nframes;
232         char  *name;
233 } debris_vclip;
234
235 typedef struct {
236         vector pos;
237         vector last_pos;
238         int active;
239         int vclip;
240         float size;     
241 } old_debris;
242
243 const int MAX_DEBRIS = 200;
244 const int MAX_STARS = 2000;
245 const float MAX_DIST = 50.0f;
246 const float MAX_DIST_RANGE = 60.0f;
247 const float MIN_DIST_RANGE = 14.0f;
248 const float BASE_SIZE = 0.12f;
249 float BASE_SIZE_NEB = 0.5f;
250
251 static int Subspace_model_inner = -1;           
252 static int Subspace_model_outer = -1;           
253
254 int Num_stars = 500;
255 fix starfield_timestamp = 0;
256
257 // for drawing cool stuff on the background - comes from a table
258 starfield_bitmap Starfield_bitmaps[MAX_STARFIELD_BITMAPS];
259 starfield_bitmap_instance Starfield_bitmap_instance[MAX_STARFIELD_BITMAPS];
260 int Num_starfield_bitmaps = 0;
261
262 // sun bitmaps and sun glow bitmaps
263 starfield_bitmap Sun_bitmaps[MAX_STARFIELD_BITMAPS];
264 starfield_bitmap_instance Suns[MAX_STARFIELD_BITMAPS];
265 int Num_suns = 0;
266
267 int last_stars_filled = 0;
268 color star_colors[8];
269 color star_aacolors[8];
270
271 typedef struct star {
272         vector pos;
273         vector last_star_pos;
274 } star;
275
276 star Stars[MAX_STARS];
277
278 old_debris odebris[MAX_DEBRIS];
279
280 //XSTR:OFF
281 debris_vclip debris_vclips_normal[MAX_DEBRIS_VCLIPS] = { { -1, -1, "debris01" }, { -1, -1, "debris02" }, { -1, -1, "debris03" }, { -1, -1, "debris04" } };
282 debris_vclip debris_vclips_nebula[MAX_DEBRIS_VCLIPS] = { { -1, -1, "Neb01-64" }, { -1, -1, "Neb01-64" }, { -1, -1, "Neb01-64" }, { -1, -1, "Neb01-64" } };
283 debris_vclip *debris_vclips = debris_vclips_normal;
284 //XSTR:ON
285
286 int stars_debris_loaded = 0;
287
288 // background data
289 int Stars_background_inited = 0;                        // if we're inited
290 int Nmodel_num = -1;                                                    // model num
291 int Nmodel_bitmap = -1;                                         // model texture
292
293 // given a starfield_bitmap_instance, return a pointer to its parent, for suns
294 starfield_bitmap *stars_lookup_sun(starfield_bitmap_instance *s)
295 {
296         int idx;
297
298         // sanity
299         if(s == NULL){
300                 return NULL;
301         }
302
303         // lookup
304         for(idx=0; idx<MAX_STARFIELD_BITMAPS; idx++){
305                 if(!stricmp(Sun_bitmaps[idx].filename, s->filename)){
306                         return &Sun_bitmaps[idx];
307                 }
308         }
309
310         // no findy
311         return NULL;
312 }
313
314 void stars_load_debris()
315 {
316         int i;
317
318         // if we're in nebula mode
319         if(The_mission.flags & MISSION_FLAG_FULLNEB){
320                 debris_vclips = debris_vclips_nebula;
321         } else {
322                 debris_vclips = debris_vclips_normal;
323         }
324
325         for (i=0; i<MAX_DEBRIS_VCLIPS; i++ )    {
326                 debris_vclips[i].bm = bm_load_animation( debris_vclips[i].name, &debris_vclips[i].nframes, NULL, 1 );
327                 if ( debris_vclips[i].bm < 0 ) {
328                         // try loading it as a single bitmap
329                         debris_vclips[i].bm = bm_load(debris_vclips[i].name);
330                         debris_vclips[i].nframes = 1;
331
332                         if(debris_vclips[i].bm <= 0){
333                                 Error( LOCATION, "Couldn't load animation/bitmap '%s'\n", debris_vclips[i].name );
334                         }
335                 }
336         }
337         stars_debris_loaded = 1;
338 }
339
340 // call on game startup
341 void stars_init()
342 {
343         starfield_bitmap *bm;   
344         int count, idx;
345         char filename[MAX_FILENAME_LEN+1] = "";
346         char glow_filename[MAX_FILENAME_LEN+1] = "";
347         float r, g, b, i;
348
349         // parse stars.tbl
350         read_file_text("stars.tbl");
351         reset_parse();
352
353         // make all bitmaps invalid
354         for(idx=0; idx<MAX_STARFIELD_BITMAPS; idx++){
355                 Starfield_bitmaps[idx].bitmap = -1;
356                 Starfield_bitmaps[idx].glow_bitmap = -1;                
357                 strcpy(Starfield_bitmaps[idx].filename, "");
358                 strcpy(Starfield_bitmaps[idx].glow_filename, "");
359
360                 Sun_bitmaps[idx].bitmap = -1;           
361                 Sun_bitmaps[idx].glow_bitmap = -1;              
362                 strcpy(Sun_bitmaps[idx].filename, "");
363                 strcpy(Sun_bitmaps[idx].glow_filename, "");
364         }
365
366         // starfield bitmaps
367         count = 0;
368         while(!optional_string("#end")){
369                 // intensity alpha bitmap
370                 if(optional_string("$Bitmap:")){
371                         stuff_string(filename, F_NAME, NULL);
372                         if(count < MAX_STARFIELD_BITMAPS){
373                                 bm = &Starfield_bitmaps[count++];
374                                 strcpy(bm->filename, filename);
375                                 bm->xparent = 0;
376                                 bm->bitmap = bm_load(bm->filename);                             
377                                 Assert(bm->bitmap != -1);
378
379                                 // if fred is running we should lock the bitmap now
380                                 if(Fred_running && (bm->bitmap >= 0)){
381                                         bm_lock(bm->bitmap, 8, BMP_TEX_OTHER);
382                                         bm_unlock(bm->bitmap);
383                                 } 
384                         }
385                 }
386                 // green xparency bitmap
387                 else if(optional_string("$BitmapX:")){
388                         stuff_string(filename, F_NAME, NULL);
389                         if(count < MAX_STARFIELD_BITMAPS){
390                                 bm = &Starfield_bitmaps[count++];
391                                 strcpy(bm->filename, filename);
392                                 bm->xparent = 1;
393                                 bm->bitmap = bm_load(bm->filename);
394                                 Assert(bm->bitmap != -1);
395
396                                 // if fred is running we should lock as a 0, 255, 0 bitmap now
397                                 if(Fred_running && (bm->bitmap >= 0)){
398                                         bm_lock(bm->bitmap, 8, BMP_TEX_XPARENT);
399                                         bm_unlock(bm->bitmap);
400                                 } 
401                         }
402                 }
403         }
404
405         // sun bitmaps
406         count = 0;
407         while(!optional_string("#end")){
408                 if(optional_string("$Sun:")){
409                         stuff_string(filename, F_NAME, NULL);
410
411                         // associated glow
412                         required_string("$Sunglow:");
413                         stuff_string(glow_filename, F_NAME, NULL);
414
415                         // associated lighting values
416                         required_string("$SunRGBI:");
417                         stuff_float(&r);
418                         stuff_float(&g);
419                         stuff_float(&b);
420                         stuff_float(&i);
421
422                         if(count < MAX_STARFIELD_BITMAPS){
423                                 bm = &Sun_bitmaps[count++];
424                                 strcpy(bm->filename, filename);
425                                 strcpy(bm->glow_filename, glow_filename);
426                                 bm->xparent = 1;
427                                 bm->bitmap = bm_load(bm->filename);
428                                 bm->glow_bitmap = bm_load(bm->glow_filename);
429                                 Assert(bm->bitmap != -1);
430                                 Assert(bm->glow_bitmap != -1);
431                                 bm->r = r;
432                                 bm->g = g;
433                                 bm->b = b;
434                                 bm->i = i;
435
436                                 // if fred is running we should lock the bitmap now
437                                 if(Fred_running){
438                                         if(bm->bitmap >= 0){
439                                                 bm_lock(bm->bitmap, 8, BMP_TEX_OTHER);
440                                                 bm_unlock(bm->bitmap);
441                                         }
442                                         if(bm->glow_bitmap >= 0){
443                                                 bm_lock(bm->glow_bitmap, 8, BMP_TEX_OTHER);
444                                                 bm_unlock(bm->glow_bitmap);
445                                         }
446                                 } 
447                         }
448                 }
449         }       
450
451         // normal debris pieces
452         count = 0;
453         while(!optional_string("#end")){
454                 required_string("$Debris:");
455                 stuff_string(filename, F_NAME, NULL);
456
457                 if(count < MAX_DEBRIS_VCLIPS){
458                         strcpy(debris_vclips_normal[count++].name, filename);
459                 }
460         }
461         Assert(count == 4);
462
463         // nebula debris pieces
464         count = 0;
465         while(!optional_string("#end")){
466                 required_string("$DebrisNeb:");
467                 stuff_string(filename, F_NAME, NULL);
468
469                 if(count < MAX_DEBRIS_VCLIPS){
470                         strcpy(debris_vclips_nebula[count++].name, filename);
471                 }
472         }
473         Assert(count == 4);
474 }
475
476 // call this in game_post_level_init() so we know whether we're running in full nebula mode or not
477 void stars_level_init()
478 {
479         int i;
480         vector v;
481         float dist, dist_max;
482
483         // reset to -1 so we reload it each mission (if we need to)
484         Nmodel_num = -1;                
485         if(Nmodel_bitmap != -1){
486                 bm_unload(Nmodel_bitmap);
487                 Nmodel_bitmap = -1;
488         }
489
490         // if (!stars_debris_loaded){
491                 stars_load_debris();
492         // }
493
494 // following code randomly distributes star points within a sphere volume, which
495 // avoids there being denser areas along the edges and in corners that we had in the
496 // old rectangular distribution scheme.
497         dist_max = (float) (HALF_RND_MAX * HALF_RND_MAX);
498         for (i=0; i<MAX_STARS; i++) {
499                 dist = dist_max;
500                 while (dist >= dist_max) {
501                         v.x = (float) ((myrand() & RND_MAX_MASK) - HALF_RND_MAX);
502                         v.y = (float) ((myrand() & RND_MAX_MASK) - HALF_RND_MAX);
503                         v.z = (float) ((myrand() & RND_MAX_MASK) - HALF_RND_MAX);
504
505                         dist = v.x * v.x + v.y * v.y + v.z * v.z;
506                 }
507                 vm_vec_copy_normalize(&Stars[i].pos, &v);
508         }
509
510         for (i=0; i<MAX_DEBRIS; i++) {
511                 odebris[i].active = 0;
512         }
513
514         for (i=0; i<8; i++ )    {
515                 ubyte intensity = (ubyte)((i + 1) * 24);
516                 gr_init_alphacolor(&star_aacolors[i], 255, 255, 255, intensity, AC_TYPE_BLEND );
517                 gr_init_color(&star_colors[i], intensity, intensity, intensity );
518         }
519
520         last_stars_filled = 0;
521
522         // if we have no sun instances, create one
523         if(Num_suns <= 0){
524                 mprintf(("Adding default sun\n"));
525                 
526                 // stuff some values
527                 strcpy(Suns[0].filename, Sun_bitmaps[0].filename);
528                 Suns[0].scale_x = 1.0f;
529                 Suns[0].scale_y = 1.0f;
530                 Suns[0].div_x = 1;
531                 Suns[0].div_y = 1;
532                 memset(&Suns[0].ang, 0, sizeof(angles));
533                 Suns[0].ang.h = fl_radian(60.0f);
534
535                 // one sun
536                 Num_suns = 1;
537         }               
538 }
539
540
541 #include "object.h"
542 extern object * Player_obj;
543
544 #define STAR_AMOUNT_DEFAULT 0.75f
545 #define STAR_DIM_DEFAULT 7800.0f
546 #define STAR_CAP_DEFAULT 75.0f
547 #define STAR_MAX_LENGTH_DEFAULT 0.04f           // 312
548
549 float Star_amount = STAR_AMOUNT_DEFAULT;
550 float Star_dim = STAR_DIM_DEFAULT;
551 float Star_cap = STAR_CAP_DEFAULT;
552 float Star_max_length = STAR_MAX_LENGTH_DEFAULT;        
553
554 #define STAR_FLAG_TAIL                  (1<<0)  // Draw a tail when moving
555 #define STAR_FLAG_DIM                   (1<<1)  // Dim as you move
556 #define STAR_FLAG_ANTIALIAS     (1<<2)  // Draw the star using antialiased lines
557 #define STAR_FLAG_DEFAULT               (STAR_FLAG_TAIL | STAR_FLAG_DIM)
558
559 uint Star_flags = STAR_FLAG_DEFAULT;
560
561 //XSTR:OFF
562 DCF(stars,"Set parameters for starfield")
563 {
564         if ( Dc_command )       {
565                 dc_get_arg(ARG_STRING);
566                 if ( !strcmp( Dc_arg, "tail" )) {
567                         dc_get_arg(ARG_FLOAT);
568                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 1.0f) )   {
569                                 Dc_help = 1;
570                         } else {
571                                 Star_amount = Dc_arg_float;
572                         } 
573                 } else if ( !strcmp( Dc_arg, "len" ))   {
574                         dc_get_arg(ARG_FLOAT);
575                         Star_max_length = Dc_arg_float;
576                 } else if ( !strcmp( Dc_arg, "dim" ))   {
577                         dc_get_arg(ARG_FLOAT);
578                         if ( Dc_arg_float < 0.0f )      {
579                                 Dc_help = 1;
580                         } else {
581                                 Star_dim = Dc_arg_float;
582                         } 
583                 } else if ( !strcmp( Dc_arg, "flag" ))  {
584                         dc_get_arg(ARG_STRING);
585                         if ( !strcmp( Dc_arg, "tail" )) {
586                                 Star_flags ^= STAR_FLAG_TAIL;
587                         } else if ( !strcmp( Dc_arg, "dim" ))   {
588                                 Star_flags ^= STAR_FLAG_DIM;
589                         } else if ( !strcmp( Dc_arg, "aa" ))    {
590                                 Star_flags ^= STAR_FLAG_ANTIALIAS;
591                         } else {
592                                 Dc_help = 1;    
593                         }
594                 } else if ( !strcmp( Dc_arg, "cap" ))   {
595                         dc_get_arg(ARG_FLOAT);
596                         if ( (Dc_arg_float < 0.0f) || (Dc_arg_float > 255.0f) ) {
597                                 Dc_help = 1;
598                         } else {
599                                 Star_cap = Dc_arg_float;
600                         } 
601                 } else if ( !strcmp( Dc_arg, "m0" )  )  {
602                         Star_amount = 0.0f;
603                         Star_dim = 0.0f;
604                         Star_cap = 0.0f;
605                         Star_flags = 0;
606                         Star_max_length = STAR_MAX_LENGTH_DEFAULT;
607                 } else if ( !strcmp( Dc_arg, "m1" ) || !strcmp( Dc_arg, "default" ))    {
608                         Star_amount = STAR_AMOUNT_DEFAULT;
609                         Star_dim = STAR_DIM_DEFAULT;
610                         Star_cap = STAR_CAP_DEFAULT;
611                         Star_flags = STAR_FLAG_DEFAULT;
612                         Star_max_length = STAR_MAX_LENGTH_DEFAULT;
613                 } else if ( !strcmp( Dc_arg, "m2" ))    {
614                         Star_amount = 0.75f;
615                         Star_dim = 20.0f;
616                         Star_cap = 75.0f;
617                         Star_flags = STAR_FLAG_TAIL|STAR_FLAG_DIM|STAR_FLAG_ANTIALIAS;
618                         Star_max_length = STAR_MAX_LENGTH_DEFAULT;
619                 } else if ( !strcmp( Dc_arg, "num" ))   {
620                         dc_get_arg(ARG_INT);
621                         if ( (Dc_arg_int < 0) || (Dc_arg_int > MAX_STARS) )     {
622                                 Dc_help = 1;
623                         } else {
624                                 Num_stars = Dc_arg_int;
625                         } 
626                 } else {
627                         // print usage, not stats
628                         Dc_help = 1;
629                 }
630         }
631
632         if ( Dc_help )  {
633                 dc_printf( "Usage: stars keyword\nWhere keyword can be in the following forms:\n" );
634                 dc_printf( "stars default   Resets stars to all default values\n" );
635                 dc_printf( "stars num X     Sets number of stars to X.  Between 0 and %d.\n", MAX_STARS );
636                 dc_printf( "stars tail X    Where X is the percent of 'tail' between 0 and 1.0\n" );
637                 dc_printf( "stars dim X     Where X is the amount stars dim between 0 and 255.0\n" );
638                 dc_printf( "stars cap X     Where X is the cap of dimming between 0 and 255.\n" );
639                 dc_printf( "stars len X     Where X is the cap of length.\n" );
640                 dc_printf( "stars m0        Macro0. Old 'pixel type' crappy stars. flags=none\n" );
641                 dc_printf( "stars m1        Macro1. (default) tail=.75, dim=20.0, cap=75.0, flags=dim,tail\n" );
642                 dc_printf( "stars m2        Macro2. tail=.75, dim=20.0, cap=75.0, flags=dim,tail,aa\n" );
643                 dc_printf( "stars flag X    Toggles flag X, where X is tail or dim or aa (aa=antialias)\n" );
644                 dc_printf( "\nHINT: set cap to 0 to get dim rate and tail down, then use\n" );
645                 dc_printf( "cap to keep the lines from going away when moving too fast.\n" );
646                 dc_printf( "\nUse '? stars' to see current values.\n" );
647                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
648         }
649
650         if ( Dc_status )        {
651                 dc_printf( "Num_stars: %d\n", Num_stars );
652                 dc_printf( "Tail: %.2f\n", Star_amount );
653                 dc_printf( "Dim: %.2f\n", Star_dim );
654                 dc_printf( "Cap: %.2f\n", Star_cap );
655                 dc_printf( "Max length: %.2f\n", Star_max_length );
656                 dc_printf( "Flags:\n" );
657                 dc_printf( "  Tail: %s\n", (Star_flags&STAR_FLAG_TAIL?"On":"Off") );
658                 dc_printf( "  Dim: %s\n", (Star_flags&STAR_FLAG_DIM?"On":"Off") );
659                 dc_printf( "  Antialias: %s\n", (Star_flags&STAR_FLAG_ANTIALIAS?"On":"Off") );
660                 dc_printf( "\nTHESE AREN'T SAVED TO DISK, SO IF YOU TWEAK\n" );
661                 dc_printf( "THESE AND LIKE THEM, WRITE THEM DOWN!!\n" );
662         }
663 }
664 //XSTR:ON
665
666 int reload_old_debris = 1;              // If set to one, then reload all the last_pos of the debris
667
668 // Call this if camera "cuts" or moves long distances
669 // so blur effect doesn't draw lines all over the screen.
670 void stars_camera_cut()
671 {
672         last_stars_filled = 0;
673         reload_old_debris = 1;
674 }
675
676 //#define TIME_STAR_CODE                // enable to time star code
677
678 extern int Sun_drew;
679 extern float Viewer_zoom;
680
681 // get the world coords of the sun pos on the unit sphere.
682 void stars_get_sun_pos(int sun_n, vector *pos)
683 {
684         vector temp;
685         matrix rot;
686
687         // sanity
688         Assert(sun_n < Num_suns);
689         if((sun_n >= Num_suns) || (sun_n < 0)){
690                 return;
691         }
692
693         // rotate the sun properly
694         temp = vmd_zero_vector;
695         temp.z = 1.0f;
696         
697         // rotation matrix
698         vm_angles_2_matrix(&rot, &Suns[sun_n].ang);
699         vm_vec_rotate(pos, &temp, &rot);
700 }
701
702 // draw sun
703 void stars_draw_sun( int show_sun )
704 {       
705         int idx;
706         vector sun_pos;
707         vector sun_dir;
708         vertex sun_vex; 
709         starfield_bitmap *bm;
710         float local_scale = 1.0f;
711
712         // no suns drew yet
713         Sun_drew = 0;
714
715         // draw all suns
716         for(idx=0; idx<Num_suns; idx++){                
717                 // get the instance
718                 bm = stars_lookup_sun(&Suns[idx]);
719                 if(bm == NULL){
720                         continue;
721                 }
722
723                 // get sun pos
724                 sun_pos = vmd_zero_vector;
725                 sun_pos.y = 1.0f;
726                 stars_get_sun_pos(idx, &sun_pos);
727                 
728                 // get the direction            
729                 sun_dir = sun_pos;
730                 vm_vec_normalize(&sun_dir);
731
732                 // add the light source corresponding to the sun
733                 light_add_directional(&sun_dir, bm->i, bm->r, bm->g, bm->b);
734
735                 // if supernova
736                 if(supernova_active()){
737                         local_scale = 1.0f + (SUPERNOVA_SUN_SCALE * supernova_pct_complete());
738                 }
739
740                 // draw the sun itself, keep track of how many we drew
741                 gr_set_bitmap(bm->bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.999f);
742                 g3_rotate_faraway_vertex(&sun_vex, &sun_pos);
743                 if(!g3_draw_bitmap(&sun_vex, 0, 0.05f * Suns[idx].scale_x * local_scale, TMAP_FLAG_TEXTURED)){
744                         Sun_drew++;
745                 }
746         }
747 }
748
749 // draw the corresponding glow for sun_n
750 void stars_draw_sun_glow(int sun_n)
751 {
752         starfield_bitmap *bm;           
753         vector sun_pos, sun_dir;
754         vertex sun_vex; 
755         float local_scale = 1.0f;
756
757         // sanity
758         Assert(sun_n < Num_suns);
759         if((sun_n >= Num_suns) || (sun_n < 0)){
760                 return;
761         }
762
763         // get the instance
764         bm = stars_lookup_sun(&Suns[sun_n]);
765         if(bm == NULL){
766                 return;
767         }
768
769         // get sun pos
770         sun_pos = vmd_zero_vector;
771         sun_pos.y = 1.0f;
772         stars_get_sun_pos(sun_n, &sun_pos);     
773
774         // get the direction            
775         sun_dir = sun_pos;
776         vm_vec_normalize(&sun_dir);     
777
778         // if supernova
779         if(supernova_active()){
780                 local_scale = 1.0f + (SUPERNOVA_SUN_SCALE * supernova_pct_complete());
781         }
782
783         // draw the sun itself, keep track of how many we drew
784         gr_set_bitmap(bm->glow_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.5f);
785         g3_rotate_faraway_vertex(&sun_vex, &sun_pos);
786         g3_draw_bitmap(&sun_vex, 0, 0.10f * Suns[sun_n].scale_x * local_scale, TMAP_FLAG_TEXTURED);     
787 }
788
789 // draw bitmaps
790 void stars_draw_bitmaps( int show_bitmaps )
791 {
792         int idx;
793         int star_index; 
794
795         // if we're in the nebula, don't render any backgrounds
796         if(The_mission.flags & MISSION_FLAG_FULLNEB){
797                 return;
798         }
799
800         // detail settings
801         if(!Detail.planets_suns){
802                 return;
803         }
804         
805         // render all bitmaps
806         for(idx=0; idx<Num_starfield_bitmaps; idx++){
807                 // lookup the info index
808                 star_index = stars_find_bitmap(Starfield_bitmap_instance[idx].filename);
809                 if(star_index < 0){
810                         continue;
811                 }
812         
813                 // set the bitmap                               
814                 if(Fred_running){
815                         gr_set_bitmap(Starfield_bitmaps[star_index].bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.9999f);              
816                         g3_draw_perspective_bitmap(&Starfield_bitmap_instance[idx].ang, Starfield_bitmap_instance[idx].scale_x, Starfield_bitmap_instance[idx].scale_y, Starfield_bitmap_instance[idx].div_x, Starfield_bitmap_instance[idx].div_y, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT);
817                 } else {
818                         if(Starfield_bitmaps[star_index].xparent){
819                                 gr_set_bitmap(Starfield_bitmaps[star_index].bitmap);            
820                                 g3_draw_perspective_bitmap(&Starfield_bitmap_instance[idx].ang, Starfield_bitmap_instance[idx].scale_x, Starfield_bitmap_instance[idx].scale_y, Starfield_bitmap_instance[idx].div_x, Starfield_bitmap_instance[idx].div_y, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT | TMAP_FLAG_XPARENT);
821                         } else {                                
822                                 gr_set_bitmap(Starfield_bitmaps[star_index].bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.9999f);              
823                                 g3_draw_perspective_bitmap(&Starfield_bitmap_instance[idx].ang, Starfield_bitmap_instance[idx].scale_x, Starfield_bitmap_instance[idx].scale_y, Starfield_bitmap_instance[idx].div_x, Starfield_bitmap_instance[idx].div_y, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT);
824                         }
825                 }
826         }
827 }
828
829 /*
830 void calculate_bitmap_matrix(starfield_bitmaps *bm, vector *v)
831 {
832         vm_vector_2_matrix(&bm->m, v, NULL, NULL);
833         vm_orthogonalize_matrix(&bm->m);
834 }
835
836 void calculate_bitmap_points(starfield_bitmaps *bm, float bank)
837 {
838         int i;
839         vector fvec, uvec, rvec, tmp;
840         angles tangles;
841
842         vm_orthogonalize_matrix(&bm->m);
843         if (bank) {
844                 tangles.p = tangles.h = 0.0f;
845                 tangles.b = bank;
846                 vm_rotate_matrix_by_angles(&bm->m, &tangles);
847         }
848
849         fvec = bm->m.fvec;
850         vm_vec_scale(&fvec, bm->dist );
851         uvec = bm->m.uvec;
852         rvec = bm->m.rvec;
853
854         vm_vec_sub(&tmp, &fvec, &uvec);
855         vm_vec_sub(&bm->points[3], &tmp, &rvec);
856
857         vm_vec_sub(&tmp, &fvec, &uvec);
858         vm_vec_add(&bm->points[2], &tmp, &rvec);
859
860         vm_vec_add(&tmp, &fvec, &uvec);
861         vm_vec_add(&bm->points[1], &tmp, &rvec);
862
863         vm_vec_add(&tmp, &fvec, &uvec);
864         vm_vec_sub(&bm->points[0], &tmp, &rvec);
865
866         for (i=0; i<4; i++){
867                 vm_vec_normalize(&bm->points[i]);
868         }
869 }
870 */
871
872 extern int Interp_subspace;
873 extern float Interp_subspace_offset_u;
874 extern float Interp_subspace_offset_u;
875 extern float Interp_subspace_offset_v;
876
877 float subspace_offset_u = 0.0f;
878 float subspace_offset_u_inner = 0.0f;
879 float subspace_offset_v = 0.0f;
880
881 float subspace_u_speed = 0.07f;                 // how fast u changes
882 float subspace_v_speed = 0.05f;                 // how fast v changes
883
884 int Subspace_glow_bitmap = -1;
885
886 float Subspace_glow_frame = 0.0f;
887 float Subspace_glow_rate = 1.0f;
888
889
890 //XSTR:OFF
891 DCF(subspace_set,"Set parameters for subspace effect")
892 {
893         if ( Dc_command )       {
894                 dc_get_arg(ARG_STRING);
895                 if ( !strcmp( Dc_arg, "u" ))    {
896                         dc_get_arg(ARG_FLOAT);
897                         if ( Dc_arg_float < 0.0f )      {
898                                 Dc_help = 1;
899                         } else {
900                                 subspace_u_speed = Dc_arg_float;
901                         } 
902                 } else if ( !strcmp( Dc_arg, "v" ))     {
903                         dc_get_arg(ARG_FLOAT);
904                         if ( Dc_arg_float < 0.0f )      {
905                                 Dc_help = 1;
906                         } else {
907                                 subspace_v_speed = Dc_arg_float;
908                         } 
909                 } else {
910                         // print usage, not stats
911                         Dc_help = 1;
912                 }
913         }
914
915         if ( Dc_help )  {
916                 dc_printf( "Usage: subspace keyword\nWhere keyword can be in the following forms:\n" );
917                 dc_printf( "subspace u X    Where X is how fast u moves.\n", MAX_STARS );
918                 dc_printf( "subspace v X    Where X is how fast v moves.\n" );
919                 dc_printf( "\nUse '? subspace' to see current values.\n" );
920                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
921         }
922
923         if ( Dc_status )        {
924                 dc_printf( "u: %.2f\n", subspace_u_speed );
925                 dc_printf( "v: %.2f\n", subspace_v_speed );
926         }
927 }
928 //XSTR:ON
929
930 void subspace_render()
931 {
932         if ( Subspace_model_inner == -1 )       {
933                 Subspace_model_inner = model_load( "subspace_small.pof", 0, NULL );
934                 Assert(Subspace_model_inner>-1);
935         }
936
937         if ( Subspace_model_outer == -1 )       {
938                 Subspace_model_outer = model_load( "subspace_big.pof", 0, NULL );
939                 Assert(Subspace_model_outer>-1);
940         }
941
942         if ( Subspace_glow_bitmap == -1 )       {
943                 Subspace_glow_bitmap = bm_load( NOX("SunGlow01"));
944                 Assert(Subspace_glow_bitmap>-1);
945         }
946
947         Subspace_glow_frame += flFrametime * 1.0f;
948
949         float total_time = i2fl(NOISE_NUM_FRAMES) / 15.0f;
950
951         // Sanity checks
952         if ( Subspace_glow_frame < 0.0f )       Subspace_glow_frame = 0.0f;
953         if ( Subspace_glow_frame > 100.0f ) Subspace_glow_frame = 0.0f;
954
955         while ( Subspace_glow_frame > total_time )      {
956                 Subspace_glow_frame -= total_time;
957         }
958         int framenum = fl2i( (Subspace_glow_frame*NOISE_NUM_FRAMES) / total_time );
959         if ( framenum < 0 ) framenum = 0;
960         if ( framenum >= NOISE_NUM_FRAMES ) framenum = NOISE_NUM_FRAMES-1;
961
962         subspace_offset_u += flFrametime*subspace_u_speed;
963         if (subspace_offset_u > 1.0f )  {
964                 subspace_offset_u -= 1.0f;
965         }
966
967         subspace_offset_u_inner += flFrametime*subspace_u_speed*3.0f;
968         if (subspace_offset_u > 1.0f )  {
969                 subspace_offset_u -= 1.0f;
970         }
971
972         subspace_offset_v += flFrametime*subspace_v_speed;
973         if (subspace_offset_v > 1.0f )  {
974                 subspace_offset_v -= 1.0f;
975         }
976
977         
978
979         matrix tmp;
980         angles angs = { 0.0f, 0.0f, 0.0f };
981         angs.b = subspace_offset_v * PI2;
982         
983         vm_angles_2_matrix(&tmp,&angs);
984         
985         int saved_gr_zbuffering =       gr_zbuffer_get();
986
987         gr_zbuffer_set(GR_ZBUFF_NONE);
988
989         if ( !D3D_enabled )     {
990
991                 int render_flags = MR_NO_LIGHTING | MR_ALWAYS_REDRAW;
992
993                 Interp_subspace = 1;    
994                 Interp_subspace_offset_u = 1.0f - subspace_offset_u;
995                 Interp_subspace_offset_v = 0.0f;
996
997                 model_set_thrust( Subspace_model_inner, 1.0f, -1, Subspace_glow_bitmap, Noise[framenum] );
998                 render_flags |= MR_SHOW_THRUSTERS;
999                 model_render( Subspace_model_outer, &tmp, &Eye_position, render_flags );        //MR_NO_CORRECT|MR_SHOW_OUTLINE 
1000
1001         } else {
1002
1003                 int render_flags = MR_NO_LIGHTING | MR_ALWAYS_REDRAW;
1004
1005                 Interp_subspace = 1;    
1006                 Interp_subspace_offset_u = 1.0f - subspace_offset_u;
1007                 Interp_subspace_offset_v = 0.0f;
1008
1009                 model_set_thrust( Subspace_model_inner, 1.0f, -1, Subspace_glow_bitmap, Noise[framenum] );
1010                 render_flags |= MR_SHOW_THRUSTERS;
1011                 model_render( Subspace_model_outer, &tmp, &Eye_position, render_flags );        //MR_NO_CORRECT|MR_SHOW_OUTLINE 
1012                 
1013                 Interp_subspace = 1;    
1014                 Interp_subspace_offset_u = 1.0f - subspace_offset_u_inner;
1015                 Interp_subspace_offset_v = 0.0f;        
1016
1017                 angs.b = -subspace_offset_v * PI2;
1018
1019                 vm_angles_2_matrix(&tmp,&angs);
1020
1021                 model_set_outline_color(255,255,255);
1022
1023                 model_set_thrust( Subspace_model_inner, 1.0f, -1, Subspace_glow_bitmap, Noise[framenum] );
1024                 render_flags |= MR_SHOW_THRUSTERS;
1025
1026                 model_render( Subspace_model_inner, &tmp, &Eye_position, render_flags  );       //MR_NO_CORRECT|MR_SHOW_OUTLINE 
1027         }
1028
1029         Interp_subspace = 0;
1030         gr_zbuffer_set(saved_gr_zbuffering);
1031 }
1032
1033 void stars_draw( int show_stars, int show_suns, int show_nebulas, int show_subspace )
1034 {
1035         int i;
1036         float vdist;
1037
1038
1039         int gr_zbuffering_save = gr_zbuffer_get();
1040         gr_zbuffer_set(GR_ZBUFF_NONE);
1041
1042         if ( show_subspace )    {
1043                 subspace_render();
1044         }
1045
1046         
1047         if (Num_stars >= MAX_STARS){
1048                 Num_stars = MAX_STARS;
1049         }
1050
1051 #ifdef TIME_STAR_CODE
1052         fix xt1, xt2;
1053         xt1 = timer_get_fixed_seconds();
1054 #endif
1055         
1056         if ( show_nebulas && (Game_detail_flags & DETAIL_FLAG_NEBULAS) && (Neb2_render_mode != NEB2_RENDER_POF) && (Neb2_render_mode != NEB2_RENDER_LAME))      {
1057                 nebula_render();
1058         }
1059
1060         // draw background stuff        
1061         if((Neb2_render_mode != NEB2_RENDER_POLY) && (Neb2_render_mode != NEB2_RENDER_LAME) && show_stars){
1062                 // semi-hack, do we don't fog the background
1063                 int neb_save = Neb2_render_mode;
1064                 Neb2_render_mode = NEB2_RENDER_NONE;
1065                 extern void stars_draw_background();
1066                 stars_draw_background();
1067                 Neb2_render_mode = neb_save;
1068         }
1069
1070         if (show_stars && ( Game_detail_flags & DETAIL_FLAG_STARS) && !(The_mission.flags & MISSION_FLAG_FULLNEB) && (supernova_active() < 3))  {
1071                 //Num_stars = 1;
1072         
1073                 star *sp;
1074
1075                 if ( !last_stars_filled )       {
1076                         for (sp=Stars,i=0; i<Num_stars; i++, sp++ ) {
1077                                 vertex p2;
1078                                 g3_rotate_faraway_vertex(&p2, &sp->pos);
1079                                 sp->last_star_pos.x = p2.x;
1080                                 sp->last_star_pos.y = p2.y;
1081                                 sp->last_star_pos.z = p2.z;
1082                         }
1083                 }
1084
1085                 int tmp_num_stars;
1086
1087                 tmp_num_stars = (Detail.num_stars*Num_stars)/MAX_DETAIL_LEVEL;
1088                 if (tmp_num_stars < 0 ) {
1089                         tmp_num_stars = 0;
1090                 } else if ( tmp_num_stars > Num_stars ) {
1091                         tmp_num_stars = Num_stars;
1092                 }
1093                 
1094                 for (sp=Stars,i=0; i<tmp_num_stars; i++, sp++ ) {
1095                         vertex p1, p2;                  
1096                         int can_draw = 1;                       
1097
1098                         memset(&p1, 0, sizeof(vertex));
1099
1100                         // This makes a star look "proper" by not translating the
1101                         // point around the viewer's eye before rotation.  In other
1102                         // words, when the ship translates, the stars do not change.
1103
1104                         g3_rotate_faraway_vertex(&p2, &sp->pos);
1105                         if ( p2.codes ) {
1106                                 can_draw = 0;
1107                         } else {
1108                                 g3_project_vertex(&p2);
1109                                 if ( p2.flags & PF_OVERFLOW )   {
1110                                         can_draw = 0;
1111                                 }
1112                         }
1113
1114                         float dist = 0.0f;
1115
1116                         if ( can_draw && (Star_flags & (STAR_FLAG_TAIL|STAR_FLAG_DIM)) )        {
1117
1118                                 dist = vm_vec_dist_quick( &sp->last_star_pos, (vector *)&p2.x );
1119
1120                                 float ratio;
1121                                 if ( dist > Star_max_length )   {
1122                                         ratio = Star_max_length / dist;
1123                                         dist = Star_max_length;
1124                                 } else {
1125                                         ratio = 1.0f;
1126                                 }
1127                                 ratio *= Star_amount;
1128
1129                                 p1.x = p2.x + (sp->last_star_pos.x-p2.x)*ratio;
1130                                 p1.y = p2.y + (sp->last_star_pos.y-p2.y)*ratio;
1131                                 p1.z = p2.z + (sp->last_star_pos.z-p2.z)*ratio;
1132
1133                                 p1.flags = 0;   // not projected
1134                                 g3_code_vertex( &p1 );
1135
1136                                 if ( p1.codes ) {
1137                                         can_draw = 0;
1138                                 } else {
1139                                         g3_project_vertex(&p1);
1140                                         if ( p1.flags & PF_OVERFLOW )   {
1141                                                 can_draw = 0;
1142                                         }
1143                                 }
1144                         }
1145
1146                         sp->last_star_pos.x = p2.x;
1147                         sp->last_star_pos.y = p2.y;
1148                         sp->last_star_pos.z = p2.z;
1149
1150                         if ( !can_draw )        continue;
1151
1152                         int color;
1153
1154                         if ( Star_flags & STAR_FLAG_DIM )       {
1155
1156                                 float colorf = 255.0f - dist*Star_dim;
1157
1158                                 if ( colorf < Star_cap )
1159                                         colorf = Star_cap;
1160
1161                                 color = (fl2i(colorf)*(i&7))/256;
1162
1163                         } else {
1164                                 color = i & 7;
1165                         }
1166
1167                         if ( (Star_flags & STAR_FLAG_ANTIALIAS) || (D3D_enabled) )      {
1168                                 gr_set_color_fast( &star_aacolors[color] );
1169
1170                                 // if the two points are the same, fudge it, since some D3D cards (G200 and G400) are lame.                             
1171                                 if( (fl2i(p1.sx) == fl2i(p2.sx)) && (fl2i(p1.sy) == fl2i(p2.sy)) ){                                     
1172                                         p1.sx += 1.0f;
1173                                 }                                                               
1174                                 gr_aaline(&p1,&p2);
1175                         } else {
1176                                 // use alphablended line so that dark stars don't look bad on top of nebulas
1177                                 gr_set_color_fast( &star_aacolors[color] );
1178                                 if ( Star_flags & STAR_FLAG_TAIL )      {
1179                                         gr_line(fl2i(p1.sx),fl2i(p1.sy),fl2i(p2.sx),fl2i(p2.sy));
1180                                 } else {
1181                                         gr_pixel( fl2i(p2.sx),fl2i(p2.sy) );
1182                                 }
1183                         }
1184                 }
1185         }
1186
1187         last_stars_filled = 1;
1188
1189 #ifdef TIME_STAR_CODE
1190         xt2 = timer_get_fixed_seconds();
1191         mprintf(( "Stars: %d\n", xt2-xt1 ));
1192 #endif
1193         
1194
1195         if ( (Game_detail_flags & DETAIL_FLAG_MOTION) && (!Fred_running) && (supernova_active() < 3) )  {
1196
1197                 gr_set_color( 0, 0, 0 );
1198
1199                 // turn off fogging
1200                 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1201                         gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
1202                 }
1203
1204                 old_debris * d = odebris; 
1205                 for (i=0; i<MAX_DEBRIS; i++, d++ ) {
1206                         vertex p;
1207
1208                         if (!d->active) {
1209                                 d->pos.x = f2fl(myrand() - RAND_MAX/2);
1210                                 d->pos.y = f2fl(myrand() - RAND_MAX/2);
1211                                 d->pos.z = f2fl(myrand() - RAND_MAX/2);
1212
1213                                 vm_vec_normalize(&d->pos);
1214
1215                                 vm_vec_scale(&d->pos, MAX_DIST);
1216                                 vm_vec_add2(&d->pos, &Eye_position );
1217 //                              vm_vec_add2(&d->pos, &Player_obj->pos );
1218                                 d->active = 1;
1219                                 d->vclip = i % MAX_DEBRIS_VCLIPS;       //rand()
1220
1221                                 // if we're in full neb mode
1222                                 if((The_mission.flags & MISSION_FLAG_FULLNEB) && (Neb2_render_mode != NEB2_RENDER_NONE)){
1223                                         d->size = i2fl(myrand() % 4)*BASE_SIZE_NEB;
1224                                 } else {
1225                                         d->size = i2fl(myrand() % 4)*BASE_SIZE;
1226                                 }
1227
1228                                 vm_vec_sub( &d->last_pos, &d->pos, &Eye_position );
1229                         }
1230
1231                         if ( reload_old_debris )        {
1232                                 vm_vec_sub( &d->last_pos, &d->pos, &Eye_position );
1233                         }
1234                         
1235                         g3_rotate_vertex(&p, &d->pos);
1236
1237                         if (p.codes == 0) {
1238                                 int frame = Missiontime / (DEBRIS_ROT_MIN + (i % DEBRIS_ROT_RANGE) * DEBRIS_ROT_RANGE_SCALER);
1239                                 frame %= debris_vclips[d->vclip].nframes;
1240
1241                                 if((The_mission.flags & MISSION_FLAG_FULLNEB) && (Neb2_render_mode != NEB2_RENDER_NONE)){
1242                                         gr_set_bitmap( debris_vclips[d->vclip].bm + frame, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.3f);  
1243                                 } else {
1244                                         gr_set_bitmap( debris_vclips[d->vclip].bm + frame );                                            
1245                                 }
1246                                         
1247                                 vector tmp;
1248                                 vm_vec_add( &tmp, &d->last_pos, &Eye_position );
1249                                 g3_draw_laser( &d->pos,d->size,&tmp,d->size, TMAP_FLAG_TEXTURED|TMAP_FLAG_XPARENT, 25.0f );                                     
1250                         }
1251
1252                         vm_vec_sub( &d->last_pos, &d->pos, &Eye_position );
1253
1254                         vdist = vm_vec_mag_quick(&d->last_pos);
1255
1256                         if (vdist > MAX_DIST_RANGE)
1257                                 d->active = 0;
1258                         else if (vdist < MIN_DIST_RANGE)
1259                                 d->active = 0;
1260
1261         //              vector tmp;
1262         //              vm_vec_sub( &tmp, &d->pos, &Player_obj->pos );
1263         //              vdist = vm_vec_dot( &tmp, &Player_obj->orient.fvec );
1264         //              if ( vdist < 0.0f )
1265         //                      d->active = 0;
1266
1267                 }
1268
1269                 reload_old_debris = 0;
1270         }
1271
1272
1273         stars_draw_sun( show_suns );    
1274         stars_draw_bitmaps( show_suns );
1275
1276         gr_zbuffer_set( gr_zbuffering_save );
1277 }
1278
1279 void stars_page_in()
1280 {
1281         int i, j;
1282
1283         // Initialize the subspace stuff
1284
1285         if ( Game_subspace_effect )     {
1286
1287                 Subspace_model_inner = model_load( "subspace_small.pof", 0, NULL );
1288                 Assert(Subspace_model_inner>-1);
1289                 Subspace_model_outer = model_load( "subspace_big.pof", 0, NULL );
1290                 Assert(Subspace_model_outer>-1);
1291
1292                 polymodel *pm;
1293                 
1294                 pm = model_get(Subspace_model_inner);
1295                 
1296                 nprintf(( "Paging", "Paging in textures for subspace effect.\n" ));
1297
1298                 for (j=0; j<pm->n_textures; j++ )       {
1299                         int bitmap_num = pm->original_textures[j];
1300
1301                         if ( bitmap_num > -1 )  {
1302                                 bm_page_in_texture( bitmap_num );
1303                         }
1304                 }
1305
1306                 pm = model_get(Subspace_model_outer);
1307                 
1308                 nprintf(( "Paging", "Paging in textures for subspace effect.\n" ));
1309
1310                 for (j=0; j<pm->n_textures; j++ )       {
1311                         int bitmap_num = pm->original_textures[j];
1312
1313                         if ( bitmap_num > -1 )  {
1314                                 bm_page_in_texture( bitmap_num );
1315                         }
1316                 }
1317         } else {
1318                 Subspace_model_inner = -1;
1319                 Subspace_model_outer = -1;
1320         }
1321
1322         Subspace_glow_bitmap = bm_load( NOX("SunGlow01"));
1323         bm_page_in_xparent_texture(Subspace_glow_bitmap);
1324
1325         // page in starfield bitmaps
1326         int idx;
1327         idx = 0;
1328         while((idx < MAX_STARFIELD_BITMAPS) && (Starfield_bitmaps[idx].bitmap != -1)){  
1329                 if(Starfield_bitmaps[idx].xparent){
1330                         bm_page_in_xparent_texture(Starfield_bitmaps[idx].bitmap);
1331                 } else { 
1332                         bm_page_in_texture(Starfield_bitmaps[idx].bitmap);
1333                 }
1334
1335                 // next;
1336                 idx++;
1337         }
1338
1339         // sun bitmaps and glows
1340         idx = 0;
1341         while((idx < MAX_STARFIELD_BITMAPS) && (Sun_bitmaps[idx].bitmap != -1) && (Sun_bitmaps[idx].glow_bitmap != -1)){
1342                 bm_page_in_texture(Sun_bitmaps[idx].bitmap);
1343                 bm_page_in_texture(Sun_bitmaps[idx].glow_bitmap);
1344
1345                 // next 
1346                 idx++;
1347         }
1348
1349         for (i=0; i<MAX_DEBRIS_VCLIPS; i++ )    {
1350                 for (j=0; j<debris_vclips[i].nframes; j++ )     {
1351                         bm_page_in_xparent_texture(debris_vclips[i].bm + j);
1352                 }
1353         }       
1354 }
1355
1356 // background nebula models and planets
1357 void stars_draw_background()
1358 {                               
1359         if((Nmodel_num < 0) || (Nmodel_bitmap < 0)){
1360                 return;
1361         }
1362
1363         // draw the model at the player's eye wif no z-buffering
1364         model_set_alpha(1.0f);
1365         model_set_forced_texture(Nmodel_bitmap);        
1366         model_render(Nmodel_num, &vmd_identity_matrix, &Eye_position, MR_NO_ZBUFFER | MR_NO_CULL | MR_ALL_XPARENT | MR_NO_LIGHTING | MR_FORCE_TEXTURE); 
1367         model_set_forced_texture(-1);
1368 }
1369
1370 // call this to set a specific model as the background model
1371 void stars_set_background_model(char *model_name, char *texture_name)
1372 {
1373         Nmodel_num = model_load(model_name, 0, NULL);
1374         Nmodel_bitmap = bm_load(texture_name);
1375 }
1376
1377 // lookup a starfield bitmap, return index or -1 on fail
1378 int stars_find_bitmap(char *name)
1379 {
1380         int idx;
1381
1382         // lookup
1383         for(idx=0; idx<MAX_STARFIELD_BITMAPS; idx++){
1384                 if(!strcmp(name, Starfield_bitmaps[idx].filename)){
1385                         return idx;
1386                 }
1387         }
1388
1389         // not found 
1390         return -1;
1391 }
1392
1393 // lookup a sun by bitmap filename, return index or -1 on fail
1394 int stars_find_sun(char *name)
1395 {
1396         int idx;
1397
1398         // lookup
1399         for(idx=0; idx<MAX_STARFIELD_BITMAPS; idx++){
1400                 if(!strcmp(name, Sun_bitmaps[idx].filename)){
1401                         return idx;
1402                 }
1403         }
1404
1405         // not found 
1406         return -1;
1407 }
1408