diff options
| author | 2020-08-24 00:52:48 -0400 | |
|---|---|---|
| committer | 2020-08-24 00:52:48 -0400 | |
| commit | c5ab6fd0e37cfb8c5ba65ade8eb076e980010048 (patch) | |
| tree | e70c74fe46bac58449d9161378a24a8f1bf452d6 /src | |
| download | mauri-c5ab6fd0e37cfb8c5ba65ade8eb076e980010048.tar.gz mauri-c5ab6fd0e37cfb8c5ba65ade8eb076e980010048.tar.bz2 mauri-c5ab6fd0e37cfb8c5ba65ade8eb076e980010048.zip | |
initial commit
Diffstat (limited to 'src')
| -rw-r--r-- | src/assets.c | 201 | ||||
| -rw-r--r-- | src/assets.h | 77 | ||||
| -rw-r--r-- | src/context.c | 27 | ||||
| -rw-r--r-- | src/context.h | 32 | ||||
| -rw-r--r-- | src/context_glfw.c | 99 | ||||
| -rw-r--r-- | src/context_glfw.h | 17 | ||||
| -rw-r--r-- | src/gl.c | 50 | ||||
| -rw-r--r-- | src/gl.h | 10 | ||||
| -rw-r--r-- | src/json.c | 83 | ||||
| -rw-r--r-- | src/json.h | 17 | ||||
| -rw-r--r-- | src/log.h | 31 | ||||
| -rw-r--r-- | src/mauri.c | 26 | ||||
| -rw-r--r-- | src/objects/material.c | 41 | ||||
| -rw-r--r-- | src/objects/material.h | 13 | ||||
| -rw-r--r-- | src/objects/model.c | 35 | ||||
| -rw-r--r-- | src/objects/model.h | 18 | ||||
| -rw-r--r-- | src/objects/object.c | 52 | ||||
| -rw-r--r-- | src/objects/object.h | 46 | ||||
| -rw-r--r-- | src/objects/pass.c | 19 | ||||
| -rw-r--r-- | src/objects/pass.h | 20 | ||||
| -rw-r--r-- | src/objects/scene.c | 57 | ||||
| -rw-r--r-- | src/objects/scene.h | 42 | ||||
| -rw-r--r-- | src/texture.c | 124 | ||||
| -rw-r--r-- | src/texture.h | 53 | ||||
| -rw-r--r-- | src/util.c | 23 | ||||
| -rw-r--r-- | src/util.h | 23 |
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 = ¤t_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 |