
#include "Syst.hpp"

#include "CMaths.hpp"
#include "CLog.hpp"

#include "CSphere.hpp"

extern CLog c_log;

extern PFNGLMULTITEXCOORD1FARBPROC	        glMultiTexCoord1fARB    ;
extern PFNGLMULTITEXCOORD2FARBPROC	        glMultiTexCoord2fARB	  ;
extern PFNGLMULTITEXCOORD3FARBPROC	        glMultiTexCoord3fARB	  ;
extern PFNGLMULTITEXCOORD4FARBPROC	        glMultiTexCoord4fARB	  ;
extern PFNGLACTIVETEXTUREARBPROC	          glActiveTextureARB	    ;
extern PFNGLCLIENTACTIVETEXTUREARBPROC	    glClientActiveTextureARB;
extern PFNGLTEXIMAGE3DEXTPROC               glTexImage3DEXT         ;


//-----------------------------------------------------------------------------
// setVertData()
// Remplir la structure myVertex
//-----------------------------------------------------------------------------
void CSphere::setVertData(int index,
                          float tu, float tv,
                          float nx, float ny, float nz,
                          float vx, float vy, float vz )
{
    (g_VertArray+index)->tu = tu;
    (g_VertArray+index)->tv = tv;
    (g_VertArray+index)->nx = nx;
    (g_VertArray+index)->ny = ny;
    (g_VertArray+index)->nz = nz;
    (g_VertArray+index)->vx = vx;
    (g_VertArray+index)->vy = vy;
    (g_VertArray+index)->vz = vz;
}

//-----------------------------------------------------------------------------
// Init(...)
// Initialisation d'une sphere suivant la texture
// on va essayer d'élever la position de la normale
// suivant la couleur du pixel ;-)
//-----------------------------------------------------------------------------
void CSphere::Init(unsigned int id_t,
                   float cx, float cy, float cz,
                   float r,
                   int   n)
{
    float theta1 = 0.0;
    float theta2 = 0.0;
    float theta3 = 0.0;

    float ex = 0.0f;
    float ey = 0.0f;
    float ez = 0.0f;

    float px = 0.0f;
    float py = 0.0f;
    float pz = 0.0f;

    float tu  = 0.0f;
    float tv  = 0.0f;

    int i =  0;
    int j =  0;
    int k = -1;

    //-------------------------------------------------------------------------
    // If Sphere resolution is set to 4, then 20 verts will be needed to
    // hold the array of GL_QUAD_STRIP(s) and so on...
    //
    // total_verts = (n/2) * ((n+1)*2)
    // total_verts =      20
    //-------------------------------------------------------------------------

    g_nVerts   = (n/2) * ((n+1)*2);
    rayon      = r;
    id_texture = id_t;

    if( g_VertArray != 0 )
    {
        delete [] g_VertArray;
        g_VertArray = NULL;
        g_VertArray = new myVertex [g_nVerts];
    }
    else
        g_VertArray = new myVertex [g_nVerts];


    if( r < 0 )
      r = -r;

    if( n < 4 )  // taille minimale
        n = 4;

    for( j = 0; j < n/2; ++j )
    {
        theta1 = j * TWOPI / n - PIDIV2;
        theta2 = (j + 1) * TWOPI / n - PIDIV2;

        for( i = 0; i <= n; i++ )
        {
            theta3 = i * TWOPI / n;

            ex = cosf(theta2) * cosf(theta3);
            ey = sinf(theta2);
            ez = cosf(theta2) * sinf(theta3);   // Il faut elever cette position...
            px = cx + r * ex;
            py = cy + r * ey;
            pz = cz + r * ez;
            tu  = i/(float)n;
            tv  = 2*(j+1)/(float)n;

            ++k;
            setVertData( k, tu, tv, ex, ey, ez, px, py, pz );

            ex = cosf(theta1) * cosf(theta3);
            ey = sinf(theta1);
            ez = cosf(theta1) * sinf(theta3);
            px = cx + r * ex;
            py = cy + r * ey;
            pz = cz + r * ez;
            tu  = i/(float)n;
            tv  = 2*j/(float)n;

            ++k;
            setVertData( k, tu, tv, ex, ey, ez, px, py, pz );
        }
    }
}

//-----------------------------------------------------------------------------
// RenderLoop()
// Afficher notre "sphere" avec une méthode relativement lente..
//-----------------------------------------------------------------------------
void CSphere::RenderLoop() const
{
    glRotatef            (-90.0, 1.0, 0.0, 0.0);

		glBindTexture( GL_TEXTURE_2D, id_texture );
    glBegin(GL_QUAD_STRIP);
		for( GLuint i = 0; i < g_nVerts; ++i )
		{
			glNormal3f(   (g_VertArray+i)->nx,
				            (g_VertArray+i)->ny,
				            (g_VertArray+i)->nz );

			glTexCoord2f( (g_VertArray+i)->tu,
				            (g_VertArray+i)->tv );

			glVertex3f(   (g_VertArray+i)->vx,
				            (g_VertArray+i)->vy,
				            (g_VertArray+i)->vz );
		}
		glEnd();
}


//-----------------------------------------------------------------------------
// RenderWire()
// Affichage filaire
//-----------------------------------------------------------------------------
void CSphere::RenderWire() const
{
    // Par rapport à la texture
    glRotatef            (-90.0, 1.0, 0.0, 0.0);
		glDisable (GL_TEXTURE_2D);
    // On se met en mode filaire
		glPolygonMode(GL_FRONT, GL_LINE);
		// -------------------------
    glBegin(GL_QUAD_STRIP);
  		for( GLuint i = 0; i < g_nVerts; ++i )
  		{
  			glNormal3f(   (g_VertArray+i)->nx,
  				            (g_VertArray+i)->ny,
  				            (g_VertArray+i)->nz );
  
  			glTexCoord2f( (g_VertArray+i)->tu,
  				            (g_VertArray+i)->tv );
  
  			glVertex3f(   (g_VertArray+i)->vx,
  				            (g_VertArray+i)->vy,
  				            (g_VertArray+i)->vz );
  		}
		glEnd();
		glEnable (GL_TEXTURE_2D);
    // Et on remet ensuite le mode normal...
    glPolygonMode(GL_FRONT, GL_FILL);
}

//-----------------------------------------------------------------------------
// Render()
// Afficher notre "sphere" avec les VERTEX_ARRAY (les vrais ;-)
//-----------------------------------------------------------------------------
void CSphere::Render() const
{
    glRotatef            (-90.0, 1.0, 0.0, 0.0);
		glBindTexture( GL_TEXTURE_2D, id_texture );

		glInterleavedArrays( GL_T2F_N3F_V3F, 0, g_VertArray );
		glDrawArrays( GL_QUAD_STRIP, 0, g_nVerts );
}


//-----------------------------------------------------------------------------
// Clouds()
// Options des nuages
//-----------------------------------------------------------------------------
void CSphere::Clouds(unsigned int id_texture, float dist)
{
    id_nuages = id_texture;
    r_nuages  = dist;
}


//-----------------------------------------------------------------------------
// RenderAll()
// Rendre toute la scène...
//-----------------------------------------------------------------------------
void CSphere::RenderAll() const
{
    glRotatef            (-90.0, 1.0, 0.0, 0.0);

		glBindTexture                ( GL_TEXTURE_2D, id_texture );
		glInterleavedArrays          ( GL_T2F_N3F_V3F, 0, g_VertArray );
		glDrawArrays                 ( GL_QUAD_STRIP, 0, g_nVerts );

    if (r_nuages) 
    {
      glEnable                     (GL_BLEND);
      glBlendFunc                  (GL_SRC_ALPHA, GL_ZERO); // on blend sur la couche alpha pour qu'elle
  		glBindTexture                ( GL_TEXTURE_2D, id_nuages );
      glScalef                     (1.0+r_nuages,1.0+r_nuages,1.0+r_nuages);
  		glInterleavedArrays          ( GL_T2F_N3F_V3F, 0, g_VertArray );
  		glDrawArrays                 ( GL_QUAD_STRIP, 0, g_nVerts );
    }
}

//-----------------------------------------------------------------------------
// RenderCg()
// Afficher notre "sphere" avec une méthode relativement lente..
//-----------------------------------------------------------------------------
void CSphere::RenderCg() const
{
    glRotatef            (-90.0, 1.0, 0.0, 0.0);
    
    cgGLBindProgram(program);
    cgGLEnableProfile(profile);

    // OpenGL lighting must be disabled since the pixel shader
    // program will compute the lighting value
    glDisable(GL_LIGHTING);

    // The first texture unit contains the detail texture
    glActiveTextureARB(GL_TEXTURE0_ARB);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, id_texture);

    // The second texture unit contains the normalmap texture
    glActiveTextureARB(GL_TEXTURE1_ARB);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, id_normalmap);

    // Set the (fixed) ambient color value
    CGparameter ambientColorParameter = cgGetNamedParameter(program, "ambientColor");
    //cgGLSetParameter3f(ambientColorParameter, [ambientr], [ambientg], [ambientb]);
    cgGLSetParameter3f(ambientColorParameter, 0.0f, 0.0f, 0.0f);

    //for every vertex in the triangle {
    glBegin(GL_QUAD_STRIP);
		for( GLuint i = 0; i < g_nVerts; ++i ) 
    {
        // Bind the light vector to COLOR0 and interpolate
        // it across the edge
        //glColor3f([lightx], [lighty], [lightz]);
      glColor3f (0.5f,0.5f,0.5f);
	
        // Bind the texture coordinates to TEXTURE0 and
        // interpolate them across the edge
        //glMultiTexCoord2fARB(GL_TEXTURE0_ARB,
        //    [texturex], [texturey]);
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 
                    (g_VertArray+i)->tu,
				            (g_VertArray+i)->tv );
        // Bind the normalmap coordinates to TEXTURE1 and
        // interpolate them across the edge
        //glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
        //    [texturex], [texturey]);
			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,   
                    (g_VertArray+i)->tu,
				            (g_VertArray+i)->tv);

        // Specify the vertex coordinates
        //glVertex3fv([vertexx], [vertexy], [vertexz]);
			glVertex3f(   (g_VertArray+i)->vx,
				            (g_VertArray+i)->vy,
				            (g_VertArray+i)->vz );
     }
     
          
  cgGLDisableProfile(profile);
		
}



