天天看點

代碼分析

      這是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發生的,在這裡進行了實際的旋轉和平移動作。

滑鼠控制

最後,代碼中還加入了對空間球,圖形闆,撥号按鍵盒的事件處理支援。