OpenGL实现交互
前言
有一说一越是学习openGL就越是能感觉到我的代码的极限 为了展示更加炫酷的效果,对图形化效果进行学习
作者 : recom
实现效果如下
1. 鼠标交互
2. 键盘交互
3. 菜单控制
4. 多页面切换GUI 待实现
实现opengl交互
实验8 OpenGL交互 鼠标
https://www.cnblogs.com/opengl/archive/2012/10/23/2736254.html
预期实现效果,
1.菜单栏选择绘制图形样式
2.鼠标点击地点绘制模型
3.实现鼠标拖拽效果
void glutMouseFunc(void(*func)(int button,int state,int x,int y));
参数:func:处理鼠标click事件的函数的函数名。
从上面可以看到,处理鼠标单击事件的函数,一定有4个参数。第一个参数表明哪个鼠标键被按下或松开,这个变量可以是下面的三个值中的
一个:
GLUT_LEFT_BUTTON 左键
GLUT_MIDDLE_BUTTON 中键
GLUT_RIGHT_BUTTON 右键
第二个参数表明,函数被调用发生时,鼠标的状态,也就是是被按下,或松开,可能取值如下:
GLUT_DOWN 按下
GLUT_UP 松开
当函数被调用时,state的值是GLUT_DOWN,那么程序可能会假定将会有个GLUT_UP事件,甚至鼠标移动到窗口外面,也如此。
然而,如果程序调用glutMouseFunc传递NULL作为参数,那么GLUT将不会改变鼠标的状态。
剩下的两个参数(x,y)提供了鼠标当前的窗口坐标(以左上角为原点)
实现目标: 鼠标当前位置绘制方框
代码如下
#include
#include
#include
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
void drawSquare(GLint x, GLint y) {
y = wh - y;
glBegin(GL_POLYGON);
glVertex3f(x + size, y + size, 0);
glVertex3f(x - size, y + size, 0);
glVertex3f(x - size, y - size, 0);
glVertex3f(x + size, y - size, 0);
glEnd();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
drawSquare(x, y);
glutSwapBuffers();
glutPostRedisplay();
}
void init()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
}
void myreshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, w, 0, h, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
ww = w;
wh = h;
}
void mymouse(GLint button, GLint state, GLint wx, GLint wy)
{
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
exit(0);
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
x = wx;
y = wy;
}
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("double");
init();
glutDisplayFunc(mydisplay);
glutReshapeFunc(myreshape);
glutMouseFunc(mymouse);
glutMainLoop();
}
描述效果
左键点击顶点,加入绘制点集合
右键点击一下进行绘制 两下取消绘制
点击滑轮按钮后清空绘制点集合
绘制一个三角形
出现的问题
1. opengl鼠标点击坐标和点坐标不一致
OpenGL生成窗口,鼠标点击位置和显示位置有偏移 https://blog.csdn.net/keneyr/article/details/90111046
我的坐标原点为屏幕中心 上 右为正方向
鼠标坐标原点为左上角 下 右为正方向
进行换算后
2. 绘制出的图形闪烁的厉害
开启双缓冲模式
glutSwapBuffers();该指令在绘制函数中也使用,导致闪烁,注释后不闪烁
#include
#include
#include
#include
#include
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
bool flag = false;
//定义用于表示像素点坐标的类Point
class Point
{
public:
int x;
int y;
Point(int x, int y)
{
this->x = x;
this->y = y;
}
};
vector vectices;//待绘制的顶点集合
//绘制多边形
void plot_polygon(const vector& vertices) {
Point startPoint = vertices[0];//定义初始点
Point endPoint = Point(0, 0);
//绘制直线
glBegin(GL_LINES);
glColor3f(1.0, 0, 0);
for (int i = 1; i < vertices.size(); i++) {
endPoint = vertices[i];
glVertex2f(startPoint.x, startPoint.y); //直线起始坐标
glVertex2f(endPoint.x, endPoint.y); //直线结束坐标
startPoint = endPoint;
}
endPoint = vertices[0];
glVertex2f(startPoint.x, startPoint.y); //直线起始坐标
glVertex2f(endPoint.x, endPoint.y); //直线结束坐标
glEnd();
//cout << "函数内绘制成功 " << endl;
//glFlush();
//glutSwapBuffers();
//glutPostRedisplay();
}
//绘制坐标轴
void display_coordinate(void) {
//绘制x轴
glBegin(GL_LINES);
glVertex2f(-400, 0); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(-400 + i, 0); //直线起始坐标
glVertex2f(-400 + i, 0 + 10); //直线结束坐标
}
//绘制箭头
glVertex2f(400 - 20, 20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
glVertex2f(400 - 20, -20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
//绘制y轴
glVertex2f(0, -400); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(0, -400 + i); //直线起始坐标
glVertex2f(10, -400 + i); //直线结束坐标
}
//绘制箭头
glVertex2f(-20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glVertex2f(20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glEnd();
//glFlush();
//glutSwapBuffers();
//glutPostRedisplay();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0, 0, 0);
display_coordinate();
if (flag==true&&vectices.size() > 2) {
plot_polygon(vectices);
//cout << "绘制的顶点总数为 " << vectices.size() << endl;
}
//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
glutSwapBuffers();
//glutPostRedisplay重新刷新页面绘图
glutPostRedisplay();
}
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
gluOrtho2D(-500, 500, -500, 500);
}
void mymouse(GLint button, GLint state, GLint wx, GLint wy)
{
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {//点击鼠标右键
if (flag == false) {
cout << "绘制成功" << endl;
flag = true;
}
else if (flag==true) {
cout << "取消绘制" << endl;
flag = false;
}
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//点击鼠标左键
{
x = (1000 - wx - 500) * -1;
y = 1000 - wy - 500 - 40;
cout << "绘制的顶点坐标为" << x << " " << y << endl;
vectices.emplace_back(Point(x, y));
}
if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) {//点击中间进行清空
vectices.clear();
}
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 100);
glutInitWindowSize(1000, 1000);
glutCreateWindow("3D Tech- GLUT Tutorial");
init();
glutDisplayFunc(mydisplay);
glutMouseFunc(mymouse);
glutMainLoop();
return 0;
}
描述
左键点击拖拽绘图,键盘z对绘制的直线进行撤销
使用vector,对鼠标点击点进行存储,并对鼠标松开点进行存储
#include
#include
#include
#include
#include
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
bool flag = false;
//定义用于表示像素点坐标的类Point
//定义用于表示像素点坐标的类Point
class Point
{
public:
int x;
int y;
Point(int x, int y)
{
this->x = x;
this->y = y;
}
};
vector vectices;//待绘制的顶点集合
//绘制坐标轴
void plot_line(const vector& vectices) {
glBegin(GL_LINES);
for (int i = 0; i < vectices.size(); i = i + 2) {
glVertex2f(vectices[i].x, vectices[i].y);
glVertex2f(vectices[i + 1].x, vectices[i + 1].y);
}
glEnd();
}
void display_coordinate(void) {
//绘制x轴
glBegin(GL_LINES);
glVertex2f(-400, 0); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(-400 + i, 0); //直线起始坐标
glVertex2f(-400 + i, 0 + 10); //直线结束坐标
}
//绘制箭头
glVertex2f(400 - 20, 20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
glVertex2f(400 - 20, -20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
//绘制y轴
glVertex2f(0, -400); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(0, -400 + i); //直线起始坐标
glVertex2f(10, -400 + i); //直线结束坐标
}
//绘制箭头
glVertex2f(-20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glVertex2f(20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glEnd();
//glFlush();
//glutSwapBuffers();
//glutPostRedisplay();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 0, 0);
display_coordinate();
if (vectices.size() > 1&& vectices.size()%2==0) {
plot_line(vectices);
}
//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
glutSwapBuffers();
//glutPostRedisplay重新刷新页面绘图
glutPostRedisplay();
}
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
gluOrtho2D(-500, 500, -500, 500);
}
void mymouse(GLint button, GLint state, GLint wx, GLint wy)
{
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {//点击鼠标右键
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//点击鼠标左键
{
x = (1000 - wx - 500) * -1;
y = 1000 - wy - 500 - 40;
cout << "绘制的顶点坐标起点为" << x << " " << y << endl;
vectices.emplace_back(Point(x, y));
//glVertex2f(x, y);
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)//松开鼠标左键
{
x = (1000 - wx - 500) * -1;
y = 1000 - wy - 500 - 40;
cout << "绘制的顶点坐标终点为" << x << " " << y << endl;
vectices.emplace_back(Point(x, y));
}
}
void processNormalKeys(unsigned char key, int x, int y) {
if (key == 'z') {
int mod = glutGetModifiers();
if (mod == GLUT_ACTIVE_CTRL) {
}
else {
if (vectices.size() > 1) {
vectices.pop_back();
vectices.pop_back();
cout << "撤销该条线段" << endl;
}
else {
cout << "撤销失败" << endl;
}
}
}
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 100);
glutInitWindowSize(1000, 1000);
glutCreateWindow("3D Tech- GLUT Tutorial");
init();
glutDisplayFunc(mydisplay);
glutKeyboardFunc(processNormalKeys);
glutMouseFunc(mymouse);
glutMainLoop();
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
bool flag = false;
int x_start = 0;
int y_start = 0;
int x_end = 0;
int y_end = 0;
//定义用于表示像素点坐标的类Point
class Point
{
public:
int x;
int y;
Point(int x, int y)
{
this->x = x;
this->y = y;
}
};
vector vectices = {Point(100,100),Point(150,150),Point(200,100)};//待绘制的顶点集合
//绘制多边形
void plot_polygon(const vector& vertices) {
Point startPoint = vertices[0];//定义初始点
Point endPoint = Point(0, 0);
//绘制直线
glBegin(GL_LINES);
glColor3f(1.0, 0, 0);
for (int i = 1; i < vertices.size(); i++) {
endPoint = vertices[i];
glVertex2f(startPoint.x, startPoint.y); //直线起始坐标
glVertex2f(endPoint.x, endPoint.y); //直线结束坐标
startPoint = endPoint;
}
endPoint = vertices[0];
glVertex2f(startPoint.x, startPoint.y); //直线起始坐标
glVertex2f(endPoint.x, endPoint.y); //直线结束坐标
glEnd();
//cout << "函数内绘制成功 " << endl;
//glFlush();
//glutSwapBuffers();
//glutPostRedisplay();
}
//平移
vector translation(const vector& vertices, int Tx, int Ty) {
vector result;
result.clear();
for (int i = 0; i < vertices.size(); i++) {
result.emplace_back(Point(vertices[i].x + Tx, vertices[i].y + Ty));
}
return result;
}
//绘制坐标轴
void display_coordinate(void) {
//绘制x轴
glBegin(GL_LINES);
glVertex2f(-400, 0); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(-400 + i, 0); //直线起始坐标
glVertex2f(-400 + i, 0 + 10); //直线结束坐标
}
//绘制箭头
glVertex2f(400 - 20, 20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
glVertex2f(400 - 20, -20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
//绘制y轴
glVertex2f(0, -400); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(0, -400 + i); //直线起始坐标
glVertex2f(10, -400 + i); //直线结束坐标
}
//绘制箭头
glVertex2f(-20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glVertex2f(20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glEnd();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0, 0, 0);
display_coordinate();
plot_polygon(vectices);
//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
glutSwapBuffers();
//glutPostRedisplay重新刷新页面绘图
glutPostRedisplay();
}
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
gluOrtho2D(-500, 500, -500, 500);
}
void mymouse(GLint button, GLint state, GLint wx, GLint wy)
{
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {//点击鼠标右键
exit(0);//结束
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//点击鼠标左键
{
x = (1000 - wx - 500) * -1;
y = 1000 - wy - 500 - 40;
x_start = x;
y_start = y;
cout << "起始的顶点坐标为" << x << " " << y << endl;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {//松开鼠标左键
x = (1000 - wx - 500) * -1;
y = 1000 - wy - 500 - 40;
x_end = x;
y_end = y;
vectices=translation(vectices, x_end - x_start, y_end - y_start);
cout << "结束的顶点坐标为" << x << " " << y << endl;
//vectices.clear();
}
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 100);
glutInitWindowSize(1000, 1000);
glutCreateWindow("3D Tech- GLUT Tutorial");
init();
glutDisplayFunc(mydisplay);
glutMouseFunc(mymouse);
glutMainLoop();
return 0;
}
https://www.jianshu.com/p/c9215017d591 原始的openGL不支持滚轮,需要进行更高级的配置,所以只给出资料链接
https://blog.csdn.net/wuyong2k/article/details/7839973 Glut处理鼠标事件
未找到实现的思路
或许可以通过 glutMotionFunc函数实现
参考资料 https://blog.csdn.net/xie_zi/article/details/1911891 OpenGL—GLUT教程(五) GLUT键盘控制
实现 按下escape按钮进行退出
关键代码如下
void processNormalKeys(unsigned char key,int x,int y)
{
if(key==27)
exit(0);
}
//主函数添加
glutKeyboardFunc(processNormalKeys);
完整代码
#include
#include
#include
#include
#include
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
//绘制坐标轴
void display_coordinate(void) {
//绘制x轴
glBegin(GL_LINES);
glVertex2f(-400, 0); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(-400 + i, 0); //直线起始坐标
glVertex2f(-400 + i, 0 + 10); //直线结束坐标
}
//绘制箭头
glVertex2f(400 - 20, 20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
glVertex2f(400 - 20, -20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
//绘制y轴
glVertex2f(0, -400); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(0, -400 + i); //直线起始坐标
glVertex2f(10, -400 + i); //直线结束坐标
}
//绘制箭头
glVertex2f(-20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glVertex2f(20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glEnd();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0, 0, 0);
display_coordinate();
//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
glutSwapBuffers();
//glutPostRedisplay重新刷新页面绘图
glutPostRedisplay();
}
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
gluOrtho2D(-500, 500, -500, 500);
}
void processNormalKeys(unsigned char key, int x, int y)
{
if (key == 27)
exit(0);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("3D Tech- GLUT Tutorial");
init();
glutDisplayFunc(mydisplay);
glutKeyboardFunc(processNormalKeys);
glutMainLoop();
return 0;
}
实现按下F1坐标轴为红色,F2坐标轴为绿色,F3坐标轴为蓝色,F4坐标轴为黑色
void processSpecialKeys(int key, int x, int y) {
switch(key) {
case GLUT_KEY_F1 :
red = 1.0; green = 0.0; blue = 0.0;
break;
case GLUT_KEY_F2 :
red = 0.0; green = 1.0; blue = 0.0;
break;
case GLUT_KEY_F3 :
red = 0.0; green = 0.0; blue = 1.0;
break;
case GLUT_KEY_F4 :
red = 0.0; green = 0.0; blue = 0.0;
break;
}
}
//主函数添加
glutSpecialFunc(processSpecialKeys);
完整代码
#include
#include
#include
#include
#include
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
double red = 0;
double green = 0;
double blue = 0;
//绘制坐标轴
void display_coordinate(void) {
//绘制x轴
glBegin(GL_LINES);
glVertex2f(-400, 0); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(-400 + i, 0); //直线起始坐标
glVertex2f(-400 + i, 0 + 10); //直线结束坐标
}
//绘制箭头
glVertex2f(400 - 20, 20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
glVertex2f(400 - 20, -20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
//绘制y轴
glVertex2f(0, -400); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(0, -400 + i); //直线起始坐标
glVertex2f(10, -400 + i); //直线结束坐标
}
//绘制箭头
glVertex2f(-20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glVertex2f(20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glEnd();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(red, green, blue);
display_coordinate();
//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
glutSwapBuffers();
//glutPostRedisplay重新刷新页面绘图
glutPostRedisplay();
}
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
gluOrtho2D(-500, 500, -500, 500);
}
void processSpecialKeys(int key, int x, int y) {
switch (key) {
case GLUT_KEY_F1:
red = 1.0; green = 0.0; blue = 0.0;
break;
case GLUT_KEY_F2:
red = 0.0; green = 1.0; blue = 0.0;
break;
case GLUT_KEY_F3:
red = 0.0; green = 0.0; blue = 1.0;
break;
case GLUT_KEY_F4:
red = 0.0; green = 0.0; blue = 0.0;
break;
}
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("3D Tech- GLUT Tutorial");
init();
glutDisplayFunc(mydisplay);
glutSpecialFunc(processSpecialKeys);
glutMainLoop();
return 0;
}
怎样知道是否按下组合键
一些时候我们想知道要是一个组合键( modifier key)也就是CTRL,ALT或者SHIFT被按下该如何处理。
GLUT提供了一个函数来检测时候有组合键被按下。这个函数仅仅只能在处理按键消息或者鼠标消息函数里被调用。函数原型如下:
int glutGetModifiers(void);
这个函数的返回值是三个 glut.h里预定义的常量里的一个,或它们的或组合。这三个常量是:
1: GLUT_ACTIVE_SHIFT: 返回它,当按下SHIFT键或以按下CAPS LOCK,注意两者同时按下时,不会返回这个值。
2: GLUT_ACTIVE_CTRL: 返回它,当按下CTRL键。
3: GLUT_ACTIVE_ATL:返回它,当按下ATL键。
处理组合键,按下 r 键时green变量被设置为1.0,red设置为0,当按下ATL+r时red被设置为1.0,green为0.0
void processNormalKeys(unsigned char key, int x, int y) {
if (key == 27)
exit(0);
else if (key=='r') {
int mod = glutGetModifiers();
if (mod == GLUT_ACTIVE_ALT)
red = 0.0;
else
red = 1.0;
}
}
//主函数添加检测普通按键的就可以了
glutKeyboardFunc(processNormalKeys);
完整代码
#include
#include
#include
#include
#include
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
double red = 0;
double green = 0;
double blue = 0;
//绘制坐标轴
void display_coordinate(void) {
//绘制x轴
glBegin(GL_LINES);
glVertex2f(-400, 0); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(-400 + i, 0); //直线起始坐标
glVertex2f(-400 + i, 0 + 10); //直线结束坐标
}
//绘制箭头
glVertex2f(400 - 20, 20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
glVertex2f(400 - 20, -20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
//绘制y轴
glVertex2f(0, -400); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(0, -400 + i); //直线起始坐标
glVertex2f(10, -400 + i); //直线结束坐标
}
//绘制箭头
glVertex2f(-20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glVertex2f(20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glEnd();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(red, green, blue);
display_coordinate();
//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
glutSwapBuffers();
//glutPostRedisplay重新刷新页面绘图
glutPostRedisplay();
}
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
gluOrtho2D(-500, 500, -500, 500);
}
void processNormalKeys(unsigned char key, int x, int y) {
if (key == 27)
exit(0);
else if (key == 'r') {
int mod = glutGetModifiers();
if (mod == GLUT_ACTIVE_ALT) {
green = 1.0;
red = 0;
}
else {
red = 1.0;
green = 0;
}
}
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("3D Tech- GLUT Tutorial");
init();
glutDisplayFunc(mydisplay);
glutKeyboardFunc(processNormalKeys);
glutMainLoop();
return 0;
}
CTRL+ALT+F1时颜色改变为红色,F1时颜色改变为绿色,F2颜色变为绿色,F3颜色变为蓝色
void processSpecialKeys(int key, int x, int y) {
int mod;
switch(key) {
case GLUT_KEY_F1 :
mod = glutGetModifiers();
if (mod == (GLUT_ACTIVE_CTRL|GLUT_ACTIVE_ALT)) {
red = 1.0; green = 0.0; blue = 0.0;
}else
break;
case GLUT_KEY_F2 :
red = 0.0;
green = 1.0;
blue = 0.0; break;
case GLUT_KEY_F3 :
red = 0.0;
green = 0.0;
blue = 1.0; break;
}
}
//主函数添加
glutSpecialFunc(processSpecialKeys);
#include
#include
#include
#include
#include
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
double red = 0;
double green = 0;
double blue = 0;
//绘制坐标轴
void display_coordinate(void) {
//绘制x轴
glBegin(GL_LINES);
glVertex2f(-400, 0); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(-400 + i, 0); //直线起始坐标
glVertex2f(-400 + i, 0 + 10); //直线结束坐标
}
//绘制箭头
glVertex2f(400 - 20, 20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
glVertex2f(400 - 20, -20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
//绘制y轴
glVertex2f(0, -400); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(0, -400 + i); //直线起始坐标
glVertex2f(10, -400 + i); //直线结束坐标
}
//绘制箭头
glVertex2f(-20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glVertex2f(20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glEnd();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(red, green, blue);
display_coordinate();
//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
glutSwapBuffers();
//glutPostRedisplay重新刷新页面绘图
glutPostRedisplay();
}
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
gluOrtho2D(-500, 500, -500, 500);
}
void processSpecialKeys(int key, int x, int y) {
int mod;
switch (key) {
case GLUT_KEY_F1:
mod = glutGetModifiers();
if (mod == (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_ALT)) {
red = 1.0; green = 0.0; blue = 0.0;
}
else {
red = 0.0; green = 1.0; blue = 0.0;
}
break;
case GLUT_KEY_F2:
red = 0.0;
green = 1.0;
blue = 0.0; break;
case GLUT_KEY_F3:
red = 0.0;
green = 0.0;
blue = 1.0; break;
}
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("3D Tech- GLUT Tutorial");
init();
glutDisplayFunc(mydisplay);
glutSpecialFunc(processSpecialKeys);
glutMainLoop();
return 0;
}
参考资料 https://blog.csdn.net/xie_zi/article/details/1963383 OpenGL—GLUT教程(十) GLUT菜单
弹出式菜单(像点鼠标右键出来的菜单那样的)也是 GLUT的一部分,虽然它不能实现我们经常看到的windows系统弹出式菜单的所有的功能,但是它也有很大的作用。给一个程序增加菜单提供了一个比键盘更简单的方法来和程序交互,选择不同选项,而不用去记那些按键。
我们首先要做的是创建菜单,创建菜单函数 glutCreateMenu的原型如下:
int glutCreateMenu( void (*func)(int value));
参数:
func:为新建的菜单处理菜单事件的函数名。
这个函数的返回值是菜单的标识符( menu identifier)。
我们的程序中,我们可以相加多少菜单就加多少菜单。对每个菜单我们要指定一个回调函数,而且我们可以指定相同的函数。
下面为菜单增加一些条目(出来个空菜单也没什么用)。
使用的函数是 glutAddMenuEntry:
void glutAddMenuEntry( char *name,int value);
参数:
name:菜单名称的字符串。
value:当你选择菜单里的一项后,这个值就返回给上面的 glutCreateMenu里调用的函数。
这个函数根据函数名来看,就是给菜单里添加条目的,可以一直添加(这里有个顺序,自己实验下就明白了的)。
好了现在有了一个弹出式菜单。但还有最后一件事要做,就是把菜单和一个鼠标键连接起来( attach)。因为我们必须指定菜单怎么出现,使用GLUT你可以在按下一个鼠标按键后让菜单显示,函数是glutAttachMenu:
void glutAttachMenu( int button);
参数:
button: 一个整数,指定菜单和哪个鼠标键关联起来。
botton 可以取下面的值 ;
GLUT_LEFT_BUTTON
GLUT_MIDDLE_BUTTON
GLUT_RIGHT_BUTTON
描述
1.通过鼠标右键展开菜单
2.通过鼠标左键选择需要修改的颜色
#define RED 1
#define GREEN 2
#define BLUE 3
#define WHITE 4
void createGLUTMenus() {
int menu;
// 创建菜单并告诉GLUT,processMenuEvents处理菜单事件。
menu = glutCreateMenu(processMenuEvents);
//给菜单增加条目
glutAddMenuEntry("Red",RED);
glutAddMenuEntry("Blue",BLUE);
glutAddMenuEntry("Green",GREEN);
glutAddMenuEntry("White",WHITE);
// 把菜单和鼠标右键关联起来。
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
//注意 RED,BLUE,GREEN,和WHITE必须定义为整数,再就是你必须为每个选单(菜单里的条目)定义不同的value
//下面我们写处理菜单事件的函数。我们将使用我们的菜单来设置三角形的颜色。函数如下:
void processMenuEvents(int option) {
//option,就是传递过来的value的值。
switch (option) {
case RED :
red = 1.0;
green = 0.0;
blue = 0.0; break;
case GREEN :
red = 0.0;
green = 1.0;
blue = 0.0; break;
case BLUE :
red = 0.0;
green = 0.0;
blue = 1.0; break;
case WHITE :
red = 1.0;
green = 1.0;
blue = 1.0; break;
}
}
//主函数添加
//调用我们的函数来创建菜单
createGLUTMenus();
完整代码
#include
#include
#include
#include
#include
using namespace std;
GLfloat x = 0.0;
GLfloat y = 0.0;
GLfloat size = 50.0;
GLsizei wh = 500, ww = 500;
#define RED 1
#define GREEN 2
#define BLUE 3
#define WHITE 4
double red = 0;
double green = 0;
double blue = 0;
//绘制坐标轴
void display_coordinate(void) {
//绘制x轴
glBegin(GL_LINES);
glVertex2f(-400, 0); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(-400 + i, 0); //直线起始坐标
glVertex2f(-400 + i, 0 + 10); //直线结束坐标
}
//绘制箭头
glVertex2f(400 - 20, 20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
glVertex2f(400 - 20, -20); //直线起始坐标
glVertex2f(400, 0); //直线结束坐标
//绘制y轴
glVertex2f(0, -400); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
for (int i = 0; i < 800; i = i + 20) {
glVertex2f(0, -400 + i); //直线起始坐标
glVertex2f(10, -400 + i); //直线结束坐标
}
//绘制箭头
glVertex2f(-20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glVertex2f(20, 400 - 20); //直线起始坐标
glVertex2f(0, 400); //直线结束坐标
glEnd();
}
void mydisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(red, green, blue);
display_coordinate();
//glFlush与glutSwapBuffers区别 glutSwapBuffers其实就是交换缓冲区
glutSwapBuffers();
//glutPostRedisplay重新刷新页面绘图
glutPostRedisplay();
}
void init(void)
{
glClearColor(1.0, 1.0, 1.0, 0.5);
glMatrixMode(GL_PROJECTION);
//gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
gluOrtho2D(-500, 500, -500, 500);
}
//下面我们写处理菜单事件的函数。我们将使用我们的菜单来设置三角形的颜色。函数如下:
void processMenuEvents(int option) {
//option,就是传递过来的value的值。
switch (option) {
case RED:
red = 1.0;
green = 0.0;
blue = 0.0; break;
case GREEN:
red = 0.0;
green = 1.0;
blue = 0.0; break;
case BLUE:
red = 0.0;
green = 0.0;
blue = 1.0; break;
case WHITE:
red = 1.0;
green = 1.0;
blue = 1.0; break;
}
}
void createGLUTMenus() {
int menu;
// 创建菜单并告诉GLUT,processMenuEvents处理菜单事件。
menu = glutCreateMenu(processMenuEvents);
//给菜单增加条目
glutAddMenuEntry("Red", RED);
glutAddMenuEntry("Blue", BLUE);
glutAddMenuEntry("Green", GREEN);
glutAddMenuEntry("White", WHITE);
// 把菜单和鼠标右键关联起来。
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
//注意 RED,BLUE,GREEN,和WHITE必须定义为整数,再就是你必须为每个选单(菜单里的条目)定义不同的value
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(50, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("3D Tech- GLUT Tutorial");
init();
glutDisplayFunc(mydisplay);
createGLUTMenus();
glutMainLoop();
return 0;
}