diff --git a/assets/test_char.m3d b/assets/models/test_char.m3d similarity index 100% rename from assets/test_char.m3d rename to assets/models/test_char.m3d diff --git a/assets/yoda.m3d b/assets/models/yoda.m3d similarity index 100% rename from assets/yoda.m3d rename to assets/models/yoda.m3d diff --git a/assets/cheesoid.png b/assets/textures/cheesoid.png similarity index 100% rename from assets/cheesoid.png rename to assets/textures/cheesoid.png diff --git a/assets/ham_smoke.png b/assets/textures/ham_smoke.png similarity index 100% rename from assets/ham_smoke.png rename to assets/textures/ham_smoke.png diff --git a/assets/hamster.png b/assets/textures/hamster.png similarity index 100% rename from assets/hamster.png rename to assets/textures/hamster.png diff --git a/assets/hog.jpg b/assets/textures/hog.jpg similarity index 100% rename from assets/hog.jpg rename to assets/textures/hog.jpg diff --git a/assets/patamon.png b/assets/textures/patamon.png similarity index 100% rename from assets/patamon.png rename to assets/textures/patamon.png diff --git a/assets/pattermon.png b/assets/textures/pattermon.png similarity index 100% rename from assets/pattermon.png rename to assets/textures/pattermon.png diff --git a/assets/purplemon.png b/assets/textures/purplemon.png similarity index 100% rename from assets/purplemon.png rename to assets/textures/purplemon.png diff --git a/src/assets.c b/src/assets.c index 2629bc7..12baff2 100644 --- a/src/assets.c +++ b/src/assets.c @@ -1,3 +1,27 @@ +// ::Assets::Constants::Start:: + +const u32 M3D_FILE = CreateMagicValue('3', 'D', 'M', 'O'); +const u32 M3D_PREVIEW = CreateMagicValue('P', 'R', 'V', 'W'); +const u32 M3D_HEAD = CreateMagicValue('H', 'E', 'A', 'D'); +const u32 M3D_END_CHUNK = CreateMagicValue('O', 'M', 'D', '3'); +const u32 M3D_ASSET = CreateMagicValue('A', 'S', 'E', 'T'); +const u32 M3D_ACTION = CreateMagicValue('A', 'C', 'T', 'N'); +const u32 M3D_COL_MAP = CreateMagicValue('C', 'M', 'A', 'P'); +const u32 M3D_TEX_MAP = CreateMagicValue('T', 'M', 'A', 'P'); +const u32 M3D_VERT = CreateMagicValue('V', 'R', 'T', 'S'); +const u32 M3D_BONE = CreateMagicValue('B', 'O', 'N', 'E'); +const u32 M3D_MAT = CreateMagicValue('M', 'T', 'R', 'L'); +const u32 M3D_PROCEDURAL = CreateMagicValue('P', 'R', 'O', 'C'); +const u32 M3D_MESH = CreateMagicValue('M', 'E', 'S', 'H'); +const u32 M3D_VOXEL_TYPE = CreateMagicValue('V', 'O', 'X', 'T'); +const u32 M3D_VOXEL_DATA = CreateMagicValue('V', 'O', 'X', 'D'); +const u32 M3D_SHAPE = CreateMagicValue('S', 'H', 'P', 'E'); +const u32 M3D_LABEL = CreateMagicValue('L', 'B', 'L', 'S'); + + +// ::Assets::Constants::Start:: + + // ::Assets::Globals::Start:: @@ -14,9 +38,13 @@ static Asset Texture_Asset_Lookup[TEXTURE_ASSET_MAX]; static AssetFile Shader_Assets[SHADER_ASSET_MAX]; static Asset Shader_Asset_Lookup[SHADER_ASSET_MAX]; +static AssetFile Model_Assets[MODEL_ASSET_MAX]; +static Asset Model_Asset_Lookup[MODEL_ASSET_MAX]; + // TODO(MA): Implement async asset handling static u32 Shader_Asset_Ref_Count[SHADER_ASSET_MAX]; static u32 Texture_Asset_Ref_Count[TEXTURE_ASSET_MAX]; +static u32 Model_Asset_Ref_Count[MODEL_ASSET_MAX]; static b32 ASSET_HEADER_LOADED = false; @@ -37,6 +65,8 @@ static void apInit() MemCpy(Shader_Assets, &ASSET_PACK[File_Header.asset_offsets[SHADER_ASSET]], sizeof(AssetFile) * File_Header.asset_counts[SHADER_ASSET]); + MemCpy(Model_Assets, &ASSET_PACK[File_Header.asset_offsets[MODEL_ASSET]], sizeof(AssetFile) * File_Header.asset_counts[MODEL_ASSET]); + ASSET_HEADER_LOADED = true; } @@ -95,6 +125,29 @@ static Asset apLoadShader(ShaderAsset asset_id) return asset; } +static Asset apLoadModel(ModelAsset asset_id) +{ + if (!ASSET_HEADER_LOADED) + { + apInit(); + } + + Assert(asset_id < MODEL_ASSET_MAX, "apLoadModel failure: asset_id is higher than MODEL_ASSET_MAX"); + + Asset asset = Model_Asset_Lookup[asset_id]; + if (asset.bytes == NULL) + { + AssetFile *asset_info = Model_Assets + asset_id; + + asset.bytes = FLMemAlloc(asset_info->len); + MemCpy(asset.bytes, &ASSET_PACK[asset_info->data_offset], asset_info->len); + asset.len = asset_info->len; + Model_Asset_Lookup[asset_id] = asset; + } + + return asset; +} + static TextureAssetMeta apGetTextureMeta(TextureAsset asset_id) { AssetFile *asset_file = Texture_Assets + asset_id; @@ -123,4 +176,63 @@ static void apUnloadShader(ShaderAsset asset_id) } } +static void apUnloadModel(ModelAsset asset_id) +{ + Asset *asset = Model_Asset_Lookup + asset_id; + if (asset->bytes != NULL) + { + FLMemFree(asset->bytes); + asset->bytes = NULL; + asset->len = 0; + } +} + // ::Assets::Loading::Functions::End:: + + + +// ::Assets::Models::Functions::Start:: + +static inline b32 apChkMag(u32 *magic, u32 expected) +{ + return *magic == expected; +} + +// TODO: parse this without the SDK +static m3dModel *apParseModel(rawptr data) +{ + m3d_t *m3d = m3d_load(data, NULL, NULL, NULL); + + m3dModel *model = FLMemAlloc(sizeof(m3dModel)); + model->v_count = u64(m3d->numvertex); + model->vertices = FLMemAlloc(sizeof(Vertex) * model->v_count); + + for (u64 i = 0; i < m3d->numvertex; i += 1) + { + model->vertices[i].pos.x = m3d->vertex[i].x; + model->vertices[i].pos.y = m3d->vertex[i].y; + model->vertices[i].pos.z = m3d->vertex[i].z; + model->vertices[i].pos.w = m3d->vertex[i].w; + + model->vertices[i].col.r = 0.0f; + model->vertices[i].col.g = 1.0f; + model->vertices[i].col.b = 0.0f; + model->vertices[i].col.a = 0.0f; + } + + model->i_count = u64(m3d->numface * 3); + model->indices = FLMemAlloc(sizeof(u32) * model->i_count); + + for (u64 i = 0; i < m3d->numface; i += 1) + { + model->indices[i] = m3d->face[i].vertex[0]; + model->indices[i+1] = m3d->face[i].vertex[1]; + model->indices[i+2] = m3d->face[i].vertex[2]; + } + + m3d_free(m3d); + + return model; +} + +// ::Assets::Models::Functions::End:: diff --git a/src/assets.h b/src/assets.h index 4524d50..1c6ccaa 100644 --- a/src/assets.h +++ b/src/assets.h @@ -59,6 +59,9 @@ typedef enum SoundAssetTag_e : u32 typedef enum ModelAsset_e : u32 { + MODEL_YODA, + MODEL_BLOCK_CHAR, + MODEL_ASSET_MAX, } ModelAsset; @@ -123,12 +126,18 @@ static void apInit(); static Asset apLoadTexture(TextureAsset asset_id); static Asset apLoadShader(ShaderAsset asset_id); +static Asset apLoadModel(ModelAsset asset_id); static TextureAssetMeta apGetTextureMeta(TextureAsset asset_id); static void apUnloadTexture(TextureAsset asset_id); static void apUnloadShader(ShaderAsset asset_id); +static void apUnloadModel(ModelAsset asset_id); // ::Assets::Util::Functions::Header:: // TODO(MA): Implement async asset handling static inline b32 apMarkUnloaded(AssetType type, u32 index); static inline void apMarkLoaded(AssetType type, u32 index); + +// ::Assets::Models::Functions::Header:: + +static m3dModel *apParseModel(rawptr data); diff --git a/src/entry_linux.h b/src/entry_linux.h index e46b2a5..0f986cb 100644 --- a/src/entry_linux.h +++ b/src/entry_linux.h @@ -24,7 +24,6 @@ #include "stb/stb_image.h" #include "xxhash/xxhash.h" #include "fastlz/fastlz.h" -#include "m3d/m3d.h" #include "renderer.h" #include "game.h" diff --git a/src/packer.c b/src/packer.c index f304732..2074b6c 100644 --- a/src/packer.c +++ b/src/packer.c @@ -42,8 +42,14 @@ const FileMapping g_Texture_File_Map[] = { { .file_name = "hog.jpg", .ix = HOG }, }; +const FileMapping g_Model_File_Map[] = { + { .file_name = "yoda.m3d", .ix = MODEL_YODA }, + { .file_name = "test_char.m3d", .ix = MODEL_BLOCK_CHAR }, +}; + c8 *g_Shader_File_Names[SHADER_ASSET_MAX] = {0}; c8 *g_Texture_File_Names[TEXTURE_ASSET_MAX] = {0}; +c8 *g_Model_File_Names[MODEL_ASSET_MAX] = {0}; // ::Packer::Globals::End:: @@ -74,6 +80,17 @@ void SetArrayLookups() { Assert(g_Texture_File_Names[i] != NULL, "Texture file name is null"); } + + for (i32 i = 0; i < Len(g_Model_File_Map); i++) + { + FileMapping file_mapping = g_Model_File_Map[i]; + g_Model_File_Names[file_mapping.ix] = file_mapping.file_name; + } + + for (int i = 0; i < MODEL_ASSET_MAX; i++) + { + Assert(g_Model_File_Names[i] != NULL, "Model file name is null"); + } } i32 WriteHeader(pFile file, FileHeader *header) @@ -101,14 +118,40 @@ void MoveToShaderDir(c8 **return_dir) void MoveToTextureDir(c8 **return_dir) { - if (pDirIsVisible("assets")) + if (pDirIsVisible("textures")) { - Assert(pDirNavigate("./assets") == 0, "Unable to change to assets directory"); + Assert(pDirNavigate("./textures") == 0, "Unable to change to textures directory"); *return_dir = ".."; } + else if (pDirIsVisible("assets")) + { + Assert(pDirNavigate("./assets/textures") == 0, "Unable to change to assets directory"); + *return_dir = "../.."; + } else if (pDirIsVisible("shaders")) { - Assert(pDirNavigate("../assets") == 0, "Unable to change to assets directory"); + Assert(pDirNavigate("../assets/textures") == 0, "Unable to change to assets directory"); + *return_dir = "../build"; + } + else + Assert(false, "Unable to find assets directory"); +} + +void MoveToModelDir(c8 **return_dir) +{ + if (pDirIsVisible("models")) + { + Assert(pDirNavigate("./models") == 0, "Unable to change to models directory"); + *return_dir = ".."; + } + else if (pDirIsVisible("assets")) + { + Assert(pDirNavigate("./assets/models") == 0, "Unable to change to assets directory"); + *return_dir = "../.."; + } + else if (pDirIsVisible("shaders")) + { + Assert(pDirNavigate("../assets/models") == 0, "Unable to change to assets directory"); *return_dir = "../build"; } else @@ -228,7 +271,7 @@ void PackFiles(Arena *arena, FileHeader *header) } u64 loaded_length = u64(w * h * ch); - + u64 prev_offset = data_offset; data_offset += pFileWrite(file, data_offset, image_bytes, loaded_length); @@ -245,8 +288,36 @@ void PackFiles(Arena *arena, FileHeader *header) pFileClose(asset_file); } + Assert(pDirNavigate(return_dir) == 0, "Unable to return to previous directory"); + MoveToModelDir(&return_dir); + + AssetFile *model_assets = MakeArray(arena, AssetFile, MODEL_ASSET_MAX); + for (u32 i = 0; i < MODEL_ASSET_MAX; i++) + { + c8 *asset_name = g_Model_File_Names[i]; + + Printfln("Packing file: %s...", asset_name); + + pFile asset_file = pFileOpen(asset_name, pFS_READ); + u64 file_size = pFileLength(asset_file); + + u8 *file_data = MakeArray(arena, u8, file_size); + pFileRead(asset_file, 0, file_data, file_size); + + u64 prev_offset = data_offset; + data_offset += pFileWrite(file, data_offset, file_data, file_size); + + Assert((data_offset - prev_offset) == file_size, "File write size invalid"); + + model_assets[i].data_offset = prev_offset; + model_assets[i].len = file_size; + + pFileClose(asset_file); + } + pFileWrite(file, header->asset_offsets[SHADER_ASSET], shader_assets, sizeof(AssetFile)*SHADER_ASSET_MAX); pFileWrite(file, header->asset_offsets[TEXTURE_ASSET], texture_assets, sizeof(AssetFile)*TEXTURE_ASSET_MAX); + pFileWrite(file, header->asset_offsets[MODEL_ASSET], model_assets, sizeof(AssetFile)*MODEL_ASSET_MAX); pDirNavigate(return_dir); } @@ -262,7 +333,6 @@ static inline void TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *fi pFile asset_file = pFileOpen(file_name, pFS_READ); u64 size = pFileLength(asset_file); - u8 *file_data = MakeArray(arena, u8, size); u64 write_count = pFileRead(asset_file, 0, file_data, size); Assert(write_count == size, "Incorrect asset size retrieved"); @@ -356,6 +426,14 @@ void TestAssetPack(Arena *arena) { TestAssetIsCorrect(arena, g_Texture_File_Names[i], &files[TEXTURE_ASSET][i], TEXTURE_ASSET, file); } + + pDirNavigate(return_dir); + MoveToModelDir(&return_dir); + + for (u32 i = 0; i < MODEL_ASSET_MAX; i++) + { + TestAssetIsCorrect(arena, g_Model_File_Names[i], &files[MODEL_ASSET][i], MODEL_ASSET, file); + } } // ::Packer::Tests::Functions::End:: diff --git a/src/packer.h b/src/packer.h index a33ac44..9259b28 100644 --- a/src/packer.h +++ b/src/packer.h @@ -14,6 +14,8 @@ #define STB_IMAGE_IMPLEMENTATION +#define M3D_IMPLEMENTATION + #include "shared_types.h" #include "platform/platform.h" #include "util.h" @@ -26,6 +28,7 @@ #include "stb/stb_image.h" #include "xxhash/xxhash.h" #include "fastlz/fastlz.h" +#include "m3d/m3d.h" #include "renderer.h" #include "game.h" @@ -53,6 +56,7 @@ i32 WriteHeader(pFile file, FileHeader *header); void PackFiles(Arena *arena, FileHeader *header); void MoveToTextureDir(c8 **return_dir); void MoveToShaderDir(c8 **return_dir); +void MoveToModelDir(c8 **return_dir); // ::Packer::Tests::Functions::Header:: diff --git a/src/shared_types.h b/src/shared_types.h index 41f7dd6..e64985d 100644 --- a/src/shared_types.h +++ b/src/shared_types.h @@ -141,3 +141,16 @@ typedef f64 dMat2[4]; typedef f64 dMat3[9]; typedef f64 dMat4[16]; +typedef struct Vertex +{ + Vec4 pos; + Vec4 col; +} Vertex; + +typedef struct m3dModel +{ + Vertex *vertices; + u32 *indices; + u64 v_count; + u64 i_count; +} m3dModel; diff --git a/src/vulkan_config.c b/src/vulkan_config.c index cb31429..5635add 100644 --- a/src/vulkan_config.c +++ b/src/vulkan_config.c @@ -465,10 +465,10 @@ VkVertexInputAttributeDescription pbr_input_descriptions[] = { { .binding = 1, .location = 1, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(rPBRVertex, col) }, }; -VkPipelineVertexInputStateCreationInfo pbr_vertex_input_info = { +VkPipelineVertexInputStateCreateInfo pbr_vertex_input_info = { .sType = STYPE(PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO), .vertexBindingDescriptionCount = 1, - .pVertexBindingDescriptions = &pbr_vertex_bind_desc, + .pVertexBindingDescriptions = &pbr_input_bind_desc, .vertexAttributeDescriptionCount = Len(pbr_input_descriptions), .pVertexAttributeDescriptions = pbr_input_descriptions, };