diff --git a/data/gfx/gfx_mudPot_a.xml b/data/gfx/gfx_mudPot_a.xml
new file mode 100644
index 000000000..cc6ead88f
--- /dev/null
+++ b/data/gfx/gfx_mudPot_a.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/shaders/lensblend.frag b/data/shaders/lensblend.frag
new file mode 100644
index 000000000..220d4898f
--- /dev/null
+++ b/data/shaders/lensblend.frag
@@ -0,0 +1,24 @@
+/*
+Lens flare blend
+based on bloomblend.frag
+author: samuncle
+*/
+uniform sampler2D tex_128;
+uniform sampler2D tex_256;
+uniform sampler2D tex_512;
+
+out vec4 FragColor;
+
+void main()
+{
+ vec2 uv = gl_FragCoord.xy / screen;
+ vec4 col = .125 * texture(tex_128, uv);
+ col += .25 * texture(tex_256, uv);
+ col += .5 * texture(tex_512, uv);
+
+ float final = max(col.r,max(col.g,col.b));
+ //final = final * 2;
+ vec3 blue = vec3(final * 0.1, final * 0.2, final);
+
+ FragColor = vec4(blue, 1.);
+}
diff --git a/data/shaders/volumetriclight.frag b/data/shaders/volumetriclight.frag
new file mode 100644
index 000000000..0b4952068
--- /dev/null
+++ b/data/shaders/volumetriclight.frag
@@ -0,0 +1,43 @@
+#ifdef GL_ARB_bindless_texture
+layout(bindless_sampler) uniform sampler2D tex;
+#else
+uniform sampler2D tex;
+#endif
+
+
+uniform float fogmax;
+uniform float startH;
+uniform float endH;
+uniform float start;
+uniform float end;
+uniform vec3 col;
+
+in vec2 uv;
+in vec4 color;
+out vec4 FragColor;
+
+
+void main()
+{
+ vec4 diffusecolor = texture(tex, uv);
+#ifdef GL_ARB_bindless_texture
+ diffusecolor.xyz = pow(diffusecolor.xyz, vec3(2.2));
+#endif
+ diffusecolor.xyz *= pow(color.xyz, vec3(2.2));
+ diffusecolor.a *= color.a;
+ vec3 tmp = vec3(gl_FragCoord.xy / screen, gl_FragCoord.z);
+ tmp = 2. * tmp - 1.;
+
+ vec4 xpos = vec4(tmp, 1.0);
+ xpos = InverseProjectionMatrix * xpos;
+ xpos.xyz /= xpos.w;
+
+ float dist = length(xpos.xyz);
+ float fog = smoothstep(start, end, dist);
+
+ fog = min(fog, fogmax);
+
+ vec4 finalcolor = vec4(col, 0.) * fog + diffusecolor *(1. - fog);
+ FragColor = vec4(finalcolor.rgb * finalcolor.a, finalcolor.a);
+ //FragColor = vec4(1.0, 0.0, 0.0, finalcolor.a);
+}
diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp
index d530002af..9bffa86cc 100644
--- a/src/graphics/irr_driver.hpp
+++ b/src/graphics/irr_driver.hpp
@@ -101,10 +101,15 @@ enum TypeFBO
FBO_BLOOM_1024,
FBO_BLOOM_512,
FBO_TMP_512,
+ FBO_LENS_512,
+
FBO_BLOOM_256,
- FBO_TMP_256,
+ FBO_TMP_256,
+ FBO_LENS_256,
+
FBO_BLOOM_128,
FBO_TMP_128,
+ FBO_LENS_128,
FBO_COUNT
};
@@ -157,10 +162,13 @@ enum TypeRTT
RTT_BLOOM_1024,
RTT_BLOOM_512,
RTT_TMP_512,
+ RTT_LENS_512,
RTT_BLOOM_256,
RTT_TMP_256,
+ RTT_LENS_256,
RTT_BLOOM_128,
RTT_TMP_128,
+ RTT_LENS_128,
RTT_COUNT
};
diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp
index 7c1500674..020c5e3df 100644
--- a/src/graphics/post_processing.cpp
+++ b/src/graphics/post_processing.cpp
@@ -353,6 +353,25 @@ void PostProcessing::renderGaussian6Blur(FrameBuffer &in_fbo, FrameBuffer &auxil
}
}
+void PostProcessing::renderHorizontalBlur(FrameBuffer &in_fbo, FrameBuffer &auxiliary)
+{
+ assert(in_fbo.getWidth() == auxiliary.getWidth() && in_fbo.getHeight() == auxiliary.getHeight());
+ float inv_width = 1.0f / in_fbo.getWidth(), inv_height = 1.0f / in_fbo.getHeight();
+ {
+ auxiliary.Bind();
+
+ FullScreenShader::Gaussian6HBlurShader::getInstance()->SetTextureUnits(in_fbo.getRTT()[0]);
+ DrawFullScreenEffect(core::vector2df(inv_width, inv_height), 2.0);
+ }
+ {
+ in_fbo.Bind();
+
+ FullScreenShader::Gaussian6HBlurShader::getInstance()->SetTextureUnits(auxiliary.getRTT()[0]);
+ DrawFullScreenEffect(core::vector2df(inv_width, inv_height), 2.0);
+ }
+}
+
+
void PostProcessing::renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &auxiliary)
{
assert(in_fbo.getWidth() == auxiliary.getWidth() && in_fbo.getHeight() == auxiliary.getHeight());
@@ -713,13 +732,22 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo
// Downsample
FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_512), irr_driver->getFBO(FBO_BLOOM_256), GL_COLOR_BUFFER_BIT, GL_LINEAR);
FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_256), irr_driver->getFBO(FBO_BLOOM_128), GL_COLOR_BUFFER_BIT, GL_LINEAR);
+
+ // Copy for lens flare
+ FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_512), irr_driver->getFBO(FBO_LENS_512), GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_256), irr_driver->getFBO(FBO_LENS_256), GL_COLOR_BUFFER_BIT, GL_LINEAR);
+ FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_128), irr_driver->getFBO(FBO_LENS_128), GL_COLOR_BUFFER_BIT, GL_LINEAR);
+
// Blur
+
renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_512), irr_driver->getFBO(FBO_TMP_512), 1., 1.);
-
renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_256), irr_driver->getFBO(FBO_TMP_256), 1., 1.);
-
renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_128), irr_driver->getFBO(FBO_TMP_128), 1., 1.);
+
+ renderHorizontalBlur(irr_driver->getFBO(FBO_LENS_512), irr_driver->getFBO(FBO_TMP_512));
+ renderHorizontalBlur(irr_driver->getFBO(FBO_LENS_256), irr_driver->getFBO(FBO_TMP_256));
+ renderHorizontalBlur(irr_driver->getFBO(FBO_LENS_128), irr_driver->getFBO(FBO_TMP_128));
// Additively blend on top of tmp1
in_fbo->Bind();
@@ -730,6 +758,11 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo
irr_driver->getRenderTargetTexture(RTT_BLOOM_128), irr_driver->getRenderTargetTexture(RTT_BLOOM_256), irr_driver->getRenderTargetTexture(RTT_BLOOM_512));
DrawFullScreenEffect();
+
+ FullScreenShader::LensBlendShader::getInstance()->SetTextureUnits(
+ irr_driver->getRenderTargetTexture(RTT_LENS_128), irr_driver->getRenderTargetTexture(RTT_LENS_256), irr_driver->getRenderTargetTexture(RTT_LENS_512));
+ DrawFullScreenEffect();
+
glDisable(GL_BLEND);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
} // end if bloom
diff --git a/src/graphics/post_processing.hpp b/src/graphics/post_processing.hpp
index 920c0f6b7..430623036 100644
--- a/src/graphics/post_processing.hpp
+++ b/src/graphics/post_processing.hpp
@@ -87,7 +87,10 @@ public:
/** Blur the in texture */
void renderGaussian3Blur(FrameBuffer &in_fbo, FrameBuffer &auxiliary);
+
void renderGaussian6Blur(FrameBuffer &in_fbo, FrameBuffer &auxiliary, float sigmaV, float sigmaH);
+ void renderHorizontalBlur(FrameBuffer &in_fbo, FrameBuffer &auxiliary);
+
void renderGaussian6BlurLayer(FrameBuffer &in_fbo);
void renderGaussian17TapBlur(FrameBuffer &in_fbo, FrameBuffer &auxiliary);
diff --git a/src/graphics/rtts.cpp b/src/graphics/rtts.cpp
index 4b6024975..5dad9df4f 100644
--- a/src/graphics/rtts.cpp
+++ b/src/graphics/rtts.cpp
@@ -125,10 +125,15 @@ RTT::RTT(size_t width, size_t height)
RenderTargetTextures[RTT_BLOOM_1024] = generateRTT(shadowsize0, GL_RGBA16F, GL_BGR, GL_FLOAT);
RenderTargetTextures[RTT_BLOOM_512] = generateRTT(shadowsize1, GL_RGBA16F, GL_BGR, GL_FLOAT);
RenderTargetTextures[RTT_TMP_512] = generateRTT(shadowsize1, GL_RGBA16F, GL_BGR, GL_FLOAT);
+ RenderTargetTextures[RTT_LENS_512] = generateRTT(shadowsize1, GL_RGBA16F, GL_BGR, GL_FLOAT);
+
RenderTargetTextures[RTT_BLOOM_256] = generateRTT(shadowsize2, GL_RGBA16F, GL_BGR, GL_FLOAT);
RenderTargetTextures[RTT_TMP_256] = generateRTT(shadowsize2, GL_RGBA16F, GL_BGR, GL_FLOAT);
+ RenderTargetTextures[RTT_LENS_256] = generateRTT(shadowsize2, GL_RGBA16F, GL_BGR, GL_FLOAT);
+
RenderTargetTextures[RTT_BLOOM_128] = generateRTT(shadowsize3, GL_RGBA16F, GL_BGR, GL_FLOAT);
RenderTargetTextures[RTT_TMP_128] = generateRTT(shadowsize3, GL_RGBA16F, GL_BGR, GL_FLOAT);
+ RenderTargetTextures[RTT_LENS_128] = generateRTT(shadowsize3, GL_RGBA16F, GL_BGR, GL_FLOAT);
std::vector somevector;
somevector.push_back(RenderTargetTextures[RTT_SSAO]);
@@ -208,17 +213,30 @@ RTT::RTT(size_t width, size_t height)
somevector.clear();
somevector.push_back(RenderTargetTextures[RTT_TMP_512]);
FrameBuffers.push_back(new FrameBuffer(somevector, 512, 512));
+ somevector.clear();
+ somevector.push_back(RenderTargetTextures[RTT_LENS_512]);
+ FrameBuffers.push_back(new FrameBuffer(somevector, 512, 512));
+
+
somevector.clear();
somevector.push_back(RenderTargetTextures[RTT_BLOOM_256]);
FrameBuffers.push_back(new FrameBuffer(somevector, 256, 256));
somevector.clear();
somevector.push_back(RenderTargetTextures[RTT_TMP_256]);
FrameBuffers.push_back(new FrameBuffer(somevector, 256, 256));
+ somevector.clear();
+ somevector.push_back(RenderTargetTextures[RTT_LENS_256]);
+ FrameBuffers.push_back(new FrameBuffer(somevector, 256, 256));
+
+
somevector.clear();
somevector.push_back(RenderTargetTextures[RTT_BLOOM_128]);
FrameBuffers.push_back(new FrameBuffer(somevector, 128, 128));
somevector.clear();
somevector.push_back(RenderTargetTextures[RTT_TMP_128]);
+ FrameBuffers.push_back(new FrameBuffer(somevector, 128, 128));
+ somevector.clear();
+ somevector.push_back(RenderTargetTextures[RTT_LENS_128]);
FrameBuffers.push_back(new FrameBuffer(somevector, 128, 128));
if (UserConfigParams::m_shadows && !irr_driver->needUBOWorkaround())
diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp
index 9a575159f..9b3f4d5af 100644
--- a/src/graphics/shaders.cpp
+++ b/src/graphics/shaders.cpp
@@ -1596,6 +1596,16 @@ namespace FullScreenShader
AssignSamplerNames(Program, 0, "tex_128", 1, "tex_256", 2, "tex_512");
}
+
+ LensBlendShader::LensBlendShader()
+ {
+ Program = LoadProgram(OBJECT,
+ GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(),
+ GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/lensblend.frag").c_str());
+ AssignUniforms();
+
+ AssignSamplerNames(Program, 0, "tex_128", 1, "tex_256", 2, "tex_512");
+ }
ToneMapShader::ToneMapShader()
{
@@ -1741,6 +1751,16 @@ namespace FullScreenShader
AssignSamplerNames(Program, 0, "tex");
}
+
+ HorizontalBlurShader::HorizontalBlurShader()
+ {
+ Program = LoadProgram(OBJECT,
+ GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(),
+ GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/gaussian6h.frag").c_str());
+ AssignUniforms("pixel");
+
+ AssignSamplerNames(Program, 0, "tex");
+ }
Gaussian3HBlurShader::Gaussian3HBlurShader()
{
diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp
index de0eb71bf..3088e6b2c 100644
--- a/src/graphics/shaders.hpp
+++ b/src/graphics/shaders.hpp
@@ -385,6 +385,13 @@ public:
BloomBlendShader();
};
+class LensBlendShader : public ShaderHelperSingleton, public TextureRead
+{
+public:
+ LensBlendShader();
+};
+
+
class ToneMapShader : public ShaderHelperSingleton, public TextureRead
{
public:
@@ -463,6 +470,12 @@ public:
Gaussian6HBlurShader();
};
+class HorizontalBlurShader : public ShaderHelperSingleton, public TextureRead
+{
+public:
+ HorizontalBlurShader();
+};
+
class Gaussian3HBlurShader : public ShaderHelperSingleton, public TextureRead
{
public:
diff --git a/supertuxkart.project b/supertuxkart.project
new file mode 100644
index 000000000..829e4235f
--- /dev/null
+++ b/supertuxkart.project
@@ -0,0 +1,2164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ make clean
+ make
+
+
+
+ None
+ $(WorkspacePath)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ make clean
+ make
+
+
+
+ None
+ $(WorkspacePath)
+
+
+
+
+
+
+
+
+
+
+
+
+
+