mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
450 lines
13 KiB
C++
450 lines
13 KiB
C++
#include "AssetLoaderMaterial.h"
|
|
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
#include "ObjLoading.h"
|
|
#include "AssetLoading/AbstractGdtEntryReader.h"
|
|
#include "Game/IW4/CommonIW4.h"
|
|
#include "Game/IW4/IW4.h"
|
|
#include "Game/IW4/MaterialConstantsIW4.h"
|
|
#include "Game/IW4/ObjConstantsIW4.h"
|
|
#include "Pool/GlobalAssetPool.h"
|
|
|
|
using namespace IW4;
|
|
|
|
namespace IW4
|
|
{
|
|
class MaterialGdtLoader : AbstractGdtEntryReader
|
|
{
|
|
public:
|
|
MaterialGdtLoader(const GdtEntry& entry, MemoryManager* memory, IAssetLoadingManager* manager)
|
|
: AbstractGdtEntryReader(entry),
|
|
m_memory(memory),
|
|
m_manager(manager),
|
|
m_material(nullptr)
|
|
{
|
|
}
|
|
|
|
bool Load()
|
|
{
|
|
m_material = m_memory->Create<Material>();
|
|
memset(m_material, 0, sizeof(Material));
|
|
|
|
m_material->info.name = m_memory->Dup(m_entry.m_name.c_str());
|
|
material_template();
|
|
|
|
FinalizeMaterial();
|
|
return true;
|
|
}
|
|
|
|
_NODISCARD Material* GetMaterial() const
|
|
{
|
|
return m_material;
|
|
}
|
|
|
|
_NODISCARD std::vector<XAssetInfoGeneric*> GetDependencies()
|
|
{
|
|
return std::move(m_dependencies);
|
|
}
|
|
|
|
private:
|
|
void material_template()
|
|
{
|
|
const auto materialType = ReadStringProperty("materialType");
|
|
|
|
if (materialType == GDT_MATERIAL_TYPE_MODEL_PHONG
|
|
|| materialType == GDT_MATERIAL_TYPE_WORLD_PHONG
|
|
|| materialType == GDT_MATERIAL_TYPE_IMPACT_MARK)
|
|
{
|
|
mtl_phong_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_MODEL_AMBIENT)
|
|
{
|
|
mtl_ambient_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_2D)
|
|
{
|
|
mtl_2d_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_MODEL_UNLIT
|
|
|| materialType == GDT_MATERIAL_TYPE_WORLD_UNLIT)
|
|
{
|
|
mtl_unlit_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_UNLIT)
|
|
{
|
|
mtl_unlit_deprecated_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_EFFECT)
|
|
{
|
|
mtl_effect_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_DISTORTION)
|
|
{
|
|
mtl_distortion_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_PARTICLE_CLOUD)
|
|
{
|
|
mtl_particlecloud_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_TOOLS)
|
|
{
|
|
mtl_tools_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_SKY)
|
|
{
|
|
mtl_sky_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_WATER)
|
|
{
|
|
mtl_water_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_OBJECTIVE)
|
|
{
|
|
mtl_objective_template();
|
|
}
|
|
else if (materialType == GDT_MATERIAL_TYPE_CUSTOM)
|
|
{
|
|
custom_template();
|
|
}
|
|
else
|
|
{
|
|
std::ostringstream ss;
|
|
ss << "Unknown material type: \"" << materialType << "\"";
|
|
throw GdtReadingException(ss.str());
|
|
}
|
|
}
|
|
|
|
void mtl_phong_template()
|
|
{
|
|
}
|
|
|
|
void mtl_ambient_template()
|
|
{
|
|
}
|
|
|
|
void mtl_2d_template()
|
|
{
|
|
commonsetup_template();
|
|
|
|
SetTechniqueSet("2d");
|
|
|
|
const auto colorMapName = ReadStringProperty("colorMap");
|
|
|
|
if (!colorMapName.empty())
|
|
AddMapTexture("colorMap", TS_2D, colorMapName);
|
|
else
|
|
throw GdtReadingException("ColorMap may not be blank in 2d materials");
|
|
}
|
|
|
|
void mtl_unlit_template()
|
|
{
|
|
}
|
|
|
|
void mtl_unlit_deprecated_template()
|
|
{
|
|
}
|
|
|
|
void mtl_effect_template()
|
|
{
|
|
}
|
|
|
|
void mtl_distortion_template()
|
|
{
|
|
}
|
|
|
|
void mtl_particlecloud_template()
|
|
{
|
|
}
|
|
|
|
void mtl_tools_template()
|
|
{
|
|
}
|
|
|
|
void mtl_sky_template()
|
|
{
|
|
}
|
|
|
|
void mtl_water_template()
|
|
{
|
|
}
|
|
|
|
void mtl_objective_template()
|
|
{
|
|
}
|
|
|
|
void custom_template()
|
|
{
|
|
const auto customTemplate = ReadStringProperty("customTemplate");
|
|
|
|
if (customTemplate == GDT_CUSTOM_MATERIAL_TYPE_CUSTOM)
|
|
{
|
|
mtl_custom_template();
|
|
}
|
|
else if (customTemplate == GDT_CUSTOM_MATERIAL_TYPE_PHONG_FLAG)
|
|
{
|
|
mtl_phong_flag_template();
|
|
}
|
|
else if (customTemplate == GDT_CUSTOM_MATERIAL_TYPE_GRAIN_OVERLAY)
|
|
{
|
|
mtl_grain_overlay_template();
|
|
}
|
|
else if (customTemplate == GDT_CUSTOM_MATERIAL_TYPE_EFFECT_EYE_OFFSET)
|
|
{
|
|
mtl_effect_eyeoffset_template();
|
|
}
|
|
else if (customTemplate == GDT_CUSTOM_MATERIAL_TYPE_REFLEXSIGHT)
|
|
{
|
|
mtl_reflexsight_template();
|
|
}
|
|
else if (customTemplate == GDT_CUSTOM_MATERIAL_TYPE_SHADOWCLEAR)
|
|
{
|
|
mtl_shadowclear_template();
|
|
}
|
|
else if (customTemplate == GDT_CUSTOM_MATERIAL_TYPE_SHADOWOVERLAY)
|
|
{
|
|
mtl_shadowoverlay_template();
|
|
}
|
|
else if (customTemplate == GDT_CUSTOM_MATERIAL_TYPE_SPLATTER)
|
|
{
|
|
mtl_splatter_template();
|
|
}
|
|
else
|
|
{
|
|
std::ostringstream ss;
|
|
ss << "Unknown custom template: \"" << customTemplate << "\"";
|
|
throw GdtReadingException(ss.str());
|
|
}
|
|
}
|
|
|
|
void mtl_custom_template()
|
|
{
|
|
}
|
|
|
|
void mtl_phong_flag_template()
|
|
{
|
|
}
|
|
|
|
void mtl_grain_overlay_template()
|
|
{
|
|
}
|
|
|
|
void mtl_effect_eyeoffset_template()
|
|
{
|
|
}
|
|
|
|
void mtl_reflexsight_template()
|
|
{
|
|
}
|
|
|
|
void mtl_shadowclear_template()
|
|
{
|
|
}
|
|
|
|
void mtl_shadowoverlay_template()
|
|
{
|
|
}
|
|
|
|
void mtl_splatter_template()
|
|
{
|
|
}
|
|
|
|
void commonsetup_template()
|
|
{
|
|
refblend_template();
|
|
sort_template();
|
|
clamp_template();
|
|
|
|
// tessSize
|
|
|
|
textureAtlas_template();
|
|
|
|
// hasEditorMaterial
|
|
|
|
// allocLightmap
|
|
|
|
statebits_template();
|
|
}
|
|
|
|
void refblend_template()
|
|
{
|
|
const auto blendFunc = ReadStringProperty("blendFunc");
|
|
}
|
|
|
|
void sort_template()
|
|
{
|
|
const auto sort = ReadStringProperty("sort");
|
|
const auto materialType = ReadStringProperty("materialType");
|
|
const auto polygonOffset = ReadStringProperty("polygonOffset");
|
|
const auto blendFunc = ReadStringProperty("blendFunc");
|
|
|
|
std::string sortKey;
|
|
if (sort.empty() || sort == GDT_SORTKEY_DEFAULT)
|
|
{
|
|
if (materialType == GDT_MATERIAL_TYPE_DISTORTION)
|
|
sortKey = GDT_SORTKEY_DISTORTION;
|
|
else if (polygonOffset == "Static Decal")
|
|
sortKey = GDT_SORTKEY_DECAL_STATIC;
|
|
else if (polygonOffset == "Weapon Impact")
|
|
sortKey = GDT_SORTKEY_DECAL_WEAPON_IMPACT;
|
|
else if (materialType == GDT_MATERIAL_TYPE_EFFECT)
|
|
sortKey = GDT_SORTKEY_EFFECT_AUTO_SORT;
|
|
else if (materialType == GDT_MATERIAL_TYPE_OBJECTIVE
|
|
|| blendFunc == "Blend" || blendFunc == "Add" || blendFunc == "Screen Add")
|
|
sortKey = GDT_SORTKEY_BLEND_ADDITIVE;
|
|
// else if (blendFunc == "Multiply") // TODO
|
|
// sortKey = GDT_SORTKEY_MULTIPLICATIVE;
|
|
else if (materialType == GDT_MATERIAL_TYPE_SKY)
|
|
sortKey = GDT_SORTKEY_SKY;
|
|
else if (materialType == GDT_MATERIAL_TYPE_MODEL_AMBIENT)
|
|
sortKey = GDT_SORTKEY_OPAQUE_AMBIENT;
|
|
else
|
|
sortKey = GDT_SORTKEY_OPAQUE;
|
|
}
|
|
else
|
|
sortKey = sort;
|
|
|
|
bool foundSortKey = false;
|
|
for (auto sortKeyIndex = 0u; sortKeyIndex < SORTKEY_MAX; sortKeyIndex++)
|
|
{
|
|
if (sortKey == SortKeyNames[sortKeyIndex])
|
|
{
|
|
SetSort(static_cast<unsigned char>(sortKeyIndex));
|
|
foundSortKey = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundSortKey)
|
|
{
|
|
char* endPtr;
|
|
const auto sortKeyNum = strtoul(sortKey.c_str(), &endPtr, 10);
|
|
|
|
if (endPtr != &sortKey[sortKey.size()])
|
|
{
|
|
std::ostringstream ss;
|
|
ss << "Invalid sortkey value: \"" << sortKey << "\"";
|
|
throw GdtReadingException(ss.str());
|
|
}
|
|
|
|
SetSort(static_cast<unsigned char>(sortKeyNum));
|
|
}
|
|
}
|
|
|
|
void clamp_template()
|
|
{
|
|
}
|
|
|
|
void textureAtlas_template()
|
|
{
|
|
}
|
|
|
|
void statebits_template()
|
|
{
|
|
}
|
|
|
|
void SetTechniqueSet(const std::string& techsetName)
|
|
{
|
|
auto* techset = reinterpret_cast<XAssetInfo<MaterialTechniqueSet>*>(m_manager->LoadDependency(ASSET_TYPE_TECHNIQUE_SET, techsetName));
|
|
|
|
if (techset == nullptr)
|
|
{
|
|
std::ostringstream ss;
|
|
ss << "Could not load techset: \"" << techsetName << "\"";
|
|
throw GdtReadingException(ss.str());
|
|
}
|
|
|
|
m_dependencies.push_back(techset);
|
|
m_material->techniqueSet = techset->Asset();
|
|
}
|
|
|
|
void AddMapTexture(const std::string& typeName, const TextureSemantic semantic, const std::string& textureName)
|
|
{
|
|
MaterialTextureDef textureDef{};
|
|
textureDef.nameHash = Common::R_HashString(typeName.c_str());
|
|
textureDef.nameStart = typeName[0];
|
|
textureDef.nameEnd = typeName[typeName.size() - 1];
|
|
textureDef.samplerState = 0; // TODO
|
|
textureDef.semantic = static_cast<unsigned char>(semantic);
|
|
|
|
auto* image = reinterpret_cast<XAssetInfo<GfxImage>*>(m_manager->LoadDependency(ASSET_TYPE_IMAGE, textureName));
|
|
|
|
if (image == nullptr)
|
|
{
|
|
std::ostringstream ss;
|
|
ss << "Could not load image: \"" << textureName << "\"";
|
|
throw GdtReadingException(ss.str());
|
|
}
|
|
|
|
m_dependencies.push_back(image);
|
|
textureDef.u.image = image->Asset();
|
|
|
|
m_textures.push_back(textureDef);
|
|
}
|
|
|
|
void SetSort(const unsigned char sort) const
|
|
{
|
|
m_material->info.sortKey = sort;
|
|
}
|
|
|
|
void FinalizeMaterial() const
|
|
{
|
|
if (!m_textures.empty())
|
|
{
|
|
m_material->textureTable = static_cast<MaterialTextureDef*>(m_memory->Alloc(sizeof(MaterialTextureDef) * m_textures.size()));
|
|
m_material->textureCount = static_cast<unsigned char>(m_textures.size());
|
|
memcpy(m_material->textureTable, m_textures.data(), sizeof(MaterialTextureDef) * m_textures.size());
|
|
}
|
|
else
|
|
{
|
|
m_material->textureTable = nullptr;
|
|
m_material->textureCount = 0u;
|
|
}
|
|
}
|
|
|
|
MemoryManager* m_memory;
|
|
IAssetLoadingManager* m_manager;
|
|
std::vector<XAssetInfoGeneric*> m_dependencies;
|
|
|
|
Material* m_material;
|
|
std::vector<MaterialTextureDef> m_textures;
|
|
};
|
|
}
|
|
|
|
void* AssetLoaderMaterial::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory)
|
|
{
|
|
auto* material = memory->Create<Material>();
|
|
memset(material, 0, sizeof(Material));
|
|
material->info.name = memory->Dup(assetName.c_str());
|
|
return material;
|
|
}
|
|
|
|
bool AssetLoaderMaterial::CanLoadFromGdt() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool AssetLoaderMaterial::LoadFromGdt(const std::string& assetName, IGdtQueryable* gdtQueryable, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
|
|
{
|
|
const auto* entry = gdtQueryable->GetGdtEntryByGdfAndName(ObjConstants::GDF_FILENAME_MATERIAL, assetName);
|
|
if (!entry)
|
|
return false;
|
|
|
|
MaterialGdtLoader loader(*entry, memory, manager);
|
|
|
|
try
|
|
{
|
|
if (loader.Load())
|
|
manager->AddAsset(ASSET_TYPE_MATERIAL, assetName, loader.GetMaterial(), loader.GetDependencies(), std::vector<scr_string_t>());
|
|
}
|
|
catch (const GdtReadingException& e)
|
|
{
|
|
std::cerr << "Error while trying to load material from gdt: " << e.what() << " @ GdtEntry \"" << entry->m_name << "\"\n";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|