mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 03:35:27 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
ed58e9e553
@ -306,7 +306,7 @@ if(DPKG_PROGRAM)
|
|||||||
Data files from the original game is required to run it.")
|
Data files from the original game is required to run it.")
|
||||||
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
|
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
|
||||||
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
|
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
|
||||||
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher")
|
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
|
||||||
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "nvidia-cg-toolkit (>= 2.1), libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
|
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "nvidia-cg-toolkit (>= 2.1), libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
|
||||||
|
|
||||||
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
|
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
|
||||||
@ -392,6 +392,11 @@ if (BUILD_LAUNCHER)
|
|||||||
add_subdirectory( apps/launcher )
|
add_subdirectory( apps/launcher )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(BUILD_MWINIIMPORTER "build MWiniImporter inspector" ON)
|
||||||
|
if (BUILD_MWINIIMPORTER)
|
||||||
|
add_subdirectory( apps/mwiniimporter )
|
||||||
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
if (USE_DEBUG_CONSOLE)
|
if (USE_DEBUG_CONSOLE)
|
||||||
|
20
apps/mwiniimporter/CMakeLists.txt
Normal file
20
apps/mwiniimporter/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
set(MWINIIMPORT
|
||||||
|
main.cpp
|
||||||
|
importer.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(MWINIIMPORT_HEADER
|
||||||
|
importer.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
source_group(launcher FILES ${MWINIIMPORT} ${MWINIIMPORT_HEADER})
|
||||||
|
|
||||||
|
add_executable(mwiniimport
|
||||||
|
${MWINIIMPORT}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(mwiniimport
|
||||||
|
${Boost_LIBRARIES}
|
||||||
|
components
|
||||||
|
)
|
||||||
|
|
184
apps/mwiniimporter/importer.cpp
Normal file
184
apps/mwiniimporter/importer.cpp
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include "importer.hpp"
|
||||||
|
#include <boost/iostreams/device/file.hpp>
|
||||||
|
#include <boost/iostreams/stream.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
MwIniImporter::MwIniImporter() {
|
||||||
|
const char *map[][2] =
|
||||||
|
{
|
||||||
|
{ "fps", "General:Show FPS" },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
for(int i=0; map[i][0]; i++) {
|
||||||
|
mMergeMap.insert(std::make_pair<std::string, std::string>(map[i][0], map[i][1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MwIniImporter::setVerbose(bool verbose) {
|
||||||
|
mVerbose = verbose;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MwIniImporter::numberToString(int n) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << n;
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
|
||||||
|
std::cout << "load ini file: " << filename << std::endl;
|
||||||
|
|
||||||
|
std::string section("");
|
||||||
|
MwIniImporter::multistrmap map;
|
||||||
|
boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str());
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
|
||||||
|
if(line[0] == '[') {
|
||||||
|
if(line.length() > 2) {
|
||||||
|
section = line.substr(1, line.length()-3);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int comment_pos = line.find(";");
|
||||||
|
if(comment_pos > 0) {
|
||||||
|
line = line.substr(0,comment_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = line.find("=");
|
||||||
|
if(pos < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key(section + ":" + line.substr(0,pos));
|
||||||
|
std::string value(line.substr(pos+1));
|
||||||
|
|
||||||
|
multistrmap::iterator it;
|
||||||
|
if((it = map.find(key)) == map.end()) {
|
||||||
|
map.insert( std::make_pair<std::string, std::vector<std::string> > (key, std::vector<std::string>() ) );
|
||||||
|
}
|
||||||
|
map[key].push_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) {
|
||||||
|
std::cout << "load cfg file: " << filename << std::endl;
|
||||||
|
|
||||||
|
MwIniImporter::multistrmap map;
|
||||||
|
boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str());
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
|
||||||
|
// we cant say comment by only looking at first char anymore
|
||||||
|
int comment_pos = line.find("#");
|
||||||
|
if(comment_pos > 0) {
|
||||||
|
line = line.substr(0,comment_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = line.find("=");
|
||||||
|
if(pos < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key(line.substr(0,pos));
|
||||||
|
std::string value(line.substr(pos+1));
|
||||||
|
|
||||||
|
multistrmap::iterator it;
|
||||||
|
if((it = map.find(key)) == map.end()) {
|
||||||
|
map.insert( std::make_pair<std::string, std::vector<std::string> > (key, std::vector<std::string>() ) );
|
||||||
|
}
|
||||||
|
map[key].push_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) {
|
||||||
|
multistrmap::iterator cfgIt;
|
||||||
|
multistrmap::iterator iniIt;
|
||||||
|
for(strmap::iterator it=mMergeMap.begin(); it!=mMergeMap.end(); it++) {
|
||||||
|
if((iniIt = ini.find(it->second)) != ini.end()) {
|
||||||
|
cfg.erase(it->first);
|
||||||
|
if(!this->specialMerge(it->first, it->second, cfg, ini)) {
|
||||||
|
cfg.insert(std::make_pair<std::string, std::vector<std::string> >(it->first, iniIt->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MwIniImporter::specialMerge(std::string cfgKey, std::string iniKey, multistrmap &cfg, multistrmap &ini) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
|
||||||
|
std::vector<std::string> esmFiles;
|
||||||
|
std::vector<std::string> espFiles;
|
||||||
|
std::string baseGameFile("Game Files:GameFile");
|
||||||
|
std::string gameFile("");
|
||||||
|
|
||||||
|
multistrmap::iterator it = ini.begin();
|
||||||
|
for(int i=0; it != ini.end(); i++) {
|
||||||
|
gameFile = baseGameFile;
|
||||||
|
gameFile.append(this->numberToString(i));
|
||||||
|
|
||||||
|
it = ini.find(gameFile);
|
||||||
|
if(it == ini.end()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); entry++) {
|
||||||
|
std::string filetype(entry->substr(entry->length()-4, 3));
|
||||||
|
std::transform(filetype.begin(), filetype.end(), filetype.begin(), ::tolower);
|
||||||
|
|
||||||
|
if(filetype.compare("esm") == 0) {
|
||||||
|
esmFiles.push_back(*entry);
|
||||||
|
}
|
||||||
|
else if(filetype.compare("esp") == 0) {
|
||||||
|
espFiles.push_back(*entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gameFile = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.erase("master");
|
||||||
|
cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("master", std::vector<std::string>() ) );
|
||||||
|
|
||||||
|
for(std::vector<std::string>::iterator it=esmFiles.begin(); it!=esmFiles.end(); it++) {
|
||||||
|
cfg["master"].push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.erase("plugin");
|
||||||
|
cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("plugin", std::vector<std::string>() ) );
|
||||||
|
|
||||||
|
for(std::vector<std::string>::iterator it=espFiles.begin(); it!=espFiles.end(); it++) {
|
||||||
|
cfg["plugin"].push_back(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg) {
|
||||||
|
|
||||||
|
for(multistrmap::iterator it=cfg.begin(); it != cfg.end(); it++) {
|
||||||
|
for(std::vector<std::string>::iterator entry=it->second.begin(); entry != it->second.end(); entry++) {
|
||||||
|
out << (it->first) << "=" << (*entry) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
apps/mwiniimporter/importer.hpp
Normal file
32
apps/mwiniimporter/importer.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef MWINIIMPORTER_IMPORTER
|
||||||
|
#define MWINIIMPORTER_IMPORTER 1
|
||||||
|
|
||||||
|
#include <boost/iostreams/device/file.hpp>
|
||||||
|
#include <boost/iostreams/stream.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
class MwIniImporter {
|
||||||
|
public:
|
||||||
|
typedef std::map<std::string, std::string> strmap;
|
||||||
|
typedef std::map<std::string, std::vector<std::string> > multistrmap;
|
||||||
|
|
||||||
|
MwIniImporter();
|
||||||
|
void setVerbose(bool verbose);
|
||||||
|
multistrmap loadIniFile(std::string filename);
|
||||||
|
multistrmap loadCfgFile(std::string filename);
|
||||||
|
void merge(multistrmap &cfg, multistrmap &ini);
|
||||||
|
void importGameFiles(multistrmap &cfg, multistrmap &ini);
|
||||||
|
void writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool specialMerge(std::string cfgKey, std::string iniKey, multistrmap &cfg, multistrmap &ini);
|
||||||
|
std::string numberToString(int n);
|
||||||
|
bool mVerbose;
|
||||||
|
strmap mMergeMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
79
apps/mwiniimporter/main.cpp
Normal file
79
apps/mwiniimporter/main.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include "importer.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
bpo::options_description desc("Syntax: mwiniimporter <options>\nAllowed options");
|
||||||
|
desc.add_options()
|
||||||
|
("help,h", "produce help message")
|
||||||
|
("verbose,v", "verbose output")
|
||||||
|
("ini,i", bpo::value<std::string>(), "morrowind.ini file")
|
||||||
|
("cfg,c", bpo::value<std::string>(), "openmw.cfg file")
|
||||||
|
("output,o", bpo::value<std::string>()->default_value(""), "openmw.cfg file")
|
||||||
|
("game-files,g", "import esm and esp files")
|
||||||
|
;
|
||||||
|
|
||||||
|
bpo::variables_map vm;
|
||||||
|
try {
|
||||||
|
bpo::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
|
||||||
|
|
||||||
|
// parse help before calling notify because we dont want it to throw an error if help is set
|
||||||
|
if(vm.count("help")) {
|
||||||
|
std::cout << desc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpo::notify(vm);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(std::exception& e) {
|
||||||
|
std::cerr << "Error:" << e.what() << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
std::cerr << "Error" << std::endl;
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string iniFile = vm["ini"].as<std::string>();
|
||||||
|
std::string cfgFile = vm["cfg"].as<std::string>();
|
||||||
|
|
||||||
|
// if no output is given, write back to cfg file
|
||||||
|
std::string outputFile(vm["output"].as<std::string>());
|
||||||
|
if(vm["output"].defaulted()) {
|
||||||
|
outputFile = vm["cfg"].as<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!boost::filesystem::exists(iniFile)) {
|
||||||
|
std::cerr << "ini file does not exist" << std::endl;
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
if(!boost::filesystem::exists(cfgFile)) {
|
||||||
|
std::cerr << "cfg file does not exist" << std::endl;
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
MwIniImporter importer;
|
||||||
|
importer.setVerbose(vm.count("verbose"));
|
||||||
|
boost::iostreams::stream<boost::iostreams::file_sink> file(outputFile);
|
||||||
|
|
||||||
|
MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile);
|
||||||
|
MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile);
|
||||||
|
|
||||||
|
importer.merge(cfg, ini);
|
||||||
|
|
||||||
|
if(vm.count("game-files")) {
|
||||||
|
importer.importGameFiles(cfg, ini);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "write to: " << outputFile << std::endl;
|
||||||
|
importer.writeToFile(file, cfg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -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 water terrain terrainmaterial
|
renderinginterface localmap occlusionquery terrain terrainmaterial water
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
254
apps/openmw/mwrender/occlusionquery.cpp
Normal file
254
apps/openmw/mwrender/occlusionquery.cpp
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
#include "occlusionquery.hpp"
|
||||||
|
|
||||||
|
#include <OgreRenderSystem.h>
|
||||||
|
#include <OgreRoot.h>
|
||||||
|
#include <OgreBillboardSet.h>
|
||||||
|
#include <OgreHardwareOcclusionQuery.h>
|
||||||
|
#include <OgreEntity.h>
|
||||||
|
|
||||||
|
using namespace MWRender;
|
||||||
|
using namespace Ogre;
|
||||||
|
|
||||||
|
OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) :
|
||||||
|
mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0),
|
||||||
|
mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false),
|
||||||
|
mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false)
|
||||||
|
{
|
||||||
|
mRendering = renderer;
|
||||||
|
mSunNode = sunNode;
|
||||||
|
|
||||||
|
try {
|
||||||
|
RenderSystem* renderSystem = Root::getSingleton().getRenderSystem();
|
||||||
|
|
||||||
|
mSunTotalAreaQuery = renderSystem->createHardwareOcclusionQuery();
|
||||||
|
mSunVisibleAreaQuery = renderSystem->createHardwareOcclusionQuery();
|
||||||
|
mSingleObjectQuery = renderSystem->createHardwareOcclusionQuery();
|
||||||
|
|
||||||
|
mSupported = (mSunTotalAreaQuery != 0) && (mSunVisibleAreaQuery != 0) && (mSingleObjectQuery != 0);
|
||||||
|
}
|
||||||
|
catch (Ogre::Exception e)
|
||||||
|
{
|
||||||
|
mSupported = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mSupported)
|
||||||
|
{
|
||||||
|
std::cout << "Hardware occlusion queries not supported." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This means that everything up to RENDER_QUEUE_MAIN can occlude the objects that are tested
|
||||||
|
const int queue = RENDER_QUEUE_MAIN+1;
|
||||||
|
|
||||||
|
MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting");
|
||||||
|
MaterialPtr matQueryArea = matBase->clone("QueryTotalPixels");
|
||||||
|
matQueryArea->setDepthWriteEnabled(false);
|
||||||
|
matQueryArea->setColourWriteEnabled(false);
|
||||||
|
matQueryArea->setDepthCheckEnabled(false); // Not occluded by objects
|
||||||
|
MaterialPtr matQueryVisible = matBase->clone("QueryVisiblePixels");
|
||||||
|
matQueryVisible->setDepthWriteEnabled(false);
|
||||||
|
matQueryVisible->setColourWriteEnabled(false); // Uncomment this to visualize the occlusion query
|
||||||
|
matQueryVisible->setDepthCheckEnabled(true); // Occluded by objects
|
||||||
|
matQueryVisible->setCullingMode(CULL_NONE);
|
||||||
|
matQueryVisible->setManualCullingMode(MANUAL_CULL_NONE);
|
||||||
|
|
||||||
|
mBBNode = mSunNode->getParentSceneNode()->createChildSceneNode();
|
||||||
|
|
||||||
|
mObjectNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode();
|
||||||
|
mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode();
|
||||||
|
|
||||||
|
mBBQueryTotal = mRendering->getScene()->createBillboardSet(1);
|
||||||
|
mBBQueryTotal->setDefaultDimensions(150, 150);
|
||||||
|
mBBQueryTotal->createBillboard(Vector3::ZERO);
|
||||||
|
mBBQueryTotal->setMaterialName("QueryTotalPixels");
|
||||||
|
mBBQueryTotal->setRenderQueueGroup(queue+1);
|
||||||
|
mBBNodeReal->attachObject(mBBQueryTotal);
|
||||||
|
|
||||||
|
mBBQueryVisible = mRendering->getScene()->createBillboardSet(1);
|
||||||
|
mBBQueryVisible->setDefaultDimensions(150, 150);
|
||||||
|
mBBQueryVisible->createBillboard(Vector3::ZERO);
|
||||||
|
mBBQueryVisible->setMaterialName("QueryVisiblePixels");
|
||||||
|
mBBQueryVisible->setRenderQueueGroup(queue+1);
|
||||||
|
mBBNodeReal->attachObject(mBBQueryVisible);
|
||||||
|
|
||||||
|
mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1);
|
||||||
|
/// \todo ideally this should occupy exactly 1 pixel on the screen
|
||||||
|
mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003);
|
||||||
|
mBBQuerySingleObject->createBillboard(Vector3::ZERO);
|
||||||
|
mBBQuerySingleObject->setMaterialName("QueryVisiblePixels");
|
||||||
|
mBBQuerySingleObject->setRenderQueueGroup(queue);
|
||||||
|
mObjectNode->attachObject(mBBQuerySingleObject);
|
||||||
|
|
||||||
|
mRendering->getScene()->addRenderObjectListener(this);
|
||||||
|
mRendering->getScene()->addRenderQueueListener(this);
|
||||||
|
mDoQuery = true;
|
||||||
|
mDoQuery2 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
OcclusionQuery::~OcclusionQuery()
|
||||||
|
{
|
||||||
|
RenderSystem* renderSystem = Root::getSingleton().getRenderSystem();
|
||||||
|
if (mSunTotalAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery);
|
||||||
|
if (mSunVisibleAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery);
|
||||||
|
if (mSingleObjectQuery) renderSystem->destroyHardwareOcclusionQuery(mSingleObjectQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OcclusionQuery::supported()
|
||||||
|
{
|
||||||
|
return mSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source,
|
||||||
|
const LightList* pLightList, bool suppressRenderStateChanges)
|
||||||
|
{
|
||||||
|
// The following code activates and deactivates the occlusion queries
|
||||||
|
// so that the queries only include the rendering of their intended targets
|
||||||
|
|
||||||
|
// Close the last occlusion query
|
||||||
|
// Each occlusion query should only last a single rendering
|
||||||
|
if (mActiveQuery != NULL)
|
||||||
|
{
|
||||||
|
mActiveQuery->endOcclusionQuery();
|
||||||
|
mActiveQuery = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a new occlusion query
|
||||||
|
if (mDoQuery == true)
|
||||||
|
{
|
||||||
|
if (rend == mBBQueryTotal)
|
||||||
|
{
|
||||||
|
mActiveQuery = mSunTotalAreaQuery;
|
||||||
|
mWasVisible = true;
|
||||||
|
}
|
||||||
|
else if (rend == mBBQueryVisible)
|
||||||
|
{
|
||||||
|
mActiveQuery = mSunVisibleAreaQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mDoQuery == true && rend == mBBQuerySingleObject)
|
||||||
|
{
|
||||||
|
mQuerySingleObjectStarted = true;
|
||||||
|
mQuerySingleObjectRequested = false;
|
||||||
|
mActiveQuery = mSingleObjectQuery;
|
||||||
|
mObjectWasVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mActiveQuery != NULL)
|
||||||
|
mActiveQuery->beginOcclusionQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation)
|
||||||
|
{
|
||||||
|
if (mActiveQuery != NULL)
|
||||||
|
{
|
||||||
|
mActiveQuery->endOcclusionQuery();
|
||||||
|
mActiveQuery = NULL;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* for every beginOcclusionQuery(), we want a respective pullOcclusionQuery() and vice versa
|
||||||
|
* this also means that results can be wrong at other places if we pull, but beginOcclusionQuery() was never called
|
||||||
|
* this can happen for example if the object that is tested is outside of the view frustum
|
||||||
|
* to prevent this, check if the queries have been performed after everything has been rendered and if not, start them manually
|
||||||
|
*/
|
||||||
|
if (queueGroupId == RENDER_QUEUE_SKIES_LATE)
|
||||||
|
{
|
||||||
|
if (mWasVisible == false && mDoQuery)
|
||||||
|
{
|
||||||
|
mSunTotalAreaQuery->beginOcclusionQuery();
|
||||||
|
mSunTotalAreaQuery->endOcclusionQuery();
|
||||||
|
mSunVisibleAreaQuery->beginOcclusionQuery();
|
||||||
|
mSunVisibleAreaQuery->endOcclusionQuery();
|
||||||
|
}
|
||||||
|
if (mObjectWasVisible == false && mDoQuery)
|
||||||
|
{
|
||||||
|
mSingleObjectQuery->beginOcclusionQuery();
|
||||||
|
mSingleObjectQuery->endOcclusionQuery();
|
||||||
|
mQuerySingleObjectStarted = true;
|
||||||
|
mQuerySingleObjectRequested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OcclusionQuery::update(float duration)
|
||||||
|
{
|
||||||
|
if (!mSupported) return;
|
||||||
|
|
||||||
|
mWasVisible = false;
|
||||||
|
mObjectWasVisible = false;
|
||||||
|
|
||||||
|
// Adjust the position of the sun billboards according to camera viewing distance
|
||||||
|
// we need to do this to make sure that _everything_ can occlude the sun
|
||||||
|
float dist = mRendering->getCamera()->getFarClipDistance();
|
||||||
|
if (dist==0) dist = 10000000;
|
||||||
|
dist -= 1000; // bias
|
||||||
|
dist /= 1000.f;
|
||||||
|
mBBNode->setPosition(mSunNode->getPosition() * dist);
|
||||||
|
mBBNode->setScale(dist, dist, dist);
|
||||||
|
mBBNodeReal->setPosition(mBBNode->_getDerivedPosition());
|
||||||
|
mBBNodeReal->setScale(mBBNode->getScale());
|
||||||
|
|
||||||
|
// Stop occlusion queries until we get their information
|
||||||
|
// (may not happen on the same frame they are requested in)
|
||||||
|
mDoQuery = false;
|
||||||
|
mDoQuery2 = false;
|
||||||
|
|
||||||
|
if (!mSunTotalAreaQuery->isStillOutstanding()
|
||||||
|
&& !mSunVisibleAreaQuery->isStillOutstanding()
|
||||||
|
&& !mSingleObjectQuery->isStillOutstanding())
|
||||||
|
{
|
||||||
|
unsigned int totalPixels;
|
||||||
|
unsigned int visiblePixels;
|
||||||
|
|
||||||
|
mSunTotalAreaQuery->pullOcclusionQuery(&totalPixels);
|
||||||
|
mSunVisibleAreaQuery->pullOcclusionQuery(&visiblePixels);
|
||||||
|
|
||||||
|
if (totalPixels == 0)
|
||||||
|
{
|
||||||
|
// probably outside of the view frustum
|
||||||
|
mSunVisibility = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mSunVisibility = float(visiblePixels) / float(totalPixels);
|
||||||
|
if (mSunVisibility > 1) mSunVisibility = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int result;
|
||||||
|
|
||||||
|
mSingleObjectQuery->pullOcclusionQuery(&result);
|
||||||
|
|
||||||
|
mTestResult = (result != 0);
|
||||||
|
|
||||||
|
mQuerySingleObjectStarted = false;
|
||||||
|
mQuerySingleObjectRequested = false;
|
||||||
|
|
||||||
|
mDoQuery = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNode* object)
|
||||||
|
{
|
||||||
|
assert( !occlusionTestPending()
|
||||||
|
&& "Occlusion test still pending");
|
||||||
|
|
||||||
|
mBBQuerySingleObject->setVisible(true);
|
||||||
|
|
||||||
|
mObjectNode->setPosition(position);
|
||||||
|
// scale proportional to camera distance, in order to always give the billboard the same size in screen-space
|
||||||
|
mObjectNode->setScale( Vector3(1,1,1)*(position - mRendering->getCamera()->getRealPosition()).length() );
|
||||||
|
|
||||||
|
mQuerySingleObjectRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OcclusionQuery::occlusionTestPending()
|
||||||
|
{
|
||||||
|
return (mQuerySingleObjectRequested || mQuerySingleObjectStarted);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OcclusionQuery::getTestResult()
|
||||||
|
{
|
||||||
|
assert( !occlusionTestPending()
|
||||||
|
&& "Occlusion test still pending");
|
||||||
|
|
||||||
|
return mTestResult;
|
||||||
|
}
|
95
apps/openmw/mwrender/occlusionquery.hpp
Normal file
95
apps/openmw/mwrender/occlusionquery.hpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#ifndef _GAME_OCCLUSION_QUERY_H
|
||||||
|
#define _GAME_OCCLUSION_QUERY_H
|
||||||
|
|
||||||
|
#include <OgreRenderObjectListener.h>
|
||||||
|
#include <OgreRenderQueueListener.h>
|
||||||
|
|
||||||
|
namespace Ogre
|
||||||
|
{
|
||||||
|
class HardwareOcclusionQuery;
|
||||||
|
class Entity;
|
||||||
|
class SceneNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <openengine/ogre/renderer.hpp>
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
///
|
||||||
|
/// \brief Implements hardware occlusion queries on the GPU
|
||||||
|
///
|
||||||
|
class OcclusionQuery : public Ogre::RenderObjectListener, public Ogre::RenderQueueListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OcclusionQuery(OEngine::Render::OgreRenderer*, Ogre::SceneNode* sunNode);
|
||||||
|
~OcclusionQuery();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if occlusion queries are supported on the user's hardware
|
||||||
|
*/
|
||||||
|
bool supported();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* per-frame update
|
||||||
|
*/
|
||||||
|
void update(float duration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* request occlusion test for a billboard at the given position, omitting an entity
|
||||||
|
* @param position of the billboard in ogre coordinates
|
||||||
|
* @param object to exclude from the occluders
|
||||||
|
*/
|
||||||
|
void occlusionTest(const Ogre::Vector3& position, Ogre::SceneNode* object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if a request is still outstanding
|
||||||
|
*/
|
||||||
|
bool occlusionTestPending();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the object tested in the last request was occluded
|
||||||
|
*/
|
||||||
|
bool getTestResult();
|
||||||
|
|
||||||
|
float getSunVisibility() const {return mSunVisibility;};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ogre::HardwareOcclusionQuery* mSunTotalAreaQuery;
|
||||||
|
Ogre::HardwareOcclusionQuery* mSunVisibleAreaQuery;
|
||||||
|
Ogre::HardwareOcclusionQuery* mSingleObjectQuery;
|
||||||
|
Ogre::HardwareOcclusionQuery* mActiveQuery;
|
||||||
|
|
||||||
|
Ogre::BillboardSet* mBBQueryVisible;
|
||||||
|
Ogre::BillboardSet* mBBQueryTotal;
|
||||||
|
Ogre::BillboardSet* mBBQuerySingleObject;
|
||||||
|
|
||||||
|
Ogre::SceneNode* mSunNode;
|
||||||
|
Ogre::SceneNode* mBBNode;
|
||||||
|
Ogre::SceneNode* mBBNodeReal;
|
||||||
|
float mSunVisibility;
|
||||||
|
|
||||||
|
Ogre::SceneNode* mObjectNode;
|
||||||
|
|
||||||
|
bool mWasVisible;
|
||||||
|
bool mObjectWasVisible;
|
||||||
|
|
||||||
|
bool mTestResult;
|
||||||
|
|
||||||
|
bool mSupported;
|
||||||
|
bool mDoQuery;
|
||||||
|
bool mDoQuery2;
|
||||||
|
|
||||||
|
bool mQuerySingleObjectRequested;
|
||||||
|
bool mQuerySingleObjectStarted;
|
||||||
|
|
||||||
|
OEngine::Render::OgreRenderer* mRendering;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void notifyRenderSingleObject(Ogre::Renderable* rend, const Ogre::Pass* pass, const Ogre::AutoParamDataSource* source,
|
||||||
|
const Ogre::LightList* pLightList, bool suppressRenderStateChanges);
|
||||||
|
|
||||||
|
virtual void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -47,9 +47,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
|||||||
mObjects.setMwRoot(mMwRoot);
|
mObjects.setMwRoot(mMwRoot);
|
||||||
mActors.setMwRoot(mMwRoot);
|
mActors.setMwRoot(mMwRoot);
|
||||||
|
|
||||||
//used to obtain ingame information of ogre objects (which are faced or selected)
|
|
||||||
mRaySceneQuery = mRendering.getScene()->createRayQuery(Ray());
|
|
||||||
|
|
||||||
Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player");
|
Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player");
|
||||||
playerNode->pitch(Degree(90));
|
playerNode->pitch(Degree(90));
|
||||||
Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode();
|
Ogre::SceneNode *cameraYawNode = playerNode->createChildSceneNode();
|
||||||
@ -59,10 +56,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);
|
||||||
|
|
||||||
|
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
|
||||||
|
|
||||||
mWater = 0;
|
mWater = 0;
|
||||||
|
|
||||||
|
|
||||||
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
||||||
mSun = 0;
|
mSun = 0;
|
||||||
|
|
||||||
@ -76,6 +73,7 @@ RenderingManager::~RenderingManager ()
|
|||||||
delete mSkyManager;
|
delete mSkyManager;
|
||||||
delete mTerrainManager;
|
delete mTerrainManager;
|
||||||
delete mLocalMap;
|
delete mLocalMap;
|
||||||
|
delete mOcclusionQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWRender::SkyManager* RenderingManager::getSkyManager()
|
MWRender::SkyManager* RenderingManager::getSkyManager()
|
||||||
@ -167,8 +165,12 @@ void RenderingManager::update (float duration){
|
|||||||
|
|
||||||
mActors.update (duration);
|
mActors.update (duration);
|
||||||
|
|
||||||
|
mOcclusionQuery->update(duration);
|
||||||
|
|
||||||
mSkyManager->update(duration);
|
mSkyManager->update(duration);
|
||||||
|
|
||||||
|
mSkyManager->setGlare(mOcclusionQuery->getSunVisibility());
|
||||||
|
|
||||||
mRendering.update(duration);
|
mRendering.update(duration);
|
||||||
|
|
||||||
mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealDirection() );
|
mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealDirection() );
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "water.hpp"
|
#include "water.hpp"
|
||||||
#include "localmap.hpp"
|
#include "localmap.hpp"
|
||||||
|
#include "occlusionquery.hpp"
|
||||||
|
|
||||||
namespace Ogre
|
namespace Ogre
|
||||||
{
|
{
|
||||||
@ -108,6 +109,9 @@ class RenderingManager: private RenderingInterface {
|
|||||||
void sunEnable();
|
void sunEnable();
|
||||||
void sunDisable();
|
void sunDisable();
|
||||||
|
|
||||||
|
bool occlusionQuerySupported() { return mOcclusionQuery->supported(); };
|
||||||
|
OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; };
|
||||||
|
|
||||||
void setGlare(bool glare);
|
void setGlare(bool glare);
|
||||||
void skyEnable ();
|
void skyEnable ();
|
||||||
void skyDisable ();
|
void skyDisable ();
|
||||||
@ -145,10 +149,12 @@ class RenderingManager: private RenderingInterface {
|
|||||||
|
|
||||||
SkyManager* mSkyManager;
|
SkyManager* mSkyManager;
|
||||||
|
|
||||||
MWRender::Water *mWater;
|
OcclusionQuery* mOcclusionQuery;
|
||||||
|
|
||||||
TerrainManager* mTerrainManager;
|
TerrainManager* mTerrainManager;
|
||||||
|
|
||||||
|
MWRender::Water *mWater;
|
||||||
|
|
||||||
OEngine::Render::OgreRenderer &mRendering;
|
OEngine::Render::OgreRenderer &mRendering;
|
||||||
|
|
||||||
MWRender::Objects mObjects;
|
MWRender::Objects mObjects;
|
||||||
@ -164,7 +170,6 @@ class RenderingManager: private RenderingInterface {
|
|||||||
/// that the OGRE coordinate system matches that used internally in
|
/// that the OGRE coordinate system matches that used internally in
|
||||||
/// Morrowind.
|
/// Morrowind.
|
||||||
Ogre::SceneNode *mMwRoot;
|
Ogre::SceneNode *mMwRoot;
|
||||||
Ogre::RaySceneQuery *mRaySceneQuery;
|
|
||||||
|
|
||||||
OEngine::Physic::PhysicEngine* mPhysicsEngine;
|
OEngine::Physic::PhysicEngine* mPhysicsEngine;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "../mwworld/environment.hpp"
|
#include "../mwworld/environment.hpp"
|
||||||
#include "../mwworld/world.hpp"
|
#include "../mwworld/world.hpp"
|
||||||
|
#include "occlusionquery.hpp"
|
||||||
|
|
||||||
using namespace MWRender;
|
using namespace MWRender;
|
||||||
using namespace Ogre;
|
using namespace Ogre;
|
||||||
@ -30,7 +31,7 @@ BillboardObject::BillboardObject()
|
|||||||
|
|
||||||
void BillboardObject::setVisible(const bool visible)
|
void BillboardObject::setVisible(const bool visible)
|
||||||
{
|
{
|
||||||
mNode->setVisible(visible);
|
mBBSet->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BillboardObject::setSize(const float size)
|
void BillboardObject::setSize(const float size)
|
||||||
@ -88,7 +89,7 @@ void BillboardObject::init(const String& textureName,
|
|||||||
/// \todo These billboards are not 100% correct, might want to revisit them later
|
/// \todo These billboards are not 100% correct, might want to revisit them later
|
||||||
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
|
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
|
||||||
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
|
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
|
||||||
mBBSet->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+2);
|
mBBSet->setRenderQueueGroup(RENDER_QUEUE_MAIN+2);
|
||||||
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
|
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
|
||||||
mBBSet->setCommonDirection( -position.normalisedCopy() );
|
mBBSet->setCommonDirection( -position.normalisedCopy() );
|
||||||
mNode = rootNode->createChildSceneNode();
|
mNode = rootNode->createChildSceneNode();
|
||||||
@ -319,8 +320,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
|||||||
, mThunderTextureUnit(NULL)
|
, mThunderTextureUnit(NULL)
|
||||||
, mRemainingTransitionTime(0.0f)
|
, mRemainingTransitionTime(0.0f)
|
||||||
, mGlareFade(0.0f)
|
, mGlareFade(0.0f)
|
||||||
|
, mGlare(0.0f)
|
||||||
, mEnabled(true)
|
, mEnabled(true)
|
||||||
, mGlareEnabled(true)
|
|
||||||
, mSunEnabled(true)
|
, mSunEnabled(true)
|
||||||
, mMasserEnabled(true)
|
, mMasserEnabled(true)
|
||||||
, mSecundaEnabled(true)
|
, mSecundaEnabled(true)
|
||||||
@ -592,10 +593,23 @@ void SkyManager::update(float duration)
|
|||||||
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||||
mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||||
|
|
||||||
// increase the strength of the sun glare effect depending
|
|
||||||
// on how directly the player is looking at the sun
|
|
||||||
if (mSunEnabled)
|
if (mSunEnabled)
|
||||||
{
|
{
|
||||||
|
// take 1/5 sec for fading the glare effect from invisible to full
|
||||||
|
if (mGlareFade > mGlare)
|
||||||
|
{
|
||||||
|
mGlareFade -= duration*5;
|
||||||
|
if (mGlareFade < mGlare) mGlareFade = mGlare;
|
||||||
|
}
|
||||||
|
else if (mGlareFade < mGlare)
|
||||||
|
{
|
||||||
|
mGlareFade += duration*5;
|
||||||
|
if (mGlareFade > mGlare) mGlareFade = mGlare;
|
||||||
|
}
|
||||||
|
|
||||||
|
// increase the strength of the sun glare effect depending
|
||||||
|
// on how directly the player is looking at the sun
|
||||||
Vector3 sun = mSunGlare->getPosition();
|
Vector3 sun = mSunGlare->getPosition();
|
||||||
sun = Vector3(sun.x, sun.z, -sun.y);
|
sun = Vector3(sun.x, sun.z, -sun.y);
|
||||||
Vector3 cam = mViewport->getCamera()->getRealDirection();
|
Vector3 cam = mViewport->getCamera()->getRealDirection();
|
||||||
@ -603,21 +617,10 @@ void SkyManager::update(float duration)
|
|||||||
float val = 1- (angle.valueDegrees() / 180.f);
|
float val = 1- (angle.valueDegrees() / 180.f);
|
||||||
val = (val*val*val*val)*2;
|
val = (val*val*val*val)*2;
|
||||||
|
|
||||||
if (mGlareEnabled)
|
mSunGlare->setSize(val * mGlareFade);
|
||||||
{
|
|
||||||
mGlareFade += duration*3;
|
|
||||||
if (mGlareFade > 1) mGlareFade = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mGlareFade -= duration*3;
|
|
||||||
if (mGlareFade < 0.3) mGlareFade = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mSunGlare->setSize(val * (mGlareFade));
|
mSunGlare->setVisible(mSunEnabled);
|
||||||
}
|
|
||||||
|
|
||||||
mSunGlare->setVisible(mGlareFade>0 && mSunEnabled);
|
|
||||||
mSun->setVisible(mSunEnabled);
|
mSun->setVisible(mSunEnabled);
|
||||||
mMasser->setVisible(mMasserEnabled);
|
mMasser->setVisible(mMasserEnabled);
|
||||||
mSecunda->setVisible(mSecundaEnabled);
|
mSecunda->setVisible(mSecundaEnabled);
|
||||||
@ -719,15 +722,15 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
|||||||
else
|
else
|
||||||
strength = 1.f;
|
strength = 1.f;
|
||||||
|
|
||||||
mSunGlare->setVisibility(weather.mGlareView * strength);
|
mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength);
|
||||||
mSun->setVisibility(strength);
|
mSun->setVisibility(mGlareFade >= 0.5 ? weather.mGlareView * mGlareFade * strength : 0);
|
||||||
|
|
||||||
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
|
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setGlare(bool glare)
|
void SkyManager::setGlare(const float glare)
|
||||||
{
|
{
|
||||||
mGlareEnabled = glare;
|
mGlare = glare;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 SkyManager::getRealSunPos()
|
Vector3 SkyManager::getRealSunPos()
|
||||||
@ -812,3 +815,8 @@ void SkyManager::setDate(int day, int month)
|
|||||||
mDay = day;
|
mDay = day;
|
||||||
mMonth = month;
|
mMonth = month;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ogre::SceneNode* SkyManager::getSunNode()
|
||||||
|
{
|
||||||
|
return mSun->getNode();
|
||||||
|
}
|
||||||
|
@ -138,6 +138,8 @@ namespace MWRender
|
|||||||
|
|
||||||
void setWeather(const MWWorld::WeatherResult& weather);
|
void setWeather(const MWWorld::WeatherResult& weather);
|
||||||
|
|
||||||
|
Ogre::SceneNode* getSunNode();
|
||||||
|
|
||||||
void sunEnable();
|
void sunEnable();
|
||||||
|
|
||||||
void sunDisable();
|
void sunDisable();
|
||||||
@ -160,7 +162,7 @@ namespace MWRender
|
|||||||
|
|
||||||
void setThunder(const float factor);
|
void setThunder(const float factor);
|
||||||
|
|
||||||
void setGlare(bool glare);
|
void setGlare(const float glare);
|
||||||
Ogre::Vector3 getRealSunPos();
|
Ogre::Vector3 getRealSunPos();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -203,12 +205,12 @@ namespace MWRender
|
|||||||
|
|
||||||
float mRemainingTransitionTime;
|
float mRemainingTransitionTime;
|
||||||
|
|
||||||
float mGlareFade;
|
float mGlare; // target
|
||||||
|
float mGlareFade; // actual
|
||||||
|
|
||||||
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
|
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
|
||||||
|
|
||||||
bool mEnabled;
|
bool mEnabled;
|
||||||
bool mGlareEnabled;
|
|
||||||
bool mSunEnabled;
|
bool mSunEnabled;
|
||||||
bool mMasserEnabled;
|
bool mMasserEnabled;
|
||||||
bool mSecundaEnabled;
|
bool mSecundaEnabled;
|
||||||
|
@ -261,7 +261,16 @@ bool OpenAL_SoundStream::isPlaying()
|
|||||||
|
|
||||||
void OpenAL_SoundStream::update()
|
void OpenAL_SoundStream::update()
|
||||||
{
|
{
|
||||||
alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume);
|
ALfloat gain = mVolume*mBaseVolume;
|
||||||
|
ALfloat pitch = mPitch;
|
||||||
|
if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
|
||||||
|
{
|
||||||
|
gain *= 0.9f;
|
||||||
|
pitch *= 0.7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
alSourcef(mSource, AL_GAIN, gain);
|
||||||
|
alSourcef(mSource, AL_PITCH, pitch);
|
||||||
alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
|
alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
|
||||||
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
|
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
|
||||||
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||||
@ -389,7 +398,16 @@ bool OpenAL_Sound::isPlaying()
|
|||||||
|
|
||||||
void OpenAL_Sound::update()
|
void OpenAL_Sound::update()
|
||||||
{
|
{
|
||||||
alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume);
|
ALfloat gain = mVolume*mBaseVolume;
|
||||||
|
ALfloat pitch = mPitch;
|
||||||
|
if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
|
||||||
|
{
|
||||||
|
gain *= 0.9f;
|
||||||
|
pitch *= 0.7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
alSourcef(mSource, AL_GAIN, gain);
|
||||||
|
alSourcef(mSource, AL_PITCH, pitch);
|
||||||
alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
|
alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
|
||||||
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
|
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
|
||||||
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||||
@ -398,10 +416,18 @@ void OpenAL_Sound::update()
|
|||||||
|
|
||||||
void OpenAL_Sound3D::update()
|
void OpenAL_Sound3D::update()
|
||||||
{
|
{
|
||||||
|
ALfloat gain = mVolume*mBaseVolume;
|
||||||
|
ALfloat pitch = mPitch;
|
||||||
if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance)
|
if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance)
|
||||||
alSourcef(mSource, AL_GAIN, 0.0f);
|
gain = 0.0f;
|
||||||
else
|
else if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater)
|
||||||
alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume);
|
{
|
||||||
|
gain *= 0.9f;
|
||||||
|
pitch *= 0.7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
alSourcef(mSource, AL_GAIN, gain);
|
||||||
|
alSourcef(mSource, AL_PITCH, pitch);
|
||||||
alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
|
alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
|
||||||
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
|
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
|
||||||
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||||
@ -639,6 +665,11 @@ SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float
|
|||||||
alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
|
alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
|
||||||
alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
|
alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
|
||||||
|
|
||||||
|
if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater)
|
||||||
|
{
|
||||||
|
volume *= 0.9f;
|
||||||
|
pitch *= 0.7f;
|
||||||
|
}
|
||||||
alSourcef(src, AL_GAIN, volume);
|
alSourcef(src, AL_GAIN, volume);
|
||||||
alSourcef(src, AL_PITCH, pitch);
|
alSourcef(src, AL_PITCH, pitch);
|
||||||
|
|
||||||
@ -686,6 +717,11 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector
|
|||||||
alSourcef(src, AL_MAX_DISTANCE, max);
|
alSourcef(src, AL_MAX_DISTANCE, max);
|
||||||
alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f);
|
alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f);
|
||||||
|
|
||||||
|
if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater)
|
||||||
|
{
|
||||||
|
volume *= 0.9f;
|
||||||
|
pitch *= 0.7f;
|
||||||
|
}
|
||||||
alSourcef(src, AL_GAIN, (pos.squaredDistance(mPos) > max*max) ?
|
alSourcef(src, AL_GAIN, (pos.squaredDistance(mPos) > max*max) ?
|
||||||
0.0f : volume);
|
0.0f : volume);
|
||||||
alSourcef(src, AL_PITCH, pitch);
|
alSourcef(src, AL_PITCH, pitch);
|
||||||
@ -702,7 +738,7 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch)
|
SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch, int flags)
|
||||||
{
|
{
|
||||||
boost::shared_ptr<OpenAL_SoundStream> sound;
|
boost::shared_ptr<OpenAL_SoundStream> sound;
|
||||||
ALuint src;
|
ALuint src;
|
||||||
@ -714,6 +750,8 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if((flags&Play_Loop))
|
||||||
|
std::cout <<"Warning: cannot loop stream "<<fname<< std::endl;
|
||||||
DecoderPtr decoder = mManager.getDecoder();
|
DecoderPtr decoder = mManager.getDecoder();
|
||||||
decoder->open(fname);
|
decoder->open(fname);
|
||||||
sound.reset(new OpenAL_SoundStream(*this, src, decoder));
|
sound.reset(new OpenAL_SoundStream(*this, src, decoder));
|
||||||
@ -732,6 +770,11 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa
|
|||||||
alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
|
alSourcef(src, AL_MAX_DISTANCE, 1000.0f);
|
||||||
alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
|
alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f);
|
||||||
|
|
||||||
|
if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater)
|
||||||
|
{
|
||||||
|
volume *= 0.9f;
|
||||||
|
pitch *= 0.7f;
|
||||||
|
}
|
||||||
alSourcef(src, AL_GAIN, volume);
|
alSourcef(src, AL_GAIN, volume);
|
||||||
alSourcef(src, AL_PITCH, pitch);
|
alSourcef(src, AL_PITCH, pitch);
|
||||||
|
|
||||||
@ -744,9 +787,10 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir)
|
void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env)
|
||||||
{
|
{
|
||||||
mPos = pos;
|
mPos = pos;
|
||||||
|
mLastEnvironment = env;
|
||||||
|
|
||||||
if(mContext)
|
if(mContext)
|
||||||
{
|
{
|
||||||
@ -763,7 +807,7 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3
|
|||||||
|
|
||||||
OpenAL_Output::OpenAL_Output(SoundManager &mgr)
|
OpenAL_Output::OpenAL_Output(SoundManager &mgr)
|
||||||
: Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0),
|
: Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0),
|
||||||
mStreamThread(new StreamThread)
|
mLastEnvironment(Env_Normal), mStreamThread(new StreamThread)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,8 @@ namespace MWSound
|
|||||||
ALuint getBuffer(const std::string &fname);
|
ALuint getBuffer(const std::string &fname);
|
||||||
void bufferFinished(ALuint buffer);
|
void bufferFinished(ALuint buffer);
|
||||||
|
|
||||||
|
Environment mLastEnvironment;
|
||||||
|
|
||||||
virtual std::vector<std::string> enumerate();
|
virtual std::vector<std::string> enumerate();
|
||||||
virtual void init(const std::string &devname="");
|
virtual void init(const std::string &devname="");
|
||||||
virtual void deinit();
|
virtual void deinit();
|
||||||
@ -43,9 +45,9 @@ namespace MWSound
|
|||||||
virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags);
|
virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags);
|
||||||
virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
|
virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
|
||||||
float volume, float pitch, float min, float max, int flags);
|
float volume, float pitch, float min, float max, int flags);
|
||||||
virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch);
|
virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags);
|
||||||
|
|
||||||
virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir);
|
virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env);
|
||||||
|
|
||||||
OpenAL_Output& operator=(const OpenAL_Output &rhs);
|
OpenAL_Output& operator=(const OpenAL_Output &rhs);
|
||||||
OpenAL_Output(const OpenAL_Output &rhs);
|
OpenAL_Output(const OpenAL_Output &rhs);
|
||||||
|
@ -16,6 +16,7 @@ namespace MWSound
|
|||||||
Ogre::Vector3 mPos;
|
Ogre::Vector3 mPos;
|
||||||
float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */
|
float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */
|
||||||
float mBaseVolume;
|
float mBaseVolume;
|
||||||
|
float mPitch;
|
||||||
float mMinDistance;
|
float mMinDistance;
|
||||||
float mMaxDistance;
|
float mMaxDistance;
|
||||||
int mFlags;
|
int mFlags;
|
||||||
@ -29,6 +30,7 @@ namespace MWSound
|
|||||||
Sound() : mPos(0.0f, 0.0f, 0.0f)
|
Sound() : mPos(0.0f, 0.0f, 0.0f)
|
||||||
, mVolume(1.0f)
|
, mVolume(1.0f)
|
||||||
, mBaseVolume(1.0f)
|
, mBaseVolume(1.0f)
|
||||||
|
, mPitch(1.0f)
|
||||||
, mMinDistance(20.0f) /* 1 * min_range_scale */
|
, mMinDistance(20.0f) /* 1 * min_range_scale */
|
||||||
, mMaxDistance(12750.0f) /* 255 * max_range_scale */
|
, mMaxDistance(12750.0f) /* 255 * max_range_scale */
|
||||||
, mFlags(Play_Normal)
|
, mFlags(Play_Normal)
|
||||||
|
@ -27,9 +27,9 @@ namespace MWSound
|
|||||||
virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0;
|
virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0;
|
||||||
virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
|
virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
|
||||||
float volume, float pitch, float min, float max, int flags) = 0;
|
float volume, float pitch, float min, float max, int flags) = 0;
|
||||||
virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch) = 0;
|
virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags) = 0;
|
||||||
|
|
||||||
virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir) = 0;
|
virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0;
|
||||||
|
|
||||||
Sound_Output& operator=(const Sound_Output &rhs);
|
Sound_Output& operator=(const Sound_Output &rhs);
|
||||||
Sound_Output(const Sound_Output &rhs);
|
Sound_Output(const Sound_Output &rhs);
|
||||||
|
@ -88,10 +88,7 @@ namespace MWSound
|
|||||||
if(snd == NULL)
|
if(snd == NULL)
|
||||||
throw std::runtime_error(std::string("Failed to lookup sound ")+soundId);
|
throw std::runtime_error(std::string("Failed to lookup sound ")+soundId);
|
||||||
|
|
||||||
if(snd->data.volume == 0)
|
volume *= pow(10.0, (snd->data.volume/255.0*3348.0 - 3348.0) / 2000.0);
|
||||||
volume = 0.0f;
|
|
||||||
else
|
|
||||||
volume *= pow(10.0, (snd->data.volume/255.0f*3348.0 - 3348.0) / 2000.0);
|
|
||||||
|
|
||||||
if(snd->data.minRange == 0 && snd->data.maxRange == 0)
|
if(snd->data.minRange == 0 && snd->data.maxRange == 0)
|
||||||
{
|
{
|
||||||
@ -135,10 +132,10 @@ namespace MWSound
|
|||||||
std::cout <<"Playing "<<filename<< std::endl;
|
std::cout <<"Playing "<<filename<< std::endl;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(mMusic)
|
stopMusic();
|
||||||
mMusic->stop();
|
mMusic = mOutput->streamSound(filename, 0.4f, 1.0f, Play_NoEnv);
|
||||||
mMusic = mOutput->streamSound(filename, 0.4f, 1.0f);
|
|
||||||
mMusic->mBaseVolume = 0.4f;
|
mMusic->mBaseVolume = 0.4f;
|
||||||
|
mMusic->mFlags = Play_NoEnv;
|
||||||
}
|
}
|
||||||
catch(std::exception &e)
|
catch(std::exception &e)
|
||||||
{
|
{
|
||||||
@ -215,6 +212,7 @@ namespace MWSound
|
|||||||
sound = mOutput->playSound(file, volume*basevol, pitch, mode);
|
sound = mOutput->playSound(file, volume*basevol, pitch, mode);
|
||||||
sound->mVolume = volume;
|
sound->mVolume = volume;
|
||||||
sound->mBaseVolume = basevol;
|
sound->mBaseVolume = basevol;
|
||||||
|
sound->mPitch = pitch;
|
||||||
sound->mMinDistance = min;
|
sound->mMinDistance = min;
|
||||||
sound->mMaxDistance = max;
|
sound->mMaxDistance = max;
|
||||||
sound->mFlags = mode;
|
sound->mFlags = mode;
|
||||||
@ -245,6 +243,7 @@ namespace MWSound
|
|||||||
sound->mPos = objpos;
|
sound->mPos = objpos;
|
||||||
sound->mVolume = volume;
|
sound->mVolume = volume;
|
||||||
sound->mBaseVolume = basevol;
|
sound->mBaseVolume = basevol;
|
||||||
|
sound->mPitch = pitch;
|
||||||
sound->mMinDistance = min;
|
sound->mMinDistance = min;
|
||||||
sound->mMaxDistance = max;
|
sound->mMaxDistance = max;
|
||||||
sound->mFlags = mode;
|
sound->mFlags = mode;
|
||||||
@ -408,19 +407,25 @@ namespace MWSound
|
|||||||
if(!isMusicPlaying())
|
if(!isMusicPlaying())
|
||||||
startRandomTitle();
|
startRandomTitle();
|
||||||
|
|
||||||
|
MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell();
|
||||||
Ogre::Camera *cam = mEnvironment.mWorld->getPlayer().getRenderer()->getCamera();
|
Ogre::Camera *cam = mEnvironment.mWorld->getPlayer().getRenderer()->getCamera();
|
||||||
Ogre::Vector3 nPos, nDir, nUp;
|
Ogre::Vector3 nPos, nDir, nUp;
|
||||||
nPos = cam->getRealPosition();
|
nPos = cam->getRealPosition();
|
||||||
nDir = cam->getRealDirection();
|
nDir = cam->getRealDirection();
|
||||||
nUp = cam->getRealUp();
|
nUp = cam->getRealUp();
|
||||||
|
|
||||||
|
Environment env = Env_Normal;
|
||||||
|
if(nPos.y < current->cell->water)
|
||||||
|
env = Env_Underwater;
|
||||||
|
|
||||||
// The output handler is expecting vectors oriented like the game
|
// The output handler is expecting vectors oriented like the game
|
||||||
// (that is, -Z goes down, +Y goes forward), but that's not what we
|
// (that is, -Z goes down, +Y goes forward), but that's not what we
|
||||||
// get from Ogre's camera, so we have to convert.
|
// get from Ogre's camera, so we have to convert.
|
||||||
const Ogre::Vector3 pos(nPos[0], -nPos[2], nPos[1]);
|
const Ogre::Vector3 pos(nPos[0], -nPos[2], nPos[1]);
|
||||||
const Ogre::Vector3 at(nDir[0], -nDir[2], nDir[1]);
|
const Ogre::Vector3 at(nDir[0], -nDir[2], nDir[1]);
|
||||||
const Ogre::Vector3 up(nUp[0], -nUp[2], nUp[1]);
|
const Ogre::Vector3 up(nUp[0], -nUp[2], nUp[1]);
|
||||||
mOutput->updateListener(pos, at, up);
|
|
||||||
|
mOutput->updateListener(pos, at, up, env);
|
||||||
|
|
||||||
// Check if any sounds are finished playing, and trash them
|
// Check if any sounds are finished playing, and trash them
|
||||||
SoundMap::iterator snditer = mActiveSounds.begin();
|
SoundMap::iterator snditer = mActiveSounds.begin();
|
||||||
|
@ -43,6 +43,11 @@ namespace MWSound
|
|||||||
static inline int operator&(const PlayMode &a, const PlayMode &b)
|
static inline int operator&(const PlayMode &a, const PlayMode &b)
|
||||||
{ return (int)a & (int)b; }
|
{ return (int)a & (int)b; }
|
||||||
|
|
||||||
|
enum Environment {
|
||||||
|
Env_Normal,
|
||||||
|
Env_Underwater,
|
||||||
|
};
|
||||||
|
|
||||||
class SoundManager
|
class SoundManager
|
||||||
{
|
{
|
||||||
Ogre::ResourceGroupManager& mResourceMgr;
|
Ogre::ResourceGroupManager& mResourceMgr;
|
||||||
|
@ -51,6 +51,28 @@ namespace MWWorld
|
|||||||
return mEngine->rayTest(from,to);
|
return mEngine->rayTest(from,to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector < std::pair <float, std::string> > PhysicsSystem::getFacedObjects ()
|
||||||
|
{
|
||||||
|
//get a ray pointing to the center of the viewport
|
||||||
|
Ray centerRay = mRender.getCamera()->getCameraToViewportRay(
|
||||||
|
mRender.getViewport()->getWidth()/2,
|
||||||
|
mRender.getViewport()->getHeight()/2);
|
||||||
|
btVector3 from(centerRay.getOrigin().x,-centerRay.getOrigin().z,centerRay.getOrigin().y);
|
||||||
|
btVector3 to(centerRay.getPoint(500).x,-centerRay.getPoint(500).z,centerRay.getPoint(500).y);
|
||||||
|
|
||||||
|
return mEngine->rayTest2(from,to);
|
||||||
|
}
|
||||||
|
|
||||||
|
btVector3 PhysicsSystem::getRayPoint(float extent)
|
||||||
|
{
|
||||||
|
//get a ray pointing to the center of the viewport
|
||||||
|
Ray centerRay = mRender.getCamera()->getCameraToViewportRay(
|
||||||
|
mRender.getViewport()->getWidth()/2,
|
||||||
|
mRender.getViewport()->getHeight()/2);
|
||||||
|
btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to)
|
bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to)
|
||||||
{
|
{
|
||||||
btVector3 _from, _to;
|
btVector3 _from, _to;
|
||||||
|
@ -36,6 +36,10 @@ namespace MWWorld
|
|||||||
|
|
||||||
std::pair<std::string, float> getFacedHandle (MWWorld::World& world);
|
std::pair<std::string, float> getFacedHandle (MWWorld::World& world);
|
||||||
|
|
||||||
|
btVector3 getRayPoint(float extent);
|
||||||
|
|
||||||
|
std::vector < std::pair <float, std::string> > getFacedObjects ();
|
||||||
|
|
||||||
// cast ray, return true if it hit something
|
// cast ray, return true if it hit something
|
||||||
bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to);
|
bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to);
|
||||||
|
|
||||||
|
@ -157,7 +157,8 @@ namespace MWWorld
|
|||||||
const std::string& master, const boost::filesystem::path& resDir,
|
const std::string& master, const boost::filesystem::path& resDir,
|
||||||
bool newGame, Environment& environment, const std::string& encoding)
|
bool newGame, Environment& environment, const std::string& encoding)
|
||||||
: mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0),
|
: mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0),
|
||||||
mSky (true), mEnvironment (environment), mNextDynamicRecord (0), mCells (mStore, mEsm, *this)
|
mSky (true), mEnvironment (environment), mNextDynamicRecord (0), mCells (mStore, mEsm, *this),
|
||||||
|
mNumFacing(0)
|
||||||
{
|
{
|
||||||
mPhysics = new PhysicsSystem(renderer);
|
mPhysics = new PhysicsSystem(renderer);
|
||||||
mPhysEngine = mPhysics->getEngine();
|
mPhysEngine = mPhysics->getEngine();
|
||||||
@ -497,6 +498,8 @@ namespace MWWorld
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string World::getFacedHandle()
|
std::string World::getFacedHandle()
|
||||||
|
{
|
||||||
|
if (!mRendering->occlusionQuerySupported())
|
||||||
{
|
{
|
||||||
std::pair<std::string, float> result = mPhysics->getFacedHandle (*this);
|
std::pair<std::string, float> result = mPhysics->getFacedHandle (*this);
|
||||||
|
|
||||||
@ -506,6 +509,12 @@ namespace MWWorld
|
|||||||
|
|
||||||
return result.first;
|
return result.first;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// updated every few frames in update()
|
||||||
|
return mFacedHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void World::deleteObject (Ptr ptr)
|
void World::deleteObject (Ptr ptr)
|
||||||
{
|
{
|
||||||
@ -706,6 +715,8 @@ namespace MWWorld
|
|||||||
|
|
||||||
mWeatherManager->update (duration);
|
mWeatherManager->update (duration);
|
||||||
|
|
||||||
|
if (!mRendering->occlusionQuerySupported())
|
||||||
|
{
|
||||||
// cast a ray from player to sun to detect if the sun is visible
|
// cast a ray from player to sun to detect if the sun is visible
|
||||||
// this is temporary until we find a better place to put this code
|
// this is temporary until we find a better place to put this code
|
||||||
// currently its here because we need to access the physics system
|
// currently its here because we need to access the physics system
|
||||||
@ -715,6 +726,73 @@ namespace MWWorld
|
|||||||
mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun));
|
mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update faced handle (object the player is looking at)
|
||||||
|
// this uses a mixture of raycasts and occlusion queries.
|
||||||
|
else // if (mRendering->occlusionQuerySupported())
|
||||||
|
{
|
||||||
|
MWRender::OcclusionQuery* query = mRendering->getOcclusionQuery();
|
||||||
|
if (!query->occlusionTestPending())
|
||||||
|
{
|
||||||
|
// get result of last query
|
||||||
|
if (mNumFacing == 0) mFacedHandle = "";
|
||||||
|
else if (mNumFacing == 1)
|
||||||
|
{
|
||||||
|
bool result = query->getTestResult();
|
||||||
|
mFacedHandle = result ? mFaced1Name : "";
|
||||||
|
}
|
||||||
|
else if (mNumFacing == 2)
|
||||||
|
{
|
||||||
|
bool result = query->getTestResult();
|
||||||
|
mFacedHandle = result ? mFaced2Name : mFaced1Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send new query
|
||||||
|
// figure out which object we want to test against
|
||||||
|
std::vector < std::pair < float, std::string > > results = mPhysics->getFacedObjects();
|
||||||
|
|
||||||
|
// ignore the player
|
||||||
|
for (std::vector < std::pair < float, std::string > >::iterator it = results.begin();
|
||||||
|
it != results.end(); ++it)
|
||||||
|
{
|
||||||
|
if ( (*it).second == mPlayer->getPlayer().getRefData().getHandle() )
|
||||||
|
{
|
||||||
|
results.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.size() == 0)
|
||||||
|
{
|
||||||
|
mNumFacing = 0;
|
||||||
|
}
|
||||||
|
else if (results.size() == 1)
|
||||||
|
{
|
||||||
|
mFaced1 = getPtrViaHandle(results.front().second);
|
||||||
|
mFaced1Name = results.front().second;
|
||||||
|
mNumFacing = 1;
|
||||||
|
|
||||||
|
btVector3 p = mPhysics->getRayPoint(results.front().first);
|
||||||
|
Ogre::Vector3 pos(p.x(), p.z(), -p.y());
|
||||||
|
Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode();
|
||||||
|
query->occlusionTest(pos, node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFaced1Name = results.front().second;
|
||||||
|
mFaced2Name = results[1].second;
|
||||||
|
mFaced1 = getPtrViaHandle(results.front().second);
|
||||||
|
mFaced2 = getPtrViaHandle(results[1].second);
|
||||||
|
mNumFacing = 2;
|
||||||
|
|
||||||
|
btVector3 p = mPhysics->getRayPoint(results[1].first);
|
||||||
|
Ogre::Vector3 pos(p.x(), p.z(), -p.y());
|
||||||
|
Ogre::SceneNode* node = mFaced2.getRefData().getBaseNode();
|
||||||
|
query->occlusionTest(pos, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool World::isCellExterior() const
|
bool World::isCellExterior() const
|
||||||
{
|
{
|
||||||
Ptr::CellStore *currentCell = mWorldScene->getCurrentCell();
|
Ptr::CellStore *currentCell = mWorldScene->getCurrentCell();
|
||||||
|
@ -93,6 +93,12 @@ namespace MWWorld
|
|||||||
|
|
||||||
Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cellStore);
|
Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cellStore);
|
||||||
|
|
||||||
|
std::string mFacedHandle;
|
||||||
|
Ptr mFaced1;
|
||||||
|
Ptr mFaced2;
|
||||||
|
std::string mFaced1Name;
|
||||||
|
std::string mFaced2Name;
|
||||||
|
int mNumFacing;
|
||||||
|
|
||||||
int getDaysPerMonth (int month) const;
|
int getDaysPerMonth (int month) const;
|
||||||
|
|
||||||
|
@ -426,4 +426,35 @@ namespace Physic
|
|||||||
|
|
||||||
return std::pair<std::string,float>(name,d);
|
return std::pair<std::string,float>(name,d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector< std::pair<float, std::string> > PhysicEngine::rayTest2(btVector3& from, btVector3& to)
|
||||||
|
{
|
||||||
|
MyRayResultCallback resultCallback1;
|
||||||
|
resultCallback1.m_collisionFilterMask = COL_WORLD;
|
||||||
|
dynamicsWorld->rayTest(from, to, resultCallback1);
|
||||||
|
std::vector< std::pair<float, btCollisionObject*> > results = resultCallback1.results;
|
||||||
|
|
||||||
|
MyRayResultCallback resultCallback2;
|
||||||
|
resultCallback2.m_collisionFilterMask = COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL;
|
||||||
|
dynamicsWorld->rayTest(from, to, resultCallback2);
|
||||||
|
std::vector< std::pair<float, btCollisionObject*> > actorResults = resultCallback2.results;
|
||||||
|
|
||||||
|
std::vector< std::pair<float, std::string> > results2;
|
||||||
|
|
||||||
|
for (std::vector< std::pair<float, btCollisionObject*> >::iterator it=results.begin();
|
||||||
|
it != results.end(); ++it)
|
||||||
|
{
|
||||||
|
results2.push_back( std::make_pair( (*it).first, static_cast<RigidBody&>(*(*it).second).mName ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector< std::pair<float, btCollisionObject*> >::iterator it=actorResults.begin();
|
||||||
|
it != actorResults.end(); ++it)
|
||||||
|
{
|
||||||
|
results2.push_back( std::make_pair( (*it).first, static_cast<PairCachingGhostObject&>(*(*it).second).mName ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(results2.begin(), results2.end(), MyRayResultCallback::cmp);
|
||||||
|
|
||||||
|
return results2;
|
||||||
|
}
|
||||||
}};
|
}};
|
||||||
|
@ -206,6 +206,11 @@ namespace Physic
|
|||||||
*/
|
*/
|
||||||
std::pair<std::string,float> rayTest(btVector3& from,btVector3& to);
|
std::pair<std::string,float> rayTest(btVector3& from,btVector3& to);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all objects hit by a ray.
|
||||||
|
*/
|
||||||
|
std::vector< std::pair<float, std::string> > rayTest2(btVector3& from, btVector3& to);
|
||||||
|
|
||||||
//event list of non player object
|
//event list of non player object
|
||||||
std::list<PhysicEvent> NPEventList;
|
std::list<PhysicEvent> NPEventList;
|
||||||
|
|
||||||
@ -235,6 +240,25 @@ namespace Physic
|
|||||||
bool mDebugActive;
|
bool mDebugActive;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct MyRayResultCallback : public btCollisionWorld::RayResultCallback
|
||||||
|
{
|
||||||
|
virtual btScalar addSingleResult( btCollisionWorld::LocalRayResult& rayResult, bool bNormalInWorldSpace)
|
||||||
|
{
|
||||||
|
results.push_back( std::make_pair(rayResult.m_hitFraction, rayResult.m_collisionObject) );
|
||||||
|
return rayResult.m_hitFraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cmp( const std::pair<float, std::string>& i, const std::pair<float, std::string>& j )
|
||||||
|
{
|
||||||
|
if( i.first > j.first ) return false;
|
||||||
|
if( j.first > i.first ) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector < std::pair<float, btCollisionObject*> > results;
|
||||||
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user