diff --git a/.ignore b/.ignore index 20d49d3..8c8c7b5 100644 --- a/.ignore +++ b/.ignore @@ -1,3 +1,4 @@ +.git external assets build diff --git a/src/assets.cpp b/src/assets.cpp index e5eba1f..f890d48 100644 --- a/src/assets.cpp +++ b/src/assets.cpp @@ -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); } diff --git a/src/assets.h b/src/assets.h index 04d8881..cb2c39f 100644 --- a/src/assets.h +++ b/src/assets.h @@ -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); diff --git a/src/base_types.h b/src/base_types.h index c1426f4..4e7242a 100644 --- a/src/base_types.h +++ b/src/base_types.h @@ -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; }; diff --git a/src/packer.cpp b/src/packer.cpp index 2db67e3..fa4a483 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -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"); } } diff --git a/src/renderer.cpp b/src/renderer.cpp index 28de5da..585afe3 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -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); diff --git a/src/renderer.h b/src/renderer.h index a483867..fbdeb9e 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -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); diff --git a/src/shaders/pbr.vert.glsl b/src/shaders/pbr.vert.glsl index 270d7b2..8bb64e7 100644 --- a/src/shaders/pbr.vert.glsl +++ b/src/shaders/pbr.vert.glsl @@ -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() { diff --git a/src/shaders/structures.glsl b/src/shaders/structures.glsl index 3ff86a9..29570bd 100644 --- a/src/shaders/structures.glsl +++ b/src/shaders/structures.glsl @@ -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 { diff --git a/src/util.h b/src/util.h index fce84d7..30b34c9 100644 --- a/src/util.h +++ b/src/util.h @@ -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);