通过按箭头键移动图型的源码实例。
// Move.cpp
// Move a Block based on arrow key movements
#include
// OpenGL toolkit
#include
#ifdef __APPLE__
#include
#else
#define FREEGLUT_STATIC
#include
#endif
GLBatch squareBatch;
GLShaderManager shaderManager;
GLfloat blockSize = 0.1f;
GLfloat vVerts[] = { -blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize, blockSize, 0.0f,
-blockSize, blockSize, 0.0f};
///
// This function does any needed initialization on the rendering context.
// This is the first opportunity to do any OpenGL related tasks.
void SetupRC()
{
// Black background
glClearColor(0.0f, 0.0f, 1.0f, 1.0f );
shaderManager.InitializeStockShaders();
// Load up a triangle
squareBatch.Begin(GL_TRIANGLE_FAN, 4);
squareBatch.CopyVertexData3f(vVerts);
squareBatch.End();
}
// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
{
GLfloat stepSize = 0.025f;
GLfloat blockX = vVerts[0]; // Upper left X
GLfloat blockY = vVerts[7]; // Upper left Y
if(key == GLUT_KEY_UP)
blockY += stepSize;
if(key == GLUT_KEY_DOWN)
blockY -= stepSize;
if(key == GLUT_KEY_LEFT)
blockX -= stepSize;
if(key == GLUT_KEY_RIGHT)
blockX += stepSize;
// Collision detection
if(blockX < -1.0f) blockX = -1.0f;
if(blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;;
if(blockY < -1.0f + blockSize * 2) blockY = -1.0f + blockSize * 2;
if(blockY > 1.0f) blockY = 1.0f;
// Recalculate vertex positions
vVerts[0] = blockX;
vVerts[1] = blockY - blockSize*2;
vVerts[3] = blockX + blockSize*2;
vVerts[4] = blockY - blockSize*2;
vVerts[6] = blockX + blockSize*2;
vVerts[7] = blockY;
vVerts[9] = blockX;
vVerts[10] = blockY;
squareBatch.CopyVertexData3f(vVerts);
glutPostRedisplay();
}
///
// Called to draw scene
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
squareBatch.Draw();
// Flush drawing commands
glutSwapBuffers();
}
///
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
}
///
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("Move Block with Arrow Keys");
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return 1;
}
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
SetupRC();
glutMainLoop();
return 0;
}
特殊按键和刷新显示
GLUT提供了一个回调函数,即glutSpecialFunc。它注册了一个能够在按一个特殊按键时被调用的函数。在GLUT语法中,特殊按键是指功能键或者方向键(上、下、左
右箭头键,page up/down键灯)中的一个。在主函数加入glutSpecialFunc(SpecialKeys);来注册SpeciaKeys回调函数。
本例中将顶点存储在全局数组中,可以在按键时相应修改正方形的位置。
void SpecialKeys(int key,int x, int y)函数,实现了按键移动图形的功能。
GLfloat stepSize = 0.025f;
设置按键按一下移动的步长;
GLfloat blockX = vVerts[0]; // Upper left X
GLfloat blockY = vVerts[7]; // Upper left Y
得到四边形左上顶点的x坐标和左上顶点的y坐标;(四边形左边顶点的x坐标相同,上边的y坐标相同,右边的x坐标相同,下边的x坐标相同)
if(key == GLUT_KEY_UP)
blockY += stepSize;
当按下上箭头,x坐标不变,y坐标加步长;
if(key == GLUT_KEY_DOWN)
blockY -= stepSize;
当按下下箭头,x坐标不变,y坐标减步长;
if(key == GLUT_KEY_LEFT)
blockX -= stepSize;
当按下左箭头,y坐标不变,x坐标减步长;
if(key == GLUT_KEY_RIGHT)
blockX += stepSize;
当按下右箭头,y坐标不变,x坐标加步长;
// Collision detection碰撞检测,防止按下按键时,图形超出窗口的范围
if(blockX < -1.0f) blockX = -1.0f;
if(blockX > (1.0f - blockSize * 2)) blockX = 1.0f - blockSize * 2;
if(blockY < -1.0f + blockSize * 2) blockY = -1.0f + blockSize * 2;
if(blockY > 1.0f) blockY = 1.0f;
要知道全局变量blockSize=0.1f; 局部变量stepSize = 0.025f; 并且坐标是映射到实际的屏幕像素;blockX和blockY分别对应左上角顶点的x坐标和右上角顶点的y坐标;(0,0,0)坐标位于屏幕的中心。即以四边上上面的边为参考边,确保不会超出窗口的范围即可,可画图理解。(我把blockSize理解成四边形边长的一半,有好的见解希望评论。)
// Recalculate vertex positions
vVerts[0] = blockX;
vVerts[1] = blockY - blockSize*2;
vVerts[3] = blockX + blockSize*2;
vVerts[4] = blockY - blockSize*2;
vVerts[6] = blockX + blockSize*2;
vVerts[7] = blockY;
vVerts[9] = blockX;
vVerts[10] = blockY;
重新赋值顶点坐标,记住blockX初始值是四边形左边顶点的x的坐标值,blockY初始值是四边形上边顶点的y的坐标值。可画图理解。
例如vVerts[0]是四边形左下角顶点的x坐标,所以等于blockX(左边顶点的x坐标相等);vVerts[1]是四边形左下角顶点的y坐标,是由上面的y坐标值减去2*blockSize,画图理解更清晰。
glutPostRedisplay();
默认情况下,在窗口创建和改变大小或者需要重绘是,GLUT通过调用RenderScene函数来更新窗口。可以通过调用glutPostRedisplay()来告诉GLUT发生了某些改变,应该对场景进行渲染了。本例的glutPostRedisplay方法是在SpecialKeys里面调用的,当然在RenderScene方法中调用也可以,也是很方便的。
欢迎评论,共勉!!!