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