全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2036
推到 Plurk!
推到 Facebook!

DirectX - tasy (節選)

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-11-27 13:28:33 IP:61.218.xxx.xxx 未訂閱
DirectX - tasy (節選)    資料來源: Game Resource http://www.gameres.com/index.htm     我不會在這兒講 DirectX 的編程技術,所以我重點要做的是關於 DirectDraw 的程序設計,以及編寫足夠的函數來使得程序能夠建立並運行。我們要求所建立的程序結構能直接處理顯存、支持鍵盤。現在先看看我們需要點什麼:      C++ 編譯器 (MS VC++ 4.0 或更高)。       DirectX 5.0+ SDK (或更高)。沒有的話去 www.microsoft.com 下載。      許多必要的經驗。     準備好了?那就開始了。我們將創建一個基於 Windows 的 DirectX 程序,因此,我們的程序必須包含一個 Windows 程序所包含的必要元素。如,窗口的建立、窗口的初始化等等。在那些結束後,我們開始初始化 DirectX,將程序設置成全屏顯示模式,剩下我們所做的就是去處理顯存和處理鍵盤的輸入。另人驚訝的是,這一切不困難。在我們開始?手代碼之前,我們先來簡單地看一下一個標準的 Windows 程序的結構圖:(圖 1.0) Windows 系統是一個多任務系統,這就是意味?我們可以運行多個程序。而 Windows 會自動將用戶的輸入以“消息”、“事件”的形式發送出去。我們不必像以前寫 DOS 程序一樣來處理。這個獨特的結構就直接決定了我們遊戲的主體結構。我們必須包含一個“消息循環”,附加地,還得有個“消息處理器”來處理這些消息。當 Windows 收到用戶的輸入,它就運行我們程序的消息處理函數來處理事件。這並不糟糕,但是我們必須將我們自己的消息盡量地從這些消息中分離出來,以便我建立一個強勁的遊戲平台。 我們對計劃的實施如下:我們首先進行必要的程序初始化,包括建立窗口、事件處理器和 DirectX 。然後我們就建立一個每進行一次循環就運行一次 void Game_Main(void) 的消息循環。在 void Game_Main(void) 函數中,我們可以處理一切我們想要的。這裡就是我們整個遊戲進行的地方。我們還有兩個必要的函數: void Game_Init(void), 和 void Game_Shutdown(void). 這兩個函數將分別在遊戲開始時運行一次和在 Windows 事件主循環退出時運行一次。我們這樣做的目的是希望在退出 void Game_Main(void) 時有機會釋放程序資源,避免資源浪費。(圖 2.0,一個遊戲平台的基本結構) 圖 2.0 清晰地顯示出了我們的遊戲系統結構。這個程序所顯示的美麗之處就在於它不必我們擔心我們正在 Windows 中運行程序,我們隻要寫進顯存,運行函數,分配內存等等,就像在一個 DOS 32 保護模式中的程序!現在,既然我沒有堆一堆的程序清單給你,然後說:“嘿,就按這個打吧”,那麼,我們至少還要談論一些關於把 DirectDraw 用進程序的高級話題。 步驟 1: 一個 DirectDraw 對象必須是創建的,這將允許使得我們和 DirectDraw 取得聯系。你可以將這個步驟想象成初始化與顯卡的聯系。 步驟 2: 和系統的之間、和其他的 DirectX 之間的協作級別必須被正確設置。這個步驟是必要的,因為 Windows 系統是共享資源的。 步驟 3: 設置想要的顯示模式和屏幕的色深。我們將使用 640x480x256 色的顯示模式,但是其他的模式都是很容易通過一個簡單的設置來實現的。這裡,我們使用 8 比特的顏色。 步驟 4: 創建一個主表面。這步意味?我們向 DirectDraw 對象申請一個直接操作顯存的工具。 步驟 5: 創建一個 8 比特的調色板,並且關聯到主表面。這個調色板將被鴝l化成一個灰、紅、綠、藍的剃度。你通過一個簡單的函數 int Set_Pal_Entry(int index, int red, int green, int blue) 即可完成調換和注冊調色板的工作。 我們介紹了一下具體的步驟。下面的清單 1.0 包含了所有的功能以及一個展示如何操作顯存和鍵盤的例子。我們簡單地將它作為一個演示。 // LISTING 1.0 - DIRECT X 5.0 GAME CONSOLE //////////////////////////////////// // INCLUDES /////////////////////////////////////////////////////////////////// #define WIN32_LEAN_AND_MEAN // make sure certain headers are included correctly #include // include the standard windows stuff #include // include the 32 bit stuff #include // include the multi media stuff // note you need winmm.lib also #include // include direct draw components #include // include all the good stuff #include #include <math.h> #include // DEFINES //////////////////////////////////////////////////////////////////// #define WINDOW_CLASS_NAME "WINDOW_CLASS" // this is the name of the window class // defines for screen parameters #define SCREEN_WIDTH 640 // the width of the viewing surface #define SCREEN_HEIGHT 480 // the height of the viewing surface #define SCREEN_BPP 8 // the bits per pixel #define MAX_COLORS 256 // the maximum number of colors // TYPES ////////////////////////////////////////////////////////////////////// typedef unsigned char UCHAR; // MACROS ///////////////////////////////////////////////////////////////////// // these query the keyboard in real-time #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0) #define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1) // PROTOTYPES ///////////////////////////////////////////////////////////////// int DD_Init(HWND hwnd); int DD_Shutdown(void); int Set_Pal_Entry(int index, int red, int green, int blue); void Game_Init(void); void Game_Main(void); void Game_Shutdown(void); // DIRECTDRAW GLOBALS //////////////////////////////////////////////////////// LPDIRECTDRAW lpdd = NULL; // dd object LPDIRECTDRAWSURFACE lpddsprimary = NULL; // dd primary surface LPDIRECTDRAWPALETTE lpddpal = NULL; // a pointer to the created dd palette PALETTEENTRY color_palette[256]; // holds the shadow palette entries DDSURFACEDESC ddsd; // a direct draw surface description struct DDSCAPS ddscaps; // a direct draw surface capabilities struct HRESULT ddrval; // result back from dd calls HWND main_window_handle = NULL; // used to store the window handle UCHAR *video_buffer = NULL; // pointer to video ram // GAME GLOBALS GO HERE ///////////////////////////////////////////////////// // DIRECT X FUNCTIONS ///////////////////////////////////////////////////////// int DD_Init(HWND hwnd) { // this function is responsible for initializing direct draw, it creates a // primary surface int index; // looping index // now that the windows portion is complete, start up direct draw if (DirectDrawCreate(NULL,&lpdd,NULL)!=DD_OK) { // shutdown any other dd objects and kill window DD_Shutdown(); return(0); } // end if // now set the coop level to exclusive and set for full screen and mode x if (lpdd->SetCooperativeLevel(hwnd, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX)!=DD_OK) { // shutdown any other dd objects and kill window DD_Shutdown(); return(0); } // end if // now set the display mode if (lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP)!=DD_OK) { // shutdown any other dd objects and kill window DD_Shutdown(); return(0); } // end if // Create the primary surface ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if (lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)!=DD_OK) { // shutdown any other dd objects and kill window DD_Shutdown(); return(0); } // end if // create the palette and attach it to the primary surface // clear all the palette entries to RGB 0,0,0 memset(color_palette,0,256*sizeof(PALETTEENTRY)); // set all of the flags to the correct value for (index=0; index<256; index ) { // create the GRAY/RED/GREEN/BLUE palette, 64 shades of each if ((index / 64)==0) { color_palette[index].peRed = index*4; color_palette[index].peGreen = index*4; color_palette[index].peBlue = index*4; } // end if else if ((index / 64)==1) color_palette[index].peRed = (indexd)*4; else if ((index / 64)==2) color_palette[index].peGreen = (indexd)*4; else if ((index / 64)==3) color_palette[index].peBlue = (indexd)*4; // set the no collapse flag color_palette[index].peFlags = PC_NOCOLLAPSE; } // end for index // now create the palette object, note that it is a member of the dd object itself if (lpdd->CreatePalette((DDPCAPS_8BIT | DDPCAPS_INITIALIZE),color_palette,&lpddpal,NULL)!=DD_OK) { // shutdown any other dd objects and kill window DD_Shutdown(); return(0); } // end if // now attach the palette to the primary surface lpddsprimary->SetPalette(lpddpal); // return success if we got this far return(1); } // end DD_Init /////////////////////////////////////////////////////////////////////////////// int DD_Shutdown(void) { // this function tests for dd components that have been created and releases // them back to the operating system // test if the dd object exists if (lpdd) { // test if there is a primary surface if(lpddsprimary) { // release the memory and set pointer to NULL lpddsprimary->Release(); lpddsprimary = NULL; } // end if // now release the dd object itself lpdd->Release(); lpdd = NULL; // return success return(1); } // end if else return(0); } // end DD_Shutdown ////////////////////////////////////////////////////////////////////////////// int Set_Pal_Entry(int index, int red, int green, int blue) { // this function sets a palette entry with the sent color PALETTEENTRY color; // used to build up color // set RGB value in structure color.peRed = (BYTE)red; color.peGreen = (BYTE)green; color.peBlue = (BYTE)blue; color.peFlags = PC_NOCOLLAPSE; // set the color palette entry lpddpal->SetEntries(0,index,1,&color); // make copy in shadow palette memcpy(&color_palette[index], &color, sizeof(PALETTEENTRY)); // return success return(1); } // end Set_Pal_Entry // WINDOWS CALLBACK FUNCTION ////////////////////////////////////////////////// LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { // this is the main message handler of the system HDC hdc; // handle to graphics context PAINTSTRUCT ps; // used to hold the paint info // what is the message? switch(msg) { case WM_CREATE: { // do windows inits here return(0); } break; case WM_PAINT: { // this message occurs when your window needs repainting hdc = BeginPaint(hwnd,&ps); EndPaint(hwnd,&ps); return(0); } break; case WM_DESTROY: { // this message is sent when your window is destroyed PostQuitMessage(0); return(0); } break; default:break; } // end switch // let windows process any messages that we didn't take care of return (DefWindowProc(hwnd, msg, wparam, lparam)); } // end WinProc // WINMAIN //////////////////////////////////////////////////////////////////// int WINAPI WinMain( HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { WNDCLASSEX winclass; // this holds the windows class info HWND hwnd; // this holds the handle of our new window MSG msg; // this holds a generic message // first fill in the window class stucture winclass.cbSize = sizeof(WNDCLASSEX); winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; winclass.lpfnWndProc = WindowProc; winclass.cbClsExtra = 0; winclass.cbWndExtra = 0; winclass.hInstance = hinstance; winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); winclass.hCursor = LoadCursor(NULL, IDC_ARROW); winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); winclass.lpszMenuName = NULL; winclass.lpszClassName = WINDOW_CLASS_NAME; // register the window class if (!RegisterClassEx(&winclass)) return(0); // create the window if (!(hwnd = CreateWindowEx(WS_EX_TOPMOST, WINDOW_CLASS_NAME, // class "You can't See This!", // title WS_VISIBLE | WS_POPUP, 0,0, // x,y GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, // parent NULL, // menu hinstance, // instance NULL))) // creation parms return(0); // hide the mouse cursor ShowCursor(0); // save the window handle main_window_handle = hwnd; // initialize direct draw if (!DD_Init(hwnd)) { DestroyWindow(hwnd); return(0); } // end if // initialize game Game_Init(); // enter main event loop while(1) { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { // test if this is a quit if (msg.message == WM_QUIT) break; // translate any accelerator keys TranslateMessage(&msg); // send the message to the window proc DispatchMessage(&msg); } // end if else { // do asynchronous processing here // acquire pointer to video ram, note it is always linear memset(&ddsd,0,sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); lpddsprimary->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR,NULL); video_buffer = (UCHAR *)ddsd.lpSurface; // call main logic module Game_Main(); // release pointer to video ram lpddsprimary->Unlock(ddsd.lpSurface); } // end else } // end while // shut down direct draw DD_Shutdown(); // shutdown game Game_Shutdown(); // return to Windows return(msg.wParam); } // end WinMain // HERE ARE OUR GAME CONSOLE FUNCTIONS /////////////////////////////////////////////////////// void Game_Init(void) { // do any initialization here } // end Game_Init ///////////////////////////////////////////////////////////////////////////////////////////// void Game_Shutdown(void) { // cleanup and release all resources here } // end Game_Shutdown ///////////////////////////////////////////////////////////////////////////////////////////// void Game_Main(void) { // process your game logic and draw next frame // this function must exit each frame and return back to windows // also this function is responsible for controlling the frame rate // therefore, if you want the game to run at 30fps, then the function should // take 1/30th of a second before returning static int px = SCREEN_WIDTH/2, // position of player py = SCREEN_HEIGHT/2, color = 0; // color of blob 0..3, gray, red, green, blue // on entry video_buffer is valid // get input, note how keyboard is accessed with constants //"VK_" // these are defined in "winuser.h" are basically the //scan codes // for letters just use capital ASCII codes if (KEY_DOWN(VK_ESCAPE)) PostMessage(main_window_handle,WM_CLOSE,0,0); // this is how you exit you game // which way is player moving if (KEY_DOWN(VK_RIGHT)) if ( px>SCREEN_WIDTH-8) px=8; if (KEY_DOWN(VK_LEFT)) if (--px<8) px=SCREEN_WIDTH-8; if (KEY_DOWN(VK_UP)) if (--py<8) py=SCREEN_HEIGHT-8; if (KEY_DOWN(VK_DOWN)) if ( py>SCREEN_HEIGHT-8) py=8; // adjust color, notice if (KEY_DOWN('C')) { if ( color>=4) color=0; Sleep(100); } // end if // draw graphics for (int pixels=0; pixels<32; pixels ) video_buffer[(px-4 rand()%8) (py-4 rand()%8)*SCREEN_WIDTH] = (color*64) rand()d; // sync time (optional) // use sleep to slow system down to 70ish fps Sleep(14); // note that Sleep is extremly inaccurate, IRL you would use something more robust // return and let windows have some time } // end Game_Main 要編譯這個程序並且運行它,你需要在工程中包括庫文件 DDRAW.LIB ,和頭文件 DDRAW.H 。他們通過設置搜索路徑存在於你的 IDE 中或者是直接加到工程中去。你的目標程序,應該是一個標準的 Windows 程序。在建立了程序後,運行它,你應該可以看到一個熾熱的水滴,並且可以通過方向鍵來移動它, 鍵可以更改色彩,按 可以退出程序。現在你擁有了開始體驗 DirectX 基礎的所有東西了。你可以通過常量 SCREEN_WIDTH 和 SCREEN_HEIGHT 來嘗試雙緩沖、不同分辨率,甚至是調色板顏色變換。 現在,隻剩下一個可能引起的問題了。如果你的顯卡不能簡單地為 DirectX 創建一個線形的顯存模式的話,你必須直接仔細得操作顯卡了。舉個簡單的例子,如果你創建了一個 640 象素每行,即在 640x480x256 色模式中,操作下一行的顯存的話,你必須加上 640,或者是一般地操作一個象素點,你可以這樣寫: video_buffer[x y*640] = pixel; 無論如何,如果你的顯卡無法支持線形內存的話,那麼,你必須去修改一下,以便能直接真正地操作顯存的“線形內存跨度”。這個值會比象素值大。舉個例子,它在 640 個象素每行的模式中甚至可能是 1024 個象素的值。這個線形跨度能夠通過鎖定一個 DirectDraw 表面的描述來訪問,像這樣: // 我們可以這樣鎖定 lpddsprimary->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR,NULL); video_buffer = (UCHAR *)ddsd.lpSurface; // 這裡就是我們可以用於操作的值 int lpitch = ddsd.lPitch; 那麼,我們可以通過下面的方法來直接操作顯存了: video_buffer[x y*lpitch] = pixel; 因此,最安全的方法是去經常使用我們修改後得到的值。但是,這個方法犧牲了極大的性能。因此,你可能會去測試他們是否會是一個相等的值,然後使用一個不同的基於此原理的渲染函數。 [本文例子的源代碼下載]http://www.gameres.com/Visual/2D/t-article002.zip 聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]---
系統時間:2024-04-26 12:22:42
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!