diff --git a/include/llmr/geometry/text_buffer.hpp b/include/llmr/geometry/text_buffer.hpp new file mode 100644 index 000000000..005d54a3a --- /dev/null +++ b/include/llmr/geometry/text_buffer.hpp @@ -0,0 +1,17 @@ +#ifndef LLMR_GEOMETRY_TEXT_BUFFER +#define LLMR_GEOMETRY_TEXT_BUFFER + +#include "buffer.hpp" + +namespace llmr { + +class TextVertexBuffer : public Buffer< + 4 // 2 coordinates per vertex +> { +public: +}; + + +} + +#endif diff --git a/include/llmr/map/tile_data.hpp b/include/llmr/map/tile_data.hpp index e8cbb6793..fbaa4c0f0 100644 --- a/include/llmr/map/tile_data.hpp +++ b/include/llmr/map/tile_data.hpp @@ -28,9 +28,11 @@ class VectorTileLayer; class FillVertexBuffer; class LineVertexBuffer; class PointVertexBuffer; +class TextVertexBuffer; class TriangleElementsBuffer; class LineElementsBuffer; class PointElementsBuffer; +class TextElementsBuffer; class PlainShader; class TileData : public std::enable_shared_from_this, @@ -66,6 +68,7 @@ public: std::shared_ptr createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); std::shared_ptr createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); std::shared_ptr createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); + std::shared_ptr createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); void cancel(); @@ -82,10 +85,12 @@ public: std::shared_ptr fillVertexBuffer; std::shared_ptr lineVertexBuffer; std::shared_ptr pointVertexBuffer; + std::shared_ptr textVertexBuffer; std::shared_ptr triangleElementsBuffer; std::shared_ptr lineElementsBuffer; std::shared_ptr pointElementsBuffer; + std::shared_ptr textElementsBuffer; // Holds the buckets of this tile. // They contain the location offsets in the buffers stored above diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 0080773f2..71bb60615 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -25,6 +25,7 @@ class Tile; class FillBucket; class LineBucket; class PointBucket; +class TextBucket; class Painter : private util::noncopyable { public: @@ -38,6 +39,7 @@ public: 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 renderPoint(PointBucket& bucket, const std::string& layer_name, const Tile::ID& id); + void renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id); void resize(int width, int height); diff --git a/include/llmr/renderer/shader-text.hpp b/include/llmr/renderer/shader-text.hpp new file mode 100644 index 000000000..cd8e65bee --- /dev/null +++ b/include/llmr/renderer/shader-text.hpp @@ -0,0 +1,26 @@ +#ifndef LLMR_RENDERER_SHADER_TEXT +#define LLMR_RENDERER_SHADER_TEXT + +#include "shader.hpp" + +namespace llmr { + +class TextShader : public Shader { +public: + TextShader(); + + void bind(char *offset); + + void setColor(float r, float g, float b, float a); + void setColor(const std::array& color); + +private: + int32_t a_pos = -1; + + std::array color = {{}}; + int32_t u_color = -1; +}; + +} + +#endif diff --git a/include/llmr/renderer/text_bucket.hpp b/include/llmr/renderer/text_bucket.hpp new file mode 100644 index 000000000..60b0668a1 --- /dev/null +++ b/include/llmr/renderer/text_bucket.hpp @@ -0,0 +1,51 @@ +#ifndef LLMR_RENDERER_TEXTBUCKET +#define LLMR_RENDERER_TEXTBUCKET + +#include "bucket.hpp" +#include +#include +#include +#include +#include + +namespace llmr { + +class Style; +class TextVertexBuffer; +class TriangleElementsBuffer; +class TextShader; +struct Coordinate; +struct pbf; + +class TextBucket : public Bucket { + typedef ElementGroup triangle_group_type; +public: + TextBucket(const std::shared_ptr& vertexBuffer, + const std::shared_ptr& triangleElementsBuffer, + const BucketDescription& bucket_desc); + + virtual void render(Painter& painter, const std::string& layer_name, const Tile::ID& id); + + void addGeometry(pbf& data); + + bool empty() const; + + void drawGlyphs(TextShader& shader); + +public: + const BucketGeometryDescription geometry; + +private: + + std::shared_ptr vertexBuffer; + std::shared_ptr triangleElementsBuffer; + + const size_t vertex_start; + const size_t triangle_elements_start; + + std::vector triangleGroups; +}; + +} + +#endif diff --git a/include/llmr/shader/shaders.hpp b/include/llmr/shader/shaders.hpp index 6312cc694..5cd4f493e 100644 --- a/include/llmr/shader/shaders.hpp +++ b/include/llmr/shader/shaders.hpp @@ -17,6 +17,7 @@ enum { PATTERN_SHADER, PLAIN_SHADER, POINT_SHADER, + TEXT_SHADER, SHADER_COUNT }; diff --git a/src/map/tile_data.cpp b/src/map/tile_data.cpp index 16c1e461f..d06a0becc 100644 --- a/src/map/tile_data.cpp +++ b/src/map/tile_data.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -194,3 +195,9 @@ std::shared_ptr TileData::createPointBucket(const VectorTileLayer& layer addBucketFeatures(bucket, layer, bucket_desc); return state == State::obsolete ? nullptr : bucket; } + +std::shared_ptr TileData::createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { + std::shared_ptr bucket = std::make_shared(textVertexBuffer, triangleElementsBuffer, bucket_desc); + addBucketFeatures(bucket, layer, bucket_desc); + return state == State::obsolete ? nullptr : bucket; +} diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index a9094fdfb..ed7cc506e 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -451,6 +452,10 @@ void Painter::renderPoint(PointBucket& bucket, const std::string& layer_name, co bucket.drawPoints(*pointShader); } +void Painter::renderText(TextBucket& bucket, const std::string& layer_name, const Tile::ID& id) { + // noop +} + void Painter::renderDebug(const TileData::Ptr& tile_data) { // Disable depth test and don't count this towards the depth buffer, // but *don't* disable stencil test, as we want to clip the red tile border diff --git a/src/renderer/shader-text.cpp b/src/renderer/shader-text.cpp new file mode 100644 index 000000000..3133857d6 --- /dev/null +++ b/src/renderer/shader-text.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include + +using namespace llmr; + +TextShader::TextShader() + : Shader( + shaders[TEXT_SHADER].vertex, + shaders[TEXT_SHADER].fragment + ) { + if (!valid) { + fprintf(stderr, "invalid text shader\n"); + return; + } + + a_pos = glGetAttribLocation(program, "a_pos"); + + u_matrix = glGetUniformLocation(program, "u_matrix"); + u_color = glGetUniformLocation(program, "u_color"); + + // fprintf(stderr, "TextShader:\n"); + // fprintf(stderr, " - a_pos: %d\n", a_pos); + // fprintf(stderr, " - u_matrix: %d\n", u_matrix); + // fprintf(stderr, " - u_color: %d\n", u_color); +} + +void TextShader::bind(char *offset) { + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); +} + +void TextShader::setColor(const std::array& new_color) { + if (color != new_color) { + glUniform4fv(u_color, 1, new_color.data()); + color = new_color; + } +} + +void TextShader::setColor(float r, float g, float b, float a) { + setColor({{ r, g, b, a }}); +} diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp new file mode 100644 index 000000000..dd646794b --- /dev/null +++ b/src/renderer/text_bucket.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define BUFFER_OFFSET(i) ((char *)nullptr + (i)) + +#include + +struct geometry_too_long_exception : std::exception {}; + +using namespace llmr; + +TextBucket::TextBucket(const std::shared_ptr& vertexBuffer, + const std::shared_ptr& triangleElementsBuffer, + const BucketDescription& bucket_desc) + : geometry(bucket_desc.geometry), + vertexBuffer(vertexBuffer), + triangleElementsBuffer(triangleElementsBuffer), + vertex_start(vertexBuffer->index()), + triangle_elements_start(triangleElementsBuffer->index()) +{ +} + +void TextBucket::addGeometry(pbf& geom) { + // noop +} + +void TextBucket::render(Painter& painter, const std::string& layer_name, const Tile::ID& id) { + painter.renderText(*this, layer_name, id); +} + +bool TextBucket::empty() const { + return triangleGroups.empty(); +} + +void TextBucket::drawGlyphs(TextShader& shader) { + // noop +} diff --git a/src/shader/shaders.cpp b/src/shader/shaders.cpp index 44524f30d..f5cc884c2 100644 --- a/src/shader/shaders.cpp +++ b/src/shader/shaders.cpp @@ -27,5 +27,9 @@ const shader_source llmr::shaders[SHADER_COUNT] = { { "attribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nuniform float u_size;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n gl_PointSize = u_size;\n}\n", "#define root2 1.4142135623730951\n\nuniform sampler2D u_image;\nuniform vec2 u_tl;\nuniform vec2 u_br;\nuniform vec4 u_color;\n\nuniform vec2 pos;\nuniform float inbounds;\nuniform vec4 color;\n\nvoid main() {\n vec2 pos = (gl_PointCoord * 2.0 - 1.0) * root2 / 2.0 + 0.5;\n\n float inbounds = step(0.0, pos.x) * step(0.0, pos.y) *\n (1.0 - step(1.0, pos.x)) * (1.0 - step(1.0, pos.y));\n\n vec4 color = texture2D(u_image, mix(u_tl, u_br, pos)) * inbounds;\n\n gl_FragColor = color * u_color;\n}\n", + }, + { + "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", } }; diff --git a/src/shader/text.fragment.glsl b/src/shader/text.fragment.glsl new file mode 100644 index 000000000..8df552c17 --- /dev/null +++ b/src/shader/text.fragment.glsl @@ -0,0 +1,5 @@ +uniform vec4 u_color; + +void main() { + gl_FragColor = u_color; +} diff --git a/src/shader/text.vertex.glsl b/src/shader/text.vertex.glsl new file mode 100644 index 000000000..866c3cd2f --- /dev/null +++ b/src/shader/text.vertex.glsl @@ -0,0 +1,7 @@ +attribute vec2 a_pos; + +uniform mat4 u_matrix; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); +}