retain child tiles
This commit is contained in:
@@ -4,11 +4,12 @@
|
||||
#include "../platform/platform.hpp"
|
||||
#include "../renderer/painter.hpp"
|
||||
#include "transform.hpp"
|
||||
#include <llmr/map/tile.hpp>
|
||||
|
||||
#include <forward_list>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
class tile;
|
||||
|
||||
class map {
|
||||
public:
|
||||
map();
|
||||
@@ -22,20 +23,22 @@ public:
|
||||
void moveBy(double dx, double dy);
|
||||
void scaleBy(double ds, double cx, double cy);
|
||||
void rotateBy(double cx, double cy, double sx, double sy, double ex, double ey);
|
||||
void tileLoaded(std::shared_ptr<tile> tile);
|
||||
void tileFailed(std::shared_ptr<tile> tile);
|
||||
void tileLoaded(tile::ptr tile);
|
||||
void tileFailed(tile::ptr tile);
|
||||
|
||||
private:
|
||||
void updateTiles();
|
||||
tile::ptr addTile(tile_id id);
|
||||
tile::ptr hasTile(tile_id id);
|
||||
|
||||
private:
|
||||
transform *transform;
|
||||
painter *painter;
|
||||
|
||||
// int32_t min_zoom;
|
||||
// int32_t max_zoom;
|
||||
int32_t min_zoom;
|
||||
int32_t max_zoom;
|
||||
|
||||
std::vector<std::shared_ptr<tile>> tiles;
|
||||
std::forward_list<tile::ptr> tiles;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -4,18 +4,26 @@
|
||||
#include "../geometry/linevertexbuffer.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <forward_list>
|
||||
#include <mutex>
|
||||
#include <llmr/util/vec2.hpp>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
typedef vec3<int32_t> tile_id;
|
||||
|
||||
class tile {
|
||||
public:
|
||||
typedef std::shared_ptr<tile> ptr;
|
||||
enum state {
|
||||
initial,
|
||||
loading,
|
||||
ready,
|
||||
obsolete
|
||||
};
|
||||
|
||||
public:
|
||||
tile(int32_t z, int32_t x, int32_t y);
|
||||
tile(tile_id id);
|
||||
~tile();
|
||||
|
||||
void setData(uint8_t *data, uint32_t bytes);
|
||||
@@ -26,18 +34,20 @@ public:
|
||||
|
||||
void cancel();
|
||||
|
||||
const std::string toString() const;
|
||||
|
||||
static tile_id parent(const tile_id& id, int32_t z);
|
||||
static std::forward_list<tile_id> children(const tile_id& id, int32_t z);
|
||||
|
||||
// static int64_t toID(int32_t z, int32_t x, int32_t y, int32_t w = 0);
|
||||
// static vec4<int32_t> fromID(int64_t id);
|
||||
|
||||
public:
|
||||
const int32_t z, x, y;
|
||||
bool loaded;
|
||||
bool cancelled;
|
||||
const tile_id id;
|
||||
state state;
|
||||
linevertexbuffer lineVertex;
|
||||
|
||||
private:
|
||||
std::mutex mutex;
|
||||
|
||||
// Source data
|
||||
uint8_t *data;
|
||||
uint32_t bytes;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <llmr/util/vec2.hpp>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
@@ -26,7 +27,7 @@ public:
|
||||
void setLonLat(double lon, double lat);
|
||||
|
||||
// Getters
|
||||
void matrixFor(float matrix[16], uint32_t z, uint32_t x, uint32_t y) const;
|
||||
void matrixFor(float matrix[16], const vec3<int32_t>& id) const;
|
||||
int32_t getZoom() const;
|
||||
void getLonLat(double& lon, double& lat) const;
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ public:
|
||||
void clear();
|
||||
void render(std::shared_ptr<tile> tile);
|
||||
|
||||
void switchShader(Shader *shader, float matrix[16]);
|
||||
void drawClippingMask();
|
||||
void switchShader(Shader *shader);
|
||||
|
||||
private:
|
||||
void setupShaders();
|
||||
@@ -37,9 +38,7 @@ private:
|
||||
FillShader *fillShader;
|
||||
LineShader *lineShader;
|
||||
|
||||
// uint32_t vertexArray;
|
||||
uint32_t triangleVertexBuffer;
|
||||
uint32_t fillVertexBuffer;
|
||||
uint32_t tile_stencil_buffer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ template <typename T = double>
|
||||
struct vec2 {
|
||||
T x, y;
|
||||
|
||||
inline vec2() {}
|
||||
inline vec2(const vec2& o) : x(o.x), y(o.y) {}
|
||||
inline vec2(T x, T y) : x(x), y(y) {}
|
||||
inline bool operator==(const vec2& rhs) const {
|
||||
return x == rhs.x && y == rhs.y;
|
||||
}
|
||||
@@ -16,6 +19,9 @@ template <typename T = double>
|
||||
struct vec3 {
|
||||
T x, y, z;
|
||||
|
||||
inline vec3() {}
|
||||
inline vec3(const vec3& o) : x(o.x), y(o.y), z(o.z) {}
|
||||
inline vec3(T x, T y, T z) : x(x), y(y), z(z) {}
|
||||
inline bool operator==(const vec3& rhs) const {
|
||||
return x == rhs.x && y == rhs.y && z == rhs.z;
|
||||
}
|
||||
@@ -25,6 +31,9 @@ template <typename T = double>
|
||||
struct vec4 {
|
||||
T x, y, z, w;
|
||||
|
||||
inline vec4() {}
|
||||
inline vec4(const vec4& o) : x(o.x), y(o.y), z(o.z), w(o.w) {}
|
||||
inline vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
|
||||
inline bool operator==(const vec4& rhs) const {
|
||||
return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ public:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_STENCIL_BITS, 8);
|
||||
glfwWindowHint(GLFW_DEPTH_BITS, 16);
|
||||
|
||||
window = glfwCreateWindow(640, 480, "llmr", NULL, NULL);
|
||||
if (!window) {
|
||||
glfwTerminate();
|
||||
@@ -29,6 +32,9 @@ public:
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
|
||||
int stencil_bits = glfwGetWindowAttrib(window, GLFW_STENCIL_BITS);
|
||||
fprintf(stderr, "stencil bits: %d\n", stencil_bits);
|
||||
|
||||
map->setup();
|
||||
|
||||
|
||||
@@ -173,6 +179,7 @@ void restart(void *) {
|
||||
}
|
||||
|
||||
void request(void *, tile::ptr tile) {
|
||||
assert((bool)tile);
|
||||
// fprintf(stderr, "request %d/%d/%d\n", tile->z, tile->x, tile->y);
|
||||
|
||||
// fprintf(stderr, "requesting tile\n");
|
||||
@@ -180,9 +187,9 @@ void request(void *, tile::ptr tile) {
|
||||
NSString *urlTemplate = @"http://localhost:3333/gl/tiles/plain/%d-%d-%d.vector.pbf";
|
||||
NSString *urlString = [NSString
|
||||
stringWithFormat:urlTemplate,
|
||||
tile->z,
|
||||
tile->x,
|
||||
tile->y];
|
||||
tile->id.z,
|
||||
tile->id.x,
|
||||
tile->id.y];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
// NSLog(@"Requesting %@", urlString);
|
||||
|
||||
@@ -210,12 +217,9 @@ void request(void *, tile::ptr tile) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "[%s] status code %d\n", [urlString UTF8String], code);
|
||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
||||
view->map->tileFailed(tile);
|
||||
});
|
||||
}
|
||||
|
||||
fprintf(stderr, "[%s] status code %d\n", [urlString UTF8String], code);
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
||||
|
||||
115
src/map/map.cpp
115
src/map/map.cpp
@@ -6,12 +6,15 @@
|
||||
#include <thread>
|
||||
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
|
||||
using namespace llmr;
|
||||
|
||||
map::map()
|
||||
: transform(new class transform()),
|
||||
painter(new class painter(transform)) {
|
||||
painter(new class painter(transform)),
|
||||
min_zoom(0),
|
||||
max_zoom(14) {
|
||||
|
||||
// transform->setLonLat(13, 50);
|
||||
// transform->setZoom(3);
|
||||
@@ -50,9 +53,38 @@ void map::rotateBy(double cx, double cy, double sx, double sy, double ex, double
|
||||
platform::restart(this);
|
||||
}
|
||||
|
||||
|
||||
tile::ptr map::hasTile(tile_id id) {
|
||||
for (tile::ptr& tile : tiles) {
|
||||
if (tile->id == id) {
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
|
||||
return tile::ptr();
|
||||
}
|
||||
|
||||
tile::ptr map::addTile(tile_id id) {
|
||||
tile::ptr tile = hasTile(id);
|
||||
|
||||
if (!tile.get()) {
|
||||
// We couldn't find the tile in the list. Create a new one.
|
||||
tile = std::make_shared<class tile>(id);
|
||||
assert(tile);
|
||||
std::cerr << "init " << id.z << "/" << id.x << "/" << id.y << std::endl;
|
||||
std::cerr << "add " << tile->toString() << std::endl;
|
||||
tiles.push_front(tile);
|
||||
}
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
void map::updateTiles() {
|
||||
// Figure out what tiles we need to load
|
||||
int32_t zoom = transform->getZoom();
|
||||
if (zoom > max_zoom) zoom = max_zoom;
|
||||
if (zoom < min_zoom) zoom = min_zoom;
|
||||
|
||||
int32_t max_dim = pow(2, zoom);
|
||||
|
||||
// Map four viewport corners to pixel coordinates
|
||||
@@ -65,55 +97,75 @@ void map::updateTiles() {
|
||||
br.x = fmin(max_dim, ceil(fmax(box.tr.x, box.br.x)));
|
||||
br.y = fmin(max_dim, ceil(fmax(box.bl.y, box.br.y)));
|
||||
|
||||
typedef vec3<int32_t> tile_id;
|
||||
|
||||
// TODO: Discard tiles that are outside the viewport
|
||||
std::vector<tile_id> required;
|
||||
std::forward_list<tile_id> required;
|
||||
for (int32_t y = tl.y; y < br.y; y++) {
|
||||
for (int32_t x = tl.x; x < br.x; x++) {
|
||||
tile_id id; id.z = zoom; id.x = x; id.y = y;
|
||||
required.push_back(id);
|
||||
required.emplace_front(x, y, zoom);
|
||||
}
|
||||
}
|
||||
|
||||
// Add existing child/parent tiles if the actual tile is not yet loaded
|
||||
// TODO
|
||||
std::forward_list<tile_id> retain(required);
|
||||
|
||||
// Add existing child/parent tiles if the actual tile is not yet loaded
|
||||
for (const tile_id& id : required) {
|
||||
tile::ptr tile = addTile(id);
|
||||
assert(tile);
|
||||
|
||||
if (tile->state == tile::initial || tile->state == tile::loading) {
|
||||
// The tile we require is not yet loaded. Try to find a parent or
|
||||
// child tile that we already have.
|
||||
std::forward_list<tile_id> covering;
|
||||
|
||||
// Find existing child tiles.
|
||||
// TODO: Limit to existing tile ranges.
|
||||
if (id.z + 1 <= max_zoom) {
|
||||
covering = tile::children(id, id.z + 1);
|
||||
}
|
||||
|
||||
// Find existing parent tile.
|
||||
// TODO: Limit to existing tile ranges.
|
||||
if (id.z - 1 >= min_zoom) {
|
||||
covering.push_front(tile::parent(id, id.z - 1));
|
||||
}
|
||||
|
||||
for (const tile_id& covering_id : covering) {
|
||||
tile::ptr covering_tile = hasTile(covering_id);
|
||||
if (covering_tile) {
|
||||
assert(covering_tile);
|
||||
if (covering_tile->state == tile::ready) {
|
||||
retain.emplace_front(covering_tile->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tile->state == tile::initial) {
|
||||
// If the tile is new, we have to make sure to load it.
|
||||
tile->state = tile::loading;
|
||||
platform::request(this, tile);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove tiles that we definitely don't need, i.e. tiles that are not on
|
||||
// the required list.
|
||||
for (std::vector<tile::ptr>::iterator it = tiles.begin(); it != tiles.end(); it++) {
|
||||
tile::ptr& tile = *it;
|
||||
tile_id id; id.z = tile->z; id.x = tile->x; id.y = tile->y;
|
||||
std::vector<tile_id>::const_iterator required_it = std::find(required.begin(), required.end(), id);
|
||||
bool retain = required_it != required.end();
|
||||
if (retain) {
|
||||
// We already have the tile; remove it from the list of required tiles.
|
||||
required.erase(required_it);
|
||||
} else {
|
||||
// We don't need this tile, so we can remove it entirely.
|
||||
std::vector<tile::ptr>::iterator to_remove = it - 1;
|
||||
tiles.remove_if([&retain](const tile::ptr& tile) {
|
||||
assert(tile);
|
||||
bool obsolete = std::find(retain.begin(), retain.end(), tile->id) == retain.end();
|
||||
if (obsolete) {
|
||||
tile->cancel();
|
||||
tiles.erase(it);
|
||||
it = to_remove;
|
||||
}
|
||||
}
|
||||
|
||||
// Required now only contains those tiles that are not yet in the list of
|
||||
// tiles, so we should add them all.
|
||||
for (tile_id& id : required) {
|
||||
tile::ptr tile = std::make_shared<class tile>(id.z, id.x, id.y);
|
||||
tiles.push_back(tile);
|
||||
platform::request(this, tile);
|
||||
}
|
||||
return obsolete;
|
||||
});
|
||||
}
|
||||
|
||||
bool map::render() {
|
||||
painter->clear();
|
||||
|
||||
for (tile::ptr& tile : tiles) {
|
||||
// painter->viewport();
|
||||
if (tile->loaded) {
|
||||
assert(tile);
|
||||
if (tile->state == tile::ready) {
|
||||
painter->render(tile);
|
||||
}
|
||||
}
|
||||
@@ -122,6 +174,7 @@ bool map::render() {
|
||||
}
|
||||
|
||||
void map::tileLoaded(tile::ptr tile) {
|
||||
std::cerr << "loaded " << tile->toString() << std::endl;
|
||||
platform::restart(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "pbf.hpp"
|
||||
#include <llmr/util/vec2.hpp>
|
||||
#include <llmr/util/string.hpp>
|
||||
#include <cmath>
|
||||
|
||||
using namespace llmr;
|
||||
@@ -34,48 +35,69 @@ using namespace llmr;
|
||||
// return coord;
|
||||
// };
|
||||
|
||||
tile::tile(int32_t z, int32_t x, int32_t y)
|
||||
: z(z),
|
||||
x(x),
|
||||
y(y),
|
||||
loaded(false),
|
||||
cancelled(false),
|
||||
tile_id tile::parent(const tile_id& id, int32_t z) {
|
||||
assert(z < id.z);
|
||||
tile_id pos(id);
|
||||
while (pos.z > z) {
|
||||
pos.z--;
|
||||
pos.x = floor(pos.x / 2);
|
||||
pos.y = floor(pos.y / 2);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
std::forward_list<tile_id> tile::children(const tile_id& id, int32_t z) {
|
||||
assert(z > id.z);
|
||||
int32_t factor = pow(2, z - id.z);
|
||||
|
||||
std::forward_list<tile_id> children;
|
||||
for (int32_t y = id.y * factor, y_max = (id.y + 1) * factor; y < y_max; y++) {
|
||||
for (int32_t x = id.x * factor, x_max = (id.x + 1) * factor; x < x_max; x++) {
|
||||
children.emplace_front(x, y, z);
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
|
||||
tile::tile(tile_id id)
|
||||
: id(id),
|
||||
state(initial),
|
||||
data(0),
|
||||
bytes(0) {
|
||||
}
|
||||
|
||||
tile::~tile() {
|
||||
fprintf(stderr, "[%p] deleting tile %d/%d/%d\n", this, z, x, y);
|
||||
fprintf(stderr, "[%p] deleting tile %d/%d/%d\n", this, id.z, id.x, id.y);
|
||||
if (this->data) {
|
||||
free(this->data);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string tile::toString() const {
|
||||
return util::sprintf("[tile %d/%d/%d]", id.z, id.x, id.y);
|
||||
}
|
||||
|
||||
|
||||
void tile::setData(uint8_t *data, uint32_t bytes) {
|
||||
this->data = (uint8_t *)malloc(bytes);
|
||||
this->bytes = bytes;
|
||||
memcpy(this->data, data, bytes);
|
||||
}
|
||||
|
||||
void tile::cancel()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
void tile::cancel() {
|
||||
// TODO: thread safety
|
||||
if (!cancelled) {
|
||||
cancelled = true;
|
||||
if (state != obsolete) {
|
||||
state = obsolete;
|
||||
} else {
|
||||
assert((!"logic error? multiple cancelleations"));
|
||||
}
|
||||
}
|
||||
|
||||
bool tile::parse()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (cancelled) {
|
||||
return false;
|
||||
}
|
||||
bool tile::parse() {
|
||||
if (state == obsolete) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "[%p] parsing tile [%d/%d/%d]...\n", this, z, x, y);
|
||||
@@ -84,7 +106,7 @@ bool tile::parse()
|
||||
|
||||
int code = setjmp(tile.jump_buffer);
|
||||
if (code > 0) {
|
||||
fprintf(stderr, "[%p] parsing tile [%d/%d/%d]... failed: %s\n", this, z, x, y, tile.msg.c_str());
|
||||
fprintf(stderr, "[%p] parsing tile [%d/%d/%d]... failed: %s\n", this, id.z, id.x, id.y, tile.msg.c_str());
|
||||
cancel();
|
||||
return false;
|
||||
}
|
||||
@@ -101,14 +123,12 @@ bool tile::parse()
|
||||
|
||||
// fprintf(stderr, "[%p] parsing tile [%d/%d/%d]... done\n", this, z, x, y);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (cancelled) {
|
||||
return false;
|
||||
}
|
||||
if (state == obsolete) {
|
||||
return false;
|
||||
} else {
|
||||
state = ready;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <llmr/map/transform.hpp>
|
||||
|
||||
#include <llmr/util/mat4.h>
|
||||
#include <llmr/util/vec2.hpp>
|
||||
#include <llmr/util/math.hpp>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
@@ -131,8 +130,8 @@ double transform::pixel_y() const {
|
||||
return center + y;
|
||||
}
|
||||
|
||||
void transform::matrixFor(float matrix[16], uint32_t tile_z, uint32_t tile_x, uint32_t tile_y) const {
|
||||
const double tile_scale = pow(2, tile_z);
|
||||
void transform::matrixFor(float matrix[16], const vec3<int32_t>& id) const {
|
||||
const double tile_scale = pow(2, id.z);
|
||||
const double tile_size = scale * size / tile_scale;
|
||||
|
||||
mat4_identity(matrix);
|
||||
@@ -142,7 +141,7 @@ void transform::matrixFor(float matrix[16], uint32_t tile_z, uint32_t tile_x, ui
|
||||
mat4_translate(matrix, matrix, -0.5f * (float)width, -0.5f * (float)height, 0);
|
||||
|
||||
mat4_translate(matrix, matrix, pixel_x(), pixel_y(), 0);
|
||||
mat4_translate(matrix, matrix, tile_x * tile_size, tile_y * tile_size, 0);
|
||||
mat4_translate(matrix, matrix, id.x * tile_size, id.y * tile_size, 0);
|
||||
|
||||
// TODO: Get rid of the 8 (scaling from 4096 to 512 px tile size);
|
||||
mat4_scale(matrix, matrix, scale / tile_scale / 8, scale / tile_scale / 8, 1);
|
||||
|
||||
@@ -11,49 +11,37 @@ using namespace llmr;
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
|
||||
GLfloat triangle_vertices[] = {
|
||||
100, 100,
|
||||
100, 300,
|
||||
150, 150
|
||||
};
|
||||
|
||||
GLfloat fill_vertices[] = {
|
||||
GLshort tile_stencil_vertices[] = {
|
||||
0, 0,
|
||||
300, 0,
|
||||
0, 300,
|
||||
300, 300
|
||||
4096, 0,
|
||||
0, 4096,
|
||||
4096, 4096
|
||||
};
|
||||
|
||||
|
||||
painter::painter(class transform *transform)
|
||||
: transform(transform),
|
||||
currentShader(NULL),
|
||||
fillShader(NULL) {
|
||||
|
||||
fillShader(NULL),
|
||||
lineShader(NULL) {
|
||||
}
|
||||
|
||||
|
||||
void painter::setup() {
|
||||
setupShaders();
|
||||
|
||||
|
||||
assert(fillShader);
|
||||
assert(lineShader);
|
||||
|
||||
// Set up the stencil quad we're using to generate the stencil mask.
|
||||
glGenBuffers(1, &tile_stencil_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, tile_stencil_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(tile_stencil_vertices), tile_stencil_vertices, GL_STATIC_DRAW);
|
||||
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
|
||||
|
||||
glGenBuffers(1, &triangleVertexBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices, GL_STATIC_DRAW);
|
||||
|
||||
glGenBuffers(1, &fillVertexBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, fillVertexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(fill_vertices), fill_vertices, GL_STATIC_DRAW);
|
||||
|
||||
|
||||
// glGenVertexArraysOES(1, &vertexArray);
|
||||
// glBindVertexArrayOES(vertexArray);
|
||||
// glBindVertexArrayOES(0);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
void painter::setupShaders() {
|
||||
@@ -62,10 +50,7 @@ void painter::setupShaders() {
|
||||
}
|
||||
|
||||
void painter::teardown() {
|
||||
glDeleteBuffers(1, &triangleVertexBuffer);
|
||||
glDeleteBuffers(1, &fillVertexBuffer);
|
||||
|
||||
// glDeleteVertexArraysOES(1, &vertexArray);
|
||||
glDeleteBuffers(1, &tile_stencil_buffer);
|
||||
|
||||
if (fillShader) {
|
||||
delete fillShader;
|
||||
@@ -87,74 +72,74 @@ void painter::changeMatrix(std::shared_ptr<tile> tile) {
|
||||
mat4_ortho(projMatrix, 0, transform->width, transform->height, 0, 1, 10);
|
||||
|
||||
float mvMatrix[16];
|
||||
transform->matrixFor(mvMatrix, tile->z, tile->x, tile->y);
|
||||
transform->matrixFor(mvMatrix, tile->id);
|
||||
|
||||
mat4_multiply(matrix, projMatrix, mvMatrix);
|
||||
}
|
||||
|
||||
void painter::drawClippingMask() {
|
||||
switchShader(lineShader);
|
||||
glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix);
|
||||
|
||||
glColorMask(false, false, false, false);
|
||||
|
||||
// Clear the entire stencil buffer, except for the 7th bit, which stores
|
||||
// the global clipping mask that allows us to avoid drawing in regions of
|
||||
// tiles we've already painted in.
|
||||
glClearStencil(0x0);
|
||||
glStencilMask(0xBF);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// The stencil test will fail always, meaning we set all pixels covered
|
||||
// by this geometry to 0x80. We use the highest bit 0x80 to mark the regions
|
||||
// we want to draw in. All pixels that have this bit *not* set will never be
|
||||
// drawn in.
|
||||
glStencilFunc(GL_EQUAL, 0xC0, 0x40);
|
||||
glStencilMask(0xC0);
|
||||
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
|
||||
|
||||
// Draw the clipping mask
|
||||
glBindBuffer(GL_ARRAY_BUFFER, tile_stencil_buffer);
|
||||
glVertexAttribPointer(lineShader->a_pos, 2, GL_SHORT, false, 0, BUFFER_OFFSET(0));
|
||||
glUniform4f(lineShader->u_color, 1.0f, 0.0f, 1.0f, 1.0f);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(tile_stencil_vertices));
|
||||
|
||||
// glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(GL_EQUAL, 0x80, 0x80);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glStencilMask(0x00);
|
||||
glColorMask(true, true, true, true);
|
||||
}
|
||||
|
||||
void painter::clear() {
|
||||
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
glClearStencil(0x0);
|
||||
glStencilMask(0xFF);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void painter::render(std::shared_ptr<tile> tile) {
|
||||
void painter::render(tile::ptr tile) {
|
||||
if (tile->state != tile::ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
changeMatrix(tile);
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
drawClippingMask();
|
||||
|
||||
// fprintf(stderr, "render tile\n");
|
||||
switchShader(lineShader, matrix);
|
||||
switchShader(lineShader);
|
||||
glUniformMatrix4fv(lineShader->u_matrix, 1, GL_FALSE, matrix);
|
||||
|
||||
// glEnable(GL_BLEND);
|
||||
|
||||
// glVertexAttribPointer(fillShader->a_pos, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
||||
// glVertexAttribPointer(fillShader->a_pos, 2, GL_SHORT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBuffer);
|
||||
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);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, tile->lineVertex.length());
|
||||
|
||||
// switchShader(fillShader, matrix);
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBuffer);
|
||||
// glVertexAttribPointer(fillShader->a_pos, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
||||
// glUniform4f(fillShader->u_color, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
// glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
|
||||
|
||||
|
||||
|
||||
|
||||
// glBindVertexArrayOES(vertexArray);
|
||||
// switchShader(fillShader, matrix);
|
||||
// glUniformMatrix4fv(fillShader->u_matrix, 1, GL_FALSE, matrix);
|
||||
|
||||
// glEnable(GL_STENCIL_TEST);
|
||||
|
||||
// Draw stencil mask.
|
||||
// glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
// glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
|
||||
// glStencilFunc(GL_EQUAL, 0xFF, 0xFF);
|
||||
// glStencilMask(0xFF);
|
||||
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBuffer);
|
||||
// glVertexAttribPointer(fillShader->a_pos, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
||||
// glUniform4f(fillShader->u_color, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
// glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
|
||||
|
||||
|
||||
// // Draw covering fill.
|
||||
// glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
// glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
// glStencilFunc(GL_EQUAL, 0xFF, 0xFF);
|
||||
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, fillVertexBuffer);
|
||||
// glVertexAttribPointer(fillShader->a_pos, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
|
||||
// glUniform4f(fillShader->u_color, 1.0f, 0.0f, 0.0f, 1.0f);
|
||||
// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
void painter::viewport() {
|
||||
@@ -162,7 +147,7 @@ void painter::viewport() {
|
||||
}
|
||||
|
||||
// Switches to a different shader program.
|
||||
void painter::switchShader(Shader *shader, float matrix[16]) {
|
||||
void painter::switchShader(Shader *shader) {
|
||||
if (currentShader != shader) {
|
||||
glUseProgram(shader->program);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
uniform vec4 u_color;
|
||||
|
||||
void main() {
|
||||
|
||||
Reference in New Issue
Block a user