/*
								+----------------------------------+
								|                                  |
								|  ***  GPU image processing  ***  |
								|                                  |
								|   Copyright © -tHE SWINe- 2008   |
								|                                  |
								|          GPUImgProc.inl          |
								|                                  |
								+----------------------------------+
*/

#pragma once
#ifndef __GPU_IMAGE_PROCESSING_INLINES_INCLUDED
#define __GPU_IMAGE_PROCESSING_INLINES_INCLUDED

/**
 *	@file dev/GPUImgProc.inl
 *	@date 2008
 *	@author -tHE SWINe-
 *	@brief GPU image processing
 *
 *	@date 2008-08-03
 *
 *	renamed from ImageProc.inl to GPUImgProc.inl for the sake of consistency
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64, added \#define for GL_GLEXT_LEGACY (for linux builds)
 *
 *	@date 2008-08-09
 *
 *	added void CGLImageProc::DisableProgrammableShading(),
 *	CGLImageProc::DisableFixedVertexProcessing(), and
 *	CGLImageProc::DisableFixedFragmentProcessing(). those can be used to disable unwanted
 *	operations on outputs of vertex / fragment programs
 *
 *	added IdentityMatrices() and FullscreenQuad(). those are pretty common
 *	functions in GPU image processing.
 *
 *	added GPUImgProc.inl
 *
 *	@date 2009-05-23
 *
 *	removed all instances of std::vector::reserve and replaced them by stl_ut::Reserve_*
 *
 *	changed format of message, printed on FBO allocation (GPU_IMGPROC_REPORT_ALLOCATING_FBO)
 *
 *	@date 2009-10-20
 *
 *	fixed some warnings when compiling under VC 2005, implemented "Security
 *	Enhancements in the CRT" for VC 2008. compare against MyProjects_2009-10-19_
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(for) && _MSC_VER <= 1200
#define for if(0) {} else for
#endif // _MSC_VER && !__MWERKS__ && !for && _MSC_VER <= 1200
// msvc 'for' scoping hack

/*
 *				=== CGLImageProc ===
 */

/*
 *	static inline void CGLImageProc::DisableProgrammableShading(CGLState *p_state)
 *		- utility function; disables programmable shading
 *		  (vertex programs, fragment programs and shader objects)
 *		- p_state is OpenGL state guard
 */
inline void CGLImageProc::DisableProgrammableShading(CGLState *p_state)
{
	p_state->DisableVertexProgram();
	p_state->DisableFragmentProgram();
	p_state->BindProgramObject(0);
}

/*
 *	static inline void CGLImageProc::DisableFixedVertexProcessing(CGLState *p_state)
 *		- utility function; disables fixed vertex processing (backface culling
 *		  and user-defined clipping)
 *		- p_state is OpenGL state guard
 */
inline void CGLImageProc::DisableFixedVertexProcessing(CGLState *p_state)
{
	/*
		excerpt from OpenGL 2.1 specification, page 85:

			The following operations are applied to vertex values that are the result of
		executing the vertex shader:
		• Color clamping or masking (section 2.14.6).
		• Perspective division on clip coordinates (section 2.11).
		• Viewport mapping, including depth range scaling (section 2.11.1).
		• Clipping, including client-defined clip planes (section 2.12).
		• Front face determination (section 2.14.1).
		• Flat-shading (section 2.14.7).
		• Color, texture coordinate, fog, point-size and generic attribute clipping (section
		  2.14.8).
		• Final color processing (section 2.14.9.)
	*/

	p_state->DisableCullFace();
	p_state->DisableAllClipPlanes();
	// others cannot be disabled
}

/*
 *	static inline void CGLImageProc::DisableFixedFragmentProcessing(CGLState *p_state,
 *		bool b_disable_stipple = false, bool b_disable_scissor = false,
 *		bool b_disable_dither = false, bool b_disable_color_logic_op = false,
 *		bool b_disable_index_logic_op = false)
 *		- utility function; disables fixed fragment processing (polygon stipple (only if
 *		  b_disable_stipple is true), scissor test (only if b_disable_scissor is true),
 *		  alpha test, stencil test, depth test, blending, dithering (only if b_disable_dither
 *		  is true), color logical operation and index logical operation (only if
 *		  b_disable_color_logic_op or b_disable_index_logic_op is true, respectively)
 *		  and resets color write mask)
 *		- p_state is OpenGL state guard
 */
inline void CGLImageProc::DisableFixedFragmentProcessing(CGLState *p_state,
	bool b_disable_scissor, bool b_disable_stipple, bool b_disable_dither,
	bool b_disable_color_logic_op, bool b_disable_index_logic_op)
{
	if(b_disable_stipple)
		p_state->Disable(GL_POLYGON_STIPPLE);
	if(b_disable_scissor)
		p_state->Disable(GL_SCISSOR_TEST);
	p_state->DisableAlphaTest();
	p_state->DisableStencilTest();
	p_state->DisableDepthTest();
	p_state->DisableBlend();
	if(b_disable_dither)
		p_state->Disable(GL_DITHER);
	if(b_disable_color_logic_op)
		p_state->Disable(GL_COLOR_LOGIC_OP);
	if(b_disable_index_logic_op)
		p_state->Disable(GL_INDEX_LOGIC_OP);
	p_state->ColorMask(true, true, true, true);
	// stages from Figure 4.1. from OpenGL specifiction
}

/*
 *	static inline void CGLImageProc::IdentityMatrices()
 *		- sets modelview and projection matrices to identity
 *		- does not modify texture matrices
 *		- always ends with GL_MODELVIEW matrix mode
 */
inline void CGLImageProc::IdentityMatrices()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

/*
 *	static inline void CGLImageProc::IdentityMatrices(CGLState *p_state,
 *		int n_set_identity_texture = 1)
 *		- sets modelview, projection and texture matrices to identity
 *		- n_set_identity_texture is number of texture units (starting with 0)
 *		  to set identity matrix in
 *		- always ends with GL_MODELVIEW matrix mode
 *		- if n_set_identity_texture is positive number, ends with active texture unit 0
 */
inline void CGLImageProc::IdentityMatrices(CGLState *p_state, int n_set_identity_texture)
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if(n_set_identity_texture) {
		glMatrixMode(GL_TEXTURE);
		for(int i = n_set_identity_texture - 1; i >= 0; -- i) {
			p_state->ActiveTextureUnit(i);
			glLoadIdentity();
		}
	}
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

/*
 *	static inline void CGLImageProc::FullscreenQuad(int n_texture_coord_num = 1,
 *		bool b_use_fullscreen_tri = false)
 *		- renders fullscreen quad
 *		- n_texture_coord_num is number of texture coordinates (for multitexturing);
 *		  texture coordinates (2D) are: (0, 1), (0, 0), (1, 0), (1, 1)
 *		- if b_use_fullscreen_tri is true, uses fullscreen triangle rather than
 *		  fullscreen quad, that might prove faster on some renderers since three
 *		  vertices are specified only (but more clipping needs to be done)
 *		- note modelview and projection matrices needs to be identity for this to
 *		  work correctly
 *		- note the primitive is drawn in immediate mode, use of display list is advised
 *		  (that might be hidden inside this function in future versions)
 */
inline void CGLImageProc::FullscreenQuad(int n_texture_coord_num, bool b_use_fullscreen_tri)
{
	if(!b_use_fullscreen_tri) {
		glBegin(GL_QUADS);
		for(int i = 0; i < n_texture_coord_num; ++ i)
			glMultiTexCoord2f(GL_TEXTURE0 + i, 0, 1);
		glVertex2f(-1,  1);
		for(int i = 0; i < n_texture_coord_num; ++ i)
			glMultiTexCoord2f(GL_TEXTURE0 + i, 0, 0);
		glVertex2f(-1, -1);
		for(int i = 0; i < n_texture_coord_num; ++ i)
			glMultiTexCoord2f(GL_TEXTURE0 + i, 1, 0);
		glVertex2f( 1, -1);
		for(int i = 0; i < n_texture_coord_num; ++ i)
			glMultiTexCoord2f(GL_TEXTURE0 + i, 1, 1);
		glVertex2f( 1,  1);
		glEnd();
	} else {
		glBegin(GL_TRIANGLES);
		for(int i = 0; i < n_texture_coord_num; ++ i)
			glMultiTexCoord2f(GL_TEXTURE0 + i, 0, 1);
		glVertex2f(-1,  1);
		for(int i = 0; i < n_texture_coord_num; ++ i)
			glMultiTexCoord2f(GL_TEXTURE0 + i, 0, -1);
		glVertex2f(-1, -3);
		for(int i = 0; i < n_texture_coord_num; ++ i)
			glMultiTexCoord2f(GL_TEXTURE0 + i, 2, 1);
		glVertex2f( 3,  1);
		glEnd(); // todo - use display list
	}
	// GL3 deprecated // todo - use vertex buffer object
}

/*
 *	static inline CGLShaderObject *CGLImageProc::p_CompileLinkReport(CGLState *p_state,
 *		const TShaderInfo *p_vs, const TShaderInfo *p_fs, bool b_exclusive)
 *		- compiles and links shaders p_vs and p_fs (one of them can be 0)
 *		  and returns new CGLShaderObject
 *		- setting b_exclusive to true disables this shader from being stored in the pool,
 *		  caller is responsible for deleting shader once it's no longer needed
 *		- reports any errors / warnings to stderr
 *		- if shader couldn't be compiled returns 0
 */
inline CGLShaderObject *CGLImageProc::p_CompileLinkReport(CGLState *p_state,
	const TShaderInfo *p_vs, const TShaderInfo *p_fs, bool b_exclusive)
{
	return p_CompileLinkReport(p_state, p_vs, 0, p_fs, b_exclusive);
}

/*
 *				=== ~CGLImageProc ===
 */

#endif // __GPU_IMAGE_PROCESSING_INLINES_INCLUDED

