#include "../nif/node.hpp" #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; constexpr VFS::Path::NormalizedView testNif("test.nif"); struct BaseNifOsgLoaderTest { VFS::Manager mVfs; Resource::ImageManager mImageManager{ &mVfs, 0 }; Resource::BgsmFileManager mMaterialManager{ &mVfs, 0 }; 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; line.erase(line.find_last_not_of(" \t\n\r\f\v") + 1); result += line; result += '\n'; } return result; } }; struct NifOsgLoaderTest : Test, BaseNifOsgLoaderTest { }; TEST_F(NifOsgLoaderTest, shouldLoadFileWithDefaultNode) { Nif::NiAVObject node; init(node); Nif::NIFFile file(testNif); file.mRoots.push_back(&node); auto result = Loader::load(file, &mImageManager, &mMaterialManager); 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 formatOsgNodeForBSShaderProperty(std::string_view shaderPrefix) { std::ostringstream oss; oss << 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 ")" << shaderPrefix << R"(" } osg::BoolValueObject { UniqueID 8 Name "shaderRequired" Value TRUE } } } } StateSet TRUE { osg::StateSet { UniqueID 9 } } } } } )"; return oss.str(); } std::string formatOsgNodeForBSLightingShaderProperty(std::string_view shaderPrefix) { std::ostringstream oss; oss << 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 ")" << shaderPrefix << R"(" } osg::BoolValueObject { UniqueID 8 Name "shaderRequired" Value TRUE } } } } StateSet TRUE { osg::StateSet { UniqueID 9 ModeList 1 { GL_DEPTH_TEST ON } AttributeList 1 { osg::Depth { UniqueID 10 Function LEQUAL } Value OFF } } } } } } )"; return oss.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), "bs/default" }, ShaderPrefixParams{ static_cast(Nif::BSShaderType::ShaderType_NoLighting), "bs/nolighting" }, ShaderPrefixParams{ static_cast(Nif::BSShaderType::ShaderType_Tile), "bs/default" }, ShaderPrefixParams{ std::numeric_limits::max(), "bs/default" }, }; }; TEST_P(NifOsgLoaderBSShaderPrefixTest, shouldAddShaderPrefix) { Nif::NiAVObject node; init(node); Nif::BSShaderPPLightingProperty property; property.recType = Nif::RC_BSShaderPPLightingProperty; property.mTextureSet = nullptr; property.mController = nullptr; property.mType = GetParam().mShaderType; node.mProperties.push_back(Nif::RecordPtrT(&property)); Nif::NIFFile file(testNif); file.mRoots.push_back(&node); auto result = Loader::load(file, &mImageManager, &mMaterialManager); EXPECT_EQ(serialize(*result), formatOsgNodeForBSShaderProperty(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), "bs/default" }, ShaderPrefixParams{ static_cast(Nif::BSLightingShaderType::ShaderType_Cloud), "bs/default" }, ShaderPrefixParams{ std::numeric_limits::max(), "bs/default" }, }; }; TEST_P(NifOsgLoaderBSLightingShaderPrefixTest, shouldAddShaderPrefix) { Nif::NiAVObject node; init(node); Nif::BSLightingShaderProperty property; property.recType = Nif::RC_BSLightingShaderProperty; property.mTextureSet = nullptr; property.mController = nullptr; property.mType = GetParam().mShaderType; property.mShaderFlags1 |= Nif::BSShaderFlags1::BSSFlag1_DepthTest; property.mShaderFlags2 |= Nif::BSShaderFlags2::BSSFlag2_DepthWrite; node.mProperties.push_back(Nif::RecordPtrT(&property)); Nif::NIFFile file(testNif); file.mRoots.push_back(&node); auto result = Loader::load(file, &mImageManager, &mMaterialManager); EXPECT_EQ(serialize(*result), formatOsgNodeForBSLightingShaderProperty(GetParam().mExpectedShaderPrefix)); } INSTANTIATE_TEST_SUITE_P( Params, NifOsgLoaderBSLightingShaderPrefixTest, ValuesIn(NifOsgLoaderBSLightingShaderPrefixTest::sParams)); }