mirror of
https://github.com/thepigeongenerator/mcaselector-lite.git
synced 2025-12-17 09:35:46 +01:00
use a geometry shader to render rectangles
This commit is contained in:
25
res/sh.geom.glsl
Normal file
25
res/sh.geom.glsl
Normal file
@@ -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();
|
||||||
|
}
|
||||||
@@ -1,7 +1,22 @@
|
|||||||
#version 330 core
|
#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() {
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,23 +8,27 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "../util/vec/float2.h"
|
|
||||||
#include "shader.h"
|
|
||||||
#include "../error.h"
|
#include "../error.h"
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
#define VERTC 6
|
// include GLFW
|
||||||
GLuint pipe;
|
#include <GLFW/glfw3.h>
|
||||||
float2 verts[VERTC] = {
|
|
||||||
{-1, -1 }, // pnt A
|
|
||||||
{1, -1 }, // pnt B
|
|
||||||
{1, -0.9F}, // pnt C
|
|
||||||
|
|
||||||
{-1, -0.9F}, // pnt D
|
#define VERTC 1
|
||||||
{1, -0.9F}, // pnt C
|
static GLuint pipe;
|
||||||
{-1, -1 }, // pnt A
|
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},
|
||||||
};
|
};
|
||||||
GLuint vbo; // vertex buffer object
|
|
||||||
GLuint vao; // vertex array object
|
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) {
|
int render_init(void) {
|
||||||
pipe = glCreateProgram();
|
pipe = glCreateProgram();
|
||||||
@@ -32,11 +36,6 @@ int render_init(void) {
|
|||||||
glLinkProgram(pipe); // link the application
|
glLinkProgram(pipe); // link the application
|
||||||
glValidateProgram(pipe); // validate that what we've done is correct
|
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;
|
int len;
|
||||||
glGetProgramiv(pipe, GL_INFO_LOG_LENGTH, &len);
|
glGetProgramiv(pipe, GL_INFO_LOG_LENGTH, &len);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
@@ -46,14 +45,18 @@ int render_init(void) {
|
|||||||
fatal("error whilst linking the pipe: '%s'", log);
|
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);
|
glGenVertexArrays(1, &vao);
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
// set VBO info
|
// set VBO info
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float2), NULL);
|
glVertexAttribIPointer(0, 4, GL_INT, 4 * sizeof(int32_t), NULL);
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -65,11 +68,16 @@ void render_update(GLFWwindow* win) {
|
|||||||
|
|
||||||
int w, h;
|
int w, h;
|
||||||
glfwGetWindowSize(win, &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);
|
glUseProgram(pipe);
|
||||||
|
|
||||||
glBindVertexArray(vao);
|
static int d = -1; // initialize d to an impossible value so the condition below is always true on first execution
|
||||||
glDrawArrays(GL_TRIANGLES, 0, VERTC);
|
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_POINTS, 0, VERTC);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ extern char const NAM_S(sh_vert_glsl)[];
|
|||||||
extern char const NAM_E(sh_vert_glsl)[];
|
extern char const NAM_E(sh_vert_glsl)[];
|
||||||
extern char const NAM_S(sh_frag_glsl)[];
|
extern char const NAM_S(sh_frag_glsl)[];
|
||||||
extern char const NAM_E(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
|
// NOLINTEND
|
||||||
|
|
||||||
/* compile a shader */
|
/* compile a shader */
|
||||||
@@ -41,10 +43,14 @@ static GLuint shader_compile(GLenum type, char const* src, size_t len) {
|
|||||||
int shader_init(GLuint pipe) {
|
int shader_init(GLuint pipe) {
|
||||||
GLuint vs = COMPILE_NAME(GL_VERTEX_SHADER, sh_vert_glsl);
|
GLuint vs = COMPILE_NAME(GL_VERTEX_SHADER, sh_vert_glsl);
|
||||||
GLuint fs = COMPILE_NAME(GL_FRAGMENT_SHADER, sh_frag_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, vs);
|
||||||
glAttachShader(pipe, fs);
|
glAttachShader(pipe, fs);
|
||||||
|
glAttachShader(pipe, gs);
|
||||||
|
|
||||||
glDeleteShader(vs);
|
glDeleteShader(vs);
|
||||||
glDeleteShader(fs);
|
glDeleteShader(fs);
|
||||||
|
glDeleteShader(gs);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user