mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 03:29:55 +00: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 #7698: Implement sAbsorb, sDamage, sDrain, sFortify and sRestore
|
||||
Feature #7709: Improve resolution selection in Launcher
|
||||
Feature #7777: Support external Bethesda material files (BGSM/BGEM)
|
||||
Feature #7792: Support Timescale Clouds
|
||||
Feature #7795: Support MaxNumberRipples INI setting
|
||||
Feature #7805: Lua Menu context
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/misc/strings/conversion.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/resource/bgsmfilemanager.hpp>
|
||||
#include <components/resource/bulletshape.hpp>
|
||||
#include <components/resource/bulletshapemanager.hpp>
|
||||
#include <components/resource/foreachbulletobject.hpp>
|
||||
|
@ -173,7 +174,8 @@ namespace
|
|||
constexpr double expiryDelay = 0;
|
||||
Resource::ImageManager imageManager(&vfs, expiryDelay);
|
||||
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::forEachBulletObject(
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <components/files/conversion.hpp>
|
||||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/resource/bgsmfilemanager.hpp>
|
||||
#include <components/resource/bulletshapemanager.hpp>
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
#include <components/resource/niffilemanager.hpp>
|
||||
|
@ -220,7 +221,8 @@ namespace NavMeshTool
|
|||
|
||||
Resource::ImageManager imageManager(&vfs, expiryDelay);
|
||||
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);
|
||||
DetourNavigator::RecastGlobalAllocator::init();
|
||||
DetourNavigator::Settings navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <components/bgsm/reader.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/files/constrainedfilestream.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
|
@ -25,7 +26,7 @@
|
|||
namespace bpo = boost::program_options;
|
||||
|
||||
/// 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());
|
||||
return Misc::StringUtils::ciEqual(extension, extensionToFind);
|
||||
|
@ -36,6 +37,13 @@ bool isNIF(const std::filesystem::path& filename)
|
|||
{
|
||||
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.
|
||||
bool isBSA(const std::filesystem::path& filename)
|
||||
{
|
||||
|
@ -51,16 +59,17 @@ std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void readNIF(
|
||||
void readFile(
|
||||
const std::filesystem::path& source, const std::filesystem::path& path, const VFS::Manager* vfs, bool quiet)
|
||||
{
|
||||
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||
const bool isNif = isNIF(path);
|
||||
if (!quiet)
|
||||
{
|
||||
if (hasExtension(path, ".kf"))
|
||||
std::cout << "Reading KF file '" << pathStr << "'";
|
||||
if (isNif)
|
||||
std::cout << "Reading " << (hasExtension(path, ".nif") ? "NIF" : "KF") << " file '" << pathStr << "'";
|
||||
else
|
||||
std::cout << "Reading NIF file '" << pathStr << "'";
|
||||
std::cout << "Reading " << (hasExtension(path, ".bgsm") ? "BGSM" : "BGEM") << " file '" << pathStr << "'";
|
||||
if (!source.empty())
|
||||
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
|
||||
std::cout << std::endl;
|
||||
|
@ -68,12 +77,23 @@ void readNIF(
|
|||
const std::filesystem::path fullPath = !source.empty() ? source / path : path;
|
||||
try
|
||||
{
|
||||
Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
|
||||
Nif::Reader reader(file, nullptr);
|
||||
if (vfs != nullptr)
|
||||
reader.parse(vfs->get(pathStr));
|
||||
if (isNif)
|
||||
{
|
||||
Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
|
||||
Nif::Reader reader(file, nullptr);
|
||||
if (vfs != nullptr)
|
||||
reader.parse(vfs->get(pathStr));
|
||||
else
|
||||
reader.parse(Files::openConstrainedFileStream(fullPath));
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
@ -97,9 +117,9 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
|||
|
||||
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& 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:
|
||||
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.
|
||||
|
||||
Allowed options)");
|
||||
|
@ -221,9 +241,9 @@ int main(int argc, char** argv)
|
|||
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||
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))
|
||||
{
|
||||
|
@ -231,7 +251,7 @@ int main(int argc, char** argv)
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <components/nif/node.hpp>
|
||||
#include <components/nif/property.hpp>
|
||||
#include <components/nifosg/nifloader.hpp>
|
||||
#include <components/resource/bgsmfilemanager.hpp>
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
#include <components/sceneutil/serialize.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
|
@ -29,6 +30,7 @@ namespace
|
|||
{
|
||||
VFS::Manager mVfs;
|
||||
Resource::ImageManager mImageManager{ &mVfs, 0 };
|
||||
Resource::BgsmFileManager mMaterialManager{ &mVfs, 0 };
|
||||
const osgDB::ReaderWriter* mReaderWriter = osgDB::Registry::instance()->getReaderWriterForExtension("osgt");
|
||||
osg::ref_ptr<osgDB::Options> mOptions = new osgDB::Options;
|
||||
|
||||
|
@ -70,7 +72,7 @@ namespace
|
|||
init(node);
|
||||
Nif::NIFFile file("test.nif");
|
||||
file.mRoots.push_back(&node);
|
||||
auto result = Loader::load(file, &mImageManager);
|
||||
auto result = Loader::load(file, &mImageManager, &mMaterialManager);
|
||||
EXPECT_EQ(serialize(*result), R"(
|
||||
osg::Group {
|
||||
UniqueID 1
|
||||
|
@ -259,7 +261,7 @@ osg::Group {
|
|||
node.mProperties.push_back(Nif::RecordPtrT<Nif::NiProperty>(&property));
|
||||
Nif::NIFFile file("test.nif");
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -289,7 +291,7 @@ osg::Group {
|
|||
node.mProperties.push_back(Nif::RecordPtrT<Nif::NiProperty>(&property));
|
||||
Nif::NIFFile file("test.nif");
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,10 @@ add_component_dir (settings
|
|||
windowmode
|
||||
)
|
||||
|
||||
add_component_dir (bgsm
|
||||
reader stream file
|
||||
)
|
||||
|
||||
add_component_dir (bsa
|
||||
bsa_file compressedbsafile ba2gnrlfile ba2dx10file ba2file memorystream
|
||||
)
|
||||
|
@ -125,7 +129,7 @@ add_component_dir (vfs
|
|||
|
||||
add_component_dir (resource
|
||||
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
|
||||
|
|
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;
|
||||
}
|
||||
|
||||
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 res = "meshes\\";
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace Misc
|
|||
/// 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". :(
|
||||
std::string correctActorModelPath(const std::string& resPath, const VFS::Manager* vfs);
|
||||
std::string correctMaterialPath(std::string_view resPath, const VFS::Manager* vfs);
|
||||
|
||||
// Adds "meshes\\".
|
||||
std::string correctMeshPath(std::string_view resPath);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <components/misc/strings/algorithm.hpp>
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
#include <components/nif/parent.hpp>
|
||||
#include <components/resource/bgsmfilemanager.hpp>
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
|
||||
// particle
|
||||
|
@ -42,6 +43,7 @@
|
|||
#include <osg/TexEnvCombine>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <components/bgsm/file.hpp>
|
||||
#include <components/nif/effect.hpp>
|
||||
#include <components/nif/exception.hpp>
|
||||
#include <components/nif/extra.hpp>
|
||||
|
@ -247,6 +249,8 @@ namespace NifOsg
|
|||
}
|
||||
std::filesystem::path mFilename;
|
||||
unsigned int mVersion, mUserVersion, mBethVersion;
|
||||
Resource::BgsmFileManager* mMaterialManager{ nullptr };
|
||||
Resource::ImageManager* mImageManager{ nullptr };
|
||||
|
||||
size_t mFirstRootTextureIndex{ ~0u };
|
||||
bool mFoundFirstRootTexturingProperty = false;
|
||||
|
@ -339,7 +343,6 @@ namespace NifOsg
|
|||
struct HandleNodeArgs
|
||||
{
|
||||
unsigned int mNifVersion;
|
||||
Resource::ImageManager* mImageManager;
|
||||
SceneUtil::TextKeyMap* mTextKeys;
|
||||
std::vector<unsigned int> mBoundTextures = {};
|
||||
int mAnimFlags = 0;
|
||||
|
@ -349,7 +352,7 @@ namespace NifOsg
|
|||
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();
|
||||
std::vector<const Nif::NiAVObject*> roots;
|
||||
|
@ -371,10 +374,8 @@ namespace NifOsg
|
|||
created->setDataVariance(osg::Object::STATIC);
|
||||
for (const Nif::NiAVObject* root : roots)
|
||||
{
|
||||
auto node = handleNode(root, nullptr, nullptr,
|
||||
{ .mNifVersion = nif.getVersion(),
|
||||
.mImageManager = imageManager,
|
||||
.mTextKeys = &textkeys->mTextKeys });
|
||||
auto node = handleNode(
|
||||
root, nullptr, nullptr, { .mNifVersion = nif.getVersion(), .mTextKeys = &textkeys->mTextKeys });
|
||||
created->addChild(node);
|
||||
}
|
||||
if (mHasNightDayLabel)
|
||||
|
@ -405,8 +406,7 @@ namespace NifOsg
|
|||
}
|
||||
|
||||
void applyNodeProperties(const Nif::NiAVObject* nifNode, osg::Node* applyTo,
|
||||
SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager,
|
||||
std::vector<unsigned int>& boundTextures, int animflags)
|
||||
SceneUtil::CompositeStateSetUpdater* composite, std::vector<unsigned int>& boundTextures, int animflags)
|
||||
{
|
||||
bool hasStencilProperty = false;
|
||||
|
||||
|
@ -444,8 +444,7 @@ namespace NifOsg
|
|||
if (property.getPtr()->recIndex == mFirstRootTextureIndex)
|
||||
applyTo->setUserValue("overrideFx", 1);
|
||||
}
|
||||
handleProperty(property.getPtr(), applyTo, composite, imageManager, boundTextures, animflags,
|
||||
hasStencilProperty);
|
||||
handleProperty(property.getPtr(), applyTo, composite, boundTextures, animflags, hasStencilProperty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -457,8 +456,7 @@ namespace NifOsg
|
|||
shaderprop = static_cast<const Nif::BSTriShape*>(nifNode)->mShaderProperty;
|
||||
|
||||
if (!shaderprop.empty())
|
||||
handleProperty(shaderprop.getPtr(), applyTo, composite, imageManager, boundTextures, animflags,
|
||||
hasStencilProperty);
|
||||
handleProperty(shaderprop.getPtr(), applyTo, composite, boundTextures, animflags, hasStencilProperty);
|
||||
}
|
||||
|
||||
static void setupController(const Nif::NiTimeController* ctrl, SceneUtil::Controller* toSetup, int animflags)
|
||||
|
@ -522,32 +520,21 @@ namespace NifOsg
|
|||
sequenceNode->setMode(osg::Sequence::START);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Image> handleSourceTexture(
|
||||
const Nif::NiSourceTexture* st, Resource::ImageManager* imageManager)
|
||||
osg::ref_ptr<osg::Image> handleSourceTexture(const Nif::NiSourceTexture* st) const
|
||||
{
|
||||
if (!st)
|
||||
return nullptr;
|
||||
if (st)
|
||||
{
|
||||
if (st->mExternal)
|
||||
return getTextureImage(st->mFile);
|
||||
|
||||
osg::ref_ptr<osg::Image> image;
|
||||
if (st->mExternal)
|
||||
{
|
||||
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->mFile, imageManager->getVFS());
|
||||
image = imageManager->getImage(filename);
|
||||
if (!st->mData.empty())
|
||||
return handleInternalTexture(st->mData.getPtr());
|
||||
}
|
||||
else if (!st->mData.empty())
|
||||
{
|
||||
image = handleInternalTexture(st->mData.getPtr());
|
||||
}
|
||||
return image;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void handleTextureWrapping(osg::Texture2D* texture, bool wrapS, bool wrapT)
|
||||
{
|
||||
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)
|
||||
bool handleEffect(const Nif::NiAVObject* nifNode, osg::StateSet* stateset)
|
||||
{
|
||||
if (nifNode->recType != Nif::RC_NiTextureEffect)
|
||||
{
|
||||
|
@ -590,16 +577,12 @@ namespace NifOsg
|
|||
return false;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Image> image(handleSourceTexture(textureEffect->mTexture.getPtr(), imageManager));
|
||||
osg::ref_ptr<osg::Texture2D> texture2d(new osg::Texture2D(image));
|
||||
if (image)
|
||||
texture2d->setTextureSize(image->s(), image->t());
|
||||
texture2d->setName("envMap");
|
||||
handleTextureWrapping(texture2d, textureEffect->wrapS(), textureEffect->wrapT());
|
||||
|
||||
int texUnit = 3; // FIXME
|
||||
|
||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
||||
const unsigned int uvSet = 0;
|
||||
const unsigned int texUnit = 3; // FIXME
|
||||
std::vector<unsigned int> boundTextures;
|
||||
boundTextures.resize(3); // Dummy vector for attachNiSourceTexture
|
||||
attachNiSourceTexture("envMap", textureEffect->mTexture.getPtr(), textureEffect->wrapS(),
|
||||
textureEffect->wrapT(), uvSet, stateset, boundTextures);
|
||||
stateset->setTextureAttributeAndModes(texUnit, texGen, 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;
|
||||
|
||||
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 isBSGeometry = isTypeBSGeometry(nifNode->recType);
|
||||
|
@ -769,7 +752,7 @@ namespace NifOsg
|
|||
|
||||
if (isGeometry && !args.mSkipMeshes)
|
||||
{
|
||||
bool skip;
|
||||
bool skip = false;
|
||||
if (args.mNifVersion <= Nif::NIFFile::NIFVersion::VER_MW)
|
||||
{
|
||||
skip = (args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->mName, "tri editormarker"))
|
||||
|
@ -777,7 +760,11 @@ namespace NifOsg
|
|||
|| Misc::StringUtils::ciStartsWith(nifNode->mName, "tri shadow");
|
||||
}
|
||||
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 (isNiGeometry)
|
||||
|
@ -859,7 +846,7 @@ namespace NifOsg
|
|||
if (!effect.empty())
|
||||
{
|
||||
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)
|
||||
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,
|
||||
SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager,
|
||||
osg::StateSet* stateset, int animflags)
|
||||
SceneUtil::CompositeStateSetUpdater* composite, osg::StateSet* stateset, int animflags)
|
||||
{
|
||||
for (Nif::NiTimeControllerPtr ctrl = texProperty->mController; !ctrl.empty(); ctrl = ctrl->mNext)
|
||||
{
|
||||
|
@ -1056,17 +1090,16 @@ namespace NifOsg
|
|||
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)
|
||||
{
|
||||
if (source.empty())
|
||||
continue;
|
||||
|
||||
osg::ref_ptr<osg::Image> image(handleSourceTexture(source.getPtr(), imageManager));
|
||||
osg::ref_ptr<osg::Texture2D> texture(new osg::Texture2D(image));
|
||||
if (image)
|
||||
texture->setTextureSize(image->s(), image->t());
|
||||
texture->setWrap(osg::Texture::WRAP_S, wrapS);
|
||||
texture->setWrap(osg::Texture::WRAP_T, wrapT);
|
||||
// NB: not changing the stateset
|
||||
osg::ref_ptr<osg::Texture2D> texture
|
||||
= attachNiSourceTexture({}, source.getPtr(), wrapS, wrapT, uvSet, nullptr, boundTextures);
|
||||
textures.push_back(texture);
|
||||
}
|
||||
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())
|
||||
return nullptr;
|
||||
|
@ -1946,7 +1979,7 @@ namespace NifOsg
|
|||
return image;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::TexEnvCombine> createEmissiveTexEnv()
|
||||
static osg::ref_ptr<osg::TexEnvCombine> createEmissiveTexEnv()
|
||||
{
|
||||
osg::ref_ptr<osg::TexEnvCombine> texEnv(new osg::TexEnvCombine);
|
||||
// Sum the previous colour and the emissive colour.
|
||||
|
@ -1977,33 +2010,42 @@ namespace NifOsg
|
|||
|
||||
void handleTextureProperty(const Nif::NiTexturingProperty* texprop, const std::string& nodeName,
|
||||
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
|
||||
for (unsigned int i = 0; i < boundTextures.size(); ++i)
|
||||
stateset->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
||||
boundTextures.clear();
|
||||
}
|
||||
// overriding a parent NiTexturingProperty, so remove what was previously bound
|
||||
clearBoundTextures(stateset, boundTextures);
|
||||
|
||||
// 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.
|
||||
for (size_t i = 0; i < texprop->mTextures.size(); ++i)
|
||||
{
|
||||
if (texprop->mTextures[i].mEnabled
|
||||
|| (i == Nif::NiTexturingProperty::BaseTexture && !texprop->mController.empty()))
|
||||
const Nif::NiTexturingProperty::Texture& tex = texprop->mTextures[i];
|
||||
if (tex.mEnabled || (i == Nif::NiTexturingProperty::BaseTexture && !texprop->mController.empty()))
|
||||
{
|
||||
std::string textureName;
|
||||
switch (i)
|
||||
{
|
||||
// These are handled later on
|
||||
case Nif::NiTexturingProperty::BaseTexture:
|
||||
textureName = "diffuseMap";
|
||||
break;
|
||||
case Nif::NiTexturingProperty::GlowTexture:
|
||||
textureName = "glowMap";
|
||||
break;
|
||||
case Nif::NiTexturingProperty::DarkTexture:
|
||||
textureName = "darkMap";
|
||||
break;
|
||||
case Nif::NiTexturingProperty::BumpTexture:
|
||||
textureName = "bumpMap";
|
||||
break;
|
||||
case Nif::NiTexturingProperty::DetailTexture:
|
||||
textureName = "detailMap";
|
||||
break;
|
||||
case Nif::NiTexturingProperty::DecalTexture:
|
||||
textureName = "decalMap";
|
||||
break;
|
||||
case Nif::NiTexturingProperty::GlossTexture:
|
||||
textureName = "glossMap";
|
||||
break;
|
||||
default:
|
||||
{
|
||||
|
@ -2013,12 +2055,9 @@ namespace NifOsg
|
|||
}
|
||||
}
|
||||
|
||||
unsigned int uvSet = 0;
|
||||
// create a new texture, will later attempt to share using the SharedStateManager
|
||||
osg::ref_ptr<osg::Texture2D> texture2d;
|
||||
if (texprop->mTextures[i].mEnabled)
|
||||
const unsigned int texUnit = boundTextures.size();
|
||||
if (tex.mEnabled)
|
||||
{
|
||||
const Nif::NiTexturingProperty::Texture& tex = texprop->mTextures[i];
|
||||
if (tex.mSourceTexture.empty() && texprop->mController.empty())
|
||||
{
|
||||
if (i == 0)
|
||||
|
@ -2028,32 +2067,18 @@ namespace NifOsg
|
|||
}
|
||||
|
||||
if (!tex.mSourceTexture.empty())
|
||||
{
|
||||
const Nif::NiSourceTexture* st = tex.mSourceTexture.getPtr();
|
||||
osg::ref_ptr<osg::Image> image = handleSourceTexture(st, imageManager);
|
||||
texture2d = new osg::Texture2D(image);
|
||||
if (image)
|
||||
texture2d->setTextureSize(image->s(), image->t());
|
||||
}
|
||||
attachNiSourceTexture(textureName, tex.mSourceTexture.getPtr(), tex.wrapS(), tex.wrapT(),
|
||||
tex.mUVSet, stateset, boundTextures);
|
||||
else
|
||||
texture2d = new osg::Texture2D;
|
||||
|
||||
handleTextureWrapping(texture2d, tex.wrapS(), tex.wrapT());
|
||||
|
||||
uvSet = tex.mUVSet;
|
||||
attachTexture(
|
||||
textureName, nullptr, tex.wrapS(), tex.wrapT(), tex.mUVSet, stateset, boundTextures);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Texture only comes from NiFlipController, so tex is ignored, set defaults
|
||||
texture2d = new osg::Texture2D;
|
||||
handleTextureWrapping(texture2d, true, true);
|
||||
uvSet = 0;
|
||||
attachTexture(textureName, nullptr, true, true, 0, stateset, boundTextures);
|
||||
}
|
||||
|
||||
unsigned int texUnit = boundTextures.size();
|
||||
|
||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
||||
|
||||
if (i == Nif::NiTexturingProperty::GlowTexture)
|
||||
{
|
||||
stateset->setTextureAttributeAndModes(texUnit, createEmissiveTexEnv(), osg::StateAttribute::ON);
|
||||
|
@ -2121,51 +2146,165 @@ namespace NifOsg
|
|||
texEnv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
|
||||
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,
|
||||
const std::string& nodeName, osg::StateSet* stateset, Resource::ImageManager* imageManager,
|
||||
std::vector<unsigned int>& boundTextures)
|
||||
static Bgsm::MaterialFilePtr getShaderMaterial(
|
||||
std::string_view path, Resource::BgsmFileManager* materialManager)
|
||||
{
|
||||
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)
|
||||
stateset->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
||||
boundTextures.clear();
|
||||
return materialManager->get(VFS::Path::Normalized(normalizedPath));
|
||||
}
|
||||
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;
|
||||
|
||||
for (size_t i = 0; i < textureSet->mTextures.size(); ++i)
|
||||
|
@ -2175,8 +2314,16 @@ namespace NifOsg
|
|||
switch (static_cast<Nif::BSShaderTextureSet::TextureType>(i))
|
||||
{
|
||||
case Nif::BSShaderTextureSet::TextureType::Base:
|
||||
attachExternalTexture(
|
||||
"diffuseMap", textureSet->mTextures[i], wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||
break;
|
||||
case Nif::BSShaderTextureSet::TextureType::Normal:
|
||||
attachExternalTexture(
|
||||
"normalMap", textureSet->mTextures[i], wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||
break;
|
||||
case Nif::BSShaderTextureSet::TextureType::Glow:
|
||||
attachExternalTexture(
|
||||
"emissiveMap", textureSet->mTextures[i], wrapS, wrapT, uvSet, stateset, boundTextures);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
|
@ -2185,31 +2332,6 @@ namespace NifOsg
|
|||
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,
|
||||
SceneUtil::CompositeStateSetUpdater* composite, Resource::ImageManager* imageManager,
|
||||
std::vector<unsigned int>& boundTextures, int animflags, bool hasStencilProperty)
|
||||
SceneUtil::CompositeStateSetUpdater* composite, std::vector<unsigned int>& boundTextures, int animflags,
|
||||
bool hasStencilProperty)
|
||||
{
|
||||
switch (property->recType)
|
||||
{
|
||||
|
@ -2352,8 +2474,7 @@ namespace NifOsg
|
|||
{
|
||||
const Nif::NiTexturingProperty* texprop = static_cast<const Nif::NiTexturingProperty*>(property);
|
||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||
handleTextureProperty(
|
||||
texprop, node->getName(), stateset, composite, imageManager, boundTextures, animflags);
|
||||
handleTextureProperty(texprop, node->getName(), stateset, composite, boundTextures, animflags);
|
||||
node->setUserValue("applyMode", static_cast<int>(texprop->mApplyMode));
|
||||
break;
|
||||
}
|
||||
|
@ -2364,13 +2485,13 @@ namespace NifOsg
|
|||
node->setUserValue("shaderPrefix", std::string(getBSShaderPrefix(texprop->mType)));
|
||||
node->setUserValue("shaderRequired", shaderRequired);
|
||||
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())
|
||||
{
|
||||
auto textureSet = texprop->mTextureSet.getPtr();
|
||||
handleTextureSet(
|
||||
textureSet, texprop->mClamp, node->getName(), stateset, imageManager, boundTextures);
|
||||
}
|
||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||
texprop->mTextureSet.getPtr(), wrapS, wrapT, node->getName(), stateset, boundTextures);
|
||||
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||
if (texprop->refraction())
|
||||
SceneUtil::setupDistortion(*node, texprop->mRefraction.mStrength);
|
||||
break;
|
||||
|
@ -2383,34 +2504,20 @@ namespace NifOsg
|
|||
node->setUserValue("shaderPrefix", std::string(getBSShaderPrefix(texprop->mType)));
|
||||
node->setUserValue("shaderRequired", shaderRequired);
|
||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||
clearBoundTextures(stateset, boundTextures);
|
||||
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;
|
||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
||||
boundTextures.push_back(uvSet);
|
||||
if (mBethVersion >= 27)
|
||||
{
|
||||
useFalloff = true;
|
||||
stateset->addUniform(new osg::Uniform("falloffParams", texprop->mFalloffParams));
|
||||
}
|
||||
attachExternalTexture("diffuseMap", texprop->mFilename, texprop->wrapS(), texprop->wrapT(),
|
||||
uvSet, stateset, boundTextures);
|
||||
}
|
||||
if (mBethVersion >= 27)
|
||||
{
|
||||
useFalloff = true;
|
||||
stateset->addUniform(new osg::Uniform("falloffParams", texprop->mFalloffParams));
|
||||
}
|
||||
stateset->addUniform(new osg::Uniform("useFalloff", useFalloff));
|
||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
||||
break;
|
||||
}
|
||||
|
@ -2421,10 +2528,18 @@ namespace NifOsg
|
|||
node->setUserValue("shaderPrefix", std::string(getBSLightingShaderPrefix(texprop->mType)));
|
||||
node->setUserValue("shaderRequired", shaderRequired);
|
||||
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())
|
||||
handleTextureSet(texprop->mTextureSet.getPtr(), texprop->mClamp, node->getName(), stateset,
|
||||
imageManager, boundTextures);
|
||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||
handleTextureSet(
|
||||
texprop->mTextureSet.getPtr(), wrapS, wrapT, node->getName(), stateset, boundTextures);
|
||||
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||
if (texprop->doubleSided())
|
||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
if (texprop->treeAnim())
|
||||
|
@ -2442,27 +2557,20 @@ namespace NifOsg
|
|||
node->setUserValue("shaderPrefix", std::string("bs/nolighting"));
|
||||
node->setUserValue("shaderRequired", shaderRequired);
|
||||
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 (!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;
|
||||
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
|
||||
boundTextures.push_back(uvSet);
|
||||
|
||||
const bool wrapS = (texprop->mClamp >> 1) & 0x1;
|
||||
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);
|
||||
// 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));
|
||||
if (useFalloff)
|
||||
stateset->addUniform(new osg::Uniform("falloffParams", texprop->mFalloffParams));
|
||||
handleTextureControllers(texprop, composite, imageManager, stateset, animflags);
|
||||
handleTextureControllers(texprop, composite, stateset, animflags);
|
||||
if (texprop->doubleSided())
|
||||
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
|
||||
handleDepthFlags(stateset, texprop->depthTest(), texprop->depthWrite());
|
||||
|
@ -2566,12 +2674,9 @@ namespace NifOsg
|
|||
|
||||
bool hasMatCtrl = 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_Traversal = [](osg::StateSet* ss) { ss->setRenderBinDetails(2, "TraversalOrderBin"); };
|
||||
auto setBin_Inherit = [](osg::StateSet* ss) { ss->setRenderBinToInherit(); };
|
||||
|
||||
auto lightmode = Nif::NiVertexColorProperty::LightMode::LightMode_EmiAmbDif;
|
||||
float emissiveMult = 1.f;
|
||||
|
@ -2657,52 +2762,10 @@ namespace NifOsg
|
|||
case Nif::RC_NiAlphaProperty:
|
||||
{
|
||||
const Nif::NiAlphaProperty* alphaprop = static_cast<const Nif::NiAlphaProperty*>(property);
|
||||
if (alphaprop->useAlphaBlending())
|
||||
{
|
||||
osg::ref_ptr<osg::BlendFunc> blendFunc(
|
||||
new osg::BlendFunc(getBlendMode(alphaprop->sourceBlendMode()),
|
||||
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);
|
||||
}
|
||||
handleAlphaBlending(alphaprop->useAlphaBlending(), alphaprop->sourceBlendMode(),
|
||||
alphaprop->destinationBlendMode(), !alphaprop->noSorter(), hasSortAlpha, *node);
|
||||
handleAlphaTesting(alphaprop->useAlphaTesting(), getTestMode(alphaprop->alphaTestMode()),
|
||||
alphaprop->mThreshold, *node);
|
||||
break;
|
||||
}
|
||||
case Nif::RC_BSShaderPPLightingProperty:
|
||||
|
@ -2714,6 +2777,18 @@ namespace NifOsg
|
|||
case Nif::RC_BSLightingShaderProperty:
|
||||
{
|
||||
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->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));
|
||||
|
@ -2722,31 +2797,18 @@ namespace NifOsg
|
|||
emissiveMult = shaderprop->mEmissiveMult;
|
||||
specStrength = shaderprop->mSpecStrength;
|
||||
specEnabled = shaderprop->specular();
|
||||
if (shaderprop->decal())
|
||||
{
|
||||
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);
|
||||
}
|
||||
handleDecal(shaderprop->decal(), hasSortAlpha, *node);
|
||||
break;
|
||||
}
|
||||
case Nif::RC_BSEffectShaderProperty:
|
||||
{
|
||||
auto shaderprop = static_cast<const Nif::BSEffectShaderProperty*>(property);
|
||||
if (shaderprop->decal())
|
||||
if (Bgsm::MaterialFilePtr shaderMat = getShaderMaterial(shaderprop->mName, mMaterialManager))
|
||||
{
|
||||
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);
|
||||
handleShaderMaterialDrawableProperties(shaderMat, mat, *node, hasSortAlpha);
|
||||
break;
|
||||
}
|
||||
handleDecal(shaderprop->decal(), hasSortAlpha, *node);
|
||||
if (shaderprop->softEffect())
|
||||
SceneUtil::setupSoftEffect(
|
||||
*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());
|
||||
return impl.load(file, imageManager);
|
||||
impl.mMaterialManager = materialManager;
|
||||
impl.mImageManager = imageManager;
|
||||
return impl.load(file);
|
||||
}
|
||||
|
||||
void Loader::loadKf(Nif::FileView kf, SceneUtil::KeyframeHolder& target)
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace osg
|
|||
namespace Resource
|
||||
{
|
||||
class ImageManager;
|
||||
class BgsmFileManager;
|
||||
}
|
||||
|
||||
namespace NifOsg
|
||||
|
@ -30,7 +31,8 @@ namespace NifOsg
|
|||
public:
|
||||
/// Create a scene graph for the given NIF. Auto-detects when skinning is used and wraps the graph in a Skeleton
|
||||
/// 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.
|
||||
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 "bgsmfilemanager.hpp"
|
||||
#include "imagemanager.hpp"
|
||||
#include "keyframemanager.hpp"
|
||||
#include "niffilemanager.hpp"
|
||||
|
@ -15,11 +16,14 @@ namespace Resource
|
|||
: mVFS(vfs)
|
||||
{
|
||||
mNifFileManager = std::make_unique<NifFileManager>(vfs, encoder);
|
||||
mBgsmFileManager = std::make_unique<BgsmFileManager>(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);
|
||||
|
||||
addResourceManager(mNifFileManager.get());
|
||||
addResourceManager(mBgsmFileManager.get());
|
||||
addResourceManager(mKeyframeManager.get());
|
||||
// note, scene references images so add images afterwards for correct implementation of updateCache()
|
||||
addResourceManager(mSceneManager.get());
|
||||
|
@ -43,6 +47,11 @@ namespace Resource
|
|||
return mImageManager.get();
|
||||
}
|
||||
|
||||
BgsmFileManager* ResourceSystem::getBgsmFileManager()
|
||||
{
|
||||
return mBgsmFileManager.get();
|
||||
}
|
||||
|
||||
NifFileManager* ResourceSystem::getNifFileManager()
|
||||
{
|
||||
return mNifFileManager.get();
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Resource
|
|||
|
||||
class SceneManager;
|
||||
class ImageManager;
|
||||
class BgsmFileManager;
|
||||
class NifFileManager;
|
||||
class KeyframeManager;
|
||||
class BaseResourceManager;
|
||||
|
@ -41,6 +42,7 @@ namespace Resource
|
|||
|
||||
SceneManager* getSceneManager();
|
||||
ImageManager* getImageManager();
|
||||
BgsmFileManager* getBgsmFileManager();
|
||||
NifFileManager* getNifFileManager();
|
||||
KeyframeManager* getKeyframeManager();
|
||||
|
||||
|
@ -74,6 +76,7 @@ namespace Resource
|
|||
private:
|
||||
std::unique_ptr<SceneManager> mSceneManager;
|
||||
std::unique_ptr<ImageManager> mImageManager;
|
||||
std::unique_ptr<BgsmFileManager> mBgsmFileManager;
|
||||
std::unique_ptr<NifFileManager> mNifFileManager;
|
||||
std::unique_ptr<KeyframeManager> mKeyframeManager;
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include <components/files/hash.hpp>
|
||||
#include <components/files/memorystream.hpp>
|
||||
|
||||
#include "bgsmfilemanager.hpp"
|
||||
#include "errormarker.hpp"
|
||||
#include "imagemanager.hpp"
|
||||
#include "niffilemanager.hpp"
|
||||
|
@ -409,7 +410,7 @@ namespace Resource
|
|||
};
|
||||
|
||||
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)
|
||||
, mShaderManager(new Shader::ShaderManager)
|
||||
, mForceShaders(false)
|
||||
|
@ -424,6 +425,7 @@ namespace Resource
|
|||
, mSharedStateManager(new SharedStateManager)
|
||||
, mImageManager(imageManager)
|
||||
, mNifFileManager(nifFileManager)
|
||||
, mBgsmFileManager(bgsmFileManager)
|
||||
, mMinFilter(osg::Texture::LINEAR_MIPMAP_LINEAR)
|
||||
, mMagFilter(osg::Texture::LINEAR)
|
||||
, mMaxAnisotropy(1)
|
||||
|
@ -795,11 +797,12 @@ namespace Resource
|
|||
}
|
||||
|
||||
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());
|
||||
if (ext == "nif")
|
||||
return NifOsg::Loader::load(*nifFileManager->get(normalizedFilename), imageManager);
|
||||
return NifOsg::Loader::load(*nifFileManager->get(normalizedFilename), imageManager, materialMgr);
|
||||
else if (ext == "spt")
|
||||
{
|
||||
Log(Debug::Warning) << "Ignoring SpeedTree data file " << normalizedFilename;
|
||||
|
@ -921,7 +924,7 @@ namespace Resource
|
|||
{
|
||||
path.changeExtension(meshType);
|
||||
if (mVFS->exists(path))
|
||||
return load(path, mVFS, mImageManager, mNifFileManager);
|
||||
return load(path, mVFS, mImageManager, mNifFileManager, mBgsmFileManager);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
|
@ -953,7 +956,7 @@ namespace Resource
|
|||
osg::ref_ptr<osg::Node> loaded;
|
||||
try
|
||||
{
|
||||
loaded = load(normalized, mVFS, mImageManager, mNifFileManager);
|
||||
loaded = load(normalized, mVFS, mImageManager, mNifFileManager, mBgsmFileManager);
|
||||
|
||||
SceneUtil::ProcessExtraDataVisitor extraDataVisitor(this);
|
||||
loaded->accept(extraDataVisitor);
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace Resource
|
|||
{
|
||||
class ImageManager;
|
||||
class NifFileManager;
|
||||
class BgsmFileManager;
|
||||
class SharedStateManager;
|
||||
}
|
||||
|
||||
|
@ -90,7 +91,7 @@ namespace Resource
|
|||
{
|
||||
public:
|
||||
explicit SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager,
|
||||
Resource::NifFileManager* nifFileManager, double expiryDelay);
|
||||
Resource::NifFileManager* nifFileManager, Resource::BgsmFileManager* bgsmFileManager, double expiryDelay);
|
||||
~SceneManager();
|
||||
|
||||
Shader::ShaderManager& getShaderManager();
|
||||
|
@ -259,6 +260,7 @@ namespace Resource
|
|||
|
||||
Resource::ImageManager* mImageManager;
|
||||
Resource::NifFileManager* mNifFileManager;
|
||||
Resource::BgsmFileManager* mBgsmFileManager;
|
||||
|
||||
osg::Texture::FilterMode mMinFilter;
|
||||
osg::Texture::FilterMode mMagFilter;
|
||||
|
|
|
@ -87,6 +87,7 @@ namespace Resource
|
|||
"Image",
|
||||
"Nif",
|
||||
"Keyframe",
|
||||
"BSShader Material",
|
||||
"Groundcover Chunk",
|
||||
"Object Chunk",
|
||||
"Terrain Chunk",
|
||||
|
|
Loading…
Reference in a new issue