2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Starfield/StarField.cpp $
15 * Code to handle and draw starfields, background space image bitmaps, floating
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
26 * Revision 1.9 2004/09/20 01:31:45 theoddone33
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
32 * Revision 1.7 2003/05/25 02:30:44 taylor
35 * Revision 1.6 2002/06/22 23:57:39 relnev
36 * remove writable strings.
38 * fix compile for intel compiler.
40 * Revision 1.5 2002/06/17 06:33:11 relnev
41 * ryan's struct patch for gcc 2.95
43 * Revision 1.4 2002/06/09 04:41:27 relnev
44 * added copyright header
46 * Revision 1.3 2002/06/02 04:26:34 relnev
49 * Revision 1.2 2002/05/07 03:16:52 theoddone33
50 * The Great Newline Fix
52 * Revision 1.1.1.1 2002/05/03 03:28:10 root
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.
61 * 33 9/01/99 10:14a Dave
64 * 32 8/30/99 5:01p Dave
65 * Made d3d do less state changing in the nebula. Use new chat server for
68 * 31 8/19/99 10:59a Dave
69 * Packet loss detection.
71 * 30 7/27/99 3:52p Dave
72 * Make star drawing a bit more robust to help lame D3D cards.
74 * 29 7/21/99 8:10p Dave
75 * First run of supernova effect.
77 * 28 7/13/99 2:01p Dave
78 * Don't draw background bitmaps in the nebula.
80 * 27 6/08/99 2:34p Jasenw
81 * Made perspective bitmaps render in Fred.
83 * 26 6/04/99 1:18p Dave
84 * Fixed briefing model rendering problems. Made show background option in
85 * fred toggle nebula rendering.
87 * 25 6/03/99 6:37p Dave
88 * More TNT fun. Made perspective bitmaps more flexible.
90 * 24 5/28/99 1:45p Dave
91 * Fixed up perspective bitmap drawing.
93 * 23 5/20/99 7:00p Dave
94 * Added alternate type names for ships. Changed swarm missile table
97 * 22 5/11/99 10:03a Dave
98 * Put a bunch of stuff into tables.
100 * 21 5/11/99 9:10a Dave
101 * Move default sun position.
103 * 20 5/09/99 6:00p Dave
104 * Lots of cool new effects. E3 build tweaks.
106 * 19 4/26/99 8:49p Dave
107 * Made all pof based nebula stuff full customizable through fred.
109 * 18 4/25/99 7:43p Dave
110 * Misc small bug fixes. Made sun draw properly.
112 * 17 4/23/99 5:53p Dave
113 * Started putting in new pof nebula support into Fred.
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.
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.
124 * 14 3/20/99 5:09p Dave
125 * Fixed release build fred warnings and unhandled exception.
127 * 13 3/20/99 3:46p Dave
128 * Added support for model-based background nebulae. Added 3 new
131 * 12 3/20/99 2:04p Dave
132 * Removed unnecessary planet rendering.
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.
138 * 12 3/15/99 6:45p Daveb
139 * Put in rough nebula bitmap support.
141 * 11 3/11/99 5:53p Dave
142 * More network optimization. Spliced in Dell OEM planet bitmap crap.
144 * 10 2/03/99 11:44a Dave
145 * Fixed d3d transparent textures.
147 * 9 12/09/98 7:34p Dave
148 * Cleanup up nebula effect. Tweaked many values.
150 * 8 12/01/98 10:32a Johnson
151 * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
154 * 7 12/01/98 8:06a Dave
155 * Temporary checkin to fix some texture transparency problems in d3d.
157 * 6 11/14/98 5:33p Dave
158 * Lots of nebula work. Put in ship contrails.
160 * 5 11/05/98 5:55p Dave
161 * Big pass at reducing #includes
163 * 4 10/13/98 9:29a Dave
164 * Started neatening up freespace.h. Many variables renamed and
165 * reorganized. Added AlphaColors.[h,cpp]
167 * 3 10/07/98 11:16a Dave
170 * 2 10/07/98 10:54a Dave
173 * 1 10/07/98 10:51a Dave
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.
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.
184 * 104 5/13/98 10:28a John
185 * made subpsace forward sliding 40% faster.
187 * 103 5/10/98 4:18p John
188 * Reversed the subspace effect direction
190 * 102 5/08/98 8:38p John
191 * Subspace tweaks. Made two layers rotate independentyl.
193 * 101 5/08/98 1:32p John
194 * Added code for using two layered subspace effects.
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
202 * 99 4/22/98 4:09p John
203 * String externalization
205 * 98 4/22/98 3:28p John
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.
212 * 96 4/12/98 5:55p John
213 * Made models work with subspace. Made subspace rotate also.
215 * 95 4/11/98 6:53p John
216 * Added first rev of subspace effect.
218 * 94 4/08/98 11:31a Dave
219 * AL: Fix syntax error for non-demo
221 * 93 4/08/98 10:46a Lawrance
222 * #ifdef out asteroid check for demo
224 * 92 4/08/98 9:25a John
225 * Made asteroid missions not show suns
227 * 91 4/07/98 4:17p John
228 * Made Fred be able to move suns. Made suns actually affect the lighting
231 * 90 4/07/98 11:19a Hoffoss
232 * Changed code to only use Sun01 for a bitmap by default, as John
239 #include "floating.h"
243 #include "starfield.h"
246 #include "freespace.h"
249 #include "linklist.h"
250 #include "lighting.h"
251 #include "asteroid.h"
252 #include "missionparse.h"
254 #include "alphacolors.h"
255 #include "supernova.h"
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
264 typedef struct debris_vclip {
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;
286 static int Subspace_model_inner = -1;
287 static int Subspace_model_outer = -1;
290 fix starfield_timestamp = 0;
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;
297 // sun bitmaps and sun glow bitmaps
298 starfield_bitmap Sun_bitmaps[MAX_STARFIELD_BITMAPS];
299 starfield_bitmap_instance Suns[MAX_STARFIELD_BITMAPS];
302 int last_stars_filled = 0;
303 color star_colors[8];
304 color star_aacolors[8];
306 typedef struct star {
308 vector last_star_pos;
311 star Stars[MAX_STARS];
313 old_debris odebris[MAX_DEBRIS];
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;
321 int stars_debris_loaded = 0;
324 int Stars_background_inited = 0; // if we're inited
325 int Nmodel_num = -1; // model num
326 int Nmodel_bitmap = -1; // model texture
328 // given a starfield_bitmap_instance, return a pointer to its parent, for suns
329 starfield_bitmap *stars_lookup_sun(starfield_bitmap_instance *s)
339 for(idx=0; idx<MAX_STARFIELD_BITMAPS; idx++){
340 if(!SDL_strcasecmp(Sun_bitmaps[idx].filename, s->filename)){
341 return &Sun_bitmaps[idx];
349 void stars_load_debris()
353 // if we're in nebula mode
354 if(The_mission.flags & MISSION_FLAG_FULLNEB){
355 debris_vclips = debris_vclips_nebula;
357 debris_vclips = debris_vclips_normal;
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;
367 if(debris_vclips[i].bm <= 0){
368 Error( LOCATION, "Couldn't load animation/bitmap '%s'\n", debris_vclips[i].name );
372 stars_debris_loaded = 1;
375 // call on game startup
379 starfield_bitmap *bm;
381 char filename[MAX_FILENAME_LEN+1] = "";
382 char glow_filename[MAX_FILENAME_LEN+1] = "";
387 read_file_text("stars.tbl");
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));
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));
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));
413 bm->bitmap = bm_load(bm->filename);
414 SDL_assert(bm->bitmap != -1);
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);
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));
430 bm->bitmap = bm_load(bm->filename);
431 SDL_assert(bm->bitmap != -1);
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);
444 while(!optional_string("#end")){
445 if(optional_string("$Sun:")){
446 stuff_string(filename, F_NAME, NULL);
449 required_string("$Sunglow:");
450 stuff_string(glow_filename, F_NAME, NULL);
452 // associated lighting values
453 required_string("$SunRGBI:");
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));
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);
473 // if fred is running we should lock the bitmap now
476 bm_lock(bm->bitmap, 8, BMP_TEX_OTHER);
477 bm_unlock(bm->bitmap);
479 if(bm->glow_bitmap >= 0){
480 bm_lock(bm->glow_bitmap, 8, BMP_TEX_OTHER);
481 bm_unlock(bm->glow_bitmap);
488 // normal debris pieces
490 while(!optional_string("#end")){
491 required_string("$Debris:");
492 stuff_string(filename, F_NAME, NULL);
494 if(count < MAX_DEBRIS_VCLIPS){
495 SDL_strlcpy(debris_vclips_normal[count++].name, filename, SDL_arraysize(debris_vclips_normal[0].name));
498 SDL_assert(count == 4);
500 // nebula debris pieces
502 while(!optional_string("#end")){
503 required_string("$DebrisNeb:");
504 stuff_string(filename, F_NAME, NULL);
506 if(count < MAX_DEBRIS_VCLIPS){
507 SDL_strlcpy(debris_vclips_nebula[count++].name, filename, SDL_arraysize(debris_vclips_nebula[0].name));
511 SDL_assert(count == 4);
512 } catch (parse_error_t rval) {
513 Error(LOCATION, "Unable to parse stars.tbl! Code = %i.\n", (int)rval);
516 // hard-coded for FS1
517 starfield_bitmap *bm;
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));
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));
535 bm = &Sun_bitmaps[count++];
537 SDL_strlcpy(bm->filename, "Sun01", SDL_arraysize(bm->filename));
538 SDL_strlcpy(bm->glow_filename, "Sunglow01", SDL_arraysize(bm->glow_filename));
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);
549 // we use the default debris vclips so no need to specify those again here
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()
558 float dist, dist_max;
560 // reset to -1 so we reload it each mission (if we need to)
562 if(Nmodel_bitmap != -1){
563 bm_unload(Nmodel_bitmap);
567 // if (!stars_debris_loaded){
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++) {
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);
582 dist = v.xyz.x * v.xyz.x + v.xyz.y * v.xyz.y + v.xyz.z * v.xyz.z;
584 vm_vec_copy_normalize(&Stars[i].pos, &v);
587 for (i=0; i<MAX_DEBRIS; i++) {
588 odebris[i].active = 0;
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 );
597 last_stars_filled = 0;
599 #ifndef MAKE_FS1 // some FS1 missions don't have a sun
600 // if we have no sun instances, create one
602 mprintf(("Adding default sun\n"));
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;
610 memset(&Suns[0].ang, 0, sizeof(angles));
611 Suns[0].ang.h = fl_radian(60.0f);
621 extern object * Player_obj;
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
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;
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)
638 uint Star_flags = STAR_FLAG_DEFAULT;
641 DCF(stars,"Set parameters for starfield")
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) ) {
650 Star_amount = Dc_arg_float;
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 ) {
660 Star_dim = Dc_arg_float;
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;
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) ) {
678 Star_cap = Dc_arg_float;
680 } else if ( !strcmp( Dc_arg, "m0" ) ) {
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" )) {
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" )) {
700 if ( (Dc_arg_int < 0) || (Dc_arg_int > MAX_STARS) ) {
703 Num_stars = Dc_arg_int;
706 // print usage, not stats
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.
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" );
745 int reload_old_debris = 1; // If set to one, then reload all the last_pos of the debris
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()
751 last_stars_filled = 0;
752 reload_old_debris = 1;
755 //#define TIME_STAR_CODE // enable to time star code
758 extern float Viewer_zoom;
760 // get the world coords of the sun pos on the unit sphere.
761 void stars_get_sun_pos(int sun_n, vector *pos)
769 SDL_assert(sun_n < Num_suns);
770 if((sun_n >= Num_suns) || (sun_n < 0)){
774 // rotate the sun properly
775 temp = vmd_zero_vector;
780 // we aleady know what the matrix is so just rotate
781 vm_vec_rotate(pos, &temp, &Suns[sun_n].m);
783 vm_angles_2_matrix(&rot, &Suns[sun_n].ang);
784 vm_vec_rotate(pos, &temp, &rot);
789 void stars_draw_sun( int show_sun )
795 starfield_bitmap *bm;
796 float local_scale = 1.0f;
802 for(idx=0; idx<Num_suns; idx++){
804 bm = stars_lookup_sun(&Suns[idx]);
810 sun_pos = vmd_zero_vector;
811 sun_pos.xyz.y = 1.0f;
812 stars_get_sun_pos(idx, &sun_pos);
816 vm_vec_normalize(&sun_dir);
818 // add the light source corresponding to the sun
819 light_add_directional(&sun_dir, bm->i, bm->r, bm->g, bm->b);
822 if(supernova_active()){
823 local_scale = 1.0f + (SUPERNOVA_SUN_SCALE * supernova_pct_complete());
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);
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)){
833 if(!g3_draw_bitmap(&sun_vex, 0, 0.05f * Suns[idx].scale_x * local_scale, TMAP_FLAG_TEXTURED)){
840 // draw the corresponding glow for sun_n
841 void stars_draw_sun_glow(int sun_n)
843 starfield_bitmap *bm;
844 vector sun_pos, sun_dir;
846 float local_scale = 1.0f;
849 SDL_assert(sun_n < Num_suns);
850 if((sun_n >= Num_suns) || (sun_n < 0)){
855 bm = stars_lookup_sun(&Suns[sun_n]);
861 sun_pos = vmd_zero_vector;
862 sun_pos.xyz.y = 1.0f;
863 stars_get_sun_pos(sun_n, &sun_pos);
867 vm_vec_normalize(&sun_dir);
870 if(supernova_active()){
871 local_scale = 1.0f + (SUPERNOVA_SUN_SCALE * supernova_pct_complete());
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);
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);
881 g3_draw_bitmap(&sun_vex, 0, 0.10f * Suns[sun_n].scale_x * local_scale, TMAP_FLAG_TEXTURED);
886 void stars_draw_bitmaps( int show_bitmaps )
891 // if we're in the nebula, don't render any backgrounds
892 if(The_mission.flags & MISSION_FLAG_FULLNEB){
897 if(!Detail.planets_suns){
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);
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);
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);
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);
926 void calculate_bitmap_matrix(starfield_bitmaps *bm, vector *v)
928 vm_vector_2_matrix(&bm->m, v, NULL, NULL);
929 vm_orthogonalize_matrix(&bm->m);
932 void calculate_bitmap_points(starfield_bitmaps *bm, float bank)
935 vector fvec, uvec, rvec, tmp;
938 vm_orthogonalize_matrix(&bm->m);
940 tangles.p = tangles.h = 0.0f;
942 vm_rotate_matrix_by_angles(&bm->m, &tangles);
946 vm_vec_scale(&fvec, bm->dist );
950 vm_vec_sub(&tmp, &fvec, &uvec);
951 vm_vec_sub(&bm->points[3], &tmp, &rvec);
953 vm_vec_sub(&tmp, &fvec, &uvec);
954 vm_vec_add(&bm->points[2], &tmp, &rvec);
956 vm_vec_add(&tmp, &fvec, &uvec);
957 vm_vec_add(&bm->points[1], &tmp, &rvec);
959 vm_vec_add(&tmp, &fvec, &uvec);
960 vm_vec_sub(&bm->points[0], &tmp, &rvec);
963 vm_vec_normalize(&bm->points[i]);
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;
973 float subspace_offset_u = 0.0f;
974 float subspace_offset_u_inner = 0.0f;
975 float subspace_offset_v = 0.0f;
977 float subspace_u_speed = 0.07f; // how fast u changes
978 float subspace_v_speed = 0.05f; // how fast v changes
980 int Subspace_glow_bitmap = -1;
982 float Subspace_glow_frame = 0.0f;
983 float Subspace_glow_rate = 1.0f;
987 DCF(subspace_set,"Set parameters for subspace effect")
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 ) {
996 subspace_u_speed = Dc_arg_float;
998 } else if ( !strcmp( Dc_arg, "v" )) {
999 dc_get_arg(ARG_FLOAT);
1000 if ( Dc_arg_float < 0.0f ) {
1003 subspace_v_speed = Dc_arg_float;
1006 // print usage, not stats
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.
1020 dc_printf( "u: %.2f\n", subspace_u_speed );
1021 dc_printf( "v: %.2f\n", subspace_v_speed );
1026 void subspace_render()
1028 if ( Subspace_model_inner == -1 ) {
1029 Subspace_model_inner = model_load( "subspace_small.pof", 0, NULL );
1030 SDL_assert(Subspace_model_inner>-1);
1033 if ( Subspace_model_outer == -1 ) {
1034 Subspace_model_outer = model_load( "subspace_big.pof", 0, NULL );
1035 SDL_assert(Subspace_model_outer>-1);
1038 if ( Subspace_glow_bitmap == -1 ) {
1039 Subspace_glow_bitmap = bm_load( NOX("SunGlow01"));
1040 SDL_assert(Subspace_glow_bitmap>-1);
1043 Subspace_glow_frame += flFrametime * 1.0f;
1045 float total_time = i2fl(NOISE_NUM_FRAMES) / 15.0f;
1048 if ( Subspace_glow_frame < 0.0f ) Subspace_glow_frame = 0.0f;
1049 if ( Subspace_glow_frame > 100.0f ) Subspace_glow_frame = 0.0f;
1051 while ( Subspace_glow_frame > total_time ) {
1052 Subspace_glow_frame -= total_time;
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;
1058 subspace_offset_u += flFrametime*subspace_u_speed;
1059 if (subspace_offset_u > 1.0f ) {
1060 subspace_offset_u -= 1.0f;
1063 subspace_offset_u_inner += flFrametime*subspace_u_speed*3.0f;
1064 if (subspace_offset_u > 1.0f ) {
1065 subspace_offset_u -= 1.0f;
1068 subspace_offset_v += flFrametime*subspace_v_speed;
1069 if (subspace_offset_v > 1.0f ) {
1070 subspace_offset_v -= 1.0f;
1076 angles angs = { 0.0f, 0.0f, 0.0f };
1077 angs.b = subspace_offset_v * PI2;
1079 vm_angles_2_matrix(&tmp,&angs);
1081 int saved_gr_zbuffering = gr_zbuffer_get();
1083 gr_zbuffer_set(GR_ZBUFF_NONE);
1085 int render_flags = MR_NO_LIGHTING | MR_ALWAYS_REDRAW;
1087 Interp_subspace = 1;
1088 Interp_subspace_offset_u = 1.0f - subspace_offset_u;
1089 Interp_subspace_offset_v = 0.0f;
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
1095 Interp_subspace = 1;
1096 Interp_subspace_offset_u = 1.0f - subspace_offset_u_inner;
1097 Interp_subspace_offset_v = 0.0f;
1099 angs.b = -subspace_offset_v * PI2;
1101 vm_angles_2_matrix(&tmp,&angs);
1103 model_set_outline_color(255,255,255);
1105 model_set_thrust( Subspace_model_inner, 1.0f, -1, Subspace_glow_bitmap, Noise[framenum] );
1106 render_flags |= MR_SHOW_THRUSTERS;
1108 model_render( Subspace_model_inner, &tmp, &Eye_position, render_flags ); //MR_NO_CORRECT|MR_SHOW_OUTLINE
1110 Interp_subspace = 0;
1111 gr_zbuffer_set(saved_gr_zbuffering);
1114 void stars_draw( int show_stars, int show_suns, int show_nebulas, int show_subspace )
1120 int gr_zbuffering_save = gr_zbuffer_get();
1121 gr_zbuffer_set(GR_ZBUFF_NONE);
1123 if ( show_subspace ) {
1128 if (Num_stars >= MAX_STARS){
1129 Num_stars = MAX_STARS;
1132 #ifdef TIME_STAR_CODE
1134 xt1 = timer_get_fixed_seconds();
1137 if ( show_nebulas && (Game_detail_flags & DETAIL_FLAG_NEBULAS) && (Neb2_render_mode != NEB2_RENDER_POF) && (Neb2_render_mode != NEB2_RENDER_LAME)) {
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;
1151 if (show_stars && ( Game_detail_flags & DETAIL_FLAG_STARS) && !(The_mission.flags & MISSION_FLAG_FULLNEB) && (supernova_active() < 3)) {
1156 if ( !last_stars_filled ) {
1157 for (sp=Stars,i=0; i<Num_stars; i++, sp++ ) {
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;
1168 tmp_num_stars = (Detail.num_stars*Num_stars)/MAX_DETAIL_LEVEL;
1169 if (tmp_num_stars < 0 ) {
1171 } else if ( tmp_num_stars > Num_stars ) {
1172 tmp_num_stars = Num_stars;
1175 for (sp=Stars,i=0; i<tmp_num_stars; i++, sp++ ) {
1179 memset(&p1, 0, sizeof(vertex));
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.
1185 g3_rotate_faraway_vertex(&p2, &sp->pos);
1189 g3_project_vertex(&p2);
1190 if ( p2.flags & PF_OVERFLOW ) {
1197 if ( can_draw && (Star_flags & (STAR_FLAG_TAIL|STAR_FLAG_DIM)) ) {
1199 dist = vm_vec_dist_quick( &sp->last_star_pos, (vector *)&p2.x );
1202 if ( dist > Star_max_length ) {
1203 ratio = Star_max_length / dist;
1204 dist = Star_max_length;
1208 ratio *= Star_amount;
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;
1214 p1.flags = 0; // not projected
1215 g3_code_vertex( &p1 );
1220 g3_project_vertex(&p1);
1221 if ( p1.flags & PF_OVERFLOW ) {
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;
1231 if ( !can_draw ) continue;
1235 if ( Star_flags & STAR_FLAG_DIM ) {
1237 float colorf = 255.0f - dist*Star_dim;
1239 if ( colorf < Star_cap )
1242 color = (fl2i(colorf)*(i&7))/256;
1248 gr_set_color_fast( &star_aacolors[color] );
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)) ) {
1259 last_stars_filled = 1;
1261 #ifdef TIME_STAR_CODE
1262 xt2 = timer_get_fixed_seconds();
1263 mprintf(( "Stars: %d\n", xt2-xt1 ));
1267 if ( (Game_detail_flags & DETAIL_FLAG_MOTION) && (!Fred_running) && (supernova_active() < 3) ) {
1269 gr_set_color( 0, 0, 0 );
1272 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1273 gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0, -1.0f, -1.0f);
1276 old_debris * d = odebris;
1277 for (i=0; i<MAX_DEBRIS; i++, d++ ) {
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);
1285 vm_vec_normalize(&d->pos);
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 );
1291 d->vclip = i % MAX_DEBRIS_VCLIPS; //rand()
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;
1297 d->size = i2fl(myrand() % 4)*BASE_SIZE;
1300 vm_vec_sub( &d->last_pos, &d->pos, &Eye_position );
1303 if ( reload_old_debris ) {
1304 vm_vec_sub( &d->last_pos, &d->pos, &Eye_position );
1307 g3_rotate_vertex(&p, &d->pos);
1310 int frame = Missiontime / (DEBRIS_ROT_MIN + (i % DEBRIS_ROT_RANGE) * DEBRIS_ROT_RANGE_SCALER);
1311 frame %= debris_vclips[d->vclip].nframes;
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);
1316 gr_set_bitmap( debris_vclips[d->vclip].bm + frame, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
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 );
1324 vm_vec_sub( &d->last_pos, &d->pos, &Eye_position );
1326 vdist = vm_vec_mag_quick(&d->last_pos);
1328 if (vdist > MAX_DIST_RANGE)
1330 else if (vdist < MIN_DIST_RANGE)
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 )
1341 reload_old_debris = 0;
1345 stars_draw_sun( show_suns );
1346 stars_draw_bitmaps( show_suns );
1348 gr_zbuffer_set( gr_zbuffering_save );
1351 void stars_page_in()
1355 // Initialize the subspace stuff
1357 if ( Game_subspace_effect ) {
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);
1366 pm = model_get(Subspace_model_inner);
1368 nprintf(( "Paging", "Paging in textures for subspace effect.\n" ));
1370 for (j=0; j<pm->n_textures; j++ ) {
1371 int bitmap_num = pm->original_textures[j];
1373 if ( bitmap_num > -1 ) {
1374 bm_page_in_texture( bitmap_num );
1378 pm = model_get(Subspace_model_outer);
1380 nprintf(( "Paging", "Paging in textures for subspace effect.\n" ));
1382 for (j=0; j<pm->n_textures; j++ ) {
1383 int bitmap_num = pm->original_textures[j];
1385 if ( bitmap_num > -1 ) {
1386 bm_page_in_texture( bitmap_num );
1390 Subspace_model_inner = -1;
1391 Subspace_model_outer = -1;
1394 Subspace_glow_bitmap = bm_load( NOX("SunGlow01"));
1395 bm_page_in_xparent_texture(Subspace_glow_bitmap);
1397 // page in starfield bitmaps
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);
1407 bm_page_in_texture(Starfield_bitmaps[idx].bitmap);
1416 // sun bitmaps and glows
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);
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);
1438 // background nebula models and planets
1439 void stars_draw_background()
1441 if((Nmodel_num < 0) || (Nmodel_bitmap < 0)){
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);
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)
1455 Nmodel_num = model_load(model_name, 0, NULL);
1456 Nmodel_bitmap = bm_load(texture_name);
1459 // lookup a starfield bitmap, return index or -1 on fail
1460 int stars_find_bitmap(const char *name)
1465 for(idx=0; idx<MAX_STARFIELD_BITMAPS; idx++){
1466 if(!strcmp(name, Starfield_bitmaps[idx].filename)){
1475 // lookup a sun by bitmap filename, return index or -1 on fail
1476 int stars_find_sun(const char *name)
1481 for(idx=0; idx<MAX_STARFIELD_BITMAPS; idx++){
1482 if(!strcmp(name, Sun_bitmaps[idx].filename)){