diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b64895f3..c56b1585 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: build-essential ninja-build wget lsb-release software-properties-common gnupg \ libgl1-mesa-dev libglew-dev libglfw3-dev \ libpng-dev libopenal-dev libluajit-5.1-dev \ - libserialport-dev libsndfile1-dev \ + libserialport-dev libsndfile1-dev libcurl4-openssl-dev \ xorg-dev libxkbcommon-dev libwayland-dev wayland-protocols - name: Install LLVM/Clang 22 diff --git a/.github/workflows/build_bin.yml b/.github/workflows/build_bin.yml index c64539b5..6ba1a384 100644 --- a/.github/workflows/build_bin.yml +++ b/.github/workflows/build_bin.yml @@ -181,6 +181,7 @@ jobs: libluajit-5.1-dev \ libserialport-dev \ libsndfile1-dev \ + libcurl4-openssl-dev \ xorg-dev \ libxkbcommon-dev \ libwayland-dev \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dc46bbd..7ec662cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -630,10 +630,18 @@ find_package(Threads REQUIRED) target_link_libraries(${PROJECT_NAME} Threads::Threads) # the editor's map imagery talks to a WMS over https. windows has WinHttp in the platform sdk; -# everywhere else libcurl is the transport (see editor/orthophoto.cpp) +# everywhere else libcurl is the transport (see editor/orthophoto.cpp). it is not required: a tree +# without it builds an editor that draws and exports as usual, only with no imagery behind the plan if (NOT WIN32) - find_package(CURL REQUIRED) - target_link_libraries(${PROJECT_NAME} CURL::libcurl) + find_package(CURL) + if (CURL_FOUND) + target_link_libraries(${PROJECT_NAME} CURL::libcurl) + target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_CURL) + else() + message(WARNING + "libcurl not found: the editor will have no map imagery. " + "Install libcurl4-openssl-dev (Debian/Ubuntu) or libcurl-devel (Fedora) to get it back.") + endif() endif() find_package(GLM REQUIRED) diff --git a/editor/orthophoto.cpp b/editor/orthophoto.cpp index f4e650e2..3ba38771 100644 --- a/editor/orthophoto.cpp +++ b/editor/orthophoto.cpp @@ -20,7 +20,7 @@ module; #include #include #pragma comment(lib, "winhttp.lib") -#else +#elif defined(WITH_CURL) #include #endif @@ -37,6 +37,21 @@ obtain one at http://mozilla.org/MPL/2.0/. */ +namespace +{ + +// stb keeps one flip flag for the whole program - there is a single stb_image.c in the build - and +// the model texture loader turns it on for its own sake (models want the bottom row first). A WMS +// tile is the other way about: its first row is its northern edge, which is what the drawing code +// takes v=0 to be. So the orientation is stated per thread, where nobody else can reach it, rather +// than left to whoever decoded an image last +void decode_top_down() +{ + stbi_set_flip_vertically_on_load_thread(0); +} + +} // namespace + namespace editor { @@ -143,7 +158,7 @@ bool http_get(std::string const &Url, std::vector &Bytes, std::str return ok; } -#else +#elif defined(WITH_CURL) // libcurl's write callback: appends one chunk of the body to the caller's buffer std::size_t append_body(char const *Data, std::size_t const Size, std::size_t const Count, void *Userdata) @@ -205,6 +220,22 @@ bool http_get(std::string const &Url, std::vector &Bytes, std::str return ok; } +#else + +// built without a transport: libcurl was not there when this was configured. the editor draws and +// exports as usual - there is simply nothing to put behind the plan, and saying so once is better +// than a silent grey screen +bool http_get(std::string const &, std::vector &, std::string &Contenttype) +{ + Contenttype.clear(); + static auto const said = []() { + ErrorLog("Editor: built without libcurl, so there is no map imagery"); + return true; + }(); + (void)said; + return false; +} + #endif } // namespace @@ -375,6 +406,7 @@ unsigned int orthophoto_source::upload(editor::plan::TileKey const &Key) int width = 0; int height = 0; int channels = 0; + decode_top_down(); auto *pixels = stbi_load_from_memory(image->bytes.data(), static_cast(image->bytes.size()), &width, &height, &channels, 3); if (pixels == nullptr) { @@ -463,6 +495,7 @@ unsigned int upload_image(std::vector const &Bytes) int width = 0; int height = 0; int channels = 0; + decode_top_down(); auto *pixels = stbi_load_from_memory(Bytes.data(), static_cast(Bytes.size()), &width, &height, &channels, 3); if (pixels == nullptr) { diff --git a/model/Texture.cpp b/model/Texture.cpp index c7f65090..e95e6e8a 100644 --- a/model/Texture.cpp +++ b/model/Texture.cpp @@ -368,7 +368,10 @@ void opengl_texture::load_PNG() void opengl_texture::load_STBI() { int x, y, n; - stbi_set_flip_vertically_on_load(1); + // per thread, not for the whole program: there is one stb_image.c in the build, so the global + // flag reaches every other decoder too - which is how the editor's WMS tiles ended up upside + // down as soon as any model texture had been loaded through this path + stbi_set_flip_vertically_on_load_thread(1); uint8_t *image = stbi_load((name + type).c_str(), &x, &y, &n, 4); if (!image) {