/******************************************************************************
    Xplanet 0.43 - render an image of the earth into an X window
    Copyright (C) 1999 Hari Nair <hari@alumni.caltech.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

******************************************************************************/

/*
    glutfuncs.cc - OpenGL/Mesa routines to pop up a window with a globe the 
                   user can manipulate
*/

#include <stdlib.h>
#include <GL/glut.h>

#include "image.h"
#include "xplanet.h"

static GLuint Sphere;
static GLfloat range=2e6;
static GLsizei angle_theta=0, angle_phi=0;
static GLsizei glutwidth, glutheight;

static int ihelp = 0;
static int idir = 1;
static int ispeed = 2;

void 
Idle ()
{
  angle_phi = (angle_phi + idir*ispeed) % 360;
  glutPostRedisplay ();
}

void 
keyboard (unsigned char key, int x, int y)
{
  switch (key) 
    {
    case 'h':
      ihelp = 1 - ihelp;
      break;
    case 'q':
      exit (EXIT_SUCCESS);
      break;
    case 'r':
      idir *= -1;
      break;
    case '+':
      ispeed++;
      break;
    case '-':
      ispeed--;
      if(ispeed < 0) ispeed = 0;
      break;
    }
}

void 
special (int key, int x, int y)
{
  switch (key) 
    {
    case GLUT_KEY_UP:
      angle_theta = (angle_theta - 5) % 360;
      break;
    case GLUT_KEY_DOWN:
      angle_theta = (angle_theta + 5) % 360;
      break;
    case GLUT_KEY_LEFT:
      angle_phi = (angle_phi - 5) % 360;
      break;
    case GLUT_KEY_RIGHT:
      angle_phi = (angle_phi + 5) % 360;
      break;
    case GLUT_KEY_HOME:
      range /= 1.5;
      break;
    case GLUT_KEY_END:
      range *= 1.5;
      break;
    default:
      break;
    }
}

void 
printstring (void *font, char *string)
{
  int i=0;
  glColor3f (1., 1., 1.);
  while (string[i]) glutBitmapCharacter (font, string[i++]);
}

void 
Reshape (GLsizei x, GLsizei y)
{
  glutwidth=x;
  glutheight=y;
  glViewport (0, 0, glutwidth, glutheight);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  gluPerspective (0.4, 1.0, 1.0E3, -1.0E5);
  glMatrixMode (GL_MODELVIEW);
}

void 
help ()
{
  int i = int (glutwidth * 0.2);
  int j = int (glutheight * 0.2);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glOrtho (0.0, (float) glutwidth, (float) glutheight, 0.0, 0.0, 1.0);
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();
  glRasterPos2i (i, j);
  printstring (GLUT_BITMAP_HELVETICA_10, "Home/End: Move closer/farther");
  glRasterPos2i (i, j += 15);
  printstring (GLUT_BITMAP_HELVETICA_10, "Arrow keys: rotate body");
  glRasterPos2i (i, j += 15);
  printstring (GLUT_BITMAP_HELVETICA_10, "+/-: Increase/decrease rotation speed");
  glRasterPos2i (i, j += 15);
  printstring (GLUT_BITMAP_HELVETICA_10, "r: reverse rotation");
  glRasterPos2i (i, j += 15);
  printstring (GLUT_BITMAP_HELVETICA_10, "h: Toggle this help screen");
  glRasterPos2i (i, j += 15);
  printstring (GLUT_BITMAP_HELVETICA_10, "q: Quit");
  Reshape (glutwidth, glutheight);
}

void 
display ()
{
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glPushMatrix ();
  glLoadIdentity ();
  gluLookAt (range, 0., 0.,
	     0., 0., 0.,
	     0., 0., 1.);
  glRotatef (180.0, 1.0, 0.0, 0.0);
  glRotatef ((GLfloat) angle_theta, 0., 1., 0.);
  glRotatef ((GLfloat) angle_phi, 0., 0., 1.);

  glCallList (Sphere);

  glPopMatrix ();
  if (ihelp) help ();
  glutSwapBuffers ();
}

void 
Init ()
{
  GLUquadricObj *Quadric;

  GLubyte *texImage = rgb_data;

  glTexImage2D (GL_TEXTURE_2D, 0, 3, texture_width, texture_height, 0,
		GL_RGB, GL_UNSIGNED_BYTE, texImage);
  
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
  glEnable (GL_TEXTURE_2D);
  
  glEnable (GL_CULL_FACE);
  glCullFace (GL_BACK);
  
  Quadric = gluNewQuadric ();
  gluQuadricTexture (Quadric, GL_TRUE);
  
  Sphere = glGenLists (1);
  glNewList (Sphere, GL_COMPILE);
  gluSphere (Quadric, 6378.0, 48, 48);
  glEndList ();
}

void 
doAnimate( int argc, char **argv ) 
{
  glutInit (&argc, argv);
  glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  glutCreateWindow (versionstring);
  Init ();
  glutReshapeFunc ((void (*)(int, int))Reshape);
  glutDisplayFunc (display);
  glutKeyboardFunc (keyboard);
  glutIdleFunc (Idle);
  glutSpecialFunc (special);
  glutMainLoop ();
}
