2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-06 08:42:35 +00:00

BSP creator now reads colour data from materials and applies them to the vertices. Minor GFXWorld fixups and extensions to accomodate the changes.

This commit is contained in:
LJW-Dev
2026-03-16 14:20:25 +08:00
committed by Jan Laupetin
parent d683967b1d
commit 60060e9a7a
3 changed files with 102 additions and 87 deletions
+5 -5
View File
@@ -14,8 +14,7 @@ namespace BSP
enum BSPMaterialType enum BSPMaterialType
{ {
MATERIAL_TYPE_COLOUR, MATERIAL_TYPE_COLOUR,
MATERIAL_TYPE_TEXTURE, MATERIAL_TYPE_TEXTURE
MATERIAL_TYPE_EMPTY
}; };
struct BSPVertex struct BSPVertex
@@ -30,8 +29,9 @@ namespace BSP
struct BSPMaterial struct BSPMaterial
{ {
BSPMaterialType materialType;
std::string materialName; std::string materialName;
BSPMaterialType materialType;
vec4_t materialColour;
}; };
struct BSPSurface struct BSPSurface
@@ -132,7 +132,7 @@ namespace BSP
namespace BSPLinkingConstants namespace BSPLinkingConstants
{ {
constexpr const char* MISSING_IMAGE_NAME = ",mc/lambert1"; constexpr const char* MISSING_IMAGE_NAME = ",mc/lambert1";
constexpr const char* COLOR_ONLY_IMAGE_NAME = ",white"; constexpr const char* COLOR_ONLY_IMAGE_NAME = ",mc/lambert1";
constexpr const char* DEFAULT_SPAWN_POINT_STRING = R"({ constexpr const char* DEFAULT_SPAWN_POINT_STRING = R"({
"attackers": [ "attackers": [
@@ -186,7 +186,7 @@ namespace BSP
constexpr int DEFAULT_SMODEL_REFLECTION_PROBE = 0; constexpr int DEFAULT_SMODEL_REFLECTION_PROBE = 0;
// Default surface values // Default surface values
constexpr int DEFAULT_SURFACE_LIGHT = 2; constexpr int DEFAULT_SURFACE_LIGHT = 1;
constexpr int DEFAULT_SURFACE_LIGHTMAP = 0; constexpr int DEFAULT_SURFACE_LIGHTMAP = 0;
constexpr int DEFAULT_SURFACE_REFLECTION_PROBE = 0; constexpr int DEFAULT_SURFACE_REFLECTION_PROBE = 0;
constexpr int DEFAULT_SURFACE_FLAGS = 0; constexpr int DEFAULT_SURFACE_FLAGS = 0;
+92 -75
View File
@@ -28,7 +28,7 @@ namespace
unsigned m_position_accessor; unsigned m_position_accessor;
unsigned m_normal_accessor; unsigned m_normal_accessor;
std::optional<unsigned> m_color_accessor; std::optional<unsigned> m_color_accessor;
unsigned m_uv_accessor; std::optional<unsigned> m_uv_accessor;
unsigned m_index_accessor; unsigned m_index_accessor;
}; };
@@ -83,7 +83,6 @@ namespace
private: private:
const Input& m_input; const Input& m_input;
BSPData* m_bsp; BSPData* m_bsp;
size_t m_color_mat_idx;
std::vector<std::unique_ptr<Accessor>> m_accessors; std::vector<std::unique_ptr<Accessor>> m_accessors;
std::vector<std::unique_ptr<BufferView>> m_buffer_views; std::vector<std::unique_ptr<BufferView>> m_buffer_views;
std::vector<std::unique_ptr<Buffer>> m_buffers; std::vector<std::unique_ptr<Buffer>> m_buffers;
@@ -190,7 +189,8 @@ namespace
return T.matrix(); return T.matrix();
} }
unsigned CreateVertices(const AccessorsForVertex& accessorsForVertex, const gltf::JsonNode& node, Eigen::Matrix4f& nodeMatrix, BSPSurface& surface) unsigned CreateVertices(
const AccessorsForVertex& accessorsForVertex, const gltf::JsonNode& node, Eigen::Matrix4f& nodeMatrix, BSPSurface& surface, vec4_t vertexColor)
{ {
// clang-format off // clang-format off
const auto* positionAccessor = GetAccessorForIndex( const auto* positionAccessor = GetAccessorForIndex(
@@ -203,6 +203,7 @@ namespace
assert(positionAccessor != nullptr); assert(positionAccessor != nullptr);
const auto vertexCount = positionAccessor->GetCount(); const auto vertexCount = positionAccessor->GetCount();
NullAccessor nullAccessor(vertexCount);
OnesAccessor onesAccessor(vertexCount); OnesAccessor onesAccessor(vertexCount);
// clang-format off // clang-format off
@@ -220,9 +221,8 @@ namespace
accessorsForVertex.m_uv_accessor, accessorsForVertex.m_uv_accessor,
{ JsonAccessorType::VEC2 }, { JsonAccessorType::VEC2 },
{ JsonAccessorComponentType::FLOAT, JsonAccessorComponentType::UNSIGNED_BYTE, JsonAccessorComponentType::UNSIGNED_SHORT } { JsonAccessorComponentType::FLOAT, JsonAccessorComponentType::UNSIGNED_BYTE, JsonAccessorComponentType::UNSIGNED_SHORT }
).value_or(nullptr); ).value_or(&nullAccessor);
VerifyAccessorVertexCount("TEXCOORD_0", uvAccessor, vertexCount); VerifyAccessorVertexCount("TEXCOORD_0", uvAccessor, vertexCount);
assert(uvAccessor != nullptr);
const auto* colorAccessor = GetAccessorForIndex( const auto* colorAccessor = GetAccessorForIndex(
"COLOR_0", "COLOR_0",
@@ -282,6 +282,11 @@ namespace
assert(false); assert(false);
} }
vertex.color.x *= vertexColor.x;
vertex.color.y *= vertexColor.y;
vertex.color.z *= vertexColor.z;
vertex.color.w *= vertexColor.w;
Eigen::Vector4f position(vertex.pos.x, vertex.pos.y, vertex.pos.z, 1.0f); Eigen::Vector4f position(vertex.pos.x, vertex.pos.y, vertex.pos.z, 1.0f);
Eigen::Vector4f transformedPosition = nodeMatrix * position; Eigen::Vector4f transformedPosition = nodeMatrix * position;
vertex.pos.x = transformedPosition.x(); vertex.pos.x = transformedPosition.x();
@@ -313,24 +318,8 @@ namespace
return vertexOffset; return vertexOffset;
} }
void loadSurfaceLightData(const JsonRoot& jRoot, const JsonMeshPrimitives& primitive, BSPSurface& surface) bool addNodeToBSP(const JsonRoot& jRoot, const gltf::JsonNode& node)
{ {
if (!primitive.material)
{
if (!primitive.attributes.COLOR_0)
throw GltfLoadException("Primitive requires material or colour data.");
surface.materialIndex = m_color_mat_idx;
}
else
surface.materialIndex = *primitive.material;
}
bool CreateSurfacesFromNode(const JsonRoot& jRoot, const gltf::JsonNode& node)
{
if (!node.mesh && !node.extensions)
return false;
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node); Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
if (node.extensions && node.extensions->KHR_lights_punctual) if (node.extensions && node.extensions->KHR_lights_punctual)
@@ -375,48 +364,45 @@ namespace
return true; return true;
} }
con::info("Mesh {} found", node.name.has_value() ? node.name.value() : ""); if (node.mesh)
const auto& mesh = jRoot.meshes.value()[node.mesh.value()];
for (const auto& primitive : mesh.primitives)
{ {
if (!primitive.indices) assert(jRoot.meshes);
throw GltfLoadException("Requires primitives indices"); const auto& mesh = jRoot.meshes.value()[node.mesh.value()];
if (primitive.mode.value_or(JsonMeshPrimitivesMode::TRIANGLES) != JsonMeshPrimitivesMode::TRIANGLES) for (const auto& primitive : mesh.primitives)
throw GltfLoadException("Only triangles are supported"); {
if (!primitive.attributes.POSITION) if (!primitive.indices)
throw GltfLoadException("Requires primitives attribute POSITION"); throw GltfLoadException("Requires primitives indices");
if (!primitive.attributes.NORMAL) if (primitive.mode.value_or(JsonMeshPrimitivesMode::TRIANGLES) != JsonMeshPrimitivesMode::TRIANGLES)
throw GltfLoadException("Requires primitives attribute NORMAL"); throw GltfLoadException("Only triangles are supported");
if (!primitive.attributes.TEXCOORD_0) if (!primitive.attributes.POSITION)
throw GltfLoadException("Requires primitives attribute TEXCOORD_0"); throw GltfLoadException("Requires primitives attribute POSITION");
if (!primitive.attributes.NORMAL)
throw GltfLoadException("Requires primitives attribute NORMAL");
const AccessorsForVertex accessorsForVertex{ const AccessorsForVertex accessorsForVertex{
.m_position_accessor = *primitive.attributes.POSITION, .m_position_accessor = *primitive.attributes.POSITION,
.m_normal_accessor = *primitive.attributes.NORMAL, .m_normal_accessor = *primitive.attributes.NORMAL,
.m_color_accessor = primitive.attributes.COLOR_0, .m_color_accessor = primitive.attributes.COLOR_0,
.m_uv_accessor = *primitive.attributes.TEXCOORD_0, .m_uv_accessor = primitive.attributes.TEXCOORD_0,
.m_index_accessor = *primitive.indices, .m_index_accessor = *primitive.indices,
}; };
BSPSurface surface; BSPSurface surface;
if (primitive.material)
surface.materialIndex = *primitive.material;
else
surface.materialIndex = m_bsp->gfxWorld.materials.size() - 1; // last material is used for colour only meshes
vec4_t vertexColour = m_bsp->gfxWorld.materials.at(surface.materialIndex).materialColour;
CreateVertices(accessorsForVertex, node, nodeMatrix, surface, vertexColour);
if (primitive.material) m_bsp->gfxWorld.surfaces.emplace_back(surface);
surface.materialIndex = *primitive.material; return true;
else if (primitive.attributes.COLOR_0) }
surface.materialIndex = m_color_mat_idx;
else
throw GltfLoadException("Primitive requires material or colour data.");
CreateVertices(accessorsForVertex, node, nodeMatrix, surface);
m_bsp->gfxWorld.surfaces.emplace_back(surface);
} }
return true;
} }
static std::vector<unsigned> GetRootNodes(const JsonRoot& jRoot) static std::vector<unsigned> GetRootNodes(const JsonRoot& jRoot)
{ {
if (!jRoot.nodes || jRoot.nodes->empty()) if (!jRoot.nodes || jRoot.nodes->empty())
return {}; return {};
@@ -453,31 +439,62 @@ namespace
void LoadMaterials(const JsonRoot& jRoot) void LoadMaterials(const JsonRoot& jRoot)
{ {
if (!jRoot.materials) if (jRoot.materials)
return;
m_bsp->gfxWorld.materials.reserve((*jRoot.materials).size());
for (auto& jsMaterial : *jRoot.materials)
{ {
BSPMaterial material; m_bsp->gfxWorld.materials.reserve((*jRoot.materials).size());
for (auto& jsMaterial : *jRoot.materials)
if (jsMaterial.name && (*jsMaterial.name).length() != 0)
{ {
material.materialType = MATERIAL_TYPE_TEXTURE; BSPMaterial material;
material.materialName = *jsMaterial.name;
}
else
{
material.materialType = MATERIAL_TYPE_EMPTY;
material.materialName = "";
}
m_bsp->gfxWorld.materials.emplace_back(material); if (jsMaterial.name && (*jsMaterial.name).length() != 0)
material.materialName = *jsMaterial.name;
else
material.materialName = "";
if (jsMaterial.pbrMetallicRoughness)
{
if (jsMaterial.pbrMetallicRoughness->baseColorFactor)
{
material.materialColour.x = (*jsMaterial.pbrMetallicRoughness->baseColorFactor)[0];
material.materialColour.y = (*jsMaterial.pbrMetallicRoughness->baseColorFactor)[1];
material.materialColour.z = (*jsMaterial.pbrMetallicRoughness->baseColorFactor)[2];
material.materialColour.w = (*jsMaterial.pbrMetallicRoughness->baseColorFactor)[3];
}
else
{
material.materialColour.x = 1.0f;
material.materialColour.y = 1.0f;
material.materialColour.z = 1.0f;
material.materialColour.w = 1.0f;
}
if (jsMaterial.pbrMetallicRoughness->baseColorTexture)
material.materialType = MATERIAL_TYPE_TEXTURE;
else
material.materialType = MATERIAL_TYPE_COLOUR;
}
else
{
material.materialType = MATERIAL_TYPE_COLOUR;
material.materialColour.x = 1.0f;
material.materialColour.y = 1.0f;
material.materialColour.z = 1.0f;
material.materialColour.w = 1.0f;
}
m_bsp->gfxWorld.materials.emplace_back(material);
}
} }
m_color_mat_idx = m_bsp->gfxWorld.materials.size(); // last material is used when a primitve has no material/colour data
BSPMaterial colorMaterial; BSPMaterial colorMaterial;
colorMaterial.materialType = MATERIAL_TYPE_COLOUR; colorMaterial.materialType = MATERIAL_TYPE_COLOUR;
colorMaterial.materialName = ""; colorMaterial.materialName = "";
colorMaterial.materialColour.x = 1.0f;
colorMaterial.materialColour.y = 1.0f;
colorMaterial.materialColour.z = 1.0f;
colorMaterial.materialColour.w = 1.0f;
m_bsp->gfxWorld.materials.emplace_back(colorMaterial); m_bsp->gfxWorld.materials.emplace_back(colorMaterial);
} }
@@ -579,7 +596,7 @@ namespace
con::warn("Parent node has position data that won't be used"); con::warn("Parent node has position data that won't be used");
} }
CreateSurfacesFromNode(jRoot, node); addNodeToBSP(jRoot, node);
} }
} }
@@ -692,7 +709,7 @@ namespace
LoadLights(jRoot); LoadLights(jRoot);
LoadMaterials(jRoot); LoadMaterials(jRoot);
TraverseNodes(jRoot); TraverseNodes(jRoot); // requires materials and lights
} }
catch (const GltfLoadException& e) catch (const GltfLoadException& e)
{ {
@@ -74,15 +74,13 @@ namespace BSP
gfxSurface->tris.vertexDataOffset0 = bspSurface.indexOfFirstVertex * sizeof(GfxPackedWorldVertex); gfxSurface->tris.vertexDataOffset0 = bspSurface.indexOfFirstVertex * sizeof(GfxPackedWorldVertex);
gfxSurface->tris.vertexDataOffset1 = 0; // vd1 is unused gfxSurface->tris.vertexDataOffset1 = 0; // vd1 is unused
BSPMaterial bspMaterial = bsp->colWorld.materials.at(bspSurface.materialIndex); BSPMaterial bspMaterial = bsp->gfxWorld.materials.at(bspSurface.materialIndex);
std::string materialName; std::string materialName;
if (bspMaterial.materialType == MATERIAL_TYPE_EMPTY) if (bspMaterial.materialType == MATERIAL_TYPE_TEXTURE)
materialName = BSPLinkingConstants::MISSING_IMAGE_NAME;
else if (bspMaterial.materialType == MATERIAL_TYPE_COLOUR)
materialName = BSPLinkingConstants::COLOR_ONLY_IMAGE_NAME;
else // MATERIAL_TYPE_TEXTURE
materialName = bspMaterial.materialName; materialName = bspMaterial.materialName;
else // MATERIAL_TYPE_COLOUR
materialName = BSPLinkingConstants::COLOR_ONLY_IMAGE_NAME;
auto surfMaterialAsset = m_context.LoadDependency<AssetMaterial>(materialName); auto surfMaterialAsset = m_context.LoadDependency<AssetMaterial>(materialName);
if (surfMaterialAsset == nullptr) if (surfMaterialAsset == nullptr)
@@ -401,7 +399,7 @@ namespace BSP
for (unsigned int i = 0; i < gfxWorld->lightGrid.entryCount; i++) for (unsigned int i = 0; i < gfxWorld->lightGrid.entryCount; i++)
{ {
entryArray[i].colorsIndex = 0; // always index first colour entryArray[i].colorsIndex = 0; // always index first colour
entryArray[i].primaryLightIndex = BSPEditableConstants::DEFAULT_SURFACE_LIGHT; entryArray[i].primaryLightIndex = BSPGameConstants::SUN_LIGHT_INDEX;
entryArray[i].visibility = 0; entryArray[i].visibility = 0;
} }
gfxWorld->lightGrid.entries = entryArray; gfxWorld->lightGrid.entries = entryArray;