diff --git a/H2Codez/Common/BasicTagTypes.cpp b/H2Codez/Common/BasicTagTypes.cpp new file mode 100644 index 0000000..c21bfe9 --- /dev/null +++ b/H2Codez/Common/BasicTagTypes.cpp @@ -0,0 +1,6 @@ +#include "BasicTagTypes.h" +#include "TagInterface.h" + +int32_t tag_block_add_impl(tag_block_ref* block) { + return tags::add_block_element(block); +} diff --git a/H2Codez/Common/BasicTagTypes.h b/H2Codez/Common/BasicTagTypes.h index 92c3077..1d53f6f 100644 --- a/H2Codez/Common/BasicTagTypes.h +++ b/H2Codez/Common/BasicTagTypes.h @@ -12,6 +12,23 @@ struct tag_reference const char *tag_name; int field_8; datum tag_index; + + bool operator==(const tag_reference& other) const { + if (tag_type != other.tag_type) + return false; + if (strcmp(tag_name, other.tag_name) == 0) + return true; + + // maybe sometimes different names could result in the same tag getting loaded? not sure + if (tag_index == NONE) + return false; // ignore false positives from two unloadable tags + + return tag_index == other.tag_index; + } + + bool operator!=(const tag_reference& other) const { + return !operator==(other); + } }; CHECK_STRUCT_SIZE(tag_reference, 16); @@ -21,6 +38,9 @@ struct tag_block; typedef tag_block tag_block_ref; +// I hate this, but I don't feel like refactoring +int32_t tag_block_add_impl(tag_block_ref* block); + template struct tag_block { @@ -38,6 +58,14 @@ struct tag_block return get_ref(); } + int32_t add() { + return tag_block_add_impl(get_ref()); + } + + int32_t add(const T *value) { + return add_impl(value); + } + bool is_valid() const { if (reinterpret_cast(this->data) == NONE) @@ -145,6 +173,22 @@ struct tag_block uint8_t *data_char = reinterpret_cast(this->data); return &data_char[element_size * idx]; } + + template + int32_t add_impl(const T1* value) { + int32_t new_index = add(); + if (new_index == NONE) + return NONE; + + *get_element(new_index) = *(T*)value; + + return new_index; + } + + template<> + int32_t add_impl(const void* value) { + ASSERT_CHECK(false && "add(T *value) is not supported for tag_block_ref"); + } }; CHECK_STRUCT_SIZE(tag_block, 12); CHECK_STRUCT_SIZE(tag_block_ref, 12); diff --git a/H2Codez/Common/BlamBaseTypes.h b/H2Codez/Common/BlamBaseTypes.h index bb350b9..2acd4c4 100644 --- a/H2Codez/Common/BlamBaseTypes.h +++ b/H2Codez/Common/BlamBaseTypes.h @@ -124,6 +124,11 @@ struct blam_tag return this->as_int() == other.as_int(); } + constexpr bool operator!=(const blam_tag& other) const + { + return !(operator==(other)); + } + constexpr static blam_tag null() { return blam_tag(0xFFFFFFFF); diff --git a/H2Codez/H2Codez.vcxproj b/H2Codez/H2Codez.vcxproj index 69885f7..c17c793 100644 --- a/H2Codez/H2Codez.vcxproj +++ b/H2Codez/H2Codez.vcxproj @@ -230,6 +230,7 @@ + diff --git a/H2Codez/H2Codez.vcxproj.filters b/H2Codez/H2Codez.vcxproj.filters index da1edfa..d915287 100644 --- a/H2Codez/H2Codez.vcxproj.filters +++ b/H2Codez/H2Codez.vcxproj.filters @@ -499,6 +499,9 @@ Source Files\Patches\H2Sapien + + Source Files\Common Interfaces\Tags + diff --git a/H2Codez/H2Tool/H2Tool_extra_commands.inl b/H2Codez/H2Tool/H2Tool_extra_commands.inl index 3705eda..bca95fe 100644 --- a/H2Codez/H2Tool/H2Tool_extra_commands.inl +++ b/H2Codez/H2Tool/H2Tool_extra_commands.inl @@ -594,7 +594,31 @@ static bool _cdecl h2pc_generate_render_model(datum tag, file_reference& FILE_RE if (ASSERT_CHECK(section->sectionData.size == 1) && LOG_CHECK(cluster->clusterData.size == 1)) { - // copy data from the cluster to the section + ASSERT_CHECK(render_model->materials.size <= 0x100); + ASSERT_CHECK(sbsp->materials.size <= 0x100); + + // copy materials or map them to existing ones + // there are at most 0x100 materials per section (hopefully less) + short material_map[0x100] = {}; + + for (short i = 0; i < sbsp->materials.size; i++) + { + const global_geometry_material_block* bsp_material = sbsp->materials[i]; + + int32_t found = render_model->materials.find_element( + [bsp_material](const global_geometry_material_block* block) -> bool { + return *block == *bsp_material; + } + ); + + int32_t material_index = found == NONE ? render_model->materials.add(bsp_material) : found; + + ASSERT_CHECK(material_index <= 0x100); + material_map[i] = static_cast(material_index); + } + + + // copy the remaining data from the cluster to the section auto *section_data = section->sectionData[0]; auto *cluster_data = cluster->clusterData[0]; @@ -606,12 +630,9 @@ static bool _cdecl h2pc_generate_render_model(datum tag, file_reference& FILE_RE copy_block(stripIndices); copy_block(vertexBuffers); #undef copy_block - // fix materials index + // map material index to new one for (auto& part : section_data->section.parts) - part.material += static_cast(render_model->materials.size); - - // copy over materials for this BSP - tags::copy_block(&sbsp->materials, &render_model->materials); + part.material = material_map[part.material]; // add node map entry tags::resize_block(§ion_data->nodeMap, 1); diff --git a/H2Codez/Tags/GlobalGeometry.h b/H2Codez/Tags/GlobalGeometry.h index 0189afb..86d3e09 100644 --- a/H2Codez/Tags/GlobalGeometry.h +++ b/H2Codez/Tags/GlobalGeometry.h @@ -279,6 +279,14 @@ struct global_geometry_material_property_block Type type; short intValue; float realValue; + + bool operator==(const global_geometry_material_property_block& other) { + return memcmp(this, &other, sizeof(global_geometry_material_property_block)) == 0; + } + + bool operator!=(const global_geometry_material_property_block& other) { + return !operator==(other); + } }; CHECK_STRUCT_SIZE(global_geometry_material_property_block, 8); @@ -294,6 +302,24 @@ struct global_geometry_material_block byte padding81[4]; byte breakableSurfaceIndex; byte padding82[3]; + + bool operator==(const global_geometry_material_block& other) const + { + if (oldShader != other.oldShader) + return false; + if (shader != other.shader) + return false; + if (breakableSurfaceIndex != other.breakableSurfaceIndex) + return false; + + if (properties.size != other.properties.size) + return false; + for (int i = 0; i < properties.size; i++) + if (*properties[i] != *other.properties[i]) + return false; + + return true; + } }; CHECK_STRUCT_SIZE(global_geometry_material_block, 52);