通过OpenGL自己绘制按钮,菜单,可以自己贴图,可以自己构建很炫的GUI。我这里只是做了一个最原始的模型, 没有增加贴图。
程序实现思路:通过正交变换绘制出按钮cube, 然后重置投影视图矩阵,转入场景绘制。具体在display函数里。
主要想想说一下几个细节问题:
1,正交投影的坐标系原点位于左下角, 而透视投影坐标系原点位于窗口中心。
2,mouse函数参数x,y分别是鼠标的坐标,鼠标的坐标系是:窗口左上角为原点。所以在验证鼠标是否在按钮上时,必须先进行坐标变换。
3,按钮被按下时,增加了反馈:按钮会被缩小为glScalef(0.9, 0.9, 1.0);
运行效果,按了白色小按钮,线框cube会旋转个角度。
下面是基于glut+OpenGL的程序源码:
#include <cstdio>
#include <cstdlib>
#include <GL/glut.h>
#include <cmath>
#include <ctime>
//
//global
float g_fWidth = 500;
float g_fHeight = 500;
float g_fDepth = 100;
float g_fAngle = .0;
struct Button{
float m_fPosX; //表示在正交投影坐标系(左下角为坐标原点)的坐标,
float m_fPosY;
float m_fWidth; //屏幕像素单位
float m_fHeight;
bool m_bPressed;
void Render()
{
glPushMatrix();
{
//将中心位于原点的cube移动到使cube左下角坐标为m_fPosX,m_fPosY的位置
//必须考虑cube的自身长宽
glTranslatef(m_fPosX+m_fWidth/2, m_fPosY+m_fHeight/2, -2.0); //-2.0只是为了按钮可见
if( m_bPressed )
{
//double scaleAmt = 10.0 * sin( (double)rand() );
//double scaleAmt = sin( (double)rand() );
glScalef(0.9, 0.9, 1.0);
}
//cube中心位于原点
glScalef (m_fWidth, m_fHeight, 5.0);
glutSolidCube(1.0);
}
}
bool OnMouseDown(int mousex, int mousey)
{
//鼠标的位置:mousex,mousey坐标系是原点位于左上角
//必须将mousey变换到原点位于左下角的坐标系中
mousey = g_fHeight-mousey;
if( mousex > m_fPosX && mousex < m_fPosX+m_fWidth &&
mousey > m_fPosY && mousey < m_fPosY+m_fHeight )
{
printf("button is pressed .... /n");
m_bPressed = true;
return true;
}
return false;
}
void OnMouseUp()
{
m_bPressed = false;
}
};
Button* pBtn;
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_SMOOTH);
pBtn = new Button;
pBtn->m_bPressed = false;
pBtn->m_fPosX = 40;
pBtn->m_fPosY = 480;
pBtn->m_fWidth = 60;
pBtn->m_fHeight = 20;
printf("**********button pos: 40/t480/n");
}
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, g_fWidth, 0, g_fHeight, 0, g_fDepth);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
pBtn->Render();
// 绘制cube物体,
glMatrixMode (GL_PROJECTION); //回复原有的设置
glLoadIdentity ();
gluPerspective(60,1.0,1.5,20);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
/* viewing transformation */
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glRotatef(g_fAngle, 0.0, 1.0, 0.0);
glScalef (1.0, 2.0, 1.0); /* modeling transformation */
glutWireCube (1.0);
//glFlush();
glutSwapBuffers();
}
void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(60,1.0,1.5,20);
glMatrixMode (GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
}
}
void mouse(int button, int state, int x, int y)
{
if(button==GLUT_LEFT_BUTTON)
switch(state)
{
case GLUT_DOWN:
//左键按下:
printf("Mouse pos : %d/t%d/n", x, 500-y);
if( pBtn->OnMouseDown(x, y) )
g_fAngle += 2.0;
break;
case GLUT_UP:
pBtn->OnMouseUp();
break;
}
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc( mouse );
glutMainLoop();
return 0;
}