diff --git a/.gitignore b/.gitignore index 2ee38036f8..d8774d5225 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ # Created by http://www.gitignore.io +### OSX ### +.vscode +.vs + ### OSX ### .DS_Store .AppleDouble diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b07485080..60c8571fe9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.15) project(tangram) @@ -18,11 +18,6 @@ option(TANGRAM_DEV_MODE "For developers only: Don't omit the frame pointer" OFF) message(STATUS "Build type configuration: ${CMAKE_BUILD_TYPE}") -# Check that submodules are present. -if(NOT EXISTS "${PROJECT_SOURCE_DIR}/core/deps/harfbuzz-icu-freetype/harfbuzz/README") - message(SEND_ERROR "Missing submodules - Please run:\n 'git submodule update --init'") - return() -endif() if(CMAKE_BUILD_TYPE MATCHES Debug) add_definitions(-DDEBUG) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 4075f8ca8f..e673300181 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,6 +1,7 @@ project(tangram-core) # Build core library dependencies. +find_package(yaml-cpp CONFIG REQUIRED) add_subdirectory(deps) add_library(tangram-core @@ -231,7 +232,6 @@ target_link_libraries(tangram-core alfons double-conversion miniz - z ) # Add JavaScript implementation. @@ -260,6 +260,7 @@ if(UNIX AND NOT APPLE) target_link_libraries(tangram-core PRIVATE dl) endif() +target_compile_definitions(tangram-core PUBLIC _USE_MATH_DEFINES) if(TANGRAM_WARN_ON_RULE_CONFLICT) target_compile_definitions(tangram-core PRIVATE diff --git a/core/deps/CMakeLists.txt b/core/deps/CMakeLists.txt index 4de4f69315..32061c21e6 100644 --- a/core/deps/CMakeLists.txt +++ b/core/deps/CMakeLists.txt @@ -11,15 +11,15 @@ add_library(glm INTERFACE) target_include_directories(glm INTERFACE glm) target_compile_definitions(glm INTERFACE GLM_FORCE_CTOR_INIT) -## yaml-cpp ## -############## -set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "") -set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "") -set(YAML_CPP_BUILD_CONTRIB OFF CACHE BOOL "") -set(YAML_CPP_INSTALL OFF CACHE BOOL "") -add_subdirectory(yaml-cpp) +### yaml-cpp ## +############### +#set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "") +#set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "") +#set(YAML_CPP_BUILD_CONTRIB OFF CACHE BOOL "") +#set(YAML_CPP_INSTALL OFF CACHE BOOL "") +#add_subdirectory(yaml-cpp) -target_include_directories(yaml-cpp PUBLIC yaml-cpp/include) +#target_include_directories(yaml-cpp PUBLIC yaml-cpp/include) ## css-color-parser-cpp ## ########################## @@ -48,14 +48,10 @@ target_include_directories(miniz if(NOT TANGRAM_USE_SYSTEM_FONT_LIBS) ## Harfbuzz - ICU-Common - Freetype2 ## ####################################### - set(HARFBUZZ_BUILD_ICU ON CACHE BOOL "Enable building of ICU") - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/harfbuzz-icu-freetype) - - message(STATUS "harfbuzz" ${HARFBUZZ_LIBRARIES}) - + #find_package(ICU REQUIRED COMPONENTS common) + find_package(harfbuzz CONFIG REQUIRED) set(ALFONS_DEPS_LIBRARIES - ${ALFONS_DEPS_LIBRARIES} - harfbuzz ${HARFBUZZ_LIBRARIES} + harfbuzz::harfbuzz CACHE INTERNAL "alfons-libs" FORCE) endif() diff --git a/core/deps/pbf/pbf.hpp b/core/deps/pbf/pbf.hpp index f73b4f4056..62d4bc8871 100644 --- a/core/deps/pbf/pbf.hpp +++ b/core/deps/pbf/pbf.hpp @@ -26,9 +26,13 @@ #endif namespace protobuf { - +#if defined(__GNUC__) #define FORCEINLINE inline __attribute__((always_inline)) #define NOINLINE __attribute__((noinline)) +#else +#define FORCEINLINE inline +#define NOINLINE +#endif #define PBF_INLINE FORCEINLINE class message { diff --git a/core/include/tangram/log.h b/core/include/tangram/log.h index eb594e791a..c5d6041278 100644 --- a/core/include/tangram/log.h +++ b/core/include/tangram/log.h @@ -27,7 +27,11 @@ static constexpr const char * past_last_slash(const char * const str) { return past_last_slash(str, str); } +#ifdef TANGRAM_WINDOWS +#define __FILENAME__ __FILE__ +#else #define __FILENAME__ ({constexpr const char * const sf__ {past_last_slash(__FILE__)}; sf__;}) +#endif #define TANGRAM_MAX_BUFFER_LOG_SIZE 99999 diff --git a/core/include/tangram/tile/tileID.h b/core/include/tangram/tile/tileID.h index 57107daa0c..327a458cfa 100644 --- a/core/include/tangram/tile/tileID.h +++ b/core/include/tangram/tile/tileID.h @@ -3,6 +3,7 @@ #include #include #include +#include /* An immutable identifier for a map tile * diff --git a/core/include/tangram/util/variant.h b/core/include/tangram/util/variant.h index 87998a45c3..f0512a91b1 100644 --- a/core/include/tangram/util/variant.h +++ b/core/include/tangram/util/variant.h @@ -55,7 +55,15 @@ using Value = variant; class Value : public detail::Value { using Base = detail::Value; - using Base::Base; + +public: + Value(): Base() {} + + template + Value(const T& val): Base(val) {} + + template + Value(T&& val): Base(val) {} }; const static Value NOT_A_VALUE(none_type{}); diff --git a/core/src/data/rasterSource.cpp b/core/src/data/rasterSource.cpp index 689e9e31f5..32ef27a2eb 100644 --- a/core/src/data/rasterSource.cpp +++ b/core/src/data/rasterSource.cpp @@ -208,7 +208,7 @@ std::shared_ptr RasterSource::cacheTexture(const TileID& _tileId, std:: } texture = std::shared_ptr(_texture.release(), - [c = std::weak_ptr(m_textures), id](auto t) { + [c = std::weak_ptr(m_textures), id](auto* t) { if (auto cache = c.lock()) { cache->erase(id); LOGD("%d - remove %s", cache->size(), id.toString().c_str()); diff --git a/core/src/debug/textDisplay.cpp b/core/src/debug/textDisplay.cpp index 5b3166ee30..fff2af7105 100644 --- a/core/src/debug/textDisplay.cpp +++ b/core/src/debug/textDisplay.cpp @@ -89,7 +89,7 @@ void TextDisplay::draw(RenderState& rs, const std::string& _text, int _posx, int std::vector vertices; int nquads; - nquads = stb_easy_font_print(_posx, _posy, _text.c_str(), NULL, m_vertexBuffer, VERTEX_BUFFER_SIZE); + nquads = stb_easy_font_print(_posx, _posy, const_cast(_text.c_str()), NULL, m_vertexBuffer, VERTEX_BUFFER_SIZE); float* data = reinterpret_cast(m_vertexBuffer); diff --git a/core/src/gl/framebuffer.cpp b/core/src/gl/framebuffer.cpp index a8886e198d..ff71db6809 100644 --- a/core/src/gl/framebuffer.cpp +++ b/core/src/gl/framebuffer.cpp @@ -147,7 +147,7 @@ void FrameBuffer::init(RenderState& _rs) { } GLenum status = GL::checkFramebufferStatus(GL_FRAMEBUFFER); - GL_CHECK(); + GL_CHECK(""); if (status != GL_FRAMEBUFFER_COMPLETE) { LOGE("Framebuffer status is incomplete:"); diff --git a/core/src/scene/importer.cpp b/core/src/scene/importer.cpp index 54d0dd9b82..fc1f211701 100644 --- a/core/src/scene/importer.cpp +++ b/core/src/scene/importer.cpp @@ -188,7 +188,11 @@ void Importer::addSceneYaml(const Url& sceneUrl, const char* sceneYaml, size_t l auto& sceneNode = m_sceneNodes[sceneUrl]; try { +#ifdef TANGRAM_WINDOWS + sceneNode.yaml = YAML::Load(sceneYaml); +#else sceneNode.yaml = YAML::Load(sceneYaml, length); +#endif } catch (const YAML::ParserException& e) { LOGE("Parsing scene config '%s'", e.what()); return; diff --git a/core/src/scene/sceneLoader.cpp b/core/src/scene/sceneLoader.cpp index 2866edd93d..0f271971f9 100644 --- a/core/src/scene/sceneLoader.cpp +++ b/core/src/scene/sceneLoader.cpp @@ -145,7 +145,7 @@ void SceneLoader::applyScene(const Node& _node, Color& backgroundColor, Stops& backgroundStops, Scene::animate& animated) { if (!_node) { return; } if (!_node.IsMap()) { - LOGNode("Invalid 'scene' section", _node); + LOGNode("Invalid 'scene' section", _node, ""); return; } @@ -302,7 +302,7 @@ Scene::Lights SceneLoader::applyLights(const Node& _node) { } } } else if (_node) { - LOGNode("Invalid 'lights'", _node); + LOGNode("Invalid 'lights'", _node, ""); } if (lights.empty()) { @@ -436,14 +436,14 @@ void SceneLoader::parseLightPosition(const Node& _positionNode, PointLight& _lig } _light.setPosition(positionResult); } else { - LOGNode("Invalid light position parameter:", _positionNode); + LOGNode("Invalid light position parameter:", _positionNode, ""); } } void SceneLoader::applyTextures(const Node& _node, SceneTextures& _textures) { if (!_node) { return; } if (!_node.IsMap()) { - LOGNode("Invalid 'textures' section", _node); + LOGNode("Invalid 'textures' section", _node, ""); return; } @@ -543,7 +543,7 @@ bool SceneLoader::parseTexFiltering(const Node& _filteringNode, TextureOptions& void SceneLoader::applyFonts(const Node& _node, SceneFonts& _fonts) { if (!_node) { return; } if (!_node.IsMap()) { - LOGNode("Invalid 'fonts' section", _node); + LOGNode("Invalid 'fonts' section", _node, ""); return; } @@ -570,7 +570,7 @@ void SceneLoader::applyFonts(const Node& _node, SceneFonts& _fonts) { void SceneLoader::loadFontDescription(const Node& _node, const std::string& _family, SceneFonts& _fonts) { if (!_node) { return; } if (!_node.IsMap()) { - LOGNode("Invalid 'font' section", _node); + LOGNode("Invalid 'font' section", _node, ""); return; } @@ -634,18 +634,18 @@ Scene::TileSources SceneLoader::applySources(const Node& _config, const SceneOpt if (const Node& rasters = source.second["rasters"]) { if (!rasters.IsSequence()) { - LOGNode("Invalid 'rasters'", rasters); + LOGNode("Invalid 'rasters'", rasters, ""); continue; } for (const auto& raster : rasters) { if (!raster.IsScalar()) { - LOGNode("Invalid 'raster'", raster); + LOGNode("Invalid 'raster'", raster, ""); continue; } if (auto rasterSource = getTileSource(raster.Scalar())) { tileSource->addRasterSource(rasterSource); } else { - LOGNode("Missing raster source", raster); + LOGNode("Missing raster source", raster, ""); } } } @@ -676,7 +676,7 @@ Scene::TileSources SceneLoader::applySources(const Node& _config, const SceneOpt if (!data_source) { continue;} if (!data_source.IsScalar()) { - LOGNode("Invalid 'source", data); + LOGNode("Invalid 'source", data, ""); continue; } auto source = data_source.Scalar(); @@ -875,7 +875,7 @@ Scene::Styles SceneLoader::applyStyles(const Node& _node, SceneTextures& _textur if (!_node) { return styles; } if (!_node.IsMap()) { - LOGNode("Invalid 'styles' section", _node); + LOGNode("Invalid 'styles' section", _node, ""); return styles; } @@ -1256,7 +1256,7 @@ void SceneLoader::loadShaderConfig(const Node& _shaders, Style& _style, SceneTex _style.styleUniforms().emplace_back(name, styleUniform.value); } else { - LOGNode("Style uniform parsing failure", uniform.second); + LOGNode("Style uniform parsing failure", uniform.second, ""); } } } @@ -1387,7 +1387,7 @@ void SceneLoader::loadMaterial(const Node& _matNode, Material& _material, Style& // Handled as texture break; default: - LOGNode("Invalid 'material'", prop); + LOGNode("Invalid 'material'", prop, ""); break; } return glm::vec4(0.0); @@ -1441,7 +1441,7 @@ MaterialTexture SceneLoader::loadMaterialTexture(const Node& _matCompNode, Style Node textureNode = _matCompNode["texture"]; if (!textureNode) { - LOGNode("Expected a 'texture' parameter", _matCompNode); + LOGNode("Expected a 'texture' parameter", _matCompNode, ""); return MaterialTexture{}; } @@ -1501,7 +1501,7 @@ std::vector SceneLoader::applyLayers(const Node& _node, SceneFunctio SceneStops& _stops, DrawRuleNames& _ruleNames) { if (!_node) { return {}; } if (!_node.IsMap()) { - LOGNode("Invalid 'layers' section", _node); + LOGNode("Invalid 'layers' section", _node, ""); return {}; } diff --git a/core/src/scene/stops.cpp b/core/src/scene/stops.cpp index d94895ab37..93e420cf3e 100644 --- a/core/src/scene/stops.cpp +++ b/core/src/scene/stops.cpp @@ -266,15 +266,16 @@ auto Stops::Numbers(const YAML::Node& node) -> Stops { auto Stops::evalExpFloat(float _key) const -> float { if (frames.empty()) { return 0; } + if (_key <= frames[0].key) { + return frames[0].value.get(); + } + auto upper = nearestHigherFrame(_key); auto lower = upper - 1; if (upper == frames.end()) { return lower->value.get(); } - if (lower < frames.begin()) { - return upper->value.get(); - } if (upper->key <= _key) { return upper->value.get(); @@ -294,15 +295,16 @@ auto Stops::evalExpFloat(float _key) const -> float { auto Stops::evalFloat(float _key) const -> float { if (frames.empty()) { return 0; } + if (_key <= frames[0].key) { + return frames[0].value.get(); + } + auto upper = nearestHigherFrame(_key); auto lower = upper - 1; if (upper == frames.end()) { return lower->value.get(); } - if (lower < frames.begin()) { - return upper->value.get(); - } float lerp = (_key - lower->key) / (upper->key - lower->key); @@ -312,14 +314,15 @@ auto Stops::evalFloat(float _key) const -> float { auto Stops::evalColor(float _key) const -> uint32_t { if (frames.empty()) { return 0; } + if (_key <= frames[0].key) { + return frames[0].value.get().abgr; + } + auto upper = nearestHigherFrame(_key); auto lower = upper - 1; if (upper == frames.end()) { return lower->value.get().abgr; } - if (lower < frames.begin()) { - return upper->value.get().abgr; - } float lerp = (_key - lower->key) / (upper->key - lower->key); @@ -329,15 +332,16 @@ auto Stops::evalColor(float _key) const -> uint32_t { auto Stops::evalExpVec2(float _key) const -> glm::vec2 { if (frames.empty()) { return glm::vec2{0.f}; } + if (_key <= frames[0].key) { + return frames[0].value.get(); + } + auto upper = nearestHigherFrame(_key); auto lower = upper - 1; if (upper == frames.end()) { return lower->value.get(); } - if (lower < frames.begin()) { - return upper->value.get(); - } double range = exp2(upper->key - lower->key) - 1.0; double pos = exp2(_key - lower->key) - 1.0; @@ -349,21 +353,21 @@ auto Stops::evalExpVec2(float _key) const -> glm::vec2 { return glm::vec2(lowerVal.x * (1 - lerp) + upperVal.x * lerp, lowerVal.y * (1 - lerp) + upperVal.y * lerp); - } auto Stops::evalVec2(float _key) const -> glm::vec2 { if (frames.empty()) { return glm::vec2{0.f}; } + if (_key <= frames[0].key) { + return frames[0].value.get(); + } + auto upper = nearestHigherFrame(_key); auto lower = upper - 1; if (upper == frames.end()) { return lower->value.get(); } - if (lower < frames.begin()) { - return upper->value.get(); - } float lerp = (_key - lower->key) / (upper->key - lower->key); @@ -379,15 +383,16 @@ auto Stops::evalSize(float _key, const glm::vec2& _cssSize) const -> glm::vec2 { if (frames.empty()) { return {NAN, NAN}; } + if (_key <= frames[0].key) { + return frames[0].value.get().getSizePixels(_cssSize); + } + auto upper = nearestHigherFrame(_key); auto lower = upper - 1; if (upper == frames.end()) { return lower->value.get().getSizePixels(_cssSize); } - if (lower < frames.begin()) { - return upper->value.get().getSizePixels(_cssSize); - } double range = exp2(upper->key - lower->key) - 1.0; double pos = exp2(_key - lower->key) - 1.0; diff --git a/core/src/text/textUtil.cpp b/core/src/text/textUtil.cpp index f1a2b76b57..8f89f18e8a 100644 --- a/core/src/text/textUtil.cpp +++ b/core/src/text/textUtil.cpp @@ -67,7 +67,7 @@ int TextWrapper::draw(alfons::TextBatch& _batch, float _maxWidth, const alfons:: TextLabelProperty::Align _alignment, float _lineSpacing, alfons::LineMetrics& _layoutMetrics) { size_t shapeStart = 0; - glm::vec2 position; + glm::vec2 position{}; for (auto wrap : m_lineWraps) { alfons::LineMetrics lineMetrics; diff --git a/core/src/util/floatFormatter.h b/core/src/util/floatFormatter.h index b6d3f0189f..9194947835 100644 --- a/core/src/util/floatFormatter.h +++ b/core/src/util/floatFormatter.h @@ -20,14 +20,14 @@ struct ff { static double stod(const std::string& _string) { int end = 0; - return stod(_string.data(), _string.size(), &end); + return stod(_string.data(), static_cast(_string.size()), &end); } static float stof(const char* _string, int _length, int* _end); static float stof(const std::string& _string) { int end = 0; - return stof(_string.data(), _string.size(), &end); + return stof(_string.data(), static_cast(_string.size()), &end); } }; diff --git a/core/src/util/geom.h b/core/src/util/geom.h index 437f49d3d4..6bf4f6e354 100644 --- a/core/src/util/geom.h +++ b/core/src/util/geom.h @@ -72,7 +72,7 @@ float signedArea(InputIt begin, InputIt end) { float area = 0; auto prev = end - 1; for (auto curr = begin; curr != end; ++curr) { - area += curr->x * prev->y - curr->y * prev->x; + area += static_cast(curr->x * prev->y - curr->y * prev->x); prev = curr; } return 0.5f * area; @@ -82,14 +82,14 @@ float signedArea(InputIt begin, InputIt end) { /// If the polygon has no area, the coordinates returned are NaN. template Vector centroid(InputIt begin, InputIt end) { - Vector centroid; + Vector centroid{}; float area = 0.f; const Vector offset(begin->x, begin->y); for (auto curr = begin, prev = end - 1; curr != end; prev = curr, ++curr) { const Vector prevPoint(prev->x - offset.x, prev->y - offset.y); const Vector currPoint(curr->x - offset.x, curr->y - offset.y); - float a = (prevPoint.x * currPoint.y - currPoint.x * prevPoint.y); + float a = static_cast(prevPoint.x * currPoint.y - currPoint.x * prevPoint.y); centroid.x += (prevPoint.x + currPoint.x) * a; centroid.y += (prevPoint.y + currPoint.y) * a; area += a; diff --git a/core/src/util/url.cpp b/core/src/util/url.cpp index caa01c8193..d71b3fa806 100644 --- a/core/src/util/url.cpp +++ b/core/src/util/url.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace Tangram { diff --git a/platforms/common/glfwApp.cpp b/platforms/common/glfwApp.cpp index 0c0c11eb5d..2bcdb5a2e2 100644 --- a/platforms/common/glfwApp.cpp +++ b/platforms/common/glfwApp.cpp @@ -3,6 +3,12 @@ #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" #include "imgui_stl.h" + +#ifdef TANGRAM_WINDOWS +#define GLFW_INCLUDE_NONE +#include +#endif // TANGRAM_WINDOWS + #define GLFW_INCLUDE_GLEXT #define GL_SILENCE_DEPRECATION #include @@ -203,6 +209,10 @@ void create(std::unique_ptr p, int w, int h) { glfwMakeContextCurrent(main_window); glfwSwapInterval(1); // Enable vsync +#ifdef TANGRAM_WINDOWS + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); +#endif + // Set input callbacks glfwSetFramebufferSizeCallback(main_window, framebufferResizeCallback); glfwSetMouseButtonCallback(main_window, mouseButtonCallback); @@ -535,17 +545,19 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods map->loadSceneYamlAsync("{ scene: { background: { color: red } } }", std::string("")); break; case GLFW_KEY_G: - static bool geoJSON = false; - if (!geoJSON) { - loadSceneFile(false, - { SceneUpdate{"sources.osm.type", "GeoJSON"}, - SceneUpdate{"sources.osm.url", "https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.json"}}); - } else { - loadSceneFile(false, - { SceneUpdate{"sources.osm.type", "MVT"}, - SceneUpdate{"sources.osm.url", "https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt"}}); + { + static bool geoJSON = false; + if (!geoJSON) { + loadSceneFile(false, + { SceneUpdate{"sources.osm.type", "GeoJSON"}, + SceneUpdate{"sources.osm.url", "https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.json"}}); + } else { + loadSceneFile(false, + { SceneUpdate{"sources.osm.type", "MVT"}, + SceneUpdate{"sources.osm.url", "https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt"}}); + } + geoJSON = !geoJSON; } - geoJSON = !geoJSON; break; case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, true); @@ -603,7 +615,7 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods case GLFW_KEY_W: map->onMemoryWarning(); break; - default: + default: break; } } diff --git a/platforms/common/platform_gl.cpp b/platforms/common/platform_gl.cpp index de50335bf0..4756fa0580 100644 --- a/platforms/common/platform_gl.cpp +++ b/platforms/common/platform_gl.cpp @@ -11,7 +11,7 @@ GLenum GL::getError() { const GLubyte* GL::getString(GLenum name) { auto result = glGetString(name); - GL_CHECK(); + GL_CHECK(""); return result; } @@ -86,12 +86,12 @@ void GL::deleteShader(GLuint shader) { } GLuint GL::createShader(GLenum type) { auto result = glCreateShader(type); - GL_CHECK(); + GL_CHECK(""); return result; } GLuint GL::createProgram() { auto result = glCreateProgram(); - GL_CHECK(); + GL_CHECK(""); return result; } @@ -117,12 +117,12 @@ void GL::getProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLc } GLint GL::getUniformLocation(GLuint program, const GLchar *name) { auto result = glGetUniformLocation(program, name); - GL_CHECK(); + GL_CHECK(""); return result; } GLint GL::getAttribLocation(GLuint program, const GLchar *name) { auto result = glGetAttribLocation(program, name); - GL_CHECK(); + GL_CHECK(""); return result; } void GL::getProgramiv(GLuint program, GLenum pname, GLint *params) { @@ -263,12 +263,12 @@ void GL::uniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, co // mapbuffer void* GL::mapBuffer(GLenum target, GLenum access) { auto result = glMapBuffer(target, access); - GL_CHECK(); + GL_CHECK(""); return result; } GLboolean GL::unmapBuffer(GLenum target) { auto result = glUnmapBuffer(target); - GL_CHECK(); + GL_CHECK(""); return result; } @@ -329,7 +329,7 @@ void GL::deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) { GLenum GL::checkFramebufferStatus(GLenum target) { GLenum status = glCheckFramebufferStatus(target); - GL_CHECK(); + GL_CHECK(""); return status; } diff --git a/platforms/common/platform_gl.h b/platforms/common/platform_gl.h index 107396e3be..4fbed058b8 100644 --- a/platforms/common/platform_gl.h +++ b/platforms/common/platform_gl.h @@ -45,6 +45,15 @@ extern PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOESEXT; #include #endif // TANGRAM_LINUX +#ifdef TANGRAM_WINDOWS +#define GL_GLEXT_PROTOTYPES +#include +#include +// Resolve aliased names on Windows +#define glClearDepthf glClearDepth +#define glDepthRangef glDepthRange +#endif // TANGRAM_WINDOWS + #ifdef TANGRAM_RPI // Broadcom library for direct GPU access #include "bcm_host.h" diff --git a/platforms/common/urlClient.cpp b/platforms/common/urlClient.cpp index 07132dfd9c..aad7b8d953 100644 --- a/platforms/common/urlClient.cpp +++ b/platforms/common/urlClient.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include constexpr char const* requestCancelledError = "Request cancelled"; @@ -22,6 +21,92 @@ struct CurlGlobals { } } s_curl; +UrlClient::SelfPipe::~SelfPipe() { +#if defined(_WIN32) + if(pipeFds[0] != SocketInvalid) { + closesocket(pipeFds[0]); + } + if(pipeFds[1] != SocketInvalid) { + closesocket(pipeFds[1]); + } +#endif +} + +bool UrlClient::SelfPipe::initialize() { +#if defined(_WIN32) + // https://stackoverflow.com/questions/3333361/how-to-cancel-waiting-in-select-on-windows + struct sockaddr_in inaddr; + int len = sizeof(inaddr); + memset(&inaddr, 0, len); + struct sockaddr addr; + memset(&addr, 0, sizeof(addr)); + + inaddr.sin_family = AF_INET; + inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + inaddr.sin_port = 0; + int yes = 1; + SOCKET lst = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(lst == INVALID_SOCKET) { + return false; + } + if( + setsockopt(lst, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)) == SOCKET_ERROR || + bind(lst, (struct sockaddr *)&inaddr, sizeof(inaddr)) == SOCKET_ERROR || + listen(lst, 1) == SOCKET_ERROR || + getsockname(lst, &addr, &len) || + (pipeFds[0] = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET + ) { + closesocket(lst); + return false; + } + + if( + (connect(pipeFds[0], &addr, len)) == SOCKET_ERROR || + (pipeFds[1] = accept(lst, 0, 0)) == INVALID_SOCKET + ) { + closesocket(pipeFds[0]); + closesocket(lst); + pipeFds[0] = -1; + return false; + } + + closesocket(lst); + return true; +#else + return pipe(pipeFds) >= 0; +#endif +} + +bool UrlClient::SelfPipe::write() { +#if defined(_WIN32) + return send(pipeFds[1], "\0", 1, 0) >= 0; +#else + return write(pipeFds[1], "\0", 1) >= 0; +#endif +} + +bool UrlClient::SelfPipe::read(int *error) { + char buffer[1]; +#if defined(_WIN32) + int n = recv(pipeFds[0], buffer, sizeof(buffer), 0); + if(n == SOCKET_ERROR) { + *error = WSAGetLastError(); + return false; + } +#else + int n = read(pipeFds[0], buffer, sizeof(buffer)); + if (n <= 0) { + *error = n; + return false; + } +#endif + return true; +} + +UrlClient::SelfPipe::Socket UrlClient::SelfPipe::getReadFd() { + return pipeFds[0]; +} + struct UrlClient::Task { // Reduce Task content capacity when it's more than 128kb and last // content size was less then half limit_capacity. @@ -63,6 +148,7 @@ struct UrlClient::Task { curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(handle, CURLOPT_MAXREDIRS, 20); curl_easy_setopt(handle, CURLOPT_TCP_NODELAY, 1); + curl_easy_setopt(handle, CURLOPT_USERAGENT, _options.userAgentString); } void setup() { @@ -107,7 +193,7 @@ UrlClient::UrlClient(Options options) : m_options(options) { // Using a pipe to notify select() in curl-thread of new requests.. // https://www.linuxquestions.org/questions/programming-9/exit-from-blocked-pselect-661200/ - if (pipe(m_requestNotify) < 0) { + if (!m_requestNotify.initialize()) { LOGE("Could not initialize select breaker!"); } } @@ -154,7 +240,7 @@ UrlClient::~UrlClient() { void UrlClient::curlWakeUp() { if (!m_curlNotified) { - if (write(m_requestNotify[1], "\0", 1) <= 0) { + if (!m_requestNotify.write()) { // err return; } @@ -292,7 +378,7 @@ void UrlClient::curlLoop() { } // Listen on requestNotify to break select when new requests are added. - FD_SET(m_requestNotify[0], &fdread); + FD_SET(m_requestNotify.getReadFd(), &fdread); // Wait for transfers // On success the value of maxfd is guaranteed to be >= -1. We call @@ -306,11 +392,12 @@ void UrlClient::curlLoop() { continue; } else { - if (FD_ISSET(m_requestNotify[0], &fdread)) { + if (FD_ISSET(m_requestNotify.getReadFd(), &fdread)) { // Clear notify fd - char buffer[1]; - int n = read(m_requestNotify[0], buffer, sizeof(buffer)); - if (n <= 0) { LOGE("Read request notify %d", n); } + int error; + if(!m_requestNotify.read(&error)) { + LOGE("Read request notify %d", error); + } //LOG("Got request notifies %d %d", n, m_curlNotified); m_curlNotified = false; } diff --git a/platforms/common/urlClient.h b/platforms/common/urlClient.h index 965386faaa..faad84ecf5 100644 --- a/platforms/common/urlClient.h +++ b/platforms/common/urlClient.h @@ -13,6 +13,9 @@ #include #include +#if defined(_WIN32) +#include +#endif namespace Tangram { @@ -24,6 +27,7 @@ class UrlClient { uint32_t maxActiveTasks = 20; uint32_t connectionTimeoutMs = 3000; uint32_t requestTimeoutMs = 30000; + const char* userAgentString = "tangram"; }; UrlClient(Options options); @@ -43,6 +47,24 @@ class UrlClient { RequestId id; }; + class SelfPipe { + public: +#if defined(_WIN32) + using Socket = SOCKET; + const Socket SocketInvalid = INVALID_SOCKET; +#else + using Socket = int; + const Socket SocketInvalid = -1; +#endif + ~SelfPipe(); + bool initialize(); + bool write(); + bool read(int *error); + Socket getReadFd(); + private: + Socket pipeFds[2] = { SocketInvalid, SocketInvalid }; + }; + struct Task; void curlLoop(); @@ -73,7 +95,7 @@ class UrlClient { std::atomic m_requestCount{0}; // File descriptors to break waiting select. - int m_requestNotify[2] = { -1, -1 }; + SelfPipe m_requestNotify; }; } // namespace Tangram diff --git a/platforms/windows/config.cmake b/platforms/windows/config.cmake new file mode 100644 index 0000000000..628634ac7e --- /dev/null +++ b/platforms/windows/config.cmake @@ -0,0 +1,54 @@ +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments") +endif() + +check_unsupported_compiler_version() + +add_definitions(-DTANGRAM_WINDOWS) + +find_package(OpenGL REQUIRED) +find_package(CURL REQUIRED) + +include(cmake/glfw.cmake) + +add_executable(tangram + platforms/windows/src/windowsPlatform.cpp + platforms/windows/src/main.cpp + platforms/common/platform_gl.cpp + platforms/common/urlClient.cpp + platforms/common/glfwApp.cpp + platforms/common/imgui_impl_glfw.cpp + platforms/common/imgui_impl_opengl3.cpp + platforms/common/glfw/deps/glad.c +) + +add_resources(tangram "${PROJECT_SOURCE_DIR}/scenes" "res") + +add_subdirectory(platforms/common/imgui) + +target_include_directories(tangram + PRIVATE + platforms/common + platforms/common/glfw/deps + ${CURL_INCLUDE_DIRS} +) + +target_link_libraries(tangram + PRIVATE + tangram-core + glfw + imgui + ${GLFW_LIBRARIES} + ${OPENGL_LIBRARIES} + ${CURL_LIBRARIES} + -pthread + wsock32 ws2_32 crypt32 wldap32 +) + +#target_compile_options(tangram +# PRIVATE +# -std=c++14 +#) + +get_nextzen_api_key(NEXTZEN_API_KEY) +target_compile_definitions(tangram PRIVATE NEXTZEN_API_KEY="${NEXTZEN_API_KEY}") diff --git a/platforms/windows/src/main.cpp b/platforms/windows/src/main.cpp new file mode 100644 index 0000000000..ad94df2e2d --- /dev/null +++ b/platforms/windows/src/main.cpp @@ -0,0 +1,39 @@ +#include "glfwApp.h" +#include "windowsPlatform.h" +#include "log.h" +#include "map.h" +#include +#include // _getcwd + +#define PATH_MAX 512 + +using namespace Tangram; + +int main(int argc, char* argv[]) { + + // Create the windowed app. + GlfwApp::create(std::make_unique(), 1024, 768); + + GlfwApp::sceneFile = "res\\scene.yaml"; + GlfwApp::parseArgs(argc, argv); + + // Resolve the input path against the current directory. + Url baseUrl("file:///"); + char pathBuffer[PATH_MAX] = {0}; + if (getcwd(pathBuffer, PATH_MAX) != nullptr) { + baseUrl = baseUrl.resolve(Url("file://" + std::string(pathBuffer))); + } + + LOG("Base URL: %s", baseUrl.string().c_str()); + + Url sceneUrl = baseUrl.resolve(Url(GlfwApp::sceneFile)); + GlfwApp::sceneFile = sceneUrl.string(); + + // Loop until the user closes the window + GlfwApp::run(); + + // Clean up. + GlfwApp::destroy(); + + return 0; +} diff --git a/platforms/windows/src/windowsPlatform.cpp b/platforms/windows/src/windowsPlatform.cpp new file mode 100644 index 0000000000..0b36fc932f --- /dev/null +++ b/platforms/windows/src/windowsPlatform.cpp @@ -0,0 +1,77 @@ +#include "windowsPlatform.h" +#include "gl/hardware.h" +#include "log.h" +#include +#include + +#include + +#define DEFAULT "res/fonts/NotoSans-Regular.ttf" +#define FONT_AR "res/fonts/NotoNaskh-Regular.ttf" +#define FONT_HE "res/fonts/NotoSansHebrew-Regular.ttf" +#define FONT_JA "res/fonts/DroidSansJapanese.ttf" +#define FALLBACK "res/fonts/DroidSansFallback.ttf" + +namespace Tangram { + +void logMsg(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +WindowsPlatform::WindowsPlatform() + : WindowsPlatform(UrlClient::Options{}) {} + +WindowsPlatform::WindowsPlatform(UrlClient::Options urlClientOptions) : + m_urlClient(std::make_unique(urlClientOptions)) { +} + +WindowsPlatform::~WindowsPlatform() {} + +void WindowsPlatform::shutdown() { + // Stop all UrlWorker threads + m_urlClient.reset(); + + Platform::shutdown(); +} + +void WindowsPlatform::requestRender() const { + if (m_shutdown) { return; } + glfwPostEmptyEvent(); +} + +std::vector WindowsPlatform::systemFontFallbacksHandle() const { + std::vector handles; + + handles.emplace_back(Url(DEFAULT)); + handles.emplace_back(Url(FONT_AR)); + handles.emplace_back(Url(FONT_HE)); + handles.emplace_back(Url(FONT_JA)); + handles.emplace_back(Url(FALLBACK)); + + return handles; +} + +bool WindowsPlatform::startUrlRequestImpl(const Url& _url, const UrlRequestHandle _request, UrlRequestId& _id) { + auto onURLResponse = [this, _request](UrlResponse&& response) { + onUrlResponse(_request, std::move(response)); + }; + _id = m_urlClient->addRequest(_url.string(), onURLResponse); + return false; +} + +void WindowsPlatform::cancelUrlRequestImpl(const UrlRequestId _id) { + if (m_urlClient) { + m_urlClient->cancelRequest(_id); + } +} + +void setCurrentThreadPriority(int priority) {} + +void initGLExtensions() { + Tangram::Hardware::supportsMapBuffer = true; +} + +} // namespace Tangram diff --git a/platforms/windows/src/windowsPlatform.h b/platforms/windows/src/windowsPlatform.h new file mode 100644 index 0000000000..ad7cd91066 --- /dev/null +++ b/platforms/windows/src/windowsPlatform.h @@ -0,0 +1,25 @@ +#pragma once + +#include "platform.h" +#include "urlClient.h" + +namespace Tangram { + +class WindowsPlatform : public Platform { + +public: + + WindowsPlatform(); + explicit WindowsPlatform(UrlClient::Options urlClientOptions); + ~WindowsPlatform() override; + void shutdown() override; + void requestRender() const override; + std::vector systemFontFallbacksHandle() const override; + bool startUrlRequestImpl(const Url& _url, const UrlRequestHandle _request, UrlRequestId& _id) override; + void cancelUrlRequestImpl(const UrlRequestId _id) override; + +protected: + std::unique_ptr m_urlClient; +}; + +} // namespace Tangram diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000000..19e50ab90e --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,30 @@ +{ + "name": "tangram-es", + "version-string": "0.1.0", + "dependencies": [ + { + "name":"curl", + "features":[ + "ssl", + "http2" + ] + }, + "glad", + "yaml-cpp", + "glfw3", + "benchmark", + { + "name": "harfbuzz", + "features": [ + "icu", + "graphite2" + ] + }, + { + "name": "imgui", + "features": [ + "docking-experimental" + ] + } + ] +}