/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2008.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: src/drivers/common/opengl/ogltexture.cpp

*/

#include "sgx/core/core.hpp"
#include "sgx/graphics/graphics.hpp"

#include "drivers/common/opengl/opengl.hpp"

SGX_INLINE GLint format2GL(CImageData::tFormat fmt)
{
	return fmt == CImageData::eRGB ? GL_RGB : GL_RGBA;
}

SGX_INLINE GLint blendMode2GL(CSGXOpenGLSurface::tBlendMode blend)
{
	switch(blend) {
	case	CSGXSurface::eBlendDecal:
		return GL_DECAL;

	case	CSGXSurface::eBlend:
		return GL_BLEND;

	case	CSGXSurface::eBlendModulate:
		return GL_MODULATE;
	}

	return GL_REPLACE;
}

CSGXOpenGLSurface::CSGXOpenGLSurface(const tUINT32 width, const tUINT32 height, const CImageData::tFormat format, void *bitmap, const CSGXSurface::tReason reason)
: CSGXSurface(width, height, format, bitmap, reason)
{
	// NOTE: We may also have used glGenTextures instead to retrieve unused IDs
	m_id = CSGXOpenGLTextureManager::getNextTextureID();
	m_pProperty = NULL;

	sgxAssert(!glIsTexture(m_id));

	glBindTexture(GL_TEXTURE_2D, m_id);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	
	// Default wrapping, can be overriding with separate call to 'setWrapped'
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	//
	// Reason translates to basic priority levels in openGL
	//
	GLclampf pri;
	if (reason == eReasonVideo) {
		pri = 1.0f;
	} else if (reason == eReasonDynamic) { 
		pri = 0;
	} else {
		pri = 0.5f;
	}
	glPrioritizeTextures(1, &m_id, &pri);

	//
	// Fixup basic data
	//
	m_GL_format = format2GL(format);

	rebuild(bitmap);

}

CSGXOpenGLSurface::~CSGXOpenGLSurface()
{
	delete m_pProperty;
	glDeleteTextures(1, &m_id);
}

void CSGXOpenGLSurface::rebuild(void *bitmap_)
{
	const void *bitmap = bitmap_;

	if (!bitmap) {
		bitmap = m_pBitmap;
		if (!bitmap) {
			return;
		}
	}

	glBindTexture(GL_TEXTURE_2D, m_id);

	if (m_GL_format == GL_RGBA) {
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_iWidth, m_iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
	} else {	
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
		gluBuild2DMipmaps(GL_TEXTURE_2D, m_GL_format, m_iWidth, m_iHeight, m_GL_format, GL_UNSIGNED_BYTE, bitmap);
	}
}

void CSGXOpenGLSurface::set() const
{
	COpenGLEngine::m_StateBindTex.Apply(m_id);
	
	if (m_GL_format == GL_RGBA) {
		// So is this code below needed?
		COpenGLEngine::m_StateBlendFunc.Apply(oglBlend(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
	}
//		COpenGLEngine::m_StateBlendFunc.Apply(oglBlend(GL_SRC_COLOR, GL_ZERO));

	COpenGLEngine::m_StateTexEnv.Apply(blendMode2GL(m_BlendMode));
	
	glDisable(GL_TEXTURE_GEN_S);
	glDisable(GL_TEXTURE_GEN_T);

	if (m_pProperty && m_pProperty->applyTexture(m_id)) {
		return;
	}

}

void CSGXOpenGLSurface::setRegion(const tUINT32 region)
{
	// TODO	
}

void CSGXOpenGLSurface::setRegion(const sgxUV &uv)
{
	// TODO	
}

void CSGXOpenGLSurface::setWrapped(const tWrapped wrapped)
{
	set();

	// set up 'U' co-ord
	if (wrapped == eRepeatUV || wrapped == eRepeatUClampV) {
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	} else {
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	}

	// set up 'V' co-ord
	if (wrapped == eRepeatUV || wrapped == eRepeatVClampU) {
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	} else {
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	}
}

tBOOL
CSGXOpenGLSurface::lock(CImageData &img)
{
	if (!CSGXSurface::lock(img)) {
		return FALSE;
	}

	glBindTexture(GL_TEXTURE_2D, m_id);
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glReadPixels(0, 0, m_iWidth, m_iHeight, format2GL(m_iFormat), GL_UNSIGNED_BYTE, (GLvoid *)img.getBitmap());

	return TRUE;
}

tBOOL
CSGXOpenGLSurface::setTextureProperty(const sgxString &property, const sgxTexturePropertyParams *pParams)
{
	delete m_pProperty;

	if (property == SGX_TEXTURE_QUADRIC) { 
		m_pProperty = new sgxOpenGLTexturePropertyQuadric; 
		return m_pProperty ? TRUE : FALSE;
	}

	// Other properties may cast the pParams to an appropriate type

	return FALSE;
}
