diff --git a/CMakeLists.txt b/CMakeLists.txt index bb401d38e6..bcb27f7649 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 49) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 68) +set(OPENMW_LUA_API_REVISION 69) set(OPENMW_POSTPROCESSING_API_REVISION 2) set(OPENMW_VERSION_COMMITHASH "") diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 904b96c463..dae7bfe062 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -516,7 +516,7 @@ namespace MWBase virtual void spawnBloodEffect(const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0; virtual void spawnEffect(VFS::Path::NormalizedView model, const std::string& textureOverride, - const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) + const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true, bool useAmbientLight = false) = 0; /// @see MWWorld::WeatherManager::isInStorm diff --git a/apps/openmw/mwlua/animationbindings.cpp b/apps/openmw/mwlua/animationbindings.cpp index b74a3e51c3..daf3bd5340 100644 --- a/apps/openmw/mwlua/animationbindings.cpp +++ b/apps/openmw/mwlua/animationbindings.cpp @@ -267,10 +267,11 @@ namespace MWLua [object = ObjectVariant(object), model = std::string(model), effectId = options->get_or("vfxId", ""), loop = options->get_or("loop", false), boneName = options->get_or("boneName", ""), - particleTexture = options->get_or("particleTextureOverride", "")] { + particleTexture = options->get_or("particleTextureOverride", ""), + useAmbientLight = options->get_or("useAmbientLight", true)] { MWRender::Animation* anim = getMutableAnimationOrThrow(ObjectVariant(object)); - anim->addEffect(model, effectId, loop, boneName, particleTexture); + anim->addEffect(model, effectId, loop, boneName, particleTexture, useAmbientLight); }, "addVfxAction"); } @@ -318,15 +319,20 @@ namespace MWLua bool magicVfx = options->get_or("mwMagicVfx", true); std::string texture = options->get_or("particleTextureOverride", ""); float scale = options->get_or("scale", 1.f); + bool useAmbientLight = options->get_or("useAmbientLight", true); context.mLuaManager->addAction( [world, model = VFS::Path::Normalized(model), texture = std::move(texture), worldPos, scale, - magicVfx]() { world->spawnEffect(model, texture, worldPos, scale, magicVfx); }, + magicVfx, useAmbientLight]() { + world->spawnEffect(model, texture, worldPos, scale, magicVfx, useAmbientLight); + }, "openmw.vfx.spawn"); } else { - context.mLuaManager->addAction([world, model = VFS::Path::Normalized(model), - worldPos]() { world->spawnEffect(model, "", worldPos); }, + context.mLuaManager->addAction( + [world, model = VFS::Path::Normalized(model), worldPos]() { + world->spawnEffect(model, "", worldPos, 1.f, true, true); + }, "openmw.vfx.spawn"); } }; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2b5092087a..0a2ef7bef8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -389,22 +389,6 @@ namespace std::string_view mEffectId; }; - namespace - { - osg::ref_ptr makeVFXLightModelInstance() - { - osg::ref_ptr lightModel = new osg::LightModel; - lightModel->setAmbientIntensity({ 1, 1, 1, 1 }); - return lightModel; - } - - const osg::ref_ptr& getVFXLightModelInstance() - { - static const osg::ref_ptr lightModel = makeVFXLightModelInstance(); - return lightModel; - } - } - void assignBoneBlendCallbackRecursive(MWRender::BoneAnimBlendController* controller, osg::Node* parent, bool isRoot) { // Attempt to cast node to an osgAnimation::Bone @@ -1725,7 +1709,7 @@ namespace MWRender } void Animation::addEffect(std::string_view model, std::string_view effectId, bool loop, std::string_view bonename, - std::string_view texture) + std::string_view texture, bool useAmbientLight) { if (!mObjectRoot.get()) return; @@ -1778,10 +1762,15 @@ namespace MWRender osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(VFS::Path::toNormalized(model), trans); - // Morrowind has a white ambient light attached to the root VFX node of the scenegraph - node->getOrCreateStateSet()->setAttributeAndModes( - getVFXLightModelInstance(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + if (useAmbientLight) + { + // Morrowind has a white ambient light attached to the root VFX node of the scenegraph + node->getOrCreateStateSet()->setAttributeAndModes( + getVFXLightModelInstance(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + } + mResourceSystem->getSceneManager()->setUpNormalsRTForStateSet(node->getOrCreateStateSet(), false); + SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor; node->accept(findMaxLengthVisitor); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d398c5b727..b6cb6f333c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -342,10 +342,13 @@ namespace MWRender * you need to remove it manually using removeEffect when the effect should end. * @param bonename Bone to attach to, or empty string to use the scene node instead * @param texture override the texture specified in the model's materials - if empty, do not override + * @param useAmbientLight attach white ambient light to the root VFX node of the scenegraph (Morrowind + * default) * @note Will not add an effect twice. */ void addEffect(std::string_view model, std::string_view effectId, bool loop = false, - std::string_view bonename = {}, std::string_view texture = {}); + std::string_view bonename = {}, std::string_view texture = {}, bool useAmbientLight = true); + void removeEffect(std::string_view effectId); void removeEffects(); std::vector getLoopingEffects() const; diff --git a/apps/openmw/mwrender/effectmanager.cpp b/apps/openmw/mwrender/effectmanager.cpp index 0ac509742c..927f3f7ad0 100644 --- a/apps/openmw/mwrender/effectmanager.cpp +++ b/apps/openmw/mwrender/effectmanager.cpp @@ -28,7 +28,7 @@ namespace MWRender } void EffectManager::addEffect(VFS::Path::NormalizedView model, std::string_view textureOverride, - const osg::Vec3f& worldPosition, float scale, bool isMagicVFX) + const osg::Vec3f& worldPosition, float scale, bool isMagicVFX, bool useAmbientLight) { osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(model); @@ -58,6 +58,15 @@ namespace MWRender mParentNode->addChild(trans); + if (useAmbientLight) + { + // Morrowind has a white ambient light attached to the root VFX node of the scenegraph + node->getOrCreateStateSet()->setAttributeAndModes( + getVFXLightModelInstance(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + } + + mResourceSystem->getSceneManager()->setUpNormalsRTForStateSet(node->getOrCreateStateSet(), false); + mEffects.push_back(std::move(effect)); } diff --git a/apps/openmw/mwrender/effectmanager.hpp b/apps/openmw/mwrender/effectmanager.hpp index 671c441a59..b1e123c0b0 100644 --- a/apps/openmw/mwrender/effectmanager.hpp +++ b/apps/openmw/mwrender/effectmanager.hpp @@ -35,7 +35,7 @@ namespace MWRender /// Add an effect. When it's finished playing, it will be removed automatically. void addEffect(VFS::Path::NormalizedView model, std::string_view textureOverride, - const osg::Vec3f& worldPosition, float scale, bool isMagicVFX = true); + const osg::Vec3f& worldPosition, float scale, bool isMagicVFX = true, bool useAmbientLight = false); void update(float dt); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index afb6101534..01556d9c0c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1248,9 +1248,9 @@ namespace MWRender } void RenderingManager::spawnEffect(VFS::Path::NormalizedView model, std::string_view texture, - const osg::Vec3f& worldPosition, float scale, bool isMagicVFX) + const osg::Vec3f& worldPosition, float scale, bool isMagicVFX, bool useAmbientLight) { - mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX); + mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX, useAmbientLight); } void RenderingManager::notifyWorldSpaceChanged() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index ee587f84cc..5e673f9fa3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -195,7 +195,7 @@ namespace MWRender SkyManager* getSkyManager(); void spawnEffect(VFS::Path::NormalizedView model, std::string_view texture, const osg::Vec3f& worldPosition, - float scale = 1.f, bool isMagicVFX = true); + float scale = 1.f, bool isMagicVFX = true, bool useAmbientLight = false); /// Clear all savegame-specific data void clear(); diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index c2231c31f8..1b24bbc490 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -74,4 +74,16 @@ namespace MWRender return Settings::shaders().mAntialiasAlphaTest && Settings::video().mAntialiasing > 1; } + osg::ref_ptr makeVFXLightModelInstance() + { + osg::ref_ptr lightModel = new osg::LightModel; + lightModel->setAmbientIntensity({ 1, 1, 1, 1 }); + return lightModel; + } + + const osg::ref_ptr& getVFXLightModelInstance() + { + static const osg::ref_ptr lightModel = makeVFXLightModelInstance(); + return lightModel; + } } diff --git a/apps/openmw/mwrender/util.hpp b/apps/openmw/mwrender/util.hpp index fc43680d67..bed22d2a5e 100644 --- a/apps/openmw/mwrender/util.hpp +++ b/apps/openmw/mwrender/util.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_MWRENDER_UTIL_H #define OPENMW_MWRENDER_UTIL_H +#include #include #include @@ -35,6 +36,8 @@ namespace MWRender }; bool shouldAddMSAAIntermediateTarget(); + + const osg::ref_ptr& getVFXLightModelInstance(); } #endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2ec62c4543..53beac689b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3689,9 +3689,9 @@ namespace MWWorld } void World::spawnEffect(VFS::Path::NormalizedView model, const std::string& textureOverride, - const osg::Vec3f& worldPos, float scale, bool isMagicVFX) + const osg::Vec3f& worldPos, float scale, bool isMagicVFX, bool useAmbientLight) { - mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX); + mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX, useAmbientLight); } struct ResetActorsVisitor diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0da5a7f1f7..1601111fc1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -603,7 +603,8 @@ namespace MWWorld void spawnBloodEffect(const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) override; void spawnEffect(VFS::Path::NormalizedView model, const std::string& textureOverride, - const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) override; + const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true, + bool useAmbientLight = false) override; /// @see MWWorld::WeatherManager::isInStorm bool isInStorm() const override; diff --git a/files/lua_api/openmw/animation.lua b/files/lua_api/openmw/animation.lua index 065a150605..46f3ff20fc 100644 --- a/files/lua_api/openmw/animation.lua +++ b/files/lua_api/openmw/animation.lua @@ -227,8 +227,9 @@ -- * `loop` - boolean, if true the effect will loop until removed (default: 0). -- * `boneName` - name of the bone to attach the vfx to. (default: "") -- * `particleTextureOverride` - name of the particle texture to use. (default: "") --- * `vfxId` - a string ID that can be used to remove the effect later, using #removeVfx, and to avoid duplicate effects. The default value of "" can have duplicates. To avoid interaction with the engine, use unique identifiers unrelated to magic effect IDs. The engine uses this identifier to add and remove magic effects based on what effects are active on the actor. If this is set equal to the @{openmw.core#MagicEffectId} identifier of the magic effect being added, for example core.magic.EFFECT_TYPE.FireDamage, then the engine will remove it once the fire damage effect on the actor reaches 0. (Default: ""). --- +-- * `vfxId` - a string ID that can be used to remove the effect later, using #removeVfx, and to avoid duplicate effects. The default value of "" can have duplicates. To avoid interaction with the engine, use unique identifiers unrelated to magic effect IDs. The engine uses this identifier to add and remove magic effects based on what effects are active on the actor. If this is set equal to the @{openmw.core#MagicEffectId} identifier of the magic effect being added, for example core.magic.EFFECT_TYPE.FireDamage, then the engine will remove it once the fire damage effect on the actor reaches 0. (Default: ""). +-- * `useAmbientLighting` - boolean, vfx get a white ambient light attached in Morrowind. If false don't attach this. (default: 1) +-- -- @usage local mgef = core.magic.effects.records[myEffectName] -- anim.addVfx(self, 'VFX_Hands', {boneName = 'Bip01 L Hand', particleTextureOverride = mgef.particle, loop = mgef.continuousVfx, vfxId = mgef.id..'_myuniquenamehere'}) -- -- later: diff --git a/files/lua_api/openmw/world.lua b/files/lua_api/openmw/world.lua index 3ed85e9ab5..b4925885b0 100644 --- a/files/lua_api/openmw/world.lua +++ b/files/lua_api/openmw/world.lua @@ -193,6 +193,7 @@ -- * `mwMagicVfx` - Boolean that if true causes the textureOverride parameter to only affect nodes with the Nif::RC_NiTexturingProperty property set. (default: true). -- * `particleTextureOverride` - Name of a particle texture that should override this effect's default texture. (default: "") -- * `scale` - A number that scales the size of the vfx (Default: 1) +-- * `useAmbientLighting` - boolean, vfx get a white ambient light attached in Morrowind. If false don't attach this. (default: 1) -- -- @usage -- Spawn a sanctuary effect near the player -- local effect = core.magic.effects.records[core.magic.EFFECT_TYPE.Sanctuary]