diff --git a/res/sh.geom.glsl b/res/sh.geom.glsl new file mode 100644 index 0000000..8900a0e --- /dev/null +++ b/res/sh.geom.glsl @@ -0,0 +1,25 @@ +#version 330 core +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; // output the vertices of this rectangle + +void push_vert(float x, float y) { + gl_Position = vec4(x, y, 0.0F, 1.0F); + EmitVertex(); +} + +void main() { + // position data is stored as (x,y,w,h) + vec4 rect_a = gl_in[0].gl_Position; // get the rectangle data which will be our first point of the rectangle + vec2 rect_d = vec2( // compute point D + rect_a.x + rect_a.z, + rect_a.y - rect_a.w); + + // A---B + // C---D + // triangle_strip will use the last two vertices to create a triangle + push_vert(rect_a.x, rect_a.y); // A + push_vert(rect_d.x, rect_a.y); // B + push_vert(rect_a.x, rect_d.y); // C + push_vert(rect_d.x, rect_d.y); // D + EndPrimitive(); +} diff --git a/res/sh.vert.glsl b/res/sh.vert.glsl index ad355fa..d867fca 100644 --- a/res/sh.vert.glsl +++ b/res/sh.vert.glsl @@ -1,7 +1,22 @@ #version 330 core +layout(location = 0) in ivec4 rect; // rectangle data +uniform ivec2 screen; // current screen dimensions -layout(location = 0) in vec4 pos; - +/* this vertex shader takes in unsigned integers formatted as (x,y,w,h), which denote rectangles + * the shader is responsible to output the data for this rectangle in the same format, + * but transformed to match the OpenGL coördinate space. + * I found the formula `(x-0.5*l)/0.5*l` to work well for scaling an axis to fit within the -1—1 coördinate space. + * And for transforming width/height, you just divide by the length of the corresponding axis. + * I demonstrate this here: https://www.desmos.com/calculator/ptwuyiv6bh */ void main() { - gl_Position = vec4(pos.x, pos.y, 0.0F, 1.0F); + // divide the screen x and y coördinates by 2 + // using bit shift because I don't trust the compiler optimiser since I've got less control. + int w_2 = screen.x >> 1; + int h_2 = screen.y >> 1; + + gl_Position = vec4( + (rect.x - w_2) / float(w_2), // scale the rect X point + (screen.y - rect.y - h_2) / float(h_2), // scale the rect Y point and invert the axis for top left alignment + rect.z / float(w_2), // scale the rect width + rect.w / float(h_2)); // scale the rect height } diff --git a/src/io/render.c b/src/io/render.c index 5defc5a..edfab46 100644 --- a/src/io/render.c +++ b/src/io/render.c @@ -8,23 +8,27 @@ #include #include -#include "../util/vec/float2.h" -#include "shader.h" #include "../error.h" +#include "shader.h" -#define VERTC 6 -GLuint pipe; -float2 verts[VERTC] = { - {-1, -1 }, // pnt A - {1, -1 }, // pnt B - {1, -0.9F}, // pnt C +// include GLFW +#include - {-1, -0.9F}, // pnt D - {1, -0.9F}, // pnt C - {-1, -1 }, // pnt A -}; -GLuint vbo; // vertex buffer object -GLuint vao; // vertex array object +#define VERTC 1 +static GLuint pipe; +static GLuint vbo; // vertex buffer object +static GLuint vao; // vertex array object +static GLuint screen_loc; // location to where OpenGL sends to the shaders of the screen dimensions + +static void screen_resize(int w, int h) { + int32_t verts[VERTC][4] = { + {0, h, w, -20}, + }; + + glUniform2i(screen_loc, w, h); // send the screen dimensions to the shader pipeline + glViewport(0, 0, w, h); // update the viewport + glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_DYNAMIC_DRAW); // bind the data to it +} int render_init(void) { pipe = glCreateProgram(); @@ -32,11 +36,6 @@ int render_init(void) { glLinkProgram(pipe); // link the application glValidateProgram(pipe); // validate that what we've done is correct - // init the VBO - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); - int len; glGetProgramiv(pipe, GL_INFO_LOG_LENGTH, &len); if (len > 0) { @@ -46,14 +45,18 @@ int render_init(void) { fatal("error whilst linking the pipe: '%s'", log); } - // init the VAO + screen_loc = glGetUniformLocation(pipe, "screen"); + + glGenBuffers(1, &vbo); // create the vertex buffer objects + glBindBuffer(GL_ARRAY_BUFFER, vbo); // bind to it + glGenVertexArrays(1, &vao); glBindVertexArray(vao); // set VBO info glBindBuffer(GL_ARRAY_BUFFER, vbo); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float2), NULL); + glVertexAttribIPointer(0, 4, GL_INT, 4 * sizeof(int32_t), NULL); glBindVertexArray(0); return 0; @@ -65,11 +68,16 @@ void render_update(GLFWwindow* win) { int w, h; glfwGetWindowSize(win, &w, &h); - glViewport(0, 0, w, h); - glClearColor(0.1F, 0.1F, 0.1F, 1.0F); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glUseProgram(pipe); + static int d = -1; // initialize d to an impossible value so the condition below is always true on first execution + if ((h ^ w) != d) { // false negative when h and w swap integers, but this is quite a rare occurrence and it's impact is minimal + screen_resize(w, h); + d = h ^ w; + } + + glClearColor(0.1F, 0.1F, 0.1F, 1.0F); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glBindVertexArray(vao); - glDrawArrays(GL_TRIANGLES, 0, VERTC); + glDrawArrays(GL_POINTS, 0, VERTC); } diff --git a/src/io/shader.c b/src/io/shader.c index 439d55f..6b44c08 100644 --- a/src/io/shader.c +++ b/src/io/shader.c @@ -16,6 +16,8 @@ extern char const NAM_S(sh_vert_glsl)[]; extern char const NAM_E(sh_vert_glsl)[]; extern char const NAM_S(sh_frag_glsl)[]; extern char const NAM_E(sh_frag_glsl)[]; +extern char const NAM_S(sh_geom_glsl)[]; +extern char const NAM_E(sh_geom_glsl)[]; // NOLINTEND /* compile a shader */ @@ -41,10 +43,14 @@ static GLuint shader_compile(GLenum type, char const* src, size_t len) { int shader_init(GLuint pipe) { GLuint vs = COMPILE_NAME(GL_VERTEX_SHADER, sh_vert_glsl); GLuint fs = COMPILE_NAME(GL_FRAGMENT_SHADER, sh_frag_glsl); + GLuint gs = COMPILE_NAME(GL_GEOMETRY_SHADER, sh_geom_glsl); glAttachShader(pipe, vs); glAttachShader(pipe, fs); + glAttachShader(pipe, gs); + glDeleteShader(vs); glDeleteShader(fs); + glDeleteShader(gs); return 1; }