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