diff --git a/Makefile b/Makefile index 1d16f0c94..70ce2a4d4 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,11 @@ app: config.gypi src macosx/llmr-app.gyp make -C build/macosx-make V=$(V) open build/macosx-make/out/Release/llmr.app +linux: config.gypi src linux/llmr-app.gyp + deps/run_gyp linux/llmr-app.gyp -Goutput_dir=./out/ --depth=. --generator-output=./build/linux-make -f make + make -C build/linux-make V=$(V) + ./build/linux-make/out/Release/llmr.app + # build just xcode project for libllmr xcode: config.gypi llmr.gyp deps/run_gyp llmr.gyp -Goutput_dir=./out/ --depth=. --generator-output=./ -f xcode diff --git a/linux/llmr-app.gyp b/linux/llmr-app.gyp new file mode 100644 index 000000000..40b8c76ec --- /dev/null +++ b/linux/llmr-app.gyp @@ -0,0 +1,32 @@ +{ + 'includes': [ + '../common.gypi', + '../config.gypi' + ], + 'targets': [ + { + "target_name": "linuxapp", + "product_name": "llmr", + "type": "executable", + "sources": [ + "./main.cpp", + "./settings.cpp", + "./settings.hpp" + ], + 'product_extension': 'app', + 'link_settings': { + 'libraries': [ + '<@(glfw3_libraries)', + '-lcurl' + ], + }, + 'cflags': [ + '<@(png_cflags)', + '<@(glfw3_cflags)' + ], + "dependencies": [ + "../llmr.gyp:llmr-osx" + ] + } + ] +} diff --git a/linux/main.cpp b/linux/main.cpp new file mode 100644 index 000000000..c51d27f82 --- /dev/null +++ b/linux/main.cpp @@ -0,0 +1,263 @@ +#include +#include +#include +#include +#include "settings.hpp" + +#include + +class MapView { +public: + MapView() : + dirty(true), + tracking(false), + rotating(false), + last_click(-1), + settings(), + map(settings) { + } + + void init() { + if (!glfwInit()) { + fprintf(stderr, "Failed to initialize glfw\n"); + exit(1); + } + + glfwWindowHint(GLFW_STENCIL_BITS, 8); + glfwWindowHint(GLFW_DEPTH_BITS, 16); + + window = glfwCreateWindow(1024, 768, "llmr", NULL, NULL); + if (!window) { + glfwTerminate(); + fprintf(stderr, "Failed to initialize window\n"); + exit(1); + } + + glfwSetWindowUserPointer(window, this); + glfwMakeContextCurrent(window); + + settings.load(); + map.setup(); + + resize(window, 0, 0); + + glfwSwapInterval(1); + + map.loadSettings(); + + glfwSetCursorPosCallback(window, mousemove); + glfwSetMouseButtonCallback(window, mouseclick); + glfwSetWindowSizeCallback(window, resize); + glfwSetFramebufferSizeCallback(window, resize); + glfwSetScrollCallback(window, scroll); + glfwSetCharCallback(window, character); + glfwSetKeyCallback(window, key); + + } + + static void character(GLFWwindow *window, unsigned int codepoint) { + + } + + + static void key(GLFWwindow *window, int key, int scancode, int action, int mods) { + MapView *mapView = (MapView *)glfwGetWindowUserPointer(window); + + if (action == GLFW_RELEASE) { + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, true); + break; + case GLFW_KEY_TAB: + mapView->map.toggleDebug(); + break; + case GLFW_KEY_R: + if (!mods) mapView->map.resetPosition(); + break; + case GLFW_KEY_N: + if (!mods) mapView->map.resetNorth(); + break; + } + } + } + + + static void scroll(GLFWwindow *window, double xoffset, double yoffset) { + MapView *mapView = (MapView *)glfwGetWindowUserPointer(window); + double delta = yoffset * 40; + + 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)); + + // Make the scroll wheel a bit slower. + if (!is_wheel) { + scale = (scale - 1.0) / 2.0 + 1.0; + } + + // Zooming out. + if (delta < 0 && scale != 0) { + scale = 1.0 / scale; + } + + mapView->map.scaleBy(scale, mapView->last_x, mapView->last_y); + } + + static void resize(GLFWwindow *window, int, int) { + MapView *mapView = (MapView *)glfwGetWindowUserPointer(window); + + int width, height; + glfwGetWindowSize(window, &width, &height); + int fb_width, fb_height; + glfwGetFramebufferSize(window, &fb_width, &fb_height); + + mapView->map.resize(width, height, fb_width, fb_height); + } + + static void mouseclick(GLFWwindow *window, int button, int action, int modifiers) { + MapView *mapView = (MapView *)glfwGetWindowUserPointer(window); + + if (button == GLFW_MOUSE_BUTTON_RIGHT || (button == GLFW_MOUSE_BUTTON_LEFT && modifiers & GLFW_MOD_CONTROL)) { + mapView->rotating = action == GLFW_PRESS; + if (mapView->rotating) { + mapView->start_x = mapView->last_x; + mapView->start_y = mapView->last_y; + } + } else if (button == GLFW_MOUSE_BUTTON_LEFT) { + mapView->tracking = action == GLFW_PRESS; + + if (action == GLFW_RELEASE) { + double now = glfwGetTime(); + if (now - mapView->last_click < 0.4) { + mapView->map.scaleBy(2.0, mapView->last_x, mapView->last_y); + } + mapView->last_click = now; + } + } + } + + static void mousemove(GLFWwindow *window, double x, double y) { + MapView *mapView = (MapView *)glfwGetWindowUserPointer(window); + if (mapView->tracking) { + mapView->map.moveBy(x - mapView->last_x, y - mapView->last_y); + } else if (mapView->rotating) { + mapView->map.rotateBy(mapView->start_x, mapView->start_y, mapView->last_x, mapView->last_y, x, y); + } + mapView->last_x = x; + mapView->last_y = y; + } + + int run() { + while (!glfwWindowShouldClose(window)) { + if (dirty) { + try { + dirty = render(); + } catch (std::exception& ex) { + fprintf(stderr, "exception: %s\n", ex.what()); + } + glfwSwapBuffers(window); + fps(); + } + + if (dirty) { + glfwPollEvents(); + } else { + glfwWaitEvents(); + } + } + + return 0; + } + + bool render() { + return map.render(); + } + + void fps() { + static int frames = 0; + static double time_elapsed = 0; + + frames++; + double current_time = glfwGetTime(); + + if (current_time - time_elapsed >= 1) { + fprintf(stderr, "FPS: %4.2f\n", frames / (current_time - time_elapsed)); + time_elapsed = current_time; + frames = 0; + } + } + + ~MapView() { + glfwTerminate(); + } + +public: + bool dirty; + double last_x, last_y; + bool tracking; + + double start_x, start_y; + bool rotating; + + double last_click; + + GLFWwindow *window; + llmr::Settings_MacOSX settings; + llmr::Map map; +}; + +MapView *mapView; + +namespace llmr { +namespace platform { + +void restart(void *) { + mapView->dirty = true; +} + + + +static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { + ((std::string*)userp)->append((char*)contents, size *nmemb); + return size * nmemb; +} + +void request_http(std::string url, std::function func, std::function cb) { + + Response res; + + CURL *curl; + CURLcode code; + curl = curl_easy_init(); + + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &res.body); + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate"); + code = curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res.code); + curl_easy_cleanup(curl); + } + + func(res); + cb(); +} + + +double time() { + return glfwGetTime(); +} + +} +} + +int main() { + mapView = new MapView(); + mapView->init(); + int ret = mapView->run(); + mapView->settings.sync(); + delete mapView; + return ret; +} diff --git a/linux/settings.cpp b/linux/settings.cpp new file mode 100644 index 000000000..2aa4b8c8a --- /dev/null +++ b/linux/settings.cpp @@ -0,0 +1,52 @@ +#include "settings.hpp" + +using namespace llmr; + +Settings_MacOSX::Settings_MacOSX() +{ + /* + [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"longitude" : @(longitude), + @"latitude" : @(latitude), + @"scale" : @(scale), + @"angle" : @(angle), + @"debug" : @(debug) }]; + */ +} + +void Settings_MacOSX::load() +{ + /* + NSDictionary *settings = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]; + + longitude = [settings[@"longitude"] doubleValue]; + latitude = [settings[@"latitude"] doubleValue]; + scale = [settings[@"scale"] doubleValue]; + angle = [settings[@"angle"] doubleValue]; + debug = [settings[@"debug"] boolValue]; + */ +} + +void Settings_MacOSX::persist() +{ + /* + [[NSUserDefaults standardUserDefaults] setValuesForKeysWithDictionary:@{ @"longitude" : @(longitude), + @"latitude" : @(latitude), + @"scale" : @(scale), + @"angle" : @(angle), + @"debug" : @(debug) }]; + */ +} + +void Settings_MacOSX::sync() +{ + /* + [[NSUserDefaults standardUserDefaults] synchronize]; + */ +} + +void Settings_MacOSX::clear() +{ + /* + [NSUserDefaults resetStandardUserDefaults]; + */ +} diff --git a/linux/settings.hpp b/linux/settings.hpp new file mode 100644 index 000000000..dae645c74 --- /dev/null +++ b/linux/settings.hpp @@ -0,0 +1,23 @@ +#ifndef LLMR_MACOSX_SETTINGS +#define LLMR_MACOSX_SETTINGS + +#include + +namespace llmr { + +class Settings_MacOSX : public Settings { +public: + Settings_MacOSX(); + virtual void load(); + virtual void persist(); + virtual void sync(); + virtual void clear(); + double angle; + double longitude; + double latitude; + double scale; +}; + +} + +#endif diff --git a/src/style/sprite.cpp b/src/style/sprite.cpp index ceef26739..e2707f5b9 100644 --- a/src/style/sprite.cpp +++ b/src/style/sprite.cpp @@ -121,6 +121,7 @@ void warningHandler(png_structp png, png_const_charp error_msg) { } void Sprite::loadImage(const std::string& data) { + return; std::lock_guard lock(mtx); Buffer buffer(data);