/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser 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, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/

#include "ps_1_4.h"
#include "OgreException.h"
#include "OgreRoot.h"
#include "OgreRenderSystem.h"
#include "OgreRenderSystemCapabilities.h"
#include "OgreLogManager.h"
#include "ATI_FS_GLGpuProgram.h"

using namespace Ogre;


ATI_FS_GLGpuProgram::ATI_FS_GLGpuProgram(ResourceManager* creator, 
        const String& name, ResourceHandle handle, 
        const String& group, bool isManual, ManualResourceLoader* loader) :
    GLGpuProgram(creator, name, handle, group, isManual, loader)
{
	mProgramType = GL_FRAGMENT_SHADER_ATI;
    mProgramID = glGenFragmentShadersATI(1);
}

ATI_FS_GLGpuProgram::~ATI_FS_GLGpuProgram()
{
    // have to call this here reather than in Resource destructor
    // since calling virtual methods in base destructors causes crash
    unload(); 
}

void ATI_FS_GLGpuProgram::bindProgram(void)
{
	glEnable(mProgramType);
	glBindFragmentShaderATI(mProgramID);
}

void ATI_FS_GLGpuProgram::unbindProgram(void)
{
	glDisable(mProgramType);
}


void ATI_FS_GLGpuProgram::bindProgramParameters(GpuProgramParametersSharedPtr params)
{

	// only supports float constants
	const GpuLogicalBufferStruct* floatStruct = params->getFloatLogicalBufferStruct();

	for (GpuLogicalIndexUseMap::const_iterator i = floatStruct->map.begin();
		i != floatStruct->map.end(); ++i)
	{
		size_t logicalIndex = i->first;
		const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
		// Iterate over the params, set in 4-float chunks (low-level)
		for (size_t j = 0; j < i->second.currentSize; j+=4)
		{
			glSetFragmentShaderConstantATI(GL_CON_0_ATI + logicalIndex, pFloat);
			pFloat += 4;
			++logicalIndex;
		}
	}

}

void ATI_FS_GLGpuProgram::bindProgramPassIterationParameters(GpuProgramParametersSharedPtr params)
{
	if (params->hasPassIterationNumber())
	{
		size_t physicalIndex = params->getPassIterationNumberIndex();
		size_t logicalIndex = params->getFloatLogicalIndexForPhysicalIndex(physicalIndex);
		const float* pFloat = params->getFloatPointer(physicalIndex);
		glSetFragmentShaderConstantATI( GL_CON_0_ATI + (GLuint)logicalIndex, pFloat);
	}
}


void ATI_FS_GLGpuProgram::unloadImpl(void)
{
	glDeleteFragmentShaderATI(mProgramID);
}


void ATI_FS_GLGpuProgram::loadFromSource(void)
{

    PS_1_4 PS1_4Assembler;
	// attempt to compile the source
#ifdef _DEBUG
	PS1_4Assembler.test(); // run compiler tests in debug mode
#endif

    bool Error = !PS1_4Assembler.compile(mSource.c_str());

    if(!Error) { 
		glBindFragmentShaderATI(mProgramID);
		glBeginFragmentShaderATI();
			// compile was successfull so send the machine instructions thru GL to GPU
			Error = !PS1_4Assembler.bindAllMachineInstToFragmentShader();
        glEndFragmentShaderATI();

		// check GL for GPU machine instruction bind erros
		if (Error)
		{
			OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
				"Cannot Bind ATI fragment shader :" + mName, mName); 
		}

    }
    else
	{
		// an error occured when compiling the ps_1_4 source code
		char buff[50];
        sprintf(buff,"error on line %d in pixel shader source\n", PS1_4Assembler.mCurrentLine);

		LogManager::getSingleton().logMessage("Warning: atifs compiler reported the following errors:");
		LogManager::getSingleton().logMessage(buff + mName);

		OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
			"Cannot Compile ATI fragment shader : " + mName + "\n\n" + buff , mName);// + 
    }


}

