mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-10-04 21:56:32 +00:00
Add OpenMW 0.47 commits up to 25 Jul 2021
This commit is contained in:
commit
0567dc1fd4
23 changed files with 261 additions and 90 deletions
|
@ -130,6 +130,7 @@
|
||||||
Bug #6036: OpenMW-CS: Terrain selection at the border of cells omits certain corner vertices
|
Bug #6036: OpenMW-CS: Terrain selection at the border of cells omits certain corner vertices
|
||||||
Bug #6043: Actor can have torch missing when torch animation is played
|
Bug #6043: Actor can have torch missing when torch animation is played
|
||||||
Bug #6047: Mouse bindings can be triggered during save loading
|
Bug #6047: Mouse bindings can be triggered during save loading
|
||||||
|
Bug #6136: Game freezes when NPCs try to open doors that are about to be closed
|
||||||
Feature #390: 3rd person look "over the shoulder"
|
Feature #390: 3rd person look "over the shoulder"
|
||||||
Feature #832: OpenMW-CS: Handle deleted references
|
Feature #832: OpenMW-CS: Handle deleted references
|
||||||
Feature #1536: Show more information about level on menu
|
Feature #1536: Show more information about level on menu
|
||||||
|
|
|
@ -500,8 +500,8 @@ else ()
|
||||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
pack_resource_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
||||||
"${OpenMW_BINARY_DIR}" "openmw-cs.cfg")
|
"${OpenMW_BINARY_DIR}" "defaults-cs.bin")
|
||||||
|
|
||||||
# Needs the copy version because the configure version assumes the end of the file has been reached when a null character is reached and there are no CMake expressions to evaluate.
|
# Needs the copy version because the configure version assumes the end of the file has been reached when a null character is reached and there are no CMake expressions to evaluate.
|
||||||
copy_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
|
copy_resource_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
|
||||||
|
@ -1039,7 +1039,7 @@ elseif(NOT APPLE)
|
||||||
# End of tes3mp addition
|
# End of tes3mp addition
|
||||||
|
|
||||||
IF(BUILD_OPENCS)
|
IF(BUILD_OPENCS)
|
||||||
INSTALL(FILES "${INSTALL_SOURCE}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
|
INSTALL(FILES "${INSTALL_SOURCE}/defaults-cs.bin" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
|
||||||
ENDIF(BUILD_OPENCS)
|
ENDIF(BUILD_OPENCS)
|
||||||
|
|
||||||
# Install resources
|
# Install resources
|
||||||
|
|
|
@ -158,7 +158,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns")
|
set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns")
|
||||||
set (OPENCS_CFG "${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
set (OPENCS_CFG "${OpenMW_BINARY_DIR}/defaults-cs.bin")
|
||||||
set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters")
|
set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters")
|
||||||
set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg")
|
set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||||
else()
|
else()
|
||||||
|
@ -270,7 +270,7 @@ if (WIN32)
|
||||||
SET(INSTALL_SOURCE "${OpenMW_BINARY_DIR}")
|
SET(INSTALL_SOURCE "${OpenMW_BINARY_DIR}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
INSTALL(FILES "${INSTALL_SOURCE}/openmw-cs.cfg" DESTINATION ".")
|
INSTALL(FILES "${INSTALL_SOURCE}/defaults-cs.bin" DESTINATION ".")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|
|
@ -17,15 +17,15 @@ CSMPrefs::State *CSMPrefs::State::sThis = nullptr;
|
||||||
void CSMPrefs::State::load()
|
void CSMPrefs::State::load()
|
||||||
{
|
{
|
||||||
// default settings file
|
// default settings file
|
||||||
boost::filesystem::path local = mConfigurationManager.getLocalPath() / mConfigFile;
|
boost::filesystem::path local = mConfigurationManager.getLocalPath() / mDefaultConfigFile;
|
||||||
boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mConfigFile;
|
boost::filesystem::path global = mConfigurationManager.getGlobalPath() / mDefaultConfigFile;
|
||||||
|
|
||||||
if (boost::filesystem::exists (local))
|
if (boost::filesystem::exists (local))
|
||||||
mSettings.loadDefault (local.string());
|
mSettings.loadDefault (local.string());
|
||||||
else if (boost::filesystem::exists (global))
|
else if (boost::filesystem::exists (global))
|
||||||
mSettings.loadDefault (global.string());
|
mSettings.loadDefault (global.string());
|
||||||
else
|
else
|
||||||
throw std::runtime_error ("No default settings file found! Make sure the file \"openmw-cs.cfg\" was properly installed.");
|
throw std::runtime_error ("No default settings file found! Make sure the file \"" + mDefaultConfigFile + "\" was properly installed.");
|
||||||
|
|
||||||
// user settings file
|
// user settings file
|
||||||
boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile;
|
boost::filesystem::path user = mConfigurationManager.getUserConfigPath() / mConfigFile;
|
||||||
|
@ -641,7 +641,7 @@ void CSMPrefs::State::setDefault (const std::string& key, const std::string& def
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager)
|
CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager)
|
||||||
: mConfigFile ("openmw-cs.cfg"), mConfigurationManager (configurationManager),
|
: mConfigFile ("openmw-cs.cfg"), mDefaultConfigFile("defaults-cs.bin"), mConfigurationManager (configurationManager),
|
||||||
mCurrentCategory (mCategories.end())
|
mCurrentCategory (mCategories.end())
|
||||||
{
|
{
|
||||||
if (sThis)
|
if (sThis)
|
||||||
|
|
|
@ -48,6 +48,7 @@ namespace CSMPrefs
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const std::string mConfigFile;
|
const std::string mConfigFile;
|
||||||
|
const std::string mDefaultConfigFile;
|
||||||
const Files::ConfigurationManager& mConfigurationManager;
|
const Files::ConfigurationManager& mConfigurationManager;
|
||||||
ShortcutManager mShortcutManager;
|
ShortcutManager mShortcutManager;
|
||||||
Settings::Manager mSettings;
|
Settings::Manager mSettings;
|
||||||
|
|
|
@ -55,6 +55,11 @@ MWWorld::Ptr MWMechanics::AiPackage::getTarget() const
|
||||||
|
|
||||||
if (mTargetActorId == -1)
|
if (mTargetActorId == -1)
|
||||||
{
|
{
|
||||||
|
if (mTargetActorRefId.empty())
|
||||||
|
{
|
||||||
|
mTargetActorId = -2;
|
||||||
|
return MWWorld::Ptr();
|
||||||
|
}
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mTargetActorRefId, false);
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mTargetActorRefId, false);
|
||||||
if (target.isEmpty())
|
if (target.isEmpty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,8 +32,8 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler)
|
Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler, bool canWaterWalk)
|
||||||
: mStandingOnPtr(nullptr), mCanWaterWalk(false), mWalkingOnWater(false)
|
: mStandingOnPtr(nullptr), mCanWaterWalk(canWaterWalk), mWalkingOnWater(false)
|
||||||
, mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBox.center), mHalfExtents(shape->mCollisionBox.extents)
|
, mCollisionObject(nullptr), mMeshTranslation(shape->mCollisionBox.center), mHalfExtents(shape->mCollisionBox.extents)
|
||||||
, mVelocity(0,0,0), mStuckFrames(0), mLastStuckPosition{0, 0, 0}
|
, mVelocity(0,0,0), mStuckFrames(0), mLastStuckPosition{0, 0, 0}
|
||||||
, mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false)
|
, mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false)
|
||||||
|
@ -159,11 +159,13 @@ void Actor::updatePosition()
|
||||||
mPositionOffset = osg::Vec3f();
|
mPositionOffset = osg::Vec3f();
|
||||||
mStandingOnPtr = nullptr;
|
mStandingOnPtr = nullptr;
|
||||||
mSkipCollisions = true;
|
mSkipCollisions = true;
|
||||||
|
mSkipSimulation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actor::setSimulationPosition(const osg::Vec3f& position)
|
void Actor::setSimulationPosition(const osg::Vec3f& position)
|
||||||
{
|
{
|
||||||
mSimulationPosition = position;
|
if (!std::exchange(mSkipSimulation, false))
|
||||||
|
mSimulationPosition = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f Actor::getSimulationPosition() const
|
osg::Vec3f Actor::getSimulationPosition() const
|
||||||
|
@ -180,18 +182,20 @@ void Actor::updateCollisionObjectPosition()
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(mPositionMutex);
|
std::scoped_lock lock(mPositionMutex);
|
||||||
mShape->setLocalScaling(Misc::Convert::toBullet(mScale));
|
mShape->setLocalScaling(Misc::Convert::toBullet(mScale));
|
||||||
osg::Vec3f scaledTranslation = mRotation * osg::componentMultiply(mMeshTranslation, mScale);
|
osg::Vec3f newPosition = getScaledMeshTranslation() + mPosition;
|
||||||
osg::Vec3f newPosition = scaledTranslation + mPosition;
|
|
||||||
mLocalTransform.setOrigin(Misc::Convert::toBullet(newPosition));
|
auto& trans = mCollisionObject->getWorldTransform();
|
||||||
mLocalTransform.setRotation(Misc::Convert::toBullet(mRotation));
|
trans.setOrigin(Misc::Convert::toBullet(newPosition));
|
||||||
mCollisionObject->setWorldTransform(mLocalTransform);
|
trans.setRotation(Misc::Convert::toBullet(mRotation));
|
||||||
|
mCollisionObject->setWorldTransform(trans);
|
||||||
|
|
||||||
mWorldPositionChanged = false;
|
mWorldPositionChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f Actor::getCollisionObjectPosition() const
|
osg::Vec3f Actor::getCollisionObjectPosition() const
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(mPositionMutex);
|
std::scoped_lock lock(mPositionMutex);
|
||||||
return Misc::Convert::toOsg(mLocalTransform.getOrigin());
|
return getScaledMeshTranslation() + mPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actor::setPosition(const osg::Vec3f& position)
|
bool Actor::setPosition(const osg::Vec3f& position)
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace MWPhysics
|
||||||
class Actor final : public PtrHolder
|
class Actor final : public PtrHolder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler);
|
Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler, bool canWaterWalk);
|
||||||
~Actor() override;
|
~Actor() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,9 +74,6 @@ namespace MWPhysics
|
||||||
*/
|
*/
|
||||||
osg::Vec3f getOriginalHalfExtents() const;
|
osg::Vec3f getOriginalHalfExtents() const;
|
||||||
|
|
||||||
/// Returns the mesh translation, scaled and rotated as necessary
|
|
||||||
osg::Vec3f getScaledMeshTranslation() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the position of the collision body
|
* 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.
|
* @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.
|
||||||
|
@ -181,6 +178,9 @@ namespace MWPhysics
|
||||||
void addCollisionMask(int collisionMask);
|
void addCollisionMask(int collisionMask);
|
||||||
int getCollisionMask() const;
|
int getCollisionMask() const;
|
||||||
|
|
||||||
|
/// Returns the mesh translation, scaled and rotated as necessary
|
||||||
|
osg::Vec3f getScaledMeshTranslation() const;
|
||||||
|
|
||||||
bool mCanWaterWalk;
|
bool mCanWaterWalk;
|
||||||
std::atomic<bool> mWalkingOnWater;
|
std::atomic<bool> mWalkingOnWater;
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ namespace MWPhysics
|
||||||
osg::Vec3f mVelocity;
|
osg::Vec3f mVelocity;
|
||||||
bool mWorldPositionChanged;
|
bool mWorldPositionChanged;
|
||||||
bool mSkipCollisions;
|
bool mSkipCollisions;
|
||||||
btTransform mLocalTransform;
|
bool mSkipSimulation;
|
||||||
mutable std::mutex mPositionMutex;
|
mutable std::mutex mPositionMutex;
|
||||||
|
|
||||||
unsigned int mStuckFrames;
|
unsigned int mStuckFrames;
|
||||||
|
|
|
@ -599,7 +599,7 @@ namespace MWPhysics
|
||||||
if (!mRemainingSteps)
|
if (!mRemainingSteps)
|
||||||
return;
|
return;
|
||||||
for (auto& data : mActorsFrameData)
|
for (auto& data : mActorsFrameData)
|
||||||
if (data.mActor.lock())
|
if (const auto actor = data.mActor.lock())
|
||||||
{
|
{
|
||||||
std::unique_lock lock(mCollisionWorldMutex);
|
std::unique_lock lock(mCollisionWorldMutex);
|
||||||
MovementSolver::unstuck(data, mCollisionWorld);
|
MovementSolver::unstuck(data, mCollisionWorld);
|
||||||
|
|
|
@ -27,8 +27,8 @@ namespace MWPhysics
|
||||||
mCollisionObject->setUserPointer(this);
|
mCollisionObject->setUserPointer(this);
|
||||||
|
|
||||||
setScale(ptr.getCellRef().getScale());
|
setScale(ptr.getCellRef().getScale());
|
||||||
setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude()));
|
setRotation(ptr.getRefData().getBaseNode()->getAttitude());
|
||||||
setOrigin(Misc::Convert::toBullet(ptr.getRefData().getPosition().asVec3()));
|
updatePosition();
|
||||||
commitPositionChange();
|
commitPositionChange();
|
||||||
|
|
||||||
mTaskScheduler->addCollisionObject(mCollisionObject.get(), collisionType, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile);
|
mTaskScheduler->addCollisionObject(mCollisionObject.get(), collisionType, CollisionType_Actor|CollisionType_HeightMap|CollisionType_Projectile);
|
||||||
|
@ -51,17 +51,17 @@ namespace MWPhysics
|
||||||
mScaleUpdatePending = true;
|
mScaleUpdatePending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::setRotation(const btQuaternion& quat)
|
void Object::setRotation(const osg::Quat& quat)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mPositionMutex);
|
std::unique_lock<std::mutex> lock(mPositionMutex);
|
||||||
mLocalTransform.setRotation(quat);
|
mRotation = quat;
|
||||||
mTransformUpdatePending = true;
|
mTransformUpdatePending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::setOrigin(const btVector3& vec)
|
void Object::updatePosition()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mPositionMutex);
|
std::unique_lock<std::mutex> lock(mPositionMutex);
|
||||||
mLocalTransform.setOrigin(vec);
|
mPosition = mPtr.getRefData().getPosition().asVec3();
|
||||||
mTransformUpdatePending = true;
|
mTransformUpdatePending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,10 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
if (mTransformUpdatePending)
|
if (mTransformUpdatePending)
|
||||||
{
|
{
|
||||||
mCollisionObject->setWorldTransform(mLocalTransform);
|
btTransform trans;
|
||||||
|
trans.setOrigin(Misc::Convert::toBullet(mPosition));
|
||||||
|
trans.setRotation(Misc::Convert::toBullet(mRotation));
|
||||||
|
mCollisionObject->setWorldTransform(trans);
|
||||||
mTransformUpdatePending = false;
|
mTransformUpdatePending = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +96,10 @@ namespace MWPhysics
|
||||||
btTransform Object::getTransform() const
|
btTransform Object::getTransform() const
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mPositionMutex);
|
std::unique_lock<std::mutex> lock(mPositionMutex);
|
||||||
return mLocalTransform;
|
btTransform trans;
|
||||||
|
trans.setOrigin(Misc::Convert::toBullet(mPosition));
|
||||||
|
trans.setRotation(Misc::Convert::toBullet(mRotation));
|
||||||
|
return trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Object::isSolid() const
|
bool Object::isSolid() const
|
||||||
|
|
|
@ -16,7 +16,6 @@ namespace Resource
|
||||||
}
|
}
|
||||||
|
|
||||||
class btCollisionObject;
|
class btCollisionObject;
|
||||||
class btQuaternion;
|
|
||||||
class btVector3;
|
class btVector3;
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
|
@ -31,8 +30,8 @@ namespace MWPhysics
|
||||||
|
|
||||||
const Resource::BulletShapeInstance* getShapeInstance() const;
|
const Resource::BulletShapeInstance* getShapeInstance() const;
|
||||||
void setScale(float scale);
|
void setScale(float scale);
|
||||||
void setRotation(const btQuaternion& quat);
|
void setRotation(const osg::Quat& quat);
|
||||||
void setOrigin(const btVector3& vec);
|
void updatePosition();
|
||||||
void commitPositionChange();
|
void commitPositionChange();
|
||||||
btCollisionObject* getCollisionObject();
|
btCollisionObject* getCollisionObject();
|
||||||
const btCollisionObject* getCollisionObject() const;
|
const btCollisionObject* getCollisionObject() const;
|
||||||
|
@ -51,7 +50,8 @@ namespace MWPhysics
|
||||||
std::map<int, osg::NodePath> mRecIndexToNodePath;
|
std::map<int, osg::NodePath> mRecIndexToNodePath;
|
||||||
bool mSolid;
|
bool mSolid;
|
||||||
btVector3 mScale;
|
btVector3 mScale;
|
||||||
btTransform mLocalTransform;
|
osg::Vec3f mPosition;
|
||||||
|
osg::Quat mRotation;
|
||||||
bool mScaleUpdatePending;
|
bool mScaleUpdatePending;
|
||||||
bool mTransformUpdatePending;
|
bool mTransformUpdatePending;
|
||||||
mutable std::mutex mPositionMutex;
|
mutable std::mutex mPositionMutex;
|
||||||
|
|
|
@ -654,7 +654,7 @@ namespace MWPhysics
|
||||||
ObjectMap::iterator found = mObjects.find(ptr);
|
ObjectMap::iterator found = mObjects.find(ptr);
|
||||||
if (found != mObjects.end())
|
if (found != mObjects.end())
|
||||||
{
|
{
|
||||||
found->second->setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude()));
|
found->second->setRotation(ptr.getRefData().getBaseNode()->getAttitude());
|
||||||
mTaskScheduler->updateSingleAabb(found->second);
|
mTaskScheduler->updateSingleAabb(found->second);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -675,7 +675,7 @@ namespace MWPhysics
|
||||||
ObjectMap::iterator found = mObjects.find(ptr);
|
ObjectMap::iterator found = mObjects.find(ptr);
|
||||||
if (found != mObjects.end())
|
if (found != mObjects.end())
|
||||||
{
|
{
|
||||||
found->second->setOrigin(Misc::Convert::toBullet(ptr.getRefData().getPosition().asVec3()));
|
found->second->updatePosition();
|
||||||
mTaskScheduler->updateSingleAabb(found->second);
|
mTaskScheduler->updateSingleAabb(found->second);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -705,7 +705,15 @@ namespace MWPhysics
|
||||||
if (!shape)
|
if (!shape)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto actor = std::make_shared<Actor>(ptr, shape, mTaskScheduler.get());
|
// check if Actor should spawn above water
|
||||||
|
const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects();
|
||||||
|
const bool canWaterWalk = effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() > 0;
|
||||||
|
|
||||||
|
auto actor = std::make_shared<Actor>(ptr, shape, mTaskScheduler.get(), canWaterWalk);
|
||||||
|
|
||||||
|
// check if Actor is on the ground or in the air
|
||||||
|
traceDown(ptr, ptr.getRefData().getPosition().asVec3(), 10.f);
|
||||||
|
|
||||||
mActors.emplace(ptr, std::move(actor));
|
mActors.emplace(ptr, std::move(actor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,11 @@
|
||||||
#include <BulletCollision/CollisionShapes/btSphereShape.h>
|
#include <BulletCollision/CollisionShapes/btSphereShape.h>
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||||
|
|
||||||
#include <LinearMath/btVector3.h>
|
|
||||||
|
|
||||||
#include <components/misc/convert.hpp>
|
#include <components/misc/convert.hpp>
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
#include "collisiontype.hpp"
|
#include "collisiontype.hpp"
|
||||||
#include "memory"
|
|
||||||
#include "mtphysics.hpp"
|
#include "mtphysics.hpp"
|
||||||
#include "projectile.hpp"
|
#include "projectile.hpp"
|
||||||
|
|
||||||
|
@ -55,7 +52,9 @@ void Projectile::commitPositionChange()
|
||||||
std::scoped_lock lock(mMutex);
|
std::scoped_lock lock(mMutex);
|
||||||
if (mTransformUpdatePending)
|
if (mTransformUpdatePending)
|
||||||
{
|
{
|
||||||
mCollisionObject->setWorldTransform(mLocalTransform);
|
auto& trans = mCollisionObject->getWorldTransform();
|
||||||
|
trans.setOrigin(Misc::Convert::toBullet(mPosition));
|
||||||
|
mCollisionObject->setWorldTransform(trans);
|
||||||
mTransformUpdatePending = false;
|
mTransformUpdatePending = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,14 +62,14 @@ void Projectile::commitPositionChange()
|
||||||
void Projectile::setPosition(const osg::Vec3f &position)
|
void Projectile::setPosition(const osg::Vec3f &position)
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(mMutex);
|
std::scoped_lock lock(mMutex);
|
||||||
mLocalTransform.setOrigin(Misc::Convert::toBullet(position));
|
mPosition = position;
|
||||||
mTransformUpdatePending = true;
|
mTransformUpdatePending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f Projectile::getPosition() const
|
osg::Vec3f Projectile::getPosition() const
|
||||||
{
|
{
|
||||||
std::scoped_lock lock(mMutex);
|
std::scoped_lock lock(mMutex);
|
||||||
return Misc::Convert::toOsg(mLocalTransform.getOrigin());
|
return mPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Projectile::canTraverseWater() const
|
bool Projectile::canTraverseWater() const
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include <LinearMath/btVector3.h>
|
||||||
|
|
||||||
#include "ptrholder.hpp"
|
#include "ptrholder.hpp"
|
||||||
|
|
||||||
class btCollisionObject;
|
class btCollisionObject;
|
||||||
class btCollisionShape;
|
class btCollisionShape;
|
||||||
class btConvexShape;
|
class btConvexShape;
|
||||||
class btVector3;
|
|
||||||
|
|
||||||
namespace osg
|
namespace osg
|
||||||
{
|
{
|
||||||
|
@ -76,7 +77,6 @@ namespace MWPhysics
|
||||||
btConvexShape* mConvexShape;
|
btConvexShape* mConvexShape;
|
||||||
|
|
||||||
std::unique_ptr<btCollisionObject> mCollisionObject;
|
std::unique_ptr<btCollisionObject> mCollisionObject;
|
||||||
btTransform mLocalTransform;
|
|
||||||
bool mTransformUpdatePending;
|
bool mTransformUpdatePending;
|
||||||
bool mCanCrossWaterSurface;
|
bool mCanCrossWaterSurface;
|
||||||
bool mCrossedWaterSurface;
|
bool mCrossedWaterSurface;
|
||||||
|
@ -84,6 +84,7 @@ namespace MWPhysics
|
||||||
MWWorld::Ptr mCaster;
|
MWWorld::Ptr mCaster;
|
||||||
MWWorld::Ptr mHitTarget;
|
MWWorld::Ptr mHitTarget;
|
||||||
std::optional<btVector3> mWaterHitPosition;
|
std::optional<btVector3> mWaterHitPosition;
|
||||||
|
osg::Vec3f mPosition;
|
||||||
btVector3 mHitPosition;
|
btVector3 mHitPosition;
|
||||||
btVector3 mHitNormal;
|
btVector3 mHitNormal;
|
||||||
|
|
||||||
|
|
|
@ -364,6 +364,7 @@ namespace MWRender
|
||||||
osg::ref_ptr<osg::StateSet> stateset = node.getStateSet() ? osg::clone(node.getStateSet(), osg::CopyOp::SHALLOW_COPY) : new osg::StateSet;
|
osg::ref_ptr<osg::StateSet> stateset = node.getStateSet() ? osg::clone(node.getStateSet(), osg::CopyOp::SHALLOW_COPY) : new osg::StateSet;
|
||||||
stateset->setAttribute(m);
|
stateset->setAttribute(m);
|
||||||
stateset->addUniform(new osg::Uniform("colorMode", 0));
|
stateset->addUniform(new osg::Uniform("colorMode", 0));
|
||||||
|
stateset->addUniform(new osg::Uniform("emissiveMult", 1.f));
|
||||||
node.setStateSet(stateset);
|
node.setStateSet(stateset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -477,8 +478,7 @@ namespace MWRender
|
||||||
constexpr auto copyMask = ~Mask_UpdateVisitor;
|
constexpr auto copyMask = ~Mask_UpdateVisitor;
|
||||||
|
|
||||||
AnalyzeVisitor analyzeVisitor(copyMask);
|
AnalyzeVisitor analyzeVisitor(copyMask);
|
||||||
osg::Vec3f center3 = { center.x(), center.y(), 0.f };
|
analyzeVisitor.mCurrentDistance = (viewPoint - worldCenter).length2();
|
||||||
analyzeVisitor.mCurrentDistance = (viewPoint - center3).length2();
|
|
||||||
float minSize = mMinSize;
|
float minSize = mMinSize;
|
||||||
if (mMinSizeMergeFactor)
|
if (mMinSizeMergeFactor)
|
||||||
minSize *= mMinSizeMergeFactor;
|
minSize *= mMinSizeMergeFactor;
|
||||||
|
|
|
@ -478,12 +478,6 @@ namespace MWWorld
|
||||||
|
|
||||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
||||||
// By default the player is grounded, with the scene fully loaded, we validate and correct this.
|
|
||||||
if (player.mCell == cell) // Only run once, during initial cell load.
|
|
||||||
{
|
|
||||||
mPhysics->traceDown(player, player.getRefData().getPosition().asVec3(), 10.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
navigator->update(player.getRefData().getPosition().asVec3());
|
navigator->update(player.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||||
|
|
|
@ -1427,7 +1427,7 @@ namespace MWWorld
|
||||||
if (movePhysics)
|
if (movePhysics)
|
||||||
{
|
{
|
||||||
if (const auto object = mPhysics->getObject(ptr))
|
if (const auto object = mPhysics->getObject(ptr))
|
||||||
updateNavigatorObject(object);
|
updateNavigatorObject(*object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1486,7 +1486,7 @@ namespace MWWorld
|
||||||
if (mPhysics->getActor(ptr))
|
if (mPhysics->getActor(ptr))
|
||||||
mNavigator->addAgent(getPathfindingHalfExtents(ptr));
|
mNavigator->addAgent(getPathfindingHalfExtents(ptr));
|
||||||
else if (const auto object = mPhysics->getObject(ptr))
|
else if (const auto object = mPhysics->getObject(ptr))
|
||||||
mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator;
|
updateNavigatorObject(*object);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::rotateObjectImp(const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags)
|
void World::rotateObjectImp(const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags)
|
||||||
|
@ -1535,7 +1535,7 @@ namespace MWWorld
|
||||||
mWorldScene->updateObjectRotation(ptr, order);
|
mWorldScene->updateObjectRotation(ptr, order);
|
||||||
|
|
||||||
if (const auto object = mPhysics->getObject(ptr))
|
if (const auto object = mPhysics->getObject(ptr))
|
||||||
updateNavigatorObject(object);
|
updateNavigatorObject(*object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1627,7 +1627,7 @@ namespace MWWorld
|
||||||
mPhysics->updateRotation(ptr);
|
mPhysics->updateRotation(ptr);
|
||||||
|
|
||||||
if (const auto object = mPhysics->getObject(ptr))
|
if (const auto object = mPhysics->getObject(ptr))
|
||||||
updateNavigatorObject(object);
|
updateNavigatorObject(*object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1775,14 +1775,11 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::updateNavigator()
|
void World::updateNavigator()
|
||||||
{
|
{
|
||||||
mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object)
|
mPhysics->forEachAnimatedObject([&] (const MWPhysics::Object* object) { updateNavigatorObject(*object); });
|
||||||
{
|
|
||||||
mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const auto& door : mDoorStates)
|
for (const auto& door : mDoorStates)
|
||||||
if (const auto object = mPhysics->getObject(door.first))
|
if (const auto object = mPhysics->getObject(door.first))
|
||||||
mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator;
|
updateNavigatorObject(*object);
|
||||||
|
|
||||||
if (mShouldUpdateNavigator)
|
if (mShouldUpdateNavigator)
|
||||||
{
|
{
|
||||||
|
@ -1791,13 +1788,14 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::updateNavigatorObject(const MWPhysics::Object* object)
|
void World::updateNavigatorObject(const MWPhysics::Object& object)
|
||||||
{
|
{
|
||||||
const DetourNavigator::ObjectShapes shapes {
|
const DetourNavigator::ObjectShapes shapes {
|
||||||
*object->getShapeInstance()->getCollisionShape(),
|
*object.getShapeInstance()->getCollisionShape(),
|
||||||
object->getShapeInstance()->getAvoidCollisionShape()
|
object.getShapeInstance()->getAvoidCollisionShape()
|
||||||
};
|
};
|
||||||
return mNavigator->updateObject(DetourNavigator::ObjectId(object), shapes, object->getTransform());
|
mShouldUpdateNavigator = mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform())
|
||||||
|
|| mShouldUpdateNavigator;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWPhysics::RayCastingInterface* World::getRayCasting() const
|
const MWPhysics::RayCastingInterface* World::getRayCasting() const
|
||||||
|
|
|
@ -167,7 +167,7 @@ namespace MWWorld
|
||||||
|
|
||||||
void updateNavigator();
|
void updateNavigator();
|
||||||
|
|
||||||
bool updateNavigatorObject(const MWPhysics::Object* object);
|
void updateNavigatorObject(const MWPhysics::Object& object);
|
||||||
|
|
||||||
void ensureNeededRecords();
|
void ensureNeededRecords();
|
||||||
|
|
||||||
|
|
|
@ -2011,6 +2011,11 @@ namespace NifOsg
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::BlendFunc> blendFunc (new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf),
|
osg::ref_ptr<osg::BlendFunc> blendFunc (new osg::BlendFunc(getBlendMode((alphaprop->flags>>1)&0xf),
|
||||||
getBlendMode((alphaprop->flags>>5)&0xf)));
|
getBlendMode((alphaprop->flags>>5)&0xf)));
|
||||||
|
// on AMD hardware, alpha still seems to be stored with an RGBA framebuffer with OpenGL.
|
||||||
|
// This might be mandated by the OpenGL 2.1 specification section 2.14.9, or might be a bug.
|
||||||
|
// Either way, D3D8.1 doesn't do that, so adapt the destination factor.
|
||||||
|
if (blendFunc->getDestination() == GL_DST_ALPHA)
|
||||||
|
blendFunc->setDestination(GL_ONE);
|
||||||
blendFunc = shareAttribute(blendFunc);
|
blendFunc = shareAttribute(blendFunc);
|
||||||
stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
|
|
@ -904,6 +904,7 @@ void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & sh
|
||||||
program->addShader(castingVertexShader);
|
program->addShader(castingVertexShader);
|
||||||
program->addShader(shaderManager.getShader("shadowcasting_fragment.glsl", { {"alphaFunc", std::to_string(alphaFunc)},
|
program->addShader(shaderManager.getShader("shadowcasting_fragment.glsl", { {"alphaFunc", std::to_string(alphaFunc)},
|
||||||
{"alphaToCoverage", "0"},
|
{"alphaToCoverage", "0"},
|
||||||
|
{"adjustCoverage", "1"},
|
||||||
{"useGPUShader4", useGPUShader4}
|
{"useGPUShader4", useGPUShader4}
|
||||||
}, osg::Shader::FRAGMENT));
|
}, osg::Shader::FRAGMENT));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,68 @@
|
||||||
|
|
||||||
namespace Shader
|
namespace Shader
|
||||||
{
|
{
|
||||||
|
class AddedState : public osg::Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddedState() = default;
|
||||||
|
AddedState(const AddedState& rhs, const osg::CopyOp& copyOp)
|
||||||
|
: osg::Object(rhs, copyOp)
|
||||||
|
, mUniforms(rhs.mUniforms)
|
||||||
|
, mModes(rhs.mModes)
|
||||||
|
, mAttributes(rhs.mAttributes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void addUniform(const std::string& name) { mUniforms.emplace(name); }
|
||||||
|
void setMode(osg::StateAttribute::GLMode mode) { mModes.emplace(mode); }
|
||||||
|
void setAttribute(osg::StateAttribute::TypeMemberPair typeMemberPair) { mAttributes.emplace(typeMemberPair); }
|
||||||
|
|
||||||
|
void setAttribute(const osg::StateAttribute* attribute)
|
||||||
|
{
|
||||||
|
mAttributes.emplace(attribute->getTypeMemberPair());
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void setAttribute(osg::ref_ptr<T> attribute) { setAttribute(attribute.get()); }
|
||||||
|
|
||||||
|
void setAttributeAndModes(const osg::StateAttribute* attribute)
|
||||||
|
{
|
||||||
|
setAttribute(attribute);
|
||||||
|
InterrogateModesHelper helper(this);
|
||||||
|
attribute->getModeUsage(helper);
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void setAttributeAndModes(osg::ref_ptr<T> attribute) { setAttributeAndModes(attribute.get()); }
|
||||||
|
|
||||||
|
bool hasUniform(const std::string& name) { return mUniforms.count(name); }
|
||||||
|
bool hasMode(osg::StateAttribute::GLMode mode) { return mModes.count(mode); }
|
||||||
|
bool hasAttribute(osg::StateAttribute::TypeMemberPair typeMemberPair) { return mAttributes.count(typeMemberPair); }
|
||||||
|
bool hasAttribute(osg::StateAttribute::Type type, unsigned int member) { return hasAttribute(osg::StateAttribute::TypeMemberPair(type, member)); }
|
||||||
|
|
||||||
|
const std::set<osg::StateAttribute::TypeMemberPair>& getAttributes() { return mAttributes; }
|
||||||
|
|
||||||
|
bool empty()
|
||||||
|
{
|
||||||
|
return mUniforms.empty() && mModes.empty() && mAttributes.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
META_Object(Shader, AddedState)
|
||||||
|
|
||||||
|
private:
|
||||||
|
class InterrogateModesHelper : public osg::StateAttribute::ModeUsage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InterrogateModesHelper(AddedState* tracker) : mTracker(tracker) {}
|
||||||
|
void usesMode(osg::StateAttribute::GLMode mode) override { mTracker->setMode(mode); }
|
||||||
|
void usesTextureMode(osg::StateAttribute::GLMode mode) override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AddedState* mTracker;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_set<std::string> mUniforms;
|
||||||
|
std::unordered_set<osg::StateAttribute::GLMode> mModes;
|
||||||
|
std::set<osg::StateAttribute::TypeMemberPair> mAttributes;
|
||||||
|
};
|
||||||
|
|
||||||
ShaderVisitor::ShaderRequirements::ShaderRequirements()
|
ShaderVisitor::ShaderRequirements::ShaderRequirements()
|
||||||
: mShaderRequired(false)
|
: mShaderRequired(false)
|
||||||
|
@ -105,14 +167,32 @@ namespace Shader
|
||||||
return static_cast<osg::StateSet *>(stateSet.getUserDataContainer()->getUserObject("removedState"));
|
return static_cast<osg::StateSet *>(stateSet.getUserDataContainer()->getUserObject("removedState"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateRemovedState(osg::UserDataContainer& userData, osg::StateSet* stateSet)
|
void updateRemovedState(osg::UserDataContainer& userData, osg::StateSet* removedState)
|
||||||
{
|
{
|
||||||
unsigned int index = userData.getUserObjectIndex("removedState");
|
unsigned int index = userData.getUserObjectIndex("removedState");
|
||||||
if (index < userData.getNumUserObjects())
|
if (index < userData.getNumUserObjects())
|
||||||
userData.setUserObject(index, stateSet);
|
userData.setUserObject(index, removedState);
|
||||||
else
|
else
|
||||||
userData.addUserObject(stateSet);
|
userData.addUserObject(removedState);
|
||||||
stateSet->setName("removedState");
|
removedState->setName("removedState");
|
||||||
|
}
|
||||||
|
|
||||||
|
AddedState* getAddedState(osg::StateSet& stateSet)
|
||||||
|
{
|
||||||
|
if (!stateSet.getUserDataContainer())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return static_cast<AddedState*>(stateSet.getUserDataContainer()->getUserObject("addedState"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateAddedState(osg::UserDataContainer& userData, AddedState* addedState)
|
||||||
|
{
|
||||||
|
unsigned int index = userData.getUserObjectIndex("addedState");
|
||||||
|
if (index < userData.getNumUserObjects())
|
||||||
|
userData.setUserObject(index, addedState);
|
||||||
|
else
|
||||||
|
userData.addUserObject(addedState);
|
||||||
|
addedState->setName("addedState");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap", "bumpMap" };
|
const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap", "bumpMap" };
|
||||||
|
@ -280,11 +360,13 @@ namespace Shader
|
||||||
osg::StateSet::AttributeList removedAttributes;
|
osg::StateSet::AttributeList removedAttributes;
|
||||||
if (osg::ref_ptr<osg::StateSet> removedState = getRemovedState(*stateset))
|
if (osg::ref_ptr<osg::StateSet> removedState = getRemovedState(*stateset))
|
||||||
removedAttributes = removedState->getAttributeList();
|
removedAttributes = removedState->getAttributeList();
|
||||||
|
osg::ref_ptr<AddedState> addedState = getAddedState(*stateset);
|
||||||
|
|
||||||
for (const auto* attributeMap : std::initializer_list<const osg::StateSet::AttributeList*>{ &attributes, &removedAttributes })
|
for (const auto* attributeMap : std::initializer_list<const osg::StateSet::AttributeList*>{ &attributes, &removedAttributes })
|
||||||
{
|
{
|
||||||
for (osg::StateSet::AttributeList::const_iterator it = attributeMap->begin(); it != attributeMap->end(); ++it)
|
for (osg::StateSet::AttributeList::const_iterator it = attributeMap->begin(); it != attributeMap->end(); ++it)
|
||||||
{
|
{
|
||||||
if (attributeMap != &removedAttributes && removedAttributes.count(it->first))
|
if (addedState && attributeMap != &removedAttributes && addedState->hasAttribute(it->first))
|
||||||
continue;
|
continue;
|
||||||
if (it->first.first == osg::StateAttribute::MATERIAL)
|
if (it->first.first == osg::StateAttribute::MATERIAL)
|
||||||
{
|
{
|
||||||
|
@ -296,9 +378,6 @@ namespace Shader
|
||||||
|
|
||||||
const osg::Material* mat = static_cast<const osg::Material*>(it->second.first.get());
|
const osg::Material* mat = static_cast<const osg::Material*>(it->second.first.get());
|
||||||
|
|
||||||
if (!writableStateSet)
|
|
||||||
writableStateSet = getWritableStateSet(node);
|
|
||||||
|
|
||||||
int colorMode;
|
int colorMode;
|
||||||
switch (mat->getColorMode())
|
switch (mat->getColorMode())
|
||||||
{
|
{
|
||||||
|
@ -376,6 +455,10 @@ namespace Shader
|
||||||
writableStateSet = node.getOrCreateStateSet();
|
writableStateSet = node.getOrCreateStateSet();
|
||||||
else
|
else
|
||||||
writableStateSet = getWritableStateSet(node);
|
writableStateSet = getWritableStateSet(node);
|
||||||
|
osg::ref_ptr<AddedState> addedState = new AddedState;
|
||||||
|
osg::ref_ptr<AddedState> previousAddedState = getAddedState(*writableStateSet);
|
||||||
|
if (!previousAddedState)
|
||||||
|
previousAddedState = new AddedState;
|
||||||
|
|
||||||
ShaderManager::DefineMap defineMap;
|
ShaderManager::DefineMap defineMap;
|
||||||
for (unsigned int i=0; i<sizeof(defaultTextures)/sizeof(defaultTextures[0]); ++i)
|
for (unsigned int i=0; i<sizeof(defaultTextures)/sizeof(defaultTextures[0]); ++i)
|
||||||
|
@ -392,6 +475,7 @@ namespace Shader
|
||||||
defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0";
|
defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0";
|
||||||
|
|
||||||
writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode));
|
writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode));
|
||||||
|
addedState->addUniform("colorMode");
|
||||||
|
|
||||||
defineMap["alphaFunc"] = std::to_string(reqs.mAlphaFunc);
|
defineMap["alphaFunc"] = std::to_string(reqs.mAlphaFunc);
|
||||||
|
|
||||||
|
@ -403,26 +487,35 @@ namespace Shader
|
||||||
removedState = new osg::StateSet();
|
removedState = new osg::StateSet();
|
||||||
|
|
||||||
defineMap["alphaToCoverage"] = "0";
|
defineMap["alphaToCoverage"] = "0";
|
||||||
|
defineMap["adjustCoverage"] = "0";
|
||||||
if (reqs.mAlphaFunc != osg::AlphaFunc::ALWAYS)
|
if (reqs.mAlphaFunc != osg::AlphaFunc::ALWAYS)
|
||||||
{
|
{
|
||||||
writableStateSet->addUniform(new osg::Uniform("alphaRef", reqs.mAlphaRef));
|
writableStateSet->addUniform(new osg::Uniform("alphaRef", reqs.mAlphaRef));
|
||||||
|
addedState->addUniform("alphaRef");
|
||||||
|
|
||||||
if (!removedState->getAttributePair(osg::StateAttribute::ALPHAFUNC))
|
if (!removedState->getAttributePair(osg::StateAttribute::ALPHAFUNC))
|
||||||
{
|
{
|
||||||
const auto* alphaFunc = writableStateSet->getAttributePair(osg::StateAttribute::ALPHAFUNC);
|
const auto* alphaFunc = writableStateSet->getAttributePair(osg::StateAttribute::ALPHAFUNC);
|
||||||
if (alphaFunc)
|
if (alphaFunc && !previousAddedState->hasAttribute(osg::StateAttribute::ALPHAFUNC, 0))
|
||||||
removedState->setAttribute(alphaFunc->first, alphaFunc->second);
|
removedState->setAttribute(alphaFunc->first, alphaFunc->second);
|
||||||
}
|
}
|
||||||
// This prevents redundant glAlphaFunc calls while letting the shadows bin still see the test
|
// This prevents redundant glAlphaFunc calls while letting the shadows bin still see the test
|
||||||
writableStateSet->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
writableStateSet->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||||
|
addedState->setAttribute(RemovedAlphaFunc::getInstance(reqs.mAlphaFunc));
|
||||||
|
|
||||||
// Blending won't work with A2C as we use the alpha channel for coverage. gl_SampleCoverage from ARB_sample_shading would save the day, but requires GLSL 130
|
// Blending won't work with A2C as we use the alpha channel for coverage. gl_SampleCoverage from ARB_sample_shading would save the day, but requires GLSL 130
|
||||||
if (mConvertAlphaTestToAlphaToCoverage && !reqs.mAlphaBlend)
|
if (mConvertAlphaTestToAlphaToCoverage && !reqs.mAlphaBlend)
|
||||||
{
|
{
|
||||||
writableStateSet->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, osg::StateAttribute::ON);
|
writableStateSet->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, osg::StateAttribute::ON);
|
||||||
|
addedState->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB);
|
||||||
defineMap["alphaToCoverage"] = "1";
|
defineMap["alphaToCoverage"] = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjusting coverage isn't safe with blending on as blending requires the alpha to be intact.
|
||||||
|
// Maybe we could also somehow (e.g. userdata) detect when the diffuse map has coverage-preserving mip maps in the future
|
||||||
|
if (!reqs.mAlphaBlend)
|
||||||
|
defineMap["adjustCoverage"] = "1";
|
||||||
|
|
||||||
// Preventing alpha tested stuff shrinking as lower mip levels are used requires knowing the texture size
|
// Preventing alpha tested stuff shrinking as lower mip levels are used requires knowing the texture size
|
||||||
osg::ref_ptr<osg::GLExtensions> exts = osg::GLExtensions::Get(0, false);
|
osg::ref_ptr<osg::GLExtensions> exts = osg::GLExtensions::Get(0, false);
|
||||||
if (exts && exts->isGpuShader4Supported)
|
if (exts && exts->isGpuShader4Supported)
|
||||||
|
@ -430,10 +523,11 @@ namespace Shader
|
||||||
// We could fall back to a texture size uniform if EXT_gpu_shader4 is missing
|
// We could fall back to a texture size uniform if EXT_gpu_shader4 is missing
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT)
|
if (writableStateSet->getMode(GL_ALPHA_TEST) != osg::StateAttribute::INHERIT && !previousAddedState->hasMode(GL_ALPHA_TEST))
|
||||||
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
|
removedState->setMode(GL_ALPHA_TEST, writableStateSet->getMode(GL_ALPHA_TEST));
|
||||||
// This disables the deprecated fixed-function alpha test
|
// This disables the deprecated fixed-function alpha test
|
||||||
writableStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
|
writableStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
|
||||||
|
addedState->setMode(GL_ALPHA_TEST);
|
||||||
|
|
||||||
if (!removedState->getModeList().empty() || !removedState->getAttributeList().empty())
|
if (!removedState->getModeList().empty() || !removedState->getAttributeList().empty())
|
||||||
{
|
{
|
||||||
|
@ -447,6 +541,18 @@ namespace Shader
|
||||||
updateRemovedState(*writableUserData, removedState);
|
updateRemovedState(*writableUserData, removedState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!addedState->empty())
|
||||||
|
{
|
||||||
|
// user data is normally shallow copied so shared with the original stateset
|
||||||
|
osg::ref_ptr<osg::UserDataContainer> writableUserData;
|
||||||
|
if (mAllowedToModifyStateSets)
|
||||||
|
writableUserData = writableStateSet->getOrCreateUserDataContainer();
|
||||||
|
else
|
||||||
|
writableUserData = getWritableUserDataContainer(*writableStateSet);
|
||||||
|
|
||||||
|
updateAddedState(*writableUserData, addedState);
|
||||||
|
}
|
||||||
|
|
||||||
defineMap["translucentFramebuffer"] = mTranslucentFramebuffer ? "1" : "0";
|
defineMap["translucentFramebuffer"] = mTranslucentFramebuffer ? "1" : "0";
|
||||||
|
|
||||||
std::string shaderPrefix;
|
std::string shaderPrefix;
|
||||||
|
@ -458,11 +564,14 @@ namespace Shader
|
||||||
|
|
||||||
if (vertexShader && fragmentShader)
|
if (vertexShader && fragmentShader)
|
||||||
{
|
{
|
||||||
writableStateSet->setAttributeAndModes(mShaderManager.getProgram(vertexShader, fragmentShader), osg::StateAttribute::ON);
|
auto program = mShaderManager.getProgram(vertexShader, fragmentShader);
|
||||||
|
writableStateSet->setAttributeAndModes(program, osg::StateAttribute::ON);
|
||||||
|
addedState->setAttributeAndModes(program);
|
||||||
|
|
||||||
for (std::map<int, std::string>::const_iterator texIt = reqs.mTextures.begin(); texIt != reqs.mTextures.end(); ++texIt)
|
for (std::map<int, std::string>::const_iterator texIt = reqs.mTextures.begin(); texIt != reqs.mTextures.end(); ++texIt)
|
||||||
{
|
{
|
||||||
writableStateSet->addUniform(new osg::Uniform(texIt->second.c_str(), texIt->first), osg::StateAttribute::ON);
|
writableStateSet->addUniform(new osg::Uniform(texIt->second.c_str(), texIt->first), osg::StateAttribute::ON);
|
||||||
|
addedState->addUniform(texIt->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -477,24 +586,57 @@ namespace Shader
|
||||||
else
|
else
|
||||||
writableStateSet = getWritableStateSet(node);
|
writableStateSet = getWritableStateSet(node);
|
||||||
|
|
||||||
writableStateSet->removeAttribute(osg::StateAttribute::PROGRAM);
|
// user data is normally shallow copied so shared with the original stateset - we'll need to copy before edits
|
||||||
|
osg::ref_ptr<osg::UserDataContainer> writableUserData;
|
||||||
|
|
||||||
if (osg::ref_ptr<osg::StateSet> removedState = getRemovedState(*writableStateSet))
|
if (osg::ref_ptr<AddedState> addedState = getAddedState(*writableStateSet))
|
||||||
{
|
{
|
||||||
// user data is normally shallow copied so shared with the original stateset
|
|
||||||
osg::ref_ptr<osg::UserDataContainer> writableUserData;
|
|
||||||
if (mAllowedToModifyStateSets)
|
if (mAllowedToModifyStateSets)
|
||||||
writableUserData = writableStateSet->getUserDataContainer();
|
writableUserData = writableStateSet->getUserDataContainer();
|
||||||
else
|
else
|
||||||
writableUserData = getWritableUserDataContainer(*writableStateSet);
|
writableUserData = getWritableUserDataContainer(*writableStateSet);
|
||||||
|
|
||||||
|
unsigned int index = writableUserData->getUserObjectIndex("addedState");
|
||||||
|
writableUserData->removeUserObject(index);
|
||||||
|
|
||||||
|
// O(n log n) to use StateSet::removeX, but this is O(n)
|
||||||
|
for (auto itr = writableStateSet->getUniformList().begin(); itr != writableStateSet->getUniformList().end();)
|
||||||
|
{
|
||||||
|
if (addedState->hasUniform(itr->first))
|
||||||
|
writableStateSet->getUniformList().erase(itr++);
|
||||||
|
else
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto itr = writableStateSet->getModeList().begin(); itr != writableStateSet->getModeList().end();)
|
||||||
|
{
|
||||||
|
if (addedState->hasMode(itr->first))
|
||||||
|
writableStateSet->getModeList().erase(itr++);
|
||||||
|
else
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateAttributes track the StateSets they're attached to
|
||||||
|
// We don't have access to the function to do that, and can't call removeAttribute with an iterator
|
||||||
|
for (const auto& [type, member] : addedState->getAttributes())
|
||||||
|
writableStateSet->removeAttribute(type, member);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (osg::ref_ptr<osg::StateSet> removedState = getRemovedState(*writableStateSet))
|
||||||
|
{
|
||||||
|
if (!writableUserData)
|
||||||
|
{
|
||||||
|
if (mAllowedToModifyStateSets)
|
||||||
|
writableUserData = writableStateSet->getUserDataContainer();
|
||||||
|
else
|
||||||
|
writableUserData = getWritableUserDataContainer(*writableStateSet);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int index = writableUserData->getUserObjectIndex("removedState");
|
unsigned int index = writableUserData->getUserObjectIndex("removedState");
|
||||||
writableUserData->removeUserObject(index);
|
writableUserData->removeUserObject(index);
|
||||||
|
|
||||||
for (const auto& [mode, value] : removedState->getModeList())
|
writableStateSet->merge(*removedState);
|
||||||
writableStateSet->setMode(mode, value);
|
|
||||||
|
|
||||||
for (const auto& attribute : removedState->getAttributeList())
|
|
||||||
writableStateSet->setAttribute(attribute.second.first, attribute.second.second);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
extern/Base64/Base64.h
vendored
6
extern/Base64/Base64.h
vendored
|
@ -95,6 +95,12 @@ class Base64 {
|
||||||
size_t in_len = input.size();
|
size_t in_len = input.size();
|
||||||
if (in_len % 4 != 0) return "Input data size is not a multiple of 4";
|
if (in_len % 4 != 0) return "Input data size is not a multiple of 4";
|
||||||
|
|
||||||
|
if (in_len == 0)
|
||||||
|
{
|
||||||
|
out = "";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
size_t out_len = in_len / 4 * 3;
|
size_t out_len = in_len / 4 * 3;
|
||||||
if (input[in_len - 1] == '=') out_len--;
|
if (input[in_len - 1] == '=') out_len--;
|
||||||
if (input[in_len - 2] == '=') out_len--;
|
if (input[in_len - 2] == '=') out_len--;
|
||||||
|
|
|
@ -22,7 +22,7 @@ float mipmapLevel(vec2 scaleduv)
|
||||||
|
|
||||||
float coveragePreservingAlphaScale(sampler2D diffuseMap, vec2 uv)
|
float coveragePreservingAlphaScale(sampler2D diffuseMap, vec2 uv)
|
||||||
{
|
{
|
||||||
#if @alphaFunc != FUNC_ALWAYS && @alphaFunc != FUNC_NEVER
|
#if @adjustCoverage
|
||||||
vec2 textureSize;
|
vec2 textureSize;
|
||||||
#if @useGPUShader4
|
#if @useGPUShader4
|
||||||
textureSize = textureSize2D(diffuseMap, 0);
|
textureSize = textureSize2D(diffuseMap, 0);
|
||||||
|
|
Loading…
Reference in a new issue