diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ad840f..94581d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,8 @@ target_sources(${PROJECT_NAME} "SWBF2/Native/Level.cpp" "SWBF2/Core.cpp" "SWBF2/Level.cpp" + "SWBF2/MaterialPools.cpp" + "RegisterExtension.cpp" ) diff --git a/src/SWBF2/Core.cpp b/src/SWBF2/Core.cpp index 3631673..c10de40 100644 --- a/src/SWBF2/Core.cpp +++ b/src/SWBF2/Core.cpp @@ -19,12 +19,16 @@ namespace SWBF2 void Core::_ready() { + set_name("Core"); + godot::UtilityFunctions::print("hello world!"); // SWBF2::Native::UcfbChunk::ReadUcfbFile("data/_lvl_pc/common.lvl"); // SWBF2::Native::UcfbChunk::ReadUcfbFile("data/_lvl_pc/core.lvl"); - add_child(memnew(Level)); + Level *lvl = memnew(Level); + add_child(lvl); + lvl->set_owner(this); } void Core::_bind_methods() diff --git a/src/SWBF2/Level.cpp b/src/SWBF2/Level.cpp index 4050185..4f3fc58 100644 --- a/src/SWBF2/Level.cpp +++ b/src/SWBF2/Level.cpp @@ -14,42 +14,22 @@ namespace SWBF2 { void Level::_ready() { + set_name("Level"); + SWBF2::Native::UcfbChunk::ReadUcfbFile("data/_lvl_pc/cor/cor1.lvl"); - LoadTextures(); LoadMeshes(); } - void Level::LoadTextures() - { - for (auto const &[id, tex] : Native::Level::m_tex) - { - for (auto const format : tex->m_formats) - { - for (auto const faceLevel : format.m_faceLevels) - { - godot::Ref material; - material.instantiate(); - material->set_texture(godot::StandardMaterial3D::TEXTURE_ALBEDO, faceLevel.m_gdImageTexture); - material->set_flag(godot::BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - material->set_cull_mode(godot::BaseMaterial3D::CULL_DISABLED); - - m_textureMaterials.insert_or_assign(id, material); - } - } - } - } - void Level::LoadMeshes() { for (auto const &[id, model] : Native::Level::m_models) { + uint32_t segment_id = 0; for (auto const &segment : model.m_segments) { godot::MeshInstance3D *meshInstance = memnew(godot::MeshInstance3D); - meshInstance->set_name(std::format("_lvl_mesh_{}", id).c_str()); - - add_child(meshInstance); + meshInstance->set_name(std::format("{}_segm_{}", id, segment_id).c_str()); godot::PackedVector3Array vertices; godot::PackedVector3Array normals; @@ -100,18 +80,28 @@ namespace SWBF2 godot::ArrayMesh *arrMesh = memnew(godot::ArrayMesh); arrMesh->add_surface_from_arrays(godot::Mesh::PRIMITIVE_TRIANGLE_STRIP, arrays); + meshInstance->set_mesh(arrMesh); + auto tex_id = 0; for (const auto &texName : segment.m_textureNames) { - if (!m_textureMaterials.contains(texName)) + // TODO, apply bump to texture + if (texName.ends_with("bump")) + continue; + + auto &material = m_materialPool.getItem(texName); + if (material.is_null()) { - godot::UtilityFunctions::printerr(__FILE__, ":", __LINE__, ": No texture found for ", texName.c_str()); + godot::UtilityFunctions::printerr(__FILE__, ":", __LINE__, ": No material found for ", texName.c_str()); continue; } - godot::UtilityFunctions::print(__FILE__, ":", __LINE__, ": Found texture of ", texName.c_str()); + godot::UtilityFunctions::print(__FILE__, ":", __LINE__, ": Found texture ", texName.c_str(), " for mesh ", id.c_str(), " with segment id ", segment_id); + + // if (segment.m_material.m_flags & Native::MaterialFlags::Transparent) + // material->set_transparency(godot::BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR); - meshInstance->set_material_override(m_textureMaterials[texName]); + meshInstance->set_surface_override_material(0, material); tex_id++; } @@ -121,7 +111,11 @@ namespace SWBF2 godot::UtilityFunctions::printerr(__FILE__, ":", __LINE__, ": Mesh ", id.c_str(), " has no texture at all"); } - meshInstance->set_mesh(arrMesh); + add_child(meshInstance); + meshInstance->set_owner(this->get_parent()); + meshInstance->add_to_group("Level Meshes"); + + segment_id++; } } } diff --git a/src/SWBF2/Level.hpp b/src/SWBF2/Level.hpp index fbd0ed3..15c9d77 100644 --- a/src/SWBF2/Level.hpp +++ b/src/SWBF2/Level.hpp @@ -4,20 +4,21 @@ #include #include +#include "MaterialPools.hpp" + namespace SWBF2 { class Level : public godot::Node3D { GDCLASS(Level, godot::Node3D) - private: - std::unordered_map> m_textureMaterials; public: Level() {} ~Level() = default; + MaterialPools m_materialPool; + virtual void _ready() override; - void LoadTextures(); void LoadMeshes(); void _process(double delta_time) override; diff --git a/src/SWBF2/MaterialPools.cpp b/src/SWBF2/MaterialPools.cpp new file mode 100644 index 0000000..3e07349 --- /dev/null +++ b/src/SWBF2/MaterialPools.cpp @@ -0,0 +1,33 @@ + +#pragma once + +#include "Native/Level.hpp" + +#include "MaterialPools.hpp" + +namespace SWBF2 +{ + const godot::Ref &SWBF2::MaterialPools::findTexture(const std::string &id) + { + if (!Native::Level::m_tex.contains(id)) + return m_empty; + + auto &tex = Native::Level::m_tex[id]; + auto &gdTex = tex.m_formats.at(0).m_faceLevels.at(0).m_gdTexture; + return gdTex; + } + + godot::Ref &MaterialPools::getItem(const std::string &key) + { + auto &texture = findTexture(key); + + godot::Ref material = memnew(godot::StandardMaterial3D); + material->set_texture(godot::StandardMaterial3D::TEXTURE_ALBEDO, texture); + material->set_flag(godot::BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + material->set_cull_mode(godot::BaseMaterial3D::CULL_DISABLED); + + m_pool.emplace(key, material); + + return m_pool[key]; + } +} diff --git a/src/SWBF2/MaterialPools.hpp b/src/SWBF2/MaterialPools.hpp new file mode 100644 index 0000000..d1a1698 --- /dev/null +++ b/src/SWBF2/MaterialPools.hpp @@ -0,0 +1,20 @@ + +#pragma once + +#include +#include + +#include "Pools.hpp" + +namespace SWBF2 +{ + class MaterialPools : public Pools { + private: + godot::Ref m_empty; + + const godot::Ref &findTexture(const std::string &id); + public: + + godot::Ref &getItem(const std::string &key) override; + }; +} diff --git a/src/SWBF2/Native/Chunks/TextureChunk.cpp b/src/SWBF2/Native/Chunks/TextureChunk.cpp index f6c67a4..b2fdba5 100644 --- a/src/SWBF2/Native/Chunks/TextureChunk.cpp +++ b/src/SWBF2/Native/Chunks/TextureChunk.cpp @@ -1,5 +1,7 @@ #include +#include + #include "Native/Chunks/StreamReader.hpp" #include "Native/Chunks/TextureChunk.hpp" @@ -10,19 +12,19 @@ namespace SWBF2::Native { void TextureChunk::ProcessChunk(StreamReader &streamReader) { - std::unique_ptr tex = std::make_unique(); + Texture tex{}; auto texNameReaderChild = streamReader.ReadChildWithHeader<"NAME"_m>(); { - *texNameReaderChild >> tex->m_name; + *texNameReaderChild >> tex.m_name; } auto infoReaderChild = streamReader.ReadChildWithHeader<"INFO"_m>(); { - *infoReaderChild >> tex->m_formatCount; + *infoReaderChild >> tex.m_formatCount; - tex->m_d3dFormats.resize(tex->m_formatCount); - *infoReaderChild >> tex->m_d3dFormats; + tex.m_d3dFormats.resize(tex.m_formatCount); + *infoReaderChild >> tex.m_d3dFormats; std::optional fmtReaderChild; while ((fmtReaderChild = streamReader.ReadChild()).has_value()) @@ -31,7 +33,7 @@ namespace SWBF2::Native { case "FMT_"_m: { StreamReader r{ *fmtReaderChild }; - TextureChunk::ProcessFMTChunk(r, tex.get()); + TextureChunk::ProcessFMTChunk(r, tex); break; } @@ -42,14 +44,14 @@ namespace SWBF2::Native } } - Level::m_tex.try_emplace(tex->m_name, std::move(tex)); + Level::m_tex.try_emplace(tex.m_name, std::move(tex)); } - void TextureChunk::ProcessFMTChunk(StreamReader &streamReader, Texture *tex) + void TextureChunk::ProcessFMTChunk(StreamReader &streamReader, Texture &tex) { auto infoReaderChild = streamReader.ReadChildWithHeader<"INFO"_m>(); - auto &fmt = tex->m_formats.emplace_back(TextureFormat()); + auto &fmt = tex.m_formats.emplace_back(TextureFormat{}); { *infoReaderChild >> fmt.m_format; *infoReaderChild >> fmt.m_width; @@ -73,7 +75,7 @@ namespace SWBF2::Native void TextureChunk::ProcessTextureLevelChunk(StreamReader &streamReader, TextureFormat &fmt) { - TextureFormatFaceLevel lvl; + TextureFormatFaceLevel lvl{}; auto infoReaderChild = streamReader.ReadChildWithHeader<"INFO"_m>(); { @@ -95,9 +97,9 @@ namespace SWBF2::Native std::copy(lvl.m_imageInBytes.begin(), lvl.m_imageInBytes.end(), (std::byte *)imageBuf.ptrw()); godot::Ref image{ godot::Image::create_from_data(fmt.m_width, fmt.m_height, false, TextureUtils::D3DToGLFormat(fmt.m_format), imageBuf) }; + godot::Ref imageTex{ godot::ImageTexture::create_from_image(image) }; - lvl.m_gdImageTexture.instantiate(); - lvl.m_gdImageTexture->create_from_image(image); + lvl.m_gdTexture = imageTex; } fmt.m_faceLevels.push_back(lvl); diff --git a/src/SWBF2/Native/Chunks/TextureChunk.hpp b/src/SWBF2/Native/Chunks/TextureChunk.hpp index 9331bc4..268a570 100644 --- a/src/SWBF2/Native/Chunks/TextureChunk.hpp +++ b/src/SWBF2/Native/Chunks/TextureChunk.hpp @@ -9,7 +9,7 @@ namespace SWBF2::Native class TextureChunk { public: static void ProcessChunk(StreamReader &streamReader); - static void ProcessFMTChunk(StreamReader &streamReader, Texture *tex); + static void ProcessFMTChunk(StreamReader &streamReader, Texture &tex); static void ProcessTextureLevelChunk(StreamReader &streamReader, TextureFormat &fmt); }; diff --git a/src/SWBF2/Native/Level.cpp b/src/SWBF2/Native/Level.cpp index b20a2aa..fe7eb5f 100644 --- a/src/SWBF2/Native/Level.cpp +++ b/src/SWBF2/Native/Level.cpp @@ -6,6 +6,6 @@ namespace SWBF2::Native World Level::m_world; std::unordered_map Level::m_models; - std::unordered_map> Level::m_tex; + std::unordered_map Level::m_tex; std::unordered_map Level::m_locl; } diff --git a/src/SWBF2/Native/Level.hpp b/src/SWBF2/Native/Level.hpp index fcaa5c1..164ac07 100644 --- a/src/SWBF2/Native/Level.hpp +++ b/src/SWBF2/Native/Level.hpp @@ -13,7 +13,7 @@ namespace SWBF2::Native static World m_world; static std::unordered_map m_models; - static std::unordered_map> m_tex; + static std::unordered_map m_tex; using LoclEntriesMap = std::unordered_map; static std::unordered_map m_locl; diff --git a/src/SWBF2/Native/Texture/Texture.hpp b/src/SWBF2/Native/Texture/Texture.hpp index 5087072..a862d91 100644 --- a/src/SWBF2/Native/Texture/Texture.hpp +++ b/src/SWBF2/Native/Texture/Texture.hpp @@ -1,7 +1,7 @@ #pragma once -#include +#include #include "Native/D3D9/d3dformat.hpp" @@ -13,7 +13,7 @@ namespace SWBF2::Native uint32_t m_bodySize; std::vector m_imageInBytes; - godot::Ref m_gdImageTexture; + godot::Ref m_gdTexture; } TextureFormatFaceLevel; typedef struct _TEX_FMT diff --git a/src/SWBF2/Pools.hpp b/src/SWBF2/Pools.hpp new file mode 100644 index 0000000..48bfb77 --- /dev/null +++ b/src/SWBF2/Pools.hpp @@ -0,0 +1,28 @@ + +#pragma once + +#include + +#include "Types.hpp" + +namespace SWBF2 +{ + template + class Pools { + + godot::Ref m_empty; + + public: + std::unordered_map> m_pool; + + inline virtual bool contains(const K &key) + { + return m_pool.contains(key); + } + + inline virtual godot::Ref &getItem(const K &key) + { + return m_pool.contains(key) ? m_pool.at(key) : m_empty; + } + }; +}