diff options
Diffstat (limited to 'linux/main.cpp')
-rw-r--r-- | linux/main.cpp | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/linux/main.cpp b/linux/main.cpp new file mode 100644 index 0000000000..1e6c409a0f --- /dev/null +++ b/linux/main.cpp @@ -0,0 +1,294 @@ +#include <llmr/llmr.hpp> +#include <GLFW/glfw3.h> +#include <curl/curl.h> +#include <llmr/platform/platform.hpp> +#include "settings.hpp" +#include <future> +#include <list> +#include <chrono> + +#include <thread> + +std::list<std::future<void>> futures; +std::list<std::future<void>>::iterator f_it; +std::list<std::function<void()>> callbacks; +std::list<std::function<void()>>::iterator c_it; +std::chrono::milliseconds zero (0); + +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)) { + + f_it = futures.begin(); + c_it = callbacks.begin(); + + while (f_it != futures.end()) { + if (f_it->wait_for(zero) == std::future_status::ready) { + std::function<void()> cb = *c_it; + futures.erase(f_it++); + callbacks.erase(c_it++); + cb(); + } else { + f_it++; + c_it++; + } + } + + if (dirty) { + try { + dirty = render(); + } catch (std::exception& ex) { + fprintf(stderr, "exception: %s\n", ex.what()); + } + glfwSwapBuffers(window); + fps(); + } + + if (dirty || futures.size()) { + 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 = nullptr; + +namespace llmr { +namespace platform { + +void restart(void *) { + if (mapView) { + 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_async(std::string url, std::function<void(Response&)> func) { + + 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); +} + +void request_http(std::string url, std::function<void(Response&)> func, std::function<void()> cb) { + futures.emplace_back(std::async(std::launch::async, request_http_async, url, func)); + callbacks.push_back(cb); +} + + +double time() { + return glfwGetTime(); +} + +} +} + +int main() { + mapView = new MapView(); + mapView->init(); + int ret = mapView->run(); + mapView->settings.sync(); + delete mapView; + return ret; +} |