Merge remote-tracking branch 'scrawl/master' into openmw-37

openmw-37
Marc Zinnschlag 9 years ago
commit 77b325a1db

2
.gitignore vendored

@ -5,7 +5,7 @@ CMakeCache.txt
cmake_install.cmake cmake_install.cmake
Makefile Makefile
makefile makefile
build build*
prebuilt prebuilt
## doxygen ## doxygen

@ -1479,6 +1479,8 @@ bool CharacterController::updateWeaponState()
} }
} }
mAnimation->setAccurateAiming(mUpperBodyState > UpperCharState_WeapEquiped);
return forcestateupdate; return forcestateupdate;
} }

@ -11,8 +11,8 @@
namespace MWMechanics namespace MWMechanics
{ {
// NOTE: determined empirically but probably need further tweaking // NOTE: determined empirically but probably need further tweaking
static const float DIST_SAME_SPOT = 1.8f; static const float DIST_SAME_SPOT = 0.5f;
static const float DURATION_SAME_SPOT = 1.0f; static const float DURATION_SAME_SPOT = 1.5f;
static const float DURATION_TO_EVADE = 0.4f; static const float DURATION_TO_EVADE = 0.4f;
const float ObstacleCheck::evadeDirections[NUM_EVADE_DIRECTIONS][2] = const float ObstacleCheck::evadeDirections[NUM_EVADE_DIRECTIONS][2] =
@ -114,20 +114,23 @@ namespace MWMechanics
* t = how long before considered stuck * t = how long before considered stuck
* u = how long to move sideways * u = how long to move sideways
* *
* DIST_SAME_SPOT is calibrated for movement speed of around 150.
* A rat has walking speed of around 30, so we need to adjust for
* that.
*/ */
bool ObstacleCheck::check(const MWWorld::Ptr& actor, float duration) bool ObstacleCheck::check(const MWWorld::Ptr& actor, float duration)
{ {
const MWWorld::Class& cls = actor.getClass(); const MWWorld::Class& cls = actor.getClass();
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
// actors can move at most 60 fps (the physics framerate).
// the max() can be removed if we implement physics interpolation.
float movementDuration = std::max(1/60.f, duration);
if(mDistSameSpot == -1) if(mDistSameSpot == -1)
mDistSameSpot = DIST_SAME_SPOT * (cls.getSpeed(actor) / 150); mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor);
float distSameSpot = mDistSameSpot * movementDuration;
bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < distSameSpot * distSameSpot;
bool samePosition = (std::abs(pos.pos[0] - mPrevX) < mDistSameSpot) &&
(std::abs(pos.pos[1] - mPrevY) < mDistSameSpot);
// update position // update position
mPrevX = pos.pos[0]; mPrevX = pos.pos[0];
mPrevY = pos.pos[1]; mPrevY = pos.pos[1];
@ -160,13 +163,13 @@ namespace MWMechanics
{ {
mStuckDuration = 0; mStuckDuration = 0;
mWalkState = State_Evade; mWalkState = State_Evade;
chooseEvasionDirection();
} }
} }
} }
/* FALL THROUGH */ /* FALL THROUGH */
case State_Evade: case State_Evade:
{ {
chooseEvasionDirection(samePosition);
mEvadeDuration += duration; mEvadeDuration += duration;
if(mEvadeDuration < DURATION_TO_EVADE) if(mEvadeDuration < DURATION_TO_EVADE)
return true; return true;
@ -188,16 +191,13 @@ namespace MWMechanics
actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1]; actorMovement.mPosition[1] = evadeDirections[mEvadeDirectionIndex][1];
} }
void ObstacleCheck::chooseEvasionDirection(bool samePosition) void ObstacleCheck::chooseEvasionDirection()
{ {
// change direction if attempt didn't work // change direction if attempt didn't work
if (samePosition && (0 < mEvadeDuration)) ++mEvadeDirectionIndex;
if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS)
{ {
++mEvadeDirectionIndex; mEvadeDirectionIndex = 0;
if (mEvadeDirectionIndex == NUM_EVADE_DIRECTIONS)
{
mEvadeDirectionIndex = 0;
}
} }
} }

@ -65,7 +65,7 @@ namespace MWMechanics
float mDistSameSpot; // take account of actor's speed float mDistSameSpot; // take account of actor's speed
int mEvadeDirectionIndex; int mEvadeDirectionIndex;
void chooseEvasionDirection(bool samePosition); void chooseEvasionDirection();
}; };
} }

@ -11,6 +11,7 @@
#include <osg/Geode> #include <osg/Geode>
#include <osg/BlendFunc> #include <osg/BlendFunc>
#include <osg/Material> #include <osg/Material>
#include <osg/Version>
#include <osgParticle/ParticleSystem> #include <osgParticle/ParticleSystem>
@ -174,72 +175,93 @@ namespace
return 0.0f; return 0.0f;
} }
/// @brief Base class for visitors that remove nodes from a scene graph.
/// Subclasses need to fill the mToRemove vector.
/// To use, node->accept(removeVisitor); removeVisitor.remove();
class RemoveVisitor : public osg::NodeVisitor
{
public:
RemoveVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{
}
void remove()
{
for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it)
it->second->removeChild(it->first);
}
protected:
// <node to remove, parent node to remove it from>
typedef std::vector<std::pair<osg::Node*, osg::Group*> > RemoveVec;
std::vector<std::pair<osg::Node*, osg::Group*> > mToRemove;
};
// Removes all drawables from a graph. // Removes all drawables from a graph.
class RemoveDrawableVisitor : public osg::NodeVisitor class RemoveDrawableVisitor : public RemoveVisitor
{ {
public: public:
RemoveDrawableVisitor() virtual void apply(osg::Geode &geode)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{ {
applyImpl(geode);
} }
virtual void apply(osg::Geode &node) #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
virtual void apply(osg::Drawable& drw)
{ {
// Not safe to remove in apply(), since the visitor is still iterating the child list applyImpl(drw);
osg::Group* parent = node.getParent(0);
// prune nodes that would be empty after the removal
if (parent->getNumChildren() == 1 && parent->getDataVariance() == osg::Object::STATIC)
mToRemove.push_back(parent);
else
mToRemove.push_back(&node);
traverse(node);
} }
#endif
void remove() void applyImpl(osg::Node& node)
{ {
for (std::vector<osg::Node*>::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) osg::NodePath::iterator parent = getNodePath().end()-2;
// We know that the parent is a Group because only Groups can have children.
osg::Group* parentGroup = static_cast<osg::Group*>(*parent);
// Try to prune nodes that would be empty after the removal
if (parent != getNodePath().begin())
{ {
osg::Node* node = *it; // This could be extended to remove the parent's parent, and so on if they are empty as well.
if (node->getNumParents()) // But for NIF files, there won't be a benefit since only TriShapes can be set to STATIC dataVariance.
node->getParent(0)->removeChild(node); osg::Group* parentParent = static_cast<osg::Group*>(*(parent - 1));
if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC)
{
mToRemove.push_back(std::make_pair(parentGroup, parentParent));
return;
}
} }
}
private: mToRemove.push_back(std::make_pair(&node, parentGroup));
std::vector<osg::Node*> mToRemove; }
}; };
class RemoveTriBipVisitor : public osg::NodeVisitor class RemoveTriBipVisitor : public RemoveVisitor
{ {
public: public:
RemoveTriBipVisitor() virtual void apply(osg::Geode &node)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{ {
applyImpl(node);
} }
virtual void apply(osg::Geode &node) #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
virtual void apply(osg::Drawable& drw)
{ {
const std::string toFind = "tri bip"; applyImpl(drw);
if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0)
{
// Not safe to remove in apply(), since the visitor is still iterating the child list
mToRemove.push_back(&node);
}
} }
#endif
void remove() void applyImpl(osg::Node& node)
{ {
for (std::vector<osg::Node*>::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) const std::string toFind = "tri bip";
if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0)
{ {
osg::Node* node = *it; osg::Group* parent = static_cast<osg::Group*>(*(getNodePath().end()-2));
if (node->getNumParents()) // Not safe to remove in apply(), since the visitor is still iterating the child list
node->getParent(0)->removeChild(node); mToRemove.push_back(std::make_pair(&node, parent));
} }
} }
private:
std::vector<osg::Node*> mToRemove;
}; };
} }
@ -1066,6 +1088,7 @@ namespace MWRender
osg::ref_ptr<SceneUtil::LightSource> lightSource = new SceneUtil::LightSource; osg::ref_ptr<SceneUtil::LightSource> lightSource = new SceneUtil::LightSource;
osg::Light* light = new osg::Light; osg::Light* light = new osg::Light;
lightSource->setLight(light); lightSource->setLight(light);
lightSource->setNodeMask(Mask_Lighting);
const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback(); const MWWorld::Fallback* fallback = MWBase::Environment::get().getWorld()->getFallback();
@ -1294,6 +1317,7 @@ namespace MWRender
{ {
mGlowLight = new SceneUtil::LightSource; mGlowLight = new SceneUtil::LightSource;
mGlowLight->setLight(new osg::Light); mGlowLight->setLight(new osg::Light);
mGlowLight->setNodeMask(Mask_Lighting);
osg::Light* light = mGlowLight->getLight(); osg::Light* light = mGlowLight->getLight();
light->setDiffuse(osg::Vec4f(0,0,0,0)); light->setDiffuse(osg::Vec4f(0,0,0,0));
light->setSpecular(osg::Vec4f(0,0,0,0)); light->setSpecular(osg::Vec4f(0,0,0,0));

@ -61,6 +61,9 @@ public:
private: private:
osg::ref_ptr<osg::Node> mNode; osg::ref_ptr<osg::Node> mNode;
void operator= (const PartHolder&);
PartHolder(const PartHolder&);
}; };
typedef boost::shared_ptr<PartHolder> PartHolderPtr; typedef boost::shared_ptr<PartHolder> PartHolderPtr;
@ -439,6 +442,7 @@ public:
virtual void setHeadYaw(float yawRadians); virtual void setHeadYaw(float yawRadians);
virtual float getHeadPitch() const; virtual float getHeadPitch() const;
virtual float getHeadYaw() const; virtual float getHeadYaw() const;
virtual void setAccurateAiming(bool enabled) {}
private: private:
Animation(const Animation&); Animation(const Animation&);

@ -42,7 +42,8 @@ namespace MWRender
{ {
Camera::Camera (osg::Camera* camera) Camera::Camera (osg::Camera* camera)
: mCamera(camera), : mHeightScale(1.f),
mCamera(camera),
mAnimation(NULL), mAnimation(NULL),
mFirstPersonView(true), mFirstPersonView(true),
mPreviewMode(false), mPreviewMode(false),
@ -93,7 +94,7 @@ namespace MWRender
osg::Vec3d position = worldMat.getTrans(); osg::Vec3d position = worldMat.getTrans();
if (!isFirstPerson()) if (!isFirstPerson())
position.z() += mHeight; position.z() += mHeight * mHeightScale;
return position; return position;
} }
@ -372,11 +373,17 @@ namespace MWRender
mTrackingNode = mAnimation->getNode("Camera"); mTrackingNode = mAnimation->getNode("Camera");
if (!mTrackingNode) if (!mTrackingNode)
mTrackingNode = mAnimation->getNode("Head"); mTrackingNode = mAnimation->getNode("Head");
mHeightScale = 1.f;
} }
else else
{ {
mAnimation->setViewMode(NpcAnimation::VM_Normal); mAnimation->setViewMode(NpcAnimation::VM_Normal);
mTrackingNode = mTrackingPtr.getRefData().getBaseNode(); osg::PositionAttitudeTransform* transform = mTrackingPtr.getRefData().getBaseNode();
mTrackingNode = transform;
if (transform)
mHeightScale = transform->getScale().z();
else
mHeightScale = 1.f;
} }
rotateCamera(getPitch(), getYaw(), false); rotateCamera(getPitch(), getYaw(), false);
} }

@ -29,6 +29,7 @@ namespace MWRender
MWWorld::Ptr mTrackingPtr; MWWorld::Ptr mTrackingPtr;
osg::ref_ptr<const osg::Node> mTrackingNode; osg::ref_ptr<const osg::Node> mTrackingNode;
float mHeightScale;
osg::ref_ptr<osg::Camera> mCamera; osg::ref_ptr<osg::Camera> mCamera;

@ -157,11 +157,10 @@ namespace MWRender
void CharacterPreview::rebuild() void CharacterPreview::rebuild()
{ {
delete mAnimation; mAnimation.reset(NULL);
mAnimation = NULL;
mAnimation = new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true, mAnimation.reset(new NpcAnimation(mCharacter, mNode, mResourceSystem, true, true,
(renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)));
onSetup(); onSetup();
@ -194,7 +193,7 @@ namespace MWRender
void InventoryPreview::update() void InventoryPreview::update()
{ {
if (!mAnimation) if (!mAnimation.get())
return; return;
mAnimation->showWeapons(true); mAnimation->showWeapons(true);

@ -2,6 +2,7 @@
#define MWRENDER_CHARACTERPREVIEW_H #define MWRENDER_CHARACTERPREVIEW_H
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <memory>
#include <components/esm/loadnpc.hpp> #include <components/esm/loadnpc.hpp>
@ -61,7 +62,7 @@ namespace MWRender
MWWorld::Ptr mCharacter; MWWorld::Ptr mCharacter;
MWRender::NpcAnimation* mAnimation; std::auto_ptr<MWRender::NpcAnimation> mAnimation;
osg::ref_ptr<osg::PositionAttitudeTransform> mNode; osg::ref_ptr<osg::PositionAttitudeTransform> mNode;
std::string mCurrentAnimGroup; std::string mCurrentAnimGroup;

@ -62,9 +62,8 @@ namespace
class CameraUpdateGlobalCallback : public osg::NodeCallback class CameraUpdateGlobalCallback : public osg::NodeCallback
{ {
public: public:
CameraUpdateGlobalCallback(osg::Camera* cam, MWRender::GlobalMap* parent) CameraUpdateGlobalCallback(MWRender::GlobalMap* parent)
: mRendered(false) : mRendered(false)
, mCamera(cam)
, mParent(parent) , mParent(parent)
{ {
} }
@ -73,7 +72,7 @@ namespace
{ {
if (mRendered) if (mRendered)
{ {
mCamera->setNodeMask(0); node->setNodeMask(0);
return; return;
} }
@ -82,13 +81,12 @@ namespace
if (!mRendered) if (!mRendered)
{ {
mRendered = true; mRendered = true;
mParent->markForRemoval(mCamera); mParent->markForRemoval(static_cast<osg::Camera*>(node));
} }
} }
private: private:
bool mRendered; bool mRendered;
osg::ref_ptr<osg::Camera> mCamera;
MWRender::GlobalMap* mParent; MWRender::GlobalMap* mParent;
}; };
@ -263,11 +261,14 @@ namespace MWRender
else else
camera->setClearMask(GL_NONE); camera->setClearMask(GL_NONE);
camera->setUpdateCallback(new CameraUpdateGlobalCallback(camera, this)); camera->setUpdateCallback(new CameraUpdateGlobalCallback(this));
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT);
camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture); camera->attach(osg::Camera::COLOR_BUFFER, mOverlayTexture);
// no need for a depth buffer
camera->setImplicitBufferAttachmentMask(osg::DisplaySettings::IMPLICIT_COLOR_BUFFER_ATTACHMENT);
if (cpuCopy) if (cpuCopy)
{ {
// Attach an image to copy the render back to the CPU when finished // Attach an image to copy the render back to the CPU when finished
@ -288,10 +289,12 @@ namespace MWRender
{ {
osg::ref_ptr<osg::Geometry> geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom); osg::ref_ptr<osg::Geometry> geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom);
osg::ref_ptr<osg::Depth> depth = new osg::Depth; osg::ref_ptr<osg::Depth> depth = new osg::Depth;
depth->setFunction(osg::Depth::ALWAYS); depth->setWriteMask(0);
geom->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); osg::StateSet* stateset = geom->getOrCreateStateSet();
geom->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); stateset->setAttribute(depth);
geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
osg::ref_ptr<osg::Geode> geode = new osg::Geode; osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(geom); geode->addDrawable(geom);
camera->addChild(geode); camera->addChild(geode);

@ -30,22 +30,21 @@ namespace
class CameraLocalUpdateCallback : public osg::NodeCallback class CameraLocalUpdateCallback : public osg::NodeCallback
{ {
public: public:
CameraLocalUpdateCallback(osg::Camera* cam, MWRender::LocalMap* parent) CameraLocalUpdateCallback(MWRender::LocalMap* parent)
: mRendered(false) : mRendered(false)
, mCamera(cam)
, mParent(parent) , mParent(parent)
{ {
} }
virtual void operator()(osg::Node*, osg::NodeVisitor*) virtual void operator()(osg::Node* node, osg::NodeVisitor*)
{ {
if (mRendered) if (mRendered)
mCamera->setNodeMask(0); node->setNodeMask(0);
if (!mRendered) if (!mRendered)
{ {
mRendered = true; mRendered = true;
mParent->markForRemoval(mCamera); mParent->markForRemoval(static_cast<osg::Camera*>(node));
} }
// Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's, // Note, we intentionally do not traverse children here. The map camera's scene data is the same as the master camera's,
@ -55,7 +54,6 @@ namespace
private: private:
bool mRendered; bool mRendered;
osg::ref_ptr<osg::Camera> mCamera;
MWRender::LocalMap* mParent; MWRender::LocalMap* mParent;
}; };
@ -205,7 +203,7 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
camera->setStateSet(stateset); camera->setStateSet(stateset);
camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext()); camera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext());
camera->setViewport(0, 0, mMapResolution, mMapResolution); camera->setViewport(0, 0, mMapResolution, mMapResolution);
camera->setUpdateCallback(new CameraLocalUpdateCallback(camera, this)); camera->setUpdateCallback(new CameraLocalUpdateCallback(this));
return camera; return camera;
} }

@ -281,7 +281,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> par
mShowWeapons(false), mShowWeapons(false),
mShowCarriedLeft(true), mShowCarriedLeft(true),
mNpcType(Type_Normal), mNpcType(Type_Normal),
mSoundsDisabled(disableSounds) mSoundsDisabled(disableSounds),
mAccurateAiming(false),
mAimingFactor(0.f)
{ {
mNpc = mPtr.get<ESM::NPC>()->mBase; mNpc = mPtr.get<ESM::NPC>()->mBase;
@ -726,7 +728,14 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed)
if (mFirstPersonNeckController) if (mFirstPersonNeckController)
{ {
mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0], osg::Vec3f(-1,0,0))); if (mAccurateAiming)
mAimingFactor = 1.f;
else
mAimingFactor = std::max(0.f, mAimingFactor - timepassed * 0.5f);
float rotateFactor = 0.75f + 0.25f * mAimingFactor;
mFirstPersonNeckController->setRotate(osg::Quat(mPtr.getRefData().getPosition().rot[0] * rotateFactor, osg::Vec3f(-1,0,0)));
mFirstPersonNeckController->setOffset(mFirstPersonOffset); mFirstPersonNeckController->setOffset(mFirstPersonOffset);
} }
@ -1072,4 +1081,9 @@ void NpcAnimation::updatePtr(const MWWorld::Ptr &updated)
mHeadAnimationTime->updatePtr(updated); mHeadAnimationTime->updatePtr(updated);
} }
void NpcAnimation::setAccurateAiming(bool enabled)
{
mAccurateAiming = enabled;
}
} }

@ -67,6 +67,9 @@ private:
bool mSoundsDisabled; bool mSoundsDisabled;
bool mAccurateAiming;
float mAimingFactor;
void updateNpcBase(); void updateNpcBase();
PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename,
@ -104,6 +107,10 @@ public:
virtual void enableHeadAnimation(bool enable); virtual void enableHeadAnimation(bool enable);
/// 1: the first person meshes follow the camera's rotation completely
/// 0: the first person meshes follow the camera with a reduced factor, so you can look down at your own hands
virtual void setAccurateAiming(bool enabled);
virtual void setWeaponGroup(const std::string& group); virtual void setWeaponGroup(const std::string& group);
virtual osg::Vec3f runAnimation(float timepassed); virtual osg::Vec3f runAnimation(float timepassed);

@ -6,6 +6,7 @@
#include <osg/Geode> #include <osg/Geode>
#include <osg/PositionAttitudeTransform> #include <osg/PositionAttitudeTransform>
#include <osg/UserDataContainer> #include <osg/UserDataContainer>
#include <osg/Version>
#include <osgParticle/ParticleSystem> #include <osgParticle/ParticleSystem>
#include <osgParticle/ParticleProcessor> #include <osgParticle/ParticleProcessor>
@ -54,11 +55,19 @@ namespace
for (std::vector<osgParticle::ParticleSystem*>::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it) for (std::vector<osgParticle::ParticleSystem*>::iterator it = partsysVector.begin(); it != partsysVector.end(); ++it)
geode.removeDrawable(*it); geode.removeDrawable(*it);
} }
#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
virtual void apply(osg::Drawable& drw)
{
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw))
mToRemove.push_back(partsys);
}
#endif
void remove() void remove()
{ {
for (std::vector<osg::ref_ptr<osg::Node> >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) for (std::vector<osg::ref_ptr<osg::Node> >::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it)
{ {
// FIXME: a Drawable might have more than one parent
osg::Node* node = *it; osg::Node* node = *it;
if (node->getNumParents()) if (node->getNumParents())
node->getParent(0)->removeChild(node); node->getParent(0)->removeChild(node);

@ -137,7 +137,10 @@ namespace MWRender
, mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog"))
, mNightEyeFactor(0.f) , mNightEyeFactor(0.f)
{ {
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
osg::ref_ptr<SceneUtil::LightManager> lightRoot = new SceneUtil::LightManager; osg::ref_ptr<SceneUtil::LightManager> lightRoot = new SceneUtil::LightManager;
lightRoot->setLightingMask(Mask_Lighting);
mLightRoot = lightRoot; mLightRoot = lightRoot;
lightRoot->setStartLight(1); lightRoot->setStartLight(1);
@ -163,7 +166,7 @@ namespace MWRender
mViewer->setLightingMode(osgViewer::View::NO_LIGHT); mViewer->setLightingMode(osgViewer::View::NO_LIGHT);
osg::ref_ptr<osg::LightSource> source = new osg::LightSource; osg::ref_ptr<osg::LightSource> source = new osg::LightSource;
source->setNodeMask(SceneUtil::Mask_Lit); source->setNodeMask(Mask_Lighting);
mSunLight = new osg::Light; mSunLight = new osg::Light;
source->setLight(mSunLight); source->setLight(mSunLight);
mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); mSunLight->setDiffuse(osg::Vec4f(0,0,0,1));
@ -439,6 +442,9 @@ namespace MWRender
void RenderingManager::scaleObject(const MWWorld::Ptr &ptr, const osg::Vec3f &scale) void RenderingManager::scaleObject(const MWWorld::Ptr &ptr, const osg::Vec3f &scale)
{ {
ptr.getRefData().getBaseNode()->setScale(scale); ptr.getRefData().getBaseNode()->setScale(scale);
if (ptr == mCamera->getTrackingPtr()) // update height of camera
mCamera->processViewChange();
} }
void RenderingManager::removeObject(const MWWorld::Ptr &ptr) void RenderingManager::removeObject(const MWWorld::Ptr &ptr)

@ -27,7 +27,7 @@ protected:
bool mEnabled; bool mEnabled;
osg::Quat mRotate; osg::Quat mRotate;
osg::ref_ptr<osg::Node> mRelativeTo; osg::Node* mRelativeTo;
}; };

@ -351,33 +351,36 @@ public:
for (unsigned int i=0; i<geode.getNumDrawables(); ++i) for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
{ {
osg::Drawable* drw = geode.getDrawable(i); osg::Drawable* drw = geode.getDrawable(i);
apply(*drw);
}
}
void apply(osg::Drawable& drw)
{
osg::Geometry* geom = drw.asGeometry();
if (!geom)
return;
osg::Geometry* geom = drw->asGeometry(); osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements());
if (!geom) for (unsigned int i=0; i<colors->size(); ++i)
continue; {
float alpha = 1.f;
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row
for (unsigned int i=0; i<colors->size(); ++i) else if (mMeshType == 1)
{ {
float alpha = 1.f; if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row
if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row else if (i>= 33 && i <= 48) alpha = 0.25098; // second row
else if (mMeshType == 1) else alpha = 1.f;
{ }
if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row else if (mMeshType == 2)
else if (i>= 33 && i <= 48) alpha = 0.25098; // second row {
else alpha = 1.f; osg::Vec4Array* origColors = static_cast<osg::Vec4Array*>(geom->getColorArray());
} alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f;
else if (mMeshType == 2)
{
osg::Vec4Array* origColors = static_cast<osg::Vec4Array*>(geom->getColorArray());
alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f;
}
(*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha);
} }
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); (*colors)[i] = osg::Vec4f(0.f, 0.f, 0.f, alpha);
} }
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
} }
private: private:
@ -1268,7 +1271,7 @@ public:
if (stateset->getAttribute(osg::StateAttribute::MATERIAL)) if (stateset->getAttribute(osg::StateAttribute::MATERIAL))
{ {
SceneUtil::CompositeStateSetUpdater* composite = NULL; SceneUtil::CompositeStateSetUpdater* composite = NULL;
#if OSG_MIN_VERSION_REQUIRED(3,3,3) #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
osg::Callback* callback = node.getUpdateCallback(); osg::Callback* callback = node.getUpdateCallback();
#else #else
osg::NodeCallback* callback = node.getUpdateCallback(); osg::NodeCallback* callback = node.getUpdateCallback();

@ -15,16 +15,16 @@ namespace MWRender
Mask_Actor = (1<<3), Mask_Actor = (1<<3),
Mask_Player = (1<<4), Mask_Player = (1<<4),
Mask_Sky = (1<<5), Mask_Sky = (1<<5),
Mask_Water = (1<<6), Mask_Water = (1<<6), // choose Water or SimpleWater depending on detail required
Mask_Terrain = (1<<7), Mask_SimpleWater = (1<<7),
Mask_FirstPerson = (1<<8), Mask_Terrain = (1<<8),
Mask_FirstPerson = (1<<9),
// child of Sky // child of Sky
Mask_Sun = (1<<9), Mask_Sun = (1<<10),
Mask_WeatherParticles = (1<<10), Mask_WeatherParticles = (1<<11),
// child of Water // child of Water
Mask_SimpleWater = (1<<11),
// top level masks // top level masks
Mask_Scene = (1<<12), Mask_Scene = (1<<12),
@ -34,9 +34,10 @@ namespace MWRender
Mask_ParticleSystem = (1<<14), Mask_ParticleSystem = (1<<14),
// Set on cameras within the main scene graph // Set on cameras within the main scene graph
Mask_RenderToTexture = (1<<15) Mask_RenderToTexture = (1<<15),
// reserved: (1<<16) for SceneUtil::Mask_Lit // Set on a camera's cull mask to enable the LightManager
Mask_Lighting = (1<<16)
}; };
} }

@ -302,7 +302,7 @@ public:
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
setReferenceFrame(osg::Camera::RELATIVE_RF); setReferenceFrame(osg::Camera::RELATIVE_RF);
setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|(1<<16)); setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting);
setNodeMask(Mask_RenderToTexture); setNodeMask(Mask_RenderToTexture);
setViewport(0, 0, rttSize, rttSize); setViewport(0, 0, rttSize, rttSize);
@ -378,7 +378,7 @@ public:
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
setReferenceFrame(osg::Camera::RELATIVE_RF); setReferenceFrame(osg::Camera::RELATIVE_RF);
setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|(1<<16)); setCullMask(Mask_Effect|Mask_Scene|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting);
setNodeMask(Mask_RenderToTexture); setNodeMask(Mask_RenderToTexture);
unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water");

@ -146,7 +146,7 @@ namespace NifOsg
{ {
public: public:
UVController(); UVController();
UVController(const UVController&,const osg::CopyOp& = osg::CopyOp::SHALLOW_COPY); UVController(const UVController&,const osg::CopyOp&);
UVController(const Nif::NiUVData *data, std::set<int> textureUnits); UVController(const Nif::NiUVData *data, std::set<int> textureUnits);
META_Object(NifOsg,UVController) META_Object(NifOsg,UVController)

@ -5,6 +5,7 @@
#include <osg/Geode> #include <osg/Geode>
#include <osg/Geometry> #include <osg/Geometry>
#include <osg/Array> #include <osg/Array>
#include <osg/Version>
// resource // resource
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
@ -536,7 +537,7 @@ namespace NifOsg
handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags);
if (!nifNode->controller.empty()) if (!nifNode->controller.empty())
handleMeshControllers(nifNode, composite, boundTextures, animflags); handleMeshControllers(nifNode, node, composite, boundTextures, animflags);
} }
if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles) if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles)
@ -570,7 +571,7 @@ namespace NifOsg
return node; return node;
} }
void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int> &boundTextures, int animflags) void handleMeshControllers(const Nif::Node *nifNode, osg::Node* node, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int> &boundTextures, int animflags)
{ {
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
{ {
@ -587,6 +588,14 @@ namespace NifOsg
setupController(uvctrl, ctrl, animflags); setupController(uvctrl, ctrl, animflags);
composite->addController(ctrl); composite->addController(ctrl);
} }
else if (ctrl->recType == Nif::RC_NiVisController)
{
handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), node, animflags);
}
else if(ctrl->recType == Nif::RC_NiGeomMorpherController)
{} // handled in handleTriShape
else
std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl;
} }
} }
@ -609,15 +618,20 @@ namespace NifOsg
} }
else if (ctrl->recType == Nif::RC_NiVisController) else if (ctrl->recType == Nif::RC_NiVisController)
{ {
const Nif::NiVisController* visctrl = static_cast<const Nif::NiVisController*>(ctrl.getPtr()); handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), transformNode, animflags);
osg::ref_ptr<VisController> callback(new VisController(visctrl->data.getPtr()));
setupController(visctrl, callback, animflags);
transformNode->addUpdateCallback(callback);
} }
else
std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl;
} }
} }
void handleVisController(const Nif::NiVisController* visctrl, osg::Node* node, int animflags)
{
osg::ref_ptr<VisController> callback(new VisController(visctrl->data.getPtr()));
setupController(visctrl, callback, animflags);
node->addUpdateCallback(callback);
}
void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags)
{ {
for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next)
@ -810,6 +824,8 @@ namespace NifOsg
continue; continue;
if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController)
partctrl = static_cast<Nif::NiParticleSystemController*>(ctrl.getPtr()); partctrl = static_cast<Nif::NiParticleSystemController*>(ctrl.getPtr());
else
std::cerr << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename << std::endl;
} }
if (!partctrl) if (!partctrl)
{ {
@ -870,9 +886,6 @@ namespace NifOsg
// localToWorldMatrix for transforming to particle space // localToWorldMatrix for transforming to particle space
handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf); handleParticlePrograms(partctrl->affectors, partctrl->colliders, parentNode, partsys.get(), rf);
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(partsys);
std::vector<const Nif::Property*> drawableProps; std::vector<const Nif::Property*> drawableProps;
collectDrawableProperties(nifNode, drawableProps); collectDrawableProperties(nifNode, drawableProps);
applyDrawableProperties(parentNode, drawableProps, composite, true, animflags); applyDrawableProperties(parentNode, drawableProps, composite, true, animflags);
@ -892,13 +905,21 @@ namespace NifOsg
updater->addParticleSystem(partsys); updater->addParticleSystem(partsys);
parentNode->addChild(updater); parentNode->addChild(updater);
#if OSG_VERSION_LESS_THAN(3,3,3)
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(partsys);
osg::Node* toAttach = geode.get();
#else
osg::Node* toAttach = partsys.get();
#endif
if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) if (rf == osgParticle::ParticleProcessor::RELATIVE_RF)
parentNode->addChild(geode); parentNode->addChild(toAttach);
else else
{ {
osg::MatrixTransform* trans = new osg::MatrixTransform; osg::MatrixTransform* trans = new osg::MatrixTransform;
trans->setUpdateCallback(new InverseWorldMatrix); trans->setUpdateCallback(new InverseWorldMatrix);
trans->addChild(geode); trans->addChild(toAttach);
parentNode->addChild(trans); parentNode->addChild(trans);
} }
} }
@ -943,44 +964,57 @@ namespace NifOsg
void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags) void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
{ {
osg::ref_ptr<osg::Geometry> geometry; osg::ref_ptr<osg::Geometry> geometry;
if(!triShape->controller.empty()) for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next)
{ {
Nif::ControllerPtr ctrl = triShape->controller; if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active))
do { continue;
if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) if(ctrl->recType == Nif::RC_NiGeomMorpherController)
{ {
geometry = handleMorphGeometry(static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())); geometry = handleMorphGeometry(static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr()));
osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController( osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController(
static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())->data.getPtr()); static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())->data.getPtr());
setupController(ctrl.getPtr(), morphctrl, animflags); setupController(ctrl.getPtr(), morphctrl, animflags);
geometry->setUpdateCallback(morphctrl); geometry->setUpdateCallback(morphctrl);
break; break;
} }
} while(!(ctrl=ctrl->next).empty());
} }
if (!geometry.get()) if (!geometry.get())
geometry = new osg::Geometry; geometry = new osg::Geometry;
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags);
#if OSG_VERSION_LESS_THAN(3,3,3)
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(geometry); geode->addDrawable(geometry);
#endif
if (geometry->getDataVariance() == osg::Object::DYNAMIC) if (geometry->getDataVariance() == osg::Object::DYNAMIC)
{ {
// Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch
// This is so we can set the DataVariance as STATIC, giving a huge performance boost // This is so we can set the DataVariance as STATIC, giving a huge performance boost
geometry->setDataVariance(osg::Object::STATIC); geometry->setDataVariance(osg::Object::STATIC);
osg::ref_ptr<osg::Geode> geode2 = static_cast<osg::Geode*>(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES));
osg::ref_ptr<FrameSwitch> frameswitch = new FrameSwitch; osg::ref_ptr<FrameSwitch> frameswitch = new FrameSwitch;
#if OSG_VERSION_LESS_THAN(3,3,3)
osg::ref_ptr<osg::Geode> geode2 = static_cast<osg::Geode*>(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES));
frameswitch->addChild(geode); frameswitch->addChild(geode);
frameswitch->addChild(geode2); frameswitch->addChild(geode2);
#else
osg::ref_ptr<osg::Geometry> geom2 = static_cast<osg::Geometry*>(osg::clone(geometry.get(), osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES));
frameswitch->addChild(geometry);
frameswitch->addChild(geom2);
#endif
parentNode->addChild(frameswitch); parentNode->addChild(frameswitch);
} }
else else
#if OSG_VERSION_LESS_THAN(3,3,3)
parentNode->addChild(geode); parentNode->addChild(geode);
#else
parentNode->addChild(geometry);
#endif
} }
osg::ref_ptr<osg::Geometry> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher) osg::ref_ptr<osg::Geometry> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher)
@ -1041,8 +1075,6 @@ namespace NifOsg
void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite,
const std::vector<int>& boundTextures, int animflags) const std::vector<int>& boundTextures, int animflags)
{ {
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry); osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags);
@ -1075,17 +1107,27 @@ namespace NifOsg
} }
rig->setInfluenceMap(map); rig->setInfluenceMap(map);
geode->addDrawable(rig);
// Add a copy, we will alternate between the two copies every other frame using the FrameSwitch // Add a copy, we will alternate between the two copies every other frame using the FrameSwitch
// This is so we can set the DataVariance as STATIC, giving a huge performance boost // This is so we can set the DataVariance as STATIC, giving a huge performance boost
rig->setDataVariance(osg::Object::STATIC); rig->setDataVariance(osg::Object::STATIC);
osg::ref_ptr<FrameSwitch> frameswitch = new FrameSwitch;
#if OSG_VERSION_LESS_THAN(3,3,3)
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(rig);
osg::Geode* geode2 = static_cast<osg::Geode*>(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES| osg::Geode* geode2 = static_cast<osg::Geode*>(osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES|
osg::CopyOp::DEEP_COPY_DRAWABLES)); osg::CopyOp::DEEP_COPY_DRAWABLES));
osg::ref_ptr<FrameSwitch> frameswitch = new FrameSwitch;
frameswitch->addChild(geode); frameswitch->addChild(geode);
frameswitch->addChild(geode2); frameswitch->addChild(geode2);
#else
SceneUtil::RigGeometry* rig2 = static_cast<SceneUtil::RigGeometry*>(osg::clone(rig.get(), osg::CopyOp::DEEP_COPY_NODES|
osg::CopyOp::DEEP_COPY_DRAWABLES));
frameswitch->addChild(rig);
frameswitch->addChild(rig2);
#endif
parentNode->addChild(frameswitch); parentNode->addChild(frameswitch);
} }
@ -1365,7 +1407,7 @@ namespace NifOsg
osg::StateSet* stateset = node->getOrCreateStateSet(); osg::StateSet* stateset = node->getOrCreateStateSet();
int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty
osg::Material* mat = new osg::Material; osg::ref_ptr<osg::Material> mat (new osg::Material);
mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF);
// NIF material defaults don't match OpenGL defaults // NIF material defaults don't match OpenGL defaults
@ -1420,12 +1462,11 @@ namespace NifOsg
case Nif::RC_NiAlphaProperty: case Nif::RC_NiAlphaProperty:
{ {
const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property); const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property);
osg::BlendFunc* blendfunc = new osg::BlendFunc;
if (alphaprop->flags&1) if (alphaprop->flags&1)
{ {
blendfunc->setFunction(getBlendMode((alphaprop->flags>>1)&0xf), stateset->setAttributeAndModes(new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf),
getBlendMode((alphaprop->flags>>5)&0xf)); getBlendMode((alphaprop->flags>>5)&0xf)),
stateset->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); osg::StateAttribute::ON);
bool noSort = (alphaprop->flags>>13)&1; bool noSort = (alphaprop->flags>>13)&1;
if (!noSort) if (!noSort)
@ -1440,11 +1481,10 @@ namespace NifOsg
stateset->setRenderBinToInherit(); stateset->setRenderBinToInherit();
} }
osg::AlphaFunc* alphafunc = new osg::AlphaFunc;
if((alphaprop->flags>>9)&1) if((alphaprop->flags>>9)&1)
{ {
alphafunc->setFunction(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f); stateset->setAttributeAndModes(new osg::AlphaFunc(getTestMode((alphaprop->flags>>10)&0x7),
stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON); alphaprop->data.threshold/255.f), osg::StateAttribute::ON);
} }
else else
{ {

@ -60,7 +60,7 @@ namespace NifOsg
InverseWorldMatrix() InverseWorldMatrix()
{ {
} }
InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY) InverseWorldMatrix(const InverseWorldMatrix& copy, const osg::CopyOp& op)
: osg::Object(), osg::NodeCallback() : osg::Object(), osg::NodeCallback()
{ {
} }
@ -139,9 +139,6 @@ namespace NifOsg
META_Object(NifOsg, ParticleColorAffector) META_Object(NifOsg, ParticleColorAffector)
// TODO: very similar to vec3 version, refactor to a template
osg::Vec4f interpolate(const float time, const Nif::Vector4KeyMap::MapType& keys);
virtual void operate(osgParticle::Particle* particle, double dt); virtual void operate(osgParticle::Particle* particle, double dt);
private: private:

@ -3,6 +3,7 @@
#include <osg/Node> #include <osg/Node>
#include <osg/Geode> #include <osg/Geode>
#include <osg/UserDataContainer> #include <osg/UserDataContainer>
#include <osg/Version>
#include <osgParticle/ParticleSystem> #include <osgParticle/ParticleSystem>
@ -25,35 +26,54 @@ namespace
class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor class InitWorldSpaceParticlesVisitor : public osg::NodeVisitor
{ {
public: public:
InitWorldSpaceParticlesVisitor() /// @param mask The node mask to set on ParticleSystem nodes.
InitWorldSpaceParticlesVisitor(unsigned int mask)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mMask(mask)
{ {
} }
void apply(osg::Node& node) bool isWorldSpaceParticleSystem(osgParticle::ParticleSystem* partsys)
{ {
if (osg::Geode* geode = node.asGeode()) // HACK: ParticleSystem has no getReferenceFrame()
return (partsys->getUserDataContainer()
&& partsys->getUserDataContainer()->getNumDescriptions() > 0
&& partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace");
}
void apply(osg::Geode& geode)
{
for (unsigned int i=0;i<geode.getNumDrawables();++i)
{ {
for (unsigned int i=0;i<geode->getNumDrawables();++i) if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(geode.getDrawable(i)))
{ {
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(geode->getDrawable(i))) if (isWorldSpaceParticleSystem(partsys))
{ {
// HACK: ParticleSystem has no getReferenceFrame() // HACK: Ignore the InverseWorldMatrix transform the geode is attached to
if (partsys->getUserDataContainer() if (geode.getNumParents() && geode.getParent(0)->getNumParents())
&& partsys->getUserDataContainer()->getNumDescriptions() > 0 transformInitialParticles(partsys, geode.getParent(0)->getParent(0));
&& partsys->getUserDataContainer()->getDescriptions()[0] == "worldspace")
{
// HACK: Ignore the InverseWorldMatrix transform the geode is attached to
if (geode->getNumParents() && geode->getParent(0)->getNumParents())
transformInitialParticles(partsys, geode->getParent(0)->getParent(0));
}
geode->setNodeMask((1<<10)); //MWRender::Mask_ParticleSystem
} }
geode.setNodeMask(mMask);
} }
} }
}
traverse(node); #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
// in OSG 3.3 and up Drawables can be directly in the scene graph without a Geode decorating them.
void apply(osg::Drawable& drw)
{
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw))
{
if (isWorldSpaceParticleSystem(partsys))
{
// HACK: Ignore the InverseWorldMatrix transform the particle system is attached to
if (partsys->getNumParents() && partsys->getParent(0)->getNumParents())
transformInitialParticles(partsys, partsys->getParent(0)->getParent(0));
}
partsys->setNodeMask(mMask);
}
} }
#endif
void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node) void transformInitialParticles(osgParticle::ParticleSystem* partsys, osg::Node* node)
{ {
@ -74,8 +94,9 @@ namespace
box.expandBy(sphere); box.expandBy(sphere);
partsys->setInitialBound(box); partsys->setInitialBound(box);
} }
private:
unsigned int mMask;
}; };
} }
namespace Resource namespace Resource
@ -84,6 +105,7 @@ namespace Resource
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager) SceneManager::SceneManager(const VFS::Manager *vfs, Resource::TextureManager* textureManager)
: mVFS(vfs) : mVFS(vfs)
, mTextureManager(textureManager) , mTextureManager(textureManager)
, mParticleSystemMask(~0u)
{ {
} }
@ -183,7 +205,7 @@ namespace Resource
void SceneManager::notifyAttached(osg::Node *node) const void SceneManager::notifyAttached(osg::Node *node) const
{ {
InitWorldSpaceParticlesVisitor visitor; InitWorldSpaceParticlesVisitor visitor (mParticleSystemMask);
node->accept(visitor); node->accept(visitor);
} }
@ -197,4 +219,9 @@ namespace Resource
return mTextureManager; return mTextureManager;
} }
void SceneManager::setParticleSystemMask(unsigned int mask)
{
mParticleSystemMask = mask;
}
} }

@ -73,12 +73,17 @@ namespace Resource
Resource::TextureManager* getTextureManager(); Resource::TextureManager* getTextureManager();
/// @param mask The node mask to apply to loaded particle system nodes.
void setParticleSystemMask(unsigned int mask);
private: private:
const VFS::Manager* mVFS; const VFS::Manager* mVFS;
Resource::TextureManager* mTextureManager; Resource::TextureManager* mTextureManager;
osg::ref_ptr<osgUtil::IncrementalCompileOperation> mIncrementalCompileOperation; osg::ref_ptr<osgUtil::IncrementalCompileOperation> mIncrementalCompileOperation;
unsigned int mParticleSystemMask;
// observer_ptr? // observer_ptr?
typedef std::map<std::string, osg::ref_ptr<const osg::Node> > Index; typedef std::map<std::string, osg::ref_ptr<const osg::Node> > Index;
Index mIndex; Index mIndex;

@ -119,7 +119,7 @@ namespace Resource
case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT): case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
{ {
#if OSG_MIN_VERSION_REQUIRED(3,3,3) #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); osg::GLExtensions* exts = osg::GLExtensions::Get(0, false);
if (exts && !exts->isTextureCompressionS3TCSupported if (exts && !exts->isTextureCompressionS3TCSupported
// This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG. // This one works too. Should it be included in isTextureCompressionS3TCSupported()? Submitted as a patch to OSG.

@ -65,7 +65,7 @@ namespace SceneUtil
void ControllerVisitor::apply(osg::Node &node) void ControllerVisitor::apply(osg::Node &node)
{ {
#if OSG_MIN_VERSION_REQUIRED(3,3,3) #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
osg::Callback* callback = node.getUpdateCallback(); osg::Callback* callback = node.getUpdateCallback();
#else #else
osg::NodeCallback* callback = node.getUpdateCallback(); osg::NodeCallback* callback = node.getUpdateCallback();
@ -96,7 +96,7 @@ namespace SceneUtil
{ {
osg::Drawable* drw = geode.getDrawable(i); osg::Drawable* drw = geode.getDrawable(i);
#if OSG_MIN_VERSION_REQUIRED(3,3,3) #if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
osg::Callback* callback = drw->getUpdateCallback(); osg::Callback* callback = drw->getUpdateCallback();
#else #else
osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback(); osg::Drawable::UpdateCallback* callback = drw->getUpdateCallback();

@ -131,6 +131,7 @@ namespace SceneUtil
LightManager::LightManager() LightManager::LightManager()
: mStartLight(0) : mStartLight(0)
, mLightingMask(~0u)
{ {
setUpdateCallback(new LightManagerUpdateCallback); setUpdateCallback(new LightManagerUpdateCallback);
} }
@ -138,10 +139,21 @@ namespace SceneUtil
LightManager::LightManager(const LightManager &copy, const osg::CopyOp &copyop) LightManager::LightManager(const LightManager &copy, const osg::CopyOp &copyop)
: osg::Group(copy, copyop) : osg::Group(copy, copyop)
, mStartLight(copy.mStartLight) , mStartLight(copy.mStartLight)
, mLightingMask(copy.mLightingMask)
{ {
} }
void LightManager::setLightingMask(unsigned int mask)
{
mLightingMask = mask;
}
unsigned int LightManager::getLightingMask() const
{
return mLightingMask;
}
void LightManager::update() void LightManager::update()
{ {
mLights.clear(); mLights.clear();
@ -237,7 +249,6 @@ namespace SceneUtil
LightSource::LightSource() LightSource::LightSource()
: mRadius(0.f) : mRadius(0.f)
{ {
setNodeMask(Mask_Lit);
setUpdateCallback(new CollectLightCallback); setUpdateCallback(new CollectLightCallback);
mId = sLightId++; mId = sLightId++;
} }
@ -260,12 +271,6 @@ namespace SceneUtil
{ {
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv); osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
if (!(cv->getCurrentCamera()->getCullMask()&Mask_Lit))
{
traverse(node, nv);
return;
}
if (!mLightManager) if (!mLightManager)
{ {
mLightManager = findLightManager(nv->getNodePath()); mLightManager = findLightManager(nv->getNodePath());
@ -276,6 +281,12 @@ namespace SceneUtil
} }
} }
if (!(cv->getCurrentCamera()->getCullMask() & mLightManager->getLightingMask()))
{
traverse(node, nv);
return;
}
// Possible optimizations: // Possible optimizations:
// - cull list of lights by the camera frustum // - cull list of lights by the camera frustum
// - organize lights in a quad tree // - organize lights in a quad tree

@ -9,9 +9,6 @@
namespace SceneUtil namespace SceneUtil
{ {
// This mask should be included in the Cull and Update visitor's traversal mask if lighting is desired.
const int Mask_Lit = (1<<16);
/// LightSource managed by a LightManager. /// LightSource managed by a LightManager.
class LightSource : public osg::Node class LightSource : public osg::Node
{ {
@ -68,6 +65,14 @@ namespace SceneUtil
LightManager(const LightManager& copy, const osg::CopyOp& copyop); LightManager(const LightManager& copy, const osg::CopyOp& copyop);
/// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired.
/// By default, it's ~0u i.e. always on.
/// If you have some views that do not require lighting, then set the Camera's cull mask to not include
/// the lightingMask for a much faster cull and rendering.
void setLightingMask (unsigned int mask);
unsigned int getLightingMask() const;
// Called automatically by the UpdateCallback // Called automatically by the UpdateCallback
void update(); void update();
@ -111,6 +116,8 @@ namespace SceneUtil
LightStateSetMap mStateSetCache; LightStateSetMap mStateSetCache;
int mStartLight; int mStartLight;
unsigned int mLightingMask;
}; };
/// @note Not thread safe for CullThreadPerCamera threading mode. /// @note Not thread safe for CullThreadPerCamera threading mode.
@ -121,7 +128,7 @@ namespace SceneUtil
: mLightManager(NULL) : mLightManager(NULL)
, mLastFrameNumber(0) , mLastFrameNumber(0)
{} {}
LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop)
: osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop)
, mLightManager(copy.mLightManager) , mLightManager(copy.mLightManager)
, mLastFrameNumber(0) , mLastFrameNumber(0)

@ -2,9 +2,9 @@
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
#include <osg/Version>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include "skeleton.hpp" #include "skeleton.hpp"
@ -58,6 +58,14 @@ public:
} }
}; };
// We can't compute the bounds without a NodeVisitor, since we need the current geomToSkelMatrix.
// So we return nothing. Bounds are updated every frame in the UpdateCallback.
class DummyComputeBoundCallback : public osg::Drawable::ComputeBoundingBoxCallback
{
public:
virtual osg::BoundingBox computeBound(const osg::Drawable&) const { return osg::BoundingBox(); }
};
RigGeometry::RigGeometry() RigGeometry::RigGeometry()
: mSkeleton(NULL) : mSkeleton(NULL)
, mLastFrameNumber(0) , mLastFrameNumber(0)
@ -66,6 +74,7 @@ RigGeometry::RigGeometry()
setCullCallback(new UpdateRigGeometry); setCullCallback(new UpdateRigGeometry);
setUpdateCallback(new UpdateRigBounds); setUpdateCallback(new UpdateRigBounds);
setSupportsDisplayList(false); setSupportsDisplayList(false);
setComputeBoundingBoxCallback(new DummyComputeBoundCallback);
} }
RigGeometry::RigGeometry(const RigGeometry &copy, const osg::CopyOp &copyop) RigGeometry::RigGeometry(const RigGeometry &copy, const osg::CopyOp &copyop)
@ -278,6 +287,12 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv)
} }
_boundingBox = box; _boundingBox = box;
_boundingBoxComputed = true;
#if OSG_VERSION_GREATER_OR_EQUAL(3,3,3)
// in OSG 3.3.3 and up Drawable inherits from Node, so has a bounding sphere as well.
_boundingSphere = osg::BoundingSphere(_boundingBox);
_boundingSphereComputed = true;
#endif
for (unsigned int i=0; i<getNumParents(); ++i) for (unsigned int i=0; i<getNumParents(); ++i)
getParent(i)->dirtyBound(); getParent(i)->dirtyBound();
} }

@ -22,11 +22,13 @@ namespace SceneUtil
void DisableFreezeOnCullVisitor::apply(osg::Geode &geode) void DisableFreezeOnCullVisitor::apply(osg::Geode &geode)
{ {
for (unsigned int i=0; i<geode.getNumDrawables(); ++i) for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
{ apply(*geode.getDrawable(i));
osg::Drawable* drw = geode.getDrawable(i); }
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(drw))
partsys->setFreezeOnCull(false); void DisableFreezeOnCullVisitor::apply(osg::Drawable& drw)
} {
if (osgParticle::ParticleSystem* partsys = dynamic_cast<osgParticle::ParticleSystem*>(&drw))
partsys->setFreezeOnCull(false);
} }
} }

@ -35,6 +35,7 @@ namespace SceneUtil
} }
virtual void apply(osg::Geode &geode); virtual void apply(osg::Geode &geode);
virtual void apply(osg::Drawable& drw);
}; };
} }

@ -2,7 +2,6 @@
#include <SDL_video.h> #include <SDL_video.h>
#include <osg/DeleteHandler>
#include <osg/Version> #include <osg/Version>
namespace SDLUtil namespace SDLUtil
@ -79,15 +78,13 @@ void GraphicsWindowSDL2::init()
if(!_traits.valid()) if(!_traits.valid())
return; return;
// getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get());
WindowData *inheritedWindowData = dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()); WindowData *inheritedWindowData = dynamic_cast<WindowData*>(_traits->inheritedWindowData.get());
mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL; mWindow = inheritedWindowData ? inheritedWindowData->mWindow : NULL;
mOwnsWindow = (mWindow == 0); mOwnsWindow = (mWindow == 0);
if(mOwnsWindow) if(mOwnsWindow)
{ {
OSG_NOTICE<<"Error: No SDL window provided."<<std::endl; OSG_FATAL<<"Error: No SDL window provided."<<std::endl;
return; return;
} }
@ -99,7 +96,7 @@ void GraphicsWindowSDL2::init()
mContext = SDL_GL_CreateContext(mWindow); mContext = SDL_GL_CreateContext(mWindow);
if(!mContext) if(!mContext)
{ {
OSG_NOTICE<< "Error: Unable to create OpenGL graphics context: "<<SDL_GetError() <<std::endl; OSG_FATAL<< "Error: Unable to create OpenGL graphics context: "<<SDL_GetError() <<std::endl;
return; return;
} }
@ -109,7 +106,7 @@ void GraphicsWindowSDL2::init()
mValid = true; mValid = true;
#if OSG_MIN_VERSION_REQUIRED(3,3,4) #if OSG_VERSION_GREATER_OR_EQUAL(3,3,4)
getEventQueue()->syncWindowRectangleWithGraphicsContext(); getEventQueue()->syncWindowRectangleWithGraphicsContext();
#else #else
getEventQueue()->syncWindowRectangleWithGraphcisContext(); getEventQueue()->syncWindowRectangleWithGraphcisContext();
@ -130,7 +127,7 @@ bool GraphicsWindowSDL2::realizeImplementation()
SDL_ShowWindow(mWindow); SDL_ShowWindow(mWindow);
#if OSG_MIN_VERSION_REQUIRED(3,3,4) #if OSG_VERSION_GREATER_OR_EQUAL(3,3,4)
getEventQueue()->syncWindowRectangleWithGraphicsContext(); getEventQueue()->syncWindowRectangleWithGraphicsContext();
#else #else
getEventQueue()->syncWindowRectangleWithGraphcisContext(); getEventQueue()->syncWindowRectangleWithGraphcisContext();
@ -145,7 +142,7 @@ bool GraphicsWindowSDL2::makeCurrentImplementation()
{ {
if(!mRealized) if(!mRealized)
{ {
OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl; OSG_WARN<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl;
return false; return false;
} }
@ -156,7 +153,7 @@ bool GraphicsWindowSDL2::releaseContextImplementation()
{ {
if(!mRealized) if(!mRealized)
{ {
OSG_NOTICE<< "Warning: GraphicsWindow not realized, cannot do releaseContext." <<std::endl; OSG_WARN<< "Warning: GraphicsWindow not realized, cannot do releaseContext." <<std::endl;
return false; return false;
} }
@ -166,8 +163,6 @@ bool GraphicsWindowSDL2::releaseContextImplementation()
void GraphicsWindowSDL2::closeImplementation() void GraphicsWindowSDL2::closeImplementation()
{ {
// OSG_NOTICE<<"Closing GraphicsWindowSDL2"<<std::endl;
if(mContext) if(mContext)
SDL_GL_DeleteContext(mContext); SDL_GL_DeleteContext(mContext);
mContext = NULL; mContext = NULL;
@ -184,8 +179,6 @@ void GraphicsWindowSDL2::swapBuffersImplementation()
{ {
if(!mRealized) return; if(!mRealized) return;
//OSG_NOTICE<< "swapBuffersImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
SDL_GL_SwapWindow(mWindow); SDL_GL_SwapWindow(mWindow);
} }

Loading…
Cancel
Save