openGL学习笔记3

第三章主要就是与程序进行交互

首先来个简单的点击的程序,然后是作业题。

【题目描述】

  绘制出红色、蓝色部分重叠矩形,鼠标点击相应区域,根据指针所覆盖5像素内方形块中对应的对象对其进行高亮,点击背景均恢复原状。

【分析】

  基础的点击然后程序给出反应。需要利用鼠标回调函数、名字栈、拾取和选择、可选键盘回调函数,开始接触到一些reshape回调函数中各类矩阵的设置了。

【代码】

  1 //绘制出红色、蓝色部分重叠矩形,鼠标点击相应区域,根据指针所覆盖5像素内方形块中对应的对象对其进行高亮,点击背景均恢复原状。
  2 
  3 #include <stdlib.h>
  4 #include <stdio.h>
  5 #include <GL/glut.h>
  6 
  7 GLint now;
  8 
  9 void init()
 10 {
 11     now=0;
 12    glClearColor (0.0, 0.0, 0.0, 0.0);
 13 }
 14 
 15 void drawObjects(GLenum mode)
 16 {
 17     GLdouble color1=0.5,color2=0.5;
 18     if (now==1)
 19         color1=1.0;
 20     else if (now==2)
 21         color2=1.0;
 22     else if (now==3)
 23         color1=color2=1.0;
 24     if(mode == GL_SELECT) glLoadName(1);
 25     glColor3f(color1, 0.0, 0.0);
 26     glRectf(-0.5, -0.5, 1.0, 1.0);
 27     if(mode == GL_SELECT) glLoadName(2);
 28     glColor3f(0.0, 0.0, color2);
 29     glRectf(-1.0, -1.0, 0.5, 0.5);
 30 }
 31 
 32 void display()
 33 {
 34     glClear(GL_COLOR_BUFFER_BIT);
 35     drawObjects(GL_RENDER);
 36     glFlush();
 37 }
 38 
 39 void processHits (GLint hits, GLuint buffer[])
 40 {
 41    unsigned int i, j;
 42    GLint names, *ptr;
 43    ptr = (GLint *) buffer; 
 44    if (hits==2)
 45       {now=3;return;}
 46    if (hits==0)
 47       {now=0;return;}
 48    for (i = 0; i < hits; i++) {    //  for each hit  
 49       names = *ptr;
 50       ptr+=3;
 51       for (j = 0; j < names; j++) { //  for each name 
 52          if(*ptr==1) now=1;
 53          else now=2;
 54          ptr++;
 55       }
 56    }
 57 }
 58 
 59 #define SIZE 512
 60 
 61 void mouse(int button, int state, int x, int y)
 62 {
 63    GLuint selectBuf[SIZE];
 64    GLint hits;
 65    GLint viewport[4];
 66 
 67    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 
 68    {
 69    glGetIntegerv (GL_VIEWPORT, viewport);
 70 
 71    glSelectBuffer (SIZE, selectBuf);
 72    glRenderMode(GL_SELECT);
 73 
 74    glInitNames();
 75    glPushName(0);
 76 
 77    glMatrixMode (GL_PROJECTION);
 78    glPushMatrix ();
 79    glLoadIdentity ();
 80 //  5像素方形选择区域
 81    gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 
 82                   5.0, 5.0, viewport);
 83    gluOrtho2D (-2.0, 2.0, -2.0, 2.0);
 84    drawObjects(GL_SELECT);
 85 
 86 
 87    glMatrixMode (GL_PROJECTION);
 88    glPopMatrix ();
 89    glFlush ();
 90 
 91    hits = glRenderMode (GL_RENDER);
 92    processHits (hits, selectBuf);
 93 
 94    glutPostRedisplay();
 95    }
 96 } 
 97 
 98 
 99 void reshape(int w, int h)
100 {
101    glViewport(0, 0, w, h);
102    glMatrixMode(GL_PROJECTION);
103    glLoadIdentity();
104    gluOrtho2D (-2.0, 2.0, -2.0, 2.0);
105    glMatrixMode(GL_MODELVIEW);
106    glLoadIdentity();
107 }
108 
109 int main(int argc, char** argv)
110 {
111    glutInit(&argc, argv);
112    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
113    glutInitWindowSize (500, 500);
114    glutInitWindowPosition (100, 100);
115    glutCreateWindow (argv[0]);
116    init ();
117    glutReshapeFunc (reshape);
118    glutDisplayFunc(display); 
119    glutMouseFunc (mouse);
120    glutMainLoop();
121    return 0; 
122 }

 【效果】

3.14作业题:

【题目描述】

创建一个简单的绘制程序,使得可用鼠标来创建一些简单的形状,如线段矩形和三角形,并可通过菜单来选择各种

模式,并允许用户改变绘制颜色。

附加功能:按CTRL+点击已绘制图像可高亮显示,CTRL+点击背景取消所有高亮

【分析】

没有曲线,都是基本图元,很好绘制。

通过创建一个list来进行display,每个元素是一个结构:颜色,点数组,绘制形式。

改变颜色功能只需要修改当前颜色nowcolor即可。

至于CTRL高亮和恢复:用到渲染模式和选择模式:在鼠标回调中用gluPickMatrix拾取区域,hit来记录命中,利用名字空间处理重叠图元,修改对应结构中的颜色,再glutRedispaly即可高亮和恢复。

还有更多可添加的功能:比如绘制线段时确定一个端点后鼠标移动,相应线段会即时显示,可以用鼠标移动的函数进行处理。

【代码】

  1 /*创建一个简单的绘制程序,使得可用鼠标来创建一些简单的形状,如线段矩形和三角形,并可通过菜单来选择各种
  2 模式,并允许用户改变绘制颜色。
  3 附加功能:按CTRL+点击已绘制图像可高亮显示,CTRL+点击背景取消所有高亮*/
  4 #include <stdlib.h>
  5 #include <stdio.h>
  6 #include <GL/glut.h>
  7 #define MAX 10000
  8 #define SIZE 512//buffer尺寸
  9  struct graphic
 10 {
 11     int type;//1=线段 2=矩形 3=三角形
 12     GLfloat color[3];
 13     GLfloat point[3][3];
 14     GLenum mode;
 15 }showlist[MAX];
 16 //count 0不用 type 0不用 showlist 0不用 last 0不用       color 0用 point 0用 hisnow 0用 
 17 GLint count,hitsmax,hitsnow,nowtype,last[MAX],lastcount;//last:已高亮节点记录,带now的为当前绘制记录
 18 GLenum nowmode;
 19 GLfloat nowcolor[3],nowpoint[3][3],neww,newh;
 20 
 21 void mymenu(int value)
 22 {
 23     if (value==1)
 24     {nowtype=1;hitsmax=2;hitsnow=0;}
 25     else if (value==2)
 26     {nowtype=2;hitsmax=2;hitsnow=0;}
 27     else if (value==3)
 28     {nowtype=3;hitsmax=3;hitsnow=0;}
 29     else if (value==4)
 30     {
 31         glClear(GL_COLOR_BUFFER_BIT);
 32         glFlush();
 33     }
 34 }
 35 void drawObjects(GLenum mode)
 36 {
 37     GLint i;
 38     for (i=1;i<=count;i++)
 39     {
 40     if(mode == GL_SELECT) glLoadName(i);//如果是进入了选择模式,则给名称,从1开始
 41     glColor3fv(showlist[i].color);//设置当前绘制颜色
 42     glPolygonMode(GL_FRONT_AND_BACK,showlist[i].mode);//设置当前绘制模式
 43     if (showlist[i].type==1)//线段
 44     {
 45         glBegin(GL_LINES);
 46           glVertex2fv(showlist[i].point[0]);
 47           glVertex2fv(showlist[i].point[1]);
 48         glEnd();
 49     }
 50     else if (showlist[i].type==2)//矩形
 51     {
 52         glRectfv(showlist[i].point[0],showlist[i].point[1]);
 53     }
 54     else if (showlist[i].type==3)//三角形
 55     {
 56         glBegin(GL_POLYGON);
 57           glVertex2fv(showlist[i].point[0]);
 58           glVertex2fv(showlist[i].point[1]);
 59           glVertex2fv(showlist[i].point[2]);
 60         glEnd();
 61     }
 62     }
 63 }
 64 void submenu1(int value)
 65 {
 66     if (value==1)
 67         nowmode=GL_FILL;
 68     else
 69         nowmode=GL_LINE;
 70 }
 71 void submenu2(int value)
 72 {
 73     if (value==1)
 74     {nowcolor[0]=0.5;nowcolor[1]=0.5;nowcolor[2]=0.5;}
 75     else
 76     {nowcolor[0]=0.5;nowcolor[1]=0;nowcolor[2]=0;}
 77 }
 78 
 79 void init()
 80 {
 81    int id1,id2;
 82    hitsmax=hitsnow=nowtype=count=lastcount=0;//初始化各种数据
 83    glClearColor (0.3, 0.1, 0.5, 0.0);
 84    nowcolor[0]=0.5;nowcolor[1]=0.5;nowcolor[2]=0.5;
 85    nowmode=GL_FILL;
 86 
 87    //菜单初始化
 88    id1=glutCreateMenu(submenu1);//次1
 89    glutAddMenuEntry("填充",1);
 90    glutAddMenuEntry("勾勒",2);
 91    id2=glutCreateMenu(submenu2);//次2
 92    glutAddMenuEntry("白色",1);
 93    glutAddMenuEntry("红色",2);
 94    glutCreateMenu(mymenu);//主菜单
 95    glutAddMenuEntry("创建线段",1);
 96    glutAddMenuEntry("创建矩形",2);
 97    glutAddMenuEntry("创建三角形",3);
 98    glutAddSubMenu("选择模式(默认填充)",id1);
 99    glutAddSubMenu("改变颜色(默认白色)",id2);
100    glutAddMenuEntry("清屏",4);
101    glutAttachMenu(GLUT_RIGHT_BUTTON);
102 
103 }
104 
105 void display()
106 {
107     glClear(GL_COLOR_BUFFER_BIT);
108     drawObjects(GL_RENDER);
109     glFlush();
110 }
111 
112 void change(int i)//高亮函数
113 {
114     lastcount++;
115     last[lastcount]=i;
116     if (showlist[i].color[1]==0.0)
117         showlist[i].color[0]=1.0;//红色
118     else //白色
119     {
120         showlist[i].color[0]=1.0;
121         showlist[i].color[1]=1.0;
122         showlist[i].color[2]=1.0;
123     }
124 
125 }
126 void recovery()//高亮恢复函数
127 {
128     for (;lastcount>0;lastcount--)
129     {
130         if (showlist[last[lastcount]].color [1]==0.0)//亮红
131             showlist[last[lastcount]].color [0]=0.5;
132         else //亮白
133         {
134             showlist[last[lastcount]].color[0]=0.5;
135             showlist[last[lastcount]].color[1]=0.5;
136             showlist[last[lastcount]].color[2]=0.5;
137         }
138     }
139 }
140 
141 void processHits (GLint hits, GLuint buffer[])//hits处理函数
142 {
143    unsigned int i, j;
144    GLint names, *ptr;
145    ptr = (GLint *) buffer; 
146    if (hits==0)//如果按ctrl+点击背景,则取消所有高亮
147    {recovery();return;}
148    for (i = 0; i < hits; i++) {    //命中覆盖对象个数
149       names = *ptr;
150       ptr+=3;
151       for (j = 0; j < names; j++) { //对于每个对象(名称为索引)
152           change(*ptr);//高亮
153          ptr++;
154 
155       }
156    }
157 }
158 void mouse(int button, int state, int x, int y)
159 {
160    GLuint selectBuf[SIZE];
161    GLint hits,i,j;
162    GLint viewport[4];
163    glGetIntegerv (GL_VIEWPORT, viewport);
164    if (glutGetModifiers ()==GLUT_ACTIVE_CTRL && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//CTRL+点击=高亮
165    {
166    recovery();//对已高亮元素进行恢复
167    glSelectBuffer (SIZE, selectBuf);
168    glRenderMode(GL_SELECT);
169 
170    glInitNames();
171    glPushName(0);//初始化名称堆栈等
172 
173    glMatrixMode (GL_PROJECTION);
174    glPushMatrix ();
175    glLoadIdentity ();    
176    //  5像素精度指针选择区域
177    gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 
178                   5.0, 5.0, viewport);
179    gluOrtho2D (0, neww, 0, newh);
180    drawObjects(GL_SELECT);
181 
182 
183    glMatrixMode (GL_PROJECTION);
184    glPopMatrix ();
185    glFlush ();
186 
187    hits = glRenderMode (GL_RENDER);//回渲染,处理hit
188    processHits (hits, selectBuf);
189    }
190    else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//绘制
191    {
192        nowpoint[hitsnow][0]=(GLdouble) x;
193        nowpoint[hitsnow][1]=(GLdouble) (viewport[3] - y);
194        hitsnow++;
195        if (hitsnow==hitsmax)//点数已达到绘制要求,存储当前点到showlist
196        {
197            count++;
198            for (i=0;i<3;i++)
199            {
200                showlist[count].color[i]=nowcolor[i];
201                for (j=0;j<2;j++)
202                    showlist[count].point[i][j]=nowpoint[i][j];
203            }
204            showlist[count].type=nowtype;
205            showlist[count].mode=nowmode;
206            hitsnow=0;
207        }
208    }
209    glutPostRedisplay();
210 } 
211 
212 
213 void reshape(int w, int h)//改变形状时重新设置视口、投影、裁剪
214 {
215    glViewport(0, 0, w, h);
216    glMatrixMode(GL_PROJECTION);
217    glLoadIdentity();
218    gluOrtho2D (0, w, 0, h);
219    neww=w;
220    newh=h;//把WH传给全局变量,供给hit函数的裁剪,来保证改变了窗口大小仍能使用所有功能
221    glMatrixMode(GL_MODELVIEW);
222    glLoadIdentity();
223 }
224 int main(int argc, char** argv)
225 {
226    glutInit(&argc, argv);
227    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);//初始化
228    glutInitWindowSize (500, 500);
229    glutInitWindowPosition (200,200);
230    glutCreateWindow ("绘图");
231    init ();
232    glutReshapeFunc (reshape);//改变形状回调
233    glutDisplayFunc(display); //显示回调
234    glutMouseFunc (mouse);//鼠标回调
235    glutMainLoop();
236    return 0; 
237 }

【效果】

 

——————————————————————————心得———————————————————————————————————

1.要理解屏幕、视口、投影和世界的关系,在改变窗口大小后仍然能够绘制,注意Reshape函数里的内容

2.使用到的知识有:鼠标交互、菜单、类似显示列表、图元的各种参数设置、各种回调、渲染选择模式

3.曾经遇到显示不出来任何图像,然后改变窗口大小后发现原来是绘制出来了的,原因在于视口调整

4.在修改了参数后一定要GlutPostRedisplay重绘,不然不会发生变化的。

posted on 2014-04-26 12:51  BWB  阅读(758)  评论(0编辑  收藏  举报

导航