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/Nebula/Neb.cpp $
18 * Revision 1.8 2003/05/25 02:30:43 taylor
21 * Revision 1.7 2002/06/17 06:33:09 relnev
22 * ryan's struct patch for gcc 2.95
24 * Revision 1.6 2002/06/09 04:41:23 relnev
25 * added copyright header
27 * Revision 1.5 2002/06/01 03:32:00 relnev
28 * fix texture loading mistake.
30 * enable some d3d stuff for opengl also
32 * Revision 1.4 2002/05/26 20:22:48 theoddone33
33 * Most of network/ works
35 * Revision 1.3 2002/05/07 03:16:47 theoddone33
36 * The Great Newline Fix
38 * Revision 1.2 2002/05/04 04:36:56 theoddone33
39 * More changes, took out a lot of the sound stuff which will bite later but
42 * Revision 1.1.1.1 2002/05/03 03:28:10 root
46 * 50 8/30/99 5:01p Dave
47 * Made d3d do less state changing in the nebula. Use new chat server for
50 * 49 8/10/99 6:54p Dave
51 * Mad optimizations. Added paging to the nebula effect.
53 * 48 8/05/99 2:05a Dave
56 * 47 7/30/99 10:55a Anoop
57 * Hmm. Fixed release build problem again, with area-rotated bitmaps.
59 * 46 7/29/99 10:47p Dave
60 * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
62 * 44 7/29/99 12:05a Dave
63 * Nebula speed optimizations.
65 * 43 7/19/99 7:20p Dave
66 * Beam tooling. Specialized player-killed-self messages. Fixed d3d nebula
69 * 42 7/18/99 5:20p Dave
70 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
72 * 41 7/13/99 1:15p Dave
73 * 32 bit support. Whee!
75 * 40 7/09/99 5:54p Dave
76 * Seperated cruiser types into individual types. Added tons of new
77 * briefing icons. Campaign screen.
79 * 39 7/07/99 10:44a Jamesa
80 * Make sure the nebula regens properly after loading a mission.
82 * 38 6/11/99 2:32p Dave
83 * Toned down nebula brightness a bit.
85 * 37 5/26/99 3:39p Dave
86 * Fixed nebula regeneration problem. Removed optimizations from
89 * 36 5/26/99 11:46a Dave
90 * Added ship-blasting lighting and made the randomization of lighting
91 * much more customizable.
93 * 35 5/24/99 5:45p Dave
94 * Added detail levels to the nebula, with a decent speedup. Split nebula
95 * lightning into its own section.
111 #include "freespace.h"
114 #include "starfield.h"
119 #include "grinternal.h"
121 #include "alphacolors.h"
123 // --------------------------------------------------------------------------------------------------------
124 // NEBULA DEFINES/VARS
127 // #define NEB2_THUMBNAIL
130 3D CARDS THAT FOG PROPERLY
136 3D CARDS THAT DON'T FOG PROPERLY
141 // if nebula rendering is active (DCF stuff - not mission specific)
142 int Neb2_render_mode = NEB2_RENDER_NONE;
144 // array of neb2 poofs
145 char Neb2_poof_filenames[MAX_NEB2_POOFS][MAX_FILENAME_LEN] = {
146 "", "", "", "", "", ""
148 int Neb2_poofs[MAX_NEB2_POOFS] = { -1, -1, -1, -1, -1, -1 };
149 int Neb2_poof_flags = ( (1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5) );
150 int Neb2_poof_count = 0;
152 // array of neb2 bitmaps
153 char Neb2_bitmap_filenames[MAX_NEB2_BITMAPS][MAX_FILENAME_LEN] = {
154 "", "", "", "", "", ""
156 int Neb2_bitmap[MAX_NEB2_BITMAPS] = { -1, -1, -1, -1, -1, -1 };
157 int Neb2_bitmap_count = 0;
159 // texture to use for this level
160 char Neb2_texture_name[MAX_FILENAME_LEN] = "";
163 #define NF_USED (1<<0) // if this nebula slot is used
165 float max_rotation = 3.75f;
166 float neb2_flash_fade = 0.3f;
168 // fog values for different ship types
169 float Neb_ship_fog_vals_glide[MAX_SHIP_TYPE_COUNTS][2] = {
170 {0.0f, 0.0f}, // SHIP_TYPE_NONE
171 {10.0f, 500.0f}, // SHIP_TYPE_CARGO
172 {10.0f, 500.0f}, // SHIP_TYPE_FIGHTER_BOMBER
173 {10.0f, 600.0f}, // SHIP_TYPE_CRUISER
174 {10.0f, 600.0f}, // SHIP_TYPE_FREIGHTER
175 {10.0f, 750.0f}, // SHIP_TYPE_CAPITAL
176 {10.0f, 500.0f}, // SHIP_TYPE_TRANSPORT
177 {10.0f, 500.0f}, // SHIP_TYPE_REPAIR_REARM
178 {10.0f, 500.0f}, // SHIP_TYPE_NAVBUOY
179 {10.0f, 500.0f}, // SHIP_TYPE_SENTRYGUN
180 {10.0f, 600.0f}, // SHIP_TYPE_ESCAPEPOD
181 {10.0f, 1000.0f}, // SHIP_TYPE_SUPERCAP
182 {10.0f, 500.0f}, // SHIP_TYPE_STEALTH
183 {10.0f, 500.0f}, // SHIP_TYPE_FIGHTER
184 {10.0f, 500.0f}, // SHIP_TYPE_BOMBER
185 {10.0f, 750.0f}, // SHIP_TYPE_DRYDOCK
186 {10.0f, 600.0f}, // SHIP_TYPE_AWACS
187 {10.0f, 600.0f}, // SHIP_TYPE_GAS_MINER
188 {10.0f, 600.0f}, // SHIP_TYPE_CORVETTE
189 {10.0f, 1000.0f}, // SHIP_TYPE_KNOSSOS_DEVICE
191 float Neb_ship_fog_vals_d3d[MAX_SHIP_TYPE_COUNTS][2] = {
192 {0.0f, 0.0f}, // SHIP_TYPE_NONE
193 {10.0f, 500.0f}, // SHIP_TYPE_CARGO
194 {10.0f, 500.0f}, // SHIP_TYPE_FIGHTER_BOMBER
195 {10.0f, 600.0f}, // SHIP_TYPE_CRUISER
196 {10.0f, 600.0f}, // SHIP_TYPE_FREIGHTER
197 {10.0f, 750.0f}, // SHIP_TYPE_CAPITAL
198 {10.0f, 500.0f}, // SHIP_TYPE_TRANSPORT
199 {10.0f, 500.0f}, // SHIP_TYPE_REPAIR_REARM
200 {10.0f, 500.0f}, // SHIP_TYPE_NAVBUOY
201 {10.0f, 500.0f}, // SHIP_TYPE_SENTRYGUN
202 {10.0f, 600.0f}, // SHIP_TYPE_ESCAPEPOD
203 {10.0f, 1000.0f}, // SHIP_TYPE_SUPERCAP
204 {10.0f, 500.0f}, // SHIP_TYPE_STEALTH
205 {10.0f, 500.0f}, // SHIP_TYPE_FIGHTER
206 {10.0f, 500.0f}, // SHIP_TYPE_BOMBER
207 {10.0f, 750.0f}, // SHIP_TYPE_DRYDOCK
208 {10.0f, 600.0f}, // SHIP_TYPE_AWACS
209 {10.0f, 600.0f}, // SHIP_TYPE_GAS_MINER
210 {10.0f, 600.0f}, // SHIP_TYPE_CORVETTE
211 {10.0f, 1000.0f}, // SHIP_TYPE_KNOSSOS_DEVICE
214 // fog near and far values for rendering the background nebula
215 #define NEB_BACKG_FOG_NEAR_GLIDE 2.5f
216 #define NEB_BACKG_FOG_NEAR_D3D 4.5f
217 #define NEB_BACKG_FOG_FAR_GLIDE 10.0f
218 #define NEB_BACKG_FOG_FAR_D3D 10.0f
219 float Neb_backg_fog_near = NEB_BACKG_FOG_NEAR_GLIDE;
220 float Neb_backg_fog_far = NEB_BACKG_FOG_FAR_GLIDE;
223 int pneb_tried = 0; // total pnebs tried to render
224 int pneb_tossed_alpha = 0; // pnebs tossed because of alpha optimization
225 int pneb_tossed_dot = 0; // pnebs tossed because of dot product
226 int pneb_tossed_off = 0; // pnebs tossed because of being offscree
227 int neb_tried = 0; // total nebs tried
228 int neb_tossed_alpha = 0; // nebs tossed because of alpha
229 int neb_tossed_dot = 0; // nebs tossed because of dot product
230 int neb_tossed_count = 0; // nebs tossed because of max render count
232 // the AWACS suppresion level for the nebula
233 float Neb2_awacs = -1.0f;
235 // how many "slices" are in the current player nebuls
238 cube_poof Neb2_cubes[MAX_CPTS][MAX_CPTS][MAX_CPTS];
240 // nebula detail level
241 typedef struct neb2_detail {
242 float max_alpha_glide; // max alpha for this detail level in Glide
243 float max_alpha_d3d; // max alpha for this detail level in D3d
244 float break_alpha; // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
245 float break_x, break_y; // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
246 float cube_dim; // total dimension of player poof cube
247 float cube_inner; // inner radius of the player poof cube
248 float cube_outer; // outer radius of the player pood cube
249 float prad; // radius of the poofs
250 float wj, hj, dj; // width, height, depth jittering. best left at 1.0
252 neb2_detail Neb2_detail[MAX_DETAIL_LEVEL] = {
253 { // lowest detail level
254 0.575f, // max alpha for this detail level in Glide
255 0.71f, // max alpha for this detail level in D3d
256 0.13f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
257 150.0f, 150.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
258 510.0f, // total dimension of player poof cube
259 50.0f, // inner radius of the player poof cube
260 250.0f, // outer radius of the player pood cube
261 120.0f, // radius of the poofs
262 1.0f, 1.0f, 1.0f // width, height, depth jittering. best left at 1.0
264 { // 2nd lowest detail level
265 0.575f, // max alpha for this detail level in Glide
266 0.71f, // max alpha for this detail level in D3d
267 0.125f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
268 300.0f, 300.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
269 550.0f, // total dimension of player poof cube
270 100.0f, // inner radius of the player poof cube
271 250.0f, // outer radius of the player pood cube
272 125.0f, // radius of the poofs
273 1.0f, 1.0f, 1.0f // width, height, depth jittering. best left at 1.0
275 { // 2nd highest detail level
276 0.575f, // max alpha for this detail level in Glide
277 0.71f, // max alpha for this detail level in D3d
278 0.1f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
279 300.0f, 300.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
280 550.0f, // total dimension of player poof cube
281 150.0f, // inner radius of the player poof cube
282 250.0f, // outer radius of the player pood cube
283 125.0f, // radius of the poofs
284 1.0f, 1.0f, 1.0f // width, height, depth jittering. best left at 1.0
286 { // higest detail level
287 0.475f, // max alpha for this detail level in Glide
288 0.575f, // max alpha for this detail level in D3d
289 0.05f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot
290 200.0f, 200.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen
291 750.0f, // total dimension of player poof cube
292 200.0f, // inner radius of the player poof cube
293 360.0f, // outer radius of the player pood cube
294 150.0f, // radius of the poofs
295 1.0f, 1.0f, 1.0f // width, height, depth jittering. best left at 1.0
298 neb2_detail *Nd = &Neb2_detail[MAX_DETAIL_LEVEL - 2];
300 int Neb2_background_color[3] = {0, 0, 255}; // rgb background color (used for lame rendering)
304 // --------------------------------------------------------------------------------------------------------
305 // NEBULA FORWARD DECLARATIONS
308 // return the alpha the passed poof should be rendered with, for a 2 shell nebula
309 float neb2_get_alpha_2shell(float inner_radius, float outer_radius, float magic_num, vector *v);
311 // return an alpha value for a bitmap offscreen based upon "break" value
312 float neb2_get_alpha_offscreen(float sx, float sy, float incoming_alpha);
314 // do a pre-render of the background nebula
315 void neb2_pre_render(vector *eye_pos, matrix *eye_orient);
317 // fill in the position of the eye for this frame
318 void neb2_get_eye_pos(vector *eye);
320 // fill in the eye orient for this frame
321 void neb2_get_eye_orient(matrix *eye);
323 // get a (semi) random bitmap to use for a poof
324 int neb2_get_bitmap();
326 // regenerate the player nebula
330 // --------------------------------------------------------------------------------------------------------
334 // initialize neb2 stuff at game startup
340 // read in the nebula.tbl
341 read_file_text("nebula.tbl");
344 // background bitmaps
345 Neb2_bitmap_count = 0;
346 while(!optional_string("#end")){
348 required_string("+Nebula:");
349 stuff_string(name, F_NAME, NULL);
351 if(Neb2_bitmap_count < MAX_NEB2_BITMAPS){
352 strcpy(Neb2_bitmap_filenames[Neb2_bitmap_count++], name);
358 while(!optional_string("#end")){
360 required_string("+Poof:");
361 stuff_string(name, F_NAME, NULL);
363 if(Neb2_poof_count < MAX_NEB2_POOFS){
364 strcpy(Neb2_poof_filenames[Neb2_poof_count++], name);
368 // should always have 6 neb poofs
369 Assert(Neb2_poof_count == 6);
374 void neb2_set_detail_level(int level)
378 Nd = &Neb2_detail[0];
381 if(level >= MAX_DETAIL_LEVEL){
382 Nd = &Neb2_detail[MAX_DETAIL_LEVEL-1];
386 Nd = &Neb2_detail[level];
388 // regen the player neb
392 // initialize nebula stuff - call from game_post_level_init(), so the mission has been loaded
393 void neb2_level_init()
397 // standalone servers can bail here
398 if(Game_mode & GM_STANDALONE_SERVER){
402 // if the mission is not a fullneb mission, skip
403 if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
404 Neb2_render_mode = NEB2_RENDER_NONE;
410 if(gr_screen.mode == GR_DIRECT3D){
411 max_alpha_player = NEB2_MAX_ALPHA_D3D;
413 max_alpha_player = NEB2_MAX_ALPHA_GLIDE;
417 // by default we'll use pof rendering
418 Neb2_render_mode = NEB2_RENDER_POF;
419 stars_set_background_model(BACKGROUND_MODEL_FILENAME, Neb2_texture_name);
421 // load in all nebula bitmaps
422 for(idx=0; idx<Neb2_poof_count; idx++){
423 if(Neb2_poofs[idx] < 0){
424 Neb2_poofs[idx] = bm_load(Neb2_poof_filenames[idx]);
429 pneb_tossed_alpha = 0;
432 neb_tossed_alpha = 0;
434 neb_tossed_count = 0;
436 // setup proper fogging values
437 switch(gr_screen.mode){
439 Neb_backg_fog_near = NEB_BACKG_FOG_NEAR_GLIDE;
440 Neb_backg_fog_far = NEB_BACKG_FOG_FAR_GLIDE;
444 Neb_backg_fog_near = NEB_BACKG_FOG_NEAR_D3D;
445 Neb_backg_fog_far = NEB_BACKG_FOG_FAR_D3D;
448 Assert(Fred_running);
458 // shutdown nebula stuff
459 void neb2_level_close()
463 // standalone servers can bail here
464 if(Game_mode & GM_STANDALONE_SERVER){
468 // if the mission is not a fullneb mission, skip
469 if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
473 // unload all nebula bitmaps
474 for(idx=0; idx<Neb2_poof_count; idx++){
475 if(Neb2_poofs[idx] >= 0){
476 bm_unload(Neb2_poofs[idx]);
477 Neb2_poofs[idx] = -1;
481 // unflag the mission as being fullneb so stuff doesn't fog in the techdata room :D
482 The_mission.flags &= ~MISSION_FLAG_FULLNEB;
485 // call before beginning all rendering
486 void neb2_render_setup(vector *eye_pos, matrix *eye_orient)
488 // standalone servers can bail here
489 if(Game_mode & GM_STANDALONE_SERVER){
493 // if the mission is not a fullneb mission, skip
494 if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
498 // pre-render the real background nebula
499 neb2_pre_render(eye_pos, eye_orient);
507 // load in all nebula bitmaps
508 for(idx=0; idx<Neb2_poof_count; idx++){
509 if((Neb2_poofs[idx] >= 0) && (Neb2_poof_flags & (1<<idx))){
510 bm_page_in_texture(Neb2_poofs[idx]);
515 // should we not render this object because its obscured by the nebula?
516 int neb_skip_opt = 1;
519 neb_skip_opt = !neb_skip_opt;
521 dc_printf("Using neb object skipping!\n");
523 dc_printf("Not using neb object skipping!\n");
526 int neb2_skip_render(object *objp, float z_depth)
528 float fog_near, fog_far;
530 // if we're never skipping
536 if(Neb2_render_mode == NEB2_RENDER_LAME){
540 // get near and far fog values based upon object type and rendering mode
541 neb2_get_fog_values(&fog_near, &fog_far, objp);
544 switch( objp->type ) {
545 // some objects we always render
553 // any weapon over 500 meters away
555 if(z_depth >= 500.0f){
560 // any small ship over the fog limit, or any cruiser 50% further than the fog limit
563 if((objp->instance >= 0) && (Ships[objp->instance].ship_info_index >= 0)){
564 sip = &Ship_info[Ships[objp->instance].ship_info_index];
569 // small ships over the fog limit by a small factor
570 if((sip->flags & SIF_SMALL_SHIP) && (z_depth >= (fog_far * 1.3f))){
575 if((sip->flags & SIF_BIG_SHIP) && (z_depth >= (fog_far * 2.0f))){
580 if((sip->flags & SIF_HUGE_SHIP) && (z_depth >= (fog_far * 3.0f))){
585 // any fireball over the fog limit for small ships
588 if(z_depth >= fog_far){
595 // any debris over the fog limit for small ships
598 if(z_depth >= fog_far){
605 // any asteroids 50% farther than the fog limit for small ships
607 if(z_depth >= (fog_far * 1.5f)){
612 // any countermeasures over 100 meters away
614 if(z_depth >= 100.0f){
619 // hmmm. unknown object type - should probably let it through
628 float neb2_get_lod_scale(int objnum)
634 if((objnum < 0) || (objnum >= MAX_OBJECTS) || (Objects[objnum].type != OBJ_SHIP) || (Objects[objnum].instance < 0) || (Objects[objnum].instance >= MAX_SHIPS)){
637 shipp = &Ships[Objects[objnum].instance];
638 sip = &Ship_info[shipp->ship_info_index];
641 if(sip->flags & SIF_SMALL_SHIP){
643 } else if(sip->flags & SIF_BIG_SHIP){
652 // --------------------------------------------------------------------------------------------------------
653 // NEBULA FORWARD DEFINITIONS
656 // return the alpha the passed poof should be rendered with, for a 2 shell nebula
657 float neb2_get_alpha_2shell(float inner_radius, float outer_radius, float magic_num, vector *v)
663 // get the eye position
664 neb2_get_eye_pos(&eye_pos);
666 // determine what alpha to draw this bitmap with
667 // higher alpha the closer the bitmap gets to the eye
668 dist = vm_vec_dist_quick(&eye_pos, v);
670 // if the point is inside the inner radius, alpha is based on distance to the player's eye,
671 // becoming more transparent as it gets close
672 if(dist <= inner_radius){
673 // alpha per meter between the magic # and the inner radius
674 alpha = Nd->max_alpha_glide / (inner_radius - magic_num);
676 // above value times the # of meters away we are
677 alpha *= (dist - magic_num);
678 return alpha < 0.0f ? 0.0f : alpha;
680 // if the point is outside the inner radius, it starts out as completely transparent at max
681 // outer radius, and becomes more opaque as it moves towards inner radius
682 else if(dist <= outer_radius){
683 // alpha per meter between the outer radius and the inner radius
684 alpha = Nd->max_alpha_glide / (outer_radius - inner_radius);
686 // above value times the range between the outer radius and the poof
687 return alpha < 0.0f ? 0.0f : alpha * (outer_radius - dist);
690 // otherwise transparent
694 // return an alpha value for a bitmap offscreen based upon "break" value
695 float neb2_get_alpha_offscreen(float sx, float sy, float incoming_alpha)
698 float per_pixel_x = incoming_alpha / (float)Nd->break_x;
699 float per_pixel_y = incoming_alpha / (float)Nd->break_y;
700 int off_x = ((sx < 0.0f) || (sx > (float)gr_screen.max_w));
701 int off_y = ((sy < 0.0f) || (sy > (float)gr_screen.max_h));
702 float off_x_amount = 0.0f;
703 float off_y_amount = 0.0f;
705 // determine how many pixels outside we are
708 off_x_amount = fl_abs(sx);
710 off_x_amount = sx - (float)gr_screen.max_w;
715 off_y_amount = fl_abs(sy);
717 off_y_amount = sy - (float)gr_screen.max_h;
723 // offscreen X and Y - and Y is greater
724 if(off_y && (off_y_amount > off_x_amount)){
725 alpha = incoming_alpha - (off_y_amount * per_pixel_y);
727 alpha = incoming_alpha - (off_x_amount * per_pixel_x);
732 alpha = incoming_alpha - (off_y_amount * per_pixel_y);
734 // should never get here
739 return alpha < 0.0f ? 0.0f : alpha;
742 // -------------------------------------------------------------------------------------------------
743 // WACKY LOCAL PLAYER NEBULA STUFF
751 float ws = Nd->cube_dim / (float)Neb2_slices;
752 float hs = Nd->cube_dim / (float)Neb2_slices;
753 float ds = Nd->cube_dim / (float)Neb2_slices;
755 // get the eye position
756 neb2_get_eye_pos(&eye_pos);
758 // check left, right (0, and 1, x and -x)
759 if(cube_cen.xyz.x - eye_pos.xyz.x > ws){
762 } else if(eye_pos.xyz.x - cube_cen.xyz.x > ws){
767 // check up, down (2, and 3, y and -y)
768 if(cube_cen.xyz.y - eye_pos.xyz.y > hs){
771 } else if(eye_pos.xyz.y - cube_cen.xyz.y > hs){
776 // check front, back (4, and 5, z and -z)
777 if(cube_cen.xyz.z - eye_pos.xyz.z > ds){
780 } else if(eye_pos.xyz.z - cube_cen.xyz.z > ds){
789 void neb2_copy(int xyz, int src, int dest)
795 for(idx1=0; idx1<Neb2_slices; idx1++){
796 for(idx2=0; idx2<Neb2_slices; idx2++){
797 Neb2_cubes[dest][idx1][idx2] = Neb2_cubes[src][idx1][idx2];
802 for(idx1=0; idx1<Neb2_slices; idx1++){
803 for(idx2=0; idx2<Neb2_slices; idx2++){
804 Neb2_cubes[idx1][dest][idx2] = Neb2_cubes[idx1][src][idx2];
809 for(idx1=0; idx1<Neb2_slices; idx1++){
810 for(idx2=0; idx2<Neb2_slices; idx2++){
811 Neb2_cubes[idx1][idx2][dest] = Neb2_cubes[idx1][idx2][src];
821 void neb2_gen_slice(int xyz, int src, vector *cube_center)
824 float h_incw, h_inch, h_incd;
829 ws = Nd->cube_dim / (float)Neb2_slices;
831 hs = Nd->cube_dim / (float)Neb2_slices;
833 ds = Nd->cube_dim / (float)Neb2_slices;
835 cube_corner = *cube_center;
836 cube_corner.xyz.x -= (Nd->cube_dim / 2.0f);
837 cube_corner.xyz.y -= (Nd->cube_dim / 2.0f);
838 cube_corner.xyz.z -= (Nd->cube_dim / 2.0f);
841 for(idx1=0; idx1<Neb2_slices; idx1++){
842 for(idx2=0; idx2<Neb2_slices; idx2++){
843 v = &Neb2_cubes[src][idx1][idx2].pt;
845 v->xyz.x = h_incw + (ws * (float)src) + frand_range(-Nd->wj, Nd->wj);
846 v->xyz.y = h_inch + (hs * (float)idx1) + frand_range(-Nd->hj, Nd->hj);
847 v->xyz.z = h_incd + (ds * (float)idx2) + frand_range(-Nd->dj, Nd->dj);
848 vm_vec_add2(v, &cube_corner);
851 Neb2_cubes[src][idx1][idx2].bmap = neb2_get_bitmap();
853 // set the rotation speed
854 Neb2_cubes[src][idx1][idx2].rot = 0.0f;
855 Neb2_cubes[src][idx1][idx2].rot_speed = frand_range(-max_rotation, max_rotation);
856 Neb2_cubes[src][idx1][idx2].flash = 0.0f;
861 for(idx1=0; idx1<Neb2_slices; idx1++){
862 for(idx2=0; idx2<Neb2_slices; idx2++){
863 v = &Neb2_cubes[idx1][src][idx2].pt;
865 v->xyz.x = h_incw + (ws * (float)idx1) + frand_range(-Nd->wj, Nd->wj);
866 v->xyz.y = h_inch + (hs * (float)src) + frand_range(-Nd->hj, Nd->hj);
867 v->xyz.z = h_incd + (ds * (float)idx2) + frand_range(-Nd->dj, Nd->dj);
868 vm_vec_add2(v, &cube_corner);
871 Neb2_cubes[idx1][src][idx2].bmap = neb2_get_bitmap();
873 // set the rotation speed
874 Neb2_cubes[idx1][src][idx2].rot = 0.0f;
875 Neb2_cubes[idx1][src][idx2].rot_speed = frand_range(-max_rotation, max_rotation);
876 Neb2_cubes[src][idx1][idx2].flash = 0.0f;
881 for(idx1=0; idx1<Neb2_slices; idx1++){
882 for(idx2=0; idx2<Neb2_slices; idx2++){
883 v = &Neb2_cubes[idx1][idx2][src].pt;
885 v->xyz.x = h_incw + (ws * (float)idx1) + frand_range(-Nd->wj, Nd->wj);
886 v->xyz.y = h_inch + (hs * (float)idx2) + frand_range(-Nd->hj, Nd->hj);
887 v->xyz.z = h_incd + (ds * (float)src) + frand_range(-Nd->dj, Nd->dj);
888 vm_vec_add2(v, &cube_corner);
891 Neb2_cubes[idx1][idx2][src].bmap = neb2_get_bitmap();
893 // set the rotation speed
894 Neb2_cubes[idx1][idx2][src].rot = 0.0f;
895 Neb2_cubes[idx1][idx2][src].rot_speed = frand_range(-max_rotation, max_rotation);
896 Neb2_cubes[src][idx1][idx2].flash = 0.0f;
906 // regenerate the player nebula
913 mprintf(("Regenerating local nebula!\n"));
915 // get eye position and orientation
916 neb2_get_eye_pos(&eye_pos);
917 neb2_get_eye_orient(&eye_orient);
919 // determine the corner of the cube
922 // generate slices of the cube
923 for(idx=0; idx<Neb2_slices; idx++){
924 neb2_gen_slice(0, idx, &cube_cen);
928 float max_area = 100000000.0f;
931 dc_get_arg(ARG_FLOAT);
932 max_area = Dc_arg_float;
935 float g3_draw_rotated_bitmap_area(vertex *pnt, float angle, float rad, uint tmap_flags, float area);
937 int frames_total = 0;
940 void neb2_render_player()
943 int idx1, idx2, idx3;
951 float frame_area = max_area;
952 float total_area = 0.0f;
955 // standalone servers can bail here
956 if(Game_mode & GM_STANDALONE_SERVER){
960 // if the mission is not a fullneb mission, skip
961 if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
970 // don't render in lame mode
971 if((Neb2_render_mode == NEB2_RENDER_LAME) || (Neb2_render_mode == NEB2_RENDER_NONE)){
975 // get eye position and orientation
976 neb2_get_eye_pos(&eye_pos);
977 neb2_get_eye_orient(&eye_orient);
979 // maybe swap stuff around if the player crossed a "border"
980 for(idx2=0; idx2<3; idx2++){
981 switch(crossed_border()){
986 cube_cen.xyz.x -= Nd->cube_dim / (float)Neb2_slices;
987 for(idx1=Neb2_slices-1; idx1>0; idx1--){
988 neb2_copy(0, idx1-1, idx1);
990 neb2_gen_slice(0, 0, &cube_cen);
994 cube_cen.xyz.x += Nd->cube_dim / (float)Neb2_slices;
995 for(idx1=0; idx1<Neb2_slices-1; idx1++){
996 neb2_copy(0, idx1+1, idx1);
998 neb2_gen_slice(0, Neb2_slices - 1, &cube_cen);
1002 cube_cen.xyz.y -= Nd->cube_dim / (float)Neb2_slices;
1003 for(idx1=Neb2_slices-1; idx1>0; idx1--){
1004 neb2_copy(1, idx1-1, idx1);
1006 neb2_gen_slice(1, 0, &cube_cen);
1010 cube_cen.xyz.y += Nd->cube_dim / (float)Neb2_slices;
1011 for(idx1=0; idx1<Neb2_slices-1; idx1++){
1012 neb2_copy(1, idx1+1, idx1);
1014 neb2_gen_slice(1, Neb2_slices - 1, &cube_cen);
1018 cube_cen.xyz.z -= Nd->cube_dim / (float)Neb2_slices;
1019 for(idx1=Neb2_slices-1; idx1>0; idx1--){
1020 neb2_copy(2, idx1-1, idx1);
1022 neb2_gen_slice(2, 0, &cube_cen);
1026 cube_cen.xyz.z += Nd->cube_dim / (float)Neb2_slices;
1027 for(idx1=0; idx1<Neb2_slices-1; idx1++){
1028 neb2_copy(2, idx1+1, idx1);
1030 neb2_gen_slice(2, Neb2_slices - 1, &cube_cen);
1035 // if we've switched nebula rendering off
1036 if(Neb2_render_mode == NEB2_RENDER_NONE){
1041 // render the nebula
1042 for(idx1=0; idx1<Neb2_slices; idx1++){
1043 for(idx2=0; idx2<Neb2_slices; idx2++){
1044 for(idx3=0; idx3<Neb2_slices; idx3++){
1048 Neb2_cubes[idx1][idx2][idx3].rot += (Neb2_cubes[idx1][idx2][idx3].rot_speed * flFrametime);
1049 if(Neb2_cubes[idx1][idx2][idx3].rot >= 360.0f){
1050 Neb2_cubes[idx1][idx2][idx3].rot = 0.0f;
1053 // optimization 1 - don't draw backfacing poly's
1055 if(vm_vec_dot_to_point(&eye_orient.v.fvec, &eye_pos, &Neb2_cubes[idx1][idx2][idx3].pt) <= 0.0f){
1060 // rotate and project the vertex into viewspace
1061 g3_rotate_vertex(&p, &Neb2_cubes[idx1][idx2][idx3].pt);
1063 g3_project_vertex(&ptemp);
1065 // get the proper alpha value
1066 alpha = neb2_get_alpha_2shell(Nd->cube_inner, Nd->cube_outer, Nd->prad/4.0f, &Neb2_cubes[idx1][idx2][idx3].pt);
1068 // optimization 2 - don't draw 0.0f or less poly's
1069 // this amounts to big savings
1070 if(alpha <= Nd->break_alpha){
1071 pneb_tossed_alpha++;
1075 // drop poly's which are offscreen at all
1076 // if the poly's are offscreen
1077 if((ptemp.sx < 0.0f) || (ptemp.sx > (float)gr_screen.max_w) || (ptemp.sy < 0.0f) || (ptemp.sy > (float)gr_screen.max_h) ){
1078 alpha = neb2_get_alpha_offscreen(ptemp.sx, ptemp.sy, alpha);
1081 // optimization 2 - don't draw 0.0f or less poly's
1082 // this amounts to big savings
1083 if(alpha <= Nd->break_alpha){
1084 pneb_tossed_alpha++;
1088 // set the bitmap and render
1089 gr_set_bitmap(Neb2_cubes[idx1][idx2][idx3].bmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha + Neb2_cubes[idx1][idx2][idx3].flash);
1092 this_area = g3_draw_rotated_bitmap_area(&p, fl_radian(Neb2_cubes[idx1][idx2][idx3].rot), Nd->prad, TMAP_FLAG_TEXTURED, max_area);
1093 total_area += this_area;
1094 frame_area -= this_area;
1097 g3_draw_rotated_bitmap(&p, fl_radian(Neb2_cubes[idx1][idx2][idx3].rot), Nd->prad, TMAP_FLAG_TEXTURED);
1103 frames_total += frame_rendered;
1105 frame_avg = (float)frames_total / (float)frame_count;
1107 // gr_set_color_fast(&Color_bright_red);
1108 // gr_printf(30, 100, "Area %.3f", total_area);
1109 #ifdef NEB2_THUMBNAIL
1112 gr_set_bitmap(tbmap);
1118 // call this when the player's viewpoint has changed, this will cause the code to properly reset
1119 // the eye's local poofs
1120 void neb2_eye_changed()
1125 // get near and far fog values based upon object type and rendering mode
1126 void neb2_get_fog_values(float *fnear, float *ffar, object *objp)
1130 // default values in case something truly nasty happens
1134 // determine what fog index to use
1135 if(objp->type == OBJ_SHIP){
1136 Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS));
1137 if((objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
1138 fog_index = SHIP_TYPE_FIGHTER_BOMBER;
1140 fog_index = ship_query_general_type(objp->instance);
1141 Assert(fog_index >= 0);
1143 fog_index = SHIP_TYPE_FIGHTER_BOMBER;
1147 // fog everything else like a fighter
1149 fog_index = SHIP_TYPE_FIGHTER_BOMBER;
1153 switch(gr_screen.mode){
1155 *fnear = Neb_ship_fog_vals_glide[fog_index][0];
1156 *ffar = Neb_ship_fog_vals_glide[fog_index][1];
1161 *fnear = Neb_ship_fog_vals_d3d[fog_index][0];
1162 *ffar = Neb_ship_fog_vals_d3d[fog_index][1];
1170 // given a position in space, return a value from 0.0 to 1.0 representing the fog level
1171 float neb2_get_fog_intensity(object *obj)
1173 float f_near, f_far, pct;
1175 // get near and far fog values based upon object type and rendering mode
1176 neb2_get_fog_values(&f_near, &f_far, obj);
1179 pct = vm_vec_dist_quick(&Eye_position, &obj->pos) / (f_far - f_near);
1182 } else if(pct > 1.0f){
1189 // fogging stuff --------------------------------------------------------------------
1191 // do a pre-render of the background nebula
1193 ubyte tpixels[ESIZE * ESIZE * 4]; // for 32 bits
1194 int last_esize = -1;
1195 int this_esize = ESIZE;
1196 extern float Viewer_zoom;
1197 float ex_scale, ey_scale;
1199 void neb2_pre_render(vector *eye_pos, matrix *eye_orient)
1201 // bail early in lame and poly modes
1202 if(Neb2_render_mode != NEB2_RENDER_POF){
1206 // set the view clip
1207 gr_screen.clip_width = this_esize;
1208 gr_screen.clip_height = this_esize;
1209 g3_start_frame(1); // Turn on zbuffering
1210 g3_set_view_matrix(eye_pos, eye_orient, Viewer_zoom);
1211 gr_set_clip(0, 0, this_esize, this_esize);
1213 // render the background properly
1214 // hack - turn off nebula stuff
1215 int neb_save = Neb2_render_mode;
1216 Neb2_render_mode = NEB2_RENDER_NONE;
1218 // draw background stuff nebula
1219 extern void stars_draw_background();
1220 stars_draw_background();
1222 Neb2_render_mode = neb_save;
1224 // HACK - flush d3d here so everything is rendered
1225 if(gr_screen.mode == GR_DIRECT3D){
1226 extern void d3d_flush();
1231 gr_get_region(0, this_esize, this_esize, (ubyte*)tpixels);
1233 #ifdef NEB2_THUMBNAIL
1235 tbmap = bm_create(16, this_esize, this_esize, tpixels, 0);
1236 bm_lock(tbmap, 16, 0);
1241 // maybe do some swizzling
1248 // HACK - flush d3d here so everything is properly cleared
1249 if(gr_screen.mode == GR_DIRECT3D){
1250 extern void d3d_flush();
1254 // if the size has changed between frames, make a new bitmap
1255 if(this_esize != last_esize){
1256 last_esize = this_esize;
1258 // recalculate ex_scale and ey_scale values for looking up color values
1259 ex_scale = (float)this_esize / (float)gr_screen.max_w;
1260 ey_scale = (float)this_esize / (float)gr_screen.max_h;
1263 // restore the game clip stuff
1264 extern void game_set_view_clip();
1265 game_set_view_clip();
1268 // wacky scheme for smoothing colors
1269 int wacky_scheme = 3;
1271 // get the color of the pixel in the small pre-rendered background nebula
1272 #define PIXEL_INDEX_SMALL(xv, yv) ( (this_esize * (yv) * gr_screen.bytes_per_pixel) + ((xv) * gr_screen.bytes_per_pixel) )
1273 void neb2_get_pixel(int x, int y, int *r, int *g, int *b)
1280 // if we're in lame rendering mode, return a constant value
1281 if(Neb2_render_mode == NEB2_RENDER_LAME){
1282 *r = Neb2_background_color[0];
1283 *g = Neb2_background_color[1];
1284 *b = Neb2_background_color[2];
1289 // get the proper pixel index to be looking up
1292 // select screen format
1293 BM_SELECT_SCREEN_FORMAT();
1295 // pixel plus all immediate neighbors (on the small screen - should be more effective than 2 or 1)
1296 xs = (int)(ex_scale * x);
1297 ys = (int)(ey_scale * y);
1299 // sometimes goes over by 1 in direct3d
1300 if(ys >= (this_esize - 1)){
1305 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs, ys)], &rv, &gv, &bv, NULL);
1311 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs - 1, ys)], &rv, &gv, &bv, NULL); // left
1317 if(xs < this_esize - 1){
1318 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs + 1, ys)], &rv, &gv, &bv, NULL); // right
1325 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs, ys - 1)], &rv, &gv, &bv, NULL); // top
1331 if(ys < this_esize - 2){
1332 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs, ys + 1)], &rv, &gv, &bv, NULL); // bottom
1339 if((xs > 0) && (ys > 0)){
1340 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs - 1, ys - 1)], &rv, &gv, &bv, NULL); // upper left
1346 if((xs < this_esize - 1) && (ys < this_esize - 1)){
1347 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs + 1, ys + 1)], &rv, &gv, &bv, NULL); // lower right
1353 if((ys > 0) && (xs < this_esize - 1)){
1354 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs + 1, ys - 1)], &rv, &gv, &bv, NULL); // lower left
1360 if((ys < this_esize - 1) && (xs > 0)){
1361 bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs - 1, ys + 1)], &rv, &gv, &bv, NULL); // upper right
1368 rv = (ubyte) (ra / avg_count);
1369 gv = (ubyte) (ga / avg_count);
1370 bv = (ubyte) (ba / avg_count);
1378 // get the color to fog the background color to
1379 void neb2_get_backg_color(int *r, int *g, int *b)
1381 *r = Neb2_background_color[0];
1382 *g = Neb2_background_color[1];
1383 *b = Neb2_background_color[2];
1386 // set the background color
1387 void neb2_set_backg_color(int r, int g, int b)
1389 Neb2_background_color[0] = r;
1390 Neb2_background_color[1] = g;
1391 Neb2_background_color[2] = b;
1394 // fill in the position of the eye for this frame
1395 void neb2_get_eye_pos(vector *eye)
1397 *eye = Eye_position;
1400 // fill in the eye orient for this frame
1401 void neb2_get_eye_orient(matrix *eye)
1406 // get a (semi) random bitmap to use for a poof
1407 int neb2_get_bitmap()
1411 static int neb2_choose = 0;
1413 // get a random count
1414 count = (int)frand_range(1.0f, 5.0f);
1418 // don't cycle too many times
1421 if(neb2_choose == MAX_NEB2_POOFS - 1){
1428 } while(!(Neb2_poof_flags & (1<<neb2_choose)) && (huh < 10));
1434 if(Neb2_poofs[neb2_choose] < 0){
1435 return Neb2_poofs[0];
1437 return Neb2_poofs[neb2_choose];
1440 // nebula DCF functions ------------------------------------------------------
1442 DCF(neb2, "list nebula console commands")
1444 dc_printf("neb2_fog <X> <float> <float> : set near and far fog planes for ship type X\n");
1445 dc_printf("where X is an integer from 1 - 11\n");
1446 dc_printf("1 = cargo containers, 2 = fighters/bombers, 3 = cruisers\n");
1447 dc_printf("4 = freighters, 5 = capital ships, 6 = transports, 7 = support ships\n");
1448 dc_printf("8 = navbuoys, 9 = sentryguns, 10 = escape pods, 11 = background nebula polygons\n\n");
1450 dc_printf("neb2_max_alpha : max alpha value (0.0 to 1.0) for cloud poofs. 0.0 is completely transparent\n");
1451 dc_printf("neb2_break_alpha : alpha value (0.0 to 1.0) at which faded polygons are not drawn. higher values generally equals higher framerate, with more visual cloud popping\n");
1452 dc_printf("neb2_break_off : how many pixels offscreen (left, right, top, bottom) when a cloud poof becomes fully transparent. Lower values cause quicker fading\n");
1453 dc_printf("neb2_smooth : magic fog smoothing modes (0 - 3)\n");
1454 dc_printf("neb2_select : <int> <int> where the first # is the bitmap to be adjusting (0 through 5), and the second int is a 0 or 1, to turn off and on\n");
1455 dc_printf("neb2_rot : set max rotation speed for poofs\n");
1456 dc_printf("neb2_prad : set cloud poof radius\n");
1457 dc_printf("neb2_cdim : poof cube dimension\n");
1458 dc_printf("neb2_cinner : poof cube inner dimension\n");
1459 dc_printf("neb2_couter : poof cube outer dimension\n");
1460 dc_printf("neb2_jitter : poof jitter\n");
1461 dc_printf("neb2_mode : switch between no nebula, polygon background, amd pof background (0, 1 and 2 respectively)\n\n");
1462 dc_printf("neb2_ff : flash fade/sec\n");
1463 dc_printf("neb2_background : rgb background color\n");
1465 dc_printf("neb2_fog_vals : display all the current settings for all above values\n");
1470 dc_get_arg(ARG_FLOAT);
1471 Nd->prad = Dc_arg_float;
1475 dc_get_arg(ARG_FLOAT);
1476 Nd->cube_dim = Dc_arg_float;
1479 DCF(neb2_cinner, "")
1481 dc_get_arg(ARG_FLOAT);
1482 Nd->cube_inner = Dc_arg_float;
1485 DCF(neb2_couter, "")
1487 dc_get_arg(ARG_FLOAT);
1488 Nd->cube_outer = Dc_arg_float;
1491 DCF(neb2_jitter, "")
1493 dc_get_arg(ARG_FLOAT);
1494 Nd->hj = Nd->dj = Nd->wj = Dc_arg_float;
1501 dc_get_arg(ARG_INT);
1503 dc_get_arg(ARG_FLOAT);
1504 fnear = Dc_arg_float;
1505 dc_get_arg(ARG_FLOAT);
1506 ffar = Dc_arg_float;
1508 if((index >= 1) && (index <= 11) && (fnear >= 0.0f) && (ffar >= 0.0f) && (ffar > fnear)){
1510 Neb_backg_fog_near = fnear;
1511 Neb_backg_fog_far = ffar;
1513 if(gr_screen.mode == GR_GLIDE){
1514 Neb_ship_fog_vals_glide[index][0] = fnear;
1515 Neb_ship_fog_vals_glide[index][1] = ffar;
1517 Assert(gr_screen.mode == GR_DIRECT3D || gr_screen.mode == GR_OPENGL);
1518 Neb_ship_fog_vals_d3d[index][0] = fnear;
1519 Neb_ship_fog_vals_d3d[index][1] = ffar;
1525 DCF(neb2_max_alpha, "")
1527 dc_get_arg(ARG_FLOAT);
1528 Nd->max_alpha_glide = Dc_arg_float;
1531 DCF(neb2_break_alpha, "")
1533 dc_get_arg(ARG_FLOAT);
1534 Nd->break_alpha = Dc_arg_float;
1537 DCF(neb2_break_off, "")
1539 dc_get_arg(ARG_INT);
1540 Nd->break_y = (float)Dc_arg_int;
1541 Nd->break_x = Nd->break_y * 1.3333f;
1544 DCF(neb2_smooth, "")
1547 dc_get_arg(ARG_INT);
1549 if((index >= 0) && (index <= 3)){
1550 wacky_scheme = index;
1554 DCF(neb2_select, "")
1556 dc_get_arg(ARG_INT);
1557 int bmap = Dc_arg_int;
1558 if((bmap >= 0) && (bmap < Neb2_poof_count)){
1559 dc_get_arg(ARG_INT);
1562 Neb2_poof_flags |= (1<<bmap);
1564 Neb2_poof_flags &= ~(1<<bmap);
1571 dc_get_arg(ARG_FLOAT);
1572 max_rotation = Dc_arg_float;
1577 dc_get_arg(ARG_FLOAT);
1578 neb2_flash_fade = Dc_arg_float;
1583 dc_get_arg(ARG_INT);
1586 case NEB2_RENDER_NONE:
1587 Neb2_render_mode = NEB2_RENDER_NONE;
1590 case NEB2_RENDER_POLY:
1591 Neb2_render_mode = NEB2_RENDER_POLY;
1594 case NEB2_RENDER_POF:
1595 Neb2_render_mode = NEB2_RENDER_POF;
1596 stars_set_background_model(BACKGROUND_MODEL_FILENAME, "Eraseme3");
1599 case NEB2_RENDER_LAME:
1600 Neb2_render_mode = NEB2_RENDER_LAME;
1605 DCF(neb2_slices, "")
1607 dc_get_arg(ARG_INT);
1608 Neb2_slices = Dc_arg_int;
1612 DCF(neb2_background, "")
1616 dc_get_arg(ARG_INT);
1618 dc_get_arg(ARG_INT);
1620 dc_get_arg(ARG_INT);
1623 Neb2_background_color[0] = r;
1624 Neb2_background_color[1] = g;
1625 Neb2_background_color[2] = b;
1628 DCF(neb2_fog_vals, "")
1630 dc_printf("neb2_fog : \n");
1631 if(gr_screen.mode == GR_GLIDE){
1632 dc_printf("(1)cargo containers : %f, %f\n", Neb_ship_fog_vals_glide[1][0], Neb_ship_fog_vals_glide[1][1]);
1633 dc_printf("(2)fighters/bombers : %f, %f\n", Neb_ship_fog_vals_glide[2][0], Neb_ship_fog_vals_glide[2][1]);
1634 dc_printf("(3)cruisers : %f, %f\n", Neb_ship_fog_vals_glide[3][0], Neb_ship_fog_vals_glide[3][1]);
1635 dc_printf("(4)freighters : %f, %f\n", Neb_ship_fog_vals_glide[4][0], Neb_ship_fog_vals_glide[4][1]);
1636 dc_printf("(5)cap ships : %f, %f\n", Neb_ship_fog_vals_glide[5][0], Neb_ship_fog_vals_glide[5][1]);
1637 dc_printf("(6)transports : %f, %f\n", Neb_ship_fog_vals_glide[6][0], Neb_ship_fog_vals_glide[6][1]);
1638 dc_printf("(7)support ships : %f, %f\n", Neb_ship_fog_vals_glide[7][0], Neb_ship_fog_vals_glide[7][1]);
1639 dc_printf("(8)navbuoys : %f, %f\n", Neb_ship_fog_vals_glide[8][0], Neb_ship_fog_vals_glide[8][1]);
1640 dc_printf("(9)sentry guns : %f, %f\n", Neb_ship_fog_vals_glide[9][0], Neb_ship_fog_vals_glide[9][1]);
1641 dc_printf("(10)escape pods : %f, %f\n", Neb_ship_fog_vals_glide[10][0], Neb_ship_fog_vals_glide[10][1]);
1642 dc_printf("(11)background polys : %f, %f\n\n", Neb_backg_fog_near, Neb_backg_fog_far);
1645 Assert(gr_screen.mode == GR_DIRECT3D || gr_screen.mode == GR_OPENGL);
1646 dc_printf("(1)cargo containers : %f, %f\n", Neb_ship_fog_vals_d3d[1][0], Neb_ship_fog_vals_d3d[1][1]);
1647 dc_printf("(2)fighters/bombers : %f, %f\n", Neb_ship_fog_vals_d3d[2][0], Neb_ship_fog_vals_d3d[2][1]);
1648 dc_printf("(3)cruisers : %f, %f\n", Neb_ship_fog_vals_d3d[3][0], Neb_ship_fog_vals_d3d[3][1]);
1649 dc_printf("(4)freighters : %f, %f\n", Neb_ship_fog_vals_d3d[4][0], Neb_ship_fog_vals_d3d[4][1]);
1650 dc_printf("(5)cap ships : %f, %f\n", Neb_ship_fog_vals_d3d[5][0], Neb_ship_fog_vals_d3d[5][1]);
1651 dc_printf("(6)transports : %f, %f\n", Neb_ship_fog_vals_d3d[6][0], Neb_ship_fog_vals_d3d[6][1]);
1652 dc_printf("(7)support ships : %f, %f\n", Neb_ship_fog_vals_d3d[7][0], Neb_ship_fog_vals_d3d[7][1]);
1653 dc_printf("(8)navbuoys : %f, %f\n", Neb_ship_fog_vals_d3d[8][0], Neb_ship_fog_vals_d3d[8][1]);
1654 dc_printf("(9)sentry guns : %f, %f\n", Neb_ship_fog_vals_d3d[9][0], Neb_ship_fog_vals_d3d[9][1]);
1655 dc_printf("(10)escape pods : %f, %f\n", Neb_ship_fog_vals_d3d[10][0], Neb_ship_fog_vals_d3d[10][1]);
1656 dc_printf("(11)background polys : %f, %f\n\n", Neb_backg_fog_near, Neb_backg_fog_far);
1658 dc_printf("neb2_max_alpha : %f\n", Nd->max_alpha_glide);
1659 dc_printf("neb2_break_alpha : %f\n", Nd->break_alpha);
1660 dc_printf("neb2_break_off : %d\n", (int)Nd->break_y);
1661 dc_printf("neb2_smooth : %d\n", wacky_scheme);
1662 dc_printf("neb2_toggle : %s\n", Neb2_render_mode ? "on" : "off");
1663 dc_printf("neb2_rot : %f\n", max_rotation);
1664 dc_printf("neb2_prad : %f\n", Nd->prad);
1665 dc_printf("neb2_cdim : %f\n", Nd->cube_dim);
1666 dc_printf("neb2_couter : %f\n", Nd->cube_outer);
1667 dc_printf("neb2_cinner : %f\n", Nd->cube_inner);
1668 dc_printf("neb2_jitter : %f\n", Nd->wj);
1669 dc_printf("neb2_ff : %f\n", neb2_flash_fade);
1670 dc_printf("neb2_background : %d %d %d\n", Neb2_background_color[0], Neb2_background_color[1], Neb2_background_color[2]);
1674 DCF(neb2_create, "create a basic nebula")
1680 dc_get_arg(ARG_INT);
1681 if(Dc_arg_type & ARG_INT){
1682 points = Dc_arg_int;
1684 dc_get_arg(ARG_FLOAT);
1685 if(Dc_arg_type & ARG_FLOAT){
1686 rad1 = Dc_arg_float;
1688 dc_get_arg(ARG_FLOAT);
1689 if(Dc_arg_type & ARG_FLOAT){
1690 rad2 = Dc_arg_float;
1692 neb2_create(&vmd_zero_vector, points, rad1, -1.0f, rad2);
1695 DCF(neb2_del, "delete existing nebulae")
1697 for(int idx=0; idx<MAX_OBJECTS; idx++){
1698 if(Objects[idx].type == OBJ_NEB2){
1705 float magic1 = 1000.0f;
1706 float magic2 = -1.0f;
1707 float magic3 = 700.0f;
1708 DCF(neb2_def, "create a default nebula")
1711 vm_vec_make(&a, 0.0f, 0.0f, 0.0f);
1712 vm_vec_make(&b, 3600.0f, 700.0f, 0.0f);
1713 vm_vec_make(&c, -3000.0f, 20.0f, 480.0f);
1714 vm_vec_make(&d, -4000.0f, 100.0f, 100.0f);
1715 vm_vec_make(&e, 0.0f, 3000.0f, -400.0f);
1716 vm_vec_make(&f, 670.0f, -2500.0f, -1600.0f);
1718 neb2_create(&a, magic0, magic1, magic2, magic3);
1719 neb2_create(&b, magic0, magic1, magic2, magic3);
1720 neb2_create(&c, magic0, magic1, magic2, magic3);
1721 neb2_create(&d, magic0, magic1, magic2, magic3);
1722 neb2_create(&e, magic0, magic1, magic2, magic3);
1723 neb2_create(&f, magic0, magic1, magic2, magic3);
1726 DCF(neb2_plr, "regenerate the player's nebula")
1731 DCF(neb2_stats, "display info about the nebula rendering")
1733 dc_printf("Player poofs tried : %d\n", pneb_tried);
1734 dc_printf("Player poofs tossed (alpha): %d\n", pneb_tossed_alpha);
1735 dc_printf("Player poofs tossed (dot): %d\n", pneb_tossed_dot);
1736 dc_printf("Player poofs tossed (off): %d\n", pneb_tossed_off);
1738 dc_printf("Poofs tried : %d\n", neb_tried);
1739 dc_printf("Poofs tossed (alpha): %d\n", neb_tossed_alpha);
1740 dc_printf("Poofs tossed (dot): %d\n", neb_tossed_dot);
1741 dc_printf("Poofs tossed (count): %d\n", neb_tossed_count);
1743 dc_printf("Avg poofs/frame: %f\n", frame_avg);
1746 // create a nebula object, return objnum of the nebula or -1 on fail
1747 // NOTE : in most cases you will want to pass -1.0f for outer_radius. Trust me on this
1748 int neb2_create(vector *offset, int num_poofs, float inner_radius, float outer_radius, float max_poof_radius)
1754 // delete a nebula object
1755 void neb2_delete(object *objp)
1760 // renders a nebula object
1761 void neb2_render(object *objp)
1766 // preprocess the nebula object before simulation
1767 void neb2_process_pre(object *objp)
1772 // process the nebula object after simulating, but before rendering
1773 void neb2_process_post(object *objp)
1780 // add N poofs to the inner shell of the nebula
1781 // if orient and ang are specified, generate the poofs so that they are "visible" around
1782 // the orient v.fvec in a cone of ang degrees
1783 void neb2_add_inner(neb2 *neb, int num_poofs, matrix *orient, float ang)
1786 vector pt, pt2, pt3;
1787 int final_index = (neb->num_poofs + num_poofs) > neb->max_poofs ? neb->max_poofs : (neb->num_poofs + num_poofs);
1789 // add the points a pick a random bitmap
1790 for(idx=neb->num_poofs; idx<final_index; idx++){
1792 // put a point directly in front of the player, between 0 and inner_radius distance away
1793 vm_vec_copy_scale(&pt, &orient->v.fvec, frand_range(neb->magic_num, neb->inner_radius));
1795 // rotate the point by -ang <-> ang around the up vector
1796 vm_rot_point_around_line(&pt2, &pt, fl_radian(frand_range(-ang, ang)), &vmd_zero_vector, &orient->uvec);
1798 // rotate the point by -ang <-> ang around the right vector
1799 vm_rot_point_around_line(&pt3, &pt2, fl_radian(frand_range(-ang, ang)), &vmd_zero_vector, &orient->rvec);
1801 // now add in the center of the nebula so its placed properly (ie, not around the origin)
1802 vm_vec_add(&neb->pts[idx], &pt3, &Objects[neb->objnum].pos);
1804 neb->pts[idx].xyz.x = frand_range(-1.0f * neb->inner_radius, neb->inner_radius) + Objects[neb->objnum].pos.xyz.x;
1805 neb->pts[idx].xyz.y = frand_range(-1.0f * neb->inner_radius, neb->inner_radius) + Objects[neb->objnum].pos.xyz.y;
1806 neb->pts[idx].xyz.z = frand_range(-1.0f * neb->inner_radius, neb->inner_radius) + Objects[neb->objnum].pos.xyz.z;
1809 neb->bmaps[idx] = (int)frand_range(0.0f, (float)2);
1814 // add N poofs to the outer shell of the nebula
1815 // if orient and ang are specified, generate the poofs so that they are "visible" around
1816 // the orient v.fvec in a cone of ang degrees
1817 void neb2_add_outer(neb2 *neb, int num_poofs, matrix *orient, float ang)
1821 vector pt, pt2, pt3;
1822 int final_index = (neb->num_poofs + num_poofs) > neb->max_poofs ? neb->max_poofs : (neb->num_poofs + num_poofs);
1824 // add the points a pick a random bitmap
1825 for(idx=neb->num_poofs; idx<final_index; idx++){
1827 // put a point directly in front of the player, at outer_radius distance away
1828 vm_vec_copy_scale(&pt, &orient->v.fvec, neb->outer_radius);
1830 // rotate the point by -ang <-> ang around the up vector
1831 vm_rot_point_around_line(&pt2, &pt, fl_radian(frand_range(-ang, ang)), &vmd_zero_vector, &orient->uvec);
1833 // rotate the point by -ang <-> ang around the right vector
1834 vm_rot_point_around_line(&pt3, &pt2, fl_radian(frand_range(-ang, ang)), &vmd_zero_vector, &orient->rvec);
1836 // now add in the center of the nebula so its placed properly (ie, not around the origin)
1837 vm_vec_add(&neb->pts[idx], &pt, &Objects[neb->objnum].pos);
1839 // get a random point on the very outer radius, using spherical coords
1840 phi = fl_radian(frand_range(0.0f, 360.0f));
1841 theta = fl_radian(frand_range(0.0f, 360.f));
1843 neb->pts[idx].xyz.x = neb->outer_radius * (float)sin(phi) * (float)cos(theta);
1844 neb->pts[idx].xyz.y = neb->outer_radius * (float)sin(phi) * (float)sin(theta);
1845 neb->pts[idx].xyz.z = neb->outer_radius * (float)cos(phi);
1848 // pick a random bitmap and increment the # of poofs
1849 neb->bmaps[idx] = (int)frand_range(0.0f, (float)2);
1854 // return the alpha the passed poof should be rendered with, for a 1 shell nebula
1855 float neb2_get_alpha_1shell(neb2 *neb, int poof_index)
1861 // get the eye position
1862 neb2_get_eye_pos(&eye_pos);
1864 // determine what alpha to draw this bitmap with
1865 // higher alpha the closer the bitmap gets to the eye
1866 dist = vm_vec_dist_quick(&eye_pos, &neb->pts[poof_index]);
1868 // at poof radius or greater, alpha should be 1.0
1869 // scale from 0.0 to 1.0 between radius and magic
1870 if(dist >= neb->max_poof_radius){
1871 return max_alpha - 0.0001f;
1872 } else if(dist > neb->magic_num){
1873 // alpha per meter between the magic # and the max radius
1874 alpha = max_alpha / (neb->max_poof_radius - neb->magic_num);
1876 // above value times the # of meters away we are
1877 return alpha * (dist - neb->magic_num);
1880 // otherwise transparent