天天看点

代码分析

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

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

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");

    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;

    }

    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)

{//设置初始显示模式

  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,菜单管理

menu1到menu8这8个int型变量用来保存创建的菜单项,并且menu2到menu8都作为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)

  if (!leftDown && !middleDown)//旋转角度加1

    angle += 1;

    angle = angle % 360;

    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);

  glPopMatrix();

10,显示列表

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

显示列表

11,鼠标事件处理

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

鼠标控制

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