// Fancy... Here we are going to create our own sphere without the use of
// GLUT. I chose to write this tutorial, because I did not like the way
// you could and could not texture the sphere created by GLUT and when
// I looked on the internet, I could not find any tutorials on it. The advantage
// of our sphere, is that we can set texture coordinates.

// ---------------------------------------------------------------------
// Section 1: Variables

// Now to start off, here are the variables we are going to be using:

// This will hold our texture
// GLuint texture[1];

// This will just hold our angle of rotation
// double angle = 0;

// This here will hold the information of all our vertices, such as
// x, y and z coordinates along with texture coordinates.
// typedef struct 
// {
// The x position of our current vertex
// int X;
// The Y position of our current vertex
// int Y;
// The Z position of our current vertex
// int Z;

// The U(x) texture coordinate of the current vertex
// double U;
// The V(x) texture coordinate of the current vertex
// double V;
// }VERTICES;

// Next we are going to use PI to convert our angles in degrees to radians.
// const double PI = 3.1415926535897;

// This here is going to determine how far apart each of our vertices are
// the further apart, the faster the program, but the squarer the sphere.
// I chose 10 because it looks nice, and runs excellent.
// const space = 10;

// This will hold out total amount of vertices.
// const VertexCount = (90 / space) * (360 / space) * 4;

// Now we set up how many vertices we are going to use.
// VERTICES VERTEX[VertexCount];

// ---------------------------------------------------------------------
// Section 2: Enabling and Creating

// Here I am enabling depth testing, texturing and face culling. The depth testing
// is so that we acctually have depth to our scene, the texturing is so that
// we can apply textures to our sphere, and culling to used to speed up the
// application. I have set the front face for culling to Counter Clock Wise, as triangle
// strips cull the opposite face to most other shapes.
// glEnable(GL_DEPTH_TEST);
// glEnable( GL_TEXTURE_2D );
// glDepthFunc(GL_LEQUAL);
// glCullFace(GL_BACK);
// glFrontFace(GL_CCW);
// glEnable(GL_CULL_FACE);

// Now we load our texture to be used. It will be stored in texture[0]
// texture[0] = LoadTextureRAW( "texture.raw" );

// Now we call to create the sphere, I do not know why it does this, but the first
// input seems to choose how many subdivisions to perform. The next lets you choose
// where to move the sphere on the x, y and z axis.
// CreateSphere(70,0,0,0);

// Now for the actual creation code. We are inputting R as the number of subdivisions,
// H as the translation on the horizontal axis, K as the translation on the vertical
// axis, and Z as the translation on the Z axis.
// void CreateSphere (double R, double H, double K, double Z) {
// Now are variables for this is as followed. n is the current vertex we are working
// with. While a and b are used to control our loops.
// int n;
// double a;
// double b;

// Set n to 0 to start off with the first vertex
// n = 0;

// Assign our b loop to go through 90 degrees in intervals of our variable space
// for( b = 0; b <= 90 - space; b+=space){
// Assign our a loop to go through 360 degrees in intervals of our variable space
// 	for( a = 0; a <= 360 - space; a+=space){

// Start editing our vertex.
// I am calculating the X value here.
// VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b) / 180 * PI) - H;
// The Y value here.
// VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b) / 180 * PI) + K;
// The Z value here.
// VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
// Now I am calculating the texture coordinates. I have used (2*b) as the texture
// is twice as wide as it is high. Hence 2:1. You can remove the (2*) if you wish
// to use a texture with the same width and height, or increase it accordingly.
// VERTEX[n].V = (2 * b) / 360;
// VERTEX[n].U = (a) / 360;
// Then start working with the next vertex
// n++;

// Then we do the same calculations as before, only adding the space variable
// to the b values.
// VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b + space) / 180 * PI) - H;
// VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b + space) / 180 * PI) + K;
// VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
// VERTEX[n].V = (2 * (b + space)) / 360;
// VERTEX[n].U = (a) / 360;
// n++;

// Then we do the same calculations as the first, only adding the space variable
// to the a values.
// VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b) / 180 * PI) - H;
// VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b) / 180 * PI) + K;
// VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
// VERTEX[n].V = (2 * b) / 360;
// VERTEX[n].U = (a + space) / 360;
// n++;

// Then we do the same calculations as the first again, only adding the space variable
// to both the b and the a values.
// VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b + space) / 180 * PI) - H;
// VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b + space) / 180 * PI) + K;
// VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
// VERTEX[n].V = (2 * (b + space)) / 360;
// VERTEX[n].U = (a + space) / 360;
// n++;

// 	}
// }
// }

// ---------------------------------------------------------------------------------
// Section 3: Displaying the Sphere

// To display the sphere I am calling this funtion which will set the size of it
// to 5 and assign the texture specified.
// DisplaySphere(5, texture[0]);

// This is the actual displaying code itself, it inputs the radius and texture
// void DisplaySphere (double R, GLuint texture){
// This variable will control which vertex we are currently working with
// int b;

// I have chosen to scale it here to 0.0125 times its original size, and then
// increase it by R as the original sphere is rather large.
// glScalef (0.0125 * R, 0.0125 * R, 0.0125 * R);
    
// Now I am rotating it because, if you run it, it is sideways :)
// glRotatef (90, 1, 0, 0);

// Now I bind the texure we inputted above.
// glBindTexture (GL_TEXTURE_2D, texture);

// Now to begin drawing the sphere itself. I am drawing it with triangle strips
// as they are the fastest shape for this.
// glBegin (GL_TRIANGLE_STRIP);
// Now I am looping through each vertex
// for ( b = 0; b <= VertexCount; b++){
// Assigning the texture coordinates of the current vertex
// glTexCoord2f (VERTEX[b].U, VERTEX[b].V);
// And the drawing the specified vertex with the Z coordinate inverted. Because
// our creation code only draws half a sphere, which is why I am also doing
// this loop again for the other half below.
// glVertex3f (VERTEX[b].X, VERTEX[b].Y, -VERTEX[b].Z);
// }

// And here I do the same as above, only this time, I invert
// the V(y) texture coordinate.
// for ( b = 0; b <= VertexCount; b++){
// glTexCoord2f (VERTEX[b].U, -VERTEX[b].V);
// glVertex3f (VERTEX[b].X, VERTEX[b].Y, VERTEX[b].Z);
// }
// Then end the shape.
// glEnd();
// }

// ---------------------------------------------------------------------------------
// And there we have it. A textured sphere without the need for GLUT

// If you have any questions, please email me at swiftless@gmail.com

#include <GL/gl.h>
#include <GL/glut.h>
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <iostream.h>

GLuint texture[1];

double angle = 0;

typedef struct 
{
int X;
int Y;
int Z;

double U;
double V;
}VERTICES;

const double PI = 3.1415926535897;

const space = 10;

const VertexCount = (90 / space) * (360 / space) * 4;

VERTICES VERTEX[VertexCount];

GLuint LoadTextureRAW( const char * filename );

void DisplaySphere (double R, GLuint texture){
int b;

glScalef (0.0125 * R, 0.0125 * R, 0.0125 * R);
    
glRotatef (90, 1, 0, 0);

glBindTexture (GL_TEXTURE_2D, texture);

glBegin (GL_TRIANGLE_STRIP);
for ( b = 0; b <= VertexCount; b++){
glTexCoord2f (VERTEX[b].U, VERTEX[b].V);
glVertex3f (VERTEX[b].X, VERTEX[b].Y, -VERTEX[b].Z);
}

for ( b = 0; b <= VertexCount; b++){
glTexCoord2f (VERTEX[b].U, -VERTEX[b].V);
glVertex3f (VERTEX[b].X, VERTEX[b].Y, VERTEX[b].Z);
}
glEnd();
}

void CreateSphere (double R, double H, double K, double Z) {
int n;
double a;
double b;

n = 0;

for( b = 0; b <= 90 - space; b+=space){
	for( a = 0; a <= 360 - space; a+=space){

VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b) / 180 * PI) - H;
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a) / 360;
n++;

VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b + space) / 180 * PI) - H;
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b + space) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a) / 360;
n++;

VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b) / 180 * PI) - H;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a + space) / 360;
n++;

VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b + space) / 180 * PI) - H;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b + space) / 180 * PI) + K;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a + space) / 360;
n++;

	}
}
}

void display (void) {
	glClearDepth(1);
	glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity(); 

	glTranslatef(0,0,-10);

	glRotatef(angle,0,1,0);
	DisplaySphere(5, texture[0]);

	glutSwapBuffers();
	angle ++;
}

void init (void) {
glEnable(GL_DEPTH_TEST);
glEnable( GL_TEXTURE_2D );
glDepthFunc(GL_LEQUAL);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
texture[0] = LoadTextureRAW( "earth.raw" );
CreateSphere(70,0,0,0);
}
void reshape (int w, int h) {
	glViewport (0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	gluPerspective (60, (GLfloat)w / (GLfloat)h, 0.1, 100.0);
	glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit (&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowSize (500, 500);
	glutInitWindowPosition (100, 100);
    glutCreateWindow ("A basic OpenGL Window");
	init();
    glutDisplayFunc (display);
	glutIdleFunc (display);
	glutReshapeFunc (reshape);
    glutMainLoop ();
    return 0;
}

GLuint LoadTextureRAW( const char * filename )
{
  GLuint texture;
  int width, height;
  unsigned char * data;
  FILE * file;

  file = fopen( filename, "rb" );
  if ( file == NULL ) return 0;

  width = 1024;
  height = 512;
  data = (unsigned char *)malloc( width * height * 3 );

  fread( data, width * height * 3, 1, file );
  fclose( file );

  glGenTextures( 1, &texture ); 

  glBindTexture( GL_TEXTURE_2D, texture );

  glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); 

  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );

  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

  gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data );

  free( data );

  return texture;

}
