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