Example 18

Example 18

This is just example 5 with video capturing added to it. An example video is show below:

Spaceship video

Source Code

spaceship.cc:

// Peter Bui
// CSE 40166 Computer Graphics (Fall 2010)
// Example 5: spaceship

#include "capture.h"

#include <cmath>
#include <cstdio>
#include <cstdlib>

#include <list>

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

using namespace std;

// Missile data structure ------------------------------------------------------

typedef struct {
    double x;
    double y;
    double angle;
} missile;

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

enum DISPLAY_LISTS {
    DL_SPACESHIP,
    DL_CROSSHAIR,
    DL_MISSILE_TRIANGLE,
    DL_MISSILE_DIAMOND,
    DL_MISSILE_CIRCLE,
    DL_MAX
};

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

static GLuint DisplayListsBase;

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

static GLuint CursorX, CursorY;
static GLuint SpaceshipX, SpaceshipY;

static GLuint FrameRate  = 30;

static GLuint MissileType = DL_MISSILE_TRIANGLE;

static int MissileTypeMenu;
static int MainMenu;

static list<missile> Missiles;

// Draw spaceship --------------------------------------------------------------

void
draw_spaceship()
{
    glBegin(GL_TRIANGLE_FAN); {
        double ox = 0.0, oy = 0.0, radius = 0.5;
        int triangles = 32;

        glVertex2f(ox, oy);
        for (int i = 0; i <= triangles; i++) {
            double angle = i * 2.0 * M_PI / triangles;
            glVertex2f(ox + radius * cos(angle), oy + radius * sin(angle));
        }
    } glEnd();
    
    glBegin(GL_TRIANGLES); {
        glVertex2f( 0.55,  0.4);
        glVertex2f( 0.55, -0.4);
        glVertex2f( 0.95,  0.0);
    } glEnd();
}

// Draw crosshair --------------------------------------------------------------

void
draw_crosshair() 
{
    glBegin(GL_LINE_LOOP); {
        glVertex2f(-0.5, -0.5);
        glVertex2f(-0.5,  0.5);
        glVertex2f( 0.5,  0.5);
        glVertex2f( 0.5, -0.5);
    } glEnd();
    glBegin(GL_LINES); {
        glVertex2f(-0.5,  0.0);
        glVertex2f( 0.5,  0.0);
        glVertex2f( 0.0,  0.5);
        glVertex2f( 0.0, -0.5);
    } glEnd();
}

// Draw missile triangle -------------------------------------------------------

void
draw_missile_triangle()
{
    glBegin(GL_TRIANGLES); {
        glVertex2f(-0.5,  0.5);
        glVertex2f(-0.5, -0.5);
        glVertex2f( 0.5,  0.0);
    } glEnd();
}

// Draw missile diamond --------------------------------------------------------

void
draw_missile_diamond()
{
    glBegin(GL_QUADS); {
        glVertex2f(-0.5,  0.0);
        glVertex2f( 0.0, -0.5);
        glVertex2f( 0.5,  0.0);
        glVertex2f( 0.0,  0.5);
    } glEnd();
}

// Draw missile circle ---------------------------------------------------------

void
draw_missile_circle()
{
    glBegin(GL_TRIANGLE_FAN); {
        double ox = 0.0, oy = 0.0, radius = 1.0;
        int triangles = 32;

        glVertex2f(ox, oy);
        for (int i = 0; i <= triangles; i++) {
            double angle = i * 2.0 * M_PI / triangles;
            glVertex2f(ox + radius * cos(angle), oy + radius * sin(angle));
        }
    } glEnd();
}

// Compute angle ---------------------------------------------------------------

double
compute_angle(double a_x, double a_y, double b_x, double b_y)
{
    double angle = 0.0;
    
    if (b_x > a_x && b_y > a_y)
        angle = atan2(b_y - a_y, b_x - a_x) * 180.0 / M_PI;
    else if (b_x < a_x && b_y > a_y)
        angle = 180.0 - (atan2(b_y - a_y, a_x - b_x) * 180.0 / M_PI);
    else if (b_x < a_x && b_y < a_y)
        angle = 180.0 + (atan2(a_y - b_y, a_x - b_x) * 180.0 / M_PI);
    else if (b_x > a_x && b_y < a_y)
        angle = 360.0 - (atan2(a_y - b_y, b_x - a_x) * 180.0 / M_PI);

    return angle;
}

// Draw scene ------------------------------------------------------------------

void
draw_scene()
{
    double angle = compute_angle(SpaceshipX, SpaceshipY, CursorX, CursorY);

    glColor3f(0.0, 1.0, 0.0);
    glPushMatrix();
    glTranslatef(SpaceshipX, SpaceshipY, 0.0);
    glRotatef(angle, 0.0, 0.0, 1.0);
    glScalef(20.0, 20.0, 1.0);
    glCallList(DisplayListsBase + DL_SPACESHIP);
    glPopMatrix();

    glPushMatrix();
    glColor3f(1.0, 0.0, 0.0);
    glTranslatef(CursorX, CursorY, 0.0);
    glScalef(10.0, 10.0, 1.0);
    glCallList(DisplayListsBase + DL_CROSSHAIR);
    glPopMatrix();

    for (list<missile>::iterator i = Missiles.begin(); i != Missiles.end(); i++) {
        glColor3f(0.0, 0.0, 1.0);
        i->x += 5.0*cos(i->angle*M_PI/180.0);
        i->y += 5.0*sin(i->angle*M_PI/180.0);

        if (i->x < 0 || i->x > WindowWidth || i->y < 0 || i->y > WindowHeight) {
            i = Missiles.erase(i);
        } else {
            glPushMatrix();
            glTranslatef(i->x, i->y, 0.0);
            glRotatef(i->angle, 0.0, 0.0, 1.0);
            glScalef(10.0, 10.0, 1.0);
            glCallList(DisplayListsBase + MissileType);
            glPopMatrix();
        }
    }
}

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

void
init_scene()
{
    glClearColor(1.0, 1.0, 1.0, 1.0);

    glutSetCursor(GLUT_CURSOR_NONE);

    SpaceshipX = WindowWidth  / 2;
    SpaceshipY = WindowHeight / 2;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, WindowWidth, 0, WindowHeight);
    glMatrixMode(GL_MODELVIEW);    
    
    glViewport(0, 0, WindowWidth, WindowHeight);
}

// Menu functions --------------------------------------------------------------

void
missile_type_menu(int id)
{
    glutSetMenu(MissileTypeMenu);

    switch (MissileType) {
        case DL_MISSILE_TRIANGLE:
            glutChangeToMenuEntry(1, "Triangle", DL_MISSILE_TRIANGLE);
            break;
        case DL_MISSILE_DIAMOND:
            glutChangeToMenuEntry(2, "Diamond", DL_MISSILE_DIAMOND);
            break;
        case DL_MISSILE_CIRCLE:
            glutChangeToMenuEntry(3, "Circle", DL_MISSILE_CIRCLE);
            break;
    }

    MissileType = id;
    
    switch (MissileType) {
        case DL_MISSILE_TRIANGLE:
            glutChangeToMenuEntry(1, "Triangle <", DL_MISSILE_TRIANGLE);
            break;
        case DL_MISSILE_DIAMOND:
            glutChangeToMenuEntry(2, "Diamond <", DL_MISSILE_DIAMOND);
            break;
        case DL_MISSILE_CIRCLE:
            glutChangeToMenuEntry(3, "Circle <", DL_MISSILE_CIRCLE);
            break;
    }
}

void
main_menu(int id)
{
    switch (id) {
        case 1: exit(EXIT_SUCCESS);
    }
}

void
setup_menus()
{
    MissileTypeMenu = glutCreateMenu(missile_type_menu);
    glutAddMenuEntry("Triangle <", DL_MISSILE_TRIANGLE);
    glutAddMenuEntry("Diamond",  DL_MISSILE_DIAMOND);
    glutAddMenuEntry("Circle",   DL_MISSILE_CIRCLE);
    
    MainMenu = glutCreateMenu(main_menu);
    glutAddSubMenu("Missile Type", MissileTypeMenu);
    glutAddMenuEntry("Quit", 1);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
}

// Make display lists ----------------------------------------------------------

void
make_display_lists()
{
    DisplayListsBase = glGenLists(DL_MAX);

    glNewList(DisplayListsBase + DL_SPACESHIP, GL_COMPILE); {
        glPushMatrix();
        draw_spaceship();
        glPopMatrix();
    } glEndList();
    
    glNewList(DisplayListsBase + DL_CROSSHAIR, GL_COMPILE); {
        glPushMatrix();
        draw_crosshair();
        glPopMatrix();
    } glEndList();
    
    glNewList(DisplayListsBase + DL_MISSILE_TRIANGLE, GL_COMPILE); {
        glPushMatrix();
        draw_missile_triangle();
        glPopMatrix();
    } glEndList();
    
    glNewList(DisplayListsBase + DL_MISSILE_DIAMOND, GL_COMPILE); {
        glPushMatrix();
        draw_missile_diamond();
        glPopMatrix();
    } glEndList();
    
    glNewList(DisplayListsBase + DL_MISSILE_CIRCLE, GL_COMPILE); {
        glPushMatrix();
        draw_missile_circle();
        glPopMatrix();
    } glEndList();
}
// Display callback ------------------------------------------------------------

void
display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    draw_scene();

    glFlush();

    capture("spaceship.frame", WindowWidth, WindowHeight);
    
    glutSwapBuffers();
}

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

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

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, WindowWidth, 0, WindowHeight);
    glMatrixMode(GL_MODELVIEW);    
    
    glViewport(0, 0, WindowWidth, WindowHeight);
}

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

void 
mouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
        missile m;

        CursorX = x;
        CursorY = WindowHeight - y;
        
        m.x = SpaceshipX;
        m.y = SpaceshipY;
        m.angle = compute_angle(SpaceshipX, SpaceshipY, CursorX, CursorY);
        Missiles.push_back(m);
    }
}

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

void
passive_motion(int x, int y)
{
    CursorX = x;
    CursorY = WindowHeight - y;
}

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

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

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

void
timer(int value)
{
    glutPostRedisplay();
    glutTimerFunc(1000/FrameRate, timer, value);
}

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

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

    init_scene();
    make_display_lists();
    setup_menus();

    glutMainLoop();

    return (EXIT_SUCCESS);
}

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


Files