/* tp2.c --- Colors, materials, textures, lights.
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Didier Verna
Author: Didier Verna <didier@lrde.epita.fr>
Maintainer: Didier Verna <didier@lrde.epita.fr>
Created: Tue Mar 19 19:12:37 2002
Last Revision: Wed Jan 9 19:39:50 2008
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., 675 Mass Ave, Cambridge, MA 02139, USA.
Commentary:
Contents management by FCM version 0.1.
*/
/* Code: */
#include <stdio.h>
#include <stdlib.h>
#include <GL\glut.h>
/* ========================================================================
Viewpoint management
======================================================================== */
/* TP1 Data structures and global variables needed to implement the
TP1 walker metaphore. */
/* #### Define one of the macros below to choose the walker implementation:
#### - TRIGO is a pure trigonometric solution (note: this one does not work
#### out of the box in unfilled TP),
#### - HYBRID is an OpenGL solution that mimics the trigonometric one,
#### - OPENGL is a pure OpenGL solution. */
/* #define WALKER_TRIGO 1 */
/* #define WALKER_HYBRID 1 */
#define WALKER_OPENGL 1
/* #### When using the trigonometric solution, you can further choose between
#### a raw usage of matrix computation, or usage of GLU to position the
#### viewpoint. */
#define WALKER_TRIGO_RAW 1
/* #define WALKER_TRIGO_GLU 1 */
#if defined WALKER_TRIGO
# include <math.h>
#endif
#if defined WALKER_TRIGO
/* We keep the eye coordinates on the horizontal plan (X, Z), and the global
orientation around the Y axis. */
static GLfloat eye_x, eye_z, eye_r;
#elif defined WALKER_HYBRID
/* We keep two seperate matrices for the translation and rotation amounts,
plus the rotation angle (same as eye_r above). */
static GLfloat translation_matrix[16];
static GLfloat rotation_matrix[16];
static GLfloat rotation_angle;
#elif defined WALKER_OPENGL
/* We keep a single matrix containing the current viewpoint transformation. */
static GLfloat viewpoint_matrix[16];
#else
# error No valid walker implementation selected
#endif
/* Called by keyboard_handle and main. */
static void viewpoint_reset (void)
{
/* TP1 Reset the viewpoint to the original position.
TP1 This means update the data structures choosen above.
TP1 The eye must be located at (0, 0, 30), and look down the Z axis.
*/
#if defined WALKER_TRIGO
eye_x = 0.0;
eye_z = 30.0;
/* Note that we're using an angle from the -Z axis here ... */
eye_r = 0.0;
#elif defined WALKER_HYBRID
glLoadIdentity ();
glGetFloatv (GL_MODELVIEW_MATRIX, rotation_matrix);
glTranslatef (0.0, 0.0, -30.0);
glGetFloatv (GL_MODELVIEW_MATRIX, translation_matrix);
rotation_angle = 0.0;
#elif defined WALKER_OPENGL
glLoadIdentity ();
glTranslatef (0.0, 0.0, -30.0);
glGetFloatv (GL_MODELVIEW_MATRIX, viewpoint_matrix);
#else
# error No valid walker implementation selected
#endif
}
/* Called by keyboard_handle and idle_handle.
x and z are the translation amount on both axis. */
static void viewpoint_translate (GLfloat x, GLfloat z)
{
/* TP1 Translate the viewpoint by x and z on X and Z axis.
TP1 Note that we're working in the walker's coordinate system, not
TP1 the global one. */
#if defined WALKER_TRIGO
/* The translation must be done in the walker's coordinate system, so the
global position must move accordingly. */
GLfloat cos_y = cos (eye_r * M_PI / 180.0);
GLfloat sin_y = sin (eye_r * M_PI / 180.0);
eye_x += cos_y * x + sin_y * z;
eye_z += - sin_y * x + cos_y * z;
#elif defined WALKER_HYBRID
/* That's the equivalent OpenGL solution: in order to update the translation
matrix, we need to take into account the fact that the next translation
is done in the walker's coordinate system, which includes a rotation.
*/
glLoadMatrixf (translation_matrix);
glRotatef (rotation_angle, 0.0, 1.0, 0.0);
glTranslatef (-x, 0.0, -z);
glRotatef (-rotation_angle, 0.0, 1.0, 0.);
glGetFloatv (GL_MODELVIEW_MATRIX, translation_matrix);
#elif defined WALKER_OPENGL
/* And this solution is the simplest one: the global viewpoint matrix
includes everything so we're implicitly in the walker's coordinate
system. */
glLoadIdentity ();
glTranslatef (-x, 0.0, -z);
glMultMatrixf (viewpoint_matrix);
glGetFloatv (GL_MODELVIEW_MATRIX, viewpoint_matrix);
#else
# error No valid walker implementation selected
#endif
}
/* Called by keyboard_handle and idle_handle.
a is the rotation angle around the Y axis in degrees. */
static void viewpoint_rotate (GLfloat a)
{
/* TP1 Rotate the viewpoint by a degrees around the Y axis.
TP1 Note that the Y axis is the same in the walker and and global
TP1 coordinate system. */
#if defined WALKER_TRIGO
eye_r += a;
/* Clamp the rotation angle into [0,360[. */
if (eye_r < 0.0)
eye_r += 360.0;
else if (eye_r >= 360.0)
eye_r -= 360.0;
#elif defined WALKER_HYBRID
rotation_angle += a;
glLoadMatrixf (rotation_matrix);
glRotatef (-a, 0.0, 1.0, 0.0);
glGetFloatv (GL_MODELVIEW_MATRIX, rotation_matrix);
#elif defined WALKER_OPENGL
glLoadIdentity ();
glRotatef (-a, 0.0, 1.0, 0.0);
glMultMatrixf (viewpoint_matrix);
glGetFloatv (GL_MODELVIEW_MATRIX, viewpoint_matrix);
#else
# error No valid walker implementation selected
#endif
}
/* ========================================================================
Window Management
======================================================================== */
/* Called when the window is created, and each time it is resized.
w and h are the new window width and height. */
static void window_reshape (int w, int h)
{
/* TP1 Setup the correct viewport. Use the full window for drawing. */
/* Watch out for wild casts :-) This function gets integers but glViewport
expects unsigned ! */
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
/* TP1 Setup the perspective transformation. This is needed only when
TP1 the window shape changes, not each time the window is
TP1 redisplayed. That's why we do it here.
TP1 Use a fovy of 60 degrees and clip planes at 1.0 and 1000.0 from
TP1 the eye. */
/* Put us in projection mode for setting up the perspective. And again,
watch out for wild casts. */
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (60.0, (GLdouble) w / (GLdouble) h, 1.0, 1000.0);
/* Since OpenGL is in MODELVIEW matrix mode by default, and this function is
the only place where we tweak the projection matrix, we can simply switch
back to MODELVIEW here and don't worry about that in the remainder of the
code. Also, note that instead of switching back explicitely to MODELVIEW,
we could have used:
glPushAttrib (GL_TRANSFORM_BIT);
blah blah blah
glPopAttrib (); */
glMatrixMode (GL_MODELVIEW);
}
/* ========================================================================
Scene rendering
======================================================================== */
/* Display lists for the objects we have to draw. */
static GLuint sphere_display_list;
static