From 8cbeca44fd38fa8f0cc0f1df99384fb71d213fe0 Mon Sep 17 00:00:00 2001 From: vlj Date: Sun, 8 Jun 2014 22:18:32 +0200 Subject: [PATCH 01/30] Add a way to display shadow map. --- data/shaders/layertexturequad.frag | 10 ++++++++++ src/graphics/irr_driver.hpp | 1 + src/graphics/post_processing.cpp | 15 +++++++++++++++ src/graphics/post_processing.hpp | 1 + src/graphics/render.cpp | 18 ++++++++++++++++++ src/graphics/shaders.cpp | 15 +++++++++++++++ src/graphics/shaders.hpp | 10 ++++++++++ 7 files changed, 70 insertions(+) create mode 100644 data/shaders/layertexturequad.frag diff --git a/data/shaders/layertexturequad.frag b/data/shaders/layertexturequad.frag new file mode 100644 index 000000000..d9be4690b --- /dev/null +++ b/data/shaders/layertexturequad.frag @@ -0,0 +1,10 @@ +uniform sampler2DArray tex; +uniform int layer; + +in vec2 uv; +out vec4 FragColor; + +void main() +{ + FragColor = texture(tex, vec3(uv, float(layer))); +} \ No newline at end of file diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index bfffa6c3c..3b0438861 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -380,6 +380,7 @@ private: void renderSSAO(); void renderLights(unsigned pointlightCount); void renderDisplacement(); + void renderShadowsDebug(); void doScreenShot(); public: IrrDriver(); diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index fd4fc0eed..c1c7c69bb 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -477,6 +477,21 @@ void PostProcessing::renderPassThrough(GLuint tex) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } +void PostProcessing::renderTextureLayer(unsigned tex, unsigned layer) +{ + glUseProgram(FullScreenShader::LayerPassThroughShader::Program); + glBindVertexArray(FullScreenShader::LayerPassThroughShader::vao); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, tex); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glUniform1i(FullScreenShader::LayerPassThroughShader::uniform_texture, 0); + glUniform1i(FullScreenShader::LayerPassThroughShader::uniform_layer, layer); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + void PostProcessing::renderGlow(unsigned tex) { diff --git a/src/graphics/post_processing.hpp b/src/graphics/post_processing.hpp index edf314700..a0e6c4484 100644 --- a/src/graphics/post_processing.hpp +++ b/src/graphics/post_processing.hpp @@ -90,6 +90,7 @@ public: /** Render tex. Used for blit/texture resize */ void renderPassThrough(unsigned tex); + void renderTextureLayer(unsigned tex, unsigned layer); void applyMLAA(); void renderMotionBlur(unsigned cam, FrameBuffer &in_fbo, FrameBuffer &out_fbo); diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index b7647a38c..620f73f91 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -197,6 +197,10 @@ void IrrDriver::renderGLSL(float dt) glViewport(viewport.UpperLeftCorner.X, viewport.UpperLeftCorner.Y, viewport.LowerRightCorner.X, viewport.LowerRightCorner.Y); m_post_processing->renderPassThrough(m_rtts->getRSM().getRTT()[0]); } + else if (irr_driver->getShadowViz()) + { + renderShadowsDebug(); + } else fbo->BlitToDefault(viewport.UpperLeftCorner.X, viewport.UpperLeftCorner.Y, viewport.LowerRightCorner.X, viewport.LowerRightCorner.Y); } @@ -824,6 +828,20 @@ void IrrDriver::renderShadows() } } + +void IrrDriver::renderShadowsDebug() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); + m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 0); + glViewport(UserConfigParams::m_width / 2, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); + m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 1); + glViewport(0, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); + m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 2); + glViewport(UserConfigParams::m_width / 2, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); + m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 3); +} + // ---------------------------------------------------------------------------- void IrrDriver::renderGlow(std::vector& glows) diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index f33f11c49..bb0e5ceec 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -290,6 +290,7 @@ void Shaders::loadShaders() FullScreenShader::Gaussian6VBlurShader::init(); FullScreenShader::GlowShader::init(); FullScreenShader::PassThroughShader::init(); + FullScreenShader::LayerPassThroughShader::init(); FullScreenShader::LinearizeDepthShader::init(); FullScreenShader::SSAOShader::init(); FullScreenShader::SunLightShader::init(); @@ -2554,6 +2555,20 @@ namespace FullScreenShader vao = createVAO(Program); } + GLuint LayerPassThroughShader::Program; + GLuint LayerPassThroughShader::uniform_texture; + GLuint LayerPassThroughShader::uniform_layer; + GLuint LayerPassThroughShader::vao; + void LayerPassThroughShader::init() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/layertexturequad.frag").c_str()); + uniform_texture = glGetUniformLocation(Program, "tex"); + uniform_layer = glGetUniformLocation(Program, "layer"); + vao = createVAO(Program); + } + GLuint LinearizeDepthShader::Program; GLuint LinearizeDepthShader::uniform_zn; GLuint LinearizeDepthShader::uniform_zf; diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 551275678..f46be5337 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -720,6 +720,16 @@ public: static void init(); }; +class LayerPassThroughShader +{ +public: + static GLuint Program; + static GLuint uniform_layer, uniform_texture; + static GLuint vao; + + static void init(); +}; + class LinearizeDepthShader { public: From 753e22600d8e17469cb0f4328b685b2afa978c2e Mon Sep 17 00:00:00 2001 From: vlj Date: Sun, 8 Jun 2014 22:22:58 +0200 Subject: [PATCH 02/30] Reverse shadowmap views. --- src/graphics/render.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 620f73f91..7843d62d0 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -832,13 +832,13 @@ void IrrDriver::renderShadows() void IrrDriver::renderShadowsDebug() { glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); - m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 0); - glViewport(UserConfigParams::m_width / 2, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); - m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 1); glViewport(0, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); - m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 2); + m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 0); glViewport(UserConfigParams::m_width / 2, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); + m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 1); + glViewport(0, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); + m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 2); + glViewport(UserConfigParams::m_width / 2, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 3); } From e2ef26e667b29c41ffa7a9ffeda28c9c68b6c0d0 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Wed, 18 Jun 2014 00:27:03 +0200 Subject: [PATCH 03/30] Add wireframe frustrum view. --- data/shaders/frustrum.vert | 18 ++++++++++++ src/graphics/irr_driver.hpp | 1 + src/graphics/render.cpp | 42 +++++++++++++++++++++++++++ src/graphics/shaders.cpp | 57 +++++++++++++++++++++++++++++++++++++ src/graphics/shaders.hpp | 14 ++++++++- 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 data/shaders/frustrum.vert diff --git a/data/shaders/frustrum.vert b/data/shaders/frustrum.vert new file mode 100644 index 000000000..489241b4d --- /dev/null +++ b/data/shaders/frustrum.vert @@ -0,0 +1,18 @@ +layout (std140) uniform MatrixesData +{ + mat4 ViewMatrix; + mat4 ProjectionMatrix; + mat4 InverseViewMatrix; + mat4 InverseProjectionMatrix; + mat4 ShadowViewProjMatrixes[4]; + vec2 screen; +}; + +uniform int idx; + +in vec3 Position; + +void main(void) +{ + gl_Position = ShadowViewProjMatrixes[idx] * vec4(Position, 1.); +} diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index 3b0438861..393180ab5 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -345,6 +345,7 @@ private: class STKMeshSceneNode *m_sun_interposer; scene::CLensFlareSceneNode *m_lensflare; scene::ICameraSceneNode *m_suncam; + scene::ICameraSceneNode *m_shadows_cam[3]; std::vector m_glowing; diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 7843d62d0..9902b3eb3 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -711,6 +711,7 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz camnode->setFarValue(FarValues[i]); camnode->setNearValue(NearValues[i]); camnode->render(); + m_shadows_cam[i] = camnode; const core::aabbox3df smallcambox = camnode-> getViewFrustum()->getBoundingBox(); core::aabbox3df trackbox(vmin->toIrrVector(), vmax->toIrrVector() - @@ -828,18 +829,59 @@ void IrrDriver::renderShadows() } } +static void renderWireFrameFrustrum(const scene::SViewFrustum *frustrum, unsigned i) +{ + glUseProgram(MeshShader::ViewFrustrumShader::Program); + glBindVertexArray(MeshShader::ViewFrustrumShader::frustrumvao); + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::frustrumvbo); + float tmp[24] = { + frustrum->getFarLeftDown().X, + frustrum->getFarLeftDown().Y, + frustrum->getFarLeftDown().Z, + frustrum->getFarLeftUp().X, + frustrum->getFarLeftUp().Y, + frustrum->getFarLeftUp().Z, + frustrum->getFarRightDown().X, + frustrum->getFarRightDown().Y, + frustrum->getFarRightDown().Z, + frustrum->getFarRightUp().X, + frustrum->getFarRightUp().Y, + frustrum->getFarRightUp().Z, + frustrum->getNearLeftDown().X, + frustrum->getNearLeftDown().Y, + frustrum->getNearLeftDown().Z, + frustrum->getNearLeftUp().X, + frustrum->getNearLeftUp().Y, + frustrum->getNearLeftUp().Z, + frustrum->getNearRightDown().X, + frustrum->getNearRightDown().Y, + frustrum->getNearRightDown().Z, + frustrum->getNearRightUp().X, + frustrum->getNearRightUp().Y, + frustrum->getNearRightUp().Z, + }; + glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * 3 * sizeof(float), tmp); + MeshShader::ViewFrustrumShader::setUniforms(video::SColor(255, 0, 255, 0)); + glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0); +} + void IrrDriver::renderShadowsDebug() { glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 0); + renderWireFrameFrustrum(m_shadows_cam[0]->getViewFrustum(), 0); glViewport(UserConfigParams::m_width / 2, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 1); + renderWireFrameFrustrum(m_shadows_cam[1]->getViewFrustum(), 1); glViewport(0, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 2); + renderWireFrameFrustrum(m_shadows_cam[2]->getViewFrustum(), 2); glViewport(UserConfigParams::m_width / 2, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 3); + renderWireFrameFrustrum(m_shadows_cam[3]->getViewFrustum(), 3); + glViewport(0, 0, UserConfigParams::m_width, UserConfigParams::m_height); } // ---------------------------------------------------------------------------- diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index bb0e5ceec..9c719bea7 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -169,6 +169,26 @@ static void initCubeVBO() glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * 6 * sizeof(int), indices, GL_STATIC_DRAW); } +GLuint SharedObject::frustrumvbo = 0; +GLuint SharedObject::frustrumindexes = 0; + +static void initFrustrumVBO() +{ + glGenBuffers(1, &SharedObject::frustrumvbo); + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::frustrumvbo); + glBufferData(GL_ARRAY_BUFFER, 8 * 3 * sizeof(float), 0, GL_DYNAMIC_DRAW); + + int indices[24] = { + 0, 1, 1, 3, 3, 2, 2, 0, + 4, 5, 5, 7, 7, 6, 6, 4, + 0, 4, 1, 5, 2, 6, 3, 7, + }; + + glGenBuffers(1, &SharedObject::frustrumindexes); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedObject::frustrumindexes); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, 12 * 2 * sizeof(int), indices, GL_STATIC_DRAW); +} + GLuint SharedObject::ViewProjectionMatrixesUBO; static void initShadowVPMUBO() @@ -271,6 +291,7 @@ void Shaders::loadShaders() initQuadBuffer(); initBillboardVBO(); initCubeVBO(); + initFrustrumVBO(); initShadowVPMUBO(); FullScreenShader::BloomBlendShader::init(); FullScreenShader::BloomShader::init(); @@ -341,6 +362,7 @@ void Shaders::loadShaders() MeshShader::InstancedRefShadowShader::init(); MeshShader::GrassShadowShader::init(); MeshShader::SkyboxShader::init(); + MeshShader::ViewFrustrumShader::init(); ParticleShader::FlipParticleRender::init(); ParticleShader::HeightmapSimulationShader::init(); ParticleShader::SimpleParticleRender::init(); @@ -1794,6 +1816,41 @@ namespace MeshShader glUniformMatrix4fv(uniform_MM, 1, GL_FALSE, ModelMatrix.pointer()); glUniform1i(uniform_tex, TU_tex); } + + GLuint ViewFrustrumShader::Program; + GLuint ViewFrustrumShader::attrib_position; + GLuint ViewFrustrumShader::uniform_color; + GLuint ViewFrustrumShader::uniform_idx; + GLuint ViewFrustrumShader::frustrumvao; + + void ViewFrustrumShader::init() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/frustrum.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/coloredquad.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + if (!UserConfigParams::m_ubo_disabled) + { + GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); + glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); + } + uniform_color = glGetUniformLocation(Program, "color"); + uniform_idx = glGetUniformLocation(Program, "idx"); + + glGenVertexArrays(1, &frustrumvao); + glBindVertexArray(frustrumvao); + glBindBuffer(GL_ARRAY_BUFFER, SharedObject::frustrumvbo); + glEnableVertexAttribArray(attrib_position); + glVertexAttribPointer(attrib_position, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, SharedObject::frustrumindexes); + glBindVertexArray(0); + } + + void ViewFrustrumShader::setUniforms(const video::SColor &color, unsigned idx) + { + glUniform4i(uniform_color, color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + glUniform1i(uniform_idx, idx); + } } namespace LightShader diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index f46be5337..3368da771 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -29,7 +29,7 @@ class SharedObject { public: static GLuint billboardvbo; - static GLuint cubevbo, cubeindexes; + static GLuint cubevbo, cubeindexes, frustrumvbo, frustrumindexes; static GLuint ViewProjectionMatrixesUBO; }; @@ -424,6 +424,18 @@ public: static void setUniforms(const core::matrix4 &ModelMatrix, const core::vector2df &screen, unsigned TU_tex); }; +class ViewFrustrumShader +{ +public: + static GLuint Program; + static GLuint attrib_position; + static GLuint uniform_color, uniform_idx; + static GLuint frustrumvao; + + static void init(); + static void setUniforms(const video::SColor &color, unsigned idx); +}; + } #define MAXLIGHT 32 From 6bc9446b913325eadd6480dc9f6b3354f6971c70 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Wed, 18 Jun 2014 00:27:39 +0200 Subject: [PATCH 04/30] Fix build --- src/graphics/render.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 9902b3eb3..df8fe46e3 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -861,7 +861,7 @@ static void renderWireFrameFrustrum(const scene::SViewFrustum *frustrum, unsigne frustrum->getNearRightUp().Z, }; glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * 3 * sizeof(float), tmp); - MeshShader::ViewFrustrumShader::setUniforms(video::SColor(255, 0, 255, 0)); + MeshShader::ViewFrustrumShader::setUniforms(video::SColor(255, 0, 255, 0), i); glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0); } From bd6c8c4839a64c21cb28cb097fce6fef05be7621 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Wed, 18 Jun 2014 00:43:41 +0200 Subject: [PATCH 05/30] Fix shadowdebug not using right viewfrustrum --- src/graphics/irr_driver.hpp | 2 +- src/graphics/render.cpp | 68 +++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index 393180ab5..48ceb741d 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -345,7 +345,7 @@ private: class STKMeshSceneNode *m_sun_interposer; scene::CLensFlareSceneNode *m_lensflare; scene::ICameraSceneNode *m_suncam; - scene::ICameraSceneNode *m_shadows_cam[3]; + float m_shadows_cam[4][24]; std::vector m_glowing; diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index df8fe46e3..cfb4a600b 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -711,7 +711,34 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz camnode->setFarValue(FarValues[i]); camnode->setNearValue(NearValues[i]); camnode->render(); - m_shadows_cam[i] = camnode; + const scene::SViewFrustum *frustrum = camnode->getViewFrustum(); + float tmp[24] = { + frustrum->getFarLeftDown().X, + frustrum->getFarLeftDown().Y, + frustrum->getFarLeftDown().Z, + frustrum->getFarLeftUp().X, + frustrum->getFarLeftUp().Y, + frustrum->getFarLeftUp().Z, + frustrum->getFarRightDown().X, + frustrum->getFarRightDown().Y, + frustrum->getFarRightDown().Z, + frustrum->getFarRightUp().X, + frustrum->getFarRightUp().Y, + frustrum->getFarRightUp().Z, + frustrum->getNearLeftDown().X, + frustrum->getNearLeftDown().Y, + frustrum->getNearLeftDown().Z, + frustrum->getNearLeftUp().X, + frustrum->getNearLeftUp().Y, + frustrum->getNearLeftUp().Z, + frustrum->getNearRightDown().X, + frustrum->getNearRightDown().Y, + frustrum->getNearRightDown().Z, + frustrum->getNearRightUp().X, + frustrum->getNearRightUp().Y, + frustrum->getNearRightUp().Z, + }; + memcpy(m_shadows_cam[i], tmp, 24 * sizeof(float)); const core::aabbox3df smallcambox = camnode-> getViewFrustum()->getBoundingBox(); core::aabbox3df trackbox(vmin->toIrrVector(), vmax->toIrrVector() - @@ -829,38 +856,13 @@ void IrrDriver::renderShadows() } } -static void renderWireFrameFrustrum(const scene::SViewFrustum *frustrum, unsigned i) +static void renderWireFrameFrustrum(float *tmp, unsigned i) { glUseProgram(MeshShader::ViewFrustrumShader::Program); glBindVertexArray(MeshShader::ViewFrustrumShader::frustrumvao); glBindBuffer(GL_ARRAY_BUFFER, SharedObject::frustrumvbo); - float tmp[24] = { - frustrum->getFarLeftDown().X, - frustrum->getFarLeftDown().Y, - frustrum->getFarLeftDown().Z, - frustrum->getFarLeftUp().X, - frustrum->getFarLeftUp().Y, - frustrum->getFarLeftUp().Z, - frustrum->getFarRightDown().X, - frustrum->getFarRightDown().Y, - frustrum->getFarRightDown().Z, - frustrum->getFarRightUp().X, - frustrum->getFarRightUp().Y, - frustrum->getFarRightUp().Z, - frustrum->getNearLeftDown().X, - frustrum->getNearLeftDown().Y, - frustrum->getNearLeftDown().Z, - frustrum->getNearLeftUp().X, - frustrum->getNearLeftUp().Y, - frustrum->getNearLeftUp().Z, - frustrum->getNearRightDown().X, - frustrum->getNearRightDown().Y, - frustrum->getNearRightDown().Z, - frustrum->getNearRightUp().X, - frustrum->getNearRightUp().Y, - frustrum->getNearRightUp().Z, - }; - glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * 3 * sizeof(float), tmp); + + glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * 3 * sizeof(float), (void *)tmp); MeshShader::ViewFrustrumShader::setUniforms(video::SColor(255, 0, 255, 0), i); glDrawElements(GL_LINES, 24, GL_UNSIGNED_INT, 0); } @@ -871,16 +873,16 @@ void IrrDriver::renderShadowsDebug() glBindFramebuffer(GL_FRAMEBUFFER, 0); glViewport(0, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 0); - renderWireFrameFrustrum(m_shadows_cam[0]->getViewFrustum(), 0); + renderWireFrameFrustrum(m_shadows_cam[0], 0); glViewport(UserConfigParams::m_width / 2, UserConfigParams::m_height / 2, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 1); - renderWireFrameFrustrum(m_shadows_cam[1]->getViewFrustum(), 1); + renderWireFrameFrustrum(m_shadows_cam[1], 1); glViewport(0, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 2); - renderWireFrameFrustrum(m_shadows_cam[2]->getViewFrustum(), 2); + renderWireFrameFrustrum(m_shadows_cam[2], 2); glViewport(UserConfigParams::m_width / 2, 0, UserConfigParams::m_width / 2, UserConfigParams::m_height / 2); m_post_processing->renderTextureLayer(m_rtts->getShadowDepthTex(), 3); - renderWireFrameFrustrum(m_shadows_cam[3]->getViewFrustum(), 3); + renderWireFrameFrustrum(m_shadows_cam[3], 3); glViewport(0, 0, UserConfigParams::m_width, UserConfigParams::m_height); } From 78864c5df0dbd58a3329c24346043ed1be6e4a92 Mon Sep 17 00:00:00 2001 From: hiker Date: Fri, 20 Jun 2014 15:44:59 +1000 Subject: [PATCH 06/30] Removed unused variables. --- src/guiengine/skin.hpp | 4 +--- src/states_screens/race_result_gui.hpp | 6 ------ 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/guiengine/skin.hpp b/src/guiengine/skin.hpp index f13a5066a..7228cedaa 100644 --- a/src/guiengine/skin.hpp +++ b/src/guiengine/skin.hpp @@ -270,9 +270,7 @@ namespace GUIEngine video::ITexture* bg_image; std::vector m_tooltips; std::vector m_tooltip_at_mouse; -#ifdef USE_PER_LINE_BACKGROUND - public: -#endif + LEAK_CHECK() void drawBoxFromStretchableTexture(SkinWidgetContainer* w, diff --git a/src/states_screens/race_result_gui.hpp b/src/states_screens/race_result_gui.hpp index a24e975a2..3019461ab 100644 --- a/src/states_screens/race_result_gui.hpp +++ b/src/states_screens/race_result_gui.hpp @@ -101,12 +101,6 @@ private: video::ITexture *m_kart_icon; /** The times of all karts in the right order. */ core::stringw m_finish_time_string; -#ifdef USE_PER_LINE_BACKGROUND - /** For the background bar behind each line. */ - GUIEngine::SkinWidgetContainer m_widget_container; - /** The parameter for rendering the background box. */ - GUIEngine::BoxRenderParams m_box_params; -#endif }; // Rowinfo /** The team icons. */ From 4c9d1888f89fc84baa2059640cb538b7413a5ce0 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Fri, 20 Jun 2014 22:52:19 +0200 Subject: [PATCH 07/30] Factorize transparent mesh rendering. --- src/graphics/render.cpp | 23 ++++++++++++++++++++ src/graphics/stkanimatedmesh.cpp | 28 ++++++------------------ src/graphics/stkmesh.hpp | 19 ++++++++++++++++ src/graphics/stkmeshscenenode.cpp | 36 +++++++++++-------------------- 4 files changed, 62 insertions(+), 44 deletions(-) diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index b7647a38c..89a1b46aa 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -648,7 +648,30 @@ void IrrDriver::renderTransparent() glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glDisable(GL_CULL_FACE); + TransparentMeshes::reset(); + TransparentMeshes::reset(); m_scene_manager->drawAll(scene::ESNRP_TRANSPARENT); + + if (World::getWorld() && World::getWorld()->isFogEnabled()) + { + glUseProgram(MeshShader::TransparentFogShader::Program); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + for (unsigned i = 0; i < TransparentMeshes::MeshSet.size(); i++) + drawTransparentFogObject(*TransparentMeshes::MeshSet[i], TransparentMeshes::MVPSet[i], TransparentMeshes::MeshSet[i]->TextureMatrix); + glBlendFunc(GL_ONE, GL_ONE); + for (unsigned i = 0; i < TransparentMeshes::MeshSet.size(); i++) + drawTransparentFogObject(*TransparentMeshes::MeshSet[i], TransparentMeshes::MVPSet[i], TransparentMeshes::MeshSet[i]->TextureMatrix); + } + else + { + glUseProgram(MeshShader::TransparentShader::Program); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + for (unsigned i = 0; i < TransparentMeshes::MeshSet.size(); i++) + drawTransparentObject(*TransparentMeshes::MeshSet[i], TransparentMeshes::MVPSet[i], TransparentMeshes::MeshSet[i]->TextureMatrix); + glBlendFunc(GL_ONE, GL_ONE); + for (unsigned i = 0; i < TransparentMeshes::MeshSet.size(); i++) + drawTransparentObject(*TransparentMeshes::MeshSet[i], TransparentMeshes::MVPSet[i], TransparentMeshes::MeshSet[i]->TextureMatrix); + } } void IrrDriver::renderParticles() diff --git a/src/graphics/stkanimatedmesh.cpp b/src/graphics/stkanimatedmesh.cpp index 91769e262..b4464a46c 100644 --- a/src/graphics/stkanimatedmesh.cpp +++ b/src/graphics/stkanimatedmesh.cpp @@ -227,30 +227,16 @@ void STKAnimatedMesh::render() glUseProgram(MeshShader::BubbleShader::Program); GLMesh* mesh; - for_in(mesh, TransparentMesh[TM_BUBBLE]) - drawBubble(*mesh, ModelViewProjectionMatrix); - - if (World::getWorld() != NULL && World::getWorld()->isFogEnabled()) + for_in(mesh, TransparentMesh[TM_DEFAULT]) { - if (!TransparentMesh[TM_DEFAULT].empty() || !TransparentMesh[TM_ADDITIVE].empty()) - glUseProgram(MeshShader::TransparentFogShader::Program); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - for_in(mesh, TransparentMesh[TM_DEFAULT]) - drawTransparentFogObject(*mesh, ModelViewProjectionMatrix, mesh->TextureMatrix); - glBlendFunc(GL_ONE, GL_ONE); - for_in(mesh, TransparentMesh[TM_ADDITIVE]) - drawTransparentFogObject(*mesh, ModelViewProjectionMatrix, mesh->TextureMatrix); + TransparentMeshes::MeshSet.push_back(mesh); + TransparentMeshes::MVPSet.push_back(ModelViewProjectionMatrix); } - else + + for_in(mesh, TransparentMesh[TM_ADDITIVE]) { - if (!TransparentMesh[TM_DEFAULT].empty() || !TransparentMesh[TM_ADDITIVE].empty()) - glUseProgram(MeshShader::TransparentShader::Program); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - for_in(mesh, TransparentMesh[TM_DEFAULT]) - drawTransparentObject(*mesh, ModelViewProjectionMatrix, mesh->TextureMatrix); - glBlendFunc(GL_ONE, GL_ONE); - for_in(mesh, TransparentMesh[TM_ADDITIVE]) - drawTransparentObject(*mesh, ModelViewProjectionMatrix, mesh->TextureMatrix); + TransparentMeshes::MeshSet.push_back(mesh); + TransparentMeshes::MVPSet.push_back(ModelViewProjectionMatrix); } return; } diff --git a/src/graphics/stkmesh.hpp b/src/graphics/stkmesh.hpp index a7e0fb19d..c16e075b0 100644 --- a/src/graphics/stkmesh.hpp +++ b/src/graphics/stkmesh.hpp @@ -147,6 +147,25 @@ void drawObjectUnlit(const GLMesh &mesh, const core::matrix4 &ModelViewProjectio void drawShadowRef(const GLMesh &mesh, const core::matrix4 &ModelMatrix); void drawShadow(const GLMesh &mesh, const core::matrix4 &ModelMatrix); +template +class TransparentMeshes +{ +public: + static std::vector MeshSet; + static std::vector MVPSet; + + static void reset() + { + MeshSet.clear(); + MVPSet.clear(); + } +}; + +template +std::vector TransparentMeshes::MeshSet; +template +std::vector TransparentMeshes::MVPSet; + // Forward pass (for transparents meshes) void drawTransparentObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); void drawTransparentFogObject(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TextureMatrix); diff --git a/src/graphics/stkmeshscenenode.cpp b/src/graphics/stkmeshscenenode.cpp index 0ecf8586d..07d9b0bd0 100644 --- a/src/graphics/stkmeshscenenode.cpp +++ b/src/graphics/stkmeshscenenode.cpp @@ -440,33 +440,23 @@ void STKMeshSceneNode::render() ModelViewProjectionMatrix = computeMVP(AbsoluteTransformation); GLMesh* mesh; + + for_in(mesh, TransparentMesh[TM_DEFAULT]) + { + TransparentMeshes::MeshSet.push_back(mesh); + TransparentMeshes::MVPSet.push_back(ModelViewProjectionMatrix); + } + + for_in(mesh, TransparentMesh[TM_ADDITIVE]) + { + TransparentMeshes::MeshSet.push_back(mesh); + TransparentMeshes::MVPSet.push_back(ModelViewProjectionMatrix); + } + if (!TransparentMesh[TM_BUBBLE].empty()) glUseProgram(MeshShader::BubbleShader::Program); for_in(mesh, TransparentMesh[TM_BUBBLE]) drawBubble(*mesh, ModelViewProjectionMatrix); - - if (World::getWorld() ->isFogEnabled()) - { - if (!TransparentMesh[TM_DEFAULT].empty() || !TransparentMesh[TM_ADDITIVE].empty()) - glUseProgram(MeshShader::TransparentFogShader::Program); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - for_in(mesh, TransparentMesh[TM_DEFAULT]) - drawTransparentFogObject(*mesh, ModelViewProjectionMatrix, (*mesh).TextureMatrix); - glBlendFunc(GL_ONE, GL_ONE); - for_in(mesh, TransparentMesh[TM_ADDITIVE]) - drawTransparentFogObject(*mesh, ModelViewProjectionMatrix, (*mesh).TextureMatrix); - } - else - { - if (!TransparentMesh[TM_DEFAULT].empty() || !TransparentMesh[TM_ADDITIVE].empty()) - glUseProgram(MeshShader::TransparentShader::Program); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - for_in(mesh, TransparentMesh[TM_DEFAULT]) - drawTransparentObject(*mesh, ModelViewProjectionMatrix, (*mesh).TextureMatrix); - glBlendFunc(GL_ONE, GL_ONE); - for_in(mesh, TransparentMesh[TM_ADDITIVE]) - drawTransparentObject(*mesh, ModelViewProjectionMatrix, (*mesh).TextureMatrix); - } return; } From cb161a2774fda07412a0c0ad8873034cdca7e8bb Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Fri, 20 Jun 2014 22:56:56 +0200 Subject: [PATCH 08/30] Remove code never executed. --- src/graphics/stkmeshscenenode.cpp | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/graphics/stkmeshscenenode.cpp b/src/graphics/stkmeshscenenode.cpp index 07d9b0bd0..4f97ed8c7 100644 --- a/src/graphics/stkmeshscenenode.cpp +++ b/src/graphics/stkmeshscenenode.cpp @@ -209,33 +209,9 @@ void STKMeshSceneNode::drawSolidPass2(const GLMesh &mesh, ShadedMaterial type) { switch (type) { - case SM_SPHEREMAP: - drawSphereMap(mesh, ModelViewProjectionMatrix, TransposeInverseModelView); - break; - case SM_SPLATTING: - drawSplatting(mesh, ModelViewProjectionMatrix); - break; - case SM_ALPHA_REF_TEXTURE: - drawObjectRefPass2(mesh, ModelViewProjectionMatrix, mesh.TextureMatrix); - break; case SM_GRASS: drawGrassPass2(mesh, ModelViewProjectionMatrix, windDir); break; - case SM_RIMLIT: - drawObjectRimLimit(mesh, ModelViewProjectionMatrix, TransposeInverseModelView, core::matrix4::EM4CONST_IDENTITY); - break; - case SM_UNLIT: - drawObjectUnlit(mesh, ModelViewProjectionMatrix); - break; - case SM_DETAILS: - drawDetailledObjectPass2(mesh, ModelViewProjectionMatrix); - break; - case SM_UNTEXTURED: - drawUntexturedObject(mesh, ModelViewProjectionMatrix); - break; - case SM_DEFAULT: - drawObjectPass2(mesh, ModelViewProjectionMatrix, mesh.TextureMatrix); - break; default: assert(0 && "Wrong shaded material"); break; From 71969acd228393dfbe6dc4798e0faeef9b045041 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Fri, 20 Jun 2014 23:10:31 +0200 Subject: [PATCH 09/30] Use a precomputed invmatrix in gi.frag (General) matrix inversion is costly, it's better if it's done a single time on cpu. Improve performance. --- data/shaders/gi.frag | 3 ++- src/graphics/post_processing.cpp | 4 +++- src/graphics/shaders.cpp | 5 ++++- src/graphics/shaders.hpp | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/data/shaders/gi.frag b/data/shaders/gi.frag index 92f9e0804..b6983b4f2 100644 --- a/data/shaders/gi.frag +++ b/data/shaders/gi.frag @@ -12,6 +12,7 @@ uniform sampler3D SHB; uniform float R_wcs = 10.; uniform vec3 extents; uniform mat4 RHMatrix; +uniform mat4 InvRHMatrix; layout (std140) uniform MatrixesData { @@ -55,7 +56,7 @@ void main() if (depth==1.0) discard; vec4 pos_screen_space = getPosFromUVDepth(vec3(uv, depth), InverseProjectionMatrix); - vec4 tmp = (inverse(RHMatrix) * InverseViewMatrix * pos_screen_space); + vec4 tmp = (InvRHMatrix * InverseViewMatrix * pos_screen_space); vec3 pos = tmp.xyz / tmp.w; vec3 normal_screen_space = normalize(DecodeNormal(2. * texture(ntex, uv).xy - 1.)); vec3 normal = (transpose(ViewMatrix) * vec4(normal_screen_space, 0.)).xyz; diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index fd4fc0eed..648e76301 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -244,6 +244,8 @@ void PostProcessing::renderDiffuseEnvMap(const float *bSHCoeff, const float *gSH void PostProcessing::renderGI(const core::matrix4 &RHMatrix, const core::vector3df &rh_extend, GLuint shr, GLuint shg, GLuint shb) { + core::matrix4 InvRHMatrix; + RHMatrix.getInverse(InvRHMatrix); glDisable(GL_DEPTH_TEST); glUseProgram(FullScreenShader::GlobalIlluminationReconstructionShader::Program); glBindVertexArray(FullScreenShader::GlobalIlluminationReconstructionShader::vao); @@ -267,7 +269,7 @@ void PostProcessing::renderGI(const core::matrix4 &RHMatrix, const core::vector3 } setTexture(3, irr_driver->getRenderTargetTexture(RTT_NORMAL_AND_DEPTH), GL_NEAREST, GL_NEAREST); setTexture(4, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); - FullScreenShader::GlobalIlluminationReconstructionShader::setUniforms(RHMatrix, rh_extend, 3, 4, 0, 1, 2); + FullScreenShader::GlobalIlluminationReconstructionShader::setUniforms(RHMatrix, InvRHMatrix, rh_extend, 3, 4, 0, 1, 2); glDrawArrays(GL_TRIANGLES, 0, 3); } diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 14cd9035d..1744ce8ad 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -2400,6 +2400,7 @@ namespace FullScreenShader GLuint GlobalIlluminationReconstructionShader::uniform_SHB; GLuint GlobalIlluminationReconstructionShader::uniform_extents; GLuint GlobalIlluminationReconstructionShader::uniform_RHMatrix; + GLuint GlobalIlluminationReconstructionShader::uniform_InvRHMatrix; GLuint GlobalIlluminationReconstructionShader::vao; void GlobalIlluminationReconstructionShader::init() @@ -2415,15 +2416,17 @@ namespace FullScreenShader uniform_SHG = glGetUniformLocation(Program, "SHG"); uniform_SHB = glGetUniformLocation(Program, "SHB"); uniform_RHMatrix = glGetUniformLocation(Program, "RHMatrix"); + uniform_InvRHMatrix = glGetUniformLocation(Program, "InvRHMatrix"); uniform_extents = glGetUniformLocation(Program, "extents"); vao = createFullScreenVAO(Program); GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); } - void GlobalIlluminationReconstructionShader::setUniforms(const core::matrix4 &RHMatrix, const core::vector3df &extents, unsigned TU_ntex, unsigned TU_dtex, unsigned TU_SHR, unsigned TU_SHG, unsigned TU_SHB) + void GlobalIlluminationReconstructionShader::setUniforms(const core::matrix4 &RHMatrix, const core::matrix4 &InvRHMatrix, const core::vector3df &extents, unsigned TU_ntex, unsigned TU_dtex, unsigned TU_SHR, unsigned TU_SHG, unsigned TU_SHB) { glUniformMatrix4fv(uniform_RHMatrix, 1, GL_FALSE, RHMatrix.pointer()); + glUniformMatrix4fv(uniform_InvRHMatrix, 1, GL_FALSE, InvRHMatrix.pointer()); glUniform1i(uniform_ntex, TU_ntex); glUniform1i(uniform_dtex, TU_dtex); glUniform1i(uniform_SHR, TU_SHR); diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 551275678..53089372f 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -624,11 +624,11 @@ class GlobalIlluminationReconstructionShader { public: static GLuint Program; - static GLuint uniform_ntex, uniform_dtex, uniform_extents, uniform_SHR, uniform_SHG, uniform_SHB, uniform_RHMatrix; + static GLuint uniform_ntex, uniform_dtex, uniform_extents, uniform_SHR, uniform_SHG, uniform_SHB, uniform_RHMatrix, uniform_InvRHMatrix; static GLuint vao; static void init(); - static void setUniforms(const core::matrix4 &RHMatrix, const core::vector3df &extents, unsigned TU_ntex, unsigned TU_dtex, unsigned TU_SHR, unsigned TU_SHG, unsigned TU_SHB); + static void setUniforms(const core::matrix4 &RHMatrix, const core::matrix4 &InvRHMatrix, const core::vector3df &extents, unsigned TU_ntex, unsigned TU_dtex, unsigned TU_SHR, unsigned TU_SHG, unsigned TU_SHB); }; class Gaussian17TapHShader From 1e959a0e10c133e56cab39ab234a352e0d74af83 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sat, 21 Jun 2014 18:09:22 +0200 Subject: [PATCH 10/30] Tigher fit of shadow map. --- src/graphics/render.cpp | 42 ++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index cfb4a600b..9dbcc83d6 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -748,8 +748,32 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz core::aabbox3df box = smallcambox; box = box.intersect(trackbox); - - SunCamViewMatrix.transformBoxEx(trackbox); + float xmin = INFINITY, xmax = -INFINITY; + float ymin = INFINITY, ymax = -INFINITY; + float zmin = INFINITY, zmax = -INFINITY; + const vector3df vectors[] = + { + frustrum->getFarLeftDown(), + frustrum->getFarLeftUp(), + frustrum->getFarRightDown(), + frustrum->getFarRightUp(), + frustrum->getNearLeftDown(), + frustrum->getNearLeftUp(), + frustrum->getNearRightDown(), + frustrum->getNearRightUp() + }; + for (unsigned j = 0; j < 8; j++) + { + vector3df vector; + SunCamViewMatrix.transformVect(vector, vectors[j]); + xmin = MIN2(xmin, vector.X); + xmax = MAX2(xmax, vector.X); + ymin = MIN2(ymin, vector.Y); + ymax = MAX2(ymax, vector.Y); + zmin = MIN2(zmin, vector.Z); + zmax = MAX2(zmax, vector.Z); + } +/* SunCamViewMatrix.transformBoxEx(trackbox); SunCamViewMatrix.transformBoxEx(box); core::vector3df extent = box.getExtent(); @@ -759,12 +783,12 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz // Snap to texels const float units_per_w = w / 1024; - const float units_per_h = h / 1024; + const float units_per_h = h / 1024;*/ - float left = box.MinEdge.X; - float right = box.MaxEdge.X; - float up = box.MaxEdge.Y; - float down = box.MinEdge.Y; + float left = xmin; + float right = xmax; + float up = ymin; + float down = ymax; core::matrix4 tmp_matrix; @@ -777,8 +801,8 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz } tmp_matrix.buildProjectionMatrixOrthoLH(left, right, - up, down, - 30, z); + down, up, + 30, zmax); m_suncam->setProjectionMatrix(tmp_matrix, true); m_suncam->render(); From 88a5d08e912d37768f7edb203aca44e3080b29f6 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sat, 21 Jun 2014 19:29:35 +0200 Subject: [PATCH 11/30] Report opengl vendor and renderer. --- src/graphics/irr_driver.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 2f4291056..0bf9aa5e3 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -443,7 +443,10 @@ void IrrDriver::initDevice() glGetIntegerv(GL_MAJOR_VERSION, &GLMajorVersion); glGetIntegerv(GL_MINOR_VERSION, &GLMinorVersion); } - Log::info("IrrDriver", "OPENGL VERSION IS %d.%d", GLMajorVersion, GLMinorVersion); + Log::info("IrrDriver", "OpenGL version: %d.%d", GLMajorVersion, GLMinorVersion); + Log::info("IrrDriver", "OpenGL vendor: %s", glGetString(GL_VENDOR)); + Log::info("IrrDriver", "OpenGL renderer: %s", glGetString(GL_RENDERER)); + Log::info("IrrDriver", "OpenGL version string: %s", glGetString(GL_VERSION)); m_glsl = (GLMajorVersion > 3 || (GLMajorVersion == 3 && GLMinorVersion >= 1)); // Parse extensions From 6e85ac4eab4b54beff70dde3a431aaf9069a0e96 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sat, 21 Jun 2014 19:54:12 +0200 Subject: [PATCH 12/30] Fix GI matrix generation. --- src/graphics/render.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 9dbcc83d6..e18f6a58b 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -809,7 +809,18 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz sun_ortho_matrix.push_back(getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW)); } if ((tick % 100) == 2) - rsm_matrix = sun_ortho_matrix[3]; + { + core::aabbox3df trackbox(vmin->toIrrVector(), vmax->toIrrVector() - + core::vector3df(0, 30, 0)); + SunCamViewMatrix.transformBoxEx(trackbox); + core::matrix4 tmp_matrix; + tmp_matrix.buildProjectionMatrixOrthoLH(trackbox.MinEdge.X, trackbox.MaxEdge.X, + trackbox.MaxEdge.Y, trackbox.MinEdge.Y, + 30, trackbox.MaxEdge.Z); + m_suncam->setProjectionMatrix(tmp_matrix, true); + m_suncam->render(); + rsm_matrix = getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW); + } rh_extend = core::vector3df(128, 64, 128); core::vector3df campos = camnode->getAbsolutePosition(); core::vector3df translation(8 * floor(campos.X / 8), 8 * floor(campos.Y / 8), 8 * floor(campos.Z / 8)); From 83cfe79404ff494c45411b56f57bdfa87c45688e Mon Sep 17 00:00:00 2001 From: vlj Date: Sun, 22 Jun 2014 02:12:17 +0200 Subject: [PATCH 13/30] Fix disappearing shadows --- src/karts/kart_model.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index 9870fb957..fb9772fb5 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -340,7 +340,10 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim node = irr_driver->addAnimatedMesh(m_mesh); // as animated mesh are not cheap to render use frustum box culling - node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX); + if (irr_driver->isGLSL()) + node->setAutomaticCulling(false); + else + node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX); if (always_animated) { From a7dbdc7a544b68aef748d2e1ad6c5a633abd7610 Mon Sep 17 00:00:00 2001 From: vlj Date: Sun, 22 Jun 2014 02:17:50 +0200 Subject: [PATCH 14/30] Use EAC_OFF --- src/karts/kart_model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index fb9772fb5..b95b8dbee 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -341,7 +341,7 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool always_anim node = irr_driver->addAnimatedMesh(m_mesh); // as animated mesh are not cheap to render use frustum box culling if (irr_driver->isGLSL()) - node->setAutomaticCulling(false); + node->setAutomaticCulling(scene::EAC_OFF); else node->setAutomaticCulling(scene::EAC_FRUSTUM_BOX); From 3219e564d02f801bf23341a99d9791d9e980bd11 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sat, 21 Jun 2014 00:27:23 +0200 Subject: [PATCH 15/30] Implemented bilateral for compute path. --- .../shaders/{gaussian.comp => bilateralH.comp} | 17 ++++++++++++++--- .../{gaussianv.comp => bilateralV.comp} | 18 +++++++++++++++--- src/graphics/post_processing.cpp | 12 ++++++++---- src/graphics/shaders.cpp | 8 ++++++-- src/graphics/shaders.hpp | 4 ++-- 5 files changed, 45 insertions(+), 14 deletions(-) rename data/shaders/{gaussian.comp => bilateralH.comp} (53%) rename data/shaders/{gaussianv.comp => bilateralV.comp} (53%) diff --git a/data/shaders/gaussian.comp b/data/shaders/bilateralH.comp similarity index 53% rename from data/shaders/gaussian.comp rename to data/shaders/bilateralH.comp index a5c1a3d22..1611b5d55 100644 --- a/data/shaders/gaussian.comp +++ b/data/shaders/bilateralH.comp @@ -1,20 +1,25 @@ // From http://http.developer.nvidia.com/GPUGems3/gpugems3_ch40.html uniform layout(size1x16) restrict readonly image2D source; +uniform layout(size1x32) restrict readonly image2D depth; uniform layout(size1x16) volatile restrict writeonly image2D dest; uniform float sigma = 5.; layout (local_size_x = 8, local_size_y = 8) in; shared float local_src[8 + 2 * 8][8]; +shared float local_depth[8 + 2 * 8][8]; void main() { int x = int(gl_LocalInvocationID.x), y = int(gl_LocalInvocationID.y); ivec2 uv = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); local_src[x][y] = imageLoad(source, ivec2(uv) - ivec2(8, 0)).x; + local_depth[x][y] = imageLoad(depth, ivec2(uv) - ivec2(8, 0)).x; local_src[x + 8][y] = imageLoad(source, ivec2(uv)).x; + local_depth[x + 8][y] = imageLoad(depth, ivec2(uv)).x; local_src[x + 16][y] = imageLoad(source, ivec2(uv) + ivec2(8, 0)).x; + local_depth[x + 16][y] = imageLoad(depth, ivec2(uv) + ivec2(8, 0)).x; barrier(); @@ -23,14 +28,20 @@ void main() g1 = exp(-0.5 / (sigma * sigma)); g2 = g1 * g1; float sum = local_src[x + 8][y] * g0; + float pixel_depth = local_depth[x + 8][y]; g0 *= g1; g1 *= g2; + float tmp_weight, total_weight = g0; for (int j = 1; j < 8; j++) { - sum += local_src[8 + x - j][y] * g0; - sum += local_src[8 + x + j][y] * g0; + tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[8 + x - j][y] - pixel_depth)); + total_weight += g0 * tmp_weight; + sum += local_src[8 + x - j][y] * g0 * tmp_weight; + tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[8 + x + j][y] - pixel_depth)); + total_weight += g0 * tmp_weight; + sum += local_src[8 + x + j][y] * g0 * tmp_weight; g0 *= g1; g1 *= g2; } - imageStore(dest, ivec2(uv), vec4(sum)); + imageStore(dest, ivec2(uv), vec4(sum / total_weight)); } diff --git a/data/shaders/gaussianv.comp b/data/shaders/bilateralV.comp similarity index 53% rename from data/shaders/gaussianv.comp rename to data/shaders/bilateralV.comp index 38674a61d..42338305f 100644 --- a/data/shaders/gaussianv.comp +++ b/data/shaders/bilateralV.comp @@ -1,20 +1,25 @@ // From http://http.developer.nvidia.com/GPUGems3/gpugems3_ch40.html uniform layout(size1x16) restrict readonly image2D source; +uniform layout(size1x32) restrict readonly image2D depth; uniform layout(size1x16) volatile restrict writeonly image2D dest; uniform float sigma = 5.; layout (local_size_x = 8, local_size_y = 8) in; shared float local_src[8][8 + 2 * 8]; +shared float local_depth[8][8 + 2 * 8]; void main() { int x = int(gl_LocalInvocationID.x), y = int(gl_LocalInvocationID.y); ivec2 uv = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); local_src[x][y] = imageLoad(source, ivec2(uv) - ivec2(0, 8)).x; + local_depth[x][y] = imageLoad(depth, ivec2(uv) - ivec2(0, 8)).x; local_src[x][y + 8] = imageLoad(source, ivec2(uv)).x; + local_depth[x][y + 8] = imageLoad(depth, ivec2(uv)).x; local_src[x][y + 16] = imageLoad(source, ivec2(uv) + ivec2(0, 8)).x; + local_depth[x][y + 16] = imageLoad(depth, ivec2(uv) + ivec2(0, 8)).x; barrier(); @@ -23,14 +28,21 @@ void main() g1 = exp(-0.5 / (sigma * sigma)); g2 = g1 * g1; float sum = local_src[x][y + 8] * g0; + float pixel_depth = local_depth[x][y + 8]; g0 *= g1; g1 *= g2; + float tmp_weight, total_weight = g0; for (int j = 1; j < 8; j++) { - sum += local_src[x][y + 8 + j] * g0; - sum += local_src[x][y + 8 - j] * g0; + tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 8 + j] - pixel_depth)); + sum += local_src[x][y + 8 + j] * g0 * tmp_weight; + total_weight += g0 * tmp_weight; + tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 8 - j] - pixel_depth)); + sum += local_src[x][y + 8 - j] * g0 * tmp_weight; + total_weight += g0 * tmp_weight; g0 *= g1; g1 *= g2; + } - imageStore(dest, ivec2(uv), vec4(sum)); + imageStore(dest, ivec2(uv), vec4(sum / total_weight)); } diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index 928efeac4..f13ca69c8 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -425,9 +425,11 @@ void PostProcessing::renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &a glUseProgram(FullScreenShader::ComputeGaussian17TapHShader::Program); glBindImageTexture(0, in_fbo.getRTT()[0], 0, false, 0, GL_READ_ONLY, GL_R16F); - glBindImageTexture(1, auxiliary.getRTT()[0], 0, false, 0, GL_WRITE_ONLY, GL_R16F); + glBindImageTexture(1, irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0], 1, false, 0, GL_READ_ONLY, GL_R32F); + glBindImageTexture(2, auxiliary.getRTT()[0], 0, false, 0, GL_WRITE_ONLY, GL_R16F); glUniform1i(FullScreenShader::ComputeGaussian17TapHShader::uniform_source, 0); - glUniform1i(FullScreenShader::ComputeGaussian17TapHShader::uniform_dest, 1); + glUniform1i(FullScreenShader::ComputeGaussian17TapHShader::uniform_depth, 1); + glUniform1i(FullScreenShader::ComputeGaussian17TapHShader::uniform_dest, 2); glDispatchCompute(in_fbo.getWidth() / 8, in_fbo.getHeight() / 8, 1); } #endif @@ -455,9 +457,11 @@ void PostProcessing::renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &a { glUseProgram(FullScreenShader::ComputeGaussian17TapVShader::Program); glBindImageTexture(0, auxiliary.getRTT()[0], 0, false, 0, GL_READ_ONLY, GL_R16F); - glBindImageTexture(1, in_fbo.getRTT()[0], 0, false, 0, GL_WRITE_ONLY, GL_R16F); + glBindImageTexture(1, irr_driver->getFBO(FBO_LINEAR_DEPTH).getRTT()[0], 1, false, 0, GL_READ_ONLY, GL_R32F); + glBindImageTexture(2, in_fbo.getRTT()[0], 0, false, 0, GL_WRITE_ONLY, GL_R16F); glUniform1i(FullScreenShader::ComputeGaussian17TapVShader::uniform_source, 0); - glUniform1i(FullScreenShader::ComputeGaussian17TapVShader::uniform_dest, 1); + glUniform1i(FullScreenShader::ComputeGaussian17TapVShader::uniform_depth, 1); + glUniform1i(FullScreenShader::ComputeGaussian17TapVShader::uniform_dest, 2); glDispatchCompute(in_fbo.getWidth() / 8, in_fbo.getHeight() / 8, 1); } #endif diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index efaa65ad2..1014704e2 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -2509,13 +2509,15 @@ namespace FullScreenShader GLuint ComputeGaussian17TapHShader::Program; GLuint ComputeGaussian17TapHShader::uniform_source; + GLuint ComputeGaussian17TapHShader::uniform_depth; GLuint ComputeGaussian17TapHShader::uniform_dest; void ComputeGaussian17TapHShader::init() { #if WIN32 Program = LoadProgram( - GL_COMPUTE_SHADER, file_manager->getAsset("shaders/gaussian.comp").c_str()); + GL_COMPUTE_SHADER, file_manager->getAsset("shaders/bilateralH.comp").c_str()); uniform_source = glGetUniformLocation(Program, "source"); + uniform_depth = glGetUniformLocation(Program, "depth"); uniform_dest = glGetUniformLocation(Program, "dest"); #endif } @@ -2564,13 +2566,15 @@ namespace FullScreenShader GLuint ComputeGaussian17TapVShader::Program; GLuint ComputeGaussian17TapVShader::uniform_source; + GLuint ComputeGaussian17TapVShader::uniform_depth; GLuint ComputeGaussian17TapVShader::uniform_dest; void ComputeGaussian17TapVShader::init() { #if WIN32 Program = LoadProgram( - GL_COMPUTE_SHADER, file_manager->getAsset("shaders/gaussianv.comp").c_str()); + GL_COMPUTE_SHADER, file_manager->getAsset("shaders/bilateralV.comp").c_str()); uniform_source = glGetUniformLocation(Program, "source"); + uniform_depth = glGetUniformLocation(Program, "depth"); uniform_dest = glGetUniformLocation(Program, "dest"); #endif } diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 26e955545..6aed8e7df 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -657,7 +657,7 @@ class ComputeGaussian17TapHShader { public: static GLuint Program; - static GLuint uniform_source, uniform_dest; + static GLuint uniform_source, uniform_depth, uniform_dest; static void init(); }; @@ -696,7 +696,7 @@ class ComputeGaussian17TapVShader { public: static GLuint Program; - static GLuint uniform_source, uniform_dest; + static GLuint uniform_source, uniform_depth, uniform_dest; static void init(); }; From 8f5dd6edae9bb6d744e98322805ea3457074c7ab Mon Sep 17 00:00:00 2001 From: vlj Date: Sat, 21 Jun 2014 01:26:05 +0200 Subject: [PATCH 16/30] Some tweak to ssao. --- data/shaders/ssao.frag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/shaders/ssao.frag b/data/shaders/ssao.frag index 5241ff764..5409be0fb 100644 --- a/data/shaders/ssao.frag +++ b/data/shaders/ssao.frag @@ -24,12 +24,12 @@ layout (std140) uniform MatrixesData out float AO; -const float sigma = 1.; +const float sigma = 2.; const float tau = 7.; const float beta = 0.001; const float epsilon = .00001; const float radius = 1.; -const float k = 1.5; +const float k = 5.; #define SAMPLES 16 From f76cd6e7a903bc26d1d123eea178d02c15b56d9a Mon Sep 17 00:00:00 2001 From: vlj Date: Sun, 22 Jun 2014 18:02:30 +0200 Subject: [PATCH 17/30] Implement bilateral with fragment codepath. --- data/shaders/bilateralH.frag | 37 +++++++++++++++++++++++++++++++ data/shaders/bilateralV.frag | 38 ++++++++++++++++++++++++++++++++ data/shaders/gaussian17taph.frag | 30 ------------------------- data/shaders/gaussian17tapv.frag | 31 -------------------------- src/graphics/post_processing.cpp | 8 +++++++ src/graphics/shaders.cpp | 8 +++++-- src/graphics/shaders.hpp | 4 ++-- 7 files changed, 91 insertions(+), 65 deletions(-) create mode 100644 data/shaders/bilateralH.frag create mode 100644 data/shaders/bilateralV.frag delete mode 100644 data/shaders/gaussian17taph.frag delete mode 100644 data/shaders/gaussian17tapv.frag diff --git a/data/shaders/bilateralH.frag b/data/shaders/bilateralH.frag new file mode 100644 index 000000000..283578d28 --- /dev/null +++ b/data/shaders/bilateralH.frag @@ -0,0 +1,37 @@ +// From http://http.developer.nvidia.com/GPUGems3/gpugems3_ch40.html + +uniform sampler2D tex; +uniform sampler2D depth; +uniform vec2 pixel; +uniform float sigma = 5.; + +out vec4 FragColor; + +void main() +{ + vec2 uv = gl_FragCoord.xy * pixel; + float X = uv.x; + float Y = uv.y; + + float g0, g1, g2; + g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma); + g1 = exp(-0.5 / (sigma * sigma)); + g2 = g1 * g1; + vec4 sum = texture(tex, vec2(X, Y)) * g0; + float pixel_depth = texture(depth, vec2(X, Y)).x; + g0 *= g1; + g1 *= g2; + float tmp_weight, total_weight = g0; + for (int i = 1; i < 9; i++) { + tmp_weight = max(0.0, 1.0 - .001 * abs(texture(depth, vec2(X - i * pixel.x, Y)).x - pixel_depth)); + sum += texture(tex, vec2(X - i * pixel.x, Y)) * g0 * tmp_weight; + total_weight += g0 * tmp_weight; + tmp_weight = max(0.0, 1.0 - .001 * abs(texture(depth, vec2(X + i * pixel.x, Y)).x - pixel_depth)); + sum += texture(tex, vec2(X + i * pixel.x, Y)) * g0 * tmp_weight; + total_weight += g0 * tmp_weight; + g0 *= g1; + g1 *= g2; + } + + FragColor = sum / total_weight; +} diff --git a/data/shaders/bilateralV.frag b/data/shaders/bilateralV.frag new file mode 100644 index 000000000..c34218844 --- /dev/null +++ b/data/shaders/bilateralV.frag @@ -0,0 +1,38 @@ +// From http://http.developer.nvidia.com/GPUGems3/gpugems3_ch40.html + +uniform sampler2D tex; +uniform sampler2D depth; +uniform vec2 pixel; +uniform float sigma = 5.; + +out vec4 FragColor; + +void main() +{ + vec2 uv = gl_FragCoord.xy * pixel; + float X = uv.x; + float Y = uv.y; + + float g0, g1, g2; + g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma); + g1 = exp(-0.5 / (sigma * sigma)); + g2 = g1 * g1; + vec4 sum = texture(tex, vec2(X, Y)) * g0; + float pixel_depth = texture(depth, vec2(X, Y)).x; + g0 *= g1; + g1 *= g2; + float tmp_weight, total_weight = g0; + for (int i = 1; i < 9; i++) { + tmp_weight = max(0.0, 1.0 - .001 * abs(texture(depth, vec2(X, Y - i * pixel.y)).x - pixel_depth)); + sum += texture(tex, vec2(X, Y - i * pixel.y)) * g0 * tmp_weight; + total_weight += g0 * tmp_weight; + tmp_weight = max(0.0, 1.0 - .001 * abs(texture(depth, vec2(X, Y + i * pixel.y)).x - pixel_depth)); + sum += texture(tex, vec2(X, Y + i * pixel.y)) * g0 * tmp_weight; + total_weight += g0 * tmp_weight; + g0 *= g1; + g1 *= g2; + } + + FragColor = sum / total_weight; +} + diff --git a/data/shaders/gaussian17taph.frag b/data/shaders/gaussian17taph.frag deleted file mode 100644 index 6ac30cd54..000000000 --- a/data/shaders/gaussian17taph.frag +++ /dev/null @@ -1,30 +0,0 @@ -// From http://http.developer.nvidia.com/GPUGems3/gpugems3_ch40.html - -uniform sampler2D tex; -uniform vec2 pixel; -uniform float sigma = 5.; - -out vec4 FragColor; - -void main() -{ - vec2 uv = gl_FragCoord.xy * pixel; - float X = uv.x; - float Y = uv.y; - - float g0, g1, g2; - g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma); - g1 = exp(-0.5 / (sigma * sigma)); - g2 = g1 * g1; - vec4 sum = texture(tex, vec2(X, Y)) * g0; - g0 *= g1; - g1 *= g2; - for (int i = 1; i < 9; i++) { - sum += texture(tex, vec2(X - i * pixel.x, Y)) * g0; - sum += texture(tex, vec2(X + i * pixel.x, Y)) * g0; - g0 *= g1; - g1 *= g2; - } - - FragColor = sum; -} diff --git a/data/shaders/gaussian17tapv.frag b/data/shaders/gaussian17tapv.frag deleted file mode 100644 index 59c2c05ab..000000000 --- a/data/shaders/gaussian17tapv.frag +++ /dev/null @@ -1,31 +0,0 @@ -// From http://http.developer.nvidia.com/GPUGems3/gpugems3_ch40.html - -uniform sampler2D tex; -uniform vec2 pixel; -uniform float sigma = 5.; - -out vec4 FragColor; - -void main() -{ - vec2 uv = gl_FragCoord.xy * pixel; - float X = uv.x; - float Y = uv.y; - - float g0, g1, g2; - g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma); - g1 = exp(-0.5 / (sigma * sigma)); - g2 = g1 * g1; - vec4 sum = texture(tex, vec2(X, Y)) * g0; - g0 *= g1; - g1 *= g2; - for (int i = 1; i < 9; i++) { - sum += texture(tex, vec2(X, Y - i * pixel.y)) * g0; - sum += texture(tex, vec2(X, Y + i * pixel.y)) * g0; - g0 *= g1; - g1 *= g2; - } - - FragColor = sum; -} - diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index f13ca69c8..d1822ce6a 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -415,7 +415,11 @@ void PostProcessing::renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &a setTexture(0, in_fbo.getRTT()[0], GL_LINEAR, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + setTexture(1, irr_driver->getDepthStencilTexture(), GL_LINEAR, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glUniform1i(FullScreenShader::Gaussian17TapHShader::uniform_tex, 0); + glUniform1i(FullScreenShader::Gaussian17TapHShader::uniform_depth, 1); glDrawArrays(GL_TRIANGLES, 0, 3); } @@ -448,7 +452,11 @@ void PostProcessing::renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &a setTexture(0, auxiliary.getRTT()[0], GL_LINEAR, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + setTexture(1, irr_driver->getDepthStencilTexture(), GL_LINEAR, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glUniform1i(FullScreenShader::Gaussian17TapVShader::uniform_tex, 0); + glUniform1i(FullScreenShader::Gaussian17TapVShader::uniform_depth, 1); glDrawArrays(GL_TRIANGLES, 0, 3); } diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 1014704e2..1d8bf1eb3 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -2495,15 +2495,17 @@ namespace FullScreenShader GLuint Gaussian17TapHShader::Program; GLuint Gaussian17TapHShader::uniform_tex; + GLuint Gaussian17TapHShader::uniform_depth; GLuint Gaussian17TapHShader::uniform_pixel; GLuint Gaussian17TapHShader::vao; void Gaussian17TapHShader::init() { Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/gaussian17taph.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/bilateralH.frag").c_str()); uniform_tex = glGetUniformLocation(Program, "tex"); uniform_pixel = glGetUniformLocation(Program, "pixel"); + uniform_depth = glGetUniformLocation(Program, "depth"); vao = createFullScreenVAO(Program); } @@ -2552,15 +2554,17 @@ namespace FullScreenShader GLuint Gaussian17TapVShader::Program; GLuint Gaussian17TapVShader::uniform_tex; + GLuint Gaussian17TapVShader::uniform_depth; GLuint Gaussian17TapVShader::uniform_pixel; GLuint Gaussian17TapVShader::vao; void Gaussian17TapVShader::init() { Program = LoadProgram( GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), - GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/gaussian17tapv.frag").c_str()); + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/bilateralV.frag").c_str()); uniform_tex = glGetUniformLocation(Program, "tex"); uniform_pixel = glGetUniformLocation(Program, "pixel"); + uniform_depth = glGetUniformLocation(Program, "depth"); vao = createFullScreenVAO(Program); } diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 6aed8e7df..e1f3ae6ea 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -647,7 +647,7 @@ class Gaussian17TapHShader { public: static GLuint Program; - static GLuint uniform_tex, uniform_pixel; + static GLuint uniform_tex, uniform_depth, uniform_pixel; static GLuint vao; static void init(); @@ -686,7 +686,7 @@ class Gaussian17TapVShader { public: static GLuint Program; - static GLuint uniform_tex, uniform_pixel; + static GLuint uniform_tex, uniform_depth, uniform_pixel; static GLuint vao; static void init(); From aaee62ca820beb72d62139ede6fa633d5c90db99 Mon Sep 17 00:00:00 2001 From: vlj Date: Sun, 22 Jun 2014 18:08:26 +0200 Subject: [PATCH 18/30] Reverse delete order of fbo. Should be safer. --- src/graphics/rtts.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/graphics/rtts.cpp b/src/graphics/rtts.cpp index 907394453..7151bb3c7 100644 --- a/src/graphics/rtts.cpp +++ b/src/graphics/rtts.cpp @@ -265,20 +265,19 @@ RTT::~RTT() glDeleteTextures(1, &DepthStencilTexture); if (UserConfigParams::m_shadows) { + delete m_shadow_FBO; glDeleteTextures(1, &shadowColorTex); glDeleteTextures(1, &shadowDepthTex); } if (UserConfigParams::m_gi) { + delete m_RH_FBO; + delete m_RSM; glDeleteTextures(1, &RSM_Color); glDeleteTextures(1, &RSM_Normal); glDeleteTextures(1, &RSM_Depth); glDeleteTextures(1, &RH_Red); glDeleteTextures(1, &RH_Green); glDeleteTextures(1, &RH_Blue); - - delete m_shadow_FBO; - delete m_RH_FBO; - delete m_RSM; } } From a461a1f807f3e61f58759d94293acebd43762386 Mon Sep 17 00:00:00 2001 From: vlj Date: Mon, 23 Jun 2014 00:12:39 +0200 Subject: [PATCH 19/30] Remove tick for GI. --- src/graphics/render.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 6c890d65f..65cd195a9 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -689,8 +689,6 @@ void IrrDriver::renderParticles() void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, size_t width, size_t height) { - static int tick = 0; - tick++; m_scene_manager->drawAll(scene::ESNRP_CAMERA); irr_driver->setProjMatrix(irr_driver->getVideoDriver()->getTransform(video::ETS_PROJECTION)); irr_driver->setViewMatrix(irr_driver->getVideoDriver()->getTransform(video::ETS_VIEW)); @@ -831,7 +829,7 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz sun_ortho_matrix.push_back(getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW)); } - if ((tick % 100) == 2) + { core::aabbox3df trackbox(vmin->toIrrVector(), vmax->toIrrVector() - core::vector3df(0, 30, 0)); From be26ac7213b8c3792793a9544773360d77b4c652 Mon Sep 17 00:00:00 2001 From: vlj Date: Mon, 23 Jun 2014 00:24:02 +0200 Subject: [PATCH 20/30] Fix crash with intel --- src/graphics/rtts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/rtts.cpp b/src/graphics/rtts.cpp index 7151bb3c7..4f4a4627d 100644 --- a/src/graphics/rtts.cpp +++ b/src/graphics/rtts.cpp @@ -42,7 +42,7 @@ static GLuint generateRTT(const core::dimension2du &res, GLint internalFormat, G glGenTextures(1, &result); glBindTexture(GL_TEXTURE_2D, result); #if WIN32 - if (irr_driver->getGLSLVersion() < 420) + if (irr_driver->getGLSLVersion() >= 420) glTexStorage2D(GL_TEXTURE_2D, mipmaplevel, internalFormat, res.Width, res.Height); else #endif From d2fc2581245f3524b680a636f8bb4e1fad3dd9f1 Mon Sep 17 00:00:00 2001 From: vlj Date: Mon, 23 Jun 2014 01:03:55 +0200 Subject: [PATCH 21/30] Tweak ssao (again) Random factor is less perdicable, no more spiral. --- data/shaders/ssao.frag | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/shaders/ssao.frag b/data/shaders/ssao.frag index 5409be0fb..445de5388 100644 --- a/data/shaders/ssao.frag +++ b/data/shaders/ssao.frag @@ -24,12 +24,12 @@ layout (std140) uniform MatrixesData out float AO; -const float sigma = 2.; +const float sigma = 1.; const float tau = 7.; const float beta = 0.001; const float epsilon = .00001; const float radius = 1.; -const float k = 5.; +const float k = 1.5; #define SAMPLES 16 @@ -56,7 +56,7 @@ void main(void) vec3 norm = -normalize(cross(ddy, ddx)); float r = radius / FragPos.z; - float phi = 30. * (x ^ y) + 10. * x * y; + float phi = 3. * (x ^ y) + x * y; float bl = 0.0; float m = log2(r) + 6 + log2(invSamples); From 6231e618d8dd5bc5488880e12117fa6a149fd417 Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 23 Jun 2014 09:13:44 +1000 Subject: [PATCH 22/30] Added new message system to show achievements in race (and not as a dialog later). Work in progress ... it doesn't look particulary nice yet ;) --- data/skins/Ocean.stkskin | 8 ++ data/skins/Peach.stkskin | 8 ++ src/achievements/achievement.cpp | 5 +- src/guiengine/engine.cpp | 3 + src/guiengine/message_queue.cpp | 161 +++++++++++++++++++++++++++ src/guiengine/message_queue.hpp | 41 +++++++ src/guiengine/skin.cpp | 14 +++ src/guiengine/skin.hpp | 4 +- src/online/online_player_profile.cpp | 13 +-- 9 files changed, 243 insertions(+), 14 deletions(-) create mode 100755 src/guiengine/message_queue.cpp create mode 100644 src/guiengine/message_queue.hpp diff --git a/data/skins/Ocean.stkskin b/data/skins/Ocean.stkskin index 890138cc0..4318a6083 100644 --- a/data/skins/Ocean.stkskin +++ b/data/skins/Ocean.stkskin @@ -68,6 +68,14 @@ when the border that intersect at this corner are enabled. + + + + diff --git a/data/skins/Peach.stkskin b/data/skins/Peach.stkskin index 5951a560c..d5c7bb408 100644 --- a/data/skins/Peach.stkskin +++ b/data/skins/Peach.stkskin @@ -68,6 +68,14 @@ when the border that intersect at this corner are enabled. + + + + diff --git a/src/achievements/achievement.cpp b/src/achievements/achievement.cpp index bdc33591d..29f9bc2d8 100644 --- a/src/achievements/achievement.cpp +++ b/src/achievements/achievement.cpp @@ -21,7 +21,7 @@ #include "achievements/achievement.hpp" #include "achievements/achievement_info.hpp" -#include "guiengine/dialog_queue.hpp" +#include "guiengine/message_queue.hpp" #include "io/utf_writer.hpp" #include "config/player_manager.hpp" #include "states_screens/dialogs/notification_dialog.hpp" @@ -202,8 +202,7 @@ void Achievement::check() //show achievement core::stringw s = StringUtils::insertValues(_("Completed achievement \"%s\"."), m_achievement_info->getTitle()); - GUIEngine::DialogQueue::get()->pushDialog( - new NotificationDialog(NotificationDialog::T_Achievements, s)); + MessageQueue::add(MessageQueue::MT_ACHIEVEMENT, s); // Sends a confirmation to the server that an achievement has been // completed, if a user is signed in. diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index 2126d1f19..b1903c1d3 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -662,6 +662,7 @@ namespace GUIEngine #include "io/file_manager.hpp" #include "guiengine/event_handler.hpp" #include "guiengine/modaldialog.hpp" +#include "guiengine/message_queue.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/skin.hpp" @@ -1189,6 +1190,8 @@ namespace GUIEngine // further render) g_env->drawAll(); + MessageQueue::update(elapsed_time); + // ---- some menus may need updating if (gamestate != GAME) { diff --git a/src/guiengine/message_queue.cpp b/src/guiengine/message_queue.cpp new file mode 100755 index 000000000..ff938ea16 --- /dev/null +++ b/src/guiengine/message_queue.cpp @@ -0,0 +1,161 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2014 Joerg Henrichs +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/** + \page addons Addons + */ + +#include "guiengine/message_queue.hpp" + +#include "config/user_config.hpp" +#include "guiengine/engine.hpp" +#include "guiengine/scalable_font.hpp" +#include "guiengine/skin.hpp" + +#include "IGUIElement.h" + +using namespace GUIEngine; + +namespace MessageQueue +{ + +/** A small helper class to store and sort messages to be displayed. */ +class Message +{ +private: + /** The type of the message. */ + MessageQueue::MessageType m_message_type; + /** The message. */ + core::stringw m_message; + +public: + Message(MessageQueue::MessageType mt, const core::stringw &message) + { + m_message_type = mt; + m_message = message; + } // Message + // -------------------------------------------------------------------- + bool operator<(const Message &rhs) const + { + return m_message_type < rhs.m_message_type; + } // operator() + // -------------------------------------------------------------------- + /** Returns the message. */ + const core::stringw & getMessage() const { return m_message; } + // -------------------------------------------------------------------- + MessageQueue::MessageType getMessageType() const { return m_message_type; } +}; // class Message + +// ============================================================================ +/** A function class to compare messages, required for priority_queue. */ +class CompareMessages +{ +public: + bool operator() (const Message *a, const Message *b) const + { + return a->getMessageType() < b->getMessageType(); + } // operator () +}; // operator() + + +// ============================================================================ +/** List of all messages. */ +std::priority_queue, + CompareMessages> g_all_messages; + +/** How long the current message has been displayed. */ +float g_current_display_time = -1.0f; + +/** How long the current message should be displaed. */ +float g_max_display_time = -1.0f; + +/** The label widget used to show the current message. */ +SkinWidgetContainer *g_container = NULL; +core::recti g_area; + +// ============================================================================ + +void createLabel(const Message *message) +{ + if(!g_container) + g_container = new SkinWidgetContainer(); + + gui::ScalableFont *font = GUIEngine::getFont(); + core::dimension2du dim = font->getDimension(message->getMessage().c_str()); + + g_current_display_time = 0.0f; + // Maybe make this time dependent on message length as well? + g_max_display_time = 5.0f; + int x = (UserConfigParams::m_width - dim.Width) / 2; + int y = UserConfigParams::m_height - int(1.5f*dim.Height); + g_area = irr::core::recti(x, y, x+dim.Width, y+dim.Height); +} // createLabel + +// ---------------------------------------------------------------------------- +/** Adds a message to the message queue. + * \param mt The MessageType of the message. + * \param message The actual message. + */ +void MessageQueue::add(MessageType mt, const core::stringw &message) +{ + Message *m = new Message(mt, message); + if(g_all_messages.size()==0) + { + createLabel(m); + } + g_all_messages.push(m); +} // add + +// ---------------------------------------------------------------------------- +/** Update function called from the GUIEngine to handle displaying of the + * messages. It will make sure that each message is shown for a certain + * amount of time, before it is discarded and the next message (if any) + * is displayed. + * \param dt Time step size. + */ +void MessageQueue::update(float dt) +{ + if(g_all_messages.size()==0) return; + + g_current_display_time += dt; + if(g_current_display_time > g_max_display_time) + { + Message *last= g_all_messages.top(); + g_all_messages.pop(); + delete last; + + if(g_all_messages.size()==0) + { + return; + } + createLabel(g_all_messages.top()); + } + + Message *current = g_all_messages.top(); + std::string type = current->getMessageType() == MT_ACHIEVEMENT + ? "achievement-message" + : "friend-message"; + GUIEngine::getSkin()->drawMessage(g_container, g_area, type); + gui::ScalableFont *font = GUIEngine::getFont(); + + video::SColor color(255, 0, 0, 0); + font->draw(current->getMessage(), g_area, color, true, true); + +} // update + +} // namespace GUIEngine + +// ---------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/guiengine/message_queue.hpp b/src/guiengine/message_queue.hpp new file mode 100644 index 000000000..8e2f14a42 --- /dev/null +++ b/src/guiengine/message_queue.hpp @@ -0,0 +1,41 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2014 Joerg Henrichs +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_MESSAGE_QUEUE_HPP +#define HEADER_MESSAGE_QUEUE_HPP + +#include "guiengine/widgets/label_widget.hpp" + +#include "irrString.h" + +#include +#include + +using namespace irr; + +namespace MessageQueue +{ + /** The various message type which can be shown (which might use a + * different look. */ + enum MessageType {MT_ACHIEVEMENT, MT_FRIEND}; + + void add(MessageType mt, const core::stringw &message); + void update(float dt); + +}; // namespace GUIEngine +#endif diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 1f4048017..dd2eafd2a 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -373,6 +373,20 @@ void Skin::drawBgImage() irr_driver->getVideoDriver()->enableMaterial2D(false); } // drawBgImage +// ---------------------------------------------------------------------------- +/** Draws a background box for an in-game notification message. Example would + * be an achievement, or friends comming online. + * \param w The SkinWidgetContainer for the outline. + * \param dest The destination rectangle to use. + * \param type The type of the message (achievement or friend). + */ +void Skin::drawMessage(SkinWidgetContainer* w, const core::recti &dest, + const std::string &type) +{ + drawBoxFromStretchableTexture(w, dest, + SkinConfig::m_render_params[type+"::neutral"]); +} // drawMessage + // ---------------------------------------------------------------------------- void Skin::drawBoxFromStretchableTexture(SkinWidgetContainer* w, const core::recti &dest, diff --git a/src/guiengine/skin.hpp b/src/guiengine/skin.hpp index 7228cedaa..6adaf274e 100644 --- a/src/guiengine/skin.hpp +++ b/src/guiengine/skin.hpp @@ -394,7 +394,7 @@ namespace GUIEngine virtual const wchar_t* getDefaultText(gui::EGUI_DEFAULT_TEXT text) const; virtual gui::IGUIFont* getFont(gui::EGUI_DEFAULT_FONT which= - gui::EGDF_DEFAULT) const ; + gui::EGDF_DEFAULT) const; virtual u32 getIcon (gui::EGUI_DEFAULT_ICON icon) const ; virtual s32 getSize (gui::EGUI_DEFAULT_SIZE size) const ; virtual gui::IGUISpriteBank * getSpriteBank () const ; @@ -409,6 +409,8 @@ namespace GUIEngine virtual void setSpriteBank (gui::IGUISpriteBank *bank); void drawTooltips(); + void drawMessage(SkinWidgetContainer* w, const core::recti &dest, + const std::string &type); video::ITexture* getImage(const char* name); diff --git a/src/online/online_player_profile.cpp b/src/online/online_player_profile.cpp index 28e955fe0..16506f5c7 100644 --- a/src/online/online_player_profile.cpp +++ b/src/online/online_player_profile.cpp @@ -22,7 +22,7 @@ #include "achievements/achievements_manager.hpp" #include "config/player_manager.hpp" #include "config/user_config.hpp" -#include "guiengine/dialog_queue.hpp" +#include "guiengine/message_queue.hpp" #include "guiengine/screen.hpp" #include "online/online_profile.hpp" #include "online/profile_manager.hpp" @@ -379,11 +379,7 @@ namespace Online message = _("%d friends are now online.", to_notify.size()); } - NotificationDialog *dia = - new NotificationDialog(NotificationDialog::T_Friends, - message); - GUIEngine::DialogQueue::get()->pushDialog(dia, false); - OnlineProfileFriends::getInstance()->refreshFriendsList(); + MessageQueue::add(MessageQueue::MT_FRIEND, message); } else if(went_offline) { @@ -422,10 +418,7 @@ namespace Online { message = _("You have a new friend request!"); } - NotificationDialog *dia = - new NotificationDialog(NotificationDialog::T_Friends, - message); - GUIEngine::DialogQueue::get()->pushDialog(dia, false); + MessageQueue::add(MessageQueue::MT_FRIEND, message); OnlineProfileFriends::getInstance()->refreshFriendsList(); } } From 6ed86fe09c14231f1c8cb4bbc69e46a8b1a15651 Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 23 Jun 2014 09:28:01 +1000 Subject: [PATCH 23/30] Fixed linux compilation. --- src/guiengine/message_queue.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/guiengine/message_queue.cpp b/src/guiengine/message_queue.cpp index ff938ea16..4fb7101a1 100755 --- a/src/guiengine/message_queue.cpp +++ b/src/guiengine/message_queue.cpp @@ -109,7 +109,7 @@ void createLabel(const Message *message) * \param mt The MessageType of the message. * \param message The actual message. */ -void MessageQueue::add(MessageType mt, const core::stringw &message) +void add(MessageType mt, const irr::core::stringw &message) { Message *m = new Message(mt, message); if(g_all_messages.size()==0) @@ -126,7 +126,7 @@ void MessageQueue::add(MessageType mt, const core::stringw &message) * is displayed. * \param dt Time step size. */ -void MessageQueue::update(float dt) +void update(float dt) { if(g_all_messages.size()==0) return; @@ -158,4 +158,4 @@ void MessageQueue::update(float dt) } // namespace GUIEngine -// ---------------------------------------------------------------------------- \ No newline at end of file +// ---------------------------------------------------------------------------- From 1a590e0fe10b3a6c0a62c2db7412c5281759572e Mon Sep 17 00:00:00 2001 From: Arthur-D Date: Mon, 23 Jun 2014 05:38:56 +0200 Subject: [PATCH 24/30] Added new achievement background --- data/skins/Peach.stkskin | 6 +++--- data/skins/peach/achievement.png | Bin 0 -> 27437 bytes 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 data/skins/peach/achievement.png diff --git a/data/skins/Peach.stkskin b/data/skins/Peach.stkskin index d5c7bb408..312421893 100644 --- a/data/skins/Peach.stkskin +++ b/data/skins/Peach.stkskin @@ -68,9 +68,9 @@ when the border that intersect at this corner are enabled. - + hhS$=AqocWuqzh-JK&_5vb}0|073QC3RZd-2~k1`633ifjj@MfgC4 zv4Q&|$Rm3f9hkxsj2OXe!bQQs%c@N>r)yVkkDj+{E;`n7KW^n^ZP?o?c^aMPyXO_e z)z=K2ZLF;1{+woCiYVi}JhW0?R<>SeEgr7?-_y~*XpsrZ$p-gePnf>}pC5s%pPHpX z0EGIhkx=&obpQ4+p3zG$$0d3pyN96d>*JOlpIr&1-;IuEw&ef~;Ri$mFjy6+UO z1GSqiZvp9gGn5Zfs8i`^fw?3#y$b?BeqNIQVla?}y1$13pFO>+mLR~HbLiZ&vzi+u z@a9TxIa;Lj>a}uwZ{pCByJ4IauJ6ob0SBl#8MFGuU+FfXJNdK1J3JUx1qz%$A{?u6 z{6Odr-vX`;yT=lv0>!UuRRmbE_1|z?A>rf95xL)H2XlqCa9l1cc{`Dp?JQQZ-7EXL zD4-A54NMZfjzFG+-K&E{2C?Fb72%?As-N@VD$0#598QpU;9q8B`A^T zB?;GJNQ!c!_rE?6#zKO%GxSg&I2Z$exoE!!w0*sn?u6)z@uWf0m6A-6!Qgx8{1oj( z%>%_c?YBS|3#bnskX!oaCYtQI|NFq;W_8*<$JSY>%JvX}G3nUKZs><2@l>t@*>2ru zHt)gf!XLDWPQ@+nvOu(alauDNr*E}4Li+*&aDkHLmlYJjc$5gGFpdZ*TuGYz&Mxw^ zfm@tS3RBcO)YEKjFq*?#&f(%<687>g&J<2U@)G3XDteMgu6>-=FIZwCbYr>tf*}$< z%jOj|dpQ{tDqNddeVytha;Ar?$CA@e{BiF~@Y{0{&kUE!(biIbL}!!}&ir!abdp%g zLy%NQdD!(s3=GSrj*_HgWSJ2{NKXg#AblS8z4ZPg9`AU0xbRBJYP{FA+^_A(p zq*4X-u&)lu=+7icphvq$6O!71REY{dQO`bj@I9VDtPO(nI^dHqE_xe~W{czijLIVC zk!2L)iv_R-IW*S9Ee=Z?0p)b%rePW7_?=o|)IQ0R*+DtK4G)PPw5Q z@K7(3l;NmU2iUw|-e6b7 zaELehE$Q#?VDJdC!yGZ1jF30FSB5^+(t*Rc$cgC zS=D6jdP@x)Z#^#icTxg{Dgq=ObN?bVVEL?Xyq?mO3Vn^E&P`mGn<#lc{ij_rORee< z)6emIFS3%rkGuJKDUX>-n-cSO&t;jXh(L;4WQoa{<`>3ef|jT1vM{(J+NI7|s8A4Z zw*({R0~V_(i{-V*TkG>$B+VcK>J({e0#HQ&dT1~ebt4I=fXi^o-4-_E58;C!sEf)$ zb#u}v?7=4lVnSsxujjFJngLIHZJs^CsLAC9$)1%5(KaEDyh6{5qx#y0Kx1^Ge~ms| ziJ%}Z6;yWDRGGZz_#<5Cr%9jKT`EvO5bsE=vf47eX~nTmcH#|ReZ+G2z?DlZuCW|0 zv@?5CNIMl|!S4&wbf{<4Apig{3W2W-vLYQqsP@SH!y2*VXi_5DnV_|>CL3>ddXbO3 zY;Ph8L7&cOSM2+G7nK~b6zugW2?i>^@9(^?vj2V~R+A9rpRi)h9gW9@QDFU&&o z+)!#|6hyYXO8eIB?&8nULz}Vbx+Un?`AFae?F+bbL4~f9_6l&Q71Sv+WW9+va+m3N zXX9RGcEaV_B*lJVP<`YINnwt%_!ErF2l>GzXa>1PC=>{mfRMn7?7$g`I*d!^4g=RpTxQFwd?2o~aHH0LQd)1%$tW4}# z>@UypnMd>^#Ksp610py(Efr6Mkc}G&$N}$0CiSCmz=j|=CC691sp^Da95hYb6istM zrYFgM;>=58B^s1wZ0gf79`nRo!iyl;iN#!~*qekbM@V_xh3~+(x z8U8adHERSTUSFx8=@;c9|EI5$7D|4=7`9u&=>5NoHM$Ebq#-K?kbfD;Jif436Vkqk znnEWb^c07OQf7JDw|56eG@@@O@UXscNd3VlgIsRPbP?w&s=rey|Eo_`f3MOcX-RW9 zr!_O?584<>mSdEgFzG&e8C?4_DprMJko2gALZ=~4dp6T?eSG!sj0jS&*np4_EurR* zO(trTnxKL%!y7jj$W+2BkHEP3U0tsPM<*Q;~X#ki6I@7Ip3!y>`nICtL}1} zKr*U`IbkdUX`-CPGH%;nRTcRQ%{wQV;Rrb-U=NPHKM_VqZ;Cwi5{lWU;`t0G3*f#F zhMS@(5Hc&I<_}aZDdd_-8S9G;O=P%`X92>o@H8D?H5&`fpeRTZ;IptFBzg*+7@uK< z3EU9-?FwXZ1b>J{*qpw>9q5esu^tQ-9vKle(d=VJ`L*24>AfcwKz{s>BCYr7&&H?P zrhL+mHNr*_nsnHqn0ZS02u?bwoyuyYI)`R>IQ}*9?^`zLha!~Jbj=LcY^th*ZO)#q zcjc!rVx3cgeK-gUo$<>G<~?0368SXmeDh27@Klmb(oo(t-;|?Spy!2+@#XIVg|S<5 z(4LC?Es1=?07~rPm&sUw=R4pdk3i|?iKE^n8k_?!{vh8BjDNx4?Ib4`kqBv{S_z}W zRypjfYo-RH;m{mgR)db|05nAV&>-19#$sbt)RI`8O*iRfEs}9!_TVj1D5-~ySlY=O zqL2_vHv&y5Tu>=HTp7-Xg*5;3_`GUL5xZH_^Qn7A>qRz^5ejE+YYTLUVs^eF|Gfj5 z5qSyzEp%lHVSEnncCP`f!{;Xu=4bytOF&ods{)r%0C=@!$q>2FAUVkp;l-A_-&)iB z+gP+=?-(knp5uMef=iFBSolPW=b4S@^BQ+%z_PW%_sk1dW#|UCcH+RdD7+amiFfya z6%!S0Kh+}Ujst%npD1ENhu|1YWfs7e{*RWcp8uRz^zx0 z&_vmueEt_-YFq@gBE+bMU|AY4$%Jz3F1=gN4}GbhK^oiw8OcR-pXvQ7jAf987z{@a zRHh%2_k3Q@quM@+`u_^DmWHND+Ywq@z$3Lj0yka$ybl{pugm-0>t;isw9FT)>ylKb zg`)c@sNjN@9ND$14w|q=$YovTeT?D+{C-gU*}ZK^eKWz6GIQQX)WO+rHVQ%*qzO|= z+smj&I5U(oLw^;%2kvnlBSZMl+||z7iEvi!?rMuZ`#ZbAk)Ti?W0-bYBj~-L6)ugdn8n<~iwn z96R&W3;GK zD%YxLW;ks__d=bS|3Q((m*tgeZtLk#BPm%L?)@hA2WGl@!_AFvGpqgrB`q%>D-~{w zjl<*lXpY^yIS%U8%SIl3IN%wPocG^i-feZ>pmNdT&|$=*ivBnHrww)uMv12_?44Yn zlZr2JdCy0-=Nqrj8{Ypa${-tg4@u`Fx@`ZTS8T&Uvtqx#4bdP_r-U++f|xz@ne-qO zNHm1ml2CLMW<8oyd{Hxd)*(xh2~_s%$V5+ixl0;r`Yks%!J>&+R_^R{e`6?X=?1e)y49Ehol-wJaQ zs@_PISx+aKu>Xe$aCGd`uKL}sd2q@qMSZ^9HGlNXNhk@^=O#PYB&CcuNgSLB;nn}5 zKxSfq#r!t3APBTWK7kCPMPUc2-V^vnO$STYQYTqf0CeGZxq?pHAVAm}13kB(N< z^CD`9Vo#rwD$o>ioy#}*cp$I#Q{45>M^>7t^4(d7lg?ba1Tx@6&JROi`5U|6r6Fm| z7t)60wRGLdmSV$><7JFElv~5+I?@G$J)Kk{2Sh||q?f?jRnnkd<&n&h+*$$|`BA_x zx?sR^#5;52RK>kG4snw-?t9A3w5Y_UFuAOx6z~|1=zqCN?f>#e{Npj}-0`2M`%B9{ ziQ-^EP8M@9^lHl=GI z?^mcsT4-hDtoBDb$L;2)pXGIVvLec4U%$yFuTTwvnCc#c=KTs3Kk`<9?L*faa?qIy z{K}Dz^NkFSBc*(QlU41Z>faG2 z|DM6nuEW*ZdOjDf{b1r8J(Z&a=d4gas=&Nk#*TdEMC}%MX4dBu>c)`Z}3=gK~Uhd zFG;SUDh{*Ok6INJC^mt>2`V|T=UFloF7D^BSZ7Iz77fRoH6mJWG|G{DWML_Gj zJA4`rc#`*hxy*~e0ck3cfBut1?ckp{8^hUyV$(R<>a-HhJ0U2up)g}G08Hg<3Hoag z>2=*oLP}-c!&iXM=wU|u*=$zR@^h3gHFq{X$EtM)^cE$3Kuj4Lg@D}e@n&PP}BZcGw^5Ss=+YI7-N`swwX;RZ>JH333D zd(W&^>0bh9BMXxs4&SlV?3pRPF3CM<#}PO%AU5Mb?_svkP96#EmAyPwaxWH>_R1_` zwPd17C=eM)I_JBy#aK)BY~h5uUN_){%IA{)7{5K1UFTe{Gib62iiC{wFK#C1J-uac zH)^y}ytPX3;9X(oJ~$$ro55v86+fsB3Y=21w%SXx%wUxUM-L?@@T z_K4r%@M;dNmJ(Fxx)HB=(VwS}1Q`EiIE6QAr~`KO95y|z0YKAxpRB9Rdc`l^t=?Tyc>AxAaEQ5Mku35@FpX*octoRs zAzT)Pq0w2A)E<;-y79yyA+xQY>@R(2g6Sv{K9_~sR7c4=ANiTG6tiUA;~(?lzHP8w zuH1k)JrvCdg~EHjzM(9Jwm#}|oXw@<|efA&><1|#!Q2Bt&^Hf7pen3R{l+-*fP*iF;2 znRbyJ_b`{#JFN(?88jkTT3UjYwo>Rs&i`VQgCwT3!8C~@grE8|;&t&x2>B5Cz7ms6 zC}PA#MPiZh@J(%IlqM@3*#=i1wLC@b}D6Upi{B7vHaG3S-P&lgwa+?1eSFJUsJmtVAYt{rL5bw*j&x z{dAxn(Erkmi;E@n2PZZ*7V2SwAQd=lMkcqB_ycZ@{KuzYvLKZb&0xNgveaN^NqL>p z23Z>FKfchvU#KL&OYc~^iG4z}D1GRAj|W^J3;dfketw?PA1J3IKPV7Er#r8^AULneNaJ4wz%n0JHsMJpeOKc|)=};q3x!AbgPDnUFmNP8`UjoVinMhbCnGbhLuqS@}}KNmT$LU zU|{5zmD%>fziQGjKg6Q)GwBBZLyLIlDla9)n_6ghye>{kgo*=ZxRWF zHUI8VD42Y}1}=guIBy@VEOiiOs|rKptvSIei@*8|7`y` zOmcjh|HdOKqPb{HsEqu0Bo*zhu4P~Z`LBkEd9w;itk2DnlsI?<8~uoa= zdYgh#W!TZfsFydQxAWe*dL`)%Ba_WUw$KUX_4T#6Am{l-ElA+_{JfQ}QK3`C2&75N zey#5q0C1&fQ8>0e4!_!%_%D8Dw0Xyuufc%orGnSTGwn8t&wfETe7^8S&icB>+o^FPx|!Din84POn%2r^i8k2Sc}0YKAzlK z5p9&_Q+l?RW8~;B5r3t64f4zyKGpJmdZJkue;ebfKB~MjWXL#A=~NA@%=xTzNVsNZ zR$g|hzFA5bDqMS*89i+JDHspGC?_4~ht5)?+n?^FV8`ZRF<8UZAJN3&$4^!Mtpssh zSW87q!X62+AOCO|usiV?2*=$2_piU&pvht-;Czs{!F5NjYlq^L>CtbtR8_zJL!Uq9 zL)JT&q5d%RF@K-UAmnB7eBU_&F=xWmK4A^Qap!3uR2H>CqSfuL~rj`*p1MKbiF z;4h7AuO~&b*#0lEwev*zWP1vY1$G~yt7%OxpZ;>Df|;fe!lE&|i~j-go$>F<*LYL? z>}|3H(mwDO&N&1H*z>6y$59=+P1;Eb?T7I;9f@_y|4}hnC!G%FpyXUQd>we;W@^fH zhV{bcSBClc8Yj&8DyOjpX`&5Nc#$tu8_ecp76;u944NQT;94nCF`q&m-lgJwv)N;h~(da5Xe8@jn9bO?9d1 z+*|Bwz!lC`caWxSXv?#draEQJDHcz z*86;XchlBua-A84;<#8l`1&;Y8ps`P%n>oh(aF}~Rgmxj)|~!#H+nfVwC5tc9Q)wJ zQ0aWS249+M66UaUpODY54FYYS)QHV|KD?Xk>v_TWKou=-*EJUsCuedB_YKANMz&xUV}J5Hy+e`t{AfHE*X8kwHT#FfzHH%j zYsm#Vld<8s`vVo;Po;voEUFUM3TT;&OZwZ-Gpx>8{+`D?ZYwr zqeXs&uf=@xmgdUJsvc&U(>B=&Luo{@Su&Exe`=H-%5-P+YMzyPhZoQ*iv#sdj;RD; z>#rz=)yKZfa$&ZFa>fQXWt|2W&WHKV%>Vvx`|Hc&7?cX|JYA2wK3oimgxvp4*Au&6 z{qD|)@dASs-bW3?cp(zN)7`Lyb2Q@iXH(U)-lvN(DOvqqe?Nqm0@t&r%gLRW$5YNu z2?`2|B%K)%ChB78W%^>3pH2~})t$crkKrwD@Uze_y|ALxERTf%uFdvk=)Tv&jlsCJsc5I3q=~AyN>#p| zrKDdP$yXlXtJl9K?8hcH{%4Z4ohQNobo!DNhK!8GiN?aBsjhQ$09MHS}%a!Ir|r z?9Fr+tl*!j$M;4I+@U?ri&zf$DSeD3^Q!;dogbkL=P8{$W$2hHH(??ceUeTvJH)*| z`A`n>;=~CLsEOZOeOzsCI3VrC7P|t=Y*HCwV~gKWPl#UrDkaKAuRH&ftRC~7Mbf&+PhCLQdB6O;B<2v6xTY_S+AW5EtzEUGf;gSmN#&uHp z`E#xQuFy=q=ie?y*~<}keD}pMdOtL%1=Ls@`5qaiv8ids35d;SVlBLmh5uX8&E={q zkUwuH9!GaVGK9>OH&Y#+D~C?Ychsr%<-8a00Cc!6RhC~n2%)6CSe$7*YMsJ2y)NbA zsu$q{B2!6Q5OUBCMl3!FV|HWn8#D0$+}gVnxsU5zq)oPyaxN||TKva#0ndl{MAXmE z&l%j7ayROmL|qEw5->EGCMr)BM0n$R(RX34 zPWD{DcFKJd(qNa~)9hCJ+v;UmUm?|9a!#;xA(*2QDL*-^ZiMX22@#40unJ0b7%x7$ zX6$~GIqA)~Hwrj8qD0$-AWe9z`Ajqe)U?@;yYOd^#K^82RJR{)PuALZGaYHi%nMgw zAt_#jv92@BZ=o&Jn#5?Si?!H;HZvV-qwZeZH{5`i+n>B}6@Vtd4XMp1kP?FSBt7)& zu#~WK>*=(BL?aaLm7Ld!e?43ZyatxIuQec~ggHI?Sf5kFedLBS`v18AKWW*%7VoWO z?kg-!7U$;{zjgb%Q)a=oT*Fz@(IdFN)+%Vy{dEHE8o%wUY!SboRIvjn9~tUqi74A* zLypzNP>1!ZB2-N5a?59HqP+5ad@1wg{H7knK*we07%16(5)yNs?lIu)p-$Ph=J}?! z=fS}{_nkS*zN6Wrp%(C1n&s>e4S)BSEOhLpftOdi#2@OJ4f0g}gVeC0)VCO^1}T(;X6us+Y$ zM-2=c0_~rZYf{U+hFVjRJ0b3e88!2Idl8b^?M>ulhXr!aw-5jH1;a;O~mqAtIQf9jHk?B&ihS3Mg$8tDg)&%Og*$TU0sg zWzMn-2@@~P3xiO4rlddo(p&H7`7qQWKJ6#TxDjDh@Tv80Dx;yZP(|wkf!u`VV{;46 z$G(|xP-bO=!R<&ozDd7VEE6m;6(cwVoU2X?s1)za-E`{MCYeKIM@$Uygz)zYw%^5*6N7P)0uiHZ}$M6-38r-uR)?ua?q=q8F3CfV518kAeK zB=(M;jTmlyN!^0XFLONS85OCw^gpZ$zc$?mw46cPan#!;{K^Rh3=dy~oc{Ad>AEck zbELO30^T{6O1BBhBbAJ7$zX}mZR1J}IGkyTSg2A?ul?j5V2m_5-LPk$u+tv)ZGY2! zQtaK#lI^dIAomF&WT4(MFTv%-jWH4~R>MGw4+lOHGCDnb?viI1onq8Q94EIS3LAgJ zv_u5C+y8KZ?^y^{tkWr@#67C-hD$kT$ztL;$xEI(MaVmH{%(w?fyrOyo3W6+I?qBc z$-L8S_lcM@W<#})U^_uT4LN{>i`gxU?rHS(vY4%Z0b^&DPD7KUu zXu^5ZVff3t=I-P0cGtDV>`v`)&1F{1^7--n_ReQaz|HZ<2pw#qT=4F<PT8$?~_eLrD<3 z(LeHM%=6_jUL2H{c$i-D^YQUH-!Do~%W!FbY#M_MMImQw(cy3hHiI!Dt^#tYpgGv~ zqqaZ4(znB!7+pp=J+J17|2}Kno((10gs^AG$csp6NdcSRQg>mHBmUaYTG2dJQTO_* z>2`CkL*}O%v}4jQ?lz=i7EHolg|uwHU(< zm%O-lX=z?CIwp+RG_rXS-6eo@(utD)pccWRx}B$E9W_?{*L|n^o|@?S5B!G5oKG`~ zXQJ3K#GFIs5fr*!8!&Q8^lmc*)0!ato1TfO#!dv19~wIXZMCUHEcV8OrWH;1SwFh< zp6}mOJubdtI-!J|bSb^?zQ1g+kld9r{Se0_;tgYuskf=~GHa<=(?Fi-Ikes5*MZXb zXt-Jh5^c+`k47=j8h3xwy{#G~yw>27w3`!Jabe4<*nwD9EI

E-oKP2{+F$T3$Jgu8}KoRvLW}4*;CVkHzI#^&Am}s;ic6=ZLSd%7d;p_)xT)$g3Im6 z6!#%VcWRWfKZ{fhQ6E^DWlHX1j!u|*=jxfkneXGVDge3V)*!xwuss=$) z_Ep=N<~i97g@biQA{&l*0`f=7o?JxT2u{z$gV6NLK}qAz#%<5-`}nzaI4Y|9p_rwX zNzMXkl;{irBnCUURsYB1hR07H9`8Yc?(wiqn!ojAYK*g&+<-UEdA75w@Y<3M?tQ2U zJmS-i6XyrL02(*p-c!F*R*{>MbklwvJrhFvS9!{m@I4;7Z2mKmY+ABN?#gU_8qAcn z_ILZ$aCWZP((Eks6Xah1AnO8|RwY{T!-Cpt!dL@x(6N?wD%S~(H)WokvF}B$OLP|Z zhVJ11nbgI>>kjIJT7R0ggi5WB+Qp#)AW#B+7+JAx`$KbC--c`SZ)oj+r19ls-seSQ zl`%IQ+%z_WU>GEBKa$lmc10Aw{XS`*X_J@W-gCt#a2@}iT0xG^20!xkb?wwYLd@sp z$BEZ3?&18-PLT)yhl8@Bs;a7zX-Qye_8?WVp=V;ea|m*hzF^^)hc)@Sx+fmNTH9WD z)DCNa1Qu4q;hGz!?KGX{R!QZdVA+0Q6WkPfPlhtJk;4-MRC+1cv>xG8aF^C)ZEhv- z4pX3G&a`aWR!!4$9H9*i!imZI7BmQU6q^Ap`w?IClU~4<;sCfR3do(&iJy_x?E|FiHFr zk=U5)#OmGJC;Xn*=TjNxu$s=xyUp~x!Eg%8-BCXF?Xw|f>XnP}(}35$y@wPvftS{Wfrv13Y9e(L-9HS~SoS)Kv+xzOb`e{~m2Mhg_o-XW-1Q#~1 zun7bU(nRo50|8flWF&+#R8tBYhuqZlOh4eYfdYygJSrr+sj6jlfLz+|x zc76m3fqm@Om~5KhFMT*;Eo@osUl)HvE%$6)r%5~d|K1$0(2W*;f{{;`g(GRIokM3y zM!ADMThLGGK_YPmfY0s8;7)>sbIa*}l4!!?I0I~s4$@$M{)$nV?2+?tlA8gk*hZ5aSz#u9_ywq<}b$}ALG(b7H3weSer95leyD| z-?{w-Lr`DmI5ByI-5BQ-C?X(_gAo=s={+ua_rGi*eTc-dtOtLN2N%EA6a}p&4rC#5` z2wltX!Y^wdd2=`TFiHq|E^|&dce7k-KSZMt8$;m4FTYI!fQ_e6`}6kuj&jOqwe|hn zOYqp@CY1p>p+69Dpx9&yE)_UM=i$a$Y{xKO2?Kw`Z~jQkUVG2iGC(SBI0-dWlhp zP$)D|=Ykk8cKb!h?N%nF;_1@+ULnS`XbV!;DFS0$WV zFeZem?Q~wxEbi3*wo}-xe73JUPXcYW!x&O}%B`YJvKy4;Z5 zbnK~(Y(K1qOeTpMmg*v?cPA=gbwb|fCf1gx2U-=4cj6u5B+b}=@tG7nN(Td zEfhvo-lJ<%u=bVCg*Yi*cl1LmZ~#QW^c#GJo)wUlDJdKk1ug6lAGG2CLC&fPPVSb> z@0QvY%qPKthjqP_{}GX8;@1_8VP-vNVVwDOb=Ym|Us(OG=bSO(k)rxM);c`AVPp`u z!3t-(drg>J12!rfXhav8i{G^4VA*?8FB z67<$Z3*syilDF2-`Vwh?x_3%?Sp5t4NIu?=-#F2ismyrJ39;&CzD-yY5FVF{0#Y;>^NBbR07TwfU{vpR{P@rp@Z?8$pt_S)ML8WcJUixQ*ZO%Ex5S;6>fWac&-SHN~S9EXy zrfHT!b~|AQ$~9}>5PNJ<<~f_7PBs)VU5f$Z6eH+|IRSkrH$Li*?{Ku2SsYG9l0Puo zWCg$YGg9ieV4U{ckjDN&fOVdd-1n^SKk5m=7l6QE=r+tM2Vp`$(S(PWmywWh?``*~ zYR5m1!n|&aegT|3(K7g%xw16uSk0M&@ucUsoZloaA5vkP2MV%cQjVnB-eJ z|GdBvscO2Qww%$jkIwhHvuXZzvQq!K_hU8j0qd+Klff$CsUEI+- znBU^?v;S*cg%Hq4PB)hyysZ?ig}eiOQCn)n}4t7_9tyY<-3K(0VG{h1zdQiNPO+yv(QxxEW6+VU}V^Wlw4y<49pIQ}psq7=^^8iZ39js8(YrA`9T zjlaXsxUao6$DnWVM{zM-4xuvhVB1w&M4aa6zM2`KG3rS?;M8!D`rCJyed+U?m+Rr=1jvX69YFO!w(HCUPi$&l4bH+5Q4o10ik zE}=lEAZXloP-mk#uChXJrBpXm(U`l<;rFQPcX$Ds@NtaUkAK?*>(2FB1{dGxaQzGV zET+uo40k68Rxzd;>AORrF8L)z1BK|u@|dfBl?vmAwi^X_T_*cCbIjFB0$%?Hca?C z>{rW~!q|;kKdg6sw(bo$k1_jU;-Pxh*Xk?0C*44lWeZX zDx3ln)bJKPH<3+C4t)NJJX9>gK492q*_OPp99_{H}a-(-t8YU?Bd0KyW?3A$dumHo(M1k(M-KvdQY~sr>Cc5tIXWy0v=lw zCn&%>ZsTe99i7AocT5LtViE?bo$LPDv8Jp}ZeO4d(IkwZVp}74Ms3#0{e^>qO&g?+ zQJhmtmpBaRg=LLe+h@@x5<; z+n(3B_^}Fae6!6pxOKR=7p3$$;zpsVmOGo4r+Uwk9&^o(gByzDecQP~v9b$WG?ZWV zX|g?+?RA)|nkL2Hz!(|UP9oZVSZJ=X>N-q8P0MDs8g^>ZK+fA?%tVhlbm*f{+$@Pm zU7&O#K`5UxG9{`laLiKaq&Fq;2DwWv!;)?9`z_9 znri*g4%-s8<3&!OFqz_fkkh{*R=A?&`u5g{F(3yPVF*57&Ek*8(krKJ4icNiuATnJ zqowMZM&;(_R!Ud)_VymNIo5R(d9Au410SY?NPS-`ceuO9g1)lMT(oo}C=fb4mwd`+ z6SgfEjL^2rW%kP>)Sd>a=npH?Tm5Rp_8-Tt!EfRap9z1(K)1g*%_k$$)nXE^U20xQoc()Y2OqOXV8w|?8-{RDmf=GFT@+7*j2 z8hG7e2i%3|9M}Ro4u>lr1soCKq023f4bE#F=UxiTM=NbE**NHRNs;yDk4zJ$_XN4# z&QurTXNuIUO;D!u9Id=5(Fb zHrm~$E5q{&W~9L$q0$4Op!xkI%@P)?`6|7^oVeYJLXHTs-f*^(^6Cierv_}QjsyFy zMyI!+F?q_*Kgd48#a88Mxrpq<^5UTf!YpIu%SN5wv7=5!@yxAeA511pkPY5Sb)vhQ zimN)`Ozw;^6xCVX+27UprdA+rUKRa9syddcj;&+;pqOJw9m_Cx!pZ%9_(Xlr_u2Y2 zy2*PxRLVGN*D%wsMdivcO{eAp55I!WiV-Ldo&yCsnEEj%Ns=8(S<5rYAXo4dG`K7c zt4jP1Z0J&pHG~N{DVlZjOF0Jl{_z z_**%3|CiGBU-A5u=&$RrY^`@sA1H1x5eXxmLL6(z#KVuA4WqrEVbH1oq$6U2HHH zhs1&tN4Z4MW}ZslQqxnX@@Ufi;E=g3ha9iq)S`4hBUW$Jj!~QWo)22ni*`Cqc-QoB2b$ju+F z?jm@aVy%%<7$d_h^N|sS5YOYGqL?-eIS?mhZXVsrY6chhRHEQn_A|o7!MExAttXoD zDwQuPjO02N+WBP_+ciXM;zP-Qq#P*F;POqGIDN@zKL z0RmqtW`g0!6Il=%rr4{`BKD%oIu2_)@#y`+R$u{yTGx4;OY^eV!A!|!He(NW?cw&n zs=6Vey=+SuO=i$E+Oq*eP2PJV8&N{;yK@Y$Dg7|dAJ%!=^9HE@tcRt%XN&1qO3klR z#LP!8)5P}ak?cmkSGjI?CRDw}{`vY1!409>RZk=Sdc`c+nNf zS_H<1vL1XB#LRY>l9IgMcDX+3tu$}oV?)Un_KK{GVbeKbOCe;Edr!QM)^;N9RGS_xx z9}4~fUuvxCNB`8c2fLKhseC0TW(A~Ksf`dAYnqW8v;C(GOG_!Ex!%)n)(xSeG9g-E zD4~)I)xo=$`7F(!4tSVc-Q38L`<3vYUCpXn4n`AdeE#!npT%v7M8shn$?v%E;r`;U zwIOUPf<@E=Fj>+gC!dm7o_q$5-uk{8W9Lbc)XD5UNQb#*%Mq?1cGrvmLs~bdrE->T zKDAJjqxsvi6W(}(0pb#a+k_3g$?9h(w49a!{bnOG!{4QtOG9w(-SeIQ3{YDBy=cE+ z6D?*gVS`lxZ>2tBJT{z;97z@g>GzpsDUwo5#j+^UnP0$4K}rCNk_OK!Jh#f}+1a$$ z_yBQl8>JM^CQMo!f^8)czng4#-fY~3i<{wW!bt5tPXBXs0Gi{q9;M9j-HLpCX2OUe z87@C(>c4R6yeaP)BYr0^@+?Z-7X(W~_%B5vSkm%LeuJNCR)pLH;IKMOh4Z6!!x+Ok zN-gyVRe*5VEFJQ$hvsBTCeq@$aVgZn10l{*&2u*a!KEW@k(RQfg z-05~ja*|xSb1ypjLUVSF#4mL+^|nmV#eg2t!-bld?R^;2F`+Pk8N^*21e1_&-oX8b zjC@br^J02lw~2cr5kRz-#)o|W7Wq5lahE2Y# z(Pn$gVmm+HGgSL{Ai&c}k#c!j2@*{lL*3t8qZz`oJzN?-^aVd}+pCpmPVar^oh2bf z=hAMN`Q40#96_-f6d-O(qh=`qJIeGnx6u-nW>L^Ts-9dWxEvM3(4QMVR??SB>` z2%9sqXtKybnk!Gm%0I z4@EQd)<}-bzx-T2B?0ask>~;*^R6UqMGzfY1eFD%7#u=t78tSy<<%L)k`W-~aYMn& zzNRW^gW7QyQSh#B@@rGKjMRZ))EHEupm*PhV+l8rr7MELa|QavQc8$-LBUiC1PHvV z0o-Uz#c%UJ+1Xj)GvT+FM=wa~3#H)JZ`V6l3uYhi%uwU(k^PB+>bXb#6lHq-sKyGOUNJqu8iK#=hJ_y!3X z8J202Xvcl?a~*a!#`pb8dRq!I`pHzK-q8oi>31d3G@@I!MZXVaMRZEm3Eis!=gK? z(=UsiSN}|TH3g4De*?u^XBt>1NtdDoXpNDNDD0KnDT&e4C4nh3g2C1)VeAOed^w3p zbqvM9zLyff{+Yt3e;Awj@39r=QlxlWj=uOcbWhk^^=e2!wG-ZV-oR9iko8-U$5W=Kp&b4g3>^NV4NVX_z(Ct`Y756!pnF}Gq^p85JV}#We|!KT5L%A z9Djb|BA4MkqQjT}p9>(K`lP;yCH)6g=POVOxhiz_y|)~L{C09YgKhZ1+&0}dXI9RR z3)N94uM#T%+^0`Wkq|rHaRe!8H!7ND}@79 z-`RLIuJ+B|ksQTX(0dqyZd`Bb|NPBDOu;X(tAtY*6PD}~zoBx1VV8B7Tx$>iq&>_D zK3$zRm3-z$U~xqJ{p<3F5MK$1`U<`p2$Yom7l{{!RRX)WgeUjK^iQ?{g0yMITbsb2 zNqCyBToqT9pk0$pM5`3En&A3XF+xAYA=;_U^83?(yOn$WPJiI_^!bgHEKHq)G2HKM zZEcMLUlaVVitPGsEwOUKV_t6y?VeIn7#)Q!A;n_^LCF70h3J1e z|3U+MVEin8DgQ4N{J{8UB#`s9HQ`tA|A7R}>0-J0J$%FnfTX}w>w#z_s%D~#rYGfp z>(K@iaS+FyYofJiCVMQ}tuJU{n>O^JO)?f$*}v8@lBy191NP3{TFz+GDu$iW5Lgm2vtC(k%L- z%KZQ(;hdoykiu~PW>p3y0V$;Ut}TKlt*=0u1Tcw$FQa6=iW#c_(A;i5wrGYk zf?@@((i!gTC^Wui(ZTZv+5j zQVjRs{5M!Ix1$L1svO}<`%2Nm3mWKAQs6C2wGdK5gcOi6mX|0A%@qm-Um@=+L;n_-C+Uea<76a$_~BSdWJBwJd85}MhyV&>x#m)d14Z0`AF z_N7&ACY>i_3CdK%DoDcN*VFt}jX7^qL#VC*0Dv{-wGe=BXakHE6jBb5D`*h#qq1J zpNey@`aOQXwohx_=`{ZM$3J4(vSpKI39Med8XGojz~?{zc>uulE*IbW{E1kypexe+ zNt&cMSql8h2tr*pRT&ycDQObwq{*mOQ3-Al31V4H%8SB3OU6S2IbYK~qXilHZ_&%o4{599qq8b~UjAhgr55J+SMgOCzIK=2%8s)R}~ zNl>h)4Qt5RMS6U$Sy@=SF`};cJtB2Go2xfj{u5urZo!C zKy#L_s|EP5)aHT4{0+9+ZW3XW)K4*0W6_TDqFHSwu`ZL&lej*^;vF&kJz4Cd8W8{y z4Wtz2`2pZ_t!?If17k0THYzx?Gd(bd(3;o)KI z+O-R_XU}dPF-R2o97ab+qu)RHzZPKSg-el5^GLhb#J#GB{0YCyXwA(~utcCQbfT9E zWRz4Fn24T2pdbPR`o{VSgv3}uAm?l6d_GVZD@cs_GRhGs1iJZ|SvGd$Y^Q%_2OC3k zV%ZTxm#8{GY{M<`Yw<+rcF6VLQv z@8Ga5uRLcC(&;o-uU?IP`}W~YZ+cT=jsJ-!p1}0!)3J2v(z5??Mp$@Y2QK@EBXIVq zhm-()5#UWDrlvzl25{&LFm?Wmc>t!ow#gX?gwf`OgcRBj;2Rn!A4n7eiJUJHn6b$F zVVx#zmF4_m^-rO|7S7=P%MNt+AXx#pBo9xcw8&&9P1yolk|?Emeu74=o~ay*cI!(k z=UOAtVYc%Luy^RzTX~Ecm@8;h0Bi!VhBLg~7pl{Bv=9g#iaB2*?GjP}q2NpSE+HQf zJfFdH6dYf`bqIw5Kq&$j1V#kL6ex1^N-*NO#(h{IP6;g-ir5}S3l;C5j7m)CU$vvS zyTidu(@hog=<3IOo2k9`byi}|kb;sLnU#t6 z*D^wA-d`vPp`e5gsnuG%gdb?j$`2&+2Jj1kLe5Zdd0&HmP~!YmN~uDiRN8^Rc$Tww z@hm=wV)=)pkt%TylnqZmQHNhGkhO8J)}oM*u%D>Yo=twbiWf-PqIi`1TOv`X| zq&cQ#Il8j?b4QvZ?Qvv0j+DpXc^nRBa2$f;a4@dx{%}XX6C;3;`OM8i^STxgNdHee zikZ1x1eni+lKsp&W<#R_cl^gX-16h<>-o-~KR*f|t)zKsZGZpv`S`@&9gYRFGjKRF z@%&mSAp-JJ`UfQrUKOpCAf?bkPU_=y_Ozycq|mfZ;7bHjqEHaX6(sU`{XUWt7|sa{ zjrtfE)!zq41@?{v7#I~8%1MmmB?iYd4K!L%$oonj*v$qmdSl1h51f$QR!7@KLi0O` z>1Rki1@mRELUs}~>QrfUy-@+_=QRQ=3f;}kt?w9-~ zDt;Fg`vwzz9dX01AkG2+fHl6rQwmtBorr+T6-IpthZ9_1A?-`#3YzwD9YQ`}@O%Z& z(Hbdd4349~g#rr{h$%2>Dqa%6In$Lb8NeiIj1OrbR?!=&L0_4~Fpc*TiU^7oOHAv! zLWHg?$7j!5f=mD5aQx)qt@!WNy?A#00JiSZ-2HLK9ar~B@5(w@d`KsbIkX3-ESrh5 z-gZ z$Bm2sx6!g~`UlJVG0_myb{&g$>`SxfT0QzFZvG{q&f@9=*<5o{`mmu=5M?xw0)Eq- zruU2$R8Qy(b{LuXbBUZ!81;)`p}B%Y${`dS0%HWuB^;l?8G$hg@{J-d7#t{*>8nda zD@aH|V4Uf4(TY`>RR&0nH4w%GkpxueO=hLHQ6cRRK6K^+od1pmc;N9Jxaj()0095_ zpZ{66tn~3mPREb0J4NRpNEHEgNoZ0D#Zw{#puwC`7#7}j1?qug<^zIU}&Q-@@IOMhL1nQ-G0;@cfgWDiJOqN z4!0yrFHRJ|ZR6JCu0N@1pCm$tV(w|Xj77WkrB&BwLkZbf3UNXNRr~?ApkGN9)uV%& z<^zbVfPA1H_a)w;tpF;q0vKE_k@g8Ad2IzS0@5A>FX)(khfDo?K;Rr;5)eXDHj*h& zAOVL1kl#{?V(xLm?@fPzopL?{^Qo)ObkKMnYklu*PVgaUUYNHHDu zPr7shF&35s(t-h|Mv&4AOzMI;MT>yKRkNT<`~q47|8s=^sJ1OwumGDkZ^o{@d0pO= zO1XU#f*RFq2$Q_R!fqx1E6o8g;9o53tdA2ynhana?;i*WDWItzUjuy*DEPjP@6Vg} z;hYKo%ooAGwD4Q0_Mdi8ICO^7d*p0qA8N<`C(&fdLX)=9mXdJtNh3hwEC*XoyIz>5 z4bPvH#%hELJBanE@cwYeE`h>JA zQ3wd51qH?=MhgVT5paEAjI;nC7UHomc+EgULK=W(4ucQ?=bG4&P(~O??HDE&Gg8c~W z2_-&&D8}EEb{4vjj{=~Cro5z~fWlfoGK~BQH1A(1efbij1x@|rgQ5j6nwL86-SCkHxz6L7+003(OiJx(Xg$g*>4?v^PzJSq!g2N?- z^Exix1oFV;1kYjMq(eR(t}}hZP*BFSX02Hq2G@~*02pHs%Fsau(L-mj5<;&sFPV1! zN}U&Asz_)^CNh=-X&Q(a!nFmSd~RQKK^I?qarK!(grT9K==;M@?ZQzDI!Y4JR0-%8 z9la3^1XJlVs^Te&S-=MTl?v$|O;_nfb%d^gf=*)XK3UN3%plOS?KLR{k4CSP#`uuwhgV2v=XRo;ju=n z1slyhPJ4ufmZ&Dshshj^cI->5+f)-2N`QSxZ?*lBSOQ73|3t;$s#*a6{!>US2XKLc zlCA?bX8ZuTg3btsSTdsInxf3$a8)rCmXRhCWUul2|NGsJGEKkM=6N2n*(^p!NAasCcj3}= z7Deq8WkBf?jws3SE&2zd5)WaYXZRL;rG-F2 zVmK#s0+>)n2xzT;%-2F=v>>IB5QRW7slXS{ayFg4Ec4RbZaxxYw#ETgoJRfsw|A{U zauwJ4JKgs&GrQVd$wDs#dVw5djKBszka;F?m8n#KL{2KHa%|$H5-zR&uHt9PF;3!C5*)DO0>5JOlE4lGX(fR{0(MqAk9%)-pZw^)v$N9fPTxB- zyR$;KYHH`%+xK?g^PTgZ7YYgj-6wpBqpL005g9_FVusYJ+X9lnD`qd3JD+8H5t3WQ1m7DIY0-rm)dK zp|o-SBF*U>ph7v^2|I%f2tokLMgnPNASA(%0crbX64r4Fmp8yJB)~#FdxzBwL_uqd%UOdsjODE>AXKSsiamzwyaPEg-=kPUb z7Bq9|&_Oxf0|TS1vo}+&o0?)|9cQnN{coi?2pF^yYXKw~qnQ{q+g*-dWs|`g39Dwx zT4^Q#n5fXql^2Fb_HPSMc{nS5v_BMd{sHCV^2hFe(9Z0*p=2}?11YTV z7h;|cvOr)55!993>y9v=MP}PSBCit!0d~J7NARMXGZ2-Xa*I$pZv9V=Obar+Y0C2jgaL->oi%;FQ1Gl_yQz!1f+Zmjvg29z*&Mg76 zAo?e7-#GtVDeD+k-C>^jBh9&e7v-aD)K7={Net$4UqEUwmzb=XnoMa9G((00+5Tr;jTw{Ey@Vj)z}yPoS(1H z1s*`;lc?5<5@Zj~p0RXKf-?7tHvk*~@CaIJD`f~`NMR5Nf)vI^ z{Rj;qEg%pP0%55j+X~Wj2h@P2a|lZf$=10m!7zp(0@2~tiG)r5(#9$K7G2()%kb8m z!Vh1ltHqi zc4E+IS^B4y%=7;?0gRDktXio_GtDBe-nw~0zWQr>)Qvgz#;5FU?+fW&6E|95r7bZUje>6`h+1MU4Xw} z0}8C)Kr2AXJo(Fj3}8s$R6WCEPrr#Lo}b0fUYx~|*V+r5y7}>$&wK`Z_UyqOciiE1 zq7OXq0A7CiWjyrIL!I}YpKjpr(K&qWThkb;NL;ad9M@briR&((!Zmx>xtM<&!ITSs zoBYKc3qWhriT2SZFX+Zj_**A$GqD1{**2JMY0M>-5^6Z%pGW;98Jp8>leRJz##rG$ z7SZf`w}*$W+Z`Xn!j4}>9G+C-24T;e&X=p~#ohJ-5)>5nzM7$r_6ZLmGs%J&miczIp+; z1Z41IESyJc#>43oidtOj%b?y;XeEr9rp8=iL1MOL+NTqvQpKTR1c5;M-ixB2-2I`k|Gwtp=uP-lt1Kc2 zdzr*2A;f&RR1}~Ge4L17x`_1>9=(#)*6Lb}%3KCLCVE(EKHn`QPL{C{&aCmXRL!8} zYW#TD3i7Q5dw>2snu%E;koWD|hnblf96x@1fe_!kd2=~rbS0$$;DQS- z=m`8qqk+A9_hS9}^*D6s5R%N`wV4#3`r0pW->utm=SQ}I;OL%Q@VmcC+ZsMf18FY& z6Ke@H6I0e4M%{_*v1YkbVW8uSL?!1RwRa@CB@unhS<_em;AqNa+Y)u<)UhmYTzIy?~44 z2$TYVv#6j}%9$XFL&<1oKor=RcOR%!q24FLGcBggUK zD<`pQQw*JldK%ZtQCsJ4su)@3B6(7SwzB+xuK71zjQ?C)<8)hNww=GWA)oDxG1t}& z)y4bQBC21tJ$mNGOXH(X8}Jddz4*c+%}=O+aPSS6EJCFK{*gjOg}jd+!N-xfme#^@ zt)nrQmE3FnGzRLm2YiayEk(QeL_Gl|GK9+jzzl$I0+<5uab>VARkluMEdrXU4c8IE zHhMpE%G%Yv0Wkm9044&WP9P0~9T;$6yF_Y3c=CnQc>3i=M-yk}v!Z%dswXf2eD<@S z1ps{Vlb=MTQUL(`^}oD=Kl_6nVC`!AxSqY*RrE|9#P+d7+RnszfaCQ%$1hSUafETWnBTo^uiaDU~0cB~KP3f!b+ieMGhp5eK1 z;laTdt>EZWs=(Kw*h|wbLQ}1!wHVcXF^DmJo8I>V43yZH%UN1WIeHh1{vr6cksKHR zE6qqU3kJE+Pcw~X!f0hS%XhY^U1%qF zgnv6TXe5T~O+9yNPN#`t$~4D@5oiM$2&8*A1wXyx{k893yE8uJ;Y{?UBZ`zd@V!Bc z_MZ6V#JYchN448U(NNaJ|_sVW`4>5}++2lrS1uK?#1O+B!?^rx5U^cb7`Bs@a*klz{6s>#%9yE=sKo-Adu@z>Qj8!lh_pbc3D;g)!~M5! z!$aSA1(^nJy6Gkm5$?bLethwZUxestB(q%CuYQgvo_GR}KKdvgc;JD~d+RC!_uR4x zf^4W}n%U@|%$0I(B^C@CPW!iIoh|*7XZX%p>L+`3COg$gm^E{x3@Y8if1*OiKeQ|U z*FU*-?8ldE3>qj_C#Q@iU8bN}QI5Np8C#?%TNy#z3w(SvwsU1ImZK6@V_yt=OyANE zz33NT%c2+UxYW5W<|80apFw}l0*_+~z-@x?X#y@61Q7Vzt2w0(Bi!2Dlq0Jl~i|yYqAXGzvN+jliAR@$pu*qdoAPQ`z@OPd&jc@#D z1}A4TBpEN@=9eq|T!!oK9(Vk_{w1b@3D^eyGnbfKNr z0c@YQQe#e@)-&~%PMIN%#Omx8_W5&NMEGL>nZRCj zkg=V(?#meaq3roLQ`;jrZ{(|tfi{Fp1C`J@hK;R+S&bx&0TN{phXR$5kt#wGFajwM zhm6#fia4-$3^(puheO9&cYsh-pU4gV$6&!Qz14_2DoHP1y}Ex)~6N# z01B2#L_t)pVfUs8N;BqKwwJGU_*w^W-mNQj5kOY(YgfK`Uh8+@z_V@BthaQk4PwJq z>t{y5KrkNDOCQ(~J@Tj5jy-YN=CI)@{K}^A`SXyU7w7Myf10VKgc>g7vs>%WTRFBf&fb{QZDkPgyzmc&Kzrkuc=`i7 zqW}2#HMM8nwI!S@uu%#-gh~o8U+uQYP0??e2B5s7vq*V^b9F5Y7EeSPm3=XYF@3^- zi%?Jf)P*Wqjsxf&?n$c!0No&PB-1!D7SqR)j5lP8kyAndpoDGyt_(pNEA%TNqY@Gl z#i&MBphiyXZ)FD6P#_76%@L45Q@Ak$0+AhC3V}cX7p@PmeZ#u>GSsk@No@le>NI$< z?Iqc@^tIQ}7zZS-K2h$d&J-hISIUF8zB@*?pOn< zBI`WW0_}`Y2`!BhhXQe65Cw!L;R)8^#M7by+2Lef#(9iV32JW`5k4ah?i(K;u zz;S>#cE2O|w~t+2`}V>8)n5*h$wIM2q_P{`r+``!AzfrHWrS{#SnapNTKE9KO74r5 z+-qg66O`OHMZ%(&13E&9Zezg;Z1f`x{QX?QZ&d>NT`6!)qF7{_DU?=Y&orYN3Mj*< z8QW8!8we^c5-3&NasFE2&uBU@5W>Ch9@14I&3h3$0{}wUwv_oNJe|K$= z-#fU!`n`kutFII=Da+oV{Ujd^QgiKBD=*9A`i33y+h{EWtYdN1_QfErq$1jOSz2m2 zUkNan1jnU>J&g(g0IqgWTk%r>ZY9ERfw9dn3s(?MWZIw>5tO!dgcbvWK#+|J3JIYw z4h$?6BqbqqeTV}INCybQ^(dAO0feAsvp$TQkTz^VfcY$epSjO6*UUZD_OsOW=~bE+ z5&V`a%0U1C+8L`n$|saKxpkfV?$sBE-@X0a)t|qAM>N-`NmRTdZ)c_#(3p@_s2s4fXxK%T*)P~0r z1rtgJGs!3*3eA~7Ku9txylW9bCN`W@3PKbxLWvF-01PRtPay0P`ql@)5Ja6`!uGPe zX75A*Gjw-_QrG1xGmK2-;NXP4GEfFcG6QXZc4n=IW@=w6eYW7w98g$Gfms=lAhc@{ z{ruu7`S|TuR3H2JHMJ83O~QUQVi^;(*M=@yyQg2erJpg13X`|XS}bM(toFVb=9q(~ z{>oUny@YwMD!HYK!>uF$EU*S(>j>Qn;5KILOcl~hGeX6v1ZM+5AP7-F(8db>c9uJQ zO$Q7DX>2=6rVc0o))L4Y#Y+K80nxnt&o57|_2*a2_7rx}J;uIgeE{4g^i4;o8^dU2 z)=``}UqLSTQ^lNWu>Bqk13@Tpa^slz&Q%wNkKKMn_4yn2#B&4EDEs-H&yD6Iw0wW# zL-+L4fTbTx;_bK=%atQujkyeC%t2Ta!%_mu`WH%p*J=R30&4)k(*SM&aAOVxN;5?o z6bBHYWFWKM#d2pcU=zziX|?;)ZToo+6oDkyoZg+JoWC|w!1WeJ7yCc|DyM(|bXrYz zYxK%J&l}DgM+LP~+vGlX?&hDjQqEG%tPBL(5Th^IN`EpiHI6y`F_z1FKb>@b4?`U!#g1Bo&;f%S5IR?_ zYuQzo@YlwE)Gh401-^1wzxnTSZ9i3PthUcdra_M5CjbEvW-9^xbjv#N=q>vy|9S8A z<0nd>J!9};Z~bmopStm7Iru@|XhofNZ^yM@Cl~aH%!P(D<{;K`m^5dR#6zrA09cF` zx&gN5@RizNXEWs#U;>bmjpodVK!G451#}=Ntb`PXlBgC@g^Oo#Vu41W0AS5y!G z#=9!B16<6q@yRQ#v6t0ySK>Io77GtOg8O1nWAW&^^pYDkASjEN`rUJx9<@sjx1!Tr@?3;sd}= z8bW(e9P9bDIQvi|yf0RAuayZ9=%;e&AVG0O%0UkU2%d6}#~lFd&#eLn1`&X?OW>wf zKqFN)8LN?BfZS>jWQ!09f)Ij?B*;KgNB{*Ap(K(3LLngYiF8vx_BCLbO*7@xxTa-5 z=lh`>|5zN*p=yZdHq^wS_iT?2J$TE+u@Mq_!_c+{b#wMZsf_Zm7S}?J&|HQ!=5oI; znhZxHwzt+41+*MBbi@I{&Mq+6*#!pO#{xhA@+R|0P4`mjT;JzBLpXDfwy-&46a^G( zWAn*~K!#xw#l~s+!aX`dKa_Yjlyq!7qUSE0lF$C?rSb7U`oLIy4GE)B(#D461314H z{)a}%@&apE^Y2zbM4#usT6?I_H43mcj&7@9Y7sEVA5%*JLA2!6J7bA+rC-@(E#n?x zm(T}*x+F|Xf$2cdbS5A2GkKYhb^eU$~#YLqqTSHoZFd7fX3<*lu}20f3! zTvlUD>bm!bNptmURg|&9)+7M*0)w3ZcDUD5U0`tLqsUPwLY-_?(>f9AQsAf{s!M@- z9MJTJ8cn}*ADO7*?R%_tGS~TI@Yhic007oH_fI9yf0%RZ*FjC^0st%p2KjL& z08E|%08;>_f-bJVb9J1+2LLHhC!!fas7Dg@NYc!{E#c9>{peJEz#CvKN4%VC0`dG> ztd0dRiu+_Wf&*5Z5)974#hf_<5Y9ZN08C9(=qv!(Iw9--^oQ@5IY+d(^T+wMD0}4e g$NBX?$JhV=0gOpaPd5X{&j0`b07*qoM6N<$g4Mh{i~s-t literal 0 HcmV?d00001 From 3e77f4be0ac8fa543fe97d5c28813f3fd08bf881 Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 23 Jun 2014 16:17:38 +1000 Subject: [PATCH 25/30] Fix windows compiler warnings. --- src/graphics/render.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 65cd195a9..53ad6a8e5 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -48,6 +48,7 @@ #include "utils/profiler.hpp" #include +#include #define MAX2(a, b) ((a) > (b) ? (a) : (b)) #define MIN2(a, b) ((a) > (b) ? (b) : (a)) @@ -769,9 +770,12 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz core::aabbox3df box = smallcambox; box = box.intersect(trackbox); - float xmin = INFINITY, xmax = -INFINITY; - float ymin = INFINITY, ymax = -INFINITY; - float zmin = INFINITY, zmax = -INFINITY; + float xmin = std::numeric_limits::infinity(); + float xmax = -std::numeric_limits::infinity(); + float ymin = std::numeric_limits::infinity(); + float ymax = -std::numeric_limits::infinity(); + float zmin = std::numeric_limits::infinity(); + float zmax = -std::numeric_limits::infinity(); const vector3df vectors[] = { frustrum->getFarLeftDown(), From 299816ac6f3c968cf89f05ade491ecf97161bbe8 Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 23 Jun 2014 16:40:30 +1000 Subject: [PATCH 26/30] Fixed sort order of achievements- and friend-messages. --- src/guiengine/message_queue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guiengine/message_queue.cpp b/src/guiengine/message_queue.cpp index 4fb7101a1..b2c823182 100755 --- a/src/guiengine/message_queue.cpp +++ b/src/guiengine/message_queue.cpp @@ -66,7 +66,7 @@ class CompareMessages public: bool operator() (const Message *a, const Message *b) const { - return a->getMessageType() < b->getMessageType(); + return a->getMessageType() > b->getMessageType(); } // operator () }; // operator() From 01a3a446bb52d2f2af15a751141f5792d1467b72 Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 23 Jun 2014 17:24:07 +1000 Subject: [PATCH 27/30] Adjust the text width computation to take the left/right border of the achievement background into account. --- src/guiengine/message_queue.cpp | 61 +++++++++++++++++++++------------ src/guiengine/message_queue.hpp | 6 ++-- src/guiengine/skin.cpp | 12 +++++-- src/guiengine/skin.hpp | 7 ++-- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/src/guiengine/message_queue.cpp b/src/guiengine/message_queue.cpp index b2c823182..3ae0d671f 100755 --- a/src/guiengine/message_queue.cpp +++ b/src/guiengine/message_queue.cpp @@ -41,22 +41,33 @@ private: /** The message. */ core::stringw m_message; + /** The render type of the message: either achievement-message::neutral + * or friend-message::neutral. */ + std::string m_render_type; + public: Message(MessageQueue::MessageType mt, const core::stringw &message) { m_message_type = mt; m_message = message; + if(mt==MessageQueue::MT_ACHIEVEMENT) + m_render_type = "achievement-message::neutral"; + else + m_render_type = "friend-message::neutral"; } // Message - // -------------------------------------------------------------------- - bool operator<(const Message &rhs) const - { - return m_message_type < rhs.m_message_type; - } // operator() - // -------------------------------------------------------------------- + // ------------------------------------------------------------------------ /** Returns the message. */ const core::stringw & getMessage() const { return m_message; } - // -------------------------------------------------------------------- + // ------------------------------------------------------------------------ + /** Returns the type of the message (achievement or friend). */ MessageQueue::MessageType getMessageType() const { return m_message_type; } + // ------------------------------------------------------------------------ + /** Returns the render type: either achievement-message::neutral or + * friend-message::neutral (see skin for details). */ + const std::string &getRenderType() const + { + return m_render_type; + } }; // class Message // ============================================================================ @@ -64,9 +75,12 @@ public: class CompareMessages { public: + /** Used to sort messages by priority in the priority queue. Achievement + * messages (1) need to have a higher priority than friend messages + * (value 0). */ bool operator() (const Message *a, const Message *b) const { - return a->getMessageType() > b->getMessageType(); + return a->getMessageType() < b->getMessageType(); } // operator () }; // operator() @@ -76,7 +90,8 @@ public: std::priority_queue, CompareMessages> g_all_messages; -/** How long the current message has been displayed. */ +/** How long the current message has been displayed. The special value + * -1 indicates that a new message was added when the queue was empty. */ float g_current_display_time = -1.0f; /** How long the current message should be displaed. */ @@ -95,10 +110,12 @@ void createLabel(const Message *message) gui::ScalableFont *font = GUIEngine::getFont(); core::dimension2du dim = font->getDimension(message->getMessage().c_str()); - g_current_display_time = 0.0f; - // Maybe make this time dependent on message length as well? + // Maybe make this time dependent on message length as well? g_max_display_time = 5.0f; + const GUIEngine::BoxRenderParams &brp = + GUIEngine::getSkin()->getBoxRenderParams(message->getRenderType()); + dim.Width +=brp.m_left_border + brp.m_right_border; int x = (UserConfigParams::m_width - dim.Width) / 2; int y = UserConfigParams::m_height - int(1.5f*dim.Height); g_area = irr::core::recti(x, y, x+dim.Width, y+dim.Height); @@ -114,7 +131,9 @@ void add(MessageType mt, const irr::core::stringw &message) Message *m = new Message(mt, message); if(g_all_messages.size()==0) { - createLabel(m); + // Indicate that there is a new message, which should + // which needs a new label etc. to be computed. + g_current_display_time =-1.0f; } g_all_messages.push(m); } // add @@ -133,22 +152,22 @@ void update(float dt) g_current_display_time += dt; if(g_current_display_time > g_max_display_time) { - Message *last= g_all_messages.top(); + Message *last = g_all_messages.top(); g_all_messages.pop(); delete last; + if(g_all_messages.size()==0) return; + g_current_display_time = -1.0f; + } - if(g_all_messages.size()==0) - { - return; - } + // Create new data for the display. + if(g_current_display_time < 0) + { createLabel(g_all_messages.top()); } Message *current = g_all_messages.top(); - std::string type = current->getMessageType() == MT_ACHIEVEMENT - ? "achievement-message" - : "friend-message"; - GUIEngine::getSkin()->drawMessage(g_container, g_area, type); + GUIEngine::getSkin()->drawMessage(g_container, g_area, + current->getRenderType()); gui::ScalableFont *font = GUIEngine::getFont(); video::SColor color(255, 0, 0, 0); diff --git a/src/guiengine/message_queue.hpp b/src/guiengine/message_queue.hpp index 8e2f14a42..edda96d4b 100644 --- a/src/guiengine/message_queue.hpp +++ b/src/guiengine/message_queue.hpp @@ -31,8 +31,10 @@ using namespace irr; namespace MessageQueue { /** The various message type which can be shown (which might use a - * different look. */ - enum MessageType {MT_ACHIEVEMENT, MT_FRIEND}; + * different look. This type is used to sort the messages, so it is + * important that messages that need to be shown as early as possible + * will be listed last (i.e. have highest priority). */ + enum MessageType {MT_FRIEND, MT_ACHIEVEMENT}; void add(MessageType mt, const core::stringw &message); void update(float dt); diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index dd2eafd2a..b3b109326 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -373,6 +373,15 @@ void Skin::drawBgImage() irr_driver->getVideoDriver()->enableMaterial2D(false); } // drawBgImage +// ---------------------------------------------------------------------------- +/** Returns the BoxRenderParams data structure for a given type. + * \param type The type name of the box render param to get. + */ +const BoxRenderParams& Skin::getBoxRenderParams(const std::string &type) +{ + return SkinConfig::m_render_params[type]; +} // getBoxRenderParams + // ---------------------------------------------------------------------------- /** Draws a background box for an in-game notification message. Example would * be an achievement, or friends comming online. @@ -383,8 +392,7 @@ void Skin::drawBgImage() void Skin::drawMessage(SkinWidgetContainer* w, const core::recti &dest, const std::string &type) { - drawBoxFromStretchableTexture(w, dest, - SkinConfig::m_render_params[type+"::neutral"]); + drawBoxFromStretchableTexture(w, dest, SkinConfig::m_render_params[type]); } // drawMessage // ---------------------------------------------------------------------------- diff --git a/src/guiengine/skin.hpp b/src/guiengine/skin.hpp index 6adaf274e..efa26f23d 100644 --- a/src/guiengine/skin.hpp +++ b/src/guiengine/skin.hpp @@ -395,9 +395,10 @@ namespace GUIEngine getDefaultText(gui::EGUI_DEFAULT_TEXT text) const; virtual gui::IGUIFont* getFont(gui::EGUI_DEFAULT_FONT which= gui::EGDF_DEFAULT) const; - virtual u32 getIcon (gui::EGUI_DEFAULT_ICON icon) const ; - virtual s32 getSize (gui::EGUI_DEFAULT_SIZE size) const ; - virtual gui::IGUISpriteBank * getSpriteBank () const ; + virtual u32 getIcon (gui::EGUI_DEFAULT_ICON icon) const; + virtual s32 getSize (gui::EGUI_DEFAULT_SIZE size) const; + const BoxRenderParams& getBoxRenderParams(const std::string &type); + virtual gui::IGUISpriteBank * getSpriteBank () const; virtual void setColor (gui::EGUI_DEFAULT_COLOR which, video::SColor newColor); virtual void setDefaultText (gui::EGUI_DEFAULT_TEXT which, From 31d8234776dfcdad5077feef04bf9550306f2998 Mon Sep 17 00:00:00 2001 From: Arthur-D Date: Mon, 23 Jun 2014 13:11:42 +0200 Subject: [PATCH 28/30] Added friend message icon. --- data/skins/Peach.stkskin | 4 ++-- data/skins/peach/friend.png | Bin 0 -> 25940 bytes 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 data/skins/peach/friend.png diff --git a/data/skins/Peach.stkskin b/data/skins/Peach.stkskin index 312421893..eab077f3f 100644 --- a/data/skins/Peach.stkskin +++ b/data/skins/Peach.stkskin @@ -72,8 +72,8 @@ when the border that intersect at this corner are enabled. left_border="128" right_border="13" top_border="13" bottom_border="13" preserve_h_aspect_ratios="true" hborder_out_portion="0.3" vborder_out_portion="0"/> - Y)^G^g%LuAy!+M#}OqAqg zUgno}E8Xn-GGW-uYdgNYG5fy`lwwM8dwGcNr0`J|eFcpao$g&{Mz<{h00k(>NPco# zIBfk|L*M88_G&q}fB3)p>x1n}KZ6Q9D1cxY2aXl&y)I8D43bflj+CVtpvZU=^5%EG z#et^ZyBN7?WAce?n$l9K-L{*#sa<%rXnMT>`=Wq}hKyZ_fTAKq&+A!+)7 zk4{*7qktrQ@c51iA1c7ufPf^p0vf!NhkSTqKb!Nt%PY0R3a+nb_11X$?RfIz_(z`U zy2ohDY)I+Bqfg(_-Kx8Wp#lhsdXECQ+J%dA0xUeN9@FYj0q1^8)r4T7_sA9^t!Tf< zj{#1H`Dq=M&zrjzB=5gX+zWpxKiQJl#WxhO8|}HP<3jh_uRekTg2WOcv}~q!1b?=^ z72JG1q3H*Z2R`8ee}X~|!h6KK=5}iz9}=+TtI$h3CGjFLI)5PlL?C$; z$Np7Dr!R}Kr#GJe-Mg_oPSYYopsHSZ?msO_y1mi~Yosa-VRh%2a9&n?*20ag>v9d^ zC!yHjK7an@JNGdY9#o3GH}n}`mWjI-4PCMz_tcd%!~hlE8bEcyurPSE0c`77yq(l#Rd$%z}= zWIY1Y%1!|1{7X94yhB^RHrOSg=1Nin7SM4k92(w?JzZ~m+O7wN87#IZ!ncgE3^go5u_nfrn?ThHrpNEG8oI zw$0P%i@4{r^Y}qVi}$z6?f^TqleXU!?ggu_QA2l1`AAEZ*KA3U@fB*6O~v8Fl?JS4 z(dX$BZEdMw1<|3U+MeO!CZwo z+AJYuIbTCQdly$YDMXSn3yP{N6Pr#MwbzJJedZ}~e*D)_!n2}j45&IIay!*Wr+;#S zOIRqdu;Av&k%|f@f$|vuPT!6$bFp>tfHFzN1TiV^Z~rm_rXXr!Q2@6&lxJ)JI|h|J zL1|_=Sh5b#7JK|CieyzFzbTjj0P*}5RuXzq#DQaV%;1_ICsBxiTBMuI^ghdfA?Dr5 z2faKAlzL(Olvq|Sv!4q(ky?j(wO*e;o>MD1-y;M`k7f--%G>WGM7i9vad|6f*xm7n z`YVXgY`NRV(Ewqm9sU)sSJJUu_2zf3Wrp;=O=$^iBuzQk*8PkXg?JPgVixvOd>C{v zOu=}#b}xMve|`sqWq|`j&C*vwh=iZg;nr(N{hJ~zdh-N0UI3I4J2el+P6DXy$(RDI zrNSz(=?$g@T}o9eo}Af#l-pF68tT=u_BIuQ(BeqJHf(-H!LKt?;#Pf6@AmF9+AKG= z(Acsi*%$ugv!daY`EOm6$2D5j0=`kwdgo~Y-MO@)aE-)l?3iAys?`D1n|6)MZwrta z5Wfhb0Y#X4NbQ9(6cUdFdcHn=!vO8p!Gd8(6}DVuoCD?0NMI@M6_FFbe>y-sn=2Ba zCESkOik@Vl=}~H191HyUzpTP36Wt8M+OVKBStK0ojgcL`UdcbXM2b7_bN>51CCiH( z8WAn;Cxokv63UF#?2vT!sBDB^A5HfLO^}8QUh>nnC}}AO?wB!;uS4qp?rm+>N)UU+ zU|ApCOfZMY(;qxQsnci!x-T_zuzXA?(Lmfz5!eK$RRaT@i|)+~S5-s1QpB5^6hqXL zs1GvscZ$&OM&h&mSz}ixyXQGJr6~H3 z$++#ku(nl|+>v;3($pMJoj{lfrq!Hj7LL$cXW>5Ml1oXQ%KayWu*~=P#uYK3%+Cj_ zC;%C*tN>NNY-{;kaLie9TkNYflzo5!rc|yK&R#(Rf++Ibbw+ZM4(gDZaR&g8=ee5O z4t~7*M!ns2$me6)vSUZSz{4^#DaGCi{RH0hLV*wu!PK4U2s+f41rjJ+;?t;#qOb9_ z-a9kwbiHicQ~bVbT8y)$h~|E;V=#NfUSsSp3RuGjy#}sx@%9G85a7UArf3;r z+|w78amRdkb&5)d8lcE0DZxktlEhn4RE@<`1jV3u(*m+RLPM%0~x!*j~VOCZ$}^^%s#&1$NCWrkMaJU0MB6chWWFumX3 zgWt;fS`8Mg18*n5lnI5ZXR4H7?ODYSG0B4(}b$_ zUtTj)dfWs?ZjP7KHoQF>EQN}D(~0m}yDCNlDGHBiu7Kp9Nw==>SKL2rG126K!HoyX zHUY39;_cL?uJG>jdn4pljSnN3s-JRb>|O0Evf3nk)BvHcIzWDfV7{Cz_BbclUgTpn5=BQ&J9->F^O zt@Y-ePAB=P>%<)^0;x4ObyJ)L%M@Mn1gc^{6d?hU8uz$Fl8QiuKT7}xh*Xous2_kp zStvM_CUcqJ0*fo}0@q)f5t0Nn1!JS=h)5bG8L>sv3sk={`2#_DpNeO)UE-HaF9Xb( zsesg0L%swA;*n8eF*j9wOVBhavl((GP&Jt859+OZF%Htck7nPm$FX);+fUOg3vB19 z*>HdJFk{-Ar)HY--?~ufaw-cWU>9l+?KDra#r9=;`gEr?Y`9Mj2r)1BqQa>iV*B7Xu zXKx1m0M*RYX#3Q5I6aJI{R=xkjbExAa=pEIM)(GuSC|#f&h`t%SIF2X;(S3znk&Jm z1vN7dEs5#;p`}O&T@; z6eFu(Yk}Ik1BaE#tI)W7No<`!e?}hKPz*fQkG+OS!~U?Iwk;@EAJZ#R`QW9t&Kka&XX6c{nHdg(~a>I*%$ zf&D1ZZcrM8OILsSwG$|xm!rMjLy?-cd5k;;{+A^~gx5=l{$yN1a)YvOptO#Zh~_Ar z`SAprVEma^gWK`b*J8kM1s&=zVrY8_%q4GACd&oE*^T1EF2)n^ZtYb!9l;<5BW&rf zFq?)-Mv}{6KjRXuCu@gb$9wE$n2^9sNFo3@iEgoa|?dKq4SN6Y^y{-m&y@@_<_(RS{L&Mmy^t~Gs z1mXM*KBGcD+l;Oz_cfgfEO?6h4w%8T{o~TTyTArZxfvU*fL<6Yj4}-Ns~S)|TH^8-BJcw>VTkUQ~@pqUlc_pP-f^m6mm5#^w3ic!9 zT6yy%ZYvP9`ML?9h4KVo`h{kdmywF#PsI#_KWcI-v_dr* zN?5Spw}9|ve;XWBPz;uQSHJ~Q(84Ftt`lqi+guv}l+DH2d5_{t*t#>V68Ev1@ad$`LN0s89jx30p&s1WC4H%PV^@T0~78OA@S(H; z6{V7L;JLWZL{czCK(y9(t`QCtl@<$oTkXvo?TEn7a0RJ1aDKF5YyuFA`dqs!U5>H5 z{0F;vzc5lxDCV1~kHM2lAfxc?xr{r>mUN;@%-GZ06+ql@?ckX@VN~ zZeWK)n%G$b?L*3HW-JLMjs}1Vbc*#PjNyeks)Sq>@nmFqeTdSjMbB;UFO&q@P9#%V0dD}d4sK9io zfw5cc1iQjDrCJqRSL?tFmxDVT8cdrPI28cXVNwVtB&{SuM=Qoj#HIDFt5Po_hDA@* zIdN7e^%GUqO0DHp>l~#LWIQ}f)(VPyC|%0qGOCly;p2=A%!K7|f`a@rwL@2;nP5us z<0~9}jWFD%@4US{d!{7BCbBv3&^z+byNCvy-BHvs$@<$(Nh~xUDR=$kp8Y0Rh1 zl`IjpA5ozN?r)2kQR&ris5A51;846WNGk5haC#m9KPv&C(mryt;7HLo%3wtXv|$g3 zCM*BM&CMU!>RHyw`BZG!8QDmEJP1KlR&oyy4@0rLN~i+((Qw5sBuh%l{Jh!sCJR(H zRi3w0>^Ck6lQJ^oayo>3(tmhJZuV$U&@}RQt{0<(|0Gc7fijesLpr!7q^x0>L40vv z&whNP%?qGU%uBr!u*UJrwHP??I_F`4Z@-cP7>T;mk*81-K3n$%-1s+_g^Z9m>5w>U zW#b}Q2LF(5Yd0fQ#~0XIZFlIX?6s?@6L0l`IUb%ZO2Q;*99tvjC7CFf!O^z!84FhT z=H*y8>HsRhX;}I_O(IASgK60Dsc4608|f?RpeDXajHr}vvZ5J1*OXef%7EiBW8`^p zH^5++*AxJfzu`2k7Nm6m1nfwo@Xy5!J52|t>DO)OxZ*cZmyx5+r7~e~$3ok2 z_D7|PkbwdIayz$Ok$)qUw#WgEg3~-sAN*1Ab8G|8BPOTVwaYM)=haOdwi$%$A!em- zF^u0xg&8<_7ff%Og)ObzZV&>p61ZMV zq#qiu?FOGVij+r=WVux-YWG>z%j&*&JigS%=k-JMk8v(n(rR2XPRF!+gutiv@38<^Ou*c=lh8)tP{u!pX&*Y;Hvke5ml=h8 zX)V+8?{@9hZhT1(IPn9vSiRnj>1i=|?dFjgx;G)tS;5ioYjt`=%GzJmx9_&zSW5gO zZ20?MF;}%Yn);x{c>QbLV%6Ymi0Ac5UzwPv{h!*|ji~{Ro59sb>bB>{lg;js*&mfN z$lVP23P-HXm}?oKmQgGqV5VV@mKO4!3_?r0R!Dnxf@Qdn3`X>;NgeV(eKuZP@te_Q z48r&fB?MU}V0&Nli(6qw8uGKZxB7l5&Gu?J^H`)M8OUezBqZJT#pt1P3Dp6aSNoxx zM}!aRtThW zr&YU-WqE=Aw7%UN^1S2ySDxloiBD>UtlNRl8=*l+09{t5xzM3cwpeH!QA6qu-FHl0 z7E|(G?l8=yY+>jl$<2_>(@|<`>1IAhsOnb3y z3CZZk3Se>u%PHdt`NCxwoZvKQEB{ynhmJpkWWwWR)&_ELytenzMmR*+?-p#zdhH$- zeZ#uymxGFmn3?i0Z65Oe(C1Zn_q`gnT@JM=ZzWl*|K8XB{J7dzY1(JM0ouIPpzy3` z0mraP0|_cf@Mdm7v3w%h?~I`YFgo@xi9;U@CNt&|3oK^M$lBOy>mtzx)ls|=O_O03 z$Ca8Jx^^q%Y;CT-ZdsX=Me>Da+GVvL=su`9Qg|=HWs&W_P}O>Yb76EH=I=8hEk(A6|CX#L6|B=H%4X0*KjtJA*C zZ%@jK5WA0?NY_GPkn-tEg;I;*2JIg2NQ0;5MGjmvH#)IS%z zb{&$!)Ly{teo}VVl6nXK#6gQl>93g+Exv>MxurJ|;3{vgnLA&X2Z@KB&?8Mii?3+z zsyucXBPfsGn{NB>RRP7b*;Z;R^E5C2&du`+hRPbIL$HW%RTE%>5i*(JT)JyEVpzcD zF1z^s(dSfATo~rzVmog818ckA{c$_ZuV25ur!{qvfQ^YvW{;PXl2bclUVcj>7OUH~ zQ+UXKoo%I<#sEBw)hJ|EvpoTn^*y63OH;~%uTBZwB?iR7DQZ1GSg?(zvi8r3mP-Qc zjil2biOT0 zV3-=_9!z$97qEocu)xoJ!s*Ta9BS?GFwJ)`+xHkHN9TCfgqc~i!-*gGhf4+hA@V6k zCdm%4>Xn7~MT$)pQ2Cck{B}TPqwW5r@8aSj$lrJ6tEh-bSjOGyPgT3Ae?QxwPkz`c zY^IFP+MgQ)qKJSX`>D-%ATu^>nfJGNYlKLqsE0PZv;(EX(DB=uI3LVfPEpGeM@+_q zM?JGocxl>o%`~2QKlbv|toLV%JHwbrHw_XJIVfzFhl+IG{>}gP*L%E4A}w+}!ZMGb z4{6Rvnj?^4oNgEszNrj^$bRi|$zVV&tWm}=l$Dl3-$cO+xR1|_n&ls=L8hGH%oigz zpZm^gRCHz}F+PDv*9il~w|Kuzh!f*JslV$hXWe@XjX!8`HXhgr)S$RTla@!=lsA){ zcs^6lRhbXvBYX`Y-{z}OU02*0+fM5ZkyxCfQJN}@H|wl8!ylDCe4^ImB(He=5J3ya zo})Cte$Rl@yfgJ@kqD5ipC$ZV|Hr!_gZt43;MODHkgy+u^XKeV@Uo-4bHMdABneAF#g?@+3nf)E3O z!JpBJ+jPD#q&mvYOc?hIjsW22TUwkNdY`rTwmsepP(PeIjlC@XRZCoRKa@WouNs@X zV{oQgt(B$xmsHYZ;+#PKVdQTtJpd=V3ZP&=@*B&rW<+N-sh1}SHQXg$zP7UBu;y8d zmyRKt?Aj+6T;u#DLjXB%PTA`ArTw7j*S~|GR{>aJwuf}%tgUpsp&-NZ@P3{(e?P$L zQP3fyQgupo>9@B>g(E#ok>+DIr5SaRtv*<&Whu5O7p+tcX=gk^8~}^pQ{Lp;j+#0N zz^6}b3wTqB5!cZ`SvcI+&6kcRwKsh-xLY(bg5DwLfiM zcZW3kkJB;9Pb|dY6JLrx*)JZ|Z|0}i_2Rzv1&zL*b=$7#job$qBcV#^C$5iRc?>HQ zraGvsJk*FB0z$EnLInrG%`r?7id%dSKUj^~@s!^4BlaS92gXW+Bqid8K`om_?3n( zhTmZv!`^n~a*lyuuKgKs+;ngIK}97h^`-Xv64WfYu6o}rXtsr#%0+F^__TzItO!Rw zF1B{f5+ngw!SrlwjZ9f_mzH1gD?I;T&wBMF4- zXSiPgAqemn!`_D*2<74z3(R;JQ!yS&U~ip<<5ay$;v_C{6mi{nLvzbz;Pnr6?~W%j z-FT^nl&oCHdZ?DQ8t5ITZ3_n`|hi~iIrlHka3Y_`}vwjEdQh#dUH+qF1dVn^)5{r zN526jQv+zIW{l)y0lWeV(L=t3SX9<4Lh%$yuYOwqG^N+WkizMP%%n$~)_2h-VJQi& zF0agrzyWyLU(GbB{(P2iZUB27{YLw{5dVoRBUL7@cva#*N_^UA0x5{q_kTM*6xRQ+ z*Qk*)Z6*GIU~)XLiOY6IDL`Zrph%E3pbdBr(+)#IW&^~H1AuQP!rvncDdf-tL$I)> zdp%g;`0{>rBbY)iYIgVQA!hd(0JrJbLam<6KRU%xS!%1E%>LvK zb>y}-C7-#y+*l4HDLD8t@q1kCNAU-~1tcY1Eg^sx@CqaZvyWIte7gU6GPLLfLRWXw z>F;?K8MC`O{jAtP<|`SU{d+ql!R;;W@^81;mYFfP%PkfdNDXhT^~9Ug!lFLB<%MBl z_%yk#zj(pE9=)3A?Q-OkcBSGY7h5Jog%bS*Y0*X!0aIMHPtPKHgUu#&#D)lRV&~}^ zCa`~@mVj!`QRx9A<#QpVD^rUj94Y6EjAl9TI$ip%Dkf;$`ltJ&?>Yi(c49CCuzaZf zoNVE*KS@~Ob6P>}KIVl@+1fo#LksI1UgFMUdqqRZYzs6EaR8w;cKC1D&b!ZfU*L2y zn7;v#NgWs>hd$d&q)$(dQ*)yu&^5K28MC>pzmgHVTg)`h3$h4PS%Y_jYL zZe_sp#DabrAsrh#45$SVYzDaKzY%p%9(^rrnO~>U{}Kx-YSz3UFMM%xjAPc>9ATAnCiFr_oC-#gzla({FxE7q%YKn(Z^pmO-eZr zQ)6S`^TnYfBv9(G_!mJ)NhhOxXVpM{@R~O$P9V1uj;aNz;EEm`m*~a&VEx&hf*qTw z8e}~YzZuML{^uBF9b8#QvfxM0P19~=;p@dR@6m^_FTyn-Wit4$p-?&o3uGaoASla! zo4uSpNFN^mF^;0Ak*wC4d)Smj0e-;$x-+lVd(40EFY3ZF-=o2Rq4zG3Z=c5R`#awh z?RK?j>!I=jo#%(Z?Efu|(h{VIOzfzsvGX ziKlU2T< zy&+FrRbkM`JBaB4JNHPHe>{|_BN9!g)|4}CTz8~2iFdKrTn_+HMYeDj|0cyaIYeDC ze?(_0YP|}*+1Fg;)GfED-pTHFp6{>3K6seXpvU_z^sH>OLh)yk{YSCxK zIBPfM%UfBHpE8-AInwMdtAzW$#4$uWCZBqFhE1;s%$8>i{EqR(WtI5tNdq(G+Z1D{ z64OCz(Y{smhyDbS2bz9(iVd#}c$~qWr)nTYqy}-BU%}~!Awj3?y<4r|_sCc^ z2>_F98DgR(?Q4qUcZFD^uRrkB@mKC6e|T*mzBgE>NEJ@(GgedpnynaZG!ScmRpJMg zattr45_rYo0ln~DAK5h(3nHj$gy0tlQ31(QLJI>)>5GJYq`a|$2GO66V_Dq&7K~*- zS)`f46sjIPoqhy)ko&}|iPu!I^-Pvqw56*mQ;au~O*?Z3n_dlaGd10j1z5cc5$h4JDCxFS99fE7{2irKdoeqR5r%F&zv z&qxc1mnxl9;w**aio=r!OG6UHN{9r1o#$3#gTCXxExU@&@qws2B($ahgz8O-In&1{ zcQp@hOE;yif1H=0#|^=qe`}rcQ1Q=T7|Dj_TxK_*q2_j_hN)2xL8IoQG7r$6_K*kl zp824IY7GH9LE4T3d;s~Qbj_7qpbAKd8I3u58Wqz!H|j!4O403S`AI0l#9n{C%PI@F z{~pAYBM%uSS)gEJV}sdOGGzaG$_jq+&O7a z5DY?WqurlTi!%==1_@Q0758x_|69DyRs(&Sbv!2>=eqxhec*gf@^Mox$BbhZc|}( z^>D-jZp4_~k_-NyHbZ+>ofIq8MT?i9D#BdLru6XI`6vG%HL}@?czotyj{UIuL$0dI zQ06o`m$X&abNTqO*cvOkhjzHH&W>dMi2ik>yt{AtCDw>{WGeC6!G_%`-RS_Xtuz^? z=(#lxE5E-M??{H&&-R;YiLUQ2sZH0``{g(0sHzn6(w%Br%wxQkIPm#Is}X=iPW#e5 zJq8z8(l%WSFW_UdelvuHnLM^ZTV1;0fD!^^_$DB@zpMS2uP3x;-D%y}K^yAqPnoc3 zrv=cakN1^M01q;@=qo!`j+@R0A50&JMXa#X6=kYq5*E7Z@E*B6+d2m{Vf?KF8TCqV zY(E!a(2vkWtBZWBzz0Q7IRUWN_pasU>eIID=XyvM9qatoW1xJOao6z8 zkzDjCTIzX4*+E4w|4Zh%n|lZXSq|)7f3@H(5^bl6ETv9z1zj5unSCwQ+P?KQ`o5V6 z9Rg-jF-)-mW302tZ|=R*cm>(d;rZvY8q}aEwy0=cRP{dlT%xN#K#_XQ3U2}AKfwdH zBPTx@o78vCm?zeJ@ALV$isd5LunccNQav{zB6TJ%Z-@6@zdc(|FMC3{=S34tTXtVp zw#i>nlk$VSt8zl{ePkDZlOm3y-M;N<#JIZH+K0jRepxdb1-U^{1xUO^sW@ z&#kW=TOjC*QD43YxR)?#t`?U)d(_-szMsYR^Pa#4#|HkfUfpZ@#e!pt*Vm+-dzL_s_ zqpZ(DG(=2~6;DZz$NtrO51vg7HGu{>7+bZ0xh5Ik%(-wEwpuEBfzdQ$7~VJBb+&yCYY~vga1*X` zC>oKJlz^><*~k;A#O%?;jRDlo+;ZMp2{>{Hn6T9->=t0D$}9!0p6mo1O||6x+8$F@ zb*@IkOpH(l8ojFplwcVQpXv?NuBtTd?YxP&QgFB2MTeuakRJZ(t@n&3jC}gn!xiKI z{K3e~2PjEKqd8aWjjhy|SW!^{CpElbY&q|xRHLR`oN7MV3L(6?%Zc)vTSGy&`EL9!zj|xUX{Us=agWsV!NmOaGK1)M5 z2}(GWZpMbaQ^)zguTvU$3&}1bzz3IR#R++70;U{R-7`HEGdcyMd`;JD>;xf`#nPl% z?IsA>fN%Rcu#b#f(M$-Y2!P@vNIjP}vj{~C#u5|s&oV}gV_)7Z0mwgnU#sYedG>(= z%B=)CzX-Mp3bxHqb9??nDCA&*QC!R~`p=(c{Rv&7p$G)E?H2Mm6e1x>gc7eO9Q1Mv z=RXwXMe3iyN9W`6LJW_c)AI*pq|V>vN+lMNd!aYm;j19JrbovLK(U*>VZ ztjc~6ccLn+w@ksQKid~@W5$X8wk^IK_a9ikg7qo^)U5g4@u9jLrRIuCD9>|3=T>+< z`dAl-;p(U)lR~j%ianA>B+}7x)MWAM$XhVfP=y_8(R=n0 z8j2urmv|!DeK+Wy_8WIkw>f=Lo39Q#4i685%85$(4MaSMn1t?UvJQ^F8s|0s4iNl4D~hZ6t!FT7taEiGL z%9B=YK} zkI}|s!~K!3k@*rg+SNiJtd*aCWtcWO=%d9#`{wiHe_7R&z+>?iR0$7b@?BEGheyr! zP;?p(JYHU2ZH|uj-*-pTx@Kt}(b)`I;3%H|xs86*APd`~2xH89Y>fY>@HO*-(-a3M zfZqpE>+O&{E6^HLqH@$c;hGjfb;ob-GP7=Z2|O~8k|nkcN*TsD)R6W?a}kuIy)0TZ`(cdu6XZ}P>Fky&Ag)NtC_hO$MuCv+-^#A zo}KYP!Zj?dZ)T!KH~;Ey&eh7A95}&YRmIPnIq8MER(6rBCW`0i5R#Af*CyRV;R(*N z?BfxM6;e|!R|5=&{Uj4d-$OUf^1D`EJpYu12f(~MS!@az9Y$oz8vAVyXX*Zkc}W*Q zA4I792&h5ZS)>Y@NM|Gu&eI0kyzwbK+Q-|L9QGdN$$71tDpc_A(5BdJBXr{urv=oD(O6g;)$r@baet+qhf8P4Ijh7*sikzeHFN+fo@NR&n=t5J2h!B7cckPcafea&7>#oo3Hdd z|M1UMyK=Iq1t`{r4h$%0*$B!2J}4`1_|tenu9qAIlgNKiZBD{bPM+?*l%hNcVSK{g{&F$iX_yz{p;v^RO3>_H=h(X}={yoq%C#YU(!IY}-5P z^RVf5;<@_s`(hn!c&8H5Cnp=88<#X+W&X$0v#beIfogLF{WWr2)38TE>>2d574`gP zB&`{4C+3YW;qetH;duS!;UZ19()4|!!>D$lReIBaf~o=Q!z}2XC7;@Y^m;76+Bb48 zkyle~I3{mssnGOI+_gZ5ih882QoJHx=cZ6D7Kwv41@7ZZai{o`hh>-CkeBaY54F)Y0lFx{evz`ZU3Bw2t;;D1)svw> z4<#yS+E10*14LGyeGZrFan*<-wgzL=rM?u;)%!|Z9WVa$e^JPRBIbwvjHgw%&29y@ z@|jc3sJ4)89qQ+e72%h3gVau^tRz79pw?$3JIev6YV*ls_rPU#nkQO-yt?tLpg?Vvmn zV7m;Up$k6`V8UiJ2W+i8c7D4NTpiAN6(jOZpZZ}cBw7~bR!8WT`L|*1&Eg6BX0ZyJ ziF+-O0CazS(pB!g!`twTK<5${7msa)FOJ~h=jZ32p1#4|+)1(PtZ%<$fA~l9%stZL zj^_K6x0#e-*um*#^}^RFgl(gmE28Ep8yE_9-D%Dks%)alTnTy}foqIi&duhDll)0X zgmc*RnFwRJCW&K=gq**Z@lkxuX_HWN{J~HjW?)X#1axB+n^Zz6c;)m`!@SY0KNzKE zOK3wyuv8Op+ zf8iU2yX1)5+t#k~r(`*7e0N`e&W)Z# zPUwBx(L(bcz6|$o26z;hRm^Oa8lbL@$tK0!8mIuHb%5j>nB_GoR1rq=x+pWiSkx{a zPr32}s)izKIz|XoPve3Q$TmYV`g-!_S9yBhJ{Cq2xrpmgXZh2e@6YDrX549O;>7c} z0m#Fd(i>8mXQ34#ZwlX2bYHkfP9$S`d+<-&#mJDy&9*rMUfOVA#rBm_9NF-U#*f2N z_7MZhA#&=(Ji&!48&5iV5%QQ347j9qy*Xc>B(ah1sNE}yJ&#A*7%9sfuK!D5cwG&d zy8`XlE;l!6L(={})%XN~c6AnT$CLqJKus+kGuD~Q(`K`xIiZG-mnw3) zB0TVUuGb1Nk4;mKih+8Cc!4`3lG%A_d1gP$zf{xq+L2TN5~cp0j?}hC*^{t zu~JZpW&^WosubHdoLrDm2Nqncw3D%1Ha}8sDDpti;J`H#OopPh84w6{SzzO4(`J%4 zynpy^Lc}prWwt#+Sv9tA67?RvZ&{um5SMm2z1}v^Jq-4?K|(*DgHDzc<`Ya zJ$7hbM>%N)n)@$DEbrmU63|n>@ieZs4Z6y7B2q81{@xmzP=4$>< zlJPWbdD`*6&71e%lFoN>b)(>l!dIV;R(tIpXYAGw=d0Zg2hJOw$G$9y3Hbj!)s^5vdiZ+jvkI7ss42>-(Gp=JYQ>fuiNh)5DoZ=oNB zQ(63IFaUfC+E^HVN!k7{z3$h}kc#3`X?Q9!j(k4*1a2bitb;yOOo3mc{2@O1tjT`qjGq<<_9q zk1vieM(%Y-2qELCXZy9M+h!-r)9HC19xCXh*@r+4_8V>VYh3*IvxgZIoab_O9^+K9 zk*kj_NaYW^&f@s7SNJdsIK_HJ?SSOJaY}{JI3N{8R%0f)xgcX*pDFEt2_{+Y{!n9Ujet${r;~ zla?zB?4j^d-TI9J-#g>OxysEdj7z;y0bX8z^w(~HjQgeC(+w=nwFoTa^LcF;87{+$ zcV;LI+4p>d^?s$k6I_SZt0RX_9>h&DBQzFOJ9$UANqu3p^AhM~wMKK5MPa*q9CBMF z(e7F>(K7EOQX?RHUqtIsu57IJ6HXRa%cJO6Id7Wv(ZI(1SLXu8PlK%VWw3I+RZg}| zgpw{`0Sd&^IiLzDnjGhmrYs1t-ed#XV9a2WhIAg+3Y4j^&&B&y80l$Qc-pcPfE3GW4D+AcT1JHFnU zBdwE^rz2iYG1<_2s_H^j$)CGj*~9zgdV0u+QvP2%e+|t|iu%48x#9&tSzzjPL-Z3>v)-oZW%=K3 zw845D#JzrNy|rjIdM-w7EEwW3i_nKflCh}G{+-%Lau?7BiaU2ZIj7Nqo+>N=F4gX+ zlC`U6)e4#sK>bn}8x@{e#1t>0jSmuhJ86GKD5qZ6cogOWBQ}jsy6YB`-!2Zn zn-FQ26HumEO+RHNE)f9p0DkO+z#hwx+Jkz^|64BvV$Epi)CtTmo-axaAc8N+%ViHK?SS-6>|iSK`vB%teuFzL8@Y)-lVj6DkPG)WIq!!{K++{JF!LFH%FO zs{jCir~Kmp0PR8t3AKa~Dn?yfR4iruvI8B9#1i7fB2WT}Whlc?7BJSrSfG&r=a(!D z1eB7v^X|K`{Vfvu*=-X-U~X;>`}Xa_u~%P#F@%#BW6ZAv7z@Zp06Fbn>n5)sC$@S0 zz5hjPo6$dsVbr{Jkhq8~HVnFYRxZAKS1^y>8NmHe0KIOeG8}UeKrKq=^jiaF5Fv#9 zP+ynJTx`}@hIxKv1x%5;{OywF+I_dE=1*lb{4y568XCx0R}4;DMhKUrl+OsZHs=dS z7$!)8O29~lwHDd{QV5(`VEo{f7?vfr&Thed4?KYB>1n*Z0Xuf=z=uBcAw2r`e-9-I zN6#d9`HdJ`$6WImqm3`aZINi3Sz~eH=^me)r~P{={X=LLgG=iI?VOUU*KSoyxHJL? zD3)4Z7NCK_w6E&~_$a8&1O53MifX%MgiTpL#b(XLD6We^9kYyeS$3WD8Z!z!w-Y4Y z=B7yYav=ebr-Alq18C`JpnAd(!Xi|ZQ9vrTs01R*2WV(Qpe+(fP?{Wo35&W07FS(_ zP!vU&o|$<|g?@J1!Z5^5H{XmMb91J2;8{MK<%!(d|B(St7GE+ z`=PitVlIYJ(`is+8T2vBM0S;-SBf-;;VwLWnf1|0;88yUAftgS;{f0yNE+IQbXv+B zjrG_GgL+~S1%yT-5Xcmq7=d9(0Z8NO{(}fo2<*Pk8%az%G^Bt z(jpt3G*uMX%0wx3^Aq%I^=#%`jM`X+xz_rL4lBBzfZ`6_Zk@-dkG0Yl1(ec2Pf3A? zwB-pU$t4u|WTVvC7@MYM+DI%yHIC;K-<+{X71(`sNebi6lpPdj$wg09Ckazw9U~PbkLVWEu zb>Z4=auLn)4`m}&dfiY(c=~>LbQA#DA`aG06cS2~6J3tSC}&~N2+zf+t&3rtA4*b- zz33sJcZrC0<)nMX_4f)P?Ph6|769`Aek=*cE#oF_fIy}(<<0?I*A}5}<^(hnMif}Y zS|CtBl2|Ay5NHc22w!`qfw%!wBF4<@76dYQ8})Nr5Ck}U_%J^9GatoY{pDZ4AVFf& z*nW#7aZX_Et+6XO8 zzVY#K9KQ81{{CxUL$Z1S3o9CPF_KN>6qGcBu9|~TN^@f;^>RgQCSO&e; zy3s$q)?XRwtXF-YBIjI|KJ2R$#2OlifybsQ^zdrTGpRFJWwGaQ;I9akAhiOVFCf+e zGGQob5om&xl${o{#nQq8PQGz+L%V)m4jn_1BtgAiLnCQmc_qP*k6Fx300G&IW^<80 z77gt}KT}^!%J*mWntbd(0BjkfcEEJ?rdM(JJ4!1I`7uO5mMdQ|coqt)= zzD$G+^|+>^G8dyZmSLS=5lX0trO-==pp8GEDCoD-=!>*{r1c5_0C=jQ`8(R;Lzh|s zKwUCI%~*|{rY{JH0s$!u1QDdL2&8}zHXF|BY7Kw$H-Cf29{WZ)O?jPdASBk-JsygL zS;zPQSNnf{{vwtam!OTst7k0cuO>`|#({inu@XD(zZP56Vn!{tYqkF*SNg%Y(hqxQ zXM^b6E|wAI%&+sG1_c-zzk+7o|0db1`b`V%Te~D8&bq zb2#@JTWi!$yZS$jA!b~6697kJjVD5h`z@oo)(RlUM<*7cB-Es%epVU=O1ip1O1sAI zQUFR4j3pRjaOCA9IP&t#8>(GjK0O0{-(Pml+(cU>bL@W^O_mC1(nYkTGMs$b2#{WuLs3q2Bg%V^oQ5R^${curVuK5)0qnBxf`G7N5+G)*G#vHQ(2QEc(LJf=pGN*P zwf|vZjV6{SN#Uqc}Q002*Ei_b}c1I*Z?4X6f&5{y~` zD8X0}7J>jF071?nT#FfkEQkb@w0Q6afuk1$Y6&0(K?oNjN`fE>AVDBXAKsDbpR-Y? zlo2)0WettgN-5=Dr(a=zIo(wx|LorMx;Hp~joZ3za&L0lXr*Px^ffno{HCoO;hXBP zFR5*P8%=9{u{Xo0D&V^93`qtJ%~)v|)M7^k)nkj**kUzy!lB`Xud$3;!WMND&^p2(3`I5@^xFWBphQMKt$b+9L{RiM)<6Y~);w;#h`# zOkSr@0*Z(9w%f0aB~V8DFI5b#trY;^KO2jK0Dh4TTO~=C5>SqCl${KjPce2ukPA7xkK**GU} z?4E0}L6TUob((#x;Ua%hu#dG90<}gn>(^LdHD+rptTqsqA+Ft~j(+r(>We$4Ta0NiI8dm5T80F`D3#~KKvMI#~98WxfONrY8lL4u$ZfrLawT7&^1 zk`|SK5GqC`Bq#+a>1Yor04W8ebOJyKZv_Ye5(JTgzsQ3;Wfp^z6C(YmiSMb#p9LhX zz4onIe>PL(XqYCrJDLVe*|%VwW>4&D@F3Of)3%PxU@O3up{<3{0>)Ux+E-fDggRMB zFzT?d#=>Zex^W<1^BRBC`D@ouKZ#+iHmt5E)}}pwrz$jmXisqT;O^jD0cT|q?GGiL ze?b3n`Ta!Bpu{oDSQJH_puKLqqK@NHn2TN-|3;66hj`4Qib+vxkP3`ae#FoNyWbLh!PAbtk?PhAzW0Dl7yQ7pUBfcEkms2$EXAV3ucCr z0tQYfz*-OltZ>RX7=Xx8JLw@AVA$*f62iTgeMlf;FjJEy;wI`hkKtNck_DL9gS@AD z*nQTt2Hf~8BeMh?_`CCPHT`X_SAq-cw8k`@xrvYTNh}&MXR-dZ9Prm;ZcF{FHmt5| z*2Y3wh71JagS&$lK6rif3Ys)Pj>s_vdU9^V-AFdpGC7*KeP z4OkF6!GuIeK~W6JB>99OQ6xZ$6!;5Ken39vTf#30BnnYp!XOj`D3S4tpgd&H;DmsQ z=g!#9|M1$6Q1Xapwv?cLnc+R z$P>%~iyVq7hr2$_dojegp2WFW=Jn-jF313)oIGt$``$ZiAOIW$%m!ph z1yUh^48#B?sBsn;7$Xq~l+ICl2s%ln69%+TKSd8M(<2?89%v^TcQ|}XoDRi^pf&jV zg|N;@CSe`r$bckX-^U>?A+~7tj1U-A#Vw^%B>?aNm1pc$jJ-NwcdGPH;{UtUPva#_ z8>xK|6T7#{8!y=Z`PFxfUU=kU`AScrb4WEUGL7v~;c=hhqMYoUMVxI8k1st8+M>Mw zMI7^K+>1qA_DQW})%WZ(hv6tnEQew`NEALu16VZbu}=Zs(i*^=ARIy95`g=sUV=LG zY^*h?z19YpTC;%w{g+zGW#3xF%n7!I3lLZo0sssfjjS~S5(8@q4E5j*2!RZg2?`MI z=m8)#$|Q3fztTAKdnVMCfxFwqbF>f%T0;*(%kd}BU{MN4SilJk;t&@fjelV6-s!!d zX+mtW7ci}*_4@bffZd9*J=K42?uFL)??xS9>e~z;-l@2$yciZ8BYb{DH$HH&c>b5( zI=Y7WiC=vLPa5zBk<2$;E?2pTyIlk%=xOY8J;NOD6B$P4H1EY>Q>jjBEwYAt0{Q)p zaw#(O6xQirmGMw-KgZzrzWM;bbpT%h@Bo0%ieRJi5=uuVQ9-&6Eer!R1ISslqHxFG zo-_VxRHNZ8Eg*zo1toOAya6kWh=DQD5vKr-;;%6+Zv%!TomfF(?!?GU6c)6gKwTw3 zX3vx)Nxo{-)4p<7_>H@_9 zhfEP$WIPrXtDV)oI4x^g^*ym5Qp@?>K38s`932A0eJ@%E0KA3@igSV)fYDVloH5uj z9JPU2dT9C{b?iQ?W(pR;SPbGEbZ}u%h(RR+X9Fx7upu}Lh*hDN48cg^`;8iGlN4W4 zkVq!KBN9jSP|Aq}9VUPFq@!_{xnm(KcODRAvayJ50wJsXA1Q-@;N#}j*xhk_JTTZ;*(y>ah|nh1_LcR z1369X4x`<2vYvne6~aRRAW=b^06r5K_cuXHtR{ul1_00=KnE;2#G&N?T903%=RE49 zPO>AVQyjqsfUUqff)#-wg0Th^7{+StfTm(b<4yoY%7)U5AeQ2t)v=^uKT&&`rxkK+40R{$~%cCN#!>FHwvVREqVo~&+8X62LK^bC@qIxsP{Y`nP@}}oDFc!z=>uOIY%(8Sw_qN8%_DN z9BCk^p;sP1l?24pPo_C)h(ta5R*UFX0TUwkFKvd9u<8LJW%@+UKZq80aU9Uz1f_qp zkG~rFCie8%s~L3@uv<&y_5*J2YSr&vJv08X?StH$^6slUp{awA4=9uIcLvov-r)ZA z_day)TaR5Dy^xRLHo|5?K89^heGO;Wt7{dA$Q=+S=x&}kLe%sPPh2GsNV5b#&x%K?_ zYL=gEhgWY*S$q&1cxL;*a$&}mr9I`5ey2IsVTpaBN{sB05)S{4T5U{N?hCm!;`l#0MoNkNeKI-+0^+6rG4fg7)aZyf}_ z(JY^)5loxVfIF5Vf2-1CKM(3P$uK=1PuY!=;suR%uH-5XB|PHZ7EXkQKAk-w13~)p*1njKZ*t+0zwE{*u_BX z>w~tJ4>Q_qpC-~ib?D6Rt?0<5@zdCKCHU2EH5{>`e z6Z+9d-a7i)?>sVj_6X58w9(n0&uA7^zh(8KT_$6Bz) zdtyN(gUr3BOu)+R4118_KkQ5i@*S(S0KjzsUy1+Qmss$g83-gNA_)OXl{7)XV%i?| zA@b-=5KP#h49dMT6TBBV#~2j`MPM}6pezK|$D#8^KQ~6fz{GB&hV_39CVKirfKh3n zZALwp7OGi3EYzlU0=f=CqKKOyMr;h+<`8lU?3E4AapY?{|ztoq%pbd+Oi>zuw; z%15wUtMT8fMS@5XX2#zEz=bhg`^5)GfAhJ=Hoo`Jy>18n`s57pq=z&#>&tO33S;{; zWgB9MbHu$IkL_03i=(K7lQ$0vOs4 z0!sgcKxmlY*=R;R3w*H3p9@gi*_gwPky1jXCybq-EOY>kvxHHpG>UWDdfHjjX)(>P zE>#FC?PHC04pj<>+Oh#^+dXKsn_^yR+xtY%pSkVo$pQo)0V~V~uryKV4XmRwea!r+ zQv?t}AW=Um2+w-^?8OS-?J0*>Zibt?HIo1?Fh*VDf7h6SQTqHX6onM+e87qgb84^jz03)6omE?HtXK^p~Qw=A*mUY~7sAjS3*`XDlkz7Ie zSO8!l2uzAdRzzyi2LsOmECzKDj0-IU3#E=UoD}Ny*M$PXs1S^tMg-OpN=Im%fi)@y z7gpyFJFlsskl0c>brg+VN|X4j89<#U-Rb}`7X>iSdIWKrycJRuqfvkl3QB38TCj$DE)r^o7Ap1y#Gz5A96$k` zH~`Fn00Ce0g3D=rdySy5vtRUq!K@tr$Qk&cdO+PU#-#zXLFEM_FBmn1x)4-FoIBtM zl_NOAaF$RO1`R0y7^8;XS=LM-Xf-mTAWVklY5>~S&>~>vfZ8hH#Py5lgsl*}eun7% z*Ri*c=g9keK@;W;f9;duSMI;|v7JL|1JURpmz|3DwkvLe%qX8|{N4Ex{pW`tD8Kso z$2R`?=igZDWE#JrCH#E^*1lqG-!MK$NX_l@-p63|$>zA#_96j*oRYPy>z<3iB$t}$ zlj7S~q&@7M&=J&6uc%Zi7Zsu7F|f^&@88WfIDIE@6VIF8cANWd5cgVcpoDIifnI1QFb&!{swjJv)3Q-NAU z1D`0L_-}|sUsW2#*a3j9;oqwjBz8Mv9Fy0dMrl@!`0Kl&_KZR>Gyc|Kdhdq${)ZnZ z|Nb+No_prqZz{HX9F*RI&_Lsr>)rNwQ!Lx20ZRy-ecBt`s(ZmWxDe^IoQqZ5GbatW z5B0Q6U#PzAIDp0Jo^(BfF%>DAEkc^8*2m54isw(ztV6>A(=I# zL(EPJGcZWC35}QbXSI)@;FbFE$>0YCfHbsy+RQ$$;xLyq!?$WgZcKUFFp7@XkCDSG z7w@*;`i=LD|LzNqpZ^c!S8fjVHgde#+>D1@W7+4*5rLQC^_SsXZ?(NRsQ=7Kt!15O zEf;KZ2f;6+GxaszE9nTjE&xc^(*peIP9<9#Bl<%Hfq6>EGcYQEh6NK=kH7MSu`{T> zplm1t0Ao@b_`q@YFr#n=r2~pML9DO_hIB%ibNYPJoZ{3Xh!#BCc>sv~zn~R+nRTtg zn(FBTP&bT*^=Gx$Y@XV82DeAU--MahuY$2)x8}O?Vpuz1x5odiuXBI<=?|X!+Lg3e0f6H?7sq+lhDIkCcy9WnMIQxpgaOmW z+%X*V7X|q9?Mhx9JNjK~@Mz`5&Y}T{=`yOCNQ4yHqC%xg!$6R2(J0I0_=ti@m=H1+Z{fG3IY zn*i=-FT^Sg8_oP71Xfz-ARsUX7&(KoAUJ~=7(^<_MG@FV4Zy{A5J?zD%mg~>ngKwp zOpg3Nv$S5m4+<2GPhzk{ggvMrxk;vXP@Y! z^mQ`)J{G%q2AUue7-R^0=SuqFTQ==epL*Zq>z{e_+{-;f!etKPkPvjyf$rP8XIZ*s znS1m#Cb!F8925bZ^to8)Jy%Wr4T*9W8S_P5atAesJ5B(Yiw2;5gq{TONfBIX0vgZ4 zg%OmFOkqJT_6@RDDV)NnSZoa7yucZa1V)8vhtQi?`I|riX|Q~}tRdLhNMM}_6CaNb zagp|k`B)iNN25(KGDs<_$>?i!v(iCRpJ*cNH~dmZqaU+LZDH|~dpFEKJ#v5XzN>*8 z000ENNkl_CQ06r>$OLaigu%NUsg%v6+0bW`|-$VmFDGZzu z7z1oqDk$5S3Th1IGJl+%2Y{oxHYG1#J^xuW(8OkSJ~pvy!n{~KZM3c+MFl?IXWEEw zf=CdUSWo7h!H+MD>AUw`u;2aoJICMq!s8n+W0)v7w9W6(Q2wxxl2&lgSN*$!)o|^% z<6g{~b)EcL)_K+zb%$MNGQcuP5G#wKPYM9`M*~kqAb1kM!y?$Mym-&Bo-C4gu+gv=k?&7{koGWv0-(A;dRo>TyqHA!2xgH$*VuOrexh@_k%JFF9fTugR5#k- z&czL~M7S|_^n*9uW&ZIK?;8KZAARKf%LC9}u==#OWe;mk-}s>%{3_pQeMP(5aW5p= zg>XvNLTkF`D)w@nG-sc}!@<`{1HeJF&=b&^!w(0>rNEN9T{c8Q1bFr2!Ip@vg&R96 zoFR-$8c{O#B+=+=^ni9w%+b#-6@Gzc5kT_heUR46PX-?Vrk;K6!7LIyx3lDn^o*^+ zkH(H(xNAf&yzO51o!@%jWD0<+!3{$&8>Jar16Mk- z){yIZ{EJ#m&bQQl`Sv?r?_T)m zL!)a~E>G5N_*eBeLmE;MPUm$T(Z;Q|7ycBVi{m_NLlOj*>0G)>P&}4)(CYw#r{l*{ z5dbcys33wtYAu%xZW9f5698P_HsdNBgQr4ATe>VQG_ngfLP3C-yG7}tt!aQj=* zM4+e>P!yI*7O~n*f`~=9_HAx7#b?(V{lene!qT<#B|UflrhWET-ah)#AAERY>x_BB zr^Opvmj-ZWFY>Q|CE5(1QP02YfS4s;|4E&pUeCzkY+T)_VDkVlNFSSr06~%UBs+Bg zQ3Q^;(Bk5ONL0_3C0w-zSDm4&=Sq6+&3Bt;AAfLk^-E8j-#TGKbP{b1mi6$Dd!2Xo z;^=6LVgw+kU@a$c&omx{*GzLQ8&wR6!pOJS^>IW{CFa7baUD(3yd!2MK*PUzi&(W*^0M0u1PXk~7I@h?Y zKuxy-02~Ge>Dmtfckcs$O#qwDz`o|`M1v0i)?kZ>t{cKuX|YvWy8f;=6)*kSZ*Oj` z_yC;cjF(%@Al})FlZgOM<2gBr Date: Mon, 23 Jun 2014 13:28:06 +0200 Subject: [PATCH 29/30] Fixed accidental and embarrassing error. --- data/skins/Peach.stkskin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/skins/Peach.stkskin b/data/skins/Peach.stkskin index eab077f3f..e9594353f 100644 --- a/data/skins/Peach.stkskin +++ b/data/skins/Peach.stkskin @@ -72,7 +72,7 @@ when the border that intersect at this corner are enabled. left_border="128" right_border="13" top_border="13" bottom_border="13" preserve_h_aspect_ratios="true" hborder_out_portion="0.3" vborder_out_portion="0"/> - From 1be98dc5dbdcabcd2ce2a065cba7d6d4689effe1 Mon Sep 17 00:00:00 2001 From: Marianne Gagnon Date: Mon, 23 Jun 2014 20:02:31 -0400 Subject: [PATCH 30/30] Support animated textures in non-static objects too --- src/animations/animation_base.cpp | 2 ++ src/tracks/track_object_presentation.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/animations/animation_base.cpp b/src/animations/animation_base.cpp index cd51bf3c1..784068288 100644 --- a/src/animations/animation_base.cpp +++ b/src/animations/animation_base.cpp @@ -33,6 +33,8 @@ AnimationBase::AnimationBase(const XMLNode &node) node.get("fps", &fps); for(unsigned int i=0; igetName() == "animated-texture") + continue; Ipo *ipo = new Ipo(*node.getNode(i), fps); m_all_ipos.push_back(ipo); } diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 266320998..ca4ddfadd 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -254,7 +254,7 @@ TrackObjectPresentationMesh::TrackObjectPresentationMesh(const XMLNode& xml_node else { m_mesh = irr_driver->getMesh(model_name); - + if (tangent) { scene::IMeshManipulator* manip = irr_driver->getVideoDriver()->getMeshManipulator(); @@ -368,6 +368,9 @@ void TrackObjectPresentationMesh::init(const XMLNode* xml_node, scene::ISceneNod m_node = irr_driver->addMesh(m_mesh, parent); m_frame_start = 0; m_frame_end = 0; + + if (World::getWorld() != NULL && World::getWorld()->getTrack() != NULL) + World::getWorld()->getTrack()->handleAnimatedTextures(m_node, *xml_node); } //#ifdef DEBUG // std::string debug_name = model_name+" (track-object)";