- 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;
|
|
||||||
};
|
|
Loading…
Reference in New Issue