From de2c1472e8f4dc7e2f54d386734b24cebc257362 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 3 Jan 2024 19:44:26 +0100 Subject: [PATCH 01/65] texture compression wip. goofy tc doesn't compile for linux :( --- nucleus/CMakeLists.txt | 7 +- nucleus/Controller.cpp | 10 +- nucleus/utils/texture_compression.cpp | 39 +++++ nucleus/utils/texture_compression.h | 28 ++++ unittests/gl_engine/CMakeLists.txt | 1 + unittests/gl_engine/compressed_textures.cpp | 159 ++++++++++++++++++++ 6 files changed, 239 insertions(+), 5 deletions(-) create mode 100644 nucleus/utils/texture_compression.cpp create mode 100644 nucleus/utils/texture_compression.h create mode 100644 unittests/gl_engine/compressed_textures.cpp diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index 404762b1..bf518b0e 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -28,10 +28,14 @@ if (NOT TARGET fmt) alp_add_git_repository(fmt URL https://github.com/fmtlib/fmt.git COMMITISH 10.1.1) endif() alp_add_git_repository(zppbits URL https://github.com/eyalz800/zpp_bits.git COMMITISH v4.4.20 DO_NOT_ADD_SUBPROJECT) +alp_add_git_repository(goofy_tc URL https://github.com/AlpineMapsOrgDependencies/Goofy_slim.git COMMITISH main DO_NOT_ADD_SUBPROJECT) add_library(zppbits INTERFACE) target_include_directories(zppbits SYSTEM INTERFACE ${zppbits_SOURCE_DIR}) +add_library(goofy_tc INTERFACE) +target_include_directories(goofy_tc INTERFACE ${goofy_tc_SOURCE_DIR}) + add_library(tl_expected INTERFACE) target_include_directories(tl_expected INTERFACE ${tl_expected_SOURCE_DIR}/include) @@ -96,10 +100,11 @@ qt_add_library(nucleus STATIC timing/TimerManager.h timing/TimerManager.cpp timing/TimerInterface.h timing/TimerInterface.cpp timing/CpuTimer.h timing/CpuTimer.cpp + utils/texture_compression.h utils/texture_compression.cpp ) target_include_directories(nucleus PRIVATE . PUBLIC ${CMAKE_SOURCE_DIR}) -target_link_libraries(nucleus PUBLIC radix Qt::Core Qt::Gui Qt::Network Qt::Svg fmt::fmt zppbits tl_expected nucleus_version stb_slim) +target_link_libraries(nucleus PUBLIC radix Qt::Core Qt::Gui Qt::Network Qt::Svg fmt::fmt zppbits tl_expected nucleus_version stb_slim goofy_tc) # if (EMSCRIPTEN) # # target_compile_options(nucleus PUBLIC -fwasm-exceptions) diff --git a/nucleus/Controller.cpp b/nucleus/Controller.cpp index 1267673c..36a5d9df 100644 --- a/nucleus/Controller.cpp +++ b/nucleus/Controller.cpp @@ -51,10 +51,12 @@ Controller::Controller(AbstractRenderWindow* render_window) m_terrain_service = std::make_unique("https://alpinemaps.cg.tuwien.ac.at/tiles/alpine_png/", TileLoadService::UrlPattern::ZXY, ".png"); // m_ortho_service.reset(new TileLoadService("https://tiles.bergfex.at/styles/bergfex-osm/", TileLoadService::UrlPattern::ZXY_yPointingSouth, ".jpeg")); // m_ortho_service.reset(new TileLoadService("https://alpinemaps.cg.tuwien.ac.at/tiles/ortho/", TileLoadService::UrlPattern::ZYX_yPointingSouth, ".jpeg")); - // m_ortho_service.reset(new TileLoadService( - // "https://maps%1.wien.gv.at/basemap/bmaporthofoto30cm/normal/google3857/", TileLoadService::UrlPattern::ZYX_yPointingSouth, ".jpeg", { "", "1", "2", "3", "4" })); - m_ortho_service.reset(new TileLoadService( - "https://gataki.cg.tuwien.ac.at/raw/basemap/tiles/", TileLoadService::UrlPattern::ZYX_yPointingSouth, ".jpeg")); + m_ortho_service.reset(new TileLoadService("https://maps%1.wien.gv.at/basemap/bmaporthofoto30cm/normal/google3857/", + TileLoadService::UrlPattern::ZYX_yPointingSouth, + ".jpeg", + {"", "1", "2", "3", "4"})); + // m_ortho_service.reset(new TileLoadService( + // "https://gataki.cg.tuwien.ac.at/raw/basemap/tiles/", TileLoadService::UrlPattern::ZYX_yPointingSouth, ".jpeg")); m_tile_scheduler = std::make_unique(); m_tile_scheduler->read_disk_cache(); diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp new file mode 100644 index 00000000..f7164503 --- /dev/null +++ b/nucleus/utils/texture_compression.cpp @@ -0,0 +1,39 @@ +/***************************************************************************** + * Alpine Terrain Renderer + * Copyright (C) 2024 Adam Celarek + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#define GOOFYTC_IMPLEMENTATION +#include + +#include "texture_compression.h" + +std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& qimage) +{ + std::vector compressed; + compressed.resize(256 * 256 * 2); + if (qimage.format() != QImage::Format_ARGB32 && qimage.format() != QImage::Format_RGB32) { + // let's hope that the format is always ARGB32 + // if not, please implement the conversion, that'll give better performance. + // the assert will be disabled in release, just as a backup. + assert(false); + return to_dxt1(qimage.convertedTo(QImage::Format_ARGB32)); + } + const auto result = goofy::compressDXT1(compressed.data(), qimage.bits(), qimage.width(), qimage.height(), qimage.width()); + assert(result == 0); + + return compressed; +} diff --git a/nucleus/utils/texture_compression.h b/nucleus/utils/texture_compression.h new file mode 100644 index 00000000..68e2c5d3 --- /dev/null +++ b/nucleus/utils/texture_compression.h @@ -0,0 +1,28 @@ +/***************************************************************************** + * Alpine Terrain Renderer + * Copyright (C) 2024 Adam Celarek + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#pragma once + +#include +#include + +namespace nucleus::utils::texture_compression { + +std::vector to_dxt1(const QImage& image); + +} diff --git a/unittests/gl_engine/CMakeLists.txt b/unittests/gl_engine/CMakeLists.txt index 53d9db55..67685ec6 100644 --- a/unittests/gl_engine/CMakeLists.txt +++ b/unittests/gl_engine/CMakeLists.txt @@ -23,6 +23,7 @@ alp_add_unittest(unittests_gl_engine UnittestGLContext.h UnittestGLContext.cpp framebuffer.cpp uniformbuffer.cpp + compressed_textures.cpp ) target_link_libraries(unittests_gl_engine PUBLIC gl_engine) diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp new file mode 100644 index 00000000..ede7fa90 --- /dev/null +++ b/unittests/gl_engine/compressed_textures.cpp @@ -0,0 +1,159 @@ +/***************************************************************************** + * Alpine Terrain Renderer + * Copyright (C) 2024 Adam Celarek + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include +#include + +#include "UnittestGLContext.h" +#include "gl_engine/Framebuffer.h" +#include "gl_engine/ShaderProgram.h" +#include "gl_engine/helpers.h" +#include "nucleus/utils/texture_compression.h" + +using gl_engine::Framebuffer; +using gl_engine::ShaderProgram; + +static const char* const vertex_source = R"( +out highp vec2 texcoords; +void main() { + vec2 vertices[3]=vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0)); + gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0); + texcoords = 0.5 * gl_Position.xy + vec2(0.5); +})"; + +namespace { +ShaderProgram create_debug_shader(const char* fragmentShaderOverride = nullptr) +{ + static const char* const fragment_source = R"( + out lowp vec4 out_Color; + void main() { + out_Color = vec4(0.2, 0.0, 1.0, 0.8); + })"; + ShaderProgram tmp(vertex_source, fragmentShaderOverride ? fragmentShaderOverride : fragment_source, gl_engine::ShaderCodeSource::PLAINTEXT); + return tmp; +} +} // namespace + +TEST_CASE("gl compressed textures") +{ + UnittestGLContext::initialise(); + + const auto* c = QOpenGLContext::currentContext(); + QOpenGLExtraFunctions* f = c->extraFunctions(); + REQUIRE(f); + + QImage test_texture(256, 256, QImage::Format_RGBA8888); + test_texture.fill(qRgba(0, 0, 0, 255)); + { + QPainter painter(&test_texture); + QRadialGradient grad; + grad.setCenter(85, 108); + grad.setRadius(100); + grad.setFocalPoint(120, 150); + grad.setColorAt(0, qRgb(245, 200, 5)); + grad.setColorAt(1, qRgb(145, 100, 0)); + grad.setSpread(QGradient::ReflectSpread); + painter.setBrush(grad); + painter.drawRect(0, 0, 255, 255); + test_texture.save("test_texture.png"); + } + + SECTION("compression") + { + const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); + CHECK(compressed.size() == 256 * 256 * 2); + } + + SECTION("verify test methodology") + { + Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); + b.bind(); + QOpenGLTexture opengl_texture(test_texture); + opengl_texture.setWrapMode(QOpenGLTexture::WrapMode::ClampToBorder); + opengl_texture.setMinMagFilters(QOpenGLTexture::Filter::Nearest, QOpenGLTexture::Filter::Nearest); + opengl_texture.bind(); + + ShaderProgram shader = create_debug_shader(R"( + uniform sampler2D texture_sampler; + in highp vec2 texcoords; + out lowp vec4 out_color; + void main() { + out_color = texture(texture_sampler, vec2(texcoords.x, 1-texcoords.y)); + } + )"); + shader.bind(); + gl_engine::helpers::create_screen_quad_geometry().draw(); + + const QImage render_result = b.read_colour_attachment(0); + render_result.save("render_result.png"); + Framebuffer::unbind(); + REQUIRE(!render_result.isNull()); + CHECK(render_result.width() == test_texture.width()); + CHECK(render_result.height() == test_texture.height()); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.01); + } + + SECTION("compression") + { + Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); + b.bind(); + QOpenGLTexture opengl_texture(QOpenGLTexture::Target2D); + opengl_texture.setSize(256, 256); + opengl_texture.setFormat(QOpenGLTexture::TextureFormat::RGBA_DXT1); + // opengl_texture.setCompressedData(); + opengl_texture.setWrapMode(QOpenGLTexture::WrapMode::ClampToBorder); + opengl_texture.setMinMagFilters(QOpenGLTexture::Filter::Nearest, QOpenGLTexture::Filter::Nearest); + opengl_texture.bind(); + + ShaderProgram shader = create_debug_shader(R"( + uniform sampler2D texture_sampler; + in highp vec2 texcoords; + out lowp vec4 out_color; + void main() { + out_color = texture(texture_sampler, vec2(texcoords.x, 1-texcoords.y)); + } + )"); + shader.bind(); + gl_engine::helpers::create_screen_quad_geometry().draw(); + + const QImage render_result = b.read_colour_attachment(0); + render_result.save("render_result.png"); + Framebuffer::unbind(); + REQUIRE(!render_result.isNull()); + CHECK(render_result.width() == test_texture.width()); + CHECK(render_result.height() == test_texture.height()); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.01); + } +} From 929969ac5b2eb9251e685e69bba79a5a617c2217 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:25:29 +0100 Subject: [PATCH 02/65] switch back to gataki for tiles --- nucleus/Controller.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nucleus/Controller.cpp b/nucleus/Controller.cpp index 36a5d9df..2408fa78 100644 --- a/nucleus/Controller.cpp +++ b/nucleus/Controller.cpp @@ -51,12 +51,12 @@ Controller::Controller(AbstractRenderWindow* render_window) m_terrain_service = std::make_unique("https://alpinemaps.cg.tuwien.ac.at/tiles/alpine_png/", TileLoadService::UrlPattern::ZXY, ".png"); // m_ortho_service.reset(new TileLoadService("https://tiles.bergfex.at/styles/bergfex-osm/", TileLoadService::UrlPattern::ZXY_yPointingSouth, ".jpeg")); // m_ortho_service.reset(new TileLoadService("https://alpinemaps.cg.tuwien.ac.at/tiles/ortho/", TileLoadService::UrlPattern::ZYX_yPointingSouth, ".jpeg")); - m_ortho_service.reset(new TileLoadService("https://maps%1.wien.gv.at/basemap/bmaporthofoto30cm/normal/google3857/", - TileLoadService::UrlPattern::ZYX_yPointingSouth, - ".jpeg", - {"", "1", "2", "3", "4"})); - // m_ortho_service.reset(new TileLoadService( - // "https://gataki.cg.tuwien.ac.at/raw/basemap/tiles/", TileLoadService::UrlPattern::ZYX_yPointingSouth, ".jpeg")); + // m_ortho_service.reset(new TileLoadService("https://maps%1.wien.gv.at/basemap/bmaporthofoto30cm/normal/google3857/", + // TileLoadService::UrlPattern::ZYX_yPointingSouth, + // ".jpeg", + // {"", "1", "2", "3", "4"})); + m_ortho_service.reset( + new TileLoadService("https://gataki.cg.tuwien.ac.at/raw/basemap/tiles/", TileLoadService::UrlPattern::ZYX_yPointingSouth, ".jpeg")); m_tile_scheduler = std::make_unique(); m_tile_scheduler->read_disk_cache(); From abcbea21dcc1e81e4c06659d2a243b7fe613f345 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Fri, 26 Jan 2024 09:44:39 +0100 Subject: [PATCH 03/65] works on desktop. compiles on webassembly (won't run due to wrong compression algorithm) --- nucleus/CMakeLists.txt | 12 ++++---- nucleus/utils/texture_compression.cpp | 33 ++++++++++++++------- nucleus/utils/texture_compression.h | 5 ++-- unittests/gl_engine/compressed_textures.cpp | 31 ++++++++++++------- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index bf518b0e..3169e3c2 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -28,7 +28,7 @@ if (NOT TARGET fmt) alp_add_git_repository(fmt URL https://github.com/fmtlib/fmt.git COMMITISH 10.1.1) endif() alp_add_git_repository(zppbits URL https://github.com/eyalz800/zpp_bits.git COMMITISH v4.4.20 DO_NOT_ADD_SUBPROJECT) -alp_add_git_repository(goofy_tc URL https://github.com/AlpineMapsOrgDependencies/Goofy_slim.git COMMITISH main DO_NOT_ADD_SUBPROJECT) +alp_add_git_repository(goofy_tc URL https://github.com/AlpineMapsOrgDependencies/Goofy_slim.git COMMITISH 13b228784960a6227bb6ca704ff34161bbac1b91 DO_NOT_ADD_SUBPROJECT) add_library(zppbits INTERFACE) target_include_directories(zppbits SYSTEM INTERFACE ${zppbits_SOURCE_DIR}) @@ -106,10 +106,11 @@ qt_add_library(nucleus STATIC target_include_directories(nucleus PRIVATE . PUBLIC ${CMAKE_SOURCE_DIR}) target_link_libraries(nucleus PUBLIC radix Qt::Core Qt::Gui Qt::Network Qt::Svg fmt::fmt zppbits tl_expected nucleus_version stb_slim goofy_tc) -# if (EMSCRIPTEN) +if (EMSCRIPTEN) + target_compile_options(nucleus PUBLIC -msimd128 -msse2 -Wno-dollar-in-identifier-extension) # # target_compile_options(nucleus PUBLIC -fwasm-exceptions) # # target_link_options(nucleus PUBLIC -fwasm-exceptions) -# endif() +endif() if (ALP_ENABLE_THREADING) target_compile_definitions(nucleus PUBLIC "ALP_ENABLE_THREADING") endif() @@ -117,10 +118,7 @@ endif() if (MSVC) target_compile_options(nucleus PUBLIC /W4 #[[/WX]]) # /WX fails with an unreachable code warning/error in zpp_bits.h. the system property doesn't seem to work (even though it appears in the build log as - # -external:ID:\a\renderer\renderer\extern\zppbits -external:W0 + # "-external:ID:\a\renderer\renderer\extern\zppbits -external:W0") else() target_compile_options(nucleus PUBLIC -Wall -Wextra -pedantic -Werror) - if (EMSCRIPTEN) - target_compile_options(nucleus PUBLIC -Wno-dollar-in-identifier-extension) - endif() endif() diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp index f7164503..9b7fd6c2 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/texture_compression.cpp @@ -21,19 +21,32 @@ #include "texture_compression.h" -std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& qimage) +std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& qimage) { - std::vector compressed; - compressed.resize(256 * 256 * 2); - if (qimage.format() != QImage::Format_ARGB32 && qimage.format() != QImage::Format_RGB32) { - // let's hope that the format is always ARGB32 - // if not, please implement the conversion, that'll give better performance. - // the assert will be disabled in release, just as a backup. - assert(false); - return to_dxt1(qimage.convertedTo(QImage::Format_ARGB32)); + if (qimage.format() != QImage::Format_RGBA8888 && qimage.format() != QImage::Format_RGBX8888) { + // format is ARGB32 most of the time. we could implement on-the-fly transformation in goofy::compressDXT1 if this is too slow. + return to_dxt1(qimage.convertedTo(QImage::Format_RGBX8888)); } - const auto result = goofy::compressDXT1(compressed.data(), qimage.bits(), qimage.width(), qimage.height(), qimage.width()); + assert(qimage.width() == qimage.height()); + assert(qimage.width() % 16 == 0); + + // struct alignas(64) AlignedBlock + // { + // std::array data; + // }; + // static_assert(sizeof(AlignedBlock) == 64); + + const auto n_bytes = qimage.width() * qimage.height() / 2; + // assert(n_bytes % sizeof(AlignedBlock) == 0); + + // auto buffer = std::vector(n_bytes / sizeof(AlignedBlock)); + // auto data_ptr = reinterpret_cast(buffer.data()); + + std::vector compressed(n_bytes); + const auto result = goofy::compressDXT1(compressed.data(), qimage.bits(), qimage.width(), qimage.height(), qimage.width() * 4); assert(result == 0); + // std::copy(data_ptr, data_ptr + n_bytes, compressed.begin()); + return compressed; } diff --git a/nucleus/utils/texture_compression.h b/nucleus/utils/texture_compression.h index 68e2c5d3..d7429778 100644 --- a/nucleus/utils/texture_compression.h +++ b/nucleus/utils/texture_compression.h @@ -19,10 +19,9 @@ #pragma once #include -#include +#include namespace nucleus::utils::texture_compression { -std::vector to_dxt1(const QImage& image); - +std::vector to_dxt1(const QImage& image); } diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index ede7fa90..75efd0d6 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "UnittestGLContext.h" #include "gl_engine/Framebuffer.h" @@ -58,7 +59,7 @@ TEST_CASE("gl compressed textures") QOpenGLExtraFunctions* f = c->extraFunctions(); REQUIRE(f); - QImage test_texture(256, 256, QImage::Format_RGBA8888); + QImage test_texture(256, 256, QImage::Format_ARGB32); test_texture.fill(qRgba(0, 0, 0, 255)); { QPainter painter(&test_texture); @@ -77,7 +78,7 @@ TEST_CASE("gl compressed textures") SECTION("compression") { const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); - CHECK(compressed.size() == 256 * 256 * 2); + CHECK(compressed.size() == 256 * 128); } SECTION("verify test methodology") @@ -101,7 +102,7 @@ TEST_CASE("gl compressed textures") gl_engine::helpers::create_screen_quad_geometry().draw(); const QImage render_result = b.read_colour_attachment(0); - render_result.save("render_result.png"); + // render_result.save("render_result.png"); Framebuffer::unbind(); REQUIRE(!render_result.isNull()); CHECK(render_result.width() == test_texture.width()); @@ -121,13 +122,23 @@ TEST_CASE("gl compressed textures") { Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); b.bind(); - QOpenGLTexture opengl_texture(QOpenGLTexture::Target2D); - opengl_texture.setSize(256, 256); - opengl_texture.setFormat(QOpenGLTexture::TextureFormat::RGBA_DXT1); - // opengl_texture.setCompressedData(); - opengl_texture.setWrapMode(QOpenGLTexture::WrapMode::ClampToBorder); - opengl_texture.setMinMagFilters(QOpenGLTexture::Filter::Nearest, QOpenGLTexture::Filter::Nearest); - opengl_texture.bind(); + + const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); + opengl_texture.bind(0); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + f->glCompressedTexImage2D(GL_TEXTURE_2D, + 0, + GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + test_texture.width(), + test_texture.height(), + 0, + compressed.size(), + compressed.data()); ShaderProgram shader = create_debug_shader(R"( uniform sampler2D texture_sampler; From abad884a632948f8be692e487407b9d6c9127263 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Fri, 26 Jan 2024 10:48:10 +0100 Subject: [PATCH 04/65] try implement texture compression for mobile devices (unittests) --- nucleus/utils/texture_compression.cpp | 30 ++++++++++ nucleus/utils/texture_compression.h | 1 + unittests/gl_engine/compressed_textures.cpp | 66 +++++++++++++++++++-- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp index 9b7fd6c2..7864de9e 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/texture_compression.cpp @@ -50,3 +50,33 @@ std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& return compressed; } + +std::vector nucleus::utils::texture_compression::to_etc1(const QImage& qimage) +{ + if (qimage.format() != QImage::Format_RGBA8888 && qimage.format() != QImage::Format_RGBX8888) { + // format is ARGB32 most of the time. we could implement on-the-fly transformation in goofy::compressDXT1 if this is too slow. + return to_dxt1(qimage.convertedTo(QImage::Format_RGBX8888)); + } + assert(qimage.width() == qimage.height()); + assert(qimage.width() % 16 == 0); + + // struct alignas(64) AlignedBlock + // { + // std::array data; + // }; + // static_assert(sizeof(AlignedBlock) == 64); + + const auto n_bytes = qimage.width() * qimage.height() / 2; + // assert(n_bytes % sizeof(AlignedBlock) == 0); + + // auto buffer = std::vector(n_bytes / sizeof(AlignedBlock)); + // auto data_ptr = reinterpret_cast(buffer.data()); + + std::vector compressed(n_bytes); + const auto result = goofy::compressETC1(compressed.data(), qimage.bits(), qimage.width(), qimage.height(), qimage.width() * 4); + assert(result == 0); + + // std::copy(data_ptr, data_ptr + n_bytes, compressed.begin()); + + return compressed; +} diff --git a/nucleus/utils/texture_compression.h b/nucleus/utils/texture_compression.h index d7429778..9d6e896b 100644 --- a/nucleus/utils/texture_compression.h +++ b/nucleus/utils/texture_compression.h @@ -24,4 +24,5 @@ namespace nucleus::utils::texture_compression { std::vector to_dxt1(const QImage& image); +std::vector to_etc1(const QImage& image); } diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index 75efd0d6..0fb73f45 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -77,8 +77,14 @@ TEST_CASE("gl compressed textures") SECTION("compression") { - const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); - CHECK(compressed.size() == 256 * 128); + { + const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); + CHECK(compressed.size() == 256 * 128); + } + { + const auto compressed = nucleus::utils::texture_compression::to_etc1(test_texture); + CHECK(compressed.size() == 256 * 128); + } } SECTION("verify test methodology") @@ -95,7 +101,7 @@ TEST_CASE("gl compressed textures") in highp vec2 texcoords; out lowp vec4 out_color; void main() { - out_color = texture(texture_sampler, vec2(texcoords.x, 1-texcoords.y)); + out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); } )"); shader.bind(); @@ -118,7 +124,7 @@ TEST_CASE("gl compressed textures") CHECK(diff / (256 * 256 * 3) < 0.01); } - SECTION("compression") + SECTION("compression dxt1") { Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); b.bind(); @@ -145,7 +151,57 @@ TEST_CASE("gl compressed textures") in highp vec2 texcoords; out lowp vec4 out_color; void main() { - out_color = texture(texture_sampler, vec2(texcoords.x, 1-texcoords.y)); + out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); + } + )"); + shader.bind(); + gl_engine::helpers::create_screen_quad_geometry().draw(); + + const QImage render_result = b.read_colour_attachment(0); + render_result.save("render_result.png"); + Framebuffer::unbind(); + REQUIRE(!render_result.isNull()); + CHECK(render_result.width() == test_texture.width()); + CHECK(render_result.height() == test_texture.height()); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.01); + } + + SECTION("compression etc1") + { + Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); + b.bind(); + + const auto compressed = nucleus::utils::texture_compression::to_etc1(test_texture); + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); + opengl_texture.bind(0); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + f->glCompressedTexImage2D(GL_TEXTURE_2D, + 0, + GL_COMPRESSED_RGB8_ETC2, + test_texture.width(), + test_texture.height(), + 0, + compressed.size(), + compressed.data()); + + ShaderProgram shader = create_debug_shader(R"( + uniform sampler2D texture_sampler; + in highp vec2 texcoords; + out lowp vec4 out_color; + void main() { + out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); } )"); shader.bind(); From a16ab22e90330f1eb69bbaed3cb6d5f9bd84e38a Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 29 Jan 2024 18:46:51 +0100 Subject: [PATCH 05/65] fix android build --- nucleus/CMakeLists.txt | 1 + unittests/gl_engine/compressed_textures.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index 3169e3c2..702dc918 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -35,6 +35,7 @@ target_include_directories(zppbits SYSTEM INTERFACE ${zppbits_SOURCE_DIR}) add_library(goofy_tc INTERFACE) target_include_directories(goofy_tc INTERFACE ${goofy_tc_SOURCE_DIR}) +set_target_properties(goofy_tc PROPERTIES SYSTEM true) add_library(tl_expected INTERFACE) target_include_directories(tl_expected INTERFACE ${tl_expected_SOURCE_DIR}/include) diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index 0fb73f45..96af0217 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -20,6 +20,9 @@ #include #include #include +#ifdef ANDROID +#include +#endif #include "UnittestGLContext.h" #include "gl_engine/Framebuffer.h" From 3747d640cfb80c270d78c90369958f2b2c490aef Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 30 Jan 2024 19:37:48 +0100 Subject: [PATCH 06/65] fix alignment on input for mobile webassembly. --- nucleus/utils/texture_compression.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp index 7864de9e..806e8154 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/texture_compression.cpp @@ -59,20 +59,23 @@ std::vector nucleus::utils::texture_compression::to_etc1(const QImage& } assert(qimage.width() == qimage.height()); assert(qimage.width() % 16 == 0); + assert(qimage.bytesPerLine() * qimage.height() == qimage.width() * qimage.height() * 4); - // struct alignas(64) AlignedBlock - // { - // std::array data; - // }; - // static_assert(sizeof(AlignedBlock) == 64); + struct alignas(16) AlignedBlock + { + std::array data; + }; + static_assert(sizeof(AlignedBlock) == 16); - const auto n_bytes = qimage.width() * qimage.height() / 2; - // assert(n_bytes % sizeof(AlignedBlock) == 0); + const auto n_bytes_in = qimage.width() * qimage.height() * 4; + const auto n_bytes_out = qimage.width() * qimage.height() / 2; + assert(n_bytes_in % sizeof(AlignedBlock) == 0); - // auto buffer = std::vector(n_bytes / sizeof(AlignedBlock)); + auto aligned_in = std::vector(n_bytes_in / sizeof(AlignedBlock)); + std::copy(qimage.bits(), qimage.bits() + n_bytes_in, aligned_in.data()->data.data()); // auto data_ptr = reinterpret_cast(buffer.data()); - std::vector compressed(n_bytes); + std::vector compressed(n_bytes_out); const auto result = goofy::compressETC1(compressed.data(), qimage.bits(), qimage.width(), qimage.height(), qimage.width() * 4); assert(result == 0); From 9f4010f34cf23b35c8389b2317d8618818f90b77 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 31 Jan 2024 08:34:07 +0100 Subject: [PATCH 07/65] try using the WEBGL_compressed_texture_etc1 extension in webassembly --- unittests/gl_engine/compressed_textures.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index 96af0217..fabf78de 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -23,6 +23,10 @@ #ifdef ANDROID #include #endif +#ifdef __EMSCRIPTEN__ +#include +#include +#endif #include "UnittestGLContext.h" #include "gl_engine/Framebuffer.h" @@ -181,6 +185,14 @@ TEST_CASE("gl compressed textures") { Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); b.bind(); +#ifdef __EMSCRIPTEN__ + int gl_texture_format = EM_ASM_INT({ + const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); + return ext.COMPRESSED_RGB_ETC1_WEBGL; + }); +#else + constexpr gl_texture_format = GL_COMPRESSED_RGB8_ETC2; +#endif const auto compressed = nucleus::utils::texture_compression::to_etc1(test_texture); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); @@ -192,7 +204,7 @@ TEST_CASE("gl compressed textures") f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); f->glCompressedTexImage2D(GL_TEXTURE_2D, 0, - GL_COMPRESSED_RGB8_ETC2, + gl_texture_format, test_texture.width(), test_texture.height(), 0, From 2a477709be4dccf7770d13c91e7c0b18880a6694 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 31 Jan 2024 08:34:31 +0100 Subject: [PATCH 08/65] fix fix alignment issues --- nucleus/utils/texture_compression.cpp | 31 +++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp index 806e8154..5743f04d 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/texture_compression.cpp @@ -29,21 +29,24 @@ std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& } assert(qimage.width() == qimage.height()); assert(qimage.width() % 16 == 0); + assert(qimage.bytesPerLine() * qimage.height() == qimage.width() * qimage.height() * 4); - // struct alignas(64) AlignedBlock - // { - // std::array data; - // }; - // static_assert(sizeof(AlignedBlock) == 64); + struct alignas(16) AlignedBlock + { + std::array data; + }; + static_assert(sizeof(AlignedBlock) == 16); - const auto n_bytes = qimage.width() * qimage.height() / 2; - // assert(n_bytes % sizeof(AlignedBlock) == 0); + const auto n_bytes_in = qimage.width() * qimage.height() * 4; + const auto n_bytes_out = qimage.width() * qimage.height() / 2; + assert(n_bytes_in % sizeof(AlignedBlock) == 0); - // auto buffer = std::vector(n_bytes / sizeof(AlignedBlock)); - // auto data_ptr = reinterpret_cast(buffer.data()); + auto aligned_in = std::vector(n_bytes_in / sizeof(AlignedBlock)); + auto data_ptr = reinterpret_cast(aligned_in.data()); + std::copy(qimage.bits(), qimage.bits() + n_bytes_in, data_ptr); - std::vector compressed(n_bytes); - const auto result = goofy::compressDXT1(compressed.data(), qimage.bits(), qimage.width(), qimage.height(), qimage.width() * 4); + std::vector compressed(n_bytes_out); + const auto result = goofy::compressDXT1(compressed.data(), data_ptr, qimage.width(), qimage.height(), qimage.width() * 4); assert(result == 0); // std::copy(data_ptr, data_ptr + n_bytes, compressed.begin()); @@ -72,11 +75,11 @@ std::vector nucleus::utils::texture_compression::to_etc1(const QImage& assert(n_bytes_in % sizeof(AlignedBlock) == 0); auto aligned_in = std::vector(n_bytes_in / sizeof(AlignedBlock)); - std::copy(qimage.bits(), qimage.bits() + n_bytes_in, aligned_in.data()->data.data()); - // auto data_ptr = reinterpret_cast(buffer.data()); + auto data_ptr = reinterpret_cast(aligned_in.data()); + std::copy(qimage.bits(), qimage.bits() + n_bytes_in, data_ptr); std::vector compressed(n_bytes_out); - const auto result = goofy::compressETC1(compressed.data(), qimage.bits(), qimage.width(), qimage.height(), qimage.width() * 4); + const auto result = goofy::compressETC1(compressed.data(), data_ptr, qimage.width(), qimage.height(), qimage.width() * 4); assert(result == 0); // std::copy(data_ptr, data_ptr + n_bytes, compressed.begin()); From 3cb0a98dae4d63a9501fbe97df8d7867f991da02 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 31 Jan 2024 19:01:43 +0100 Subject: [PATCH 09/65] attempt ericson texture compression for webassembly mobile --- unittests/gl_engine/compressed_textures.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index fabf78de..005b67be 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -186,12 +186,20 @@ TEST_CASE("gl compressed textures") Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); b.bind(); #ifdef __EMSCRIPTEN__ + // clang-format off int gl_texture_format = EM_ASM_INT({ + var canvas = document.createElement('canvas'); + var gl = canvas.getContext("webgl2"); const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); + if (ext === null) + return 0; return ext.COMPRESSED_RGB_ETC1_WEBGL; }); + // clang-format on + if (gl_texture_format == 0) + gl_texture_format = GL_COMPRESSED_RGB8_ETC2; // not on mobile #else - constexpr gl_texture_format = GL_COMPRESSED_RGB8_ETC2; + constexpr auto gl_texture_format = GL_COMPRESSED_RGB8_ETC2; #endif const auto compressed = nucleus::utils::texture_compression::to_etc1(test_texture); From 29f4303e4b13f19452ff486acd921b964cd225da Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 31 Jan 2024 21:51:21 +0100 Subject: [PATCH 10/65] debug out --- unittests/gl_engine/compressed_textures.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index 005b67be..6691e497 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -195,9 +195,12 @@ TEST_CASE("gl compressed textures") return 0; return ext.COMPRESSED_RGB_ETC1_WEBGL; }); + qDebug() << "gl_texture_format from js: " << gl_texture_format; // clang-format on - if (gl_texture_format == 0) + if (gl_texture_format == 0) { gl_texture_format = GL_COMPRESSED_RGB8_ETC2; // not on mobile + qDebug() << "gl_texture_format from GL_COMPRESSED_RGB8_ETC2: " << gl_texture_format; + } #else constexpr auto gl_texture_format = GL_COMPRESSED_RGB8_ETC2; #endif From 07d16dc06e9d21c99566b5205cca5e450338beeb Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 31 Jan 2024 22:51:29 +0100 Subject: [PATCH 11/65] fix function call --- nucleus/utils/texture_compression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp index 5743f04d..cc019ee3 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/texture_compression.cpp @@ -58,7 +58,7 @@ std::vector nucleus::utils::texture_compression::to_etc1(const QImage& { if (qimage.format() != QImage::Format_RGBA8888 && qimage.format() != QImage::Format_RGBX8888) { // format is ARGB32 most of the time. we could implement on-the-fly transformation in goofy::compressDXT1 if this is too slow. - return to_dxt1(qimage.convertedTo(QImage::Format_RGBX8888)); + return to_etc1(qimage.convertedTo(QImage::Format_RGBX8888)); } assert(qimage.width() == qimage.height()); assert(qimage.width() % 16 == 0); From e54581c793ed8c8c4699586d8fa3fb32ffda7087 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Thu, 1 Feb 2024 21:27:49 +0100 Subject: [PATCH 12/65] atempt platform independent compression (dxt for desktop, etc for mobile) --- gl_engine/Texture.cpp | 60 +++++++ gl_engine/Texture.h | 4 + unittests/gl_engine/compressed_textures.cpp | 190 ++++++++++++-------- 3 files changed, 184 insertions(+), 70 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 85335675..2c1b353b 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -17,8 +17,16 @@ *****************************************************************************/ #include "Texture.h" +#include "nucleus/utils/texture_compression.h" #include +#ifdef __EMSCRIPTEN__ +#include +#include +#endif +#ifdef ANDROID +#include +#endif gl_engine::Texture::Texture(Target target) : m_target(target) @@ -41,3 +49,55 @@ void gl_engine::Texture::bind(unsigned int texture_unit) f->glActiveTexture(GL_TEXTURE0 + texture_unit); f->glBindTexture(GLenum(m_target), m_id); } + +GLenum gl_engine::Texture::compressed_texture_format() +{ + // select between + // DXT1, also called s3tc, old desktop compression + // ETC1, old mobile compression +#if defined(__EMSCRIPTEN__) + // clang-format off + static int gl_texture_format = EM_ASM_INT({ + var canvas = document.createElement('canvas'); + var gl = canvas.getContext("webgl2"); + const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); + if (ext === null) + return 0; + return ext.COMPRESSED_RGB_ETC1_WEBGL; + }); + qDebug() << "gl_texture_format from js: " << gl_texture_format; + // clang-format on + if (gl_texture_format == 0) { + gl_texture_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // not on mobile + } + return gl_texture_format; +#elif defined(__ANDROID__) + return GL_COMPRESSED_RGB8_ETC2; +#else + return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; +#endif +} + +std::vector gl_engine::Texture::compress(const QImage& image) +{ +#if defined(__EMSCRIPTEN__) + // clang-format off + static const int gl_texture_format = EM_ASM_INT({ + var canvas = document.createElement('canvas'); + var gl = canvas.getContext("webgl2"); + const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); + if (ext === null) + return 0; + return ext.COMPRESSED_RGB_ETC1_WEBGL; + }); + // clang-format on + if (gl_texture_format == 0) { + return nucleus::utils::texture_compression::to_dxt1(image); + } + return nucleus::utils::texture_compression::to_etc1(image); +#elif defined(__ANDROID__) + return nucleus::utils::texture_compression::to_etc1(image); +#else + return nucleus::utils::texture_compression::to_dxt1(image); +#endif +} diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index 2206d05f..ba16338b 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -18,6 +18,7 @@ #pragma once +#include #include namespace gl_engine { @@ -30,9 +31,12 @@ class Texture { ~Texture(); void bind(unsigned texture_unit); + static GLenum compressed_texture_format(); + static std::vector compress(const QImage& image); private: GLuint m_id = -1; Target m_target = Target::_2d; }; + } // namespace gl_engine diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index 6691e497..170286dc 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -131,12 +131,12 @@ TEST_CASE("gl compressed textures") CHECK(diff / (256 * 256 * 3) < 0.01); } - SECTION("compression dxt1") + SECTION("compression") { Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); b.bind(); - const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); + const auto compressed = gl_engine::Texture::compress(test_texture); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); opengl_texture.bind(0); f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -146,7 +146,7 @@ TEST_CASE("gl compressed textures") f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); f->glCompressedTexImage2D(GL_TEXTURE_2D, 0, - GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + gl_engine::Texture::compressed_texture_format(), test_texture.width(), test_texture.height(), 0, @@ -165,7 +165,7 @@ TEST_CASE("gl compressed textures") gl_engine::helpers::create_screen_quad_geometry().draw(); const QImage render_result = b.read_colour_attachment(0); - render_result.save("render_result.png"); + // render_result.save("render_result.png"); Framebuffer::unbind(); REQUIRE(!render_result.isNull()); CHECK(render_result.width() == test_texture.width()); @@ -178,75 +178,125 @@ TEST_CASE("gl compressed textures") diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; } } - CHECK(diff / (256 * 256 * 3) < 0.01); + CHECK(diff / (256 * 256 * 3) < 0.015); } - SECTION("compression etc1") - { - Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); - b.bind(); -#ifdef __EMSCRIPTEN__ - // clang-format off - int gl_texture_format = EM_ASM_INT({ - var canvas = document.createElement('canvas'); - var gl = canvas.getContext("webgl2"); - const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); - if (ext === null) - return 0; - return ext.COMPRESSED_RGB_ETC1_WEBGL; - }); - qDebug() << "gl_texture_format from js: " << gl_texture_format; - // clang-format on - if (gl_texture_format == 0) { - gl_texture_format = GL_COMPRESSED_RGB8_ETC2; // not on mobile - qDebug() << "gl_texture_format from GL_COMPRESSED_RGB8_ETC2: " << gl_texture_format; - } -#else - constexpr auto gl_texture_format = GL_COMPRESSED_RGB8_ETC2; -#endif + // SECTION("compression dxt1") + // { + // Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); + // b.bind(); - const auto compressed = nucleus::utils::texture_compression::to_etc1(test_texture); - gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); - opengl_texture.bind(0); - f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - f->glCompressedTexImage2D(GL_TEXTURE_2D, - 0, - gl_texture_format, - test_texture.width(), - test_texture.height(), - 0, - compressed.size(), - compressed.data()); + // const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); + // gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); + // opengl_texture.bind(0); + // f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // f->glCompressedTexImage2D(GL_TEXTURE_2D, + // 0, + // GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + // test_texture.width(), + // test_texture.height(), + // 0, + // compressed.size(), + // compressed.data()); - ShaderProgram shader = create_debug_shader(R"( - uniform sampler2D texture_sampler; - in highp vec2 texcoords; - out lowp vec4 out_color; - void main() { - out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); - } - )"); - shader.bind(); - gl_engine::helpers::create_screen_quad_geometry().draw(); + // ShaderProgram shader = create_debug_shader(R"( + // uniform sampler2D texture_sampler; + // in highp vec2 texcoords; + // out lowp vec4 out_color; + // void main() { + // out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); + // } + // )"); + // shader.bind(); + // gl_engine::helpers::create_screen_quad_geometry().draw(); - const QImage render_result = b.read_colour_attachment(0); - render_result.save("render_result.png"); - Framebuffer::unbind(); - REQUIRE(!render_result.isNull()); - CHECK(render_result.width() == test_texture.width()); - CHECK(render_result.height() == test_texture.height()); - double diff = 0; - for (int i = 0; i < render_result.width(); ++i) { - for (int j = 0; j < render_result.height(); ++j) { - diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; - diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; - diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; - } - } - CHECK(diff / (256 * 256 * 3) < 0.01); - } + // const QImage render_result = b.read_colour_attachment(0); + // render_result.save("render_result.png"); + // Framebuffer::unbind(); + // REQUIRE(!render_result.isNull()); + // CHECK(render_result.width() == test_texture.width()); + // CHECK(render_result.height() == test_texture.height()); + // double diff = 0; + // for (int i = 0; i < render_result.width(); ++i) { + // for (int j = 0; j < render_result.height(); ++j) { + // diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + // diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + // diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + // } + // } + // CHECK(diff / (256 * 256 * 3) < 0.015); + // } + + // SECTION("compression etc1") + // { + // Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); + // b.bind(); + // #ifdef __EMSCRIPTEN__ + // // clang-format off + // int gl_texture_format = EM_ASM_INT({ + // var canvas = document.createElement('canvas'); + // var gl = canvas.getContext("webgl2"); + // const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); + // if (ext === null) + // return 0; + // return ext.COMPRESSED_RGB_ETC1_WEBGL; + // }); + // qDebug() << "gl_texture_format from js: " << gl_texture_format; + // // clang-format on + // if (gl_texture_format == 0) { + // gl_texture_format = GL_COMPRESSED_RGB8_ETC2; // not on mobile + // qDebug() << "gl_texture_format from GL_COMPRESSED_RGB8_ETC2: " << gl_texture_format; + // } + // #else + // constexpr auto gl_texture_format = GL_COMPRESSED_RGB8_ETC2; + // #endif + + // const auto compressed = nucleus::utils::texture_compression::to_etc1(test_texture); + // gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); + // opengl_texture.bind(0); + // f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // f->glCompressedTexImage2D(GL_TEXTURE_2D, + // 0, + // gl_texture_format, + // test_texture.width(), + // test_texture.height(), + // 0, + // compressed.size(), + // compressed.data()); + + // ShaderProgram shader = create_debug_shader(R"( + // uniform sampler2D texture_sampler; + // in highp vec2 texcoords; + // out lowp vec4 out_color; + // void main() { + // out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); + // } + // )"); + // shader.bind(); + // gl_engine::helpers::create_screen_quad_geometry().draw(); + + // const QImage render_result = b.read_colour_attachment(0); + // render_result.save("render_result.png"); + // Framebuffer::unbind(); + // REQUIRE(!render_result.isNull()); + // CHECK(render_result.width() == test_texture.width()); + // CHECK(render_result.height() == test_texture.height()); + // double diff = 0; + // for (int i = 0; i < render_result.width(); ++i) { + // for (int j = 0; j < render_result.height(); ++j) { + // diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + // diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + // diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + // } + // } + // CHECK(diff / (256 * 256 * 3) < 0.015); + // } } From a8445b39c4abf38d454a319157e893dc21fcce79 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:16:15 +0100 Subject: [PATCH 13/65] remove obsolete import --- app/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/app/main.cpp b/app/main.cpp index 44e4ffae..fab1dbc6 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include From 758e443b26234ad354f5689feb9aa664f3aff7f6 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:46:06 +0100 Subject: [PATCH 14/65] remove version number in qml files (as per new guidelines) --- app/components/FluxColor/AngleWheel.qml | 2 +- app/components/FluxColor/HueRing.qml | 2 +- app/components/FluxColor/HueWheel.qml | 2 +- app/components/FluxColor/WheelArea.qml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/components/FluxColor/AngleWheel.qml b/app/components/FluxColor/AngleWheel.qml index 8245887f..b885ae89 100644 --- a/app/components/FluxColor/AngleWheel.qml +++ b/app/components/FluxColor/AngleWheel.qml @@ -6,7 +6,7 @@ * */ -import QtQuick 2.0 +import QtQuick WheelArea { id: control diff --git a/app/components/FluxColor/HueRing.qml b/app/components/FluxColor/HueRing.qml index cbc1b856..c7a0f036 100644 --- a/app/components/FluxColor/HueRing.qml +++ b/app/components/FluxColor/HueRing.qml @@ -6,7 +6,7 @@ * */ -import QtQuick 2.6 +import QtQuick Canvas { anchors.fill: parent diff --git a/app/components/FluxColor/HueWheel.qml b/app/components/FluxColor/HueWheel.qml index 046814ba..d225db5c 100644 --- a/app/components/FluxColor/HueWheel.qml +++ b/app/components/FluxColor/HueWheel.qml @@ -6,7 +6,7 @@ * */ -import QtQuick 2.0 +import QtQuick WheelArea { id: control diff --git a/app/components/FluxColor/WheelArea.qml b/app/components/FluxColor/WheelArea.qml index a6ab4346..020bafa1 100644 --- a/app/components/FluxColor/WheelArea.qml +++ b/app/components/FluxColor/WheelArea.qml @@ -6,7 +6,7 @@ * */ -import QtQuick 2.0 +import QtQuick Item { id: control From d656dcd4fe658bf4838b4ee042ebb40d872adafd Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:46:49 +0100 Subject: [PATCH 15/65] replace html text with markdown. this allows to remove the html backend from qt --- app/About.qml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/app/About.qml b/app/About.qml index 8e830ba6..fa6f6246 100644 --- a/app/About.qml +++ b/app/About.qml @@ -36,11 +36,12 @@ Rectangle { Rectangle { id: about_content - width: logo.width + Math.max(alpine_text.width, maps_text.width) + 20 + width: logo.width + logo_type.width + 20 color: "#00FFFFFF" height: about_text.implicitHeight + logo.height + 20 Image { id: logo; width: 120; height: 120; source: "icons/mascot.jpg" } Image { + id: logo_type anchors { left: logo.right top: logo.top @@ -55,7 +56,7 @@ Rectangle { } - Label { + Text { id: about_text anchors { left: logo.left @@ -65,13 +66,18 @@ Rectangle { width: about_root.width - 20 wrapMode: Text.Wrap onLinkActivated: Qt.openUrlExternally(link) + textFormat: Text.MarkdownText + text: qsTr(" +This is an open source application. It is released under the GNU General Public License (version 3 or any later version). The source code is available on [github.com/AlpineMapsOrg/renderer](https://github.com/AlpineMapsOrg/renderer). - text: qsTr("

This is an open source application. It is released under the GNU General Public License (version 3 or any later version). " - + "The source code is available on github.com/AlpineMapsOrg/renderer.

" - + "

The source of elevation and orthographic photo data is basemap.at, " - + "it is licensed under the Open Government Data Austria license (CC-BY 4.0).

" - + "

Authors:

Adam Celarek, Lucas Dworschak, Gerald Kimmersdorfer, Jakob Lindner

" - + "

Impressum:

Adam Celarek
Hartmanngasse 12/22
1050 Wien
Österreich / Austria

") +The source of elevation and orthographic photo data is basemap.at, +it is licensed under the Open Government Data Austria license (CC-BY 4.0). + +# Authors: +Adam Celarek, Lucas Dworschak, Gerald Kimmersdorfer, Jakob Lindner + +# Impressum: +Adam Celarek
Hartmanngasse 12/22
1050 Wien
Österreich / Austria") } } } From e5708ded0d10278fe28fcf63810503bb77429763 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:47:29 +0100 Subject: [PATCH 16/65] fix compiler error on newer emscripten compiler --- nucleus/camera/FirstPersonInteraction.cpp | 1 - nucleus/utils/texture_compression.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/nucleus/camera/FirstPersonInteraction.cpp b/nucleus/camera/FirstPersonInteraction.cpp index 2462cfd1..e7d5b8f5 100644 --- a/nucleus/camera/FirstPersonInteraction.cpp +++ b/nucleus/camera/FirstPersonInteraction.cpp @@ -130,7 +130,6 @@ std::optional FirstPersonInteraction::update(Definition camera, Abst if (m_key_q) { direction -= camera.y_axis(); } - glm::normalize(direction); double dt = m_stopwatch.lap().count(); if (dt > 120) { // catches big time steps dt = 120; diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp index cc019ee3..de1775ba 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/texture_compression.cpp @@ -48,6 +48,7 @@ std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& std::vector compressed(n_bytes_out); const auto result = goofy::compressDXT1(compressed.data(), data_ptr, qimage.width(), qimage.height(), qimage.width() * 4); assert(result == 0); + Q_UNUSED(result); // std::copy(data_ptr, data_ptr + n_bytes, compressed.begin()); @@ -81,6 +82,7 @@ std::vector nucleus::utils::texture_compression::to_etc1(const QImage& std::vector compressed(n_bytes_out); const auto result = goofy::compressETC1(compressed.data(), data_ptr, qimage.width(), qimage.height(), qimage.width() * 4); assert(result == 0); + Q_UNUSED(result); // std::copy(data_ptr, data_ptr + n_bytes, compressed.begin()); From 3e7902f9de7a03526f63a3ca52964046a13fafd6 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:39:24 +0100 Subject: [PATCH 17/65] remove dependency on qt svg --- CMakeLists.txt | 2 +- app/About.qml | 11 +- app/CMakeLists.txt | 43 ++++---- app/FloatingActionButtonGroup.qml | 6 +- app/Main.qml | 16 +-- app/SearchBox.qml | 2 +- app/components/FluxColor/HueWheel.qml | 2 +- app/components/PageDrawer.qml | 4 +- app/icons/icon.png | Bin 0 -> 5758 bytes app/icons/icon.svg | 56 ++-------- app/icons/icon_small.svg | 57 ++-------- app/icons/logo_type_horizontal.png | Bin 0 -> 10590 bytes app/icons/logo_type_horizontal_short.png | Bin 0 -> 8622 bytes app/icons/logo_type_vertical.png | Bin 0 -> 10407 bytes app/icons/logo_types.svg | 128 +++++++++++++++++++--- app/icons/material/3d_rotation.png | Bin 0 -> 754 bytes app/icons/material/chevron_left.png | Bin 0 -> 285 bytes app/icons/material/format_paint.png | Bin 0 -> 377 bytes app/icons/material/info.png | Bin 0 -> 660 bytes app/icons/material/location_searching.png | Bin 0 -> 908 bytes app/icons/material/map.png | Bin 0 -> 535 bytes app/icons/material/monitoring.png | Bin 0 -> 448 bytes app/icons/material/my_location.png | Bin 0 -> 938 bytes app/icons/material/navigation.png | Bin 0 -> 542 bytes app/icons/material/navigation_offset.png | Bin 0 -> 540 bytes app/icons/material/pin_drop.png | Bin 0 -> 635 bytes app/icons/material/settings.png | Bin 0 -> 739 bytes app/icons/material/visibility_off.png | Bin 0 -> 893 bytes app/icons/menu.png | Bin 0 -> 393 bytes app/icons/menu.svg | 16 +-- app/icons/needle_head_down.png | Bin 0 -> 865 bytes app/icons/needle_head_down.svg | 47 ++++---- app/icons/peak.png | Bin 0 -> 1118 bytes app/icons/peak.svg | 21 ++-- app/icons/search.png | Bin 0 -> 860 bytes app/icons/search.svg | 40 ++++--- nucleus/CMakeLists.txt | 2 +- nucleus/map_label/MapLabel.h | 2 +- nucleus/map_label/MapLabelManager.cpp | 3 +- 39 files changed, 241 insertions(+), 217 deletions(-) create mode 100644 app/icons/icon.png create mode 100644 app/icons/logo_type_horizontal.png create mode 100644 app/icons/logo_type_horizontal_short.png create mode 100644 app/icons/logo_type_vertical.png create mode 100644 app/icons/material/3d_rotation.png create mode 100644 app/icons/material/chevron_left.png create mode 100644 app/icons/material/format_paint.png create mode 100644 app/icons/material/info.png create mode 100644 app/icons/material/location_searching.png create mode 100644 app/icons/material/map.png create mode 100644 app/icons/material/monitoring.png create mode 100644 app/icons/material/my_location.png create mode 100644 app/icons/material/navigation.png create mode 100644 app/icons/material/navigation_offset.png create mode 100644 app/icons/material/pin_drop.png create mode 100644 app/icons/material/settings.png create mode 100644 app/icons/material/visibility_off.png create mode 100644 app/icons/menu.png create mode 100644 app/icons/needle_head_down.png create mode 100644 app/icons/peak.png create mode 100644 app/icons/search.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 78bb8f8e..ebcf3f90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ if (ALP_USE_LLVM_LINKER) endif() ########################################### dependencies ################################################# -find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL Network Quick QuickControls2 LinguistTools Svg) +find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL Network Quick QuickControls2 LinguistTools) if (ALP_ENABLE_DEBUG_GUI) find_package(Qt6 REQUIRED COMPONENTS Widgets Charts) endif() diff --git a/app/About.qml b/app/About.qml index fa6f6246..ec40bdd8 100644 --- a/app/About.qml +++ b/app/About.qml @@ -52,7 +52,7 @@ Rectangle { fillMode: Image.PreserveAspectFit width: 180 height: 120 - source: "icons/logo_type_vertical.svg" + source: "icons/logo_type_vertical.png" } @@ -73,11 +73,14 @@ This is an open source application. It is released under the GNU General Public The source of elevation and orthographic photo data is basemap.at, it is licensed under the Open Government Data Austria license (CC-BY 4.0). -# Authors: +## Authors: Adam Celarek, Lucas Dworschak, Gerald Kimmersdorfer, Jakob Lindner -# Impressum: -Adam Celarek
Hartmanngasse 12/22
1050 Wien
Österreich / Austria") +## Impressum: +Adam Celarek\\ +Hartmanngasse 12/22\\ +1050 Wien\\ +Österreich / Austria") } } } diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e3758b48..cfd6ce74 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -70,31 +70,30 @@ qt_add_qml_module(alpineapp components/FluxColor/WheelArea.qml RESOURCES icons/mascot.jpg - icons/menu.svg - icons/peak.svg - icons/search.svg - icons/favicon.ico - icons/icon.svg - icons/material/monitoring.svg - icons/material/3d_rotation.svg - icons/material/map.svg - icons/material/pin_drop.svg - icons/material/settings.svg - icons/material/info.svg - icons/material/format_paint.svg - icons/material/location_searching.svg - icons/material/my_location.svg - icons/material/navigation.svg - icons/material/navigation_offset.svg - icons/material/chevron_left.svg - icons/material/visibility_off.svg + icons/menu.png + icons/peak.png + icons/search.png + icons/icon.png + icons/material/monitoring.png + icons/material/3d_rotation.png + icons/material/map.png + icons/material/pin_drop.png + icons/material/settings.png + icons/material/info.png + icons/material/format_paint.png + icons/material/location_searching.png + icons/material/my_location.png + icons/material/navigation.png + icons/material/navigation_offset.png + icons/material/chevron_left.png + icons/material/visibility_off.png icons/presets/basic.png icons/presets/shaded.png icons/presets/snow.png - icons/needle_head_down.svg - icons/logo_type_horizontal.svg - icons/logo_type_vertical.svg - icons/logo_type_horizontal_short.svg + icons/needle_head_down.png + icons/logo_type_horizontal.png + icons/logo_type_vertical.png + icons/logo_type_horizontal_short.png ) diff --git a/app/FloatingActionButtonGroup.qml b/app/FloatingActionButtonGroup.qml index 1da42bf3..a3a1d626 100644 --- a/app/FloatingActionButtonGroup.qml +++ b/app/FloatingActionButtonGroup.qml @@ -60,21 +60,21 @@ ColumnLayout { FloatingActionButton { rotation: map.camera_rotation_from_north - image: "../icons/material/navigation_offset.svg" + image: "../icons/material/navigation_offset.png" onClicked: map.rotate_north() size: parent.width } FloatingActionButton { id: fab_location - image: checked ? "../icons/material/my_location.svg" : "../icons/material/location_searching.svg" + image: checked ? "../icons/material/my_location.png" : "../icons/material/location_searching.png" checkable: true size: parent.width } FloatingActionButton { id: fab_presets - image: checked ? "../icons/material/chevron_left.svg" : "../icons/material/format_paint.svg" + image: checked ? "../icons/material/chevron_left.png" : "../icons/material/format_paint.png" size: parent.width checkable: true diff --git a/app/Main.qml b/app/Main.qml index 2e606b24..ed7f7689 100644 --- a/app/Main.qml +++ b/app/Main.qml @@ -49,7 +49,7 @@ Item { height: 48 color: "#00FF0000" Image { - source: "icons/menu.svg" + source: "icons/menu.png" width: parent.width / 2 height: parent.height / 2 anchors.centerIn: parent @@ -99,19 +99,19 @@ Item { DrawerButton { bid: 0 text: qsTr ("Map") - iconSource: "../icons/material/map.svg" + iconSource: "../icons/material/map.png" onClicked: change_page("map", qsTr("Map")) } DrawerButton { text: qsTr ("Coordinates") - iconSource: "../icons/material/pin_drop.svg" + iconSource: "../icons/material/pin_drop.png" onClicked: change_page("Coordinates.qml", qsTr("Coordinates")) } DrawerButton { text: qsTr ("Settings") - iconSource: "../icons/material/settings.svg" + iconSource: "../icons/material/settings.png" onClicked: change_page("Settings.qml", qsTr("Settings")) } @@ -119,7 +119,7 @@ Item { DrawerButton { text: qsTr("Reload Shaders") - iconSource: "../icons/material/3d_rotation.svg" + iconSource: "../icons/material/3d_rotation.png" hotkey: "F6" selectable: false onClicked: map.reload_shader(); @@ -128,7 +128,7 @@ Item { DrawerButton { text: (stats_window_loader.item !== null && stats_window_loader.item.visible) ? qsTr ("Hide Statistics") : qsTr("Statistics") hotkey: "F8" - iconSource: "../icons/material/monitoring.svg" + iconSource: "../icons/material/monitoring.png" selectable: false visible: _debug_gui onClicked: toggleStatsWindow(); @@ -136,7 +136,7 @@ Item { DrawerButton { text: qsTr("Hide User Interface") - iconSource: "../icons/material/visibility_off.svg" + iconSource: "../icons/material/visibility_off.png" hotkey: "F10" selectable: false onClicked: map.hud_visible = false; @@ -148,7 +148,7 @@ Item { DrawerButton { text: qsTr ("About") - iconSource: "../icons/material/info.svg" + iconSource: "../icons/material/info.png" onClicked: change_page("About.qml", qsTr("About")) } diff --git a/app/SearchBox.qml b/app/SearchBox.qml index 518f8757..bca82050 100644 --- a/app/SearchBox.qml +++ b/app/SearchBox.qml @@ -75,7 +75,7 @@ Rectangle { } text: "" - icon.source: "icons/search.svg" + icon.source: "icons/search.png" background: Rectangle { color: "#00FFFFFF" } onClicked: { search_input.accepted() diff --git a/app/components/FluxColor/HueWheel.qml b/app/components/FluxColor/HueWheel.qml index d225db5c..0ffed5c8 100644 --- a/app/components/FluxColor/HueWheel.qml +++ b/app/components/FluxColor/HueWheel.qml @@ -33,7 +33,7 @@ WheelArea { } Image { - source: "../../icons/needle_head_down.svg" + source: "../../icons/needle_head_down.png" anchors.centerIn: hueRing anchors.verticalCenterOffset: hueRing.radius - hueRing.thickness } diff --git a/app/components/PageDrawer.qml b/app/components/PageDrawer.qml index fd033011..d7eb1de9 100644 --- a/app/components/PageDrawer.qml +++ b/app/components/PageDrawer.qml @@ -81,7 +81,7 @@ Drawer { } Image { id: logo_mark - source: "../icons/icon.svg" + source: "../icons/icon.png" sourceSize: Qt.size (64, 64) fillMode: Image.PreserveAspectFit width: banner.width * 0.16 @@ -93,7 +93,7 @@ Drawer { } Image { id: logo_type - source: "../icons/logo_type_horizontal_short.svg" + source: "../icons/logo_type_horizontal_short.png" width: banner.width * 0.65 fillMode: Image.PreserveAspectFit anchors { diff --git a/app/icons/icon.png b/app/icons/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..76c397d92b85dd70f1aaa5a77af1192df47c6a15 GIT binary patch literal 5758 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 Nb>(MDXa&o#{{ial7{CAk literal 0 HcmV?d00001 diff --git a/app/icons/icon.svg b/app/icons/icon.svg index fc44b2fa..56eef551 100644 --- a/app/icons/icon.svg +++ b/app/icons/icon.svg @@ -2,80 +2,44 @@ - + transform="matrix(0.21377203,0,0,0.21377203,-5.0744178,-5.3952963)"> + id="path4518" /> + id="path4516" /> + id="path1" /> + id="path869" /> + id="path2" /> + id="path1847" /> diff --git a/app/icons/icon_small.svg b/app/icons/icon_small.svg index 14d69f79..3085fe21 100644 --- a/app/icons/icon_small.svg +++ b/app/icons/icon_small.svg @@ -2,80 +2,45 @@ - + id="layer1" + transform="matrix(0.15999999,0,0,0.15999999,1.2155701e-6,-2.5207164)"> + id="path4518" /> + id="path4516" /> + id="path1" /> + id="path869" /> + id="path2" /> + id="path1847" /> diff --git a/app/icons/logo_type_horizontal.png b/app/icons/logo_type_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..25ff3a7e3cc9cedc51d141a560d2a8efe9f0e074 GIT binary patch literal 10590 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 ab>M2~pimo53zqhXgQKpjqf`O43i&^2f+JM` literal 0 HcmV?d00001 diff --git a/app/icons/logo_type_horizontal_short.png b/app/icons/logo_type_horizontal_short.png new file mode 100644 index 0000000000000000000000000000000000000000..dd5a40938788d4c5d5b10ff000e570f4d703ed27 GIT binary patch literal 8622 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 literal 0 HcmV?d00001 diff --git a/app/icons/logo_type_vertical.png b/app/icons/logo_type_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..1e3cd4d78ea370f5e9998bf619f2426aa6c9f17b GIT binary patch literal 10407 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%0DZN?@Ru&I63I4 zTQwbZX<*jXNSt^x8f62xdtKxboE@=$!!k-hcp4sj{$QJyuUX(Hji0>*C$&(6q+rO9Q7}uYVteiJ?^?o)pJ-G6*31;dCQ%p*jg2lK;;E$&$ z%Gs;FxO6ve3?(x_G1%sYj1wdrHXg?+J?ul5qMVN|D&S&Yk^m%Q9KoV1D_Z{uYPc-9 zEFh%ud>gIcQY#e7@-|#!7V* zyjAA)ZCuAt2z7o}fAg^DL}i-ouy?PDQ)Dg?FM)+*qs=IC=?gk(nNedg5qY1i_&vg9 zM<)~EX~$?PvB}OLi}+p+QunG0C1^6x(j@1lcTXR#{6ckA+#~icoh96E-K=yOMD0W= zsaZ#u(hcy=a-AZeT{ufDh4j4aJW~o!Q%`!z`?pQ9Kzu~~JBIIjoNJzW){C9j;466K zpG2ZdfBrAFy%S`n9?-QQcnWF%wqo(Jw=G3Zfnzwo#iHa;3w`6Xypq)K6 zPU|`IORe{}(8t>`gXI%!WcD8f=J6cdS*(W1Erg|s>z2+=iTwGh+w?3B?P5utY(CGw zJfg1Vci9Ovt_4~g-$8C359~i7ko4!A&!rF)&*bU*eis|kI(pD8#KV48+i|;e)$4u8 z8Imql68tJz&*L_bR#5b_x>nwE<>R3}+F=1lEW%~b8>eGUGgjvQL%(hSJ>}#z6IaSR zkGLhg9H|E!`b)VD3=Dj}|HJ|in9wIEdWPcs{Q)f}I#oyQ_%YiRDD}h-ok>bWxlpd| zC2;xi_goZ`&2Zmst7R;<{kqrVy`vh!H>x~<(b(8nPEDKq)wGzMmH1CqfH*d6Dt__}B$VGug@(wwrNOon~B2j)9XHM&iIdSV}4AH+D1+{3+5xJ(>Tejy@@t=2e zC(RKZD^?FYWH+j~%O8m34yzW=r17*Ps{1^fjU}&=wN%QaXFjP(%cx{aem8eOA5vi6 z%mNd-xYV2E3#jIISd1lSWAhztsc$VOoJ-PYPGFGsJf&}71j^)u+%cU@s*>!pkg+eE zcI%k*+!-RQ#^$G{){v3ly$G;ypIW68nIt3d_u46i2a>ljt%+}hV;(SvTc!zCn zGH@6yLt!bp0-U*Vq2!vJz(D(N|S1`KCD&u z*>OHK6CpbNN5q}G29RD-eOqmTrruhnA2&+)&J{@D6VCPLjrT-(P`;LQ+c(Mb;e9dN z9?jpyW^A@As~lW9Tq&Y-!ssq(l1sUhe8!Qa`n+~j_a6dOaAxm;cqz3ZV=L^i*7;2u z$8qEC4{_RVQbN7#ZTw@`6Sa(tD|E_Ub4A*N7Qx6L>a8H99!58&9540V zu?k08gZ6m>?JKrrllhZ9w^Si}iv;{}iN|e@DRG54<@V!iKih?PMI-yV+R}mP0;4C5 zwb%s6a`*k`Hx|l~r@Pcl=|W;-vZXF_a;OnBl017t5K?*kwp4sDowaRlRb=BSIi1M| zCYJ*2FtQNL7JkbF4S;Z}Jb%<$dTSAT{bqeA-p359`5(?*5smCM3_g?V?`t1K{j z zK8o8#i^R4kKgU0Uc+2SECHzpff8w@1;EJP~?-ZMVf#|b!4U2^35OVL3*>lE|wUMYF z6h+XA7bSl-fcF!ndyCzZ!CZ56ViYZ7Q={Q@vIR$8UU$L$jJK>pczSxuA)q&fTJ@_` z^C8Ouy-&iJPhu!1+mmAm!=jR6mvTU5n@=^`STY)e6ZO;?Xfi&;gJiPH*%GPyQiue- zU58)>&jL%~^Vp`G-{{nbi!IdQef{h=KWdxO*TZg8U_YRR`CmF0P;qG!6e?%0l=s?$ z@H%kh9^D30&H&7Z(G8MPwHCiwV_)6EyJ`Aks!6P^iH3Ms3Y%wr2^FWyIuM-}lh?#g z*_SS@;lbb`aolzYw~}4m4D0u-^mGM!WgZLLD^OFQ3itW>U41$4*XhiYW%d|H`a8B< zXaNW%N-tA&o!u+F^bedXRo^+C;iM?b*sX~3z~0S9VJtx^Huwd-j+~WwE#{HbdYnvZ zKwW++bvA-AXSlf*ccrcqnl38C#tM{=@5$8I{5XwosH+=2S;X!-Sz8L57Epdo|O4C1W7%QC#|_Omk{_#@c!n?d`y*2S!~rtmEv?3)>}Uo3vg5J%++ zxbwUG9tUGM3pffEuU$ylgX=0`I>m>e!NFF$K=5MaQ_fdnLP@CjFv-_E+B;?UME{|u z<=_7SggfY0g*;_sR8UI6{2!UsevdxGG?`mhha}cbToE{r%uKL-O7!)%nnr6}j1y_9 zvLeOJ`1I>D>eew}Tu~}PgFbjiGs=03CVLUnGv{}@rrJ{e=Qx-g4;swCkhH#59ZvRy zBeZo)88U5&0QDQdt2}Jz-#yagc7N9@KmKy!@sK?bNs}TE|2Kijbcpr&gymzbG(#Xo z)1P2cc*=rkl9kYrmQiJR3qAjU6p1!alua9mX1l6(i%7VUHTw0(lPY7##(twjnwZ-K z*EK7DvC~*PJJdt$2#>2Mhfz9O`lQ<)4Sqij(DrDM6K`XU;%YEs$kF{7ZTry1#xL#3 zdt?OUlp@A?Y)ns3mm=_gqviWlnF8ww#~2Xrvg)U+{+}Uv`8^L?p2 + inkscape:current-layer="layer1" + inkscape:pageshadow="2" + showgrid="false" /> + + Alpine + id="tspan1135">Alpine MapsMaps.org + id="tspan1141">.org AlpineAlpineMapsMaps.org + id="tspan1149">.org + logo mark large + logo mark small + + + + + + + + + + + + + + + + + + + + diff --git a/app/icons/material/3d_rotation.png b/app/icons/material/3d_rotation.png new file mode 100644 index 0000000000000000000000000000000000000000..5fb5b9d96cce318c47b3cbe74fe23c67bd56a3a2 GIT binary patch literal 754 zcmVXXqwMD(ufjAqBZDj)M2hxpQyVxp%JU7tZ3${ASMcn>jP*ISN(Ht-#v@BvGBi=6_;KQOnkjcSu^4RaVTBiMTUuZb$QFpuF9;!V)HCr4&#{>}x7QX>>3qmpQYN-Bg#p~hXK52JG1U2xv*ek8emoSugOrJ`coS2y zCKe;jBvxciJn3AR`Rq6GO!~==Vp-P2oess=kSXEG=S_<-tg1Dzu8V%L&2Uk6$~`VM zq86BuUF^=48qt5!Cp(p9OO2=n?#bp(y+sd_m#E!pLARd){EqZjI%S}WuPx|eo<`c4 zSa9N?4ssYPK(`e2Cu2ch)8V8^ZHTH(Ueibi@1p)hENJH&D1skRf3#f#)tld`^LfW& z1|!{8Gr`2G;9!Xc8j_kq8&Q9xiTm{IYaJzJ;9Jx`-HAY2C1qeG>R-yaK5yDIx~33P z2Hr>gn=RgZtzcc#Tvhu-f8k^uZQknIOezuU3ZWNYqJi!fJxIHmQ)^&F8#2LmGLF9* zBvReZyjla>!glY_Fd~%u_M2FhpFLKDjr&xNrlU;D{yCO$CZVkeC6m3k)iov-WKFEd z=H`pCQ?4saRD?2LY+_3&3-<5oQWdyup}bf+L((RyLV@;yu!rqx6BVIWS#MR{#0#N> z9-r$P6NFmjy8MlLs&$o#VLXyu><*O)!iqgBBxR+TC~61Qi_5qn{9Y$;R`~dL@MpIz k;|*TpV?kpdbIg(EAGXYHFc4_-jsO4v07*qoM6N<$g3Wwc%>V!Z literal 0 HcmV?d00001 diff --git a/app/icons/material/chevron_left.png b/app/icons/material/chevron_left.png new file mode 100644 index 0000000000000000000000000000000000000000..709c4abe7f8faf8de00c1e61704d537b96a2ecd6 GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC&H|6fVg?3TAX~PbvH$7ERG^?_ ziEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0wkJY5_^G8*4r+{=5&K*aUo z;rN3_COQW~0zSQn=x#EMXlR-yG|R<>OGw42tm&Nk&W%f-SATVwq~f`gr9ek^(Rv2C ztCF#u4@CFb-JaCAi{sYA^#@iZEL+dormt*JBiZ=yGzZW9^Cky-e$U=*xxvH0dbaFa z-8&7XCj(+5lQeV;MW#t~&7U@7sl=y)k~0`)AG<5GBP4(E#XCpru3nIlUU7A{1!H^9 ff3Ha@f7hyK|0(D?UE;w9bTxygtDnm{r-UW|c}{Og literal 0 HcmV?d00001 diff --git a/app/icons/material/format_paint.png b/app/icons/material/format_paint.png new file mode 100644 index 0000000000000000000000000000000000000000..9cc2202e26e0c6fb9003ec54da7212581f771368 GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC&H|6fVg?3TAX~PbvH$7ERG^?_ ziEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$QVa}?Y@RNTAsLNtryKG$IS9DU zKNfJaf@A9wwL5(467wHfJ`sviSbNclTiG$~gpTl|JuPh;cK=VE{zRX}QQ%Ckj7FpJ z1*ZNZ{gRRajNdt(W^<<;D17u_8Pn9@3gN~%?>4S%WQyQE_MP?8K6zhH^FMBe_hJ|P zo3$aJuUvdbt*?fq*?bkz2oC0q;~p<&hi|=iNux(v@xj?sg}IaKU+R}1STjGu;I}LX zW4_aY*#aNjlrE_GU-UQr(&+LaMIc2-E&F|=_T~6z`UkE#F(k0dRODv9dT_Q{H?U&$ zZP6FjL0bYj80*10j|Dkgp2=q2C*sZMoB#1m_+Ag|$(hGDJ_}C|DxIUikz&IbTFt|3 TEql`j7;Frlu6{1-oD!Mn||h|c&K+)Vrd3}~WZHYTzYMn4l} z5)&N=4!w(}^z^PR<%m4VyA-Z{-dwNOz6TQ~{BNc#^^*XKKnYj_R)Ixe*89B+JOeGD z2{eFfpl4}(ZI*#u;1TFYj0f-9ymM<{0XPIcL(2XZpTGf-btS(AbS#L=@#^(GG-iO4 zA&ARS1yZ)JH`oxB}8P5^ynXg5uazertsCew20Pv%pIX66he7 z?Z_M&4qO9rUepZx+K(!~jQL9{_oKfh!@fQUcwd&H*kPc|$JHmoShvZ^Um3X|oC*pwSo2^1WN=rZ7@N?^r-h%N(eNyVQQEe$50 z_WBn39B@!~5@fD7OS~hxxum#3tSXjs)3a+l?>sT!A`lJxGN*B|{ zdU^dPWrnjlywcfJ6Y-Qf1od07?!0000s5 literal 0 HcmV?d00001 diff --git a/app/icons/material/location_searching.png b/app/icons/material/location_searching.png new file mode 100644 index 0000000000000000000000000000000000000000..94c2dc8733d1b3be2a5e359595fcecde872b3ea7 GIT binary patch literal 908 zcmV;719SX|P)+pspkm?&9u3TH2r$ z>Qsk%(efS#Ne?Qdnidy&(5OCjn0?K@-<#dHyEFS<#QP?5`0dVozu(#Y&Fsu9R8U@2 z#mN0i#O-m2#My!6QfO7jL0U@u^Bq`ik*gl)1ok>bVhG3pX5g+SM~!1l_XI}>_o3PcJoDfhbF{3Y8W_}w&7lTyR2&1o zXn5~qd5XWT5qS%2w!q!ua7q4a7PtYG8d*V}2I_1HI9zF=u>`c45?2E$K|BjIn-Xi# z2z(Y=;~1vWX$oKMVI!OV=+x+)G9i2-$Og>(1;PWN`8X<36DkjLL|LHKg27^F1^$pf z78;`vU7#=@ON9xcecr30-vE&_z$0^CfiWy%&)LYY1A9dLJhGke7!|Q+2i*IC6tK}1 z%a7EYnWs>g6>&Q-<%+)o2W6uf{8x;%aX9tBx*}d?auvgTB(fF_7Q<4|ieWm?5Wz@P zB!gCTkAV(gl`9?scDmvQ;G>bP;E)gN9dN=GuVjO}1D`~r3GzFzA9!iQT>u;q@i_27 zSJ5wpG9vCaaTF3=B2Gsk*+u@y|3zuWK@zn`c56po!i)=|n-&Zf!!4niG9kMp$QFTZ zh6eqxox-Po(S$I88a!^o46xS7rni<{#7zNfOo>lY_$3^~?xwp6=+o%P!5kR_8uC8u z9DmdR{Tlv$3*0NHrEt@|jC$oJClf8GA0d+WH8G@V6ELk2`-wVsSs#L{9=PGOm3-5V zRxD^ne}=OR{6MAESzrrlQ09)Z+9f;P zsP$72bHJ;eLJ&J(r3WneO(S$CNPdNF+JHhbLx97p|LY6CWj`?IK-EDbybUf2+= i{AMjTDjlfcf5%@3vtY(Tn|~9pY)#Tz zW~knLbT2jio1XK>zmwPRE`DceynSanN0Y*elWz^L+aHzM_Cad%kIwtauMRn{N#b<> zal271;y|^`qxi!y3G(@d(^uBApZ?Kxui@Fb9m}471pd0#94YKR z7uor;x}rJ%(z<67`Llv+j(NpbOX+VkfAlM78+Y$Fw~A-{enzF6E%kXmFudMnz4H-6 z?4B2bWY;!p6`mXKkI06nCoIO{%oa<;FkKh6`Txc@K2FfW3~2rnVeIXec-Z+dwo^jlv^7!x2cOJ_-kb>UwWv_Rja_CyVq>) z9jSNISS+#y?WV2za8xlneTi3X_`h}X9-;qgI$t`LvAI-VT6%a>3FpMab4qS*T)+2? z?G!y$s^7Kh2^Aq9`Pqv8L3?PULh7vTIN1=%PvWxCWM;Bp0t7)2 z1Tr)_fCmEbH9ABsgrD$J79jkEpRNGmG5k~o2>-+1_B6jb^?CSD0I%L)R`Z$?_xhpX zYf5nXq2VnhIQ>(E*OcJ&L&M*GKlyVq=$EdkH_X$?9RYkW>sO_|6_h!sKPuaFQL&lDL~9dwR1X^(CXa< zh}pzDrx%0XUBEi(axMn1H-*0$>$KqXXNAwYp>I;4c21|~?;9Q~WWB3^XHMU*otX6% zdVN&^=?5zr^j;T{ro~efI0zxP$T!XR>b(vCcwwVWgth?n4AC3HnD2P=yU^YNo8N`@ q4(Ogjqo+(vp(&WYKoA7MSiS+o$!ieTb&%Hp0000{F6FNPxZg5dTP3>yI~JIi+ve#e>a{BSs2MO zfQ@F@+Mfk!GqLLfXbH$w0ImRiT1O(d>LpDz}>F7O#a6K zxB<9mAukhlgmT1#sG?@NhR{NMs$2yQHcD(k8!9DhZGAzlHK{RZ5U!J)^S!_WU>W$U zWf>R&PA2s2BmQF#r1Tw7D{L*w-zb-jNBig{g?-b329RJ zT`$2-Zz-!nd)?#H}x8`;I+_x)Oem{ zyKf!Q3)dHzH=fT4dSl3`;KI7@YlCTPP9pIM;F_Sf06cW?NEih^3-7KP&td>BW1F!S$@p~6_9dcqVg|T_T1mUvI$G@3 zZFhn9$VZE%ES-;#LmfK#9H%Eq6_xYB)5e8h($ M07*qoM6N<$f@AuhH2?qr literal 0 HcmV?d00001 diff --git a/app/icons/material/navigation.png b/app/icons/material/navigation.png new file mode 100644 index 0000000000000000000000000000000000000000..67d733fa3a7a0ee68978d4d241b964e746124780 GIT binary patch literal 542 zcmV+(0^$9MP)mK7$-+VJSBL z1ugat@#Jo1?`FIO?*~(6W;eUpPZ8+T=YMD5+JOkjC?{B}TjBurr&n~|g zU(`;A>r&^6>J40XxGq&DR4=}$&CXV*$P9S{$--8^C2hbIHp^$UfJ;h}u$AGG$_zHE z6DY$aB`Mgd;F2mM5!mYBk}3(<>fn;9bJ#R+B@LSfu4G};!sQBEn`cxDmy}Lmi-pS# zwx%Z#3zw8Xg{>)E$-veIt|VY<1D90puvx$*l`Cu(a7pC`+ZY?Tq>6$q<{7nuONt9@ z)^JIshE00{v2eW+elOd=25=6%M10;9wivh`fK$Ss8s)42Q{Yb7E5qo@YT&vdoYIn_ z-;e;-rJ}D1Y*lc*5}v%R7QNSjGvK*mh6!xbQq#I?(lk}q>)2|*2`~rt2v@)>!+gd( gpV_BRpFWA_3keUjXvdWh0ssI207*qoM6N<$f}N4<7XSbN literal 0 HcmV?d00001 diff --git a/app/icons/material/navigation_offset.png b/app/icons/material/navigation_offset.png new file mode 100644 index 0000000000000000000000000000000000000000..a1bf0f7ba14284a93b8f24f6f1abaf6cf9c4c88f GIT binary patch literal 540 zcmV+%0^|LOP)JQn0bGOsS<;&?6*A@Bk9=4Dvt=OR@1U zXt8;SPhMvBy&2yY`-3U7Gn?J)r$`UqjDU6E!MTrHrog1@A)00gd;p)ohF6m%uZ4jV zU>WEE$BunmG60@{uX#NKs~(NKPT+{&0}p^hr(Wji0eAd-`(+h`E0uiq`8#}BdmYZD z&NcNLxan{%RYuegU)FYK(k literal 0 HcmV?d00001 diff --git a/app/icons/material/pin_drop.png b/app/icons/material/pin_drop.png new file mode 100644 index 0000000000000000000000000000000000000000..888b8f8d9fc7224afe023cde0e5205d8f73237ec GIT binary patch literal 635 zcmV->0)+jEP)7N&?c7Ajh(g@tyun&2aiE~t&Aih>A&ot@}65Ul(t79t6l zAY!B7ql?5>&?Y`uA6bi?h26OB-n%<@MsWUcnw`7n{LjptnLC$?ivOE6Ip(V2AdcWL zwqt8{>>Xa?KJH;2D>>F4i5kw}DVl-t3Ky}y1m7<9;E8bY)$t7b3b)QUh2;T)A+en0 zDwHWSMilRi@0c!1{s2DbDBpP{_NSJwVJ?AuJ04{5wT^E`#rhyNE$9 zf=|+&{f~M-0CMG0!Uis+mZvrCLf1txF(cn?p1$nRda>m>b#@gc-)0g&Mig)2r$o!= z5UvCW4vNc#Td(4p;pMNF;M&@gPo-7LmRcBx24%;Kq;%%V3zZb`SYi=b+tqN1W)egkC) V4xD@0Y%c%+002ovPDHLkV1kJ|D_H;l literal 0 HcmV?d00001 diff --git a/app/icons/material/settings.png b/app/icons/material/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..bb6bd1d85a8b403663b0c0a7618eb5bb78dc4599 GIT binary patch literal 739 zcmV<90v!E`P)vkvKs1+#76H9Ru?mM4=0Lbg!Nw-Nxmr*`ND+t#cBv9jV<2|1 zwT%{HZ(*q^A~B>47m3CMGhSl1$u*&1 zw$(7ZZ*38{PxQvEdVy)&{{zojI7P!=+%sm_*ZeVHsZH`tU>3LytSZdgs2j$tVYWVB zG9J`=;9)LQjBCvg0N*oEz$S23Q^1Q1n71+KYQ6$AGGN?B1Gp+RUjW`^z;tW8N4V_Q zJQLN4KK?Rr9OwZq0C#A=qPavZ$^0Q;#UsHh;&<31MC-qnzhXSbs-i674bYtgH+rlz zUlH;-1Cnt3QW5Bi`fu=#ZCE#uw4_ylWj;ewpt|_?v0`pZL z<9n5~C!AMuzs4{d5`B@fzrh;U5KNJopO;rc=!$ zK@(U59s-xyJNhfA z{tJqesMUA|3b?B^53-A`x`(+{!*~vCwR!%5Xw&mj($!)SU7I+~{`RvE7-jzpyY6e= zD(P~!tSF$|fmHx*0*?ZD7b&&t^^i*C2ab>p&9cMT&!Lj0Re;ObSRMERa^?Ep^#^*k VM^a&*?PmZ0002ovPDHLkV1k5`N6`QP literal 0 HcmV?d00001 diff --git a/app/icons/material/visibility_off.png b/app/icons/material/visibility_off.png new file mode 100644 index 0000000000000000000000000000000000000000..538eea3c30b513533fd19efcd080a553be18ea5d GIT binary patch literal 893 zcmV-@1A_dCP)0r6_`K+-0F4iVOdRxN}`sf-VKu z72HTcYODA_w2KNw1Q7%uP4NY#XyW2b$Yi*anR93IlKkL6lDTuv`EoP&o_hivb=1*+ zsi9^k5Jjhe4d6zz6S2`bU=t`g*76Vu*XwP-J7B;w<~ooM@Y4qz1C9X0z%HN{NCJO= zf@9x+*T53+6!;V=dxOS+H7YYuHa~z9z(XfV?>%Ac6>tSe#R)M1tcQfy3B0jP-fh2t zn?O%o5aY;{djpxCi5>|X=6!~t;__+bc=H;nBgo|!1yBcMMHh^!Apy=S5X zd;|_f1(-s9pQZqL!}vbn9&i=d3v>fr$f}eB?gK>y#BX56Hu;l|gIWPh5JAcSD@us0 zHpme0J!AkIh%_*-fG7a_!#Ym^ZxzmKL5u+BeS)Xa&BQ9Q*#_#4GWl8%Y2cZ2eG%B> zxt>AyOw0x)e^lvE3$X_5_FSJ+_%9+0i%|(+IYRPbA(lMXa!UWt{Q%BbBzqC_G8+VO z!1ei{Mcio+p9^! zSFvg2co`f9Yz>1TESK0^rNkE+U!1gczAhnC>MCNDnF+ik{P0r-MfIRFf zWeF~)y)%)C2+@r!k?wIDNb|r-GfIdea%jmRhnOy8v%BCk-UN}PvL~%aNxrNx;DZ7} zYkm-SfqhYvFRLFpXg3lfb|sLX#^*XgG^~x;gX|SQ>j05&6a>h!cNu99+9dmz>PE5^ zgl|ou)Bv(0PXePzd!?63t8mS+F9`4=vgVHf52#eNWrb-dw~VrwJ0LCJ+IMS$@V(fU z)dc3&ep^9|BY%RlHH2vb# zpLGf`GBE7f$Zfp4a`gt|mwH9)6&74S^>bfO{oNYWwMnOVa&o2w+pAsYEYkS}jvFq` ztg5;qczMa+=YM{Fxbl#vn*Cet^4!}sTP36|9Q8lm4dghW{czfk)6uPS @@ -40,7 +40,7 @@ id="layer1"> + transform="matrix(0.72251722,0,0,0.72251722,0.43972448,-0.43847892)"> 8NZSic zPEJ|{9=IuR1Na0;E|+Ut_~YYaQA!E$8MxUfV8EupFW?El^768qLA1o;;vymfkN|$V zUGJ7s>O2?>N}*8DKK){`D4|eDlu|!{+jimX?f}4d5qVZBl~`L_b2|)MR#sLpO%oA$ z3Vicw-Mhf={{DV33`5)WP1BTcI4nRJ81O2*#V#PpWKvs!&CN|)ak*g(kio%0DVNJy z3JebqTLngS6aaV+NG6lQSOuna7SJNLR>W0HGq2HV zF2t5dBwD<*K1)kWo{GzkJ}<>qEEc7wr>ALg)za!6063M3*w)wA9bEn|tE;ORhT*xm z?C?Zvy2WM39w4by%5i~YGHJbecH12uU>uO4p&`d&s}k3k9|Zu80Lf;vEr-u!GFJGH zH2$>J$}AwUSghp&(P-2vFymKvsEAD|B_}5*O^46t^Nz)(g9Sk1@p#h(=H}+C=|A#0 zJJ6!oYQ%NN?dDEIR?De~Ja1NPRpQzPzIw2~C)}e6vDJv{zR#Jjun)-A)>hpDsZ`2( z_V;|w`d=on5!=Yfh*eHro;6vSSvIsi~Ur<6Jmg+fv&6spB#;DNYmx$gCX z{1w{^(=;D$Y-}JR7={6`O$Uj~jsc(?4u^gH;&RJNF8|}&_c@CrCb%px;d2(p9HCiU r*K{php#;1EK4{)Y8^Oxar5=9(r=wIav_sQX00000NkvXXu0mjf$cT)3 literal 0 HcmV?d00001 diff --git a/app/icons/needle_head_down.svg b/app/icons/needle_head_down.svg index 642af535..816a2825 100644 --- a/app/icons/needle_head_down.svg +++ b/app/icons/needle_head_down.svg @@ -1,19 +1,19 @@ + inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)" + sodipodi:docname="needle_head_down.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + fit-margin-bottom="0" + inkscape:pagecheckerboard="0"> image/svg+xml - @@ -64,14 +64,9 @@ id="layer1" transform="translate(-1.5875,-2.1166667)"> - diff --git a/app/icons/peak.png b/app/icons/peak.png new file mode 100644 index 0000000000000000000000000000000000000000..153831c1ff2a0eeb9a298bf9ca4108bbeb8c9e8a GIT binary patch literal 1118 zcmV-k1flzhP)YA+V=zVn53WNB+WTJ_kB-$ z?z^Y2(4v_Zh5H760cw`zHAB4)HOf@exq>#cYt<}G}h%k8jCO6O^-C1 z@)S@&5UT5XQP*`@0fkb|g+KwmK@h1ZN^yC4xwx{jQdCt{R>b#!>h|Ifxm^Hw6_^#B z6B84Rj*b!zhdDkzW_x>Ee9NQ2F7Sh!iz{xDfiUnZ5UF&ALLqXw9PRDKUd`w8q*5vN z_xHv8LqG@qa4NvC1kqO;Bhm14HhfpOXT^{~@I8t@as zOs{Dgxm=D&q~>l~m&3zDQmGUtCnsX)4sZpi3COUsiEjWeiOzI7O?R^6u+ zMIn>PpsLQ#LRD2+TwIi`;R8O!LW^5zq3gh+=u9LMjE#+1(OH*BB*M|r5j#6OV(2n( z8~CwaexnLQ7{l5lmClZi4mLJ6s^%Rx|W7w;i0?Rb|{@+Cq4=_7B zdv4;vxRcGy%*aAv;O%<3^$K_fm=c{mJw3$Z=l`H>WMqWi-d##ixL13r^w1p)z9S69zXpcPtL zOrOSo1bl_jQdPW#^(Sjy+YM2CH*o&~2(xN`0Z&vG@Z|*%W!Ju@bQisP0mL}9s|v8h kgZo$L?_LXN(!^{20h<@7+xwqPApigX07*qoM6N<$g4%ld3IG5A literal 0 HcmV?d00001 diff --git a/app/icons/peak.svg b/app/icons/peak.svg index 4a222fb2..70c4cab8 100644 --- a/app/icons/peak.svg +++ b/app/icons/peak.svg @@ -2,9 +2,9 @@ + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-page="true" /> diff --git a/app/icons/search.png b/app/icons/search.png new file mode 100644 index 0000000000000000000000000000000000000000..4e94e8a5bba9c694834da6743076151157c4c9d6 GIT binary patch literal 860 zcmV-i1Ec(jP)gps6-Nl3YA5flh5Y@>^og18d@04WI} zLbP_dFi_jrCKp9f5N=Etp-|J0A(|8^v}c^TEzTXfb3M;9&#!xL!hOTpoZ)=FpYOTP z^S$5i9R>^-a9=Z2v)(d1fVrA=yTS-|;{#mAG@7k7g-dt`JJf$sl^Di8!DKV%`l)rM z?}+&1#T;E|`&t1289e*!kFwdICOFj1PHQ~jqYJPqtnCO-HXJy~~w>W^U7{e3T zj>EW;ac&B0yKR06uBI6H8LuvKzJa%JGezUGuDEVvUrOLhc)Wnl)A%t(Ygdha7ceB; za%aF_Fj_+I8T=K|`>GDJF(x9xnnE=y%b|$goG!f!M{acq$U8DKu$i`6!}y2ai-Sn#DJffC*kKq4j1&tBH^6Fq+2Bl%O~8asi#aLZyja z#`^l~#yKAe+{9fR$Lfr;PYO4jHWR#C)m)ywW~J~brOmPlF5*j}nk>P%@aerEeUNWr zKTZ_zTbhmdQ+*?4dnfvy>~dZk>+pR|raK?SbE=i++&qd?t)NAX-^Tm+BXT|wE~o1= z@;saHNz2q?#%~EpkGIZl7ACXVND{weOA#Ygh7))guV9+kx8NJyok@;+pO&r z2KwQS{aMUl56)Kf)^+ws|E*~bNBZWh00*TfF^dn?)53R^W73Plj4;8i>YKY9G=zeX zh$oTYLf_owWCUMGPvU0(tmS99@H1v-5(!TB(N`fxh4MS&Kl9hHqMxRUvH?E`FZOAn mnY{04_#gZ`YQTU2J>Xx)iGl^(oX*Pt0000 - - + + + + diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index 702dc918..926b8486 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -105,7 +105,7 @@ qt_add_library(nucleus STATIC ) target_include_directories(nucleus PRIVATE . PUBLIC ${CMAKE_SOURCE_DIR}) -target_link_libraries(nucleus PUBLIC radix Qt::Core Qt::Gui Qt::Network Qt::Svg fmt::fmt zppbits tl_expected nucleus_version stb_slim goofy_tc) +target_link_libraries(nucleus PUBLIC radix Qt::Core Qt::Gui Qt::Network fmt::fmt zppbits tl_expected nucleus_version stb_slim goofy_tc) if (EMSCRIPTEN) target_compile_options(nucleus PUBLIC -msimd128 -msse2 -Wno-dollar-in-identifier-extension) diff --git a/nucleus/map_label/MapLabel.h b/nucleus/map_label/MapLabel.h index 3d3559e7..32d745da 100644 --- a/nucleus/map_label/MapLabel.h +++ b/nucleus/map_label/MapLabel.h @@ -55,7 +55,7 @@ class MapLabel { void init(const std::unordered_map& character_data, const stbtt_fontinfo* fontinfo, const float uv_width_norm); constexpr static float font_size = 60.0f; - constexpr static glm::vec2 icon_size = glm::vec2(50.0f); + constexpr static glm::vec2 icon_size = glm::vec2(48.0f); const std::vector& vertex_data() const; diff --git a/nucleus/map_label/MapLabelManager.cpp b/nucleus/map_label/MapLabelManager.cpp index 535b7161..97b53065 100644 --- a/nucleus/map_label/MapLabelManager.cpp +++ b/nucleus/map_label/MapLabelManager.cpp @@ -99,8 +99,7 @@ void MapLabelManager::init() label.init(m_char_data, &m_fontinfo, uv_width_norm); } - // paint svg icon into the an image of appropriate size - m_icon = QIcon(QString(":/qt/qml/app/icons/peak.svg")).pixmap(QSize(MapLabel::icon_size.x, MapLabel::icon_size.y)).toImage(); + m_icon = QImage(":/qt/qml/app/icons/peak.png"); } Raster MapLabelManager::make_font_raster() From 8113361a2650d9307729ffe6ea02a285ef836a30 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:57:09 +0100 Subject: [PATCH 18/65] use embed file instead of qrc for webassembly (time until first tile load 2.2s->1.6s) --- app/About.qml | 6 +- app/CMakeLists.txt | 130 ++++++++++++++++---------- app/FloatingActionButtonGroup.qml | 12 +-- app/HotReloader.cpp | 6 ++ app/Main.qml | 20 ++-- app/SearchBox.qml | 2 +- app/components/FluxColor/HueWheel.qml | 2 +- app/components/PageDrawer.qml | 4 +- app/main.cpp | 61 +++++++----- app/main_loader.qml | 4 +- nucleus/CMakeLists.txt | 23 ++++- nucleus/Controller.cpp | 2 +- nucleus/map_label/MapLabelManager.cpp | 8 +- plain_renderer/CMakeLists.txt | 5 - unittests/nucleus/CMakeLists.txt | 5 - 15 files changed, 174 insertions(+), 116 deletions(-) diff --git a/app/About.qml b/app/About.qml index ec40bdd8..646fe4db 100644 --- a/app/About.qml +++ b/app/About.qml @@ -39,7 +39,7 @@ Rectangle { width: logo.width + logo_type.width + 20 color: "#00FFFFFF" height: about_text.implicitHeight + logo.height + 20 - Image { id: logo; width: 120; height: 120; source: "icons/mascot.jpg" } + Image { id: logo; width: 120; height: 120; source: _r + "icons/mascot.jpg" } Image { id: logo_type anchors { @@ -52,7 +52,7 @@ Rectangle { fillMode: Image.PreserveAspectFit width: 180 height: 120 - source: "icons/logo_type_vertical.png" + source: _r + "icons/logo_type_vertical.png" } @@ -68,7 +68,7 @@ Rectangle { onLinkActivated: Qt.openUrlExternally(link) textFormat: Text.MarkdownText text: qsTr(" -This is an open source application. It is released under the GNU General Public License (version 3 or any later version). The source code is available on [github.com/AlpineMapsOrg/renderer](https://github.com/AlpineMapsOrg/renderer). +This is an open source application. It is **released** under the GNU General Public License (version 3 or any later version). The source code is available on [github.com/AlpineMapsOrg/renderer](https://github.com/AlpineMapsOrg/renderer). The source of elevation and orthographic photo data is basemap.at, it is licensed under the Open Government Data Austria license (CC-BY 4.0). diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index cfd6ce74..c8f2fe96 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -69,65 +69,93 @@ qt_add_qml_module(alpineapp components/FluxColor/HueWheel.qml components/FluxColor/WheelArea.qml RESOURCES - icons/mascot.jpg - icons/menu.png - icons/peak.png - icons/search.png - icons/icon.png - icons/material/monitoring.png - icons/material/3d_rotation.png - icons/material/map.png - icons/material/pin_drop.png - icons/material/settings.png - icons/material/info.png - icons/material/format_paint.png - icons/material/location_searching.png - icons/material/my_location.png - icons/material/navigation.png - icons/material/navigation_offset.png - icons/material/chevron_left.png - icons/material/visibility_off.png - icons/presets/basic.png - icons/presets/shaded.png - icons/presets/snow.png - icons/needle_head_down.png - icons/logo_type_horizontal.png - icons/logo_type_vertical.png - icons/logo_type_horizontal_short.png - ) -qt_add_resources(alpineapp "height_data" - PREFIX "/map" - BASE ${renderer_static_data_SOURCE_DIR} - FILES ${renderer_static_data_SOURCE_DIR}/height_data.atb -) +if (NOT EMSCRIPTEN) + qt_add_resources(alpineapp "icons" + PREFIX "/" + FILES + icons/favicon.ico + icons/mascot.jpg + icons/menu.png + icons/peak.png + icons/search.png + icons/icon.png + icons/material/monitoring.png + icons/material/3d_rotation.png + icons/material/map.png + icons/material/pin_drop.png + icons/material/settings.png + icons/material/info.png + icons/material/format_paint.png + icons/material/location_searching.png + icons/material/my_location.png + icons/material/navigation.png + icons/material/navigation_offset.png + icons/material/chevron_left.png + icons/material/visibility_off.png + icons/presets/basic.png + icons/presets/shaded.png + icons/presets/snow.png + icons/needle_head_down.png + icons/logo_type_horizontal.png + icons/logo_type_vertical.png + icons/logo_type_horizontal_short.png + ) + qt_add_resources(alpineapp "fonts" + BASE ${alpineapp_fonts_SOURCE_DIR}/SourceSans/ + PREFIX "/fonts" + FILES + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-BlackIt.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-BoldIt.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-ExtraLightIt.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-It.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Light.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Medium.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-SemiboldIt.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Black.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Bold.ttf # already importet by nucleus + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-ExtraLight.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-LightIt.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-MediumIt.ttf + ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Regular.ttf + # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Semibold.ttf + ) +else() + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/mascot.jpg@/icons/mascot.jpg") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/menu.png@icons/menu.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/peak.png@icons/peak.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/search.png@icons/search.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/icon.png@icons/icon.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/monitoring.png@icons/material/monitoring.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/3d_rotation.png@icons/material/3d_rotation.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/map.png@icons/material/map.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/pin_drop.png@icons/material/pin_drop.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/settings.png@icons/material/settings.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/info.png@icons/material/info.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/format_paint.png@icons/material/format_paint.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/location_searching.png@icons/material/location_searching.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/my_location.png@icons/material/my_location.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/navigation.png@icons/material/navigation.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/navigation_offset.png@icons/material/navigation_offset.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/chevron_left.png@icons/material/chevron_left.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/visibility_off.png@icons/material/visibility_off.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/presets/basic.png@icons/presets/basic.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/presets/shaded.png@icons/presets/shaded.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/presets/snow.png@icons/presets/snow.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/needle_head_down.png@icons/needle_head_down.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/logo_type_horizontal.png@icons/logo_type_horizontal.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/logo_type_vertical.png@icons/logo_type_vertical.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/logo_type_horizontal_short.png@icons/logo_type_horizontal_short.png") + target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Regular.ttf@/fonts/SourceSans3-Regular.ttf") + # target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-ExtraLight.ttf@/fonts/SourceSans3-ExtraLight.ttf") +endif() qt_add_translations(alpineapp TS_FILES i18n/de.ts i18n/en.ts ) -qt_add_resources(alpineapp "fonts" - BASE ${alpineapp_fonts_SOURCE_DIR}/SourceSans/ - PREFIX "/fonts" - FILES - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-BlackIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-BoldIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-ExtraLightIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-It.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Light.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Medium.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-SemiboldIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Black.ttf - ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Bold.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-ExtraLight.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-LightIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-MediumIt.ttf - ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Regular.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Semibold.ttf -) - set_target_properties(alpineapp PROPERTIES QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android diff --git a/app/FloatingActionButtonGroup.qml b/app/FloatingActionButtonGroup.qml index a3a1d626..088dcd1b 100644 --- a/app/FloatingActionButtonGroup.qml +++ b/app/FloatingActionButtonGroup.qml @@ -60,21 +60,21 @@ ColumnLayout { FloatingActionButton { rotation: map.camera_rotation_from_north - image: "../icons/material/navigation_offset.png" + image: _r + "icons/material/navigation_offset.png" onClicked: map.rotate_north() size: parent.width } FloatingActionButton { id: fab_location - image: checked ? "../icons/material/my_location.png" : "../icons/material/location_searching.png" + image: _r + "icons/material/" + (checked ? "my_location.png" : "location_searching.png") checkable: true size: parent.width } FloatingActionButton { id: fab_presets - image: checked ? "../icons/material/chevron_left.png" : "../icons/material/format_paint.png" + image: _r + "icons/material/" + (checked ? "chevron_left.png" : "format_paint.png") size: parent.width checkable: true @@ -94,7 +94,7 @@ ColumnLayout { height: parent.height FloatingActionButton { - image: "../icons/presets/basic.png" + image: _r + "icons/presets/basic.png" onClicked: map.set_gl_preset("AAABIHjaY2BgYLL_wAAGGPRhY2EHEP303YEDIPrZPr0FQHr_EU-HBAYEwKn_5syZIPX2DxgEGLDQcP0_ILQDBwMKcHBgwAoc7KC0CJTuhyh0yGRAoeHueIBK4wAKQMwIxXAAAFQuIIw") size: parent.height image_size: 42 @@ -105,7 +105,7 @@ ColumnLayout { } FloatingActionButton { - image: "../icons/presets/shaded.png" + image: _r + "icons/presets/shaded.png" onClicked: map.set_gl_preset("AAABIHjaY2BgYLL_wAAGGPRhY2EHEP1s0rwEMG32D0TvPxS4yIEBAXDqvzlz5gIQ_YBBgAELDdf_A0I7cDCgAAcHBqzAwQ5Ki0DpfohCh0wGFBrujgeoNBAwQjEyXwFNHEwDAMaIIAM") size: parent.height image_size: 42 @@ -116,7 +116,7 @@ ColumnLayout { } FloatingActionButton { - image: "../icons/presets/snow.png" + image: _r + "icons/presets/snow.png" onClicked: map.set_gl_preset("AAABIHjaY2BgYLL_wAAGGPRhY2EHEP1s0rwEMG32D0TvPxS4yIEBAXDqvzlz5gIQ_YBBgAELDdf_A0I7cDCgAAcHVPPg4nZQWgRK90MUOmQyoNBwdzxApYGAEYqR-Qpo4mAaAFhrITI") size: parent.height image_size: 42 diff --git a/app/HotReloader.cpp b/app/HotReloader.cpp index 9a0a0472..fd900d96 100644 --- a/app/HotReloader.cpp +++ b/app/HotReloader.cpp @@ -26,6 +26,7 @@ HotReloader::HotReloader(QQmlApplicationEngine* engine, QString directory, QObje : QObject { parent } , m_engine(engine) { +#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) m_watcher = new QFileSystemWatcher(this); directory.replace("file:/", ""); m_watcher->addPath(directory); @@ -41,9 +42,14 @@ HotReloader::HotReloader(QQmlApplicationEngine* engine, QString directory, QObje qDebug("path updated: %s", path.toStdString().c_str()); emit watched_source_changed(); }); +#else + Q_UNUSED(directory); +#endif } void HotReloader::clear_cache() { +#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) m_engine->clearComponentCache(); +#endif } diff --git a/app/Main.qml b/app/Main.qml index ed7f7689..7e34d6a3 100644 --- a/app/Main.qml +++ b/app/Main.qml @@ -49,7 +49,7 @@ Item { height: 48 color: "#00FF0000" Image { - source: "icons/menu.png" + source: _r + "icons/menu.png" width: parent.width / 2 height: parent.height / 2 anchors.centerIn: parent @@ -99,19 +99,19 @@ Item { DrawerButton { bid: 0 text: qsTr ("Map") - iconSource: "../icons/material/map.png" + iconSource: _r + "icons/material/map.png" onClicked: change_page("map", qsTr("Map")) } DrawerButton { text: qsTr ("Coordinates") - iconSource: "../icons/material/pin_drop.png" + iconSource: _r + "icons/material/pin_drop.png" onClicked: change_page("Coordinates.qml", qsTr("Coordinates")) } DrawerButton { text: qsTr ("Settings") - iconSource: "../icons/material/settings.png" + iconSource: _r + "icons/material/settings.png" onClicked: change_page("Settings.qml", qsTr("Settings")) } @@ -119,7 +119,7 @@ Item { DrawerButton { text: qsTr("Reload Shaders") - iconSource: "../icons/material/3d_rotation.png" + iconSource: _r + "icons/material/3d_rotation.png" hotkey: "F6" selectable: false onClicked: map.reload_shader(); @@ -128,7 +128,7 @@ Item { DrawerButton { text: (stats_window_loader.item !== null && stats_window_loader.item.visible) ? qsTr ("Hide Statistics") : qsTr("Statistics") hotkey: "F8" - iconSource: "../icons/material/monitoring.png" + iconSource: _r + "icons/material/monitoring.png" selectable: false visible: _debug_gui onClicked: toggleStatsWindow(); @@ -136,7 +136,7 @@ Item { DrawerButton { text: qsTr("Hide User Interface") - iconSource: "../icons/material/visibility_off.png" + iconSource: _r + "icons/material/visibility_off.png" hotkey: "F10" selectable: false onClicked: map.hud_visible = false; @@ -148,7 +148,7 @@ Item { DrawerButton { text: qsTr ("About") - iconSource: "../icons/material/info.png" + iconSource: _r + "icons/material/info.png" onClicked: change_page("About.qml", qsTr("About")) } @@ -167,9 +167,9 @@ Item { return } if (main_stack_view.depth === 1) - main_stack_view.push(_qmlPath + source) + main_stack_view.push(source) else - main_stack_view.replace(_qmlPath + source) + main_stack_view.replace(source) main_stack_view.selectedPage = selectedPage page_title.visible = true search.visible = false diff --git a/app/SearchBox.qml b/app/SearchBox.qml index bca82050..50bcb7f7 100644 --- a/app/SearchBox.qml +++ b/app/SearchBox.qml @@ -75,7 +75,7 @@ Rectangle { } text: "" - icon.source: "icons/search.png" + icon.source: _r + "icons/search.png" background: Rectangle { color: "#00FFFFFF" } onClicked: { search_input.accepted() diff --git a/app/components/FluxColor/HueWheel.qml b/app/components/FluxColor/HueWheel.qml index 0ffed5c8..09a87288 100644 --- a/app/components/FluxColor/HueWheel.qml +++ b/app/components/FluxColor/HueWheel.qml @@ -33,7 +33,7 @@ WheelArea { } Image { - source: "../../icons/needle_head_down.png" + source: _r + "icons/needle_head_down.png" anchors.centerIn: hueRing anchors.verticalCenterOffset: hueRing.radius - hueRing.thickness } diff --git a/app/components/PageDrawer.qml b/app/components/PageDrawer.qml index d7eb1de9..8712bdc6 100644 --- a/app/components/PageDrawer.qml +++ b/app/components/PageDrawer.qml @@ -81,7 +81,7 @@ Drawer { } Image { id: logo_mark - source: "../icons/icon.png" + source: _r + "icons/icon.png" sourceSize: Qt.size (64, 64) fillMode: Image.PreserveAspectFit width: banner.width * 0.16 @@ -93,7 +93,7 @@ Drawer { } Image { id: logo_type - source: "../icons/logo_type_horizontal_short.png" + source: _r + "icons/logo_type_horizontal_short.png" width: banner.width * 0.65 fillMode: Image.PreserveAspectFit anchors { diff --git a/app/main.cpp b/app/main.cpp index fab1dbc6..018d9004 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -54,37 +54,46 @@ int main(int argc, char **argv) #else QGuiApplication app(argc, argv); #endif - app.setWindowIcon(QIcon("app/icons/favicon.ico")); + app.setWindowIcon(QIcon(ALP_ASSET_PREFIX "/icons/favicon.ico")); QCoreApplication::setOrganizationName("AlpineMaps.org"); QCoreApplication::setApplicationName("AlpineApp"); QGuiApplication::setApplicationDisplayName("Alpine Maps"); QNetworkInformation::loadDefaultBackend(); // load here, so it sits on the correct thread. + QFontDatabase::addApplicationFont(ALP_ASSET_PREFIX "/fonts/SourceSans3-Regular.ttf"); + QFontDatabase::addApplicationFont(ALP_ASSET_PREFIX "/fonts/SourceSans3-Bold.ttf"); + app.setFont(QFont("Source Sans 3", 12, 400)); + +#ifndef NDEBUG // QLoggingCategory::setFilterRules("*.debug=true\n" // "qt.qpa.fonts=true"); // output qrc files: - QDirIterator it(":", QDirIterator::Subdirectories); - while (it.hasNext()) { - const auto path = it.next(); - const auto file = QFile(path); - qDebug() << path << " size: " << file.size() / 1024 << "kb"; + { + qDebug() << "qrc files:"; + QDirIterator it(":", QDirIterator::Subdirectories); + while (it.hasNext()) { + const auto path = it.next(); + const auto file = QFile(path); + qDebug() << path << " size: " << file.size() / 1024 << "kb"; + } } - - // qDebug() << ":: before adding fonts::" << QFontDatabase::families().size(); - // for (const auto& entry : QFontDatabase::families()) { - // qDebug() << entry; - // } - for (const auto& entry : QDir(":/fonts").entryInfoList()) { - // qDebug() << entry.filePath() << " -> " << - QFontDatabase::addApplicationFont(entry.filePath()); +#ifdef __EMSCRIPTEN__ + { + qDebug() << "packaged files:"; + QDirIterator it("/", QDirIterator::Subdirectories); + while (it.hasNext()) { + const auto path = it.next(); + const auto file = QFile(path); + qDebug() << path << " size: " << file.size() / 1024 << "kb"; + } } - // qDebug() << ":: after adding fonts::" << QFontDatabase::families().size(); - // for (const auto& entry : QFontDatabase::families()) { - // qDebug() << entry; - // } - - QFont fon("Source Sans 3"); - app.setFont(fon); +#endif + qDebug() << "Available fonts:"; + for (const auto& family : QFontDatabase::families()) { + for (const auto& style : QFontDatabase::styles(family)) + qDebug() << family << "|" << style; + } +#endif QTranslator translator; const QStringList uiLanguages = QLocale::system().uiLanguages(); @@ -117,9 +126,13 @@ int main(int argc, char **argv) QQmlApplicationEngine engine; - HotReloader hotreloader(&engine, ALP_QML_SOURCE_DIR); // FOR NATIVE BUILD ALP_QML_SOURCE_DIR="app/"; + HotReloader hotreloader(&engine, ALP_QML_SOURCE_DIR); engine.rootContext()->setContextProperty("_hotreloader", &hotreloader); - engine.rootContext()->setContextProperty("_qmlPath", ""); +#ifdef __EMSCRIPTEN__ + engine.rootContext()->setContextProperty("_r", "file:///"); +#else + engine.rootContext()->setContextProperty("_r", (ALP_ASSET_PREFIX == std::string(":/")) ? "qrc:/" : ALP_QML_SOURCE_DIR); +#endif engine.rootContext()->setContextProperty("_positionList", QVariant::fromValue(nucleus::camera::PositionStorage::instance()->getPositionList())); engine.rootContext()->setContextProperty("_alpine_renderer_version", QString::fromStdString(nucleus::version())); #ifdef ALP_ENABLE_DEBUG_GUI @@ -138,7 +151,7 @@ int main(int argc, char **argv) } }, Qt::QueuedConnection); - engine.load(QUrl(ALP_QML_SOURCE_DIR "main_loader.qml")); // FOR NATIVE BUILD ALP_QML_SOURCE_DIR="app/"; + engine.load(QUrl(ALP_QML_SOURCE_DIR "main_loader.qml")); QQuickWindow* root_window = dynamic_cast(engine.rootObjects().first()); if (root_window == nullptr) { qDebug() << "root window not created!"; diff --git a/app/main_loader.qml b/app/main_loader.qml index 2a21b716..7826b05b 100644 --- a/app/main_loader.qml +++ b/app/main_loader.qml @@ -31,7 +31,7 @@ ApplicationWindow { Loader { id: mainLoader anchors.fill: parent - source: _qmlPath + "Main.qml" + source: "Main.qml" focus: true } @@ -54,7 +54,7 @@ ApplicationWindow { function onWatched_source_changed() { mainLoader.active = false; _hotreloader.clear_cache(); - mainLoader.setSource(_qmlPath + "Main.qml") + mainLoader.setSource("Main.qml") mainLoader.active = true; } } diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index 926b8486..fd7ed0b8 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -107,13 +107,34 @@ qt_add_library(nucleus STATIC target_include_directories(nucleus PRIVATE . PUBLIC ${CMAKE_SOURCE_DIR}) target_link_libraries(nucleus PUBLIC radix Qt::Core Qt::Gui Qt::Network fmt::fmt zppbits tl_expected nucleus_version stb_slim goofy_tc) +if (NOT EMSCRIPTEN) + qt_add_resources(nucleus "height_data" + PREFIX "/map" + BASE ${renderer_static_data_SOURCE_DIR} + FILES ${renderer_static_data_SOURCE_DIR}/height_data.atb + ) + qt_add_resources(nucleus "nucleus_fonts" + BASE ${alpineapp_fonts_SOURCE_DIR}/SourceSans/ + PREFIX "/fonts" + FILES + ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Bold.ttf + ) + target_compile_definitions(nucleus PUBLIC ALP_ASSET_PREFIX=":") +else() + target_link_options(nucleus PUBLIC "SHELL:--embed-file ${renderer_static_data_SOURCE_DIR}/height_data.atb@/map/height_data.atb") + target_link_options(nucleus PUBLIC "SHELL:--embed-file ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Bold.ttf@/fonts/SourceSans3-Bold.ttf") + target_compile_definitions(nucleus PUBLIC ALP_ASSET_PREFIX="") +endif() + + + if (EMSCRIPTEN) target_compile_options(nucleus PUBLIC -msimd128 -msse2 -Wno-dollar-in-identifier-extension) # # target_compile_options(nucleus PUBLIC -fwasm-exceptions) # # target_link_options(nucleus PUBLIC -fwasm-exceptions) endif() if (ALP_ENABLE_THREADING) - target_compile_definitions(nucleus PUBLIC "ALP_ENABLE_THREADING") + target_compile_definitions(nucleus PUBLIC ALP_ENABLE_THREADING) endif() if (MSVC) diff --git a/nucleus/Controller.cpp b/nucleus/Controller.cpp index 2408fa78..31778ce1 100644 --- a/nucleus/Controller.cpp +++ b/nucleus/Controller.cpp @@ -63,7 +63,7 @@ Controller::Controller(AbstractRenderWindow* render_window) m_tile_scheduler->set_gpu_quad_limit(500); m_tile_scheduler->set_ram_quad_limit(12000); { - QFile file(":/map/height_data.atb"); + QFile file(ALP_ASSET_PREFIX "/map/height_data.atb"); const auto open = file.open(QIODeviceBase::OpenModeFlag::ReadOnly); assert(open); Q_UNUSED(open); diff --git a/nucleus/map_label/MapLabelManager.cpp b/nucleus/map_label/MapLabelManager.cpp index 97b53065..2ec01a36 100644 --- a/nucleus/map_label/MapLabelManager.cpp +++ b/nucleus/map_label/MapLabelManager.cpp @@ -91,21 +91,21 @@ void MapLabelManager::init() Raster rgba_raster = { m_font_atlas.size(), { 255, 255, 0, 255 } }; std::transform(m_font_atlas.cbegin(), m_font_atlas.cend(), rgba_raster.begin(), [](const auto& v) { return glm::u8vec4(v.x, v.y, 0, 255); }); - const auto debug_out = QImage(rgba_raster.bytes(), m_font_atlas_size.width(), m_font_atlas_size.height(), QImage::Format_RGBA8888); - debug_out.save("font_atlas.png"); + // const auto debug_out = QImage(rgba_raster.bytes(), m_font_atlas_size.width(), m_font_atlas_size.height(), QImage::Format_RGBA8888); + // debug_out.save("font_atlas.png"); } for (auto& label : m_labels) { label.init(m_char_data, &m_fontinfo, uv_width_norm); } - m_icon = QImage(":/qt/qml/app/icons/peak.png"); + m_icon = QImage(ALP_ASSET_PREFIX "/icons/peak.png"); } Raster MapLabelManager::make_font_raster() { // load ttf file - QFile file(":/fonts/SourceSans3-Bold.ttf"); + QFile file(ALP_ASSET_PREFIX "/fonts/SourceSans3-Bold.ttf"); const auto open = file.open(QIODeviceBase::OpenModeFlag::ReadOnly); assert(open); Q_UNUSED(open); diff --git a/plain_renderer/CMakeLists.txt b/plain_renderer/CMakeLists.txt index 948f4c52..d6c7acf4 100644 --- a/plain_renderer/CMakeLists.txt +++ b/plain_renderer/CMakeLists.txt @@ -29,11 +29,6 @@ set_target_properties(plain_renderer PROPERTIES target_link_libraries(plain_renderer PUBLIC gl_engine) target_include_directories(plain_renderer PRIVATE .) -qt_add_resources(plain_renderer "height_data" - PREFIX "/map" - BASE ${renderer_static_data_SOURCE_DIR} - FILES ${renderer_static_data_SOURCE_DIR}/height_data.atb -) if (EMSCRIPTEN) message(NOTICE "ALP_WWW_INSTALL_DIR = ${ALP_WWW_INSTALL_DIR}") diff --git a/unittests/nucleus/CMakeLists.txt b/unittests/nucleus/CMakeLists.txt index b114469b..7da9334c 100644 --- a/unittests/nucleus/CMakeLists.txt +++ b/unittests/nucleus/CMakeLists.txt @@ -43,11 +43,6 @@ alp_add_unittest(unittests_nucleus bits_and_pieces.cpp ) -qt_add_resources(unittests_nucleus "height_data" - PREFIX "/map" - BASE ${renderer_static_data_SOURCE_DIR} - FILES ${renderer_static_data_SOURCE_DIR}/height_data.atb -) qt_add_resources(unittests_nucleus "test_data" PREFIX "/test_data" BASE ${CMAKE_CURRENT_SOURCE_DIR}/data/ From b077b83caff8de8b79f6bcfbf8d418a630a91cfa Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 14 Feb 2024 12:11:30 +0100 Subject: [PATCH 19/65] explicitly enable lto --- nucleus/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index fd7ed0b8..decfbcbf 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -129,7 +129,8 @@ endif() if (EMSCRIPTEN) - target_compile_options(nucleus PUBLIC -msimd128 -msse2 -Wno-dollar-in-identifier-extension) + target_compile_options(nucleus PUBLIC -msimd128 -msse2 -Wno-dollar-in-identifier-extension -flto) + target_link_options(nucleus PUBLIC -flto) # # target_compile_options(nucleus PUBLIC -fwasm-exceptions) # # target_link_options(nucleus PUBLIC -fwasm-exceptions) endif() From c898d31fee5c533556090753de15622cd9b5aeac Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 12:40:22 +0100 Subject: [PATCH 20/65] hide lto behinde a cmake option since it takes significantly longer to build. --- CMakeLists.txt | 1 + nucleus/CMakeLists.txt | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ebcf3f90..90dee994 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option(ALP_ENABLE_THREAD_SANITIZER "compiles atb with thread sanitizer enabled ( option(ALP_ENABLE_ASSERTS "enable asserts (do not define NDEBUG)" ON) option(ALP_ENABLE_TRACK_OBJECT_LIFECYCLE "enables debug cmd printout of constructors & deconstructors if implemented" OFF) option(ALP_ENABLE_APP_SHUTDOWN_AFTER_60S "Shuts down the app after 60S, used for CI testing with asan." OFF) +option(ALP_ENABLE_LTO "Enable link time optimisation." OFF) set(ALP_EXTERN_DIR "extern" CACHE STRING "name of the directory to store external libraries, fonts etc..") diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index decfbcbf..c6bc29ae 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -126,11 +126,14 @@ else() target_compile_definitions(nucleus PUBLIC ALP_ASSET_PREFIX="") endif() +if (ALP_ENABLE_LTO) + target_compile_options(nucleus PUBLIC -flto) + target_link_options(nucleus PUBLIC -flto) +endif() if (EMSCRIPTEN) - target_compile_options(nucleus PUBLIC -msimd128 -msse2 -Wno-dollar-in-identifier-extension -flto) - target_link_options(nucleus PUBLIC -flto) + target_compile_options(nucleus PUBLIC -msimd128 -msse2 -Wno-dollar-in-identifier-extension) # # target_compile_options(nucleus PUBLIC -fwasm-exceptions) # # target_link_options(nucleus PUBLIC -fwasm-exceptions) endif() From 71eb2bafd82deb02723b7b18ea0ff262bf69449b Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 14:18:33 +0100 Subject: [PATCH 21/65] roll back emscripten embed option (same compile speed, same file size, but increased cmake complexity. --- app/CMakeLists.txt | 110 ++++++++------------------ app/main.cpp | 14 ++-- gl_engine/CMakeLists.txt | 2 - nucleus/CMakeLists.txt | 36 ++++----- nucleus/Controller.cpp | 2 +- nucleus/map_label/MapLabel.h | 2 +- nucleus/map_label/MapLabelManager.cpp | 4 +- 7 files changed, 58 insertions(+), 112 deletions(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index c8f2fe96..069f4f6a 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -69,87 +69,39 @@ qt_add_qml_module(alpineapp components/FluxColor/HueWheel.qml components/FluxColor/WheelArea.qml RESOURCES + icons/favicon.ico + icons/mascot.jpg + icons/menu.png + icons/search.png + icons/icon.png + icons/material/monitoring.png + icons/material/3d_rotation.png + icons/material/map.png + icons/material/pin_drop.png + icons/material/settings.png + icons/material/info.png + icons/material/format_paint.png + icons/material/location_searching.png + icons/material/my_location.png + icons/material/navigation.png + icons/material/navigation_offset.png + icons/material/chevron_left.png + icons/material/visibility_off.png + icons/presets/basic.png + icons/presets/shaded.png + icons/presets/snow.png + icons/needle_head_down.png + icons/logo_type_horizontal.png + icons/logo_type_vertical.png + icons/logo_type_horizontal_short.png ) -if (NOT EMSCRIPTEN) - qt_add_resources(alpineapp "icons" - PREFIX "/" - FILES - icons/favicon.ico - icons/mascot.jpg - icons/menu.png - icons/peak.png - icons/search.png - icons/icon.png - icons/material/monitoring.png - icons/material/3d_rotation.png - icons/material/map.png - icons/material/pin_drop.png - icons/material/settings.png - icons/material/info.png - icons/material/format_paint.png - icons/material/location_searching.png - icons/material/my_location.png - icons/material/navigation.png - icons/material/navigation_offset.png - icons/material/chevron_left.png - icons/material/visibility_off.png - icons/presets/basic.png - icons/presets/shaded.png - icons/presets/snow.png - icons/needle_head_down.png - icons/logo_type_horizontal.png - icons/logo_type_vertical.png - icons/logo_type_horizontal_short.png - ) - qt_add_resources(alpineapp "fonts" - BASE ${alpineapp_fonts_SOURCE_DIR}/SourceSans/ - PREFIX "/fonts" - FILES - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-BlackIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-BoldIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-ExtraLightIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-It.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Light.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Medium.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-SemiboldIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Black.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Bold.ttf # already importet by nucleus - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-ExtraLight.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-LightIt.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-MediumIt.ttf - ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Regular.ttf - # ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Semibold.ttf - ) -else() - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/mascot.jpg@/icons/mascot.jpg") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/menu.png@icons/menu.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/peak.png@icons/peak.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/search.png@icons/search.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/icon.png@icons/icon.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/monitoring.png@icons/material/monitoring.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/3d_rotation.png@icons/material/3d_rotation.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/map.png@icons/material/map.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/pin_drop.png@icons/material/pin_drop.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/settings.png@icons/material/settings.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/info.png@icons/material/info.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/format_paint.png@icons/material/format_paint.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/location_searching.png@icons/material/location_searching.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/my_location.png@icons/material/my_location.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/navigation.png@icons/material/navigation.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/navigation_offset.png@icons/material/navigation_offset.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/chevron_left.png@icons/material/chevron_left.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/material/visibility_off.png@icons/material/visibility_off.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/presets/basic.png@icons/presets/basic.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/presets/shaded.png@icons/presets/shaded.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/presets/snow.png@icons/presets/snow.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/needle_head_down.png@icons/needle_head_down.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/logo_type_horizontal.png@icons/logo_type_horizontal.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/logo_type_vertical.png@icons/logo_type_vertical.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${CMAKE_CURRENT_SOURCE_DIR}/icons/logo_type_horizontal_short.png@icons/logo_type_horizontal_short.png") - target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Regular.ttf@/fonts/SourceSans3-Regular.ttf") - # target_link_options(alpineapp PUBLIC "SHELL:--embed-file ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-ExtraLight.ttf@/fonts/SourceSans3-ExtraLight.ttf") -endif() +qt_add_resources(alpineapp "fonts" + BASE ${alpineapp_fonts_SOURCE_DIR}/ + PREFIX "/fonts" + FILES + ${alpineapp_fonts_SOURCE_DIR}/Roboto/Roboto-Regular.ttf +) qt_add_translations(alpineapp TS_FILES i18n/de.ts diff --git a/app/main.cpp b/app/main.cpp index 018d9004..8d31e233 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -54,15 +54,15 @@ int main(int argc, char **argv) #else QGuiApplication app(argc, argv); #endif - app.setWindowIcon(QIcon(ALP_ASSET_PREFIX "/icons/favicon.ico")); + app.setWindowIcon(QIcon(":/icons/favicon.ico")); QCoreApplication::setOrganizationName("AlpineMaps.org"); QCoreApplication::setApplicationName("AlpineApp"); QGuiApplication::setApplicationDisplayName("Alpine Maps"); QNetworkInformation::loadDefaultBackend(); // load here, so it sits on the correct thread. - QFontDatabase::addApplicationFont(ALP_ASSET_PREFIX "/fonts/SourceSans3-Regular.ttf"); - QFontDatabase::addApplicationFont(ALP_ASSET_PREFIX "/fonts/SourceSans3-Bold.ttf"); - app.setFont(QFont("Source Sans 3", 12, 400)); + QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Regular.ttf"); + QFontDatabase::addApplicationFont(":/fonts/Roboto/Roboto-Bold.ttf"); + app.setFont(QFont("Roboto", 12, 400)); #ifndef NDEBUG // QLoggingCategory::setFilterRules("*.debug=true\n" @@ -128,11 +128,7 @@ int main(int argc, char **argv) HotReloader hotreloader(&engine, ALP_QML_SOURCE_DIR); engine.rootContext()->setContextProperty("_hotreloader", &hotreloader); -#ifdef __EMSCRIPTEN__ - engine.rootContext()->setContextProperty("_r", "file:///"); -#else - engine.rootContext()->setContextProperty("_r", (ALP_ASSET_PREFIX == std::string(":/")) ? "qrc:/" : ALP_QML_SOURCE_DIR); -#endif + engine.rootContext()->setContextProperty("_r", ALP_QML_SOURCE_DIR); engine.rootContext()->setContextProperty("_positionList", QVariant::fromValue(nucleus::camera::PositionStorage::instance()->getPositionList())); engine.rootContext()->setContextProperty("_alpine_renderer_version", QString::fromStdString(nucleus::version())); #ifdef ALP_ENABLE_DEBUG_GUI diff --git a/gl_engine/CMakeLists.txt b/gl_engine/CMakeLists.txt index 7cfee95a..96eb0114 100644 --- a/gl_engine/CMakeLists.txt +++ b/gl_engine/CMakeLists.txt @@ -79,6 +79,4 @@ else() target_compile_definitions(gl_engine PUBLIC ALP_ENABLE_SHADER_NETWORK_HOTRELOAD=false) endif() -#target_compile_definitions(gl_engine PUBLIC ALP_SHADER_NETWORK_URL="http://localhost:5500/") - target_compile_definitions(gl_engine PUBLIC "ALP_SHADER_NETWORK_URL=\"${ALP_SHADER_NETWORK_URL}\"") diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index c6bc29ae..ce88ee45 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -107,24 +107,24 @@ qt_add_library(nucleus STATIC target_include_directories(nucleus PRIVATE . PUBLIC ${CMAKE_SOURCE_DIR}) target_link_libraries(nucleus PUBLIC radix Qt::Core Qt::Gui Qt::Network fmt::fmt zppbits tl_expected nucleus_version stb_slim goofy_tc) -if (NOT EMSCRIPTEN) - qt_add_resources(nucleus "height_data" - PREFIX "/map" - BASE ${renderer_static_data_SOURCE_DIR} - FILES ${renderer_static_data_SOURCE_DIR}/height_data.atb - ) - qt_add_resources(nucleus "nucleus_fonts" - BASE ${alpineapp_fonts_SOURCE_DIR}/SourceSans/ - PREFIX "/fonts" - FILES - ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Bold.ttf - ) - target_compile_definitions(nucleus PUBLIC ALP_ASSET_PREFIX=":") -else() - target_link_options(nucleus PUBLIC "SHELL:--embed-file ${renderer_static_data_SOURCE_DIR}/height_data.atb@/map/height_data.atb") - target_link_options(nucleus PUBLIC "SHELL:--embed-file ${alpineapp_fonts_SOURCE_DIR}/SourceSans/SourceSans3-Bold.ttf@/fonts/SourceSans3-Bold.ttf") - target_compile_definitions(nucleus PUBLIC ALP_ASSET_PREFIX="") -endif() +qt_add_resources(nucleus "icons" + PREFIX "/map_icons" + BASE ${CMAKE_SOURCE_DIR}/app/icons + FILES + ${CMAKE_SOURCE_DIR}/app/icons/peak.png +) +qt_add_resources(nucleus "height_data" + PREFIX "/map" + BASE ${renderer_static_data_SOURCE_DIR} + FILES ${renderer_static_data_SOURCE_DIR}/height_data.atb +) +qt_add_resources(nucleus "nucleus_fonts" + BASE ${alpineapp_fonts_SOURCE_DIR}/SourceSans/ + PREFIX "/fonts" + FILES + ${alpineapp_fonts_SOURCE_DIR}/Roboto/Roboto-Bold.ttf +) + if (ALP_ENABLE_LTO) target_compile_options(nucleus PUBLIC -flto) diff --git a/nucleus/Controller.cpp b/nucleus/Controller.cpp index 31778ce1..2408fa78 100644 --- a/nucleus/Controller.cpp +++ b/nucleus/Controller.cpp @@ -63,7 +63,7 @@ Controller::Controller(AbstractRenderWindow* render_window) m_tile_scheduler->set_gpu_quad_limit(500); m_tile_scheduler->set_ram_quad_limit(12000); { - QFile file(ALP_ASSET_PREFIX "/map/height_data.atb"); + QFile file(":/map/height_data.atb"); const auto open = file.open(QIODeviceBase::OpenModeFlag::ReadOnly); assert(open); Q_UNUSED(open); diff --git a/nucleus/map_label/MapLabel.h b/nucleus/map_label/MapLabel.h index 32d745da..b87a3d3d 100644 --- a/nucleus/map_label/MapLabel.h +++ b/nucleus/map_label/MapLabel.h @@ -54,7 +54,7 @@ class MapLabel { void init(const std::unordered_map& character_data, const stbtt_fontinfo* fontinfo, const float uv_width_norm); - constexpr static float font_size = 60.0f; + constexpr static float font_size = 48.0f; constexpr static glm::vec2 icon_size = glm::vec2(48.0f); const std::vector& vertex_data() const; diff --git a/nucleus/map_label/MapLabelManager.cpp b/nucleus/map_label/MapLabelManager.cpp index 2ec01a36..efa1f565 100644 --- a/nucleus/map_label/MapLabelManager.cpp +++ b/nucleus/map_label/MapLabelManager.cpp @@ -99,13 +99,13 @@ void MapLabelManager::init() label.init(m_char_data, &m_fontinfo, uv_width_norm); } - m_icon = QImage(ALP_ASSET_PREFIX "/icons/peak.png"); + m_icon = QImage(":/map_icons/peak.png"); } Raster MapLabelManager::make_font_raster() { // load ttf file - QFile file(ALP_ASSET_PREFIX "/fonts/SourceSans3-Bold.ttf"); + QFile file(":/fonts/Roboto/Roboto-Bold.ttf"); const auto open = file.open(QIODeviceBase::OpenModeFlag::ReadOnly); assert(open); Q_UNUSED(open); From d381aa203d83337647bfdf71ba40f775cfe3e683 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 14:23:03 +0100 Subject: [PATCH 22/65] fix permission dialogue --- app/GnssInformation.cpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/app/GnssInformation.cpp b/app/GnssInformation.cpp index 64b7f3dd..dd968736 100644 --- a/app/GnssInformation.cpp +++ b/app/GnssInformation.cpp @@ -20,6 +20,7 @@ #ifdef ALP_ENABLE_GNSS #include +#include #endif GnssInformation::GnssInformation() @@ -96,10 +97,33 @@ void GnssInformation::set_enabled(bool new_enabled) return; m_enabled = new_enabled; #ifdef ALP_ENABLE_GNSS - if (m_enabled) - m_position_source->startUpdates(); - else + if (m_enabled) { + QLocationPermission gnssPermission; + gnssPermission.setAccuracy(QLocationPermission::Accuracy::Precise); + gnssPermission.setAvailability(QLocationPermission::Availability::WhenInUse); + switch (qApp->checkPermission(gnssPermission)) { + case Qt::PermissionStatus::Undetermined: + qDebug() << "Qt::PermissionStatus::Undetermined"; + qApp->requestPermission(gnssPermission, this, [this](const QPermission& permission) { + qDebug() << "qApp->requestPermission" << permission; + if (permission.status() == Qt::PermissionStatus::Granted) { + m_position_source->startUpdates(); + } else { + set_enabled(false); + } + }); + return; + case Qt::PermissionStatus::Denied: + qDebug() << "Qt::PermissionStatus::Denied"; + set_enabled(false); + return; + case Qt::PermissionStatus::Granted: + qDebug() << "Qt::PermissionStatus::Granted"; + m_position_source->startUpdates(); + } + } else { m_position_source->stopUpdates(); + } #endif emit enabled_changed(); From 994f6d2821dca9cd0499c8d73fa72cd44b542235 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 14:23:11 +0100 Subject: [PATCH 23/65] fix link --- app/About.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/About.qml b/app/About.qml index 646fe4db..c17382cd 100644 --- a/app/About.qml +++ b/app/About.qml @@ -70,7 +70,7 @@ Rectangle { text: qsTr(" This is an open source application. It is **released** under the GNU General Public License (version 3 or any later version). The source code is available on [github.com/AlpineMapsOrg/renderer](https://github.com/AlpineMapsOrg/renderer). -The source of elevation and orthographic photo data is basemap.at, +The source of elevation and orthographic photo data is [basemap.at](https://basemap.at), it is licensed under the Open Government Data Austria license (CC-BY 4.0). ## Authors: From f6ccec921dc7e4361e5fec97c821ec81b60f4689 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 17:53:11 +0100 Subject: [PATCH 24/65] build with new fonts repo version + fix warning format --- CMakeLists.txt | 2 +- app/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 90dee994..a05fec77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,7 +89,7 @@ endif() include(cmake/alp_add_git_repository.cmake) alp_add_git_repository(renderer_static_data URL https://github.com/AlpineMapsOrg/renderer_static_data.git COMMITISH v23.11 DO_NOT_ADD_SUBPROJECT) -alp_add_git_repository(alpineapp_fonts URL https://github.com/AlpineMapsOrg/fonts.git COMMITISH v23.11 DO_NOT_ADD_SUBPROJECT) +alp_add_git_repository(alpineapp_fonts URL https://github.com/AlpineMapsOrg/fonts.git COMMITISH v24.02 DO_NOT_ADD_SUBPROJECT) alp_add_git_repository(doc URL https://github.com/AlpineMapsOrg/documentation.git COMMITISH origin/main DO_NOT_ADD_SUBPROJECT DESTINATION_PATH doc) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 069f4f6a..2569980d 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -114,7 +114,7 @@ set_target_properties(alpineapp PROPERTIES ) target_link_libraries(alpineapp PUBLIC gl_engine Qt::Quick Qt::QuickControls2) if (ALP_ENABLE_DEBUG_GUI) - message(WARNING building alpine app with debug gui) + message(WARNING "building alpine app with debug gui") qt_target_qml_sources(alpineapp QML_FILES StatsWindow.qml) target_link_libraries(alpineapp PUBLIC Qt::Charts Qt::Widgets) target_compile_definitions(alpineapp PUBLIC ALP_ENABLE_DEBUG_GUI) From 161a30ecc66fea1a48f41a187711f053235a8f7b Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 18:05:52 +0100 Subject: [PATCH 25/65] unit tests for compression pass on linux, ff/linux, chrome/linux and android --- gl_engine/Texture.cpp | 10 +- gl_engine/Texture.h | 11 +- gl_engine/Window.cpp | 7 +- gl_engine/Window.h | 1 + nucleus/AbstractRenderWindow.h | 4 +- nucleus/utils/texture_compression.cpp | 40 ++++- nucleus/utils/texture_compression.h | 5 + unittests/gl_engine/compressed_textures.cpp | 167 ++++++-------------- 8 files changed, 108 insertions(+), 137 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 2c1b353b..6b793f61 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -78,7 +78,7 @@ GLenum gl_engine::Texture::compressed_texture_format() #endif } -std::vector gl_engine::Texture::compress(const QImage& image) +nucleus::utils::texture_compression::Algorithm gl_engine::Texture::compression_algorithm() { #if defined(__EMSCRIPTEN__) // clang-format off @@ -92,12 +92,12 @@ std::vector gl_engine::Texture::compress(const QImage& image) }); // clang-format on if (gl_texture_format == 0) { - return nucleus::utils::texture_compression::to_dxt1(image); + return nucleus::utils::texture_compression::Algorithm::DXT1; } - return nucleus::utils::texture_compression::to_etc1(image); + return nucleus::utils::texture_compression::Algorithm::ETC1; #elif defined(__ANDROID__) - return nucleus::utils::texture_compression::to_etc1(image); + return nucleus::utils::texture_compression::Algorithm::ETC1; #else - return nucleus::utils::texture_compression::to_dxt1(image); + return nucleus::utils::texture_compression::Algorithm::DXT1; #endif } diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index ba16338b..7cb1bf07 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include namespace gl_engine { @@ -27,15 +28,19 @@ class Texture { enum class Target : GLenum { _2d = GL_TEXTURE_2D, _2dArray = GL_TEXTURE_2D_ARRAY }; public: - Texture(Target target); + Texture(const Texture&) = default; + Texture(Texture&&) = delete; + Texture& operator=(const Texture&) = default; + Texture& operator=(Texture&&) = delete; + explicit Texture(Target target); ~Texture(); void bind(unsigned texture_unit); static GLenum compressed_texture_format(); - static std::vector compress(const QImage& image); + static nucleus::utils::texture_compression::Algorithm compression_algorithm(); private: - GLuint m_id = -1; + GLuint m_id = GLuint(-1); Target m_target = Target::_2d; }; diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index d3cf6fb1..9e9c377b 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -483,7 +483,6 @@ void Window::remove_tile(const tile::Id& id) m_tile_manager->remove_tile(id); } -nucleus::camera::AbstractDepthTester* Window::depth_tester() -{ - return this; -} +nucleus::camera::AbstractDepthTester* Window::depth_tester() { return this; } + +nucleus::utils::texture_compression::Algorithm Window::ortho_tile_compression_algorithm() const { return Texture::compression_algorithm(); } diff --git a/gl_engine/Window.h b/gl_engine/Window.h index f6a6bb70..b2cbc083 100644 --- a/gl_engine/Window.h +++ b/gl_engine/Window.h @@ -70,6 +70,7 @@ class Window : public nucleus::AbstractRenderWindow, public nucleus::camera::Abs void set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr&) override; void remove_tile(const tile::Id&) override; [[nodiscard]] nucleus::camera::AbstractDepthTester* depth_tester() override; + [[nodiscard]] nucleus::utils::texture_compression::Algorithm ortho_tile_compression_algorithm() const override; void keyPressEvent(QKeyEvent*); void keyReleaseEvent(QKeyEvent*); void updateCameraEvent(); diff --git a/nucleus/AbstractRenderWindow.h b/nucleus/AbstractRenderWindow.h index 5f46d77d..de931679 100644 --- a/nucleus/AbstractRenderWindow.h +++ b/nucleus/AbstractRenderWindow.h @@ -23,7 +23,8 @@ #include -#include +#include "nucleus/tile_scheduler/tile_types.h" +#include "utils/texture_compression.h" class QOpenGLFramebufferObject; @@ -51,6 +52,7 @@ class AbstractRenderWindow : public QObject { virtual void deinit_gpu() = 0; virtual void set_permissible_screen_space_error(float new_error) = 0; [[nodiscard]] virtual camera::AbstractDepthTester* depth_tester() = 0; + [[nodiscard]] virtual utils::texture_compression::Algorithm ortho_tile_compression_algorithm() const = 0; public slots: virtual void update_camera(const camera::Definition& new_definition) = 0; diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp index de1775ba..d004cd8c 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/texture_compression.cpp @@ -30,6 +30,7 @@ std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& assert(qimage.width() == qimage.height()); assert(qimage.width() % 16 == 0); assert(qimage.bytesPerLine() * qimage.height() == qimage.width() * qimage.height() * 4); + assert(qimage.sizeInBytes() == qimage.width() * qimage.height() * 4); struct alignas(16) AlignedBlock { @@ -37,13 +38,13 @@ std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& }; static_assert(sizeof(AlignedBlock) == 16); - const auto n_bytes_in = qimage.width() * qimage.height() * 4; + const auto n_bytes_in = size_t(qimage.sizeInBytes()); const auto n_bytes_out = qimage.width() * qimage.height() / 2; assert(n_bytes_in % sizeof(AlignedBlock) == 0); auto aligned_in = std::vector(n_bytes_in / sizeof(AlignedBlock)); auto data_ptr = reinterpret_cast(aligned_in.data()); - std::copy(qimage.bits(), qimage.bits() + n_bytes_in, data_ptr); + std::copy(qimage.constBits(), qimage.constBits() + n_bytes_in, data_ptr); std::vector compressed(n_bytes_out); const auto result = goofy::compressDXT1(compressed.data(), data_ptr, qimage.width(), qimage.height(), qimage.width() * 4); @@ -64,6 +65,7 @@ std::vector nucleus::utils::texture_compression::to_etc1(const QImage& assert(qimage.width() == qimage.height()); assert(qimage.width() % 16 == 0); assert(qimage.bytesPerLine() * qimage.height() == qimage.width() * qimage.height() * 4); + assert(qimage.sizeInBytes() == qimage.width() * qimage.height() * 4); struct alignas(16) AlignedBlock { @@ -71,13 +73,13 @@ std::vector nucleus::utils::texture_compression::to_etc1(const QImage& }; static_assert(sizeof(AlignedBlock) == 16); - const auto n_bytes_in = qimage.width() * qimage.height() * 4; + const auto n_bytes_in = size_t(qimage.sizeInBytes()); const auto n_bytes_out = qimage.width() * qimage.height() / 2; assert(n_bytes_in % sizeof(AlignedBlock) == 0); auto aligned_in = std::vector(n_bytes_in / sizeof(AlignedBlock)); auto data_ptr = reinterpret_cast(aligned_in.data()); - std::copy(qimage.bits(), qimage.bits() + n_bytes_in, data_ptr); + std::copy(qimage.constBits(), qimage.constBits() + n_bytes_in, data_ptr); std::vector compressed(n_bytes_out); const auto result = goofy::compressETC1(compressed.data(), data_ptr, qimage.width(), qimage.height(), qimage.width() * 4); @@ -88,3 +90,33 @@ std::vector nucleus::utils::texture_compression::to_etc1(const QImage& return compressed; } + +std::vector nucleus::utils::texture_compression::to_compressed(const QImage& image, Algorithm algorithm) +{ + switch (algorithm) { + case Algorithm::DXT1: + return to_dxt1(image); + case Algorithm::ETC1: + return to_etc1(image); + case Algorithm::Uncompressed_RGBA: + return to_uncompressed_rgba(image); + } + assert(false); + return to_uncompressed_rgba(image); +} + +std::vector nucleus::utils::texture_compression::to_uncompressed_rgba(const QImage& qimage) +{ + if (qimage.format() != QImage::Format_RGBA8888 && qimage.format() != QImage::Format_RGBX8888) { + qimage.save("to_uncompressed_rgba1.png"); + return to_uncompressed_rgba(qimage.convertedTo(QImage::Format_RGBA8888)); + } + assert(qimage.sizeInBytes() == qimage.width() * qimage.height() * 4); + std::vector data; + data.resize(size_t(qimage.sizeInBytes())); + auto* data_ptr = reinterpret_cast(data.data()); + const auto* bits = qimage.constScanLine(0); + Q_UNUSED(bits); + std::copy(qimage.constBits(), qimage.constBits() + qimage.sizeInBytes(), data_ptr); + return data; +} diff --git a/nucleus/utils/texture_compression.h b/nucleus/utils/texture_compression.h index 9d6e896b..599fd03b 100644 --- a/nucleus/utils/texture_compression.h +++ b/nucleus/utils/texture_compression.h @@ -23,6 +23,11 @@ namespace nucleus::utils::texture_compression { +enum class Algorithm { Uncompressed_RGBA, DXT1, ETC1 }; + std::vector to_dxt1(const QImage& image); std::vector to_etc1(const QImage& image); +std::vector to_uncompressed_rgba(const QImage& image); + +std::vector to_compressed(const QImage& image, Algorithm algorithm); } diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index 170286dc..426d752a 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -36,6 +36,7 @@ using gl_engine::Framebuffer; using gl_engine::ShaderProgram; +using namespace nucleus::utils; static const char* const vertex_source = R"( out highp vec2 texcoords; @@ -78,6 +79,8 @@ TEST_CASE("gl compressed textures") grad.setColorAt(1, qRgb(145, 100, 0)); grad.setSpread(QGradient::ReflectSpread); painter.setBrush(grad); + painter.setPen(qRgba(242, 0, 42, 255)); + // painter.drawRect(-1, -1, 257, 257); painter.drawRect(0, 0, 255, 255); test_texture.save("test_texture.png"); } @@ -85,11 +88,11 @@ TEST_CASE("gl compressed textures") SECTION("compression") { { - const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); + const auto compressed = texture_compression::to_dxt1(test_texture); CHECK(compressed.size() == 256 * 128); } { - const auto compressed = nucleus::utils::texture_compression::to_etc1(test_texture); + const auto compressed = texture_compression::to_etc1(test_texture); CHECK(compressed.size() == 256 * 128); } } @@ -128,7 +131,7 @@ TEST_CASE("gl compressed textures") diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; } } - CHECK(diff / (256 * 256 * 3) < 0.01); + CHECK(diff / (256 * 256 * 3) < 0.001); } SECTION("compression") @@ -136,7 +139,7 @@ TEST_CASE("gl compressed textures") Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); b.bind(); - const auto compressed = gl_engine::Texture::compress(test_texture); + const auto compressed = texture_compression::to_compressed(test_texture, gl_engine::Texture::compression_algorithm()); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); opengl_texture.bind(0); f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -178,125 +181,49 @@ TEST_CASE("gl compressed textures") diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; } } - CHECK(diff / (256 * 256 * 3) < 0.015); + CHECK(diff / (256 * 256 * 3) < 0.017); } - // SECTION("compression dxt1") - // { - // Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); - // b.bind(); - - // const auto compressed = nucleus::utils::texture_compression::to_dxt1(test_texture); - // gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); - // opengl_texture.bind(0); - // f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // f->glCompressedTexImage2D(GL_TEXTURE_2D, - // 0, - // GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - // test_texture.width(), - // test_texture.height(), - // 0, - // compressed.size(), - // compressed.data()); - - // ShaderProgram shader = create_debug_shader(R"( - // uniform sampler2D texture_sampler; - // in highp vec2 texcoords; - // out lowp vec4 out_color; - // void main() { - // out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); - // } - // )"); - // shader.bind(); - // gl_engine::helpers::create_screen_quad_geometry().draw(); - - // const QImage render_result = b.read_colour_attachment(0); - // render_result.save("render_result.png"); - // Framebuffer::unbind(); - // REQUIRE(!render_result.isNull()); - // CHECK(render_result.width() == test_texture.width()); - // CHECK(render_result.height() == test_texture.height()); - // double diff = 0; - // for (int i = 0; i < render_result.width(); ++i) { - // for (int j = 0; j < render_result.height(); ++j) { - // diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; - // diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; - // diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; - // } - // } - // CHECK(diff / (256 * 256 * 3) < 0.015); - // } - - // SECTION("compression etc1") - // { - // Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); - // b.bind(); - // #ifdef __EMSCRIPTEN__ - // // clang-format off - // int gl_texture_format = EM_ASM_INT({ - // var canvas = document.createElement('canvas'); - // var gl = canvas.getContext("webgl2"); - // const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); - // if (ext === null) - // return 0; - // return ext.COMPRESSED_RGB_ETC1_WEBGL; - // }); - // qDebug() << "gl_texture_format from js: " << gl_texture_format; - // // clang-format on - // if (gl_texture_format == 0) { - // gl_texture_format = GL_COMPRESSED_RGB8_ETC2; // not on mobile - // qDebug() << "gl_texture_format from GL_COMPRESSED_RGB8_ETC2: " << gl_texture_format; - // } - // #else - // constexpr auto gl_texture_format = GL_COMPRESSED_RGB8_ETC2; - // #endif + SECTION("not compression") + { + Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); + b.bind(); - // const auto compressed = nucleus::utils::texture_compression::to_etc1(test_texture); - // gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); - // opengl_texture.bind(0); - // f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - // f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // f->glCompressedTexImage2D(GL_TEXTURE_2D, - // 0, - // gl_texture_format, - // test_texture.width(), - // test_texture.height(), - // 0, - // compressed.size(), - // compressed.data()); + const auto compressed = texture_compression::to_compressed(test_texture, texture_compression::Algorithm::Uncompressed_RGBA); + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); + opengl_texture.bind(0); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, test_texture.width(), test_texture.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, compressed.data()); - // ShaderProgram shader = create_debug_shader(R"( - // uniform sampler2D texture_sampler; - // in highp vec2 texcoords; - // out lowp vec4 out_color; - // void main() { - // out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); - // } - // )"); - // shader.bind(); - // gl_engine::helpers::create_screen_quad_geometry().draw(); + ShaderProgram shader = create_debug_shader(R"( + uniform sampler2D texture_sampler; + in highp vec2 texcoords; + out lowp vec4 out_color; + void main() { + out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); + } + )"); + shader.bind(); + gl_engine::helpers::create_screen_quad_geometry().draw(); - // const QImage render_result = b.read_colour_attachment(0); - // render_result.save("render_result.png"); - // Framebuffer::unbind(); - // REQUIRE(!render_result.isNull()); - // CHECK(render_result.width() == test_texture.width()); - // CHECK(render_result.height() == test_texture.height()); - // double diff = 0; - // for (int i = 0; i < render_result.width(); ++i) { - // for (int j = 0; j < render_result.height(); ++j) { - // diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; - // diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; - // diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; - // } - // } - // CHECK(diff / (256 * 256 * 3) < 0.015); - // } + const QImage render_result = b.read_colour_attachment(0); + render_result.save("render_result.png"); + Framebuffer::unbind(); + REQUIRE(!render_result.isNull()); + CHECK(render_result.width() == test_texture.width()); + CHECK(render_result.height() == test_texture.height()); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.001); + } } From 99f8df3dfb6c4e3356cf7db766bf183a4ea4957c Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 19:13:28 +0100 Subject: [PATCH 26/65] refactor ortho textures (prep for compression) --- gl_engine/Texture.cpp | 10 ++--- gl_engine/Texture.h | 6 +-- gl_engine/TileManager.cpp | 20 +++++++--- gl_engine/TileManager.h | 4 +- gl_engine/TileSet.h | 8 ++-- gl_engine/UniformBuffer.h | 1 - gl_engine/Window.cpp | 2 +- gl_engine/Window.h | 2 +- nucleus/AbstractRenderWindow.h | 2 +- nucleus/CMakeLists.txt | 2 +- nucleus/map_label/MapLabel.cpp | 4 +- nucleus/map_label/MapLabelManager.cpp | 5 +-- nucleus/tile_scheduler/Scheduler.cpp | 16 +++++--- nucleus/tile_scheduler/Scheduler.h | 7 +++- nucleus/tile_scheduler/tile_types.h | 9 +++-- nucleus/utils/texture_compression.cpp | 44 +++++++++++++-------- nucleus/utils/texture_compression.h | 25 ++++++++---- unittests/gl_engine/compressed_textures.cpp | 26 ++++++------ 18 files changed, 117 insertions(+), 76 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 6b793f61..6fe3602f 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -78,7 +78,7 @@ GLenum gl_engine::Texture::compressed_texture_format() #endif } -nucleus::utils::texture_compression::Algorithm gl_engine::Texture::compression_algorithm() +nucleus::utils::CompressedTexture::Algorithm gl_engine::Texture::compression_algorithm() { #if defined(__EMSCRIPTEN__) // clang-format off @@ -92,12 +92,12 @@ nucleus::utils::texture_compression::Algorithm gl_engine::Texture::compression_a }); // clang-format on if (gl_texture_format == 0) { - return nucleus::utils::texture_compression::Algorithm::DXT1; + return nucleus::utils::CompressedTexture::Algorithm::DXT1; } - return nucleus::utils::texture_compression::Algorithm::ETC1; + return nucleus::utils::CompressedTexture::Algorithm::ETC1; #elif defined(__ANDROID__) - return nucleus::utils::texture_compression::Algorithm::ETC1; + return nucleus::utils::CompressedTexture::Algorithm::ETC1; #else - return nucleus::utils::texture_compression::Algorithm::DXT1; + return nucleus::utils::CompressedTexture::Algorithm::DXT1; #endif } diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index 7cb1bf07..404411be 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -28,16 +28,16 @@ class Texture { enum class Target : GLenum { _2d = GL_TEXTURE_2D, _2dArray = GL_TEXTURE_2D_ARRAY }; public: - Texture(const Texture&) = default; + Texture(const Texture&) = delete; Texture(Texture&&) = delete; - Texture& operator=(const Texture&) = default; + Texture& operator=(const Texture&) = delete; Texture& operator=(Texture&&) = delete; explicit Texture(Target target); ~Texture(); void bind(unsigned texture_unit); static GLenum compressed_texture_format(); - static nucleus::utils::texture_compression::Algorithm compression_algorithm(); + static nucleus::utils::CompressedTexture::Algorithm compression_algorithm(); private: GLuint m_id = GLuint(-1); diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index 41c12543..68482b43 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -181,7 +181,8 @@ void TileManager::set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbD m_draw_list_generator.set_aabb_decorator(new_aabb_decorator); } -void TileManager::add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, const QImage& ortho_texture, const nucleus::Raster& height_map, const QImage& height_texture) +void TileManager::add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::CompressedTexture& ortho_texture, + const nucleus::Raster& height_map, const QImage& height_texture) { if (!QOpenGLContext::currentContext()) // can happen during shutdown. return; @@ -211,11 +212,18 @@ void TileManager::add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, tileset.gl_index_type = GL_UNSIGNED_SHORT; } tileset.vao->release(); - tileset.ortho_texture = std::make_unique(ortho_texture); - tileset.ortho_texture->setMaximumAnisotropy(m_max_anisotropy); - tileset.ortho_texture->setWrapMode(QOpenGLTexture::WrapMode::ClampToEdge); - tileset.ortho_texture->setMinMagFilters(QOpenGLTexture::Filter::LinearMipMapLinear, QOpenGLTexture::Filter::Linear); - tileset.ortho_texture->generateMipMaps(); + tileset.ortho_texture = std::make_unique(Texture::Target::_2d); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ORTHO_RESOLUTION, ORTHO_RESOLUTION, 0, GL_RGBA, GL_UNSIGNED_BYTE, ortho_texture.data()); + + // tileset.ortho_texture->setMaximumAnisotropy(m_max_anisotropy); + // tileset.ortho_texture->setWrapMode(QOpenGLTexture::WrapMode::ClampToEdge); + // tileset.ortho_texture->setMinMagFilters(QOpenGLTexture::Filter::LinearMipMapLinear, QOpenGLTexture::Filter::Linear); + // tileset.ortho_texture->generateMipMaps(); tileset.heightmap_texture = std::make_unique(height_texture); tileset.heightmap_texture->setWrapMode(QOpenGLTexture::WrapMode::ClampToEdge); diff --git a/gl_engine/TileManager.h b/gl_engine/TileManager.h index 69f71c48..65ee5874 100644 --- a/gl_engine/TileManager.h +++ b/gl_engine/TileManager.h @@ -62,12 +62,14 @@ public slots: void set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr& new_aabb_decorator); private: - void add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, const QImage& ortho, const nucleus::Raster& heights, const QImage& height_texture); + void add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::CompressedTexture& ortho, const nucleus::Raster& heights, + const QImage& height_texture); struct TileGLAttributeLocations { int height = -1; }; static constexpr auto N_EDGE_VERTICES = 65; + static constexpr auto ORTHO_RESOLUTION = 256; static constexpr auto MAX_TILES_PER_TILESET = 1; float m_max_anisotropy = 0; diff --git a/gl_engine/TileSet.h b/gl_engine/TileSet.h index 02be6a56..033707f8 100644 --- a/gl_engine/TileSet.h +++ b/gl_engine/TileSet.h @@ -1,4 +1,4 @@ - /***************************************************************************** +/***************************************************************************** * Alpine Terrain Renderer * Copyright (C) 2023 Adam Celerek * Copyright (C) 2023 Gerald Kimmersdorfer @@ -26,11 +26,13 @@ #include #include +#include "Texture.h" #include "radix/tile.h" // we want to be flexible and have the ability to draw several tiles at once. // GpuTileSets can have an arbitrary number of slots, each slot is an index in the corresponding // vao buffers and textures. + namespace gl_engine { struct TileSet { struct Tile { @@ -44,7 +46,7 @@ struct TileSet { [[nodiscard]] bool isValid() const { return tile_id.zoom_level < 100; } }; - std::unique_ptr ortho_texture; + std::unique_ptr ortho_texture; std::unique_ptr heightmap_buffer; std::unique_ptr heightmap_texture; std::unique_ptr vao; @@ -53,4 +55,4 @@ struct TileSet { unsigned gl_index_type = 0; // texture }; -} +} // namespace gl_engine diff --git a/gl_engine/UniformBuffer.h b/gl_engine/UniformBuffer.h index 8061e630..53cbeabd 100644 --- a/gl_engine/UniformBuffer.h +++ b/gl_engine/UniformBuffer.h @@ -30,7 +30,6 @@ class ShaderProgram; template class UniformBuffer { public: - // Generate GPU Buffer and bind to location void init(); diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index 9e9c377b..05565963 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -485,4 +485,4 @@ void Window::remove_tile(const tile::Id& id) nucleus::camera::AbstractDepthTester* Window::depth_tester() { return this; } -nucleus::utils::texture_compression::Algorithm Window::ortho_tile_compression_algorithm() const { return Texture::compression_algorithm(); } +nucleus::utils::CompressedTexture::Algorithm Window::ortho_tile_compression_algorithm() const { return Texture::compression_algorithm(); } diff --git a/gl_engine/Window.h b/gl_engine/Window.h index b2cbc083..7dadb2a7 100644 --- a/gl_engine/Window.h +++ b/gl_engine/Window.h @@ -70,7 +70,7 @@ class Window : public nucleus::AbstractRenderWindow, public nucleus::camera::Abs void set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr&) override; void remove_tile(const tile::Id&) override; [[nodiscard]] nucleus::camera::AbstractDepthTester* depth_tester() override; - [[nodiscard]] nucleus::utils::texture_compression::Algorithm ortho_tile_compression_algorithm() const override; + [[nodiscard]] nucleus::utils::CompressedTexture::Algorithm ortho_tile_compression_algorithm() const override; void keyPressEvent(QKeyEvent*); void keyReleaseEvent(QKeyEvent*); void updateCameraEvent(); diff --git a/nucleus/AbstractRenderWindow.h b/nucleus/AbstractRenderWindow.h index de931679..761fd604 100644 --- a/nucleus/AbstractRenderWindow.h +++ b/nucleus/AbstractRenderWindow.h @@ -52,7 +52,7 @@ class AbstractRenderWindow : public QObject { virtual void deinit_gpu() = 0; virtual void set_permissible_screen_space_error(float new_error) = 0; [[nodiscard]] virtual camera::AbstractDepthTester* depth_tester() = 0; - [[nodiscard]] virtual utils::texture_compression::Algorithm ortho_tile_compression_algorithm() const = 0; + [[nodiscard]] virtual utils::CompressedTexture::Algorithm ortho_tile_compression_algorithm() const = 0; public slots: virtual void update_camera(const camera::Definition& new_definition) = 0; diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index ce88ee45..8e7de3f5 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -104,7 +104,7 @@ qt_add_library(nucleus STATIC utils/texture_compression.h utils/texture_compression.cpp ) -target_include_directories(nucleus PRIVATE . PUBLIC ${CMAKE_SOURCE_DIR}) +target_include_directories(nucleus PUBLIC ${CMAKE_SOURCE_DIR}) target_link_libraries(nucleus PUBLIC radix Qt::Core Qt::Gui Qt::Network fmt::fmt zppbits tl_expected nucleus_version stb_slim goofy_tc) qt_add_resources(nucleus "icons" diff --git a/nucleus/map_label/MapLabel.cpp b/nucleus/map_label/MapLabel.cpp index 6f9389cc..564f064c 100644 --- a/nucleus/map_label/MapLabel.cpp +++ b/nucleus/map_label/MapLabel.cpp @@ -18,11 +18,11 @@ #include "MapLabel.h" -#include "srs.h" #include +#include -#include "stb_slim/stb_truetype.h" +#include "nucleus/srs.h" namespace nucleus { diff --git a/nucleus/map_label/MapLabelManager.cpp b/nucleus/map_label/MapLabelManager.cpp index efa1f565..adb16d65 100644 --- a/nucleus/map_label/MapLabelManager.cpp +++ b/nucleus/map_label/MapLabelManager.cpp @@ -23,13 +23,12 @@ #include #include #include -#include -#include "Raster.h" +#include "nucleus/Raster.h" #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION -#include "stb_slim/stb_truetype.h" +#include using namespace Qt::Literals::StringLiterals; diff --git a/nucleus/tile_scheduler/Scheduler.cpp b/nucleus/tile_scheduler/Scheduler.cpp index c90b8cd9..b5db7599 100644 --- a/nucleus/tile_scheduler/Scheduler.cpp +++ b/nucleus/tile_scheduler/Scheduler.cpp @@ -175,8 +175,8 @@ void Scheduler::update_gpu_quads() if (quad.tiles[i].ortho->size()) { ortho_data = quad.tiles[i].ortho.get(); } - auto ortho = nucleus::utils::tile_conversion::toQImage(*ortho_data); - gpu_quad.tiles[i].ortho = std::make_shared(std::move(ortho)); + const auto ortho_qimage = nucleus::utils::tile_conversion::toQImage(*ortho_data); + gpu_quad.tiles[i].ortho = std::make_shared(ortho_qimage, m_ortho_tile_compression_algorithm); const auto* height_data = m_default_height_tile.get(); if (quad.tiles[i].height->size()) { @@ -184,9 +184,8 @@ void Scheduler::update_gpu_quads() } auto heightimage = nucleus::utils::tile_conversion::toQImage(*height_data); gpu_quad.tiles[i].height_image = std::make_shared(std::move(heightimage)); - //TODO: We dont need height in VBO anymore!!! Delete at some point!! - auto heightraster = nucleus::utils::tile_conversion::qImage2uint16Raster( - nucleus::utils::tile_conversion::toQImage(*height_data)); + // TODO: We dont need height in VBO anymore!!! Delete at some point!! + auto heightraster = nucleus::utils::tile_conversion::qImage2uint16Raster(nucleus::utils::tile_conversion::toQImage(*height_data)); gpu_quad.tiles[i].height = std::make_shared>( std::move(heightraster)); } @@ -302,6 +301,13 @@ std::vector Scheduler::tiles_for_current_camera_position() const return all_inner_nodes; } +nucleus::utils::CompressedTexture::Algorithm Scheduler::ortho_tile_compression_algorithm() const { return m_ortho_tile_compression_algorithm; } + +void Scheduler::set_ortho_tile_compression_algorithm(nucleus::utils::CompressedTexture::Algorithm new_ortho_tile_compression_algorithm) +{ + m_ortho_tile_compression_algorithm = new_ortho_tile_compression_algorithm; +} + void Scheduler::set_retirement_age_for_tile_cache(unsigned int new_retirement_age_for_tile_cache) { m_retirement_age_for_tile_cache = new_retirement_age_for_tile_cache; diff --git a/nucleus/tile_scheduler/Scheduler.h b/nucleus/tile_scheduler/Scheduler.h index 96032a1d..9856be0f 100644 --- a/nucleus/tile_scheduler/Scheduler.h +++ b/nucleus/tile_scheduler/Scheduler.h @@ -23,10 +23,9 @@ #include #include +#include "Cache.h" #include "nucleus/camera/Definition.h" #include "radix/tile.h" - -#include "Cache.h" #include "tile_types.h" class QTimer; @@ -78,6 +77,9 @@ class Scheduler : public QObject { void set_retirement_age_for_tile_cache(unsigned int new_retirement_age_for_tile_cache); + nucleus::utils::CompressedTexture::Algorithm ortho_tile_compression_algorithm() const; + void set_ortho_tile_compression_algorithm(nucleus::utils::CompressedTexture::Algorithm new_ortho_tile_compression_algorithm); + signals: void statistics_updated(Statistics stats); void quad_received(const tile::Id& ids); @@ -122,5 +124,6 @@ public slots: Cache m_gpu_cached; std::shared_ptr m_default_ortho_tile; std::shared_ptr m_default_height_tile; + nucleus::utils::CompressedTexture::Algorithm m_ortho_tile_compression_algorithm = nucleus::utils::CompressedTexture::Algorithm::Uncompressed_RGBA; }; } diff --git a/nucleus/tile_scheduler/tile_types.h b/nucleus/tile_scheduler/tile_types.h index 7d3f42e2..bbad72a5 100644 --- a/nucleus/tile_scheduler/tile_types.h +++ b/nucleus/tile_scheduler/tile_types.h @@ -18,11 +18,12 @@ #pragma once -#include "nucleus/tile_scheduler/utils.h" -#include "radix/tile.h" - #include +#include "nucleus/tile_scheduler/utils.h" +#include "nucleus/utils/texture_compression.h" +#include + class QImage; namespace nucleus { template @@ -102,7 +103,7 @@ static_assert(NamedTile); struct GpuLayeredTile { tile::Id id; tile::SrsAndHeightBounds bounds = {}; - std::shared_ptr ortho; + std::shared_ptr ortho; std::shared_ptr> height; std::shared_ptr height_image; }; diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/texture_compression.cpp index d004cd8c..488de187 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/texture_compression.cpp @@ -21,7 +21,8 @@ #include "texture_compression.h" -std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& qimage) +namespace { +std::vector to_dxt1(const QImage& qimage) { if (qimage.format() != QImage::Format_RGBA8888 && qimage.format() != QImage::Format_RGBX8888) { // format is ARGB32 most of the time. we could implement on-the-fly transformation in goofy::compressDXT1 if this is too slow. @@ -56,7 +57,7 @@ std::vector nucleus::utils::texture_compression::to_dxt1(const QImage& return compressed; } -std::vector nucleus::utils::texture_compression::to_etc1(const QImage& qimage) +std::vector to_etc1(const QImage& qimage) { if (qimage.format() != QImage::Format_RGBA8888 && qimage.format() != QImage::Format_RGBX8888) { // format is ARGB32 most of the time. we could implement on-the-fly transformation in goofy::compressDXT1 if this is too slow. @@ -91,8 +92,26 @@ std::vector nucleus::utils::texture_compression::to_etc1(const QImage& return compressed; } -std::vector nucleus::utils::texture_compression::to_compressed(const QImage& image, Algorithm algorithm) +std::vector to_uncompressed_rgba(const QImage& qimage) { + if (qimage.format() != QImage::Format_RGBA8888 && qimage.format() != QImage::Format_RGBX8888) { + // qimage.save("to_uncompressed_rgba1.png"); + return to_uncompressed_rgba(qimage.convertedTo(QImage::Format_RGBA8888)); + } + assert(qimage.sizeInBytes() == qimage.width() * qimage.height() * 4); + std::vector data; + data.resize(size_t(qimage.sizeInBytes())); + auto* data_ptr = reinterpret_cast(data.data()); + const auto* bits = qimage.constScanLine(0); + Q_UNUSED(bits); + std::copy(qimage.constBits(), qimage.constBits() + qimage.sizeInBytes(), data_ptr); + return data; +} + +std::vector to_compressed(const QImage& image, nucleus::utils::CompressedTexture::Algorithm algorithm) +{ + using Algorithm = nucleus::utils::CompressedTexture::Algorithm; + switch (algorithm) { case Algorithm::DXT1: return to_dxt1(image); @@ -104,19 +123,12 @@ std::vector nucleus::utils::texture_compression::to_compressed(const QI assert(false); return to_uncompressed_rgba(image); } +} // namespace -std::vector nucleus::utils::texture_compression::to_uncompressed_rgba(const QImage& qimage) +nucleus::utils::CompressedTexture::CompressedTexture(const QImage& image, Algorithm algorithm) + : m_data(to_compressed(image, algorithm)) + , m_width(unsigned(image.width())) + , m_height(unsigned(image.height())) + , m_algorithm(algorithm) { - if (qimage.format() != QImage::Format_RGBA8888 && qimage.format() != QImage::Format_RGBX8888) { - qimage.save("to_uncompressed_rgba1.png"); - return to_uncompressed_rgba(qimage.convertedTo(QImage::Format_RGBA8888)); - } - assert(qimage.sizeInBytes() == qimage.width() * qimage.height() * 4); - std::vector data; - data.resize(size_t(qimage.sizeInBytes())); - auto* data_ptr = reinterpret_cast(data.data()); - const auto* bits = qimage.constScanLine(0); - Q_UNUSED(bits); - std::copy(qimage.constBits(), qimage.constBits() + qimage.sizeInBytes(), data_ptr); - return data; } diff --git a/nucleus/utils/texture_compression.h b/nucleus/utils/texture_compression.h index 599fd03b..40ce9cd7 100644 --- a/nucleus/utils/texture_compression.h +++ b/nucleus/utils/texture_compression.h @@ -21,13 +21,24 @@ #include #include -namespace nucleus::utils::texture_compression { +namespace nucleus::utils { -enum class Algorithm { Uncompressed_RGBA, DXT1, ETC1 }; +class CompressedTexture { +public: + enum class Algorithm { Uncompressed_RGBA, DXT1, ETC1 }; -std::vector to_dxt1(const QImage& image); -std::vector to_etc1(const QImage& image); -std::vector to_uncompressed_rgba(const QImage& image); +private: + std::vector m_data; + unsigned m_width = 0; + unsigned m_height = 0; + Algorithm m_algorithm = Algorithm::Uncompressed_RGBA; -std::vector to_compressed(const QImage& image, Algorithm algorithm); -} +public: + explicit CompressedTexture(const QImage& image, Algorithm algorithm); + const uint8_t* data() const { return m_data.data(); } + size_t n_bytes() const { return m_data.size(); } + unsigned width() const { return m_width; } + unsigned height() const { return m_height; } +}; + +} // namespace nucleus::utils diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/compressed_textures.cpp index 426d752a..668468be 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/compressed_textures.cpp @@ -88,12 +88,16 @@ TEST_CASE("gl compressed textures") SECTION("compression") { { - const auto compressed = texture_compression::to_dxt1(test_texture); - CHECK(compressed.size() == 256 * 128); + const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::DXT1); + CHECK(compressed.n_bytes() == 256 * 128); } { - const auto compressed = texture_compression::to_etc1(test_texture); - CHECK(compressed.size() == 256 * 128); + const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::ETC1); + CHECK(compressed.n_bytes() == 256 * 128); + } + { + const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::Uncompressed_RGBA); + CHECK(compressed.n_bytes() == 256 * 256 * 4); } } @@ -139,7 +143,7 @@ TEST_CASE("gl compressed textures") Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); b.bind(); - const auto compressed = texture_compression::to_compressed(test_texture, gl_engine::Texture::compression_algorithm()); + const auto compressed = CompressedTexture(test_texture, gl_engine::Texture::compression_algorithm()); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); opengl_texture.bind(0); f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -147,14 +151,8 @@ TEST_CASE("gl compressed textures") f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - f->glCompressedTexImage2D(GL_TEXTURE_2D, - 0, - gl_engine::Texture::compressed_texture_format(), - test_texture.width(), - test_texture.height(), - 0, - compressed.size(), - compressed.data()); + f->glCompressedTexImage2D(GL_TEXTURE_2D, 0, gl_engine::Texture::compressed_texture_format(), test_texture.width(), test_texture.height(), 0, + compressed.n_bytes(), compressed.data()); ShaderProgram shader = create_debug_shader(R"( uniform sampler2D texture_sampler; @@ -189,7 +187,7 @@ TEST_CASE("gl compressed textures") Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); b.bind(); - const auto compressed = texture_compression::to_compressed(test_texture, texture_compression::Algorithm::Uncompressed_RGBA); + const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::Uncompressed_RGBA); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); opengl_texture.bind(0); f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); From a3ac53333d72a6ed3ccbd7b27f862a9b1f97315c Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 21:36:59 +0100 Subject: [PATCH 27/65] refactor textures #2 --- gl_engine/Texture.cpp | 70 +++++++++- gl_engine/Texture.h | 16 ++- nucleus/AbstractRenderWindow.h | 2 +- nucleus/CMakeLists.txt | 2 +- nucleus/tile_scheduler/tile_types.h | 2 +- ..._compression.cpp => CompressedTexture.cpp} | 2 +- ...ture_compression.h => CompressedTexture.h} | 9 +- unittests/gl_engine/CMakeLists.txt | 2 +- .../{compressed_textures.cpp => texture.cpp} | 132 +++++++++++------- 9 files changed, 175 insertions(+), 62 deletions(-) rename nucleus/utils/{texture_compression.cpp => CompressedTexture.cpp} (99%) rename nucleus/utils/{texture_compression.h => CompressedTexture.h} (79%) rename unittests/gl_engine/{compressed_textures.cpp => texture.cpp} (67%) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 6fe3602f..57a3205f 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -17,7 +17,7 @@ *****************************************************************************/ #include "Texture.h" -#include "nucleus/utils/texture_compression.h" +#include "nucleus/utils/CompressedTexture.h" #include #ifdef __EMSCRIPTEN__ @@ -28,8 +28,9 @@ #include #endif -gl_engine::Texture::Texture(Target target) +gl_engine::Texture::Texture(Target target, Format format) : m_target(target) + , m_format(format) { QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glGenTextures(1, &m_id); @@ -50,6 +51,71 @@ void gl_engine::Texture::bind(unsigned int texture_unit) f->glBindTexture(GLenum(m_target), m_id); } +void gl_engine::Texture::setParams(Filter min_filter, Filter mag_filter) +{ + assert(mag_filter != Filter::MipMapLinear); // doesn't make sense, does it? + assert(m_format != Format::CompressedRGBA8 || min_filter != Filter::MipMapLinear); // add upload functionality for compressed mipmaps to support this + m_min_filter = min_filter; + m_mag_filter = mag_filter; + + QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); + f->glBindTexture(GLenum(m_target), m_id); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(m_min_filter)); + f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(m_mag_filter)); +} + +void gl_engine::Texture::upload(const nucleus::utils::CompressedTexture& texture) +{ + QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); + f->glBindTexture(GLenum(m_target), m_id); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + switch (m_format) { + case Format::CompressedRGBA8: + f->glCompressedTexImage2D(GLenum(m_target), 0, gl_engine::Texture::compressed_texture_format(), GLsizei(texture.width()), GLsizei(texture.height()), 0, + GLsizei(texture.n_bytes()), texture.data()); + return; + case Format::RGBA8: + f->glTexImage2D(GLenum(m_target), 0, GL_RGBA8, GLsizei(texture.width()), GLsizei(texture.height()), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.data()); + if (m_min_filter == Filter::MipMapLinear) + f->glGenerateMipmap(GLenum(m_target)); + return; + case Format::RG8: + case Format::R16UI: + case Format::Invalid: + assert(false); + break; + } + assert(false); +} + +void gl_engine::Texture::upload(const nucleus::Raster& texture) +{ + assert(m_format == Format::RG8); + + QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); + f->glBindTexture(GLenum(m_target), m_id); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + f->glTexImage2D(GLenum(m_target), 0, GL_RG8, GLsizei(texture.width()), GLsizei(texture.height()), 0, GL_RG, GL_UNSIGNED_BYTE, texture.bytes()); + + if (m_min_filter == Filter::MipMapLinear) + f->glGenerateMipmap(GLenum(m_target)); +} + +void gl_engine::Texture::upload(const nucleus::Raster& texture) +{ + assert(m_format == Format::R16UI); + + QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); + f->glBindTexture(GLenum(m_target), m_id); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + f->glTexImage2D(GLenum(m_target), 0, GL_R16UI, GLsizei(texture.width()), GLsizei(texture.height()), 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, texture.bytes()); + + // not Texture filterable according to https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml + assert(m_min_filter != Filter::MipMapLinear); +} + GLenum gl_engine::Texture::compressed_texture_format() { // select between diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index 404411be..753da93f 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -19,29 +19,41 @@ #pragma once #include -#include #include +#include +#include + namespace gl_engine { class Texture { public: enum class Target : GLenum { _2d = GL_TEXTURE_2D, _2dArray = GL_TEXTURE_2D_ARRAY }; + enum class Format { RGBA8, CompressedRGBA8, RG8, R16UI, Invalid = -1 }; + enum class Filter : GLint { Nearest = GL_NEAREST, Linear = GL_LINEAR, MipMapLinear = GL_LINEAR_MIPMAP_LINEAR }; public: Texture(const Texture&) = delete; Texture(Texture&&) = delete; Texture& operator=(const Texture&) = delete; Texture& operator=(Texture&&) = delete; - explicit Texture(Target target); + explicit Texture(Target target, Format format = Format::Invalid); ~Texture(); void bind(unsigned texture_unit); + void setParams(Filter min_filter, Filter mag_filter); + void upload(const nucleus::utils::CompressedTexture& texture); + void upload(const nucleus::Raster& texture); + void upload(const nucleus::Raster& texture); + static GLenum compressed_texture_format(); static nucleus::utils::CompressedTexture::Algorithm compression_algorithm(); private: GLuint m_id = GLuint(-1); Target m_target = Target::_2d; + Format m_format = Format::Invalid; + Filter m_min_filter = Filter::Nearest; + Filter m_mag_filter = Filter::Nearest; }; } // namespace gl_engine diff --git a/nucleus/AbstractRenderWindow.h b/nucleus/AbstractRenderWindow.h index 761fd604..e80e6051 100644 --- a/nucleus/AbstractRenderWindow.h +++ b/nucleus/AbstractRenderWindow.h @@ -24,7 +24,7 @@ #include #include "nucleus/tile_scheduler/tile_types.h" -#include "utils/texture_compression.h" +#include "utils/CompressedTexture.h" class QOpenGLFramebufferObject; diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index 8e7de3f5..c9b5608b 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -101,7 +101,7 @@ qt_add_library(nucleus STATIC timing/TimerManager.h timing/TimerManager.cpp timing/TimerInterface.h timing/TimerInterface.cpp timing/CpuTimer.h timing/CpuTimer.cpp - utils/texture_compression.h utils/texture_compression.cpp + utils/CompressedTexture.h utils/CompressedTexture.cpp ) target_include_directories(nucleus PUBLIC ${CMAKE_SOURCE_DIR}) diff --git a/nucleus/tile_scheduler/tile_types.h b/nucleus/tile_scheduler/tile_types.h index bbad72a5..5dce6cd2 100644 --- a/nucleus/tile_scheduler/tile_types.h +++ b/nucleus/tile_scheduler/tile_types.h @@ -21,7 +21,7 @@ #include #include "nucleus/tile_scheduler/utils.h" -#include "nucleus/utils/texture_compression.h" +#include "nucleus/utils/CompressedTexture.h" #include class QImage; diff --git a/nucleus/utils/texture_compression.cpp b/nucleus/utils/CompressedTexture.cpp similarity index 99% rename from nucleus/utils/texture_compression.cpp rename to nucleus/utils/CompressedTexture.cpp index 488de187..93f4303a 100644 --- a/nucleus/utils/texture_compression.cpp +++ b/nucleus/utils/CompressedTexture.cpp @@ -19,7 +19,7 @@ #define GOOFYTC_IMPLEMENTATION #include -#include "texture_compression.h" +#include "CompressedTexture.h" namespace { std::vector to_dxt1(const QImage& qimage) diff --git a/nucleus/utils/texture_compression.h b/nucleus/utils/CompressedTexture.h similarity index 79% rename from nucleus/utils/texture_compression.h rename to nucleus/utils/CompressedTexture.h index 40ce9cd7..cc78c404 100644 --- a/nucleus/utils/texture_compression.h +++ b/nucleus/utils/CompressedTexture.h @@ -35,10 +35,11 @@ class CompressedTexture { public: explicit CompressedTexture(const QImage& image, Algorithm algorithm); - const uint8_t* data() const { return m_data.data(); } - size_t n_bytes() const { return m_data.size(); } - unsigned width() const { return m_width; } - unsigned height() const { return m_height; } + [[nodiscard]] const uint8_t* data() const { return m_data.data(); } + [[nodiscard]] size_t n_bytes() const { return m_data.size(); } + [[nodiscard]] unsigned width() const { return m_width; } + [[nodiscard]] unsigned height() const { return m_height; } + [[nodiscard]] Algorithm algorithm() const { return m_algorithm; } }; } // namespace nucleus::utils diff --git a/unittests/gl_engine/CMakeLists.txt b/unittests/gl_engine/CMakeLists.txt index 67685ec6..6774568b 100644 --- a/unittests/gl_engine/CMakeLists.txt +++ b/unittests/gl_engine/CMakeLists.txt @@ -23,7 +23,7 @@ alp_add_unittest(unittests_gl_engine UnittestGLContext.h UnittestGLContext.cpp framebuffer.cpp uniformbuffer.cpp - compressed_textures.cpp + texture.cpp ) target_link_libraries(unittests_gl_engine PUBLIC gl_engine) diff --git a/unittests/gl_engine/compressed_textures.cpp b/unittests/gl_engine/texture.cpp similarity index 67% rename from unittests/gl_engine/compressed_textures.cpp rename to unittests/gl_engine/texture.cpp index 668468be..5a58df7b 100644 --- a/unittests/gl_engine/compressed_textures.cpp +++ b/unittests/gl_engine/texture.cpp @@ -32,7 +32,7 @@ #include "gl_engine/Framebuffer.h" #include "gl_engine/ShaderProgram.h" #include "gl_engine/helpers.h" -#include "nucleus/utils/texture_compression.h" +#include "nucleus/utils/CompressedTexture.h" using gl_engine::Framebuffer; using gl_engine::ShaderProgram; @@ -50,16 +50,19 @@ namespace { ShaderProgram create_debug_shader(const char* fragmentShaderOverride = nullptr) { static const char* const fragment_source = R"( - out lowp vec4 out_Color; - void main() { - out_Color = vec4(0.2, 0.0, 1.0, 0.8); - })"; + uniform sampler2D texture_sampler; + in highp vec2 texcoords; + out lowp vec4 out_color; + void main() { + out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); + } + )"; ShaderProgram tmp(vertex_source, fragmentShaderOverride ? fragmentShaderOverride : fragment_source, gl_engine::ShaderCodeSource::PLAINTEXT); return tmp; } } // namespace -TEST_CASE("gl compressed textures") +TEST_CASE("gl texture") { UnittestGLContext::initialise(); @@ -110,14 +113,7 @@ TEST_CASE("gl compressed textures") opengl_texture.setMinMagFilters(QOpenGLTexture::Filter::Nearest, QOpenGLTexture::Filter::Nearest); opengl_texture.bind(); - ShaderProgram shader = create_debug_shader(R"( - uniform sampler2D texture_sampler; - in highp vec2 texcoords; - out lowp vec4 out_color; - void main() { - out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); - } - )"); + ShaderProgram shader = create_debug_shader(); shader.bind(); gl_engine::helpers::create_screen_quad_geometry().draw(); @@ -138,30 +134,18 @@ TEST_CASE("gl compressed textures") CHECK(diff / (256 * 256 * 3) < 0.001); } - SECTION("compression") + SECTION("compressed rgba") { - Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); + Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); b.bind(); const auto compressed = CompressedTexture(test_texture, gl_engine::Texture::compression_algorithm()); - gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::CompressedRGBA8); opengl_texture.bind(0); - f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - f->glCompressedTexImage2D(GL_TEXTURE_2D, 0, gl_engine::Texture::compressed_texture_format(), test_texture.width(), test_texture.height(), 0, - compressed.n_bytes(), compressed.data()); + opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); + opengl_texture.upload(compressed); - ShaderProgram shader = create_debug_shader(R"( - uniform sampler2D texture_sampler; - in highp vec2 texcoords; - out lowp vec4 out_color; - void main() { - out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); - } - )"); + ShaderProgram shader = create_debug_shader(); shader.bind(); gl_engine::helpers::create_screen_quad_geometry().draw(); @@ -182,34 +166,23 @@ TEST_CASE("gl compressed textures") CHECK(diff / (256 * 256 * 3) < 0.017); } - SECTION("not compression") + SECTION("rgba") { Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); b.bind(); const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::Uncompressed_RGBA); - gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d); + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::RGBA8); opengl_texture.bind(0); - f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, test_texture.width(), test_texture.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, compressed.data()); + opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); + opengl_texture.upload(compressed); - ShaderProgram shader = create_debug_shader(R"( - uniform sampler2D texture_sampler; - in highp vec2 texcoords; - out lowp vec4 out_color; - void main() { - out_color = texture(texture_sampler, vec2(texcoords.x, 1.0 - texcoords.y)); - } - )"); + ShaderProgram shader = create_debug_shader(); shader.bind(); gl_engine::helpers::create_screen_quad_geometry().draw(); const QImage render_result = b.read_colour_attachment(0); - render_result.save("render_result.png"); + // render_result.save("render_result.png"); Framebuffer::unbind(); REQUIRE(!render_result.isNull()); CHECK(render_result.width() == test_texture.width()); @@ -224,4 +197,65 @@ TEST_CASE("gl compressed textures") } CHECK(diff / (256 * 256 * 3) < 0.001); } + + SECTION("rg8") + { + Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 1, 1 }); + b.bind(); + + const auto tex = nucleus::Raster({ 1, 1 }, glm::u8vec2(240, 120)); + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::RG8); + opengl_texture.bind(0); + opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); + opengl_texture.upload(tex); + + ShaderProgram shader = create_debug_shader(); + shader.bind(); + gl_engine::helpers::create_screen_quad_geometry().draw(); + + const QImage render_result = b.read_colour_attachment(0); + // render_result.save("render_result.png"); + Framebuffer::unbind(); + REQUIRE(!render_result.isNull()); + CHECK(render_result.width() == 1); + CHECK(render_result.height() == 1); + CHECK(qRed(render_result.pixel(0, 0)) == 240); + CHECK(qGreen(render_result.pixel(0, 0)) == 120); + CHECK(qBlue(render_result.pixel(0, 0)) == 0); + CHECK(qAlpha(render_result.pixel(0, 0)) == 255); + } + + SECTION("red16") + { + Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 1, 1 }); + b.bind(); + + const auto tex = nucleus::Raster({ 1, 1 }, uint16_t(120 * 256)); + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::R16UI); + opengl_texture.bind(0); + opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); + opengl_texture.upload(tex); + + ShaderProgram shader = create_debug_shader(R"( + uniform usampler2D texture_sampler; + in highp vec2 texcoords; + out lowp vec4 out_color; + void main() { + out_color = vec4(float(texture(texture_sampler, vec2(0.5, 0.5)).r) / 65535.0, 0, 0, 1); + } + )"); + shader.bind(); + gl_engine::helpers::create_screen_quad_geometry().draw(); + + const QImage render_result = b.read_colour_attachment(0); + // render_result.save("render_result.png"); + Framebuffer::unbind(); + REQUIRE(!render_result.isNull()); + CHECK(render_result.width() == 1); + CHECK(render_result.height() == 1); + CHECK(qRed(render_result.pixel(0, 0)) == 120); + CHECK(qGreen(render_result.pixel(0, 0)) == 0); + CHECK(qBlue(render_result.pixel(0, 0)) == 0); + CHECK(qAlpha(render_result.pixel(0, 0)) == 255); + } } From cc00d2173ed8cd9a8958e37bf885a7160ad53e75 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:25:03 +0100 Subject: [PATCH 28/65] red16 texture on all platforms --- gl_engine/Texture.cpp | 11 +++++++++-- gl_engine/TileManager.cpp | 13 ++----------- unittests/gl_engine/texture.cpp | 8 +++++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 57a3205f..8c5f18f8 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -53,8 +53,15 @@ void gl_engine::Texture::bind(unsigned int texture_unit) void gl_engine::Texture::setParams(Filter min_filter, Filter mag_filter) { - assert(mag_filter != Filter::MipMapLinear); // doesn't make sense, does it? - assert(m_format != Format::CompressedRGBA8 || min_filter != Filter::MipMapLinear); // add upload functionality for compressed mipmaps to support this + // doesn't make sense, does it? + assert(mag_filter != Filter::MipMapLinear); + + // add upload functionality for compressed mipmaps to support this + assert(m_format != Format::CompressedRGBA8 || min_filter != Filter::MipMapLinear); + + // webgl supports only nearest filtering for R16UI + assert(m_format != Format::R16UI || (min_filter == Filter::Nearest && mag_filter == Filter::Nearest)); + m_min_filter = min_filter; m_mag_filter = mag_filter; diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index 68482b43..fc2c641a 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -213,17 +213,8 @@ void TileManager::add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, } tileset.vao->release(); tileset.ortho_texture = std::make_unique(Texture::Target::_2d); - f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ORTHO_RESOLUTION, ORTHO_RESOLUTION, 0, GL_RGBA, GL_UNSIGNED_BYTE, ortho_texture.data()); - - // tileset.ortho_texture->setMaximumAnisotropy(m_max_anisotropy); - // tileset.ortho_texture->setWrapMode(QOpenGLTexture::WrapMode::ClampToEdge); - // tileset.ortho_texture->setMinMagFilters(QOpenGLTexture::Filter::LinearMipMapLinear, QOpenGLTexture::Filter::Linear); - // tileset.ortho_texture->generateMipMaps(); + tileset.ortho_texture->setParams(Texture::Filter::Linear, Texture::Filter::Linear); + tileset.ortho_texture->upload(ortho_texture); tileset.heightmap_texture = std::make_unique(height_texture); tileset.heightmap_texture->setWrapMode(QOpenGLTexture::WrapMode::ClampToEdge); diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index 5a58df7b..a9dd747f 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -233,15 +233,17 @@ TEST_CASE("gl texture") const auto tex = nucleus::Raster({ 1, 1 }, uint16_t(120 * 256)); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::R16UI); opengl_texture.bind(0); - opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); + opengl_texture.setParams(gl_engine::Texture::Filter::Nearest, gl_engine::Texture::Filter::Nearest); opengl_texture.upload(tex); ShaderProgram shader = create_debug_shader(R"( - uniform usampler2D texture_sampler; + uniform mediump usampler2D texture_sampler; in highp vec2 texcoords; out lowp vec4 out_color; void main() { - out_color = vec4(float(texture(texture_sampler, vec2(0.5, 0.5)).r) / 65535.0, 0, 0, 1); + mediump uint v = texture(texture_sampler, vec2(0.5, 0.5)).r; + highp float v2 = float(v); // need temporary for android, otherwise it is cast to a mediump float and 0 is returned. + out_color = vec4(v2 / 65535.0, 0, 0, 1); } )"); shader.bind(); From 01b26bb9f3869abc6f2579d979d2df06a70f6c2d Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 19 Feb 2024 00:45:24 +0100 Subject: [PATCH 29/65] remove obsolete code --- unittests/nucleus/nucleus_tile_scheduler_cache.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/unittests/nucleus/nucleus_tile_scheduler_cache.cpp b/unittests/nucleus/nucleus_tile_scheduler_cache.cpp index a6631d10..c0b0355a 100644 --- a/unittests/nucleus/nucleus_tile_scheduler_cache.cpp +++ b/unittests/nucleus/nucleus_tile_scheduler_cache.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include From 5fc248f18bac83e3d06806648e18fc63d2075f01 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 19 Feb 2024 00:46:01 +0100 Subject: [PATCH 30/65] enable texture compression + remove texture default invalid format. --- app/TerrainRenderer.cpp | 3 ++- gl_engine/MapLabelManager.cpp | 11 +++-------- gl_engine/Texture.h | 2 +- gl_engine/TileManager.cpp | 4 +++- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/app/TerrainRenderer.cpp b/app/TerrainRenderer.cpp index e65e4ae9..d799c90a 100644 --- a/app/TerrainRenderer.cpp +++ b/app/TerrainRenderer.cpp @@ -28,12 +28,13 @@ #include "gl_engine/Window.h" #include "nucleus/Controller.h" #include "nucleus/camera/Controller.h" - +#include "nucleus/tile_scheduler/Scheduler.h" TerrainRenderer::TerrainRenderer() { m_glWindow = std::make_unique(); m_controller = std::make_unique(m_glWindow.get()); + m_controller->tile_scheduler()->set_ortho_tile_compression_algorithm(m_glWindow->ortho_tile_compression_algorithm()); m_glWindow->initialise_gpu(); #ifdef ALP_ENABLE_TRACK_OBJECT_LIFECYCLE qDebug("TerrainRendererItemRenderer()"); diff --git a/gl_engine/MapLabelManager.cpp b/gl_engine/MapLabelManager.cpp index 21a027ff..3f7bcec4 100644 --- a/gl_engine/MapLabelManager.cpp +++ b/gl_engine/MapLabelManager.cpp @@ -80,14 +80,9 @@ void MapLabelManager::init() // load the font texture const auto& font_atlas = m_mapLabelManager.font_atlas(); - m_font_texture = std::make_unique(Texture::Target::_2d); - f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, font_atlas.width(), font_atlas.height(), 0, GL_RG, GL_UNSIGNED_BYTE, font_atlas.bytes()); - f->glGenerateMipmap(GL_TEXTURE_2D); + m_font_texture = std::make_unique(Texture::Target::_2d, Texture::Format::RG8); + m_font_texture->setParams(Texture::Filter::MipMapLinear, Texture::Filter::Linear); + m_font_texture->upload(font_atlas); // load the icon texture QImage icon = m_mapLabelManager.icon(); diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index 753da93f..f651268b 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -36,7 +36,7 @@ class Texture { Texture(Texture&&) = delete; Texture& operator=(const Texture&) = delete; Texture& operator=(Texture&&) = delete; - explicit Texture(Target target, Format format = Format::Invalid); + explicit Texture(Target target, Format format); ~Texture(); void bind(unsigned texture_unit); diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index fc2c641a..86f0c56d 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -212,7 +212,9 @@ void TileManager::add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, tileset.gl_index_type = GL_UNSIGNED_SHORT; } tileset.vao->release(); - tileset.ortho_texture = std::make_unique(Texture::Target::_2d); + tileset.ortho_texture = std::make_unique(Texture::Target::_2d, + ortho_texture.algorithm() == nucleus::utils::CompressedTexture::Algorithm::Uncompressed_RGBA ? Texture::Format::RGBA8 + : Texture::Format::CompressedRGBA8); tileset.ortho_texture->setParams(Texture::Filter::Linear, Texture::Filter::Linear); tileset.ortho_texture->upload(ortho_texture); From a6d4d18476741249dca311385751dd27c3013ad9 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:23:37 +0100 Subject: [PATCH 31/65] switch to red16bit texture for height map. remove qimage/qopengltexture for heightmap --- gl_engine/TileManager.cpp | 38 +++++++++++++++------------- gl_engine/TileManager.h | 5 ++-- gl_engine/TileSet.h | 3 +-- gl_engine/shaders/tile.vert | 27 ++++++++++---------- nucleus/tile_scheduler/Scheduler.cpp | 3 --- nucleus/tile_scheduler/tile_types.h | 1 - 6 files changed, 38 insertions(+), 39 deletions(-) diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index 86f0c56d..bfae3e6f 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -181,14 +181,14 @@ void TileManager::set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbD m_draw_list_generator.set_aabb_decorator(new_aabb_decorator); } -void TileManager::add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::CompressedTexture& ortho_texture, - const nucleus::Raster& height_map, const QImage& height_texture) +void TileManager::add_tile( + const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::CompressedTexture& ortho_texture, const nucleus::Raster& height_map) { if (!QOpenGLContext::currentContext()) // can happen during shutdown. return; - assert(m_attribute_locations.height != -1); - auto* f = QOpenGLContext::currentContext()->extraFunctions(); + // assert(m_attribute_locations.height != -1); + // auto* f = QOpenGLContext::currentContext()->extraFunctions(); // need to call GLWindow::makeCurrent, when calling through signals? // find an empty slot => todo, for now just create a new tile every time. // setup / copy data to gpu @@ -197,15 +197,20 @@ void TileManager::add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, tileset.vao = std::make_unique(); tileset.vao->create(); tileset.vao->bind(); + // if (!m_dummy_buffer) { + // m_dummy_buffer = std::make_unique(QOpenGLBuffer::VertexBuffer); + // m_dummy_buffer->create(); + // m_dummy_buffer->bind(); + // m_dummy_buffer->setUsagePattern(QOpenGLBuffer::StaticDraw); + // // std::vector dummy(m_index_buffers.size()); + // m_dummy_buffer->allocate(int(m_index_buffers.size())); + // } { // vao state - tileset.heightmap_buffer = std::make_unique(QOpenGLBuffer::VertexBuffer); - tileset.heightmap_buffer->create(); - tileset.heightmap_buffer->bind(); - tileset.heightmap_buffer->setUsagePattern(QOpenGLBuffer::StaticDraw); - auto height_buffer = prepare_altitude_buffer(height_map); - tileset.heightmap_buffer->allocate(height_buffer.data(), bufferLengthInBytes(height_buffer)); - f->glEnableVertexAttribArray(GLuint(m_attribute_locations.height)); - f->glVertexAttribPointer(GLuint(m_attribute_locations.height), /*size*/ 1, /*type*/ GL_UNSIGNED_SHORT, /*normalised*/ GL_TRUE, /*stride*/ 0, nullptr); + // auto height_buffer = prepare_altitude_buffer(height_map); + // tileset.heightmap_buffer->allocate(height_buffer.data(), bufferLengthInBytes(height_buffer)); + // f->glEnableVertexAttribArray(GLuint(m_attribute_locations.height)); + // f->glVertexAttribPointer(GLuint(m_attribute_locations.height), /*size*/ 1, /*type*/ GL_UNSIGNED_SHORT, /*normalised*/ GL_TRUE, /*stride*/ 0, + // nullptr); m_index_buffers[0].first->bind(); tileset.gl_element_count = int(m_index_buffers[0].second); @@ -218,9 +223,9 @@ void TileManager::add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, tileset.ortho_texture->setParams(Texture::Filter::Linear, Texture::Filter::Linear); tileset.ortho_texture->upload(ortho_texture); - tileset.heightmap_texture = std::make_unique(height_texture); - tileset.heightmap_texture->setWrapMode(QOpenGLTexture::WrapMode::ClampToEdge); - tileset.heightmap_texture->setMinMagFilters(QOpenGLTexture::Filter::Nearest, QOpenGLTexture::Filter::Nearest); + tileset.heightmap_texture = std::make_unique(Texture::Target::_2d, Texture::Format::R16UI); + tileset.heightmap_texture->setParams(Texture::Filter::Nearest, Texture::Filter::Nearest); + tileset.heightmap_texture->upload(height_map); // add to m_gpu_tiles m_gpu_tiles.push_back(std::move(tileset)); @@ -242,8 +247,7 @@ void TileManager::update_gpu_quads(const std::vector& heights, - const QImage& height_texture); + void add_tile( + const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::CompressedTexture& ortho, const nucleus::Raster& heights); struct TileGLAttributeLocations { int height = -1; }; @@ -79,6 +79,7 @@ public slots: // for 4 tiles take index 1, for 16 2.. // the size_t is the number of indices std::vector, size_t>> m_index_buffers; + std::unique_ptr m_dummy_buffer; TileGLAttributeLocations m_attribute_locations; unsigned m_tiles_per_set = 1; nucleus::tile_scheduler::DrawListGenerator m_draw_list_generator; diff --git a/gl_engine/TileSet.h b/gl_engine/TileSet.h index 033707f8..bebd302f 100644 --- a/gl_engine/TileSet.h +++ b/gl_engine/TileSet.h @@ -47,8 +47,7 @@ struct TileSet { }; std::unique_ptr ortho_texture; - std::unique_ptr heightmap_buffer; - std::unique_ptr heightmap_texture; + std::unique_ptr heightmap_texture; std::unique_ptr vao; std::vector> tiles; int gl_element_count = -1; diff --git a/gl_engine/shaders/tile.vert b/gl_engine/shaders/tile.vert index 613810e0..21b02ba7 100644 --- a/gl_engine/shaders/tile.vert +++ b/gl_engine/shaders/tile.vert @@ -21,13 +21,11 @@ #include "hashing.glsl" #include "camera_config.glsl" -layout(location = 0) in highp float altitude; - uniform highp vec4 bounds[32]; uniform highp int n_edge_vertices; uniform highp int tileset_id; uniform highp int tileset_zoomlevel; -uniform highp sampler2D height_sampler; +uniform mediump usampler2D height_sampler; out highp vec2 uv; out highp vec3 var_pos_cws; @@ -46,18 +44,18 @@ highp float y_to_lat(highp float y) { return latRad; } -highp float altitude_from_color(highp vec4 color) { - return (color.r + color.g / 255.0); -} - highp vec3 normal_by_finite_difference_method(vec2 uv, float edge_vertices_count, float tile_width, float tile_height, float altitude_correction_factor) { // from here: https://stackoverflow.com/questions/6656358/calculating-normals-in-a-triangle-mesh/21660173#21660173 vec2 offset = vec2(1.0, 0.0) / (edge_vertices_count); float height = tile_width + tile_height; - float hL = altitude_from_color(texture(height_sampler, uv - offset.xy)) * altitude_correction_factor; - float hR = altitude_from_color(texture(height_sampler, uv + offset.xy)) * altitude_correction_factor; - float hD = altitude_from_color(texture(height_sampler, uv + offset.yx)) * altitude_correction_factor; - float hU = altitude_from_color(texture(height_sampler, uv - offset.yx)) * altitude_correction_factor; + highp float hL = float(texture(height_sampler, uv - offset.xy).r); + hL *= altitude_correction_factor; + highp float hR = float(texture(height_sampler, uv + offset.xy).r); + hR *= altitude_correction_factor; + highp float hD = float(texture(height_sampler, uv + offset.yx).r); + hD *= altitude_correction_factor; + highp float hU = float(texture(height_sampler, uv - offset.yx).r); + hU *= altitude_correction_factor; return normalize(vec3(hL - hR, hD - hU, height)); } @@ -102,11 +100,12 @@ void main() { // Note: May be enough to calculate altitude_correction_factor per tile on CPU: float var_pos_cws_y = float(edge_vertices_count_int - row) * float(tile_width) + bounds[geometry_id].y; float pos_y = var_pos_cws_y + camera.position.y; - float altitude_correction_factor = 65536.0 * 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 + float altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 uv = vec2(float(col) / edge_vertices_count_float, float(row) / edge_vertices_count_float); - float adjusted_altitude = altitude * altitude_correction_factor; + float altitude_tex = float(texture(height_sampler, uv).r); + float adjusted_altitude = altitude_tex * altitude_correction_factor; var_pos_cws = vec3(float(col) * tile_width + bounds[geometry_id].x, var_pos_cws_y, @@ -134,6 +133,6 @@ void main() { case 2u: vertex_color = color_from_id_hash(uint(tileset_id)); break; case 3u: vertex_color = color_from_id_hash(uint(tileset_zoomlevel)); break; case 4u: vertex_color = color_from_id_hash(uint(gl_VertexID)); break; - case 5u: vertex_color = texture(height_sampler, uv).rgb; break; + case 5u: vertex_color = vec3(texture(height_sampler, uv).rrr) / 65535.0; break; } } diff --git a/nucleus/tile_scheduler/Scheduler.cpp b/nucleus/tile_scheduler/Scheduler.cpp index b5db7599..9f030ef6 100644 --- a/nucleus/tile_scheduler/Scheduler.cpp +++ b/nucleus/tile_scheduler/Scheduler.cpp @@ -182,9 +182,6 @@ void Scheduler::update_gpu_quads() if (quad.tiles[i].height->size()) { height_data = quad.tiles[i].height.get(); } - auto heightimage = nucleus::utils::tile_conversion::toQImage(*height_data); - gpu_quad.tiles[i].height_image = std::make_shared(std::move(heightimage)); - // TODO: We dont need height in VBO anymore!!! Delete at some point!! auto heightraster = nucleus::utils::tile_conversion::qImage2uint16Raster(nucleus::utils::tile_conversion::toQImage(*height_data)); gpu_quad.tiles[i].height = std::make_shared>( std::move(heightraster)); diff --git a/nucleus/tile_scheduler/tile_types.h b/nucleus/tile_scheduler/tile_types.h index 5dce6cd2..439aeb76 100644 --- a/nucleus/tile_scheduler/tile_types.h +++ b/nucleus/tile_scheduler/tile_types.h @@ -105,7 +105,6 @@ struct GpuLayeredTile { tile::SrsAndHeightBounds bounds = {}; std::shared_ptr ortho; std::shared_ptr> height; - std::shared_ptr height_image; }; static_assert(NamedTile); From 8b34f2d218ddc93353d5d6296cc0abd2464fcef6 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:47:40 +0100 Subject: [PATCH 32/65] try fix compiler error on msvc --- nucleus/utils/CompressedTexture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/nucleus/utils/CompressedTexture.cpp b/nucleus/utils/CompressedTexture.cpp index 93f4303a..c146c5be 100644 --- a/nucleus/utils/CompressedTexture.cpp +++ b/nucleus/utils/CompressedTexture.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . *****************************************************************************/ +#include #define GOOFYTC_IMPLEMENTATION #include From b9b02b6a14af4508f0d1b3aee1ebae74bd312e16 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:57:44 +0100 Subject: [PATCH 33/65] try fix compiler error on msvc #2 --- nucleus/utils/CompressedTexture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/nucleus/utils/CompressedTexture.cpp b/nucleus/utils/CompressedTexture.cpp index c146c5be..46fd3781 100644 --- a/nucleus/utils/CompressedTexture.cpp +++ b/nucleus/utils/CompressedTexture.cpp @@ -16,6 +16,7 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include #define GOOFYTC_IMPLEMENTATION #include From 32c3425ba33d8107b38da3190695bc13f5da2335 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 20 Feb 2024 13:40:42 +0100 Subject: [PATCH 34/65] remove obsolete data --- gl_engine/TileManager.cpp | 50 ++------------------------------------- gl_engine/TileManager.h | 1 - 2 files changed, 2 insertions(+), 49 deletions(-) diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index bfae3e6f..edf3b6f3 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -50,34 +50,6 @@ std::vector boundsArray(const TileSet& tileset, const glm::dvec3& cam } return ret; } - -template -std::vector prepare_altitude_buffer(const nucleus::Raster& alti_map) -{ - // add heights for curtains - auto alti_buffer = alti_map.buffer(); - alti_buffer.reserve(alti_buffer.size() + alti_map.width() * 2 - 2 + alti_map.height() * 2 - 2); - const auto height = alti_map.height(); - const auto width = alti_map.width(); - - for (size_t row = height - 1; row >= 1; row--) { - alti_buffer.push_back(alti_map.pixel({ width - 1, row })); - } - - for (size_t col = width - 1; col >= 1; col--) { - alti_buffer.push_back(alti_map.pixel({ col, 0 })); - } - - for (size_t row = 0; row < height - 1; row++) { - alti_buffer.push_back(alti_map.pixel({ 0, row })); - } - - for (size_t col = 0; col < width - 1; col++) { - alti_buffer.push_back(alti_map.pixel({ col, height - 1 })); - } - - return alti_buffer; -} } TileManager::TileManager(QObject* parent) @@ -171,10 +143,7 @@ void TileManager::remove_tile(const tile::Id& tile_id) emit tiles_changed(); } -void TileManager::initilise_attribute_locations(ShaderProgram* program) -{ - m_attribute_locations.height = program->attribute_location("altitude"); -} +void TileManager::initilise_attribute_locations(ShaderProgram* /*program*/) { } void TileManager::set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr& new_aabb_decorator) { @@ -187,8 +156,6 @@ void TileManager::add_tile( if (!QOpenGLContext::currentContext()) // can happen during shutdown. return; - // assert(m_attribute_locations.height != -1); - // auto* f = QOpenGLContext::currentContext()->extraFunctions(); // need to call GLWindow::makeCurrent, when calling through signals? // find an empty slot => todo, for now just create a new tile every time. // setup / copy data to gpu @@ -197,21 +164,8 @@ void TileManager::add_tile( tileset.vao = std::make_unique(); tileset.vao->create(); tileset.vao->bind(); - // if (!m_dummy_buffer) { - // m_dummy_buffer = std::make_unique(QOpenGLBuffer::VertexBuffer); - // m_dummy_buffer->create(); - // m_dummy_buffer->bind(); - // m_dummy_buffer->setUsagePattern(QOpenGLBuffer::StaticDraw); - // // std::vector dummy(m_index_buffers.size()); - // m_dummy_buffer->allocate(int(m_index_buffers.size())); - // } - { // vao state - // auto height_buffer = prepare_altitude_buffer(height_map); - // tileset.heightmap_buffer->allocate(height_buffer.data(), bufferLengthInBytes(height_buffer)); - // f->glEnableVertexAttribArray(GLuint(m_attribute_locations.height)); - // f->glVertexAttribPointer(GLuint(m_attribute_locations.height), /*size*/ 1, /*type*/ GL_UNSIGNED_SHORT, /*normalised*/ GL_TRUE, /*stride*/ 0, - // nullptr); + { // vao state m_index_buffers[0].first->bind(); tileset.gl_element_count = int(m_index_buffers[0].second); tileset.gl_index_type = GL_UNSIGNED_SHORT; diff --git a/gl_engine/TileManager.h b/gl_engine/TileManager.h index d779bfdf..11af9a6f 100644 --- a/gl_engine/TileManager.h +++ b/gl_engine/TileManager.h @@ -65,7 +65,6 @@ public slots: void add_tile( const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::CompressedTexture& ortho, const nucleus::Raster& heights); struct TileGLAttributeLocations { - int height = -1; }; static constexpr auto N_EDGE_VERTICES = 65; From 53092d8bddd8d9224283ef7fec203b597da28145 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 20 Feb 2024 13:40:51 +0100 Subject: [PATCH 35/65] fix shadows --- gl_engine/shaders/shadowmap.vert | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gl_engine/shaders/shadowmap.vert b/gl_engine/shaders/shadowmap.vert index 079dc41e..9981d5f2 100644 --- a/gl_engine/shaders/shadowmap.vert +++ b/gl_engine/shaders/shadowmap.vert @@ -1,6 +1,7 @@ /***************************************************************************** * Alpine Terrain Renderer * Copyright (C) 2023 Gerald Kimmersdorfer + * Copyright (C) 2024 Adam Celarek * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +21,10 @@ #include "camera_config.glsl" #include "shadow_config.glsl" -layout(location = 0) in highp float altitude; - uniform highp vec4 bounds[32]; uniform highp int n_edge_vertices; -uniform highp sampler2D height_sampler; +uniform mediump usampler2D height_sampler; uniform lowp int current_layer; @@ -70,9 +69,10 @@ void main() { // Note: May be enough to calculate altitude_correction_factor per tile on CPU: highp float var_pos_cws_y = float(edge_vertices_count_int - row) * float(tile_width) + bounds[geometry_id].y; highp float pos_y = var_pos_cws_y + camera.position.y; - highp float altitude_correction_factor = 65536.0 * 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 + float altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 - highp float adjusted_altitude = altitude * altitude_correction_factor; + vec2 uv = vec2(float(col) / edge_vertices_count_float, float(row) / edge_vertices_count_float); + highp float adjusted_altitude = float(texture(height_sampler, uv).r) * altitude_correction_factor; highp vec3 var_pos_cws = vec3(float(col) * tile_width + bounds[geometry_id].x, var_pos_cws_y, From 0cc30819996542fcb652dbf651c6749f05571769 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 20 Feb 2024 23:12:17 +0100 Subject: [PATCH 36/65] texture arrays for textures --- gl_engine/Texture.cpp | 60 +++++++++++++++---- gl_engine/Texture.h | 4 +- unittests/gl_engine/texture.cpp | 103 +++++++++++++++++++++++++++----- 3 files changed, 138 insertions(+), 29 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 8c5f18f8..ecadf518 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -19,6 +19,7 @@ #include "Texture.h" #include "nucleus/utils/CompressedTexture.h" +#include #include #ifdef __EMSCRIPTEN__ #include @@ -73,28 +74,61 @@ void gl_engine::Texture::setParams(Filter min_filter, Filter mag_filter) f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(m_mag_filter)); } +void gl_engine::Texture::allocate_array(unsigned int width, unsigned int height, unsigned int n_layers) +{ + assert(m_target == Target::_2dArray); + assert(m_format != Format::Invalid); + auto* f = QOpenGLContext::currentContext()->extraFunctions(); + + auto mip_level_count = 1; + if (m_min_filter == Filter::MipMapLinear) + mip_level_count = GLsizei(1 + std::floor(std::log2(std::max(width, height)))); + + auto internalformat = GLenum(m_format); + if (m_format == Format::CompressedRGBA8) + internalformat = gl_engine::Texture::compressed_texture_format(); + + f->glTexStorage3D(GLenum(m_target), mip_level_count, internalformat, GLsizei(width), GLsizei(height), GLsizei(n_layers)); +} + void gl_engine::Texture::upload(const nucleus::utils::CompressedTexture& texture) { QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glBindTexture(GLenum(m_target), m_id); f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - switch (m_format) { - case Format::CompressedRGBA8: - f->glCompressedTexImage2D(GLenum(m_target), 0, gl_engine::Texture::compressed_texture_format(), GLsizei(texture.width()), GLsizei(texture.height()), 0, - GLsizei(texture.n_bytes()), texture.data()); - return; - case Format::RGBA8: - f->glTexImage2D(GLenum(m_target), 0, GL_RGBA8, GLsizei(texture.width()), GLsizei(texture.height()), 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.data()); + const auto width = GLsizei(texture.width()); + const auto height = GLsizei(texture.height()); + if (m_format == Format::CompressedRGBA8) { + assert(m_min_filter != Filter::MipMapLinear); + const auto format = gl_engine::Texture::compressed_texture_format(); + f->glCompressedTexImage2D(GLenum(m_target), 0, format, width, height, 0, GLsizei(texture.n_bytes()), texture.data()); + } else if (m_format == Format::RGBA8) { + f->glTexImage2D(GLenum(m_target), 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.data()); + if (m_min_filter == Filter::MipMapLinear) + f->glGenerateMipmap(GLenum(m_target)); + } else { + assert(false); + } +} + +void gl_engine::Texture::upload(const nucleus::utils::CompressedTexture& texture, unsigned int array_index) +{ + auto* f = QOpenGLContext::currentContext()->extraFunctions(); + f->glBindTexture(GLenum(m_target), m_id); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + const auto width = GLsizei(texture.width()); + const auto height = GLsizei(texture.height()); + if (m_format == Format::CompressedRGBA8) { + assert(m_min_filter != Filter::MipMapLinear); + const auto format = gl_engine::Texture::compressed_texture_format(); + f->glCompressedTexSubImage3D(GLenum(m_target), 0, 0, 0, GLint(array_index), width, height, 1, format, GLsizei(texture.n_bytes()), texture.data()); + } else if (m_format == Format::RGBA8) { + f->glTexSubImage3D(GLenum(m_target), 0, 0, 0, GLint(array_index), width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, texture.data()); if (m_min_filter == Filter::MipMapLinear) f->glGenerateMipmap(GLenum(m_target)); - return; - case Format::RG8: - case Format::R16UI: - case Format::Invalid: + } else { assert(false); - break; } - assert(false); } void gl_engine::Texture::upload(const nucleus::Raster& texture) diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index f651268b..fc076ae1 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -28,7 +28,7 @@ namespace gl_engine { class Texture { public: enum class Target : GLenum { _2d = GL_TEXTURE_2D, _2dArray = GL_TEXTURE_2D_ARRAY }; - enum class Format { RGBA8, CompressedRGBA8, RG8, R16UI, Invalid = -1 }; + enum class Format : GLenum { RGBA8 = GL_RGBA8, CompressedRGBA8 = GLenum(-2), RG8 = GL_RG8, R16UI = GL_R16UI, Invalid = GLenum(-1) }; enum class Filter : GLint { Nearest = GL_NEAREST, Linear = GL_LINEAR, MipMapLinear = GL_LINEAR_MIPMAP_LINEAR }; public: @@ -41,7 +41,9 @@ class Texture { void bind(unsigned texture_unit); void setParams(Filter min_filter, Filter mag_filter); + void allocate_array(unsigned width, unsigned height, unsigned n_layers); void upload(const nucleus::utils::CompressedTexture& texture); + void upload(const nucleus::utils::CompressedTexture& texture, unsigned array_index); void upload(const nucleus::Raster& texture); void upload(const nucleus::Raster& texture); diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index a9dd747f..b6f31772 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -120,9 +120,6 @@ TEST_CASE("gl texture") const QImage render_result = b.read_colour_attachment(0); // render_result.save("render_result.png"); Framebuffer::unbind(); - REQUIRE(!render_result.isNull()); - CHECK(render_result.width() == test_texture.width()); - CHECK(render_result.height() == test_texture.height()); double diff = 0; for (int i = 0; i < render_result.width(); ++i) { for (int j = 0; j < render_result.height(); ++j) { @@ -152,9 +149,6 @@ TEST_CASE("gl texture") const QImage render_result = b.read_colour_attachment(0); // render_result.save("render_result.png"); Framebuffer::unbind(); - REQUIRE(!render_result.isNull()); - CHECK(render_result.width() == test_texture.width()); - CHECK(render_result.height() == test_texture.height()); double diff = 0; for (int i = 0; i < render_result.width(); ++i) { for (int j = 0; j < render_result.height(); ++j) { @@ -184,9 +178,6 @@ TEST_CASE("gl texture") const QImage render_result = b.read_colour_attachment(0); // render_result.save("render_result.png"); Framebuffer::unbind(); - REQUIRE(!render_result.isNull()); - CHECK(render_result.width() == test_texture.width()); - CHECK(render_result.height() == test_texture.height()); double diff = 0; for (int i = 0; i < render_result.width(); ++i) { for (int j = 0; j < render_result.height(); ++j) { @@ -216,9 +207,6 @@ TEST_CASE("gl texture") const QImage render_result = b.read_colour_attachment(0); // render_result.save("render_result.png"); Framebuffer::unbind(); - REQUIRE(!render_result.isNull()); - CHECK(render_result.width() == 1); - CHECK(render_result.height() == 1); CHECK(qRed(render_result.pixel(0, 0)) == 240); CHECK(qGreen(render_result.pixel(0, 0)) == 120); CHECK(qBlue(render_result.pixel(0, 0)) == 0); @@ -252,12 +240,97 @@ TEST_CASE("gl texture") const QImage render_result = b.read_colour_attachment(0); // render_result.save("render_result.png"); Framebuffer::unbind(); - REQUIRE(!render_result.isNull()); - CHECK(render_result.width() == 1); - CHECK(render_result.height() == 1); CHECK(qRed(render_result.pixel(0, 0)) == 120); CHECK(qGreen(render_result.pixel(0, 0)) == 0); CHECK(qBlue(render_result.pixel(0, 0)) == 0); CHECK(qAlpha(render_result.pixel(0, 0)) == 255); } + + SECTION("rgba array") + { + Framebuffer framebuffer(Framebuffer::DepthFormat::None, + { { Framebuffer::ColourFormat::RGBA8 }, { Framebuffer::ColourFormat::RGBA8 }, { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); + framebuffer.bind(); + + std::array texture_types = { CompressedTexture::Algorithm::Uncompressed_RGBA, gl_engine::Texture::compression_algorithm() }; + for (auto texture_type : texture_types) { + const auto format = (texture_type == CompressedTexture::Algorithm::Uncompressed_RGBA) ? gl_engine::Texture::Format::RGBA8 + : gl_engine::Texture::Format::CompressedRGBA8; + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2dArray, format); + opengl_texture.bind(0); + opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); + opengl_texture.allocate_array(256, 256, 3); + { + const auto compressed = CompressedTexture(test_texture, texture_type); + opengl_texture.upload(compressed, 0); + } + { + QImage test_texture(256, 256, QImage::Format_ARGB32); + test_texture.fill(qRgba(42, 142, 242, 255)); + const auto compressed = CompressedTexture(test_texture, texture_type); + opengl_texture.upload(compressed, 1); + } + { + QImage test_texture(256, 256, QImage::Format_ARGB32); + test_texture.fill(qRgba(222, 111, 0, 255)); + const auto compressed = CompressedTexture(test_texture, texture_type); + opengl_texture.upload(compressed, 2); + } + ShaderProgram shader = create_debug_shader(R"( + uniform sampler2DArray texture_sampler; + in highp vec2 texcoords; + out lowp vec4 out_color_0; + out lowp vec4 out_color_1; + out lowp vec4 out_color_2; + void main() { + out_color_0 = texture(texture_sampler, vec3(texcoords.x, 1.0 - texcoords.y, 0.0)); + out_color_1 = texture(texture_sampler, vec3(texcoords.x, 1.0 - texcoords.y, 1.0)); + out_color_2 = texture(texture_sampler, vec3(texcoords.x, 1.0 - texcoords.y, 2.0)); + } + )"); + shader.bind(); + gl_engine::helpers::create_screen_quad_geometry().draw(); + + { + const QImage render_result = framebuffer.read_colour_attachment(0); + // render_result.save("render_result.png"); + // test_texture.save("test_texture.png"); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.017); + } + { + const QImage render_result = framebuffer.read_colour_attachment(1); + // render_result.save("render_result1.png"); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - 42) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - 142) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - 242) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.017); + } + { + const QImage render_result = framebuffer.read_colour_attachment(2); + // render_result.save("render_result2.png"); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - 222) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - 111) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - 0) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.017); + } + } + } } From 3ca8af974af53cb3f98a883090aeba8622c7af23 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 20 Feb 2024 23:27:37 +0100 Subject: [PATCH 37/65] clean up Framebuffer a bit --- gl_engine/Framebuffer.cpp | 32 ++++++++++++++------------------ gl_engine/Framebuffer.h | 13 ++----------- gl_engine/SSAO.cpp | 4 ++-- gl_engine/ShadowMapping.cpp | 8 +++----- gl_engine/Window.cpp | 14 ++++++-------- unittests/gl_engine/texture.cpp | 6 +++--- 6 files changed, 30 insertions(+), 47 deletions(-) diff --git a/gl_engine/Framebuffer.cpp b/gl_engine/Framebuffer.cpp index d6654ff5..f7944f57 100644 --- a/gl_engine/Framebuffer.cpp +++ b/gl_engine/Framebuffer.cpp @@ -190,19 +190,16 @@ void Framebuffer::recreate_texture(size_t index) } } else { m_colour_textures[index]->destroy(); - m_colour_textures[index]->setFormat(internal_format_qt(m_colour_definitions[index].format)); + m_colour_textures[index]->setFormat(internal_format_qt(m_colour_definitions[index])); m_colour_textures[index]->setSize(int(m_size.x), int(m_size.y)); - m_colour_textures[index]->setAutoMipMapGenerationEnabled(m_colour_definitions[index].autoMipMapGeneration); - m_colour_textures[index]->setMinMagFilters(m_colour_definitions[index].minFilter, m_colour_definitions[index].magFilter); -#if (defined(__linux) && !defined(__ANDROID__)) || defined(_WIN32) || defined(_WIN64) - // No support on WebGL and OpenGL ES for Border (Warning: On those platforms we just ignore the wrap mode) - // Feel free to make this code better!! - m_colour_textures[index]->setWrapMode(m_colour_definitions[index].wrapMode); - m_colour_textures[index]->setBorderColor(m_colour_definitions[index].borderColor); -#endif - // NOTE: If format and type not specifically defined in the following function it will crash for uint-textures + m_colour_textures[index]->setAutoMipMapGenerationEnabled(false); + m_colour_textures[index]->setMinMagFilters(QOpenGLTexture::Filter::Nearest, QOpenGLTexture::Filter::Nearest); + m_colour_textures[index]->setWrapMode(QOpenGLTexture::WrapMode::ClampToEdge); + + // WARNING: If format and type not specifically defined in the following function it will crash for uint-textures // on OpenGL ES (Android). Might be a bug with the default of QOpenGLTexture on that platform. - m_colour_textures[index]->allocateStorage((QOpenGLTexture::PixelFormat)format(m_colour_definitions[index].format), (QOpenGLTexture::PixelType)type(m_colour_definitions[index].format)); + m_colour_textures[index]->allocateStorage( + (QOpenGLTexture::PixelFormat)format(m_colour_definitions[index]), (QOpenGLTexture::PixelType)type(m_colour_definitions[index])); } } @@ -212,11 +209,10 @@ void Framebuffer::recreate_all_textures() { recreate_texture(i); } - -Framebuffer::Framebuffer(DepthFormat depth_format, std::vector colour_definitions, glm::uvec2 init_size) - : m_depth_format(depth_format), - m_colour_definitions(std::move(colour_definitions)), - m_size(init_size) +Framebuffer::Framebuffer(DepthFormat depth_format, std::vector colour_definitions, glm::uvec2 init_size) + : m_depth_format(depth_format) + , m_colour_definitions(std::move(colour_definitions)) + , m_size(init_size) { for (size_t i = 0; i < m_colour_definitions.size(); i++) { @@ -276,7 +272,7 @@ QImage Framebuffer::read_colour_attachment(unsigned index) { assert(index < m_colour_textures.size()); - auto texFormat = m_colour_definitions[index].format; + auto texFormat = m_colour_definitions[index]; // Float framebuffers can not be read efficiently on all environments. // that is, reading float red channel crashes on linux webassembly, but reading it as rgba is inefficient on linux native (4x slower, yes I measured). @@ -302,7 +298,7 @@ T Framebuffer::read_colour_attachment_pixel(unsigned int index, const glm::dvec2 { assert(index < m_colour_textures.size()); - auto texFormat = m_colour_definitions[index].format; + auto texFormat = m_colour_definitions[index]; switch (texFormat) { case Framebuffer::ColourFormat::R8: case Framebuffer::ColourFormat::RGB8: diff --git a/gl_engine/Framebuffer.h b/gl_engine/Framebuffer.h index 4eff34c5..79b4bad4 100644 --- a/gl_engine/Framebuffer.h +++ b/gl_engine/Framebuffer.h @@ -60,7 +60,7 @@ class Framebuffer private: DepthFormat m_depth_format; - std::vector m_colour_definitions; + std::vector m_colour_definitions; std::unique_ptr m_depth_texture; std::vector> m_colour_textures; @@ -73,7 +73,7 @@ class Framebuffer void recreate_all_textures(); public: - Framebuffer(DepthFormat depth_format, std::vector colour_definitions, glm::uvec2 init_size = {4,4}); + Framebuffer(DepthFormat depth_format, std::vector colour_definitions, glm::uvec2 init_size = { 4, 4 }); ~Framebuffer(); void resize(const glm::uvec2& new_size); void bind(); @@ -96,15 +96,6 @@ class Framebuffer void reset_fbo(); }; -struct TextureDefinition { - Framebuffer::ColourFormat format = Framebuffer::ColourFormat::RGBA8; - QOpenGLTexture::Filter minFilter = QOpenGLTexture::Filter::Nearest; - QOpenGLTexture::Filter magFilter = QOpenGLTexture::Filter::Nearest; - QOpenGLTexture::WrapMode wrapMode = QOpenGLTexture::WrapMode::ClampToEdge; - QColor borderColor = QColor(0.0f, 0.0f, 0.0f, 1.0f); - bool autoMipMapGeneration = false; -}; - extern template glm::vec4 Framebuffer::read_colour_attachment_pixel(unsigned index, const glm::dvec2& normalised_device_coordinates); extern template glm::u8vec4 Framebuffer::read_colour_attachment_pixel(unsigned index, const glm::dvec2& normalised_device_coordinates); } diff --git a/gl_engine/SSAO.cpp b/gl_engine/SSAO.cpp index 826ce9d0..25f10668 100644 --- a/gl_engine/SSAO.cpp +++ b/gl_engine/SSAO.cpp @@ -54,8 +54,8 @@ SSAO::SSAO(std::shared_ptr program, std::shared_ptrsetData(QOpenGLTexture::RGB, QOpenGLTexture::Float32, &ssaoNoise[0]); // GENERATE FRAMEBUFFER - m_ssaobuffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector{ TextureDefinition{Framebuffer::ColourFormat::R8}}); - m_ssao_blurbuffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector{ TextureDefinition{Framebuffer::ColourFormat::R8}}); + m_ssaobuffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { Framebuffer::ColourFormat::R8 }); + m_ssao_blurbuffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { Framebuffer::ColourFormat::R8 }); } void SSAO::recreate_kernel(unsigned int size) { diff --git a/gl_engine/ShadowMapping.cpp b/gl_engine/ShadowMapping.cpp index a5c7bc59..96eb604f 100644 --- a/gl_engine/ShadowMapping.cpp +++ b/gl_engine/ShadowMapping.cpp @@ -35,11 +35,9 @@ ShadowMapping::ShadowMapping(std::shared_ptr program, std::shared { m_f = QOpenGLContext::currentContext()->extraFunctions(); for (int i = 0; i < SHADOW_CASCADES; i++) { - m_shadowmapbuffer.push_back(std::make_unique( - Framebuffer::DepthFormat::Float32, - std::vector{}, // no colour texture needed (=> depth only) - glm::uvec2(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT) - )); + m_shadowmapbuffer.push_back(std::make_unique(Framebuffer::DepthFormat::Float32, + std::vector {}, // no colour texture needed (=> depth only) + glm::uvec2(SHADOWMAP_WIDTH, SHADOWMAP_HEIGHT))); } } diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index 05565963..c9b75f44 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -18,7 +18,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ -#include #include #include @@ -57,7 +56,6 @@ #include "UniformBufferObjects.h" #include "nucleus/timing/TimerManager.h" -#include "nucleus/timing/TimerInterface.h" #include "nucleus/timing/CpuTimer.h" #include "nucleus/utils/bit_coding.h" #if (defined(__linux) && !defined(__ANDROID__)) || defined(_WIN32) || defined(_WIN64) @@ -121,14 +119,14 @@ void Window::initialise_gpu() // ANOTHER IMPORTANT NOTE: RGB32f, RGB16f are not supported by OpenGL ES and/or WebGL m_gbuffer = std::make_unique(Framebuffer::DepthFormat::Float32, std::vector { - TextureDefinition { Framebuffer::ColourFormat::RGBA8 }, // Albedo - TextureDefinition { Framebuffer::ColourFormat::RGBA32F }, // Position WCS and distance (distance is optional, but i use it directly for a little speed improvement) - TextureDefinition { Framebuffer::ColourFormat::RG16UI }, // Octahedron Normals - TextureDefinition { Framebuffer::ColourFormat::RGBA8 } // Discretized Encoded Depth for readback IMPORTANT: IF YOU MOVE THIS YOU HAVE TO ADAPT THE GET DEPTH FUNCTION + Framebuffer::ColourFormat::RGBA8, // Albedo + Framebuffer::ColourFormat::RGBA32F, // Position WCS and distance (distance is optional, but i use it directly for a little speed improvement) + Framebuffer::ColourFormat::RG16UI, // Octahedron Normals + Framebuffer::ColourFormat::RGBA8, // Discretized Encoded Depth for readback IMPORTANT: IF YOU MOVE THIS YOU HAVE TO ADAPT THE GET DEPTH FUNCTION }); - m_atmospherebuffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector{ TextureDefinition{Framebuffer::ColourFormat::RGBA8} }); - m_decoration_buffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { TextureDefinition { Framebuffer::ColourFormat::RGBA8 } }); + m_atmospherebuffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { Framebuffer::ColourFormat::RGBA8 }); + m_decoration_buffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { Framebuffer::ColourFormat::RGBA8 }); f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_gbuffer->depth_texture()->textureId(), 0); m_shared_config_ubo = std::make_shared>(0, "shared_config"); diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index b6f31772..41c98f63 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -106,7 +106,7 @@ TEST_CASE("gl texture") SECTION("verify test methodology") { - Framebuffer b(Framebuffer::DepthFormat::None, {{Framebuffer::ColourFormat::RGBA8}}, {256, 256}); + Framebuffer b(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8 }, { 256, 256 }); b.bind(); QOpenGLTexture opengl_texture(test_texture); opengl_texture.setWrapMode(QOpenGLTexture::WrapMode::ClampToBorder); @@ -133,7 +133,7 @@ TEST_CASE("gl texture") SECTION("compressed rgba") { - Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); + Framebuffer b(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8 }, { 256, 256 }); b.bind(); const auto compressed = CompressedTexture(test_texture, gl_engine::Texture::compression_algorithm()); @@ -249,7 +249,7 @@ TEST_CASE("gl texture") SECTION("rgba array") { Framebuffer framebuffer(Framebuffer::DepthFormat::None, - { { Framebuffer::ColourFormat::RGBA8 }, { Framebuffer::ColourFormat::RGBA8 }, { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); + { Framebuffer::ColourFormat::RGBA8, Framebuffer::ColourFormat::RGBA8, Framebuffer::ColourFormat::RGBA8 }, { 256, 256 }); framebuffer.bind(); std::array texture_types = { CompressedTexture::Algorithm::Uncompressed_RGBA, gl_engine::Texture::compression_algorithm() }; From 2f394517aa7721743e84f3d4f1a2e26a44efa90d Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 20 Feb 2024 23:31:38 +0100 Subject: [PATCH 38/65] rename CompressedTexture -> ColourTexture --- gl_engine/Texture.cpp | 10 +++---- gl_engine/Texture.h | 8 +++--- gl_engine/TileManager.cpp | 5 ++-- gl_engine/TileManager.h | 3 +-- gl_engine/Window.cpp | 2 +- gl_engine/Window.h | 2 +- nucleus/AbstractRenderWindow.h | 4 +-- nucleus/CMakeLists.txt | 2 +- nucleus/tile_scheduler/Scheduler.cpp | 6 ++--- nucleus/tile_scheduler/Scheduler.h | 8 +++--- nucleus/tile_scheduler/tile_types.h | 4 +-- ...ompressedTexture.cpp => ColourTexture.cpp} | 8 +++--- .../{CompressedTexture.h => ColourTexture.h} | 5 ++-- unittests/gl_engine/texture.cpp | 26 +++++++++---------- 14 files changed, 45 insertions(+), 48 deletions(-) rename nucleus/utils/{CompressedTexture.cpp => ColourTexture.cpp} (95%) rename nucleus/utils/{CompressedTexture.h => ColourTexture.h} (92%) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index ecadf518..097821d3 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -17,7 +17,7 @@ *****************************************************************************/ #include "Texture.h" -#include "nucleus/utils/CompressedTexture.h" +#include "nucleus/utils/ColourTexture.h" #include #include @@ -91,7 +91,7 @@ void gl_engine::Texture::allocate_array(unsigned int width, unsigned int height, f->glTexStorage3D(GLenum(m_target), mip_level_count, internalformat, GLsizei(width), GLsizei(height), GLsizei(n_layers)); } -void gl_engine::Texture::upload(const nucleus::utils::CompressedTexture& texture) +void gl_engine::Texture::upload(const nucleus::utils::ColourTexture& texture) { QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glBindTexture(GLenum(m_target), m_id); @@ -111,7 +111,7 @@ void gl_engine::Texture::upload(const nucleus::utils::CompressedTexture& texture } } -void gl_engine::Texture::upload(const nucleus::utils::CompressedTexture& texture, unsigned int array_index) +void gl_engine::Texture::upload(const nucleus::utils::ColourTexture& texture, unsigned int array_index) { auto* f = QOpenGLContext::currentContext()->extraFunctions(); f->glBindTexture(GLenum(m_target), m_id); @@ -185,7 +185,7 @@ GLenum gl_engine::Texture::compressed_texture_format() #endif } -nucleus::utils::CompressedTexture::Algorithm gl_engine::Texture::compression_algorithm() +nucleus::utils::ColourTexture::Algorithm gl_engine::Texture::compression_algorithm() { #if defined(__EMSCRIPTEN__) // clang-format off @@ -205,6 +205,6 @@ nucleus::utils::CompressedTexture::Algorithm gl_engine::Texture::compression_alg #elif defined(__ANDROID__) return nucleus::utils::CompressedTexture::Algorithm::ETC1; #else - return nucleus::utils::CompressedTexture::Algorithm::DXT1; + return nucleus::utils::ColourTexture::Algorithm::DXT1; #endif } diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index fc076ae1..afa35c6d 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -22,7 +22,7 @@ #include #include -#include +#include namespace gl_engine { class Texture { @@ -42,13 +42,13 @@ class Texture { void bind(unsigned texture_unit); void setParams(Filter min_filter, Filter mag_filter); void allocate_array(unsigned width, unsigned height, unsigned n_layers); - void upload(const nucleus::utils::CompressedTexture& texture); - void upload(const nucleus::utils::CompressedTexture& texture, unsigned array_index); + void upload(const nucleus::utils::ColourTexture& texture); + void upload(const nucleus::utils::ColourTexture& texture, unsigned array_index); void upload(const nucleus::Raster& texture); void upload(const nucleus::Raster& texture); static GLenum compressed_texture_format(); - static nucleus::utils::CompressedTexture::Algorithm compression_algorithm(); + static nucleus::utils::ColourTexture::Algorithm compression_algorithm(); private: GLuint m_id = GLuint(-1); diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index edf3b6f3..7bfa289a 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -151,7 +151,7 @@ void TileManager::set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbD } void TileManager::add_tile( - const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::CompressedTexture& ortho_texture, const nucleus::Raster& height_map) + const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::ColourTexture& ortho_texture, const nucleus::Raster& height_map) { if (!QOpenGLContext::currentContext()) // can happen during shutdown. return; @@ -172,8 +172,7 @@ void TileManager::add_tile( } tileset.vao->release(); tileset.ortho_texture = std::make_unique(Texture::Target::_2d, - ortho_texture.algorithm() == nucleus::utils::CompressedTexture::Algorithm::Uncompressed_RGBA ? Texture::Format::RGBA8 - : Texture::Format::CompressedRGBA8); + ortho_texture.algorithm() == nucleus::utils::ColourTexture::Algorithm::Uncompressed_RGBA ? Texture::Format::RGBA8 : Texture::Format::CompressedRGBA8); tileset.ortho_texture->setParams(Texture::Filter::Linear, Texture::Filter::Linear); tileset.ortho_texture->upload(ortho_texture); diff --git a/gl_engine/TileManager.h b/gl_engine/TileManager.h index 11af9a6f..a61e13c2 100644 --- a/gl_engine/TileManager.h +++ b/gl_engine/TileManager.h @@ -62,8 +62,7 @@ public slots: void set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr& new_aabb_decorator); private: - void add_tile( - const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::CompressedTexture& ortho, const nucleus::Raster& heights); + void add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::ColourTexture& ortho, const nucleus::Raster& heights); struct TileGLAttributeLocations { }; diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index c9b75f44..175a11be 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -483,4 +483,4 @@ void Window::remove_tile(const tile::Id& id) nucleus::camera::AbstractDepthTester* Window::depth_tester() { return this; } -nucleus::utils::CompressedTexture::Algorithm Window::ortho_tile_compression_algorithm() const { return Texture::compression_algorithm(); } +nucleus::utils::ColourTexture::Algorithm Window::ortho_tile_compression_algorithm() const { return Texture::compression_algorithm(); } diff --git a/gl_engine/Window.h b/gl_engine/Window.h index 7dadb2a7..ec539684 100644 --- a/gl_engine/Window.h +++ b/gl_engine/Window.h @@ -70,7 +70,7 @@ class Window : public nucleus::AbstractRenderWindow, public nucleus::camera::Abs void set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr&) override; void remove_tile(const tile::Id&) override; [[nodiscard]] nucleus::camera::AbstractDepthTester* depth_tester() override; - [[nodiscard]] nucleus::utils::CompressedTexture::Algorithm ortho_tile_compression_algorithm() const override; + [[nodiscard]] nucleus::utils::ColourTexture::Algorithm ortho_tile_compression_algorithm() const override; void keyPressEvent(QKeyEvent*); void keyReleaseEvent(QKeyEvent*); void updateCameraEvent(); diff --git a/nucleus/AbstractRenderWindow.h b/nucleus/AbstractRenderWindow.h index e80e6051..3d5c7b9c 100644 --- a/nucleus/AbstractRenderWindow.h +++ b/nucleus/AbstractRenderWindow.h @@ -24,7 +24,7 @@ #include #include "nucleus/tile_scheduler/tile_types.h" -#include "utils/CompressedTexture.h" +#include "utils/ColourTexture.h" class QOpenGLFramebufferObject; @@ -52,7 +52,7 @@ class AbstractRenderWindow : public QObject { virtual void deinit_gpu() = 0; virtual void set_permissible_screen_space_error(float new_error) = 0; [[nodiscard]] virtual camera::AbstractDepthTester* depth_tester() = 0; - [[nodiscard]] virtual utils::CompressedTexture::Algorithm ortho_tile_compression_algorithm() const = 0; + [[nodiscard]] virtual utils::ColourTexture::Algorithm ortho_tile_compression_algorithm() const = 0; public slots: virtual void update_camera(const camera::Definition& new_definition) = 0; diff --git a/nucleus/CMakeLists.txt b/nucleus/CMakeLists.txt index c9b5608b..3de5c336 100644 --- a/nucleus/CMakeLists.txt +++ b/nucleus/CMakeLists.txt @@ -101,7 +101,7 @@ qt_add_library(nucleus STATIC timing/TimerManager.h timing/TimerManager.cpp timing/TimerInterface.h timing/TimerInterface.cpp timing/CpuTimer.h timing/CpuTimer.cpp - utils/CompressedTexture.h utils/CompressedTexture.cpp + utils/ColourTexture.h utils/ColourTexture.cpp ) target_include_directories(nucleus PUBLIC ${CMAKE_SOURCE_DIR}) diff --git a/nucleus/tile_scheduler/Scheduler.cpp b/nucleus/tile_scheduler/Scheduler.cpp index 9f030ef6..594b170a 100644 --- a/nucleus/tile_scheduler/Scheduler.cpp +++ b/nucleus/tile_scheduler/Scheduler.cpp @@ -176,7 +176,7 @@ void Scheduler::update_gpu_quads() ortho_data = quad.tiles[i].ortho.get(); } const auto ortho_qimage = nucleus::utils::tile_conversion::toQImage(*ortho_data); - gpu_quad.tiles[i].ortho = std::make_shared(ortho_qimage, m_ortho_tile_compression_algorithm); + gpu_quad.tiles[i].ortho = std::make_shared(ortho_qimage, m_ortho_tile_compression_algorithm); const auto* height_data = m_default_height_tile.get(); if (quad.tiles[i].height->size()) { @@ -298,9 +298,9 @@ std::vector Scheduler::tiles_for_current_camera_position() const return all_inner_nodes; } -nucleus::utils::CompressedTexture::Algorithm Scheduler::ortho_tile_compression_algorithm() const { return m_ortho_tile_compression_algorithm; } +nucleus::utils::ColourTexture::Algorithm Scheduler::ortho_tile_compression_algorithm() const { return m_ortho_tile_compression_algorithm; } -void Scheduler::set_ortho_tile_compression_algorithm(nucleus::utils::CompressedTexture::Algorithm new_ortho_tile_compression_algorithm) +void Scheduler::set_ortho_tile_compression_algorithm(nucleus::utils::ColourTexture::Algorithm new_ortho_tile_compression_algorithm) { m_ortho_tile_compression_algorithm = new_ortho_tile_compression_algorithm; } diff --git a/nucleus/tile_scheduler/Scheduler.h b/nucleus/tile_scheduler/Scheduler.h index 9856be0f..64ce68e1 100644 --- a/nucleus/tile_scheduler/Scheduler.h +++ b/nucleus/tile_scheduler/Scheduler.h @@ -76,9 +76,9 @@ class Scheduler : public QObject { void read_disk_cache(); void set_retirement_age_for_tile_cache(unsigned int new_retirement_age_for_tile_cache); - - nucleus::utils::CompressedTexture::Algorithm ortho_tile_compression_algorithm() const; - void set_ortho_tile_compression_algorithm(nucleus::utils::CompressedTexture::Algorithm new_ortho_tile_compression_algorithm); + + nucleus::utils::ColourTexture::Algorithm ortho_tile_compression_algorithm() const; + void set_ortho_tile_compression_algorithm(nucleus::utils::ColourTexture::Algorithm new_ortho_tile_compression_algorithm); signals: void statistics_updated(Statistics stats); @@ -124,6 +124,6 @@ public slots: Cache m_gpu_cached; std::shared_ptr m_default_ortho_tile; std::shared_ptr m_default_height_tile; - nucleus::utils::CompressedTexture::Algorithm m_ortho_tile_compression_algorithm = nucleus::utils::CompressedTexture::Algorithm::Uncompressed_RGBA; + nucleus::utils::ColourTexture::Algorithm m_ortho_tile_compression_algorithm = nucleus::utils::ColourTexture::Algorithm::Uncompressed_RGBA; }; } diff --git a/nucleus/tile_scheduler/tile_types.h b/nucleus/tile_scheduler/tile_types.h index 439aeb76..2260c74f 100644 --- a/nucleus/tile_scheduler/tile_types.h +++ b/nucleus/tile_scheduler/tile_types.h @@ -21,7 +21,7 @@ #include #include "nucleus/tile_scheduler/utils.h" -#include "nucleus/utils/CompressedTexture.h" +#include "nucleus/utils/ColourTexture.h" #include class QImage; @@ -103,7 +103,7 @@ static_assert(NamedTile); struct GpuLayeredTile { tile::Id id; tile::SrsAndHeightBounds bounds = {}; - std::shared_ptr ortho; + std::shared_ptr ortho; std::shared_ptr> height; }; static_assert(NamedTile); diff --git a/nucleus/utils/CompressedTexture.cpp b/nucleus/utils/ColourTexture.cpp similarity index 95% rename from nucleus/utils/CompressedTexture.cpp rename to nucleus/utils/ColourTexture.cpp index 46fd3781..7e557f28 100644 --- a/nucleus/utils/CompressedTexture.cpp +++ b/nucleus/utils/ColourTexture.cpp @@ -21,7 +21,7 @@ #define GOOFYTC_IMPLEMENTATION #include -#include "CompressedTexture.h" +#include "ColourTexture.h" namespace { std::vector to_dxt1(const QImage& qimage) @@ -110,9 +110,9 @@ std::vector to_uncompressed_rgba(const QImage& qimage) return data; } -std::vector to_compressed(const QImage& image, nucleus::utils::CompressedTexture::Algorithm algorithm) +std::vector to_compressed(const QImage& image, nucleus::utils::ColourTexture::Algorithm algorithm) { - using Algorithm = nucleus::utils::CompressedTexture::Algorithm; + using Algorithm = nucleus::utils::ColourTexture::Algorithm; switch (algorithm) { case Algorithm::DXT1: @@ -127,7 +127,7 @@ std::vector to_compressed(const QImage& image, nucleus::utils::Compress } } // namespace -nucleus::utils::CompressedTexture::CompressedTexture(const QImage& image, Algorithm algorithm) +nucleus::utils::ColourTexture::ColourTexture(const QImage& image, Algorithm algorithm) : m_data(to_compressed(image, algorithm)) , m_width(unsigned(image.width())) , m_height(unsigned(image.height())) diff --git a/nucleus/utils/CompressedTexture.h b/nucleus/utils/ColourTexture.h similarity index 92% rename from nucleus/utils/CompressedTexture.h rename to nucleus/utils/ColourTexture.h index cc78c404..a0f35bd5 100644 --- a/nucleus/utils/CompressedTexture.h +++ b/nucleus/utils/ColourTexture.h @@ -19,11 +19,10 @@ #pragma once #include -#include namespace nucleus::utils { -class CompressedTexture { +class ColourTexture { public: enum class Algorithm { Uncompressed_RGBA, DXT1, ETC1 }; @@ -34,7 +33,7 @@ class CompressedTexture { Algorithm m_algorithm = Algorithm::Uncompressed_RGBA; public: - explicit CompressedTexture(const QImage& image, Algorithm algorithm); + explicit ColourTexture(const QImage& image, Algorithm algorithm); [[nodiscard]] const uint8_t* data() const { return m_data.data(); } [[nodiscard]] size_t n_bytes() const { return m_data.size(); } [[nodiscard]] unsigned width() const { return m_width; } diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index 41c98f63..8d0a109b 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -32,7 +32,7 @@ #include "gl_engine/Framebuffer.h" #include "gl_engine/ShaderProgram.h" #include "gl_engine/helpers.h" -#include "nucleus/utils/CompressedTexture.h" +#include "nucleus/utils/ColourTexture.h" using gl_engine::Framebuffer; using gl_engine::ShaderProgram; @@ -91,15 +91,15 @@ TEST_CASE("gl texture") SECTION("compression") { { - const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::DXT1); + const auto compressed = ColourTexture(test_texture, ColourTexture::Algorithm::DXT1); CHECK(compressed.n_bytes() == 256 * 128); } { - const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::ETC1); + const auto compressed = ColourTexture(test_texture, ColourTexture::Algorithm::ETC1); CHECK(compressed.n_bytes() == 256 * 128); } { - const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::Uncompressed_RGBA); + const auto compressed = ColourTexture(test_texture, ColourTexture::Algorithm::Uncompressed_RGBA); CHECK(compressed.n_bytes() == 256 * 256 * 4); } } @@ -136,7 +136,7 @@ TEST_CASE("gl texture") Framebuffer b(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8 }, { 256, 256 }); b.bind(); - const auto compressed = CompressedTexture(test_texture, gl_engine::Texture::compression_algorithm()); + const auto compressed = ColourTexture(test_texture, gl_engine::Texture::compression_algorithm()); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::CompressedRGBA8); opengl_texture.bind(0); opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); @@ -165,7 +165,7 @@ TEST_CASE("gl texture") Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); b.bind(); - const auto compressed = CompressedTexture(test_texture, CompressedTexture::Algorithm::Uncompressed_RGBA); + const auto compressed = ColourTexture(test_texture, ColourTexture::Algorithm::Uncompressed_RGBA); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::RGBA8); opengl_texture.bind(0); opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); @@ -246,34 +246,34 @@ TEST_CASE("gl texture") CHECK(qAlpha(render_result.pixel(0, 0)) == 255); } - SECTION("rgba array") + SECTION("rgba array (compressed and uncompressed)") { Framebuffer framebuffer(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8, Framebuffer::ColourFormat::RGBA8, Framebuffer::ColourFormat::RGBA8 }, { 256, 256 }); framebuffer.bind(); - std::array texture_types = { CompressedTexture::Algorithm::Uncompressed_RGBA, gl_engine::Texture::compression_algorithm() }; + std::array texture_types = { ColourTexture::Algorithm::Uncompressed_RGBA, gl_engine::Texture::compression_algorithm() }; for (auto texture_type : texture_types) { - const auto format = (texture_type == CompressedTexture::Algorithm::Uncompressed_RGBA) ? gl_engine::Texture::Format::RGBA8 - : gl_engine::Texture::Format::CompressedRGBA8; + const auto format = (texture_type == ColourTexture::Algorithm::Uncompressed_RGBA) ? gl_engine::Texture::Format::RGBA8 + : gl_engine::Texture::Format::CompressedRGBA8; gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2dArray, format); opengl_texture.bind(0); opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); opengl_texture.allocate_array(256, 256, 3); { - const auto compressed = CompressedTexture(test_texture, texture_type); + const auto compressed = ColourTexture(test_texture, texture_type); opengl_texture.upload(compressed, 0); } { QImage test_texture(256, 256, QImage::Format_ARGB32); test_texture.fill(qRgba(42, 142, 242, 255)); - const auto compressed = CompressedTexture(test_texture, texture_type); + const auto compressed = ColourTexture(test_texture, texture_type); opengl_texture.upload(compressed, 1); } { QImage test_texture(256, 256, QImage::Format_ARGB32); test_texture.fill(qRgba(222, 111, 0, 255)); - const auto compressed = CompressedTexture(test_texture, texture_type); + const auto compressed = ColourTexture(test_texture, texture_type); opengl_texture.upload(compressed, 2); } ShaderProgram shader = create_debug_shader(R"( From 6c5bbae8f075e22ce5711fb89d1d4e8d8552d6c8 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 20 Feb 2024 23:38:36 +0100 Subject: [PATCH 39/65] rename (compression) algorithm to format in colour texture. --- gl_engine/Texture.cpp | 4 ++-- gl_engine/Texture.h | 2 +- gl_engine/TileManager.cpp | 2 +- gl_engine/Window.cpp | 2 +- gl_engine/Window.h | 2 +- nucleus/AbstractRenderWindow.h | 2 +- nucleus/tile_scheduler/Scheduler.cpp | 4 ++-- nucleus/tile_scheduler/Scheduler.h | 6 +++--- nucleus/utils/ColourTexture.cpp | 10 +++++----- nucleus/utils/ColourTexture.h | 8 ++++---- unittests/gl_engine/texture.cpp | 24 ++++++++++++------------ 11 files changed, 33 insertions(+), 33 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 097821d3..c23caa51 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -185,7 +185,7 @@ GLenum gl_engine::Texture::compressed_texture_format() #endif } -nucleus::utils::ColourTexture::Algorithm gl_engine::Texture::compression_algorithm() +nucleus::utils::ColourTexture::Format gl_engine::Texture::compression_algorithm() { #if defined(__EMSCRIPTEN__) // clang-format off @@ -205,6 +205,6 @@ nucleus::utils::ColourTexture::Algorithm gl_engine::Texture::compression_algorit #elif defined(__ANDROID__) return nucleus::utils::CompressedTexture::Algorithm::ETC1; #else - return nucleus::utils::ColourTexture::Algorithm::DXT1; + return nucleus::utils::ColourTexture::Format::DXT1; #endif } diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index afa35c6d..9619d439 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -48,7 +48,7 @@ class Texture { void upload(const nucleus::Raster& texture); static GLenum compressed_texture_format(); - static nucleus::utils::ColourTexture::Algorithm compression_algorithm(); + static nucleus::utils::ColourTexture::Format compression_algorithm(); private: GLuint m_id = GLuint(-1); diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index 7bfa289a..00a46f44 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -172,7 +172,7 @@ void TileManager::add_tile( } tileset.vao->release(); tileset.ortho_texture = std::make_unique(Texture::Target::_2d, - ortho_texture.algorithm() == nucleus::utils::ColourTexture::Algorithm::Uncompressed_RGBA ? Texture::Format::RGBA8 : Texture::Format::CompressedRGBA8); + ortho_texture.format() == nucleus::utils::ColourTexture::Format::Uncompressed_RGBA ? Texture::Format::RGBA8 : Texture::Format::CompressedRGBA8); tileset.ortho_texture->setParams(Texture::Filter::Linear, Texture::Filter::Linear); tileset.ortho_texture->upload(ortho_texture); diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index 175a11be..29a1fe8c 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -483,4 +483,4 @@ void Window::remove_tile(const tile::Id& id) nucleus::camera::AbstractDepthTester* Window::depth_tester() { return this; } -nucleus::utils::ColourTexture::Algorithm Window::ortho_tile_compression_algorithm() const { return Texture::compression_algorithm(); } +nucleus::utils::ColourTexture::Format Window::ortho_tile_compression_algorithm() const { return Texture::compression_algorithm(); } diff --git a/gl_engine/Window.h b/gl_engine/Window.h index ec539684..aaf64c1f 100644 --- a/gl_engine/Window.h +++ b/gl_engine/Window.h @@ -70,7 +70,7 @@ class Window : public nucleus::AbstractRenderWindow, public nucleus::camera::Abs void set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr&) override; void remove_tile(const tile::Id&) override; [[nodiscard]] nucleus::camera::AbstractDepthTester* depth_tester() override; - [[nodiscard]] nucleus::utils::ColourTexture::Algorithm ortho_tile_compression_algorithm() const override; + [[nodiscard]] nucleus::utils::ColourTexture::Format ortho_tile_compression_algorithm() const override; void keyPressEvent(QKeyEvent*); void keyReleaseEvent(QKeyEvent*); void updateCameraEvent(); diff --git a/nucleus/AbstractRenderWindow.h b/nucleus/AbstractRenderWindow.h index 3d5c7b9c..e754147e 100644 --- a/nucleus/AbstractRenderWindow.h +++ b/nucleus/AbstractRenderWindow.h @@ -52,7 +52,7 @@ class AbstractRenderWindow : public QObject { virtual void deinit_gpu() = 0; virtual void set_permissible_screen_space_error(float new_error) = 0; [[nodiscard]] virtual camera::AbstractDepthTester* depth_tester() = 0; - [[nodiscard]] virtual utils::ColourTexture::Algorithm ortho_tile_compression_algorithm() const = 0; + [[nodiscard]] virtual utils::ColourTexture::Format ortho_tile_compression_algorithm() const = 0; public slots: virtual void update_camera(const camera::Definition& new_definition) = 0; diff --git a/nucleus/tile_scheduler/Scheduler.cpp b/nucleus/tile_scheduler/Scheduler.cpp index 594b170a..6547a533 100644 --- a/nucleus/tile_scheduler/Scheduler.cpp +++ b/nucleus/tile_scheduler/Scheduler.cpp @@ -298,9 +298,9 @@ std::vector Scheduler::tiles_for_current_camera_position() const return all_inner_nodes; } -nucleus::utils::ColourTexture::Algorithm Scheduler::ortho_tile_compression_algorithm() const { return m_ortho_tile_compression_algorithm; } +nucleus::utils::ColourTexture::Format Scheduler::ortho_tile_compression_algorithm() const { return m_ortho_tile_compression_algorithm; } -void Scheduler::set_ortho_tile_compression_algorithm(nucleus::utils::ColourTexture::Algorithm new_ortho_tile_compression_algorithm) +void Scheduler::set_ortho_tile_compression_algorithm(nucleus::utils::ColourTexture::Format new_ortho_tile_compression_algorithm) { m_ortho_tile_compression_algorithm = new_ortho_tile_compression_algorithm; } diff --git a/nucleus/tile_scheduler/Scheduler.h b/nucleus/tile_scheduler/Scheduler.h index 64ce68e1..44506940 100644 --- a/nucleus/tile_scheduler/Scheduler.h +++ b/nucleus/tile_scheduler/Scheduler.h @@ -77,8 +77,8 @@ class Scheduler : public QObject { void set_retirement_age_for_tile_cache(unsigned int new_retirement_age_for_tile_cache); - nucleus::utils::ColourTexture::Algorithm ortho_tile_compression_algorithm() const; - void set_ortho_tile_compression_algorithm(nucleus::utils::ColourTexture::Algorithm new_ortho_tile_compression_algorithm); + nucleus::utils::ColourTexture::Format ortho_tile_compression_algorithm() const; + void set_ortho_tile_compression_algorithm(nucleus::utils::ColourTexture::Format new_ortho_tile_compression_algorithm); signals: void statistics_updated(Statistics stats); @@ -124,6 +124,6 @@ public slots: Cache m_gpu_cached; std::shared_ptr m_default_ortho_tile; std::shared_ptr m_default_height_tile; - nucleus::utils::ColourTexture::Algorithm m_ortho_tile_compression_algorithm = nucleus::utils::ColourTexture::Algorithm::Uncompressed_RGBA; + nucleus::utils::ColourTexture::Format m_ortho_tile_compression_algorithm = nucleus::utils::ColourTexture::Format::Uncompressed_RGBA; }; } diff --git a/nucleus/utils/ColourTexture.cpp b/nucleus/utils/ColourTexture.cpp index 7e557f28..d9114ab6 100644 --- a/nucleus/utils/ColourTexture.cpp +++ b/nucleus/utils/ColourTexture.cpp @@ -110,9 +110,9 @@ std::vector to_uncompressed_rgba(const QImage& qimage) return data; } -std::vector to_compressed(const QImage& image, nucleus::utils::ColourTexture::Algorithm algorithm) +std::vector to_compressed(const QImage& image, nucleus::utils::ColourTexture::Format algorithm) { - using Algorithm = nucleus::utils::ColourTexture::Algorithm; + using Algorithm = nucleus::utils::ColourTexture::Format; switch (algorithm) { case Algorithm::DXT1: @@ -127,10 +127,10 @@ std::vector to_compressed(const QImage& image, nucleus::utils::ColourTe } } // namespace -nucleus::utils::ColourTexture::ColourTexture(const QImage& image, Algorithm algorithm) - : m_data(to_compressed(image, algorithm)) +nucleus::utils::ColourTexture::ColourTexture(const QImage& image, Format format) + : m_data(to_compressed(image, format)) , m_width(unsigned(image.width())) , m_height(unsigned(image.height())) - , m_algorithm(algorithm) + , m_format(format) { } diff --git a/nucleus/utils/ColourTexture.h b/nucleus/utils/ColourTexture.h index a0f35bd5..612b7d41 100644 --- a/nucleus/utils/ColourTexture.h +++ b/nucleus/utils/ColourTexture.h @@ -24,21 +24,21 @@ namespace nucleus::utils { class ColourTexture { public: - enum class Algorithm { Uncompressed_RGBA, DXT1, ETC1 }; + enum class Format { Uncompressed_RGBA, DXT1, ETC1 }; private: std::vector m_data; unsigned m_width = 0; unsigned m_height = 0; - Algorithm m_algorithm = Algorithm::Uncompressed_RGBA; + Format m_format = Format::Uncompressed_RGBA; public: - explicit ColourTexture(const QImage& image, Algorithm algorithm); + explicit ColourTexture(const QImage& image, Format format); [[nodiscard]] const uint8_t* data() const { return m_data.data(); } [[nodiscard]] size_t n_bytes() const { return m_data.size(); } [[nodiscard]] unsigned width() const { return m_width; } [[nodiscard]] unsigned height() const { return m_height; } - [[nodiscard]] Algorithm algorithm() const { return m_algorithm; } + [[nodiscard]] Format format() const { return m_format; } }; } // namespace nucleus::utils diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index 8d0a109b..9a81d34d 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -91,15 +91,15 @@ TEST_CASE("gl texture") SECTION("compression") { { - const auto compressed = ColourTexture(test_texture, ColourTexture::Algorithm::DXT1); + const auto compressed = ColourTexture(test_texture, ColourTexture::Format::DXT1); CHECK(compressed.n_bytes() == 256 * 128); } { - const auto compressed = ColourTexture(test_texture, ColourTexture::Algorithm::ETC1); + const auto compressed = ColourTexture(test_texture, ColourTexture::Format::ETC1); CHECK(compressed.n_bytes() == 256 * 128); } { - const auto compressed = ColourTexture(test_texture, ColourTexture::Algorithm::Uncompressed_RGBA); + const auto compressed = ColourTexture(test_texture, ColourTexture::Format::Uncompressed_RGBA); CHECK(compressed.n_bytes() == 256 * 256 * 4); } } @@ -162,10 +162,10 @@ TEST_CASE("gl texture") SECTION("rgba") { - Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 256, 256 }); + Framebuffer b(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8 }, { 256, 256 }); b.bind(); - - const auto compressed = ColourTexture(test_texture, ColourTexture::Algorithm::Uncompressed_RGBA); + + const auto compressed = ColourTexture(test_texture, ColourTexture::Format::Uncompressed_RGBA); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::RGBA8); opengl_texture.bind(0); opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); @@ -191,7 +191,7 @@ TEST_CASE("gl texture") SECTION("rg8") { - Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 1, 1 }); + Framebuffer b(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8 }, { 1, 1 }); b.bind(); const auto tex = nucleus::Raster({ 1, 1 }, glm::u8vec2(240, 120)); @@ -215,7 +215,7 @@ TEST_CASE("gl texture") SECTION("red16") { - Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }, { 1, 1 }); + Framebuffer b(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8 }, { 1, 1 }); b.bind(); const auto tex = nucleus::Raster({ 1, 1 }, uint16_t(120 * 256)); @@ -251,11 +251,11 @@ TEST_CASE("gl texture") Framebuffer framebuffer(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8, Framebuffer::ColourFormat::RGBA8, Framebuffer::ColourFormat::RGBA8 }, { 256, 256 }); framebuffer.bind(); - - std::array texture_types = { ColourTexture::Algorithm::Uncompressed_RGBA, gl_engine::Texture::compression_algorithm() }; + + std::array texture_types = { ColourTexture::Format::Uncompressed_RGBA, gl_engine::Texture::compression_algorithm() }; for (auto texture_type : texture_types) { - const auto format = (texture_type == ColourTexture::Algorithm::Uncompressed_RGBA) ? gl_engine::Texture::Format::RGBA8 - : gl_engine::Texture::Format::CompressedRGBA8; + const auto format + = (texture_type == ColourTexture::Format::Uncompressed_RGBA) ? gl_engine::Texture::Format::RGBA8 : gl_engine::Texture::Format::CompressedRGBA8; gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2dArray, format); opengl_texture.bind(0); opengl_texture.setParams(gl_engine::Texture::Filter::Linear, gl_engine::Texture::Filter::Linear); From 2fdbf68bf5919da9c4ef856a311e9669eacd23f6 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 21 Feb 2024 01:15:43 +0100 Subject: [PATCH 40/65] move ortho textures to an array --- gl_engine/Texture.cpp | 7 +++ gl_engine/Texture.h | 3 ++ gl_engine/TileManager.cpp | 80 ++++++++++++++++++++-------------- gl_engine/TileManager.h | 15 +++---- gl_engine/TileSet.h | 2 +- gl_engine/Window.cpp | 8 ++-- gl_engine/Window.h | 1 + gl_engine/shaders/tile.frag | 6 ++- nucleus/AbstractRenderWindow.h | 1 + nucleus/Controller.cpp | 3 +- 10 files changed, 75 insertions(+), 51 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index c23caa51..fa209395 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -89,6 +89,9 @@ void gl_engine::Texture::allocate_array(unsigned int width, unsigned int height, internalformat = gl_engine::Texture::compressed_texture_format(); f->glTexStorage3D(GLenum(m_target), mip_level_count, internalformat, GLsizei(width), GLsizei(height), GLsizei(n_layers)); + m_width = width; + m_height = height; + m_n_layers = n_layers; } void gl_engine::Texture::upload(const nucleus::utils::ColourTexture& texture) @@ -113,6 +116,10 @@ void gl_engine::Texture::upload(const nucleus::utils::ColourTexture& texture) void gl_engine::Texture::upload(const nucleus::utils::ColourTexture& texture, unsigned int array_index) { + assert(texture.width() == m_width); + assert(texture.height() == m_height); + assert(array_index < m_n_layers); + auto* f = QOpenGLContext::currentContext()->extraFunctions(); f->glBindTexture(GLenum(m_target), m_id); f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index 9619d439..b5775fd7 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -56,6 +56,9 @@ class Texture { Format m_format = Format::Invalid; Filter m_min_filter = Filter::Nearest; Filter m_mag_filter = Filter::Nearest; + unsigned m_width = unsigned(-1); + unsigned m_height = unsigned(-1); + unsigned m_n_layers = unsigned(-1); }; } // namespace gl_engine diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index 00a46f44..ac014b18 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -61,23 +61,22 @@ void TileManager::init() { using nucleus::utils::terrain_mesh_index_generator::surface_quads_with_curtains; assert(QOpenGLContext::currentContext()); - for (auto i = 0; i < MAX_TILES_PER_TILESET; ++i) { - const auto indices = surface_quads_with_curtains(N_EDGE_VERTICES); - auto index_buffer = std::make_unique(QOpenGLBuffer::IndexBuffer); - index_buffer->create(); - index_buffer->bind(); - index_buffer->setUsagePattern(QOpenGLBuffer::StaticDraw); - index_buffer->allocate(indices.data(), bufferLengthInBytes(indices)); - index_buffer->release(); - m_index_buffers.emplace_back(std::move(index_buffer), indices.size()); - } - auto* f = QOpenGLContext::currentContext()->extraFunctions(); - f->glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_max_anisotropy); -} - -const std::vector& TileManager::tiles() const -{ - return m_gpu_tiles; + const auto indices = surface_quads_with_curtains(N_EDGE_VERTICES); + auto index_buffer = std::make_unique(QOpenGLBuffer::IndexBuffer); + index_buffer->create(); + index_buffer->bind(); + index_buffer->setUsagePattern(QOpenGLBuffer::StaticDraw); + index_buffer->allocate(indices.data(), bufferLengthInBytes(indices)); + index_buffer->release(); + m_index_buffer.first = std::move(index_buffer); + m_index_buffer.second = indices.size(); + + m_ortho_textures = std::make_unique(Texture::Target::_2dArray, Texture::Format::CompressedRGBA8); + m_ortho_textures->setParams(Texture::Filter::Linear, Texture::Filter::Linear); + // TODO: might become larger than GL_MAX_ARRAY_TEXTURE_LAYERS + m_ortho_textures->allocate_array(ORTHO_RESOLUTION, ORTHO_RESOLUTION, unsigned(m_loaded_tiles.size())); + + // m_heightmap_textures = std::make_unique(Texture::Target::_2dArray, Texture::Format::R16UI); } bool compareTileSetPair(std::pair t1, std::pair t2) @@ -95,12 +94,12 @@ void TileManager::draw(ShaderProgram* shader_program, const nucleus::camera::Def { QOpenGLExtraFunctions* f = QOpenGLContext::currentContext()->extraFunctions(); shader_program->set_uniform("n_edge_vertices", N_EDGE_VERTICES); - shader_program->set_uniform("texture_sampler", 2); + shader_program->set_uniform("ortho_sampler", 2); shader_program->set_uniform("height_sampler", 1); // Sort depending on distance to sort_position std::vector> tile_list; - for (const auto& tileset : tiles()) { + for (const auto& tileset : m_gpu_tiles) { float dist = 0.0; if (!draw_tiles.contains(tileset.tiles.front().first)) continue; @@ -115,12 +114,13 @@ void TileManager::draw(ShaderProgram* shader_program, const nucleus::camera::Def } if (sort_tiles) std::sort(tile_list.begin(), tile_list.end(), compareTileSetPair); + m_ortho_textures->bind(2); for (const auto& tileset : tile_list) { tileset.second->vao->bind(); shader_program->set_uniform_array("bounds", boundsArray(*tileset.second, camera.position())); - shader_program->set_uniform("tileset_id", (int)((tileset.second->tiles[0].first.coords[0] + tileset.second->tiles[0].first.coords[1]))); + shader_program->set_uniform("tileset_id", int((tileset.second->tiles[0].first.coords[0] + tileset.second->tiles[0].first.coords[1]))); shader_program->set_uniform("tileset_zoomlevel", tileset.second->tiles[0].first.zoom_level); - tileset.second->ortho_texture->bind(2); + shader_program->set_uniform("texture_layer", int(tileset.second->texture_layer)); tileset.second->heightmap_texture->bind(1); f->glDrawElements(GL_TRIANGLE_STRIP, tileset.second->gl_element_count, tileset.second->gl_index_type, nullptr); } @@ -131,6 +131,12 @@ void TileManager::remove_tile(const tile::Id& tile_id) { if (!QOpenGLContext::currentContext()) // can happen during shutdown. return; + + const auto t = std::find(m_loaded_tiles.begin(), m_loaded_tiles.end(), tile_id); + assert(t != m_loaded_tiles.end()); // removing a tile that's not here. likely there is a race. + *t = tile::Id { unsigned(-1), {} }; + m_draw_list_generator.remove_tile(tile_id); + // clear slot // or remove from list and free resources const auto found_tile = std::find_if(m_gpu_tiles.begin(), m_gpu_tiles.end(), [&tile_id](const TileSet& tileset) { @@ -138,7 +144,6 @@ void TileManager::remove_tile(const tile::Id& tile_id) }); if (found_tile != m_gpu_tiles.end()) m_gpu_tiles.erase(found_tile); - m_draw_list_generator.remove_tile(tile_id); emit tiles_changed(); } @@ -150,6 +155,12 @@ void TileManager::set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbD m_draw_list_generator.set_aabb_decorator(new_aabb_decorator); } +void TileManager::set_quad_limit(unsigned int new_limit) +{ + m_loaded_tiles.resize(new_limit * 4); + std::fill(m_loaded_tiles.begin(), m_loaded_tiles.end(), tile::Id { unsigned(-1), {} }); +} + void TileManager::add_tile( const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::ColourTexture& ortho_texture, const nucleus::Raster& height_map) { @@ -166,20 +177,23 @@ void TileManager::add_tile( tileset.vao->bind(); { // vao state - m_index_buffers[0].first->bind(); - tileset.gl_element_count = int(m_index_buffers[0].second); + m_index_buffer.first->bind(); + tileset.gl_element_count = int(m_index_buffer.second); tileset.gl_index_type = GL_UNSIGNED_SHORT; } tileset.vao->release(); - tileset.ortho_texture = std::make_unique(Texture::Target::_2d, - ortho_texture.format() == nucleus::utils::ColourTexture::Format::Uncompressed_RGBA ? Texture::Format::RGBA8 : Texture::Format::CompressedRGBA8); - tileset.ortho_texture->setParams(Texture::Filter::Linear, Texture::Filter::Linear); - tileset.ortho_texture->upload(ortho_texture); tileset.heightmap_texture = std::make_unique(Texture::Target::_2d, Texture::Format::R16UI); tileset.heightmap_texture->setParams(Texture::Filter::Nearest, Texture::Filter::Nearest); tileset.heightmap_texture->upload(height_map); + // find empty spot and upload texture + const auto t = std::find(m_loaded_tiles.begin(), m_loaded_tiles.end(), tile::Id { unsigned(-1), {} }); + assert(t != m_loaded_tiles.end()); + *t = id; + m_ortho_textures->upload(ortho_texture, unsigned(t - m_loaded_tiles.begin())); + tileset.texture_layer = unsigned(t - m_loaded_tiles.begin()); + // add to m_gpu_tiles m_gpu_tiles.push_back(std::move(tileset)); m_draw_list_generator.add_tile(id); @@ -194,6 +208,11 @@ void TileManager::set_permissible_screen_space_error(float new_permissible_scree void TileManager::update_gpu_quads(const std::vector& new_quads, const std::vector& deleted_quads) { + for (const auto& quad : deleted_quads) { + for (const auto& id : quad.children()) { + remove_tile(id); + } + } for (const auto& quad : new_quads) { for (const auto& tile : quad.tiles) { // test for validity @@ -203,9 +222,4 @@ void TileManager::update_gpu_quads(const std::vector& tiles() const; void draw(ShaderProgram* shader_program, const nucleus::camera::Definition& camera, const nucleus::tile_scheduler::DrawListGenerator::TileSet draw_tiles, bool sort_tiles, glm::dvec3 sort_position) const; const nucleus::tile_scheduler::DrawListGenerator::TileSet generate_tilelist(const nucleus::camera::Definition& camera) const; @@ -60,6 +59,7 @@ public slots: void remove_tile(const tile::Id& tile_id); void initilise_attribute_locations(ShaderProgram* program); void set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr& new_aabb_decorator); + void set_quad_limit(unsigned new_limit); private: void add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::ColourTexture& ortho, const nucleus::Raster& heights); @@ -68,16 +68,13 @@ public slots: static constexpr auto N_EDGE_VERTICES = 65; static constexpr auto ORTHO_RESOLUTION = 256; - static constexpr auto MAX_TILES_PER_TILESET = 1; - float m_max_anisotropy = 0; + + std::vector m_loaded_tiles; + std::pair, size_t> m_index_buffer; + std::unique_ptr m_ortho_textures; + std::unique_ptr m_heightmap_textures; std::vector m_gpu_tiles; - // indexbuffers for 4^index tiles, - // e.g., for single tile tile sets take index 0 - // for 4 tiles take index 1, for 16 2.. - // the size_t is the number of indices - std::vector, size_t>> m_index_buffers; - std::unique_ptr m_dummy_buffer; TileGLAttributeLocations m_attribute_locations; unsigned m_tiles_per_set = 1; nucleus::tile_scheduler::DrawListGenerator m_draw_list_generator; diff --git a/gl_engine/TileSet.h b/gl_engine/TileSet.h index bebd302f..50731dad 100644 --- a/gl_engine/TileSet.h +++ b/gl_engine/TileSet.h @@ -46,12 +46,12 @@ struct TileSet { [[nodiscard]] bool isValid() const { return tile_id.zoom_level < 100; } }; - std::unique_ptr ortho_texture; std::unique_ptr heightmap_texture; std::unique_ptr vao; std::vector> tiles; int gl_element_count = -1; unsigned gl_index_type = 0; + unsigned texture_layer = unsigned(-1); // texture }; } // namespace gl_engine diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index 29a1fe8c..d47ffa3d 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -422,11 +422,9 @@ void Window::updateCameraEvent() emit update_camera_requested(); } -void Window::set_permissible_screen_space_error(float new_error) -{ - if (m_tile_manager) - m_tile_manager->set_permissible_screen_space_error(new_error); -} +void Window::set_permissible_screen_space_error(float new_error) { m_tile_manager->set_permissible_screen_space_error(new_error); } + +void Window::set_quad_limit(unsigned int new_limit) { m_tile_manager->set_quad_limit(new_limit); } void Window::update_camera(const nucleus::camera::Definition& new_definition) { diff --git a/gl_engine/Window.h b/gl_engine/Window.h index aaf64c1f..e6df5a6a 100644 --- a/gl_engine/Window.h +++ b/gl_engine/Window.h @@ -75,6 +75,7 @@ class Window : public nucleus::AbstractRenderWindow, public nucleus::camera::Abs void keyReleaseEvent(QKeyEvent*); void updateCameraEvent(); void set_permissible_screen_space_error(float new_error) override; + void set_quad_limit(unsigned new_limit) override; public slots: void update_camera(const nucleus::camera::Definition& new_definition) override; diff --git a/gl_engine/shaders/tile.frag b/gl_engine/shaders/tile.frag index 5acbe6d1..64a8fba2 100644 --- a/gl_engine/shaders/tile.frag +++ b/gl_engine/shaders/tile.frag @@ -21,7 +21,8 @@ #include "camera_config.glsl" #include "encoder.glsl" -uniform sampler2D texture_sampler; +uniform highp int texture_layer; +uniform sampler2DArray ortho_sampler; layout (location = 0) out lowp vec3 texout_albedo; layout (location = 1) out highp vec4 texout_position; @@ -54,7 +55,8 @@ void main() { #endif // Write Albedo (ortho picture) in gbuffer - lowp vec3 fragColor = texture(texture_sampler, uv).rgb; + highp float texture_layer_f = float(texture_layer); + lowp vec3 fragColor = texture(ortho_sampler, vec3(uv, texture_layer_f)).rgb; fragColor = mix(fragColor, conf.material_color.rgb, conf.material_color.a); texout_albedo = fragColor; diff --git a/nucleus/AbstractRenderWindow.h b/nucleus/AbstractRenderWindow.h index e754147e..405089f2 100644 --- a/nucleus/AbstractRenderWindow.h +++ b/nucleus/AbstractRenderWindow.h @@ -51,6 +51,7 @@ class AbstractRenderWindow : public QObject { virtual void paint(QOpenGLFramebufferObject* framebuffer = nullptr) = 0; virtual void deinit_gpu() = 0; virtual void set_permissible_screen_space_error(float new_error) = 0; + virtual void set_quad_limit(unsigned new_limit) = 0; [[nodiscard]] virtual camera::AbstractDepthTester* depth_tester() = 0; [[nodiscard]] virtual utils::ColourTexture::Format ortho_tile_compression_algorithm() const = 0; diff --git a/nucleus/Controller.cpp b/nucleus/Controller.cpp index 2408fa78..3c0aa821 100644 --- a/nucleus/Controller.cpp +++ b/nucleus/Controller.cpp @@ -60,7 +60,8 @@ Controller::Controller(AbstractRenderWindow* render_window) m_tile_scheduler = std::make_unique(); m_tile_scheduler->read_disk_cache(); - m_tile_scheduler->set_gpu_quad_limit(500); + m_render_window->set_quad_limit(512); // must be same as scheduler, dynamic resizing is not supported atm + m_tile_scheduler->set_gpu_quad_limit(512); m_tile_scheduler->set_ram_quad_limit(12000); { QFile file(":/map/height_data.atb"); From 8749909b4ae9a087439107dd140c80ccb9951174 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 21 Feb 2024 23:48:40 +0100 Subject: [PATCH 41/65] uint16 array textures --- gl_engine/Texture.cpp | 28 ++++++++++++++---- gl_engine/Texture.h | 1 + unittests/gl_engine/texture.cpp | 52 ++++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index fa209395..248e9ba9 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -35,7 +35,6 @@ gl_engine::Texture::Texture(Target target, Format format) { QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glGenTextures(1, &m_id); - bind(0); } gl_engine::Texture::~Texture() @@ -78,7 +77,6 @@ void gl_engine::Texture::allocate_array(unsigned int width, unsigned int height, { assert(m_target == Target::_2dArray); assert(m_format != Format::Invalid); - auto* f = QOpenGLContext::currentContext()->extraFunctions(); auto mip_level_count = 1; if (m_min_filter == Filter::MipMapLinear) @@ -88,10 +86,13 @@ void gl_engine::Texture::allocate_array(unsigned int width, unsigned int height, if (m_format == Format::CompressedRGBA8) internalformat = gl_engine::Texture::compressed_texture_format(); - f->glTexStorage3D(GLenum(m_target), mip_level_count, internalformat, GLsizei(width), GLsizei(height), GLsizei(n_layers)); m_width = width; m_height = height; m_n_layers = n_layers; + + auto* f = QOpenGLContext::currentContext()->extraFunctions(); + f->glBindTexture(GLenum(m_target), m_id); + f->glTexStorage3D(GLenum(m_target), mip_level_count, internalformat, GLsizei(width), GLsizei(height), GLsizei(n_layers)); } void gl_engine::Texture::upload(const nucleus::utils::ColourTexture& texture) @@ -154,14 +155,31 @@ void gl_engine::Texture::upload(const nucleus::Raster& texture) void gl_engine::Texture::upload(const nucleus::Raster& texture) { assert(m_format == Format::R16UI); + assert(m_mag_filter == Filter::Nearest); // not filterable according to + assert(m_min_filter == Filter::Nearest); // https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glBindTexture(GLenum(m_target), m_id); f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); f->glTexImage2D(GLenum(m_target), 0, GL_R16UI, GLsizei(texture.width()), GLsizei(texture.height()), 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, texture.bytes()); +} - // not Texture filterable according to https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml - assert(m_min_filter != Filter::MipMapLinear); +void gl_engine::Texture::upload(const nucleus::Raster& texture, unsigned int array_index) +{ + assert(m_format == Format::R16UI); + assert(m_mag_filter == Filter::Nearest); // not filterable according to + assert(m_min_filter == Filter::Nearest); // https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml + assert(array_index < m_n_layers); + assert(texture.width() == m_width); + assert(texture.height() == m_height); + + const auto width = GLsizei(texture.width()); + const auto height = GLsizei(texture.height()); + + auto* f = QOpenGLContext::currentContext()->extraFunctions(); + f->glBindTexture(GLenum(m_target), m_id); + f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + f->glTexSubImage3D(GLenum(m_target), 0, 0, 0, GLint(array_index), width, height, 1, GL_RED_INTEGER, GL_UNSIGNED_SHORT, texture.bytes()); } GLenum gl_engine::Texture::compressed_texture_format() diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index b5775fd7..0c0c0f48 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -46,6 +46,7 @@ class Texture { void upload(const nucleus::utils::ColourTexture& texture, unsigned array_index); void upload(const nucleus::Raster& texture); void upload(const nucleus::Raster& texture); + void upload(const nucleus::Raster& texture, unsigned int array_index); static GLenum compressed_texture_format(); static nucleus::utils::ColourTexture::Format compression_algorithm(); diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index 9a81d34d..33f982d8 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -218,7 +218,7 @@ TEST_CASE("gl texture") Framebuffer b(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8 }, { 1, 1 }); b.bind(); - const auto tex = nucleus::Raster({ 1, 1 }, uint16_t(120 * 256)); + const auto tex = nucleus::Raster({ 1, 1 }, uint16_t((120 * 65535) / 255)); gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2d, gl_engine::Texture::Format::R16UI); opengl_texture.bind(0); opengl_texture.setParams(gl_engine::Texture::Filter::Nearest, gl_engine::Texture::Filter::Nearest); @@ -333,4 +333,54 @@ TEST_CASE("gl texture") } } } + + SECTION("red16 array") + { + Framebuffer b(Framebuffer::DepthFormat::None, { Framebuffer::ColourFormat::RGBA8, Framebuffer::ColourFormat::RGBA8 }, { 1, 1 }); + b.bind(); + + gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2dArray, gl_engine::Texture::Format::R16UI); + opengl_texture.allocate_array(1, 1, 2); + opengl_texture.setParams(gl_engine::Texture::Filter::Nearest, gl_engine::Texture::Filter::Nearest); + opengl_texture.upload(nucleus::Raster({ 1, 1 }, uint16_t((120 * 65535) / 255)), 0); + opengl_texture.upload(nucleus::Raster({ 1, 1 }, uint16_t((190 * 65535) / 255)), 1); + + ShaderProgram shader = create_debug_shader(R"( + uniform mediump usampler2DArray texture_sampler; + out lowp vec4 out_color1; + out lowp vec4 out_color2; + void main() { + { + mediump uint v = texture(texture_sampler, vec3(0.5, 0.5, 0)).r; + highp float v2 = float(v); // need temporary for android, otherwise it is cast to a mediump float and 0 is returned. + out_color1 = vec4(v2 / 65535.0, 0, 0, 1); + } + + { + mediump uint v = texture(texture_sampler, vec3(0.5, 0.5, 1)).r; + highp float v2 = float(v); // need temporary for android, otherwise it is cast to a mediump float and 0 is returned. + out_color2 = vec4(v2 / 65535.0, 0, 0, 1); + } + } + )"); + shader.bind(); + opengl_texture.bind(0); + shader.set_uniform("texture_sampler", 0); + gl_engine::helpers::create_screen_quad_geometry().draw(); + + { + const QImage render_result = b.read_colour_attachment(0); + CHECK(qRed(render_result.pixel(0, 0)) == 120); + CHECK(qGreen(render_result.pixel(0, 0)) == 0); + CHECK(qBlue(render_result.pixel(0, 0)) == 0); + CHECK(qAlpha(render_result.pixel(0, 0)) == 255); + } + { + const QImage render_result = b.read_colour_attachment(1); + CHECK(qRed(render_result.pixel(0, 0)) == 190); + CHECK(qGreen(render_result.pixel(0, 0)) == 0); + CHECK(qBlue(render_result.pixel(0, 0)) == 0); + CHECK(qAlpha(render_result.pixel(0, 0)) == 255); + } + } } From cb1fb348e7911af0c733edee96585f3ebd727ca0 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Thu, 22 Feb 2024 21:00:45 +0100 Subject: [PATCH 42/65] fix filtering and clamping for array textures --- gl_engine/Texture.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 248e9ba9..29239daf 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -67,10 +67,10 @@ void gl_engine::Texture::setParams(Filter min_filter, Filter mag_filter) QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glBindTexture(GLenum(m_target), m_id); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLint(m_min_filter)); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLint(m_mag_filter)); + f->glTexParameteri(GLenum(m_target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GLenum(m_target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + f->glTexParameteri(GLenum(m_target), GL_TEXTURE_MIN_FILTER, GLint(m_min_filter)); + f->glTexParameteri(GLenum(m_target), GL_TEXTURE_MAG_FILTER, GLint(m_mag_filter)); } void gl_engine::Texture::allocate_array(unsigned int width, unsigned int height, unsigned int n_layers) From 3243a7fc2f917e3f2a0c6c240e8e9da038cd6344 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Thu, 22 Feb 2024 21:00:56 +0100 Subject: [PATCH 43/65] fix array textures for webassembly --- gl_engine/shaders/tile.frag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gl_engine/shaders/tile.frag b/gl_engine/shaders/tile.frag index 64a8fba2..849dab23 100644 --- a/gl_engine/shaders/tile.frag +++ b/gl_engine/shaders/tile.frag @@ -22,7 +22,7 @@ #include "encoder.glsl" uniform highp int texture_layer; -uniform sampler2DArray ortho_sampler; +uniform lowp sampler2DArray ortho_sampler; layout (location = 0) out lowp vec3 texout_albedo; layout (location = 1) out highp vec4 texout_position; From 60f04c4f5ac24af717e60094dbd92854683ed30d Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Thu, 22 Feb 2024 21:01:25 +0100 Subject: [PATCH 44/65] fix compilation for webassembly --- gl_engine/Texture.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 29239daf..6c2d3d1c 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -224,11 +224,11 @@ nucleus::utils::ColourTexture::Format gl_engine::Texture::compression_algorithm( }); // clang-format on if (gl_texture_format == 0) { - return nucleus::utils::CompressedTexture::Algorithm::DXT1; + return nucleus::utils::ColourTexture::Format::DXT1; } - return nucleus::utils::CompressedTexture::Algorithm::ETC1; + return nucleus::utils::ColourTexture::Format::ETC1; #elif defined(__ANDROID__) - return nucleus::utils::CompressedTexture::Algorithm::ETC1; + return nucleus::utils::ColourTexture::Format::ETC1; #else return nucleus::utils::ColourTexture::Format::DXT1; #endif From 05badbc6e6f5a21f54b5846a106724c6fc85ce35 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Thu, 22 Feb 2024 21:25:07 +0100 Subject: [PATCH 45/65] use height map array, only one vao for all tiles + clean up --- gl_engine/TileManager.cpp | 36 +++++++++++++----------------- gl_engine/TileManager.h | 14 +++++++----- gl_engine/TileSet.h | 10 --------- gl_engine/shaders/shadowmap.vert | 5 +++-- gl_engine/shaders/tile.vert | 15 +++++++------ nucleus/tile_scheduler/Scheduler.h | 2 +- 6 files changed, 37 insertions(+), 45 deletions(-) diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index ac014b18..f498741d 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -71,12 +71,20 @@ void TileManager::init() m_index_buffer.first = std::move(index_buffer); m_index_buffer.second = indices.size(); + m_vao = std::make_unique(); + m_vao->create(); + m_vao->bind(); + m_index_buffer.first->bind(); + m_vao->release(); + m_ortho_textures = std::make_unique(Texture::Target::_2dArray, Texture::Format::CompressedRGBA8); m_ortho_textures->setParams(Texture::Filter::Linear, Texture::Filter::Linear); // TODO: might become larger than GL_MAX_ARRAY_TEXTURE_LAYERS m_ortho_textures->allocate_array(ORTHO_RESOLUTION, ORTHO_RESOLUTION, unsigned(m_loaded_tiles.size())); - // m_heightmap_textures = std::make_unique(Texture::Target::_2dArray, Texture::Format::R16UI); + m_heightmap_textures = std::make_unique(Texture::Target::_2dArray, Texture::Format::R16UI); + m_heightmap_textures->setParams(Texture::Filter::Nearest, Texture::Filter::Nearest); + m_heightmap_textures->allocate_array(HEIGHTMAP_RESOLUTION, HEIGHTMAP_RESOLUTION, unsigned(m_loaded_tiles.size())); } bool compareTileSetPair(std::pair t1, std::pair t2) @@ -115,14 +123,14 @@ void TileManager::draw(ShaderProgram* shader_program, const nucleus::camera::Def if (sort_tiles) std::sort(tile_list.begin(), tile_list.end(), compareTileSetPair); m_ortho_textures->bind(2); + m_heightmap_textures->bind(1); + m_vao->bind(); for (const auto& tileset : tile_list) { - tileset.second->vao->bind(); shader_program->set_uniform_array("bounds", boundsArray(*tileset.second, camera.position())); shader_program->set_uniform("tileset_id", int((tileset.second->tiles[0].first.coords[0] + tileset.second->tiles[0].first.coords[1]))); shader_program->set_uniform("tileset_zoomlevel", tileset.second->tiles[0].first.zoom_level); shader_program->set_uniform("texture_layer", int(tileset.second->texture_layer)); - tileset.second->heightmap_texture->bind(1); - f->glDrawElements(GL_TRIANGLE_STRIP, tileset.second->gl_element_count, tileset.second->gl_index_type, nullptr); + f->glDrawElements(GL_TRIANGLE_STRIP, int(m_index_buffer.second), GL_UNSIGNED_SHORT, nullptr); } f->glBindVertexArray(0); } @@ -172,27 +180,15 @@ void TileManager::add_tile( // setup / copy data to gpu TileSet tileset; tileset.tiles.emplace_back(id, tile::SrsBounds(bounds)); - tileset.vao = std::make_unique(); - tileset.vao->create(); - tileset.vao->bind(); - - { // vao state - m_index_buffer.first->bind(); - tileset.gl_element_count = int(m_index_buffer.second); - tileset.gl_index_type = GL_UNSIGNED_SHORT; - } - tileset.vao->release(); - - tileset.heightmap_texture = std::make_unique(Texture::Target::_2d, Texture::Format::R16UI); - tileset.heightmap_texture->setParams(Texture::Filter::Nearest, Texture::Filter::Nearest); - tileset.heightmap_texture->upload(height_map); // find empty spot and upload texture const auto t = std::find(m_loaded_tiles.begin(), m_loaded_tiles.end(), tile::Id { unsigned(-1), {} }); assert(t != m_loaded_tiles.end()); *t = id; - m_ortho_textures->upload(ortho_texture, unsigned(t - m_loaded_tiles.begin())); - tileset.texture_layer = unsigned(t - m_loaded_tiles.begin()); + const auto layer_index = unsigned(t - m_loaded_tiles.begin()); + tileset.texture_layer = layer_index; + m_ortho_textures->upload(ortho_texture, layer_index); + m_heightmap_textures->upload(height_map, layer_index); // add to m_gpu_tiles m_gpu_tiles.push_back(std::move(tileset)); diff --git a/gl_engine/TileManager.h b/gl_engine/TileManager.h index 736fa598..1a52e1e3 100644 --- a/gl_engine/TileManager.h +++ b/gl_engine/TileManager.h @@ -1,4 +1,4 @@ - /***************************************************************************** +/***************************************************************************** * Alpine Terrain Renderer * Copyright (C) 2023 Adam Celerek * Copyright (C) 2023 Gerald Kimmersdorfer @@ -22,12 +22,14 @@ #include #include +#include +#include -#include - +#include "gl_engine/Texture.h" #include "gl_engine/TileSet.h" -#include "nucleus/Tile.h" -#include "nucleus/tile_scheduler/DrawListGenerator.h" +#include +#include +#include namespace camera { class Definition; @@ -68,11 +70,13 @@ public slots: static constexpr auto N_EDGE_VERTICES = 65; static constexpr auto ORTHO_RESOLUTION = 256; + static constexpr auto HEIGHTMAP_RESOLUTION = 65; std::vector m_loaded_tiles; std::pair, size_t> m_index_buffer; std::unique_ptr m_ortho_textures; std::unique_ptr m_heightmap_textures; + std::unique_ptr m_vao; std::vector m_gpu_tiles; TileGLAttributeLocations m_attribute_locations; diff --git a/gl_engine/TileSet.h b/gl_engine/TileSet.h index 50731dad..3c0edfce 100644 --- a/gl_engine/TileSet.h +++ b/gl_engine/TileSet.h @@ -19,14 +19,8 @@ #pragma once -#include #include -#include -#include -#include - -#include "Texture.h" #include "radix/tile.h" // we want to be flexible and have the ability to draw several tiles at once. @@ -46,11 +40,7 @@ struct TileSet { [[nodiscard]] bool isValid() const { return tile_id.zoom_level < 100; } }; - std::unique_ptr heightmap_texture; - std::unique_ptr vao; std::vector> tiles; - int gl_element_count = -1; - unsigned gl_index_type = 0; unsigned texture_layer = unsigned(-1); // texture }; diff --git a/gl_engine/shaders/shadowmap.vert b/gl_engine/shaders/shadowmap.vert index 9981d5f2..f1ade705 100644 --- a/gl_engine/shaders/shadowmap.vert +++ b/gl_engine/shaders/shadowmap.vert @@ -24,7 +24,8 @@ uniform highp vec4 bounds[32]; uniform highp int n_edge_vertices; -uniform mediump usampler2D height_sampler; +uniform highp int texture_layer; +uniform mediump usampler2DArray height_sampler; uniform lowp int current_layer; @@ -72,7 +73,7 @@ void main() { float altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 vec2 uv = vec2(float(col) / edge_vertices_count_float, float(row) / edge_vertices_count_float); - highp float adjusted_altitude = float(texture(height_sampler, uv).r) * altitude_correction_factor; + highp float adjusted_altitude = float(texture(height_sampler, vec3(uv, texture_layer)).r) * altitude_correction_factor; highp vec3 var_pos_cws = vec3(float(col) * tile_width + bounds[geometry_id].x, var_pos_cws_y, diff --git a/gl_engine/shaders/tile.vert b/gl_engine/shaders/tile.vert index 21b02ba7..42827ef1 100644 --- a/gl_engine/shaders/tile.vert +++ b/gl_engine/shaders/tile.vert @@ -25,7 +25,8 @@ uniform highp vec4 bounds[32]; uniform highp int n_edge_vertices; uniform highp int tileset_id; uniform highp int tileset_zoomlevel; -uniform mediump usampler2D height_sampler; +uniform highp int texture_layer; +uniform mediump usampler2DArray height_sampler; out highp vec2 uv; out highp vec3 var_pos_cws; @@ -48,13 +49,13 @@ highp vec3 normal_by_finite_difference_method(vec2 uv, float edge_vertices_count // from here: https://stackoverflow.com/questions/6656358/calculating-normals-in-a-triangle-mesh/21660173#21660173 vec2 offset = vec2(1.0, 0.0) / (edge_vertices_count); float height = tile_width + tile_height; - highp float hL = float(texture(height_sampler, uv - offset.xy).r); + highp float hL = float(texture(height_sampler, vec3(uv - offset.xy, texture_layer)).r); hL *= altitude_correction_factor; - highp float hR = float(texture(height_sampler, uv + offset.xy).r); + highp float hR = float(texture(height_sampler, vec3(uv + offset.xy, texture_layer)).r); hR *= altitude_correction_factor; - highp float hD = float(texture(height_sampler, uv + offset.yx).r); + highp float hD = float(texture(height_sampler, vec3(uv + offset.yx, texture_layer)).r); hD *= altitude_correction_factor; - highp float hU = float(texture(height_sampler, uv - offset.yx).r); + highp float hU = float(texture(height_sampler, vec3(uv - offset.yx, texture_layer)).r); hU *= altitude_correction_factor; return normalize(vec3(hL - hR, hD - hU, height)); @@ -104,7 +105,7 @@ void main() { uv = vec2(float(col) / edge_vertices_count_float, float(row) / edge_vertices_count_float); - float altitude_tex = float(texture(height_sampler, uv).r); + float altitude_tex = float(texture(height_sampler, vec3(uv, texture_layer)).r); float adjusted_altitude = altitude_tex * altitude_correction_factor; var_pos_cws = vec3(float(col) * tile_width + bounds[geometry_id].x, @@ -133,6 +134,6 @@ void main() { case 2u: vertex_color = color_from_id_hash(uint(tileset_id)); break; case 3u: vertex_color = color_from_id_hash(uint(tileset_zoomlevel)); break; case 4u: vertex_color = color_from_id_hash(uint(gl_VertexID)); break; - case 5u: vertex_color = vec3(texture(height_sampler, uv).rrr) / 65535.0; break; + case 5u: vertex_color = vec3(texture(height_sampler, vec3(uv, texture_layer)).rrr) / 65535.0; break; } } diff --git a/nucleus/tile_scheduler/Scheduler.h b/nucleus/tile_scheduler/Scheduler.h index 44506940..5db665f8 100644 --- a/nucleus/tile_scheduler/Scheduler.h +++ b/nucleus/tile_scheduler/Scheduler.h @@ -111,7 +111,7 @@ public slots: unsigned m_gpu_quad_limit = 300; unsigned m_ram_quad_limit = 15000; static constexpr unsigned m_ortho_tile_size = 256; - static constexpr unsigned m_height_tile_size = 64; + static constexpr unsigned m_height_tile_size = 65; bool m_enabled = false; bool m_network_requests_enabled = true; Statistics m_statistics; From f5f2e186cf76bf63d1b1e7163b7a20b75f83a05e Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Fri, 23 Feb 2024 00:36:43 +0100 Subject: [PATCH 46/65] instanced drawing (less cpu usage, but gpu stayed almost the same) --- gl_engine/TileManager.cpp | 133 +++++++++++++++++++++++-------- gl_engine/TileManager.h | 9 ++- gl_engine/TileSet.h | 14 +--- gl_engine/shaders/shadowmap.vert | 11 ++- gl_engine/shaders/tile.frag | 4 +- gl_engine/shaders/tile.vert | 19 ++--- 6 files changed, 125 insertions(+), 65 deletions(-) diff --git a/gl_engine/TileManager.cpp b/gl_engine/TileManager.cpp index f498741d..2bb1a582 100644 --- a/gl_engine/TileManager.cpp +++ b/gl_engine/TileManager.cpp @@ -37,19 +37,6 @@ int bufferLengthInBytes(const std::vector& vec) { return int(vec.size() * sizeof(T)); } - -std::vector boundsArray(const TileSet& tileset, const glm::dvec3& camera_position) -{ - std::vector ret; - ret.reserve(tileset.tiles.size()); - for (const auto& tile : tileset.tiles) { - ret.emplace_back(tile.second.min.x - camera_position.x, - tile.second.min.y - camera_position.y, - tile.second.max.x - camera_position.x, - tile.second.max.y - camera_position.y); - } - return ret; -} } TileManager::TileManager(QObject* parent) @@ -71,6 +58,30 @@ void TileManager::init() m_index_buffer.first = std::move(index_buffer); m_index_buffer.second = indices.size(); + m_bounds_buffer = std::make_unique(QOpenGLBuffer::VertexBuffer); + m_bounds_buffer->create(); + m_bounds_buffer->bind(); + m_bounds_buffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); + m_bounds_buffer->allocate(GLsizei(m_loaded_tiles.size() * sizeof(glm::vec4))); + + m_tileset_id_buffer = std::make_unique(QOpenGLBuffer::VertexBuffer); + m_tileset_id_buffer->create(); + m_tileset_id_buffer->bind(); + m_tileset_id_buffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); + m_tileset_id_buffer->allocate(GLsizei(m_loaded_tiles.size() * sizeof(int32_t))); + + m_zoom_level_buffer = std::make_unique(QOpenGLBuffer::VertexBuffer); + m_zoom_level_buffer->create(); + m_zoom_level_buffer->bind(); + m_zoom_level_buffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); + m_zoom_level_buffer->allocate(GLsizei(m_loaded_tiles.size() * sizeof(int32_t))); + + m_texture_layer_buffer = std::make_unique(QOpenGLBuffer::VertexBuffer); + m_texture_layer_buffer->create(); + m_texture_layer_buffer->bind(); + m_texture_layer_buffer->setUsagePattern(QOpenGLBuffer::DynamicDraw); + m_texture_layer_buffer->allocate(GLsizei(m_loaded_tiles.size() * sizeof(int32_t))); + m_vao = std::make_unique(); m_vao->create(); m_vao->bind(); @@ -109,13 +120,10 @@ void TileManager::draw(ShaderProgram* shader_program, const nucleus::camera::Def std::vector> tile_list; for (const auto& tileset : m_gpu_tiles) { float dist = 0.0; - if (!draw_tiles.contains(tileset.tiles.front().first)) + if (!draw_tiles.contains(tileset.tile_id)) continue; if (sort_tiles) { - glm::vec2 pos_wrt = glm::vec2( - tileset.tiles[0].second.min.x - sort_position.x, - tileset.tiles[0].second.min.y - sort_position.y - ); + glm::vec2 pos_wrt = glm::vec2(tileset.bounds.min.x - sort_position.x, tileset.bounds.min.y - sort_position.y); dist = glm::length(pos_wrt); } tile_list.push_back(std::pair(dist, &tileset)); @@ -125,13 +133,41 @@ void TileManager::draw(ShaderProgram* shader_program, const nucleus::camera::Def m_ortho_textures->bind(2); m_heightmap_textures->bind(1); m_vao->bind(); + + std::vector bounds; + bounds.reserve(tile_list.size()); + + std::vector tileset_id; + tileset_id.reserve(tile_list.size()); + + std::vector zoom_level; + zoom_level.reserve(tile_list.size()); + + std::vector texture_layer; + texture_layer.reserve(tile_list.size()); + for (const auto& tileset : tile_list) { - shader_program->set_uniform_array("bounds", boundsArray(*tileset.second, camera.position())); - shader_program->set_uniform("tileset_id", int((tileset.second->tiles[0].first.coords[0] + tileset.second->tiles[0].first.coords[1]))); - shader_program->set_uniform("tileset_zoomlevel", tileset.second->tiles[0].first.zoom_level); - shader_program->set_uniform("texture_layer", int(tileset.second->texture_layer)); - f->glDrawElements(GL_TRIANGLE_STRIP, int(m_index_buffer.second), GL_UNSIGNED_SHORT, nullptr); + bounds.emplace_back(tileset.second->bounds.min.x - camera.position().x, tileset.second->bounds.min.y - camera.position().y, + tileset.second->bounds.max.x - camera.position().x, tileset.second->bounds.max.y - camera.position().y); + + tileset_id.emplace_back(tileset.second->tile_id.coords[0] + tileset.second->tile_id.coords[1]); + zoom_level.emplace_back(tileset.second->tile_id.zoom_level); + texture_layer.emplace_back(tileset.second->texture_layer); } + + m_bounds_buffer->bind(); + m_bounds_buffer->write(0, bounds.data(), GLsizei(bounds.size() * sizeof(decltype(bounds)::value_type))); + + m_tileset_id_buffer->bind(); + m_tileset_id_buffer->write(0, tileset_id.data(), GLsizei(tileset_id.size() * sizeof(decltype(tileset_id)::value_type))); + + m_zoom_level_buffer->bind(); + m_zoom_level_buffer->write(0, zoom_level.data(), GLsizei(zoom_level.size() * sizeof(decltype(zoom_level)::value_type))); + + m_texture_layer_buffer->bind(); + m_texture_layer_buffer->write(0, texture_layer.data(), GLsizei(texture_layer.size() * sizeof(decltype(texture_layer)::value_type))); + + f->glDrawElementsInstanced(GL_TRIANGLE_STRIP, GLsizei(m_index_buffer.second), GL_UNSIGNED_SHORT, nullptr, GLsizei(tile_list.size())); f->glBindVertexArray(0); } @@ -147,16 +183,51 @@ void TileManager::remove_tile(const tile::Id& tile_id) // clear slot // or remove from list and free resources - const auto found_tile = std::find_if(m_gpu_tiles.begin(), m_gpu_tiles.end(), [&tile_id](const TileSet& tileset) { - return tileset.tiles.front().first == tile_id; - }); + const auto found_tile = std::find_if(m_gpu_tiles.begin(), m_gpu_tiles.end(), [&tile_id](const TileSet& tileset) { return tileset.tile_id == tile_id; }); if (found_tile != m_gpu_tiles.end()) m_gpu_tiles.erase(found_tile); emit tiles_changed(); } -void TileManager::initilise_attribute_locations(ShaderProgram* /*program*/) { } +void TileManager::initilise_attribute_locations(ShaderProgram* program) +{ + int bounds = program->attribute_location("bounds"); + qDebug() << "attrib location for bounds: " << bounds; + int tileset_id = program->attribute_location("tileset_id"); + qDebug() << "attrib location for tileset_id: " << tileset_id; + int zoom_level = program->attribute_location("tileset_zoomlevel"); + qDebug() << "attrib location for zoom_level: " << zoom_level; + int texture_layer = program->attribute_location("texture_layer"); + qDebug() << "attrib location for texture_layer: " << texture_layer; + + m_vao->bind(); + QOpenGLExtraFunctions* f = QOpenGLContext::currentContext()->extraFunctions(); + if (bounds != -1) { + m_bounds_buffer->bind(); + f->glEnableVertexAttribArray(GLuint(bounds)); + f->glVertexAttribPointer(GLuint(bounds), /*size*/ 4, /*type*/ GL_FLOAT, /*normalised*/ GL_FALSE, /*stride*/ 0, nullptr); + f->glVertexAttribDivisor(GLuint(bounds), 1); + } + if (tileset_id != -1) { + m_tileset_id_buffer->bind(); + f->glEnableVertexAttribArray(GLuint(tileset_id)); + f->glVertexAttribIPointer(GLuint(tileset_id), /*size*/ 1, /*type*/ GL_INT, /*stride*/ 0, nullptr); + f->glVertexAttribDivisor(GLuint(tileset_id), 1); + } + if (zoom_level != -1) { + m_zoom_level_buffer->bind(); + f->glEnableVertexAttribArray(GLuint(zoom_level)); + f->glVertexAttribIPointer(GLuint(zoom_level), /*size*/ 1, /*type*/ GL_INT, /*stride*/ 0, nullptr); + f->glVertexAttribDivisor(GLuint(zoom_level), 1); + } + if (texture_layer != -1) { + m_texture_layer_buffer->bind(); + f->glEnableVertexAttribArray(GLuint(texture_layer)); + f->glVertexAttribIPointer(GLuint(texture_layer), /*size*/ 1, /*type*/ GL_INT, /*stride*/ 0, nullptr); + f->glVertexAttribDivisor(GLuint(texture_layer), 1); + } +} void TileManager::set_aabb_decorator(const nucleus::tile_scheduler::utils::AabbDecoratorPtr& new_aabb_decorator) { @@ -175,11 +246,9 @@ void TileManager::add_tile( if (!QOpenGLContext::currentContext()) // can happen during shutdown. return; - // need to call GLWindow::makeCurrent, when calling through signals? - // find an empty slot => todo, for now just create a new tile every time. - // setup / copy data to gpu TileSet tileset; - tileset.tiles.emplace_back(id, tile::SrsBounds(bounds)); + tileset.tile_id = id; + tileset.bounds = tile::SrsBounds(bounds); // find empty spot and upload texture const auto t = std::find(m_loaded_tiles.begin(), m_loaded_tiles.end(), tile::Id { unsigned(-1), {} }); @@ -191,7 +260,7 @@ void TileManager::add_tile( m_heightmap_textures->upload(height_map, layer_index); // add to m_gpu_tiles - m_gpu_tiles.push_back(std::move(tileset)); + m_gpu_tiles.push_back(tileset); m_draw_list_generator.add_tile(id); emit tiles_changed(); diff --git a/gl_engine/TileManager.h b/gl_engine/TileManager.h index 1a52e1e3..fbb496a0 100644 --- a/gl_engine/TileManager.h +++ b/gl_engine/TileManager.h @@ -65,21 +65,22 @@ public slots: private: void add_tile(const tile::Id& id, tile::SrsAndHeightBounds bounds, const nucleus::utils::ColourTexture& ortho, const nucleus::Raster& heights); - struct TileGLAttributeLocations { - }; static constexpr auto N_EDGE_VERTICES = 65; static constexpr auto ORTHO_RESOLUTION = 256; static constexpr auto HEIGHTMAP_RESOLUTION = 65; std::vector m_loaded_tiles; - std::pair, size_t> m_index_buffer; std::unique_ptr m_ortho_textures; std::unique_ptr m_heightmap_textures; std::unique_ptr m_vao; + std::pair, size_t> m_index_buffer; + std::unique_ptr m_bounds_buffer; + std::unique_ptr m_tileset_id_buffer; + std::unique_ptr m_zoom_level_buffer; + std::unique_ptr m_texture_layer_buffer; std::vector m_gpu_tiles; - TileGLAttributeLocations m_attribute_locations; unsigned m_tiles_per_set = 1; nucleus::tile_scheduler::DrawListGenerator m_draw_list_generator; const nucleus::tile_scheduler::DrawListGenerator::TileSet m_last_draw_list; // buffer last generated draw list diff --git a/gl_engine/TileSet.h b/gl_engine/TileSet.h index 3c0edfce..6ab174a0 100644 --- a/gl_engine/TileSet.h +++ b/gl_engine/TileSet.h @@ -29,18 +29,8 @@ namespace gl_engine { struct TileSet { - struct Tile { - tile::Id tile_id; - tile::SrsBounds bounds; - void invalidate() - { - tile_id = { unsigned(-1), { unsigned(-1), unsigned(-1) } }; - bounds = {}; - } - [[nodiscard]] bool isValid() const { return tile_id.zoom_level < 100; } - }; - - std::vector> tiles; + tile::Id tile_id = {}; + tile::SrsBounds bounds = {}; unsigned texture_layer = unsigned(-1); // texture }; diff --git a/gl_engine/shaders/shadowmap.vert b/gl_engine/shaders/shadowmap.vert index f1ade705..9e6f6820 100644 --- a/gl_engine/shaders/shadowmap.vert +++ b/gl_engine/shaders/shadowmap.vert @@ -21,7 +21,7 @@ #include "camera_config.glsl" #include "shadow_config.glsl" -uniform highp vec4 bounds[32]; +in highp vec4 bounds; uniform highp int n_edge_vertices; uniform highp int texture_layer; @@ -39,12 +39,11 @@ highp float y_to_lat(highp float y) { } void main() { - highp int geometry_id = 0; highp int edge_vertices_count_int = n_edge_vertices - 1; highp float edge_vertices_count_float = float(edge_vertices_count_int); // Note: The following is actually not the tile_width but the primitive/cell width/height - highp float tile_width = (bounds[geometry_id].z - bounds[geometry_id].x) / edge_vertices_count_float; - highp float tile_height = (bounds[geometry_id].w - bounds[geometry_id].y) / edge_vertices_count_float; + highp float tile_width = (bounds.z - bounds.x) / edge_vertices_count_float; + highp float tile_height = (bounds.w - bounds.y) / edge_vertices_count_float; highp int row = gl_VertexID / n_edge_vertices; highp int col = gl_VertexID - (row * n_edge_vertices); @@ -68,14 +67,14 @@ void main() { } } // Note: May be enough to calculate altitude_correction_factor per tile on CPU: - highp float var_pos_cws_y = float(edge_vertices_count_int - row) * float(tile_width) + bounds[geometry_id].y; + highp float var_pos_cws_y = float(edge_vertices_count_int - row) * float(tile_width) + bounds.y; highp float pos_y = var_pos_cws_y + camera.position.y; float altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 vec2 uv = vec2(float(col) / edge_vertices_count_float, float(row) / edge_vertices_count_float); highp float adjusted_altitude = float(texture(height_sampler, vec3(uv, texture_layer)).r) * altitude_correction_factor; - highp vec3 var_pos_cws = vec3(float(col) * tile_width + bounds[geometry_id].x, + highp vec3 var_pos_cws = vec3(float(col) * tile_width + bounds.x, var_pos_cws_y, adjusted_altitude - camera.position.z); diff --git a/gl_engine/shaders/tile.frag b/gl_engine/shaders/tile.frag index 849dab23..ad2b7b8a 100644 --- a/gl_engine/shaders/tile.frag +++ b/gl_engine/shaders/tile.frag @@ -21,7 +21,6 @@ #include "camera_config.glsl" #include "encoder.glsl" -uniform highp int texture_layer; uniform lowp sampler2DArray ortho_sampler; layout (location = 0) out lowp vec3 texout_albedo; @@ -29,6 +28,7 @@ layout (location = 1) out highp vec4 texout_position; layout (location = 2) out highp uvec2 texout_normal; layout (location = 3) out lowp vec4 texout_depth; +flat in highp int v_texture_layer; in highp vec2 uv; in highp vec3 var_pos_cws; in highp vec3 var_normal; @@ -55,7 +55,7 @@ void main() { #endif // Write Albedo (ortho picture) in gbuffer - highp float texture_layer_f = float(texture_layer); + highp float texture_layer_f = float(v_texture_layer); lowp vec3 fragColor = texture(ortho_sampler, vec3(uv, texture_layer_f)).rgb; fragColor = mix(fragColor, conf.material_color.rgb, conf.material_color.a); texout_albedo = fragColor; diff --git a/gl_engine/shaders/tile.vert b/gl_engine/shaders/tile.vert index 42827ef1..bd563ac6 100644 --- a/gl_engine/shaders/tile.vert +++ b/gl_engine/shaders/tile.vert @@ -21,16 +21,17 @@ #include "hashing.glsl" #include "camera_config.glsl" -uniform highp vec4 bounds[32]; +in highp vec4 bounds; uniform highp int n_edge_vertices; -uniform highp int tileset_id; -uniform highp int tileset_zoomlevel; -uniform highp int texture_layer; +in highp int tileset_id; +in highp int tileset_zoomlevel; +in highp int texture_layer; uniform mediump usampler2DArray height_sampler; out highp vec2 uv; out highp vec3 var_pos_cws; out highp vec3 var_normal; +flat out highp int v_texture_layer; #if CURTAIN_DEBUG_MODE > 0 out lowp float is_curtain; #endif @@ -62,12 +63,11 @@ highp vec3 normal_by_finite_difference_method(vec2 uv, float edge_vertices_count } void main() { - int geometry_id = 0; int edge_vertices_count_int = n_edge_vertices - 1; float edge_vertices_count_float = float(edge_vertices_count_int); // Note: The following is actually not the tile_width but the primitive/cell width/height - float tile_width = (bounds[geometry_id].z - bounds[geometry_id].x) / edge_vertices_count_float; - float tile_height = (bounds[geometry_id].w - bounds[geometry_id].y) / edge_vertices_count_float; + float tile_width = (bounds.z - bounds.x) / edge_vertices_count_float; + float tile_height = (bounds.w - bounds.y) / edge_vertices_count_float; int row = gl_VertexID / n_edge_vertices; int col = gl_VertexID - (row * n_edge_vertices); int curtain_vertex_id = gl_VertexID - n_edge_vertices * n_edge_vertices; @@ -99,7 +99,7 @@ void main() { } } // Note: May be enough to calculate altitude_correction_factor per tile on CPU: - float var_pos_cws_y = float(edge_vertices_count_int - row) * float(tile_width) + bounds[geometry_id].y; + float var_pos_cws_y = float(edge_vertices_count_int - row) * float(tile_width) + bounds.y; float pos_y = var_pos_cws_y + camera.position.y; float altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 @@ -108,7 +108,7 @@ void main() { float altitude_tex = float(texture(height_sampler, vec3(uv, texture_layer)).r); float adjusted_altitude = altitude_tex * altitude_correction_factor; - var_pos_cws = vec3(float(col) * tile_width + bounds[geometry_id].x, + var_pos_cws = vec3(float(col) * tile_width + bounds.x, var_pos_cws_y, adjusted_altitude - camera.position.z); @@ -136,4 +136,5 @@ void main() { case 4u: vertex_color = color_from_id_hash(uint(gl_VertexID)); break; case 5u: vertex_color = vec3(texture(height_sampler, vec3(uv, texture_layer)).rrr) / 65535.0; break; } + v_texture_layer = texture_layer; } From e308ba4e06ad577d539201274c0b949c02d35d2f Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 24 Feb 2024 17:08:13 +0100 Subject: [PATCH 47/65] simplify ui visibility (F10) --- app/FloatingActionButtonGroup.qml | 32 +-------------------------- app/GlSettings.qml | 3 --- app/Main.qml | 36 +++++++++++-------------------- app/Map.qml | 9 ++++++++ app/TerrainRendererItem.cpp | 9 -------- app/TerrainRendererItem.h | 5 ----- 6 files changed, 22 insertions(+), 72 deletions(-) diff --git a/app/FloatingActionButtonGroup.qml b/app/FloatingActionButtonGroup.qml index 088dcd1b..94573c64 100644 --- a/app/FloatingActionButtonGroup.qml +++ b/app/FloatingActionButtonGroup.qml @@ -25,38 +25,8 @@ import "components" ColumnLayout { id: fab_group - property real button_spacing: 0 - property real group_margin: 15 width: 64 - x: group_margin - y: map.height - implicitHeight - group_margin - spacing: button_spacing - - function responsive_update() { - let newVisible = true; - if (main_stack_view.selectedPage === "settings") { - if (main.width < main.height) newVisible = false; - } else if (main_stack_view.selectedPage !== "map") { - newVisible = false; - } - fab_group.visible = newVisible; - } - - Connections { - target: main - function onWidthChanged() { - responsive_update(); - } - function onHeightChanged() { - responsive_update(); - } - } - Connections { - target: main_stack_view; - function onSelectedPageChanged() { - responsive_update(); - } - } + spacing: 0 FloatingActionButton { rotation: map.camera_rotation_from_north diff --git a/app/GlSettings.qml b/app/GlSettings.qml index 8d95aa41..ce41297c 100644 --- a/app/GlSettings.qml +++ b/app/GlSettings.qml @@ -61,9 +61,6 @@ SettingsPanel { Item { // i need to pack Connections in an item (dunno why) Connections { target: map - function onHud_visible_changed(hud_visible) { - //debugMenu.visible = hud_visible; - } function onShared_config_changed(conf) { update_control_values(); } diff --git a/app/Main.qml b/app/Main.qml index 7e34d6a3..3c42661e 100644 --- a/app/Main.qml +++ b/app/Main.qml @@ -28,8 +28,14 @@ Item { id: main property int theme: Material.Light property int accent: Material.BlueGrey - property string selectedPage: "map"; - + property string selectedPage: "map" + property bool userInterfaceVisible: true + Shortcut { + id: ui_visibility_shortcut + sequence: "F10" + onActivated: userInterfaceVisible = !userInterfaceVisible + context: Qt.ApplicationShortcut + } Rectangle { id: tool_bar @@ -40,6 +46,7 @@ Item { right: parent.right top: parent.top } + visible: userInterfaceVisible RowLayout { anchors.fill: parent @@ -137,9 +144,9 @@ Item { DrawerButton { text: qsTr("Hide User Interface") iconSource: _r + "icons/material/visibility_off.png" - hotkey: "F10" + hotkey: ui_visibility_shortcut.nativeText selectable: false - onClicked: map.hud_visible = false; + onClicked: userInterfaceVisible = !userInterfaceVisible } DrawerSpacer {} @@ -187,8 +194,6 @@ Item { TerrainRenderer { - property var allLvl1HudElements: [tool_bar, main_stack_view, fab_group] - property var _hudElementsVisibility: [] id: map focus: true anchors.fill: parent @@ -197,20 +202,6 @@ Item { toggleStatsWindow(); } } - - onHud_visible_changed: function(new_hud_visible) { - if (new_hud_visible) { // show all items - for (let i1 = 0; i1 < allLvl1HudElements.length; i1++) { - allLvl1HudElements[i1].visible = _hudElementsVisibility[i1]; - } - } else { // hide all items and save their state - _hudElementsVisibility = []; - for (let i = 0; i < allLvl1HudElements.length; i++) { - _hudElementsVisibility.push(allLvl1HudElements[i].visible); - allLvl1HudElements[i].visible = false; - } - } - } } StackView { @@ -222,6 +213,7 @@ Item { left: parent.left right: parent.right } + visible: userInterfaceVisible initialItem: Map { renderer: map @@ -232,10 +224,6 @@ Item { id: stats_window_loader } - FloatingActionButtonGroup { - id: fab_group - } - Component.onCompleted: { change_page("map") } diff --git a/app/Map.qml b/app/Map.qml index 9d350512..c40d18c1 100644 --- a/app/Map.qml +++ b/app/Map.qml @@ -48,4 +48,13 @@ Rectangle { visible: renderer.camera_operation_centre_visibility } + FloatingActionButtonGroup { + id: fab_group + anchors { + left: map_gui.left + bottom: map_gui.bottom + leftMargin: 8 + bottomMargin: 8 + } + } } diff --git a/app/TerrainRendererItem.cpp b/app/TerrainRendererItem.cpp index 7f59e62d..85d9f03e 100644 --- a/app/TerrainRendererItem.cpp +++ b/app/TerrainRendererItem.cpp @@ -186,9 +186,6 @@ void TerrainRendererItem::keyPressEvent(QKeyEvent* e) if (e->isAutoRepeat()) { return; } - if (e->key() == Qt::Key::Key_F10) { - set_hud_visible(!m_hud_visible); - } emit key_pressed(e->keyCombination()); RenderThreadNotifier::instance()->notify(); } @@ -398,12 +395,6 @@ void TerrainRendererItem::set_shared_config(gl_engine::uboSharedConfig new_share } } -void TerrainRendererItem::set_hud_visible(bool new_hud_visible) { - if (new_hud_visible == m_hud_visible) return; - m_hud_visible = new_hud_visible; - emit hud_visible_changed(m_hud_visible); -} - void TerrainRendererItem::set_selected_camera_position_index(unsigned value) { schedule_update(); diff --git a/app/TerrainRendererItem.h b/app/TerrainRendererItem.h index dec52bdb..7f1ef2e9 100644 --- a/app/TerrainRendererItem.h +++ b/app/TerrainRendererItem.h @@ -55,7 +55,6 @@ class TerrainRendererItem : public QQuickFramebufferObject { Q_PROPERTY(unsigned int tile_cache_size READ tile_cache_size WRITE set_tile_cache_size NOTIFY tile_cache_size_changed) Q_PROPERTY(bool render_looped READ render_looped WRITE set_render_looped NOTIFY render_looped_changed) Q_PROPERTY(unsigned int selected_camera_position_index MEMBER m_selected_camera_position_index WRITE set_selected_camera_position_index) - Q_PROPERTY(bool hud_visible READ hud_visible WRITE set_hud_visible NOTIFY hud_visible_changed) Q_PROPERTY(QVector2D sun_angles READ sun_angles WRITE set_sun_angles NOTIFY sun_angles_changed) public: @@ -165,9 +164,6 @@ private slots: gl_engine::uboSharedConfig shared_config() const; void set_shared_config(gl_engine::uboSharedConfig new_shared_config); - bool hud_visible() const { return m_hud_visible; } - void set_hud_visible(bool new_hud_visible); - void set_selected_camera_position_index(unsigned value); [[nodiscard]] unsigned int in_flight_tiles() const; @@ -203,7 +199,6 @@ private slots: unsigned m_in_flight_tiles = 0; unsigned int m_selected_camera_position_index = 0; bool m_render_looped = false; - bool m_hud_visible = true; QDateTime m_selected_datetime = QDateTime::currentDateTime(); gl_engine::uboSharedConfig m_shared_config; From bb0eb88d520a663c89934d11896e9651908c0c7c Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 24 Feb 2024 17:40:00 +0100 Subject: [PATCH 48/65] fix order --- app/Settings.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Settings.qml b/app/Settings.qml index 2a3e0650..bdc2b032 100644 --- a/app/Settings.qml +++ b/app/Settings.qml @@ -87,11 +87,11 @@ Rectangle { contentWidth: parent.width position: TabBar.Header TabButton { - text: qsTr("GL Configuration") + text: qsTr("General") width: implicitWidth + 20 } TabButton { - text: qsTr("General") + text: qsTr("GL Configuration") width: implicitWidth + 20 } } From f51a27058b4f972fb8c9f1eb3ad563212f9218a5 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 25 Feb 2024 15:35:41 +0100 Subject: [PATCH 49/65] refactor tile vertex shader --- gl_engine/CMakeLists.txt | 1 + gl_engine/shaders/shadowmap.vert | 68 +------------------ gl_engine/shaders/tile.glsl | 110 +++++++++++++++++++++++++++++++ gl_engine/shaders/tile.vert | 98 ++------------------------- 4 files changed, 121 insertions(+), 156 deletions(-) create mode 100644 gl_engine/shaders/tile.glsl diff --git a/gl_engine/CMakeLists.txt b/gl_engine/CMakeLists.txt index 96eb0114..bddf7544 100644 --- a/gl_engine/CMakeLists.txt +++ b/gl_engine/CMakeLists.txt @@ -70,6 +70,7 @@ qt_add_resources(gl_engine "shaders" shaders/labels.frag shaders/labels.vert shaders/snow.glsl + shaders/tile.glsl ) target_compile_definitions(gl_engine PUBLIC ALP_RESOURCES_PREFIX="${CMAKE_CURRENT_SOURCE_DIR}/shaders/") diff --git a/gl_engine/shaders/shadowmap.vert b/gl_engine/shaders/shadowmap.vert index 9e6f6820..8fb13823 100644 --- a/gl_engine/shaders/shadowmap.vert +++ b/gl_engine/shaders/shadowmap.vert @@ -20,73 +20,11 @@ #include "shared_config.glsl" #include "camera_config.glsl" #include "shadow_config.glsl" - -in highp vec4 bounds; - -uniform highp int n_edge_vertices; -uniform highp int texture_layer; -uniform mediump usampler2DArray height_sampler; +#include "tile.glsl" uniform lowp int current_layer; -highp float y_to_lat(highp float y) { - const highp float pi = 3.1415926535897932384626433; - const highp float cOriginShift = 20037508.342789244; - - highp float mercN = y * pi / cOriginShift; - highp float latRad = 2.f * (atan(exp(mercN)) - (pi / 4.0)); - return latRad; -} - void main() { - highp int edge_vertices_count_int = n_edge_vertices - 1; - highp float edge_vertices_count_float = float(edge_vertices_count_int); - // Note: The following is actually not the tile_width but the primitive/cell width/height - highp float tile_width = (bounds.z - bounds.x) / edge_vertices_count_float; - highp float tile_height = (bounds.w - bounds.y) / edge_vertices_count_float; - - highp int row = gl_VertexID / n_edge_vertices; - highp int col = gl_VertexID - (row * n_edge_vertices); - highp int curtain_vertex_id = gl_VertexID - n_edge_vertices * n_edge_vertices; - if (curtain_vertex_id >= 0) { - if (curtain_vertex_id < n_edge_vertices) { - row = (n_edge_vertices - 1) - curtain_vertex_id; - col = (n_edge_vertices - 1); - } - else if (curtain_vertex_id >= n_edge_vertices && curtain_vertex_id < 2 * n_edge_vertices - 1) { - row = 0; - col = (n_edge_vertices - 1) - (curtain_vertex_id - n_edge_vertices) - 1; - } - else if (curtain_vertex_id >= 2 * n_edge_vertices - 1 && curtain_vertex_id < 3 * n_edge_vertices - 2) { - row = curtain_vertex_id - 2 * n_edge_vertices + 2; - col = 0; - } - else { - row = (n_edge_vertices - 1); - col = curtain_vertex_id - 3 * n_edge_vertices + 3; - } - } - // Note: May be enough to calculate altitude_correction_factor per tile on CPU: - highp float var_pos_cws_y = float(edge_vertices_count_int - row) * float(tile_width) + bounds.y; - highp float pos_y = var_pos_cws_y + camera.position.y; - float altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 - - vec2 uv = vec2(float(col) / edge_vertices_count_float, float(row) / edge_vertices_count_float); - highp float adjusted_altitude = float(texture(height_sampler, vec3(uv, texture_layer)).r) * altitude_correction_factor; - - highp vec3 var_pos_cws = vec3(float(col) * tile_width + bounds.x, - var_pos_cws_y, - adjusted_altitude - camera.position.z); - - if (curtain_vertex_id >= 0) { - float curtain_height = CURTAIN_REFERENCE_HEIGHT; -#if CURTAIN_HEIGHT_MODE == 1 - float dist_factor = clamp(length(var_pos_cws) / 100000.0, 0.2, 1.0); - curtain_height *= dist_factor; -#endif - var_pos_cws.z = var_pos_cws.z - curtain_height; - } - - - gl_Position = shadow.light_space_view_proj_matrix[current_layer] * vec4(var_pos_cws, 1); + vec2 uv; + gl_Position = shadow.light_space_view_proj_matrix[current_layer] * vec4(camera_world_space_position(), 1); } diff --git a/gl_engine/shaders/tile.glsl b/gl_engine/shaders/tile.glsl new file mode 100644 index 00000000..d573461c --- /dev/null +++ b/gl_engine/shaders/tile.glsl @@ -0,0 +1,110 @@ +/***************************************************************************** +* Alpine Renderer +* Copyright (C) 2022 Adam Celarek +* Copyright (C) 2023 Gerald Kimmersdorfer +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +layout(location = 0) in highp vec4 bounds; +layout(location = 1) in highp int texture_layer; +layout(location = 2) in highp int tileset_id; +layout(location = 3) in highp int tileset_zoomlevel; + +uniform highp int n_edge_vertices; +uniform mediump usampler2DArray height_sampler; + +highp float y_to_lat(highp float y) { + const highp float pi = 3.1415926535897932384626433; + const highp float cOriginShift = 20037508.342789244; + + highp float mercN = y * pi / cOriginShift; + highp float latRad = 2.f * (atan(exp(mercN)) - (pi / 4.0)); + return latRad; +} + +highp vec3 camera_world_space_position(out vec2 uv, out float n_quads_per_direction, out float quad_width, out float quad_height, out float altitude_correction_factor) { + highp int n_quads_per_direction_int = n_edge_vertices - 1; + n_quads_per_direction = float(n_quads_per_direction_int); + quad_width = (bounds.z - bounds.x) / n_quads_per_direction; + quad_height = (bounds.w - bounds.y) / n_quads_per_direction; + + highp int row = gl_VertexID / n_edge_vertices; + highp int col = gl_VertexID - (row * n_edge_vertices); + highp int curtain_vertex_id = gl_VertexID - n_edge_vertices * n_edge_vertices; + if (curtain_vertex_id >= 0) { + if (curtain_vertex_id < n_edge_vertices) { + row = (n_edge_vertices - 1) - curtain_vertex_id; + col = (n_edge_vertices - 1); + } + else if (curtain_vertex_id >= n_edge_vertices && curtain_vertex_id < 2 * n_edge_vertices - 1) { + row = 0; + col = (n_edge_vertices - 1) - (curtain_vertex_id - n_edge_vertices) - 1; + } + else if (curtain_vertex_id >= 2 * n_edge_vertices - 1 && curtain_vertex_id < 3 * n_edge_vertices - 2) { + row = curtain_vertex_id - 2 * n_edge_vertices + 2; + col = 0; + } + else { + row = (n_edge_vertices - 1); + col = curtain_vertex_id - 3 * n_edge_vertices + 3; + } + } + // Note: May be enough to calculate altitude_correction_factor per tile on CPU: + highp float var_pos_cws_y = float(n_quads_per_direction_int - row) * float(quad_width) + bounds.y; + highp float pos_y = var_pos_cws_y + camera.position.y; + altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 + + uv = vec2(float(col) / n_quads_per_direction, float(row) / n_quads_per_direction); + float altitude_tex = float(texture(height_sampler, vec3(uv, texture_layer)).r); + float adjusted_altitude = altitude_tex * altitude_correction_factor; + + highp vec3 var_pos_cws = vec3(float(col) * quad_width + bounds.x, var_pos_cws_y, adjusted_altitude - camera.position.z); + + if (curtain_vertex_id >= 0) { + float curtain_height = CURTAIN_REFERENCE_HEIGHT; +#if CURTAIN_HEIGHT_MODE == 1 + float dist_factor = clamp(length(var_pos_cws) / 100000.0, 0.2, 1.0); + curtain_height *= dist_factor; +#endif + var_pos_cws.z = var_pos_cws.z - curtain_height; + } + + return var_pos_cws; +} + +highp vec3 camera_world_space_position() { + vec2 uv; + float n_quads_per_direction; + float quad_width; + float quad_height; + float altitude_correction_factor; + return camera_world_space_position(uv, n_quads_per_direction, quad_width, quad_height, altitude_correction_factor); +} + +highp vec3 normal_by_finite_difference_method(vec2 uv, float edge_vertices_count, float quad_width, float quad_height, float altitude_correction_factor) { + // from here: https://stackoverflow.com/questions/6656358/calculating-normals-in-a-triangle-mesh/21660173#21660173 + vec2 offset = vec2(1.0, 0.0) / (edge_vertices_count); + float height = quad_width + quad_height; + highp float hL = float(texture(height_sampler, vec3(uv - offset.xy, texture_layer)).r); + hL *= altitude_correction_factor; + highp float hR = float(texture(height_sampler, vec3(uv + offset.xy, texture_layer)).r); + hR *= altitude_correction_factor; + highp float hD = float(texture(height_sampler, vec3(uv + offset.yx, texture_layer)).r); + hD *= altitude_correction_factor; + highp float hU = float(texture(height_sampler, vec3(uv - offset.yx, texture_layer)).r); + hU *= altitude_correction_factor; + + return normalize(vec3(hL - hR, hD - hU, height)); +} diff --git a/gl_engine/shaders/tile.vert b/gl_engine/shaders/tile.vert index bd563ac6..647224a2 100644 --- a/gl_engine/shaders/tile.vert +++ b/gl_engine/shaders/tile.vert @@ -20,13 +20,7 @@ #include "shared_config.glsl" #include "hashing.glsl" #include "camera_config.glsl" - -in highp vec4 bounds; -uniform highp int n_edge_vertices; -in highp int tileset_id; -in highp int tileset_zoomlevel; -in highp int texture_layer; -uniform mediump usampler2DArray height_sampler; +#include "tile.glsl" out highp vec2 uv; out highp vec3 var_pos_cws; @@ -37,94 +31,16 @@ out lowp float is_curtain; #endif flat out lowp vec3 vertex_color; -highp float y_to_lat(highp float y) { - const highp float pi = 3.1415926535897932384626433; - const highp float cOriginShift = 20037508.342789244; - - highp float mercN = y * pi / cOriginShift; - highp float latRad = 2.f * (atan(exp(mercN)) - (pi / 4.0)); - return latRad; -} - -highp vec3 normal_by_finite_difference_method(vec2 uv, float edge_vertices_count, float tile_width, float tile_height, float altitude_correction_factor) { - // from here: https://stackoverflow.com/questions/6656358/calculating-normals-in-a-triangle-mesh/21660173#21660173 - vec2 offset = vec2(1.0, 0.0) / (edge_vertices_count); - float height = tile_width + tile_height; - highp float hL = float(texture(height_sampler, vec3(uv - offset.xy, texture_layer)).r); - hL *= altitude_correction_factor; - highp float hR = float(texture(height_sampler, vec3(uv + offset.xy, texture_layer)).r); - hR *= altitude_correction_factor; - highp float hD = float(texture(height_sampler, vec3(uv + offset.yx, texture_layer)).r); - hD *= altitude_correction_factor; - highp float hU = float(texture(height_sampler, vec3(uv - offset.yx, texture_layer)).r); - hU *= altitude_correction_factor; - - return normalize(vec3(hL - hR, hD - hU, height)); -} void main() { - int edge_vertices_count_int = n_edge_vertices - 1; - float edge_vertices_count_float = float(edge_vertices_count_int); - // Note: The following is actually not the tile_width but the primitive/cell width/height - float tile_width = (bounds.z - bounds.x) / edge_vertices_count_float; - float tile_height = (bounds.w - bounds.y) / edge_vertices_count_float; - int row = gl_VertexID / n_edge_vertices; - int col = gl_VertexID - (row * n_edge_vertices); - int curtain_vertex_id = gl_VertexID - n_edge_vertices * n_edge_vertices; -#if CURTAIN_DEBUG_MODE > 0 - is_curtain = 0.0; - if (curtain_vertex_id >= 0) is_curtain = 1.0; -#endif - if (curtain_vertex_id >= 0) { - // curtains - if (curtain_vertex_id < n_edge_vertices) { - // eastern - row = (n_edge_vertices - 1) - curtain_vertex_id; - col = (n_edge_vertices - 1); - } - else if (curtain_vertex_id >= n_edge_vertices && curtain_vertex_id < 2 * n_edge_vertices - 1) { - // northern - row = 0; - col = (n_edge_vertices - 1) - (curtain_vertex_id - n_edge_vertices) - 1; - } - else if (curtain_vertex_id >= 2 * n_edge_vertices - 1 && curtain_vertex_id < 3 * n_edge_vertices - 2) { - // western - row = curtain_vertex_id - 2 * n_edge_vertices + 2; - col = 0; - } - else { - // southern - row = (n_edge_vertices - 1); - col = curtain_vertex_id - 3 * n_edge_vertices + 3; - } - } - // Note: May be enough to calculate altitude_correction_factor per tile on CPU: - float var_pos_cws_y = float(edge_vertices_count_int - row) * float(tile_width) + bounds.y; - float pos_y = var_pos_cws_y + camera.position.y; - float altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 - - uv = vec2(float(col) / edge_vertices_count_float, float(row) / edge_vertices_count_float); - - float altitude_tex = float(texture(height_sampler, vec3(uv, texture_layer)).r); - float adjusted_altitude = altitude_tex * altitude_correction_factor; - - var_pos_cws = vec3(float(col) * tile_width + bounds.x, - var_pos_cws_y, - adjusted_altitude - camera.position.z); - - if (curtain_vertex_id >= 0) { - float curtain_height = CURTAIN_REFERENCE_HEIGHT; -#if CURTAIN_HEIGHT_MODE == 1 - // NOTE: This is definitely subject for improvement! (Perfect would be a function of the neighbouring zoomlevels!) - float dist_factor = clamp(length(var_pos_cws) / 100000.0, 0.2, 1.0); - curtain_height *= dist_factor; -#endif - var_pos_cws.z = var_pos_cws.z - curtain_height; - } - + float n_quads_per_direction; + float quad_width; + float quad_height; + float altitude_correction_factor; + var_pos_cws = camera_world_space_position(uv, n_quads_per_direction, quad_width, quad_height, altitude_correction_factor); if (conf.normal_mode == 1u) { - var_normal = normal_by_finite_difference_method(uv, edge_vertices_count_float, tile_width, tile_height, altitude_correction_factor); + var_normal = normal_by_finite_difference_method(uv, n_quads_per_direction, quad_width, quad_height, altitude_correction_factor); } gl_Position = camera.view_proj_matrix * vec4(var_pos_cws, 1); From 9ef82a3725271e78b08cf97456232488dadc7295 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 25 Feb 2024 19:11:49 +0100 Subject: [PATCH 50/65] use texel fetch (more accurate texture command) and edit comments. no perf difference. --- gl_engine/shaders/tile.glsl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gl_engine/shaders/tile.glsl b/gl_engine/shaders/tile.glsl index d573461c..251e4257 100644 --- a/gl_engine/shaders/tile.glsl +++ b/gl_engine/shaders/tile.glsl @@ -61,13 +61,15 @@ highp vec3 camera_world_space_position(out vec2 uv, out float n_quads_per_direct col = curtain_vertex_id - 3 * n_edge_vertices + 3; } } - // Note: May be enough to calculate altitude_correction_factor per tile on CPU: + // Note: for higher zoom levels it would be enough to calculate the altitude_correction_factor on cpu + // for lower zoom levels we could bake it into the texture. + // but there was no measurable difference despite a cos and a atan, so leaving as is for now. highp float var_pos_cws_y = float(n_quads_per_direction_int - row) * float(quad_width) + bounds.y; highp float pos_y = var_pos_cws_y + camera.position.y; altitude_correction_factor = 0.125 / cos(y_to_lat(pos_y)); // https://github.com/AlpineMapsOrg/renderer/issues/5 uv = vec2(float(col) / n_quads_per_direction, float(row) / n_quads_per_direction); - float altitude_tex = float(texture(height_sampler, vec3(uv, texture_layer)).r); + float altitude_tex = float(texelFetch(height_sampler, ivec3(col, row, texture_layer), 0).r); float adjusted_altitude = altitude_tex * altitude_correction_factor; highp vec3 var_pos_cws = vec3(float(col) * quad_width + bounds.x, var_pos_cws_y, adjusted_altitude - camera.position.z); From 4452aecd2ff901f571ad440b2c6468a2879f9f49 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:54:08 +0100 Subject: [PATCH 51/65] checkbox for continuous update in stats window (easier benchmarking) --- app/StatsWindow.qml | 12 ++++++++++-- app/TerrainRendererItem.cpp | 20 +++++++++++++++++++- app/TerrainRendererItem.h | 9 ++++++++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/app/StatsWindow.qml b/app/StatsWindow.qml index 551aa167..61f0cd1a 100644 --- a/app/StatsWindow.qml +++ b/app/StatsWindow.qml @@ -54,8 +54,6 @@ Rectangle { maxHeight = height width = main.width - 2 * innerMargin } - - } } @@ -304,6 +302,16 @@ Rectangle { CheckGroup { name: "Frame Profiler" + checkBoxEnabled: true + CheckBox { + text: "Continuous update" + id: continuous_update_checkbox + onCheckStateChanged: { + console.log("Continuous update: " + checkState) + console.log("map: " + map) + map.continuous_update = checked + } + } Pane { id: stats_timing; diff --git a/app/TerrainRendererItem.cpp b/app/TerrainRendererItem.cpp index 85d9f03e..d41497df 100644 --- a/app/TerrainRendererItem.cpp +++ b/app/TerrainRendererItem.cpp @@ -71,7 +71,7 @@ TerrainRendererItem::TerrainRendererItem(QQuickItem* parent) connect(m_settings, &AppSettings::gl_sundir_date_link_changed, this, &TerrainRendererItem::gl_sundir_date_link_changed); connect(m_settings, &AppSettings::render_quality_changed, this, &TerrainRendererItem::schedule_update); - m_update_timer->setSingleShot(true); + m_update_timer->setSingleShot(!m_continuous_update); m_update_timer->setInterval(1000 / m_frame_limit); setMirrorVertically(true); setAcceptTouchEvents(true); @@ -481,6 +481,24 @@ void TerrainRendererItem::update_gl_sun_dir_from_sun_angles(gl_engine::uboShared ubo.m_sun_light_dir = newDirUboEntry; } +bool TerrainRendererItem::continuous_update() const +{ + return m_continuous_update; +} + +void TerrainRendererItem::set_continuous_update(bool new_continuous_update) +{ + qDebug() << "TerrainRendererItem::m_continuous_update" << m_continuous_update; + qDebug() << "TerrainRendererItem::new_continuous_update" << new_continuous_update; + if (m_continuous_update == new_continuous_update) + return; + qDebug() << "continuoius update" << m_continuous_update; + m_continuous_update = new_continuous_update; + m_update_timer->setSingleShot(!m_continuous_update); + m_update_timer->start(); + emit continuous_update_changed(m_continuous_update); +} + void TerrainRendererItem::init_after_creation_slot() { // INITIALIZE shared config with URL parameter: auto urlmodifier = m_url_modifier.get(); diff --git a/app/TerrainRendererItem.h b/app/TerrainRendererItem.h index 7f1ef2e9..7735d5f6 100644 --- a/app/TerrainRendererItem.h +++ b/app/TerrainRendererItem.h @@ -56,6 +56,7 @@ class TerrainRendererItem : public QQuickFramebufferObject { Q_PROPERTY(bool render_looped READ render_looped WRITE set_render_looped NOTIFY render_looped_changed) Q_PROPERTY(unsigned int selected_camera_position_index MEMBER m_selected_camera_position_index WRITE set_selected_camera_position_index) Q_PROPERTY(QVector2D sun_angles READ sun_angles WRITE set_sun_angles NOTIFY sun_angles_changed) + Q_PROPERTY(bool continuous_update READ continuous_update WRITE set_continuous_update NOTIFY continuous_update_changed) public: explicit TerrainRendererItem(QQuickItem* parent = 0); @@ -108,6 +109,8 @@ class TerrainRendererItem : public QQuickFramebufferObject { void init_after_creation() const; + void continuous_update_changed(bool continuous_update); + protected: void touchEvent(QTouchEvent*) override; void mousePressEvent(QMouseEvent*) override; @@ -183,16 +186,20 @@ private slots: const AppSettings* settings() { return m_settings; } + bool continuous_update() const; + void set_continuous_update(bool new_continuous_update); + private: void recalculate_sun_angles(); void update_gl_sun_dir_from_sun_angles(gl_engine::uboSharedConfig& ubo); + bool m_continuous_update = false; float m_camera_rotation_from_north = 0; QPointF m_camera_operation_centre; bool m_camera_operation_centre_visibility = false; float m_camera_operation_centre_distance = 1; float m_field_of_view = 60; - int m_frame_limit = 60; + int m_frame_limit = 30; unsigned m_tile_cache_size = 12000; unsigned m_cached_tiles = 0; unsigned m_queued_tiles = 0; From 8346855fcf385b0614f45326c8c7732e262a9a9f Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:58:25 +0100 Subject: [PATCH 52/65] fix compiler errors in tests --- unittests/gl_engine/framebuffer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/unittests/gl_engine/framebuffer.cpp b/unittests/gl_engine/framebuffer.cpp index ce114be1..a3572118 100644 --- a/unittests/gl_engine/framebuffer.cpp +++ b/unittests/gl_engine/framebuffer.cpp @@ -75,7 +75,7 @@ TEST_CASE("gl framebuffer") REQUIRE(f); SECTION("rgba8 bit") { - Framebuffer b(Framebuffer::DepthFormat::None, { {Framebuffer::ColourFormat::RGBA8} }, { 501, 211 }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA8}, {501, 211}); b.bind(); ShaderProgram shader = create_debug_shader(); shader.bind(); @@ -98,7 +98,7 @@ TEST_CASE("gl framebuffer") // Only color renderable on WEBGL with EXT_color_buffer_float extension SECTION("rgba32f color format") { - Framebuffer b(Framebuffer::DepthFormat::None, { {Framebuffer::ColourFormat::RGBA32F} }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA32F}); b.bind(); ShaderProgram shader = create_debug_shader( R"( out highp vec4 out_Color; @@ -196,7 +196,7 @@ TEST_CASE("gl framebuffer") SECTION("rgba8 bit pixel read benchmark") { - Framebuffer b(Framebuffer::DepthFormat::None, { {Framebuffer::ColourFormat::RGBA8} }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA8}); b.bind(); ShaderProgram shader = create_debug_shader(); shader.bind(); @@ -214,7 +214,7 @@ TEST_CASE("gl framebuffer") // NOTE: Tests dont terminate on webgl for me if this benchmark is enabled. The function is not in use anyway... SECTION("rgba8 bit read benchmark") { - Framebuffer b(Framebuffer::DepthFormat::None, { {Framebuffer::ColourFormat::RGBA8} }, { 1920, 1080 }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA8}, {1920, 1080}); b.bind(); ShaderProgram shader = create_debug_shader(); shader.bind(); @@ -229,7 +229,7 @@ TEST_CASE("gl framebuffer") #endif SECTION("read pixel") { - Framebuffer b(Framebuffer::DepthFormat::None, { {Framebuffer::ColourFormat::RGBA8} }, { 1920, 1080 }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA8}, {1920, 1080}); b.bind(); ShaderProgram shader = create_debug_shader(); shader.bind(); @@ -260,7 +260,7 @@ TEST_CASE("gl framebuffer") gl_engine::helpers::create_screen_quad_geometry().draw_with_depth_test(); f->glFinish(); // Now lets try to use it as an input texture - Framebuffer b2(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA32F } }); + Framebuffer b2(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA32F}); b2.bind(); ShaderProgram p2 = create_debug_shader(R"( in highp vec2 texcoords; From 257d31a3ca5494efa5ea49336254df4aa554c99b Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 12 Mar 2024 22:34:48 +0100 Subject: [PATCH 53/65] gl tests don't work in github's windows runner --- .github/workflows/windows.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 3fb46667..ec3a94e4 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -70,5 +70,4 @@ jobs: run: | ./build/alp_external/radix/unittests/unittests_radix.exe ./build/unittests/unittests_nucleus.exe - ./build/unittests/unittests_gl_engine.exe From da27d9c17244b06f2250496418c78b51ec633646 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 12 Mar 2024 22:36:48 +0100 Subject: [PATCH 54/65] fix compiler error (github runner) --- nucleus/utils/ColourTexture.cpp | 5 ++++- nucleus/utils/ColourTexture.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/nucleus/utils/ColourTexture.cpp b/nucleus/utils/ColourTexture.cpp index d9114ab6..729eef5e 100644 --- a/nucleus/utils/ColourTexture.cpp +++ b/nucleus/utils/ColourTexture.cpp @@ -16,12 +16,15 @@ * along with this program. If not, see . *****************************************************************************/ +#include "ColourTexture.h" + #include #include +#include + #define GOOFYTC_IMPLEMENTATION #include -#include "ColourTexture.h" namespace { std::vector to_dxt1(const QImage& qimage) diff --git a/nucleus/utils/ColourTexture.h b/nucleus/utils/ColourTexture.h index 612b7d41..05eafde7 100644 --- a/nucleus/utils/ColourTexture.h +++ b/nucleus/utils/ColourTexture.h @@ -19,6 +19,7 @@ #pragma once #include +#include namespace nucleus::utils { From 6526719bb2e896ff1001c63c4dd943f539b843d4 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 12 Mar 2024 23:20:59 +0100 Subject: [PATCH 55/65] fix more compiler errors --- nucleus/utils/ColourTexture.cpp | 1 - unittests/gl_engine/uniformbuffer.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/nucleus/utils/ColourTexture.cpp b/nucleus/utils/ColourTexture.cpp index 729eef5e..a677816a 100644 --- a/nucleus/utils/ColourTexture.cpp +++ b/nucleus/utils/ColourTexture.cpp @@ -20,7 +20,6 @@ #include #include -#include #define GOOFYTC_IMPLEMENTATION #include diff --git a/unittests/gl_engine/uniformbuffer.cpp b/unittests/gl_engine/uniformbuffer.cpp index 42ce1930..e929adea 100644 --- a/unittests/gl_engine/uniformbuffer.cpp +++ b/unittests/gl_engine/uniformbuffer.cpp @@ -72,7 +72,7 @@ TEST_CASE("gl uniformbuffer") SECTION("test buffer content") { - Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA8}); ShaderProgram shader = create_debug_shader2(R"( layout (std140) uniform test_config { highp vec4 tv4; @@ -105,7 +105,7 @@ TEST_CASE("gl uniformbuffer") SECTION("test shared config buffer") { // NOTE: If theres an error here, check proper alignment first!!! - Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA8}); ShaderProgram shader = create_debug_shader2(R"( #include "shared_config.glsl" out lowp vec4 out_Number; @@ -132,7 +132,7 @@ TEST_CASE("gl uniformbuffer") SECTION("test shared camera buffer") { // NOTE: If theres an error here, check proper alignment first!!! - Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA8}); ShaderProgram shader = create_debug_shader2(R"( #include "camera_config.glsl" out lowp vec4 out_Number; @@ -159,7 +159,7 @@ TEST_CASE("gl uniformbuffer") SECTION("test shared Shadow config buffer") { // NOTE: If theres an error here, check proper alignment first!!! - Framebuffer b(Framebuffer::DepthFormat::None, { { Framebuffer::ColourFormat::RGBA8 } }); + Framebuffer b(Framebuffer::DepthFormat::None, {Framebuffer::ColourFormat::RGBA8}); ShaderProgram shader = create_debug_shader2(R"( #include "shadow_config.glsl" out lowp vec4 out_Number; From ef42a59048e1bf986f984cce1da83cf15f76fe0d Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 12 Mar 2024 23:47:36 +0100 Subject: [PATCH 56/65] fix more compiler errors (android) --- gl_engine/Texture.cpp | 3 --- gl_engine/Texture.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 6c2d3d1c..955df075 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -25,9 +25,6 @@ #include #include #endif -#ifdef ANDROID -#include -#endif gl_engine::Texture::Texture(Target target, Format format) : m_target(target) diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index 0c0c0f48..edcf26f2 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -20,6 +20,9 @@ #include #include +#ifdef ANDROID +#include +#endif #include #include From 2978dfb74aeaaa2142701d0c4c69c3b7eec56291 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Tue, 12 Mar 2024 23:53:11 +0100 Subject: [PATCH 57/65] remove obsolete file --- .gitmodules | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29b..00000000 From 99707c55241856b6f59593d96d0ba161ad60ddac Mon Sep 17 00:00:00 2001 From: Adam <5292991+adam-ce@users.noreply.github.com> Date: Tue, 12 Mar 2024 23:59:09 +0100 Subject: [PATCH 58/65] remove obsolete licenses from COPYRIGHT_NOTICES fonts are in an extra repo now. --- COPYRIGHT_NOTICES | 114 +--------------------------------------------- 1 file changed, 2 insertions(+), 112 deletions(-) diff --git a/COPYRIGHT_NOTICES b/COPYRIGHT_NOTICES index f2d7d834..b5bd4b3b 100644 --- a/COPYRIGHT_NOTICES +++ b/COPYRIGHT_NOTICES @@ -1,5 +1,4 @@ This software includes code from: -- https://github.com/adobe-fonts/source-sans - https://github.com/nocnokneo/cmake-git-versioning-example - https://github.com/mourner/suncalc - https://github.com/frankencode/FluxColor @@ -7,112 +6,7 @@ This software includes code from: Following are the corresponding licenses: ############################################################################### - - -https://github.com/adobe-fonts/source-sans - -############################################################################### - -Copyright 2010-2022 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. - -This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. - -############################################################################### -############################################################################### - - https://github.com/nocnokneo/cmake-git-versioning-example - ############################################################################### MIT License @@ -138,11 +32,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ############################################################################### -############################################################################### - +############################################################################### https://github.com/mourner/suncalc - ############################################################################### Copyright (c) 2014, Vladimir Agafonkin @@ -169,11 +61,9 @@ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF TH SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ############################################################################### -############################################################################### - +############################################################################### https://github.com/frankencode/FluxColor - ############################################################################### Copyright (C) 2020-2021 Frank Mertens From 10700c97083b80949dfb10f8508e8fc4617c2265 Mon Sep 17 00:00:00 2001 From: Adam <5292991+adam-ce@users.noreply.github.com> Date: Wed, 13 Mar 2024 01:20:34 +0100 Subject: [PATCH 59/65] Update README.md (try trigger ci runs) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f3ec0e0b..5a2e38ca 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ https://discord.gg/p8T9XzVwRa `git clone git@github.com:AlpineMapsOrg/renderer.git` After that it should be a normal cmake project. That is, you run cmake to generate a project or build file and then run your favourite tool. All dependencies should be pulled automatically while you run CMake. -We use Qt Creator (with mingw on Windows), which is the only tested setup atm and makes setup of Android and WebAssembly builds reasonably easy. If you have questions, please go to discord. +We use Qt Creator (with mingw on Windows), which is the only tested setup atm and makes setup of Android and WebAssembly builds reasonably easy. If you have questions, please go to Discord. ## Dependencies * Qt 6.6.0, or greater From 9d0b16c96eda25c370874936f18b12baa2395289 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 16 Mar 2024 09:50:21 +0100 Subject: [PATCH 60/65] fix unit tests for android --- gl_engine/Framebuffer.cpp | 2 -- unittests/gl_engine/texture.cpp | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/gl_engine/Framebuffer.cpp b/gl_engine/Framebuffer.cpp index f7944f57..8f7525b2 100644 --- a/gl_engine/Framebuffer.cpp +++ b/gl_engine/Framebuffer.cpp @@ -248,7 +248,6 @@ void Framebuffer::bind() QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glViewport(0, 0, int(m_size.x), int(m_size.y)); f->glBindFramebuffer(GL_FRAMEBUFFER, m_frame_buffer); - //reset_fbo(); } void Framebuffer::bind_colour_texture(unsigned index, unsigned location) @@ -347,7 +346,6 @@ void Framebuffer::unbind() void Framebuffer::reset_fbo() { QOpenGLExtraFunctions* f = QOpenGLContext::currentContext()->extraFunctions(); - //QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glBindFramebuffer(GL_FRAMEBUFFER, m_frame_buffer); // unsigned int draw_attachments[m_colour_textures.size()]; std::vector draw_attachments; diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index 33f982d8..e413c731 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -277,11 +277,11 @@ TEST_CASE("gl texture") opengl_texture.upload(compressed, 2); } ShaderProgram shader = create_debug_shader(R"( - uniform sampler2DArray texture_sampler; + uniform lowp sampler2DArray texture_sampler; in highp vec2 texcoords; - out lowp vec4 out_color_0; - out lowp vec4 out_color_1; - out lowp vec4 out_color_2; + layout (location = 0) out lowp vec4 out_color_0; + layout (location = 1) out lowp vec4 out_color_1; + layout (location = 2) out lowp vec4 out_color_2; void main() { out_color_0 = texture(texture_sampler, vec3(texcoords.x, 1.0 - texcoords.y, 0.0)); out_color_1 = texture(texture_sampler, vec3(texcoords.x, 1.0 - texcoords.y, 1.0)); @@ -347,8 +347,8 @@ TEST_CASE("gl texture") ShaderProgram shader = create_debug_shader(R"( uniform mediump usampler2DArray texture_sampler; - out lowp vec4 out_color1; - out lowp vec4 out_color2; + layout (location = 0) out lowp vec4 out_color1; + layout (location = 1) out lowp vec4 out_color2; void main() { { mediump uint v = texture(texture_sampler, vec3(0.5, 0.5, 0)).r; From 53aec0ee0a51fb7cdd70629ce2a6175ced4d5495 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 16 Mar 2024 12:18:34 +0100 Subject: [PATCH 61/65] test for webassembly mobile --- gl_engine/Texture.cpp | 3 +- unittests/gl_engine/texture.cpp | 80 ++++++++++++++++----------------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 955df075..e813d187 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -194,7 +194,7 @@ GLenum gl_engine::Texture::compressed_texture_format() return 0; return ext.COMPRESSED_RGB_ETC1_WEBGL; }); - qDebug() << "gl_texture_format from js: " << gl_texture_format; + qDebug() << "gl_engine::Texture::compressed_texture_format: gl_texture_format from js: " << gl_texture_format; // clang-format on if (gl_texture_format == 0) { gl_texture_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // not on mobile @@ -220,6 +220,7 @@ nucleus::utils::ColourTexture::Format gl_engine::Texture::compression_algorithm( return ext.COMPRESSED_RGB_ETC1_WEBGL; }); // clang-format on + qDebug() << "gl_engine::Texture::compression_algorithm: gl_texture_format from js: " << gl_texture_format; if (gl_texture_format == 0) { return nucleus::utils::ColourTexture::Format::DXT1; } diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index e413c731..15d2f142 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -291,46 +291,46 @@ TEST_CASE("gl texture") shader.bind(); gl_engine::helpers::create_screen_quad_geometry().draw(); - { - const QImage render_result = framebuffer.read_colour_attachment(0); - // render_result.save("render_result.png"); - // test_texture.save("test_texture.png"); - double diff = 0; - for (int i = 0; i < render_result.width(); ++i) { - for (int j = 0; j < render_result.height(); ++j) { - diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; - diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; - diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; - } - } - CHECK(diff / (256 * 256 * 3) < 0.017); - } - { - const QImage render_result = framebuffer.read_colour_attachment(1); - // render_result.save("render_result1.png"); - double diff = 0; - for (int i = 0; i < render_result.width(); ++i) { - for (int j = 0; j < render_result.height(); ++j) { - diff += std::abs(qRed(render_result.pixel(i, j)) - 42) / 255.0; - diff += std::abs(qGreen(render_result.pixel(i, j)) - 142) / 255.0; - diff += std::abs(qBlue(render_result.pixel(i, j)) - 242) / 255.0; - } - } - CHECK(diff / (256 * 256 * 3) < 0.017); - } - { - const QImage render_result = framebuffer.read_colour_attachment(2); - // render_result.save("render_result2.png"); - double diff = 0; - for (int i = 0; i < render_result.width(); ++i) { - for (int j = 0; j < render_result.height(); ++j) { - diff += std::abs(qRed(render_result.pixel(i, j)) - 222) / 255.0; - diff += std::abs(qGreen(render_result.pixel(i, j)) - 111) / 255.0; - diff += std::abs(qBlue(render_result.pixel(i, j)) - 0) / 255.0; - } - } - CHECK(diff / (256 * 256 * 3) < 0.017); - } + // { + // const QImage render_result = framebuffer.read_colour_attachment(0); + // // render_result.save("render_result.png"); + // // test_texture.save("test_texture.png"); + // double diff = 0; + // for (int i = 0; i < render_result.width(); ++i) { + // for (int j = 0; j < render_result.height(); ++j) { + // diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + // diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + // diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + // } + // } + // CHECK(diff / (256 * 256 * 3) < 0.017); + // } + // { + // const QImage render_result = framebuffer.read_colour_attachment(1); + // // render_result.save("render_result1.png"); + // double diff = 0; + // for (int i = 0; i < render_result.width(); ++i) { + // for (int j = 0; j < render_result.height(); ++j) { + // diff += std::abs(qRed(render_result.pixel(i, j)) - 42) / 255.0; + // diff += std::abs(qGreen(render_result.pixel(i, j)) - 142) / 255.0; + // diff += std::abs(qBlue(render_result.pixel(i, j)) - 242) / 255.0; + // } + // } + // CHECK(diff / (256 * 256 * 3) < 0.017); + // } + // { + // const QImage render_result = framebuffer.read_colour_attachment(2); + // // render_result.save("render_result2.png"); + // double diff = 0; + // for (int i = 0; i < render_result.width(); ++i) { + // for (int j = 0; j < render_result.height(); ++j) { + // diff += std::abs(qRed(render_result.pixel(i, j)) - 222) / 255.0; + // diff += std::abs(qGreen(render_result.pixel(i, j)) - 111) / 255.0; + // diff += std::abs(qBlue(render_result.pixel(i, j)) - 0) / 255.0; + // } + // } + // CHECK(diff / (256 * 256 * 3) < 0.017); + // } } } From 67e47a0d4b47d384482bb848f8a85c3c12cab570 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 16 Mar 2024 17:15:23 +0100 Subject: [PATCH 62/65] try to fix compressed array textures on webassembly mobile --- gl_engine/Texture.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index e813d187..be0051d1 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -189,10 +189,10 @@ GLenum gl_engine::Texture::compressed_texture_format() static int gl_texture_format = EM_ASM_INT({ var canvas = document.createElement('canvas'); var gl = canvas.getContext("webgl2"); - const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); + const ext = gl.getExtension("WEBGL_compressed_texture_es3"); if (ext === null) return 0; - return ext.COMPRESSED_RGB_ETC1_WEBGL; + return ext.COMPRESSED_RGB8_ETC2; }); qDebug() << "gl_engine::Texture::compressed_texture_format: gl_texture_format from js: " << gl_texture_format; // clang-format on @@ -214,10 +214,10 @@ nucleus::utils::ColourTexture::Format gl_engine::Texture::compression_algorithm( static const int gl_texture_format = EM_ASM_INT({ var canvas = document.createElement('canvas'); var gl = canvas.getContext("webgl2"); - const ext = gl.getExtension("WEBGL_compressed_texture_etc1"); + const ext = gl.getExtension("WEBGL_compressed_texture_es3"); if (ext === null) return 0; - return ext.COMPRESSED_RGB_ETC1_WEBGL; + return ext.COMPRESSED_RGB8_ETC2; }); // clang-format on qDebug() << "gl_engine::Texture::compression_algorithm: gl_texture_format from js: " << gl_texture_format; From d72dce7b44c4cb6cc1596a47412684fa9136f753 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 16 Mar 2024 17:30:19 +0100 Subject: [PATCH 63/65] use standard extension name --- gl_engine/Texture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index be0051d1..ae192007 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -189,7 +189,7 @@ GLenum gl_engine::Texture::compressed_texture_format() static int gl_texture_format = EM_ASM_INT({ var canvas = document.createElement('canvas'); var gl = canvas.getContext("webgl2"); - const ext = gl.getExtension("WEBGL_compressed_texture_es3"); + const ext = gl.getExtension("WEBGL_compressed_texture_etc"); if (ext === null) return 0; return ext.COMPRESSED_RGB8_ETC2; @@ -214,7 +214,7 @@ nucleus::utils::ColourTexture::Format gl_engine::Texture::compression_algorithm( static const int gl_texture_format = EM_ASM_INT({ var canvas = document.createElement('canvas'); var gl = canvas.getContext("webgl2"); - const ext = gl.getExtension("WEBGL_compressed_texture_es3"); + const ext = gl.getExtension("WEBGL_compressed_texture_etc"); if (ext === null) return 0; return ext.COMPRESSED_RGB8_ETC2; From f1e69ac11efe8472aa10cbf0f7996f22193fe561 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 16 Mar 2024 17:47:21 +0100 Subject: [PATCH 64/65] reenable tests --- unittests/gl_engine/texture.cpp | 80 ++++++++++++++++----------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index 15d2f142..e413c731 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -291,46 +291,46 @@ TEST_CASE("gl texture") shader.bind(); gl_engine::helpers::create_screen_quad_geometry().draw(); - // { - // const QImage render_result = framebuffer.read_colour_attachment(0); - // // render_result.save("render_result.png"); - // // test_texture.save("test_texture.png"); - // double diff = 0; - // for (int i = 0; i < render_result.width(); ++i) { - // for (int j = 0; j < render_result.height(); ++j) { - // diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; - // diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; - // diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; - // } - // } - // CHECK(diff / (256 * 256 * 3) < 0.017); - // } - // { - // const QImage render_result = framebuffer.read_colour_attachment(1); - // // render_result.save("render_result1.png"); - // double diff = 0; - // for (int i = 0; i < render_result.width(); ++i) { - // for (int j = 0; j < render_result.height(); ++j) { - // diff += std::abs(qRed(render_result.pixel(i, j)) - 42) / 255.0; - // diff += std::abs(qGreen(render_result.pixel(i, j)) - 142) / 255.0; - // diff += std::abs(qBlue(render_result.pixel(i, j)) - 242) / 255.0; - // } - // } - // CHECK(diff / (256 * 256 * 3) < 0.017); - // } - // { - // const QImage render_result = framebuffer.read_colour_attachment(2); - // // render_result.save("render_result2.png"); - // double diff = 0; - // for (int i = 0; i < render_result.width(); ++i) { - // for (int j = 0; j < render_result.height(); ++j) { - // diff += std::abs(qRed(render_result.pixel(i, j)) - 222) / 255.0; - // diff += std::abs(qGreen(render_result.pixel(i, j)) - 111) / 255.0; - // diff += std::abs(qBlue(render_result.pixel(i, j)) - 0) / 255.0; - // } - // } - // CHECK(diff / (256 * 256 * 3) < 0.017); - // } + { + const QImage render_result = framebuffer.read_colour_attachment(0); + // render_result.save("render_result.png"); + // test_texture.save("test_texture.png"); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - qRed(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - qGreen(test_texture.pixel(i, j))) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - qBlue(test_texture.pixel(i, j))) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.017); + } + { + const QImage render_result = framebuffer.read_colour_attachment(1); + // render_result.save("render_result1.png"); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - 42) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - 142) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - 242) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.017); + } + { + const QImage render_result = framebuffer.read_colour_attachment(2); + // render_result.save("render_result2.png"); + double diff = 0; + for (int i = 0; i < render_result.width(); ++i) { + for (int j = 0; j < render_result.height(); ++j) { + diff += std::abs(qRed(render_result.pixel(i, j)) - 222) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) - 111) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) - 0) / 255.0; + } + } + CHECK(diff / (256 * 256 * 3) < 0.017); + } } } From 8926e703c4bc0a2fd7d8d7e53caea03e693839a4 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 16 Mar 2024 17:59:59 +0100 Subject: [PATCH 65/65] remove debug output --- gl_engine/Texture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index ae192007..cfe3166b 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -194,7 +194,7 @@ GLenum gl_engine::Texture::compressed_texture_format() return 0; return ext.COMPRESSED_RGB8_ETC2; }); - qDebug() << "gl_engine::Texture::compressed_texture_format: gl_texture_format from js: " << gl_texture_format; + // qDebug() << "gl_engine::Texture::compressed_texture_format: gl_texture_format from js: " << gl_texture_format; // clang-format on if (gl_texture_format == 0) { gl_texture_format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // not on mobile @@ -220,7 +220,7 @@ nucleus::utils::ColourTexture::Format gl_engine::Texture::compression_algorithm( return ext.COMPRESSED_RGB8_ETC2; }); // clang-format on - qDebug() << "gl_engine::Texture::compression_algorithm: gl_texture_format from js: " << gl_texture_format; + // qDebug() << "gl_engine::Texture::compression_algorithm: gl_texture_format from js: " << gl_texture_format; if (gl_texture_format == 0) { return nucleus::utils::ColourTexture::Format::DXT1; }