diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 833c1533e0..4887d0ef3d 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -44,8 +44,10 @@ #include "../../model/world/data.hpp" #include +#include #include #include +#include #include #include @@ -167,7 +169,7 @@ void CSVRender::Object::update() if (light) { bool isExterior = false; // FIXME - SceneUtil::addLight(mBaseNode, light, Mask_Lighting, isExterior); + SceneUtil::addLight(mBaseNode, SceneUtil::LightCommon(*light), Mask_Lighting, isExterior); } } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index cf9d76be4e..294dc9e7b6 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -90,6 +90,7 @@ add_openmw_dir (mwphysics add_openmw_dir (mwclass classes activator creature npc weapon armor potion apparatus book clothing container door ingredient creaturelevlist itemlevlist light lockpick misc probe repair static actor bodypart + light4 ) add_openmw_dir (mwmechanics diff --git a/apps/openmw/mwclass/classes.cpp b/apps/openmw/mwclass/classes.cpp index e96350294e..ca4bbee5db 100644 --- a/apps/openmw/mwclass/classes.cpp +++ b/apps/openmw/mwclass/classes.cpp @@ -13,6 +13,7 @@ #include "ingredient.hpp" #include "itemlevlist.hpp" #include "light.hpp" +#include "light4.hpp" #include "lockpick.hpp" #include "misc.hpp" #include "npc.hpp" @@ -49,5 +50,6 @@ namespace MWClass BodyPart::registerSelf(); ESM4Static::registerSelf(); + ESM4Light::registerSelf(); } } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 04d9a758c5..0465240a65 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "../mwbase/environment.hpp" @@ -242,4 +243,5 @@ namespace MWClass { return ptr.get()->mBase->mSound; } + } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 612d6f9e5e..d2e80a945a 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -78,6 +78,7 @@ namespace MWClass const ESM::RefId& getSound(const MWWorld::ConstPtr& ptr) const override; }; + } #endif diff --git a/apps/openmw/mwclass/light4.cpp b/apps/openmw/mwclass/light4.cpp new file mode 100644 index 0000000000..8e3341fbb1 --- /dev/null +++ b/apps/openmw/mwclass/light4.cpp @@ -0,0 +1,61 @@ +#include "light4.hpp" +#include "classmodel.hpp" + +#include "../mwphysics/physicssystem.hpp" +#include "../mwrender/objects.hpp" +#include "../mwrender/renderinginterface.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/ptr.hpp" + +#include + +namespace MWClass +{ + ESM4Light::ESM4Light() + : MWWorld::RegisteredClass(ESM4::Light::sRecordId) + { + } + + void ESM4Light ::insertObjectRendering( + const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const + { + MWWorld::LiveCellRef* ref = ptr.get(); + + // Insert even if model is empty, so that the light is added + renderingInterface.getObjects().insertModel(ptr, model, !(ref->mBase->mData.flags & ESM4::Light::OffDefault)); + } + + void ESM4Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const + { + insertObjectPhysics(ptr, model, rotation, physics); + } + + void ESM4Light::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const + { + physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World); + } + + std::string ESM4Light::getModel(const MWWorld::ConstPtr& ptr) const + { + return getClassModel(ptr); + } + + std::string_view ESM4Light ::getName(const MWWorld::ConstPtr& ptr) const + { + return {}; + } + + bool ESM4Light::hasToolTip(const MWWorld::ConstPtr& ptr) const + { + return false; + } + + MWWorld::Ptr ESM4Light::copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const + { + const MWWorld::LiveCellRef* ref = ptr.get(); + + return MWWorld::Ptr(cell.insert(ref), &cell); + } +} diff --git a/apps/openmw/mwclass/light4.hpp b/apps/openmw/mwclass/light4.hpp new file mode 100644 index 0000000000..6145281298 --- /dev/null +++ b/apps/openmw/mwclass/light4.hpp @@ -0,0 +1,34 @@ +#ifndef OPENW_MWCLASS_LIGHT4 +#define OPENW_MWCLASS_LIGHT4 +#include "../mwworld/registeredclass.hpp" + +namespace MWClass +{ + class ESM4Light : public MWWorld::RegisteredClass + { + friend MWWorld::RegisteredClass; + + ESM4Light(); + + MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const override; + + public: + void insertObjectRendering(const MWWorld::Ptr& ptr, const std::string& model, + MWRender::RenderingInterface& renderingInterface) const override; + ///< Add reference into a cell for rendering + + void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const override; + void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, + MWPhysics::PhysicsSystem& physics) const override; + + std::string_view getName(const MWWorld::ConstPtr& ptr) const override; + ///< \return name or ID; can return an empty string. + + bool hasToolTip(const MWWorld::ConstPtr& ptr) const override; + ///< @return true if this object has a tooltip when focused (default implementation: true) + + std::string getModel(const MWWorld::ConstPtr& ptr) const override; + }; +} +#endif diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index b2b34f1741..c71e4f0afd 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -557,7 +558,7 @@ namespace MWRender osg::Vec4f ambient(1, 1, 1, 1); osg::ref_ptr lightSource - = SceneUtil::createLightSource(esmLight, Mask_Lighting, exterior, ambient); + = SceneUtil::createLightSource(SceneUtil::LightCommon(*esmLight), Mask_Lighting, exterior, ambient); mInsert->addChild(lightSource); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 15af30de5d..9813c68a06 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,9 +23,11 @@ #include #include #include +#include #include #include #include +#include #include @@ -1510,7 +1512,7 @@ namespace MWRender } } - void Animation::addExtraLight(osg::ref_ptr parent, const ESM::Light* esmLight) + void Animation::addExtraLight(osg::ref_ptr parent, const SceneUtil::LightCommon& esmLight) { bool exterior = mPtr.isInCell() && mPtr.getCell()->getCell()->isExterior(); @@ -1854,7 +1856,9 @@ namespace MWRender mObjectRoot, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr)); } if (ptr.getType() == ESM::Light::sRecordId && allowLight) - addExtraLight(getOrCreateObjectRoot(), ptr.get()->mBase); + addExtraLight(getOrCreateObjectRoot(), SceneUtil::LightCommon(*ptr.get()->mBase)); + if (ptr.getType() == ESM4::Light::sRecordId && allowLight) + addExtraLight(getOrCreateObjectRoot(), SceneUtil::LightCommon(*ptr.get()->mBase)); if (!allowLight && mObjectRoot) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b241c3b931..ac5376fb22 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -30,6 +30,7 @@ namespace SceneUtil class LightSource; class LightListCallback; class Skeleton; + struct LightCommon; } namespace MWRender @@ -333,7 +334,7 @@ namespace MWRender void addSingleAnimSource(const std::string& model, const std::string& baseModel); /** Adds an additional light to the given node using the specified ESM record. */ - void addExtraLight(osg::ref_ptr parent, const ESM::Light* light); + void addExtraLight(osg::ref_ptr parent, const SceneUtil::LightCommon& light); void clearAnimSources(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7447b9f280..7d2a9ec0a4 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -664,7 +665,7 @@ namespace MWRender addOrReplaceIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1, Misc::ResourceHelpers::correctMeshPath(light->mModel, vfs), false, nullptr, true); if (mObjectParts[ESM::PRT_Shield]) - addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), light); + addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), SceneUtil::LightCommon(*light)); } } @@ -1041,7 +1042,8 @@ namespace MWRender if (mesh.empty()) reserveIndividualPart(ESM::PRT_Shield, MWWorld::InventoryStore::Slot_CarriedLeft, 1); if (iter->getType() == ESM::Light::sRecordId && mObjectParts[ESM::PRT_Shield]) - addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), iter->get()->mBase); + addExtraLight(mObjectParts[ESM::PRT_Shield]->getNode()->asGroup(), + SceneUtil::LightCommon(*iter->get()->mBase)); } } else diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 6078feba4c..c41fc844f9 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 9843c8a06a..eab25c21b8 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -59,6 +59,7 @@ namespace ESM4 struct Cell; struct Reference; struct Static; + struct Light; } namespace MWWorld @@ -73,7 +74,7 @@ namespace MWWorld CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, - CellRefList>; + CellRefList, CellRefList>; /// \brief Mutable state of a cell class CellStore diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 7d9fda7273..0227d6ede3 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -279,6 +280,7 @@ namespace MWWorld case ESM::REC_WEAP: case ESM::REC_BODY: case ESM::REC_STAT4: + case ESM::REC_LIGH4: return true; break; } diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 9d737c3f53..3f153d45c0 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -30,6 +30,7 @@ namespace ESM4 struct Static; struct Cell; struct Reference; + struct Light; } namespace ESM @@ -105,7 +106,7 @@ namespace MWWorld // Special entry which is hardcoded and not loaded from an ESM Store, - Store, Store, Store>; + Store, Store, Store, Store>; private: template diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 19b07c0725..a8c49e9252 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -1250,5 +1251,6 @@ template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 795a9932ae..cca5a5cd35 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e05ff978af..0af1e61a23 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -66,7 +66,7 @@ add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt - screencapture depth color riggeometryosgaextension extradata unrefqueue + screencapture depth color riggeometryosgaextension extradata unrefqueue lightcommon ) add_component_dir (nif diff --git a/components/esm4/loadligh.cpp b/components/esm4/loadligh.cpp index eb82224d66..6c222a6f60 100644 --- a/components/esm4/loadligh.cpp +++ b/components/esm4/loadligh.cpp @@ -33,8 +33,9 @@ void ESM4::Light::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.id; - reader.adjustFormId(mFormId); + FormId formId = reader.hdr().record.id; + reader.adjustFormId(formId); + mId = ESM::RefId::formIdRefId(formId); mFlags = reader.hdr().record.flags; std::uint32_t esmVer = reader.esmVersion(); bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; diff --git a/components/esm4/loadligh.hpp b/components/esm4/loadligh.hpp index fe5129f8b0..b6447853b8 100644 --- a/components/esm4/loadligh.hpp +++ b/components/esm4/loadligh.hpp @@ -32,6 +32,9 @@ #include "formid.hpp" +#include +#include + namespace ESM4 { class Reader; @@ -39,6 +42,20 @@ namespace ESM4 struct Light { + enum Flag + { + Dynamic = 0x01, + Carryable = 0x02, + Negative = 0x04, + Flicker = 0x08, + OffDefault = 0x020, + FlickerSlow = 0x040, + Pulse = 0x080, + PulseSlow = 0x100, + SpotLight = 0x200, + SpotShadow = 0x400, + }; + struct Data { std::uint32_t time; // FO/FONV only @@ -67,7 +84,7 @@ namespace ESM4 float weight; }; - FormId mFormId; // from the header + ESM::RefId mId; // from the header std::uint32_t mFlags; // from the header, see enum type RecordFlag for details std::string mEditorId; @@ -87,6 +104,8 @@ namespace ESM4 void load(ESM4::Reader& reader); // void save(ESM4::Writer& writer) const; + static constexpr ESM::RecNameInts sRecordId = ESM::REC_LIGH4; + // void blank(); }; } diff --git a/components/sceneutil/lightcommon.cpp b/components/sceneutil/lightcommon.cpp new file mode 100644 index 0000000000..03d00811e2 --- /dev/null +++ b/components/sceneutil/lightcommon.cpp @@ -0,0 +1,33 @@ + +#include "lightcommon.hpp" +#include +#include +#include + +namespace SceneUtil +{ + LightCommon::LightCommon(const ESM::Light& light) + : mFlicker(light.mData.mFlags & ESM::Light::Flicker) + , mFlickerSlow(light.mData.mFlags & ESM::Light::FlickerSlow) + , mNegative(light.mData.mFlags & ESM::Light::Negative) + , mPulse(light.mData.mFlags & ESM::Light::Pulse) + , mPulseSlow(light.mData.mFlags & ESM::Light::PulseSlow) + , mOffDefault(light.mData.mFlags & ESM::Light::OffDefault) + , mColor(SceneUtil::colourFromRGB(light.mData.mColor)) + , mRadius(light.mData.mRadius) + + { + } + LightCommon::LightCommon(const ESM4::Light& light) + : mFlicker(light.mData.flags & ESM4::Light::Flicker) + , mFlickerSlow(light.mData.flags & ESM4::Light::FlickerSlow) + , mNegative(light.mData.flags & ESM::Light::Negative) + , mPulse(light.mData.flags & ESM4::Light::Pulse) + , mPulseSlow(light.mData.flags & ESM4::Light::PulseSlow) + , mOffDefault(light.mData.flags & ESM4::Light::OffDefault) + , mColor(SceneUtil::colourFromRGB(light.mData.colour)) + , mRadius(light.mData.radius) + + { + } +} diff --git a/components/sceneutil/lightcommon.hpp b/components/sceneutil/lightcommon.hpp new file mode 100644 index 0000000000..ed86427372 --- /dev/null +++ b/components/sceneutil/lightcommon.hpp @@ -0,0 +1,38 @@ + +#ifndef COMPONENTS_SCENEUTIL_LIGHTCOMMON +#define COMPONENTS_SCENEUTIL_LIGHTCOMMON +#include +#include + +#include + +namespace ESM4 +{ + struct Light; +} + +namespace ESM +{ + struct Light; +} + +namespace SceneUtil +{ + struct LightCommon + { + explicit LightCommon(const ESM::Light& light); + explicit LightCommon(const ESM4::Light& light); + + bool mFlicker; + bool mFlickerSlow; + bool mNegative; + bool mPulse; + bool mPulseSlow; + bool mOffDefault; + + osg::Vec4 mColor; + float mRadius; + }; + +} +#endif diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 30292bea61..940c7c3ceb 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "lightcontroller.hpp" #include "lightmanager.hpp" @@ -86,7 +87,7 @@ namespace SceneUtil } osg::ref_ptr addLight( - osg::Group* node, const ESM::Light* esmLight, unsigned int lightMask, bool isExterior) + osg::Group* node, const SceneUtil::LightCommon& esmLight, unsigned int lightMask, bool isExterior) { SceneUtil::FindByNameVisitor visitor("AttachLight"); node->accept(visitor); @@ -105,19 +106,19 @@ namespace SceneUtil } osg::ref_ptr createLightSource( - const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, const osg::Vec4f& ambient) + const SceneUtil::LightCommon& esmLight, unsigned int lightMask, bool isExterior, const osg::Vec4f& ambient) { osg::ref_ptr lightSource(new SceneUtil::LightSource); osg::ref_ptr light(new osg::Light); lightSource->setNodeMask(lightMask); - float radius = esmLight->mData.mRadius; + float radius = esmLight.mRadius; lightSource->setRadius(radius); configureLight(light, radius, isExterior); - osg::Vec4f diffuse = SceneUtil::colourFromRGB(esmLight->mData.mColor); - if (esmLight->mData.mFlags & ESM::Light::Negative) + osg::Vec4f diffuse = esmLight.mColor; + if (esmLight.mNegative) { diffuse *= -1; diffuse.a() = 1; @@ -130,13 +131,13 @@ namespace SceneUtil osg::ref_ptr ctrl(new SceneUtil::LightController); ctrl->setDiffuse(light->getDiffuse()); - if (esmLight->mData.mFlags & ESM::Light::Flicker) + if (esmLight.mFlicker) ctrl->setType(SceneUtil::LightController::LT_Flicker); - if (esmLight->mData.mFlags & ESM::Light::FlickerSlow) + if (esmLight.mFlickerSlow) ctrl->setType(SceneUtil::LightController::LT_FlickerSlow); - if (esmLight->mData.mFlags & ESM::Light::Pulse) + if (esmLight.mPulse) ctrl->setType(SceneUtil::LightController::LT_Pulse); - if (esmLight->mData.mFlags & ESM::Light::PulseSlow) + if (esmLight.mPulseSlow) ctrl->setType(SceneUtil::LightController::LT_PulseSlow); lightSource->addUpdateCallback(ctrl); diff --git a/components/sceneutil/lightutil.hpp b/components/sceneutil/lightutil.hpp index cae973bb38..5dcbfa3c56 100644 --- a/components/sceneutil/lightutil.hpp +++ b/components/sceneutil/lightutil.hpp @@ -18,6 +18,7 @@ namespace ESM namespace SceneUtil { class LightSource; + struct LightCommon; /// @brief Set up global attenuation settings for an osg::Light. /// @param radius The radius of the light source. @@ -32,15 +33,15 @@ namespace SceneUtil /// @param lightMask Mask to assign to the newly created LightSource. /// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use. osg::ref_ptr addLight( - osg::Group* node, const ESM::Light* esmLight, unsigned int lightMask, bool isExterior); + osg::Group* node, const SceneUtil::LightCommon& esmLight, unsigned int lightMask, bool isExterior); /// @brief Convert an ESM::Light to a SceneUtil::LightSource, and return it. /// @param esmLight The light definition coming from the game files containing radius, color, flicker, etc. /// @param lightMask Mask to assign to the newly created LightSource. /// @param isExterior Is the light outside? May be used for deciding which attenuation settings to use. /// @param ambient Ambient component of the light. - osg::ref_ptr createLightSource(const ESM::Light* esmLight, unsigned int lightMask, bool isExterior, - const osg::Vec4f& ambient = osg::Vec4f(0, 0, 0, 1)); + osg::ref_ptr createLightSource(const SceneUtil::LightCommon& esmLight, unsigned int lightMask, + bool isExterior, const osg::Vec4f& ambient = osg::Vec4f(0, 0, 0, 1)); }