mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-10-30 02:56:50 +00:00 
			
		
		
		
	Merge branch 'master' into minimap
Conflicts: apps/openmw/mwscript/docs/vmformat.txt apps/openmw/mwworld/world.cpp
This commit is contained in:
		
						commit
						521b9eec6c
					
				
					 41 changed files with 3642 additions and 64 deletions
				
			
		|  | @ -181,6 +181,7 @@ ENDIF(WIN32) | ||||||
| ENDIF(OGRE_STATIC) | ENDIF(OGRE_STATIC) | ||||||
| include_directories("." | include_directories("." | ||||||
|     ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} |     ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} | ||||||
|  |     ${OGRE_Terrain_INCLUDE_DIR} | ||||||
|     ${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} |     ${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} | ||||||
|     ${PLATFORM_INCLUDE_DIR} |     ${PLATFORM_INCLUDE_DIR} | ||||||
|     ${MYGUI_INCLUDE_DIRS} |     ${MYGUI_INCLUDE_DIRS} | ||||||
|  | @ -200,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 | ||||||
|  |  | ||||||
|  | @ -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 |     renderinginterface localmap water terrain terrainmaterial | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
| add_openmw_dir (mwinput | add_openmw_dir (mwinput | ||||||
|  | @ -82,6 +82,7 @@ add_definitions(${SOUND_DEFINE}) | ||||||
| 
 | 
 | ||||||
| target_link_libraries(openmw | target_link_libraries(openmw | ||||||
|     ${OGRE_LIBRARIES} |     ${OGRE_LIBRARIES} | ||||||
|  |     ${OGRE_Terrain_LIBRARY} | ||||||
|     ${OGRE_STATIC_PLUGINS} |     ${OGRE_STATIC_PLUGINS} | ||||||
|     ${OIS_LIBRARIES} |     ${OIS_LIBRARIES} | ||||||
|     ${Boost_LIBRARIES} |     ${Boost_LIBRARIES} | ||||||
|  |  | ||||||
|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -43,9 +43,6 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environm | ||||||
|     // Centre dialog
 |     // Centre dialog
 | ||||||
|     center(); |     center(); | ||||||
| 
 | 
 | ||||||
|     //WindowManager *wm = environment.mWindowManager;
 |  | ||||||
|     setText("NpcName", "Name of character"); |  | ||||||
| 
 |  | ||||||
|     //History view
 |     //History view
 | ||||||
|     getWidget(history, "History"); |     getWidget(history, "History"); | ||||||
|     history->setOverflowToTheLeft(true); |     history->setOverflowToTheLeft(true); | ||||||
|  | @ -116,7 +113,8 @@ void DialogueWindow::onSelectTopic(MyGUI::ListBox* _sender, size_t _index) | ||||||
| 
 | 
 | ||||||
| void DialogueWindow::startDialogue(std::string npcName) | void DialogueWindow::startDialogue(std::string npcName) | ||||||
| { | { | ||||||
|     setText("NpcName", npcName); |     static_cast<MyGUI::Window*>(mMainWidget)->setCaption(npcName); | ||||||
|  |     adjustWindowCaption(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DialogueWindow::setKeywords(std::list<std::string> keyWords) | void DialogueWindow::setKeywords(std::list<std::string> keyWords) | ||||||
|  |  | ||||||
|  | @ -371,7 +371,6 @@ void WindowManager::updateSkillArea() | ||||||
| 
 | 
 | ||||||
| void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) | void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) | ||||||
| { | { | ||||||
|     std::cout << "dialogue a la poubelle"; |  | ||||||
|     assert(dialog); |     assert(dialog); | ||||||
|     if (!dialog) |     if (!dialog) | ||||||
|         return; |         return; | ||||||
|  |  | ||||||
|  | @ -23,6 +23,12 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const | ||||||
| :mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mDebugging(engine) | :mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mDebugging(engine) | ||||||
| { | { | ||||||
|     mRendering.createScene("PlayerCam", 55, 5); |     mRendering.createScene("PlayerCam", 55, 5); | ||||||
|  |     mTerrainManager = new TerrainManager(mRendering.getScene(), | ||||||
|  |                                          environment); | ||||||
|  | 
 | ||||||
|  |     //The fog type must be set before any terrain objects are created as if the
 | ||||||
|  |     //fog type is set to FOG_NONE then the initially created terrain won't have any fog
 | ||||||
|  |     configureFog(1, ColourValue(1,1,1)); | ||||||
| 
 | 
 | ||||||
|     // Set default mipmap level (NB some APIs ignore this)
 |     // Set default mipmap level (NB some APIs ignore this)
 | ||||||
|     TextureManager::getSingleton().setDefaultNumMipmaps(5); |     TextureManager::getSingleton().setDefaultNumMipmaps(5); | ||||||
|  | @ -53,6 +59,10 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const | ||||||
|     //mSkyManager = 0;
 |     //mSkyManager = 0;
 | ||||||
|     mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); |     mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     mWater = 0; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); |     mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); | ||||||
|     mSun = 0; |     mSun = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -64,6 +74,7 @@ RenderingManager::~RenderingManager () | ||||||
|     //TODO: destroy mSun?
 |     //TODO: destroy mSun?
 | ||||||
|     delete mPlayer; |     delete mPlayer; | ||||||
|     delete mSkyManager; |     delete mSkyManager; | ||||||
|  |     delete mTerrainManager; | ||||||
|     delete mLocalMap; |     delete mLocalMap; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -88,14 +99,33 @@ 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()) | ||||||
|  |       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); | ||||||
|  |     if (store->cell->isExterior()) | ||||||
|  |       mTerrainManager->cellAdded(store); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RenderingManager::addObject (const MWWorld::Ptr& ptr){ | void RenderingManager::addObject (const MWWorld::Ptr& ptr){ | ||||||
|  | @ -142,6 +172,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 () | ||||||
|  | @ -236,17 +287,17 @@ void RenderingManager::setAmbientMode() | ||||||
|   { |   { | ||||||
|     case 0: |     case 0: | ||||||
| 
 | 
 | ||||||
|       mRendering.getScene()->setAmbientLight(mAmbientColor); |       setAmbientColour(mAmbientColor); | ||||||
|       break; |       break; | ||||||
| 
 | 
 | ||||||
|     case 1: |     case 1: | ||||||
| 
 | 
 | ||||||
|       mRendering.getScene()->setAmbientLight(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); |       setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); | ||||||
|       break; |       break; | ||||||
| 
 | 
 | ||||||
|     case 2: |     case 2: | ||||||
| 
 | 
 | ||||||
|       mRendering.getScene()->setAmbientLight(ColourValue(1,1,1)); |       setAmbientColour(ColourValue(1,1,1)); | ||||||
|       break; |       break; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -286,6 +337,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) | ||||||
|  | @ -301,11 +357,13 @@ void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr) | ||||||
| void RenderingManager::setSunColour(const Ogre::ColourValue& colour) | void RenderingManager::setSunColour(const Ogre::ColourValue& colour) | ||||||
| { | { | ||||||
|     mSun->setDiffuseColour(colour); |     mSun->setDiffuseColour(colour); | ||||||
|  |     mTerrainManager->setDiffuse(colour); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) | void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) | ||||||
| { | { | ||||||
|     mRendering.getScene()->setAmbientLight(colour); |     mRendering.getScene()->setAmbientLight(colour); | ||||||
|  |     mTerrainManager->setAmbient(colour); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RenderingManager::sunEnable() | void RenderingManager::sunEnable() | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #include "sky.hpp" | #include "sky.hpp" | ||||||
|  | #include "terrain.hpp" | ||||||
| #include "debugging.hpp" | #include "debugging.hpp" | ||||||
| 
 | 
 | ||||||
| #include "../mwworld/class.hpp" | #include "../mwworld/class.hpp" | ||||||
|  | @ -24,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" | ||||||
| 
 | 
 | ||||||
| namespace Ogre | namespace Ogre | ||||||
|  | @ -59,6 +61,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
 | ||||||
|  | @ -75,6 +79,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
 | ||||||
|  | @ -86,6 +93,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); | ||||||
| 
 | 
 | ||||||
|  | @ -134,6 +145,10 @@ class RenderingManager: private RenderingInterface { | ||||||
| 
 | 
 | ||||||
|     SkyManager* mSkyManager; |     SkyManager* mSkyManager; | ||||||
| 
 | 
 | ||||||
|  |     MWRender::Water *mWater; | ||||||
|  | 
 | ||||||
|  |     TerrainManager* mTerrainManager; | ||||||
|  | 
 | ||||||
|     OEngine::Render::OgreRenderer &mRendering; |     OEngine::Render::OgreRenderer &mRendering; | ||||||
| 
 | 
 | ||||||
|     MWRender::Objects mObjects; |     MWRender::Objects mObjects; | ||||||
|  |  | ||||||
							
								
								
									
										510
									
								
								apps/openmw/mwrender/terrain.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								apps/openmw/mwrender/terrain.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,510 @@ | ||||||
|  | #include <OgreTerrain.h> | ||||||
|  | #include <OgreTerrainGroup.h> | ||||||
|  | #include <boost/lexical_cast.hpp> | ||||||
|  | 
 | ||||||
|  | #include "../mwworld/world.hpp" | ||||||
|  | 
 | ||||||
|  | #include "terrainmaterial.hpp" | ||||||
|  | #include "terrain.hpp" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | using namespace Ogre; | ||||||
|  | 
 | ||||||
|  | namespace MWRender | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     TerrainManager::TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& evn) : | ||||||
|  |         mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)) | ||||||
|  |     { | ||||||
|  | 
 | ||||||
|  |         TerrainMaterialGeneratorPtr matGen; | ||||||
|  |         TerrainMaterialGeneratorB* matGenP = new TerrainMaterialGeneratorB(); | ||||||
|  |         matGen.bind(matGenP); | ||||||
|  |         mTerrainGlobals.setDefaultMaterialGenerator(matGen); | ||||||
|  | 
 | ||||||
|  |         TerrainMaterialGenerator::Profile* const activeProfile = | ||||||
|  |             mTerrainGlobals.getDefaultMaterialGenerator() | ||||||
|  |                            ->getActiveProfile(); | ||||||
|  |         mActiveProfile = static_cast<TerrainMaterialGeneratorB::SM2Profile*>(activeProfile); | ||||||
|  | 
 | ||||||
|  |         //The pixel error should be as high as possible without it being noticed
 | ||||||
|  |         //as it governs how fast mesh quality decreases.
 | ||||||
|  |         mTerrainGlobals.setMaxPixelError(8); | ||||||
|  | 
 | ||||||
|  |         mTerrainGlobals.setLayerBlendMapSize(32); | ||||||
|  |         mTerrainGlobals.setDefaultGlobalColourMapSize(65); | ||||||
|  | 
 | ||||||
|  |         //10 (default) didn't seem to be quite enough
 | ||||||
|  |         mTerrainGlobals.setSkirtSize(128); | ||||||
|  | 
 | ||||||
|  |         //due to the sudden flick between composite and non composite textures,
 | ||||||
|  |         //this seemed the distance where it wasn't too noticeable
 | ||||||
|  |         mTerrainGlobals.setCompositeMapDistance(mWorldSize*2); | ||||||
|  | 
 | ||||||
|  |         mActiveProfile->setLightmapEnabled(false); | ||||||
|  |         mActiveProfile->setLayerSpecularMappingEnabled(false); | ||||||
|  |         mActiveProfile->setLayerNormalMappingEnabled(false); | ||||||
|  |         mActiveProfile->setLayerParallaxMappingEnabled(false); | ||||||
|  |         mActiveProfile->setReceiveDynamicShadowsEnabled(false); | ||||||
|  | 
 | ||||||
|  |         //composite maps lead to a drastic reduction in loading time so are
 | ||||||
|  |         //disabled
 | ||||||
|  |         mActiveProfile->setCompositeMapEnabled(false); | ||||||
|  | 
 | ||||||
|  |         mTerrainGroup.setOrigin(Vector3(mWorldSize/2, | ||||||
|  |                                          0, | ||||||
|  |                                          -mWorldSize/2)); | ||||||
|  | 
 | ||||||
|  |         Terrain::ImportData& importSettings = mTerrainGroup.getDefaultImportSettings(); | ||||||
|  | 
 | ||||||
|  |         importSettings.inputBias    = 0; | ||||||
|  |         importSettings.terrainSize  = mLandSize; | ||||||
|  |         importSettings.worldSize    = mWorldSize; | ||||||
|  |         importSettings.minBatchSize = 9; | ||||||
|  |         importSettings.maxBatchSize = mLandSize; | ||||||
|  | 
 | ||||||
|  |         importSettings.deleteInputData = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     TerrainManager::~TerrainManager() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     void TerrainManager::setDiffuse(const ColourValue& diffuse) | ||||||
|  |     { | ||||||
|  |         mTerrainGlobals.setCompositeMapDiffuse(diffuse); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     void TerrainManager::setAmbient(const ColourValue& ambient) | ||||||
|  |     { | ||||||
|  |         mTerrainGlobals.setCompositeMapAmbient(ambient); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     void TerrainManager::cellAdded(MWWorld::Ptr::CellStore *store) | ||||||
|  |     { | ||||||
|  |         const int cellX = store->cell->getGridX(); | ||||||
|  |         const int cellY = store->cell->getGridY(); | ||||||
|  | 
 | ||||||
|  |         ESM::Land* land = mEnvironment.mWorld->getStore().lands.search(cellX, cellY); | ||||||
|  |         if ( land != NULL ) | ||||||
|  |         { | ||||||
|  |             land->loadData(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //split the cell terrain into four segments
 | ||||||
|  |         const int numTextures = ESM::Land::LAND_TEXTURE_SIZE/2; | ||||||
|  | 
 | ||||||
|  |         for ( int x = 0; x < 2; x++ ) | ||||||
|  |         { | ||||||
|  |             for ( int y = 0; y < 2; y++ ) | ||||||
|  |             { | ||||||
|  |                 Terrain::ImportData terrainData = | ||||||
|  |                     mTerrainGroup.getDefaultImportSettings(); | ||||||
|  | 
 | ||||||
|  |                 const int terrainX = cellX * 2 + x; | ||||||
|  |                 const int terrainY = cellY * 2 + y; | ||||||
|  | 
 | ||||||
|  |                 //it makes far more sense to reallocate the memory here,
 | ||||||
|  |                 //and let Ogre deal with it due to the issues with deleting
 | ||||||
|  |                 //it at the wrong time if using threads (Which Terrain does)
 | ||||||
|  |                 terrainData.inputFloat = OGRE_ALLOC_T(float, | ||||||
|  |                                                       mLandSize*mLandSize, | ||||||
|  |                                                       MEMCATEGORY_GEOMETRY); | ||||||
|  | 
 | ||||||
|  |                 if ( land != NULL ) | ||||||
|  |                 { | ||||||
|  |                     //copy the height data row by row
 | ||||||
|  |                     for ( int terrainCopyY = 0; terrainCopyY < mLandSize; terrainCopyY++ ) | ||||||
|  |                     { | ||||||
|  |                                                //the offset of the current segment
 | ||||||
|  |                         const size_t yOffset = y * (mLandSize-1) * ESM::Land::LAND_SIZE + | ||||||
|  |                                                //offset of the row
 | ||||||
|  |                                                terrainCopyY * ESM::Land::LAND_SIZE; | ||||||
|  |                         const size_t xOffset = x * (mLandSize-1); | ||||||
|  | 
 | ||||||
|  |                         memcpy(&terrainData.inputFloat[terrainCopyY*mLandSize], | ||||||
|  |                                &land->landData->heights[yOffset + xOffset], | ||||||
|  |                                mLandSize*sizeof(float)); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     memset(terrainData.inputFloat, 0, mLandSize*mLandSize*sizeof(float)); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 std::map<uint16_t, int> indexes; | ||||||
|  |                 initTerrainTextures(&terrainData, cellX, cellY, | ||||||
|  |                                     x * numTextures, y * numTextures, | ||||||
|  |                                     numTextures, indexes); | ||||||
|  | 
 | ||||||
|  |                 if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL) | ||||||
|  |                 { | ||||||
|  |                     mTerrainGroup.defineTerrain(terrainX, terrainY, &terrainData); | ||||||
|  | 
 | ||||||
|  |                     mTerrainGroup.loadTerrain(terrainX, terrainY, true); | ||||||
|  | 
 | ||||||
|  |                     Terrain* terrain = mTerrainGroup.getTerrain(terrainX, terrainY); | ||||||
|  |                     initTerrainBlendMaps(terrain, | ||||||
|  |                                          cellX, cellY, | ||||||
|  |                                          x * numTextures, y * numTextures, | ||||||
|  |                                          numTextures, | ||||||
|  |                                          indexes); | ||||||
|  | 
 | ||||||
|  |                     if ( land && land->landData->usingColours ) | ||||||
|  |                     { | ||||||
|  |                         // disable or enable global colour map (depends on available vertex colours)
 | ||||||
|  |                         mActiveProfile->setGlobalColourMapEnabled(true); | ||||||
|  |                         TexturePtr vertex = getVertexColours(land, | ||||||
|  |                                                              cellX, cellY, | ||||||
|  |                                                              x*(mLandSize-1), | ||||||
|  |                                                              y*(mLandSize-1), | ||||||
|  |                                                              mLandSize); | ||||||
|  | 
 | ||||||
|  |                         //this is a hack to get around the fact that Ogre seems to
 | ||||||
|  |                         //corrupt the global colour map leading to rendering errors
 | ||||||
|  |                         MaterialPtr mat = terrain->getMaterial(); | ||||||
|  |                         mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName( vertex->getName() ); | ||||||
|  |                         //mat = terrain->_getCompositeMapMaterial();
 | ||||||
|  |                         //mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName( vertex->getName() );
 | ||||||
|  |                     } | ||||||
|  |                     else | ||||||
|  |                     { | ||||||
|  |                         mActiveProfile->setGlobalColourMapEnabled(false); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         mTerrainGroup.freeTemporaryResources(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     void TerrainManager::cellRemoved(MWWorld::Ptr::CellStore *store) | ||||||
|  |     { | ||||||
|  |         for ( int x = 0; x < 2; x++ ) | ||||||
|  |         { | ||||||
|  |             for ( int y = 0; y < 2; y++ ) | ||||||
|  |             { | ||||||
|  |                 mTerrainGroup.unloadTerrain(store->cell->getGridX() * 2 + x, | ||||||
|  |                                             store->cell->getGridY() * 2 + y); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     void TerrainManager::initTerrainTextures(Terrain::ImportData* terrainData, | ||||||
|  |                                              int cellX, int cellY, | ||||||
|  |                                              int fromX, int fromY, int size, | ||||||
|  |                                              std::map<uint16_t, int>& indexes) | ||||||
|  |     { | ||||||
|  |         assert(terrainData != NULL && "Must have valid terrain data"); | ||||||
|  |         assert(fromX >= 0 && fromY >= 0 && | ||||||
|  |                "Can't get a terrain texture on terrain outside the current cell"); | ||||||
|  |         assert(fromX+size <= ESM::Land::LAND_TEXTURE_SIZE && | ||||||
|  |                fromY+size <= ESM::Land::LAND_TEXTURE_SIZE && | ||||||
|  |                "Can't get a terrain texture on terrain outside the current cell"); | ||||||
|  | 
 | ||||||
|  |         //this ensures that the ltex indexes are sorted (or retrived as sorted
 | ||||||
|  |         //which simplifies shading between cells).
 | ||||||
|  |         //
 | ||||||
|  |         //If we don't sort the ltex indexes, the splatting order may differ between
 | ||||||
|  |         //cells which may lead to inconsistent results when shading between cells
 | ||||||
|  |         std::set<uint16_t> ltexIndexes; | ||||||
|  |         for ( int y = fromY - 1; y < fromY + size + 1; y++ ) | ||||||
|  |         { | ||||||
|  |             for ( int x = fromX - 1; x < fromX + size + 1; x++ ) | ||||||
|  |             { | ||||||
|  |                 ltexIndexes.insert(getLtexIndexAt(cellX, cellY, x, y)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //there is one texture that we want to use as a base (i.e. it won't have
 | ||||||
|  |         //a blend map). This holds the ltex index of that base texture so that
 | ||||||
|  |         //we know not to include it in the output map
 | ||||||
|  |         int baseTexture = -1; | ||||||
|  |         for ( std::set<uint16_t>::iterator iter = ltexIndexes.begin(); | ||||||
|  |               iter != ltexIndexes.end(); | ||||||
|  |               ++iter ) | ||||||
|  |         { | ||||||
|  |             const uint16_t ltexIndex = *iter; | ||||||
|  |             //this is the base texture, so we can ignore this at present
 | ||||||
|  |             if ( ltexIndex == baseTexture ) | ||||||
|  |             { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             const std::map<uint16_t, int>::const_iterator it = indexes.find(ltexIndex); | ||||||
|  | 
 | ||||||
|  |             if ( it == indexes.end() ) | ||||||
|  |             { | ||||||
|  |                 //NB: All vtex ids are +1 compared to the ltex ids
 | ||||||
|  | 
 | ||||||
|  |                 assert( (int)mEnvironment.mWorld->getStore().landTexts.getSize() >= (int)ltexIndex - 1 && | ||||||
|  |                        "LAND.VTEX must be within the bounds of the LTEX array"); | ||||||
|  | 
 | ||||||
|  |                 std::string texture; | ||||||
|  |                 if ( ltexIndex == 0 ) | ||||||
|  |                 { | ||||||
|  |                     texture = "_land_default.dds"; | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     texture = mEnvironment.mWorld->getStore().landTexts.search(ltexIndex-1)->texture; | ||||||
|  |                     //TODO this is needed due to MWs messed up texture handling
 | ||||||
|  |                     texture = texture.substr(0, texture.rfind(".")) + ".dds"; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 const size_t position = terrainData->layerList.size(); | ||||||
|  |                 terrainData->layerList.push_back(Terrain::LayerInstance()); | ||||||
|  | 
 | ||||||
|  |                 terrainData->layerList[position].worldSize = 256; | ||||||
|  |                 terrainData->layerList[position].textureNames.push_back("textures\\" + texture); | ||||||
|  | 
 | ||||||
|  |                 if ( baseTexture == -1 ) | ||||||
|  |                 { | ||||||
|  |                     baseTexture = ltexIndex; | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     indexes[ltexIndex] = position; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     void TerrainManager::initTerrainBlendMaps(Terrain* terrain, | ||||||
|  |                                               int cellX, int cellY, | ||||||
|  |                                               int fromX, int fromY, int size, | ||||||
|  |                                               const std::map<uint16_t, int>& indexes) | ||||||
|  |     { | ||||||
|  |         assert(terrain != NULL && "Must have valid terrain"); | ||||||
|  |         assert(fromX >= 0 && fromY >= 0 && | ||||||
|  |                "Can't get a terrain texture on terrain outside the current cell"); | ||||||
|  |         assert(fromX+size <= ESM::Land::LAND_TEXTURE_SIZE && | ||||||
|  |                fromY+size <= ESM::Land::LAND_TEXTURE_SIZE && | ||||||
|  |                "Can't get a terrain texture on terrain outside the current cell"); | ||||||
|  | 
 | ||||||
|  |         //size must be a power of 2 as we do divisions with a power of 2 number
 | ||||||
|  |         //that need to result in an integer for correct splatting
 | ||||||
|  |         assert( (size & (size - 1)) == 0 && "Size must be a power of 2"); | ||||||
|  | 
 | ||||||
|  |         const int blendMapSize = terrain->getLayerBlendMapSize(); | ||||||
|  |         const int splatSize    = blendMapSize / size; | ||||||
|  | 
 | ||||||
|  |         //zero out every map
 | ||||||
|  |         std::map<uint16_t, int>::const_iterator iter; | ||||||
|  |         for ( iter = indexes.begin(); iter != indexes.end(); ++iter ) | ||||||
|  |         { | ||||||
|  |             float* pBlend = terrain->getLayerBlendMap(iter->second) | ||||||
|  |                                    ->getBlendPointer(); | ||||||
|  |             memset(pBlend, 0, sizeof(float) * blendMapSize * blendMapSize); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //covert the ltex data into a set of blend maps
 | ||||||
|  |         for ( int texY = fromY - 1; texY < fromY + size + 1; texY++ ) | ||||||
|  |         { | ||||||
|  |             for ( int texX = fromX - 1; texX < fromX + size + 1; texX++ ) | ||||||
|  |             { | ||||||
|  |                 const uint16_t ltexIndex = getLtexIndexAt(cellX, cellY, texX, texY); | ||||||
|  | 
 | ||||||
|  |                 //check if it is the base texture (which isn't in the map) and
 | ||||||
|  |                 //if it is don't bother altering the blend map for it
 | ||||||
|  |                 if ( indexes.find(ltexIndex) == indexes.end() ) | ||||||
|  |                 { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 //while texX is the splat index relative to the entire cell,
 | ||||||
|  |                 //relX is relative to the current segment we are splatting
 | ||||||
|  |                 const int relX = texX - fromX; | ||||||
|  |                 const int relY = texY - fromY; | ||||||
|  | 
 | ||||||
|  |                 const int layerIndex = indexes.find(ltexIndex)->second; | ||||||
|  | 
 | ||||||
|  |                 float* const pBlend = terrain->getLayerBlendMap(layerIndex) | ||||||
|  |                                              ->getBlendPointer(); | ||||||
|  | 
 | ||||||
|  |                 for ( int y = -1; y < splatSize + 1; y++ ) | ||||||
|  |                 { | ||||||
|  |                     for ( int x = -1; x < splatSize + 1; x++ ) | ||||||
|  |                     { | ||||||
|  | 
 | ||||||
|  |                         //Note: Y is reversed
 | ||||||
|  |                         const int splatY = blendMapSize - 1 - relY * splatSize - y; | ||||||
|  |                         const int splatX = relX * splatSize + x; | ||||||
|  | 
 | ||||||
|  |                         if ( splatX >= 0 && splatX < blendMapSize && | ||||||
|  |                              splatY >= 0 && splatY < blendMapSize ) | ||||||
|  |                         { | ||||||
|  |                             const int index = (splatY)*blendMapSize + splatX; | ||||||
|  | 
 | ||||||
|  |                             if ( y >= 0 && y < splatSize && | ||||||
|  |                                  x >= 0 && x < splatSize ) | ||||||
|  |                             { | ||||||
|  |                                 pBlend[index] = 1; | ||||||
|  |                             } | ||||||
|  |                             else | ||||||
|  |                             { | ||||||
|  |                                 //this provides a transition shading but also
 | ||||||
|  |                                 //rounds off the corners slightly
 | ||||||
|  |                                 pBlend[index] = std::min(1.0f, pBlend[index] + 0.5f); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for ( int i = 1; i < terrain->getLayerCount(); i++ ) | ||||||
|  |         { | ||||||
|  |              TerrainLayerBlendMap* blend = terrain->getLayerBlendMap(i); | ||||||
|  |              blend->dirty(); | ||||||
|  |              blend->update(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     int TerrainManager::getLtexIndexAt(int cellX, int cellY, | ||||||
|  |                                        int x, int y) | ||||||
|  |     { | ||||||
|  |         //check texture index falls within the 9 cell bounds
 | ||||||
|  |         //as this function can't cope with anything above that
 | ||||||
|  |         assert(x >= -ESM::Land::LAND_TEXTURE_SIZE && | ||||||
|  |                y >= -ESM::Land::LAND_TEXTURE_SIZE && | ||||||
|  |                "Trying to get land textures that are out of bounds"); | ||||||
|  | 
 | ||||||
|  |         assert(x < 2*ESM::Land::LAND_TEXTURE_SIZE && | ||||||
|  |                y < 2*ESM::Land::LAND_TEXTURE_SIZE && | ||||||
|  |                "Trying to get land textures that are out of bounds"); | ||||||
|  | 
 | ||||||
|  |         if ( x < 0 ) | ||||||
|  |         { | ||||||
|  |             cellX--; | ||||||
|  |             x += ESM::Land::LAND_TEXTURE_SIZE; | ||||||
|  |         } | ||||||
|  |         else if ( x >= ESM::Land::LAND_TEXTURE_SIZE ) | ||||||
|  |         { | ||||||
|  |             cellX++; | ||||||
|  |             x -= ESM::Land::LAND_TEXTURE_SIZE; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if ( y < 0 ) | ||||||
|  |         { | ||||||
|  |             cellY--; | ||||||
|  |             y += ESM::Land::LAND_TEXTURE_SIZE; | ||||||
|  |         } | ||||||
|  |         else if ( y >= ESM::Land::LAND_TEXTURE_SIZE ) | ||||||
|  |         { | ||||||
|  |             cellY++; | ||||||
|  |             y -= ESM::Land::LAND_TEXTURE_SIZE; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         ESM::Land* land = mEnvironment.mWorld->getStore().lands.search(cellX, cellY); | ||||||
|  |         if ( land != NULL ) | ||||||
|  |         { | ||||||
|  |             land->loadData(); | ||||||
|  |             return land->landData | ||||||
|  |                        ->textures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //----------------------------------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  |     TexturePtr TerrainManager::getVertexColours(ESM::Land* land, | ||||||
|  |                                                 int cellX, int cellY, | ||||||
|  |                                                 int fromX, int fromY, int size) | ||||||
|  |     { | ||||||
|  |         TextureManager* const texMgr = TextureManager::getSingletonPtr(); | ||||||
|  | 
 | ||||||
|  |         const std::string colourTextureName = "VtexColours_" + | ||||||
|  |                                               boost::lexical_cast<std::string>(cellX) + | ||||||
|  |                                               "_" + | ||||||
|  |                                               boost::lexical_cast<std::string>(cellY) + | ||||||
|  |                                               "_" + | ||||||
|  |                                               boost::lexical_cast<std::string>(fromX) + | ||||||
|  |                                               "_" + | ||||||
|  |                                               boost::lexical_cast<std::string>(fromY); | ||||||
|  | 
 | ||||||
|  |         TexturePtr tex = texMgr->getByName(colourTextureName); | ||||||
|  |         if ( !tex.isNull() ) | ||||||
|  |         { | ||||||
|  |             return tex; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         tex = texMgr->createManual(colourTextureName, | ||||||
|  |                                    ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, | ||||||
|  |                                    TEX_TYPE_2D, size, size, 0, PF_BYTE_BGR); | ||||||
|  | 
 | ||||||
|  |         HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer(); | ||||||
|  | 
 | ||||||
|  |         pixelBuffer->lock(HardwareBuffer::HBL_DISCARD); | ||||||
|  |         const PixelBox& pixelBox = pixelBuffer->getCurrentLock(); | ||||||
|  | 
 | ||||||
|  |         uint8* pDest = static_cast<uint8*>(pixelBox.data); | ||||||
|  | 
 | ||||||
|  |         if ( land != NULL ) | ||||||
|  |         { | ||||||
|  |             const char* const colours = land->landData->colours; | ||||||
|  |             for ( int y = 0; y < size; y++ ) | ||||||
|  |             { | ||||||
|  |                 for ( int x = 0; x < size; x++ ) | ||||||
|  |                 { | ||||||
|  |                     const size_t colourOffset = (y+fromY)*3*65 + (x+fromX)*3; | ||||||
|  | 
 | ||||||
|  |                     assert( colourOffset < 65*65*3 && | ||||||
|  |                             "Colour offset is out of the expected bounds of record" ); | ||||||
|  | 
 | ||||||
|  |                     const unsigned char r = colours[colourOffset + 0]; | ||||||
|  |                     const unsigned char g = colours[colourOffset + 1]; | ||||||
|  |                     const unsigned char b = colours[colourOffset + 2]; | ||||||
|  | 
 | ||||||
|  |                     //as is the case elsewhere we need to flip the y
 | ||||||
|  |                     const size_t imageOffset = (size - 1 - y)*size*4 + x*4; | ||||||
|  |                     pDest[imageOffset + 0] = b; | ||||||
|  |                     pDest[imageOffset + 1] = g; | ||||||
|  |                     pDest[imageOffset + 2] = r; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             for ( int y = 0; y < size; y++ ) | ||||||
|  |             { | ||||||
|  |                 for ( int x = 0; x < size; x++ ) | ||||||
|  |                 { | ||||||
|  |                     for ( int k = 0; k < 3; k++ ) | ||||||
|  |                     { | ||||||
|  |                         *pDest++ = 0; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         pixelBuffer->unlock(); | ||||||
|  | 
 | ||||||
|  |         return tex; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										117
									
								
								apps/openmw/mwrender/terrain.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								apps/openmw/mwrender/terrain.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,117 @@ | ||||||
|  | #ifndef _GAME_RENDER_TERRAIN_H | ||||||
|  | #define _GAME_RENDER_TERRAIN_H | ||||||
|  | 
 | ||||||
|  | #include <OgreTerrain.h> | ||||||
|  | #include <OgreTerrainGroup.h> | ||||||
|  | #include "terrainmaterial.hpp" | ||||||
|  | 
 | ||||||
|  | #include "../mwworld/ptr.hpp" | ||||||
|  | 
 | ||||||
|  | namespace Ogre{ | ||||||
|  |     class SceneManager; | ||||||
|  |     class TerrainGroup; | ||||||
|  |     class TerrainGlobalOptions; | ||||||
|  |     class Terrain; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace MWRender{ | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Implements the Morrowind terrain using the Ogre Terrain Component | ||||||
|  |      * | ||||||
|  |      * Each terrain cell is split into four blocks as this leads to an increase | ||||||
|  |      * in performance and means we don't hit splat limits quite as much | ||||||
|  |      */ | ||||||
|  |     class TerrainManager{ | ||||||
|  |     public: | ||||||
|  |         TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& env); | ||||||
|  |         virtual ~TerrainManager(); | ||||||
|  | 
 | ||||||
|  |         void setDiffuse(const Ogre::ColourValue& diffuse); | ||||||
|  |         void setAmbient(const Ogre::ColourValue& ambient); | ||||||
|  | 
 | ||||||
|  |         void cellAdded(MWWorld::Ptr::CellStore* store); | ||||||
|  |         void cellRemoved(MWWorld::Ptr::CellStore* store); | ||||||
|  |     private: | ||||||
|  |         Ogre::TerrainGlobalOptions mTerrainGlobals; | ||||||
|  |         Ogre::TerrainGroup mTerrainGroup; | ||||||
|  | 
 | ||||||
|  |         const MWWorld::Environment& mEnvironment; | ||||||
|  | 
 | ||||||
|  |         Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile; | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * The length in verticies of a single terrain block. | ||||||
|  |          */ | ||||||
|  |         static const int mLandSize = (ESM::Land::LAND_SIZE - 1)/2 + 1; | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * The length in game units of a single terrain block. | ||||||
|  |          */ | ||||||
|  |         static const int mWorldSize = ESM::Land::REAL_SIZE/2; | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Setups up the list of textures for part of a cell, using indexes as | ||||||
|  |          * an output to create a mapping of MW LtexIndex to the relevant terrain | ||||||
|  |          * layer | ||||||
|  |          * | ||||||
|  |          * @param terrainData the terrain data to setup the textures for | ||||||
|  |          * @param cellX the coord of the cell | ||||||
|  |          * @param cellY the coord of the cell | ||||||
|  |          * @param fromX the ltex index in the current cell to start making the texture from | ||||||
|  |          * @param fromY the ltex index in the current cell to start making the texture from | ||||||
|  |          * @param size the size (number of splats) to get | ||||||
|  |          * @param indexes a mapping of ltex index to the terrain texture layer that | ||||||
|  |          *          can be used by initTerrainBlendMaps | ||||||
|  |          */ | ||||||
|  |         void initTerrainTextures(Ogre::Terrain::ImportData* terrainData, | ||||||
|  |                                  int cellX, int cellY, | ||||||
|  |                                  int fromX, int fromY, int size, | ||||||
|  |                                  std::map<uint16_t, int>& indexes); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Creates the blend (splatting maps) for the given terrain from the ltex data. | ||||||
|  |          * | ||||||
|  |          * @param terrain the terrain object for the current cell | ||||||
|  |          * @param cellX the coord of the cell | ||||||
|  |          * @param cellY the coord of the cell | ||||||
|  |          * @param fromX the ltex index in the current cell to start making the texture from | ||||||
|  |          * @param fromY the ltex index in the current cell to start making the texture from | ||||||
|  |          * @param size the size (number of splats) to get | ||||||
|  |          * @param indexes the mapping of ltex to blend map produced by initTerrainTextures | ||||||
|  |          */ | ||||||
|  |         void initTerrainBlendMaps(Ogre::Terrain* terrain, | ||||||
|  |                                   int cellX, int cellY, | ||||||
|  |                                   int fromX, int fromY, int size, | ||||||
|  |                                   const std::map<uint16_t, int>& indexes); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Gets a LTEX index at the given point, assuming the current cell | ||||||
|  |          * starts at (0,0). This supports getting values from the surrounding | ||||||
|  |          * cells so negative x, y is acceptable | ||||||
|  |          * | ||||||
|  |          * @param cellX the coord of the cell | ||||||
|  |          * @param cellY the coord of the cell | ||||||
|  |          * @param x, y the splat position of the ltex index to get relative to the | ||||||
|  |          *             first splat of the current cell | ||||||
|  |          */ | ||||||
|  |         int getLtexIndexAt(int cellX, int cellY, int x, int y); | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Due to the fact that Ogre terrain doesn't support vertex colours | ||||||
|  |          * we have to generate them manually | ||||||
|  |          * | ||||||
|  |          * @param cellX the coord of the cell | ||||||
|  |          * @param cellY the coord of the cell | ||||||
|  |          * @param fromX the *vertex* index in the current cell to start making texture from | ||||||
|  |          * @param fromY the *vertex* index in the current cell to start making the texture from | ||||||
|  |          * @param size the size (number of vertexes) to get | ||||||
|  |          */ | ||||||
|  |         Ogre::TexturePtr getVertexColours(ESM::Land* land, | ||||||
|  |                                           int cellX, int cellY, | ||||||
|  |                                           int fromX, int fromY, int size); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif // _GAME_RENDER_TERRAIN_H
 | ||||||
							
								
								
									
										1741
									
								
								apps/openmw/mwrender/terrainmaterial.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1741
									
								
								apps/openmw/mwrender/terrainmaterial.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										266
									
								
								apps/openmw/mwrender/terrainmaterial.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								apps/openmw/mwrender/terrainmaterial.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,266 @@ | ||||||
|  | /*
 | ||||||
|  | ----------------------------------------------------------------------------- | ||||||
|  | This source file is part of OGRE | ||||||
|  | (Object-oriented Graphics Rendering Engine) | ||||||
|  | For the latest info, see http://www.ogre3d.org/
 | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2000-2011 Torus Knot Software Ltd | ||||||
|  | 
 | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  | 
 | ||||||
|  | The above copyright notice and this permission notice shall be included in | ||||||
|  | all copies or substantial portions of the Software. | ||||||
|  | 
 | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  | THE SOFTWARE. | ||||||
|  | ----------------------------------------------------------------------------- | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #ifndef __Ogre_TerrainMaterialGeneratorB_H__ | ||||||
|  | #define __Ogre_TerrainMaterialGeneratorB_H__ | ||||||
|  | 
 | ||||||
|  | #include "OgreTerrainPrerequisites.h" | ||||||
|  | #include "OgreTerrainMaterialGenerator.h" | ||||||
|  | #include "OgreGpuProgramParams.h" | ||||||
|  | 
 | ||||||
|  | namespace Ogre | ||||||
|  | { | ||||||
|  | 	class PSSMShadowCameraSetup; | ||||||
|  | 
 | ||||||
|  | 	/** \addtogroup Optional Components
 | ||||||
|  | 	*  @{ | ||||||
|  | 	*/ | ||||||
|  | 	/** \addtogroup Terrain
 | ||||||
|  | 	*  Some details on the terrain component | ||||||
|  | 	*  @{ | ||||||
|  | 	*/ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	/** A TerrainMaterialGenerator which can cope with normal mapped, specular mapped
 | ||||||
|  | 		terrain.  | ||||||
|  | 		@note Requires the Cg plugin to render correctly | ||||||
|  | 	*/ | ||||||
|  | 	class _OgreTerrainExport TerrainMaterialGeneratorB : public TerrainMaterialGenerator | ||||||
|  | 	{ | ||||||
|  | 	public: | ||||||
|  | 		TerrainMaterialGeneratorB(); | ||||||
|  | 		~TerrainMaterialGeneratorB(); | ||||||
|  | 
 | ||||||
|  | 		/** Shader model 2 profile target. 
 | ||||||
|  | 		*/ | ||||||
|  | 		class _OgreTerrainExport SM2Profile : public TerrainMaterialGenerator::Profile | ||||||
|  | 		{ | ||||||
|  | 		public: | ||||||
|  | 			SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc); | ||||||
|  | 			~SM2Profile(); | ||||||
|  | 
 | ||||||
|  |             bool isVertexCompressionSupported() const {return false;} | ||||||
|  |              | ||||||
|  | 			MaterialPtr generate(const Terrain* terrain); | ||||||
|  | 			MaterialPtr generateForCompositeMap(const Terrain* terrain); | ||||||
|  | 			uint8 getMaxLayers(const Terrain* terrain) const; | ||||||
|  | 			void updateParams(const MaterialPtr& mat, const Terrain* terrain); | ||||||
|  | 			void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain); | ||||||
|  | 			void requestOptions(Terrain* terrain); | ||||||
|  | 
 | ||||||
|  | 			/** Whether to support normal mapping per layer in the shader (default true). 
 | ||||||
|  | 			*/ | ||||||
|  | 			bool isLayerNormalMappingEnabled() const  { return mLayerNormalMappingEnabled; } | ||||||
|  | 			/** Whether to support normal mapping per layer in the shader (default true). 
 | ||||||
|  | 			*/ | ||||||
|  | 			void setLayerNormalMappingEnabled(bool enabled); | ||||||
|  | 			/** Whether to support parallax mapping per layer in the shader (default true). 
 | ||||||
|  | 			*/ | ||||||
|  | 			bool isLayerParallaxMappingEnabled() const  { return mLayerParallaxMappingEnabled; } | ||||||
|  | 			/** Whether to support parallax mapping per layer in the shader (default true). 
 | ||||||
|  | 			*/ | ||||||
|  | 			void setLayerParallaxMappingEnabled(bool enabled); | ||||||
|  | 			/** Whether to support specular mapping per layer in the shader (default true). 
 | ||||||
|  | 			*/ | ||||||
|  | 			bool isLayerSpecularMappingEnabled() const  { return mLayerSpecularMappingEnabled; } | ||||||
|  | 			/** Whether to support specular mapping per layer in the shader (default true). 
 | ||||||
|  | 			*/ | ||||||
|  | 			void setLayerSpecularMappingEnabled(bool enabled); | ||||||
|  | 			/** Whether to support a global colour map over the terrain in the shader,
 | ||||||
|  | 				if it's present (default true).  | ||||||
|  | 			*/ | ||||||
|  | 			bool isGlobalColourMapEnabled() const  { return mGlobalColourMapEnabled; } | ||||||
|  | 			/** Whether to support a global colour map over the terrain in the shader,
 | ||||||
|  | 			if it's present (default true).  | ||||||
|  | 			*/ | ||||||
|  | 			void setGlobalColourMapEnabled(bool enabled); | ||||||
|  | 			/** Whether to support a light map over the terrain in the shader,
 | ||||||
|  | 			if it's present (default true).  | ||||||
|  | 			*/ | ||||||
|  | 			bool isLightmapEnabled() const  { return mLightmapEnabled; } | ||||||
|  | 			/** Whether to support a light map over the terrain in the shader,
 | ||||||
|  | 			if it's present (default true).  | ||||||
|  | 			*/ | ||||||
|  | 			void setLightmapEnabled(bool enabled); | ||||||
|  | 			/** Whether to use the composite map to provide a lower LOD technique
 | ||||||
|  | 				in the distance (default true).  | ||||||
|  | 			*/ | ||||||
|  | 			bool isCompositeMapEnabled() const  { return mCompositeMapEnabled; } | ||||||
|  | 			/** Whether to use the composite map to provide a lower LOD technique
 | ||||||
|  | 			in the distance (default true).  | ||||||
|  | 			*/ | ||||||
|  | 			void setCompositeMapEnabled(bool enabled); | ||||||
|  | 			/** Whether to support dynamic texture shadows received from other 
 | ||||||
|  | 				objects, on the terrain (default true).  | ||||||
|  | 			*/ | ||||||
|  | 			bool getReceiveDynamicShadowsEnabled() const  { return mReceiveDynamicShadows; } | ||||||
|  | 			/** Whether to support dynamic texture shadows received from other 
 | ||||||
|  | 			objects, on the terrain (default true).  | ||||||
|  | 			*/ | ||||||
|  | 			void setReceiveDynamicShadowsEnabled(bool enabled); | ||||||
|  | 
 | ||||||
|  | 			/** Whether to use PSSM support dynamic texture shadows, and if so the 
 | ||||||
|  | 				settings to use (default 0).  | ||||||
|  | 			*/ | ||||||
|  | 			void setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup* pssmSettings); | ||||||
|  | 			/** Whether to use PSSM support dynamic texture shadows, and if so the 
 | ||||||
|  | 			settings to use (default 0).  | ||||||
|  | 			*/ | ||||||
|  | 			PSSMShadowCameraSetup* getReceiveDynamicShadowsPSSM() const { return mPSSM; } | ||||||
|  | 			/** Whether to use depth shadows (default false). 
 | ||||||
|  | 			*/ | ||||||
|  | 			void setReceiveDynamicShadowsDepth(bool enabled); | ||||||
|  | 			/** Whether to use depth shadows (default false). 
 | ||||||
|  | 			*/ | ||||||
|  | 			bool getReceiveDynamicShadowsDepth() const { return mDepthShadows; } | ||||||
|  | 			/** Whether to use shadows on low LOD material rendering (when using composite map) (default false). 
 | ||||||
|  | 			*/ | ||||||
|  | 			void setReceiveDynamicShadowsLowLod(bool enabled); | ||||||
|  | 			/** Whether to use shadows on low LOD material rendering (when using composite map) (default false). 
 | ||||||
|  | 			*/ | ||||||
|  | 			bool getReceiveDynamicShadowsLowLod() const { return mLowLodShadows; } | ||||||
|  | 
 | ||||||
|  |                         int getNumberOfLightsSupported() const; | ||||||
|  | 
 | ||||||
|  | 			/// Internal
 | ||||||
|  | 			bool _isSM3Available() const { return mSM3Available; } | ||||||
|  | 		 | ||||||
|  | 		protected: | ||||||
|  | 
 | ||||||
|  | 			enum TechniqueType | ||||||
|  | 			{ | ||||||
|  | 				HIGH_LOD,  | ||||||
|  | 				LOW_LOD,  | ||||||
|  | 				RENDER_COMPOSITE_MAP | ||||||
|  | 			}; | ||||||
|  | 			void addTechnique(const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 
 | ||||||
|  | 			/// Interface definition for helper class to generate shaders
 | ||||||
|  | 			class _OgreTerrainExport ShaderHelper : public TerrainAlloc | ||||||
|  | 			{ | ||||||
|  | 			public: | ||||||
|  | 				ShaderHelper() {} | ||||||
|  | 				virtual ~ShaderHelper() {} | ||||||
|  | 				virtual HighLevelGpuProgramPtr generateVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				virtual HighLevelGpuProgramPtr generateFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				virtual void updateParams(const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap); | ||||||
|  | 			protected: | ||||||
|  | 				virtual String getVertexProgramName(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				virtual String getFragmentProgramName(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				virtual HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) = 0; | ||||||
|  | 				virtual HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) = 0; | ||||||
|  | 				virtual void generateVertexProgramSource(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				virtual void generateFragmentProgramSource(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				virtual void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0; | ||||||
|  | 				virtual void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0; | ||||||
|  | 				virtual void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) = 0; | ||||||
|  | 				virtual void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) = 0; | ||||||
|  | 				virtual void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0; | ||||||
|  | 				virtual void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0; | ||||||
|  | 				virtual void defaultVpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog); | ||||||
|  | 				virtual void defaultFpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog); | ||||||
|  | 				virtual void updateVpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params); | ||||||
|  | 				virtual void updateFpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params); | ||||||
|  | 				static String getChannel(uint idx); | ||||||
|  | 
 | ||||||
|  | 				size_t mShadowSamplerStartHi; | ||||||
|  | 				size_t mShadowSamplerStartLo; | ||||||
|  | 
 | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			/// Utility class to help with generating shaders for Cg / HLSL.
 | ||||||
|  | 			class _OgreTerrainExport ShaderHelperCg : public ShaderHelper | ||||||
|  | 			{ | ||||||
|  | 			protected: | ||||||
|  | 				HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				uint generateVpDynamicShadowsParams(uint texCoordStart, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateVpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateFpDynamicShadowsHelpers(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateFpDynamicShadowsParams(uint* texCoord, uint* sampler, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 				void generateFpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			class _OgreTerrainExport ShaderHelperHLSL : public ShaderHelperCg | ||||||
|  | 			{ | ||||||
|  | 			protected: | ||||||
|  | 				HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			/// Utility class to help with generating shaders for GLSL.
 | ||||||
|  | 			class _OgreTerrainExport ShaderHelperGLSL : public ShaderHelper | ||||||
|  | 			{ | ||||||
|  | 			protected: | ||||||
|  | 				HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); | ||||||
|  | 				void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {} | ||||||
|  | 				void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {} | ||||||
|  | 				void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) {} | ||||||
|  | 				void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) {} | ||||||
|  | 				void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {} | ||||||
|  | 				void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {} | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			ShaderHelper* mShaderGen; | ||||||
|  | 			bool mLayerNormalMappingEnabled; | ||||||
|  | 			bool mLayerParallaxMappingEnabled; | ||||||
|  | 			bool mLayerSpecularMappingEnabled; | ||||||
|  | 			bool mGlobalColourMapEnabled; | ||||||
|  | 			bool mLightmapEnabled; | ||||||
|  | 			bool mCompositeMapEnabled; | ||||||
|  | 			bool mReceiveDynamicShadows; | ||||||
|  | 			PSSMShadowCameraSetup* mPSSM; | ||||||
|  | 			bool mDepthShadows; | ||||||
|  | 			bool mLowLodShadows; | ||||||
|  | 			bool mSM3Available; | ||||||
|  | 
 | ||||||
|  | 			bool isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const; | ||||||
|  | 
 | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	/** @} */ | ||||||
|  | 	/** @} */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
							
								
								
									
										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,5 +123,9 @@ op 0x200013d: FadeOut | ||||||
| op 0x200013e: FadeTo | op 0x200013e: FadeTo | ||||||
| op 0x200013f: GetCurrentWeather | op 0x200013f: GetCurrentWeather | ||||||
| op 0x2000140: ChangeWeather | op 0x2000140: ChangeWeather | ||||||
|  | op 0x2000141: GetWaterLevel | ||||||
|  | op 0x2000142: SetWaterLevel | ||||||
|  | op 0x2000143: ModWaterLevel | ||||||
|  | op 0x2000144: ToggleWater, twa | ||||||
| op 0x2000145: ToggleFogOfWar (tfow) | op 0x2000145: ToggleFogOfWar (tfow) | ||||||
| opcodes 0x2000146-0x3ffffff unused | opcodes 0x2000146-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,12 +441,34 @@ 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); | ||||||
|         for(size_t i = 0;i < maxtotal;i++) |         if (maxtotal == 0) // workaround for broken implementations
 | ||||||
|         { |         { | ||||||
|             ALuint src = 0; |             maxtotal = 256; | ||||||
|             alGenSources(1, &src); |             bool stop = false; | ||||||
|             throwALerror(); |             for(size_t i = 0;i < maxtotal && !stop;i++) // generate source until error returned
 | ||||||
|             mFreeSources.push_back(src); |             { | ||||||
|  |                 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++) | ||||||
|  |             { | ||||||
|  |                 ALuint src = 0; | ||||||
|  |                 alGenSources(1, &src); | ||||||
|  |                 throwALerror(); | ||||||
|  |                 mFreeSources.push_back(src); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     catch(std::exception &e) |     catch(std::exception &e) | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -531,9 +531,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) | ||||||
|             { |             { | ||||||
|  | @ -766,4 +767,15 @@ namespace MWWorld | ||||||
|         Vector2 d = Vector2(dir.x, dir.z); |         Vector2 d = Vector2(dir.x, dir.z); | ||||||
|         return d; |         return d; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     void World::setWaterHeight(const float height) | ||||||
|  |     { | ||||||
|  |         mRendering->setWaterHeight(height); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void World::toggleWater() | ||||||
|  |     { | ||||||
|  |         mRendering->toggleWater(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -113,6 +113,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,11 +114,26 @@ 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); | ||||||
| 
 | 
 | ||||||
|  |   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
 |   // 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
 |   // 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
 |   // somewhere other than the file system, you need to pre-open the
 | ||||||
|  |  | ||||||
|  | @ -4,6 +4,8 @@ namespace ESM | ||||||
| { | { | ||||||
| void Land::load(ESMReader &esm) | void Land::load(ESMReader &esm) | ||||||
| { | { | ||||||
|  |     mEsm = &esm; | ||||||
|  | 
 | ||||||
|     // Get the grid location
 |     // Get the grid location
 | ||||||
|     esm.getSubNameIs("INTV"); |     esm.getSubNameIs("INTV"); | ||||||
|     esm.getSubHeaderIs(8); |     esm.getSubHeaderIs(8); | ||||||
|  | @ -19,14 +21,117 @@ void Land::load(ESMReader &esm) | ||||||
|     int cnt = 0; |     int cnt = 0; | ||||||
| 
 | 
 | ||||||
|     // Skip these here. Load the actual data when the cell is loaded.
 |     // Skip these here. Load the actual data when the cell is loaded.
 | ||||||
|     if(esm.isNextSub("VNML")) {esm.skipHSubSize(12675);cnt++;} |     if (esm.isNextSub("VNML")) | ||||||
|     if(esm.isNextSub("VHGT")) {esm.skipHSubSize(4232);cnt++;} |     { | ||||||
|     if(esm.isNextSub("WNAM")) esm.skipHSubSize(81); |         esm.skipHSubSize(12675); | ||||||
|     if(esm.isNextSub("VCLR")) esm.skipHSubSize(12675); |         cnt++; | ||||||
|     if(esm.isNextSub("VTEX")) {esm.skipHSubSize(512);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
 |     // We need all three of VNML, VHGT and VTEX in order to use the
 | ||||||
|     // landscape.
 |     // landscape.
 | ||||||
|     hasData = (cnt == 3); |     hasData = (cnt == 3); | ||||||
|  | 
 | ||||||
|  |     dataLoaded = false; | ||||||
|  |     landData = NULL; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void Land::loadData() | ||||||
|  | { | ||||||
|  |     if (dataLoaded) | ||||||
|  |     { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     landData = new LandData; | ||||||
|  | 
 | ||||||
|  |     if (hasData) | ||||||
|  |     { | ||||||
|  |         mEsm->restoreContext(context); | ||||||
|  | 
 | ||||||
|  |         //esm.getHNExact(landData->normals, sizeof(VNML), "VNML");
 | ||||||
|  |         if (mEsm->isNextSub("VNML")) | ||||||
|  |         { | ||||||
|  |             mEsm->skipHSubSize(12675); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         VHGT rawHeights; | ||||||
|  | 
 | ||||||
|  |         mEsm->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; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (mEsm->isNextSub("WNAM")) | ||||||
|  |         { | ||||||
|  |             mEsm->skipHSubSize(81); | ||||||
|  |         } | ||||||
|  |         if (mEsm->isNextSub("VCLR")) | ||||||
|  |         { | ||||||
|  |             landData->usingColours = true; | ||||||
|  |             mEsm->getHExact(&landData->colours, 3*LAND_NUM_VERTS); | ||||||
|  |         }else{ | ||||||
|  |             landData->usingColours = false; | ||||||
|  |         } | ||||||
|  |         //TODO fix magic numbers
 | ||||||
|  |         uint16_t vtex[512]; | ||||||
|  |         mEsm->getHNExact(&vtex, 512, "VTEX"); | ||||||
|  | 
 | ||||||
|  |         int readPos = 0; //bit ugly, but it works
 | ||||||
|  |         for ( int y1 = 0; y1 < 4; y1++ ) | ||||||
|  |             for ( int x1 = 0; x1 < 4; x1++ ) | ||||||
|  |                 for ( int y2 = 0; y2 < 4; y2++) | ||||||
|  |                     for ( int x2 = 0; x2 < 4; x2++ ) | ||||||
|  |                         landData->textures[(y1*4+y2)*16+(x1*4+x2)] = vtex[readPos++]; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         landData->usingColours = false; | ||||||
|  |         memset(&landData->textures, 0, 512 * sizeof(uint16_t)); | ||||||
|  |         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; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,11 +17,66 @@ struct Land | ||||||
| 
 | 
 | ||||||
|     // File context. This allows the ESM reader to be 'reset' to this
 |     // File context. This allows the ESM reader to be 'reset' to this
 | ||||||
|     // location later when we are ready to load the full data set.
 |     // location later when we are ready to load the full data set.
 | ||||||
|  |     ESMReader* mEsm; | ||||||
|     ESM_Context context; |     ESM_Context context; | ||||||
| 
 | 
 | ||||||
|     bool hasData; |     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; | ||||||
|  | 
 | ||||||
|  |     //number of textures per side of land
 | ||||||
|  |     static const int LAND_TEXTURE_SIZE = 16; | ||||||
|  | 
 | ||||||
|  |     //total number of textures per land
 | ||||||
|  |     static const int LAND_NUM_TEXTURES = LAND_TEXTURE_SIZE * LAND_TEXTURE_SIZE; | ||||||
|  | 
 | ||||||
|  | #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];
 | ||||||
|  |         uint16_t textures[LAND_NUM_TEXTURES]; | ||||||
|  | 
 | ||||||
|  |         bool usingColours; | ||||||
|  |         char colours[3 * LAND_NUM_VERTS]; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     LandData *landData; | ||||||
|  | 
 | ||||||
|     void load(ESMReader &esm); |     void load(ESMReader &esm); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Actually loads data | ||||||
|  |      */ | ||||||
|  |     void loadData(); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Frees memory allocated for land data | ||||||
|  |      */ | ||||||
|  |     void unloadData(); | ||||||
| }; | }; | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -95,12 +95,17 @@ namespace ESMS | ||||||
|         State_Unloaded, State_Preloaded, State_Loaded |         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) | ||||||
|  |     { | ||||||
|  |         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; | ||||||
|  |  | ||||||
|  | @ -201,15 +201,21 @@ namespace ESMS | ||||||
| 
 | 
 | ||||||
|     // TODO: For multiple ESM/ESP files we need one list per file.
 |     // TODO: For multiple ESM/ESP files we need one list per file.
 | ||||||
|     std::vector<LandTexture> ltex; |     std::vector<LandTexture> ltex; | ||||||
|     int count; |  | ||||||
| 
 | 
 | ||||||
|     LTexList() : count(0) |     LTexList() | ||||||
|     { |     { | ||||||
|       // More than enough to hold Morrowind.esm.
 |       // More than enough to hold Morrowind.esm.
 | ||||||
|       ltex.reserve(128); |       ltex.reserve(128); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     int getSize() { return count; } |     const LandTexture* search(size_t index) const | ||||||
|  |     { | ||||||
|  |         assert(index < ltex.size()); | ||||||
|  |         return <ex.at(index); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int getSize() { return ltex.size(); } | ||||||
|  |     int getSize() const { return ltex.size(); } | ||||||
| 
 | 
 | ||||||
|     virtual void listIdentifier (std::vector<std::string>& identifier) const {} |     virtual void listIdentifier (std::vector<std::string>& identifier) const {} | ||||||
| 
 | 
 | ||||||
|  | @ -233,12 +239,18 @@ namespace ESMS | ||||||
|    */ |    */ | ||||||
|   struct LandList : RecList |   struct LandList : RecList | ||||||
|   { |   { | ||||||
|     virtual ~LandList() {} |     virtual ~LandList() | ||||||
|  |     { | ||||||
|  |       for ( LandMap::iterator itr = lands.begin(); itr != lands.end(); ++itr ) | ||||||
|  |       { | ||||||
|  |           delete itr->second; | ||||||
|  |       } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // Map containing all landscapes
 |     // Map containing all landscapes
 | ||||||
|     typedef std::map<int, Land*> LandsCol; |     typedef std::pair<int, int> LandCoord; | ||||||
|     typedef std::map<int, LandsCol> Lands; |     typedef std::map<LandCoord, Land*> LandMap; | ||||||
|     Lands lands; |     LandMap lands; | ||||||
| 
 | 
 | ||||||
|     int count; |     int count; | ||||||
|     LandList() : count(0) {} |     LandList() : count(0) {} | ||||||
|  | @ -247,17 +259,15 @@ namespace ESMS | ||||||
|     virtual void listIdentifier (std::vector<std::string>& identifier) const {} |     virtual void listIdentifier (std::vector<std::string>& identifier) const {} | ||||||
| 
 | 
 | ||||||
|     // Find land for the given coordinates. Return null if no data.
 |     // 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); |       LandMap::const_iterator itr = lands.find(std::make_pair<int, int>(x, y)); | ||||||
|       if(it==lands.end()) |       if ( itr == lands.end() ) | ||||||
|  |       { | ||||||
|         return NULL; |         return NULL; | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|       LandsCol::const_iterator it2 = it->second.find(y); |       return itr->second; | ||||||
|       if(it2 == it->second.end()) |  | ||||||
|         return NULL; |  | ||||||
| 
 |  | ||||||
|       return it2->second; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void load(ESMReader &esm, const std::string &id) |     void load(ESMReader &esm, const std::string &id) | ||||||
|  | @ -266,11 +276,11 @@ namespace ESMS | ||||||
| 
 | 
 | ||||||
|       // Create the structure and load it. This actually skips the
 |       // Create the structure and load it. This actually skips the
 | ||||||
|       // landscape data and remembers the file position for later.
 |       // landscape data and remembers the file position for later.
 | ||||||
|       Land *land = new Land; |       Land *land = new Land(); | ||||||
|       land->load(esm); |       land->load(esm); | ||||||
| 
 | 
 | ||||||
|       // Store the structure
 |       // Store the structure
 | ||||||
|       lands[land->X][land->Y] = land; |       lands[std::make_pair<int, int>(land->X, land->Y)] = land; | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -116,7 +116,7 @@ namespace ESMS | ||||||
|       recLists[REC_GLOB] = &globals; |       recLists[REC_GLOB] = &globals; | ||||||
|       recLists[REC_GMST] = &gameSettings; |       recLists[REC_GMST] = &gameSettings; | ||||||
|       recLists[REC_INGR] = &ingreds; |       recLists[REC_INGR] = &ingreds; | ||||||
|       //recLists[REC_LAND] = &lands;
 |       recLists[REC_LAND] = &lands; | ||||||
|       recLists[REC_LEVC] = &creatureLists; |       recLists[REC_LEVC] = &creatureLists; | ||||||
|       recLists[REC_LEVI] = &itemLists; |       recLists[REC_LEVI] = &itemLists; | ||||||
|       recLists[REC_LIGH] = &lights; |       recLists[REC_LIGH] = &lights; | ||||||
|  |  | ||||||
							
								
								
									
										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) | ||||||
|  | @ -1,34 +1,29 @@ | ||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| 
 | 
 | ||||||
| <MyGUI type="Layout"> | <MyGUI type="Layout"> | ||||||
|     <Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 588 433" name="_Main"> |     <Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 588 433" name="_Main"> | ||||||
|         <!-- HEADER --> |  | ||||||
|         <Widget type="TextBox" skin="HeaderText" position="0 0 588 18" name="NpcName" align="ALIGN_LEFT ALIGN_TOP"> |  | ||||||
|             <Property key="Caption" value="Name"/> |  | ||||||
|             <Property key="TextAlign" value="ALIGN_CENTER"/> |  | ||||||
|         </Widget> |  | ||||||
| 
 | 
 | ||||||
|         <!-- The Dialogue history --> |         <!-- The Dialogue history --> | ||||||
|         <Widget type="DialogueHistory" skin="MW_TextBoxEdit" position="8 39 400 375" name="History"  align="ALIGN_LEFT ALIGN_TOP STRETCH"> |         <Widget type="DialogueHistory" skin="MW_TextBoxEdit" position="8 8 415 381" name="History"  align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH"> | ||||||
|             <Property key="Static" value="true"/> |             <Property key="Static" value="true"/> | ||||||
|             <Property key="WordWrap" value="true"/> |             <Property key="WordWrap" value="true"/> | ||||||
|             <Property key="MultiLine" value="1" /> |             <Property key="MultiLine" value="1" /> | ||||||
|             <Property key="VisibleVScroll" value="1" /> |             <Property key="VisibleVScroll" value="1" /> | ||||||
|             <!-- invisible box for receiving mouse events --> |             <!-- invisible box for receiving mouse events --> | ||||||
|             <Widget type="Widget" skin="" position="0 0 400 375" name="EventBox" align="ALIGN_LEFT ALIGN_TOP STRETCH"/> |             <Widget type="Widget" skin="" position="0 0 400 375" name="EventBox" align="ALIGN_LEFT ALIGN_TOP ALIGN_STRETCH"/> | ||||||
|         </Widget> |         </Widget> | ||||||
| 
 | 
 | ||||||
| 		<!-- The disposition bar--> | 		<!-- The disposition bar--> | ||||||
|         <Widget type="ProgressBar" skin="MW_EnergyBar_Blue" position="432 39 132 18" |         <Widget type="ProgressBar" skin="MW_EnergyBar_Blue" position="432 8 132 18" | ||||||
|             align="Right Top" name="Disposition"> |             align="Right Top" name="Disposition"> | ||||||
| 			<Widget type="EditBox" skin="MW_DispositionEdit" position_real = "0.25 0 0.5 1" name = "DispositionText"/> | 			<Widget type="EditBox" skin="MW_DispositionEdit" position_real = "0.25 0 0.5 1" name = "DispositionText"/> | ||||||
| 		</Widget> | 		</Widget> | ||||||
|         <!-- The list of topics --> |         <!-- The list of topics --> | ||||||
|         <Widget type="ListBox" skin="MW_List" position="432 62 132 318" name="TopicsList"> |         <Widget type="ListBox" skin="MW_List" position="432 31 132 328" name="TopicsList" align="Right VStretch"> | ||||||
|         </Widget> |         </Widget> | ||||||
| 
 | 
 | ||||||
|         <!-- The Goodbye button --> |         <!-- The Goodbye button --> | ||||||
|         <Widget type="Button" skin="MW_Button" position="432 387 132 23" name="ByeButton"> |         <Widget type="Button" skin="MW_Button" position="432 366 132 23" name="ByeButton" align="Right Bottom"> | ||||||
|             <Property key="Caption" value="Goodbye"/> |             <Property key="Caption" value="Goodbye"/> | ||||||
|         </Widget> |         </Widget> | ||||||
|     </Widget> |     </Widget> | ||||||
|  |  | ||||||
|  | @ -294,7 +294,7 @@ | ||||||
|         <Property key="TextAlign" value = "ALIGN_CENTER" /> |         <Property key="TextAlign" value = "ALIGN_CENTER" /> | ||||||
|         <Property key="TextColour" value = "0.8 0.8 0.8" /> |         <Property key="TextColour" value = "0.8 0.8 0.8" /> | ||||||
| 
 | 
 | ||||||
|         <Child type="Widget" skin="DialogBG" offset = "4 4 248 46" align = "ALIGN_STRETCH" name = "Client"/> |         <Child type="Widget" skin="BlackBG" offset = "4 4 248 46" align = "ALIGN_STRETCH" name = "Client"/> | ||||||
| 
 | 
 | ||||||
|         <!-- Outer borders --> |         <!-- Outer borders --> | ||||||
|         <Child type="Widget" skin="DB_T" offset="4 0 248 4" align="ALIGN_TOP ALIGN_HSTRETCH" name="Border"> |         <Child type="Widget" skin="DB_T" offset="4 0 248 4" align="ALIGN_TOP ALIGN_HSTRETCH" name="Border"> | ||||||
|  |  | ||||||
							
								
								
									
										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