線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:3383
推到 Plurk!
推到 Facebook!

做一個OpenGL控制項

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-09-29 22:06:18 IP:61.70.xxx.xxx 未訂閱
此為轉貼資料 做一個OpenGL控制項 OpenGL是一個獨立於視窗的圖形庫,而圖形最終是在視窗系統裏繪製出來的,那?OpenGL的繪圖命令是怎?在窗口裏生成輸出的呢? 這就是各個系統上的OpenGL實現者需要做的工作了。在Windows裏是通過wgl庫完成的,在X-Windows裏是通過glx伺服器來完成的,至於這些OpenGL實現具體是怎?工作的,請參考sgi發佈的sample implement源碼,不過那個代碼是用C寫的。 在MS-Windows裏,wgl庫負責將OpenGL的繪製設備RenderContext與GDI的DeviceContext聯繫起來,使得發到OpenGL的RC裏的命令生成的點陣圖能夠在GDI DC裏繪製出來,你可以把它想象成OpenGL在RC裏有一個FrameBuffer,記錄著生成的圖案,而wgl則負責把FrameBuffer的內容BitBlt到DC上。當然,這並不是它實際的工作方法,如果想瞭解更多請參考SGI發佈的SDK資料或聯繫MS公司。 ?了使GDI DC能夠接受OpenGL RC的輸出,必須?DC選定特別的圖元格式,然後建立RC,再用wglMakeCurrent把當前要使用的RC和DC聯繫起來。此後我們就可以用OpenGL命令正常工作了。在一個程式裏可以創建多個RC和多個DC,程式中的OpenGL命令會發到被wglMakeCurrent指定?當前的那一組合中。 我並不認?這個初始化過程是個很有意思的工作,這個世界上有很多聰明的程式師也這?想,所以他們發明了glaux庫和glut庫。glaux是在著名的OpenGL Programmer Guide裏提出的,這本書是OpenGL編程的官方文檔,因?它的封皮是紅色的,所以通常簡稱?RedBook。故名思意,glaux是一套輸助庫,它使得你無須關心在具體視窗系統裏初始化、消息回應的細節,而是使用傳統的c/dos程式風格編制OpenGL程式。 int main(int argc, char** argv) { auxInitDisplayMode( AUX_SINGLE|AUX_RGB|AUX_DEPTH16);//使用單緩衝、RGB彩色模式、16位元濃度 auxInitPosition(0,0,250,250); auxInitWindow("Title");//以上兩行在(0,0)片建立了一個大小?250X250的窗口,其標題?"Title"。 myinit();//建立OpenGL透視投影環境 auxReshapeFunc(myReshape);//指定視窗大小變化的回應函數 auxMainLoop(display);//指定繪製函數 return 0; } 由於glaux是?教學目的開發的,所以實用價值很限,所以又有程式師開發了glut,這套庫被廣泛使用,它的工作方式與glaux極?類似,但功能完善得多,特別是對交互、全屏等的支援要理想得多,所以許多的OpenGL演示程式使用它,比如SGI網站上提供的多數演示程式都需要使用它。同時這套庫已經被移植到多種平臺上,所以要是想用簡單的方法開發在windows/macos/os2/xwindows等系統上都能使用的程式,那?應該選擇這套庫。 我並不認?一個Delphi程式師會喜歡glaux或glut,因?那意味著你不能利用Delphi的可視開發能力,另外任何真正實用的Delphi程式想直接在其他作業系統上編譯運行好象也不現實,即glut的跨平臺能力也沒有什?吸引力。我們應該開發一個VCL控制項,把初始化工作封裝起來。 我認?從TCustomPanel派生一個子類比較方便,讓我們稱它?TGLPanel吧。初始化過程要在WMCreate裏完成,之所以要放在這裏是因?這個時候Window Handle已經建立,但還沒?用。 在WMCreate中會?調用initDC完成DC調整工作,initDC會以本窗口使用的DC調用PreparePixelFormat,而PixelFormat則真正完成圖元格式調整,?然後WMCreate會調用InitGL完成OpenGL透視投影環境的設定,?最後調用OnInit給用戶一個調整透視投影環境的機會。 注意,如果要在MDI環境中的子表單中使用OpenGL,還有些附加工作要做,這就是給窗口類的Params.Style加上WS_CLIPCHILDREN和WS_CLIPSIBLINGS屬性,這得在Window Handle建立之前就完成,因此要寫在CreateParams裏。由於SDI應用並不需要該代碼,所以應該定義OnPreInit事件,讓用戶在需要的時候自己加上,在Create裏調用OnPreInit。以下代碼定義了OnPreInit,但並沒有定義CreateParams,如果需要自己加上吧。 在TGLPanel類中實際所做工作的詳細說明(按成員可見性組織): 私有 1、加入DC/RC/Pal私有變數 2、定義初始化DC/RC的私有方法 保護: 3、加入FOnPaint,FOnResize,FOnInit,FOnPreInit四個事件回應變數。 4、繼承/重載虛方法CreateParams,Paint,Resize 5、回應以下消息 WM_CREATE, TWMCreate, WMCreate WM_DESTROY, TWMDestroy, WMDestroy WM_PALETTECHANGED, TWMPaletteChanged, WMPaletteChanged WM_QUERYNEWPALETTE, TWMQueryNewPalette, WMQueryNewPalette WM_ERASEBKGND, TWMEraseBkgnd, WMEraseBkgnd 公開: 6、定義建構與析構方法 7、定義必要的其他方法以提供各種特性 發佈: 8、以下繼承來的屬性 __property Alignment; __property Align; __property DragCursor; __property DragMode; __property Enabled; __property ParentFont; __property ParentShowHint; __property PopupMenu; __property ShowHint; __property TabOrder; __property TabStop; __property Visible; 9、以下繼承來的方法 __property OnClick; __property OnDblClick; __property OnDragDrop; __property OnDragOver; __property OnEndDrag; __property OnEnter; __property OnExit; __property OnMouseDown; __property OnMouseMove; __property OnMouseUp; __property OnStartDrag; 10、加入以下事件 //初始化OpenGL狀態 __property TNotifyEvent OnInit = {read=FOnInit,write=FOnInit}; //專用於修改顯示BPP模式 __property TNotifyEvent OnPreInit = {read=FOnPreInit,write=FOnPreInit}; 11、重載以下事件 __property TNotifyEvent OnResize = {read=FOnResize,write=FOnResize}; __property TNotifyEvent OnPaint = {read=FOnPaint,write=FOnPaint}; 12、將消息與其回應函數連接起來(Delphi中這一步是在定義函數時指定的) 源代碼 unit GLPanel; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls,OpenGL; type TGLPanel = class(TCustomPanel) private { Private declarations } DC: HDC; RC: HGLRC; procedure initDC; procedure initGL; procedure PreparePixelFormat(var DC: HDC); protected { Protected declarations } FOnPaint:TNotifyEvent; FOnInit:TNotifyEvent; FOnPreInit:TNotifyEvent; FOnResize:TNotifyEvent; procedure Paint;override; procedure Resize;override; procedure WMDestroy(var Msg: TWMDestroy);message WM_DESTROY; procedure WMCreate(var Msg:TWMCreate); message WM_CREATE; public { Public declarations } constructor Create(Owner:TComponent);override; published { Published declarations } property Alignment; property Align; property DragCursor; property DragMode; property Enabled; property ParentFont; property ParentShowHint; property PopupMenu; property ShowHint; property TabOrder; property TabStop; property Visible; property OnClick; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDrag; property OnEnter; property OnExit; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnStartDrag; property OnInit:TNotifyEvent read FOnInit write FOnInit; property OnPreInit:TNotifyEvent read FOnPreInit write FOnPreInit; property OnResize:TNotifyEvent read FOnResize write FOnResize; property OnPaint:TNotifyEvent read FOnPaint write FOnPaint; end; procedure Register; implementation procedure Register; begin RegisterComponents('Samples', [TGLPanel]); end; //--------------------------------------------- constructor TGLPanel.Create; begin inherited; end; //--------------------------------------------- procedure TGLPanel.WMDestroy(var Msg: TWMDestroy); begin wglMakeCurrent(0, 0); wglDeleteContext(RC); ReleaseDC(Handle, DC); end; //--------------------------------------------------- procedure TGLPanel.initDC; begin DC := GetDC(Handle); PreparePixelFormat(DC); end; //--------------------------------------------------- procedure TGLPanel.initGL; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glOrtho(-1, 1, -1, 1, -1, 50); glMatrixMode(GL_MODELVIEW); glLoadIdentity; glEnable(GL_DEPTH_TEST); //注意下面這一行是?了做練習程式時可以直接用glColor指定材質而加的, // 可能使得光照或表面材質發生意想不到的變化, // 如果不需要可以去掉或在程式中用glDisable(GL_COLOR_MATERIAL);關閉 glEnable(GL_COLOR_MATERIAL); glShadeModel(GL_SMOOTH); gluLookAt(2, 4, 6, 0, 0, 0, 0, 1, 0); SwapBuffers(DC); end; //--------------------------------------------- procedure TGLPanel.PreparePixelFormat(var DC: HDC); var PFD : TPixelFormatDescriptor; ChosenPixelFormat : Integer; begin FillChar(PFD, SizeOf(TPixelFormatDescriptor), 0); with PFD do begin nSize := SizeOf(TPixelFormatDescriptor); nVersion := 1; dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; iPixelType := PFD_TYPE_RGBA; cColorBits := 16; // 16位?色 cDepthBits := 32; // 32位深度緩衝 iLayerType := PFD_MAIN_PLANE; { Should be 24, but we must allow for the clunky WKU boxes } end; ChosenPixelFormat := ChoosePixelFormat(DC, @PFD); if ChosenPixelFormat = 0 then Raise Exception.Create('ChoosePixelFormat failed!'); SetPixelFormat(DC, ChosenPixelFormat, @PFD); end; procedure TGLPanel.WMCreate(var Msg:TWMCreate); begin //在這裏做初始化工作 //修改DC的象素格式,使之支援OpenGL繪製 initDC; RC := wglCreateContext(DC); wglMakeCurrent(DC, RC); //初始化GL繪製系統 initGL; if Assigned(FOnInit) then begin if (wglMakeCurrent(DC,RC)=false) then ShowMessage('wglMakeCurrent:' IntToStr(GetLastError)); FOnInit(self); end; end; //--------------------------------------------------------------------------- procedure TGLPanel.Paint; begin //TCustomPanel::Paint(); if Assigned(FOnPaint) then begin wglMakeCurrent(DC,RC); FOnPaint(self); SwapBuffers(DC); end; end; //--------------------------------------------------------------------------- procedure TGLPanel.Resize; begin inherited; if Assigned(FOnResize) then begin wglMakeCurrent(DC,RC); glViewport(0,0,ClientWidth,ClientHeight); FOnResize(self); end; end; end. 以上代碼僅用來說明原理及建立一個基本的練習環境,您可以自由使用,轉載請注明出處。如果使用從本人主頁下載的TGLPanel請遵守內附使用說明的版權申明。如果實際做東西,建議使用Mike Lischke的GLScene控制項組(http://www.lischke-online.de/)。
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-05-09 0:03:33
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!