用OpenGL实现折线和矩形的橡皮筋绘制技术(可完全脱离鼠标)

        这学期开始学计算机图形学基础,课后有个习题让用OpenGL实现折线和矩形的橡皮筋绘制技术,只要求了用右键菜单实现功能的选择。老师嫌有些简单,就说要加上教材上基于键盘实现的代码,可教材上的代码还是要先把鼠标移到一个点上,再用按键确定这个点,这样配合着使用很别扭。我想既然用键盘了,不如直接写个可以完全由键盘控制绘图过程的代码吧。

        正好现在我想学下Python,就决定拿这道题开始练手。代码虽然很简单,但写的过程中,一边要学Python的语法,一边又要查OpenGL的库函数,还是挺费精力的。这算是我第一次用Python写代码,结果还算满意,写个博客纪念下吧。

        程序用鼠标完成绘图就不用说了。键盘方面  A、D、W、X 用于移动窗口内的点,P用于选定某一点,L、 R、 C 分别为菜单各功能的快捷键,用于选择画折线、画矩形或清除图形。所有按键不区分大小写。为了使程序使用方便,键盘和鼠标没做什么限制,既可以分别使用,也可以结合使用。代码如下:


#!/usr/bin/python
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

iMode=1
winWidth = 800; winHeight = 600
num = 0; a = [0]*100; b = [0]*100
w1 = 200; h1 = 500; w2 = 200; h2 = 500
iPointNum = 0; x1 = 200; y1 = 500; x2 = 200; y2 = 500

def ChangeSize(w, h): 
    global winWidth, winHeight
    winWidth = w
    winHeight = h
    glViewport(0, 0, w, h)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0.0, winWidth, 0.0, winHeight)

def ProcessMenu(value):
    global iMode
    iMode = value
    glutPostRedisplay()

def DrawPoint(x , y):
    glClear(GL_COLOR_BUFFER_BIT)
    glPointSize(1.5)
    glBegin(GL_POINTS)
    glVertex2i(x, y)
    glEnd()
    glutSwapBuffers()


def Draw():
    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClear(GL_COLOR_BUFFER_BIT)
    glColor3f(1.0, 0.0, 0.0)
    
    global num, iMode, w1, h1, w2, h2, x1, x2, y1, y2, iPointNum, a, b
    #Line
    if iMode == 1:
        glBegin(GL_LINE_STRIP)
        for i in range(0, num):
            glVertex2i(a[i], b[i])
        glEnd()
    
        if num > 0:  
            glBegin(GL_LINES)
            glVertex2i(w1, h1)
            glVertex2i(w2, h2)
            glEnd()

    #Rectangle    
    elif iMode == 2 and iPointNum > 0:
        glBegin(GL_LINES)
        glVertex2i(x1, y1)
        glVertex2i(x2, y1)
        glEnd()

        glBegin(GL_LINES)
        glVertex2i(x1, y1)
        glVertex2i(x1, y2)
        glEnd()

        glBegin(GL_LINES)
        glVertex2i(x2, y1)
        glVertex2i(x2, y2)
        glEnd()

        glBegin(GL_LINES)
        glVertex2i(x1, y2)
        glVertex2i(x2, y2)
        glEnd()

    elif iMode == 3:
        num = 0
        iPointNum = 0
        w1 = w2 = x1 = x2 = 200
        h1 = h2 = y1 = y2 = 500
    
    glutSwapBuffers()

def MousePlot(button, action, xMouse, yMouse):
    global num, iMode, winHeight, w1, h1, w2, h2, x1, x2, y1, y2, iPointNum, a, b
    if iMode == 1:
    	if button == GLUT_LEFT_BUTTON and action == GLUT_DOWN:
	    if num == 0:
		w1 = xMouse
		h1 = winHeight - yMouse
		a[num] = w1; b[num] = h1
		num += 1
	    else:
                w2 = xMouse
                h2 = winHeight - yMouse
		a[num] = w2; b[num] = h2
		num += 1
		w1 = w2; h1 = h2
		glutPostRedisplay()				
	elif button == GLUT_RIGHT_BUTTON and action == GLUT_DOWN:
	    num = 0
	    glutPostRedisplay()
	
    elif iMode == 2:
	if button == GLUT_LEFT_BUTTON and action == GLUT_DOWN:
	    if iPointNum == 0 or iPointNum == 2:
		iPointNum = 1
		x1 = xMouse
		y1 = winHeight - yMouse
            else:
	        iPointNum = 2
	        x2 = xMouse
	        y2 = winHeight - yMouse
	        glutPostRedisplay()
	elif button == GLUT_RIGHT_BUTTON and action == GLUT_DOWN:
	    iPointNum = 0

def Key(key, xMouse, yMouse):
    global num, iMode, winWidth, winHeight, w1, h1, w2, h2, x1, x2, y1, y2, iPointNum
    #python has no switch statements
    if key == 'l' or key == 'L':
        iMode = 1
        glutPostRedisplay()

    elif key == 'r' or key == 'R':
        iMode = 2
        glutPostRedisplay()

    elif key == 'c' or key =='C':
        iMode = 3
        glutPostRedisplay()

    elif key == 'p' or key == 'P':
        if iMode == 1:
            if num == 0:
                a[num] = w1; b[num] = h1
                num += 1
            else:
                a[num] = w2; b[num] = h2
                num += 1
                w1 = w2; h1 = h2
                glutPostRedisplay()
        
        elif iMode == 2:
            if iPointNum == 0 or iPointNum == 2:
                iPointNum = 1
            else:
                iPointNum = 2
                glRecti(x1, y1, x2, y2)
                glutSwapBuffers()

    elif key == 'a' or key == 'A':
        if iMode == 1:
            if num == 0:
                if w1 >= 5:
                    w1 -= 5
                DrawPoint(w1, h1)
            else:
                if w2 >= 5:
                    w2 -= 5
                    glutPostRedisplay()

        elif iMode == 2:
            if iPointNum == 0 or iPointNum == 2:
                if x1 >= 5:
                    x1 -= 5
                DrawPoint(x1, y1)
            else:
                if x2 >= 5:
                    x2 -= 5
                glutPostRedisplay()
    elif  key == 'd' or key == 'D':
        if iMode == 1:
            if num == 0:
                if w1 <= winWidth - 5:
                    w1 += 5
                DrawPoint(w1, h1)
            else:
                if w2 <= winWidth - 5:
                    w2 += 5
                    glutPostRedisplay()

        elif iMode == 2:
            if iPointNum == 0 or iPointNum == 2:
                if x1 <= winWidth - 5:
                    x1 += 5                
                DrawPoint(x1, y1)
            else:
                if x2 <= winWidth - 5:
                    x2 += 5
                glutPostRedisplay()

    elif  key == 'w' or key == 'W':
        if iMode == 1:
            if num == 0:
                if h1 <= winHeight - 5:
                    h1 += 5
                DrawPoint(w1, h1)
            else:
                if h2 <= winHeight - 5:
                    h2 += 5
                    glutPostRedisplay()

        elif iMode == 2:
            if iPointNum == 0 or iPointNum == 2:
                if y1 <= winHeight - 5:
                    y1 += 5
                DrawPoint(x1, y1)
            else:
                if y2 <= winHeight - 5:
                    y2 += 5
                glutPostRedisplay()

    elif  key == 'x' or key == 'X':
        if iMode == 1:
            if num == 0:
                if h1 >= 5:
                    h1 -= 5
                DrawPoint(w1, h1)
            else:
                if h2 >= 5:
                    h2 -= 5
                    glutPostRedisplay()

        elif iMode == 2:
            if iPointNum == 0 or iPointNum == 2:
                if y1 >= 5:
                    y1 -= 5
                DrawPoint(x1, y1)
            else:
                if y2 >= 5:
                    y2 -= 5
                glutPostRedisplay()
        
def PassiveMouseMove(xMouse, yMouse):
    global iMode, num, w2, h2, x1, y1, x2, y2, winHeight, iPointNum
    if iMode == 1:
	if num > 0:
	    w2 = xMouse
	    h2 = winHeight - yMouse
	    glutPostRedisplay()

    elif iMode == 2:
	if iPointNum == 1:
	    x2 = xMouse
	    y2 = winHeight - yMouse
	    glutPostRedisplay()
        elif iPointNum == 2:
            glRecti(x1, y1, x2, y2)
            glutSwapBuffers()

glutInit()
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA)
glutInitWindowSize(800, 600)
glutInitWindowPosition(100, 100)
glutCreateWindow("3-11 Line and Rectangle")
glutCreateMenu(ProcessMenu)
glutAddMenuEntry("Line(L)", 1)
glutAddMenuEntry("Rectangle(R)", 2)
glutAddMenuEntry("Clear(C)", 3)
glutAttachMenu(GLUT_RIGHT_BUTTON)
glutDisplayFunc(Draw)
glutReshapeFunc(ChangeSize)
glutKeyboardFunc(Key)
glutMouseFunc(MousePlot)
glutPassiveMotionFunc(PassiveMouseMove)
glutMainLoop()

#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、付费专栏及课程。

余额充值