/*********************************************************************
*                                                                    *          
*                              FLY                                   *
*                           --E#Y#E--   			     *
*                         ===MUSCLE===                               *
*                                                                    *
*********************************************************************/
/* Header Files */
#include "opengl.h"

/* Class */
UNIFORM uniform3;
FLYBOX box3;
CUBE cube3;
TMFONT tmfont3;
TARGA targa3;
PNG png3;
MOV mov3;
MOD mod3;
FLY fly3;
WIND wind3;

//--------------------------------------------------------------------------

PFNGLGENBUFFERSARBPROC glGenBuffers = NULL;
PFNGLBINDBUFFERPROC glBindBuffer = NULL;
PFNGLBUFFERDATAPROC glBufferData = NULL;

/* Buffer */
GLuint vbos3[MAX_BUFFERS];

/* Structure Float */
struct f_float
{
        struct f_color col;
	struct f_texture tex;
	struct f_triangles tri;
}gl;

/* Shader Program */
struct f_Shader
{
        unsigned int shaderProgram;
        unsigned int basicProgram;
        unsigned int cubeProgram;
}g;

//--------------------------------------------------------------------------

/* Motor */
bool code03;
float code1;
float code2;
float xRotation;
float zRotation;

/* Scale */
float Fplus = 1.0;
float m_scale;

/* Cube Map */
GLuint cubeMapTexID;

//--------------------------------------------------------------------------

/* Bool */
bool Fday = true;
bool Fnight = false;
bool Fcloud = false;
bool Fgrid = false;
bool Fiso = false;
bool Fwind = false;
bool Ftemp = false;
bool Fpurple = false;

//--------------------------------------------------------------------------

/* Vector */
vector<GLfloat> vcolor3;
vector<GLfloat> tcircle3;
vector<GLfloat> vcircle3;

/* Buffer */
vector<M_Color> m_colors;
vector<M_Textur> m_texCoords;
vector<M_Vertex> m_vertices;

/* Index */
vector<GLuint> m_indices;

/* Texture */
GLubyte *bla;
GLubyte *des;
GLubyte *sea;
GLubyte *sky;

//--------------------------------------------------------------------------

/* Load Texture */
void FLY::loadTexture()
{	
	#if PNG_TEXTURE
	/* Textures PNG */
	const char forestPNG[] = "PIXEL/forest.png";
	const char desertPNG[] = "PIXEL/desert.png";
	const char seaocePNG[] = "PIXEL/sea.png";
	const char cloudPNG[] = "PIXEL/cloud.png";
	
	/* Read PNG */
	png3.read_png(forestPNG, &bla);		
	png3.read_png(desertPNG, &des);
	png3.read_png(seaocePNG, &sea);
	png3.read_png(cloudPNG, &sky);
	
	/* Load Textures */
	std::cerr << " PNG TEXTURES WORLD: " << std::endl;
	#endif

	#if TARGA_TEXTURE
        /* Textures TGA */
        const char forestTGA[] = "PIXEL/forest.tga";
        const char desertTGA[] = "PIXEL/desert.tga";
        const char seaoceTGA[] = "PIXEL/sea.tga";
        const char cloudTGA[] = "PIXEL/cloud.tga";
	
	/* Load TGA */
	targa3.readTarga(forestTGA, &bla);
	targa3.readTarga(desertTGA, &des);
	targa3.readTarga(seaoceTGA, &sea);
	targa3.readTarga(cloudTGA, &sky);
	
	/* Load Textures */
	std::cerr << " TARGA TEXTURES WORLD: " << std::endl;
	#endif	
}

//--------------------------------------------------------------------------

/* GLEW Init */
void FLY::glewStatus()
{
        /* GLEW Init */
        GLenum err = glewInit();
        if(GLEW_OK != err)
        {
                fprintf(stderr," GLEW ERROR: %s \n", glewGetErrorString(err));
        }
        
        /* GLEW Version */
        fprintf(stdout," GLEW VERSION: %s \n", glewGetString(GLEW_VERSION));
        
        /* Version 130 */
        if(GLEW_VERSION_1_3)
        {
                std::cerr << " OPENGL SUPPORTED: " << std::endl;
        }
        
        /* Shader Version */
	char *shaderversion = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION); 
	if(GL_SHADING_LANGUAGE_VERSION)
	{
	        std::cout << " SHADER VERSION: " << shaderversion << std::endl;
	}
	
	/* OpenGL Version */
	char *version = (char *)glGetString(GL_VERSION); 
	if(GL_VERSION)
	{
	        std::cout << " OPENGL VERSION: " << version << std::endl;
	}
}

//---------------------------------------------------------------------------

/* Shader Language */
bool FLY::textureShader3()
{	        
        /* Fly Version */
        static const GLchar fly_vert[] = "GLSL/fly.vert";
        static const GLchar fly_frag[] = "GLSL/fly.frag";
 
        /* Create GLSL Shaders / Compile Shaders */
        uniform3.createShader(fly_vert, fly_frag);
        uniform3.createProgram(g.shaderProgram);
        /* Init */
	uniform3.Location(g.shaderProgram, 0, "a_Vertex");
	uniform3.Location(g.shaderProgram, 1, "a_TexCoord");
	uniform3.Location(g.shaderProgram, 2, "a_Color");
	/* Re link the program */
	//uniform3.linkProgram(g.shaderProgram);
        //uniform3.bindShader(g.shaderProgram);
	
        //-------------------------------------------------------------------

        /* Cube Version */
        static const GLchar cube_vert[] = "GLSL/cube.vert";
        static const GLchar cube_frag[] = "GLSL/cube.frag";

        /* Create GLSL Shaders / Compile Shaders */
        uniform3.createShader(cube_vert, cube_frag);
        uniform3.createProgram(g.cubeProgram);
	/* Init */
	uniform3.Location(g.cubeProgram, 0, "c_Vertex");
	uniform3.Location(g.cubeProgram, 1, "c_TexCoord");
	uniform3.Location(g.cubeProgram, 2, "c_Normal");
	/* Re link the program */
	uniform3.linkProgram(g.cubeProgram);
        //uniform3.bindShader(g.cubeProgram);
	
	//-------------------------------------------------------------------
 
        /* Basic Version */
        static const GLchar basic_vert[] = "GLSL/basic.vert";
        static const GLchar basic_frag[] = "GLSL/basic.frag";
 
        /* Create GLSL Shaders / Compile Shaders */
        uniform3.createShader(basic_vert, basic_frag);
        uniform3.createProgram(g.basicProgram);
        /* Init */
	uniform3.Location(g.basicProgram, 0, "b_Vertex");
	uniform3.Location(g.basicProgram, 1, "b_TexCoord");
	/* Re link the program */
	uniform3.linkProgram(g.basicProgram);
        uniform3.bindShader(g.basicProgram);
        
        return true;
}

//--------------------------------------------------------------------------

/* Init Landscape */
bool FLY::initGrid()
{	
        glGenBuffers = (PFNGLGENBUFFERSARBPROC)glXGetProcAddress
        ((const GLubyte*)"glGenBuffers");
        glBindBuffer = (PFNGLBINDBUFFERPROC)glXGetProcAddress
        ((const GLubyte*)"glBindBuffer");
        glBufferData = (PFNGLBUFFERDATAPROC)glXGetProcAddress
        ((const GLubyte*)"glBufferData");

	/* Buffer */
        if(!glGenBuffers || !glBindBuffer || !glBufferData)
        {
                std::cerr << " VBO: NOT SUPPORTED " << std::endl;
                return false;
        }
        
        //-------------------------------------------------------------------
        
        #if LAND_VECTOR
        /* Texture */
        const char forestFile[] = "DATA/forest.fs";
        const char desertFile[] = "DATA/desert.fs";
        const char seaoceFile[] = "DATA/seaoce.fs";
        const char cloudFile[] = "DATA/cloud.fs";
        
	/* Texture */
	fly3.GridRender(forestFile);
	fly3.GridRender(desertFile);
	fly3.GridRender(seaoceFile);
	fly3.GridRender(cloudFile); 
	
	//-------------------------------------------------------------------
	
	/* Grid */
        const char squareFile[] = "DATA/square.fs";
        const char gridFile[] = "DATA/grid.fs";
        const char isobarFile[] = "DATA/isobar.fs";
        const char terrainFile[] = "DATA/terrain.fs";
        const char windFile[] = "DATA/wind.fs";
        const char temperaturFile[] = "DATA/temperatur.fs";
	
	/* Grid */
	fly3.GridRender(squareFile);
	fly3.GridRender(isobarFile);
	fly3.GridRender(terrainFile);
	fly3.GridRender(gridFile);
	fly3.GridRender(windFile);
	fly3.GridRender(temperaturFile);
	#endif

        //-------------------------------------------------------------------

	/* Create Color Buffer */
	glGenBuffers(MAX_BUFFERS, &vbos3[0]);
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[COLOR_BUFFER]); 
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * AV, &m_colors[0], GL_STATIC_DRAW);

	/* Create Texture Buffer */ 
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[NORMAL_BUFFER]); 
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 2 * AV, &m_texCoords[0], GL_STATIC_DRAW);

        /* Create Vertex Buffer */        
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[VERTEX_BUFFER]); 
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * AV, &m_vertices[0], GL_STATIC_DRAW);
        
        //-------------------------------------------------------------------
        
        /* Create Element Buffer */
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos3[INDEX_BUFFER]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * 3 * AV, &m_indices[0], GL_STATIC_DRAW);
        
        return true;
}

//--------------------------------------------------------------------------

/* Main Init */
bool FLY::initMain()
{
	/* Background Color */
	glEnable(GL_BLEND);
	glEnable(GL_AMBIENT);
	glEnable(GL_LIGHT7);
	glEnable(GL_LIGHTING);	
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_SCISSOR_TEST);
	glEnable(GL_COLOR_MATERIAL);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	//-------------------------------------------------------------------
	
	/* Night */
	if(Fnight)
	{	
		glClearColor( 0.10f , 0.20f , 0.30f , 0.5f );
		glDisable(GL_LIGHT7);
	}
	/* Day */
	else if(Fday)
	{	
		glClearColor( 0.30f , 0.50f , 0.70f , 0.5f );
		glDisable(GL_LIGHTING);
	}
	/* Grid */
	else
	{	
		glClearColor( 0.01f , 0.01f , 0.01f , 0.5f );
		glDisable(GL_LIGHTING);
	}
	        
        //-------------------------------------------------------------------
        
        /* Clear everything */
        glClearDepth(1.0); 
        
        /* Enable */
        glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        
        /* Viewport */
        GLint viewport[4];
        glGetIntegerv(GL_VIEWPORT, viewport);
        // Viewport[2] stores the width of the viewport, vieport[3] stores the height
        // We pass these into our font so the ortho mode can set the resolution for the window 
        tmfont3.TMFont("FONT/mono.tga", viewport[2], viewport[3], 25.0f);
            
        //-------------------------------------------------------------------
        
        /* Initialize the Font */
        if(!tmfont3.initFont()) 
        {
                std::cerr << " COULD NOT INITIALIZE THE FONT " << std::endl; 
                return false;
        }
        /* Initialize the Flybox */
        if(!box3.initBox()) 
        {
                std::cerr << " COULD NOT INITIALIZE THE FLYBOX " << std::endl; 
                return false;
        }
        /* Initialize the Cockpit */
        if(!mod3.initCockpit()) 
        {
                std::cerr << " COULD NOT INITIALIZE THE COCKPIT " << std::endl; 
                return false;
        }
        /* Initialize the Grid */
        if(!fly3.initGrid()) 
        {
                std::cerr << " COULD NOT INITIALIZE THE GRID " << std::endl; 
                return false;
        }
        /* Initialize the Shader */
        if(!fly3.textureShader3()) 
        {
                std::cerr << " COULD NOT INITIALIZE THE SHADER " << std::endl; 
                return false;
        }
        
        return true;
}

//--------------------------------------------------------------------------

/* X / Y / Z / W */
float FLY::F_Vertex(float fx, float fy, float fz)
{
        float vcircle3[3];
        
        vcircle3[0] = 0;
        vcircle3[1] = 0; 
        vcircle3[2] = 0;
        
        vcircle3[0] = fx;
        vcircle3[1] = fy; 
        vcircle3[2] = fz;
        
        return *vcircle3;      
}

//--------------------------------------------------------------------------

/* R / G / B / A */
float FLY::F_Color(float fr, float fg, float fb, float fa) 
{
        float vcolor3[4];
        
        vcolor3[0] = 0;
        vcolor3[1] = 0; 
        vcolor3[2] = 0;
        vcolor3[3] = 0;
        
        vcolor3[0] = fr;
        vcolor3[1] = fg; 
        vcolor3[2] = fb;
        vcolor3[3] = fa;
        
        return *vcolor3;         
}

//--------------------------------------------------------------------------

/* S / T / P / Q */
float FLY::F_Textur(float fs, float ft)
{
        float tcircle3[2];
        
        tcircle3[0] = 0;
        tcircle3[1] = 0;

        tcircle3[0] = fs;
        tcircle3[1] = ft;
        
        return *tcircle3;      
}

//--------------------------------------------------------------------------

/* Render Grid */
void FLY::GridRender(const char *nFile)
{
        char code[ID];
	int world = 0;
	int counter = 0;
        const float pt = 0.05;
        
        /* Load File */
	FILE *grid;
	grid=fopen(nFile,"r");
	      
        /* Grid File */
	while((fscanf(grid,"%s  %f %f %f %f  %f %f  %f %f %f", &code[0], 
	        &gl.col.r, &gl.col.g, &gl.col.b, &gl.col.a,
	        &gl.tex.s, &gl.tex.t, &gl.tri.x, &gl.tri.y, &gl.tri.z)) != EOF)
	{ 	
	        /* Counter */
		counter++;
	
		#if LAND_VECTOR
	        /* MASSTAB */
	        m_scale = (gl.tri.z * Fplus) * pt;
	        m_scale = (gl.tri.y * Fplus) * pt; 
		m_scale = (gl.tri.x * Fplus) * pt; 

                /* VERTEX */
                m_colors.push_back(M_Color(gl.col.r, gl.col.g, gl.col.b, gl.col.a));
                m_texCoords.push_back(M_Textur(gl.tex.s, gl.tex.t));
	        m_vertices.push_back(M_Vertex(gl.tri.x, gl.tri.y, gl.tri.z));  
	       
	       	/* VECTOR */
		//m_vertices.push_back(gl.tri.x);  
	        //m_vertices.push_back(gl.tri.y);
	        //m_vertices.push_back(gl.tri.z);
	       
	        /* ELEMENTS */
	        m_indices.push_back(world++);
	        m_indices.push_back(world++);
	        m_indices.push_back(world++);
		#else
	
		/* MASSTAB */
		gl.tri.x = (gl.tri.x * Fplus); 
	        gl.tri.y = (gl.tri.y * Fplus); 
	        gl.tri.z = (gl.tri.z * Fplus);
	
		/* ARRAY */
		glColor4f(gl.col.r, gl.col.g, gl.col.b, gl.col.a);
		glTexCoord2f(gl.tex.s, gl.tex.t);
		glScalef(gl.tri.x, gl.tri.y, gl.tri.z);
		glVertex3f(gl.tri.x, gl.tri.y, gl.tri.z);
		#endif
	}
	
	/* Buffer Counter */
	//std::cout << " BUFFER WORLD: " << counter << std::endl;
        
        /* Close File */
	fclose(grid);
}

//--------------------------------------------------------------------------

/* Polygon Mode */
void FLY::PolygonCircle(const GLenum mode, const GLenum front, const char *nFile)
{
	glPolygonMode(GL_FRONT_AND_BACK, front); 
	glBegin(mode);
	fly3.GridRender(nFile);
	glEnd();
}

//-------------------------------------------------------------------------

/* Draw Arrays */
void FLY::DrawCircle(const GLenum mode, const GLenum front, const GLint count, const GLint offset)
{
        //glTranslatef(0.0, 0.0, -code1);
        glPolygonMode(GL_FRONT_AND_BACK, front);
        //glDrawArrays(GL_LINES, 888, 888);
        glPushMatrix();
        
        /* Masstab */
        glScalef(m_scale, m_scale, m_scale);
        
        /* Move Line */
        //glRotatef(xRotation, 1.0f, 0.0f, 0.0f);
	//glRotatef(zRotation, 0.0f, 0.0f, 1.0f); 
        
	#if DRAW_ELEMENTS
	glDrawElements(mode, count, GL_UNSIGNED_INT, 0);
	#else
	glDrawArrays(mode, offset, count);
	//glDrawArrays(GL_LINES, 3480, 3480);
	#endif
	glPopMatrix();
}

//--------------------------------------------------------------------------

/* Render Landscape */
void FLY::SubImage(const GLint count, const char *nFile, GLubyte *pixel)
{
        /* Enable Texture */
	glEnable(GL_TEXTURE_2D);
	
	/* Filtering Mode */
	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        
        /* Image Data */
        glTexImage2D(GL_TEXTURE_2D,
                     0,                      // level
                     GL_RGBA8,               // internal format
                     128,                    // width
                     128,                    // height
                     0,                      // border
                     GL_BGRA,                // format
                     GL_UNSIGNED_SHORT,      // type
                     pixel                   // data
        ); 
        
	glTexSubImage2D(GL_TEXTURE_2D,0,0,0,128,128,GL_BGRA,GL_UNSIGNED_SHORT,pixel);	
	glTexSubImage2D(GL_TEXTURE_2D,0,2,0,128,128,GL_BGRA,GL_UNSIGNED_SHORT,pixel);
	glTexSubImage2D(GL_TEXTURE_2D,0,0,2,128,128,GL_BGRA,GL_UNSIGNED_SHORT,pixel);
	glTexSubImage2D(GL_TEXTURE_2D,0,2,2,128,128,GL_BGRA,GL_UNSIGNED_SHORT,pixel);

	#if LAND_VECTOR
	fly3.DrawCircle(GL_TRIANGLES, GL_FILL, count, 0);
        #else
	fly3.PolygonCircle(GL_TRIANGLES, GL_FILL, nFile);
	#endif

	/* Disable Texture */
	glDisable(GL_TEXTURE_2D);
}

//--------------------------------------------------------------------------

/* Point Speed */
void FLY::pointSpeed(float dt)
{
        const float xSpeed = 20.0f;
        const float ySpeed = 60.0f;
        
        xRotation += xSpeed * dt;
        zRotation += ySpeed * dt;
        
        if(xRotation > 360.0f) { 
           xRotation -= 360.0f;
        }
        if(zRotation > 360.0f) { 
           zRotation -= 360.0f;
        }
}

//--------------------------------------------------------------------------

/* Point Grid */
void FLY::pointGrid(float dt)
{
        float speed = 0.2f;
        float maxSpeed = +90.0f;
        float minSpeed = -90.0f; 
        
        /* Speed */
        fly3.pointSpeed(dt);
        
        /* Line */  
        if(code03)
        {
                  code1 += speed;
                  code2 -= speed;
        }
        else
        {
                  code1 -= speed;
                  code2 += speed;
        }
        
        /* Limit */ 
        if(code1 >= maxSpeed)
        {
                  code03 = false;
        }
        else if(code1 <= minSpeed)
        {
                  code03 = true;
        }
}

//-------------------------------------------------------------------------

/* Moving Objects */
void FLY::vectorObjects() 
{        
	/* Primitive */
        const GLenum modeP = GL_POINTS;
        const GLenum modeL = GL_LINES;
        const GLenum modeT = GL_TRIANGLES;
        
        /* Mode */
        const GLenum frontP = GL_POINT;
        const GLenum frontL = GL_LINE;
        const GLenum frontF = GL_FILL;

        //-------------------------------------------------------------------

	/* Offset */
        const GLint squareOffset =  888;     //  900 
        const GLint isobarOffset = 1752;     // 1800 
        const GLint terrainOffset = 2616;    // 2700 
        const GLint gridOffset = 3480;       // 3600
        const GLint windOffset = 4344;       // 4500 
        const GLint tempOffset = 5208;       // 5300 
                
        /* Count */
        const GLint countP = 864;       // 864
        const GLint countL = 864;       // 864
        const GLint countT = 864;       // 864
        
        //-------------------------------------------------------------------

        /* Size */
        float lineWidth = 3.0f;
        float pointSize = 7.0f;
      
	/* Enable Anti-aliasing */
        glEnable(GL_POINT_SMOOTH);
        glLineWidth(lineWidth);
        glPointSize(pointSize);
        
        //-------------------------------------------------------------------

	/* Terrain */
	if(Fgrid || Fiso) 
	{
	        fly3.DrawCircle(modeP, frontP, countP, squareOffset);
	        fly3.DrawCircle(modeL, frontL, countL, gridOffset);
	        fly3.DrawCircle(modeT, frontF, countT, terrainOffset);
	        
	        /* Isobar */
	        if(Fiso) 
	        {
	                fly3.DrawCircle(modeP, frontP, countP, isobarOffset);
	                fly3.DrawCircle(modeT, frontL, countL, isobarOffset);
	                fly3.DrawCircle(modeT, frontF, countT, isobarOffset);
	        } 
	}
	/* Wind */
	else if(Fwind) 
	{
	        fly3.DrawCircle(modeP, frontP, countP, squareOffset);
	        glEnable(GL_CULL_FACE);
	        fly3.DrawCircle(modeT, frontF, countL, gridOffset);
	        glDisable(GL_CULL_FACE);
	        fly3.DrawCircle(modeT, frontF, countT, windOffset); 
	}
	/* Celsius */
	else if(Ftemp) 
	{
	        fly3.DrawCircle(modeP, frontP, countP, squareOffset);
	        fly3.DrawCircle(modeT, frontL, countL, gridOffset); 
	        fly3.DrawCircle(modeT, frontF, countT, tempOffset); 
	}
	
	//-------------------------------------------------------------------
	
	/* Disable Anti-aliasing */
        glDisable(GL_POINT_SMOOTH);
}

//--------------------------------------------------------------------------

/* Moving Objects */
void FLY::polygonObjects() 
{
	/* Primitive */
        const GLenum modeP = GL_POINTS;
        const GLenum modeL = GL_LINES;
        const GLenum modeT = GL_TRIANGLES;
        
        /* Mode */
        const GLenum frontP = GL_POINT;
        const GLenum frontL = GL_LINE;
        const GLenum frontF = GL_FILL;

        //-------------------------------------------------------------------

        /* Grid */
        const char squareFile[] = "DATA/square.fs";
        const char gridFile[] = "DATA/grid.fs";
        const char isobarFile[] = "DATA/isobar.fs";
        const char terrainFile[] = "DATA/terrain.fs";
        const char windFile[] = "DATA/wind.fs";
        const char temperaturFile[] = "DATA/temperatur.fs";

        //-------------------------------------------------------------------

        /* Size */
        float lineWidth = 3.0f;
        float pointSize = 7.0f;
      
	/* Enable Anti-aliasing */
        glEnable(GL_POINT_SMOOTH);
        glLineWidth(lineWidth);
        glPointSize(pointSize);
        
        //-------------------------------------------------------------------

        /* Terrain */
	if(Fgrid || Fiso) 
	{
	        fly3.PolygonCircle(modeP, frontP, squareFile);
	        fly3.PolygonCircle(modeL, frontL, gridFile);       
	        fly3.PolygonCircle(modeT, frontF, terrainFile); 
	        
	        /* Isobar */
	        if(Fiso) 
	        {
	                fly3.PolygonCircle(modeP, frontP, isobarFile);
	                fly3.PolygonCircle(modeT, frontL, isobarFile);
	                fly3.PolygonCircle(modeT, frontF, isobarFile); 
	        }
        }
	/* Wind */
	else if(Fwind) 
	{ 
	        fly3.PolygonCircle(modeP, frontP, squareFile);
	        glEnable(GL_CULL_FACE);
	        fly3.PolygonCircle(modeT, frontF, gridFile);
	        glDisable(GL_CULL_FACE);
	        fly3.PolygonCircle(modeT, frontF, windFile); 
	}
	/* Fahrenheit */
	else if(Ftemp) 
	{ 
	        fly3.PolygonCircle(modeP, frontP, squareFile);
	        fly3.PolygonCircle(modeT, frontL, gridFile);
	        fly3.PolygonCircle(modeT, frontF, temperaturFile); 
	}
	  
	//-------------------------------------------------------------------
	  
	/* Disable Anti-aliasing */
        glDisable(GL_POINT_SMOOTH);
}

//--------------------------------------------------------------------------

/* Moving Objects */
void FLY::textureObjects() 
{
        int PIX = 4;
        GLuint texID[EV];

        /* Basic Program */
        uniform3.linkProgram(g.basicProgram);
        uniform3.bindShader(g.basicProgram);
        uniform3.Uniform(g.basicProgram, "texture1", 0);

	/* Generate Textures */
	glGenTextures(PIX, texID);
	glBindTexture(GL_TEXTURE_2D_ARRAY, texID[PIX]);

        //-------------------------------------------------------------------

        /* Texture */
        const char forestFile[] = "DATA/forest.fs";
        const char desertFile[] = "DATA/desert.fs";
        const char seaoceFile[] = "DATA/seaoce.fs";
        const char cloudFile[] = "DATA/cloud.fs";

	/* Count */
	const GLint countF = 288;       // 288
        const GLint countD = 672;       // 384
        const GLint countS = 864;       // 192
	const GLint countC = 888;       //  24
	
	//-------------------------------------------------------------------

	/* Landscape */
	if(Fnight || Fday || Fcloud)
	{
	        /* SubImage */
	        fly3.SubImage(countF, forestFile, bla);
	        fly3.SubImage(countD, desertFile, des);
	        fly3.SubImage(countS, seaoceFile, sea);

                /* Cloud */
	        if(Fcloud)
	        {
	                /* Translate / Rotate */
	                //glTranslatef(0.0, 0.0, -code1);
	                //glRotatef(-code1, 0.0f, 1.0f, 0.0f);
	                //glRotatef(-code2, 0.0f, 0.0f, 0.0f); 	        
	                         
	                /* Cloud File */
	                fly3.SubImage(countC, cloudFile, sky);
	        }
        }

	/* Delete Textures */
	glDeleteTextures(PIX, texID);
}

//--------------------------------------------------------------------------

/* Render Objects */
void FLY::vertexObjects() 
{  
        /* Active Texture */
	//glActiveTextureARB(GL_TEXTURE5_ARB + PIX);
	//glClientActiveTextureARB(GL_TEXTURE5_ARB); 
 
        /* Attrib Array */
	glEnableVertexAttribArrayARB(0); 
    	glEnableVertexAttribArrayARB(1);
	glEnableVertexAttribArrayARB(2);
         
	//-------------------------------------------------------------------

        /* Bind Color Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[COLOR_BUFFER]);

        /* Color */
        const GLint csize = 3;                      // ( R, G, B, A)
        const GLenum ctype = GL_FLOAT;              // the data is 8bit unsigned values
        const GLboolean cnormalize = false;         // normalize the data (convert from 0-255 to 0-1)
        const GLsizei cstride = 0;                  // 0 = move forward size * sizeof(type)
        const GLbyte coffset = 0;                   // start at the beginning of the buffer

        glVertexAttribPointerARB((GLuint)2, csize, ctype, cnormalize, cstride, &vcolor3[coffset]);
	
	//-------------------------------------------------------------------

        /* Bind Vertex Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[VERTEX_BUFFER]);

        /* Vertex */
        const GLint vsize = 3;			    // ( X, Y, Z, W )
        const GLenum vtype = GL_FLOAT;
        const GLboolean vnormalize = false;
        const GLsizei vstride = 0;
        const GLbyte voffset = 0;

        glVertexAttribPointerARB((GLuint)0, vsize, vtype, vnormalize, vstride, &vcircle3[voffset]);
        
        //-------------------------------------------------------------------
        
        /* Bind Normal Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[NORMAL_BUFFER]);

        /* Texture */
        const GLint tsize = 2;			    // ( S, T, P, Q )
        const GLenum ttype = GL_FLOAT;
        const GLboolean tnormalize = false;
        const GLsizei tstride = 0;
        const GLbyte toffset = 0;

        glVertexAttribPointerARB((GLuint)1, tsize, ttype, tnormalize, tstride, &tcircle3[toffset]);

        //-------------------------------------------------------------------
        
        /* Objects */
        #if LAND_VECTOR
        fly3.vectorObjects();
        #else
        fly3.polygonObjects();
        #endif
        fly3.textureObjects();
	
	//-------------------------------------------------------------------

        /* Disable Array */
        glDisableVertexAttribArrayARB(2);
        glDisableVertexAttribArrayARB(1);
        glDisableVertexAttribArrayARB(0);
        
	/* Active Texture 0 */
	//glActiveTextureARB(GL_TEXTURE0_ARB);
	//glClientActiveTextureARB(GL_TEXTURE0_ARB);
}

//--------------------------------------------------------------------------

/* Render Objects */
void FLY::renderObjects() 
{  
	/* Vertex Array */
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);	
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
         
	//-------------------------------------------------------------------

        /* Bind Color Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[COLOR_BUFFER]);

        /* Color */
        const GLint csize = 4;                      // ( R, G, B, A)
        const GLenum ctype = GL_FLOAT;              // the data is 8bit unsigned values
        const GLsizei cstride = 0;                  // 0 = move forward size * sizeof(type)
        const GLbyte coffset = 0;                   // start at the beginning of the buffer

        glColorPointer(csize, ctype, cstride, &vcolor3[coffset]);
	
	//-------------------------------------------------------------------

        /* Bind Vertex Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[VERTEX_BUFFER]);

        /* Vertex */
        const GLint vsize = 3;			    // ( X, Y, Z, W )
        const GLenum vtype = GL_FLOAT;
        const GLsizei vstride = 0;
        const GLbyte voffset = 0;

        glVertexPointer(vsize, vtype, vstride, &vcircle3[voffset]);
        
        //-------------------------------------------------------------------
        
        /* Bind Normal Buffer */
        glBindBuffer(GL_ARRAY_BUFFER, vbos3[NORMAL_BUFFER]);

        /* Texture */
        const GLint tsize = 2;			    // ( S, T, P, Q )
        const GLenum ttype = GL_FLOAT;
        const GLsizei tstride = 0;
        const GLbyte toffset = 0;

        glTexCoordPointer(tsize, ttype, tstride, &tcircle3[toffset]);

        //-------------------------------------------------------------------
        
        /* Objects */
        #if LAND_VECTOR
        fly3.vectorObjects();
        #else
        fly3.polygonObjects();
        #endif
        fly3.textureObjects();
	
	//-------------------------------------------------------------------
        
	/* Disable Client State */
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);
}

//--------------------------------------------------------------------------

/* Render Landscape */
void FLY::Landscape(int width, int height)
{ 
	/* Matrix */
	float modelview3[ID];
        float projection3[ID];

        /* Texture */
        glDisable(GL_SCISSOR_TEST);

	/* Render Triangles */
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	
	/* PlaneView */
	mov3.CameraLook();
	mov3.PlaneView();
	
	//------------------------------------------------------------------
	
	/* Font */
	tmfont3.printString("VULKANO:", 110, 25);
	
	//------------------------------------------------------------------
	
	/* Passing Data */
	glGetFloatv(GL_PROJECTION_MATRIX, projection3);
	glGetFloatv(GL_MODELVIEW_MATRIX, modelview3);
	
	/* Matrix */
	uniform3.Uniform4x4(g.shaderProgram, "projection_matrix", 0, projection3);
        uniform3.Uniform4x4(g.shaderProgram, "modelview_matrix", 1, modelview3);
		
	//*************************************************************
        // Draw the plane with stencil on
        //*************************************************************

        /* Enable Depth */
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_STENCIL_TEST);    //Enable stenciling
        glDepthMask(GL_FALSE);        //Disable depth writes
        glDepthFunc(GL_LESS);

        /* Always replace the stencil value whether it passes or fails */
        glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

        /* Make the test always pass */
        glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
        
        /* Flybox */
        box3.initBox();
	box3.render(0, 0, 0, g.basicProgram);
	
	/* Re-enable depth writes */
        glDepthMask(GL_TRUE);

        //*************************************************************
        // Draw the sphere's reflection, with blending and stencil testing
        //*************************************************************
	
	/* Cube Program */
        uniform3.bindShader(g.cubeProgram);
        uniform3.sendUniform3f(g.cubeProgram, "camera_position", 0.0f, 0.0f, 0.0f);
        uniform3.Uniform(g.cubeProgram, "texture2", 0);
        
        /* Cube Map */
        glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMapTexID);
        
        /* Only render where the stencil value is 1 */
        glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
        /* Don’t change the stencil values any more */
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

        /* Purple Look */
        if(Fpurple)
        {
                glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);
        }
        
        /* Render Objects */
        #if VERTEX_LAND
        fly3.vertexObjects(); 
	#else
	fly3.renderObjects(); 
	#endif
	
	//-------------------------------------------------------------------
	
	/* Shader Program */	
	uniform3.linkProgram(g.shaderProgram);            // Re link the program 
        uniform3.bindShader(g.shaderProgram);             // Enable our shader 
	uniform3.Uniform(g.shaderProgram, "texture0", 0);

        /* Disable the stencil test */
        glDisable(GL_STENCIL_TEST);

        //*************************************************************
        // Draw the sphere normal
        //*************************************************************

	/* Render Objects */
	#if VERTEX_LAND
	fly3.vertexObjects();
	#else
	fly3.renderObjects(); 
	#endif
	
	/* Cube Map */
	#if CUBE_MAP
	fly3.CubeMap();
	#endif
	
	//-------------------------------------------------------------------

        /* Delete Buffer */
        glDeleteBuffers(MAX_BUFFERS, &vbos3[0]);

        /* Delete Shader */
        uniform3.DeleteShader(g.shaderProgram);
        uniform3.DeleteShader(g.cubeProgram);
        uniform3.DeleteShader(g.basicProgram);
	
	/* Disable */
	glDisable(GL_COLOR_MATERIAL);
	glDisable(GL_LIGHTING);
	glDisable(GL_AMBIENT);
	glFlush();
}

//---------------------------------------------------------------------------

/* Render Landscape */
void FLY::CubeMap()
{  
        int TEX = 0;
  
        /* Clear */
        glClear(GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();

        /* Begin Box */
        cube3.beginCubeMapRendering(256);
        glEnable(GL_SCISSOR_TEST);
 
        /* Number of Texture */
        for(TEX = 0; TEX < 6; ++TEX) 
        {        
                /* Cube Render */
                cube3.beginCubeMapFace(TEX);
                        
                /* Flybox */
                box3.initBox();
                box3.render( 0, 0, 0, g.basicProgram);
                     
                /* Translate Y-Achse */
	        glTranslatef(0.0f, 2.0f, 0.0f);
                     
                /* Render Objects */
                #if VERTEX_LAND
                fly3.vertexObjects();
                #else
                fly3.renderObjects();
                #endif
                cube3.finishCubeMapFace(TEX, 256);
        }
        
        /* End Box */
        cube3.endCubeMapRendering();
        glDisable(GL_SCISSOR_TEST);
}

//---------------------------------------------------------------------------

/* Process Event */
void FLY::process_event1(XEvent report)
{ 
	KeySym key;
	key = XLookupKeysym (&report.xkey, 0);
	
	/* Keyboard Control Keys */
	switch(key)
	{
	        /* GRID */
		case XK_F1: 
		Fday = false; Fnight = false; Fcloud = false;
                Fgrid = true; Fiso = false; Fwind = false; Ftemp = false;
		break;
		case XK_F2: 
		Fday = false; Fnight = false; Fcloud = false;
                Fgrid = true; Fiso = true; Fwind = false; Ftemp = false;
		break;
		case XK_F3: 
		Fday = false; Fnight = false; Fcloud = false;
                Fgrid = false; Fiso = false; Fwind = true; Ftemp = false;
		break;
		case XK_F4: 
		Fday = false; Fnight = false; Fcloud = false;
                Fgrid = false; Fiso = false; Fwind = false; Ftemp = true;
		break;
	
	        /* TEXTURE */
		case XK_F5: 
		Fday = true; Fnight = false; Fcloud = false;
                Fgrid = false; Fiso = false; Fwind = false; Ftemp = false;
		break;
		case XK_F6:
		Fday = true; Fnight = false; Fcloud = true;
                Fgrid = false; Fiso = false; Fwind = false; Ftemp = false;
		break;
		case XK_F7:
		Fday = false; Fnight = true; Fcloud = false;
                Fgrid = false; Fiso = false; Fwind = false; Ftemp = false;
		break;
		
		/* CLEAR */
		case XK_F8: 
                Fday = false; Fnight = false; Fcloud = false;
                Fgrid = false; Fiso = false; Fwind = false; Ftemp = false;
                break;
		
		/* PURPLE */
		case XK_F9: Fpurple = true; break;
		case XK_F10: Fpurple = false; break;
		
		/* MASSTAB */
		case XK_i: Fplus += plus; break;
		case XK_o: Fplus -= minus ; break;
                
		case XK_Escape: 
		wind3.closeWin(); 
		break;
	}
}

//---------------------------------------------------------------------------

