/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES Utilities
 * ------------------------------------------------
 *
 * 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 OpenGL rendering configuration.
 *//*--------------------------------------------------------------------*/

#include "gluRenderConfig.hpp"
#include "tcuCommandLine.hpp"
#include "deString.h"

namespace glu
{

void parseConfigBitsFromName (RenderConfig* config, const char* renderCfgName)
{
	const char*	cfgName	= renderCfgName;

	DE_ASSERT(config->redBits		== RenderConfig::DONT_CARE	&&
			  config->greenBits		== RenderConfig::DONT_CARE	&&
			  config->blueBits		== RenderConfig::DONT_CARE	&&
			  config->alphaBits		== RenderConfig::DONT_CARE	&&
			  config->depthBits		== RenderConfig::DONT_CARE	&&
			  config->stencilBits	== RenderConfig::DONT_CARE	&&
			  config->numSamples	== RenderConfig::DONT_CARE);

	static const struct
	{
		const char*	name;
		int			redBits;
		int			greenBits;
		int			blueBits;
		int			alphaBits;
	} colorCfgs[] =
	{
		{ "rgb888",		8, 8, 8, 0 },
		{ "rgba8888",	8, 8, 8, 8 },
		{ "rgb565",		5, 6, 5, 0 },
		{ "rgba4444",	4, 4, 4, 4 },
		{ "rgba5551",	5, 5, 5, 1 }
	};
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorCfgs); ndx++)
	{
		if (deStringBeginsWith(cfgName, colorCfgs[ndx].name))
		{
			config->redBits		= colorCfgs[ndx].redBits;
			config->greenBits	= colorCfgs[ndx].greenBits;
			config->blueBits	= colorCfgs[ndx].blueBits;
			config->alphaBits	= colorCfgs[ndx].alphaBits;

			cfgName	+= strlen(colorCfgs[ndx].name);
			break;
		}
	}

	static const struct
	{
		const char*	name;
		int			depthSize;
	} depthCfgs[] =
	{
		{ "d0",		0 },
		{ "d16",	16 },
		{ "d24",	24 },
		{ "d32",	32 }
	};
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(depthCfgs); ndx++)
	{
		if (deStringBeginsWith(cfgName, depthCfgs[ndx].name))
		{
			config->depthBits = depthCfgs[ndx].depthSize;

			cfgName += strlen(depthCfgs[ndx].name);
			break;
		}
	}

	static const struct
	{
		const char*	name;
		int			stencilSize;
	} stencilCfgs[] =
	{
		{ "s0",		 0 },
		{ "s8",		 8 },
		{ "s16",	16 },
	};
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stencilCfgs); ndx++)
	{
		if (deStringBeginsWith(cfgName, stencilCfgs[ndx].name))
		{
			config->stencilBits = stencilCfgs[ndx].stencilSize;

			cfgName += strlen(stencilCfgs[ndx].name);
			break;
		}
	}

	static const struct
	{
		const char*	name;
		int			numSamples;
	} multiSampleCfgs[] =
	{
		{ "ms0",	 0 },
		{ "ms16",	16 },
		{ "ms1",	 1 },
		{ "ms2",	 2 },
		{ "ms4",	 4 },
		{ "ms8",	 8 }
	};
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(multiSampleCfgs); ndx++)
	{
		if (deStringBeginsWith(cfgName, multiSampleCfgs[ndx].name))
		{
			config->numSamples = multiSampleCfgs[ndx].numSamples;

			cfgName += strlen(multiSampleCfgs[ndx].name);
			break;
		}
	}

	if (cfgName[0] != 0)
		throw tcu::InternalError(std::string("Invalid GL configuration: '") + renderCfgName + "'");
}

void parseRenderConfig (RenderConfig* config, const tcu::CommandLine& cmdLine)
{
	switch (cmdLine.getSurfaceType())
	{
		case tcu::SURFACETYPE_WINDOW:				config->surfaceType		= RenderConfig::SURFACETYPE_WINDOW;				break;
		case tcu::SURFACETYPE_OFFSCREEN_NATIVE:		config->surfaceType		= RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE;	break;
		case tcu::SURFACETYPE_OFFSCREEN_GENERIC:	config->surfaceType		= RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC;	break;
		case tcu::SURFACETYPE_FBO:					config->surfaceType		= RenderConfig::SURFACETYPE_DONT_CARE;			break;
		case tcu::SURFACETYPE_LAST:					config->surfaceType		= RenderConfig::SURFACETYPE_DONT_CARE;			break;
		default:
			throw tcu::InternalError("Unsupported surface type");
	}

	config->windowVisibility = parseWindowVisibility(cmdLine);

	if (cmdLine.getSurfaceWidth() > 0)
		config->width = cmdLine.getSurfaceWidth();

	if (cmdLine.getSurfaceHeight() > 0)
		config->height = cmdLine.getSurfaceHeight();

	if (cmdLine.getGLConfigName() != DE_NULL)
		parseConfigBitsFromName(config, cmdLine.getGLConfigName());

	if (cmdLine.getGLConfigId() >= 0)
		config->id = cmdLine.getGLConfigId();
}

RenderConfig::Visibility parseWindowVisibility (const tcu::CommandLine& cmdLine)
{
	switch (cmdLine.getVisibility())
	{
		case tcu::WINDOWVISIBILITY_HIDDEN:		return RenderConfig::VISIBILITY_HIDDEN;
		case tcu::WINDOWVISIBILITY_WINDOWED:	return RenderConfig::VISIBILITY_VISIBLE;
		case tcu::WINDOWVISIBILITY_FULLSCREEN:	return RenderConfig::VISIBILITY_FULLSCREEN;
		default:
			throw tcu::InternalError("Unsupported window visibility");
	}
}

} // glu