OpenGL程序之用鼠标实现橡皮筋技术


前言

橡皮筋技术的关键在于控制图形随着用户的操作(以鼠标移动为例)而不断发生变化,此时需要擦除原有的图形同时生成新的图形。橡皮筋技术有两种实现方法:一种是利用颜色的异或操作,对原有图形不是擦除,而是再绘制一条同样的直线段并与原图形进行异或操作,此时原图形会从屏幕上消失;另一种是利用双缓存技术,绘制图形时分别绘制到两个缓存,交替显示。这里我们采用双缓存技术实现橡皮筋技术。

一、用鼠标实现橡皮筋技术的实现思路

如何感知鼠标的点击和移动

需要一个鼠标点击的响应函数;也需要一个鼠标移动的响应函数
要记录点击点的坐标和移动时的实时坐标,并进行相应的转化,使之正确地显示在界面上。

如何解决坐标对应的问题并使之显示在界面上

需要一个窗口再整形回调函数(处理坐标对应和窗口大小的问题);
需要一个绘制函数(画直线段和切换缓存)

整体的逻辑

1)在鼠标点击界面之前,页面将不显示任何内容;
2)当鼠标点击第一次,会确定第一个坐标,鼠标移动函数的实时状态的坐标会临时作为第二个坐标,此刻等于第一个坐标(重合为点),所以绘制函数也只能画成一个点,不过仍然会切换缓存,并清空OpenGL命令缓存区。
3)当鼠标点击第一次后移动,鼠标移动函数的坐标会随着鼠标的位置动态变化,并会动态存为第二个坐标,所以绘制函数画成的线也会动态的变化(模拟出橡皮筋的效果),每变一次就会切换一次缓存,并清空OpenGL命令缓存区。
4)当鼠标点击第二次,就会确定第二个坐标,鼠标移动函数的实时状态的坐标会临时作为第二个坐标,此刻等于第二个坐标,绘制函数便画出一条确定的线,会切换缓存,并清空OpenGL命令缓存区。
5)当鼠标点击第一次后移动,移动函数便不会起作用了。
6)当鼠标再一次点击,就会确定该点击点坐标为第一个坐标,同(1),原来的直线会在切换缓存,清空OpenGL命令缓存区中消失,如此往复下去
7)上面说到的都是点击鼠标左键,可以设置点击鼠标右键,将任意时刻作出的图(线、点)清空。

留给读者一个问题:在上面的描述中,我们可以发现有一个逻辑上的错误,就是我竟然在画了线之后才切换缓存,并清空OpenGL命令缓存区,其实在具体代码中确实是绘制的语句在前,切换的语句在后,而这与我们的常识理解不符,这便是OpenGL的特性了,如果感兴趣的话,大家可以自己去从原理上去了解深层次的原因。这里的逻辑描述是为了更好的转化成代码的思路,并不是我故意犯这个错哈,希望大家能够理解。

二、用鼠标实现橡皮筋技术的实现框架

1.鼠标响应函数

第一部分:点击响应函数

void MousePlot(GLint button, GLint action, GLint xMouse, GLint yMouse);
  • 1)参数button的取值是GLUT定义的3个鼠标按键符号常量
    • GLUT_LEFT_BUTTON左键
    • GLUT_MIDDLE_BUTTON中键(有才有效)
    • GLUT_RIGHT_BUTTON右键
  • 2)参数action的取值也是符号常量,可以为GLUT_DOWN,GLUT_UP确定鼠标按键的行为是按下还是松开状态。
  • 3)坐标(xMouse, yMouse)用于指定当前鼠标在窗口中相对于窗口左上角点的位置坐标
  • 值得注意的是OpenGL程序绘制图形时的坐标原点在窗口的左下角点,所以对y坐标要进行相应处理

使用:注册一个鼠标响应函数(对鼠标在窗口范围内的按键按下或松开事件的处理)

glutMouseFunc(MousePlot);

第二部分:移动响应函数

分别定义了一个鼠标移动响应函数,以获得鼠标在窗口中移动时的位置

void MouseMove(GLint xMouse, GLint yMouse);
void PassiveMouseMove(GLint xMouse, GLint yMouse);

使用:两个用于处理鼠标移动的注册函数

1)当一个或多个鼠标按键被按下时在窗口内移动的注册函数

glutMotionFunc(MouseMove);

2)当鼠标按键没有被按下时在窗口内移动的注册函数(本程序仅需这个)

glutPassiveMotionFunc(PassiveMouseMove);

2.利用鼠标实现橡皮筋技术

第一部分:双缓存

1)在指定窗口使用双缓存

glutInitDisplayMode
#include "stdafx.h" #include <GL/glut.h> #include <stdlib.h> #include <stdio.h> #define stripeImageWidth 32 GLubyte stripeImage[4 * stripeImageWidth]; #ifdef GL_VERSION_1_1 static GLuint texName; #endif void makeStripeImage(void) { int j; for (j = 0; j < stripeImageWidth; j++) { stripeImage[4 * j] = (GLubyte)((j <= 4) ? 255 : 0); stripeImage[4 * j + 1] = (GLubyte)((j>4) ? 255 : 0); stripeImage[4 * j + 2] = (GLubyte)0; stripeImage[4 * j + 3] = (GLubyte)255; } } /* planes for texture coordinate generation */ static GLfloat xequalzero[] = { 1.0, 0.0, 0.0, 0.0 }; static GLfloat slanted[] = { 1.0, 1.0, 1.0, 0.0 }; static GLfloat *currentCoeff; static GLenum currentPlane; static GLint currentGenMode; static float roangles; static float roangles1; float roangles2 = -2; float roangles3 = -3; void SpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_F1) roangles += 2.0f; roangles2 += 0.05; roangles3 += 1; if (key == GLUT_KEY_F2) roangles1 += 2.0f; if (roangles2 >= 3) roangles2 = -3; // 使用新的坐标重新绘制场景 glutPostRedisplay(); } void init(void) { glClearColor(1.0, 1.0, 1.0, 0.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); makeStripeImage(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); #ifdef GL_VERSION_1_1 glGenTextures(1, &texName;); glBindTexture(GL_TEXTURE_1D, texName); #endif glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifdef GL_VERSION_1_1 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage); #else glTexImage1D(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage); #endif glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); currentCoeff = xequalzero; currentGenMode = GL_OBJECT_LINEAR; currentPlane = GL_OBJECT_PLANE; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGenMode); glTexGenfv(GL_S, currentPlane, currentCoeff); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_1D); //glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glFrontFace(GL_CW); //glCullFace(GL_BACK); glMaterialf(GL_FRONT, GL_SHININESS, 64.0); roangles = 45.0f; roangles1 = 362.0f; } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glBegin(GL_QUADS); glColor3f(1, 0, 1); glVertex3f(-1, -1, 0); glColor3f(1, 0, 1); glVertex3f(-3, -1, 0); glColor3f(1, 0, 1); glVertex3f(1, -1, 0); glColor3f(1, 0, 1); glVertex3f(-1, -2, 0); glEnd(); glPopMatrix(); glPushMatrix(); glTranslated(roangles2, 2, -3); glRotatef(roangles, 0.0, 1.0, 0.0); #ifdef GL_VERSION_1_1 glBindTexture(GL_TEXTURE_1D, texName); #endif //glutSolidTeapot(2.0); glutSolidSphere(0.8, 32, 32); glPopMatrix(); glFlush(); glPushMatrix(); glTranslated(1, 2, -3); glRotatef(roangles1, 1.0, 0.0, 0.0); glRotatef(roangles3, 0.0, 1.0, 0.0); #ifdef GL_VERSION_1_1 glBindTexture(GL_TEXTURE_1D, texName); #endif //glutSolidTeapot(2.0); glTranslated(-1, -3, -0); glRotatef(90, 1.0f, 0.0f, 0.0f); glRotatef(180, 0.0f, 1.0f, 0.0f); glRotatef(-30, 0.0f, 0.0f, 1.0f); glutSolidCone(1, 2, 32, 32); glPopMatrix(); glFlush(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-3.5, 3.5, -3.5*(GLfloat)h / (GLfloat)w, 3.5*(GLfloat)h / (GLfloat)w, -3.5, 3.5); else glOrtho(-3.5*(GLfloat)w / (GLfloat)h, 3.5*(GLfloat)w / (GLfloat)h, -3.5, 3.5, -3.5, 3.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void idle() { roangles += 0.1f; glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc;, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(600, 600); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); //glutIdleFunc(idle); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutSpecialFunc(SpecialKeys); glutMainLoop(); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值