152 lines
3.8 KiB
C
152 lines
3.8 KiB
C
/*
|
|
* This software is licensed under the terms of the MIT License.
|
|
* See COPYING for further information.
|
|
* ---
|
|
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
|
|
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
|
|
*/
|
|
|
|
#include "material.h"
|
|
|
|
#include "util.h"
|
|
#include "util/io.h"
|
|
#include "util/kvparser.h"
|
|
|
|
static char *material_path(const char *basename);
|
|
static bool material_check_path(const char *path);
|
|
static void material_load_stage1(ResourceLoadState *st);
|
|
static bool material_transfer(void *dst, void *src);
|
|
|
|
ResourceHandler material_res_handler = {
|
|
.type = RES_MATERIAL,
|
|
.typename = "material",
|
|
.subdir = MATERIAL_PATH_PREFIX,
|
|
|
|
.procs = {
|
|
.find = material_path,
|
|
.check = material_check_path,
|
|
.load = material_load_stage1,
|
|
.transfer = material_transfer,
|
|
.unload = mem_free,
|
|
},
|
|
};
|
|
|
|
static char *material_path(const char *basename) {
|
|
return try_path(MATERIAL_PATH_PREFIX, basename, MATERIAL_EXTENSION);
|
|
}
|
|
|
|
static bool material_check_path(const char *path) {
|
|
return strendswith(path, MATERIAL_EXTENSION);
|
|
}
|
|
|
|
struct mat_load_data {
|
|
PBRMaterial *mat;
|
|
|
|
union {
|
|
struct {
|
|
char *diffuse_map;
|
|
char *normal_map;
|
|
char *ambient_map;
|
|
char *roughness_map;
|
|
char *depth_map;
|
|
char *ao_map;
|
|
};
|
|
|
|
char *maps[6];
|
|
};
|
|
};
|
|
|
|
static void free_mat_load_data(struct mat_load_data *ld) {
|
|
for(int i = 0; i < ARRAY_SIZE(ld->maps); ++i) {
|
|
mem_free(ld->maps[i]);
|
|
}
|
|
|
|
mem_free(ld);
|
|
}
|
|
|
|
static void material_load_stage2(ResourceLoadState *st);
|
|
|
|
static void material_load_stage1(ResourceLoadState *st) {
|
|
SDL_RWops *rw = res_open_file(st, st->path, VFS_MODE_READ);
|
|
|
|
if(UNLIKELY(!rw)) {
|
|
log_error("VFS error: %s", vfs_get_error());
|
|
res_load_failed(st);
|
|
}
|
|
|
|
auto ld = ALLOC(struct mat_load_data);
|
|
ld->mat = ALLOC(typeof(*ld->mat), {
|
|
.diffuse_color = { 1, 1, 1 },
|
|
.ambient_color = { 1, 1, 1 },
|
|
.roughness_value = 1,
|
|
.metallic_value = 0,
|
|
.depth_scale = 0,
|
|
});
|
|
|
|
bool ok = parse_keyvalue_stream_with_spec(rw, (KVSpec[]) {
|
|
{ "diffuse_map", .out_str = &ld->diffuse_map },
|
|
{ "normal_map", .out_str = &ld->normal_map },
|
|
{ "ambient_map", .out_str = &ld->ambient_map },
|
|
{ "roughness_map", .out_str = &ld->roughness_map },
|
|
{ "depth_map", .out_str = &ld->depth_map },
|
|
{ "ao_map", .out_str = &ld->ao_map },
|
|
{ "diffuse_color", .callback = kvparser_vec3, .callback_data = ld->mat->diffuse_color },
|
|
{ "ambient_color", .callback = kvparser_vec3, .callback_data = ld->mat->ambient_color },
|
|
{ "roughness", .out_float = &ld->mat->roughness_value },
|
|
{ "metallic", .out_float = &ld->mat->metallic_value },
|
|
{ "depth_scale", .out_float = &ld->mat->depth_scale },
|
|
{ NULL },
|
|
});
|
|
|
|
SDL_RWclose(rw);
|
|
|
|
if(!ok) {
|
|
free_mat_load_data(ld);
|
|
log_error("Failed to parse material file '%s'", st->path);
|
|
res_load_failed(st);
|
|
return;
|
|
}
|
|
|
|
for(int i = 0; i < ARRAY_SIZE(ld->maps); ++i) {
|
|
if(ld->maps[i]) {
|
|
res_load_dependency(st, RES_TEXTURE, ld->maps[i]);
|
|
}
|
|
}
|
|
|
|
res_load_continue_after_dependencies(st, material_load_stage2, ld);
|
|
}
|
|
|
|
#define LOADMAP(_map_) do { \
|
|
if(ld->_map_##_map) { \
|
|
ld->mat->_map_##_map = res_get_data( \
|
|
RES_TEXTURE, ld->_map_##_map, st->flags & ~RESF_RELOAD); \
|
|
if(UNLIKELY(ld->mat->_map_##_map == NULL)) { \
|
|
log_error("%s: failed to load " #_map_ " map '%s'", st->name, ld->_map_##_map); \
|
|
free_mat_load_data(ld); \
|
|
res_load_failed(st); \
|
|
return; \
|
|
} \
|
|
} \
|
|
} while(0)
|
|
|
|
static void material_load_stage2(ResourceLoadState *st) {
|
|
struct mat_load_data *ld = st->opaque;
|
|
|
|
LOADMAP(diffuse);
|
|
LOADMAP(normal);
|
|
LOADMAP(ambient);
|
|
LOADMAP(roughness);
|
|
LOADMAP(depth);
|
|
LOADMAP(ao);
|
|
|
|
res_load_finished(st, ld->mat);
|
|
free_mat_load_data(ld);
|
|
}
|
|
|
|
static bool material_transfer(void *dst, void *src) {
|
|
PBRMaterial *mdst = dst;
|
|
PBRMaterial *msrc = src;
|
|
*mdst = *msrc;
|
|
mem_free(msrc);
|
|
return true;
|
|
}
|