33. DirectDraw II
  1. Další příklad ukazuje, jak inicializovat DirectDraw, vytvořit uživatelskou paletu a zobrazit ji na DirectDrawSurface. Začneme vývoj nové aplikace. Formulář necháme prázdný, je u něj pouze doplněn konstruktor a vytvořena obsluha události OnPaint. Do deklarace třídy formuláře bylo doplněno několik veřejných složek (tři metody a pět datových složek):

  2. void __fastcall InitializeDirectDraw();
    void __fastcall SetupPrimarySurface();
    void __fastcall ShowPalette();
    int ddColors, ddWidth, ddHeight;
    IDirectDraw *DirectDraw;
    IDirectDrawSurface *PrimarySurface;
    Následuje výpis zdrojového souboru formuláře:
    #include <vcl.h>
    #pragma hdrstop
    #include "DDCP.h"
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
    {
      BorderStyle = bsNone;
      InitializeDirectDraw();
    }
    void __fastcall TForm1::InitializeDirectDraw()
    {
      DirectDrawCreate(NULL, &DirectDraw, NULL);
      DirectDraw->SetCooperativeLevel(Handle, DDSCL_ALLOWREBOOT |
        DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
      DirectDraw->SetDisplayMode(640, 480, 8);
      SetupPrimarySurface();
    }
    void __fastcall TForm1::SetupPrimarySurface()
    {
      DDSURFACEDESC ddsd;
      ZeroMemory(&ddsd, sizeof(ddsd));
      ddsd.dwSize = sizeof(ddsd);
      ddsd.dwFlags = DDSD_CAPS;
      ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
      DirectDraw->CreateSurface(&ddsd, &PrimarySurface, NULL);
    }
    void __fastcall TForm1::ShowPalette()
    {
      RECT rect;
      rect.top = 60;
      DDBLTFX ddbltfx;
      ZeroMemory(&ddbltfx, sizeof(ddbltfx));
      ddbltfx.dwSize = sizeof(ddbltfx);
      IDirectDrawPalette *palette332;
      PALETTEENTRY pe[256];
      // algoritmus pro paletu 332
      for(int i = 0; i < 256; i++)
      {
        pe[i].peRed = (BYTE) (((i >> 5)& 7)* 255/ 7);
        pe[i].peGreen = (BYTE) (((i >> 2)& 7)* 255/ 7);
        pe[i].peBlue = (BYTE) (((i >> 0)& 3)* 255/ 3);
        pe[i].peFlags = (BYTE)0;
      }
      DirectDraw->CreatePalette(DDPCAPS_8BIT, pe, &palette332, NULL);
      PrimarySurface->SetPalette(palette332);
      for (int i = 0; i < 255; i++)
      {
        ddbltfx.dwFillColor = i;
        if(i % 16 == 0)
        {
          rect.top += 20;
          rect.left = 160;
          rect.right = rect.left + 10;
          rect.bottom = rect.top + 10;
        }
        else
        {
          rect.left += 20;
          rect.right = rect.left + 10;
        }
        PrimarySurface->Blt(&rect, NULL, NULL, DDBLT_COLORFILL, &ddbltfx);
      }
    }
    void __fastcall TForm1::FormPaint(TObject *Sender)
    {
      DDBLTFX ddbltfx;
      ZeroMemory(&ddbltfx, sizeof(ddbltfx));
      ddbltfx.dwSize = sizeof(ddbltfx);
      ddbltfx.dwFillColor = RGB(0x00, 0x00, 0x00);
      PrimarySurface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx);
      ShowPalette();
    }
    Program si prostudujte. Po jeho spuštění je inicializován DirectDraw, vytvořena primární vrstva, vytvořena a zobrazena paleta. Program není možno běžným způsobem ukončit.
  3. Další program ukazuje koncepci zavádění bitové mapy do DirectDraw. Program ukazuje přepínání mezi dvěmi vrstvami (jedna obsahuje bitovou mapu a druhá je černá). Obrázek tedy bliká. Tento program používá pomocnou knihovnu funkcí pro zavádění bitových map a palet ze zdrojů. Následuje výpis hlavičkového souboru této zdrojové jednotky (soubor ddutil.h):

  4. /*  Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
     *  File:       ddutil.cpp
     *  Content:    Routines for loading bitmap and palettes from resources
     *********************************************************************/
    #ifdef __cplusplus
    extern "C" {            /* Assume C declarations for C++ */
    #endif /* __cplusplus */
    extern IDirectDrawPalette * DDLoadPalette(IDirectDraw *pdd,
           LPCSTR szBitmap);
    extern IDirectDrawSurface * DDLoadBitmap(IDirectDraw *pdd,
           LPCSTR szBitmap, int dx, int dy);
    extern HRESULT DDReLoadBitmap(IDirectDrawSurface *pdds,LPCSTR szBitmap);
    extern HRESULT DDCopyBitmap(IDirectDrawSurface *pdds, HBITMAP hbm,
           int x, int y, int dx, int dy);
    extern DWORD DDColorMatch(IDirectDrawSurface *pdds, COLORREF rgb);
    extern HRESULT DDSetColorKey(IDirectDrawSurface *pdds, COLORREF rgb);
    #ifdef __cplusplus
    }
    #endif /* __cplusplus */
    Zdrojový soubor ddutil.cpp má následující obsah:
    #undef WIN32_LEAN_AND_MEAN
    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
    #include <windowsx.h>
    #include <ddraw.h>
    #include "ddutil.h"
    /*
     *  DDLoadBitmap - zavádění vrstvy DirectDraw ze zdroje bitové mapy.
     */
    extern "C" IDirectDrawSurface * DDLoadBitmap(IDirectDraw *pdd,
               LPCSTR szBitmap, int dx, int dy)
    {
      HBITMAP             hbm;
      BITMAP              bm;
      DDSURFACEDESC       ddsd;
      IDirectDrawSurface *pdds;
      // pokus o zavedení bitové mapy jako zdroje, při neúspěchu ji zavedeme
      // ze souboru
      hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap,
             IMAGE_BITMAP, dx, dy, LR_CREATEDIBSECTION);
      if (hbm == NULL)
        hbm = (HBITMAP)LoadImage(NULL, szBitmap, IMAGE_BITMAP, dx, dy,
               LR_LOADFROMFILE|LR_CREATEDIBSECTION);
      if (hbm == NULL) return NULL;
      // získání velikosti bitové mapy
      GetObject(hbm, sizeof(bm), &bm);
      // vytvoření vrstvy pro tuto bitovou mapu
      ZeroMemory(&ddsd, sizeof(ddsd));
      ddsd.dwSize = sizeof(ddsd);
      ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
      ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
      ddsd.dwWidth = bm.bmWidth;
      ddsd.dwHeight = bm.bmHeight;
      if (pdd->CreateSurface(&ddsd, &pdds, NULL) != DD_OK) return NULL;
      DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);
      DeleteObject(hbm);
      return pdds;
    }
    /*
     * DDReLoadBitmap - zavedení bitové mapy ze souboru nebo zdroje
     * na vrstvu (používáno k opětovnému zavedení vrstvy po obnoveni).
     */
    HRESULT DDReLoadBitmap(IDirectDrawSurface *pdds, LPCSTR szBitmap)
    {
      HBITMAP             hbm;
      HRESULT             hr;
      hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap,
             IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
      if (hbm == NULL)
      hbm = (HBITMAP)LoadImage(NULL, szBitmap, IMAGE_BITMAP, 0, 0,
            LR_LOADFROMFILE|LR_CREATEDIBSECTION);
      if (hbm == NULL)
      {
        OutputDebugString("handle is null\n");
        return E_FAIL;
      }
      hr = DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);
      if (hr != DD_OK) OutputDebugString("ddcopybitmap failed\n");
      DeleteObject(hbm);
      return hr;
    }

    /*
     *  DDCopyBitmap - kreslení bitové mapy na vrstvě
     */
    extern "C" HRESULT DDCopyBitmap(IDirectDrawSurface *pdds, HBITMAP hbm,
            int x, int y, int dx, int dy)
    {
      HDC                 hdcImage;
      HDC                 hdc;
      BITMAP              bm;
      DDSURFACEDESC       ddsd;
      HRESULT             hr;
      if (hbm == NULL || pdds == NULL) return E_FAIL;
      // obnovení vrstvy
      pdds->Restore();
      // výběr bitové mapy v memoryDC, kterou chceme použít
      hdcImage = CreateCompatibleDC(NULL);
      if (!hdcImage) OutputDebugString("createcompatible dc failed\n");
      SelectObject(hdcImage, hbm);
      // získání velikosti bitové mapy
      GetObject(hbm, sizeof(bm), &bm);
      dx = dx == 0 ? bm.bmWidth  : dx;
      dy = dy == 0 ? bm.bmHeight : dy;
      // získání velikosti vrstvy
      ddsd.dwSize = sizeof(ddsd);
      ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
      pdds->GetSurfaceDesc(&ddsd);
      if ((hr = pdds->GetDC(&hdc)) == DD_OK)
      {
        StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, x, y,
                   dx, dy, SRCCOPY);
        pdds->ReleaseDC(hdc);
      }
      DeleteDC(hdcImage);
      return hr;
    }
    //
    // DDLoadPalette - vytvoření objektu palety DirectDraw ze zdroje bitové
    // mapy (pokud zdroj neexistuje vytvoříme implicitní paletu 332).
    //
    #pragma warn -pia-
    extern "C" IDirectDrawPalette * DDLoadPalette(IDirectDraw *pdd,
            LPCSTR szBitmap)
    {
      IDirectDrawPalette* ddpal;
      int                 i;
      int                 n;
      int                 fh;
      HRSRC               h;
      LPBITMAPINFOHEADER  lpbi;
      PALETTEENTRY        ape[256];
      RGBQUAD *           prgb;
      // vytvoření palety 332 jako implicitní
      for (i=0; i<256; i++)
      {
        ape[i].peRed   = (BYTE)(((i >> 5) & 0x07) * 255 / 7);
        ape[i].peGreen = (BYTE)(((i >> 2) & 0x07) * 255 / 7);
        ape[i].peBlue  = (BYTE)(((i >> 0) & 0x03) * 255 / 3);
        ape[i].peFlags = (BYTE)0;
      }
      // získání ukazatele na zdroj bitové mapy
      if (szBitmap && (h = FindResource(NULL, szBitmap, RT_BITMAP)))
      {
        lpbi = (LPBITMAPINFOHEADER)LockResource(LoadResource(NULL, h));
        if (!lpbi) OutputDebugString("lock resource failed\n");
        prgb = (RGBQUAD*)((BYTE*)lpbi + lpbi->biSize);
        if (lpbi == NULL || lpbi->biSize < sizeof(BITMAPINFOHEADER)) n = 0;
        else if (lpbi->biBitCount > 8) n = 0;
        else if (lpbi->biClrUsed == 0) n = 1 << lpbi->biBitCount;
        else n = lpbi->biClrUsed;
        // tabulka barev DIB má své bavy uloeny jako BGR a ne RGB
        for(i=0; i<n; i++ )
        {
          ape[i].peRed   = prgb[i].rgbRed;
          ape[i].peGreen = prgb[i].rgbGreen;
          ape[i].peBlue  = prgb[i].rgbBlue;
          ape[i].peFlags = 0;
        }
      }
      else if (szBitmap && (fh = _lopen(szBitmap, OF_READ)) != -1)
      {
        BITMAPFILEHEADER bf;
        BITMAPINFOHEADER bi;
        _lread(fh, &bf, sizeof(bf));
        _lread(fh, &bi, sizeof(bi));
        _lread(fh, ape, sizeof(ape));
        _lclose(fh);
        if (bi.biSize != sizeof(BITMAPINFOHEADER)) n = 0;
        else if (bi.biBitCount > 8) n = 0;
        else if (bi.biClrUsed == 0) n = 1 << bi.biBitCount;
        else n = bi.biClrUsed;
        // tabulka barev DIB má své bavy uloeny jako BGR a ne RGB
        for(i=0; i<n; i++ )
        {
          BYTE r = ape[i].peRed;
          ape[i].peRed  = ape[i].peBlue;
          ape[i].peBlue = r;
        }
      }
      pdd->CreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL);
      return ddpal;
    }
    #pragma warn -pia
    /*
     * DDColorMatch - převod RGB barvy na fyzické barvy
     */
    extern "C" DWORD DDColorMatch(IDirectDrawSurface *pdds, COLORREF rgb)
    {
      COLORREF rgbT;
      HDC hdc;
      DWORD dw = CLR_INVALID;
      DDSURFACEDESC ddsd;
      HRESULT hres;
      if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
      {
        rgbT = GetPixel(hdc, 0, 0); // uložení současné barvy
        SetPixel(hdc, 0, 0, rgb);   // nastavení vlastní barvy
        pdds->ReleaseDC(hdc);
      }
      ddsd.dwSize = sizeof(ddsd);
      while((hres=pdds->Lock(NULL,&ddsd,0,NULL))==DDERR_WASSTILLDRAWING);
      if (hres == DD_OK)
      {
        dw  = *(DWORD *)ddsd.lpSurface;
        if(ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
          dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1;
        pdds->Unlock(NULL);
      }
      if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
      {
        SetPixel(hdc, 0, 0, rgbT);
        pdds->ReleaseDC(hdc);
      }
      return dw;
    }
    /*
     * DDSetColorKey - nastavení barevného klíče pro vrstvu
     */
    extern "C" HRESULT DDSetColorKey(IDirectDrawSurface *pdds, COLORREF rgb)
    {
      DDCOLORKEY          ddck;
      ddck.dwColorSpaceLowValue  = DDColorMatch(pdds, rgb);
      ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
      return pdds->SetColorKey(DDCKEY_SRCBLT, &ddck);
    }
    Začneme vývojem nové aplikace. Do projektu přidáme výše uvedený zdrojový soubor. Naše aplikace potřebuje soubor zdrojů bitové mapy. Bitovou mapu si stáhneme a uložíme do stejného adresáře jako ostatní soubory projektu. K vytvoření souboru zdrojů z této bitové mapy vytvoříme soubor ddex2.rc, který také přidáme k projektu (ve stejném adresáři jako je projekt) s následujícím obsahem:
    BACK BITMAP BACK.BMP
    Na formulář vložíme komponentu Timer a vytvoříme několik obsluh událostí. Hlavičkový soubor formuláře vypadá takto:
    #ifndef MainH
    #define MainH
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <Menus.hpp>
    #include <ExtCtrls.hpp>
    class TForm1 : public TForm
    {
    __published:
            TTimer *Timer1;
            void __fastcall FormDestroy(TObject *Sender);
            void __fastcall FormKeyDown(TObject *Sender, WORD &Key,
                                        TShiftState Shift);
            void __fastcall FormPaint(TObject *Sender);
            void __fastcall Timer1Timer(TObject *Sender);
    private:
      LPDIRECTDRAW         lpDD;           // objekt DirectDraw
      LPDIRECTDRAWSURFACE  lpDDSPrimary;   // primární vrstva DirectDraw
      LPDIRECTDRAWSURFACE  lpDDSBack;      // zadní vrstva DirectDraw
      LPDIRECTDRAWPALETTE  lpDDPal;        // paleta DirectDraw
      BOOL                 bActive;
      BYTE phase;
      AnsiString FrontMsg;
      AnsiString BackMsg;
      void __fastcall Start();
    public:
            __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    Zdrojový soubor formuláře tvoří:
    #include <vcl.h>
    #include <ddraw.h>
    #pragma hdrstop
    #include "Main.h"
    #include "ddutil.h"
    #pragma resource "*.dfm"
    #define TIMER_ID        1
    #define TIMER_RATE      500
    TForm1 *Form1;
    char szBackground[] = "BACK";
    __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
    {
      lpDD = NULL;
      phase = 0;
      bActive = False;
      FrontMsg = "Front buffer (F12 or Esc to quit)";
      BackMsg = "Back buffer (F12 or Esc to quit)";
    }
    void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
      if(lpDD != NULL)
      {
        if(lpDDSPrimary != NULL)
        {
          lpDDSPrimary->Release();
          lpDDSPrimary = NULL;
        }
        if(lpDDPal != NULL )
        {
          lpDDPal->Release();
          lpDDPal = NULL;
        }
        lpDD->Release();
        lpDD = NULL;
      }
    }
    void __fastcall TForm1::Start()
    {
      HRESULT ddrval;
      DDSURFACEDESC ddsd;
      DDSCAPS ddscaps;
      char buf[256];
      ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
      if(ddrval == DD_OK)
      {
        ddrval = lpDD->SetCooperativeLevel(Handle,
          DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
        if(ddrval == DD_OK)
        {
          ddrval = lpDD->SetDisplayMode(640, 480, 8);
          if(ddrval == DD_OK)
          {
            ddsd.dwSize = sizeof(ddsd);
            ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
            ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
                                  DDSCAPS_FLIP | DDSCAPS_COMPLEX;
            ddsd.dwBackBufferCount = 1;
            ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
            if(ddrval == DD_OK)
            {
              ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
              ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps,
                                                    &lpDDSBack);
              if(ddrval == DD_OK)
              {
                lpDDPal = DDLoadPalette(lpDD, szBackground);
                if (lpDDPal == NULL) goto error;
                ddrval = lpDDSPrimary->SetPalette(lpDDPal);
                if( ddrval != DD_OK ) goto error;
                ddrval = DDReLoadBitmap(lpDDSBack, szBackground);
                if( ddrval != DD_OK ) goto error;
                Timer1->Enabled = True;
                bActive = True;
                return;
              }
            }
          }
        }
      }
    error:
      wsprintf(buf, "Direct Draw Init Failed (%08lx)\n", ddrval);
      MessageBox(Handle, buf, "ERROR", MB_OK);
      Close();
    }
    void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,
            TShiftState Shift)
    {
       switch (Key)
       {
         case VK_F3:
           Start();
           break;
         case VK_ESCAPE:
         case VK_F12:
           Close();
           break;
       }
    }
    void __fastcall TForm1::FormPaint(TObject *Sender)
    {
      RECT rc;
      SIZE size;
      char szMsg[]="Page Flipping Test: Press F3 to start, F12 or Esc to exit";
      if (!bActive)
      {
        HDC DC = GetDC(Handle);
        rc = GetClientRect();
        GetTextExtentPoint(DC, szMsg, lstrlen(szMsg), &size);
        SetBkColor(DC, RGB(0, 0, 0));
        SetTextColor(DC, RGB(255, 255, 0));
        TextOut(DC, (rc.right - size.cx)/2, (rc.bottom - size.cy)/2,
          szMsg, sizeof(szMsg)-1);
        ReleaseDC(Handle, DC);
      }
    }
    void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
      HDC DC;
      if (lpDDSBack->GetDC(&DC) == DD_OK)
      {
        if(phase)
        {
          SetBkColor(DC, RGB(0, 0, 255));
          SetTextColor(DC, RGB(255, 255, 0));
          TextOut(DC, 0, 0, FrontMsg.c_str(), FrontMsg.Length());
          phase = 0;
        }
        else
        {
          SetBkColor(DC, RGB(0, 0, 255));
          SetTextColor(DC, RGB(0, 255, 255));
          TextOut(DC, 0, 0, BackMsg.c_str(), BackMsg.Length());
          phase = 1;
        }
        lpDDSBack->ReleaseDC(DC);
      }
      while(1)
      {
        HRESULT ddrval;
        ddrval = lpDDSPrimary->Flip( NULL, 0 );
        if( ddrval == DD_OK )
          break;
        if( ddrval == DDERR_SURFACELOST )
        {
          ddrval = lpDDSPrimary->Restore();
          if( ddrval != DD_OK ) break;
          ddrval = DDReLoadBitmap(lpDDSBack, szBackground);
          if( ddrval != DD_OK ) break;
        }
        if( ddrval != DDERR_WASSTILLDRAWING ) break;
      }
    }
    Zde jsou použity nám již známé metody. Aplikaci vyzkoušejte.

  5. Jako poslední aplikaci používající DirectDraw si ukážeme aplikaci provádějící již skutečnou animaci. Začneme vývoj nové aplikace. Tato aplikace opět využívá funkce z jednotky ddutil.cpp (jako předchozí aplikace). Přidáme tedy tuto jednotku k našemu projektu (hlavičkový soubor ddutil.h musí být ve stejném adresáři). Aplikace opět bude potřebovat soubor zdrojů s bitovou mapou. Stáhneme si bitovou mapu a umístíme ji do adresáře projektu. Z této bitové mapy vytvoříme soubor zdrojů pomocí následujícího souborů (je zapotřebí aby byl v adresáři projektu, nazveme jej ddex4.rc a přidáme jej k projektu):

  6. #include "resource.h"
    ALL BITMAP ALL.BMP
    IDR_MENU MENU DISCARDABLE
    BEGIN
        POPUP "&File"
        BEGIN
            MENUITEM "E&xit",  IDM_EXIT
        END
    END
    Vidíme že tento soubor vkládá hlavičkový soubor resource.h. Tento hlavičkový soubor obsahuje (umístíme jej do stejného adresáře; jsou zde definice identifikátorů prvků souboru zdrojů):
    #define IDR_MENU                        102
    #define IDM_EXIT                        40001
    Hlavičkový soubor formuláře má následující obsah:
    #ifndef MainH
    #define MainH
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #define WM_INFOSTART WM_USER
    class TForm1 : public TForm
    {
    __published:
      void __fastcall FormDestroy(TObject *Sender);
      void __fastcall FormKeyDown(TObject *Sender, WORD &Key,
        TShiftState Shift);
      void __fastcall FormPaint(TObject *Sender);
    private:
      LPDIRECTDRAW  lpDD;
      LPDIRECTDRAWSURFACE  lpDDSPrimary;
      LPDIRECTDRAWSURFACE  lpDDSBack;
      LPDIRECTDRAWSURFACE  lpDDSOne;
      LPDIRECTDRAWPALETTE  lpDDPal;
      BOOL FActive;
      BOOL FRunApp;
      void UpdateFrame(void);
      void Start();
      void InitFail();
      HRESULT RestoreAll(void);
      MESSAGE void MyMove(TMessage &Message);
    public:
      __fastcall TForm1(TComponent* Owner);
    BEGIN_MESSAGE_MAP
      MESSAGE_HANDLER(WM_INFOSTART, TMessage, MyMove);
    END_MESSAGE_MAP(TForm);
    };
    extern TForm1 *Form1;
    #endif
    a zdrojový soubor formuláře obsahuje:
    #include <vcl.h>
    #include <ddraw.h>
    #pragma hdrstop
    #include "ddutil.h"
    #include "Main.h"
    #pragma resource "*.dfm"
    #define NAME "DDExample4"
    #define TITLE "Direct Draw Example 4"
    char szBitmap[] = "ALL";
    TForm1 *Form1;
    __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
    {
      FRunApp = True;
      FActive = False;
    }
    MESSAGE void TForm1::MyMove(TMessage &Message)
    {
      do {
        UpdateFrame();
        Application->ProcessMessages();
      } while(FRunApp == True);
    }
    void TForm1::InitFail()
    {
        MessageBox(Handle, "DirectDraw Init FAILED", TITLE, MB_OK );
        Close();
    }
    void TForm1::Start()
    {
      HRESULT ddrval;
      DDSURFACEDESC ddsd;
      DDSCAPS ddscaps;
      ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
      if( ddrval != DD_OK )
      {
         InitFail();
         return;
      }
      ddrval = lpDD->SetCooperativeLevel(Handle, DDSCL_EXCLUSIVE |
               DDSCL_FULLSCREEN );
      if( ddrval != DD_OK )
      {
        InitFail();
        return;
      }
      ddrval = lpDD->SetDisplayMode( 640, 480, 8);
      if( ddrval != DD_OK )
      {
        InitFail();
        return;
      }
      ddsd.dwSize = sizeof( ddsd );
      ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
      ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
                            DDSCAPS_FLIP | DDSCAPS_COMPLEX;
      ddsd.dwBackBufferCount = 1;
      ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
      if( ddrval != DD_OK )
      {
        InitFail();
        return;
      }
      ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
      ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack);
      if( ddrval != DD_OK )
      {
        InitFail();
        return;
      }
      lpDDPal = DDLoadPalette(lpDD, szBitmap);
      if (lpDDPal)
          lpDDSPrimary->SetPalette(lpDDPal);
      lpDDSOne = DDLoadBitmap(lpDD, szBitmap, 0, 0);
      if( lpDDSOne == NULL )
      {
        InitFail();
        return;
      }
      DDSetColorKey(lpDDSOne, RGB(0,0,0));
    }
    void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
      if( lpDD != NULL )
      {
        if( lpDDSPrimary != NULL )
        {
          lpDDSPrimary->Release();
          lpDDSPrimary = NULL;
        }
        if( lpDDSOne != NULL )
        {
          lpDDSOne->Release();
          lpDDSOne = NULL;
        }
        if( lpDDPal != NULL )
        {
          lpDDPal->Release();
          lpDDPal = NULL;
        }
        lpDD->Release();
        lpDD = NULL;
      }
    }
    void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,
            TShiftState Shift)
    {
      switch (Key)
      {
        case VK_F3:
          FActive = True;
          Start();
          PostMessage(Handle, WM_INFOSTART, 0, 0);
          break;
        case VK_ESCAPE:
        case VK_F12:
          FRunApp = False;
          FActive = False;
          Close();
          break;
      }
    }
    HRESULT TForm1::RestoreAll( void )
    {
      HRESULT ddrval;
      ddrval = lpDDSPrimary->Restore();
      if( ddrval == DD_OK )
      {
       ddrval = lpDDSOne->Restore();
       if( ddrval == DD_OK ) DDReLoadBitmap(lpDDSOne, szBitmap);
      }
      return ddrval;
    }
    void TForm1::UpdateFrame( void )
    {
      static DWORD lastTickCount[3] = {0,0,0};
      static int  currentFrame[3] = {0,0,0};
      DWORD  thisTickCount;
      RECT  rcRect;
      DWORD  delay[3] = {50, 78, 13};
      int   i;
      int   xpos[3] = {288, 190, 416};
      int   ypos[3] = {128, 300, 256};
      HRESULT  ddrval;
      thisTickCount = GetTickCount();
      for(i=0; i<3; i++)
      {
        if((thisTickCount - lastTickCount[i]) > delay[i])
        {
          lastTickCount[i] = thisTickCount;
          currentFrame[i]++;
          if(currentFrame[i] > 59) currentFrame[i] = 0;
        }
      }
      rcRect.left = 0;
      rcRect.top = 0;
      rcRect.right = 640;
      rcRect.bottom = 480;
      while(1)
      {
        ddrval = lpDDSBack->BltFast( 0, 0, lpDDSOne,
        &rcRect, DDBLTFAST_NOCOLORKEY );
        if( ddrval == DD_OK ) break;
        if( ddrval == DDERR_SURFACELOST )
        {
          ddrval = RestoreAll();
          if( ddrval != DD_OK ) return;
        }
        if( ddrval != DDERR_WASSTILLDRAWING ) return;
      }
      if(ddrval != DD_OK) return;
      for(i=0; i<3; i++)
      {
        rcRect.left   = currentFrame[i]%10*64;
        rcRect.top    = currentFrame[i]/10*64 + 480;
        rcRect.right  = currentFrame[i]%10*64 + 64;
        rcRect.bottom = currentFrame[i]/10*64 + 64 + 480;
        while( 1 )
        {
          ddrval = lpDDSBack->BltFast( xpos[i], ypos[i], lpDDSOne,
            &rcRect, DDBLTFAST_SRCCOLORKEY );
          if( ddrval == DD_OK ) break;
          if( ddrval == DDERR_SURFACELOST )
          {
            ddrval = RestoreAll();
            if( ddrval != DD_OK ) return;
          }
          if( ddrval != DDERR_WASSTILLDRAWING ) return;
        }
      }
      while( 1 )
      {
        ddrval = lpDDSPrimary->Flip( NULL, 0 );
        if( ddrval == DD_OK ) break;
        if( ddrval == DDERR_SURFACELOST )
        {
          ddrval = RestoreAll();
          if( ddrval != DD_OK ) break;
        }
        if( ddrval != DDERR_WASSTILLDRAWING ) break;
      }
    }
    void __fastcall TForm1::FormPaint(TObject *Sender)
    {
      AnsiString S = "F3 to Start, Esc to Exit";
      HDC DC = GetDC(Handle);
      if (!FActive)
      {
        SetBkMode(DC, TRANSPARENT);
        TextOut(DC, 25, 100, S.c_str(), S.Length());
      }
      ReleaseDC(Handle, DC);
    }
    Aplikace je hotova, můžeme ji vyzkoušej. Pokuste se zjistit, jak je animace prováděna.
  7. Pokuste se vytvořit nějakou jinou aplikaci, ve které se bude provádět animace.
33. DirectDraw II