git.haldean.org ana / 8be87ea src / shaders.cpp
8be87ea

Tree @8be87ea (Download .tar.gz)

shaders.cpp @8be87earaw · history · blame

#include "shaders.hpp"
#include "glerr.hpp"
#include "node.hpp"
#include "wbogl/shader_utils.hpp"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <string>

namespace ana {
namespace shaders {

static const std::string node_vert_src = R"(
#version 330 core
layout (location = 0) in vec4 data;

out NODE_DATA {
    vec2 size;
} node_data;

uniform mat4 viewport;

void main(void) {
    gl_Position = viewport * vec4(data[0], data[1], 0.0, 1.0);
    vec4 s = viewport * vec4(data[2], data[3], 0.0, 0.0);
    node_data.size = vec2(s[0], s[1]);
}
)";

static const std::string node_frag_src = R"(
#version 330 core
out vec4 Color;

void main()
{
    Color = vec4(1.0, 1.0, 1.0, 0.8);
}
)";

static const std::string node_geo_src = R"(
#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 4) out;
in NODE_DATA {
    vec2 size;
} nd[];

void main() {
    vec4 p = gl_in[0].gl_Position;
    vec2 s = nd[0].size;
    gl_Position = p;
    EmitVertex();
    gl_Position = p + vec4(s[0], 0, 0, 0);
    EmitVertex();
    gl_Position = p + vec4(0, s[1], 0, 0);
    EmitVertex();
    gl_Position = p + vec4(s[0], s[1], 0, 0);
    EmitVertex();
    EndPrimitive();
}
)";

static GLuint node_vao;
static GLuint node_program_id;

static GLint node_data_attr;
static GLint node_viewport_attr;

static GLuint node_data_buf;

bool init(void) {
    GLuint vs, fs, gs;
    if (!(vs = create_shader_from_string(node_vert_src, GL_VERTEX_SHADER))) {
        std::cerr << "[E] vert shader couldn't be loaded" << std::endl;
        return false;
    }
    if (!(fs = create_shader_from_string(node_frag_src, GL_FRAGMENT_SHADER))) {
        std::cerr << "[E] frag shader couldn't be loaded" << std::endl;
        return false;
    }
    if (!(gs = create_shader_from_string(node_geo_src, GL_GEOMETRY_SHADER))) {
        std::cerr << "[E] geometry shader couldn't be loaded" << std::endl;
        return false;
    }
    node_program_id = glCreateProgram();
    glAttachShader(node_program_id, vs);
    glAttachShader(node_program_id, fs);
    glAttachShader(node_program_id, gs);
    glLinkProgram(node_program_id);
    GLint link_ok;
    glGetProgramiv(node_program_id, GL_LINK_STATUS, &link_ok);
    if (!link_ok) {
        std::cerr << "[E] glLinkProgram: ";
        print_log(node_program_id);
        std::cerr << std::endl << "vert src:" << std::endl << node_vert_src;
        std::cerr << std::endl << "frag src:" << std::endl << node_frag_src;
        std::cerr << std::endl << "geo src:" << std::endl << node_geo_src;
        node_program_id = 0;
        return false;
    }

    node_data_attr = glGetAttribLocation(node_program_id, "data");
    if (node_data_attr == -1) {
        std::cerr << "[E] glGetAttribLocation failed for node data" << std::endl;
        return false;
    }

    node_viewport_attr = glGetUniformLocation(node_program_id, "viewport");
    if (node_viewport_attr == -1) {
        std::cerr << "[E] glGetAttribLocation failed for viewport matrix" << std::endl;
        return false;
    }

    glGenVertexArrays(1, &node_vao);
    INSERT_GL_ERROR_CHECK;
    glBindVertexArray(node_vao);
    INSERT_GL_ERROR_CHECK;
    glGenBuffers(1, &node_data_buf);
    INSERT_GL_ERROR_CHECK;
    glBindVertexArray(0);

    return true;
}

void draw(const ana::ui &ui, const ana::nodeset &nodes) {
    static GLfloat *node_data = nullptr;
    static size_t node_data_size = 0;

    size_t elems = nodes.size() * 4;
    if (elems != node_data_size) {
        node_data = (GLfloat*) reallocarray(node_data, elems, sizeof(GLfloat));
    }
    int i = 0;
    for (const ana::node &n : nodes.nodes) {
        node_data[4 * i + 0] = n.loc.x;
        node_data[4 * i + 1] = n.loc.y;
        node_data[4 * i + 2] = n.size.x;
        node_data[4 * i + 3] = n.size.y;
        i++;
    }

    glUseProgram(node_program_id); INSERT_GL_ERROR_CHECK;

    glBindVertexArray(node_vao); INSERT_GL_ERROR_CHECK;
    glBindBuffer(GL_ARRAY_BUFFER, node_data_buf); INSERT_GL_ERROR_CHECK;
    glBufferData(GL_ARRAY_BUFFER, elems * sizeof(GLfloat), node_data, GL_DYNAMIC_DRAW); INSERT_GL_ERROR_CHECK;

    glm::mat4 m = glm::ortho(
        ui.center.x - ui.view, ui.center.x + ui.view,
        ui.center.y - ui.view * ui.aspect, ui.center.y + ui.view * ui.aspect,
        -1.f, 1.f);
    glUniformMatrix4fv(node_viewport_attr, 1, GL_FALSE, glm::value_ptr(m));

    glEnableVertexAttribArray(node_data_attr); INSERT_GL_ERROR_CHECK;
    glBindBuffer(GL_ARRAY_BUFFER, node_data_buf); INSERT_GL_ERROR_CHECK;
    glVertexAttribPointer(node_data_attr, 4, GL_FLOAT, GL_FALSE, 0, 0); INSERT_GL_ERROR_CHECK;

    glDrawArrays(GL_POINTS, 0, nodes.size()); INSERT_GL_ERROR_CHECK;
    glDisableVertexAttribArray(node_data_attr); INSERT_GL_ERROR_CHECK;
    glBindVertexArray(0);
}

void destroy(void) {
    glDeleteProgram(node_program_id);
    glDeleteBuffers(1, &node_data_buf);
}

}
}