/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ /* * $Logfile: /Freespace2/code/Nebula/Neb.cpp $ * $Revision: 2.44 $ * $Date: 2005-12-29 08:08:39 $ * $Author: wmcoolmon $ * * Nebula effect * * $Log: not supported by cvs2svn $ * Revision 2.43 2005/12/08 15:17:34 taylor * fix several bad crash related problems from WMC's commits on the 4th * * Revision 2.42 2005/12/04 19:07:48 wmcoolmon * Final commit of codebase * * Revision 2.41 2005/11/13 06:44:18 taylor * small bit of EFF cleanup * add -img2dds support * cleanup some D3D stuff (missing a lot since the old code is so unstable I couldn't get it working like I wanted) * some minor OGL cleanup and small performance changes * converge the various pcx_read_bitmap* functions into one * cleanup/rename/remove some cmdline options * * Revision 2.40 2005/10/30 06:44:57 wmcoolmon * Codebase commit - nebula.tbl, scripting, new dinky explosion/shockwave stuff, moving muzzle flashes * * Revision 2.39 2005/10/09 08:03:20 wmcoolmon * New SEXP stuff * * Revision 2.38 2005/06/21 00:20:24 taylor * in the model _render functions change "light_ignore_id" to "objnum" since that's what it really is * and this makes it so much easier to realize that * properly deal with the fact that objnum can be -1 in model_really_render() * add NULL check to neb2_get_fog_values() so that it can just send back defaults if objp is NULL * small compiler warning fix for neb code * * Revision 2.37 2005/05/12 17:49:15 taylor * use vm_malloc(), vm_free(), vm_realloc(), vm_strdup() rather than system named macros * fixes various problems and is past time to make the switch * * Revision 2.36 2005/04/25 00:27:32 wmcoolmon * Commented out unneeded array (Glide) * * Revision 2.35 2005/04/05 05:53:20 taylor * s/vector/vec3d/g, better support for different compilers (Jens Granseuer) * * Revision 2.34 2005/03/03 06:05:30 wmcoolmon * Merge of WMC's codebase. "Features and bugs, making Goober say "Grr!", as release would be stalled now for two months for sure" * * Revision 2.33 2005/02/23 04:55:08 taylor * more bm_unload() -> bm_release() changes * * Revision 2.32 2005/02/04 20:06:04 taylor * merge with Linux/OSX tree - p0204-2 * * Revision 2.31 2005/01/22 22:53:07 wmcoolmon * Instead of trying to allocate a ridiculously large buffer if the file is defined but doesn't exist, give a warning. Someone with nebula-code experience should probably double-check this; also added jpg and TGA support. * * Revision 2.30 2005/01/10 06:58:12 wmcoolmon * Bug-guard * * Revision 2.29 2004/10/31 21:56:09 taylor * new bmpman support, new OGL fixes don't need the freaky neb lighting fix anymore * * Revision 2.28 2004/07/26 20:47:41 Kazan * remove MCD complete * * Revision 2.27 2004/07/12 16:32:56 Kazan * MCD - define _MCD_CHECK to use memory tracking * * Revision 2.26 2004/07/01 01:12:33 bobboau * implemented index buffered background bitmaps, * OGL people you realy should get this implemented * * Revision 2.25 2004/04/18 19:39:13 randomtiger * Added -2d_poof command which allows access to 2D poof rendering * Added -radar_reduce to launcher flag description structure * * Revision 2.24 2004/04/14 10:25:50 taylor * don't page in neb poofs unless in a neb2 mission, fix OGL whiteout issue * * Revision 2.23 2004/04/11 13:56:33 randomtiger * Adding batching functions here and there and into gr_screen for use with OGL when its ready. * * Revision 2.22 2004/04/03 02:55:49 bobboau * commiting recent minor bug fixes * * Revision 2.21 2004/03/17 04:07:30 bobboau * new fighter beam code * fixed old after burner trails * had to bump a few limits, working on some dynamic solutions * a few fixed to background POF rendering * fixing asorted bugs * * Revision 2.20 2004/03/05 09:02:07 Goober5000 * Uber pass at reducing #includes * --Goober5000 * * Revision 2.19 2004/02/28 14:14:57 randomtiger * Removed a few uneeded if DIRECT3D's. * Set laser function to only render the effect one sided. * Added some stuff to the credits. * Set D3D fogging to fall back to vertex fog if table fog not supported. * * Revision 2.18 2004/02/14 00:18:34 randomtiger * Please note that from now on OGL will only run with a registry set by Launcher v4. See forum for details. * OK, these changes effect a lot of file, I suggest everyone updates ASAP: * Removal of many files from project. * Removal of meanless Gr_bitmap_poly variable. * Removal of glide, directdraw, software modules all links to them, and all code specific to those paths. * Removal of redundant Fred paths that arent needed for Fred OGL. * Have seriously tidied the graphics initialisation code and added generic non standard mode functionality. * Fixed many D3D non standard mode bugs and brought OGL up to the same level. * Removed texture section support for D3D8, voodoo 2 and 3 cards will no longer run under fs2_open in D3D, same goes for any card with a maximum texture size less than 1024. * * Revision 2.17 2004/02/13 04:17:14 randomtiger * Turned off fog in OGL for Fred. * Simulated speech doesnt say tags marked by $ now. * The following are fixes to issues that came up testing TBP in fs2_open and fred2_open: * Changed vm_vec_mag and parse_tmap to fail gracefully on bad data. * Error now given on missing briefing icon and bad ship normal data. * Solved more species divide by zero error. * Fixed neb cube crash. * * Revision 2.16 2004/02/04 04:28:15 Goober5000 * fixed Asserts in two places and commented out an unneeded variable * --Goober5000 * * Revision 2.15 2004/01/12 21:12:42 randomtiger * Added fix for fogging debris in D3D htl. * * Revision 2.14 2003/11/29 10:52:10 randomtiger * Turned off D3D file mapping, its using too much memory which may be hurting older systems and doesnt seem to be providing much of a speed benifit. * Added stats command for ingame stats on memory usage. * Trys to play intro.mve and intro.avi, just to be safe since its not set by table. * Added fix for fonts wrapping round in non standard hi res modes. * Changed D3D mipmapping to a good value to suit htl mode. * Added new fog colour method which makes use of the bitmap, making this htl feature backcompatible again. * * Revision 2.13 2003/11/19 20:37:24 randomtiger * Almost fully working 32 bit pcx, use -pcx32 flag to activate. * Made some commandline variables fit the naming standard. * Changed timerbar system not to run pushes and pops if its not in use. * Put in a note about not uncommenting asserts. * Fixed up a lot of missing POP's on early returns? * Perhaps the motivation for Assert functionality getting commented out? * Fixed up some bad asserts. * Changed nebula poofs to render in 2D in htl, it makes it look how it used to in non htl. (neb.cpp,1248) * Before the poofs were creating a nasty stripe effect where they intersected with ships hulls. * Put in a special check for the signs of that D3D init bug I need to lock down. * * Revision 2.12 2003/11/17 04:25:57 bobboau * made the poly list dynamicly alocated, * started work on fixing the node model not rendering, * but most of that got commented out so I wouldn't have to deal with it * while mucking about with the polylist * * Revision 2.11 2003/11/16 04:09:21 Goober5000 * language * * Revision 2.10 2003/11/11 03:56:12 bobboau * lots of bug fixing, much of it in nebula and bitmap drawing * * Revision 2.9 2003/11/11 02:15:46 Goober5000 * ubercommit - basically spelling and language fixes with some additional * warnings disabled * --Goober5000 * * Revision 2.8 2003/10/14 17:39:16 randomtiger * Implemented hardware fog for the HT&L code path. * It doesnt use the backgrounds anymore but its still an improvement. * Currently it fogs to a brighter colour than it should because of Bob specular code. * I will fix this after discussing it with Bob. * * Also tided up some D3D stuff, a cmdline variable name and changed a small bit of * the htl code to use the existing D3D engine instead of work around it. * And added extra information in version number on bottom left of frontend screen. * * Revision 2.7 2003/09/26 14:37:15 bobboau * commiting Hardware T&L code, everything is ifdefed out with the compile flag HTL * still needs a lot of work, ubt the frame rates were getting with it are incredable * the biggest problem it still has is a bad lightmanegment system, and the zbuffer * doesn't work well with things still getting rendered useing the sofware pipeline, like thrusters, * and weapons, I think these should be modifyed to be sent through hardware, * it would be slightly faster and it would likely fix the problem * * also the thruster glow/particle stuff I did is now in. * * Revision 2.6 2003/03/19 23:06:40 Goober5000 * bit o' housecleaning * --Goober5000 * * Revision 2.5 2003/03/19 09:05:26 Goober5000 * more housecleaning, this time for debug warnings * --Goober5000 * * Revision 2.4 2003/03/19 06:22:58 Goober5000 * added typecasting to get rid of some build warnings * --Goober5000 * * Revision 2.3 2003/03/18 10:07:04 unknownplayer * The big DX/main line merge. This has been uploaded to the main CVS since I can't manage to get it to upload to the DX branch. Apologies to all who may be affected adversely, but I'll work to debug it as fast as I can. * * Revision 2.2 2002/11/18 21:32:48 phreak * added some lines that makes ogl work in windowed mode for fullneb - phreak * * Revision 2.1.2.3 2002/11/11 21:26:04 randomtiger * * Tided up D3DX8 calls, did some documentation and add new file: grd3dcalls.cpp. - RT * * Revision 2.1.2.2 2002/11/10 02:44:43 randomtiger * * Have put in a hack to get fog working in D3D8 but the method V has used is frowned * on in D3D8 and will likely be a lot slower than the same thing in D3D5. - RT * * Revision 2.1.2.1 2002/10/26 09:55:42 unknownplayer * * Fixed the nebula flicker bug. Check the NO_DIRECT3D conditional compile * sections in the future for bits of code which may cause problems due to hacks * correcting for DirectX5 that no longer apply. * * Revision 2.1 2002/08/01 01:41:07 penguin * The big include file move * * Revision 2.0 2002/06/03 04:02:25 penguin * Warpcore CVS sync * * Revision 1.3 2002/05/09 13:49:30 mharris * Added ifndef NO_DIRECT3D * * Revision 1.2 2002/05/04 04:52:22 mharris * 1st draft at porting * * Revision 1.1 2002/05/02 18:03:10 mharris * Initial checkin - converted filenames and includes to lower case * * * 50 8/30/99 5:01p Dave * Made d3d do less state changing in the nebula. Use new chat server for * PXO. * * 49 8/10/99 6:54p Dave * Mad optimizations. Added paging to the nebula effect. * * 48 8/05/99 2:05a Dave * Whee. * * 47 7/30/99 10:55a Anoop * Hmm. Fixed release build problem again, with area-rotated bitmaps. * * 46 7/29/99 10:47p Dave * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs. * * 44 7/29/99 12:05a Dave * Nebula speed optimizations. * * 43 7/19/99 7:20p Dave * Beam tooling. Specialized player-killed-self messages. Fixed d3d nebula * pre-rendering. * * 42 7/18/99 5:20p Dave * Jump node icon. Fixed debris fogging. Framerate warning stuff. * * 41 7/13/99 1:15p Dave * 32 bit support. Whee! * * 40 7/09/99 5:54p Dave * Seperated cruiser types into individual types. Added tons of new * briefing icons. Campaign screen. * * 39 7/07/99 10:44a Jamesa * Make sure the nebula regens properly after loading a mission. * * 38 6/11/99 2:32p Dave * Toned down nebula brightness a bit. * * 37 5/26/99 3:39p Dave * Fixed nebula regeneration problem. Removed optimizations from * neblightning.cpp * * 36 5/26/99 11:46a Dave * Added ship-blasting lighting and made the randomization of lighting * much more customizable. * * 35 5/24/99 5:45p Dave * Added detail levels to the nebula, with a decent speedup. Split nebula * lightning into its own section. * * $NoKeywords: $ */ #include "nebula/neb.h" #include "render/3d.h" #include "bmpman/bmpman.h" #include "object/object.h" #include "freespace2/freespace.h" #include "starfield/starfield.h" #include "parse/parselo.h" #include "pcxutils/pcxutils.h" #include "tgautils/tgautils.h" #include "jpgutils/jpgutils.h" #include "ddsutils/ddsutils.h" #include "mission/missionparse.h" #include "ship/ship.h" #include "cmdline/cmdline.h" // -------------------------------------------------------------------------------------------------------- // NEBULA DEFINES/VARS // bool Nebula_sexp_used = false; unsigned char Neb2_fog_colour_r = 0; unsigned char Neb2_fog_colour_g = 0; unsigned char Neb2_fog_colour_b = 0; ubyte *Neb2_htl_fog_data = NULL; int Neb2_max_fog_value = 0; int Neb2_cur_fog_value = 0; const int Neb2_cur_fog_factor = 10; // #define NEB2_THUMBNAIL /* 3D CARDS THAT FOG PROPERLY Voodoo1 Voodoo2 G200 TNT 3D CARDS THAT DON'T FOG PROPERLY Permedia2 AccelStar II */ // if nebula rendering is active (DCF stuff - not mission specific) int Neb2_render_mode = NEB2_RENDER_NONE; // array of neb2 poofs char Neb2_poof_filenames[MAX_NEB2_POOFS][MAX_FILENAME_LEN] = { "", "", "", "", "", "" }; int Neb2_poofs[MAX_NEB2_POOFS] = { -1, -1, -1, -1, -1, -1 }; int Neb2_poof_flags = ( (1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4) | (1<<5) ); int Neb2_poof_count = 0; // array of neb2 bitmaps char Neb2_bitmap_filenames[MAX_NEB2_BITMAPS][MAX_FILENAME_LEN] = { "", "", "", "", "", "" }; int Neb2_bitmap[MAX_NEB2_BITMAPS] = { -1, -1, -1, -1, -1, -1 }; int Neb2_bitmap_count = 0; // texture to use for this level char Neb2_texture_name[MAX_FILENAME_LEN] = ""; // nebula flags #define NF_USED (1<<0) // if this nebula slot is used float max_rotation = 3.75f; float neb2_flash_fade = 0.3f; // fog values for different ship types //Why the heck is this still here? Commenting out. -WMC /* float Neb_ship_fog_vals_glide[MAX_SHIP_TYPE_COUNTS][2] = { {0.0f, 0.0f}, // SHIP_TYPE_NONE {10.0f, 500.0f}, // SHIP_TYPE_CARGO {10.0f, 500.0f}, // SHIP_TYPE_FIGHTER_BOMBER {10.0f, 600.0f}, // SHIP_TYPE_CRUISER {10.0f, 600.0f}, // SHIP_TYPE_FREIGHTER {10.0f, 750.0f}, // SHIP_TYPE_CAPITAL {10.0f, 500.0f}, // SHIP_TYPE_TRANSPORT {10.0f, 500.0f}, // SHIP_TYPE_REPAIR_REARM {10.0f, 500.0f}, // SHIP_TYPE_NAVBUOY {10.0f, 500.0f}, // SHIP_TYPE_SENTRYGUN {10.0f, 600.0f}, // SHIP_TYPE_ESCAPEPOD {10.0f, 1000.0f}, // SHIP_TYPE_SUPERCAP {10.0f, 500.0f}, // SHIP_TYPE_STEALTH {10.0f, 500.0f}, // SHIP_TYPE_FIGHTER {10.0f, 500.0f}, // SHIP_TYPE_BOMBER {10.0f, 750.0f}, // SHIP_TYPE_DRYDOCK {10.0f, 600.0f}, // SHIP_TYPE_AWACS {10.0f, 600.0f}, // SHIP_TYPE_GAS_MINER {10.0f, 600.0f}, // SHIP_TYPE_CORVETTE {10.0f, 1000.0f}, // SHIP_TYPE_KNOSSOS_DEVICE }; */ /* float Neb_ship_fog_vals_d3d[MAX_SHIP_TYPE_COUNTS][2] = { {0.0f, 0.0f}, // SHIP_TYPE_NONE {10.0f, 500.0f}, // SHIP_TYPE_CARGO {10.0f, 500.0f}, // SHIP_TYPE_FIGHTER_BOMBER {10.0f, 600.0f}, // SHIP_TYPE_CRUISER {10.0f, 600.0f}, // SHIP_TYPE_FREIGHTER {10.0f, 750.0f}, // SHIP_TYPE_CAPITAL {10.0f, 500.0f}, // SHIP_TYPE_TRANSPORT {10.0f, 500.0f}, // SHIP_TYPE_REPAIR_REARM {10.0f, 500.0f}, // SHIP_TYPE_NAVBUOY {10.0f, 500.0f}, // SHIP_TYPE_SENTRYGUN {10.0f, 600.0f}, // SHIP_TYPE_ESCAPEPOD {10.0f, 1000.0f}, // SHIP_TYPE_SUPERCAP {10.0f, 500.0f}, // SHIP_TYPE_STEALTH {10.0f, 500.0f}, // SHIP_TYPE_FIGHTER {10.0f, 500.0f}, // SHIP_TYPE_BOMBER {10.0f, 750.0f}, // SHIP_TYPE_DRYDOCK {10.0f, 600.0f}, // SHIP_TYPE_AWACS {10.0f, 600.0f}, // SHIP_TYPE_GAS_MINER {10.0f, 600.0f}, // SHIP_TYPE_CORVETTE {10.0f, 1000.0f}, // SHIP_TYPE_KNOSSOS_DEVICE }; */ //WMC - these were originally indexed to SHIP_TYPE_FIGHTER_BOMBER const static float Default_fog_near = 10.0f; const static float Default_fog_far = 500.0f; // fog near and far values for rendering the background nebula #define NEB_BACKG_FOG_NEAR_GLIDE 2.5f #define NEB_BACKG_FOG_NEAR_D3D 4.5f #define NEB_BACKG_FOG_FAR_GLIDE 10.0f #define NEB_BACKG_FOG_FAR_D3D 10.0f float Neb_backg_fog_near = NEB_BACKG_FOG_NEAR_GLIDE; float Neb_backg_fog_far = NEB_BACKG_FOG_FAR_GLIDE; // stats int pneb_tried = 0; // total pnebs tried to render int pneb_tossed_alpha = 0; // pnebs tossed because of alpha optimization int pneb_tossed_dot = 0; // pnebs tossed because of dot product int pneb_tossed_off = 0; // pnebs tossed because of being offscree int neb_tried = 0; // total nebs tried int neb_tossed_alpha = 0; // nebs tossed because of alpha int neb_tossed_dot = 0; // nebs tossed because of dot product int neb_tossed_count = 0; // nebs tossed because of max render count // the AWACS suppresion level for the nebula float Neb2_awacs = -1.0f; // how many "slices" are in the current player nebuls int Neb2_slices = 5; cube_poof Neb2_cubes[MAX_CPTS][MAX_CPTS][MAX_CPTS]; // nebula detail level typedef struct neb2_detail { float max_alpha_glide; // max alpha for this detail level in Glide float max_alpha_d3d; // max alpha for this detail level in D3d float break_alpha; // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot float break_x, break_y; // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen float cube_dim; // total dimension of player poof cube float cube_inner; // inner radius of the player poof cube float cube_outer; // outer radius of the player pood cube float prad; // radius of the poofs float wj, hj, dj; // width, height, depth jittering. best left at 1.0 } neb2_detail; neb2_detail Neb2_detail[MAX_DETAIL_LEVEL] = { { // lowest detail level 0.575f, // max alpha for this detail level in Glide 0.71f, // max alpha for this detail level in D3d 0.13f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot 150.0f, 150.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen 510.0f, // total dimension of player poof cube 50.0f, // inner radius of the player poof cube 250.0f, // outer radius of the player pood cube 120.0f, // radius of the poofs 1.0f, 1.0f, 1.0f // width, height, depth jittering. best left at 1.0 }, { // 2nd lowest detail level 0.575f, // max alpha for this detail level in Glide 0.71f, // max alpha for this detail level in D3d 0.125f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot 300.0f, 300.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen 550.0f, // total dimension of player poof cube 100.0f, // inner radius of the player poof cube 250.0f, // outer radius of the player pood cube 125.0f, // radius of the poofs 1.0f, 1.0f, 1.0f // width, height, depth jittering. best left at 1.0 }, { // 2nd highest detail level 0.575f, // max alpha for this detail level in Glide 0.71f, // max alpha for this detail level in D3d 0.1f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot 300.0f, 300.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen 550.0f, // total dimension of player poof cube 150.0f, // inner radius of the player poof cube 250.0f, // outer radius of the player pood cube 125.0f, // radius of the poofs 1.0f, 1.0f, 1.0f // width, height, depth jittering. best left at 1.0 }, { // higest detail level 0.475f, // max alpha for this detail level in Glide 0.575f, // max alpha for this detail level in D3d 0.05f, // break alpha (below which, poofs don't draw). this affects the speed and visual quality a lot 200.0f, 200.0f / 1.3333f, // x and y alpha fade/break values. adjust alpha on the polys as they move offscreen 750.0f, // total dimension of player poof cube 200.0f, // inner radius of the player poof cube 360.0f, // outer radius of the player pood cube 150.0f, // radius of the poofs 1.0f, 1.0f, 1.0f // width, height, depth jittering. best left at 1.0 }, }; neb2_detail *Nd = &Neb2_detail[MAX_DETAIL_LEVEL - 2]; int Neb2_background_color[3] = {0, 0, 255}; // rgb background color (used for lame rendering) int Neb2_regen = 0; // -------------------------------------------------------------------------------------------------------- // NEBULA FORWARD DECLARATIONS // // return the alpha the passed poof should be rendered with, for a 2 shell nebula float neb2_get_alpha_2shell(float inner_radius, float outer_radius, float magic_num, vec3d *v); // return an alpha value for a bitmap offscreen based upon "break" value float neb2_get_alpha_offscreen(float sx, float sy, float incoming_alpha); // do a pre-render of the background nebula void neb2_pre_render(vec3d *eye_pos, matrix *eye_orient); // fill in the position of the eye for this frame void neb2_get_eye_pos(vec3d *eye); // fill in the eye orient for this frame void neb2_get_eye_orient(matrix *eye); // get a (semi) random bitmap to use for a poof int neb2_get_bitmap(); // regenerate the player nebula void neb2_regen(); // -------------------------------------------------------------------------------------------------------- // NEBULA FUNCTIONS // // initialize neb2 stuff at game startup void neb2_init() { char name[255] = ""; // read in the nebula.tbl read_file_text("nebula.tbl"); reset_parse(); // background bitmaps Neb2_bitmap_count = 0; while(!optional_string("#end")){ // nebula required_string("+Nebula:"); stuff_string(name, F_NAME, NULL); if(Neb2_bitmap_count < MAX_NEB2_BITMAPS){ strcpy(Neb2_bitmap_filenames[Neb2_bitmap_count++], name); } } // poofs Neb2_poof_count = 0; while(!optional_string("#end")){ // nebula required_string("+Poof:"); stuff_string(name, F_NAME, NULL); if(Neb2_poof_count < MAX_NEB2_POOFS){ strcpy(Neb2_poof_filenames[Neb2_poof_count++], name); } } //Distance //WMC - Obsolete! Obsolete! Obsolete! /* if(optional_string("#Fog Distance")) { char buf[32]; int len = sizeof(Neb_ship_fog_vals_d3d)/sizeof(Neb_ship_fog_vals_d3d[0]); for(int i = 0; i < len; i++) { Assert( i < (int)(sizeof(Ship_type_names) / sizeof(Ship_type_names[0])) ); //Create the var string and parse it if necessary sprintf(buf, "$%s:", Ship_type_names[i]); if(optional_string(buf)) { stuff_float_list((float *)&(Neb_ship_fog_vals_d3d[i]), 2); } } required_string("#End"); }*/ // should always have 6 neb poofs Assert(Neb2_poof_count == 6); } // set detail level void neb2_set_detail_level(int level) { // sanity if(level < 0){ Nd = &Neb2_detail[0]; return; } if(level >= MAX_DETAIL_LEVEL){ Nd = &Neb2_detail[MAX_DETAIL_LEVEL-1]; return; } Nd = &Neb2_detail[level]; // regen the player neb Neb2_regen = 1; } void neb2_get_fog_colour(unsigned char *r, unsigned char *g, unsigned char *b) { if(r) *r = Neb2_fog_colour_r; if(g) *g = Neb2_fog_colour_g; if(b) *b = Neb2_fog_colour_b; } void neb2_level_init() { Nebula_sexp_used = false; } // initialize nebula stuff - call from game_post_level_init(), so the mission has been loaded void neb2_post_level_init() { int idx; // standalone servers can bail here if(Game_mode & GM_STANDALONE_SERVER){ return; } // if the mission is not a fullneb mission, skip if(!(The_mission.flags & MISSION_FLAG_FULLNEB) && !Nebula_sexp_used){ Neb2_render_mode = NEB2_RENDER_NONE; Neb2_awacs = -1.0f; return; } if(Cmdline_nohtl || Fred_running && (The_mission.flags & MISSION_FLAG_FULLNEB)) { // by default we'll use pof rendering Neb2_render_mode = NEB2_RENDER_POF; stars_set_background_model(BACKGROUND_MODEL_FILENAME, Neb2_texture_name); } else { // Set a default colour just incase something goes wrong Neb2_fog_colour_r = 30; Neb2_fog_colour_g = 52; Neb2_fog_colour_b = 157; // OK, lets try something a bit more interesting if(strlen(Neb2_texture_name)) { int width, height; int format = -1; if(targa_read_header(Neb2_texture_name, NULL, &width, &height) == TARGA_ERROR_NONE) format = 0; else if(jpeg_read_header(Neb2_texture_name, NULL, &width, &height) == JPEG_ERROR_NONE) format = 1; /*else if(dds_read_header(Neb2_texture_name, NULL, &width, &height) == DDS_ERROR_NONE) format = 2;*/ else if(pcx_read_header(Neb2_texture_name, NULL, &width, &height) == PCX_ERROR_NONE) format = 3; if(format != -1) { bool loaded = false; Neb2_max_fog_value = width * height; Neb2_htl_fog_data = (ubyte *) vm_malloc(Neb2_max_fog_value * 4); if(Neb2_htl_fog_data) { // Always read in 32 bit, bypass normal bitmap code to avoid D3D locking issues switch(format) { case 0: if(targa_read_bitmap(Neb2_texture_name, Neb2_htl_fog_data, NULL, 4) == TARGA_ERROR_NONE) loaded = true; break; case 1: if(jpeg_read_bitmap(Neb2_texture_name, Neb2_htl_fog_data, NULL, 4) == JPEG_ERROR_NONE) loaded = true; break; /* case 2: if(dds_read_bitmap(Neb2_texture_name, Neb2_htl_fog_data) == DDS_ERROR_NONE) loaded = true; break;*/ case 3: if(pcx_read_bitmap(Neb2_texture_name, Neb2_htl_fog_data, NULL, 4) == PCX_ERROR_NONE) loaded = true; break; } if(loaded) { Neb2_fog_colour_r = Neb2_htl_fog_data[2]; Neb2_fog_colour_g = Neb2_htl_fog_data[1]; Neb2_fog_colour_b = Neb2_htl_fog_data[0]; } else { vm_free(Neb2_htl_fog_data); Neb2_htl_fog_data = NULL; } } } else { Warning(LOCATION, "Could not open specified nebula texture '%s'", Neb2_texture_name); } } Neb2_render_mode = NEB2_RENDER_HTL; } // load in all nebula bitmaps for(idx=0; idx= 0){ bm_release(Neb2_poofs[idx]); Neb2_poofs[idx] = -1; } } // unflag the mission as being fullneb so stuff doesn't fog in the techdata room :D The_mission.flags &= ~MISSION_FLAG_FULLNEB; if(Neb2_htl_fog_data) { vm_free(Neb2_htl_fog_data); Neb2_htl_fog_data = NULL; } } // call before beginning all rendering void neb2_render_setup(vec3d *eye_pos, matrix *eye_orient) { // standalone servers can bail here if(Game_mode & GM_STANDALONE_SERVER){ return; } // if the mission is not a fullneb mission, skip if(!(The_mission.flags & MISSION_FLAG_FULLNEB) && !Nebula_sexp_used){ return; } if(Neb2_render_mode == NEB2_RENDER_HTL) { if(Neb2_htl_fog_data) { Neb2_cur_fog_value++; if(Neb2_cur_fog_value >= (Neb2_max_fog_value*Neb2_cur_fog_factor)) Neb2_cur_fog_value = 0; int index = Neb2_cur_fog_value / Neb2_cur_fog_factor * 4; int r = (((int) Neb2_fog_colour_r) + ((int) Neb2_htl_fog_data[index+2]))/2; int g = (((int) Neb2_fog_colour_g) + ((int) Neb2_htl_fog_data[index+1]))/2; int b = (((int) Neb2_fog_colour_b) + ((int) Neb2_htl_fog_data[index+0]))/2; Neb2_fog_colour_r = (ubyte) (r & 0xff); Neb2_fog_colour_g = (ubyte) (g & 0xff); Neb2_fog_colour_b = (ubyte) (b & 0xff); } // RT The background needs to be the same colour as the fog and this seems // to be the ideal place to do it unsigned char tr = gr_screen.current_clear_color.red; unsigned char tg = gr_screen.current_clear_color.green; unsigned char tb = gr_screen.current_clear_color.blue; neb2_get_fog_colour( &gr_screen.current_clear_color.red, &gr_screen.current_clear_color.green, &gr_screen.current_clear_color.blue); gr_clear(); gr_screen.current_clear_color.red = tr; gr_screen.current_clear_color.green = tg; gr_screen.current_clear_color.blue = tb; return; } // pre-render the real background nebula neb2_pre_render(eye_pos, eye_orient); } // level paging code void neb2_page_in() { int idx; // load in all nebula bitmaps if (The_mission.flags & MISSION_FLAG_FULLNEB || Nebula_sexp_used) { for(idx=0; idx= 0) && (Neb2_poof_flags & (1<type ) { // some objects we always render case OBJ_SHOCKWAVE: case OBJ_JUMP_NODE: case OBJ_NONE: case OBJ_GHOST: case OBJ_BEAM: case OBJ_WAYPOINT: return 0; // any weapon over 500 meters away case OBJ_WEAPON: if(z_depth >= 500.0f){ return 1; } break; // any small ship over the fog limit, or any cruiser 50% further than the fog limit case OBJ_SHIP: ship_info *sip; if((objp->instance >= 0) && (Ships[objp->instance].ship_info_index >= 0)){ sip = &Ship_info[Ships[objp->instance].ship_info_index]; } else { return 0; } // small ships over the fog limit by a small factor if((sip->flags & SIF_SMALL_SHIP) && (z_depth >= (fog_far * 1.5f))){ return 1; } // big ships if((sip->flags & SIF_BIG_SHIP) && (z_depth >= (fog_far * 2.0f))){ return 1; } // huge ships if((sip->flags & SIF_HUGE_SHIP) && (z_depth >= (fog_far * 3.0f))){ return 1; } break; // any fireball over the fog limit for small ships case OBJ_FIREBALL: /* if(z_depth >= fog_far){ return 1; } */ return 0; break; // any debris over the fog limit for small ships case OBJ_DEBRIS: /* if(z_depth >= fog_far){ return 1; } */ return 0; break; // any asteroids 50% farther than the fog limit for small ships case OBJ_ASTEROID: if(z_depth >= (fog_far * 1.5f)){ return 1; } break; /* // any countermeasures over 100 meters away case OBJ_CMEASURE: if(z_depth >= 100.0f){ return 1; } break; */ // hmmm. unknown object type - should probably let it through default: Int3(); return 0; } return 0; } // extend LOD float neb2_get_lod_scale(int objnum) { ship *shipp; ship_info *sip; // bogus if((objnum < 0) || (objnum >= MAX_OBJECTS) || (Objects[objnum].type != OBJ_SHIP) || (Objects[objnum].instance < 0) || (Objects[objnum].instance >= MAX_SHIPS)){ return 1.0f; } shipp = &Ships[Objects[objnum].instance]; sip = &Ship_info[shipp->ship_info_index]; // small ship? if(sip->flags & SIF_SMALL_SHIP){ return 1.8f; } else if(sip->flags & SIF_BIG_SHIP){ return 1.4f; } // hmm return 1.0f; } // -------------------------------------------------------------------------------------------------------- // NEBULA FORWARD DEFINITIONS // // return the alpha the passed poof should be rendered with, for a 2 shell nebula float neb2_get_alpha_2shell(float inner_radius, float outer_radius, float magic_num, vec3d *v) { float dist; float alpha; vec3d eye_pos; // get the eye position neb2_get_eye_pos(&eye_pos); // determine what alpha to draw this bitmap with // higher alpha the closer the bitmap gets to the eye dist = vm_vec_dist_quick(&eye_pos, v); // if the point is inside the inner radius, alpha is based on distance to the player's eye, // becoming more transparent as it gets close if(dist <= inner_radius){ // alpha per meter between the magic # and the inner radius alpha = Nd->max_alpha_glide / (inner_radius - magic_num); // above value times the # of meters away we are alpha *= (dist - magic_num); return alpha < 0.0f ? 0.0f : alpha; } // if the point is outside the inner radius, it starts out as completely transparent at max // outer radius, and becomes more opaque as it moves towards inner radius else if(dist <= outer_radius){ // alpha per meter between the outer radius and the inner radius alpha = Nd->max_alpha_glide / (outer_radius - inner_radius); // above value times the range between the outer radius and the poof return alpha < 0.0f ? 0.0f : alpha * (outer_radius - dist); } // otherwise transparent return 0.0f; } // return an alpha value for a bitmap offscreen based upon "break" value float neb2_get_alpha_offscreen(float sx, float sy, float incoming_alpha) { float alpha = 0.0f; float per_pixel_x = incoming_alpha / (float)Nd->break_x; float per_pixel_y = incoming_alpha / (float)Nd->break_y; int off_x = ((sx < 0.0f) || (sx > (float)gr_screen.max_w)); int off_y = ((sy < 0.0f) || (sy > (float)gr_screen.max_h)); float off_x_amount = 0.0f; float off_y_amount = 0.0f; // determine how many pixels outside we are if(off_x){ if(sx < 0.0f){ off_x_amount = fl_abs(sx); } else { off_x_amount = sx - (float)gr_screen.max_w; } } if(off_y){ if(sy < 0.0f){ off_y_amount = fl_abs(sy); } else { off_y_amount = sy - (float)gr_screen.max_h; } } // if offscreen X if(off_x){ // offscreen X and Y - and Y is greater if(off_y && (off_y_amount > off_x_amount)){ alpha = incoming_alpha - (off_y_amount * per_pixel_y); } else { alpha = incoming_alpha - (off_x_amount * per_pixel_x); } } // offscreen y else if(off_y){ alpha = incoming_alpha - (off_y_amount * per_pixel_y); } // should never get here else { Int3(); } return alpha < 0.0f ? 0.0f : alpha; } // ------------------------------------------------------------------------------------------------- // WACKY LOCAL PLAYER NEBULA STUFF // vec3d cube_cen; int crossed_border() { vec3d eye_pos; float ws = Nd->cube_dim / (float)Neb2_slices; float hs = Nd->cube_dim / (float)Neb2_slices; float ds = Nd->cube_dim / (float)Neb2_slices; // get the eye position neb2_get_eye_pos(&eye_pos); // check left, right (0, and 1, x and -x) if(cube_cen.xyz.x - eye_pos.xyz.x > ws){ // -x return 0; } else if(eye_pos.xyz.x - cube_cen.xyz.x > ws){ // +x return 1; } // check up, down (2, and 3, y and -y) if(cube_cen.xyz.y - eye_pos.xyz.y > hs){ // -y return 2; } else if(eye_pos.xyz.y - cube_cen.xyz.y > hs){ // +y return 3; } // check front, back (4, and 5, z and -z) if(cube_cen.xyz.z - eye_pos.xyz.z > ds){ // -z return 4; } else if(eye_pos.xyz.z - cube_cen.xyz.z > ds){ // +z return 5; } // nothing return -1; } void neb2_copy(int xyz, int src, int dest) { int idx1, idx2; switch(xyz){ case 0: for(idx1=0; idx1cube_dim / (float)Neb2_slices; h_incw = ws / 2.0f; hs = Nd->cube_dim / (float)Neb2_slices; h_inch = hs / 2.0f; ds = Nd->cube_dim / (float)Neb2_slices; h_incd = ds / 2.0f; cube_corner = *cube_center; cube_corner.xyz.x -= (Nd->cube_dim / 2.0f); cube_corner.xyz.y -= (Nd->cube_dim / 2.0f); cube_corner.xyz.z -= (Nd->cube_dim / 2.0f); switch(xyz){ case 0: for(idx1=0; idx1xyz.x = h_incw + (ws * (float)src) + frand_range(-Nd->wj, Nd->wj); v->xyz.y = h_inch + (hs * (float)idx1) + frand_range(-Nd->hj, Nd->hj); v->xyz.z = h_incd + (ds * (float)idx2) + frand_range(-Nd->dj, Nd->dj); vm_vec_add2(v, &cube_corner); // set the bitmap Neb2_cubes[src][idx1][idx2].bmap = neb2_get_bitmap(); // set the rotation speed Neb2_cubes[src][idx1][idx2].rot = 0.0f; Neb2_cubes[src][idx1][idx2].rot_speed = frand_range(-max_rotation, max_rotation); Neb2_cubes[src][idx1][idx2].flash = 0.0f; } } break; case 1: for(idx1=0; idx1xyz.x = h_incw + (ws * (float)idx1) + frand_range(-Nd->wj, Nd->wj); v->xyz.y = h_inch + (hs * (float)src) + frand_range(-Nd->hj, Nd->hj); v->xyz.z = h_incd + (ds * (float)idx2) + frand_range(-Nd->dj, Nd->dj); vm_vec_add2(v, &cube_corner); // set the bitmap Neb2_cubes[idx1][src][idx2].bmap = neb2_get_bitmap(); // set the rotation speed Neb2_cubes[idx1][src][idx2].rot = 0.0f; Neb2_cubes[idx1][src][idx2].rot_speed = frand_range(-max_rotation, max_rotation); Neb2_cubes[src][idx1][idx2].flash = 0.0f; } } break; case 2: for(idx1=0; idx1xyz.x = h_incw + (ws * (float)idx1) + frand_range(-Nd->wj, Nd->wj); v->xyz.y = h_inch + (hs * (float)idx2) + frand_range(-Nd->hj, Nd->hj); v->xyz.z = h_incd + (ds * (float)src) + frand_range(-Nd->dj, Nd->dj); vm_vec_add2(v, &cube_corner); // set the bitmap Neb2_cubes[idx1][idx2][src].bmap = neb2_get_bitmap(); // set the rotation speed Neb2_cubes[idx1][idx2][src].rot = 0.0f; Neb2_cubes[idx1][idx2][src].rot_speed = frand_range(-max_rotation, max_rotation); Neb2_cubes[src][idx1][idx2].flash = 0.0f; } } break; default: Int3(); break; } } // regenerate the player nebula void neb2_regen() { int idx; vec3d eye_pos; matrix eye_orient; mprintf(("Regenerating local nebula!\n")); // get eye position and orientation neb2_get_eye_pos(&eye_pos); neb2_get_eye_orient(&eye_orient); // determine the corner of the cube cube_cen = eye_pos; // generate slices of the cube for(idx=0; idxcube_dim / (float)Neb2_slices; for(idx1=Neb2_slices-1; idx1>0; idx1--){ neb2_copy(0, idx1-1, idx1); } neb2_gen_slice(0, 0, &cube_cen); break; // x case 1 : cube_cen.xyz.x += Nd->cube_dim / (float)Neb2_slices; for(idx1=0; idx1cube_dim / (float)Neb2_slices; for(idx1=Neb2_slices-1; idx1>0; idx1--){ neb2_copy(1, idx1-1, idx1); } neb2_gen_slice(1, 0, &cube_cen); break; // y case 3 : cube_cen.xyz.y += Nd->cube_dim / (float)Neb2_slices; for(idx1=0; idx1cube_dim / (float)Neb2_slices; for(idx1=Neb2_slices-1; idx1>0; idx1--){ neb2_copy(2, idx1-1, idx1); } neb2_gen_slice(2, 0, &cube_cen); break; // z case 5 : cube_cen.xyz.z += Nd->cube_dim / (float)Neb2_slices; for(idx1=0; idx1= 360.0f){ Neb2_cubes[idx1][idx2][idx3].rot = 0.0f; } // optimization 1 - don't draw backfacing poly's // useless if(vm_vec_dot_to_point(&eye_orient.vec.fvec, &eye_pos, &Neb2_cubes[idx1][idx2][idx3].pt) <= 0.0f){ pneb_tossed_dot++; continue; } vertex p_; // rotate and project the vertex into viewspace g3_rotate_vertex(&p, &Neb2_cubes[idx1][idx2][idx3].pt); if(!Cmdline_nohtl) g3_transfer_vertex(&p_, &Neb2_cubes[idx1][idx2][idx3].pt); ptemp = p; g3_project_vertex(&ptemp); // get the proper alpha value alpha = neb2_get_alpha_2shell(Nd->cube_inner, Nd->cube_outer, Nd->prad/4.0f, &Neb2_cubes[idx1][idx2][idx3].pt); // optimization 2 - don't draw 0.0f or less poly's // this amounts to big savings if(alpha <= Nd->break_alpha){ pneb_tossed_alpha++; continue; } // drop poly's which are offscreen at all // if the poly's are offscreen if((ptemp.sx < 0.0f) || (ptemp.sx > (float)gr_screen.max_w) || (ptemp.sy < 0.0f) || (ptemp.sy > (float)gr_screen.max_h) ){ alpha = neb2_get_alpha_offscreen(ptemp.sx, ptemp.sy, alpha); } // optimization 2 - don't draw 0.0f or less poly's // this amounts to big savings if(alpha <= Nd->break_alpha){ pneb_tossed_alpha++; continue; } // set the bitmap and render gr_set_bitmap(Neb2_cubes[idx1][idx2][idx3].bmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, (alpha + Neb2_cubes[idx1][idx2][idx3].flash)); /*#ifndef NDEBUG // float this_area; float frame_area = max_area; float total_area = 0.0f; this_area = g3_draw_rotated_bitmap_area(&p, fl_radian(Neb2_cubes[idx1][idx2][idx3].rot), Nd->prad, TMAP_FLAG_TEXTURED, max_area); total_area += this_area; frame_area -= this_area; frame_rendered++; #else */ if (!Cmdline_nohtl) gr_set_lighting(false, false); gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0); if(Cmdline_nohtl || Cmdline_2d_poof) g3_draw_rotated_bitmap(&p, fl_radian(Neb2_cubes[idx1][idx2][idx3].rot), Nd->prad, TMAP_FLAG_TEXTURED); else g3_draw_rotated_bitmap(&p_, fl_radian(Neb2_cubes[idx1][idx2][idx3].rot), Nd->prad, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT); //#endif } } } frames_total += frame_rendered; frame_count++; frame_avg = (float)frames_total / (float)frame_count; // gr_set_color_fast(&Color_bright_red); // gr_printf(30, 100, "Area %.3f", total_area); #ifdef NEB2_THUMBNAIL extern int tbmap; if(tbmap != -1){ gr_set_bitmap(tbmap); gr_bitmap(0, 0); } #endif } // call this when the player's viewpoint has changed, this will cause the code to properly reset // the eye's local poofs void neb2_eye_changed() { Neb2_regen = 1; } /* //Object types #define OBJ_NONE 0 //unused object #define OBJ_SHIP 1 //a ship #define OBJ_WEAPON 2 //a laser, missile, etc #define OBJ_FIREBALL 3 //an explosion #define OBJ_START 4 //a starting point marker (player start, etc) #define OBJ_WAYPOINT 5 //a waypoint object, maybe only ever used by Fred #define OBJ_DEBRIS 6 //a flying piece of ship debris #define OBJ_CMEASURE 7 //a countermeasure, such as chaff #define OBJ_GHOST 8 //so far, just a placeholder for when a player dies. #define OBJ_POINT 9 //generic object type to display a point in Fred. #define OBJ_SHOCKWAVE 10 // a shockwave #define OBJ_WING 11 // not really a type used anywhere, but I need it for Fred. #define OBJ_OBSERVER 12 // used for multiplayer observers (possibly single player later) #define OBJ_ASTEROID 13 // An asteroid, you know, a big rock, like debris, sort of. #define OBJ_JUMP_NODE 14 // A jump node object, used only in Fred. #define OBJ_BEAM 15 // beam weapons. we have to roll them into the object system to get the benefits of the collision pairs */ // get near and far fog values based upon object type and rendering mode void neb2_get_fog_values(float *fnear, float *ffar, object *objp) { int type_index = -1; // default values in case something truly nasty happens *fnear = 10.0f; *ffar = 1000.0f; if (objp == NULL) return; //Otherwise, use defaults *fnear = Default_fog_near; *ffar = Default_fog_far; // determine what fog index to use if(objp->type == OBJ_SHIP) { Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS)); if((objp->instance >= 0) && (objp->instance < MAX_SHIPS)) { type_index = ship_query_general_type(objp->instance); if(type_index > 0) { *fnear = Ship_types[type_index].fog_start_dist; *ffar = Ship_types[type_index].fog_complete_dist; } } } else if(objp->type == OBJ_FIREBALL) {//mostly here for the warp effect *fnear = objp->radius*2; *ffar = (objp->radius*objp->radius*200)+objp->radius*200; return; //we want these to show up realy far away, this seems like a good value-Bobboau /* }else if(objp->type == OBJ_BEAM){ *fnear = 10.0f; *ffar = 10000.0f; return; // fog everything else like a fighter */ } } float nNf_near, nNf_far; // given a position in space, return a value from 0.0 to 1.0 representing the fog level float neb2_get_fog_intensity(object *obj) { float pct; // get near and far fog values based upon object type and rendering mode neb2_get_fog_values(&nNf_near, &nNf_far, obj); // get the fog pct pct = vm_vec_dist_quick(&Eye_position, &obj->pos) / (nNf_far - nNf_near); if(pct < 0.0f){ return 0.0f; } else if(pct > 1.0f){ return 1.0f; } return pct; } //this only gets called after the one above has been called as it assumes you have set the near and far planes properly //doun't use this outside of ship rendering float neb2_get_fog_intensity(vec3d *pos) { float pct; // get near and far fog values based upon object type and rendering mode // neb2_get_fog_values(&f_near, &f_far, pos); // get the fog pct pct = vm_vec_dist_quick(&Eye_position, pos) / ((nNf_far*2) - nNf_near); if(pct < 0.0f){ return 0.0f; } else if(pct > 1.0f){ return 1.0f; } return pct; } // fogging stuff -------------------------------------------------------------------- // do a pre-render of the background nebula #define ESIZE 32 ubyte tpixels[ESIZE * ESIZE * 4]; // for 32 bits int last_esize = -1; int this_esize = ESIZE; extern float Viewer_zoom; float ex_scale, ey_scale; int tbmap = -1; // UnknownPlayer : Contained herein, the origins of the nebula rendering bug! // I am really not entirely sure what this code achieves, but the old // D3D calls were the cause of the nebula bug - they have been commented out. // If you want to save some rendering time, I would suggest maybe kill this off. // It doesn't use much, but it APPEARS to be fairly useless unless someone wants // to enlighten me. // void neb2_pre_render(vec3d *eye_pos, matrix *eye_orient) { if(Neb2_render_mode == NEB2_RENDER_HTL) return; // bail early in lame and poly modes if(Neb2_render_mode != NEB2_RENDER_POF){ return; } // set the view clip gr_screen.clip_width = this_esize; gr_screen.clip_height = this_esize; g3_start_frame(1); // Turn on zbuffering g3_set_view_matrix(eye_pos, eye_orient, Viewer_zoom); gr_set_clip(0, 0, this_esize, this_esize); // render the background properly // hack - turn off nebula stuff int neb_save = Neb2_render_mode; Neb2_render_mode = NEB2_RENDER_NONE; // draw background stuff nebula extern void stars_draw_background(int); stars_draw_background(0); Neb2_render_mode = neb_save; // grab the region gr_get_region(0, this_esize, this_esize, (ubyte*)tpixels); #ifdef NEB2_THUMBNAIL if(tbmap == -1){ tbmap = bm_create(16, this_esize, this_esize, tpixels, 0); bm_lock(tbmap, 16, 0); bm_unlock(tbmap); } #endif // maybe do some swizzling // end the frame g3_end_frame(); gr_clear(); // if the size has changed between frames, make a new bitmap if(this_esize != last_esize){ last_esize = this_esize; // recalculate ex_scale and ey_scale values for looking up color values ex_scale = (float)this_esize / (float)gr_screen.max_w; ey_scale = (float)this_esize / (float)gr_screen.max_h; } } // wacky scheme for smoothing colors int wacky_scheme = 3; // get the color of the pixel in the small pre-rendered background nebula #define PIXEL_INDEX_SMALL(xv, yv) ( (this_esize * (yv) * gr_screen.bytes_per_pixel) + ((xv) * gr_screen.bytes_per_pixel) ) void neb2_get_pixel(int x, int y, int *r, int *g, int *b) { if(Neb2_render_mode == NEB2_RENDER_HTL) return; int ra, ga, ba; ubyte rv, gv, bv; ubyte avg_count; int xs, ys; // if we're in lame rendering mode, return a constant value if(Neb2_render_mode == NEB2_RENDER_LAME){ *r = Neb2_background_color[0]; *g = Neb2_background_color[1]; *b = Neb2_background_color[2]; return; } // get the proper pixel index to be looking up rv = gv = bv = 0; // select screen format BM_SELECT_SCREEN_FORMAT(); // pixel plus all immediate neighbors (on the small screen - should be more effective than 2 or 1) xs = (int)(ex_scale * x); ys = (int)(ey_scale * y); // sometimes goes over by 1 in direct3d if(ys >= (this_esize - 1)){ ys--; } avg_count = 0; bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs, ys)], &rv, &gv, &bv, NULL); ra = rv; ga = gv; ba = bv; avg_count++; if(xs > 0){ bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs - 1, ys)], &rv, &gv, &bv, NULL); // left ra += rv; ba += bv; ga += gv; avg_count++; } if(xs < this_esize - 1){ bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs + 1, ys)], &rv, &gv, &bv, NULL); // right ra += rv; ba += bv; ga += gv; avg_count++; } if(ys > 0){ bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs, ys - 1)], &rv, &gv, &bv, NULL); // top ra += rv; ba += bv; ga += gv; avg_count++; } if(ys < this_esize - 2){ bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs, ys + 1)], &rv, &gv, &bv, NULL); // bottom ra += rv; ba += bv; ga += gv; avg_count++; } if((xs > 0) && (ys > 0)){ bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs - 1, ys - 1)], &rv, &gv, &bv, NULL); // upper left ra += rv; ba += bv; ga += gv; avg_count++; } if((xs < this_esize - 1) && (ys < this_esize - 1)){ bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs + 1, ys + 1)], &rv, &gv, &bv, NULL); // lower right ra += rv; ba += bv; ga += gv; avg_count++; } if((ys > 0) && (xs < this_esize - 1)){ bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs + 1, ys - 1)], &rv, &gv, &bv, NULL); // lower left ra += rv; ba += bv; ga += gv; avg_count++; } if((ys < this_esize - 1) && (xs > 0)){ bm_get_components(&tpixels[PIXEL_INDEX_SMALL(xs - 1, ys + 1)], &rv, &gv, &bv, NULL); // upper right ra += rv; ba += bv; ga += gv; avg_count++; } rv = (ubyte)(ra / (int)avg_count); gv = (ubyte)(ga / (int)avg_count); bv = (ubyte)(ba / (int)avg_count); // return values *r = (int)rv; *g = (int)gv; *b = (int)bv; } // get the color to fog the background color to void neb2_get_backg_color(int *r, int *g, int *b) { *r = Neb2_background_color[0]; *g = Neb2_background_color[1]; *b = Neb2_background_color[2]; } // set the background color void neb2_set_backg_color(int r, int g, int b) { Neb2_background_color[0] = r; Neb2_background_color[1] = g; Neb2_background_color[2] = b; } // fill in the position of the eye for this frame void neb2_get_eye_pos(vec3d *eye) { *eye = Eye_position; } // fill in the eye orient for this frame void neb2_get_eye_orient(matrix *eye) { *eye = Eye_matrix; } // get a (semi) random bitmap to use for a poof int neb2_get_bitmap() { int count = 0; int huh; static int neb2_choose = 0; // get a random count count = (int)frand_range(1.0f, 5.0f); // very ad-hoc while(count > 0){ // don't cycle too many times huh = 0; do { if(neb2_choose == MAX_NEB2_POOFS - 1){ neb2_choose = 0; } else { neb2_choose++; } huh++; } while(!(Neb2_poof_flags & (1< : set near and far fog planes for ship type X\n"); dc_printf("where X is an integer from 1 - 11\n"); dc_printf("1 = cargo containers, 2 = fighters/bombers, 3 = cruisers\n"); dc_printf("4 = freighters, 5 = capital ships, 6 = transports, 7 = support ships\n"); dc_printf("8 = navbuoys, 9 = sentryguns, 10 = escape pods, 11 = background nebula polygons\n\n"); dc_printf("neb2_max_alpha : max alpha value (0.0 to 1.0) for cloud poofs. 0.0 is completely transparent\n"); 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"); 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"); dc_printf("neb2_smooth : magic fog smoothing modes (0 - 3)\n"); dc_printf("neb2_select : 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"); dc_printf("neb2_rot : set max rotation speed for poofs\n"); dc_printf("neb2_prad : set cloud poof radius\n"); dc_printf("neb2_cdim : poof cube dimension\n"); dc_printf("neb2_cinner : poof cube inner dimension\n"); dc_printf("neb2_couter : poof cube outer dimension\n"); dc_printf("neb2_jitter : poof jitter\n"); dc_printf("neb2_mode : switch between no nebula, polygon background, amd pof background (0, 1 and 2 respectively)\n\n"); dc_printf("neb2_ff : flash fade/sec\n"); dc_printf("neb2_background : rgb background color\n"); dc_printf("neb2_fog_vals : display all the current settings for all above values\n"); } DCF(neb2_prad, "") { dc_get_arg(ARG_FLOAT); Nd->prad = Dc_arg_float; } DCF(neb2_cdim, "") { dc_get_arg(ARG_FLOAT); Nd->cube_dim = Dc_arg_float; } DCF(neb2_cinner, "") { dc_get_arg(ARG_FLOAT); Nd->cube_inner = Dc_arg_float; } DCF(neb2_couter, "") { dc_get_arg(ARG_FLOAT); Nd->cube_outer = Dc_arg_float; } DCF(neb2_jitter, "") { dc_get_arg(ARG_FLOAT); Nd->hj = Nd->dj = Nd->wj = Dc_arg_float; } //WMC - unfortunately, this has to go bye-bye //I don't think anyone used it anyway so I'm not going to try to resurrect it /* DCF(neb2_fog, "") { int index; float fnear, ffar; dc_get_arg(ARG_INT); index = Dc_arg_int; dc_get_arg(ARG_FLOAT); fnear = Dc_arg_float; dc_get_arg(ARG_FLOAT); ffar = Dc_arg_float; if((index >= 1) && (index <= 11) && (fnear >= 0.0f) && (ffar >= 0.0f) && (ffar > fnear)){ if(index == 11){ Neb_backg_fog_near = fnear; Neb_backg_fog_far = ffar; } else { Neb_ship_fog_vals_d3d[index][0] = fnear; Neb_ship_fog_vals_d3d[index][1] = ffar; } } }*/ DCF(neb2_max_alpha, "") { dc_get_arg(ARG_FLOAT); Nd->max_alpha_glide = Dc_arg_float; } DCF(neb2_break_alpha, "") { dc_get_arg(ARG_FLOAT); Nd->break_alpha = Dc_arg_float; } DCF(neb2_break_off, "") { dc_get_arg(ARG_INT); Nd->break_y = (float)Dc_arg_int; Nd->break_x = Nd->break_y * 1.3333f; } DCF(neb2_smooth, "") { int index; dc_get_arg(ARG_INT); index = Dc_arg_int; if((index >= 0) && (index <= 3)){ wacky_scheme = index; } } DCF(neb2_select, "") { dc_get_arg(ARG_INT); int bmap = Dc_arg_int; if((bmap >= 0) && (bmap < Neb2_poof_count)){ dc_get_arg(ARG_INT); if(Dc_arg_int){ Neb2_poof_flags |= (1<max_alpha_glide); dc_printf("neb2_break_alpha : %f\n", Nd->break_alpha); dc_printf("neb2_break_off : %d\n", (int)Nd->break_y); dc_printf("neb2_smooth : %d\n", wacky_scheme); dc_printf("neb2_toggle : %s\n", Neb2_render_mode ? "on" : "off"); dc_printf("neb2_rot : %f\n", max_rotation); dc_printf("neb2_prad : %f\n", Nd->prad); dc_printf("neb2_cdim : %f\n", Nd->cube_dim); dc_printf("neb2_couter : %f\n", Nd->cube_outer); dc_printf("neb2_cinner : %f\n", Nd->cube_inner); dc_printf("neb2_jitter : %f\n", Nd->wj); dc_printf("neb2_ff : %f\n", neb2_flash_fade); dc_printf("neb2_background : %d %d %d\n", Neb2_background_color[0], Neb2_background_color[1], Neb2_background_color[2]); }*/ /* Obsolete !? DCF(neb2_create, "create a basic nebula") { int points = 0; float rad1 = 0.0f; float rad2 = 0.0f; dc_get_arg(ARG_INT); if(Dc_arg_type & ARG_INT){ points = Dc_arg_int; } dc_get_arg(ARG_FLOAT); if(Dc_arg_type & ARG_FLOAT){ rad1 = Dc_arg_float; } dc_get_arg(ARG_FLOAT); if(Dc_arg_type & ARG_FLOAT){ rad2 = Dc_arg_float; } neb2_create(&vmd_zero_vector, points, rad1, -1.0f, rad2); } DCF(neb2_del, "delete existing nebulae") { for(int idx=0; idxnum_poofs + num_poofs) > neb->max_poofs ? neb->max_poofs : (neb->num_poofs + num_poofs); // add the points a pick a random bitmap for(idx=neb->num_poofs; idxfvec, frand_range(neb->magic_num, neb->inner_radius)); // rotate the point by -ang <-> ang around the up vector vm_rot_point_around_line(&pt2, &pt, fl_radian(frand_range(-ang, ang)), &vmd_zero_vector, &orient->uvec); // rotate the point by -ang <-> ang around the right vector vm_rot_point_around_line(&pt3, &pt2, fl_radian(frand_range(-ang, ang)), &vmd_zero_vector, &orient->rvec); // now add in the center of the nebula so its placed properly (ie, not around the origin) vm_vec_add(&neb->pts[idx], &pt3, &Objects[neb->objnum].pos); } else { neb->pts[idx].xyz.x = frand_range(-1.0f * neb->inner_radius, neb->inner_radius) + Objects[neb->objnum].pos.xyz.x; neb->pts[idx].xyz.y = frand_range(-1.0f * neb->inner_radius, neb->inner_radius) + Objects[neb->objnum].pos.xyz.y; neb->pts[idx].xyz.z = frand_range(-1.0f * neb->inner_radius, neb->inner_radius) + Objects[neb->objnum].pos.xyz.z; } neb->bmaps[idx] = (int)frand_range(0.0f, (float)2); neb->num_poofs++; } } // add N poofs to the outer shell of the nebula // if orient and ang are specified, generate the poofs so that they are "visible" around // the orient fvec in a cone of ang degrees void neb2_add_outer(neb2 *neb, int num_poofs, matrix *orient, float ang) { int idx; float phi, theta; vec3d pt, pt2, pt3; int final_index = (neb->num_poofs + num_poofs) > neb->max_poofs ? neb->max_poofs : (neb->num_poofs + num_poofs); // add the points a pick a random bitmap for(idx=neb->num_poofs; idxfvec, neb->outer_radius); // rotate the point by -ang <-> ang around the up vector vm_rot_point_around_line(&pt2, &pt, fl_radian(frand_range(-ang, ang)), &vmd_zero_vector, &orient->uvec); // rotate the point by -ang <-> ang around the right vector vm_rot_point_around_line(&pt3, &pt2, fl_radian(frand_range(-ang, ang)), &vmd_zero_vector, &orient->rvec); // now add in the center of the nebula so its placed properly (ie, not around the origin) vm_vec_add(&neb->pts[idx], &pt, &Objects[neb->objnum].pos); } else { // get a random point on the very outer radius, using spherical coords phi = fl_radian(frand_range(0.0f, 360.0f)); theta = fl_radian(frand_range(0.0f, 360.f)); neb->pts[idx].xyz.x = neb->outer_radius * (float)sin(phi) * (float)cos(theta); neb->pts[idx].xyz.y = neb->outer_radius * (float)sin(phi) * (float)sin(theta); neb->pts[idx].xyz.z = neb->outer_radius * (float)cos(phi); } // pick a random bitmap and increment the # of poofs neb->bmaps[idx] = (int)frand_range(0.0f, (float)2); neb->num_poofs++; } } // return the alpha the passed poof should be rendered with, for a 1 shell nebula float neb2_get_alpha_1shell(neb2 *neb, int poof_index) { float dist; float alpha; vec3d eye_pos; // get the eye position neb2_get_eye_pos(&eye_pos); // determine what alpha to draw this bitmap with // higher alpha the closer the bitmap gets to the eye dist = vm_vec_dist_quick(&eye_pos, &neb->pts[poof_index]); // at poof radius or greater, alpha should be 1.0 // scale from 0.0 to 1.0 between radius and magic if(dist >= neb->max_poof_radius){ return max_alpha - 0.0001f; } else if(dist > neb->magic_num){ // alpha per meter between the magic # and the max radius alpha = max_alpha / (neb->max_poof_radius - neb->magic_num); // above value times the # of meters away we are return alpha * (dist - neb->magic_num); } // otherwise transparent return 0.0f; } */