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