diff options
Diffstat (limited to 'src/resource.c')
| -rw-r--r-- | src/resource.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/resource.c b/src/resource.c new file mode 100644 index 0000000..8a0fa6c --- /dev/null +++ b/src/resource.c @@ -0,0 +1,124 @@ +#define STB_IMAGE_IMPLEMENTATION +#include "lib/stb_image.h" +#include <assert.h> +#include "util/file.h" +#include "util/err.h" +#include "resource.h" +#include "cube.h" + +static void image_copy(unsigned int dst_size[2], rgba_data dst, unsigned int src_size[2], const rgba_data src, unsigned int off[2]) +{ + assert(off[0] + dst_size[0] <= src_size[0]); + assert(off[1] + dst_size[1] <= src_size[1]); + for (unsigned int y = 0; y < dst_size[1]; y++) + memcpy( + (char *)dst + dst_size[0]*y * 4, + (const char *)src + ((off[1] + y)*src_size[0] + off[0]) * 4, + dst_size[0]*4); +} + +static texture_id create_texture(struct texture_source *tex, struct source *src, struct draw_backend *draw) +{ + FILE *f = file_open(tex->path.str, "rb"); + if (!f) + source_error(src, tex->path.loc, "%.*s: failed to open file", PSTR(tex->path.str)); + int width, height; + void *img_data = stbi_load_from_file(f, &width, &height, nullptr, 4); + if (!img_data) + source_error(src, tex->path.loc, "%.*s: failed to load image", PSTR(tex->path.str)); + unsigned int img_size[2] = { width, height }; + texture_id id; + switch (tex->type) { + case TEXTURE_2D: + if (!draw->create_texture(tex->type, img_size, &img_data, &id)) + source_error(src, tex->path.loc, "%.*s: failed to create texture", PSTR(tex->path.str)); + break; + case TEXTURE_CUBEMAP: { + if (img_size[0] % 4) + source_error(src, tex->path.loc, "%.*s: cubemap image width is not divisible by 4", PSTR(tex->path.str)); + if (img_size[1] % 3) + source_error(src, tex->path.loc, "%.*s: cubemap image height is not divisible by 3", PSTR(tex->path.str)); + unsigned int face_size[2] = { img_size[0] / 4, img_size[1] / 3 }; + static const unsigned int coords[6][2] = { + // right, left, top, bottom, front, back + { 2, 1 }, { 0, 1 }, { 1, 0 }, { 1, 2 }, { 1, 1 }, { 1, 3 }, + }; + rgba_data faces[6]; + size_t face_len = 4 * face_size[0] * face_size[1]; + void *buffer = malloc(6 * face_len); + for (size_t i = 0; i < 6; i++) + image_copy( + face_size, + faces[i] = (char *)buffer + face_len*i, + img_size, + img_data, + (unsigned int [2]) { coords[i][0] * face_size[0], coords[i][1] * face_size[1] }); + if (!draw->create_texture(tex->type, face_size, faces, &id)) + source_error(src, tex->path.loc, "%.*s: failed to create texture", PSTR(tex->path.str)); + free(buffer); + } + } + stbi_image_free(img_data); + return id; +} + +static mesh_id create_mesh(struct mesh_source *mesh, struct source *src, struct draw_backend *draw) +{ + (void) draw; + source_error(src, mesh->path.loc, "TODO: obj loading"); +} + +#define LOAD_CACHED(what, cache_field) do { \ + what ## _id id, *p_id = nullptr; \ + map_find(&cache->cache_field, what->source.path.str, &p_id); \ + if (p_id) { \ + id = *p_id; \ + } else { \ + id = create_ ## what(&what->source, src, draw); \ + map_insert_end(&cache->cache_field, what->source.path.str, id); \ + } \ + what->id = id; \ + } while (0) + +void texture_load(struct texture *texture, struct source *src, struct draw_backend *draw, struct cache *cache) +{ + /* + texture_id id, *p_id = nullptr; + map_find(&cache->textures[tex->source.type], tex->source.path, &p_id); + if (p_id) { + id = *p_id; + } else { + id = create_texture(&tex->source, src, draw); + map_insert_end(&cache->textures[tex->source.type], tex->source.path, id); + } + free(tex->source.path.str); + tex->id = id; + */ + LOAD_CACHED(texture, textures[texture->source.type]); +} + +void mesh_load(struct mesh *mesh, struct source *src, struct draw_backend *draw, struct cache *cache) +{ + switch (mesh->source.type) { + case MESH_CUBE: + if (cache->cube_mesh.present) { + mesh->id = cache->cube_mesh.data; + } else { + if (!draw->create_mesh(sizeof cube_verts / sizeof *cube_verts, cube_verts, &mesh->id)) + eprintf("failed to create cube mesh\n"); + cache->cube_mesh.present = true; + cache->cube_mesh.data = mesh->id; + } + break; + case MESH_OBJ: + LOAD_CACHED(mesh, meshes); + break; + } +} + +void cache_free(struct cache *cache) +{ + free(cache->textures[TEXTURE_2D].ptr); + free(cache->textures[TEXTURE_CUBEMAP].ptr); + free(cache->meshes.ptr); +} |
