From a808e9e4c44e167afa96607e2327570a08788bcd Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 12 Aug 2026 09:11:53 +0100 Subject: [PATCH 01/10] rendering: expose neutral depth and light state --- include/Inventor/elements/SoLazyElement.h | 4 +++ include/Inventor/nodes/SoDepthBuffer.h | 2 ++ include/Inventor/nodes/SoLight.h | 1 + src/elements/SoLazyElement.cpp | 31 +++++++++++++++++++++++ src/nodes/SoAlphaTest.cpp | 27 ++++++++++++++++++++ src/nodes/SoDepthBuffer.cpp | 27 ++++++++++++++++++++ src/nodes/SoLight.cpp | 11 ++++++++ 7 files changed, 103 insertions(+) diff --git a/include/Inventor/elements/SoLazyElement.h b/include/Inventor/elements/SoLazyElement.h index 9607d566d8..972ff2651d 100644 --- a/include/Inventor/elements/SoLazyElement.h +++ b/include/Inventor/elements/SoLazyElement.h @@ -146,6 +146,7 @@ class COIN_DLL_API SoLazyElement : public SoElement { static void setTwosideLighting(SoState * state, SbBool onoff); static void setShadeModel(SoState * state, SbBool flatshading); static void setAlphaTest(SoState * state, int func, float value); + static void setAlphaTestSemantic(SoState * state, int function, float value); static const SbColor & getDiffuse(SoState* state, int index); static float getTransparency(SoState*, int index); @@ -164,6 +165,7 @@ class COIN_DLL_API SoLazyElement : public SoElement { static int32_t getLightModel(SoState*); static int getAlphaTest(SoState * state, float & value); + static int getAlphaTestSemantic(SoState * state, float & value); static SbBool getTwoSidedLighting(SoState * state); int32_t getNumDiffuse(void) const; @@ -236,6 +238,7 @@ class COIN_DLL_API SoLazyElement : public SoElement { SbBool culling; SbBool flatshading; int alphatestfunc; + int semanticalphatestfunc; float alphatestvalue; } coinstate; @@ -277,6 +280,7 @@ class COIN_DLL_API SoLazyElement : public SoElement { virtual void setTwosideLightingElt(SbBool onoff); virtual void setShadeModelElt(SbBool flatshading); virtual void setAlphaTestElt(int func, float value); + virtual void setAlphaTestSemanticElt(int function, float value); private: SoLazyElementP * pimpl; // for future use diff --git a/include/Inventor/nodes/SoDepthBuffer.h b/include/Inventor/nodes/SoDepthBuffer.h index 8ac4efa396..bfe994249d 100644 --- a/include/Inventor/nodes/SoDepthBuffer.h +++ b/include/Inventor/nodes/SoDepthBuffer.h @@ -64,6 +64,8 @@ class COIN_DLL_API SoDepthBuffer : public SoNode { SoSFEnum function; SoSFVec2f range; + void doAction(SoAction * action) override; + #if COIN_HAVE_LEGACY_GL_RENDERER void GLRender(SoGLRenderAction * action) override; #endif diff --git a/include/Inventor/nodes/SoLight.h b/include/Inventor/nodes/SoLight.h index 8c7a383ff7..bfe0b360be 100644 --- a/include/Inventor/nodes/SoLight.h +++ b/include/Inventor/nodes/SoLight.h @@ -50,6 +50,7 @@ class COIN_DLL_API SoLight : public SoNode { SoSFFloat intensity; SoSFColor color; + void doAction(SoAction * action) override; void callback(SoCallbackAction * action) override; protected: diff --git a/src/elements/SoLazyElement.cpp b/src/elements/SoLazyElement.cpp index ab4e70ad97..42f5f2504b 100644 --- a/src/elements/SoLazyElement.cpp +++ b/src/elements/SoLazyElement.cpp @@ -193,6 +193,7 @@ SoLazyElement::init(SoState * COIN_UNUSED_ARG(state)) this->coinstate.culling = FALSE; this->coinstate.flatshading = FALSE; this->coinstate.alphatestfunc = 0; + this->coinstate.semanticalphatestfunc = 0; this->coinstate.alphatestvalue = 0.5f; } @@ -615,6 +616,14 @@ SoLazyElement::getAlphaTest(SoState * state, float & value) return elem->coinstate.alphatestfunc; } +int +SoLazyElement::getAlphaTestSemantic(SoState * state, float & value) +{ + SoLazyElement * elem = getInstance(state); + value = elem->coinstate.alphatestvalue; + return elem->coinstate.semanticalphatestfunc; +} + // ! FIXME: write doc int32_t @@ -897,6 +906,21 @@ SoLazyElement::setAlphaTest(SoState * state, int func, float value) } } +void +SoLazyElement::setAlphaTestSemantic(SoState * state, int function, float value) +{ + SoLazyElement * elem = SoLazyElement::getInstance(state); + if (elem->coinstate.semanticalphatestfunc != function || + elem->coinstate.alphatestvalue != value) { + elem = getWInstance(state); + elem->setAlphaTestSemanticElt(function, value); + if (state->isCacheOpen()) elem->lazyDidSet(ALPHATEST_MASK); + } + else if (state->isCacheOpen()) { + elem->lazyDidntSet(ALPHATEST_MASK); + } +} + // ! FIXME: write doc @@ -1149,6 +1173,13 @@ SoLazyElement::setAlphaTestElt(int func, float value) this->coinstate.alphatestvalue = value; } +void +SoLazyElement::setAlphaTestSemanticElt(int function, float value) +{ + this->coinstate.semanticalphatestfunc = function; + this->coinstate.alphatestvalue = value; +} + // SoColorPacker class. FIXME: move to separate file and document, pederb, 2002-09-09 diff --git a/src/nodes/SoAlphaTest.cpp b/src/nodes/SoAlphaTest.cpp index ca49c37838..e4b627de85 100644 --- a/src/nodes/SoAlphaTest.cpp +++ b/src/nodes/SoAlphaTest.cpp @@ -173,6 +173,33 @@ SoAlphaTest::~SoAlphaTest() { } +static int +coin_alpha_test_function_to_gl(const int function) +{ + switch (function) { + case SoAlphaTest::NEVER: return GL_NEVER; + case SoAlphaTest::ALWAYS: return GL_ALWAYS; + case SoAlphaTest::LESS: return GL_LESS; + case SoAlphaTest::LEQUAL: return GL_LEQUAL; + case SoAlphaTest::EQUAL: return GL_EQUAL; + case SoAlphaTest::GEQUAL: return GL_GEQUAL; + case SoAlphaTest::GREATER: return GL_GREATER; + case SoAlphaTest::NOTEQUAL: return GL_NOTEQUAL; + case SoAlphaTest::NONE: + default: return 0; + } +} + +void +SoAlphaTest::doAction(SoAction * action) +{ + // Generic traversal retains the semantic Inventor function. The LegacyGL + // override below is the only path that translates it to a GL enum. + SoLazyElement::setAlphaTestSemantic(action->getState(), + this->function.getValue(), + this->value.getValue()); +} + // Doc from parent #if COIN_BUILD_LEGACY_GL_RENDERER void diff --git a/src/nodes/SoDepthBuffer.cpp b/src/nodes/SoDepthBuffer.cpp index 2903907995..bc181064d0 100644 --- a/src/nodes/SoDepthBuffer.cpp +++ b/src/nodes/SoDepthBuffer.cpp @@ -189,6 +189,33 @@ SoDepthBuffer::~SoDepthBuffer() { } +void +SoDepthBuffer::doAction(SoAction * action) +{ + SoState * state = action->getState(); + SbBool testenable = this->test.getValue(); + SbBool writeenable = this->write.getValue(); + SoDepthBufferElement::DepthWriteFunction function = + static_cast(this->function.getValue()); + SbVec2f depthrange = this->range.getValue(); + + if (this->test.isIgnored()) { + testenable = SoDepthBufferElement::getTestEnable(state); + } + if (this->write.isIgnored()) { + writeenable = SoDepthBufferElement::getWriteEnable(state); + } + if (this->function.isIgnored()) { + function = SoDepthBufferElement::getFunction(state); + } + if (this->range.isIgnored()) { + depthrange = SoDepthBufferElement::getRange(state); + } + + SoDepthBufferElement::set(state, testenable, writeenable, + function, depthrange); +} + #if COIN_BUILD_LEGACY_GL_RENDERER // Doc from parent void diff --git a/src/nodes/SoLight.cpp b/src/nodes/SoLight.cpp index 1809c524a3..d59f1a612a 100644 --- a/src/nodes/SoLight.cpp +++ b/src/nodes/SoLight.cpp @@ -72,6 +72,7 @@ #include #include +#include #include #if COIN_BUILD_LEGACY_GL_RENDERER #include @@ -80,6 +81,7 @@ #include #include #include +#include #include "nodes/SoSubNodeP.h" @@ -140,6 +142,15 @@ SoLight::initClass(void) SO_ENABLE(SoCallbackAction, SoLightElement); } +// Doc from superclass. +void +SoLight::doAction(SoAction * action) +{ + SoState * state = action->getState(); + SoLightElement::add(state, this, SoModelMatrixElement::get(state) * + SoViewingMatrixElement::get(state)); +} + // Doc from superclass. void SoLight::callback(SoCallbackAction * action) From bbf8ccd5b2bd9996db215f7f49ff486d8d09a84c Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 12 Aug 2026 09:15:27 +0100 Subject: [PATCH 02/10] rendering: extend retained IR state capture --- include/Inventor/elements/SoLazyElement.h | 7 +- include/Inventor/rendering/SoRenderIR.h | 26 +++- src/elements/SoLazyElement.cpp | 138 ++++++++++++++--- src/elements/SoLazyElementP.h | 48 ++++++ src/nodes/SoAlphaTest.cpp | 7 +- src/nodes/SoVertexProperty.cpp | 9 +- src/rendering/CMakeLists.txt | 1 + src/rendering/SoGLImage.cpp | 29 +--- src/rendering/SoRenderIR.cpp | 173 ++++++++++++++++++++-- src/rendering/SoRenderIRP.h | 10 +- src/rendering/SoTextureQualityPolicy.h | 82 ++++++++++ src/shapenodes/SoShape.cpp | 3 +- 12 files changed, 458 insertions(+), 75 deletions(-) create mode 100644 src/elements/SoLazyElementP.h create mode 100644 src/rendering/SoTextureQualityPolicy.h diff --git a/include/Inventor/elements/SoLazyElement.h b/include/Inventor/elements/SoLazyElement.h index 972ff2651d..94e047c4de 100644 --- a/include/Inventor/elements/SoLazyElement.h +++ b/include/Inventor/elements/SoLazyElement.h @@ -146,7 +146,6 @@ class COIN_DLL_API SoLazyElement : public SoElement { static void setTwosideLighting(SoState * state, SbBool onoff); static void setShadeModel(SoState * state, SbBool flatshading); static void setAlphaTest(SoState * state, int func, float value); - static void setAlphaTestSemantic(SoState * state, int function, float value); static const SbColor & getDiffuse(SoState* state, int index); static float getTransparency(SoState*, int index); @@ -165,7 +164,6 @@ class COIN_DLL_API SoLazyElement : public SoElement { static int32_t getLightModel(SoState*); static int getAlphaTest(SoState * state, float & value); - static int getAlphaTestSemantic(SoState * state, float & value); static SbBool getTwoSidedLighting(SoState * state); int32_t getNumDiffuse(void) const; @@ -238,7 +236,6 @@ class COIN_DLL_API SoLazyElement : public SoElement { SbBool culling; SbBool flatshading; int alphatestfunc; - int semanticalphatestfunc; float alphatestvalue; } coinstate; @@ -280,10 +277,10 @@ class COIN_DLL_API SoLazyElement : public SoElement { virtual void setTwosideLightingElt(SbBool onoff); virtual void setShadeModelElt(SbBool flatshading); virtual void setAlphaTestElt(int func, float value); - virtual void setAlphaTestSemanticElt(int function, float value); private: - SoLazyElementP * pimpl; // for future use + friend class SoLazyElementP; + SoLazyElementP * pimpl = nullptr; }; diff --git a/include/Inventor/rendering/SoRenderIR.h b/include/Inventor/rendering/SoRenderIR.h index 2dab38bf44..dc16ddcbe5 100644 --- a/include/Inventor/rendering/SoRenderIR.h +++ b/include/Inventor/rendering/SoRenderIR.h @@ -146,6 +146,15 @@ enum SoTextureColorSpace : uint8_t { SO_TEXTURE_COLORSPACE_SRGB }; +// Texture environment models retained from SoMultiTextureImageElement. These +// are semantic values; a backend maps them to its own texture-combine API. +enum SoTextureModel : uint8_t { + SO_TEXTURE_MODEL_MODULATE = 0, + SO_TEXTURE_MODEL_DECAL, + SO_TEXTURE_MODEL_BLEND, + SO_TEXTURE_MODEL_REPLACE +}; + // --- Depth state --------------------------------------------------------- // Semantic comparison functions. These deliberately do not use GL enum @@ -179,7 +188,11 @@ enum SoBlendFactor : uint8_t { SO_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, SO_BLEND_FACTOR_CONSTANT_ALPHA, SO_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, - SO_BLEND_FACTOR_SRC_ALPHA_SATURATE + SO_BLEND_FACTOR_SRC_ALPHA_SATURATE, + SO_BLEND_FACTOR_SRC1_COLOR, + SO_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, + SO_BLEND_FACTOR_SRC1_ALPHA, + SO_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA }; enum SoBlendEquation : uint8_t { @@ -234,12 +247,16 @@ struct SoTextureData { SoTextureWrap wrapS = SO_TEXTURE_WRAP_CLAMP_TO_EDGE; SoTextureWrap wrapT = SO_TEXTURE_WRAP_CLAMP_TO_EDGE; SoTextureColorSpace colorSpace = SO_TEXTURE_COLORSPACE_LEGACY; - // A nonzero key permits a backend to retain the texture resource across // frame lifetimes. revision changes require the resource contents to be // refreshed; zero remains transient. uint64_t cacheKey = 0; uint64_t revision = 0; + // Request anisotropic filtering when Coin's texture-quality policy enables + // it. The executor selects the driver's supported level. + bool anisotropic = false; + SoTextureModel model = SO_TEXTURE_MODEL_MODULATE; + SbVec4f blendColor = SbVec4f(0.0f, 0.0f, 0.0f, 1.0f); }; /*! @@ -259,7 +276,10 @@ struct SoMaterialData { SbVec4f ambient = {0.2f, 0.2f, 0.2f, 1.0f}; SbVec4f specular = {0.0f, 0.0f, 0.0f, 1.0f}; SbVec4f emissive = {0.0f, 0.0f, 0.0f, 1.0f}; - SoShadingModel shadingModel = SO_SHADING_LEGACY_GOURAUD; + // A command with no retained lighting setup is explicitly unlit. Scene + // traversal fills this with the effective Gouraud model when lighting is + // present, so the executor never needs to invent a headlight. + SoShadingModel shadingModel = SO_SHADING_UNLIT; float shininess = 0.2f; float opacity = 1.0f; diff --git a/src/elements/SoLazyElement.cpp b/src/elements/SoLazyElement.cpp index 42f5f2504b..56f34fbdda 100644 --- a/src/elements/SoLazyElement.cpp +++ b/src/elements/SoLazyElement.cpp @@ -72,8 +72,11 @@ #include +#include "elements/SoLazyElementP.h" + #include #include +#include #include #if COIN_BUILD_LEGACY_GL_RENDERER @@ -156,6 +159,8 @@ SoLazyElement::initClass() SoLazyElement::~SoLazyElement() { + delete this->pimpl; + this->pimpl = NULL; } // ! FIXME: write doc @@ -163,6 +168,9 @@ SoLazyElement::~SoLazyElement() void SoLazyElement::init(SoState * COIN_UNUSED_ARG(state)) { + if (!this->pimpl) this->pimpl = new SoLazyElementP; + this->pimpl->packedColor = SoLazyElementP::PackedColorState(); + this->pimpl->semanticAlphaTest = SoLazyElementP::SemanticAlphaTestState(); this->coinstate.ambient = this->getDefaultAmbient(); this->coinstate.specular = this->getDefaultSpecular(); this->coinstate.emissive = this->getDefaultEmissive(); @@ -193,7 +201,6 @@ SoLazyElement::init(SoState * COIN_UNUSED_ARG(state)) this->coinstate.culling = FALSE; this->coinstate.flatshading = FALSE; this->coinstate.alphatestfunc = 0; - this->coinstate.semanticalphatestfunc = 0; this->coinstate.alphatestvalue = 0.5f; } @@ -205,6 +212,9 @@ SoLazyElement::push(SoState *state) inherited::push(state); const SoLazyElement * prev = coin_assert_cast(this->getNextInStack()); this->coinstate = prev->coinstate; + if (!this->pimpl) this->pimpl = new SoLazyElementP; + if (prev->pimpl) *this->pimpl = *prev->pimpl; + else *this->pimpl = SoLazyElementP(); } @@ -254,6 +264,7 @@ SoLazyElement::setDiffuse(SoState * state, SoNode * node, int32_t numcolors, if (numcolors && (elem->coinstate.diffusenodeid != get_diffuse_node_id(node, numcolors, colors))) { elem = getWInstance(state); + SoLazyElementP::clearPackedVertexColorState(state); elem->setDiffuseElt(node, numcolors, colors, packer); if (state->isCacheOpen()) elem->lazyDidSet(DIFFUSE_MASK); } @@ -277,6 +288,7 @@ SoLazyElement::setTransparency(SoState *state, SoNode *node, int32_t numvalues, if (numvalues && (elem->coinstate.transpnodeid != get_transp_node_id(node, numvalues, transparency))) { elem = getWInstance(state); + SoLazyElementP::clearPackedVertexColorState(state); elem->setTranspElt(node, numvalues, transparency, packer); if (state->isCacheOpen()) elem->lazyDidSet(TRANSPARENCY_MASK); } @@ -301,6 +313,7 @@ SoLazyElement::setPacked(SoState * state, SoNode * node, SoLazyElement * elem = SoLazyElement::getInstance(state); if (numcolors && elem->coinstate.diffusenodeid != node->getNodeId()) { elem = getWInstance(state); + SoLazyElementP::clearPackedVertexColorState(state); elem->setPackedElt(node, numcolors, colors, packedtransparency); if (state->isCacheOpen()) elem->lazyDidSet(TRANSPARENCY_MASK|DIFFUSE_MASK); } @@ -310,6 +323,86 @@ SoLazyElement::setPacked(SoState * state, SoNode * node, SoShapeStyleElement::setTransparentMaterial(state, elem->coinstate.istransparent); } +void +SoLazyElementP::setPackedVertexColors( + SoState * state, SoNode * node, int32_t numcolors, + const uint32_t * colors, const SbBool packedtransparency) +{ + SbList inheritedOpacities; + SoLazyElementP::capturePackedVertexColorOpacities( + state, inheritedOpacities); + SoLazyElement::setPacked(state, node, numcolors, colors, + packedtransparency); + SoLazyElementP::setPackedVertexColorState(state, inheritedOpacities); +} + +void +SoLazyElementP::capturePackedVertexColorOpacities( + SoState * state, SbList & opacities) +{ + opacities.truncate(0); + SoLazyElement * lazy = SoLazyElement::getInstance(state); + if (lazy->pimpl && lazy->pimpl->packedColor.fromVertexProperty) { + opacities = lazy->pimpl->packedColor.inheritedOpacities; + return; + } + + // A packed color written by another node is vertex data, not a material + // opacity source. Start a new composition from neutral opacity. + if (lazy->isPacked()) { + opacities.append(1.0f); + return; + } + + const int count = std::max(1, lazy->getNumTransparencies()); + for (int i = 0; i < count; ++i) { + opacities.append(1.0f - SoLazyElement::getTransparency(state, i)); + } +} + +void +SoLazyElementP::setPackedVertexColorState( + SoState * state, const SbList & opacities) +{ + SoLazyElement * lazy = SoLazyElement::getWInstance(state); + if (!lazy->pimpl) lazy->pimpl = new SoLazyElementP; + lazy->pimpl->packedColor.fromVertexProperty = opacities.getLength() > 0; + lazy->pimpl->packedColor.inheritedOpacities = opacities; +} + +void +SoLazyElementP::clearPackedVertexColorState(SoState * state) +{ + SoLazyElement * lazy = SoLazyElement::getWInstance(state); + if (!lazy->pimpl) lazy->pimpl = new SoLazyElementP; + lazy->pimpl->packedColor.fromVertexProperty = FALSE; + lazy->pimpl->packedColor.inheritedOpacities.truncate(0); +} + +SbBool +SoLazyElementP::hasPackedVertexColorState(SoState * state) +{ + const SoLazyElement * lazy = SoLazyElement::getInstance(state); + return lazy->pimpl && lazy->pimpl->packedColor.fromVertexProperty && + lazy->isPacked(); +} + +float +SoLazyElementP::getPackedVertexColorOpacity(SoState * state, + const int materialIndex) +{ + const SoLazyElement * lazy = SoLazyElement::getInstance(state); + if (!lazy->pimpl || !lazy->pimpl->packedColor.fromVertexProperty || + !lazy->isPacked() || + lazy->pimpl->packedColor.inheritedOpacities.getLength() == 0) { + return 1.0f; + } + const int index = std::max( + 0, std::min(materialIndex, + lazy->pimpl->packedColor.inheritedOpacities.getLength() - 1)); + return lazy->pimpl->packedColor.inheritedOpacities[index]; +} + // ! FIXME: write doc void @@ -319,6 +412,7 @@ SoLazyElement::setColorIndices(SoState *state, SoNode *node, SoLazyElement * elem = SoLazyElement::getInstance(state); if (numindices && elem->coinstate.diffusenodeid != node->getNodeId()) { elem = getWInstance(state); + SoLazyElementP::clearPackedVertexColorState(state); elem->setColorIndexElt(node, numindices, indices); if (state->isCacheOpen()) elem->lazyDidSet(DIFFUSE_MASK); } @@ -617,11 +711,15 @@ SoLazyElement::getAlphaTest(SoState * state, float & value) } int -SoLazyElement::getAlphaTestSemantic(SoState * state, float & value) +SoLazyElementP::getAlphaTestSemantic(SoState * state, float & value) { - SoLazyElement * elem = getInstance(state); - value = elem->coinstate.alphatestvalue; - return elem->coinstate.semanticalphatestfunc; + const SoLazyElement * elem = SoLazyElement::getInstance(state); + if (!elem->pimpl) { + value = 0.5f; + return 0; + } + value = elem->pimpl->semanticAlphaTest.value; + return elem->pimpl->semanticAlphaTest.function; } // ! FIXME: write doc @@ -818,6 +916,9 @@ SoLazyElement::setMaterials(SoState * state, SoNode *node, uint32_t bitmask, if (eltbitmask) { welem = getWInstance(state); + if (eltbitmask & (DIFFUSE_MASK | TRANSPARENCY_MASK)) { + SoLazyElementP::clearPackedVertexColorState(state); + } welem->setMaterialElt(node, eltbitmask, packer, diffuse, numdiffuse, transp, numtransp, ambient, emissive, specular, shininess, @@ -899,25 +1000,26 @@ SoLazyElement::setAlphaTest(SoState * state, int func, float value) elem->coinstate.alphatestvalue != value) { elem = getWInstance(state); elem->setAlphaTestElt(func, value); - if (state->isCacheOpen()) elem->lazyDidSet(ALPHATEST_MASK); + if (state->isCacheOpen()) elem->lazyDidSet(SoLazyElement::ALPHATEST_MASK); } else if (state->isCacheOpen()) { - elem->lazyDidntSet(ALPHATEST_MASK); + elem->lazyDidntSet(SoLazyElement::ALPHATEST_MASK); } } void -SoLazyElement::setAlphaTestSemantic(SoState * state, int function, float value) +SoLazyElementP::setAlphaTestSemantic(SoState * state, int function, float value) { SoLazyElement * elem = SoLazyElement::getInstance(state); - if (elem->coinstate.semanticalphatestfunc != function || - elem->coinstate.alphatestvalue != value) { - elem = getWInstance(state); - elem->setAlphaTestSemanticElt(function, value); - if (state->isCacheOpen()) elem->lazyDidSet(ALPHATEST_MASK); + if (!elem->pimpl || elem->pimpl->semanticAlphaTest.function != function || + elem->pimpl->semanticAlphaTest.value != value) { + elem = SoLazyElement::getWInstance(state); + elem->pimpl->semanticAlphaTest.function = function; + elem->pimpl->semanticAlphaTest.value = value; + if (state->isCacheOpen()) elem->lazyDidSet(SoLazyElement::ALPHATEST_MASK); } else if (state->isCacheOpen()) { - elem->lazyDidntSet(ALPHATEST_MASK); + elem->lazyDidntSet(SoLazyElement::ALPHATEST_MASK); } } @@ -1173,14 +1275,6 @@ SoLazyElement::setAlphaTestElt(int func, float value) this->coinstate.alphatestvalue = value; } -void -SoLazyElement::setAlphaTestSemanticElt(int function, float value) -{ - this->coinstate.semanticalphatestfunc = function; - this->coinstate.alphatestvalue = value; -} - - // SoColorPacker class. FIXME: move to separate file and document, pederb, 2002-09-09 static uint32_t colorpacker_default = 0xccccccff; diff --git a/src/elements/SoLazyElementP.h b/src/elements/SoLazyElementP.h new file mode 100644 index 0000000000..bdd4293ba1 --- /dev/null +++ b/src/elements/SoLazyElementP.h @@ -0,0 +1,48 @@ +#ifndef COIN_SOLAZYELEMENTP_H +#define COIN_SOLAZYELEMENTP_H + +#include +#include + +class SoLazyElement; +class SoNode; +class SoState; + +// Source-private access to metadata describing SoLazyElement's packed color +// representation. The state remains owned by SoLazyElement's pimpl; these +// helpers are not part of Coin's public element API. +class SoLazyElementP { +public: + SoLazyElementP() = default; + + static void setPackedVertexColors( + SoState * state, SoNode * node, int32_t numcolors, + const uint32_t * colors, SbBool packedtransparency); + static SbBool hasPackedVertexColorState(SoState * state); + static float getPackedVertexColorOpacity(SoState * state, + int materialIndex); + static void setAlphaTestSemantic(SoState * state, int function, + float value); + static int getAlphaTestSemantic(SoState * state, float & value); + +private: + friend class SoLazyElement; + + static void capturePackedVertexColorOpacities( + SoState * state, SbList & opacities); + static void setPackedVertexColorState( + SoState * state, const SbList & opacities); + static void clearPackedVertexColorState(SoState * state); + + struct PackedColorState { + SbBool fromVertexProperty = FALSE; + SbList inheritedOpacities; + } packedColor; + + struct SemanticAlphaTestState { + int function = 0; + float value = 0.5f; + } semanticAlphaTest; +}; + +#endif // COIN_SOLAZYELEMENTP_H diff --git a/src/nodes/SoAlphaTest.cpp b/src/nodes/SoAlphaTest.cpp index e4b627de85..f6e7f1242b 100644 --- a/src/nodes/SoAlphaTest.cpp +++ b/src/nodes/SoAlphaTest.cpp @@ -69,6 +69,7 @@ #include #include +#include "elements/SoLazyElementP.h" #include "nodes/SoSubNodeP.h" /*! @@ -195,9 +196,9 @@ SoAlphaTest::doAction(SoAction * action) { // Generic traversal retains the semantic Inventor function. The LegacyGL // override below is the only path that translates it to a GL enum. - SoLazyElement::setAlphaTestSemantic(action->getState(), - this->function.getValue(), - this->value.getValue()); + SoLazyElementP::setAlphaTestSemantic(action->getState(), + this->function.getValue(), + this->value.getValue()); } // Doc from parent diff --git a/src/nodes/SoVertexProperty.cpp b/src/nodes/SoVertexProperty.cpp index aabf6096a7..da4546d8df 100644 --- a/src/nodes/SoVertexProperty.cpp +++ b/src/nodes/SoVertexProperty.cpp @@ -99,7 +99,6 @@ class SoVBO; #include #include #include - #include #include #include @@ -126,6 +125,7 @@ class SoVBO; #include #include "nodes/SoSubNodeP.h" +#include "elements/SoLazyElementP.h" #if COIN_BUILD_LEGACY_GL_RENDERER #include "rendering/SoVBO.h" #endif @@ -621,10 +621,9 @@ SoVertexProperty::updateMaterial(SoState * state, uint32_t overrideflags, SbBool int num = this->orderedRGBA.getNum(); if (num > 0 && !TEST_OVERRIDE(DIFFUSE_COLOR, overrideflags)) { - - SoLazyElement::setPacked(state, this, num, - this->orderedRGBA.getValues(0), - PRIVATE(this)->transparent); + SoLazyElementP::setPackedVertexColors( + state, this, num, this->orderedRGBA.getValues(0), + PRIVATE(this)->transparent); if (this->isOverride()) { SoOverrideElement::setDiffuseColorOverride(state, this, TRUE); } diff --git a/src/rendering/CMakeLists.txt b/src/rendering/CMakeLists.txt index 1eb44ace05..5fd167a36f 100644 --- a/src/rendering/CMakeLists.txt +++ b/src/rendering/CMakeLists.txt @@ -55,6 +55,7 @@ set(COIN_RENDERING_INTERNAL_FILES CoinGLReadback.cpp SoRenderIRP.h SoRenderPlan.h + SoTextureQualityPolicy.h SoRenderBackend.h SoGLRenderBackend.h ) diff --git a/src/rendering/SoGLImage.cpp b/src/rendering/SoGLImage.cpp index 64094a68fb..d8a6771cf4 100644 --- a/src/rendering/SoGLImage.cpp +++ b/src/rendering/SoGLImage.cpp @@ -219,6 +219,7 @@ #include "tidbitsp.h" #include "rendering/SoGL.h" +#include "rendering/SoTextureQualityPolicy.h" #include "elements/SoTextureScaleQualityElement.h" #include "glue/GLUWrapper.h" #include "glue/glp.h" @@ -233,11 +234,7 @@ // ************************************************************************* -static float DEFAULT_LINEAR_LIMIT = 0.2f; -static float DEFAULT_MIPMAP_LIMIT = 0.5f; -static float DEFAULT_LINEAR_MIPMAP_LIMIT = 0.8f; static float DEFAULT_SCALEUP_LIMIT = 0.7f; -static float DEFAULT_ANISOTROPIC_LIMIT = 0.85f; static float COIN_TEX2_LINEAR_LIMIT = -1.0f; static float COIN_TEX2_MIPMAP_LIMIT = -1.0f; @@ -741,26 +738,16 @@ SoGLImage::SoGLImage(void) PRIVATE(this)->owner = this; // check environment variables + const CoinTextureQualityLimits qualityLimits = + coin_get_texture_quality_limits(); if (COIN_TEX2_LINEAR_LIMIT < 0.0f) { - const char *env = coin_getenv("COIN_TEX2_LINEAR_LIMIT"); - if (env) COIN_TEX2_LINEAR_LIMIT = (float) atof(env); - if (COIN_TEX2_LINEAR_LIMIT < 0.0f || COIN_TEX2_LINEAR_LIMIT > 1.0f) { - COIN_TEX2_LINEAR_LIMIT = DEFAULT_LINEAR_LIMIT; - } + COIN_TEX2_LINEAR_LIMIT = qualityLimits.linear; } if (COIN_TEX2_MIPMAP_LIMIT < 0.0f) { - const char *env = coin_getenv("COIN_TEX2_MIPMAP_LIMIT"); - if (env) COIN_TEX2_MIPMAP_LIMIT = (float) atof(env); - if (COIN_TEX2_MIPMAP_LIMIT < 0.0f || COIN_TEX2_MIPMAP_LIMIT > 1.0f) { - COIN_TEX2_MIPMAP_LIMIT = DEFAULT_MIPMAP_LIMIT; - } + COIN_TEX2_MIPMAP_LIMIT = qualityLimits.mipmap; } if (COIN_TEX2_LINEAR_MIPMAP_LIMIT < 0.0f) { - const char *env = coin_getenv("COIN_TEX2_LINEAR_MIPMAP_LIMIT"); - if (env) COIN_TEX2_LINEAR_MIPMAP_LIMIT = (float) atof(env); - if (COIN_TEX2_LINEAR_MIPMAP_LIMIT < 0.0f || COIN_TEX2_LINEAR_MIPMAP_LIMIT > 1.0f) { - COIN_TEX2_LINEAR_MIPMAP_LIMIT = DEFAULT_LINEAR_MIPMAP_LIMIT; - } + COIN_TEX2_LINEAR_MIPMAP_LIMIT = qualityLimits.linearMipmap; } if (COIN_TEX2_SCALEUP_LIMIT < 0.0f) { @@ -794,9 +781,7 @@ SoGLImage::SoGLImage(void) else COIN_ENABLE_CONFORMANT_GL_CLAMP = 0; } if (COIN_TEX2_ANISOTROPIC_LIMIT < 0.0f) { - const char *env = coin_getenv("COIN_TEX2_ANISOTROPIC_LIMIT"); - if (env) COIN_TEX2_ANISOTROPIC_LIMIT = (float) atof(env); - else COIN_TEX2_ANISOTROPIC_LIMIT = DEFAULT_ANISOTROPIC_LIMIT; + COIN_TEX2_ANISOTROPIC_LIMIT = qualityLimits.anisotropic; } } diff --git a/src/rendering/SoRenderIR.cpp b/src/rendering/SoRenderIR.cpp index 76a37180d1..ce1822fdf0 100644 --- a/src/rendering/SoRenderIR.cpp +++ b/src/rendering/SoRenderIR.cpp @@ -1,6 +1,8 @@ // src/rendering/SoRenderIR.cpp #include "rendering/SoRenderIRP.h" +#include "rendering/SoTextureQualityPolicy.h" +#include "elements/SoLazyElementP.h" #include #include @@ -11,9 +13,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -29,6 +34,7 @@ #include #include #include +#include #include namespace { @@ -140,6 +146,49 @@ alphaTestFunctionFromLegacyGL(const int value) } } +SoTextureModel +textureModelFromLegacy(SoMultiTextureImageElement::Model model) +{ + switch (model) { + case SoMultiTextureImageElement::DECAL: + return SO_TEXTURE_MODEL_DECAL; + case SoMultiTextureImageElement::BLEND: + return SO_TEXTURE_MODEL_BLEND; + case SoMultiTextureImageElement::REPLACE: + return SO_TEXTURE_MODEL_REPLACE; + case SoMultiTextureImageElement::MODULATE: + default: + return SO_TEXTURE_MODEL_MODULATE; + } +} + +void +textureFiltersFromQuality(const float quality, SoTextureData & texture) +{ + const CoinTextureQualityPolicy policy = + coin_get_texture_quality_policy(quality); + if (!policy.linear) { + texture.minFilter = SO_TEXTURE_FILTER_NEAREST; + texture.magFilter = SO_TEXTURE_FILTER_NEAREST; + } + else if (!policy.mipmap) { + texture.minFilter = SO_TEXTURE_FILTER_LINEAR; + texture.magFilter = SO_TEXTURE_FILTER_LINEAR; + } + else if (!policy.linearMipmap) { + texture.minFilter = SO_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR; + texture.magFilter = SO_TEXTURE_FILTER_LINEAR; + } + else { + texture.minFilter = SO_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR; + texture.magFilter = SO_TEXTURE_FILTER_LINEAR; + } + + // Preserve the LegacyGL quality policy in the neutral IR. The GL + // executor selects the active driver's supported anisotropy level. + texture.anisotropic = policy.anisotropic; +} + } // namespace SbBool @@ -387,29 +436,62 @@ SoIRDumpFirstN(const SoDrawList & drawlist, int count) namespace SoRenderIR { +static void fillTextureFromState(SoState * state, SoIRRenderAction * action, + SoMaterialData & material); + +static SoTextureWrap +textureWrapFromLegacy(SoMultiTextureImageElement::Wrap wrap) +{ + switch (wrap) { + case SoMultiTextureImageElement::REPEAT: + return SO_TEXTURE_WRAP_REPEAT; + case SoMultiTextureImageElement::CLAMP_TO_BORDER: + return SO_TEXTURE_WRAP_CLAMP_TO_BORDER; + case SoMultiTextureImageElement::CLAMP: + default: + // GL_CLAMP is the historical Coin spelling for edge clamping here. + return SO_TEXTURE_WRAP_CLAMP_TO_EDGE; + } +} + +static bool +hasTexture(const SoMaterialData & material) +{ + return material.texture.pixels != nullptr && + material.texture.width > 0 && material.texture.height > 0 && + material.texture.numComponents > 0; +} + void -fillCommandStateFromState(SoState * state, SoDrawList & drawlist, - SoRenderCommand & command) +fillCommandStateFromAction(SoIRRenderAction * action, + SoRenderCommand & command, + const int materialIndex) { + SoState * state = action->getState(); + SoDrawList & drawlist = action->getMutableDrawList(); command.modelMatrix = SoModelMatrixElement::get(state); command.viewMatrix = SoViewingMatrixElement::get(state); command.projMatrix = SoProjectionMatrixElement::get(state); - fillMaterialFromState(state, command.material); + fillMaterialFromState(state, command.material, materialIndex); + fillTextureFromState(state, action, command.material); fillRenderStateFromState(state, command.state); - ensureMaterialBlendState(command.state, command.material); command.lightingHandle = fillLightingFromState(state, drawlist); } void -fillMaterialFromState(SoState * state, SoMaterialData & material) +fillMaterialFromState(SoState * state, SoMaterialData & material, + int materialIndex) { SoState * mutableState = state; - const SbColor & diffuse = SoLazyElement::getDiffuse(mutableState, 0); + const SbColor & diffuse = SoLazyElement::getDiffuse(mutableState, materialIndex); const SbColor & ambient = SoLazyElement::getAmbient(mutableState); const SbColor & specular = SoLazyElement::getSpecular(mutableState); const SbColor & emissive = SoLazyElement::getEmissive(mutableState); - const float transparency = SoLazyElement::getTransparency(mutableState, 0); + const float transparency = SoLazyElement::getTransparency(mutableState, materialIndex); + // Keep diffuse and emissive independent. The explicit lighting shader owns + // emissive contribution, so inferring diffuse from a default-looking + // material would double-count emissive-only materials. material.diffuse.setValue(diffuse[0], diffuse[1], diffuse[2], 1.0f - transparency); @@ -429,10 +511,52 @@ fillMaterialFromState(SoState * state, SoMaterialData & material) material.shininess = SoLazyElement::getShininess(mutableState); material.opacity = 1.0f - transparency; + material.texture = SoTextureData(); material.textureAlphaIncludesOpacity = false; material.vertexColorAlphaIncludesOpacity = false; } +static void +fillTextureFromState(SoState * state, SoIRRenderAction * action, + SoMaterialData & material) +{ + if (!state || !action || !SoMultiTextureEnabledElement::get(state, 0)) { + return; + } + + SbVec2s size; + int numComponents = 0; + SoMultiTextureImageElement::Wrap wrapS; + SoMultiTextureImageElement::Wrap wrapT; + SoMultiTextureImageElement::Model model; + SbColor blendColor; + const unsigned char * bytes = SoMultiTextureImageElement::get( + state, 0, size, numComponents, wrapS, wrapT, model, blendColor); + if (!bytes || size[0] <= 0 || size[1] <= 0 || + numComponents < 1 || numComponents > 4) { + return; + } + + const size_t pixelCount = static_cast(size[0]) * + static_cast(size[1]); + const size_t byteCount = pixelCount * static_cast(numComponents); + unsigned char * copy = static_cast( + action->allocateGeometryStorage(byteCount, alignof(unsigned char))); + std::memcpy(copy, bytes, byteCount); + + material.texture.pixels = copy; + material.texture.width = size[0]; + material.texture.height = size[1]; + material.texture.numComponents = numComponents; + material.texture.wrapS = textureWrapFromLegacy(wrapS); + material.texture.wrapT = textureWrapFromLegacy(wrapT); + material.texture.model = textureModelFromLegacy(model); + material.texture.blendColor.setValue(blendColor[0], blendColor[1], + blendColor[2], 1.0f); + textureFiltersFromQuality(SoTextureQualityElement::get(state), + material.texture); +} + void fillRenderStateFromState(SoState * state, SoRenderState & rs) { @@ -468,6 +592,7 @@ fillRenderStateFromState(SoState * state, SoRenderState & rs) rs.blend.dstAlphaFactor = rs.blend.dstRGBFactor; } + // LegacyGL does not expose a Coin state element for blend equations. ADD // is its effective equation and is the only value that can be captured // deterministically from traversal. @@ -475,9 +600,9 @@ fillRenderStateFromState(SoState * state, SoRenderState & rs) rs.blend.alphaEquation = SO_BLEND_EQUATION_ADD; float alphaTestValue = 0.5f; - const int alphaTestFunction = SoLazyElement::getAlphaTest(mutableState, - alphaTestValue); - rs.alphaTest.function = alphaTestFunctionFromLegacyGL(alphaTestFunction); + const int alphaTestFunction = SoLazyElementP::getAlphaTestSemantic( + mutableState, alphaTestValue); + rs.alphaTest.function = static_cast(alphaTestFunction); rs.alphaTest.reference = alphaTestValue; rs.alphaTest.policy = rs.alphaTest.function == SO_ALPHA_TEST_NONE ? SO_ALPHA_TEST_POLICY_NONE @@ -625,7 +750,7 @@ ensureMaterialBlendState(SoRenderState & renderState, // transparency setup. Make that implicit IR contract explicit without // replacing an actual non-standard blend state. if (renderState.blend.enabled || - !isMaterialTransparent(material)) { + (!isMaterialTransparent(material) && !hasTexture(material))) { return; } @@ -638,4 +763,30 @@ ensureMaterialBlendState(SoRenderState & renderState, renderState.blend.alphaEquation = SO_BLEND_EQUATION_ADD; } +void +finalizeCommand(SoRenderCommand & command) +{ + ensureMaterialBlendState(command.state, command.material); + bool transparent = isMaterialTransparent(command.material); + if (!transparent && command.geometry.colors) { + for (uint32_t i = 0; i < command.geometry.vertexCount; ++i) { + if (command.geometry.colors[i * 4 + 3] < 0.999f) { + transparent = true; + break; + } + } + } + command.pass = transparent ? SO_RENDERPASS_TRANSPARENT + : SO_RENDERPASS_OPAQUE; + if (transparent && !command.state.blend.enabled) { + command.state.blend.enabled = TRUE; + command.state.blend.srcRGBFactor = SO_BLEND_FACTOR_SRC_ALPHA; + command.state.blend.dstRGBFactor = SO_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + command.state.blend.srcAlphaFactor = SO_BLEND_FACTOR_SRC_ALPHA; + command.state.blend.dstAlphaFactor = SO_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + } + command.sortKey = SoIRComputeSortKey( + command, static_cast(command.pass), 0); +} + } // namespace SoRenderIR diff --git a/src/rendering/SoRenderIRP.h b/src/rendering/SoRenderIRP.h index 774472c692..6f0178b55c 100644 --- a/src/rendering/SoRenderIRP.h +++ b/src/rendering/SoRenderIRP.h @@ -58,10 +58,12 @@ SbBool coin_render_ir_trace_enabled(); */ namespace SoRenderIR { //! Capture the ordinary traversal state shared by retained shape producers. -void fillCommandStateFromState(SoState * state, SoDrawList & drawlist, - SoRenderCommand & command); +void fillCommandStateFromAction(SoIRRenderAction * action, + SoRenderCommand & command, + int materialIndex = 0); //! Fill a material snapshot from the current Inventor traversal state. -void fillMaterialFromState(SoState * state, SoMaterialData & material); +void fillMaterialFromState(SoState * state, SoMaterialData & material, + int materialIndex = 0); //! Fill render-state fields from the current Inventor traversal state. void fillRenderStateFromState(SoState * state, SoRenderState & renderState); //! Complete blend state after material opacity has been captured. @@ -71,6 +73,8 @@ void ensureMaterialBlendState(SoRenderState & renderState, SoLightingHandle fillLightingFromState(SoState * state, SoDrawList & drawlist); //! Return whether the material should be treated as translucent. bool isMaterialTransparent(const SoMaterialData & material); +//! Complete derived command state after producer-specific adjustments. +void finalizeCommand(SoRenderCommand & command); } #endif // COIN_SORENDERIRP_H diff --git a/src/rendering/SoTextureQualityPolicy.h b/src/rendering/SoTextureQualityPolicy.h new file mode 100644 index 0000000000..5b0f845af2 --- /dev/null +++ b/src/rendering/SoTextureQualityPolicy.h @@ -0,0 +1,82 @@ +// src/rendering/SoTextureQualityPolicy.h + +#ifndef COIN_SOTEXTUREQUALITYPOLICY_H +#define COIN_SOTEXTUREQUALITYPOLICY_H + +#include "tidbitsp.h" + +#include + +// This is the shared semantic quality decision used by LegacyGL and retained +// capture. API-specific code maps the result to its own sampler state. +struct CoinTextureQualityLimits { + float linear = 0.2f; + float mipmap = 0.5f; + float linearMipmap = 0.8f; + float anisotropic = 0.85f; +}; + +inline float +coin_texture_quality_limit(const char * name, const float fallback) +{ + const char * value = coin_getenv(name); + if (!value) return fallback; + const float parsed = static_cast(std::atof(value)); + return parsed >= 0.0f && parsed <= 1.0f ? parsed : fallback; +} + +inline float +coin_texture_anisotropic_limit() +{ + const char * value = coin_getenv("COIN_TEX2_ANISOTROPIC_LIMIT"); + return value ? static_cast(std::atof(value)) : 0.85f; +} + +inline CoinTextureQualityLimits +coin_read_texture_quality_limits() +{ + CoinTextureQualityLimits limits; + limits.linear = coin_texture_quality_limit( + "COIN_TEX2_LINEAR_LIMIT", limits.linear); + limits.mipmap = coin_texture_quality_limit( + "COIN_TEX2_MIPMAP_LIMIT", limits.mipmap); + limits.linearMipmap = coin_texture_quality_limit( + "COIN_TEX2_LINEAR_MIPMAP_LIMIT", limits.linearMipmap); + // LegacyGL intentionally accepts the anisotropic threshold verbatim. In + // particular, it does not clamp out-of-range environment values the way + // the ordinary quality thresholds are validated. + limits.anisotropic = coin_texture_anisotropic_limit(); + return limits; +} + +inline const CoinTextureQualityLimits & +coin_get_texture_quality_limits() +{ + // SoGLImage caches these values on first use. Keep retained capture on the + // same one-time snapshot instead of rereading the environment for every + // command. + static const CoinTextureQualityLimits limits = + coin_read_texture_quality_limits(); + return limits; +} + +struct CoinTextureQualityPolicy { + bool linear = false; + bool mipmap = false; + bool linearMipmap = false; + bool anisotropic = false; +}; + +inline CoinTextureQualityPolicy +coin_get_texture_quality_policy(const float quality) +{ + const CoinTextureQualityLimits & limits = coin_get_texture_quality_limits(); + CoinTextureQualityPolicy policy; + policy.linear = quality >= limits.linear; + policy.mipmap = quality >= limits.mipmap; + policy.linearMipmap = quality >= limits.linearMipmap; + policy.anisotropic = quality > limits.anisotropic; + return policy; +} + +#endif // COIN_SOTEXTUREQUALITYPOLICY_H diff --git a/src/shapenodes/SoShape.cpp b/src/shapenodes/SoShape.cpp index f277d0828f..fe5a7e9158 100644 --- a/src/shapenodes/SoShape.cpp +++ b/src/shapenodes/SoShape.cpp @@ -215,7 +215,8 @@ class SoIRPrimitiveAssembler : public SoIRRenderAction::PrimitiveCollector { SoRenderCommand command = {}; this->fillGeometry(command.geometry); SoRenderIR::fillCommandStateFromState( - this->action->getState(), this->action->getMutableDrawList(), command); + this->action->getState(), this->action, + this->action->getMutableDrawList(), command); command.material.vertexColorAlphaIncludesOpacity = command.geometry.colors != nullptr; this->action->addCommand(command); From ac0df0ff8ec322a03e70ba6d86c8db38b263127a Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 12 Aug 2026 09:15:50 +0100 Subject: [PATCH 03/10] rendering: retain per-material geometry and alpha Retain alpha and generated vertex transparency alongside per-material geometry batches. --- include/Inventor/nodes/SoAlphaTest.h | 2 + src/nodes/SoTexture2.cpp | 2 +- src/shapenodes/SoShape.cpp | 170 ++++++++++++++++++++------- 3 files changed, 132 insertions(+), 42 deletions(-) diff --git a/include/Inventor/nodes/SoAlphaTest.h b/include/Inventor/nodes/SoAlphaTest.h index f43de64ff0..c285ff90da 100644 --- a/include/Inventor/nodes/SoAlphaTest.h +++ b/include/Inventor/nodes/SoAlphaTest.h @@ -61,6 +61,8 @@ class COIN_DLL_API SoAlphaTest : public SoNode { SoSFEnum function; SoSFFloat value; + void doAction(SoAction * action) override; + #if COIN_HAVE_LEGACY_GL_RENDERER void GLRender(SoGLRenderAction * action) override; #endif diff --git a/src/nodes/SoTexture2.cpp b/src/nodes/SoTexture2.cpp index 416a128945..7e81c60bad 100644 --- a/src/nodes/SoTexture2.cpp +++ b/src/nodes/SoTexture2.cpp @@ -663,8 +663,8 @@ SoTexture2::doAction(SoAction * action) if (size != SbVec2s(0,0)) { SoMultiTextureImageElement::set(state, this, unit, size, nc, bytes, - (SoMultiTextureImageElement::Wrap)this->wrapT.getValue(), (SoMultiTextureImageElement::Wrap)this->wrapS.getValue(), + (SoMultiTextureImageElement::Wrap)this->wrapT.getValue(), (SoMultiTextureImageElement::Model) model.getValue(), this->blendColor.getValue()); SoMultiTextureEnabledElement::set(state, this, unit, TRUE); diff --git a/src/shapenodes/SoShape.cpp b/src/shapenodes/SoShape.cpp index fe5a7e9158..3f05acc4c9 100644 --- a/src/shapenodes/SoShape.cpp +++ b/src/shapenodes/SoShape.cpp @@ -50,6 +50,8 @@ class SoVBO; #include #include +#include "elements/SoLazyElementP.h" + #include #include #include @@ -154,52 +156,54 @@ class SoVBO; namespace { -static SbVec4f -so_ir_effective_vertex_color(SoState * state, int materialIndex) -{ - if (materialIndex < 0) materialIndex = 0; - const SbColor & diffuse = SoLazyElement::getDiffuse(state, materialIndex); - const float transparency = SoLazyElement::getTransparency( - state, materialIndex); - return SbVec4f(diffuse[0], diffuse[1], diffuse[2], 1.0f - transparency); -} - struct SoIRVertex { SbVec3f position; SbVec3f normal; SbVec4f texcoord; - SbVec4f color; + int materialIndex = 0; +}; + +struct SoIRBatch { + size_t first = 0; + size_t count = 0; + int materialIndex = -1; + + SoIRBatch(size_t first, size_t count, int materialIndex) + : first(first), count(count), materialIndex(materialIndex) {} +}; + +struct SoIRMaterialBatchPlan { + std::vector batches; + bool needsVertexColors = false; }; class SoIRPrimitiveAssembler : public SoIRRenderAction::PrimitiveCollector { public: SoIRPrimitiveAssembler(SoIRRenderAction * action, SoShape * shape) - : action(action), shape(shape), topology(SO_TOPOLOGY_COUNT), - hasVertexColors(SoMaterialBindingElement::get(action->getState()) != - SoMaterialBindingElement::OVERALL) {} + : action(action), shape(shape), topology(SO_TOPOLOGY_COUNT) {} void onTriangle(const SoPrimitiveVertex * v1, const SoPrimitiveVertex * v2, const SoPrimitiveVertex * v3) override { this->setTopology(SO_TOPOLOGY_TRIANGLES); - this->append(v1); - this->append(v2); - this->append(v3); + this->append(v1, v1->getMaterialIndex()); + this->append(v2, v2->getMaterialIndex()); + this->append(v3, v3->getMaterialIndex()); } void onLine(const SoPrimitiveVertex * v1, const SoPrimitiveVertex * v2) override { this->setTopology(SO_TOPOLOGY_LINES); - this->append(v1); - this->append(v2); + this->append(v1, v1->getMaterialIndex()); + this->append(v2, v2->getMaterialIndex()); } void onPoint(const SoPrimitiveVertex * v) override { this->setTopology(SO_TOPOLOGY_POINTS); - this->append(v); + this->append(v, v->getMaterialIndex()); } void finalize() @@ -212,19 +216,67 @@ class SoIRPrimitiveAssembler : public SoIRRenderAction::PrimitiveCollector { { if (this->vertices.empty()) return; - SoRenderCommand command = {}; - this->fillGeometry(command.geometry); - SoRenderIR::fillCommandStateFromState( - this->action->getState(), this->action, - this->action->getMutableDrawList(), command); - command.material.vertexColorAlphaIncludesOpacity = - command.geometry.colors != nullptr; - this->action->addCommand(command); - + SoState * state = this->action->getState(); + SoGeometryDesc geometry = {}; + std::vector batches; + this->fillGeometry(state, geometry, batches); + this->emitCommands(state, geometry, batches); this->vertices.clear(); } - void fillGeometry(SoGeometryDesc & geometry) + SoIRMaterialBatchPlan buildMaterialBatches(SoState * state) + { + SoIRMaterialBatchPlan plan; + const size_t count = this->vertices.size(); + const size_t primitiveWidth = this->topology == SO_TOPOLOGY_TRIANGLES ? 3 + : this->topology == SO_TOPOLOGY_LINES ? 2 : 1; + + const SoMaterialBindingElement::Binding materialBinding = + SoMaterialBindingElement::get(state); + const bool hasExplicitMaterialIndices = + materialBinding == SoMaterialBindingElement::PER_PART || + materialBinding == SoMaterialBindingElement::PER_PART_INDEXED || + materialBinding == SoMaterialBindingElement::PER_FACE || + materialBinding == SoMaterialBindingElement::PER_FACE_INDEXED || + materialBinding == SoMaterialBindingElement::PER_VERTEX_INDEXED; + const bool hasPerVertexMaterials = + materialBinding == SoMaterialBindingElement::PER_VERTEX || + materialBinding == SoMaterialBindingElement::PER_VERTEX_INDEXED; + + if (!hasExplicitMaterialIndices) { + plan.batches.push_back(SoIRBatch(0, count, 0)); + } + for (size_t first = 0; hasExplicitMaterialIndices && first < count;) { + const size_t primitiveCount = std::min(primitiveWidth, count - first); + int materialIndex = this->vertices[first].materialIndex; + for (size_t i = 1; i < primitiveCount; ++i) { + if (this->vertices[first + i].materialIndex != materialIndex) { + materialIndex = -1; + break; + } + } + if (plan.batches.empty() || + plan.batches.back().materialIndex != materialIndex) { + plan.batches.push_back(SoIRBatch(first, primitiveCount, materialIndex)); + } + else { + plan.batches.back().count += primitiveCount; + } + first += primitiveCount; + } + plan.needsVertexColors = hasPerVertexMaterials; + for (const SoIRBatch & batch : plan.batches) { + if (batch.materialIndex < 0) { + plan.needsVertexColors = true; + break; + } + } + return plan; + } + + void fillGeometry(SoState * state, + SoGeometryDesc & geometry, + std::vector & batches) { const size_t count = this->vertices.size(); geometry.topology = this->topology; @@ -239,8 +291,11 @@ class SoIRPrimitiveAssembler : public SoIRRenderAction::PrimitiveCollector { this->action->allocateGeometryStorage(sizeof(float) * 3 * count)); float * texcoords = static_cast( this->action->allocateGeometryStorage(sizeof(float) * 4 * count)); + const SoIRMaterialBatchPlan plan = this->buildMaterialBatches(state); + batches = plan.batches; + float * colors = nullptr; - if (this->hasVertexColors) { + if (plan.needsVertexColors) { colors = static_cast( this->action->allocateGeometryStorage(sizeof(float) * 4 * count)); } @@ -258,10 +313,13 @@ class SoIRPrimitiveAssembler : public SoIRRenderAction::PrimitiveCollector { texcoords[i * 4 + 2] = vertex.texcoord[2]; texcoords[i * 4 + 3] = vertex.texcoord[3]; if (colors) { - colors[i * 4 + 0] = vertex.color[0]; - colors[i * 4 + 1] = vertex.color[1]; - colors[i * 4 + 2] = vertex.color[2]; - colors[i * 4 + 3] = vertex.color[3]; + const int materialIndex = std::max(vertex.materialIndex, 0); + const SbColor & color = SoLazyElement::getDiffuse(state, materialIndex); + const float alpha = 1.0f - SoLazyElement::getTransparency(state, materialIndex); + colors[i * 4 + 0] = color[0]; + colors[i * 4 + 1] = color[1]; + colors[i * 4 + 2] = color[2]; + colors[i * 4 + 3] = alpha; } } @@ -271,6 +329,40 @@ class SoIRPrimitiveAssembler : public SoIRRenderAction::PrimitiveCollector { geometry.colors = colors; } + void emitCommands(SoState * state, + const SoGeometryDesc & sourceGeometry, + const std::vector & batches) + { + for (const SoIRBatch & batch : batches) { + SoRenderCommand command = {}; + command.geometry = sourceGeometry; + command.geometry.vertexCount = static_cast(batch.count); + command.geometry.normalCount = command.geometry.vertexCount; + command.geometry.positions = sourceGeometry.positions + batch.first * 3; + command.geometry.normals = sourceGeometry.normals + batch.first * 3; + command.geometry.texcoords = sourceGeometry.texcoords + batch.first * 4; + command.geometry.colors = sourceGeometry.colors + ? sourceGeometry.colors + batch.first * 4 : nullptr; + + SoRenderIR::fillCommandStateFromAction( + this->action, command, std::max(batch.materialIndex, 0)); + const bool packedVertexColors = + SoLazyElementP::hasPackedVertexColorState(state); + if (packedVertexColors) { + const float inheritedOpacity = + SoLazyElementP::getPackedVertexColorOpacity( + state, std::max(batch.materialIndex, 0)); + command.material.opacity = inheritedOpacity; + command.material.diffuse[3] = inheritedOpacity; + } + command.material.vertexColorAlphaIncludesOpacity = + command.geometry.colors != nullptr && !packedVertexColors; + SoRenderIR::finalizeCommand(command); + command.userData = this->shape; + this->action->addCommand(command); + } + } + void setTopology(SoPrimitiveTopology candidate) { if (this->topology == candidate) return; @@ -279,23 +371,19 @@ class SoIRPrimitiveAssembler : public SoIRRenderAction::PrimitiveCollector { this->topology = candidate; } - void append(const SoPrimitiveVertex * vertex) + void append(const SoPrimitiveVertex * vertex, int materialIndex) { SoIRVertex copy; copy.position = vertex->getPoint(); copy.normal = vertex->getNormal(); copy.texcoord = vertex->getTextureCoords(); - if (this->hasVertexColors) { - copy.color = so_ir_effective_vertex_color( - this->action->getState(), vertex->getMaterialIndex()); - } + copy.materialIndex = materialIndex; this->vertices.push_back(copy); } SoIRRenderAction * action; SoShape * shape; SoPrimitiveTopology topology; - bool hasVertexColors; std::vector vertices; }; From 03b2634fe97de082be426da869d510db28e56934 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Fri, 14 Aug 2026 08:23:47 +0100 Subject: [PATCH 04/10] rendering: execute retained material and lighting semantics --- data/shaders/gl/common/VertexColor.glsl | 9 - data/shaders/gl/material/AlphaTest.glsl | 31 ++ .../gl/material/FragmentEvaluation.glsl | 39 ++ data/shaders/gl/material/Lighting.glsl | 62 +++ data/shaders/gl/material/Texture.glsl | 47 ++ .../shaders/gl/material/VertexEvaluation.glsl | 47 ++ data/shaders/gl/visual/Fragment.glsl | 17 +- data/shaders/gl/visual/Vertex.glsl | 33 +- include/Inventor/rendering/SoRenderIR.h | 15 + src/rendering/SoGLRenderBackend.cpp | 493 ++++++++++++++++-- src/rendering/SoGLRenderBackend.h | 77 ++- src/rendering/SoRenderIR.cpp | 6 +- src/rendering/SoRenderPlan.cpp | 55 +- src/rendering/SoRenderPlan.h | 3 + testsuite/RenderPlanTest.cpp | 25 + 15 files changed, 867 insertions(+), 92 deletions(-) create mode 100644 data/shaders/gl/material/AlphaTest.glsl create mode 100644 data/shaders/gl/material/FragmentEvaluation.glsl create mode 100644 data/shaders/gl/material/Lighting.glsl create mode 100644 data/shaders/gl/material/Texture.glsl create mode 100644 data/shaders/gl/material/VertexEvaluation.glsl diff --git a/data/shaders/gl/common/VertexColor.glsl b/data/shaders/gl/common/VertexColor.glsl index 3e3ea5eee4..6d655b5c6d 100644 --- a/data/shaders/gl/common/VertexColor.glsl +++ b/data/shaders/gl/common/VertexColor.glsl @@ -5,12 +5,3 @@ vec4 coin_visual_color(vec4 vertexColor, vec4 uniformColor, { return useVertexColor > 0.5 ? vertexColor : uniformColor; } - -vec4 coin_visual_texture(vec4 color, sampler2D textureSampler, - vec2 texcoord, float textureEnabled, - vec4 textureModulation) -{ - return textureEnabled > 0.5 - ? color * texture(textureSampler, texcoord) * textureModulation - : color; -} diff --git a/data/shaders/gl/material/AlphaTest.glsl b/data/shaders/gl/material/AlphaTest.glsl new file mode 100644 index 0000000000..2db26bd2fe --- /dev/null +++ b/data/shaders/gl/material/AlphaTest.glsl @@ -0,0 +1,31 @@ +/* + * Retained alpha-test comparison helper. + * + * The caller supplies the alpha whose coverage semantics apply to the + * producer. This module performs only the comparison; it does not decide + * pass ordering, blending, or which producer alpha should be tested. + */ + +const int COIN_ALPHA_TEST_NONE = 0; +const int COIN_ALPHA_TEST_NEVER = 1; +const int COIN_ALPHA_TEST_ALWAYS = 2; +const int COIN_ALPHA_TEST_LESS = 3; +const int COIN_ALPHA_TEST_LEQUAL = 4; +const int COIN_ALPHA_TEST_EQUAL = 5; +const int COIN_ALPHA_TEST_GEQUAL = 6; +const int COIN_ALPHA_TEST_GREATER = 7; +const int COIN_ALPHA_TEST_NOTEQUAL = 8; + +bool coin_material_alpha_test_pass(float alpha, int function, + float reference) +{ + if (function == COIN_ALPHA_TEST_NEVER) return false; + if (function == COIN_ALPHA_TEST_ALWAYS) return true; + if (function == COIN_ALPHA_TEST_LESS) return alpha < reference; + if (function == COIN_ALPHA_TEST_LEQUAL) return alpha <= reference; + if (function == COIN_ALPHA_TEST_EQUAL) return alpha == reference; + if (function == COIN_ALPHA_TEST_GEQUAL) return alpha >= reference; + if (function == COIN_ALPHA_TEST_GREATER) return alpha > reference; + if (function == COIN_ALPHA_TEST_NOTEQUAL) return alpha != reference; + return true; +} diff --git a/data/shaders/gl/material/FragmentEvaluation.glsl b/data/shaders/gl/material/FragmentEvaluation.glsl new file mode 100644 index 0000000000..35ca4c9bae --- /dev/null +++ b/data/shaders/gl/material/FragmentEvaluation.glsl @@ -0,0 +1,39 @@ +/* + * Shared material and texture evaluation for surface fragments. + * + * The returned RGBA is the surface coverage used by visual, line, and point + * roots. Alpha testing remains a caller decision so alternate output roots + * can share coverage without sharing framebuffer or selection policy. + */ + +uniform sampler2D u_texture; +uniform float u_textureEnabled; +uniform int u_textureModel; +uniform vec4 u_textureBlendColor; +uniform vec4 u_color; +uniform float u_useVertexColor; +uniform float u_vertexColorAlphaIncludesOpacity; +uniform float u_textureAlphaIncludesOpacity; +uniform float u_textureHasAlpha; +uniform int u_alphaTestFunction; +uniform float u_alphaTestReference; + +#include "Texture.glsl" +#include "AlphaTest.glsl" + +vec4 +coin_surface_fragment_color(vec4 vertexColor, vec3 litColor, vec2 texcoord) +{ + float materialAlpha = u_color.a; + if (u_useVertexColor > 0.5 && + u_vertexColorAlphaIncludesOpacity > 0.5) { + materialAlpha = 1.0; + } + if (u_textureEnabled > 0.5) { + return coin_material_textured_color( + u_texture, texcoord, vec4(litColor, vertexColor.a), materialAlpha, + u_textureAlphaIncludesOpacity, u_textureHasAlpha, u_textureModel, + u_textureBlendColor); + } + return vec4(litColor, vertexColor.a * materialAlpha); +} diff --git a/data/shaders/gl/material/Lighting.glsl b/data/shaders/gl/material/Lighting.glsl new file mode 100644 index 0000000000..6a9a1c465b --- /dev/null +++ b/data/shaders/gl/material/Lighting.glsl @@ -0,0 +1,62 @@ +/* + * Retained Gouraud lighting evaluation. + * + * Inputs are the captured view-space light/material uniforms and the base + * surface color. This module computes lighting only; framebuffer, pass, + * texture and alpha-test policy belong to the calling shader roots. + */ + +const int COIN_MAX_LIGHTS = 8; +const int COIN_LIGHT_DIRECTIONAL = 0; +const int COIN_LIGHT_POINT = 1; +const int COIN_LIGHT_SPOT = 2; + +vec3 coin_material_compute_gouraud_color(vec3 eyePos, vec3 eyeNormal, + vec3 baseColor) +{ + vec3 N = normalize(eyeNormal); + vec3 V = normalize(-eyePos); + if (u_twoSidedLighting > 0.5 && dot(N, V) < 0.0) { + N = -N; + } + vec3 litColor = u_ambientLight * u_materialAmbient; + + for (int i = 0; i < COIN_MAX_LIGHTS; ++i) { + if (i >= u_lightCount) break; + + vec3 L = u_lightDirection[i]; + float attenuation = 1.0; + float spotFactor = 1.0; + if (u_lightType[i] != COIN_LIGHT_DIRECTIONAL) { + vec3 lightVector = u_lightPosition[i] - eyePos; + float distanceToLight = length(lightVector); + if (distanceToLight <= 0.0001) continue; + L = lightVector / distanceToLight; + vec3 att = u_lightAttenuation[i]; + attenuation = 1.0 / max(att.z + att.y * distanceToLight + + att.x * distanceToLight * distanceToLight, + 0.0001); + if (u_lightType[i] == COIN_LIGHT_SPOT) { + vec3 coneDir = normalize(u_lightDirection[i]); + vec3 fromLight = normalize(eyePos - u_lightPosition[i]); + float spotCos = dot(coneDir, fromLight); + if (spotCos < u_lightSpotParams[i].x) continue; + spotFactor = pow(max(spotCos, 0.0), u_lightSpotParams[i].y); + } + } + + vec3 Ln = normalize(L); + float NdotL = max(dot(N, Ln), 0.0); + if (NdotL <= 0.0) continue; + vec3 H = normalize(Ln + V); + float NdotH = max(dot(N, H), 0.0); + float shininess = max(u_materialShininess * 128.0, 0.0); + float specularFactor = shininess > 0.0 + ? pow(NdotH, shininess) : 0.0; + vec3 diffuse = baseColor * NdotL; + vec3 specular = u_materialSpecular * specularFactor; + litColor += u_lightColor[i] * attenuation * spotFactor * + (diffuse + specular); + } + return clamp(litColor + u_emissiveColor, 0.0, 1.0); +} diff --git a/data/shaders/gl/material/Texture.glsl b/data/shaders/gl/material/Texture.glsl new file mode 100644 index 0000000000..2c0bfb9032 --- /dev/null +++ b/data/shaders/gl/material/Texture.glsl @@ -0,0 +1,47 @@ +/* + * Retained material texture evaluation. + * + * Applies Coin's texture model and alpha semantics to a supplied surface + * color. It does not choose a render pass or perform alpha testing; callers + * retain those decisions explicitly so visual, picking, and selection roots + * can share coverage without sharing output policy. + */ + +const int COIN_TEXTURE_MODEL_MODULATE = 0; +const int COIN_TEXTURE_MODEL_DECAL = 1; +const int COIN_TEXTURE_MODEL_BLEND = 2; +const int COIN_TEXTURE_MODEL_REPLACE = 3; + +vec4 coin_material_textured_color(sampler2D textureSampler, vec2 texcoord, + vec4 visualColor, float materialAlpha, + float textureAlphaIncludesOpacity, + float textureHasAlpha, + int textureModel, vec4 blendColor) +{ + vec4 texel = texture(textureSampler, texcoord); + float primaryAlpha = visualColor.a * + (textureAlphaIncludesOpacity > 0.5 ? 1.0 : materialAlpha); + float textureAlpha = textureHasAlpha > 0.5 ? texel.a : 1.0; + vec3 rgb = visualColor.rgb; + float alpha = primaryAlpha; + + switch (textureModel) { + case COIN_TEXTURE_MODEL_DECAL: + rgb = mix(visualColor.rgb, texel.rgb, textureAlpha); + break; + case COIN_TEXTURE_MODEL_BLEND: + rgb = mix(visualColor.rgb, blendColor.rgb, texel.rgb); + alpha = primaryAlpha * textureAlpha; + break; + case COIN_TEXTURE_MODEL_REPLACE: + rgb = texel.rgb; + alpha = textureHasAlpha > 0.5 ? texel.a : primaryAlpha; + break; + case COIN_TEXTURE_MODEL_MODULATE: + default: + rgb = visualColor.rgb * texel.rgb; + alpha = primaryAlpha * textureAlpha; + break; + } + return vec4(rgb, alpha); +} diff --git a/data/shaders/gl/material/VertexEvaluation.glsl b/data/shaders/gl/material/VertexEvaluation.glsl new file mode 100644 index 0000000000..3a1844ace4 --- /dev/null +++ b/data/shaders/gl/material/VertexEvaluation.glsl @@ -0,0 +1,47 @@ +/* + * Shared surface evaluation for visual, wide-line, and point vertex stages. + * + * This module selects vertex color and computes optional view-space lighting. + * It owns no framebuffer output, raster-path selection, pass ordering, or + * alpha-test decision. + */ + +#include "../common/VertexColor.glsl" + +uniform mat4 u_proj; +uniform mat4 u_view; +uniform mat4 u_model; +uniform vec4 u_color; +uniform float u_useVertexColor; +uniform int u_shadingModel; +uniform vec3 u_emissiveColor; +uniform vec3 u_ambientLight; +uniform vec3 u_materialAmbient; +uniform vec3 u_materialSpecular; +uniform float u_materialShininess; +uniform float u_twoSidedLighting; +uniform int u_lightCount; +uniform int u_lightType[8]; +uniform vec3 u_lightColor[8]; +uniform vec3 u_lightDirection[8]; +uniform vec3 u_lightPosition[8]; +uniform vec3 u_lightAttenuation[8]; +uniform vec2 u_lightSpotParams[8]; + +#include "Lighting.glsl" + +vec4 +coin_surface_vertex_color(vec4 vertexColor) +{ + return coin_visual_color(vertexColor, vec4(u_color.rgb, 1.0), + u_useVertexColor); +} + +vec3 +coin_surface_lit_color(vec4 vertexColor, vec3 eyePosition, vec3 eyeNormal) +{ + return u_shadingModel == 0 + ? vertexColor.rgb + : coin_material_compute_gouraud_color(eyePosition, eyeNormal, + vertexColor.rgb); +} diff --git a/data/shaders/gl/visual/Fragment.glsl b/data/shaders/gl/visual/Fragment.glsl index b0f08c69d6..178d502e91 100644 --- a/data/shaders/gl/visual/Fragment.glsl +++ b/data/shaders/gl/visual/Fragment.glsl @@ -1,20 +1,19 @@ #version 330 core -/* Base retained visual fragment root: evaluate the bound surface and emit - * framebuffer color. Coverage policy remains explicit at this root. */ -#include "../common/VertexColor.glsl" - -uniform sampler2D u_texture; -uniform float u_textureEnabled; -uniform vec4 u_texModColor; +/* Visual surface fragment root: shared surface evaluation, explicit alpha + * test, then framebuffer color. */ +#include "../material/FragmentEvaluation.glsl" in vec4 v_color; +in vec3 v_litColor; in vec2 v_texcoord; out vec4 fragColor; void main() { - fragColor = coin_visual_texture(v_color, u_texture, v_texcoord, - u_textureEnabled, u_texModColor); + vec4 color = coin_surface_fragment_color(v_color, v_litColor, v_texcoord); + if (!coin_material_alpha_test_pass(color.a, u_alphaTestFunction, + u_alphaTestReference)) discard; + fragColor = color; } diff --git a/data/shaders/gl/visual/Vertex.glsl b/data/shaders/gl/visual/Vertex.glsl index 18599dc954..f6f3bb634d 100644 --- a/data/shaders/gl/visual/Vertex.glsl +++ b/data/shaders/gl/visual/Vertex.glsl @@ -1,28 +1,27 @@ #version 330 core -/* - * Base retained visual vertex root. The OpenGL backend requires 3.3 or newer; - * executable roots therefore use GLSL 330 core. Included files are semantic - * modules and intentionally provide no version directive or main(). - */ -#include "../common/VertexColor.glsl" - +/* Visual surface vertex root. The backend requires OpenGL 3.3 or newer, so + * executable roots use GLSL 330 core; this root wires shared vertex color and + * lighting evaluation into the ordinary triangle pipeline. */ +#include "../material/VertexEvaluation.glsl" layout(location = 0) in vec3 a_position; -layout(location = 1) in vec4 a_color; -layout(location = 2) in vec2 a_texcoord; - -uniform mat4 u_proj; -uniform mat4 u_view; -uniform mat4 u_model; -uniform vec4 u_color; -uniform float u_useVertexColor; +layout(location = 1) in vec3 a_normal; +layout(location = 2) in vec4 a_color; +layout(location = 3) in vec2 a_texcoord; out vec4 v_color; +out vec3 v_litColor; out vec2 v_texcoord; void main() { - v_color = (u_useVertexColor > 0.5) ? a_color : u_color; + v_color = coin_surface_vertex_color(a_color); v_texcoord = a_texcoord; - gl_Position = u_proj * u_view * u_model * vec4(a_position, 1.0); + + vec4 worldPos = u_model * vec4(a_position, 1.0); + vec4 eyePos = u_view * worldPos; + mat3 normalMatrix = transpose(inverse(mat3(u_view * u_model))); + vec3 eyeNormal = normalMatrix * a_normal; + v_litColor = coin_surface_lit_color(v_color, eyePos.xyz, eyeNormal); + gl_Position = u_proj * eyePos; } diff --git a/include/Inventor/rendering/SoRenderIR.h b/include/Inventor/rendering/SoRenderIR.h index dc16ddcbe5..b27c4064a0 100644 --- a/include/Inventor/rendering/SoRenderIR.h +++ b/include/Inventor/rendering/SoRenderIR.h @@ -376,6 +376,20 @@ struct SoRenderState { SoBlendState blend; SoAlphaTestState alphaTest; SoRasterState raster; + //! Use view/projection matrices captured with this command. + SbBool useCommandMatrices = FALSE; +}; + +/*! + \enum SoOpacityClass + \brief Semantic surface opacity classification used by the planner. + + This describes whether a command contributes translucent surface semantics. + It is not an execution pass and does not encode ordering. +*/ +enum SoOpacityClass : uint8_t { + SO_OPACITY_OPAQUE = 0, + SO_OPACITY_TRANSPARENT }; /*! @@ -439,6 +453,7 @@ struct SoRenderCommand { SbMatrix viewMatrix; SbMatrix projMatrix; + SoOpacityClass opacityClass = SO_OPACITY_OPAQUE; SoLightingHandle lightingHandle = 0; SoNodeId nodeId = 0; //!< Identity of the underlying scene node. SoInstanceId instanceId = 0; //!< Identity of this rendered occurrence. diff --git a/src/rendering/SoGLRenderBackend.cpp b/src/rendering/SoGLRenderBackend.cpp index c88bdf4500..0540c8a9b5 100644 --- a/src/rendering/SoGLRenderBackend.cpp +++ b/src/rendering/SoGLRenderBackend.cpp @@ -2,13 +2,18 @@ #include "rendering/SoGLRenderBackend.h" +#include +#include #include +#include #include "glue/glp.h" #include "glue/glslp.h" #include #include +#include +#include #include #include #include @@ -19,9 +24,113 @@ namespace { static constexpr int MAX_VERTEX_COUNT = 10000000; +static constexpr int MAX_SHADER_LIGHTS = 8; static constexpr GLuint POSITION_ATTRIBUTE = 0; -static constexpr GLuint COLOR_ATTRIBUTE = 1; -static constexpr GLuint TEXCOORD_ATTRIBUTE = 2; +static constexpr GLuint NORMAL_ATTRIBUTE = 1; +static constexpr GLuint COLOR_ATTRIBUTE = 2; +static constexpr GLuint TEXCOORD_ATTRIBUTE = 3; + +GLenum +textureWrapToGL(const SoTextureWrap wrap) +{ + switch (wrap) { + case SO_TEXTURE_WRAP_REPEAT: return GL_REPEAT; + case SO_TEXTURE_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER; + case SO_TEXTURE_WRAP_CLAMP_TO_EDGE: + default: return GL_CLAMP_TO_EDGE; + } +} + +GLenum +textureMinFilterToGL(const SoTextureFilter filter) +{ + switch (filter) { + case SO_TEXTURE_FILTER_LINEAR: return GL_LINEAR; + case SO_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST: + return GL_NEAREST_MIPMAP_NEAREST; + case SO_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST: + return GL_LINEAR_MIPMAP_NEAREST; + case SO_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR: + return GL_NEAREST_MIPMAP_LINEAR; + case SO_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR: + return GL_LINEAR_MIPMAP_LINEAR; + case SO_TEXTURE_FILTER_NEAREST: + default: return GL_NEAREST; + } +} + +GLenum +textureMagFilterToGL(const SoTextureFilter filter) +{ + return filter == SO_TEXTURE_FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; +} + +GLenum +blendFactorToGL(const SoBlendFactor factor) +{ + switch (factor) { + case SO_BLEND_FACTOR_ZERO: return GL_ZERO; + case SO_BLEND_FACTOR_ONE: return GL_ONE; + case SO_BLEND_FACTOR_SRC_COLOR: return GL_SRC_COLOR; + case SO_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; + case SO_BLEND_FACTOR_DST_COLOR: return GL_DST_COLOR; + case SO_BLEND_FACTOR_ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; + case SO_BLEND_FACTOR_SRC_ALPHA: return GL_SRC_ALPHA; + case SO_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; + case SO_BLEND_FACTOR_DST_ALPHA: return GL_DST_ALPHA; + case SO_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; + case SO_BLEND_FACTOR_CONSTANT_COLOR: return GL_CONSTANT_COLOR; + case SO_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: + return GL_ONE_MINUS_CONSTANT_COLOR; + case SO_BLEND_FACTOR_CONSTANT_ALPHA: return GL_CONSTANT_ALPHA; + case SO_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: + return GL_ONE_MINUS_CONSTANT_ALPHA; + case SO_BLEND_FACTOR_SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE; + case SO_BLEND_FACTOR_SRC1_COLOR: return GL_SRC_COLOR; + case SO_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR: return GL_ONE_MINUS_SRC_COLOR; + case SO_BLEND_FACTOR_SRC1_ALPHA: return GL_SRC_ALPHA; + case SO_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; + default: return GL_ONE; + } +} + +bool +isDualSourceBlendFactor(const SoBlendFactor factor) +{ + return factor == SO_BLEND_FACTOR_SRC1_COLOR || + factor == SO_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR || + factor == SO_BLEND_FACTOR_SRC1_ALPHA || + factor == SO_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; +} + +GLenum +blendEquationToGL(const SoBlendEquation equation) +{ + switch (equation) { + case SO_BLEND_EQUATION_SUBTRACT: return GL_FUNC_SUBTRACT; + case SO_BLEND_EQUATION_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT; + case SO_BLEND_EQUATION_MIN: return GL_MIN; + case SO_BLEND_EQUATION_MAX: return GL_MAX; + case SO_BLEND_EQUATION_ADD: + default: return GL_FUNC_ADD; + } +} + +GLenum +depthFunctionToGL(const SoDepthFunction function) +{ + switch (function) { + case SO_DEPTH_NEVER: return GL_NEVER; + case SO_DEPTH_ALWAYS: return GL_ALWAYS; + case SO_DEPTH_LESS: return GL_LESS; + case SO_DEPTH_LEQUAL: return GL_LEQUAL; + case SO_DEPTH_EQUAL: return GL_EQUAL; + case SO_DEPTH_GEQUAL: return GL_GEQUAL; + case SO_DEPTH_GREATER: return GL_GREATER; + case SO_DEPTH_NOTEQUAL: return GL_NOTEQUAL; + default: return GL_LEQUAL; + } +} GLenum topologyToGL(const SoPrimitiveTopology topology) @@ -224,9 +333,13 @@ SoGLRenderBackend::initialize(const SoRenderBackendInitParams & params) !this->glue->glEnableVertexAttribArray || !this->glue->glDisableVertexAttribArray || !this->glue->glVertexAttrib4f || + !this->glue->glVertexAttrib3f || !this->glue->glVertexAttrib2f || !this->glue->glUniform1f || !this->glue->glUniform1i || - !this->glue->glUniform4f || !this->glue->glUniformMatrix4fv) { + !this->glue->glUniform3f || !this->glue->glUniform1iv || + !this->glue->glUniform2fv || !this->glue->glUniform3fv || + !this->glue->glUniform4f || !this->glue->glUniformMatrix4fv || + !this->glue->glBlendFuncSeparate) { this->emitError("active context does not provide retained-renderer GL dispatch"); this->glue = nullptr; return FALSE; @@ -248,6 +361,9 @@ SoGLRenderBackend::destroyCacheEntry(CachedCommand & entry) if (entry.positionBuffer) { cc_glglue_glDeleteBuffers(this->glue, 1, &entry.positionBuffer); } + if (entry.normalBuffer) { + cc_glglue_glDeleteBuffers(this->glue, 1, &entry.normalBuffer); + } if (entry.colorBuffer) { cc_glglue_glDeleteBuffers(this->glue, 1, &entry.colorBuffer); } @@ -378,6 +494,21 @@ SoGLRenderBackend::uploadVertexBuffers(CachedCommand & entry, vertexStride, geometry.positions, GL_STATIC_DRAW); + if (geometry.normals && geometry.normalCount >= geometry.vertexCount) { + if (!entry.normalBuffer) { + cc_glglue_glGenBuffers(this->glue, 1, &entry.normalBuffer); + } + cc_glglue_glBindBuffer(this->glue, GL_ARRAY_BUFFER, entry.normalBuffer); + cc_glglue_glBufferData(this->glue, GL_ARRAY_BUFFER, + static_cast(geometry.vertexCount) * + vertexStride, + geometry.normals, GL_STATIC_DRAW); + } + else if (entry.normalBuffer) { + cc_glglue_glDeleteBuffers(this->glue, 1, &entry.normalBuffer); + entry.normalBuffer = 0; + } + if (geometry.colors && geometry.vertexCount) { if (!entry.colorBuffer) { cc_glglue_glGenBuffers(this->glue, 1, &entry.colorBuffer); @@ -430,10 +561,30 @@ SoGLRenderBackend::uploadTexture(CachedCommand & entry, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, format.swizzle[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, format.swizzle[2]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, format.swizzle[3]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + textureMinFilterToGL(texture.minFilter)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + textureMagFilterToGL(texture.magFilter)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + textureWrapToGL(texture.wrapS)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + textureWrapToGL(texture.wrapT)); + const bool mipmapped = + texture.minFilter == SO_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST || + texture.minFilter == SO_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST || + texture.minFilter == SO_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR || + texture.minFilter == SO_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR; + if (mipmapped && this->glue->glGenerateMipmap) { + this->glue->glGenerateMipmap(GL_TEXTURE_2D); + } + if (SoGLDriverDatabase::isSupported( + this->glue, SbName(SO_GL_ANISOTROPIC_FILTERING))) { + const float supported = cc_glglue_get_max_anisotropy(this->glue); + if (supported > 1.0f) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, + texture.anisotropic ? supported : 1.0f); + } + } cc_glglue_glBindTexture(this->glue, GL_TEXTURE_2D, 0); } @@ -467,11 +618,13 @@ SoGLRenderBackend::updateCacheDescription(CachedCommand & entry, const SoGeometryDesc & geometry = command.geometry; const SoTextureData & texture = command.material.texture; entry.positionsKey = geometry.positions; + entry.normalsKey = geometry.normals; entry.colorsKey = geometry.colors; entry.texcoordsKey = geometry.texcoords; entry.texturePixelsKey = hasTexture ? texture.pixels : nullptr; entry.indicesKey = geometry.indices; entry.vertexCount = geometry.vertexCount; + entry.normalCount = geometry.normalCount; entry.indexCount = geometry.indexCount; entry.vertexStride = vertexStride; entry.texcoordStride = geometry.texcoordStride; @@ -484,6 +637,15 @@ SoGLRenderBackend::updateCacheDescription(CachedCommand & entry, entry.geometryRevision = geometry.revision; entry.textureCacheKey = hasTexture ? texture.cacheKey : 0; entry.textureRevision = hasTexture ? texture.revision : 0; + entry.textureMinFilter = hasTexture ? texture.minFilter + : SO_TEXTURE_FILTER_NEAREST; + entry.textureMagFilter = hasTexture ? texture.magFilter + : SO_TEXTURE_FILTER_NEAREST; + entry.textureWrapS = hasTexture ? texture.wrapS + : SO_TEXTURE_WRAP_CLAMP_TO_EDGE; + entry.textureWrapT = hasTexture ? texture.wrapT + : SO_TEXTURE_WRAP_CLAMP_TO_EDGE; + entry.textureAnisotropic = hasTexture ? texture.anisotropic : false; } void @@ -502,6 +664,17 @@ SoGLRenderBackend::setupVisualVAO(CachedCommand & entry) GL_FLOAT, GL_FALSE, entry.vertexStride, nullptr); } + if (entry.normalBuffer) { + cc_glglue_glBindBuffer(this->glue, GL_ARRAY_BUFFER, entry.normalBuffer); + cc_glglue_glEnableVertexAttribArray(this->glue, NORMAL_ATTRIBUTE); + cc_glglue_glVertexAttribPointer(this->glue, NORMAL_ATTRIBUTE, 3, + GL_FLOAT, GL_FALSE, entry.vertexStride, + nullptr); + } + else { + cc_glglue_glDisableVertexAttribArray(this->glue, NORMAL_ATTRIBUTE); + this->glue->glVertexAttrib3f(NORMAL_ATTRIBUTE, 0.0f, 0.0f, 1.0f); + } if (entry.colorBuffer) { cc_glglue_glBindBuffer(this->glue, GL_ARRAY_BUFFER, entry.colorBuffer); cc_glglue_glEnableVertexAttribArray(this->glue, COLOR_ATTRIBUTE); @@ -547,7 +720,12 @@ SoGLRenderBackend::textureDescriptionMatches( entry.textureWidth == texture.width && entry.textureHeight == texture.height && entry.textureComponents == texture.numComponents && - entry.textureColorSpace == texture.colorSpace; + entry.textureColorSpace == texture.colorSpace && + entry.textureMinFilter == texture.minFilter && + entry.textureMagFilter == texture.magFilter && + entry.textureWrapS == texture.wrapS && + entry.textureWrapT == texture.wrapT && + entry.textureAnisotropic == texture.anisotropic; } void @@ -586,13 +764,15 @@ SoGLRenderBackend::updateGeometryCache(const SoDrawList & drawlist) const bool identityMatches = geometry.cacheKey != 0 ? entry.geometryCacheKey == geometry.cacheKey && entry.geometryRevision == geometry.revision - : entry.positionsKey == geometry.positions; + : entry.positionsKey == geometry.positions && + entry.normalsKey == geometry.normals; const bool geometryMatches = entry.positionBuffer != 0 && identityMatches && entry.colorsKey == geometry.colors && entry.texcoordsKey == geometry.texcoords && entry.indicesKey == geometry.indices && entry.vertexCount == geometry.vertexCount && + entry.normalCount == geometry.normalCount && entry.indexCount == geometry.indexCount && entry.vertexStride == vertexStride && entry.texcoordStride == geometry.texcoordStride && @@ -608,7 +788,79 @@ SoGLRenderBackend::updateGeometryCache(const SoDrawList & drawlist) } void -SoGLRenderBackend::drawCommand(const SoRenderCommand & command, +SoGLRenderBackend::uploadLighting(const SoDrawList & drawlist, + const SoRenderCommand & command) +{ + const SoLightingData * lighting = drawlist.getLighting(command.lightingHandle); + static const SoLightingData emptyLighting; + if (!lighting) { + lighting = &emptyLighting; + if (command.lightingHandle != 0) { + static std::once_flag invalidHandleWarning; + std::call_once(invalidHandleWarning, []() { + SoDebugError::postWarning( + "SoGLRenderBackend::uploadLighting", + "Ignoring an invalid retained lighting handle; no headlight is synthesized."); + }); + } + } + + const SbVec3f & ambient = lighting->ambient; + const VisualProgram::Uniforms & uniforms = this->visualProgram.uniforms; + this->glue->glUniform3f(uniforms.lighting.ambient, + ambient[0], ambient[1], ambient[2]); + + GLint types[MAX_SHADER_LIGHTS] = {}; + GLfloat colors[MAX_SHADER_LIGHTS * 3] = {}; + GLfloat directions[MAX_SHADER_LIGHTS * 3] = {}; + GLfloat positions[MAX_SHADER_LIGHTS * 3] = {}; + GLfloat attenuations[MAX_SHADER_LIGHTS * 3] = {}; + GLfloat spotParams[MAX_SHADER_LIGHTS * 2] = {}; + const int count = std::min(static_cast(lighting->lights.size()), + MAX_SHADER_LIGHTS); + if (static_cast(lighting->lights.size()) > MAX_SHADER_LIGHTS) { + static std::once_flag lightLimitWarning; + std::call_once(lightLimitWarning, []() { + SoDebugError::postWarning( + "SoGLRenderBackend::uploadLighting", + "The retained GL Visual program supports eight lights; additional " + "retained lights are not uploaded."); + }); + } + for (int i = 0; i < count; ++i) { + const SoLightData & light = lighting->lights[static_cast(i)]; + types[i] = static_cast(light.type); + colors[i * 3 + 0] = light.color[0]; + colors[i * 3 + 1] = light.color[1]; + colors[i * 3 + 2] = light.color[2]; + directions[i * 3 + 0] = light.direction[0]; + directions[i * 3 + 1] = light.direction[1]; + directions[i * 3 + 2] = light.direction[2]; + positions[i * 3 + 0] = light.position[0]; + positions[i * 3 + 1] = light.position[1]; + positions[i * 3 + 2] = light.position[2]; + attenuations[i * 3 + 0] = light.attenuation[0]; + attenuations[i * 3 + 1] = light.attenuation[1]; + attenuations[i * 3 + 2] = light.attenuation[2]; + spotParams[i * 2 + 0] = light.spotCutoffCos; + spotParams[i * 2 + 1] = light.spotExponent; + } + this->glue->glUniform1i(uniforms.lighting.lightCount, count); + this->glue->glUniform1iv(uniforms.lighting.lightType, MAX_SHADER_LIGHTS, types); + this->glue->glUniform3fv(uniforms.lighting.lightColor, MAX_SHADER_LIGHTS, colors); + this->glue->glUniform3fv(uniforms.lighting.lightDirection, MAX_SHADER_LIGHTS, + directions); + this->glue->glUniform3fv(uniforms.lighting.lightPosition, MAX_SHADER_LIGHTS, + positions); + this->glue->glUniform3fv(uniforms.lighting.lightAttenuation, MAX_SHADER_LIGHTS, + attenuations); + this->glue->glUniform2fv(uniforms.lighting.lightSpotParams, MAX_SHADER_LIGHTS, + spotParams); +} + +void +SoGLRenderBackend::drawCommand(const SoDrawList & drawlist, + const SoRenderCommand & command, const SbMat & viewMat, const SbMat & projMat, const SoRenderParams & params) @@ -620,44 +872,170 @@ SoGLRenderBackend::drawCommand(const SoRenderCommand & command, const CachedCommand & entry = this->gpuCache[found->second]; if (!entry.vertexArray) return; - this->bindVisualCommand(command, entry, viewMat, projMat, params); + this->bindVisualCommand(drawlist, command, entry, viewMat, projMat, params); this->drawGeometry(command, entry); } void -SoGLRenderBackend::bindVisualCommand(const SoRenderCommand & command, - const CachedCommand & entry, - const SbMat & viewMat, - const SbMat & projMat, - const SoRenderParams & params) +SoGLRenderBackend::bindTransforms(const SoRenderCommand & command, + const SbMat & viewMat, + const SbMat & projMat) { - applyViewport(params); const VisualProgram::Uniforms & uniforms = this->visualProgram.uniforms; - this->glue->glUniformMatrix4fv(uniforms.view, 1, GL_FALSE, + this->glue->glUniformMatrix4fv(uniforms.transforms.view, 1, GL_FALSE, &viewMat[0][0]); - this->glue->glUniformMatrix4fv(uniforms.projection, 1, GL_FALSE, + this->glue->glUniformMatrix4fv(uniforms.transforms.projection, 1, GL_FALSE, &projMat[0][0]); SbMat model; command.modelMatrix.getValue(model); - this->glue->glUniformMatrix4fv(uniforms.model, 1, GL_FALSE, + this->glue->glUniformMatrix4fv(uniforms.transforms.model, 1, GL_FALSE, &model[0][0]); +} + +void +SoGLRenderBackend::bindMaterial(const SoRenderCommand & command, + const CachedCommand & entry) +{ + const VisualProgram::Uniforms & uniforms = this->visualProgram.uniforms; const SbVec4f & color = command.material.diffuse; - this->glue->glUniform4f(uniforms.color, + this->glue->glUniform4f(uniforms.material.color, color[0], color[1], color[2], color[3]); - this->glue->glUniform1f(uniforms.useVertexColor, + this->glue->glUniform1f(uniforms.material.useVertexColor, entry.colorBuffer ? 1.0f : 0.0f); + this->glue->glUniform1f( + uniforms.material.vertexColorAlphaIncludesOpacity, + command.material.vertexColorAlphaIncludesOpacity ? 1.0f : 0.0f); + this->glue->glUniform1f( + uniforms.texture.alphaIncludesOpacity, + command.material.textureAlphaIncludesOpacity ? 1.0f : 0.0f); + const bool textureHasAlpha = command.material.texture.numComponents == 2 || + command.material.texture.numComponents == 4; + this->glue->glUniform1f(uniforms.texture.hasAlpha, + textureHasAlpha ? 1.0f : 0.0f); + + const SoShadingModel shadingModel = command.material.shadingModel; + this->glue->glUniform1i(uniforms.material.shadingModel, + static_cast(shadingModel)); + const SbVec4f & emissive = command.material.emissive; + const SbVec4f & ambient = command.material.ambient; + const SbVec4f & specular = command.material.specular; + this->glue->glUniform3f(uniforms.material.emissiveColor, + emissive[0], emissive[1], emissive[2]); + this->glue->glUniform3f(uniforms.material.ambient, + ambient[0], ambient[1], ambient[2]); + this->glue->glUniform3f(uniforms.material.specular, + specular[0], specular[1], specular[2]); + this->glue->glUniform1f(uniforms.material.shininess, + command.material.shininess); + this->glue->glUniform1f(uniforms.material.twoSidedLighting, + command.material.twoSidedLighting ? 1.0f : 0.0f); +} +void +SoGLRenderBackend::applyDepthState(const SoRenderCommand & command) +{ + + if (command.state.depth.enabled) { + glEnable(GL_DEPTH_TEST); + glDepthFunc(depthFunctionToGL(command.state.depth.func)); + } + else { + glDisable(GL_DEPTH_TEST); + } + glDepthMask(command.state.depth.writeEnabled && + command.pass != SO_RENDERPASS_TRANSPARENT + ? GL_TRUE : GL_FALSE); + glDepthRange(command.state.depth.range[0], command.state.depth.range[1]); + +} + +void +SoGLRenderBackend::applyBlendState(const SoRenderCommand & command) +{ + const bool blending = command.state.blend.enabled || + command.pass == SO_RENDERPASS_TRANSPARENT || + command.material.diffuse[3] < 0.999f; + if (blending) { + glEnable(GL_BLEND); + if (isDualSourceBlendFactor(command.state.blend.srcRGBFactor) || + isDualSourceBlendFactor(command.state.blend.dstRGBFactor) || + isDualSourceBlendFactor(command.state.blend.srcAlphaFactor) || + isDualSourceBlendFactor(command.state.blend.dstAlphaFactor)) { + static std::once_flag dualSourceWarning; + std::call_once(dualSourceWarning, []() { + SoDebugError::postWarning( + "SoGLRenderBackend::bindVisualCommand", + "Dual-source blend factors are not supported by the Visual " + "program; using primary-source factors for execution."); + }); + } + cc_glglue_glBlendFuncSeparate( + this->glue, blendFactorToGL(command.state.blend.srcRGBFactor), + blendFactorToGL(command.state.blend.dstRGBFactor), + blendFactorToGL(command.state.blend.srcAlphaFactor), + blendFactorToGL(command.state.blend.dstAlphaFactor)); + if (cc_glglue_has_blendequation(this->glue) && + command.state.blend.rgbEquation == command.state.blend.alphaEquation) { + cc_glglue_glBlendEquation( + this->glue, blendEquationToGL(command.state.blend.rgbEquation)); + } + } + else { + glDisable(GL_BLEND); + } +} + +void +SoGLRenderBackend::bindAlphaTest(const SoRenderCommand & command) +{ + const VisualProgram::Uniforms & uniforms = this->visualProgram.uniforms; + this->glue->glUniform1i( + uniforms.alphaTest.function, + command.state.alphaTest.policy == SO_ALPHA_TEST_POLICY_NONE + ? 0 : static_cast(command.state.alphaTest.function)); + this->glue->glUniform1f(uniforms.alphaTest.reference, + command.state.alphaTest.reference); + +} + +void +SoGLRenderBackend::bindTexture(const SoRenderCommand & command, + const CachedCommand & entry) +{ + const VisualProgram::Uniforms & uniforms = this->visualProgram.uniforms; const bool textured = entry.texture != 0 && entry.texcoordBuffer != 0; - this->glue->glUniform1f(uniforms.textureEnabled, + this->glue->glUniform1f(uniforms.texture.enabled, textured ? 1.0f : 0.0f); if (textured) { cc_glglue_glActiveTexture(this->glue, GL_TEXTURE0); cc_glglue_glBindTexture(this->glue, GL_TEXTURE_2D, entry.texture); - this->glue->glUniform1i(uniforms.texture, 0); - this->glue->glUniform4f(uniforms.textureModulation, - color[0], color[1], color[2], color[3]); + this->glue->glUniform1i(uniforms.texture.sampler, 0); } + this->glue->glUniform1i(uniforms.texture.model, + static_cast(command.material.texture.model)); + const SbVec4f & textureBlend = command.material.texture.blendColor; + this->glue->glUniform4f(uniforms.texture.blendColor, + textureBlend[0], textureBlend[1], + textureBlend[2], textureBlend[3]); +} + +void +SoGLRenderBackend::bindVisualCommand(const SoDrawList & drawlist, + const SoRenderCommand & command, + const CachedCommand & entry, + const SbMat & viewMat, + const SbMat & projMat, + const SoRenderParams & params) +{ + applyViewport(params); + this->bindTransforms(command, viewMat, projMat); + this->bindMaterial(command, entry); + this->uploadLighting(drawlist, command); + this->applyDepthState(command); + this->applyBlendState(command); + this->bindAlphaTest(command); + this->bindTexture(command, entry); } void @@ -681,6 +1059,7 @@ SoGLRenderBackend::drawGeometry(const SoRenderCommand & command, } } +void void SoGLRenderBackend::beginFrame(const SoRenderParams & params) { @@ -730,19 +1109,59 @@ SoGLRenderBackend::createVisualProgram() this->visualProgram.handle = program; VisualProgram::Uniforms & uniforms = this->visualProgram.uniforms; - uniforms.view = cc_glglue_glGetUniformLocation(this->glue, program, "u_view"); - uniforms.projection = cc_glglue_glGetUniformLocation( + uniforms.transforms.view = cc_glglue_glGetUniformLocation(this->glue, program, "u_view"); + uniforms.transforms.projection = cc_glglue_glGetUniformLocation( this->glue, program, "u_proj"); - uniforms.model = cc_glglue_glGetUniformLocation(this->glue, program, "u_model"); - uniforms.color = cc_glglue_glGetUniformLocation(this->glue, program, "u_color"); - uniforms.useVertexColor = cc_glglue_glGetUniformLocation( + uniforms.transforms.model = cc_glglue_glGetUniformLocation(this->glue, program, "u_model"); + uniforms.material.color = cc_glglue_glGetUniformLocation(this->glue, program, "u_color"); + uniforms.material.useVertexColor = cc_glglue_glGetUniformLocation( this->glue, program, "u_useVertexColor"); - uniforms.texture = cc_glglue_glGetUniformLocation( + uniforms.material.shadingModel = cc_glglue_glGetUniformLocation( + this->glue, program, "u_shadingModel"); + uniforms.material.emissiveColor = cc_glglue_glGetUniformLocation( + this->glue, program, "u_emissiveColor"); + uniforms.material.ambient = cc_glglue_glGetUniformLocation( + this->glue, program, "u_materialAmbient"); + uniforms.material.specular = cc_glglue_glGetUniformLocation( + this->glue, program, "u_materialSpecular"); + uniforms.material.shininess = cc_glglue_glGetUniformLocation( + this->glue, program, "u_materialShininess"); + uniforms.material.twoSidedLighting = cc_glglue_glGetUniformLocation( + this->glue, program, "u_twoSidedLighting"); + uniforms.material.vertexColorAlphaIncludesOpacity = cc_glglue_glGetUniformLocation( + this->glue, program, "u_vertexColorAlphaIncludesOpacity"); + uniforms.texture.alphaIncludesOpacity = cc_glglue_glGetUniformLocation( + this->glue, program, "u_textureAlphaIncludesOpacity"); + uniforms.texture.hasAlpha = cc_glglue_glGetUniformLocation( + this->glue, program, "u_textureHasAlpha"); + uniforms.lighting.ambient = cc_glglue_glGetUniformLocation( + this->glue, program, "u_ambientLight"); + uniforms.lighting.lightCount = cc_glglue_glGetUniformLocation( + this->glue, program, "u_lightCount"); + uniforms.lighting.lightType = cc_glglue_glGetUniformLocation( + this->glue, program, "u_lightType"); + uniforms.lighting.lightColor = cc_glglue_glGetUniformLocation( + this->glue, program, "u_lightColor"); + uniforms.lighting.lightDirection = cc_glglue_glGetUniformLocation( + this->glue, program, "u_lightDirection"); + uniforms.lighting.lightPosition = cc_glglue_glGetUniformLocation( + this->glue, program, "u_lightPosition"); + uniforms.lighting.lightAttenuation = cc_glglue_glGetUniformLocation( + this->glue, program, "u_lightAttenuation"); + uniforms.lighting.lightSpotParams = cc_glglue_glGetUniformLocation( + this->glue, program, "u_lightSpotParams"); + uniforms.texture.sampler = cc_glglue_glGetUniformLocation( this->glue, program, "u_texture"); - uniforms.textureEnabled = cc_glglue_glGetUniformLocation( + uniforms.texture.enabled = cc_glglue_glGetUniformLocation( this->glue, program, "u_textureEnabled"); - uniforms.textureModulation = cc_glglue_glGetUniformLocation( - this->glue, program, "u_texModColor"); + uniforms.texture.model = cc_glglue_glGetUniformLocation( + this->glue, program, "u_textureModel"); + uniforms.texture.blendColor = cc_glglue_glGetUniformLocation( + this->glue, program, "u_textureBlendColor"); + uniforms.alphaTest.function = cc_glglue_glGetUniformLocation( + this->glue, program, "u_alphaTestFunction"); + uniforms.alphaTest.reference = cc_glglue_glGetUniformLocation( + this->glue, program, "u_alphaTestReference"); return true; } @@ -771,8 +1190,8 @@ SoGLRenderBackend::render(const SoDrawList & drawlist, this->emitError("render plan references a missing DrawList command"); return FALSE; } - this->drawCommand(drawlist.getCommand(static_cast(commandIndex)), - view, projection, params); + this->drawCommand(drawlist, drawlist.getCommand( + static_cast(commandIndex)), view, projection, params); } cc_glglue_glUseProgram(this->glue, 0); return TRUE; diff --git a/src/rendering/SoGLRenderBackend.h b/src/rendering/SoGLRenderBackend.h index 81e671d6af..ebdeb2eb7b 100644 --- a/src/rendering/SoGLRenderBackend.h +++ b/src/rendering/SoGLRenderBackend.h @@ -61,6 +61,7 @@ class COIN_DLL_API SoGLRenderBackend : public SoRenderBackend { struct CachedCommand { GLuint positionBuffer = 0; + GLuint normalBuffer = 0; GLuint colorBuffer = 0; GLuint texcoordBuffer = 0; GLuint texture = 0; @@ -68,11 +69,13 @@ class COIN_DLL_API SoGLRenderBackend : public SoRenderBackend { GLuint vertexArray = 0; const float * positionsKey = nullptr; + const float * normalsKey = nullptr; const float * colorsKey = nullptr; const float * texcoordsKey = nullptr; const unsigned char * texturePixelsKey = nullptr; const uint32_t * indicesKey = nullptr; uint32_t vertexCount = 0; + uint32_t normalCount = 0; uint32_t indexCount = 0; uint32_t vertexStride = 0; uint32_t texcoordStride = 0; @@ -80,6 +83,11 @@ class COIN_DLL_API SoGLRenderBackend : public SoRenderBackend { int textureHeight = 0; int textureComponents = 0; SoTextureColorSpace textureColorSpace = SO_TEXTURE_COLORSPACE_LEGACY; + SoTextureFilter textureMinFilter = SO_TEXTURE_FILTER_NEAREST; + SoTextureFilter textureMagFilter = SO_TEXTURE_FILTER_NEAREST; + SoTextureWrap textureWrapS = SO_TEXTURE_WRAP_CLAMP_TO_EDGE; + SoTextureWrap textureWrapT = SO_TEXTURE_WRAP_CLAMP_TO_EDGE; + bool textureAnisotropic = false; uint64_t geometryCacheKey = 0; uint64_t geometryRevision = 0; uint64_t textureCacheKey = 0; @@ -92,14 +100,44 @@ class COIN_DLL_API SoGLRenderBackend : public SoRenderBackend { GLuint handle = 0; struct Uniforms { - GLint view = -1; - GLint projection = -1; - GLint model = -1; - GLint color = -1; - GLint useVertexColor = -1; - GLint texture = -1; - GLint textureEnabled = -1; - GLint textureModulation = -1; + struct Transforms { + GLint view = -1; + GLint projection = -1; + GLint model = -1; + } transforms; + struct Material { + GLint color = -1; + GLint useVertexColor = -1; + GLint shadingModel = -1; + GLint emissiveColor = -1; + GLint ambient = -1; + GLint specular = -1; + GLint shininess = -1; + GLint twoSidedLighting = -1; + GLint vertexColorAlphaIncludesOpacity = -1; + } material; + struct Lighting { + GLint ambient = -1; + GLint lightCount = -1; + GLint lightType = -1; + GLint lightColor = -1; + GLint lightDirection = -1; + GLint lightPosition = -1; + GLint lightAttenuation = -1; + GLint lightSpotParams = -1; + } lighting; + struct Texture { + GLint sampler = -1; + GLint enabled = -1; + GLint alphaIncludesOpacity = -1; + GLint hasAlpha = -1; + GLint model = -1; + GLint blendColor = -1; + } texture; + struct AlphaTest { + GLint function = -1; + GLint reference = -1; + } alphaTest; } uniforms; } visualProgram; @@ -108,10 +146,18 @@ class COIN_DLL_API SoGLRenderBackend : public SoRenderBackend { void beginFrame(const SoRenderParams & params); void invalidateCache(); void updateGeometryCache(const SoDrawList & drawlist); - void drawCommand(const SoRenderCommand & command, + void renderPass(const SoDrawList & drawlist, + const SbMat & viewMat, + const SbMat & projMat, + const SoRenderParams & params, + SoRenderPassType pass); + void drawCommand(const SoDrawList & drawlist, + const SoRenderCommand & command, const SbMat & viewMat, const SbMat & projMat, const SoRenderParams & params); + void uploadLighting(const SoDrawList & drawlist, + const SoRenderCommand & command); CachedCommand & getOrCreateCache(const SoRenderCommand * command); void uploadGeometry(CachedCommand & entry, @@ -129,11 +175,22 @@ class COIN_DLL_API SoGLRenderBackend : public SoRenderBackend { uint32_t vertexStride); void setupVisualVAO(CachedCommand & entry); void destroyCacheEntry(CachedCommand & entry); - void bindVisualCommand(const SoRenderCommand & command, + void bindVisualCommand(const SoDrawList & drawlist, + const SoRenderCommand & command, const CachedCommand & entry, const SbMat & viewMat, const SbMat & projMat, const SoRenderParams & params); + void bindTransforms(const SoRenderCommand & command, + const SbMat & viewMat, + const SbMat & projMat); + void bindMaterial(const SoRenderCommand & command, + const CachedCommand & entry); + void applyDepthState(const SoRenderCommand & command); + void applyBlendState(const SoRenderCommand & command); + void bindAlphaTest(const SoRenderCommand & command); + void bindTexture(const SoRenderCommand & command, + const CachedCommand & entry); void drawGeometry(const SoRenderCommand & command, const CachedCommand & entry); bool textureDescriptionMatches(const CachedCommand & entry, diff --git a/src/rendering/SoRenderIR.cpp b/src/rendering/SoRenderIR.cpp index ce1822fdf0..3c4058e51a 100644 --- a/src/rendering/SoRenderIR.cpp +++ b/src/rendering/SoRenderIR.cpp @@ -776,8 +776,8 @@ finalizeCommand(SoRenderCommand & command) } } } - command.pass = transparent ? SO_RENDERPASS_TRANSPARENT - : SO_RENDERPASS_OPAQUE; + command.opacityClass = transparent + ? SO_OPACITY_TRANSPARENT : SO_OPACITY_OPAQUE; if (transparent && !command.state.blend.enabled) { command.state.blend.enabled = TRUE; command.state.blend.srcRGBFactor = SO_BLEND_FACTOR_SRC_ALPHA; @@ -785,8 +785,6 @@ finalizeCommand(SoRenderCommand & command) command.state.blend.srcAlphaFactor = SO_BLEND_FACTOR_SRC_ALPHA; command.state.blend.dstAlphaFactor = SO_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; } - command.sortKey = SoIRComputeSortKey( - command, static_cast(command.pass), 0); } } // namespace SoRenderIR diff --git a/src/rendering/SoRenderPlan.cpp b/src/rendering/SoRenderPlan.cpp index ee7765961d..062e6d458a 100644 --- a/src/rendering/SoRenderPlan.cpp +++ b/src/rendering/SoRenderPlan.cpp @@ -1,18 +1,61 @@ #include "rendering/SoRenderPlan.h" +#include + void SoRenderPlanner::build(const SoDrawList & drawlist, - const SbMatrix &, + const SbMatrix & frameViewMatrix, SoRenderPlan & plan) const { - plan.draws.clear(); - plan.draws.reserve(static_cast(drawlist.getNumCommands())); + struct PlannedEntry { + SoPlannedDraw draw; + SoOpacityClass opacity = SO_OPACITY_OPAQUE; + float depth = 0.0f; + }; + + std::vector entries; + entries.reserve(static_cast(drawlist.getNumCommands())); for (uint32_t commandIndex = 0; commandIndex < static_cast(drawlist.getNumCommands()); ++commandIndex) { - SoPlannedDraw draw; - draw.commandIndex = commandIndex; - plan.draws.push_back(draw); + const SoRenderCommand & command = drawlist.getCommand( + static_cast(commandIndex)); + SbMat view; + SbMat model; + const SbMatrix & effectiveView = command.state.useCommandMatrices + ? command.viewMatrix : frameViewMatrix; + effectiveView.getValue(view); + command.modelMatrix.getValue(model); + const float worldX = model[3][0]; + const float worldY = model[3][1]; + const float worldZ = model[3][2]; + const float eyeZ = view[0][2] * worldX + + view[1][2] * worldY + + view[2][2] * worldZ + + view[3][2]; + + PlannedEntry entry; + entry.draw.commandIndex = commandIndex; + entry.opacity = command.opacityClass; + entry.depth = -eyeZ; + entries.push_back(entry); + } + + std::stable_sort(entries.begin(), entries.end(), + [](const PlannedEntry & lhs, const PlannedEntry & rhs) { + if (lhs.opacity != rhs.opacity) { + return lhs.opacity == SO_OPACITY_OPAQUE; + } + if (lhs.opacity == SO_OPACITY_OPAQUE) { + return false; + } + return lhs.depth > rhs.depth; + }); + + plan.draws.clear(); + plan.draws.reserve(entries.size()); + for (const PlannedEntry & entry : entries) { + plan.draws.push_back(entry.draw); } } diff --git a/src/rendering/SoRenderPlan.h b/src/rendering/SoRenderPlan.h index a54d03259e..4b4e12b956 100644 --- a/src/rendering/SoRenderPlan.h +++ b/src/rendering/SoRenderPlan.h @@ -21,6 +21,8 @@ struct SoPlannedDraw { The plan owns no command data. It contains only stable indices into the source SoDrawList and is therefore cheap to rebuild for each invocation. + Opaque commands retain insertion order; transparent commands are resolved + back-to-front after opaque commands. */ class SoRenderPlan { public: @@ -41,6 +43,7 @@ class SoRenderPlan { */ class COIN_DLL_API SoRenderPlanner { public: + //! Resolve semantic command state into backend execution order. void build(const SoDrawList & drawlist, const SbMatrix & frameViewMatrix, SoRenderPlan & plan) const; }; diff --git a/testsuite/RenderPlanTest.cpp b/testsuite/RenderPlanTest.cpp index 3078729950..bf0b264b9c 100644 --- a/testsuite/RenderPlanTest.cpp +++ b/testsuite/RenderPlanTest.cpp @@ -70,5 +70,30 @@ main() plan.getDraw(0).commandIndex == 0, "reusing a cleared plan did not rebuild its operations") && result; + + SoDrawList transparencyDrawList; + SoRenderCommand opaque; + SoRenderCommand transparentNear; + SoRenderCommand transparentFar; + opaque.viewMatrix.makeIdentity(); + opaque.modelMatrix.makeIdentity(); + transparentNear.viewMatrix.makeIdentity(); + transparentNear.modelMatrix.makeIdentity(); + transparentFar.viewMatrix.makeIdentity(); + transparentFar.modelMatrix.makeIdentity(); + transparentNear.opacityClass = SO_OPACITY_TRANSPARENT; + transparentFar.opacityClass = SO_OPACITY_TRANSPARENT; + transparentFar.modelMatrix.setTranslate(SbVec3f(0.0f, 0.0f, -2.0f)); + transparencyDrawList.addCommand(opaque); + transparencyDrawList.addCommand(transparentNear); + transparencyDrawList.addCommand(transparentFar); + planner.build(transparencyDrawList, frameViewMatrix, plan); + result = check(plan.getNumDraws() == 3 && + plan.getDraw(0).commandIndex == 0 && + plan.getDraw(1).commandIndex == 2 && + plan.getDraw(2).commandIndex == 1, + "planner did not schedule transparent commands back-to-front") && + result; + return result ? 0 : 1; } From 531454f536c24656bd0e68adc6d7d737af9d9a31 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 12 Aug 2026 15:23:40 +0100 Subject: [PATCH 05/10] tests: cover retained material and lighting semantics --- testsuite/CMakeLists.txt | 8 + testsuite/retained-material-lighting-test.cpp | 465 ++++++++++++++++++ 2 files changed, 473 insertions(+) create mode 100644 testsuite/retained-material-lighting-test.cpp diff --git a/testsuite/CMakeLists.txt b/testsuite/CMakeLists.txt index be63634b76..2ae73b585f 100644 --- a/testsuite/CMakeLists.txt +++ b/testsuite/CMakeLists.txt @@ -311,7 +311,15 @@ target_include_directories(RetainedMixedTopologyTest PRIVATE ${PROJECT_BINARY_DIR}/include ${COIN_TARGET_INCLUDE_DIRECTORIES} ) +add_executable(RetainedMaterialLightingTest retained-material-lighting-test.cpp) +target_link_libraries(RetainedMaterialLightingTest Coin ${COIN_TARGET_LINK_LIBRARIES}) +target_include_directories(RetainedMaterialLightingTest PRIVATE + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include + ${COIN_TARGET_INCLUDE_DIRECTORIES} +) add_test(NAME RetainedMixedTopologyTest COMMAND RetainedMixedTopologyTest) +add_test(NAME RetainedMaterialLightingTest COMMAND RetainedMaterialLightingTest) if(HAVE_EGL) coin_add_egl_test(NAME EGLBindingTest SOURCES EGLBindingTest.cpp LABELS requires-egl) diff --git a/testsuite/retained-material-lighting-test.cpp b/testsuite/retained-material-lighting-test.cpp new file mode 100644 index 0000000000..fcbf4d5092 --- /dev/null +++ b/testsuite/retained-material-lighting-test.cpp @@ -0,0 +1,465 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace { + +bool nearlyEqual(float lhs, float rhs) +{ + return std::fabs(lhs - rhs) < 0.0001f; +} + +bool checkTextureClassification(int components, unsigned char alpha, + SoTexture2::Model model, + bool expectedTransparent) +{ + const unsigned char pixels[] = { 255, 128, 64, alpha }; + SoSeparator * root = new SoSeparator; + root->ref(); + SoTexture2 * texture = new SoTexture2; + texture->model = model; + texture->image.setValue(SbVec2s(1, 1), components, pixels); + root->addChild(texture); + root->addChild(new SoCube); + + SoIRRenderAction action(SbViewportRegion(32, 32)); + action.apply(root); + bool result = action.getDrawList().getNumCommands() == 1; + if (result) { + const SoRenderCommand & command = action.getDrawList().getCommand(0); + const bool payloadHasTransparency = (components == 2 || components == 4) && + alpha != 255; + result = (command.opacityClass == (expectedTransparent + ? SO_OPACITY_TRANSPARENT + : SO_OPACITY_OPAQUE)) && + (command.state.blend.enabled == (expectedTransparent ? TRUE : FALSE)) && + (command.material.texture.hasTransparency == payloadHasTransparency); + } + root->unref(); + return result; +} + +} + +int +runTest() +{ + SoDB::init(); + + SoSeparator * root = new SoSeparator; + root->ref(); + + SoDepthBuffer * depth = new SoDepthBuffer; + depth->test = TRUE; + depth->write = FALSE; + depth->function = SoDepthBuffer::GREATER; + depth->range = SbVec2f(0.2f, 0.8f); + root->addChild(depth); + + SoAlphaTest * alphaTest = new SoAlphaTest; + alphaTest->function = SoAlphaTest::GREATER; + alphaTest->value = 0.25f; + root->addChild(alphaTest); + + const unsigned char texturePixel[] = { 255, 128, 64, 255 }; + SoTexture2 * texture = new SoTexture2; + texture->image.setValue(SbVec2s(1, 1), 4, texturePixel); + texture->wrapS = SoTexture2::REPEAT; + texture->wrapT = SoTexture2::CLAMP; + texture->model = SoTexture2::BLEND; + texture->blendColor.setValue(0.1f, 0.2f, 0.3f); + root->addChild(texture); + + SoDirectionalLight * light = new SoDirectionalLight; + light->color.setValue(0.25f, 0.5f, 0.75f); + root->addChild(light); + + SoPointLight * pointLight = new SoPointLight; + pointLight->location.setValue(1.0f, -2.0f, 3.0f); + pointLight->color.setValue(0.8f, 0.7f, 0.6f); + root->addChild(pointLight); + + SoSpotLight * spotLight = new SoSpotLight; + spotLight->location.setValue(-1.0f, -2.0f, 3.0f); + spotLight->direction.setValue(0.0f, 0.0f, -1.0f); + spotLight->cutOffAngle = 0.5f; + spotLight->dropOffRate = 0.25f; + root->addChild(spotLight); + + for (int i = 0; i < 8; ++i) { + root->addChild(new SoDirectionalLight); + } + + SoMaterial * material = new SoMaterial; + material->ambientColor.setValue(0.1f, 0.2f, 0.3f); + material->diffuseColor.setValue(0.4f, 0.5f, 0.6f); + material->specularColor.setValue(0.7f, 0.8f, 0.9f); + material->emissiveColor.setValue(0.15f, 0.1f, 0.05f); + material->shininess = 0.5f; + material->transparency = 0.25f; + root->addChild(material); + root->addChild(new SoCube); + + SoIRRenderAction action(SbViewportRegion(64, 64)); + action.apply(root); + + int result = 0; + if (action.getDrawList().getNumCommands() != 1) { + std::cerr << "FAIL: material scene did not emit one retained command" << std::endl; + result = 1; + } + else { + const SoRenderCommand & command = action.getDrawList().getCommand(0); + if (!command.state.depth.enabled || command.state.depth.writeEnabled || + command.state.depth.func != SO_DEPTH_GREATER || + !nearlyEqual(command.state.depth.range[0], 0.2f) || + !nearlyEqual(command.state.depth.range[1], 0.8f)) { + std::cerr << "FAIL: SoDepthBuffer state was not retained" << std::endl; + result = 1; + } + if (command.state.alphaTest.function != SO_ALPHA_TEST_GREATER || + !nearlyEqual(command.state.alphaTest.reference, 0.25f)) { + std::cerr << "FAIL: SoAlphaTest state was not retained" << std::endl; + result = 1; + } + if (command.material.texture.wrapS != SO_TEXTURE_WRAP_REPEAT || + command.material.texture.wrapT != SO_TEXTURE_WRAP_CLAMP_TO_EDGE || + command.material.texture.model != SO_TEXTURE_MODEL_BLEND || + !nearlyEqual(command.material.texture.blendColor[1], 0.2f) || + command.material.texture.minFilter != SO_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR || + command.material.texture.magFilter != SO_TEXTURE_FILTER_LINEAR || + command.material.texture.pixels == nullptr) { + std::cerr << "FAIL: texture model and sampler state were not retained" << std::endl; + result = 1; + } + if (!nearlyEqual(command.material.ambient[0], 0.1f) || + !nearlyEqual(command.material.diffuse[1], 0.5f) || + !nearlyEqual(command.material.specular[2], 0.9f) || + !nearlyEqual(command.material.diffuse[3], 0.75f) || + !nearlyEqual(command.material.emissive[0], 0.15f)) { + std::cerr << "FAIL: complete material state was not retained" << std::endl; + result = 1; + } + const SoLightingData * lighting = action.getDrawList().getLighting(command.lightingHandle); + if (!lighting || lighting->lights.size() != 11 || + !nearlyEqual(lighting->lights[0].color[1], 0.5f)) { + std::cerr << "FAIL: SoLight state was not retained" << std::endl; + result = 1; + } + else { + const SoLightData & point = lighting->lights[1]; + const SoLightData & spot = lighting->lights[2]; + if (point.type != SO_LIGHT_POINT || + !nearlyEqual(point.position[0], 1.0f) || + !nearlyEqual(point.position[1], -2.0f) || + !nearlyEqual(point.position[2], 3.0f) || + spot.type != SO_LIGHT_SPOT || + !nearlyEqual(spot.position[0], -1.0f) || + !nearlyEqual(spot.position[1], -2.0f) || + !nearlyEqual(spot.position[2], 3.0f) || + !nearlyEqual(spot.direction[2], -1.0f) || + !nearlyEqual(spot.spotCutoffCos, std::cos(0.5f)) || + !nearlyEqual(spot.spotExponent, 32.0f)) { + std::cerr << "FAIL: point and spot light state was not retained" + << std::endl; + result = 1; + } + } + } + + root->unref(); + + // SoVertexProperty packed alpha is an independent vertex contribution in + // retained rendering. Verify both ways that Coin can introduce the + // property: through the SoVertexShape field and as a traversal node. + const SbVec3f alphaPoints[] = { + SbVec3f(-1.0f, -1.0f, 0.0f), SbVec3f(1.0f, -1.0f, 0.0f), + SbVec3f(1.0f, 1.0f, 0.0f), SbVec3f(-1.0f, 1.0f, 0.0f) + }; + const uint32_t alphaColors[] = { + 0xFF000080, 0xFF000080, 0xFF000080, 0xFF000080 + }; + + for (int propertyMode = 0; propertyMode < 2; ++propertyMode) { + SoSeparator * alphaRoot = new SoSeparator; + alphaRoot->ref(); + + SoMaterial * alphaMaterial = new SoMaterial; + alphaMaterial->transparency = 0.25f; + alphaRoot->addChild(alphaMaterial); + + SoVertexProperty * alphaVertexProperty = new SoVertexProperty; + alphaVertexProperty->vertex.setValues(0, 4, alphaPoints); + alphaVertexProperty->orderedRGBA.setValues(0, 4, alphaColors); + alphaVertexProperty->materialBinding = SoVertexProperty::PER_VERTEX; + + SoFaceSet * alphaFaces = new SoFaceSet; + if (propertyMode == 0) { + alphaFaces->vertexProperty = alphaVertexProperty; + } + else { + alphaRoot->addChild(alphaVertexProperty); + } + alphaFaces->numVertices = 4; + alphaRoot->addChild(alphaFaces); + + SoIRRenderAction alphaAction(SbViewportRegion(64, 64)); + alphaAction.apply(alphaRoot); + if (alphaAction.getDrawList().getNumCommands() != 1) { + std::cerr << "FAIL: packed vertex alpha did not emit one retained command" + << std::endl; + result = 1; + } + else { + const SoRenderCommand & command = alphaAction.getDrawList().getCommand(0); + if (!command.geometry.colors || + command.material.vertexColorAlphaIncludesOpacity || + !nearlyEqual(command.material.opacity, 0.75f) || + !nearlyEqual(command.material.diffuse[3], 0.75f) || + !nearlyEqual(command.geometry.colors[3], 128.0f / 255.0f)) { + std::cerr << "FAIL: packed vertex alpha did not compose with material opacity" + << std::endl; + result = 1; + } + } + + alphaRoot->unref(); + } + + // The provenance must retain the complete inherited opacity array, not + // only material zero. This also verifies that packed colors do not make a + // later per-face material use the vertex alpha as material opacity. + SoSeparator * indexedAlphaRoot = new SoSeparator; + indexedAlphaRoot->ref(); + SoMaterial * indexedAlphaMaterial = new SoMaterial; + const float indexedTransparency[] = { 0.25f, 0.5f }; + indexedAlphaMaterial->transparency.setValues(0, 2, indexedTransparency); + indexedAlphaRoot->addChild(indexedAlphaMaterial); + + SoVertexProperty * indexedAlphaVertexProperty = new SoVertexProperty; + const SbVec3f indexedAlphaPoints[] = { + SbVec3f(-1.0f, -1.0f, 0.0f), SbVec3f(0.0f, -1.0f, 0.0f), + SbVec3f(-0.5f, 0.0f, 0.0f), SbVec3f(0.0f, 0.0f, 0.0f), + SbVec3f(1.0f, 0.0f, 0.0f), SbVec3f(0.5f, 1.0f, 0.0f) + }; + const uint32_t indexedAlphaColors[] = { + 0xFF000080, 0xFF000080, 0xFF000080, + 0xFF000080, 0xFF000080, 0xFF000080 + }; + indexedAlphaVertexProperty->vertex.setValues(0, 6, indexedAlphaPoints); + indexedAlphaVertexProperty->orderedRGBA.setValues( + 0, 6, indexedAlphaColors); + indexedAlphaVertexProperty->materialBinding = SoVertexProperty::PER_FACE; + indexedAlphaRoot->addChild(indexedAlphaVertexProperty); + + SoFaceSet * indexedAlphaFaces = new SoFaceSet; + const int32_t indexedAlphaCounts[] = { 3, 3 }; + indexedAlphaFaces->numVertices.setValues(0, 2, indexedAlphaCounts); + indexedAlphaRoot->addChild(indexedAlphaFaces); + + SoIRRenderAction indexedAlphaAction(SbViewportRegion(64, 64)); + indexedAlphaAction.apply(indexedAlphaRoot); + if (indexedAlphaAction.getDrawList().getNumCommands() != 2) { + std::cerr << "FAIL: packed vertex alpha did not preserve material batches" + << std::endl; + result = 1; + } + else { + const SoRenderCommand & first = + indexedAlphaAction.getDrawList().getCommand(0); + const SoRenderCommand & second = + indexedAlphaAction.getDrawList().getCommand(1); + if (!nearlyEqual(first.material.opacity, 0.75f) || + !nearlyEqual(second.material.opacity, 0.5f) || + first.material.vertexColorAlphaIncludesOpacity || + second.material.vertexColorAlphaIncludesOpacity) { + std::cerr << "FAIL: packed vertex alpha lost per-material opacity" + << std::endl; + result = 1; + } + } + indexedAlphaRoot->unref(); + + // A later ordinary material update must invalidate the packed-color + // provenance. Otherwise a retained command could reuse opacity from the + // material that preceded SoVertexProperty. + SoSeparator * invalidatedAlphaRoot = new SoSeparator; + invalidatedAlphaRoot->ref(); + SoMaterial * inheritedAlphaMaterial = new SoMaterial; + inheritedAlphaMaterial->transparency = 0.5f; + invalidatedAlphaRoot->addChild(inheritedAlphaMaterial); + + SoVertexProperty * invalidatedAlphaVertexProperty = new SoVertexProperty; + invalidatedAlphaVertexProperty->vertex.setValues(0, 4, alphaPoints); + invalidatedAlphaVertexProperty->orderedRGBA.setValues(0, 4, alphaColors); + invalidatedAlphaVertexProperty->materialBinding = SoVertexProperty::PER_VERTEX; + invalidatedAlphaRoot->addChild(invalidatedAlphaVertexProperty); + + SoMaterial * replacementMaterial = new SoMaterial; + replacementMaterial->transparency = 0.0f; + invalidatedAlphaRoot->addChild(replacementMaterial); + SoFaceSet * invalidatedAlphaFaces = new SoFaceSet; + invalidatedAlphaFaces->numVertices = 4; + invalidatedAlphaRoot->addChild(invalidatedAlphaFaces); + + SoIRRenderAction invalidatedAlphaAction(SbViewportRegion(64, 64)); + invalidatedAlphaAction.apply(invalidatedAlphaRoot); + if (invalidatedAlphaAction.getDrawList().getNumCommands() != 1 || + !nearlyEqual(invalidatedAlphaAction.getDrawList().getCommand(0).material.opacity, + 1.0f)) { + std::cerr << "FAIL: ordinary material state did not clear packed-color provenance" + << std::endl; + result = 1; + } + invalidatedAlphaRoot->unref(); + + struct BindingCase { + SoMaterialBinding::Binding binding; + bool indexed; + const char * name; + }; + const BindingCase cases[] = { + { SoMaterialBinding::PER_PART, false, "PER_PART" }, + { SoMaterialBinding::PER_PART_INDEXED, true, "PER_PART_INDEXED" }, + { SoMaterialBinding::PER_FACE, false, "PER_FACE" }, + { SoMaterialBinding::PER_FACE_INDEXED, true, "PER_FACE_INDEXED" }, + { SoMaterialBinding::PER_VERTEX, false, "PER_VERTEX" }, + { SoMaterialBinding::PER_VERTEX_INDEXED, true, "PER_VERTEX_INDEXED" } + }; + + const SbVec3f points[] = { + SbVec3f(-1.0f, -1.0f, 0.0f), SbVec3f(0.0f, -1.0f, 0.0f), + SbVec3f(-0.5f, 0.0f, 0.0f), SbVec3f(0.0f, 0.0f, 0.0f), + SbVec3f(1.0f, 0.0f, 0.0f), SbVec3f(0.5f, 1.0f, 0.0f) + }; + const int32_t coordIndices[] = { 0, 1, 2, -1, 3, 4, 5, -1 }; + const int32_t faceMaterialIndices[] = { 0, 1 }; + const int32_t vertexMaterialIndices[] = { 0, 1, 2, 3, 4, 5 }; + const SbColor materialColors[] = { + SbColor(1.0f, 0.0f, 0.0f), SbColor(0.0f, 1.0f, 0.0f), + SbColor(0.0f, 0.0f, 1.0f), SbColor(1.0f, 1.0f, 0.0f), + SbColor(1.0f, 0.0f, 1.0f), SbColor(0.0f, 1.0f, 1.0f) + }; + const float materialTransparency[] = { 0.0f, 0.5f, 0.0f, + 0.5f, 0.0f, 0.5f }; + + for (const BindingCase & bindingCase : cases) { + SoSeparator * batchRoot = new SoSeparator; + batchRoot->ref(); + + SoCoordinate3 * coordinates = new SoCoordinate3; + coordinates->point.setValues(0, 6, points); + batchRoot->addChild(coordinates); + + SoMaterial * batchMaterial = new SoMaterial; + batchMaterial->diffuseColor.setValues(0, 6, materialColors); + batchMaterial->transparency.setValues(0, 6, materialTransparency); + batchRoot->addChild(batchMaterial); + + SoMaterialBinding * materialBinding = new SoMaterialBinding; + materialBinding->value = bindingCase.binding; + batchRoot->addChild(materialBinding); + + SoIndexedFaceSet * faces = new SoIndexedFaceSet; + faces->coordIndex.setValues(0, 8, coordIndices); + if (bindingCase.binding == SoMaterialBinding::PER_FACE_INDEXED || + bindingCase.binding == SoMaterialBinding::PER_PART_INDEXED) { + faces->materialIndex.setValues(0, 2, faceMaterialIndices); + } + else if (bindingCase.binding == SoMaterialBinding::PER_VERTEX_INDEXED) { + faces->materialIndex.setValues(0, 6, vertexMaterialIndices); + } + const std::vector originalCoordIndices( + faces->coordIndex.getValues(0), faces->coordIndex.getValues(0) + 8); + const int originalMaterialIndexCount = faces->materialIndex.getNum(); + const std::vector originalMaterialIndices = originalMaterialIndexCount + ? std::vector(faces->materialIndex.getValues(0), + faces->materialIndex.getValues(0) + originalMaterialIndexCount) + : std::vector(); + batchRoot->addChild(faces); + + SoIRRenderAction batchAction(SbViewportRegion(64, 64)); + batchAction.apply(batchRoot); + + bool hasGeneratedColors = false; + bool hasTransparentBatch = false; + const int expectedCommands = + (bindingCase.binding == SoMaterialBinding::PER_PART || + bindingCase.binding == SoMaterialBinding::PER_PART_INDEXED || + (bindingCase.binding == SoMaterialBinding::PER_FACE || + bindingCase.binding == SoMaterialBinding::PER_FACE_INDEXED)) ? 2 : 1; + if (batchAction.getDrawList().getNumCommands() != expectedCommands) { + std::cerr << "FAIL: " << bindingCase.name + << " did not produce two material batches" << std::endl; + result = 1; + } + for (int i = 0; i < batchAction.getDrawList().getNumCommands(); ++i) { + const SoRenderCommand & command = batchAction.getDrawList().getCommand(i); + if (command.geometry.colors) { + hasGeneratedColors = true; + if (!command.material.vertexColorAlphaIncludesOpacity) { + std::cerr << "FAIL: " << bindingCase.name + << " lost generated vertex alpha policy" << std::endl; + result = 1; + } + } + if (command.opacityClass == SO_OPACITY_TRANSPARENT) { + hasTransparentBatch = true; + } + } + if ((bindingCase.binding == SoMaterialBinding::PER_VERTEX || + bindingCase.binding == SoMaterialBinding::PER_VERTEX_INDEXED) && + !hasGeneratedColors) { + std::cerr << "FAIL: " << bindingCase.name + << " did not retain per-vertex colors" << std::endl; + result = 1; + } + if (!hasTransparentBatch) { + std::cerr << "FAIL: " << bindingCase.name + << " did not classify transparent material data" << std::endl; + result = 1; + } + + if (std::vector(faces->coordIndex.getValues(0), + faces->coordIndex.getValues(0) + 8) != originalCoordIndices || + faces->materialIndex.getNum() != originalMaterialIndexCount || + (originalMaterialIndexCount && + std::vector(faces->materialIndex.getValues(0), + faces->materialIndex.getValues(0) + originalMaterialIndexCount) + != originalMaterialIndices)) { + std::cerr << "FAIL: " << bindingCase.name + << " modified the source scene graph" << std::endl; + result = 1; + } + + batchRoot->unref(); + } + + return result; +} + +int +main() +{ + const int result = runTest(); + SoDB::finish(); + return result; +} From 56c0a23eec6a589f851b7f18746ac939e7fa3d31 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Thu, 13 Aug 2026 18:47:28 +0100 Subject: [PATCH 06/10] tests: cover retained material and lighting pixels --- CMakeLists.txt | 22 + testsuite/CMakeLists.txt | 2 + .../render/baselines/gl/material_emissive.png | Bin 0 -> 22163 bytes .../baselines/gl/point_spot_lights_basic.png | Bin 0 -> 59502 bytes .../baselines/gl/texture_luminance_alpha.png | Bin 0 -> 62324 bytes testsuite/render/baselines/gl/texture_rgb.png | Bin 0 -> 102361 bytes .../baselines/gl/transparent_overlap.png | Bin 0 -> 10821 bytes testsuite/render/baselines/gl/two_lights.png | Bin 0 -> 72678 bytes testsuite/render/scenes/material_emissive.iv | 36 ++ .../render/scenes/point_spot_lights_basic.iv | 31 + .../render/scenes/texture_luminance_alpha.iv | 19 + testsuite/render/scenes/texture_rgb.iv | 19 + .../render/scenes/transparent_overlap.iv | 32 + testsuite/render/scenes/two_lights.iv | 27 + testsuite/render/specs/material_emissive.yml | 7 + .../render/specs/point_spot_lights_basic.yml | 7 + .../render/specs/texture_luminance_alpha.yml | 7 + testsuite/render/specs/texture_rgb.yml | 7 + .../render/specs/transparent_overlap.yml | 7 + testsuite/render/specs/two_lights.yml | 7 + .../retained-material-lighting-gl-test.cpp | 576 ++++++++++++++++++ 21 files changed, 806 insertions(+) create mode 100644 testsuite/render/baselines/gl/material_emissive.png create mode 100644 testsuite/render/baselines/gl/point_spot_lights_basic.png create mode 100644 testsuite/render/baselines/gl/texture_luminance_alpha.png create mode 100644 testsuite/render/baselines/gl/texture_rgb.png create mode 100644 testsuite/render/baselines/gl/transparent_overlap.png create mode 100644 testsuite/render/baselines/gl/two_lights.png create mode 100644 testsuite/render/scenes/material_emissive.iv create mode 100644 testsuite/render/scenes/point_spot_lights_basic.iv create mode 100644 testsuite/render/scenes/texture_luminance_alpha.iv create mode 100644 testsuite/render/scenes/texture_rgb.iv create mode 100644 testsuite/render/scenes/transparent_overlap.iv create mode 100644 testsuite/render/scenes/two_lights.iv create mode 100644 testsuite/render/specs/material_emissive.yml create mode 100644 testsuite/render/specs/point_spot_lights_basic.yml create mode 100644 testsuite/render/specs/texture_luminance_alpha.yml create mode 100644 testsuite/render/specs/texture_rgb.yml create mode 100644 testsuite/render/specs/transparent_overlap.yml create mode 100644 testsuite/render/specs/two_lights.yml create mode 100644 testsuite/retained-material-lighting-gl-test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 009e94ce3f..465c616660 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -970,6 +970,8 @@ if(COIN_BUILD_VISUAL_TESTS) add_subdirectory(tools) set(COIN_DRAWLIST_BASE_VISUAL_SPECS "unlit_cube_basic,unlit_transformed_cubes,unlit_vertex_colors,unlit_orthographic_basic,unlit_depth_overlap") + set(COIN_MATERIAL_VISUAL_SPECS + "cube_basic,camera_persp_basic,camera_ortho_basic,material_emissive,two_lights,point_spot_lights_basic,texture_rgb,texture_luminance_alpha,transparent_overlap") add_test(NAME visual_smoke COMMAND CoinVisualTests snapshot --help) set_tests_properties(visual_smoke PROPERTIES LABELS "visual-contract") if(COIN_BUILD_LEGACY_GL_RENDERER) @@ -1001,6 +1003,26 @@ if(COIN_BUILD_VISUAL_TESTS) ) set_tests_properties(visual_gl_drawlist_core PROPERTIES LABELS "visual-render;visual-drawlist") + add_test( + NAME visual_gl_drawlist_material_compat + COMMAND CoinVisualTests run + --renderer drawlist + --gl-profile compat + --only ${COIN_MATERIAL_VISUAL_SPECS} + --artifacts-dir ${CMAKE_BINARY_DIR}/render_artifacts + ) + set_tests_properties(visual_gl_drawlist_material_compat + PROPERTIES LABELS "visual-render;visual-material") + add_test( + NAME visual_gl_drawlist_material_core + COMMAND CoinVisualTests run + --renderer drawlist + --gl-profile core + --only ${COIN_MATERIAL_VISUAL_SPECS} + --artifacts-dir ${CMAKE_BINARY_DIR}/render_artifacts + ) + set_tests_properties(visual_gl_drawlist_material_core + PROPERTIES LABELS "visual-render;visual-material") add_test( NAME visual_gl_invalid_legacy_profile COMMAND CoinVisualTests run diff --git a/testsuite/CMakeLists.txt b/testsuite/CMakeLists.txt index 2ae73b585f..39db43f2ea 100644 --- a/testsuite/CMakeLists.txt +++ b/testsuite/CMakeLists.txt @@ -196,6 +196,8 @@ if(COIN_BUILD_GL_TESTS_EFFECTIVE) target_link_libraries(OffscreenReadbackTest CoinGLReadbackTestSupport) coin_add_gl_test(NAME DrawListGLTest PROFILE core SOURCES DrawListGLTest.cpp) + coin_add_gl_test(NAME RetainedMaterialLightingGLTest PROFILE core + SOURCES RetainedMaterialLightingGLTest.cpp) endif() function(coin_add_egl_test) diff --git a/testsuite/render/baselines/gl/material_emissive.png b/testsuite/render/baselines/gl/material_emissive.png new file mode 100644 index 0000000000000000000000000000000000000000..8a08df11d0c6717c855f111daba1912ce5d85561 GIT binary patch literal 22163 zcmeIaX;_oV)-L>HAVeTcGK4TB7!U=~Ad{$&02&ZQkXb+o0cnP)fM{z(2?7Cx5KvK^ z5M&TUASfc(jUDEw*b+pIGegv2ERa1K=8UX&VGBsBE>^PvO6Rt zsw>R~`IiqrG>OymIR>4_=KteEpqwT|@nbIFF=;||?Dr2CTmIF8-~a2+?_tKIm2lF@ zKDWP&%Zf-w(rh&THY6B4AIhux^XGmac^C^X_l3$|Gyi534V`BPQICB4hehB|;G4UD zv2pJIxuesB8Z2S56AoT(O#1zUNJ3Keq4FCC{x&A~Cid@BccqzR@Fi$|%*wycGfe}S zgkcGz$bTJE{*BEazu=EwrRhSGPxK7;uf9X8%=zxp-^P@?4)@QloA=#yzy8&Aa|2@j zcRUxNH|M!|`~Eh||IVJ1FU7w&$q*x%wK z&6xBE!g_xCTZGBK`RAA;8Y8K0AOlVPkBPbeV9&|7|Gyjt@>KrMnOEhOI`#}4>nZwM ze8634O)%2QvA-p5`8WR@b5xh_r{0JEF){a_>^b@N|K|ea-=0~=z`?FSI?4N6d>}!Q zfS}nt{9Cag|K^`#E-ynJD?jyK{m+TH|6tGkyQ25sX5J;Pv}7fkO~l{gXUY%;U%_U=?pPT1ja+$;!%#w0yZ{mw3g*?Ch+{?98`F z%K7Kl_pide>Lehs4l7p7aC^l4%4umA#&a+=LUwyhJq`nVlL_hS>LRSIt(6uwk7U`Z zE=t5y!&tRekY?({NOw%KTD!cSQz>-UAJcZaPBYl1l6Q<#ZcJgK$H&KMeqTzdkX76M z(6~h$MHdWA6w`jh%!^u{g3gd{yaMWgcm24VKB9c<^B8o2E<7bACCFmGhs6Q!bk?K9 zgFDtho8R9$zD%VdtPSU>nLc-iNMGc`j<4ieWV^YcsJFU=>NFa3d$g1N*}3zJ#PwT+ zROURKvs%pkwQ4O9vNMO4>+jEiLWsln>q5$fPVO%9V}hk&HDI2S;_Ubci?y8Z=7UBn zD@XRdA_h(iK74I4-xbtg6rRbw$UZi#Tq_gCim5O=+tS79`u5xN7S6zwz-0n5L>y@9 zFk8x#TmND>K?SyH)22KRyq~a>RDFpWJwK%V$bfpOf6Icv_ZjB<3xbnvQ)g$k%09eO z>-_EcFM39+_mED)BwFBF1L088m`ty|L-}@KLLFrW@R5-b6+zMJ=9@TOP>$liV zpQ=!Or^eQR7#OGkTaSV@Z-T@h5j-Iz?%~I{vcA-$Ho+*}B*Qw{>%i4qV1Pa%eKC^q zRr>JZLp_m5#P6K02$W4j>mTN-sD`@%{D915%CdFpLcd`6> z=cgnP-b@{u6vsr;npPWRt3&>SJP-VuPUg44>gk%z6GShKev8xYo99EdY(wWA%aNjC-fI=!ye0fUS}dtC7f!GTGlz@2$AAr83Ho)iEUJR_BM{nXZ)+sQ zF;*N#&c5Bz(LouzaDee9#`Xa>K9EnTL>*lew|9o=M84m`9RMwk$? zp+qakM-V}MW4ZQhf5RGJRXGNhfNwsJKSBNBh)*KeNUp6KtZkOib&oUN>98$EO}@~e zIwX|*grbxquI_kl z;v$O3ZThfuvHWE+9GuW9tbw7}8qXnY-L#uU8u;CU4T#dR{lI^IuhY9| zt}{n%paf6EP;JX%!)Lu!_$>@lmrecN6zL%Y{MmwFF%@cNLoptZiPL}^f|`t=HBI8{ zrVBw0YD`)_fT;G#xc#Bie82SO*^{m_ydLP{WbXqs;c6Ns??n3I-HPWlSkD%*CU!i% zW=mJ@(0Kgaj#LKl2paqBHGD3Moacs4ls_MGdmT!i+)WmZlPft;lD=BHRlto{Bx^ct zJ-&HudW-q~Cb<**G zcrh|)t>?x}&XX0TO=TnzJ(*+&uMhvl>70^4Qdf0l5MzB?ep&66=_2CMrPzy7H92?aH3lds^=JQQSwNwWy7SNVEyXOKNG zWJY-CZ1CJq2gl}kzwjD!CX4;1Hv}#HYFzcetL~7|affsVRL<*fYHNs)jR)!Uc_e$= z?~7hz2ruWb$_lG!MdU9!WKjXx>hZTlHL?f{6jaI0?Fk$Pv$%t9%ZTCi7%hGaRX;`Z zcLfu^Ncjn8G_l73hIKQwY4W_ke9cflK7t#Lr~mv5K7xb}rm*USlMOkAD-%q>kK&p?-w;uDla6<4V%jGp?%pGc`!fH6^;w>WPtc;3Wy5*V; zL+Me(-QVManKd_Dg@gAC?zU?D{%$gJt!K<{=X zw^`dh6R+5FYY)5qGNkxClbl}mfcu`^9u{2STj*O3gD&ar#XyaigCAbqQF{&F<1UXH zu+>s|^6kR9Zsok;1@~PkKE+km<@cq+2BH|d)V_w2ZX3-_>K=`9R*AnmM%}KlY_%re z#;>+uZq@M{j7cYrUhC@fZsG@j%K9jCwu#9ktE8L9G1_(}neUYj@AsIJnePZb;ppd~ zoHVVb?B&s^dMr9YSlX1iR8iBKM8aOmw7L~zyIc;#QO>ACws5K&Jm%EN6)RR?3qDT~ z17!jQ8^%xgW``6Xb0r2?rUNORvw|YcdZn|$BV8M9^IqOyQ&e~2Z@gZwH-=LxE#;G8!WSH-zTkMFd(N{86 zyzV$l_&ge7MsY7Gt~=QE>n!m%b*S;qnN{{;rI*GJzQ@CC8G!mY(3>93F^_QRO?*hV zSIj-~mujf7Xm#0CYS31%TOMb8E@$mSuy8*iXz?&XEL!Et+B7*N{qc1Sx}N}mMntu4 zHBZU#@slNAPLn75$qt>fGWN7yq3Tq7&%(jS=iLynv-)fgYOkG^m)F(w0jSR@)EAQB zaIQ5JLm#l`p3TN=am2xi%a8@SpCdvfisn3_Zj8o-i#dg6SF9)u1j}z1F;<2Td4uwA zmTuSL<6!bt-EMDZ7rkQNr?G+?6|Pm^<8r^NC4iw|i?~+({p9N&_y-+isgluyCuCck zQkP%<;DxTmwm+B@EjVgpKpW26p+Q)*r16GYC6zDH;>WbD#KCODmL}W;4MeIZ^VE{IazkI22Tqe5LbV-hc1~5;VHdsocDJ^j^u$AxnTIME zfWRTFlKI{KZ@_+Ffy9Lc&Rs@Zs`!vmV5L_c&O37hqZ}46rFK7T*4sz{o86r%S`MG| zgRW~pDR&jpuVm{DeqV;$HlYBr*J8y);1*gxlnO%Ola?(4&DJhRd^CVhYZGX?pv6@7152VNd~G9mAr+PBeQsbV~u6%*$- z*;KNS@*{DPiR3978#gu2p^rA4X;DA#hVMx#&(lrAB04VaCTNvV03@Vyw7h5*;D~+d z6#N&rrBOmR1sVtP9?p-CIV&m^ zDYZfPsKu+4+9MM(EhnYzrST#aJ4Mc?8Mn8i!$x362G(q0!-wu>6!dtSZ23|q)K>)O zYKHl);08y+z3H;k=TW{vhpn}t^;b(jLg|)9sCxjgZ(jj?0%{r+Sg3-9Ra+{ZJv-sQ z;AkF7Jr1pc+8brB(mkl~wvzby{zQ)PSB+Cfp%Ik680g|>wdIJ%Xy_VtIljw?kqbXT zRemBz$zWeVu8h>xcq!@qHWDmTj5i_N`8NOYstT$pcl!g{#p%Y%C{Zx0?Bt!sx~&8^ zl`U#ZoFXRN^H#fKmRJ_9!~yHl7aO5G!HEg#dp3YzqS#Qg629${;zZ$jsM=vkUMP$Z zcucUHPe-*4uwEOYap7CJwad$+TZFfkNO`7yo92g<5qlRebrg+JKihvnYn8FnGBXuA zX|VLUvvU#pq5Ct3J|UR%J}#df>yG`2iXuJMVhmrb}kJ zUb-c9qfc6LHDd#iA81Qt$|m#=f%akEOBVtyzkvbHHg8)3J< zWiaw?`Yi(w9IVS^m5;^V&^KAkg}pj=2Gw1;WFH(-0E)D#VwCIYyzK~sx|un^8)bsz zVTwj@FM9*{3j%M-%$dcn3iM&3!SYjC>+x6Mxxq!NjCU4Tw3eM5EY$thKJALJD%hN% zqeVaBRzH1Xs~WonI}R}Q2ygZ#QU_>}y@WA(zjY}2h$DO%nHJ2ooLah>-$ePXNPP|d zLUw4`K&__PeIv%^c@NcGZEKCc;zNSGeN`L}2yat2rV<<&*!^3eYq)}GT9C55QyBa$ zUyc>@J0c5|*SKgqfshfq=(VwWdfWoN+%Zg78p#%3K;(LZRJ3rHOWXe9UnV}jj0l;e z#7&$~R3f@eN?t1jxa_1t@w$sps^9~mDlNKkXPH>NsBxV}D6#KmwyjF0$p7=0}q1NniCdkVBWOGxKL4UR08Tfa5ad0Wv zHQHom1Ae~*-^!yd%b2(^Tq`bAj!(Acy(V6TQy;kHdKevlTwrmt?DRl{>nj4eRPE!D zRX?jKTl-WY6DpNcw8@JsiE7^>*Z+vnut(UzNsqqb>yoLikS&txQUYOS)0N0c`(`Wr zrd!OD8JWu(>4P4Z2jkp_YNdtW$Oe-*W_RurURpQafqqotywP5C{{k&utF%^Mu!$wd zse)tVT{6~oW6Jj5!1>7yizNoac`k-+1N#_4lzL3v7e}p)72Eb1al(!7MgQe4XWgvSqLx zr;S*5#OGnTJ)F&4?v{^dU<{JFdEI8$u+2Phi9NDFb^UXMwmo71!Wz!t>k`2{_n}o@ z{S15bRn5Ynk%KI4fKisZM<^_3nzBMk#K5r@>BxXuE+%=u;M0P~nRNrD&8tm|9Iu72 z*B@}@MvC_ksusBA{~)!=EIBrQf@Ar#&}X8&_R6J8xPnEvzbq6$2gXw5a=`fCBa1+Hgb&1|G<7PN@>3y*s-D!B}&4Qe$u*GUT>Y)IZO z8pAFvA`5oNMqmrM8;)48EuDCowtbF+rEY5wv}9Ro(_HTLtH=rVyjMHgJ^o4rxhKiD)_WX z(}?#oZQC}_&*u`8k$+ma5=m1qvD!H+iOa5&6bhQ43n8)w*-P6-)9dA@@7zv;opYhBc%dyVPhI@( zTlwdoX|O|~4ursI$z+$EYQepT+R*H}J&XObPSXUo@hw|d(amE*ISNT1&z*-!lhK#C zLAVg7($9^+E^W%FH*1hObo$c(%4E_N@ zvsOEn@9v-mId~1x?^@J@jyjgwF7IwabuN(KiP2MEd;I|%7AG=~VQ8;NitzAI;MS|@ z=(KbdzKHnLf0&xDFHSJ-{&o0hM`I?eKA~NQI;hq8LWgd?w*bfB(8bb?Z}*h1mj~%t zdB8)PjY&s8s4`^uKxenUY^eE=K|ss7z`+b~Yp|%lX?S);^P%)7N_yd$nI+!tR}djC z#AX+q(wjv!{KC7cNiB5cNP1WQ(}R}N*(ct(+#yO&qU3#&y5hNWFGdqy@o8q>N45aO zsbki5)J4dQY7mmi3Wa$S)e|2&A9_f#rutm!dHF-iFy$iC9So3arO?oH!~v^$~Vgsvi|!coO4)QKv$(Egucq?OZi{2SIeb?l+N z=&6@v?=n=aL}-x`q>vMa9Wn10DsS;nj%H}MGTJxBRV?_b@p4Dfd{o_&6-O_b+nVq8 z(O1nF(7&!^urTY{3V!$1D_1J_CIeOtDevH%(Q#Q&l5=*$i0e}CdH!)-e#|aAbi#?X z7gpGIU>sB2t&V86b(-EAU9a0!rI-@oT(2iGPbqMeywn)EySzlsnAs{XO4*R73)D*M z4A^9xtKpM-JFQFWbcNP4nYm{1H^~gY`@9LIF;lzorF_r-fJm8eW2_`B#0)8!g)*H- zBuU^Tl}WR?a>C2-9D|1PQJvtYF?`s}BtJ}JbR@ki$5NVD(`~kK5x@UiT5S?x;n2KH zQzz?1jX#opP)?ay;GZu_cF9>86zpP;z@Ifrv{wl3!m}r&~DYQsGX_)rjFUMlP5*Pi82s@=;o!{GtC{um9fp78^Hew!iw(=eDbTF7}&P5`jGkg{)o2IdtZ5 zDfE!rV9a9JT?Wwo$iBYA;P`>$t3KtE)X%!MeJ1y3J56gwKP;UdpYYtfOa~Ig+MO6{271BDL6Yq84tEyV%k#n60f&=^g#~$J-n-N@Cw&~jH!SA;p7ZU&cUvP z6FJK~?^>vWwnTa6_f34y6$)T!oQo)0mXwy&K3oX+!$p4MR~yRW9k6RGl)qmD>$F+fJB2Uk`X-vhd8SBjCW8k za7o%&)mr1c+D&Ub;*8HblTJ?(TZI3|2+R#<<8g~2?ByyAnpfm@wDOb_0|%lZhm-okeTFxtT3@~7HQT;JT7bwJ-T}SWq7nSLjR*bKkK-RlxhqQ0VYn2?Rpq6ng zpP*Ya4IDd-r$#^6*Km-GH#r8k5mzM{{ z5!jI8$RnG3F}{rdyFe%vx*at51l<85f^%SubTPGiR14IwGmwHPZz9C%2d3&enYn#qb&b+ zO4L4HD_5szv1xRE#?3QF*EpzSVD!8C?uJXRNJcVba!zK)--)BHtdZ~Ji8X)5TV{|* zXRF3xMF-Rte0}#8fvQ=QuJIMpzQ$Iyh19%N*_aI;eHEGe*hzML-DMRwHBRNbZ^~M4 zd2NNU)0NSfzeI>7GP`cI@ScWmv8L||&5%Wr@lon`DFm}p+IE-o>#TAO+K!6s{VpM! zW$e~7ehxkZs#e2@+2R-qm?W+?f%6v67@ zxC*ti2F+0CiyxBUx=)uR;gmZaHXqU7(N(3J65*DkM`#lb*j&Pv*?8UFW9X>(N1+Z{ zhY9`}f)SBOd<_<*^JQc)y_=@(XqBrH@jm?oXQQts`)Kjnyf8-5{e<-&Wz+6)m7W)w z^ue@2K8aae{?_f~D2SEs$>{6cSzE0G=fU&TF|~UNE&P)m1xW(cis<3ITdIst5tolY zVRgO;r1zDt`7L3?8`;R#Qu6}^ZKOQQzQ!BIKNWqChDFuqz zmSc%vVKbNZZAdB16`x#7OJZ)>B zu0t9}q6_u0UB$T<*|^wj?yk{9#hLck;X21#Wz(*) z*mI{m5ABs!FF{2vH8xc(eCoB%RLwfeyEq+eTgNe84)Ii0uIIZIrJE7_5B48oYUUtH zO1C;zY44j?ch0Iv6ilvr94U4=>fO$%OE9IXRG`j&Yf;+aQLYufM?K!|nw|<#Mg5R{ zXuESf@1tD+s|uy(6#9U3VNs!>$2%AOXgj-|HQE%(FeQJBs3XZ{ zo~sKKzQ-qcudikg;isHNJZRMWPlJV|?)>$SvNdpPR)Yp5u97U$hYeO=Tx^91k*V~G z^Y5JPs?taqcGhFyX8-YJt8{*jtsQWfeqI_eIa2 zG;@Hh=P0E%jr>3(Tp2M7a5UaU*o&odQyC)?y5QyAl}3L#aX}Ibh#5BjnRjE%yz*0e8U25eL=WLuEh6UMX#K-l*iYt)?I1W14W(}L^(XG=U8<^MlX0gBG0N3){ z$ojh^hu{(z<-6 z`Wqa7Dw}rO&Odi*-603*MG9)c+aYEBlmopB-7p`!Dx8DLj}!z)?PYe2N*w+?vv0dV zfiJQfN)b1Pubsu8HRzi!8XOvM%UiJlv(l48DQ7?IYEiC;USYN~Wrld~H_@Q4IlCU; z)w_^=n*CZMyc{q$e?R@fH6?(raW3&=eu6ezrnE6dVNv}dmS3U=T-kAnz$zCPt#aJN zYkN1>6K~s1iEbw`gCf`eBB0Br*MJJ{AN3KX))j9p|qpmM2pgvB<0BD zRBxZ^`AX|k3f*$r(j7vEKIqmY9j!2=f9x2*USp=DFuR`qrI1{QCg{>c=2lT)-5MPV zydw_P(tG`Rn!ZElz9Mwb9)`Mg0=iDRH1=yL0Cs+TGMWT5Z!d4EqZC(A3zC$q0h~J``XLeK-A4|5sA#h z=-^^uTcI`9ba5==z03I<>kPZTB(8Ynm=eMA%*VZ%cS8AaR)mz-yD)#5spZ_+nhtNuxxoe^eJu0CF?shE9!Mkj}G3(Y6z>7*nc; z*4pc~O;VQS6)H2thv4CvYvNi)E~RVjtbScmcGwzqVWd|lTvFt)q^>k~bToYu>DW=S z^cBQnldfK#F|^z|ce1&wq?N7C{Pgz0GE{VQw5*>zfBt+#QkkN;7@d>$D}u80N#PXl zGMqM$i?h+Dov+4^J-D1QUi&6OiI$}k@{Sb?%v(D0$KQljpCiNZ=Jr%QW9 zeQR_&D|H-7dHy(&`2vr7n>v3Tmd|`J;s8}Gm65on9^2fK*_wsL1xB*MCTy9Sgt-eH zxQh9MushfVh-hyL@1;FiyRHEr&c(NOnAt3cY6%7VM!GWe1gdfQSlZm(cJ48nFWC+O&>sgk$>b*ptV?47sX*0Y3|*%{S*jJG zuq3Gr6Ip(1cy#n``bD)=GZl^7L}P1rtYOJyq54RB{pzlhjs}`W zNulLm^>scAY+C7EHVgZ2vs*DI7FP9gFP1z@T=N;EY-<=bo-b7AOKR>n^&jG z#u{fGS3Bj9%JjN({7Thuf^VGNwNr)fI?U_`4?8WvX!tr4&tsxKc1gN*@ZgddiwJqK z@sNnp)h$^-nTtPgCUeyxZMH}UK4NYnbelJB`Gwdtq$ZE-gC@~Ytov>Pxe!{Q%0(+#U zwGu0A#R6T4NGVzh$K&x^$VrvCw~QFtip)xir&F_*OTGSFgTPlj-lOxW3tZWKldY0> z7QD!*nVwhUuzL*KnH~EF@Rp{b2QNKX;O&KO<*f-{qhOI8p+K^o5=7Ijbr;$d*fg(k zWt7vZ%~nWPxN#Nf=1B|;nlZ6Xzz|EF*CC)|*A>mT{{?+*bAcXcK^qLtP?v@Zbzutv z(HS~uVC>P2imb897n`Aqlib=(toJ>`1veZ0hh#XEU?P9Lp%q3E82FKJep8ekb5#5I z%BUZOtMX9{jUkB*Kc>fIIb1m z9)TM)E(ME3EWhq6=nKbr{Rsv5pFza%W- z_1YZ_<5M|aY8&#gxbRULVKkC*6_%e5&kI-$;tNm>0%(VS(gA3s+tQy4EmFh>^#e*H zj{w;Gl#}#knodf}VtCu71;@w+K6=bhjgU>m+D@JDjJ|d=FApNL#d6U%wW#0l;s)W) z?{=!Bpz|tvNMD3}fx_r7&I#s(OZ#Yx5nJ+}94hwNFYG74~eX?dFzEF%Rdy@IIElBjF z+0v_+k5TysS&|~VC5{>)dx^C~e>GEW@)tiorS}GlD^DnS_nnB2NGjb3Ix}zl^KaoO zb(HoYQ57QL_NfjfhS&pYOCn@(J=K=(=CyrXAIn1O{eXFSKlHiX{}pK2Gm-h*qF#sBGjhW zlm*bzo~-80%BD}TEnDSz;;qsrv&%CN=E@k^duS^V+k>| zp#3(G-*DvobnSW`93K+FS+BaqlDRgG!}U@Ld68DPprbOsILfWYQ1BjqQ}0Z%ho0kD zW2WIXtg)j^>B`b_x_FLqKYc0H1N7OJFQAgIGn_A+aJ9|VxX=_av%t-;6$7W=B}|?R5GNm)6yI>x zFiekDqDfB<3GL*HjXrf2=4(2;Goo{r*P*%B13JN3ZNROgQ|m*84<#w$*YE;^FUgQy zV>=J69uf!3>`n+pW`}NyjF%Nyu%DrcRnDxiDdOjuM$h=NTnxK4HRzGv76e}|r)A9m z+R|6I42KwVC}1kGJmM~l*8{s~%;Xg8^XL4eeHS^KyVgQFlt!Ta*s`_Yt!alm3I zJ_$$+^Zaj05)WB!k0`QBng$){xHbI2(Kq+zUzm;{Zk7`n{6YUji`Hargh?yZgSRMo ziG?sJ8@hNtKeTm}PSl;2Fj6>(6=@;L zls+5i63%DeHvzNILYIE{SDGFMdqK~z4F)NvCb=oNzx&uZMg%=i(EW%FVjATQlNSLX ztsE-fH95Chz(EloW(1wHa|}dD7f)!B=%T&a4$!|o37a--Mys$<(DjJ@bn(WsPPYL$ zmmp_B!^*pR5`c2~8F?71;Hg01!iV%>kUyWaH${7;RXO5lKDyv!fFj+GR{g@vhxvvl z>$NqfypDmHVp#3LQ|TQHZ!Z{NMuL$#O_5ZK)R9QdWIJe*2{C-(0wSDu^VDE0l+t#< z#|`OT*YCE|ZWz>G2-aW^Two}+gHWSClamD8dKmV0&fM{sz7)yxQ~;2$q=-Cu5)z%G zh>aYRw&uq(q5a4-kp?WN+iM*(5N|_Uv~Z_%7|^vREArI~LZ&+J!&E+z@KOM9fiC=` z*lNIu`R%L}yXLGC>m$EFAJvr)AFAz3w}g@kzJ z6(DjtfBE&aLnm-hDWDzA&Fp(#eXs~(MnbK|tXdZ{e}jN^d>6xTBD}5Ryh&Az1CDgm zN8PGu%h>=)Q7CJ!EI@T$7oMPfwd{6 z+LMfLQXvhaV!i(iFS5wCh z=8zyFZz*+y0ynhmNXNqSllVB-SzZ%KjGGJGdpBu-*H)JLrdR#CKBCYKqTPiNa4(gD zwx-GVX?ft7fP-=&!o`ev28I~^1`9y?7Su_F`dSq>aPW5lR)kN={7_&30~BRBJ2zgw zvzl`C#E65mTtwnFWu*Vb!D19;J2Vt;Ff?gv>4u=~)_k0eHLpZjwe16{mu*mi??k%v z^r|1XyX)MPQy6yv3ZpkrOIV~nGONUs50H45FP8@)YsU)JkOv!`mDZg>5t<)xofbfs zl-rgsG+iUuGG_l|`8dTEqI~M09vQbq@+={P3yGwt@7wd^CmIl>+&p`r5r&(`ddPm} zs_1`?lvg)m7L9|Rdy}tg!04_};94(^de?(&tdc3p@zochJ}!ef3)u1nqD*C7EP#Cx za#kh_@aSnkzJK%VOe5&lZSz5#N+Hy6l818^l?*QGjmAAVEvWw&yW35 z7CMzaaI@en{C6J#8Mwu4n)3co4kYzB2`E|zO4X}f6k4%%+bD6J&~pj2#DrF4XJzbq z#}@8dR)MWXL1oX#8;l0Atl_e-DYaY_B$)r*6bc~Mz95gkR&CP&slGE59fu?Yei4Aa z6OMsFFgVD9;1nXf#U+YBMYzXis~pqJ5TT$YM*Ue6H#B+!raH~{icUh}L-?-idnQJB zi;}Z$1C9b!&e$z62E0MF5-BPkNvoYM>@GfWLXTGD$k2r~g67nhg4?WjD_EII%uKHh zF~Ue28t=HKbUVZv>kPOtdO_w~G+Vj;INLK~)y3VvXD6xLZK>mx*7OHRzIl=lAUgo^ zIaP%coo=opRyy;@m|ES)@;pE~u3GU)91*dhx}9|=6l88dulAb?zn-!;Nc&RfcKx9k zBB0SzfX20MT5-ph14-I<={r+&TpOl^`bd&fQjBIfs;Wfmifh>#Lh~zb zSlRpwLxuWE5)Mjyv&6ew?ZR|JXzTJZr3VpvRl$tqgXYc+ntBax3#S#qleXscvEQli z?_cholp9)7Ri1uj5})rnBbjhokPkO9#9-^b-2esP%~VO1AqYG1Vz}rN#RCU#(V3?S zN*C45%#HI^dT!#y3+XtxjEY9zhP>fdlm6JPkx#K58fqI~3=w(p;>Nsi2bngw5eNd9W_# z_oLzNC8CJgIq`^#Ts%Sn$|E#rBmrR#*c-DZ6JI~?V3Sj4NGzQU<3IxGZ0Azd4*%gJ zchy;EFqGIAT!U4v`)ydKZ=N0O0qpJBx{#|>#%6(_y?r9plg1nKq|24qZfZOzRR z4u_L==FAz`nsh2eq4TJq6keFsQ>D1~DO7(3(SpN@20I52FR;hbnFRAxspD)Zl~A3Q z@b%L>jV(~V3~Q^e}=VS%*jzw!$5lVedD|T_K|o#9aPE3Lal&8?0QirkRSz5 zj4H$W$H@#2=stnvIgb!HBjLbZFbHWO6hvf&6_NW&((?AleFmEsI0N50qUirgu%~IH zH}4x5s>DD(R9I0rSjFI}`TB4PpdLp;0k6yLk+h;!*Qv0{qtNvlC5sNzIK+f0@k zK7ZkX1#^SZm+OJSI4QP(%ylevPzC0__0ThPX-^E)NQ41}3c5zGTFaSp(x_8lGZe0W_e7m?0b0#sI-PI(!PszfU@tT4kZlF`q>WhgN+88v35L#1Z{&1^pG|8 zSq-9fq{m*9!nlJEY?u|6yOqy7n+S4stOH$rk6{14~tu)E(nW8!|r&WNS?$c)7;$ z5>E)JV}dOxHy%L+_!vi1N<+ee=5uDze$f76{2)k`vYPovfY8(YWi}xCe>*fR^hj+Q z0OAjRceeuBr}!|CV^Sg8m){EYwWKP`==(m22GgF*)9k%Js`$IW(i-Fz)V2j+Ir7K% z=Exurd`|KW>!fbCe*Qycs*K1vv7q#x4dmESc({aIA2u7)?e$YJfa3cbll8W#tLuu& zi)Laf$p)?zKfj|e8%L;9f~ z=Ahg;PxLV`6w2Az871BX6SJXgOgviMHN9hgcxT$9VNSyJpAlHu4 z3Kn(`13j;Nde;HiW++z^t4J^q_UutMWOt>hdOFd65|quymxW`)+L*Suci#oYt|psR zU!dCMhJNC(q1VRz&dzk80a@qD8rZ}7C`tscQ|sUh3=eg#$)AN7&5Ug{)nwXFc0Z&8Qp@PuY# zO1?$o?csFh)Q;!Z4LP48K=lPK7E!C`)D*vefH#whsge8T?VdS=_WOqz*GJqWLj~oev zf&ZP~tNSm;+<&m=0H5|>-~Rb`nfHI*OMm~xXKnt2J@;?loBDT|_y4_-_)qV0{s((b jPPF^~`i(@mD+EPzf5lF$m~er>KkL?RTvP8tJNUlQ8MfCUfj(0HhxE#I{ z;@@6^(2U%>V*<2Htoq+CYJE``QYEOQU`1Vc;;$D_{A0-SU!VThI7nkGhB1oTegAD< zVc0GN--+-aQ$myH0kU)d>;L{Wa~}~_wi+mVpZp(-;-h6Q0Qd0p|6URF4jOs0A>DNuIr;D5{sjcobPt#kNR8L9!aO0f9f_bDPkOTr4f zB3b`F=Z_Jm|9ZfGJ<8CV|6`-4z=+z)ILN1f9QvZ z#&`h`SAP2s4f`?j-*t{oLvVc|1p5B}8lC(9u;hN2|Nn3XKcM`-BQNGYo_GpIT&ejF z{eW@!wIHKt=s$q_$H;%zIj;9FulMEuUguyOVU*L;pEHW1(P(WlL?Wr2qz@30 zaDtE7;C%cULiCbA)jBEaVMb6_y4^l5won%(kDEC0siet9ZDW1jxP)(6nDB572$D!aQ(E3fDm zeadi#5t$kprnt?#z9vQ(G9H=3w9F;4o6ylF<&S)00S1Fn?4;L=)zN4`cvI#dWptgg zL$^&SUaydh(1x_3lJT%6ZSQN(x|$eZO;d%(LFwP|-=;*_ zq`qVl5uJ-KmXnLWjnlrBNkv6ET3Rk#a02iQjGyQbr1PD=WwE*EfWB_hxgkx;EX0%yG zWvAi0UizLk0q&LjhUH7a6FR=Bau+n$5n6GlBM-YKu(U>mhb-bR)Z zB9_k=VhpLxVO7(Aa7__q$9FGLOmL_%@WvLC0Uoiu}x0gKd#||M3TQLN_pBH4*mST z1>~KTAIK0AN{@r}VM0C!hJI$rsR(f|89%ejtn4mJN{S+1xnWeFK(B>8y=1n3Y* zG*t(ta+pLa^jbecBoX~3@51iv@80BD?U5o~t7Z}as0rnN$EZSh>Ap((e;8yQ9Uz8qoqFYP?ug{N8~T#x(P zr9|_uwIN?^u6qBj>|RqL5U*W?Y#~>Hgx2`O2|9&>jGc<^$!+PZ8F0fR&g^q^BixUc$8? zea(zE!Jw~f`#&5fL@!o1Nk`tp6CyC*E{Uja-R}{FFQqH|jq=b_zE5zMr$i=NNuJ&m zC*q$;=VWS^fJ?!Gqrdi@)rA*|RjEj?afN5%(vD`pd=OQcj`{BBP`qZQxDDr^CtUl! ztTHp`^FYDkP;8qGFgOaTQ|jD0#i07RW`BPj88%R`B>FA*+&$yF<{W`fH}QAu!=jN% z0tbFrskKW_F2HRpVh)ME&UD$O^2&rF(0wCNoA~EHU3Y;d8zL6`S0vgXH4w2d-o5kp zW!R=PD_B(y&6~RDToAnoQAix=7)iG~U>_Tg)4nBRg&KIaAd~~U8%^D_f_6KtmE|pD z%x<3eE%JqTaI19Xv(z_S47-xQ8brJFr@)$xz$3UIWoj*xu@08k`*Y{kS^^372PuQZ z-Z@@q%z~RFNQr~)tm|T+9A;f-Aq4LvK$h_=eXkKv|9PpBRE%mb%Z zqtN@Q1@rXIfZKjQ1>Q;Yy_6C#_Mt4KJINHsYnoDKA0s?iFm(&ZFaa=;QOp4FyWni(P^ds z{x9W=5X6ylK`HM*)TDOSlKH?EqL8e!#Mcy7cJ?g;_cOCHq+F*BOV*M%y?5l;?GEiY zqg(%XhcKlWM~4r-aUbH$lt1`V7BXBuWFj0@(E>8|+fk|uT-9d%G_BTWn`!g&4>8Tp z)X=W%5@@zN1uZL;9_&+Fz;>N9r5L=FJrW^(fz* zw!Yav;XcTt%Db1618c*xF1w{R^8h%!-=D(!OOiTb@oD*~+D#rcZc+kLtkqVZUMRdN zkV{{Co_-I8p2b{r&o?F1X*8x3>3cAoj8bP|Hn%+B1;tub(}Yd!sh!Yt^`P`Cs4>;m zlCH~K5Zo2*VMafn+V5`f-MjFjVbWh7j-yGNG{cU=&5S?(J66*_!1c#a?MI43?(M|nT6DUJ@PT)?`|5gEAp!%ufg){JAu_y1EK zGOoOf9#jK1$^38Bs|mR<>KdtfLcPO`O2%ql!3>u^PgYBxy9z5B{9?Of5sWv>T5NIw ztK9?1_&X`>VxTkt*n+0YO{%oahc&X+cq-KP0GG=}_AjTDqh5bO1$PeXk)EQ*<@ErrRpHrCzaQDinZjsw z<%`+2?OMdQNqT!j$os<{J8+*`IERpzKT0&V$)Qm>mlA*#0$FIF89gsZx^*S6=c|;9 zx|z`I0^>ghrDC9eoKK|O<}1LlFz@2KjW2!}=7q&R-akX|Ak={$Vu@DWD8zZ5!EGEu zRZe&nc+@?L5ynlz#~ym+!s1(Ug5GO=w*ylV?0;IC?DkvQ#-)@Yniq_7FlXOh(Ih~~ zlAJZqIYXa=rw~><5~ei7>>I}1Gd`m zZ}HJjd7;w>cE$2*lgxX5X>3V4q_H~(yjG2H*0;B+fh9_mSGujfb?s?Z&0-%NY}G)Q zFHnqy_k8&#@c5?HoQL__#W&JHbuO}<3$uz{iJU|pA1qQPAm7CrP1L2YqmuQJZK06HT=ej?2auYWOZZWZ3W ztn)NDJG~3vtRvF+RU{q9&EBa#*v2C9r9(u!qPV9rpso zJv)7s`N>mSZG_)kwr%9D5v}Vvb0Sd9-m&=M$0pkYYPT5~M%o1nZOPqmk24W1OX4Cr&+Fsw>>e^+ zLWh6LJ_Y{Xi+^?mtaSYh2{gRZPSC$;Q7jw`d@gEMv{Zi`PFQ4*kLF)BwG_W#Gz3X@ zoB}Jq59s37FU{LH1jP@@VV|P-)DVwoI*%!mpIw-2F=KPfCcnovV#2VO0e z4956SF0e242bePOZlP)P-y3~@D=jp3Zoi^2blgHmC6PgPQ`UuEZA3-7i_r|-z=RAb zrOEAdh(&>j*!S@&PA}_*8@xQt_rrJ2?9meYan4q%@Gqe!zgYvS0P}ScgST4Aw+Ry8 zc+urdArxEPo;yQ1uo9^849(2CGbTS!1O)1q%811)XRB--8+VSE2M^VeXW=K~7omwI z&dz(r*oSb;)w$-*K5zz1KDDs+*fgbPo_?TLU(p9&vN@GusZs;xOWAHKfIFbjy-G{j zvVd}CasTVFROBPOt%c8(NF@BBGopN@KHqdBJ7_{fw!<^KkviVy%?H$3dAGSh%`N}K z40@i?$~GQAKe`33!F$T?ZlDN5rzEA{Sf5A1a3`QVdPG3y*CH(bMb7;p(g!WJB6%(H zn+0-0#~W667l1@^W!q9Q7^UfSul`hTfpg#vixnNG!4E}%&s$)_yyD*|3>Dc}UEo=M zi1Yq0$KK0R1Y>J&Y*nMxjT-Lg)9PHqUh-gT@Ro>0@DneU&S=JYLqRv1UHN@vk?l-b z`My9hrf#-QqwT(KJ&XMu;H#f#X<4qYD=(9zJ1cb+wg>)*j z^(TjyB*fo&h7! zlrbf15XS1+IbEm^=KC75gJCx}g~H+c2$nX5`OSS>37z|=HMZNsZF{w@=du3hXW{Sc z8}!rR-^?vUf>vF$sW#woGjQT2d*#tOQ`ER!;#97l9;EhvPtWbd3t!CQ=g2Fn0wi5oYgSBN0J@R-rJp6=%@5sHmFc=B z4J^!!?yJN^;4Z6*~9bV5WNC4^_-rPLc>@r6Mk4)v6k@yO`M_~3xn=iR(tu4z6UqN(%xve6#i=Rz#hJfx9S_y@Ff+v za4r%}$&b6Y4Z&_iJuyc!+v7ledLibvAxck}{9U;O@VDFRA8UDzAgtV8OH(oQ1|Y&7 zqCFzHllb1f4fT&GAJD+v9?z;rl3WZ#CJjUY!GY?g;lcvwLT7|Lab%Ks!3nSt4IjsMy^w))=IZI-l zVE9~v{${@yYS?=^XoCfi17zUjW0>G2BFleK>MkdK?XGhPzw#d9HjeO5?6$L>ky|O( zUwaOQuqzfLM|Vy`e8y~CV{(ON|2NFQ#cAetEj;+OqSWk9Z#MGw-=J`mV>)X9i}o)A zqmBUYHu?Ou{QI!yw>I*#Qg0-(J=^?QDTg;FZ>v?>kpTT5M}Ah`=hsVOIj}K*mgR9r zOZyn=6LZLa30HaWPyLCqo%pRdO(Hkp2TKI@G8Y(EU$E|1$axNA5{!Ufaj|yVPDE1F~si!_Kzg()h#w- zWW=&kDgnv&iuHQh)d!L&MkN)w805)4ic*tnjdPv00T;;mU->m*%j9Xa6mH?4{9tCY zU!3uxFy@NPEr1jj40rNa!*gvWZyHiLi>dUC_So=)%ir8U#?o`M+F zriL=>;2~r8zOa;VE==jdB@&6l?{%EP-aGq>Uub<+>KC6jlhzytINDUP+h%Tu9&vun zg*Dd>;xchtBB?`>)L1fbjUepFx!b}0n6UbsNg#7(?zR`Oq4*8o zEa$SCd59XDlDk0VR4TF&+T*UCca~&Ac~NE;np#2|maCCXLtR`btyp;$&nIE;b>WM- zXoeoj%iy1|jQJlU*l|yqUJ$80FMTa^_>t^Qqo_-auy-?(RV0YZRz1Zt8W$g-B6_rRgEFWyRAUv|iVze7g;Jrk8Z-UoyRIVgy%2Bu*4$^a=X+c1xAnoTXiUjCp={BiP2)X6+u4t$c6kl+23Rk4 z0rWT`Wy?6l_S-)!ONd7c@P)Gjwaifmhw_oBh{CU#SwDH)vouCgHuo{Ug{HDHgt_;l zG_5g_$Pkquza0_j$nzSo#rc(BX$)uIy~j&~#xw_>{p9=cm<>6wAZoOYTeG#R)Ro zf%);I-meQvVcgL-0d`Rt0qWT5U_Xsr3ReIJ-&jgXc*lh2>G4Z$E*c)m|BIMk zY>y1OR`@Nz7Ke)oO={u>5|xwKC%JeFmp>dF7*kxo{7U;2ZIpHSWn;ZG zkAv1nkTCkLNMP>{N~J}zDF9EI0G=P$HhApeMS&M1tAno>-r3QeX14w<5Q&30N)Ms( zI7r~s{KNV^dx({tFB6yuzw^@6pEEQHhKMNLIKMQ}D$ZnHEa5cuZZ6{qW6U9ZS!P|o zQal@ea~d7&bHP{7^-X*0r_BnR##f5rbiWlesH)Sse`erLN-dP^SiU0;hGJ<5 z%0K@Cp=7llXx+s_`b6b9P04$Rd^Th);p}aAm2EO4O;J9GY%uV)`19_gTN$q8`Wx6U z$a!~?f;<#ylr?3d?$_=wc&gNljWVNiZd|hh^Xu8iy4#4+PEpY%-&DHCGu^dm74A&9 z?uEQ))w@*+;=O`JMI{vz^N7p%!mr(gTqqju?n_lZkqNMHBvd6(V`Z3eQ_S(QTtFPa z-t^O7uQs>`nS#j!p+i-NH0m{Fu@-k`EQar0IY9XEourt1rR41unM|Dvj#`q|caX0) znqB?Oy=0^?MQK8E-kyH!TL*iB@#!rI9*@^GdyM4&<;o>PCrxfVS9{3!GCbjgPJT)E zg8p&g@fK+ivve-kJ5fDI>T+^?L%u5^w@J@|t68yw4GZK-qm35U>7P)Mp7d_LT}(Ws z#s%2oBn0mtfd$!bttCJ~5APS-SxK9RC~OHQDJ1`d8N1J-SEc!$YiJ?DBLggA38>5c zOp{OGlVWEybtPCaD}Q+?*X-xH|86OYG~1VKl9Ku+G1$YZyTCsdUaBY z>r;^ZC8^eGyeEAYobHfOunNOlx~TfjK~4WWt_VAiOCrU$U!`Mjq*b0E;_Cb+{S#0fDt3;+Rg=~8 z`)CK>Jn+6W-kFYg7tP&}@PJ+65aY9n)uvLhSN$a?uO1i?%jNNlAdbRg6*1pTJQR~; zM!l3Nx|hyHv)3Z(6BHglEwTAmo$4Ci7}jo>g;8G|C3XHiz8TAAgvUs~ixG62t!|UOX{4i)P)C&V;)XOsYXvPXF+QevQ8|iAG#P~P% z+jwWB!ZukM%k8(suG?K)(a_b@x@NfSUWr9-`oO*jmPS&SZ60vX>j}pcB2@cX4;d}d z3pX(7`?3g|=ZNhkxhw14=^=m5x~?BgNz7~&5+oJI)-_Jcmu5wyZ{8HI_C z*;3z4D%4gh_VQKSpq)x*B(d6Ln+@kBqqQ-}fvU@HCNkGy72bym+fMnX!>@(MG#e-K z+Txwr@oSvQaRIZIH>y81-@R*;E>$%zdxlFOBvwRf83=d|3 z%OLZ2v}5&PW*(lpM6ayTYZmpgw|5~gJ2~w1eAAZ{Ra!t{>T z`X3^~EB~xMheHn0QMH)$aqn?QPj)5ZHE<0XWH|B@F&K>CF#=8D7wQ(k0*V_wa{pfV zv&gpLS6XQr$^mv=XVD!O!Rdh)^eNY4A|qAKI>5p`4pUGi7FO#rDM1p9Jf7Q z!`wzC~5uNH9Em9G&9i-SI6)J!0P6BpCm=Nb1#y*U29W3O3@SFT;T zYZN<3HsIB$W^af{6J^A6v3sFpOIBeJ?z7WqLlJ>+nfNKP`8Aro!%QVZeu(kGq9XV6 zfiK4N>5=hKBL{VY+`k@Dc$6iI@1d7@`aS}JZq}~u;_UUfxq0Nfc^rnG*LIqaN(W4SuQ=G~SOhrBjd|%@kev&}JniB_ zrF}k>A*FZW0qi74JoCNSm{p2K?R}kZ8^Rq>(5=Ty(ewd zyZR7$FDxX!_c}70VX!;2bXFM^RX_WI9@lczt0(VbnDEYx4#4E@?tA#gK+K}jdejZ~ z-CSLw6ruja&+xUAW)2w~8HiS$Lm3{ed%`TXCY`(-(foFM>^-LC5|f-;yxb*5Z&hBX zB7bjvmOwGnYGS~4>r~CUc}MG2wnNMOV!%TjO|28QB4?15-&d|RJrrhyk>iO_b7|ka z@09bjc+Fe!Oob)%}4oR;d#3<2)+Vx=hwHUI>K^FP>$kj z)2sXF2b=xRR=j~6m%=RD(850BUly14v;%}OD-F{^V~y) zyBh;$*m&|OJwEXsf0rH~(dtRRNR7NtiSJ<57DUN^pXeZ(%sS& zle~htCr@f4o=&+s<%ciwn_pwWYh!OqDQG_!~J`Z{laE1I`D^3wpmN!HlPiD z^r92U-?gq-YR*ik*OwXl&h5y+h2|Ti)Gs1XXLBEJ-T`9R9qf@UP_i;Q2@s2;nZ;uh zBwB>QKmcH?R2o-kT8II*PC?Fii-T9G6V(?Q-Yw{EIZ$|ZZlhTb7Cx#kl2)J4L@rm` z2kmR$mL)UlM-^_0bi~K`lo4*Z#}29rtf3AAD`XRKg59Oxf)Qj74@N*_$`b6OdI!X)sXMo^cT6)g(eL;s-jyb0rU*whsUVOQB|5JNZq;kNnh+NjlV z+_WPMHx(BCPUndRBf~)Ff=Sv7Ld@%L`qYsws8`CFOblB}q$g%!7Gdeu#A>OkMPXHK ztb{T!{jl*~_y$r{TDXs4gA;-_N!ilE;+fCn13hBHPichD`d)un?oTJINo)ONkob}N zRFa#!!s68h>Tbr1oo?!9vmS(|+#pKz(QS^CIPqT@&xFYaz65zMJew49?BRQZmX)>wP^=Xggr zw@=n$k8#F>k!R9o=Xuq>SvhCe!b5Wk-)h$opqjt=-Z z>p%8H#zmKDuBox`?PYVtAK!IN9U&?G~(@rP>ZYU1u z3=)1A2m+dTaEQ_;7`;sm4Hg#sK^?DUS$9UUI!nPowPm(${8xkd38a!IuGhEiS4-eb z>P3!SqQ6{MT(Dg>yxp`)#mUoyViRu}kr^Gf6^UQZccdC?FoL5c6r3zs4)j@=Y+uCR z5y?1Iv?t$5F}PV8-2Bxrp$MCuIQjy;5>wXb`XgQf%{ihC z;tE;sDx|(>1AD_2<2Ml%Zd6w3lN~aFf%i2D7%>W4ADC7sdKY4q8TwIm!a8A1V@7*; zIrY-&$8p@Gn_jMHOELKhb#2Oa>wZe&*F$BvV-~mj?n;k{XE;ZXl~$r$=8?2zmz+fz zBpc)2nlCJMkG8P>J*(3`?$~;fp+f~>IA_Z)TVYtnPuw!>OLf~-eCLNkS+7#lSTcp> zQNpFMy!O_CzZ@GYlL~G9x4<3H^@B0Zp+4v{NMY_`27^zT@r6QZvq55KEGjOO_PTL) z*Ks1x;X0(=)+(c~IRN;-e(Tk7q$=(tERS9l|X`TZMewwt- zj|)YLLgd#O+TYVnpT7GJK55c7EN@8Qa>v=8b$@iAFDglWQN*g3ax0jzx6!sLf7&eIn*!nzck{*rjO|iO> zf2bAJoo89hokvee zhHcJF+wKy%Je{yf$15~+oKGuU()kx*LCL$O7C0ULR_(L2l>dn`HHzpOQ*!SZv#i)!|@yD1B#ZKF4+r{skE4Y!Vs!`zv z8O^{bGSUYd5o*wE6vO8uD|INdFh|VpFco1wLMX*&$fG+~rutREI={^9BN9s#pzl)o z(|;r(gBY6$qT(D#ErWMH$^$puW`8(XYdL$JWus4ix&=oDW$l|hn-N^3y^ah09P#FX zfq)KPsYTqkQjO?|`6z}qUnQpk2`tlC}+9}7?*RT z^GSoAOU53>bfGb>($mjb=Bl^FTgSyNKDJsPMue~N#2 zNz&M86YL+>(UuJAeZ@Hw|3;E6>c(sv-CNA~(L%mB3C(>G$lrz#Vq#G~nybHVitV1eTPAxbn^D(J_fKIP#sg$YD!L6Gr zd-_33Dh_rFGCqQ1Iq9r>(HPvf#aMWjztpWy&-nQ%g}>MpJf4f*f~>QuLba)c>peW( zHhc@$v(lg%(3bpZroG4IGmD`v%yS$?N{TE&I>7~-Ot>?ui{MSmQ?MRq<1K9%XiNMc9m{ubu3W@-I< zxz3&rR@Fcl0{4+)>&JVFx?hax;^ZK>M-IA|8%owpNiB8u-2j?RxV$E)oOVeQrmAQo zB^Vv82uR=2vSi&DvWgJ0yQvc1U3n6$L@qTd3-{dvR=O1*G)aCd1TP%YYALTaHUDML zSncJpm}_O%*#w$WN@mY9BM~xP;ZC=+p5BL8MA@BzPd*8#z?Dm{Q4A|fLvH9O!*JNKMw{Pc+#cO*4gq>%{C+3`2J41;Ggj#c$zWbt44i>k z!&t1t@QXN_wGw}D05_O*5Hq~*0PmgTYd6i<<92*Rq>t&hsEmc@ID_{c8Ko6X+fBZ~ zX00E|wij>e^RC<=T`O%f4|6F>HY!u}D{QxPS4c)b5pupN#{EB1vkAVJfTI!Yop70a zSNot=+ZlKU>?-zJ&_g0BXAcnzbi3b1zRx6cWt;lzIAQ5;%?ZTrJ*f6SwD~>DmxpAc z9O23Kj(pOJ#_K3bB`(LSyl7?iEw4UloaejK2mSRj&zTp7$E{j=h?B6e$U+gKbT=94 zGKG`G9zT*QaRBD#dz||yZt2Y(mtq(pt%%EXxAm3HCWvO-Bl=i zhST-zw}#s7s^(%YcxyR23PIAH5z4ap-jq8337lOK`;9bP46a=WKSW0QoH+@8P`DrM zOEFqPQ~>RUJ)^0}$h{3y4MO9oR(z&(3d-J+P%o&ewS5kZV$9ORf%^`Zn)C<74U&ot zWy*5k>#S>b2f4M%wBt~xg6ULDu{nE{W&aEB>`8Vk^AT_e;3heijt%CI%Uq!n$0*f# zw5vTF{@Hg2CX)E{N6%q<>FmVEl!4Q!;BfvQHeV*7L}+m>Q&@46ly%yK-@LA*q0-R? zJ2>dgyiF4}N=Rv&?xi*7=lF$2WmOskGU!>;z7Dwh?z_qNbZ?##}vc~NMw%@@UyMA@>CR5ZA-pz$e zPv4Q*?0ll$f{mUVJrSYOn{o8_Jqda&b6_wOu`VvhdL7`BtNGjo_ylaoed%*Fkd@w) zL-2)zOU(%HFoHn>6zpTl79kxlOMd8Md+8BEa?e6~#aM?LGtY^b@8Ier;pnaQ320MG zo5cmTn2M&e+LAlnT1G;-;Sj49x>YQUk{VZiV!_Mh2ISu}l%(PUN6m&hG7_ooo1@A0 z9nC%g6}WH6H!#^fB7fYwGHeT{yX-_(j@;%eEt)phtS7p7LdQ+TfD>r?q&G{m4cq>H zpMUbc)Wlaau6!XTUXux;o9d1XM5)5xrNY87PB1M=`J1UC+h{b<|IZZOo88SY8m&ZB5Kb@xSIj#*2{4=#~D=ilVC3|`%4Kd9x z7(!CEG)jv0^7Mo9FnF>a?XG>z$EBZMIy4@h507J--mI@{f;+laXENaM;~q&)O^gT8 zk$lw&q;xNZH-`>S5Qgq%I0iK0ES?GI3;mZ;v*A2pp033Y7p(cgvNN&*HINHd-aptW znGBfvPFd$i3-06@I}Y|tvyjMsJ@ZSj7*)vgh^Jj6xtW#-TsZ9L0C zwXs>q!8|X)bY{=C6dw%5#TBK4uc12%_9=aR>B*hAo101}j;lq@LIeL-*wxu)X9nU* zzsoYXCNqwB2mN>JxX4GQR7J*D%0J!6nrUr`S^q|&vNJ4FAV$f^C7wawS zNDbOO;7Pp+6Wf~AUDJ^bUv_71=NinaOSa0bYv-3Ue$%#=Xj#T>dWr48B&umO9t@ny zzI+r_vWfE=R86og@tF7X;Lo+yQW4omOL%OcJ~qJrrp%|~-Yv74 zraXVlOXOP@t*c8DFO0=2lrAj-XRh+r^20Xxo)^Jf-hWj zpnA?)S#b>2kh-Ng3OO%&*2SZQ{e!AOL11^dBe0P*P(uyr^~a3;)Xg8+24wND(ym4 zbNC`LvByFho{~)B0d?N9mrk+ZYlTMJWX&&BYT@2fz)iP|aZQ!Zd(auiE}TWYVo}zL zaK!BX!5%g;(U9LxxreL$9E0dmwizE6V;|Fl+m+eI`-+6%iN#JkXUa~9x&^}HnZekk zaZ2q)V6nMM_*}u>?%Ml$K9J3@H(r={VS=&@%bk;J)`#9nwGYk2Ze2X(yUUTJ__%bX zlQv-mQ}tk4ei?OVU)p`VRc^fXbz8(T%(|Nq7k7nS7OH8LU}G%dQ|q~-gnRtJ^F;qw z8RS(1dqk08;pzfnD3mOKXI^1kfqBLbVuI3&qjOcaKK;n@6A%w5T*^#Lu{?ozVS?U) z0Jh@JcSWR;#122Q^v3E|HSG55*+K8qKaHav7Y}8fC3=~JN2<&ckYcb6?dUX?UMnhO z6oD6D6CG-`&{ATS$IG<*Y{~L3Xq9&Jg`>~&AL;=2rX{ja{$?}u%lX0~RH$*z?^Ikj zJ-T;|L(fZ73aR~lSg>+h9eX0y#dhCpkNQGc89-N_0Rq(@P6g<55VH8K8u z6cu2Urh|mXGRzThL$qTjDD26z5TiYB+BbVK0-%-`*hwTGv<@-hvv)G4V~9GOML#aC ziv>N?QO~0J8NoBfC8^w@CN1$!a=C@a_0tonf;pIfM0DKW^s$*Na}xV$dYlWqyflWr z9WS&??I*xGOTGF7;QnFoCz1`-Z;08xxi7T5mPOL6UQR9NyOukFOUouNeQqc7huR*LavtQu}gW2e<#(4&E{G{1;+T%H+^r^(O%ce zGAP%TOXq#mMpUX8y{w}~X=j9uY%5m1XqC4{FRd{4vJA6AyNmo+61`8#W?N876}q1YrZ zRo4ftd}}07Im3cO8>>KbT3l}!T0YNt@JeChv%oMc&de!sqh1V$s7-LzQ}~ip%foD| zUxK7%U_EA|g!FF62#lBN?s9)4$O#-1p}#;~tl$2e6+A)@-md;?=5>enkQO}O z&kia`IgOQFYnsffQ29$SH4faV4I{gO+<=QxbVNwG$fYY(!8ytzQlJW$qq3PbSjp26d8nPRlweig%1wQ+skwpW{2!HAC21UL-;% zAVZyKHJ1K|Mp$s}Q%KQ0fUA@qG(g6jK=Pv_A?y43T{Il#bJ%{Z%qB;x9GY%@yD+IF zJ;*^N{=}@MJ)`rEn?)lFxeLPl^XVvSPc7-FK?lEoz)`YU&NBIEE8k(yP4KEt4f=Rgn~KOXCX;yke!q8*PNsv zeAt3{u_QI3nBlX^*!BB>A$yYl7$^=9c5MN~G=1pnSHz*+B8j#HHKQVf80GiWep<3@ zIpN5Y0Os|QNo~?-AL}D7+@*#b7ddrMJTHNlrn)3w`UslcsL| zLc8L}pmN)OYKs8+y?m1O!i8Po`uRaR1RPQ~>a!9lll|bXiy?3YAJ$^O7`qIhUW&h> znwI}xM7?`F)BXR)zZo;^=s3rXQ3!2F_`@5cCOqE;_luur^##dEo(Q9xncK8_Q4}+^>?bx zLFPx=c%Xkot$A%KR=I!#Y)w327nXX%5VU)%RjZM`eSbk7ordgpn2pubnZP=M0(A zH{Y$Z@ouanh~6})+L>J1nMSwQRfw6dr3Lzr{-nKRwz4Me?LIUVI4U_W^-Y7?%^T+P zj4knO8;3hj5>!=~1Pe&*)54EyLHWzNpZuhXs8v}Xu0a3L!Curc$45T8otTY?(W2PR zYRpC1t0InKTh)T&(?nRKMchffi$kKn3cE0npxp>HO@)AdAA?lc@{GOICwV}v!Myy0 z$}4k<;64X&LrT97RzsORK(hRSDa4S;Xn78T72eDX9c0}%4dQ!feP{z{2(K*Bw66t0 zVSH304qM(2H+{Py>!{3%1pBZ9z~dv1wSpzK=ETGUkqV?Uv}Du8aYNf##7locr zpNU8&Lga4^f9V8Mh{i~Ws9e22a4=8tothdRwCx2=2jXtzt|eE?k^aUYWui3K)@a!W zVOzlrR05(8)K!aEB77v)?A&g=-Z8^p-eOi?CF{G4tOJ{AY8oijTwLAxR`eo4~GyvLBjGZ!N;8h+_sa{N9dH_up#R)u=PMGDJ(!xPlhd~SW{ z1$|nGStiXxa;q?}atb^8l0gcD2UqO(; z7R#Am`B)wb@Q~kMYB{9E`Zuz=gy(FVhA-LGOV)74rUJecagSU_h@5|g*Zg%{UZNQ& zS)vt~bQz0xh$g}sF#I2sYe>rv|N zL(6XRpF{RyS;!?=tNHZIIQz9p2w?`^0vvfme&GWD= zx?50s>$1Lzl;B;ug6IN|oF-UZ6dW*5AItMLd}i_TbI2H17I9j|=@`th*BLW$&wqi~ zd|jQy-d2*nj#M_%E@(Z>Y{hq1o#jFQX@)Su2d@pA1fL3tX;X7a#SP)C%_!|NcDY8a zkSw-UJL4s6EsW3JK+8yC@#M%3S4l9Bbr_Ta=i1_auFz8v=DZzCG<<*-Bo#~Cwu{Um zM~z7V#+K)dBx%no^+A17kbe+Lpfj!mB-3uI29?wJGrk%Rh^BfCBBF3M!_ye?DUgx} z-FxB+)B=G7aBC3af`Q=0;%jIN0{$SGv6_JtxzxB(M?DS7zcj~`Lsv=A%zw4 z1=+VNEm96aO@bA<1KP}dd^%Jdo45+p_gb!p+zfk}FTH|*H8?>x!ypb~URmBr#Q#0; z7DzDh0#OOb?_1R3xH;P7cH%S#toQr5lkPDMD<^^uzu>45P}u!&oAsFX2x@sYIm{7T1ik742&22=okl1HEDKF_%=WRu z_?l*b8J?B(3YWuFgKerUu+jJo$HsL{o;C*^qp)bjrjR_nhjuy*-3#R3;!l%mOt0xy zT9>8_^7jWYEJCRj!S(0u!N?7gxK^|BmTX}&{d~Twi|8cVUa=u4iRGbHqr0#lGBquy z6;wY47q0g5!qx9qA(|(2_nJXSq}tDgk2B>l56A=UE!ql5qCw6{i&!VX5fL{w{rhMK)S!B-VZDk93Pvt^9txF=^bI+C%q4>!>e<|C(@Gjh%4FQ z6YP-2F=~`d8e$%mGi2Cy)}cHBihIP29y*g>yD~_xu%&56ehtdxekwYT%L)T&D5i8e z*gv2DDZ$c?aw26764C%F=|d%;IXy~>Yi}6Yoz9*m?A113kE$XD*GZ6bX&rgB{1`o;`x+cCx>*b$u^ganooR{9-GKqE0zG>UJJeXrrc zUs5!(4u6eM>7Q5>hzi+{pcx@s{PfFqS=G^=Rz2n$2B@8~>XkB0CDR*1?|?uFMxeFo1I*m-=a&5bY^z>ldKTe(1y6ais}%o+)z zGF`gWXx^bpA_JA>3|+bwcrgq``qY9jGX4Q7t6eh|+hSiROmf4*5uSW@2^zYrmqn-Q?<&$fJWyNDHy{zAq~YnpSSCQ zq!N<}_qylZ$~7FZatXO>P5#Or%yYfKaOLA0_Q_4X@=KHK75jryyFfYK;&SK`xE#8` zj~Uyd0Mc_!o7bXn6qlysOFDmfN!YVJzY-cxbAgtZrmsct z+$2-MFJl2vcp|KO=XZkPR>oe)zC6gYW@J+bN#RP|HxNUq`tL=XpFN_w3i=kchI{HM zB-2sRmuFXKk1z^*zQVYO^72|&i)qZ5W)WlXC(zq37hKJX@9di7xw0j|k5TFoO?L;=@HjHM|_;g!$6%zChX)(^&eChJLF`Ap*67d84hk7iY zafo#(YF_xxQJ!R)9lCS{>5tT&Sxly(%+ekci70$W2+V0S5Nx?!eRb9SQ>M;^cC%NY z9)(@ALllG7^(o`>IIV1elop24frp&oDw~mxZebWpm$_W$6ZA#@6C>*kRfX)tS1s`= zhP^#ec2BvjzZ2IEWMN=)<>(+yi>WWe_5~M3b{~Kqaj^X^h)~c zg;xXf_M5Jm!9KuZBTeED!(cD-16;7gP6VAS4qDx7|IkW*1?wYLYd5KWU=#8q20 z%`CPZwj1Eo#N)?z!TTnk`tIQc{13Pi5wEC%gk3F(H#}vLuZK1DTh~&~>x4#|!XAC3 z(k+5^{6{O@Au`0My%R|d4bxjMOJunVr*P|S8($Q?5gJdWdz80I;I=Owv9{{IRx;Fn zF5_KWa8VI0S81a|;rquj=X>0VZ-x79e7@5UgSng2@^QzgHgI3WT>8p?4v_8xyhi60 z^jqE;4TH)7*kcS`d~3zHVwN@Qrd@rzBbmGNuae*G!Ys}L!T^HMp6}Nv z=Z0Q{9(9HtcO+~?w;rcGXgQ3g%`SyiJ_kEn4#-rP#6DyuOyJ)LE+))}jpSizh7|lfg2@cXjeq_mI zN92JOlNQiPrv!)rX%L$mefi1ZbbY_vo6lSJu1FJGrmlPv4=p0i{*f`$)nMHb+yORN zT}&w7!Stq93*?S0CfTTfbrT6)1lf^By__0bUdL z)w#t`r;z`wKw(hYbC1wCKb$XkeXO!UoG0Y+UqMVUY#^JcF<_tI^o~f31iT$^(mv( z-xOeT(KR!8kXl57BIgzG>sIlJu*|;(Iq+sia%i+XNIUf01IK4;8fz#a| z084FyKH%p$xqn4RJs@sQNNdin2seJm2>kDA!tP*NM>BYk~3=`@mnG9$Yt5e(Y;$$Qo0;B-B4PVVD{} z4jVMR>%ANdc~_fM3uvK#m&))eh1qU0sk=v#E=|=Kx$`3)5u;ZPrW_{B zQVXV-RYFQUoQsCV!>=9gmC`z@myZeha#tg<;Y;QE3p~9;bJQ7q)|4K1OeyOP4+6hY zaQRVUXGH1sZNkU~W%fsgiTnL_!m*EKQ>)ZT6}hw2q!)U-#KD#;BzER+-t)yTAgixZ zI$+_pqoPPl-vQPS;k(lz&fh2`?QMIX(?W_ims!+sp_f__L%HOfNlgEpF}G_C$0GYe zN_VDA{&>N)#u@`c-&DNgU6?YF#Z_)<4>_wmyGigXQQpaW^G+4>fqZ;9Oc>7a$nIj_ zv3&C*8R|^G4ENUX&w!=i%gcy6WMhw7o$t3O%rYPp{g2bJ%c#xksGc22I zX&WDKC-~Zqhc@TIP}}tfcOOZBj3uq0_ppd7%z?J@FipY(w9EG^P+#IstCBKs(f4=| z&IM<@dnJIoP#HE^9(+h|Kn&!^@;f(5SV4zK;j0O;Eu`!v z(Nym1t;|lCGkdx5UTD4P0qwevET2Mmk?Q*0PqD9o_fI!gW?F6KrbWv+%Z{hBGEtRNa&`J)z)cn*o9`GVa*ES zXu|&WA*p!ql%c~_AZ%jcgp9-b&YG+8)RxU`k&c@?)_a;edg^w=K#5+wy@=99Lhtms zx1^GDA3H#1=Q(lvS(4+Mt_X3l@p=6wGr=8eD=Tv!?n4`)fmhFbYozI^frbghzYe@iOrX|p%clpdvSAZyLjwQp_MjD;q=)_>95nI&GUZ=&u1w(4^botM!7CoSMN3T5OWZn% z#8SC^g*IixbJDUpqJj`Z$45!WK2fvxl*mwTcNx!ddY)(v^YY6t zl}+x?oCh+ROe*|ZPz;IIRF-^s`Lcd4UqjNL=WDpiTVS^^f>KibixTpCHu!eZzVfz_ zk+mjX>V2gtCTJLp0?J#C+?XS@ZeYZOJ;2x%gC4h-+ojmbfq(^Ja|`qkDM~LljnJ!I zYo!9A!dO~=xBy?se>6h9Z_AlDk(=*W^|x@qLk{iT2n+^lB}pcUkfUf*{iZM$UTULN z*(NZ@$Yeo#5d$|z*n{+yYh;BG^}70#(D?q~8^^%(YGkHp<42CwyCOsWsvyPp?=ydK_=R$+?)jAzv)rTxrZejYwy zezZcM;m`u>EoP0S!rjc}j?^qWUBmI)qJ<>;Fr>MCOwdd5Qp_zhIrP|eGS6glsUyh@ z>!UD$>b>aC>(@c)GX=!ISI+;op!68$C9Y8U)kMN7*vETvjShZ;ecukj-eW2ao=rCm zeIdXS59>533XXlDCKX$AZ@?HNotI;v0dlbonK!moPinU0j7Q?tQfcYV; zL5S<-vbd&rfxGoM8h*DNS{sHh*EbS{3;qDGTO=n|Rf?~~udI$+um-+Qs}#d_950AT|5m+^?YWC_jR)PP)|srEG}!2EKF z*aCR><<`S@T8o8APLC{Q)6+$~QwU_<_q7tZhjgS3qz0KT*CGSY^>*EPMMauv!s?>g zbq!nN)CHtX2WhX^E34Sz7LdEUnGj<5hMT%nU0GE2SA#f|W0?j_NMja}dFbVR+;7CX0pa&FzEFBEp|764pR-9|8>(9~k4B>QHUi$WvWW zgG9zBcxgZQhk7>d8)400?pD^8Hg4;2W@&=TSb6r)K%K^8;NCP9y*=RATW4PI;p+{rkXU7Ld z-HBUgfJjR%ajH2hZ#CA59#T+3@#l_bOcY(ZkSdFQ;`omNaiv?@E!(HAA&J{(%I%qt z6yB#a)CT{`+{yC-jXGD4YEp7(CIs z#sT6vOpT_(RDKn?6V&@Md2=3wlmi4?EfJh<$qJ}(1a-j0RQ6yycgV3`IfX=u(aCZx zP$y?|-Ju5VASZu@JpPZWvUtKr4U%;$XI0*olcxaW5$K^$AaeCC&Nyrf?U9doT~}z= zDga<~qqdYtb)AgKA0t9#pF(jzgv~geElR}3m{P{Gl5#NWE&Lhv)@30&-5nqPOE}wC zu-%co820%dSpNQZI&Z!!j_<~g)1$~|16OUbzX>uG>Ops9OuyFWr2HvXya2hmBc+8S zSl?9mUw5uv>k`l~UkPQ~s0&I%woM`hpI{Y*AkIy$9HwS3>F*1X+(_U)#YOv5c6gct z!NWXp6U-NZV+&f3_S#KT&sKmEf?#OLx)~`E9ulWSEn!TQj-Sf=z7Y(!mCEUEql%}1 znAb+zJw@Oj3@NJC@$srgROZ!bRc5E1p?0{5vzgJ7f5S%eIsykhB&NQAIl07kc~P5$ zmSSPFy(hA4iAo7{`QS1#>23TUXULf&BWRTCCrsACV2SxWo@^aG?Tq8KfRL`GFbfCn z_hG6j#id$@83vbJW6!p67?Ij9`IH9$0ar*g&Fs&cI1Gm~6ZGOuZ?r)Hz86tG2ei2> zW4RGL!22ToiFb&@rdgnSr<&`jDO~Z5@Yu?WBNZN8 z4BL`FX){v@+u*Z-;22j<0UNi`KdA-w-Mn3affozP`y(>Ff=m^PShm(d(G!O$D(nNB zBW@lz@Mom+K0yb^P=(#&y}|7MB^YvQfcw6aYY`+^ng`#Ug)YE0SioivfI_J{(O}XL z6)ncav{NK&?D3)r`1!vCzuR&x_DvmxF?({O?b@6=b}@1k3Jc0?o*^&>)tR*nPk`_( z;EA+)i=Z=<#$>zDr7Agze{!RVzmEf$;b22(u?84J!A9DxM^{;~_22xs!m9!Q)~zXobZiB>hhf)a zqu1u0X$e1Ep=A~i$tfP7dTPk}9|1uh^stKK;xkH3Dk%q7vfqB5W$~!#$WzD$ROS)T z(sdXObE9Ro=6yPWEC*^o!QZw6-V-Z-vDy(~cOG;4Dc#5;6ymO5^No7pysQ?Kq?;=L zadXL(Np!obXQ@gFq#6Y&Y|#?kA?7au)a8F?3q;Ozx{HYxtgPKS)r39_Iy6Am z!34zv+{qRcTGIlx&rN_|Pl8QpX}?!PqFz|W7A4GlH^-Wg>mk8zSrK7zU33&kxcwaI zE+KSP$B zZmEK|5&&}nC|ka|8(#10nSS9LsM|gFYmFdbTZ!i+_Zs91hMno?>2jRrpL+{_u{aWJ zB@V96@@<&bE3#dAuDkdOI|5W#LzG0A`k`@OfhtBH>y|`w7Q8bA)qoh8-}{?!|0?TD(uY-eRz{^;2#UZJ>d}H6=`6}l8OfRL&35hcUkNP zq`|YLf^KXa8&%?)vt_L;uS~GTpeW+VF~iMH8(tgfw%~XxIkvhGw>{}=fM@NsDkgN} z31(+QnCI<@xcXlhn~@sA>~45+RLj?V2SLzT`y@2KkqD0?71ZKyaHY_Fq`n-)!!ThuxWC zaW%3ly~UzXY~tVRCw@Ow=+v_su)R9Psd`;CmssA9$?)~O)eVF1;Fy9blaX#98?s#t z#s~gE{cYUH3#1!)zC+ZxyBlhDkUbM_1d5h^xtF#?c)Z>_-wAI%FTA4&4bNp-=S`S0 zE95Hj2wvp;TmBiOtdE;!_Gp(e6-Z{y3vXsAaNaVX!>5|ArDB@6z&-W)#_GfCVDlv^6fKvJ`K5IM$1oT5!=(L9&6 zgm_uuT9_91qqG>C3M7=e$vbo5`nL)pFvWSK>=&`@M(Y&JP6nz5YFDVv2Dvzwqmtyd z7(Mdh95yPi#?n6^5}A}pG+=#&+ur86fHrrpDiu59mm+hd$nzUv94~HGdluqP4U78q zl84jH9$i_!lu@)Yw0m_S+qi4RGS&okxp8Wb-rf2ILS;gOUVJexB*J+LXgW4a+>!q4 zTG(H|K zZO(wzS4j6EMK93YwqDLmyG({3AY4(n75!|#c&WFC!lDrDwc8EH_G?eK#4`-jDexYrwRA^L)=G$yo434KS>sQUOm^DvEHUTV`^m2?=UM&Q40t=BcL;mri#(P^OvM%c-?4WlnJQT44WDVNMVS zn<>1|u2t|qcwAEavj*gm98~#t;fDnJJf?DU#)8dGE7O`T(H=QHuN6$e)!@{hu++1p zI80Pwn(jKn+nn4JaGf3w;~l@iT(AN=0dkDye%`PfZXhoYi|$z7w;P~_Zwj4CH!~xe z&*D1}lW<@F^w)g-s6Mm$kyqO2 zV%y+RnfC>2@;$ZZHM}Ck_+ZK)FYPnOGmP7mE(HWL`DyNsh`|;_`0Zun!vBlCmV_5G zd<0OZeW1SQ2D-s_feN$D5a}Pe3fWrPp?e2xGsXx$K;x`Q_sgN;e)aftk!^86X|YW` zs>+OR*Un=8h9BIvSgj{W4@M5=`3c1T0YV#e1hgle_f#kLHlfDEVS{u(e?iZUpQxv3 zZnD&oz0oRuiv*7~rcE8<&)C|X5r-vSWZCK%)gvO*pJ%(H*q-0`yNCxm5qCR$C%9_K z9EO0D+=#ClBk~0vgcuHRtO~K+e;#sF9*eGiLvbA!ydmRuRJ zDhQswKF|3Z;aOVG<#j3@X7+!j^Vu`xo$4)mViY{Zk%Il(o9m6M;p3bTEjdSm4VY^H z{u-pHhosZTInuPmM_&wj4eH)%S2t{(=`H+^-H>nd9B~iGD6^4Ynj=_TDebj1L2&HW zXiwD@d?(m+GkAr@?~&v-54je6i}jHUknsT3M=G;}L_Wwx9D~EH`u7U{N{{Yv{BF+B z#eZ*5`2=jC9A6|j%!6HAy$pC&^zcJ(?Zp73@ zKQN)B^au&0wsidji08SVUuuhLXFm&-#g)9q0Mqlx_fOnwM)E%e-4KZ^5X4~f?r@^O z#?bj-t%EEVaoiXZ-^Q`up)sl-!|gC(-wOQuE8&kIFi-fUVCf396I~OjmGY^m8=q^T zePe>1QP`}2KU2)+O(;^bY-iZD1@Lvt_TkZs8cs?zi00X+dl`R#%`1D!UBH;^QB~Fu zPaWyO9)Ai6IJSI#^)5Z9<(^j$f;T+v{y5ci3CM`f0Wx|EY&C>CDD5qI^`>s{JzU3` zc7okgh!^%PGHsMHAp1u3BoJSsJB}m%CfhmKhF6_q8%L~JKDP6m1EqU*&s;1Rd;_RV z%_9yn9H5RbJnV$pv=Q0X%%;)50Hwzoh4mCTQ>X-FiQ!dXG*ud6j22Ys53WdDtH`3Q z%1&WQAM16ix!!ZsyKO=r2gqrDSGq5tR3H++a6oD!*xm3nH}9IYTU4pJA6A7mnbqhY zf1txeKJzm^Otza~C(gg1J&A?;rAjB+A+;^ZZoN7JM!Xy%K(OR`+*HA%Mcpg@OoaeS zm>2Fe^g-j*5H-7%Cf_KC=E)HJJLF14L_u#45Y}j>3W@nj2qn}RMD$3{^U}}^>qoI! zhb1?8pZGUnPaVFDSvsbggBzUo6T}Be82FoW0)BA^Ta)lt6q4EK^hj4TjJIoz$|5?o z#!h=wZ8G7eDWdstwM5WnA2y?fHMhPKmCW6ii1;Rrc^C23oDv45Wp{TLPObRFuJb1VKdPv5!;3I6mtqXfkI z+@R;*#qk1g@X)DCSTAX~Wn4GuObB2uI`&bvLOV)F=N^=DkK4DS5I=JTdiW#yr3RqB zG=}8#K;p@BIGm_R(!>MvCwa@Jp7R>4fw^Ft!8hXB%l>tMddFdi-j;flPD)eDX{Rck zr(CFp)c1^QAi2?!ZA6Slc|V_e%TLtJUUU~B- zwF+0}!mmQt!FR6qULSNxIANOgBQR$ozP4(tMQ0SI_Z0a5svL|{gj5W+VpYROWZXlY z-EKjr^D=FX^Hq*x=D3Y;ffebEZDQ}9(3bTG?+|f1ir_RP6)(FvHiuDCz-xW_mMVo-WjvFT&S=`7Ny2XRMp+@`77q zw%xkpztXO$_(U)~_h<)`#)CgG_O(%lnTJ}=w#s}=H(G~Zd%7*wZbW1t2dDBu?`h@N z>fFo=UkrQpL>5%o#Lf;WKsF#j`MlU4YY}g9s-F>x?U+^Xm=vwbj(Da;`36etuxD0# zdGH=ZIv=jN?AN1xe9IzO@*ANmITI&WGv|S@-&ia! zZIKc>p%KO9BI8~nhb;EY>|l5T`yN=J~ zC{|)}Pe=Z#2b$pwzrC5{*R>{8)e(^uDRwY7LbrQ;ha;p3$qF&{mnFfRO#DOEzKjJ? zuR`O&{{da^OpgsiYHS`?mM@_Xt%CJ2;@C+wa~5jKmYzp%F&nB-s8!lJhDgQ{!uYRs|@%IK?H$|xh|5wk6Q z{Ir#gm9~MMYRJBTJZ34lvWY*70*F`t1AyK}3(8x9kHL`h`l&NPvJWe&!V9+*N5C@+ zLofZ4Fa9NBf;vj}s|ts2O+x&c#~eEe6UB=0Ln#UQSGqp)#k}1%#!>1mT8<|cUvRG` z1B6{O>@xjF96;>h9q?4SHia`4adp^ zB*4d)qMq3$`m)ooON5Q6;`f>akU!{rJn;fpvHLlf4DLBSmKZ9{kj{Zl%P{1&{=Rs8GxKV!Ca#67P0C=xqfJW9KOEM=Uazs^gEl3XZB zI0+>wb{Rj=gn`une3x@%Z8i2Wr0aG3`5no$n=)zA!0tue-RY?1iy;2ARMF6g$`yk>6b@&-izuQP(Pl_%`jc5MUS(_3HMpGsj(QS&CQ~~`dxSHiZPb*p=@Gk*W)CJ)x z9)sGD)w|Mt=BPHiX&*JGrQfKrx6eWENs?JA4}Hk}vfjZHRwhfFH2*{SphV!;Xi@K9 z{2!mFJ+11KhKYv*6&UvsOq4;3qlrV$-l<{@)&2?MQZwcOUQNuxb#cVU0=GCZEmH*E z!L{Jy{_6IQ(aMFCg}2%1t@e-(6DCPL}(DsbwG-d_2Q zvy8*6SHizG#L+cjr{{$|e%$r8ug2nu)OZ0HQVx2MS(i4^{s!kN9sNSsNMQI+AR)~8 z+$ws>^jhUTpdQSvG(U4I0m?k z1v=9fA;@C|D9@ASg3#kgS-1|{)UKCoX#wcXe6cMsV;>tl<5PT8poJTyjvN3DO&ZL! zjkk@Uu8$qrE|^+vXNButuZ~Of$AaPaBWSRz3Wn^>e(i{|VP0Ge13Uf~TDd)<{JK5z zM^;v&M{B9(QZ$=LAo7h0ol22eP%vNByIx@L86`u(q22lNBPfD=92X$rM-71IdSO4&GL`-?bS|U z(Gskl*mJb#Al5t{gnPq#hICa4A*l?>dp##Vf#n`nNSzDVA(3yO{pLqgHEf#{R2gr# z!GYCo(W*e%dZ3$5$ESCIO@*hBt9VucNu5?&Y;rsHu8o%`6XY+XhQ#+4RGIz{@q%;2 z`XuM1R_aIezs;nHC1L-cYBZ@r)t!onzw3@I_nq3mKDhC;@elPOOP5{vE;ziw#315N z+jwy1k88`z9!?@?k^D9gm^v_yEtGzYg6F?w>{s3Whg$pxz*G=+6ubb9Wj_Ne^8ck( z6*~Z2dJo6%3v(pGeUfA6SGwyiajQ3g3sx)#Sji){Sv8k^NR8*QUfi!ty`meYzqIOa4e5##Sp)3mIbaGK>Uo50iD!98^<|IE#xH|I!mvasKc+YMb=02Y z5ZL6@N(a7jX^tRta~Y(m(IX(;r*%ak8-2erCUp(>sKZPYbA#Y_q7JVJ~rowN?5)IEU8?eq#};O;o{9KUoC8opZ^39 z@y+faC%s^rQyUw!1;IK7Dpm^u&W4L|JNoSU(1*<&(Rwa1A&~~fMi)=QYv4$iUs+i? zY-tDg@hAu^B=&IUH#7BM>j$VducODF8~(d1q|}}Eis;8cKb{=>y~>n?ZAPrM%l@xdg`Et1%}1EUnRski`Jr2fKJ!#d3P&*f>wIw^{gO6Y z86TB6>5WV&p25RuJ$8NEUtH^d@c*>sj)6>-TyeYg_?oy96Sf{^!mS<*C0vXbg$JQ_ zF;orzT2R!gZs15G+~$s`Urq~|v}@lEOqYhRC|u*UtaZ4-47@>sMyP%;=3{jWB&kf= za#C(^k9{D->t}ACB|Iw!8uFb|v9#0^QPq`TR_OZkrg5W4!HKa&ju+A$dHb%)kxkuQ z9nZOr6Xtl)DmpkXh;XMdWUH<@g?5`}F1l`n2b2a5QLD1y@Q{z_0~Gom)LGgb#w75>`Os$~AsxjwZxM&R1t~p*D%WTt>U02-CMTZjSiY(!plYezm9d1id6Q23$kV0RB=EzY zL>B%Mkc?;k-yZdOFyPocpaAr|HB{VXQXneYNf5LihJk4smC9@X`V4GFN(r|DnQJ^5nV-q-sTMAC@I9jcDbrfd{{WYx%e#j zadmlc#I;S)N=Ak*)79;PXsiqj8faeVr*vFiX8H|fGANg+;-OR7EDzXOQ@pG<&*qT5 z?i!_|Bxae<3=fVCa)OEuba3qA!WbyMq=Bu)D;B_Ut(ypT7*Zr?sNf0h;IrnSH+n3; zwk5$7b_)k*l*0}<40FWhy`7xW>&bJ@!fptLdm-$kefQ=4oSXtb+I8i^1j>&U9x4Z_TOq~kgKN^7+0Yz zYh!0hxfAF_pSU3;6SB)gzDpylE5W_OM)d`reFug)&{I2D8^ovCu{2M2%S0>_=`8rg z+V;QzXehTd=L&2qd7UWrWyQx(a1g`SpY2?x9qjiR{+@1*d~d=E_(*7?__^JRO6-k7 ziMwJ{5>s4z#-!u3?1WZYmeGD^(*4WciZ=4WvF6`I`W1>Y=tHf7v0OE2vn|WR%nsf? zO=##xy{icf7&ra%Qmu)1h-*hQh`P}tbil*e`?Tc~w6R1M?G`ukqj|*W`<84?aI1s| zYcRvvfG1s_mhrr>>MT@8()5Fxh$g&6;WfGANve3apwFD1sd>ysk5a_V=?ex2A=!({ ztOTPlcZ&dH^jF>G=}9FokjAq>WWRo8V<6fuXA%^Q>pMn);*HONFicV#D5D2K3lTa^ zJxhEz^3c(cKfVK3z@iUm;oBAQ=^I83IhQ*IRf19#lVzz2FMQvCjWc<{BexM^1gq-b zkhY&#gLb_>JhPHAx3sd>GE!{YQ)QNp4X7F6-pIYlJNKqGxPw^IU@}6!L+;=`GTwq| ze2CrI+usJ+%`LKfA;2Hyj?vd(Dz_64mNIlGu)FCxC4p;*e}QwLXM1_$4O{Ef<-96_ z@!eAFFXV|m#6AQlTaTBVo2DK;vj*np7GasF&VXNT2f@~~DmCe-=_ES81vxhO9F)z3 zB9G;e%$1On7VsHas2S+MblO1r5^<8e)H?<+dx$rGVD2G; zOQEMs2Zn%Ww-FxOACB*S+z9c2BKpIRO0FL8kFTYb+ygULy7boE4wV5ANRX~McD zC%g{K_0j%So>wjmUq+kh|t>a5uHH~F#T~U50P^?x3%#Xcxk#X zWota+2F9hx#HFz`(Rx`p(M7vRwz43NDqf{rIlo5~zu!%{O2+N zLIVaeR4$c`VFLFxQ?Tz5XKNa>uJWl>|)eFrq( zZoLeBHVFuJdGEi6J;(jXKI=hT{6a9ZbmYZCw_I;Se?aSffsyvFl`rOU+F`H#Yo%p9 z!~CPzXIE6{S9!y*I?P)<-6g)MCtd)A&07v7!7HA0GNj;F2EyEpo)@~)dN`iGgYm%L zxCIYlhwj^=b^Rtob5m$ddxe**(Vd|EC$Goc}2@FC~o^tNa;^>==zm@noOrc#3|jp5Sg_kz#Dgz^GwxN! z@#0lefiJ->Z}}|kb9{a;Hx)hFM-H-yN8}49b}=b}&Ykleu=YUyP&r0BH{Wa=0qs~l zFasGGxal~3Gjty6KbpR^PNr}2Fka{LWeI&xr+kWV;1TpjqcWWYyVZ?mi{Ak$8P5b^uBVK>ex$!$e=4^2*uY?m!2fsLXDU3z+wR4JvI7vhynqZ!N&`yg=QMn+d?dL@H=60G7EIC$;l$fWmi0LxF0Ylo*o46<#8&m>}eI;Ip6u~6*WZu zJK7$$I;_0%YpI~U3`D^lp1C3)auw`U8Gm6O8&1)Llo}E%OMYdV8yb(z4UG=FV{W|E za&CEpprNyv^Sr&pz*-#SRY`4cL&x7BfqW~}!=1R6A<-;gPOhRydkoCE57gDOlLo~> z@_08=BM%G@) zSU3-La$#l5T<1Vc=1rddV%RH8IbZcZj{O>Nfw%30+q;5wvUfz@+i!$-Gz};mm?~Y~ z#9M!EV#i+_?kpzG&z^&&_+}mx7eRA=cWIwrM?o(N>k!RYHh0f%_YTF4kJLgWL;LDt z{uyj(Eee|WH?ha4P6Ut^w7!u8u7P=E{Wut$j+%-$3bd^46o{>;uRfE7P}n%wba1?a zJJsZHpT1mRM>Gh2kW&?8oKmlBPL1P=u`IVQeyp&Ss+o&WbrGVT3s);+QRAtY7e zV4QX$k$aNJRg~ej1)qW@2OIhytZFlHDFvIV7Lh7*oNaNZRaIx9Mer$eAo7)?OMvK= zYi16nu$^E!=Xi$NRSw8lqIbT?G%(j^{mk_xPXAG1NiP7Zso7H7WINCs`vNGM!F}$L zp83zQY!UNo9|#`-j{LJhZ!?Ct4T1m$E>$OU$9a6~s06LnUlGaGX1((ZVuSB26DyJ@ zi#3>cP9wbCShy8r?&WoYYMcip(AP_{u9jP-VZuvL(3oLpLfUmedY=XplyfcRU%-az z!+)qR8QQ17NEV)ZU^3z(zInqb6;Qp#b82~(-mz-!bKXwi;DBs=`AgfgEy@L|ogXVz z*4=BNhdn6v=hS~M@8f|Pl2bs}DvrRaC#Tle_7&9e4>n$B2DMDlgIx2TLaZct?pxH| zY6V1IgJ_03EmcWY&UHUtKwb-@EKHtah|NXJ+y55J^>-l;flDa{XMo4R(OAM@9N$P75$7?tP zA8{90W0s3Ynw0l?*GRZ6&gDKTYCb5J6C#AS!&-3V93Q8w*44#0AZW@$Jy#67{L3Ql zCP!%L=6jE!N-Q<~@`@0ux3*W~H5*lQO%-Jo*F3_Gv;{99TTdZ3`inxJYRmb&OLLQT zxZ7``mhB6aBf>v^N{1Gy-K9_`#Z#Mqx2s=ag-`4vul6VL>`@Rmmi+rsIjfxfUo${E7lIzNXwYC{lYxb-uVra9H}x|5(%wkP?rPqr zvi#;7XW=hDm_E9b*`l^!bP{FK?v|6Ad@Z<$yjKH+Wf-6!Y z@cTRixflN+B%GTfcEnoNAtNox$f-Q7;u5H$Zkif|xZq^7VXImP3upBQVev1t zN30AE5NP!vNMlhcYQ5)%moqSO*(ROx6^)$7&&@8|a${@&#P~4TV;=Z5lp``~k$oi; z$6!6p*<4^8FrEwi!d0=dGi$+)lo@Z1{zUb(cIYpifMpqnIE_v)Id$;sh1X-~shKE^ zTbur)hTUoN|4~xY1usmHMGaLA=oWgY3}P;h0jH^}kBzct}eRJoz&GFN&DhIzuPAj7aowO?1Qo}wfdR^>`)y1cgX^9u}Bub9AJHmkzi z8m0=}mi^oX%=Z{l%!GoP?49kBZ< zGMd;$$@#^n`9D|O&=t=|NnX+B3$A{C0oxxX(Saj+zn z_40QkD@`mERLxO^deG?uaHEqLd%Bfar|>4r^N?A%>M6<{g6HaVPaB2m4yoPH#R`5X zhlT3j)m(v~{0V$fTixl!ZtjkAJ2jwQWE*7?JGPeW~BlzW{s4=!e-(Q97=!8Vo8ea_1Ohf+|l0sN>nD(43ZN5EoKZH9p3e=gZu!Rsg z$*gH)nI)AMS^#wX_o7w)wP*=T<5p}!s+>E)UB-3X>D&pVoeyBNoj?r!=5#r_v8W}^ zu+l91-|#}K#MWn=@VDfjs9@cuZj&Ni}1%yo$5aIW|!ua#I7f(B9v*kk00f`)Y+9Q@XFW2To)Z;p^UH$D;AT=|k&^n2_-b{DIfDU}Nebrm1v2%~()DDT$6y z_?OD!=$E8dv%^Y_d$pI#7V&X9-PR?_ah$)Ps$DZpV7k$0JPl>*zPU(tQ; zhS?oP;tkckepOE7z!|bW&sgoA!AJoVy}-24S)&Gs8RId=sg;L6;ilJBe)laax!m?SbeWkhFFT$L)+PYeoTU_wC(Chvwd|HWYNOWVVx&yaoj9-fyi485wJ%h4re&7fj*(&}3Rr(q)ph**>>sm?QS;H$h8?R2(rGQh~~;!!?}oUC9aYPR5s4#9yRDTodU=n|e#)3Ku(H zDa|?LOzJv98hcQ4%7z-xp)w`q2EFLZxI>7Wmh8g!=C5Fou54FN3q@JL!m!_CZ+TsE|T^w4^-v-YH?p}Bc9q1yhJ7<13x_zyowc_iyjkt{9Wt~ z^L2H%9xJE1yZ$M5i`Fc2JWNU>#BowC7T?2)Da~VMl{JX_NbAPI>&&ighV|28ltRo$cm%@NFuIF) zLZ8(8w?qglG!2^v`K0x~b5%=M7*wrda`tMetF~K0^aglmQXAW{_N=D;q^R}$vFaN> z0m>oYOW^P3h`xKe+S3zs6GCPR{XHi3nzYkiKIeoFljVfcGSff-O{8Vr1SU?DPoI3G-070SzJO7HsLE)O+MZQubAyE%T&JykbUbxP^UAL zV10R{J)J)(w!=qT)OjfyMvoXQRUMC~+iStB{F6)Un7AHYu&O@lUuU zs-s@rkhj|A!m!!}XgEYJb7hOq(IRHlNttvwI97Njdd$m40@PmB-e6jU;g1r;?t#u6 z)7`%e0MBp8{taBfz^Y&lFX+&%3mL-HCq z+hLl3_n6GZ)~=2%OsMrn(pE+Es1!-oWpK)I9fQ5?3U%-(TokYm*0~eFbZn=fnpZ=@ z+aMbv2bY}G^iIDl-yM*d=5+-(9|D98_4P8Z!)s%%D3x{}J>pip1Iw6b`)pJ-R+icH zzF-&?n`-iSYx;3>{qOv9$Z4C4a=+A1IJ*^fpKFgJ``B zm{$Xgd1;~G-y;lN{q2Kn4G%?@dhfd2`5MUQ)*f|b;Q=@*eNi|@=+AUNK(596FA7h> z@e2h>DX_*#uTLMtLO5+M(S?N$Z(cAWUlH8@s${*{ticsR+FwzzJ!FFg>F_9OSdUrs!OG~Ox6~!i*c;_7a5hHbEqT`ho4`}1d zCF1@r{WW<5mn<2l1bEfLZ@IEm`eC&&I=4(a2RZN-st7SEeXND-UL~-cX(s3pwO{5k zR{!HKg+J@3%6^qG>AMiFC;gkAF#0tSP6mM7h(?08H(GQ&{;7v5{HkX($;4*C!|&R_ zC`ed*9Tf5m7W0slQYStOYcUilAx9jC<0Zje8Y}0B*6(R+@dwaW;moP$9L-y!5ydf( zw2||z_W*Vl5?byOJ%<<$7ghH%&+xAK1WptAJ4AV^0!#I*SX?fSIJb{ei+`htU#CFJ9@y)s21vB8(clmX zJO>dkgrR(sSUqTRm@)b@S!)7-Vq_Es;J%#m8N1F&EHROK!=~atbd`eS{tc|@fy(Ez zdyE{@36FgebUJO*+cUj-*wGx2sZR8=j&Y&bmFBmo|2e@fB6!_YhwKN|Ki2tUWxebgUA2I3k6Me?1@SsjH#}JOyw~ZhuBK3YNF@-ST?w4H(F&-cz9+`fmp4sV} zb}asKbV}*UZ@-}Ot=?a(Ju=G&FEKsm)UMY#b?_`a^tRK|Nmuj>JGck-ax}MKDnRy{ z^6H~yxx+RnR6D}pk5*ufdHMT3+VvUkYi97nP;b@Jxq#!hh!uEPqCUAC;VI;Mt3EVo z89E$VyVT~dqPv%#uhSn>HfLWR+@gM*waUXvA}Z1)eNh5_9}~)k+EgqsJZam|tmb=2 z-8u3&=?QMVb_)Z9yXQt({DV>k(P?5Sn6CoI4Y24>$$zOdpDdg8Gf0;|8b9+C$$HPOT(1^k-oKflNRp+@ zWGh}cM_IS$GB?dLq#NigRb?OA_B;CHEw*8xuI`WbkTDjCifEPxLTTmNk3lNc@P@GA zqmmFfIXvsGJJ16GM#CjZg3@;G6-}#6X9;0pO>4JspTz~X(qAw8%mL>NkDsJZP=W~g z%$9Tx{sU*SOJ4B=c-}om_i?LXh5ui8cs?0py^?xB<)b$53Okr?8rgV&Mr{AaNu&nMXI-_F6VZDuCt40|vL*#bGAlmmTZ10B3 zOltYB2hSM!TU={A)O!n6tBVx`=!6za_LF#^6_Xi=Qcx$N>}bo1(^RsFg3|WpUTutt zS+qDc`hnJ)^T^_N%mu;CPWss3J}hbf<1bODAeyiq3e~gq=R<7~xO!q!9RIpU$gifj z2w4tQT=N+r-|%=-P>vgm6A<>Fq4tKCdiS2C7V64W;c1OXfQx+njf-SEpq}cL25K_w zo3nKbd)e)Qywc;)wmzShbLd(4oQZObLZ~Xae%imoXDu+_hnx;;Fh{w6aJ5r&i|M@B z4Jlq}10F&2`J>(#Ac;oVnSVJcT}t1|yE*Uo-a-Mpf!6ex;rUTf+m-Z#5;51SD=aU- zds!pD`y!Bcmaz=7BbJ$j&(jBpmW#)fpmuLdnc7Y&IqU?tw)cuk=PSif!|wGbzVJ)e zcUQiUFjzcTq`@^0xtQ{^V1(##ei8SYP zR<9e@Q$Bl8^i2W<*{L@;GXYKt2Tsa?+~Tg#2l@Egq} z?}`GA(%>+0+KNAnaknY7VB4WDf7_RCzvI+R=D%b|x|WJf@0ZI99(8e8ZER6PRx&kl zZ(gkSb8nb`7rSQOY`b-$0W$|39s$gdrf2=pyl*~R_kej^(c1N$xqE1Uu6C-C`G{Gq z|GuDiN#RxI&F}nY^l$DvThRDlB&qT0Bn7(UC4JtQHfc^}a<%X!c zzt1y5_9}-B6M!+sp=k9mzj>-|rFqGURfbfsE#oIGC{pUWWA!A+x@}?87jW|sJts`+G@2ugM{z=7|#bPeFnX6 z5#sZZdXi)t+<)DY$Fx3>j28Z0qiN}F&mUu4u$Z%k#;w{XHjt3c&Wc-b+wJw$r1Cu$ z@L%kgTXP~x2Dxz6u^yPWjc;XT!yn`2sW2-y|Rq=G2_Ngh>8TF$R z=Y%!c=SS=0Q044v;R^z7%OR(Jv_nbn7c9yYDO}AAk3~hNr}-JBd%Jdl6f?^|D{FlU za44&hQ`VV9xsnOb%}KI2vo^KRN#oB5O{nx8Zu>kDw@i#NzoS<*29bY^PQCa+Zdehi zo!tlFRW*kHfC+Vw|3nzMDhOEWAU6$23gO}pZV%t!o&`hu9d^x?#2A@fIU*-s6F>fB zEY^$MXKSKkFM95^7FRdJ1ChdCT#Jp;KS0Hq&AAaRda-$0!=Xx|03=L3SE% zFt9}f(WQ%uCr0Hht@}t#u3~S!Y8CCKDBjRTJpP?Hp2?(@EO62ZWTSh%frvZD#E0#| zu@>^Kk6BzU?KaV3yLz|E7WZ7n7u1!%HI66L;Q_v?#fy$~bZRd}gnnYipEH}}1C{ zy5FFfLasl89}D>A8OV<{<+k#QL4LrSFs8G3S>~~*E@hdf&d~Y8kg%&hDn!!7zHj?K&X&s4k^SZ)Qp;4k611UenP$sWYvLN zu;(WRMuhuqtgyny{EmNRW2M2;Hef|~$`+Yv0C?Ezi=D+m`BidikOr7dA8P^7{d)j& zf3Hx1>7rKt@>@C|&E4*S(X$0gIx_UCXtyzHLxl3ZG&0!Lx`beNoLJLgBb&C&n&4#LOVJ| z(!R@b&+Sdq-0s>AZfsEorTIyxw=x;|&^*1E^Kt1Upp?Nx)Xs0sPa(flGHk>>^fK>^ z9GE&9kFFA>3>UUs`%H~6MV1?B1j^2kl=a6#iu-CUH+#xFf;4s>1MuZe;R``0M6}-T z-!lO*_GjT)_^yd4Nvt}jUnOZ86t1M{fMG)E89946loTf;YQHv*swn0;n!xU;?1vBR zE)DblL|qTP`0Y@{VNu{SRk`85d$52aN8FEa+C(>D#99G|*6hG?NRzXX1S;R<~M|aSgqwWc@ZCT=&%?k2ko@Qb=ee z3AU(c(1~)eI4ph7D@qoAYu$%-WJ}vUF17Ii$c!1pMYhcZI5Zk$=GEb&g#J_W@m z4ij~$LzXe#DBlORk{0>t59aViAQ4~rwos~J#FGU)k#X2W*Hc$5u0Mo68X0na>PBff z9+v^B=<5c)o~O(PD$7q()UwMnMri>iOg$jF*u+M$*5cySUOK>#V@0rN88Q3|vZvV+ zq89z2fob{d?~$S)aK#4w6;i)W@T-`!iv_6>%9$6SZBKNDFCbq&5sYU;46l_z2oKdY z>?NP;{kl`fREKtHCJ7rkUr4nqifiwC)$QKQ6a?TJ$1L)|sC%iPu{???3G4%ow=TJ( zt}!kl3w9Ky)l+GVqkrLf6?uGpNxL^z<`POqp3Cc>1Ug|6Qxa47QY+Dt?ucHMe^X;+ zaPA-#+4@Qm>N;h+W?i{x(XZC{J5di$IZ4txrt|dVbQR8v#u+T@B8MQ~0 zaUOns+!#bsp!{DDyD>+l?ax8O>-YP%-Wj9t$td(Wx~p_Ng7=KGWxY9@Z9MVq@69LpUwo={?3W5>NeAFRHN!grS0r?j zA4gOM@+D;5gP&lkIGnvg8jD)0K-Yr0gtYYs)Yc=Q|JhCZ$zUPvN<`U0c$rS$mKLLr zo3FcyDH(kkb~|Bfb4MR50N=-rsh;0SnT`I={^3hL5#$CPEA*Lk|6&h0RHg^q4RC7! zN$-dhF8TqnJwL)L(ZN3<#j&(@2ypTgd8>a@5$(Lv?3AmDY0p0luRr@Tm%p3ZeouCb zw>_1xCR4Xn(EV&5Y1~b07~j}ZhaS8IMep=+9~3xR<;NO6_r}CXQM-QH)A)y~=k-V2 zsvNqXRQ8+EW}4`o&F72kQ4&{%x4{`Fr1lilvMz#vNmosbW!;Dd1`6viz+z_Y7R#8L z;Z_jK+7+a@W}UoE7|R+0-)KwDF6x?w&NsxRjORb4+VZ^T5bpUE92t#ngSvwI29&ua zk4i(}yaoqf$;))5uomIa)=d>>9G1oID(>X`Ctlh<+mV*0pl4Oy?CUJpt*cu)R_G4% zvaS)g?z5>%lf;wB&1$Id5ov3{ato%1^X`4&C04a@1g#URczXrzvXdMP1$jgX=MOx zkaPp6S3gd4NqaN^tgu+r^d}QJfEE)L)hZwH_Mh+X2?@-9kvr zNi&$D8kc`Y2B7r;5Qx)E%DSU-Ek08(vj^&Jo}IkyYP041^_sStxJ`M5Fs}ey zl8TzWBqnP+uO}BwVZGQOJ|w!uE;p@76H&1Z#);zvhA`V=hiY4BSITV|K5p3r*N6TuRkX&hX1*7jXTD7@Q5J(iBoI^=Q>Y(AD zgj=c)KpthF#^bh1<0wu`!gW@(uq1I5#yy zjqnTF|2=Mi4*QoovyS9izW|&tK#C7=`M}cZz|zpkw)!kL+o_YSJv74$YErodiCi~% zCgi=9dLAY)Y}#`H$Eq==P*2ktg?hO9nr=dGhlDnt?j}B7`e9`aBOkuecFlu|27OnP zf$yYs_CrQ=2?f1UT#o4ksjW1}vv zUINO^kN?d={Pn1s6s7J%aPX}%pG5x$p6r*~F5SRY5CHR^GdpBEzw|MbDvN1) z^GLyF*R4m$8LCJmyrHw-onpnXy#Qz`YcB!a+?dgcFy> z5_{$RInUY^8uh)aQw!&yqn3xnE+AyhlX;M!9yCq-q(Sn}z)dV8RZ-xd&&hY^O@OSg zDiF%YVND|9Z3w9;D(34TpQ4HGL`N;llfGA%+N^=B*Un7Ml0v`Ea_}UV4{@H+8@ER1 z6Z;}+K^k9yH>bP&UBST)czaW2>;(@sc#NThXaAJNZ2?Ish)ZHgj9Xys3T417-^)F? z#_+FqS*rRoM-`_AS=ha$mBy9l32P71eVbQhUNjP4CSQyI){NW>PXuFs42|zIojL(? z(V{xU)1Cvnt@ZjQ_cgNqq{+VBp~5ysU5@a8S^ws4K@GZ< zf~u?+z%S&mJQl^SUrB3=wN%QP&4oOzuw2Tkgpd>rj>eZm9z7ssvc#P!sa97T+3qb9 zAlh$xb^+wbxYm+Xd?Cwu69^M8if#`JG4anh%`4?lY_T!pQ_Ihrdz0br@tRw&~nE9T2kPUcr>*A1tTrY zWyH>oiHMCbmrG8e3bzR>wK8Ni@!VbDJw;`|3un{Z& zLGqXBAn~b{{ihEf(nZ;WBnT#99Om56oM=wY%D-~*vfp8IxzB{IM?WYGE719oN}(O> z=s%UMon&2pGlxA;o;bDFo7-MD@M_`rN7WA=)zLGoy!ajcGHtV~cdxYk0{+QOtl+dV zL|%kzzJ_dlkdu$ix?$mixhDDK{P=SP2Zxd8#{z03>@x=*)R`%?GD$|L~|i z_J4%}@{>aYb3g3-Yo!A9(yf0l^S=Nr`lFB9>RP>M1L-i6m1*MVuR0b^&D>R*+Ix*H z+Xe$HHviv}a*U~e?md_$?%j%yU!X`nwkDPHwe7i&J@M(XU(jB)0PO8(`N#7g+ZxA+ zeMz}c*%>l9MvC-OMf$33_F5nYa3fyv!jty|N)k&Yol2u&B$E+tN7Rfqsx-+8S6j(E`RS_BX-j|=;YuNa+fK~W=FwzP8b?$zdC5EL3 zNWVeXn3zvdrHh#Rp_5dh79M#v8~N{(IDxY2v!NT%{P7zycxHfY+N^vZ=~x>~B;My~ z$fX@2XYYiR)&_T$Yguz_`#U&M>tw{--qo9O6_9zUfma;}gsjae%)P)rtgUgf78m7k zzes6%!~LV4I(wM3yFb7!hyXS$qx(qzOf?BwqqR{a^i7RZg z_}zbFu%4clnP57(HYMJ#jUsvZnmy*AEI6nx8TayA&IQb}miO@{m#4Ta95UuI?lk|E zKkANCre2{gV~oUr(@s@_d5?!#vP6d* zDAn-ElHtM#&sTIKBFlzcqmX${in)RDj~1j1)s5Ks?vJNDwtD9t4K!Zk?Co-1ym8P0 zo%7!F>pq}+ucT3ZZC*b$+}w)Wm=z67c8pJigZ1Y*w;=35ol|sP`bUP&y4N=D?UG9+S8K%Ct`Y&LS%Ni5= z7jIRcN3JdG^*T!6q7M=3`)cQ9Ny{x`#>pbJ>=e*b+9ojNV9x9t)@ojSQ+X5X4d3d6!Q!$W$$B-Msx4y-)RIvcJZxw9cfo$Usk3GI80PBkgxkYr-74OP zbz&4V>wpo0cF0OTORe*GdS-XP%#zuyK%Z+tVgc+ zZJH%22&r4G`4$_he6(2I@n5@$0Nfv=il@oR;P)8DuTU$uqo^`sgp#LfuIiLZrk;0t zSaF@ges7Hs`A0GGwyS5YN~;Ycu31~n{4mQ_|F)4vdz1tL+8fXH$e7v{-TZf$S}YlP zSR#0_CHhoudcR+K1APYGZLR{w}_?O zbyIXz(r`$!J#+s@>Kz5Ee+Y#UD4&%}#GDFdoFq!8dMp62juf=phP0EDvJ#Mt7wqV; zp9SL~sCL$g&{m-6QQHUtp|`;pQ5EZqm~+kfi;5kK1#@!UOw-?iv0a&mG=Z}PQf@}b zj{Zb!zUQxW@w@+N3*o->eDa=r3@N2QH~u&&6{KkCv`2Y{UCgVR!z`!tbL^+au4z)=Z1XcwvGq zIE#t28(uFx8DIuh(7z4stmKssH%Ys(4!5n~CY~Foc1JJSxwDK)Eo)5eHJ6NbJ;HjZ z{XWdSIHGv`W*Fhis1WMD`;~er@QlJAw7ZKkW0;-xV}8RNHR`rOpYn`8oW3BOO1+C81oRfR?l(11#!`)4du z#U}h)V3k}kEdM|V$~)Y|S+jMQ0V~~PiP)u{)@DO?S6tIDnYHH`zPCTaI@iCYv!5G2 z)jaZFKntPpD$HMJ-j>4D*WzT;Rq2i@86c`W+}APoEAfOO4D8qJ-}}|^%N$fVr!?1^ zhM{sp8GFgd^(CP%c(YvPb>1^iwbm|CEX_mdi^Q-hyNKZDqbao3Ro>i!)?ML;>DsI8 z>->sU2a84wE$Bfe) zxWf-kD5?SdOeUe5QtMO%zYB!9F?(|b8tn&9f|QfSUOl||cWhy%alNbg9MTyC2y)*+ z99^B)7ywRq{01j7qsy14rge~&vIvD&xw*MmEbpT~?4q%A=49#zF_gwgNr9`EAZ*B=F5K2zJdKUE_Xl#Ra2?*1~dl ztAD>LtpD8t4JBFq9n^a>%zOTunJJy$(zmSUq<}J{dHdT%h{jCf3a295g0R*8F%u32GX}z@+LZfffggHNQIq zp)X&h-Ev>E)cNzMA+X@yLVL)bs)NTq1+fqmvQskNHKlMfLANty6kAxgP3#n=RB%hX zuOv5mL45uhXS7i|o7VqC(5i}cN?8DLg<^DDLR)7V(cxaYb#j+f;SEL+xYDLCvIg6M z_7sZVZKamJ_IiAS;Rq#NIkblL1}R(_Yt$_5ezVzc;5lKk9JQJY7+)w5MYDv83 z?RnOie|vf&bAbj*p-(o*OF#yoF}Pokf_Kx?z=f2@QOunqqqPdgGoTa_FE1> zY{p)%OScKvGzqnBihx=jTswN=lp*YHw!+oZL#X*?s>rog=i#zXUp?wB(ih^Z_1H%c z@A%x74WtkfZ2FPMbXFEYAJ5lI4x+wS;oDsvI%scT#<$vz6g&UOxr^B z4kcNbY?`26zcx_W!eG9I=Xk{Td1X6=TAw=3^i|JmNA19A^OT2x4ETo(=9ol^qQA87 z?}r2zpj23hoDD{S%9(V`uUz=kkxL)j{FobYW6RPB4B?>>*i?Z7an4x@O7_^o1F@63U9W)fC^H~)vH<}E3G0D`joW! z+W&}Ec;bUNg&lwexS}+zCGKzJ1>OjuxX8wSFhbZB$I0oTSEoAlCdS$pT;&|91?%_ZNblGR$%li45mGIUq*hkG*g~hP5gT zx@Wt1JG7nd;KxL^Xb_5e;jdKOXaanok_iZa#)B-d5cH{53Qy>CcQ8da>%Ts!lo#Y0 z+ASS#(?jJ}<~cI`%&^$e8=nbNrbojQheuhGn)C1*`qhN|4!09=oRG&@(ex5&(f`*7 z*yR!m@z55&mo!7pTomf-#?R93($_6Fr9kYyUI2$oVt&CPl+90M+u&GiuIIu8HLFa* zC|`hzZ!CA^($)zB-Mo!EWD?rJ4Wtoc)nyNBSOBF#P%fM?ZqUEF%V2D3Y$X$&xy$?Q zIs-yh{0gfw+o6pKghU3y^oz$Gp211aFHPl`61Vu3c|k1RMZvBqUTddiYV4T&@X%H_XlyfXI_MmWq0B zr<9cIM2S^#yIeCCH1)JbrrYDs!_`c9u-P}a}9pu~ccT|&tXYYBn@ja>z-28Wrc zH_CXyxM8%ud3P>WblHY{X_MmSM!0tKXLPZ_#Y{VbuD=hB(oMHU=GdG3c&KYT-f|F) z%nl1b%+VA!_yKn{F8ua8;V0ed26PmvTF#Up#I5>w>`r|D^;T)+81Rh%vc5B>v=y^y;60XQ3N5|i5#;B^T0@eC3iE!$HZ@+30ild z+LevGY=kKT6HHG9O$&Kcq(pUe6@Mfoc8v)D%g35}V6dE5WkcvbWcYt=lZTRfsM2^8 zm`_Qa4>#?32{6%T=CJzBl%JAIc2&cBBAKKrqn>?{KQ*7Y#ct#l>UYjcx;>&t)iR)Y z{ww+!#2vR`q+;hM|DTLk%A^gH7##sD*k10zAJMhtj|!L5%XKQz7Q6hHpK^|c{|5pK zJpKNpNtNEc)GB@>-;-r}UPiZGC@>;0>aq+TEVTuEkTmPAQVm3JQ`rYy-C975M7R5D zZYW&BMx@^t zw9wNn@lV4mXB_NFm(6`~C{-=VNK{n{K?&DD=9`g=c&}1LSJl5`R0MB8Uu(2gVYd9| zg~F7hz4mqk3P&peXgRs=_|%t`JJdS{Nsgj(!Fj52&bQNV&11%v3qVY>364hA*(n_LitE#Sc{d~1Z`liZbLHQ9x@!(31+n<-pKnz(2WNDDuEzB zy~oaNOLW}IxwzEOQyjvU+997{fOEGWgUaNKs*$u{`R`Sq1QHV^lqL94O_)oRiseDV zmtoeO>`f0F4<`R5{Rv<`m#z2w|NVH@tn=f($kI_4cx;^MAqUuS2G@Wt8AFRJm@Fxy zKMr1VbWaO@olNPhkT$k*lM&zKdU2lgBoOI6F%D@FX}N%k=sGMofai&iMNMYVM$b5d zujHln^e3{CoeQ>KuI8`kMnuGU9`A4XOAM1#E?BvaCf~Nw6sU03&lPM_3#OQCH=l3k zYMmhI1pKuMNf*}9q6q!?x`%c_y zf1ygex2CfJh>gIaPeL{q|rGdb2{K-kmKJo?bPHKcs6I--OydEWR z5`9PCT!P%{$4Xe0oGuGkrVu$$0n2R(|HR$(a+%o4aX+kD|7>z<%En;H??VyN!IU!Y zwSv^vkt>S=wzlgi<$XC#eC2^a^vkW+jgn_&WTL`*&qRfIs*ot`J&G-+w`c_dUX*M{P$R*{Tqbax4`$<8<+ujK_rYE zST&fdn~bh#B?a4KM(KVE0~;2(X`>ZtPAgQ5rmGi~uERS{6Ie*qJ(*4SJ(j7LVtM3e z+SN$j4 z`CM?hoTtQky6kh!p7AOt2JhBLI+M%DCxuxfFYTg|ky5IO#lXY$~fM>G*$A1 zzp3=uo^Zi((A zx4V-Blzze$zc_OE;EY$6*vz6(su1HA$QyYU9{=6 zkUL;`Jn~54J9Wtj4%j4<>X6n33D=cQF1v8sZ zaQ-f+FEI454tm9o?nt*P_&3}j2MMP8uRF?Wzffb(xEyYrUz#R5pY7C&$fA3THb`dJ zf|Jn3tQgY`{_PP!CK6|ckBgwa%yB!zS&g@|qZB^)afyqWEaB)~9GorTx^OxqP&~BE z|2a$jl|(+W9$vg!e%hoBb|93N%*&M1=NCsisZz%8KAXH^X?}_a4=>_1@N=am>i#F` zO$e&@xO7rXbH`bqIPoxMqZs{{Gc&;(H8l6$p4Kxc)`>y~pT}$fmODf|=UuDdoPuta z@0k`6xiZu0nCX`JnH6^WjYB@SdVx>i52*O7!axd8oe)YLH008=E8N@RhCfvPnEhXw zqVZb_KAbjq#|Y+%n)5^iC=MVK$MujJVolxfDl&Ee0dv?nVGT1(0|B_$0M*25z zLXpy04w3m%=Af((m>9L)L$0rXP))t0Gvo`%^%FXY!~d}}yS78*2Wr13vVE{amayHS zo%I2eB~f_pM51?1c0QNk7EUbUz6eL5W_AJR=E-`cn~TpF<%`TQ-RjyEYtU;~fO>8L zgSbPTI^V%@Ugq4o1n=0AuAx8{T4Z)cBaD-xR~FojXbYH<>cgR_+xYo{%R^{It#&ur zUMdz_N@n|jD?K;*wG51oHw5VYsQb@S^ z2E5~nk2=MA;SDg_>!uzWh-Xrc(Ap>IqA^?CGPrNB-oC&a&%+mC>^O@LY-30w%0Un+ z#c_G^=|%W8yQ>MUxOZAGy*c#zxgRA5lb;c#7&IuxuoW;Pgz10El3-zl&JhT`1ttw| z76gqphv!(eaXgG}yoEXu7x5=+OC%G>Xwkr-6+s%d?Rm>Ea! z%QM%hVXkrY(q9%cX?8jrsSMTV!GCd+&5s~#d&Ld8&*oI-FPfqEX}F7mtVEgcmdl7; ziT%DZ^&S*}NW=SN|wwG*IlK4eU(}21p&wbuxVn*_u;x!NTBDp zl|?pl2lM9o`&T>0br#xf6uyaNFIIRYHib471K)q)T92Tw*_`))*xRZ)!P_Z4zju^{ zf6?il@Rd@!VhXcJbx`4((8IWmA9?88y(iV38Z%CR9k^p6OZ*hWM`w3fUs@Nbg_+ns zIi!UXyNXDWvODZeEO)-G7r3k?+Hda#8Qzv=)+63Ht2Z?><+2O#y&Uhv!pt&SUnX}) zTCGviI*Ik%s|j>VPSi=ueXyj5)fJJ@qZ}Lpp@;ujX+5f4^~^ZI;nn3G?`e@nFU~*8 zLe7o5%P_rY=&h_8cZwkvVU_zfElQWQdk?FB0-5E7=_yWj)X|ZuZg&r2vgMMsL1adq z%WXGKI=CEj&gK`vy_|&aeZksn?{W}}4Z^U5kIclbG4A^n_oXqvgdSTX=>bJ!kN-Jw zou^Iv55-zoMGoj*899$S`BG01PFy`f$Zq9G7X>L!_^jTcoq&@;X4pK<#=kDcYc$-h$ zbPiIjyn9{A%bb1mem;~zY#)=AECzmoAFswk@OFAaOhCw#GXyx(-FuJSN!AJJ2txa6FkH61o>xs?oY)ZJj8FB0&v)kIv#Y^GVWjyJ~^cX!`6 zt8y>l8!lDO@jm6edtY!nw$kK%OJJrv=cry-l{9ot*VqO{;}nl@pi1(Zz~j8*(_>u6 zblk!iZ9c?=X<(X8GI~?7EVKKmV$C$>lMR-_34VQV+G28Fl$E))#9p@jF^I9b<5<&$ zVR$D*4@*G*@GQAWg*RuHeCY(@GLNJ`0tlZLvKx9sg}awpe|NmY zIuagfIYZi=vZ%t?r_o1Ss=}pntE@p)l7rW!S>bRCZd!8^MO$=H{_AtMP%*ufRTWEvp=IXu+Mwxd`@luV76ij9 zjru^)L;yeUn)pHtv5q<@ZT($ioQ1gfni=?<#R8!)OlX^eu?#cHj#Zd}#h|PM=uLHz zqbKJDzwScl9GmK?_f)%6eLxY|QJLgmE@yvKsb-N|T7%N-1GK!zsj=PgZ3 zaNT9nF_fbRobHYWLLg!Jr@$a%`z*aip65LOb_}oHYol^r?~Ub*i?u7_HxClv5pd5l zeAyN%cz2+vw@rq9b5;~vad=OY_jRcDL2b+*xjps|o(04yiuG=pW=rr^fB|OM)amwK z>o5iTfLB!g!ieMY_!*u&pOTCFNLL*}HRzUnxJ8l3ic^fpU1Y3d8JlnIzxmkIXJ6lP zShwU?XxzyOWc7Bc^yQ63H!9I8b+9D25Qw&l>>F)V?||tj19{=WVoAo-bwaC_E=)`3 zcY_2>>YD4k`^`$V3l=}PRtCo0c&>{9%K%#xOYwPn$MQ4}5A}Eo)aYO=q844~U5`_r zg2l`@ihXFYkj2=o>}_*>uIrdOW^qPRvLsj2^g&>;X`#MqTv>h%NYIc&1Gz<10$jyj zS>wE!ovhdtIa0Y?`pcr6R|y^QreZg3ckPxvau{8_5fvP;a@S5P|Mr7OZiH{vouN$_ zS%2`(sCy(*h36SGjCm4R5vI7LqT|~iASQFgY%}NBB<6P(_ZDWAavS(Ce>H|Ju5(_? za$j&G%CAFH?{O=oQza2q?A7c!Sc+!-S5+^-<-iZK zOuAZ|j3B!q3IZiA8?R{HC0(2PIQz)zvu6QjC{Ms%25MMXehRZMptC#D%u|N> z%`i)(YvyB9y)pS;=Jo|Vh$3Ax|Gr4=3rlR4T;D zAqhKcd!A(suI@hLKDeEeYKk1tiTW4m6GCOx?iVFc8er`N$Fit&EP(#1<1P`pnBQ2R zK`d4!;lvos!5+!fJd$8?vQP5J@`e%9$qZ^Au@A4s4$WNFZn zwOa`A4F?S88KKLhRR=Fdvr?j9B+U9$dF9W6F{V!{qwu5b9Z^~#9GViE5KhMKH=jd= z2Em2oTGB>2rj#O`C~Q$$9V0tmQ*z?|D75PyF(`2cvI8~kysgi9ASuA=Vo7dOj=+K) z|9m*+KF&{uAN=}v_3E5E`6dkz%Oz12W_-+xss`nlHZ&6*jfLVj!wh!XinpHNh~2Jh zL?2HlDsxbPutKJ=f{N9drk`y6x|JEW|0a=_#1h}bd=YMB67Sv?8Ym^1Cr4eKcG->N zcb>gN@fYVw1=+v%_tBKG)%H$*(%kl#()FfLm7)w1zmr27zgcyxQ8!_A$Ts)Yw_#=AoG?=$2b%xO~xr=KtcDH{=6pqSg3P6oUEu!WgT`n4rQ zp&E7Fk|FV*FoC?5OAovA;R+08AQW5$L3Ox~gRD2AybaA$8hFdeMg28+L~e44JbypS zhX9xGG0dTLZ-+H^dkqXv3-g|_=#cYSZ|EegGwByOHwsHJI_mVG>?qe2%Ie{oUR5(tk48Mc>(^ z^ls4EVBxSAmN%-Ap7%~uMb2Yh9p)IamJPJ3QaZvIXOVLL%VyEw7s z6T>9%Xcc;^cy_Ce{QPY*b>_pP1%Z0T%G>|$_V!pkW2s(P^@=xH(&~$vy;*0Kju8f| zuea;5M$8VEG0^v_PxMnTix7=371Itp2#Xh*E#dVr^z{x1VNf2=|sy=+ZL#6ld}<)Jml42HbEuoOj9Hf?LBfly%)sDZQr z;@=#X0#I^xaWx3QzKjxX!vur{;ENAZU|BR`jl{}aPsB;4H4xE}oG{&F}u;VuY+7Xom{nQZg0uOAjP{UO3Brs}=cXiq985p*M0C@j7z$_pq<76gm`G&EYJ zAyx$8WDT^6ogUQs5kb>)5iZhOFB3D?bFnp!7z8ouHB)QMv$z`y@}Xpdz_#&&#a)0f zojyw}a2?m2nhR`+zQUDguLA-01yJNd)_o|Cw;c%C*@myo9SPa6Wp>dGItAtMHxUls zU|^$LL!=}!IOTS>1xw!{cQ zFb)M^o%s4ACJhZ5O|~`JDicDIKH^Z{Ky1Ep&{ipGn>yJ+v`-|8UIG#WCg0RE1y(ZL zk2utSXB`A`KZM*PpY-y77CCe%J_8BWtdGW45B+H{z%ziN`F-3=roKuLqS`eHuYNdz zVgC#{mIOWD68U~2AODZs|4!skA^uD;QMLM5_fgeYWsjx`B4#^2k&nN(z&=c>v|i`I zrr2jP7Yc#|z+T-J|9=~q`#+2vs{Wr%22L;~{9i3E>TaBX_%?4pkq@PQ5}Wq^6T^*e u`TeWR6%jGu+zc7Y{I`+0{}wqj1_b53E3+8iS(OffpRffHAq_#ooPPq)&DX>L literal 0 HcmV?d00001 diff --git a/testsuite/render/baselines/gl/texture_luminance_alpha.png b/testsuite/render/baselines/gl/texture_luminance_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..77e137d6b6fe1a7e3f589dbfc483efaa3866d23a GIT binary patch literal 62324 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 JUUgxn{ueCJMAHBO literal 0 HcmV?d00001 diff --git a/testsuite/render/baselines/gl/texture_rgb.png b/testsuite/render/baselines/gl/texture_rgb.png new file mode 100644 index 0000000000000000000000000000000000000000..12cd03ca848a9528b65258961c88eb44bac5c65a GIT binary patch literal 102361 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

ADZg;f`f-`wh$$oQ8P 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%0Dy=TF!%}bb* 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®ccI&PI}%sw3)G_M%xKm6~&z*xY+H5 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 HLE`@c|67PQ literal 0 HcmV?d00001 diff --git a/testsuite/render/scenes/material_emissive.iv b/testsuite/render/scenes/material_emissive.iv new file mode 100644 index 0000000000..bc3180be4a --- /dev/null +++ b/testsuite/render/scenes/material_emissive.iv @@ -0,0 +1,36 @@ +#Inventor V2.1 ascii + +Separator { + PerspectiveCamera { + position 0 0 5 + heightAngle 0.785398 + nearDistance 0.1 + farDistance 10 + } + LightModel { model PHONG } + DirectionalLight { + direction 0 0 -1 + color 1 1 1 + intensity 1 + } + Separator { + Translation { translation -1 0 0 } + Material { + ambientColor 0 0 0 + diffuseColor 0 0 0 + emissiveColor 0.75 0.05 0.02 + specularColor 0 0 0 + } + Sphere { radius 0.85 } + } + Separator { + Translation { translation 1 0 0 } + Material { + ambientColor 0 0 0 + diffuseColor 0.55 0.55 0.55 + emissiveColor 0 0 0 + specularColor 0 0 0 + } + Sphere { radius 0.85 } + } +} diff --git a/testsuite/render/scenes/point_spot_lights_basic.iv b/testsuite/render/scenes/point_spot_lights_basic.iv new file mode 100644 index 0000000000..5099714d7a --- /dev/null +++ b/testsuite/render/scenes/point_spot_lights_basic.iv @@ -0,0 +1,31 @@ +#Inventor V2.1 ascii + +Separator { + PerspectiveCamera { + position 0 0 5.5 + heightAngle 0.7 + nearDistance 0.1 + farDistance 20 + } + LightModel { model PHONG } + PointLight { + location 2 1.5 3 + color 1 0.18 0.05 + intensity 0.9 + } + SpotLight { + location -2 1.5 3 + direction 0.5 -0.4 -1 + color 0.1 0.3 1 + intensity 1 + cutOffAngle 0.9 + dropOffRate 0.35 + } + Material { + ambientColor 0 0 0 + diffuseColor 0.65 0.65 0.65 + specularColor 0.25 0.25 0.25 + shininess 0.35 + } + Sphere { radius 1.25 } +} diff --git a/testsuite/render/scenes/texture_luminance_alpha.iv b/testsuite/render/scenes/texture_luminance_alpha.iv new file mode 100644 index 0000000000..6a2c7a014d --- /dev/null +++ b/testsuite/render/scenes/texture_luminance_alpha.iv @@ -0,0 +1,19 @@ +#Inventor V2.1 ascii + +Separator { + PerspectiveCamera { + position 0 0 5 + heightAngle 0.785398 + nearDistance 0.1 + farDistance 10 + } + LightModel { model BASE_COLOR } + Material { diffuseColor 0.2 0.8 0.35 } + Texture2 { + model MODULATE + image 2 2 2 + 0x66ff 0xccff + 0x99aa 0xeeaa + } + Cube { } +} diff --git a/testsuite/render/scenes/texture_rgb.iv b/testsuite/render/scenes/texture_rgb.iv new file mode 100644 index 0000000000..6765d4efee --- /dev/null +++ b/testsuite/render/scenes/texture_rgb.iv @@ -0,0 +1,19 @@ +#Inventor V2.1 ascii + +Separator { + PerspectiveCamera { + position 0 0 5 + heightAngle 0.785398 + nearDistance 0.1 + farDistance 10 + } + LightModel { model BASE_COLOR } + Material { diffuseColor 1 1 1 } + Texture2 { + model MODULATE + image 2 2 3 + 0x00e63b3b 0x003b6ee6 + 0x003be66e 0x00e6c93b + } + Cube { } +} diff --git a/testsuite/render/scenes/transparent_overlap.iv b/testsuite/render/scenes/transparent_overlap.iv new file mode 100644 index 0000000000..477e44b3ea --- /dev/null +++ b/testsuite/render/scenes/transparent_overlap.iv @@ -0,0 +1,32 @@ +#Inventor V2.1 ascii + +Separator { + PerspectiveCamera { + position 0 0 6 + heightAngle 0.785398 + nearDistance 0.1 + farDistance 10 + } + LightModel { model BASE_COLOR } + DepthBuffer { test FALSE } + Separator { + Material { + diffuseColor 0.9 0.15 0.1 + transparency 0.35 + } + Coordinate3 { + point [ -1.1 -1 0, 0.3 -1 0, 0.3 1 0, -1.1 1 0 ] + } + FaceSet { numVertices 4 } + } + Separator { + Material { + diffuseColor 0.1 0.25 0.9 + transparency 0.35 + } + Coordinate3 { + point [ -0.3 -1 0, 1.1 -1 0, 1.1 1 0, -0.3 1 0 ] + } + FaceSet { numVertices 4 } + } +} diff --git a/testsuite/render/scenes/two_lights.iv b/testsuite/render/scenes/two_lights.iv new file mode 100644 index 0000000000..f8bf6478cb --- /dev/null +++ b/testsuite/render/scenes/two_lights.iv @@ -0,0 +1,27 @@ +#Inventor V2.1 ascii + +Separator { + PerspectiveCamera { + position 0 0 5 + heightAngle 0.785398 + nearDistance 0.1 + farDistance 10 + } + LightModel { model PHONG } + DirectionalLight { + direction -1 -1 -1 + color 1 0.55 0.2 + intensity 0.8 + } + DirectionalLight { + direction 1 -0.5 -1 + color 0.2 0.45 1 + intensity 0.7 + } + Material { + ambientColor 0 0 0 + diffuseColor 0.7 0.7 0.7 + specularColor 0 0 0 + } + Sphere { radius 1.25 } +} diff --git a/testsuite/render/specs/material_emissive.yml b/testsuite/render/specs/material_emissive.yml new file mode 100644 index 0000000000..3c5d9f772f --- /dev/null +++ b/testsuite/render/specs/material_emissive.yml @@ -0,0 +1,7 @@ +id: material_emissive +scene: ../scenes/material_emissive.iv + +viewport: + background: [0.03, 0.03, 0.03, 1.0] + +baseline: ../baselines/gl/material_emissive.png diff --git a/testsuite/render/specs/point_spot_lights_basic.yml b/testsuite/render/specs/point_spot_lights_basic.yml new file mode 100644 index 0000000000..6c5f3eb2ba --- /dev/null +++ b/testsuite/render/specs/point_spot_lights_basic.yml @@ -0,0 +1,7 @@ +id: point_spot_lights_basic +scene: ../scenes/point_spot_lights_basic.iv + +viewport: + background: [0.03, 0.03, 0.03, 1.0] + +baseline: ../baselines/gl/point_spot_lights_basic.png diff --git a/testsuite/render/specs/texture_luminance_alpha.yml b/testsuite/render/specs/texture_luminance_alpha.yml new file mode 100644 index 0000000000..6805a91113 --- /dev/null +++ b/testsuite/render/specs/texture_luminance_alpha.yml @@ -0,0 +1,7 @@ +id: texture_luminance_alpha +scene: ../scenes/texture_luminance_alpha.iv + +viewport: + background: [0.5, 0.5, 0.5, 1.0] + +baseline: ../baselines/gl/texture_luminance_alpha.png diff --git a/testsuite/render/specs/texture_rgb.yml b/testsuite/render/specs/texture_rgb.yml new file mode 100644 index 0000000000..5bdce2bbdb --- /dev/null +++ b/testsuite/render/specs/texture_rgb.yml @@ -0,0 +1,7 @@ +id: texture_rgb +scene: ../scenes/texture_rgb.iv + +viewport: + background: [0.5, 0.5, 0.5, 1.0] + +baseline: ../baselines/gl/texture_rgb.png diff --git a/testsuite/render/specs/transparent_overlap.yml b/testsuite/render/specs/transparent_overlap.yml new file mode 100644 index 0000000000..003c1b081f --- /dev/null +++ b/testsuite/render/specs/transparent_overlap.yml @@ -0,0 +1,7 @@ +id: transparent_overlap +scene: ../scenes/transparent_overlap.iv + +viewport: + background: [0.5, 0.5, 0.5, 1.0] + +baseline: ../baselines/gl/transparent_overlap.png diff --git a/testsuite/render/specs/two_lights.yml b/testsuite/render/specs/two_lights.yml new file mode 100644 index 0000000000..8a0e4cd6ef --- /dev/null +++ b/testsuite/render/specs/two_lights.yml @@ -0,0 +1,7 @@ +id: two_lights +scene: ../scenes/two_lights.iv + +viewport: + background: [0.08, 0.08, 0.08, 1.0] + +baseline: ../baselines/gl/two_lights.png diff --git a/testsuite/retained-material-lighting-gl-test.cpp b/testsuite/retained-material-lighting-gl-test.cpp new file mode 100644 index 0000000000..ef9e610eaa --- /dev/null +++ b/testsuite/retained-material-lighting-gl-test.cpp @@ -0,0 +1,576 @@ +#include "rendering/CoinOffscreenGLCanvas.h" +#include "rendering/SoGLRenderBackend.h" +#include "rendering/SoRenderPlan.h" + +#include + +#include +#include +#include +#include +#include + +namespace { + +int skip(const char * reason) +{ + std::cout << "SKIP: " << reason << std::endl; + return 77; +} + +void setEnvironment(const char * name, const char * value) +{ +#ifdef _WIN32 + _putenv_s(name, value); +#else + setenv(name, value, 1); +#endif +} + +struct RenderFixture { + CoinOffscreenGLCanvas canvas; + SoGLRenderBackend backend; + + int initialize() + { + canvas.setWantedSize(SbVec2s(64, 64)); + if (canvas.activateGLContext() == 0) return 77; + SoRenderBackendInitParams init = {}; + if (backend.initialize(init)) return 0; + canvas.deactivateGLContext(); + return 1; + } + + std::vector render(SoDrawList & drawlist, + const SbVec4f & clearColor) + { + SoRenderParams params = {}; + params.viewport = SbViewportRegion(64, 64); + params.viewport.setViewportPixels(SbVec2s(0, 0), SbVec2s(64, 64)); + params.viewMatrix.makeIdentity(); + params.projMatrix.makeIdentity(); + params.clearColor = clearColor; + params.clearDepth = 1.0f; + params.flags = SO_PARAM_CLEAR_WINDOW | SO_PARAM_CLEAR_DEPTH; + SoRenderPlanner planner; + SoRenderPlan plan; + planner.build(drawlist, plan); + backend.render(drawlist, plan, params); + glFinish(); + std::vector pixels(64 * 64 * 4, 0); + canvas.readPixels(pixels.data(), SbVec2s(64, 64), 64, 4); + return pixels; + } + + void shutdown() + { + backend.shutdown(); + canvas.deactivateGLContext(); + } +}; + +const uint32_t quadIndices[] = { 0, 1, 2, 0, 2, 3 }; +const float quadPositions[] = { + -0.8f, -0.8f, 0.0f, 0.8f, -0.8f, 0.0f, + 0.8f, 0.8f, 0.0f, -0.8f, 0.8f, 0.0f +}; +const float halfLeftPositions[] = { + -1.0f, -0.8f, 0.0f, 0.0f, -0.8f, 0.0f, + 0.0f, 0.8f, 0.0f, -1.0f, 0.8f, 0.0f +}; +const float halfRightPositions[] = { + 0.0f, -0.8f, 0.0f, 1.0f, -0.8f, 0.0f, + 1.0f, 0.8f, 0.0f, 0.0f, 0.8f, 0.0f +}; +const float sideFacingPositions[] = { + -0.25f, -0.25f, 0.0f, 0.25f, -0.25f, 0.0f, + 0.25f, 0.25f, 0.0f, -0.25f, 0.25f, 0.0f +}; + +SoRenderCommand baseCommand(const float * positions) +{ + SoRenderCommand command; + command.modelMatrix.makeIdentity(); + command.geometry.topology = SO_TOPOLOGY_TRIANGLES; + command.geometry.vertexCount = 4; + command.geometry.indexCount = 6; + command.geometry.positions = positions; + command.geometry.indices = quadIndices; + command.geometry.vertexStride = sizeof(float) * 3; + command.material.shadingModel = SO_SHADING_UNLIT; + command.state.depth.enabled = TRUE; + command.state.depth.writeEnabled = TRUE; + command.state.depth.func = SO_DEPTH_LEQUAL; + return command; +} + +void enableAlphaBlend(SoRenderCommand & command) +{ + command.state.blend.enabled = TRUE; + command.state.blend.srcRGBFactor = SO_BLEND_FACTOR_SRC_ALPHA; + command.state.blend.dstRGBFactor = SO_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + command.state.blend.srcAlphaFactor = SO_BLEND_FACTOR_ONE; + command.state.blend.dstAlphaFactor = SO_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; +} + +const uint8_t * pixelAt(const std::vector & pixels, int x, int y) +{ + return &pixels[static_cast(y * 64 + x) * 4]; +} + +bool check(bool condition, const char * message) +{ + if (!condition) std::cerr << "FAIL: " << message << std::endl; + return condition; +} + +bool testTextureWrap(RenderFixture & fixture) +{ + const unsigned char pixels[] = { + 255, 0, 0, 255, + 0, 255, 0, 255 + }; + const float texcoords[] = { + 1.25f, 0.5f, 0.0f, 0.0f, 1.25f, 0.5f, 0.0f, 0.0f, + 1.25f, 0.5f, 0.0f, 0.0f, 1.25f, 0.5f, 0.0f, 0.0f + }; + SoDrawList drawlist; + SoRenderCommand command = baseCommand(quadPositions); + command.geometry.texcoords = texcoords; + command.geometry.texcoordStride = sizeof(float) * 4; + command.material.texture.pixels = pixels; + command.material.texture.width = 2; + command.material.texture.height = 1; + command.material.texture.numComponents = 4; + command.material.texture.minFilter = SO_TEXTURE_FILTER_NEAREST; + command.material.texture.magFilter = SO_TEXTURE_FILTER_NEAREST; + command.material.texture.wrapT = SO_TEXTURE_WRAP_CLAMP_TO_EDGE; + + command.material.texture.wrapS = SO_TEXTURE_WRAP_REPEAT; + drawlist.addCommand(command); + std::vector repeated = fixture.render(drawlist, SbVec4f(0, 0, 0, 1)); + drawlist.clear(); + command.material.texture.wrapS = SO_TEXTURE_WRAP_CLAMP_TO_EDGE; + drawlist.addCommand(command); + std::vector clamped = fixture.render(drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * repeatPixel = pixelAt(repeated, 32, 32); + const uint8_t * clampPixel = pixelAt(clamped, 32, 32); + return check(repeatPixel[0] > 200 && repeatPixel[1] < 50 && + clampPixel[1] > 200 && clampPixel[0] < 50, + "retained texture wrap state did not affect sampling"); +} + +bool testTextureAlphaOnce(RenderFixture & fixture) +{ + const unsigned char pixels[] = { 255, 0, 0, 128 }; + const float texcoords[] = { + 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f + }; + SoRenderCommand command = baseCommand(quadPositions); + command.material.diffuse = SbVec4f(1, 1, 1, 0.5f); + command.geometry.texcoords = texcoords; + command.geometry.texcoordStride = sizeof(float) * 4; + command.material.texture.pixels = pixels; + command.material.texture.width = 1; + command.material.texture.height = 1; + command.material.texture.numComponents = 4; + command.material.textureAlphaIncludesOpacity = false; + enableAlphaBlend(command); + SoDrawList drawlist; + drawlist.addCommand(command); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 1, 1)); + const uint8_t * pixel = pixelAt(rendered, 32, 32); + return check(pixel[0] >= 50 && pixel[0] <= 80 && + pixel[2] >= 175 && pixel[2] <= 205, + "texture and material opacity were not composed exactly once"); +} + +bool testTextureModels(RenderFixture & fixture) +{ + const unsigned char pixels[] = { 128, 128, 128, 128 }; + const float texcoords[] = { + 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f + }; + const SoTextureModel models[] = { + SO_TEXTURE_MODEL_MODULATE, SO_TEXTURE_MODEL_DECAL, + SO_TEXTURE_MODEL_BLEND, SO_TEXTURE_MODEL_REPLACE + }; + const uint8_t expected[][3] = { + { 100, 25, 12 }, { 164, 89, 76 }, { 100, 152, 12 }, { 128, 128, 128 } + }; + + for (int i = 0; i < 4; ++i) { + SoRenderCommand command = baseCommand(quadPositions); + command.material.diffuse = SbVec4f(200.0f / 255.0f, + 50.0f / 255.0f, + 25.0f / 255.0f, 1.0f); + command.geometry.texcoords = texcoords; + command.geometry.texcoordStride = sizeof(float) * 4; + command.material.texture.pixels = pixels; + command.material.texture.width = 1; + command.material.texture.height = 1; + command.material.texture.numComponents = 4; + command.material.texture.model = models[i]; + command.material.texture.blendColor = SbVec4f(0, 1, 0, 1); + + SoDrawList drawlist; + drawlist.addCommand(command); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * pixel = pixelAt(rendered, 32, 32); + if (!check(std::abs(static_cast(pixel[0]) - expected[i][0]) < 25 && + std::abs(static_cast(pixel[1]) - expected[i][1]) < 25 && + std::abs(static_cast(pixel[2]) - expected[i][2]) < 25, + "retained texture model semantics were not executed")) { + return false; + } + } + + const float alphaTexcoords[] = { + 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f + }; + auto renderAlphaCase = [&](const unsigned char * data, int components, + SoTextureModel model, float materialAlpha) { + SoRenderCommand command = baseCommand(quadPositions); + command.material.diffuse = SbVec4f(1, 1, 1, materialAlpha); + command.geometry.texcoords = alphaTexcoords; + command.geometry.texcoordStride = sizeof(float) * 4; + command.material.texture.pixels = data; + command.material.texture.width = 1; + command.material.texture.height = 1; + command.material.texture.numComponents = components; + command.material.texture.model = model; + command.material.texture.blendColor = SbVec4f(1, 0, 0, 1); + command.material.texture.minFilter = SO_TEXTURE_FILTER_NEAREST; + command.material.texture.magFilter = SO_TEXTURE_FILTER_NEAREST; + enableAlphaBlend(command); + SoDrawList drawlist; + drawlist.addCommand(command); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 1, 1)); + const uint8_t * pixel = pixelAt(rendered, 32, 32); + return std::array{ pixel[0], pixel[1], pixel[2], pixel[3] }; + }; + auto closeTo = [](uint8_t value, int expected) { + return std::abs(static_cast(value) - expected) < 30; + }; + + const unsigned char rgbRed[] = { 255, 0, 0 }; + const unsigned char rgbaRed[] = { 255, 0, 0, 64 }; + const unsigned char lWhite[] = { 255 }; + const unsigned char laWhite[] = { 255, 64 }; + const unsigned char rgbWhite[] = { 255, 255, 255 }; + const unsigned char rgbaWhite[] = { 255, 255, 255, 64 }; + const auto replaceRGB = renderAlphaCase( + rgbRed, 3, SO_TEXTURE_MODEL_REPLACE, 0.5f); + const auto replaceRGBA = renderAlphaCase( + rgbaRed, 4, SO_TEXTURE_MODEL_REPLACE, 0.5f); + const auto decalRGB = renderAlphaCase( + rgbWhite, 3, SO_TEXTURE_MODEL_DECAL, 0.5f); + const auto decalRGBA = renderAlphaCase( + rgbaWhite, 4, SO_TEXTURE_MODEL_DECAL, 0.5f); + const auto modulateL = renderAlphaCase( + lWhite, 1, SO_TEXTURE_MODEL_MODULATE, 0.5f); + const auto modulateLA = renderAlphaCase( + laWhite, 2, SO_TEXTURE_MODEL_MODULATE, 0.5f); + const auto blendRGB = renderAlphaCase( + rgbWhite, 3, SO_TEXTURE_MODEL_BLEND, 0.5f); + const auto blendRGBA = renderAlphaCase( + rgbaWhite, 4, SO_TEXTURE_MODEL_BLEND, 0.5f); + + if (!check(closeTo(replaceRGB[0], 128) && closeTo(replaceRGB[2], 128) && + closeTo(replaceRGBA[0], 64) && closeTo(replaceRGBA[2], 191), + "REPLACE did not distinguish RGB and RGBA texture alpha")) { + return false; + } + if (!check(closeTo(decalRGB[0], 128) && closeTo(decalRGB[2], 255) && + closeTo(decalRGBA[0], 128) && closeTo(decalRGBA[2], 255), + "DECAL incorrectly used texture alpha for final alpha")) { + return false; + } + if (!check(closeTo(modulateL[0], 128) && + closeTo(modulateLA[0], 32), + "MODULATE did not preserve L versus LA alpha semantics")) { + return false; + } + return check(closeTo(blendRGB[0], 128) && closeTo(blendRGB[2], 128) && + closeTo(blendRGBA[0], 32) && closeTo(blendRGBA[2], 223), + "BLEND did not preserve RGB versus RGBA alpha semantics"); +} + +bool testTexturedLightingComposition(RenderFixture & fixture) +{ + const unsigned char pixels[] = { 255, 255, 255, 255 }; + const float texcoords[] = { + 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f, 0.0f + }; + SoRenderCommand command = baseCommand(quadPositions); + command.material.shadingModel = SO_SHADING_LEGACY_GOURAUD; + command.material.diffuse = SbVec4f(0.8f, 0.8f, 0.8f, 1.0f); + command.material.ambient = SbVec4f(0, 0, 0, 1); + command.material.specular = SbVec4f(0, 0, 0, 1); + command.material.emissive = SbVec4f(0, 0, 0, 1); + command.material.texture.pixels = pixels; + command.material.texture.width = 1; + command.material.texture.height = 1; + command.material.texture.numComponents = 4; + command.geometry.texcoords = texcoords; + command.geometry.texcoordStride = sizeof(float) * 4; + + SoLightingData lighting; + lighting.ambient.setValue(0, 0, 0); + SoLightData directional; + directional.color.setValue(0.25f, 0.25f, 0.25f); + directional.direction.setValue(0, 0, 1); + lighting.lights.push_back(directional); + SoDrawList drawlist; + command.lightingHandle = drawlist.addLightingSetup(lighting); + drawlist.addCommand(command); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * pixel = pixelAt(rendered, 32, 32); + return check(pixel[0] >= 40 && pixel[0] <= 65 && + pixel[1] >= 40 && pixel[1] <= 65 && + pixel[2] >= 40 && pixel[2] <= 65, + "textured geometry bypassed retained lighting"); +} + +bool testEmissiveIsIndependent(RenderFixture & fixture) +{ + SoRenderCommand command = baseCommand(quadPositions); + command.material.shadingModel = SO_SHADING_LEGACY_GOURAUD; + command.material.diffuse = SbVec4f(0.8f, 0.8f, 0.8f, 1.0f); + command.material.ambient = SbVec4f(0, 0, 0, 1); + command.material.specular = SbVec4f(0, 0, 0, 1); + command.material.emissive = SbVec4f(0.2f, 0.2f, 0.2f, 1.0f); + SoLightingData lighting; + lighting.ambient.setValue(0, 0, 0); + SoDrawList drawlist; + command.lightingHandle = drawlist.addLightingSetup(lighting); + drawlist.addCommand(command); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * pixel = pixelAt(rendered, 32, 32); + return check(pixel[0] >= 45 && pixel[0] <= 60 && + pixel[1] >= 45 && pixel[1] <= 60 && + pixel[2] >= 45 && pixel[2] <= 60, + "emissive material was folded into diffuse twice"); +} + +bool testTwoSidedLightingUsesFacing(RenderFixture & fixture) +{ + const float normals[] = { + 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 + }; + SoRenderCommand command = baseCommand(sideFacingPositions); + command.material.shadingModel = SO_SHADING_LEGACY_GOURAUD; + command.material.diffuse = SbVec4f(1, 1, 1, 1); + command.material.ambient = SbVec4f(0, 0, 0, 1); + command.material.specular = SbVec4f(0, 0, 0, 1); + command.material.emissive = SbVec4f(0, 0, 0, 1); + command.material.twoSidedLighting = true; + command.geometry.normals = normals; + command.geometry.normalCount = 4; + command.modelMatrix.setTranslate(SbVec3f(0.5f, 0, 0)); + SoLightingData lighting; + lighting.ambient.setValue(0, 0, 0); + SoLightData directional; + directional.direction.setValue(-1, 0, 0); + lighting.lights.push_back(directional); + SoDrawList drawlist; + command.lightingHandle = drawlist.addLightingSetup(lighting); + drawlist.addCommand(command); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * pixel = pixelAt(rendered, 48, 32); + return check(pixel[0] > 220 && pixel[1] > 220 && pixel[2] > 220, + "two-sided lighting did not use the actual viewer-facing side"); +} + +bool testExecutorLightLimit(RenderFixture & fixture) +{ + SoRenderCommand command = baseCommand(quadPositions); + command.material.shadingModel = SO_SHADING_LEGACY_GOURAUD; + command.material.diffuse = SbVec4f(1, 1, 1, 1); + command.material.ambient = SbVec4f(0, 0, 0, 1); + command.material.specular = SbVec4f(0, 0, 0, 1); + command.material.emissive = SbVec4f(0, 0, 0, 1); + SoLightingData lighting; + lighting.ambient.setValue(0, 0, 0); + lighting.lights.resize(9); + for (int i = 0; i < 8; ++i) { + lighting.lights[static_cast(i)].color.setValue(0, 0, 0); + } + lighting.lights[8].direction.setValue(0, 0, 1); + SoDrawList drawlist; + command.lightingHandle = drawlist.addLightingSetup(lighting); + drawlist.addCommand(command); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * pixel = pixelAt(rendered, 32, 32); + return check(pixel[0] < 10 && pixel[1] < 10 && pixel[2] < 10, + "GL executor uploaded more lights than its declared shader cap"); +} + +bool testTransparentDepthWriteContract(RenderFixture & fixture) +{ + SoRenderCommand command = baseCommand(quadPositions); + command.material.shadingModel = SO_SHADING_UNLIT; + command.material.diffuse = SbVec4f(1, 0, 0, 0.5f); + command.state.depth.writeEnabled = TRUE; + enableAlphaBlend(command); + SoDrawList drawlist; + drawlist.addCommand(command); + fixture.render(drawlist, SbVec4f(0, 0, 0, 1)); + GLboolean depthWrite = GL_FALSE; + glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWrite); + return check(depthWrite == GL_FALSE, + "transparent retained commands unexpectedly wrote depth"); +} + +bool testMaterialTransparency(RenderFixture & fixture) +{ + SoRenderCommand left = baseCommand(halfLeftPositions); + left.material.diffuse = SbVec4f(1, 0, 0, 0.25f); + enableAlphaBlend(left); + SoRenderCommand right = baseCommand(halfRightPositions); + right.material.diffuse = SbVec4f(0, 1, 0, 0.75f); + enableAlphaBlend(right); + SoDrawList drawlist; + drawlist.addCommand(left); + drawlist.addCommand(right); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * leftPixel = pixelAt(rendered, 16, 32); + const uint8_t * rightPixel = pixelAt(rendered, 48, 32); + return check(leftPixel[0] >= 50 && leftPixel[0] <= 80 && + rightPixel[1] >= 175 && rightPixel[1] <= 205, + "per-material transparency was not preserved per command"); +} + +bool testNonUniformScaleLighting(RenderFixture & fixture) +{ + const float normals[] = { + 0.7071067f, 0.0f, 0.7071067f, + 0.7071067f, 0.0f, 0.7071067f, + 0.7071067f, 0.0f, 0.7071067f, + 0.7071067f, 0.0f, 0.7071067f + }; + SoRenderCommand command = baseCommand(quadPositions); + command.material.shadingModel = SO_SHADING_LEGACY_GOURAUD; + command.material.diffuse = SbVec4f(1, 1, 1, 1); + command.material.ambient = SbVec4f(0, 0, 0, 1); + command.material.specular = SbVec4f(0, 0, 0, 1); + command.material.emissive = SbVec4f(0, 0, 0, 1); + command.material.shininess = 0.0f; + command.geometry.normals = normals; + command.geometry.normalCount = 4; + SoLightingData lighting; + lighting.ambient.setValue(0, 0, 0); + SoLightData directional; + directional.type = SO_LIGHT_DIRECTIONAL; + directional.direction.setValue(0, 0, 1); + lighting.lights.push_back(directional); + SoDrawList drawlist; + command.lightingHandle = drawlist.addLightingSetup(lighting); + command.modelMatrix.setScale(SbVec3f(4, 1, 1)); + drawlist.addCommand(command); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * pixel = pixelAt(rendered, 32, 32); + return check(pixel[0] > 220 && pixel[1] > 220 && pixel[2] > 220, + "non-uniform model scale corrupted retained normal lighting"); +} + +bool testDepth(RenderFixture & fixture) +{ + SoRenderCommand back = baseCommand(quadPositions); + back.material.diffuse = SbVec4f(0, 0, 1, 1); + back.modelMatrix.setTranslate(SbVec3f(0, 0, 0.5f)); + SoRenderCommand front = baseCommand(quadPositions); + front.material.diffuse = SbVec4f(1, 0, 0, 1); + front.modelMatrix.setTranslate(SbVec3f(0, 0, 0.0f)); + SoDrawList drawlist; + drawlist.addCommand(back); + drawlist.addCommand(front); + const std::vector rendered = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * pixel = pixelAt(rendered, 32, 32); + return check(pixel[0] > 200 && pixel[1] < 50 && pixel[2] < 50, + "retained depth testing did not select the nearer command"); +} + +bool testAlphaTest(RenderFixture & fixture) +{ + SoRenderCommand command = baseCommand(quadPositions); + command.material.diffuse = SbVec4f(1, 0, 0, 0.5f); + command.state.alphaTest.policy = SO_ALPHA_TEST_POLICY_EXPLICIT; + command.state.alphaTest.function = SO_ALPHA_TEST_GREATER; + command.state.alphaTest.reference = 0.75f; + SoDrawList drawlist; + drawlist.addCommand(command); + const std::vector rejected = fixture.render( + drawlist, SbVec4f(0, 0, 1, 1)); + const uint8_t * rejectedPixel = pixelAt(rejected, 32, 32); + if (!check(rejectedPixel[2] > 200 && rejectedPixel[0] < 50, + "alpha-test rejection did not discard the fragment")) { + return false; + } + + drawlist.clear(); + command.state.alphaTest.function = SO_ALPHA_TEST_LESS; + drawlist.addCommand(command); + const std::vector accepted = fixture.render( + drawlist, SbVec4f(0, 0, 1, 1)); + const uint8_t * acceptedPixel = pixelAt(accepted, 32, 32); + return check(acceptedPixel[0] > 200 && acceptedPixel[2] < 50, + "alpha-test acceptance did not preserve the fragment"); +} + +} // namespace + +static int runTest() +{ + setEnvironment("COIN_EGL", "1"); + setEnvironment("EGL_PLATFORM", "surfaceless"); + setEnvironment("COIN_EGL_CORE_PROFILE", "1"); + SoDB::init(); + RenderFixture fixture; + const int initializationResult = fixture.initialize(); + if (initializationResult != 0) { + if (initializationResult == 77) { + return skip("core EGL retained-material context is unavailable"); + } + std::cerr << "FAIL: retained material backend did not initialize on the " + << "verified OpenGL 3.3/GLSL 330 context" << std::endl; + return 1; + } + + int result = 0; + if (!testTextureWrap(fixture)) result = 1; + if (!testTextureAlphaOnce(fixture)) result = 1; + if (!testTextureModels(fixture)) result = 1; + if (!testTexturedLightingComposition(fixture)) result = 1; + if (!testEmissiveIsIndependent(fixture)) result = 1; + if (!testTwoSidedLightingUsesFacing(fixture)) result = 1; + if (!testExecutorLightLimit(fixture)) result = 1; + if (!testTransparentDepthWriteContract(fixture)) result = 1; + if (!testMaterialTransparency(fixture)) result = 1; + if (!testNonUniformScaleLighting(fixture)) result = 1; + if (!testDepth(fixture)) result = 1; + if (!testAlphaTest(fixture)) result = 1; + fixture.shutdown(); + return result; +} + +int main() +{ + const int result = runTest(); + SoDB::finish(); + return result; +} From a5165646e4f02bc366c36801a0ec3be288559a12 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Mon, 17 Aug 2026 11:40:17 +0100 Subject: [PATCH 07/10] rendering: finalize retained material semantics --- CMakeLists.txt | 2 +- data/shaders/gl/material/Lighting.glsl | 6 +- include/Inventor/actions/SoIRRenderAction.h | 8 +++ include/Inventor/rendering/SoRenderIR.h | 3 + src/actions/SoIRRenderAction.cpp | 63 ++++++++++++++++++ src/nodes/SoAlphaTest.cpp | 17 ----- src/rendering/SoGLRenderBackend.cpp | 9 +-- src/rendering/SoGLRenderBackend.h | 5 -- src/rendering/SoRenderIR.cpp | 36 +++++++--- testsuite/CMakeLists.txt | 2 +- ...cpp => RetainedMaterialLightingGLTest.cpp} | 8 +-- ...t.cpp => RetainedMaterialLightingTest.cpp} | 32 +++++++++ .../render/baselines/gl/alpha_test_basic.png | Bin 0 -> 19938 bytes .../baselines/gl/depth_buffer_basic.png | Bin 0 -> 10825 bytes .../gl/drawlist/transparency_depth_basic.png | Bin 0 -> 10830 bytes .../baselines/gl/specular_shininess_basic.png | Bin 0 -> 56664 bytes .../baselines/gl/transparency_depth_basic.png | Bin 0 -> 10827 bytes testsuite/render/scenes/alpha_test_basic.iv | 28 ++++++++ testsuite/render/scenes/depth_buffer_basic.iv | 26 ++++++++ .../render/scenes/specular_shininess_basic.iv | 36 ++++++++++ .../render/scenes/transparency_depth_basic.iv | 32 +++++++++ testsuite/render/specs/alpha_test_basic.yml | 8 +++ testsuite/render/specs/depth_buffer_basic.yml | 7 ++ .../render/specs/specular_shininess_basic.yml | 7 ++ .../render/specs/transparency_depth_basic.yml | 10 +++ 25 files changed, 298 insertions(+), 47 deletions(-) rename testsuite/{retained-material-lighting-gl-test.cpp => RetainedMaterialLightingGLTest.cpp} (98%) rename testsuite/{retained-material-lighting-test.cpp => RetainedMaterialLightingTest.cpp} (92%) create mode 100644 testsuite/render/baselines/gl/alpha_test_basic.png create mode 100644 testsuite/render/baselines/gl/depth_buffer_basic.png create mode 100644 testsuite/render/baselines/gl/drawlist/transparency_depth_basic.png create mode 100644 testsuite/render/baselines/gl/specular_shininess_basic.png create mode 100644 testsuite/render/baselines/gl/transparency_depth_basic.png create mode 100644 testsuite/render/scenes/alpha_test_basic.iv create mode 100644 testsuite/render/scenes/depth_buffer_basic.iv create mode 100644 testsuite/render/scenes/specular_shininess_basic.iv create mode 100644 testsuite/render/scenes/transparency_depth_basic.iv create mode 100644 testsuite/render/specs/alpha_test_basic.yml create mode 100644 testsuite/render/specs/depth_buffer_basic.yml create mode 100644 testsuite/render/specs/specular_shininess_basic.yml create mode 100644 testsuite/render/specs/transparency_depth_basic.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index 465c616660..fadb20301f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -971,7 +971,7 @@ if(COIN_BUILD_VISUAL_TESTS) set(COIN_DRAWLIST_BASE_VISUAL_SPECS "unlit_cube_basic,unlit_transformed_cubes,unlit_vertex_colors,unlit_orthographic_basic,unlit_depth_overlap") set(COIN_MATERIAL_VISUAL_SPECS - "cube_basic,camera_persp_basic,camera_ortho_basic,material_emissive,two_lights,point_spot_lights_basic,texture_rgb,texture_luminance_alpha,transparent_overlap") + "cube_basic,camera_persp_basic,camera_ortho_basic,material_emissive,two_lights,point_spot_lights_basic,texture_rgb,texture_luminance_alpha,transparent_overlap,depth_buffer_basic,alpha_test_basic,transparency_depth_basic,specular_shininess_basic") add_test(NAME visual_smoke COMMAND CoinVisualTests snapshot --help) set_tests_properties(visual_smoke PROPERTIES LABELS "visual-contract") if(COIN_BUILD_LEGACY_GL_RENDERER) diff --git a/data/shaders/gl/material/Lighting.glsl b/data/shaders/gl/material/Lighting.glsl index 6a9a1c465b..44dfe6f130 100644 --- a/data/shaders/gl/material/Lighting.glsl +++ b/data/shaders/gl/material/Lighting.glsl @@ -16,6 +16,10 @@ vec3 coin_material_compute_gouraud_color(vec3 eyePos, vec3 eyeNormal, { vec3 N = normalize(eyeNormal); vec3 V = normalize(-eyePos); + // Coin's LegacyGL path leaves GL_LIGHT_MODEL_LOCAL_VIEWER at its default + // false value, so the fixed-function half-vector uses a viewer direction + // of (0, 0, 1) in eye space rather than a per-vertex eye position. + vec3 specularViewer = vec3(0.0, 0.0, 1.0); if (u_twoSidedLighting > 0.5 && dot(N, V) < 0.0) { N = -N; } @@ -48,7 +52,7 @@ vec3 coin_material_compute_gouraud_color(vec3 eyePos, vec3 eyeNormal, vec3 Ln = normalize(L); float NdotL = max(dot(N, Ln), 0.0); if (NdotL <= 0.0) continue; - vec3 H = normalize(Ln + V); + vec3 H = normalize(Ln + specularViewer); float NdotH = max(dot(N, H), 0.0); float shininess = max(u_materialShininess * 128.0, 0.0); float specularFactor = shininess > 0.0 diff --git a/include/Inventor/actions/SoIRRenderAction.h b/include/Inventor/actions/SoIRRenderAction.h index 68e1cc36ae..f49c3acc91 100644 --- a/include/Inventor/actions/SoIRRenderAction.h +++ b/include/Inventor/actions/SoIRRenderAction.h @@ -105,6 +105,14 @@ class COIN_DLL_API SoIRRenderAction : public SoAction { */ void * allocateGeometryStorage(size_t bytes, size_t alignment = alignof(float)); + //! Copy one texture payload into the current frame, reusing an existing copy. + const unsigned char * allocateTextureStorage(const unsigned char * source, + size_t bytes, + int width, + int height, + int numComponents, + bool & hasTransparency); + //! Push a primitive collector for subsequent fallback primitive generation. void pushPrimitiveCollector(PrimitiveCollector * collector); //! Pop the current primitive collector. The caller must pop in stack order. diff --git a/include/Inventor/rendering/SoRenderIR.h b/include/Inventor/rendering/SoRenderIR.h index b27c4064a0..5b5a3e3d4b 100644 --- a/include/Inventor/rendering/SoRenderIR.h +++ b/include/Inventor/rendering/SoRenderIR.h @@ -241,6 +241,9 @@ struct SoTextureData { int width = 0; int height = 0; int numComponents = 0; // 1=L, 2=LA, 3=RGB, 4=RGBA + // True when at least one texel can contribute alpha below one. This is a + // semantic classification captured once with the frame payload. + bool hasTransparency = false; SoTextureFilter minFilter = SO_TEXTURE_FILTER_NEAREST; SoTextureFilter magFilter = SO_TEXTURE_FILTER_NEAREST; diff --git a/src/actions/SoIRRenderAction.cpp b/src/actions/SoIRRenderAction.cpp index 94b4250ef2..0593038f70 100644 --- a/src/actions/SoIRRenderAction.cpp +++ b/src/actions/SoIRRenderAction.cpp @@ -61,14 +61,27 @@ #include #include #include +#include +#include SO_ACTION_SOURCE(SoIRRenderAction); class SoIRRenderActionP { public: + struct TextureStorage { + const unsigned char * source = nullptr; + size_t bytes = 0; + int width = 0; + int height = 0; + int numComponents = 0; + const unsigned char * copy = nullptr; + bool hasTransparency = false; + }; + SoIRRenderActionP() = default; SoIRBuffer geometryPool; + std::vector textureStorage; SbList collectorStack; std::vector instancePathNodes; std::vector instancePathIndices; @@ -290,10 +303,60 @@ SoIRRenderAction::allocateGeometryStorage(size_t bytes, size_t alignment) return PRIVATE(this)->geometryPool.allocate(bytes, alignment); } +const unsigned char * +SoIRRenderAction::allocateTextureStorage(const unsigned char * source, + size_t bytes, + int width, + int height, + int numComponents, + bool & hasTransparency) +{ + assert(source != NULL); + for (std::vector::const_iterator it = + PRIVATE(this)->textureStorage.begin(); + it != PRIVATE(this)->textureStorage.end(); ++it) { + if (it->source == source && it->bytes == bytes && + it->width == width && it->height == height && + it->numComponents == numComponents) { + hasTransparency = it->hasTransparency; + return it->copy; + } + } + + const bool carriesAlpha = numComponents == 2 || numComponents == 4; + bool transparent = false; + if (carriesAlpha) { + const size_t pixelCount = bytes / static_cast(numComponents); + for (size_t pixel = 0; pixel < pixelCount; ++pixel) { + if (source[pixel * static_cast(numComponents) + + static_cast(numComponents - 1)] != 0xffu) { + transparent = true; + break; + } + } + } + + unsigned char * copy = static_cast( + PRIVATE(this)->geometryPool.allocate(bytes, alignof(unsigned char))); + std::memcpy(copy, source, bytes); + SoIRRenderActionP::TextureStorage storage; + storage.source = source; + storage.bytes = bytes; + storage.width = width; + storage.height = height; + storage.numComponents = numComponents; + storage.copy = copy; + storage.hasTransparency = transparent; + PRIVATE(this)->textureStorage.push_back(storage); + hasTransparency = transparent; + return copy; +} + void SoIRRenderAction::resetFrameResources() { PRIVATE(this)->geometryPool.clear(); + PRIVATE(this)->textureStorage.clear(); PRIVATE(this)->collectorStack.truncate(0); PRIVATE(this)->instancePathNodes.clear(); PRIVATE(this)->instancePathIndices.clear(); diff --git a/src/nodes/SoAlphaTest.cpp b/src/nodes/SoAlphaTest.cpp index f6e7f1242b..aa026969ce 100644 --- a/src/nodes/SoAlphaTest.cpp +++ b/src/nodes/SoAlphaTest.cpp @@ -174,23 +174,6 @@ SoAlphaTest::~SoAlphaTest() { } -static int -coin_alpha_test_function_to_gl(const int function) -{ - switch (function) { - case SoAlphaTest::NEVER: return GL_NEVER; - case SoAlphaTest::ALWAYS: return GL_ALWAYS; - case SoAlphaTest::LESS: return GL_LESS; - case SoAlphaTest::LEQUAL: return GL_LEQUAL; - case SoAlphaTest::EQUAL: return GL_EQUAL; - case SoAlphaTest::GEQUAL: return GL_GEQUAL; - case SoAlphaTest::GREATER: return GL_GREATER; - case SoAlphaTest::NOTEQUAL: return GL_NOTEQUAL; - case SoAlphaTest::NONE: - default: return 0; - } -} - void SoAlphaTest::doAction(SoAction * action) { diff --git a/src/rendering/SoGLRenderBackend.cpp b/src/rendering/SoGLRenderBackend.cpp index 0540c8a9b5..c253f64374 100644 --- a/src/rendering/SoGLRenderBackend.cpp +++ b/src/rendering/SoGLRenderBackend.cpp @@ -943,9 +943,7 @@ SoGLRenderBackend::applyDepthState(const SoRenderCommand & command) else { glDisable(GL_DEPTH_TEST); } - glDepthMask(command.state.depth.writeEnabled && - command.pass != SO_RENDERPASS_TRANSPARENT - ? GL_TRUE : GL_FALSE); + glDepthMask(command.state.depth.writeEnabled ? GL_TRUE : GL_FALSE); glDepthRange(command.state.depth.range[0], command.state.depth.range[1]); } @@ -953,9 +951,7 @@ SoGLRenderBackend::applyDepthState(const SoRenderCommand & command) void SoGLRenderBackend::applyBlendState(const SoRenderCommand & command) { - const bool blending = command.state.blend.enabled || - command.pass == SO_RENDERPASS_TRANSPARENT || - command.material.diffuse[3] < 0.999f; + const bool blending = command.state.blend.enabled; if (blending) { glEnable(GL_BLEND); if (isDualSourceBlendFactor(command.state.blend.srcRGBFactor) || @@ -1059,7 +1055,6 @@ SoGLRenderBackend::drawGeometry(const SoRenderCommand & command, } } -void void SoGLRenderBackend::beginFrame(const SoRenderParams & params) { diff --git a/src/rendering/SoGLRenderBackend.h b/src/rendering/SoGLRenderBackend.h index ebdeb2eb7b..c2c82beb03 100644 --- a/src/rendering/SoGLRenderBackend.h +++ b/src/rendering/SoGLRenderBackend.h @@ -146,11 +146,6 @@ class COIN_DLL_API SoGLRenderBackend : public SoRenderBackend { void beginFrame(const SoRenderParams & params); void invalidateCache(); void updateGeometryCache(const SoDrawList & drawlist); - void renderPass(const SoDrawList & drawlist, - const SbMat & viewMat, - const SbMat & projMat, - const SoRenderParams & params, - SoRenderPassType pass); void drawCommand(const SoDrawList & drawlist, const SoRenderCommand & command, const SbMat & viewMat, diff --git a/src/rendering/SoRenderIR.cpp b/src/rendering/SoRenderIR.cpp index 3c4058e51a..554fdc1104 100644 --- a/src/rendering/SoRenderIR.cpp +++ b/src/rendering/SoRenderIR.cpp @@ -455,11 +455,25 @@ textureWrapFromLegacy(SoMultiTextureImageElement::Wrap wrap) } static bool -hasTexture(const SoMaterialData & material) -{ - return material.texture.pixels != nullptr && - material.texture.width > 0 && material.texture.height > 0 && - material.texture.numComponents > 0; +textureHasTransparency(const SoTextureData & texture) +{ + // DECAL uses texture alpha as a color interpolation factor; it does not + // change the fragment alpha that controls coverage or blending. + if (texture.model == SO_TEXTURE_MODEL_DECAL) return false; + if (texture.hasTransparency) return true; + if (!texture.pixels || texture.width <= 0 || texture.height <= 0 || + (texture.numComponents != 2 && texture.numComponents != 4)) { + return false; + } + const size_t pixelCount = static_cast(texture.width) * + static_cast(texture.height); + for (size_t pixel = 0; pixel < pixelCount; ++pixel) { + if (texture.pixels[pixel * static_cast(texture.numComponents) + + static_cast(texture.numComponents - 1)] != 0xffu) { + return true; + } + } + return false; } void @@ -540,14 +554,15 @@ fillTextureFromState(SoState * state, SoIRRenderAction * action, const size_t pixelCount = static_cast(size[0]) * static_cast(size[1]); const size_t byteCount = pixelCount * static_cast(numComponents); - unsigned char * copy = static_cast( - action->allocateGeometryStorage(byteCount, alignof(unsigned char))); - std::memcpy(copy, bytes, byteCount); + bool hasTransparency = false; + const unsigned char * copy = action->allocateTextureStorage( + bytes, byteCount, size[0], size[1], numComponents, hasTransparency); material.texture.pixels = copy; material.texture.width = size[0]; material.texture.height = size[1]; material.texture.numComponents = numComponents; + material.texture.hasTransparency = hasTransparency; material.texture.wrapS = textureWrapFromLegacy(wrapS); material.texture.wrapT = textureWrapFromLegacy(wrapT); material.texture.model = textureModelFromLegacy(model); @@ -738,7 +753,7 @@ fillLightingFromState(SoState * state, SoDrawList & drawlist) bool isMaterialTransparent(const SoMaterialData & material) { - return material.opacity < 0.999f; + return material.opacity < 0.999f || textureHasTransparency(material.texture); } void @@ -749,8 +764,7 @@ ensureMaterialBlendState(SoRenderState & renderState, // legacy GL action enables the conventional blend function as part of its // transparency setup. Make that implicit IR contract explicit without // replacing an actual non-standard blend state. - if (renderState.blend.enabled || - (!isMaterialTransparent(material) && !hasTexture(material))) { + if (renderState.blend.enabled || !isMaterialTransparent(material)) { return; } diff --git a/testsuite/CMakeLists.txt b/testsuite/CMakeLists.txt index 39db43f2ea..cd1c783ebb 100644 --- a/testsuite/CMakeLists.txt +++ b/testsuite/CMakeLists.txt @@ -313,7 +313,7 @@ target_include_directories(RetainedMixedTopologyTest PRIVATE ${PROJECT_BINARY_DIR}/include ${COIN_TARGET_INCLUDE_DIRECTORIES} ) -add_executable(RetainedMaterialLightingTest retained-material-lighting-test.cpp) +add_executable(RetainedMaterialLightingTest RetainedMaterialLightingTest.cpp) target_link_libraries(RetainedMaterialLightingTest Coin ${COIN_TARGET_LINK_LIBRARIES}) target_include_directories(RetainedMaterialLightingTest PRIVATE ${PROJECT_SOURCE_DIR}/include diff --git a/testsuite/retained-material-lighting-gl-test.cpp b/testsuite/RetainedMaterialLightingGLTest.cpp similarity index 98% rename from testsuite/retained-material-lighting-gl-test.cpp rename to testsuite/RetainedMaterialLightingGLTest.cpp index ef9e610eaa..4615c9773b 100644 --- a/testsuite/retained-material-lighting-gl-test.cpp +++ b/testsuite/RetainedMaterialLightingGLTest.cpp @@ -417,7 +417,7 @@ bool testExecutorLightLimit(RenderFixture & fixture) "GL executor uploaded more lights than its declared shader cap"); } -bool testTransparentDepthWriteContract(RenderFixture & fixture) +bool testTransparentDepthWriteFaithful(RenderFixture & fixture) { SoRenderCommand command = baseCommand(quadPositions); command.material.shadingModel = SO_SHADING_UNLIT; @@ -429,8 +429,8 @@ bool testTransparentDepthWriteContract(RenderFixture & fixture) fixture.render(drawlist, SbVec4f(0, 0, 0, 1)); GLboolean depthWrite = GL_FALSE; glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWrite); - return check(depthWrite == GL_FALSE, - "transparent retained commands unexpectedly wrote depth"); + return check(depthWrite == GL_TRUE, + "transparent retained command changed the requested depth-write state"); } bool testMaterialTransparency(RenderFixture & fixture) @@ -559,7 +559,7 @@ static int runTest() if (!testEmissiveIsIndependent(fixture)) result = 1; if (!testTwoSidedLightingUsesFacing(fixture)) result = 1; if (!testExecutorLightLimit(fixture)) result = 1; - if (!testTransparentDepthWriteContract(fixture)) result = 1; + if (!testTransparentDepthWriteFaithful(fixture)) result = 1; if (!testMaterialTransparency(fixture)) result = 1; if (!testNonUniformScaleLighting(fixture)) result = 1; if (!testDepth(fixture)) result = 1; diff --git a/testsuite/retained-material-lighting-test.cpp b/testsuite/RetainedMaterialLightingTest.cpp similarity index 92% rename from testsuite/retained-material-lighting-test.cpp rename to testsuite/RetainedMaterialLightingTest.cpp index fcbf4d5092..fe7bf058c0 100644 --- a/testsuite/retained-material-lighting-test.cpp +++ b/testsuite/RetainedMaterialLightingTest.cpp @@ -298,6 +298,38 @@ runTest() } indexedAlphaRoot->unref(); + if (!checkTextureClassification(3, 255, SoTexture2::MODULATE, false) || + !checkTextureClassification(4, 255, SoTexture2::MODULATE, false) || + !checkTextureClassification(4, 127, SoTexture2::MODULATE, true) || + !checkTextureClassification(4, 127, SoTexture2::DECAL, false)) { + std::cerr << "FAIL: texture alpha was not classified consistently with retained blend state" + << std::endl; + result = 1; + } + + // Two commands using one scene texture must borrow one frame-local payload + // rather than copying the image once per command. + { + const unsigned char pixels[] = { 255, 128, 64, 127 }; + SoSeparator * textureRoot = new SoSeparator; + textureRoot->ref(); + SoTexture2 * sharedTexture = new SoTexture2; + sharedTexture->image.setValue(SbVec2s(1, 1), 4, pixels); + textureRoot->addChild(sharedTexture); + textureRoot->addChild(new SoCube); + textureRoot->addChild(new SoCube); + SoIRRenderAction textureAction(SbViewportRegion(32, 32)); + textureAction.apply(textureRoot); + if (textureAction.getDrawList().getNumCommands() != 2 || + textureAction.getDrawList().getCommand(0).material.texture.pixels != + textureAction.getDrawList().getCommand(1).material.texture.pixels) { + std::cerr << "FAIL: frame texture payload was copied once per command" + << std::endl; + result = 1; + } + textureRoot->unref(); + } + // A later ordinary material update must invalidate the packed-color // provenance. Otherwise a retained command could reuse opacity from the // material that preceded SoVertexProperty. diff --git a/testsuite/render/baselines/gl/alpha_test_basic.png b/testsuite/render/baselines/gl/alpha_test_basic.png new file mode 100644 index 0000000000000000000000000000000000000000..7f9b8405b5450ac6476057231d8aedd8da21a448 GIT binary patch literal 19938 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 C>h2H# literal 0 HcmV?d00001 diff --git a/testsuite/render/baselines/gl/depth_buffer_basic.png b/testsuite/render/baselines/gl/depth_buffer_basic.png new file mode 100644 index 0000000000000000000000000000000000000000..2b78453e0a28a508c8937205fbffb21f6197765c GIT binary patch literal 10825 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 hxe?s|rg+5?1H Date: Mon, 17 Aug 2026 12:05:12 +0100 Subject: [PATCH 08/10] tests: preserve default transparency traversal order --- CMakeLists.txt | 2 +- .../gl/drawlist/transparency_order_basic.png | Bin 0 -> 10832 bytes .../baselines/gl/transparency_order_basic.png | Bin 0 -> 10832 bytes .../render/scenes/transparency_depth_basic.iv | 6 ++-- .../render/scenes/transparency_order_basic.iv | 33 ++++++++++++++++++ .../render/specs/transparency_order_basic.yml | 10 ++++++ 6 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 testsuite/render/baselines/gl/drawlist/transparency_order_basic.png create mode 100644 testsuite/render/baselines/gl/transparency_order_basic.png create mode 100644 testsuite/render/scenes/transparency_order_basic.iv create mode 100644 testsuite/render/specs/transparency_order_basic.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index fadb20301f..5d75c5d14c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -971,7 +971,7 @@ if(COIN_BUILD_VISUAL_TESTS) set(COIN_DRAWLIST_BASE_VISUAL_SPECS "unlit_cube_basic,unlit_transformed_cubes,unlit_vertex_colors,unlit_orthographic_basic,unlit_depth_overlap") set(COIN_MATERIAL_VISUAL_SPECS - "cube_basic,camera_persp_basic,camera_ortho_basic,material_emissive,two_lights,point_spot_lights_basic,texture_rgb,texture_luminance_alpha,transparent_overlap,depth_buffer_basic,alpha_test_basic,transparency_depth_basic,specular_shininess_basic") + "cube_basic,camera_persp_basic,camera_ortho_basic,material_emissive,two_lights,point_spot_lights_basic,texture_rgb,texture_luminance_alpha,transparent_overlap,depth_buffer_basic,alpha_test_basic,transparency_depth_basic,transparency_order_basic,specular_shininess_basic") add_test(NAME visual_smoke COMMAND CoinVisualTests snapshot --help) set_tests_properties(visual_smoke PROPERTIES LABELS "visual-contract") if(COIN_BUILD_LEGACY_GL_RENDERER) diff --git a/testsuite/render/baselines/gl/drawlist/transparency_order_basic.png b/testsuite/render/baselines/gl/drawlist/transparency_order_basic.png new file mode 100644 index 0000000000000000000000000000000000000000..e967e20441885b3b0efef539b4d16ae6731388f1 GIT binary patch literal 10832 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&zE~)R&4YzZe*_#64XcLn`8uMFa(Zo;Tof zb51Z}K_Wsp40?}!&*123JAfcga5r9LJCLzTp11L$fCPkKYy$}?L3wa-MnwZFCWBdL z+>y*}NGxGVFcCyC5@>iIL(ej}KB&nLC72cmGc0~th2p3Ljvg}xx55;1{U0JBQSDFNisx&6pt$H4;*yGETe=kGc3TNF>=_5#cer*oA5W3^l?ByBA1~@?KeEdg3=mL z1S8E&6kuAc3`}!1qag=LXhS*VK-nK7V}eQ~Hl#uhR5rDxa`gBy_Ncuw+IM=yDKP76rPWs>l{fs#I$oD;S% z8q9iwQgDMr(9@io6QtJrJZ#e3NDetr_D64kV6C&J0V{S^gIOC;(gzE$k-(f_aucPo z01`n@b3H8r5};b|`S3||BRJ%+HF~j@ygJSaC0q$6i74rV!p0=UX|5sFV<`B=Sdae5pNQWhV6pnBgut zFYrj1bu~i^*jR4_b}meT?Zmuc(@vx?Ibo|IvG(dl`zE7(6IdS>YYjOvdUaUK`O&@! z^6(RmF_;k?awJt?qkR*kalerqawE8fP2uR(2oAZS-8UJ?F_;k?a@d+~SWDiBwgWFj z4rCmXLz+Yy;K>z=`@@u~BfyTmRGiGCXL_5*Vlj(|sYKx5 zVl1-(F)Fc@aibmk(T@FS#~!@qV06+EX@ZsL#TBC+d(_bnY(uJ}la6Q$dayPxM@Yzx z;O^;Y$DZ6}DcG8BSWDhPIq67ICyT-bJtHOL7#L0o2yTw7*nNZn2s~Z=T-G@yGywqN C2#$aN literal 0 HcmV?d00001 diff --git a/testsuite/render/baselines/gl/transparency_order_basic.png b/testsuite/render/baselines/gl/transparency_order_basic.png new file mode 100644 index 0000000000000000000000000000000000000000..db3637d8e0d8f07b9773de82669abc25830f8f67 GIT binary patch literal 10832 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&zE~)R&4YzZe*_#64XcLn`8uMFa(Zo;Tof zb51Z}K_Wsp40?}!&*123JAfcga5r9LJCLzTp11L$fCPkKYy$}?L3wa-MnwZFCWBdL z+>y*}NGxGVFcCyC5@>iIL(ej}KB&nLC72cmGc0~th2p3Ljvg}xx55;1{U0JBQSDFNisx&6pt$H4;*yGETe=kGc3TNF>=_5#cer*oA5W3^l?ByBA1~@?KeEdg3=mL z1S8E&6kuAc3`}!1qag=LXhS*VK-nK7V}eQ~Hl#uhR5rDxa`gBy_Ncuw+IM=yDKP76rPWs>l{fs#I$oD;S% z8q9iwQgDMr(9@io6QtJrJZ#e3NDetr_D64kV6C&J0V{S^gIOC;(gzE$k-(f_aucPo z01`n@b3H8r5};b|`S3||BRJ%+HF~j@ygJSaC0q$6i74rV!p0=UX|5sFV<`B=Sda_*7_B=a~Ee=GP_d z4vk-uS6>VPw)L3>nHFaQ^ZebxNDgT}V1UQTDel@( zl;%co$YE>rf=5QthekF4CqgtEF1FYr&!Y@%2WDWq(<3f-XR z|JWbkkcBZz-KqQ1yca-2vW!~o48NV1UNn&9Wn2X;v0sL|He;lO90SAAK*7xtS)nT#fWXt$&t;uc GLK6UpX_S=! literal 0 HcmV?d00001 diff --git a/testsuite/render/scenes/transparency_depth_basic.iv b/testsuite/render/scenes/transparency_depth_basic.iv index 2428061447..3846e72f43 100644 --- a/testsuite/render/scenes/transparency_depth_basic.iv +++ b/testsuite/render/scenes/transparency_depth_basic.iv @@ -10,22 +10,24 @@ Separator { LightModel { model BASE_COLOR } DepthBuffer { test TRUE write TRUE function LEQUAL } Separator { + Translation { translation 0 0 0.25 } Material { diffuseColor 0.9 0.1 0.05 transparency 0.35 } Coordinate3 { - point [ -0.9 -0.9 0.25, 0.9 -0.9 0.25, 0.9 0.9 0.25, -0.9 0.9 0.25 ] + point [ -0.9 -0.9 0, 0.9 -0.9 0, 0.9 0.9 0, -0.9 0.9 0 ] } FaceSet { numVertices 4 } } Separator { + Translation { translation 0 0 -0.35 } Material { diffuseColor 0.05 0.2 0.95 transparency 0.35 } Coordinate3 { - point [ -1.1 -1.1 -0.35, 1.1 -1.1 -0.35, 1.1 1.1 -0.35, -1.1 1.1 -0.35 ] + point [ -1.1 -1.1 0, 1.1 -1.1 0, 1.1 1.1 0, -1.1 1.1 0 ] } FaceSet { numVertices 4 } } diff --git a/testsuite/render/scenes/transparency_order_basic.iv b/testsuite/render/scenes/transparency_order_basic.iv new file mode 100644 index 0000000000..6fd2a851c5 --- /dev/null +++ b/testsuite/render/scenes/transparency_order_basic.iv @@ -0,0 +1,33 @@ +#Inventor V2.1 ascii + +Separator { + PerspectiveCamera { + position 0 0 6 + heightAngle 0.785398 + nearDistance 0.1 + farDistance 20 + } + LightModel { model BASE_COLOR } + DepthBuffer { test TRUE write TRUE function LEQUAL } + Separator { + Translation { translation 0 0 0.25 } + Material { + diffuseColor 0.9 0.1 0.05 + transparency 0.35 + } + Coordinate3 { + point [ -0.9 -0.9 0, 0.9 -0.9 0, 0.9 0.9 0, -0.9 0.9 0 ] + } + FaceSet { numVertices 4 } + } + Separator { + Translation { translation 0 0 -0.35 } + Material { + diffuseColor 0.05 0.2 0.95 + } + Coordinate3 { + point [ -1.1 -1.1 0, 1.1 -1.1 0, 1.1 1.1 0, -1.1 1.1 0 ] + } + FaceSet { numVertices 4 } + } +} diff --git a/testsuite/render/specs/transparency_order_basic.yml b/testsuite/render/specs/transparency_order_basic.yml new file mode 100644 index 0000000000..ab2ce92c91 --- /dev/null +++ b/testsuite/render/specs/transparency_order_basic.yml @@ -0,0 +1,10 @@ +id: transparency_order_basic +scene: ../scenes/transparency_order_basic.iv + +viewport: + background: [0.08, 0.08, 0.08, 1.0] + +baseline: ../baselines/gl/transparency_order_basic.png + +baselines: + drawlist: ../baselines/gl/drawlist/transparency_order_basic.png From 20768f98d3c6365182008ac5ec10735f6a0c4923 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Tue, 18 Aug 2026 15:24:27 +0100 Subject: [PATCH 09/10] tests: run retained lighting through shared GL support --- src/rendering/SoRenderPlan.cpp | 13 ++++--- src/shapenodes/SoShape.cpp | 1 - testsuite/RenderPlanTest.cpp | 28 +++++++++++++++ testsuite/RetainedMaterialLightingGLTest.cpp | 38 ++++++++------------ 4 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/rendering/SoRenderPlan.cpp b/src/rendering/SoRenderPlan.cpp index 062e6d458a..5b29e0adf2 100644 --- a/src/rendering/SoRenderPlan.cpp +++ b/src/rendering/SoRenderPlan.cpp @@ -22,14 +22,17 @@ SoRenderPlanner::build(const SoDrawList & drawlist, const SoRenderCommand & command = drawlist.getCommand( static_cast(commandIndex)); SbMat view; - SbMat model; const SbMatrix & effectiveView = command.state.useCommandMatrices ? command.viewMatrix : frameViewMatrix; effectiveView.getValue(view); - command.modelMatrix.getValue(model); - const float worldX = model[3][0]; - const float worldY = model[3][1]; - const float worldZ = model[3][2]; + SbVec3f worldCenter; + command.modelMatrix.multVecMatrix( + command.geometry.hasBounds ? command.geometry.boundsCenter + : SbVec3f(0.0f, 0.0f, 0.0f), + worldCenter); + const float worldX = worldCenter[0]; + const float worldY = worldCenter[1]; + const float worldZ = worldCenter[2]; const float eyeZ = view[0][2] * worldX + view[1][2] * worldY + view[2][2] * worldZ + diff --git a/src/shapenodes/SoShape.cpp b/src/shapenodes/SoShape.cpp index 3f05acc4c9..14363f5b41 100644 --- a/src/shapenodes/SoShape.cpp +++ b/src/shapenodes/SoShape.cpp @@ -358,7 +358,6 @@ class SoIRPrimitiveAssembler : public SoIRRenderAction::PrimitiveCollector { command.material.vertexColorAlphaIncludesOpacity = command.geometry.colors != nullptr && !packedVertexColors; SoRenderIR::finalizeCommand(command); - command.userData = this->shape; this->action->addCommand(command); } } diff --git a/testsuite/RenderPlanTest.cpp b/testsuite/RenderPlanTest.cpp index bf0b264b9c..e40251e15b 100644 --- a/testsuite/RenderPlanTest.cpp +++ b/testsuite/RenderPlanTest.cpp @@ -95,5 +95,33 @@ main() "planner did not schedule transparent commands back-to-front") && result; + SbMatrix movedFrameView = SbMatrix::identity(); + movedFrameView.setTranslate(SbVec3f(0.0f, 0.0f, -4.0f)); + transparentNear.geometry.boundsCenter.setValue(0.0f, 0.0f, -3.0f); + transparentNear.geometry.hasBounds = TRUE; + transparentFar.geometry.boundsCenter.setValue(0.0f, 0.0f, 1.0f); + transparentFar.geometry.hasBounds = TRUE; + transparencyDrawList.clear(); + transparencyDrawList.addCommand(opaque); + transparencyDrawList.addCommand(transparentNear); + transparencyDrawList.addCommand(transparentFar); + planner.build(transparencyDrawList, movedFrameView, plan); + result = check(plan.getDraw(1).commandIndex == 1 && + plan.getDraw(2).commandIndex == 2, + "planner ignored frame camera and geometry bounds") && result; + + SoRenderCommand overrideNear = transparentNear; + overrideNear.state.useCommandMatrices = TRUE; + overrideNear.viewMatrix.makeIdentity(); + overrideNear.geometry.boundsCenter.setValue(0.0f, 0.0f, 2.0f); + transparencyDrawList.clear(); + transparencyDrawList.addCommand(opaque); + transparencyDrawList.addCommand(overrideNear); + transparencyDrawList.addCommand(transparentFar); + planner.build(transparencyDrawList, movedFrameView, plan); + result = check(plan.getDraw(1).commandIndex == 2 && + plan.getDraw(2).commandIndex == 1, + "planner ignored an explicit command-matrix override") && result; + return result ? 0 : 1; } diff --git a/testsuite/RetainedMaterialLightingGLTest.cpp b/testsuite/RetainedMaterialLightingGLTest.cpp index 4615c9773b..04ccf5176a 100644 --- a/testsuite/RetainedMaterialLightingGLTest.cpp +++ b/testsuite/RetainedMaterialLightingGLTest.cpp @@ -1,12 +1,11 @@ -#include "rendering/CoinOffscreenGLCanvas.h" #include "rendering/SoGLRenderBackend.h" #include "rendering/SoRenderPlan.h" +#include "support/GLTestContext.h" #include #include #include -#include #include #include @@ -18,26 +17,22 @@ int skip(const char * reason) return 77; } -void setEnvironment(const char * name, const char * value) -{ -#ifdef _WIN32 - _putenv_s(name, value); -#else - setenv(name, value, 1); -#endif -} - struct RenderFixture { - CoinOffscreenGLCanvas canvas; + GLTestContext context; SoGLRenderBackend backend; int initialize() { - canvas.setWantedSize(SbVec2s(64, 64)); - if (canvas.activateGLContext() == 0) return 77; + GLTestContextConfig config; + config.profile = GLTestProfile::Core; + config.major = 3; + config.minor = 3; + config.width = 64; + config.height = 64; + if (!context.initialize(config)) return 77; SoRenderBackendInitParams init = {}; if (backend.initialize(init)) return 0; - canvas.deactivateGLContext(); + context.shutdown(); return 1; } @@ -54,18 +49,16 @@ struct RenderFixture { params.flags = SO_PARAM_CLEAR_WINDOW | SO_PARAM_CLEAR_DEPTH; SoRenderPlanner planner; SoRenderPlan plan; - planner.build(drawlist, plan); + planner.build(drawlist, params.viewMatrix, plan); backend.render(drawlist, plan, params); glFinish(); - std::vector pixels(64 * 64 * 4, 0); - canvas.readPixels(pixels.data(), SbVec2s(64, 64), 64, 4); - return pixels; + return context.readPixels(); } void shutdown() { backend.shutdown(); - canvas.deactivateGLContext(); + context.shutdown(); } }; @@ -536,15 +529,12 @@ bool testAlphaTest(RenderFixture & fixture) static int runTest() { - setEnvironment("COIN_EGL", "1"); - setEnvironment("EGL_PLATFORM", "surfaceless"); - setEnvironment("COIN_EGL_CORE_PROFILE", "1"); SoDB::init(); RenderFixture fixture; const int initializationResult = fixture.initialize(); if (initializationResult != 0) { if (initializationResult == 77) { - return skip("core EGL retained-material context is unavailable"); + return skip("core GLFW retained-material context is unavailable"); } std::cerr << "FAIL: retained material backend did not initialize on the " << "verified OpenGL 3.3/GLSL 330 context" << std::endl; From 8461cd6c7bf662b92e199f46bffc56bf6a575b43 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 19 Aug 2026 02:11:04 +0100 Subject: [PATCH 10/10] rendering: centralize surface program selection --- src/rendering/SoGLRenderBackend.cpp | 16 ++++++++ src/rendering/SoGLRenderBackend.h | 2 + testsuite/RetainedMaterialLightingGLTest.cpp | 35 ++++++++++++++++++ .../gl/drawlist/transparency_depth_basic.png | Bin 10830 -> 0 bytes .../gl/drawlist/transparency_order_basic.png | Bin 10832 -> 0 bytes .../render/specs/transparency_depth_basic.yml | 3 -- .../render/specs/transparency_order_basic.yml | 3 -- 7 files changed, 53 insertions(+), 6 deletions(-) delete mode 100644 testsuite/render/baselines/gl/drawlist/transparency_depth_basic.png delete mode 100644 testsuite/render/baselines/gl/drawlist/transparency_order_basic.png diff --git a/src/rendering/SoGLRenderBackend.cpp b/src/rendering/SoGLRenderBackend.cpp index c253f64374..378bbb644b 100644 --- a/src/rendering/SoGLRenderBackend.cpp +++ b/src/rendering/SoGLRenderBackend.cpp @@ -1024,6 +1024,8 @@ SoGLRenderBackend::bindVisualCommand(const SoDrawList & drawlist, const SbMat & projMat, const SoRenderParams & params) { + const VisualProgram & program = this->selectSurfaceProgram(command); + cc_glglue_glUseProgram(this->glue, program.handle); applyViewport(params); this->bindTransforms(command, viewMat, projMat); this->bindMaterial(command, entry); @@ -1093,6 +1095,20 @@ SoGLRenderBackend::createShaders() return this->createVisualProgram(); } +const SoGLRenderBackend::VisualProgram & +SoGLRenderBackend::selectSurfaceProgram(const SoRenderCommand & command) const +{ + // Centralize the mapping from retained material semantics to an executor + // implementation. Both current models use the retained Inventor lighting + // evaluation program, with u_shadingModel selecting its defined behavior. + switch (command.material.shadingModel) { + case SO_SHADING_UNLIT: + case SO_SHADING_LEGACY_GOURAUD: + default: + return this->visualProgram; + } +} + bool SoGLRenderBackend::createVisualProgram() { diff --git a/src/rendering/SoGLRenderBackend.h b/src/rendering/SoGLRenderBackend.h index c2c82beb03..26534e988e 100644 --- a/src/rendering/SoGLRenderBackend.h +++ b/src/rendering/SoGLRenderBackend.h @@ -143,6 +143,8 @@ class COIN_DLL_API SoGLRenderBackend : public SoRenderBackend { bool createShaders(); bool createVisualProgram(); + const VisualProgram & selectSurfaceProgram( + const SoRenderCommand & command) const; void beginFrame(const SoRenderParams & params); void invalidateCache(); void updateGeometryCache(const SoDrawList & drawlist); diff --git a/testsuite/RetainedMaterialLightingGLTest.cpp b/testsuite/RetainedMaterialLightingGLTest.cpp index 04ccf5176a..9cbe2bd057 100644 --- a/testsuite/RetainedMaterialLightingGLTest.cpp +++ b/testsuite/RetainedMaterialLightingGLTest.cpp @@ -333,6 +333,40 @@ bool testTexturedLightingComposition(RenderFixture & fixture) "textured geometry bypassed retained lighting"); } +bool testShadingModelSelection(RenderFixture & fixture) +{ + SoRenderCommand command = baseCommand(quadPositions); + command.material.diffuse = SbVec4f(1, 1, 1, 1); + command.material.ambient = SbVec4f(0, 0, 0, 1); + command.material.specular = SbVec4f(0, 0, 0, 1); + command.material.emissive = SbVec4f(0, 0, 0, 1); + + SoLightingData lighting; + lighting.ambient.setValue(0, 0, 0); + SoDrawList drawlist; + command.lightingHandle = drawlist.addLightingSetup(lighting); + command.material.shadingModel = SO_SHADING_UNLIT; + drawlist.addCommand(command); + const std::vector unlit = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * unlitPixel = pixelAt(unlit, 32, 32); + if (!check(unlitPixel[0] > 220 && unlitPixel[1] > 220 && + unlitPixel[2] > 220, + "UNLIT did not select unlit surface evaluation")) { + return false; + } + + drawlist.clear(); + command.lightingHandle = drawlist.addLightingSetup(lighting); + command.material.shadingModel = SO_SHADING_LEGACY_GOURAUD; + drawlist.addCommand(command); + const std::vector lit = fixture.render( + drawlist, SbVec4f(0, 0, 0, 1)); + const uint8_t * litPixel = pixelAt(lit, 32, 32); + return check(litPixel[0] < 10 && litPixel[1] < 10 && litPixel[2] < 10, + "LEGACY_GOURAUD did not select Inventor lighting evaluation"); +} + bool testEmissiveIsIndependent(RenderFixture & fixture) { SoRenderCommand command = baseCommand(quadPositions); @@ -545,6 +579,7 @@ static int runTest() if (!testTextureWrap(fixture)) result = 1; if (!testTextureAlphaOnce(fixture)) result = 1; if (!testTextureModels(fixture)) result = 1; + if (!testShadingModelSelection(fixture)) result = 1; if (!testTexturedLightingComposition(fixture)) result = 1; if (!testEmissiveIsIndependent(fixture)) result = 1; if (!testTwoSidedLightingUsesFacing(fixture)) result = 1; diff --git a/testsuite/render/baselines/gl/drawlist/transparency_depth_basic.png b/testsuite/render/baselines/gl/drawlist/transparency_depth_basic.png deleted file mode 100644 index 1ea7717ca69dfd4d636a939bae1e60bdb740f1f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10830 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&zE~)R&4YzZe*_L_J*`Ln`8uMFa(Zo;Tof zb51Z}K_Wsp40?}!&*123JAfcga5r9LJCLzTp11L$fCPkKYy$}?L3wa-MnwZFCWBdL z+>y*}NGxGVFcCyC5@>iIL(ej}KB&nLC72cmGc0~th2p3Ljvg}xx55;1{U0JBQSDFNisx&6pt$H4;*yGETe=kGc3TNF>=_5#cer*oA5W3^l?ByBA1~@?KeEdg3=mL z1S8E&6kuAc3`}!1qag=LXhS*VK-nK7V}eQ~Hl#uhR5rDxa`gBy_Ncuw+IM=yDKP76rPWs>l{fs#I$oD;S% z8q9iwQgDMr(9@io6QtJrJZ#e3NDetr_D64kV6C&J0V{S^gIOC;(gzE$k-(f_aucPo z01`n@b3H8r5};b|`S3||BRJ%+HF~j@ygJSaC0q$6i74rV!p0=UX|5sFHp@c|h4 z9{i0$=TatK3<0+GnFW~^X9IKn-C0zBn&Vcbaiz6k?(zlG62KdI8hWlJ*bH~ z2})U;d`M^Aflhz}I3+!TM{P#OyU1MzF@i^JC@kkjaL8fpJ76n$M<-U%7A=kBkQ>3H xHWV(s8Nnfkt?z)fy*}NGxGVFcCyC5@>iIL(ej}KB&nLC72cmGc0~th2p3Ljvg}xx55;1{U0JBQSDFNisx&6pt$H4;*yGETe=kGc3TNF>=_5#cer*oA5W3^l?ByBA1~@?KeEdg3=mL z1S8E&6kuAc3`}!1qag=LXhS*VK-nK7V}eQ~Hl#uhR5rDxa`gBy_Ncuw+IM=yDKP76rPWs>l{fs#I$oD;S% z8q9iwQgDMr(9@io6QtJrJZ#e3NDetr_D64kV6C&J0V{S^gIOC;(gzE$k-(f_aucPo z01`n@b3H8r5};b|`S3||BRJ%+HF~j@ygJSaC0q$6i74rV!p0=UX|5sFV<`B=Sdae5pNQWhV6pnBgut zFYrj1bu~i^*jR4_b}meT?Zmuc(@vx?Ibo|IvG(dl`zE7(6IdS>YYjOvdUaUK`O&@! z^6(RmF_;k?awJt?qkR*kalerqawE8fP2uR(2oAZS-8UJ?F_;k?a@d+~SWDiBwgWFj z4rCmXLz+Yy;K>z=`@@u~BfyTmRGiGCXL_5*Vlj(|sYKx5 zVl1-(F)Fc@aibmk(T@FS#~!@qV06+EX@ZsL#TBC+d(_bnY(uJ}la6Q$dayPxM@Yzx z;O^;Y$DZ6}DcG8BSWDhPIq67ICyT-bJtHOL7#L0o2yTw7*nNZn2s~Z=T-G@yGywqN C2#$aN diff --git a/testsuite/render/specs/transparency_depth_basic.yml b/testsuite/render/specs/transparency_depth_basic.yml index f8e55e8e87..44dadf9e69 100644 --- a/testsuite/render/specs/transparency_depth_basic.yml +++ b/testsuite/render/specs/transparency_depth_basic.yml @@ -5,6 +5,3 @@ viewport: background: [0.08, 0.08, 0.08, 1.0] baseline: ../baselines/gl/transparency_depth_basic.png - -baselines: - drawlist: ../baselines/gl/drawlist/transparency_depth_basic.png diff --git a/testsuite/render/specs/transparency_order_basic.yml b/testsuite/render/specs/transparency_order_basic.yml index ab2ce92c91..c3982c6459 100644 --- a/testsuite/render/specs/transparency_order_basic.yml +++ b/testsuite/render/specs/transparency_order_basic.yml @@ -5,6 +5,3 @@ viewport: background: [0.08, 0.08, 0.08, 1.0] baseline: ../baselines/gl/transparency_order_basic.png - -baselines: - drawlist: ../baselines/gl/drawlist/transparency_order_basic.png