diff --git a/src/ObjLoading/AssetLoading/AbstractGdtEntryReader.cpp b/src/ObjLoading/AssetLoading/AbstractGdtEntryReader.cpp index 5c1ae860..01eba76a 100644 --- a/src/ObjLoading/AssetLoading/AbstractGdtEntryReader.cpp +++ b/src/ObjLoading/AssetLoading/AbstractGdtEntryReader.cpp @@ -79,3 +79,66 @@ float AbstractGdtEntryReader::ReadFloatProperty(const std::string& propertyName, return result; } + +Vector2f AbstractGdtEntryReader::ReadVec2Property(const std::string& propertyName, const Vector2f defaultValue) const +{ + const auto foundProperty = m_entry.m_properties.find(propertyName); + if (foundProperty == m_entry.m_properties.end()) + return defaultValue; + + std::istringstream iss(foundProperty->second); + Vector2f result; + + iss >> result(0) >> result(1); + + if (iss.fail()) + { + std::ostringstream oss; + oss << "\"" << foundProperty->second << "\" is not a valid vec2 value"; + throw GdtReadingException(oss.str()); + } + + return result; +} + +Vector3f AbstractGdtEntryReader::ReadVec3Property(const std::string& propertyName, const Vector3f defaultValue) const +{ + const auto foundProperty = m_entry.m_properties.find(propertyName); + if (foundProperty == m_entry.m_properties.end()) + return defaultValue; + + std::istringstream iss(foundProperty->second); + Vector3f result; + + iss >> result(0) >> result(1) >> result(2); + + if (iss.fail()) + { + std::ostringstream oss; + oss << "\"" << foundProperty->second << "\" is not a valid vec3 value"; + throw GdtReadingException(oss.str()); + } + + return result; +} + +Vector4f AbstractGdtEntryReader::ReadVec4Property(const std::string& propertyName, const Vector4f defaultValue) const +{ + const auto foundProperty = m_entry.m_properties.find(propertyName); + if (foundProperty == m_entry.m_properties.end()) + return defaultValue; + + std::istringstream iss(foundProperty->second); + Vector4f result; + + iss >> result(0) >> result(1) >> result(2) >> result(3); + + if (iss.fail()) + { + std::ostringstream oss; + oss << "\"" << foundProperty->second << "\" is not a valid vec4 value"; + throw GdtReadingException(oss.str()); + } + + return result; +} diff --git a/src/ObjLoading/AssetLoading/AbstractGdtEntryReader.h b/src/ObjLoading/AssetLoading/AbstractGdtEntryReader.h index e731380b..df45dcf7 100644 --- a/src/ObjLoading/AssetLoading/AbstractGdtEntryReader.h +++ b/src/ObjLoading/AssetLoading/AbstractGdtEntryReader.h @@ -2,6 +2,7 @@ #include +#include "Math/Vector.h" #include "Utils/ClassUtils.h" #include "Obj/Gdt/GdtEntry.h" @@ -24,6 +25,9 @@ protected: _NODISCARD bool ReadBoolProperty(const std::string& propertyName, bool defaultValue = false) const; _NODISCARD int ReadIntegerProperty(const std::string& propertyName, int defaultValue = 0) const; _NODISCARD float ReadFloatProperty(const std::string& propertyName, float defaultValue = 0.0f) const; + _NODISCARD Vector2f ReadVec2Property(const std::string& propertyName, Vector2f defaultValue = {}) const; + _NODISCARD Vector3f ReadVec3Property(const std::string& propertyName, Vector3f defaultValue = {}) const; + _NODISCARD Vector4f ReadVec4Property(const std::string& propertyName, Vector4f defaultValue = {}) const; const GdtEntry& m_entry; }; diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMaterial.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMaterial.cpp index 97e29fc9..9e3ccf0a 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMaterial.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderMaterial.cpp @@ -11,6 +11,7 @@ #include "Game/IW4/IW4.h" #include "Game/IW4/MaterialConstantsIW4.h" #include "Game/IW4/ObjConstantsIW4.h" +#include "Math/Vector.h" #include "Pool/GlobalAssetPool.h" using namespace IW4; @@ -183,8 +184,23 @@ namespace IW4 void mtl_tools_template() { - // TODO - throw SkipMaterialException(); + commonsetup_template(); + + SetTechniqueSet("tools"); + + AddMapTexture("normalMap", TileMode_e::NO_TILE, GdtFilter_e::NOMIP_NEAREST, TS_NORMAL_MAP, "$identitynormalmap"); + + const auto colorMapName = ReadStringProperty("colorMap"); + const auto tileColor = ReadEnumProperty("tileColor", GdtTileModeNames, std::extent_v); + const auto filterColor = ReadEnumProperty("filterColor", GdtSamplerFilterNames, std::extent_v); + + if (!colorMapName.empty()) + AddMapTexture("colorMap", tileColor, filterColor, TS_COLOR_MAP, colorMapName); + else + throw GdtReadingException("ColorMap may not be blank in tools materials"); + + const auto colorTint = ReadVec4Property("colorTint", {1.0f, 1.0f, 1.0f, 1.0f}); + AddConstant("colorTint", colorTint); } void mtl_sky_template() @@ -730,6 +746,19 @@ namespace IW4 m_textures.push_back(textureDef); } + void AddConstant(const std::string& constantName, Vector4f literalData) + { + MaterialConstantDef constantDef{}; + constantDef.literal[0] = literalData(0); + constantDef.literal[1] = literalData(1); + constantDef.literal[2] = literalData(2); + constantDef.literal[3] = literalData(3); + strncpy(constantDef.name, constantName.c_str(), std::extent_v); + constantDef.nameHash = Common::R_HashString(constantName.c_str()); + + m_constants.push_back(constantDef); + } + void SetSort(const unsigned char sort) const { m_material->info.sortKey = sort; @@ -994,6 +1023,18 @@ namespace IW4 m_material->textureCount = 0u; } + if (!m_constants.empty()) + { + m_material->constantTable = static_cast(m_memory->Alloc(sizeof(MaterialConstantDef) * m_constants.size())); + m_material->constantCount = static_cast(m_constants.size()); + memcpy(m_material->constantTable, m_constants.data(), sizeof(MaterialConstantDef) * m_constants.size()); + } + else + { + m_material->constantTable = nullptr; + m_material->constantCount = 0u; + } + if (!m_state_bits.empty()) { m_material->stateBitsTable = static_cast(m_memory->Alloc(sizeof(GfxStateBits) * m_state_bits.size())); @@ -1034,6 +1075,7 @@ namespace IW4 GfxStateBits m_base_state_bits; std::vector m_state_bits; std::vector m_textures; + std::vector m_constants; }; }