#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
/* 需要旋转的变量*/
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static int iShape = 1;
/*目录中的选择*/
void ProcessMenu(int value)
{
iShape = value;
/*
glutPostRedisplay 标记当前窗口需要重新绘制。通过glutMainLoop下一次循环时,
窗口显示将被回调以重新显示窗口的正常面板。
多次调用glutPostRedisplay,在下一个显示回调只产生单一的重新显示回调。
*/
glutPostRedisplay();
}
/* 绘制函数(!!!)*/
void RenderScene(void)
{
/*清屏*/
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/*保存矩阵状态然后进行旋转操作*/
/*
终于明白为什么使用glPushMatrix()和glPopMatrix()的原因了。
将本次需要执行的缩放、平移等操作放在glPushMatrix和glPopMatrix之间。
glPushMatrix()和glPopMatrix()的配对使用可以消除上一次的变换对本次变换的影响。
使本次变换是以世界坐标系的原点为参考点进行。
*/
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
/*
glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
x,y,z中哪一个非0,则绕谁旋转
*/
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
/*glut提供的9种实体对象*/
switch (iShape)
{
case 1:
glutWireSphere(1.0f, 25, 25);
/*
void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);
radius:球体半径
slices:球体经线条数
stacks:球体纬线条数
功能:用于渲染一个球体(由线条构成球体)
*/
break;
case 2:
/*
绘制线框立方体
*/
glutWireCube(1.0f);
break;
case 3:
/*
绘制线框圆锥体
*/
glutWireCone(0.30f, 1.1f, 20, 20);
break;
case 4:
/*
线框圆环
*/
glutWireTorus(0.3f, 1.0f, 10, 25);
break;
case 5:
/*
线框12面体
*/
glutWireDodecahedron();
break;
case 6:
/*
线框8面体
*/
glutWireOctahedron();
break;
case 7:
/*
线框4面体
*/
glutWireTetrahedron();
break;
case 8:
/*
线框20面体
*/
glutWireIcosahedron();
break;
case 9:
/*
线框茶壶
*/
glutWireTeapot(1.0f);
break;
}
glPopMatrix();
glutSwapBuffers();
/*
但当我们进行复杂的绘图操作时,画面便可能有明显的闪烁。
解决这个问题的关键在于使绘制的东西同时出现在屏幕上。
所谓双缓冲技术, 是指使用两个缓冲区: 前台缓冲和后台缓冲。
前台缓冲即我们看到的屏幕,后台缓冲则在内存当中,对我们来说是不可见的。
每次的所有绘图操作都在后台缓冲中进行, 当绘制完成时, 把绘制的最终结果复制到屏幕上,
这样, 我们看到所有GDI元素同时出现在屏幕上,从而解决了频繁刷新导致的画面闪烁问题。
*/
}
/*初始化操作*/
void SetupRC()
{
/*设置初始背景是黑色*/
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
/*启用深度,要不就只是个平面*/
glEnable(GL_DEPTH_TEST);
/*设置绘制的线条是蓝色*/
glColor3ub(50, 255, 255);
}
void SpecialKeys(int key, int x, int y)
{
/*
键盘对于上下左右的控制在图形中的形态变换
*/
if (key == GLUT_KEY_UP)
xRot -= 5.0f;
if (key == GLUT_KEY_DOWN)
xRot += 5.0f;
if (key == GLUT_KEY_LEFT)
yRot -= 5.0f;
if (key == GLUT_KEY_RIGHT)
yRot += 5.0f;
/*刷新窗口*/
glutPostRedisplay();
}
void ChangeSize(int w, int h)
{
GLfloat nRange = 1.9f;
/*防止分母出现0的异常出现*/
if (h == 0)
h = 1;
glViewport(0, 0, w, h);
/*
glViewport(GLint x,GLint y,GLsizei width,GLsizei height)为其函数原型。
X,Y————以像素为单位,指定了视口的左下角(在第一象限内,以(0,0)为原点的)位置。
width,height————表示这个视口矩形的宽度和高度,根据窗口的实时变化重绘窗口。
*/
/*
重置当前指定的矩阵为单位矩阵.
*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-nRange, nRange, -nRange*h / w, nRange*h / w, -nRange, nRange);
/*
void glOrtho(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far);
其中近裁剪平面是一个矩形,矩形左下角点三维空间坐标是(left,bottom,-near),右上角点是(right,top,-near);
远裁剪平面也是一个矩形,左下角点空间坐标是(left,bottom,-far),右上角点是(right,top,-far)。
所有的near和far值同时为正或同时为负。
如果没有其他变换,正射投影的方向平行于Z轴,且视点朝向Z负轴。
这意味着物体在视点前面时far和near都为负值,物体在视点后面时far和near都为正值。
函数描述了一个平行修剪空间。
这种投影意味着离观察者较远的对象看上去不会变小(与透视投影相反)。
*/
else
glOrtho(-nRange*w / h, nRange*w / h, -nRange, nRange, -nRange, nRange);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char* argv[])
{
int nSolidMenu;
int nWireMenu;
int nMainMenu;
/*
初始化系列操作
*/
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutCreateWindow("GLUT Shapes");
/*
创建目录:右击鼠标进行选择图形绘制
*/
nWireMenu = glutCreateMenu(ProcessMenu);
glutAddMenuEntry("Sphere", 1);
glutAddMenuEntry("Cube", 2);
glutAddMenuEntry("Cone", 3);
glutAddMenuEntry("Torus", 4);
glutAddMenuEntry("Dodecahedron", 5);
glutAddMenuEntry("Octahedron", 6);
glutAddMenuEntry("Tetrahedron", 7);
glutAddMenuEntry("Icosahedron", 8);
glutAddMenuEntry("Teapot", 9);
// nMainMenu = glutCreateMenu(ProcessMenu);
// glutAddSubMenu("Wire", nWireMenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutReshapeFunc(ChangeSize);
/*
改变窗口大小时保持图形比例
*/
glutSpecialFunc(SpecialKeys);
/*
注册鼠标响应事件,使用glutKeyboardFunc函数注册键盘响应事件
*/
glutDisplayFunc(RenderScene);
SetupRC();
glutMainLoop();
return 0;
}