OpenGL实验一:画图小程序

2016-03-16  本文已影响3499人  Beatrice7

要求:开发一个画图程序,用户可以用鼠标绘制线段、矩形、圆和三角形等。通过菜单让用户选择需要绘制的图元。

框架参考

/* globals */
GLsizei wh = 500, ww = 500; /* initial window size */
float xm, ym, xmm, ymm;
int first = 0;
void mouse(int btn, int state, int x, int y)
{
    if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN)
    {
        xm = x;
        ym = wh-y;
        glColor3f(0.0, 0.0, 1.0);
        glLogicOp(GL_XOR);
        first = 0;
    }

    if(btn==GLUT_LEFT_BUTTON && state==GLUT_UP)
    {
        if (first == 1)
        {
            glRectf(xm, ym, xmm, ymm);
            glFlush();
        }

        xmm = x;
        ymm = wh-y;
        glColor3f(0.0, 1.0, 0.0);
        glLogicOp(GL_COPY);
        glRectf(xm, ym, xmm, ymm);
        glFlush();
    }

    if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN)  
        exit(0);
}

void move(int x, int y)
{
    if(first == 1)
    {
        glRectf(xm, ym, xmm, ymm);
        glFlush();
    }

    xmm = x;
    ymm = wh-y;
    glRectf(xm, ym, xmm, ymm);
    glFlush();
    first = 1;
}

void reshape(GLsizei w, GLsizei h)
{
    
    /* adjust clipping box */
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity(); 
    glOrtho(0.0,(GLdouble)w, 0.0,(GLdouble)h, -1.0, 1.0);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity(); 
    
    /* adjust viewport and clear */
    
    glViewport(0,0,w,h);
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glFlush();
    
    /* set global size for use by drawing routine */
    
    ww = w;
    wh = h; 
}

void init(void)
{
    glViewport(0,0,ww,wh);
    
    /* Pick 2D clipping window to match size of screen window 
    This choice avoids having to scale object coordinates
    each time window is resized */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity(); 
    glOrtho(0.0,(GLdouble) ww , 0.0,(GLdouble) wh , -1.0, 1.0);
    
    /* set clear color to black and clear window */
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glFlush();  

    glEnable(GL_COLOR_LOGIC_OP);
}


/* display callback required by GLUT 3.0 */
void display(void)
{}

int main(int argc, char** argv)
{
    /***GLUT窗口管理,就当做是固定写法吧***/
    glutInit(&argc,argv);                         //初始化GLUT,在调用其他GLUT函数前调用
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);  //设置窗口的显示模式
    glutInitWindowSize(ww, wh);                   //设置窗口的初始宽度和高度,单位为像素,缺省300x300
    glutInitWindowPosition(500, 500)              //窗口左上角相对于屏幕左上角的位置,单位为像素,缺省(0,0) 
    glutCreateWindow("rubber banding");           //创建窗口,标题为title。调用glutMainLoop()之前,窗口不会被显示
    
    init();  //设置OpenGL状态

    /***GLUT事件处理***/
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);
    glutMotionFunc(move);
    glutDisplayFunc(display);
    glutMainLoop();
}

OpenGL库

首先你会发现这些函数有些不是以gl开头就是以glut开头,以什么开头就代表是哪个库中的函数。

OpenGL函数名称格式

OpenGL函数名称格式

GLUT事件处理

我们这里界面都是采用GLUT库来写。GLUT使用回调函数(callback)机制来进行事件处理。

窗口

窗口是显示器上的一块矩形区域。窗口内的位置用窗口坐标来指定,单位是像素。

注意原点的位置

所以在画图的时候,我们要把鼠标位置的坐标转换成OpenGL命令中对应的坐标。原点在左上角和左下角相比较一下,不就是x坐标不用变,y坐标是个互补的关系嘛,用窗口的高度(wh)减掉鼠标位置的y坐标就得到OpenGL命令中的坐标啦。

画直线要求的橡皮条功能

这里用到一个函数glLogicOp

画圆

OpenGL没有提供直接画圆的函数,实现方式用一个多边形来逼近。大家都知道正多边形的边如越多越接近圆吧~
这里我用到了G_TRIANGLE_FAN这个参数,书上都有讲解。
截取一部分代码:

if (btn == GLUT_LEFT_BUTTON && state == GLUT_UP)
    {
        xmm = x;
        ymm = wh - y;
        float r = sqrt(pow((xm - xmm), 2) + pow((ym - ymm), 2));
        glBegin(GL_TRIANGLE_FAN);
        for (int i = 0; i< 1000; ++i){
            glVertex2f(xm + r*cos(2 * PI / 1000 * i), ym + r*sin(2 * PI / 1000 * i));
        }
        glEnd();
        glFlush();
    }

画三角形

简单的一个实现的思路:用一个变量将三个点的坐标保存起来,每点击一次鼠标记录一个位置并计数,当点数满三个的时候,就把这个三角形画出来。
截取一部分代码:

void mouse_triangle(int btn, int state, int x, int y)
{
    if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        triVertex[ver][0] = x;
        triVertex[ver][1] = wh - y;
        glColor3f(1.0, 0.5, 0.0);
        glBegin(GL_POINTS);
        glVertex2f(triVertex[ver][0], triVertex[ver][1]);
        glEnd();
        glFlush();
        ver++;
        if (ver == 3)
        {   
            //glLogicOp(GL_COPY);//直接用源像素取代目标像素 默认的
            glBegin(GL_TRIANGLES);
            glVertex2f(triVertex[0][0], triVertex[0][1]);
            glVertex2f(triVertex[1][0], triVertex[1][1]);
            glVertex2f(triVertex[2][0], triVertex[2][1]);
            glEnd();
            glFlush();
            ver = 0;
        }

    }
}

添加菜单

用到如下的三个函数,比如:

    glutCreateMenu(menu); //创建菜单
    glutAddMenuEntry("line", 0);  //在菜单中添加选项
    glutAddMenuEntry("square", 1);
    glutAddMenuEntry("triangle", 2);
    glutAddMenuEntry("circle", 3);
    glutAddMenuEntry("clear", 4);
    glutAttachMenu(GLUT_RIGHT_BUTTON); //将菜单绑定鼠标操作
上一篇 下一篇

猜你喜欢

热点阅读