Minimal viable wavefront object parser completed
This commit is contained in:
parent
ce539d4903
commit
8ce4221ad2
@ -11,13 +11,64 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
typedef struct ModelFace
|
typedef struct WavefrontModelFace
|
||||||
{
|
{
|
||||||
i32 numVertex;
|
DqnArray<i32> vertexArray;
|
||||||
i32 *vertexIndex;
|
DqnArray<i32> textureArray;
|
||||||
i32 *textureIndex;
|
DqnArray<i32> normalArray;
|
||||||
i32 *normalIndex;
|
} WavefrontModelFace;
|
||||||
} ModelFace;
|
|
||||||
|
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,
|
FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const memory,
|
||||||
const char *const path)
|
const char *const path)
|
||||||
@ -40,11 +91,6 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
DqnV3 *vertex;
|
|
||||||
ModelFace *face;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum WavefrontVertexType {
|
enum WavefrontVertexType {
|
||||||
WavefrontVertexType_Invalid,
|
WavefrontVertexType_Invalid,
|
||||||
WavefrontVertexType_Geometric,
|
WavefrontVertexType_Geometric,
|
||||||
@ -52,17 +98,21 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
|||||||
WavefrontVertexType_Normal,
|
WavefrontVertexType_Normal,
|
||||||
};
|
};
|
||||||
|
|
||||||
DqnArray<DqnV4> vGeometricArray = {};
|
WavefrontObj obj = {};
|
||||||
DqnArray<DqnV3> vTextureArray = {};
|
if (!ObjWaveFrontInit(&obj))
|
||||||
DqnArray<DqnV3> vNormalArray = {};
|
|
||||||
DQN_ASSERT(DqnArray_Init(&vGeometricArray, 1000) && DqnArray_Init(&vTextureArray, 1000) &&
|
|
||||||
DqnArray_Init(&vNormalArray, 1000));
|
|
||||||
|
|
||||||
for (char *scan = (char *)rawBytes; scan;)
|
|
||||||
{
|
{
|
||||||
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':
|
case 'v':
|
||||||
{
|
{
|
||||||
scan++;
|
scan++;
|
||||||
@ -70,14 +120,15 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
|||||||
|
|
||||||
enum WavefrontVertexType type = WavefrontVertexType_Invalid;
|
enum WavefrontVertexType type = WavefrontVertexType_Invalid;
|
||||||
|
|
||||||
if (*scan == ' ') type = WavefrontVertexType_Geometric;
|
char identifier = DqnChar_ToLower(*scan);
|
||||||
else if (*scan == 't' || *scan == 'n')
|
if (identifier == ' ') type = WavefrontVertexType_Geometric;
|
||||||
|
else if (identifier == 't' || identifier == 'n')
|
||||||
{
|
{
|
||||||
scan++;
|
scan++;
|
||||||
if (*scan == 't') type = WavefrontVertexType_Texture;
|
if (identifier == 't') type = WavefrontVertexType_Texture;
|
||||||
else type = WavefrontVertexType_Normal;
|
else type = WavefrontVertexType_Normal;
|
||||||
}
|
}
|
||||||
else DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
else DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||||
|
|
||||||
i32 vIndex = 0;
|
i32 vIndex = 0;
|
||||||
DqnV4 v4 = {0, 0, 0, 1.0f};
|
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);
|
DQN_ASSERT(vIndex == 3 || vIndex == 4);
|
||||||
if (type == WavefrontVertexType_Geometric)
|
if (type == WavefrontVertexType_Geometric)
|
||||||
{
|
{
|
||||||
DqnArray_Push(&vGeometricArray, v4);
|
DqnArray_Push(&obj.geometryArray, v4);
|
||||||
}
|
}
|
||||||
else if (type == WavefrontVertexType_Texture)
|
else if (type == WavefrontVertexType_Texture)
|
||||||
{
|
{
|
||||||
DqnArray_Push(&vTextureArray, v4.xyz);
|
DqnArray_Push(&obj.texUVArray, v4.xyz);
|
||||||
}
|
}
|
||||||
else if (type == WavefrontVertexType_Normal)
|
else if (type == WavefrontVertexType_Normal)
|
||||||
{
|
{
|
||||||
DqnArray_Push(&vNormalArray, v4.xyz);
|
DqnArray_Push(&obj.normalArray, v4.xyz);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -126,9 +177,175 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
|
|||||||
}
|
}
|
||||||
break;
|
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':
|
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;
|
break;
|
||||||
|
|
||||||
|
27
src/dqn.h
27
src/dqn.h
@ -507,8 +507,15 @@ typedef union DqnV3
|
|||||||
f32 e[3];
|
f32 e[3];
|
||||||
} DqnV3;
|
} DqnV3;
|
||||||
|
|
||||||
// Create a vector using ints and typecast to floats
|
typedef union DqnV3i
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_3i(i32 x, i32 y, i32 z);
|
{
|
||||||
|
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_3f(f32 x, f32 y, f32 z);
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_Add (DqnV3 a, DqnV3 b);
|
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 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); }
|
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
|
// Vec4
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -2096,6 +2107,18 @@ DQN_FILE_SCOPE DqnV3 DqnV3_Cross(DqnV3 a, DqnV3 b)
|
|||||||
return result;
|
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
|
// Vec4
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user