Delphi 環境下使用DirectDraw實現簡單的繪製

注:demo來源於《windows遊戲編程大師技巧》demo6-3,本文章用Delphi實現該demo。

首先,使用Windows API函數實現原生態窗體,然後調用DDraw類實現效果。

部分註釋用英文寫在代碼裏(爲了能無障礙看懂英文文檔,所以在邊學代碼邊學好英語,呵呵~~)

運行效果爲,循環隨機在全屏幕上繪製像素點:
按下Escape鍵退出全屏

program Test_6_1;

uses
  Windows,
  Messages,
  DirectX, DXDraws,
  uUtil in '..\Library\DirectDraw_demo\uUtil.pas';

const
//set the resolution of displayer of you
  SCREEN_WIDTH = 1920;
  SCREEN_HEIGHT = 1080;                    

var
  MyClassName : string;
  MyWindowName : string;

var
  gbl_MSG : MSG;
  gbl_HDC : HDC;
  gbl_HW : HWND;
  gbl_hinst : HINST;

var
  FDirectDrawSurface : TDirectDrawSurface;
  FDirectDraw : TDirectDraw;
  ddsd : TDDSurfaceDesc_DX6;

//call back function
function MyWndProc(hW: HWnd; messages: UInt; wParams: WPARAM; lParams: LPARAM): LRESULT; stdcall;
var
  ps : PAINTSTRUCT;
  local_hdc : HDC;
begin
  Result := 0;
  case messages of
    WM_COMMAND:
    begin

    end;

    WM_PAINT:
    begin
      local_hdc := BeginPaint(hW, ps);
      EndPaint(hW, ps);
    end;

    WM_DESTROY:
    begin
      PostQuitMessage(0);
    end
  else
    Result := DefWindowProc(hW, messages, wParams, lParams);
  end;
end;

//initialize
function Game_Init(pParam: PChar = nil; num_Params : Integer = 0): Integer;
begin
  Randomize;
  //create a instance of TDirectDraw,use DDraw7 by default
  FDirectDraw := TDirectDraw.Create(nil);

  //set ccoperative level between window and dx
  //you can simply set flag to ddscl_normal, to be a windowed game
  //if you use ddscl_fullscreen please ddscl_exclusive
  FDirectDraw.IDDraw7.SetCooperativeLevel(gbl_HW, DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE or DDSCL_ALLOWREBOOT);

  //set display mode
  FDirectDraw.IDDraw7.SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, 16, 0, 0);

  FDirectDrawSurface := TDirectDrawSurface.Create(FDirectDraw);

  //fill structure TDDSurfaceDesc
  FillChar(ddsd, SizeOf(TDDSurfaceDesc_DX6), #0);
  ddsd.dwSize := SizeOf(TDDSurfaceDesc_DX6);
  ddsd.dwFlags := DDSD_CAPS;
  ddsd.ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE;

  //create surface
  FDirectDrawSurface.CreateSurface(ddsd);

end;

//finalize
function Game_ShutDown(pParam: PChar = nil; num_Params : Integer = 0): Integer;
begin
  if Assigned(FDirectDraw) then
  begin
    FDirectDraw.Free;
    FDirectDraw := nil;
  end;

  if Assigned(FDirectDrawSurface) then
  begin
    FDirectDrawSurface.Free;
    FDirectDrawSurface := nil;
  end;
end;

//game loop
function Game_Main(pParam: PChar = nil; num_Params : Integer = 0): Integer;
var
  ddsd : TDDSurfaceDesc_DX6;
  iPitch : Integer;
  pSurface : PChar;
  i, x, y: Integer;
  color : COLOR16;
begin
  if KeyDown(VK_ESCAPE) then
    SendMessage(gbl_HW, WM_CLOSE, 0, 0);

  FillChar(ddsd, SizeOf(TDDSurfaceDesc_DX6), #0);
  ddsd.dwSize := Sizeof(TDDSurfaceDesc_DX6);

  //lock
  FDirectDrawSurface.Lock(ddsd);

  iPitch := ddsd.lPitch;
  pSurface := ddsd.lpSurface;

  color := RGB(255, 0, 0);

  for i := 0 to 1000 - 1 do
  begin
    x := Random(SCREEN_WIDTH) * 2;
    y := Random(SCREEN_HEIGHT);

    move(color, pSurface[x + y * iPitch], SizeOf(COLOR16));
  end;

  //unlock
  FDirectDrawSurface.UnLock;

end;

{$R *.res}

// main loop
begin
  gbl_hinst := GetModuleHandle(nil);

  MyClassName := 'Test';
  MyWindowName := 'MyTest_6_1';

  if MyRegisterClass(gbl_hinst, @MyWndProc, PChar(MyClassName)) = 0 then
  begin
    MessageBox(0, 'RegisterClass defeat', 'Error', MB_OKCANCEL);
    Exit;
  end;

  if not InitInstance(gbl_hinst, SW_SHOW, PChar(MyClassName), PChar(MyWindowName), gbl_HW) then
  begin
    MessageBox(0, 'InitInstance defeat', 'Error', MB_OKCANCEL);
    Exit;
  end;

  Game_Init();


  //if use peekmessage,please add one line code : 'Sleep(100);' ,used to slow the effect
//  while True do
//  begin
//    if PeekMessage(gbl_MSG, 0, 0, 0, PM_REMOVE) then
//    begin
//      if gbl_MSG.message = WM_QUIT then
//        Break;
//
//      TranslateMessage(gbl_MSG);
//      DispatchMessage(gbl_MSG);
//    end;
//
//    Game_Main();
//  end;

  while GetMessage(gbl_MSG, 0, 0, 0) do
  begin
    TranslateMessage(gbl_MSG);
    DispatchMessage(gbl_MSG);

    Game_Main();
  end;

  Game_ShutDown();

end.

然後,請包含下面這個單元:

unit uUtil;

interface

uses
  Windows, Messages;


function KeyDown(const Key : Integer): Boolean;

function MyRegisterClass(hInst : HINST; pProc: Pointer; pClassName : PChar): WORD; overload;

function MyRegisterClass(const wClass : TWndClassEx): WORD; overload;

function InitInstance(hInst : HINST; nCmdShow : Integer; pClassName, pWindowName : PChar; out hW : HWND): Boolean;


implementation


function KeyDown(const Key : Integer): Boolean;
begin
  Result := GetAsyncKeyState(Key) <> 0;
end;

function MyRegisterClass(hInst : HINST; pProc: Pointer; pClassName : PChar): WORD;
var
  wclass: TWndClassEx;
begin
  //Don't forget to set all the properties, or you will failed to register
  wclass.cbSize := SizeOf(WNDCLASSEXW);                                 //set size of this structure
  wclass.style := CS_HREDRAW or CS_VREDRAW;                             //set style of general property of this form
  wclass.lpfnWndProc := pProc;                                         //callback function
  wclass.cbClsExtra := 0;
  wclass.cbWndExtra := 0;
  wclass.hInstance := hInst;                                           //set instance
  wclass.hIcon := LoadIcon(0, IDI_APPLICATION);
  wclass.hCursor := LoadCursor(0, IDC_ARROW);
  wclass.hbrBackground := GetStockObject(WHITE_BRUSH);
  wclass.lpszMenuName := nil;
  wclass.lpszClassName := pClassName;
  wclass.hIconSm := LoadIcon(wclass.hInstance, MAKEINTRESOURCE(0));   //set small icon

  Result := RegisterClassEx(wclass);
end;

function MyRegisterClass(const wClass : TWndClassEx): WORD;
begin
  Result := RegisterClassEx(wClass);
end;

function InitInstance(hInst : HINST; nCmdShow : Integer; pClassName, pWindowName: PChar; out hW : HWND): Boolean;
begin
  Result := False;

  hW := CreateWindow(pClassName, pWindowName, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInst, nil);

  if hW <> 0 then
  begin
    ShowWindow(hW, nCmdShow);
    UpdateWindow(hW);
    Result := True;
  end;
end;

end.

注意:請將:

const
  SCREEN_WIDTH = 1920;
  SCREEN_HEIGHT = 1080;   

設置爲你電腦當前的分辨率,否者效果可能會有問題。

另外,不要用在win10系統下使用或者學習,因爲win10已經將DDraw拋棄(集成到d3d中去了)。我在win10下試驗過,顯示效果會有問題。

最後,請包含一下DelphiX中的DirectX, DXDraws單元,或者編譯一下DelphiX的dpk工程文件,即可編譯通過。DelphiX源代碼網上有很多前輩已經共享過,下載下來即可。(我也上傳了DelphiX全部源代碼,訪問我的資源頁能找到。)

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