From aea7b10986343bca77ae74c9f2892c9cf7161dc6 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Wed, 17 Apr 2024 22:53:55 +0300 Subject: [PATCH] Add dummy BGSM/BGEM file reader --- components/CMakeLists.txt | 4 + components/bgsm/file.cpp | 20 +++++ components/bgsm/file.hpp | 164 +++++++++++++++++++++++++++++++++++++ components/bgsm/reader.cpp | 35 ++++++++ components/bgsm/reader.hpp | 25 ++++++ components/bgsm/stream.cpp | 110 +++++++++++++++++++++++++ components/bgsm/stream.hpp | 143 ++++++++++++++++++++++++++++++++ 7 files changed, 501 insertions(+) create mode 100644 components/bgsm/file.cpp create mode 100644 components/bgsm/file.hpp create mode 100644 components/bgsm/reader.cpp create mode 100644 components/bgsm/reader.hpp create mode 100644 components/bgsm/stream.cpp create mode 100644 components/bgsm/stream.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 68411be2fc..084deaea58 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -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 ) diff --git a/components/bgsm/file.cpp b/components/bgsm/file.cpp new file mode 100644 index 0000000000..870d9e4067 --- /dev/null +++ b/components/bgsm/file.cpp @@ -0,0 +1,20 @@ +#include "file.hpp" + +#include "stream.hpp" + +namespace Bgsm +{ + void MaterialFile::read(BGSMStream& stream) + { + } + + void BGSMFile::read(BGSMStream& stream) + { + MaterialFile::read(stream); + } + + void BGEMFile::read(BGSMStream& stream) + { + MaterialFile::read(stream); + } +} diff --git a/components/bgsm/file.hpp b/components/bgsm/file.hpp new file mode 100644 index 0000000000..117b135e4f --- /dev/null +++ b/components/bgsm/file.hpp @@ -0,0 +1,164 @@ +#ifndef OPENMW_COMPONENTS_BGSM_FILE_HPP +#define OPENMW_COMPONENTS_BGSM_FILE_HPP + +#include +#include +#include +#include + +#include +#include +#include + +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; + std::uint8_t mSourceBlendMode; + std::uint32_t mDestinationBlendMode; + std::uint32_t mAlphaTestMode; + std::uint8_t mAlphaTestRef; + bool mAlphaTest; + bool mDepthWrite, mDepthTest; + bool mSSR; + bool mWetnessControlSSR; + bool mDecal; + bool mTwoSided; + bool mDecalNoFade; + bool mNonOccluder; + bool mRefraction; + bool mRefractionFalloff; + float mRefractionPower; + bool mEnvMap; + float mEnvMapMaskScale; + bool mDepthBias; + bool mGrayscaleToPaletteColor; + std::uint8_t mMaskWrites; + + MaterialFile() = default; + virtual void read(BGSMStream& stream); + virtual ~MaterialFile() {} + }; + + struct BGSMFile : MaterialFile + { + std::string mDiffuseMap; + std::string mNormalMap; + std::string mSmoothSpecMap; + std::string mGreyscaleMap; + 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 mEnableEditorAlphaRef; + bool mTranslucency; + bool mTranslucencyThickObject; + bool mTranslucencyMixAlbedoWithSubsurfaceColor; + osg::Vec4f mTranslucencySubsurfaceColor; + float mTranslucencyTransmissiveScale; + float mTranslucencyTurbulence; + bool mRimLighting; + float mRimPower; + float mBackLightPower; + bool mSursurfaceLighting; + float mSubsurfaceLightingRolloff; + bool mSpecularEnabled; + osg::Vec4f 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::Vec4f 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 mHasGlowMap; + bool mEnvMapWindow; + bool mEnvMapEye; + bool mHair; + osg::Vec4f mHairTintColor; + bool mTree; + bool mFacegen; + bool mSkinTint; + bool mTessellate; + osg::Vec2f mDisplacementMapParams; + osg::Vec3f mTesselationParams; + 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::Vec4f mBaseColor; + float mBaseColorScale; + osg::Vec4f mFalloffParams; + float mLightingInfluence; + std::uint8_t mEnvmapMinLOD; + float mSoftDepth; + osg::Vec4f mEmittanceColor; + osg::Vec3f mAdaptiveEmissiveExposureParams; + bool mHasGlowMap; + bool mEffectPbrSpecular; + + void read(BGSMStream& stream) override; + }; + + using MaterialFilePtr = std::shared_ptr; +} +#endif diff --git a/components/bgsm/reader.cpp b/components/bgsm/reader.cpp new file mode 100644 index 0000000000..c89d872bd7 --- /dev/null +++ b/components/bgsm/reader.cpp @@ -0,0 +1,35 @@ +#include "reader.hpp" + +#include +#include +#include + +#include "file.hpp" +#include "stream.hpp" + +namespace Bgsm +{ + void Reader::parse(Files::IStreamPtr&& inputStream) + { + BGSMStream stream(*this, std::move(inputStream)); + + std::array signature; + stream.readArray(signature); + std::string shaderType(signature.data(), 4); + if (shaderType == "BGEM") + { + mFile = std::make_unique(); + mFile->mShaderType = Bgsm::ShaderType::Effect; + } + else if (shaderType == "BGSM") + { + mFile = std::make_unique(); + mFile->mShaderType = Bgsm::ShaderType::Lighting; + } + else + throw std::runtime_error("Invalid material file"); + + mFile->read(stream); + } + +} diff --git a/components/bgsm/reader.hpp b/components/bgsm/reader.hpp new file mode 100644 index 0000000000..5ac67c0467 --- /dev/null +++ b/components/bgsm/reader.hpp @@ -0,0 +1,25 @@ +#ifndef OPENMW_COMPONENTS_BGSM_READER_HPP +#define OPENMW_COMPONENTS_BGSM_READER_HPP + +#include +#include +#include +#include + +#include + +#include "file.hpp" + +namespace Bgsm +{ + class Reader + { + std::unique_ptr mFile; + + public: + void parse(Files::IStreamPtr&& stream); + + std::uint32_t getVersion() const { return mFile->mVersion; } + }; +} +#endif diff --git a/components/bgsm/stream.cpp b/components/bgsm/stream.cpp new file mode 100644 index 0000000000..d8434fcb8a --- /dev/null +++ b/components/bgsm/stream.cpp @@ -0,0 +1,110 @@ +#include "stream.hpp" + +#include + +#include "reader.hpp" + +namespace +{ + + // Read a range of elements into a dynamic buffer per-element + // This one should be used if the type cannot be read contiguously + // (e.g. quaternions) + template + void readRange(Bgsm::BGSMStream& stream, T* dest, size_t size) + { + for (T& value : std::span(dest, size)) + stream.read(value); + } + + // Read a range of elements into a dynamic buffer + // This one should be used if the type can be read contiguously as an array of a different type + // (e.g. osg::VecXf can be read as a float array of X elements) + template + void readAlignedRange(Files::IStreamPtr& stream, T* dest, size_t size) + { + static_assert(std::is_standard_layout_v); + static_assert(std::alignment_of_v == std::alignment_of_v); + static_assert(sizeof(T) == sizeof(elementType) * numElements); + Bgsm::readDynamicBufferOfType(stream, reinterpret_cast(dest), size * numElements); + } + +} + +namespace Bgsm +{ + + std::uint32_t BGSMStream::getVersion() const + { + return mReader.getVersion(); + } + + std::string BGSMStream::getSizedString(size_t length) + { + std::string str(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"); + size_t end = str.find('\0'); + if (end != std::string::npos) + str.erase(end); + return str; + } + + void BGSMStream::getSizedStrings(std::vector& vec, size_t size) + { + vec.resize(size); + for (size_t i = 0; i < vec.size(); i++) + vec[i] = getSizedString(); + } + + template <> + void BGSMStream::read(osg::Vec2f& vec) + { + readBufferOfType(mStream, vec._v); + } + + template <> + void BGSMStream::read(osg::Vec3f& vec) + { + readBufferOfType(mStream, vec._v); + } + + template <> + void BGSMStream::read(osg::Vec4f& vec) + { + readBufferOfType(mStream, vec._v); + } + + template <> + void BGSMStream::read(std::string& str) + { + str = getSizedString(); + } + + template <> + void BGSMStream::read(osg::Vec2f* dest, size_t size) + { + readAlignedRange(mStream, dest, size); + } + + template <> + void BGSMStream::read(osg::Vec3f* dest, size_t size) + { + readAlignedRange(mStream, dest, size); + } + + template <> + void BGSMStream::read(osg::Vec4f* dest, size_t size) + { + readAlignedRange(mStream, dest, size); + } + + template <> + void BGSMStream::read(std::string* dest, size_t size) + { + for (std::string& value : std::span(dest, size)) + value = getSizedString(); + } + +} diff --git a/components/bgsm/stream.hpp b/components/bgsm/stream.hpp new file mode 100644 index 0000000000..8b0e1efdbe --- /dev/null +++ b/components/bgsm/stream.hpp @@ -0,0 +1,143 @@ +#ifndef OPENMW_COMPONENTS_BGSM_STREAM_HPP +#define OPENMW_COMPONENTS_BGSM_STREAM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace Bgsm +{ + class Reader; + + template + inline void readBufferOfType(Files::IStreamPtr& pIStream, T* dest) + { + static_assert(std::is_arithmetic_v, "Buffer element type is not arithmetic"); + pIStream->read((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 + inline void readBufferOfType(Files::IStreamPtr& pIStream, T (&dest)[numInstances]) + { + readBufferOfType(pIStream, static_cast(dest)); + } + + template + inline void readDynamicBufferOfType(Files::IStreamPtr& pIStream, T* dest, std::size_t numInstances) + { + static_assert(std::is_arithmetic_v, "Buffer element type is not arithmetic"); + pIStream->read((char*)dest, numInstances * sizeof(T)); + if (pIStream->bad()) + throw std::runtime_error("Failed to read typed (" + std::string(typeid(T).name()) + ") dynamic 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]); + } + + class BGSMStream + { + const Reader& mReader; + Files::IStreamPtr mStream; + + public: + explicit BGSMStream( + const Reader& reader, Files::IStreamPtr&& stream) + : mReader(reader) + , mStream(std::move(stream)) + { + } + + const Reader& getFile() const { return mReader; } + + std::uint32_t getVersion() const; + + void skip(size_t size) { mStream->ignore(size); } + + /// Read into a single instance of type + template + void read(T& data) + { + readBufferOfType<1>(mStream, &data); + } + + /// Read multiple instances of type into an array + template + void readArray(std::array& arr) + { + readBufferOfType(mStream, arr.data()); + } + + /// Read instances of type into a dynamic buffer + template + void read(T* dest, size_t size) + { + readDynamicBufferOfType(mStream, dest, size); + } + + /// Read multiple instances of type into a vector + template + void readVector(std::vector& vec, size_t size) + { + if (size == 0) + return; + vec.resize(size); + read(vec.data(), size); + } + + /// Extract an instance of type + template + T get() + { + T data; + read(data); + return data; + } + + /// Read a string of the given length + std::string getSizedString(size_t length); + + /// Read a string of the length specified in the file + std::string getSizedString() { return getSizedString(get()); } + + /// Read a list of strings + void getSizedStrings(std::vector& vec, size_t size); + }; + + template <> + void BGSMStream::read(osg::Vec2f& vec); + template <> + void BGSMStream::read(osg::Vec3f& vec); + template <> + void BGSMStream::read(osg::Vec4f& vec); + template <> + void BGSMStream::read(std::string& str); + + template <> + void BGSMStream::read(osg::Vec2f* dest, size_t size); + template <> + void BGSMStream::read(osg::Vec3f* dest, size_t size); + template <> + void BGSMStream::read(osg::Vec4f* dest, size_t size); + template <> + void BGSMStream::read(std::string* dest, size_t size); +} + +#endif