代码分析

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

200782201.jpg

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

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=
{
//各个窗口的左上角坐标
  {50150},            /* win 0  */
  {
450150},           /* win 1  */
  {
50600},            /* win 2  */
  {
450600},           /* win 3  */
  {
1010},             /* subwin 4 (relative to parent win 0) */
  {
300400},           /* help win 5  */
  {
850150},           /* cmap win 6  */
  {
850600},           /* cmap win 7  */
  {
250450}            /* text win 8  */
};
int size[MAXWIN][2=
{
//各个窗口大小(宽度,高度)
  {350350},           /* win 0  */
  {
350350},           /* win 1  */
  {
350350},           /* win 2  */
  {
350350},           /* win 3  */
  {
200200},           /* subwin 4  */
  {
700300},           /* help win 5  */
  {
350350},           /* cmap win 6  */
  {
350350},           /* cmap win 7  */
  {
800450}            /* 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发生的,在这里进行了实际的旋转和平移动作。

鼠标控制

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




posted on   Phinecos(洞庭散人)  阅读(2030)  评论(6编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述

导航

统计

点击右上角即可分享
微信分享提示