Browse Source

Lens flare work

Panagiotis Christopoulos Charitos 11 years ago
parent
commit
34137bff12

+ 1 - 0
include/anki/Gl.h

@@ -32,6 +32,7 @@
 #include "anki/gl/GlPipelineHandle.h"
 
 #include "anki/gl/GlCommandBufferHandle.h"
+#include "anki/gl/GlOcclusionQueryHandle.h"
 #include "anki/gl/GlDevice.h"
 
 #endif

+ 1 - 1
include/anki/gl/GlOcclusionQueryHandle.h

@@ -27,7 +27,7 @@ public:
 	~GlOcclusionQueryHandle();
 
 	/// Create a query.
-	ANKI_USE_RESULT Error create(GlCommandBufferHandle& commands);
+	ANKI_USE_RESULT Error create(GlDevice* dev);
 
 	/// Begin query.
 	void begin(GlCommandBufferHandle& commands);

+ 46 - 0
include/anki/renderer/Dp.h

@@ -0,0 +1,46 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#ifndef ANKI_RENDERER_DP_H
+#define ANKI_RENDERER_DP_H
+
+#include "anki/renderer/RenderingPass.h"
+#include "anki/Gl.h"
+
+namespace anki {
+
+/// @addtogroup renderer
+/// @{
+
+/// Depth buffer processing.
+class Dp: public RenderingPass
+{
+public:
+	/// @privatesection
+	/// @{
+	Dp(Renderer* r)
+	:	RenderingPass(r)
+	{}
+
+	GlTextureHandle& getSmallDepthRt()
+	{
+		return m_smallDepthRt;
+	}
+
+	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
+	ANKI_USE_RESULT Error run(GlCommandBufferHandle& cmdBuff);
+	/// @}
+
+private:
+	GlTextureHandle m_smallDepthRt; ///< A smaller depth buffer
+	GlFramebufferHandle m_smallDepthFb; ///< Used to blit
+	UVec2 m_smallDepthSize;
+};
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 0 - 2
include/anki/renderer/Ez.h

@@ -29,10 +29,8 @@ private:
 	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
 	ANKI_USE_RESULT Error run(GlCommandBufferHandle& cmdBuff);
 };
-
 /// @}
 
 } // end namespace anki
 
-
 #endif

+ 6 - 2
include/anki/renderer/Lf.h

@@ -33,6 +33,8 @@ public:
 	{
 		return m_rt;
 	}
+
+	Error runOcclusionTests(GlCommandBufferHandle& cmdb);
 	/// @}
 
 private:
@@ -53,10 +55,12 @@ private:
 	GlFramebufferHandle m_fb;
 
 	TextureResourcePointer m_lensDirtTex;
-	U8 m_maxFlaresPerLight;
-	U8 m_maxLightsWithFlares;
+	U8 m_maxSpritesPerFlare;
+	U8 m_maxFlares;
 	GlBufferHandle m_flareDataBuff;
 
+	U32 m_flareSize;
+
 	Lf(Renderer* r)
 	:	RenderingPass(r)
 	{}

+ 2 - 6
include/anki/renderer/Ms.h

@@ -38,9 +38,9 @@ public:
 		return m_planes[1].m_depthRt;
 	}
 
-	GlTextureHandle& _getSmallDepthRt()
+	GlFramebufferHandle& getFramebuffer()
 	{
-		return m_smallDepthRt;
+		return m_planes[1].m_fb;
 	}
 	/// @}
 
@@ -61,10 +61,6 @@ private:
 		GlTextureHandle m_depthRt;
 	};
 
-	GlTextureHandle m_smallDepthRt; ///< A smaller depth buffer
-	GlFramebufferHandle m_smallDepthFb; ///< Used to blit
-	UVec2 m_smallDepthSize;
-
 	Ez m_ez; /// EarlyZ pass
 
 	/// One for multisampled and one for not. 0: multisampled, 1: not

+ 11 - 0
include/anki/renderer/Renderer.h

@@ -15,6 +15,7 @@
 #include "anki/scene/Forward.h"
 
 #include "anki/renderer/Ms.h"
+#include "anki/renderer/Dp.h"
 #include "anki/renderer/Is.h"
 #include "anki/renderer/Pps.h"
 #include "anki/renderer/Bs.h"
@@ -52,6 +53,15 @@ public:
 		return m_ms;
 	}
 
+	const Dp& getDp() const
+	{
+		return m_dp;
+	}
+	Dp& getDp()
+	{
+		return m_dp;
+	}
+
 	const Is& getIs() const
 	{
 		return m_is;
@@ -264,6 +274,7 @@ private:
 	/// @name Rendering stages
 	/// @{
 	Ms m_ms; ///< Material rendering stage
+	Dp m_dp; ///< Depth processing stage.
 	Is m_is; ///< Illumination rendering stage
 	Pps m_pps; ///< Postprocessing rendering stage
 	Bs m_bs; ///< Blending stage

+ 122 - 0
include/anki/scene/LensFlareComponent.h

@@ -0,0 +1,122 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#ifndef ANKI_SCENE_LENS_FLARE_NODE_H
+#define ANKI_SCENE_LENS_FLARE_NODE_H
+
+#include "anki/scene/SceneNode.h"
+#include "anki/Gl.h"
+#include "anki/resource/ResourceManager.h"
+#include "anki/resource/TextureResource.h"
+
+namespace anki {
+
+/// @addtogroup scene
+/// @{
+
+/// Lens flare scene component.
+class LensFlareComponent final: public SceneComponent
+{
+public:
+	LensFlareComponent(SceneNode* node)
+	:	SceneComponent(Type::LENS_FLARE, node),
+		m_node(node)
+	{}
+
+	ANKI_USE_RESULT Error create(const CString& textureFilename);
+
+	void setWorldPosition(const Vec4& worldPosition)
+	{
+		m_worldPosition = worldPosition;
+	}
+
+	const Vec4& getWorldPosition() const
+	{
+		return m_worldPosition;
+	}
+
+	void setFirstFlareSize(const Vec2& size)
+	{
+		m_firstFlareSize = size;
+	}
+
+	const Vec2& getFirstFlareSize() const
+	{
+		return m_firstFlareSize;
+	}
+
+	void setOtherFlareSize(const Vec2& size)
+	{
+		m_otherFlareSize = size;
+	}
+
+	const Vec2& getOtherFlareSize() const
+	{
+		return m_otherFlareSize;
+	}
+
+	void setColorMultiplier(const Vec4& color)
+	{
+		m_colorMul = color;
+	}
+
+	const Vec4& getColorMultiplier() const
+	{
+		return m_colorMul;
+	}
+
+	GlTextureHandle getTexture() const
+	{
+		return m_tex->getGlTexture();
+	}
+
+	GlOcclusionQueryHandle& getOcclusionQueryToTest()
+	{
+		return m_queries[m_crntQueryIndex];
+	}
+
+	GlOcclusionQueryHandle& getOcclusionQueryToCheck()
+	{
+		return m_queries[(m_crntQueryIndex + 1) % m_queries.getSize()];
+	}
+
+	/// @name SceneComponent virtuals
+	/// @{
+	Error update(
+		SceneNode& node, F32 prevTime, F32 crntTime, Bool& updated)
+	{
+		// Move the query counter
+		m_crntQueryIndex = getGlobTimestamp() % m_queries.getSize();
+		updated = false;
+		return ErrorCode::NONE;
+	}
+	/// @}
+
+	static constexpr Type getClassType()
+	{
+		return Type::LENS_FLARE;
+	}
+
+private:
+	TextureResourcePointer m_tex; ///< Array of textures.
+	U8 m_flareCount = 0; ///< Cache the flare count.
+
+	Vec4 m_colorMul = Vec4(1.0); ///< Color multiplier.
+	
+	Vec2 m_firstFlareSize = Vec2(1.0);
+	Vec2 m_otherFlareSize = Vec2(1.0);
+
+	Array<GlOcclusionQueryHandle, 3> m_queries;
+	U8 m_crntQueryIndex = 0;
+	
+	Vec4 m_worldPosition = Vec4(0.0);
+	SceneNode* m_node;
+};
+/// @}
+
+} // end namespace anki
+
+#endif
+

+ 0 - 79
include/anki/scene/Light.h

@@ -31,30 +31,6 @@ public:
 	}
 };
 
-/// XXX
-class FlareBatch
-{
-public:
-	static constexpr U MAX_FLARES = 10;
-
-	enum FlareFlag
-	{
-		POSITION_LIGHT = 1 << 0,
-		POSITION_FLOATING = 1 << 1
-	};
-
-private:
-	/// A 2D array texture with the flare textures
-	TextureResourcePointer flaresTex;
-
-	/// The size of each flare
-	Array<Vec2, MAX_FLARES> size;
-
-	Array<Vec2, MAX_FLARES> stretchMultiplier;
-
-	F32 flaresAlpha = 1.0;
-};
-
 /// Light scene node. It can be spot or point
 ///
 /// Explaining the lighting model:
@@ -144,53 +120,6 @@ public:
 		m_shadowMapIndex = static_cast<U8>(i);
 	}
 
-	Bool hasLensFlare() const
-	{
-		return m_flaresTex.isLoaded();
-	}
-
-	const GlTextureHandle& getLensFlareTexture() const
-	{
-		ANKI_ASSERT(hasLensFlare());
-		return m_flaresTex->getGlTexture();
-	}
-
-	U32 getLensFlareTextureDepth() const
-	{
-		ANKI_ASSERT(hasLensFlare());
-		return m_flaresTex->getDepth();
-	}
-
-	const Vec2& getLensFlaresSize() const
-	{
-		return m_flaresSize;
-	}
-
-	void setLensFlaresSize(const Vec2& val)
-	{
-		m_flaresSize = val;
-	}
-
-	const Vec2& getLensFlaresStretchMultiplier() const
-	{
-		return m_flaresStretchMultiplier;
-	}
-
-	void setLensFlaresStretchMultiplier(const Vec2& val)
-	{
-		m_flaresStretchMultiplier = val;
-	}
-
-	F32 getLensFlaresAlpha() const
-	{
-		return m_flaresAlpha;
-	}
-
-	void setLensFlaresAlpha(F32 val)
-	{
-		m_flaresAlpha = val;
-	}
-
 	ANKI_USE_RESULT Error loadLensFlare(const CString& filename);
 
 	/// @name SpatialComponent virtuals
@@ -213,14 +142,6 @@ private:
 	Vec4 m_color = Vec4(1.0);
 	Vec4 m_specColor = Vec4(1.0);
 
-	/// @name Flare struff
-	/// @{
-	TextureResourcePointer m_flaresTex;
-	Vec2 m_flaresSize = Vec2(0.2);
-	Vec2 m_flaresStretchMultiplier = Vec2(1.0);
-	F32 m_flaresAlpha = 1.0;
-	/// @}
-
 	Bool8 m_shadow = false;
 	U8 m_shadowMapIndex = 0xFF; ///< Used by the renderer
 };

+ 1 - 0
include/anki/scene/SceneComponent.h

@@ -26,6 +26,7 @@ public:
 		SPATIAL,
 		LIGHT,
 		INSTANCE,
+		LENS_FLARE,
 		BODY,
 		LAST_COMPONENT_ID = BODY
 	};

+ 30 - 18
include/anki/scene/Visibility.h

@@ -39,7 +39,7 @@ enum VisibleBy
 
 /// Visible node pointer with some more info
 /// @note Keep this structore as small as possible
-class VisibleNode: public NonCopyable
+class VisibleNode
 {
 public:
 	SceneNode* m_node = nullptr;
@@ -50,21 +50,16 @@ public:
 	VisibleNode()
 	{}
 
-	VisibleNode(VisibleNode&& other)
+	VisibleNode(const VisibleNode& other)
 	{
-		*this = std::move(other);
+		*this = other;
 	}
 
-	VisibleNode& operator=(VisibleNode&& other)
+	VisibleNode& operator=(const VisibleNode& other)
 	{
 		m_node = other.m_node;
 		m_spatialIndices = other.m_spatialIndices;
 		m_spatialsCount = other.m_spatialsCount;
-
-		other.m_node = nullptr;
-		other.m_spatialIndices = nullptr;
-		other.m_spatialsCount = 0;
-
 		return *this;
 	}
 
@@ -89,21 +84,15 @@ public:
 	ANKI_USE_RESULT Error create(
 		SceneFrameAllocator<U8> alloc,
 		U32 renderablesReservedSize,
-		U32 lightsReservedSize)
-	{
-		Error err = m_renderables.create(alloc, renderablesReservedSize);
-		if(!err)
-		{
-			err = m_lights.create(alloc, lightsReservedSize);
-		}
-		return err;
-	}
+		U32 lightsReservedSize,
+		U32 lensFlaresReservedSize);
 
 	void prepareMerge()
 	{
 		ANKI_ASSERT(m_renderablesCount == 0 && m_lightsCount == 0);
 		m_renderablesCount = m_renderables.getSize();
 		m_lightsCount = m_lights.getSize();
+		m_flaresCount = m_flares.getSize();
 	}
 
 	VisibleNode* getRenderablesBegin()
@@ -127,6 +116,16 @@ public:
 		return (m_lightsCount) ? (&m_lights[0] + m_lightsCount) : nullptr;
 	}
 
+	VisibleNode* getLensFlaresBegin()
+	{
+		return (m_flaresCount) ? &m_flares[0] : nullptr;
+	}
+
+	VisibleNode* getLensFlaresEnd()
+	{
+		return (m_flaresCount) ? (&m_flares[0] + m_flaresCount) : nullptr;
+	}
+
 	U32 getRenderablesCount() const
 	{
 		return m_renderablesCount;
@@ -137,6 +136,11 @@ public:
 		return m_lightsCount;
 	}
 
+	U32 getLensFlaresCount() const
+	{
+		return m_flaresCount;
+	}
+
 	ANKI_USE_RESULT Error moveBackRenderable(
 		SceneFrameAllocator<U8> alloc, VisibleNode& x)
 	{
@@ -149,11 +153,19 @@ public:
 		return moveBack(alloc, m_lights, m_lightsCount, x);
 	}
 
+	ANKI_USE_RESULT Error moveBackLensFlare(
+		SceneFrameAllocator<U8> alloc, VisibleNode& x)
+	{
+		return moveBack(alloc, m_flares, m_flaresCount, x);
+	}
+
 private:
 	Container m_renderables;
 	Container m_lights;
+	Container m_flares;
 	U32 m_renderablesCount = 0;
 	U32 m_lightsCount = 0;
+	U32 m_flaresCount = 0;
 
 	ANKI_USE_RESULT Error moveBack(SceneFrameAllocator<U8> alloc, 
 		Container& c, U32& count, VisibleNode& x);

+ 48 - 8
include/anki/util/Array.h

@@ -45,52 +45,92 @@ public:
 		return m_data[n];
 	}
 
+	Iterator getBegin()
+	{
+		return &m_data[0];
+	}
+
+	ConstIterator getBegin() const
+	{
+		return &m_data[0];
+	}
+
+	Iterator getEnd()
+	{
+		return &m_data[0] + N;
+	}
+
+	ConstIterator getEnd() const
+	{
+		return &m_data[0] + N;
+	}
+
+	Reference getFront() 
+	{
+		return m_data[0];
+	}
+
+	ConstReference getFront() const
+	{
+		return m_data[0];
+	}
+
+	Reference getBack() 
+	{
+		return m_data[N - 1];
+	}
+
+	ConstReference getBack() const
+	{
+		return m_data[N - 1];
+	}
+
 	/// Make it compatible with the C++11 range based for loop
 	Iterator begin()
 	{
-		return &m_data[0];
+		return getBegin();
 	}
 
 	/// Make it compatible with the C++11 range based for loop
 	ConstIterator begin() const
 	{
-		return &m_data[0];
+		return getBegin();
 	}
 
 	/// Make it compatible with the C++11 range based for loop
 	Iterator end()
 	{
-		return &m_data[0] + N;
+		return getEnd();
 	}
 
 	/// Make it compatible with the C++11 range based for loop
 	ConstIterator end() const
 	{
-		return &m_data[0] + N;
+		return getEnd();
 	}
 
 	/// Make it compatible with STL
 	Reference front() 
 	{
-		return m_data[0];
+		return getFront();
 	}
 
 	/// Make it compatible with STL
 	ConstReference front() const
 	{
-		return m_data[0];
+		return getFront();
 	}
 
 	/// Make it compatible with STL
 	Reference back() 
 	{
-		return m_data[N - 1];
+		return getBack;
 	}
 
 	/// Make it compatible with STL
 	ConstReference back() const
 	{
-		return m_data[N - 1];
+		return getBack();
 	}
 
 	static constexpr PtrSize getSize()

+ 1 - 1
shaders/Final.frag.glsl

@@ -19,6 +19,6 @@ layout(location = 0) out vec3 outFragColor;
 void main()
 {
 	vec3 col = textureRt(uRasterImage, inTexCoords).rgb;
-	//vec3 col = vec3((2.0 * 0.5) / (500.0 + 0.5 - textureRt(uRasterImage, inTexCoords).r * (500.0 - 0.5)));
+	//vec3 col = vec3(textureRt(uRasterImage, inTexCoords).r);
 	outFragColor = col;
 }

+ 1 - 7
shaders/IsCommon.glsl

@@ -32,12 +32,6 @@ struct SpotLight
 	vec4 lightDir;
 	vec4 outerCosInnerCos;
 	vec4 extendPoints[4]; // The positions of the 4 camera points
-};
-
-// Spot light with texture
-struct SpotTexLight
-{
-	SpotLight spotLightBase;
 	mat4 texProjectionMat;
 };
 
@@ -47,7 +41,7 @@ struct Lights
 	uvec4 count; // x: points, z: 
 	PointLight pointLights[MAX_POINT_LIGHTS];
 	SpotLight spotLights[MAX_SPOT_LIGHTS];
-	SpotTexLight spotTexLights[MAX_SPOT_TEX_LIGHTS];
+	SpotLight spotTexLights[MAX_SPOT_TEX_LIGHTS];
 };
 
 // Common uniforms between lights

+ 93 - 111
shaders/IsLp.frag.glsl

@@ -13,7 +13,7 @@
 
 #define ATTENUATION_BOOST (0.05)
 
-#define LAMBERT_MIN (0.1)
+#define SUBSURFACE_COLOR (0.1)
 
 layout(std140, binding = 1) readonly buffer pointLightsBlock
 {
@@ -27,7 +27,7 @@ layout(std140, binding = 2) readonly buffer spotLightsBlock
 
 layout(std140, binding = 3) readonly buffer spotTexLightsBlock
 {
-	SpotTexLight uSpotTexLights[MAX_SPOT_TEX_LIGHTS];
+	SpotLight uSpotTexLights[MAX_SPOT_TEX_LIGHTS];
 };
 
 layout(std430, binding = 4) readonly buffer tilesBlock
@@ -53,73 +53,75 @@ vec3 getFragPosVSpace()
 {
 	float depth = textureRt(uMsDepthRt, inTexCoord).r;
 
-	vec3 fragPosVspace;
-	fragPosVspace.z = uProjectionParams.z / (uProjectionParams.w + depth);
-	fragPosVspace.xy = inProjectionParams * fragPosVspace.z;
+	vec3 fragPos;
+	fragPos.z = uProjectionParams.z / (uProjectionParams.w + depth);
+	fragPos.xy = inProjectionParams * fragPos.z;
 
-	return fragPosVspace;
+	return fragPos;
 }
 
 //==============================================================================
 float computeAttenuationFactor(
-	in vec3 fragPosVspace, 
-	in Light light,
-	out vec3 frag2LightVec)
+	in float lightRadius,
+	in vec3 frag2Light)
 {
-	// get the vector from the frag to the light
-	frag2LightVec = light.posRadius.xyz - fragPosVspace;
+	float fragLightDist = length(frag2Light);
 
-	float fragLightDist = length(frag2LightVec);
-	frag2LightVec = normalize(frag2LightVec);
-
-	float att = max(  
-		(fragLightDist * light.posRadius.w) + (1.0 + ATTENUATION_BOOST), 
-		0.0);
+	float att = (fragLightDist * lightRadius) + (1.0 + ATTENUATION_BOOST);
+	att = max(0.0, att);
 
 	return att;
 }
 
 //==============================================================================
-float computeLambertTerm(in vec3 normal, in vec3 frag2LightVec)
+float computeLambertTerm(in vec3 normal, in vec3 frag2LightDir)
 {
-	return max(LAMBERT_MIN, dot(normal, frag2LightVec));
+	return max(SUBSURFACE_COLOR, dot(normal, frag2LightDir));
 }
 
 //==============================================================================
 // Performs phong lighting using the MS FAIs and a few other things
-vec3 computePhong(in vec3 fragPosVspace, in vec3 diffuse, 
-	in float specColor, in float specPower, in vec3 normal, in Light light, 
-	in vec3 rayDir)
+vec3 computeSpecularColor(
+	in vec3 viewDir,
+	in vec3 frag2LightDir,
+	in vec3 normal,
+	in float specCol, 
+	in float specPower, 
+	in vec3 lightSpecCol)
 {
-	// Specular
-	vec3 eyeVec = normalize(fragPosVspace);
-	vec3 h = normalize(rayDir - eyeVec);
+	vec3 h = normalize(frag2LightDir + viewDir);
 	float specIntensity = pow(max(0.0, dot(normal, h)), specPower);
-	vec3 specCol = 
-		light.specularColorTexId.rgb * (specIntensity * specColor);
+	vec3 outSpecCol = lightSpecCol * (specIntensity * specCol);
 	
-	// Do a mad optimization
-	// diffCol = diffuse * light.diffuseColorShadowmapId.rgb
-	return (diffuse * light.diffuseColorShadowmapId.rgb) + specCol;
+	return outSpecCol;
 }
 
 //==============================================================================
-float computeSpotFactor(in SpotLight light, in vec3 frag2LightVec)
+vec3 computeDiffuseColor(in vec3 diffCol, in vec3 lightDiffCol)
 {
-	float costheta = -dot(frag2LightVec, light.lightDir.xyz);
-	float spotFactor = smoothstep(
-		light.outerCosInnerCos.x, 
-		light.outerCosInnerCos.y, 
-		costheta);
+	return diffCol * lightDiffCol;
+}
 
+//==============================================================================
+float computeSpotFactor(
+	in vec3 frag2LightDir,
+	in float outerCos,
+	in float innerCos,
+	in vec3 spotDir)
+{
+	float costheta = -dot(frag2LightDir, spotDir);
+	float spotFactor = smoothstep(outerCos, innerCos, costheta);
 	return spotFactor;
 }
 
 //==============================================================================
-float computeShadowFactor(in SpotTexLight light, in vec3 fragPosVspace, 
-	in highp sampler2DArrayShadow shadowMapArr, in float layer)
+float computeShadowFactor(
+	in mat4 lightProjectionMat, 
+	in vec3 fragPos, 
+	in highp sampler2DArrayShadow shadowMapArr, 
+	in float layer)
 {
-	vec4 texCoords4 = light.texProjectionMat * vec4(fragPosVspace, 1.0);
+	vec4 texCoords4 = lightProjectionMat * vec4(fragPos, 1.0);
 	vec3 texCoords3 = texCoords4.xyz / texCoords4.w;
 
 #if POISSON == 1
@@ -154,21 +156,22 @@ float computeShadowFactor(in SpotTexLight light, in vec3 fragPosVspace,
 void main()
 {
 	// get frag pos in view space
-	vec3 fragPosVspace = getFragPosVSpace();
+	vec3 fragPos = getFragPosVSpace();
+	vec3 viewDir = normalize(-fragPos);
 
 	// Decode GBuffer
 	vec3 normal;
-	vec3 diffColor;
-	float specColor;
+	vec3 diffCol;
+	float specCol;
 	float specPower;
 
-	readGBuffer(uMsRt0, uMsRt1,
-		inTexCoord, diffColor, normal, specColor, specPower);
+	readGBuffer(
+		uMsRt0, uMsRt1, inTexCoord, diffCol, normal, specCol, specPower);
 
 	specPower *= 128.0;
 
 	// Ambient color
-	outColor = diffColor * uSceneAmbientColor.rgb;
+	outColor = diffCol * uSceneAmbientColor.rgb;
 
 	//Tile tile = uTiles[inInstanceId];
 	#define tile uTiles[inInstanceId]
@@ -180,70 +183,79 @@ void main()
 		uint lightId = tile.pointLightIndices[i];
 		PointLight light = uPointLights[lightId];
 
-		vec3 ray;
-		float att = computeAttenuationFactor(fragPosVspace, light, ray);
+		vec3 frag2Light = light.posRadius.xyz - fragPos;
+		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
-		float lambert = computeLambertTerm(normal, ray);
+		vec3 frag2LightDir = normalize(frag2Light);
+		float lambert = computeLambertTerm(normal, frag2LightDir);
 
-		outColor += computePhong(fragPosVspace, diffColor, 
-			specColor, specPower, normal, light, ray) * (att * lambert);
+		vec3 specC = computeSpecularColor(viewDir, frag2LightDir, normal,
+			specCol, specPower, light.specularColorTexId.rgb);
+
+		vec3 diffC = computeDiffuseColor(
+			diffCol, light.diffuseColorShadowmapId.rgb);
+
+		outColor += (specC + diffC) * (att * lambert);
 	}
 
 	// Spot lights
 	uint spotLightsCount = tile.lightsCount[2];
-
 	for(uint i = 0U; i < spotLightsCount; ++i)
 	{
 		uint lightId = tile.spotLightIndices[i];
-		SpotLight light = uSpotLights[lightId];
+		SpotLight slight = uSpotLights[lightId];
+		Light light = slight.lightBase;
+
+		vec3 frag2Light = light.posRadius.xyz - fragPos;
+		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
-		vec3 ray;
-		float att = computeAttenuationFactor(fragPosVspace, 
-			light.lightBase, ray);
+		vec3 frag2LightDir = normalize(frag2Light);
+		float lambert = computeLambertTerm(normal, frag2LightDir);
 
-		float lambert = computeLambertTerm(normal, ray);
+		vec3 specC = computeSpecularColor(viewDir, frag2LightDir, normal,
+			specCol, specPower, light.specularColorTexId.rgb);
 
-		float spot = computeSpotFactor(light, ray);
+		vec3 diffC = computeDiffuseColor(
+			diffCol, light.diffuseColorShadowmapId.rgb);
 
-		vec3 col = computePhong(fragPosVspace, diffColor, 
-			specColor, specPower, normal, light.lightBase, ray);
+		float spot = computeSpotFactor(
+			frag2LightDir, slight.outerCosInnerCos.x, 
+			slight.outerCosInnerCos.y, 
+			slight.lightDir.xyz);
 
-		outColor += col * (att * lambert * spot);
+		outColor += (diffC + specC) * (att * lambert * spot);
 	}
 
 	// Spot lights with shadow
 	uint spotTexLightsCount = tile.lightsCount[3];
-
 	for(uint i = 0U; i < spotTexLightsCount; ++i)
 	{
 		uint lightId = tile.spotTexLightIndices[i];
-		SpotTexLight light = uSpotTexLights[lightId];
-
-		vec3 ray;
-		float att = computeAttenuationFactor(fragPosVspace, 
-			light.spotLightBase.lightBase, ray);
+		SpotLight slight = uSpotTexLights[lightId];
+		Light light = slight.lightBase;
 
-		float lambert = computeLambertTerm(normal, ray);
+		vec3 frag2Light = light.posRadius.xyz - fragPos;
+		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
-		float spot = 
-			computeSpotFactor(light.spotLightBase, ray);
+		vec3 frag2LightDir = normalize(frag2Light);
+		float lambert = computeLambertTerm(normal, frag2LightDir);
 
-		float midFactor = att * lambert * spot;
+		vec3 specC = computeSpecularColor(viewDir, frag2LightDir, normal,
+			specCol, specPower, light.specularColorTexId.rgb);
 
-		//if(midFactor > 0.0)
-		{
-			float shadowmapLayerId = 
-				light.spotLightBase.lightBase.diffuseColorShadowmapId.w;
+		vec3 diffC = computeDiffuseColor(
+			diffCol, light.diffuseColorShadowmapId.rgb);
 
-			float shadow = computeShadowFactor(light, 
-				fragPosVspace, uShadowMapArr, shadowmapLayerId);
+		float spot = computeSpotFactor(
+			frag2LightDir, slight.outerCosInnerCos.x, 
+			slight.outerCosInnerCos.y, 
+			slight.lightDir.xyz);
 
-			vec3 col = computePhong(fragPosVspace, diffColor, 
-				specColor, specPower, normal, light.spotLightBase.lightBase, 
-				ray);
+		float shadowmapLayerId = light.diffuseColorShadowmapId.w;
+		float shadow = computeShadowFactor(slight.texProjectionMat, 
+			fragPos, uShadowMapArr, shadowmapLayerId);
 
-			outColor += col * (midFactor * shadow);
-		}
+		outColor += (diffC + specC) * (att * lambert * spot * shadow);
 	}
 
 #if GROUND_LIGHT
@@ -257,34 +269,4 @@ void main()
 		outColor = vec3(specPower / 120.0);
 	}
 #endif
-
-#if 0
-	if(pointLightsCount > 0)
-	{
-		outColor += vec3(0.1);
-	}
-#endif
-
-#if 0
-	outColor += vec3(slights[0].light.diffuseColorShadowmapId.w,
-		slights[1].light.diffuseColorShadowmapId.w, 0.0);
-#endif
-
-#if 0
-	outColor = outColor * 0.0001 
-		+ vec3(uintBitsToFloat(tiles[inInstanceId].lightsCount[1]));
-#endif
-
-#if 0
-	if(tiles[inInstanceId].lightsCount[0] > 0)
-	{
-		outColor += vec3(0.0, 0.1, 0.0);
-	}
-#endif
-
-#if 0
-	vec3 tmpc = vec3((inInstanceId % 4) / 3.0, (inInstanceId % 3) / 2.0, 
-		(inInstanceId % 2));
-	outColor += tmpc / 40.0;
-#endif
 }

+ 1 - 1
shaders/PpsLfSpritePass.vert.glsl

@@ -16,7 +16,7 @@ struct Flare
 // The block contains data for all flares
 layout(std140) uniform bFlares
 {
-	Flare uFlares[MAX_FLARES];
+	Flare uFlares[MAX_SPRITES];
 };
 
 layout(location = 0) in vec2 inPosition;

+ 2 - 2
src/core/Config.cpp

@@ -54,8 +54,8 @@ Config::Config()
 	newOption("pps.bl.sideBlurFactor", 1.0);
 
 	newOption("pps.lf.enabled", true);
-	newOption("pps.lf.maxFlaresPerLight", 8);
-	newOption("pps.lf.maxLightsWithFlares", 4);
+	newOption("pps.lf.maxSpritesPerFlare", 8);
+	newOption("pps.lf.maxFlares", 4);
 
 	newOption("pps.enabled", true);
 	newOption("pps.sharpen", true);

+ 10 - 6
src/gl/GlOcclusionQueryHandle.cpp

@@ -18,7 +18,7 @@ GlOcclusionQueryHandle::~GlOcclusionQueryHandle()
 {}
 
 //==============================================================================
-Error GlOcclusionQueryHandle::create(GlCommandBufferHandle& commands)
+Error GlOcclusionQueryHandle::create(GlDevice* dev)
 {
 	class Command: public GlCommand
 	{
@@ -47,16 +47,20 @@ Error GlOcclusionQueryHandle::create(GlCommandBufferHandle& commands)
 	using Deleter = 
 		GlHandleDeferredDeleter<GlOcclusionQuery, Alloc, DeleteCommand>;
 
-	Error err = _createAdvanced(
-		&commands._get().getQueue().getDevice(),
-		commands._get().getGlobalAllocator(), 
-		Deleter());
+	GlCommandBufferHandle cmd;
+	Error err = cmd.create(dev);
+
+	if(!err)
+	{
+		err = _createAdvanced(dev, dev->_getAllocator(), Deleter());
+	}
 
 	if(!err)
 	{
 		_setState(GlHandleState::TO_BE_CREATED);
 
-		commands._pushBackNewCommand<Command>(*this);
+		cmd._pushBackNewCommand<Command>(*this);
+		cmd.flush();
 	}
 
 	return err;

+ 57 - 0
src/renderer/Dp.cpp

@@ -0,0 +1,57 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/renderer/Dp.h"
+#include "anki/renderer/Renderer.h"
+
+namespace anki {
+
+//==============================================================================
+Error Dp::init(const ConfigSet& config)
+{
+	m_smallDepthSize = UVec2(
+		getAlignedRoundDown(16, m_r->getWidth() / 3),
+		getAlignedRoundDown(16, m_r->getHeight() / 3));
+
+	Error err = m_r->createRenderTarget(
+		m_smallDepthSize.x(), 
+		m_smallDepthSize.y(),
+		GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
+		GL_UNSIGNED_INT, 1, m_smallDepthRt);
+	if(err) return err;
+
+	GlDevice& gl = getGlDevice();
+	GlCommandBufferHandle cmdb;
+	err = cmdb.create(&gl);
+	if(err)	return err;
+
+	m_smallDepthRt.setFilter(cmdb, GlTextureHandle::Filter::LINEAR);
+
+	err = m_smallDepthFb.create(
+		cmdb,
+		{{m_smallDepthRt, GL_DEPTH_ATTACHMENT}});
+	if(err)	return err;
+
+	cmdb.finish();
+
+	return ErrorCode::NONE;
+}
+
+//==============================================================================
+Error Dp::run(GlCommandBufferHandle& cmdb)
+{
+	m_smallDepthFb.blit(
+		cmdb, 
+		m_r->getMs().getFramebuffer(), 
+		{{0, 0, m_r->getWidth(), m_r->getHeight()}},
+		{{0, 0, m_smallDepthSize.x(), m_smallDepthSize.y()}},
+		GL_DEPTH_BUFFER_BIT, 
+		false);
+
+	return ErrorCode::NONE;
+}
+
+} // end namespace anki
+

+ 1 - 1
src/renderer/Drawer.cpp

@@ -202,7 +202,7 @@ public:
 			{
 				auto unit = glvar.getTextureUnit();
 
-				m_drawer->m_r->getMs()._getSmallDepthRt().bind(m_cmdBuff, unit);
+				m_drawer->m_r->getDp().getSmallDepthRt().bind(m_cmdBuff, unit);
 			}
 			break;
 		default:

+ 5 - 10
src/renderer/Is.cpp

@@ -50,11 +50,6 @@ public:
 	Vec4 m_lightDir;
 	Vec4 m_outerCosInnerCos;
 	Array<Vec4, 4> m_extendPoints;
-};
-
-class SpotTexLight: public SpotLight
-{
-public:
 	Mat4 m_texProjectionMat; ///< Texture projection matrix
 };
 
@@ -75,7 +70,7 @@ class WriteLightsJob: public Threadpool::Task
 public:
 	shader::PointLight* m_pointLights = nullptr;
 	shader::SpotLight* m_spotLights = nullptr;
-	shader::SpotTexLight* m_spotTexLights = nullptr;
+	shader::SpotLight* m_spotTexLights = nullptr;
 
 	U8* m_tileBuffer = nullptr;
 
@@ -188,7 +183,7 @@ public:
 				return -1;
 			}
 
-			shader::SpotTexLight& slight = m_spotTexLights[i];
+			shader::SpotLight& slight = m_spotTexLights[i];
 			baseslight = &slight;
 
 			// Write matrix
@@ -612,7 +607,7 @@ Error Is::lightPass(GlCommandBufferHandle& cmdBuff)
 
 	PtrSize spotTexLightsOffset = spotLightsOffset + spotLightsSize;
 	PtrSize spotTexLightsSize = getAlignedRoundUp(blockAlignment, 
-		sizeof(shader::SpotTexLight) * visibleSpotTexLightsCount);
+		sizeof(shader::SpotLight) * visibleSpotTexLightsCount);
 
 	ANKI_ASSERT(
 		spotTexLightsOffset + spotTexLightsSize <= calcLightsBufferSize());
@@ -667,7 +662,7 @@ Error Is::lightPass(GlCommandBufferHandle& cmdBuff)
 				job.m_spotLights = (shader::SpotLight*)(
 					(U8*)lightsClientBuff.getBaseAddress() 
 					+ spotLightsOffset);
-				job.m_spotTexLights = (shader::SpotTexLight*)(
+				job.m_spotTexLights = (shader::SpotLight*)(
 					(U8*)lightsClientBuff.getBaseAddress() 
 					+ spotTexLightsOffset);
 			}
@@ -869,7 +864,7 @@ PtrSize Is::calcLightsBufferSize() const
 
 	size += getAlignedRoundUp(
 		buffAlignment,
-		m_maxSpotTexLights * sizeof(shader::SpotTexLight));
+		m_maxSpotTexLights * sizeof(shader::SpotLight));
 
 	return size;
 }

+ 108 - 162
src/renderer/Lf.cpp

@@ -7,9 +7,10 @@
 #include "anki/renderer/Renderer.h"
 #include "anki/scene/SceneGraph.h"
 #include "anki/scene/MoveComponent.h"
+#include "anki/scene/LensFlareComponent.h"
 #include "anki/scene/Camera.h"
-#include "anki/scene/Light.h"
 #include "anki/misc/ConfigSet.h"
+#include "anki/util/Functions.h"
 
 namespace anki {
 
@@ -17,12 +18,9 @@ namespace anki {
 // Misc                                                                        =
 //==============================================================================
 
-namespace {
-
 //==============================================================================
-class Flare
+struct Sprite
 {
-public:
 	Vec2 m_pos; ///< Position in NDC
 	Vec2 m_scale; ///< Scale of the quad
 	F32 m_alpha; ///< Alpha value
@@ -30,22 +28,6 @@ public:
 	U32 m_padding[2];
 };
 
-//==============================================================================
-class LightSortFunctor
-{
-public:
-	Bool operator()(const Light* lightA, const Light* lightB)
-	{
-		ANKI_ASSERT(lightA && lightB);
-		ANKI_ASSERT(lightA->hasLensFlare() && lightB->hasLensFlare());
-
-		return lightA->getLensFlareTexture() <
-			lightB->getLensFlareTexture();
-	}
-};
-
-} // end namespace anonymous
-
 //==============================================================================
 // Lf                                                                          =
 //==============================================================================
@@ -81,8 +63,8 @@ Error Lf::initInternal(const ConfigSet& config)
 	err = cmdBuff.create(&getGlDevice());
 	if(err) return err;
 
-	m_maxFlaresPerLight = config.get("pps.lf.maxFlaresPerLight");
-	m_maxLightsWithFlares = config.get("pps.lf.maxLightsWithFlares");
+	m_maxSpritesPerFlare = config.get("pps.lf.maxSpritesPerFlare");
+	m_maxFlares = config.get("pps.lf.maxFlares");
 
 	// Load program 1
 	String pps;
@@ -104,8 +86,8 @@ Error Lf::initInternal(const ConfigSet& config)
 
 	// Load program 2
 	pps.destroy(getAllocator());
-	err = pps.sprintf(getAllocator(), "#define MAX_FLARES %u\n",
-		m_maxFlaresPerLight * m_maxLightsWithFlares);
+	err = pps.sprintf(getAllocator(), "#define MAX_SPRITES %u\n",
+		m_maxSpritesPerFlare);
 	if(err)
 	{
 		return err;
@@ -123,8 +105,11 @@ Error Lf::initInternal(const ConfigSet& config)
 		{m_realVert->getGlProgram(), m_realFrag->getGlProgram()});
 	if(err) return err;
 
-	PtrSize blockSize = 
-		sizeof(Flare) * m_maxFlaresPerLight * m_maxLightsWithFlares;
+	PtrSize uboAlignment = 
+		m_r->_getGlDevice().getBufferOffsetAlignment(GL_UNIFORM_BUFFER);
+	m_flareSize = getAlignedRoundUp(
+		uboAlignment, sizeof(Sprite) * m_maxSpritesPerFlare);
+	PtrSize blockSize = m_flareSize * m_maxFlares;
 
 	// Init buffer
 	err = m_flareDataBuff.create(
@@ -158,6 +143,48 @@ Error Lf::initInternal(const ConfigSet& config)
 	return err;
 }
 
+//==============================================================================
+Error Lf::runOcclusionTests(GlCommandBufferHandle& cmdb)
+{
+	ANKI_ASSERT(m_enabled);
+	Error err = ErrorCode::NONE;
+
+	// Retrieve some things
+	SceneGraph& scene = m_r->getSceneGraph();
+	Camera& cam = scene.getActiveCamera();
+	VisibilityTestResults& vi = cam.getVisibilityTestResults();
+
+	U totalCount = min<U>(vi.getLensFlaresCount(), m_maxFlares);
+	if(totalCount > 0)
+	{
+		// Setup state
+		cmdb.setColorWriteMask(false, false, false, false);
+		cmdb.setDepthWriteMask(false);
+		cmdb.enableDepthTest(true);
+
+		// Iterate lens flare
+		auto it = vi.getLensFlaresBegin();
+		auto end = vi.getLensFlaresEnd();
+		for(; it != end; ++it)
+		{
+			LensFlareComponent& lf = 
+				(it->m_node)->getComponent<LensFlareComponent>();
+
+			GlOcclusionQueryHandle& query = lf.getOcclusionQueryToTest();
+			query.begin(cmdb);
+
+			query.end(cmdb);
+		}
+
+		// Restore state
+		cmdb.setColorWriteMask(true, true, true, true);
+		cmdb.setDepthWriteMask(true);
+		cmdb.enableDepthTest(false);
+	}
+
+	return err;
+}
+
 //==============================================================================
 Error Lf::run(GlCommandBufferHandle& cmdBuff)
 {
@@ -191,72 +218,43 @@ Error Lf::run(GlCommandBufferHandle& cmdBuff)
 	Camera& cam = scene.getActiveCamera();
 	VisibilityTestResults& vi = cam.getVisibilityTestResults();
 
-	// Iterate the visible light and get those that have lens flare
-	SceneFrameDArrayAuto<Light*> lights(scene.getFrameAllocator());
-	err = lights.create(m_maxLightsWithFlares, nullptr);
-	if(err)	return err;
-
-	U lightsCount = 0;
-	auto it = vi.getLightsBegin();
-	auto end = vi.getLightsEnd();
-	for(; it != end; ++it)
+	U totalCount = min<U>(vi.getLensFlaresCount(), m_maxFlares);
+	if(totalCount > 0)
 	{
-		SceneNode& sn = *(it->m_node);
-		ANKI_ASSERT(sn.tryGetComponent<LightComponent>() != nullptr);
-		Light* light = staticCastPtr<Light*>(&sn);
-
-		if(light->hasLensFlare())
-		{
-			lights[lightsCount++] = light;
+		// Allocate client buffer
+		U uboAlignment = 
+			m_r->_getGlDevice().getBufferOffsetAlignment(GL_UNIFORM_BUFFER);
+		U bufferSize = m_flareSize * totalCount;
 
-			if(lightsCount == m_maxLightsWithFlares)
-			{
-				break;
-			}
-		}
-	}
-
-	// Check the light count
-	if(lightsCount != 0)
-	{
-		// Sort the lights using their lens flare texture
-		std::sort(lights.begin(), lights.begin() + lightsCount, 
-			LightSortFunctor());
-
-		// Write the UBO and get the groups
-		//
 		GlClientBufferHandle flaresCBuff;
-		err = flaresCBuff.create(cmdBuff,
-			sizeof(Flare) * lightsCount * m_maxFlaresPerLight, nullptr);
-		if(err)	return err;
-
-		Flare* flares = (Flare*)flaresCBuff.getBaseAddress();
-		U flaresCount = 0;
-
-		// Contains the number of flares per flare texture
-		SceneFrameDArrayAuto<U> groups(scene.getFrameAllocator());
-		err = groups.create(lightsCount, 0U);
-		if(err)	return err;
-
-		SceneFrameDArrayAuto<const GlTextureHandle*> texes(
-			scene.getFrameAllocator());
-		err = texes.create(lightsCount, nullptr);
+		err = flaresCBuff.create(cmdBuff, bufferSize, nullptr);
 		if(err)	return err;
 
-		U groupsCount = 0;
-
-		GlTextureHandle lastTex;
+		Sprite* sprites = static_cast<Sprite*>(flaresCBuff.getBaseAddress());
+		U8* spritesInitialPtr = reinterpret_cast<U8*>(sprites);
 
-		// Iterate all lights and update the flares as well as the groups
-		while(lightsCount-- != 0)
-		{
-			Light& light = *lights[lightsCount];
-			const GlTextureHandle& tex = light.getLensFlareTexture();
-			const U depth = light.getLensFlareTextureDepth();
+		// Set common rendering state
+		m_realPpline.bind(cmdBuff);
+		cmdBuff.enableBlend(true);
+		cmdBuff.setBlendFunctions(GL_ONE, GL_ONE);
 
-			// Transform
-			Vec3 posWorld = light.getWorldTransform().getOrigin().xyz();
-			Vec4 posClip = cam.getViewProjectionMatrix() * Vec4(posWorld, 1.0);
+		// Send the command to write the buffer now
+		m_flareDataBuff.write(
+			cmdBuff, flaresCBuff, 0, 0, 
+			bufferSize);
+
+		// Iterate lens flare
+		auto it = vi.getLensFlaresBegin();
+		auto end = vi.getLensFlaresEnd();
+		for(; it != end; ++it)
+		{			
+			LensFlareComponent& lf = 
+				(it->m_node)->getComponent<LensFlareComponent>();
+			U count = 0;
+
+			// Compute position
+			Vec4 lfPos = Vec4(lf.getWorldPosition().xyz(), 1.0);
+			Vec4 posClip = cam.getViewProjectionMatrix() * lfPos;
 
 			if(posClip.x() > posClip.w() || posClip.x() < -posClip.w()
 				|| posClip.y() > posClip.w() || posClip.y() < -posClip.w())
@@ -271,87 +269,35 @@ Error Lf::run(GlCommandBufferHandle& cmdBuff)
 			F32 len = dir.getLength();
 			dir /= len; // Normalize dir
 
-			// New group?
-			if(lastTex != tex)
-			{
-				texes[groupsCount] = &tex;
-				lastTex = tex;
-
-				++groupsCount;
-			}
-
 			// First flare 
-			F32 stretchFactor = 1.0 - posNdc.getLength();
-			stretchFactor *= stretchFactor;
-
-			Vec2 stretch = 
-				light.getLensFlaresStretchMultiplier() * stretchFactor;
-
-			flares[flaresCount].m_pos = posNdc;
-			flares[flaresCount].m_scale =
-				light.getLensFlaresSize() * Vec2(1.0, m_r->getAspectRatio())
-				* stretch;
-			flares[flaresCount].m_depth = 0.0;
-			flares[flaresCount].m_alpha = 
-				light.getLensFlaresAlpha() * stretchFactor;
-			++flaresCount;
-			++groups[groupsCount - 1];
-
-			// The rest of the flares
-			for(U d = 1; d < depth; d++)
-			{
-				// Write the "flares"
-				F32 factor = d / ((F32)depth - 1.0);
-
-				F32 flen = len * 2.0 * factor;
-
-				flares[flaresCount].m_pos = posNdc + dir * flen;
-
-				flares[flaresCount].m_scale =
-					light.getLensFlaresSize() * Vec2(1.0, m_r->getAspectRatio())
-					* ((len - flen) * 2.0);
-
-				flares[flaresCount].m_depth = d;
-
-				flares[flaresCount].m_alpha = light.getLensFlaresAlpha();
-
-				// Advance
-				++flaresCount;
-				++groups[groupsCount - 1];
-			}
-		}
-
-		// Time to render
-		//
-
-		// Write the buffer
-		m_flareDataBuff.write(
-			cmdBuff, flaresCBuff, 0, 0, sizeof(Flare) * flaresCount);
-
-		// Set the common state
-		m_realPpline.bind(cmdBuff);
-
-		cmdBuff.enableBlend(true);
-		cmdBuff.setBlendFunctions(GL_ONE, GL_ONE);
-
-		PtrSize offset = 0;
-		for(U i = 0; i < groupsCount; i++)
-		{
-			GlTextureHandle tex = *texes[i];
-			U instances = groups[i];
-			PtrSize buffSize = sizeof(Flare) * instances;
-
-			tex.bind(cmdBuff, 0);
-			m_flareDataBuff.bindShaderBuffer(cmdBuff, offset, buffSize, 0);
-
-			m_r->drawQuadInstanced(cmdBuff, instances);
-
-			offset += buffSize;
+			sprites[count].m_pos = posNdc;
+			sprites[count].m_scale =
+				lf.getFirstFlareSize() * Vec2(1.0, m_r->getAspectRatio());
+			sprites[count].m_depth = 0.0;
+			sprites[count].m_alpha = lf.getColorMultiplier().w();
+			++count;
+
+			// Render
+			lf.getTexture().bind(cmdBuff, 0);
+			m_flareDataBuff.bindShaderBuffer(
+				cmdBuff, 
+				reinterpret_cast<U8*>(sprites) - spritesInitialPtr, 
+				sizeof(Sprite) * count,
+				0);
+
+			m_r->drawQuad(cmdBuff);
+
+			// Advance
+			U advancementSize = 
+				getAlignedRoundUp(uboAlignment, sizeof(Sprite) * count);
+
+			sprites = reinterpret_cast<Sprite*>(
+				reinterpret_cast<U8*>(sprites) + advancementSize);
 		}
 	}
 	else
 	{
-		// No lights
+		// No flares
 
 		cmdBuff.enableBlend(true);
 		cmdBuff.setBlendFunctions(GL_ONE, GL_ONE);

+ 1 - 1
src/renderer/MainRenderer.cpp

@@ -94,7 +94,7 @@ Error MainRenderer::render(SceneGraph& scene)
 			rt = &getIs()._getRt();
 		}
 
-		//rt = &getPps().getSsao()._getRt();
+		//rt = &getDp().getSmallDepthRt();
 		//rt = &getIs()._getRt();
 
 		rt->setFilter(lastJobs, GlTextureHandle::Filter::LINEAR);

+ 0 - 34
src/renderer/Ms.cpp

@@ -81,34 +81,6 @@ Error Ms::initInternal(const ConfigSet& initializer)
 	err = createRt(1, 1);
 	if(err)	return err;
 
-	// Init small depth 
-	{
-		m_smallDepthSize = UVec2(
-			getAlignedRoundDown(16, m_r->getWidth() / 3),
-			getAlignedRoundDown(16, m_r->getHeight() / 3));
-
-		err = m_r->createRenderTarget(
-			m_smallDepthSize.x(), 
-			m_smallDepthSize.y(),
-			GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT,
-			GL_UNSIGNED_INT, 1, m_smallDepthRt);
-		if(err) return err;
-
-		GlDevice& gl = getGlDevice();
-		GlCommandBufferHandle cmdb;
-		err = cmdb.create(&gl);
-		if(err)	return err;
-
-		m_smallDepthRt.setFilter(cmdb, GlTextureHandle::Filter::LINEAR);
-
-		err = m_smallDepthFb.create(
-			cmdb,
-			{{m_smallDepthRt, GL_DEPTH_ATTACHMENT}});
-		if(err)	return err;
-
-		cmdb.finish();
-	}
-
 	err = m_ez.init(initializer);
 	return err;
 }
@@ -181,12 +153,6 @@ Error Ms::run(GlCommandBufferHandle& cmdb)
 		ANKI_ASSERT(0 && "TODO");
 	}
 
-	// Blit big depth buffer to small one
-	m_smallDepthFb.blit(cmdb, m_planes[1].m_fb, 
-		{{0, 0, m_r->getWidth(), m_r->getHeight()}},
-		{{0, 0, m_smallDepthSize.x(), m_smallDepthSize.y()}},
-		GL_DEPTH_BUFFER_BIT, false);
-
 	cmdb.enableDepthTest(false);
 
 	return err;

+ 6 - 0
src/renderer/Renderer.cpp

@@ -14,6 +14,7 @@ namespace anki {
 //==============================================================================
 Renderer::Renderer()
 :	m_ms(this), 
+	m_dp(this), 
 	m_is(this),
 	m_pps(this),
 	m_bs(this),
@@ -114,6 +115,8 @@ Error Renderer::initInternal(const ConfigSet& config)
 
 	err = m_ms.init(config);
 	if(err) return err;
+	err = m_dp.init(config);
+	if(err) return err;
 	err = m_is.init(config);
 	if(err) return err;
 	err = m_bs.init(config);
@@ -167,6 +170,9 @@ Error Renderer::render(SceneGraph& scene,
 	cmdBuff[0].flush();
 	ANKI_COUNTER_STOP_TIMER_INC(RENDERER_MS_TIME);
 
+	err = m_dp.run(cmdBuff[1]);
+	if(err) return err;
+
 	m_tiler.runMinMax(m_ms._getDepthRt());
 
 	ANKI_COUNTER_START_TIMER(RENDERER_IS_TIME);

+ 1 - 1
src/renderer/Ssao.cpp

@@ -279,7 +279,7 @@ Error Ssao::run(GlCommandBufferHandle& cmdb)
 	m_uniformsBuff.bindShaderBuffer(cmdb, 0);
 
 	Array<GlTextureHandle, 3> tarr = {{
-		m_r->getMs()._getSmallDepthRt(),
+		m_r->getDp().getSmallDepthRt(),
 		m_r->getMs()._getRt1(),
 		m_noiseTex}};
 	cmdb.bindTextures(0, tarr.begin(), tarr.getSize());

+ 1 - 1
src/renderer/Sslr.cpp

@@ -107,7 +107,7 @@ Error Sslr::run(GlCommandBufferHandle& cmdBuff)
 
 	Array<GlTextureHandle, 3> tarr = {{
 		m_r->getIs()._getRt(),
-		m_r->getMs()._getSmallDepthRt(),
+		m_r->getDp().getSmallDepthRt(),
 		m_r->getMs()._getRt1()}};
 	cmdBuff.bindTextures(0	, tarr.begin(), tarr.getSize()); 
 

+ 30 - 0
src/scene/LensFlareComponent.cpp

@@ -0,0 +1,30 @@
+// Copyright (C) 2014, Panagiotis Christopoulos Charitos.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include "anki/scene/LensFlareComponent.h"
+#include "anki/scene/SceneGraph.h"
+#include "anki/resource/TextureResource.h"
+
+namespace anki {
+
+//==============================================================================
+Error LensFlareComponent::create(const CString& textureFilename)
+{
+	// Texture
+	Error err = m_tex.load(
+		textureFilename, &m_node->getSceneGraph()._getResourceManager());
+
+	// Queries
+	GlDevice& gl = m_node->getSceneGraph()._getGlDevice();
+	for(auto it = m_queries.getBegin(); it != m_queries.getEnd() && !err; ++it)
+	{
+		err = (*it).create(&gl);
+	}
+
+	return err;
+}
+
+} // end namespace anki
+

+ 42 - 3
src/scene/Light.cpp

@@ -4,6 +4,7 @@
 // http://www.anki3d.org/LICENSE
 
 #include "anki/scene/Light.h"
+#include "anki/scene/LensFlareComponent.h"
 
 namespace anki {
 
@@ -54,7 +55,13 @@ Error Light::create(const CString& name)
 
 //==============================================================================
 Light::~Light()
-{}
+{
+	LensFlareComponent* flareComp = tryGetComponent<LensFlareComponent>();
+	if(flareComp)
+	{
+		getSceneAllocator().deleteInstance(flareComp);
+	}
+}
 
 //==============================================================================
 void Light::frustumUpdate()
@@ -103,13 +110,45 @@ void Light::onMoveComponentUpdateCommon()
 	// Update the spatial
 	SpatialComponent& sp = getComponent<SpatialComponent>();
 	sp.markForUpdate();
+
+	// Update the lens flare
+	LensFlareComponent* lf = tryGetComponent<LensFlareComponent>();
+	if(lf)
+	{
+		lf->setWorldPosition(move.getWorldTransform().getOrigin());
+	}
 }
 
 //==============================================================================
 Error Light::loadLensFlare(const CString& filename)
 {
-	ANKI_ASSERT(!hasLensFlare());
-	return m_flaresTex.load(filename, &getResourceManager());
+	ANKI_ASSERT(tryGetComponent<LensFlareComponent>() == nullptr);
+	Error err = ErrorCode::NONE;
+
+	LensFlareComponent* flareComp = 
+		getSceneAllocator().newInstance<LensFlareComponent>(this);
+	
+	if(flareComp)
+	{
+		err = flareComp->create(filename);
+	}
+	else
+	{
+		err = ErrorCode::OUT_OF_MEMORY;
+	}
+
+	if(!err)
+	{
+		err = addComponent(flareComp);	
+	}
+
+	// Clean up on any error
+	if(err && flareComp)
+	{
+		getSceneAllocator().deleteInstance(flareComp);
+	}
+
+	return err;
 }
 
 //==============================================================================

+ 71 - 21
src/scene/Visibility.cpp

@@ -6,6 +6,7 @@
 #include "anki/scene/Visibility.h"
 #include "anki/scene/SceneGraph.h"
 #include "anki/scene/FrustumComponent.h"
+#include "anki/scene/LensFlareComponent.h"
 #include "anki/scene/Light.h"
 #include "anki/renderer/Renderer.h"
 #include "anki/util/Logger.h"
@@ -28,7 +29,7 @@ public:
 	VisibilityTestResults* m_cameraVisible; // out
 
 	/// Test a frustum component
-	ANKI_USE_RESULT Error test(SceneNode& testedNode, Bool isLight, 
+	ANKI_USE_RESULT Error test(SceneNode& testedNode, Bool testingLight, 
 		U32 threadId, PtrSize threadsCount);
 
 	/// Do the tests
@@ -39,10 +40,10 @@ public:
 };
 
 //==============================================================================
-Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight, 
+Error VisibilityTestTask::test(SceneNode& testedNode, Bool testingLight, 
 	U32 threadId, PtrSize threadsCount)
 {
-	ANKI_ASSERT(isLight == 
+	ANKI_ASSERT(testingLight == 
 		(testedNode.tryGetComponent<LightComponent>() != nullptr));
 
 	Error err = ErrorCode::NONE;
@@ -58,7 +59,7 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 	// Init visible
 	FrustumComponent::VisibilityStats stats = testedFr.getLastVisibilityStats();
 	
-	if(!isLight)
+	if(!testingLight)
 	{
 		// For camera be conservative
 		stats.m_renderablesCount /= threadsCount;
@@ -66,12 +67,12 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 	}
 
 	err = visible->create(
-		m_alloc, stats.m_renderablesCount, stats.m_lightsCount);
+		m_alloc, stats.m_renderablesCount, stats.m_lightsCount, 4);
 	if(err)	return err;
 
 	// Chose the test range and a few other things
 	PtrSize start, end;
-	if(!isLight)
+	if(!testingLight)
 	{
 		choseStartEnd(threadId, threadsCount, m_nodesCount, start, end);
 		m_cameraVisible = visible;
@@ -90,7 +91,7 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 		Error err = ErrorCode::NONE;
 
 		FrustumComponent* fr = node.tryGetComponent<FrustumComponent>();
-
+		
 		// Skip if it is the same
 		if(ANKI_UNLIKELY(&testedFr == fr))
 		{
@@ -119,7 +120,7 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 				ANKI_ASSERT(spIdx < MAX_U8);
 				sps[count++] = SpatialTemp{&sp, static_cast<U8>(spIdx)};
 
-				sp.enableBits(isLight 
+				sp.enableBits(testingLight 
 					? SpatialComponent::Flag::VISIBLE_LIGHT 
 					: SpatialComponent::Flag::VISIBLE_CAMERA);
 			}
@@ -164,7 +165,7 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 
 		// Do something with the result
 		RenderComponent* r = node.tryGetComponent<RenderComponent>();
-		if(isLight)
+		if(testingLight)
 		{
 			if(r && r->getCastsShadow())
 			{
@@ -177,21 +178,26 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 			{
 				err = visible->moveBackRenderable(m_alloc, visibleNode);
 			}
-			else
+
+			LightComponent* l = node.tryGetComponent<LightComponent>();
+			if(!err && l)
 			{
-				LightComponent* l = node.tryGetComponent<LightComponent>();
-				if(l)
-				{
-					Light* light = staticCastPtr<Light*>(&node);
+				Light* light = staticCastPtr<Light*>(&node);
 
-					err = visible->moveBackLight(m_alloc, visibleNode);
+				err = visible->moveBackLight(m_alloc, visibleNode);
 
-					if(!err && light->getShadowEnabled() && fr)
-					{
-						err = test(node, true, 0, 0);
-					}
+				if(!err && light->getShadowEnabled() && fr)
+				{
+					err = test(node, true, 0, 0);
 				}
 			}
+
+			LensFlareComponent* lf = node.tryGetComponent<LensFlareComponent>();
+			if(!err && lf)
+			{
+				err = visible->moveBackLensFlare(m_alloc, visibleNode);
+				ANKI_ASSERT(visibleNode.m_node);
+			}
 		}
 
 		return err;
@@ -200,6 +206,32 @@ Error VisibilityTestTask::test(SceneNode& testedNode, Bool isLight,
 	return err;
 }
 
+//==============================================================================
+// VisibilityTestResults                                                       =
+//==============================================================================
+
+//==============================================================================
+Error VisibilityTestResults::create(
+	SceneFrameAllocator<U8> alloc,
+	U32 renderablesReservedSize,
+	U32 lightsReservedSize,
+	U32 lensFlaresReservedSize)
+{
+	Error err = m_renderables.create(alloc, renderablesReservedSize);
+	
+	if(!err)
+	{
+		err = m_lights.create(alloc, lightsReservedSize);
+	}
+
+	if(!err)
+	{
+		err = m_flares.create(alloc, lensFlaresReservedSize);
+	}
+
+	return err;
+}
+
 //==============================================================================
 Error VisibilityTestResults::moveBack(
 	SceneFrameAllocator<U8> alloc, Container& c, U32& count, VisibleNode& x)
@@ -215,12 +247,16 @@ Error VisibilityTestResults::moveBack(
 
 	if(!err)
 	{
-		c[count++] = std::move(x);
+		c[count++] = x;
 	}
 
 	return err;
 }
 
+//==============================================================================
+// doVisibilityTests                                                           =
+//==============================================================================
+
 //==============================================================================
 Error doVisibilityTests(SceneNode& fsn, SceneGraph& scene, Renderer& r)
 {
@@ -252,10 +288,12 @@ Error doVisibilityTests(SceneNode& fsn, SceneGraph& scene, Renderer& r)
 	// final result
 	U32 renderablesSize = 0;
 	U32 lightsSize = 0;
+	U32 lensFlaresSize = 0;
 	for(U i = 0; i < threadPool.getThreadsCount(); i++)
 	{
 		renderablesSize += jobs[i].m_cameraVisible->getRenderablesCount();
 		lightsSize += jobs[i].m_cameraVisible->getLightsCount();
+		lensFlaresSize += jobs[i].m_cameraVisible->getLensFlaresCount();
 	}
 
 	// Allocate
@@ -266,7 +304,8 @@ Error doVisibilityTests(SceneNode& fsn, SceneGraph& scene, Renderer& r)
 	err = visible->create(
 		scene.getFrameAllocator(), 
 		renderablesSize, 
-		lightsSize);
+		lightsSize,
+		lensFlaresSize);
 	if(err)	return err;
 
 	visible->prepareMerge();
@@ -279,12 +318,14 @@ Error doVisibilityTests(SceneNode& fsn, SceneGraph& scene, Renderer& r)
 	// Append thread results
 	VisibleNode* renderables = visible->getRenderablesBegin();
 	VisibleNode* lights = visible->getLightsBegin();
+	VisibleNode* lensFlares = visible->getLensFlaresBegin();
 	for(U i = 0; i < threadPool.getThreadsCount(); i++)
 	{
 		VisibilityTestResults& from = *jobs[i].m_cameraVisible;
 
 		U rCount = from.getRenderablesCount();
 		U lCount = from.getLightsCount();
+		U lfCount = from.getLensFlaresCount();
 
 		if(rCount > 0)
 		{
@@ -303,6 +344,15 @@ Error doVisibilityTests(SceneNode& fsn, SceneGraph& scene, Renderer& r)
 
 			lights += lCount;
 		}
+
+		if(lfCount > 0)
+		{
+			memcpy(lensFlares,
+				from.getLensFlaresBegin(),
+				sizeof(VisibleNode) * lfCount);
+
+			lensFlares += lfCount;
+		}
 	}
 
 	// Set the frustumable

+ 7 - 5
testapp/Main.cpp

@@ -29,6 +29,7 @@
 #include "anki/event/JitterMoveEvent.h"
 #include "anki/core/Counters.h"
 #include "anki/core/Config.h"
+#include "anki/scene/LensFlareComponent.h"
 
 using namespace anki;
 
@@ -138,14 +139,15 @@ Error init()
 			("vase_plight" + std::to_string(i)).c_str(), point);
 		if(err) return err;
 
-		point->loadLensFlare("textures/lens_flare/flares0.ankitex");
-
 		point->setRadius(2.0);
 		point->setLocalOrigin(lightPos);
 		point->setDiffuseColor(Vec4(3.0, 0.2, 0.0, 0.0));
 		point->setSpecularColor(Vec4(1.0, 1.0, 0.0, 0.0));
-		point->setLensFlaresStretchMultiplier(Vec2(10.0, 1.0));
-		point->setLensFlaresAlpha(1.0);
+		
+		point->loadLensFlare("textures/lens_flare/flares0.ankitex");
+		LensFlareComponent& lf = point->getComponent<LensFlareComponent>();
+		lf.setFirstFlareSize(Vec2(0.5, 0.2));
+		lf.setColorMultiplier(Vec4(1.0, 1.0, 1.0, 0.6));
 
 		LightEvent* event;
 		err = scene.getEventManager().newEvent(event, 0.0, 0.8, point);
@@ -549,7 +551,7 @@ Error initSubsystems(int argc, char* argv[])
 	config.set("tilesYCount", 16);
 
 	config.set("fullscreenDesktopResolution", true);
-	config.set("debugContext", false);
+	config.set("debugContext", true);
 
 	app = new App;
 	err = app->create(config, allocAligned, nullptr);

+ 1 - 1
thirdparty

@@ -1 +1 @@
-Subproject commit 09349de128a289385c6a226b005b90c59757509d
+Subproject commit 6a6d6a5c43a8bb4422c67deceadaf28cf8423e7a