Orange/src/Orange/Graphics/Mesh.cpp

106 lines
3.5 KiB
C++

#pragma once
#include <Orange/Graphics/Mesh.h>
#include <Orange/Core/Parse.h>
namespace orange
{
Result<MeshData> ParseOBJ(StringView buffer)
{
MeshData data{ MeshVertexType::Static };
Vector<vec3> positions;
Vector<vec2> uvs;
Vector<vec3> normals;
const char* obj = buffer.data;
const char* end = buffer.data + buffer.size;
while (obj != end)
{
SmallVector<char, 8> element;
stream::ReadString(obj, end, " #\n", element);
if (element == "v" || element == "vt" || element == "vn")
{
float vtx[3]{};
for (int i = 0; i < 3; i++)
{
stream::ConsumeSpace(obj, end);
if (auto r_float = stream::Parse<float>(obj, end))
vtx[i] = *r_float;
}
if (element == "v")
positions.EmplaceBack(vtx[0], vtx[1], vtx[2]);
else if (element == "vt")
uvs.EmplaceBack(vtx[0], vtx[1]);
else if (element == "vn")
normals.EmplaceBack(vtx[0], vtx[1], vtx[2]);
}
else if (element == "g" || element == "o")
{
stream::ConsumeSpace(obj, end);
SmallVector<char, 32> name;
stream::ReadString(obj, end, " #\n", name);
name.PushBack('\0');
if (element == "g")
log::info("Group name: %s", name.Data());
else
log::info("Object name: %s", name.Data());
}
else if (element == "f")
{
int32_t indices[3][3]{};
for (int i = 0; i < 3; i++)
{
stream::ConsumeSpace(obj, end);
for (int j = 0; j < 3; j++)
{
indices[i][j] = -1;
if (j == 0 || stream::Consume(obj, end, "/"))
{
if (auto r_int = stream::Parse<uint32_t>(obj, end))
indices[i][j] = *r_int - 1; // OBJ indexing starts at one.
}
}
}
for (int i = 0; i < 3; i++)
{
StaticVertex vertex =
{
.pos = indices[i][0] != -1 ? positions[indices[i][0]] : vec3{},
.uv = indices[i][1] != -1 ? uvs [indices[i][1]] : vec2{},
.normal = indices[i][2] != -1 ? normals [indices[i][2]] : vec3{},
};
auto& vertices = data.vertexData.GetStaticVertices();
size_t vertexIdx = vertices.FindIdx(vertex);
if (vertexIdx == vertices.InvalidIdx)
{
data.bounds.Extend(vertex.pos);
vertexIdx = vertices.PushBack(vertex);
}
Assert(vertexIdx < UINT16_MAX);
data.indices.PushBack(uint16_t(vertexIdx));
}
}
else if (!element.Empty())
{
element.PushBack('\0');
log::info("Unknown element: %s", element.Data());
}
stream::AdvancePast(obj, end, "\n");
};
return Result<MeshData>::Success(data);
}
}