From d24e881a2f2038feae5ae5262a9e80d2afb08260 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 6 Jul 2025 17:55:40 +0200 Subject: [PATCH 01/12] update qml console --- cmake/alp_add_unittest.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/alp_add_unittest.cmake b/cmake/alp_add_unittest.cmake index a2908947..1cdcbfaa 100644 --- a/cmake/alp_add_unittest.cmake +++ b/cmake/alp_add_unittest.cmake @@ -20,7 +20,7 @@ find_package(Qt6 REQUIRED COMPONENTS Test) if (NOT TARGET Catch2) alp_add_git_repository(catch2 URL https://github.com/catchorg/Catch2.git COMMITISH v3.5.1) endif() -alp_add_git_repository(qml_catch2_console URL https://github.com/AlpineMapsOrg/qml_catch2_console.git COMMITISH fcf6dafe6c95ac5b5436b0dfe634341c3a37513a DO_NOT_ADD_SUBPROJECT) +alp_add_git_repository(qml_catch2_console URL https://github.com/AlpineMapsOrg/qml_catch2_console.git COMMITISH 33430766f7f896db523b72c76c49eeb427ee9c63 DO_NOT_ADD_SUBPROJECT) if (EMSCRIPTEN AND ALP_ENABLE_THREADING) target_compile_options(Catch2 PRIVATE -pthread) From 717c5d3e182d4a682cdaa6123696fe80af37edf6 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 6 Jul 2025 17:57:45 +0200 Subject: [PATCH 02/12] fix #54 (fetching tiles in scheduler thread doesn't work on webassembly) --- nucleus/map_label/setup.h | 4 ---- nucleus/tile/setup.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/nucleus/map_label/setup.h b/nucleus/map_label/setup.h index d770df18..8c0efc5b 100644 --- a/nucleus/map_label/setup.h +++ b/nucleus/map_label/setup.h @@ -73,12 +73,8 @@ SchedulerHolder scheduler(TileLoadServicePtr tile_service, const tile::utils::Aa Q_UNUSED(thread); #ifdef ALP_ENABLE_THREADING -#ifdef __EMSCRIPTEN__ // make request from main thread on webassembly due to QTBUG-109396 - tile_service->moveToThread(QCoreApplication::instance()->thread()); -#else if (thread) tile_service->moveToThread(thread); -#endif if (thread) scheduler->moveToThread(thread); #endif diff --git a/nucleus/tile/setup.h b/nucleus/tile/setup.h index 7a4432cb..3348a803 100644 --- a/nucleus/tile/setup.h +++ b/nucleus/tile/setup.h @@ -75,12 +75,8 @@ inline GeometrySchedulerHolder geometry_scheduler(TileLoadServicePtr tile_servic Q_UNUSED(thread); #ifdef ALP_ENABLE_THREADING -#ifdef __EMSCRIPTEN__ // make request from main thread on webassembly due to QTBUG-109396 - tile_service->moveToThread(QCoreApplication::instance()->thread()); -#else if (thread) tile_service->moveToThread(thread); -#endif if (thread) scheduler->moveToThread(thread); #endif From 960056fbdf1bb2ab09c76abcc98e968ea7229ae0 Mon Sep 17 00:00:00 2001 From: Adam Ce <5292991+adam-ce@users.noreply.github.com> Date: Fri, 11 Jul 2025 00:04:10 +0200 Subject: [PATCH 03/12] fix handling of peaks with no ele (#166) --- nucleus/picker/PickerManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nucleus/picker/PickerManager.cpp b/nucleus/picker/PickerManager.cpp index 6d761662..69fd9411 100644 --- a/nucleus/picker/PickerManager.cpp +++ b/nucleus/picker/PickerManager.cpp @@ -72,6 +72,8 @@ void PickerManager::eval_pick(uint32_t value) for (const auto& key_value : poi->attributes.asKeyValueRange()) { picked.properties[key_value.first] = key_value.second; } + if (!picked.properties.contains("ele")) + picked.properties["ele"] = std::round(poi->lat_long_alt.z); picked.properties["type"] = to_string(poi->type); picked.properties["latitude"] = poi->lat_long_alt.x; picked.properties["longitude"] = poi->lat_long_alt.y; From c20cb46ee8bd4c85c86a3bc79d198b7e1ef3d64b Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Wed, 20 Aug 2025 15:24:11 +0200 Subject: [PATCH 04/12] suppress more system libraries in asan (triggered in ci) --- sanitizer_supressions/linux_leak.supp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sanitizer_supressions/linux_leak.supp b/sanitizer_supressions/linux_leak.supp index fa893459..aca639ec 100644 --- a/sanitizer_supressions/linux_leak.supp +++ b/sanitizer_supressions/linux_leak.supp @@ -2,3 +2,7 @@ leak:dbus leak:fontconfig leak:icui18n leak:gallium +leak:libGLX_mesa +leak:libGLX.so +leak:qglx_findConfig +leak:Qt6Gui.so From 37e3e094b6799503463201adb7f45b8009a29c8f Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 25 Oct 2025 22:45:40 +0200 Subject: [PATCH 05/12] experiment with srgb: atmosphere looks nicer, but problem with labels. not tested on web and android. --- app/TerrainRenderer.cpp | 1 + gl_engine/Framebuffer.cpp | 10 ++++++++-- gl_engine/Framebuffer.h | 9 +++++---- gl_engine/Texture.cpp | 2 +- gl_engine/Window.cpp | 8 +++++--- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/TerrainRenderer.cpp b/app/TerrainRenderer.cpp index 6201b843..c78a4def 100644 --- a/app/TerrainRenderer.cpp +++ b/app/TerrainRenderer.cpp @@ -138,6 +138,7 @@ QOpenGLFramebufferObject *TerrainRenderer::createFramebufferObject(const QSize & QOpenGLFramebufferObjectFormat format; format.setSamples(1); format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + format.setInternalTextureFormat(GL_SRGB8_ALPHA8); return new QOpenGLFramebufferObject(size, format); } diff --git a/gl_engine/Framebuffer.cpp b/gl_engine/Framebuffer.cpp index 0e20d001..94d5486b 100644 --- a/gl_engine/Framebuffer.cpp +++ b/gl_engine/Framebuffer.cpp @@ -43,6 +43,8 @@ QOpenGLTexture::TextureFormat internal_format_qt(Framebuffer::ColourFormat f) return QOpenGLTexture::TextureFormat::RGB8_UNorm; case Framebuffer::ColourFormat::RGBA8: return QOpenGLTexture::TextureFormat::RGBA8_UNorm; + case Framebuffer::ColourFormat::SRGBA8: + return QOpenGLTexture::TextureFormat::SRGB8_Alpha8; case Framebuffer::ColourFormat::RG16UI: return QOpenGLTexture::TextureFormat::RG16U; case Framebuffer::ColourFormat::Float32: @@ -69,6 +71,8 @@ GLenum format(Framebuffer::ColourFormat f) return GL_RGB; case Framebuffer::ColourFormat::RGBA8: return GL_RGBA; + case Framebuffer::ColourFormat::SRGBA8: + return GL_RGBA; case Framebuffer::ColourFormat::RG16UI: return QOpenGLTexture::PixelFormat::RG_Integer; case Framebuffer::ColourFormat::Float32: // reading Float32 is inefficient, see read_colour_attachment() for details. @@ -114,6 +118,7 @@ GLenum type(Framebuffer::ColourFormat f) switch (f) { case Framebuffer::ColourFormat::R8: case Framebuffer::ColourFormat::RGBA8: + case Framebuffer::ColourFormat::SRGBA8: case Framebuffer::ColourFormat::RGB8: return GL_UNSIGNED_BYTE; case Framebuffer::ColourFormat::RG16UI: @@ -196,8 +201,8 @@ void Framebuffer::recreate_texture(size_t index) // 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]), (QOpenGLTexture::PixelType)type(m_colour_definitions[index])); + m_colour_textures[index]->allocateStorage(); + // (QOpenGLTexture::PixelFormat)format(m_colour_definitions[index]), (QOpenGLTexture::PixelType)type(m_colour_definitions[index])); } } @@ -314,6 +319,7 @@ T Framebuffer::read_colour_attachment_pixel(unsigned int index, const glm::dvec2 assert(false); return {}; case Framebuffer::ColourFormat::RGBA8: + case Framebuffer::ColourFormat::SRGBA8: assert(sizeof(T) == 4); if (sizeof(T) != 4) return {}; diff --git a/gl_engine/Framebuffer.h b/gl_engine/Framebuffer.h index 79b4bad4..8adcfc4d 100644 --- a/gl_engine/Framebuffer.h +++ b/gl_engine/Framebuffer.h @@ -50,12 +50,13 @@ class Framebuffer R8, RGB8, RGBA8, + SRGBA8, RG16UI, - RGB16F, // NOT COLOR RENDERABLE ON OPENGLES - RGBA16F, // NOT COLOR RENDERABLE ON OPENGLES + RGB16F, // NOT COLOR RENDERABLE ON OPENGLES + RGBA16F, // NOT COLOR RENDERABLE ON OPENGLES R32UI, - Float32, // NOT COLOR RENDERABLE ON OPENGLES - RGBA32F, // NOT COLOR RENDERABLE ON OPENGLES (weirdly it works, maybe because of extension, that qt activates?) + Float32, // NOT COLOR RENDERABLE ON OPENGLES + RGBA32F, // NOT COLOR RENDERABLE ON OPENGLES (weirdly it works, maybe because of extension, that qt activates?) }; private: diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 50819172..a9561505 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -285,7 +285,7 @@ GLenum gl_engine::Texture::compressed_texture_format() #elif defined(__ANDROID__) return GL_COMPRESSED_RGB8_ETC2; #else - return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; #endif } diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index ec37477d..6ac61826 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -172,15 +172,15 @@ 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 { - Framebuffer::ColourFormat::RGBA8, // Albedo + Framebuffer::ColourFormat::SRGBA8, // 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 // TextureDefinition { Framebuffer::ColourFormat::R32UI }, // VertexID }); - 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 }); + m_atmospherebuffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { Framebuffer::ColourFormat::SRGBA8 }); + m_decoration_buffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { Framebuffer::ColourFormat::SRGBA8 }); m_pickerbuffer = std::make_unique(Framebuffer::DepthFormat::Float32, std::vector { Framebuffer::ColourFormat::RGBA32F }); f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_gbuffer->depth_texture()->textureId(), 0); @@ -262,6 +262,7 @@ void Window::paint(QOpenGLFramebufferObject* framebuffer) QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + f->glEnable(GL_FRAMEBUFFER_SRGB); f->glEnable(GL_CULL_FACE); f->glCullFace(GL_BACK); @@ -443,6 +444,7 @@ void Window::paint(QOpenGLFramebufferObject* framebuffer) f->glDisable(GL_BLEND); f->glBlendFunc(GL_ONE, GL_ZERO); f->glDisable(GL_CULL_FACE); + f->glDisable(GL_FRAMEBUFFER_SRGB); m_timer->stop_timer("cpu_total"); m_timer->stop_timer("gpu_total"); From c258e19d198b7fef4a92085cf73731912e73acc1 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sat, 25 Oct 2025 23:24:07 +0200 Subject: [PATCH 06/12] i do not understand, why we need to disable gamma encoding for text. the target buffer should be srgb, so writing without encoding will result in sth that is decoded 1 time too often. the symbols look a bit wrong (probably their texture needs the srgba format). --- gl_engine/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index 6ac61826..8176aee0 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -439,12 +439,12 @@ void Window::paint(QOpenGLFramebufferObject* framebuffer) m_decoration_buffer->bind_colour_texture(0, 0); f->glEnable(GL_BLEND); f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + f->glDisable(GL_FRAMEBUFFER_SRGB); m_screen_quad_geometry.draw(); f->glDisable(GL_BLEND); f->glBlendFunc(GL_ONE, GL_ZERO); f->glDisable(GL_CULL_FACE); - f->glDisable(GL_FRAMEBUFFER_SRGB); m_timer->stop_timer("cpu_total"); m_timer->stop_timer("gpu_total"); From 9f98315964af4163973cd918aae4267dfa0c1712 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 26 Oct 2025 16:25:56 +0100 Subject: [PATCH 07/12] srgba framebuffer support is patchy (not working on android, for webgl you need an extension, which i didn't test). so imo the better option is to manually encode after we are done. in theory we could do better by manually encoding in the g-buffer. however, the difference is hardly perceptible (i saw sth in the decoration buffer with the labels), and we risk other problems (sb. forgets it, bad filtering or blending). --- app/TerrainRenderer.cpp | 1 - gl_engine/Texture.cpp | 6 +++--- gl_engine/Window.cpp | 8 +++----- gl_engine/shaders/compose.frag | 2 ++ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/TerrainRenderer.cpp b/app/TerrainRenderer.cpp index c78a4def..6201b843 100644 --- a/app/TerrainRenderer.cpp +++ b/app/TerrainRenderer.cpp @@ -138,7 +138,6 @@ QOpenGLFramebufferObject *TerrainRenderer::createFramebufferObject(const QSize & QOpenGLFramebufferObjectFormat format; format.setSamples(1); format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - format.setInternalTextureFormat(GL_SRGB8_ALPHA8); return new QOpenGLFramebufferObject(size, format); } diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index a9561505..0499a31e 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -274,16 +274,16 @@ GLenum gl_engine::Texture::compressed_texture_format() const ext = gl.getExtension("WEBGL_compressed_texture_etc"); if (ext === null) return 0; - return ext.COMPRESSED_RGB8_ETC2; + return ext.COMPRESSED_SRGB8_ETC2; }); // 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 + gl_texture_format = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; // not on mobile } return gl_texture_format; #elif defined(__ANDROID__) - return GL_COMPRESSED_RGB8_ETC2; + return GL_COMPRESSED_SRGB8_ETC2; #else return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; #endif diff --git a/gl_engine/Window.cpp b/gl_engine/Window.cpp index 8176aee0..ec37477d 100644 --- a/gl_engine/Window.cpp +++ b/gl_engine/Window.cpp @@ -172,15 +172,15 @@ 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 { - Framebuffer::ColourFormat::SRGBA8, // Albedo + 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 // TextureDefinition { Framebuffer::ColourFormat::R32UI }, // VertexID }); - m_atmospherebuffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { Framebuffer::ColourFormat::SRGBA8 }); - m_decoration_buffer = std::make_unique(Framebuffer::DepthFormat::None, std::vector { Framebuffer::ColourFormat::SRGBA8 }); + 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 }); m_pickerbuffer = std::make_unique(Framebuffer::DepthFormat::Float32, std::vector { Framebuffer::ColourFormat::RGBA32F }); f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_gbuffer->depth_texture()->textureId(), 0); @@ -262,7 +262,6 @@ void Window::paint(QOpenGLFramebufferObject* framebuffer) QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); - f->glEnable(GL_FRAMEBUFFER_SRGB); f->glEnable(GL_CULL_FACE); f->glCullFace(GL_BACK); @@ -439,7 +438,6 @@ void Window::paint(QOpenGLFramebufferObject* framebuffer) m_decoration_buffer->bind_colour_texture(0, 0); f->glEnable(GL_BLEND); f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - f->glDisable(GL_FRAMEBUFFER_SRGB); m_screen_quad_geometry.draw(); f->glDisable(GL_BLEND); diff --git a/gl_engine/shaders/compose.frag b/gl_engine/shaders/compose.frag index fb886f34..add96b95 100644 --- a/gl_engine/shaders/compose.frag +++ b/gl_engine/shaders/compose.frag @@ -260,4 +260,6 @@ void main() { } } + // srgb framebuffer support is patchy. encoding manually here. + out_Color = vec4(pow(out_Color.rgb, vec3(1.0/2.2)), out_Color.a); } From c60dd8881d4e89f3b1dc68e2094337c0891d8e75 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Sun, 26 Oct 2025 16:26:43 +0100 Subject: [PATCH 08/12] comment disfunctional formats so nobody is tempted to use them. --- gl_engine/Framebuffer.cpp | 58 +++++++++++++++++++-------------------- gl_engine/Framebuffer.h | 8 +++--- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/gl_engine/Framebuffer.cpp b/gl_engine/Framebuffer.cpp index 94d5486b..77328ddf 100644 --- a/gl_engine/Framebuffer.cpp +++ b/gl_engine/Framebuffer.cpp @@ -43,16 +43,16 @@ QOpenGLTexture::TextureFormat internal_format_qt(Framebuffer::ColourFormat f) return QOpenGLTexture::TextureFormat::RGB8_UNorm; case Framebuffer::ColourFormat::RGBA8: return QOpenGLTexture::TextureFormat::RGBA8_UNorm; - case Framebuffer::ColourFormat::SRGBA8: - return QOpenGLTexture::TextureFormat::SRGB8_Alpha8; + // case Framebuffer::ColourFormat::SRGBA8: + // return QOpenGLTexture::TextureFormat::SRGB8_Alpha8; case Framebuffer::ColourFormat::RG16UI: return QOpenGLTexture::TextureFormat::RG16U; - case Framebuffer::ColourFormat::Float32: - return QOpenGLTexture::TextureFormat::R32F; - case Framebuffer::ColourFormat::RGB16F: - return QOpenGLTexture::TextureFormat::RGB16F; - case Framebuffer::ColourFormat::RGBA16F: - return QOpenGLTexture::TextureFormat::RGBA16F; + // case Framebuffer::ColourFormat::Float32: + // return QOpenGLTexture::TextureFormat::R32F; + // case Framebuffer::ColourFormat::RGB16F: + // return QOpenGLTexture::TextureFormat::RGB16F; + // case Framebuffer::ColourFormat::RGBA16F: + // return QOpenGLTexture::TextureFormat::RGBA16F; case Framebuffer::ColourFormat::R32UI: return QOpenGLTexture::TextureFormat::R32U; case Framebuffer::ColourFormat::RGBA32F: @@ -71,16 +71,16 @@ GLenum format(Framebuffer::ColourFormat f) return GL_RGB; case Framebuffer::ColourFormat::RGBA8: return GL_RGBA; - case Framebuffer::ColourFormat::SRGBA8: - return GL_RGBA; + // case Framebuffer::ColourFormat::SRGBA8: + // return GL_RGBA; case Framebuffer::ColourFormat::RG16UI: return QOpenGLTexture::PixelFormat::RG_Integer; - case Framebuffer::ColourFormat::Float32: // reading Float32 is inefficient, see read_colour_attachment() for details. - return GL_RED; - case Framebuffer::ColourFormat::RGB16F: - return GL_RGB; - case Framebuffer::ColourFormat::RGBA16F: - return GL_RGBA; + // case Framebuffer::ColourFormat::Float32: // reading Float32 is inefficient, see read_colour_attachment() for details. + // return GL_RED; + // case Framebuffer::ColourFormat::RGB16F: + // return GL_RGB; + // case Framebuffer::ColourFormat::RGBA16F: + // return GL_RGBA; case Framebuffer::ColourFormat::R32UI: return GL_RED_INTEGER; case Framebuffer::ColourFormat::RGBA32F: @@ -118,17 +118,17 @@ GLenum type(Framebuffer::ColourFormat f) switch (f) { case Framebuffer::ColourFormat::R8: case Framebuffer::ColourFormat::RGBA8: - case Framebuffer::ColourFormat::SRGBA8: + // case Framebuffer::ColourFormat::SRGBA8: case Framebuffer::ColourFormat::RGB8: return GL_UNSIGNED_BYTE; case Framebuffer::ColourFormat::RG16UI: return QOpenGLTexture::PixelType::UInt16; - case Framebuffer::ColourFormat::Float32: + // case Framebuffer::ColourFormat::Float32: case Framebuffer::ColourFormat::RGBA32F: return GL_FLOAT; - case Framebuffer::ColourFormat::RGB16F: - case Framebuffer::ColourFormat::RGBA16F: - return GL_HALF_FLOAT; + // case Framebuffer::ColourFormat::RGB16F: + // case Framebuffer::ColourFormat::RGBA16F: + // return GL_HALF_FLOAT; case Framebuffer::ColourFormat::R32UI: return GL_UNSIGNED_INT; } @@ -164,8 +164,8 @@ QImage::Format qimage_format(Framebuffer::ColourFormat f) return QImage::Format_RGBA8888; case Framebuffer::ColourFormat::RGB8: return QImage::Format_RGB888; - case Framebuffer::ColourFormat::RGB16F: - return QImage::Format_RGB16; + // case Framebuffer::ColourFormat::RGB16F: + // return QImage::Format_RGB16; default: throw std::logic_error("unsupported, QImage does not support the color format of the texture"); } @@ -201,8 +201,8 @@ void Framebuffer::recreate_texture(size_t index) // 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]), (QOpenGLTexture::PixelType)type(m_colour_definitions[index])); + m_colour_textures[index]->allocateStorage( + (QOpenGLTexture::PixelFormat)format(m_colour_definitions[index]), (QOpenGLTexture::PixelType)type(m_colour_definitions[index])); } } @@ -309,9 +309,9 @@ T Framebuffer::read_colour_attachment_pixel(unsigned int index, const glm::dvec2 case Framebuffer::ColourFormat::R8: case Framebuffer::ColourFormat::RGB8: case Framebuffer::ColourFormat::RG16UI: // unsupported on android emulator (and webassembly linux firefox?) - case Framebuffer::ColourFormat::Float32: - case Framebuffer::ColourFormat::RGB16F: - case Framebuffer::ColourFormat::RGBA16F: + // case Framebuffer::ColourFormat::Float32: + // case Framebuffer::ColourFormat::RGB16F: + // case Framebuffer::ColourFormat::RGBA16F: case Framebuffer::ColourFormat::R32UI: // fails on linux firefox // unsupported or untested. // you really should add a unit test if you move something down to the supported section @@ -319,7 +319,7 @@ T Framebuffer::read_colour_attachment_pixel(unsigned int index, const glm::dvec2 assert(false); return {}; case Framebuffer::ColourFormat::RGBA8: - case Framebuffer::ColourFormat::SRGBA8: + // case Framebuffer::ColourFormat::SRGBA8: assert(sizeof(T) == 4); if (sizeof(T) != 4) return {}; diff --git a/gl_engine/Framebuffer.h b/gl_engine/Framebuffer.h index 8adcfc4d..b63c755b 100644 --- a/gl_engine/Framebuffer.h +++ b/gl_engine/Framebuffer.h @@ -50,12 +50,12 @@ class Framebuffer R8, RGB8, RGBA8, - SRGBA8, + // SRGBA8, // not supported as a framebuffer on android RG16UI, - RGB16F, // NOT COLOR RENDERABLE ON OPENGLES - RGBA16F, // NOT COLOR RENDERABLE ON OPENGLES + // RGB16F, // NOT COLOR RENDERABLE ON OPENGLES + // RGBA16F, // NOT COLOR RENDERABLE ON OPENGLES R32UI, - Float32, // NOT COLOR RENDERABLE ON OPENGLES + // Float32, // NOT COLOR RENDERABLE ON OPENGLES RGBA32F, // NOT COLOR RENDERABLE ON OPENGLES (weirdly it works, maybe because of extension, that qt activates?) }; From 8422492c3ef89f603c2ff10dba13c0adec8e48a0 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 27 Oct 2025 00:25:36 +0100 Subject: [PATCH 09/12] fix unit tests --- gl_engine/Texture.cpp | 11 +++++++---- gl_engine/Texture.h | 1 + unittests/gl_engine/texture.cpp | 30 +++++++++++++++--------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/gl_engine/Texture.cpp b/gl_engine/Texture.cpp index 0499a31e..3334306b 100644 --- a/gl_engine/Texture.cpp +++ b/gl_engine/Texture.cpp @@ -48,6 +48,8 @@ GlParams gl_tex_params(gl_engine::Texture::Format format) return { GLint(gl_engine::Texture::compressed_texture_format()), 0, 0, 0, 0, true }; case F::RGBA8: return { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, 4, 1, true }; + case F::SRGBA8: + return { GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, 4, 1, true }; case F::RGBA8UI: return { GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, 4, 1 }; case F::RGBA32F: @@ -135,12 +137,13 @@ void gl_engine::Texture::upload(const nucleus::utils::ColourTexture& texture) f->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); const auto width = GLsizei(texture.width()); const auto height = GLsizei(texture.height()); + const auto p = gl_tex_params(m_format); 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()); + } else if (m_format == Format::RGBA8 || m_format == Format::SRGBA8) { + f->glTexImage2D(GLenum(m_target), 0, p.internal_format, width, height, 0, p.format, p.type, texture.data()); if (m_min_filter == Filter::MipMapLinear) f->glGenerateMipmap(GLenum(m_target)); } else { @@ -163,7 +166,7 @@ void gl_engine::Texture::upload(const nucleus::utils::ColourTexture& texture, un if (m_format == Format::CompressedRGBA8) { 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) { + } else if (m_format == Format::RGBA8 || m_format == Format::SRGBA8) { f->glTexSubImage3D(GLenum(m_target), 0, 0, 0, GLint(array_index), width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, texture.data()); } else { assert(false); @@ -188,7 +191,7 @@ void gl_engine::Texture::upload(const nucleus::utils::MipmappedColourTexture& mi const auto format = gl_engine::Texture::compressed_texture_format(); f->glCompressedTexSubImage3D( GLenum(m_target), mip_level, 0, 0, GLint(array_index), width, height, 1, format, GLsizei(texture.n_bytes()), texture.data()); - } else if (m_format == Format::RGBA8) { + } else if (m_format == Format::RGBA8 || m_format == Format::SRGBA8) { f->glTexSubImage3D(GLenum(m_target), mip_level, 0, 0, GLint(array_index), width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, texture.data()); } else { assert(false); diff --git a/gl_engine/Texture.h b/gl_engine/Texture.h index 697d1820..0632f4ac 100644 --- a/gl_engine/Texture.h +++ b/gl_engine/Texture.h @@ -33,6 +33,7 @@ class Texture { enum class Target : GLenum { _2d = GL_TEXTURE_2D, _2dArray = GL_TEXTURE_2D_ARRAY }; // no 1D textures in webgl enum class Format { RGBA8, // normalised on gpu + SRGBA8, // normalised on gpu CompressedRGBA8, // normalised on gpu, compression format depends on desktop/mobile RGBA8UI, RGBA32F, diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index b923c7cf..aa13aaf8 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -291,9 +291,9 @@ TEST_CASE("gl texture") const auto g = qGreen(result_pixel); const auto b = qBlue(result_pixel); - diff += std::abs(r - ref_pixel.x) / 255.0; - diff += std::abs(g - ref_pixel.y) / 255.0; - diff += std::abs(b - ref_pixel.z) / 255.0; + diff += std::abs(r / 255.0 - std::pow(ref_pixel.x / 255.0, 2.2)); + diff += std::abs(g / 255.0 - std::pow(ref_pixel.y / 255.0, 2.2)); + diff += std::abs(b / 255.0 - std::pow(ref_pixel.z / 255.0, 2.2)); } } CAPTURE(resolution); @@ -381,7 +381,7 @@ TEST_CASE("gl texture") for (auto texture_type : texture_types) { CAPTURE(texture_type.first); CAPTURE(texture_type.second); - const auto format = (texture_type.first == ColourTexture::Format::Uncompressed_RGBA) ? gl_engine::Texture::Format::RGBA8 + const auto format = (texture_type.first == ColourTexture::Format::Uncompressed_RGBA) ? gl_engine::Texture::Format::SRGBA8 : gl_engine::Texture::Format::CompressedRGBA8; const auto use_mipmaps = texture_type.second; gl_engine::Texture opengl_texture(gl_engine::Texture::Target::_2dArray, format); @@ -433,9 +433,9 @@ TEST_CASE("gl texture") 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)) - test_raster.pixel({ i, j }).x) / 255.0; - diff += std::abs(qGreen(render_result.pixel(i, j)) - test_raster.pixel({ i, j }).y) / 255.0; - diff += std::abs(qBlue(render_result.pixel(i, j)) - test_raster.pixel({ i, j }).z) / 255.0; + diff += std::abs(qRed(render_result.pixel(i, j)) / 255.0 - std::pow(test_raster.pixel({ i, j }).x / 255.0, 2.2)); + diff += std::abs(qGreen(render_result.pixel(i, j)) / 255.0 - std::pow(test_raster.pixel({ i, j }).y / 255.0, 2.2)); + diff += std::abs(qBlue(render_result.pixel(i, j)) / 255.0 - std::pow(test_raster.pixel({ i, j }).z / 255.0, 2.2)); } } CHECK(diff / (256 * 256 * 3) < 0.017); @@ -446,12 +446,12 @@ TEST_CASE("gl texture") 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; + diff += std::abs(qRed(render_result.pixel(i, j)) / 255.0 - std::pow(42 / 255.0, 2.2)); + diff += std::abs(qGreen(render_result.pixel(i, j)) / 255.0 - std::pow(142 / 255.0, 2.2)); + diff += std::abs(qBlue(render_result.pixel(i, j)) / 255.0 - std::pow(242 / 255.0, 2.2)); } } - CHECK(diff / (256 * 256 * 3) < 0.017); + CHECK(diff / (256 * 256 * 3) < 0.018); } { const QImage render_result = framebuffer.read_colour_attachment(2); @@ -459,12 +459,12 @@ TEST_CASE("gl texture") 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; + diff += std::abs(qRed(render_result.pixel(i, j)) / 255.0 - std::pow(222 / 255.0, 2.2)) / 255.0; + diff += std::abs(qGreen(render_result.pixel(i, j)) / 255.0 - std::pow(111 / 255.0, 2.2)) / 255.0; + diff += std::abs(qBlue(render_result.pixel(i, j)) / 255.0 - std::pow(0 / 255.0, 2.2)) / 255.0; } } - CHECK(diff / (256 * 256 * 3) < 0.017); + CHECK(diff / (256 * 256 * 3) < 0.018); } } } From 26a45cd23767f8c492bb9409e4d2aaf8276a89b6 Mon Sep 17 00:00:00 2001 From: Adam Celarek <5292991+adam-ce@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:22:36 +0100 Subject: [PATCH 10/12] fix unit test #2 --- unittests/gl_engine/texture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittests/gl_engine/texture.cpp b/unittests/gl_engine/texture.cpp index aa13aaf8..4180e3cf 100644 --- a/unittests/gl_engine/texture.cpp +++ b/unittests/gl_engine/texture.cpp @@ -451,7 +451,7 @@ TEST_CASE("gl texture") diff += std::abs(qBlue(render_result.pixel(i, j)) / 255.0 - std::pow(242 / 255.0, 2.2)); } } - CHECK(diff / (256 * 256 * 3) < 0.018); + CHECK(diff / (256 * 256 * 3) < 0.02); } { const QImage render_result = framebuffer.read_colour_attachment(2); @@ -464,7 +464,7 @@ TEST_CASE("gl texture") diff += std::abs(qBlue(render_result.pixel(i, j)) / 255.0 - std::pow(0 / 255.0, 2.2)) / 255.0; } } - CHECK(diff / (256 * 256 * 3) < 0.018); + CHECK(diff / (256 * 256 * 3) < 0.02); } } } From a01db4bfcb805caafc0159d0b85708ee4114b096 Mon Sep 17 00:00:00 2001 From: Adam Ce <5292991+adam-ce@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:35:13 +0100 Subject: [PATCH 11/12] fixes for android play console publishing --- app/CMakeLists.txt | 2 +- app/TrackModel.cpp | 6 ++++-- nucleus/camera/gesture.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 5403ac8e..dee632e0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -126,7 +126,7 @@ alp_get_version( set_target_properties(alpineapp PROPERTIES QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android QT_ANDROID_VERSION_NAME ${ALP_VERSION} - QT_ANDROID_VERSION_CODE "${ALP_VERSION_INTEGER}000" # accidentally uploaded a high versino code to google. now there is no way back. + QT_ANDROID_VERSION_CODE "${ALP_VERSION_INTEGER}" ) target_link_libraries(alpineapp PUBLIC gl_engine Qt::Quick Qt::QuickControls2) diff --git a/app/TrackModel.cpp b/app/TrackModel.cpp index 7717c1f9..333ae2cb 100644 --- a/app/TrackModel.cpp +++ b/app/TrackModel.cpp @@ -134,8 +134,10 @@ void TrackModel::upload_track() #else const auto path = QFileDialog::getOpenFileName(nullptr, tr("Open GPX track"), "", "GPX (*.gpx *.xml)"); auto file = QFile(path); - file.open(QFile::ReadOnly); - fileContentReady(file.fileName(), file.readAll()); + if (file.open(QFile::ReadOnly)) + fileContentReady(file.fileName(), file.readAll()); + else + qDebug() << "TrackModel::upload_track: failed to read file!" << path; #endif } diff --git a/nucleus/camera/gesture.h b/nucleus/camera/gesture.h index d3f898e9..1dd03294 100644 --- a/nucleus/camera/gesture.h +++ b/nucleus/camera/gesture.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include #include #include From 65b97aa3169ab129c2751d39d1839ffe1946d19d Mon Sep 17 00:00:00 2001 From: Adam Ce <5292991+adam-ce@users.noreply.github.com> Date: Fri, 31 Oct 2025 21:56:53 +0100 Subject: [PATCH 12/12] fix atmosphere somewhat when zooming far out (there is still atmoshpere from the marching, which is probably also incorrect) --- gl_engine/shaders/compose.frag | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gl_engine/shaders/compose.frag b/gl_engine/shaders/compose.frag index add96b95..851a3d93 100644 --- a/gl_engine/shaders/compose.frag +++ b/gl_engine/shaders/compose.frag @@ -20,6 +20,11 @@ highp float calculate_falloff(highp float dist, highp float from, highp float to return clamp(1.0 - (dist - from) / (to - from), 0.0, 1.0); } +highp float calculate_atmospheric_falloff(highp float dist, highp float camera_cos, highp float from, highp float to) { + // return clamp(1.0 - (dist - from) / (to - from), 0.0, 1.0); + return clamp(1.0 - (dist - from) / (to - from), camera_cos, 1.0); +} + #include "atmosphere_implementation.glsl" #include "encoder.glsl" #include "shared_config.glsl" @@ -157,7 +162,6 @@ void main() { highp float dist = pos_dist.w; // negative if sky // Alpha-Value for Tile-Overlay (distant linear falloff) lowp float alpha = 0.0; - if (dist > 0.0) alpha = calculate_falloff(dist, 300000.0, 600000.0); highp vec3 normal = octNormalDecode2u16(texture(texin_normal, texcoords).xy); @@ -174,8 +178,8 @@ void main() { highp vec3 pos_ws = pos_cws + origin; highp vec3 ray_direction = pos_cws / dist; highp vec4 material_light_response = conf.material_light_response; + alpha = calculate_atmospheric_falloff(dist, -ray_direction.z, 300000.0, 600000.0); - highp vec3 light_through_atmosphere = calculate_atmospheric_light(origin / 1000.0, ray_direction, dist / 1000.0, albedo, 10); highp float shadow_term = 0.0; if (bool(conf.csm_enabled)) {