add antialiased line shader

This commit is contained in:
Konstantin Käfer
2014-01-17 16:52:41 +01:00
parent 509b223fbf
commit 8443687092
12 changed files with 124 additions and 39 deletions

View File

@@ -3,6 +3,7 @@
#include "shader-fill.hpp"
#include "shader-line.hpp"
#include "shader-outline.hpp"
namespace llmr {
@@ -38,6 +39,7 @@ private:
Shader *currentShader;
FillShader *fillShader;
LineShader *lineShader;
OutlineShader *outlineShader;
uint32_t tile_stencil_buffer;
uint32_t tile_border_buffer;

View File

@@ -0,0 +1,20 @@
#ifndef LLMR_RENDERER_SHADER_OUTLINE
#define LLMR_RENDERER_SHADER_OUTLINE
#include "shader.hpp"
namespace llmr {
class OutlineShader : public Shader {
public:
OutlineShader();
int32_t a_pos;
int32_t u_matrix;
int32_t u_color;
int32_t u_world;
};
}
#endif

View File

@@ -1,7 +1,7 @@
#ifndef LLMR_RENDERER_SHADER
#define LLMR_RENDERER_SHADER
#include <vector>
#include <forward_list>
namespace llmr {
@@ -11,7 +11,7 @@ public:
~Shader();
bool valid;
uint32_t program;
std::vector<uint32_t> attributes;
std::forward_list<uint32_t> attributes;
private:
bool compileShader(uint32_t *shader, uint32_t type, const char *source);

View File

@@ -16,6 +16,7 @@ typedef struct llmr_shader llmr_shader_t;
enum {
FILL_SHADER,
LINE_SHADER,
OUTLINE_SHADER,
SHADER_COUNT
};

View File

@@ -7,6 +7,7 @@ SET(llmr_SOURCES
renderer/painter.cpp
renderer/shader-fill.cpp
renderer/shader-line.cpp
renderer/shader-outline.cpp
renderer/shader.cpp
shader/shaders.c
util/animation.cpp
@@ -25,6 +26,7 @@ SET(llmr_HEADERS
../include/llmr/renderer/painter.hpp
../include/llmr/renderer/shader-fill.hpp
../include/llmr/renderer/shader-line.hpp
../include/llmr/renderer/shader-outline.hpp
../include/llmr/renderer/shader.hpp
../include/llmr/util/animation.hpp
../include/llmr/util/math.hpp

View File

@@ -32,7 +32,8 @@ painter::painter(class transform *transform, class settings *settings)
settings(settings),
currentShader(NULL),
fillShader(NULL),
lineShader(NULL) {
lineShader(NULL),
outlineShader(NULL) {
}
@@ -41,6 +42,7 @@ void painter::setup() {
assert(fillShader);
assert(lineShader);
assert(outlineShader);
// Set up the stencil quad we're using to generate the stencil mask.
glGenBuffers(1, &tile_stencil_buffer);
@@ -63,6 +65,7 @@ void painter::setup() {
void painter::setupShaders() {
fillShader = new FillShader();
lineShader = new LineShader();
outlineShader = new OutlineShader();
}
void painter::teardown() {
@@ -143,23 +146,21 @@ void painter::render(tile::ptr tile) {
drawClippingMask();
switchShader(lineShader);
glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix);
switchShader(outlineShader);
glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix);
glStencilFunc(GL_EQUAL, 0x80, 0x80);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// glDisable(GL_STENCIL_TEST);
tile->lineVertex.bind();
glVertexAttribPointer(lineShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, BUFFER_OFFSET(0));
glUniform4f(lineShader->u_color, 0.0f, 0.0f, 0.0f, 1.0f);
glLineWidth(1.0f);
glVertexAttribPointer(outlineShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, BUFFER_OFFSET(0));
glUniform4f(outlineShader->u_color, 0.0f, 0.0f, 0.0f, 1.0f);
glUniform2f(outlineShader->u_world, transform->width, transform->height);
glLineWidth(2.0f);
glDrawArrays(GL_LINE_STRIP, 0, tile->lineVertex.length());
if (settings->debug) {
// draw tile outline
switchShader(lineShader);
@@ -189,36 +190,47 @@ void painter::viewport() {
}
// Switches to a different shader program.
void painter::switchShader(Shader *shader) {
/**
* @return boolean whether the shader was actually switched
*/
bool painter::switchShader(Shader *shader) {
if (currentShader != shader) {
glUseProgram(shader->program);
// Disable all attributes from the existing shader that aren't used in
// the new shader. Note: attribute indices are *not* program specific!
if (currentShader) {
// const std::vector<GLuint> &enabled = currentShader->attributes;
// const std::vector<GLuint> &required = shader->attributes;
// TODO
const std::forward_list<uint32_t> &hitherto = currentShader->attributes;
const std::forward_list<uint32_t> &henceforth = shader->attributes;
// for (var i = 0; i < enabled.length; i++) {
// if (required.indexOf(enabled[i]) < 0) {
// gl.disableVertexAttribArray(enabled[i]);
// }
// }
// Find all attribute indices that are used in the old shader,
// but unused in the new one.
for (uint32_t i : hitherto) {
if (std::find(henceforth.begin(), henceforth.end(), i) == henceforth.end()) {
glDisableVertexAttribArray(i);
}
}
// // Enable all attributes for the new shader.
// for (var j = 0; j < required.length; j++) {
// if (enabled.indexOf(required[j]) < 0) {
// gl.enableVertexAttribArray(required[j]);
// }
// }
// Enable all attributes for the new shader that were not already in
// use in the old one.
for (uint32_t i : henceforth) {
if (std::find(hitherto.begin(), hitherto.end(), i) == hitherto.end()) {
glEnableVertexAttribArray(i);
}
}
currentShader = shader;
} else {
// Enable all attributes for the new shader.
// Enable all attributes for the new shader (== first shader).
for (GLuint index : shader->attributes) {
glEnableVertexAttribArray(index);
}
}
}
currentShader = shader;
currentShader = shader;
return true;
} else {
return false;
}
}

View File

@@ -9,10 +9,13 @@ FillShader::FillShader()
llmr_shaders[FILL_SHADER].vertex,
llmr_shaders[FILL_SHADER].fragment
) {
if (!valid) return;
if (!valid) {
fprintf(stderr, "invalid fill shader\n");
return;
}
a_pos = glGetAttribLocation(program, "a_pos");
attributes.push_back(a_pos);
attributes.emplace_front(a_pos);
u_matrix = glGetUniformLocation(program, "u_matrix");
u_color = glGetUniformLocation(program, "u_color");

View File

@@ -2,26 +2,20 @@
#include <llmr/shader/shaders.h>
#include <llmr/platform/gl.hpp>
#include <cstdio>
using namespace llmr;
LineShader::LineShader()
: Shader(
llmr_shaders[LINE_SHADER].vertex,
llmr_shaders[LINE_SHADER].fragment
),
a_pos(42) {
) {
if (!valid) {
fprintf(stderr, "invalid line shader\n");
return;
}
GLint pos = glGetAttribLocation(program, "a_pos");
fprintf(stderr, "a_pos: %d\n", pos);
a_pos = glGetAttribLocation(program, "a_pos");
attributes.push_back(a_pos);
attributes.emplace_front(a_pos);
u_matrix = glGetUniformLocation(program, "u_matrix");
u_color = glGetUniformLocation(program, "u_color");

View File

@@ -0,0 +1,23 @@
#include <llmr/renderer/shader-outline.hpp>
#include <llmr/shader/shaders.h>
#include <llmr/platform/gl.hpp>
using namespace llmr;
OutlineShader::OutlineShader()
: Shader(
llmr_shaders[OUTLINE_SHADER].vertex,
llmr_shaders[OUTLINE_SHADER].fragment
) {
if (!valid) {
fprintf(stderr, "invalid outline shader\n");
return;
}
a_pos = glGetAttribLocation(program, "a_pos");
attributes.emplace_front(a_pos);
u_matrix = glGetUniformLocation(program, "u_matrix");
u_color = glGetUniformLocation(program, "u_color");
u_world = glGetUniformLocation(program, "u_world");
}

View File

@@ -0,0 +1,9 @@
uniform vec4 u_color;
varying vec2 v_pos;
void main() {
float dist = length(v_pos - gl_FragCoord.xy);
float alpha = smoothstep(1.0, 0.0, dist);
gl_FragColor = u_color * alpha;
}

View File

@@ -0,0 +1,15 @@
attribute vec2 a_pos;
uniform mat4 u_matrix;
uniform vec2 u_world;
varying vec2 v_pos;
void main() {
// If the x coordinate is the maximum integer, we move the z coordinates out
// of the view plane so that the triangle gets clipped. This makes it easier
// for us to create degenerate triangle strips.
float z = step(32767.0, a_pos.x) * 2.0;
gl_Position = u_matrix * vec4(a_pos, z, 1);
v_pos = (gl_Position.xy + 1.0) / 2.0 * u_world;
}

View File

@@ -9,5 +9,9 @@ const llmr_shader_t llmr_shaders[SHADER_COUNT] = {
[LINE_SHADER] = {
.vertex = "attribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n float z = step(32767.0, a_pos.x) * 2.0;\n gl_Position = u_matrix * vec4(a_pos, z, 1);\n }\n",
.fragment = "uniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n",
},
[OUTLINE_SHADER] = {
.vertex = "attribute vec2 a_pos;\nuniform mat4 u_matrix;\nuniform vec2 u_world;\n\nvarying vec2 v_pos;\n\nvoid main() {\n // If the x coordinate is the maximum integer, we move the z coordinates out\n // of the view plane so that the triangle gets clipped. This makes it easier\n // for us to create degenerate triangle strips.\n float z = step(32767.0, a_pos.x) * 2.0;\n gl_Position = u_matrix * vec4(a_pos, z, 1);\n\n v_pos = (gl_Position.xy + 1.0) / 2.0 * u_world;\n}\n",
.fragment = "uniform vec4 u_color;\n\nvarying vec2 v_pos;\n\nvoid main() {\n float dist = length(v_pos - gl_FragCoord.xy);\n float alpha = smoothstep(1.0, 0.0, dist);\n gl_FragColor = u_color * alpha;\n}\n",
}
};