1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 09:35:28 +00:00

Merge branch 'master' into gamesettings

This commit is contained in:
scrawl 2012-03-31 21:37:15 +02:00
commit 55c984c179
44 changed files with 931 additions and 412 deletions

View File

@ -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

View File

@ -204,13 +204,18 @@ OMW::Engine::~Engine()
void OMW::Engine::loadBSA() void OMW::Engine::loadBSA()
{ {
const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa"); const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa");
std::string dataDirectory;
for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter) for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter)
{ {
std::cout << "Adding " << iter->second.string() << std::endl; std::cout << "Adding " << iter->second.string() << std::endl;
Bsa::addBSA(iter->second.string()); Bsa::addBSA(iter->second.string());
}
dataDirectory = iter->second.parent_path().string(); const Files::PathContainer& dataDirs = mFileCollections.getPaths();
std::string dataDirectory;
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
dataDirectory = iter->string();
std::cout << "Data dir " << dataDirectory << std::endl; std::cout << "Data dir " << dataDirectory << std::endl;
Bsa::addDir(dataDirectory, mFSStrict); Bsa::addDir(dataDirectory, mFSStrict);
} }

View File

@ -56,7 +56,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Apparatus::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -60,7 +60,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Armor::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -58,7 +58,7 @@ namespace MWClass
{ {
// TODO implement reading // TODO implement reading
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -57,7 +57,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Clothing::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -85,7 +85,7 @@ namespace MWClass
{ {
// TODO check for key // TODO check for key
std::cout << "Locked container" << std::endl; std::cout << "Locked container" << std::endl;
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false); environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction); return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
} }
else else
@ -100,7 +100,7 @@ namespace MWClass
{ {
// Trap activation goes here // Trap activation goes here
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl; std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0, false); environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0);
ptr.getCellRef().trap = ""; ptr.getCellRef().trap = "";
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction); return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
} }

View File

@ -73,7 +73,7 @@ namespace MWClass
// TODO check for key // TODO check for key
// TODO report failure to player (message, sound?). Look up behaviour of original MW. // TODO report failure to player (message, sound?). Look up behaviour of original MW.
std::cout << "Locked!" << std::endl; std::cout << "Locked!" << std::endl;
environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0, false); environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction); return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
} }
@ -81,7 +81,7 @@ namespace MWClass
{ {
// Trap activation // Trap activation
std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl; std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl;
environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0, false); environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0);
ptr.getCellRef().trap = ""; ptr.getCellRef().trap = "";
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction); return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
} }
@ -110,7 +110,7 @@ namespace MWClass
// TODO return action for rotating the door // TODO return action for rotating the door
// This is a little pointless, but helps with testing // This is a little pointless, but helps with testing
environment.mSoundManager->playSound3D (ptr, openSound, 1.0, 1.0, false); environment.mSoundManager->playSound3D (ptr, openSound, 1.0, 1.0);
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction); return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
} }
} }

View File

@ -54,7 +54,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Ingredient::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -59,7 +59,7 @@ namespace MWClass
if (!ref->base->sound.empty()) if (!ref->base->sound.empty())
{ {
environment.mSoundManager->playSound3D (ptr, ref->base->sound, 1.0, 1.0, true); environment.mSoundManager->playSound3D (ptr, ref->base->sound, 1.0, 1.0, MWSound::Play_Loop);
} }
} }
@ -83,7 +83,7 @@ namespace MWClass
if (!(ref->base->data.flags & ESM::Light::Carry)) if (!(ref->base->data.flags & ESM::Light::Carry))
return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction); return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction);
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -58,7 +58,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Lockpick::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -56,7 +56,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Miscellaneous::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -56,7 +56,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Potion::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -57,7 +57,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Probe::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -56,7 +56,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Repair::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -57,7 +57,7 @@ namespace MWClass
boost::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> Weapon::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
{ {
environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, false, true); environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack);
return boost::shared_ptr<MWWorld::Action> ( return boost::shared_ptr<MWWorld::Action> (
new MWWorld::ActionTake (ptr)); new MWWorld::ActionTake (ptr));

View File

@ -180,71 +180,58 @@ void WindowManager::updateVisible()
// Mouse is visible whenever we're not in game mode // Mouse is visible whenever we're not in game mode
MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
// If in game mode, don't show anything. switch(mode) {
if(mode == GM_Game) //Use a switch/case structure case GM_Game:
{ // If in game mode, don't show anything.
return; break;
} case GM_MainMenu:
menu->setVisible(true);
break;
case GM_Console:
console->enable();
break;
case GM_Name:
case GM_Race:
case GM_Class:
case GM_ClassPick:
case GM_ClassCreate:
case GM_Birth:
case GM_ClassGenerate:
case GM_Review:
mCharGen->spawnDialog(mode);
break;
case GM_Inventory:
{
// First, compute the effective set of windows to show.
// This is controlled both by what windows the
// user has opened/closed (the 'shown' variable) and by what
// windows we are allowed to show (the 'allowed' var.)
int eff = shown & allowed;
if(mode == GM_MainMenu) // Show the windows we want
{ map -> setVisible( (eff & GW_Map) != 0 );
// Enable the main menu stats -> setVisible( (eff & GW_Stats) != 0 );
menu->setVisible(true); break;
return;
}
if(mode == GM_Console)
{
console->enable();
return;
}
//There must be a more elegant solution
if (mode == GM_Name || mode == GM_Race || mode == GM_Class || mode == GM_ClassPick || mode == GM_ClassCreate || mode == GM_Birth || mode == GM_ClassGenerate || mode == GM_Review)
{
mCharGen->spawnDialog(mode);
return;
}
if(mode == GM_Inventory)
{
// Ah, inventory mode. First, compute the effective set of
// windows to show. This is controlled both by what windows the
// user has opened/closed (the 'shown' variable) and by what
// windows we are allowed to show (the 'allowed' var.)
int eff = shown & allowed;
// Show the windows we want
map -> setVisible( (eff & GW_Map) != 0 );
stats -> setVisible( (eff & GW_Stats) != 0 );
return;
}
if (mode == GM_Dialogue)
{
dialogueWindow->open();
return;
}
if(mode == GM_InterMessageBox)
{
if(!mMessageBoxManager->isInteractiveMessageBox()) {
setGuiMode(GM_Game);
} }
return; case GM_Dialogue:
dialogueWindow->open();
break;
case GM_InterMessageBox:
if(!mMessageBoxManager->isInteractiveMessageBox()) {
setGuiMode(GM_Game);
}
break;
case GM_Journal:
mJournal->setVisible(true);
mJournal->open();
break;
default:
// Unsupported mode, switch back to game
// Note: The call will eventually end up this method again but
// will stop at the check if mode is GM_Game.
setGuiMode(GM_Game);
break;
} }
if(mode == GM_Journal)
{
mJournal->setVisible(true);
mJournal->open();
return;
}
// Unsupported mode, switch back to game
// Note: The call will eventually end up this method again but
// will stop at the check if(mode == GM_Game) above.
setGuiMode(GM_Game);
} }
void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int>& value) void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int>& value)

View File

@ -126,6 +126,11 @@ namespace MWRender{
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){ void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){
shapeNumber = 0; shapeNumber = 0;
if (allshapes == NULL || creaturemodel == NULL || skel == NULL)
{
return;
}
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter; std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++) for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)

View File

@ -27,11 +27,7 @@ bool Debugging::toggleRenderMode (int mode){
switch (mode) switch (mode)
{ {
case MWWorld::World::Render_CollisionDebug: case MWWorld::World::Render_CollisionDebug:
return eng->toggleDebugRendering();
// TODO use a proper function instead of accessing the member variable
// directly.
eng->setDebugRenderingMode (!eng->isDebugCreated);
return eng->isDebugCreated;
} }
return false; return false;

View 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;
}

View 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

View File

@ -46,9 +46,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
mMwRoot->pitch(Degree(-90)); mMwRoot->pitch(Degree(-90));
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));
@ -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()
@ -166,9 +164,13 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve
void RenderingManager::update (float duration){ 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() );

View File

@ -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;

View File

@ -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(mGlareFade>0 && mSunEnabled); mSunGlare->setVisible(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();
}

View File

@ -109,58 +109,60 @@ namespace MWRender
public: public:
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env); SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env);
~SkyManager(); ~SkyManager();
void update(float duration); void update(float duration);
void enable(); void enable();
void disable(); void disable();
void setHour (double hour); void setHour (double hour);
///< will be called even when sky is disabled. ///< will be called even when sky is disabled.
void setDate (int day, int month); void setDate (int day, int month);
///< will be called even when sky is disabled. ///< will be called even when sky is disabled.
int getMasserPhase() const; int getMasserPhase() const;
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half, ///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
/// 3 waxing or waning gibbous, 4 full moon /// 3 waxing or waning gibbous, 4 full moon
int getSecundaPhase() const; int getSecundaPhase() const;
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half, ///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
/// 3 waxing or waning gibbous, 4 full moon /// 3 waxing or waning gibbous, 4 full moon
void setMoonColour (bool red); void setMoonColour (bool red);
///< change Secunda colour to red ///< change Secunda colour to red
void setCloudsOpacity(float opacity); void setCloudsOpacity(float opacity);
///< change opacity of the clouds ///< change opacity of the clouds
void setWeather(const MWWorld::WeatherResult& weather); void setWeather(const MWWorld::WeatherResult& weather);
Ogre::SceneNode* getSunNode();
void sunEnable(); void sunEnable();
void sunDisable(); void sunDisable();
void setSunDirection(const Ogre::Vector3& direction); void setSunDirection(const Ogre::Vector3& direction);
void setMasserDirection(const Ogre::Vector3& direction); void setMasserDirection(const Ogre::Vector3& direction);
void setSecundaDirection(const Ogre::Vector3& direction); void setSecundaDirection(const Ogre::Vector3& direction);
void setMasserFade(const float fade); void setMasserFade(const float fade);
void setSecundaFade(const float fade); void setSecundaFade(const float fade);
void masserEnable(); void masserEnable();
void masserDisable(); void masserDisable();
void secundaEnable(); void secundaEnable();
void secundaDisable(); void secundaDisable();
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;

View File

@ -50,7 +50,7 @@ namespace Ogre
terrain. terrain.
@note Requires the Cg plugin to render correctly @note Requires the Cg plugin to render correctly
*/ */
class _OgreTerrainExport TerrainMaterialGeneratorB : public TerrainMaterialGenerator class TerrainMaterialGeneratorB : public TerrainMaterialGenerator
{ {
public: public:
TerrainMaterialGeneratorB(); TerrainMaterialGeneratorB();
@ -58,7 +58,7 @@ namespace Ogre
/** Shader model 2 profile target. /** Shader model 2 profile target.
*/ */
class _OgreTerrainExport SM2Profile : public TerrainMaterialGenerator::Profile class SM2Profile : public TerrainMaterialGenerator::Profile
{ {
public: public:
SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc); SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc);
@ -161,7 +161,7 @@ namespace Ogre
void addTechnique(const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt); void addTechnique(const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt);
/// Interface definition for helper class to generate shaders /// Interface definition for helper class to generate shaders
class _OgreTerrainExport ShaderHelper : public TerrainAlloc class ShaderHelper : public TerrainAlloc
{ {
public: public:
ShaderHelper() {} ShaderHelper() {}
@ -194,7 +194,7 @@ namespace Ogre
}; };
/// Utility class to help with generating shaders for Cg / HLSL. /// Utility class to help with generating shaders for Cg / HLSL.
class _OgreTerrainExport ShaderHelperCg : public ShaderHelper class ShaderHelperCg : public ShaderHelper
{ {
protected: protected:
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
@ -212,7 +212,7 @@ namespace Ogre
void generateFpDynamicShadows(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 class ShaderHelperHLSL : public ShaderHelperCg
{ {
protected: protected:
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
@ -220,7 +220,7 @@ namespace Ogre
}; };
/// Utility class to help with generating shaders for GLSL. /// Utility class to help with generating shaders for GLSL.
class _OgreTerrainExport ShaderHelperGLSL : public ShaderHelper class ShaderHelperGLSL : public ShaderHelper
{ {
protected: protected:
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);

View File

@ -130,7 +130,7 @@ namespace MWScript
std::string sound = runtime.getStringLiteral (runtime[0].mInteger); std::string sound = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
context.getSoundManager().playSound3D (ptr, sound, 1.0, 1.0, mLoop); context.getSoundManager().playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWSound::Play_Loop : 0);
} }
}; };
@ -159,7 +159,7 @@ namespace MWScript
Interpreter::Type_Float pitch = runtime[0].mFloat; Interpreter::Type_Float pitch = runtime[0].mFloat;
runtime.pop(); runtime.pop();
context.getSoundManager().playSound3D (ptr, sound, volume, pitch, mLoop); context.getSoundManager().playSound3D (ptr, sound, volume, pitch, mLoop ? MWSound::Play_Loop : 0);
} }
}; };

View File

@ -25,14 +25,20 @@ static void throwALCerror(ALCdevice *device)
{ {
ALCenum err = alcGetError(device); ALCenum err = alcGetError(device);
if(err != ALC_NO_ERROR) if(err != ALC_NO_ERROR)
fail(alcGetString(device, err)); {
const ALCchar *errstring = alcGetString(device, err);
fail(errstring ? errstring : "");
}
} }
static void throwALerror() static void throwALerror()
{ {
ALenum err = alGetError(); ALenum err = alGetError();
if(err != AL_NO_ERROR) if(err != AL_NO_ERROR)
fail(alGetString(err)); {
const ALchar *errstring = alGetString(err);
fail(errstring ? errstring : "");
}
} }
@ -89,8 +95,7 @@ public:
virtual void stop(); virtual void stop();
virtual bool isPlaying(); virtual bool isPlaying();
virtual void setVolume(float volume); virtual void update();
virtual void update(const float *pos);
void play(); void play();
bool process(); bool process();
@ -187,7 +192,6 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode
} }
catch(std::exception &e) catch(std::exception &e)
{ {
mOutput.mFreeSources.push_back(mSource);
alDeleteBuffers(sNumBuffers, mBuffers); alDeleteBuffers(sNumBuffers, mBuffers);
alGetError(); alGetError();
throw; throw;
@ -255,16 +259,10 @@ bool OpenAL_SoundStream::isPlaying()
return !mIsFinished; return !mIsFinished;
} }
void OpenAL_SoundStream::setVolume(float volume) void OpenAL_SoundStream::update()
{ {
alSourcef(mSource, AL_GAIN, volume*mBaseVolume); alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume);
throwALerror(); alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
mVolume = volume;
}
void OpenAL_SoundStream::update(const float *pos)
{
alSource3f(mSource, AL_POSITION, pos[0], pos[2], -pos[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);
throwALerror(); throwALerror();
@ -321,15 +319,17 @@ bool OpenAL_SoundStream::process()
} }
// //
// A regular OpenAL sound // A regular 2D OpenAL sound
// //
class OpenAL_Sound : public Sound class OpenAL_Sound : public Sound
{ {
protected:
OpenAL_Output &mOutput; OpenAL_Output &mOutput;
ALuint mSource; ALuint mSource;
ALuint mBuffer; ALuint mBuffer;
private:
OpenAL_Sound(const OpenAL_Sound &rhs); OpenAL_Sound(const OpenAL_Sound &rhs);
OpenAL_Sound& operator=(const OpenAL_Sound &rhs); OpenAL_Sound& operator=(const OpenAL_Sound &rhs);
@ -339,8 +339,23 @@ public:
virtual void stop(); virtual void stop();
virtual bool isPlaying(); virtual bool isPlaying();
virtual void setVolume(float volume); virtual void update();
virtual void update(const float *pos); };
//
// A regular 3D OpenAL sound
//
class OpenAL_Sound3D : public OpenAL_Sound
{
OpenAL_Sound3D(const OpenAL_Sound &rhs);
OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs);
public:
OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf)
: OpenAL_Sound(output, src, buf)
{ }
virtual void update();
}; };
OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf) OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf)
@ -372,16 +387,22 @@ bool OpenAL_Sound::isPlaying()
return state==AL_PLAYING; return state==AL_PLAYING;
} }
void OpenAL_Sound::setVolume(float volume) void OpenAL_Sound::update()
{ {
alSourcef(mSource, AL_GAIN, volume*mBaseVolume); alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume);
alSource3f(mSource, AL_POSITION, mPos[0], mPos[2], -mPos[1]);
alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
throwALerror(); throwALerror();
mVolume = volume;
} }
void OpenAL_Sound::update(const float *pos) void OpenAL_Sound3D::update()
{ {
alSource3f(mSource, AL_POSITION, pos[0], pos[2], -pos[1]); if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance)
alSourcef(mSource, AL_GAIN, 0.0f);
else
alSourcef(mSource, AL_GAIN, mVolume*mBaseVolume);
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);
throwALerror(); throwALerror();
@ -410,8 +431,7 @@ std::vector<std::string> OpenAL_Output::enumerate()
void OpenAL_Output::init(const std::string &devname) void OpenAL_Output::init(const std::string &devname)
{ {
if(mDevice || mContext) deinit();
fail("Device already open");
mDevice = alcOpenDevice(devname.c_str()); mDevice = alcOpenDevice(devname.c_str());
if(!mDevice) if(!mDevice)
@ -428,7 +448,12 @@ void OpenAL_Output::init(const std::string &devname)
mContext = alcCreateContext(mDevice, NULL); mContext = alcCreateContext(mDevice, NULL);
if(!mContext || alcMakeContextCurrent(mContext) == ALC_FALSE) if(!mContext || alcMakeContextCurrent(mContext) == ALC_FALSE)
{
if(mContext)
alcDestroyContext(mContext);
mContext = 0;
fail(std::string("Failed to setup context: ")+alcGetString(mDevice, alcGetError(mDevice))); fail(std::string("Failed to setup context: ")+alcGetString(mDevice, alcGetError(mDevice)));
}
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
throwALerror(); throwALerror();
@ -442,33 +467,13 @@ void OpenAL_Output::init(const std::string &devname)
{ {
ALCuint maxtotal = std::min<ALCuint>(maxmono+maxstereo, 256); ALCuint maxtotal = std::min<ALCuint>(maxmono+maxstereo, 256);
if (maxtotal == 0) // workaround for broken implementations if (maxtotal == 0) // workaround for broken implementations
{
maxtotal = 256; maxtotal = 256;
bool stop = false; for(size_t i = 0;i < maxtotal;i++)
for(size_t i = 0;i < maxtotal && !stop;i++) // generate source until error returned
{
ALuint src = 0;
alGenSources(1, &src);
ALenum err = alGetError();
if(err != AL_NO_ERROR)
{
stop = true;
}
else
{
mFreeSources.push_back(src);
}
}
}
else // normal case
{ {
for(size_t i = 0;i < maxtotal;i++) ALuint src = 0;
{ alGenSources(1, &src);
ALuint src = 0; throwALerror();
alGenSources(1, &src); mFreeSources.push_back(src);
throwALerror();
mFreeSources.push_back(src);
}
} }
} }
catch(std::exception &e) catch(std::exception &e)
@ -602,10 +607,8 @@ void OpenAL_Output::bufferFinished(ALuint buf)
} }
SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, bool loop) SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, int flags)
{ {
throwALerror();
boost::shared_ptr<OpenAL_Sound> sound; boost::shared_ptr<OpenAL_Sound> sound;
ALuint src=0, buf=0; ALuint src=0, buf=0;
@ -640,7 +643,7 @@ SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float
alSourcef(src, AL_PITCH, pitch); alSourcef(src, AL_PITCH, pitch);
alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE);
alSourcei(src, AL_LOOPING, (loop?AL_TRUE:AL_FALSE)); alSourcei(src, AL_LOOPING, (flags&Play_Loop) ? AL_TRUE : AL_FALSE);
throwALerror(); throwALerror();
alSourcei(src, AL_BUFFER, buf); alSourcei(src, AL_BUFFER, buf);
@ -650,11 +653,9 @@ SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float
return sound; return sound;
} }
SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const float *pos, float volume, float pitch, SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch,
float min, float max, bool loop) float min, float max, int flags)
{ {
throwALerror();
boost::shared_ptr<OpenAL_Sound> sound; boost::shared_ptr<OpenAL_Sound> sound;
ALuint src=0, buf=0; ALuint src=0, buf=0;
@ -666,7 +667,7 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const float *pos,
try try
{ {
buf = getBuffer(fname); buf = getBuffer(fname);
sound.reset(new OpenAL_Sound(*this, src, buf)); sound.reset(new OpenAL_Sound3D(*this, src, buf));
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -677,7 +678,7 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const float *pos,
throw; throw;
} }
alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]); alSource3f(src, AL_POSITION, pos.x, pos.z, -pos.y);
alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
@ -685,11 +686,12 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const float *pos,
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);
alSourcef(src, AL_GAIN, volume); alSourcef(src, AL_GAIN, (pos.squaredDistance(mPos) > max*max) ?
0.0f : volume);
alSourcef(src, AL_PITCH, pitch); alSourcef(src, AL_PITCH, pitch);
alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE);
alSourcei(src, AL_LOOPING, (loop?AL_TRUE:AL_FALSE)); alSourcei(src, AL_LOOPING, (flags&Play_Loop) ? AL_TRUE : AL_FALSE);
throwALerror(); throwALerror();
alSourcei(src, AL_BUFFER, buf); alSourcei(src, AL_BUFFER, buf);
@ -702,8 +704,6 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const float *pos,
SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch) SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch)
{ {
throwALerror();
boost::shared_ptr<OpenAL_SoundStream> sound; boost::shared_ptr<OpenAL_SoundStream> sound;
ALuint src; ALuint src;
@ -743,61 +743,21 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa
return sound; return sound;
} }
SoundPtr OpenAL_Output::streamSound3D(const std::string &fname, const float *pos, float volume, float pitch,
float min, float max) void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir)
{ {
throwALerror(); mPos = pos;
boost::shared_ptr<OpenAL_SoundStream> sound; if(mContext)
ALuint src;
if(mFreeSources.empty())
fail("No free sources");
src = mFreeSources.front();
mFreeSources.pop_front();
try
{ {
DecoderPtr decoder = mManager.getDecoder(); ALfloat orient[6] = {
decoder->open(fname); atdir.x, atdir.z, -atdir.y,
sound.reset(new OpenAL_SoundStream(*this, src, decoder)); updir.x, updir.z, -updir.y
};
alListener3f(AL_POSITION, mPos.x, mPos.z, -mPos.y);
alListenerfv(AL_ORIENTATION, orient);
throwALerror();
} }
catch(std::exception &e)
{
mFreeSources.push_back(src);
throw;
}
alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]);
alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcef(src, AL_REFERENCE_DISTANCE, min);
alSourcef(src, AL_MAX_DISTANCE, max);
alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f);
alSourcef(src, AL_GAIN, volume);
alSourcef(src, AL_PITCH, pitch);
alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE);
alSourcei(src, AL_LOOPING, AL_FALSE);
throwALerror();
sound->play();
return sound;
}
void OpenAL_Output::updateListener(const float *pos, const float *atdir, const float *updir)
{
float orient[6] = {
atdir[0], atdir[2], -atdir[1],
updir[0], updir[2], -updir[1]
};
alListener3f(AL_POSITION, pos[0], pos[2], -pos[1]);
alListenerfv(AL_ORIENTATION, orient);
throwALerror();
} }

View File

@ -40,15 +40,12 @@ namespace MWSound
virtual void init(const std::string &devname=""); virtual void init(const std::string &devname="");
virtual void deinit(); virtual void deinit();
virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, bool loop); virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags);
virtual SoundPtr playSound3D(const std::string &fname, const float *pos, float volume, float pitch, virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
float min, float max, bool loop); 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);
virtual SoundPtr streamSound3D(const std::string &fname, const float *pos, float volume, float pitch,
float min, float max);
virtual void updateListener(const float *pos, const float *atdir, const float *updir); virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir);
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);
@ -60,6 +57,7 @@ namespace MWSound
std::auto_ptr<StreamThread> mStreamThread; std::auto_ptr<StreamThread> mStreamThread;
friend class OpenAL_Sound; friend class OpenAL_Sound;
friend class OpenAL_Sound3D;
friend class OpenAL_SoundStream; friend class OpenAL_SoundStream;
friend class SoundManager; friend class SoundManager;
}; };

View File

@ -1,30 +1,37 @@
#ifndef GAME_SOUND_SOUND_H #ifndef GAME_SOUND_SOUND_H
#define GAME_SOUND_SOUND_H #define GAME_SOUND_SOUND_H
#include <OgreVector3.h>
namespace MWSound namespace MWSound
{ {
class Sound class Sound
{ {
virtual void update(const float *pos) = 0; virtual void update() = 0;
Sound& operator=(const Sound &rhs); Sound& operator=(const Sound &rhs);
Sound(const Sound &rhs); Sound(const Sound &rhs);
protected: protected:
Ogre::Vector3 mPos;
float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */ float mVolume; /* NOTE: Real volume = mVolume*mBaseVolume */
float mBaseVolume; float mBaseVolume;
float mMinDistance; float mMinDistance;
float mMaxDistance; float mMaxDistance;
int mFlags;
public: public:
virtual void stop() = 0; virtual void stop() = 0;
virtual bool isPlaying() = 0; virtual bool isPlaying() = 0;
virtual void setVolume(float volume) = 0; void setPosition(const Ogre::Vector3 &pos) { mPos = pos; }
void setVolume(float volume) { mVolume = volume; }
Sound() : mVolume(1.0f) Sound() : mPos(0.0f, 0.0f, 0.0f)
, mVolume(1.0f)
, mBaseVolume(1.0f) , mBaseVolume(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)
{ } { }
virtual ~Sound() { } virtual ~Sound() { }

View File

@ -4,6 +4,8 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <OgreVector3.h>
#include "soundmanager.hpp" #include "soundmanager.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
@ -22,19 +24,23 @@ namespace MWSound
virtual void init(const std::string &devname="") = 0; virtual void init(const std::string &devname="") = 0;
virtual void deinit() = 0; virtual void deinit() = 0;
virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, bool loop) = 0; virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0;
virtual SoundPtr playSound3D(const std::string &fname, const float *pos, float volume, float pitch, virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos,
float min, float max, bool loop) = 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) = 0;
virtual SoundPtr streamSound3D(const std::string &fname, const float *pos, float volume, float pitch,
float min, float max) = 0;
virtual void updateListener(const float *pos, const float *atdir, const float *updir) = 0; virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir) = 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);
Sound_Output(SoundManager &mgr) : mManager(mgr) { } protected:
Ogre::Vector3 mPos;
Sound_Output(SoundManager &mgr)
: mManager(mgr)
, mPos(0.0f, 0.0f, 0.0f)
{ }
public: public:
virtual ~Sound_Output() { } virtual ~Sound_Output() { }

View File

@ -41,6 +41,8 @@ namespace MWSound
SoundManager::SoundManager(bool useSound, MWWorld::Environment& environment) SoundManager::SoundManager(bool useSound, MWWorld::Environment& environment)
: mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) : mResourceMgr(Ogre::ResourceGroupManager::getSingleton())
, mEnvironment(environment) , mEnvironment(environment)
, mOutput(new DEFAULT_OUTPUT(*this))
{ {
if(!useSound) if(!useSound)
return; return;
@ -50,8 +52,6 @@ namespace MWSound
try try
{ {
mOutput.reset(new DEFAULT_OUTPUT(*this));
std::vector<std::string> names = mOutput->enumerate(); std::vector<std::string> names = mOutput->enumerate();
std::cout <<"Enumerated output devices:"<< std::endl; std::cout <<"Enumerated output devices:"<< std::endl;
for(size_t i = 0;i < names.size();i++) for(size_t i = 0;i < names.size();i++)
@ -62,8 +62,6 @@ namespace MWSound
catch(std::exception &e) catch(std::exception &e)
{ {
std::cout <<"Sound init failed: "<<e.what()<< std::endl; std::cout <<"Sound init failed: "<<e.what()<< std::endl;
mOutput.reset();
return;
} }
} }
@ -108,7 +106,7 @@ namespace MWSound
max = std::max(min, max); max = std::max(min, max);
} }
return std::string("Sound/")+snd->sound; return "Sound/"+snd->sound;
} }
@ -182,11 +180,13 @@ namespace MWSound
{ {
// The range values are not tested // The range values are not tested
float basevol = 1.0f; /* TODO: volume settings */ float basevol = 1.0f; /* TODO: volume settings */
std::string filePath = std::string("Sound/")+filename; std::string filePath = "Sound/"+filename;
const ESM::Position &pos = ptr.getCellRef().pos; const ESM::Position &pos = ptr.getCellRef().pos;
const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
SoundPtr sound = mOutput->playSound3D(filePath, pos.pos, basevol, 1.0f, SoundPtr sound = mOutput->playSound3D(filePath, objpos, basevol, 1.0f,
20.0f, 12750.0f, false); 20.0f, 12750.0f, Play_Normal);
sound->mPos = objpos;
sound->mBaseVolume = basevol; sound->mBaseVolume = basevol;
mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound"));
@ -203,7 +203,7 @@ namespace MWSound
} }
SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, bool loop) SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode)
{ {
SoundPtr sound; SoundPtr sound;
try try
@ -212,11 +212,12 @@ namespace MWSound
float min, max; float min, max;
std::string file = lookup(soundId, basevol, min, max); std::string file = lookup(soundId, basevol, min, max);
sound = mOutput->playSound(file, volume*basevol, pitch, loop); sound = mOutput->playSound(file, volume*basevol, pitch, mode);
sound->mVolume = volume; sound->mVolume = volume;
sound->mBaseVolume = basevol; sound->mBaseVolume = basevol;
sound->mMinDistance = min; sound->mMinDistance = min;
sound->mMaxDistance = max; sound->mMaxDistance = max;
sound->mFlags = mode;
mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId);
} }
@ -228,8 +229,7 @@ namespace MWSound
} }
SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId,
float volume, float pitch, bool loop, float volume, float pitch, int mode)
bool untracked)
{ {
SoundPtr sound; SoundPtr sound;
try try
@ -239,15 +239,20 @@ namespace MWSound
float min, max; float min, max;
std::string file = lookup(soundId, basevol, min, max); std::string file = lookup(soundId, basevol, min, max);
const ESM::Position &pos = ptr.getCellRef().pos; const ESM::Position &pos = ptr.getCellRef().pos;
const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
sound = mOutput->playSound3D(file, pos.pos, volume*basevol, pitch, min, max, loop); sound = mOutput->playSound3D(file, objpos, volume*basevol, pitch, min, max, mode);
sound->mPos = objpos;
sound->mVolume = volume; sound->mVolume = volume;
sound->mBaseVolume = basevol; sound->mBaseVolume = basevol;
sound->mMinDistance = min; sound->mMinDistance = min;
sound->mMaxDistance = max; sound->mMaxDistance = max;
sound->mFlags = mode;
mActiveSounds[sound] = (!untracked ? std::make_pair(ptr, soundId) : if((mode&Play_NoTrack))
std::make_pair(MWWorld::Ptr(), soundId)); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId);
else
mActiveSounds[sound] = std::make_pair(ptr, soundId);
} }
catch(std::exception &e) catch(std::exception &e)
{ {
@ -326,11 +331,12 @@ namespace MWSound
void SoundManager::updateObject(MWWorld::Ptr ptr) void SoundManager::updateObject(MWWorld::Ptr ptr)
{ {
const ESM::Position &pos = ptr.getCellRef().pos; const ESM::Position &pos = ptr.getCellRef().pos;
const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
SoundMap::iterator snditer = mActiveSounds.begin(); SoundMap::iterator snditer = mActiveSounds.begin();
while(snditer != mActiveSounds.end()) while(snditer != mActiveSounds.end())
{ {
if(snditer->second.first == ptr) if(snditer->second.first == ptr)
snditer->first->update(pos.pos); snditer->first->setPosition(objpos);
snditer++; snditer++;
} }
} }
@ -411,9 +417,9 @@ namespace MWSound
// 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.
float pos[3] = { nPos[0], -nPos[2], nPos[1] }; const Ogre::Vector3 pos(nPos[0], -nPos[2], nPos[1]);
float at[3] = { nDir[0], -nDir[2], nDir[1] }; const Ogre::Vector3 at(nDir[0], -nDir[2], nDir[1]);
float up[3] = { 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);
// Check if any sounds are finished playing, and trash them // Check if any sounds are finished playing, and trash them
@ -423,7 +429,10 @@ namespace MWSound
if(!snditer->first->isPlaying()) if(!snditer->first->isPlaying())
mActiveSounds.erase(snditer++); mActiveSounds.erase(snditer++);
else else
{
snditer->first->update();
snditer++; snditer++;
}
} }
} }

View File

@ -30,6 +30,19 @@ namespace MWSound
typedef boost::shared_ptr<Sound_Decoder> DecoderPtr; typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
typedef boost::shared_ptr<Sound> SoundPtr; typedef boost::shared_ptr<Sound> SoundPtr;
enum PlayMode {
Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */
Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */
Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */
Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position
* but do not keep it updated (the sound will not move with
* the object and will not stop when the object is deleted. */
};
static inline int operator|(const PlayMode &a, const PlayMode &b)
{ return (int)a | (int)b; }
static inline int operator&(const PlayMode &a, const PlayMode &b)
{ return (int)a & (int)b; }
class SoundManager class SoundManager
{ {
Ogre::ResourceGroupManager& mResourceMgr; Ogre::ResourceGroupManager& mResourceMgr;
@ -87,12 +100,11 @@ namespace MWSound
bool sayDone(MWWorld::Ptr reference) const; bool sayDone(MWWorld::Ptr reference) const;
///< Is actor not speaking? ///< Is actor not speaking?
SoundPtr playSound(const std::string& soundId, float volume, float pitch, bool loop=false); SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal);
///< Play a sound, independently of 3D-position ///< Play a sound, independently of 3D-position
SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId,
float volume, float pitch, bool loop, float volume, float pitch, int mode=Play_Normal);
bool untracked=false);
///< Play a sound from an object ///< Play a sound from an object
void stopSound3D(MWWorld::Ptr reference, const std::string& soundId); void stopSound3D(MWWorld::Ptr reference, const std::string& soundId);

View File

@ -50,6 +50,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)
{ {

View File

@ -35,7 +35,11 @@ namespace MWWorld
bool toggleCollisionMode(); bool toggleCollisionMode();
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);

View File

@ -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();
@ -498,13 +499,21 @@ namespace MWWorld
std::string World::getFacedHandle() std::string World::getFacedHandle()
{ {
std::pair<std::string, float> result = mPhysics->getFacedHandle (*this); if (!mRendering->occlusionQuerySupported())
{
std::pair<std::string, float> result = mPhysics->getFacedHandle (*this);
if (result.first.empty() || if (result.first.empty() ||
result.second>getStore().gameSettings.find ("iMaxActivateDist")->i) result.second>getStore().gameSettings.find ("iMaxActivateDist")->i)
return ""; return "";
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,13 +715,82 @@ namespace MWWorld
mWeatherManager->update (duration); mWeatherManager->update (duration);
// cast a ray from player to sun to detect if the sun is visible if (!mRendering->occlusionQuerySupported())
// this is temporary until we find a better place to put this code {
// currently its here because we need to access the physics system // cast a ray from player to sun to detect if the sun is visible
float* p = mPlayer->getPlayer().getRefData().getPosition().pos; // this is temporary until we find a better place to put this code
Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); // currently its here because we need to access the physics system
sun = Vector3(sun.x, -sun.z, sun.y); float* p = mPlayer->getPlayer().getRefData().getPosition().pos;
mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); Vector3 sun = mRendering->getSkyManager()->getRealSunPos();
sun = Vector3(sun.x, -sun.z, sun.y);
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

View File

@ -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;

View File

@ -45,6 +45,20 @@ struct ciLessBoost : std::binary_function<std::string, std::string, bool>
} }
}; };
struct pathComparer
{
private:
int m_start, m_size;
public:
pathComparer(int start, int size) : m_start(start), m_size(size) { }
bool operator() (const std::string& first, const std::string& other)
{
return lexicographical_compare(first.substr(m_start,m_size), other.substr(m_start,m_size), boost::algorithm::is_iless());
}
};
static bool fsstrict = false; static bool fsstrict = false;
/// An OGRE Archive wrapping a BSAFile archive /// An OGRE Archive wrapping a BSAFile archive
@ -55,16 +69,62 @@ class DirArchive: public Ogre::FileSystemArchive
std::map<std::string, std::vector<std::string>, ciLessBoost> m; std::map<std::string, std::vector<std::string>, ciLessBoost> m;
unsigned int cutoff; unsigned int cutoff;
bool comparePortion(std::string file1, std::string file2, int start, int size) const bool findFile(const String& filename, std::string& copy) const
{ {
for(int i = start; i < start+size; i++) if (filename.find(".tga") != std::string::npos)
return false;
{ {
char one = file1.at(i); String passed = filename;
char two = file2.at(i); if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
if(tolower(one) != tolower(two) ) || filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':'
return false; || filename.at(filename.length() - 1) == '|')
{
passed = filename.substr(0, filename.length() - 2);
}
if(filename.at(filename.length() - 2) == '>')
passed = filename.substr(0, filename.length() - 6);
copy = passed;
} }
return true;
std::replace(copy.begin(), copy.end(), '\\', '/');
if(copy.at(0) == '/')
copy.erase(0, 1);
if(fsstrict == true)
return true;
std::string folder;
int delimiter = 0;
size_t lastSlash = copy.rfind('/');
if (lastSlash != std::string::npos)
{
folder = copy.substr(0, lastSlash);
delimiter = lastSlash+1;
}
std::vector<std::string> current;
{
std::map<std::string,std::vector<std::string>,ciLessBoost>::const_iterator found = m.find(folder);
if (found == m.end())
{
return false;
}
else
current = found->second;
}
pathComparer comp(delimiter, copy.size() - delimiter-1);
std::vector<std::string>::iterator find = std::lower_bound(current.begin(), current.end(), copy, comp);
if (find != current.end() && !comp(copy, current.front()))
{
copy = *find;
return true;
}
return false;
} }
public: public:
@ -83,16 +143,14 @@ class DirArchive: public Ogre::FileSystemArchive
//need to cut off first //need to cut off first
boost::filesystem::directory_iterator dir_iter(d), dir_end; boost::filesystem::directory_iterator dir_iter(d), dir_end;
std::vector<std::string> filesind; std::vector<std::string> filesind;
boost::filesystem::path f;
for(;dir_iter != dir_end; dir_iter++) for(;dir_iter != dir_end; dir_iter++)
{ {
if(boost::filesystem::is_directory(*dir_iter)) if(boost::filesystem::is_directory(*dir_iter))
populateMap(*dir_iter); populateMap(*dir_iter);
else else
{ {
std::string s = dir_iter->path().string();
f = *dir_iter; std::replace(s.begin(), s.end(), '\\', '/');
std::string s = f.string();
std::string small; std::string small;
if(cutoff < s.size()) if(cutoff < s.size())
@ -103,14 +161,17 @@ class DirArchive: public Ogre::FileSystemArchive
filesind.push_back(small); filesind.push_back(small);
} }
} }
std::sort(filesind.begin(), filesind.end(), ciLessBoost());
std::string small; std::string small;
std::string original = d.string(); std::string original = d.string();
std::replace(original.begin(), original.end(), '\\', '/');
if(cutoff < original.size()) if(cutoff < original.size())
small = original.substr(cutoff, original.size() - cutoff); small = original.substr(cutoff, original.size() - cutoff);
else else
small = original.substr(cutoff - 1, original.size() - cutoff); small = original.substr(cutoff - 1, original.size() - cutoff);
m[small] = filesind;
m[small] = filesind;
} }
bool isCaseSensitive() const { return fsstrict; } bool isCaseSensitive() const { return fsstrict; }
@ -120,97 +181,21 @@ class DirArchive: public Ogre::FileSystemArchive
void unload() {} void unload() {}
bool exists(const String& filename) { bool exists(const String& filename) {
std::string copy = filename; std::string copy;
if (findFile(filename, copy))
for (unsigned int i = 0; i < filename.size(); i++)
{
if(copy.at(i) == '\\' ){
copy.replace(i, 1, "/");
}
}
if(copy.at(0) == '\\' || copy.at(0) == '/')
{
copy.erase(0, 1);
}
if(fsstrict == true)
{
//std::cout << "fsstrict " << copy << "\n";
return FileSystemArchive::exists(copy); return FileSystemArchive::exists(copy);
}
int last = copy.size() - 1;
int i = last;
for (;last >= 0; i--)
{
if(copy.at(i) == '/' || copy.at(i) == '\\')
break;
}
std::string folder = copy.substr(0, i); //folder with no slash
std::vector<std::string>& current = m[folder];
for(std::vector<std::string>::iterator iter = current.begin(); iter != current.end(); iter++)
{
if(comparePortion(*iter, copy, i + 1, copy.size() - i -1) == true){
return FileSystemArchive::exists(*iter);
}
}
return false; return false;
} }
DataStreamPtr open(const String& filename, bool readonly = true) const DataStreamPtr open(const String& filename, bool readonly = true) const
{ {
std::map<std::string, std::vector<std::string>, ciLessBoost> mlocal = m; std::string copy;
std::string copy = filename;
if (findFile(filename, copy))
for (unsigned int i = 0; i < filename.size(); i++)
{
if(copy.at(i) == '\\' ){
copy.replace(i, 1, "/");
}
}
if(copy.at(0) == '\\' || copy.at(0) == '/')
{
copy.erase(0, 1);
}
if(fsstrict == true)
{
return FileSystemArchive::open(copy, readonly); return FileSystemArchive::open(copy, readonly);
}
int last = copy.size() - 1;
int i = last;
for (;last >= 0; i--)
{
if(copy.at(i) == '/' || copy.at(i) == '\\')
break;
}
std::string folder = copy.substr(0, i); //folder with no slash
std::vector<std::string> current = mlocal[folder];
for(std::vector<std::string>::iterator iter = current.begin(); iter != current.end(); iter++)
{
if(comparePortion(*iter, copy, i + 1, copy.size() - i -1) == true){
return FileSystemArchive::open(*iter, readonly);
}
}
DataStreamPtr p; DataStreamPtr p;
return p; return p;
} }
@ -261,7 +246,7 @@ bool exists(const String& filename) {
} }
// Check if the file exists. // Check if the file exists.
bool cexists(const String& filename) const { bool cexists(const String& filename) const {
String passed = filename; String passed = filename;
if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<' if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
|| filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':' || filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':'
@ -272,7 +257,7 @@ bool exists(const String& filename) {
if(filename.at(filename.length() - 2) == '>') if(filename.at(filename.length() - 2) == '>')
passed = filename.substr(0, filename.length() - 6); passed = filename.substr(0, filename.length() - 6);
return arc.exists(passed.c_str()); return arc.exists(passed.c_str());
} }
time_t getModifiedTime(const String&) { return 0; } time_t getModifiedTime(const String&) { return 0; }

View File

@ -30,4 +30,9 @@ namespace Files
return iter->second; return iter->second;
} }
const Files::PathContainer& Collections::getPaths() const
{
return mDirectories;
}
} }

View File

@ -21,6 +21,8 @@ namespace Files
/// leading dot and must be all lower-case. /// leading dot and must be all lower-case.
const MultiDirCollection& getCollection(const std::string& extension) const; const MultiDirCollection& getCollection(const std::string& extension) const;
const Files::PathContainer& getPaths() const;
private: private:
typedef std::map<std::string, MultiDirCollection> MultiDirCollectionContainer; typedef std::map<std::string, MultiDirCollection> MultiDirCollectionContainer;
Files::PathContainer mDirectories; Files::PathContainer mDirectories;

View File

@ -1368,7 +1368,7 @@ void NIFLoader::loadResource(Resource *resource)
if (!vfs->isFile(resourceName)) if (!vfs->isFile(resourceName))
{ {
warn("File not found."); warn("File "+resourceName+" not found.");
return; return;
} }

Binary file not shown.

View File

@ -151,7 +151,8 @@ namespace Physic
PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader) :
mDebugActive(0)
{ {
// Set up the collision configuration and dispatcher // Set up the collision configuration and dispatcher
collisionConfiguration = new btDefaultCollisionConfiguration(); collisionConfiguration = new btDefaultCollisionConfiguration();
@ -203,6 +204,13 @@ namespace Physic
createDebugRendering(); createDebugRendering();
} }
mDebugDrawer->setDebugMode(mode); mDebugDrawer->setDebugMode(mode);
mDebugActive = mode;
}
bool PhysicEngine::toggleDebugRendering()
{
setDebugRenderingMode(!mDebugActive);
return mDebugActive;
} }
PhysicEngine::~PhysicEngine() PhysicEngine::~PhysicEngine()
@ -418,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;
}
}}; }};

View File

@ -199,11 +199,18 @@ namespace Physic
*/ */
void setDebugRenderingMode(int mode); void setDebugRenderingMode(int mode);
bool toggleDebugRendering();
/** /**
* Return the closest object hit by a ray. If there are no objects, it will return ("",-1). * Return the closest object hit by a ray. If there are no objects, it will return ("",-1).
*/ */
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;
@ -230,6 +237,26 @@ namespace Physic
//debug rendering //debug rendering
BtOgre::DebugDrawer* mDebugDrawer; BtOgre::DebugDrawer* mDebugDrawer;
bool isDebugCreated; bool isDebugCreated;
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;
}; };
}} }}