Files
fs2open.github.com/code/nebula/neb.cpp
T
taylor 0652c0a1f2 fix some of the envmap issues
- use proper hand-ness for OGL
 - fix distortion
 - get rid of extra index buffer requirement
change starfield bitmaps to use an instance matrix rather than going through all the trouble of resetting the view matrix
basic cleanup and get rid of a couple of struct/variable naming issues (compiler sanity)
make double sure that we aren't using culling of z-buffering when rendering starfield bitmaps
2006-11-06 06:46:08 +00:00

2256 lines
67 KiB
C++

/*
* 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.53 $
* $Date: 2006-11-06 06:46:08 $
* $Author: taylor $
*
* Nebula effect
*
* $Log: not supported by cvs2svn $
* Revision 2.52 2006/09/11 06:50:42 taylor
* fixes for stuff_string() bounds checking
*
* Revision 2.51 2006/06/07 05:19:49 wmcoolmon
* Move fog disappearance factor to objecttypes.tbl
*
* Revision 2.50 2006/04/12 01:03:00 taylor
* more s/colour/color/ changes
* throw in a couple of safety checks for some neb2 functions
*
* Revision 2.49 2006/03/18 10:25:45 taylor
* some cleanup to the nebula debug console help messages
*
* Revision 2.48 2006/01/30 19:37:33 taylor
* and after all of my recent work fixing div-by-0 zero bugs, ya had to know this was coming :)
*
* Revision 2.47 2006/01/30 06:36:01 taylor
* minor warning fixage
*
* Revision 2.46 2006/01/26 03:59:59 taylor
* first version of this sucked, this should be a bit better while working with both new and retail data
* - get an average color from the palette rather than picking first (unoptimized palettes could have unused pixels in first entry)
* - slight cleanup, and s/colour/color/ (yeah, stupid American, deal with it! :))
*
* Revision 2.45 2006/01/18 16:01:14 taylor
* support only PCX for the nebula background graphics (given how it works that's the fastest and easiest way to get it done)
*
* Revision 2.44 2005/12/29 08:08:39 wmcoolmon
* Codebase commit, most notably including objecttypes.tbl
*
* 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;
static ubyte Neb2_fog_color_r = 0;
static ubyte Neb2_fog_color_g = 0;
static ubyte Neb2_fog_color_b = 0;
static ubyte *Neb2_htl_fog_data = NULL;
// #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[MAX_FILENAME_LEN];
// 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, MAX_FILENAME_LEN);
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, MAX_FILENAME_LEN);
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_color(ubyte *r, ubyte *g, ubyte *b)
{
if (r) *r = Neb2_fog_color_r;
if (g) *g = Neb2_fog_color_g;
if (b) *b = Neb2_fog_color_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 in case something goes wrong
Neb2_fog_color_r = 30;
Neb2_fog_color_g = 52;
Neb2_fog_color_b = 157;
// OK, lets try something a bit more interesting
if (strlen(Neb2_texture_name)) {
Neb2_htl_fog_data = new ubyte[768];
if ( pcx_read_header(Neb2_texture_name, NULL, NULL, NULL, NULL, Neb2_htl_fog_data) == PCX_ERROR_NONE ) {
// based on the palette, get an average color value (this doesn't really account for actual pixel usage though)
ushort r = 0, g = 0, b = 0, pcount = 0;
for (idx = 0; idx < 768; idx += 3) {
if (Neb2_htl_fog_data[idx] || Neb2_htl_fog_data[idx+1] || Neb2_htl_fog_data[idx+2]) {
r += Neb2_htl_fog_data[idx];
g += Neb2_htl_fog_data[idx+1];
b += Neb2_htl_fog_data[idx+2];
pcount++;
}
}
if (pcount > 0) {
Neb2_fog_color_r = (ubyte)(r / pcount);
Neb2_fog_color_g = (ubyte)(g / pcount);
Neb2_fog_color_b = (ubyte)(b / pcount);
} else {
// it's just black
Neb2_fog_color_r = Neb2_fog_color_g = Neb2_fog_color_b = 0;
}
// done, now free up the palette data
if ( Neb2_htl_fog_data != NULL ) {
delete[] Neb2_htl_fog_data;
Neb2_htl_fog_data = NULL;
}
}
}
Neb2_render_mode = NEB2_RENDER_HTL;
}
// load in all nebula bitmaps
for(idx=0; idx<Neb2_poof_count; idx++){
if(Neb2_poofs[idx] < 0){
Neb2_poofs[idx] = bm_load(Neb2_poof_filenames[idx]);
}
}
pneb_tried = 0;
pneb_tossed_alpha = 0;
pneb_tossed_dot = 0;
neb_tried = 0;
neb_tossed_alpha = 0;
neb_tossed_dot = 0;
neb_tossed_count = 0;
// setup proper fogging values
Neb_backg_fog_near = NEB_BACKG_FOG_NEAR_D3D;
Neb_backg_fog_far = NEB_BACKG_FOG_FAR_D3D;
// regen the nebula
neb2_eye_changed();
}
// shutdown nebula stuff
void neb2_level_close()
{
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){
return;
}
// unload all nebula bitmaps
for(idx=0; idx<Neb2_poof_count; idx++){
if(Neb2_poofs[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) {
delete[] 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) {
// RT The background needs to be the same colour as the fog and this seems
// to be the ideal place to do it
ubyte tr = gr_screen.current_clear_color.red;
ubyte tg = gr_screen.current_clear_color.green;
ubyte tb = gr_screen.current_clear_color.blue;
neb2_get_fog_color(
&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<Neb2_poof_count; idx++){
if((Neb2_poofs[idx] >= 0) && (Neb2_poof_flags & (1<<idx))){
bm_page_in_texture(Neb2_poofs[idx]);
}
}
}
}
// should we not render this object because its obscured by the nebula?
int neb_skip_opt = 1;
DCF(neb_skip, "")
{
neb_skip_opt = !neb_skip_opt;
if(neb_skip_opt){
dc_printf("Using neb object skipping!\n");
} else {
dc_printf("Not using neb object skipping!\n");
}
}
int neb2_skip_render(object *objp, float z_depth)
{
float fog_near, fog_far;
// if we're never skipping
if(!neb_skip_opt){
return 0;
}
// lame rendering
if(Neb2_render_mode == NEB2_RENDER_LAME){
return 0;
}
// get near and far fog values based upon object type and rendering mode
neb2_get_fog_values(&fog_near, &fog_far, objp);
// by object type
switch( objp->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->class_type > -1)
{
if(z_depth >= (fog_far * Ship_types[sip->class_type].fog_disappear_factor)) {
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; idx1<Neb2_slices; idx1++){
for(idx2=0; idx2<Neb2_slices; idx2++){
Neb2_cubes[dest][idx1][idx2] = Neb2_cubes[src][idx1][idx2];
}
}
break;
case 1:
for(idx1=0; idx1<Neb2_slices; idx1++){
for(idx2=0; idx2<Neb2_slices; idx2++){
Neb2_cubes[idx1][dest][idx2] = Neb2_cubes[idx1][src][idx2];
}
}
break;
case 2:
for(idx1=0; idx1<Neb2_slices; idx1++){
for(idx2=0; idx2<Neb2_slices; idx2++){
Neb2_cubes[idx1][idx2][dest] = Neb2_cubes[idx1][idx2][src];
}
}
break;
default:
Int3();
break;
}
}
void neb2_gen_slice(int xyz, int src, vec3d *cube_center)
{
int idx1, idx2;
float h_incw, h_inch, h_incd;
float ws, hs, ds;
vec3d cube_corner;
vec3d *v;
ws = Nd->cube_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; idx1<Neb2_slices; idx1++){
for(idx2=0; idx2<Neb2_slices; idx2++){
v = &Neb2_cubes[src][idx1][idx2].pt;
v->xyz.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; idx1<Neb2_slices; idx1++){
for(idx2=0; idx2<Neb2_slices; idx2++){
v = &Neb2_cubes[idx1][src][idx2].pt;
v->xyz.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; idx1<Neb2_slices; idx1++){
for(idx2=0; idx2<Neb2_slices; idx2++){
v = &Neb2_cubes[idx1][idx2][src].pt;
v->xyz.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; idx<Neb2_slices; idx++){
neb2_gen_slice(0, idx, &cube_cen);
}
}
float max_area = 100000000.0f;
DCF(max_area, "")
{
dc_get_arg(ARG_FLOAT);
max_area = Dc_arg_float;
}
float g3_draw_rotated_bitmap_area(vertex *pnt, float angle, float rad, uint tmap_flags, float area);
int neb_mode = 1;
int frames_total = 0;
int frame_count = 0;
float frame_avg;
void neb2_render_player()
{
vertex p, ptemp;
int idx1, idx2, idx3;
float alpha;
int frame_rendered;
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)){
return;
}
if(Neb2_regen){
neb2_regen();
Neb2_regen = 0;
}
// don't render in lame mode
if((Neb2_render_mode == NEB2_RENDER_LAME) || (Neb2_render_mode == NEB2_RENDER_NONE)){
return;
}
// get eye position and orientation
neb2_get_eye_pos(&eye_pos);
neb2_get_eye_orient(&eye_orient);
// maybe swap stuff around if the player crossed a "border"
for(idx2=0; idx2<3; idx2++){
switch(crossed_border()){
case -1:
break;
// -x
case 0 :
cube_cen.xyz.x -= Nd->cube_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; idx1<Neb2_slices-1; idx1++){
neb2_copy(0, idx1+1, idx1);
}
neb2_gen_slice(0, Neb2_slices - 1, &cube_cen);
break;
// -y
case 2 :
cube_cen.xyz.y -= Nd->cube_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; idx1<Neb2_slices-1; idx1++){
neb2_copy(1, idx1+1, idx1);
}
neb2_gen_slice(1, Neb2_slices - 1, &cube_cen);
break;
// -z
case 4 :
cube_cen.xyz.z -= Nd->cube_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<Neb2_slices-1; idx1++){
neb2_copy(2, idx1+1, idx1);
}
neb2_gen_slice(2, Neb2_slices - 1, &cube_cen);
break;
}
}
// if we've switched nebula rendering off
if(Neb2_render_mode == NEB2_RENDER_NONE){
return;
}
frame_rendered = 0;
// render the nebula
for(idx1=0; idx1<Neb2_slices; idx1++){
for(idx2=0; idx2<Neb2_slices; idx2++){
for(idx3=0; idx3<Neb2_slices; idx3++){
// Miss this one out if the id is -1
if(Neb2_cubes[idx1][idx2][idx3].bmap == -1)
continue;
pneb_tried++;
// rotate the poof
Neb2_cubes[idx1][idx2][idx3].rot += (Neb2_cubes[idx1][idx2][idx3].rot_speed * flFrametime);
if(Neb2_cubes[idx1][idx2][idx3].rot >= 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 the mission is not a fullneb mission, skip
if (!(The_mission.flags & MISSION_FLAG_FULLNEB))
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
stars_draw_background();
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)
{
// we shouldn't ever be here if in htl rendering mode
Assert( Neb2_render_mode != NEB2_RENDER_HTL );
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<<neb2_choose)) && (huh < 10));
count--;
}
// bitmap 0
if(Neb2_poofs[neb2_choose] < 0){
return Neb2_poofs[0];
}
return Neb2_poofs[neb2_choose];
}
// nebula DCF functions ------------------------------------------------------
DCF(neb2, "list nebula console commands")
{
// dc_printf("neb2_fog <X> <float> <float> : 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 : <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");
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, pof background, lame or HTL rendering (0, 1, 2, 3 and 4 respectively)\n\n");
dc_printf("neb2_ff : flash fade/sec\n");
dc_printf("neb2_background : rgb background color\n");
dc_printf("neb2_fog_color : rgb fog 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<<bmap);
} else {
Neb2_poof_flags &= ~(1<<bmap);
}
}
}
DCF(neb2_rot, "")
{
dc_get_arg(ARG_FLOAT);
max_rotation = Dc_arg_float;
}
DCF(neb2_ff, "")
{
dc_get_arg(ARG_FLOAT);
neb2_flash_fade = Dc_arg_float;
}
DCF(neb2_mode, "")
{
dc_get_arg(ARG_INT);
switch (Dc_arg_int)
{
case NEB2_RENDER_NONE:
Neb2_render_mode = NEB2_RENDER_NONE;
break;
case NEB2_RENDER_POLY:
Neb2_render_mode = NEB2_RENDER_POLY;
break;
case NEB2_RENDER_POF:
Neb2_render_mode = NEB2_RENDER_POF;
stars_set_background_model(BACKGROUND_MODEL_FILENAME, "Eraseme3");
break;
case NEB2_RENDER_LAME:
Neb2_render_mode = NEB2_RENDER_LAME;
break;
case NEB2_RENDER_HTL:
if (!Cmdline_nohtl) {
Neb2_render_mode = NEB2_RENDER_HTL;
}
break;
}
}
DCF(neb2_slices, "")
{
dc_get_arg(ARG_INT);
Neb2_slices = Dc_arg_int;
Neb2_regen = 1;
}
DCF(neb2_background, "")
{
int r, g, b;
dc_get_arg(ARG_INT);
r = Dc_arg_int;
dc_get_arg(ARG_INT);
g = Dc_arg_int;
dc_get_arg(ARG_INT);
b = Dc_arg_int;
Neb2_background_color[0] = r;
Neb2_background_color[1] = g;
Neb2_background_color[2] = b;
}
DCF(neb2_fog_color, "")
{
int r, g, b;
dc_get_arg(ARG_INT);
r = Dc_arg_int;
dc_get_arg(ARG_INT);
g = Dc_arg_int;
dc_get_arg(ARG_INT);
b = Dc_arg_int;
Neb2_fog_color_r = r;
Neb2_fog_color_g = g;
Neb2_fog_color_b = b;
}
//WMC - Going bye-bye for ship types too
/*
DCF(neb2_fog_vals, "")
{
dc_printf("neb2_fog : \n");
{
dc_printf("(1)cargo containers : %f, %f\n", Neb_ship_fog_vals_d3d[1][0], Neb_ship_fog_vals_d3d[1][1]);
dc_printf("(2)fighters/bombers : %f, %f\n", Neb_ship_fog_vals_d3d[2][0], Neb_ship_fog_vals_d3d[2][1]);
dc_printf("(3)cruisers : %f, %f\n", Neb_ship_fog_vals_d3d[3][0], Neb_ship_fog_vals_d3d[3][1]);
dc_printf("(4)freighters : %f, %f\n", Neb_ship_fog_vals_d3d[4][0], Neb_ship_fog_vals_d3d[4][1]);
dc_printf("(5)cap ships : %f, %f\n", Neb_ship_fog_vals_d3d[5][0], Neb_ship_fog_vals_d3d[5][1]);
dc_printf("(6)transports : %f, %f\n", Neb_ship_fog_vals_d3d[6][0], Neb_ship_fog_vals_d3d[6][1]);
dc_printf("(7)support ships : %f, %f\n", Neb_ship_fog_vals_d3d[7][0], Neb_ship_fog_vals_d3d[7][1]);
dc_printf("(8)navbuoys : %f, %f\n", Neb_ship_fog_vals_d3d[8][0], Neb_ship_fog_vals_d3d[8][1]);
dc_printf("(9)sentry guns : %f, %f\n", Neb_ship_fog_vals_d3d[9][0], Neb_ship_fog_vals_d3d[9][1]);
dc_printf("(10)escape pods : %f, %f\n", Neb_ship_fog_vals_d3d[10][0], Neb_ship_fog_vals_d3d[10][1]);
dc_printf("(11)background polys : %f, %f\n\n", Neb_backg_fog_near, Neb_backg_fog_far);
}
dc_printf("neb2_max_alpha : %f\n", Nd->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; idx<MAX_OBJECTS; idx++){
if(Objects[idx].type == OBJ_NEB2){
obj_delete(idx);
}
}
}
int magic0 = 15;
float magic1 = 1000.0f;
float magic2 = -1.0f;
float magic3 = 700.0f;
DCF(neb2_def, "create a default nebula")
{
vec3d a,b,c,d,e,f;
vm_vec_make(&a, 0.0f, 0.0f, 0.0f);
vm_vec_make(&b, 3600.0f, 700.0f, 0.0f);
vm_vec_make(&c, -3000.0f, 20.0f, 480.0f);
vm_vec_make(&d, -4000.0f, 100.0f, 100.0f);
vm_vec_make(&e, 0.0f, 3000.0f, -400.0f);
vm_vec_make(&f, 670.0f, -2500.0f, -1600.0f);
neb2_create(&a, magic0, magic1, magic2, magic3);
neb2_create(&b, magic0, magic1, magic2, magic3);
neb2_create(&c, magic0, magic1, magic2, magic3);
neb2_create(&d, magic0, magic1, magic2, magic3);
neb2_create(&e, magic0, magic1, magic2, magic3);
neb2_create(&f, magic0, magic1, magic2, magic3);
}
DCF(neb2_plr, "regenerate the player's nebula")
{
Neb2_regen = 0;
}
DCF(neb2_stats, "display info about the nebula rendering")
{
dc_printf("Player poofs tried : %d\n", pneb_tried);
dc_printf("Player poofs tossed (alpha): %d\n", pneb_tossed_alpha);
dc_printf("Player poofs tossed (dot): %d\n", pneb_tossed_dot);
dc_printf("Player poofs tossed (off): %d\n", pneb_tossed_off);
dc_printf("Poofs tried : %d\n", neb_tried);
dc_printf("Poofs tossed (alpha): %d\n", neb_tossed_alpha);
dc_printf("Poofs tossed (dot): %d\n", neb_tossed_dot);
dc_printf("Poofs tossed (count): %d\n", neb_tossed_count);
dc_printf("Avg poofs/frame: %f\n", frame_avg);
}
// create a nebula object, return objnum of the nebula or -1 on fail
// NOTE : in most cases you will want to pass -1.0f for outer_radius. Trust me on this
int neb2_create(vec3d *offset, int num_poofs, float inner_radius, float outer_radius, float max_poof_radius)
{
Int3();
return -1;
}
// delete a nebula object
void neb2_delete(object *objp)
{
Int3();
}
// renders a nebula object
void neb2_render(object *objp)
{
Int3();
}
// preprocess the nebula object before simulation
void neb2_process_pre(object *objp)
{
Int3();
}
// process the nebula object after simulating, but before rendering
void neb2_process_post(object *objp)
{
Int3();
}
*/
/*
// add N poofs to the inner 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_inner(neb2 *neb, int num_poofs, matrix *orient, float ang)
{
int idx;
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; idx<final_index; idx++){
if(orient != NULL){
// put a point directly in front of the player, between 0 and inner_radius distance away
vm_vec_copy_scale(&pt, &orient->fvec, 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; idx<final_index; idx++){
if(orient != NULL){
// put a point directly in front of the player, at outer_radius distance away
vm_vec_copy_scale(&pt, &orient->fvec, 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;
}
*/