diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2014-01-13 18:07:13 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2014-01-13 18:07:13 +0100 |
commit | 654972bb3feb1f451a820afbc7c46e7e502ce687 (patch) | |
tree | f154d0dab2415f0494a4d976f7226118039d9661 | |
parent | 16d0c83df2b1a882eae1c4d988a84bca5fe84e9a (diff) | |
download | qtlocation-mapboxgl-654972bb3feb1f451a820afbc7c46e7e502ce687.tar.gz |
cmake + tile loading
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | emscripten/main.cpp | 14 | ||||
-rw-r--r-- | include/llmr/map/map.hpp | 9 | ||||
-rw-r--r-- | include/llmr/map/tile.hpp | 7 | ||||
-rw-r--r-- | include/llmr/map/transform.hpp | 10 | ||||
-rw-r--r-- | include/llmr/platform/gl.hpp | 2 | ||||
-rw-r--r-- | include/llmr/platform/platform.hpp | 13 | ||||
-rw-r--r-- | include/llmr/renderer/painter.hpp | 6 | ||||
-rw-r--r-- | include/llmr/util/vec2.hpp | 40 | ||||
-rw-r--r-- | macosx/CMakeLists.txt | 37 | ||||
-rw-r--r-- | macosx/main.mm | 36 | ||||
-rw-r--r-- | src/CMakeLists.txt | 43 | ||||
-rw-r--r-- | src/map/map.cpp | 100 | ||||
-rw-r--r-- | src/map/pbf.hpp | 20 | ||||
-rw-r--r-- | src/map/tile.cpp | 50 | ||||
-rw-r--r-- | src/map/transform.cpp | 56 | ||||
-rw-r--r-- | src/renderer/painter.cpp | 5 |
18 files changed, 389 insertions, 84 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..fa5ddfdfab --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) +project(llmr) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11") + +add_subdirectory(src) +add_subdirectory(macosx) @@ -1,5 +1,5 @@ -CXXFLAGS = -Wall -Wextra -std=c++11 -stdlib=libc++ -fno-exceptions -CPPFLAGS = -O3 -DDEBUG +CXXFLAGS = -O2 -Wall -Wextra -std=c++11 -stdlib=libc++ -fno-exceptions +CPPFLAGS = -DDEBUG INCLUDE = -Iinclude @@ -21,8 +21,9 @@ main: macosx macosx: SRCS += macosx/main.mm emscripten: SRCS += emscripten/main.cpp +emscripten3: SRCS += emscripten/main.cpp -macosx emscripten: OBJS = $(patsubst %.mm,%.o,$(patsubst %.cpp,%.o,$(patsubst %.c,%.o,$(SRCS)))) +macosx emscripten emscripten3: OBJS = $(patsubst %.mm,%.o,$(patsubst %.cpp,%.o,$(patsubst %.c,%.o,$(SRCS)))) %.o: %.cpp $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE) -c -o $@ $^ @@ -36,13 +37,18 @@ macosx emscripten: OBJS = $(patsubst %.mm,%.o,$(patsubst %.cpp,%.o,$(patsubst %. .SECONDEXPANSION: macosx: $$(OBJS) - $(CXX) $(OBJS) $(INCLUDE) -lglfw3 -framework OpenGL -framework Foundation -o macosx/main + $(CXX) -O3 $(OBJS) $(INCLUDE) -lglfw3 -framework OpenGL -framework Foundation -o macosx/main emscripten: $$(OBJS) $(CXX) $(OBJS) $(INCLUDE) -o emscripten/main.js +emscripten3: $$(OBJS) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OBJS) $(INCLUDE) -s DOUBLE_MODE=0 -s FORCE_ALIGNED_MEMORY=1 -s PRECISE_I64_MATH=0 --closure 1 -o emscripten/main.js + uglifyjs emscripten/main.js -mc > emscripten/main.dist.js + gzip -c emscripten/main.dist.js > emscripten/main.dist.js.gz + clean: - rm -rf src/*/*.o - rm -rf macosx/main + rm -rf */*.o */*/*.o + rm -rf macosx/main emscripten/main.js emscripten/main.js.map .PHONY: macosx emscripten diff --git a/emscripten/main.cpp b/emscripten/main.cpp index 20e9212baf..4565a67d51 100644 --- a/emscripten/main.cpp +++ b/emscripten/main.cpp @@ -3,6 +3,7 @@ #include <cstdio> #include <cstdlib> #include <cmath> + #include <unistd.h> #include <llmr/llmr.hpp> #include <llmr/map/tile.hpp> @@ -18,8 +19,7 @@ public: MapView() : dirty(true), platform(new llmr::platform(this)), - painter(new llmr::painter(platform)), - map(new llmr::map(platform, painter)) { + map(new llmr::map(platform)) { // Initialize GLFW if (!glfwInit()) { @@ -42,14 +42,13 @@ public: exit(1); } - painter->setup(); - painter->resize(width, height); + map->setup(); + map->resize(width, height); } ~MapView() { delete map; - delete painter; delete platform; glfwTerminate(); } @@ -65,7 +64,7 @@ public: static void scroll(float pos) { double delta = pos; - bool is_wheel = delta != 0 && fmod(delta, 4.000244140625) == 0; + // bool is_wheel = delta != 0 && fmod(delta, 4.000244140625) == 0; double absdelta = delta < 0 ? -delta : delta; double scale = 2.0 / (1.0 + exp(-absdelta / 100.0)); @@ -86,6 +85,8 @@ public: static void mouseclick(int button, int action) { if (button == GLFW_MOUSE_BUTTON_1) { view->tracking = action == GLFW_PRESS; + } else if (button == GLFW_MOUSE_BUTTON_RIGHT) { + fprintf(stderr, "right mouse\n"); } } @@ -110,7 +111,6 @@ public: llmr::platform *platform; - llmr::painter *painter; llmr::map *map; }; diff --git a/include/llmr/map/map.hpp b/include/llmr/map/map.hpp index 7f2903a261..745ccce89d 100644 --- a/include/llmr/map/map.hpp +++ b/include/llmr/map/map.hpp @@ -11,7 +11,7 @@ class tile; class map { public: - map(class platform *platform); + map(); ~map(); void setup(); @@ -26,10 +26,15 @@ public: void tileFailed(tile *tile); private: - platform *platform; + void updateTiles(); + +private: transform *transform; painter *painter; + // int32_t min_zoom; + // int32_t max_zoom; + std::vector<tile *> tiles; }; diff --git a/include/llmr/map/tile.hpp b/include/llmr/map/tile.hpp index 026810ace4..95d0593f72 100644 --- a/include/llmr/map/tile.hpp +++ b/include/llmr/map/tile.hpp @@ -5,6 +5,7 @@ #include <stdint.h> #include <vector> +#include <llmr/util/vec2.hpp> namespace llmr { @@ -18,9 +19,15 @@ public: void parseFeature(const uint8_t *data, uint32_t bytes); void loadGeometry(const uint8_t *data, uint32_t bytes); + void cancel(); + + static uint64_t toID(int32_t z, int32_t x, int32_t y, int32_t w = 0); + static vec4<int32_t> fromID(uint64_t id); + public: const int32_t z, x, y; bool loaded; + bool cancelled; linevertexbuffer lineVertex; private: diff --git a/include/llmr/map/transform.hpp b/include/llmr/map/transform.hpp index 4ff3cc0076..5d81b0c202 100644 --- a/include/llmr/map/transform.hpp +++ b/include/llmr/map/transform.hpp @@ -3,8 +3,11 @@ #include <cstdint> + namespace llmr { +struct box; + class tile; class transform { @@ -24,8 +27,13 @@ public: // Getters void matrixFor(float matrix[16], uint32_t z, uint32_t x, uint32_t y) const; + int32_t getZoom() const; void getLonLat(double& lon, double& lat) const; + + // Temporary + void mapCornersToBox(uint32_t z, box& b) const; + private: double pixel_x() const; double pixel_y() const; @@ -40,6 +48,8 @@ private: double angle; double scale; + double min_scale, max_scale; + // tile size const int32_t size = 512; diff --git a/include/llmr/platform/gl.hpp b/include/llmr/platform/gl.hpp index 58d9099c70..fb36b5b794 100644 --- a/include/llmr/platform/gl.hpp +++ b/include/llmr/platform/gl.hpp @@ -12,8 +12,8 @@ #include <OpenGLES/ES2/gl.h> #include <OpenGLES/ES2/glext.h> #elif TARGET_OS_MAC - #include <GLFW/glfw3.h> #include <OpenGL/OpenGL.h> + #include <OpenGL/gl.h> #else #error Unsupported Apple platform #endif diff --git a/include/llmr/platform/platform.hpp b/include/llmr/platform/platform.hpp index e8aa972d7b..69efb68064 100644 --- a/include/llmr/platform/platform.hpp +++ b/include/llmr/platform/platform.hpp @@ -5,18 +5,13 @@ namespace llmr { class tile; -class platform { -public: - platform(void *obj) : obj(obj) {} - void restart(); - void request(tile *tile); +namespace platform { -private: - void *obj; -}; +void restart(void *obj); +void request(void *obj, tile *tile); } - +} #endif diff --git a/include/llmr/renderer/painter.hpp b/include/llmr/renderer/painter.hpp index 21dec5e075..e01f6828a1 100644 --- a/include/llmr/renderer/painter.hpp +++ b/include/llmr/renderer/painter.hpp @@ -6,13 +6,12 @@ namespace llmr { -class platform; class transform; class tile; class painter { public: - painter(class platform *platform, class transform *tranform); + painter(class transform *tranform); void setup(); void teardown(); @@ -31,7 +30,6 @@ private: public: private: - platform *platform; transform *transform; float matrix[16]; @@ -39,7 +37,7 @@ private: FillShader *fillShader; LineShader *lineShader; - uint32_t vertexArray; + // uint32_t vertexArray; uint32_t triangleVertexBuffer; uint32_t fillVertexBuffer; }; diff --git a/include/llmr/util/vec2.hpp b/include/llmr/util/vec2.hpp new file mode 100644 index 0000000000..abc49e54bd --- /dev/null +++ b/include/llmr/util/vec2.hpp @@ -0,0 +1,40 @@ +#ifndef llmr_util_vec2_ +#define llmr_util_vec2_ + +namespace llmr { + +template <typename T = double> +struct vec2 { + T x, y; + + // inline bool operator==(const vec2& rhs) const { + // return x == rhs.x && y == rhs.y; + // } +}; + +template <typename T = double> +struct vec3 { + T x, y, z; + + // inline bool operator==(const vec3& rhs) const { + // return x == rhs.x && y == rhs.y && z == rhs.z; + // } +}; + +template <typename T = double> +struct vec4 { + T x, y, z, w; + + // inline bool operator==(const vec4& rhs) const { + // return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w; + // } +}; + + +struct box { + vec2<double> tl, tr, bl, br; +}; + +} + +#endif diff --git a/macosx/CMakeLists.txt b/macosx/CMakeLists.txt new file mode 100644 index 0000000000..2a839c0c1d --- /dev/null +++ b/macosx/CMakeLists.txt @@ -0,0 +1,37 @@ +FIND_LIBRARY(COCOA_LIBRARY Cocoa) +FIND_LIBRARY(OPENGL_LIBRARY OpenGL) +FIND_LIBRARY(IOKIT_LIBRARY IOKit) +FIND_LIBRARY(COREVIDEO_LIBRARY CoreVidoe) + +FIND_PACKAGE(PkgConfig REQUIRED) +PKG_SEARCH_MODULE(GLFW REQUIRED glfw3) + + +SET(macosx_SOURCES + main.mm +) + +SET(macosx_HEADERS +) + +INCLUDE_DIRECTORIES( + ../include + ${GLFW_INCLUDE_DIRS} +) + +LINK_DIRECTORIES( + ${GLFW_LIBRARY_DIRS} +) + +ADD_EXECUTABLE(macosx + ${macosx_SOURCES} +) + +TARGET_LINK_LIBRARIES(macosx + llmr + ${COCOA_LIBRARY} + ${OPENGL_LIBRARY} + ${IOKIT_LIBRARY} + ${COREVIDOE_LIBRARY} + ${GLFW_LIBRARIES} +) diff --git a/macosx/main.mm b/macosx/main.mm index 3119d2b869..20b6cc174a 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -11,8 +11,10 @@ public: tracking(false), rotating(false), last_click(-1), - platform(new llmr::platform(this)), - map(new llmr::map(platform)) { + map(new llmr::map()) { + } + + void init() { if (!glfwInit()) { fprintf(stderr, "Failed to initialize glfw\n"); exit(1); @@ -143,7 +145,6 @@ public: ~MapView() { delete map; - delete platform; glfwTerminate(); } @@ -158,19 +159,25 @@ public: double last_click; GLFWwindow *window; - llmr::platform *platform; llmr::map *map; }; -void llmr::platform::restart() { - ((MapView *)obj)->dirty = true; + +MapView *view; + +namespace llmr { +namespace platform { + +void restart(void *) { + view->dirty = true; } -void llmr::platform::request(tile *tile) { +void request(void *, tile *tile) { fprintf(stderr, "request %d/%d/%d\n", tile->z, tile->x, tile->y); fprintf(stderr, "requesting tile\n"); - NSString *urlTemplate = @"http://api.tiles.mapbox.com/v3/mapbox.mapbox-streets-v4/%d/%d/%d.vector.pbf"; + // NSString *urlTemplate = @"http://api.tiles.mapbox.com/v3/mapbox.mapbox-streets-v4/%d/%d/%d.vector.pbf"; + NSString *urlTemplate = @"http://localhost:3333/gl/tiles/%d-%d-%d.vector.pbf"; NSString *urlString = [NSString stringWithFormat:urlTemplate, tile->z, @@ -192,20 +199,25 @@ void llmr::platform::request(tile *tile) { tile->setData((uint8_t *)[data bytes], [data length]); if (tile->parse()) { dispatch_async(dispatch_get_main_queue(), ^ { - ((MapView *)obj)->map->tileLoaded(tile); + view->map->tileLoaded(tile); }); return; } } dispatch_async(dispatch_get_main_queue(), ^ { - ((MapView *)obj)->map->tileFailed(tile); + view->map->tileFailed(tile); }); }]; } +} +} int main() { - MapView view; - return view.run(); + view = new MapView(); + view->init(); + int ret = view->run(); + delete view; + return ret; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..22f140bfac --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,43 @@ +SET(llmr_SOURCES + geometry/linevertexbuffer.cpp + map/map.cpp + map/tile.cpp + map/transform.cpp + renderer/painter.cpp + renderer/shader-fill.cpp + renderer/shader-line.cpp + renderer/shader.cpp + shader/shaders.c + util/mat4.c +) + +SET(llmr_HEADERS + ../include/llmr/geometry/linevertexbuffer.hpp + ../include/llmr/llmr.hpp + ../include/llmr/map/map.hpp + ../include/llmr/map/tile.hpp + ../include/llmr/map/transform.hpp + ../include/llmr/platform/gl.hpp + ../include/llmr/platform/platform.hpp + ../include/llmr/renderer/painter.hpp + ../include/llmr/renderer/shader-fill.hpp + ../include/llmr/renderer/shader-line.hpp + ../include/llmr/renderer/shader.hpp + ../include/llmr/util/math.hpp + ../include/llmr/util/vec2.hpp +) + +INCLUDE_DIRECTORIES( + ../include +) + +ADD_LIBRARY(llmr STATIC + ${llmr_SOURCES} + ${llmr_HEADERS} +) + +LINK_DIRECTORIES( +) + +TARGET_LINK_LIBRARIES(llmr +) diff --git a/src/map/map.cpp b/src/map/map.cpp index f010fa95af..1fcf5d6636 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -1,31 +1,20 @@ #include <llmr/map/map.hpp> #include <llmr/map/tile.hpp> +#include <llmr/util/vec2.hpp> #include <iostream> #include <thread> -using namespace llmr; - -map::map(class platform *platform) - : platform(platform), - transform(new class transform()), - painter(new class painter(platform, transform)) { - - transform->setLonLat(13, 50); - transform->setZoom(3); - - tiles.push_back(new class tile(1, 0, 0)); - platform->request(tiles.back()); +#include <cmath> - tiles.push_back(new class tile(1, 1, 0)); - platform->request(tiles.back()); - - tiles.push_back(new class tile(1, 0, 1)); - platform->request(tiles.back()); +using namespace llmr; - tiles.push_back(new class tile(1, 1, 1)); - platform->request(tiles.back()); +map::map() + : transform(new class transform()), + painter(new class painter(transform)) { + // transform->setLonLat(13, 50); + // transform->setZoom(3); } map::~map() { @@ -39,24 +28,83 @@ void map::setup() { void map::resize(uint32_t width, uint32_t height) { transform->width = width; transform->height = height; - platform->restart(); + updateTiles(); + platform::restart(this); } void map::moveBy(double dx, double dy) { transform->moveBy(dx, dy); - platform->restart(); + updateTiles(); + platform::restart(this); } void map::scaleBy(double ds, double cx, double cy) { transform->scaleBy(ds, cx, cy); - platform->restart(); + updateTiles(); + platform::restart(this); } void map::rotateBy(double cx, double cy, double sx, double sy, double ex, double ey) { transform->rotateBy(cx, cy, sx, sy, ex, ey); - platform->restart(); + updateTiles(); + platform::restart(this); } +void map::updateTiles() { + // Figure out what tiles we need to load + int32_t zoom = transform->getZoom(); + int32_t max_dim = pow(2, zoom); + + // Map four viewport corners to pixel coordinates + box box; + transform->mapCornersToBox(zoom, box); + + vec2<int32_t> tl, br; + tl.x = fmax(0, floor(fmin(box.tl.x, box.bl.x))); + tl.y = fmax(0, floor(fmin(box.tl.y, box.tr.y))); + 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))); + + // TODO: Discard tiles that are outside the viewport + std::vector<uint64_t> required; + for (int32_t y = tl.y; y < br.y; y++) { + for (int32_t x = tl.x; x < br.x; x++) { + required.push_back(tile::toID(zoom, x, y)); + } + } + + // Add existing child/parent tiles if the actual tile is not yet loaded + // TODO + + + // Remove tiles that we definitely don't need, i.e. tiles that are not on + // the required list. + for (std::vector<tile *>::iterator it = tiles.begin(); it != tiles.end(); it++) { + tile *tile = *it; + uint64_t id = tile::toID(tile->z, tile->x, tile->y); + std::vector<uint64_t>::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<class tile *>::iterator to_remove = it - 1; + 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 (int64_t id : required) { + vec4<int32_t> tile_coord = tile::fromID(id); + tile *tile = new class tile(tile_coord.z, tile_coord.x, tile_coord.y); + tiles.push_back(tile); + platform::request(this, tile); + } +} bool map::render() { painter->clear(); @@ -72,11 +120,7 @@ bool map::render() { } void map::tileLoaded(tile *tile) { - platform->restart(); - // fprintf(stderr, "[%8zx] tile loaded %d/%d/%d\n", - // std::hash<std::thread::id>()(std::this_thread::get_id()), - // tile->z, tile->x, tile->y); - // schedule rerender + platform::restart(this); } void map::tileFailed(tile *tile) { diff --git a/src/map/pbf.hpp b/src/map/pbf.hpp index 29c252e115..b9ed95a1a0 100644 --- a/src/map/pbf.hpp +++ b/src/map/pbf.hpp @@ -22,11 +22,11 @@ struct pbf { inline bool next(); template <typename T = uint32_t> inline T varint(); - inline int64_t svarint(); + template <typename T = uint32_t> inline T svarint(); inline std::string string(); inline float float32(); inline double float64(); - inline int64_t int64(); + // inline int64_t int64(); inline bool boolean(); template <typename T, typename... Args> @@ -91,10 +91,11 @@ T pbf::varint() return result; } -int64_t pbf::svarint() +template <typename T> +T pbf::svarint() { - uint64_t n = varint(); - return (n >> 1) ^ -(int64_t)(n & 1); + T n = varint<T>(); + return (n >> 1) ^ -(T)(n & 1); } std::string pbf::string() @@ -112,6 +113,7 @@ float pbf::float32() memcpy(&result, data - 4, 4); return result; } + double pbf::float64() { skipBytes(8); @@ -120,10 +122,10 @@ double pbf::float64() return result; } -int64_t pbf::int64() -{ - return (int64_t)varint(); -} +// int64_t pbf::int64() +// { +// return (int64_t)varint(); +// } bool pbf::boolean() { diff --git a/src/map/tile.cpp b/src/map/tile.cpp index 6216c55caa..c04392af3a 100644 --- a/src/map/tile.cpp +++ b/src/map/tile.cpp @@ -1,18 +1,43 @@ #include <llmr/map/tile.hpp> #include <stdint.h> +#include <cassert> // #include <iostream> #include <thread> #include "pbf.hpp" +#include <llmr/util/vec2.hpp> +#include <cmath> using namespace llmr; + +uint64_t tile::toID(int32_t z, int32_t x, int32_t y, int32_t w) { + w *= 2; + if (w < 0) w = w * -1 -1; + int32_t dim = 1 << z; + return ((dim * dim * w + dim * y + x) * 32) + z; +} + +vec4<int32_t> tile::fromID(uint64_t id) { + vec4<int32_t> coord; + coord.z = id % 32; + int32_t dim = 1 << coord.z; + int32_t xy = ((id - coord.z) / 32); + coord.x = xy % dim; + coord.y = ((xy - coord.x) / dim) % dim; + coord.w = floor(xy / (dim * dim)); + if (coord.w % 2 != 0) coord.w = coord.w * -1 -1; + coord.w /= 2; + return coord; +}; + tile::tile(int32_t z, int32_t x, int32_t y) : z(z), x(x), y(y), loaded(false), + cancelled(false), data(0), bytes(0) { } @@ -23,8 +48,26 @@ void tile::setData(uint8_t *data, uint32_t bytes) { memcpy(this->data, data, bytes); } +void tile::cancel() +{ + // TODO: thread safety + if (!cancelled) { + cancelled = true; + if (loaded) { + delete this; + } + } else { + assert((!"logic error? multiple cancelleations")); + } +} + bool tile::parse() { + if (cancelled) { + delete this; + return false; + } + fprintf(stderr, "[%p] parsing tile...\n", this); pbf tile(data, bytes); @@ -40,6 +83,11 @@ bool tile::parse() fprintf(stderr, "[%p] parsing tile...done\n", this); + if (cancelled) { + delete this; + return false; + } + loaded = true; return true; } @@ -84,7 +132,7 @@ void tile::parseFeature(const uint8_t *data, uint32_t bytes) { } void tile::loadGeometry(const uint8_t *data, uint32_t bytes) { - pbf geometry(data, bytes); + pbf geometry(data, bytes); uint32_t cmd = 1; uint32_t length = 0; diff --git a/src/map/transform.cpp b/src/map/transform.cpp index e458d663b4..e31fad4233 100644 --- a/src/map/transform.cpp +++ b/src/map/transform.cpp @@ -1,6 +1,7 @@ #include <llmr/map/transform.hpp> #include <llmr/util/mat4.h> +#include <llmr/util/vec2.hpp> #include <llmr/util/math.hpp> #include <cmath> #include <cstdio> @@ -22,7 +23,9 @@ transform::transform() x(0), y(0), angle(0.0), - scale(1.0) { + scale(1.0), + min_scale(pow(2, 0)), + max_scale(pow(2, 20)) { setScale(scale); setAngle(angle); } @@ -33,6 +36,14 @@ void transform::moveBy(double dx, double dy) { } void transform::scaleBy(double ds, double cx, double cy) { + // clamp scale to min/max values + const double new_scale = scale * ds; + if (new_scale < min_scale) { + ds = min_scale / scale; + } else if (new_scale > max_scale) { + ds = max_scale / scale; + } + const double dx = (cx - width / 2) * (1.0 - ds); const double dy = (cy - height / 2) * (1.0 - ds); const double fx = cos(angle) * dx + sin(angle) * dy; @@ -41,6 +52,8 @@ void transform::scaleBy(double ds, double cx, double cy) { scale *= ds; x = (x * ds) + fx; y = (y * ds) + fy; + + fprintf(stderr, "scale: %f, %f, %f\n", scale, x, y); } @@ -78,6 +91,12 @@ void transform::setAngle(double new_angle) { } void transform::setScale(double new_scale) { + if (new_scale < min_scale) { + new_scale = min_scale; + } else if (new_scale > max_scale) { + new_scale = max_scale; + } + const double factor = new_scale / scale; x *= factor; y *= factor; @@ -99,7 +118,7 @@ void transform::setLonLat(double lon, double lat) { y = round(0.5 * Cc * log((1 + f) / (1 - f))); } -void transform::getLonLat(double& lon, double& lat) const { +void transform::getLonLat(double &lon, double &lat) const { lon = -x / Bc; lat = R2D * (2 * atan(exp(y / Cc)) - 0.5 * M_PI); } @@ -132,7 +151,40 @@ void transform::matrixFor(float matrix[16], uint32_t tile_z, uint32_t tile_x, ui // Clipping plane mat4_translate(matrix, matrix, 0, 0, -1); +} +int32_t transform::getZoom() const { + return floor(log(scale) / M_LN2); +} +void transform::mapCornersToBox(uint32_t z, box& b) const { + const double ref_scale = pow(2, z); + + // Keep the map as upright as possible. + double local_angle = angle; + if (local_angle >= M_PI_2) local_angle -= M_PI; + if (local_angle < -M_PI_2) local_angle += M_PI; + + const double angle_sin = sin(-local_angle); + const double angle_cos = cos(-local_angle); + + const double w_2 = width / 2; + const double h_2 = height / 2; + const double ss_1 = ref_scale / (scale * size); + const double ss_2 = (scale * size) / 2; + + // Calculate the corners of the map view. The resulting coordinates will be + // in fractional tile coordinates. + b.tl.x = ((-w_2) * angle_cos - (-h_2) * angle_sin + ss_2 - x) * ss_1; + b.tl.y = ((-w_2) * angle_sin + (-h_2) * angle_cos + ss_2 - y) * ss_1; + b.tr.x = ((+w_2) * angle_cos - (-h_2) * angle_sin + ss_2 - x) * ss_1; + b.tr.y = ((+w_2) * angle_sin + (-h_2) * angle_cos + ss_2 - y) * ss_1; + b.bl.x = ((-w_2) * angle_cos - (+h_2) * angle_sin + ss_2 - x) * ss_1; + b.bl.y = ((-w_2) * angle_sin + (+h_2) * angle_cos + ss_2 - y) * ss_1; + b.br.x = ((+w_2) * angle_cos - (+h_2) * angle_sin + ss_2 - x) * ss_1; + b.br.y = ((+w_2) * angle_sin + (+h_2) * angle_cos + ss_2 - y) * ss_1; + + // Quick hack: use the entire non-rotated bounding box. } + diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp index 696e6a8625..656d1fd645 100644 --- a/src/renderer/painter.cpp +++ b/src/renderer/painter.cpp @@ -25,9 +25,8 @@ GLfloat fill_vertices[] = { }; -painter::painter(class platform *platform, class transform *transform) - : platform(platform), - transform(transform), +painter::painter(class transform *transform) + : transform(transform), currentShader(NULL), fillShader(NULL) { |