mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 06:35:30 +00:00
Merge remote branch 'zini/master' into sound
This commit is contained in:
commit
9c06bfc8fc
@ -15,7 +15,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
add_openmw_dir (mwrender
|
||||
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
||||
renderinginterface localmap water terrain terrainmaterial
|
||||
renderinginterface localmap occlusionquery terrain terrainmaterial water
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
@ -180,71 +180,58 @@ void WindowManager::updateVisible()
|
||||
// Mouse is visible whenever we're not in game mode
|
||||
MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
|
||||
|
||||
// If in game mode, don't show anything.
|
||||
if(mode == GM_Game) //Use a switch/case structure
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch(mode) {
|
||||
case GM_Game:
|
||||
// If in game mode, don't show anything.
|
||||
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)
|
||||
{
|
||||
// Enable the main menu
|
||||
menu->setVisible(true);
|
||||
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);
|
||||
// Show the windows we want
|
||||
map -> setVisible( (eff & GW_Map) != 0 );
|
||||
stats -> setVisible( (eff & GW_Stats) != 0 );
|
||||
break;
|
||||
}
|
||||
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)
|
||||
|
@ -126,6 +126,11 @@ namespace MWRender{
|
||||
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){
|
||||
shapeNumber = 0;
|
||||
|
||||
if (allshapes == NULL || creaturemodel == NULL || skel == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
|
||||
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)
|
||||
|
||||
|
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
|
@ -46,9 +46,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
||||
mMwRoot->pitch(Degree(-90));
|
||||
mObjects.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");
|
||||
playerNode->pitch(Degree(90));
|
||||
@ -59,10 +56,10 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
|
||||
//mSkyManager = 0;
|
||||
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment);
|
||||
|
||||
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
|
||||
|
||||
mWater = 0;
|
||||
|
||||
|
||||
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
|
||||
mSun = 0;
|
||||
|
||||
@ -76,6 +73,7 @@ RenderingManager::~RenderingManager ()
|
||||
delete mSkyManager;
|
||||
delete mTerrainManager;
|
||||
delete mLocalMap;
|
||||
delete mOcclusionQuery;
|
||||
}
|
||||
|
||||
MWRender::SkyManager* RenderingManager::getSkyManager()
|
||||
@ -166,9 +164,13 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve
|
||||
void RenderingManager::update (float duration){
|
||||
|
||||
mActors.update (duration);
|
||||
|
||||
|
||||
mOcclusionQuery->update(duration);
|
||||
|
||||
mSkyManager->update(duration);
|
||||
|
||||
|
||||
mSkyManager->setGlare(mOcclusionQuery->getSunVisibility());
|
||||
|
||||
mRendering.update(duration);
|
||||
|
||||
mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealDirection() );
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "player.hpp"
|
||||
#include "water.hpp"
|
||||
#include "localmap.hpp"
|
||||
#include "occlusionquery.hpp"
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
@ -108,6 +109,9 @@ class RenderingManager: private RenderingInterface {
|
||||
void sunEnable();
|
||||
void sunDisable();
|
||||
|
||||
bool occlusionQuerySupported() { return mOcclusionQuery->supported(); };
|
||||
OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; };
|
||||
|
||||
void setGlare(bool glare);
|
||||
void skyEnable ();
|
||||
void skyDisable ();
|
||||
@ -145,10 +149,12 @@ class RenderingManager: private RenderingInterface {
|
||||
|
||||
SkyManager* mSkyManager;
|
||||
|
||||
MWRender::Water *mWater;
|
||||
OcclusionQuery* mOcclusionQuery;
|
||||
|
||||
TerrainManager* mTerrainManager;
|
||||
|
||||
MWRender::Water *mWater;
|
||||
|
||||
OEngine::Render::OgreRenderer &mRendering;
|
||||
|
||||
MWRender::Objects mObjects;
|
||||
@ -164,7 +170,6 @@ class RenderingManager: private RenderingInterface {
|
||||
/// that the OGRE coordinate system matches that used internally in
|
||||
/// Morrowind.
|
||||
Ogre::SceneNode *mMwRoot;
|
||||
Ogre::RaySceneQuery *mRaySceneQuery;
|
||||
|
||||
OEngine::Physic::PhysicEngine* mPhysicsEngine;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
#include "occlusionquery.hpp"
|
||||
|
||||
using namespace MWRender;
|
||||
using namespace Ogre;
|
||||
@ -30,7 +31,7 @@ BillboardObject::BillboardObject()
|
||||
|
||||
void BillboardObject::setVisible(const bool visible)
|
||||
{
|
||||
mNode->setVisible(visible);
|
||||
mBBSet->setVisible(visible);
|
||||
}
|
||||
|
||||
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
|
||||
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
|
||||
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->setCommonDirection( -position.normalisedCopy() );
|
||||
mNode = rootNode->createChildSceneNode();
|
||||
@ -319,8 +320,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environmen
|
||||
, mThunderTextureUnit(NULL)
|
||||
, mRemainingTransitionTime(0.0f)
|
||||
, mGlareFade(0.0f)
|
||||
, mGlare(0.0f)
|
||||
, mEnabled(true)
|
||||
, mGlareEnabled(true)
|
||||
, mSunEnabled(true)
|
||||
, mMasserEnabled(true)
|
||||
, mSecundaEnabled(true)
|
||||
@ -592,10 +593,23 @@ void SkyManager::update(float duration)
|
||||
mMasser->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)
|
||||
{
|
||||
// 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();
|
||||
sun = Vector3(sun.x, sun.z, -sun.y);
|
||||
Vector3 cam = mViewport->getCamera()->getRealDirection();
|
||||
@ -603,21 +617,10 @@ void SkyManager::update(float duration)
|
||||
float val = 1- (angle.valueDegrees() / 180.f);
|
||||
val = (val*val*val*val)*2;
|
||||
|
||||
if (mGlareEnabled)
|
||||
{
|
||||
mGlareFade += duration*3;
|
||||
if (mGlareFade > 1) mGlareFade = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mGlareFade -= duration*3;
|
||||
if (mGlareFade < 0.3) mGlareFade = 0;
|
||||
}
|
||||
|
||||
mSunGlare->setSize(val * (mGlareFade));
|
||||
mSunGlare->setSize(val * mGlareFade);
|
||||
}
|
||||
|
||||
mSunGlare->setVisible(mGlareFade>0 && mSunEnabled);
|
||||
mSunGlare->setVisible(mSunEnabled);
|
||||
mSun->setVisible(mSunEnabled);
|
||||
mMasser->setVisible(mMasserEnabled);
|
||||
mSecunda->setVisible(mSecundaEnabled);
|
||||
@ -719,15 +722,15 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
||||
else
|
||||
strength = 1.f;
|
||||
|
||||
mSunGlare->setVisibility(weather.mGlareView * strength);
|
||||
mSun->setVisibility(strength);
|
||||
mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength);
|
||||
mSun->setVisibility(mGlareFade >= 0.5 ? weather.mGlareView * mGlareFade * strength : 0);
|
||||
|
||||
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
|
||||
}
|
||||
|
||||
void SkyManager::setGlare(bool glare)
|
||||
void SkyManager::setGlare(const float glare)
|
||||
{
|
||||
mGlareEnabled = glare;
|
||||
mGlare = glare;
|
||||
}
|
||||
|
||||
Vector3 SkyManager::getRealSunPos()
|
||||
@ -812,3 +815,8 @@ void SkyManager::setDate(int day, int month)
|
||||
mDay = day;
|
||||
mMonth = month;
|
||||
}
|
||||
|
||||
Ogre::SceneNode* SkyManager::getSunNode()
|
||||
{
|
||||
return mSun->getNode();
|
||||
}
|
||||
|
@ -109,58 +109,60 @@ namespace MWRender
|
||||
public:
|
||||
SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env);
|
||||
~SkyManager();
|
||||
|
||||
|
||||
void update(float duration);
|
||||
|
||||
|
||||
void enable();
|
||||
|
||||
|
||||
void disable();
|
||||
|
||||
|
||||
void setHour (double hour);
|
||||
///< will be called even when sky is disabled.
|
||||
|
||||
|
||||
void setDate (int day, int month);
|
||||
///< will be called even when sky is disabled.
|
||||
|
||||
|
||||
int getMasserPhase() const;
|
||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||
/// 3 waxing or waning gibbous, 4 full moon
|
||||
|
||||
|
||||
int getSecundaPhase() const;
|
||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||
/// 3 waxing or waning gibbous, 4 full moon
|
||||
|
||||
|
||||
void setMoonColour (bool red);
|
||||
///< change Secunda colour to red
|
||||
|
||||
|
||||
void setCloudsOpacity(float opacity);
|
||||
///< change opacity of the clouds
|
||||
|
||||
|
||||
void setWeather(const MWWorld::WeatherResult& weather);
|
||||
|
||||
|
||||
Ogre::SceneNode* getSunNode();
|
||||
|
||||
void sunEnable();
|
||||
|
||||
|
||||
void sunDisable();
|
||||
|
||||
|
||||
void setSunDirection(const Ogre::Vector3& direction);
|
||||
|
||||
|
||||
void setMasserDirection(const Ogre::Vector3& direction);
|
||||
|
||||
|
||||
void setSecundaDirection(const Ogre::Vector3& direction);
|
||||
|
||||
|
||||
void setMasserFade(const float fade);
|
||||
|
||||
|
||||
void setSecundaFade(const float fade);
|
||||
|
||||
|
||||
void masserEnable();
|
||||
void masserDisable();
|
||||
|
||||
void secundaEnable();
|
||||
void secundaDisable();
|
||||
|
||||
|
||||
void setThunder(const float factor);
|
||||
|
||||
void setGlare(bool glare);
|
||||
|
||||
void setGlare(const float glare);
|
||||
Ogre::Vector3 getRealSunPos();
|
||||
|
||||
private:
|
||||
@ -203,12 +205,12 @@ namespace MWRender
|
||||
|
||||
float mRemainingTransitionTime;
|
||||
|
||||
float mGlareFade;
|
||||
float mGlare; // target
|
||||
float mGlareFade; // actual
|
||||
|
||||
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
|
||||
|
||||
bool mEnabled;
|
||||
bool mGlareEnabled;
|
||||
bool mSunEnabled;
|
||||
bool mMasserEnabled;
|
||||
bool mSecundaEnabled;
|
||||
|
@ -50,7 +50,7 @@ namespace Ogre
|
||||
terrain.
|
||||
@note Requires the Cg plugin to render correctly
|
||||
*/
|
||||
class _OgreTerrainExport TerrainMaterialGeneratorB : public TerrainMaterialGenerator
|
||||
class TerrainMaterialGeneratorB : public TerrainMaterialGenerator
|
||||
{
|
||||
public:
|
||||
TerrainMaterialGeneratorB();
|
||||
@ -58,7 +58,7 @@ namespace Ogre
|
||||
|
||||
/** Shader model 2 profile target.
|
||||
*/
|
||||
class _OgreTerrainExport SM2Profile : public TerrainMaterialGenerator::Profile
|
||||
class SM2Profile : public TerrainMaterialGenerator::Profile
|
||||
{
|
||||
public:
|
||||
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);
|
||||
|
||||
/// Interface definition for helper class to generate shaders
|
||||
class _OgreTerrainExport ShaderHelper : public TerrainAlloc
|
||||
class ShaderHelper : public TerrainAlloc
|
||||
{
|
||||
public:
|
||||
ShaderHelper() {}
|
||||
@ -194,7 +194,7 @@ namespace Ogre
|
||||
};
|
||||
|
||||
/// Utility class to help with generating shaders for Cg / HLSL.
|
||||
class _OgreTerrainExport ShaderHelperCg : public ShaderHelper
|
||||
class ShaderHelperCg : public ShaderHelper
|
||||
{
|
||||
protected:
|
||||
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);
|
||||
};
|
||||
|
||||
class _OgreTerrainExport ShaderHelperHLSL : public ShaderHelperCg
|
||||
class ShaderHelperHLSL : public ShaderHelperCg
|
||||
{
|
||||
protected:
|
||||
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.
|
||||
class _OgreTerrainExport ShaderHelperGLSL : public ShaderHelper
|
||||
class ShaderHelperGLSL : public ShaderHelper
|
||||
{
|
||||
protected:
|
||||
HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt);
|
||||
|
@ -71,7 +71,7 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
|
||||
class OpenAL_SoundStream : public Sound
|
||||
{
|
||||
static const ALuint sNumBuffers = 6;
|
||||
static const ALfloat sBufferLength = 0.125f;
|
||||
static const ALfloat sBufferLength;
|
||||
|
||||
OpenAL_Output &mOutput;
|
||||
|
||||
@ -101,6 +101,7 @@ public:
|
||||
bool process();
|
||||
};
|
||||
|
||||
const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f;
|
||||
|
||||
//
|
||||
// A background streaming thread (keeps active streams processed)
|
||||
|
@ -50,6 +50,28 @@ namespace MWWorld
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -35,7 +35,11 @@ namespace MWWorld
|
||||
bool toggleCollisionMode();
|
||||
|
||||
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
|
||||
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,
|
||||
bool newGame, Environment& environment, const std::string& encoding)
|
||||
: 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);
|
||||
mPhysEngine = mPhysics->getEngine();
|
||||
@ -498,13 +499,21 @@ namespace MWWorld
|
||||
|
||||
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() ||
|
||||
result.second>getStore().gameSettings.find ("iMaxActivateDist")->i)
|
||||
return "";
|
||||
if (result.first.empty() ||
|
||||
result.second>getStore().gameSettings.find ("iMaxActivateDist")->i)
|
||||
return "";
|
||||
|
||||
return result.first;
|
||||
return result.first;
|
||||
}
|
||||
else
|
||||
{
|
||||
// updated every few frames in update()
|
||||
return mFacedHandle;
|
||||
}
|
||||
}
|
||||
|
||||
void World::deleteObject (Ptr ptr)
|
||||
@ -706,13 +715,82 @@ namespace MWWorld
|
||||
|
||||
mWeatherManager->update (duration);
|
||||
|
||||
// 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
|
||||
// currently its here because we need to access the physics system
|
||||
float* p = mPlayer->getPlayer().getRefData().getPosition().pos;
|
||||
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));
|
||||
if (!mRendering->occlusionQuerySupported())
|
||||
{
|
||||
// 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
|
||||
// currently its here because we need to access the physics system
|
||||
float* p = mPlayer->getPlayer().getRefData().getPosition().pos;
|
||||
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
|
||||
|
@ -93,6 +93,12 @@ namespace MWWorld
|
||||
|
||||
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;
|
||||
|
||||
|
@ -71,6 +71,9 @@ class DirArchive: public Ogre::FileSystemArchive
|
||||
|
||||
bool findFile(const String& filename, std::string& copy) const
|
||||
{
|
||||
if (filename.find(".tga") != std::string::npos)
|
||||
return false;
|
||||
|
||||
{
|
||||
String passed = filename;
|
||||
if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<'
|
||||
@ -179,7 +182,7 @@ class DirArchive: public Ogre::FileSystemArchive
|
||||
|
||||
bool exists(const String& filename) {
|
||||
std::string copy;
|
||||
|
||||
|
||||
if (findFile(filename, copy))
|
||||
return FileSystemArchive::exists(copy);
|
||||
|
||||
@ -192,7 +195,7 @@ class DirArchive: public Ogre::FileSystemArchive
|
||||
|
||||
if (findFile(filename, copy))
|
||||
return FileSystemArchive::open(copy, readonly);
|
||||
|
||||
|
||||
DataStreamPtr p;
|
||||
return p;
|
||||
}
|
||||
@ -243,7 +246,7 @@ bool exists(const String& filename) {
|
||||
}
|
||||
|
||||
// Check if the file exists.
|
||||
bool cexists(const String& filename) const {
|
||||
bool cexists(const String& filename) const {
|
||||
String passed = filename;
|
||||
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) == ':'
|
||||
@ -254,7 +257,7 @@ bool exists(const String& filename) {
|
||||
if(filename.at(filename.length() - 2) == '>')
|
||||
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; }
|
||||
|
||||
|
Binary file not shown.
@ -426,4 +426,35 @@ namespace Physic
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
std::list<PhysicEvent> NPEventList;
|
||||
|
||||
@ -235,6 +240,25 @@ namespace Physic
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user