ddraw顯示詳解

前些時間做過一個ddraw顯示來代替原來的gdi顯示,顯示的速度快了許多,在不斷的探索中,終於明白了ddraw的用法。現在記下來。本人文字功底欠佳,如有不明白的地方,一起討論。

 

1.ddraw 與 gdi的區別

 

兩者都可以用來顯示,gdi是windows比較抵觸的繪圖方式,ddraw是用gdi來實現的,但是ddraw利用了硬件加速。ddraw更多的應用於遊戲編程當中,在wince6.0上是可以使用ddraw的,所以手機編程中用draw會提程序速度。

 

2。 我的開發環境是Windows Mobile 6.0 ,用ddraw blt方式來實現顯示。

 

 

 

 

 

ddraw採用了COM的形式架構,如果實在 .c  的文件名下編譯會有鏈接錯誤,這個注意,關於COM這個還沒有顧上研究。

 

第一步: 創建一個DirectDraw : DirectDrawCreate(NULL, &mini_suf_ddraw_api, NULL);

 

第二步:設置顯示模式爲全屏獨佔模式: mini_suf_ddraw_api->SetCooperativeLevel(suf_hwnd, DDSCL_FULLSCREEN);

 

第三步:創建一個主表面: 

mini_suf_dds_desc.dwSize = sizeof(mini_suf_dds_desc) ; 
 mini_suf_dds_desc.dwFlags = DDSD_CAPS;
 mini_suf_dds_desc.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE;

 //創建主表面
 ret = mini_suf_ddraw_api->CreateSurface(&mini_suf_dds_desc, &mini_suf_dds_ptr, NULL); 

 

主表面是和顯存直接相關的,可以說你往這個表面寫任何東西都會直接的反映到顯示屏幕上。先前我直接往這個主表面寫數據,發現有刷新的問題,原因就是在這裏。所以我的程序中採用了向附表面寫數據然後copy到主表面,這樣做是稍微有點損失效率。

 

第四步: 創建一個副表面:

int systemWidth = GetSystemMetrics(SM_CXSCREEN);
 int systemHeight = GetSystemMetrics(SM_CYSCREEN);
 mini_suf_dds_desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT ;//|DDSD_CAPS ;//| DDSD_CAPS;
 //mini_suf_dds_desc.ddsCaps.dwCaps =  ;
 mini_suf_dds_desc.dwWidth = systemWidth; //mini_suf_dds_desc.dwWidth;
 mini_suf_dds_desc.dwHeight = systemHeight; //mini_suf_dds_desc.dwHeight;
 ret = mini_suf_ddraw_api->CreateSurface(&mini_suf_dds_desc, &mini_suf_dds_buf, NULL);

 

這個地方又有玄機:我好不容易研究出來的。爲啥副表面非得指定設備的寬和高。因爲主表面的創建是完全和設備相關的,顯示屏啥樣就創建成啥樣,但是附表面只是一個緩存區,需要這些寬高。

 

第五步: 加鎖 :

 mini_suf_dds_buf->Lock(0, &mini_suf_dds_desc, DDLOCK_WAITNOTBUSY, 0) ;

 

我老覺得這個Lock太害人了,我原來以爲是和互斥鎖差不多呢,其實根本不是那麼回事。其實調用lock的時候,返回了好多參數給DDSURFACEDESC結構體,包括顯存地址(這個是最關鍵的),包括顯示的寬高。

加鎖是加了副表面的鎖,所以獲得的是副表面的顯存地址,我們就是要往這個副表面的顯存裏寫東西。加鎖加到主表面那就傻了,這個還和flip有關係

 

flip是創建了兩個相關表面,當一個表面數據寫滿後交換這兩個表面的地址,交換地址就是通過每次的lock來實現的。這個在後邊的flip實現有詳細介紹。

 

第六步  顯示

mini_suf_dds_ptr->Blt(NULL, mini_suf_dds_buf, NULL, NULL, NULL);

 

這就沒啥說的了,直接將副表面的數據copy到主表面,實現顯示,和bitblt類似。

 

 

 

3. ddrwa的flip顯示實現。

 

第一步. 創建 

基本和前面類似,參數不同而已,

mini_suf_dds_desc.dwSize = sizeof(mini_suf_dds_desc) ; 
 mini_suf_dds_desc.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;//|DDSD_HEIGHT|DDSD_WIDTH;
 mini_suf_dds_desc.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP;
 mini_suf_dds_desc.dwBackBufferCount = 1; //一個後臺緩存
 /*mini_suf_dds_desc.dwWidth = 480;
 mini_suf_dds_desc.dwHeight = 640;
 mini_suf_dds_desc.ddpfPixelFormat.dwRGBBitCount = 16;*/

 //創建主表面
 ret = mini_suf_ddraw_api->CreateSurface(&mini_suf_dds_desc, &mini_suf_dds_ptr, NULL);

創建了帶一個後臺緩存的主表面,在真正的遊戲編程當中,有很多的後臺緩存表面,貼上位圖,不斷的進行切換,windows自帶的例子有這樣的。

 

 

第二步. 加鎖 的時候要切換表面的顯存地址的, 前面的代碼是沒有切換的注意啊。

 

  int ret;
  //mini_suf_dds_buf->Restore();
  ret = mini_suf_dds_buf->Lock(0, &mini_suf_dds_desc, 0, 0) ;
  if(ret != DD_OK) 
   InitFail(_T("lock field"));
  g_pddrawBitmapBuf = (U8 *) mini_suf_dds_desc.lpSurface;

 

 

第三步. 顯示: 就簡單了。

 

 mini_suf_dds_ptr->Flip( NULL, 0 );

 

4.橫屏

 

橫盤的時候,和手機本身和Windwos Mobile 的版本有相當大的關係。

 

 

 

 

 

 

這是我寫的自動橫屏的部分,剛開始我旋轉90度,死活不行,改成270度就好了,不知道微軟是咋滴了,換個手機就好了。

 

 

總結:

手機軟件開發,一定不能忘記手機本身的侷限性。

還要在一個問題無法解決的時候,多多嘗試,自己寫寫demo程序,這個提高自己編碼能力最快的辦法。

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章