summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules6
-rw-r--r--TODO1
-rw-r--r--meson.build6
-rw-r--r--src/assets.c149
-rw-r--r--src/assets.h33
-rw-r--r--src/context.h6
-rw-r--r--src/context_glfw.c12
-rw-r--r--src/engine.c175
-rw-r--r--src/engine.h72
-rw-r--r--src/gl.c212
-rw-r--r--src/gl.h55
-rw-r--r--src/json.c41
-rw-r--r--src/json.h9
-rw-r--r--src/log.h2
-rw-r--r--src/mauri.c15
-rw-r--r--src/objects/effect.c59
-rw-r--r--src/objects/effect.h18
-rw-r--r--src/objects/material.c38
-rw-r--r--src/objects/material.h7
-rw-r--r--src/objects/model.c17
-rw-r--r--src/objects/model.h8
-rw-r--r--src/objects/object.c82
-rw-r--r--src/objects/object.h19
-rw-r--r--src/objects/pass.c212
-rw-r--r--src/objects/pass.h26
-rw-r--r--src/objects/scene.c30
-rw-r--r--src/objects/scene.h6
-rw-r--r--src/objects/types.h11
-rw-r--r--src/shader.c283
-rw-r--r--src/shader.h32
-rw-r--r--src/texture.c108
-rw-r--r--src/texture.h16
-rw-r--r--src/util.c8
-rw-r--r--src/util.h17
m---------subprojects/moro0
36 files changed, 1403 insertions, 389 deletions
diff --git a/.gitignore b/.gitignore
index a5309e6..b2d8280 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
build*/
+random.sh
diff --git a/.gitmodules b/.gitmodules
index b99ac04..26f663b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,9 +4,9 @@
[submodule "subprojects/glfw"]
path = subprojects/glfw
url = https://github.com/glfw/glfw.git
-[submodule "subprojects/moro"]
- path = subprojects/moro
- url = git@github.com:Pizzabelly/moro.git
[submodule "subprojects/jansson"]
path = subprojects/jansson
url = https://github.com/akheron/jansson.git
+[submodule "subprojects/moro"]
+ path = subprojects/moro
+ url = git@github.com:Pizzabelly/moro.git
diff --git a/TODO b/TODO
index 295ea59..cb255ed 100644
--- a/TODO
+++ b/TODO
@@ -1 +1,2 @@
[ ] shader loading
+[ ] store uniform location on the uniform object
diff --git a/meson.build b/meson.build
index 893c191..0a3f83b 100644
--- a/meson.build
+++ b/meson.build
@@ -2,6 +2,8 @@ project('mauri', 'c',
version : '0.1',
default_options : ['warning_level=2', 'c_std=c99'])
+add_project_arguments('-D_GNU_SOURCE', language : 'c')
+
if get_option('buildtype').startswith('debug')
add_project_arguments('-D_DEBUG_', language : 'c')
endif
@@ -27,11 +29,13 @@ src = [
'src/shader.c',
'src/context.c',
'src/context_glfw.c',
+ 'src/engine.c',
'src/objects/scene.c',
'src/objects/object.c',
'src/objects/model.c',
'src/objects/material.c',
- 'src/objects/pass.c'
+ 'src/objects/pass.c',
+ 'src/objects/effect.c'
]
executable('mauri', src, dependencies: deps, install: true)
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 <stdio.h>
#include <stdlib.h>
@@ -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 <stdbool.h>
-#include <moro_vec.h>
+#include <moro.h>
#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 <cglm/cglm.h>
+
+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 <cglm/cglm.h>
+
+#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 <glad/gl.h>
#include <stddef.h>
+#include <moro.h>
+
#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 <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);
+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 <cglm/cglm.h>
#include <stdbool.h>
+#include <moro_str.h>
+
+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 <stdio.h>
#include <string.h>
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 <stdio.h>
+#include <moro_str.h>
#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 <moro.h>
+
+#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 <moro_str.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);
+ 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 <jansson.h>
+#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 <jansson.h>
+#include <moro_str.h>
#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 <jansson.h>
+#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 <jansson.h>
+#include <cglm/cglm.h>
+#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 <moro_vec.h>
+#include <moro.h>
#include <jansson.h>
#include <stdbool.h>
#include <cglm/cglm.h>
+#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 <jansson.h>
+#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 <cglm/cglm.h>
#include <moro_vec.h>
+#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 <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <jansson.h>
+#include <glad/gl.h>
+
+#include <moro.h>
#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;
-
- char *source = (char *)malloc(source_len);
- source[source_index] = '\0';
+static mstr *build_shader_source(mri_shader *shader, mstr *isource, bool start) {
+ mstr *source = mstr_from("\0");
- if (first) {
- source_index += strlen(gl_compat) + 1;
- strncat(source, gl_compat, source_index);
- }
+ if (start)
+ mstr_cat(source, mstr_c(gl_compat));
- char *line = buffer;
+ mstr line = {0};
- while (line) {
- char *next_line = strchr(line, '\n');
- size_t len = next_line ? (size_t)(next_line - line) : strlen(line);
+ while (mstr_get_line(isource, &line)) {
+ bool cut_line = false;
- if (memcmp(line, "#include", 8) == 0) {
- char *open = strchr(line, '"') + 1;
- char *close = strchr(open, '"') + 1;
+ if (mstr_eqn(&line, mstr_c("#include"), 8)) {
+ mstr inc_name = mstr_substr(&line, mstr_find(&line, '"') + 1, mstr_rfind(&line, '"'));
- char *include = (char *)malloc(close - open);
- snprintf(include, close - open, "%s", open);
+ mri_asset *inc_asset = mri_asset_manager_get(&inc_name, SHADER);
+ mstr *inc = build_shader_source(shader, mri_asset_as_str(inc_asset), false);
- mri_asset *include_asset = mri_asset_manager_get(include, SHADER);
+ mstr_cat(source, inc);
+ mstr_free(inc);
- if (include_asset->type == ASSET_VOID) {
- return NULL;
- }
+ cut_line = true;
+ } else if (mstr_eqn(&line, mstr_c("uniform"), 7)) {
+ mri_uniform *u = mvec_next(shader->uniforms);
- 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);
+ mstr type = mstr_substr(&line, mstr_find(&line, ' ') + 1, mstr_len(&line));
- if (!include_src) {
- return NULL;
+ 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++;
}
- size_t include_len = strlen(include_src);
+ u->uname = mstr_substr_copy(&type, mstr_find(&type, ' ') + 1, mstr_find(&type, ';'));
- if (!(source = realloc(source, source_len + include_len))) {
- log_error("%s", "failed to allocate memory for shader source");
- abort(); // fatal
- }
+ ptrdiff_t combo_start = mstr_find(&line, '/');
- strncat(source, include_src, include_len + 1);
- source_index += include_len + 1;
+ if (combo_start >= 0) {
+ mstr combo_str = mstr_substr(&line, combo_start + 2, mstr_len(&line));
- 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_t *root = json_load_mstr(&combo_str);
- mri_uniform *u = &mvec_last(shader->uniforms);
+ if (!root) continue;
- char *type_start = strchr(line, ' ') + 1;
- char *type_end = strchr(type_start, ' ') + 1;
+ json_t *label = json_object_get(root, "label");
+ json_t *material = json_object_get(root, "material");
- char *type = (char *)malloc(type_end - type_start);
- snprintf(type, type_end - type_start, "%s", type_start);
+ 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)));
- 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;
+ 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));
- char *name_end = strchr(type_end, ';') + 1;
+ json_t *root = json_load_mstr(&combo);
- u->uname = (char *)malloc(name_end - type_end);
- snprintf(u->uname, name_end - type_end, "%s", type_end);
+ mri_combo c = {
+ .name = mstr_from(json_string_value(json_object_get(root, "combo"))),
+ .value = json_integer_value(json_object_get(root, "default"))
+ };
- char *combo_start = strchr(line, '/');
+ mvec_push(shader->combos, c);
- if (combo_start && combo_start - line < len) {
- // parse combo
- }
- } else {
- strncat(source, line, len + 1);
- source_index += len + 1;
- source[source_index] = '\0';
+ json_decref(root);
}
- line = next_line ? next_line + 1 : NULL;
+ if (!cut_line) {
+ mstr_cat(source, &line);
+ mstr_cat(source, mstr_c("\n"));
+ }
}
return source;
}
-void mri_shader_load(mri_shader *shader, const char *name) {
+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;
+}
+
+void mri_shader_compile(mri_shader *shader) {
+ mstr *vs_source = mstr_clone(shader->vs_source);
+ mstr *fs_source = mstr_clone(shader->fs_source);
+
+ 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);
+ }
+
+ mstr_prepend(vs_source, mstr_c(version));
+ mstr_prepend(fs_source, mstr_c(version));
+
+ char *vs_source_c = mstr_to_cstr(vs_source);
+ char *fs_source_c = mstr_to_cstr(fs_source);
+
+ create_gl_shader(&shader->gl_shader, vs_source_c, fs_source_c);
+
+ free(vs_source_c);
+ free(fs_source_c);
+
+ mstr_free(vs_source);
+ mstr_free(fs_source);
+}
+
+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);
+ }
- free(vertex_str);
+ mri_asset *fs_asset = mri_asset_manager_get(name, FRAGMENT_SHADER);
+
+ 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);
}
+}
- 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);
+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);
+ }
- if (!shader->fragment_source) {
- log_error("failed to parse shader (%s.frag)", name);
- }
+ set_gl_uniform(uniform->loc, uniform->type, uniform->value);
+}
+
+void mri_shader_bind(mri_engine *engine, mri_shader *shader, mat4 mvp) {
+ bind_gl_shader(&shader->gl_shader);
- free(fragment_str);
+ 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]);
+
+ 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 <moro_str.h>
+
+#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 <stb_image.h>
+
#include <lz4.h>
+#include <moro.h>
#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 <stdbool.h>
#include <cglm/cglm.h>
+#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 <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
diff --git a/subprojects/moro b/subprojects/moro
-Subproject 60d4fed94c6d2acbba7a64b95fc52140d36ad40
+Subproject fb15eafe3d50bf99881caa6b1968223df362e95