Axle/src/assets.cpp

454 lines
11 KiB
C++

// ::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::