/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES 2.0 Module
 * -------------------------------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief glDepthRangef() tests.
 *//*--------------------------------------------------------------------*/

#include "es2fDepthRangeTests.hpp"
#include "tcuVector.hpp"
#include "tcuTestLog.hpp"
#include "tcuSurface.hpp"
#include "tcuImageCompare.hpp"
#include "tcuRenderTarget.hpp"
#include "gluPixelTransfer.hpp"
#include "gluShaderProgram.hpp"
#include "gluRenderContext.hpp"
#include "deRandom.hpp"
#include "deMath.h"
#include "deString.h"

#include "glw.h"

namespace deqp
{
namespace gles2
{
namespace Functional
{

enum
{
	VISUALIZE_DEPTH_STEPS	= 32 //!< Number of depth steps in visualization
};

using tcu::Vec2;
using tcu::Vec3;
using tcu::Vec4;
using tcu::TestLog;
using std::string;
using std::vector;

static const char* s_vertexShaderSrc =
	"attribute highp vec4 a_position;\n"
	"attribute highp vec2 a_coord;\n"
	"void main (void)\n"
	"{\n"
	"	gl_Position = a_position;\n"
	"}\n";
static const char* s_fragmentShaderSrc =
	"uniform mediump vec4 u_color;\n"
	"void main (void)\n"
	"{\n"
	"	gl_FragColor = u_color;\n"
	"}\n";

template <typename T>
static inline bool compare (deUint32 func, T a, T b)
{
	switch (func)
	{
		case GL_NEVER:		return false;
		case GL_ALWAYS:		return true;
		case GL_LESS:		return a < b;
		case GL_LEQUAL:		return a <= b;
		case GL_EQUAL:		return a == b;
		case GL_NOTEQUAL:	return a != b;
		case GL_GEQUAL:		return a >= b;
		case GL_GREATER:	return a > b;
		default:
			DE_ASSERT(DE_FALSE);
			return false;
	}
}

inline float triangleInterpolate (const float v0, const float v1, const float v2, const float x, const float y)
{
	return v0 + (v2-v0)*x + (v1-v0)*y;
}

inline float triQuadInterpolate (const float x, const float y, const tcu::Vec4& quad)
{
	// \note Top left fill rule.
	if (x + y < 1.0f)
		return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y);
	else
		return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
}

inline float depthRangeTransform (const float zd, const float zNear, const float zFar)
{
	const float	cNear	= de::clamp(zNear, 0.0f, 1.0f);
	const float	cFar	= de::clamp(zFar, 0.0f, 1.0f);
	return ((cFar - cNear)/2.0f) * zd + (cNear + cFar)/2.0f;
}

class DepthRangeCompareCase : public TestCase
{
public:
							DepthRangeCompareCase	(Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc);
							~DepthRangeCompareCase	(void);

	IterateResult			iterate					(void);

private:
	const tcu::Vec4			m_depthCoord;
	const float				m_zNear;
	const float				m_zFar;
	const deUint32			m_compareFunc;
};

DepthRangeCompareCase::DepthRangeCompareCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar, const deUint32 compareFunc)
	: TestCase			(context, name, desc)
	, m_depthCoord		(depthCoord)
	, m_zNear			(zNear)
	, m_zFar			(zFar)
	, m_compareFunc		(compareFunc)
{
}

DepthRangeCompareCase::~DepthRangeCompareCase (void)
{
}

DepthRangeCompareCase::IterateResult DepthRangeCompareCase::iterate (void)
{
	TestLog&					log					= m_testCtx.getLog();
	de::Random					rnd					(deStringHash(getName()));
	const tcu::RenderTarget&	renderTarget		= m_context.getRenderContext().getRenderTarget();
	const int					viewportW			= de::min(128, renderTarget.getWidth());
	const int					viewportH			= de::min(128, renderTarget.getHeight());
	const int					viewportX			= rnd.getInt(0, renderTarget.getWidth()-viewportW);
	const int					viewportY			= rnd.getInt(0, renderTarget.getHeight()-viewportH);
	tcu::Surface				renderedFrame		(viewportW, viewportH);
	tcu::Surface				referenceFrame		(viewportW, viewportH);
	const float					constDepth			= 0.1f;

	if (renderTarget.getDepthBits() == 0)
		throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);

	const glu::ShaderProgram	program				(m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc));

	if (!program.isOk())
	{
		log << program;
		TCU_FAIL("Compile failed");
	}

	const int					colorLoc			= glGetUniformLocation(program.getProgram(), "u_color");
	const int					posLoc				= glGetAttribLocation(program.getProgram(), "a_position");

	m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage;

	glViewport(viewportX, viewportY, viewportW, viewportH);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);
	glUseProgram(program.getProgram());
	glEnableVertexAttribArray(posLoc);

	static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };

	// Fill viewport with 2 quads - one with constant depth and another with d = [-1..1]
	{
		static const float constDepthCoord[] =
		{
			-1.0f, -1.0f, constDepth, 1.0f,
			-1.0f, +1.0f, constDepth, 1.0f,
			 0.0f, -1.0f, constDepth, 1.0f,
			 0.0f, +1.0f, constDepth, 1.0f
		};
		static const float varyingDepthCoord[] =
		{
			 0.0f, -1.0f, +1.0f, 1.0f,
			 0.0f, +1.0f,  0.0f, 1.0f,
			+1.0f, -1.0f,  0.0f, 1.0f,
			+1.0f, +1.0f, -1.0f, 1.0f
		};

		glUniform4f(colorLoc, 0.0f, 0.0f, 1.0f, 1.0f);
		glDepthFunc(GL_ALWAYS);

		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &constDepthCoord);
		glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);

		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &varyingDepthCoord);
		glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);

		GLU_CHECK();
	}

	// Render with depth test.
	{
		const float position[] =
		{
			-1.0f, -1.0f, m_depthCoord[0], 1.0f,
			-1.0f, +1.0f, m_depthCoord[1], 1.0f,
			+1.0f, -1.0f, m_depthCoord[2], 1.0f,
			+1.0f, +1.0f, m_depthCoord[3], 1.0f
		};

		glDepthRangef(m_zNear, m_zFar);
		glDepthFunc(m_compareFunc);
		glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);

		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
		glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);

		GLU_CHECK();
	}

	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());

	// Render reference.
	for (int y = 0; y < referenceFrame.getHeight(); y++)
	{
		float	yf		= ((float)y + 0.5f) / (float)referenceFrame.getHeight();
		int		half	= de::clamp((int)((float)referenceFrame.getWidth()*0.5f + 0.5f), 0, referenceFrame.getWidth());

		// Fill left half - comparison to constant 0.5
		for (int x = 0; x < half; x++)
		{
			float	xf		= ((float)x + 0.5f) / (float)referenceFrame.getWidth();
			float	d		= depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
			bool	dpass	= compare(m_compareFunc, d, constDepth*0.5f + 0.5f);

			referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
		}

		// Fill right half - comparison to interpolated depth
		for (int x = half; x < referenceFrame.getWidth(); x++)
		{
			float	xf		= ((float)x + 0.5f) / (float)referenceFrame.getWidth();
			float	xh		= ((float)(x - half) + 0.5f) / (float)(referenceFrame.getWidth()-half);
			float	rd		= 1.0f - (xh + yf) * 0.5f;
			float	d		= depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
			bool	dpass	= compare(m_compareFunc, d, rd);

			referenceFrame.setPixel(x, y, dpass ? tcu::RGBA::green() : tcu::RGBA::blue());
		}
	}

	bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT);
	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
							isOk ? "Pass"				: "Fail");
	return STOP;
}

class DepthRangeWriteCase : public TestCase
{
public:
							DepthRangeWriteCase		(Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar);
							~DepthRangeWriteCase	(void);

	IterateResult			iterate					(void);

private:
	const tcu::Vec4&		m_depthCoord;
	const float				m_zNear;
	const float				m_zFar;
};

DepthRangeWriteCase::DepthRangeWriteCase (Context& context, const char* name, const char* desc, const tcu::Vec4& depthCoord, const float zNear, const float zFar)
	: TestCase			(context, name, desc)
	, m_depthCoord		(depthCoord)
	, m_zNear			(zNear)
	, m_zFar			(zFar)
{
}

DepthRangeWriteCase::~DepthRangeWriteCase (void)
{
}

DepthRangeWriteCase::IterateResult DepthRangeWriteCase::iterate (void)
{
	TestLog&					log				= m_testCtx.getLog();
	de::Random					rnd				(deStringHash(getName()));
	const tcu::RenderTarget&	renderTarget	= m_context.getRenderContext().getRenderTarget();
	const int					viewportW		= de::min(128, renderTarget.getWidth());
	const int					viewportH		= de::min(128, renderTarget.getHeight());
	const int					viewportX		= rnd.getInt(0, renderTarget.getWidth()-viewportW);
	const int					viewportY		= rnd.getInt(0, renderTarget.getHeight()-viewportH);
	tcu::Surface				renderedFrame	(viewportW, viewportH);
	tcu::Surface				referenceFrame	(viewportW, viewportH);
	const int					numDepthSteps	= VISUALIZE_DEPTH_STEPS;
	const float					depthStep		= 1.0f/(float)(numDepthSteps-1);

	if (renderTarget.getDepthBits() == 0)
		throw tcu::NotSupportedError("Depth buffer is required", "", __FILE__, __LINE__);

	const glu::ShaderProgram	program			(m_context.getRenderContext(), glu::makeVtxFragSources(s_vertexShaderSrc, s_fragmentShaderSrc));

	if (!program.isOk())
	{
		log << program;
		TCU_FAIL("Compile failed");
	}

	const int					colorLoc		= glGetUniformLocation(program.getProgram(), "u_color");
	const int					posLoc			= glGetAttribLocation(program.getProgram(), "a_position");

	m_testCtx.getLog() << TestLog::Message << "glDepthRangef(" << m_zNear << ", " << m_zFar << ")" << TestLog::EndMessage;

	glViewport(viewportX, viewportY, viewportW, viewportH);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);
	glUseProgram(program.getProgram());
	glEnableVertexAttribArray(posLoc);

	static const deUint16 quadIndices[] = { 0, 1, 2, 2, 1, 3 };

	// Render with depth range.
	{
		const float position[] =
		{
			-1.0f, -1.0f, m_depthCoord[0], 1.0f,
			-1.0f, +1.0f, m_depthCoord[1], 1.0f,
			+1.0f, -1.0f, m_depthCoord[2], 1.0f,
			+1.0f, +1.0f, m_depthCoord[3], 1.0f
		};

		glDepthFunc(GL_ALWAYS);
		glDepthRangef(m_zNear, m_zFar);
		glUniform4f(colorLoc, 0.0f, 1.0f, 0.0f, 1.0f);
		glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
		glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
		GLU_CHECK();
	}

	// Visualize by rendering full-screen quads with increasing depth and color.
	{
		glDepthFunc(GL_LEQUAL);
		glDepthMask(GL_FALSE);
		glDepthRangef(0.0f, 1.0f);

		for (int stepNdx = 0; stepNdx < numDepthSteps; stepNdx++)
		{
			float	f		= (float)stepNdx*depthStep;
			float	depth	= f*2.0f - 1.0f;
			Vec4	color	= Vec4(f, f, f, 1.0f);

			float position[] =
			{
				-1.0f, -1.0f, depth, 1.0f,
				-1.0f, +1.0f, depth, 1.0f,
				+1.0f, -1.0f, depth, 1.0f,
				+1.0f, +1.0f, depth, 1.0f
			};

			glUniform4fv(colorLoc, 1, color.getPtr());
			glVertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &position[0]);
			glDrawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(quadIndices), GL_UNSIGNED_SHORT, &quadIndices[0]);
		}

		GLU_CHECK();
	}

	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, renderedFrame.getAccess());

	// Render reference.
	for (int y = 0; y < referenceFrame.getHeight(); y++)
	{
		for (int x = 0; x < referenceFrame.getWidth(); x++)
		{
			float	xf		= ((float)x + 0.5f) / (float)referenceFrame.getWidth();
			float	yf		= ((float)y + 0.5f) / (float)referenceFrame.getHeight();
			float	d		= depthRangeTransform(triQuadInterpolate(xf, yf, m_depthCoord), m_zNear, m_zFar);
			int		step	= (int)deFloatFloor(d / depthStep);
			int		col		= de::clamp(deRoundFloatToInt32((float)step*depthStep*255.0f), 0, 255);

			referenceFrame.setPixel(x, y, tcu::RGBA(col, col, col, 0xff));
		}
	}

	bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT);
	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
							isOk ? "Pass"				: "Fail");
	return STOP;
}

DepthRangeTests::DepthRangeTests (Context& context)
	: TestCaseGroup(context, "depth_range", "glDepthRangef() tests")
{
}

DepthRangeTests::~DepthRangeTests (void)
{
}

void DepthRangeTests::init (void)
{
	static const struct
	{
		const char*			name;
		const char*			desc;
		const tcu::Vec4		depthCoord;
		const float			zNear;
		const float			zFar;
	} cases[] =
	{
		{ "default",		"Default depth range",		tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.0f,		1.0f },
		{ "reverse",		"Reversed default range",	tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	1.0f,		0.0f },
		{ "zero_to_half",	"From 0 to 0.5",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.0f,		0.5f },
		{ "half_to_one",	"From 0.5 to 1",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.5f,		1.0f },
		{ "half_to_zero",	"From 0.5 to 0",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.5f,		0.0f },
		{ "one_to_half",	"From 1 to 0.5",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	1.0f,		0.5f },
		{ "third_to_0_8",	"From 1/3 to 0.8",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	1.0f/3.0f,	0.8f },
		{ "0_8_to_third",	"From 0.8 to 1/3",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.8f,		1.0f/3.0f },
		{ "zero_to_zero",	"From 0 to 0",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.0f,		0.0f },
		{ "half_to_half",	"From 0.5 to 0.5",			tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.5f,		0.5f },
		{ "one_to_one",		"From 1 to 1",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	1.0f,		1.0f },
		{ "clamp_near",		"From -1 to 1",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	-1.0f,		1.0f },
		{ "clamp_far",		"From 0 to 2",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	0.0f,		2.0 },
		{ "clamp_both",		"From -1 to 2",				tcu::Vec4(-1.0f, 0.2f, -0.3f, 1.0f),	-1.0,		2.0 }
	};

	// .write
	tcu::TestCaseGroup* writeGroup = new tcu::TestCaseGroup(m_testCtx, "write", "gl_FragDepth write tests");
	addChild(writeGroup);
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
		writeGroup->addChild(new DepthRangeWriteCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar));

	// .compare
	tcu::TestCaseGroup* compareGroup = new tcu::TestCaseGroup(m_testCtx, "compare", "gl_FragDepth used with depth comparison");
	addChild(compareGroup);
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ndx++)
		compareGroup->addChild(new DepthRangeCompareCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].depthCoord, cases[ndx].zNear, cases[ndx].zFar, GL_LESS));
}

} // Functional
} // gles3
} // deqp
