set up model data loading

This commit is contained in:
matthew 2025-06-17 20:02:34 +10:00
parent 3500f657d8
commit 874b5de482
10 changed files with 389 additions and 128 deletions

View File

@ -1,3 +1,4 @@
.git
external
assets
build

View File

@ -376,7 +376,7 @@ static inline b32 apChkMag(u32 *magic, u32 expected)
}
// TODO: parse this without the SDK
static Model *
static apModel *
apParseModel(u8 *data)
{
m3d_t *m3d = m3d_load(data, NULL, NULL, NULL);
@ -399,82 +399,186 @@ apParseModel(u8 *data)
Printfln("numinlined: %llu", m3d->numinlined);
Printfln("numextra: %llu", m3d->numextra);
Model *model = (Model *)malloc(sizeof(Model));
model->vertex.count = u64(m3d->numvertex);
model->vertex.data = (Vertex *)malloc(sizeof(Vertex) * model->vertex.count);
apModel *model = (apModel *)malloc(sizeof(apModel));
model->index.count = u64(m3d->numface * 3);
model->index.data = (u32 *)malloc(sizeof(u32) * model->index.count);
model->vertices.length = u64(m3d->numface * 3);
model->vertices.data = (apVertex *)malloc(sizeof(apVertex) * model->vertices.length);
model->material.count = u64(m3d->nummaterial);
model->material.data = (Material *)malloc(sizeof(Material) * m3d->nummaterial);
model->indices.length = u64(m3d->numface * 3);
model->indices.data = (u32 *)malloc(sizeof(u32) * model->indices.length);
model->materials.length = u64(m3d->nummaterial);
model->materials.data = (apMaterial *)malloc(sizeof(apMaterial) * m3d->nummaterial);
model->textures.length = u64(m3d->numtexture);
model->textures.data = (apTexData *)malloc(sizeof(apTexData) * m3d->numtexture);
for (u64 i = 0; i < m3d->numtexture; i += 1)
{
model->textures.data[i].bytes = m3d->texture[i].d;
model->textures.data[i].w = m3d->texture[i].w;
model->textures.data[i].h = m3d->texture[i].h;
model->textures.data[i].ch = m3d->texture[i].f;
#ifdef BUILD_DEBUG
Assert(i < model->textures.length, "Textures out of bounds access");
#endif
}
for (u64 i = 0; i < m3d->nummaterial; i += 1)
{
model->materials.data[i].tex.albedo = UINT32_MAX;
model->materials.data[i].tex.ambient = UINT32_MAX;
model->materials.data[i].tex.specular = UINT32_MAX;
for (u64 j = 0; j < m3d->material[i].numprop; j += 1)
{
switch (m3d->material[i].prop[j].type)
{
case m3dp_Kd:
{
U32ColToVec4(&model->material.data[i].color, m3d->material[i].prop[j].value.color);
U32ColToVec4(&model->materials.data[i].props.albedo, m3d->material[i].prop[j].value.color);
} break;
case m3dp_Ka:
{
U32ColToVec4(&model->material.data[i].ambient, m3d->material[i].prop[j].value.color);
U32ColToVec4(&model->materials.data[i].props.ambient, m3d->material[i].prop[j].value.color);
} break;
case m3dp_Ks:
{
U32ColToVec4(&model->material.data[i].specular, m3d->material[i].prop[j].value.color);
} break;
case m3dp_Ke:
{
U32ColToVec4(&model->material.data[i].emission, m3d->material[i].prop[j].value.color);
U32ColToVec4(&model->materials.data[i].props.specular, m3d->material[i].prop[j].value.color);
} break;
case m3dp_Ns:
{
model->material.data[i].shininess = m3d->material[i].prop[j].value.fnum;
model->materials.data[i].props.shininess = m3d->material[i].prop[j].value.fnum;
} break;
case m3dp_map_Kd:
{
model->materials.data[i].tex.albedo = m3d->material[i].prop[j].value.textureid;
} break;
case m3dp_map_Ka:
{
model->materials.data[i].tex.ambient = m3d->material[i].prop[j].value.textureid;
} break;
case m3dp_map_Ks:
{
model->materials.data[i].tex.specular = m3d->material[i].prop[j].value.textureid;
} break;
default:
break;
}
}
#ifdef BUILD_DEBUG
Assert(i < model->materials.length, "Materials out of bounds access");
#endif
}
u32 num_meshes = 0;
u32 last = UINT32_MAX;
for (u64 i = 0; i < m3d->numface; i += 1)
{
if (m3d->face[i].materialid != last)
{
last = m3d->face[i].materialid;
num_meshes += 1;
}
}
for (u64 i = 0; i < m3d->numinlined; i += 1)
{
Image texture = apLoadImage(m3d->inlined[i].data, m3d->inlined[i].length);
Assert(texture.data != NULL, "Image is null");
}
model->meshes.length = u64(num_meshes);
model->meshes.data = (apMesh *)malloc(sizeof(apMesh) * num_meshes);
/*
TODO: replace
for (u64 i = 0; i < m3d->numvertex; i += 1)
last = UINT32_MAX;
u32 current_index = 0;
for (u64 i = 0, j = 0; i < m3d->numface; i += 1, j += 3)
{
model->vertex.data[i].pos.x = m3d->vertex[i].x;
model->vertex.data[i].pos.y = m3d->vertex[i].y;
model->vertex.data[i].pos.z = m3d->vertex[i].z;
model->vertex.data[i].pos.w = m3d->vertex[i].w;
model->vertex.data[i].col.packed = m3d->vertex[i].color;
if (last == UINT32_MAX)
{
model->meshes.data[current_index].mat_idx = m3d->face[i].materialid;
model->meshes.data[current_index].start_idx = 0;
last = m3d->face[i].materialid;
}
else if (m3d->face[i].materialid != last)
{
model->meshes.data[current_index].length = j - model->meshes.data[current_index].start_idx;
current_index += 1;
model->meshes.data[current_index].mat_idx = m3d->face[i].materialid;
model->meshes.data[current_index].start_idx = j;
last = m3d->face[i].materialid;
}
else if (i == m3d->numface-1)
{
model->meshes.data[current_index].length = j+3 - model->meshes.data[current_index].start_idx;
}
#ifdef BUILD_DEBUG
Assert(current_index < model->meshes.length, "Mesh out of bounds access");
#endif
}
for (u64 i = 0, j = 0; i < m3d->numface; i += 1, j += 3)
{
model->index.data[j] = m3d->face[i].vertex[0];
model->index.data[j+1] = m3d->face[i].vertex[1];
model->index.data[j+2] = m3d->face[i].vertex[2];
}
*/
model->vertices.data[j+0].pos.x = m3d->vertex[m3d->face[i].vertex[0]].x;
model->vertices.data[j+0].pos.y = m3d->vertex[m3d->face[i].vertex[0]].y;
model->vertices.data[j+0].pos.z = m3d->vertex[m3d->face[i].vertex[0]].z;
m3d_free(m3d);
model->vertices.data[j+1].pos.x = m3d->vertex[m3d->face[i].vertex[1]].x;
model->vertices.data[j+1].pos.y = m3d->vertex[m3d->face[i].vertex[1]].y;
model->vertices.data[j+1].pos.z = m3d->vertex[m3d->face[i].vertex[1]].z;
model->vertices.data[j+2].pos.x = m3d->vertex[m3d->face[i].vertex[2]].x;
model->vertices.data[j+2].pos.y = m3d->vertex[m3d->face[i].vertex[2]].y;
model->vertices.data[j+2].pos.z = m3d->vertex[m3d->face[i].vertex[2]].z;
model->vertices.data[j+0].normal.x = m3d->vertex[m3d->face[i].normal[0]].x;
model->vertices.data[j+0].normal.y = m3d->vertex[m3d->face[i].normal[0]].y;
model->vertices.data[j+0].normal.z = m3d->vertex[m3d->face[i].normal[0]].z;
model->vertices.data[j+1].normal.x = m3d->vertex[m3d->face[i].normal[1]].x;
model->vertices.data[j+1].normal.y = m3d->vertex[m3d->face[i].normal[1]].y;
model->vertices.data[j+1].normal.z = m3d->vertex[m3d->face[i].normal[1]].z;
model->vertices.data[j+2].normal.x = m3d->vertex[m3d->face[i].normal[2]].x;
model->vertices.data[j+2].normal.y = m3d->vertex[m3d->face[i].normal[2]].y;
model->vertices.data[j+2].normal.z = m3d->vertex[m3d->face[i].normal[2]].z;
model->vertices.data[j+0].uv.x = m3d->tmap[m3d->face[i].texcoord[0]].u;
model->vertices.data[j+0].uv.y = m3d->tmap[m3d->face[i].texcoord[0]].v;
model->vertices.data[j+1].uv.x = m3d->tmap[m3d->face[i].texcoord[1]].u;
model->vertices.data[j+1].uv.y = m3d->tmap[m3d->face[i].texcoord[1]].v;
model->vertices.data[j+2].uv.x = m3d->tmap[m3d->face[i].texcoord[2]].u;
model->vertices.data[j+2].uv.y = m3d->tmap[m3d->face[i].texcoord[2]].v;
model->indices.data[j+0] = j+0;
model->indices.data[j+1] = j+1;
model->indices.data[j+2] = j+2;
#ifdef BUILD_DEBUG
Assert(j+2 < model->indices.length, "Indices out of bounds access");
Assert(j+2 < model->vertices.length, "Vertices out of bounds access");
#endif
}
for (u64 i = 0; i < model->meshes.length; i += 1)
{
apMesh *mesh = model->meshes.data + i;
Printfln("mat_idx: %llu start_idx: %llu length: %llu", mesh->mat_idx, mesh->start_idx, mesh->length);
}
model->m3d = m3d;
return model;
}
static void apFreeModel(Model *model)
static void apFreeModel(apModel *model)
{
free(model->vertex.data);
free(model->index.data);
m3d_free(model->m3d);
free(model->vertices.data);
free(model->indices.data);
free(model->meshes.data);
free(model->materials.data);
free(model);
}

View File

@ -11,13 +11,14 @@
// ::Assets::Types::Header::
typedef struct Vertex
typedef struct apVertex
{
f32 v_x, v_y, v_z;
f32 n_x, n_y, n_z;
f32 uv_x, uv_y;
u32 color;
} Vertex;
Vec3 pos;
Vec3 normal;
Vec2 uv;
} apVertex;
ArrayType(apVertex);
typedef struct Image
{
@ -27,45 +28,57 @@ typedef struct Image
i32 ch;
} Image;
typedef struct Material
typedef struct apMatProps
{
Vec4 color;
Vec4 albedo;
Vec4 ambient;
Vec4 specular;
Vec4 emission;
f32 shininess;
} Material;
} apMatProps;
typedef struct ModelIndex
typedef struct apMatTextures
{
u32 material;
u32 start;
u32 count;
} ModelIndex;
u32 albedo;
u32 ambient;
u32 specular;
} apMatTextures;
typedef struct Model
typedef struct apMaterial
{
struct
{
Vertex *data;
u64 count;
} vertex;
struct
{
u32 *data;
u64 count;
} index;
struct
{
Material *data;
u64 count;
} material;
struct
{
ModelIndex *data;
u64 count;
} offset;
} Model;
apMatProps props;
apMatTextures tex;
} apMaterial;
ArrayType(apMaterial);
typedef struct apMesh
{
u64 mat_idx;
u64 start_idx;
u64 length;
} apMesh;
ArrayType(apMesh);
typedef struct apTexData
{
rawptr bytes;
u32 w;
u32 h;
u32 ch;
} apTexData;
ArrayType(apTexData);
typedef struct apModel
{
apVertexArray vertices;
u32Array indices;
apMeshArray meshes;
apMaterialArray materials;
apTexDataArray textures;
m3d_t *m3d;
} apModel;
typedef struct TexMeta
{
@ -99,7 +112,7 @@ typedef struct Asset
{
const char *cstr;
u8 *bytes;
Model *model;
apModel *model;
};
union
{
@ -160,5 +173,5 @@ static void apFreeImage(Image *image);
// ::Assets::Models::Functions::Header::
static Model *apParseModel(u8 *data);
static void apFreeModel(Model *model);
static apModel *apParseModel(u8 *data);
static void apFreeModel(apModel *model);

View File

@ -43,6 +43,26 @@ typedef void * rawptr;
typedef u32 usize;
#endif
#define ArrayType(T) \
typedef struct T##Array \
{ \
T *data; \
u64 length; \
} T##Array
#define PtrArrayType(T) \
typedef struct T##PtrArray \
{ \
T **data; \
u64 length; \
} T##PtrArray
#define InitArrayType(arr, arena, T, len) \
arr.data = MakeArray(arena, T, len); \
arr.length = len
ArrayType(u32);
typedef struct String8
{
c8 *value;
@ -53,8 +73,23 @@ typedef union
{
struct { f32 x, y, z, w; };
struct { f32 r, g, b, a; };
f32 array[4];
} Vec4;
typedef union
{
struct { f32 x, y, z; };
struct { f32 r, g, b; };
f32 array[3];
} Vec3;
typedef union
{
struct { f32 x, y; };
struct { f32 r, g; };
f32 array[2];
} Vec2;
typedef union
{
struct { u8 x, y, z, w; };

View File

@ -259,7 +259,7 @@ TestAssetPack(Arena *arena)
for (u32 i = 0; i < MODEL_ASSET_MAX; i++, current_asset++)
{
TestAssetIsCorrect(arena, g_Model_Asset_Names[i], files + current_asset, file);
Assert(files[current_asset].hash == g_Model_Asset_Hashes[i], "Model asset hash mismatch");
Assert(files[current_asset].hash == g_Model_Asset_Hashes[i], "apModel asset hash mismatch");
}
}

View File

@ -11,7 +11,7 @@ PipelineCreateInfo g_Pipeline_Create_Info[] = {
// ::Init::Impl::Start::
MeshBuffer yoder;
rIndexedBuffer yoder;
static b32
Init(Renderer *renderer)
@ -46,11 +46,26 @@ Init(Renderer *renderer)
renderer->pipelines[i] = BuildPipeline(g_Pipeline_Create_Info + i);
}
yoder = CreateMeshBuffer("models/yoda");
yoder = rLoadModel("models/yoda");
return success;
}
static b32
InitModels(Renderer *renderer)
{
b32 success = true;
for (u64 i = 0; i < MODEL_ASSET_MAX; i += 1)
{
u64 hash = g_Model_Asset_Hashes[i];
Asset asset = apLoadWithHash(hash);
Assert(asset.model != NULL, "InitModels failure: Model loaded is NULL");
}
return success;
}
static PipelineHandle
BuildPipeline(PipelineCreateInfo *create_info)
@ -142,10 +157,10 @@ CreateShader(int type)
return (ShaderHandle)glCreateShader(type);
}
static MeshBuffer
CreateMeshBuffer(char *asset)
static rIndexedBuffer
rLoadModel(char *asset)
{
MeshBuffer mesh = {0};
rIndexedBuffer mesh = {0};
/*
mesh.array = CreateVertexArray();
@ -164,7 +179,7 @@ CreateMeshBuffer(char *asset)
glBufferData(
GL_ARRAY_BUFFER,
data.model->v_count * sizeof(Vertex),
data.model->v_count * sizeof(apVertex),
data.model->vertices,
GL_STATIC_DRAW
);
@ -178,10 +193,10 @@ CreateMeshBuffer(char *asset)
);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(apVertex), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, col));
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(apVertex), (void *)offsetof(apVertex, col));
apUnload(asset);
@ -192,17 +207,86 @@ CreateMeshBuffer(char *asset)
return mesh;
}
static void
DrawMeshBuffer(MeshBuffer *mesh)
{
glBindVertexArray(mesh->array);
glDrawElements(GL_TRIANGLES, mesh->draw_count, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
// ::Init::Impl::End::
// ::Draw::Impl::Start::
static void
DrawIndexedBuffer(rIndexedBuffer *buffer)
{
glBindVertexArray(buffer->vao);
glDrawElements(GL_TRIANGLES, buffer->icount, GL_UNSIGNED_INT, (void *)buffer->ioffset);
}
// ::Draw::Impl::End::
// ::Buffers::Impl::Start::
static rIndexedBuffer
CreateIndexedBuffer(rawptr vert_data, u32 vcount, rawptr idx_data, u32 icount)
{
i32 alignment = GL_NONE;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment);
u32 vao = GL_NONE;
u32 buffer = GL_NONE;
isize vert_len = isize(vcount * sizeof(apVertex));
isize idx_len = isize(icount * sizeof(u32));
isize vert_len_aligned = Align(vert_len, alignment);
isize idx_len_aligned = Align(idx_len, alignment);
#if BUILD_DEBUG
Assert((vert_len_aligned / alignment) == 0, "Buffers are not aligned");
Assert((idx_len_aligned / alignment) == 0, "Buffers are not aligned");
#endif
isize vert_offset = 0;
isize idx_offset = vert_len_aligned;
glCreateBuffers(1, &buffer);
glNamedBufferStorage(buffer, idx_len_aligned + vert_len_aligned, NULL, GL_DYNAMIC_STORAGE_BIT);
glNamedBufferSubData(buffer, vert_offset, vert_len, vert_data);
glNamedBufferSubData(buffer, idx_offset, idx_len, idx_data);
glCreateVertexArrays(1, &vao);
constexpr u32 pos_size = SizeOfMember(apVertex, pos) / sizeof(f32);
glEnableVertexArrayAttrib(vao, 0);
glVertexArrayAttribBinding(vao, 0, 0);
glVertexArrayAttribFormat(vao, 0, pos_size, GL_FLOAT, GL_FALSE, 0);
constexpr u32 normal_size = SizeOfMember(apVertex, normal) / sizeof(f32);
glEnableVertexArrayAttrib(vao, 1);
glVertexArrayAttribBinding(vao, 1, 0);
glVertexArrayAttribFormat(vao, 1, normal_size, GL_FLOAT, GL_FALSE, offsetof(apVertex, normal));
constexpr u32 uv_size = SizeOfMember(apVertex, uv) / sizeof(f32);
glEnableVertexArrayAttrib(vao, 2);
glVertexArrayAttribBinding(vao, 2, 0);
glVertexArrayAttribFormat(vao, 2, uv_size, GL_FLOAT, GL_FALSE, offsetof(apVertex, uv));
glVertexArrayVertexBuffer(vao, 0, buffer, vert_offset, sizeof(apVertex));
glVertexArrayElementBuffer(vao, buffer);
rIndexedBuffer indexed_buffer = {0};
indexed_buffer.ioffset = idx_offset;
indexed_buffer.icount = icount;
indexed_buffer.vao = vao;
indexed_buffer.buffer = buffer;
return indexed_buffer;
}
// ::Buffers::Impl::End::
// ::Textures::Impl::Start::
@ -255,12 +339,14 @@ RunCycle(Renderer *renderer)
{
while (RGFW_window_checkEvent(renderer->window));
Asset yoder = apLoad("models/yoda");
glUseProgram(renderer->pipelines[PIPELINE_PBR]);
glClearColor(0.1f, 0.8f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
DrawMeshBuffer(&yoder);
//DrawMeshBuffer(&yoder);
RGFW_window_swapBuffers(renderer->window);

View File

@ -25,39 +25,60 @@ typedef unsigned int ShaderHandle;
typedef unsigned int VertexArray;
typedef unsigned int UBO;
typedef struct MeshBuffer
typedef struct rIndexedBuffer
{
VertexArray array;
VertexBuffer vertex;
IndexBuffer index;
u32 draw_count;
} MeshBuffer;
i64 icount, ioffset;
u32 vao, buffer;
} rIndexedBuffer;
typedef struct rMesh
{
rIndexedBuffer buffer;
apMatProps material;
u32 texture;
} rMesh;
ArrayType(rMesh);
typedef struct rModel
{
rMeshArray meshes;
} rModel;
typedef struct Renderer
{
RGFW_window *window;
PipelineHandle pipelines[PIPELINE_MAX];
MeshBuffer models[MODEL_ASSET_MAX];
rIndexedBuffer models[MODEL_ASSET_MAX];
} Renderer;
// ::Init::Decl::
static b32 Init(Renderer *renderer);
static b32 InitModels(Renderer *renderer);
static PipelineHandle CreatePipeline();
static VertexBuffer CreateVertexBuffer();
static IndexBuffer CreateIndexBuffer();
static VertexArray CreateVertexArray();
static ShaderHandle CreateShader(int type);
static PipelineHandle BuildPipeline(PipelineCreateInfo *create_info);
static MeshBuffer CreateMeshBuffer(char *asset);
static UBO CreateUBO(rawptr data, u32 size);
static b32 BuildShader(ShaderHandle *handle, char *asset);
// ::Draw::Decl::
static void DrawIndexedBuffer(rIndexedBuffer *buffer);
// ::Buffers::Decl::
static rIndexedBuffer rLoadModel(char *asset);
static rIndexedBuffer CreateIndexedBuffer(rawptr vert_data, u32 vcount, rawptr idx_data, u32 icount);
// ::Textures::Decl::
static u32 CreateTexture(rawptr data, u32 width, u32 height);
static u32 CreateTexture(rawptr data, u32 width, u32 height, u32 channels);
// ::Draw::Decl::
static void DrawMeshBuffer(MeshBuffer *mesh);
static void DrawMeshBuffer(rIndexedBuffer *mesh);

View File

@ -1,9 +1,25 @@
#version 460
layout (location = 0) in vec3 in_pos;
layout (location = 1) in vec4 in_color;
layout (location = 1) in vec3 in_normal;
layout (location = 2) in vec2 in_uv;
layout (location = 0) out vec4 out_color;
layout (location = 1) out vec2 out_uv;
layout (std140, location = 0) uniform Properties
{
vec4 color;
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
layout (binding = 0) uniform sampler2D albedo_texture;
layout (binding = 1) uniform sampler2D ambient_texture;
layout (binding = 2) uniform sampler2D specular_texture;
layout (binding = 3) uniform sampler2D emission_texture;
void main()
{

View File

@ -2,7 +2,7 @@
// ====== TODO: Research values here ========
// ==========================================
struct Vertex {
struct apVertex {
vec4 pos;
vec4 col;
};
@ -14,7 +14,7 @@ struct GUIVertex {
};
layout (buffer_reference, std430) readonly buffer VertexBuffer {
Vertex vertices[];
apVertex vertices[];
};
layout (set = 0, binding = 0) uniform GlobalUniform {

View File

@ -18,6 +18,9 @@ constexpr u64 HASH_SEED = 5995;
#define AlignPow2(x, b) (((x) + (b) - 1) & (~((b) - 1)))
#define IsPow2(x) ((x) != 0 && ((x) &((x) - 1)) == 0)
#define PtrAdd(ptr, add) ((rawptr)(((uintptr)ptr) + ((uintptr)add)))
#define Align(x, b) ((x / b) == 0 ? (x) : (x + (x % b)))
#define SizeOfMember(T, M) (sizeof(((T *)0)->M))
#define MakeArray(arena, type, count) (type *)(ArenaAlloc(arena, (isize)(sizeof(type)) * (isize)(count)))
#define Len(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
@ -67,24 +70,6 @@ constexpr u64 HASH_SEED = 5995;
DefIntegerImpl(def); \
DefFloatImpl(def)
#define ArrayType(T) \
typedef struct T##Array \
{ \
T *data; \
u64 length; \
} T##Array
#define PtrArrayType(T) \
typedef struct T##PtrArray \
{ \
T **data; \
u64 length; \
} T##PtrArray
#define InitArrayType(arr, arena, T, len) \
arr.data = MakeArray(arena, T, len); \
arr.length = len
// ::String8::
static b32 String8Eq(String8 l, String8 r);