diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2020-07-31 16:54:31 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2020-07-31 16:54:31 -0700 |
commit | 94de2291e005f1c646fd779e8d32b2820e22e071 (patch) | |
tree | 988bb9fde53a73edf948dd14fec07802a2f42406 /src/shader-node.c | |
parent | cd7e9ebd9675461f59d5f7a9c7c0a9a1a0536d12 (diff) |
*: initial implementation of pig
This is nothing to write home about, but it provides a little sandbox for
developing shader-generated textures in the spirit of shadertoy or the
demoscene tool bonzomatic.
It's more oriented towards developing shaders for use with libstage in
the small games I've been hacking on.
Diffstat (limited to 'src/shader-node.c')
-rw-r--r-- | src/shader-node.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/shader-node.c b/src/shader-node.c new file mode 100644 index 0000000..aa4f0b7 --- /dev/null +++ b/src/shader-node.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2018-2019 - Vito Caputo - <vcaputo@pengaru.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <stdlib.h> + +#include <stage.h> + +#include "glad.h" +#include "m4f.h" +#include "macros.h" +#include "shader.h" +#include "shader-node.h" + +typedef struct shader_node_t { + shader_t *shader; + shader_node_uniforms_func_t *uniforms_func; + void *uniforms_ctxt; + const m4f_t *transform; +} shader_node_t; + +static unsigned vbo, tcbo; + +static const float vertices[] = { + +1.f, +1.f, 0.f, + +1.f, -1.f, 0.f, + -1.f, +1.f, 0.f, + +1.f, -1.f, 0.f, + -1.f, -1.f, 0.f, + -1.f, +1.f, 0.f, +}; + + +/* TODO: verify that this is OK, I recall tutorials stating these are always + * in the range 0-1, but it seems perfectly OK to use -1..+1 which is more + * convenient here where these shader-textured quads appreciate being fed + * unit square coordinates with 0,0 @ the center. + */ +static const float texcoords[] = { + 1.f, 1.f, + 1.f, -1.f, + -1.f, 1.f, + 1.f, -1.f, + -1.f, -1.f, + -1.f, 1.f, +}; + + +/* TODO: the vertex shader should probably just be private to this listing, and maybe + * shader_pair_new() should be refactored to lookup uniforms and attributes as a + * separate step... + */ +static const char * shader_node_attributes[] = { + "i_vertex", + "i_texcoord" +}; + +static void shader_node_render(const stage_t *stage, void *object, float alpha, void *render_ctxt) +{ + shader_node_t *shader_node = object; + unsigned n_uniforms, n_attributes; + int *uniforms, *attributes; + + assert(stage); + assert(shader_node); + + shader_use(shader_node->shader, &n_uniforms, &uniforms, &n_attributes, &attributes); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glVertexAttribPointer(attributes[0], 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, tcbo); + glVertexAttribPointer(attributes[1], 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + //glTexCoordPointer(2, GL_FLOAT, 0, 0); + + /* XXX: this could be made optional, but since alpha is a constant throughout the stage + * integration I'm just always turning it on so stage_set_alpha() always works. There + * are definitely full-screen full-opaque shader node situations where the pointless + * performance hit sucks though, especially on older hardware. + */ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if (shader_node->uniforms_func) + shader_node->uniforms_func(shader_node->shader, shader_node->uniforms_ctxt, render_ctxt, n_uniforms, uniforms, shader_node->transform, alpha); + + glDrawArrays(GL_TRIANGLES, 0, 6); + glUseProgram(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + + +static void shader_node_free(const stage_t *stage, void *object) +{ + shader_node_t *shader_node = object; + + assert(stage); + assert(shader_node); + + /* XXX FIXME: hmm, maybe the caller should supply a shader_t ** instead */ + (void) shader_free(shader_node->shader); + free(shader_node); +} + + +static const stage_ops_t shader_node_ops = { + .render_func = shader_node_render, + .free_func = shader_node_free, +}; + +/* return a new shader stage node from an already compiled and linked shader program */ +stage_t * shader_node_new_shader(const stage_conf_t *conf, shader_t *shader, const m4f_t *transform, shader_node_uniforms_func_t *uniforms_func, void *uniforms_ctxt) +{ + shader_node_t *shader_node; + stage_t *stage; + + assert(conf); + assert(shader); + + if (!vbo) { + /* common to all shader nodes */ + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glGenBuffers(1, &tcbo); + glBindBuffer(GL_ARRAY_BUFFER, tcbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords), texcoords, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + shader_node = calloc(1, sizeof(shader_node_t)); + fatal_if(!shader_node, "Unable to allocate shader_node"); + + shader_ref(shader); + shader_node->shader = shader; + shader_node->uniforms_func = uniforms_func; + shader_node->uniforms_ctxt = uniforms_ctxt; + shader_node->transform = transform; + + stage = stage_new(conf, &shader_node_ops, shader_node); + fatal_if(!stage, "Unable to create stage \"%s\"", conf->name); + + return stage; +} + + +/* return a new shader stage node from source */ +stage_t * shader_node_new_src(const stage_conf_t *conf, const char *vs_src, const char *fs_src, const m4f_t *transform, shader_node_uniforms_func_t *uniforms_func, void *uniforms_ctxt, unsigned n_uniforms, const char **uniforms) +{ + stage_t *stage; + shader_t *shader; + + assert(vs_src); + assert(fs_src); + + shader = shader_pair_new(vs_src, fs_src, n_uniforms, uniforms, NELEMS(shader_node_attributes), shader_node_attributes); + stage = shader_node_new_shader(conf, shader, transform, uniforms_func, uniforms_ctxt); + shader_free(shader); + + return stage; +} + + +stage_t * shader_node_new_files(const stage_conf_t *conf, const char *vs_path, const char *fs_path, const m4f_t *transform, shader_node_uniforms_func_t *uniforms_func, void *uniforms_ctxt, unsigned n_uniforms, const char **uniforms) +{ + stage_t *stage; + shader_t *shader; + + assert(vs_path); + assert(fs_path); + + shader = shader_pair_new_files(vs_path, fs_path, n_uniforms, uniforms, NELEMS(shader_node_attributes), shader_node_attributes); + stage = shader_node_new_shader(conf, shader, transform, uniforms_func, uniforms_ctxt); + shader_free(shader); + + return stage; +} |