Merge of corristo's terrain rendering and fixes so that the terrain is correctly positioned and rendered

actorid
Jacob Essex 13 years ago
parent 51d5c7cd59
commit 18108c02a7

@ -188,6 +188,7 @@ find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED)
include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE
${OGRE_Terrain_INCLUDE_DIR}
${OIS_INCLUDE_DIR} ${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR}
${CMAKE_HOME_DIRECTORY}/extern/caelum/include
@ -259,6 +260,16 @@ if (APPLE)
configure_file(${OGRE_PLUGIN_DIR}/Plugin_ParticleFX.dylib
"${APP_BUNDLE_DIR}/Contents/Plugins/Plugin_ParticleFX.dylib" COPYONLY)
# prepare components
configure_file(${OGRE_LIB_DIR}/libOgrePaging.dylib
"${APP_BUNDLE_DIR}/Contents/Components/libOgrePaging.dylib" COPYONLY)
configure_file(${OGRE_LIB_DIR}/libOgreTerrain.dylib
"${APP_BUNDLE_DIR}/Contents/Components/libOgreTerrain.dylib" COPYONLY)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${APP_BUNDLE_DIR}/Contents/MacOS/openmw.cfg")
endif (APPLE)

@ -16,7 +16,7 @@ set(GAME_HEADER
source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender
renderingmanager debugging sky player npcs creatures objects renderinginterface
renderingmanager debugging sky terrain player npcs creatures objects renderinginterface
)
add_openmw_dir (mwinput
@ -75,6 +75,7 @@ add_definitions(${SOUND_DEFINE})
target_link_libraries(openmw
${OGRE_LIBRARIES}
${OGRE_Terrain_LIBRARY}
${OIS_LIBRARIES}
${Boost_LIBRARIES}
${OPENAL_LIBRARY}

@ -26,6 +26,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
{
rend.createScene("PlayerCam", 55, 5);
mSkyManager = MWRender::SkyManager::create(rend.getWindow(), rend.getCamera(), resDir);
mTerrainManager = new TerrainManager(rend.getScene());
// Set default mipmap level (NB some APIs ignore this)
TextureManager::getSingleton().setDefaultNumMipmaps(5);
@ -59,6 +60,7 @@ RenderingManager::~RenderingManager ()
{
delete mPlayer;
delete mSkyManager;
delete mTerrainManager;
}
MWRender::Npcs& RenderingManager::getNPCs(){
@ -76,11 +78,13 @@ MWRender::Player& RenderingManager::getPlayer(){
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store){
objects.removeCell(store);
mTerrainManager->cellRemoved(store);
}
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
{
objects.buildStaticGeometry (*store);
mTerrainManager->cellAdded(store);
}
void RenderingManager::addObject (const MWWorld::Ptr& ptr){

@ -3,6 +3,7 @@
#include "sky.hpp"
#include "terrain.hpp"
#include "debugging.hpp"
#include "../mwworld/class.hpp"
@ -97,6 +98,7 @@ class RenderingManager: private RenderingInterface {
void setAmbientMode();
SkyManager* mSkyManager;
TerrainManager* mTerrainManager;
OEngine::Render::OgreRenderer &rend;
Ogre::Camera* camera;
MWRender::Npcs npcs;

@ -0,0 +1,62 @@
#include <OgreTerrain.h>
#include <OgreTerrainGroup.h>
#include "terrain.hpp"
#include "components/esm/loadland.hpp"
namespace MWRender
{
TerrainManager::TerrainManager(Ogre::SceneManager* mgr)
{
mTerrainGlobals = OGRE_NEW Ogre::TerrainGlobalOptions();
mTerrainGlobals->setMaxPixelError(8);
mTerrainGroup = OGRE_NEW Ogre::TerrainGroup(mgr,
Ogre::Terrain::ALIGN_X_Z, ESM::Land::LAND_SIZE,
ESM::Land::REAL_SIZE);
mTerrainGroup->setOrigin(Ogre::Vector3(ESM::Land::REAL_SIZE/2,
0,
-ESM::Land::REAL_SIZE/2));
Ogre::Terrain::ImportData importSettings =
mTerrainGroup->getDefaultImportSettings();
importSettings.terrainSize = ESM::Land::LAND_SIZE;
importSettings.worldSize = ESM::Land::REAL_SIZE;
importSettings.minBatchSize = 9;
importSettings.maxBatchSize = 33;
importSettings.deleteInputData = false;
}
TerrainManager::~TerrainManager()
{
OGRE_DELETE mTerrainGroup;
OGRE_DELETE mTerrainGlobals;
}
void TerrainManager::cellAdded(MWWorld::Ptr::CellStore *store)
{
int x = store->cell->getGridX();
int y = store->cell->getGridY();
Ogre::Terrain::ImportData terrainData;
terrainData.inputBias = 0;
terrainData.inputFloat = store->land->landData->heights;
mTerrainGroup->defineTerrain(x, y, &terrainData);
mTerrainGroup->loadTerrain(x, y, true);
}
void TerrainManager::cellRemoved(MWWorld::Ptr::CellStore *store)
{
mTerrainGroup->removeTerrain(store->cell->getGridX(),
store->cell->getGridY());
}
}

@ -0,0 +1,31 @@
#ifndef _GAME_RENDER_TERRAIN_H
#define _GAME_RENDER_TERRAIN_H
#include "../mwworld/ptr.hpp"
namespace Ogre{
class SceneManager;
class TerrainGroup;
class TerrainGlobalOptions;
}
namespace MWRender{
/**
* Implements the Morrowind terrain using the Ogre Terrain Component
*/
class TerrainManager{
public:
TerrainManager(Ogre::SceneManager*);
virtual ~TerrainManager();
void cellAdded(MWWorld::Ptr::CellStore* store);
void cellRemoved(MWWorld::Ptr::CellStore* store);
private:
Ogre::TerrainGlobalOptions* mTerrainGlobals;
Ogre::TerrainGroup* mTerrainGroup;
};
}
#endif // _GAME_RENDER_TERRAIN_H

@ -96,10 +96,25 @@ IF (OGRE_INCLUDE_DIR AND OGRE_LIBRARIES)
ENDIF (OGRE_INCLUDE_DIR AND OGRE_LIBRARIES)
IF (OGRE_FOUND)
# find terrain component
find_path(OGRE_Terrain_INCLUDE_DIR NAMES OgreTerrain.h HINTS ${OGRE_INCLUDE_DIR} PATH_SUFFIXES Terrain Components/Terrain/include)
set(OGRE_Terrain_LIBRARY_NAMES "OgreTerrain")
find_library(OGRE_Terrain_LIBRARY NAMES ${OGRE_Terrain_LIBRARY_NAMES} HINTS ${OGRE_LIB_DIR} PATH_SUFFIXES "" "release" "relwithdebinfo" "minsizerel")
if(OGRE_Terrain_INCLUDE_DIR AND OGRE_Terrain_LIBRARY)
SET(OGRE_Terrain_FOUND TRUE)
endif(OGRE_Terrain_INCLUDE_DIR AND OGRE_Terrain_LIBRARY)
IF (NOT OGRE_FIND_QUIETLY)
MESSAGE(STATUS " libraries : ${OGRE_LIBRARIES} from ${OGRE_LIB_DIR}")
MESSAGE(STATUS " includes : ${OGRE_INCLUDE_DIR}")
MESSAGE(STATUS " plugins : ${OGRE_PLUGIN_DIR}")
IF (OGRE_Terrain_FOUND)
MESSAGE(STATUS "Ogre Terrain component found:")
MESSAGE(STATUS " include : ${OGRE_Terrain_INCLUDE_DIR}")
MESSAGE(STATUS " library : ${OGRE_Terrain_LIBRARY}")
ELSE (OGRE_Terrain_FOUND)
MESSAGE(FATAL_ERROR "Required Ogre terrain component not found")
ENDIF (OGRE_Terrain_FOUND)
ENDIF (NOT OGRE_FIND_QUIETLY)
ELSE (OGRE_FOUND)
IF (OGRE_FIND_REQUIRED)

@ -119,6 +119,21 @@ struct Cell
void load(ESMReader &esm);
bool isExterior() const
{
return !(data.flags & Interior);
}
int getGridX() const
{
return data.gridX;
}
int getGridY() const
{
return data.gridY;
}
// Restore the given reader to the stored position. Will try to open
// the file matching the stored file name. If you want to read from
// somewhere other than the file system, you need to pre-open the

@ -19,14 +19,93 @@ void Land::load(ESMReader &esm)
int cnt = 0;
// Skip these here. Load the actual data when the cell is loaded.
if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;}
if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;}
if(esm.isNextSub("WNAM")) esm.skipHSubSize(81);
if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675);
if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);cnt++;}
if (esm.isNextSub("VNML"))
{
esm.skipHSubSize(12675);
cnt++;
}
if (esm.isNextSub("VHGT"))
{
esm.skipHSubSize(4232);
cnt++;
}
if (esm.isNextSub("WNAM"))
{
esm.skipHSubSize(81);
}
if (esm.isNextSub("VCLR"))
{
esm.skipHSubSize(12675);
}
if (esm.isNextSub("VTEX"))
{
esm.skipHSubSize(512);
cnt++;
}
// We need all three of VNML, VHGT and VTEX in order to use the
// landscape.
hasData = (cnt == 3);
dataLoaded = false;
landData = NULL;
}
void Land::loadData(ESMReader &esm)
{
if (dataLoaded)
{
return;
}
landData = new LandData;
if (hasData)
{
esm.restoreContext(context);
//esm.getHNExact(landData->normals, sizeof(VNML), "VNML");
if (esm.isNextSub("VNML"))
{
esm.skipHSubSize(12675);
}
VHGT rawHeights;
esm.getHNExact(&rawHeights, sizeof(VHGT), "VHGT");
int currentHeightOffset = rawHeights.heightOffset;
for (int y = 0; y < LAND_SIZE; y++)
{
currentHeightOffset += rawHeights.heightData[y * LAND_SIZE];
landData->heights[y * LAND_SIZE] = currentHeightOffset * HEIGHT_SCALE;
int tempOffset = currentHeightOffset;
for (int x = 1; x < LAND_SIZE; x++)
{
tempOffset += rawHeights.heightData[y * LAND_SIZE + x];
landData->heights[x + y * LAND_SIZE] = tempOffset * HEIGHT_SCALE;
}
}
}
else
{
for (int i = 0; i < LAND_NUM_VERTS; i++)
{
landData->heights[i] = -256.0f * HEIGHT_SCALE;
}
}
dataLoaded = true;
}
void Land::unloadData()
{
if (dataLoaded)
{
delete landData;
landData = NULL;
dataLoaded = false;
}
}
}

@ -21,7 +21,51 @@ struct Land
bool hasData;
bool dataLoaded;
// number of vertices per side
static const int LAND_SIZE = 65;
// cell terrain size in world coords
static const int REAL_SIZE = 8192;
// total number of vertices
static const int LAND_NUM_VERTS = LAND_SIZE * LAND_SIZE;
static const int HEIGHT_SCALE = 8;
#pragma pack(push,1)
struct VHGT
{
float heightOffset;
int8_t heightData[LAND_NUM_VERTS];
short unknown1;
char unknown2;
};
#pragma pack(pop)
typedef uint8_t VNML[LAND_NUM_VERTS * 3];
struct LandData
{
float heightOffset;
float heights[LAND_NUM_VERTS];
//float normals[LAND_NUM_VERTS * 3];
};
LandData *landData;
void load(ESMReader &esm);
/**
* Actually loads data
*/
void loadData(ESMReader &esm);
/**
* Frees memory allocated for land data
*/
void unloadData();
};
}
#endif

@ -96,7 +96,8 @@ namespace ESMS
State_Unloaded, State_Preloaded, State_Loaded
};
CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded) {}
CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded),
land(NULL) {}
const ESM::Cell *cell;
State mState;
@ -124,6 +125,8 @@ namespace ESMS
CellRefList<Static, D> statics;
CellRefList<Weapon, D> weapons;
const Land* land;
void load (const ESMStore &store, ESMReader &esm)
{
if (mState!=State_Loaded)
@ -135,6 +138,11 @@ namespace ESMS
loadRefs (store, esm);
if ( ! (cell->data.flags & ESM::Cell::Interior) )
{
loadTerrain(cell->data.gridX, cell->data.gridY, store, esm);
}
mState = State_Loaded;
}
}
@ -180,6 +188,29 @@ namespace ESMS
private:
void loadTerrain(int X, int Y, const ESMStore &store, ESMReader &esm)
{
// load terrain
Land *land = store.lands.search(X, Y);
if (land != NULL)
{
land->loadData(esm);
}
this->land = land;
}
void unloadTerrain(int X, int Y, const ESMStore &store) {
Land *land = store.lands.search(X,Y);
// unload terrain
if (land != NULL)
{
land->unloadData();
}
this->land = NULL;
}
template<class Functor, class List>
bool forEachImp (Functor& functor, List& list)
{

@ -235,7 +235,7 @@ namespace ESMS
virtual void listIdentifier (std::vector<std::string>& identifier) const {}
// Find land for the given coordinates. Return null if no data.
const Land *search(int x, int y) const
Land *search(int x, int y) const
{
Lands::const_iterator it = lands.find(x);
if(it==lands.end())

@ -115,7 +115,7 @@ namespace ESMS
recLists[REC_GLOB] = &globals;
recLists[REC_GMST] = &gameSettings;
recLists[REC_INGR] = &ingreds;
//recLists[REC_LAND] = &lands;
recLists[REC_LAND] = &lands;
recLists[REC_LEVC] = &creatureLists;
recLists[REC_LEVI] = &itemLists;
recLists[REC_LIGH] = &lights;

@ -7,6 +7,6 @@ PluginFolder=${OGRE_PLUGIN_DIR}
Plugin=RenderSystem_GL
Plugin=Plugin_ParticleFX
Plugin=Plugin_OctreeSceneManager
# Plugin=Plugin_CgProgramManager
Plugin=Plugin_CgProgramManager

@ -7,6 +7,6 @@ PluginFolder=
Plugin=RenderSystem_GL.dylib
Plugin=Plugin_ParticleFX.dylib
Plugin=Plugin_OctreeSceneManager.dylib
# Plugin=Plugin_CgProgramManager
Plugin=Plugin_CgProgramManager

Loading…
Cancel
Save