#include "shaders.hpp"
#include "glerr.hpp"
#include "node.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;
void print_log(GLuint object) {
GLint log_length = 0;
if (glIsShader(object)) {
glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length);
} else if (glIsProgram(object)) {
glGetProgramiv(object, GL_INFO_LOG_LENGTH, &log_length);
} else {
std::cerr << "print_log called with invalid object" << std::endl;
return;
}
char* log = (char*)malloc(log_length);
if (glIsShader(object))
glGetShaderInfoLog(object, log_length, NULL, log);
else if (glIsProgram(object))
glGetProgramInfoLog(object, log_length, NULL, log);
std::cerr << log << std::endl;
free(log);
}
GLuint create_shader_from_string(const std::string &src, GLenum type) {
GLuint res = glCreateShader(type);
const GLchar *csrc = src.c_str();
GLint len = src.length();
glShaderSource(res, 1, &csrc, &len);
glCompileShader(res);
GLint compile_ok = GL_FALSE;
glGetShaderiv(res, GL_COMPILE_STATUS, &compile_ok);
if (compile_ok == GL_FALSE) {
std::cerr << "[E] error loading shader: " << std::endl;
print_log(res);
glDeleteShader(res);
return 0;
}
return res;
}
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;
std::cout << "new center: " << ui.center.x << ", " << ui.center.y << std::endl;
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);
}
}
}