Move terrain grid implementation to a component so the editor can use it (Feature #1597)

This commit is contained in:
scrawl 2014-08-07 20:43:33 +02:00
parent 982453d4f6
commit 8c26f802e6
5 changed files with 14 additions and 19 deletions

View file

@ -23,7 +23,7 @@ add_openmw_dir (mwrender
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
actors objects renderinginterface localmap occlusionquery water shadows
characterpreview globalmap videoplayer ripplesimulation refraction
terrainstorage renderconst effectmanager weaponanimation terraingrid
terrainstorage renderconst effectmanager weaponanimation
)
add_openmw_dir (mwinput

View file

@ -23,6 +23,7 @@
#include <components/settings/settings.hpp>
#include <components/terrain/defaultworld.hpp>
#include <components/terrain/terraingrid.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
@ -45,7 +46,6 @@
#include "globalmap.hpp"
#include "terrainstorage.hpp"
#include "effectmanager.hpp"
#include "terraingrid.hpp"
using namespace MWRender;
using namespace Ogre;
@ -1045,7 +1045,7 @@ void RenderingManager::enableTerrain(bool enable)
mTerrain = new Terrain::DefaultWorld(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY, 1, 64);
else
mTerrain = new MWRender::TerrainGrid(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
mTerrain = new Terrain::TerrainGrid(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY);
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
Settings::Manager::getBool("split", "Shadows"));

View file

@ -1,167 +0,0 @@
#include "terraingrid.hpp"
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <OgreAxisAlignedBox.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include <components/terrain/chunk.hpp>
namespace MWRender
{
TerrainGrid::TerrainGrid(Ogre::SceneManager *sceneMgr, Terrain::Storage *storage, int visibilityFlags, bool shaders, Terrain::Alignment align)
: Terrain::World(sceneMgr, storage, visibilityFlags, shaders, align)
, mVisible(true)
{
mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
}
TerrainGrid::~TerrainGrid()
{
while (!mGrid.empty())
{
unloadCell(mGrid.begin()->first.first, mGrid.begin()->first.second);
}
mSceneMgr->destroySceneNode(mRootNode);
}
void TerrainGrid::update(const Ogre::Vector3 &cameraPos)
{
}
void TerrainGrid::loadCell(int x, int y)
{
if (mGrid.find(std::make_pair(x, y)) != mGrid.end())
return; // already loaded
Ogre::Vector2 center(x+0.5, y+0.5);
float minH, maxH;
if (!mStorage->getMinMaxHeights(1, center, minH, maxH))
return; // no terrain defined
Ogre::Vector3 min (-0.5*mStorage->getCellWorldSize(),
-0.5*mStorage->getCellWorldSize(),
minH);
Ogre::Vector3 max (0.5*mStorage->getCellWorldSize(),
0.5*mStorage->getCellWorldSize(),
maxH);
Ogre::AxisAlignedBox bounds(min, max);
GridElement element;
Ogre::Vector2 worldCenter = center*mStorage->getCellWorldSize();
element.mSceneNode = mRootNode->createChildSceneNode(Ogre::Vector3(worldCenter.x, worldCenter.y, 0));
std::vector<float> positions;
std::vector<float> normals;
std::vector<Ogre::uint8> colours;
mStorage->fillVertexBuffers(0, 1, center, mAlign, positions, normals, colours);
element.mChunk = new Terrain::Chunk(mCache.getUVBuffer(), bounds, positions, normals, colours);
element.mChunk->setIndexBuffer(mCache.getIndexBuffer(0));
element.mChunk->setVisibilityFlags(mVisibilityFlags);
element.mChunk->setCastShadows(true);
std::vector<Ogre::PixelBox> blendmaps;
std::vector<Terrain::LayerInfo> layerList;
mStorage->getBlendmaps(1, center, mShaders, blendmaps, layerList);
element.mMaterialGenerator.setLayerList(layerList);
// upload blendmaps to GPU
std::vector<Ogre::TexturePtr> blendTextures;
for (std::vector<Ogre::PixelBox>::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it)
{
static int count=0;
Ogre::TexturePtr map = Ogre::TextureManager::getSingleton().createManual("terrain/blend/"
+ Ogre::StringConverter::toString(count++), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D, it->getWidth(), it->getHeight(), 0, it->format);
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(it->data, it->getWidth()*it->getHeight()*Ogre::PixelUtil::getNumElemBytes(it->format), true));
map->loadRawData(stream, it->getWidth(), it->getHeight(), it->format);
blendTextures.push_back(map);
}
element.mMaterialGenerator.setBlendmapList(blendTextures);
element.mSceneNode->attachObject(element.mChunk);
updateMaterial(element);
mGrid[std::make_pair(x,y)] = element;
}
void TerrainGrid::updateMaterial(GridElement &element)
{
element.mMaterialGenerator.enableShadows(getShadowsEnabled());
element.mMaterialGenerator.enableSplitShadows(getSplitShadowsEnabled());
element.mChunk->setMaterial(element.mMaterialGenerator.generate());
}
void TerrainGrid::unloadCell(int x, int y)
{
Grid::iterator it = mGrid.find(std::make_pair(x,y));
if (it == mGrid.end())
return;
GridElement& element = it->second;
delete element.mChunk;
element.mChunk = NULL;
const std::vector<Ogre::TexturePtr>& blendmaps = element.mMaterialGenerator.getBlendmapList();
for (std::vector<Ogre::TexturePtr>::const_iterator it = blendmaps.begin(); it != blendmaps.end(); ++it)
Ogre::TextureManager::getSingleton().remove((*it)->getName());
mSceneMgr->destroySceneNode(element.mSceneNode);
element.mSceneNode = NULL;
mGrid.erase(it);
}
void TerrainGrid::applyMaterials(bool shadows, bool splitShadows)
{
mShadows = shadows;
mSplitShadows = splitShadows;
for (Grid::iterator it = mGrid.begin(); it != mGrid.end(); ++it)
{
updateMaterial(it->second);
}
}
bool TerrainGrid::getVisible()
{
return mVisible;
}
void TerrainGrid::setVisible(bool visible)
{
mVisible = visible;
mRootNode->setVisible(visible);
}
Ogre::AxisAlignedBox TerrainGrid::getWorldBoundingBox (const Ogre::Vector2& center)
{
int cellX, cellY;
MWBase::Environment::get().getWorld()->positionToIndex(center.x, center.y, cellX, cellY);
Grid::iterator it = mGrid.find(std::make_pair(cellX, cellY));
if (it == mGrid.end())
return Ogre::AxisAlignedBox::BOX_NULL;
Terrain::Chunk* chunk = it->second.mChunk;
Ogre::SceneNode* node = it->second.mSceneNode;
Ogre::AxisAlignedBox box = chunk->getBoundingBox();
box = Ogre::AxisAlignedBox(box.getMinimum() + node->getPosition(), box.getMaximum() + node->getPosition());
return box;
}
void TerrainGrid::syncLoad()
{
}
}

View file

@ -1,75 +0,0 @@
#ifndef OPENMW_MWRENDER_TERRAINGRID_H
#define OPENMW_MWRENDER_TERRAINGRID_H
#include <components/terrain/world.hpp>
#include <components/terrain/material.hpp>
namespace Terrain
{
class Chunk;
}
namespace MWRender
{
struct GridElement
{
Ogre::SceneNode* mSceneNode;
Terrain::MaterialGenerator mMaterialGenerator;
Terrain::Chunk* mChunk;
};
/// @brief Simple terrain implementation that loads cells in a grid, with no LOD
class TerrainGrid : public Terrain::World
{
public:
/// @note takes ownership of \a storage
/// @param sceneMgr scene manager to use
/// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..)
/// @param visbilityFlags visibility flags for the created meshes
/// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually
/// faster so this is just here for compatibility.
/// @param align The align of the terrain, see Alignment enum
TerrainGrid(Ogre::SceneManager* sceneMgr,
Terrain::Storage* storage, int visibilityFlags, bool shaders, Terrain::Alignment align);
~TerrainGrid();
/// Update chunk LODs according to this camera position
virtual void update (const Ogre::Vector3& cameraPos);
virtual void loadCell(int x, int y);
virtual void unloadCell(int x, int y);
/// Get the world bounding box of a chunk of terrain centered at \a center
virtual Ogre::AxisAlignedBox getWorldBoundingBox (const Ogre::Vector2& center);
/// Show or hide the whole terrain
/// @note this setting may be invalidated once you call Terrain::update, so do not call it while the terrain should be hidden
virtual void setVisible(bool visible);
virtual bool getVisible();
/// Recreate materials used by terrain chunks. This should be called whenever settings of
/// the material factory are changed. (Relying on the factory to update those materials is not
/// enough, since turning a feature on/off can change the number of texture units available for layer/blend
/// textures, and to properly respond to this we may need to change the structure of the material, such as
/// adding or removing passes. This can only be achieved by a full rebuild.)
virtual void applyMaterials(bool shadows, bool splitShadows);
/// Wait until all background loading is complete.
virtual void syncLoad();
private:
void updateMaterial (GridElement& element);
typedef std::map<std::pair<int, int>, GridElement> Grid;
Grid mGrid;
Ogre::SceneNode* mRootNode;
bool mVisible;
};
}
#endif