橡皮筋技术:
如果大家用绘图软件画过直线,你就会发现选中那些直线、椭圆、矩形画图工具后,在画布上单击拖动就能画出我们所需尺寸的对应图形,十分方便,这就是所谓的橡皮筋技术。
实现橡皮筋技术的关键函数:
当然是鼠标响应函数了,OpenGL提供了以下几种响应鼠标事件的函数:
-
鼠标按下或者松开的响应函数:
glutMouseFunc(MousePlot);
参数MousePlot是对应的回调函数,可以随便取名字,但是参数一定是下面四个:
void MousePlot(GLint button,GLint action,GLint xMouse,GLint yMouse)
每个参数可取的值:
(1)你按的是鼠标的哪个键(左中右)
button:GLUT_LEFT_BUTTON
、GLUT_RIGHT_BUTTON
、GLUT_MIDDLE_BUTTON
(2)对应事件(鼠标按下还是松开)
action:GLUT_DOWN
/GLUT_UP
(3)鼠标的位置
xMouse
到窗口左侧的距离yMouse
到窗口顶部的距离,这里要注意这个yMouse,因为OpenGL的窗口是以左下角为坐标原点绘制图形的,所以yMouse
是鼠标到底部的距离, 所以我们处理鼠标的y坐标时应该是用窗口高度减去yMouse
来表示鼠标到顶部的距离。 -
按下鼠标移动鼠标时的响应函数
glutMotionFunc(MouseMove);
其参数仍是回调函数void MouseMove(GLint xMouse,GLint yMouse) -
未按下鼠标移动鼠标时的响应函数
glutPassiveMotionFunc(PassiveMouseMove);
其参数仍是回调函数void PassiveMouseMove(GLint xMouse,GLint yMouse)
首先我们用鼠标来实现:
实现效果:
下面代码实现的功能有:
(1)单击一点松开鼠标再移动鼠标可以任意控制直线方向,再单击可以画一条直线
(2)右键清屏
屏幕上没有画或者画了都可以单击鼠标左键重新选第一个点
#include <GL\freeglut.h>
int iPointNum=0;//已确定点的数目
int x1=0,y1=0,x2=0,y2=0;//确定的点的坐标
int Width=400,Height=300;
//用户初始化函数
void myinit(void)
{
//your initialization code
glClearColor(1.0f,1.0f,1.0f,1.0f);
}
//窗口大小变化时的回调函数
void myReshape(int w, int h)
{
Width=w;
Height=h;
//设定视区
glViewport(0, 0, w, h);
//设定透视方式
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,Width,0.0,Height);
}
//每桢OpenGL都会调用这个函数,用户应该把显示代码放在这个函数中
void display(void)
{
//设置清除屏幕的颜色,并清除屏幕
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,0.0f,0.0f);
if(iPointNum>=1){
glBegin(GL_LINES);
glVertex2i(x1,y1);
glVertex2i(x2,y2);
glEnd();
}
//交换前后缓冲区
glutSwapBuffers();
}
//按下鼠标的响应函数
void MousePlot(GLint button,GLint action,GLint xMouse,GLint yMouse)
{
if(button==GLUT_LEFT_BUTTON && action==GLUT_DOWN){
if(iPointNum==0||iPointNum==2){//屏幕上没有画或者画了都可以单击鼠标左键重新选第一个点
iPointNum=1;//确定直线段的第一个端点
x1=xMouse;
y1=Height-yMouse;
}else{//确定直线段的第二个端点
iPointNum=2;
x2=xMouse;
y2=Height-yMouse;
glutPostRedisplay();//指定窗口重新绘制
}
}
if(button==GLUT_RIGHT_BUTTON && action==GLUT_DOWN){//右击可以清屏
iPointNum=0;
glutPostRedisplay();
}
}
//没按鼠标时移动鼠标的回调函数,实现橡皮筋技术的地方
void PassiveMouseMove(GLint xMouse,GLint yMouse)
{
if(iPointNum==1){
x2=xMouse;
y2=Height-yMouse;
glutPostRedisplay();
}
}
//主函数
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
//初始化OPENGL显示方式
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA);
//设定OPENGL窗口位置和大小
glutInitWindowSize (400, 300);
glutInitWindowPosition (100, 100);
//打开窗口
glutCreateWindow ("橡皮筋技术");
//调用初始化函数
myinit();
//开始OPENGL的循环
glutDisplayFunc(display);
//设定窗口大小变化的回调函数
glutReshapeFunc(myReshape);
//鼠标响应函数
glutMouseFunc(MousePlot);
//移动鼠标响应函数
glutPassiveMotionFunc(PassiveMouseMove);
glutMainLoop();
return 0;
}
用键盘控制:
我把代替鼠标的部分注释掉了,换成了键盘控制的部分,现在按下松开鼠标就由P键控制了。但是移动鼠标还是用的鼠标事件函数。
#include <GL\freeglut.h>
int iPointNum=0;//已确定点的数目
int x1=0,y1=0,x2=0,y2=0;//确定的点的坐标
int Width=400,Height=300;
//用户初始化函数
void myinit(void)
{
//your initialization code
glClearColor(1.0f,1.0f,1.0f,1.0f);
}
//窗口大小变化时的回调函数
void myReshape(int w, int h)
{
Width=w;
Height=h;
//设定视区
glViewport(0, 0, w, h);
//设定透视方式
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,Width,0.0,Height);
}
//每桢OpenGL都会调用这个函数,用户应该把显示代码放在这个函数中
void display(void)
{
//设置清除屏幕的颜色,并清除屏幕
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,0.0f,0.0f);
if(iPointNum>=1){
glBegin(GL_LINES);
glVertex2i(x1,y1);
glVertex2i(x2,y2);
glEnd();
}
//交换前后缓冲区
glutSwapBuffers();
}
//用键盘的输入代替按下鼠标
void processNormalKeys(unsigned char key,int x,int y)
{
switch(key){
case 'p':
if(iPointNum==0||iPointNum==2){//屏幕上没有画或者画了都可以单击鼠标左键重新选第一个点
iPointNum=1;//确定直线段的第一个端点
x1=x;
y1=Height-y;
}else{//确定直线段的第二个端点
iPointNum=2;
x2=x;
y2=Height-y;
glutPostRedisplay();//指定窗口重新绘制
}
break;
default:break;
}
}
/*//按下鼠标的响应函数
void MousePlot(GLint button,GLint action,GLint xMouse,GLint yMouse)
{
if(button==GLUT_LEFT_BUTTON && action==GLUT_DOWN){
if(iPointNum==0||iPointNum==2){//屏幕上没有画或者画了都可以单击鼠标左键重新选第一个点
iPointNum=1;//确定直线段的第一个端点
x1=xMouse;
y1=Height-yMouse;
}else{//确定直线段的第二个端点
iPointNum=2;
x2=xMouse;
y2=Height-yMouse;
glutPostRedisplay();//指定窗口重新绘制
}
}
if(button==GLUT_RIGHT_BUTTON && action==GLUT_DOWN){//右击可以清屏
iPointNum=0;
glutPostRedisplay();
}
}*/
//没按鼠标时移动鼠标的回调函数,实现橡皮筋技术的地方
void PassiveMouseMove(GLint xMouse,GLint yMouse)
{
if(iPointNum==1){
x2=xMouse;
y2=Height-yMouse;
glutPostRedisplay();
}
}
//主函数
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
//初始化OPENGL显示方式
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA);
//设定OPENGL窗口位置和大小
glutInitWindowSize (400, 300);
glutInitWindowPosition (100, 100);
//打开窗口
glutCreateWindow ("橡皮筋技术");
//调用初始化函数
myinit();
//开始OPENGL的循环
glutDisplayFunc(display);
//设定窗口大小变化的回调函数
glutReshapeFunc(myReshape);
//鼠标响应函数
//glutMouseFunc(MousePlot);
//用键盘实现橡皮筋技术
glutKeyboardFunc(processNormalKeys);
//移动鼠标响应函数
glutPassiveMotionFunc(PassiveMouseMove);
glutMainLoop();
return 0;
}