Merge pull request #39 from mapbox/ios-speed

Switch to Vertex Array Objects
This commit is contained in:
Konstantin Käfer
2014-02-05 19:14:08 +01:00
31 changed files with 270 additions and 263 deletions

View File

@@ -0,0 +1,51 @@
#ifndef LLMR_GEOMETRY_VAO
#define LLMR_GEOMETRY_VAO
#include <llmr/platform/gl.hpp>
#include <stdexcept>
namespace llmr {
template <typename Shader>
class VertexArrayObject {
public:
template <typename Buffer>
void bind(Shader& shader, Buffer& buffer, char *offset) {
if (!vao) {
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
buffer.bind();
shader.bind(offset);
buffer_ptr = &buffer;
offset_ptr = offset;
} else if (buffer_ptr != &buffer) {
throw std::runtime_error("trying to bind VAO to another buffer");
} else if (offset_ptr != offset) {
throw std::runtime_error("trying to bind VAO to another offset");
} else {
// We have been given the correct information.
glBindVertexArray(vao);
}
}
~VertexArrayObject() {
if (vao) {
glDeleteVertexArrays(1, &vao);
}
}
private:
GLuint vao = 0;
// For debug reasons, we're storing the bind information so that we can
// detect errors and report
void *buffer_ptr = NULL;
char *offset_ptr = 0;
};
}
#endif

View File

@@ -2,6 +2,8 @@
#define LLMR_MAP_TILE
#include <llmr/util/vec.hpp>
#include <llmr/geometry/debug_font_buffer.hpp>
#include <llmr/geometry/vao.hpp>
#include <cstdint>
#include <forward_list>
@@ -18,9 +20,9 @@ class LayerDescription;
class BucketDescription;
class VectorTile;
class VectorTileLayer;
class DebugFontBuffer;
class FillBuffer;
class LineBuffer;
class PlainShader;
class Tile : public std::enable_shared_from_this<Tile> {
public:
@@ -71,7 +73,9 @@ public:
state state;
// Holds the actual geometries in this tile.
std::shared_ptr<DebugFontBuffer> debugFontBuffer;
DebugFontBuffer debugFontBuffer;
VertexArrayObject<PlainShader> debugFontArray;
std::shared_ptr<FillBuffer> fillBuffer;
std::shared_ptr<LineBuffer> lineBuffer;

View File

@@ -8,12 +8,18 @@
#if TARGET_OS_IPHONE
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#define glGenVertexArrays glGenVertexArraysOES
#define glBindVertexArray glBindVertexArrayOES
#define glDeleteVertexArrays glDeleteVertexArraysOES
#elif TARGET_IPHONE_SIMULATOR
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#elif TARGET_OS_MAC
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#define glGenVertexArrays glGenVertexArraysAPPLE
#define glBindVertexArray glBindVertexArrayAPPLE
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
#else
#error Unsupported Apple platform
#endif

View File

@@ -3,15 +3,23 @@
#include "bucket.hpp"
#include <llmr/style/bucket_description.hpp>
#include <llmr/geometry/vao.hpp>
#include <llmr/geometry/fill_buffer.hpp>
#include <vector>
#include <memory>
#ifndef BUFFER_OFFSET
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#endif
namespace llmr {
class Style;
class FillBuffer;
class BucketDescription;
class OutlineShader;
class PlainShader;
struct Coordinate;
struct pbf;
@@ -24,8 +32,9 @@ public:
void addGeometry(pbf& data);
void addGeometry(const std::vector<Coordinate>& line);
uint32_t size() const;
void drawElements(int32_t attrib);
void drawVertices(int32_t attrib);
void drawElements(PlainShader& shader);
void drawVertices(OutlineShader& shader);
public:
const BucketGeometryDescription geom_desc;
@@ -34,6 +43,7 @@ private:
std::shared_ptr<FillBuffer> buffer;
struct group {
VertexArrayObject<PlainShader> array;
uint32_t vertex_length;
uint32_t elements_length;
@@ -48,6 +58,7 @@ private:
uint32_t vertex_start;
uint32_t elements_start;
uint32_t length;
VertexArrayObject<OutlineShader> array;
std::vector<group> groups;
};

View File

@@ -3,6 +3,7 @@
#include "bucket.hpp"
#include <llmr/style/bucket_description.hpp>
#include <llmr/geometry/vao.hpp>
#include <memory>
#include <vector>
@@ -10,6 +11,7 @@ namespace llmr {
class Style;
class LineBuffer;
class LineShader;
struct Coordinate;
struct pbf;
@@ -21,10 +23,12 @@ public:
void addGeometry(pbf& data);
void addGeometry(const std::vector<Coordinate>& line);
uint32_t size() const;
void bind();
char *vertexOffset() const;
size_t size() const;
void bind(LineShader& shader);
void drawLines();
void drawPoints();
public:
const BucketGeometryDescription geometry;
@@ -33,6 +37,7 @@ private:
std::shared_ptr<LineBuffer> buffer;
uint32_t start;
uint32_t length;
VertexArrayObject<LineShader> array;
};
}

View File

@@ -2,23 +2,22 @@
#define LLMR_RENDERER_PAINTER
#include <llmr/map/tile.hpp>
#include <llmr/geometry/vao.hpp>
#include <llmr/geometry/vertex_buffer.hpp>
#include <llmr/util/mat4.hpp>
#include <llmr/renderer/shader-plain.hpp>
#include <llmr/renderer/shader-outline.hpp>
#include <llmr/renderer/shader-pattern.hpp>
#include <llmr/renderer/shader-line.hpp>
namespace llmr {
class Transform;
class Settings;
class Style;
class Tile;
// class LayerDescription;
class Shader;
class PlainShader;
class OutlineShader;
class FillShader;
class LineShader;
class PatternShader;
class FillBucket;
class LineBucket;
@@ -33,29 +32,21 @@ public:
Painter& operator=(const Painter&) = delete;
Painter& operator=(const Painter && ) = delete;
void setup();
void clear();
void changeMatrix(const Tile::ID& id);
void render(const std::shared_ptr<Tile>& tile);
void renderLayers(const std::shared_ptr<Tile>& tile, const std::vector<LayerDescription>& layers);
void renderDebug(const std::shared_ptr<Tile>& tile);
void renderMatte();
void renderBackground();
void renderFill(FillBucket& bucket, const std::string& layer_name, const Tile::ID& id);
void renderLine(LineBucket& bucket, const std::string& layer_name, const Tile::ID& id);
void drawClippingMask();
bool switchShader(std::shared_ptr<Shader> shader);
private:
void setupShaders();
public:
void drawClippingMask();
void renderLayers(const std::shared_ptr<Tile>& tile, const std::vector<LayerDescription>& layers);
void renderDebug(const std::shared_ptr<Tile>& tile);
private:
Transform& transform;
@@ -66,12 +57,10 @@ private:
mat4 matrix;
mat4 exMatrix;
std::shared_ptr<Shader> currentShader;
std::shared_ptr<FillShader> fillShader;
std::shared_ptr<PlainShader> plainShader;
std::shared_ptr<OutlineShader> outlineShader;
std::shared_ptr<LineShader> lineShader;
std::shared_ptr<PatternShader> patternShader;
std::unique_ptr<PlainShader> plainShader;
std::unique_ptr<OutlineShader> outlineShader;
std::unique_ptr<LineShader> lineShader;
std::unique_ptr<PatternShader> patternShader;
// Set up the stencil quad we're using to generate the stencil mask.
VertexBuffer tileStencilBuffer = {
@@ -86,6 +75,9 @@ private:
4096, 4096
};
VertexArrayObject<PlainShader> coveringPlainArray;
VertexArrayObject<PatternShader> coveringPatternArray;
// Set up the tile boundary lines we're using to draw the tile outlines.
VertexBuffer tileBorderBuffer = {
0, 0,
@@ -95,6 +87,8 @@ private:
0, 0
};
VertexArrayObject<PlainShader> tileBorderArray;
// Set up the matte buffer we're using to draw the filling background.
VertexBuffer matteBuffer = {
// top left triangle
@@ -108,6 +102,7 @@ private:
16384, 16384
};
VertexArrayObject<PlainShader> matteArray;
};
}

View File

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

View File

@@ -9,6 +9,8 @@ class LineShader : public Shader {
public:
LineShader();
void bind(char *offset);
int32_t a_pos;
int32_t a_extrude;
int32_t a_linesofar;

View File

@@ -9,6 +9,8 @@ class OutlineShader : public Shader {
public:
OutlineShader();
void bind(char *offset);
int32_t a_pos;
int32_t u_matrix;
int32_t u_color;

View File

@@ -9,6 +9,8 @@ class PatternShader : public Shader {
public:
PatternShader();
void bind(char *offset);
int32_t a_pos;
int32_t u_matrix;
int32_t u_color;

View File

@@ -9,6 +9,8 @@ class PlainShader : public Shader {
public:
PlainShader();
void bind(char *offset);
int32_t a_pos;
int32_t u_matrix;
int32_t u_color;

View File

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

View File

@@ -11,7 +11,6 @@ struct shader_source {
};
enum {
FILL_SHADER,
LINE_SHADER,
OUTLINE_SHADER,
PATTERN_SHADER,

View File

@@ -46,20 +46,24 @@ struct pbf {
inline void skipValue(uint32_t val);
inline void skipBytes(uint32_t bytes);
const uint8_t *data;
const uint8_t *end;
uint32_t value;
uint32_t tag;
const uint8_t *data = NULL;
const uint8_t *end = NULL;
uint32_t value = 0;
uint32_t tag = 0;
};
pbf::pbf(const unsigned char *data, uint32_t length)
: data(data),
end(data + length) {
end(data + length),
value(0),
tag(0) {
}
pbf::pbf()
: data(NULL),
end(NULL) {
end(NULL),
value(0),
tag(0) {
}

16
include/llmr/util/std.hpp Normal file
View File

@@ -0,0 +1,16 @@
#ifndef LLMR_UTIL_STD
#define LLMR_UTIL_STD
#include <memory>
namespace std {
// C++14 backfill from http://herbsutter.com/gotw/_102/
template<typename T, typename ...Args>
::std::unique_ptr<T> make_unique(Args&& ...args) {
return ::std::unique_ptr<T>(new T(::std::forward<Args>(args)...));
}
}
#endif

View File

@@ -72,6 +72,7 @@ class MBXMapView
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
self.preferredFramesPerSecond = 60;
[view bindDrawable];
[EAGLContext setCurrentContext:self.context];

View File

@@ -9,7 +9,6 @@ VertexBuffer::VertexBuffer(std::initializer_list<int16_t> init) : array(init) {}
VertexBuffer::~VertexBuffer() {
if (buffer != 0) {
glDeleteBuffers(1, &buffer);
buffer = 0;
}
}
@@ -26,5 +25,4 @@ void VertexBuffer::bind() {
} else {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
}
}

View File

@@ -94,7 +94,7 @@ void Map::setScale(double scale) {
}
void Map::setAngle(double angle, double x, double y) {
double dx, dy;
double dx = 0, dy = 0;
if (x >= 0 && y >= 0) {
dx = (transform.width / 2) - x;

View File

@@ -2,7 +2,6 @@
#include <llmr/style/style.hpp>
#include <llmr/map/vector_tile.hpp>
#include <llmr/geometry/debug_font_buffer.hpp>
#include <llmr/geometry/fill_buffer.hpp>
#include <llmr/geometry/line_buffer.hpp>
#include <llmr/renderer/fill_bucket.hpp>
@@ -43,7 +42,6 @@ std::forward_list<Tile::ID> Tile::children(const ID& id, int32_t z) {
Tile::Tile(ID id, const Style& style)
: id(id),
state(initial),
debugFontBuffer(std::make_shared<DebugFontBuffer>()),
fillBuffer(std::make_shared<FillBuffer>()),
lineBuffer(std::make_shared<LineBuffer>()),
style(style) {
@@ -51,7 +49,7 @@ Tile::Tile(ID id, const Style& style)
// Initialize tile debug coordinates
char coord[32];
snprintf(coord, sizeof(coord), "%d/%d/%d", id.z, id.x, id.y);
debugFontBuffer->addText(coord, 50, 200, 5);
debugFontBuffer.addText(coord, 50, 200, 5);
}
Tile::~Tile() {

View File

@@ -8,8 +8,6 @@
#include <llmr/platform/gl.hpp>
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#include <cassert>
struct geometry_too_long_exception : std::exception {};
@@ -97,26 +95,6 @@ void FillBucket::addGeometry(const std::vector<Coordinate>& line) {
}
void FillBucket::drawElements(int32_t attrib) {
char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t));
char *elements_index = BUFFER_OFFSET(elements_start * 3 * sizeof(int16_t));
buffer->bind();
for (const auto& group : groups) {
glVertexAttribPointer(attrib, 2, GL_SHORT, GL_FALSE, 0, vertex_index);
glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index);
vertex_index += group.vertex_length * 2 * sizeof(uint16_t);
elements_index += group.elements_length * 3 * sizeof(uint16_t);
}
}
void FillBucket::drawVertices(int32_t attrib) {
// Draw the entire line
char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t));
buffer->bind();
glVertexAttribPointer(attrib, 2, GL_SHORT, GL_FALSE, 0, vertex_index);
glDrawArrays(GL_LINE_STRIP, 0, length);
}
void FillBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) {
painter.renderFill(*this, layer_name, id);
}
@@ -125,3 +103,24 @@ uint32_t FillBucket::size() const {
return length;
}
void FillBucket::drawElements(PlainShader& shader) {
char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t));
char *elements_index = BUFFER_OFFSET(elements_start * 3 * sizeof(int16_t));
for (group& group : groups) {
group.array.bind(shader, *buffer, vertex_index);
glDrawElements(GL_TRIANGLES, group.elements_length * 3 - 3, GL_UNSIGNED_SHORT, elements_index);
vertex_index += group.vertex_length * 2 * sizeof(uint16_t);
elements_index += group.elements_length * 3 * sizeof(uint16_t);
}
}
void FillBucket::drawVertices(OutlineShader& shader) {
// Draw the entire line
char *vertex_index = BUFFER_OFFSET(vertex_start * 2 * sizeof(int16_t));
array.bind(shader, *buffer, vertex_index);
glDrawArrays(GL_LINE_STRIP, 0, length);
}

View File

@@ -3,6 +3,7 @@
#include <llmr/geometry/geometry.hpp>
#include <llmr/renderer/painter.hpp>
#include <llmr/renderer/shader-line.hpp>
#include <llmr/style/style.hpp>
#include <llmr/map/vector_tile.hpp>
@@ -264,14 +265,19 @@ void LineBucket::render(Painter& painter, const std::string& layer_name, const T
painter.renderLine(*this, layer_name, id);
}
uint32_t LineBucket::size() const {
size_t LineBucket::size() const {
return length;
}
void LineBucket::bind() {
buffer->bind();
void LineBucket::bind(LineShader& shader) {
char *vertex_index = BUFFER_OFFSET(start * 4 * sizeof(int16_t));
array.bind(shader, *buffer, vertex_index);
}
char *LineBucket::vertexOffset() const {
return BUFFER_OFFSET(start * 4 * sizeof(int16_t));
void LineBucket::drawLines() {
glDrawArrays(GL_TRIANGLE_STRIP, 0, length);
}
void LineBucket::drawPoints() {
glDrawArrays(GL_POINTS, 0, length);
}

View File

@@ -1,15 +1,13 @@
#include <cassert>
#include <algorithm>
#include <llmr/renderer/painter.hpp>
#include <llmr/renderer/shader-plain.hpp>
#include <llmr/renderer/shader-fill.hpp>
#include <llmr/renderer/shader-outline.hpp>
#include <llmr/renderer/shader-pattern.hpp>
#include <llmr/renderer/shader-line.hpp>
#include <llmr/renderer/painter.hpp>
#include <llmr/util/std.hpp>
#include <llmr/renderer/fill_bucket.hpp>
#include <llmr/renderer/line_bucket.hpp>
#include <llmr/map/transform.hpp>
#include <llmr/map/settings.hpp>
#include <llmr/geometry/debug_font_buffer.hpp>
@@ -24,15 +22,13 @@ using namespace llmr;
Painter::Painter(Transform& transform, Settings& settings, Style& style)
: transform(transform),
settings(settings),
style(style),
currentShader(NULL) {
style(style) {
}
void Painter::setup() {
setupShaders();
assert(fillShader);
assert(plainShader);
assert(outlineShader);
assert(lineShader);
@@ -47,11 +43,10 @@ void Painter::setup() {
}
void Painter::setupShaders() {
fillShader = std::make_shared<FillShader>();
plainShader = std::make_shared<PlainShader>();
outlineShader = std::make_shared<OutlineShader>();
lineShader = std::make_shared<LineShader>();
patternShader = std::make_shared<PatternShader>();
plainShader = std::make_unique<PlainShader>();
outlineShader = std::make_unique<OutlineShader>();
lineShader = std::make_unique<LineShader>();
patternShader = std::make_unique<PatternShader>();
}
void Painter::changeMatrix(const Tile::ID& id) {
@@ -76,7 +71,7 @@ void Painter::changeMatrix(const Tile::ID& id) {
}
void Painter::drawClippingMask() {
switchShader(plainShader);
glUseProgram(plainShader->program);
glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data());
glColorMask(false, false, false, false);
@@ -96,9 +91,10 @@ void Painter::drawClippingMask() {
glStencilMask(0xC0);
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
// Draw the clipping mask
tileStencilBuffer.bind();
glVertexAttribPointer(plainShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
glUniform4f(plainShader->u_color, 1.0f, 0.0f, 1.0f, 1.0f);
glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.length());
@@ -197,11 +193,11 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
glColorMask(false, false, false, false);
// Draw the actual triangle fan into the stencil buffer.
switchShader(fillShader);
glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix.data());
glUseProgram(plainShader->program);
glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data());
// Draw all groups
bucket.drawElements(fillShader->a_pos);
bucket.drawElements(*plainShader);
// Now that we have the stencil mask in the stencil buffer, we can start
// writing to the color buffer.
@@ -215,7 +211,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
// Because we're drawing top-to-bottom, and we update the stencil mask
// below, we have to draw the outline first (!)
if (properties.antialias) {
switchShader(outlineShader);
glUseProgram(outlineShader->program);
glUniformMatrix4fv(outlineShader->u_matrix, 1, GL_FALSE, matrix.data());
glLineWidth(2);
@@ -238,7 +234,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
// Draw the entire line
glUniform2f(outlineShader->u_world, transform.fb_width, transform.fb_height);
glLineWidth(2.0f);
bucket.drawVertices(outlineShader->a_pos);
bucket.drawVertices(*outlineShader);
}
// Only draw regions that we marked
@@ -257,7 +253,7 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
fmod(id.y * 4096, imageSize.y)
};
switchShader(patternShader);
glUseProgram(patternShader->program);
glUniformMatrix4fv(patternShader->u_matrix, 1, GL_FALSE, matrix.data());
glUniform2f(patternShader->u_pattern_size, imageSize.x, imageSize.y);
glUniform2f(patternShader->u_offset, offset.x, offset.y);
@@ -268,19 +264,17 @@ void Painter::renderFill(FillBucket& bucket, const std::string& layer_name, cons
style.sprite->bind(true);
// Draw a rectangle that covers the entire viewport.
tileStencilBuffer.bind();
glVertexAttribPointer(patternShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
coveringPatternArray.bind(*patternShader, tileStencilBuffer, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.length());
} else {
// Draw filling rectangle.
switchShader(fillShader);
glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix.data());
glUniform4fv(fillShader->u_color, 1, fill_color.data());
glUseProgram(plainShader->program);
glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data());
glUniform4fv(plainShader->u_color, 1, fill_color.data());
// Draw a rectangle that covers the entire viewport.
tileStencilBuffer.bind();
glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.length());
}
@@ -324,42 +318,37 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
// glUniform1f(painter.linepatternShader.u_fade, painter.transform.z % 1.0);
} else {
switchShader(lineShader);
glUseProgram(lineShader->program);
glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix.data());
glUniformMatrix4fv(lineShader->u_exmatrix, 1, GL_FALSE, exMatrix.data());
// glUniform2fv(painter.lineShader.u_dasharray, properties.dasharray || [1, -1]);
glUniform2f(lineShader->u_dasharray, 1, -1);
}
// TODO: Move this to transform?
const double tilePixelRatio = transform.getScale() / (1 << transform.getIntegerZoom()) / 8;
// TODO: Move this to transform?
const double tilePixelRatio = transform.getScale() / (1 << transform.getIntegerZoom()) / 8;
glUniform2f(lineShader->u_linewidth, outset, inset);
glUniform1f(lineShader->u_ratio, tilePixelRatio);
glUniform1f(lineShader->u_gamma, transform.pixelRatio);
glUniform2f(lineShader->u_linewidth, outset, inset);
glUniform1f(lineShader->u_ratio, tilePixelRatio);
glUniform1f(lineShader->u_gamma, transform.pixelRatio);
// const Color& color = properties.color;
// if (!params.antialiasing) {
// color[3] = Infinity;
// glUniform4fv(lineShader->u_color, color);
// } else {
glUniform4fv(lineShader->u_color, 1, color.data());
// }
// const Color& color = properties.color;
// if (!params.antialiasing) {
// color[3] = Infinity;
// glUniform4fv(lineShader->u_color, color);
// } else {
glUniform4fv(lineShader->u_color, 1, color.data());
// }
glUniform1f(lineShader->u_point, 0);
glUniform1f(lineShader->u_point, 0);
bucket.bind(*lineShader);
bucket.drawLines();
bucket.bind();
char *vertex_index = bucket.vertexOffset();
glVertexAttribPointer(lineShader->a_pos, 2, GL_SHORT, false, 8, vertex_index);
glVertexAttribPointer(lineShader->a_extrude, 2, GL_BYTE, false, 8, vertex_index + 6);
glVertexAttribPointer(lineShader->a_linesofar, 1, GL_SHORT, false, 8, vertex_index + 4);
glDrawArrays(GL_TRIANGLE_STRIP, 0, bucket.size());
if (bucket.geometry.join == JoinType::Round) {
glUniform1f(lineShader->u_point, 1);
glDrawArrays(GL_POINTS, 0, bucket.size());
if (bucket.geometry.join == JoinType::Round) {
glUniform1f(lineShader->u_point, 1);
bucket.drawPoints();
}
}
// statistics
@@ -369,27 +358,23 @@ void Painter::renderLine(LineBucket& bucket, const std::string& layer_name, cons
void Painter::renderDebug(const Tile::Ptr& tile) {
// Blend to the front, not the back.
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(plainShader->program);
glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data());
// draw tile outline
switchShader(plainShader);
glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data());
tileBorderBuffer.bind();
glVertexAttribPointer(plainShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
glUniform4f(plainShader->u_color, 1.0f, 1.0f, 1.0f, 1.0f);
tileBorderArray.bind(*plainShader, tileBorderBuffer, BUFFER_OFFSET(0));
glUniform4f(plainShader->u_color, 1.0f, 0.0f, 0.0f, 1.0f);
glLineWidth(4.0f);
glDrawArrays(GL_LINE_STRIP, 0, tileBorderBuffer.length());
// draw debug info
switchShader(plainShader);
glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data());
tile->debugFontBuffer->bind();
glVertexAttribPointer(plainShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, BUFFER_OFFSET(0));
tile->debugFontArray.bind(*plainShader, tile->debugFontBuffer, BUFFER_OFFSET(0));
glUniform4f(plainShader->u_color, 1.0f, 1.0f, 1.0f, 1.0f);
glLineWidth(4.0f);
glDrawArrays(GL_LINES, 0, tile->debugFontBuffer->length());
glDrawArrays(GL_LINES, 0, tile->debugFontBuffer.length());
glUniform4f(plainShader->u_color, 0.0f, 0.0f, 0.0f, 1.0f);
glLineWidth(2.0f);
glDrawArrays(GL_LINES, 0, tile->debugFontBuffer->length());
glDrawArrays(GL_LINES, 0, tile->debugFontBuffer.length());
// Revert blending mode to blend to the back.
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
@@ -398,76 +383,27 @@ void Painter::renderDebug(const Tile::Ptr& tile) {
void Painter::renderMatte() {
glDisable(GL_STENCIL_TEST);
switchShader(fillShader);
glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, nativeMatrix.data());
Color white = {{ 0.9, 0.9, 0.9, 1 }};
Color white = {{ 1, 1, 1, 1 }};
glUseProgram(plainShader->program);
glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, nativeMatrix.data());
// Draw the clipping mask
matteBuffer.bind();
glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
glUniform4fv(fillShader->u_color, 1, white.data());
matteArray.bind(*plainShader, matteBuffer, BUFFER_OFFSET(0));
glUniform4fv(plainShader->u_color, 1, white.data());
glDrawArrays(GL_TRIANGLES, 0, matteBuffer.length());
glEnable(GL_STENCIL_TEST);
}
void Painter::renderBackground() {
switchShader(fillShader);
glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix.data());
Color white = {{ 1, 1, 1, 1 }};
glUseProgram(plainShader->program);
glUniformMatrix4fv(plainShader->u_matrix, 1, GL_FALSE, matrix.data());
// Draw the clipping mask
tileStencilBuffer.bind();
glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
glUniform4fv(fillShader->u_color, 1, white.data());
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
glUniform4fv(plainShader->u_color, 1, white.data());
glDrawArrays(GL_TRIANGLES, 0, tileStencilBuffer.length());
}
// Switches to a different shader program.
/**
* @return boolean whether the shader was actually switched
*/
bool Painter::switchShader(std::shared_ptr<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::forward_list<uint32_t>& hitherto = currentShader->attributes;
const std::forward_list<uint32_t>& henceforth = shader->attributes;
// 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 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 (== first shader).
for (GLuint index : shader->attributes) {
glEnableVertexAttribArray(index);
}
}
currentShader = shader;
return true;
} else {
return false;
}
}

View File

@@ -1,22 +0,0 @@
#include <llmr/renderer/shader-fill.hpp>
#include <llmr/shader/shaders.hpp>
#include <llmr/platform/gl.hpp>
using namespace llmr;
FillShader::FillShader()
: Shader(
shaders[FILL_SHADER].vertex,
shaders[FILL_SHADER].fragment
) {
if (!valid) {
fprintf(stderr, "invalid fill 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");
}

View File

@@ -2,6 +2,8 @@
#include <llmr/shader/shaders.hpp>
#include <llmr/platform/gl.hpp>
#include <cstdio>
using namespace llmr;
LineShader::LineShader()
@@ -15,11 +17,8 @@ LineShader::LineShader()
}
a_pos = glGetAttribLocation(program, "a_pos");
attributes.emplace_front(a_pos);
a_extrude = glGetAttribLocation(program, "a_extrude");
attributes.emplace_front(a_extrude);
a_linesofar = glGetAttribLocation(program, "a_linesofar");
attributes.emplace_front(a_linesofar);
u_matrix = glGetUniformLocation(program, "u_matrix");
u_exmatrix = glGetUniformLocation(program, "u_exmatrix");
@@ -31,3 +30,14 @@ LineShader::LineShader()
u_point = glGetUniformLocation(program, "u_point");
u_gamma = glGetUniformLocation(program, "u_gamma");
}
void LineShader::bind(char *offset) {
glEnableVertexAttribArray(a_pos);
glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset);
glEnableVertexAttribArray(a_extrude);
glVertexAttribPointer(a_extrude, 2, GL_BYTE, false, 8, offset + 6);
glEnableVertexAttribArray(a_linesofar);
glVertexAttribPointer(a_linesofar, 1, GL_SHORT, false, 8, offset + 4);
}

View File

@@ -2,6 +2,8 @@
#include <llmr/shader/shaders.hpp>
#include <llmr/platform/gl.hpp>
#include <cstdio>
using namespace llmr;
OutlineShader::OutlineShader()
@@ -15,9 +17,13 @@ OutlineShader::OutlineShader()
}
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");
}
void OutlineShader::bind(char *offset) {
glEnableVertexAttribArray(a_pos);
glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset);
}

View File

@@ -2,6 +2,8 @@
#include <llmr/shader/shaders.hpp>
#include <llmr/platform/gl.hpp>
#include <cstdio>
using namespace llmr;
PatternShader::PatternShader()
@@ -15,7 +17,6 @@ PatternShader::PatternShader()
}
a_pos = glGetAttribLocation(program, "a_pos");
attributes.emplace_front(a_pos);
u_matrix = glGetUniformLocation(program, "u_matrix");
u_color = glGetUniformLocation(program, "u_color");
@@ -25,3 +26,8 @@ PatternShader::PatternShader()
u_pattern_br = glGetUniformLocation(program, "u_pattern_br");
u_mix = glGetUniformLocation(program, "u_mix");
}
void PatternShader::bind(char *offset) {
glEnableVertexAttribArray(a_pos);
glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset);
}

View File

@@ -2,6 +2,8 @@
#include <llmr/shader/shaders.hpp>
#include <llmr/platform/gl.hpp>
#include <cstdio>
using namespace llmr;
PlainShader::PlainShader()
@@ -15,8 +17,12 @@ PlainShader::PlainShader()
}
a_pos = glGetAttribLocation(program, "a_pos");
attributes.emplace_front(a_pos);
u_matrix = glGetUniformLocation(program, "u_matrix");
u_color = glGetUniformLocation(program, "u_color");
}
void PlainShader::bind(char *offset) {
glEnableVertexAttribArray(a_pos);
glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset);
}

View File

@@ -107,7 +107,7 @@ bool Shader::compileShader(GLuint *shader, GLenum type, const GLchar *source) {
#if defined(EMSCRIPTEN) || defined(GL_ES_VERSION_2_0)
// Add WebGL GLSL / OpenGL ES precision premable
const GLchar *preamble = "precision mediump float;\n\n";
const GLchar *preamble = "precision highp float;\n\n";
#else
// Desktop GLSL
const GLchar *preamble = "#version 120\n\n";

View File

@@ -1,5 +0,0 @@
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}

View File

@@ -1,7 +0,0 @@
attribute vec2 a_pos;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
}

View File

@@ -4,10 +4,6 @@
using namespace llmr;
const shader_source llmr::shaders[SHADER_COUNT] = {
{
"attribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n",
"uniform vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n",
},
{
"// these are the shaders for rendering antialiased lines\n\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n#define scale 63.0\n\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute float a_linesofar;\n\n// matrix is for the vertex position, exmatrix is for rotating and projecting\n// the extrusion vector.\nuniform mat4 u_matrix;\nuniform mat4 u_exmatrix;\n\n\nuniform float u_debug;\n\n// shared\nuniform float u_ratio;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform float u_point;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n vec2 extrude = a_extrude / scale;\n vec2 dist = u_linewidth.s * extrude * (1.0 - u_point);\n\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);\n\n // When drawing points, skip every other vertex\n z += u_point * step(1.0, v_normal.y);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix. Add the extrusion vector *after* the model/view matrix\n // because we're extruding the line in pixel space, regardless of the current\n // tile's zoom level.\n gl_Position = u_matrix * vec4(floor(a_pos / 2.0), 0.0, 1.0) + u_exmatrix * vec4(dist, z, 0.0);\n v_linesofar = a_linesofar * u_ratio;\n\n\n gl_PointSize = 2.0 * u_linewidth.s - 1.0;\n}\n",
"// shared\nuniform float u_debug;\nuniform vec2 u_linewidth;\nuniform vec4 u_color;\nuniform float u_point;\nuniform float u_gamma;\n\nuniform vec2 u_dasharray;\n\nvarying vec2 v_normal;\nvarying float v_linesofar;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * (1.0 - u_point) + u_point * length(gl_PointCoord * 2.0 - 1.0);\n\n dist *= u_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist) * u_gamma, 0.0, 1.0);\n\n // Calculate the antialiasing fade factor based on distance to the dash.\n // Only affects alpha when line is dashed\n float pos = mod(v_linesofar, u_dasharray.x + u_dasharray.y);\n alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0));\n\n gl_FragColor = u_color * alpha;\n\n if (u_debug > 0.0) {\n gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n }\n}\n",