代码分析

      这是susu给我的一份关于glut的示例代码,里面涉及到的内容有:用glut来完成菜单管理,文本显示,显示列表,材质,光照,多窗口显示,鼠标事件处理,键盘事件处理,菜单事件处理,窗口创建,缩放,销毁,动画播放,定时器等功能,运行效果如图:

代码分析_第1张图片

      我分成几个部分来对代码进行分析:

1,命令行参数检查

void  checkArgs( int  argc,  char   * argv[])
{
  
int  argp;
  GLboolean quit 
=  GL_FALSE;
  GLboolean error 
=  GL_FALSE;
#define  AA argv[argp]
  argp 
=   1 ;
  
while  (argp  <  argc)
  {
    
if  (match(AA,  " -help " ))
    {
      commandLineHelp();
      quit 
=  GL_TRUE;
    } 
    
else   if  (match(AA,  " -version " ))
    {
      printf(VERSIONLONG 
" \n " );
      quit 
=  GL_TRUE;
    } 
    
else   if  (match(AA,  " -auto " ))
    {
// 自动运行
      demoMode  =  GL_TRUE;
    } 
    
else   if  (match(AA,  " -scale " ))
    {
// 放缩
      argp ++ ;
      scaleFactor 
=  atof(argv[argp]); // 设置缩放因子
    } 
    
else  
    {
// 出错处理
      fprintf(stderr,  " Unknown arg: %s\n " , AA);
      error 
=  GL_TRUE;
      quit 
=  GL_TRUE;
    }
    argp
++ ;
  }
GLboolean match(
char   * arg,  char   * t)
{
  
if  (strstr(t, arg))
    
return  GL_TRUE;
  
else
    
return  GL_FALSE;
}
  
if  (error) 
  {
    commandLineHelp();
    exit(
1 );
  }
  
if  (quit)
    exit(
0 );
}

这里match函数考虑到-help可能被输入为-h等形式,因此用的是strstr而不是strcmp来进行字符串的匹配。

2,窗口的缩放

通过对窗口原点和大小的调整就可以实现窗口的缩放。

int  pos[MAXWIN][ 2 =
{
// 各个窗口的左上角坐标
  { 50 150 },             /*  win 0   */
  {
450 150 },            /*  win 1   */
  {
50 600 },             /*  win 2   */
  {
450 600 },            /*  win 3   */
  {
10 10 },              /*  subwin 4 (relative to parent win 0)  */
  {
300 400 },            /*  help win 5   */
  {
850 150 },            /*  cmap win 6   */
  {
850 600 },            /*  cmap win 7   */
  {
250 450 }             /*  text win 8   */
};
int  size[MAXWIN][ 2 =
{
// 各个窗口大小(宽度,高度)
  { 350 350 },            /*  win 0   */
  {
350 350 },            /*  win 1   */
  {
350 350 },            /*  win 2   */
  {
350 350 },            /*  win 3   */
  {
200 200 },            /*  subwin 4   */
  {
700 300 },            /*  help win 5   */
  {
350 350 },            /*  cmap win 6   */
  {
350 350 },            /*  cmap win 7   */
  {
800 450 }             /*  text win 8   */
};
void  scaleWindows( float  scale)
{
// 放缩初始窗口大小和位置 
   int  i;
  
for  (i  =   0 ; i  <  MAXWIN; i ++ )
  {
    pos[i][
0 =  pos[i][ 0 *  scale; // x坐标
    pos[i][ 1 =  pos[i][ 1 *  scale; // y坐标
    size[i][ 0 =  size[i][ 0 *  scale; // 宽度
    size[i][ 1 =  size[i][ 1 *  scale; // 高度
  }
}

3,设置显示模式、

Int型的数组modes用来记录各个模式位的值(0或者1),从而表明窗口是否支持这种模式。displayMode |= glutMode[i];通过这样的按位或运算最终获得窗口的显示模式。

int  modes[MODES]  = { 0 };
modes[RGBA] 
=   1 ;
  modes[DOUBLEBUFFER] 
=   1 ;
  modes[DEPTH] 
=   1 ;
  setInitDisplayMode()
void  setInitDisplayMode( void )
{
// 设置初始显示模式
   int  i;
  displayMode 
=   0 ;
  
for  (i  =   0 ; i  <  MODES; i ++ ) {
    
if  (modes[i]) {
      
/*  printf("Requesting %s \n", modeNames[i]);   */
      displayMode 
|=  glutMode[i]; // 进行按位或运行,
    }
  }
  glutInitDisplayMode(displayMode);
  createMenu6();
  
if  ( ! glutGet(GLUT_DISPLAY_MODE_POSSIBLE))
    warning(
" This display mode not supported\n " );
}

4,菜单管理

menu1menu88int型变量用来保存创建的菜单项,并且menu2menu8都作为menu1的子菜单加入到menu1中。

创建菜单

5,创建窗口

本文中创建的窗口有4种类型,第1种是普通的RGB窗口,用来显示要绘制的图形,第2种是第1种窗口的子窗口(类似于画中画的效果),第3种是文本窗口和帮助窗口,第4种是颜色索引窗口。设置好窗口的显示模式,并根据保存的窗口大小和位置创建完窗口后,就可以对窗口进行OpenGL绘制的初始化工作,这是在gfxInit函数中完成的,最后就是为窗口加上各种事件处理函数。

创建窗口

为每个窗口初始化OpenGL时,首先通过redefineShapes为窗口建立其显示列表,然后渲染其背景矩阵,接着进行投影变换和视图变换,为了简单起见,作者采用了默认的白色光源来进行材质和光源位置的设置,最后就是启用光照并设置窗口的背景颜色。

OpenGL初始化

6,动画效果

我在MFC中是通过设置一个定时器,并且在定时方法中修改旋转角度来刷新屏幕的,从而实现动画旋转的效果,在这里作者把这部分代码放到窗口的空闲事件处理函数中进行。每次执行时角度都进行了变换,并且通知窗口强制其重绘。

/*  idleFunc - GLUT idle func callback - animates windows  */
void  idleFunc( void )
{
  
int  i;
  
if  ( ! leftDown  &&   ! middleDown) // 旋转角度加1
    angle  +=   1 ;
    angle 
=  angle  %   360 ;
  
for  (i  =   0 ; i  <  MAXWIN; i ++ )
  {
    
if  (winId[i]  &&  winVis[i]  &&   ! winFreeze[i]) 
    {
      glutSetWindow(winId[i]);
      glutPostRedisplay();
// 强制重画
    }
  }
}

7,自动演示

这里采用了一个小的技巧来实现多个窗口连续创建的自动演示功能。通过执行当前的动作后,为下一个应该接着发生的动作设置一个定时器,从而实现动作之间的接连发送效果。

旋转动画

8,图形绘制代码部分

所有窗口都使用drawScene来绘制其图形,只是各个窗口调用的显示列表不同而已,这通过各个窗口的标识符来进行区别,并且通过调用trackBall(APPLY, 0, 0, 0, 0);来绘制鼠标左键控制的结果(旋转后的角度或者平移后的距离),如果窗口还有文本要显示,则调用showText来显示文本信息。

图形绘制代码

9.文本显示

这里有两种文本的显示方式,第一种采用位图字体来显示文本,第二种采用Stroke 字体来显示文本。

void  textString( int  x,  int  y,  char   * msg,  void   * font)
{
// 显示文本,x,y是起始坐标,msg:要显示的文本,font:显示的字体
  glRasterPos2f(x, y); // 定位位图字体
   while  ( * msg)
  {
    glutBitmapCharacter(font, 
* msg);
    msg
++ ;
  }
}

/*  strokeString - Stroke font string  */
void  strokeString( int  x,  int  y,  char   * msg,  void   * font)
{
  glPushMatrix();
  glTranslatef(x, y, 
0 );
  glScalef(.
04 , . 04 , . 04 );
  
while  ( * msg) 
  {
    glutStrokeCharacter(font, 
* msg);
    msg
++ ;
  }
  glPopMatrix();
}

10,显示列表

显示列表由于是已经编译好的代码段,因此可以加快程序的速度。这里每种要绘制的图形(如球,茶壶等)都有实体和虚体两种模式可以选择。

显示列表

11,鼠标事件处理

这里鼠标有三种控制方式,1)左键进行旋转。2)中键进行xy平面的平移。3)左键+中键进行关于Z轴的平移(产生缩放的效果)。鼠标的事件模式这里有RESETMOUSEBUTTONAPPLY MOUSEMOTION四种,其中RESET是用来对清空以往的操作,让图形回到原点处。MOUSEBUTTON是鼠标按下激发的,用来记录下鼠标的位置,MOUSEMOTION是鼠标按下后并移动鼠标时,用来计算旋转的角度或者平移的距离,而最终这些变换后产生的效果的绘制是APPLY发生的,在这里进行了实际的旋转和平移动作。

鼠标控制

最后,代码中还加入了对空间球,图形板,拨号按键盒的事件处理支持。




你可能感兴趣的:(代码)