forked from mirror/openmw-tes3mp
Merge branch 'master' into occlusionquery
Conflicts: apps/openmw/CMakeLists.txt apps/openmw/mwrender/renderingmanager.cpp apps/openmw/mwrender/renderingmanager.hpp components/esm_store/cell_store.hpp
This commit is contained in:
commit
4a6d034591
34 changed files with 846 additions and 34 deletions
|
@ -201,6 +201,7 @@ if(APPLE)
|
||||||
"Plugin_ParticleFX")
|
"Plugin_ParticleFX")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
|
add_subdirectory( files/)
|
||||||
add_subdirectory( files/mygui )
|
add_subdirectory( files/mygui )
|
||||||
|
|
||||||
# Specify build paths
|
# Specify build paths
|
||||||
|
|
|
@ -95,5 +95,5 @@ else()
|
||||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")
|
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")
|
||||||
|
|
||||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
||||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}launcher.cfg")
|
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.cfg")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -15,7 +15,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||||
|
|
||||||
add_openmw_dir (mwrender
|
add_openmw_dir (mwrender
|
||||||
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
||||||
renderinginterface localmap occlusionquery terrain terrainmaterial
|
renderinginterface localmap occlusionquery terrain terrainmaterial water
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
|
|
@ -315,7 +315,11 @@ void OMW::Engine::go()
|
||||||
|
|
||||||
// This has to be added BEFORE MyGUI is initialized, as it needs
|
// This has to be added BEFORE MyGUI is initialized, as it needs
|
||||||
// to find core.xml here.
|
// to find core.xml here.
|
||||||
|
|
||||||
|
//addResourcesDirectory(mResDir);
|
||||||
|
|
||||||
addResourcesDirectory(mResDir / "mygui");
|
addResourcesDirectory(mResDir / "mygui");
|
||||||
|
addResourcesDirectory(mResDir / "water");
|
||||||
|
|
||||||
// Create the window
|
// Create the window
|
||||||
mOgre->createWindow("OpenMW");
|
mOgre->createWindow("OpenMW");
|
||||||
|
|
|
@ -182,7 +182,9 @@ void HUD::setPlayerPos(const float x, const float y)
|
||||||
}
|
}
|
||||||
|
|
||||||
MapWindow::MapWindow()
|
MapWindow::MapWindow()
|
||||||
: Layout("openmw_map_window_layout.xml"), mGlobal(false)
|
: Layout("openmw_map_window_layout.xml")
|
||||||
|
, mGlobal(false)
|
||||||
|
, mVisible(false)
|
||||||
{
|
{
|
||||||
setCoord(500,0,320,300);
|
setCoord(500,0,320,300);
|
||||||
setText("WorldButton", "World");
|
setText("WorldButton", "World");
|
||||||
|
@ -272,6 +274,17 @@ void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender)
|
||||||
mButton->setCaption( mGlobal ? "Local" : "World" );
|
mButton->setCaption( mGlobal ? "Local" : "World" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocalMapBase::LocalMapBase()
|
||||||
|
: mCurX(0)
|
||||||
|
, mCurY(0)
|
||||||
|
, mInterior(false)
|
||||||
|
, mLocalMap(NULL)
|
||||||
|
, mPrefix()
|
||||||
|
, mChanged(true)
|
||||||
|
, mLayout(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout)
|
void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout)
|
||||||
{
|
{
|
||||||
mLocalMap = widget;
|
mLocalMap = widget;
|
||||||
|
|
|
@ -34,6 +34,7 @@ namespace MWGui
|
||||||
class LocalMapBase
|
class LocalMapBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
LocalMapBase();
|
||||||
void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout);
|
void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout);
|
||||||
|
|
||||||
void setCellPrefix(const std::string& prefix);
|
void setCellPrefix(const std::string& prefix);
|
||||||
|
@ -85,6 +86,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MapWindow();
|
MapWindow();
|
||||||
|
virtual ~MapWindow(){}
|
||||||
|
|
||||||
void setVisible(bool b);
|
void setVisible(bool b);
|
||||||
void setPlayerPos(const float x, const float y);
|
void setPlayerPos(const float x, const float y);
|
||||||
|
|
|
@ -88,19 +88,66 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||||
NifOgre::NIFLoader::load(mesh);
|
NifOgre::NIFLoader::load(mesh);
|
||||||
Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh);
|
Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ogre::Vector3 extents = ent->getBoundingBox().getSize();
|
||||||
|
extents *= insert->getScale();
|
||||||
|
// float size = std::max(std::max(extents.x, extents.y), extents.z);
|
||||||
|
|
||||||
|
bool small = (size < 250); /// \todo config value
|
||||||
|
|
||||||
|
// do not fade out doors. that will cause holes and look stupid
|
||||||
|
if (ptr.getTypeName().find("Door") != std::string::npos)
|
||||||
|
small = false;
|
||||||
|
*/
|
||||||
|
const bool small = false;
|
||||||
|
|
||||||
|
if (mBounds.find(ptr.getCell()) == mBounds.end())
|
||||||
|
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
|
||||||
|
|
||||||
|
Ogre::AxisAlignedBox bounds = ent->getBoundingBox();
|
||||||
|
bounds = Ogre::AxisAlignedBox(
|
||||||
|
insert->_getDerivedPosition() + bounds.getMinimum(),
|
||||||
|
insert->_getDerivedPosition() + bounds.getMaximum()
|
||||||
|
);
|
||||||
|
|
||||||
|
bounds.scale(insert->getScale());
|
||||||
|
mBounds[ptr.getCell()].merge(bounds);
|
||||||
|
|
||||||
if(!mIsStatic)
|
if(!mIsStatic)
|
||||||
{
|
{
|
||||||
insert->attachObject(ent);
|
insert->attachObject(ent);
|
||||||
|
|
||||||
|
ent->setRenderingDistance(small ? 2500 : 0); /// \todo config value
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Ogre::StaticGeometry* sg = 0;
|
Ogre::StaticGeometry* sg = 0;
|
||||||
if(mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
|
||||||
|
if (small)
|
||||||
|
{
|
||||||
|
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
|
||||||
{
|
{
|
||||||
uniqueID = uniqueID +1;
|
uniqueID = uniqueID +1;
|
||||||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||||
//Create the scenenode and put it in the map
|
mStaticGeometrySmall[ptr.getCell()] = sg;
|
||||||
|
|
||||||
|
sg->setRenderingDistance(2500); /// \todo config value
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sg = mStaticGeometrySmall[ptr.getCell()];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end())
|
||||||
|
{
|
||||||
|
|
||||||
|
uniqueID = uniqueID +1;
|
||||||
|
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||||
mStaticGeometry[ptr.getCell()] = sg;
|
mStaticGeometry[ptr.getCell()] = sg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sg = mStaticGeometry[ptr.getCell()];
|
||||||
|
}
|
||||||
|
|
||||||
// This specifies the size of a single batch region.
|
// This specifies the size of a single batch region.
|
||||||
// If it is set too high:
|
// If it is set too high:
|
||||||
|
@ -110,16 +157,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
||||||
// - there will be too many batches.
|
// - there will be too many batches.
|
||||||
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
|
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
|
||||||
|
|
||||||
mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL;
|
|
||||||
mBounds[ptr.getCell()].merge(ent->getBoundingBox());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sg = mStaticGeometry[ptr.getCell()];
|
|
||||||
}
|
|
||||||
|
|
||||||
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
|
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
|
||||||
mBounds[ptr.getCell()].merge(insert->_getDerivedPosition());
|
|
||||||
|
|
||||||
mRenderer.getScene()->destroyEntity(ent);
|
mRenderer.getScene()->destroyEntity(ent);
|
||||||
}
|
}
|
||||||
|
@ -206,6 +244,13 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store)
|
||||||
mRenderer.getScene()->destroyStaticGeometry (sg);
|
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||||
sg = 0;
|
sg = 0;
|
||||||
}
|
}
|
||||||
|
if(mStaticGeometrySmall.find(store) != mStaticGeometrySmall.end())
|
||||||
|
{
|
||||||
|
Ogre::StaticGeometry* sg = mStaticGeometrySmall[store];
|
||||||
|
mStaticGeometrySmall.erase(store);
|
||||||
|
mRenderer.getScene()->destroyStaticGeometry (sg);
|
||||||
|
sg = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(mBounds.find(store) != mBounds.end())
|
if(mBounds.find(store) != mBounds.end())
|
||||||
mBounds.erase(store);
|
mBounds.erase(store);
|
||||||
|
@ -218,6 +263,11 @@ void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
|
||||||
Ogre::StaticGeometry* sg = mStaticGeometry[&cell];
|
Ogre::StaticGeometry* sg = mStaticGeometry[&cell];
|
||||||
sg->build();
|
sg->build();
|
||||||
}
|
}
|
||||||
|
if(mStaticGeometrySmall.find(&cell) != mStaticGeometrySmall.end())
|
||||||
|
{
|
||||||
|
Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell];
|
||||||
|
sg->build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
|
||||||
|
|
|
@ -14,6 +14,7 @@ class Objects{
|
||||||
OEngine::Render::OgreRenderer &mRenderer;
|
OEngine::Render::OgreRenderer &mRenderer;
|
||||||
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
||||||
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
|
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
|
||||||
|
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
|
||||||
std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds;
|
std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds;
|
||||||
Ogre::SceneNode* mMwRoot;
|
Ogre::SceneNode* mMwRoot;
|
||||||
bool mIsStatic;
|
bool mIsStatic;
|
||||||
|
|
|
@ -58,6 +58,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
||||||
|
|
||||||
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
|
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
|
||||||
|
|
||||||
|
mWater = 0;
|
||||||
|
|
||||||
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
||||||
mSun = 0;
|
mSun = 0;
|
||||||
|
|
||||||
|
@ -95,13 +97,28 @@ OEngine::Render::Fader* RenderingManager::getFader()
|
||||||
return mRendering.getFader();
|
return mRendering.getFader();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store){
|
void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store)
|
||||||
|
{
|
||||||
mObjects.removeCell(store);
|
mObjects.removeCell(store);
|
||||||
mActors.removeCell(store);
|
mActors.removeCell(store);
|
||||||
if (store->cell->isExterior())
|
if (store->cell->isExterior())
|
||||||
mTerrainManager->cellRemoved(store);
|
mTerrainManager->cellRemoved(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderingManager::removeWater ()
|
||||||
|
{
|
||||||
|
if(mWater){
|
||||||
|
delete mWater;
|
||||||
|
mWater = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingManager::toggleWater()
|
||||||
|
{
|
||||||
|
if (mWater)
|
||||||
|
mWater->toggle();
|
||||||
|
}
|
||||||
|
|
||||||
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
|
void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
|
||||||
{
|
{
|
||||||
mObjects.buildStaticGeometry (*store);
|
mObjects.buildStaticGeometry (*store);
|
||||||
|
@ -157,6 +174,27 @@ void RenderingManager::update (float duration){
|
||||||
mRendering.update(duration);
|
mRendering.update(duration);
|
||||||
|
|
||||||
mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealDirection() );
|
mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealDirection() );
|
||||||
|
|
||||||
|
checkUnderwater();
|
||||||
|
}
|
||||||
|
void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){
|
||||||
|
if(store->cell->data.flags & store->cell->HasWater){
|
||||||
|
if(mWater == 0)
|
||||||
|
mWater = new MWRender::Water(mRendering.getCamera(), store->cell);
|
||||||
|
else
|
||||||
|
mWater->changeCell(store->cell);
|
||||||
|
//else
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
removeWater();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingManager::setWaterHeight(const float height)
|
||||||
|
{
|
||||||
|
if (mWater)
|
||||||
|
mWater->setHeight(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::skyEnable ()
|
void RenderingManager::skyEnable ()
|
||||||
|
@ -301,6 +339,11 @@ void RenderingManager::toggleLight()
|
||||||
|
|
||||||
setAmbientMode();
|
setAmbientMode();
|
||||||
}
|
}
|
||||||
|
void RenderingManager::checkUnderwater(){
|
||||||
|
if(mWater){
|
||||||
|
mWater->checkUnderwater( mRendering.getCamera()->getRealPosition().y );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
|
void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName,
|
||||||
int mode, int number)
|
int mode, int number)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "objects.hpp"
|
#include "objects.hpp"
|
||||||
#include "actors.hpp"
|
#include "actors.hpp"
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
|
#include "water.hpp"
|
||||||
#include "localmap.hpp"
|
#include "localmap.hpp"
|
||||||
#include "occlusionquery.hpp"
|
#include "occlusionquery.hpp"
|
||||||
|
|
||||||
|
@ -61,6 +62,8 @@ class RenderingManager: private RenderingInterface {
|
||||||
RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment);
|
RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment);
|
||||||
virtual ~RenderingManager();
|
virtual ~RenderingManager();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual MWRender::Player& getPlayer(); /// \todo move this to private again as soon as
|
virtual MWRender::Player& getPlayer(); /// \todo move this to private again as soon as
|
||||||
/// MWWorld::Player has been rewritten to not need access
|
/// MWWorld::Player has been rewritten to not need access
|
||||||
/// to internal details of the rendering system anymore
|
/// to internal details of the rendering system anymore
|
||||||
|
@ -77,6 +80,9 @@ class RenderingManager: private RenderingInterface {
|
||||||
/// \todo this function should be removed later. Instead the rendering subsystems should track
|
/// \todo this function should be removed later. Instead the rendering subsystems should track
|
||||||
/// when rebatching is needed and update automatically at the end of each frame.
|
/// when rebatching is needed and update automatically at the end of each frame.
|
||||||
void cellAdded (MWWorld::Ptr::CellStore *store);
|
void cellAdded (MWWorld::Ptr::CellStore *store);
|
||||||
|
void waterAdded(MWWorld::Ptr::CellStore *store);
|
||||||
|
|
||||||
|
void removeWater();
|
||||||
|
|
||||||
void preCellChange (MWWorld::Ptr::CellStore* store);
|
void preCellChange (MWWorld::Ptr::CellStore* store);
|
||||||
///< this event is fired immediately before changing cell
|
///< this event is fired immediately before changing cell
|
||||||
|
@ -88,6 +94,10 @@ class RenderingManager: private RenderingInterface {
|
||||||
void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale);
|
void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale);
|
||||||
void rotateObject (const MWWorld::Ptr& ptr, const::Ogre::Quaternion& orientation);
|
void rotateObject (const MWWorld::Ptr& ptr, const::Ogre::Quaternion& orientation);
|
||||||
|
|
||||||
|
void checkUnderwater();
|
||||||
|
void setWaterHeight(const float height);
|
||||||
|
void toggleWater();
|
||||||
|
|
||||||
/// \param store Cell the object was in previously (\a ptr has already been updated to the new cell).
|
/// \param store Cell the object was in previously (\a ptr has already been updated to the new cell).
|
||||||
void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::Ptr::CellStore *store);
|
void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::Ptr::CellStore *store);
|
||||||
|
|
||||||
|
@ -143,6 +153,8 @@ class RenderingManager: private RenderingInterface {
|
||||||
|
|
||||||
TerrainManager* mTerrainManager;
|
TerrainManager* mTerrainManager;
|
||||||
|
|
||||||
|
MWRender::Water *mWater;
|
||||||
|
|
||||||
OEngine::Render::OgreRenderer &mRendering;
|
OEngine::Render::OgreRenderer &mRendering;
|
||||||
|
|
||||||
MWRender::Objects mObjects;
|
MWRender::Objects mObjects;
|
||||||
|
|
95
apps/openmw/mwrender/water.cpp
Normal file
95
apps/openmw/mwrender/water.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include "water.hpp"
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
|
||||||
|
Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) :
|
||||||
|
mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()),
|
||||||
|
mIsUnderwater(false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Ogre::CompositorManager::getSingleton().addCompositor(mViewport, "Water", -1);
|
||||||
|
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false);
|
||||||
|
} catch(...) {}
|
||||||
|
|
||||||
|
mTop = cell->water;
|
||||||
|
|
||||||
|
mIsUnderwater = false;
|
||||||
|
|
||||||
|
mWaterPlane = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0);
|
||||||
|
|
||||||
|
Ogre::MeshManager::getSingleton().createPlane("water", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,5, Ogre::Vector3::UNIT_Z);
|
||||||
|
|
||||||
|
mWater = mSceneManager->createEntity("water");
|
||||||
|
|
||||||
|
mWater->setMaterialName("Examples/Water0");
|
||||||
|
|
||||||
|
mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode();
|
||||||
|
mWaterNode->setPosition(0, mTop, 0);
|
||||||
|
|
||||||
|
if(!(cell->data.flags & cell->Interior))
|
||||||
|
{
|
||||||
|
mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY));
|
||||||
|
}
|
||||||
|
mWaterNode->attachObject(mWater);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Water::~Water()
|
||||||
|
{
|
||||||
|
Ogre::MeshManager::getSingleton().remove("water");
|
||||||
|
|
||||||
|
mWaterNode->detachObject(mWater);
|
||||||
|
mSceneManager->destroyEntity(mWater);
|
||||||
|
mSceneManager->destroySceneNode(mWaterNode);
|
||||||
|
|
||||||
|
Ogre::CompositorManager::getSingleton().removeCompositorChain(mViewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::changeCell(const ESM::Cell* cell)
|
||||||
|
{
|
||||||
|
mTop = cell->water;
|
||||||
|
|
||||||
|
if(!(cell->data.flags & cell->Interior))
|
||||||
|
mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY));
|
||||||
|
else
|
||||||
|
setHeight(mTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::setHeight(const float height)
|
||||||
|
{
|
||||||
|
mTop = height;
|
||||||
|
mWaterNode->setPosition(0, height, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::toggle()
|
||||||
|
{
|
||||||
|
mWater->setVisible(!mWater->getVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Water::checkUnderwater(float y)
|
||||||
|
{
|
||||||
|
if ((mIsUnderwater && y > mTop) || !mWater->isVisible())
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false);
|
||||||
|
} catch(...) {}
|
||||||
|
mIsUnderwater = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mIsUnderwater && y < mTop && mWater->isVisible())
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", true);
|
||||||
|
} catch(...) {}
|
||||||
|
mIsUnderwater = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY)
|
||||||
|
{
|
||||||
|
return Ogre::Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
40
apps/openmw/mwrender/water.hpp
Normal file
40
apps/openmw/mwrender/water.hpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef GAME_MWRENDER_WATER_H
|
||||||
|
#define GAME_MWRENDER_WATER_H
|
||||||
|
|
||||||
|
#include <Ogre.h>
|
||||||
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
|
namespace MWRender {
|
||||||
|
|
||||||
|
/// Water rendering
|
||||||
|
class Water : Ogre::RenderTargetListener, Ogre::Camera::Listener
|
||||||
|
{
|
||||||
|
static const int CELL_SIZE = 8192;
|
||||||
|
Ogre::Camera *mCamera;
|
||||||
|
Ogre::SceneManager *mSceneManager;
|
||||||
|
Ogre::Viewport *mViewport;
|
||||||
|
|
||||||
|
Ogre::Plane mWaterPlane;
|
||||||
|
Ogre::SceneNode *mWaterNode;
|
||||||
|
Ogre::Entity *mWater;
|
||||||
|
|
||||||
|
bool mIsUnderwater;
|
||||||
|
int mTop;
|
||||||
|
|
||||||
|
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Water (Ogre::Camera *camera, const ESM::Cell* cell);
|
||||||
|
~Water();
|
||||||
|
|
||||||
|
void toggle();
|
||||||
|
|
||||||
|
void checkUnderwater(float y);
|
||||||
|
void changeCell(const ESM::Cell* cell);
|
||||||
|
void setHeight(const float height);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -133,11 +133,70 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OpGetWaterLevel : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context
|
||||||
|
= static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell();
|
||||||
|
runtime.push (cell->mWaterLevel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpSetWaterLevel : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context
|
||||||
|
= static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
Interpreter::Type_Float level = runtime[0].mFloat;
|
||||||
|
|
||||||
|
MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell();
|
||||||
|
|
||||||
|
if (!(cell->cell->data.flags & ESM::Cell::Interior))
|
||||||
|
throw std::runtime_error("Can't set water level in exterior cell");
|
||||||
|
|
||||||
|
cell->mWaterLevel = level;
|
||||||
|
context.getEnvironment().mWorld->setWaterHeight(cell->mWaterLevel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpModWaterLevel : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context
|
||||||
|
= static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
Interpreter::Type_Float level = runtime[0].mFloat;
|
||||||
|
|
||||||
|
MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell();
|
||||||
|
|
||||||
|
if (!(cell->cell->data.flags & ESM::Cell::Interior))
|
||||||
|
throw std::runtime_error("Can't set water level in exterior cell");
|
||||||
|
|
||||||
|
cell->mWaterLevel +=level;
|
||||||
|
context.getEnvironment().mWorld->setWaterHeight(cell->mWaterLevel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const int opcodeCellChanged = 0x2000000;
|
const int opcodeCellChanged = 0x2000000;
|
||||||
const int opcodeCOC = 0x2000026;
|
const int opcodeCOC = 0x2000026;
|
||||||
const int opcodeCOE = 0x200008e;
|
const int opcodeCOE = 0x200008e;
|
||||||
const int opcodeGetInterior = 0x2000131;
|
const int opcodeGetInterior = 0x2000131;
|
||||||
const int opcodeGetPCCell = 0x2000136;
|
const int opcodeGetPCCell = 0x2000136;
|
||||||
|
const int opcodeGetWaterLevel = 0x2000141;
|
||||||
|
const int opcodeSetWaterLevel = 0x2000142;
|
||||||
|
const int opcodeModWaterLevel = 0x2000143;
|
||||||
|
|
||||||
void registerExtensions (Compiler::Extensions& extensions)
|
void registerExtensions (Compiler::Extensions& extensions)
|
||||||
{
|
{
|
||||||
|
@ -146,8 +205,11 @@ namespace MWScript
|
||||||
extensions.registerInstruction ("centeroncell", "S", opcodeCOC);
|
extensions.registerInstruction ("centeroncell", "S", opcodeCOC);
|
||||||
extensions.registerInstruction ("coe", "ll", opcodeCOE);
|
extensions.registerInstruction ("coe", "ll", opcodeCOE);
|
||||||
extensions.registerInstruction ("centeronexterior", "ll", opcodeCOE);
|
extensions.registerInstruction ("centeronexterior", "ll", opcodeCOE);
|
||||||
|
extensions.registerInstruction ("setwaterlevel", "f", opcodeSetWaterLevel);
|
||||||
|
extensions.registerInstruction ("modwaterlevel", "f", opcodeModWaterLevel);
|
||||||
extensions.registerFunction ("getinterior", 'l', "", opcodeGetInterior);
|
extensions.registerFunction ("getinterior", 'l', "", opcodeGetInterior);
|
||||||
extensions.registerFunction ("getpccell", 'l', "c", opcodeGetPCCell);
|
extensions.registerFunction ("getpccell", 'l', "c", opcodeGetPCCell);
|
||||||
|
extensions.registerFunction ("getwaterlevel", 'f', "", opcodeGetWaterLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
|
@ -157,6 +219,9 @@ namespace MWScript
|
||||||
interpreter.installSegment5 (opcodeCOE, new OpCOE);
|
interpreter.installSegment5 (opcodeCOE, new OpCOE);
|
||||||
interpreter.installSegment5 (opcodeGetInterior, new OpGetInterior);
|
interpreter.installSegment5 (opcodeGetInterior, new OpGetInterior);
|
||||||
interpreter.installSegment5 (opcodeGetPCCell, new OpGetPCCell);
|
interpreter.installSegment5 (opcodeGetPCCell, new OpGetPCCell);
|
||||||
|
interpreter.installSegment5 (opcodeGetWaterLevel, new OpGetWaterLevel);
|
||||||
|
interpreter.installSegment5 (opcodeSetWaterLevel, new OpSetWaterLevel);
|
||||||
|
interpreter.installSegment5 (opcodeModWaterLevel, new OpModWaterLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,4 +123,8 @@ op 0x200013d: FadeOut
|
||||||
op 0x200013e: FadeTo
|
op 0x200013e: FadeTo
|
||||||
op 0x200013f: GetCurrentWeather
|
op 0x200013f: GetCurrentWeather
|
||||||
op 0x2000140: ChangeWeather
|
op 0x2000140: ChangeWeather
|
||||||
opcodes 0x2000141-0x3ffffff unused
|
op 0x2000141: GetWaterLevel
|
||||||
|
op 0x2000142: SetWaterLevel
|
||||||
|
op 0x2000143: ModWaterLevel
|
||||||
|
op 0x2000144: ToggleWater, twa
|
||||||
|
opcodes 0x2000145-0x3ffffff unused
|
||||||
|
|
|
@ -175,6 +175,19 @@ namespace MWScript
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OpToggleWater : public Interpreter::Opcode0
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void execute (Interpreter::Runtime& runtime)
|
||||||
|
{
|
||||||
|
InterpreterContext& context =
|
||||||
|
static_cast<InterpreterContext&> (runtime.getContext());
|
||||||
|
|
||||||
|
context.getWorld().toggleWater();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const int opcodeXBox = 0x200000c;
|
const int opcodeXBox = 0x200000c;
|
||||||
const int opcodeOnActivate = 0x200000d;
|
const int opcodeOnActivate = 0x200000d;
|
||||||
const int opcodeActivate = 0x2000075;
|
const int opcodeActivate = 0x2000075;
|
||||||
|
@ -187,6 +200,7 @@ namespace MWScript
|
||||||
const int opcodeFadeIn = 0x200013c;
|
const int opcodeFadeIn = 0x200013c;
|
||||||
const int opcodeFadeOut = 0x200013d;
|
const int opcodeFadeOut = 0x200013d;
|
||||||
const int opcodeFadeTo = 0x200013e;
|
const int opcodeFadeTo = 0x200013e;
|
||||||
|
const int opcodeToggleWater = 0x2000144;
|
||||||
|
|
||||||
void registerExtensions (Compiler::Extensions& extensions)
|
void registerExtensions (Compiler::Extensions& extensions)
|
||||||
{
|
{
|
||||||
|
@ -204,6 +218,8 @@ namespace MWScript
|
||||||
extensions.registerInstruction ("fadein", "f", opcodeFadeIn);
|
extensions.registerInstruction ("fadein", "f", opcodeFadeIn);
|
||||||
extensions.registerInstruction ("fadeout", "f", opcodeFadeOut);
|
extensions.registerInstruction ("fadeout", "f", opcodeFadeOut);
|
||||||
extensions.registerInstruction ("fadeto", "ff", opcodeFadeTo);
|
extensions.registerInstruction ("fadeto", "ff", opcodeFadeTo);
|
||||||
|
extensions.registerInstruction ("togglewater", "", opcodeToggleWater);
|
||||||
|
extensions.registerInstruction ("twa", "", opcodeToggleWater);
|
||||||
}
|
}
|
||||||
|
|
||||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
|
@ -220,6 +236,7 @@ namespace MWScript
|
||||||
interpreter.installSegment5 (opcodeFadeIn, new OpFadeIn);
|
interpreter.installSegment5 (opcodeFadeIn, new OpFadeIn);
|
||||||
interpreter.installSegment5 (opcodeFadeOut, new OpFadeOut);
|
interpreter.installSegment5 (opcodeFadeOut, new OpFadeOut);
|
||||||
interpreter.installSegment5 (opcodeFadeTo, new OpFadeTo);
|
interpreter.installSegment5 (opcodeFadeTo, new OpFadeTo);
|
||||||
|
interpreter.installSegment5 (opcodeToggleWater, new OpToggleWater);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -441,6 +441,27 @@ void OpenAL_Output::init(const std::string &devname)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ALCuint maxtotal = std::min<ALCuint>(maxmono+maxstereo, 256);
|
ALCuint maxtotal = std::min<ALCuint>(maxmono+maxstereo, 256);
|
||||||
|
if (maxtotal == 0) // workaround for broken implementations
|
||||||
|
{
|
||||||
|
maxtotal = 256;
|
||||||
|
bool stop = false;
|
||||||
|
for(size_t i = 0;i < maxtotal && !stop;i++) // generate source until error returned
|
||||||
|
{
|
||||||
|
ALuint src = 0;
|
||||||
|
alGenSources(1, &src);
|
||||||
|
ALenum err = alGetError();
|
||||||
|
if(err != AL_NO_ERROR)
|
||||||
|
{
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFreeSources.push_back(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // normal case
|
||||||
|
{
|
||||||
for(size_t i = 0;i < maxtotal;i++)
|
for(size_t i = 0;i < maxtotal;i++)
|
||||||
{
|
{
|
||||||
ALuint src = 0;
|
ALuint src = 0;
|
||||||
|
@ -449,6 +470,7 @@ void OpenAL_Output::init(const std::string &devname)
|
||||||
mFreeSources.push_back(src);
|
mFreeSources.push_back(src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch(std::exception &e)
|
catch(std::exception &e)
|
||||||
{
|
{
|
||||||
std::cout <<"Error: "<<e.what()<<", trying to continue"<< std::endl;
|
std::cout <<"Error: "<<e.what()<<", trying to continue"<< std::endl;
|
||||||
|
|
|
@ -54,9 +54,11 @@ void insertCellRefList(MWRender::RenderingManager& rendering, MWWorld::Environme
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
void Scene::update (float duration){
|
void Scene::update (float duration){
|
||||||
mRendering.update (duration);
|
mRendering.update (duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::unloadCell (CellStoreCollection::iterator iter)
|
void Scene::unloadCell (CellStoreCollection::iterator iter)
|
||||||
{
|
{
|
||||||
std::cout << "Unloading cell\n";
|
std::cout << "Unloading cell\n";
|
||||||
|
@ -79,6 +81,7 @@ namespace MWWorld
|
||||||
mPhysics->removeObject (node->getName());
|
mPhysics->removeObject (node->getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mRendering.removeCell(*iter);
|
mRendering.removeCell(*iter);
|
||||||
//mPhysics->removeObject("Unnamed_43");
|
//mPhysics->removeObject("Unnamed_43");
|
||||||
|
|
||||||
|
@ -88,6 +91,7 @@ namespace MWWorld
|
||||||
mActiveCells.erase(*iter);
|
mActiveCells.erase(*iter);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::loadCell (Ptr::CellStore *cell)
|
void Scene::loadCell (Ptr::CellStore *cell)
|
||||||
|
@ -101,7 +105,7 @@ namespace MWWorld
|
||||||
mActiveCells.insert(cell);
|
mActiveCells.insert(cell);
|
||||||
if(result.second){
|
if(result.second){
|
||||||
insertCell(*cell, mEnvironment);
|
insertCell(*cell, mEnvironment);
|
||||||
mRendering.cellAdded (cell);
|
mRendering.cellAdded(cell);
|
||||||
mRendering.configureAmbient(*cell);
|
mRendering.configureAmbient(*cell);
|
||||||
mRendering.requestMap(cell);
|
mRendering.requestMap(cell);
|
||||||
mRendering.configureAmbient(*cell);
|
mRendering.configureAmbient(*cell);
|
||||||
|
@ -192,6 +196,7 @@ namespace MWWorld
|
||||||
|
|
||||||
mCurrentCell = *iter;
|
mCurrentCell = *iter;
|
||||||
|
|
||||||
|
|
||||||
// adjust player
|
// adjust player
|
||||||
playerCellChange (mWorld->getExterior(X, Y), position, adjustPlayerPos);
|
playerCellChange (mWorld->getExterior(X, Y), position, adjustPlayerPos);
|
||||||
|
|
||||||
|
@ -199,6 +204,7 @@ namespace MWWorld
|
||||||
mWorld->adjustSky();
|
mWorld->adjustSky();
|
||||||
|
|
||||||
mCellChanged = true;
|
mCellChanged = true;
|
||||||
|
mRendering.waterAdded(mCurrentCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
//We need the ogre renderer and a scene node.
|
//We need the ogre renderer and a scene node.
|
||||||
|
@ -239,6 +245,7 @@ namespace MWWorld
|
||||||
|
|
||||||
loadCell (cell);
|
loadCell (cell);
|
||||||
|
|
||||||
|
|
||||||
// adjust player
|
// adjust player
|
||||||
mCurrentCell = cell;
|
mCurrentCell = cell;
|
||||||
playerCellChange (cell, position);
|
playerCellChange (cell, position);
|
||||||
|
@ -250,6 +257,8 @@ namespace MWWorld
|
||||||
mWorld->adjustSky();
|
mWorld->adjustSky();
|
||||||
|
|
||||||
mCellChanged = true;
|
mCellChanged = true;
|
||||||
|
|
||||||
|
mRendering.waterAdded(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::changeToExteriorCell (const ESM::Position& position)
|
void Scene::changeToExteriorCell (const ESM::Position& position)
|
||||||
|
|
|
@ -540,9 +540,10 @@ namespace MWWorld
|
||||||
ptr.getRefData().getPosition().pos[0] = x;
|
ptr.getRefData().getPosition().pos[0] = x;
|
||||||
ptr.getRefData().getPosition().pos[1] = y;
|
ptr.getRefData().getPosition().pos[1] = y;
|
||||||
ptr.getRefData().getPosition().pos[2] = z;
|
ptr.getRefData().getPosition().pos[2] = z;
|
||||||
|
|
||||||
if (ptr==mPlayer->getPlayer())
|
if (ptr==mPlayer->getPlayer())
|
||||||
{
|
{
|
||||||
|
//std::cout << "X:" << ptr.getRefData().getPosition().pos[0] << " Z: " << ptr.getRefData().getPosition().pos[1] << "\n";
|
||||||
|
|
||||||
Ptr::CellStore *currentCell = mWorldScene->getCurrentCell();
|
Ptr::CellStore *currentCell = mWorldScene->getCurrentCell();
|
||||||
if (currentCell)
|
if (currentCell)
|
||||||
{
|
{
|
||||||
|
@ -832,4 +833,15 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
return mRendering->getFader();
|
return mRendering->getFader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::setWaterHeight(const float height)
|
||||||
|
{
|
||||||
|
mRendering->setWaterHeight(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::toggleWater()
|
||||||
|
{
|
||||||
|
mRendering->toggleWater();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,9 @@ namespace MWWorld
|
||||||
|
|
||||||
Ptr::CellStore *getInterior (const std::string& name);
|
Ptr::CellStore *getInterior (const std::string& name);
|
||||||
|
|
||||||
|
void setWaterHeight(const float height);
|
||||||
|
void toggleWater();
|
||||||
|
|
||||||
void adjustSky();
|
void adjustSky();
|
||||||
|
|
||||||
MWWorld::Player& getPlayer();
|
MWWorld::Player& getPlayer();
|
||||||
|
|
|
@ -21,8 +21,13 @@ void Cell::load(ESMReader &esm)
|
||||||
if (data.flags & Interior)
|
if (data.flags & Interior)
|
||||||
{
|
{
|
||||||
// Interior cells
|
// Interior cells
|
||||||
|
if (esm.isNextSub("INTV"))
|
||||||
if (esm.isNextSub("INTV") || esm.isNextSub("WHGT"))
|
{
|
||||||
|
int waterl;
|
||||||
|
esm.getHT(waterl);
|
||||||
|
water = (float) waterl;
|
||||||
|
}
|
||||||
|
else if (esm.isNextSub("WHGT"))
|
||||||
esm.getHT(water);
|
esm.getHT(water);
|
||||||
|
|
||||||
// Quasi-exterior cells have a region (which determines the
|
// Quasi-exterior cells have a region (which determines the
|
||||||
|
|
|
@ -114,7 +114,7 @@ struct Cell
|
||||||
ESM_Context context; // File position
|
ESM_Context context; // File position
|
||||||
DATAstruct data;
|
DATAstruct data;
|
||||||
AMBIstruct ambi;
|
AMBIstruct ambi;
|
||||||
int water; // Water level
|
float water; // Water level
|
||||||
int mapColor;
|
int mapColor;
|
||||||
|
|
||||||
void load(ESMReader &esm);
|
void load(ESMReader &esm);
|
||||||
|
|
|
@ -96,12 +96,16 @@ namespace ESMS
|
||||||
};
|
};
|
||||||
|
|
||||||
CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded)
|
CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded)
|
||||||
{}
|
{
|
||||||
|
mWaterLevel = cell->water;
|
||||||
|
}
|
||||||
|
|
||||||
const ESM::Cell *cell;
|
const ESM::Cell *cell;
|
||||||
State mState;
|
State mState;
|
||||||
std::vector<std::string> mIds;
|
std::vector<std::string> mIds;
|
||||||
|
|
||||||
|
float mWaterLevel;
|
||||||
|
|
||||||
// Lists for each individual object type
|
// Lists for each individual object type
|
||||||
CellRefList<Activator, D> activators;
|
CellRefList<Activator, D> activators;
|
||||||
CellRefList<Potion, D> potions;
|
CellRefList<Potion, D> potions;
|
||||||
|
|
13
files/CMakeLists.txt
Normal file
13
files/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
project(resources)
|
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/caustic_0.png "${OpenMW_BINARY_DIR}/resources/water/caustic_0.png" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Example_Fresnel.cg "${OpenMW_BINARY_DIR}/resources/water/Example_Fresnel.cg" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Example_FresnelPS.asm "${OpenMW_BINARY_DIR}/resources/water/Example_FresnelPS.asm" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassFP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassFP.cg" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassVP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassVP.cg" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/perlinvolume.dds "${OpenMW_BINARY_DIR}/resources/water/perlinvolume.dds" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Water02.jpg "${OpenMW_BINARY_DIR}/resources/water/Water02.jpg" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINARY_DIR}/resources/water/water.compositor" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/waves2.dds "${OpenMW_BINARY_DIR}/resources/water/waves2.dds" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Examples-Water.material "${OpenMW_BINARY_DIR}/resources/water/Examples-Water.material" COPYONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal1.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal1.tga" COPYONLY)
|
116
files/water/Example_Fresnel.cg
Normal file
116
files/water/Example_Fresnel.cg
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
// Vertex program for fresnel reflections / refractions
|
||||||
|
void main_vp(
|
||||||
|
float4 pos : POSITION,
|
||||||
|
float4 normal : NORMAL,
|
||||||
|
float2 tex : TEXCOORD0,
|
||||||
|
|
||||||
|
out float4 oPos : POSITION,
|
||||||
|
out float3 noiseCoord : TEXCOORD0,
|
||||||
|
out float4 projectionCoord : TEXCOORD1,
|
||||||
|
out float3 oEyeDir : TEXCOORD2,
|
||||||
|
out float3 oNormal : TEXCOORD3,
|
||||||
|
|
||||||
|
uniform float4x4 worldViewProjMatrix,
|
||||||
|
uniform float3 eyePosition, // object space
|
||||||
|
uniform float timeVal,
|
||||||
|
uniform float scale, // the amount to scale the noise texture by
|
||||||
|
uniform float scroll, // the amount by which to scroll the noise
|
||||||
|
uniform float noise // the noise perturb as a factor of the time
|
||||||
|
)
|
||||||
|
{
|
||||||
|
oPos = mul(worldViewProjMatrix, pos);
|
||||||
|
// Projective texture coordinates, adjust for mapping
|
||||||
|
float4x4 scalemat = float4x4(0.5, 0, 0, 0.5,
|
||||||
|
0,-0.5, 0, 0.5,
|
||||||
|
0, 0, 0.5, 0.5,
|
||||||
|
0, 0, 0, 1);
|
||||||
|
projectionCoord = mul(scalemat, oPos);
|
||||||
|
// Noise map coords
|
||||||
|
noiseCoord.xy = (tex + (timeVal * scroll)) * scale;
|
||||||
|
noiseCoord.z = noise * timeVal;
|
||||||
|
|
||||||
|
oEyeDir = normalize(pos.xyz - eyePosition);
|
||||||
|
oNormal = normal.rgb;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fragment program for distorting a texture using a 3D noise texture
|
||||||
|
void main_fp(
|
||||||
|
float3 noiseCoord : TEXCOORD0,
|
||||||
|
float4 projectionCoord : TEXCOORD1,
|
||||||
|
float3 eyeDir : TEXCOORD2,
|
||||||
|
float3 normal : TEXCOORD3,
|
||||||
|
|
||||||
|
out float4 col : COLOR,
|
||||||
|
|
||||||
|
uniform float4 tintColour,
|
||||||
|
uniform float noiseScale,
|
||||||
|
uniform float fresnelBias,
|
||||||
|
uniform float fresnelScale,
|
||||||
|
uniform float fresnelPower,
|
||||||
|
uniform sampler2D waterTex : register(s0),
|
||||||
|
uniform sampler2D noiseMap : register(s1),
|
||||||
|
uniform sampler2D reflectMap : register(s2),
|
||||||
|
uniform sampler2D refractMap : register(s3)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Do the tex projection manually so we can distort _after_
|
||||||
|
float2 final = projectionCoord.xy / projectionCoord.w;
|
||||||
|
|
||||||
|
// Noise
|
||||||
|
float3 noiseNormal = (tex2D(noiseMap, (noiseCoord.xy / 5)).rgb - 0.5).rbg * noiseScale;
|
||||||
|
final += noiseNormal.xz;
|
||||||
|
|
||||||
|
// Fresnel
|
||||||
|
//normal = normalize(normal + noiseNormal.xz);
|
||||||
|
float fresnel = fresnelBias + fresnelScale * pow(1 + dot(eyeDir, normal), fresnelPower);
|
||||||
|
|
||||||
|
// Reflection / refraction
|
||||||
|
float4 reflectionColour = tex2D(reflectMap, final);
|
||||||
|
float4 refractionColour = tex2D(refractMap, final) + tintColour;
|
||||||
|
|
||||||
|
// Final colour
|
||||||
|
col = lerp(refractionColour, reflectionColour, fresnel) * tex2D(waterTex, noiseNormal) / 3 ;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Old version to match ATI PS 1.3 implementation
|
||||||
|
void main_vp_old(
|
||||||
|
float4 pos : POSITION,
|
||||||
|
float4 normal : NORMAL,
|
||||||
|
float2 tex : TEXCOORD0,
|
||||||
|
|
||||||
|
out float4 oPos : POSITION,
|
||||||
|
out float fresnel : COLOR,
|
||||||
|
out float3 noiseCoord : TEXCOORD0,
|
||||||
|
out float4 projectionCoord : TEXCOORD1,
|
||||||
|
|
||||||
|
uniform float4x4 worldViewProjMatrix,
|
||||||
|
uniform float3 eyePosition, // object space
|
||||||
|
uniform float fresnelBias,
|
||||||
|
uniform float fresnelScale,
|
||||||
|
uniform float fresnelPower,
|
||||||
|
uniform float timeVal,
|
||||||
|
uniform float scale, // the amount to scale the noise texture by
|
||||||
|
uniform float scroll, // the amount by which to scroll the noise
|
||||||
|
uniform float noise // the noise perturb as a factor of the time
|
||||||
|
)
|
||||||
|
{
|
||||||
|
oPos = mul(worldViewProjMatrix, pos);
|
||||||
|
// Projective texture coordinates, adjust for mapping
|
||||||
|
float4x4 scalemat = float4x4(0.5, 0, 0, 0.5,
|
||||||
|
0,-0.5, 0, 0.5,
|
||||||
|
0, 0, 0.5, 0.5,
|
||||||
|
0, 0, 0, 1);
|
||||||
|
projectionCoord = mul(scalemat, oPos);
|
||||||
|
// Noise map coords
|
||||||
|
noiseCoord.xy = (tex + (timeVal * scroll)) * scale;
|
||||||
|
noiseCoord.z = noise * timeVal;
|
||||||
|
|
||||||
|
// calc fresnel factor (reflection coefficient)
|
||||||
|
float3 eyeDir = normalize(pos.xyz - eyePosition);
|
||||||
|
fresnel = fresnelBias + fresnelScale * pow(1 + dot(eyeDir, normal), fresnelPower);
|
||||||
|
|
||||||
|
}
|
72
files/water/Example_FresnelPS.asm
Normal file
72
files/water/Example_FresnelPS.asm
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
ps.1.4
|
||||||
|
// conversion from Cg generated ARB_fragment_program to ps.1.4 by NFZ
|
||||||
|
// command line args: -profile arbfp1 -entry main_fp
|
||||||
|
// program main_fp
|
||||||
|
// c0 : distortionRange
|
||||||
|
// c1 : tintColour
|
||||||
|
// testure 0 : noiseMap
|
||||||
|
// texture 1 : reflectMap
|
||||||
|
// texture 2 : refractMap
|
||||||
|
// v0.x : fresnel
|
||||||
|
// t0.xyz : noiseCoord
|
||||||
|
// t1.xyw : projectionCoord
|
||||||
|
|
||||||
|
def c2, 2, 1, 0, 0
|
||||||
|
|
||||||
|
// Cg: distort.x = tex3D(noiseMap, noiseCoord).x;
|
||||||
|
// arbfp1: TEX R0.x, fragment.texcoord[0], texture[0], 3D;
|
||||||
|
// sample noise map using noiseCoord in TEX unit 0
|
||||||
|
|
||||||
|
texld r0, t0.xyz
|
||||||
|
|
||||||
|
// get projected texture coordinates from TEX coord 1
|
||||||
|
// will be used in phase 2
|
||||||
|
|
||||||
|
texcrd r1.xy, t1_dw.xyw
|
||||||
|
mov r1.z, c2.y
|
||||||
|
|
||||||
|
// Cg: distort.y = tex3D(noiseMap, noiseCoord + yoffset).x;
|
||||||
|
// arbfp1: ADD R1.xyz, fragment.texcoord[0], c1;
|
||||||
|
// arbfp1: TEX R1.x, R1, texture[0], 3D;
|
||||||
|
// arbfp1: MOV R0.y, R1.x;
|
||||||
|
|
||||||
|
// Cg: distort = (distort * 2 - 1) * distortionRange;
|
||||||
|
// arbfp1: MAD R0.xy, R0, c0.x, -c0.y;
|
||||||
|
// arbfp1: MUL R0.xy, R0, u0.x;
|
||||||
|
// (distort * 2 - 1) same as 2*(distort -.5) so use _bx2
|
||||||
|
|
||||||
|
|
||||||
|
// Cg: final = projectionCoord.xy / projectionCoord.w;
|
||||||
|
// Cg: final += distort;
|
||||||
|
// arbfp1: RCP R0.w, fragment.texcoord[1].w;
|
||||||
|
// arbfp1: MAD R0.xy, fragment.texcoord[1], R0.w, R0;
|
||||||
|
// final = (distort * projectionCoord.w) + projectionCoord.xy
|
||||||
|
// for ps.1.4 have to re-arrange things a bit to perturb projected texture coordinates
|
||||||
|
|
||||||
|
mad r0.xyz, r0_bx2, c0.x, r1
|
||||||
|
|
||||||
|
phase
|
||||||
|
|
||||||
|
// do dependant texture reads
|
||||||
|
// Cg: reflectionColour = tex2D(reflectMap, final);
|
||||||
|
// arbfp1: TEX R0, R0, texture[1], 2D;
|
||||||
|
// sampe reflectMap using dependant read : texunit 1
|
||||||
|
|
||||||
|
texld r1, r0.xyz
|
||||||
|
|
||||||
|
// Cg: refractionColour = tex2D(refractMap, final) + tintColour;
|
||||||
|
// arbfp1: TEX R1, R0, texture[2], 2D;
|
||||||
|
// sample refractMap : texunit 2
|
||||||
|
|
||||||
|
texld r2, r0.xyz
|
||||||
|
|
||||||
|
// adding tintColour that is in global c1
|
||||||
|
// arbfp1: ADD R1, R1, u1;
|
||||||
|
|
||||||
|
add r2, r2, c1
|
||||||
|
|
||||||
|
// Cg: col = lerp(refractionColour, reflectionColour, fresnel);
|
||||||
|
// arbfp1: ADD R0, R0, -R1;
|
||||||
|
// arbfp1: MAD result.color, fragment.color.primary.x, R0, R1;
|
||||||
|
|
||||||
|
lrp r0, v0.x, r1, r2
|
149
files/water/Examples-Water.material
Normal file
149
files/water/Examples-Water.material
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
|
||||||
|
vertex_program Water/GlassVP cg
|
||||||
|
{
|
||||||
|
source GlassVP.cg
|
||||||
|
entry_point glass_vp
|
||||||
|
profiles vs_1_1 arbvp1
|
||||||
|
|
||||||
|
default_params
|
||||||
|
{
|
||||||
|
param_named_auto worldViewProj worldviewproj_matrix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fragment_program Water/GlassFP cg
|
||||||
|
{
|
||||||
|
source GlassFP.cg
|
||||||
|
entry_point main_ps
|
||||||
|
profiles ps_2_0 arbfp1
|
||||||
|
}
|
||||||
|
|
||||||
|
material Water/Compositor
|
||||||
|
{
|
||||||
|
technique
|
||||||
|
{
|
||||||
|
pass
|
||||||
|
{
|
||||||
|
depth_check off
|
||||||
|
vertex_program_ref Water/GlassVP
|
||||||
|
{
|
||||||
|
param_named_auto timeVal time 0.25
|
||||||
|
param_named scale float 0.1
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment_program_ref Water/GlassFP
|
||||||
|
{
|
||||||
|
param_named tintColour float4 0 0.35 0.35 1
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_unit RT
|
||||||
|
{
|
||||||
|
tex_coord_set 0
|
||||||
|
tex_address_mode clamp
|
||||||
|
filtering linear linear linear
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_unit
|
||||||
|
{
|
||||||
|
texture WaterNormal1.tga 2d
|
||||||
|
tex_coord_set 1
|
||||||
|
//tex_address_mode clamp
|
||||||
|
filtering linear linear linear
|
||||||
|
}
|
||||||
|
texture_unit
|
||||||
|
{
|
||||||
|
texture caustic_0.png 2d
|
||||||
|
tex_coord_set 2
|
||||||
|
//tex_address_mode clamp
|
||||||
|
filtering linear linear linear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertex_program Water/RefractReflectVP cg
|
||||||
|
{
|
||||||
|
source Example_Fresnel.cg
|
||||||
|
entry_point main_vp
|
||||||
|
profiles vs_1_1 arbvp1
|
||||||
|
}
|
||||||
|
vertex_program Water/RefractReflectVPold cg
|
||||||
|
{
|
||||||
|
source Example_Fresnel.cg
|
||||||
|
entry_point main_vp_old
|
||||||
|
profiles vs_1_1 arbvp1
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment_program Water/RefractReflectFP cg
|
||||||
|
{
|
||||||
|
source Example_Fresnel.cg
|
||||||
|
entry_point main_fp
|
||||||
|
// sorry, ps_1_1 and fp20 can't do this
|
||||||
|
profiles ps_2_0 arbfp1
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment_program Water/RefractReflectPS asm
|
||||||
|
{
|
||||||
|
source Example_FresnelPS.asm
|
||||||
|
// sorry, only for ps_1_4 :)
|
||||||
|
syntax ps_1_4
|
||||||
|
|
||||||
|
}
|
||||||
|
material Examples/Water0
|
||||||
|
{
|
||||||
|
|
||||||
|
technique
|
||||||
|
{
|
||||||
|
pass
|
||||||
|
{
|
||||||
|
//
|
||||||
|
|
||||||
|
depth_write off
|
||||||
|
vertex_program_ref Water/RefractReflectVP
|
||||||
|
{
|
||||||
|
param_named_auto worldViewProjMatrix worldviewproj_matrix
|
||||||
|
param_named_auto eyePosition camera_position_object_space
|
||||||
|
param_named_auto timeVal time 0.15
|
||||||
|
param_named scroll float 1
|
||||||
|
param_named scale float 1
|
||||||
|
param_named noise float 1
|
||||||
|
// scroll and noisePos will need updating per frame
|
||||||
|
}
|
||||||
|
fragment_program_ref Water/RefractReflectFP
|
||||||
|
{
|
||||||
|
param_named fresnelBias float -0.1
|
||||||
|
param_named fresnelScale float 0.8
|
||||||
|
param_named fresnelPower float 20
|
||||||
|
param_named tintColour float4 1 1 1 1
|
||||||
|
param_named noiseScale float 0.05
|
||||||
|
}
|
||||||
|
// Water
|
||||||
|
scene_blend alpha_blend
|
||||||
|
texture_unit
|
||||||
|
{
|
||||||
|
|
||||||
|
// Water texture
|
||||||
|
texture Water02.jpg
|
||||||
|
// min / mag filtering, no mip
|
||||||
|
filtering linear linear none
|
||||||
|
alpha_op_ex source1 src_manual src_current 0.9
|
||||||
|
|
||||||
|
}
|
||||||
|
// Noise
|
||||||
|
texture_unit
|
||||||
|
{
|
||||||
|
alpha_op_ex source1 src_manual src_current 0.9
|
||||||
|
// Perlin noise volume
|
||||||
|
texture waves2.dds
|
||||||
|
// min / mag filtering, no mip
|
||||||
|
filtering linear linear none
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
15
files/water/GlassFP.cg
Normal file
15
files/water/GlassFP.cg
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
sampler RT : register(s0);
|
||||||
|
sampler NormalMap : register(s1);
|
||||||
|
sampler CausticMap : register(s2);
|
||||||
|
|
||||||
|
float4 main_ps(float2 iTexCoord : TEXCOORD0,
|
||||||
|
float3 noiseCoord : TEXCOORD1,
|
||||||
|
uniform float4 tintColour) : COLOR
|
||||||
|
{
|
||||||
|
float4 normal = tex2D(NormalMap, noiseCoord);
|
||||||
|
|
||||||
|
|
||||||
|
return tex2D(RT, iTexCoord + normal.xy * 0.05) +
|
||||||
|
(tex2D(CausticMap, noiseCoord) / 5) +
|
||||||
|
tintColour ;
|
||||||
|
}
|
24
files/water/GlassVP.cg
Normal file
24
files/water/GlassVP.cg
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
void glass_vp
|
||||||
|
(
|
||||||
|
in float4 inPos : POSITION,
|
||||||
|
|
||||||
|
out float4 pos : POSITION,
|
||||||
|
out float2 uv0 : TEXCOORD0,
|
||||||
|
out float4 noiseCoord : TEXCOORD1,
|
||||||
|
|
||||||
|
uniform float4x4 worldViewProj,
|
||||||
|
uniform float timeVal,
|
||||||
|
uniform float scale
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Use standardise transform, so work accord with render system specific (RS depth, requires texture flipping, etc)
|
||||||
|
pos = mul(worldViewProj, inPos);
|
||||||
|
|
||||||
|
// The input positions adjusted by texel offsets, so clean up inaccuracies
|
||||||
|
inPos.xy = sign(inPos.xy);
|
||||||
|
|
||||||
|
// Convert to image-space
|
||||||
|
uv0 = (float2(inPos.x, -inPos.y) + 1.0f) * 0.5f;
|
||||||
|
noiseCoord = (pos + timeVal) * scale;
|
||||||
|
}
|
||||||
|
|
BIN
files/water/Water02.jpg
Normal file
BIN
files/water/Water02.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
BIN
files/water/WaterNormal1.tga
Normal file
BIN
files/water/WaterNormal1.tga
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
BIN
files/water/caustic_0.png
Normal file
BIN
files/water/caustic_0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
files/water/perlinvolume.dds
Normal file
BIN
files/water/perlinvolume.dds
Normal file
Binary file not shown.
21
files/water/water.compositor
Normal file
21
files/water/water.compositor
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
compositor Water
|
||||||
|
{
|
||||||
|
technique
|
||||||
|
{
|
||||||
|
texture rt0 target_width target_height PF_R8G8B8
|
||||||
|
|
||||||
|
target rt0 { input previous }
|
||||||
|
|
||||||
|
target_output
|
||||||
|
{
|
||||||
|
// Start with clear output
|
||||||
|
input none
|
||||||
|
|
||||||
|
pass render_quad
|
||||||
|
{
|
||||||
|
material Water/Compositor
|
||||||
|
input 0 rt0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
files/water/waves2.dds
Normal file
BIN
files/water/waves2.dds
Normal file
Binary file not shown.
Loading…
Reference in a new issue