// ::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:: #ifndef BUILD_PACKER u8 ASSET_PACK[] = { #embed "../build/assets.sgp" }; #else u8 ASSET_PACK[] = {}; #endif static FileHeader File_Header = {0}; static AssetFile Asset_Info[ASSET_MAX]; static Asset Asset_Data[ASSET_MAX]; static b32 ASSET_HEADER_LOADED = false; // ::Assets::Global::End:: // ::Assets::Init::Functions::Start:: static void apInit() { MemCpy(&File_Header, ASSET_PACK, sizeof(FileHeader)); Assert(File_Header.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic value is incorrect"); Assert(File_Header.version == FILE_VERSION, "Asset file version mismatch"); MemCpy(Asset_Info, &ASSET_PACK[File_Header.asset_offset], sizeof(AssetFile) * File_Header.asset_counts); ASSET_HEADER_LOADED = true; } // ::Assets::Init::Functions::End:: // ::Assets::Loading::Functions::Start:: static Asset * apAssetSearch(u64 hash) { Asset *asset = NULL; for (u64 i = 0; i < ASSET_MAX; i++) { if (asset == NULL && Asset_Data[i].hash == 0) { asset = Asset_Data + i; } if (hash == Asset_Data[i].hash) { asset = Asset_Data + i; break; } } return asset; } static Asset apLoadWithHash(u64 hash) { if (!ASSET_HEADER_LOADED) { apInit(); } Asset *asset = apAssetSearch(hash); AssetFile file_info = {0}; if (asset->bytes == NULL) { for (u64 i = 0; i < ASSET_MAX; i++) { if (hash == Asset_Info[i].hash) { file_info = Asset_Info[i]; break; } } if (file_info.hash != 0) { asset->hash = hash; asset->type = file_info.type; u8 *bytes = (u8 *)malloc(file_info.len); MemCpy(bytes, &ASSET_PACK[file_info.data_offset], file_info.len); if (file_info.type == AT_MODEL) { asset->model = apParseModel(bytes); asset->model_meta = file_info.model_meta; free(bytes); } else { asset->len = file_info.len; asset->bytes = bytes; asset->texture_meta = file_info.texture_meta; } } } return *asset; } static Asset apLoad(c8 *str) { u64 hash = HashFromString(String8CStr(str)); return apLoadWithHash(hash); } static Asset apLoadS8(String8 str) { return apLoad(str.value); } static void apUnloadWithHash(u64 hash) { Asset *asset = apAssetSearch(hash); if (asset->bytes != NULL) { if (asset->type == AT_MODEL) { apFreeModel(asset->model); } else { free(asset->bytes); } asset->bytes = NULL; asset->type = AT_NONE; asset->len = 0; asset->hash = 0; } } static void apUnload(c8 *str) { u64 hash = HashFromString(String8CStr(str)); apUnloadWithHash(hash); } static void apUnloadS8(String8 str) { apUnload(str.value); } static u64 apAssetIndex(c8 *str) { return 0; } // ::Assets::Loading::Functions::End:: // ::Assets::Images::Start:: static Image apLoadImage(u8 *data, u64 len) { Image image = {0}; image.w = -1; image.h = -1; image.ch = -1; int w, h, has_ch; u8 *bytes = stbi_load_from_memory(data, len, &w, &h, &has_ch, 0); if (w <= 0 || h <= 0 || has_ch <= 0) { Printfln("apLoadImage failure: %s", stbi_failure_reason()); } else { image.data = bytes; image.w = w; image.h = h; image.ch = has_ch; } return image; } static void apFreeImage(Image *image) { if (image->data != NULL) { stbi_image_free(image->data); } } // ::Assets::Images::End:: // ::Assets::Models::Functions::Start:: static inline b32 apChkMag(u32 *magic, u32 expected) { return *magic == expected; } // TODO: parse this without the SDK static apModel * apParseModel(u8 *data) { m3d_t *m3d = m3d_load(data, NULL, NULL, NULL); Assert(m3d != NULL, "model returned is NULL"); /* Printfln("model: %s", m3d->name); Printfln("numcmap: %llu", m3d->numcmap); Printfln("numtmap: %llu", m3d->numtmap); Printfln("numtexture: %llu", m3d->numtexture); Printfln("numbone: %llu", m3d->numbone); Printfln("numvertex: %llu", m3d->numvertex); Printfln("numskin: %llu", m3d->numskin); Printfln("nummaterial: %llu", m3d->nummaterial); Printfln("numface: %llu", m3d->numface); Printfln("numvoxtype: %llu", m3d->numvoxtype); Printfln("numvoxel: %llu", m3d->numvoxel); Printfln("numshape: %llu", m3d->numshape); Printfln("numlabel: %llu", m3d->numlabel); Printfln("numaction: %llu", m3d->numaction); Printfln("numinlined: %llu", m3d->numinlined); Printfln("numextra: %llu", m3d->numextra); */ apModel *model = (apModel *)malloc(sizeof(apModel)); model->vertices.length = u64(m3d->numface * 3); model->vertices.data = (apVertex *)malloc(sizeof(apVertex) * model->vertices.length); 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_Ka: { U32ColToVec4(&model->materials.data[i].props.ambient, m3d->material[i].prop[j].value.color); } break; case m3dp_Ks: { U32ColToVec4(&model->materials.data[i].props.specular, m3d->material[i].prop[j].value.color); } break; case m3dp_Ns: { 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; u64 last = UINT64_MAX; for (u64 i = 0; i < m3d->numface; i += 1) { if (m3d->face[i].materialid != last) { last = m3d->face[i].materialid; num_meshes += 1; } } model->meshes.length = u64(num_meshes); model->meshes.data = (apMesh *)malloc(sizeof(apMesh) * num_meshes); last = UINT64_MAX; u32 current_index = 0; for (u64 i = 0, j = 0; i < m3d->numface; i += 1, j += 3) { if (last == UINT64_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->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; 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].color = m3d->vertex[m3d->face[i].vertex[0]].color; model->vertices.data[j+1].color = m3d->vertex[m3d->face[i].vertex[1]].color; model->vertices.data[j+2].color = m3d->vertex[m3d->face[i].vertex[2]].color; if (m3d->numtmap) { 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 } model->m3d = m3d; return model; } static void apFreeModel(apModel *model) { m3d_free(model->m3d); free(model->vertices.data); free(model->indices.data); free(model->meshes.data); free(model->materials.data); free(model); } // ::Assets::Models::Functions::End::