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