summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2020-08-24 00:52:48 -0400
committerAndrew Opalach <andrew@akon.city> 2020-08-24 00:52:48 -0400
commitc5ab6fd0e37cfb8c5ba65ade8eb076e980010048 (patch)
treee70c74fe46bac58449d9161378a24a8f1bf452d6 /src
downloadmauri-c5ab6fd0e37cfb8c5ba65ade8eb076e980010048.tar.gz
mauri-c5ab6fd0e37cfb8c5ba65ade8eb076e980010048.tar.bz2
mauri-c5ab6fd0e37cfb8c5ba65ade8eb076e980010048.zip
initial commit
Diffstat (limited to 'src')
-rw-r--r--src/assets.c201
-rw-r--r--src/assets.h77
-rw-r--r--src/context.c27
-rw-r--r--src/context.h32
-rw-r--r--src/context_glfw.c99
-rw-r--r--src/context_glfw.h17
-rw-r--r--src/gl.c50
-rw-r--r--src/gl.h10
-rw-r--r--src/json.c83
-rw-r--r--src/json.h17
-rw-r--r--src/log.h31
-rw-r--r--src/mauri.c26
-rw-r--r--src/objects/material.c41
-rw-r--r--src/objects/material.h13
-rw-r--r--src/objects/model.c35
-rw-r--r--src/objects/model.h18
-rw-r--r--src/objects/object.c52
-rw-r--r--src/objects/object.h46
-rw-r--r--src/objects/pass.c19
-rw-r--r--src/objects/pass.h20
-rw-r--r--src/objects/scene.c57
-rw-r--r--src/objects/scene.h42
-rw-r--r--src/texture.c124
-rw-r--r--src/texture.h53
-rw-r--r--src/util.c23
-rw-r--r--src/util.h23
26 files changed, 1236 insertions, 0 deletions
diff --git a/src/assets.c b/src/assets.c
new file mode 100644
index 0000000..c11f09f
--- /dev/null
+++ b/src/assets.c
@@ -0,0 +1,201 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "assets.h"
+#include "util.h"
+
+mri_asset_manager asset_manager;
+
+static mri_asset asset_void() {
+ return (mri_asset) {
+ .type = ASSET_VOID,
+ .size = 0,
+ .pos = 0,
+ .data = NULL,
+ .hash = 0
+ };
+}
+
+static mri_asset asset_from_path(char *path) {
+ FILE *asset_file = fopen(path, "rb");
+
+ if (asset_file == NULL) {
+ log_error("failed to open file: (%s)", path);
+ return asset_void();
+ }
+
+ mri_asset asset = {
+ .type = ASSET_FILE,
+ .size = 0,
+ .pos = 0,
+ .data = NULL,
+ .hash = djb2_hash((unsigned char *)path),
+ };
+
+ fseek(asset_file, 0, SEEK_END);
+
+ asset.size = ftell(asset_file);
+ asset.data = (unsigned char *)malloc(asset.size);
+
+ rewind(asset_file);
+
+ size_t res = fread(asset.data, 1, asset.size, asset_file);
+
+ fclose(asset_file);
+
+ if (res != asset.size) {
+ log_error("failed to read file (%s)", path);
+ free(asset.data);
+ return asset_void();
+ }
+
+ return asset;
+}
+
+static mri_asset asset_from_slice(char *path, unsigned char* begin, unsigned char *end) {
+ return (mri_asset) {
+ .type = ASSET_SLICE,
+ .size = end - begin,
+ .pos = 0,
+ .data = begin,
+ .hash = djb2_hash((unsigned char *)path)
+ };
+}
+
+static void mri_asset_manager_init() {
+ mvec_init(asset_manager.files);
+}
+
+bool mri_asset_manager_load_pkg(char *path) {
+ mri_asset_manager_init();
+
+ asset_manager.pkg = asset_from_path(path);
+
+ if (asset_manager.pkg.type == ASSET_VOID) {
+ log_error("failed to load pkg file: (%s)", path);
+ return false;
+ }
+
+ mri_str sig = read_string(asset_manager.pkg, read_value(asset_manager.pkg, int));
+
+ if (memcmp(sig.ptr, "PKGV", 4) != 0) {
+ log_error("invalid pkg file: (%s)", path);
+ return false;
+ }
+
+ int count = read_value(asset_manager.pkg, int);
+
+ mri_pkg_file *pkg_files = (mri_pkg_file *)malloc(sizeof(mri_pkg_file) * count);
+
+ for (int i = 0; i < count; i++) {
+ pkg_files[i] = (mri_pkg_file) {
+ .path = read_string(asset_manager.pkg, read_value(asset_manager.pkg, int)),
+ .length = read_value(asset_manager.pkg, unsigned int),
+ .offset = read_value(asset_manager.pkg, unsigned int)
+ };
+ }
+
+ for (int i = 0; i < count; i++) {
+ mri_pkg_file *file = &pkg_files[i];
+
+ char *pkg_path = mri_str_to_c_str(file->path);
+
+ mri_asset asset = asset_from_slice(pkg_path,
+ asset_ptr(asset_manager.pkg) + file->offset,
+ asset_ptr(asset_manager.pkg) + file->offset + file->length);
+
+ log_debug("loaded file (%s)", pkg_path);
+
+ free(pkg_path);
+
+ mvec_push(asset_manager.files, asset);
+ }
+
+ log_info("successfully loaded pkg file (%s)", path);
+
+ free(pkg_files);
+
+ return true;
+}
+
+mri_asset *mri_asset_manager_get(const char *part, mri_file_type_hint hint) {
+ int ret = 0;
+ char *path = NULL;
+
+ switch (hint) {
+ case TEXTURE:
+ ret = asprintf(&path, "materials/%s.tex", part);
+ break;
+ case SHADER:
+ ret = asprintf(&path, "shaders/%s", part);
+ break;
+ case FRAGMENT_SHADER:
+ ret = asprintf(&path, "shaders/%s.frag", part);
+ break;
+ case VERTEX_SHADER:
+ ret = asprintf(&path, "shaders/%s.vert", part);
+ break;
+ case NONE:
+ path = part;
+ break;
+ }
+
+ if (ret == -1) {
+ log_error("%s", "failed to alloc string");
+ return NULL;
+ }
+
+ unsigned long path_hash = djb2_hash((unsigned char *)path);
+
+ // true if this asset has already been loaded
+ bool asset_loaded = false;
+
+ mri_asset *asset;
+ mvec_loop_ptr(asset_manager.files, asset) {
+ if (asset->hash == path_hash) {
+ asset_loaded = true;
+ break;
+ }
+ }
+
+ if (!asset_loaded) {
+ char *asset_path;
+ int ret = asprintf(&asset_path, "assets/%s", path);
+
+ if (ret == -1) {
+ log_error("%s", "failed to alloc string");
+ return NULL;
+ }
+
+ mri_asset _asset = asset_from_path(asset_path);
+ mvec_push(asset_manager.files, _asset);
+
+ asset = &mvec_last(asset_manager.files);
+
+ free(asset_path);
+ }
+
+ if (hint != NONE) {
+ free(path);
+ }
+
+ return asset;
+}
+
+void mri_asset_unload(mri_asset *asset) {
+ if (asset->type == ASSET_FILE) {
+ free(asset->data);
+ }
+}
+
+void mri_asset_manager_unload() {
+ mri_asset *asset;
+ mvec_loop_ptr(asset_manager.files, asset) {
+ mri_asset_unload(asset);
+ }
+ mvec_free(asset_manager.files);
+ mri_asset_unload(&asset_manager.pkg);
+}
diff --git a/src/assets.h b/src/assets.h
new file mode 100644
index 0000000..cffb936
--- /dev/null
+++ b/src/assets.h
@@ -0,0 +1,77 @@
+#ifndef _ASSET_H
+#define _ASSET_H
+
+#include <stdbool.h>
+#include <moro_vec.h>
+
+#include "util.h"
+
+typedef enum {
+ ASSET_FILE,
+ ASSET_SLICE,
+ ASSET_VOID
+} mri_asset_type;
+
+typedef enum {
+ TEXTURE,
+ SHADER,
+ FRAGMENT_SHADER,
+ VERTEX_SHADER,
+ NONE
+} mri_file_type_hint;
+
+typedef struct {
+ // If this is ASSET_FILE, the data should be
+ // free'd along with this asset.
+ mri_asset_type type;
+
+ unsigned int size;
+ unsigned int pos;
+ unsigned char *data;
+
+ unsigned long hash;
+} mri_asset;
+
+typedef struct {
+ mri_str path;
+ unsigned int offset;
+ unsigned int length;
+} mri_pkg_file;
+
+typedef struct {
+ // scene.pkg of the current wallpaper
+ mri_asset pkg;
+
+ mvec(mri_asset) files;
+} mri_asset_manager;
+
+// not thread-safe
+extern mri_asset_manager asset_manager;
+
+#define asset_ptr(asset) &asset.data[asset.pos]
+#define seek(asset, n) asset.pos += n
+
+#define read_value(asset, type) ({ \
+ type val = *((type *)(asset_ptr(asset))); \
+ seek(asset, sizeof(type)); \
+ val; \
+})
+
+#define read_string(asset, n) ({ \
+ size_t _n = n; \
+ mri_str val = { \
+ .len = _n, \
+ .ptr = asset_ptr(asset) \
+ }; \
+ seek(asset, _n); \
+ val; \
+})
+
+bool mri_asset_manager_load_pkg(char *path);
+
+void mri_asset_unload(mri_asset *asset);
+void mri_asset_manager_unload();
+
+mri_asset *mri_asset_manager_get(const char *part, mri_file_type_hint hint);
+
+#endif // _ASSET_H
diff --git a/src/context.c b/src/context.c
new file mode 100644
index 0000000..292061d
--- /dev/null
+++ b/src/context.c
@@ -0,0 +1,27 @@
+#include <glad/gl.h>
+
+#include "log.h"
+#include "context.h"
+
+void print_gl_info() {
+ log_info("OpenGL loaded");
+ log_info("Vendor: %s", glGetString(GL_VENDOR));
+ log_info("Renderer: %s", glGetString(GL_RENDERER));
+ log_info("Version: %s", glGetString(GL_VERSION));
+}
+
+GLenum gl_check_error() {
+ GLenum error_code;
+ while ((error_code = glGetError()) != GL_NO_ERROR) {
+ const char *error;
+ switch (error_code) {
+ case GL_INVALID_ENUM: error = "INVALID_ENUM"; break;
+ case GL_INVALID_VALUE: error = "INVALID_VALUE"; break;
+ case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break;
+ case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break;
+ }
+ log_debug("%s", error);
+ }
+ return error_code;
+}
diff --git a/src/context.h b/src/context.h
new file mode 100644
index 0000000..a56bd7d
--- /dev/null
+++ b/src/context.h
@@ -0,0 +1,32 @@
+#ifndef _CONTEXT_H
+#define _CONTEXT_H
+
+#include <stdbool.h>
+#include <glad/gl.h>
+
+#define GL_VERSION_MAJOR 3
+#define GL_VERSION_MINOR 3
+
+typedef struct mri_context mri_context;
+
+struct mri_context {
+ int width, height;
+
+ bool (*create_window)(mri_context *, int, int, const char *, bool);
+ void (*resize_window)(mri_context *, int, int);
+
+ void (*close_window)(mri_context *);
+ bool (*should_close)(mri_context *);
+
+ void (*swap_buffers)(mri_context *);
+
+ void (*process_input)(mri_context *);
+ void (*cursor_pos)(mri_context *, float *, float *);
+
+ double (*current_time)(mri_context *);
+};
+
+void print_gl_info();
+GLenum gl_check_error();
+
+#endif // _CONTEXT_H
diff --git a/src/context_glfw.c b/src/context_glfw.c
new file mode 100644
index 0000000..639b9bc
--- /dev/null
+++ b/src/context_glfw.c
@@ -0,0 +1,99 @@
+#include <stdlib.h>
+#include <glad/gl.h>
+
+#include "log.h"
+#include "context_glfw.h"
+#include "context.h"
+
+static bool create_window(mri_context *c, int width, int height, const char *name, bool wallpaper) {
+ if (!glfwInit()) {
+ log_error("%s", "failed to init GLFW");
+ return false;
+ }
+
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, GL_VERSION_MAJOR);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, GL_VERSION_MINOR);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
+ glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_TRUE);
+
+ glfwWindowHint(GLFW_SAMPLES, 2);
+
+ c->width = width;
+ c->height = height;
+
+ GLFWwindow *window = glfwCreateWindow(width, height, name, NULL, NULL);
+
+ ((mri_glfw_context *)c)->window = window;
+
+ glfwMakeContextCurrent(window);
+
+ if (!gladLoadGL((GLADloadfunc)glfwGetProcAddress)) {
+ log_info("%s", "couldn't load opengl");
+ return false;
+ }
+
+ glEnable(GL_MULTISAMPLE);
+
+ print_gl_info();
+
+ return true;
+}
+
+static void close_window(mri_context *c) {
+ glfwSetWindowShouldClose(((mri_glfw_context *)c)->window, GLFW_TRUE);
+}
+
+static void resize_window(mri_context *c, int width, int height) {
+ c->width = width;
+ c->height = height;
+ glfwSetWindowSize(((mri_glfw_context *)c)->window, width, height);
+}
+
+static bool should_close(mri_context *c) {
+ return glfwWindowShouldClose(((mri_glfw_context *)c)->window);
+}
+
+static void cursor_pos(mri_context *c, float *x, float *y) {
+ double _x, _y;
+ glfwGetCursorPos(((mri_glfw_context *)c)->window, &_x, &_y);
+ *x = (float)_x;
+ *y = (float)_y;
+}
+
+static void swap_buffers(mri_context *c) {
+ glfwSwapBuffers(((mri_glfw_context *)c)->window);
+}
+
+static void process_input(mri_context *c) {
+ glfwPollEvents();
+}
+
+static double current_time(mri_context *c) {
+ return glfwGetTime();
+}
+
+mri_context *mri_glfw_context_new() {
+ mri_glfw_context *c = (mri_glfw_context *)malloc(sizeof(mri_glfw_context));
+ mri_glfw_context _c = {
+ ._c = {
+ .create_window = &create_window,
+ .resize_window = &resize_window,
+ .close_window = &close_window,
+ .should_close = &should_close,
+ .swap_buffers = &swap_buffers,
+ .process_input = &process_input,
+ .cursor_pos = &cursor_pos,
+ .current_time = &current_time
+ },
+ .window = NULL
+ };
+ memcpy(c, &_c, sizeof(mri_glfw_context));
+ return (mri_context *)(c);
+}
+
+void mri_glfw_context_unload(mri_context *c) {
+ glfwDestroyWindow(((mri_glfw_context *)c)->window);
+ glfwTerminate();
+ free((mri_glfw_context *)c);
+}
diff --git a/src/context_glfw.h b/src/context_glfw.h
new file mode 100644
index 0000000..f68b284
--- /dev/null
+++ b/src/context_glfw.h
@@ -0,0 +1,17 @@
+#ifndef _CONTEXT_GLFW_H
+#define _CONTEXT_GLFW_H
+
+#define GLFW_INCLUDE_NONE
+#include <GLFW/glfw3.h>
+
+#include "context.h"
+
+typedef struct {
+ mri_context _c;
+ GLFWwindow *window;
+} mri_glfw_context;
+
+mri_context *mri_glfw_context_new();
+void mri_glfw_context_unload(mri_context *c);
+
+#endif // _CONTEXT_GLFW_H
diff --git a/src/gl.c b/src/gl.c
new file mode 100644
index 0000000..4c4d23d
--- /dev/null
+++ b/src/gl.c
@@ -0,0 +1,50 @@
+#include <glad/gl.h>
+#include <stddef.h>
+
+#include "gl.h"
+#include "util.h"
+
+unsigned int create_gl_texture(bool interp, bool clamp_uv, int mm_count) {
+ unsigned int id;
+
+ glGenTextures(1, &id);
+ glBindTexture(GL_TEXTURE_2D, id);
+
+ if (interp) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ }
+
+ if (clamp_uv) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mm_count - 1);
+
+ return id;
+}
+
+void upload_gl_texture(unsigned int id, unsigned char *data, int width, int height, int level) {
+ glBindTexture(GL_TEXTURE_2D, id);
+
+ int _width = next_power_of_two(width);
+ int _height = next_power_of_two(height);
+
+ glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, _width, _height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, width, height,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+}
+
+void destroy_gl_texture(unsigned int id) {
+ glDeleteTextures(1, &id);
+}
diff --git a/src/gl.h b/src/gl.h
new file mode 100644
index 0000000..ae43abb
--- /dev/null
+++ b/src/gl.h
@@ -0,0 +1,10 @@
+#ifndef _GL_H
+#define _GL_H
+
+#include <stdbool.h>
+
+unsigned int create_gl_texture(bool interp, bool clamp_uv, int mm_count);
+void upload_gl_texture(unsigned int id, unsigned char *data, int width, int height, int level);
+void destroy_gl_texture(unsigned int id);
+
+#endif // _GL_H
diff --git a/src/json.c b/src/json.c
new file mode 100644
index 0000000..6094d4c
--- /dev/null
+++ b/src/json.c
@@ -0,0 +1,83 @@
+#include <cglm/cglm.h>
+#include <jansson.h>
+
+#include "json.h"
+#include "log.h"
+
+static json_t *json_value_user(json_t *value) {
+ if (json_is_object(value)) {
+ return json_object_get(value, "value");
+ }
+ return value;
+}
+
+void json_get_bool(bool *result, json_t *root, const char *name) {
+ json_t *value = json_value_user(json_object_get(root, name));
+ if (json_is_boolean(value)) {
+ *result = json_boolean_value(value);
+ } else {
+ *result = false;
+ log_debug("using default value for (%s)", name);
+ }
+}
+
+void json_get_int(int *result, json_t *root, const char *name) {
+ json_t *value = json_value_user(json_object_get(root, name));
+ if (json_is_integer(value)) {
+ *result = json_integer_value(value);
+ } else {
+ *result = 0;
+ log_debug("using default value for (%s)", name);
+ }
+}
+
+void json_get_float(float *result, json_t *root, const char *name) {
+ json_t *value = json_value_user(json_object_get(root, name));
+ if (json_is_number(value)) {
+ *result = json_number_value(value);
+ } else {
+ *result = 0.f;
+ log_debug("using default value for (%s)", name);
+ }
+}
+
+void json_get_vec2(vec2 *result, json_t *root, const char *name) {
+ json_t *value = json_value_user(json_object_get(root, name));
+ if (json_is_string(value)) {
+ int ret = sscanf(json_string_value(value), "%f %f", &((*result)[0]), &((*result)[1]));
+ if (ret != 2) {
+ log_debug("expected vec2 but got vec of size %i (%s)", ret, name);
+ }
+ } else {
+ memset(*result, 0, sizeof(vec2));
+ log_debug("using default value for (%s)", name);
+ }
+}
+
+void json_get_vec3(vec3 *result, json_t *root, const char *name) {
+ json_t *value = json_value_user(json_object_get(root, name));
+ if (json_is_string(value)) {
+ int ret = sscanf(json_string_value(value), "%f %f %f", &((*result)[0]),
+ &((*result)[1]), &((*result)[2]));
+ if (ret != 3) {
+ log_debug("expected vec3 but got vec of size %i (%s)", ret, name);
+ }
+ } else {
+ memset(*result, 0, sizeof(vec3));
+ log_debug("using default value for (%s)", name);
+ }
+}
+
+void json_get_vec4(vec4 *result, json_t *root, const char *name) {
+ json_t *value = json_value_user(json_object_get(root, name));
+ if (json_is_string(value)) {
+ int ret = sscanf(json_string_value(value), "%f %f %f %f", &((*result)[0]), &((*result)[1]),
+ &((*result)[2]), &((*result)[3]));
+ if (ret != 4) {
+ log_debug("expected vec4 but got vec of size %i (%s)", ret, name);
+ }
+ } else {
+ memset(*result, 0, sizeof(vec4));
+ log_debug("using default value for (%s)", name);
+ }
+}
diff --git a/src/json.h b/src/json.h
new file mode 100644
index 0000000..5d03f5a
--- /dev/null
+++ b/src/json.h
@@ -0,0 +1,17 @@
+#ifndef _JSON_H
+#define _JSON_H
+
+#include <cglm/cglm.h>
+#include <stdbool.h>
+
+#define json_array(value, array) \
+ for (size_t i = 0; i < json_array_size(array) && (value = json_array_get(array, i), 1); i++)
+
+void json_get_bool(bool *result, json_t *root, const char *name);
+void json_get_int(int *result, json_t *root, const char *name);
+void json_get_float(float *result, json_t *root, const char *name);
+void json_get_vec2(vec2 *result, json_t *root, const char *name);
+void json_get_vec3(vec3 *result, json_t *root, const char *name);
+void json_get_vec4(vec4 *result, json_t *root, const char *name);
+
+#endif // _JSON_H
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..8a5443b
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,31 @@
+#ifndef _LOG_H
+#define _LOG_H
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+
+#define PRINT(x, ...) printf(x, ##__VA_ARGS__)
+
+#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+
+#define log_print(t, fmt, ...) \
+ do \
+ { \
+ PRINT("%s:%d %s(): ", __FILENAME__, __LINE__, __FUNCTION__); \
+ PRINT("%s -> " fmt "\n", t, ##__VA_ARGS__); \
+ } \
+ while(0)
+
+#define log_info(fmt, ...) log_print("info", fmt, ##__VA_ARGS__)
+#define log_warn(fmt, ...) log_print("warn", fmt, ##__VA_ARGS__)
+#define log_error(fmt, ...) log_print("error", fmt, ##__VA_ARGS__)
+
+#ifdef _DEBUG_
+#define log_debug(fmt, ...) log_print("debug", fmt, ##__VA_ARGS__)
+#else
+#define log_debug(fmt, ...)
+#endif
+
+#endif // _LOG_H
diff --git a/src/mauri.c b/src/mauri.c
new file mode 100644
index 0000000..b7485c0
--- /dev/null
+++ b/src/mauri.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+
+#include "assets.h"
+#include "context.h"
+#include "context_glfw.h"
+#include "objects/scene.h"
+
+int main(int argc, char* argv[]) {
+ mri_context *context = mri_glfw_context_new();
+ context->create_window(context, 1600, 900, "test", false);
+
+ if (argc == 2) {
+ mri_asset_manager_load_pkg(argv[1]);
+
+ mri_scene scene = {0};
+ mri_scene_parse(&scene);
+
+ mri_scene_unload(&scene);
+ mri_asset_manager_unload();
+ }
+
+ context->close_window(context);
+ mri_glfw_context_unload(context);
+
+ return 0;
+}
diff --git a/src/objects/material.c b/src/objects/material.c
new file mode 100644
index 0000000..d01b8fe
--- /dev/null
+++ b/src/objects/material.c
@@ -0,0 +1,41 @@
+#include "material.h"
+#include "pass.h"
+
+#include "../log.h"
+#include "../json.h"
+
+void mri_material_parse(mri_material *material, json_t *value) {
+ if (json_is_string(value)) {
+ mri_asset *asset = mri_asset_manager_get(json_string_value(value), NONE);
+
+ json_error_t error;
+ json_t *root = json_loadb((char *)asset->data, asset->size, 0, &error);
+
+ if (!root) {
+ log_error("error parsing json on line %d: %s", error.line, error.text);
+ return;
+ }
+
+ mvec_init(material->passes);
+
+ json_t *pass;
+ json_t *passes = json_object_get(root, "passes");
+ json_array(pass, passes) {
+ mri_pass _pass;
+ mri_pass_parse(&_pass, pass);
+ mvec_push(material->passes, _pass);
+ }
+
+ json_decref(root);
+ } else {
+ memset(material, 0, sizeof(mri_material));
+ }
+}
+
+void mri_material_unload(mri_material *material) {
+ mri_pass *pass;
+ mvec_loop_ptr(material->passes, pass) {
+ mri_pass_unload(pass);
+ }
+ mvec_free(material->passes);
+}
diff --git a/src/objects/material.h b/src/objects/material.h
new file mode 100644
index 0000000..72b2d45
--- /dev/null
+++ b/src/objects/material.h
@@ -0,0 +1,13 @@
+#ifndef _MATERIAL_H
+#define _MATERIAL_H
+
+#include "pass.h"
+
+typedef struct {
+ mvec(mri_pass) passes;
+} mri_material;
+
+void mri_material_parse(mri_material *material, json_t *value);
+void mri_material_unload(mri_material *material);
+
+#endif // MATERIAL_H
diff --git a/src/objects/model.c b/src/objects/model.c
new file mode 100644
index 0000000..c821786
--- /dev/null
+++ b/src/objects/model.c
@@ -0,0 +1,35 @@
+#include <jansson.h>
+
+#include "../json.h"
+#include "../assets.h"
+#include "../log.h"
+
+#include "model.h"
+
+void mri_model_parse(mri_model *model, json_t *value) {
+ if (json_is_string(value)) {
+ mri_asset *asset = mri_asset_manager_get(json_string_value(value), NONE);
+
+ json_error_t error;
+ json_t *root = json_loadb((char *)asset->data, asset->size, 0, &error);
+
+ if (!root) {
+ log_error("error parsing json on line %d: %s", error.line, error.text);
+ return;
+ }
+
+ json_get_bool(&model->autosize, root, "autosize");
+ json_get_bool(&model->fullscreen, root, "fullscreen");
+ json_get_bool(&model->passthrough, root, "passthrough");
+
+ mri_material_parse(&model->material, json_object_get(root, "material"));
+
+ json_decref(root);
+ } else {
+ memset(model, 0, sizeof(mri_model));
+ }
+}
+
+void mri_model_unload(mri_model *model) {
+ mri_material_unload(&model->material);
+}
diff --git a/src/objects/model.h b/src/objects/model.h
new file mode 100644
index 0000000..e59b369
--- /dev/null
+++ b/src/objects/model.h
@@ -0,0 +1,18 @@
+#ifndef _MODEL_H
+#define _MODEL_H
+
+#include <jansson.h>
+
+#include "material.h"
+
+typedef struct {
+ bool autosize;
+ bool fullscreen;
+ bool passthrough;
+ mri_material material;
+} mri_model;
+
+void mri_model_parse(mri_model *model, json_t *value);
+void mri_model_unload(mri_model *model);
+
+#endif // _MODEL_H
diff --git a/src/objects/object.c b/src/objects/object.c
new file mode 100644
index 0000000..6b679a0
--- /dev/null
+++ b/src/objects/object.c
@@ -0,0 +1,52 @@
+#include <jansson.h>
+
+#include "object.h"
+#include "model.h"
+
+#include "../log.h"
+#include "../json.h"
+
+void mri_object_parse(mri_object *object, json_t *root) {
+ json_get_int(&object->id, root, "id");
+
+ json_get_float(&object->alpha, root, "alpha");
+
+ json_get_vec3(&object->angles, root, "angles");
+ json_get_vec3(&object->color, root, "color");
+
+ json_get_int(&object->color_blend_mode, root, "colorblendmode");
+
+ json_get_bool(&object->copy_background, root, "copybackground");
+
+ mvec_init(object->deps);
+
+ json_t *dep;
+ json_t *deps = json_object_get(root, "dependencies");
+ json_array(dep, deps) {
+ int value = json_integer_value(dep);
+ mvec_push(object->deps, value);
+ }
+
+ json_get_vec2(&object->size, root, "size");
+ json_get_vec3(&object->scale, root, "scale");
+ json_get_vec3(&object->origin, root, "origin");
+
+ mri_model_parse(&object->image, json_object_get(root, "image"));
+
+ json_get_bool(&object->visible, root, "visible");
+
+ //mvec_init(object->effects);
+
+ json_t *effect;
+ json_t *effects = json_object_get(root, "effects");
+ json_array(effect, effects) {
+ // parse effect
+ }
+}
+
+void mri_object_unload(mri_object *object) {
+ mvec_free(object->deps);
+ //mvec_free(object->effects);
+ mri_model_unload(&object->image);
+}
+
diff --git a/src/objects/object.h b/src/objects/object.h
new file mode 100644
index 0000000..18c0dec
--- /dev/null
+++ b/src/objects/object.h
@@ -0,0 +1,46 @@
+#ifndef _OBJECT_H
+#define _OBJECT_H
+
+#include <moro_vec.h>
+#include <jansson.h>
+#include <stdbool.h>
+#include <cglm/cglm.h>
+
+#include "model.h"
+
+typedef enum {
+ CENTER,
+} mri_object_alignment;
+
+typedef struct {
+ int id;
+ char *name;
+
+ mvec(int) deps;
+
+ mri_object_alignment alignment;
+
+ float alpha;
+
+ vec3 angles;
+ vec3 color;
+
+ int color_blend_mode;
+
+ bool copy_background;
+
+ mri_model image;
+
+ vec2 size;
+ vec3 origin;
+ vec3 scale;
+
+ bool visible;
+
+ //mvec(mri_effect) effects;
+} mri_object;
+
+void mri_object_parse(mri_object *object, json_t *root);
+void mri_object_unload(mri_object *object);
+
+#endif // _OBJECT_H
diff --git a/src/objects/pass.c b/src/objects/pass.c
new file mode 100644
index 0000000..c2107aa
--- /dev/null
+++ b/src/objects/pass.c
@@ -0,0 +1,19 @@
+#include "pass.h"
+
+#include "../json.h"
+#include "../texture.h"
+#include "../assets.h"
+
+void mri_pass_parse(mri_pass *pass, json_t *root) {
+ json_t *texture;
+ json_t *textures = json_object_get(root, "textures");
+ json_array(texture, textures) {
+ if (json_is_string(texture)) {
+ //mri_texture_load(&pass->textures[0], mri_asset_manager_get(json_string_value(texture), TEXTURE));
+ //mri_texture_unload(&pass->textures[0]);
+ }
+ }
+}
+
+void mri_pass_unload(mri_pass *pass) {
+}
diff --git a/src/objects/pass.h b/src/objects/pass.h
new file mode 100644
index 0000000..fca8bac
--- /dev/null
+++ b/src/objects/pass.h
@@ -0,0 +1,20 @@
+#ifndef _PASS_H
+#define _PASS_H
+
+#include <jansson.h>
+
+#include "../texture.h"
+
+typedef struct {
+ // mri_shader *shader;
+ // mri_material *material;
+ mri_texture textures[7];
+
+ // mvec(mri_uniform) uniforms;
+ // mvec(mri_combo) combos;
+} mri_pass;
+
+void mri_pass_parse(mri_pass *pass, json_t *root);
+void mri_pass_unload(mri_pass *pass);
+
+#endif // _PASS_H
diff --git a/src/objects/scene.c b/src/objects/scene.c
new file mode 100644
index 0000000..6b8cfce
--- /dev/null
+++ b/src/objects/scene.c
@@ -0,0 +1,57 @@
+#include <jansson.h>
+#include <moro_vec.h>
+
+#include "scene.h"
+#include "object.h"
+
+#include "../json.h"
+#include "../log.h"
+
+void mri_scene_parse(mri_scene *scene) {
+ mri_asset *scene_json = mri_asset_manager_get("scene.json", NONE);
+
+ json_error_t error;
+ json_t *root = json_loadb((char *)scene_json->data, scene_json->size, 0, &error);
+
+ if (!root) {
+ log_error("error parsing json on line %d: %s", error.line, error.text);
+ return;
+ }
+
+ json_t *camera = json_object_get(root, "camera");
+ json_t *general = json_object_get(root, "general");
+ json_t *ortho = json_object_get(general, "orthogonalprojection");
+
+ json_get_vec3(&scene->camera.center, camera, "center");
+ json_get_vec3(&scene->camera.eye, camera, "eye");
+ json_get_vec3(&scene->camera.up, camera, "up");
+
+ json_get_bool(&scene->clear_enabled, general, "clearenabled");
+
+ json_get_vec3(&scene->clear_color, general, "clearcolor");
+ json_get_vec3(&scene->ambient_color, general, "ambientcolor");
+ json_get_vec3(&scene->skylight_color, general, "skylightcolor");
+
+ json_get_float(&scene->width, ortho, "width");
+ json_get_float(&scene->height, ortho, "height");
+
+ mvec_init(scene->objects);
+
+ json_t *object;
+ json_t *objects = json_object_get(root, "objects");
+ json_array(object, objects) {
+ mri_object _object;
+ mri_object_parse(&_object, object);
+ mvec_push(scene->objects, _object);
+ }
+
+ json_decref(root);
+}
+
+void mri_scene_unload(mri_scene *scene) {
+ mri_object *object;
+ mvec_loop_ptr(scene->objects, object) {
+ mri_object_unload(object);
+ }
+ mvec_free(scene->objects);
+}
diff --git a/src/objects/scene.h b/src/objects/scene.h
new file mode 100644
index 0000000..5c7e90b
--- /dev/null
+++ b/src/objects/scene.h
@@ -0,0 +1,42 @@
+#ifndef _SCENE_H
+#define _SCENE_H
+
+#include <cglm/cglm.h>
+#include <moro_vec.h>
+
+#include "object.h"
+
+#include "../assets.h"
+
+typedef struct {
+ float width;
+ float height;
+
+ struct {
+ vec3 center;
+ vec3 eye;
+ vec3 up;
+
+ float farz;
+ float nearz;
+ float fov;
+ } camera;
+
+ bool clear_enabled;
+
+ vec3 clear_color;
+ vec3 ambient_color;
+ vec3 skylight_color;
+
+ bool bloom;
+
+ float bloom_strength;
+ float bloom_threshold;
+
+ mvec(mri_object) objects;
+} mri_scene;
+
+void mri_scene_parse(mri_scene *scene);
+void mri_scene_unload(mri_scene *scene);
+
+#endif // _SCENE_H
diff --git a/src/texture.c b/src/texture.c
new file mode 100644
index 0000000..e649bb4
--- /dev/null
+++ b/src/texture.c
@@ -0,0 +1,124 @@
+#define STB_IMAGE_IMPLEMENTATION
+#include <stb_image.h>
+#include <lz4.h>
+
+#include "util.h"
+#include "texture.h"
+#include "assets.h"
+#include "gl.h"
+#include "log.h"
+
+static unsigned char *load_image_rgba(unsigned char *data, int len) {
+ int w, h, channels;
+ return stbi_load_from_memory(data, len, &w, &h, &channels, 4);
+}
+
+void mri_texture_load(mri_texture *t, mri_asset *_asset) {
+ // check if texture was previously loaded
+
+ mri_asset asset = *_asset;
+
+ mri_str type = read_string(asset, 9);
+ mri_str itype = read_string(asset, 9);
+
+ t->format = (mri_texture_format)read_value(asset, unsigned int);
+
+ t->flags.integer = read_value(asset, unsigned int);
+
+ t->texture_width = read_value(asset, unsigned int);
+ t->texture_height = read_value(asset, unsigned int);
+
+ t->width = read_value(asset, unsigned int);
+ t->height = read_value(asset, unsigned int);
+
+ t->texture_resolution[0] = t->texture_width;
+ t->texture_resolution[1] = t->texture_height;
+ t->texture_resolution[2] = t->width;
+ t->texture_resolution[3] = t->height;
+
+ seek(asset, 4);
+
+ mri_str container = read_string(asset, 9);
+
+ int iformat = -1;
+
+ if (memcmp(container.ptr, "TEXB0003", 9) == 0) {
+ t->version = TEXB0003;
+ seek(asset, 4);
+ iformat = read_value(asset, unsigned int);
+ } else if (memcmp(container.ptr, "TEXB0002", 9) == 0) {
+ t->version = TEXB0002;
+ seek(asset, 4);
+ } else if (memcmp(container.ptr, "TEXB0001", 9) == 0) {
+ t->version = TEXB0001;
+ seek(asset, 4);
+ } else {
+ log_error("%s", "unknown texture version");
+ return;
+ }
+
+ int mm_count = read_value(asset, int);
+
+ t->texture_id = create_gl_texture(
+ t->flags.map.NO_INTERPOLATION,
+ t->flags.map.CLAMP_UV, mm_count);
+
+ for (int i = 0; i < mm_count; i++) {
+ unsigned int mwidth = read_value(asset, unsigned int);
+ unsigned int mheight = read_value(asset, unsigned int);
+
+ bool lz4_compressed = false;
+ unsigned int decompressed_byte_count = 0;
+
+ if (t->version == TEXB0002 || t->version == TEXB0003) {
+ lz4_compressed = read_value(asset, unsigned int) == 1;
+ decompressed_byte_count = read_value(asset, unsigned int);
+ }
+
+ unsigned int byte_count = read_value(asset, unsigned int);
+
+ if (!lz4_compressed) {
+ decompressed_byte_count = byte_count;
+ }
+
+ unsigned char *buffer = asset_ptr(asset);
+
+ if (lz4_compressed) {
+ char *decompressed = (char *)malloc(decompressed_byte_count);
+ LZ4_decompress_safe((char *)buffer, decompressed, byte_count, decompressed_byte_count);
+ buffer = (unsigned char *)decompressed;
+ }
+
+ if (iformat == -1) {
+ switch (t->format) {
+ case RGBA8888:
+ upload_gl_texture(t->texture_id, buffer, mwidth, mheight, i);
+ break;
+ case DXT5:
+ log_warn("%s", "DXT5 Texture");
+ break;
+ case DXT1:
+ log_warn("%s", "DXT1 Texture");
+ break;
+ default:
+ break;
+ }
+ } else {
+ unsigned char *data = load_image_rgba(buffer, decompressed_byte_count);
+ upload_gl_texture(t->texture_id, data, mwidth, mheight, i);
+ free(data);
+ }
+
+ if (lz4_compressed) {
+ free(buffer);
+ }
+
+ seek(asset, byte_count);
+ }
+}
+
+void mri_texture_unload(mri_texture *texture) {
+ destroy_gl_texture(texture->texture_id);
+}
+
+
diff --git a/src/texture.h b/src/texture.h
new file mode 100644
index 0000000..4a1411d
--- /dev/null
+++ b/src/texture.h
@@ -0,0 +1,53 @@
+#ifndef _TEXTURE_H
+#define _TEXTURE_H
+
+#include <cglm/cglm.h>
+
+#include "assets.h"
+
+typedef enum {
+ RGBA8888 = 0,
+ DXT5 = 4,
+ DXT3 = 6,
+ DXT1 = 7,
+ RG88 = 8,
+ R8 = 9
+} mri_texture_format;
+
+typedef enum {
+ TEXB0001,
+ TEXB0002,
+ TEXB0003
+} mri_texture_version;
+
+typedef struct {
+ bool NO_INTERPOLATION:1;
+ bool CLAMP_UV:1;
+ bool IS_GIF:1;
+ unsigned int UNKNWON: 29;
+} mri_texture_flags;
+
+typedef struct {
+ int width, height;
+ int texture_width, texture_height;
+
+ // opengl specific
+ unsigned int texture_id;
+
+ vec4 texture_resolution;
+
+ //char *combo;
+
+ union {
+ mri_texture_flags map;
+ unsigned int integer;
+ } flags;
+
+ mri_texture_format format;
+ mri_texture_version version;
+} mri_texture;
+
+void mri_texture_load(mri_texture *t, mri_asset *_asset);
+void mri_texture_unload(mri_texture *texture);
+
+#endif // _TEXTURE_H
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..d637856
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,23 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "util.h"
+
+char *mri_str_to_c_str(mri_str str) {
+ char *c_str = (char *)malloc(str.len + 1);
+ memcpy(c_str, str.ptr, str.len);
+ c_str[str.len] = '\0';
+ return c_str;
+}
+
+// http://www.cse.yorku.ca/~oz/hash.html
+unsigned long djb2_hash(unsigned char *str) {
+ unsigned long hash = 5381;
+ int c;
+
+ while ((c = *str++))
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..dc56464
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,23 @@
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#include <stddef.h>
+
+typedef struct {
+ size_t len;
+ unsigned char *ptr;
+} mri_str;
+
+char *mri_str_to_c_str(mri_str str);
+unsigned long djb2_hash(unsigned char *str);
+
+static inline ptrdiff_t next_power_of_two(ptrdiff_t n) {
+ n--;
+ n |= n >> 1;
+ n |= n >> 2;
+ n |= n >> 4;
+ n |= n >> 8;
+ return ++n;
+}
+
+#endif // _UTIL_H