Example 12

Example 12

This OpenGL program displays the sun, earth, and moon as cubes and animates them so that the sun rotates in the middle, the earth spins on its axis and revolves around the sun, and the moon spins and revolves around the earth. The camera uses the same arcball method as that in example 06.

ex_12/orbit.png

Source Code

orbit.cc:

// Peter Bui
// CSE 40166 Computer Graphics (Fall 2010)
// Example 12: orbit
 
#include <cmath>
#include <cstdio>
#include <cstdlib>

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

using namespace std;

// Constants -------------------------------------------------------------------

#define WHEEL_UP    3
#define WHEEL_DOWN  4

#define CAMERA_DISTANCE_MIN  50.0
#define CAMERA_DISTANCE_MAX 500.0

// Global variables ------------------------------------------------------------

static size_t WindowWidth  = 640;
static size_t WindowHeight = 480;

static GLint  MouseX = 0;
static GLint  MouseY = 0;

static double CameraLatitude  = 45.0; 
static double CameraLongitude = 25.0;
static double CameraDistance  = 175.0;

static double EyeX = -100.0;
static double EyeY = 50.0;
static double EyeZ = 100.0;

static double SunAngle = 0.0;
static double SunScale = 25.0;

static double EarthRevAngle  = 0.0;
static double EarthSpinAngle = 0.0;
static double EarthScale     = 10.0;
static double EarthDistance  = 2.0 * SunScale;

static double MoonRevAngle  = 0.0;
static double MoonSpinAngle = 0.0;
static double MoonScale     = 2.5;
static double MoonDistance  = 1.25 * EarthScale;

static GLint FrameRate = 30;

static bool AnimationOn = true;

// Update camera ---------------------------------------------------------------

void
update_camera_location()
{
    // Based on some magical math:
    // http://en.wikipedia.org/wiki/List_of_canonical_coordinate_transformations#From_spherical_coordinates
    // and some help from Dr. John Stewman

    double L = CameraDistance * cos(M_PI*CameraLongitude/180.0);

    EyeX = L * -sin(M_PI*CameraLatitude/180.0);
    EyeY = CameraDistance * sin(M_PI*CameraLongitude/180.0);
    EyeZ = L * cos(M_PI*CameraLatitude/180.0);

    glutPostRedisplay();
}

// Initialize scene ------------------------------------------------------------

void
init_scene()
{
    glEnable(GL_DEPTH_TEST);

    glViewport(0, 0, WindowWidth, WindowHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (GLdouble)WindowWidth/(GLdouble)WindowHeight, 1.0, 750.0);

    glMatrixMode(GL_MODELVIEW);
    
    GLfloat diffuse0[]  = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat ambient0[]  = { 0.7, 0.7, 0.7, 1.0 };

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);

    glEnable(GL_COLOR_MATERIAL) ;
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

    update_camera_location();
}

// Display callback ------------------------------------------------------------

void
display()
{
    GLfloat position0[] = { EyeX, EyeY, EyeZ, 1.0 };

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLightfv(GL_LIGHT0, GL_POSITION, position0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(EyeX, EyeY, EyeZ, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    // Sun cube
    glColor3f(0.9, 0.3, 0.0);
    glPushMatrix(); {
        glRotatef(SunAngle, 0.0, 1.0, 0.0);
        glScalef(SunScale, SunScale, SunScale);
        glutSolidCube(1.0);
    } glPopMatrix();
    
    // Earth cube
    glColor3f(0.0, 0.4, 0.8);
    glPushMatrix(); {
        glRotatef(EarthRevAngle, 0.0, 1.0, 0.0);
        glTranslatef(EarthDistance, 0.0, EarthDistance);

        glPushMatrix(); {
            glRotatef(EarthSpinAngle, 0.0, 1.0, 0.0);
            glScalef(EarthScale, EarthScale, EarthScale);
            glutSolidCube(1.0);
        } glPopMatrix();
    
        // Moon cube
        glColor3f(0.8, 0.8, 0.8);
        glPushMatrix(); {
            glRotatef(MoonRevAngle, 0.0, 1.0, 0.0);
            glTranslatef(MoonDistance, 0.0, MoonDistance);
            glRotatef(MoonSpinAngle, 0.0, 1.0, 0.0);
            glScalef(MoonScale, MoonScale, MoonScale);
            glutSolidCube(1.0);
        } glPopMatrix();
    } glPopMatrix();

    glutSwapBuffers();
}

// Reshape callback ------------------------------------------------------------

void
reshape(GLsizei nw, GLsizei nh)
{
    WindowWidth  = nw;
    WindowHeight = nh;
    
    init_scene();
}

// Keyboard callback -----------------------------------------------------------

void
keyboard(unsigned char key, int x, int y)
{
    if (key == 'q' || key == 'Q')
        exit(EXIT_SUCCESS);

    if (key == ' ')
        AnimationOn = !AnimationOn;
}

// Special callback -----------------------------------------------------------

void
special(int key, int x, int y)
{
    switch (key) {
        case GLUT_KEY_LEFT:  CameraLatitude  -= 1.0; break;
        case GLUT_KEY_RIGHT: CameraLatitude  += 1.0; break;
        case GLUT_KEY_UP:    CameraLongitude -= 1.0; break;
        case GLUT_KEY_DOWN:  CameraLongitude += 1.0; break;
    }
    
    update_camera_location();
}

// Mouse callback --------------------------------------------------------------

void
mouse(int button, int state, int x, int y)
{
    MouseX = x;
    MouseY = y;

    switch (button) {
        case WHEEL_UP:
            CameraDistance = (CameraDistance > CAMERA_DISTANCE_MIN ? CameraDistance - 1.0 : CAMERA_DISTANCE_MIN);
            break;
        case WHEEL_DOWN:
            CameraDistance = (CameraDistance < CAMERA_DISTANCE_MAX ? CameraDistance + 1.0 : CAMERA_DISTANCE_MAX);
            break;
    }
    
    update_camera_location();
}

// Motion callback -------------------------------------------------------------

void
motion(int x, int y)
{
    CameraLatitude  += 180.0*(double)(x - MouseX)/WindowWidth;
    CameraLongitude += 180.0*(double)(y - MouseY)/WindowHeight;
    
    update_camera_location();
    
    MouseX = x;
    MouseY = y;
}

// Timer callback --------------------------------------------------------------

void
timer(int value)
{
    if (AnimationOn) {
        SunAngle = (SunAngle < 360.0 ? SunAngle + 1.0 : 1.0);

        EarthSpinAngle = (EarthSpinAngle < 360.0 ? EarthSpinAngle + 1.0 : 1.0);
        EarthRevAngle  = (EarthRevAngle  < 360.0 ? EarthRevAngle  + 2.0 : 1.0);

        MoonSpinAngle  = (MoonSpinAngle < 360.0 ? MoonSpinAngle + 2.0 : 1.0);
        MoonRevAngle   = (MoonRevAngle  < 360.0 ? MoonRevAngle  + 4.0 : 1.0);
    }

    glutPostRedisplay();
    glutTimerFunc(1000/FrameRate, timer, 0);
}

// Main execution --------------------------------------------------------------

int
main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(WindowWidth, WindowHeight);
    glutCreateWindow("orbit");
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutSpecialFunc(special);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutTimerFunc(1000/FrameRate, timer, 0);

    init_scene();

    glutMainLoop();

    return (EXIT_SUCCESS);
}

// vim: sts=4 sw=4 ts=8 ft=cpp


Files