丁 智,肖 宇
OpenGL是圖形硬件的軟件接口[1-2],由于其具有穩定性好、可移植性強等特點,目前已成為廣泛應用的跨平臺三維圖形繪制引擎,也是當前事實上應用最廣泛的三維圖形標準[1].OpenGL的一個顯著特點是它獨立于操作系統、窗口系統和硬件系統環境,這種運行平臺的無關性造就了OpenGL的成功,但同時也為OpenGL應用開發帶來了不便.OpenGL程序員必須利用不同操作系統平臺提供的圖形用戶界面(Graphics User Interface,GUI)支持函數,才能開發OpenGL應用[3],而掌握相關既定窗口系統的接口功能函數和可視化編程方法,通常需要較長時間的學習[4].為了解決初學者的這一困難,美國Silicon Graphics公司的MARK K開發了一個簡易的窗口系統工具包GLUT(OpenGL Utility Toolkit)[5].GLUT是 一 個跨平臺的輕量級窗口系統,能夠滿足一般圖形應用的開發要求.由于幾乎所有操作系統上都標配了GLUT包,因此以GLUT為基礎的OpenGL程序可以不加修改地運行于不同平臺,如Windows、Linux和Mac等.
然而,GLUT僅提供了簡單的事件處理功能,并不支持單復選按鈕、拖動條、組合框、文本框等控件,更沒有提供類似于下拉菜單和對話框等圖形用戶界面元素[5].這給基于OpenGL和GLUT開發圖形應用程序的用戶帶來了不便.在通常情形下,大多數圖形應用程序需要通過GUI實現對圖形繪制過程的交互式控制[6],以增加相關程序的靈活性和界面友好性.
另一方面,OpenGL具有強大的圖形處理能力,能夠勝任GUI所需的所有繪制功能.因此可以借助GLUT的窗口事件處理功能,并配合OpenGL繪制功能實現自己所需的圖形控件,為應用程序提供個性化的圖形用戶界面.
本文在分析GLUT事件處理過程和OpenGL繪制功能的基礎上,以實例討論如何基于二者來構造圖形控件的問題.所有的控件均采用C++類進行封裝,并提供必要的接口函數對它們進行控制.本文實現的圖形控件C++類具有高可復用性.
現代操作系統均為用戶提供了易于操作、用戶友好的圖形用戶界面[3,7].運行于其上的應用一般提供了按鈕、滑動條、文本框、單選和復選按鈕等,使用戶可以通過拖動鼠標等簡單操作完成對相關程序運行參數的選擇或調節.
對用戶而言,其對程序的控制主要是通過圖形控件提供的界面來實現的;在一般用戶的認識中,應用程序在屏幕上繪制出的有形控件便是程序本身.本節以滑動條、單選和復選按鈕三種控件討論如何基于OpenGL實現控件的圖形界面設計.
圖1(a)為Windows系統提供的滑動條控件的外觀,其由固定不動的滑動導軌和能夠在導軌上左右滑動的控制滑塊組成.本節先討論如何模仿Windows系統的滑動條圖形效果.通過觀察不難發現,滑動條導軌實質上是由一條黑色線段下襯一條等長的白色線段構成,兩條平行線段的兩頭又繪制了兩條黑色和白色短線段進行修飾.由于人類視覺上的原因,最終看到的滑動導軌呈現出一種下凹立體效果.滑動控制塊是一個用背景色繪制的矩形塊,為了使其呈現出凸出于背景的立體效果,在矩形塊的頂端和左側各繪制了一條白色線段,再在其右側和底端分別繪制出一條黑色線段.控制塊的位置可通過鼠標的拖動進行控制.

圖1 標準Windows操作系統圖形控件的示例
在知道具體位置的情況下,滑動條控件可以直接運用OpenGL中繪制長方形和線段的命令實現.如下列指令可繪制線段.

圖2中,右下側為本文模仿Windows系統中的滑動條繪制出的控件外觀效果,左側為垂直方向放置的滑動條繪制效果.在設計控件時,實現者可以根據自己的需要,設計具有個性化外觀的滑動條.如在圖2的右上角,滑動控制塊采用了與Windows系統中不同的外觀款式,其中滑動導軌也更寬了.

圖2 基于OpenGL繪制出各種滑動條的外觀
圖1(b)為單選控件的可視化界面,它由一組單選按鈕及其名稱和分組框等部分組成.相對于滑動條的界面外觀而言,單選和復選按鈕的繪制過程要稍微復雜一點.這里介紹Windows系統下的單選和復選按鈕在OpenGL下的實現,其原理同樣適用于其他個性化按鈕的繪制.
用戶將Windows系統下的單選和復選按鈕進行放大,可以發現兩種按鈕的位圖表示,參見圖3.一旦得到位圖,便可以用OpenGL的位圖繪制函數來實現控件外觀的繪制.
令a∈[0, 255],并用{}a3表示{a,a,a},則{}a3表示整數值的RGB顏色三元組,即為某種灰度.這時,可以通過分析圖3得到相關位圖的數組表示,其中圖3(a)的位圖可以表示為二維向量數組icon.



圖3 Windows操作系統中單選和復選按鈕的位圖
需要注意的是,為了適應OpenGL的數據格式要求,圖3(a)中位圖最后一行的數據位于數組icon的第一行,位圖倒數第二行的數據位于數組的第二行,依次類推.
圖3(a)為被選中狀態的單選按鈕圖標,圖3(b)為被選中狀態的復選按鈕圖標,兩者所對應的未被選中狀態的按鈕圖標可以通過用顏色{200}3分別替換位圖中央的“十”字和對勾標志處的位圖像素得到.
得到相關位圖的數組表示,便可利用OpenGL的位圖繪制函數進行繪制.具體實現方式如下:


其中,xpos和ypos為放置圖標的窗口坐標值.每個單、復選按鈕后面都有一個標記選項內容的文字標簽,繪制文字標簽的任務可由如下OpenGL和GLUT函數完成.

圖4為采用以上方法繪制出來的單選和復選按鈕圖標及相關控件,其中圖4(c)為方形單選按鈕,中間劃“×”表示該按鈕處為“選中”狀態.

圖4 用本文方法繪制出的單選按鈕及控件
為使用戶能夠借助鼠標等設備通過控件界面與應用程序進行互相操作,需將控件界面與窗口事件關聯起來[8].本節以滑動條為例進行說明.
滑動條控件通常由鼠標設備控制,并且通過鼠標按鍵的按下并移動拖動滑塊在滑軌上運動改變控件所調節的數值.因此,每當鼠標鍵(設為左鍵)按下時,控件必須檢測當前的鼠標光標是否落在屏幕滑動條控件所在的區域內.如果鼠標光標未落在該區域內,滑動條控件將不對該事件進行響應;如果鼠標光標落在了該區域內,則說明用戶當前按下鼠標的行為是想拖動滑動條的滑塊運動,這時將滑動條控件設置為激活狀態.激活狀態將一直維持到鼠標左鍵抬起為止.鼠標左鍵在滑動條區域內按下時,控件被激活;鼠標左鍵松開抬起時,控件由激活狀態轉為睡眠狀態.
當滑動條控件處在激活狀態(鼠標左鍵被按下)時,如果用戶移動鼠標,說明用戶欲通過移動滑塊調整滑動條表示的值.在基于GLUT的應用程序中,鼠標運動時GLUT窗口系統將會截獲該鼠標運動事件,并將該事件交給先前由glutMouseMotionFunc()所注冊的回調函數[9]處理.該回調函數將會得到由系統傳給它的包含當前鼠標光標在應用程序窗口中坐標的反饋信息.為了使控件能夠針對鼠標的運動情況調節滑塊的位置,需將控件響應鼠標運動的函數放在該回調函數中進行調用,并僅在控件處在激活狀態時執行調節滑塊的功能(即對左鍵未按下時的鼠標運動不作響應).由于該響應函數可以得到鼠標光標在屏幕上的實時位置,故其可通過該光標位置信息修改滑塊當前位置所表示的數值.
當鼠標滑塊表示的值被修改時,控件將觸發一個窗口重繪的系統請求,該事件使窗口系統進一步調用控件圖形界面的繪制函數,重新繪制控件界面,并在新的位置繪制控件滑塊.于是對用戶而言,界面所產生的效果即為其按下鼠標鍵的操作“拖動”控件滑塊運行,并通過調節滑塊的位置確定自己所要的數值.
滑動條所調節數值的范圍,以及滑塊變動所引起數值變化的幅度,均是由封裝該控件的類內部變量決定.控件外部可以通過該類所提供的公共成員函數引用或修改這些變量以及滑塊表示的值,從而最終達到使應用程序相關變量改變的目的.
本文給出的滑動條控件類的定義如下,相關變量和成員函數的意義在程序的注釋中給出.

以set-開頭的函數的主要功能是設置滑動條內部參數的值,如函數setPosition()用來設定滑動條左上角位置在窗口坐標系中的坐標值,setLength()用來設置繪制出的滑動條長度,setRange()用來設置滑動條調節的數值范圍;函數value()返回當前滑塊位置所對應的調節值.show()、button()、slide()三個函數用來響應鼠標事件[1,2,6],其中show()用來繪制滑動條的可視化外觀,其在基于GLUT的應用程序中,由glutDisplayFunc()所注冊的繪制回調函數調用,而button()和slide()則分別由經glutMouseFunc()和glutMotionFunc()所注冊的響應鼠標事件的回調函數調用.
其他控件均可以采用類似方法實現.由于采用了面向對象方法對所有控件分別進行C++類封裝,故可由每一控件類定義若干實體對象,各對象之間相對獨立而不會相互干擾,對外為用戶提供了與應用程序進行交互的界面和接口;同時,面向對象方法也使這些控件能夠在同一應用或不同應用中得到高度復用.
設計人員基于OpenGL和GLUT,在Visual C++6.0環境下開發并實現了標簽(Label)、滑動條、單選和復選、文本框等一系列控件.所有控件均以C++類的形式進行封裝,并對外提供簡單易用接口.
在圖5中,設計人員給出了兩張以本文控件作為圖形用戶界面的程序運行效果截圖.程序主窗口的工作區被分為兩部分:左側大部分為圖形繪制區,右側部分為控件繪制區.其中圖形繪制區為主窗口的子窗口,它注冊了屬于自己的回調函數,子窗口對各類事件的響應均由它自己的回調函數完成;控件繪制區中的所有控件均由主窗口所注冊的相關回調函數驅動,主窗口通過這些控件的接口函數獲取其當前狀態參數,并適時向子窗口傳遞(可通過全局變量或公共緩沖區等實現),控制圖形繪制區的繪圖行為.因此,除了相關參數的傳遞外,主窗口和子窗口的事件處理過程是絕緣的,這種處理簡化了程序開發過程,降低了圖形用戶界面開發的難度和復雜性.

圖5 配備本文控件的應用程序界面
圖5(a)和圖5(b)右側的控件繪制區中,從上至下依次放置了標簽、單選、水平和垂直滑動條3類控件.其中單選控件用來確定繪制圖形的形狀,可分別選擇茶壺、球體、圓環等6種形體;三個水平滑動條分別用來調節圖形繪制區背景顏色RGB分量的值,取值范圍均為[0,1],當前RGB值進一步由控件繪制區最上面的三個標簽控件以文字形式進行顯示;而三個垂直滑動條控件分別用來控制所繪制的圖形繞坐標系的X、Y、Z軸的旋轉角度,取值范圍均為[0,360].在圖5(a)中,程序在白色背景上繪制了一個茶壺模型;而在圖5(b)中,通過單選控件選擇了繪制圓環,并通過調節控制顏色和旋轉的滑動條改變了工作區中的背景和繪制圖形的旋轉角度.
本文給出一種基于OpenGL和GLUT圖形用戶界面可視化控件實驗的實現方法,討論了控件的外觀繪制方法和控件的事件驅動機制,并實現了相關控件面向對象的設計和實現,并以實例展示了部分控件的應用.實驗表明,本文方法制作的控件響應窗口事件的速度快捷,易學易用,易于操作,且可復用性好,適用于輕量級交互式圖形應用程序的開發.