2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-06 16:52: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
{
MATERIAL_TYPE_COLOUR,
MATERIAL_TYPE_TEXTURE,
MATERIAL_TYPE_EMPTY
MATERIAL_TYPE_TEXTURE
};
struct BSPVertex
@@ -30,8 +29,9 @@ namespace BSP
struct BSPMaterial
{
BSPMaterialType materialType;
std::string materialName;
BSPMaterialType materialType;
vec4_t materialColour;
};
struct BSPSurface
@@ -132,7 +132,7 @@ namespace BSP
namespace BSPLinkingConstants
{
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"({
"attackers": [
@@ -186,7 +186,7 @@ namespace BSP
constexpr int DEFAULT_SMODEL_REFLECTION_PROBE = 0;
// 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_REFLECTION_PROBE = 0;
constexpr int DEFAULT_SURFACE_FLAGS = 0;
+92 -75
View File
@@ -28,7 +28,7 @@ namespace
unsigned m_position_accessor;
unsigned m_normal_accessor;
std::optional<unsigned> m_color_accessor;
unsigned m_uv_accessor;
std::optional<unsigned> m_uv_accessor;
unsigned m_index_accessor;
};
@@ -83,7 +83,6 @@ namespace
private:
const Input& m_input;
BSPData* m_bsp;
size_t m_color_mat_idx;
std::vector<std::unique_ptr<Accessor>> m_accessors;
std::vector<std::unique_ptr<BufferView>> m_buffer_views;
std::vector<std::unique_ptr<Buffer>> m_buffers;
@@ -190,7 +189,8 @@ namespace
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
const auto* positionAccessor = GetAccessorForIndex(
@@ -203,6 +203,7 @@ namespace
assert(positionAccessor != nullptr);
const auto vertexCount = positionAccessor->GetCount();
NullAccessor nullAccessor(vertexCount);
OnesAccessor onesAccessor(vertexCount);
// clang-format off
@@ -220,9 +221,8 @@ namespace
accessorsForVertex.m_uv_accessor,
{ JsonAccessorType::VEC2 },
{ JsonAccessorComponentType::FLOAT, JsonAccessorComponentType::UNSIGNED_BYTE, JsonAccessorComponentType::UNSIGNED_SHORT }
).value_or(nullptr);
).value_or(&nullAccessor);
VerifyAccessorVertexCount("TEXCOORD_0", uvAccessor, vertexCount);
assert(uvAccessor != nullptr);
const auto* colorAccessor = GetAccessorForIndex(
"COLOR_0",
@@ -282,6 +282,11 @@ namespace
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 transformedPosition = nodeMatrix * position;
vertex.pos.x = transformedPosition.x();
@@ -313,24 +318,8 @@ namespace
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);
if (node.extensions && node.extensions->KHR_lights_punctual)
@@ -375,48 +364,45 @@ namespace
return true;
}
con::info("Mesh {} found", node.name.has_value() ? node.name.value() : "");
const auto& mesh = jRoot.meshes.value()[node.mesh.value()];
for (const auto& primitive : mesh.primitives)
if (node.mesh)
{
if (!primitive.indices)
throw GltfLoadException("Requires primitives indices");
if (primitive.mode.value_or(JsonMeshPrimitivesMode::TRIANGLES) != JsonMeshPrimitivesMode::TRIANGLES)
throw GltfLoadException("Only triangles are supported");
if (!primitive.attributes.POSITION)
throw GltfLoadException("Requires primitives attribute POSITION");
if (!primitive.attributes.NORMAL)
throw GltfLoadException("Requires primitives attribute NORMAL");
if (!primitive.attributes.TEXCOORD_0)
throw GltfLoadException("Requires primitives attribute TEXCOORD_0");
assert(jRoot.meshes);
const auto& mesh = jRoot.meshes.value()[node.mesh.value()];
for (const auto& primitive : mesh.primitives)
{
if (!primitive.indices)
throw GltfLoadException("Requires primitives indices");
if (primitive.mode.value_or(JsonMeshPrimitivesMode::TRIANGLES) != JsonMeshPrimitivesMode::TRIANGLES)
throw GltfLoadException("Only triangles are supported");
if (!primitive.attributes.POSITION)
throw GltfLoadException("Requires primitives attribute POSITION");
if (!primitive.attributes.NORMAL)
throw GltfLoadException("Requires primitives attribute NORMAL");
const AccessorsForVertex accessorsForVertex{
.m_position_accessor = *primitive.attributes.POSITION,
.m_normal_accessor = *primitive.attributes.NORMAL,
.m_color_accessor = primitive.attributes.COLOR_0,
.m_uv_accessor = *primitive.attributes.TEXCOORD_0,
.m_index_accessor = *primitive.indices,
};
const AccessorsForVertex accessorsForVertex{
.m_position_accessor = *primitive.attributes.POSITION,
.m_normal_accessor = *primitive.attributes.NORMAL,
.m_color_accessor = primitive.attributes.COLOR_0,
.m_uv_accessor = primitive.attributes.TEXCOORD_0,
.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)
surface.materialIndex = *primitive.material;
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);
m_bsp->gfxWorld.surfaces.emplace_back(surface);
return true;
}
}
return true;
}
static std::vector<unsigned> GetRootNodes(const JsonRoot& jRoot)
{
if (!jRoot.nodes || jRoot.nodes->empty())
return {};
@@ -453,31 +439,62 @@ namespace
void LoadMaterials(const JsonRoot& jRoot)
{
if (!jRoot.materials)
return;
m_bsp->gfxWorld.materials.reserve((*jRoot.materials).size());
for (auto& jsMaterial : *jRoot.materials)
if (jRoot.materials)
{
BSPMaterial material;
if (jsMaterial.name && (*jsMaterial.name).length() != 0)
m_bsp->gfxWorld.materials.reserve((*jRoot.materials).size());
for (auto& jsMaterial : *jRoot.materials)
{
material.materialType = MATERIAL_TYPE_TEXTURE;
material.materialName = *jsMaterial.name;
}
else
{
material.materialType = MATERIAL_TYPE_EMPTY;
material.materialName = "";
}
BSPMaterial material;
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;
colorMaterial.materialType = MATERIAL_TYPE_COLOUR;
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);
}
@@ -579,7 +596,7 @@ namespace
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);
LoadMaterials(jRoot);
TraverseNodes(jRoot);
TraverseNodes(jRoot); // requires materials and lights
}
catch (const GltfLoadException& e)
{
@@ -74,15 +74,13 @@ namespace BSP
gfxSurface->tris.vertexDataOffset0 = bspSurface.indexOfFirstVertex * sizeof(GfxPackedWorldVertex);
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;
if (bspMaterial.materialType == MATERIAL_TYPE_EMPTY)
materialName = BSPLinkingConstants::MISSING_IMAGE_NAME;
else if (bspMaterial.materialType == MATERIAL_TYPE_COLOUR)
materialName = BSPLinkingConstants::COLOR_ONLY_IMAGE_NAME;
else // MATERIAL_TYPE_TEXTURE
if (bspMaterial.materialType == MATERIAL_TYPE_TEXTURE)
materialName = bspMaterial.materialName;
else // MATERIAL_TYPE_COLOUR
materialName = BSPLinkingConstants::COLOR_ONLY_IMAGE_NAME;
auto surfMaterialAsset = m_context.LoadDependency<AssetMaterial>(materialName);
if (surfMaterialAsset == nullptr)
@@ -401,7 +399,7 @@ namespace BSP
for (unsigned int i = 0; i < gfxWorld->lightGrid.entryCount; i++)
{
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;
}
gfxWorld->lightGrid.entries = entryArray;