added everything

This commit is contained in:
Metario
2017-04-17 06:17:10 -06:00
commit 9c6ff74f19
6121 changed files with 1625704 additions and 0 deletions

1333
engine/terrain/blender.cc Executable file

File diff suppressed because it is too large Load Diff

170
engine/terrain/blender.h Executable file
View File

@ -0,0 +1,170 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _BLENDER_H_
#define _BLENDER_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _TERRDATA_H_
#include "terrain/terrData.h"
#endif
#ifndef _TERRRENDER_H_
#include "terrain/terrRender.h"
#endif
#define GRIDFLAGS(X,Y) (TerrainRender::mCurrentBlock->findSquare( 0, Point2I( X, Y ) )->flags)
#define MATERIALSTART (GridSquare::MaterialStart)
/**
This MODULE contains class Blender. Blender has a set of textures and an ALPHA-VALUE MAP, and
exposes via the method Blender::blend(X, Y, LEVEL, LIGHT-MAP, DESTINATION-MIP-MAP) the facility
to "blend" its textures into DESTINATION-MIP-MAP using X & Y as an offset into the ALPHA-VALUE
MAP and the LIGHT-MAP.
The LANDSCAPE of the MISSION is a single (mile square?) TILE repeated infinitely.
The TILE is a SQUARES_PER_TILE_EDGE (currently 256) by SQUARES_PER_TILE_EDGE Row-Major
array of SQUARES.
A TEXEL in this context is a single element of a TEXTURE, an RGB triple or RGBA quad--what
would be thought of as a PIXEL were it mapped one-to-one to the display device.
A LUMEL is similarly the smallest unit of a LIGHT-MAP. It consists of an RGB triple (there doesn't
seem to be any special specular code, etc.) which is applied to the blended texel.
And an ALPHEL is similarly the smallest unit of a TEXTURE-ALPHA-MAP. Each TEXEL of the blended
(destination) texture is formed from the corresponding TEXELs of N source TEXTUREs. The ALPHELs
specify what part of the destination TEXEL coems from each source TEXEL.
The Blender is created with a fixed NUMBER OF MIPMAP LEVELS, a fixed NUMBER OF SOURCE TEXTURES,
and an ALPHA-VALUE MAP. The ALPHA-VALUE MAP is passed by reference (I don't know if it
can change interactively). The maximum usable value for NUMBER OF MIPMAP LEVELS is
MAX_MIPMAP_LEVELS (currently 4). I don't think anything bad happens if this is exceeded.
Each SOURCE TEXTURE is then added to the Blender with addSourceTexture, by index number,
specifying the MIP-MAP for the texture by value.
A MIP-MAP is an array of NUMBER OF MIPMAP LEVELS square BIT-MAPs in progressively
lower resolutions. The highest resolution BIT-MAP must be TEXELS_PER_SOURCE_EDGE (currently 256)
TEXELS on each side. Each successive BIT-MAP in the MIP-MAP must be 1/2 the resolution of the
preceding, or 1/4 the size. Each BIT-MAP is in Row-Major 3*8-bit RGB format.
Blender stores the value of the MIP-MAPs in an internal format, based on SQUARES. Each MIP-MAP
is stored as NUMBER OF MIPMAP LEVELS consecutive levels of descending resolution. Each level
of the MIP-MAP is stored as SQUARES_PER_MIPMAP (currently 64) consecutive SQUAREs in Row-Major
form. Each Square is stored as consecutive 32-bit 0GBR TEXELs in Row-Major form (the 0 in the
format means that those bits are waste). Please note that on LITTLE_ENDIAN platforms the
32-bit 0BGR is identical in representation to 4*8-bit RGB0, however on BIG_ENDIAN platforms
it is 4*8-bit 0BGR.
The ALPHA-VALUE MAP consists of NUMBER OF SOURCE TEXTURES individual TEXTURE-ALPHA-MAPs.
Individual TEXTURE-ALPHA-MAPs consist of a SQUARES_PER_TILE_EDGE by SQUARES_PER_TILE_EDGE
Row-Major array of 8-bit alpha blending values. The original code only used the high six bits
of each 8-bit value, but I am using the whole thing. I don't know if the lower two bits even
have meaningful values, but since they are the low-order two bits I don't much care; the worst
it can do is introduce a charming randomness. The ALPHELs are 8-bit fixed point, implicitly
divided by 256. It is implied by the code that for each offset into the TEXTURE-ALPHA-MAPs,
the sum of the ALPHELs at that offset across all of the TEXTURE-ALPHA-MAPs is less than 1.
I don't know where this is enforced.
Since the resolution of the ALPHA-MAP is one ALPHEL per SQUARE, the ALPHELs are interpolated
across the SQUARE when the terrains are being blended. Each ALPHEL is the ALPHA-VALUE of the
lower-left corner of the corresponding square. In order to compute the unlit blended texture
of a SQUARE (each SQUARE is processed separately), for each SOURCE TEXTURE the ALPHELs at the
four corners of the SQUARE are taken and interpolated smoothly across the square.
<b>How Blender::blend() does its thing:</b>
Blend() blends an array of SQUAREs of the TILE and a LIGHT-MAP into an 8-level MIP-MAP of
from 128x128 to 1x1 6-bit RGBA-5551 TEXELs per BIT-MAP. The location in the TILE to blend
from is specified by the X,Y co-ordinate of the lower-left corner and the length in SQUAREs
of a side of the square to be blended. The length of a side of the square to be blended in
SQUAREs combined with the fixed 128x128 size of the highest resolution destination BIT-MAP
implies a umber of TEXELs per SQUARE.
Blend() blends the desired SQUAREs into the highest resolution texture of the MIP-MAP and
generates the rest of the MIP-MAP from the first one (this seems like it should be an
independent utility).
Blend processes each SQUARE in turn, using the Terrain Grid to choose which SOURCE TEXTUREs
apply to that square, and the ALPHA-MAPs for that SQUARE to determine the contribution
of individual SOURCE TEXTURE's TEXELs. This is a simple multiplication of TEXEL values
by the interpolated ALPHELs.
It then applies the light map by sub-dividing the SQUARE into LUMELS_PER_SQUARE sub-squares and
interpolating LUMEL values across the sub-square in a manner exactly similar to the ALPHA-MAP. Each
LUMEL is an RGB triple, and each component of the LUMEL is multipled by the corresponding component
of the unlit texture to create the lit texture.
@note Warning, this code is ugly, even though it is pretty well documented. Flee!
*/
class Blender
{
/// Pointer to big buffer of source textures and mipmaps.
U32 *bmp_alloc_ptr;
/// One square buffer used for blending...
U32 *blendbuffer;
/// List of pointers into bmp buffer. Grouped by mip level,
/// so first X pointers are textures 0-X, mip 0.
U32 **bmpdata;
/// List of pointers to alpha data for the bmp types.
U8 **alpha_data;
/// Number of bmp types
int num_src_bmps;
/// Mip levels (including top detail) for each bmp type
int num_mip_levels;
/// C version of the blender
inline void blend_c( int x, int y, int level, const U16 *lightmap, U16 **destmips );
#if defined(__VEC__)
/// Altivec version of the blender
inline void blend_vec( int x, int y, int level, const U16 *lightmap, U16 **destmips );
#endif
public:
/// Constructor
///
/// @param num_bmp_types Number of textures we are blending.
/// @param mips_per_bmp This should include top level (always >= 1).
/// @param alphadata This is an 8 bit 256x256 bitmap.
Blender( int num_bmp_types, int mips_per_bmp, U8 **alphadata );
~Blender();
/// Blends into 5551 format.
///
/// X and Y are in blocks (same resolution as alpha table, i.e. at
/// high detail, there are 4x4 blocks covered by the 128x128 destination bmp.)
///
/// @param x Position in blocks.
/// @param y Position in blocks.
/// @param lightmap A 16 bit 512x512 bitmap.
/// @param level What mipmapping level to blend to?
/// @param destmips This is an array of pointers to the bitmap and it's
/// mips to be filled in by this function
void blend( int x, int y, int level, const U16 *lightmap, U16 **destmips );
/// Add a texture to use in blending.
///
/// Call this once per bmp type. It copies the bmp into it's own format,
/// so you can then delete your versions of the bmp and mips.
///
/// @param bmp_type Type of the bitmap.
/// @param bmps This is an array of pointers to the bitmap and its mipmaps,
/// highest detail first. Should be in 24bit format.
void addSourceTexture( int bmp_type, const U8 **bmps );
#if defined(__VEC__)
/// flag to determine which version of the blender is used.
static bool smUseVecBlender;
#endif
};
#endif

1367
engine/terrain/blender_asm.asm Executable file

File diff suppressed because it is too large Load Diff

166
engine/terrain/bvQuadTree.cc Executable file
View File

@ -0,0 +1,166 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "terrain/bvQuadTree.h"
#include "console/console.h"
BVQuadTree::BVQuadTree(BitVector *bv)
{
if (bv != NULL)
init(*bv);
else
{
BitVector localBV;
localBV.setSize(4);
localBV.set();
init(localBV);
}
}
BVQuadTree::~BVQuadTree()
{
while (mQTHierarchy.size() > 0)
{
delete mQTHierarchy.last();
mQTHierarchy.pop_back();
}
}
bool BVQuadTree::isSet(const Point2F &pos, S32 level) const
{
AssertFatal(pos.x >= 0. && pos.x <= 1., "BVQuadTree::isSet: x must be in range [0,1]");
AssertFatal(pos.y >= 0. && pos.y <= 1., "BVQuadTree::isSet: y must be in range [0,1]");
AssertFatal(level >= 0, "BVQuadTree:isSet: level must be greater than or equal to zero");
if (level >= mQTHierarchy.size())
// force to be within resolution of QT
level = mQTHierarchy.size() - 1;
if (level < 0)
level = 0;
F32 dimension = F32(1 << level);
U32 offset = U32((F32(U32(pos.y * dimension)) + pos.x) * dimension);
return(mQTHierarchy[level]->test(offset));
}
bool BVQuadTree::isClear(const Point2F &pos, S32 level) const
{
AssertFatal(pos.x >= 0. && pos.x <= 1., "BVQuadTree::isClear: x must be in range [0,1]");
AssertFatal(pos.y >= 0. && pos.y <= 1., "BVQuadTree::isClear: y must be in range [0,1]");
AssertFatal(level >= 0, "BVQuadTree:isClear: level must be greater than or equal to zero");
if (level >= mQTHierarchy.size())
// force to be within resolution of QT
level = mQTHierarchy.size() - 1;
if (level < 0)
level = 0;
F32 dimension = F32(1 << level);
U32 offset = U32((F32(U32(pos.y * dimension)) + pos.x) * dimension);
return(mQTHierarchy[level]->test(offset) == false);
}
/* Initialize the quadtree with the provided bit vector. Note that the bit vector
* denotes data at each corner of the quadtree cell. Hence the dimension for the
* deepest quadtree level must be 1 less than that of the bit vector.
*/
void BVQuadTree::init(const BitVector &bv)
{
while (mQTHierarchy.size() > 0)
{
delete mQTHierarchy.last();
mQTHierarchy.pop_back();
}
// get the width/height of the square bit vector
U32 bvDim = (U32)mSqrt((F32)bv.getSize());
U32 qtDim = bvDim - 1; // here's where we correct dimension...
AssertFatal(((mSqrt((F32)bv.getSize()) - 1) == (F32)qtDim) && (isPow2(qtDim) == true), "BVQuadTree::init: bit vector size must be power of 4");
// find the power of two we're starting at
mResolution = qtDim;
U32 level = 0;
while ((1 << (level + 1)) <= qtDim)
level++;
BitVector *initBV = new BitVector;
AssertFatal(initBV != NULL, "BVQuadTree::init: failed to allocate highest detail bit vector");
initBV->setSize(qtDim * qtDim);
initBV->clear();
for (S32 i = 0; i < qtDim; i++)
for (S32 j = 0; j < qtDim; j++)
{
S32 k = i * bvDim + j;
if (bv.test(k) || bv.test(k + 1) || bv.test(k + bvDim) || bv.test(k + bvDim + 1))
initBV->set(i * qtDim + j);
}
mQTHierarchy.push_back(initBV);
if (level > 0)
buildHierarchy(level - 1);
}
#ifdef BV_QUADTREE_DEBUG
void BVQuadTree::dump() const
{
char str[256];
U32 strlen;
for (U32 i = 0; i < mQTHierarchy.size(); i++)
{
U32 dimension = 1 << i;
Con::printf("level %d:", i);
for (U32 y = 0; y < dimension; y++)
{
U32 yOffset = y * dimension;
str[0] = '\0';
for (U32 x = 0; x < dimension; x++)
{
U32 offset = yOffset + x;
strlen = dStrlen(str);
if (strlen < 252)
dSprintf(str + strlen, 256 - strlen, mQTHierarchy[i]->isSet(offset) ? "1 " : "0 ");
else
{
dSprintf(str + strlen, 256 - strlen, "...");
break;
}
}
Con::printf("%s", str);
}
}
}
#endif
void BVQuadTree::buildHierarchy(U32 level)
{
BitVector *priorBV = mQTHierarchy.first();
BitVector *levelBV = new BitVector;
AssertFatal(levelBV != NULL, "BVQuadTree::buildHierarchy: failed to allocate bit vector");
U32 levelDim = (1 << level);
levelBV->setSize(levelDim * levelDim);
levelBV->clear();
U32 yOffset, offset, yPriorOffset, priorOffset;
// COULD THIS BE DONE WITH A SINGLE LOOP?
for (U32 y = 0; y < levelDim; y++)
{
yOffset = y * levelDim;
yPriorOffset = yOffset << 2;
for (U32 x = 0; x < levelDim; x++)
{
offset = yOffset + x;
priorOffset = yPriorOffset + (x << 1);
if (priorBV->test(priorOffset) || priorBV->test(priorOffset + 1) ||
priorBV->test(priorOffset + (levelDim << 1)) ||
priorBV->test(priorOffset + (levelDim << 1) + 1))
levelBV->set(offset);
}
}
mQTHierarchy.push_front(levelBV);
if (level > 0)
buildHierarchy(level - 1);
}

46
engine/terrain/bvQuadTree.h Executable file
View File

@ -0,0 +1,46 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _BVQUADTREE_H_
#define _BVQUADTREE_H_
//#define BV_QUADTREE_DEBUG
#ifndef _TVECTOR_H_
#include "core/tVector.h"
#endif
#ifndef _BITVECTOR_H_
#include "core/bitVector.h"
#endif
#ifndef _MPOINT_H_
#include "math/mPoint.h"
#endif
/// A bit vector quad tree, used to track flags for the terrain.
class BVQuadTree
{
protected:
VectorPtr<BitVector*> mQTHierarchy;
U32 mResolution;
public:
BVQuadTree(BitVector *bv = NULL);
~BVQuadTree();
bool isSet(const Point2F &pos, S32 level) const;
bool isClear(const Point2F &pos, S32 level) const;
void init(const BitVector &bv);
#ifdef BV_QUADTREE_DEBUG
void dump() const;
#endif
U32 countLevels() const { return(mQTHierarchy.size()); }
protected:
void buildHierarchy(U32 level);
private:
BVQuadTree(const BVQuadTree &);
BVQuadTree& operator=(const BVQuadTree &);
};
#endif

377
engine/terrain/fluid.h Executable file
View File

@ -0,0 +1,377 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _FLUID_H_
#define _FLUID_H_
//==============================================================================
// TO DO LIST
//==============================================================================
// - ARB support?
// - Optimize the fog given water is horizontal
// - New fog system
// - Attempt to reject fully fogged low LOD blocks
//==============================================================================
// - Designate specular map?
// - Turn off specular? (for lava)
//==============================================================================
//==============================================================================
// ASSUMPTIONS:
// - A single repetition of the terrain (or a "rep") is 256x256 squares.
// - A terrain square is 8 meters on a side.
// - The fluid can NOT be rotated on any axis.
// - The "anchor point" for the fluid can be on any discrete square corner.
// - The size of the fluid is constrained to be either a multiple of 4 or 8
// squares.
//==============================================================================
// DISCUSSION:
// - If the overall size of the fluid is less than a quarter of a terrain rep,
// then the fluid will use a "double resolution" mode. Thus, when the fluid
// is sufficiently small, it gets more detailed.
// - The fluid renders blocks in one of two sizes, LOW and HIGH.
// - Blocks are 8 squares in normal (LOW) resolution mode, and 4 in high (LOW).
// - A quad tree is used to quickly cull down to the blocks.
// - Reject and accept masks are used by the quad tree.
//==============================================================================
//==============================================================================
// INCLUDES
//==============================================================================
#ifndef _TYPES_H_
#include "platform/types.h"
#endif
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _MMATH_H_
#include "math/mMath.h"
#endif
#include "core/color.h"
//==============================================================================
// DEFINES
//==============================================================================
#define s32 S32
#define u32 U32
#define s16 S16
#define u16 U16
#define s8 S8
#define u8 U8
#define byte U8
#define f32 F32
#define PI (3.141592653589793238462643f)
#define SECONDS ((f32)(Sim::getCurrentTime()) * 0.001f)
#define MALLOC dMalloc
#define REALLOC dRealloc
#define FREE dFree
#define MEMSET dMemset
#define TWO_PI (PI * 2.0f)
#define FMOD(a,b) (f32)mFmod( a, b )
#define LENGTH3(a,b,c) (f32)mSqrt( (a)*(a) + (b)*(b) + (c)*(c) )
#define SINE(a) (float)mSin( a )
#define COSINE(a) (float)mCos( a )
#define ASSERT(exp)
//==============================================================================
// TYPES
//==============================================================================
//
// Order for [4] element arrays...
//
// 2----3 Y
// | | |
// | | |
// 0----1 0----X
//
//==============================================================================
class fluid
{
//------------------------------------------------------------------------------
// Public Types
//
public:
typedef f32 compute_fog_fn( f32 DeltaZ, f32 D );
//------------------------------------------------------------------------------
// Public Functions
//
public:
fluid ( void );
~fluid ();
//
// Render (in FluidRender.cc):
//
void Render ( bool& EyeSubmerged );
//
// Setup per frame (in FluidSupport.cc):
//
void SetEyePosition ( f32 X, f32 Y, f32 Z ) { m_Eye.set( X, Y, Z ); }
void SetFrustrumPlanes ( f32* pFrustrumPlanes );
//
// Setup at initialization (in FluidSupport.cc):
//
void SetInfo ( f32& X0,
f32& Y0,
f32& SizeX,
f32& SizeY,
f32 SurfaceZ,
f32 WaveAmplitude,
f32& Opacity,
f32& EnvMapIntensity,
s32 RemoveWetEdges,
bool UseDepthMap,
f32 TessellationSurface,
f32 TessellationShore,
f32 SurfaceParallax,
f32 FlowAngle,
f32 FlowRate,
f32 DistortGridScale,
f32 DistortMagnitude,
f32 DistortTime,
ColorF SpecColor,
F32 SpecPower,
bool tiling,
u32 terrainSize,
u32 terrainBlockSize);
void SetTerrainData ( u16* pTerrainData );
void SetTextures ( TextureHandle Base,
TextureHandle EnvMapOverTexture,
TextureHandle EnvMapUnderTexture,
TextureHandle ShoreTexture,
TextureHandle DepthTexture,
TextureHandle ShoreDepthTexture,
TextureHandle SpecMaskTexture ); // MM: Added Various Textures.
void SetLightMapTexture ( TextureHandle LightMapTexture );
void SetFogParameters ( f32 R, f32 G, f32 B, f32 VisibleDistance );
void SetFogFn ( compute_fog_fn* pFogFn );
//
// Run time interrogation (in FluidSupport.cc):
//
s32 IsFluidAtXY ( f32 X, f32 Y ) const;
//------------------------------------------------------------------------------
// Private Types
//
private:
struct plane { f32 A, B, C, D; };
struct rgba { f32 R, G, B, A; };
struct xyz { f32 X, Y, Z; };
struct uv { f32 U, V; };
struct node
{
s32 Level;
s32 MaskIndexX, MaskIndexY;
s32 BlockX0, BlockY0; // World Block
f32 X0, Y0; // World Position
f32 X1, Y1; // World Position
byte ClipBits[4];
};
struct block
{
f32 X0, Y0;
f32 X1, Y1;
f32 Distance[4]; // Distance from eye
f32 LOD [4]; // Level of detail
};
// Rendering phases:
// Phase 1 - Base texture (two passes of cross faded textures)
// Phase 2 - Shadow map
// Phase 3 - Environment map / Specular
// Phase 4 - Fog
struct vertex
{
Point3F XYZ; // All phases - Position
// rgba RGBA1a; // Phase 1a - Base alpha, first pass (MM: Removed)
// rgba RGBA1b; // Phase 1b - Base alpha, second pass (MM: Removed)
uv UV1; // Phase 1 - MM: Base UV.
uv UV2; // Phase 2 - MM: Shoreline UV.
rgba RGBA3; // Phase 3 - MM: EnvMap Colour/Alpha.
uv UV3; // Phase 3 - EnvMap UV
rgba RGBA4; // Phase 4 - Fog Color/Alpha
uv UV4; // Test - MM: Depth Alpha Map.
ColorF SPECULAR;
};
//------------------------------------------------------------------------------
// Private Variables
//
public:
bool mTile;
s32 m_SquareX0, m_SquareY0; // Anchor in terrain squares
s32 m_SquaresInX, m_SquaresInY; // Number of squares in fluid region
private:
f32 m_DepthTexelX, m_DepthTexelY; // MM: Added Depth Texel X/Y.
s32 m_BlocksInX, m_BlocksInY; // Number of blocks in fluid region
f32 m_SurfaceZ; // Altitude of fluid surface
s32 m_RemoveWetEdges; // Dry fill all edges of the fluid block
s32 m_HighResMode; // Blocks are 4x4 (high res) or 8x8 squares (normal)
plane m_Plane[6]; // Frustrum clip planes: 0=T 1=B 2=L 3=R 4=N 5=F
Point3F m_Eye;
f32 m_Seconds;
f32 m_BaseSeconds;
rgba m_FogColor;
f32 m_VisibleDistance;
f32 m_Opacity;
f32 m_EnvMapIntensity; // MM: Added Over/Under Env Texture Support.
f32 m_WaveAmplitude;
f32 m_WaveFactor;
u16* m_pTerrain; // 256x256 data for the terrain
bool m_UseDepthMap; // MM: Use Depth Map Flag?
F32 m_TessellationSurface; // MM: Tessellation Surface.
F32 m_TessellationShore; // MM: Tessellation Shore.
F32 m_SurfaceParallax; // MM: Surface Parallax.
F32 m_FlowAngle; // MM: Flow Angle.
F32 m_FlowRate; // MM: Flow Rate.
F32 m_FlowMagnitudeS; // MM: Flow Magnitude S.
F32 m_FlowMagnitudeT; // MM: Flow Magnitude T.
F32 m_DistortGridScale; // MM: Distort Grid Scale.
F32 m_DistortMagnitude; // MM: Distort Magnitude.
F32 m_DistortTime; // MM: Distort Time.
ColorF m_SpecColor;
F32 m_SpecPower;
U32 m_TerrainSize;
U32 m_TerrainBlockSize;
U32 m_TerrainBlockShift;
TextureHandle m_BaseTexture;
TextureHandle m_EnvMapOverTexture; // MM: Added Over/Under Env Texture Support.
TextureHandle m_EnvMapUnderTexture; // MM: Added Over/Under Env Texture Support.
TextureHandle m_LightMapTexture;
TextureHandle m_ShoreTexture; // MM: Added Shore Texture.
TextureHandle m_DepthTexture; // MM: Added Depth Texture.
TextureHandle m_ShoreDepthTexture; // MM: Added Shore-Depth Texture.
TextureHandle m_SpecMaskTex;
f32 m_Step[5]; // [0] = 0
// [1] = 1/4 block step
// [2] = 1/2 block step
// [3] = 3/4 block step
// [4] = 1 block step
compute_fog_fn* m_pFogFn;
// Bit masks to trivially accept or reject the progressive levels for the
// quad tree recursion. No need for an accept mask at the highest level
// since it is just the exact opposite of the reject mask at that level.
static s32 m_MaskOffset[6]; // Offset for given level into masks.
byte m_RejectMask[ 1 + 1 + 2 + 8 + 32 + 128 ];
byte m_AcceptMask[ 1 + 1 + 2 + 8 + 32 ];
//
// Shared among instances of fluid.
//
static vertex* m_pVertex;
static s32 m_VAllocated;
static s32 m_VUsed;
static s16* m_pIndex;
static s16* m_pINext;
static s16 m_IOffset;
static s32 m_IAllocated;
static s32 m_IUsed;
static s32 m_Instances;
//
// Debug variables.
//
public:
s32 m_ShowWire;
s32 m_ShowNodes;
s32 m_ShowBlocks;
s32 m_ShowBaseA;
s32 m_ShowBaseB;
s32 m_ShowLightMap;
s32 m_ShowEnvMap;
s32 m_ShowFog;
//------------------------------------------------------------------------------
// Private Functions
//
private:
inline F32 DISTANCE( F32 x, F32 y, F32 z )
{
return( LENGTH3( (x)-m_Eye.x, (y)-m_Eye.y, (z)-m_Eye.z ) );
}
//
// Functions in FluidSupport.cc:
//
s32 GetAcceptBit ( s32 Level, s32 IndexX, s32 IndexY ) const;
s32 GetRejectBit ( s32 Level, s32 IndexX, s32 IndexY ) const;
void SetAcceptBit ( s32 Level, s32 IndexX, s32 IndexY, s32 Value );
void SetRejectBit ( s32 Level, s32 IndexX, s32 IndexY, s32 Value );
void BuildLowerMasks ( void );
void RebuildMasks ( void );
void FloodFill ( u8* pGrid, s32 x, s32 y, s32 SizeX, s32 SizeY );
//
// Functions in FluidQuadTree.cc
//
void RunQuadTree ( bool& EyeSubmerged );
f32 ComputeLOD ( f32 Distance );
byte ComputeClipBits ( f32 X, f32 Y, f32 Z );
void ProcessNode ( node& Node );
void ProcessBlock ( block& Block );
void ProcessBlockLODHigh ( block& Block );
void ProcessBlockLODMorph ( block& Block );
void ProcessBlockLODTrans ( block& Block );
void ProcessBlockLODLow ( block& Block );
void SetupVert ( f32 X, f32 Y, f32 Distance, vertex* pV );
void InterpolateVerts ( vertex* pV0,
vertex* pV1,
vertex* pV2,
vertex* pV3,
vertex* pV4,
f32 LOD0,
f32 LOD4 );
void InterpolateVert ( vertex* pV0,
vertex* pV1,
vertex* pV2,
f32 LOD );
void ReleaseVertexMemory ( void );
vertex* AcquireVertices ( s32 Count );
void AddTriangleIndices ( s16 I1, s16 I2, s16 I3 );
void CalcVertSpecular ();
};
//==============================================================================
#endif // FLUID_HPP
//==============================================================================

1074
engine/terrain/fluidQuadTree.cc Executable file

File diff suppressed because it is too large Load Diff

842
engine/terrain/fluidRender.cc Executable file
View File

@ -0,0 +1,842 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "terrain/fluid.h"
#include "dgl/dgl.h"
#include "lightingSystem/sgLightManager.h"
#include "sceneGraph/sceneGraph.h"
#include "math/mathUtils.h"
//==============================================================================
// FUNCTIONS
//==============================================================================
// MM:
// All these nice neat transitional state blocks need blending together
// to reduce the state changes. I'll do this when I finally get to
// locking it down. ;)
//
void fluid::Render( bool& EyeSubmerged )
{
f32 BaseDriftX, BaseDriftY;
f32 Q1 = 1.0f / (F32(m_TerrainBlockSize) * 6.0f); // This just looks good.
f32 Q2 = 1.0f / F32(m_TerrainSize); // This is the size of the terrain.
f32 SBase[] = { Q1, 0.0f, 0.0f, 0.0f };
f32 TBase[] = { 0.0f, Q1, 0.0f, 0.0f };
f32 SLMap[] = { Q2, 0.0f, 0.0f, 0.0f };
f32 TLMap[] = { 0.0f, Q2, 0.0f, 0.0f };
// Several attributes in the fluid vary over time. Get a definitive time
// reading now to be used throughout this render pass.
m_Seconds = (SECONDS - m_BaseSeconds);
// Based on the view frustrum, accumulate the list of triangles that
// comprise the fluid surface for this render pass.
RunQuadTree( EyeSubmerged );
CalcVertSpecular();
// Quick debug render.
#if 0
if( 0 )
{
s32 i;
for( i = 0; i < m_IUsed / 3; i++ )
{
glDisable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glBegin ( GL_TRIANGLES );
glColor4f ( 0.0f, 1.0f, 0.0f, 0.5f );
glVertex3f ( m_pVertex[m_pIndex[i*3+0]].XYZ.x, m_pVertex[m_pIndex[i*3+0]].XYZ.y, m_pVertex[m_pIndex[i*3+0]].XYZ.z );
glVertex3f ( m_pVertex[m_pIndex[i*3+1]].XYZ.x, m_pVertex[m_pIndex[i*3+1]].XYZ.y, m_pVertex[m_pIndex[i*3+1]].XYZ.z );
glVertex3f ( m_pVertex[m_pIndex[i*3+2]].XYZ.x, m_pVertex[m_pIndex[i*3+2]].XYZ.y, m_pVertex[m_pIndex[i*3+2]].XYZ.z );
glEnd ();
}
}
#endif
//
// We need to compute some time dependant values before we start rendering.
//
// Base texture drift.
{
// MM: Added Depth-Map Specific drift.
if (m_UseDepthMap)
{
// MM: Adjust Flow Magnitude.
m_FlowMagnitudeS = (m_FlowRate * m_Seconds) * mCos(mDegToRad(m_FlowAngle));
m_FlowMagnitudeT = (m_FlowRate * m_Seconds) * mSin(mDegToRad(m_FlowAngle));
// MM: Added Flow Control.
BaseDriftX = m_FlowMagnitudeS;
BaseDriftY = m_FlowMagnitudeT;
}
else
{
#define BASE_DRIFT_CYCLE_TIME 8.0f
#define BASE_DRIFT_RATE 0.02f
#define BASE_DRIFT_SCALAR 0.03f
f32 Phase = FMOD( m_Seconds * (TWO_PI/BASE_DRIFT_CYCLE_TIME), TWO_PI );
BaseDriftX = m_Seconds * BASE_DRIFT_RATE;
BaseDriftY = COSINE( Phase ) * BASE_DRIFT_SCALAR;
}
}
//--------------------------------------------------------------------------
//--
//-- Let's rock.
//--
//--------------------------------------------------------------------------
//-- Debug - wire
if( m_ShowWire )
{
glPolygonMode ( GL_FRONT_AND_BACK, GL_LINE );
glEnableClientState ( GL_VERTEX_ARRAY );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_DEPTH_TEST );
glEnable ( GL_BLEND );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glColor4f ( 0.5f, 0.5f, 0.5f, 0.5f );
glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
glDisable ( GL_BLEND );
glEnable ( GL_DEPTH_TEST );
glColor4f ( 1.0f, 1.0f, 0.0f, 1.0f );
glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
glPolygonMode ( GL_FRONT_AND_BACK, GL_FILL );
}
// MM: Added completely new multi-texturing section.
// Don't write into the Depth Buffer.
glDepthMask ( GL_FALSE);
// MM: Let's cull backfaces.
//
// NOTE:- This will get promoted to an option for large-wave cases.
glEnable(GL_CULL_FACE);
// MM: Set culling mode.
glCullFace(EyeSubmerged?GL_BACK:GL_FRONT);
// MM: Select Appropriate Environment Map.
U32 EnvMapViewTex = EyeSubmerged ? m_EnvMapUnderTexture.getGLName() : m_EnvMapOverTexture.getGLName();
// Have we got multi-texturing?
if (m_UseDepthMap && dglDoesSupportARBMultitexture())
{
// Lock Arrays.
if (dglDoesSupportCompiledVertexArray()) glLockArraysEXT(0, m_VUsed);
m_Opacity = 1.0f;
// Disabled - The single pass and multi-pass versions look totally different.
// In addition, even using multitexture combiner operations, there is no way
// to achieve the exact same surface effect between multitexture and multi-pass
// because of the different ways they are blended into the frame buffer.
// The current solution is to disable the single pass method in favor of consistency.
// if (dglGetMaxTextureUnits() > 2)
if ( 0 )
{
// More than Dual TMU's ... let's do it a lot quicker ...
// *****************************************************************
//
// Surface Map (Single-Pass).
//
// *****************************************************************
// *****************************************************************
// TMU #0 - Surface #1
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_BaseTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV1) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode ( GL_TEXTURE );
glPushMatrix ();
glLoadIdentity ();
glTranslatef ( BaseDriftX, BaseDriftY, 0.0f );
// *****************************************************************
// TMU #1 - Surface #2
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB (GL_TEXTURE1_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_BaseTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV1) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glMatrixMode ( GL_TEXTURE );
glPushMatrix ();
glLoadIdentity ();
glRotatef ( 30.0f, 0.0f, 0.0f, 1.0f );
glTranslatef ( BaseDriftX * m_SurfaceParallax, BaseDriftY * m_SurfaceParallax, 0.0f );
// *****************************************************************
// TMU #2 - Alpha Depth Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glActiveTextureARB (GL_TEXTURE2_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_DepthTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV4) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// *****************************************************************
// Draw the Surface.
// *****************************************************************
glDrawElements( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
// *****************************************************************
// Restore State #2 - Alpha Depth Map.
// *****************************************************************
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
// *****************************************************************
// Restore State #1 - Surface #2
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB (GL_TEXTURE1_ARB);
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glPopMatrix ();
// *****************************************************************
// Restore State #0 - Surface #1
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glPopMatrix ();
}
else
{
// Dual TMU's ... let's do it a little slower ...
// *****************************************************************
//
// Surface Map (Double-Pass).
//
// *****************************************************************
// *****************************************************************
// TMU #0 - Surface #1
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_BaseTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV1) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode ( GL_TEXTURE );
glPushMatrix ();
glLoadIdentity ();
glTranslatef ( BaseDriftX, BaseDriftY, 0.0f );
// *****************************************************************
// TMU #1 - Alpha Depth Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB (GL_TEXTURE1_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_DepthTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV4) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// *****************************************************************
// Draw the Surface#1 (Pass One)
// *****************************************************************
glDrawElements( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
// *****************************************************************
// TMU #0 - Surface #2
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glPopMatrix ();
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_BaseTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV1) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glMatrixMode ( GL_TEXTURE );
glPushMatrix ();
glLoadIdentity ();
glRotatef ( 30.0f, 0.0f, 0.0f, 1.0f );
glTranslatef ( BaseDriftX * m_SurfaceParallax, BaseDriftY * m_SurfaceParallax, 0.0f );
// *****************************************************************
// TMU #1 - Alpha Depth Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB (GL_TEXTURE1_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_DepthTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV4) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// *****************************************************************
// Draw the Surface#2 (Pass Two)
// *****************************************************************
glDrawElements( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
// *****************************************************************
// Restore State #1 - Alpha Depth Map.
// *****************************************************************
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
// *****************************************************************
// Restore State #0 - Surface #1/2
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
glPopMatrix ();
}
// *****************************************************************
//
// Shore Map.
//
// *****************************************************************
// *****************************************************************
// TMU #0 - Shore #1
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_ShoreTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV2) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode ( GL_TEXTURE );
glPushMatrix ();
glLoadIdentity ();
glTranslatef ( BaseDriftX, BaseDriftY, 0.0f );
// *****************************************************************
// TMU #1 - Shore Depth Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB (GL_TEXTURE1_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_ShoreDepthTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV4) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// *****************************************************************
// Draw the Surface#1 (Pass One)
// *****************************************************************
glDrawElements( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
// *****************************************************************
// Restore State #1 - Shore Depth Map.
// *****************************************************************
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
// *****************************************************************
// Restore State #0 - Shore #1
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
glPopMatrix ();
// *****************************************************************
//
// Specular highlights
//
// *****************************************************************
// *****************************************************************
// TMU #0 - Specular Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glEnableClientState ( GL_COLOR_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_SpecMaskTex.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV1) );
glColorPointer ( 4, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].SPECULAR) );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE );
glMatrixMode ( GL_TEXTURE );
glPushMatrix ();
glLoadIdentity ();
glRotatef ( 30.0f, 0.0f, 0.0f, 1.0f );
glScalef ( 0.2f, 0.2f, 0.2f );
// *****************************************************************
// TMU #1 - Alpha Depth Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_DepthTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV4) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// *****************************************************************
// Draw the Surface#1 (Pass One)
// *****************************************************************
glDrawElements( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
// *****************************************************************
// Restore State #1 - Alpha Depth Map.
// *****************************************************************
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState ( GL_TEXTURE_COORD_ARRAY );
glDisableClientState ( GL_VERTEX_ARRAY );
// *****************************************************************
// Restore State #0 - Specular Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
glPopMatrix ();
glMatrixMode ( GL_MODELVIEW );
// *****************************************************************
//
// Environment Map.
//
// *****************************************************************
// Are we using the environment map?
if (m_EnvMapIntensity > 0.0f)
{
// *****************************************************************
// TMU #0 - Environment Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glEnableClientState ( GL_COLOR_ARRAY );
glBindTexture ( GL_TEXTURE_2D, EnvMapViewTex );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV3) );
glColorPointer ( 4, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].RGBA3) );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// *****************************************************************
// TMU #1 - Alpha Depth Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glBindTexture ( GL_TEXTURE_2D, m_DepthTexture.getGLName() );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV4) );
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// *****************************************************************
// Draw the Surface.
// *****************************************************************
glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
// *****************************************************************
// Restore State #1 - Alpha Depth Map.
// *****************************************************************
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
// *****************************************************************
// Restore State #0 - ENvironment Map.
// *****************************************************************
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glActiveTextureARB (GL_TEXTURE0_ARB);
glDisable ( GL_TEXTURE_2D );
glDisable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
}
// *****************************************************************
//
// Fog Map.
//
// *****************************************************************
// *****************************************************************
// TMU #0 - Fog Map.
// *****************************************************************
glEnableClientState ( GL_VERTEX_ARRAY );
glEnableClientState ( GL_COLOR_ARRAY );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glColorPointer ( 4, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].RGBA4) );
glEnable ( GL_BLEND );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
// *****************************************************************
// Draw the Surface.
// *****************************************************************
glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
// *****************************************************************
// Restore State #0 - Fog Map.
// *****************************************************************
glDisable ( GL_BLEND );
glDisableClientState ( GL_COLOR_ARRAY );
glDisableClientState ( GL_VERTEX_ARRAY );
// Restore Current Matrix.
glMatrixMode ( GL_MODELVIEW );
// Unlock Arrays.
if (dglDoesSupportCompiledVertexArray()) glUnlockArraysEXT();
}
else
{
//--------------------------------------------------------------------------
//-- Initializations for Phase 1 - base textures
glPolygonMode ( GL_FRONT_AND_BACK, GL_FILL );
glEnableClientState ( GL_VERTEX_ARRAY );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glMatrixMode ( GL_TEXTURE );
glPushMatrix ();
glLoadIdentity ();
// glEnableClientState ( GL_COLOR_ARRAY ); // MM: Removed Colour Array.
glEnable ( GL_TEXTURE_GEN_S );
glEnable ( GL_TEXTURE_GEN_T );
glTexGeni ( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
glTexGeni ( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
glTexGenfv ( GL_S, GL_OBJECT_PLANE, SBase );
glTexGenfv ( GL_T, GL_OBJECT_PLANE, TBase );
glBindTexture ( GL_TEXTURE_2D, m_BaseTexture.getGLName() );
//--------------------------------------------------------------------------
//-- Initializations for Phase 1a - first base texture
glTranslatef ( BaseDriftX, BaseDriftY, 0.0f ); // MM: Added Drift Translation.
//glRotatef ( 30.0f, 0.0f, 0.0f, 1.0f ); // MM: Removed Rotation.
// glColorPointer ( 4, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].RGBA1a) ); // MM: Removed Colour Array.
glColor4f ( 1.0f,1.0f,1.0f, m_Opacity ); // MM: Added Opacity.
//--------------------------------------------------------------------------
//-- Render Phase 1a - first base texture
if( m_ShowBaseA )
{
glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
}
//--------------------------------------------------------------------------
//-- Initializations for Phase 1b - second base texture
glRotatef ( 30.0f, 0.0f, 0.0f, 1.0f );
glTranslatef ( BaseDriftX * m_SurfaceParallax, BaseDriftY * m_SurfaceParallax, 0.0f ); // MM: Added Drift Translation.
// glColorPointer ( 4, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].RGBA1b) ); // MM: Removed Colour Array.
//--------------------------------------------------------------------------
//-- Render Phase 1b - first base texture
if( m_ShowBaseB )
{
glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
}
//--------------------------------------------------------------------------
//-- Cleanup from Phase 1 - base textures
glDisableClientState( GL_COLOR_ARRAY ); // MM: Removed Colour Array.
glPopMatrix ();
//--------------------------------------------------------------------------
//-- Initializations for Phase 2 - light map
// glColor4f ( 1.0f, 1.0f, 1.0f, 1.0f );
// glBindTexture ( GL_TEXTURE_2D, m_LightMapTexture.getGLName() );
// glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// glBlendFunc ( GL_DST_COLOR, GL_ZERO );
// glMatrixMode ( GL_TEXTURE );
// glPushMatrix ();
// glLoadIdentity ();
// glTexGenfv ( GL_S, GL_OBJECT_PLANE, SLMap );
// glTexGenfv ( GL_T, GL_OBJECT_PLANE, TLMap );
//--------------------------------------------------------------------------
//-- Render Phase 2 - light map
// if( m_ShowLightMap )
// {
// glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
// }
//--------------------------------------------------------------------------
//-- Cleanup from Phase 2 - light map
// glPopMatrix ();
glMatrixMode ( GL_MODELVIEW );
glDisable ( GL_TEXTURE_GEN_S );
glDisable ( GL_TEXTURE_GEN_T );
glEnableClientState ( GL_VERTEX_ARRAY );
glVertexPointer ( 3, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].XYZ) );
glEnable ( GL_TEXTURE_2D );
glEnable ( GL_BLEND );
//--------------------------------------------------------------------------
//-- Initializations for Phase 3 - environment map
glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
glTexCoordPointer ( 2, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].UV3) );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE );
glColor4f ( 1.0f, 1.0f, 1.0f, m_EnvMapIntensity );
glBindTexture ( GL_TEXTURE_2D, EnvMapViewTex );
//--------------------------------------------------------------------------
//-- Render Phase 3 - environment map / specular
if( m_ShowEnvMap )
{
glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
}
//--------------------------------------------------------------------------
//-- Initializations for Phase 4 - fog
glDisable ( GL_TEXTURE_2D );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnableClientState ( GL_COLOR_ARRAY );
glColorPointer ( 4, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].RGBA4) );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
//--------------------------------------------------------------------------
//-- Render Phase 4 - fog
if( m_ShowFog )
{
glDrawElements ( GL_TRIANGLES, m_IUsed, GL_UNSIGNED_SHORT, m_pIndex );
}
}
//--------------------------------------------------------------------------
//-- Cleanup from all Phases
// MM: Restore culling mode.
glCullFace(GL_BACK);
// MM: Stop culling backfaces.
glDisable(GL_CULL_FACE);
// Continue writing into the Depth Buffer.
glDepthMask(GL_TRUE);
glDisable ( GL_BLEND );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
//--------------------------------------------------------------------------
//-- We're done with the rendering.
}
//==============================================================================
void fluid::CalcVertSpecular()
{
Point3F lightDir;
LightInfo *sunLight = gClientSceneGraph->getLightManager()->sgGetSpecialLight(LightManager::sgSunLightType);
if(sunLight != NULL)
{
// calculate real sun elevation/azimuth.
lightDir = sunLight->mDirection;
}
else
{
// No, so set default light.
lightDir.set( 0.5f, 0.5f, -0.5f );
}
// Normalise light direction.
lightDir.normalize();
// loop through all displayed verts
for( U32 i=0; i<m_IUsed; i++ )
{
vertex *vert = m_pVertex + m_pIndex[i];
// perform half angle calculation
Point3F eyeVec( m_Eye - vert->XYZ );
eyeVec.normalize();
Point3F half( -lightDir + eyeVec );
half.normalize();
if( half.z < 0.0f ) half.z = 0.0f;
// store specular color in vert
vert->SPECULAR = m_SpecColor * pow( half.z, m_SpecPower );
}
}
//==============================================================================

678
engine/terrain/fluidSupport.cc Executable file
View File

@ -0,0 +1,678 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "terrain/fluid.h"
#include "dgl/dgl.h"
#include "console/simBase.h"
//==============================================================================
// VARIABLES
//==============================================================================
s32 fluid::m_Instances = 0;
s32 fluid::m_MaskOffset[6] = { 0, 1, 2, 4, 12, 44 };
//==============================================================================
// FUNCTIONS
//==============================================================================
fluid::fluid( void )
{
m_Instances += 1;
// Fill out fields with a stable, if useless, state.
m_SquareX0 = 0;
m_SquareY0 = 0;
m_SquaresInX = 4;
m_SquaresInY = 4;
m_BlocksInX = 1;
m_BlocksInY = 1;
m_HighResMode = 1;
m_RemoveWetEdges = 0;
m_SurfaceZ = 0.0f;
m_WaveAmplitude = 0.0f;
m_Opacity = 0.0f;
m_EnvMapIntensity = 1.0f;
m_BaseSeconds = SECONDS;
m_pTerrain = NULL;
// Set values on the debug flags.
m_ShowWire = 0;
m_ShowBlocks = 0;
m_ShowNodes = 0;
m_ShowBaseA = 1;
m_ShowBaseB = 1;
m_ShowLightMap = 1;
m_ShowEnvMap = 1;
m_ShowFog = 1;
m_TerrainSize = 2048;
m_TerrainBlockSize = 8;
m_TerrainBlockShift = 3;
}
//==============================================================================
fluid::~fluid()
{
m_Instances -= 1;
if( m_Instances == 0 )
{
ReleaseVertexMemory();
}
}
//==============================================================================
s32 fluid::GetRejectBit( s32 Level, s32 IndexX, s32 IndexY ) const
{
s32 BitNumber = (IndexY << Level) + IndexX;
s32 ByteNumber = m_MaskOffset[Level] + (BitNumber >> 3);
byte Byte = m_RejectMask[ ByteNumber ];
s32 Bit = (Byte >> (BitNumber & 0x07)) & 0x01;
return( Bit );
}
//==============================================================================
s32 fluid::GetAcceptBit( s32 Level, s32 IndexX, s32 IndexY ) const
{
if( Level == 5 )
return( !GetRejectBit( 5, IndexX, IndexY ) );
s32 BitNumber = (IndexY << Level) + IndexX;
s32 ByteNumber = m_MaskOffset[Level] + (BitNumber >> 3);
byte Byte = m_AcceptMask[ ByteNumber ];
s32 Bit = (Byte >> (BitNumber & 0x07)) & 0x01;
return( Bit );
}
//==============================================================================
void fluid::SetRejectBit( s32 Level, s32 IndexX, s32 IndexY, s32 Value )
{
s32 BitNumber = (IndexY << Level) + IndexX;
s32 ByteNumber = m_MaskOffset[Level] + (BitNumber >> 3);
byte Byte = 1 << (BitNumber & 0x07);
if( Value ) m_RejectMask[ ByteNumber ] |= Byte;
else m_RejectMask[ ByteNumber ] &= ~Byte;
}
//==============================================================================
void fluid::SetAcceptBit( s32 Level, s32 IndexX, s32 IndexY, s32 Value )
{
if( Level == 5 )
SetRejectBit( 5, IndexX, IndexY, !Value );
s32 BitNumber = (IndexY << Level) + IndexX;
s32 ByteNumber = m_MaskOffset[Level] + (BitNumber >> 3);
byte Byte = 1 << (BitNumber & 0x07);
if( Value ) m_AcceptMask[ ByteNumber ] |= Byte;
else m_AcceptMask[ ByteNumber ] &= ~Byte;
}
//==============================================================================
void fluid::BuildLowerMasks( void )
{
s32 X, Y;
// Initially, at all non-level-5 mask levels, we want to both accept and
// reject everything. Then, we'll go back and correct it all.
MEMSET( m_AcceptMask, 0xFF, 1+1+2+8+32 );
MEMSET( m_RejectMask, 0xFF, 1+1+2+8+32 );
// Now, for each entry in the level 5 mask, push its implications down
// through all the other levels.
for( Y = 0; Y < 32; Y++ )
for( X = 0; X < 32; X++ )
{
if( GetRejectBit( 5, X, Y ) )
{
// The block is set for reject.
// We cannot accept it on the lower levels.
SetAcceptBit( 4, X>>1, Y>>1, 0 );
SetAcceptBit( 3, X>>2, Y>>2, 0 );
SetAcceptBit( 2, X>>3, Y>>3, 0 );
SetAcceptBit( 1, X>>4, Y>>4, 0 );
SetAcceptBit( 0, X>>5, Y>>5, 0 );
}
else
{
// The block is set for accept.
// We cannot reject it on the lower levels.
SetRejectBit( 4, X>>1, Y>>1, 0 );
SetRejectBit( 3, X>>2, Y>>2, 0 );
SetRejectBit( 2, X>>3, Y>>3, 0 );
SetRejectBit( 1, X>>4, Y>>4, 0 );
SetRejectBit( 0, X>>5, Y>>5, 0 );
}
}
}
//==============================================================================
struct fill_segment
{
s32 Y;
s32 X0, X1;
s32 DY; // +1 or -1
};
#define STACK_SIZE 50
//------------------------------------------------------------------------------
#define PUSH(y,x0,x1,dy) \
{ \
if( ((y+(dy)) >= 0) && ((y+(dy)) < SizeY) ) \
{ \
if( Count < STACK_SIZE ) \
{ \
Stack[Count].Y = y; \
Stack[Count].X0 = x0; \
Stack[Count].X1 = x1; \
Stack[Count].DY = dy; \
Count++; \
} \
else \
{ \
FloodFill( pGrid, x0, y, SizeX, SizeY ); \
} \
} \
}
//------------------------------------------------------------------------------
#define POP(y,x0,x1,dy) \
{ \
Count--; \
Y = Stack[Count].Y + Stack[Count].DY; \
X0 = Stack[Count].X0; \
X1 = Stack[Count].X1; \
DY = Stack[Count].DY; \
}
//------------------------------------------------------------------------------
void fluid::FloodFill( u8* pGrid, s32 x, s32 y, s32 SizeX, s32 SizeY )
{
fill_segment Stack[ STACK_SIZE ];
s32 Count = 0;
s32 X, Y, X0, X1, DY, Left;
u8* p;
if( !pGrid[ (y*SizeX) + x ] )
return;
PUSH( y, x, x, 1 ); // Needed in a few cases.
PUSH( y+1, x, x, -1 ); // Primary seed point. Popped first.
while( Count > 0 )
{
POP( Y, X0, X1, DY );
// A span in y=(Y-DY) for X0<=x<=X1 was previously filled. Now consider
// adjacent entries in y=Y.
// Clear going towards decreasing X.
X = X0;
p = &pGrid[ (Y*SizeX) + X ];
while( (X >= 0) && *p )
{
*p = 0;
X--;
p--;
}
if( X >= X0 )
goto Skip;
Left = X + 1;
if( Left < X0 )
PUSH( Y, Left, X0-1, -DY )
X = X0 + 1;
do
{
// Clear going towards increasing X.
p = &pGrid[ (Y*SizeX) + X ];
while( (X < SizeX) && *p )
{
*p = 0;
X++;
p++;
}
PUSH( Y, Left, X-1, DY );
if( X > X1+1 )
PUSH( Y, X1+1, X-1, -DY );
Skip: X++;
p = &pGrid[ (Y*SizeX) + X ];
while( (X <= X1) && !(*p) )
{
X++;
p++;
}
Left = X;
}
while( X <= X1 );
}
}
//==============================================================================
void fluid::RebuildMasks( void )
{
u8* pGrid;
u8* pG; // Traveling grid pointer
s32 GridSize;
s32 X, Y;
s32 x, y;
s32 i; // Index
s32 SquaresPerBlock = m_HighResMode ? 4 : 8;
s32 ShiftPerBlock = m_HighResMode ? 2 : 3;
//
// We need a grid to classify all terrain data points which are within the
// fluid area. We will use this grid to reject underground blocks, reject
// "wet" edges if requested, and to dry fill where requested.
//
GridSize = (m_SquaresInX+1) * (m_SquaresInY+1);
pGrid = (u8*)MALLOC( GridSize );
// Default to allow all waterblocks in case we don't have a terrain object
dMemset(pGrid, 1, GridSize);
// Classify each point as above or below ground.
if( m_pTerrain )
{
u16 FluidLevel = (u16)((m_SurfaceZ + (m_WaveAmplitude/2.0f)) * 32.0f);
pG = pGrid;
for( Y = 0; Y < m_SquaresInY+1; Y++ )
for( X = 0; X < m_SquaresInX+1; X++ )
{
i = (((m_SquareY0+Y) & 255) << 8) + ((m_SquareX0+X) & 255);
*pG = (u8)(FluidLevel > m_pTerrain[i]);
pG++;
}
}
// If requested, "dry up" all edges which "protrude" into the air.
if( m_RemoveWetEdges && m_pTerrain )
{
for( X = 0; X < m_SquaresInX+1; X++ )
{
FloodFill( pGrid, X, 0 , m_SquaresInX+1, m_SquaresInY+1 );
FloodFill( pGrid, X, m_SquaresInY, m_SquaresInX+1, m_SquaresInY+1 );
}
for( Y = 0; Y < m_SquaresInY+1; Y++ )
{
FloodFill( pGrid, 0 , Y, m_SquaresInX+1, m_SquaresInY+1 );
FloodFill( pGrid, m_SquaresInX, Y, m_SquaresInX+1, m_SquaresInY+1 );
}
}
// Time to build the masks. First, reject everything! We will work on the
// level 5 reject mask. (Level 5 is the most detailed mask, and there is no
// accept mask at that level.)
MEMSET( m_RejectMask + m_MaskOffset[5], 0xFF, 128 );
// Any block which as useful points left in the grid is to be kept.
for( Y = 0; Y < m_BlocksInY; Y++ )
for( X = 0; X < m_BlocksInX; X++ )
{
s32 Accept = 0;
// If ANY point in the block is acceptable, then accept the whole block.
for( y = 0; y <= SquaresPerBlock; y++ )
for( x = 0; x <= SquaresPerBlock; x++ )
{
s32 GridX = (X << ShiftPerBlock) + x;
s32 GridY = (Y << ShiftPerBlock) + y;
i = (GridY * (m_SquaresInX+1)) + GridX;
if( pGrid[i] )
{
Accept = 1;
goto BailOut;
}
}
BailOut:
if( Accept )
SetRejectBit( 5, X, Y, 0 );
}
FREE( pGrid );
BuildLowerMasks();
}
//==============================================================================
S32 getPower(S32 x)
{
// Returns 2^n (the highest bit).
S32 i = 0;
if (x)
do
i++;
while (x >>= 1);
return i;
}
void fluid::SetInfo( f32& X0,
f32& Y0,
f32& SizeX,
f32& SizeY,
f32 SurfaceZ,
f32 WaveAmplitude,
f32& Opacity,
f32& EnvMapIntensity,
s32 RemoveWetEdges,
bool UseDepthMap,
f32 TessellationSurface,
f32 TessellationShore,
f32 SurfaceParallax,
f32 FlowAngle,
f32 FlowRate,
f32 mDistortGridScale,
f32 mDistortMagnitude,
f32 mDistortTime,
ColorF SpecColor,
F32 SpecPower,
bool tiling,
u32 terrainSize,
u32 terrainBlockSize) // MM: Added Various Parameters.
{
m_TerrainSize = terrainSize;
m_TerrainBlockSize = terrainBlockSize;
m_TerrainBlockShift = getPower(terrainBlockSize-1);
m_SpecColor = SpecColor;
m_SpecPower = SpecPower;
// MM: Calculate Depth-map Texel X/Y.
m_DepthTexelX = 1.0f / SizeX;
m_DepthTexelY = 1.0f / SizeY;
// MM: Added Depth-Map Toggle.
m_UseDepthMap = UseDepthMap;
// MM: Tessellations.
m_TessellationSurface = TessellationSurface;
m_TessellationShore = TessellationShore;
// MM: Surface Parallax.
m_SurfaceParallax = SurfaceParallax;
// MM: Flow Control.
m_FlowAngle = FlowAngle;
m_FlowRate = FlowRate;
m_FlowMagnitudeS =
m_FlowMagnitudeT = 0.0f;
// MM: Surface Disturbance. RemoveMe!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
m_DistortGridScale = mDistortGridScale;
m_DistortMagnitude = mDistortMagnitude;
m_DistortTime = mDistortTime;
// MM: Put in neater constraints.
m_EnvMapIntensity = mClampF(EnvMapIntensity, 0.0f, 1.0f);
// MM: Removed Section.
/*
// Constrain the range of parameters.
if( Opacity > 1.0f ) Opacity = 1.0f;
if( Opacity < 0.0f ) Opacity = 0.0f;
if( EnvMapIntensity > 1.0f ) EnvMapIntensity = 1.0f;
if( EnvMapIntensity < 0.0f ) EnvMapIntensity = 0.0f;
*/
// Get the easy stuff first.
m_SurfaceZ = SurfaceZ;
m_WaveAmplitude = WaveAmplitude;
m_RemoveWetEdges = RemoveWetEdges;
m_Opacity = mClampF(Opacity,0.0f,1.0f); // MM: Put in neater constraints.
m_EnvMapIntensity = EnvMapIntensity;
m_WaveFactor = m_WaveAmplitude * 0.25f;
// Place the "min" corner.
m_SquareX0 = (s32)((X0 / F32(m_TerrainBlockSize)) + 0.5f);
m_SquareY0 = (s32)((Y0 / F32(m_TerrainBlockSize)) + 0.5f);
// Constrain the range of values.
if( m_SquareX0 < 0.0f ) m_SquareX0 = 0;
if( m_SquareY0 < 0.0f ) m_SquareY0 = 0;
F32 max = terrainSize - terrainBlockSize;
if( m_SquareX0 > max ) m_SquareX0 = max;
if( m_SquareY0 > max ) m_SquareY0 = max;
// Decide on the size of the block.
m_SquaresInX = (s32)((SizeX / F32(m_TerrainBlockSize)) + 0.5f);
m_SquaresInY = (s32)((SizeY / F32(m_TerrainBlockSize)) + 0.5f);
//
// If the fluid is meant to cover less than 1/4 of a terrain rep, then we
// will enter "High Resolution Mode". The fluid will cover the same area
// as specified, but it will have twice the vertex resolution in each
// direction. So, on "small lakes", we get better memory utilization,
// better terrain fitting, and so on.
//
if( (m_SquaresInX <= 128) && (m_SquaresInY <= 128) )
{
// High Resolution Mode!
m_HighResMode = 1;
// A Block is now 4x4 terrain squares. And the number of squares in
// the fluid must be a multiple of 4 so we get whole blocks.
m_SquaresInX = (m_SquaresInX + 3) & ~0x03;
m_SquaresInY = (m_SquaresInY + 3) & ~0x03;
// Constrain the range of values.
if( m_SquaresInX <= 0 ) m_SquaresInX = 4;
if( m_SquaresInY <= 0 ) m_SquaresInY = 4;
m_BlocksInX = m_SquaresInX >> 2;
m_BlocksInY = m_SquaresInY >> 2;
}
else
{
// Normal resolution.
m_HighResMode = 0;
// A Block is now 8x8 terrain squares. And the number of squares in
// the fluid must be a multiple of 8 so we get whole blocks.
m_SquaresInX = (m_SquaresInX + 7) & ~0x07;
m_SquaresInY = (m_SquaresInY + 7) & ~0x07;
// Constrain the range of values.
if( m_SquaresInX > 256 ) m_SquaresInX = 256;
if( m_SquaresInY > 256 ) m_SquaresInY = 256;
if( m_SquaresInX <= 0 ) m_SquaresInX = 8;
if( m_SquaresInY <= 0 ) m_SquaresInY = 8;
m_BlocksInX = m_SquaresInX >> 3;
m_BlocksInY = m_SquaresInY >> 3;
}
// Set some internal values for later usage.
for(U32 i=0; i<5; i++)
{
if(m_HighResMode)
m_Step[i] = i * m_TerrainBlockSize;
else
m_Step[i] = i * m_TerrainBlockSize * 2;
}
// Set values back into parameters for caller.
X0 = m_SquareX0 * F32(m_TerrainBlockSize);
Y0 = m_SquareY0 * F32(m_TerrainBlockSize);
SizeX = m_SquaresInX * F32(m_TerrainBlockSize);
SizeY = m_SquaresInY * F32(m_TerrainBlockSize);
// Recompute our masks.
RebuildMasks();
}
//==============================================================================
void fluid::SetTerrainData( u16* pTerrainData )
{
m_pTerrain = pTerrainData;
RebuildMasks();
}
//==============================================================================
// Frustrum clip planes: 0=T 1=B 2=L 3=R 4=N 5=F
void fluid::SetFrustrumPlanes( f32* pFrustrumPlanes )
{
f32 BackOff = m_WaveAmplitude * 0.5f;
m_Plane[0].A = pFrustrumPlanes[ 0];
m_Plane[0].B = pFrustrumPlanes[ 1];
m_Plane[0].C = pFrustrumPlanes[ 2];
m_Plane[0].D = pFrustrumPlanes[ 3] + BackOff;
m_Plane[1].A = pFrustrumPlanes[ 4];
m_Plane[1].B = pFrustrumPlanes[ 5];
m_Plane[1].C = pFrustrumPlanes[ 6];
m_Plane[1].D = pFrustrumPlanes[ 7] + BackOff;
m_Plane[2].A = pFrustrumPlanes[ 8];
m_Plane[2].B = pFrustrumPlanes[ 9];
m_Plane[2].C = pFrustrumPlanes[10];
m_Plane[2].D = pFrustrumPlanes[11] + BackOff;
m_Plane[3].A = pFrustrumPlanes[12];
m_Plane[3].B = pFrustrumPlanes[13];
m_Plane[3].C = pFrustrumPlanes[14];
m_Plane[3].D = pFrustrumPlanes[15] + BackOff;
m_Plane[4].A = pFrustrumPlanes[16];
m_Plane[4].B = pFrustrumPlanes[17];
m_Plane[4].C = pFrustrumPlanes[18];
m_Plane[4].D = pFrustrumPlanes[19] + BackOff;
m_Plane[5].A = pFrustrumPlanes[20];
m_Plane[5].B = pFrustrumPlanes[21];
m_Plane[5].C = pFrustrumPlanes[22];
m_Plane[5].D = pFrustrumPlanes[23];
}
//==============================================================================
void fluid::SetTextures( TextureHandle Base,
TextureHandle EnvMapOverTexture,
TextureHandle EnvMapUnderTexture,
TextureHandle ShoreTexture,
TextureHandle DepthTexture,
TextureHandle ShoreDepthTexture,
TextureHandle SpecMaskTexture ) // MM: Added Various Textures.
{
m_BaseTexture = Base;
m_EnvMapOverTexture = EnvMapOverTexture; // MM: Added Over/Under Env Texture Support.
m_EnvMapUnderTexture = EnvMapUnderTexture; // MM: Added Over/Under Env Texture Support.
m_ShoreTexture = ShoreTexture; // MM: Added Shore Texture.
m_DepthTexture = DepthTexture; // MM: Added Depth-Map Texture.
m_ShoreDepthTexture = ShoreDepthTexture; // MM: Added Depth-Map Texture.
m_SpecMaskTex = SpecMaskTexture;
}
//==============================================================================
void fluid::SetLightMapTexture( TextureHandle LightMapTexture )
{
m_LightMapTexture = LightMapTexture;
}
//==============================================================================
void fluid::SetFogParameters( f32 R, f32 G, f32 B, f32 VisibleDistance )
{
m_FogColor.R = R;
m_FogColor.G = G;
m_FogColor.B = B;
m_FogColor.A = 1.0f;
m_VisibleDistance = VisibleDistance;
}
//==============================================================================
void fluid::SetFogFn( compute_fog_fn* pFogFn )
{
m_pFogFn = pFogFn;
}
//==============================================================================
s32 fluid::IsFluidAtXY( f32 X, f32 Y ) const
{
s32 x, y;
s32 ShiftPerBlock = m_HighResMode ? 5 : 6;
//
// Convert fluid space (X,Y) to block (x,y). Use the accept mask. Note
// that the masks are anchored at the min point rather than terrain (0,0).
//
// Convert to integer.
F32 scale = 8.0f / F32(m_TerrainBlockSize);
x = (s32)(X * scale);
y = (s32)(Y * scale);
// Compensate for min point offset.
x -= (m_SquareX0 * F32(m_TerrainBlockSize) * scale);
y -= (m_SquareY0 * F32(m_TerrainBlockSize) * scale);
// If we're outside the range and not tiling, ignore it.
if(!mTile)
{
if(x < 0 || x > 2047)
return false;
if(y < 0 || y > 2047)
return false;
}
// We only want points in the range [0,2048).
x &= 2047;
y &= 2047;
// Convert to block coordinate.
x >>= ShiftPerBlock;
y >>= ShiftPerBlock;
// When we are in high res mode, there are "virtually" 64 blocks per terrain
// along a particular axis. But only the first 32 of them are used.
if( x >= 32 ) return( 0 );
if( y >= 32 ) return( 0 );
// Consult mask.
return( GetAcceptBit( 5, x, y ) );
}
//==============================================================================

1871
engine/terrain/sky.cc Executable file

File diff suppressed because it is too large Load Diff

280
engine/terrain/sky.h Executable file
View File

@ -0,0 +1,280 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _SKY_H_
#define _SKY_H_
#ifndef _MMATH_H_
#include "math/mMath.h"
#endif
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _SCENEOBJECT_H_
#include "sim/sceneObject.h"
#endif
#ifndef _SCENESTATE_H_
#include "sceneGraph/sceneState.h"
#endif
#ifndef _SCENEGRAPH_H_
#include "sceneGraph/sceneGraph.h"
#endif
#ifndef _MPOINT_H_
#include "math/mPoint.h"
#endif
#ifndef _MATERIALLIST_H_
#include "dgl/materialList.h"
#endif
#ifndef _GAMEBASE_H_
#include "game/gameBase.h"
#endif
#define MAX_NUM_LAYERS 3
#define MAX_BAN_POINTS 20
class SceneGraph;
class SceneState;
class SceneRenderImage;
enum SkyState
{
isDone = 0,
comingIn = 1,
goingOut = 2
};
typedef struct
{
bool StormOn;
bool FadeIn;
bool FadeOut;
S32 currentCloud;
F32 stormSpeed;
F32 stormDir;
S32 numCloudLayers;
F32 fadeSpeed;
SkyState stormState;
}StormInfo;
typedef struct
{
SkyState state;
F32 speed;
F32 time;
F32 fadeSpeed;
}StormCloudData;
typedef struct
{
bool active;
SkyState state;
F32 speed;
F32 endPercentage;
F32 lastPercentage;
}StormFogVolume;
typedef struct
{
SkyState state;
U32 startTime;
F32 endPercentage;
F32 time;
S32 current;
U32 lastTime;
StormFogVolume volume[MaxFogVolumes];
}StormFogData;
//---------------------------------------------------------------------------
class Cloud
{
private:
Point3F mPoints[25];
Point2F mSpeed;
F32 mCenterHeight, mInnerHeight, mEdgeHeight;
F32 mAlpha[25];
S32 mDown, mOver;
static F32 mRadius;
F32 mLastTime, mOffset;
Point2F mBaseOffset, mTexCoords[25], mTextureScale;
TextureHandle mCloudHandle;
Point2F alphaCenter;
Point2F stormUpdate;
F32 stormAlpha[25];
F32 mAlphaSave[25];
static StormInfo mGStormData;
public:
Cloud();
~Cloud();
void setPoints();
void setHeights(F32 cHeight, F32 iHeight, F32 eHeight);
void setTexture(TextureHandle);
void setSpeed(Point2F);
void setTextPer(F32 cloudTextPer);
void updateCoord();
void calcAlpha();
void render(U32, U32, bool, S32, PlaneF*);
void updateStorm();
void calcStorm(F32 speed, F32 fadeSpeed);
void calcStormAlpha();
static void startStorm(SkyState);
static void setRadius(F32 rad) {mRadius = rad;}
void setRenderPoints(Point3F* renderPoints, Point2F* renderTexPoints, F32* renderAlpha, F32* renderSAlpha, S32 index);
void clipToPlane(Point3F* points, Point2F* texPoints, F32* alphaPoints, F32* sAlphaPoints, U32& rNumPoints, const PlaneF& rPlane);
};
//--------------------------------------------------------------------------
class Sky : public SceneObject
{
typedef SceneObject Parent;
private:
StormCloudData mStormCloudData;
StormFogData mStormFogData;
TextureHandle mSkyHandle[6];
StringTableEntry mCloudText[MAX_NUM_LAYERS];
F32 mCloudHeight[MAX_NUM_LAYERS];
F32 mCloudSpeed[MAX_NUM_LAYERS];
Cloud mCloudLayer[MAX_NUM_LAYERS];
F32 mRadius;
Point3F mPoints[10];
Point2F mTexCoord[4];
StringTableEntry mMaterialListName;
Point3F mSkyBoxPt;
Point3F mTopCenterPt;
Point3F mSpherePt;
ColorI mRealFogColor;
ColorI mRealSkyColor;
MaterialList mMaterialList;
ColorF mFogColor;
bool mSkyTexturesOn;
bool mRenderBoxBottom;
ColorF mSolidFillColor;
F32 mFogDistance;
F32 mVisibleDistance;
U32 mNumFogVolumes;
FogVolume mFogVolumes[MaxFogVolumes];
F32 mFogLine;
F32 mFogTime;
F32 mFogPercentage;
S32 mFogVolume;
S32 mRealFog;
F32 mRealFogMax;
F32 mRealFogMin;
F32 mRealFogSpeed;
bool mNoRenderBans;
bool mLastForce16Bit;
bool mLastForcePaletted;
SkyState mFogState;
S32 mNumCloudLayers;
Point3F mWindVelocity;
F32 mLastVisDisMod;
static bool smCloudsOn;
static bool smCloudOutlineOn;
static bool smSkyOn;
static S32 smNumCloudsOn;
bool mStormCloudsOn;
bool mStormFogOn;
bool mSetFog;
void calcPoints();
protected:
bool onAdd();
void onRemove();
bool prepRenderImage ( SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState=false);
void renderObject ( SceneState *state, SceneRenderImage *image);
void render(SceneState *state);
void calcAlphas_Heights(F32 zCamPos, F32 *banHeights, F32 *alphaBan, F32 DepthInFog);
void renderSkyBox(F32 lowerBanHeight, F32 alphaIn);
void calcBans(F32 *banHeights, Point3F banPoints[][MAX_BAN_POINTS], Point3F *cornerPoints);
void renderBans(F32 *alphaBan, F32 *banHeights, Point3F banPoints[][MAX_BAN_POINTS], Point3F *cornerPoints);
void inspectPostApply();
void startStorm();
void setVisibility();
void initSkyData();
bool loadDml();
void updateFog();
void updateRealFog();
void startStormFog();
void setRenderPoints(Point3F* renderPoints, S32 index);
void calcTexCoords(Point2F* texCoords, Point3F* renderPoints, S32 index);
public:
bool mEffectPrecip;
Point2F mWindDir;
enum NetMaskBits {
InitMask = BIT(0),
VisibilityMask = BIT(1),
StormCloudMask = BIT(2),
StormFogMask = BIT(3),
StormRealFogMask = BIT(4),
WindMask = BIT(5),
StormCloudsOnMask = BIT(6),
StormFogOnMask = BIT(7)
};
enum Constants {
EnvMapMaterialOffset = 6,
CloudMaterialOffset = 7
};
Sky();
~Sky();
F32 getVisibleDistance() const { return mVisibleDistance; }
/// @name Storm management.
/// @{
void stormCloudsShow(bool);
void stormFogShow(bool);
void stormCloudsOn(S32 state, F32 time);
void stormFogOn(F32 percentage, F32 time);
void stormRealFog(S32 value, F32 max, F32 min, F32 speed);
/// @}
/// @name Wind velocity
/// @{
void setWindVelocity(const Point3F &);
Point3F getWindVelocity();
/// @}
/// @name Environment mapping
/// @{
///
TextureHandle getEnvironmentMap() { return mMaterialList.getMaterial(EnvMapMaterialOffset); }
/// @}
/// Torque infrastructure
DECLARE_CONOBJECT(Sky);
static void initPersistFields();
static void consoleInit();
bool processArguments(S32 argc, const char **argv);
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
void updateVisibility();
void applySkyChanges()
{
inspectPostApply();
}
};
#endif

151
engine/terrain/sun.cc Executable file
View File

@ -0,0 +1,151 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "dgl/gBitmap.h"
#include "math/mathIO.h"
#include "core/bitStream.h"
#include "console/consoleTypes.h"
#include "sceneGraph/sceneGraph.h"
#include "terrain/terrData.h"
#include "math/mathUtils.h"
#include "terrain/sun.h"
IMPLEMENT_CO_NETOBJECT_V1(Sun);
//-----------------------------------------------------------------------------
Sun::Sun()
{
mNetFlags.set(Ghostable | ScopeAlways);
mTypeMask = EnvironmentObjectType;
mLight.mType = LightInfo::Vector;
mLight.mDirection.set(0.f, 0.707f, -0.707f);
mLight.mColor.set(0.7f, 0.7f, 0.7f);
mLight.mAmbient.set(0.3f, 0.3f, 0.3f);
mLight.sgCastsShadows = true;
mLight.sgDoubleSidedAmbient = true;
mLight.sgUseNormals = true;
mLight.sgZone[0] = 0;
mSunAzimuth = 0.0f;
mSunElevation = 35.0f;
}
//-----------------------------------------------------------------------------
void Sun::conformLight()
{
mLight.mDirection.normalize();
mLight.mColor.clamp();
mLight.mAmbient.clamp();
}
//-----------------------------------------------------------------------------
bool Sun::onAdd()
{
if(!Parent::onAdd())
return(false);
if(isClientObject())
Sim::getLightSet()->addObject(this);
else
conformLight();
return(true);
}
void Sun::registerLights(LightManager *lightManager, bool relight)
{
mRegisteredLight = mLight;
LightManager::sgGetFilteredLightColor(mRegisteredLight.mColor, mRegisteredLight.mAmbient, 0);
if(relight)
{
// static lighting not affected by this option when using the sun...
mRegisteredLight.sgCastsShadows = true;
lightManager->sgRegisterGlobalLight(&mRegisteredLight);
}
else
lightManager->sgSetSpecialLight(LightManager::sgSunLightType, &mRegisteredLight);
}
//-----------------------------------------------------------------------------
void Sun::inspectPostApply()
{
conformLight();
setMaskBits(UpdateMask);
}
void Sun::unpackUpdate(NetConnection *, BitStream * stream)
{
if(stream->readFlag())
{
// direction -> color -> ambient
mathRead(*stream, &mLight.mDirection);
stream->read(&mLight.mColor.red);
stream->read(&mLight.mColor.green);
stream->read(&mLight.mColor.blue);
stream->read(&mLight.mColor.alpha);
stream->read(&mLight.mAmbient.red);
stream->read(&mLight.mAmbient.green);
stream->read(&mLight.mAmbient.blue);
stream->read(&mLight.mAmbient.alpha);
mLight.sgCastsShadows = stream->readFlag();
}
}
U32 Sun::packUpdate(NetConnection *, U32 mask, BitStream * stream)
{
if(stream->writeFlag(mask & UpdateMask))
{
// Calculate Light Direction.
F32 Yaw = mDegToRad(mClampF(mSunAzimuth,0,359));
F32 Pitch = mDegToRad(mClampF(mSunElevation,-360,+360));
VectorF sunvec;
MathUtils::getVectorFromAngles(sunvec, Yaw, Pitch);
mLight.mDirection = -sunvec;
// direction -> color -> ambient
mathWrite(*stream, mLight.mDirection);
stream->write(mLight.mColor.red);
stream->write(mLight.mColor.green);
stream->write(mLight.mColor.blue);
stream->write(mLight.mColor.alpha);
stream->write(mLight.mAmbient.red);
stream->write(mLight.mAmbient.green);
stream->write(mLight.mAmbient.blue);
stream->write(mLight.mAmbient.alpha);
stream->writeFlag(mLight.sgCastsShadows);
}
return(0);
}
//-----------------------------------------------------------------------------
void Sun::initPersistFields()
{
Parent::initPersistFields();
addGroup("Misc");
addField("azimuth", TypeF32, Offset( mSunAzimuth, Sun));
addField("elevation", TypeF32, Offset( mSunElevation, Sun));
//addField("direction", TypePoint3F, Offset(mLight.mDirection, Sun));
addField("color", TypeColorF, Offset(mLight.mColor, Sun));
addField("ambient", TypeColorF, Offset(mLight.mAmbient, Sun));
addField( "castsShadows", TypeBool, Offset(mLight.sgCastsShadows,Sun));
endGroup("Misc");
}

56
engine/terrain/sun.h Executable file
View File

@ -0,0 +1,56 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _SUN_H_
#define _SUN_H_
#ifndef _NETOBJECT_H_
#include "sim/netObject.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#include "lightingSystem/sgLightManager.h"
class Sun : public NetObject
{
private:
typedef NetObject Parent;
LightInfo mLight;
LightInfo mRegisteredLight;
void conformLight();
public:
Sun();
// SimObject
bool onAdd();
void registerLights(LightManager *lm, bool lightingScene);
//
void inspectPostApply();
static void initPersistFields();
// NetObject
enum NetMaskBits {
UpdateMask = BIT(0)
};
U32 packUpdate (NetConnection *conn, U32 mask, BitStream * stream);
void unpackUpdate(NetConnection *conn, BitStream * stream);
F32 mSunAzimuth;
F32 mSunElevation;
DECLARE_CONOBJECT(Sun);
};
#endif

1161
engine/terrain/terrCollision.cc Executable file

File diff suppressed because it is too large Load Diff

1816
engine/terrain/terrData.cc Executable file

File diff suppressed because it is too large Load Diff

452
engine/terrain/terrData.h Executable file
View File

@ -0,0 +1,452 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _TERRDATA_H_
#define _TERRDATA_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _MPOINT_H_
#include "math/mPoint.h"
#endif
#ifndef _SCENEOBJECT_H_
#include "sim/sceneObject.h"
#endif
#ifndef _RESMANAGER_H_
#include "core/resManager.h"
#endif
#ifndef _MATERIALLIST_H_
#include "dgl/materialList.h"
#endif
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _CONVEX_H_
#include "collision/convex.h"
#endif
#include "dgl/gBitmap.h"
class GBitmap;
class TerrainFile;
class TerrainBlock;
class ColorF;
class Blender;
//--------------------------------------------------------------------------
class TerrainConvex: public Convex
{
friend class TerrainBlock;
TerrainConvex *square; ///< Alternate convex if square is concave
bool halfA; ///< Which half of square
bool split45; ///< Square split pattern
U32 squareId; ///< Used to match squares
U32 material;
Point3F point[4]; ///< 3-4 vertices
VectorF normal[2];
Box3F box; ///< Bounding box
public:
TerrainConvex() { mType = TerrainConvexType; }
TerrainConvex(const TerrainConvex& cv) {
mType = TerrainConvexType;
// Only a partial copy...
mObject = cv.mObject;
split45 = cv.split45;
squareId = cv.squareId;
material = cv.material;
point[0] = cv.point[0];
point[1] = cv.point[1];
point[2] = cv.point[2];
point[3] = cv.point[3];
normal[0] = cv.normal[0];
normal[1] = cv.normal[1];
box = cv.box;
}
Box3F getBoundingBox() const;
Box3F getBoundingBox(const MatrixF& mat, const Point3F& scale) const;
Point3F support(const VectorF& v) const;
void getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf);
void getPolyList(AbstractPolyList* list);
};
//--------------------------------------------------------------------------
struct GridSquare
{
U16 minHeight;
U16 maxHeight;
U16 heightDeviance;
U16 flags;
enum {
Split45 = 1,
Empty = 2,
HasEmpty = 4,
MaterialShift = 3,
MaterialStart = 8,
Material0 = 8,
Material1 = 16,
Material2 = 32,
Material3 = 64,
};
};
struct GridChunk
{
U16 heightDeviance[3]; // levels 0-1, 1-2, 2
U16 emptyFlags;
};
//--------------------------------------------------------------------------
class TerrainBlock : public SceneObject
{
typedef SceneObject Parent;
public:
struct Material {
enum Flags {
Plain = 0,
Rotate = 1,
FlipX = 2,
FlipXRotate = 3,
FlipY = 4,
FlipYRotate = 5,
FlipXY = 6,
FlipXYRotate = 7,
RotateMask = 7,
Empty = 8,
Modified = BIT(7),
// must not clobber TerrainFile::MATERIAL_GROUP_MASK bits!
PersistMask = BIT(7)
};
U8 flags;
U8 index;
};
enum {
BlockSize = 256,
BlockShift = 8,
LightmapSize = 512,
LightmapShift = 9,
ChunkSquareWidth = 64,
ChunkSize = 4,
ChunkDownShift = 2,
ChunkShift = BlockShift - ChunkDownShift,
BlockSquareWidth = 256,
SquareMaxPoints = 1024,
BlockMask = 255,
GridMapSize = 0x15555,
FlagMapWidth = 128, ///< Flags that map is for 2x2 squares.
FlagMapMask = 127,
MaxMipLevel = 6,
NumBaseTextures = 16,
MaterialGroups = 8,
MaxEmptyRunPairs = 100
};
enum UpdateMaskBits {
InitMask = 1,
VisibilityMask = 2,
EmptyMask = 4,
};
Blender* mBlender;
TextureHandle baseTextures[NumBaseTextures];
TextureHandle mBaseMaterials[MaterialGroups];
TextureHandle mAlphaMaterials[MaterialGroups];
GBitmap *lightMap;
GBitmap *whiteMap;
TextureHandle lightMapTexture;
void triggerLightmapReload()
{
if(whiteMap)
delete whiteMap;
whiteMap = NULL;
lightMapTexture = NULL;
}
StringTableEntry *mMaterialFileName; ///< Array from the file.
TextureHandle mDynLightTexture;
U8 *mBaseMaterialMap;
Material *materialMap;
// fixed point height values
U16 *heightMap;
U16 *flagMap;
StringTableEntry mDetailTextureName;
TextureHandle mDetailTextureHandle;
// Bumpmapping.
StringTableEntry mBumpTextureName;
TextureHandle mBumpTextureHandle;
TextureHandle mInvertedBumpTextureHandle;
F32 mBumpScale;
F32 mBumpOffset;
U32 mZeroBumpScale;
StringTableEntry mTerrFileName;
Vector<S32> mEmptySquareRuns;
U32 mTextureCallbackKey;
void processTextureEvent(const U32 eventCode);
S32 mMPMIndex[TerrainBlock::MaterialGroups];
S32 mVertexBuffer;
/// If true, we tile infinitely.
bool mTile;
private:
Resource<TerrainFile> mFile;
GridSquare *gridMap[BlockShift+1];
GridChunk *mChunkMap;
U32 mCRC;
public:
TerrainBlock();
~TerrainBlock();
void buildChunkDeviance(S32 x, S32 y);
void buildGridMap();
U32 getCRC() { return(mCRC); }
Resource<TerrainFile> getFile() { return mFile; };
bool onAdd();
void onRemove();
void refreshMaterialLists();
void onEditorEnable();
void onEditorDisable();
void rebuildEmptyFlags();
bool unpackEmptySquares();
void packEmptySquares();
TextureHandle getDetailTextureHandle();
TextureHandle getBumpTextureHandle();
TextureHandle getInvertedBumpTextureHandle();
Material *getMaterial(U32 x, U32 y);
GridSquare *findSquare(U32 level, Point2I pos);
GridSquare *findSquare(U32 level, S32 x, S32 y);
GridChunk *findChunk(Point2I pos);
void setHeight(const Point2I & pos, float height);
void updateGrid(Point2I min, Point2I max);
void updateGridMaterials(Point2I min, Point2I max);
U16 getHeight(U32 x, U32 y) { return heightMap[(x & BlockMask) + ((y & BlockMask) << BlockShift)]; }
U16 *getHeightAddress(U32 x, U32 y) { return &heightMap[(x & BlockMask) + ((y & BlockMask) << BlockShift)]; }
void setBaseMaterial(U32 x, U32 y, U8 matGroup);
S32 getTerrainMapIndex(Point3F& pt);
U8 *getMaterialAlphaMap(U32 matIndex);
U8* getBaseMaterialAddress(U32 x, U32 y);
U8 getBaseMaterial(U32 x, U32 y);
U16 *getFlagMapPtr(S32 x, S32 y);
void getMaterialAlpha(Point2I pos, U8 alphas[MaterialGroups]);
void setMaterialAlpha(Point2I pos, const U8 alphas[MaterialGroups]);
// a more useful getHeight for the public...
bool getHeight(const Point2F & pos, F32 * height);
bool getNormal(const Point2F & pos, Point3F * normal, bool normalize = true);
bool getNormalAndHeight(const Point2F & pos, Point3F * normal, F32 * height, bool normalize = true);
// only the editor currently uses this method - should always be using a ray to collide with
bool collideBox(const Point3F &start, const Point3F &end, RayInfo* info){return(castRay(start,end,info));}
S32 getMaterialAlphaIndex(const char *materialName);
private:
S32 squareSize;
public:
void setFile(Resource<TerrainFile> file);
bool save(const char* filename);
static void flushCache();
void relight(const ColorF &lightColor, const ColorF &ambient, const Point3F &lightDir);
S32 getSquareSize();
//--------------------------------------
// SceneGraph functions...
protected:
void setTransform (const MatrixF &mat);
bool prepRenderImage ( SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState=false);
void renderObject ( SceneState *state, SceneRenderImage *image);
//--------------------------------------
// collision info
private:
BSPTree *mTree;
S32 mHeightMin;
S32 mHeightMax;
public:
void buildConvex(const Box3F& box,Convex* convex);
bool buildPolyList(AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere);
BSPNode *buildCollisionBSP(BSPTree *tree, const Box3F &box, const SphereF &sphere);
bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
bool castRayI(const Point3F &start, const Point3F &end, RayInfo* info, bool emptyCollide);
bool castRayBlock(const Point3F &pStart, const Point3F &pEnd, const Point2I &blockPos, U32 level, F32 invDeltaX, F32 invDeltaY, F32 startT, F32 endT, RayInfo *info, bool);
private:
BSPNode *buildSquareTree(S32 y, S32 x);
BSPNode *buildXTree(S32 y, S32 xStart, S32 xEnd);
public:
bool buildMaterialMap();
void buildMipMap();
void setBaseMaterials(S32 argc, const char *argv[]);
bool initMMXBlender();
// private helper
private:
bool mCollideEmpty;
public:
DECLARE_CONOBJECT(TerrainBlock);
static void initPersistFields();
void inspectPostApply();
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
};
//--------------------------------------
class TerrainFile : public ResourceInstance
{
public:
enum Constants {
FILE_VERSION = 3,
MATERIAL_GROUP_MASK = 0x7
};
TerrainFile();
~TerrainFile();
U16 mHeightMap[TerrainBlock::BlockSize * TerrainBlock::BlockSize];
U8 mBaseMaterialMap[TerrainBlock::BlockSize * TerrainBlock::BlockSize];
GridSquare mGridMapBase[TerrainBlock::GridMapSize];
GridSquare *mGridMap[TerrainBlock::BlockShift+1];
GridChunk mChunkMap[TerrainBlock::ChunkSquareWidth * TerrainBlock::ChunkSquareWidth];
U16 mFlagMap[TerrainBlock::FlagMapWidth * TerrainBlock::FlagMapWidth];
char *mTextureScript;
char *mHeightfieldScript;
TerrainBlock::Material mMaterialMap[TerrainBlock::BlockSquareWidth * TerrainBlock::BlockSquareWidth];
// DMMNOTE: This loads all the alpha maps, whether or not they are used. Possible to
// restrict to only the used versions?
StringTableEntry mMaterialFileName[TerrainBlock::MaterialGroups];
U8* mMaterialAlphaMap[TerrainBlock::MaterialGroups];
bool save(const char *filename);
void buildChunkDeviance(S32 x, S32 y);
void buildGridMap();
void heightDevLine(U32 p1x, U32 p1y, U32 p2x, U32 p2y, U32 pmx, U32 pmy, U16 *devPtr);
inline GridSquare *findSquare(U32 level, Point2I pos)
{
return mGridMap[level] + (pos.x >> level) + ((pos.y>>level) << (TerrainBlock::BlockShift - level));
}
inline U16 getHeight(U32 x, U32 y)
{
return mHeightMap[(x & TerrainBlock::BlockMask) + ((y & TerrainBlock::BlockMask) << TerrainBlock::BlockShift)];
}
inline TerrainBlock::Material *getMaterial(U32 x, U32 y)
{
return &mMaterialMap[(x & TerrainBlock::BlockMask) + ((y & TerrainBlock::BlockMask) << TerrainBlock::BlockShift)];
}
void setTextureScript(const char *script);
void setHeightfieldScript(const char *script);
const char *getTextureScript();
const char *getHeightfieldScript();
};
//--------------------------------------------------------------------------
inline U16 *TerrainBlock::getFlagMapPtr(S32 x, S32 y)
{
return flagMap + ((x >> 1) & TerrainBlock::FlagMapMask) +
((y >> 1) & TerrainBlock::FlagMapMask) * TerrainBlock::FlagMapWidth;
}
inline GridSquare *TerrainBlock::findSquare(U32 level, S32 x, S32 y)
{
return gridMap[level] + ((x & TerrainBlock::BlockMask) >> level) + (((y & TerrainBlock::BlockMask) >> level) << (TerrainBlock::BlockShift - level));
}
inline GridSquare *TerrainBlock::findSquare(U32 level, Point2I pos)
{
return gridMap[level] + (pos.x >> level) + ((pos.y>>level) << (BlockShift - level));
}
inline GridChunk *TerrainBlock::findChunk(Point2I pos)
{
return mChunkMap + (pos.x >> ChunkDownShift) + ((pos.y>>ChunkDownShift) << ChunkShift);
}
inline TerrainBlock::Material *TerrainBlock::getMaterial(U32 x, U32 y)
{
return materialMap + x + (y << BlockShift);
}
inline TextureHandle TerrainBlock::getDetailTextureHandle()
{
return mDetailTextureHandle;
}
inline S32 TerrainBlock::getSquareSize()
{
return squareSize;
}
inline U8 TerrainBlock::getBaseMaterial(U32 x, U32 y)
{
return mBaseMaterialMap[(x & BlockMask) + ((y & BlockMask) << BlockShift)];
}
inline U8* TerrainBlock::getBaseMaterialAddress(U32 x, U32 y)
{
return &mBaseMaterialMap[(x & BlockMask) + ((y & BlockMask) << BlockShift)];
}
inline U8* TerrainBlock::getMaterialAlphaMap(U32 matIndex)
{
if (mFile->mMaterialAlphaMap[matIndex] == NULL) {
mFile->mMaterialAlphaMap[matIndex] = new U8[TerrainBlock::BlockSize * TerrainBlock::BlockSize];
dMemset(mFile->mMaterialAlphaMap[matIndex], 0, TerrainBlock::BlockSize * TerrainBlock::BlockSize);
}
return mFile->mMaterialAlphaMap[matIndex];
}
// 11.5 fixed point - gives us a height range from 0->2048 in 1/32 inc
inline F32 fixedToFloat(U16 val)
{
return F32(val) * 0.03125f;
}
inline U16 floatToFixed(F32 val)
{
return U16(val * 32.0);
}
extern ResourceInstance *constructTerrainFile(Stream &stream);
#endif

505
engine/terrain/terrLighting.cc Executable file
View File

@ -0,0 +1,505 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "terrain/terrData.h"
#include "math/mMath.h"
#include "dgl/dgl.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/gBitmap.h"
#include "dgl/gTexManager.h"
#include "terrain/terrRender.h"
#include "sceneGraph/sceneGraph.h"
U32 TerrainRender::TestSquareLights(GridSquare *sq, S32 level, Point2I pos, U32 lightMask)
{
U32 retMask = 0;
F32 blockX = pos.x * mSquareSize + mBlockPos.x;
F32 blockY = pos.y * mSquareSize + mBlockPos.y;
F32 blockZ = fixedToFloat(sq->minHeight);
F32 blockSize = mSquareSize * (1 << level);
F32 blockHeight = fixedToFloat(sq->maxHeight - sq->minHeight);
Point3F vec;
for(S32 i = 0; (lightMask >> i) != 0; i++)
{
if(lightMask & (1 << i))
{
Point3F *pos = &mTerrainLights[i].pos;
// test the visibility of this light to box
// find closest point on box to light and test
if(pos->z < blockZ)
vec.z = blockZ - pos->z;
else if(pos->z > blockZ + blockHeight)
vec.z = pos->z - (blockZ + blockHeight);
else
vec.z = 0;
if(pos->x < blockX)
vec.x = blockX - pos->x;
else if(pos->x > blockX + blockSize)
vec.x = pos->x - (blockX + blockSize);
else
vec.x = 0;
if(pos->y < blockY)
vec.y = blockY - pos->y;
else if(pos->y > blockY + blockSize)
vec.y = pos->y - (blockY + blockSize);
else
vec.y = 0;
F32 dist = vec.len();
if(dist < mTerrainLights[i].radius)
retMask |= (1 << i);
}
}
return retMask;
}
void TerrainRender::buildLightArray()
{
static LightInfoList lights;
lights.clear();
gClientSceneGraph->getLightManager()->sgGetBestLights(lights);
// create terrain lights from these...
U32 curIndex = 0;
for(U32 i = 0; i < lights.size(); i++)
{
if(lights[i]->mType != LightInfo::Point)
continue;
if(!lights[i]->sgAllowDiffuseZoneLighting(0))
continue;
// set the 'fo
TerrLightInfo & info = mTerrainLights[curIndex++];
mCurrentBlock->getWorldTransform().mulP(lights[i]->mPos, &info.pos);
info.radius = lights[i]->mRadius; //jff
info.radiusSquared = info.radius * info.radius;
//
info.r = lights[i]->mColor.red;
info.g = lights[i]->mColor.green;
info.b = lights[i]->mColor.blue;
Point3F dVec = mCamPos - lights[i]->mPos;
info.distSquared = mDot(dVec, dVec);
}
mDynamicLightCount = curIndex;
}
static U16 convertColor(ColorF color)
{
if(color.red > 1)
color.red = 1;
if(color.green > 1)
color.green = 1;
if(color.blue > 1)
color.blue = 1;
return (U32(color.blue * 31) << 11) |
(U32(color.green * 31) << 6) |
(U32(color.red * 31) << 1) | 1;
}
void TerrainBlock::relight(const ColorF &lightColor, const ColorF &ambient, const Point3F &lightDir)
{
if(lightDir.x == 0 && lightDir.y == 0)
return;
if(!lightMap)
return;
S32 generateLevel = Con::getIntVariable("$pref::sceneLighting::terrainGenerateLevel", 0);
generateLevel = mClamp(generateLevel, 0, 4);
U32 generateDim = TerrainBlock::LightmapSize << generateLevel;
U32 generateShift = TerrainBlock::LightmapShift + generateLevel;
U32 generateMask = generateDim - 1;
F32 zStep;
F32 frac;
Point2I blockColStep;
Point2I blockRowStep;
Point2I blockFirstPos;
Point2I lmapFirstPos;
F32 terrainDim = F32(getSquareSize()) * F32(TerrainBlock::BlockSize);
F32 stepSize = F32(getSquareSize()) / F32(generateDim / TerrainBlock::BlockSize);
if(mFabs(lightDir.x) >= mFabs(lightDir.y))
{
if(lightDir.x > 0)
{
zStep = lightDir.z / lightDir.x;
frac = lightDir.y / lightDir.x;
blockColStep.set(1, 0);
blockRowStep.set(0, 1);
blockFirstPos.set(0, 0);
lmapFirstPos.set(0, 0);
}
else
{
zStep = -lightDir.z / lightDir.x;
frac = -lightDir.y / lightDir.x;
blockColStep.set(-1, 0);
blockRowStep.set(0, 1);
blockFirstPos.set(255, 0);
lmapFirstPos.set(TerrainBlock::LightmapSize-1, 0);
}
}
else
{
if(lightDir.y > 0)
{
zStep = lightDir.z / lightDir.y;
frac = lightDir.x / lightDir.y;
blockColStep.set(0, 1);
blockRowStep.set(1, 0);
blockFirstPos.set(0, 0);
lmapFirstPos.set(0, 0);
}
else
{
zStep = -lightDir.z / lightDir.y;
frac = -lightDir.x / lightDir.y;
blockColStep.set(0, -1);
blockRowStep.set(1, 0);
blockFirstPos.set(0, 255);
lmapFirstPos.set(0, TerrainBlock::LightmapSize-1);
}
}
zStep *= stepSize;
F32 * heightArray = new F32[generateDim];
S32 fracStep = -1;
if(frac < 0)
{
fracStep = 1;
frac = -frac;
}
F32 * nextHeightArray = new F32[generateDim];
F32 oneMinusFrac = 1 - frac;
U32 blockShift = generateShift - TerrainBlock::BlockShift;
U32 lightmapShift = generateShift - TerrainBlock::LightmapShift;
U32 blockStep = 1 << blockShift;
U32 blockMask = (1 << blockShift) - 1;
U32 lightmapMask = (1 << lightmapShift) - 1;
Point2I bp = blockFirstPos;
F32 terrainHeights[2][TerrainBlock::BlockSize];
U32 i;
// get first set of heights
for(i = 0; i < TerrainBlock::BlockSize; i++, bp += blockRowStep)
terrainHeights[0][i] = fixedToFloat(getHeight(bp.x, bp.y));
// get second set of heights
bp = blockFirstPos + blockColStep;
for(i = 0; i < TerrainBlock::BlockSize; i++, bp += blockRowStep)
terrainHeights[1][i] = fixedToFloat(getHeight(bp.x, bp.y));
F32 * pTerrainHeights[2];
pTerrainHeights[0] = static_cast<F32*>(terrainHeights[0]);
pTerrainHeights[1] = static_cast<F32*>(terrainHeights[1]);
F32 heightStep = 1.f / blockStep;
F32 terrainZRowStep[2][TerrainBlock::BlockSize];
F32 terrainZColStep[TerrainBlock::BlockSize];
// fill in the row steps
for(i = 0; i < TerrainBlock::BlockSize; i++)
{
terrainZRowStep[0][i] = (terrainHeights[0][(i+1) & TerrainBlock::BlockMask] - terrainHeights[0][i]) * heightStep;
terrainZRowStep[1][i] = (terrainHeights[1][(i+1) & TerrainBlock::BlockMask] - terrainHeights[1][i]) * heightStep;
terrainZColStep[i] = (terrainHeights[1][i] - terrainHeights[0][i]) * heightStep;
}
// get first row of process heights
for(i = 0; i < generateDim; i++)
{
U32 bi = i >> blockShift;
heightArray[i] = terrainHeights[0][bi] + (i & blockMask) * terrainZRowStep[0][bi];
}
bp = blockFirstPos;
if(generateDim == TerrainBlock::BlockSize)
bp += blockColStep;
// generate the initial run
U32 x, y;
for(x = 1; x < generateDim; x++)
{
U32 xmask = x & blockMask;
// generate new height step rows?
if(!xmask)
{
F32 * tmp = pTerrainHeights[0];
pTerrainHeights[0] = pTerrainHeights[1];
pTerrainHeights[1] = tmp;
bp += blockColStep;
Point2I bwalk = bp;
for(i = 0; i < TerrainBlock::BlockSize; i++, bwalk += blockRowStep)
pTerrainHeights[1][i] = fixedToFloat(getHeight(bwalk.x, bwalk.y));
// fill in the row steps
for(i = 0; i < TerrainBlock::BlockSize; i++)
{
terrainZRowStep[0][i] = (pTerrainHeights[0][(i+1) & TerrainBlock::BlockMask] - pTerrainHeights[0][i]) * heightStep;
terrainZRowStep[1][i] = (pTerrainHeights[1][(i+1) & TerrainBlock::BlockMask] - pTerrainHeights[1][i]) * heightStep;
terrainZColStep[i] = (pTerrainHeights[1][i] - pTerrainHeights[0][i]) * heightStep;
}
}
Point2I bwalk = bp - blockRowStep;
for(y = 0; y < generateDim; y++)
{
U32 ymask = y & blockMask;
if(!ymask)
bwalk += blockRowStep;
U32 bi = y >> blockShift;
U32 binext = (bi + 1) & TerrainBlock::BlockMask;
F32 height;
// 135?
if((bwalk.x ^ bwalk.y) & 1)
{
U32 xsub = blockStep - xmask;
if(xsub > ymask) // bottom
height = pTerrainHeights[0][bi] + xmask * terrainZColStep[bi] +
ymask * terrainZRowStep[0][bi];
else // top
height = pTerrainHeights[1][bi] - xsub * terrainZColStep[binext] +
ymask * terrainZRowStep[1][bi];
}
else
{
if(xmask > ymask) // bottom
height = pTerrainHeights[0][bi] + xmask * terrainZColStep[bi] +
ymask * terrainZRowStep[1][bi];
else // top
height = pTerrainHeights[0][bi] + xmask * terrainZColStep[binext] +
ymask * terrainZRowStep[0][bi];
}
F32 intHeight = heightArray[y] * oneMinusFrac + heightArray[(y + fracStep) & generateMask] * frac + zStep;
nextHeightArray[y] = getMax(height, intHeight);
}
// swap the height rows
for(y = 0; y < generateDim; y++)
heightArray[y] = nextHeightArray[y];
}
F32 squareSize = getSquareSize();
F32 squaredSquareSize = squareSize * squareSize;
F32 lexelDim = squareSize * F32(TerrainBlock::BlockSize) / F32(TerrainBlock::LightmapSize);
// calculate normal runs
Point3F normals[2][TerrainBlock::BlockSize];
Point3F * pNormals[2];
pNormals[0] = static_cast<Point3F*>(normals[0]);
pNormals[1] = static_cast<Point3F*>(normals[1]);
// calculate the normal lookup table
F32 * normTable = new F32 [blockStep * blockStep * 4];
Point2F corners[4] = {
Point2F(0.f, 0.f),
Point2F(1.f, 0.f),
Point2F(1.f, 1.f),
Point2F(0.f, 1.f)
};
U32 idx = 0;
F32 step = 1.f / blockStep;
F32 halfStep = step / 2.f;
Point2F pos(halfStep, halfStep);
// fill it
for(x = 0; x < blockStep; x++, pos.x += step, pos.y = halfStep)
for(y = 0; y < blockStep; y++, pos.y += step)
for(i = 0; i < 4; i++, idx++)
normTable[idx] = 1.f - getMin(Point2F(pos - corners[i]).len(), 1.f);
// fill first column
bp = blockFirstPos;
for(x = 0; x < TerrainBlock::BlockSize; x++)
{
terrainHeights[0][x] = fixedToFloat(getHeight(bp.x, bp.y));
Point2F pos(bp.x * squareSize, bp.y * squareSize);
getNormal(pos, &pNormals[1][x]);
bp += blockRowStep;
}
// get swapped on first pass
pTerrainHeights[0] = static_cast<F32*>(terrainHeights[1]);
pTerrainHeights[1] = static_cast<F32*>(terrainHeights[0]);
ColorF colors[TerrainBlock::LightmapSize];
F32 ratio = F32(1 << lightmapShift);
F32 inverseRatioSquared = 1.f / (ratio * ratio);
// walk it...
bp = blockFirstPos - blockColStep;
Point2I lp = lmapFirstPos - blockColStep;
for(x = 0; x < generateDim; x++)
{
U32 xmask = x & blockMask;
// process lightmap?
if(!(x & lightmapMask))
{
dMemset(colors, 0, sizeof(ColorF) * TerrainBlock::LightmapSize);
lp += blockColStep;
}
// generate new runs?
if(!xmask)
{
bp += blockColStep;
// do the normals
Point3F * temp = pNormals[0];
pNormals[0] = pNormals[1];
pNormals[1] = temp;
// fill the row
Point2I bwalk = bp + blockColStep;
for(i = 0; i < TerrainBlock::BlockSize; i++)
{
Point2F pos(bwalk.x * squareSize, bwalk.y * squareSize);
getNormal(pos, &pNormals[1][i]);
bwalk += blockRowStep;
}
// do the heights
F32 * tmp = pTerrainHeights[0];
pTerrainHeights[0] = pTerrainHeights[1];
pTerrainHeights[1] = tmp;
bwalk = bp + blockColStep;
for(i = 0; i < TerrainBlock::BlockSize; i++, bwalk += blockRowStep)
pTerrainHeights[1][i] = fixedToFloat(getHeight(bwalk.x, bwalk.y));
// fill in the row steps
for(i = 0; i < TerrainBlock::BlockSize; i++)
{
terrainZRowStep[0][i] = (pTerrainHeights[0][(i+1) & TerrainBlock::BlockMask] - pTerrainHeights[0][i]) * heightStep;
terrainZRowStep[1][i] = (pTerrainHeights[1][(i+1) & TerrainBlock::BlockMask] - pTerrainHeights[1][i]) * heightStep;
terrainZColStep[i] = (pTerrainHeights[1][i] - pTerrainHeights[0][i]) * heightStep;
}
}
Point2I bwalk = bp - blockRowStep;
for(y = 0; y < generateDim; y++)
{
U32 ymask = y & blockMask;
if(!ymask)
bwalk += blockRowStep;
U32 bi = y >> blockShift;
U32 binext = (bi + 1) & TerrainBlock::BlockMask;
F32 height;
// 135?
if((bwalk.x ^ bwalk.y) & 1)
{
U32 xsub = blockStep - xmask;
if(xsub > ymask) // bottom
height = pTerrainHeights[0][bi] + xmask * terrainZColStep[bi] +
ymask * terrainZRowStep[0][bi];
else // top
height = pTerrainHeights[1][bi] - xsub * terrainZColStep[binext] +
ymask * terrainZRowStep[1][bi];
}
else
{
if(xmask > ymask) // bottom
height = pTerrainHeights[0][bi] + xmask * terrainZColStep[bi] +
ymask * terrainZRowStep[1][bi];
else // top
height = pTerrainHeights[0][bi] + xmask * terrainZColStep[binext] +
ymask * terrainZRowStep[0][bi];
}
F32 intHeight = heightArray[y] * oneMinusFrac + heightArray[(y + fracStep) & generateMask] * frac + zStep;
ColorF & col = colors[y >> lightmapShift];
// non shadowed?
if(height >= intHeight)
{
U32 idx = (xmask + (ymask << blockShift)) << 2;
Point3F normal;
normal = pNormals[0][bi] * normTable[idx++];
normal += pNormals[0][binext] * normTable[idx++];
normal += pNormals[1][binext] * normTable[idx++];
normal += pNormals[1][bi] * normTable[idx];
normal.normalize();
nextHeightArray[y] = height;
F32 colorScale = mDot(normal, lightDir);
if(colorScale >= 0)
col += ambient;
else
col += (ambient + lightColor * -colorScale);
}
else
{
nextHeightArray[y] = intHeight;
col += ambient;
}
}
for(y = 0; y < generateDim; y++)
heightArray[y] = nextHeightArray[y];
// do some lighting stuff?
if(!((x+1) & lightmapMask))
{
Point2I lwalk = lp;
U32 mask = TerrainBlock::LightmapSize - 1;
for(i = 0; i < TerrainBlock::LightmapSize; i++)
{
U16 * ptr = (U16*)lightMap->getAddress(lp.x & mask, lp.y & mask);
*ptr = convertColor(colors[i]);
lp += blockRowStep;
}
}
}
delete [] normTable;
delete [] heightArray;
delete [] nextHeightArray;
}

2618
engine/terrain/terrRender.cc Executable file

File diff suppressed because it is too large Load Diff

313
engine/terrain/terrRender.h Executable file
View File

@ -0,0 +1,313 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _TERRRENDER_H_
#define _TERRRENDER_H_
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _WATERBLOCK_H_
#include "terrain/waterBlock.h"
#endif
struct EmitChunk;
struct AllocatedTexture {
U32 level;
S32 x, y;
F32 distance;
EmitChunk *list;
TextureHandle handle;
AllocatedTexture *next;
AllocatedTexture *previous;
AllocatedTexture *nextLink;
U32 mipLevel;
AllocatedTexture()
{
next = previous = NULL;
}
inline void unlink()
{
AssertFatal(next && previous, "Invalid unlink.");
next->previous = previous;
previous->next = next;
next = previous = NULL;
}
inline void linkAfter(AllocatedTexture *t)
{
AssertFatal(next == NULL && previous == NULL, "Cannot link a non-null next & prev");
next = t->next;
previous = t;
t->next->previous = this;
t->next = this;
}
};
struct Render2Point : public Point3F
{
F32 d;
};
struct EdgePoint : public Point3F
{
ColorI detailColor;
F32 haze;
F32 distance;
F32 fogRed;
F32 fogGreen;
#if TERRAIN_STORE_NORMALS
Point3F vn;
#endif
};
struct ChunkCornerPoint : public EdgePoint
{
U32 pointIndex;
U32 xfIndex;
};
struct EdgeParent
{
ChunkCornerPoint *p1, *p2;
};
struct ChunkScanEdge : public EdgeParent
{
ChunkCornerPoint *mp;
EdgeParent *e1, *e2;
};
struct ChunkEdge : public EdgeParent
{
U32 xfIndex;
U32 pointIndex;
U32 pointCount;
EdgePoint pt[3];
EmitChunk *c1, *c2;
};
struct EmitChunk
{
ChunkEdge *edge[4];
S32 subDivLevel;
F32 growFactor;
S32 x, y;
S32 gridX, gridY;
U32 emptyFlags;
bool clip;
U32 lightMask;
EmitChunk *next;
bool renderDetails;
//CW - bump mapping stuff
bool renderBumps;
//CW - end bump mapping stuff
AllocatedTexture *chunkTexture;
};
struct SquareStackNode2
{
U32 clipFlags;
U32 lightMask;
Point2I pos;
U32 level;
bool texAllocated;
};
struct SquareStackNode
{
U32 clipFlags;
U32 lightMask;
Point2I pos;
U32 level;
bool texAllocated;
EdgeParent *top, *right, *bottom, *left;
};
struct TerrLightInfo
{
Point3F pos; ///< world position
F32 radius; ///< radius of the light
F32 radiusSquared; ///< radius^2
F32 r, g, b;
F32 distSquared; // distance to camera
};
enum EmptyFlags {
SquareEmpty_0_0 = BIT(0),
SquareEmpty_1_0 = BIT(1),
SquareEmpty_2_0 = BIT(2),
SquareEmpty_3_0 = BIT(3),
SquareEmpty_0_1 = BIT(4),
SquareEmpty_1_1 = BIT(5),
SquareEmpty_2_1 = BIT(6),
SquareEmpty_3_1 = BIT(7),
SquareEmpty_0_2 = BIT(8),
SquareEmpty_1_2 = BIT(9),
SquareEmpty_2_2 = BIT(10),
SquareEmpty_3_2 = BIT(11),
SquareEmpty_0_3 = BIT(12),
SquareEmpty_1_3 = BIT(13),
SquareEmpty_2_3 = BIT(14),
SquareEmpty_3_3 = BIT(15),
CornerEmpty_0_0 = SquareEmpty_0_0 | SquareEmpty_1_0 | SquareEmpty_0_1 | SquareEmpty_1_1,
CornerEmpty_1_0 = SquareEmpty_2_0 | SquareEmpty_3_0 | SquareEmpty_2_1 | SquareEmpty_3_1,
CornerEmpty_0_1 = SquareEmpty_0_2 | SquareEmpty_1_2 | SquareEmpty_0_3 | SquareEmpty_1_3,
CornerEmpty_1_1 = SquareEmpty_2_2 | SquareEmpty_3_2 | SquareEmpty_2_3 | SquareEmpty_3_3,
};
struct RenderPoint : public Point3F
{
F32 dist;
F32 haze; ///< also used as grow factor
};
enum TerrConstants {
MaxClipPlanes = 8, ///< left, right, top, bottom - don't need far tho...
MaxTerrainMaterials = 256,
EdgeStackSize = 1024, ///< value for water/terrain edge stack size.
MaxWaves = 8,
MaxDetailLevel = 9,
MaxMipLevel = 8,
MaxTerrainLights = 64,
MaxVisibleLights = 31,
ClipPlaneMask = (1 << MaxClipPlanes) - 1,
FarSphereMask = 0x80000000,
FogPlaneBoxMask = 0x40000000,
VertexBufferSize = 65 * 65 + 1000,
AllocatedTextureCount = 16 + 64 + 256 + 1024 + 4096,
TerrainTextureMipLevel = 7, ///< mip level of generated textures
TerrainTextureSize = 1 << TerrainTextureMipLevel, ///< size of generated textures
SmallMipLevel = 6
};
struct Color
{
S32 r, g, b;
F32 z;
};
class SceneState;
struct TerrainRender
{
static MatrixF mCameraToObject;
static AllocatedTexture mTextureFrameListHead;
static AllocatedTexture mTextureFrameListTail;
static AllocatedTexture mTextureFreeListHead;
static AllocatedTexture mTextureFreeListTail;
static AllocatedTexture mTextureFreeBigListHead;
static AllocatedTexture mTextureFreeBigListTail;
static U32 mTextureSlopSize;
static Vector<TextureHandle> mTextureFreeList;
static S32 mTextureMinSquareSize;
static SceneState *mSceneState;
static AllocatedTexture *mCurrentTexture;
static TerrainBlock *mCurrentBlock;
static S32 mSquareSize;
static F32 mScreenSize;
static U32 mFrameIndex;
static U32 mNumClipPlanes;
static AllocatedTexture *mTextureGrid[AllocatedTextureCount];
static AllocatedTexture **mTextureGridPtr[5];
static Point2F mBlockPos;
static Point2I mBlockOffset;
static Point2I mTerrainOffset;
static PlaneF mClipPlane[MaxClipPlanes];
static Point3F mCamPos;
static TextureHandle* mGrainyTexture;
static U32 mDynamicLightCount;
static bool mEnableTerrainDetails;
static bool mEnableTerrainEmbossBumps;
static bool mEnableTerrainDynLights;
static F32 mPixelError;
#ifdef TORQUE_OS_WIN32
//only need this in win32
static bool mRenderGL;
#endif
static TerrLightInfo mTerrainLights[MaxTerrainLights];
static F32 mScreenError;
static F32 mMinSquareSize;
static F32 mFarDistance;
static S32 mDynamicTextureCount;
static S32 mStaticTextureCount;
static bool mRenderingCommander;
static ColorF mFogColor;
static bool mRenderOutline;
static U32 mMaterialCount;
static GBitmap* mBlendBitmap;
static void init();
static void shutdown();
static void allocRenderEdges(U32 edgeCount, EdgeParent **dest, bool renderEdge);
static void subdivideChunkEdge(ChunkScanEdge *e, Point2I pos, bool chunkEdge);
static void processCurrentBlock(SceneState* state, EdgeParent *topEdge, EdgeParent *rightEdge, EdgeParent *bottomEdge, EdgeParent *leftEdge);
static ChunkCornerPoint *allocInitialPoint(Point3F pos);
static ChunkCornerPoint *allocPoint(Point2I pos);
static void emitTerrChunk(SquareStackNode *n, F32 squareDistance, U32 lightMask, bool farClip, bool useDetails, bool useBumps);
static void renderChunkOutline(EmitChunk *chunk);
static void renderChunkCommander(EmitChunk *chunk);
static void fixEdge(ChunkEdge *edge, S32 x, S32 y, S32 dx, S32 dy);
static U32 constructPoint(S32 x, S32 y);
static U32 interpPoint(U32 p1, U32 p2, S32 x, S32 y, F32 growFactor);
static void addEdge(ChunkEdge *edge);
static void clip(U32 triFanStart);
static F32 getScreenError() { return(mScreenError); }
static void setScreenError(F32 error) { mScreenError = error; }
static void flushCache();
static void flushCacheRect(RectI rect);
static void allocTerrTexture(Point2I pos, U32 level, U32 mipLevel, bool vis, F32 distance);
static void freeTerrTexture(AllocatedTexture *texture);
static void buildBlendMap(AllocatedTexture *texture);
static U32 TestSquareLights(GridSquare *sq, S32 level, Point2I pos, U32 lightMask);
static S32 TestSquareVisibility(Point3F &min, Point3F &max, S32 clipMask, F32 expand);
static void subdivideEdge(S32 edge, Point2I pos);
static F32 getSquareDistance(const Point3F& minPoint, const Point3F& maxPoint,
F32* zDiff);
//GL bumps is faster - uses multitexturing and adds 1 small pass
static void renderGLBumps(Point2F bumpTextureOffset, U32 hazeName);
#ifdef TORQUE_OS_WIN32
//D3D bumps is slower - adds 2 small passes
//no need for a D3D render function when not on windows
static void renderD3DBumps(Point2F bumpTextureOffset);
#endif
static void buildLightArray();
static void buildClippingPlanes(bool flipClipPlanes);
static void buildDetailTable();
static void renderXFCache();
static void renderBlock(TerrainBlock *, SceneState *state);
};
#endif

1066
engine/terrain/waterBlock.cc Executable file

File diff suppressed because it is too large Load Diff

173
engine/terrain/waterBlock.h Executable file
View File

@ -0,0 +1,173 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _WATERBLOCK_H_
#define _WATERBLOCK_H_
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _MPOINT_H_
#include "math/mPoint.h"
#endif
#ifndef _SCENEOBJECT_H_
#include "sim/sceneObject.h"
#endif
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _TERRDATA_H_
#include "terrain/terrData.h"
#endif
#ifndef _FLUID_H_
#include "terrain/fluid.h"
#endif
//==============================================================================
class AudioEnvironment;
class WaterBlock : public SceneObject
{
typedef SceneObject Parent;
public:
enum EWaterType
{
eWater = 0,
eOceanWater = 1,
eRiverWater = 2,
eStagnantWater = 3,
eLava = 4,
eHotLava = 5,
eCrustyLava = 6,
eQuicksand = 7,
};
enum WaterConst
{
WC_NUM_SUBMERGE_TEX = 2,
};
// MM: Depth-map Resolution.
enum WaterAttributes
{
eDepthMapResolution = 512,
};
private:
fluid mFluid;
bool mTile;
TextureHandle mSurfaceTexture;
TextureHandle mSpecMaskTex; ///< Specular mask texture.
TextureHandle mEnvMapOverTexture; ///< Overhead environment map texture handle.
TextureHandle mEnvMapUnderTexture; ///< Undersea environment map texture handle.
TextureHandle mShoreTexture; ///< Shore texture handle.
PlaneF mClipPlane[6]; ///< Frustrum clip planes: 0=T 1=B 2=L 3=R 4=N 5=F
TerrainBlock* mpTerrain; ///< Terrain block.
F32 mSurfaceZ; ///< Height of surface (approx.)
// Fields exposed to the editor.
EWaterType mLiquidType; ///< Type of liquid: Water? Lava? What?
F32 mDensity; ///< Density of liquid.
F32 mViscosity; ///< Viscosity of liquid.
F32 mWaveMagnitude; ///< Size of waves.
StringTableEntry mSurfaceName; ///< Surface texture.
StringTableEntry mSpecMaskName; ///< Specular mask texture.
F32 mSurfaceOpacity; ///< Opacity of surface texture.
StringTableEntry mEnvMapOverName; ///< Overhead environment map texture name.
StringTableEntry mEnvMapUnderName; ///< Undersea environment maptexture name
F32 mEnvMapIntensity; ///< Intensity of environment maps.
StringTableEntry mShoreName; ///< Shore texture name.
StringTableEntry mSubmergeName[WC_NUM_SUBMERGE_TEX]; ///< Name of submerge texture.
bool mRemoveWetEdges; ///< Remove wet edges?
AudioEnvironment * mAudioEnvironment; ///< Audio environment handle.
bool mEditorApplied; ///< Editor Applied Flag.
GBitmap* mDepthBitmap; ///< Depth Bitmap.
TextureHandle mDepthTexture; ///< Depth Texture.
GBitmap* mShoreDepthBitmap; ///< Shore Bitmap.
TextureHandle mShoreDepthTexture; ///< Shore Texture.
bool mUseDepthMap; ///< Use Depth-Map Flag.
F32 mShoreDepth; ///< Shore Depth.
F32 mMinAlpha; ///< Minimum Alpha.
F32 mMaxAlpha; ///< Maximum Alpha.
F32 mDepthGradient; ///< Depth Gradient.
F32 mTessellationSurface; ///< Tessellation Surface.
F32 mTessellationShore; ///< Tessellation Shore.
F32 mSurfaceParallax; ///< Surface Parallax.
F32 mFlowAngle; ///< Flow Angle.
F32 mFlowRate; ///< Flow Rate.
F32 mDistortGridScale; ///< Distort Grid Scale.
F32 mDistortMagnitude; ///< Distort Magnitude.
F32 mDistortTime; ///< Distortion Time.
ColorF mSpecColor;
F32 mSpecPower;
U32 mTerrainHalfSize;
U32 mTerrainSquareSize;
TextureHandle mLocalSubmergeTexture[WC_NUM_SUBMERGE_TEX];
static TextureHandle mSubmergeTexture[WC_NUM_SUBMERGE_TEX];
public:
WaterBlock();
~WaterBlock();
bool onAdd ( void );
void onRemove ( void );
bool onSceneAdd ( SceneGraph* graph );
void setTransform ( const MatrixF& mat );
void setScale ( const VectorF& scale );
bool prepRenderImage ( SceneState *state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState=false);
void renderObject ( SceneState *state, SceneRenderImage *image);
void inspectPostApply ( void );
F32 getSurfaceHeight ( void ) { return mSurfaceZ; }
void UpdateFluidRegion ( void );
static void SnagTerrain ( SceneObject* sceneObj, void * key );
static void cToggleWireFrame( SimObject*, S32, const char** );
void toggleWireFrame();
DECLARE_CONOBJECT(WaterBlock);
static void initPersistFields();
EWaterType getLiquidType() const { return mLiquidType; }
static bool isWater ( U32 liquidType );
static bool isLava ( U32 liquidType );
static bool isQuicksand ( U32 liquidType );
F32 getViscosity() const { return mViscosity; }
F32 getDensity() const { return mDensity; }
U32 packUpdate ( NetConnection* conn, U32 mask, BitStream *stream );
void unpackUpdate( NetConnection* conn, BitStream *stream );
bool isPointSubmerged ( const Point3F &pos, bool worldSpace = true ) const;
bool isPointSubmergedSimple( const Point3F &pos, bool worldSpace = true ) const;
AudioEnvironment * getAudioEnvironment() { return(mAudioEnvironment); }
static bool mCameraSubmerged;
static U32 mSubmergedType;
static TextureHandle getSubmergeTexture( U32 index ){ return mSubmergeTexture[index]; }
protected:
bool castRay( const Point3F& start, const Point3F& end, RayInfo* info );
void CalculateDepthMaps(void); ///< Calculate Depth Map.
void GenerateDepthTextures(GBitmap* pBitmap, TextureHandle& mTexture, bool ShoreFlag); ///< Generate Depth.
};
#endif