diff options
-rw-r--r-- | shaders/rect.frag | 36 | ||||
-rw-r--r-- | shaders/rect.vert | 18 | ||||
-rw-r--r-- | test/pugl_gl3_test.c | 76 | ||||
-rw-r--r-- | wscript | 7 |
4 files changed, 94 insertions, 43 deletions
diff --git a/shaders/rect.frag b/shaders/rect.frag new file mode 100644 index 0000000..d128f37 --- /dev/null +++ b/shaders/rect.frag @@ -0,0 +1,36 @@ +#version 330 + +/* The fragment shader uses the UV coordinates to calculate whether it is in + the T, R, B, or L border. These are then mixed with the border color, and + their inverse is mixed with the fill color, to calculate the fragment color. + For example, if we are in the top border, then T=1, so the border mix factor + TRBL=1, and the fill mix factor (1-TRBL) is 0. + + The use of pixel units here is handy because the border width can be + specified precisely in pixels to draw sharp lines. The border width is just + hardcoded, but could be made a uniform or vertex attribute easily enough. */ + +uniform vec2 u_size; +uniform vec4 u_borderColor; +uniform vec4 u_fillColor; + +noperspective in vec2 f_uv; + +layout(location = 0) out vec4 FragColor; + +void +main() +{ + const float border_width = 2.0; + + float t = step(border_width, f_uv[1]); + float r = step(border_width, u_size.x - f_uv[0]); + float b = step(border_width, u_size.y - f_uv[1]); + float l = step(border_width, f_uv[0]); + float fill_mix = t * r * b * l; + float border_mix = 1.0 - fill_mix; + vec4 fill = fill_mix * u_fillColor; + vec4 border = border_mix * u_borderColor; + + FragColor = fill + border; +} diff --git a/shaders/rect.vert b/shaders/rect.vert new file mode 100644 index 0000000..34fe0b3 --- /dev/null +++ b/shaders/rect.vert @@ -0,0 +1,18 @@ +#version 330 + +/* The vertex shader is trivial, but forwards scaled UV coordinates (in pixels) + to the fragment shader for drawing the border. */ + +uniform mat4 MVP; +uniform vec2 u_size; + +in vec2 v_position; + +noperspective out vec2 f_uv; + +void +main() +{ + f_uv = v_position * u_size; + gl_Position = MVP * vec4(v_position, 0.0, 1.0); +} diff --git a/test/pugl_gl3_test.c b/test/pugl_gl3_test.c index 8dea5a1..9ddf7db 100644 --- a/test/pugl_gl3_test.c +++ b/test/pugl_gl3_test.c @@ -73,49 +73,6 @@ static const GLfloat rectVertices[] = { static const GLuint rectIndices[4] = {0, 1, 2, 3}; -/* The vertex shader is trivial, but forwards scaled UV coordinates (in pixels) - to the fragment shader for drawing the border. */ -static const char* vertexSource = // - "#version 330\n" - "uniform mat4 MVP;\n" - "uniform vec2 u_size;\n" - "in vec2 v_position;\n" - "noperspective out vec2 f_uv;\n" - "void main() {\n" - " f_uv = v_position * u_size;\n" - " gl_Position = MVP * vec4(v_position, 0.0, 1.0);\n" - "}\n"; - -/* The fragment shader uses the UV coordinates to calculate whether it is in - the T, R, B, or L border. These are then mixed with the border color, and - their inverse is mixed with the fill color, to calculate the fragment color. - For example, if we are in the top border, then T=1, so the border mix factor - TRBL=1, and the fill mix factor (1-TRBL) is 0. - - The use of pixel units here is handy because the border width can be - specified precisely in pixels to draw sharp lines. The border width is just - hardcoded, but could be made a uniform or vertex attribute easily enough. */ -static const char* fragmentSource = // - "#version 330\n" - "uniform vec2 u_size;\n" - "uniform vec4 u_borderColor;\n" - "uniform vec4 u_fillColor;\n" - "noperspective in vec2 f_uv;\n" - "layout(location = 0) out vec4 FragColor;\n" - "void main() {\n" - " const float border_width = 2.0;\n" - "\n" - " float t = step(border_width, f_uv[1]);\n" - " float r = step(border_width, u_size.x - f_uv[0]);\n" - " float b = step(border_width, u_size.y - f_uv[1]);\n" - " float l = step(border_width, f_uv[0]);\n" - " float fill_mix = t * r * b * l;\n" - " float border_mix = 1.0 - fill_mix;\n" - " vec4 fill = fill_mix * u_fillColor;\n" - " vec4 border = border_mix * u_borderColor;\n" - " FragColor = fill + border;\n" - "}\n"; - typedef struct { PuglTestOptions opts; @@ -263,6 +220,27 @@ makeRects(const size_t numRects) return rects; } +static char* +loadShader(const char* const path) +{ + FILE* const file = fopen(path, "r"); + if (!file) { + logError("Failed to open '%s'\n", path); + return NULL; + } + + fseek(file, 0, SEEK_END); + const long fileSize = ftell(file); + + fseek(file, 0, SEEK_SET); + char* source = (char*)calloc(1, fileSize + 1); + + fread(source, 1, fileSize, file); + fclose(file); + + return source; +} + int main(int argc, char** argv) { @@ -328,8 +306,20 @@ main(int argc, char** argv) return 1; } + // Load shader sources + char* const vertexSource = loadShader("shaders/rect.vert"); + char* const fragmentSource = loadShader("shaders/rect.frag"); + if (!vertexSource || !fragmentSource) { + logError("Failed to load shader sources\n"); + puglFreeView(app.view); + puglFreeWorld(app.world); + return 1; + } + // Compile rectangle shaders and program app.drawRect = compileProgram(vertexSource, fragmentSource); + free(fragmentSource); + free(vertexSource); if (!app.drawRect.program) { puglFreeView(app.view); puglFreeWorld(app.world); @@ -284,6 +284,13 @@ def build(bld): **kwargs) if bld.env.BUILD_TESTS: + for s in ('rect.vert', 'rect.frag'): + # Copy shaders to build directory for test programs + bld(features = 'subst', + is_copy = True, + source = 'shaders/%s' % s, + target = 'shaders/%s' % s) + if bld.env.HAVE_GL: build_test('pugl_test', ['test/pugl_test.c'], platform, 'gl', uselib=['GL', 'M']) |