k4/src/loaders.inc

348 lines
8.8 KiB
PHP
Raw Normal View History

2025-01-19 17:29:52 +02:00
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;
}