diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 471ae14814..1a961374ef 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -85,6 +85,8 @@ file(GLOB UNITTEST_SRC_FILES fx/technique.cpp esm3/readerscache.cpp + + nifosg/testnifloader.cpp ) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) diff --git a/apps/openmw_test_suite/nifosg/testnifloader.cpp b/apps/openmw_test_suite/nifosg/testnifloader.cpp new file mode 100644 index 0000000000..5671227f80 --- /dev/null +++ b/apps/openmw_test_suite/nifosg/testnifloader.cpp @@ -0,0 +1,231 @@ +#include "../nif/node.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + using namespace testing; + using namespace NifOsg; + using namespace Nif::Testing; + + struct BaseNifOsgLoaderTest + { + VFS::Manager mVfs{ false }; + Resource::ImageManager mImageManager{ &mVfs }; + const osgDB::ReaderWriter* mReaderWriter = osgDB::Registry::instance()->getReaderWriterForExtension("osgt"); + osg::ref_ptr mOptions = new osgDB::Options; + + BaseNifOsgLoaderTest() + { + SceneUtil::registerSerializers(); + + if (mReaderWriter == nullptr) + throw std::runtime_error("osgt reader writer is not found"); + + mOptions->setPluginStringData("fileType", "Ascii"); + mOptions->setPluginStringData("WriteImageHint", "UseExternal"); + } + + std::string serialize(const osg::Node& node) const + { + std::stringstream stream; + mReaderWriter->writeNode(node, stream, mOptions); + std::string result; + for (std::string line; std::getline(stream, line);) + { + if (line.starts_with('#')) + continue; + boost::trim_right(line); + result += line; + result += '\n'; + } + return result; + } + }; + + struct NifOsgLoaderTest : Test, BaseNifOsgLoaderTest + { + }; + + TEST_F(NifOsgLoaderTest, shouldLoadFileWithDefaultNode) + { + Nif::Node node; + init(node); + Nif::NIFFile file("test.nif"); + file.mRoots.push_back(&node); + auto result = Loader::load(file, &mImageManager); + EXPECT_EQ(serialize(*result), R"( +osg::Group { + UniqueID 1 + DataVariance STATIC + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 2 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 3 + Name "fileHash" + } + } + } + } + Children 1 { + osg::Group { + UniqueID 4 + DataVariance STATIC + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 5 + UDC_UserObjects 1 { + osg::UIntValueObject { + UniqueID 6 + Name "recIndex" + Value 4294967295 + } + } + } + } + } + } +} +)"); + } + + std::string formatOsgNodeForShaderProperty(std::string_view shaderPrefix) + { + static constexpr const char format[] = R"( +osg::Group { + UniqueID 1 + DataVariance STATIC + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 2 + UDC_UserObjects 1 { + osg::StringValueObject { + UniqueID 3 + Name "fileHash" + } + } + } + } + Children 1 { + osg::Group { + UniqueID 4 + DataVariance STATIC + UserDataContainer TRUE { + osg::DefaultUserDataContainer { + UniqueID 5 + UDC_UserObjects 3 { + osg::UIntValueObject { + UniqueID 6 + Name "recIndex" + Value 4294967295 + } + osg::StringValueObject { + UniqueID 7 + Name "shaderPrefix" + Value "%s" + } + osg::BoolValueObject { + UniqueID 8 + Name "shaderRequired" + Value TRUE + } + } + } + } + StateSet TRUE { + osg::StateSet { + UniqueID 9 + } + } + } + } +} +)"; + return (boost::format(format) % shaderPrefix).str(); + } + + struct ShaderPrefixParams + { + unsigned int mShaderType; + std::string_view mExpectedShaderPrefix; + }; + + struct NifOsgLoaderBSShaderPrefixTest : TestWithParam, BaseNifOsgLoaderTest + { + static constexpr std::array sParams = { + ShaderPrefixParams{ static_cast(Nif::BSShaderType::ShaderType_Default), "nv_default" }, + ShaderPrefixParams{ static_cast(Nif::BSShaderType::ShaderType_NoLighting), "nv_nolighting" }, + ShaderPrefixParams{ static_cast(Nif::BSShaderType::ShaderType_Tile), "nv_default" }, + ShaderPrefixParams{ std::numeric_limits::max(), "nv_default" }, + }; + }; + + TEST_P(NifOsgLoaderBSShaderPrefixTest, shouldAddShaderPrefix) + { + Nif::Node node; + init(node); + Nif::BSShaderPPLightingProperty property; + property.recType = Nif::RC_BSShaderPPLightingProperty; + property.textureSet = nullptr; + property.controller = nullptr; + property.type = GetParam().mShaderType; + node.props.push_back(Nif::RecordPtrT(&property)); + Nif::NIFFile file("test.nif"); + file.mRoots.push_back(&node); + auto result = Loader::load(file, &mImageManager); + EXPECT_EQ(serialize(*result), formatOsgNodeForShaderProperty(GetParam().mExpectedShaderPrefix)); + } + + INSTANTIATE_TEST_SUITE_P(Params, NifOsgLoaderBSShaderPrefixTest, ValuesIn(NifOsgLoaderBSShaderPrefixTest::sParams)); + + struct NifOsgLoaderBSLightingShaderPrefixTest : TestWithParam, BaseNifOsgLoaderTest + { + static constexpr std::array sParams = { + ShaderPrefixParams{ + static_cast(Nif::BSLightingShaderType::ShaderType_Default), "nv_default" }, + ShaderPrefixParams{ static_cast(Nif::BSLightingShaderType::ShaderType_Cloud), "nv_default" }, + ShaderPrefixParams{ std::numeric_limits::max(), "nv_default" }, + }; + }; + + TEST_P(NifOsgLoaderBSLightingShaderPrefixTest, shouldAddShaderPrefix) + { + Nif::Node node; + init(node); + Nif::BSLightingShaderProperty property; + property.recType = Nif::RC_BSLightingShaderProperty; + property.mTextureSet = nullptr; + property.controller = nullptr; + property.type = GetParam().mShaderType; + node.props.push_back(Nif::RecordPtrT(&property)); + Nif::NIFFile file("test.nif"); + file.mRoots.push_back(&node); + auto result = Loader::load(file, &mImageManager); + EXPECT_EQ(serialize(*result), formatOsgNodeForShaderProperty(GetParam().mExpectedShaderPrefix)); + } + + INSTANTIATE_TEST_SUITE_P( + Params, NifOsgLoaderBSLightingShaderPrefixTest, ValuesIn(NifOsgLoaderBSLightingShaderPrefixTest::sParams)); +}