forked from mirror/openmw-tes3mp
- started code cleanup/rewrite
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@113 ea6a568a-9f4f-0410-981a-c910a81bb256actorid
parent
a46804dae3
commit
2ac9503854
@ -1,110 +0,0 @@
|
||||
MeshInterface::MeshInterface(Quad* p, Terrain* t) :
|
||||
mParentQuad(p),
|
||||
mTerrain(t),
|
||||
mMax(0),
|
||||
mMin(0),
|
||||
mSplitState(SS_NONE) {
|
||||
|
||||
mQuadData = t->getTerrainData()->getData(mParentQuad);
|
||||
|
||||
//the mesh is created a zero, so an offset is applied
|
||||
const Ogre::Vector3 pos(mParentQuad->getPosition().x - mParentQuad->getSideLength()/2,
|
||||
0,
|
||||
mParentQuad->getPosition().y - mParentQuad->getSideLength()/2);
|
||||
|
||||
mSceneNode = mTerrain->getTerrainSceneNode()->createChildSceneNode(pos);
|
||||
}
|
||||
|
||||
MeshInterface::~MeshInterface() {
|
||||
for ( std::vector<TerrainObjectGroup*>::iterator itr = mTerrainObjects.begin();
|
||||
itr != mTerrainObjects.end();
|
||||
++itr )
|
||||
delete *itr;
|
||||
|
||||
mSceneNode->removeAndDestroyAllChildren();
|
||||
mSceneMgr->destroySceneNode(mSceneNode);
|
||||
|
||||
mTerrain->getTerrainSceneNode()->detachAllObjects();
|
||||
|
||||
mTerrain->_quadDestroyed(mQuadData);
|
||||
delete mQuadData;
|
||||
|
||||
}
|
||||
|
||||
void MeshInterface::create() {
|
||||
//LOG("Creating");
|
||||
if ( mParentQuad->getDepth() == mTerrain->getMaxDepth() ) {
|
||||
for ( int y = 0; y < 4; ++y ) {
|
||||
for ( int x = 0; x < 4; ++x ) {
|
||||
addNewObject(
|
||||
Ogre::Vector3(x*16*128, 0, y*16*128), //pos
|
||||
17, //size
|
||||
false, //skirts
|
||||
0.25f, float(x)/4.0f, float(y)/4.0f); //quad seg location
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addNewObject(Ogre::Vector3(0,0,0), 65);
|
||||
}
|
||||
|
||||
getBounds();
|
||||
mTerrain->_quadCreated(mQuadData);
|
||||
}
|
||||
|
||||
void MeshInterface::addNewObject(const Ogre::Vector3& pos,
|
||||
int terrainSize,
|
||||
bool skirts /*= true*/,
|
||||
float segmentSize /*= 1*/,
|
||||
float startX /*= 0*/,
|
||||
float startY /*= 0*/ ) {
|
||||
|
||||
TerrainObjectGroup* to = new TerrainObjectGroup();
|
||||
|
||||
to->segment = new QuadSegment(mQuadData, segmentSize, startX, startY);
|
||||
to->node = mSceneNode->createChildSceneNode(pos);
|
||||
to->terrain = new TerrainRenderable(mTerrain, to->segment, terrainSize, mParentQuad->getDepth(), skirts);
|
||||
to->terrain->create(to->node);
|
||||
|
||||
mMax = std::max(to->terrain->getMax(), mMax);
|
||||
mMin = std::max(to->terrain->getMin(), mMin);
|
||||
|
||||
mTerrainObjects.push_back(to);
|
||||
}
|
||||
|
||||
void MeshInterface::update(Ogre::Real time) {
|
||||
const Ogre::Vector3 cpos = mCamera->getDerivedPosition();
|
||||
Ogre::Vector3 diff(0, 0, 0);
|
||||
|
||||
//copy?
|
||||
Ogre::AxisAlignedBox worldBounds = mBounds;
|
||||
worldBounds.transformAffine(mSceneNode->_getFullTransform());
|
||||
|
||||
diff.makeFloor(cpos - worldBounds.getMinimum() );
|
||||
diff.makeCeil(cpos - worldBounds.getMaximum() );
|
||||
const Ogre::Real camDist = diff.squaredLength();
|
||||
|
||||
mSplitState = SS_NONE;
|
||||
if ( camDist < mSplitDistance ) mSplitState = SS_SPLIT;
|
||||
else if ( camDist > mUnsplitDistance ) mSplitState = SS_UNSPLIT;
|
||||
|
||||
|
||||
for ( std::vector<TerrainObjectGroup*>::iterator itr = mTerrainObjects.begin();
|
||||
itr != mTerrainObjects.end();
|
||||
++itr )
|
||||
(*itr)->terrain->update(time, camDist, mUnsplitDistance, mMorphDistance);
|
||||
}
|
||||
|
||||
void MeshInterface::getBounds() {
|
||||
mBounds.setExtents( 0,
|
||||
mMin,
|
||||
0,
|
||||
(65 - 1) * mQuadData->getVertexSeperation(),
|
||||
mMax,
|
||||
(65 - 1) * mQuadData->getVertexSeperation());
|
||||
|
||||
mBoundingRadius = (mBounds.getMaximum() - mBounds.getMinimum()).length() / 2;
|
||||
|
||||
mSplitDistance = pow(mBoundingRadius * 0.5, 2);
|
||||
mUnsplitDistance = pow(mBoundingRadius * 2.0, 2);
|
||||
mMorphDistance = pow(mBoundingRadius * 1.5, 2);
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/**
|
||||
* Interface between the quad and the terrain renderble classes, to the
|
||||
* quad it looks like this rendereds a single mesh for the quad. This
|
||||
* may not be the case.
|
||||
*
|
||||
* It also could allow several optomizations (e.g. multiple splits)
|
||||
*/
|
||||
class MeshInterface
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @brief Holds a group of objects and destorys them in the
|
||||
* destructor. Avoids the needs for 100s of vectors
|
||||
*/
|
||||
struct TerrainObjectGroup {
|
||||
/**
|
||||
* @brief inits all ptrs at 0
|
||||
*/
|
||||
inline TerrainObjectGroup() : segment(0), terrain(0), node(0) {}
|
||||
|
||||
/**
|
||||
* @brief destorys all objects
|
||||
*/
|
||||
inline ~TerrainObjectGroup() {
|
||||
if ( node ) {
|
||||
node->detachAllObjects();
|
||||
node->getCreator()->destroySceneNode(node);
|
||||
}
|
||||
delete terrain;
|
||||
delete segment;
|
||||
}
|
||||
QuadSegment* segment;
|
||||
TerrainRenderable* terrain;
|
||||
Ogre::SceneNode* node;
|
||||
};
|
||||
public:
|
||||
enum SplitState { SS_NONE, SS_SPLIT, SS_UNSPLIT };
|
||||
|
||||
MeshInterface(Quad* p, Terrain* t);
|
||||
~MeshInterface() ;
|
||||
|
||||
/**
|
||||
* @brief creates all required meshes. If it is at the max depth, it creates 16, otherwise just one
|
||||
*/
|
||||
void create();
|
||||
|
||||
/**
|
||||
* @brief updates all meshes.
|
||||
* @remarks the camera distance is calculated here so that all terrain has the correct morph levels etc
|
||||
*/
|
||||
void update(Ogre::Real time);
|
||||
|
||||
inline SplitState getSplitState() {
|
||||
return mSplitState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief propergates the just split through all terrain
|
||||
*/
|
||||
inline void justSplit() {
|
||||
for ( std::vector<TerrainObjectGroup*>::iterator itr = mTerrainObjects.begin();
|
||||
itr != mTerrainObjects.end();
|
||||
++itr )
|
||||
(*itr)->terrain->justSplit();
|
||||
}
|
||||
/**
|
||||
* @brief propergates the just unsplit through all terrain
|
||||
*/
|
||||
inline void justUnsplit() {
|
||||
for ( std::vector<TerrainObjectGroup*>::iterator itr = mTerrainObjects.begin();
|
||||
itr != mTerrainObjects.end();
|
||||
++itr )
|
||||
(*itr)->terrain->justUnsplit();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Quad* mParentQuad;
|
||||
Terrain* mTerrain;
|
||||
|
||||
///Must be a ptr, else it destorys before we are ready
|
||||
std::vector<TerrainObjectGroup*> mTerrainObjects;
|
||||
|
||||
Ogre::SceneNode* mSceneNode;
|
||||
|
||||
///use for split distances
|
||||
Ogre::Real mBoundingRadius;
|
||||
Ogre::AxisAlignedBox mBounds;
|
||||
|
||||
///max and min heights
|
||||
float mMax, mMin;
|
||||
|
||||
Ogre::Real mSplitDistance,mUnsplitDistance,mMorphDistance;
|
||||
|
||||
SplitState mSplitState;
|
||||
QuadData* mQuadData;
|
||||
|
||||
/**
|
||||
* @brief sets the bounds and split radius of the object
|
||||
*/
|
||||
void getBounds();
|
||||
|
||||
/**
|
||||
* @brief Adds a new mesh
|
||||
* @param pos the position in relation to mSceneNode
|
||||
* @param terrainSize the size of the terrain in verts. Should be n^2+1
|
||||
* @param skirts true if the terrain should have skirts
|
||||
* @param segmentSize the size of the segment. So if splitting terrain into 4*4, it should be 0.25
|
||||
* @param startX, startY the start position of this segment (0 <= startX < 1)
|
||||
*/
|
||||
void addNewObject(const Ogre::Vector3& pos, int terrainSize,
|
||||
bool skirts = true, float segmentSize = 1,
|
||||
float startX = 0, float startY = 0 );
|
||||
|
||||
|
||||
|
||||
};
|
@ -1,84 +0,0 @@
|
||||
|
||||
/**
|
||||
* @todo mergre with matgen class
|
||||
*/
|
||||
class MWQuadMaterialGen : public QuadMaterialGenerator
|
||||
{
|
||||
public:
|
||||
MWQuadMaterialGen(MaterialGenerator* mg) : mMatGen(mg), mCount(0){}
|
||||
|
||||
Ogre::MaterialPtr getMaterial(QuadData* qd){
|
||||
return _getMaterial((MWQuadData*)qd);
|
||||
}
|
||||
Ogre::MaterialPtr getMaterialSegment(QuadData* qd, QuadSegment* qs){
|
||||
return _getMaterialSegment((MWQuadData*)qd,qs);
|
||||
}
|
||||
private:
|
||||
|
||||
Ogre::MaterialPtr _getMaterial(MWQuadData* qd){
|
||||
assert(qd);
|
||||
const std::string name("MAT" + Ogre::StringConverter::toString(mCount++));
|
||||
|
||||
if ( qd->getTexture().length() ){
|
||||
return mMatGen->generateSingleTexture(name, qd->getTexture(), qd->getUsedResourcesRef());
|
||||
|
||||
}else{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return Ogre::MaterialPtr();
|
||||
}
|
||||
|
||||
Ogre::MaterialPtr _getMaterialSegment(MWQuadData* qd, QuadSegment* qs){
|
||||
const std::string name("MAT" + Ogre::StringConverter::toString(mCount++));
|
||||
|
||||
|
||||
if ( qd->getTexture().length() )
|
||||
assert(0&&"NOT IMPLEMENTED");
|
||||
|
||||
const std::vector<int>& tref = qd->getTextureIndexRef();
|
||||
const int indexSize = sqrt(tref.size());
|
||||
const int cellIndexSize = indexSize - 2;
|
||||
|
||||
|
||||
//plus 1 to take into account border
|
||||
const int xoff = float(cellIndexSize) * qs->getStartX();
|
||||
const int yoff = float(cellIndexSize) * qs->getStartY();
|
||||
const int size = float(cellIndexSize) * qs->getSegmentSize();
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
/*
|
||||
ti.resize((size)*(size));
|
||||
|
||||
for ( int y = 1; y < size+1; ++y ){
|
||||
for ( int x = 1; x < size+1; ++x ){
|
||||
|
||||
if ( y+yoff >= indexSize ) assert(0);
|
||||
if ( x+xoff >= indexSize ) assert(0);
|
||||
|
||||
ti.at((y-1)*(size)+(x-1)) = tref.at((y+yoff)*(indexSize)+(x+xoff));
|
||||
}
|
||||
}
|
||||
*/
|
||||
Ogre::MaterialPtr t = Ogre::MaterialManager::getSingleton().
|
||||
getByName(mMatGen->generateAlphaMap
|
||||
(name,
|
||||
ti,size,
|
||||
1, 1.0f/size,
|
||||
qd->getUsedResourcesRef()));
|
||||
return t;
|
||||
}
|
||||
|
||||
MaterialGenerator* mMatGen;
|
||||
unsigned int mCount;
|
||||
|
||||
};
|
@ -1,145 +0,0 @@
|
||||
/* Represents a segment of a quad. It can also represent a large segment
|
||||
*
|
||||
* this is needed for experimenting with splitting the lowest
|
||||
* quad level into small segments for better culling. Due to the
|
||||
* intented design of using optomized meshes, this should not work on
|
||||
* optomized meshes, as there is no easy way to segment the data
|
||||
*
|
||||
* This uses floating point numbers to define the areas of the
|
||||
* quads. There may be issues due to accuracy if we go to small but it
|
||||
* should be caught in debug mode
|
||||
*/
|
||||
#define QSDEBUG
|
||||
|
||||
class QuadSegment
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param qd the parent quad data
|
||||
* @param size the proportion of the total size that the segment is. Must be greater than 0, but less than or equal to 1
|
||||
* @param x,y the start positions of the segment
|
||||
*/
|
||||
QuadSegment(QuadData* qd, float size = 1, float x = 0, float y = 0)
|
||||
: mQuadData(qd),
|
||||
mSegmentSize(size),
|
||||
mX(x),
|
||||
mY(y)
|
||||
{
|
||||
assert(qd);
|
||||
assert(size>0&&size<=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*size;
|
||||
const int isw = (int)fsw;
|
||||
assert(fsw==isw);
|
||||
}
|
||||
#endif
|
||||
|
||||
//precalc offsets, as getVertex/getNormal get called a lot (1000s of times)
|
||||
computeOffsets();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief lazy function for getting a material
|
||||
*/
|
||||
Ogre::MaterialPtr getMaterial()
|
||||
{
|
||||
if ( mMaterial.isNull() )
|
||||
createMaterial();
|
||||
assert(!mMaterial.isNull());
|
||||
return mMaterial;
|
||||
}
|
||||
|
||||
void createMaterial()
|
||||
{
|
||||
assert(mSegmentSize>0);
|
||||
if ( mSegmentSize == 1 ) //we can use the top level material
|
||||
mMaterial = mQuadData->getMaterial();
|
||||
else //generate a material spesificly for this
|
||||
mMaterial = mQuadData->getMaterialGenerator()->
|
||||
getMaterialSegment(mQuadData,this);
|
||||
assert(!mMaterial.isNull());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
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;
|
||||
Ogre::MaterialPtr mMaterial;
|
||||
|
||||
int mXOffset, mYOffset;
|
||||
};
|
@ -1,229 +1,343 @@
|
||||
/**
|
||||
* @brief Terrain for one cell. Handles building, destroying and LOD morphing
|
||||
*/
|
||||
class TerrainRenderable : public Ogre::Renderable, public Ogre::MovableObject {
|
||||
public:
|
||||
|
||||
explicit TerrainRenderable(Terrain* t, QuadSegment* qs, int width, int depth, bool skirts);
|
||||
|
||||
/**
|
||||
* Calls destroy();
|
||||
*/
|
||||
~TerrainRenderable();
|
||||
|
||||
/**
|
||||
* Creates the actual mesh, it has to be called manually, as it is not called in the constructor
|
||||
*/
|
||||
void create(Ogre::SceneNode* sn) ;
|
||||
|
||||
/**
|
||||
* Can be called manually and can be called from the destuctor. This destroyes the mesh
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* @brief Checks if it needs to be split or unsplit and deals with the morph factor
|
||||
* @brief 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);
|
||||
* @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);
|
||||
}
|
||||
|
||||
virtual const Ogre::MaterialPtr& getMaterial( void ) const {
|
||||
return mMaterial;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
void getRenderOperation( Ogre::RenderOperation& op ) {
|
||||
op.useIndexes = true;
|
||||
op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
|
||||
op.vertexData = mVertexes;
|
||||
op.indexData = mIndices;
|
||||
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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
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);
|
||||
#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));
|
||||
}
|
||||
}
|
||||
|
||||
const Ogre::AxisAlignedBox& getBoundingBox( void ) const {
|
||||
return mBounds;
|
||||
};
|
||||
//-----------------------------------------------------------------------
|
||||
Ogre::Real getBoundingRadius(void) const {
|
||||
return mBoundingRadius;
|
||||
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);
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* @brief sets the bounds on the renderable. This requires that mMin/mMax have been set. They are set in createVertexData
|
||||
* @remarks 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();
|
||||
|
||||
|
||||
const int mWidth;
|
||||
const bool mUseSkirts;
|
||||
|
||||
///true if the land has been built
|
||||
bool mBuilt;
|
||||
|
||||
int mDepth;
|
||||
QuadSegment* mSegment;
|
||||
Terrain* mTerrain;
|
||||
|
||||
Ogre::MaterialPtr mMaterial;
|
||||
|
||||
Ogre::ManualObject* mObject;
|
||||
Ogre::SceneNode* mSceneNode;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* @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;
|
||||
#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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue