mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 03:15:32 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
e081eb2c34
23 changed files with 319 additions and 143 deletions
|
@ -40,8 +40,8 @@ script:
|
|||
- cd ./build
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
|
||||
notifications:
|
||||
recipients:
|
||||
- corrmage+travis-ci@gmail.com
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components)
|
||||
OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} --exclude=ui_\* apps components)
|
||||
|
||||
if [[ $OUTPUT ]] ; then
|
||||
echo "Error: Tab characters found!"
|
||||
|
|
|
@ -504,8 +504,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false,
|
||||
1.0f, "start", "stop", 0.0f, ~0ul, true);
|
||||
}
|
||||
|
||||
updateIdleStormState();
|
||||
}
|
||||
|
||||
|
||||
|
@ -656,6 +654,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
|||
, mAnimation(anim)
|
||||
, mIdleState(CharState_None)
|
||||
, mMovementState(CharState_None)
|
||||
, mAdjustMovementAnimSpeed(false)
|
||||
, mHasMovedInXY(false)
|
||||
, mMovementAnimationControlled(true)
|
||||
, mDeathState(CharState_None)
|
||||
|
@ -867,7 +866,7 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
|
|||
mPtr = ptr;
|
||||
}
|
||||
|
||||
void CharacterController::updateIdleStormState()
|
||||
void CharacterController::updateIdleStormState(bool inwater)
|
||||
{
|
||||
bool inStormDirection = false;
|
||||
if (MWBase::Environment::get().getWorld()->isInStorm())
|
||||
|
@ -877,7 +876,7 @@ void CharacterController::updateIdleStormState()
|
|||
inStormDirection = std::acos(stormDirection * characterDirection / (stormDirection.length() * characterDirection.length()))
|
||||
> osg::DegreesToRadians(120.f);
|
||||
}
|
||||
if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm"))
|
||||
if (inStormDirection && !inwater && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm"))
|
||||
{
|
||||
float complete = 0;
|
||||
mAnimation->getInfo("idlestorm", &complete);
|
||||
|
@ -1796,6 +1795,7 @@ void CharacterController::update(float duration)
|
|||
forcestateupdate = updateCreatureState() || forcestateupdate;
|
||||
|
||||
refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate);
|
||||
updateIdleStormState(inwater);
|
||||
}
|
||||
|
||||
if (inJump)
|
||||
|
@ -2122,7 +2122,7 @@ void CharacterController::updateHeadTracking(float duration)
|
|||
osg::Matrixf mat = mats[0];
|
||||
osg::Vec3f headPos = mat.getTrans();
|
||||
|
||||
osg::Vec3f targetPos (mHeadTrackTarget.getRefData().getPosition().asVec3());
|
||||
osg::Vec3f direction;
|
||||
if (MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget))
|
||||
{
|
||||
const osg::Node* node = anim->getNode("Head");
|
||||
|
@ -2132,11 +2132,12 @@ void CharacterController::updateHeadTracking(float duration)
|
|||
{
|
||||
osg::MatrixList mats = node->getWorldMatrices();
|
||||
if (mats.size())
|
||||
targetPos = mats[0].getTrans();
|
||||
direction = mats[0].getTrans() - headPos;
|
||||
}
|
||||
else
|
||||
// no head node to look at, fall back to look at center of collision box
|
||||
direction = MWBase::Environment::get().getWorld()->aimToTarget(mPtr, mHeadTrackTarget);
|
||||
}
|
||||
|
||||
osg::Vec3f direction = targetPos - headPos;
|
||||
direction.normalize();
|
||||
|
||||
if (!mPtr.getRefData().getBaseNode())
|
||||
|
|
|
@ -196,7 +196,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
|||
|
||||
bool updateWeaponState();
|
||||
bool updateCreatureState();
|
||||
void updateIdleStormState();
|
||||
void updateIdleStormState(bool inwater);
|
||||
|
||||
void updateHeadTracking(float duration);
|
||||
|
||||
|
|
|
@ -95,6 +95,11 @@ void Actor::updatePosition()
|
|||
mCollisionObject->setWorldTransform(tr);
|
||||
}
|
||||
|
||||
osg::Vec3f Actor::getPosition() const
|
||||
{
|
||||
return toOsg(mCollisionObject->getWorldTransform().getOrigin());
|
||||
}
|
||||
|
||||
void Actor::updateRotation ()
|
||||
{
|
||||
btTransform tr = mCollisionObject->getWorldTransform();
|
||||
|
|
|
@ -70,6 +70,12 @@ namespace MWPhysics
|
|||
*/
|
||||
osg::Vec3f getHalfExtents() const;
|
||||
|
||||
/**
|
||||
* Returns the position of the collision body
|
||||
* @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space.
|
||||
*/
|
||||
osg::Vec3f getPosition() const;
|
||||
|
||||
/**
|
||||
* Returns the half extents of the collision body (scaled according to rendering scale)
|
||||
* @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape,
|
||||
|
|
|
@ -240,6 +240,8 @@ namespace MWPhysics
|
|||
const ESM::Position& refpos = ptr.getRefData().getPosition();
|
||||
osg::Vec3f position(refpos.asVec3());
|
||||
|
||||
float collisionShapeOffset = physicActor->getPosition().z() - position.z();
|
||||
|
||||
// Early-out for totally static creatures
|
||||
// (Not sure if gravity should still apply?)
|
||||
if (!ptr.getClass().isMobile(ptr))
|
||||
|
@ -256,12 +258,11 @@ namespace MWPhysics
|
|||
}
|
||||
|
||||
btCollisionObject *colobj = physicActor->getCollisionObject();
|
||||
osg::Vec3f halfExtents = physicActor->getHalfExtents();
|
||||
position.z() += halfExtents.z();
|
||||
position.z() += collisionShapeOffset;
|
||||
|
||||
static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("fSwimHeightScale")->getFloat();
|
||||
float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale);
|
||||
float swimlevel = waterlevel + collisionShapeOffset - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale);
|
||||
|
||||
ActorTracer tracer;
|
||||
osg::Vec3f inertia = physicActor->getInertialForce();
|
||||
|
@ -369,7 +370,7 @@ namespace MWPhysics
|
|||
{
|
||||
// don't let pure water creatures move out of water after stepMove
|
||||
if (ptr.getClass().isPureWaterCreature(ptr)
|
||||
&& newPosition.z() + halfExtents.z() > waterlevel)
|
||||
&& newPosition.z() + physicActor->getHalfExtents().z() > waterlevel)
|
||||
newPosition = oldPosition;
|
||||
}
|
||||
else
|
||||
|
@ -450,7 +451,7 @@ namespace MWPhysics
|
|||
}
|
||||
physicActor->setOnGround(isOnGround);
|
||||
|
||||
newPosition.z() -= halfExtents.z(); // remove what was added at the beginning
|
||||
newPosition.z() -= collisionShapeOffset; // remove what was added at the beginning
|
||||
return newPosition;
|
||||
}
|
||||
};
|
||||
|
@ -820,12 +821,8 @@ namespace MWPhysics
|
|||
if (!physactor1 || !physactor2)
|
||||
return false;
|
||||
|
||||
osg::Vec3f halfExt1 = physactor1->getHalfExtents();
|
||||
osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3());
|
||||
pos1.z() += halfExt1.z()*2*0.9f; // eye level
|
||||
osg::Vec3f halfExt2 = physactor2->getHalfExtents();
|
||||
osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3());
|
||||
pos2.z() += halfExt2.z()*2*0.9f;
|
||||
osg::Vec3f pos1 (physactor1->getPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.8)); // eye level
|
||||
osg::Vec3f pos2 (physactor2->getPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.8));
|
||||
|
||||
RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap);
|
||||
|
||||
|
@ -869,24 +866,33 @@ namespace MWPhysics
|
|||
}
|
||||
}
|
||||
|
||||
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor)
|
||||
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) const
|
||||
{
|
||||
Actor* physactor = getActor(actor);
|
||||
const Actor* physactor = getActor(actor);
|
||||
if (physactor)
|
||||
return physactor->getHalfExtents();
|
||||
else
|
||||
return osg::Vec3f();
|
||||
}
|
||||
|
||||
osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor)
|
||||
osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) const
|
||||
{
|
||||
Actor* physactor = getActor(actor);
|
||||
const Actor* physactor = getActor(actor);
|
||||
if (physactor)
|
||||
return physactor->getRenderingHalfExtents();
|
||||
else
|
||||
return osg::Vec3f();
|
||||
}
|
||||
|
||||
osg::Vec3f PhysicsSystem::getPosition(const MWWorld::Ptr &actor) const
|
||||
{
|
||||
const Actor* physactor = getActor(actor);
|
||||
if (physactor)
|
||||
return physactor->getPosition();
|
||||
else
|
||||
return osg::Vec3f();
|
||||
}
|
||||
|
||||
class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback
|
||||
{
|
||||
public:
|
||||
|
@ -1036,6 +1042,14 @@ namespace MWPhysics
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
ActorMap::const_iterator found = mActors.find(ptr);
|
||||
if (found != mActors.end())
|
||||
return found->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr)
|
||||
{
|
||||
ObjectMap::iterator found = mObjects.find(ptr);
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace MWPhysics
|
|||
void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated);
|
||||
|
||||
Actor* getActor(const MWWorld::Ptr& ptr);
|
||||
const Actor* getActor(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
// Object or Actor
|
||||
void remove (const MWWorld::Ptr& ptr);
|
||||
|
@ -108,10 +109,14 @@ namespace MWPhysics
|
|||
bool isOnGround (const MWWorld::Ptr& actor);
|
||||
|
||||
/// Get physical half extents (scaled) of the given actor.
|
||||
osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor);
|
||||
osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor) const;
|
||||
|
||||
/// @see MWPhysics::Actor::getRenderingHalfExtents
|
||||
osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor);
|
||||
osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor) const;
|
||||
|
||||
/// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the collision bounds in world space.
|
||||
/// @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space.
|
||||
osg::Vec3f getPosition(const MWWorld::Ptr& actor) const;
|
||||
|
||||
/// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
|
||||
/// be overwritten. Valid until the next call to applyQueuedMovement.
|
||||
|
|
|
@ -1111,25 +1111,6 @@ namespace MWRender
|
|||
attachTo->addChild(lightSource);
|
||||
}
|
||||
|
||||
class DisableFreezeOnCullVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
DisableFreezeOnCullVisitor()
|
||||
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void apply(osg::Geode &geode)
|
||||
{
|
||||
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
|
||||
{
|
||||
osg::Drawable* drw = geode.getDrawable(i);
|
||||
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(drw))
|
||||
partsys->setFreezeOnCull(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture)
|
||||
{
|
||||
if (!mObjectRoot.get())
|
||||
|
@ -1163,7 +1144,7 @@ namespace MWRender
|
|||
node->accept(findMaxLengthVisitor);
|
||||
|
||||
// FreezeOnCull doesn't work so well with effect particles, that tend to have moving emitters
|
||||
DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
||||
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
||||
node->accept(disableFreezeOnCullVisitor);
|
||||
|
||||
params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength();
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <components/esm/loadcell.hpp>
|
||||
|
||||
#include "../mwworld/fallback.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
|
||||
#include "sky.hpp"
|
||||
#include "effectmanager.hpp"
|
||||
|
@ -130,6 +131,10 @@ namespace MWRender
|
|||
, mRootNode(rootNode)
|
||||
, mResourceSystem(resourceSystem)
|
||||
, mFogDepth(0.f)
|
||||
, mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor"))
|
||||
, mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight"))
|
||||
, mUnderwaterFog(0.f)
|
||||
, mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog"))
|
||||
, mNightEyeFactor(0.f)
|
||||
{
|
||||
osg::ref_ptr<SceneUtil::LightManager> lightRoot = new SceneUtil::LightManager;
|
||||
|
@ -201,10 +206,6 @@ namespace MWRender
|
|||
updateProjectionMatrix();
|
||||
mStateUpdater->setFogEnd(mViewDistance);
|
||||
|
||||
mUnderwaterColor = fallback->getFallbackColour("Water_UnderwaterColor");
|
||||
mUnderwaterWeight = fallback->getFallbackFloat("Water_UnderwaterColorWeight");
|
||||
mUnderwaterIndoorFog = fallback->getFallbackFloat("Water_UnderwaterIndoorFog");
|
||||
|
||||
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip));
|
||||
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance));
|
||||
}
|
||||
|
@ -449,11 +450,13 @@ namespace MWRender
|
|||
void RenderingManager::setWaterEnabled(bool enabled)
|
||||
{
|
||||
mWater->setEnabled(enabled);
|
||||
mSky->setWaterEnabled(enabled);
|
||||
}
|
||||
|
||||
void RenderingManager::setWaterHeight(float height)
|
||||
{
|
||||
mWater->setHeight(height);
|
||||
mSky->setWaterHeight(height);
|
||||
}
|
||||
|
||||
class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/sceneutil/statesetupdater.hpp>
|
||||
#include <components/sceneutil/controller.hpp>
|
||||
#include <components/sceneutil/visitor.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -261,8 +262,18 @@ public:
|
|||
|
||||
META_Node(MWRender, CameraRelativeTransform)
|
||||
|
||||
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const
|
||||
const osg::Vec3f& getLastEyePoint() const
|
||||
{
|
||||
return mEyePoint;
|
||||
}
|
||||
|
||||
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const
|
||||
{
|
||||
if (nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||
{
|
||||
mEyePoint = static_cast<osgUtil::CullVisitor*>(nv)->getEyePoint();
|
||||
}
|
||||
|
||||
if (_referenceFrame==RELATIVE_RF)
|
||||
{
|
||||
matrix.setTrans(osg::Vec3f(0.f,0.f,0.f));
|
||||
|
@ -321,6 +332,9 @@ public:
|
|||
cv->getCurrentCullingSet().popCurrentMask();
|
||||
}
|
||||
};
|
||||
private:
|
||||
// eyePoint for the current frame
|
||||
mutable osg::Vec3f mEyePoint;
|
||||
};
|
||||
|
||||
class ModVertexAlphaVisitor : public osg::NodeVisitor
|
||||
|
@ -370,6 +384,45 @@ private:
|
|||
int mMeshType;
|
||||
};
|
||||
|
||||
/// @brief Hides the node subgraph if the eye point is below water.
|
||||
/// @note Must be added as cull callback.
|
||||
/// @note Meant to be used on a node that is child of a CameraRelativeTransform.
|
||||
/// The current eye point must be retrieved by the CameraRelativeTransform since we can't get it anymore once we are in camera-relative space.
|
||||
class UnderwaterSwitchCallback : public osg::NodeCallback
|
||||
{
|
||||
public:
|
||||
UnderwaterSwitchCallback(CameraRelativeTransform* cameraRelativeTransform)
|
||||
: mCameraRelativeTransform(cameraRelativeTransform)
|
||||
, mEnabled(true)
|
||||
, mWaterLevel(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
osg::Vec3f eyePoint = mCameraRelativeTransform->getLastEyePoint();
|
||||
|
||||
if (mEnabled && eyePoint.z() < mWaterLevel)
|
||||
return;
|
||||
|
||||
traverse(node, nv);
|
||||
}
|
||||
|
||||
void setEnabled(bool enabled)
|
||||
{
|
||||
mEnabled = enabled;
|
||||
}
|
||||
void setWaterLevel(float waterLevel)
|
||||
{
|
||||
mWaterLevel = waterLevel;
|
||||
}
|
||||
|
||||
private:
|
||||
osg::ref_ptr<CameraRelativeTransform> mCameraRelativeTransform;
|
||||
bool mEnabled;
|
||||
float mWaterLevel;
|
||||
};
|
||||
|
||||
/// A base class for the sun and moons.
|
||||
class CelestialBody
|
||||
{
|
||||
|
@ -1065,18 +1118,21 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana
|
|||
|
||||
mRootNode = skyroot;
|
||||
|
||||
// By default render before the world is rendered
|
||||
mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin");
|
||||
|
||||
mEarlyRenderBinRoot = new osg::Group;
|
||||
// render before the world is rendered
|
||||
mEarlyRenderBinRoot->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin");
|
||||
// Prevent unwanted clipping by water reflection camera's clipping plane
|
||||
mRootNode->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF);
|
||||
mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF);
|
||||
mRootNode->addChild(mEarlyRenderBinRoot);
|
||||
|
||||
mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot);
|
||||
}
|
||||
|
||||
void SkyManager::create()
|
||||
{
|
||||
assert(!mCreated);
|
||||
|
||||
mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode);
|
||||
mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot);
|
||||
ModVertexAlphaVisitor modAtmosphere(0);
|
||||
mAtmosphereDay->accept(modAtmosphere);
|
||||
|
||||
|
@ -1085,7 +1141,7 @@ void SkyManager::create()
|
|||
|
||||
mAtmosphereNightNode = new osg::PositionAttitudeTransform;
|
||||
mAtmosphereNightNode->setNodeMask(0);
|
||||
mRootNode->addChild(mAtmosphereNightNode);
|
||||
mEarlyRenderBinRoot->addChild(mAtmosphereNightNode);
|
||||
|
||||
osg::ref_ptr<osg::Node> atmosphereNight;
|
||||
if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif"))
|
||||
|
@ -1098,14 +1154,14 @@ void SkyManager::create()
|
|||
mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager());
|
||||
atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater);
|
||||
|
||||
mSun.reset(new Sun(mRootNode, *mSceneManager->getTextureManager()));
|
||||
mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getTextureManager()));
|
||||
|
||||
const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback();
|
||||
mMasser.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser));
|
||||
mSecunda.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda));
|
||||
mMasser.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser));
|
||||
mSecunda.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda));
|
||||
|
||||
mCloudNode = new osg::PositionAttitudeTransform;
|
||||
mRootNode->addChild(mCloudNode);
|
||||
mEarlyRenderBinRoot->addChild(mCloudNode);
|
||||
mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode);
|
||||
ModVertexAlphaVisitor modClouds(1);
|
||||
mCloudMesh->accept(modClouds);
|
||||
|
@ -1122,9 +1178,9 @@ void SkyManager::create()
|
|||
|
||||
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
|
||||
depth->setWriteMask(false);
|
||||
mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||
mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
mRootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF);
|
||||
mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||
mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF);
|
||||
|
||||
mMoonScriptColor = fallback->getFallbackColour("Moons_Script_Color");
|
||||
|
||||
|
@ -1196,14 +1252,13 @@ public:
|
|||
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha));
|
||||
}
|
||||
|
||||
// Helper for adding AlphaFader to a subgraph
|
||||
// Helper for adding AlphaFaders to a subgraph
|
||||
class SetupVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
SetupVisitor()
|
||||
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
||||
{
|
||||
mAlphaFader = new AlphaFader;
|
||||
}
|
||||
|
||||
virtual void apply(osg::Node &node)
|
||||
|
@ -1225,22 +1280,26 @@ public:
|
|||
callback = callback->getNestedCallback();
|
||||
}
|
||||
|
||||
osg::ref_ptr<AlphaFader> alphaFader (new AlphaFader);
|
||||
|
||||
if (composite)
|
||||
composite->addController(mAlphaFader);
|
||||
composite->addController(alphaFader);
|
||||
else
|
||||
node.addUpdateCallback(mAlphaFader);
|
||||
node.addUpdateCallback(alphaFader);
|
||||
|
||||
mAlphaFaders.push_back(alphaFader);
|
||||
}
|
||||
}
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
osg::ref_ptr<AlphaFader> getAlphaFader()
|
||||
std::vector<osg::ref_ptr<AlphaFader> > getAlphaFaders()
|
||||
{
|
||||
return mAlphaFader;
|
||||
return mAlphaFaders;
|
||||
}
|
||||
|
||||
private:
|
||||
osg::ref_ptr<AlphaFader> mAlphaFader;
|
||||
std::vector<osg::ref_ptr<AlphaFader> > mAlphaFaders;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -1278,6 +1337,7 @@ void SkyManager::createRain()
|
|||
stateset->setNestRenderBins(false);
|
||||
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
|
||||
osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate();
|
||||
particleTemplate.setSizeRange(osgParticle::rangef(5.f, 15.f));
|
||||
|
@ -1313,6 +1373,8 @@ void SkyManager::createRain()
|
|||
|
||||
mRainFader = new RainFader;
|
||||
mRainNode->addUpdateCallback(mRainFader);
|
||||
mRainNode->addCullCallback(mUnderwaterSwitch);
|
||||
mRainNode->setNodeMask(Mask_WeatherParticles);
|
||||
|
||||
mRootNode->addChild(mRainNode);
|
||||
}
|
||||
|
@ -1432,6 +1494,14 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
|||
{
|
||||
mCurrentParticleEffect = weather.mParticleEffect;
|
||||
|
||||
// cleanup old particles
|
||||
if (mParticleEffect)
|
||||
{
|
||||
mParticleNode->removeChild(mParticleEffect);
|
||||
mParticleEffect = NULL;
|
||||
mParticleFaders.clear();
|
||||
}
|
||||
|
||||
if (mCurrentParticleEffect.empty())
|
||||
{
|
||||
if (mParticleNode)
|
||||
|
@ -1439,14 +1509,14 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
|||
mRootNode->removeChild(mParticleNode);
|
||||
mParticleNode = NULL;
|
||||
}
|
||||
mParticleEffect = NULL;
|
||||
mParticleFader = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mParticleNode)
|
||||
{
|
||||
mParticleNode = new osg::PositionAttitudeTransform;
|
||||
mParticleNode->addCullCallback(mUnderwaterSwitch);
|
||||
mParticleNode->setNodeMask(Mask_WeatherParticles);
|
||||
mRootNode->addChild(mParticleNode);
|
||||
}
|
||||
mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode);
|
||||
|
@ -1456,7 +1526,10 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
|||
|
||||
AlphaFader::SetupVisitor alphaFaderSetupVisitor;
|
||||
mParticleEffect->accept(alphaFaderSetupVisitor);
|
||||
mParticleFader = alphaFaderSetupVisitor.getAlphaFader();
|
||||
mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders();
|
||||
|
||||
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
|
||||
mParticleEffect->accept(disableFreezeOnCullVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1537,8 +1610,8 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
|||
|
||||
if (mRainFader)
|
||||
mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold?
|
||||
if (mParticleFader)
|
||||
mParticleFader->setAlpha(weather.mEffectFade);
|
||||
for (std::vector<osg::ref_ptr<AlphaFader> >::const_iterator it = mParticleFaders.begin(); it != mParticleFaders.end(); ++it)
|
||||
(*it)->setAlpha(weather.mEffectFade);
|
||||
}
|
||||
|
||||
void SkyManager::sunEnable()
|
||||
|
@ -1592,4 +1665,14 @@ void SkyManager::setGlareTimeOfDayFade(float val)
|
|||
mSun->setGlareTimeOfDayFade(val);
|
||||
}
|
||||
|
||||
void SkyManager::setWaterHeight(float height)
|
||||
{
|
||||
mUnderwaterSwitch->setWaterLevel(height);
|
||||
}
|
||||
|
||||
void SkyManager::setWaterEnabled(bool enabled)
|
||||
{
|
||||
mUnderwaterSwitch->setEnabled(enabled);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace MWRender
|
|||
class RainShooter;
|
||||
class RainFader;
|
||||
class AlphaFader;
|
||||
class UnderwaterSwitchCallback;
|
||||
|
||||
struct WeatherResult
|
||||
{
|
||||
|
@ -100,6 +101,8 @@ namespace MWRender
|
|||
float mMoonAlpha;
|
||||
};
|
||||
|
||||
///@brief The SkyManager handles rendering of the sky domes, celestial bodies as well as other objects that need to be rendered
|
||||
/// relative to the camera (e.g. weather particle effects)
|
||||
class SkyManager
|
||||
{
|
||||
public:
|
||||
|
@ -144,6 +147,12 @@ namespace MWRender
|
|||
|
||||
void setGlareTimeOfDayFade(float val);
|
||||
|
||||
/// Enable or disable the water plane (used to remove underwater weather particles)
|
||||
void setWaterEnabled(bool enabled);
|
||||
|
||||
/// Set height of water plane (used to remove underwater weather particles)
|
||||
void setWaterHeight(float height);
|
||||
|
||||
private:
|
||||
void create();
|
||||
///< no need to call this, automatically done on first enable()
|
||||
|
@ -155,10 +164,12 @@ namespace MWRender
|
|||
Resource::SceneManager* mSceneManager;
|
||||
|
||||
osg::ref_ptr<osg::Group> mRootNode;
|
||||
osg::ref_ptr<osg::Group> mEarlyRenderBinRoot;
|
||||
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mParticleNode;
|
||||
osg::ref_ptr<osg::Node> mParticleEffect;
|
||||
osg::ref_ptr<AlphaFader> mParticleFader;
|
||||
std::vector<osg::ref_ptr<AlphaFader> > mParticleFaders;
|
||||
osg::ref_ptr<UnderwaterSwitchCallback> mUnderwaterSwitch;
|
||||
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mCloudNode;
|
||||
|
||||
|
|
|
@ -15,21 +15,26 @@ namespace MWRender
|
|||
Mask_Actor = (1<<3),
|
||||
Mask_Player = (1<<4),
|
||||
Mask_Sky = (1<<5),
|
||||
Mask_Sun = (1<<6),
|
||||
Mask_Water = (1<<7),
|
||||
Mask_SimpleWater = (1<<8),
|
||||
Mask_Terrain = (1<<9),
|
||||
Mask_FirstPerson = (1<<10),
|
||||
Mask_Water = (1<<6),
|
||||
Mask_Terrain = (1<<7),
|
||||
Mask_FirstPerson = (1<<8),
|
||||
|
||||
// child of Sky
|
||||
Mask_Sun = (1<<9),
|
||||
Mask_WeatherParticles = (1<<10),
|
||||
|
||||
// child of Water
|
||||
Mask_SimpleWater = (1<<11),
|
||||
|
||||
// top level masks
|
||||
Mask_Scene = (1<<11),
|
||||
Mask_GUI = (1<<12),
|
||||
Mask_Scene = (1<<12),
|
||||
Mask_GUI = (1<<13),
|
||||
|
||||
// Set on a Geode
|
||||
Mask_ParticleSystem = (1<<13),
|
||||
Mask_ParticleSystem = (1<<14),
|
||||
|
||||
// Set on cameras within the main scene graph
|
||||
Mask_RenderToTexture = (1<<14)
|
||||
Mask_RenderToTexture = (1<<15)
|
||||
|
||||
// reserved: (1<<16) for SceneUtil::Mask_Lit
|
||||
};
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
|
||||
#include <components/esm/loadcell.hpp>
|
||||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/fallback.hpp"
|
||||
|
||||
#include "vismask.hpp"
|
||||
#include "ripplesimulation.hpp"
|
||||
#include "renderbin.hpp"
|
||||
|
@ -79,6 +82,10 @@ namespace
|
|||
waterGeom->setVertexArray(verts);
|
||||
waterGeom->setTexCoordArray(0, texcoords);
|
||||
|
||||
osg::ref_ptr<osg::Vec3Array> normal (new osg::Vec3Array);
|
||||
normal->push_back(osg::Vec3f(0,0,1));
|
||||
waterGeom->setNormalArray(normal, osg::Array::BIND_OVERALL);
|
||||
|
||||
waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size()));
|
||||
return waterGeom;
|
||||
}
|
||||
|
@ -145,12 +152,9 @@ class ClipCullNode : public osg::Group
|
|||
|
||||
osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix());
|
||||
|
||||
// move the plane back along its normal a little bit to prevent bleeding at the water shore
|
||||
const float clipFudge = -5;
|
||||
// now apply the height of the plane
|
||||
// apply the height of the plane
|
||||
// we can't apply this height in the addClipPlane() since the "flip the below graph" function would otherwise flip the height as well
|
||||
float translate = clipFudge + ((*mCullPlane)[3] * -1);
|
||||
modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * translate);
|
||||
modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * ((*mCullPlane)[3] * -1));
|
||||
|
||||
// flip the below graph if the eye point is above the plane
|
||||
if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0)
|
||||
|
@ -158,6 +162,10 @@ class ClipCullNode : public osg::Group
|
|||
modelViewMatrix->preMultScale(osg::Vec3(1,1,-1));
|
||||
}
|
||||
|
||||
// move the plane back along its normal a little bit to prevent bleeding at the water shore
|
||||
const float clipFudge = -5;
|
||||
modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge);
|
||||
|
||||
cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF);
|
||||
traverse(node, nv);
|
||||
cv->popModelViewMatrix();
|
||||
|
@ -451,6 +459,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
|
|||
: mParent(parent)
|
||||
, mSceneRoot(sceneRoot)
|
||||
, mResourceSystem(resourceSystem)
|
||||
, mFallback(fallback)
|
||||
, mResourcePath(resourcePath)
|
||||
, mEnabled(true)
|
||||
, mToggled(true)
|
||||
|
@ -474,7 +483,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
|
|||
|
||||
// simple water fallback for the local map
|
||||
osg::ref_ptr<osg::Geode> geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES));
|
||||
createSimpleWaterStateSet(geode2);
|
||||
createSimpleWaterStateSet(geode2, mFallback->getFallbackFloat("Water_Map_Alpha"));
|
||||
geode2->setNodeMask(Mask_SimpleWater);
|
||||
mWaterNode->addChild(geode2);
|
||||
|
||||
|
@ -516,19 +525,19 @@ void Water::updateWaterMaterial()
|
|||
createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction);
|
||||
}
|
||||
else
|
||||
createSimpleWaterStateSet(mWaterGeode);
|
||||
createSimpleWaterStateSet(mWaterGeode, mFallback->getFallbackFloat("Water_World_Alpha"));
|
||||
|
||||
updateVisible();
|
||||
}
|
||||
|
||||
void Water::createSimpleWaterStateSet(osg::Node* node)
|
||||
void Water::createSimpleWaterStateSet(osg::Node* node, float alpha)
|
||||
{
|
||||
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet);
|
||||
|
||||
osg::ref_ptr<osg::Material> material (new osg::Material);
|
||||
material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f));
|
||||
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f));
|
||||
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
|
||||
material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
|
||||
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, alpha));
|
||||
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f));
|
||||
material->setColorMode(osg::Material::OFF);
|
||||
stateset->setAttributeAndModes(material, osg::StateAttribute::ON);
|
||||
|
||||
|
@ -542,14 +551,18 @@ void Water::createSimpleWaterStateSet(osg::Node* node)
|
|||
stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin");
|
||||
|
||||
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
|
||||
for (int i=0; i<32; ++i)
|
||||
int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount");
|
||||
std::string texture = mFallback->getFallbackString("Water_SurfaceTexture");
|
||||
for (int i=0; i<frameCount; ++i)
|
||||
{
|
||||
std::ostringstream texname;
|
||||
texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds";
|
||||
texname << "textures/water/" << texture << std::setw(2) << std::setfill('0') << i << ".dds";
|
||||
textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT));
|
||||
}
|
||||
|
||||
osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 2/32.f, textures));
|
||||
float fps = mFallback->getFallbackFloat("Water_SurfaceFPS");
|
||||
|
||||
osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 1.f/fps, textures));
|
||||
controller->setSource(boost::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
|
||||
node->setUpdateCallback(controller);
|
||||
node->setStateSet(stateset);
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#ifndef OPENMW_MWRENDER_WATER_H
|
||||
#define OPENMW_MWRENDER_WATER_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Group;
|
||||
|
@ -28,6 +29,8 @@ namespace Resource
|
|||
namespace MWWorld
|
||||
{
|
||||
class Fallback;
|
||||
class CellStore;
|
||||
class Ptr;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -47,6 +50,7 @@ namespace MWRender
|
|||
osg::ref_ptr<osg::PositionAttitudeTransform> mWaterNode;
|
||||
osg::ref_ptr<osg::Geode> mWaterGeode;
|
||||
Resource::ResourceSystem* mResourceSystem;
|
||||
const MWWorld::Fallback* mFallback;
|
||||
osg::ref_ptr<osgUtil::IncrementalCompileOperation> mIncrementalCompileOperation;
|
||||
|
||||
std::auto_ptr<RippleSimulation> mSimulation;
|
||||
|
@ -63,7 +67,7 @@ namespace MWRender
|
|||
osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY);
|
||||
void updateVisible();
|
||||
|
||||
void createSimpleWaterStateSet(osg::Node* node);
|
||||
void createSimpleWaterStateSet(osg::Node* node, float alpha);
|
||||
|
||||
/// @param reflection the reflection camera (required)
|
||||
/// @param refraction the refraction camera (optional)
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace
|
|||
|
||||
void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level)
|
||||
{
|
||||
for (std::vector<ESM::LevelledListBase::LevelItem>::iterator it = list->mList.begin(); it != list->mList.end();)
|
||||
for (std::vector<ESM::LevelledListBase::LevelItem>::iterator it = list->mList.begin(); it != list->mList.end(); ++it)
|
||||
{
|
||||
if (it->mLevel == level && itemId == it->mId)
|
||||
return;
|
||||
|
|
|
@ -68,12 +68,7 @@ namespace MWWorld
|
|||
const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName,
|
||||
const osg::Vec3f& fallbackDirection)
|
||||
{
|
||||
float height = 0;
|
||||
|
||||
height += mPhysics->getHalfExtents(caster).z() * 2.f * 0.75f; // Spawn at 0.75 * ActorHeight
|
||||
|
||||
osg::Vec3f pos(caster.getRefData().getPosition().asVec3());
|
||||
pos.z() += height;
|
||||
osg::Vec3f pos = mPhysics->getPosition(caster) + osg::Vec3f(0,0,mPhysics->getHalfExtents(caster).z() * 0.5); // Spawn at 0.75 * ActorHeight
|
||||
|
||||
if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible
|
||||
return;
|
||||
|
|
|
@ -781,6 +781,9 @@ namespace MWWorld
|
|||
|
||||
if (reference.getRefData().isEnabled())
|
||||
{
|
||||
if (reference == getPlayerPtr())
|
||||
throw std::runtime_error("can not disable player object");
|
||||
|
||||
reference.getRefData().disable();
|
||||
|
||||
if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount())
|
||||
|
@ -3256,8 +3259,7 @@ namespace MWWorld
|
|||
osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target)
|
||||
{
|
||||
osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering);
|
||||
osg::Vec3f targetPos = target.getRefData().getPosition().asVec3();
|
||||
targetPos.z() += mPhysics->getHalfExtents(target).z();
|
||||
osg::Vec3f targetPos = mPhysics->getPosition(target);
|
||||
return (targetPos - weaponPos);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -280,37 +280,40 @@ namespace SceneUtil
|
|||
// - cull list of lights by the camera frustum
|
||||
// - organize lights in a quad tree
|
||||
|
||||
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
|
||||
const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix();
|
||||
|
||||
const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix);
|
||||
|
||||
if (lights.size())
|
||||
// update light list if necessary
|
||||
// makes sure we don't update it more than once per frame when rendering with multiple cameras
|
||||
if (mLastFrameNumber != nv->getFrameStamp()->getFrameNumber())
|
||||
{
|
||||
mLastFrameNumber = nv->getFrameStamp()->getFrameNumber();
|
||||
|
||||
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
|
||||
const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix();
|
||||
const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix);
|
||||
|
||||
// we do the intersections in view space
|
||||
osg::BoundingSphere nodeBound = node->getBound();
|
||||
osg::Matrixf mat = *cv->getModelViewMatrix();
|
||||
transformBoundingSphere(mat, nodeBound);
|
||||
|
||||
LightManager::LightList lightList;
|
||||
mLightList.clear();
|
||||
for (unsigned int i=0; i<lights.size(); ++i)
|
||||
{
|
||||
const LightManager::LightSourceViewBound& l = lights[i];
|
||||
if (l.mViewBound.intersects(nodeBound))
|
||||
lightList.push_back(&l);
|
||||
mLightList.push_back(&l);
|
||||
}
|
||||
|
||||
if (lightList.empty())
|
||||
{
|
||||
traverse(node, nv);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
if (mLightList.size())
|
||||
{
|
||||
unsigned int maxLights = static_cast<unsigned int> (8 - mLightManager->getStartLight());
|
||||
|
||||
if (lightList.size() > maxLights)
|
||||
osg::StateSet* stateset = NULL;
|
||||
|
||||
if (mLightList.size() > maxLights)
|
||||
{
|
||||
// remove lights culled by this camera
|
||||
LightManager::LightList lightList = mLightList;
|
||||
for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights; )
|
||||
{
|
||||
osg::CullStack::CullingStack& stack = cv->getModelViewCullingStack();
|
||||
|
@ -334,9 +337,11 @@ namespace SceneUtil
|
|||
while (lightList.size() > maxLights)
|
||||
lightList.pop_back();
|
||||
}
|
||||
stateset = mLightManager->getLightListStateSet(lightList);
|
||||
}
|
||||
else
|
||||
stateset = mLightManager->getLightListStateSet(mLightList);
|
||||
|
||||
osg::StateSet* stateset = mLightManager->getLightListStateSet(lightList);
|
||||
|
||||
cv->pushStateSet(stateset);
|
||||
|
||||
|
|
|
@ -113,14 +113,18 @@ namespace SceneUtil
|
|||
int mStartLight;
|
||||
};
|
||||
|
||||
/// @note Not thread safe for CullThreadPerCamera threading mode.
|
||||
class LightListCallback : public osg::NodeCallback
|
||||
{
|
||||
public:
|
||||
LightListCallback()
|
||||
: mLightManager(NULL)
|
||||
, mLastFrameNumber(0)
|
||||
{}
|
||||
LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY)
|
||||
: osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager)
|
||||
: osg::Object(copy, copyop), osg::NodeCallback(copy, copyop)
|
||||
, mLightManager(copy.mLightManager)
|
||||
, mLastFrameNumber(0)
|
||||
{}
|
||||
|
||||
META_Object(NifOsg, LightListCallback)
|
||||
|
@ -129,6 +133,8 @@ namespace SceneUtil
|
|||
|
||||
private:
|
||||
LightManager* mLightManager;
|
||||
unsigned int mLastFrameNumber;
|
||||
LightManager::LightList mLightList;
|
||||
};
|
||||
|
||||
/// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings.
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace SceneUtil
|
|||
/// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame.
|
||||
/// After a frame is completed the places are swapped.
|
||||
/// @par Must be set as UpdateCallback on a Node.
|
||||
/// @note Do not add the same StateSetUpdater to multiple nodes.
|
||||
/// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetUpdater.
|
||||
class StateSetUpdater : public osg::NodeCallback
|
||||
{
|
||||
|
|
32
components/sceneutil/visitor.cpp
Normal file
32
components/sceneutil/visitor.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include "visitor.hpp"
|
||||
|
||||
#include <osg/Geode>
|
||||
|
||||
#include <osgParticle/ParticleSystem>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
|
||||
void FindByNameVisitor::apply(osg::Group &group)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind))
|
||||
{
|
||||
mFoundNode = &group;
|
||||
return;
|
||||
}
|
||||
traverse(group);
|
||||
}
|
||||
|
||||
void DisableFreezeOnCullVisitor::apply(osg::Geode &geode)
|
||||
{
|
||||
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
|
||||
{
|
||||
osg::Drawable* drw = geode.getDrawable(i);
|
||||
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(drw))
|
||||
partsys->setFreezeOnCull(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
#include <osg/NodeVisitor>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
// Commonly used scene graph visitors
|
||||
namespace SceneUtil
|
||||
{
|
||||
|
||||
// Find a Group by name, case-insensitive
|
||||
// If not found, mFoundNode will be NULL
|
||||
class FindByNameVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
|
@ -19,20 +19,24 @@ namespace SceneUtil
|
|||
{
|
||||
}
|
||||
|
||||
virtual void apply(osg::Group& group)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind))
|
||||
{
|
||||
mFoundNode = &group;
|
||||
return;
|
||||
}
|
||||
traverse(group);
|
||||
}
|
||||
virtual void apply(osg::Group& group);
|
||||
|
||||
std::string mNameToFind;
|
||||
osg::Group* mFoundNode;
|
||||
};
|
||||
|
||||
// Disable freezeOnCull for all visited particlesystems
|
||||
class DisableFreezeOnCullVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
DisableFreezeOnCullVisitor()
|
||||
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void apply(osg::Geode &geode);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue