static int matloader(void *ud, struct ResManRes *res) { char namebuf[256] = {}; snprintf(namebuf, sizeof(namebuf), "assets/mdl/%s.lua", res->name); struct k3Mat *mat = _mm_malloc(sizeof(*mat), 16); luaapi_fillmaterial(namebuf, mat); res->thing = mat; return 1; } static int mdlloader(void *ud, struct ResManRes *res) { char buf[256]; snprintf(buf, sizeof(buf), "assets/mdl/%s.k3m", res->name); FILE *f = fopen(buf, "rb"); struct { uint32_t magic; uint32_t vertCount; uint32_t indCount; uint8_t boneCount; uint8_t flags; uint16_t animCount; } header; fread(&header, 4, 4, f); int colorsEnabled = header.flags & 1; mat4 *invBind = _mm_malloc(sizeof(*invBind) * header.boneCount, 16); fread(invBind, sizeof(*invBind), header.boneCount, f); uint8_t *boneParents = malloc(header.boneCount); fread(boneParents, 1, header.boneCount, f); vec3 *pos = malloc(sizeof(*pos) * header.vertCount); fread(pos, sizeof(vec3), header.vertCount, f); uint8_t *nrm = malloc(3 * header.vertCount); fread(nrm, 3, header.vertCount, f); float *uvs = malloc(8 * header.vertCount); fread(uvs, 8, header.vertCount, f); uint8_t *boneIDs = malloc(4 * header.vertCount); fread(boneIDs, 4, header.vertCount, f); uint16_t *boneWeights = malloc(8 * header.vertCount); fread(boneWeights, 8, header.vertCount, f); uint8_t *cols = NULL; if(colorsEnabled) { cols = malloc(4 * header.vertCount); fread(cols, 4, header.vertCount, f); } uint16_t *inds = malloc(sizeof(*inds) * header.indCount); fread(inds, sizeof(uint16_t), header.indCount, f); struct k3Mdl *mdl = k3MdlCreate(header.vertCount, header.indCount, header.boneCount, pos, nrm, uvs, cols, boneIDs, boneWeights, inds, invBind, boneParents); k3MdlSetDebugName(mdl, res->name); free(pos); free(nrm); free(uvs); free(inds); uint16_t meshes; fread(&meshes, sizeof(uint16_t), 1, f); for(uint32_t i = 0; i < meshes; i++) { uint16_t startnum[2]; fread(startnum, sizeof(uint16_t), 2, f); char buf[256] = {}; for(int c = 0; c < sizeof(buf) - 1; c++) { fread(buf + c, 1, 1, f); if(buf[c] == 0) { break; } } k3MdlAddMesh(mdl, resman_ref(RESMAN_MATERIAL, buf), startnum[0], startnum[1]); } for(size_t i = 0; i < header.animCount; i++) { struct { uint16_t id; uint16_t frames; uint16_t fps; uint16_t zero; } info; fread(&info, sizeof(info), 1, f); struct k3Animation *anim = malloc(sizeof(*anim)); anim->frames = _mm_malloc(sizeof(*anim->frames) * info.frames * header.boneCount, 16); anim->boneParents = boneParents; anim->invBind = invBind; anim->id = info.id; anim->fps = info.fps; anim->frameCount = info.frames; anim->boneCount = header.boneCount; fread(anim->frames, sizeof(*anim->frames), info.frames * header.boneCount, f); k3MdlAddAnim(mdl, anim); } fclose(f); res->thing = mdl; return 1; } static int physloader(void *ud, struct ResManRes *res) { char namebuf[256]; snprintf(namebuf, sizeof(namebuf), "assets/phys/%s.phys", res->name); FILE *p = fopen(namebuf, "rb"); if(!p) return 0; dTriMeshDataID trid = dGeomTriMeshDataCreate(); fseek(p, 0, SEEK_END); size_t len = ftell(p); assert(len % 36 == 0); fseek(p, 0, SEEK_SET); float *data = malloc(len); fread(data, 1, len, p); int *idxs = malloc(sizeof(*idxs) * (len / sizeof(vec3))); for(int i = 0; i < len / sizeof(vec3); i++) idxs[i] = i; dGeomTriMeshDataBuildSingle(trid, data, sizeof(vec3), len / sizeof(vec3), idxs, len / sizeof(vec3), 3 * sizeof(int)); fclose(p); struct TrimeshData *ret = malloc(sizeof(*ret)); ret->vdata = data; ret->idata = idxs; ret->trid = trid; res->thing = ret; return 1; } static int binloader(void *ud, struct ResManRes *res) { char namebuf[256]; snprintf(namebuf, sizeof(namebuf), "assets/%s", res->name); FILE *f = fopen(namebuf, "rb"); if(!f) return 0; fseek(f, 0, SEEK_END); size_t len = ftell(f); struct ResManBin *data = malloc(sizeof(*data) + len + 1); fseek(f, 0, SEEK_SET); fread(data->data, 1, len, f); data->data[len] = 0; data->length = len; fclose(f); res->thing = data; return 1; } static void binunloader(void *ud, const char *name, void *data) { free(data); } static int streamloader(void *ud, struct ResManRes *res) { char namebuf[256]; snprintf(namebuf, sizeof(namebuf), "assets/aud/%s", res->name); res->thing = k3MixSourceFile(namebuf); return 1; } static int refresh_texture(struct ResManRes *res) { if(strlen(res->name) < 8) return 0; const char *suffix = res->name + strlen(res->name) - 8; if(!strcmp(suffix, ".cub.png")) { char namebuf[256]; int w, h, origN; unsigned char *data; struct k3Tex *tex = res->thing; if(!tex) { tex = k3TexCreate(k3_CUBEMAP); } snprintf(namebuf, sizeof(namebuf), "assets/mdl/%.*s.nx.png", suffix - res->name, res->name); data = stbi_load(namebuf, &w, &h, &origN, 4); k3TexUpdate(tex, k3_DIFFUSE, 1, w, h, data); stbi_image_free(data); snprintf(namebuf, sizeof(namebuf), "assets/mdl/%.*s.px.png", suffix - res->name, res->name); data = stbi_load(namebuf, &w, &h, &origN, 4); k3TexUpdate(tex, k3_DIFFUSE, 0, w, h, data); stbi_image_free(data); snprintf(namebuf, sizeof(namebuf), "assets/mdl/%.*s.py.png", suffix - res->name, res->name); data = stbi_load(namebuf, &w, &h, &origN, 4); k3TexUpdate(tex, k3_DIFFUSE, 2, w, h, data); stbi_image_free(data); snprintf(namebuf, sizeof(namebuf), "assets/mdl/%.*s.ny.png", suffix - res->name, res->name); data = stbi_load(namebuf, &w, &h, &origN, 4); k3TexUpdate(tex, k3_DIFFUSE, 3, w, h, data); stbi_image_free(data); snprintf(namebuf, sizeof(namebuf), "assets/mdl/%.*s.nz.png", suffix - res->name, res->name); data = stbi_load(namebuf, &w, &h, &origN, 4); k3TexUpdate(tex, k3_DIFFUSE, 5, w, h, data); stbi_image_free(data); snprintf(namebuf, sizeof(namebuf), "assets/mdl/%.*s.pz.png", suffix - res->name, res->name); data = stbi_load(namebuf, &w, &h, &origN, 4); k3TexUpdate(tex, k3_DIFFUSE, 4, w, h, data); stbi_image_free(data); res->thing = tex; } else { enum k3TexType type; int n, gamma; if(!strcmp(suffix, ".alp.png")) { type = k3_ALPHA; n = 1; gamma = 0; } else if(!strcmp(suffix, ".nrm.png")) { type = k3_NORMAL; n = 4; gamma = 1; } else if(!strcmp(suffix, ".dsp.png")) { type = k3_DISPLACEMENT; n = 1; gamma = 0; } else if(!strcmp(suffix, ".emt.png")) { type = k3_EMISSION; n = 4; gamma = 1; } else if(!strcmp(suffix, ".rgh.png")) { type = k3_ROUGHNESS; n = 1; gamma = 0; } else if(!strcmp(suffix, ".dif.png")) { type = k3_DIFFUSE; n = 4; gamma = 1; } else return 0; char namebuf[256]; snprintf(namebuf, sizeof(namebuf), "assets/mdl/%s", res->name); int w, h, origN; unsigned char *data = stbi_load(namebuf, &w, &h, &origN, n); int stbifree = 1; if(TextureResolutionReduction && data) { int newW = w >> TextureResolutionReduction; int newH = h >> TextureResolutionReduction; if(newW <= 4) newW = 4; if(newH <= 4) newH = 4; unsigned char *data2 = malloc(newW * newH * n); int success = stbir_resize_uint8_generic(data, w, h, 0, data2, newW, newH, 0, n, n == 4 ? 3 : -1, 0, STBIR_EDGE_WRAP, STBIR_FILTER_DEFAULT, gamma ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR, NULL); if(success) { stbi_image_free(data); w = newW; h = newH; data = data2; stbifree = 0; } else { free(data2); } } if(!res->thing) { res->thing = k3TexCreate(type); } if(data) { k3TexUpdate(res->thing, type, 0, w, h, data); if(stbifree) { stbi_image_free(data); } else { free(data); } } } return 1; } static int refresh_textures() { for(int b = 0; b < RESMAN_BUCKETS; b++) { for(struct ResManRes *r = ResMan.buckets[b]; r; r = r->next) { if(r->type == RESMAN_TEXTURE) { refresh_texture(r); } } } } static int texloader(void *ud, struct ResManRes *res) { refresh_texture(res); return 1; } static int fontloader(void *ud, struct ResManRes *res) { FILE *fntf = fopen(res->name, "rb"); fseek(fntf, 0, SEEK_END); size_t fntfsz = ftell(fntf); fseek(fntf, 0, SEEK_SET); char *fntbuf = malloc(fntfsz); fread(fntbuf, 1, fntfsz, fntf); struct k3Font *fnt = k3FontCreate(); struct k3Tex *fnttexldr(struct k3Font *fnt, const char *name) { return resman_ref(RESMAN_TEXTURE, name); } k3FontLoad(fnt, fntbuf, fntfsz, fnttexldr); res->thing = fnt; return 1; } static void init_res_handlers() { ResMan.handlers[RESMAN_MATERIAL].loader = matloader; ResMan.handlers[RESMAN_MODEL].loader = mdlloader; ResMan.handlers[RESMAN_PHYSICS].loader = physloader; ResMan.handlers[RESMAN_BIN].loader = binloader; ResMan.handlers[RESMAN_BIN].unloader = binunloader; ResMan.handlers[RESMAN_STREAM].loader = streamloader; ResMan.handlers[RESMAN_TEXTURE].loader = texloader; ResMan.handlers[RESMAN_FONT].loader = fontloader; }