mirror of
https://github.com/tribes2/engine.git
synced 2026-07-11 14:34:38 +00:00
t2 engine svn checkout
This commit is contained in:
commit
ff569bd2ae
988 changed files with 394180 additions and 0 deletions
1714
terrain/blender.cc
Normal file
1714
terrain/blender.cc
Normal file
File diff suppressed because it is too large
Load diff
92
terrain/blender.h
Normal file
92
terrain/blender.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _BLENDER_H_
|
||||
#define _BLENDER_H_
|
||||
|
||||
#define PAULS_TEST_CODE 0
|
||||
|
||||
|
||||
#if PAULS_TEST_CODE
|
||||
|
||||
typedef unsigned char U8;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef float F32;
|
||||
|
||||
#define GRIDFLAGS( x, y ) (grid_mats[ yp ][ xp ])
|
||||
#define MATERIALSTART 1
|
||||
#define BLENDER_USE_ASM 1
|
||||
|
||||
#else
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "Platform/platform.h"
|
||||
#endif
|
||||
#ifndef _TERRDATA_H_
|
||||
#include "terrain/terrData.h"
|
||||
#endif
|
||||
#ifndef _TERRRENDER_H_
|
||||
#include "terrain/terrRender.h"
|
||||
#endif
|
||||
|
||||
#ifdef USEASSEMBLYTERRBLEND
|
||||
#define BLENDER_USE_ASM 1
|
||||
#else
|
||||
#define BLENDER_USE_ASM 0
|
||||
#endif
|
||||
|
||||
#define GRIDFLAGS( x, y ) (TerrainRender::mCurrentBlock->findSquare( 0, Point2I( xp, yp ) )->flags)
|
||||
#define MATERIALSTART (GridSquare::MaterialStart)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
public:
|
||||
// mips_per_bmp should include top level (always >= 1)
|
||||
// alphadata is 8 bit 256x256
|
||||
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.
|
||||
// lightmap should be 16 bit 512x512.
|
||||
// destmips 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 );
|
||||
|
||||
// bmps is an array of pointers to the bitmap and it's mips
|
||||
// highest detail first. Should be in 24bit format.
|
||||
// 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.
|
||||
void addSourceTexture( int bmp_type, const U8 **bmps );
|
||||
};
|
||||
|
||||
#endif
|
||||
1351
terrain/blender_asm.asm
Normal file
1351
terrain/blender_asm.asm
Normal file
File diff suppressed because it is too large
Load diff
178
terrain/bvQuadTree.cc
Normal file
178
terrain/bvQuadTree.cc
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/******************************************************************************
|
||||
* FILENAME: D:\Tribes\darkstar\terrain\bvQuadTree.cc
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* CREATED: 1/17/00 4:07:04 PM
|
||||
*
|
||||
* BY: PeteW
|
||||
******************************************************************************/
|
||||
|
||||
#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);
|
||||
}
|
||||
57
terrain/bvQuadTree.h
Normal file
57
terrain/bvQuadTree.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/******************************************************************************
|
||||
* FILENAME: D:\Tribes\darkstar\terrain\bvQuadTree.h
|
||||
*
|
||||
* DESCRIPTION:
|
||||
*
|
||||
* CREATED: 1/17/00 4:02:53 PM
|
||||
*
|
||||
* BY: PeteW
|
||||
******************************************************************************/
|
||||
|
||||
#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
|
||||
|
||||
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
|
||||
326
terrain/fluid.h
Normal file
326
terrain/fluid.h
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, 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 fogger 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.
|
||||
// - Block are 8 squares in normal resolution mode, and 4 in high.
|
||||
// - 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
|
||||
|
||||
//==============================================================================
|
||||
// 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)(Platform::getVirtualMilliseconds()) * 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)fmod( a, b )
|
||||
#define LENGTH3(a,b,c) (f32)sqrt( (a)*(a) + (b)*(b) + (c)*(c) )
|
||||
#define SINE(a) (float)sin( a )
|
||||
#define COSINE(a) (float)cos( a )
|
||||
|
||||
#define DISTANCE(x,y,z) LENGTH3( (x)-m_Eye.X, (y)-m_Eye.Y, (z)-m_Eye.Z )
|
||||
|
||||
#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.cpp):
|
||||
//
|
||||
void Render ( bool& EyeSubmerged );
|
||||
|
||||
//
|
||||
// Setup per frame (in FluidSupport.cpp):
|
||||
//
|
||||
void SetEyePosition ( f32 X, f32 Y, f32 Z );
|
||||
void SetFrustrumPlanes ( f32* pFrustrumPlanes );
|
||||
|
||||
//
|
||||
// Setup at initialization (in FluidSupport.cpp):
|
||||
//
|
||||
void SetInfo ( f32& X0,
|
||||
f32& Y0,
|
||||
f32& SizeX,
|
||||
f32& SizeY,
|
||||
f32 SurfaceZ,
|
||||
f32 WaveAmplitude,
|
||||
f32& Opacity,
|
||||
f32& EnvMapIntensity,
|
||||
s32 RemoveWetEdges );
|
||||
|
||||
void SetTerrainData ( u16* pTerrainData );
|
||||
|
||||
void SetTextures ( TextureHandle Base,
|
||||
TextureHandle EnvMap );
|
||||
|
||||
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.cpp):
|
||||
//
|
||||
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
|
||||
{
|
||||
xyz XYZ; // All phases - Position
|
||||
rgba RGBA1a; // Phase 1a - Base alpha, first pass
|
||||
rgba RGBA1b; // Phase 1b - Base alpha, second pass
|
||||
uv UV3; // Phase 3 - EnvMap UV
|
||||
rgba RGBA4; // Phase 4 - Fog Color/Alpha
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Variables
|
||||
//
|
||||
private:
|
||||
s32 m_SquareX0, m_SquareY0; // Anchor in terrain squares
|
||||
s32 m_SquaresInX, m_SquaresInY; // Number of squares in fluid region
|
||||
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
|
||||
xyz m_Eye;
|
||||
f32 m_Seconds;
|
||||
f32 m_BaseSeconds;
|
||||
rgba m_FogColor;
|
||||
f32 m_VisibleDistance;
|
||||
f32 m_Opacity;
|
||||
f32 m_EnvMapIntensity;
|
||||
f32 m_WaveAmplitude;
|
||||
f32 m_WaveFactor;
|
||||
u16* m_pTerrain; // 256x256 data for the terrain
|
||||
|
||||
TextureHandle m_BaseTexture;
|
||||
TextureHandle m_EnvMapTexture;
|
||||
TextureHandle m_LightMapTexture;
|
||||
|
||||
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:
|
||||
|
||||
//
|
||||
// Functions in FluidSupport.cpp:
|
||||
//
|
||||
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.cpp
|
||||
//
|
||||
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 BuildFogTable ( void );
|
||||
|
||||
void ReleaseVertexMemory ( void );
|
||||
vertex* AcquireVertices ( s32 Count );
|
||||
void AddTriangleIndices ( s16 I1, s16 I2, s16 I3 );
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#endif // FLUID_HPP
|
||||
//==============================================================================
|
||||
1060
terrain/fluidQuadTree.cc
Normal file
1060
terrain/fluidQuadTree.cc
Normal file
File diff suppressed because it is too large
Load diff
249
terrain/fluidRender.cc
Normal file
249
terrain/fluidRender.cc
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "terrain/Fluid.h"
|
||||
#include "dgl/dgl.h"
|
||||
|
||||
//==============================================================================
|
||||
// FUNCTIONS
|
||||
//==============================================================================
|
||||
|
||||
void fluid::Render( bool& EyeSubmerged )
|
||||
{
|
||||
f32 BaseDriftX, BaseDriftY;
|
||||
|
||||
f32 Q1 = 1.0f / 48.0f; // This just looks good.
|
||||
f32 Q2 = 1.0f / 2048.0f; // This is the size of the terrain.
|
||||
|
||||
f32 SBase[] = { Q1, 0, 0, 0 };
|
||||
f32 TBase[] = { 0, Q1, 0, 0 };
|
||||
|
||||
f32 SLMap[] = { Q2, 0, 0, 0 };
|
||||
f32 TLMap[] = { 0, Q2, 0, 0 };
|
||||
|
||||
// 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 );
|
||||
|
||||
// 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.
|
||||
{
|
||||
#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 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-- 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 );
|
||||
|
||||
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
|
||||
|
||||
glRotatef ( 30.0f, 0.0f, 0.0f, 1.0f );
|
||||
glColorPointer ( 4, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].RGBA1a) );
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-- 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, BaseDriftY, 0.0f );
|
||||
glColorPointer ( 4, GL_FLOAT, sizeof(vertex), &(m_pVertex[0].RGBA1b) );
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-- 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 );
|
||||
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 );
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-- 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, m_EnvMapTexture.getGLName() );
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-- 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
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
glDisable ( GL_BLEND );
|
||||
glDisableClientState( GL_VERTEX_ARRAY );
|
||||
glDisableClientState( GL_COLOR_ARRAY );
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//-- We're done with the rendering.
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
607
terrain/fluidSupport.cc
Normal file
607
terrain/fluidSupport.cc
Normal file
|
|
@ -0,0 +1,607 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "terrain/Fluid.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include <string.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;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
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 );
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void fluid::SetInfo( f32& X0,
|
||||
f32& Y0,
|
||||
f32& SizeX,
|
||||
f32& SizeY,
|
||||
f32 SurfaceZ,
|
||||
f32 WaveAmplitude,
|
||||
f32& Opacity,
|
||||
f32& EnvMapIntensity,
|
||||
s32 RemoveWetEdges )
|
||||
{
|
||||
// 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 = Opacity;
|
||||
m_EnvMapIntensity = EnvMapIntensity;
|
||||
|
||||
m_WaveFactor = m_WaveAmplitude * 0.25f;
|
||||
|
||||
// Place the "min" corner.
|
||||
m_SquareX0 = (s32)((X0 / 8.0f) + 0.5f);
|
||||
m_SquareY0 = (s32)((Y0 / 8.0f) + 0.5f);
|
||||
|
||||
// Constrain the range of values.
|
||||
if( m_SquareX0 < 0.0f ) m_SquareX0 = 0;
|
||||
if( m_SquareY0 < 0.0f ) m_SquareY0 = 0;
|
||||
if( m_SquareX0 > 2040.0f ) m_SquareX0 = 2040;
|
||||
if( m_SquareY0 > 2040.0f ) m_SquareY0 = 2040;
|
||||
|
||||
// Decide on the size of the block.
|
||||
m_SquaresInX = (s32)((SizeX / 8.0f) + 0.5f);
|
||||
m_SquaresInY = (s32)((SizeY / 8.0f) + 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.
|
||||
if( m_HighResMode )
|
||||
{
|
||||
m_Step[4] = 32.0f;
|
||||
m_Step[3] = 24.0f;
|
||||
m_Step[2] = 16.0f;
|
||||
m_Step[1] = 8.0f;
|
||||
m_Step[0] = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Step[4] = 64.0f;
|
||||
m_Step[3] = 48.0f;
|
||||
m_Step[2] = 32.0f;
|
||||
m_Step[1] = 16.0f;
|
||||
m_Step[0] = 0.0f;
|
||||
}
|
||||
|
||||
// Set values back into parameters for caller.
|
||||
X0 = m_SquareX0 * 8.0f;
|
||||
Y0 = m_SquareY0 * 8.0f;
|
||||
SizeX = m_SquaresInX * 8.0f;
|
||||
SizeY = m_SquaresInY * 8.0f;
|
||||
|
||||
// Recompute our masks.
|
||||
RebuildMasks();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void fluid::SetTerrainData( u16* pTerrainData )
|
||||
{
|
||||
m_pTerrain = pTerrainData;
|
||||
RebuildMasks();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void fluid::SetEyePosition( f32 X, f32 Y, f32 Z )
|
||||
{
|
||||
m_Eye.X = X;
|
||||
m_Eye.Y = Y;
|
||||
m_Eye.Z = Z;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// 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 EnvMap )
|
||||
{
|
||||
m_BaseTexture = Base;
|
||||
m_EnvMapTexture = EnvMap;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
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.
|
||||
x = (s32)X;
|
||||
y = (s32)Y;
|
||||
|
||||
// Compensate for min point offset.
|
||||
x -= (m_SquareX0 << 3);
|
||||
y -= (m_SquareY0 << 3);
|
||||
|
||||
// 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 ) );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
1788
terrain/sky.cc
Normal file
1788
terrain/sky.cc
Normal file
File diff suppressed because it is too large
Load diff
261
terrain/sky.h
Normal file
261
terrain/sky.h
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, 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
|
||||
{
|
||||
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 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();
|
||||
|
||||
void renderObject(SceneState*, SceneRenderImage*);
|
||||
bool prepRenderImage(SceneState*, const U32, const U32, const bool);
|
||||
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();
|
||||
void 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; }
|
||||
|
||||
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);
|
||||
|
||||
void setWindVelocity(const Point3F &);
|
||||
Point3F getWindVelocity();
|
||||
|
||||
TextureHandle getEnvironmentMap() { return mMaterialList.getMaterial(EnvMapMaterialOffset); }
|
||||
|
||||
DECLARE_CONOBJECT(Sky);
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
bool processArguments(S32 argc, const char **argv);
|
||||
|
||||
void unpackUpdate(NetConnection *, BitStream *stream);
|
||||
U32 packUpdate(NetConnection *, U32 mask, BitStream *stream);
|
||||
|
||||
void updateVisibility();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
116
terrain/sun.cc
Normal file
116
terrain/sun.cc
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "terrain/Sun.h"
|
||||
#include "console/objectTypes.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
#include "Core/bitStream.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "terrain/terrData.h"
|
||||
#include "dgl/gBitmap.h"
|
||||
#include "Math/mathIO.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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
{
|
||||
lightManager->addLight(&mLight);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
U32 Sun::packUpdate(NetConnection *, U32 mask, BitStream * stream)
|
||||
{
|
||||
if(stream->writeFlag(mask & UpdateMask))
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void Sun::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
addField("direction", TypePoint3F, Offset(mLight.mDirection, Sun));
|
||||
addField("color", TypeColorF, Offset(mLight.mColor, Sun));
|
||||
addField("ambient", TypeColorF, Offset(mLight.mAmbient, Sun));
|
||||
}
|
||||
54
terrain/sun.h
Normal file
54
terrain/sun.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SUN_H_
|
||||
#define _SUN_H_
|
||||
|
||||
#ifndef _NETOBJECT_H_
|
||||
#include "Sim/netObject.h"
|
||||
#endif
|
||||
#ifndef _COLOR_H_
|
||||
#include "Core/color.h"
|
||||
#endif
|
||||
#ifndef _LIGHTMANAGER_H_
|
||||
#include "sceneGraph/lightManager.h"
|
||||
#endif
|
||||
|
||||
class Sun : public NetObject
|
||||
{
|
||||
private:
|
||||
typedef NetObject Parent;
|
||||
|
||||
LightInfo mLight;
|
||||
|
||||
void conformLight();
|
||||
|
||||
public:
|
||||
|
||||
Sun();
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void registerLights(LightManager *, bool);
|
||||
|
||||
//
|
||||
void inspectPostApply();
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
// NetObject
|
||||
enum NetMaskBits {
|
||||
UpdateMask = BIT(0)
|
||||
};
|
||||
|
||||
void unpackUpdate(NetConnection *, BitStream * stream);
|
||||
U32 packUpdate(NetConnection *, U32 mask, BitStream * stream);
|
||||
|
||||
DECLARE_CONOBJECT(Sun);
|
||||
};
|
||||
|
||||
#endif
|
||||
1018
terrain/terrCollision.cc
Normal file
1018
terrain/terrCollision.cc
Normal file
File diff suppressed because it is too large
Load diff
1420
terrain/terrData.cc
Normal file
1420
terrain/terrData.cc
Normal file
File diff suppressed because it is too large
Load diff
414
terrain/terrData.h
Normal file
414
terrain/terrData.h
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, 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
|
||||
|
||||
|
||||
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 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;
|
||||
StringTableEntry *mMaterialFileName; // array from the file
|
||||
|
||||
TextureHandle mDynLightTexture;
|
||||
|
||||
U8 *mBaseMaterialMap;
|
||||
Material *materialMap;
|
||||
// fixed point height values
|
||||
U16 *heightMap;
|
||||
U16 *flagMap;
|
||||
StringTableEntry mDetailTextureName;
|
||||
TextureHandle mDetailTextureHandle;
|
||||
|
||||
StringTableEntry mTerrFileName;
|
||||
Vector<S32> mEmptySquareRuns;
|
||||
|
||||
U32 mTextureCallbackKey;
|
||||
void processTextureEvent(const U32 eventCode);
|
||||
|
||||
S32 mMPMIndex[10];
|
||||
|
||||
S32 mVertexBuffer;
|
||||
|
||||
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); }
|
||||
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
void refreshMaterialLists();
|
||||
void onEditorEnable();
|
||||
void onEditorDisable();
|
||||
|
||||
void rebuildEmptyFlags();
|
||||
bool unpackEmptySquares();
|
||||
void packEmptySquares();
|
||||
|
||||
TextureHandle getDetailTextureHandle();
|
||||
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);
|
||||
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);
|
||||
|
||||
U8 *getMaterialAlphaMap(U32 matIndex);
|
||||
U8* getBaseMaterialAddress(U32 x, U32 y);
|
||||
U8 getBaseMaterial(U32 x, U32 y);
|
||||
U16 *getFlagMapPtr(S32 x, S32 y);
|
||||
|
||||
// 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));}
|
||||
|
||||
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&);
|
||||
bool prepRenderImage(SceneState*, const U32, const U32, const bool);
|
||||
void renderObject(SceneState*, SceneRenderImage*);
|
||||
|
||||
//--------------------------------------
|
||||
// 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, 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 loadBaseMaterials();
|
||||
bool initMMXBlender();
|
||||
|
||||
// private helper
|
||||
private:
|
||||
bool mCollideEmpty;
|
||||
|
||||
public:
|
||||
DECLARE_CONOBJECT(TerrainBlock);
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
U32 packUpdate(NetConnection *, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *, BitStream *stream);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
class TerrainFile : public ResourceInstance
|
||||
{
|
||||
public:
|
||||
enum Constants {
|
||||
FILE_VERSION = 2,
|
||||
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];
|
||||
|
||||
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)];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
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
|
||||
766
terrain/terrLighting.cc
Normal file
766
terrain/terrLighting.cc
Normal file
|
|
@ -0,0 +1,766 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, 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"
|
||||
|
||||
//void TerrainRender::setupColorAdder(F32 rSquared, F32 r, F32 g, F32 b)
|
||||
//{
|
||||
// mCurrentR = r;
|
||||
// mCurrentG = g;
|
||||
// mCurrentB = b;
|
||||
// mCurrentRSq = rSquared;
|
||||
//}
|
||||
//
|
||||
//void TerrainRender::addColor(Color &c, F32 dSquared)
|
||||
//{
|
||||
// if(dSquared > mCurrentRSq)
|
||||
// return;
|
||||
// F32 scale = 255.0f * ( 1 - (dSquared / mCurrentRSq) );
|
||||
// c.r += (S32)(mCurrentR * scale);
|
||||
// c.g += (S32)(mCurrentG * scale);
|
||||
// c.b += (S32)(mCurrentB * scale);
|
||||
//}
|
||||
//
|
||||
//inline U16 TerrainRender::convertColorBack(Color &c)
|
||||
//{
|
||||
// U16 ret;
|
||||
// if(c.r > 255)
|
||||
// ret = 0xF800;
|
||||
// else
|
||||
// ret = (c.r >> 3) << 11;
|
||||
// if(c.g > 255)
|
||||
// ret |= 0x07E0;
|
||||
// else
|
||||
// ret |= (c.g >> 2) << 5;
|
||||
//
|
||||
// if(c.b > 255)
|
||||
// ret |= 0x001F;
|
||||
// else
|
||||
// ret |= c.b >> 3;
|
||||
//
|
||||
// return ret;
|
||||
//}
|
||||
//
|
||||
//inline void TerrainRender::convertColor(Color &c, U16 lix)
|
||||
//{
|
||||
// S32 r = lix >> 11;
|
||||
// S32 g = (lix >> 5) & 0x3F;
|
||||
// S32 b = lix & 0x1F;
|
||||
//
|
||||
// c.r = (r << 3) | ( r >> 2);
|
||||
// c.g = (g << 2) | ( g >> 4);
|
||||
// c.b = (b << 3) | ( b >> 2);
|
||||
//}
|
||||
//
|
||||
//void TerrainRender::lightExpandHorz(F32 x, F32 ySquared, F32 dx, S32 j, S32 i, S32 shift)
|
||||
//{
|
||||
// S32 size = 1 << shift;
|
||||
// F32 scale = 1 / F32(size);
|
||||
//
|
||||
// F32 z = mLMABuffer[j][i].z;
|
||||
// F32 dz = (mLMABuffer[j][i+size].z - z) * scale;
|
||||
//
|
||||
// for(S32 count = 1; count < size; count++)
|
||||
// {
|
||||
// x += dx;
|
||||
// z += dz;
|
||||
//
|
||||
// addColor(mLMABuffer[j][i + count], x * x + z * z + ySquared);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void TerrainRender::lightExpandVert(F32 y, F32 xSquared, F32 dy, S32 j, S32 i, S32 shift)
|
||||
//{
|
||||
// S32 size = 1 << shift;
|
||||
// F32 scale = 1 / F32(size);
|
||||
//
|
||||
// F32 z = mLMABuffer[j][i].z;
|
||||
// F32 dz = (mLMABuffer[j+size][i].z - z) * scale;
|
||||
//
|
||||
// for(S32 count = 1; count < size; count++)
|
||||
// {
|
||||
// y += dy;
|
||||
// z += dz;
|
||||
//
|
||||
// mLMABuffer[j+count][i].z = z;
|
||||
// addColor(mLMABuffer[j+count][i], y * y + z * z + xSquared);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void TerrainRender::lmExpandHorz(S32 y, S32 x, S32 shift)
|
||||
//{
|
||||
// S32 size = 1 << shift;
|
||||
// Color d;
|
||||
// Color c = mLMABuffer[y][x];
|
||||
// d.r = (mLMABuffer[y][x+size].r - c.r) >> shift;
|
||||
// d.g = (mLMABuffer[y][x+size].g - c.g) >> shift;
|
||||
// d.b = (mLMABuffer[y][x+size].b - c.b) >> shift;
|
||||
//
|
||||
// for(S32 i = 1; i < size; i++)
|
||||
// {
|
||||
// c.r += d.r;
|
||||
// c.g += d.g;
|
||||
// c.b += d.b;
|
||||
//
|
||||
// mLMABuffer[y][x+i] = c;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void TerrainRender::lmExpandVert(S32 y, S32 x, S32 shift)
|
||||
//{
|
||||
// S32 size = 1 << shift;
|
||||
// Color d;
|
||||
// Color c = mLMABuffer[y][x];
|
||||
// d.r = (mLMABuffer[y+size][x].r - c.r) >> shift;
|
||||
// d.g = (mLMABuffer[y+size][x].g - c.g) >> shift;
|
||||
// d.b = (mLMABuffer[y+size][x].b - c.b) >> shift;
|
||||
//
|
||||
// for(S32 i = 1; i < size; i++)
|
||||
// {
|
||||
// c.r += d.r;
|
||||
// c.g += d.g;
|
||||
// c.b += d.b;
|
||||
//
|
||||
// mLMABuffer[y+i][x] = c;
|
||||
// }
|
||||
//}
|
||||
|
||||
//void TerrainRender::expandDynamicLight(TerrLightInfo &tl, S32 x, S32 y, S32 level)
|
||||
//{
|
||||
// S32 i, j;
|
||||
// setupColorAdder(tl.radiusSquared, tl.r, tl.g, tl.b);
|
||||
//
|
||||
// if(DynamicLightMapShift - level <= 0)
|
||||
// {
|
||||
// S32 step = 1 << (level - DynamicLightMapShift);
|
||||
// S32 count = DynamicLightMapSize;
|
||||
// for(j = 0; j <= count; j++)
|
||||
// {
|
||||
// for(i = 0; i <= count; i++)
|
||||
// {
|
||||
// F32 xp = (x + i*step) * mSquareSize - tl.pos.x;
|
||||
// F32 yp = (y + j*step) * mSquareSize - tl.pos.y;
|
||||
// F32 zp = fixedToFloat(mCurrentBlock->getHeight((x + i) & TerrainBlock::BlockMask,
|
||||
// (y + j) & TerrainBlock::BlockMask)) - tl.pos.z;
|
||||
//
|
||||
// addColor(mLMABuffer[j][i], xp * xp + yp * yp + zp * zp);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// S32 delt = DynamicLightMapShift - level;
|
||||
// S32 size = 1 << delt;
|
||||
// S32 count = 1 << level;
|
||||
//
|
||||
// F32 delta = mSquareSize / F32(size);
|
||||
//
|
||||
// for(j = 0; j <= count; j++)
|
||||
// {
|
||||
// for(i = 0; i <= count; i++)
|
||||
// {
|
||||
// F32 xp = (x + i) * mSquareSize - tl.pos.x;
|
||||
// F32 yp = (y + j) * mSquareSize - tl.pos.y;
|
||||
// F32 zp = fixedToFloat(mCurrentBlock->getHeight((x + i) & TerrainBlock::BlockMask, (y + j) & TerrainBlock::BlockMask)) - tl.pos.z;
|
||||
// mLMABuffer[j << delt][i << delt].z = zp;
|
||||
//
|
||||
// addColor(mLMABuffer[j << delt][i << delt], xp * xp + yp * yp + zp * zp);
|
||||
// if(i != 0)
|
||||
// lightExpandHorz(xp - mSquareSize, yp * yp, delta, j << delt, (i - 1) << delt, delt);
|
||||
// if(j != 0)
|
||||
// lightExpandVert(yp - mSquareSize, xp * xp, delta, (j-1) << delt, i << delt, delt);
|
||||
// if(i != 0 && j != 0)
|
||||
// {
|
||||
// F32 xp = (x + i - 1) * mSquareSize - tl.pos.x;
|
||||
// for(S32 k = 1; k < size; k++)
|
||||
// {
|
||||
// F32 yp = (y + j - 1) * mSquareSize + k * delta - tl.pos.y;
|
||||
// lightExpandHorz(xp, yp * yp, delta, ((j - 1) << delt) + k, (i-1) << delt, delt);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//void TerrainRender::expandLightMap(S32 /*x*/, S32 /*y*/, S32 /*level*/)
|
||||
//{
|
||||
// S32 i, j;
|
||||
// x &= TerrainBlock::BlockMask;
|
||||
// y &= TerrainBlock::BlockMask;
|
||||
// GBitmap *lightMap = mCurrentBlock->lightMapHandle.getBitmap();
|
||||
// if(DynamicLightMapShift - level <= 0)
|
||||
// {
|
||||
// S32 step = (level - DynamicLightMapShift);
|
||||
// S32 count = DynamicLightMapSize;
|
||||
// S32 lightMask = lightMap->getWidth() - 1;
|
||||
//
|
||||
// for(j = 0; j <= count; j++)
|
||||
// {
|
||||
// for(i = 0; i <= count; i++)
|
||||
// {
|
||||
// U16 lix = * ((U16 *) lightMap->
|
||||
// getAddress( (x + (i << step)) & lightMask,
|
||||
// (y + (j << step)) & lightMask ) );
|
||||
// convertColor(mLMABuffer[j][i], lix);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// S32 delt = DynamicLightMapShift - level;
|
||||
// S32 size = 1 << delt;
|
||||
// S32 count = 1 << level;
|
||||
//
|
||||
// for(j = 0; j <= count; j++)
|
||||
// {
|
||||
// U16 *pixPtr = (U16 *) lightMap->getAddress(x, y + j);
|
||||
// for(i = 0; i <= count; i++)
|
||||
// {
|
||||
// convertColor(mLMABuffer[j << delt][i << delt], *pixPtr++);
|
||||
// if(i != 0)
|
||||
// lmExpandHorz(j << delt, (i-1) << delt, delt);
|
||||
// if(j != 0)
|
||||
// lmExpandVert((j-1) << delt, i << delt, delt);
|
||||
// if(i != 0 && j != 0)
|
||||
// {
|
||||
// for(S32 k = 1; k < size; k++)
|
||||
// lmExpandHorz(((j-1) << delt) + k, (i-1) << delt, delt);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//jff tmp
|
||||
#include "sceneGraph/lightManager.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
|
||||
void TerrainRender::buildLightArray()
|
||||
{
|
||||
static Vector<LightInfo*> lights;
|
||||
|
||||
//
|
||||
lights.clear();
|
||||
gClientSceneGraph->getLightManager()->getBestLights(mClipPlane, mNumClipPlanes, mCamPos, lights, MaxTerrainLights);
|
||||
|
||||
// create terrain lights from these...
|
||||
U32 curIndex = 0;
|
||||
for(U32 i = 0; i < lights.size(); i++)
|
||||
{
|
||||
if(lights[i]->mType != LightInfo::Point)
|
||||
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;
|
||||
|
||||
/*const TMat3F & mat = mCamera->getTOW();
|
||||
TSSceneLighting * sceneLights = trs.renderContext->getLights();
|
||||
SphereF instSphere ( mat.p, 1000000.0f );
|
||||
sceneLights->prepare ( instSphere, mat );
|
||||
|
||||
S32 lightCount = 0;
|
||||
|
||||
TSSceneLighting::iterator ptr;
|
||||
for ( ptr = sceneLights->begin(); ptr != sceneLights->end() && lightCount < MaxTerrainLights ; ptr++ )
|
||||
{
|
||||
TSLight *tsl = *ptr;
|
||||
if(tsl->fLight.fType == TS::Light::LightPoint && !tsl->isStaticLight())
|
||||
{
|
||||
mTerrainLights[lightCount].pos = tsl->fLight.fPosition;
|
||||
Point3F dVec = mCamPos - mTerrainLights[lightCount].pos;
|
||||
|
||||
mTerrainLights[lightCount].distSquared = m_dot(dVec, dVec);
|
||||
mTerrainLights[lightCount].radius = tsl->fLight.fRange;
|
||||
mTerrainLights[lightCount].radiusSquared = tsl->fLight.fRange * tsl->fLight.fRange;
|
||||
mTerrainLights[lightCount].r = tsl->fLight.fRed;
|
||||
mTerrainLights[lightCount].g = tsl->fLight.fGreen;
|
||||
mTerrainLights[lightCount].b = tsl->fLight.fBlue;
|
||||
lightCount++;
|
||||
}
|
||||
}
|
||||
trs.dynamicLightCount = min(lightCount, (S32)MaxVisibleLights);
|
||||
*/
|
||||
}
|
||||
|
||||
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.red * 31) << 11) |
|
||||
(U32(color.green * 31) << 6) |
|
||||
(U32(color.blue * 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(U32 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(U32 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(U32 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;
|
||||
}
|
||||
|
||||
2298
terrain/terrRender.cc
Normal file
2298
terrain/terrRender.cc
Normal file
File diff suppressed because it is too large
Load diff
342
terrain/terrRender.h
Normal file
342
terrain/terrRender.h
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, 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;
|
||||
// ColorI color;
|
||||
};
|
||||
|
||||
struct EdgePoint : public Point3F
|
||||
{
|
||||
ColorI detailColor;
|
||||
F32 haze;
|
||||
F32 distance;
|
||||
F32 fogRed;
|
||||
F32 fogGreen;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
//struct ScanEdge
|
||||
//{
|
||||
// U16 p1, p2, mp;
|
||||
// U16 firstSubEdge; // two sub edges for each edge, mp = InvalidPointIndex if none
|
||||
//};
|
||||
|
||||
enum EmptyFlags {
|
||||
SquareEmpty_0_0 = (1 << 0),
|
||||
SquareEmpty_1_0 = (1 << 1),
|
||||
SquareEmpty_2_0 = (1 << 2),
|
||||
SquareEmpty_3_0 = (1 << 3),
|
||||
SquareEmpty_0_1 = (1 << 4),
|
||||
SquareEmpty_1_1 = (1 << 5),
|
||||
SquareEmpty_2_1 = (1 << 6),
|
||||
SquareEmpty_3_1 = (1 << 7),
|
||||
SquareEmpty_0_2 = (1 << 8),
|
||||
SquareEmpty_1_2 = (1 << 9),
|
||||
SquareEmpty_2_2 = (1 << 10),
|
||||
SquareEmpty_3_2 = (1 << 11),
|
||||
SquareEmpty_0_3 = (1 << 12),
|
||||
SquareEmpty_1_3 = (1 << 13),
|
||||
SquareEmpty_2_3 = (1 << 14),
|
||||
SquareEmpty_3_3 = (1 << 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 {
|
||||
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,
|
||||
|
||||
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 mEnableTerrainDynLights;
|
||||
|
||||
static F32 mPixelError;
|
||||
|
||||
static TerrLightInfo mTerrainLights[MaxTerrainLights];
|
||||
static F32 mScreenError;
|
||||
static F32 mMinSquareSize;
|
||||
static F32 mFarDistance;
|
||||
static S32 mDynamicTextureCount;
|
||||
static S32 mTextureSpaceUsed;
|
||||
static S32 mLevelZeroCount;
|
||||
static S32 mFullMipCount;
|
||||
static S32 mStaticTextureCount;
|
||||
static S32 mUnusedTextureCount;
|
||||
static S32 mStaticTSU;
|
||||
static S32 mSquareSeqAdd[256];
|
||||
static U32 mNewGenTextureCount;
|
||||
static F32 mInvFarDistance;
|
||||
static F32 mInvHeightRange;
|
||||
static U32 mMipCap;
|
||||
static bool mRenderingCommander;
|
||||
|
||||
static ColorF mFogColor;
|
||||
|
||||
static bool mRenderOutline;
|
||||
static U32 mMaterialCount;
|
||||
|
||||
static GBitmap* mBlendBitmap;
|
||||
|
||||
static void (*transformPoint)(U32 point, U32 p1, U32 p2);
|
||||
|
||||
static void init();
|
||||
static void shutdown();
|
||||
|
||||
// static void allocReset();
|
||||
// static void* alloc(U32 byteSize);
|
||||
static void allocRenderEdges(U32 edgeCount, EdgeParent **dest, bool renderEdge);
|
||||
static void subdivideChunkEdge(ChunkScanEdge *e, Point2I pos, bool chunkEdge);
|
||||
static void processCurrentBlock2(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);
|
||||
static void renderChunkOutline(EmitChunk *chunk);
|
||||
static void renderChunkCommander(EmitChunk *chunk);
|
||||
static void fixEdge(ChunkEdge *edge, S32 x, S32 y, S32 dx, S32 dy);
|
||||
static void drawTriFan(U32 vCount, U32 *indexBuffer);
|
||||
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 clipStart(EdgePoint *pt, U32 index);
|
||||
static void clipInsert(EdgePoint *pt, U32 index);
|
||||
static void clipEnd();
|
||||
static void clip(U32 triFanStart);
|
||||
|
||||
static F32 getScreenError() { return(mScreenError); }
|
||||
static void setScreenError(F32 error) { mScreenError = error; }
|
||||
|
||||
static void flushCache();
|
||||
static void transformTerrainPoint(U32 point, U32 p1, U32 p2);
|
||||
|
||||
static U8 getClipFlags(Point2F &pos, U8 clipMask);
|
||||
|
||||
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 S32 allocEdges(S32 count);
|
||||
static void clampEdge(S32 edge);
|
||||
static void subdivideEdge(S32 edge, Point2I pos);
|
||||
static F32 getSquareDistance(const Point3F& minPoint, const Point3F& maxPoint,
|
||||
F32* zDiff);
|
||||
static bool subdivideSquare(GridSquare *sq, S32 level, Point2I pos);
|
||||
|
||||
static void emitTerrSquare(SquareStackNode *n, U32 flags);
|
||||
static void emitFullMipSquare(SquareStackNode *n, U32 flags);
|
||||
static void emitNonzeroSquare(SquareStackNode *n, U32 flags, U32 mipLevel);
|
||||
static void emitLevelZeroSquare(SquareStackNode *n, U32 flags, U32 material, U32 mipLevel);
|
||||
|
||||
static void buildTextureCoor();
|
||||
static void renderCurrentBlock(S32 firstSquare, S32 lastSquare);
|
||||
|
||||
static void textureRecurse(SquareStackNode *n);
|
||||
static void processCurrentBlock(S32 topEdge, S32 rightEdge, S32 bottomEdge, S32 leftEdge);
|
||||
static void buildLightArray();
|
||||
static void buildClippingPlanes(bool flipClipPlanes);
|
||||
static void buildDetailTable();
|
||||
|
||||
static void renderXFCache();
|
||||
static void renderBlock(TerrainBlock *, SceneState *state);
|
||||
|
||||
static void textureRecurse2(SquareStackNode2 *n);
|
||||
static void tesselate0(SquareStackNode2 *n, U32 flags);
|
||||
static void tesselate1(SquareStackNode2 *n);
|
||||
static void tesselate2(SquareStackNode2 *n);
|
||||
static void tesselate3(SquareStackNode2 *n);
|
||||
static void farclip(SquareStackNode2 *n, U32 flags);
|
||||
static void render2();
|
||||
static void processBlockStack(SquareStackNode2 *stack, S32 curStackSize);
|
||||
|
||||
protected:
|
||||
static void doesWaterBlockSubmergeCamera(SceneObject *sceneObj, S32 key);
|
||||
};
|
||||
|
||||
#endif
|
||||
655
terrain/terrRender2.cc
Normal file
655
terrain/terrRender2.cc
Normal file
|
|
@ -0,0 +1,655 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, 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 "terrain/terrRender.h"
|
||||
#include "dgl/materialList.h"
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#include "terrain/waterBlock.h"
|
||||
#include "terrain/blender.h"
|
||||
#include "Sim/frameAllocator.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
#include "sceneGraph/sgUtil.h"
|
||||
|
||||
Render2Point gEmitPoints2[65536];
|
||||
U16 gIndexArray2[131000];
|
||||
Render2Point *mEmitPoints2;
|
||||
U16 *mIndexArray2;
|
||||
U32 mCurrPoint2;
|
||||
U32 mPrimQ[16384];
|
||||
|
||||
struct PrimitiveList
|
||||
{
|
||||
enum {
|
||||
MaxCount = 256,
|
||||
};
|
||||
U32 count;
|
||||
U16 *primList[MaxCount];
|
||||
PrimitiveList *next;
|
||||
static void alloc(PrimitiveList **ph)
|
||||
{
|
||||
PrimitiveList *next = *ph;
|
||||
*ph = (PrimitiveList *) FrameAllocator::alloc(sizeof(PrimitiveList));
|
||||
(*ph)->count = 0;
|
||||
(*ph)->next = next;
|
||||
}
|
||||
};
|
||||
|
||||
PrimitiveList *blendList[TerrainBlock::MaterialGroups];
|
||||
PrimitiveList *baseList[TerrainBlock::MaterialGroups];
|
||||
|
||||
|
||||
inline void addPrimitive(U16 *start, PrimitiveList **lp)
|
||||
{
|
||||
if(!(*lp) || ( (*lp)->count == PrimitiveList::MaxCount) )
|
||||
PrimitiveList::alloc(lp);
|
||||
(*lp)->primList[(*lp)->count++] = start;
|
||||
}
|
||||
#if 0
|
||||
void addPrimitives(U32 flags, U16 *start)
|
||||
{
|
||||
if(flags & GridSquare::Material0)
|
||||
{
|
||||
addPrimitive(start, &baseList[0]);
|
||||
goto testBlend1;
|
||||
}
|
||||
if(flags & GridSquare::Material1)
|
||||
{
|
||||
addPrimitive(start, &baseList[1]);
|
||||
goto testBlend2;
|
||||
}
|
||||
if(flags & GridSquare::Material2)
|
||||
{
|
||||
addPrimitive(start, &baseList[2]);
|
||||
goto testBlend3;
|
||||
}
|
||||
if(flags & GridSquare::Material3)
|
||||
addPrimitive(start, &baseList[3]);
|
||||
return;
|
||||
testBlend1:
|
||||
if(flags & GridSquare::Material1)
|
||||
addPrimitive(start, &blendList[1]);
|
||||
testBlend2:
|
||||
if(flags & GridSquare::Material2)
|
||||
addPrimitive(start, &blendList[2]);
|
||||
testBlend3:
|
||||
if(flags & GridSquare::Material3)
|
||||
addPrimitive(start, &blendList[3]);
|
||||
}
|
||||
#else
|
||||
#define addPrimitives(x,y)
|
||||
#endif
|
||||
|
||||
void TerrainRender::tesselate3(SquareStackNode2 *n)
|
||||
{
|
||||
// generate 9x9 array of points, and emit the 16 fans for the block
|
||||
U32 i = 0, x, y;
|
||||
Render2Point * ep = mEmitPoints2 + mCurrPoint2;
|
||||
F32 xp, yp, step = mSquareSize;
|
||||
|
||||
yp = n->pos.y * mSquareSize + mBlockPos.y;
|
||||
F32 xs = n->pos.x * mSquareSize + mBlockPos.x;
|
||||
|
||||
U16 *flp = mCurrentBlock->getFlagMapPtr(n->pos.x, n->pos.y);
|
||||
|
||||
for(y = 0; y < 9; y++)
|
||||
{
|
||||
xp = xs;
|
||||
U16 *hp = mCurrentBlock->getHeightAddress(n->pos.x, n->pos.y + y);
|
||||
for(x = 0; x < 8; x++)
|
||||
{
|
||||
ep->x = xp;
|
||||
ep->y = yp;
|
||||
ep->z = fixedToFloat(*hp++);
|
||||
ep++;
|
||||
xp += step;
|
||||
}
|
||||
ep->x = xp;
|
||||
ep->y = yp;
|
||||
ep->z = fixedToFloat(mCurrentBlock->getHeight(n->pos.x + x, n->pos.y + y));
|
||||
ep++;
|
||||
if((~y) & 1)
|
||||
{
|
||||
ep[-9].d = (ep[-9] - mCamPos).len();
|
||||
ep[-7].d = (ep[-7] - mCamPos).len();
|
||||
ep[-5].d = (ep[-5] - mCamPos).len();
|
||||
ep[-3].d = (ep[-3] - mCamPos).len();
|
||||
ep[-1].d = (ep[-1] - mCamPos).len();
|
||||
ep[-8].d = (ep[-9].d + ep[-7].d) * 0.5;
|
||||
ep[-6].d = (ep[-7].d + ep[-5].d) * 0.5;
|
||||
ep[-4].d = (ep[-5].d + ep[-3].d) * 0.5;
|
||||
ep[-2].d = (ep[-3].d + ep[-1].d) * 0.5;
|
||||
if(y > 1)
|
||||
{
|
||||
Render2Point *r1 = ep - 27;
|
||||
Render2Point *r2 = ep - 18;
|
||||
Render2Point *r3 = ep - 9;
|
||||
r2[0].d = (r1[0].d + r3[0].d) * 0.5;
|
||||
r2[2].d = (r1[2].d + r3[2].d) * 0.5;
|
||||
r2[4].d = (r1[4].d + r3[4].d) * 0.5;
|
||||
r2[6].d = (r1[6].d + r3[6].d) * 0.5;
|
||||
r2[8].d = (r1[8].d + r3[8].d) * 0.5;
|
||||
|
||||
r2[1].d = (r2[0].d + r2[2].d) * 0.5;
|
||||
r2[3].d = (r2[2].d + r2[4].d) * 0.5;
|
||||
r2[5].d = (r2[4].d + r2[6].d) * 0.5;
|
||||
r2[7].d = (r2[6].d + r2[8].d) * 0.5;
|
||||
}
|
||||
}
|
||||
yp += step;
|
||||
}
|
||||
for(y = 0; y < 4; y++)
|
||||
{
|
||||
for(x = 0; x < 4; x++)
|
||||
{
|
||||
addPrimitives(*flp, mIndexArray2);
|
||||
flp++;
|
||||
|
||||
mIndexArray2[0] = GL_TRIANGLE_FAN;
|
||||
mIndexArray2[1] = 10;
|
||||
mIndexArray2[2] = mCurrPoint2 + 10;
|
||||
mIndexArray2[3] = mCurrPoint2 + 18;
|
||||
mIndexArray2[4] = mCurrPoint2 + 19;
|
||||
mIndexArray2[5] = mCurrPoint2 + 20;
|
||||
mIndexArray2[6] = mCurrPoint2 + 11;
|
||||
mIndexArray2[7] = mCurrPoint2 + 2;
|
||||
mIndexArray2[8] = mCurrPoint2 + 1;
|
||||
mIndexArray2[9] = mCurrPoint2;
|
||||
mIndexArray2[10] = mCurrPoint2 + 9;
|
||||
mIndexArray2[11] = mCurrPoint2 + 18;
|
||||
mIndexArray2 += 12;
|
||||
mCurrPoint2 += 2;
|
||||
}
|
||||
flp += TerrainBlock::FlagMapWidth - 4;
|
||||
mCurrPoint2 += 10;
|
||||
}
|
||||
mCurrPoint2 += 9;
|
||||
}
|
||||
|
||||
void TerrainRender::tesselate2(SquareStackNode2 *n)
|
||||
{
|
||||
U32 i = 0, x, y;
|
||||
Render2Point * ep = mEmitPoints2 + mCurrPoint2;
|
||||
F32 xp, yp, step = mSquareSize;
|
||||
F32 xs = n->pos.x * mSquareSize + mBlockPos.x;
|
||||
|
||||
yp = n->pos.y * mSquareSize + mBlockPos.y;
|
||||
U16 *flp = mCurrentBlock->getFlagMapPtr(n->pos.x, n->pos.y);
|
||||
|
||||
for(y = 0; y < 5; y++)
|
||||
{
|
||||
xp = xs;
|
||||
for(x = 0; x < 5; x++)
|
||||
{
|
||||
ep->x = xp;
|
||||
ep->y = yp;
|
||||
ep->z = fixedToFloat(mCurrentBlock->getHeight(n->pos.x + x, n->pos.y + y));
|
||||
ep->d = (*ep - mCamPos).len();
|
||||
ep++;
|
||||
xp += step;
|
||||
}
|
||||
yp += step;
|
||||
}
|
||||
for(y = 0; y < 2; y++)
|
||||
{
|
||||
for(x = 0; x < 2; x++)
|
||||
{
|
||||
addPrimitives(*flp, mIndexArray2);
|
||||
flp++;
|
||||
|
||||
mIndexArray2[0] = GL_TRIANGLE_FAN;
|
||||
mIndexArray2[1] = 10;
|
||||
mIndexArray2[2] = mCurrPoint2 + 6;
|
||||
mIndexArray2[3] = mCurrPoint2 + 10;
|
||||
mIndexArray2[4] = mCurrPoint2 + 11;
|
||||
mIndexArray2[5] = mCurrPoint2 + 12;
|
||||
mIndexArray2[6] = mCurrPoint2 + 7;
|
||||
mIndexArray2[7] = mCurrPoint2 + 2;
|
||||
mIndexArray2[8] = mCurrPoint2 + 1;
|
||||
mIndexArray2[9] = mCurrPoint2;
|
||||
mIndexArray2[10] = mCurrPoint2 + 5;
|
||||
mIndexArray2[11] = mCurrPoint2 + 10;
|
||||
mIndexArray2 += 12;
|
||||
mCurrPoint2 += 2;
|
||||
}
|
||||
mCurrPoint2 += 6;
|
||||
flp += TerrainBlock::FlagMapWidth - 2;
|
||||
}
|
||||
mCurrPoint2 += 5;
|
||||
}
|
||||
|
||||
void TerrainRender::tesselate1(SquareStackNode2 *n)
|
||||
{
|
||||
U32 i = 0, x, y;
|
||||
Render2Point * ep = mEmitPoints2 + mCurrPoint2;
|
||||
F32 xp, yp, step = mSquareSize;
|
||||
F32 xs = n->pos.x * mSquareSize + mBlockPos.x;
|
||||
|
||||
yp = n->pos.y * mSquareSize + mBlockPos.y;
|
||||
|
||||
for(y = 0; y < 3; y++)
|
||||
{
|
||||
xp = xs;
|
||||
for(x = 0; x < 3; x++)
|
||||
{
|
||||
ep->x = xp;
|
||||
ep->y = yp;
|
||||
ep->z = fixedToFloat(mCurrentBlock->getHeight(n->pos.x + x, n->pos.y + y));
|
||||
ep->d = (*ep - mCamPos).len();
|
||||
ep++;
|
||||
xp += step;
|
||||
}
|
||||
yp += step;
|
||||
}
|
||||
addPrimitives( *(mCurrentBlock->getFlagMapPtr(n->pos.x, n->pos.y)), mIndexArray2);
|
||||
mIndexArray2[0] = GL_TRIANGLE_FAN;
|
||||
mIndexArray2[1] = 10;
|
||||
mIndexArray2[2] = mCurrPoint2 + 4;
|
||||
mIndexArray2[3] = mCurrPoint2 + 6;
|
||||
mIndexArray2[4] = mCurrPoint2 + 7;
|
||||
mIndexArray2[5] = mCurrPoint2 + 8;
|
||||
mIndexArray2[6] = mCurrPoint2 + 5;
|
||||
mIndexArray2[7] = mCurrPoint2 + 2;
|
||||
mIndexArray2[8] = mCurrPoint2 + 1;
|
||||
mIndexArray2[9] = mCurrPoint2;
|
||||
mIndexArray2[10] = mCurrPoint2 + 3;
|
||||
mIndexArray2[11] = mCurrPoint2 + 6;
|
||||
mIndexArray2 += 12;
|
||||
mCurrPoint2 += 9;
|
||||
}
|
||||
|
||||
void TerrainRender::tesselate0(SquareStackNode2 *n, U32 flags)
|
||||
{
|
||||
}
|
||||
|
||||
void TerrainRender::farclip(SquareStackNode2 *n, U32 flags)
|
||||
{
|
||||
}
|
||||
|
||||
void TerrainRender::render2()
|
||||
{
|
||||
glFrontFace(GL_CW);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Render2Point), mEmitPoints2);
|
||||
TextureHandle hazeTexture = gClientSceneGraph->getFogTexture();
|
||||
|
||||
F32 invLevel = 1 / F32(mSquareSize << 2);
|
||||
Point4F texGenS = Point4F(invLevel, 0, 0, 0);
|
||||
Point4F texGenT = Point4F(0, invLevel, 0, 0);
|
||||
glColor4f(1,1,1,1);
|
||||
|
||||
glClientActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
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, texGenS);
|
||||
glTexGenfv(GL_T, GL_OBJECT_PLANE, texGenT);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
invLevel = 1 / F32(mSquareSize << 8);
|
||||
texGenS = Point4F(invLevel, 0, 0, 0);
|
||||
texGenT = Point4F(0, invLevel, 0, 0);
|
||||
|
||||
glClientActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
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, texGenS);
|
||||
glTexGenfv(GL_T, GL_OBJECT_PLANE, texGenT);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
|
||||
glLockArraysEXT(0, mCurrPoint2);
|
||||
|
||||
//glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
//glTexCoordPointer(2, GL_FLOAT, sizeof(Render2Point), &mEmitPoints2->z);
|
||||
//glMatrixMode(GL_TEXTURE_MATRIX);
|
||||
|
||||
for(S32 i = 0; i < TerrainBlock::MaterialGroups; i++)
|
||||
{
|
||||
TextureHandle t = mCurrentBlock->mBaseMaterials[i];
|
||||
TextureHandle a = mCurrentBlock->mAlphaMaterials[i];
|
||||
|
||||
if(!bool(t))
|
||||
break;
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glBindTexture(GL_TEXTURE_2D, t.getGLName());
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glBindTexture(GL_TEXTURE_2D, a.getGLName());
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_ZERO);
|
||||
for(PrimitiveList *walk = baseList[i]; walk; walk = walk->next)
|
||||
for(S32 j = 0; j < walk->count; j++)
|
||||
glDrawElements(walk->primList[j][0], walk->primList[j][1], GL_UNSIGNED_SHORT, walk->primList[j] + 2);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
for(PrimitiveList *walk = blendList[i]; walk; walk = walk->next)
|
||||
for(S32 j = 0; j < walk->count; j++)
|
||||
glDrawElements(walk->primList[j][0], walk->primList[j][1], GL_UNSIGNED_SHORT, walk->primList[j] + 2);
|
||||
}
|
||||
glUnlockArraysEXT();
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glClientActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glActiveTextureARB(GL_TEXTURE1_ARB);
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
// last pass is the haze pass
|
||||
glClientActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glDisable(GL_TEXTURE_GEN_S);
|
||||
glDisable(GL_TEXTURE_GEN_T);
|
||||
glBindTexture(GL_TEXTURE_2D, hazeTexture.getGLName());
|
||||
|
||||
|
||||
static F32 texMatrix[16] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
// get the height range from the root of the block map
|
||||
GridSquare *sq = mCurrentBlock->findSquare(TerrainBlock::BlockShift, Point2I(0,0));
|
||||
|
||||
F32 heightOffset = fixedToFloat(sq->minHeight);
|
||||
F32 heightRange = fixedToFloat(sq->maxHeight) - heightOffset;
|
||||
texMatrix[4] = - 1 / mFarDistance;
|
||||
texMatrix[12] = 1;
|
||||
texMatrix[1] = 1 / heightRange;
|
||||
texMatrix[13] = -heightOffset / heightRange;
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadMatrixf(texMatrix);
|
||||
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Render2Point), &(mEmitPoints2[0].z));
|
||||
glLockArraysEXT(0, mCurrPoint2);
|
||||
|
||||
U16 *ar = gIndexArray2;
|
||||
while(ar != mIndexArray2)
|
||||
{
|
||||
glDrawElements(ar[0], ar[1], GL_UNSIGNED_SHORT, ar + 2);
|
||||
ar += ar[1] + 2;
|
||||
}
|
||||
glUnlockArraysEXT();
|
||||
|
||||
glLoadIdentity();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
//glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
static S32 getPower(S32 x)
|
||||
{
|
||||
// Returns 2^n (the highest bit).
|
||||
S32 i = 0;
|
||||
if (x)
|
||||
do
|
||||
i++;
|
||||
while (x >>= 1);
|
||||
return i;
|
||||
}
|
||||
|
||||
void TerrainRender::textureRecurse2(SquareStackNode2 *stack)
|
||||
{
|
||||
S32 curStackSize = 1;
|
||||
Point3F minPoint, maxPoint;
|
||||
F32 squareDistance;
|
||||
|
||||
while(curStackSize)
|
||||
{
|
||||
SquareStackNode2 *n = stack + curStackSize - 1;
|
||||
// see if it's visible
|
||||
Point2I pos = n->pos;
|
||||
S32 squareSz = mSquareSize << n->level;
|
||||
GridSquare *sq = mCurrentBlock->findSquare(n->level, pos);
|
||||
|
||||
minPoint.set(mSquareSize * pos.x + mBlockPos.x,
|
||||
mSquareSize * pos.y + mBlockPos.y,
|
||||
fixedToFloat(sq->minHeight));
|
||||
maxPoint.set(minPoint.x + (mSquareSize << n->level),
|
||||
minPoint.y + (mSquareSize << n->level),
|
||||
fixedToFloat(sq->maxHeight));
|
||||
|
||||
F32 zDiff;
|
||||
squareDistance = getSquareDistance(minPoint, maxPoint, &zDiff);
|
||||
|
||||
// holes only in the primary terrain block
|
||||
if (squareDistance >= mFarDistance ||
|
||||
((sq->flags & GridSquare::Empty) && mBlockPos.x == 0 && mBlockPos.y == 0))
|
||||
{
|
||||
curStackSize--;
|
||||
continue;
|
||||
}
|
||||
// first check the level - if its 3 or less, we have to just make a bitmap:
|
||||
// level 3 == 8x8 square - 8x8 * 16x16 == 128x128
|
||||
S32 mipLevel = 7;
|
||||
if(n->level > 6)
|
||||
goto norecalloc;
|
||||
if(n->level != mTextureMinSquareSize)
|
||||
{
|
||||
// get the mip level of the square and see if we're in range
|
||||
if(squareDistance > 0.001)
|
||||
{
|
||||
S32 size = S32(dglProjectRadius(squareDistance + (squareSz >> 1), squareSz));
|
||||
mipLevel = getPower(size * 0.75);
|
||||
//if(n->level >= 6)
|
||||
//{
|
||||
// if(mipLevel - n->level > 2)
|
||||
// goto norecalloc;
|
||||
//}
|
||||
//else
|
||||
if(mipLevel > 7) // too big for this square
|
||||
goto norecalloc;
|
||||
}
|
||||
else
|
||||
goto norecalloc;
|
||||
}
|
||||
|
||||
allocTerrTexture(n->pos, n->level, mipLevel, false, squareDistance);
|
||||
curStackSize--;
|
||||
continue;
|
||||
norecalloc:
|
||||
// split it up:
|
||||
S32 nextLevel = n->level - 1;
|
||||
for(S32 i = 0; i < 4; i++)
|
||||
n[i].level = nextLevel;
|
||||
|
||||
S32 squareHalfSize = 1 << nextLevel;
|
||||
|
||||
// push in reverse order of processing.
|
||||
n[3].pos = pos;
|
||||
n[2].pos.set(pos.x + squareHalfSize, pos.y);
|
||||
n[1].pos.set(pos.x, pos.y + squareHalfSize);
|
||||
n[0].pos.set(pos.x + squareHalfSize, pos.y + squareHalfSize);
|
||||
curStackSize += 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TerrainRender::processBlockStack(SquareStackNode2 *stack, S32 curStackSize)
|
||||
{
|
||||
Point3F minPoint, maxPoint;
|
||||
F32 squareDistance;
|
||||
mCurrPoint2 = 0;
|
||||
mIndexArray2 = gIndexArray2;
|
||||
mEmitPoints2 = gEmitPoints2;
|
||||
U32 i;
|
||||
|
||||
for(i = 0; i < TerrainBlock::MaterialGroups; i++)
|
||||
{
|
||||
blendList[i] = 0;
|
||||
baseList[i] = 0;
|
||||
}
|
||||
for(i = 0; i < curStackSize; i++)
|
||||
stack[i].texAllocated = false;
|
||||
|
||||
F32 worldToScreenScale = dglProjectRadius(1,1);
|
||||
F32 zeroFullMipDistance = (mSquareSize * worldToScreenScale) / (1 << 3) - (mSquareSize >> 1);
|
||||
F32 zeroSmallMipDistance = (mSquareSize * worldToScreenScale) / (1 << 6) - (mSquareSize >> 1);
|
||||
F32 zeroDetailDistance = (mSquareSize * worldToScreenScale) / (1 << 6) - (mSquareSize >> 1);
|
||||
|
||||
while(curStackSize)
|
||||
{
|
||||
SquareStackNode2 *n = stack + curStackSize - 1;
|
||||
// see if it's visible
|
||||
GridSquare *sq = mCurrentBlock->findSquare(n->level, n->pos.x, n->pos.y);
|
||||
|
||||
minPoint.set(mSquareSize * n->pos.x + mBlockPos.x,
|
||||
mSquareSize * n->pos.y + mBlockPos.y,
|
||||
fixedToFloat(sq->minHeight));
|
||||
maxPoint.set(minPoint.x + (mSquareSize << n->level),
|
||||
minPoint.y + (mSquareSize << n->level),
|
||||
fixedToFloat(sq->maxHeight));
|
||||
|
||||
// holes only in the primary terrain block
|
||||
if ((sq->flags & GridSquare::Empty) && mBlockPos.x == 0 && mBlockPos.y == 0)
|
||||
{
|
||||
curStackSize--;
|
||||
continue;
|
||||
}
|
||||
|
||||
F32 zDiff;
|
||||
S32 nextClipFlags = 0;
|
||||
squareDistance = getSquareDistance(minPoint, maxPoint, &zDiff);
|
||||
|
||||
if(n->clipFlags)
|
||||
{
|
||||
if(n->clipFlags & FarSphereMask)
|
||||
{
|
||||
if(squareDistance >= mFarDistance)
|
||||
{
|
||||
curStackSize--;
|
||||
continue;
|
||||
}
|
||||
|
||||
S32 squareSz = mSquareSize << n->level;
|
||||
if(squareDistance + maxPoint.z - minPoint.z + squareSz + squareSz > mFarDistance)
|
||||
nextClipFlags |= FarSphereMask;
|
||||
}
|
||||
nextClipFlags |= TestSquareVisibility(minPoint, maxPoint, n->clipFlags, mSquareSize);
|
||||
if(nextClipFlags == -1)
|
||||
{
|
||||
//if(!n->texAllocated)
|
||||
// textureRecurse(n);
|
||||
// trivially rejected, so pop it off the stack
|
||||
curStackSize--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(!n->texAllocated)
|
||||
{
|
||||
S32 squareSz = mSquareSize << n->level;
|
||||
// first check the level - if its 3 or less, we have to just make a bitmap:
|
||||
// level 3 == 8x8 square - 8x8 * 16x16 == 128x128
|
||||
if(n->level > 6)
|
||||
goto notexalloc;
|
||||
|
||||
S32 mipLevel = 7;
|
||||
if(n->level != mTextureMinSquareSize)
|
||||
{
|
||||
// get the mip level of the square and see if we're in range
|
||||
if(squareDistance > 0.001)
|
||||
{
|
||||
S32 size = S32(dglProjectRadius(squareDistance + (squareSz >> 1), squareSz));
|
||||
mipLevel = getPower(size * 0.75);
|
||||
if(mipLevel > 7) // too big for this square
|
||||
goto notexalloc;
|
||||
}
|
||||
else
|
||||
goto notexalloc;
|
||||
}
|
||||
allocTerrTexture(n->pos, n->level, mipLevel, true, squareDistance);
|
||||
n->texAllocated = true;
|
||||
}
|
||||
notexalloc:
|
||||
|
||||
if(n->lightMask)
|
||||
n->lightMask = TestSquareLights(sq, n->level, n->pos, n->lightMask);
|
||||
|
||||
if(n->level <= 3)
|
||||
{
|
||||
bool noHoles = !(sq->flags & GridSquare::HasEmpty);
|
||||
if(n->level == 3)
|
||||
{
|
||||
if(nextClipFlags == 0 && noHoles)
|
||||
{
|
||||
tesselate3(n);
|
||||
curStackSize--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!(nextClipFlags & FarSphereMask) && noHoles)
|
||||
{
|
||||
if(n->level == 2)
|
||||
tesselate2(n);
|
||||
else if(n->level == 1)
|
||||
tesselate1(n);
|
||||
else
|
||||
tesselate0(n, sq->flags);
|
||||
curStackSize--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(n->level == 0)
|
||||
{
|
||||
// it's gotta be far clipped...
|
||||
farclip(n, sq->flags);
|
||||
curStackSize--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Point2I pos = n->pos;
|
||||
// subdivide this square and throw it on the stack
|
||||
S32 nextLevel = n->level - 1;
|
||||
S32 squareHalfSize = 1 << nextLevel;
|
||||
|
||||
n->level = nextLevel;
|
||||
n->clipFlags = nextClipFlags;
|
||||
|
||||
for(S32 i = 1; i < 4; i++)
|
||||
{
|
||||
n[i].level = nextLevel;
|
||||
n[i].clipFlags = nextClipFlags;
|
||||
n[i].lightMask = n->lightMask;
|
||||
}
|
||||
// push in reverse order of processing.
|
||||
n[3].pos = pos;
|
||||
n[2].pos.set(pos.x + squareHalfSize, pos.y);
|
||||
n[1].pos.set(pos.x, pos.y + squareHalfSize);
|
||||
n[0].pos.set(pos.x + squareHalfSize, pos.y + squareHalfSize);
|
||||
curStackSize += 3;
|
||||
}
|
||||
}
|
||||
|
||||
724
terrain/waterBlock.cc
Normal file
724
terrain/waterBlock.cc
Normal file
|
|
@ -0,0 +1,724 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "terrain/waterBlock.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "sceneGraph/sceneGraph.h"
|
||||
#include "sceneGraph/sceneState.h"
|
||||
#include "Core/bitStream.h"
|
||||
#include "Math/mBox.h"
|
||||
#include "dgl/dgl.h"
|
||||
#include "Core/color.h"
|
||||
#include "terrain/terrData.h"
|
||||
#include "terrain/terrRender.h"
|
||||
#include "Math/mathIO.h"
|
||||
#include "sceneGraph/sgUtil.h"
|
||||
#include "audio/audioDataBlock.h"
|
||||
|
||||
//==============================================================================
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(WaterBlock);
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::mCameraSubmerged = false;
|
||||
U32 WaterBlock::mSubmergedType = 0;
|
||||
TextureHandle WaterBlock::mSubmergeTexture[WC_NUM_SUBMERGE_TEX];
|
||||
|
||||
//==============================================================================
|
||||
// I know this is a bit of a hack. I've done this in order to avoid a coupling
|
||||
// between the fluid and the rest of the system.
|
||||
//
|
||||
static SceneState* pSceneState = NULL;
|
||||
|
||||
static F32 FogFunction( F32 Distance, F32 DeltaZ )
|
||||
{
|
||||
return( pSceneState->getHazeAndFog( Distance, DeltaZ ) );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
WaterBlock::WaterBlock()
|
||||
{
|
||||
mNetFlags.set(Ghostable | ScopeAlways);
|
||||
mTypeMask = WaterObjectType;
|
||||
|
||||
mObjBox.min.set( 0, 0, 0 );
|
||||
mObjBox.max.set( 1, 1, 1 );
|
||||
|
||||
mLiquidType = eOceanWater;
|
||||
mDensity = 1;
|
||||
mViscosity = 15;
|
||||
mWaveMagnitude = 1.0f;
|
||||
mSurfaceTexture = TextureHandle();
|
||||
mSurfaceOpacity = 0.75f;
|
||||
mEnvMapTexture = TextureHandle();
|
||||
mEnvMapIntensity = 1.0f;
|
||||
mRemoveWetEdges = true;
|
||||
mAudioEnvironment = 0;
|
||||
|
||||
// lets be good little programmers and initialize our data!
|
||||
mSurfaceName = NULL;
|
||||
mEnvMapName = NULL;
|
||||
|
||||
dMemset( mSubmergeName, 0, sizeof( mSubmergeName ) );
|
||||
|
||||
mpTerrain = NULL;
|
||||
mSurfaceZ = 0.0f;
|
||||
|
||||
mFluid.SetFogFn( FogFunction );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
WaterBlock::~WaterBlock()
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::SnagTerrain( SceneObject* sceneObj, S32 key )
|
||||
{
|
||||
WaterBlock* pWater = (WaterBlock*)key;
|
||||
pWater->mpTerrain = dynamic_cast<TerrainBlock*>(sceneObj);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::UpdateFluidRegion( void )
|
||||
{
|
||||
MatrixF M;
|
||||
Point3F P;
|
||||
|
||||
P = mObjToWorld.getPosition();
|
||||
P.x += 1024.0f;
|
||||
P.y += 1024.0f;
|
||||
|
||||
mSurfaceZ = P.z + mObjScale.z;
|
||||
|
||||
mFluid.SetInfo( P.x, P.y,
|
||||
mObjScale.x, mObjScale.y,
|
||||
mSurfaceZ,
|
||||
mWaveMagnitude,
|
||||
mSurfaceOpacity,
|
||||
mEnvMapIntensity,
|
||||
mRemoveWetEdges );
|
||||
|
||||
P.x -= 1024.0f;
|
||||
P.y -= 1024.0f;
|
||||
|
||||
M.identity();
|
||||
M.setPosition( P );
|
||||
|
||||
Parent::setTransform( M );
|
||||
|
||||
resetWorldBox();
|
||||
|
||||
if( isServerObject() )
|
||||
setMaskBits(1);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::onAdd()
|
||||
{
|
||||
if( !isClientObject() )
|
||||
{
|
||||
// Make sure that the Fluid has had a chance to tweak the values.
|
||||
UpdateFluidRegion();
|
||||
}
|
||||
|
||||
if( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
if(!mRemoveWetEdges)
|
||||
{
|
||||
mObjBox.min.set(-1e4, -1e4, 0);
|
||||
mObjBox.max.set( 1e4, 1e4, 1);
|
||||
}
|
||||
|
||||
resetWorldBox();
|
||||
addToScene();
|
||||
|
||||
if( isClientObject() )
|
||||
{
|
||||
// load textures
|
||||
mSurfaceTexture = TextureHandle( mSurfaceName, MeshTexture );
|
||||
mEnvMapTexture = TextureHandle( mEnvMapName, MeshTexture );
|
||||
|
||||
for( int i=0; i<WC_NUM_SUBMERGE_TEX; i++ )
|
||||
{
|
||||
if( mSubmergeName[i] && mSubmergeName[i][0] )
|
||||
{
|
||||
mLocalSubmergeTexture[i] = TextureHandle( mSubmergeName[i], MeshTexture );
|
||||
mSubmergeTexture[i] = mLocalSubmergeTexture[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Register these textures with the Fluid.
|
||||
mFluid.SetTextures( mSurfaceTexture,
|
||||
mEnvMapTexture );
|
||||
}
|
||||
|
||||
return( true );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::onRemove()
|
||||
{
|
||||
|
||||
// clear static texture handles
|
||||
for( int i=0; i<WC_NUM_SUBMERGE_TEX; i++ )
|
||||
{
|
||||
mSubmergeTexture[i] = NULL;
|
||||
}
|
||||
|
||||
removeFromScene();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::onSceneAdd( SceneGraph* pGraph )
|
||||
{
|
||||
if( Parent::onSceneAdd(pGraph) )
|
||||
{
|
||||
// Attempt to get the terrain.
|
||||
if( (mpTerrain == NULL) && (mContainer != NULL) )
|
||||
{
|
||||
mContainer->findObjects( mWorldBox, (U32)TerrainObjectType, SnagTerrain, (S32)this );
|
||||
if( mpTerrain )
|
||||
mFluid.SetTerrainData( mpTerrain->heightMap );
|
||||
}
|
||||
|
||||
return( true );
|
||||
}
|
||||
return( false );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// The incoming matrix transforms the water into the WORLD. This includes any
|
||||
// offset in the terrain, so the translation can be negative. We need to get
|
||||
// the translation to be expressed in "terrain square" terms. The terrain
|
||||
// offset is always -1024,-1024.
|
||||
|
||||
void WaterBlock::setTransform( const MatrixF &mat )
|
||||
{
|
||||
mObjToWorld = mat;
|
||||
UpdateFluidRegion();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::setScale( const VectorF & scale )
|
||||
{
|
||||
mObjScale = scale;
|
||||
UpdateFluidRegion();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::prepRenderImage( SceneState* state,
|
||||
const U32 stateKey,
|
||||
const U32,
|
||||
const bool )
|
||||
{
|
||||
// Attempt to get the terrain.
|
||||
if( (mpTerrain == NULL) && (mContainer != NULL) )
|
||||
{
|
||||
mContainer->findObjects( mWorldBox, (U32)TerrainObjectType, SnagTerrain, (S32)this );
|
||||
if( mpTerrain )
|
||||
mFluid.SetTerrainData( mpTerrain->heightMap );
|
||||
}
|
||||
|
||||
|
||||
if (isLastState(state, stateKey))
|
||||
return false;
|
||||
setLastState(state, stateKey);
|
||||
|
||||
// This should be sufficient for most objects that don't manage zones, and
|
||||
// don't need to return a specialized RenderImage...
|
||||
if (state->isObjectRendered(this)) {
|
||||
SceneRenderImage* image = new SceneRenderImage;
|
||||
image->obj = this;
|
||||
image->isTranslucent = true;
|
||||
|
||||
image->sortType = SceneRenderImage::Plane;
|
||||
image->plane = PlaneF(0, 0, 1, -mSurfaceZ);
|
||||
image->poly[0] = Point3F(mObjBox.min.x, mObjBox.min.y, 1);
|
||||
image->poly[1] = Point3F(mObjBox.min.x, mObjBox.max.y, 1);
|
||||
image->poly[2] = Point3F(mObjBox.max.x, mObjBox.max.y, 1);
|
||||
image->poly[3] = Point3F(mObjBox.max.x, mObjBox.min.y, 1);
|
||||
for (U32 i = 0; i < 4; i++)
|
||||
{
|
||||
image->poly[i].convolve(mObjScale);
|
||||
getTransform().mulP(image->poly[i]);
|
||||
}
|
||||
|
||||
// Calc the area of this poly
|
||||
Point3F intermed;
|
||||
mCross(image->poly[2] - image->poly[0], image->poly[3] - image->poly[1], &intermed);
|
||||
image->polyArea = intermed.len() * 0.5;
|
||||
|
||||
state->insertRenderImage(image);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::renderObject( SceneState* state, SceneRenderImage* )
|
||||
{
|
||||
AssertFatal( dglIsInCanonicalState(),
|
||||
"Error, GL not in canonical state on entry" );
|
||||
|
||||
RectI viewport;
|
||||
Point3F Eye; // Camera in water space.
|
||||
bool CameraSubmergedFlag = false;
|
||||
|
||||
dglGetViewport ( &viewport );
|
||||
glMatrixMode ( GL_PROJECTION );
|
||||
glPushMatrix ();
|
||||
state->setupObjectProjection( this );
|
||||
|
||||
/****
|
||||
// Debug assist.
|
||||
// Render a wire outline around the base of the water block.
|
||||
if( 0 )
|
||||
{
|
||||
glMatrixMode ( GL_MODELVIEW );
|
||||
glPushMatrix ();
|
||||
dglMultMatrix ( &mObjToWorld );
|
||||
|
||||
F32 X0 = 0;
|
||||
F32 Y0 = 0;
|
||||
F32 X1 = mObjScale.x;
|
||||
F32 Y1 = mObjScale.y;
|
||||
F32 Z = 0;
|
||||
|
||||
glDisable ( GL_TEXTURE_2D );
|
||||
glDisable ( GL_DEPTH_TEST );
|
||||
glEnable ( GL_BLEND );
|
||||
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glPolygonMode ( GL_FRONT_AND_BACK, GL_LINE );
|
||||
glColor4f ( 0.6f, 0.6f, 0.0f, 0.5f );
|
||||
glBegin ( GL_QUADS );
|
||||
|
||||
glVertex3f ( X0, Y0, Z );
|
||||
glVertex3f ( X1, Y0, Z );
|
||||
glVertex3f ( X1, Y1, Z );
|
||||
glVertex3f ( X0, Y1, Z );
|
||||
|
||||
glEnd ();
|
||||
glEnable ( GL_DEPTH_TEST );
|
||||
glColor4f ( 0.8f, 0.8f, 0.8f, 0.8f );
|
||||
glBegin ( GL_QUADS );
|
||||
|
||||
glVertex3f ( X0, Y0, Z );
|
||||
glVertex3f ( X1, Y0, Z );
|
||||
glVertex3f ( X1, Y1, Z );
|
||||
glVertex3f ( X0, Y1, Z );
|
||||
|
||||
glEnd ();
|
||||
glPolygonMode ( GL_FRONT_AND_BACK, GL_FILL );
|
||||
|
||||
glPopMatrix ();
|
||||
glMatrixMode ( GL_MODELVIEW );
|
||||
}
|
||||
****/
|
||||
|
||||
// Handle the fluid.
|
||||
{
|
||||
// The water block lives in terrain space which is -1024,-1024.
|
||||
// To get into world space, we just add 1024,1024.
|
||||
// The fluid lives in world space.
|
||||
|
||||
Point3F W2Lv( 1024.0f, 1024.0f, 0.0f ); // World to Local vector
|
||||
Point3F L2Wv( -1024.0f, -1024.0f, 0.0f ); // Local to World vector
|
||||
MatrixF L2Wm; // Local to World matrix
|
||||
|
||||
L2Wm.identity();
|
||||
L2Wm.setPosition( L2Wv );
|
||||
|
||||
glMatrixMode ( GL_MODELVIEW );
|
||||
glPushMatrix ();
|
||||
dglMultMatrix ( &L2Wm );
|
||||
|
||||
|
||||
// We need the eye in water space.
|
||||
{
|
||||
Eye = state->getCameraPosition() + W2Lv;
|
||||
mFluid.SetEyePosition( Eye.x, Eye.y, Eye.z );
|
||||
}
|
||||
|
||||
// We need the frustrum in water space.
|
||||
{
|
||||
MatrixF L2Cm;
|
||||
dglGetModelview( &L2Cm );
|
||||
L2Cm.inverse();
|
||||
|
||||
Point3F Dummy;
|
||||
Dummy = L2Cm.getPosition();
|
||||
|
||||
F64 frustumParam[6];
|
||||
dglGetFrustum(&frustumParam[0], &frustumParam[1],
|
||||
&frustumParam[2], &frustumParam[3],
|
||||
&frustumParam[4], &frustumParam[5]);
|
||||
|
||||
sgComputeOSFrustumPlanes(frustumParam,
|
||||
L2Cm,
|
||||
Dummy,
|
||||
mClipPlane[1],
|
||||
mClipPlane[2],
|
||||
mClipPlane[3],
|
||||
mClipPlane[4],
|
||||
mClipPlane[5]);
|
||||
|
||||
// near plane is needed as well...
|
||||
PlaneF p(0, 1, 0, -frustumParam[4]);
|
||||
mTransformPlane(L2Cm, Point3F(1,1,1), p, &mClipPlane[0]);
|
||||
|
||||
// F64 left, right, bottom, top, near, far;
|
||||
// MatrixF L2Cm;
|
||||
|
||||
// dglGetFrustum( &left, &right, &bottom, &top, &near, &far );
|
||||
|
||||
// far = state->getVisibleDistance();
|
||||
|
||||
// Point3F Origin ( 0, 0, 0 );
|
||||
// Point3F FarOrigin ( 0, far, 0 );
|
||||
// Point3F UpperLeft ( left, near, top );
|
||||
// Point3F UpperRight ( right, near, top );
|
||||
// Point3F LowerLeft ( left, near, bottom );
|
||||
// Point3F LowerRight ( right, near, bottom );
|
||||
|
||||
// dglGetModelview( &L2Cm );
|
||||
// L2Cm.inverse();
|
||||
|
||||
// Point3F Dummy;
|
||||
// Dummy = L2Cm.getPosition();
|
||||
|
||||
// L2Cm.mulP( Origin );
|
||||
// L2Cm.mulP( FarOrigin );
|
||||
// L2Cm.mulP( UpperLeft );
|
||||
// L2Cm.mulP( UpperRight );
|
||||
// L2Cm.mulP( LowerLeft );
|
||||
// L2Cm.mulP( LowerRight );
|
||||
|
||||
// // Frustrum clip planes: 0=T 1=B 2=L 3=R 4=N 5=F
|
||||
|
||||
// mClipPlane[0].set( UpperLeft, Origin, UpperRight );
|
||||
// mClipPlane[1].set( LowerRight, Origin, LowerLeft );
|
||||
// mClipPlane[2].set( LowerLeft, Origin, UpperLeft );
|
||||
// mClipPlane[3].set( UpperRight, Origin, LowerRight );
|
||||
// mClipPlane[4].set( UpperRight, UpperLeft, LowerRight );
|
||||
|
||||
// // far plane is reverse of near plane vector
|
||||
// mClipPlane[5].x = -mClipPlane[4].x;
|
||||
// mClipPlane[5].y = -mClipPlane[4].y;
|
||||
// mClipPlane[5].z = -mClipPlane[4].z;
|
||||
// mClipPlane[5].d = -mClipPlane[4].d + far;
|
||||
|
||||
mFluid.SetFrustrumPlanes( (F32*)mClipPlane );
|
||||
}
|
||||
|
||||
// Fog stuff.
|
||||
{
|
||||
pSceneState = state;
|
||||
ColorF FogColor = state->getFogColor();
|
||||
mFluid.SetFogParameters( FogColor.red,
|
||||
FogColor.green,
|
||||
FogColor.blue,
|
||||
state->getVisibleDistance() );
|
||||
}
|
||||
|
||||
// And RENDER!
|
||||
{
|
||||
mFluid.Render( CameraSubmergedFlag );
|
||||
}
|
||||
|
||||
// Clean up.
|
||||
glPopMatrix ();
|
||||
glMatrixMode ( GL_MODELVIEW );
|
||||
}
|
||||
|
||||
//
|
||||
// And now the closing ceremonies...
|
||||
//
|
||||
glMatrixMode ( GL_PROJECTION );
|
||||
glPopMatrix ();
|
||||
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
|
||||
dglSetViewport ( viewport );
|
||||
|
||||
//
|
||||
// Oh yes. We have to set some state information for the scene...
|
||||
//
|
||||
|
||||
if( CameraSubmergedFlag )
|
||||
{
|
||||
mCameraSubmerged = true;
|
||||
mSubmergedType = mLiquidType;
|
||||
}
|
||||
|
||||
AssertFatal( dglIsInCanonicalState(),
|
||||
"Error, GL not in canonical state on exit" );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::inspectPostApply()
|
||||
{
|
||||
resetWorldBox();
|
||||
setMaskBits(1);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
static EnumTable::Enums gLiquidTypeEnums[] =
|
||||
{
|
||||
{ WaterBlock::eWater, "Water" },
|
||||
{ WaterBlock::eOceanWater, "OceanWater" },
|
||||
{ WaterBlock::eRiverWater, "RiverWater" },
|
||||
{ WaterBlock::eStagnantWater, "StagnantWater" },
|
||||
{ WaterBlock::eLava, "Lava" },
|
||||
{ WaterBlock::eHotLava, "HotLava" },
|
||||
{ WaterBlock::eCrustyLava, "CrustyLava" },
|
||||
{ WaterBlock::eQuicksand, "Quicksand" }
|
||||
};
|
||||
static EnumTable gLiquidTypeTable( 8, gLiquidTypeEnums );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void WaterBlock::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField( "liquidType", TypeEnum, Offset( mLiquidType, WaterBlock ), 1, &gLiquidTypeTable );
|
||||
addField( "density", TypeF32, Offset( mDensity, WaterBlock ) );
|
||||
addField( "viscosity", TypeF32, Offset( mViscosity, WaterBlock ) );
|
||||
addField( "waveMagnitude", TypeF32, Offset( mWaveMagnitude, WaterBlock ) );
|
||||
addField( "surfaceTexture", TypeString, Offset( mSurfaceName, WaterBlock ) );
|
||||
addField( "surfaceOpacity", TypeF32, Offset( mSurfaceOpacity, WaterBlock ) );
|
||||
addField( "envMapTexture", TypeString, Offset( mEnvMapName, WaterBlock ) );
|
||||
addField( "envMapIntensity", TypeF32, Offset( mEnvMapIntensity, WaterBlock ) );
|
||||
addField( "submergeTexture", TypeString, Offset( mSubmergeName, WaterBlock ), WC_NUM_SUBMERGE_TEX );
|
||||
addField( "removeWetEdges", TypeBool, Offset( mRemoveWetEdges, WaterBlock ) );
|
||||
addField( "audioEnvironment", TypeAudioEnvironmentPtr, Offset( mAudioEnvironment, WaterBlock ) );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::cToggleWireFrame( SimObject* obj, S32, const char** )
|
||||
{
|
||||
WaterBlock* pWaterBlock = static_cast<WaterBlock*>(obj);
|
||||
if( pWaterBlock )
|
||||
{
|
||||
pWaterBlock->mFluid.m_ShowWire = !(pWaterBlock->mFluid.m_ShowWire);
|
||||
if( pWaterBlock->mFluid.m_ShowWire )
|
||||
Con::printf( "WaterBlock wire frame ENABLED" );
|
||||
else
|
||||
Con::printf( "WaterBlock wire frame DISABLED" );
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::consoleInit()
|
||||
{
|
||||
Con::addCommand( "WaterBlock", "toggleWireFrame", cToggleWireFrame, "waterBlock.toggleWireFrame()", 2, 2 );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
U32 WaterBlock::packUpdate( NetConnection* c, U32 mask, BitStream* stream )
|
||||
{
|
||||
U32 retMask = Parent::packUpdate( c, mask, stream );
|
||||
|
||||
// No masking in here now.
|
||||
// There's not too much data, and it doesn't change during normal game play.
|
||||
|
||||
stream->writeAffineTransform( mObjToWorld );
|
||||
mathWrite( *stream, mObjScale );
|
||||
|
||||
stream->writeString( mSurfaceName );
|
||||
stream->writeString( mEnvMapName );
|
||||
|
||||
for( int i=0; i<WC_NUM_SUBMERGE_TEX; i++ )
|
||||
{
|
||||
stream->writeString( mSubmergeName[i] );
|
||||
}
|
||||
|
||||
stream->write( (S32)mLiquidType );
|
||||
stream->write( mDensity );
|
||||
stream->write( mViscosity );
|
||||
stream->write( mWaveMagnitude );
|
||||
stream->write( mSurfaceOpacity );
|
||||
stream->write( mEnvMapIntensity );
|
||||
stream->write( mRemoveWetEdges );
|
||||
|
||||
// audio environment:
|
||||
if(stream->writeFlag(mAudioEnvironment))
|
||||
stream->writeRangedU32(mAudioEnvironment->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
|
||||
return( retMask );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
void WaterBlock::unpackUpdate( NetConnection* c, BitStream* stream )
|
||||
{
|
||||
Parent::unpackUpdate( c, stream );
|
||||
|
||||
U32 LiquidType;
|
||||
|
||||
// No masking in here now.
|
||||
// There's not too much data, and it doesn't change during normal game play.
|
||||
|
||||
stream->readAffineTransform( &mObjToWorld );
|
||||
mathRead( *stream, &mObjScale );
|
||||
|
||||
mSurfaceName = stream->readSTString();
|
||||
mEnvMapName = stream->readSTString();
|
||||
|
||||
for( int i=0; i<WC_NUM_SUBMERGE_TEX; i++ )
|
||||
{
|
||||
mSubmergeName[i] = stream->readSTString();
|
||||
}
|
||||
|
||||
|
||||
stream->read( &LiquidType );
|
||||
stream->read( &mDensity );
|
||||
stream->read( &mViscosity );
|
||||
stream->read( &mWaveMagnitude );
|
||||
stream->read( &mSurfaceOpacity );
|
||||
stream->read( &mEnvMapIntensity );
|
||||
stream->read( &mRemoveWetEdges );
|
||||
|
||||
// audio environment:
|
||||
if(stream->readFlag())
|
||||
{
|
||||
U32 profileId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
mAudioEnvironment = dynamic_cast<AudioEnvironment*>(Sim::findObject(profileId));
|
||||
}
|
||||
else
|
||||
mAudioEnvironment = 0;
|
||||
|
||||
mLiquidType = (EWaterType)LiquidType;
|
||||
|
||||
UpdateFluidRegion();
|
||||
|
||||
if( !isProperlyAdded() )
|
||||
return;
|
||||
|
||||
resetWorldBox();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// This method can take a point in world space, or water block space. The default
|
||||
// assumes pos is in world space, and therefore must transform it to waterblock
|
||||
// space.
|
||||
|
||||
bool WaterBlock::isPointSubmerged(const Point3F &pos, bool worldSpace) const
|
||||
{
|
||||
return( isPointSubmergedSimple( pos, worldSpace ) );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::isPointSubmergedSimple(const Point3F &pos, bool worldSpace) const
|
||||
{
|
||||
Point3F Pos = pos;
|
||||
|
||||
if( Pos.z > mSurfaceZ )
|
||||
return( false );
|
||||
|
||||
if( worldSpace )
|
||||
{
|
||||
Pos.x += 1024.0f;
|
||||
Pos.y += 1024.0f;
|
||||
}
|
||||
|
||||
return( mFluid.IsFluidAtXY( Pos.x, Pos.y ) );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::castRay( const Point3F& start, const Point3F& end, RayInfo* info )
|
||||
{
|
||||
F32 t, x, y, X, Y;
|
||||
Point3F Pos;
|
||||
|
||||
//
|
||||
// Looks like the incoming points are in parametric object space. Great.
|
||||
//
|
||||
|
||||
// The water surface is 1.0. Bail if the ray does not cross the surface.
|
||||
|
||||
if( (start.z > 1.0f) && (end.z > 1.0f) ) return( false );
|
||||
if( (start.z < 1.0f) && (end.z < 1.0f) ) return( false );
|
||||
|
||||
// The ray crosses the surface plane. Find out where.
|
||||
|
||||
t = (start.z - 1.0f) / (start.z - end.z);
|
||||
x = start.x + (end.x - start.x) * t;
|
||||
y = start.y + (end.y - start.y) * t;
|
||||
|
||||
Pos = mObjToWorld.getPosition();
|
||||
|
||||
X = (x * mObjScale.x) + Pos.x + 1024.0f;
|
||||
Y = (y * mObjScale.y) + Pos.y + 1024.0f;
|
||||
|
||||
if( mFluid.IsFluidAtXY( X, Y ) )
|
||||
{
|
||||
info->t = t;
|
||||
info->point.x = x;
|
||||
info->point.y = y;
|
||||
info->point.z = 1.0f;
|
||||
info->normal.x = 0.0f;
|
||||
info->normal.y = 0.0f;
|
||||
info->normal.z = 1.0f;
|
||||
info->object = this;
|
||||
info->material = 0;
|
||||
return( true );
|
||||
}
|
||||
|
||||
// Hmm. Guess we missed!
|
||||
return( false );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::isWater( U32 liquidType )
|
||||
{
|
||||
EWaterType wType = EWaterType( liquidType );
|
||||
return( wType == eWater ||
|
||||
wType == eOceanWater ||
|
||||
wType == eRiverWater ||
|
||||
wType == eStagnantWater );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::isLava( U32 liquidType )
|
||||
{
|
||||
EWaterType wType = EWaterType( liquidType );
|
||||
return( wType == eLava ||
|
||||
wType == eHotLava ||
|
||||
wType == eCrustyLava );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
bool WaterBlock::isQuicksand( U32 liquidType )
|
||||
{
|
||||
EWaterType wType = EWaterType( liquidType );
|
||||
return( wType == eQuicksand );
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
138
terrain/waterBlock.h
Normal file
138
terrain/waterBlock.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// V12 Engine
|
||||
//
|
||||
// Copyright (c) 2001 GarageGames.Com
|
||||
// Portions Copyright (c) 2001 by Sierra Online, 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,
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
fluid mFluid;
|
||||
|
||||
TextureHandle mSurfaceTexture;
|
||||
TextureHandle mEnvMapTexture;
|
||||
PlaneF mClipPlane[6]; // Frustrum clip planes: 0=T 1=B 2=L 3=R 4=N 5=F
|
||||
TerrainBlock* mpTerrain; // Terrain block
|
||||
F32 mSurfaceZ;
|
||||
|
||||
// Fields exposed to the editor.
|
||||
EWaterType mLiquidType; // Water? Lava? What?
|
||||
F32 mDensity;
|
||||
F32 mViscosity;
|
||||
F32 mWaveMagnitude;
|
||||
StringTableEntry mSurfaceName;
|
||||
F32 mSurfaceOpacity;
|
||||
StringTableEntry mEnvMapName;
|
||||
F32 mEnvMapIntensity;
|
||||
StringTableEntry mSubmergeName[WC_NUM_SUBMERGE_TEX];
|
||||
bool mRemoveWetEdges;
|
||||
AudioEnvironment * mAudioEnvironment;
|
||||
|
||||
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* pGraph );
|
||||
void setTransform ( const MatrixF& mat );
|
||||
void setScale ( const VectorF& scale );
|
||||
bool prepRenderImage ( SceneState*, const U32, const U32, const bool );
|
||||
void renderObject ( SceneState*, SceneRenderImage* );
|
||||
void inspectPostApply ( void );
|
||||
F32 getSurfaceHeight ( void ) { return mSurfaceZ; }
|
||||
|
||||
void UpdateFluidRegion ( void );
|
||||
static void SnagTerrain ( SceneObject* sceneObj, S32 key );
|
||||
|
||||
static void cToggleWireFrame( SimObject*, S32, const char** );
|
||||
|
||||
DECLARE_CONOBJECT(WaterBlock);
|
||||
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
|
||||
// bool setLiquidType(EWaterFlag liquidType);
|
||||
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*, U32 mask, BitStream *stream );
|
||||
void unpackUpdate( NetConnection*, 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 );
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue