Minimal viable wavefront object parser completed
This commit is contained in:
parent
ce539d4903
commit
8ce4221ad2
@ -11,13 +11,64 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
typedef struct ModelFace
|
||||
typedef struct WavefrontModelFace
|
||||
{
|
||||
i32 numVertex;
|
||||
i32 *vertexIndex;
|
||||
i32 *textureIndex;
|
||||
i32 *normalIndex;
|
||||
} ModelFace;
|
||||
DqnArray<i32> vertexArray;
|
||||
DqnArray<i32> textureArray;
|
||||
DqnArray<i32> normalArray;
|
||||
} WavefrontModelFace;
|
||||
|
||||
FILE_SCOPE inline WavefrontModelFace ObjWavefrontModelFaceInit(i32 capacity = 3)
|
||||
{
|
||||
WavefrontModelFace result = {};
|
||||
DQN_ASSERT(DqnArray_Init(&result.vertexArray, capacity));
|
||||
DQN_ASSERT(DqnArray_Init(&result.textureArray, capacity));
|
||||
DQN_ASSERT(DqnArray_Init(&result.normalArray, capacity));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct WavefrontModel
|
||||
{
|
||||
// TODO(doyle): Fixed size
|
||||
char *groupName[16];
|
||||
i32 groupNameIndex;
|
||||
i32 groupSmoothing;
|
||||
|
||||
DqnArray<WavefrontModelFace> faces;
|
||||
} WavefrontModel;
|
||||
|
||||
typedef struct WavefrontObj
|
||||
{
|
||||
DqnArray<DqnV4> geometryArray;
|
||||
DqnArray<DqnV3> texUVArray;
|
||||
DqnArray<DqnV3> normalArray;
|
||||
|
||||
WavefrontModel model;
|
||||
} WavefrontObj;
|
||||
|
||||
FILE_SCOPE bool ObjWaveFrontInit(WavefrontObj *const obj, const i32 vertexInitCapacity = 1000,
|
||||
const i32 faceInitCapacity = 200)
|
||||
{
|
||||
if (!obj) return false;
|
||||
|
||||
bool initialised = false;
|
||||
|
||||
initialised |= DqnArray_Init(&obj->geometryArray, vertexInitCapacity);
|
||||
initialised |= DqnArray_Init(&obj->texUVArray, vertexInitCapacity);
|
||||
initialised |= DqnArray_Init(&obj->normalArray, vertexInitCapacity);
|
||||
initialised |= DqnArray_Init(&obj->model.faces, faceInitCapacity);
|
||||
|
||||
if (!initialised)
|
||||
{
|
||||
DqnArray_Free(&obj->geometryArray);
|
||||
DqnArray_Free(&obj->texUVArray);
|
||||
DqnArray_Free(&obj->normalArray);
|
||||
DqnArray_Free(&obj->model.faces);
|
||||
}
|
||||
|
||||
return initialised;
|
||||
}
|
||||
|
||||
FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const memory,
|
||||
const char *const path)
|
||||
@ -40,11 +91,6 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
DqnV3 *vertex;
|
||||
ModelFace *face;
|
||||
#endif
|
||||
|
||||
enum WavefrontVertexType {
|
||||
WavefrontVertexType_Invalid,
|
||||
WavefrontVertexType_Geometric,
|
||||
@ -52,17 +98,21 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
||||
WavefrontVertexType_Normal,
|
||||
};
|
||||
|
||||
DqnArray<DqnV4> vGeometricArray = {};
|
||||
DqnArray<DqnV3> vTextureArray = {};
|
||||
DqnArray<DqnV3> vNormalArray = {};
|
||||
DQN_ASSERT(DqnArray_Init(&vGeometricArray, 1000) && DqnArray_Init(&vTextureArray, 1000) &&
|
||||
DqnArray_Init(&vNormalArray, 1000));
|
||||
|
||||
for (char *scan = (char *)rawBytes; scan;)
|
||||
WavefrontObj obj = {};
|
||||
if (!ObjWaveFrontInit(&obj))
|
||||
{
|
||||
switch (*scan)
|
||||
DqnMemBuffer_EndTempRegion(tmpMemRegion);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (char *scan = (char *)rawBytes; scan && scan < ((char *)rawBytes + fileSize);)
|
||||
{
|
||||
switch (DqnChar_ToLower(*scan))
|
||||
{
|
||||
// Vertex Format: v[ |t|n|p] f32 f32 f32 [f32]
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Polygonal Free Form Statement
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Vertex Format: v[ |t|n|p] x y z [w]
|
||||
case 'v':
|
||||
{
|
||||
scan++;
|
||||
@ -70,14 +120,15 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
||||
|
||||
enum WavefrontVertexType type = WavefrontVertexType_Invalid;
|
||||
|
||||
if (*scan == ' ') type = WavefrontVertexType_Geometric;
|
||||
else if (*scan == 't' || *scan == 'n')
|
||||
char identifier = DqnChar_ToLower(*scan);
|
||||
if (identifier == ' ') type = WavefrontVertexType_Geometric;
|
||||
else if (identifier == 't' || identifier == 'n')
|
||||
{
|
||||
scan++;
|
||||
if (*scan == 't') type = WavefrontVertexType_Texture;
|
||||
else type = WavefrontVertexType_Normal;
|
||||
if (identifier == 't') type = WavefrontVertexType_Texture;
|
||||
else type = WavefrontVertexType_Normal;
|
||||
}
|
||||
else DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||
else DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||
|
||||
i32 vIndex = 0;
|
||||
DqnV4 v4 = {0, 0, 0, 1.0f};
|
||||
@ -109,15 +160,15 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
||||
DQN_ASSERT(vIndex == 3 || vIndex == 4);
|
||||
if (type == WavefrontVertexType_Geometric)
|
||||
{
|
||||
DqnArray_Push(&vGeometricArray, v4);
|
||||
DqnArray_Push(&obj.geometryArray, v4);
|
||||
}
|
||||
else if (type == WavefrontVertexType_Texture)
|
||||
{
|
||||
DqnArray_Push(&vTextureArray, v4.xyz);
|
||||
DqnArray_Push(&obj.texUVArray, v4.xyz);
|
||||
}
|
||||
else if (type == WavefrontVertexType_Normal)
|
||||
{
|
||||
DqnArray_Push(&vNormalArray, v4.xyz);
|
||||
DqnArray_Push(&obj.normalArray, v4.xyz);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -126,9 +177,175 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
||||
}
|
||||
break;
|
||||
|
||||
// Face Format: i32/i32/i32 i32/i32/i32 i32/i32/i32
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Polygonal Geometry
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Vertex numbers can be negative to reference a relative offset to
|
||||
// the vertex which means the relative order of the vertices
|
||||
// specified in the file, i.e.
|
||||
|
||||
// v 0.000000 2.000000 2.000000
|
||||
// v 0.000000 0.000000 2.000000
|
||||
// v 2.000000 0.000000 2.000000
|
||||
// v 2.000000 2.000000 2.000000
|
||||
// f -4 -3 -2 -1
|
||||
|
||||
// Point Format: p v1 v2 v3 ...
|
||||
// Each point is one vertex.
|
||||
case 'p':
|
||||
{
|
||||
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||
}
|
||||
break;
|
||||
|
||||
// Line Format: l v1/vt1 v2/vt2 v3/vt3 ...
|
||||
// Texture vertex is optional. Minimum of two vertex numbers, no
|
||||
// limit on maximum.
|
||||
case 'l':
|
||||
{
|
||||
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||
}
|
||||
break;
|
||||
|
||||
// Face Format: f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...
|
||||
// Minimum of three vertexes, no limit on maximum. vt, vn are
|
||||
// optional. But specification of vt, vn must be consistent if given
|
||||
// across all the vertices for the line.
|
||||
|
||||
// For example, to specify only the vertex and vertex normal
|
||||
// reference numbers, you would enter:
|
||||
|
||||
// f 1//1 2//2 3//3 4//4
|
||||
case 'f':
|
||||
{
|
||||
scan++;
|
||||
while (scan && (*scan == ' ' || *scan == '\n')) scan++;
|
||||
if (!scan) continue;
|
||||
|
||||
WavefrontModelFace face = ObjWavefrontModelFaceInit();
|
||||
i32 numVertexesParsed = 0;
|
||||
bool moreVertexesToParse = true;
|
||||
while (moreVertexesToParse)
|
||||
{
|
||||
enum WavefrontVertexType type = WavefrontVertexType_Geometric;
|
||||
|
||||
// Read a vertexes 3 attributes v, vt, vn
|
||||
for (i32 i = 0; i < 3; i++)
|
||||
{
|
||||
char *numStartPtr = scan;
|
||||
while (scan && DqnChar_IsDigit(*scan))
|
||||
scan++;
|
||||
|
||||
i32 numLen = (i32)((size_t)scan - (size_t)numStartPtr);
|
||||
if (numLen > 0)
|
||||
{
|
||||
i32 index = (i32)Dqn_StrToI64(numStartPtr, numLen);
|
||||
|
||||
if (type == WavefrontVertexType_Geometric)
|
||||
{
|
||||
DQN_ASSERT(DqnArray_Push(&face.vertexArray, index));
|
||||
}
|
||||
else if (type == WavefrontVertexType_Texture)
|
||||
{
|
||||
DQN_ASSERT(DqnArray_Push(&face.textureArray, index));
|
||||
}
|
||||
else if (type == WavefrontVertexType_Normal)
|
||||
{
|
||||
DQN_ASSERT(DqnArray_Push(&face.normalArray, index));
|
||||
}
|
||||
}
|
||||
|
||||
if (scan) scan++;
|
||||
type = (enum WavefrontVertexType)((i32)type + 1);
|
||||
}
|
||||
numVertexesParsed++;
|
||||
|
||||
if (scan)
|
||||
{
|
||||
// Move to next "non-empty" character
|
||||
while (scan && (*scan == ' ' || *scan == '\n'))
|
||||
scan++;
|
||||
|
||||
// If it isn't a digit, then we've read all the
|
||||
// vertexes for this face
|
||||
if (!scan || (scan && !DqnChar_IsDigit(*scan)))
|
||||
{
|
||||
moreVertexesToParse = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.model.faces.count == 7470 || obj.model.faces.count == 2491)
|
||||
{
|
||||
int x = 5;
|
||||
}
|
||||
}
|
||||
DQN_ASSERT(numVertexesParsed >= 3);
|
||||
DQN_ASSERT(DqnArray_Push(&obj.model.faces, face));
|
||||
}
|
||||
break;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Group Name Format: g group_name1 group_name2
|
||||
// This is optional, if multiple groups are specified, then the
|
||||
// following elements belong to all groups. The default group name
|
||||
// is "default"
|
||||
case 'g':
|
||||
{
|
||||
scan++;
|
||||
while (scan && (*scan == ' ' || *scan == '\n')) scan++;
|
||||
|
||||
if (!scan) continue;
|
||||
|
||||
// Iterate to end of the name, i.e. move ptr to first space
|
||||
char *namePtr = scan;
|
||||
while (scan && (*scan != ' ' && *scan != '\n'))
|
||||
scan++;
|
||||
|
||||
if (scan)
|
||||
{
|
||||
i32 nameLen = (i32)((size_t)scan - (size_t)namePtr);
|
||||
DQN_ASSERT(obj.model.groupNameIndex + 1 < DQN_ARRAY_COUNT(obj.model.groupName));
|
||||
|
||||
DQN_ASSERT(!obj.model.groupName[obj.model.groupNameIndex]);
|
||||
obj.model.groupName[obj.model.groupNameIndex++] = (char *)DqnMemBuffer_Allocate(
|
||||
&memory->permanentBuffer, (nameLen + 1) * sizeof(char));
|
||||
|
||||
for (i32 i = 0; i < nameLen; i++)
|
||||
obj.model.groupName[obj.model.groupNameIndex - 1][i] = namePtr[i];
|
||||
|
||||
while (scan && (*scan == ' ' || *scan == '\n'))
|
||||
scan++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Smoothing Group: s group_number
|
||||
// Sets the smoothing group for the elements that follow it. If it's
|
||||
// not to be used it can be specified as "off" or a value of 0.
|
||||
case 's':
|
||||
{
|
||||
// Advance to first non space char after identifier
|
||||
scan++;
|
||||
while (scan && *scan == ' ' || *scan == '\n') scan++;
|
||||
|
||||
if (scan && DqnChar_IsDigit(*scan))
|
||||
{
|
||||
char *numStartPtr = scan;
|
||||
while (scan && (*scan != ' ' && *scan != '\n'))
|
||||
{
|
||||
DQN_ASSERT(DqnChar_IsDigit(*scan));
|
||||
scan++;
|
||||
}
|
||||
|
||||
i32 numLen = (i32)((size_t)scan - (size_t)numStartPtr);
|
||||
i32 groupSmoothing = (i32)Dqn_StrToI64(numStartPtr, numLen);
|
||||
obj.model.groupSmoothing = groupSmoothing;
|
||||
}
|
||||
|
||||
while (scan && *scan == ' ' || *scan == '\n') scan++;
|
||||
}
|
||||
break;
|
||||
|
||||
|
27
src/dqn.h
27
src/dqn.h
@ -507,8 +507,15 @@ typedef union DqnV3
|
||||
f32 e[3];
|
||||
} DqnV3;
|
||||
|
||||
// Create a vector using ints and typecast to floats
|
||||
DQN_FILE_SCOPE DqnV3 DqnV3_3i(i32 x, i32 y, i32 z);
|
||||
typedef union DqnV3i
|
||||
{
|
||||
struct { i32 x, y, z; };
|
||||
struct { i32 r, g, b; };
|
||||
i32 e[3];
|
||||
} DqnV3i;
|
||||
|
||||
// DqnV3
|
||||
DQN_FILE_SCOPE DqnV3 DqnV3_3i(i32 x, i32 y, i32 z); // Create a vector using ints and typecast to floats
|
||||
DQN_FILE_SCOPE DqnV3 DqnV3_3f(f32 x, f32 y, f32 z);
|
||||
|
||||
DQN_FILE_SCOPE DqnV3 DqnV3_Add (DqnV3 a, DqnV3 b);
|
||||
@ -532,6 +539,10 @@ DQN_FILE_SCOPE inline DqnV3 &operator-=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_S
|
||||
DQN_FILE_SCOPE inline DqnV3 &operator+=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Add (a, b)); }
|
||||
DQN_FILE_SCOPE inline bool operator==(DqnV3 a, DqnV3 b) { return DqnV3_Equals (a, b); }
|
||||
|
||||
// DqnV3i
|
||||
DQN_FILE_SCOPE DqnV3i DqnV3i_3i(i32 x, i32 y, i32 z);
|
||||
DQN_FILE_SCOPE DqnV3i DqnV3i_3f(f32 x, f32 y, f32 z);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Vec4
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2096,6 +2107,18 @@ DQN_FILE_SCOPE DqnV3 DqnV3_Cross(DqnV3 a, DqnV3 b)
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_FILE_SCOPE DqnV3i DqnV3i_3i(i32 x, i32 y, i32 z)
|
||||
{
|
||||
DqnV3i result = {x, y, z};
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_FILE_SCOPE DqnV3i DqnV3i_3f(f32 x, f32 y, f32 z)
|
||||
{
|
||||
DqnV3i result = {(i32)x, (i32)y, (i32)z};
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Vec4
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user