454 lines
11 KiB
C++
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::
|
|
|