summaryrefslogtreecommitdiff
path: root/src/resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resource.c')
-rw-r--r--src/resource.c124
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);
+}