

/***********************************************************************************/
/*																				   */
/*	  Copyright 2003 University of Texas at Austin                                 */
/*	  Authors: Dr C Bajaj bajaj@cs.utexas.edu,                                     */
/*             S K Vinay  skvinay@cs.utexas.edu                                    */
/*             Anthony Thane thanea@ices.utexas.edu                                */
/*																				   */
/*    This program is free software; you can redistribute it and/or modify         */
/*    it under the terms of the GNU 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 General Public License for more details.                                 */
/*																				   */
/*    You should have received a copy of the GNU 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    */
/*                                                                                 */
/***********************************************************************************/

// StickRenderer.cpp: implementation of the StickRenderer class.
//
//////////////////////////////////////////////////////////////////////

#include "StickRenderer.h"
#include "GlobalCGContext.h"
#include "cgGLCylVertexShader.h"
#include "cgGLCylFragmentShader.h"
#include "MeshCylinderRenderer.h"

using CCVImposterRenderer::StickRenderer;

bool StickRenderer::m_UseGLFallback = false;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

StickRenderer::StickRenderer( MyExtensions* extensions )
{
	initDefaults( extensions );
}

void StickRenderer::initDefaults( MyExtensions* extensions )
{
	m_Initialized = false;
	m_NumSticks = 0;
	m_Extensions = extensions;
	m_VertexProgram = 0;
	m_FragmentProgram = 0;
}

StickRenderer::~StickRenderer()
{
	if( m_FragmentProgram ) cgDestroyProgram(m_FragmentProgram);
	if( m_VertexProgram ) cgDestroyProgram(m_VertexProgram);
}

void StickRenderer::clearSticks()
{
	m_TextureCoord1.clearBuffer();
	m_TextureCoord2.clearBuffer();
	m_Color.clearBuffer();
	m_Position.clearBuffer();

	m_NumSticks = 0;
}

int StickRenderer::getNumSticks() const
{
	return m_NumSticks;
}

void StickRenderer::initRenderer( bool drawFunction )
{
        // without extensions we cannot operate at all
        if(!initExtensions()) {
                m_Initialized = false;
                fprintf(stderr, "ERROR: OpenGL extensions unavailable, update your graphics drivers.\n");
                return;
        }
        // if FP30 isn't present we will use a different branch of every render method
        if(!initCG( drawFunction )) {
                fprintf(stderr, "WARNING: FP30 not found, falling back on GL Rendering.\n");
                m_UseGLFallback = true;
        }        
	m_Initialized = true;
}

void StickRenderer::renderBuffer( bool useHardwareBuffer, bool useFunctionOnSurface, double* rotations, double* translations, int numberOfTransformations, bool randomizeColors )
{
        // MESH RENDERING
        if(m_UseGLFallback) {
                // bail if not initialized
                if (!m_Initialized) {
                        return;
                }
                
                if (m_NumSticks==0) {
                        // we are done
                        return;
                }
                
                glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT);
                
                // Set up for Stick rendering
                // cgGLEnableProfile(m_VertexProfile);
                // cgGLBindProgram(m_VertexProgram);
                
                // cgGLEnableProfile(m_FragmentProfile);
                // cgGLBindProgram(m_FragmentProgram);

                glDisable(GL_CULL_FACE);
                glEnable(GL_LIGHTING);
                glEnable(GL_ALPHA_TEST);
                glAlphaFunc(GL_GREATER, 0.5 );
                glEnable(GL_COLOR_SUM_ARB);
                
                // cgGLEnableTextureParameter(m_NormalMapParam);
                // cgGLEnableTextureParameter(m_DepthMapParam);
                
                // cgGLSetParameter4f(m_MainColorParam, 0.7f, 0.7f, 0.7f, 1.0f); // gray
                
                m_Extensions->glSecondaryColor3fEXT(0.,0.,1.);
                
                // set up multitextures
                // m_Extensions->glClientActiveTextureARB( GL_TEXTURE0_ARB );
                // glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                // glTexCoordPointer(4, GL_FLOAT, 0, m_TextureCoord1.getBuffer());
                
                // m_Extensions->glClientActiveTextureARB( GL_TEXTURE1_ARB );
                // glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                // glTexCoordPointer(4, GL_FLOAT, 0, m_TextureCoord2.getBuffer());
                
                // draw
                // glEnableClientState(GL_VERTEX_ARRAY);
                // glEnableClientState(GL_COLOR_ARRAY);
                
                ////// perform transformations if needed and repeat the rendering
                if( rotations && translations && (numberOfTransformations>0) )
                {
                        int i;
                        for( i=0; i<numberOfTransformations; i++ )
                        {
                                GLfloat trans[16];
                                trans[0]  = (GLfloat)rotations[i*9+0];
                                trans[1]  = (GLfloat)rotations[i*9+3];
                                trans[2]  = (GLfloat)rotations[i*9+6];
                                trans[3]  = (GLfloat)translations[i*3+0];
                                trans[4]  = (GLfloat)rotations[i*9+1];
                                trans[5]  = (GLfloat)rotations[i*9+4];
                                trans[6]  = (GLfloat)rotations[i*9+7];
                                trans[7]  = (GLfloat)translations[i*3+1];
                                trans[8]  = (GLfloat)rotations[i*9+2];
                                trans[9]  = (GLfloat)rotations[i*9+5];
                                trans[10] = (GLfloat)rotations[i*9+8];
                                trans[11] = (GLfloat)translations[i*3+2];
                                trans[12] = (GLfloat)0;
                                trans[13] = (GLfloat)0;
                                trans[14] = (GLfloat)0;
                                trans[15] = (GLfloat)1;			
                                // perform the rotation needed
                                glMatrixMode(GL_MODELVIEW);
                                glPushMatrix();
                                glMultMatrixf(trans);
                                
                                // cgGLSetStateMatrixParameter(m_ModelViewITParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE);
                                // cgGLSetStateMatrixParameter(m_ModelViewProjParam, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
                                // cgGLSetStateMatrixParameter(m_ModelViewParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);	
                                // cgGLSetStateMatrixParameter(m_ProjParam, CG_GL_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
                                // cgGLSetStateMatrixParameter(m_ModelViewInverseParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE);	
                                
                                // glVertexPointer(4, GL_FLOAT, 0, m_Position.getBuffer());
                                // glColorPointer(4, GL_FLOAT, 0, m_Color.getBuffer());
                                // glDrawArrays(GL_QUADS, 0, m_NumSticks*4);
                                MeshCylinderRenderer::DrawCylinderBuffer(m_Position, m_Color, m_TextureCoord1, m_TextureCoord2);
                                
                                glPopMatrix();
                        }
                }
                else
                {
                        // cgGLSetStateMatrixParameter(m_ModelViewITParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE);
                        // cgGLSetStateMatrixParameter(m_ModelViewProjParam, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
                        // cgGLSetStateMatrixParameter(m_ModelViewParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);	
                        // cgGLSetStateMatrixParameter(m_ProjParam, CG_GL_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
                        // cgGLSetStateMatrixParameter(m_ModelViewInverseParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE);	
                        
                        // glVertexPointer(4, GL_FLOAT, 0, m_Position.getBuffer());
                        // glColorPointer(4, GL_FLOAT, 0, m_Color.getBuffer());
                        // glDrawArrays(GL_QUADS, 0, m_NumSticks*4);
                        MeshCylinderRenderer::DrawCylinderBuffer(m_Position, m_Color, m_TextureCoord1, m_TextureCoord2);
                }
                
                glDisable(GL_DEPTH_TEST);
                glDisable(GL_LIGHTING);
                glDisable(GL_BLEND);
                glDisable(GL_COLOR_SUM_ARB);
                
                glPopAttrib();
        }
        // CG RENDERING
        else {
                // bail if not initialized
                if (!m_Initialized) {
                        return;
                }
                
                if (m_NumSticks==0) {
                        // we are done
                        return;
                }
                
                glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT);
                
                // Set up for Stick rendering
                cgGLEnableProfile(m_VertexProfile);
                cgGLBindProgram(m_VertexProgram);
                
                cgGLEnableProfile(m_FragmentProfile);
                cgGLBindProgram(m_FragmentProgram);
                
                glDisable(GL_CULL_FACE);
                glDisable(GL_LIGHTING);
                glEnable(GL_ALPHA_TEST);
                glAlphaFunc(GL_GREATER, 0.5 );
                glEnable(GL_COLOR_SUM_ARB);
                
                
                cgGLEnableTextureParameter(m_NormalMapParam);
                cgGLEnableTextureParameter(m_DepthMapParam);
                
                cgGLSetParameter4f(m_MainColorParam, 0.7f, 0.7f, 0.7f, 1.0f); // gray
                
                m_Extensions->glSecondaryColor3fEXT(0.,0.,1.);
                
                // set up multitextures
                m_Extensions->glClientActiveTextureARB( GL_TEXTURE0_ARB );
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                glTexCoordPointer(4, GL_FLOAT, 0, m_TextureCoord1.getBuffer());
                
                m_Extensions->glClientActiveTextureARB( GL_TEXTURE1_ARB );
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
                glTexCoordPointer(4, GL_FLOAT, 0, m_TextureCoord2.getBuffer());
                
                // draw
                glEnableClientState(GL_VERTEX_ARRAY);
                glEnableClientState(GL_COLOR_ARRAY);
                
                ////// perform transformations if needed and repeat the rendering
                if( rotations && translations && (numberOfTransformations>0) )
                {
                        int i;
                        for( i=0; i<numberOfTransformations; i++ )
                        {
                                GLfloat trans[16];
                                trans[0]  = (GLfloat)rotations[i*9+0];
                                trans[1]  = (GLfloat)rotations[i*9+3];
                                trans[2]  = (GLfloat)rotations[i*9+6];
                                trans[3]  = (GLfloat)translations[i*3+0];
                                trans[4]  = (GLfloat)rotations[i*9+1];
                                trans[5]  = (GLfloat)rotations[i*9+4];
                                trans[6]  = (GLfloat)rotations[i*9+7];
                                trans[7]  = (GLfloat)translations[i*3+1];
                                trans[8]  = (GLfloat)rotations[i*9+2];
                                trans[9]  = (GLfloat)rotations[i*9+5];
                                trans[10] = (GLfloat)rotations[i*9+8];
                                trans[11] = (GLfloat)translations[i*3+2];
                                trans[12] = (GLfloat)0;
                                trans[13] = (GLfloat)0;
                                trans[14] = (GLfloat)0;
                                trans[15] = (GLfloat)1;			
                                // perform the rotation needed
                                glMatrixMode(GL_MODELVIEW);
                                glPushMatrix();
                                glMultMatrixf(trans);
                                
                                cgGLSetStateMatrixParameter(m_ModelViewITParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE);
                                cgGLSetStateMatrixParameter(m_ModelViewProjParam, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
                                cgGLSetStateMatrixParameter(m_ModelViewParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);	
                                cgGLSetStateMatrixParameter(m_ProjParam, CG_GL_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
                                cgGLSetStateMatrixParameter(m_ModelViewInverseParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE);	
                                
                                glVertexPointer(4, GL_FLOAT, 0, m_Position.getBuffer());
                                glColorPointer(4, GL_FLOAT, 0, m_Color.getBuffer());
                                glDrawArrays(GL_QUADS, 0, m_NumSticks*4);
                                glPopMatrix();
                                
                        }
                }
                else
                {
                        cgGLSetStateMatrixParameter(m_ModelViewITParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE);
                        cgGLSetStateMatrixParameter(m_ModelViewProjParam, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
                        cgGLSetStateMatrixParameter(m_ModelViewParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);	
                        cgGLSetStateMatrixParameter(m_ProjParam, CG_GL_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
                        cgGLSetStateMatrixParameter(m_ModelViewInverseParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE);	
                        
                        glVertexPointer(4, GL_FLOAT, 0, m_Position.getBuffer());
                        glColorPointer(4, GL_FLOAT, 0, m_Color.getBuffer());
                        glDrawArrays(GL_QUADS, 0, m_NumSticks*4);
                }
                
                // disable states
                glDisableClientState(GL_VERTEX_ARRAY);
                glDisableClientState(GL_COLOR_ARRAY);
                
                m_Extensions->glClientActiveTextureARB( GL_TEXTURE1_ARB );
                glDisableClientState(GL_TEXTURE_COORD_ARRAY);
                
                m_Extensions->glClientActiveTextureARB( GL_TEXTURE0_ARB );
                glDisableClientState(GL_TEXTURE_COORD_ARRAY);
                
                cgGLDisableTextureParameter(m_DepthMapParam);
                cgGLDisableTextureParameter(m_NormalMapParam);
                
                glDisable(GL_BLEND);
                glDisable(GL_COLOR_SUM_ARB);
                
                cgGLDisableProfile(m_VertexProfile);
                cgGLDisableProfile(m_FragmentProfile); 	
                
                glPopAttrib();
        }
}
bool StickRenderer::initCG( bool drawFunction )
{
        if ( cgGLIsProfileSupported(CG_PROFILE_VP20) ) 
                m_VertexProfile = CG_PROFILE_VP20;
        else 
                return false;
        
        if ( cgGLIsProfileSupported(CG_PROFILE_FP30) ) 
                m_FragmentProfile = CG_PROFILE_FP30;
        else 
                return false;
        
        CGcontext context = GlobalCGContext::getCGContext();
        
        // Create Vertex Program for Cylinder
//	m_VertexProgram = cgCreateProgramFromFile(context, CG_SOURCE,
//		"cgGLCylVertexShader.cg", m_VertexProfile, NULL, NULL);
        m_VertexProgram = cgCreateProgram(context, CG_SOURCE,cgGLCylVertexShader,
                                          m_VertexProfile, NULL, NULL );
        
        // Load Vertex Program for Cylinder
        cgGLLoadProgram(m_VertexProgram);
        
        m_ModelViewITParam = cgGetNamedParameter(m_VertexProgram, "ModelViewIT");
        m_ModelViewInverseParam = cgGetNamedParameter(m_VertexProgram, "ModelViewInverse");
        m_ModelViewProjParam = cgGetNamedParameter(m_VertexProgram, "ModelViewProj");
        m_ModelViewParam = cgGetNamedParameter(m_VertexProgram, "ModelView");
        m_ProjParam = cgGetNamedParameter(m_VertexProgram, "Proj");
        
        if (!m_ModelViewITParam || !m_ModelViewInverseParam || !m_ModelViewProjParam || !m_ModelViewParam || !m_ProjParam) 
                //if (!m_ModelViewITParam || !m_ModelViewInverseParam || !m_ModelViewProjParam || !m_ProjParam) 
                return false;
        
        // Create Fragment Program
//	m_FragmentProgram = cgCreateProgramFromFile(context, CG_SOURCE,
//		"cgGLCylFragmentShader.cg", m_FragmentProfile, NULL, NULL);
        m_FragmentProgram = cgCreateProgram(context, CG_SOURCE,cgGLCylFragmentShader,
                                            m_FragmentProfile, NULL, NULL );
        
        // Load Fragment Program
        cgGLLoadProgram(m_FragmentProgram);
        
        m_MainColorParam = cgGetNamedParameter(m_FragmentProgram, "maincolor");
        m_NormalMapParam = cgGetNamedParameter(m_FragmentProgram, "normalmap");
        m_DepthMapParam = cgGetNamedParameter(m_FragmentProgram, "depthmap");
        
        m_TextureNormalMap = new Texture();
        m_TextureNormalMap->calculateCylinderNormalMap(512);
        
        m_TextureDepthMap = new Texture();
        m_TextureDepthMap->calculateCylinderDepthMap(512);
        
        cgGLSetTextureParameter(m_NormalMapParam, m_TextureNormalMap->getTextureID());
        cgGLSetTextureParameter(m_DepthMapParam, m_TextureDepthMap->getTextureID());
	
        return true;
}

bool StickRenderer::initExtensions()
{
        return true;
}



