This OpenGL program allows a user to pick (select) a pawn and then select a new location to move the pawn object.
board.cc:
// Peter Bui
// CSE 40166 Computer Graphics (Fall 2010)
// Example 4: pawn board
#include <cmath>
#include <cstdio>
#include <cstdlib>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
// Pawn data structure ---------------------------------------------------------
struct pawn {
size_t row;
size_t column;
int state;
};
// Constants -------------------------------------------------------------------
enum PAWN_STATE {
PAWN_STATE_UNSELECTED,
PAWN_STATE_SELECTED,
PAWN_STATE_MAX,
};
enum DISPLAY_LISTS {
DL_CELL,
DL_PAWN,
DL_BOX,
DL_MAX
};
static const GLfloat CellColors[][3] = {
{0.0, 0.0, 0.0},
{1.0, 1.0, 1.0}
};
static const GLfloat PawnColors[][3] = {
{1.0, 0.0, 0.0},
{0.0, 1.0, 0.0},
{0.0, 0.0, 1.0}
};
#define SBSIZE 128
// Global variables ------------------------------------------------------------
static GLuint DisplayListsBase;
static size_t WindowWidth = 640;
static size_t WindowHeight = 480;
static size_t BoardRows = 8;
static size_t BoardColumns = 8;
static struct pawn Pawn = { 0, 0, PAWN_STATE_UNSELECTED };
static GLuint PawnName = (BoardRows * BoardColumns) + 1;
static GLuint SelectBuffer[SBSIZE];
static GLuint PickLimit = 5;
static GLuint CursorX, CursorY;
static GLenum Mode = GL_RENDER;
static GLuint FrameRate = 60;
// Draw cell -------------------------------------------------------------------
void
draw_cell()
{
glBegin(GL_QUADS); {
glVertex2f(0.0, 0.0);
glVertex2f(0.0, 1.0);
glVertex2f(1.0, 1.0);
glVertex2f(1.0, 0.0);
} glEnd();
}
// Draw pawn -------------------------------------------------------------------
void
draw_pawn()
{
glBegin(GL_QUADS); {
glVertex2f(-0.5, -0.5);
glVertex2f( 0.5, -0.5);
glVertex2f( 0.5, 0.0);
glVertex2f(-0.5, 0.0);
} glEnd();
glBegin(GL_TRIANGLE_FAN); {
double ox = 0.0, oy = 0.25, radius = 0.25;
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();
}
// Draw box --------------------------------------------------------------------
void
draw_box()
{
glPushAttrib(GL_LINE_BIT);
glLineWidth(4.0);
glBegin(GL_LINE_LOOP); {
glVertex2f(0.0, 0.0);
glVertex2f(0.0, 1.0);
glVertex2f(1.0, 1.0);
glVertex2f(1.0, 0.0);
} glEnd();
glPopAttrib();
}
// Draw scene ------------------------------------------------------------------
void
draw_scene()
{
size_t cc = CursorX * BoardColumns / WindowWidth;
size_t cr = (WindowHeight - CursorY) * BoardRows / WindowHeight;
for (size_t r = 0; r < BoardRows; r++) {
glPushName(r);
for (size_t c = 0; c < BoardColumns; c++) {
glPushName(c);
glPushMatrix();
glColor3fv(CellColors[(c + (r % 2)) % 2]);
glTranslatef(c, r, 0.0);
glCallList(DisplayListsBase + DL_CELL);
if (Pawn.row == r && Pawn.column == c) {
glPushName(PawnName);
glPushMatrix();
glColor3fv(PawnColors[Pawn.state]);
glTranslatef(0.5, 0.5, 0.0);
glScalef(0.5, 0.5, 1.0);
glCallList(DisplayListsBase + DL_PAWN);
glPopMatrix();
glPopName();
}
if (Pawn.state == PAWN_STATE_SELECTED) {
if (cc == c && cr == r) {
glColor3fv(PawnColors[Pawn.state]);
glCallList(DisplayListsBase + DL_BOX);
}
}
glPopMatrix();
glPopName();
}
glPopName();
}
}
// Initialize scene ------------------------------------------------------------
void
init_scene()
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, BoardRows, 0, BoardColumns);
glMatrixMode(GL_MODELVIEW);
}
// Make display lists ----------------------------------------------------------
void
make_display_lists()
{
DisplayListsBase = glGenLists(DL_MAX);
glNewList(DisplayListsBase + DL_CELL, GL_COMPILE); {
glPushMatrix();
draw_cell();
glPopMatrix();
} glEndList();
glNewList(DisplayListsBase + DL_PAWN, GL_COMPILE); {
glPushMatrix();
draw_pawn();
glPopMatrix();
} glEndList();
glNewList(DisplayListsBase + DL_BOX, GL_COMPILE); {
glPushMatrix();
draw_box();
glPopMatrix();
} glEndList();
}
// Picking functions -----------------------------------------------------------
void
start_picking()
{
GLint viewport[4];
glSelectBuffer(SBSIZE, SelectBuffer);
glGetIntegerv(GL_VIEWPORT, viewport);
glRenderMode(GL_SELECT);
glInitNames();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPickMatrix(CursorX, viewport[3] - CursorY, PickLimit, PickLimit, viewport);
gluOrtho2D(0, BoardRows, 0, BoardColumns);
glMatrixMode(GL_MODELVIEW);
}
void
process_hits(GLint hits, GLuint *buffer)
{
GLuint names;
GLuint *bp = buffer;
for (GLint i = 0; i < hits; i++) {
names = *bp;
bp += 3;
if (*(bp + (names - 1)) == PawnName) {
Pawn.state = (Pawn.state + 1) % PAWN_STATE_MAX;
} else {
if (Pawn.state == PAWN_STATE_SELECTED) {
Pawn.row = *(bp);
Pawn.column = *(bp + 1);
}
}
bp += names;
}
}
void
stop_picking()
{
GLint hits;
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glFlush();
hits = glRenderMode(GL_RENDER);
if (hits > 0)
process_hits(hits, SelectBuffer);
Mode = GL_RENDER;
}
// Display callback ------------------------------------------------------------
void
display()
{
glClear(GL_COLOR_BUFFER_BIT);
if (Mode == GL_SELECT)
start_picking();
draw_scene();
if (Mode == GL_SELECT)
stop_picking();
else
glutSwapBuffers();
}
// Reshape callback ------------------------------------------------------------
void
reshape(GLsizei nw, GLsizei nh)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, BoardRows, 0, BoardColumns);
glMatrixMode(GL_MODELVIEW);
glViewport(0, 0, nw, nh);
WindowWidth = nw;
WindowHeight = nh;
}
// Mouse callback --------------------------------------------------------------
void
mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
Mode = GL_SELECT;
CursorX = x;
CursorY = y;
}
}
// Passive Motion callback ------------------------------------------------------
void
passive_motion(int x, int y)
{
CursorX = x;
CursorY = 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();
glutMainLoop();
return (EXIT_SUCCESS);
}
// vim: sts=4 sw=4 ts=8 ft=cpp