mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-11 06:40:34 +00:00
Merge branch 'tree_and_furniture' into 'master'
Load ESM4::Tree and ESM4::Furniture See merge request OpenMW/openmw!3040
This commit is contained in:
commit
27a879de9a
@ -61,9 +61,11 @@ namespace MWClass
|
||||
ESM4Named<ESM4::Clothing>::registerSelf();
|
||||
ESM4Named<ESM4::Container>::registerSelf();
|
||||
ESM4Named<ESM4::Door>::registerSelf();
|
||||
ESM4Named<ESM4::Furniture>::registerSelf();
|
||||
ESM4Named<ESM4::Ingredient>::registerSelf();
|
||||
ESM4Named<ESM4::MiscItem>::registerSelf();
|
||||
ESM4Static::registerSelf();
|
||||
ESM4Tree::registerSelf();
|
||||
ESM4Named<ESM4::Weapon>::registerSelf();
|
||||
ESM4Light::registerSelf();
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define GAME_MWCLASS_ESM4BASE_H
|
||||
|
||||
#include <components/esm4/loadstat.hpp>
|
||||
#include <components/esm4/loadtree.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
@ -88,6 +89,15 @@ namespace MWClass
|
||||
}
|
||||
};
|
||||
|
||||
class ESM4Tree final : public MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>
|
||||
{
|
||||
friend MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>;
|
||||
ESM4Tree()
|
||||
: MWWorld::RegisteredClass<ESM4Tree, ESM4Base<ESM4::Tree>>(ESM4::Tree::sRecordId)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// For records with `mFullName` that should be shown as a tooltip.
|
||||
// All objects with a tooltip can be activated (activation can be handled in Lua).
|
||||
template <typename Record>
|
||||
|
@ -188,6 +188,9 @@ namespace MWLua
|
||||
case ESM::REC_DOOR4:
|
||||
cell.mStore->template forEachType<ESM4::Door>(visitor);
|
||||
break;
|
||||
case ESM::REC_FURN4:
|
||||
cell.mStore->template forEachType<ESM4::Furniture>(visitor);
|
||||
break;
|
||||
case ESM::REC_INGR4:
|
||||
cell.mStore->template forEachType<ESM4::Ingredient>(visitor);
|
||||
break;
|
||||
@ -203,6 +206,9 @@ namespace MWLua
|
||||
case ESM::REC_STAT4:
|
||||
cell.mStore->template forEachType<ESM4::Static>(visitor);
|
||||
break;
|
||||
case ESM::REC_TREE4:
|
||||
cell.mStore->template forEachType<ESM4::Tree>(visitor);
|
||||
break;
|
||||
case ESM::REC_WEAP4:
|
||||
cell.mStore->template forEachType<ESM4::Weapon>(visitor);
|
||||
break;
|
||||
|
@ -40,11 +40,13 @@ namespace MWLua
|
||||
constexpr std::string_view ESM4Clothing = "ESM4Clothing";
|
||||
constexpr std::string_view ESM4Container = "ESM4Container";
|
||||
constexpr std::string_view ESM4Door = "ESM4Door";
|
||||
constexpr std::string_view ESM4Furniture = "ESM4Furniture";
|
||||
constexpr std::string_view ESM4Ingredient = "ESM4Ingredient";
|
||||
constexpr std::string_view ESM4Light = "ESM4Light";
|
||||
constexpr std::string_view ESM4MiscItem = "ESM4Miscellaneous";
|
||||
constexpr std::string_view ESM4Potion = "ESM4Potion";
|
||||
constexpr std::string_view ESM4Static = "ESM4Static";
|
||||
constexpr std::string_view ESM4Tree = "ESM4Tree";
|
||||
constexpr std::string_view ESM4Weapon = "ESM4Weapon";
|
||||
}
|
||||
|
||||
@ -79,11 +81,13 @@ namespace MWLua
|
||||
{ ESM::REC_CLOT4, ObjectTypeName::ESM4Clothing },
|
||||
{ ESM::REC_CONT4, ObjectTypeName::ESM4Container },
|
||||
{ ESM::REC_DOOR4, ObjectTypeName::ESM4Door },
|
||||
{ ESM::REC_FURN4, ObjectTypeName::ESM4Furniture },
|
||||
{ ESM::REC_INGR4, ObjectTypeName::ESM4Ingredient },
|
||||
{ ESM::REC_LIGH4, ObjectTypeName::ESM4Light },
|
||||
{ ESM::REC_MISC4, ObjectTypeName::ESM4MiscItem },
|
||||
{ ESM::REC_ALCH4, ObjectTypeName::ESM4Potion },
|
||||
{ ESM::REC_STAT4, ObjectTypeName::ESM4Static },
|
||||
{ ESM::REC_TREE4, ObjectTypeName::ESM4Tree },
|
||||
{ ESM::REC_WEAP4, ObjectTypeName::ESM4Weapon },
|
||||
};
|
||||
}
|
||||
@ -210,11 +214,13 @@ namespace MWLua
|
||||
addType(ObjectTypeName::ESM4Clothing, { ESM::REC_CLOT4 });
|
||||
addType(ObjectTypeName::ESM4Container, { ESM::REC_CONT4 });
|
||||
addESM4DoorBindings(addType(ObjectTypeName::ESM4Door, { ESM::REC_DOOR4 }), context);
|
||||
addType(ObjectTypeName::ESM4Furniture, { ESM::REC_FURN4 });
|
||||
addType(ObjectTypeName::ESM4Ingredient, { ESM::REC_INGR4 });
|
||||
addType(ObjectTypeName::ESM4Light, { ESM::REC_LIGH4 });
|
||||
addType(ObjectTypeName::ESM4MiscItem, { ESM::REC_MISC4 });
|
||||
addType(ObjectTypeName::ESM4Potion, { ESM::REC_ALCH4 });
|
||||
addType(ObjectTypeName::ESM4Static, { ESM::REC_STAT4 });
|
||||
addType(ObjectTypeName::ESM4Tree, { ESM::REC_TREE4 });
|
||||
addType(ObjectTypeName::ESM4Weapon, { ESM::REC_WEAP4 });
|
||||
|
||||
sol::table typeToPackage = getTypeToPackageTable(context.mLua->sol());
|
||||
|
@ -172,6 +172,7 @@ namespace MWRender
|
||||
stateset->addUniform(new osg::Uniform("isReflection", false));
|
||||
stateset->addUniform(new osg::Uniform("windSpeed", 0.0f));
|
||||
stateset->addUniform(new osg::Uniform("playerPos", osg::Vec3f(0.f, 0.f, 0.f)));
|
||||
stateset->addUniform(new osg::Uniform("useTreeAnim", false));
|
||||
}
|
||||
|
||||
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override
|
||||
|
@ -68,8 +68,10 @@ namespace ESM4
|
||||
struct Clothing;
|
||||
struct Container;
|
||||
struct Door;
|
||||
struct Furniture;
|
||||
struct Ingredient;
|
||||
struct MiscItem;
|
||||
struct Tree;
|
||||
struct Weapon;
|
||||
}
|
||||
|
||||
@ -87,8 +89,8 @@ namespace MWWorld
|
||||
|
||||
CellRefList<ESM4::Static>, CellRefList<ESM4::Light>, CellRefList<ESM4::Activator>, CellRefList<ESM4::Potion>,
|
||||
CellRefList<ESM4::Ammunition>, CellRefList<ESM4::Armor>, CellRefList<ESM4::Book>, CellRefList<ESM4::Clothing>,
|
||||
CellRefList<ESM4::Container>, CellRefList<ESM4::Door>, CellRefList<ESM4::Ingredient>,
|
||||
CellRefList<ESM4::MiscItem>, CellRefList<ESM4::Weapon>>;
|
||||
CellRefList<ESM4::Container>, CellRefList<ESM4::Door>, CellRefList<ESM4::Ingredient>, CellRefList<ESM4::Tree>,
|
||||
CellRefList<ESM4::MiscItem>, CellRefList<ESM4::Weapon>, CellRefList<ESM4::Furniture>>;
|
||||
|
||||
/// \brief Mutable state of a cell
|
||||
class CellStore
|
||||
|
@ -286,8 +286,10 @@ namespace MWWorld
|
||||
case ESM::REC_BOOK4:
|
||||
case ESM::REC_CONT4:
|
||||
case ESM::REC_DOOR4:
|
||||
case ESM::REC_FURN4:
|
||||
case ESM::REC_INGR4:
|
||||
case ESM::REC_MISC4:
|
||||
case ESM::REC_TREE4:
|
||||
case ESM::REC_WEAP4:
|
||||
return true;
|
||||
break;
|
||||
|
@ -39,8 +39,10 @@ namespace ESM4
|
||||
struct Clothing;
|
||||
struct Container;
|
||||
struct Door;
|
||||
struct Furniture;
|
||||
struct Ingredient;
|
||||
struct MiscItem;
|
||||
struct Tree;
|
||||
struct Weapon;
|
||||
struct World;
|
||||
struct Land;
|
||||
@ -122,7 +124,7 @@ namespace MWWorld
|
||||
Store<ESM4::Static>, Store<ESM4::Cell>, Store<ESM4::Light>, Store<ESM4::Reference>, Store<ESM4::Activator>,
|
||||
Store<ESM4::Potion>, Store<ESM4::Ammunition>, Store<ESM4::Armor>, Store<ESM4::Book>, Store<ESM4::Clothing>,
|
||||
Store<ESM4::Container>, Store<ESM4::Door>, Store<ESM4::Ingredient>, Store<ESM4::MiscItem>,
|
||||
Store<ESM4::Weapon>, Store<ESM4::World>, Store<ESM4::Land>>;
|
||||
Store<ESM4::Tree>, Store<ESM4::Weapon>, Store<ESM4::World>, Store<ESM4::Furniture>, Store<ESM4::Land>>;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
|
@ -1344,9 +1344,11 @@ template class MWWorld::TypedDynamicStore<ESM4::Book>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Clothing>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Container>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Door>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Furniture>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Ingredient>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::MiscItem>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Static>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Tree>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Light>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Reference, ESM::FormId>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Cell>;
|
||||
|
@ -299,6 +299,7 @@ namespace
|
||||
Nif::NiSkinInstance mNiSkinInstance;
|
||||
Nif::NiStringExtraData mNiStringExtraData;
|
||||
Nif::NiStringExtraData mNiStringExtraData2;
|
||||
Nif::NiIntegerExtraData mNiIntegerExtraData;
|
||||
Nif::Controller mController;
|
||||
btTransform mTransform{ btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(1, 2, 3) };
|
||||
btTransform mTransformScale2{ btMatrix3x3(btQuaternion(btVector3(1, 0, 0), 0.5f)), btVector3(2, 4, 6) };
|
||||
@ -1157,6 +1158,25 @@ namespace
|
||||
EXPECT_EQ(*result, expected);
|
||||
}
|
||||
|
||||
TEST_F(TestBulletNifLoader, bsx_editor_marker_flag_disables_collision)
|
||||
{
|
||||
mNiIntegerExtraData.data = 32; // BSX flag "editor marker"
|
||||
mNiIntegerExtraData.recType = Nif::RC_BSXFlags;
|
||||
mNiTriShape.extralist.push_back(Nif::ExtraPtr(&mNiIntegerExtraData));
|
||||
mNiTriShape.parents.push_back(&mNiNode);
|
||||
mNiNode.children = Nif::NodeList(std::vector<Nif::NodePtr>({ Nif::NodePtr(&mNiTriShape) }));
|
||||
|
||||
Nif::NIFFile file("test.nif");
|
||||
file.mRoots.push_back(&mNiNode);
|
||||
file.mHash = mHash;
|
||||
|
||||
const auto result = mLoader.load(file);
|
||||
|
||||
Resource::BulletShape expected;
|
||||
|
||||
EXPECT_EQ(*result, expected);
|
||||
}
|
||||
|
||||
TEST_F(TestBulletNifLoader,
|
||||
for_tri_shape_child_node_with_extra_data_string_mrk_and_other_collision_node_should_return_shape_with_triangle_mesh_shape_with_all_meshes)
|
||||
{
|
||||
|
@ -52,11 +52,13 @@
|
||||
#include <components/esm4/loadclot.hpp>
|
||||
#include <components/esm4/loadcont.hpp>
|
||||
#include <components/esm4/loaddoor.hpp>
|
||||
#include <components/esm4/loadfurn.hpp>
|
||||
#include <components/esm4/loadingr.hpp>
|
||||
#include <components/esm4/loadligh.hpp>
|
||||
#include <components/esm4/loadmisc.hpp>
|
||||
#include <components/esm4/loadrefr.hpp>
|
||||
#include <components/esm4/loadstat.hpp>
|
||||
#include <components/esm4/loadtree.hpp>
|
||||
#include <components/esm4/loadweap.hpp>
|
||||
|
||||
#include "defs.hpp"
|
||||
|
@ -33,8 +33,7 @@
|
||||
|
||||
void ESM4::Furniture::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.getFormId();
|
||||
reader.adjustFormId(mFormId);
|
||||
mId = reader.getRefIdFromHeader();
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
|
@ -30,6 +30,9 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
|
||||
#include "formid.hpp"
|
||||
|
||||
namespace ESM4
|
||||
@ -39,7 +42,7 @@ namespace ESM4
|
||||
|
||||
struct Furniture
|
||||
{
|
||||
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;
|
||||
@ -55,6 +58,7 @@ namespace ESM4
|
||||
// void save(ESM4::Writer& writer) const;
|
||||
|
||||
// void blank();
|
||||
static constexpr ESM::RecNameInts sRecordId = ESM::RecNameInts::REC_FURN4;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,7 @@
|
||||
|
||||
void ESM4::Tree::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.getFormId();
|
||||
reader.adjustFormId(mFormId);
|
||||
mId = reader.getRefIdFromHeader();
|
||||
mFlags = reader.hdr().record.flags;
|
||||
|
||||
while (reader.getSubRecordHeader())
|
||||
|
@ -30,7 +30,8 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "formid.hpp"
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
|
||||
namespace ESM4
|
||||
{
|
||||
@ -39,7 +40,7 @@ namespace ESM4
|
||||
|
||||
struct Tree
|
||||
{
|
||||
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;
|
||||
@ -53,6 +54,7 @@ namespace ESM4
|
||||
// void save(ESM4::Writer& writer) const;
|
||||
|
||||
// void blank();
|
||||
static constexpr ESM::RecNameInts sRecordId = ESM::RecNameInts::REC_TREE4;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,9 @@ namespace Nif
|
||||
unsigned int type{ 0u }, flags1{ 0u }, flags2{ 0u };
|
||||
float envMapIntensity{ 0.f };
|
||||
void read(NIFStream* nif) override;
|
||||
|
||||
bool doubleSided() const { return (flags2 >> 4) & 1; }
|
||||
bool treeAnim() const { return (flags2 >> 29) & 1; }
|
||||
};
|
||||
|
||||
struct BSShaderLightingProperty : public BSShaderProperty
|
||||
|
@ -301,7 +301,13 @@ namespace NifBullet
|
||||
<< ". Treating it as a common NiTriShape.";
|
||||
|
||||
// Check for extra data
|
||||
std::vector<Nif::ExtraPtr> extraCollection;
|
||||
for (Nif::ExtraPtr e = node.extra; !e.empty(); e = e->next)
|
||||
extraCollection.emplace_back(e);
|
||||
for (const auto& extraNode : node.extralist)
|
||||
if (!extraNode.empty())
|
||||
extraCollection.emplace_back(extraNode);
|
||||
for (const auto& e : extraCollection)
|
||||
{
|
||||
if (e->recType == Nif::RC_NiStringExtraData)
|
||||
{
|
||||
@ -326,6 +332,12 @@ namespace NifBullet
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (e->recType == Nif::RC_BSXFlags)
|
||||
{
|
||||
auto bsxFlags = static_cast<const Nif::NiIntegerExtraData*>(e.getPtr());
|
||||
if (bsxFlags->data & 32) // Editor marker flag
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isCollisionNode)
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <components/nif/effect.hpp>
|
||||
#include <components/nif/exception.hpp>
|
||||
#include <components/nif/extra.hpp>
|
||||
#include <components/nif/niffile.hpp>
|
||||
#include <components/nif/node.hpp>
|
||||
#include <components/nif/property.hpp>
|
||||
#include <components/sceneutil/morphgeometry.hpp>
|
||||
@ -318,6 +319,19 @@ namespace NifOsg
|
||||
}
|
||||
}
|
||||
|
||||
struct HandleNodeArgs
|
||||
{
|
||||
unsigned int mNifVersion;
|
||||
Resource::ImageManager* mImageManager;
|
||||
SceneUtil::TextKeyMap* mTextKeys;
|
||||
std::vector<unsigned int> mBoundTextures = {};
|
||||
int mAnimFlags = 0;
|
||||
bool mSkipMeshes = false;
|
||||
bool mHasMarkers = false;
|
||||
bool mHasAnimatedParents = false;
|
||||
osg::Node* mRootNode = nullptr;
|
||||
};
|
||||
|
||||
osg::ref_ptr<osg::Node> load(Nif::FileView nif, Resource::ImageManager* imageManager)
|
||||
{
|
||||
const size_t numRoots = nif.numRoots();
|
||||
@ -340,8 +354,10 @@ namespace NifOsg
|
||||
created->setDataVariance(osg::Object::STATIC);
|
||||
for (const Nif::Node* root : roots)
|
||||
{
|
||||
auto node = handleNode(root, nullptr, nullptr, imageManager, std::vector<unsigned int>(), 0, false,
|
||||
false, false, &textkeys->mTextKeys);
|
||||
auto node = handleNode(root, nullptr, nullptr,
|
||||
{ .mNifVersion = nif.getVersion(),
|
||||
.mImageManager = imageManager,
|
||||
.mTextKeys = &textkeys->mTextKeys });
|
||||
created->addChild(node);
|
||||
}
|
||||
if (mHasNightDayLabel)
|
||||
@ -597,12 +613,10 @@ namespace NifOsg
|
||||
return node;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
|
||||
Resource::ImageManager* imageManager, std::vector<unsigned int> boundTextures, int animflags,
|
||||
bool skipMeshes, bool hasMarkers, bool hasAnimatedParents, SceneUtil::TextKeyMap* textKeys,
|
||||
osg::Node* rootNode = nullptr)
|
||||
osg::ref_ptr<osg::Node> handleNode(
|
||||
const Nif::Node* nifNode, const Nif::Parent* parent, osg::Group* parentNode, HandleNodeArgs args)
|
||||
{
|
||||
if (rootNode != nullptr && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box"))
|
||||
if (args.mRootNode && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box"))
|
||||
return nullptr;
|
||||
|
||||
osg::ref_ptr<osg::Group> node = createNode(nifNode);
|
||||
@ -617,8 +631,8 @@ namespace NifOsg
|
||||
if (parentNode)
|
||||
parentNode->addChild(node);
|
||||
|
||||
if (!rootNode)
|
||||
rootNode = node;
|
||||
if (!args.mRootNode)
|
||||
args.mRootNode = node;
|
||||
|
||||
// The original NIF record index is used for a variety of features:
|
||||
// - finding the correct emitter node for a particle system
|
||||
@ -637,10 +651,10 @@ namespace NifOsg
|
||||
|
||||
for (const auto& e : extraCollection)
|
||||
{
|
||||
if (e->recType == Nif::RC_NiTextKeyExtraData && textKeys)
|
||||
if (e->recType == Nif::RC_NiTextKeyExtraData && args.mTextKeys)
|
||||
{
|
||||
const Nif::NiTextKeyExtraData* tk = static_cast<const Nif::NiTextKeyExtraData*>(e.getPtr());
|
||||
extractTextKeys(tk, *textKeys);
|
||||
extractTextKeys(tk, *args.mTextKeys);
|
||||
}
|
||||
else if (e->recType == Nif::RC_NiStringExtraData)
|
||||
{
|
||||
@ -653,7 +667,7 @@ namespace NifOsg
|
||||
if (sd->string == "MRK" && !Loader::getShowMarkers())
|
||||
{
|
||||
// Marker objects. These meshes are only visible in the editor.
|
||||
hasMarkers = true;
|
||||
args.mHasMarkers = true;
|
||||
}
|
||||
else if (sd->string == "BONE")
|
||||
{
|
||||
@ -665,10 +679,16 @@ namespace NifOsg
|
||||
Misc::OsgUserValues::sExtraData, sd->string.substr(extraDataIdentifer.length()));
|
||||
}
|
||||
}
|
||||
else if (e->recType == Nif::RC_BSXFlags)
|
||||
{
|
||||
auto bsxFlags = static_cast<const Nif::NiIntegerExtraData*>(e.getPtr());
|
||||
if (bsxFlags->data & 32) // Editor marker flag
|
||||
args.mHasMarkers = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nifNode->recType == Nif::RC_NiBSAnimationNode || nifNode->recType == Nif::RC_NiBSParticleNode)
|
||||
animflags = nifNode->flags;
|
||||
args.mAnimFlags = nifNode->flags;
|
||||
|
||||
if (nifNode->recType == Nif::RC_NiSortAdjustNode)
|
||||
{
|
||||
@ -692,7 +712,7 @@ namespace NifOsg
|
||||
// We still need to animate the hidden bones so the physics system can access them
|
||||
if (nifNode->recType == Nif::RC_RootCollisionNode)
|
||||
{
|
||||
skipMeshes = true;
|
||||
args.mSkipMeshes = true;
|
||||
node->setNodeMask(Loader::getHiddenNodeMask());
|
||||
}
|
||||
|
||||
@ -709,8 +729,8 @@ namespace NifOsg
|
||||
}
|
||||
|
||||
if (!hasVisController)
|
||||
skipMeshes = true; // skip child meshes, but still create the child node hierarchy for animating
|
||||
// collision shapes
|
||||
args.mSkipMeshes = true; // skip child meshes, but still create the child node hierarchy for
|
||||
// animating collision shapes
|
||||
|
||||
node->setNodeMask(Loader::getHiddenNodeMask());
|
||||
}
|
||||
@ -720,37 +740,44 @@ namespace NifOsg
|
||||
|
||||
osg::ref_ptr<SceneUtil::CompositeStateSetUpdater> composite = new SceneUtil::CompositeStateSetUpdater;
|
||||
|
||||
applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags);
|
||||
applyNodeProperties(nifNode, node, composite, args.mImageManager, args.mBoundTextures, args.mAnimFlags);
|
||||
|
||||
const bool isGeometry = isTypeGeometry(nifNode->recType);
|
||||
|
||||
if (isGeometry && !skipMeshes)
|
||||
if (isGeometry && !args.mSkipMeshes)
|
||||
{
|
||||
const bool isMarker = hasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "tri editormarker");
|
||||
if (!isMarker && !Misc::StringUtils::ciStartsWith(nifNode->name, "shadow")
|
||||
&& !Misc::StringUtils::ciStartsWith(nifNode->name, "tri shadow"))
|
||||
bool skip;
|
||||
if (args.mNifVersion <= Nif::NIFFile::NIFVersion::VER_MW)
|
||||
{
|
||||
skip = (args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "tri editormarker"))
|
||||
|| Misc::StringUtils::ciStartsWith(nifNode->name, "shadow")
|
||||
|| Misc::StringUtils::ciStartsWith(nifNode->name, "tri shadow");
|
||||
}
|
||||
else
|
||||
skip = args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->name, "EditorMarker");
|
||||
if (!skip)
|
||||
{
|
||||
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin;
|
||||
|
||||
if (skin.empty())
|
||||
handleGeometry(nifNode, parent, node, composite, boundTextures, animflags);
|
||||
handleGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||
else
|
||||
handleSkinnedGeometry(nifNode, parent, node, composite, boundTextures, animflags);
|
||||
handleSkinnedGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||
|
||||
if (!nifNode->controller.empty())
|
||||
handleMeshControllers(nifNode, node, composite, boundTextures, animflags);
|
||||
handleMeshControllers(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||
}
|
||||
}
|
||||
|
||||
if (nifNode->recType == Nif::RC_NiParticles)
|
||||
handleParticleSystem(nifNode, parent, node, composite, animflags);
|
||||
handleParticleSystem(nifNode, parent, node, composite, args.mAnimFlags);
|
||||
|
||||
if (composite->getNumControllers() > 0)
|
||||
{
|
||||
osg::Callback* cb = composite;
|
||||
if (composite->getNumControllers() == 1)
|
||||
cb = composite->getController(0);
|
||||
if (animflags & Nif::NiNode::AnimFlag_AutoPlay)
|
||||
if (args.mAnimFlags & Nif::NiNode::AnimFlag_AutoPlay)
|
||||
node->addCullCallback(cb);
|
||||
else
|
||||
node->addUpdateCallback(
|
||||
@ -758,10 +785,10 @@ namespace NifOsg
|
||||
}
|
||||
|
||||
bool isAnimated = false;
|
||||
handleNodeControllers(nifNode, node, animflags, isAnimated);
|
||||
hasAnimatedParents |= isAnimated;
|
||||
handleNodeControllers(nifNode, node, args.mAnimFlags, isAnimated);
|
||||
args.mHasAnimatedParents |= isAnimated;
|
||||
// Make sure empty nodes and animated shapes are not optimized away so the physics system can find them.
|
||||
if (isAnimated || (hasAnimatedParents && ((skipMeshes || hasMarkers) || isGeometry)))
|
||||
if (isAnimated || (args.mHasAnimatedParents && ((args.mSkipMeshes || args.mHasMarkers) || isGeometry)))
|
||||
node->setDataVariance(osg::Object::DYNAMIC);
|
||||
|
||||
// LOD and Switch nodes must be wrapped by a transform (the current node) to support transformations
|
||||
@ -802,8 +829,7 @@ namespace NifOsg
|
||||
const Nif::Parent currentParent{ *ninode, parent };
|
||||
for (const auto& child : children)
|
||||
if (!child.empty())
|
||||
handleNode(child.getPtr(), ¤tParent, currentNode, imageManager, boundTextures, animflags,
|
||||
skipMeshes, hasMarkers, hasAnimatedParents, textKeys, rootNode);
|
||||
handleNode(child.getPtr(), ¤tParent, currentNode, args);
|
||||
|
||||
// Propagate effects to the the direct subgraph instead of the node itself
|
||||
// This simulates their "affected node list" which Morrowind appears to replace with the subgraph (?)
|
||||
@ -812,7 +838,7 @@ namespace NifOsg
|
||||
if (!effect.empty())
|
||||
{
|
||||
osg::ref_ptr<osg::StateSet> effectStateSet = new osg::StateSet;
|
||||
if (handleEffect(effect.getPtr(), effectStateSet, imageManager))
|
||||
if (handleEffect(effect.getPtr(), effectStateSet, args.mImageManager))
|
||||
for (unsigned int i = 0; i < currentNode->getNumChildren(); ++i)
|
||||
currentNode->getChild(i)->getOrCreateStateSet()->merge(*effectStateSet);
|
||||
}
|
||||
@ -2143,6 +2169,8 @@ namespace NifOsg
|
||||
textureSet, texprop->clamp, node->getName(), stateset, imageManager, boundTextures);
|
||||
}
|
||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||
if (texprop->doubleSided())
|
||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
break;
|
||||
}
|
||||
case Nif::RC_BSShaderNoLightingProperty:
|
||||
@ -2183,6 +2211,8 @@ namespace NifOsg
|
||||
stateset->addUniform(new osg::Uniform("useFalloff", false));
|
||||
}
|
||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||
if (texprop->doubleSided())
|
||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
break;
|
||||
}
|
||||
case Nif::RC_BSLightingShaderProperty:
|
||||
@ -2196,6 +2226,10 @@ namespace NifOsg
|
||||
handleTextureSet(texprop->mTextureSet.getPtr(), texprop->mClamp, node->getName(), stateset,
|
||||
imageManager, boundTextures);
|
||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||
if (texprop->doubleSided())
|
||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
if (texprop->treeAnim())
|
||||
stateset->addUniform(new osg::Uniform("useTreeAnim", true));
|
||||
break;
|
||||
}
|
||||
case Nif::RC_BSEffectShaderProperty:
|
||||
@ -2246,6 +2280,8 @@ namespace NifOsg
|
||||
stateset->addUniform(new osg::Uniform("useFalloff", false)); // Should use the shader flag
|
||||
stateset->addUniform(new osg::Uniform("falloffParams", texprop->mFalloffParams));
|
||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||
if (texprop->doubleSided())
|
||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
break;
|
||||
}
|
||||
// unused by mw
|
||||
|
@ -38,6 +38,7 @@ uniform float far;
|
||||
uniform float alphaRef;
|
||||
uniform float emissiveMult;
|
||||
uniform float specStrength;
|
||||
uniform bool useTreeAnim;
|
||||
|
||||
#include "lib/light/lighting.glsl"
|
||||
#include "lib/material/alpha.glsl"
|
||||
@ -58,7 +59,8 @@ void main()
|
||||
#endif
|
||||
|
||||
vec4 diffuseColor = getDiffuseColor();
|
||||
gl_FragData[0].a *= diffuseColor.a;
|
||||
if (!useTreeAnim)
|
||||
gl_FragData[0].a *= diffuseColor.a;
|
||||
gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef);
|
||||
|
||||
#if @normalMap
|
||||
|
@ -5,6 +5,7 @@ varying vec2 diffuseMapUV;
|
||||
varying float alphaPassthrough;
|
||||
|
||||
uniform int colorMode;
|
||||
uniform bool useTreeAnim;
|
||||
uniform bool useDiffuseMapForShadowAlpha = true;
|
||||
uniform bool alphaTestShadows = true;
|
||||
|
||||
@ -20,7 +21,7 @@ void main(void)
|
||||
else
|
||||
diffuseMapUV = vec2(0.0); // Avoid undefined behaviour if running on hardware predating the concept of dynamically uniform expressions
|
||||
if (colorMode == 2)
|
||||
alphaPassthrough = gl_Color.a;
|
||||
alphaPassthrough = useTreeAnim ? 1.0 : gl_Color.a;
|
||||
else
|
||||
// This is uniform, so if it's too low, we might be able to put the position/clip vertex outside the view frustum and skip the fragment shader and rasteriser
|
||||
alphaPassthrough = gl_FrontMaterial.diffuse.a;
|
||||
|
Loading…
x
Reference in New Issue
Block a user