mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-28 21:07:59 +03:00
Merge branch 'toboldlygowherenowizardcathasgonebefore' into 'master'
Support Bethesda shader material files (#7777) Closes #7777 See merge request OpenMW/openmw!4041
This commit is contained in:
commit
7a172b061f
23 changed files with 1057 additions and 307 deletions
|
@ -219,6 +219,7 @@
|
||||||
Feature #7652: Sort inactive post processing shaders list properly
|
Feature #7652: Sort inactive post processing shaders list properly
|
||||||
Feature #7698: Implement sAbsorb, sDamage, sDrain, sFortify and sRestore
|
Feature #7698: Implement sAbsorb, sDamage, sDrain, sFortify and sRestore
|
||||||
Feature #7709: Improve resolution selection in Launcher
|
Feature #7709: Improve resolution selection in Launcher
|
||||||
|
Feature #7777: Support external Bethesda material files (BGSM/BGEM)
|
||||||
Feature #7792: Support Timescale Clouds
|
Feature #7792: Support Timescale Clouds
|
||||||
Feature #7795: Support MaxNumberRipples INI setting
|
Feature #7795: Support MaxNumberRipples INI setting
|
||||||
Feature #7805: Lua Menu context
|
Feature #7805: Lua Menu context
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <components/files/multidircollection.hpp>
|
#include <components/files/multidircollection.hpp>
|
||||||
#include <components/misc/strings/conversion.hpp>
|
#include <components/misc/strings/conversion.hpp>
|
||||||
#include <components/platform/platform.hpp>
|
#include <components/platform/platform.hpp>
|
||||||
|
#include <components/resource/bgsmfilemanager.hpp>
|
||||||
#include <components/resource/bulletshape.hpp>
|
#include <components/resource/bulletshape.hpp>
|
||||||
#include <components/resource/bulletshapemanager.hpp>
|
#include <components/resource/bulletshapemanager.hpp>
|
||||||
#include <components/resource/foreachbulletobject.hpp>
|
#include <components/resource/foreachbulletobject.hpp>
|
||||||
|
@ -173,7 +174,8 @@ namespace
|
||||||
constexpr double expiryDelay = 0;
|
constexpr double expiryDelay = 0;
|
||||||
Resource::ImageManager imageManager(&vfs, expiryDelay);
|
Resource::ImageManager imageManager(&vfs, expiryDelay);
|
||||||
Resource::NifFileManager nifFileManager(&vfs, &encoder.getStatelessEncoder());
|
Resource::NifFileManager nifFileManager(&vfs, &encoder.getStatelessEncoder());
|
||||||
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, expiryDelay);
|
Resource::BgsmFileManager bgsmFileManager(&vfs, expiryDelay);
|
||||||
|
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, &bgsmFileManager, expiryDelay);
|
||||||
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager, expiryDelay);
|
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager, expiryDelay);
|
||||||
|
|
||||||
Resource::forEachBulletObject(
|
Resource::forEachBulletObject(
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <components/files/conversion.hpp>
|
#include <components/files/conversion.hpp>
|
||||||
#include <components/files/multidircollection.hpp>
|
#include <components/files/multidircollection.hpp>
|
||||||
#include <components/platform/platform.hpp>
|
#include <components/platform/platform.hpp>
|
||||||
|
#include <components/resource/bgsmfilemanager.hpp>
|
||||||
#include <components/resource/bulletshapemanager.hpp>
|
#include <components/resource/bulletshapemanager.hpp>
|
||||||
#include <components/resource/imagemanager.hpp>
|
#include <components/resource/imagemanager.hpp>
|
||||||
#include <components/resource/niffilemanager.hpp>
|
#include <components/resource/niffilemanager.hpp>
|
||||||
|
@ -220,7 +221,8 @@ namespace NavMeshTool
|
||||||
|
|
||||||
Resource::ImageManager imageManager(&vfs, expiryDelay);
|
Resource::ImageManager imageManager(&vfs, expiryDelay);
|
||||||
Resource::NifFileManager nifFileManager(&vfs, &encoder.getStatelessEncoder());
|
Resource::NifFileManager nifFileManager(&vfs, &encoder.getStatelessEncoder());
|
||||||
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, expiryDelay);
|
Resource::BgsmFileManager bgsmFileManager(&vfs, expiryDelay);
|
||||||
|
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, &bgsmFileManager, expiryDelay);
|
||||||
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager, expiryDelay);
|
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager, expiryDelay);
|
||||||
DetourNavigator::RecastGlobalAllocator::init();
|
DetourNavigator::RecastGlobalAllocator::init();
|
||||||
DetourNavigator::Settings navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
|
DetourNavigator::Settings navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <components/bgsm/reader.hpp>
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#include <components/files/constrainedfilestream.hpp>
|
#include <components/files/constrainedfilestream.hpp>
|
||||||
#include <components/files/conversion.hpp>
|
#include <components/files/conversion.hpp>
|
||||||
|
@ -25,7 +26,7 @@
|
||||||
namespace bpo = boost::program_options;
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
/// See if the file has the named extension
|
/// See if the file has the named extension
|
||||||
bool hasExtension(const std::filesystem::path& filename, const std::string& extensionToFind)
|
bool hasExtension(const std::filesystem::path& filename, std::string_view extensionToFind)
|
||||||
{
|
{
|
||||||
const auto extension = Files::pathToUnicodeString(filename.extension());
|
const auto extension = Files::pathToUnicodeString(filename.extension());
|
||||||
return Misc::StringUtils::ciEqual(extension, extensionToFind);
|
return Misc::StringUtils::ciEqual(extension, extensionToFind);
|
||||||
|
@ -36,6 +37,13 @@ bool isNIF(const std::filesystem::path& filename)
|
||||||
{
|
{
|
||||||
return hasExtension(filename, ".nif") || hasExtension(filename, ".kf");
|
return hasExtension(filename, ".nif") || hasExtension(filename, ".kf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the file is a material file.
|
||||||
|
bool isMaterial(const std::filesystem::path& filename)
|
||||||
|
{
|
||||||
|
return hasExtension(filename, ".bgem") || hasExtension(filename, ".bgsm");
|
||||||
|
}
|
||||||
|
|
||||||
/// See if the file has the "bsa" extension.
|
/// See if the file has the "bsa" extension.
|
||||||
bool isBSA(const std::filesystem::path& filename)
|
bool isBSA(const std::filesystem::path& filename)
|
||||||
{
|
{
|
||||||
|
@ -51,16 +59,17 @@ std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void readNIF(
|
void readFile(
|
||||||
const std::filesystem::path& source, const std::filesystem::path& path, const VFS::Manager* vfs, bool quiet)
|
const std::filesystem::path& source, const std::filesystem::path& path, const VFS::Manager* vfs, bool quiet)
|
||||||
{
|
{
|
||||||
const std::string pathStr = Files::pathToUnicodeString(path);
|
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||||
|
const bool isNif = isNIF(path);
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
{
|
{
|
||||||
if (hasExtension(path, ".kf"))
|
if (isNif)
|
||||||
std::cout << "Reading KF file '" << pathStr << "'";
|
std::cout << "Reading " << (hasExtension(path, ".nif") ? "NIF" : "KF") << " file '" << pathStr << "'";
|
||||||
else
|
else
|
||||||
std::cout << "Reading NIF file '" << pathStr << "'";
|
std::cout << "Reading " << (hasExtension(path, ".bgsm") ? "BGSM" : "BGEM") << " file '" << pathStr << "'";
|
||||||
if (!source.empty())
|
if (!source.empty())
|
||||||
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
|
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
@ -68,12 +77,23 @@ void readNIF(
|
||||||
const std::filesystem::path fullPath = !source.empty() ? source / path : path;
|
const std::filesystem::path fullPath = !source.empty() ? source / path : path;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
|
if (isNif)
|
||||||
Nif::Reader reader(file, nullptr);
|
{
|
||||||
if (vfs != nullptr)
|
Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
|
||||||
reader.parse(vfs->get(pathStr));
|
Nif::Reader reader(file, nullptr);
|
||||||
|
if (vfs != nullptr)
|
||||||
|
reader.parse(vfs->get(pathStr));
|
||||||
|
else
|
||||||
|
reader.parse(Files::openConstrainedFileStream(fullPath));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
reader.parse(Files::openConstrainedFileStream(fullPath));
|
{
|
||||||
|
Bgsm::Reader reader;
|
||||||
|
if (vfs != nullptr)
|
||||||
|
reader.parse(vfs->get(pathStr));
|
||||||
|
else
|
||||||
|
reader.parse(Files::openConstrainedFileStream(fullPath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -97,9 +117,9 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
||||||
|
|
||||||
for (const auto& name : vfs.getRecursiveDirectoryIterator(""))
|
for (const auto& name : vfs.getRecursiveDirectoryIterator(""))
|
||||||
{
|
{
|
||||||
if (isNIF(name.value()))
|
if (isNIF(name.value()) || isMaterial(name.value()))
|
||||||
{
|
{
|
||||||
readNIF(archivePath, name.value(), &vfs, quiet);
|
readFile(archivePath, name.value(), &vfs, quiet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,10 +149,10 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
||||||
bool parseOptions(int argc, char** argv, Files::PathContainer& files, Files::PathContainer& archives,
|
bool parseOptions(int argc, char** argv, Files::PathContainer& files, Files::PathContainer& archives,
|
||||||
bool& writeDebugLog, bool& quiet)
|
bool& writeDebugLog, bool& quiet)
|
||||||
{
|
{
|
||||||
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF, KF and BSA/BA2 files
|
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF, KF, BGEM/BGSM and BSA/BA2 files
|
||||||
|
|
||||||
Usages:
|
Usages:
|
||||||
niftest <nif files, kf files, BSA/BA2 files, or directories>
|
niftest <nif files, kf files, bgem/bgsm files, BSA/BA2 files, or directories>
|
||||||
Scan the file or directories for NIF errors.
|
Scan the file or directories for NIF errors.
|
||||||
|
|
||||||
Allowed options)");
|
Allowed options)");
|
||||||
|
@ -221,9 +241,9 @@ int main(int argc, char** argv)
|
||||||
const std::string pathStr = Files::pathToUnicodeString(path);
|
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (isNIF(path))
|
if (isNIF(path) || isMaterial(path))
|
||||||
{
|
{
|
||||||
readNIF({}, path, vfs.get(), quiet);
|
readFile({}, path, vfs.get(), quiet);
|
||||||
}
|
}
|
||||||
else if (auto archive = makeArchive(path))
|
else if (auto archive = makeArchive(path))
|
||||||
{
|
{
|
||||||
|
@ -231,7 +251,7 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Error: '" << pathStr << "' is not a NIF/KF file, BSA/BA2 archive, or directory"
|
std::cerr << "Error: '" << pathStr << "' is not a NIF/KF/BGEM/BGSM file, BSA/BA2 archive, or directory"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <components/nif/node.hpp>
|
#include <components/nif/node.hpp>
|
||||||
#include <components/nif/property.hpp>
|
#include <components/nif/property.hpp>
|
||||||
#include <components/nifosg/nifloader.hpp>
|
#include <components/nifosg/nifloader.hpp>
|
||||||
|
#include <components/resource/bgsmfilemanager.hpp>
|
||||||
#include <components/resource/imagemanager.hpp>
|
#include <components/resource/imagemanager.hpp>
|
||||||
#include <components/sceneutil/serialize.hpp>
|
#include <components/sceneutil/serialize.hpp>
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
@ -29,6 +30,7 @@ namespace
|
||||||
{
|
{
|
||||||
VFS::Manager mVfs;
|
VFS::Manager mVfs;
|
||||||
Resource::ImageManager mImageManager{ &mVfs, 0 };
|
Resource::ImageManager mImageManager{ &mVfs, 0 };
|
||||||
|
Resource::BgsmFileManager mMaterialManager{ &mVfs, 0 };
|
||||||
const osgDB::ReaderWriter* mReaderWriter = osgDB::Registry::instance()->getReaderWriterForExtension("osgt");
|
const osgDB::ReaderWriter* mReaderWriter = osgDB::Registry::instance()->getReaderWriterForExtension("osgt");
|
||||||
osg::ref_ptr<osgDB::Options> mOptions = new osgDB::Options;
|
osg::ref_ptr<osgDB::Options> mOptions = new osgDB::Options;
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ namespace
|
||||||
init(node);
|
init(node);
|
||||||
Nif::NIFFile file("test.nif");
|
Nif::NIFFile file("test.nif");
|
||||||
file.mRoots.push_back(&node);
|
file.mRoots.push_back(&node);
|
||||||
auto result = Loader::load(file, &mImageManager);
|
auto result = Loader::load(file, &mImageManager, &mMaterialManager);
|
||||||
EXPECT_EQ(serialize(*result), R"(
|
EXPECT_EQ(serialize(*result), R"(
|
||||||
osg::Group {
|
osg::Group {
|
||||||
UniqueID 1
|
UniqueID 1
|
||||||
|
@ -259,7 +261,7 @@ osg::Group {
|
||||||
node.mProperties.push_back(Nif::RecordPtrT<Nif::NiProperty>(&property));
|
node.mProperties.push_back(Nif::RecordPtrT<Nif::NiProperty>(&property));
|
||||||
Nif::NIFFile file("test.nif");
|
Nif::NIFFile file("test.nif");
|
||||||
file.mRoots.push_back(&node);
|
file.mRoots.push_back(&node);
|
||||||
auto result = Loader::load(file, &mImageManager);
|
auto result = Loader::load(file, &mImageManager, &mMaterialManager);
|
||||||
EXPECT_EQ(serialize(*result), formatOsgNodeForBSShaderProperty(GetParam().mExpectedShaderPrefix));
|
EXPECT_EQ(serialize(*result), formatOsgNodeForBSShaderProperty(GetParam().mExpectedShaderPrefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +291,7 @@ osg::Group {
|
||||||
node.mProperties.push_back(Nif::RecordPtrT<Nif::NiProperty>(&property));
|
node.mProperties.push_back(Nif::RecordPtrT<Nif::NiProperty>(&property));
|
||||||
Nif::NIFFile file("test.nif");
|
Nif::NIFFile file("test.nif");
|
||||||
file.mRoots.push_back(&node);
|
file.mRoots.push_back(&node);
|
||||||
auto result = Loader::load(file, &mImageManager);
|
auto result = Loader::load(file, &mImageManager, &mMaterialManager);
|
||||||
EXPECT_EQ(serialize(*result), formatOsgNodeForBSLightingShaderProperty(GetParam().mExpectedShaderPrefix));
|
EXPECT_EQ(serialize(*result), formatOsgNodeForBSLightingShaderProperty(GetParam().mExpectedShaderPrefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,10 @@ add_component_dir (settings
|
||||||
windowmode
|
windowmode
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_component_dir (bgsm
|
||||||
|
reader stream file
|
||||||
|
)
|
||||||
|
|
||||||
add_component_dir (bsa
|
add_component_dir (bsa
|
||||||
bsa_file compressedbsafile ba2gnrlfile ba2dx10file ba2file memorystream
|
bsa_file compressedbsafile ba2gnrlfile ba2dx10file ba2file memorystream
|
||||||
)
|
)
|
||||||
|
@ -125,7 +129,7 @@ add_component_dir (vfs
|
||||||
|
|
||||||
add_component_dir (resource
|
add_component_dir (resource
|
||||||
scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem
|
scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem
|
||||||
resourcemanager stats animation foreachbulletobject errormarker cachestats
|
resourcemanager stats animation foreachbulletobject errormarker cachestats bgsmfilemanager
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (shader
|
add_component_dir (shader
|
||||||
|
|
208
components/bgsm/file.cpp
Normal file
208
components/bgsm/file.cpp
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
#include "file.hpp"
|
||||||
|
|
||||||
|
#include "stream.hpp"
|
||||||
|
|
||||||
|
namespace Bgsm
|
||||||
|
{
|
||||||
|
void MaterialFile::read(BGSMStream& stream)
|
||||||
|
{
|
||||||
|
stream.read(mVersion);
|
||||||
|
stream.read(mClamp);
|
||||||
|
stream.read(mUVOffset);
|
||||||
|
stream.read(mUVScale);
|
||||||
|
stream.read(mTransparency);
|
||||||
|
stream.read(mAlphaBlend);
|
||||||
|
stream.read(mSourceBlendMode);
|
||||||
|
stream.read(mDestinationBlendMode);
|
||||||
|
stream.read(mAlphaTestThreshold);
|
||||||
|
stream.read(mAlphaTest);
|
||||||
|
stream.read(mDepthWrite);
|
||||||
|
stream.read(mDepthTest);
|
||||||
|
stream.read(mSSR);
|
||||||
|
stream.read(mWetnessControlSSR);
|
||||||
|
stream.read(mDecal);
|
||||||
|
stream.read(mTwoSided);
|
||||||
|
stream.read(mDecalNoFade);
|
||||||
|
stream.read(mNonOccluder);
|
||||||
|
stream.read(mRefraction);
|
||||||
|
stream.read(mRefractionFalloff);
|
||||||
|
stream.read(mRefractionPower);
|
||||||
|
if (mVersion < 10)
|
||||||
|
{
|
||||||
|
stream.read(mEnvMapEnabled);
|
||||||
|
stream.read(mEnvMapMaskScale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream.read(mDepthBias);
|
||||||
|
}
|
||||||
|
stream.read(mGrayscaleToPaletteColor);
|
||||||
|
if (mVersion >= 6)
|
||||||
|
stream.read(mMaskWrites);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BGSMFile::read(BGSMStream& stream)
|
||||||
|
{
|
||||||
|
MaterialFile::read(stream);
|
||||||
|
|
||||||
|
stream.read(mDiffuseMap);
|
||||||
|
stream.read(mNormalMap);
|
||||||
|
stream.read(mSmoothSpecMap);
|
||||||
|
stream.read(mGrayscaleMap);
|
||||||
|
if (mVersion >= 3)
|
||||||
|
{
|
||||||
|
stream.read(mGlowMap);
|
||||||
|
stream.read(mWrinkleMap);
|
||||||
|
stream.read(mSpecularMap);
|
||||||
|
stream.read(mLightingMap);
|
||||||
|
stream.read(mFlowMap);
|
||||||
|
if (mVersion >= 17)
|
||||||
|
stream.read(mDistanceFieldAlphaMap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream.read(mEnvMap);
|
||||||
|
stream.read(mGlowMap);
|
||||||
|
stream.read(mInnerLayerMap);
|
||||||
|
stream.read(mWrinkleMap);
|
||||||
|
stream.read(mDisplacementMap);
|
||||||
|
}
|
||||||
|
stream.read(mEnableEditorAlphaThreshold);
|
||||||
|
if (mVersion >= 8)
|
||||||
|
{
|
||||||
|
stream.read(mTranslucency);
|
||||||
|
stream.read(mTranslucencyThickObject);
|
||||||
|
stream.read(mTranslucencyMixAlbedoWithSubsurfaceColor);
|
||||||
|
stream.read(mTranslucencySubsurfaceColor);
|
||||||
|
stream.read(mTranslucencyTransmissiveScale);
|
||||||
|
stream.read(mTranslucencyTurbulence);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stream.read(mRimLighting);
|
||||||
|
stream.read(mRimPower);
|
||||||
|
stream.read(mBackLightPower);
|
||||||
|
stream.read(mSubsurfaceLighting);
|
||||||
|
stream.read(mSubsurfaceLightingRolloff);
|
||||||
|
}
|
||||||
|
stream.read(mSpecularEnabled);
|
||||||
|
stream.read(mSpecularColor);
|
||||||
|
stream.read(mSpecularMult);
|
||||||
|
stream.read(mSmoothness);
|
||||||
|
stream.read(mFresnelPower);
|
||||||
|
stream.read(mWetnessControlSpecScale);
|
||||||
|
stream.read(mWetnessControlSpecPowerScale);
|
||||||
|
stream.read(mWetnessControlSpecMinvar);
|
||||||
|
if (mVersion < 10)
|
||||||
|
stream.read(mWetnessControlEnvMapScale);
|
||||||
|
stream.read(mWetnessControlFresnelPower);
|
||||||
|
stream.read(mWetnessControlMetalness);
|
||||||
|
if (mVersion >= 3)
|
||||||
|
{
|
||||||
|
stream.read(mPBR);
|
||||||
|
if (mVersion >= 9)
|
||||||
|
{
|
||||||
|
stream.read(mCustomPorosity);
|
||||||
|
stream.read(mPorosityValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.read(mRootMaterialPath);
|
||||||
|
stream.read(mAnisoLighting);
|
||||||
|
stream.read(mEmitEnabled);
|
||||||
|
if (mEmitEnabled)
|
||||||
|
stream.read(mEmittanceColor);
|
||||||
|
stream.read(mEmittanceMult);
|
||||||
|
stream.read(mModelSpaceNormals);
|
||||||
|
stream.read(mExternalEmittance);
|
||||||
|
if (mVersion >= 12)
|
||||||
|
{
|
||||||
|
stream.read(mLumEmittance);
|
||||||
|
if (mVersion >= 13)
|
||||||
|
{
|
||||||
|
stream.read(mUseAdaptiveEmissive);
|
||||||
|
stream.read(mAdaptiveEmissiveExposureParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mVersion < 8)
|
||||||
|
{
|
||||||
|
stream.read(mBackLighting);
|
||||||
|
}
|
||||||
|
stream.read(mReceiveShadows);
|
||||||
|
stream.read(mHideSecret);
|
||||||
|
stream.read(mCastShadows);
|
||||||
|
stream.read(mDissolveFade);
|
||||||
|
stream.read(mAssumeShadowmask);
|
||||||
|
stream.read(mGlowMapEnabled);
|
||||||
|
if (mVersion < 7)
|
||||||
|
{
|
||||||
|
stream.read(mEnvMapWindow);
|
||||||
|
stream.read(mEnvMapEye);
|
||||||
|
}
|
||||||
|
stream.read(mHair);
|
||||||
|
stream.read(mHairTintColor);
|
||||||
|
stream.read(mTree);
|
||||||
|
stream.read(mFacegen);
|
||||||
|
stream.read(mSkinTint);
|
||||||
|
stream.read(mTessellate);
|
||||||
|
if (mVersion < 3)
|
||||||
|
{
|
||||||
|
stream.read(mDisplacementMapParams);
|
||||||
|
stream.read(mTessellationParams);
|
||||||
|
}
|
||||||
|
stream.read(mGrayscaleToPaletteScale);
|
||||||
|
if (mVersion >= 1)
|
||||||
|
{
|
||||||
|
stream.read(mSkewSpecularAlpha);
|
||||||
|
stream.read(mTerrain);
|
||||||
|
if (mTerrain)
|
||||||
|
{
|
||||||
|
if (mVersion == 3)
|
||||||
|
stream.skip(4); // Unknown
|
||||||
|
|
||||||
|
stream.read(mTerrainParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BGEMFile::read(BGSMStream& stream)
|
||||||
|
{
|
||||||
|
MaterialFile::read(stream);
|
||||||
|
|
||||||
|
stream.read(mBaseMap);
|
||||||
|
stream.read(mGrayscaleMap);
|
||||||
|
stream.read(mEnvMap);
|
||||||
|
stream.read(mNormalMap);
|
||||||
|
stream.read(mEnvMapMask);
|
||||||
|
if (mVersion >= 11)
|
||||||
|
{
|
||||||
|
stream.read(mSpecularMap);
|
||||||
|
stream.read(mLightingMap);
|
||||||
|
stream.read(mGlowMap);
|
||||||
|
}
|
||||||
|
if (mVersion >= 10)
|
||||||
|
{
|
||||||
|
stream.read(mEnvMapEnabled);
|
||||||
|
stream.read(mEnvMapMaskScale);
|
||||||
|
}
|
||||||
|
stream.read(mBlood);
|
||||||
|
stream.read(mEffectLighting);
|
||||||
|
stream.read(mFalloff);
|
||||||
|
stream.read(mFalloffColor);
|
||||||
|
stream.read(mGrayscaleToPaletteAlpha);
|
||||||
|
stream.read(mSoft);
|
||||||
|
stream.read(mBaseColor);
|
||||||
|
stream.read(mBaseColorScale);
|
||||||
|
stream.read(mFalloffParams);
|
||||||
|
stream.read(mLightingInfluence);
|
||||||
|
stream.read(mEnvmapMinLOD);
|
||||||
|
stream.read(mSoftDepth);
|
||||||
|
if (mVersion >= 11)
|
||||||
|
stream.read(mEmittanceColor);
|
||||||
|
if (mVersion >= 15)
|
||||||
|
stream.read(mAdaptiveEmissiveExposureParams);
|
||||||
|
if (mVersion >= 16)
|
||||||
|
stream.read(mGlowMapEnabled);
|
||||||
|
if (mVersion >= 20)
|
||||||
|
stream.read(mEffectPbrSpecular);
|
||||||
|
}
|
||||||
|
}
|
164
components/bgsm/file.hpp
Normal file
164
components/bgsm/file.hpp
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_BGSM_FILE_HPP
|
||||||
|
#define OPENMW_COMPONENTS_BGSM_FILE_HPP
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <osg/Vec2f>
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
#include <osg/Vec4f>
|
||||||
|
|
||||||
|
namespace Bgsm
|
||||||
|
{
|
||||||
|
class BGSMStream;
|
||||||
|
|
||||||
|
enum class ShaderType
|
||||||
|
{
|
||||||
|
Lighting,
|
||||||
|
Effect,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MaterialFile
|
||||||
|
{
|
||||||
|
ShaderType mShaderType;
|
||||||
|
std::uint32_t mVersion;
|
||||||
|
std::uint32_t mClamp;
|
||||||
|
osg::Vec2f mUVOffset, mUVScale;
|
||||||
|
float mTransparency;
|
||||||
|
bool mAlphaBlend;
|
||||||
|
std::uint32_t mSourceBlendMode;
|
||||||
|
std::uint32_t mDestinationBlendMode;
|
||||||
|
std::uint8_t mAlphaTestThreshold;
|
||||||
|
bool mAlphaTest;
|
||||||
|
bool mDepthWrite, mDepthTest;
|
||||||
|
bool mSSR;
|
||||||
|
bool mWetnessControlSSR;
|
||||||
|
bool mDecal;
|
||||||
|
bool mTwoSided;
|
||||||
|
bool mDecalNoFade;
|
||||||
|
bool mNonOccluder;
|
||||||
|
bool mRefraction;
|
||||||
|
bool mRefractionFalloff;
|
||||||
|
float mRefractionPower;
|
||||||
|
bool mEnvMapEnabled;
|
||||||
|
float mEnvMapMaskScale;
|
||||||
|
bool mDepthBias;
|
||||||
|
bool mGrayscaleToPaletteColor;
|
||||||
|
std::uint8_t mMaskWrites;
|
||||||
|
|
||||||
|
MaterialFile() = default;
|
||||||
|
virtual void read(BGSMStream& stream);
|
||||||
|
virtual ~MaterialFile() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BGSMFile : MaterialFile
|
||||||
|
{
|
||||||
|
std::string mDiffuseMap;
|
||||||
|
std::string mNormalMap;
|
||||||
|
std::string mSmoothSpecMap;
|
||||||
|
std::string mGrayscaleMap;
|
||||||
|
std::string mGlowMap;
|
||||||
|
std::string mWrinkleMap;
|
||||||
|
std::string mSpecularMap;
|
||||||
|
std::string mLightingMap;
|
||||||
|
std::string mFlowMap;
|
||||||
|
std::string mDistanceFieldAlphaMap;
|
||||||
|
std::string mEnvMap;
|
||||||
|
std::string mInnerLayerMap;
|
||||||
|
std::string mDisplacementMap;
|
||||||
|
bool mEnableEditorAlphaThreshold;
|
||||||
|
bool mTranslucency;
|
||||||
|
bool mTranslucencyThickObject;
|
||||||
|
bool mTranslucencyMixAlbedoWithSubsurfaceColor;
|
||||||
|
osg::Vec3f mTranslucencySubsurfaceColor;
|
||||||
|
float mTranslucencyTransmissiveScale;
|
||||||
|
float mTranslucencyTurbulence;
|
||||||
|
bool mRimLighting;
|
||||||
|
float mRimPower;
|
||||||
|
float mBackLightPower;
|
||||||
|
bool mSubsurfaceLighting;
|
||||||
|
float mSubsurfaceLightingRolloff;
|
||||||
|
bool mSpecularEnabled;
|
||||||
|
osg::Vec3f mSpecularColor;
|
||||||
|
float mSpecularMult;
|
||||||
|
float mSmoothness;
|
||||||
|
float mFresnelPower;
|
||||||
|
float mWetnessControlSpecScale;
|
||||||
|
float mWetnessControlSpecPowerScale;
|
||||||
|
float mWetnessControlSpecMinvar;
|
||||||
|
float mWetnessControlEnvMapScale;
|
||||||
|
float mWetnessControlFresnelPower;
|
||||||
|
float mWetnessControlMetalness;
|
||||||
|
bool mPBR;
|
||||||
|
bool mCustomPorosity;
|
||||||
|
float mPorosityValue;
|
||||||
|
std::string mRootMaterialPath;
|
||||||
|
bool mAnisoLighting;
|
||||||
|
bool mEmitEnabled;
|
||||||
|
osg::Vec3f mEmittanceColor;
|
||||||
|
float mEmittanceMult;
|
||||||
|
bool mModelSpaceNormals;
|
||||||
|
bool mExternalEmittance;
|
||||||
|
float mLumEmittance;
|
||||||
|
bool mUseAdaptiveEmissive;
|
||||||
|
osg::Vec3f mAdaptiveEmissiveExposureParams;
|
||||||
|
bool mBackLighting;
|
||||||
|
bool mReceiveShadows;
|
||||||
|
bool mHideSecret;
|
||||||
|
bool mCastShadows;
|
||||||
|
bool mDissolveFade;
|
||||||
|
bool mAssumeShadowmask;
|
||||||
|
bool mGlowMapEnabled;
|
||||||
|
bool mEnvMapWindow;
|
||||||
|
bool mEnvMapEye;
|
||||||
|
bool mHair;
|
||||||
|
osg::Vec3f mHairTintColor;
|
||||||
|
bool mTree;
|
||||||
|
bool mFacegen;
|
||||||
|
bool mSkinTint;
|
||||||
|
bool mTessellate;
|
||||||
|
osg::Vec2f mDisplacementMapParams;
|
||||||
|
osg::Vec3f mTessellationParams;
|
||||||
|
float mGrayscaleToPaletteScale;
|
||||||
|
bool mSkewSpecularAlpha;
|
||||||
|
bool mTerrain;
|
||||||
|
osg::Vec3f mTerrainParams;
|
||||||
|
|
||||||
|
void read(BGSMStream& stream) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BGEMFile : MaterialFile
|
||||||
|
{
|
||||||
|
std::string mBaseMap;
|
||||||
|
std::string mGrayscaleMap;
|
||||||
|
std::string mEnvMap;
|
||||||
|
std::string mNormalMap;
|
||||||
|
std::string mEnvMapMask;
|
||||||
|
std::string mSpecularMap;
|
||||||
|
std::string mLightingMap;
|
||||||
|
std::string mGlowMap;
|
||||||
|
bool mBlood;
|
||||||
|
bool mEffectLighting;
|
||||||
|
bool mFalloff;
|
||||||
|
bool mFalloffColor;
|
||||||
|
bool mGrayscaleToPaletteAlpha;
|
||||||
|
bool mSoft;
|
||||||
|
osg::Vec3f mBaseColor;
|
||||||
|
float mBaseColorScale;
|
||||||
|
osg::Vec4f mFalloffParams;
|
||||||
|
float mLightingInfluence;
|
||||||
|
std::uint8_t mEnvmapMinLOD;
|
||||||
|
float mSoftDepth;
|
||||||
|
osg::Vec3f mEmittanceColor;
|
||||||
|
osg::Vec3f mAdaptiveEmissiveExposureParams;
|
||||||
|
bool mGlowMapEnabled;
|
||||||
|
bool mEffectPbrSpecular;
|
||||||
|
|
||||||
|
void read(BGSMStream& stream) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
using MaterialFilePtr = std::shared_ptr<const Bgsm::MaterialFile>;
|
||||||
|
}
|
||||||
|
#endif
|
33
components/bgsm/reader.cpp
Normal file
33
components/bgsm/reader.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "reader.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "stream.hpp"
|
||||||
|
|
||||||
|
namespace Bgsm
|
||||||
|
{
|
||||||
|
void Reader::parse(Files::IStreamPtr&& inputStream)
|
||||||
|
{
|
||||||
|
BGSMStream stream(std::move(inputStream));
|
||||||
|
|
||||||
|
std::array<char, 4> signature;
|
||||||
|
stream.readArray(signature);
|
||||||
|
std::string shaderType(signature.data(), 4);
|
||||||
|
if (shaderType == "BGEM")
|
||||||
|
{
|
||||||
|
mFile = std::make_unique<BGEMFile>();
|
||||||
|
mFile->mShaderType = Bgsm::ShaderType::Effect;
|
||||||
|
}
|
||||||
|
else if (shaderType == "BGSM")
|
||||||
|
{
|
||||||
|
mFile = std::make_unique<BGSMFile>();
|
||||||
|
mFile->mShaderType = Bgsm::ShaderType::Lighting;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid material file");
|
||||||
|
|
||||||
|
mFile->read(stream);
|
||||||
|
}
|
||||||
|
}
|
22
components/bgsm/reader.hpp
Normal file
22
components/bgsm/reader.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_BGSM_READER_HPP
|
||||||
|
#define OPENMW_COMPONENTS_BGSM_READER_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <components/files/istreamptr.hpp>
|
||||||
|
|
||||||
|
#include "file.hpp"
|
||||||
|
|
||||||
|
namespace Bgsm
|
||||||
|
{
|
||||||
|
class Reader
|
||||||
|
{
|
||||||
|
std::unique_ptr<MaterialFile> mFile;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void parse(Files::IStreamPtr&& stream);
|
||||||
|
|
||||||
|
std::unique_ptr<MaterialFile> getFile() { return std::move(mFile); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
39
components/bgsm/stream.cpp
Normal file
39
components/bgsm/stream.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "stream.hpp"
|
||||||
|
|
||||||
|
namespace Bgsm
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
void BGSMStream::read<osg::Vec2f>(osg::Vec2f& vec)
|
||||||
|
{
|
||||||
|
readBufferOfType(mStream, vec._v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void BGSMStream::read<osg::Vec3f>(osg::Vec3f& vec)
|
||||||
|
{
|
||||||
|
readBufferOfType(mStream, vec._v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void BGSMStream::read<osg::Vec4f>(osg::Vec4f& vec)
|
||||||
|
{
|
||||||
|
readBufferOfType(mStream, vec._v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void BGSMStream::read<std::string>(std::string& str)
|
||||||
|
{
|
||||||
|
std::uint32_t length;
|
||||||
|
read(length);
|
||||||
|
// Prevent potential memory allocation freezes; strings this long are not expected in BGSM
|
||||||
|
if (length > 1024)
|
||||||
|
throw std::runtime_error("Requested string length is too large: " + std::to_string(length));
|
||||||
|
str = std::string(length, '\0');
|
||||||
|
mStream->read(str.data(), length);
|
||||||
|
if (mStream->bad())
|
||||||
|
throw std::runtime_error("Failed to read sized string of " + std::to_string(length) + " chars");
|
||||||
|
std::size_t end = str.find('\0');
|
||||||
|
if (end != std::string::npos)
|
||||||
|
str.erase(end);
|
||||||
|
}
|
||||||
|
}
|
77
components/bgsm/stream.hpp
Normal file
77
components/bgsm/stream.hpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_BGSM_STREAM_HPP
|
||||||
|
#define OPENMW_COMPONENTS_BGSM_STREAM_HPP
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <istream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <components/files/istreamptr.hpp>
|
||||||
|
#include <components/misc/endianness.hpp>
|
||||||
|
|
||||||
|
#include <osg/Vec2f>
|
||||||
|
#include <osg/Vec3f>
|
||||||
|
#include <osg/Vec4f>
|
||||||
|
|
||||||
|
namespace Bgsm
|
||||||
|
{
|
||||||
|
template <std::size_t numInstances, typename T>
|
||||||
|
inline void readBufferOfType(Files::IStreamPtr& pIStream, T* dest)
|
||||||
|
{
|
||||||
|
static_assert(std::is_arithmetic_v<T>, "Buffer element type is not arithmetic");
|
||||||
|
pIStream->read(reinterpret_cast<char*>(dest), numInstances * sizeof(T));
|
||||||
|
if (pIStream->bad())
|
||||||
|
throw std::runtime_error("Failed to read typed (" + std::string(typeid(T).name()) + ") buffer of "
|
||||||
|
+ std::to_string(numInstances) + " instances");
|
||||||
|
if constexpr (Misc::IS_BIG_ENDIAN)
|
||||||
|
for (std::size_t i = 0; i < numInstances; i++)
|
||||||
|
Misc::swapEndiannessInplace(dest[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t numInstances, typename T>
|
||||||
|
inline void readBufferOfType(Files::IStreamPtr& pIStream, T (&dest)[numInstances])
|
||||||
|
{
|
||||||
|
readBufferOfType<numInstances>(pIStream, static_cast<T*>(dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
class BGSMStream
|
||||||
|
{
|
||||||
|
Files::IStreamPtr mStream;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BGSMStream(Files::IStreamPtr&& stream)
|
||||||
|
: mStream(std::move(stream))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void skip(size_t size) { mStream->ignore(size); }
|
||||||
|
|
||||||
|
/// Read into a single instance of type
|
||||||
|
template <class T>
|
||||||
|
void read(T& data)
|
||||||
|
{
|
||||||
|
readBufferOfType<1>(mStream, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read multiple instances of type into an array
|
||||||
|
template <class T, size_t size>
|
||||||
|
void readArray(std::array<T, size>& arr)
|
||||||
|
{
|
||||||
|
readBufferOfType<size>(mStream, arr.data());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void BGSMStream::read<osg::Vec2f>(osg::Vec2f& vec);
|
||||||
|
template <>
|
||||||
|
void BGSMStream::read<osg::Vec3f>(osg::Vec3f& vec);
|
||||||
|
template <>
|
||||||
|
void BGSMStream::read<osg::Vec4f>(osg::Vec4f& vec);
|
||||||
|
template <>
|
||||||
|
void BGSMStream::read<std::string>(std::string& str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -173,6 +173,11 @@ std::string Misc::ResourceHelpers::correctActorModelPath(const std::string& resP
|
||||||
return mdlname;
|
return mdlname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Misc::ResourceHelpers::correctMaterialPath(std::string_view resPath, const VFS::Manager* vfs)
|
||||||
|
{
|
||||||
|
return correctResourcePath({ { "materials" } }, resPath, vfs);
|
||||||
|
}
|
||||||
|
|
||||||
std::string Misc::ResourceHelpers::correctMeshPath(std::string_view resPath)
|
std::string Misc::ResourceHelpers::correctMeshPath(std::string_view resPath)
|
||||||
{
|
{
|
||||||
std::string res = "meshes\\";
|
std::string res = "meshes\\";
|
||||||
|
|
|
@ -34,6 +34,7 @@ namespace Misc
|
||||||
/// Use "xfoo.nif" instead of "foo.nif" if "xfoo.kf" is available
|
/// Use "xfoo.nif" instead of "foo.nif" if "xfoo.kf" is available
|
||||||
/// Note that if "xfoo.nif" is actually unavailable, we can't fall back to "foo.nif". :(
|
/// Note that if "xfoo.nif" is actually unavailable, we can't fall back to "foo.nif". :(
|
||||||
std::string correctActorModelPath(const std::string& resPath, const VFS::Manager* vfs);
|
std::string correctActorModelPath(const std::string& resPath, const VFS::Manager* vfs);
|
||||||
|
std::string correctMaterialPath(std::string_view resPath, const VFS::Manager* vfs);
|
||||||
|
|
||||||
// Adds "meshes\\".
|
// Adds "meshes\\".
|
||||||
std::string correctMeshPath(std::string_view resPath);
|
std::string correctMeshPath(std::string_view resPath);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <components/misc/strings/algorithm.hpp>
|
#include <components/misc/strings/algorithm.hpp>
|
||||||
#include <components/misc/strings/lower.hpp>
|
#include <components/misc/strings/lower.hpp>
|
||||||
#include <components/nif/parent.hpp>
|
#include <components/nif/parent.hpp>
|
||||||
|
#include <components/resource/bgsmfilemanager.hpp>
|
||||||
#include <components/resource/imagemanager.hpp>
|
#include <components/resource/imagemanager.hpp>
|
||||||
|
|
||||||
// particle
|
// particle
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
#include <osg/TexEnvCombine>
|
#include <osg/TexEnvCombine>
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
|
#include <components/bgsm/file.hpp>
|
||||||
#include <components/nif/effect.hpp>
|
#include <components/nif/effect.hpp>
|
||||||
#include <components/nif/exception.hpp>
|
#include <components/nif/exception.hpp>
|
||||||
#include <components/nif/extra.hpp>
|
#include <components/nif/extra.hpp>
|
||||||
|
@ -247,6 +249,8 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
std::filesystem::path mFilename;
|
std::filesystem::path mFilename;
|
||||||
unsigned int mVersion, mUserVersion, mBethVersion;
|
unsigned int mVersion, mUserVersion, mBethVersion;
|
||||||
|
Resource::BgsmFileManager* mMaterialManager{ nullptr };
|
||||||
|
Resource::ImageManager* mImageManager{ nullptr };
|
||||||
|
|
||||||
size_t mFirstRootTextureIndex{ ~0u };
|
size_t mFirstRootTextureIndex{ ~0u };
|
||||||
bool mFoundFirstRootTexturingProperty = false;
|
bool mFoundFirstRootTexturingProperty = false;
|
||||||
|
@ -339,7 +343,6 @@ namespace NifOsg
|
||||||
struct HandleNodeArgs
|
struct HandleNodeArgs
|
||||||
{
|
{
|
||||||
unsigned int mNifVersion;
|
unsigned int mNifVersion;
|
||||||
Resource::ImageManager* mImageManager;
|
|
||||||
SceneUtil::TextKeyMap* mTextKeys;
|
SceneUtil::TextKeyMap* mTextKeys;
|
||||||
std::vector<unsigned int> mBoundTextures = {};
|
std::vector<unsigned int> mBoundTextures = {};
|
||||||
int mAnimFlags = 0;
|
int mAnimFlags = 0;
|
||||||
|
@ -349,7 +352,7 @@ namespace NifOsg
|
||||||
osg::Node* mRootNode = nullptr;
|
osg::Node* mRootNode = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> load(Nif::FileView nif, Resource::ImageManager* imageManager)
|
osg::ref_ptr<osg::Node> load(Nif::FileView nif)
|
||||||
{
|
{
|
||||||
const size_t numRoots = nif.numRoots();
|
const size_t numRoots = nif.numRoots();
|
||||||
std::vector<const Nif::NiAVObject*> roots;
|
std::vector<const Nif::NiAVObject*> roots;
|
||||||
|
@ -371,10 +374,8 @@ namespace NifOsg
|
||||||
created->setDataVariance(osg::Object::STATIC);
|
created->setDataVariance(osg::Object::STATIC);
|
||||||
for (const Nif::NiAVObject* root : roots)
|
for (const Nif::NiAVObject* root : roots)
|
||||||
{
|
{
|
||||||
auto node = handleNode(root, nullptr, nullptr,
|
auto node = handleNode(
|
||||||
{ .mNifVersion = nif.getVersion(),
|
root, nullptr, nullptr, { .mNifVersion = nif.getVersion(), .mTextKeys = &textkeys->mTextKeys });
|
||||||
.mImageManager = imageManager,
|
|
||||||
.mTextKeys = &textkeys->mTextKeys });
|
|
||||||
created->addChild(node);
|
created->addChild(node);
|
||||||
}
|
}
|
||||||
if (mHasNightDayLabel)
|
if (mHasNightDayLabel)
|
||||||
|
@ -405,8 +406,7 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyNodeProperties(const Nif::NiAVObject* nifNode, osg::Node* applyTo,
|
void applyNodeProperties(const Nif::NiAVObject* nifNode, osg::Node* applyTo,
|
||||||
SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager,
|
SceneUtil::CompositeStateSetUpdater* composite, std::vector<unsigned int>& boundTextures, int animflags)
|
||||||
std::vector<unsigned int>& boundTextures, int animflags)
|
|
||||||
{
|
{
|
||||||
bool hasStencilProperty = false;
|
bool hasStencilProperty = false;
|
||||||
|
|
||||||
|
@ -444,8 +444,7 @@ namespace NifOsg
|
||||||
if (property.getPtr()->recIndex == mFirstRootTextureIndex)
|
if (property.getPtr()->recIndex == mFirstRootTextureIndex)
|
||||||
applyTo->setUserValue("overrideFx", 1);
|
applyTo->setUserValue("overrideFx", 1);
|
||||||
}
|
}
|
||||||
handleProperty(property.getPtr(), applyTo, composite, imageManager, boundTextures, animflags,
|
handleProperty(property.getPtr(), applyTo, composite, boundTextures, animflags, hasStencilProperty);
|
||||||
hasStencilProperty);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,8 +456,7 @@ namespace NifOsg
|
||||||
shaderprop = static_cast<const Nif::BSTriShape*>(nifNode)->mShaderProperty;
|
shaderprop = static_cast<const Nif::BSTriShape*>(nifNode)->mShaderProperty;
|
||||||
|
|
||||||
if (!shaderprop.empty())
|
if (!shaderprop.empty())
|
||||||
handleProperty(shaderprop.getPtr(), applyTo, composite, imageManager, boundTextures, animflags,
|
handleProperty(shaderprop.getPtr(), applyTo, composite, boundTextures, animflags, hasStencilProperty);
|
||||||
hasStencilProperty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setupController(const Nif::NiTimeController* ctrl, SceneUtil::Controller* toSetup, int animflags)
|
static void setupController(const Nif::NiTimeController* ctrl, SceneUtil::Controller* toSetup, int animflags)
|
||||||
|
@ -522,32 +520,21 @@ namespace NifOsg
|
||||||
sequenceNode->setMode(osg::Sequence::START);
|
sequenceNode->setMode(osg::Sequence::START);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Image> handleSourceTexture(
|
osg::ref_ptr<osg::Image> handleSourceTexture(const Nif::NiSourceTexture* st) const
|
||||||
const Nif::NiSourceTexture* st, Resource::ImageManager* imageManager)
|
|
||||||
{
|
{
|
||||||
if (!st)
|
if (st)
|
||||||
return nullptr;
|
{
|
||||||
|
if (st->mExternal)
|
||||||
|
return getTextureImage(st->mFile);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Image> image;
|
if (!st->mData.empty())
|
||||||
if (st->mExternal)
|
return handleInternalTexture(st->mData.getPtr());
|
||||||
{
|
|
||||||
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->mFile, imageManager->getVFS());
|
|
||||||
image = imageManager->getImage(filename);
|
|
||||||
}
|
}
|
||||||
else if (!st->mData.empty())
|
|
||||||
{
|
return nullptr;
|
||||||
image = handleInternalTexture(st->mData.getPtr());
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleTextureWrapping(osg::Texture2D* texture, bool wrapS, bool wrapT)
|
bool handleEffect(const Nif::NiAVObject* nifNode, osg::StateSet* stateset)
|
||||||
{
|
|
||||||
texture->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
|
||||||
texture->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool handleEffect(const Nif::NiAVObject* nifNode, osg::StateSet* stateset, Resource::ImageManager* imageManager)
|
|
||||||
{
|
{
|
||||||
if (nifNode->recType != Nif::RC_NiTextureEffect)
|
if (nifNode->recType != Nif::RC_NiTextureEffect)
|
||||||
{
|
{
|
||||||
|
@ -590,16 +577,12 @@ namespace NifOsg
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Image> image(handleSourceTexture(textureEffect->mTexture.getPtr(), imageManager));
|
const unsigned int uvSet = 0;
|
||||||
osg::ref_ptr<osg::Texture2D> texture2d(new osg::Texture2D(image));
|
const unsigned int texUnit = 3; // FIXME
|
||||||
if (image)
|
std::vector<unsigned int> boundTextures;
|
||||||
texture2d->setTextureSize(image->s(), image->t());
|
boundTextures.resize(3); // Dummy vector for attachNiSourceTexture
|
||||||
texture2d->setName("envMap");
|
attachNiSourceTexture("envMap", textureEffect->mTexture.getPtr(), textureEffect->wrapS(),
|
||||||
handleTextureWrapping(texture2d, textureEffect->wrapS(), textureEffect->wrapT());
|
textureEffect->wrapT(), uvSet, stateset, boundTextures);
|
||||||
|
|
||||||
int texUnit = 3; // FIXME
|
|
||||||
|
|
||||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
|
||||||
stateset->setTextureAttributeAndModes(texUnit, texGen, osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(texUnit, texGen, osg::StateAttribute::ON);
|
||||||
stateset->setTextureAttributeAndModes(texUnit, createEmissiveTexEnv(), osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(texUnit, createEmissiveTexEnv(), osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
@ -761,7 +744,7 @@ namespace NifOsg
|
||||||
|
|
||||||
osg::ref_ptr<SceneUtil::CompositeStateSetUpdater> composite = new SceneUtil::CompositeStateSetUpdater;
|
osg::ref_ptr<SceneUtil::CompositeStateSetUpdater> composite = new SceneUtil::CompositeStateSetUpdater;
|
||||||
|
|
||||||
applyNodeProperties(nifNode, node, composite, args.mImageManager, args.mBoundTextures, args.mAnimFlags);
|
applyNodeProperties(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||||
|
|
||||||
const bool isNiGeometry = isTypeNiGeometry(nifNode->recType);
|
const bool isNiGeometry = isTypeNiGeometry(nifNode->recType);
|
||||||
const bool isBSGeometry = isTypeBSGeometry(nifNode->recType);
|
const bool isBSGeometry = isTypeBSGeometry(nifNode->recType);
|
||||||
|
@ -769,7 +752,7 @@ namespace NifOsg
|
||||||
|
|
||||||
if (isGeometry && !args.mSkipMeshes)
|
if (isGeometry && !args.mSkipMeshes)
|
||||||
{
|
{
|
||||||
bool skip;
|
bool skip = false;
|
||||||
if (args.mNifVersion <= Nif::NIFFile::NIFVersion::VER_MW)
|
if (args.mNifVersion <= Nif::NIFFile::NIFVersion::VER_MW)
|
||||||
{
|
{
|
||||||
skip = (args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->mName, "tri editormarker"))
|
skip = (args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->mName, "tri editormarker"))
|
||||||
|
@ -777,7 +760,11 @@ namespace NifOsg
|
||||||
|| Misc::StringUtils::ciStartsWith(nifNode->mName, "tri shadow");
|
|| Misc::StringUtils::ciStartsWith(nifNode->mName, "tri shadow");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
skip = args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->mName, "EditorMarker");
|
{
|
||||||
|
if (args.mHasMarkers)
|
||||||
|
skip = Misc::StringUtils::ciStartsWith(nifNode->mName, "EditorMarker")
|
||||||
|
|| Misc::StringUtils::ciStartsWith(nifNode->mName, "VisibilityEditorMarker");
|
||||||
|
}
|
||||||
if (!skip)
|
if (!skip)
|
||||||
{
|
{
|
||||||
if (isNiGeometry)
|
if (isNiGeometry)
|
||||||
|
@ -859,7 +846,7 @@ namespace NifOsg
|
||||||
if (!effect.empty())
|
if (!effect.empty())
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::StateSet> effectStateSet = new osg::StateSet;
|
osg::ref_ptr<osg::StateSet> effectStateSet = new osg::StateSet;
|
||||||
if (handleEffect(effect.getPtr(), effectStateSet, args.mImageManager))
|
if (handleEffect(effect.getPtr(), effectStateSet))
|
||||||
for (unsigned int i = 0; i < currentNode->getNumChildren(); ++i)
|
for (unsigned int i = 0; i < currentNode->getNumChildren(); ++i)
|
||||||
currentNode->getChild(i)->getOrCreateStateSet()->merge(*effectStateSet);
|
currentNode->getChild(i)->getOrCreateStateSet()->merge(*effectStateSet);
|
||||||
}
|
}
|
||||||
|
@ -1025,9 +1012,56 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Image> getTextureImage(std::string_view path) const
|
||||||
|
{
|
||||||
|
if (!mImageManager)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::string filename = Misc::ResourceHelpers::correctTexturePath(path, mImageManager->getVFS());
|
||||||
|
return mImageManager->getImage(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Texture2D> attachTexture(const std::string& name, osg::ref_ptr<osg::Image> image, bool wrapS,
|
||||||
|
bool wrapT, unsigned int uvSet, osg::StateSet* stateset, std::vector<unsigned int>& boundTextures) const
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Texture2D> texture2d = new osg::Texture2D(image);
|
||||||
|
if (image)
|
||||||
|
texture2d->setTextureSize(image->s(), image->t());
|
||||||
|
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||||
|
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE);
|
||||||
|
unsigned int texUnit = boundTextures.size();
|
||||||
|
if (stateset)
|
||||||
|
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
||||||
|
texture2d->setName(name);
|
||||||
|
boundTextures.emplace_back(uvSet);
|
||||||
|
return texture2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Texture2D> attachExternalTexture(const std::string& name, const std::string& path, bool wrapS,
|
||||||
|
bool wrapT, unsigned int uvSet, osg::StateSet* stateset, std::vector<unsigned int>& boundTextures) const
|
||||||
|
{
|
||||||
|
return attachTexture(name, getTextureImage(path), wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Texture2D> attachNiSourceTexture(const std::string& name, const Nif::NiSourceTexture* st,
|
||||||
|
bool wrapS, bool wrapT, unsigned int uvSet, osg::StateSet* stateset,
|
||||||
|
std::vector<unsigned int>& boundTextures) const
|
||||||
|
{
|
||||||
|
return attachTexture(name, handleSourceTexture(st), wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clearBoundTextures(osg::StateSet* stateset, std::vector<unsigned int>& boundTextures)
|
||||||
|
{
|
||||||
|
if (!boundTextures.empty())
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < boundTextures.size(); ++i)
|
||||||
|
stateset->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
||||||
|
boundTextures.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void handleTextureControllers(const Nif::NiProperty* texProperty,
|
void handleTextureControllers(const Nif::NiProperty* texProperty,
|
||||||
SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager,
|
SceneUtil::CompositeStateSetUpdater* composite, osg::StateSet* stateset, int animflags)
|
||||||
osg::StateSet* stateset, int animflags)
|
|
||||||
{
|
{
|
||||||
for (Nif::NiTimeControllerPtr ctrl = texProperty->mController; !ctrl.empty(); ctrl = ctrl->mNext)
|
for (Nif::NiTimeControllerPtr ctrl = texProperty->mController; !ctrl.empty(); ctrl = ctrl->mNext)
|
||||||
{
|
{
|
||||||
|
@ -1056,17 +1090,16 @@ namespace NifOsg
|
||||||
wrapT = inherit->getWrap(osg::Texture2D::WRAP_T);
|
wrapT = inherit->getWrap(osg::Texture2D::WRAP_T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unsigned int uvSet = 0;
|
||||||
|
std::vector<unsigned int> boundTextures; // Dummy list for attachTexture
|
||||||
for (const auto& source : flipctrl->mSources)
|
for (const auto& source : flipctrl->mSources)
|
||||||
{
|
{
|
||||||
if (source.empty())
|
if (source.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Image> image(handleSourceTexture(source.getPtr(), imageManager));
|
// NB: not changing the stateset
|
||||||
osg::ref_ptr<osg::Texture2D> texture(new osg::Texture2D(image));
|
osg::ref_ptr<osg::Texture2D> texture
|
||||||
if (image)
|
= attachNiSourceTexture({}, source.getPtr(), wrapS, wrapT, uvSet, nullptr, boundTextures);
|
||||||
texture->setTextureSize(image->s(), image->t());
|
|
||||||
texture->setWrap(osg::Texture::WRAP_S, wrapS);
|
|
||||||
texture->setWrap(osg::Texture::WRAP_T, wrapT);
|
|
||||||
textures.push_back(texture);
|
textures.push_back(texture);
|
||||||
}
|
}
|
||||||
osg::ref_ptr<FlipController> callback(new FlipController(flipctrl, textures));
|
osg::ref_ptr<FlipController> callback(new FlipController(flipctrl, textures));
|
||||||
|
@ -1811,7 +1844,7 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Image> handleInternalTexture(const Nif::NiPixelData* pixelData)
|
osg::ref_ptr<osg::Image> handleInternalTexture(const Nif::NiPixelData* pixelData) const
|
||||||
{
|
{
|
||||||
if (pixelData->mMipmaps.empty())
|
if (pixelData->mMipmaps.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1946,7 +1979,7 @@ namespace NifOsg
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::TexEnvCombine> createEmissiveTexEnv()
|
static osg::ref_ptr<osg::TexEnvCombine> createEmissiveTexEnv()
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::TexEnvCombine> texEnv(new osg::TexEnvCombine);
|
osg::ref_ptr<osg::TexEnvCombine> texEnv(new osg::TexEnvCombine);
|
||||||
// Sum the previous colour and the emissive colour.
|
// Sum the previous colour and the emissive colour.
|
||||||
|
@ -1977,33 +2010,42 @@ namespace NifOsg
|
||||||
|
|
||||||
void handleTextureProperty(const Nif::NiTexturingProperty* texprop, const std::string& nodeName,
|
void handleTextureProperty(const Nif::NiTexturingProperty* texprop, const std::string& nodeName,
|
||||||
osg::StateSet* stateset, SceneUtil::CompositeStateSetUpdater* composite,
|
osg::StateSet* stateset, SceneUtil::CompositeStateSetUpdater* composite,
|
||||||
Resource::ImageManager* imageManager, std::vector<unsigned int>& boundTextures, int animflags)
|
std::vector<unsigned int>& boundTextures, int animflags)
|
||||||
{
|
{
|
||||||
if (!boundTextures.empty())
|
// overriding a parent NiTexturingProperty, so remove what was previously bound
|
||||||
{
|
clearBoundTextures(stateset, boundTextures);
|
||||||
// overriding a parent NiTexturingProperty, so remove what was previously bound
|
|
||||||
for (unsigned int i = 0; i < boundTextures.size(); ++i)
|
|
||||||
stateset->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
|
||||||
boundTextures.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this loop is changed such that the base texture isn't guaranteed to end up in texture unit 0, the
|
// If this loop is changed such that the base texture isn't guaranteed to end up in texture unit 0, the
|
||||||
// shadow casting shader will need to be updated accordingly.
|
// shadow casting shader will need to be updated accordingly.
|
||||||
for (size_t i = 0; i < texprop->mTextures.size(); ++i)
|
for (size_t i = 0; i < texprop->mTextures.size(); ++i)
|
||||||
{
|
{
|
||||||
if (texprop->mTextures[i].mEnabled
|
const Nif::NiTexturingProperty::Texture& tex = texprop->mTextures[i];
|
||||||
|| (i == Nif::NiTexturingProperty::BaseTexture && !texprop->mController.empty()))
|
if (tex.mEnabled || (i == Nif::NiTexturingProperty::BaseTexture && !texprop->mController.empty()))
|
||||||
{
|
{
|
||||||
|
std::string textureName;
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
// These are handled later on
|
// These are handled later on
|
||||||
case Nif::NiTexturingProperty::BaseTexture:
|
case Nif::NiTexturingProperty::BaseTexture:
|
||||||
|
textureName = "diffuseMap";
|
||||||
|
break;
|
||||||
case Nif::NiTexturingProperty::GlowTexture:
|
case Nif::NiTexturingProperty::GlowTexture:
|
||||||
|
textureName = "glowMap";
|
||||||
|
break;
|
||||||
case Nif::NiTexturingProperty::DarkTexture:
|
case Nif::NiTexturingProperty::DarkTexture:
|
||||||
|
textureName = "darkMap";
|
||||||
|
break;
|
||||||
case Nif::NiTexturingProperty::BumpTexture:
|
case Nif::NiTexturingProperty::BumpTexture:
|
||||||
|
textureName = "bumpMap";
|
||||||
|
break;
|
||||||
case Nif::NiTexturingProperty::DetailTexture:
|
case Nif::NiTexturingProperty::DetailTexture:
|
||||||
|
textureName = "detailMap";
|
||||||
|
break;
|
||||||
case Nif::NiTexturingProperty::DecalTexture:
|
case Nif::NiTexturingProperty::DecalTexture:
|
||||||
|
textureName = "decalMap";
|
||||||
|
break;
|
||||||
case Nif::NiTexturingProperty::GlossTexture:
|
case Nif::NiTexturingProperty::GlossTexture:
|
||||||
|
textureName = "glossMap";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
@ -2013,12 +2055,9 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int uvSet = 0;
|
const unsigned int texUnit = boundTextures.size();
|
||||||
// create a new texture, will later attempt to share using the SharedStateManager
|
if (tex.mEnabled)
|
||||||
osg::ref_ptr<osg::Texture2D> texture2d;
|
|
||||||
if (texprop->mTextures[i].mEnabled)
|
|
||||||
{
|
{
|
||||||
const Nif::NiTexturingProperty::Texture& tex = texprop->mTextures[i];
|
|
||||||
if (tex.mSourceTexture.empty() && texprop->mController.empty())
|
if (tex.mSourceTexture.empty() && texprop->mController.empty())
|
||||||
{
|
{
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
|
@ -2028,32 +2067,18 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tex.mSourceTexture.empty())
|
if (!tex.mSourceTexture.empty())
|
||||||
{
|
attachNiSourceTexture(textureName, tex.mSourceTexture.getPtr(), tex.wrapS(), tex.wrapT(),
|
||||||
const Nif::NiSourceTexture* st = tex.mSourceTexture.getPtr();
|
tex.mUVSet, stateset, boundTextures);
|
||||||
osg::ref_ptr<osg::Image> image = handleSourceTexture(st, imageManager);
|
|
||||||
texture2d = new osg::Texture2D(image);
|
|
||||||
if (image)
|
|
||||||
texture2d->setTextureSize(image->s(), image->t());
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
texture2d = new osg::Texture2D;
|
attachTexture(
|
||||||
|
textureName, nullptr, tex.wrapS(), tex.wrapT(), tex.mUVSet, stateset, boundTextures);
|
||||||
handleTextureWrapping(texture2d, tex.wrapS(), tex.wrapT());
|
|
||||||
|
|
||||||
uvSet = tex.mUVSet;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Texture only comes from NiFlipController, so tex is ignored, set defaults
|
// Texture only comes from NiFlipController, so tex is ignored, set defaults
|
||||||
texture2d = new osg::Texture2D;
|
attachTexture(textureName, nullptr, true, true, 0, stateset, boundTextures);
|
||||||
handleTextureWrapping(texture2d, true, true);
|
|
||||||
uvSet = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int texUnit = boundTextures.size();
|
|
||||||
|
|
||||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
|
||||||
|
|
||||||
if (i == Nif::NiTexturingProperty::GlowTexture)
|
if (i == Nif::NiTexturingProperty::GlowTexture)
|
||||||
{
|
{
|
||||||
stateset->setTextureAttributeAndModes(texUnit, createEmissiveTexEnv(), osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(texUnit, createEmissiveTexEnv(), osg::StateAttribute::ON);
|
||||||
|
@ -2121,51 +2146,165 @@ namespace NifOsg
|
||||||
texEnv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
|
texEnv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
|
||||||
stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case Nif::NiTexturingProperty::BaseTexture:
|
|
||||||
texture2d->setName("diffuseMap");
|
|
||||||
break;
|
|
||||||
case Nif::NiTexturingProperty::BumpTexture:
|
|
||||||
texture2d->setName("bumpMap");
|
|
||||||
break;
|
|
||||||
case Nif::NiTexturingProperty::GlowTexture:
|
|
||||||
texture2d->setName("emissiveMap");
|
|
||||||
break;
|
|
||||||
case Nif::NiTexturingProperty::DarkTexture:
|
|
||||||
texture2d->setName("darkMap");
|
|
||||||
break;
|
|
||||||
case Nif::NiTexturingProperty::DetailTexture:
|
|
||||||
texture2d->setName("detailMap");
|
|
||||||
break;
|
|
||||||
case Nif::NiTexturingProperty::DecalTexture:
|
|
||||||
texture2d->setName("decalMap");
|
|
||||||
break;
|
|
||||||
case Nif::NiTexturingProperty::GlossTexture:
|
|
||||||
texture2d->setName("glossMap");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
boundTextures.push_back(uvSet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleTextureSet(const Nif::BSShaderTextureSet* textureSet, unsigned int clamp,
|
static Bgsm::MaterialFilePtr getShaderMaterial(
|
||||||
const std::string& nodeName, osg::StateSet* stateset, Resource::ImageManager* imageManager,
|
std::string_view path, Resource::BgsmFileManager* materialManager)
|
||||||
std::vector<unsigned int>& boundTextures)
|
|
||||||
{
|
{
|
||||||
if (!boundTextures.empty())
|
if (!materialManager)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!Misc::StringUtils::ciEndsWith(path, ".bgem") && !Misc::StringUtils::ciEndsWith(path, ".bgsm"))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::string normalizedPath = Misc::ResourceHelpers::correctMaterialPath(path, materialManager->getVFS());
|
||||||
|
try
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < boundTextures.size(); ++i)
|
return materialManager->get(VFS::Path::Normalized(normalizedPath));
|
||||||
stateset->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
}
|
||||||
boundTextures.clear();
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Failed to load shader material: " << e.what();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleShaderMaterialNodeProperties(
|
||||||
|
Bgsm::MaterialFilePtr material, osg::StateSet* stateset, std::vector<unsigned int>& boundTextures)
|
||||||
|
{
|
||||||
|
const unsigned int uvSet = 0;
|
||||||
|
const bool wrapS = (material->mClamp >> 1) & 0x1;
|
||||||
|
const bool wrapT = material->mClamp & 0x1;
|
||||||
|
if (material->mShaderType == Bgsm::ShaderType::Lighting)
|
||||||
|
{
|
||||||
|
const Bgsm::BGSMFile* bgsm = static_cast<const Bgsm::BGSMFile*>(material.get());
|
||||||
|
|
||||||
|
if (!bgsm->mDiffuseMap.empty())
|
||||||
|
attachExternalTexture(
|
||||||
|
"diffuseMap", bgsm->mDiffuseMap, wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
|
||||||
|
if (!bgsm->mNormalMap.empty())
|
||||||
|
attachExternalTexture("normalMap", bgsm->mNormalMap, wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
|
||||||
|
if (bgsm->mGlowMapEnabled && !bgsm->mGlowMap.empty())
|
||||||
|
attachExternalTexture("emissiveMap", bgsm->mGlowMap, wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
|
||||||
|
if (bgsm->mTree)
|
||||||
|
stateset->addUniform(new osg::Uniform("useTreeAnim", true));
|
||||||
|
}
|
||||||
|
else if (material->mShaderType == Bgsm::ShaderType::Effect)
|
||||||
|
{
|
||||||
|
const Bgsm::BGEMFile* bgem = static_cast<const Bgsm::BGEMFile*>(material.get());
|
||||||
|
|
||||||
|
if (!bgem->mBaseMap.empty())
|
||||||
|
attachExternalTexture("diffuseMap", bgem->mBaseMap, wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
|
||||||
|
bool useFalloff = bgem->mFalloff;
|
||||||
|
stateset->addUniform(new osg::Uniform("useFalloff", useFalloff));
|
||||||
|
if (useFalloff)
|
||||||
|
stateset->addUniform(new osg::Uniform("falloffParams", bgem->mFalloffParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (material->mTwoSided)
|
||||||
|
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||||
|
handleDepthFlags(stateset, material->mDepthTest, material->mDepthWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleDecal(bool enabled, bool hasSortAlpha, osg::Node& node)
|
||||||
|
{
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
osg::ref_ptr<osg::StateSet> stateset = node.getOrCreateStateSet();
|
||||||
|
osg::ref_ptr<osg::PolygonOffset> polygonOffset(new osg::PolygonOffset);
|
||||||
|
polygonOffset->setUnits(SceneUtil::AutoDepth::isReversed() ? 1.f : -1.f);
|
||||||
|
polygonOffset->setFactor(SceneUtil::AutoDepth::isReversed() ? 0.65f : -0.65f);
|
||||||
|
polygonOffset = shareAttribute(polygonOffset);
|
||||||
|
stateset->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON);
|
||||||
|
if (!mPushedSorter && !hasSortAlpha)
|
||||||
|
stateset->setRenderBinDetails(1, "SORT_BACK_TO_FRONT");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleAlphaTesting(
|
||||||
|
bool enabled, osg::AlphaFunc::ComparisonFunction function, int threshold, osg::Node& node)
|
||||||
|
{
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::AlphaFunc> alphaFunc(new osg::AlphaFunc(function, threshold / 255.f));
|
||||||
|
alphaFunc = shareAttribute(alphaFunc);
|
||||||
|
node.getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON);
|
||||||
|
}
|
||||||
|
else if (osg::StateSet* stateset = node.getStateSet())
|
||||||
|
{
|
||||||
|
stateset->removeAttribute(osg::StateAttribute::ALPHAFUNC);
|
||||||
|
stateset->removeMode(GL_ALPHA_TEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleAlphaBlending(
|
||||||
|
bool enabled, int sourceMode, int destMode, bool sort, bool& hasSortAlpha, osg::Node& node)
|
||||||
|
{
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::StateSet> stateset = node.getOrCreateStateSet();
|
||||||
|
osg::ref_ptr<osg::BlendFunc> blendFunc(
|
||||||
|
new osg::BlendFunc(getBlendMode(sourceMode), getBlendMode(destMode)));
|
||||||
|
// on AMD hardware, alpha still seems to be stored with an RGBA framebuffer with OpenGL.
|
||||||
|
// This might be mandated by the OpenGL 2.1 specification section 2.14.9, or might be a bug.
|
||||||
|
// Either way, D3D8.1 doesn't do that, so adapt the destination factor.
|
||||||
|
if (blendFunc->getDestination() == GL_DST_ALPHA)
|
||||||
|
blendFunc->setDestination(GL_ONE);
|
||||||
|
blendFunc = shareAttribute(blendFunc);
|
||||||
|
stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
if (sort)
|
||||||
|
{
|
||||||
|
hasSortAlpha = true;
|
||||||
|
if (!mPushedSorter)
|
||||||
|
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||||
|
}
|
||||||
|
else if (!mPushedSorter)
|
||||||
|
{
|
||||||
|
stateset->setRenderBinToInherit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (osg::ref_ptr<osg::StateSet> stateset = node.getStateSet())
|
||||||
|
{
|
||||||
|
stateset->removeAttribute(osg::StateAttribute::BLENDFUNC);
|
||||||
|
stateset->removeMode(GL_BLEND);
|
||||||
|
if (!mPushedSorter)
|
||||||
|
stateset->setRenderBinToInherit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleShaderMaterialDrawableProperties(
|
||||||
|
Bgsm::MaterialFilePtr shaderMat, osg::ref_ptr<osg::Material> mat, osg::Node& node, bool& hasSortAlpha)
|
||||||
|
{
|
||||||
|
mat->setAlpha(osg::Material::FRONT_AND_BACK, shaderMat->mTransparency);
|
||||||
|
handleAlphaTesting(shaderMat->mAlphaTest, osg::AlphaFunc::GREATER, shaderMat->mAlphaTestThreshold, node);
|
||||||
|
handleAlphaBlending(shaderMat->mAlphaBlend, shaderMat->mSourceBlendMode, shaderMat->mDestinationBlendMode,
|
||||||
|
true, hasSortAlpha, node);
|
||||||
|
handleDecal(shaderMat->mDecal, hasSortAlpha, node);
|
||||||
|
if (shaderMat->mShaderType == Bgsm::ShaderType::Lighting)
|
||||||
|
{
|
||||||
|
auto bgsm = static_cast<const Bgsm::BGSMFile*>(shaderMat.get());
|
||||||
|
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(bgsm->mEmittanceColor, 1.f));
|
||||||
|
mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(bgsm->mSpecularColor, 1.f));
|
||||||
|
}
|
||||||
|
else if (shaderMat->mShaderType == Bgsm::ShaderType::Effect)
|
||||||
|
{
|
||||||
|
auto bgem = static_cast<const Bgsm::BGEMFile*>(shaderMat.get());
|
||||||
|
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(bgem->mEmittanceColor, 1.f));
|
||||||
|
if (bgem->mSoft)
|
||||||
|
SceneUtil::setupSoftEffect(node, bgem->mSoftDepth, true, bgem->mSoftDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleTextureSet(const Nif::BSShaderTextureSet* textureSet, bool wrapS, bool wrapT,
|
||||||
|
const std::string& nodeName, osg::StateSet* stateset, std::vector<unsigned int>& boundTextures)
|
||||||
|
{
|
||||||
const unsigned int uvSet = 0;
|
const unsigned int uvSet = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < textureSet->mTextures.size(); ++i)
|
for (size_t i = 0; i < textureSet->mTextures.size(); ++i)
|
||||||
|
@ -2175,8 +2314,16 @@ namespace NifOsg
|
||||||
switch (static_cast<Nif::BSShaderTextureSet::TextureType>(i))
|
switch (static_cast<Nif::BSShaderTextureSet::TextureType>(i))
|
||||||
{
|
{
|
||||||
case Nif::BSShaderTextureSet::TextureType::Base:
|
case Nif::BSShaderTextureSet::TextureType::Base:
|
||||||
|
attachExternalTexture(
|
||||||
|
"diffuseMap", textureSet->mTextures[i], wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
break;
|
||||||
case Nif::BSShaderTextureSet::TextureType::Normal:
|
case Nif::BSShaderTextureSet::TextureType::Normal:
|
||||||
|
attachExternalTexture(
|
||||||
|
"normalMap", textureSet->mTextures[i], wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
|
break;
|
||||||
case Nif::BSShaderTextureSet::TextureType::Glow:
|
case Nif::BSShaderTextureSet::TextureType::Glow:
|
||||||
|
attachExternalTexture(
|
||||||
|
"emissiveMap", textureSet->mTextures[i], wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
@ -2185,31 +2332,6 @@ namespace NifOsg
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string filename
|
|
||||||
= Misc::ResourceHelpers::correctTexturePath(textureSet->mTextures[i], imageManager->getVFS());
|
|
||||||
osg::ref_ptr<osg::Image> image = imageManager->getImage(filename);
|
|
||||||
osg::ref_ptr<osg::Texture2D> texture2d = new osg::Texture2D(image);
|
|
||||||
if (image)
|
|
||||||
texture2d->setTextureSize(image->s(), image->t());
|
|
||||||
handleTextureWrapping(texture2d, (clamp >> 1) & 0x1, clamp & 0x1);
|
|
||||||
unsigned int texUnit = boundTextures.size();
|
|
||||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
|
||||||
// BSShaderTextureSet presence means there's no need for FFP support for the affected node
|
|
||||||
switch (static_cast<Nif::BSShaderTextureSet::TextureType>(i))
|
|
||||||
{
|
|
||||||
case Nif::BSShaderTextureSet::TextureType::Base:
|
|
||||||
texture2d->setName("diffuseMap");
|
|
||||||
break;
|
|
||||||
case Nif::BSShaderTextureSet::TextureType::Normal:
|
|
||||||
texture2d->setName("normalMap");
|
|
||||||
break;
|
|
||||||
case Nif::BSShaderTextureSet::TextureType::Glow:
|
|
||||||
texture2d->setName("emissiveMap");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
boundTextures.emplace_back(uvSet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2269,8 +2391,8 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleProperty(const Nif::NiProperty* property, osg::Node* node,
|
void handleProperty(const Nif::NiProperty* property, osg::Node* node,
|
||||||
SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager,
|
SceneUtil::CompositeStateSetUpdater* composite, std::vector<unsigned int>& boundTextures, int animflags,
|
||||||
std::vector<unsigned int>& boundTextures, int animflags, bool hasStencilProperty)
|
bool hasStencilProperty)
|
||||||
{
|
{
|
||||||
switch (property->recType)
|
switch (property->recType)
|
||||||
{
|
{
|
||||||
|
@ -2352,8 +2474,7 @@ namespace NifOsg
|
||||||
{
|
{
|
||||||
const Nif::NiTexturingProperty* texprop = static_cast<const Nif::NiTexturingProperty*>(property);
|
const Nif::NiTexturingProperty* texprop = static_cast<const Nif::NiTexturingProperty*>(property);
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||||
handleTextureProperty(
|
handleTextureProperty(texprop, node->getName(), stateset, composite, boundTextures, animflags);
|
||||||
texprop, node->getName(), stateset, composite, imageManager, boundTextures, animflags);
|
|
||||||
node->setUserValue("applyMode", static_cast<int>(texprop->mApplyMode));
|
node->setUserValue("applyMode", static_cast<int>(texprop->mApplyMode));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2364,13 +2485,13 @@ namespace NifOsg
|
||||||
node->setUserValue("shaderPrefix", std::string(getBSShaderPrefix(texprop->mType)));
|
node->setUserValue("shaderPrefix", std::string(getBSShaderPrefix(texprop->mType)));
|
||||||
node->setUserValue("shaderRequired", shaderRequired);
|
node->setUserValue("shaderRequired", shaderRequired);
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||||
|
clearBoundTextures(stateset, boundTextures);
|
||||||
|
const bool wrapS = (texprop->mClamp >> 1) & 0x1;
|
||||||
|
const bool wrapT = texprop->mClamp & 0x1;
|
||||||
if (!texprop->mTextureSet.empty())
|
if (!texprop->mTextureSet.empty())
|
||||||
{
|
|
||||||
auto textureSet = texprop->mTextureSet.getPtr();
|
|
||||||
handleTextureSet(
|
handleTextureSet(
|
||||||
textureSet, texprop->mClamp, node->getName(), stateset, imageManager, boundTextures);
|
texprop->mTextureSet.getPtr(), wrapS, wrapT, node->getName(), stateset, boundTextures);
|
||||||
}
|
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
|
||||||
if (texprop->refraction())
|
if (texprop->refraction())
|
||||||
SceneUtil::setupDistortion(*node, texprop->mRefraction.mStrength);
|
SceneUtil::setupDistortion(*node, texprop->mRefraction.mStrength);
|
||||||
break;
|
break;
|
||||||
|
@ -2383,34 +2504,20 @@ namespace NifOsg
|
||||||
node->setUserValue("shaderPrefix", std::string(getBSShaderPrefix(texprop->mType)));
|
node->setUserValue("shaderPrefix", std::string(getBSShaderPrefix(texprop->mType)));
|
||||||
node->setUserValue("shaderRequired", shaderRequired);
|
node->setUserValue("shaderRequired", shaderRequired);
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||||
|
clearBoundTextures(stateset, boundTextures);
|
||||||
if (!texprop->mFilename.empty())
|
if (!texprop->mFilename.empty())
|
||||||
{
|
{
|
||||||
if (!boundTextures.empty())
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < boundTextures.size(); ++i)
|
|
||||||
stateset->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
|
||||||
boundTextures.clear();
|
|
||||||
}
|
|
||||||
std::string filename
|
|
||||||
= Misc::ResourceHelpers::correctTexturePath(texprop->mFilename, imageManager->getVFS());
|
|
||||||
osg::ref_ptr<osg::Image> image = imageManager->getImage(filename);
|
|
||||||
osg::ref_ptr<osg::Texture2D> texture2d = new osg::Texture2D(image);
|
|
||||||
texture2d->setName("diffuseMap");
|
|
||||||
if (image)
|
|
||||||
texture2d->setTextureSize(image->s(), image->t());
|
|
||||||
handleTextureWrapping(texture2d, texprop->wrapS(), texprop->wrapT());
|
|
||||||
const unsigned int texUnit = 0;
|
|
||||||
const unsigned int uvSet = 0;
|
const unsigned int uvSet = 0;
|
||||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
attachExternalTexture("diffuseMap", texprop->mFilename, texprop->wrapS(), texprop->wrapT(),
|
||||||
boundTextures.push_back(uvSet);
|
uvSet, stateset, boundTextures);
|
||||||
if (mBethVersion >= 27)
|
}
|
||||||
{
|
if (mBethVersion >= 27)
|
||||||
useFalloff = true;
|
{
|
||||||
stateset->addUniform(new osg::Uniform("falloffParams", texprop->mFalloffParams));
|
useFalloff = true;
|
||||||
}
|
stateset->addUniform(new osg::Uniform("falloffParams", texprop->mFalloffParams));
|
||||||
}
|
}
|
||||||
stateset->addUniform(new osg::Uniform("useFalloff", useFalloff));
|
stateset->addUniform(new osg::Uniform("useFalloff", useFalloff));
|
||||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||||
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2421,10 +2528,18 @@ namespace NifOsg
|
||||||
node->setUserValue("shaderPrefix", std::string(getBSLightingShaderPrefix(texprop->mType)));
|
node->setUserValue("shaderPrefix", std::string(getBSLightingShaderPrefix(texprop->mType)));
|
||||||
node->setUserValue("shaderRequired", shaderRequired);
|
node->setUserValue("shaderRequired", shaderRequired);
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||||
|
clearBoundTextures(stateset, boundTextures);
|
||||||
|
if (Bgsm::MaterialFilePtr material = getShaderMaterial(texprop->mName, mMaterialManager))
|
||||||
|
{
|
||||||
|
handleShaderMaterialNodeProperties(material, stateset, boundTextures);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const bool wrapS = (texprop->mClamp >> 1) & 0x1;
|
||||||
|
const bool wrapT = texprop->mClamp & 0x1;
|
||||||
if (!texprop->mTextureSet.empty())
|
if (!texprop->mTextureSet.empty())
|
||||||
handleTextureSet(texprop->mTextureSet.getPtr(), texprop->mClamp, node->getName(), stateset,
|
handleTextureSet(
|
||||||
imageManager, boundTextures);
|
texprop->mTextureSet.getPtr(), wrapS, wrapT, node->getName(), stateset, boundTextures);
|
||||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||||
if (texprop->doubleSided())
|
if (texprop->doubleSided())
|
||||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||||
if (texprop->treeAnim())
|
if (texprop->treeAnim())
|
||||||
|
@ -2442,27 +2557,20 @@ namespace NifOsg
|
||||||
node->setUserValue("shaderPrefix", std::string("bs/nolighting"));
|
node->setUserValue("shaderPrefix", std::string("bs/nolighting"));
|
||||||
node->setUserValue("shaderRequired", shaderRequired);
|
node->setUserValue("shaderRequired", shaderRequired);
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||||
|
clearBoundTextures(stateset, boundTextures);
|
||||||
|
if (Bgsm::MaterialFilePtr material = getShaderMaterial(texprop->mName, mMaterialManager))
|
||||||
|
{
|
||||||
|
handleShaderMaterialNodeProperties(material, stateset, boundTextures);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!texprop->mSourceTexture.empty())
|
if (!texprop->mSourceTexture.empty())
|
||||||
{
|
{
|
||||||
if (!boundTextures.empty())
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < boundTextures.size(); ++i)
|
|
||||||
stateset->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
|
||||||
boundTextures.clear();
|
|
||||||
}
|
|
||||||
std::string filename = Misc::ResourceHelpers::correctTexturePath(
|
|
||||||
texprop->mSourceTexture, imageManager->getVFS());
|
|
||||||
osg::ref_ptr<osg::Image> image = imageManager->getImage(filename);
|
|
||||||
osg::ref_ptr<osg::Texture2D> texture2d = new osg::Texture2D(image);
|
|
||||||
texture2d->setName("diffuseMap");
|
|
||||||
if (image)
|
|
||||||
texture2d->setTextureSize(image->s(), image->t());
|
|
||||||
handleTextureWrapping(texture2d, (texprop->mClamp >> 1) & 0x1, texprop->mClamp & 0x1);
|
|
||||||
const unsigned int texUnit = 0;
|
|
||||||
const unsigned int uvSet = 0;
|
const unsigned int uvSet = 0;
|
||||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
const bool wrapS = (texprop->mClamp >> 1) & 0x1;
|
||||||
boundTextures.push_back(uvSet);
|
const bool wrapT = texprop->mClamp & 0x1;
|
||||||
|
unsigned int texUnit = boundTextures.size();
|
||||||
|
attachExternalTexture(
|
||||||
|
"diffuseMap", texprop->mSourceTexture, wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::TexMat> texMat(new osg::TexMat);
|
osg::ref_ptr<osg::TexMat> texMat(new osg::TexMat);
|
||||||
// This handles 20.2.0.7 UV settings like 4.0.0.2 UV settings (see NifOsg::UVController)
|
// This handles 20.2.0.7 UV settings like 4.0.0.2 UV settings (see NifOsg::UVController)
|
||||||
|
@ -2484,7 +2592,7 @@ namespace NifOsg
|
||||||
stateset->addUniform(new osg::Uniform("useFalloff", useFalloff));
|
stateset->addUniform(new osg::Uniform("useFalloff", useFalloff));
|
||||||
if (useFalloff)
|
if (useFalloff)
|
||||||
stateset->addUniform(new osg::Uniform("falloffParams", texprop->mFalloffParams));
|
stateset->addUniform(new osg::Uniform("falloffParams", texprop->mFalloffParams));
|
||||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||||
if (texprop->doubleSided())
|
if (texprop->doubleSided())
|
||||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||||
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
||||||
|
@ -2566,12 +2674,9 @@ namespace NifOsg
|
||||||
|
|
||||||
bool hasMatCtrl = false;
|
bool hasMatCtrl = false;
|
||||||
bool hasSortAlpha = false;
|
bool hasSortAlpha = false;
|
||||||
osg::StateSet* blendFuncStateSet = nullptr;
|
|
||||||
|
|
||||||
auto setBin_Transparent = [](osg::StateSet* ss) { ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); };
|
|
||||||
auto setBin_BackToFront = [](osg::StateSet* ss) { ss->setRenderBinDetails(0, "SORT_BACK_TO_FRONT"); };
|
auto setBin_BackToFront = [](osg::StateSet* ss) { ss->setRenderBinDetails(0, "SORT_BACK_TO_FRONT"); };
|
||||||
auto setBin_Traversal = [](osg::StateSet* ss) { ss->setRenderBinDetails(2, "TraversalOrderBin"); };
|
auto setBin_Traversal = [](osg::StateSet* ss) { ss->setRenderBinDetails(2, "TraversalOrderBin"); };
|
||||||
auto setBin_Inherit = [](osg::StateSet* ss) { ss->setRenderBinToInherit(); };
|
|
||||||
|
|
||||||
auto lightmode = Nif::NiVertexColorProperty::LightMode::LightMode_EmiAmbDif;
|
auto lightmode = Nif::NiVertexColorProperty::LightMode::LightMode_EmiAmbDif;
|
||||||
float emissiveMult = 1.f;
|
float emissiveMult = 1.f;
|
||||||
|
@ -2657,52 +2762,10 @@ namespace NifOsg
|
||||||
case Nif::RC_NiAlphaProperty:
|
case Nif::RC_NiAlphaProperty:
|
||||||
{
|
{
|
||||||
const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property);
|
const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property);
|
||||||
if (alphaprop->useAlphaBlending())
|
handleAlphaBlending(alphaprop->useAlphaBlending(), alphaprop->sourceBlendMode(),
|
||||||
{
|
alphaprop->destinationBlendMode(), !alphaprop->noSorter(), hasSortAlpha, *node);
|
||||||
osg::ref_ptr<osg::BlendFunc> blendFunc(
|
handleAlphaTesting(alphaprop->useAlphaTesting(), getTestMode(alphaprop->alphaTestMode()),
|
||||||
new osg::BlendFunc(getBlendMode(alphaprop->sourceBlendMode()),
|
alphaprop->mThreshold, *node);
|
||||||
getBlendMode(alphaprop->destinationBlendMode())));
|
|
||||||
// on AMD hardware, alpha still seems to be stored with an RGBA framebuffer with OpenGL.
|
|
||||||
// This might be mandated by the OpenGL 2.1 specification section 2.14.9, or might be a bug.
|
|
||||||
// Either way, D3D8.1 doesn't do that, so adapt the destination factor.
|
|
||||||
if (blendFunc->getDestination() == GL_DST_ALPHA)
|
|
||||||
blendFunc->setDestination(GL_ONE);
|
|
||||||
blendFunc = shareAttribute(blendFunc);
|
|
||||||
node->getOrCreateStateSet()->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
|
||||||
|
|
||||||
if (!alphaprop->noSorter())
|
|
||||||
{
|
|
||||||
hasSortAlpha = true;
|
|
||||||
if (!mPushedSorter)
|
|
||||||
setBin_Transparent(node->getStateSet());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!mPushedSorter)
|
|
||||||
setBin_Inherit(node->getStateSet());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (osg::StateSet* stateset = node->getStateSet())
|
|
||||||
{
|
|
||||||
stateset->removeAttribute(osg::StateAttribute::BLENDFUNC);
|
|
||||||
stateset->removeMode(GL_BLEND);
|
|
||||||
blendFuncStateSet = stateset;
|
|
||||||
if (!mPushedSorter)
|
|
||||||
blendFuncStateSet->setRenderBinToInherit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alphaprop->useAlphaTesting())
|
|
||||||
{
|
|
||||||
osg::ref_ptr<osg::AlphaFunc> alphaFunc(new osg::AlphaFunc(
|
|
||||||
getTestMode(alphaprop->alphaTestMode()), alphaprop->mThreshold / 255.f));
|
|
||||||
alphaFunc = shareAttribute(alphaFunc);
|
|
||||||
node->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON);
|
|
||||||
}
|
|
||||||
else if (osg::StateSet* stateset = node->getStateSet())
|
|
||||||
{
|
|
||||||
stateset->removeAttribute(osg::StateAttribute::ALPHAFUNC);
|
|
||||||
stateset->removeMode(GL_ALPHA_TEST);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Nif::RC_BSShaderPPLightingProperty:
|
case Nif::RC_BSShaderPPLightingProperty:
|
||||||
|
@ -2714,6 +2777,18 @@ namespace NifOsg
|
||||||
case Nif::RC_BSLightingShaderProperty:
|
case Nif::RC_BSLightingShaderProperty:
|
||||||
{
|
{
|
||||||
auto shaderprop = static_cast<const Nif::BSLightingShaderProperty*>(property);
|
auto shaderprop = static_cast<const Nif::BSLightingShaderProperty*>(property);
|
||||||
|
if (Bgsm::MaterialFilePtr shaderMat = getShaderMaterial(shaderprop->mName, mMaterialManager))
|
||||||
|
{
|
||||||
|
handleShaderMaterialDrawableProperties(shaderMat, mat, *node, hasSortAlpha);
|
||||||
|
if (shaderMat->mShaderType == Bgsm::ShaderType::Lighting)
|
||||||
|
{
|
||||||
|
auto bgsm = static_cast<const Bgsm::BGSMFile*>(shaderMat.get());
|
||||||
|
specEnabled = false; // bgsm->mSpecularEnabled; TODO: PBR specular lighting
|
||||||
|
specStrength = 1.f; // bgsm->mSpecularMult;
|
||||||
|
emissiveMult = bgsm->mEmittanceMult;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
mat->setAlpha(osg::Material::FRONT_AND_BACK, shaderprop->mAlpha);
|
mat->setAlpha(osg::Material::FRONT_AND_BACK, shaderprop->mAlpha);
|
||||||
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(shaderprop->mEmissive, 1.f));
|
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(shaderprop->mEmissive, 1.f));
|
||||||
mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(shaderprop->mSpecular, 1.f));
|
mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(shaderprop->mSpecular, 1.f));
|
||||||
|
@ -2722,31 +2797,18 @@ namespace NifOsg
|
||||||
emissiveMult = shaderprop->mEmissiveMult;
|
emissiveMult = shaderprop->mEmissiveMult;
|
||||||
specStrength = shaderprop->mSpecStrength;
|
specStrength = shaderprop->mSpecStrength;
|
||||||
specEnabled = shaderprop->specular();
|
specEnabled = shaderprop->specular();
|
||||||
if (shaderprop->decal())
|
handleDecal(shaderprop->decal(), hasSortAlpha, *node);
|
||||||
{
|
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
|
||||||
if (!mPushedSorter && !hasSortAlpha)
|
|
||||||
stateset->setRenderBinDetails(1, "SORT_BACK_TO_FRONT");
|
|
||||||
osg::ref_ptr<osg::PolygonOffset> polygonOffset(new osg::PolygonOffset);
|
|
||||||
polygonOffset->setUnits(SceneUtil::AutoDepth::isReversed() ? 1.f : -1.f);
|
|
||||||
polygonOffset->setFactor(SceneUtil::AutoDepth::isReversed() ? 0.65f : -0.65f);
|
|
||||||
stateset->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Nif::RC_BSEffectShaderProperty:
|
case Nif::RC_BSEffectShaderProperty:
|
||||||
{
|
{
|
||||||
auto shaderprop = static_cast<const Nif::BSEffectShaderProperty*>(property);
|
auto shaderprop = static_cast<const Nif::BSEffectShaderProperty*>(property);
|
||||||
if (shaderprop->decal())
|
if (Bgsm::MaterialFilePtr shaderMat = getShaderMaterial(shaderprop->mName, mMaterialManager))
|
||||||
{
|
{
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
handleShaderMaterialDrawableProperties(shaderMat, mat, *node, hasSortAlpha);
|
||||||
if (!mPushedSorter && !hasSortAlpha)
|
break;
|
||||||
stateset->setRenderBinDetails(1, "SORT_BACK_TO_FRONT");
|
|
||||||
osg::ref_ptr<osg::PolygonOffset> polygonOffset(new osg::PolygonOffset);
|
|
||||||
polygonOffset->setUnits(SceneUtil::AutoDepth::isReversed() ? 1.f : -1.f);
|
|
||||||
polygonOffset->setFactor(SceneUtil::AutoDepth::isReversed() ? 0.65f : -0.65f);
|
|
||||||
stateset->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON);
|
|
||||||
}
|
}
|
||||||
|
handleDecal(shaderprop->decal(), hasSortAlpha, *node);
|
||||||
if (shaderprop->softEffect())
|
if (shaderprop->softEffect())
|
||||||
SceneUtil::setupSoftEffect(
|
SceneUtil::setupSoftEffect(
|
||||||
*node, shaderprop->mFalloffDepth, true, shaderprop->mFalloffDepth);
|
*node, shaderprop->mFalloffDepth, true, shaderprop->mFalloffDepth);
|
||||||
|
@ -2860,10 +2922,13 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> Loader::load(Nif::FileView file, Resource::ImageManager* imageManager)
|
osg::ref_ptr<osg::Node> Loader::load(
|
||||||
|
Nif::FileView file, Resource::ImageManager* imageManager, Resource::BgsmFileManager* materialManager)
|
||||||
{
|
{
|
||||||
LoaderImpl impl(file.getFilename(), file.getVersion(), file.getUserVersion(), file.getBethVersion());
|
LoaderImpl impl(file.getFilename(), file.getVersion(), file.getUserVersion(), file.getBethVersion());
|
||||||
return impl.load(file, imageManager);
|
impl.mMaterialManager = materialManager;
|
||||||
|
impl.mImageManager = imageManager;
|
||||||
|
return impl.load(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loader::loadKf(Nif::FileView kf, SceneUtil::KeyframeHolder& target)
|
void Loader::loadKf(Nif::FileView kf, SceneUtil::KeyframeHolder& target)
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace osg
|
||||||
namespace Resource
|
namespace Resource
|
||||||
{
|
{
|
||||||
class ImageManager;
|
class ImageManager;
|
||||||
|
class BgsmFileManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace NifOsg
|
namespace NifOsg
|
||||||
|
@ -30,7 +31,8 @@ namespace NifOsg
|
||||||
public:
|
public:
|
||||||
/// Create a scene graph for the given NIF. Auto-detects when skinning is used and wraps the graph in a Skeleton
|
/// Create a scene graph for the given NIF. Auto-detects when skinning is used and wraps the graph in a Skeleton
|
||||||
/// if so.
|
/// if so.
|
||||||
static osg::ref_ptr<osg::Node> load(Nif::FileView file, Resource::ImageManager* imageManager);
|
static osg::ref_ptr<osg::Node> load(
|
||||||
|
Nif::FileView file, Resource::ImageManager* imageManager, Resource::BgsmFileManager* materialManager);
|
||||||
|
|
||||||
/// Load keyframe controllers from the given kf file.
|
/// Load keyframe controllers from the given kf file.
|
||||||
static void loadKf(Nif::FileView kf, SceneUtil::KeyframeHolder& target);
|
static void loadKf(Nif::FileView kf, SceneUtil::KeyframeHolder& target);
|
||||||
|
|
58
components/resource/bgsmfilemanager.cpp
Normal file
58
components/resource/bgsmfilemanager.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "bgsmfilemanager.hpp"
|
||||||
|
|
||||||
|
#include <osg/Object>
|
||||||
|
|
||||||
|
#include <components/bgsm/reader.hpp>
|
||||||
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
|
#include "objectcache.hpp"
|
||||||
|
|
||||||
|
namespace Resource
|
||||||
|
{
|
||||||
|
|
||||||
|
class BgsmFileHolder : public osg::Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BgsmFileHolder(const Bgsm::MaterialFilePtr& file)
|
||||||
|
: mBgsmFile(file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
BgsmFileHolder(const BgsmFileHolder& copy, const osg::CopyOp& copyop)
|
||||||
|
: mBgsmFile(copy.mBgsmFile)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BgsmFileHolder() = default;
|
||||||
|
|
||||||
|
META_Object(Resource, BgsmFileHolder)
|
||||||
|
|
||||||
|
Bgsm::MaterialFilePtr mBgsmFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
BgsmFileManager::BgsmFileManager(const VFS::Manager* vfs, double expiryDelay)
|
||||||
|
: ResourceManager(vfs, expiryDelay)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Bgsm::MaterialFilePtr BgsmFileManager::get(VFS::Path::NormalizedView name)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(name);
|
||||||
|
if (obj)
|
||||||
|
return static_cast<BgsmFileHolder*>(obj.get())->mBgsmFile;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Bgsm::Reader reader;
|
||||||
|
reader.parse(mVFS->get(name));
|
||||||
|
Bgsm::MaterialFilePtr file = reader.getFile();
|
||||||
|
obj = new BgsmFileHolder(file);
|
||||||
|
mCache->addEntryToObjectCache(name.value(), obj);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BgsmFileManager::reportStats(unsigned int frameNumber, osg::Stats* stats) const
|
||||||
|
{
|
||||||
|
Resource::reportStats("BSShader Material", frameNumber, mCache->getStats(), *stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
components/resource/bgsmfilemanager.hpp
Normal file
27
components/resource/bgsmfilemanager.hpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_RESOURCE_BGSMFILEMANAGER_H
|
||||||
|
#define OPENMW_COMPONENTS_RESOURCE_BGSMFILEMANAGER_H
|
||||||
|
|
||||||
|
#include <components/bgsm/file.hpp>
|
||||||
|
|
||||||
|
#include "resourcemanager.hpp"
|
||||||
|
|
||||||
|
namespace Resource
|
||||||
|
{
|
||||||
|
|
||||||
|
/// @brief Handles caching of material files.
|
||||||
|
/// @note May be used from any thread.
|
||||||
|
class BgsmFileManager : public ResourceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BgsmFileManager(const VFS::Manager* vfs, double expiryDelay);
|
||||||
|
~BgsmFileManager() = default;
|
||||||
|
|
||||||
|
/// Retrieve a material file from the cache or load it from the VFS if not cached yet.
|
||||||
|
Bgsm::MaterialFilePtr get(VFS::Path::NormalizedView name);
|
||||||
|
|
||||||
|
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "bgsmfilemanager.hpp"
|
||||||
#include "imagemanager.hpp"
|
#include "imagemanager.hpp"
|
||||||
#include "keyframemanager.hpp"
|
#include "keyframemanager.hpp"
|
||||||
#include "niffilemanager.hpp"
|
#include "niffilemanager.hpp"
|
||||||
|
@ -15,11 +16,14 @@ namespace Resource
|
||||||
: mVFS(vfs)
|
: mVFS(vfs)
|
||||||
{
|
{
|
||||||
mNifFileManager = std::make_unique<NifFileManager>(vfs, encoder);
|
mNifFileManager = std::make_unique<NifFileManager>(vfs, encoder);
|
||||||
|
mBgsmFileManager = std::make_unique<BgsmFileManager>(vfs, expiryDelay);
|
||||||
mImageManager = std::make_unique<ImageManager>(vfs, expiryDelay);
|
mImageManager = std::make_unique<ImageManager>(vfs, expiryDelay);
|
||||||
mSceneManager = std::make_unique<SceneManager>(vfs, mImageManager.get(), mNifFileManager.get(), expiryDelay);
|
mSceneManager = std::make_unique<SceneManager>(
|
||||||
|
vfs, mImageManager.get(), mNifFileManager.get(), mBgsmFileManager.get(), expiryDelay);
|
||||||
mKeyframeManager = std::make_unique<KeyframeManager>(vfs, mSceneManager.get(), expiryDelay, encoder);
|
mKeyframeManager = std::make_unique<KeyframeManager>(vfs, mSceneManager.get(), expiryDelay, encoder);
|
||||||
|
|
||||||
addResourceManager(mNifFileManager.get());
|
addResourceManager(mNifFileManager.get());
|
||||||
|
addResourceManager(mBgsmFileManager.get());
|
||||||
addResourceManager(mKeyframeManager.get());
|
addResourceManager(mKeyframeManager.get());
|
||||||
// note, scene references images so add images afterwards for correct implementation of updateCache()
|
// note, scene references images so add images afterwards for correct implementation of updateCache()
|
||||||
addResourceManager(mSceneManager.get());
|
addResourceManager(mSceneManager.get());
|
||||||
|
@ -43,6 +47,11 @@ namespace Resource
|
||||||
return mImageManager.get();
|
return mImageManager.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BgsmFileManager* ResourceSystem::getBgsmFileManager()
|
||||||
|
{
|
||||||
|
return mBgsmFileManager.get();
|
||||||
|
}
|
||||||
|
|
||||||
NifFileManager* ResourceSystem::getNifFileManager()
|
NifFileManager* ResourceSystem::getNifFileManager()
|
||||||
{
|
{
|
||||||
return mNifFileManager.get();
|
return mNifFileManager.get();
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace Resource
|
||||||
|
|
||||||
class SceneManager;
|
class SceneManager;
|
||||||
class ImageManager;
|
class ImageManager;
|
||||||
|
class BgsmFileManager;
|
||||||
class NifFileManager;
|
class NifFileManager;
|
||||||
class KeyframeManager;
|
class KeyframeManager;
|
||||||
class BaseResourceManager;
|
class BaseResourceManager;
|
||||||
|
@ -41,6 +42,7 @@ namespace Resource
|
||||||
|
|
||||||
SceneManager* getSceneManager();
|
SceneManager* getSceneManager();
|
||||||
ImageManager* getImageManager();
|
ImageManager* getImageManager();
|
||||||
|
BgsmFileManager* getBgsmFileManager();
|
||||||
NifFileManager* getNifFileManager();
|
NifFileManager* getNifFileManager();
|
||||||
KeyframeManager* getKeyframeManager();
|
KeyframeManager* getKeyframeManager();
|
||||||
|
|
||||||
|
@ -74,6 +76,7 @@ namespace Resource
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<SceneManager> mSceneManager;
|
std::unique_ptr<SceneManager> mSceneManager;
|
||||||
std::unique_ptr<ImageManager> mImageManager;
|
std::unique_ptr<ImageManager> mImageManager;
|
||||||
|
std::unique_ptr<BgsmFileManager> mBgsmFileManager;
|
||||||
std::unique_ptr<NifFileManager> mNifFileManager;
|
std::unique_ptr<NifFileManager> mNifFileManager;
|
||||||
std::unique_ptr<KeyframeManager> mKeyframeManager;
|
std::unique_ptr<KeyframeManager> mKeyframeManager;
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include <components/files/hash.hpp>
|
#include <components/files/hash.hpp>
|
||||||
#include <components/files/memorystream.hpp>
|
#include <components/files/memorystream.hpp>
|
||||||
|
|
||||||
|
#include "bgsmfilemanager.hpp"
|
||||||
#include "errormarker.hpp"
|
#include "errormarker.hpp"
|
||||||
#include "imagemanager.hpp"
|
#include "imagemanager.hpp"
|
||||||
#include "niffilemanager.hpp"
|
#include "niffilemanager.hpp"
|
||||||
|
@ -409,7 +410,7 @@ namespace Resource
|
||||||
};
|
};
|
||||||
|
|
||||||
SceneManager::SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager,
|
SceneManager::SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager,
|
||||||
Resource::NifFileManager* nifFileManager, double expiryDelay)
|
Resource::NifFileManager* nifFileManager, Resource::BgsmFileManager* bgsmFileManager, double expiryDelay)
|
||||||
: ResourceManager(vfs, expiryDelay)
|
: ResourceManager(vfs, expiryDelay)
|
||||||
, mShaderManager(new Shader::ShaderManager)
|
, mShaderManager(new Shader::ShaderManager)
|
||||||
, mForceShaders(false)
|
, mForceShaders(false)
|
||||||
|
@ -424,6 +425,7 @@ namespace Resource
|
||||||
, mSharedStateManager(new SharedStateManager)
|
, mSharedStateManager(new SharedStateManager)
|
||||||
, mImageManager(imageManager)
|
, mImageManager(imageManager)
|
||||||
, mNifFileManager(nifFileManager)
|
, mNifFileManager(nifFileManager)
|
||||||
|
, mBgsmFileManager(bgsmFileManager)
|
||||||
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
|
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
|
||||||
, mMagFilter(osg::Texture::LINEAR)
|
, mMagFilter(osg::Texture::LINEAR)
|
||||||
, mMaxAnisotropy(1)
|
, mMaxAnisotropy(1)
|
||||||
|
@ -795,11 +797,12 @@ namespace Resource
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> load(VFS::Path::NormalizedView normalizedFilename, const VFS::Manager* vfs,
|
osg::ref_ptr<osg::Node> load(VFS::Path::NormalizedView normalizedFilename, const VFS::Manager* vfs,
|
||||||
Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
|
Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager,
|
||||||
|
Resource::BgsmFileManager* materialMgr)
|
||||||
{
|
{
|
||||||
const std::string_view ext = Misc::getFileExtension(normalizedFilename.value());
|
const std::string_view ext = Misc::getFileExtension(normalizedFilename.value());
|
||||||
if (ext == "nif")
|
if (ext == "nif")
|
||||||
return NifOsg::Loader::load(*nifFileManager->get(normalizedFilename), imageManager);
|
return NifOsg::Loader::load(*nifFileManager->get(normalizedFilename), imageManager, materialMgr);
|
||||||
else if (ext == "spt")
|
else if (ext == "spt")
|
||||||
{
|
{
|
||||||
Log(Debug::Warning) << "Ignoring SpeedTree data file " << normalizedFilename;
|
Log(Debug::Warning) << "Ignoring SpeedTree data file " << normalizedFilename;
|
||||||
|
@ -921,7 +924,7 @@ namespace Resource
|
||||||
{
|
{
|
||||||
path.changeExtension(meshType);
|
path.changeExtension(meshType);
|
||||||
if (mVFS->exists(path))
|
if (mVFS->exists(path))
|
||||||
return load(path, mVFS, mImageManager, mNifFileManager);
|
return load(path, mVFS, mImageManager, mNifFileManager, mBgsmFileManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
|
@ -953,7 +956,7 @@ namespace Resource
|
||||||
osg::ref_ptr<osg::Node> loaded;
|
osg::ref_ptr<osg::Node> loaded;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
loaded = load(normalized, mVFS, mImageManager, mNifFileManager);
|
loaded = load(normalized, mVFS, mImageManager, mNifFileManager, mBgsmFileManager);
|
||||||
|
|
||||||
SceneUtil::ProcessExtraDataVisitor extraDataVisitor(this);
|
SceneUtil::ProcessExtraDataVisitor extraDataVisitor(this);
|
||||||
loaded->accept(extraDataVisitor);
|
loaded->accept(extraDataVisitor);
|
||||||
|
|
|
@ -32,6 +32,7 @@ namespace Resource
|
||||||
{
|
{
|
||||||
class ImageManager;
|
class ImageManager;
|
||||||
class NifFileManager;
|
class NifFileManager;
|
||||||
|
class BgsmFileManager;
|
||||||
class SharedStateManager;
|
class SharedStateManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ namespace Resource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager,
|
explicit SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager,
|
||||||
Resource::NifFileManager* nifFileManager, double expiryDelay);
|
Resource::NifFileManager* nifFileManager, Resource::BgsmFileManager* bgsmFileManager, double expiryDelay);
|
||||||
~SceneManager();
|
~SceneManager();
|
||||||
|
|
||||||
Shader::ShaderManager& getShaderManager();
|
Shader::ShaderManager& getShaderManager();
|
||||||
|
@ -259,6 +260,7 @@ namespace Resource
|
||||||
|
|
||||||
Resource::ImageManager* mImageManager;
|
Resource::ImageManager* mImageManager;
|
||||||
Resource::NifFileManager* mNifFileManager;
|
Resource::NifFileManager* mNifFileManager;
|
||||||
|
Resource::BgsmFileManager* mBgsmFileManager;
|
||||||
|
|
||||||
osg::Texture::FilterMode mMinFilter;
|
osg::Texture::FilterMode mMinFilter;
|
||||||
osg::Texture::FilterMode mMagFilter;
|
osg::Texture::FilterMode mMagFilter;
|
||||||
|
|
|
@ -87,6 +87,7 @@ namespace Resource
|
||||||
"Image",
|
"Image",
|
||||||
"Nif",
|
"Nif",
|
||||||
"Keyframe",
|
"Keyframe",
|
||||||
|
"BSShader Material",
|
||||||
"Groundcover Chunk",
|
"Groundcover Chunk",
|
||||||
"Object Chunk",
|
"Object Chunk",
|
||||||
"Terrain Chunk",
|
"Terrain Chunk",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue