mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-16 08:42:23 +00:00
- more reorgianization
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@114 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
2ac9503854
commit
44e9a03c17
4
Makefile
4
Makefile
@ -33,8 +33,8 @@ mygui_cpp=mygui console
|
|||||||
|
|
||||||
# Ditto for the landscape engine, in terrain/cpp_X.cpp
|
# Ditto for the landscape engine, in terrain/cpp_X.cpp
|
||||||
terrain_cpp=baseland esm framelistener generator index landdata\
|
terrain_cpp=baseland esm framelistener generator index landdata\
|
||||||
materialgen mwheightmap palette point2\
|
materialgen heightmap palette point2\
|
||||||
quad quaddata terraincls terrain terrainmesh
|
quad quaddata terrain terrainmesh terrainmesh2 heightmap2
|
||||||
|
|
||||||
# FFmpeg files, in the form sound/cpp_X.cpp.
|
# FFmpeg files, in the form sound/cpp_X.cpp.
|
||||||
avcodec_cpp=avcodec
|
avcodec_cpp=avcodec
|
||||||
|
@ -6,7 +6,7 @@ protected:
|
|||||||
*/
|
*/
|
||||||
bool frameEnded(const FrameEvent& evt)
|
bool frameEnded(const FrameEvent& evt)
|
||||||
{
|
{
|
||||||
g_Terrain->update(evt.timeSinceLastFrame);
|
g_heightMap->update(evt.timeSinceLastFrame);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,19 +16,20 @@ public:
|
|||||||
// Add the frame listener
|
// Add the frame listener
|
||||||
mRoot->addFrameListener(this);
|
mRoot->addFrameListener(this);
|
||||||
|
|
||||||
//our derived heightmap
|
// Create a root scene node first
|
||||||
g_heightMap = new MWHeightmap();
|
Ogre::SceneNode *node = mSceneMgr->getRootSceneNode()
|
||||||
|
->createChildSceneNode("TERRAIN_ROOT");
|
||||||
|
|
||||||
|
// The main terrain object
|
||||||
|
g_heightMap = new HeightMap(node);
|
||||||
g_heightMap->load(TERRAIN_OUTPUT);
|
g_heightMap->load(TERRAIN_OUTPUT);
|
||||||
|
|
||||||
//setup terrain
|
|
||||||
g_Terrain = new Terrain(mSceneMgr->getRootSceneNode()->createChildSceneNode("TERRAIN_ROOT")); //root scene node
|
|
||||||
|
|
||||||
//fix settings
|
//fix settings
|
||||||
g_Terrain->setMorphingEnabled(false);
|
g_heightMap->setMorphingEnabled(false);
|
||||||
g_Terrain->setTextureFadingEnabled(false);
|
g_heightMap->setTextureFadingEnabled(false);
|
||||||
|
|
||||||
//create the quad node
|
//create the quad node
|
||||||
g_Terrain->create();
|
g_heightMap->create();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* KILLME
|
/* KILLME
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
/**
|
class HeightMap
|
||||||
* @brief the class that deals with loading quads from the disk @todo a
|
|
||||||
* major improvment would be to store the data as a quad tree. It might
|
|
||||||
* improve lookup times. Then again. Might not
|
|
||||||
*/
|
|
||||||
class MWHeightmap
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
HeightMap(Ogre::SceneNode* r);
|
||||||
|
|
||||||
|
~HeightMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* loads the quad data from the disk
|
* loads the quad data from the disk
|
||||||
*/
|
*/
|
||||||
@ -55,12 +54,41 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void create();
|
||||||
|
|
||||||
|
inline Ogre::SceneNode* getTerrainSceneNode(){return mTerrainSceneNode;}
|
||||||
|
|
||||||
|
void update(Ogre::Real t);
|
||||||
|
|
||||||
|
inline Ogre::Real getMorphSpeed(){return 1.0f;}
|
||||||
|
inline Ogre::Real getTextureFadeSpeed(){ return 2.0f;}
|
||||||
|
inline void setMorphingEnabled(bool enabled){
|
||||||
|
mMorphingEnabled = enabled;
|
||||||
|
}
|
||||||
|
inline bool isMorphingEnabled() const{
|
||||||
|
return mMorphingEnabled;
|
||||||
|
}
|
||||||
|
inline void setTextureFadingEnabled(bool enabled){
|
||||||
|
if ( enabled && !mMorphingEnabled )
|
||||||
|
OGRE_EXCEPT(Ogre::Exception::ERR_NOT_IMPLEMENTED, "Cannot have fading but not morphing active", "Terrain::setTextureFadingEnabled");
|
||||||
|
mTextureFadingEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isTextureFadingEnabled() const{
|
||||||
|
return mTextureFadingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ogre::SceneNode* mTerrainSceneNode;
|
||||||
|
Quad* mQuadRoot;
|
||||||
|
bool mMorphingEnabled;
|
||||||
|
bool mTextureFadingEnabled;
|
||||||
|
|
||||||
|
BaseLand mBaseLand;
|
||||||
|
|
||||||
///ifs for the data file. Opned on load
|
///ifs for the data file. Opned on load
|
||||||
std::ifstream mDataIFS;
|
std::ifstream mDataIFS;
|
||||||
///holds the offsets of the quads
|
///holds the offsets of the quads
|
||||||
Index mIndex;
|
Index mIndex;
|
||||||
TexturePalette mPalette;
|
TexturePalette mPalette;
|
||||||
|
|
||||||
};
|
};
|
24
terrain/cpp_heightmap2.cpp
Normal file
24
terrain/cpp_heightmap2.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
HeightMap::HeightMap(Ogre::SceneNode* r)
|
||||||
|
: mTerrainSceneNode(r),
|
||||||
|
mQuadRoot(0),
|
||||||
|
mMorphingEnabled(true),
|
||||||
|
mTextureFadingEnabled(true),
|
||||||
|
mBaseLand(r)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
HeightMap::~HeightMap(){
|
||||||
|
delete mQuadRoot;
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void HeightMap::create(){
|
||||||
|
mQuadRoot = new Quad(Quad::QL_ROOT, 0);
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void HeightMap::update(Ogre::Real t){
|
||||||
|
assert(mQuadRoot);
|
||||||
|
mQuadRoot->update(t);
|
||||||
|
mBaseLand.update();
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
class Quad
|
class Quad
|
||||||
{
|
{
|
||||||
enum SplitState { SS_NONE, SS_SPLIT, SS_UNSPLIT };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* when each quad is split, the children can be one of 4 places,
|
* when each quad is split, the children can be one of 4 places,
|
||||||
@ -226,11 +225,11 @@ public:
|
|||||||
const Ogre::Vector3 pos(qx - mSideLength/2,
|
const Ogre::Vector3 pos(qx - mSideLength/2,
|
||||||
0,qy - mSideLength/2);
|
0,qy - mSideLength/2);
|
||||||
|
|
||||||
mSceneNode = g_Terrain->getTerrainSceneNode()->createChildSceneNode(pos);
|
mSceneNode = g_heightMap->getTerrainSceneNode()->createChildSceneNode(pos);
|
||||||
|
|
||||||
// This was in create()
|
// This was in create()
|
||||||
|
|
||||||
if ( mDepth == g_Terrain->getMaxDepth() )
|
if ( mDepth == g_heightMap->getMaxDepth() )
|
||||||
for ( int y = 0; y < 4; ++y )
|
for ( int y = 0; y < 4; ++y )
|
||||||
for ( int x = 0; x < 4; ++x )
|
for ( int x = 0; x < 4; ++x )
|
||||||
{
|
{
|
||||||
@ -265,7 +264,7 @@ public:
|
|||||||
mSceneNode->removeAndDestroyAllChildren();
|
mSceneNode->removeAndDestroyAllChildren();
|
||||||
mSceneMgr->destroySceneNode(mSceneNode);
|
mSceneMgr->destroySceneNode(mSceneNode);
|
||||||
|
|
||||||
g_Terrain->getTerrainSceneNode()->detachAllObjects();
|
g_heightMap->getTerrainSceneNode()->detachAllObjects();
|
||||||
|
|
||||||
delete mQuadData;
|
delete mQuadData;
|
||||||
mQuadData = NULL;
|
mQuadData = NULL;
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
* a set of verts Normals and indicies to allow us to pass optimized
|
* a set of verts Normals and indicies to allow us to pass optimized
|
||||||
* meshes
|
* meshes
|
||||||
*/
|
*/
|
||||||
|
enum SplitState { SS_NONE, SS_SPLIT, SS_UNSPLIT };
|
||||||
|
|
||||||
class QuadData
|
class QuadData
|
||||||
{
|
{
|
||||||
typedef std::list<Ogre::ResourcePtr> ResourceList;
|
typedef std::list<Ogre::ResourcePtr> ResourceList;
|
||||||
|
@ -54,13 +54,11 @@ const float UNSPLIT_FACTOR = 2.0;
|
|||||||
|
|
||||||
class Quad;
|
class Quad;
|
||||||
class QuadData;
|
class QuadData;
|
||||||
class Terrain;
|
|
||||||
class MaterialGenerator;
|
class MaterialGenerator;
|
||||||
class MWHeightmap;
|
class HeightMap;
|
||||||
|
|
||||||
MWHeightmap *g_heightMap;
|
HeightMap *g_heightMap;
|
||||||
MaterialGenerator *g_materialGen;
|
MaterialGenerator *g_materialGen;
|
||||||
Terrain *g_Terrain;
|
|
||||||
|
|
||||||
#undef TRACE
|
#undef TRACE
|
||||||
#define TRACE(x)
|
#define TRACE(x)
|
||||||
@ -91,17 +89,14 @@ Terrain *g_Terrain;
|
|||||||
|
|
||||||
// For rendering
|
// For rendering
|
||||||
#include "cpp_baseland.cpp"
|
#include "cpp_baseland.cpp"
|
||||||
#include "cpp_mwheightmap.cpp"
|
|
||||||
|
|
||||||
// These depend on each other, so our usual hackery won't work. We
|
// These depend on each other, so our usual hackery won't work. We
|
||||||
// need the header files first.
|
// need the header files first.
|
||||||
#include "cpp_terrainmesh.h"
|
#include "cpp_heightmap.cpp"
|
||||||
#include "cpp_terraincls.h"
|
|
||||||
|
|
||||||
#include "cpp_quad.cpp"
|
|
||||||
|
|
||||||
#include "cpp_terraincls.cpp"
|
|
||||||
#include "cpp_terrainmesh.cpp"
|
#include "cpp_terrainmesh.cpp"
|
||||||
|
#include "cpp_quad.cpp"
|
||||||
|
#include "cpp_heightmap2.cpp"
|
||||||
|
#include "cpp_terrainmesh2.cpp"
|
||||||
|
|
||||||
#include "cpp_framelistener.cpp"
|
#include "cpp_framelistener.cpp"
|
||||||
|
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
Terrain::Terrain(Ogre::SceneNode* r)
|
|
||||||
: mTerrainSceneNode(r),
|
|
||||||
mQuadRoot(0),
|
|
||||||
mMorphingEnabled(true),
|
|
||||||
mTextureFadingEnabled(true),
|
|
||||||
mBaseLand(r)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
Terrain::~Terrain(){
|
|
||||||
delete mQuadRoot;
|
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
void Terrain::create(){
|
|
||||||
mQuadRoot = new Quad(Quad::QL_ROOT, 0);
|
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
void Terrain::update(Ogre::Real t){
|
|
||||||
assert(mQuadRoot);
|
|
||||||
mQuadRoot->update(t);
|
|
||||||
mBaseLand.update();
|
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
int Terrain::getMaxDepth(){
|
|
||||||
return g_heightMap->getMaxDepth();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
//----------------------------------------------
|
|
||||||
void Terrain::reload(){
|
|
||||||
delete mQuadRoot;
|
|
||||||
mQuadRoot = new Quad(Quad::QL_ROOT, 0);
|
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
*/
|
|
@ -1,145 +0,0 @@
|
|||||||
class Terrain
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief inits vars and creates quad tree
|
|
||||||
* @param d the heightmap that contains the data
|
|
||||||
* @param s the current scne manager
|
|
||||||
* @param r the root scene node that all terrain nodes are barsed off
|
|
||||||
* @param c the camera that the poistion data is taken from
|
|
||||||
*
|
|
||||||
* The terrain is create in the constructor.
|
|
||||||
* @todo change quad root creation to create/destroy funcs?
|
|
||||||
*/
|
|
||||||
explicit Terrain(Ogre::SceneNode* r);
|
|
||||||
/**
|
|
||||||
* @brief deletes the quad tree
|
|
||||||
*/
|
|
||||||
~Terrain();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief creates the quad tree
|
|
||||||
* @remarks This must be called before any call to upate(). We cannot call it from the constructor as options
|
|
||||||
* may not have been set yet
|
|
||||||
*/
|
|
||||||
void create();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief recreates the quad tree by destroying everything and starting again.
|
|
||||||
* @remarks this is very slow, as it drops all created alpha maps and meshes.
|
|
||||||
* @todo check this works
|
|
||||||
*/
|
|
||||||
//void reload();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief sets the scene node that all of the terrain nodes are based off
|
|
||||||
* @param r the scene node to use for terrain
|
|
||||||
*/
|
|
||||||
inline void setTerrainSceneNode(Ogre::SceneNode* r){ mTerrainSceneNode = r; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the scene node that should be used as the root of the terrain
|
|
||||||
*
|
|
||||||
* This is mainly used by the quad tree
|
|
||||||
*/
|
|
||||||
inline Ogre::SceneNode* getTerrainSceneNode(){return mTerrainSceneNode;}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief updates the quad tree, splittig and unsplitting where needed.
|
|
||||||
*
|
|
||||||
* There is no requirement for this to be called every frame
|
|
||||||
*/
|
|
||||||
void update(Ogre::Real t);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief handles the actions to take on the creation of a terrain mesh
|
|
||||||
* @param qd the quad data. It is valid until the same variable is passed to _quadDestroyed
|
|
||||||
void _quadCreated(QuadData* qd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The quad as defined by the quad data qd has been destroyed
|
|
||||||
* @param qd the quad that has been destroyed. This is only valid for this function. Is is deleted just after
|
|
||||||
void _quadDestroyed(QuadData* qd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief sets the function to be used in the callback when a quad is created
|
|
||||||
* @param f the function to use. Set to null to disable callbacks
|
|
||||||
|
|
||||||
inline void setQuadCreateFunction(void (*f)(QuadData*)){
|
|
||||||
mQuadCreateFunction = f;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief sets the function to be used in the callback when a quad is destroyed
|
|
||||||
* @param f the function to use. Set to null to disable callbacks
|
|
||||||
inline void setQuadDestroyFunction(void (*f)(QuadData*)){
|
|
||||||
mQuadDestroyFunction = f;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief time in seconds to morph to full detail after an unsplit.
|
|
||||||
*/
|
|
||||||
inline Ogre::Real getMorphSpeed(){return 1.0f;}
|
|
||||||
/**
|
|
||||||
* @brief the time in seconds it takes for the texture to fade to the higher detail
|
|
||||||
*/
|
|
||||||
inline Ogre::Real getTextureFadeSpeed(){ return 2.0f;}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the maximum depth of the quad tree
|
|
||||||
* @remarks this is used by the terrain renderable for adding morhping to textures. It doesn't want to happen
|
|
||||||
* on the lowest detail
|
|
||||||
*/
|
|
||||||
int getMaxDepth();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief disables/enables morphing
|
|
||||||
* @remarks This will not happen instantly unless reload() is called
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline void setMorphingEnabled(bool enabled){
|
|
||||||
mMorphingEnabled = enabled;
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @return true if morphing is enabled
|
|
||||||
*/
|
|
||||||
inline bool isMorhpingEnabled() const{
|
|
||||||
return mMorphingEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief disables/enables texture fading.
|
|
||||||
* @remarks This will not happen instantly unless reload() is called. Morphing is required atm
|
|
||||||
*/
|
|
||||||
inline void setTextureFadingEnabled(bool enabled){
|
|
||||||
if ( enabled && !mMorphingEnabled )
|
|
||||||
OGRE_EXCEPT(Ogre::Exception::ERR_NOT_IMPLEMENTED, "Cannot have fading but not morphing active", "Terrain::setTextureFadingEnabled");
|
|
||||||
mTextureFadingEnabled = enabled;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @return true if texture fading is enabled
|
|
||||||
*/
|
|
||||||
inline bool isTextureFadingEnabled() const{
|
|
||||||
return mTextureFadingEnabled;
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
/// the scenenode that every other node is decended from. This
|
|
||||||
/// should be surplied by the user
|
|
||||||
Ogre::SceneNode* mTerrainSceneNode;
|
|
||||||
|
|
||||||
///the root node for all the quads.
|
|
||||||
Quad* mQuadRoot;
|
|
||||||
|
|
||||||
/*
|
|
||||||
///quad callback function
|
|
||||||
void (*mQuadCreateFunction)(QuadData*);
|
|
||||||
///quad callback function
|
|
||||||
void (*mQuadDestroyFunction)(QuadData*);
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool mMorphingEnabled;
|
|
||||||
bool mTextureFadingEnabled;
|
|
||||||
|
|
||||||
BaseLand mBaseLand;
|
|
||||||
};
|
|
@ -1,495 +1,343 @@
|
|||||||
TerrainMesh::TerrainMesh(QuadData* qd, float segSize, float startX, float startY,
|
/**
|
||||||
const Ogre::Vector3 &pos,
|
* @brief Terrain for one cell. Handles building, destroying and LOD morphing
|
||||||
int width, int depth, bool skirts,
|
*/
|
||||||
Ogre::SceneNode *parent)
|
#define QSDEBUG
|
||||||
: Ogre::Renderable(),
|
class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject
|
||||||
Ogre::MovableObject(),
|
|
||||||
mWidth(width),
|
|
||||||
mUseSkirts(skirts),
|
|
||||||
mBuilt(false),
|
|
||||||
mDepth(depth),
|
|
||||||
mVertexes(0),
|
|
||||||
mIndices(0),
|
|
||||||
mLODMorphFactor(0),
|
|
||||||
mTextureFadeFactor(0),
|
|
||||||
mMin(30000),
|
|
||||||
mMax(-30000),
|
|
||||||
mExtraMorphAmount(0),
|
|
||||||
mHasFadePass(false),
|
|
||||||
mQuadData(qd),
|
|
||||||
mSegmentSize(segSize),
|
|
||||||
mX(startX),
|
|
||||||
mY(startY)
|
|
||||||
{
|
{
|
||||||
// From QuadSegment()
|
public:
|
||||||
assert(qd);
|
|
||||||
assert(segSize>0&&segSize<=1);
|
|
||||||
assert(mY>=0&&mY<=1);
|
|
||||||
assert(mX>=0&&mY<=1);
|
|
||||||
|
|
||||||
|
TerrainMesh(QuadData* qd, float segSize, float startX, float startY,
|
||||||
|
const Ogre::Vector3 &pos,
|
||||||
|
int width, int depth, bool skirts,
|
||||||
|
Ogre::SceneNode *parent);
|
||||||
|
|
||||||
|
~TerrainMesh()
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
|
||||||
|
assert(node);
|
||||||
|
|
||||||
|
node->detachAllObjects();
|
||||||
|
node->getCreator()->destroySceneNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be called manually and can be called from the destuctor. This
|
||||||
|
* destroyes the mesh
|
||||||
|
*/
|
||||||
|
// FIXME: We don't need this as a separate function.
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if it needs to be split or unsplit and deals with
|
||||||
|
* the morph factor. time seconds since last frame
|
||||||
|
*/
|
||||||
|
void update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo Needs to work out what this does (if it does what it is meant to)
|
||||||
|
*/
|
||||||
|
void visitRenderables(Renderable::Visitor* visitor,
|
||||||
|
bool debugRenderables = false) {
|
||||||
|
visitor->visit(this, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const Ogre::MaterialPtr& getMaterial( void ) const {
|
||||||
|
return mMaterial;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void getRenderOperation( Ogre::RenderOperation& op ) {
|
||||||
|
op.useIndexes = true;
|
||||||
|
op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
|
||||||
|
op.vertexData = mVertexes;
|
||||||
|
op.indexData = mIndices;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void getWorldTransforms( Ogre::Matrix4* xform ) const {
|
||||||
|
*xform = mParentNode->_getFullTransform();
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
const Ogre::Quaternion& getWorldOrientation(void) const {
|
||||||
|
return mParentNode->_getDerivedOrientation();
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
const Ogre::Vector3& getWorldPosition(void) const {
|
||||||
|
return mParentNode->_getDerivedPosition();
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Ogre::Real getSquaredViewDepth(const Ogre::Camera *cam) const {
|
||||||
|
Ogre::Vector3 diff = mCenter - cam->getDerivedPosition();
|
||||||
|
// Use squared length to avoid square root
|
||||||
|
return diff.squaredLength();
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
const Ogre::LightList& getLights(void) const {
|
||||||
|
if (mLightListDirty) {
|
||||||
|
getParentSceneNode()->getCreator()->_populateLightList(
|
||||||
|
mCenter, this->getBoundingRadius(), mLightList);
|
||||||
|
mLightListDirty = false;
|
||||||
|
}
|
||||||
|
return mLightList;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
virtual const Ogre::String& getMovableType( void ) const {
|
||||||
|
static Ogre::String t = "MW_TERRAIN";
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
void _updateRenderQueue( Ogre::RenderQueue* queue ) {
|
||||||
|
mLightListDirty = true;
|
||||||
|
queue->addRenderable(this, mRenderQueueID);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Ogre::AxisAlignedBox& getBoundingBox( void ) const {
|
||||||
|
return mBounds;
|
||||||
|
};
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
Ogre::Real getBoundingRadius(void) const {
|
||||||
|
return mBoundingRadius;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief passes the morph factor to the custom vertex program
|
||||||
|
*/
|
||||||
|
void _updateCustomGpuParameter(const Ogre::GpuProgramParameters::AutoConstantEntry& constantEntry,
|
||||||
|
Ogre::GpuProgramParameters* params) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sets the mExtraMorphAmount so it slowly regains detail from the lowest morph factor
|
||||||
|
*/
|
||||||
|
void justSplit();
|
||||||
|
/**
|
||||||
|
* @brief Does nothing
|
||||||
|
*/
|
||||||
|
inline void justUnsplit(){
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float getMax(){
|
||||||
|
return mMax;
|
||||||
|
}
|
||||||
|
inline float getMin(){
|
||||||
|
return mMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets how many vertexes wide this quad segment is. Should always be 2^n+1
|
||||||
|
* @return the vertex width of this quad segment
|
||||||
|
*/
|
||||||
|
int getVertexWidth()
|
||||||
|
{
|
||||||
|
return (mQuadData->getVertexWidth()-1)*mSegmentSize+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief gets a vertex assuming that x = 0, y = 0 addresses the start of the quad
|
||||||
|
*/
|
||||||
|
float getVertex(int x, int y)
|
||||||
|
{
|
||||||
#ifdef QSDEBUG
|
#ifdef QSDEBUG
|
||||||
{
|
{
|
||||||
//check sizes
|
const int vw = getVertexWidth();
|
||||||
const float qw = mQuadData->getVertexWidth()-1;
|
assert(x<vw);
|
||||||
const float fsw = qw*segSize;
|
}
|
||||||
const int isw = (int)fsw;
|
|
||||||
assert(fsw==isw);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
return mQuadData->getVertex((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x));
|
||||||
//precalc offsets, as getVertex/getNormal get called a lot (1000s of times)
|
|
||||||
computeOffsets();
|
|
||||||
|
|
||||||
// From Quad
|
|
||||||
node = parent->createChildSceneNode(pos);
|
|
||||||
|
|
||||||
// From create()
|
|
||||||
createVertexBuffer();
|
|
||||||
calculateVetexValues();
|
|
||||||
calculateIndexValues();
|
|
||||||
setBounds();
|
|
||||||
|
|
||||||
node->attachObject(this);
|
|
||||||
|
|
||||||
createMaterial();
|
|
||||||
|
|
||||||
if ( g_Terrain->isMorhpingEnabled() && mDepth != g_Terrain->getMaxDepth() ) {
|
|
||||||
Ogre::Technique* tech = getMaterial()->getTechnique(0);
|
|
||||||
for ( size_t i = 0; i < tech->getNumPasses(); ++i ) {
|
|
||||||
assert(g_Terrain->isMorhpingEnabled());
|
|
||||||
tech->getPass(i)->setVertexProgram(MORPH_VERTEX_PROGRAM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( g_Terrain->isMorhpingEnabled() )
|
float getNormal(int x, int y, int z)
|
||||||
calculateDeltaValues();
|
|
||||||
|
|
||||||
mBuilt = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TerrainMesh::destroy() {
|
|
||||||
if ( !mBuilt ) return;
|
|
||||||
|
|
||||||
//deleting null values is fine iirc
|
|
||||||
delete mIndices;
|
|
||||||
|
|
||||||
# if ENABLED_CRASHING == 1
|
|
||||||
{
|
{
|
||||||
delete mVertexes;
|
assert(z>=0&&z<3);
|
||||||
|
return mQuadData->getNormal(((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x))*3+z);
|
||||||
}
|
}
|
||||||
# else
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void createMaterial()
|
||||||
{
|
{
|
||||||
if ( mDepth != g_Terrain->getMaxDepth() ){
|
assert(mSegmentSize>0);
|
||||||
delete mVertexes;
|
if ( mSegmentSize == 1 ) //we can use the top level material
|
||||||
|
{
|
||||||
|
mMaterial = mQuadData->getMaterial();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mQuadData->getTexture().length() )
|
||||||
|
assert(0&&"NOT IMPLEMENTED");
|
||||||
|
|
||||||
|
const std::vector<int>& tref = mQuadData->getTextureIndexRef();
|
||||||
|
const int indexSize = sqrt(tref.size());
|
||||||
|
const int cellIndexSize = indexSize - 2;
|
||||||
|
|
||||||
|
//plus 1 to take into account border
|
||||||
|
const int xoff = float(cellIndexSize) * mX;
|
||||||
|
const int yoff = float(cellIndexSize) * mY;
|
||||||
|
const int size = float(cellIndexSize) * mSegmentSize;
|
||||||
|
|
||||||
|
std::vector<int> ti;
|
||||||
|
|
||||||
|
ti.resize((size+2)*(size+2), -1);
|
||||||
|
|
||||||
|
for ( int y = 0; y < size+2; ++y ){
|
||||||
|
for ( int x = 0; x < size+2; ++x ){
|
||||||
|
ti[(y)*(size+2)+(x)] = tref.at((y+yoff)*(indexSize)+(x+xoff));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
mBuilt = false;
|
mMaterial = g_materialGen->getAlphaMat
|
||||||
}
|
(ti,size,
|
||||||
//----------------------------------------------
|
1, 1.0f/size,
|
||||||
void TerrainMesh::update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist)
|
mQuadData->getUsedResourcesRef());
|
||||||
{
|
|
||||||
TRACE("TerrainMesh::update");
|
|
||||||
//if ( USE_MORPH ){
|
|
||||||
|
|
||||||
//as aprocesh mUnsplitDistance, lower detail
|
|
||||||
if ( camDist > morphDist && mDepth > 1 ) {
|
|
||||||
mLODMorphFactor = 1 - (usplitDist - camDist)/(usplitDist-morphDist);
|
|
||||||
} else
|
|
||||||
mLODMorphFactor = 0;
|
|
||||||
mTextureFadeFactor = mLODMorphFactor;
|
|
||||||
|
|
||||||
|
|
||||||
//on an split, it sets the extra morph amount to 1, we then ensure this ends up at 0... slowly
|
|
||||||
if ( mExtraMorphAmount > 0 ) {
|
|
||||||
mLODMorphFactor += mExtraMorphAmount;
|
|
||||||
mExtraMorphAmount -= (time/g_Terrain->getMorphSpeed()); //decrease slowly
|
|
||||||
}
|
|
||||||
if ( mExtraFadeAmount > 0 ) {
|
|
||||||
mTextureFadeFactor += mExtraFadeAmount;
|
|
||||||
mExtraFadeAmount -= (time/g_Terrain->getTextureFadeSpeed());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Ensure within valid bounds
|
inline bool hasParentTexture() const{
|
||||||
if ( mLODMorphFactor > 1 )
|
return mQuadData->hasParentTexture();
|
||||||
mLODMorphFactor = 1;
|
}
|
||||||
else if ( mLODMorphFactor < 0 )
|
inline const std::string& getParentTexture() const{
|
||||||
mLODMorphFactor = 0;
|
return mQuadData->getParentTexture();
|
||||||
|
}
|
||||||
if ( mTextureFadeFactor > 1 )
|
inline int getVertexSeperation(){
|
||||||
mTextureFadeFactor = 1;
|
return mQuadData->getVertexSeperation();
|
||||||
else if ( mTextureFadeFactor < 0 )
|
|
||||||
mTextureFadeFactor = 0;
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
//remove pass. Keep outside in case terrain fading is removed while it is active
|
|
||||||
if ( mHasFadePass && mTextureFadeFactor == 0 ) {
|
|
||||||
removeFadePass();
|
|
||||||
} else if ( g_Terrain->isTextureFadingEnabled() &&
|
|
||||||
!mHasFadePass &&
|
|
||||||
mTextureFadeFactor > 0 &&
|
|
||||||
hasParentTexture() ) {
|
|
||||||
addFadePass();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
inline float getSegmentSize(){
|
||||||
//----------------------------------------------
|
return mSegmentSize;
|
||||||
void TerrainMesh::addFadePass() {
|
}
|
||||||
assert(mHasFadePass==false);
|
inline float getStartX(){
|
||||||
|
return mX;
|
||||||
if ( mDepth == g_Terrain->getMaxDepth() ) return;
|
}
|
||||||
|
inline float getStartY(){
|
||||||
|
return mY;
|
||||||
mHasFadePass = true;
|
|
||||||
Ogre::MaterialPtr mat = getMaterial();
|
|
||||||
Ogre::Pass* newPass = mat->getTechnique(0)->createPass();
|
|
||||||
newPass->setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA);
|
|
||||||
|
|
||||||
//set fragment program
|
|
||||||
assert(g_Terrain->isTextureFadingEnabled());
|
|
||||||
newPass->setFragmentProgram(FADE_FRAGMENT_PROGRAM);
|
|
||||||
|
|
||||||
if ( g_Terrain->isMorhpingEnabled() && mDepth != g_Terrain->getMaxDepth() ) {
|
|
||||||
assert(g_Terrain->isMorhpingEnabled());
|
|
||||||
newPass->setVertexProgram(MORPH_VERTEX_PROGRAM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds another pass to the material to fade in/out the material from a higher level
|
||||||
|
*/
|
||||||
|
void addFadePass();
|
||||||
|
/**
|
||||||
|
* @brief removes the last pass from the material. Assumed to be the fade pass
|
||||||
|
*/
|
||||||
|
void removeFadePass();
|
||||||
|
|
||||||
//set texture to be used
|
/**
|
||||||
newPass->createTextureUnitState(getParentTexture(), 1);
|
* @return the height at the given vertex
|
||||||
}
|
*/
|
||||||
//----------------------------------------------
|
float getVertexHeight(int x, int y);
|
||||||
void TerrainMesh::removeFadePass() {
|
|
||||||
assert(mHasFadePass==true);
|
|
||||||
mHasFadePass = false;
|
|
||||||
Ogre::MaterialPtr mat = getMaterial();
|
|
||||||
Ogre::Technique* tech = mat->getTechnique(0);
|
|
||||||
|
|
||||||
tech->removePass(tech->getNumPasses()-1);
|
/**
|
||||||
}
|
* Inits the vertex stuff
|
||||||
//----------------------------------------------
|
*/
|
||||||
void TerrainMesh::justSplit() {
|
void createVertexBuffer();
|
||||||
mExtraMorphAmount = 1;
|
|
||||||
mLODMorphFactor = 1;
|
|
||||||
mTextureFadeFactor = 1;
|
|
||||||
mExtraFadeAmount = 1;
|
|
||||||
|
|
||||||
if ( g_Terrain->isTextureFadingEnabled() && hasParentTexture() )
|
/**
|
||||||
addFadePass();
|
* @brief fills the vertex buffer with data
|
||||||
}
|
* @todo I don't think tex co-ords are right
|
||||||
|
*/
|
||||||
|
void calculateVetexValues();
|
||||||
|
|
||||||
//----------------------------------------------
|
/**
|
||||||
void TerrainMesh::_updateCustomGpuParameter(
|
* @brief returns a a new Vertex Buffer ready for input
|
||||||
const GpuProgramParameters::AutoConstantEntry& constantEntry,
|
* @remarks Unlike other terrain libs, this isn't 0s when it is returend
|
||||||
GpuProgramParameters* params) const {
|
*/
|
||||||
using namespace Ogre;
|
Ogre::HardwareVertexBufferSharedPtr createDeltaBuffer( );
|
||||||
if (constantEntry.data == MORPH_CUSTOM_PARAM_ID)
|
|
||||||
params->_writeRawConstant(constantEntry.physicalIndex, mLODMorphFactor);
|
|
||||||
else if ( constantEntry.data == FADE_CUSTOM_PARAM_ID )
|
|
||||||
params->_writeRawConstant(constantEntry.physicalIndex, mTextureFadeFactor);
|
|
||||||
else
|
|
||||||
Renderable::_updateCustomGpuParameter(constantEntry, params);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief DOESN'T WORK FULLY
|
||||||
|
* @todo fix
|
||||||
|
*/
|
||||||
|
void calculateDeltaValues();
|
||||||
|
/**
|
||||||
|
* @brief gets the position of a vertex. It will not interpolate
|
||||||
|
*/
|
||||||
|
Ogre::Vector3 getVertexPosition(int x, int y);
|
||||||
|
|
||||||
}
|
/**
|
||||||
//----------------------------------------------
|
* @brief gets the indicies for the vertex data.
|
||||||
float TerrainMesh::getVertexHeight(int x, int y) {
|
*/
|
||||||
return getVertex(x,y);
|
void calculateIndexValues();
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
Ogre::Vector3 TerrainMesh::getVertexPosition(int x, int y) {
|
|
||||||
return Ogre::Vector3(x*getVertexSeperation(), getVertexHeight(x,y) , y*getVertexSeperation());
|
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
void TerrainMesh::calculateVetexValues() {
|
|
||||||
using namespace Ogre;
|
|
||||||
|
|
||||||
//get the texture offsets for the higher uv
|
|
||||||
float xUVOffset = 0;
|
|
||||||
float yUVOffset = 0;
|
|
||||||
|
|
||||||
if ( g_Terrain->isTextureFadingEnabled() ) {
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
switch (mInterface->getLocation()) {
|
* Sets the bounds on the renderable. This requires that mMin/mMax
|
||||||
case Quad::QL_NW :
|
* have been set. They are set in createVertexData. This may look
|
||||||
yUVOffset = 32.0f/64.0f;
|
* as though it is done twice, as it is also done in MeshInterface,
|
||||||
break;
|
* however, there is no guarentee that the mesh sizes are the same
|
||||||
case Quad::QL_NE:
|
*/
|
||||||
yUVOffset = 32.0f/64.0f;
|
void setBounds();
|
||||||
xUVOffset = 32.0f/64.0f;
|
|
||||||
break;
|
Ogre::SceneNode* node;
|
||||||
case Quad::QL_SE:
|
|
||||||
xUVOffset = 32.0f/64.0f;
|
const int mWidth;
|
||||||
break;
|
const bool mUseSkirts;
|
||||||
default:
|
|
||||||
break;
|
///true if the land has been built
|
||||||
|
bool mBuilt;
|
||||||
|
|
||||||
|
int mDepth;
|
||||||
|
|
||||||
|
Ogre::MaterialPtr mMaterial;
|
||||||
|
Ogre::ManualObject* mObject;
|
||||||
|
|
||||||
|
Ogre::VertexData* mVertexes;
|
||||||
|
Ogre::IndexData* mIndices;
|
||||||
|
Ogre::HardwareVertexBufferSharedPtr mMainBuffer;
|
||||||
|
Ogre::HardwareVertexBufferSharedPtr mDeltaBuffer;
|
||||||
|
|
||||||
|
mutable bool mLightListDirty;
|
||||||
|
|
||||||
|
Ogre::Real mBoundingRadius;
|
||||||
|
Ogre::AxisAlignedBox mBounds;
|
||||||
|
Ogre::Vector3 mCenter;
|
||||||
|
|
||||||
|
Ogre::Real mLODMorphFactor, mTextureFadeFactor;
|
||||||
|
|
||||||
|
/** Max and min heights of the mesh */
|
||||||
|
float mMin, mMax;
|
||||||
|
|
||||||
|
int computeOffset(float x)
|
||||||
|
{
|
||||||
|
#ifdef QSDEBUG
|
||||||
|
{
|
||||||
|
//check it is a valid position
|
||||||
|
const int start = (mQuadData->getVertexWidth()-1)*x;
|
||||||
|
const int vw = getVertexWidth()-1;
|
||||||
|
assert(vw>0);
|
||||||
|
assert((start%vw)==0);
|
||||||
}
|
}
|
||||||
*/
|
#endif
|
||||||
|
return float((mQuadData->getVertexWidth()-1))*x;
|
||||||
int start = 0;
|
|
||||||
int end = mWidth;
|
|
||||||
|
|
||||||
if ( mUseSkirts ) {
|
|
||||||
--start;
|
|
||||||
++end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float* verts = static_cast<float*>(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD));
|
void computeOffsets()
|
||||||
for ( int y = start; y < end; y++ ) {
|
{
|
||||||
for ( int x = start; x < end; x++ ) {
|
mXOffset = computeOffset(mX);
|
||||||
|
mYOffset = computeOffset(mY);
|
||||||
//the skirts
|
|
||||||
if ( y < 0 || y > (mWidth-1) || x < 0 || x > (mWidth-1) ) {
|
|
||||||
|
|
||||||
if ( x < 0 ) *verts++ = 0;
|
|
||||||
else if ( x > (mWidth-1) ) *verts++ = (mWidth-1)*getVertexSeperation();
|
|
||||||
else *verts++ = x*getVertexSeperation();
|
|
||||||
|
|
||||||
*verts++ = -4096; //2048 below base sea floor height
|
|
||||||
|
|
||||||
if ( y < 0 ) *verts++ = 0;
|
|
||||||
else if ( y > (mWidth-1) ) *verts++ = (mWidth-1)*getVertexSeperation();
|
|
||||||
else *verts++ = y*getVertexSeperation();
|
|
||||||
|
|
||||||
|
|
||||||
for ( Ogre::uint i = 0; i < 3; i++ )
|
|
||||||
*verts++ = 0;
|
|
||||||
|
|
||||||
float u = (float)(x) / (mWidth-1);
|
|
||||||
float v = (float)(y) / (mWidth-1);
|
|
||||||
|
|
||||||
//clamped, so shouldn't matter if > 1
|
|
||||||
|
|
||||||
*verts++ = u;
|
|
||||||
*verts++ = v;
|
|
||||||
|
|
||||||
if ( g_Terrain->isTextureFadingEnabled() ) {
|
|
||||||
*verts++ = u;
|
|
||||||
*verts++ = v;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
assert(y*mWidth+x>=0&&y*mWidth+x<mWidth*mWidth);
|
|
||||||
|
|
||||||
//verts
|
|
||||||
*verts++ = x*getVertexSeperation();
|
|
||||||
*verts++ = getVertexHeight(x,y);
|
|
||||||
*verts++ = y*getVertexSeperation();
|
|
||||||
|
|
||||||
mMax = std::max(mMax, getVertexHeight(x,y));
|
|
||||||
mMin = std::min(mMin, getVertexHeight(x,y));
|
|
||||||
|
|
||||||
//normals
|
|
||||||
for ( Ogre::uint i = 0; i < 3; i++ )
|
|
||||||
*verts++ = getNormal(x,y,i);
|
|
||||||
//*verts++ = mInterface->getNormal((y*mWidth+x)*3+i);
|
|
||||||
|
|
||||||
const float u = (float)(x) / (mWidth-1);
|
|
||||||
const float v = (float)(y) / (mWidth-1);
|
|
||||||
assert(u>=0&&v>=0);
|
|
||||||
assert(u<=1&&v<=1);
|
|
||||||
|
|
||||||
*verts++ = u;
|
|
||||||
*verts++ = v;
|
|
||||||
|
|
||||||
if ( g_Terrain->isTextureFadingEnabled() ) {
|
|
||||||
*verts++ = u/2.0f + xUVOffset;
|
|
||||||
*verts++ = v/2.0f + yUVOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mMainBuffer->unlock();
|
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
void TerrainMesh::setBounds() {
|
|
||||||
mBounds.setExtents(0,mMin,0,
|
|
||||||
(mWidth - 1) * getVertexSeperation(),
|
|
||||||
mMax,
|
|
||||||
(mWidth - 1) * getVertexSeperation());
|
|
||||||
|
|
||||||
mCenter = Ogre::Vector3( ( (mWidth - 1) * getVertexSeperation() ) / 2,
|
|
||||||
( mMin + mMax ) / 2,
|
|
||||||
( (mWidth - 1) * getVertexSeperation() ) / 2);
|
|
||||||
|
|
||||||
mBoundingRadius = (mBounds.getMaximum() - mBounds.getMinimum()).length() / 2;
|
|
||||||
}
|
|
||||||
//----------------------------------------------
|
|
||||||
void TerrainMesh::createVertexBuffer() {
|
|
||||||
using namespace Ogre;
|
|
||||||
|
|
||||||
size_t vw = mWidth;
|
|
||||||
if ( mUseSkirts ) vw += 2;
|
|
||||||
|
|
||||||
mVertexes = new VertexData();
|
|
||||||
mVertexes->vertexStart = 0;
|
|
||||||
mVertexes->vertexCount = vw*vw;// VERTEX_WIDTH;
|
|
||||||
|
|
||||||
VertexDeclaration* vertexDecl = mVertexes->vertexDeclaration;
|
|
||||||
size_t currOffset = 0;
|
|
||||||
|
|
||||||
vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_POSITION);
|
|
||||||
currOffset += VertexElement::getTypeSize(VET_FLOAT3);
|
|
||||||
|
|
||||||
vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_NORMAL);
|
|
||||||
currOffset += VertexElement::getTypeSize(VET_FLOAT3);
|
|
||||||
|
|
||||||
|
|
||||||
vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
|
|
||||||
currOffset += VertexElement::getTypeSize(VET_FLOAT2);
|
|
||||||
|
|
||||||
if ( g_Terrain->isTextureFadingEnabled() ) {
|
|
||||||
vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 1);
|
|
||||||
currOffset += VertexElement::getTypeSize(VET_FLOAT2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mMainBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
|
QuadData* mQuadData;
|
||||||
vertexDecl->getVertexSize(0), // size of one whole vertex
|
float mSegmentSize;
|
||||||
mVertexes->vertexCount, // number of vertices
|
float mX, mY;
|
||||||
HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
|
int mXOffset, mYOffset;
|
||||||
false); // no shadow buffer
|
|
||||||
|
|
||||||
mVertexes->vertexBufferBinding->setBinding(MAIN_BINDING, mMainBuffer); //bind the data
|
/**
|
||||||
|
* @brief holds the amount to morph by, this decreases to 0 over a periord of time
|
||||||
|
* It is changed and used in the update() function
|
||||||
|
*/
|
||||||
|
Ogre::Real mExtraMorphAmount, mExtraFadeAmount;
|
||||||
|
|
||||||
if ( g_Terrain->isMorhpingEnabled() )
|
/**
|
||||||
vertexDecl->addElement(DELTA_BINDING, 0, VET_FLOAT1, VES_BLEND_WEIGHTS);
|
* True if the fade pass has been added to the material.
|
||||||
|
*/
|
||||||
|
bool mHasFadePass;
|
||||||
|
|
||||||
|
//Custom params used in terrian shaders.
|
||||||
|
static const size_t MORPH_CUSTOM_PARAM_ID = 77;
|
||||||
|
static const size_t FADE_CUSTOM_PARAM_ID = 78;
|
||||||
|
|
||||||
}
|
//Terrain bindings
|
||||||
|
static const int MAIN_BINDING = 0;
|
||||||
Ogre::HardwareVertexBufferSharedPtr TerrainMesh::createDeltaBuffer( ) {
|
static const int DELTA_BINDING = 1;
|
||||||
size_t vw = mWidth;
|
};
|
||||||
if ( mUseSkirts ) vw += 2;
|
|
||||||
|
|
||||||
const size_t totalVerts = (vw * vw);
|
|
||||||
return Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
|
|
||||||
Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT1),
|
|
||||||
totalVerts,
|
|
||||||
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
|
|
||||||
false); //no shadow buff
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------
|
|
||||||
#define SET_DELTA_AT(x, y, v) \
|
|
||||||
if ( mUseSkirts ) pDeltas[( y + 1)*vw+ x + 1] = v; \
|
|
||||||
else pDeltas[( y)*vw+ x] = v;
|
|
||||||
void TerrainMesh::calculateDeltaValues() {
|
|
||||||
|
|
||||||
using namespace Ogre;
|
|
||||||
size_t vw = mWidth;
|
|
||||||
if ( mUseSkirts ) vw += 2;
|
|
||||||
|
|
||||||
//must be using morphing to use this function
|
|
||||||
assert(g_Terrain->isMorhpingEnabled());
|
|
||||||
|
|
||||||
const size_t step = 2;
|
|
||||||
|
|
||||||
// Create a set of delta values
|
|
||||||
mDeltaBuffer = createDeltaBuffer();
|
|
||||||
float* pDeltas = static_cast<float*>(mDeltaBuffer->lock(HardwareBuffer::HBL_DISCARD));
|
|
||||||
memset(pDeltas, 0, (vw)*(vw) * sizeof(float));
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool flag=false;
|
|
||||||
for ( size_t y = 0; y < mWidth-step; y += step ) {
|
|
||||||
for ( size_t x = 0; x < mWidth-step; x += step ) {
|
|
||||||
//create the diffrence between the full vertex if the vertex wasn't their
|
|
||||||
|
|
||||||
float bottom_left = getVertexHeight(x,y);
|
|
||||||
float bottom_right = getVertexHeight(x+step,y);
|
|
||||||
|
|
||||||
float top_left = getVertexHeight(x,y+step);
|
|
||||||
float top_right = getVertexHeight(x+step,y+step);
|
|
||||||
|
|
||||||
//const int vw = mWidth+2;
|
|
||||||
SET_DELTA_AT(x, y+1, (bottom_left+top_left)/2 - getVertexHeight(x, y+1)) //left
|
|
||||||
SET_DELTA_AT(x+2, y+1, (bottom_right+top_right)/2 - getVertexHeight(x+2, y+1)) //right
|
|
||||||
|
|
||||||
SET_DELTA_AT(x+1, y+2, (top_right+top_left)/2 - getVertexHeight(x+1, y+2)) //top
|
|
||||||
SET_DELTA_AT(x+1, y, (bottom_right+bottom_left)/2 - getVertexHeight(x+1, y)) //bottom
|
|
||||||
|
|
||||||
//this might not be correct
|
|
||||||
if ( !flag )
|
|
||||||
SET_DELTA_AT(x+1, y+1, (bottom_left+top_right)/2 - getVertexHeight(x+1, y+1)) //center
|
|
||||||
else
|
|
||||||
SET_DELTA_AT(x+1, y+1, (bottom_right+top_left)/2 - getVertexHeight(x+1, y+1)) //center
|
|
||||||
|
|
||||||
flag = !flag;
|
|
||||||
}
|
|
||||||
flag = !flag; //flip tries for next row
|
|
||||||
}
|
|
||||||
|
|
||||||
mDeltaBuffer->unlock();
|
|
||||||
mVertexes->vertexBufferBinding->setBinding(DELTA_BINDING,mDeltaBuffer);
|
|
||||||
|
|
||||||
}
|
|
||||||
#undef SET_DELTA_AT
|
|
||||||
|
|
||||||
//----------------------------------------------
|
|
||||||
void TerrainMesh::calculateIndexValues() {
|
|
||||||
using namespace Ogre;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size_t vw = mWidth-1;
|
|
||||||
if ( mUseSkirts ) vw += 2;
|
|
||||||
|
|
||||||
const size_t indexCount = (vw)*(vw)*6;
|
|
||||||
|
|
||||||
//need to manage allocation if not null
|
|
||||||
assert(mIndices==0);
|
|
||||||
|
|
||||||
mIndices = new IndexData();
|
|
||||||
mIndices->indexCount = indexCount;
|
|
||||||
mIndices->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
|
|
||||||
HardwareIndexBuffer::IT_16BIT,
|
|
||||||
indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
|
|
||||||
|
|
||||||
unsigned short* indices = static_cast<unsigned short*>(mIndices->indexBuffer->lock(0,
|
|
||||||
mIndices->indexBuffer->getSizeInBytes(),
|
|
||||||
HardwareBuffer::HBL_DISCARD));
|
|
||||||
|
|
||||||
bool flag = false;
|
|
||||||
Ogre::uint indNum = 0;
|
|
||||||
for ( Ogre::uint y = 0; y < (vw); y+=1 ) {
|
|
||||||
for ( Ogre::uint x = 0; x < (vw); x+=1 ) {
|
|
||||||
|
|
||||||
const int line1 = y * (vw+1) + x;
|
|
||||||
const int line2 = (y + 1) * (vw+1) + x;
|
|
||||||
|
|
||||||
if ( flag ) {
|
|
||||||
*indices++ = line1;
|
|
||||||
*indices++ = line2;
|
|
||||||
*indices++ = line1 + 1;
|
|
||||||
|
|
||||||
*indices++ = line1 + 1;
|
|
||||||
*indices++ = line2;
|
|
||||||
*indices++ = line2 + 1;
|
|
||||||
} else {
|
|
||||||
*indices++ = line1;
|
|
||||||
*indices++ = line2;
|
|
||||||
*indices++ = line2 + 1;
|
|
||||||
|
|
||||||
*indices++ = line1;
|
|
||||||
*indices++ = line2 + 1;
|
|
||||||
*indices++ = line1 + 1;
|
|
||||||
}
|
|
||||||
flag = !flag; //flip tris for next time
|
|
||||||
|
|
||||||
indNum+=6;
|
|
||||||
}
|
|
||||||
flag = !flag; //flip tries for next row
|
|
||||||
}
|
|
||||||
assert(indNum==indexCount);
|
|
||||||
mIndices->indexBuffer->unlock();
|
|
||||||
//return mIndices;
|
|
||||||
}
|
|
||||||
|
@ -1,343 +0,0 @@
|
|||||||
/**
|
|
||||||
* @brief Terrain for one cell. Handles building, destroying and LOD morphing
|
|
||||||
*/
|
|
||||||
#define QSDEBUG
|
|
||||||
class TerrainMesh : public Ogre::Renderable, public Ogre::MovableObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
TerrainMesh(QuadData* qd, float segSize, float startX, float startY,
|
|
||||||
const Ogre::Vector3 &pos,
|
|
||||||
int width, int depth, bool skirts,
|
|
||||||
Ogre::SceneNode *parent);
|
|
||||||
|
|
||||||
~TerrainMesh()
|
|
||||||
{
|
|
||||||
destroy();
|
|
||||||
|
|
||||||
assert(node);
|
|
||||||
|
|
||||||
node->detachAllObjects();
|
|
||||||
node->getCreator()->destroySceneNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can be called manually and can be called from the destuctor. This
|
|
||||||
* destroyes the mesh
|
|
||||||
*/
|
|
||||||
// FIXME: We don't need this as a separate function.
|
|
||||||
void destroy();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if it needs to be split or unsplit and deals with
|
|
||||||
* the morph factor. time seconds since last frame
|
|
||||||
*/
|
|
||||||
void update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo Needs to work out what this does (if it does what it is meant to)
|
|
||||||
*/
|
|
||||||
void visitRenderables(Renderable::Visitor* visitor,
|
|
||||||
bool debugRenderables = false) {
|
|
||||||
visitor->visit(this, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const Ogre::MaterialPtr& getMaterial( void ) const {
|
|
||||||
return mMaterial;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
void getRenderOperation( Ogre::RenderOperation& op ) {
|
|
||||||
op.useIndexes = true;
|
|
||||||
op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
|
|
||||||
op.vertexData = mVertexes;
|
|
||||||
op.indexData = mIndices;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
void getWorldTransforms( Ogre::Matrix4* xform ) const {
|
|
||||||
*xform = mParentNode->_getFullTransform();
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
const Ogre::Quaternion& getWorldOrientation(void) const {
|
|
||||||
return mParentNode->_getDerivedOrientation();
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
const Ogre::Vector3& getWorldPosition(void) const {
|
|
||||||
return mParentNode->_getDerivedPosition();
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
Ogre::Real getSquaredViewDepth(const Ogre::Camera *cam) const {
|
|
||||||
Ogre::Vector3 diff = mCenter - cam->getDerivedPosition();
|
|
||||||
// Use squared length to avoid square root
|
|
||||||
return diff.squaredLength();
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
const Ogre::LightList& getLights(void) const {
|
|
||||||
if (mLightListDirty) {
|
|
||||||
getParentSceneNode()->getCreator()->_populateLightList(
|
|
||||||
mCenter, this->getBoundingRadius(), mLightList);
|
|
||||||
mLightListDirty = false;
|
|
||||||
}
|
|
||||||
return mLightList;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
virtual const Ogre::String& getMovableType( void ) const {
|
|
||||||
static Ogre::String t = "MW_TERRAIN";
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
void _updateRenderQueue( Ogre::RenderQueue* queue ) {
|
|
||||||
mLightListDirty = true;
|
|
||||||
queue->addRenderable(this, mRenderQueueID);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Ogre::AxisAlignedBox& getBoundingBox( void ) const {
|
|
||||||
return mBounds;
|
|
||||||
};
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
Ogre::Real getBoundingRadius(void) const {
|
|
||||||
return mBoundingRadius;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief passes the morph factor to the custom vertex program
|
|
||||||
*/
|
|
||||||
void _updateCustomGpuParameter(const Ogre::GpuProgramParameters::AutoConstantEntry& constantEntry,
|
|
||||||
Ogre::GpuProgramParameters* params) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief sets the mExtraMorphAmount so it slowly regains detail from the lowest morph factor
|
|
||||||
*/
|
|
||||||
void justSplit();
|
|
||||||
/**
|
|
||||||
* @brief Does nothing
|
|
||||||
*/
|
|
||||||
inline void justUnsplit(){
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float getMax(){
|
|
||||||
return mMax;
|
|
||||||
}
|
|
||||||
inline float getMin(){
|
|
||||||
return mMin;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets how many vertexes wide this quad segment is. Should always be 2^n+1
|
|
||||||
* @return the vertex width of this quad segment
|
|
||||||
*/
|
|
||||||
int getVertexWidth()
|
|
||||||
{
|
|
||||||
return (mQuadData->getVertexWidth()-1)*mSegmentSize+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief gets a vertex assuming that x = 0, y = 0 addresses the start of the quad
|
|
||||||
*/
|
|
||||||
float getVertex(int x, int y)
|
|
||||||
{
|
|
||||||
#ifdef QSDEBUG
|
|
||||||
{
|
|
||||||
const int vw = getVertexWidth();
|
|
||||||
assert(x<vw);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return mQuadData->getVertex((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x));
|
|
||||||
}
|
|
||||||
|
|
||||||
float getNormal(int x, int y, int z)
|
|
||||||
{
|
|
||||||
assert(z>=0&&z<3);
|
|
||||||
return mQuadData->getNormal(((mYOffset + y)*mQuadData->getVertexWidth()+(mXOffset+x))*3+z);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void createMaterial()
|
|
||||||
{
|
|
||||||
assert(mSegmentSize>0);
|
|
||||||
if ( mSegmentSize == 1 ) //we can use the top level material
|
|
||||||
{
|
|
||||||
mMaterial = mQuadData->getMaterial();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( mQuadData->getTexture().length() )
|
|
||||||
assert(0&&"NOT IMPLEMENTED");
|
|
||||||
|
|
||||||
const std::vector<int>& tref = mQuadData->getTextureIndexRef();
|
|
||||||
const int indexSize = sqrt(tref.size());
|
|
||||||
const int cellIndexSize = indexSize - 2;
|
|
||||||
|
|
||||||
//plus 1 to take into account border
|
|
||||||
const int xoff = float(cellIndexSize) * mX;
|
|
||||||
const int yoff = float(cellIndexSize) * mY;
|
|
||||||
const int size = float(cellIndexSize) * mSegmentSize;
|
|
||||||
|
|
||||||
std::vector<int> ti;
|
|
||||||
|
|
||||||
ti.resize((size+2)*(size+2), -1);
|
|
||||||
|
|
||||||
for ( int y = 0; y < size+2; ++y ){
|
|
||||||
for ( int x = 0; x < size+2; ++x ){
|
|
||||||
ti[(y)*(size+2)+(x)] = tref.at((y+yoff)*(indexSize)+(x+xoff));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mMaterial = g_materialGen->getAlphaMat
|
|
||||||
(ti,size,
|
|
||||||
1, 1.0f/size,
|
|
||||||
mQuadData->getUsedResourcesRef());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool hasParentTexture() const{
|
|
||||||
return mQuadData->hasParentTexture();
|
|
||||||
}
|
|
||||||
inline const std::string& getParentTexture() const{
|
|
||||||
return mQuadData->getParentTexture();
|
|
||||||
}
|
|
||||||
inline int getVertexSeperation(){
|
|
||||||
return mQuadData->getVertexSeperation();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float getSegmentSize(){
|
|
||||||
return mSegmentSize;
|
|
||||||
}
|
|
||||||
inline float getStartX(){
|
|
||||||
return mX;
|
|
||||||
}
|
|
||||||
inline float getStartY(){
|
|
||||||
return mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Adds another pass to the material to fade in/out the material from a higher level
|
|
||||||
*/
|
|
||||||
void addFadePass();
|
|
||||||
/**
|
|
||||||
* @brief removes the last pass from the material. Assumed to be the fade pass
|
|
||||||
*/
|
|
||||||
void removeFadePass();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the height at the given vertex
|
|
||||||
*/
|
|
||||||
float getVertexHeight(int x, int y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inits the vertex stuff
|
|
||||||
*/
|
|
||||||
void createVertexBuffer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief fills the vertex buffer with data
|
|
||||||
* @todo I don't think tex co-ords are right
|
|
||||||
*/
|
|
||||||
void calculateVetexValues();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief returns a a new Vertex Buffer ready for input
|
|
||||||
* @remarks Unlike other terrain libs, this isn't 0s when it is returend
|
|
||||||
*/
|
|
||||||
Ogre::HardwareVertexBufferSharedPtr createDeltaBuffer( );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief DOESN'T WORK FULLY
|
|
||||||
* @todo fix
|
|
||||||
*/
|
|
||||||
void calculateDeltaValues();
|
|
||||||
/**
|
|
||||||
* @brief gets the position of a vertex. It will not interpolate
|
|
||||||
*/
|
|
||||||
Ogre::Vector3 getVertexPosition(int x, int y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief gets the indicies for the vertex data.
|
|
||||||
*/
|
|
||||||
void calculateIndexValues();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sets the bounds on the renderable. This requires that mMin/mMax
|
|
||||||
* have been set. They are set in createVertexData. This may look
|
|
||||||
* as though it is done twice, as it is also done in MeshInterface,
|
|
||||||
* however, there is no guarentee that the mesh sizes are the same
|
|
||||||
*/
|
|
||||||
void setBounds();
|
|
||||||
|
|
||||||
Ogre::SceneNode* node;
|
|
||||||
|
|
||||||
const int mWidth;
|
|
||||||
const bool mUseSkirts;
|
|
||||||
|
|
||||||
///true if the land has been built
|
|
||||||
bool mBuilt;
|
|
||||||
|
|
||||||
int mDepth;
|
|
||||||
|
|
||||||
Ogre::MaterialPtr mMaterial;
|
|
||||||
Ogre::ManualObject* mObject;
|
|
||||||
|
|
||||||
Ogre::VertexData* mVertexes;
|
|
||||||
Ogre::IndexData* mIndices;
|
|
||||||
Ogre::HardwareVertexBufferSharedPtr mMainBuffer;
|
|
||||||
Ogre::HardwareVertexBufferSharedPtr mDeltaBuffer;
|
|
||||||
|
|
||||||
mutable bool mLightListDirty;
|
|
||||||
|
|
||||||
Ogre::Real mBoundingRadius;
|
|
||||||
Ogre::AxisAlignedBox mBounds;
|
|
||||||
Ogre::Vector3 mCenter;
|
|
||||||
|
|
||||||
Ogre::Real mLODMorphFactor, mTextureFadeFactor;
|
|
||||||
|
|
||||||
/** Max and min heights of the mesh */
|
|
||||||
float mMin, mMax;
|
|
||||||
|
|
||||||
int computeOffset(float x)
|
|
||||||
{
|
|
||||||
#ifdef QSDEBUG
|
|
||||||
{
|
|
||||||
//check it is a valid position
|
|
||||||
const int start = (mQuadData->getVertexWidth()-1)*x;
|
|
||||||
const int vw = getVertexWidth()-1;
|
|
||||||
assert(vw>0);
|
|
||||||
assert((start%vw)==0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return float((mQuadData->getVertexWidth()-1))*x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void computeOffsets()
|
|
||||||
{
|
|
||||||
mXOffset = computeOffset(mX);
|
|
||||||
mYOffset = computeOffset(mY);
|
|
||||||
}
|
|
||||||
|
|
||||||
QuadData* mQuadData;
|
|
||||||
float mSegmentSize;
|
|
||||||
float mX, mY;
|
|
||||||
int mXOffset, mYOffset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief holds the amount to morph by, this decreases to 0 over a periord of time
|
|
||||||
* It is changed and used in the update() function
|
|
||||||
*/
|
|
||||||
Ogre::Real mExtraMorphAmount, mExtraFadeAmount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if the fade pass has been added to the material.
|
|
||||||
*/
|
|
||||||
bool mHasFadePass;
|
|
||||||
|
|
||||||
//Custom params used in terrian shaders.
|
|
||||||
static const size_t MORPH_CUSTOM_PARAM_ID = 77;
|
|
||||||
static const size_t FADE_CUSTOM_PARAM_ID = 78;
|
|
||||||
|
|
||||||
//Terrain bindings
|
|
||||||
static const int MAIN_BINDING = 0;
|
|
||||||
static const int DELTA_BINDING = 1;
|
|
||||||
};
|
|
495
terrain/cpp_terrainmesh2.cpp
Normal file
495
terrain/cpp_terrainmesh2.cpp
Normal file
@ -0,0 +1,495 @@
|
|||||||
|
TerrainMesh::TerrainMesh(QuadData* qd, float segSize, float startX, float startY,
|
||||||
|
const Ogre::Vector3 &pos,
|
||||||
|
int width, int depth, bool skirts,
|
||||||
|
Ogre::SceneNode *parent)
|
||||||
|
: Ogre::Renderable(),
|
||||||
|
Ogre::MovableObject(),
|
||||||
|
mWidth(width),
|
||||||
|
mUseSkirts(skirts),
|
||||||
|
mBuilt(false),
|
||||||
|
mDepth(depth),
|
||||||
|
mVertexes(0),
|
||||||
|
mIndices(0),
|
||||||
|
mLODMorphFactor(0),
|
||||||
|
mTextureFadeFactor(0),
|
||||||
|
mMin(30000),
|
||||||
|
mMax(-30000),
|
||||||
|
mExtraMorphAmount(0),
|
||||||
|
mHasFadePass(false),
|
||||||
|
mQuadData(qd),
|
||||||
|
mSegmentSize(segSize),
|
||||||
|
mX(startX),
|
||||||
|
mY(startY)
|
||||||
|
{
|
||||||
|
// From QuadSegment()
|
||||||
|
assert(qd);
|
||||||
|
assert(segSize>0&&segSize<=1);
|
||||||
|
assert(mY>=0&&mY<=1);
|
||||||
|
assert(mX>=0&&mY<=1);
|
||||||
|
|
||||||
|
#ifdef QSDEBUG
|
||||||
|
{
|
||||||
|
//check sizes
|
||||||
|
const float qw = mQuadData->getVertexWidth()-1;
|
||||||
|
const float fsw = qw*segSize;
|
||||||
|
const int isw = (int)fsw;
|
||||||
|
assert(fsw==isw);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//precalc offsets, as getVertex/getNormal get called a lot (1000s of times)
|
||||||
|
computeOffsets();
|
||||||
|
|
||||||
|
// From Quad
|
||||||
|
node = parent->createChildSceneNode(pos);
|
||||||
|
|
||||||
|
// From create()
|
||||||
|
createVertexBuffer();
|
||||||
|
calculateVetexValues();
|
||||||
|
calculateIndexValues();
|
||||||
|
setBounds();
|
||||||
|
|
||||||
|
node->attachObject(this);
|
||||||
|
|
||||||
|
createMaterial();
|
||||||
|
|
||||||
|
if ( g_heightMap->isMorphingEnabled() && mDepth != g_heightMap->getMaxDepth() ) {
|
||||||
|
Ogre::Technique* tech = getMaterial()->getTechnique(0);
|
||||||
|
for ( size_t i = 0; i < tech->getNumPasses(); ++i ) {
|
||||||
|
assert(g_heightMap->isMorphingEnabled());
|
||||||
|
tech->getPass(i)->setVertexProgram(MORPH_VERTEX_PROGRAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( g_heightMap->isMorphingEnabled() )
|
||||||
|
calculateDeltaValues();
|
||||||
|
|
||||||
|
mBuilt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainMesh::destroy() {
|
||||||
|
if ( !mBuilt ) return;
|
||||||
|
|
||||||
|
//deleting null values is fine iirc
|
||||||
|
delete mIndices;
|
||||||
|
|
||||||
|
# if ENABLED_CRASHING == 1
|
||||||
|
{
|
||||||
|
delete mVertexes;
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
{
|
||||||
|
if ( mDepth != g_heightMap->getMaxDepth() ){
|
||||||
|
delete mVertexes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
mBuilt = false;
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::update(Ogre::Real time, Ogre::Real camDist, Ogre::Real usplitDist, Ogre::Real morphDist)
|
||||||
|
{
|
||||||
|
TRACE("TerrainMesh::update");
|
||||||
|
//if ( USE_MORPH ){
|
||||||
|
|
||||||
|
//as aprocesh mUnsplitDistance, lower detail
|
||||||
|
if ( camDist > morphDist && mDepth > 1 ) {
|
||||||
|
mLODMorphFactor = 1 - (usplitDist - camDist)/(usplitDist-morphDist);
|
||||||
|
} else
|
||||||
|
mLODMorphFactor = 0;
|
||||||
|
mTextureFadeFactor = mLODMorphFactor;
|
||||||
|
|
||||||
|
|
||||||
|
//on an split, it sets the extra morph amount to 1, we then ensure this ends up at 0... slowly
|
||||||
|
if ( mExtraMorphAmount > 0 ) {
|
||||||
|
mLODMorphFactor += mExtraMorphAmount;
|
||||||
|
mExtraMorphAmount -= (time/g_heightMap->getMorphSpeed()); //decrease slowly
|
||||||
|
}
|
||||||
|
if ( mExtraFadeAmount > 0 ) {
|
||||||
|
mTextureFadeFactor += mExtraFadeAmount;
|
||||||
|
mExtraFadeAmount -= (time/g_heightMap->getTextureFadeSpeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ensure within valid bounds
|
||||||
|
if ( mLODMorphFactor > 1 )
|
||||||
|
mLODMorphFactor = 1;
|
||||||
|
else if ( mLODMorphFactor < 0 )
|
||||||
|
mLODMorphFactor = 0;
|
||||||
|
|
||||||
|
if ( mTextureFadeFactor > 1 )
|
||||||
|
mTextureFadeFactor = 1;
|
||||||
|
else if ( mTextureFadeFactor < 0 )
|
||||||
|
mTextureFadeFactor = 0;
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
//remove pass. Keep outside in case terrain fading is removed while it is active
|
||||||
|
if ( mHasFadePass && mTextureFadeFactor == 0 ) {
|
||||||
|
removeFadePass();
|
||||||
|
} else if ( g_heightMap->isTextureFadingEnabled() &&
|
||||||
|
!mHasFadePass &&
|
||||||
|
mTextureFadeFactor > 0 &&
|
||||||
|
hasParentTexture() ) {
|
||||||
|
addFadePass();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::addFadePass() {
|
||||||
|
assert(mHasFadePass==false);
|
||||||
|
|
||||||
|
if ( mDepth == g_heightMap->getMaxDepth() ) return;
|
||||||
|
|
||||||
|
|
||||||
|
mHasFadePass = true;
|
||||||
|
Ogre::MaterialPtr mat = getMaterial();
|
||||||
|
Ogre::Pass* newPass = mat->getTechnique(0)->createPass();
|
||||||
|
newPass->setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA);
|
||||||
|
|
||||||
|
//set fragment program
|
||||||
|
assert(g_heightMap->isTextureFadingEnabled());
|
||||||
|
newPass->setFragmentProgram(FADE_FRAGMENT_PROGRAM);
|
||||||
|
|
||||||
|
if ( g_heightMap->isMorphingEnabled() && mDepth != g_heightMap->getMaxDepth() ) {
|
||||||
|
assert(g_heightMap->isMorphingEnabled());
|
||||||
|
newPass->setVertexProgram(MORPH_VERTEX_PROGRAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//set texture to be used
|
||||||
|
newPass->createTextureUnitState(getParentTexture(), 1);
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::removeFadePass() {
|
||||||
|
assert(mHasFadePass==true);
|
||||||
|
mHasFadePass = false;
|
||||||
|
Ogre::MaterialPtr mat = getMaterial();
|
||||||
|
Ogre::Technique* tech = mat->getTechnique(0);
|
||||||
|
|
||||||
|
tech->removePass(tech->getNumPasses()-1);
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::justSplit() {
|
||||||
|
mExtraMorphAmount = 1;
|
||||||
|
mLODMorphFactor = 1;
|
||||||
|
mTextureFadeFactor = 1;
|
||||||
|
mExtraFadeAmount = 1;
|
||||||
|
|
||||||
|
if ( g_heightMap->isTextureFadingEnabled() && hasParentTexture() )
|
||||||
|
addFadePass();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::_updateCustomGpuParameter(
|
||||||
|
const GpuProgramParameters::AutoConstantEntry& constantEntry,
|
||||||
|
GpuProgramParameters* params) const {
|
||||||
|
using namespace Ogre;
|
||||||
|
if (constantEntry.data == MORPH_CUSTOM_PARAM_ID)
|
||||||
|
params->_writeRawConstant(constantEntry.physicalIndex, mLODMorphFactor);
|
||||||
|
else if ( constantEntry.data == FADE_CUSTOM_PARAM_ID )
|
||||||
|
params->_writeRawConstant(constantEntry.physicalIndex, mTextureFadeFactor);
|
||||||
|
else
|
||||||
|
Renderable::_updateCustomGpuParameter(constantEntry, params);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
float TerrainMesh::getVertexHeight(int x, int y) {
|
||||||
|
return getVertex(x,y);
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
Ogre::Vector3 TerrainMesh::getVertexPosition(int x, int y) {
|
||||||
|
return Ogre::Vector3(x*getVertexSeperation(), getVertexHeight(x,y) , y*getVertexSeperation());
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::calculateVetexValues() {
|
||||||
|
using namespace Ogre;
|
||||||
|
|
||||||
|
//get the texture offsets for the higher uv
|
||||||
|
float xUVOffset = 0;
|
||||||
|
float yUVOffset = 0;
|
||||||
|
|
||||||
|
if ( g_heightMap->isTextureFadingEnabled() ) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
switch (mInterface->getLocation()) {
|
||||||
|
case Quad::QL_NW :
|
||||||
|
yUVOffset = 32.0f/64.0f;
|
||||||
|
break;
|
||||||
|
case Quad::QL_NE:
|
||||||
|
yUVOffset = 32.0f/64.0f;
|
||||||
|
xUVOffset = 32.0f/64.0f;
|
||||||
|
break;
|
||||||
|
case Quad::QL_SE:
|
||||||
|
xUVOffset = 32.0f/64.0f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int start = 0;
|
||||||
|
int end = mWidth;
|
||||||
|
|
||||||
|
if ( mUseSkirts ) {
|
||||||
|
--start;
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
|
||||||
|
float* verts = static_cast<float*>(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD));
|
||||||
|
for ( int y = start; y < end; y++ ) {
|
||||||
|
for ( int x = start; x < end; x++ ) {
|
||||||
|
|
||||||
|
//the skirts
|
||||||
|
if ( y < 0 || y > (mWidth-1) || x < 0 || x > (mWidth-1) ) {
|
||||||
|
|
||||||
|
if ( x < 0 ) *verts++ = 0;
|
||||||
|
else if ( x > (mWidth-1) ) *verts++ = (mWidth-1)*getVertexSeperation();
|
||||||
|
else *verts++ = x*getVertexSeperation();
|
||||||
|
|
||||||
|
*verts++ = -4096; //2048 below base sea floor height
|
||||||
|
|
||||||
|
if ( y < 0 ) *verts++ = 0;
|
||||||
|
else if ( y > (mWidth-1) ) *verts++ = (mWidth-1)*getVertexSeperation();
|
||||||
|
else *verts++ = y*getVertexSeperation();
|
||||||
|
|
||||||
|
|
||||||
|
for ( Ogre::uint i = 0; i < 3; i++ )
|
||||||
|
*verts++ = 0;
|
||||||
|
|
||||||
|
float u = (float)(x) / (mWidth-1);
|
||||||
|
float v = (float)(y) / (mWidth-1);
|
||||||
|
|
||||||
|
//clamped, so shouldn't matter if > 1
|
||||||
|
|
||||||
|
*verts++ = u;
|
||||||
|
*verts++ = v;
|
||||||
|
|
||||||
|
if ( g_heightMap->isTextureFadingEnabled() ) {
|
||||||
|
*verts++ = u;
|
||||||
|
*verts++ = v;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
assert(y*mWidth+x>=0&&y*mWidth+x<mWidth*mWidth);
|
||||||
|
|
||||||
|
//verts
|
||||||
|
*verts++ = x*getVertexSeperation();
|
||||||
|
*verts++ = getVertexHeight(x,y);
|
||||||
|
*verts++ = y*getVertexSeperation();
|
||||||
|
|
||||||
|
mMax = std::max(mMax, getVertexHeight(x,y));
|
||||||
|
mMin = std::min(mMin, getVertexHeight(x,y));
|
||||||
|
|
||||||
|
//normals
|
||||||
|
for ( Ogre::uint i = 0; i < 3; i++ )
|
||||||
|
*verts++ = getNormal(x,y,i);
|
||||||
|
//*verts++ = mInterface->getNormal((y*mWidth+x)*3+i);
|
||||||
|
|
||||||
|
const float u = (float)(x) / (mWidth-1);
|
||||||
|
const float v = (float)(y) / (mWidth-1);
|
||||||
|
assert(u>=0&&v>=0);
|
||||||
|
assert(u<=1&&v<=1);
|
||||||
|
|
||||||
|
*verts++ = u;
|
||||||
|
*verts++ = v;
|
||||||
|
|
||||||
|
if ( g_heightMap->isTextureFadingEnabled() ) {
|
||||||
|
*verts++ = u/2.0f + xUVOffset;
|
||||||
|
*verts++ = v/2.0f + yUVOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mMainBuffer->unlock();
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::setBounds() {
|
||||||
|
mBounds.setExtents(0,mMin,0,
|
||||||
|
(mWidth - 1) * getVertexSeperation(),
|
||||||
|
mMax,
|
||||||
|
(mWidth - 1) * getVertexSeperation());
|
||||||
|
|
||||||
|
mCenter = Ogre::Vector3( ( (mWidth - 1) * getVertexSeperation() ) / 2,
|
||||||
|
( mMin + mMax ) / 2,
|
||||||
|
( (mWidth - 1) * getVertexSeperation() ) / 2);
|
||||||
|
|
||||||
|
mBoundingRadius = (mBounds.getMaximum() - mBounds.getMinimum()).length() / 2;
|
||||||
|
}
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::createVertexBuffer() {
|
||||||
|
using namespace Ogre;
|
||||||
|
|
||||||
|
size_t vw = mWidth;
|
||||||
|
if ( mUseSkirts ) vw += 2;
|
||||||
|
|
||||||
|
mVertexes = new VertexData();
|
||||||
|
mVertexes->vertexStart = 0;
|
||||||
|
mVertexes->vertexCount = vw*vw;// VERTEX_WIDTH;
|
||||||
|
|
||||||
|
VertexDeclaration* vertexDecl = mVertexes->vertexDeclaration;
|
||||||
|
size_t currOffset = 0;
|
||||||
|
|
||||||
|
vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_POSITION);
|
||||||
|
currOffset += VertexElement::getTypeSize(VET_FLOAT3);
|
||||||
|
|
||||||
|
vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT3, VES_NORMAL);
|
||||||
|
currOffset += VertexElement::getTypeSize(VET_FLOAT3);
|
||||||
|
|
||||||
|
|
||||||
|
vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
|
||||||
|
currOffset += VertexElement::getTypeSize(VET_FLOAT2);
|
||||||
|
|
||||||
|
if ( g_heightMap->isTextureFadingEnabled() ) {
|
||||||
|
vertexDecl->addElement(MAIN_BINDING, currOffset, VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 1);
|
||||||
|
currOffset += VertexElement::getTypeSize(VET_FLOAT2);
|
||||||
|
}
|
||||||
|
|
||||||
|
mMainBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
|
||||||
|
vertexDecl->getVertexSize(0), // size of one whole vertex
|
||||||
|
mVertexes->vertexCount, // number of vertices
|
||||||
|
HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
|
||||||
|
false); // no shadow buffer
|
||||||
|
|
||||||
|
mVertexes->vertexBufferBinding->setBinding(MAIN_BINDING, mMainBuffer); //bind the data
|
||||||
|
|
||||||
|
if ( g_heightMap->isMorphingEnabled() )
|
||||||
|
vertexDecl->addElement(DELTA_BINDING, 0, VET_FLOAT1, VES_BLEND_WEIGHTS);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::HardwareVertexBufferSharedPtr TerrainMesh::createDeltaBuffer( ) {
|
||||||
|
size_t vw = mWidth;
|
||||||
|
if ( mUseSkirts ) vw += 2;
|
||||||
|
|
||||||
|
const size_t totalVerts = (vw * vw);
|
||||||
|
return Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
|
||||||
|
Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT1),
|
||||||
|
totalVerts,
|
||||||
|
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
|
||||||
|
false); //no shadow buff
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------
|
||||||
|
#define SET_DELTA_AT(x, y, v) \
|
||||||
|
if ( mUseSkirts ) pDeltas[( y + 1)*vw+ x + 1] = v; \
|
||||||
|
else pDeltas[( y)*vw+ x] = v;
|
||||||
|
void TerrainMesh::calculateDeltaValues() {
|
||||||
|
|
||||||
|
using namespace Ogre;
|
||||||
|
size_t vw = mWidth;
|
||||||
|
if ( mUseSkirts ) vw += 2;
|
||||||
|
|
||||||
|
//must be using morphing to use this function
|
||||||
|
assert(g_heightMap->isMorphingEnabled());
|
||||||
|
|
||||||
|
const size_t step = 2;
|
||||||
|
|
||||||
|
// Create a set of delta values
|
||||||
|
mDeltaBuffer = createDeltaBuffer();
|
||||||
|
float* pDeltas = static_cast<float*>(mDeltaBuffer->lock(HardwareBuffer::HBL_DISCARD));
|
||||||
|
memset(pDeltas, 0, (vw)*(vw) * sizeof(float));
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool flag=false;
|
||||||
|
for ( size_t y = 0; y < mWidth-step; y += step ) {
|
||||||
|
for ( size_t x = 0; x < mWidth-step; x += step ) {
|
||||||
|
//create the diffrence between the full vertex if the vertex wasn't their
|
||||||
|
|
||||||
|
float bottom_left = getVertexHeight(x,y);
|
||||||
|
float bottom_right = getVertexHeight(x+step,y);
|
||||||
|
|
||||||
|
float top_left = getVertexHeight(x,y+step);
|
||||||
|
float top_right = getVertexHeight(x+step,y+step);
|
||||||
|
|
||||||
|
//const int vw = mWidth+2;
|
||||||
|
SET_DELTA_AT(x, y+1, (bottom_left+top_left)/2 - getVertexHeight(x, y+1)) //left
|
||||||
|
SET_DELTA_AT(x+2, y+1, (bottom_right+top_right)/2 - getVertexHeight(x+2, y+1)) //right
|
||||||
|
|
||||||
|
SET_DELTA_AT(x+1, y+2, (top_right+top_left)/2 - getVertexHeight(x+1, y+2)) //top
|
||||||
|
SET_DELTA_AT(x+1, y, (bottom_right+bottom_left)/2 - getVertexHeight(x+1, y)) //bottom
|
||||||
|
|
||||||
|
//this might not be correct
|
||||||
|
if ( !flag )
|
||||||
|
SET_DELTA_AT(x+1, y+1, (bottom_left+top_right)/2 - getVertexHeight(x+1, y+1)) //center
|
||||||
|
else
|
||||||
|
SET_DELTA_AT(x+1, y+1, (bottom_right+top_left)/2 - getVertexHeight(x+1, y+1)) //center
|
||||||
|
|
||||||
|
flag = !flag;
|
||||||
|
}
|
||||||
|
flag = !flag; //flip tries for next row
|
||||||
|
}
|
||||||
|
|
||||||
|
mDeltaBuffer->unlock();
|
||||||
|
mVertexes->vertexBufferBinding->setBinding(DELTA_BINDING,mDeltaBuffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
#undef SET_DELTA_AT
|
||||||
|
|
||||||
|
//----------------------------------------------
|
||||||
|
void TerrainMesh::calculateIndexValues() {
|
||||||
|
using namespace Ogre;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t vw = mWidth-1;
|
||||||
|
if ( mUseSkirts ) vw += 2;
|
||||||
|
|
||||||
|
const size_t indexCount = (vw)*(vw)*6;
|
||||||
|
|
||||||
|
//need to manage allocation if not null
|
||||||
|
assert(mIndices==0);
|
||||||
|
|
||||||
|
mIndices = new IndexData();
|
||||||
|
mIndices->indexCount = indexCount;
|
||||||
|
mIndices->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
|
||||||
|
HardwareIndexBuffer::IT_16BIT,
|
||||||
|
indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
|
||||||
|
|
||||||
|
unsigned short* indices = static_cast<unsigned short*>(mIndices->indexBuffer->lock(0,
|
||||||
|
mIndices->indexBuffer->getSizeInBytes(),
|
||||||
|
HardwareBuffer::HBL_DISCARD));
|
||||||
|
|
||||||
|
bool flag = false;
|
||||||
|
Ogre::uint indNum = 0;
|
||||||
|
for ( Ogre::uint y = 0; y < (vw); y+=1 ) {
|
||||||
|
for ( Ogre::uint x = 0; x < (vw); x+=1 ) {
|
||||||
|
|
||||||
|
const int line1 = y * (vw+1) + x;
|
||||||
|
const int line2 = (y + 1) * (vw+1) + x;
|
||||||
|
|
||||||
|
if ( flag ) {
|
||||||
|
*indices++ = line1;
|
||||||
|
*indices++ = line2;
|
||||||
|
*indices++ = line1 + 1;
|
||||||
|
|
||||||
|
*indices++ = line1 + 1;
|
||||||
|
*indices++ = line2;
|
||||||
|
*indices++ = line2 + 1;
|
||||||
|
} else {
|
||||||
|
*indices++ = line1;
|
||||||
|
*indices++ = line2;
|
||||||
|
*indices++ = line2 + 1;
|
||||||
|
|
||||||
|
*indices++ = line1;
|
||||||
|
*indices++ = line2 + 1;
|
||||||
|
*indices++ = line1 + 1;
|
||||||
|
}
|
||||||
|
flag = !flag; //flip tris for next time
|
||||||
|
|
||||||
|
indNum+=6;
|
||||||
|
}
|
||||||
|
flag = !flag; //flip tries for next row
|
||||||
|
}
|
||||||
|
assert(indNum==indexCount);
|
||||||
|
mIndices->indexBuffer->unlock();
|
||||||
|
//return mIndices;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user