From b3f5067447bacba0b68e6cfbe3752ee0a064f5ae Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Mon, 7 Sep 2020 19:43:55 -0400 Subject: finish most of the core stuff --- src/assets.c | 149 +++++++++++-------------- src/assets.h | 33 +++--- src/context.h | 6 +- src/context_glfw.c | 12 +- src/engine.c | 175 ++++++++++++++++++++++++++++++ src/engine.h | 72 ++++++++++++ src/gl.c | 212 +++++++++++++++++++++++++++++++++--- src/gl.h | 55 +++++++++- src/json.c | 41 +++---- src/json.h | 9 +- src/log.h | 2 - src/mauri.c | 15 ++- src/objects/effect.c | 59 ++++++++++ src/objects/effect.h | 18 +++ src/objects/material.c | 38 ++++--- src/objects/material.h | 7 ++ src/objects/model.c | 17 +-- src/objects/model.h | 8 +- src/objects/object.c | 82 ++++++++++++-- src/objects/object.h | 19 +++- src/objects/pass.c | 212 ++++++++++++++++++++++++++++++++++-- src/objects/pass.h | 26 +++-- src/objects/scene.c | 30 +++-- src/objects/scene.h | 6 +- src/objects/types.h | 11 ++ src/shader.c | 289 +++++++++++++++++++++++++++++++++---------------- src/shader.h | 32 +++--- src/texture.c | 108 ++++++++++++------ src/texture.h | 16 ++- src/util.c | 8 +- src/util.h | 17 --- 31 files changed, 1396 insertions(+), 388 deletions(-) create mode 100644 src/engine.c create mode 100644 src/engine.h create mode 100644 src/objects/effect.c create mode 100644 src/objects/effect.h create mode 100644 src/objects/types.h (limited to 'src') diff --git a/src/assets.c b/src/assets.c index 309aaa0..013b3e5 100644 --- a/src/assets.c +++ b/src/assets.c @@ -1,5 +1,3 @@ -#define _GNU_SOURCE - #include #include @@ -9,152 +7,142 @@ 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_void = { + .type = ASSET_VOID, + .size = 0, + .pos = 0, + .data = NULL, + .hash = 0 +}; -static mri_asset asset_from_slice(char *path, unsigned char* begin, unsigned char *end) { +static mri_asset asset_from_slice(mstr *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) + .hash = mstr_hash(path) }; } -static mri_asset asset_from_path(char *path) { - FILE *asset_file = fopen(path, "rb"); +static void asset_from_path(mstr *path, mri_asset *asset) { + char *path_c = mstr_to_cstr(path); + FILE *asset_file = fopen(path_c, "rb"); if (asset_file == NULL) { - log_error("failed to open file: (%s)", path); - return asset_void(); + *asset = asset_void; + free(path_c); + return; } - mri_asset asset = { - .type = ASSET_FILE, - .size = 0, - .pos = 0, - .data = NULL, - .hash = djb2_hash((unsigned char *)path), - }; + free(path_c); + + asset->type = ASSET_FILE; + asset->pos = 0; + asset->hash = mstr_hash(path); fseek(asset_file, 0, SEEK_END); - asset.size = ftell(asset_file); - asset.data = (unsigned char *)malloc(asset.size); + 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); + 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(); + if (res != asset->size) { + //log_error("failed to read file (%s)", path); + free(asset->data); + return; } - - return asset; } static void mri_asset_manager_init() { + asset_manager.pkg.type = ASSET_VOID; mvec_init(asset_manager.files); } -bool mri_asset_manager_load_pkg(char *path) { +bool mri_asset_manager_load_pkg(mstr *path) { mri_asset_manager_init(); - asset_manager.pkg = asset_from_path(path); + asset_from_path(path, &asset_manager.pkg); if (asset_manager.pkg.type == ASSET_VOID) { - log_error("failed to load pkg file: (%s)", path); + //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)); + mstr signature = mri_asset_str(&asset_manager.pkg, + mri_asset_value(&asset_manager.pkg, int)); - if (memcmp(sig.ptr, "PKGV", 4) != 0) { - log_error("invalid pkg file: (%s)", path); + if (!mstr_eqn(&signature, mstr_c("PKGV"), 4)) { + //log_error("invalid pkg file: (%.*s)", path.len, path.ptr); return false; } - int count = read_value(asset_manager.pkg, int); + int count = mri_asset_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) + .path = mri_asset_str(&asset_manager.pkg, mri_asset_value(&asset_manager.pkg, int)), + .length = mri_asset_value(&asset_manager.pkg, unsigned int), + .offset = mri_asset_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(&file->path, + mri_asset_ptr(&asset_manager.pkg) + file->offset, + mri_asset_ptr(&asset_manager.pkg) + file->offset + file->length); - 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); + //log_debug("loaded file (%.*s)", mstr_expand(&file->path)); mvec_push(asset_manager.files, asset); } - log_info("successfully loaded pkg file (%s)", path); + //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; +mri_asset *mri_asset_manager_get(mstr *part, mri_file_type_hint hint) { + mstr *path = mstr_clone(part); switch (hint) { case TEXTURE: - ret = asprintf(&path, "materials/%s.tex", part); + mstr_prepend(path, mstr_c("materials/")); + mstr_cat(path, mstr_c(".tex")); break; case SHADER: - ret = asprintf(&path, "shaders/%s", part); + mstr_prepend(path, mstr_c("shaders/")); break; case FRAGMENT_SHADER: - ret = asprintf(&path, "shaders/%s.frag", part); + mstr_prepend(path, mstr_c("shaders/")); + mstr_cat(path, mstr_c(".frag")); break; case VERTEX_SHADER: - ret = asprintf(&path, "shaders/%s.vert", part); + mstr_prepend(path, mstr_c("shaders/")); + mstr_cat(path, mstr_c(".vert")); break; case NONE: - path = part; break; } - if (ret == -1) { - log_error("%s", "failed to build string"); - return NULL; - } - - unsigned long path_hash = djb2_hash((unsigned char *)path); + unsigned long path_hash = mstr_hash(path); // true if this asset has already been loaded bool asset_loaded = false; - mri_asset *asset; - mvec_loop_ptr(asset_manager.files, asset) { + mri_asset *asset = NULL; + mvec_loop_ptr(asset_manager.files, asset, i) { if (asset->hash == path_hash) { asset_loaded = true; break; @@ -162,25 +150,16 @@ mri_asset *mri_asset_manager_get(const char *part, mri_file_type_hint hint) { } 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; + mstr_prepend(path, mstr_c("assets/")); + asset_from_path(path, mvec_next(asset_manager.files)); + asset = mvec_last(asset_manager.files); + if (asset->type == ASSET_VOID) { + mvec_pop(asset_manager.files); + asset = &asset_void; } - - 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); - } + mstr_free(path); return asset; } @@ -193,7 +172,7 @@ void mri_asset_unload(mri_asset *asset) { void mri_asset_manager_unload() { mri_asset *asset; - mvec_loop_ptr(asset_manager.files, asset) { + mvec_loop_ptr(asset_manager.files, asset, i) { mri_asset_unload(asset); } mvec_free(asset_manager.files); diff --git a/src/assets.h b/src/assets.h index 0a49bfe..5fbc995 100644 --- a/src/assets.h +++ b/src/assets.h @@ -2,7 +2,7 @@ #define _ASSET_H #include -#include +#include #include "util.h" @@ -33,7 +33,7 @@ typedef struct { } mri_asset; typedef struct { - mri_str path; + mstr path; unsigned int offset; unsigned int length; } mri_pkg_file; @@ -48,30 +48,29 @@ typedef struct { // 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 mri_asset_ptr(asset) &((asset)->data[(asset)->pos]) +#define mri_asset_seek(asset, n) (asset)->pos += n -#define read_value(asset, type) ({ \ - type val = *((type *)(asset_ptr(asset))); \ - seek((asset), sizeof(type)); \ - val; \ +#define mri_asset_value(asset, type) ({ \ + type val = *((type *)(mri_asset_ptr(asset))); \ + mri_asset_seek((asset), sizeof(type)); \ + val; \ }) -#define read_string(asset, n) ({ \ +#define mri_asset_str(a, n) ({ \ size_t _n = n; \ - mri_str val = { \ - .len = _n, \ - .ptr = asset_ptr(asset) \ - }; \ - seek((asset), _n); \ - val; \ + mstr *s = mstr_w(mri_asset_ptr(a), _n); \ + mri_asset_seek(a, _n); \ + (*s); \ }) -bool mri_asset_manager_load_pkg(char *path); +#define mri_asset_as_str(a) mstr_w(mri_asset_ptr(a), (a)->size) + +bool mri_asset_manager_load_pkg(mstr *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); +mri_asset *mri_asset_manager_get(mstr *path, mri_file_type_hint hint); #endif // _ASSET_H diff --git a/src/context.h b/src/context.h index a56bd7d..a6e4dc0 100644 --- a/src/context.h +++ b/src/context.h @@ -10,10 +10,10 @@ typedef struct mri_context mri_context; struct mri_context { - int width, height; + float width, height; - bool (*create_window)(mri_context *, int, int, const char *, bool); - void (*resize_window)(mri_context *, int, int); + bool (*create_window)(mri_context *, float, float, const char *, bool); + void (*resize_window)(mri_context *, float, float); void (*close_window)(mri_context *); bool (*should_close)(mri_context *); diff --git a/src/context_glfw.c b/src/context_glfw.c index 639b9bc..7dbb457 100644 --- a/src/context_glfw.c +++ b/src/context_glfw.c @@ -5,7 +5,7 @@ #include "context_glfw.h" #include "context.h" -static bool create_window(mri_context *c, int width, int height, const char *name, bool wallpaper) { +static bool create_window(mri_context *c, float width, float height, const char *name, bool wallpaper) { if (!glfwInit()) { log_error("%s", "failed to init GLFW"); return false; @@ -27,6 +27,7 @@ static bool create_window(mri_context *c, int width, int height, const char *nam ((mri_glfw_context *)c)->window = window; glfwMakeContextCurrent(window); + glfwSwapInterval(1); if (!gladLoadGL((GLADloadfunc)glfwGetProcAddress)) { log_info("%s", "couldn't load opengl"); @@ -35,6 +36,13 @@ static bool create_window(mri_context *c, int width, int height, const char *nam glEnable(GL_MULTISAMPLE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable(GL_CULL_FACE); + + glClear(GL_COLOR_BUFFER_BIT); + print_gl_info(); return true; @@ -44,7 +52,7 @@ 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) { +static void resize_window(mri_context *c, float width, float height) { c->width = width; c->height = height; glfwSetWindowSize(((mri_glfw_context *)c)->window, width, height); diff --git a/src/engine.c b/src/engine.c new file mode 100644 index 0000000..58350a2 --- /dev/null +++ b/src/engine.c @@ -0,0 +1,175 @@ +#include "engine.h" + +#include "objects/object.h" + +#include + +typedef enum { + BACKGROUND, + TRANSFORM, + COMBINE, + PASS +} render_pass_stage; + +static void center_scale(float w0, float h0, float w1, float h1) { + float w_scale = w1 / w0; + float h_scale = h1 / h0; + + float scale = (w_scale > h_scale) ? w_scale : h_scale; + + float width = w0 * scale; + float height = h0 * scale; + + float wpad = (width - w1) / -2.f; + float hpad = (height - h1) / -2.f; + + glViewport(wpad, hpad, width, height); +} + +static void draw_pass(mri_engine *engine, render_pass_stage s, mri_render_pass *pass, + mri_render_object *object) { + switch (s) { + case BACKGROUND: + mri_framebuffer_bind(pass->target, true); + if (object->object->passthrough) { + mri_shader_bind(engine, &pass->shader, object->model); + bind_gl_object(&object->gl_object); + } else { + mri_shader_bind(engine, &pass->shader, object->ortho); + bind_gl_object(&object->gl_uv_object); + } + break; + case PASS: + mri_framebuffer_bind(pass->target, true); + mri_shader_bind(engine, &pass->shader, NULL); + bind_gl_object(&engine->default_gl_object); + break; + case TRANSFORM: + mri_framebuffer_bind(pass->target, true); + mri_shader_bind(engine, &pass->shader, object->model); + bind_gl_object(&object->gl_object); + break; + case COMBINE: + mri_framebuffer_bind(engine->combine_buffer, false); + mri_shader_bind(engine, &pass->shader, object->model); + bind_gl_object(&object->gl_object); + break; + } + + for (int i = 0; i < pass->shader.texture_count; i++) { + if (pass->textures[i]) mri_texture_bind(pass->textures[i], i); + } + + if (s == COMBINE || (s == BACKGROUND && object->object->passthrough)) { + center_scale(engine->width, engine->height, + engine->context->width, engine->context->height); + } else { + glViewport(0, 0, pass->target->width, pass->target->height); + } + + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void mri_engine_load(mri_engine *engine) { + mvec_init(engine->objects); + + engine->texel_size[0] = 1.f / engine->width; + engine->texel_size[1] = 1.f / engine->height; + + engine->texel_half_size[0] = .5f / engine->width; + engine->texel_half_size[1] = .5f / engine->height; + + engine->combine_buffer = mri_framebuffer_load( + mstr_c("combine"), engine->context->width, engine->context->height, 1.f); + + create_gl_object(&engine->default_gl_object, DEFAULT, 0, 0); +} + +void mri_engine_next_object(mri_engine *engine, mri_object *object) { + engine->current_object = mvec_next(engine->objects); + engine->current_object->object = object; + + float width = object->size[0]; + float height = object->size[1]; + + create_gl_object(&engine->current_object->gl_uv_object, + UV_SCALE, width, height); + + create_gl_object(&engine->current_object->gl_object, + OBJECT, width, height); + + mri_object_get_model(object, engine->current_object->model, + engine->width, engine->height); + + glm_ortho(-width, width, -height, height, 0.f, 1.f, + engine->current_object->ortho); + + engine->current_object->buffer_a = mri_framebuffer_load( + mstr_c("buffer_a"), engine->width, engine->height, 1.f); + + engine->current_object->buffer_b = mri_framebuffer_load( + mstr_c("buffer_b"), engine->width, engine->height, 1.f); + + engine->current_object->buffer_switch = false; +} + +void mri_engine_next_effect(mri_engine *engine) { + engine->current_effect = mvec_next(engine->current_object->effects); + mvec_init(engine->current_effect->passes); +} + +void mri_engine_next_pass(mri_engine *engine) { + engine->current_pass = mvec_next(engine->current_effect->passes); + mvec_init(engine->current_pass->uniforms); + mvec_init(engine->current_pass->combos); +} + +void mri_engine_update(mri_engine *engine) { + engine->context->process_input(engine->context); + engine->time = engine->context->current_time(engine->context); +} + +void mri_engine_draw(mri_engine *engine) { + mri_framebuffer_bind(engine->combine_buffer, true); + + mri_render_object *object; + mvec_loop_ptr(engine->objects, object, i) { + mri_render_pass *_pass; + mvec_loop_ptr(object->background.passes, _pass, s) { + draw_pass(engine, BACKGROUND, _pass, object); + } + + mri_render_effect *effect; + mvec_loop_ptr(object->effects, effect, s) { + mri_render_pass *pass; + mvec_loop_ptr(effect->passes, pass, j) { + if (j == (mvec_size(effect->passes) - 1)) { + // last pass + draw_pass(engine, TRANSFORM, pass, object); + if (s == mvec_size(object->effects) - 1) { + // last effect + draw_pass(engine, COMBINE, pass, object); + } + } else { + draw_pass(engine, PASS, pass, object); + } + } + } + } + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, engine->combine_buffer->buffer.id); + + // Drawing past the dimensions of the read buffer is an error. + glBlitFramebuffer(0, engine->context->height, engine->context->width, 0, 0, 0, + engine->context->width, engine->context->height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); +} + +void mri_engine_run(mri_engine *engine) { + while (!engine->context->should_close(engine->context)) { + mri_engine_update(engine); + mri_engine_draw(engine); + engine->context->swap_buffers(engine->context); + } +} diff --git a/src/engine.h b/src/engine.h new file mode 100644 index 0000000..1d0a93a --- /dev/null +++ b/src/engine.h @@ -0,0 +1,72 @@ +#ifndef _ENGINE_H +#define _ENGINE_H + +#include + +#include "context.h" +#include "texture.h" +#include "shader.h" +#include "gl.h" + +#include "objects/types.h" + +typedef struct { + mri_shader shader; + mri_texture *textures[7]; + mri_framebuffer *target; + mvec(mri_uniform) uniforms; + mvec(mri_combo) combos; +} mri_render_pass; + +typedef struct { + mvec(mri_render_pass) passes; +} mri_render_effect; + +typedef struct { + mri_object *object; + + gl_object gl_uv_object; + gl_object gl_object; + + mat4 ortho; + mat4 model; + + mri_framebuffer *buffer_a; + mri_framebuffer *buffer_b; + + bool buffer_switch; + + mri_render_effect background; + + mvec(mri_render_effect) effects; +} mri_render_object; + +struct mri_engine { + mri_context *context; + + float width; + float height; + + float time; + + vec2 texel_size; + vec2 texel_half_size; + + gl_object default_gl_object; + + mri_framebuffer *combine_buffer; + + mri_render_pass *current_pass; + mri_render_effect *current_effect; + mri_render_object *current_object; + + mvec(mri_render_object) objects; +}; + +void mri_engine_load(mri_engine *engine); +void mri_engine_next_pass(mri_engine *engine); +void mri_engine_next_effect(mri_engine *engine); +void mri_engine_next_object(mri_engine *engine, mri_object *object); +void mri_engine_run(mri_engine *engine); + +#endif // _ENGINE_H diff --git a/src/gl.c b/src/gl.c index 4c4d23d..0b269f5 100644 --- a/src/gl.c +++ b/src/gl.c @@ -1,14 +1,19 @@ #include #include +#include + #include "gl.h" -#include "util.h" -unsigned int create_gl_texture(bool interp, bool clamp_uv, int mm_count) { - unsigned int id; +void bind_gl_texture(gl_texture *tex, unsigned int index) { + glActiveTexture(GL_TEXTURE0 + index); + glBindTexture(GL_TEXTURE_2D, tex->id); +} + +void create_gl_texture(gl_texture *tex, bool interp, bool clamp_uv, int mm_count) { + glGenTextures(1, &tex->id); - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_2D, id); + bind_gl_texture(tex, 0); if (interp) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -28,15 +33,13 @@ unsigned int create_gl_texture(bool interp, bool clamp_uv, int mm_count) { 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); +void upload_gl_texture(gl_texture *tex, unsigned char *data, int width, int height, int level) { + bind_gl_texture(tex, 0); - int _width = next_power_of_two(width); - int _height = next_power_of_two(height); + int _width = m_npof2(width); + int _height = m_npof2(height); glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); @@ -45,6 +48,189 @@ void upload_gl_texture(unsigned int id, unsigned char *data, int width, int heig GL_RGBA, GL_UNSIGNED_BYTE, data); } -void destroy_gl_texture(unsigned int id) { - glDeleteTextures(1, &id); +void destroy_gl_texture(gl_texture *tex) { + glDeleteTextures(1, &tex->id); +} + +void bind_gl_framebuffer(gl_framebuffer *fbo, bool clear) { + glBindFramebuffer(GL_FRAMEBUFFER, fbo->id); + if (clear) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void create_gl_framebuffer(gl_framebuffer *fbo, float width, float height) { + glGenFramebuffers(1, &fbo->id); + + glGenTextures(1, &fbo->texture.id); + glBindTexture(GL_TEXTURE_2D, fbo->texture.id); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo->id); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + fbo->texture.id, 0); + + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void destroy_gl_framebuffer(gl_framebuffer *fbo) { + glDeleteFramebuffers(1, &fbo->id); +} + +static void set_gl_object(gl_object *obj, float *vertices, int vertex_count) { + glGenVertexArrays(1, &obj->vao); + glBindVertexArray(obj->vao); + + glGenBuffers(1, &obj->vbo); + glBindBuffer(GL_ARRAY_BUFFER, obj->vbo); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)12); + + glBufferData(GL_ARRAY_BUFFER, vertex_count, vertices, GL_STATIC_DRAW); +} + +void create_gl_object(gl_object *obj, gl_obj_type type, float width, float height) { + switch (type) { + case DEFAULT: { + float vertices[] = { + -1.f, 1.f, 0.f, 0.f, 1.f, + 1.f, -1.f, 0.f, 1.f, 0.f, + -1.f, -1.f, 0.f, 0.f, 0.f, + -1.f, 1.f, 0.f, 0.f, 1.f, + 1.f, 1.f, 0.f, 1.f, 1.f, + 1.f, -1.f, 0.f, 1.f, 0.f + }; + + set_gl_object(obj, vertices, sizeof(vertices)); + break; + } + case UV_SCALE: { + // Adjust UV coords here so that on the pass where this object is loadn + // the UV cuts out the padding used to make the texture dimensions powers of two. + float x_scale = width / (float)m_npof2(width); + float y_scale = height / (float)m_npof2(height); + + float vertices[] = { + -width, height, 0.f, 0.f, y_scale, + width, -height, 0.f, x_scale, 0.f, + -width, -height, 0.f, 0.f, 0.f, + -width, height, 0.f, 0.f, y_scale, + width, height, 0.f, x_scale, y_scale, + width, -height, 0.f, x_scale, 0.f + }; + + set_gl_object(obj, vertices, sizeof(vertices)); + break; + } + case OBJECT: { + float vertices[] = { + -width, -height, 0.f, 0.f, 1.f, + width, height, 0.f, 1.f, 0.f, + -width, height, 0.f, 0.f, 0.f, + -width, -height, 0.f, 0.f, 1.f, + width, -height, 0.f, 1.f, 1.f, + width, height, 0.f, 1.f, 0.f + }; + + set_gl_object(obj, vertices, sizeof(vertices)); + break; + } + } +} + +void bind_gl_object(gl_object *obj) { + glBindVertexArray(obj->vao); + glBindBuffer(GL_ARRAY_BUFFER, obj->vbo); +} + +static bool compile_check_error(unsigned int shader, char *source, char *error) { + glShaderSource(shader, 1, (const char * const*)&source, 0); + glCompileShader(shader); + + int status; + + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if (status == GL_FALSE) { + glGetShaderInfoLog(shader, 256, NULL, error); + glDeleteShader(shader); + + return false; + } + + return true; +} + +void create_gl_shader(gl_shader *shader, char *vs_source, char *fs_source) { + shader->program = glCreateProgram(); + + char error[256]; + + unsigned int vs_shader = glCreateShader(GL_VERTEX_SHADER); + if (!compile_check_error(vs_shader, vs_source, error)) { + //log_error("failed to compile vertex shader (%s, %s)", shader->name, error); + return; + } + + unsigned int fs_shader = glCreateShader(GL_FRAGMENT_SHADER); + if (!compile_check_error(fs_shader, fs_source, error)) { + //log_error("failed to compile fragment shader (%s, %s)", shader->name, error); + return; + } + + glAttachShader(shader->program, vs_shader); + glAttachShader(shader->program, fs_shader); + + glLinkProgram(shader->program); +} + +void bind_gl_shader(gl_shader *shader) { + glUseProgram(shader->program); +} + +void destroy_gl_shader(gl_shader *shader) { + glDeleteProgram(shader->program); +} + +void set_gl_uniform(unsigned int loc, uniform_type type, float *value) { + switch (type) { + case TYPE_FLOAT: + glUniform1f(loc, *value); + break; + case TYPE_SAMPLER2D: + glUniform1i(loc, (int)*value); + break; + case TYPE_VEC2: + glUniform2fv(loc, 1, value); + break; + case TYPE_VEC3: + glUniform3fv(loc, 1, value); + break; + case TYPE_VEC4: + glUniform4fv(loc, 1, value); + break; + case TYPE_MAT4: + glUniformMatrix4fv(loc, 1, GL_FALSE, value); + break; + } +} + +unsigned int get_uniform_loc(const char *name, gl_shader *shader) { + return glGetUniformLocation(shader->program, name); +} + +void set_gl_uniform_named(const char *name, gl_shader *shader, uniform_type type, + float *value) { + set_gl_uniform(get_uniform_loc(name, shader), type, value); } diff --git a/src/gl.h b/src/gl.h index ae43abb..eea877d 100644 --- a/src/gl.h +++ b/src/gl.h @@ -3,8 +3,57 @@ #include -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); +typedef enum { + DEFAULT, + UV_SCALE, + OBJECT +} gl_obj_type; + +typedef struct { + unsigned int vao; + unsigned int vbo; +} gl_object; + +typedef struct { + unsigned int program; +} gl_shader; + +typedef struct { + unsigned int id; +} gl_texture; + +typedef struct { + unsigned int id; + gl_texture texture; +} gl_framebuffer; + +typedef enum { + TYPE_FLOAT, + TYPE_VEC4, + TYPE_VEC3, + TYPE_VEC2, + TYPE_MAT4, + TYPE_SAMPLER2D +} uniform_type; + +void bind_gl_texture(gl_texture *tex, unsigned int index); +void create_gl_texture(gl_texture *tex, bool interp, bool clamp_uv, int mm_count); +void upload_gl_texture(gl_texture *tex, unsigned char *data, int width, int height, int level); +void destroy_gl_texture(gl_texture *tex); + +void bind_gl_framebuffer(gl_framebuffer *fbo, bool clear); +void create_gl_framebuffer(gl_framebuffer *fbo, float width, float height); +void destroy_gl_framebuffer(gl_framebuffer *fbo); + +void create_gl_object(gl_object *obj, gl_obj_type type, float width, float height); +void bind_gl_object(gl_object *obj); + +void create_gl_shader(gl_shader *shader, char *vs_source, char *fs_source); +void bind_gl_shader(gl_shader *shader); +void destroy_gl_shader(gl_shader *shader); + +void set_gl_uniform(unsigned int loc, uniform_type type, float *value); +unsigned int get_uniform_loc(const char *name, gl_shader *shader); +void set_gl_uniform_named(const char *name, gl_shader *shader, uniform_type type, float *value); #endif // _GL_H diff --git a/src/json.c b/src/json.c index 6094d4c..ddebcc9 100644 --- a/src/json.c +++ b/src/json.c @@ -4,6 +4,18 @@ #include "json.h" #include "log.h" +json_t *json_load_mstr(mstr *s) { + json_error_t error; + json_t *root = json_loadb(s->ptr, s->len, 0, &error); + + if (!root) { + log_error("err: failed to parse json on line %d: %s", error.line, error.text); + return NULL; + } + + return root; +} + static json_t *json_value_user(json_t *value) { if (json_is_object(value)) { return json_object_get(value, "value"); @@ -17,7 +29,7 @@ void json_get_bool(bool *result, json_t *root, const char *name) { *result = json_boolean_value(value); } else { *result = false; - log_debug("using default value for (%s)", name); + //log_debug("using default value for (%s)", name); } } @@ -27,7 +39,7 @@ void json_get_int(int *result, json_t *root, const char *name) { *result = json_integer_value(value); } else { *result = 0; - log_debug("using default value for (%s)", name); + //log_debug("using default value for (%s)", name); } } @@ -37,47 +49,36 @@ void json_get_float(float *result, json_t *root, const char *name) { *result = json_number_value(value); } else { *result = 0.f; - log_debug("using default value for (%s)", name); + //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); - } + sscanf_vec2(json_string_value(value), *result); } else { memset(*result, 0, sizeof(vec2)); - log_debug("using default value for (%s)", name); + //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); - } + sscanf_vec3(json_string_value(value), *result); } else { memset(*result, 0, sizeof(vec3)); - log_debug("using default value for (%s)", name); + //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); - } + sscanf_vec4(json_string_value(value), *result); } else { memset(*result, 0, sizeof(vec4)); - log_debug("using default value for (%s)", name); + //log_debug("using default value for (%s)", name); } } diff --git a/src/json.h b/src/json.h index 5d03f5a..294d8a4 100644 --- a/src/json.h +++ b/src/json.h @@ -3,9 +3,16 @@ #include #include +#include + +json_t *json_load_mstr(mstr *s); #define json_array(value, array) \ - for (size_t i = 0; i < json_array_size(array) && (value = json_array_get(array, i), 1); i++) + for (size_t i = 0; i < json_array_size(array) && (value = json_array_get(array, i), 1); i++) + +#define sscanf_vec4(s, v) sscanf(s, "%f %f %f %f", &(v)[0], &(v)[1], &(v)[2], &(v)[3]) +#define sscanf_vec3(s, v) sscanf(s, "%f %f %f", &(v)[0], &(v)[1], &(v)[2]) +#define sscanf_vec2(s, v) sscanf(s, "%f %f", &(v)[0], &(v)[1]) void json_get_bool(bool *result, json_t *root, const char *name); void json_get_int(int *result, json_t *root, const char *name); diff --git a/src/log.h b/src/log.h index 8a5443b..690e21d 100644 --- a/src/log.h +++ b/src/log.h @@ -1,8 +1,6 @@ #ifndef _LOG_H #define _LOG_H -#define _GNU_SOURCE - #include #include diff --git a/src/mauri.c b/src/mauri.c index b7485c0..9680b8b 100644 --- a/src/mauri.c +++ b/src/mauri.c @@ -1,20 +1,31 @@ #include +#include #include "assets.h" #include "context.h" +#include "engine.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); + context->create_window(context, 1600, 900, "mauri", false); if (argc == 2) { - mri_asset_manager_load_pkg(argv[1]); + mri_asset_manager_load_pkg(mstr_c(argv[1])); mri_scene scene = {0}; mri_scene_parse(&scene); + mri_engine engine = {0}; + engine.context = context; + + mri_engine_load(&engine); + + mri_scene_load(&engine, &scene); + + mri_engine_run(&engine); + mri_scene_unload(&scene); mri_asset_manager_unload(); } diff --git a/src/objects/effect.c b/src/objects/effect.c new file mode 100644 index 0000000..1ab6df3 --- /dev/null +++ b/src/objects/effect.c @@ -0,0 +1,59 @@ +#include "effect.h" +#include "../json.h" + +void mri_effect_parse(mri_effect *effect, json_t *root) { + mvec_init(effect->passes0); + mvec_init(effect->passes1); + + json_t *pass0; + json_t *passes0 = json_object_get(root, "passes"); + json_array(pass0, passes0) { + mri_pass_parse(mvec_next(effect->passes0), pass0, EFFECT0_PASS); + } + + json_t *file = json_object_get(root, "file"); + if (json_is_string(file)) { + mri_asset *effect_asset = mri_asset_manager_get(mstr_c(json_string_value(file)), NONE); + + if (effect_asset->type == ASSET_VOID) + return; + + json_t *_root = json_load_mstr(mri_asset_as_str(effect_asset)); + + json_t *pass1; + json_t *passes1 = json_object_get(_root, "passes"); + json_array(pass1, passes1) { + mri_pass_parse(mvec_next(effect->passes1), pass1, EFFECT1_PASS); + } + } +} + +void mri_effect_load(mri_engine *engine, mri_effect *effect) { + mri_engine_next_effect(engine); + + mri_pass *pass; + + mvec_loop_ptr(effect->passes0, pass, i) { + mri_engine_next_pass(engine); + mri_pass_load(engine, pass, EFFECT0_PASS); + } + + mvec_loop_ptr(effect->passes1, pass, i) { + mri_pass_load(engine, pass, EFFECT1_PASS); + } +} + +void mri_effect_unload(mri_effect *effect) { + mri_pass *pass; + + mvec_loop_ptr(effect->passes0, pass, i) { + mri_pass_unload(pass); + } + + mvec_loop_ptr(effect->passes1, pass, i) { + mri_pass_unload(pass); + } + + mvec_free(effect->passes0); + mvec_free(effect->passes1); +} diff --git a/src/objects/effect.h b/src/objects/effect.h new file mode 100644 index 0000000..76af254 --- /dev/null +++ b/src/objects/effect.h @@ -0,0 +1,18 @@ +#ifndef _EFFECT_H +#define _EFFECT_H + +#include + +#include "types.h" +#include "pass.h" + +struct mri_effect { + mvec(mri_pass) passes0; + mvec(mri_pass) passes1; +}; + +void mri_effect_parse(mri_effect *effect, json_t *root); +void mri_effect_load(mri_engine *engine, mri_effect *effect); +void mri_effect_unload(mri_effect *effect); + +#endif // _EFFECT_H diff --git a/src/objects/material.c b/src/objects/material.c index d01b8fe..d934970 100644 --- a/src/objects/material.c +++ b/src/objects/material.c @@ -1,40 +1,50 @@ #include "material.h" #include "pass.h" +#include + #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); + mvec_init(material->passes); - json_error_t error; - json_t *root = json_loadb((char *)asset->data, asset->size, 0, &error); + if (json_is_string(value)) { + mri_asset *material_asset = mri_asset_manager_get(mstr_c(json_string_value(value)), NONE); - if (!root) { - log_error("error parsing json on line %d: %s", error.line, error.text); + if (material_asset->type == ASSET_VOID) return; - } - mvec_init(material->passes); + json_t *root = json_load_mstr(mri_asset_as_str(material_asset)); 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); + mri_pass_parse(mvec_next(material->passes), pass, MATERIAL_PASS); } json_decref(root); - } else { - memset(material, 0, sizeof(mri_material)); + } +} + +void mri_material_load(mri_engine *engine, mri_material *material, mri_material_type t) { + mri_pass *pass; + mvec_loop_ptr(material->passes, pass, i) { + switch (t) { + case MATERIAL_EFFECT: + mri_pass_load(engine, pass, MATERIAL_PASS); + break; + case MATERIAL_MODEL: + mri_engine_next_pass(engine); + mri_pass_load(engine, pass, MATERIAL_ONLY_PASS); + break; + } } } void mri_material_unload(mri_material *material) { mri_pass *pass; - mvec_loop_ptr(material->passes, pass) { + mvec_loop_ptr(material->passes, pass, i) { mri_pass_unload(pass); } mvec_free(material->passes); diff --git a/src/objects/material.h b/src/objects/material.h index e7311c0..805a198 100644 --- a/src/objects/material.h +++ b/src/objects/material.h @@ -3,13 +3,20 @@ #include +#include "types.h" #include "pass.h" +typedef enum { + MATERIAL_MODEL, + MATERIAL_EFFECT +} mri_material_type; + struct mri_material { mvec(mri_pass) passes; }; void mri_material_parse(mri_material *material, json_t *value); +void mri_material_load(mri_engine *engine, mri_material *material, mri_material_type t); void mri_material_unload(mri_material *material); #endif // MATERIAL_H diff --git a/src/objects/model.c b/src/objects/model.c index c821786..3fe8e1d 100644 --- a/src/objects/model.c +++ b/src/objects/model.c @@ -1,4 +1,5 @@ #include +#include #include "../json.h" #include "../assets.h" @@ -8,15 +9,12 @@ 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); + mri_asset *model_asset = mri_asset_manager_get(mstr_c(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); + if (model_asset->type == ASSET_VOID) return; - } + + json_t *root = json_load_mstr(mri_asset_as_str(model_asset)); json_get_bool(&model->autosize, root, "autosize"); json_get_bool(&model->fullscreen, root, "fullscreen"); @@ -30,6 +28,11 @@ void mri_model_parse(mri_model *model, json_t *value) { } } +void mri_model_load(mri_engine *engine, mri_model *model) { + engine->current_effect = &engine->current_object->background; + mri_material_load(engine, &model->material, MATERIAL_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 index f1068d7..38f4405 100644 --- a/src/objects/model.h +++ b/src/objects/model.h @@ -3,17 +3,21 @@ #include +#include "types.h" #include "pass.h" #include "material.h" -typedef struct { +#include "../engine.h" + +struct mri_model { bool autosize; bool fullscreen; bool passthrough; mri_material material; -} mri_model; +}; void mri_model_parse(mri_model *model, json_t *value); +void mri_model_load(mri_engine *engine, mri_model *model); void mri_model_unload(mri_model *model); #endif // _MODEL_H diff --git a/src/objects/object.c b/src/objects/object.c index 6b679a0..55ed1c9 100644 --- a/src/objects/object.c +++ b/src/objects/object.c @@ -1,23 +1,17 @@ #include +#include +#include "types.h" #include "object.h" #include "model.h" #include "../log.h" +#include "../gl.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; @@ -27,26 +21,90 @@ void mri_object_parse(mri_object *object, json_t *root) { mvec_push(object->deps, value); } + json_get_float(&object->alpha, root, "alpha"); + json_get_vec3(&object->angles, root, "angles"); + json_get_vec3(&object->color, root, "color"); json_get_vec2(&object->size, root, "size"); json_get_vec3(&object->scale, root, "scale"); json_get_vec3(&object->origin, root, "origin"); + object->origin[2] = 0.f; + + json_get_int(&object->color_blend_mode, root, "colorblendmode"); + json_get_bool(&object->copy_background, root, "copybackground"); mri_model_parse(&object->image, json_object_get(root, "image")); json_get_bool(&object->visible, root, "visible"); - //mvec_init(object->effects); + json_t *config = json_object_get(root, "config"); + if (json_is_object(config)) { + json_get_bool(&object->passthrough, config, "passthrough"); + } + + mvec_init(object->effects); json_t *effect; json_t *effects = json_object_get(root, "effects"); json_array(effect, effects) { - // parse effect + bool visible; + json_get_bool(&visible, effect, "visible"); + if (visible) + mri_effect_parse(mvec_next(object->effects), effect); + } +} + +void mri_object_get_model(mri_object *object, mat4 model, float width, float height) { + glm_mat4_identity(model); + + glm_translate_to(model, (vec3){-width, -height, 0.f}, model); + + vec3 origin; + glm_vec3_scale(object->origin, 2.f, origin); + glm_translate_to(model, origin, model); + + glm_rotate(model, object->angles[0], (vec3){1.f, 0.f, 0.f}); + glm_rotate(model, object->angles[1], (vec3){0.f, 1.f, 0.f}); + glm_rotate(model, object->angles[2], (vec3){0.f, 0.f, 1.f}); + + glm_scale(model, object->scale); + + mat4 ortho; + glm_ortho(-width, width, height, -height, 0.f, 1.f, ortho); + glm_mat4_mul(ortho, model, model); +} + +void mri_object_load(mri_engine *engine, mri_object *object) { + mri_engine_next_object(engine, object); + + mri_model_load(engine, &object->image); + + if (object->image.fullscreen) { + object->fullscreen = true; + object->size[0] = engine->width; + object->size[1] = engine->height; + object->origin[0] = object->size[0] / 2.f; + object->origin[1] = object->size[1] / 2.f; + } + + if (object->image.passthrough) { + object->passthrough = true; + } + + mri_effect *effect; + mvec_loop_ptr(object->effects, effect, i) { + mri_effect_load(engine, effect); } } void mri_object_unload(mri_object *object) { + mri_effect *effect; + mvec_loop_ptr(object->effects, effect, i) { + mri_effect_unload(effect); + } + + mvec_free(object->effects); 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 index 18c0dec..6965224 100644 --- a/src/objects/object.h +++ b/src/objects/object.h @@ -1,18 +1,23 @@ #ifndef _OBJECT_H #define _OBJECT_H -#include +#include #include #include #include +#include "types.h" #include "model.h" +#include "pass.h" +#include "effect.h" + +#include "../gl.h" typedef enum { CENTER, } mri_object_alignment; -typedef struct { +struct mri_object { int id; char *name; @@ -37,10 +42,16 @@ typedef struct { bool visible; - //mvec(mri_effect) effects; -} mri_object; + bool passthrough; + bool fullscreen; + + mvec(mri_effect) effects; +}; + +void mri_object_get_model(mri_object *object, mat4 model, float width, float height); void mri_object_parse(mri_object *object, json_t *root); +void mri_object_load(mri_engine *engine, mri_object *object); void mri_object_unload(mri_object *object); #endif // _OBJECT_H diff --git a/src/objects/pass.c b/src/objects/pass.c index ba9de8c..942ea5e 100644 --- a/src/objects/pass.c +++ b/src/objects/pass.c @@ -1,31 +1,221 @@ #include "pass.h" #include "material.h" +#include "model.h" +#include "object.h" #include "../json.h" #include "../texture.h" #include "../assets.h" +#include "../gl.h" -void mri_pass_parse(mri_pass *pass, json_t *root) { - // TODO - pass->material = (mri_material *)malloc(sizeof(mri_material)); - mri_material_parse(pass->material, json_object_get(root, "material")); +void mri_pass_parse(mri_pass *pass, json_t *root, mri_pass_stage stage) { + memset(pass, 0, sizeof(mri_pass)); + + switch (stage) { + case EFFECT0_PASS: { + mvec_init(pass->uniforms); + + json_t *uniform; + json_t *uniforms = json_object_get(root, "constantshadervalues"); + + void *iter = json_object_iter(uniforms); + + while (iter) { + uniform = json_object_iter_value(iter); + + mri_uniform u = { + .name = mstr_from(json_object_iter_key(iter)) + }; + + if (json_is_number(uniform)) { + u.value[0] = json_number_value(uniform); + } else if (json_is_string(uniform)) { + sscanf_vec4(json_string_value(uniform), u.value); + } + + mvec_push(pass->uniforms, u); + + iter = json_object_iter_next(uniforms, iter); + } + + break; + } + case EFFECT1_PASS: { + json_t *material = json_object_get(root, "material"); + + if (json_is_string(material)) { + pass->material = (mri_material *)calloc(1, sizeof(mri_material)); + mri_material_parse(pass->material, material); + } + + json_t *target = json_object_get(root, "target"); + + if (json_is_string(target)) { + printf("%s\n", json_string_value(target)); + } + + json_t *binds = json_object_get(root, "binds"); + + if (json_is_array(binds)) { + printf("%li\n", json_array_size(binds)); + } + + break; + } + case MATERIAL_ONLY_PASS: + case MATERIAL_PASS: { + json_t *shader = json_object_get(root, "shader"); + + if (json_is_string(shader)) { + pass->shader = (mri_shader *)calloc(1, sizeof(mri_shader)); + mri_shader_load(pass->shader, mstr_c(json_string_value(shader))); + } + + break; + } + } json_t *texture; json_t *textures = json_object_get(root, "textures"); + json_array(texture, textures) { if (json_is_string(texture)) { - pass->textures[i] = mri_texture_load(mri_asset_manager_get(json_string_value(texture), TEXTURE)); - mri_texture_unload(pass->textures[i]); + mri_asset *_a = mri_asset_manager_get(mstr_c(json_string_value(texture)), TEXTURE); + if (_a->type != ASSET_VOID) { + pass->textures[i] = mri_texture_load(_a); + } } } - json_t *shader = json_object_get(root, "shader"); - if (json_is_string(shader)) { - mri_shader_load(&pass->shader, json_string_value(shader)); - mri_shader_unload(&pass->shader); + mvec_init(pass->combos); + + json_t *combo; + json_t *combos = json_object_get(root, "combos"); + + void *iter = json_object_iter(combos); + + while (iter) { + combo = json_object_iter_value(iter); + + mri_combo c = { + .name = mstr_from(json_object_iter_key(iter)) + }; + + if (json_is_integer(combo)) { + c.value = json_integer_value(combo); + } + + mvec_push(pass->combos, c); + + iter = json_object_iter_next(combo, iter); + } +} + +void mri_pass_load(mri_engine *engine, mri_pass *pass, mri_pass_stage stage) { + mri_render_object *robject = engine->current_object; + mri_render_pass *rpass = engine->current_pass; + + for (int i = 1; i < 7; i++) { + if (pass->textures[i]) rpass->textures[i] = pass->textures[i]; + } + + mri_combo *combo; + mvec_loop_ptr(pass->combos, combo, i) { + mvec_push(rpass->combos, *combo); + } + + switch (stage) { + case EFFECT0_PASS: { + mri_uniform *uniform; + mvec_loop_ptr(pass->uniforms, uniform, i) { + mvec_push(rpass->uniforms, *uniform); + } + break; + } + case EFFECT1_PASS: + if (!robject->buffer_switch) { + rpass->target = robject->buffer_b; + rpass->textures[0] = &robject->buffer_a->texture; + } else { + rpass->target = robject->buffer_a; + rpass->textures[0] = &robject->buffer_b->texture; + } + robject->buffer_switch = !robject->buffer_switch; + mri_material_load(engine, pass->material, MATERIAL_EFFECT); + break; + case MATERIAL_ONLY_PASS: + rpass->target = robject->buffer_a; + rpass->textures[0] = pass->textures[0]; + case MATERIAL_PASS: { + memcpy(&rpass->shader, pass->shader, sizeof(mri_shader)); + + for (int i = 0; i < 7; i++) { + if (!rpass->textures[i] && rpass->shader.textures[i]) { + rpass->textures[i] = rpass->shader.textures[i]; + } + } + + mri_uniform *pass_uniform, *shader_uniform; + mvec_loop_ptr(rpass->shader.uniforms, shader_uniform, i) { + // ex: g_Texture2Resolution (vec4) + // ^ index + if (mstr_eqn(shader_uniform->uname, mstr_c("g_Texture"), 9) && + shader_uniform->type == TYPE_VEC4) { + int index = shader_uniform->uname->ptr[9] - '0'; + if (rpass->textures[index]) { + vec4 *texture_res = &rpass->textures[index]->texture_resolution; + memcpy(shader_uniform->value, texture_res, sizeof(vec4)); + } + } + } + mvec_loop_ptr(rpass->uniforms, pass_uniform, i) + mvec_loop_ptr(rpass->shader.uniforms, shader_uniform, s) { + if (!shader_uniform->name) continue; + if (mstr_eq(pass_uniform->name, shader_uniform->name)) { + memcpy(shader_uniform->value, pass_uniform->value, sizeof(vec4)); + } + } + + mri_combo *pass_combo, *shader_combo; + mvec_loop_ptr(rpass->combos, pass_combo, i) + mvec_loop_ptr(rpass->shader.combos, shader_combo, s) { + if (mstr_eq(pass_combo->name, shader_combo->name)) { + shader_combo->value = pass_combo->value; + } + } + + mri_shader_compile(&rpass->shader); + + break; + } } } void mri_pass_unload(mri_pass *pass) { - free(pass->material); + for (int i = 0; i < 7; i++) { + if (pass->textures[i]) mri_texture_unload(pass->textures[i]); + } + + mri_uniform *uniform; + mvec_loop_ptr(pass->uniforms, uniform, i) { + mstr_free(uniform->name); + } + + mri_combo *combo; + mvec_loop_ptr(pass->combos, combo, i) { + mstr_free(combo->name); + } + + mvec_free(pass->uniforms); + mvec_free(pass->combos); + + if (pass->shader) { + mri_shader_unload(pass->shader); + free(pass->shader); + } + + if (pass->material) { + mri_material_unload(pass->material); + free(pass->material); + } } diff --git a/src/objects/pass.h b/src/objects/pass.h index ce34edd..94bad25 100644 --- a/src/objects/pass.h +++ b/src/objects/pass.h @@ -3,22 +3,32 @@ #include +#include "types.h" + +#include "../context.h" #include "../shader.h" +#include "../engine.h" #include "../texture.h" -typedef struct mri_material mri_material; - -typedef struct { +struct mri_pass { mri_material *material; - mri_shader shader; + mri_shader *shader; mri_texture *textures[7]; - // mvec(mri_uniform) uniforms; - // mvec(mri_combo) combos; -} mri_pass; + mvec(mri_uniform) uniforms; + mvec(mri_combo) combos; +}; + +typedef enum { + EFFECT0_PASS, + EFFECT1_PASS, + MATERIAL_PASS, + MATERIAL_ONLY_PASS +} mri_pass_stage; -void mri_pass_parse(mri_pass *pass, json_t *root); +void mri_pass_parse(mri_pass *pass, json_t *root, mri_pass_stage stage); +void mri_pass_load(mri_engine *engine, mri_pass *pass, mri_pass_stage stage); void mri_pass_unload(mri_pass *pass); #endif // _PASS_H diff --git a/src/objects/scene.c b/src/objects/scene.c index 6b8cfce..2448659 100644 --- a/src/objects/scene.c +++ b/src/objects/scene.c @@ -8,16 +8,15 @@ #include "../log.h" void mri_scene_parse(mri_scene *scene) { - mri_asset *scene_json = mri_asset_manager_get("scene.json", NONE); + mri_asset *scene_asset = mri_asset_manager_get(mstr_c("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); + if (scene_asset->type == ASSET_VOID) { + log_error("err: failed to open scene.json"); return; } + json_t *root = json_load_mstr(mri_asset_as_str(scene_asset)); + json_t *camera = json_object_get(root, "camera"); json_t *general = json_object_get(root, "general"); json_t *ortho = json_object_get(general, "orthogonalprojection"); @@ -40,17 +39,28 @@ void mri_scene_parse(mri_scene *scene) { 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); + bool visible; + json_get_bool(&visible, object, "visible"); + if (visible) + mri_object_parse(mvec_next(scene->objects), object); } json_decref(root); } +void mri_scene_load(mri_engine *engine, mri_scene *scene) { + engine->width = scene->width; + engine->height = scene->height; + + mri_object *object; + mvec_loop_ptr(scene->objects, object, i) { + mri_object_load(engine, object); + } +} + void mri_scene_unload(mri_scene *scene) { mri_object *object; - mvec_loop_ptr(scene->objects, object) { + mvec_loop_ptr(scene->objects, object, i) { mri_object_unload(object); } mvec_free(scene->objects); diff --git a/src/objects/scene.h b/src/objects/scene.h index 5c7e90b..ff0464b 100644 --- a/src/objects/scene.h +++ b/src/objects/scene.h @@ -4,11 +4,12 @@ #include #include +#include "types.h" #include "object.h" #include "../assets.h" -typedef struct { +struct mri_scene { float width; float height; @@ -34,9 +35,10 @@ typedef struct { float bloom_threshold; mvec(mri_object) objects; -} mri_scene; +}; void mri_scene_parse(mri_scene *scene); +void mri_scene_load(mri_engine *engine, mri_scene *scene); void mri_scene_unload(mri_scene *scene); #endif // _SCENE_H diff --git a/src/objects/types.h b/src/objects/types.h new file mode 100644 index 0000000..9701cb0 --- /dev/null +++ b/src/objects/types.h @@ -0,0 +1,11 @@ +#ifndef _TYPES_H +#define _TYPES_H + +typedef struct mri_scene mri_scene; +typedef struct mri_object mri_object; +typedef struct mri_model mri_model; +typedef struct mri_material mri_material; +typedef struct mri_pass mri_pass; +typedef struct mri_effect mri_effect; + +#endif // _TYPES_H diff --git a/src/shader.c b/src/shader.c index c2d7d1a..7d7783a 100644 --- a/src/shader.c +++ b/src/shader.c @@ -1,10 +1,19 @@ #include #include #include +#include +#include + +#include #include "shader.h" #include "assets.h" +#include "json.h" #include "log.h" +#include "gl.h" +#include "engine.h" + +#include "objects/object.h" static const char *gl_compat = "#define highp\n" @@ -23,147 +32,241 @@ static const char *gl_compat = "#define atan2(y,x) atan(x,y)\n" "#define ddx dFdx\n" "#define ddy(x) dFdy(-(x))\n" - "#define GLSL 1\n\0"; + "#define GLSL 1\n"; static const char *version = "#version 120\n"; -static char *build_shader_source(mri_shader *shader, char *buffer, bool first) { - size_t source_len = strlen(buffer) + strlen(gl_compat); - size_t source_index = 0; +static mstr *build_shader_source(mri_shader *shader, mstr *isource, bool start) { + mstr *source = mstr_from("\0"); - char *source = (char *)malloc(source_len); - source[source_index] = '\0'; + if (start) + mstr_cat(source, mstr_c(gl_compat)); - if (first) { - source_index += strlen(gl_compat) + 1; - strncat(source, gl_compat, source_index); - } + mstr line = {0}; - char *line = buffer; + while (mstr_get_line(isource, &line)) { + bool cut_line = false; - while (line) { - char *next_line = strchr(line, '\n'); - size_t len = next_line ? (size_t)(next_line - line) : strlen(line); + if (mstr_eqn(&line, mstr_c("#include"), 8)) { + mstr inc_name = mstr_substr(&line, mstr_find(&line, '"') + 1, mstr_rfind(&line, '"')); - if (memcmp(line, "#include", 8) == 0) { - char *open = strchr(line, '"') + 1; - char *close = strchr(open, '"') + 1; + mri_asset *inc_asset = mri_asset_manager_get(&inc_name, SHADER); + mstr *inc = build_shader_source(shader, mri_asset_as_str(inc_asset), false); - char *include = (char *)malloc(close - open); - snprintf(include, close - open, "%s", open); + mstr_cat(source, inc); + mstr_free(inc); - mri_asset *include_asset = mri_asset_manager_get(include, SHADER); + cut_line = true; + } else if (mstr_eqn(&line, mstr_c("uniform"), 7)) { + mri_uniform *u = mvec_next(shader->uniforms); - if (include_asset->type == ASSET_VOID) { - return NULL; - } + mstr type = mstr_substr(&line, mstr_find(&line, ' ') + 1, mstr_len(&line)); - char *include_str = mri_str_to_c_str(read_string(*include_asset, include_asset->size)); - char *include_src = build_shader_source(shader, include_str, false); + if (mstr_eqn(&type, mstr_c("float"), 5)) u->type = TYPE_FLOAT; + else if (mstr_eqn(&type, mstr_c("vec4"), 4)) u->type = TYPE_VEC4; + else if (mstr_eqn(&type, mstr_c("vec3"), 4)) u->type = TYPE_VEC3; + else if (mstr_eqn(&type, mstr_c("vec2"), 4)) u->type = TYPE_VEC2; + else if (mstr_eqn(&type, mstr_c("mat4"), 4)) u->type = TYPE_MAT4; + else if (mstr_eqn(&type, mstr_c("sampler2D"), 9)) { + u->type = TYPE_SAMPLER2D; + u->value[0] = (float)shader->texture_count++; + } - if (!include_src) { - return NULL; + u->uname = mstr_substr_copy(&type, mstr_find(&type, ' ') + 1, mstr_find(&type, ';')); + + ptrdiff_t combo_start = mstr_find(&line, '/'); + + if (combo_start >= 0) { + mstr combo_str = mstr_substr(&line, combo_start + 2, mstr_len(&line)); + + json_t *root = json_load_mstr(&combo_str); + + if (!root) continue; + + json_t *label = json_object_get(root, "label"); + json_t *material = json_object_get(root, "material"); + + if (json_is_string(material)) + u->name = mstr_clone(mstr_c(json_string_value(material))); + else if (json_is_string(label)) + u->name = mstr_clone(mstr_c(json_string_value(label))); + + switch (u->type) { + case TYPE_SAMPLER2D: { + json_t *texture = json_object_get(root, "default"); + if (json_is_string(texture)) { + mri_asset *_a = mri_asset_manager_get(mstr_c(json_string_value(texture)), TEXTURE); + shader->textures[(int)u->value[0]] = mri_texture_load(_a); + } + break; + } + case TYPE_FLOAT: + json_get_float(&u->value[0], root, "default"); + break; + case TYPE_VEC4: + json_get_vec4(&u->value, root, "default"); + break; + case TYPE_VEC3: + json_get_vec3((vec3 *)&u->value, root, "default"); + break; + case TYPE_VEC2: + json_get_vec2((vec2 *)&u->value, root, "default"); + break; + case TYPE_MAT4: + default: + memset(&u->value, 0, sizeof(vec4)); + break; + } + + json_decref(root); } + } else if (mstr_eqn(&line, mstr_c("// [COMBO]"), 10)) { + mstr combo = mstr_substr(&line, mstr_find(&line, '{'), mstr_len(&line)); - size_t include_len = strlen(include_src); + json_t *root = json_load_mstr(&combo); - if (!(source = realloc(source, source_len + include_len))) { - log_error("%s", "failed to allocate memory for shader source"); - abort(); // fatal - } + mri_combo c = { + .name = mstr_from(json_string_value(json_object_get(root, "combo"))), + .value = json_integer_value(json_object_get(root, "default")) + }; - strncat(source, include_src, include_len + 1); - source_index += include_len + 1; + mvec_push(shader->combos, c); - free(include); - free(include_src); - free(include_str); - } else if (memcmp(line, "uniform", 7) == 0) { - mri_uniform _u = {0}; - mvec_push(shader->uniforms, _u); + json_decref(root); + } - mri_uniform *u = &mvec_last(shader->uniforms); + if (!cut_line) { + mstr_cat(source, &line); + mstr_cat(source, mstr_c("\n")); + } + } - char *type_start = strchr(line, ' ') + 1; - char *type_end = strchr(type_start, ' ') + 1; + return source; +} - char *type = (char *)malloc(type_end - type_start); - snprintf(type, type_end - type_start, "%s", type_start); +static char *mri_combo_to_str(mri_combo *combo) { + char *combo_str; + asprintf(&combo_str, "#define %.*s %i\n", (int)combo->name->len, + combo->name->ptr, combo->value); + return combo_str; +} - if (memcmp(type, "float", 5) == 0) u->type = TYPE_FLOAT; - else if (memcmp(type, "vec4", 4) == 0) u->type = TYPE_VEC4; - else if (memcmp(type, "vec3", 4) == 0) u->type = TYPE_VEC3; - else if (memcmp(type, "vec2", 4) == 0) u->type = TYPE_VEC2; - else if (memcmp(type, "sampler2D", 10) == 0) { - u->type = TYPE_SAMPLER2D; - } +void mri_shader_compile(mri_shader *shader) { + mstr *vs_source = mstr_clone(shader->vs_source); + mstr *fs_source = mstr_clone(shader->fs_source); - char *name_end = strchr(type_end, ';') + 1; + mri_combo *combo; + mvec_loop_ptr(shader->combos, combo, i) { + char *combo_str = mri_combo_to_str(combo); + mstr_prepend(vs_source, mstr_c(combo_str)); + mstr_prepend(fs_source, mstr_c(combo_str)); + free(combo_str); + } - u->uname = (char *)malloc(name_end - type_end); - snprintf(u->uname, name_end - type_end, "%s", type_end); + mstr_prepend(vs_source, mstr_c(version)); + mstr_prepend(fs_source, mstr_c(version)); - char *combo_start = strchr(line, '/'); + char *vs_source_c = mstr_to_cstr(vs_source); + char *fs_source_c = mstr_to_cstr(fs_source); - if (combo_start && combo_start - line < len) { - // parse combo - } - } else { - strncat(source, line, len + 1); - source_index += len + 1; - source[source_index] = '\0'; - } + create_gl_shader(&shader->gl_shader, vs_source_c, fs_source_c); - line = next_line ? next_line + 1 : NULL; - } + free(vs_source_c); + free(fs_source_c); - return source; + mstr_free(vs_source); + mstr_free(fs_source); } -void mri_shader_load(mri_shader *shader, const char *name) { +void mri_shader_load(mri_shader *shader, mstr *name) { mvec_init(shader->uniforms); + mvec_init(shader->combos); - mri_asset *vertex_asset = mri_asset_manager_get(name, VERTEX_SHADER); - if (vertex_asset->type != ASSET_VOID) { - char *vertex_str = mri_str_to_c_str(read_string(*vertex_asset, vertex_asset->size)); - shader->vertex_source = build_shader_source(shader, vertex_str, true); + mri_asset *vs_asset = mri_asset_manager_get(name, VERTEX_SHADER); - if (!shader->vertex_source) { - log_error("failed to parse shader (%s.vert)", name); - } + if (vs_asset->type != ASSET_VOID) { + shader->vs_source = build_shader_source(shader, mri_asset_as_str(vs_asset), true); + } else { + log_error("failed to load shader file (%.*s.vert)", name->len, name->ptr); + } + + mri_asset *fs_asset = mri_asset_manager_get(name, FRAGMENT_SHADER); - free(vertex_str); + if (fs_asset->type != ASSET_VOID) { + shader->fs_source = build_shader_source(shader, mri_asset_as_str(fs_asset), true); } else { - log_error("failed to load shader file (%s.vert)", name); + log_error("failed to load shader file (%.*s.frag)", name->len, name->ptr); + } +} + +void mri_uniform_set(mri_shader *shader, mri_uniform *uniform) { + if (!uniform->loc) { + char *name = mstr_to_cstr(uniform->uname); + uniform->loc = get_uniform_loc(name, &shader->gl_shader); + free(name); } - mri_asset *fragment_asset = mri_asset_manager_get(name, FRAGMENT_SHADER); - if (fragment_asset->type != ASSET_VOID) { - char *fragment_str = mri_str_to_c_str(read_string(*fragment_asset, fragment_asset->size)); - shader->fragment_source = build_shader_source(shader, fragment_str, true); + set_gl_uniform(uniform->loc, uniform->type, uniform->value); +} - if (!shader->fragment_source) { - log_error("failed to parse shader (%s.frag)", name); - } +void mri_shader_bind(mri_engine *engine, mri_shader *shader, mat4 mvp) { + bind_gl_shader(&shader->gl_shader); + + mri_uniform *uniform; + mvec_loop_ptr(shader->uniforms, uniform, i) { + mri_uniform_set(shader, uniform); + } + + set_gl_uniform_named("g_Time", &shader->gl_shader, TYPE_FLOAT, &engine->time); + + set_gl_uniform_named("g_TexelSize", &shader->gl_shader, TYPE_VEC2, &engine->texel_size[0]); + set_gl_uniform_named("g_TexelSizeHalf", &shader->gl_shader, TYPE_VEC2, + &engine->texel_half_size[0]); - free(fragment_str); + if (!mvp) { + mat4 _mvp; + glm_mat4_identity(_mvp); + set_gl_uniform_named("g_ModelViewProjectionMatrix", &shader->gl_shader, + TYPE_MAT4, (float *)_mvp); } else { - log_error("failed to load shader file (%s.frag)", name); + set_gl_uniform_named("g_ModelViewProjectionMatrix", &shader->gl_shader, + TYPE_MAT4, (float *)mvp); + mat4 _inverse; + glm_mat4_inv(mvp, _inverse); + set_gl_uniform_named("g_ModelViewProjectionMatrixInverse", &shader->gl_shader, + TYPE_MAT4, (float *)_inverse); } } - + void mri_shader_unload(mri_shader *shader) { - free(shader->vertex_source); - free(shader->fragment_source); + for (int i = 0; i < 7; i++) { + if (shader->textures[i]) + mri_texture_unload(shader->textures[i]); + } + + if (shader->vs_source) + mstr_free(shader->vs_source); + if (shader->fs_source) + mstr_free(shader->fs_source); mri_uniform *uniform; - mvec_loop_ptr(shader->uniforms, uniform) { - printf("%s\n", uniform->uname); - printf("%i\n", uniform->type); - free(uniform->uname); + mvec_loop_ptr(shader->uniforms, uniform, i) { + if (uniform->uname) + mstr_free(uniform->uname); + if (uniform->name) + mstr_free(uniform->name); + } + + mri_combo *combo; + mvec_loop_ptr(shader->combos, combo, i) { + if (combo->name) + mstr_free(combo->name); } mvec_free(shader->uniforms); + mvec_free(shader->combos); + + destroy_gl_shader(&shader->gl_shader); } diff --git a/src/shader.h b/src/shader.h index a9548c3..6880397 100644 --- a/src/shader.h +++ b/src/shader.h @@ -1,34 +1,34 @@ #ifndef _SHADER_H #define _SHADER_H +#include + +#include "objects/types.h" #include "texture.h" +#include "gl.h" -typedef enum { - TYPE_FLOAT, - TYPE_VEC4, - TYPE_VEC3, - TYPE_VEC2, - TYPE_MAT4, - TYPE_SAMPLER2D -} mri_uniform_type; +typedef struct mri_engine mri_engine; typedef struct { - mri_uniform_type type; - const char *name; - const char *uname; + uniform_type type; + mstr *name; + mstr *uname; vec4 value; + unsigned int loc; } mri_uniform; typedef struct { - const char *name; + mstr *name; int value; } mri_combo; typedef struct { const char *name; - char *vertex_source; - char *fragment_source; + mstr *vs_source; + mstr *fs_source; + + gl_shader gl_shader; int texture_count; @@ -38,7 +38,9 @@ typedef struct { mvec(mri_uniform) uniforms; } mri_shader; -void mri_shader_load(mri_shader *shader, const char *name); +void mri_shader_load(mri_shader *shader, mstr *name); +void mri_shader_compile(mri_shader *shader); +void mri_shader_bind(mri_engine *engine, mri_shader *shader, mat4 mvp); void mri_shader_unload(mri_shader *shader); #endif // _SHADER_H diff --git a/src/texture.c b/src/texture.c index 9f10dca..76dfb5d 100644 --- a/src/texture.c +++ b/src/texture.c @@ -1,6 +1,8 @@ #define STB_IMAGE_IMPLEMENTATION #include + #include +#include #include "util.h" #include "texture.h" @@ -13,77 +15,73 @@ static unsigned char *load_image_rgba(unsigned char *data, int len) { return stbi_load_from_memory(data, len, &w, &h, &channels, 4); } -mri_texture *mri_texture_load(mri_asset *_asset) { +mri_texture *mri_texture_load(mri_asset *asset) { // check if texture was previously loaded mri_texture *t = (mri_texture *)malloc(sizeof(mri_texture)); - mri_asset asset = *_asset; - - mri_str type = read_string(asset, 9); - mri_str itype = read_string(asset, 9); + mstr type = mri_asset_str(asset, 9); + mstr itype = mri_asset_str(asset, 9); - t->format = (mri_texture_format)read_value(asset, unsigned int); + t->format = (mri_texture_format)mri_asset_value(asset, unsigned int); - t->flags.integer = read_value(asset, unsigned int); + t->flags.integer = mri_asset_value(asset, unsigned int); - t->texture_width = read_value(asset, unsigned int); - t->texture_height = read_value(asset, unsigned int); + t->texture_width = mri_asset_value(asset, unsigned int); + t->texture_height = mri_asset_value(asset, unsigned int); - t->width = read_value(asset, unsigned int); - t->height = read_value(asset, unsigned int); + t->width = mri_asset_value(asset, unsigned int); + t->height = mri_asset_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_asset_seek(asset, 4); - mri_str container = read_string(asset, 9); + mstr container = mri_asset_str(asset, 9); int iformat = -1; - if (memcmp(container.ptr, "TEXB0003", 9) == 0) { + if (mstr_eqn(&container, mstr_c("TEXB0003"), 8)) { t->version = TEXB0003; - seek(asset, 4); - iformat = read_value(asset, unsigned int); - } else if (memcmp(container.ptr, "TEXB0002", 9) == 0) { + mri_asset_seek(asset, 4); + iformat = mri_asset_value(asset, unsigned int); + } else if (mstr_eqn(&container, mstr_c("TEXB0002"), 8)) { t->version = TEXB0002; - seek(asset, 4); - } else if (memcmp(container.ptr, "TEXB0001", 9) == 0) { + mri_asset_seek(asset, 4); + } else if (mstr_eqn(&container, mstr_c("TEXB0001"), 8)) { t->version = TEXB0001; - seek(asset, 4); + mri_asset_seek(asset, 4); } else { - log_error("%s", "unknown texture version"); - return; + //log_error("%s", "unknown texture version"); } - int mm_count = read_value(asset, int); + int mm_count = mri_asset_value(asset, int); - t->texture_id = create_gl_texture( - t->flags.map.NO_INTERPOLATION, + create_gl_texture(&t->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); + unsigned int mwidth = mri_asset_value(asset, unsigned int); + unsigned int mheight = mri_asset_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); + lz4_compressed = mri_asset_value(asset, unsigned int) == 1; + decompressed_byte_count = mri_asset_value(asset, unsigned int); } - unsigned int byte_count = read_value(asset, unsigned int); + unsigned int byte_count = mri_asset_value(asset, unsigned int); if (!lz4_compressed) { decompressed_byte_count = byte_count; } - unsigned char *buffer = asset_ptr(asset); + unsigned char *buffer = mri_asset_ptr(asset); if (lz4_compressed) { char *decompressed = (char *)malloc(decompressed_byte_count); @@ -94,7 +92,7 @@ mri_texture *mri_texture_load(mri_asset *_asset) { if (iformat == -1) { switch (t->format) { case RGBA8888: - upload_gl_texture(t->texture_id, buffer, mwidth, mheight, i); + upload_gl_texture(&t->texture, buffer, mwidth, mheight, i); break; case DXT5: log_warn("%s", "DXT5 Texture"); @@ -107,7 +105,7 @@ mri_texture *mri_texture_load(mri_asset *_asset) { } } else { unsigned char *data = load_image_rgba(buffer, decompressed_byte_count); - upload_gl_texture(t->texture_id, data, mwidth, mheight, i); + upload_gl_texture(&t->texture, data, mwidth, mheight, i); free(data); } @@ -115,14 +113,52 @@ mri_texture *mri_texture_load(mri_asset *_asset) { free(buffer); } - seek(asset, byte_count); + mri_asset_seek(asset, byte_count); } + asset->pos = 0; + return t; } -void mri_texture_unload(mri_texture *texture) { - destroy_gl_texture(texture->texture_id); +void mri_texture_unload(mri_texture *t) { + destroy_gl_texture(&t->texture); + free(t); +} + +void mri_texture_bind(mri_texture *t, int index) { + bind_gl_texture(&t->texture, index); +} + +mri_framebuffer *mri_framebuffer_load(mstr *name, float width, float height, float scale) { + mri_framebuffer *buffer = (mri_framebuffer *)malloc(sizeof(mri_framebuffer)); + + buffer->name = mstr_clone(name); + + create_gl_framebuffer(&buffer->buffer, width / scale, height / scale); + + buffer->width = width; + buffer->height = height; + + buffer->texture.texture_resolution[0] = width; + buffer->texture.texture_resolution[1] = height; + buffer->texture.texture_resolution[2] = width; + buffer->texture.texture_resolution[3] = height; + + buffer->texture.texture.id = buffer->buffer.texture.id; + + return buffer; +} + +void mri_framebuffer_unload(mri_framebuffer *buffer) { + mstr_free(buffer->name); + destroy_gl_framebuffer(&buffer->buffer); + free(buffer); +} + +void mri_framebuffer_bind(mri_framebuffer *buffer, bool clear) { + bind_gl_framebuffer(&buffer->buffer, clear); } + diff --git a/src/texture.h b/src/texture.h index 58e3b67..706beb1 100644 --- a/src/texture.h +++ b/src/texture.h @@ -4,6 +4,7 @@ #include #include +#include "gl.h" #include "assets.h" typedef enum { @@ -32,8 +33,7 @@ typedef struct { int width, height; int texture_width, texture_height; - // opengl specific - unsigned int texture_id; + gl_texture texture; vec4 texture_resolution; @@ -48,7 +48,19 @@ typedef struct { mri_texture_version version; } mri_texture; +typedef struct { + mstr *name; + float width, height; + gl_framebuffer buffer; + mri_texture texture; +} mri_framebuffer; + mri_texture *mri_texture_load(mri_asset *_asset); void mri_texture_unload(mri_texture *texture); +void mri_texture_bind(mri_texture *t, int index); + +mri_framebuffer *mri_framebuffer_load(mstr *name, float width, float height, float scale); +void mri_framebuffer_unload(mri_framebuffer *buffer); +void mri_framebuffer_bind(mri_framebuffer *buffer, bool clear); #endif // _TEXTURE_H diff --git a/src/util.c b/src/util.c index d637856..f71761b 100644 --- a/src/util.c +++ b/src/util.c @@ -4,15 +4,9 @@ #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) { + return 0; unsigned long hash = 5381; int c; diff --git a/src/util.h b/src/util.h index dc56464..8493a39 100644 --- a/src/util.h +++ b/src/util.h @@ -1,23 +1,6 @@ #ifndef _UTIL_H #define _UTIL_H -#include - -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 -- cgit v1.2.3-101-g0448