diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..d6bbf8031 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# .editorconfig +root = true + +# Apply only to C++ source and header files +[*.{cpp,hpp,h,cc,cxx}] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true +end_of_line = lf +max_line_length = 120 diff --git a/.gitignore b/.gitignore index 3b4cd44f5..3d5e92294 100644 --- a/.gitignore +++ b/.gitignore @@ -158,7 +158,6 @@ AutoTest.Net/ # Installshield output folder [Ee]xpress/ - # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT @@ -358,3 +357,9 @@ install.json # mkdocs output site/ + +# clangd compile commands +compile_commands.json + +# gdb config +.gdbinit diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ba46db6c9..852120cd0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,3 @@ # Contributing -See https://aui-framework.github.io/develop/md_docs_2Contributing_01to_01AUI.html +See https://aui-framework.github.io/develop/contributing/?h=contrib diff --git a/aui.core/CMakeLists.txt b/aui.core/CMakeLists.txt index 0f95fdcca..a0655454c 100644 --- a/aui.core/CMakeLists.txt +++ b/aui.core/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.16) option(AUI_CATCH_UNHANDLED "Catch segfault" ON) option(AUI_COROUTINES "Use C++20 coroutines" OFF) option(AUI_ENABLE_ASAN "Enable AddressSanitizer" OFF) +option(AUI_ENABLE_UBSAN "Enable UndefinedBehaviourSanitizer" OFF) option(AUI_ENABLE_DEATH_TESTS "Enable GTest death tests" ON) aui_module(aui.core EXPORT aui) @@ -194,6 +195,12 @@ if (AUI_ENABLE_ASAN) target_link_options(aui.core PUBLIC -fsanitize=address) endif() +if (AUI_ENABLE_UBSAN) + message(STATUS "AUI_ENABLE_UBSAN=${AUI_ENABLE_UBSAN}") + target_compile_options(aui.core PUBLIC -fsanitize=undefined) + target_link_options(aui.core PUBLIC -fsanitize=undefined) +endif() + if(MSVC) target_compile_options(aui.core PUBLIC /bigobj) endif() diff --git a/aui.core/src/AUI/Common/AMap.h b/aui.core/src/AUI/Common/AMap.h index 96711a1e1..fceca837c 100644 --- a/aui.core/src/AUI/Common/AMap.h +++ b/aui.core/src/AUI/Common/AMap.h @@ -12,7 +12,6 @@ #pragma once #include #include -#include "AUI/Core.h" #include "AException.h" #include #include @@ -59,19 +58,19 @@ class ABaseMap: public Parent private: iterator mIterator; bool mValid; - + public: contains_iterator(const iterator& p, bool valid): mIterator(p), mValid(valid) { - + } contains_iterator(const contains_iterator& c): mIterator(c.mIterator), mValid(c.mValid) { - + } operator bool() const noexcept { @@ -259,4 +258,4 @@ inline auto aui::container::to_unordered_map(Iterator begin, result[std::move(key)] = std::move(value); } return result; -} \ No newline at end of file +} diff --git a/aui.core/src/AUI/Common/AString.h b/aui.core/src/AUI/Common/AString.h index 2044ebf77..f43af840b 100644 --- a/aui.core/src/AUI/Common/AString.h +++ b/aui.core/src/AUI/Common/AString.h @@ -11,7 +11,6 @@ #pragma once -#include #include #include #include @@ -20,9 +19,7 @@ #include #include #include -#include #include -#include #include #if AUI_PLATFORM_ANDROID #include @@ -288,7 +285,7 @@ class API_AUI_CORE AString: public std::string { AString(AChar c); AString(size_type n, AChar c); - + AString(size_type n, char32_t c) : AString(n, AChar(c)) {} AString(size_type n, char16_t c) : AString(n, AChar(c)) {} diff --git a/aui.uitests/src/AUI/Test/UI/UITestCase.cpp b/aui.uitests/src/AUI/Test/UI/UITestCase.cpp index 92b9b888d..7caac1078 100644 --- a/aui.uitests/src/AUI/Test/UI/UITestCase.cpp +++ b/aui.uitests/src/AUI/Test/UI/UITestCase.cpp @@ -48,6 +48,7 @@ class MyListener: public ::testing::EmptyTestEventListener { for (auto& v: matcher->toSet()) { AWindow::current()->getRenderingContext()->renderer().rectangleBorder(ASolidBrush{0xaae00000_argb}, v->getPositionInWindow() - glm::ivec2{1, 1}, + v->getZIndex(), v->getSize() + glm::ivec2{2, 2}); } } diff --git a/aui.views/CMakeLists.txt b/aui.views/CMakeLists.txt index 310408c62..0a124463c 100644 --- a/aui.views/CMakeLists.txt +++ b/aui.views/CMakeLists.txt @@ -74,22 +74,22 @@ if (OPENGL_FOUND OR ANDROID OR IOS) aui_compile_assets(aui.views EXCLUDE uni/font/Roboto.ttf) endif () - auisl_shader(aui.views basic.vsh) - auisl_shader(aui.views basic_uv.vsh) - auisl_shader(aui.views shadow.fsh) - auisl_shader(aui.views shadow_inner.fsh) - auisl_shader(aui.views rect_solid.fsh) - auisl_shader(aui.views rect_solid_rounded.fsh) - auisl_shader(aui.views rect_textured.fsh) - auisl_shader(aui.views rect_unblend.fsh) - auisl_shader(aui.views rect_gradient.fsh) - auisl_shader(aui.views rect_gradient_rounded.fsh) - auisl_shader(aui.views border_rounded.fsh) - auisl_shader(aui.views symbol.vsh) - auisl_shader(aui.views symbol.fsh) - auisl_shader(aui.views symbol_sub.fsh) - auisl_shader(aui.views square_sector.fsh) - auisl_shader(aui.views line_solid_dashed.fsh) + # auisl_shader(aui.views basic.vsh) + # auisl_shader(aui.views basic_uv.vsh) + # auisl_shader(aui.views shadow.fsh) + # auisl_shader(aui.views shadow_inner.fsh) + # auisl_shader(aui.views rect_solid.fsh) + # auisl_shader(aui.views rect_solid_rounded.fsh) + # auisl_shader(aui.views rect_textured.fsh) + # auisl_shader(aui.views rect_unblend.fsh) + # auisl_shader(aui.views rect_gradient.fsh) + # auisl_shader(aui.views rect_gradient_rounded.fsh) + # auisl_shader(aui.views border_rounded.fsh) + # auisl_shader(aui.views symbol.vsh) + # auisl_shader(aui.views symbol.fsh) + # auisl_shader(aui.views symbol_sub.fsh) + # auisl_shader(aui.views square_sector.fsh) + # auisl_shader(aui.views line_solid_dashed.fsh) target_compile_definitions(aui.views PRIVATE $<$,$>:UNICODE=1> @@ -153,4 +153,4 @@ if (OPENGL_FOUND OR ANDROID OR IOS) endif () else () message("OpenGL library was not found. Disabling aui.views") -endif () \ No newline at end of file +endif () diff --git a/aui.views/shaders/basic.vsh b/aui.views/shaders/basic.vsh deleted file mode 100644 index f9bd046a5..000000000 --- a/aui.views/shaders/basic.vsh +++ /dev/null @@ -1,10 +0,0 @@ -input { - [0] vec2 pos -} -uniform { - mat4 transform -} - -entry { - sl_position = uniform.transform * vec4(input.pos, 0, 1) -} \ No newline at end of file diff --git a/aui.views/shaders/basic_gradient.vert b/aui.views/shaders/basic_gradient.vert new file mode 100644 index 000000000..97aa03eed --- /dev/null +++ b/aui.views/shaders/basic_gradient.vert @@ -0,0 +1,23 @@ +#version 300 es + +precision highp float; + +layout(location = 0) in vec4 pos; +layout(location = 1) in vec4 color_start; +layout(location = 2) in vec4 color_end; +layout(location = 3) in float rotation; + +flat out vec4 vColorStart; +flat out vec4 vColorEnd; +out float vT; + +void main() { + gl_Position = pos; + + vec2 dir = vec2(cos(rotation), sin(rotation)); + + vT = dot(pos.xy, dir); + + vColorStart = color_start; + vColorEnd = color_end; +} diff --git a/aui.views/shaders/basic_solid.vert b/aui.views/shaders/basic_solid.vert new file mode 100644 index 000000000..09f9060c8 --- /dev/null +++ b/aui.views/shaders/basic_solid.vert @@ -0,0 +1,12 @@ +#version 300 es + +precision highp float; + +layout(location = 0) in vec4 pos; +layout(location = 1) in vec4 color; +flat out vec4 vertexColor; + +void main() { + gl_Position = vec4(pos); + vertexColor = color; +} diff --git a/aui.views/shaders/basic_uv.vsh b/aui.views/shaders/basic_uv.vsh index 2c6d7edc2..ec1200858 100644 --- a/aui.views/shaders/basic_uv.vsh +++ b/aui.views/shaders/basic_uv.vsh @@ -1,7 +1,3 @@ -uniform { - mat4 transform -} - input { [0] vec4 pos [1] vec2 uv @@ -12,7 +8,7 @@ inter { } entry { - sl_position = uniform.transform * vec4(input.pos.xy, 0, 1) + sl_position = vec4(input.pos.xyz, 1) inter.vertex = input.pos inter.uv = input.uv -} \ No newline at end of file +} diff --git a/aui.views/shaders/gradient.frag b/aui.views/shaders/gradient.frag new file mode 100644 index 000000000..7a8954469 --- /dev/null +++ b/aui.views/shaders/gradient.frag @@ -0,0 +1,13 @@ +#version 300 es +precision highp float; + +flat in vec4 vColorStart; +flat in vec4 vColorEnd; +in float vT; + +out vec4 fragColor; + +void main() { + float t = clamp(vT * 0.5 + 0.5, 0.0, 1.0); + fragColor = mix(vColorStart, vColorEnd, t); +} diff --git a/aui.views/shaders/solid.frag b/aui.views/shaders/solid.frag new file mode 100644 index 000000000..f57bacc81 --- /dev/null +++ b/aui.views/shaders/solid.frag @@ -0,0 +1,10 @@ +#version 300 es + +precision highp float; + +flat in vec4 vertexColor; +out vec4 fragColor; + +void main() { + fragColor = vertexColor; +} diff --git a/aui.views/shaders_legacy/basic.vsh b/aui.views/shaders_legacy/basic.vsh new file mode 100644 index 000000000..80d1dcdd6 --- /dev/null +++ b/aui.views/shaders_legacy/basic.vsh @@ -0,0 +1,7 @@ +input { + [0] vec3 pos +} + +entry { + sl_position = vec4(input.pos.xyz, 1) +} diff --git a/aui.views/shaders_legacy/basic_uv.vsh b/aui.views/shaders_legacy/basic_uv.vsh new file mode 100644 index 000000000..ec1200858 --- /dev/null +++ b/aui.views/shaders_legacy/basic_uv.vsh @@ -0,0 +1,14 @@ +input { + [0] vec4 pos + [1] vec2 uv +} +inter { + vec4 vertex + vec2 uv +} + +entry { + sl_position = vec4(input.pos.xyz, 1) + inter.vertex = input.pos + inter.uv = input.uv +} diff --git a/aui.views/shaders_legacy/border_rounded.fsh b/aui.views/shaders_legacy/border_rounded.fsh new file mode 100644 index 000000000..073aabcd1 --- /dev/null +++ b/aui.views/shaders_legacy/border_rounded.fsh @@ -0,0 +1,22 @@ +import rounded + +uniform { + vec4 color + vec2 innerSize + vec2 outerToInner + vec2 outerSize +} + +inter { + vec2 uv +} + +output { + [0] vec4 albedo +} + +entry { + vec2 absolute = abs(inter.uv * 2 - 1) + output.albedo = uniform.color * vec4(1, 1, 1, rounded(absolute, uniform.outerSize) - rounded(absolute * uniform.outerToInner, uniform.innerSize)) +#flag glsl120 if (gl_FragColor.a < 0.1) discard; +} diff --git a/aui.views/shaders_legacy/dashed.sl b/aui.views/shaders_legacy/dashed.sl new file mode 100644 index 000000000..6c4427126 --- /dev/null +++ b/aui.views/shaders_legacy/dashed.sl @@ -0,0 +1,8 @@ +uniform { + float divider + float threshold +} + +float dashed(float distance) { + return step(mod(distance, uniform.divider), uniform.threshold); +} \ No newline at end of file diff --git a/aui.views/shaders/gradient.sl b/aui.views/shaders_legacy/gradient.sl similarity index 100% rename from aui.views/shaders/gradient.sl rename to aui.views/shaders_legacy/gradient.sl diff --git a/aui.views/shaders/gradient_textured.sl b/aui.views/shaders_legacy/gradient_textured.sl similarity index 100% rename from aui.views/shaders/gradient_textured.sl rename to aui.views/shaders_legacy/gradient_textured.sl diff --git a/aui.views/shaders_legacy/line_solid_dashed.fsh b/aui.views/shaders_legacy/line_solid_dashed.fsh new file mode 100644 index 000000000..983862fb9 --- /dev/null +++ b/aui.views/shaders_legacy/line_solid_dashed.fsh @@ -0,0 +1,17 @@ +import dashed + +uniform { + vec4 color +} + +inter { + vec4 vertex +} + +output { + [0] vec4 albedo +} + +entry { + output.albedo = uniform.color * dashed(inter.vertex.z) +} \ No newline at end of file diff --git a/aui.views/shaders/rect_gradient.fsh b/aui.views/shaders_legacy/rect_gradient.fsh similarity index 100% rename from aui.views/shaders/rect_gradient.fsh rename to aui.views/shaders_legacy/rect_gradient.fsh diff --git a/aui.views/shaders_legacy/rect_gradient_rounded.fsh b/aui.views/shaders_legacy/rect_gradient_rounded.fsh new file mode 100644 index 000000000..e43949eeb --- /dev/null +++ b/aui.views/shaders_legacy/rect_gradient_rounded.fsh @@ -0,0 +1,20 @@ +import gradient +import rounded + +inter { + vec2 uv +} + +uniform { + vec4 color + vec2 outerSize +} + +output { + [0] vec4 albedo +} + +entry { + output.albedo = uniform.color * gradient(inter.uv) * vec4(1, 1, 1, rounded(abs(inter.uv * 2 - 1), uniform.outerSize)) +#flag glsl120 if (gl_FragColor.a < 0.1) discard; +} diff --git a/aui.views/shaders/rect_solid.fsh b/aui.views/shaders_legacy/rect_solid.fsh similarity index 100% rename from aui.views/shaders/rect_solid.fsh rename to aui.views/shaders_legacy/rect_solid.fsh diff --git a/aui.views/shaders_legacy/rect_solid_rounded.fsh b/aui.views/shaders_legacy/rect_solid_rounded.fsh new file mode 100644 index 000000000..fad9ca193 --- /dev/null +++ b/aui.views/shaders_legacy/rect_solid_rounded.fsh @@ -0,0 +1,19 @@ +import rounded + +uniform { + vec4 color + vec2 outerSize +} + +inter { + vec2 uv +} + +output { + [0] vec4 albedo +} + +entry { + output.albedo = uniform.color * vec4(1, 1, 1, rounded(abs(inter.uv * 2 - 1), uniform.outerSize)) +#flag glsl120 if (gl_FragColor.a < 0.1) discard; +} diff --git a/aui.views/shaders_legacy/rect_textured.fsh b/aui.views/shaders_legacy/rect_textured.fsh new file mode 100644 index 000000000..95d698ad2 --- /dev/null +++ b/aui.views/shaders_legacy/rect_textured.fsh @@ -0,0 +1,16 @@ +uniform { + vec4 color + 2D albedo +} + +inter { + vec2 uv +} + +output { + [0] vec4 albedo +} + +entry { + output.albedo = uniform.color * uniform.albedo[inter.uv] +} diff --git a/aui.views/shaders_legacy/rect_unblend.fsh b/aui.views/shaders_legacy/rect_unblend.fsh new file mode 100644 index 000000000..50bfc8002 --- /dev/null +++ b/aui.views/shaders_legacy/rect_unblend.fsh @@ -0,0 +1,18 @@ +uniform { + vec4 color + 2D albedo +} + +inter { + vec2 uv +} + +output { + [0] vec4 albedo +} + +entry { + vec4 unblend = uniform.albedo[inter.uv] + unblend.xyz = unblend.xyz / unblend.a + output.albedo = uniform.color * unblend +} diff --git a/aui.views/shaders_legacy/rounded.sl b/aui.views/shaders_legacy/rounded.sl new file mode 100644 index 000000000..6b73db4aa --- /dev/null +++ b/aui.views/shaders_legacy/rounded.sl @@ -0,0 +1,11 @@ +float rounded(vec2 absolute, vec2 size) { + vec2 circleCenter = 1.0 - size; + vec2 rectangleShape = step(absolute, circleCenter) + + vec2 circle = (absolute - circleCenter) / (size); + float circles = step(circle.x * circle.x + circle.y * circle.y, 1.0) + + vec2 rectCut = step(vec2(0), vec2(1.0) - absolute) + + return clamp(rectangleShape.x + rectangleShape.y + circles, 0, 1) * rectCut.x * rectCut.y +} diff --git a/aui.views/shaders_legacy/shadow.fsh b/aui.views/shaders_legacy/shadow.fsh new file mode 100644 index 000000000..8fcacd748 --- /dev/null +++ b/aui.views/shaders_legacy/shadow.fsh @@ -0,0 +1,33 @@ +uniform { + vec4 color + vec2 lower + vec2 upper + float sigma +} + +output { + [0] vec4 albedo +} + +inter { + vec4 vertex +} + +vec4 erf(vec4 x) { + vec4 s = sign(x) + vec4 a = abs(x) + x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a + x = x * x + return s - s / (x * x) +} + + +entry { + vec4 result = uniform.color + + vec2 v = inter.vertex.xy + vec4 query = vec4(v - vec2(uniform.lower), v - vec2(uniform.upper)) + vec4 integral = 0.5 + 0.5 * erf(query * (sqrt(0.5) / uniform.sigma)) + result.a = result.a * clamp((integral.z - integral.x) * (integral.w - integral.y), 0.0, 1.0) + output.albedo = result +} \ No newline at end of file diff --git a/aui.views/shaders_legacy/shadow_inner.fsh b/aui.views/shaders_legacy/shadow_inner.fsh new file mode 100644 index 000000000..39ef9e7ed --- /dev/null +++ b/aui.views/shaders_legacy/shadow_inner.fsh @@ -0,0 +1,39 @@ +import rounded + +uniform { + vec4 color + vec2 lower + vec2 upper + float sigma + + vec2 outerSize +} + +output { + [0] vec4 albedo +} + +inter { + vec4 vertex + vec2 uv +} + +vec4 erf(vec4 x) { + vec4 s = sign(x) + vec4 a = abs(x) + x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a + x = x * x + return s - s / (x * x) +} + + +entry { + vec4 result = uniform.color + + vec2 v = inter.vertex.xy + vec4 query = vec4(v - vec2(uniform.lower), v - vec2(uniform.upper)) + vec4 integral = 0.5 + 0.5 * erf(query * (sqrt(0.5) / uniform.sigma)) + result.a = result.a * (1 - clamp((integral.z - integral.x) * (integral.w - integral.y), 0.0, 1.0)) + result.a = result.a * rounded(abs(inter.uv * 2 - 1), uniform.outerSize) + output.albedo = result +} \ No newline at end of file diff --git a/aui.views/shaders_legacy/square_sector.fsh b/aui.views/shaders_legacy/square_sector.fsh new file mode 100644 index 000000000..05590dcf8 --- /dev/null +++ b/aui.views/shaders_legacy/square_sector.fsh @@ -0,0 +1,21 @@ +uniform { + mat3 m1 + mat3 m2 + float whichAlgo +} + +inter { + vec2 uv +} + +output { + [0] vec4 albedo +} + +entry { + float m1 = step((uniform.m1 * vec3(inter.uv, 1)).x, 0) + float m2 = step((uniform.m2 * vec3(inter.uv, 1)).x, 0) + output.albedo = vec4(1, 1, 1, mix(m1 * m2, m1 + m2, uniform.whichAlgo)) + + #flag glsl120 if (gl_FragColor.a < 0.1) discard; +} \ No newline at end of file diff --git a/aui.views/shaders_legacy/symbol.fsh b/aui.views/shaders_legacy/symbol.fsh new file mode 100644 index 000000000..2fe2c500e --- /dev/null +++ b/aui.views/shaders_legacy/symbol.fsh @@ -0,0 +1,17 @@ +uniform { + vec4 color + 2D albedo +} + +inter { + vec2 uv +} + +output { + [0] vec4 albedo +} + +entry { + vec4 s = uniform.albedo[inter.uv] + output.albedo = uniform.color * vec4(1, 1, 1, s.x) +} diff --git a/aui.views/shaders_legacy/symbol.vsh b/aui.views/shaders_legacy/symbol.vsh new file mode 100644 index 000000000..1c3b0a295 --- /dev/null +++ b/aui.views/shaders_legacy/symbol.vsh @@ -0,0 +1,17 @@ +uniform { + mat4 transform + float uvScale +} + +input { + [0] vec2 pos + [1] vec2 uv +} +inter { + vec2 uv +} + +entry { + sl_position = uniform.transform * vec4(input.pos, 0, 1) + inter.uv = input.uv * uniform.uvScale +} diff --git a/aui.views/shaders_legacy/symbol_sub.fsh b/aui.views/shaders_legacy/symbol_sub.fsh new file mode 100644 index 000000000..dfbf12beb --- /dev/null +++ b/aui.views/shaders_legacy/symbol_sub.fsh @@ -0,0 +1,18 @@ +uniform { + vec4 color + 2D albedo +} + +inter { + vec2 uv +} + +output { + [0] vec4 albedo +} + +entry { + vec4 s = uniform.albedo[inter.uv] + vec4 c = uniform.color + output.albedo = vec4(c.xyz * s.xyz * c.a, (s.x + s.y + s.z) / 3 * c.a) +} diff --git a/aui.views/src/AUI/ASS/AStylesheet.cpp b/aui.views/src/AUI/ASS/AStylesheet.cpp index aa76bd60e..0ccff524c 100644 --- a/aui.views/src/AUI/ASS/AStylesheet.cpp +++ b/aui.views/src/AUI/ASS/AStylesheet.cpp @@ -144,10 +144,8 @@ AStylesheet::AStylesheet() { button::Default(t()), FontRendering::ANTIALIASING, BackgroundGradient { ALinearGradientBrush{ - .colors = { - {0.f, getOsThemeColorLighter()}, - {0.f, getOsThemeColor()}, - }, + .colorStart = getOsThemeColorLighter(), + .colorEnd = getOsThemeColor() } }, BoxShadow { 0, 1_dp, 3_dp, -1_dp, getOsThemeColor() }, Border { nullptr }, @@ -164,10 +162,8 @@ AStylesheet::AStylesheet() { { button::Default(t::hover()), BackgroundGradient { ALinearGradientBrush{ - .colors = { - {0.f, getOsThemeColorLighter()}, - {1.f, getOsThemeColor()}, - }, + .colorStart = getOsThemeColorLighter(), + .colorEnd = getOsThemeColor() } }, }, { diff --git a/aui.views/src/AUI/ASS/Property/BackgroundGradient.cpp b/aui.views/src/AUI/ASS/Property/BackgroundGradient.cpp index e560d1c44..0d44fc6f9 100644 --- a/aui.views/src/AUI/ASS/Property/BackgroundGradient.cpp +++ b/aui.views/src/AUI/ASS/Property/BackgroundGradient.cpp @@ -24,9 +24,9 @@ void ass::prop::Property::renderFor(AView* view, const RenderHints::PushColor x(ctx.render); if (view->getBorderRadius() > 0) { - ctx.render.roundedRectangle(ABrush(*mInfo.gradient), {0, 0}, view->getSize(), view->getBorderRadius()); + ctx.render.roundedRectangle(ABrush(*mInfo.gradient), {0, 0}, view->getZIndex(), view->getSize(), view->getBorderRadius()); } else { - ctx.render.rectangle(ABrush(*mInfo.gradient), {0, 0}, view->getSize()); + ctx.render.rectangle(ABrush(*mInfo.gradient), {0, 0}, view->getZIndex(), view->getSize()); } IPropertyBase::renderFor(view, ctx); } diff --git a/aui.views/src/AUI/ASS/Property/BackgroundGradient.h b/aui.views/src/AUI/ASS/Property/BackgroundGradient.h index afac98fe3..6c1dfc6f9 100644 --- a/aui.views/src/AUI/ASS/Property/BackgroundGradient.h +++ b/aui.views/src/AUI/ASS/Property/BackgroundGradient.h @@ -17,6 +17,7 @@ #include #include "IProperty.h" +#include namespace ass { /** @@ -30,10 +31,8 @@ namespace ass { BackgroundGradient(ALinearGradientBrush brush) noexcept: gradient(std::move(brush)) {} BackgroundGradient(AColor begin, AColor end, AAngleRadians angle) noexcept: gradient(ALinearGradientBrush{ - .colors = { - {0.f, begin}, - {1.f, end}, - }, + .colorStart = begin, + .colorEnd = end, .rotation = angle }) {} BackgroundGradient(AColor begin, AColor end, ALayoutDirection direction) noexcept: BackgroundGradient(begin, end, direction == ALayoutDirection::VERTICAL ? 180_deg : 90_deg) {} @@ -62,4 +61,4 @@ namespace ass { }; } -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/ASS/Property/BackgroundImage.cpp b/aui.views/src/AUI/ASS/Property/BackgroundImage.cpp index 0988505bf..42f350e96 100644 --- a/aui.views/src/AUI/ASS/Property/BackgroundImage.cpp +++ b/aui.views/src/AUI/ASS/Property/BackgroundImage.cpp @@ -252,7 +252,7 @@ void ass::prop::Property::draw( glm::translate(glm::mat4(1.f), glm::vec3 { glm::vec2(viewSize - imageSize) / 2.f, 0.f })); RenderHints::PushMask mask(ctx.render, [&] { - ctx.render.rectangle(ASolidBrush {}, { 0, 0 }, view->getSize()); + ctx.render.rectangle(ASolidBrush {}, { 0, 0 }, view->getZIndex(), view->getSize()); }); drawableDrawWrapper(imageSize); @@ -260,7 +260,7 @@ void ass::prop::Property::draw( } case Sizing::NONE: { RenderHints::PushMask mask(ctx.render, [&] { - ctx.render.rectangle(ASolidBrush {}, { 0, 0 }, view->getSize()); + ctx.render.rectangle(ASolidBrush {}, { 0, 0 }, view->getZIndex(), view->getSize()); }); glm::vec2 imageSize = glm::vec2(drawable->getSizeHint()); diff --git a/aui.views/src/AUI/ASS/Property/BackgroundSolid.cpp b/aui.views/src/AUI/ASS/Property/BackgroundSolid.cpp index f01917828..9e95d4b58 100644 --- a/aui.views/src/AUI/ASS/Property/BackgroundSolid.cpp +++ b/aui.views/src/AUI/ASS/Property/BackgroundSolid.cpp @@ -23,11 +23,13 @@ void ass::prop::Property::renderFor(AView* view, const ARe if (view->getBorderRadius() > 0) { ctx.render.roundedRectangle(brush, {0, 0}, + view->getZIndex(), view->getSize(), view->getBorderRadius()); } else { ctx.render.rectangle(brush, {0, 0}, + view->getZIndex(), view->getSize()); } diff --git a/aui.views/src/AUI/ASS/Property/Border.cpp b/aui.views/src/AUI/ASS/Property/Border.cpp index 5946a809e..09e2bc996 100644 --- a/aui.views/src/AUI/ASS/Property/Border.cpp +++ b/aui.views/src/AUI/ASS/Property/Border.cpp @@ -29,6 +29,7 @@ void ass::prop::Property::renderFor(AView* view, const ARenderConte */ ctx.render.roundedRectangleBorder(ASolidBrush{mInfo.color}, {0, 0}, + view->getZIndex(), view->getSize(), view->getBorderRadius(), mInfo.width); @@ -41,4 +42,4 @@ bool ass::prop::Property::isNone() { ass::prop::PropertySlot ass::prop::Property::getPropertySlot() const { return ass::prop::PropertySlot::BORDER; -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/ASS/Property/BorderBottom.cpp b/aui.views/src/AUI/ASS/Property/BorderBottom.cpp index 6bf89364a..ede842f40 100644 --- a/aui.views/src/AUI/ASS/Property/BorderBottom.cpp +++ b/aui.views/src/AUI/ASS/Property/BorderBottom.cpp @@ -21,6 +21,7 @@ void ass::prop::Property::renderFor(AView* view, const ARende int w = mInfo.width; ctx.render.rectangle(ASolidBrush{mInfo.color}, {0, view->getHeight() - w}, + view->getZIndex(), {view->getWidth(), w}); } @@ -30,4 +31,4 @@ bool ass::prop::Property::isNone() { ass::prop::PropertySlot ass::prop::Property::getPropertySlot() const { return ass::prop::PropertySlot::BORDER; -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/ASS/Property/BorderLeft.cpp b/aui.views/src/AUI/ASS/Property/BorderLeft.cpp index 99a3a3f40..a691a77f7 100644 --- a/aui.views/src/AUI/ASS/Property/BorderLeft.cpp +++ b/aui.views/src/AUI/ASS/Property/BorderLeft.cpp @@ -22,6 +22,7 @@ void ass::prop::Property::renderFor(AView* view, const ARenderC ctx.render.rectangle(ASolidBrush{mInfo.color}, {0, 0}, + view->getZIndex(), {w, view->getHeight()}); } @@ -32,4 +33,4 @@ bool ass::prop::Property::isNone() { ass::prop::PropertySlot ass::prop::Property::getPropertySlot() const { return ass::prop::PropertySlot::BORDER; -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/ASS/Property/BorderRight.cpp b/aui.views/src/AUI/ASS/Property/BorderRight.cpp index 075fd8a98..8d4f719ea 100644 --- a/aui.views/src/AUI/ASS/Property/BorderRight.cpp +++ b/aui.views/src/AUI/ASS/Property/BorderRight.cpp @@ -18,6 +18,7 @@ void ass::prop::Property::renderFor(AView* view, const ARender ctx.render.rectangle(ASolidBrush{mInfo.color}, {view->getWidth() - w, 0}, + view->getZIndex(), {w, view->getHeight()}); } @@ -28,4 +29,4 @@ bool ass::prop::Property::isNone() { ass::prop::PropertySlot ass::prop::Property::getPropertySlot() const { return ass::prop::PropertySlot::BORDER; -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/ASS/Property/BorderTop.cpp b/aui.views/src/AUI/ASS/Property/BorderTop.cpp index e576a06df..049ec6092 100644 --- a/aui.views/src/AUI/ASS/Property/BorderTop.cpp +++ b/aui.views/src/AUI/ASS/Property/BorderTop.cpp @@ -17,6 +17,7 @@ void ass::prop::Property::renderFor(AView* view, const ARenderCo int w = mInfo.width; ctx.render.rectangle(ASolidBrush{mInfo.color}, {0, 0}, + view->getZIndex(), {view->getWidth(), w}); } @@ -26,4 +27,4 @@ bool ass::prop::Property::isNone() { ass::prop::PropertySlot ass::prop::Property::getPropertySlot() const { return ass::prop::PropertySlot::BORDER; -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/ASS/Property/BoxShadow.cpp b/aui.views/src/AUI/ASS/Property/BoxShadow.cpp index 6f6e200f8..066de9bcb 100644 --- a/aui.views/src/AUI/ASS/Property/BoxShadow.cpp +++ b/aui.views/src/AUI/ASS/Property/BoxShadow.cpp @@ -20,6 +20,7 @@ void ass::prop::Property::renderFor(AView* view, const ARenderContext& ctx) { ctx.render.boxShadow({mInfo.offsetX.getValuePx() - mInfo.spreadRadius.getValuePx(), mInfo.offsetY.getValuePx() - mInfo.spreadRadius.getValuePx()}, + view->getZIndex(), glm::vec2(view->getSize()) + mInfo.spreadRadius.getValuePx() * 2.f, mInfo.blurRadius, mInfo.color); diff --git a/aui.views/src/AUI/ASS/Property/BoxShadowInner.cpp b/aui.views/src/AUI/ASS/Property/BoxShadowInner.cpp index c6543db9d..2c0405674 100644 --- a/aui.views/src/AUI/ASS/Property/BoxShadowInner.cpp +++ b/aui.views/src/AUI/ASS/Property/BoxShadowInner.cpp @@ -19,6 +19,7 @@ void ass::prop::Property::renderFor(AView* view, const ARenderContext& ctx) { ctx.render.boxShadowInner({0, 0}, + view->getZIndex(), glm::vec2(view->getSize()), mInfo.blurRadius, mInfo.spreadRadius, @@ -33,4 +34,4 @@ ass::prop::PropertySlot ass::prop::Property::getPropertySlo bool ass::prop::Property::isNone() { return mInfo.color.isFullyTransparent(); -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/Animator/AFocusAnimator.cpp b/aui.views/src/AUI/Animator/AFocusAnimator.cpp index 0eb507c3b..ac94812bf 100644 --- a/aui.views/src/AUI/Animator/AFocusAnimator.cpp +++ b/aui.views/src/AUI/Animator/AFocusAnimator.cpp @@ -29,6 +29,7 @@ void AFocusAnimator::doAnimation(AView* view, float theta, IRenderer& render) { render.rectangleBorder( ASolidBrush{{0, 0, 0, t}}, {-t * SIZE, -t * SIZE}, + view->getZIndex(), {t * SIZE * 2 + view->getWidth(), t * SIZE * 2 + view->getHeight()}, 2.f); } diff --git a/aui.views/src/AUI/Devtools/DevtoolsPerformanceTab.cpp b/aui.views/src/AUI/Devtools/DevtoolsPerformanceTab.cpp index 1f90446fa..5fcb2e2b3 100644 --- a/aui.views/src/AUI/Devtools/DevtoolsPerformanceTab.cpp +++ b/aui.views/src/AUI/Devtools/DevtoolsPerformanceTab.cpp @@ -73,18 +73,18 @@ namespace { ctx.render.rectangle(ATexturedBrush { .texture = mTexture, .imageRendering = ImageRendering::PIXELATED, - }, {0, 0}, mImage.size() * plotScale()); + }, {0, 0}, mZIndex, mImage.size() * plotScale()); if (!mSelectionMode) { return; } if (mHoveredFrameIndex && !mSelectedFrameIndex) { - ctx.render.rectangle(ASolidBrush {AColor::WHITE.transparentize(0.6f) }, {*mHoveredFrameIndex * plotScale(), 0}, {plotScale(), getSize().y}); + ctx.render.rectangle(ASolidBrush {AColor::WHITE.transparentize(0.6f) }, {*mHoveredFrameIndex * plotScale(), 0}, mZIndex, {plotScale(), getSize().y}); } if (mSelectedFrameIndex) { - ctx.render.rectangle(ASolidBrush {AColor::WHITE.transparentize(0.5f) }, {*mSelectedFrameIndex * plotScale(), 0}, {plotScale(), getSize().y}); + ctx.render.rectangle(ASolidBrush {AColor::WHITE.transparentize(0.5f) }, {*mSelectedFrameIndex * plotScale(), 0}, mZIndex, {plotScale(), getSize().y}); } } @@ -327,7 +327,7 @@ DevtoolsPerformanceTab::DevtoolsPerformanceTab(AWindowBase* targetWindow) : mTar lastTimeUpdated = now; treeView->onPerformanceFrame(sections); - }); + }); connect(graphView->selectionChanged, AUI_SLOT(treeView)::onPerformanceFrame); connect(mState, [=](const State& state) { @@ -384,7 +384,7 @@ DevtoolsPerformanceTab::DevtoolsPerformanceTab(AWindowBase* targetWindow) : mTar }, }, }, - }); + }); #else setContents(Centered { Label { "Please set -DAUI_PROFILING=TRUE in CMake configure." } diff --git a/aui.views/src/AUI/Devtools/DevtoolsThreadsTab.cpp b/aui.views/src/AUI/Devtools/DevtoolsThreadsTab.cpp index c2f0115b4..0d4ac1447 100644 --- a/aui.views/src/AUI/Devtools/DevtoolsThreadsTab.cpp +++ b/aui.views/src/AUI/Devtools/DevtoolsThreadsTab.cpp @@ -74,7 +74,7 @@ class WatcherView : public ALabel { color = 0xff0000_rgb; paint: - ctx.render.rectangle(ASolidBrush { color }, { 0, 0 }, getSize()); + ctx.render.rectangle(ASolidBrush { color }, { 0, 0 }, mZIndex, getSize()); } }; } // namespace diff --git a/aui.views/src/AUI/GL/IBatchingRenderer.cpp b/aui.views/src/AUI/GL/IBatchingRenderer.cpp index 663019380..9898f1373 100644 --- a/aui.views/src/AUI/GL/IBatchingRenderer.cpp +++ b/aui.views/src/AUI/GL/IBatchingRenderer.cpp @@ -13,52 +13,57 @@ #include "IBatchingRenderer.h" -void IBatchingRenderer::rectangle(const ABrush& brush, glm::vec2 position, glm::vec2 size) { +void IBatchingRenderer::rectangle(const ABrush& brush, glm::vec2 position, zIndex_t zIndex, glm::vec2 size) { enqueueCommand(CmdRectangle { - .brush = std::move(brush), - .position = position, - .size = size, + .brush = std::move(brush), + .position = position, + .size = size, + .zIndex = zIndex }); } -void IBatchingRenderer::roundedRectangle(const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius) { +void IBatchingRenderer::roundedRectangle(const ABrush& brush, glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float radius) { enqueueCommand(CmdRoundedRectangle{ .brush = brush, .position = position, .size = size, .radius = radius, + .zIndex = zIndex }); } -void IBatchingRenderer::rectangleBorder(const ABrush& brush, glm::vec2 position, glm::vec2 size, float lineWidth) { +void IBatchingRenderer::rectangleBorder(const ABrush& brush, glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float lineWidth) { enqueueCommand(CmdRectangleBorder{ .brush = brush, .position = position, .size = size, .lineWidth = lineWidth, + .zIndex = zIndex }); } -void IBatchingRenderer::roundedRectangleBorder(const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius, int borderWidth) { +void IBatchingRenderer::roundedRectangleBorder(const ABrush& brush, glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float radius, int borderWidth) { enqueueCommand(CmdRoundedRectangleBorder{ .brush = brush, .position = position, .size = size, .radius = radius, .borderWidth = borderWidth, + .zIndex = zIndex }); } -void IBatchingRenderer::boxShadow(glm::vec2 position, glm::vec2 size, float blurRadius, const AColor& color) { +void IBatchingRenderer::boxShadow(glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float blurRadius, const AColor& color) { enqueueCommand(CmdBoxShadow{ .position = position, .size = size, .blurRadius = blurRadius, .color = color, + .zIndex = zIndex }); } -void IBatchingRenderer::boxShadowInner(glm::vec2 position, glm::vec2 size, float blurRadius, float spreadRadius, float borderRadius, const AColor& color, glm::vec2 offset) { +void IBatchingRenderer::boxShadowInner(glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float blurRadius, float spreadRadius, float borderRadius, const AColor& color, glm::vec2 offset) { enqueueCommand(CmdBoxShadowInner{ .position = position, .size = size, @@ -67,6 +72,7 @@ void IBatchingRenderer::boxShadowInner(glm::vec2 position, glm::vec2 size, float .borderRadius = borderRadius, .color = color, .offset = offset, + .zIndex = zIndex }); } @@ -116,23 +122,23 @@ void IBatchingRenderer::squareSector(const ABrush& brush, const glm::vec2& posit } void IBatchingRenderer::pushMaskBefore() { - enqueueCommand(CmdPushMaskBefore{}); + // TODO: move to cmds } void IBatchingRenderer::pushMaskAfter() { - enqueueCommand(CmdPushMaskAfter{}); + // TODO: move to cmds } void IBatchingRenderer::popMaskBefore() { - enqueueCommand(CmdPopMaskBefore{}); + // TODO: move to cmds } void IBatchingRenderer::popMaskAfter() { - enqueueCommand(CmdPopMaskAfter{}); + // TODO: move to cmds } void IBatchingRenderer::setBlending(Blending blending) { - enqueueCommand(CmdSetBlending{.blending = blending}); + // TODO: move to cmds } void IBatchingRenderer::flush() { diff --git a/aui.views/src/AUI/GL/IBatchingRenderer.h b/aui.views/src/AUI/GL/IBatchingRenderer.h index 57b855c6a..c8b73600a 100644 --- a/aui.views/src/AUI/GL/IBatchingRenderer.h +++ b/aui.views/src/AUI/GL/IBatchingRenderer.h @@ -9,26 +9,30 @@ #pragma once +#include #include "AUI/Render/IRenderer.h" class IBatchingRenderer : public IRenderer { public: - struct CmdRectangle { + struct CmdRectangle { ABrush brush; glm::vec2 position; glm::vec2 size; + zIndex_t zIndex; }; struct CmdRoundedRectangle { ABrush brush; glm::vec2 position; glm::vec2 size; float radius; + zIndex_t zIndex; }; struct CmdRectangleBorder { ABrush brush; glm::vec2 position; glm::vec2 size; float lineWidth; + zIndex_t zIndex; }; struct CmdRoundedRectangleBorder { ABrush brush; @@ -36,12 +40,14 @@ class IBatchingRenderer : public IRenderer { glm::vec2 size; float radius; int borderWidth; + zIndex_t zIndex; }; struct CmdBoxShadow { glm::vec2 position; glm::vec2 size; float blurRadius; AColor color; + zIndex_t zIndex; }; struct CmdBoxShadowInner { glm::vec2 position; @@ -51,6 +57,7 @@ class IBatchingRenderer : public IRenderer { float borderRadius; AColor color; glm::vec2 offset; + zIndex_t zIndex; }; struct CmdString { glm::vec2 position; @@ -81,36 +88,39 @@ class IBatchingRenderer : public IRenderer { AAngleRadians begin; AAngleRadians end; }; - struct CmdPushMaskBefore {}; - struct CmdPushMaskAfter {}; - struct CmdPopMaskBefore {}; - struct CmdPopMaskAfter {}; - struct CmdSetBlending { - Blending blending; - }; struct CmdNewRenderViewToTexture {}; struct CmdSetWindow { AWindowBase* window; }; + using BatchId_t = uint32_t; + struct BatchId { + BatchId_t value; + BatchId() : value{std::numeric_limits::max()} {}; + BatchId(int16_t z, uint8_t cmd, uint8_t brush) { + value = (static_cast(z) << 16) | (static_cast(cmd) << 8) | static_cast(brush); + } + auto operator<=>(const BatchId&) const = default; + }; struct Cmd { glm::mat4 transform; AColor color; using Arg = std::variant< CmdRectangle, CmdRoundedRectangle, CmdRectangleBorder, CmdRoundedRectangleBorder, CmdBoxShadow, - CmdBoxShadowInner, CmdString, CmdLines, CmdPoints, CmdLinesPairs, CmdSquareSector, CmdPushMaskBefore, CmdPushMaskAfter, CmdPopMaskBefore, CmdPopMaskAfter, - CmdSetBlending, CmdNewRenderViewToTexture, CmdSetWindow>; + CmdBoxShadowInner, CmdString, CmdLines, CmdPoints, CmdLinesPairs, CmdSquareSector, + CmdNewRenderViewToTexture, CmdSetWindow>; Arg arg; + BatchId batchId; }; ~IBatchingRenderer() override = default; - void rectangle(const ABrush& brush, glm::vec2 position, glm::vec2 size) override; - void roundedRectangle(const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius) override; - void rectangleBorder(const ABrush& brush, glm::vec2 position, glm::vec2 size, float lineWidth) override; + void rectangle(const ABrush& brush, glm::vec2 position, zIndex_t zIndex, glm::vec2 size) override; + void roundedRectangle(const ABrush& brush, glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float radius) override; + void rectangleBorder(const ABrush& brush, glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float lineWidth) override; void roundedRectangleBorder( - const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius, int borderWidth) override; - void boxShadow(glm::vec2 position, glm::vec2 size, float blurRadius, const AColor& color) override; + const ABrush& brush, glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float radius, int borderWidth) override; + void boxShadow(glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float blurRadius, const AColor& color) override; void boxShadowInner( - glm::vec2 position, glm::vec2 size, float blurRadius, float spreadRadius, float borderRadius, + glm::vec2 position, zIndex_t zIndex, glm::vec2 size, float blurRadius, float spreadRadius, float borderRadius, const AColor& color, glm::vec2 offset) override; void string(glm::vec2 position, const AString& string, const AFontStyle& fs) override; void lines(const ABrush& brush, AArrayView points, const ABorderStyle& style, AMetric width) override; @@ -134,6 +144,7 @@ class IBatchingRenderer : public IRenderer { .transform = getTransform(), .color = getColor(), .arg = std::move(arg), + .batchId = BatchId{} }); } diff --git a/aui.views/src/AUI/GL/OpenGLRenderer.cpp b/aui.views/src/AUI/GL/OpenGLRenderer.cpp index cb9195c07..e13111b3b 100644 --- a/aui.views/src/AUI/GL/OpenGLRenderer.cpp +++ b/aui.views/src/AUI/GL/OpenGLRenderer.cpp @@ -13,6 +13,12 @@ // Created by Alex2772 on 11/19/2021. // +#include +#include +#include +#include +#include +#include #include #include "OpenGLRenderer.h" #include "AUI/Common/AException.h" @@ -20,12 +26,14 @@ #include "AUI/GL/Framebuffer.h" #include "AUI/GL/GLDebug.h" #include "AUI/GL/GLEnums.h" +#include "AUI/GL/IBatchingRenderer.h" #include "AUI/GL/Program.h" #include "AUI/GL/Texture2D.h" #include "AUI/GL/Vao.h" -#include "AUI/Platform/AInput.h" +#include "AUI/GL/gl.h" #include "AUI/Platform/APlatform.h" #include "AUI/Render/ABorderStyle.h" +#include "AUI/Render/ABrush.h" #include "AUI/Render/Brush/Gradient.h" #include "AUI/Render/IRenderer.h" #include "AUI/Util/AAngleRadians.h" @@ -35,6 +43,7 @@ #include "glm/fwd.hpp" #include "AUI/Util/GaussianKernel.h" #include "AUI/Traits/bit.h" +#include "glm/gtc/type_ptr.hpp" #include #include #include @@ -42,26 +51,15 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include #include +#include +#include +#include +#include static constexpr auto LOG_TAG = "OpenGLRenderer"; @@ -70,17 +68,11 @@ class OpenGLTexture2D : public ITexture { gl::Texture2D mTexture; public: - void setImage(AImageView image) override { - mTexture.tex2D(image); - } + void setImage(AImageView image) override { mTexture.tex2D(image); } - void bind() { - mTexture.bind(); - } + void bind() { mTexture.bind(); } - gl::Texture2D& texture() noexcept { - return mTexture; - } + gl::Texture2D& texture() noexcept { return mTexture; } }; /** @@ -88,51 +80,24 @@ class OpenGLTexture2D : public ITexture { */ static constexpr auto UV_BIAS = 0.001f; - namespace { -void gradientBrush(const IBatchingRenderer::Cmd& cmd, const ALinearGradientBrush& brush, OpenGLRenderer& renderer, gl::Program& shader) { - - shader.use(); - shader.set(aui::ShaderUniforms::COLOR, cmd.color); - aui::render::brush::gradient::Helper h(brush); - shader.set(aui::ShaderUniforms::GRADIENT_MAT_UV, h.matrix); - - if (h.colors.size() == 2) { - // simple gradient can be used - shader.set(aui::ShaderUniforms::COLOR1, glm::vec4(h.colors[0]) / 255.f); - shader.set(aui::ShaderUniforms::COLOR2, glm::vec4(h.colors[1]) / 255.f); - } else { - // complex gradient needs a texture - // tex.tex2D(h.gradientMap()); - - // TODO complex shader is broken, use simple shader instead with first and last color - shader.set(aui::ShaderUniforms::COLOR1, glm::vec4(h.colors.first()) / 255.f); - shader.set(aui::ShaderUniforms::COLOR2, glm::vec4(h.colors.last()) / 255.f); - } - - renderer.identityUv(); -} - -void solidBrush(const IBatchingRenderer::Cmd& cmd, const ASolidBrush& brush, OpenGLRenderer& renderer, gl::Program& shader) { - shader.use(); - shader.set(aui::ShaderUniforms::COLOR, cmd.color * brush.solidColor); -} - -void texturedBrush(const IBatchingRenderer::Cmd& cmd, const ATexturedBrush& brush, OpenGLRenderer& renderer, gl::Program& shader, gl::Vao& tempVao) { +void texturedBrush( + const IBatchingRenderer::Cmd& cmd, const ATexturedBrush& brush, OpenGLRenderer& renderer, gl::Program& shader, + gl::Vao& tempVao) { shader.use(); shader.set(aui::ShaderUniforms::COLOR, cmd.color); if (brush.uv1 || brush.uv2) { - glm::vec2 uv1 = brush.uv1.valueOr(glm::vec2{0, 0}); - glm::vec2 uv2 = brush.uv2.valueOr(glm::vec2{1, 1}); + glm::vec2 uv1 = brush.uv1.valueOr(glm::vec2 { 0, 0 }); + glm::vec2 uv2 = brush.uv2.valueOr(glm::vec2 { 1, 1 }); const glm::vec2 uvs[] = { - {uv1.x, uv2.y}, - {uv2.x, uv2.y}, - {uv1.x, uv1.y}, - {uv2.x, uv1.y}, + { uv1.x, uv2.y }, + { uv2.x, uv2.y }, + { uv1.x, uv1.y }, + { uv2.x, uv1.y }, }; - tempVao.insert(1, AArrayView(uvs), "TexturedShaderHelper"); + tempVao.insert(1, std::span { uvs }, "TexturedShaderHelper"); } else { renderer.identityUv(); } @@ -162,14 +127,13 @@ void texturedBrush(const IBatchingRenderer::Cmd& cmd, const ATexturedBrush& brus } } - -template +template concept AuiSLShader = requires(C&& c) { { C::code() } -> std::same_as; C::setup(0); }; -template +template inline void useAuislShader(AOptional& out) { out.emplace(); out->loadBoth(Vertex::code(), Fragment::code()); @@ -177,6 +141,49 @@ inline void useAuislShader(AOptional& out) { Fragment::setup(out->handle()); out->compile(); } + +// TODO: Add compile time shader loading like for SL shaders +inline void useExternalShader(AOptional& out, std::string_view vsPath, std::string_view fsPath) { + out.emplace(); + ALogger::info("OpenGL") << std::format("Loading vertex shader {}", vsPath); + std::ifstream vsFile { static_cast(vsPath) }; + if (!vsFile.is_open()) { + throw AException("Couldn't open vertex shader " + vsPath); + } + ALogger::info("OpenGL") << std::format("Loading fragment shader {}", fsPath); + std::ifstream fsFile { static_cast(fsPath) }; + if (!fsFile.is_open()) { + throw AException("Couldn't open fragment shader" + fsPath); + } + std::stringstream vsBuffer; + vsBuffer << vsFile.rdbuf(); + std::stringstream fsBuffer; + fsBuffer << fsFile.rdbuf(); + out->loadVertexShader(vsBuffer.str(), gl::GLSLOptions { .custom = true }); + out->loadFragmentShader(fsBuffer.str(), gl::GLSLOptions { .custom = true }); + out->compile(); +} + +} // namespace + +ASolidBrush::Data +OpenGLRenderer::solidBrush(const IBatchingRenderer::Cmd& cmd, const ASolidBrush& brush, gl::Program& shader) { + mBatchShader = &shader; + auto color = cmd.color * brush.color; + + return color; +} + +ALinearGradientBrush::Data OpenGLRenderer::gradientBrush( + const IBatchingRenderer::Cmd& cmd, const ALinearGradientBrush& brush, gl::Program& shader) { + mBatchShader = &shader; + auto result = ALinearGradientBrush::Data { + .colorStart = cmd.color * brush.colorStart, + .colorEnd = cmd.color * brush.colorEnd, + .rotation = brush.rotation.radians() + }; + + return result; } OpenGLRenderer::OpenGLRenderer() { @@ -184,11 +191,11 @@ OpenGLRenderer::OpenGLRenderer() { ALogger::info(LOG_TAG) << "GL_VENDOR = " << ((const char*) glGetString(GL_VENDOR)); ALogger::info(LOG_TAG) << "GL_RENDERER = " << ((const char*) glGetString(GL_RENDERER)); ALogger::info(LOG_TAG) << "GL_EXTENSIONS = " << [] { - if (auto ext = ((const char*) glGetString(GL_EXTENSIONS))) { - return ext; - } else { - return "null"; - } + if (auto ext = ((const char*) glGetString(GL_EXTENSIONS))) { + return ext; + } else { + return "null"; + } }(); #if AUI_DEBUG && (AUI_PLATFORM_WIN || AUI_PLATFORM_LINUX) gl::setupDebug(); @@ -197,78 +204,176 @@ OpenGLRenderer::OpenGLRenderer() { mGradientTexture.bind(); mGradientTexture.setupLinear(); mGradientTexture.setupClampToEdge(); - useAuislShader(mSolidShader); - - useAuislShader(mBoxShadowShader); - - useAuislShader(mBoxShadowInnerShader); - - useAuislShader(mRoundedSolidShader); - useAuislShader(mRoundedSolidShaderBorder); - useAuislShader(mGradientShader); - useAuislShader(mRoundedGradientShader); - useAuislShader(mTexturedShader); - useAuislShader(mUnblendShader); - useAuislShader(mSquareSectorShader); - - useAuislShader(mSymbolShader); - useAuislShader(mSymbolShaderSubPixel); - - useAuislShader(mLineSolidDashedShader); - { - constexpr GLuint INDICES[] = {0, 1, 2, 2, 1, 3}; - mRectangleVao.indices(INDICES); - } - { - constexpr GLuint INDICES[] = {0, 1, 2, 3, 4, 5, 6, 7}; - mBorderVao.indices(INDICES); - } + useExternalShader(mSolidShader, "aui.views/shaders/basic_solid.vert", "aui.views/shaders/solid.frag"); + mSolidShader->bindAttribute(0, "pos"); + mSolidShader->bindAttribute(1, "color"); + mSolidShader->setSetupCallback([]() { + glEnableVertexAttribArray(0); + const size_t stride = sizeof(glm::vec4) * 2; + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, stride, 0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, stride, reinterpret_cast(sizeof(glm::vec4))); + }); + + useExternalShader(mGradientShader, "aui.views/shaders/basic_gradient.vert", "aui.views/shaders/gradient.frag"); + mGradientShader->bindAttribute(0, "pos"); + mGradientShader->bindAttribute(1, "color_start"); + mGradientShader->bindAttribute(2, "color_end"); + mGradientShader->bindAttribute(3, "direction"); + mGradientShader->setSetupCallback([]() { + glEnableVertexAttribArray(0); + const size_t stride = sizeof(glm::vec4) * 3 + sizeof(float); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, stride, 0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, stride, reinterpret_cast(sizeof(glm::vec4))); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, stride, reinterpret_cast(2 * sizeof(glm::vec4))); + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, stride, reinterpret_cast(3 * sizeof(glm::vec4))); + }); + + // useAuislShader(mBoxShadowShader); + // + // useAuislShader(mBoxShadowInnerShader); + // + // useAuislShader(mRoundedSolidShader); + // useAuislShader(mRoundedSolidShaderBorder); + // useAuislShader(mRoundedGradientShader); + // useAuislShader(mTexturedShader); + // useAuislShader(mUnblendShader); + // useAuislShader(mSquareSectorShader); + // + // useAuislShader(mSymbolShader); + // useAuislShader(mSymbolShaderSubPixel); + // + // useAuislShader(mLineSolidDashedShader); + + mBatchVao.indicesByCount(BATCH_BUFFER_SIZE); + mBatchVao.indicesByCount(BATCH_BUFFER_SIZE); + mBatchVertices.fill(0.f); + mCurrentBatchVertex = mBatchVertices.begin(); } void OpenGLRenderer::handleCmds(std::vector cmds) { + auto getBrushId = [](Cmd& cmd) { + unsigned char result; + const char OFFSET = 3; + + std::visit( + aui::lambda_overloaded { [&](const auto& arg) { + if constexpr (requires { arg.brush; }) { + result = arg.brush.index() + OFFSET; + } else { + result = OFFSET - 1; + } + } }, + cmd.arg); + + return result; + }; + auto getZIndex = [](const Cmd& cmd) -> int16_t { + std::optional result; + + std::visit( + aui::lambda_overloaded { [&](const auto& arg) { + if constexpr (requires { arg.zIndex; }) { + result = arg.zIndex; + } + } }, + cmd.arg); + + return result.value_or(std::numeric_limits::max()); + }; for (auto& cmd : cmds) { - std::visit(aui::lambda_overloaded{ - [&](const CmdRectangle& c) { renderRectangle(cmd, c.brush, c.position, c.size); }, - [&](const CmdRoundedRectangle& c) { renderRoundedRectangle(cmd, c.brush, c.position, c.size, c.radius); }, - [&](const CmdRectangleBorder& c) { renderRectangleBorder(cmd, c.brush, c.position, c.size, c.lineWidth); }, - [&](const CmdRoundedRectangleBorder& c) { renderRoundedRectangleBorder(cmd, c.brush, c.position, c.size, c.radius, c.borderWidth); }, - [&](const CmdBoxShadow& c) { renderBoxShadow(cmd, c.position, c.size, c.blurRadius, c.color); }, - [&](const CmdBoxShadowInner& c) { renderBoxShadowInner(cmd, c.position, c.size, c.blurRadius, c.spreadRadius, c.borderRadius, c.color, c.offset); }, - [&](const CmdString& c) { renderString(cmd, c.position, c.string, c.fs); }, - [&](const CmdLines& c) { renderLines(cmd, c.brush, c.points, c.style, c.width); }, - [&](const CmdPoints& c) { renderPoints(cmd, c.brush, c.points, c.size); }, - [&](const CmdLinesPairs& c) { renderLines(cmd, c.brush, c.points, c.style, c.width); }, - [&](const CmdSquareSector& c) { renderSquareSector(cmd, c.brush, c.position, c.size, c.begin, c.end); }, - [&](const CmdPushMaskBefore&) { renderPushMaskBefore(); }, - [&](const CmdPopMaskBefore&) { renderPopMaskBefore(); }, - [&](const CmdPushMaskAfter&) { renderPushMaskAfter(); }, - [&](const CmdPopMaskAfter&) { renderPopMaskAfter(); }, - [&](const CmdSetBlending& c) { renderSetBlending(c.blending); }, - [&](const CmdSetWindow& c) { mWindow = c.window; }, - [&](const CmdNewRenderViewToTexture&){ /* handled elsewhere */ } - }, cmd.arg); + cmd.batchId = BatchId { getZIndex(cmd), static_cast(cmd.arg.index()), getBrushId(cmd) }; } -} + std::ranges::stable_sort(cmds, [&](const Cmd& cmdA, const Cmd& cmdB) { + return cmdA.batchId.value < cmdB.batchId.value; + }); + + auto& batchVao = mBatchVao; + auto& batchVertices = mBatchVertices; + auto& batchShader = mBatchShader; + auto& currentBatchVertex = mCurrentBatchVertex; + auto drawBatch = [&](const char* name) { + if (batchShader == nullptr or currentBatchVertex == batchVertices.begin()) + return; + + batchShader->use(); + batchVao.insert(0, std::span { batchVertices }, name); + // TODO: move this and make it more expandable + batchVao.drawElements(); + }; + BatchId_t currentBatchId = 0; + bool breakBatch = false; + auto dispatch = [&](Cmd& cmd) { + BatchId_t nextId = cmd.batchId.value + 1; // + 1 so 0 ID cmd 0 ID brush != NULL + if (!currentBatchId) { + currentBatchId = nextId; + return; + } + // TODO: don't draw for non drawing commands like set window + if (currentBatchId != nextId) { + breakBatch = true; + } + // TODO: add logic here so the batch breaks if BATCH_VERTEX_AMOUNT will be exceeded + + if (not breakBatch) + return; + drawBatch("Batch"); + currentBatchId = nextId; + std::ranges::fill(batchVertices, 0.f); + currentBatchVertex = batchVertices.begin(); + breakBatch = false; + }; + + for (auto& cmd : cmds) { + dispatch(cmd); + + std::visit( + aui::lambda_overloaded { + [&](const CmdRectangle& c) { renderRectangle(cmd, c.brush, c.position, c.size, c.zIndex); }, + // [&](const CmdRoundedRectangle& c) { renderRoundedRectangle(cmd, c.brush, c.position, c.size, c.radius, + // c.zIndex); }, + // [&](const CmdRectangleBorder& c) { renderRectangleBorder(cmd, c.brush, c.position, c.size, c.lineWidth, + // c.zIndex); }, + // [&](const CmdRoundedRectangleBorder& c) { renderRoundedRectangleBorder(cmd, c.brush, c.position, + // c.size, c.radius, c.borderWidth, c.zIndex); }, + // [&](const CmdBoxShadow& c) { renderBoxShadow(cmd, c.position, c.size, c.blurRadius, c.color, c.zIndex); + // }, + // [&](const CmdBoxShadowInner& c) { renderBoxShadowInner(cmd, c.position, c.size, c.blurRadius, + // c.spreadRadius, c.borderRadius, c.color, c.offset, c.zIndex); }, + // [&](const CmdString& c) { renderString(cmd, c.position, c.string, c.fs); }, + // [&](const CmdLines& c) { renderLines(cmd, c.brush, c.points, c.style, c.width); }, + // [&](const CmdPoints& c) { renderPoints(cmd, c.brush, c.points, c.size); }, + // [&](const CmdLinesPairs& c) { renderLines(cmd, c.brush, c.points, c.style, c.width); }, + // [&](const CmdSquareSector& c) { renderSquareSector(cmd, c.brush, c.position, c.size, c.begin, c.end); + // }, + // [&](const CmdSetWindow& c) { mWindow = c.window; }, + // [&](const CmdNewRenderViewToTexture&){ /* handled elsewhere */ }, + [&](const auto& c) {} }, + cmd.arg); + } + if (mCurrentBatchVertex != mBatchVertices.begin()) + drawBatch("Batch"); +} glm::mat4 OpenGLRenderer::getProjectionMatrix() const { - return glm::ortho(0.0f, static_cast(mWindow->getWidth()), - static_cast(mWindow->getHeight()), 0.0f, - -1.f, 1.f); + return glm::ortho( + 0.0f, static_cast(mWindow->getWidth()), static_cast(mWindow->getHeight()), 0.0f, -1.f, 1.f); } std::array OpenGLRenderer::getVerticesForRect(glm::vec2 position, glm::vec2 size) { @@ -277,148 +382,139 @@ std::array OpenGLRenderer::getVerticesForRect(glm::vec2 position, float w = x + size.x; float h = y + size.y; - return - { - glm::vec2{x, h,}, - glm::vec2{w, h,}, - glm::vec2{x, y,}, - glm::vec2{w, y,}, - }; -} - -void OpenGLRenderer::renderRectangle(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size) { - std::visit(aui::lambda_overloaded{ - [&](const ALinearGradientBrush& brush) { - gradientBrush(cmd, brush, *this, *mGradientShader); + return { + glm::vec2 { + x, + h, }, - [&](const ATexturedBrush& brush) { - texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); + glm::vec2 { + w, + h, }, - [&](const ASolidBrush& brush) { - solidBrush(cmd, brush, *this, *mSolidShader); + glm::vec2 { + x, + y, }, - [](const ACustomShaderBrush& ) {}, - }, brush); - gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, cmd.transform); - - drawRectImpl(position, size); + glm::vec2 { + w, + y, + }, + }; } -void OpenGLRenderer::drawRectImpl(glm::vec2 position, glm::vec2 size) { - mRectangleVao.bind(); - - mRectangleVao.insert(0, AArrayView(getVerticesForRect(position, size)), "drawRectImpl"); - - mRectangleVao.drawElements(); +void OpenGLRenderer::renderRectangle( + const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, const zIndex_t zIndex) { + std::visit( + aui::lambda_overloaded { + [&](const ALinearGradientBrush& brush) { + ALinearGradientBrush::Data data = gradientBrush(cmd, brush, *mGradientShader); + appendRect(position, size, cmd.transform, data); + }, + [&](const ATexturedBrush& brush) { + // texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); + }, + [&](const ASolidBrush& brush) { + ASolidBrush::Data data = solidBrush(cmd, brush, *mSolidShader); + appendRect(position, size, cmd.transform, data); + }, + [](const ACustomShaderBrush&) {}, + }, + brush); } void OpenGLRenderer::identityUv() { - const glm::vec2 uvs[] = { - {0, 1}, - {1, 1}, - {0, 0}, - {1, 0} - }; - mRectangleVao.insertIfKeyMismatches(1, AArrayView(uvs), "identityUv"); + const glm::vec2 uvs[] = { { 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 } }; + mBatchVao.insertIfKeyMismatches(1, std::span { uvs }, "identityUv"); } -void OpenGLRenderer::renderRoundedRectangle(const Cmd& cmd, const ABrush& brush, - glm::vec2 position, - glm::vec2 size, - float radius) { +void OpenGLRenderer::renderRoundedRectangle( + const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius, const zIndex_t zIndex) { std::visit( aui::lambda_overloaded { - [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *this, *mRoundedGradientShader); }, - [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); }, - [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *this, *mRoundedSolidShader); }, - [](const ACustomShaderBrush& ) {}, - }, brush); + [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *mRoundedGradientShader); }, + [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mBatchVao); }, + [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *mRoundedSolidShader); }, + [](const ACustomShaderBrush&) {}, + }, + brush); identityUv(); gl::Program::currentShader()->set(aui::ShaderUniforms::OUTER_SIZE, 2.f * radius / size); - drawRectImpl(position, size); + // appendRect(position, size, zIndex, cmd.transform); } -void OpenGLRenderer::renderRectangleBorder(const Cmd& cmd, const ABrush& brush, - glm::vec2 position, - glm::vec2 size, - float lineWidth) { +void OpenGLRenderer::renderRectangleBorder( + const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float lineWidth, const zIndex_t zIndex) { std::visit( aui::lambda_overloaded { - [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *this, *mGradientShader); }, - [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); }, - [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *this, *mSolidShader); }, - [](const ACustomShaderBrush& ) {}, - }, brush); - gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, cmd.transform); + [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *mGradientShader); }, + [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mBatchVao); }, + [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *mSolidShader); }, + [](const ACustomShaderBrush&) {}, + }, + brush); identityUv(); - //rect.insert(0, getVerticesForRect(x + 0.25f + lineWidth * 0.5f, y + 0.25f + lineWidth * 0.5f, width - (0.25f + lineWidth * 0.5f), height - (0.75f + lineWidth * 0.5f))); + // rect.insert(0, getVerticesForRect(x + 0.25f + lineWidth * 0.5f, y + 0.25f + lineWidth * 0.5f, width - (0.25f + + // lineWidth * 0.5f), height - (0.75f + lineWidth * 0.5f))); const float lineDelta = 0.25f + lineWidth / 2.f; float x = position.x; float y = position.y; float w = x + size.x; float h = y + size.y; + std::array verticies = std::array { + glm::vec3(glm::vec4 { x + lineWidth, y + lineDelta, 1, 1 }), + glm::vec3(glm::vec4 { w, y + lineDelta, 1, 1 }), - mRectangleVao.insert(0, - AArrayView(std::array{ - glm::vec3(glm::vec4{x + lineWidth, y + lineDelta, 1, 1}), - glm::vec3(glm::vec4{w, y + lineDelta, 1, 1}), + glm::vec3(glm::vec4 { w - lineDelta, y + lineWidth, 1, 1 }), + glm::vec3(glm::vec4 { w - lineDelta, h, 1, 1 }), - glm::vec3(glm::vec4{w - lineDelta, y + lineWidth, 1, 1}), - glm::vec3(glm::vec4{w - lineDelta, h, 1, 1}), + glm::vec3(glm::vec4 { w - lineWidth, h - lineDelta - 0.15f, 1, 1 }), + glm::vec3(glm::vec4 { x, h - lineDelta - 0.15f, 1, 1 }), - glm::vec3(glm::vec4{w - lineWidth, h - lineDelta - 0.15f, 1, 1}), - glm::vec3(glm::vec4{x, h - lineDelta - 0.15f, 1, 1}), + glm::vec3(glm::vec4 { x + lineDelta, h - lineWidth - 0.15f, 1, 1 }), + glm::vec3(glm::vec4 { x + lineDelta, y, 1, 1 }) + }; - glm::vec3(glm::vec4{x + lineDelta, h - lineWidth - 0.15f, 1, 1}), - glm::vec3(glm::vec4{x + lineDelta, y, 1, 1}), - }), "rectangleBorder"); + mBatchVao.insert(0, std::span { verticies }, "rectangleBorder"); glLineWidth(lineWidth); - mRectangleVao.drawElements(GL_LINES); } -void OpenGLRenderer::renderRoundedRectangleBorder(const Cmd& cmd, const ABrush& brush, - glm::vec2 position, - glm::vec2 size, - float radius, - int borderWidth) { +void OpenGLRenderer::renderRoundedRectangleBorder( + const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius, int borderWidth, + const zIndex_t zIndex) { std::visit( aui::lambda_overloaded { - [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *this, *mGradientShader); }, - [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); }, - [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *this, *mRoundedSolidShaderBorder); }, - [](const ACustomShaderBrush& ) {}, - }, brush); + [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *mGradientShader); }, + [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mBatchVao); }, + [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *mRoundedSolidShaderBorder); }, + [](const ACustomShaderBrush&) {}, + }, + brush); identityUv(); - glm::vec2 innerSize = {size.x - borderWidth * 2, - size.y - borderWidth * 2}; + glm::vec2 innerSize = { size.x - borderWidth * 2, size.y - borderWidth * 2 }; gl::Program::currentShader()->set(aui::ShaderUniforms::OUTER_SIZE, 2.f * radius / size); gl::Program::currentShader()->set(aui::ShaderUniforms::INNER_SIZE, 2.f * (radius - borderWidth) / innerSize); gl::Program::currentShader()->set(aui::ShaderUniforms::OUTER_TO_INNER, size / innerSize); - gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, cmd.transform); - drawRectImpl(position, size); + // appendRect(position, size, zIndex, cmd.transform); } -void OpenGLRenderer::renderBoxShadow(const Cmd& cmd, glm::vec2 position, - glm::vec2 size, - float blurRadius, - const AColor& color) { - AUI_ASSERTX(blurRadius >= 0.f, - "blurRadius is expected to be non negative, use boxShadowInner for inset shadows instead"); +void OpenGLRenderer::renderBoxShadow( + const Cmd& cmd, glm::vec2 position, glm::vec2 size, float blurRadius, const AColor& color, const zIndex_t zIndex) { + AUI_ASSERTX( + blurRadius >= 0.f, "blurRadius is expected to be non negative, use boxShadowInner for inset shadows instead"); identityUv(); mBoxShadowShader->use(); mBoxShadowShader->set(aui::ShaderUniforms::SL_UNIFORM_SIGMA, blurRadius / 2.f); mBoxShadowShader->set(aui::ShaderUniforms::SL_UNIFORM_LOWER, position + size); mBoxShadowShader->set(aui::ShaderUniforms::SL_UNIFORM_UPPER, position); - mBoxShadowShader->set(aui::ShaderUniforms::SL_UNIFORM_TRANSFORM, cmd.transform); mBoxShadowShader->set(aui::ShaderUniforms::COLOR, cmd.color * color); - mRectangleVao.bind(); + mBatchVao.bind(); float x = position.x; float y = position.y; @@ -430,24 +526,20 @@ void OpenGLRenderer::renderBoxShadow(const Cmd& cmd, glm::vec2 position, w += blurRadius; h += blurRadius; - const glm::vec2 uvs[] = { - {x, h}, - {w, h}, - {x, y}, - {w, y}, - }; - mRectangleVao.insert(0, AArrayView(uvs), "boxShadow"); + // const glm::vec2 uvs[] = { + // {x, h}, + // {w, h}, + // {x, y}, + // {w, y}, + // }; - mRectangleVao.drawElements(); + // mRectangleVao.insert(0, std::span{uvs}, "boxShadowInner"); + // drawRectImpl(glm::vec2{x, y}, glm::vec2{w, h}, zIndex); } -void OpenGLRenderer::renderBoxShadowInner(const Cmd& cmd, glm::vec2 position, - glm::vec2 size, - float blurRadius, - float spreadRadius, - float borderRadius, - const AColor& color, - glm::vec2 offset) { +void OpenGLRenderer::renderBoxShadowInner( + const Cmd& cmd, glm::vec2 position, glm::vec2 size, float blurRadius, float spreadRadius, float borderRadius, + const AColor& color, glm::vec2 offset, const zIndex_t zIndex) { AUI_ASSERTX(blurRadius >= 0.f, "blurRadius is expected to be non negative"); blurRadius *= -1.f; identityUv(); @@ -455,32 +547,29 @@ void OpenGLRenderer::renderBoxShadowInner(const Cmd& cmd, glm::vec2 position, mBoxShadowInnerShader->set(aui::ShaderUniforms::SL_UNIFORM_SIGMA, blurRadius / 2.f); mBoxShadowInnerShader->set(aui::ShaderUniforms::SL_UNIFORM_LOWER, position + offset + size - spreadRadius); mBoxShadowInnerShader->set(aui::ShaderUniforms::SL_UNIFORM_UPPER, position + offset + spreadRadius); - mBoxShadowInnerShader->set(aui::ShaderUniforms::SL_UNIFORM_TRANSFORM, cmd.transform); mBoxShadowInnerShader->set(aui::ShaderUniforms::COLOR, cmd.color * color); gl::Program::currentShader()->set(aui::ShaderUniforms::OUTER_SIZE, 2.f * borderRadius / size); - mRectangleVao.bind(); + mBatchVao.bind(); float x = position.x; float y = position.y; float w = x + size.x; float h = y + size.y; - const glm::vec2 uvs[] = { - {x, h}, - {w, h}, - {x, y}, - {w, y}, - }; - mRectangleVao.insert(0, AArrayView(uvs), "boxShadowInner"); + // const glm::vec2 uvs[] = { + // {x, h}, + // {w, h}, + // {x, y}, + // {w, y}, + // }; - mRectangleVao.drawElements(); + // mRectangleVao.insert(0, std::span{uvs}, "boxShadowInner"); + // appendRect(glm::vec2{x, y}, glm::vec2{w, h}, zIndex, cmd.transform); } -void OpenGLRenderer::renderString(const Cmd& cmd, glm::vec2 position, - const AString& string, - const AFontStyle& fs) { +void OpenGLRenderer::renderString(const Cmd& cmd, glm::vec2 position, const AString& string, const AFontStyle& fs) { prerenderString(position, string, fs)->draw(); } @@ -540,20 +629,16 @@ class OpenGLPrerenderedString : public IRenderer::IPrerenderedString { OpenGLRenderer::FontEntryData* mEntryData; FontRendering mFontRendering; - OpenGLPrerenderedString(OpenGLRenderer* renderer, - gl::VertexBuffer vertexBuffer, - gl::IndexBuffer indexBuffer, - int textWidth, - int textHeight, - OpenGLRenderer::FontEntryData* entryData, - FontRendering fontRendering) : - mRenderer(renderer), - mVertexBuffer(std::move(vertexBuffer)), - mIndexBuffer(std::move(indexBuffer)), - mTextWidth(textWidth), - mTextHeight(textHeight), - mEntryData(entryData), - mFontRendering(fontRendering) { + OpenGLPrerenderedString( + OpenGLRenderer* renderer, gl::VertexBuffer vertexBuffer, gl::IndexBuffer indexBuffer, int textWidth, + int textHeight, OpenGLRenderer::FontEntryData* entryData, FontRendering fontRendering) + : mRenderer(renderer) + , mVertexBuffer(std::move(vertexBuffer)) + , mIndexBuffer(std::move(indexBuffer)) + , mTextWidth(textWidth) + , mTextHeight(textHeight) + , mEntryData(entryData) + , mFontRendering(fontRendering) { if (mRenderer->isVaoAvailable()) { mVao.emplace(); mVao->bind(); @@ -564,9 +649,9 @@ class OpenGLPrerenderedString : public IRenderer::IPrerenderedString { } } - void draw() override { - if (mIndexBuffer.count() == 0) return; + if (mIndexBuffer.count() == 0) + return; decltype(auto) img = mEntryData->texturePacker.getImage(); if (!img) @@ -574,7 +659,8 @@ class OpenGLPrerenderedString : public IRenderer::IPrerenderedString { if (AWindow::current()->profiling()->showBaseline) { mRenderer->rectangle( - ASolidBrush { AColor::RED.transparentize(0.5f) }, { 0, 0 }, { mTextWidth, 1 }); // debug baseline + ASolidBrush { AColor::RED.transparentize(0.5f) }, { 0, 0 }, std::numeric_limits::max(), + { mTextWidth, 1 }); // debug baseline } auto width = img->width(); @@ -621,23 +707,20 @@ class OpenGLPrerenderedString : public IRenderer::IPrerenderedString { } } - int getWidth() override { - return mTextWidth; - } + int getWidth() override { return mTextWidth; } - int getHeight() override { - return mTextHeight; - } + int getHeight() override { return mTextHeight; } private: static void setupVertexAttribs() { glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); - glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(OpenGLPrerenderedString::Vertex), - reinterpret_cast(0)); - glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(OpenGLPrerenderedString::Vertex), - reinterpret_cast(sizeof(glm::vec2))); + glVertexAttribPointer( + 0, 2, GL_FLOAT, false, sizeof(OpenGLPrerenderedString::Vertex), reinterpret_cast(0)); + glVertexAttribPointer( + 1, 2, GL_FLOAT, false, sizeof(OpenGLPrerenderedString::Vertex), + reinterpret_cast(sizeof(glm::vec2))); } }; @@ -651,14 +734,12 @@ class OpenGLMultiStringCanvas : public IRenderer::IMultiStringCanvas { int mAdvanceY = 0; public: - OpenGLMultiStringCanvas(OpenGLRenderer* renderer, const AFontStyle& fontStyle) : - mRenderer(renderer), - mFontStyle(fontStyle), - mEntryData(renderer->getFontEntryData(fontStyle)) { + OpenGLMultiStringCanvas(OpenGLRenderer* renderer, const AFontStyle& fontStyle) + : mRenderer(renderer), mFontStyle(fontStyle), mEntryData(renderer->getFontEntryData(fontStyle)) { mVertices.reserve(1000); } - template + template void addStringT(const glm::ivec2& position, UnicodeString text) noexcept { mVertices.reserve(mVertices.capacity() + text.length() * 4); auto& font = mFontStyle.font; @@ -674,11 +755,11 @@ class OpenGLMultiStringCanvas : public IRenderer::IMultiStringCanvas { for (auto i = text.begin(); i != text.end(); ++i, ++counter) { AChar c = *i; if (c == ' ') { - notifySymbolAdded({glm::ivec2{advance, advanceY}}); + notifySymbolAdded({ glm::ivec2 { advance, advanceY } }); advance += mFontStyle.getSpaceWidth(); } else if (c == '\n') { - notifySymbolAdded({glm::ivec2{advance, advanceY}}); - advanceX = (glm::max)(advanceX, int(glm::ceil(advance))); + notifySymbolAdded({ glm::ivec2 { advance, advanceY } }); + advanceX = (glm::max) (advanceX, int(glm::ceil(advance))); advance = position.x; advanceY += mFontStyle.getLineHeight(); nextLine(); @@ -689,7 +770,6 @@ class OpenGLMultiStringCanvas : public IRenderer::IMultiStringCanvas { continue; } if ((advance >= 0 && advance <= 99999) /* || gui3d */) { - int posX = advance + ch.horizontal.bearing.x; int posY = advanceY - ch.horizontal.bearing.y; int width = ch.image->width(); @@ -705,23 +785,18 @@ class OpenGLMultiStringCanvas : public IRenderer::IMultiStringCanvas { uv.y += BIAS; uv.z -= BIAS; uv.w -= BIAS; - mRenderer->mCharData.push_back(OpenGLRenderer::CharacterData{uv}); + mRenderer->mCharData.push_back(OpenGLRenderer::CharacterData { uv }); ch.rendererData = &mRenderer->mCharData.last(); mEntryData->isTextureInvalid = true; } else { uv = reinterpret_cast(ch.rendererData)->uv; } - notifySymbolAdded({glm::ivec2{posX, posY}}); - mVertices.push_back({glm::vec2(posX, posY + height), - glm::vec2(uv.x, uv.w)}); - mVertices.push_back({glm::vec2(posX + width, posY + height), - glm::vec2(uv.z, uv.w)}); - mVertices.push_back({glm::vec2(posX, posY), - glm::vec2(uv.x, uv.y)}); - mVertices.push_back({glm::vec2(posX + width, posY), - glm::vec2(uv.z, uv.y)}); - + notifySymbolAdded({ glm::ivec2 { posX, posY } }); + mVertices.push_back({ glm::vec2(posX, posY + height), glm::vec2(uv.x, uv.w) }); + mVertices.push_back({ glm::vec2(posX + width, posY + height), glm::vec2(uv.z, uv.w) }); + mVertices.push_back({ glm::vec2(posX, posY), glm::vec2(uv.x, uv.y) }); + mVertices.push_back({ glm::vec2(posX + width, posY), glm::vec2(uv.z, uv.y) }); } if (hasKerning) { @@ -736,15 +811,13 @@ class OpenGLMultiStringCanvas : public IRenderer::IMultiStringCanvas { } } - notifySymbolAdded({glm::ivec2{advance, advanceY}}); + notifySymbolAdded({ glm::ivec2 { advance, advanceY } }); - mAdvanceX = (glm::max)(mAdvanceX, (glm::max)(advanceX, int(glm::ceil(advance)))); + mAdvanceX = (glm::max) (mAdvanceX, (glm::max) (advanceX, int(glm::ceil(advance)))); mAdvanceY = advanceY + mFontStyle.getLineHeight(); } - void addString(const glm::ivec2& position, AStringView text) noexcept override { - addStringT(position, text); - } + void addString(const glm::ivec2& position, AStringView text) noexcept override { addStringT(position, text); } void addString(const glm::ivec2& position, std::u32string_view text) noexcept override { addStringT(position, text); @@ -769,23 +842,19 @@ class OpenGLMultiStringCanvas : public IRenderer::IMultiStringCanvas { gl::IndexBuffer indexBuffer; indexBuffer.set(indices); - return _new(mRenderer, - std::move(vertexBuffer), - std::move(indexBuffer), - mAdvanceX, - mAdvanceY, - mEntryData, - mFontStyle.fontRendering); + return _new( + mRenderer, std::move(vertexBuffer), std::move(indexBuffer), mAdvanceX, mAdvanceY, mEntryData, + mFontStyle.fontRendering); } ~OpenGLMultiStringCanvas() override = default; }; -_ OpenGLRenderer::prerenderString(glm::vec2 position, - const AString& text, - const AFontStyle& fs) { +_ +OpenGLRenderer::prerenderString(glm::vec2 position, const AString& text, const AFontStyle& fs) { // ALOG_DEBUG("OpenGL") << "prerenderString: " << text; - if (text.empty()) return nullptr; + if (text.empty()) + return nullptr; OpenGLMultiStringCanvas c(this, fs); c.addString(position, text); @@ -805,17 +874,13 @@ OpenGLRenderer::FontEntryData* OpenGLRenderer::getFontEntryData(const AFontStyle return entryData; } -_unique OpenGLRenderer::createNewTexture() { - return std::make_unique(); -} +_unique OpenGLRenderer::createNewTexture() { return std::make_unique(); } _ OpenGLRenderer::newMultiStringCanvas(const AFontStyle& style) { return _new(this, style); } -bool OpenGLRenderer::isVaoAvailable() const noexcept { - return glBindVertexArray != nullptr; -} +bool OpenGLRenderer::isVaoAvailable() const noexcept { return glBindVertexArray != nullptr; } void OpenGLRenderer::renderPushMaskBefore() { glStencilFunc(GL_ALWAYS, 0, 0xff); @@ -849,11 +914,9 @@ bool OpenGLRenderer::setupLineShader(const Cmd& cmd, const ABrush& brush, const [&](const ABorderStyle::Solid&) { std::visit( aui::lambda_overloaded { - [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *this, *mGradientShader); }, - [&](const ATexturedBrush& brush) { - texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); - }, - [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *this, *mSolidShader); }, + [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *mGradientShader); }, + [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mBatchVao); }, + [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *mSolidShader); }, [](const ACustomShaderBrush&) {}, }, brush); @@ -864,11 +927,9 @@ bool OpenGLRenderer::setupLineShader(const Cmd& cmd, const ABrush& brush, const [&](const ABorderStyle::Dashed& dashed) { std::visit( aui::lambda_overloaded { - [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *this, *mGradientShader); }, - [&](const ATexturedBrush& brush) { - texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); - }, - [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *this, *mLineSolidDashedShader); }, + [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *mGradientShader); }, + [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mBatchVao); }, + [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *mLineSolidDashedShader); }, [](const ACustomShaderBrush&) {}, }, brush); @@ -893,61 +954,55 @@ struct LineVertex { float distance; float unused; }; -} +} // namespace -void OpenGLRenderer::renderLines(const Cmd& cmd, const ABrush& brush, AArrayView points, const ABorderStyle& style, AMetric width) { - if (points.size() < 2) return; +void OpenGLRenderer::renderLines( + const Cmd& cmd, const ABrush& brush, AArrayView points, const ABorderStyle& style, AMetric width) { + if (points.size() < 2) + return; const auto widthPx = width.getValuePx(); bool computeDistances = setupLineShader(cmd, brush, style, widthPx); gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, cmd.transform); glLineWidth(widthPx); - mRectangleVao.bind(); - + mBatchVao.bind(); AVector positions; positions.reserve(points.size()); - positions << LineVertex{points[0], 0.f, 1.f}; + positions << LineVertex { points[0], 0.f, 1.f }; float distanceAccumulator = 0.f; - for (const auto& point: points | ranges::views::drop(1)) { + for (const auto& point : points | ranges::views::drop(1)) { if (computeDistances) { distanceAccumulator += glm::distance(positions.last().position, point); } - positions << LineVertex{point, distanceAccumulator, 1.f}; + positions << LineVertex { point, distanceAccumulator, 1.f }; } - mRectangleVao.insert(0, AArrayView(positions), "lines"); - mRectangleVao.drawArrays(GL_LINE_STRIP, points.size()); + mBatchVao.insert(0, std::span { positions }, "lines"); + mBatchVao.drawArrays(GL_LINE_STRIP, points.size()); } -void OpenGLRenderer::renderLines(const Cmd& cmd, const ABrush& brush, AArrayView> points, - const ABorderStyle& style, AMetric width) { +void OpenGLRenderer::renderLines( + const Cmd& cmd, const ABrush& brush, AArrayView> points, const ABorderStyle& style, + AMetric width) { const auto widthPx = width.getValuePx(); bool computeDistances = setupLineShader(cmd, brush, style, widthPx); gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, cmd.transform); glLineWidth(widthPx); - mRectangleVao.bind(); + mBatchVao.bind(); AVector positions; positions.reserve(points.size() * 2); - for (const auto& [p1, p2]: points) { - positions << LineVertex{ - p1, - 0.f, - 1.f - }; - positions << LineVertex{ - p2, - glm::distance(p1, p2), - 1.f - }; + for (const auto& [p1, p2] : points) { + positions << LineVertex { p1, 0.f, 1.f }; + positions << LineVertex { p2, glm::distance(p1, p2), 1.f }; } - mRectangleVao.insert(0, AArrayView(positions), "lines"); - mRectangleVao.drawArrays(GL_LINES, positions.size()); + mBatchVao.insert(0, std::span { positions }, "lines"); + mBatchVao.drawArrays(GL_LINES, positions.size()); } void OpenGLRenderer::renderPoints(const Cmd& cmd, const ABrush& brush, AArrayView points, AMetric size) { @@ -957,51 +1012,46 @@ void OpenGLRenderer::renderPoints(const Cmd& cmd, const ABrush& brush, AArrayVie std::visit( aui::lambda_overloaded { - [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *this, *mGradientShader); }, - [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); }, - [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *this, *mSolidShader); }, + [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *mGradientShader); }, + [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mBatchVao); }, + [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *mSolidShader); }, [&](const ACustomShaderBrush& brush) {}, }, brush); const auto widthPx = size.getValuePx(); gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, cmd.transform); - #if AUI_PLATFORM_ANDROID || AUI_PLATFORM_IOS || AUI_PLATFORM_EMSCRIPTEN // TODO slow, use instancing instead - for (auto point : points) { - drawRectImpl(point - glm::vec2(widthPx / 2), glm::vec2(widthPx)); - } + for (auto point : points) { + drawRectImpl(point - glm::vec2(widthPx / 2), glm::vec2(widthPx), cmd.transform); + } #else glPointSize(widthPx); - mRectangleVao.bind(); - mRectangleVao.insert(0, AArrayView(points), "points"); - mRectangleVao.drawArrays(GL_POINTS, points.size()); + mBatchVao.bind(); + mBatchVao.insert(0, std::span { points }, "lines"); + mBatchVao.drawArrays(GL_POINTS, points.size()); #endif } -void OpenGLRenderer::renderSquareSector(const Cmd& cmd, const ABrush& brush, - const glm::vec2& position, - const glm::vec2& size, - AAngleRadians begin, - AAngleRadians end) { +void OpenGLRenderer::renderSquareSector( + const Cmd& cmd, const ABrush& brush, const glm::vec2& position, const glm::vec2& size, AAngleRadians begin, + AAngleRadians end) { std::visit( aui::lambda_overloaded { - [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *this, *mGradientShader); }, - [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mRectangleVao); }, - [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *this, *mSquareSectorShader); }, + [&](const ALinearGradientBrush& brush) { gradientBrush(cmd, brush, *mGradientShader); }, + [&](const ATexturedBrush& brush) { texturedBrush(cmd, brush, *this, *mTexturedShader, mBatchVao); }, + [&](const ASolidBrush& brush) { solidBrush(cmd, brush, *mSquareSectorShader); }, [](const ACustomShaderBrush&) {}, }, brush); gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, cmd.transform); auto calculateLineMatrix = [](AAngleRadians angle) { - auto s = glm::sin(angle.radians()); - auto c = glm::cos(angle.radians()); - return glm::mat3{c, 0, 0, - s, 0, 0, - -0.5f * (s + c), 0, 0}; + auto s = glm::sin(angle.radians()); + auto c = glm::cos(angle.radians()); + return glm::mat3 { c, 0, 0, s, 0, 0, -0.5f * (s + c), 0, 0 }; }; auto m1 = calculateLineMatrix(begin + 180_deg); auto m2 = calculateLineMatrix(end); @@ -1010,10 +1060,10 @@ void OpenGLRenderer::renderSquareSector(const Cmd& cmd, const ABrush& brush, gl::Program::currentShader()->set(aui::ShaderUniforms::M1, m1); gl::Program::currentShader()->set(aui::ShaderUniforms::M2, m2); - drawRectImpl(position, size); + // TODO: replace 0 with zIndex + // appendRect(position, size, 0, cmd.transform); } - static void resetStencil() { glStencilMask(0xff); glClearStencil(0); @@ -1030,13 +1080,12 @@ void OpenGLRenderer::beginPaint(glm::uvec2 windowSize) { gl::State::bindVertexArray(0); gl::State::useProgram(0); - - glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); setBlending(Blending::NORMAL); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); resetStencil(); } @@ -1048,12 +1097,11 @@ void OpenGLRenderer::endPaint() { gl::State::useProgram(0); } - void OpenGLRenderer::bindTemporaryVao() const noexcept { if (!isVaoAvailable()) { return; } - mRectangleVao.bind(); + mBatchVao.bind(); } _unique OpenGLRenderer::newRenderViewToTexture() noexcept { @@ -1067,11 +1115,15 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept public: explicit OpenGLRenderViewToTexture(OpenGLRenderer& renderer) : mRenderer(renderer) { auto prevFramebuffer = gl::Framebuffer::current(); - AUI_DEFER { AUI_NULLSAFE(prevFramebuffer)->bind(); else gl::Framebuffer::unbind(); }; + AUI_DEFER { + AUI_NULLSAFE(prevFramebuffer)->bind(); + else gl::Framebuffer::unbind(); + }; mFramebuffer.setSupersamplingRatio(1); - mFramebuffer.resize({1, 1}); - auto albedo = _new>(); + mFramebuffer.resize({ 1, 1 }); + auto albedo = _new< + gl::TextureRenderTarget>(); mFramebuffer.attach(albedo, GL_COLOR_ATTACHMENT0); albedo->texture().setupClampToEdge(); albedo->texture().setupNearest(); @@ -1079,11 +1131,14 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept } static gl::Framebuffer* getMainRenderingFramebuffer(IRenderer& renderer) { - return dynamic_cast(renderer.getWindow()->getRenderingContext().get())->framebuffer().valueOr(nullptr); + return dynamic_cast(renderer.getWindow()->getRenderingContext().get()) + ->framebuffer() + .valueOr(nullptr); } - bool begin(IRenderer& renderer, glm::ivec2 surfaceSize, IRenderViewToTexture::InvalidArea& invalidArea) override { - AUI_ASSERT(!invalidArea.empty()); // if invalid areas are empty, what should we redraw then? + bool begin( + IRenderer& renderer, glm::ivec2 surfaceSize, IRenderViewToTexture::InvalidArea& invalidArea) override { + AUI_ASSERT(!invalidArea.empty()); // if invalid areas are empty, what should we redraw then? AUI_ASSERT(&mRenderer == &renderer); auto mainRenderingFB = getMainRenderingFramebuffer(renderer); AUI_ASSERT(mainRenderingFB != nullptr); @@ -1103,8 +1158,8 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept mFramebuffer.resize(surfaceSize); if (prevSize != mFramebuffer.size()) [[unlikely]] { // switching to full redraw - we have lost previous data. - invalidArea = InvalidArea::Full{}; - return true; // omit partial update checks + invalidArea = InvalidArea::Full {}; + return true; // omit partial update checks } } @@ -1116,9 +1171,11 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept mainRenderingFB->bindForWrite(); const auto supersampledRenderingFBSize = mFramebuffer.size() * mainRenderingFB->supersamlingRatio(); - glBlitFramebuffer(0, 0, mFramebuffer.size().x, mFramebuffer.size().y, - 0, mainRenderingFB->supersampledSize().y - supersampledRenderingFBSize.y, supersampledRenderingFBSize.x, mainRenderingFB->supersampledSize().y, - GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer( + 0, 0, mFramebuffer.size().x, mFramebuffer.size().y, 0, + mainRenderingFB->supersampledSize().y - supersampledRenderingFBSize.y, + supersampledRenderingFBSize.x, mainRenderingFB->supersampledSize().y, GL_COLOR_BUFFER_BIT, + GL_NEAREST); } // 2. mark invalidated rectangles with stencil mask. @@ -1129,40 +1186,39 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept // pixels. glDisable(GL_BLEND); AUI_DEFER { - glEnable(GL_BLEND); - glStencilMask(0x00); - glStencilFunc(GL_EQUAL, ++mRenderer.mStencilDepth, 0xff); + glEnable(GL_BLEND); + glStencilMask(0x00); + glStencilFunc(GL_EQUAL, ++mRenderer.mStencilDepth, 0xff); }; static constexpr auto MAX_RECTANGLE_COUNT = std::decay_t::capacity(); using Vertices = AStaticVector; using Indices = AStaticVector; - auto vertices = ranges::views::transform(*rectangles, [&](const ARect& r) { - return getVerticesForRect(r.p1, r.size()); - }) | ranges::views::join | ranges::to(); - mRenderer.mRectangleVao.insert(0, AArrayView(vertices), "render-to-texture invalid areas"); - auto indices = ranges::views::generate([i = 0]() mutable { - int offset = 4 * i++; - return std::array{GLuint(offset + 0), - GLuint(offset + 1), - GLuint(offset + 2), - GLuint(offset + 2), - GLuint(offset + 1), - GLuint(offset + 3)}; - }) | ranges::views::take_exactly(rectangles->size()) - | ranges::views::join - | ranges::to() - ; + auto vertices = + ranges::views::transform( + *rectangles, [&](const ARect& r) { return getVerticesForRect(r.p1, r.size()); }) | + ranges::views::join | ranges::to(); + mRenderer.mBatchVao.insert(0, std::span(vertices), "render-to-texture invalid areas"); + auto indices = + ranges::views::generate([i = 0]() mutable { + int offset = 4 * i++; + return std::array { + GLuint(offset + 0), GLuint(offset + 1), GLuint(offset + 2), + GLuint(offset + 2), GLuint(offset + 1), GLuint(offset + 3) + }; + }) | + ranges::views::take_exactly(rectangles->size()) | ranges::views::join | ranges::to(); static constexpr auto DEFAULT_INDICES_SIZE = 6; - if (indices.size() != DEFAULT_INDICES_SIZE) mRenderer.mRectangleVao.indices(AArrayView(indices)); + if (indices.size() != DEFAULT_INDICES_SIZE) + mRenderer.mBatchVao.indices(std::span { indices }); AUI_DEFER { - if (indices.size() != DEFAULT_INDICES_SIZE) { - mRenderer.mRectangleVao.indices(AArrayView(indices.data(), 6)); - } + if (indices.size() != DEFAULT_INDICES_SIZE) { + mRenderer.mBatchVao.indices(std::span { indices.data(), 6 }); + } }; mRenderer.mSolidShader->use(); // mRenderer.uploadToShaderCommon(); // TODO mRenderer.mSolidShader->set(aui::ShaderUniforms::COLOR, glm::vec4(0.f)); - mRenderer.mRectangleVao.drawElements(); + mRenderer.mBatchVao.drawElements(); } return true; @@ -1175,13 +1231,13 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept auto mainRenderingFB = gl::Framebuffer::current(); AUI_ASSERT(mainRenderingFB != nullptr); AUI_DEFER { - mainRenderingFB->bind(); - glStencilMask(0xff); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - glStencilFunc(GL_EQUAL, 0x00, 0xff); - glStencilMask(0); - mRenderer.setStencilDepth(0); + mainRenderingFB->bind(); + glStencilMask(0xff); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glStencilFunc(GL_EQUAL, 0x00, 0xff); + glStencilMask(0); + mRenderer.setStencilDepth(0); }; // copy render results from mainRenderingFB (main render buffer) to our texture render target. @@ -1189,8 +1245,10 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept mainRenderingFB->bindForRead(); mFramebuffer.bindForWrite(); const auto supersampledRenderingFBSize = mFramebuffer.size() * mainRenderingFB->supersamlingRatio(); - glBlitFramebuffer(0, mainRenderingFB->supersampledSize().y - supersampledRenderingFBSize.y, supersampledRenderingFBSize.x, mainRenderingFB->supersampledSize().y, - 0, 0, mFramebuffer.size().x, mFramebuffer.size().y, GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBlitFramebuffer( + 0, mainRenderingFB->supersampledSize().y - supersampledRenderingFBSize.y, + supersampledRenderingFBSize.x, mainRenderingFB->supersampledSize().y, 0, 0, mFramebuffer.size().x, + mFramebuffer.size().y, GL_COLOR_BUFFER_BIT, GL_LINEAR); } void draw(IRenderer& renderer) override { @@ -1201,14 +1259,9 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept mRenderer.identityUv(); // mRenderer.uploadToShaderCommon(); // TODO - const glm::vec2 uvs[] = { - {0, 0}, - {1, 0}, - {0, 1}, - {1, 1} - }; - mRenderer.mRectangleVao.insertIfKeyMismatches(1, AArrayView(uvs), "OpenGLRenderViewToTexture"); - mRenderer.drawRectImpl({0, 0}, mFramebuffer.size()); + const glm::vec2 uvs[] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; + mRenderer.mBatchVao.insertIfKeyMismatches(1, std::span { uvs }, "OpenGLRenderViewToTexture"); + // mRenderer.drawRectImpl({0, 0}, mFramebuffer.size()); if (auto& p = AWindow::current()->profiling(); p && p->renderToTextureDecay) [[unlikely]] { // decays to fast. attach it to time using namespace std::chrono; @@ -1224,12 +1277,12 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept auto mainRenderingFB = gl::Framebuffer::current(); AUI_ASSERT(mainRenderingFB != nullptr); AUI_DEFER { - // restore. - glColorMask(true, true, true, true); - mainRenderingFB->bind(); - glEnable(GL_STENCIL_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - renderer.setStencilDepth(0); + // restore. + glColorMask(true, true, true, true); + mainRenderingFB->bind(); + glEnable(GL_STENCIL_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + renderer.setStencilDepth(0); }; mFramebuffer.bind(); glDisable(GL_STENCIL_TEST); @@ -1238,7 +1291,7 @@ _unique OpenGLRenderer::newRenderViewToTexture() noexcept shader->use(); shader->set(aui::ShaderUniforms::TRANSFORM, glm::mat4(1.f)); shader->set(aui::ShaderUniforms::COLOR, glm::vec4(0.5, 0.5, 0.5, 0.1)); - mRenderer.drawRectImpl({-1, -1}, {2, 2}); // offscreen + // mRenderer.drawRectImpl({-1, -1}, {2, 2}); // offscreen } } @@ -1276,45 +1329,45 @@ void OpenGLRenderer::backdrops(glm::ivec2 position, glm::ivec2 size, std::span areaOfInterest; - auto initAreaOfInterestIfEmpty = [&](glm::ivec2 fbSize){ - if (areaOfInterest) { - return; - } - - auto fb = getFramebufferForMultiPassEffect(fbSize); - AUI_ASSERT(glm::all(glm::lessThanEqual(glm::u32vec2(fbSize), fb->framebuffer.size()))); - source->bindForRead(); - fb->framebuffer.bindForWrite(); - - auto vertices = getVerticesForRect(position, size); - std::array transformedVertices{}; - for (size_t i = 0; i < vertices.size(); ++i) { - auto ndc = glm::vec2(mTransform * glm::vec4(vertices[i], 0, 1)); - transformedVertices[i] = glm::ivec2((ndc + 1.f) / 2.f * glm::vec2(source->supersampledSize())); - } - - auto p1 = transformedVertices.front(); - auto p2 = transformedVertices.back(); - glBlitFramebuffer(p1.x, p1.y, p2.x, p2.y, 0, 0, fbSize.x, fbSize.y, GL_COLOR_BUFFER_BIT, GL_LINEAR); - areaOfInterest = AreaOfInterest{ - .framebuffer = std::move(fb), - .size = fbSize, - }; + auto initAreaOfInterestIfEmpty = [&](glm::ivec2 fbSize) { + if (areaOfInterest) { + return; + } + + auto fb = getFramebufferForMultiPassEffect(fbSize); + AUI_ASSERT(glm::all(glm::lessThanEqual(glm::u32vec2(fbSize), fb->framebuffer.size()))); + source->bindForRead(); + fb->framebuffer.bindForWrite(); + + auto vertices = getVerticesForRect(position, size); + std::array transformedVertices {}; + for (size_t i = 0; i < vertices.size(); ++i) { + auto ndc = glm::vec2(mTransform * glm::vec4(vertices[i], 0, 1)); + transformedVertices[i] = glm::ivec2((ndc + 1.f) / 2.f * glm::vec2(source->supersampledSize())); + } + + auto p1 = transformedVertices.front(); + auto p2 = transformedVertices.back(); + glBlitFramebuffer(p1.x, p1.y, p2.x, p2.y, 0, 0, fbSize.x, fbSize.y, GL_COLOR_BUFFER_BIT, GL_LINEAR); + areaOfInterest = AreaOfInterest { + .framebuffer = std::move(fb), + .size = fbSize, + }; }; { glDisable(GL_STENCIL_TEST); AUI_DEFER { - source->bind(); - source->bindViewport(); - glEnable(GL_STENCIL_TEST); + source->bind(); + source->bindViewport(); + glEnable(GL_STENCIL_TEST); }; for (const auto& backdrop : backdrops) { RenderHints::PushState s(*this); std::visit( aui::lambda_overloaded { - [&](const ass::Backdrop::LiquidFluid& liquidFluid) { + [&](const ass::Backdrop::LiquidFluid& liquidFluid) { if (areaOfInterest) { throw AException("LiquidGlass must be the first effect in backdrop list."); } @@ -1343,7 +1396,7 @@ void OpenGLRenderer::backdrops(glm::ivec2 position, glm::ivec2 size, std::spanbind(1); areaOfInterest->framebuffer->rendertarget->texture().setupNearest(); -// areaOfInterest->framebuffer->rendertarget->texture().setupMirroredRepeat(); + // areaOfInterest->framebuffer->rendertarget->texture().setupMirroredRepeat(); areaOfInterest->framebuffer->rendertarget->texture().setupClampToEdge(); auto offscreen1 = getFramebufferForMultiPassEffect(size); @@ -1351,12 +1404,12 @@ void OpenGLRenderer::backdrops(glm::ivec2 position, glm::ivec2 size, std::spanframebuffer.bindViewport(); static auto shader = [&] { - auto shader = std::make_unique(); + auto shader = std::make_unique(); - shader->loadVertexShader( - std::string(aui::sl_gen::basic_uv::vsh::glsl120::Shader::code())); - shader->loadFragmentShader( - R"( + // shader->loadVertexShader( + // std::string(aui::sl_gen::basic_uv::vsh::glsl120::Shader::code())); + shader->loadFragmentShader( + R"( precision highp float; precision highp int; varying vec4 SL_inter_vertex; @@ -1375,12 +1428,12 @@ void main() { } )"); - aui::sl_gen::basic_uv::vsh::glsl120::Shader::setup(shader->handle()); - shader->compile(); - shader->use(); - shader->set(gl::Program::Uniform("uvmap"), 1); + // aui::sl_gen::basic_uv::vsh::glsl120::Shader::setup(shader->handle()); + shader->compile(); + shader->use(); + shader->set(gl::Program::Uniform("uvmap"), 1); - return shader; + return shader; }(); if (!shader) { @@ -1398,25 +1451,29 @@ void main() { shader->set(aui::ShaderUniforms::M2, m); // source framebuffer is slightly smaller than the framebuffer in area of interest, adjust it - shader->set(aui::ShaderUniforms::UV_SCALE, glm::vec2(areaOfInterest->size) / glm::vec2(areaOfInterest->framebuffer->framebuffer.size())); + shader->set( + aui::ShaderUniforms::UV_SCALE, + glm::vec2(areaOfInterest->size) / + glm::vec2(areaOfInterest->framebuffer->framebuffer.size())); } setTransformForced(glm::ortho( - 0.0f, static_cast(offscreen1->framebuffer.size().x) - 0.0f, - 0.f, static_cast(offscreen1->framebuffer.size().y) - 0.0f, -1.f, 1.f)); + 0.0f, static_cast(offscreen1->framebuffer.size().x) - 0.0f, 0.f, + static_cast(offscreen1->framebuffer.size().y) - 0.0f, -1.f, 1.f)); gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, mTransform); identityUv(); glDisable(GL_BLEND); - drawRectImpl({}, size); + // TODO: replace 0 with zIndex and add transform, then uncomment + // drawRectImpl({}, size, 0); glEnable(GL_BLEND); areaOfInterest = AreaOfInterest { .framebuffer = std::move(offscreen1), .size = size, }; - }, - [&](const ass::Backdrop::GaussianBlurCustom& gaussianBlur) { + }, + [&](const ass::Backdrop::GaussianBlurCustom& gaussianBlur) { const auto radius = int(gaussianBlur.radius.getValuePx()); if (radius <= 1) { return; @@ -1435,25 +1492,24 @@ void main() { offscreen1->framebuffer.bindViewport(); setTransformForced(glm::ortho( - 0.0f, static_cast(offscreen1->framebuffer.size().x) - 0.0f, - 0.f, static_cast(offscreen1->framebuffer.size().y) - 0.0f, -1.f, 1.f)); + 0.0f, static_cast(offscreen1->framebuffer.size().x) - 0.0f, 0.f, + static_cast(offscreen1->framebuffer.size().y) - 0.0f, -1.f, 1.f)); struct BlurShaders { std::unique_ptr shader; }; static AUnorderedMap blurShaders; auto& blurShader = blurShaders.getOrInsert(radius, [&] { - BlurShaders result { - .shader = std::make_unique(), - }; + BlurShaders result { + .shader = std::make_unique(), + }; - auto kernel = aui::detail::gaussianKernel(radius); + auto kernel = aui::detail::gaussianKernel(radius); - result.shader->loadVertexShader( - std::string(aui::sl_gen::basic_uv::vsh::glsl120::Shader::code())); - result.shader->loadFragmentShader( - fmt::format( - R"( + // result.shader->loadVertexShader( + // std::string(aui::sl_gen::basic_uv::vsh::glsl120::Shader::code())); + result.shader->loadFragmentShader(fmt::format( + R"( precision highp float; precision highp int; varying vec2 SL_inter_uv; @@ -1474,15 +1530,14 @@ void main() {{ gl_FragColor = vec4(accumulator, 1.0); }} )", - fmt::arg("radius", radius), - fmt::arg("kernel_size", kernel.size()))); + fmt::arg("radius", radius), fmt::arg("kernel_size", kernel.size()))); - aui::sl_gen::basic_uv::vsh::glsl120::Shader::setup(result.shader->handle()); - result.shader->compile(); - result.shader->use(); - result.shader->setArray(aui::ShaderUniforms::KERNEL, kernel); + // aui::sl_gen::basic_uv::vsh::glsl120::Shader::setup(result.shader->handle()); + result.shader->compile(); + result.shader->use(); + result.shader->setArray(aui::ShaderUniforms::KERNEL, kernel); - return result; + return result; }); if (!blurShader.shader) { @@ -1492,17 +1547,19 @@ void main() {{ blurShader.shader->use(); { - auto stepSize = glm::vec2(1.f / areaOfInterest->framebuffer->framebuffer.supersampledSize().x, 0.f); + auto stepSize = + glm::vec2(1.f / areaOfInterest->framebuffer->framebuffer.supersampledSize().x, 0.f); blurShader.shader->set(aui::ShaderUniforms::PIXEL_TO_UV, stepSize); blurShader.shader->set( aui::ShaderUniforms::M2, glm::vec2(areaOfInterest->size) / - glm::vec2(areaOfInterest->framebuffer->framebuffer.supersampledSize()) - - stepSize / 2.f /* small bias to avoid dirty edges */); + glm::vec2(areaOfInterest->framebuffer->framebuffer.supersampledSize()) - + stepSize / 2.f /* small bias to avoid dirty edges */); } gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, mTransform); identityUv(); - drawRectImpl({}, sizeDownscaled); + // TODO: replace 0 with zIndex and add transform, then uncomment + // drawRectImpl({}, sizeDownscaled, 0); areaOfInterest.reset(); // release borrowed framebuffer before requesting another one @@ -1512,8 +1569,8 @@ void main() {{ offscreen2->framebuffer.bindViewport(); setTransformForced(glm::ortho( - 0.0f, static_cast(offscreen2->framebuffer.size().x) - 0.0f, - 0.f, static_cast(offscreen2->framebuffer.size().y) - 0.0f, -1.f, 1.f)); + 0.0f, static_cast(offscreen2->framebuffer.size().x) - 0.0f, 0.f, + static_cast(offscreen2->framebuffer.size().y) - 0.0f, -1.f, 1.f)); blurShader.shader->set(aui::ShaderUniforms::M1, glm::vec2(0.0)); @@ -1523,16 +1580,17 @@ void main() {{ blurShader.shader->set( aui::ShaderUniforms::M2, glm::vec2(sizeDownscaled) / glm::vec2(offscreen1->framebuffer.supersampledSize()) - - stepSize / 2.f); + stepSize / 2.f); } gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, mTransform); - drawRectImpl({}, sizeDownscaled); + // TODO: replace 0 with zIndex and add transform, then uncomment + // drawRectImpl({}, sizeDownscaled, 0); areaOfInterest = AreaOfInterest { .framebuffer = std::move(offscreen2), .size = sizeDownscaled, }; - }, + }, }, backdrop); } @@ -1546,12 +1604,12 @@ void main() {{ glm::vec2(areaOfInterest->size - 1 /* small bias to avoid dirty edges */) / glm::vec2(areaOfInterest->framebuffer->framebuffer.supersampledSize()); const glm::vec2 uvs[] = { - { 0, 0}, + { 0, 0 }, { uv.x, 0 }, - { 0, uv.y }, + { 0, uv.y }, { uv.x, uv.y }, }; - mRectangleVao.insertIfKeyMismatches(1, AArrayView(uvs), "backdrops"); + mBatchVao.insertIfKeyMismatches(1, std::span { uvs }, "backdrops"); } auto& texture = areaOfInterest->framebuffer->rendertarget->texture(); @@ -1560,7 +1618,8 @@ void main() {{ texture.setupLinear(); gl::Program::currentShader()->set(aui::ShaderUniforms::TRANSFORM, mTransform); - drawRectImpl(position, size); + // TODO: replace 0 with zIndex and add transform, then uncomment + // drawRectImpl(position, size, 0); } OpenGLRenderer::FramebufferFromPool OpenGLRenderer::getFramebufferForMultiPassEffect(glm::uvec2 minRequiredSize) { @@ -1577,38 +1636,39 @@ OpenGLRenderer::FramebufferFromPool OpenGLRenderer::getFramebufferForMultiPassEf return aui::ptr::manage_unique( [&]() -> FramebufferWithTextureRT* { - auto applicableSizeOnly = - mFramebuffersForMultiPassEffectsPool | ranges::views::filter([&](const auto& fb) { - return glm::all(glm::greaterThanEqual(fb->framebuffer.size(), minRequiredSize)); - }); - auto smallestFb = [](ranges::range auto& rng) { - return ranges::min_element(rng, std::less<> {}, [](const auto& fb) { - return fb->framebuffer.size().x * fb->framebuffer.size().y; - }); - }; - - auto release = [&](OffscreenFramebufferPool::iterator it) { - auto object = std::exchange(*it, {}); - mFramebuffersForMultiPassEffectsPool.erase(it); - return object.release(); - }; - - if (auto it = smallestFb(applicableSizeOnly); it != applicableSizeOnly.end()) { - return release(it.base()); - } + auto applicableSizeOnly = + mFramebuffersForMultiPassEffectsPool | ranges::views::filter([&](const auto& fb) { + return glm::all(glm::greaterThanEqual(fb->framebuffer.size(), minRequiredSize)); + }); + auto smallestFb = [](ranges::range auto& rng) { + return ranges::min_element(rng, std::less<> {}, [](const auto& fb) { + return fb->framebuffer.size().x * fb->framebuffer.size().y; + }); + }; + + auto release = [&](OffscreenFramebufferPool::iterator it) { + auto object = std::exchange(*it, {}); + mFramebuffersForMultiPassEffectsPool.erase(it); + return object.release(); + }; + + if (auto it = smallestFb(applicableSizeOnly); it != applicableSizeOnly.end()) { + return release(it.base()); + } - if (auto it = smallestFb(mFramebuffersForMultiPassEffectsPool); - it != mFramebuffersForMultiPassEffectsPool.end()) { - (*it)->framebuffer.resize(glm::max((*it)->framebuffer.size(), minRequiredSize)); - return release(it); - } + if (auto it = smallestFb(mFramebuffersForMultiPassEffectsPool); + it != mFramebuffersForMultiPassEffectsPool.end()) { + (*it)->framebuffer.resize(glm::max((*it)->framebuffer.size(), minRequiredSize)); + return release(it); + } - auto object = std::make_unique(); - object->framebuffer.resize(minRequiredSize); - object->rendertarget = _new>(); - object->framebuffer.attach(object->rendertarget, GL_COLOR_ATTACHMENT0); + auto object = std::make_unique(); + object->framebuffer.resize(minRequiredSize); + object->rendertarget = + _new>(); + object->framebuffer.attach(object->rendertarget, GL_COLOR_ATTACHMENT0); - return object.release(); + return object.release(); }(), FramebufferBackToPool { this }); } diff --git a/aui.views/src/AUI/GL/OpenGLRenderer.h b/aui.views/src/AUI/GL/OpenGLRenderer.h index 33ef92cfd..3c005d4da 100644 --- a/aui.views/src/AUI/GL/OpenGLRenderer.h +++ b/aui.views/src/AUI/GL/OpenGLRenderer.h @@ -12,12 +12,18 @@ #pragma once +#include +#include #include "AUI/GL/Program.h" #include "AUI/GL/Framebuffer.h" #include "AUI/GL/Vao.h" #include "AUI/Render/ABorderStyle.h" #include "AUI/GL/RenderTarget/TextureRenderTarget.h" +#include "AUI/Render/ABrush.h" #include "IBatchingRenderer.h" +#include "glm/detail/qualifier.hpp" +#include "glm/fwd.hpp" +#include "glm/gtc/type_ptr.hpp" class OpenGLRenderer final: public IBatchingRenderer { friend class OpenGLPrerenderedString; @@ -65,9 +71,12 @@ friend class OpenGLMultiStringCanvas; AOptional mSymbolShaderSubPixel; AOptional mSquareSectorShader; AOptional mLineSolidDashedShader; - gl::Vao mRectangleVao; - gl::Vao mBorderVao; + static constexpr size_t BATCH_BUFFER_SIZE = 40000; + std::array mBatchVertices; + std::array::iterator mCurrentBatchVertex; + gl::Vao mBatchVao; gl::Texture2D mGradientTexture; + gl::Program* mBatchShader; struct CharacterData { @@ -126,17 +135,47 @@ friend class OpenGLMultiStringCanvas; */ FramebufferFromPool getFramebufferForMultiPassEffect(glm::uvec2 minRequiredSize); - void drawRectImpl(glm::vec2 position, glm::vec2 size); + static constexpr size_t Z_DEPTH = 1000; + template + void appendRect(const glm::vec2 position, const glm::vec2 size, const glm::mat4 transform, T additionalData) { + static_assert(std::is_trivially_copyable_v); + float x = position.x; + float y = position.y; + float w = x + size.x; + float h = y + size.y; + float z = -1.f; + + std::array verticies { + glm::vec3 { x, h, z }, + glm::vec3 { w, h, z }, + glm::vec3 { x, y, z }, + glm::vec3 { w, y, z }, + }; + + for (const auto& vertex : verticies) { + glm::vec4 vertexTransformed = transform * glm::vec4(vertex, 1.0f); + appendVertexData(vertexTransformed); + appendVertexData(additionalData); + } + } + + template + void appendVertexData(T data) { + std::memcpy(mCurrentBatchVertex, &data, sizeof(T)); + mCurrentBatchVertex += sizeof(T) / sizeof(float); + } + ASolidBrush::Data solidBrush(const IBatchingRenderer::Cmd& cmd, const ASolidBrush& brush, gl::Program& shader); + ALinearGradientBrush::Data gradientBrush(const IBatchingRenderer::Cmd& cmd, const ALinearGradientBrush& brush, gl::Program& shader); private: // Helper methods that perform the actual rendering for each command. - void renderRectangle(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size); - void renderRoundedRectangle(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius); - void renderRectangleBorder(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float lineWidth); - void renderRoundedRectangleBorder(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius, int borderWidth); - void renderBoxShadow(const Cmd& cmd, glm::vec2 position, glm::vec2 size, float blurRadius, const AColor& color); - void renderBoxShadowInner(const Cmd& cmd, glm::vec2 position, glm::vec2 size, float blurRadius, float spreadRadius, float borderRadius, const AColor& color, glm::vec2 offset); + void renderRectangle(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, const zIndex_t zIndex); + void renderRoundedRectangle(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius, const zIndex_t zIndex); + void renderRectangleBorder(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float lineWidth, const zIndex_t zIndex); + void renderRoundedRectangleBorder(const Cmd& cmd, const ABrush& brush, glm::vec2 position, glm::vec2 size, float radius, int borderWidth, const zIndex_t zIndex); + void renderBoxShadow(const Cmd& cmd, glm::vec2 position, glm::vec2 size, float blurRadius, const AColor& color, const zIndex_t zIndex); + void renderBoxShadowInner(const Cmd& cmd, glm::vec2 position, glm::vec2 size, float blurRadius, float spreadRadius, float borderRadius, const AColor& color, glm::vec2 offset, const zIndex_t zIndex); void renderString(const Cmd& cmd, glm::vec2 position, const AString& string, const AFontStyle& fs); void renderLines(const Cmd& cmd, const ABrush& brush, AArrayView points, const ABorderStyle& style, AMetric width); void renderLines(const Cmd& cmd, const ABrush& brush, AArrayView> points, const ABorderStyle& style, AMetric width); diff --git a/aui.views/src/AUI/GL/Program.cpp b/aui.views/src/AUI/GL/Program.cpp index dff72f03d..0c91f9572 100644 --- a/aui.views/src/AUI/GL/Program.cpp +++ b/aui.views/src/AUI/GL/Program.cpp @@ -112,6 +112,8 @@ void gl::Program::compile() { void gl::Program::use() const { gl::State::useProgram(mProgram); currentShader() = const_cast(this); + if (mSetupCallback) + mSetupCallback(); } void gl::Program::bindAttribute(uint32_t index, const AString& name) { @@ -120,6 +122,10 @@ void gl::Program::bindAttribute(uint32_t index, const AString& name) { glBindAttribLocation(mProgram, index, name.toStdString().c_str()); } +void gl::Program::setSetupCallback(SetupCallback value) { + mSetupCallback = value; +} + void gl::Program::set(const gl::Program::Uniform& uniform, glm::mat4 value) const { if (sameAsCache(uniform, value)) return; diff --git a/aui.views/src/AUI/GL/Program.h b/aui.views/src/AUI/GL/Program.h index f90ffd77d..3c2afd3a8 100644 --- a/aui.views/src/AUI/GL/Program.h +++ b/aui.views/src/AUI/GL/Program.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -43,6 +44,8 @@ struct GLSLOptions { class API_AUI_VIEWS Program: public aui::noncopyable { public: + using SetupCallback = void(); + class API_AUI_VIEWS Uniform { private: const char* mUniformString; @@ -73,6 +76,7 @@ class API_AUI_VIEWS Program: public aui::noncopyable { } void compile(); void bindAttribute(uint32_t index, const AString& name); + void setSetupCallback(SetupCallback value); void use() const; ~Program(); Program(const Program&) = delete; @@ -113,6 +117,7 @@ class API_AUI_VIEWS Program: public aui::noncopyable { uint32_t mVertex = 0; uint32_t mFragment = 0; + std::function mSetupCallback; class UniformState { public: enum Value { UNINITIALIZED = -2, DOES_NOT_EXIST = -1 }; diff --git a/aui.views/src/AUI/GL/Vao.cpp b/aui.views/src/AUI/GL/Vao.cpp index 553d95413..aae8d7417 100644 --- a/aui.views/src/AUI/GL/Vao.cpp +++ b/aui.views/src/AUI/GL/Vao.cpp @@ -22,6 +22,8 @@ #include "Vao.h" #include +#include "AUI/GL/gl.h" +#include "AUI/Util/Assert.h" #include "State.h" gl::Vao::Vao() { @@ -64,6 +66,7 @@ void gl::Vao::insertIfKeyMismatches( goAhead: insert(index, data, dataSize, vertexSize, dataType, key); } + void gl::Vao::insert( GLuint index, const char* data, GLsizeiptr dataSize, GLuint vertexSize, GLenum dataType, const char* key) { bind(); @@ -91,12 +94,12 @@ void gl::Vao::insert( mBuffers[index].lastModifierKey = key; - auto signature = uint32_t(vertexSize) ^ dataType; - if (newFlag || mBuffers[index].signature != signature) { - glEnableVertexAttribArray(index); - glVertexAttribPointer(index, vertexSize, dataType, GL_FALSE, 0, nullptr); - mBuffers[index].signature = signature; - } + // auto signature = uint32_t(vertexSize) ^ dataType; + // if (newFlag || mBuffers[index].signature != signature) { + // glEnableVertexAttribArray(index); + // glVertexAttribPointer(index, vertexSize, dataType, GL_FALSE, 0, nullptr); + // mBuffers[index].signature = signature; + // } } void gl::Vao::insertInteger(GLuint index, const char* data, GLsizeiptr dataSize, GLuint vertexSize, GLenum dataType) { @@ -134,7 +137,7 @@ void gl::Vao::drawElements(GLenum type) { glDrawElements(type, mIndicesCount, mIndicesType, 0); } -void gl::Vao::indices(AArrayView data) { +void gl::Vao::indices(std::span data) { bind(); GLenum drawType = GL_DYNAMIC_DRAW; if (mIndicesBuffer == 0) { @@ -144,11 +147,33 @@ void gl::Vao::indices(AArrayView data) { } mIndicesCount = static_cast(data.size()); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndicesBuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.sizeInBytes(), data.data(), drawType); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.size_bytes(), data.data(), drawType); mIndicesType = GL_UNSIGNED_INT; } -void gl::Vao::indices(AArrayView data) { +static std::vector generateQuadIndices(const size_t vertexCount) { + AUI_ASSERT(vertexCount % 4 == 0); + + const size_t quadCount = vertexCount / 4; + std::vector indices; + indices.reserve(quadCount * 6); + + for (size_t quad = 0; quad < quadCount; ++quad) { + const unsigned short baseVertex = static_cast(quad * 4); + + indices.push_back(baseVertex + 0); + indices.push_back(baseVertex + 1); + indices.push_back(baseVertex + 2); + + indices.push_back(baseVertex + 2); + indices.push_back(baseVertex + 1); + indices.push_back(baseVertex + 3); + } + + return indices; +} + +void gl::Vao::indicesByCount(const size_t vertexCount) { bind(); GLenum drawType = GL_DYNAMIC_DRAW; if (mIndicesBuffer == 0) { @@ -156,8 +181,10 @@ void gl::Vao::indices(AArrayView data) { assert(mIndicesBuffer); drawType = GL_STATIC_DRAW; } + auto indices = std::move(generateQuadIndices(vertexCount)); + auto data = std::span{indices}; mIndicesCount = static_cast(data.size()); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndicesBuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.sizeInBytes(), data.data(), drawType); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.size_bytes(), data.data(), drawType); mIndicesType = GL_UNSIGNED_SHORT; } diff --git a/aui.views/src/AUI/GL/Vao.h b/aui.views/src/AUI/GL/Vao.h index 38d0785b5..1e33ea054 100644 --- a/aui.views/src/AUI/GL/Vao.h +++ b/aui.views/src/AUI/GL/Vao.h @@ -14,7 +14,6 @@ #include "AUI/GL/gl.h" #include #include "AUI/Common/AVector.h" -#include "AUI/Util/AArrayView.h" #include "AUI/Views.h" namespace gl { @@ -53,12 +52,12 @@ class API_AUI_VIEWS Vao { * @param data vertex data * @param key see gl::Vao::Buffer::lastModifierKey */ - template - void insert(GLuint index, AArrayView data, const char* key) { + template + void insert(GLuint index, std::span data, const char* key) { if constexpr (std::is_same_v) { - insertInteger(index, (const char*) data.data(), data.sizeInBytes(), 1, GL_UNSIGNED_INT); + insertInteger(index, (const char*) data.data(), data.size_bytes(), 1, GL_UNSIGNED_INT); } else { - insert(index, (const char*) data.data(), data.sizeInBytes(), sizeof(T) / sizeof(float), GL_FLOAT, key); + insert(index, (const char*) data.data(), data.size_bytes(), sizeof(T) / sizeof(float), GL_FLOAT, key); } } @@ -68,23 +67,25 @@ class API_AUI_VIEWS Vao { * @param data vertex data * @param key see gl::Vao::Buffer::lastModifierKey */ - template - void insertIfKeyMismatches(GLuint index, AArrayView data, const char* key) { + template + void insertIfKeyMismatches(GLuint index, std::span data, const char* key) { insertIfKeyMismatches( - index, (const char*) data.data(), data.sizeInBytes(), sizeof(T) / sizeof(float), GL_FLOAT, key); + index, (const char*) data.data(), data.size_bytes(), sizeof(T) / sizeof(float), GL_FLOAT, key); } /** * @brief Uploads VBO indices * @param data indices */ - void indices(AArrayView data); + void indices(std::span data); /** * @brief Uploads VBO indices * @param data indices */ - void indices(AArrayView data); + void indices(std::span data); + + void indicesByCount(const size_t vertexCount); void drawArrays(GLenum type, GLsizei count); diff --git a/aui.views/src/AUI/Image/AAnimatedDrawable.cpp b/aui.views/src/AUI/Image/AAnimatedDrawable.cpp index 0404b9bcb..eedc2600a 100644 --- a/aui.views/src/AUI/Image/AAnimatedDrawable.cpp +++ b/aui.views/src/AUI/Image/AAnimatedDrawable.cpp @@ -42,7 +42,8 @@ void AAnimatedDrawable::draw(IRenderer& render, const IDrawable::Params& params) params.cropUvTopLeft, params.cropUvBottomRight, params.imageRendering, - }, params.offset, params.size); + // TODO: use actual z index here + }, params.offset, 0, params.size); } glm::ivec2 AAnimatedDrawable::getSizeHint() { diff --git a/aui.views/src/AUI/Image/SvgDrawable.cpp b/aui.views/src/AUI/Image/SvgDrawable.cpp index a66d2b970..db21e5280 100644 --- a/aui.views/src/AUI/Image/SvgDrawable.cpp +++ b/aui.views/src/AUI/Image/SvgDrawable.cpp @@ -53,6 +53,8 @@ void AVectorDrawable::draw(IRenderer& render, const IDrawable::Params& params) { .repeat = params.repeat, }, params.offset, + // TODO: replace with actual zindex + 0, size); }; for (auto& p : mRasterized) { diff --git a/aui.views/src/AUI/Platform/OpenGLRenderingContext.cpp b/aui.views/src/AUI/Platform/OpenGLRenderingContext.cpp index f291c3a16..b29acd41e 100644 --- a/aui.views/src/AUI/Platform/OpenGLRenderingContext.cpp +++ b/aui.views/src/AUI/Platform/OpenGLRenderingContext.cpp @@ -83,4 +83,4 @@ uint32_t OpenGLRenderingContext::getSupersamplingRatio() const noexcept { return fb->supersamlingRatio(); } return 1; -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/Render/ABrush.h b/aui.views/src/AUI/Render/ABrush.h index d15f8dba2..c6e3fc7bd 100644 --- a/aui.views/src/AUI/Render/ABrush.h +++ b/aui.views/src/AUI/Render/ABrush.h @@ -24,13 +24,16 @@ #include "AUI/Enum/ImageRendering.h" #include "AUI/Util/AAngleRadians.h" #include "AUI/Traits/values.h" +#include "glm/fwd.hpp" /** * The simplest brush which used single solid color to fill. */ struct ASolidBrush { - AColor solidColor = AColor::WHITE; + AColor color = AColor::WHITE; + + using Data = glm::vec4; }; @@ -46,12 +49,8 @@ struct ACustomShaderBrush { * Brush which produces linear gradient by rectangle. */ struct ALinearGradientBrush { - struct ColorEntry { - aui::float_within_0_1 position; - AColor color; - }; - AVector colors; - + AColor colorStart; + AColor colorEnd; /** * @brief Clockwise gradient angle. * @details @@ -60,6 +59,12 @@ struct ALinearGradientBrush { * direction. */ AAngleRadians rotation = 180_deg; + + using Data = struct { + AColor colorStart; + AColor colorEnd; + float rotation; + }; }; class ITexture; @@ -110,4 +115,4 @@ struct ATexturedBrush { using ABrush = std::variant; \ No newline at end of file + ACustomShaderBrush>; diff --git a/aui.views/src/AUI/Render/ARenderContext.h b/aui.views/src/AUI/Render/ARenderContext.h index 23df671b4..6ab36ce27 100644 --- a/aui.views/src/AUI/Render/ARenderContext.h +++ b/aui.views/src/AUI/Render/ARenderContext.h @@ -29,7 +29,7 @@ class IRenderer; * View containers are also responsible to skip rendering of views that are outside of the clipping. * * ARenderContext is useful only for container views. - * + * * ARenderContext passed to the view (possibly AViewContainer) describes an axis aligned bounding box relative * to it's coordinate space (position). * diff --git a/aui.views/src/AUI/Render/Brush/Gradient.h b/aui.views/src/AUI/Render/Brush/Gradient.h index 7f874482a..0581dfc24 100644 --- a/aui.views/src/AUI/Render/Brush/Gradient.h +++ b/aui.views/src/AUI/Render/Brush/Gradient.h @@ -21,9 +21,8 @@ namespace aui::render::brush::gradient { glm::mat3 matrix; Helper(const ALinearGradientBrush& brush) { - for (const auto& c : brush.colors) { - colors.push_back(glm::uvec4(c.color * 255.f)); - } + colors.push_back(glm::uvec4(brush.colorStart * 255.f)); + colors.push_back(glm::uvec4(brush.colorEnd * 255.f)); //float actualEdgeUvPosition = (0.5f - 0.05f /* bias to make ideal color edge */) / float(colors.size()); float actualEdgeUvPosition = 0.f; // temporary @@ -66,4 +65,4 @@ namespace aui::render::brush::gradient { return AImageView({(const char*)colors.data(), colors.sizeInBytes()}, {colors.size(), 1}, APixelFormat::RGBA_BYTE); } }; -} \ No newline at end of file +} diff --git a/aui.views/src/AUI/Render/IRenderer.cpp b/aui.views/src/AUI/Render/IRenderer.cpp index 6f5962e8f..234e55bc4 100644 --- a/aui.views/src/AUI/Render/IRenderer.cpp +++ b/aui.views/src/AUI/Render/IRenderer.cpp @@ -9,10 +9,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include #include "IRenderer.h" -void IRenderer::stub(glm::vec2 position, glm::vec2 size) { rectangle(ASolidBrush { 0xa0a0a0_rgb }, { 0, 0 }, size); } +void IRenderer::stub(glm::vec2 position, glm::vec2 size) { rectangle(ASolidBrush { 0xa0a0a0_rgb }, { 0, 0 }, std::numeric_limits::max(), size); } void IRenderer::backdrops(glm::ivec2 position, glm::ivec2 size, std::span backdrops) { stub(position, size); diff --git a/aui.views/src/AUI/Render/IRenderer.h b/aui.views/src/AUI/Render/IRenderer.h index 475f55073..fee266d20 100644 --- a/aui.views/src/AUI/Render/IRenderer.h +++ b/aui.views/src/AUI/Render/IRenderer.h @@ -30,8 +30,6 @@ class AColor; class AWindowBase; - - /** * Blending mode. *

Terminology used in this documentation:

@@ -255,6 +253,7 @@ class IRenderer: public aui::noncopyable { */ virtual void rectangle(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size) = 0; @@ -267,6 +266,7 @@ class IRenderer: public aui::noncopyable { */ virtual void roundedRectangle(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float radius) = 0; @@ -279,6 +279,7 @@ class IRenderer: public aui::noncopyable { */ virtual void rectangleBorder(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float lineWidth = 1.f) = 0; /** @@ -291,6 +292,7 @@ class IRenderer: public aui::noncopyable { */ virtual void roundedRectangleBorder(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float radius, int borderWidth) = 0; @@ -304,6 +306,7 @@ class IRenderer: public aui::noncopyable { * @param color shadow color */ virtual void boxShadow(glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float blurRadius, const AColor& color) = 0; @@ -320,6 +323,7 @@ class IRenderer: public aui::noncopyable { * of a simple rectangle position offset. */ virtual void boxShadowInner(glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float blurRadius, float spreadRadius, @@ -425,7 +429,7 @@ class IRenderer: public aui::noncopyable { const glm::vec2& size, AAngleRadians begin, AAngleRadians end) = 0; - + /** * @brief Sets the color which is multiplied with any brush. * @param color color diff --git a/aui.views/src/AUI/SL/SL.h b/aui.views/src/AUI/SL/SL.h index 96f9a0f57..80ed275b8 100644 --- a/aui.views/src/AUI/SL/SL.h +++ b/aui.views/src/AUI/SL/SL.h @@ -12,9 +12,7 @@ #pragma once #include "AUI/Enum/ImageRendering.h" -#include "AUI/Image/AImage.h" #include "glm/common.hpp" -#include "glm/ext/quaternion_common.hpp" #include "glm/fwd.hpp" #include #include diff --git a/aui.views/src/AUI/Software/SoftwareRenderer.cpp b/aui.views/src/AUI/Software/SoftwareRenderer.cpp index f15a4c78c..93bf116b7 100644 --- a/aui.views/src/AUI/Software/SoftwareRenderer.cpp +++ b/aui.views/src/AUI/Software/SoftwareRenderer.cpp @@ -21,9 +21,9 @@ #include "SoftwareTexture.h" #include "AUI/Render/Brush/Gradient.h" #include "glm/vector_relational.hpp" -#include -#include -#include +// #include +// #include +// #include struct BrushHelper { SoftwareRenderer* renderer; @@ -38,11 +38,11 @@ struct BrushHelper { glm::ivec2& position) : renderer(renderer), x(x), y(y), end(end), position(position) {} void operator()(const ASolidBrush& brush) noexcept { - using namespace aui::sl_gen::rect_solid::fsh::software; - - renderer->putPixel({x, y}, Shader::entry({}, Shader::Uniform { - .color = renderer->getColor() * brush.solidColor - }).albedo); + // using namespace aui::sl_gen::rect_solid::fsh::software; + // + // renderer->putPixel({x, y}, Shader::entry({}, Shader::Uniform { + // .color = renderer->getColor() * brush.solidColor + // }).albedo); } void operator()(const ATexturedBrush& brush) noexcept { @@ -77,18 +77,18 @@ struct BrushHelper { void operator()(const ALinearGradientBrush& brush) noexcept { - using namespace aui::sl_gen::rect_gradient::fsh::software; - - aui::render::brush::gradient::Helper h(brush); - const auto output = Shader::entry({.uv = calculateUv()}, - { - //.gradientMap = aui::sl_gen::Texture2D(h.gradientMap(), ImageRendering::SMOOTH), - .color1 = h.colors[0], - .color2 = h.colors[1], - .matUv = h.matrix, - .color = renderer->getColor() - }); - renderer->putPixel({ x, y }, output.albedo); + // using namespace aui::sl_gen::rect_gradient::fsh::software; + // + // aui::render::brush::gradient::Helper h(brush); + // const auto output = Shader::entry({.uv = calculateUv()}, + // { + // //.gradientMap = aui::sl_gen::Texture2D(h.gradientMap(), ImageRendering::SMOOTH), + // .color1 = h.colors[0], + // .color2 = h.colors[1], + // .matUv = h.matrix, + // .color = renderer->getColor() + // }); + // renderer->putPixel({ x, y }, output.albedo); } void operator()(const ACustomShaderBrush& brush) noexcept { @@ -181,6 +181,7 @@ glm::mat4 SoftwareRenderer::getProjectionMatrix() const { void SoftwareRenderer::rectangle(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size) { auto transformedPosition = glm::ivec2(mTransform * glm::vec4(position, 1.f, 1.f)); auto end = transformedPosition + glm::ivec2(size); @@ -198,6 +199,7 @@ void SoftwareRenderer::rectangle(const ABrush& brush, void SoftwareRenderer::roundedRectangle(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float radius) { RoundedRect r(int(radius), glm::ivec2(size), glm::ivec2(mTransform * glm::vec4(position, 1.f, 1.f))); @@ -222,16 +224,18 @@ void SoftwareRenderer::roundedRectangle(const ABrush& brush, void SoftwareRenderer::rectangleBorder(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float lineWidth) { - rectangle(brush, position, {size.x, lineWidth}); - rectangle(brush, position + glm::vec2{0, size.y - lineWidth}, {size.x, lineWidth}); - rectangle(brush, position + glm::vec2{0, lineWidth}, {lineWidth, size.y - 2 * lineWidth}); - rectangle(brush, position + glm::vec2{size.x - lineWidth, lineWidth}, {lineWidth, size.y - 2 * lineWidth}); + rectangle(brush, position, 0, {size.x, lineWidth}); + rectangle(brush, position + glm::vec2{0, size.y - lineWidth}, 0, {size.x, lineWidth}); + rectangle(brush, position + glm::vec2{0, lineWidth}, 0, {lineWidth, size.y - 2 * lineWidth}); + rectangle(brush, position + glm::vec2{size.x - lineWidth, lineWidth}, 0, {lineWidth, size.y - 2 * lineWidth}); } void SoftwareRenderer::roundedRectangleBorder(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float radius, int borderWidth) { @@ -268,6 +272,7 @@ void SoftwareRenderer::roundedRectangleBorder(const ABrush& brush, } void SoftwareRenderer::boxShadow(glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float blurRadius, const AColor& color) { @@ -279,30 +284,31 @@ void SoftwareRenderer::boxShadow(glm::vec2 position, auto iSize = glm::ivec2(size + blurRadius * 2.f); - using namespace aui::sl_gen::shadow::fsh::software; - const Shader::Uniform uniform{ - .color = mColor * color, - .lower = transformedPos + size, - .upper = transformedPos, - .sigma = blurRadius / 2.f, - }; - - for (int y = 0; y < iSize.y; ++y) { - for (int x = 0; x < iSize.x; ++x) { - const auto result = Shader::entry(Shader::Inter { - .vertex = glm::ivec4(iTransformedPos + glm::ivec2{x, y}, 0, 1), - }, uniform).albedo; - - /* - glm::vec4 query = glm::vec4(pass_uv - glm::vec2(lower), pass_uv - glm::vec2(upper)); - glm::vec4 integral = 0.5f + 0.5f * erf(query * (glm::sqrt(0.5f) / sigma)); - float alpha = glm::clamp((integral.z - integral.x) * (integral.w - integral.y), 0.0f, 1.0f); -*/ - putPixel(iTransformedPos + glm::ivec2{ x, y }, result); - } - } +// using namespace aui::sl_gen::shadow::fsh::software; +// const Shader::Uniform uniform{ +// .color = mColor * color, +// .lower = transformedPos + size, +// .upper = transformedPos, +// .sigma = blurRadius / 2.f, +// }; +// +// for (int y = 0; y < iSize.y; ++y) { +// for (int x = 0; x < iSize.x; ++x) { +// const auto result = Shader::entry(Shader::Inter { +// .vertex = glm::ivec4(iTransformedPos + glm::ivec2{x, y}, 0, 1), +// }, uniform).albedo; +// +// /* +// glm::vec4 query = glm::vec4(pass_uv - glm::vec2(lower), pass_uv - glm::vec2(upper)); +// glm::vec4 integral = 0.5f + 0.5f * erf(query * (glm::sqrt(0.5f) / sigma)); +// float alpha = glm::clamp((integral.z - integral.x) * (integral.w - integral.y), 0.0f, 1.0f); +// */ +// putPixel(iTransformedPos + glm::ivec2{ x, y }, result); +// } +// } } void SoftwareRenderer::boxShadowInner(glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float blurRadius, float spreadRadius, @@ -317,28 +323,28 @@ void SoftwareRenderer::boxShadowInner(glm::vec2 position, auto iSize = glm::ivec2(size + blurRadius * 2.f); - using namespace aui::sl_gen::shadow::fsh::software; - const Shader::Uniform uniform{ - .color = mColor * color, - .lower = size, - .upper = transformedPos, - .sigma = blurRadius / 2.f, - }; + // using namespace aui::sl_gen::shadow::fsh::software; + // const Shader::Uniform uniform{ + // .color = mColor * color, + // .lower = size, + // .upper = transformedPos, + // .sigma = blurRadius / 2.f, + // }; - for (int y = 0; y < iSize.y; ++y) { - for (int x = 0; x < iSize.x; ++x) { - const auto result = Shader::entry(Shader::Inter { - .vertex = glm::vec4(transformedPos + glm::vec2{x, y}, 0.f, 1.f), - }, uniform).albedo; - - /* - glm::vec4 query = glm::vec4(pass_uv - glm::vec2(lower), pass_uv - glm::vec2(upper)); - glm::vec4 integral = 0.5f + 0.5f * erf(query * (glm::sqrt(0.5f) / sigma)); - float alpha = glm::clamp((integral.z - integral.x) * (integral.w - integral.y), 0.0f, 1.0f); -*/ - putPixel(iTransformedPos + glm::ivec2{ x, y }, result); - } - } +// for (int y = 0; y < iSize.y; ++y) { +// for (int x = 0; x < iSize.x; ++x) { +// const auto result = Shader::entry(Shader::Inter { +// .vertex = glm::vec4(transformedPos + glm::vec2{x, y}, 0.f, 1.f), +// }, uniform).albedo; +// +// /* +// glm::vec4 query = glm::vec4(pass_uv - glm::vec2(lower), pass_uv - glm::vec2(upper)); +// glm::vec4 integral = 0.5f + 0.5f * erf(query * (glm::sqrt(0.5f) / sigma)); +// float alpha = glm::clamp((integral.z - integral.x) * (integral.w - integral.y), 0.0f, 1.0f); +// */ +// putPixel(iTransformedPos + glm::ivec2{ x, y }, result); +// } +// } } @@ -401,7 +407,7 @@ class SoftwarePrerenderedString: public IRenderer::IPrerenderedString { for (int y = 0; y < size.y; ++y) { for (int x = 0; x < size.x; ++x) { auto color = entry.image->get({x, y}); - + mRenderer->putPixel(transformedPosition + glm::ivec2{ x, y }, AColor{ color.r, color.g, color.b, color.a * finalColor.a }, Blending::INVERSE_SRC); mRenderer->putPixel(transformedPosition + glm::ivec2{ x, y }, color * finalColor, Blending::ADDITIVE); } @@ -565,7 +571,7 @@ void SoftwareRenderer::drawLine(const ABrush& brush, glm::vec2 p1, glm::vec2 p2, // TODO if (p1.x == p2.x || p1.y == p2.y) { auto begin = glm::min(p1, p2); - rectangle(brush, begin, glm::max(p1, p2) - begin + glm::vec2(1)); + rectangle(brush, begin, 0, glm::max(p1, p2) - begin + glm::vec2(1)); return; } } diff --git a/aui.views/src/AUI/Software/SoftwareRenderer.h b/aui.views/src/AUI/Software/SoftwareRenderer.h index d0bf81f32..7e4383a16 100644 --- a/aui.views/src/AUI/Software/SoftwareRenderer.h +++ b/aui.views/src/AUI/Software/SoftwareRenderer.h @@ -107,30 +107,36 @@ class API_AUI_VIEWS SoftwareRenderer: public IRenderer { void rectangle(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size) override; void roundedRectangle(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float radius) override; void rectangleBorder(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float lineWidth) override; void roundedRectangleBorder(const ABrush& brush, glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float radius, int borderWidth) override; void boxShadow(glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float blurRadius, const AColor& color) override; - + void boxShadowInner(glm::vec2 position, + zIndex_t zIndex, glm::vec2 size, float blurRadius, float spreadRadius, diff --git a/aui.views/src/AUI/Util/ACursorSelectable.h b/aui.views/src/AUI/Util/ACursorSelectable.h index 481272ed8..7ab32a6d7 100644 --- a/aui.views/src/AUI/Util/ACursorSelectable.h +++ b/aui.views/src/AUI/Util/ACursorSelectable.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -139,7 +140,7 @@ class API_AUI_VIEWS ACursorSelectable { auto drawRects = [&] { for (auto r : rects) { - render.rectangle(ASolidBrush{}, r.p1, r.size()); + render.rectangle(ASolidBrush{}, r.p1, std::numeric_limits::max(), r.size()); } }; { diff --git a/aui.views/src/AUI/Util/ANoiseDrawable.cpp b/aui.views/src/AUI/Util/ANoiseDrawable.cpp index a9af5dacf..c27bbd7f4 100644 --- a/aui.views/src/AUI/Util/ANoiseDrawable.cpp +++ b/aui.views/src/AUI/Util/ANoiseDrawable.cpp @@ -33,7 +33,8 @@ void ANoiseDrawable::draw(IRenderer& render, const IDrawable::Params& params) { .uv2 = glm::vec2(params.size) * glm::vec2(0.37390528174893522421f, 0.37577434667f), .imageRendering = ImageRendering::SMOOTH, .repeat = Repeat::X_Y, - }, params.offset, params.size); + // TODO: use actual z index here + }, params.offset, 0, params.size); } glm::ivec2 ANoiseDrawable::getSizeHint() { return {1, 1}; } diff --git a/aui.views/src/AUI/Util/AStubWindowManager.h b/aui.views/src/AUI/Util/AStubWindowManager.h index 30335da0e..24466b8a5 100644 --- a/aui.views/src/AUI/Util/AStubWindowManager.h +++ b/aui.views/src/AUI/Util/AStubWindowManager.h @@ -40,7 +40,7 @@ class API_AUI_VIEWS AStubWindowManager: public AWindowManager { /** * @brief Renderer used for window manager. */ - _unique renderer = std::make_unique(); + _unique renderer = std::make_unique(); }; static void setConfig(Config config); diff --git a/aui.views/src/AUI/Util/AViewProfiler.cpp b/aui.views/src/AUI/Util/AViewProfiler.cpp index 6d0e277c7..2f2f7da16 100644 --- a/aui.views/src/AUI/Util/AViewProfiler.cpp +++ b/aui.views/src/AUI/Util/AViewProfiler.cpp @@ -33,6 +33,7 @@ void AViewProfiler::displayBoundsOn(AView& v, ARenderContext ctx) { { ctx.render.rectangle(ASolidBrush{0x7cb6c180u}, {v.getPadding().left, v.getPadding().top}, + v.getZIndex(), {v.getWidth() - v.getPadding().horizontal(), v.getHeight() - v.getPadding().vertical()}); } @@ -40,6 +41,7 @@ void AViewProfiler::displayBoundsOn(AView& v, ARenderContext ctx) { { ctx.render.rectangle(ASolidBrush{0xbccf9180u}, {0, 0}, + v.getZIndex(), v.getSize()); } @@ -47,6 +49,7 @@ void AViewProfiler::displayBoundsOn(AView& v, ARenderContext ctx) { { ctx.render.rectangle(ASolidBrush{0xffcca4a0u}, {-v.getMargin().left, -v.getMargin().top}, + v.getZIndex(), {v.getWidth() + v.getMargin().horizontal(), v.getHeight() + v.getMargin().vertical()}); } @@ -69,6 +72,7 @@ void AViewProfiler::displayBoundsOn(AView& v, ARenderContext ctx) { { ctx.render.rectangle(ASolidBrush{0x00000070u}, {x, y}, + v.getZIndex(), {s->getWidth() + 4_dp, fs.size * 2.5 + 2_dp}); } s->draw(); diff --git a/aui.views/src/AUI/Util/ImageDrawable.cpp b/aui.views/src/AUI/Util/ImageDrawable.cpp index 3a9eb0749..13513808e 100644 --- a/aui.views/src/AUI/Util/ImageDrawable.cpp +++ b/aui.views/src/AUI/Util/ImageDrawable.cpp @@ -47,7 +47,8 @@ void AImageDrawable::draw(IRenderer& render, const IDrawable::Params& params) { .uv2 = params.cropUvBottomRight, .imageRendering = params.imageRendering, .repeat = params.repeat, - }, params.offset, params.size); + // TODO: use actual z index here + }, params.offset, 0, params.size); } AImage AImageDrawable::rasterize(glm::ivec2 imageSize) { diff --git a/aui.views/src/AUI/View/AAbstractTypeable.cpp b/aui.views/src/AUI/View/AAbstractTypeable.cpp index 9cc17670b..a8a244b1f 100644 --- a/aui.views/src/AUI/View/AAbstractTypeable.cpp +++ b/aui.views/src/AUI/View/AAbstractTypeable.cpp @@ -310,7 +310,8 @@ void AAbstractTypeable::drawCursorImpl(IRenderer& renderer, glm::ivec2 position, } renderer.setBlending(Blending::INVERSE_DST); AUI_DEFER { renderer.setBlending(Blending::NORMAL); }; - renderer.rectangle(ASolidBrush{}, position, {1, lineHeight}); + // TODO: use actual z index here + renderer.rectangle(ASolidBrush{}, position, 0, {1, lineHeight}); } void AAbstractTypeable::moveCursorLeft() { diff --git a/aui.views/src/AUI/View/AGroupBox.cpp b/aui.views/src/AUI/View/AGroupBox.cpp index 22cf92f08..c17f4bfa7 100644 --- a/aui.views/src/AUI/View/AGroupBox.cpp +++ b/aui.views/src/AUI/View/AGroupBox.cpp @@ -35,6 +35,7 @@ namespace { AUI_REPEAT(2) { // render twice to definitely avoid stencil issues ctx.render.rectangle(ASolidBrush{}, d, + mZIndex, mTitle->getSize()); } } diff --git a/aui.views/src/AUI/View/ARulerArea.cpp b/aui.views/src/AUI/View/ARulerArea.cpp index 4e6fc8e98..ca8fa06f5 100644 --- a/aui.views/src/AUI/View/ARulerArea.cpp +++ b/aui.views/src/AUI/View/ARulerArea.cpp @@ -20,6 +20,7 @@ #include "AScrollbar.h" #include #include +#include using namespace ass; using namespace declarative; @@ -105,9 +106,11 @@ void ARulerArea::render(ARenderContext ctx) { ctx.render.setBlending(Blending::INVERSE_DST); ctx.render.rectangle(ASolidBrush{}, {mMousePos.x, 0.f}, + std::numeric_limits::max(), {1, mMousePos.y}); ctx.render.rectangle(ASolidBrush{}, {0.f, mMousePos.y}, + std::numeric_limits::max(), {mMousePos.x, 1}); diff --git a/aui.views/src/AUI/View/ARulerView.cpp b/aui.views/src/AUI/View/ARulerView.cpp index 9cdfdeffc..b5f9fef7c 100644 --- a/aui.views/src/AUI/View/ARulerView.cpp +++ b/aui.views/src/AUI/View/ARulerView.cpp @@ -59,11 +59,13 @@ void ARulerView::render(ARenderContext ctx) { // large dashes ctx.render.rectangle(ASolidBrush{}, {mOffsetPx + operator ""_dp(i * delayLarge), 0.f}, + mZIndex, {1, totalHeight}); // medium dashes ctx.render.rectangle(ASolidBrush{}, {mOffsetPx + operator ""_dp(i * delayLarge + delayMedium), totalHeight / 2}, + mZIndex, {1, totalHeight / 2}); @@ -72,12 +74,14 @@ void ARulerView::render(ARenderContext ctx) { int smallDashOffset = j * delaySmall; ctx.render.rectangle(ASolidBrush{}, {mOffsetPx + operator ""_dp(i * delayLarge + smallDashOffset), - 3 * totalHeight / 4}, + 3 * totalHeight / 4}, + mZIndex, {1, totalHeight / 4}); ctx.render.rectangle(ASolidBrush{}, {mOffsetPx + operator ""_dp(i * delayLarge + smallDashOffset + delayMedium), - 3 * totalHeight / 4}, + 3 * totalHeight / 4}, + mZIndex, {1, totalHeight / 4}); } } diff --git a/aui.views/src/AUI/View/AView.cpp b/aui.views/src/AUI/View/AView.cpp index ea3840054..7d84f69c2 100644 --- a/aui.views/src/AUI/View/AView.cpp +++ b/aui.views/src/AUI/View/AView.cpp @@ -103,14 +103,17 @@ void AView::drawStencilMask(ARenderContext ctx) switch (mOverflowMask) { case AOverflowMask::ROUNDED_RECT: if (mBorderRadius > 0) { - ctx.render.roundedRectangle(ASolidBrush{}, - {mPadding.left, mPadding.top}, - {getWidth() - mPadding.horizontal(), getHeight() - mPadding.vertical()}, - glm::max(mBorderRadius - std::min(mPadding.horizontal(), mPadding.vertical()), 0.f)); + // ctx.render.roundedRectangle(ASolidBrush{}, + // {mPadding.left, mPadding.top}, + // mZIndex, + // {getWidth() - mPadding.horizontal(), getHeight() - mPadding.vertical()}, + // glm::max(mBorderRadius - std::min(mPadding.horizontal(), mPadding.vertical()), 0.f)); } else { - ctx.render.rectangle(ASolidBrush{}, - {mPadding.left, mPadding.top}, - {getWidth() - mPadding.horizontal(), getHeight() - mPadding.vertical()}); + // TODO: figure out why this is rendered opaque when batching + // ctx.render.rectangle(ASolidBrush{}, + // {mPadding.left, mPadding.top}, + // mZIndex, + // {getWidth() - mPadding.horizontal(), getHeight() - mPadding.vertical()}); } break; @@ -290,6 +293,11 @@ void AView::getTransform(glm::mat4& transform) const transform = glm::translate(transform, glm::vec3{ getPosition(), 0.f }); } +const glm::mat4 AView::getTransformCopy(glm::mat4 transform) const +{ + return glm::translate(transform, glm::vec3{ getPosition(), 0.f }); +} + void AView::pack() { setSize({ getMinimumWidth(), getMinimumHeight() }); @@ -506,6 +514,13 @@ void AView::setPosition(glm::ivec2 position) { redraw(); emit mPositionChanged(position); } +void AView::setZIndex(const zIndex_t value) { + mSkipUntilLayoutUpdate = false; + mZIndex = value; + redraw(); + emit mZIndexChanged(value); +} + void AView::setSize(glm::ivec2 size) { mMarkedMinContentSizeInvalid = false; diff --git a/aui.views/src/AUI/View/AView.h b/aui.views/src/AUI/View/AView.h index ba697bb86..99f83c8fd 100644 --- a/aui.views/src/AUI/View/AView.h +++ b/aui.views/src/AUI/View/AView.h @@ -48,6 +48,7 @@ #include #include +using zIndex_t = int16_t; class AWindow; class AWindowBase; @@ -209,6 +210,12 @@ class API_AUI_VIEWS AView: public AObject return mPosition; } + [[nodiscard]] + zIndex_t getZIndex() const noexcept + { + return mZIndex; + } + /** * @brief The center point position of the view relatively to top left corner of the window. * @details @@ -562,6 +569,7 @@ class API_AUI_VIEWS AView: public AObject void setAnimator(const _& animator); void getTransform(glm::mat4& transform) const; + const glm::mat4 getTransformCopy(glm::mat4 transform = glm::mat4{1.}) const; [[nodiscard]] int getExpandingHorizontal() const @@ -584,6 +592,8 @@ class API_AUI_VIEWS AView: public AObject virtual void setPosition(glm::ivec2 position); + virtual void setZIndex(const zIndex_t value); + /** * Set size ignoring all restrictions (i.e. min size, max size, fixed size, etc...). Used by AAnimator. * @param size @@ -1041,6 +1051,10 @@ class API_AUI_VIEWS AView: public AObject */ emits mPositionChanged; + zIndex_t mZIndex = 0; + + emits mZIndexChanged; + /** * @brief Size, including content area, border and padding. */ diff --git a/aui.views/src/AUI/View/AViewContainerBase.cpp b/aui.views/src/AUI/View/AViewContainerBase.cpp index 138753067..ec04aa86b 100644 --- a/aui.views/src/AUI/View/AViewContainerBase.cpp +++ b/aui.views/src/AUI/View/AViewContainerBase.cpp @@ -75,7 +75,7 @@ void AViewContainerBase::drawView(const _& view, ARenderContext contextOf if (showRedraw) [[unlikely]] { auto c = contextOfTheView.render.getColor(); AUI_DEFER { contextOfTheView.render.setColorForced(c); }; - contextOfTheView.render.rectangle(ASolidBrush{0x40ff00ff_argb}, view->getPosition(), view->getSize()); + contextOfTheView.render.rectangle(ASolidBrush{0x40ff00ff_argb}, view->getPosition(), view->getZIndex(), view->getSize()); } }; @@ -83,7 +83,8 @@ void AViewContainerBase::drawView(const _& view, ARenderContext contextOf glm::mat4 t(1.f); view->getTransform(t); contextOfTheView.render.setTransform(t); - contextOfTheView.render.setColor(AColor(1, 1, 1, view->getOpacity())); + // TODO: this is incomatible with batching, move to vertex + // contextOfTheView.render.setColor(AColor(1, 1, 1, view->getOpacity())); if (view->mRenderToTexture) [[unlikely]] { // view was prerendered to texture; see AView::markPixelDataInvalid view->mRenderToTexture->skipRedrawUntilTextureIsPresented = false; // Check invalidArea is not dirty; otherwise we would have to draw the views without render-to-texture @@ -133,6 +134,7 @@ void AViewContainerBase::addViews(AVector<_> views) { } for (const auto& view: views) { view->mParent = this; + view->setZIndex(mZIndex + 1); view->mSkipUntilLayoutUpdate = true; AUI_NULLSAFE(mLayout)->addView(view); view->onViewGraphSubtreeChanged(); @@ -156,6 +158,7 @@ void AViewContainerBase::addView(const _& view) { view->mSkipUntilLayoutUpdate = true; mViews << view; view->mParent = this; + view->setZIndex(mZIndex + 1); AUI_NULLSAFE(mLayout)->addView(view); view->onViewGraphSubtreeChanged(); invalidateCaches(); @@ -169,6 +172,7 @@ void AViewContainerBase::addViewCustomLayout(const _& view) { } mViews << view; view->mParent = this; + view->setZIndex(mZIndex + 1); view->setSize(view->getMinimumSize()); view->mSkipUntilLayoutUpdate = true; AUI_NULLSAFE(mLayout)->addView(view); @@ -186,6 +190,7 @@ void AViewContainerBase::addView(size_t index, const _& view) { mViews.insert(mViews.begin() + index, view); view->mParent = this; AUI_NULLSAFE(mLayout)->addView(view, index); + view->setZIndex(mZIndex + 1); view->onViewGraphSubtreeChanged(); invalidateCaches(); emit childrenChanged; @@ -212,6 +217,7 @@ void AViewContainerBase::setLayoutImpl(_unique layout, std::unique_lock mViews = mLayout->getAllViews(); for (const auto& v : mViews) { v->mParent = this; + v->setZIndex(mZIndex + 1); v->onViewGraphSubtreeChanged(); } } @@ -630,6 +636,14 @@ void AViewContainerBase::setEnabled(bool enabled) { notifyParentEnabledStateChanged(enabled); } +void AViewContainerBase::setZIndex(zIndex_t value) { + AView::setZIndex(value); + + for (auto& child : mViews) { + child->setZIndex(value + 1); + } +} + void AViewContainerBase::notifyParentEnabledStateChanged(bool enabled) { enabled &= mDirectlyEnabled; AView::notifyParentEnabledStateChanged(enabled); diff --git a/aui.views/src/AUI/View/AViewContainerBase.h b/aui.views/src/AUI/View/AViewContainerBase.h index 1a7c8d460..0b61748a9 100644 --- a/aui.views/src/AUI/View/AViewContainerBase.h +++ b/aui.views/src/AUI/View/AViewContainerBase.h @@ -116,6 +116,8 @@ class API_AUI_VIEWS AViewContainerBase : public AView { void setEnabled(bool enabled = true) override; + void setZIndex(const zIndex_t value) override; + auto begin() const { return mViews.cbegin(); } diff --git a/examples/7guis/circle_drawer/src/main.cpp b/examples/7guis/circle_drawer/src/main.cpp index 34cf9341d..817345e23 100644 --- a/examples/7guis/circle_drawer/src/main.cpp +++ b/examples/7guis/circle_drawer/src/main.cpp @@ -94,11 +94,11 @@ class CircleDrawArea : public AView { for (const auto& circle : *mState->circles) { if (&circle == mHoveredCircle) { ctx.render.roundedRectangle( - ASolidBrush { AColor::GRAY }, circle.position - *circle.radius, glm::vec2(circle.radius * 2.f), + ASolidBrush { AColor::GRAY }, circle.position - *circle.radius, mZIndex, glm::vec2(circle.radius * 2.f), circle.radius); } ctx.render.roundedRectangleBorder( - ASolidBrush { AColor::BLACK }, circle.position - *circle.radius, glm::vec2(circle.radius * 2.f), + ASolidBrush { AColor::BLACK }, circle.position - *circle.radius, mZIndex, glm::vec2(circle.radius * 2.f), circle.radius, 1); } } @@ -233,4 +233,4 @@ class CircleDrawerWindow : public AWindow { AUI_ENTRY { _new()->show(); return 0; -} \ No newline at end of file +} diff --git a/examples/app/fractal/src/FractalView.cpp b/examples/app/fractal/src/FractalView.cpp index bc906a376..25915a586 100644 --- a/examples/app/fractal/src/FractalView.cpp +++ b/examples/app/fractal/src/FractalView.cpp @@ -88,7 +88,7 @@ void FractalView::render(ARenderContext context) { mShader.use(); mTexture->bind(); - context.render.rectangle(ACustomShaderBrush {}, { 0, 0 }, getSize()); + context.render.rectangle(ACustomShaderBrush {}, { 0, 0 }, mZIndex, getSize()); } void FractalView::setSize(glm::ivec2 size) { diff --git a/examples/app/game_of_life/src/main.cpp b/examples/app/game_of_life/src/main.cpp index 852c85498..d76b2abfe 100644 --- a/examples/app/game_of_life/src/main.cpp +++ b/examples/app/game_of_life/src/main.cpp @@ -128,7 +128,7 @@ class CellsView : public AView { void render(ARenderContext ctx) override { AView::render(ctx); if (mTexture) { - ctx.render.rectangle(ATexturedBrush { mTexture }, { 0, 0 }, float(SCALE) * glm::vec2(mCells->size())); + ctx.render.rectangle(ATexturedBrush { mTexture }, { 0, 0 }, mZIndex, float(SCALE) * glm::vec2(mCells->size())); } auto drawGrid = [&] { ASmallVector, 128 * 2> points; diff --git a/examples/ui/game_inventory/src/main.cpp b/examples/ui/game_inventory/src/main.cpp index 1cf837573..2a0021622 100644 --- a/examples/ui/game_inventory/src/main.cpp +++ b/examples/ui/game_inventory/src/main.cpp @@ -9,7 +9,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "AUI/ASS/Property/BackgroundSolid.h" +#include "AUI/ASS/Property/Margin.h" +#include "AUI/Common/AColor.h" #include "AUI/Platform/ARenderingContextOptions.h" +#include "AUI/Util/AAngleRadians.h" #include "AUI/View/AForEachUI.h" #include "AUI/View/AScrollArea.h" #include "AUI/View/Dynamic.h" @@ -21,6 +25,7 @@ #include #include #include +#include using namespace ass; using namespace declarative; @@ -51,18 +56,19 @@ _ itemStackView(const _>>& itemStack) { _new() AUI_LET { AObject::connect( AUI_REACT(ass::PropertyListRecursive { - BackgroundImage { (*itemStack) ->hasValue() ? ":texture/item/{}.png"_format((**itemStack)->id) : "" }, + // BackgroundImage { (*itemStack) ->hasValue() ? ":texture/item/{}.png"_format((**itemStack)->id) : "" }, + BackgroundGradient{ AColor{ "#FB181655" }, AColor{ "#1BF81655" }, 90_deg }, Expanding {}, }), AUI_SLOT(it)::setCustomStyle); }, Vertical::Expanding { SpacerExpanding {}, - Label { AUI_REACT("{}"_format((*itemStack)->valueOr(ItemStack{}).count)) } AUI_OVERRIDE_STYLE { - ATextAlign::RIGHT, - TextColor { AColor::WHITE }, - TextShadow { AColor::BLACK, 1_dp, 1_dp }, - }, + // Label { AUI_REACT("{}"_format((*itemStack)->valueOr(ItemStack{}).count)) } AUI_OVERRIDE_STYLE { + // ATextAlign::RIGHT, + // TextColor { AColor::WHITE }, + // TextShadow { AColor::BLACK, 1_dp, 1_dp }, + // }, }, } AUI_OVERRIDE_STYLE { FixedSize { 32_dp }, @@ -108,11 +114,11 @@ AUI_ENTRY { .flags = ARenderContextFlags::NO_VSYNC | ARenderContextFlags::NO_SMOOTH, }); - auto window = _new("Game inventory", 600_dp, 500_dp); + auto window = _new("Game inventory", 1920_dp, 900_dp); auto state = _new(); state->items = - ranges::view::iota(0, 128) | ranges::view::transform([&](int i) { + ranges::views::iota(0, 512) | ranges::views::transform([&](int i) { return aui::ptr::manage_shared(new State::Cell { .contents = i <= 11 ? AOptional({ @@ -126,11 +132,11 @@ AUI_ENTRY { window->setContents( Centered { Vertical { - Label { "Inventory" } AUI_OVERRIDE_STYLE { FontSize { 32_dp } }, + // Label { "Inventory" } AUI_OVERRIDE_STYLE { FontSize { 32_dp } }, inventoryGrid(state), } AUI_OVERRIDE_STYLE { Expanding {}, - MaxSize { 700_dp, {} }, + BackgroundSolid{ AColor{ "#2F3F59" }}, }, } AUI_OVERRIDE_STYLE { Padding { {}, 64_dp } }); window->show();