DirectX (13.)

T°φdu CSurface ji₧ mßme zcela naimplementovanou, dnes nßm tedy zb²vß t°φdy CDisplay, abychom dokonΦili knihovnu Display.dll. ╚lßnek op∞t bude trochu delÜφ ne₧ je obvyklΘ a budeme se vesm∞s zab²vat k≤dem, kter² znßte, tak₧e popis bude struΦn². Nakonec si jeÜt∞ ukß₧eme, jak vytvo°enΘ funkce exportovat z knihovny.

13.1. Nßvrh t°φdy CDisplay

Za prvΘ je pot°eba si ud∞lat nßvrh t°φdy - tabulku jako v p°φpad∞ t°φdy CSurface.

Pro CDisplay bude vypadat n∞jak takto:

╚lenskΘ prom∞nnΘ

 

 

Typ

JmΘno

Popis

LPDIRECTDRAW7

m_lpDD

Ukazatel na rozhranφ objektu DirectDraw.

LPDIRECTDRAWCLIPPER

m_lpDDClipper

Ukazatel na  rozhranφ  objektu clipper.

LPDIRECTDRAWPALETTE

m_lpDDPalette

Ukazatel na  rozhranφ  objektu palety.

CSurface

m_surBack

Objekt zadnφho bufferu (back buffer).

CSurface

m_surFront

Objekt p°ednφho bufferu (front buffer).

Prom∞nnΘ pot°ebnΘ pro vykreslovßnφ pozadφ

CSurface

m_surBackground

Objekt povrchu pozadφ.

CRect

m_ScrollRect

ObdΘlnφk pou₧it² p°i posunu pozadφ, viz funkce UpdateBackGround().

CRect

m_BackSource

Op∞t je to obdΘlnφk vztahujφcφ se k vykreslovßnφ pozadφ. V tomto p°φpad∞ zdrojov² obdΘlnφk pou₧it² p°i vykreslovßnφ statickΘho pozadφ.

CString

m_BackBMP

Cesta k bitmap∞ pozadφ pot°ebnß p°i obnov∞ pozadφ.

COLORREF

m_BackColor

Pokud je pozadφ jednobarevnΘ, tato hodnota urΦuje jeho barvu.

Informace o rozliÜenφ a formßtu zadnφho a p°ednφho povrchu

UINT

m_Res_X

PoΦet pixel∙ v horizontßlnφm sm∞ru - rozliÜenφ.

UINT

m_Res_Y

PoΦet pixel∙ ve vertikßlnφm sm∞ru.

BYTE

m_Depth

Barevnß hloubka povrch∙.

Nßsledujφ prom∞nnΘ, kterΘ jsou souΦßstφ poΦφtadla FPS (Frame per second)

int

m_StartTime

PoΦßteΦnφ Φas p°i poΦφtanφ FPS.

int

m_StopTime

Koncov² Φas FPS. O tom jak funguje FPS counter, se vφce dovφte p°i popisu funkce UpdateFPS().

double

m_Frames

PoΦet snφmk∙ za urΦit² Φasov² okam₧ik urΦen² konstantou FPS_REFRESH_RATE.

CString

m_strFrames

╪et∞zec, kter² je vykreslovßn na monitor. Je tu jen kv∙li tomu, aby se nemusel po ka₧dΘ obnov∞ pozadφ znovu formßtovat nov² °et∞zec.

Ostatnφ prom∞nnΘ

BOOL

m_bIsInit

TRUE pokud je objekt CDisplay °ßdn∞ zinicializovßn.

DWORD

m_dwFlags

Nastavenφ objektu CDisplay.

IDirectDrawGammaControl*

m_GammaControl

Nakonec je tu podpora °φzenφ gammy (sv∞tlosti). Toto je ukazatel na rozhranφ IDirectDrawGammaControl. ╪φzenφ gammy je novinka, tak₧e to probereme trochu podrobn∞ji u funkcφ, kterΘ se gammou zab²vajφ.

int

m_CurGamma

Aktußlnφ nastavenφ Gamma v rozmezφ 0 - 255.

Metody

 

 

Nßvratovß hodnota

JmΘno

Popis

HRESULT

CreateFullscreenSystem(HWND, DWORD)

Zßkladnφ funkce knihovny, kterß musφ b²t zavolßna na prvnφm mφst∞! Prvnφ parametr je handle na okno aplikace. Druh² parametr typu DWORD nastavuje objekt CDisplay, viz dßle.

void Present() Funkce Present() provßdφ prohozenφ povrch∙ a obnovu FPS poΦφtadla.
HRESULT UpdateFPS() O tΘto funkci ji₧ byla °eΦ. SpoΦφtß a obnovφ FPS counter.

HRESULT

SetPalette()

Tato funkce nejprve vytvo°φ paletu z p°edem urΦenΘho souboru a potΘ ji nastavφ.

Prßce s pozadφm

HRESULT

DefineBackground(COLORREF)

Nßsledujφcφ dv∞ funkce definujφ pozadφ dv∞ma zp∙soby. Prvnφ verze definuje jednobarevnΘ pozadφ - jedin² parametr urΦuje barvu.

HRESULT

DefineBackground(CString, DWORD)

Druhß verze naproti tomu definuje pozadφ z bitmapy urΦenΘ prvnφm parametrem. DalÜφ vlastnosti pozadφ jsou urΦeny druh²m parametrem typu DWORD.

void

UpdateBackground()

P°ekreslφ pozadφ definovanΘ p°edchozφmi dv∞ma funkcemi. Tuto funkci je nutno volat na zaΦßtku obnovovacφ smyΦky.

Funkce °φdφcφ Gamma corection

BOOL

HasGammaSupport()

Funkce zjistφ, zda-li je systΘm v∙bec schopen gammu °φdit.

HRESULT IncrementGamma(int) Zv²Üφ stupe≥ gammy o hodnotu urΦenou parametrem. V praxi to znamenß zesv∞tlenφ scΘny.
HRESULT DecrementGamma(int) Snφ₧φ stupe≥ gammy o hodnotu urΦenou parametrem. V praxi to znamenß ztmavenφ scΘny.
Inline metody
BOOL IsInit() Vracφ hodnotu prom∞nnΘ m_bIsInit.
LPDIRECTDRAW7 GetDirectDraw() Vracφ ukazatel na rozhranφ objektu DirectDraw.
CSurface* GetBackBuffer() Vracφ ukazatel na objekt zadnφho povrchu.
CSize GetResolution() Vracφ aktußlnφ rozliÜenφ ve struktu°e CSize(cx, cy).
Ostatnφ funkce
void Clean() Funkce provßd∞jφcφ zametacφ prßce, viz minulß lekce.
- CDisplay() Konstruktor t°φdy.
- ~CDisplay() Destruktor t°φdy.

Vidφte, ₧e t°φda je pom∞rn∞ slo₧itß. V nßsledujφcφch dvou Φßstech si podrobn∞ji probereme jednotlivΘ funkce.

13.2. Deklarace t°φdy

Za prvΘ se podφvejme na deklaraci:

class CDisplay
{
private:
 
  //
    // Objects of DirectDraw

    LPDIRECTDRAW7 m_lpDD;
    LPDIRECTDRAWCLIPPER m_lpDDClipper;
    LPDIRECTDRAWPALETTE m_lpDDPalette;
  
 // Front&back buffer
    CSurface m_surFront;
    CSurface m_surBack;
   
//
    // Background&scrolling

    CSurface m_surBackground;
    CRect m_ScrollRect;
    CRect m_BackSource;
    CString m_BackBMP;
    COLORREF m_BackColor;
   
//
    // Common display flags

    DWORD m_dwFlags;
 
  //
    // Information about display mode

    UINT m_Res_X;
    UINT m_Res_Y;
    BYTE m_Depth;
  
 //
    // Initialization of system

    BOOL m_bIsInit;
   
//
    // Display FPS counter

    int m_StartTime;
    int m_StopTime;
    double m_Frames;
    CString m_strFrames;
   
//
    // Gamma control support

    IDirectDrawGammaControl* m_GammaControl;
    int m_CurGamma;
   
public:
    BOOL IsInit() {return m_bIsInit;}
   
//
    // Create surfaces etc.

    HRESULT CreateFullScreenSystem(HWND hWnd, DWORD dwFlags);
  
 //
    // Palette functions

    HRESULT SetPalette();
 
  //
    // Flipping surfaces

    void Present();
 
  //
    // Return directdraw objects

    LPDIRECTDRAW7 GetDirectDraw() {return m_lpDD;}
    CSurface* GetBackSurface() {return &m_surBack;}
   
  
 // Resolution
    CSize GetResolution() {return CSize(m_Res_X, m_Res_Y);}
  
 //
    // Background functions

    HRESULT DefineBackground(COLORREF crColor);
    HRESULT DefineBackground(CString strBMPFile, DWORD dwFlags);
    HRESULT UpdateBackground();
   
//
    // Gamma corection support

    HRESULT IncrementGamma(int _Amount = 8);
    HRESULT DecrementGamma(int _Amount = 8);
  
private:
    HRESULT UpdateFPS();
    void Clean();
    BOOL HasGammaSupport();

public:
    CDisplay();
    ~CDisplay();
};

 
Na deklaraci nenφ nic zvlßÜtnφho. Dr₧φme se p°esn∞ tabulky z ·vodu. Jen si vÜimn∞te, ₧e n∞kterΘ metody jsou soukromΘ. Jsou to metody, ke kter²m nemß b²t p°φstup zvenku. Bylo by to zbyteΦnΘ, proto₧e jsou to ryze internφ funkce a u₧ivatel o nich nepot°ebuje v∞d∞t. TakΘ si vÜimn∞te n∞kter²ch implicitnφch parametr∙.
    V₧dy se sna₧φm odd∞lit metody a atributy t°φdy. TakΘ nechci mφchat vÜechny soukromΘ prvky dohromady, proto najdete v deklaraci vφce sekcφ private a public. Na tyto drobnosti upozor≥uji p°edevÜφm mΘn∞ zkuÜenΘ cΘΦka°e, kte°φ nemajφ velkΘ zkuÜenosti s objektov²m programovßnφm.

JeÜt∞ p°ed deklaracφ samotnΘ t°φdy bychom m∞li nadefinovat n∞kterΘ konstanty:

Soubor Core.h:

#define FPS_REFRESH_RATE 1000

#define _C_DEFAULT_SCREENWIDTH 640
#define _C_DEFAULT_SCREENHEIGHT 480
#define _C_DEFAULT_SCREENDEPTH 16


#define _S_LOADING1 _T("\\Graphics\\Backgrounds\\loading1.bmp")

#define _S_ARIAL_DDF _T("\\Graphics\\Fonts\\Arial.ddf")
#define _S_HUMANS_DDF _T("\\Graphics\\Fonts\\Humanst521 BT.ddf")

#define _S_FONT_ARIAL _T("Arial")
#define _S_FONT_HUMANS _T("Humans")
 

Zde definujeme za prvΘ obnovovacφ interval FPS ukazatele. ╚φslo 1000 znamenß, ₧e FPS counter, se bude obnovovat po 1 vte°in∞. Dßle tam mßme implicitnφ hodnoty rozliÜenφ, kterΘ se nastavujφ v p°φpad∞, ₧e se nepoda°φ naΦφst sprßvnΘ hodnoty z konfiguraΦnφho souboru. To samΘ platφ pro barevnou hloubku. DalÜφ t°i konstanty jsou cesty do datovΘho souboru. Knihovna Display.dll toti₧ intern∞ pou₧φvß n∞kterΘ bitmapy (fonty a pozadφ p°i inicializaci). VÜechny bitmapy mßme v adresß°i Graphics. VÜimn∞te si, jak²m zp∙sobem cesty definujeme. Budeme tak toti₧ definovat cesty i k vaÜim vlastnφm soubor∙m (nemusφ jφt jen o bitmapy).
Poslednφ dv∞ konstanty definujφ identifikaΦnφ °et∞zec jednotliv²ch font∙. Podle t∞chto °et∞zc∙ jsou fonty p°epφnßny pomocφ metod ze t°φdy CDDFontEngine. Tato t°φda se starß o vykreslovßnφ font∙. Tu zde nebudu rozebφrat, proto₧e jsem ji nepsal jß a nßm staΦφ pouze pßr jejich funkcφ.

Soubor Common.h (tento soubor je souΦßstφ projektu Display a nemß nic spoleΦnΘho s knihovnou Common.dll):

//
// Flags for CreateFullScreenSystem()

#define DDFLG_CLIPPER 0x00000001
#define DDFLG_WINDOWMODE 0x00000002
#define DDFLG_FULLSCREEN 0x00000004
#define DDFLG_GAMMA 0x00000008
#define DDFLG_PALETTE 0x00000010
// Common flags
#define DDFLG_FPS 0x00000020
// Flags for DefineBackground()
#define DDFLG_SYSTEM_MEMORY 0x10000000
#define DDFLG_VIDEO_MEMORY 0x20000000
#define DDFLG_SCROLLING 0x40000000
#define DDFLG_SOLID 0x80000000
#define DDFLG_COLORKEY 0xF0000000
//
// Keys
// Graphics section
#define _S_KEY_WIDTH _T("ScreenWidth")
#define _S_KEY_HEIGHT _T("ScreenHeight")
#define _S_KEY_DEPTH _T("ScreenDepth")
#define _S_KEY_FPS _T("FPS")
#define _S_KEY_USEGAMMA _T("UseGamma")
#define _S_KEY_SHOWVIDMEM _T("ShowVidMem")

Zde definujeme za prvΘ konstanty pro funkce CreateFullScreenSystem() a pro DefineBackground(). Pomocφ t∞chto konstant m∙₧eme nastavit dalÜφ vlastnosti aplikace a pozadφ. Rozeberme si je podrobn∞ji:

DDFLG_CLIPPER - aktivuje clipper. Pokud tuto hodnotu nezahrnete p°i volßnφ funkce CreateFullscreenSystem(), nebude se pou₧φvat clipper.
DDFLG_WINDOWMODE - tento flag myslφm nefunguje, ale m∞l zabrßnit p°epnutφ do fullscreen m≤du a aplikace tak z∙stala v okn∞.
DDFLG_FULLSCREEN - opak p°edchozφho.
DDFLG_GAMMA - zapnutφ podpory pro °φzenφ gammy. SystΘm si zjistφ, zda-li je to v∙bec mo₧nΘ.
DDFLG_PALETTE - Tento flag se nastavφ, pokud je nastavena paleta. Paleta by se m∞la automaticky zapnout p°i 8-mi bitovΘ hloubce barev.

DDFLG_FPS - tento flag je aktivovßn p°es konfiguraΦnφ soubor. Pokud je v setup.ini 1, je tento flag nastaven a FPS counter je zobrazen. V opaΦnΘm p°φpad∞ nikoliv.

DDFLG_SYSTEM_MEMORY - vynuceni ulo₧enφ povrchu pozadφ do systΘmovΘ pam∞ti. Je pot°eba nastavit na grafick²ch kartßch, kterΘ majφ mΘn∞ grafickΘ pam∞ti.
DDFLG_VIDEO_MEMORY - prav² opak p°edchozφ informace. Pozadφ je vytvo°eno ve video pam∞ti a a₧ kdy₧ to nejde, je mφsto alokovßno v RAM.
DDFLG_SCROLLING    - zapφnß scrolling pozadφ. Zkuste si to a uvidφte jak to funguje. Tato funkce je znaΦn∞ nepru₧nß a jedno·Φelovß. Zßle₧φ jen na Vßs, jak si to upravφte podle pot°eb.
DDFLG_SOLID - informace o tom, ₧e pozadφ je jednobarevnΘ.

DDFLG_COLORKEY - tuto hodnotu vyu₧φvß CSurface p°i uchovßnφ informace o CK.

DalÜφ hodnoty jsou klφΦe v konfiguraΦnφm souboru, ze kterΘho Φteme spoustu informacφ. Tak m∙₧ete modifikovat chovßnφ aplikace, ani₧ by se musela znovu p°eklßdat. Co znamenajφ, se dß snadno vyΦφst z jejich nßzvu. JeÜt∞ je celkem d∙le₧itΘ, ₧e flagy se dajφ kombinovat pomocφ operßtoru OR |.

13.3. Implementace funkcφ

V dalÜφ Φßsti budeme postupn∞ implementovat a rozebφrat vÜechny metody t°φdy CDisplay. ZaΦneme logicky u inicializace systΘmu:

HRESULT CDisplay::CreateFullScreenSystem(HWND hWnd, DWORD dwFlags)
{
  
 //
    // Temporary front and back buffer

    LPDIRECTDRAWSURFACE7 lpDDSBack, lpDDSFront;
    DDCAPS Hel; Hel.dwSize = sizeof(DDCAPS);
    DDCAPS Driver; Driver.dwSize = sizeof(DDCAPS);
    HRESULT dwRet;
   
   
//
    // Init olny if we not init before

    if(m_bIsInit) {
        return 1;
    }
   
//
    // Check handle to window

    ASSERT(hWnd);
   
//
    // 1. krok
    // Get resolution from "setup.ini" file

    m_Res_X = setGetSetupInt(_S_SECTION_GRAPHICS, _S_KEY_WIDTH);
    m_Res_Y = setGetSetupInt(_S_SECTION_GRAPHICS, _S_KEY_HEIGHT);
    m_Depth = setGetSetupInt(_S_SECTION_GRAPHICS, _S_KEY_DEPTH);
    if(m_Res_X == 0) m_Res_X = _C_DEFAULT_SCREENWIDTH;
    if(m_Res_Y == 0) m_Res_Y = _C_DEFAULT_SCREENHEIGHT;
    if(m_Depth == 0) m_Depth = _C_DEFAULT_SCREENDEPTH;

    if(setGetSetupInt(_S_SECTION_GRAPHICS, _S_KEY_FPS)) {
        m_dwFlags |= DDFLG_FPS;
    }
  
 //
    // Set scroll rect

    m_ScrollRect.SetRect(0, 0, m_Res_X, m_Res_Y);
   
//
    DXTRACE("Initializing display...");
  
 //
    // 2. krok

   
// Creating DDraw object
    dwRet = DirectDrawCreateEx(NULL, (void**)&m_lpDD, IID_IDirectDraw7, NULL);
    DXERR ("Creating DirectDraw object", dwRet);
    if(dwRet != DD_OK) {
        Clean();
        return dwRet;
    }
   
//
    // 3. krok
    // Get capabilities of hardware

    dwRet = m_lpDD->GetCaps(&Driver, &Hel);
    DXERR ("Getting caps about hardware", dwRet);
    if(dwRet != DD_OK) {
        Clean();
        return dwRet;
    }
  
 //
    // 4. krok

    // Set cooperative level
    dwRet = m_lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);
    DXERR ("Setting exclusive mode", dwRet);
    if(dwRet != DD_OK) {
        Clean();
        return dwRet;
    }
    // Set display mode
    dwRet = m_lpDD->SetDisplayMode(m_Res_X, m_Res_Y, m_Depth, 0, 0);
    DXERR("Setting display mode", dwRet);
    if(dwRet != DD_OK) {
        Clean();
        return dwRet;
    }
   
//
    // 5. krok
    // Create flipping loop
    DDSURFACEDESC2 ddsd;
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
                                                    DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
    ddsd.dwBackBufferCount = 1;
 
   //
    // Get a pointer to the front buffer
 
   dwRet = m_lpDD->CreateSurface(&ddsd, &lpDDSFront, NULL);
    DXERR ("Getting pointer to front buffer", dwRet);
    if(dwRet != DD_OK) {
        Clean();
        return dwRet;
    }
 
  //
    // Create front buffer
  
 dwRet = m_surFront.Create(lpDDSFront);
    DXERR ("Creating front buffer", dwRet);
    if(dwRet != DD_OK) {
        Clean();
        return dwRet;
    }
 
   //
    // Get a pointer to the back buffer
 
  DDSCAPS2 ddscaps;
    ZeroMemory(&ddscaps, sizeof(ddscaps));
    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
    dwRet = m_surFront.GetSurface()->GetAttachedSurface(&ddscaps, &lpDDSBack);
    if(dwRet != DD_OK) {
        DXERR ("Getting pointer to back buffer", dwRet);
        Clean();
        return dwRet;
    }
    //
    // Create back buffer
 
   dwRet = m_surBack.Create(lpDDSBack);
    if(dwRet != DD_OK) {
        DXERR ("Creating back buffee", dwRet);
        Clean();
        return dwRet;
    }
    ////////////////////////////////////////////////////////////////////////
    m_bIsInit = true;
 
  //
    // 6. krok

    dwRet = fntCreateFont(_S_ARIAL_DDF, _S_FONT_ARIAL);
    if(dwRet != ERROR_SUCCESS) {
        DXERR("Cannot create specified font due", dwRet);
    }
    dwRet = fntCreateFont(_S_HUMANS_DDF, _S_FONT_HUMANS, TC_DARKGREEN);
    if(dwRet != ERROR_SUCCESS) {
        DXERR("Cannot create specified font due", dwRet);
    }
    //
    // 7. krok
    // Display loading bitmap
    disDefineBackground(_S_LOADING1, DDFLG_VIDEO_MEMORY);
    disUpdateBackground();
    disPresent();
 
  //
    // 8. krok
    // Clipper
 
  if(dwFlags & DDFLG_CLIPPER) {
        //
        // Create rectangular region
        CRgn rect; RGNDATA data; int n;
        rect.CreateRectRgnIndirect(CRect(0, 0, m_Res_X, m_Res_Y));
        n = rect.GetRegionData(NULL, 0);
        if(rect.GetRegionData(&data, n) != ERROR) {
 
           //
            // Create clipper
 
          dwRet = m_lpDD->CreateClipper(0, &m_lpDDClipper, NULL);
            DXERR ("Creating clipper object", dwRet);
            if(DD_OK != dwRet) {
                Clean();
                return dwRet;
            }
 
           //
            // Set clipper
 
           dwRet = m_lpDDClipper->SetClipList(&data, 0);
            DXERR ("Setting clipper list", dwRet);
            if(DD_OK != dwRet) {
                Clean();
                return dwRet;
            }
            dwRet = m_surBack.GetSurface()->SetClipper(m_lpDDClipper);
            DXERR ("Setting clipper", dwRet);
            if(DD_OK != dwRet) {
                Clean();
                return dwRet;
            }
            m_dwFlags |= DDFLG_CLIPPER;
        }
        else {
            Clean();
            return 1;
        }
    }
   
//
    // 9. krok
    // Gamma correction

    BOOL bUseGamma = setGetSetupInt(_S_SECTION_GRAPHICS, _S_KEY_USEGAMMA);
    if(bUseGamma && (dwFlags & DDFLG_GAMMA) && HasGammaSupport()) {
        dwRet = m_surFront.GetSurface()->QueryInterface(IID_IDirectDrawGammaControl, (LPVOID*) &m_GammaControl);
        DXTRACE6("Getting pointer to gamma correction object due", dwRet);
        if(!m_GammaControl) {
            Clean();
            return dwRet;
        }
        m_dwFlags |= DDFLG_GAMMA;
    }
 
   //
    // 10.krok
    // Create and set palette
    // If we have only 8-bit color depth, we need palette
 
  if(m_Depth == 8) {
        dwRet = SetPalette();
        DXERR("Setting pallete due", dwRet);
        if(dwRet != DD_OK) {
            Clean();
            return dwRet;
        }
        m_dwFlags |= DDFLG_PALETTE;
    }

    return dwRet;
}

Tato funkce je asi nejdelÜφ, ale rozhodn∞ nenφ nikterak slo₧itß:
V prvnφm kroku naΦteme n∞kterΘ informace z konfiguraΦnφho souboru. KonkrΘtn∞ se jednß o rozliÜenφ, barevnou hloubku a viditelnost FPS poΦφtadla. Ve druhΘm kroku vytvß°φme objekt DirectDraw tak, jak jsme zvyklφ.
Ve 3. kroku zφskßme informace o funkcφch grafickΘ karty. Tyto informace m∙₧ete vyu₧φt pro p°φpadnΘ zjiÜt∞nφ n∞kter²ch vlastnostφ grafickΘ karty.
Dßle (4.krok) nßsleduje dvojice funkcφ SetCooperativeLevel() a SetDisplayMode(). I tyto dv∞ funkce dob°e znßme z p°edeÜl²ch lekcφ.
5.krok: Inicializujeme p°ednφ a zadnφ povrch. Ani zde nenφ nic novΘho, snad krom∞ prvnφho vyu₧itφ objektu z minulΘ lekce CSurface. Nejprve inicializujeme ukazatele na rozhranφ LPDIREDRAWSURFACE7 a potΘ z t∞chto ukazatel∙ vytvo°φme objekty CSurface.
V 6. kroku vytvß°φme internφ fonty pro vykreslenφ FPS apod. Nynφ koneΦn∞ vidφte, jak budeme pracovat s fonty. Nejd°φve se musφ zavolat funkce fntCreateFont(), kterß vytvo°φ nov² font z bitmapy. Funkci p°edßte °et∞zec, pod kter²m tento font p∙jde najφt (m∞l by b²t jedineΦn²), dßle cestu k bitmap∞ (obojφ jsme definovali) a p°φpadn∞ barvu fontu.
V 7. kroku pouze definuje pozadφ (Loading...). Jde tedy pouze o informaci u₧ivateli. Proto₧e flippovacφ smyΦka jeÜt∞ nenφ v provozu, musφte um∞le zavolat funkce UpdateBackground() a Present(). Tφm zajistφte, ₧e se pozadφ rovnou zobrazφ na monitoru.
8. krok je clipper. Pokud si to u₧ivatel p°eje, je na zadnφ povrch p°ipojen clipper. Prßci s nφm jsme ji₧ rovn∞₧ probφrali.
V 9. kroku inicializujeme gamma korekci. Nejprve zjistφme zda-li u₧ivatel chce °φdit gamma korekci, po tΘ zda-li to chce programßtor a nakonec zda-li je to v∙bec mo₧nΘ ze strany hardwaru. PotΘ zavolßme funkce QueryInterface(), abychom zφskali ukazatel na rozhranφ IDirectDrawGammaControl. Blφ₧e si o °φzenφ gammy povφme u funkcφ Increment a DecrementGamma().
10. a poslednφ krok je urΦen palet∞. Pokud u₧ivatel nastavφ 8-mi bitovou hloubku barev, systΘm naΦte bitmapu z p°ipravenΘho zdroje, kter² je vlo₧en p°φmo do knihovny.

Dßle si probereme funkci, kterß zjistφ zda-li mß vaÜe grafickß karta schopnost °φdit gamma korekci:

BOOL CDisplay::HasGammaSupport()
{
    // Get driver capabilities to determine gamma support.
    DDCAPS ddcaps;
    ZeroMemory( &ddcaps, sizeof(ddcaps) );
    ddcaps.dwSize = sizeof(ddcaps);

    GetDirectDraw()->GetCaps( &ddcaps, NULL );

    // Does the driver support gamma?
    // The DirectDraw emulation layer does not support overlays
    // so gamma related APIs will fail without hardware support.
 
   if( ddcaps.dwCaps2 & DDCAPS2_PRIMARYGAMMA )
        return TRUE;
    else
        return FALSE;
}

Funkce HasGammaSupport() vracφ TRUE, pokud gamma korekce je mo₧nß, jinak FALSE. Pou₧ijeme k tomu op∞t funkce objektu DirectDraw GetCaps(). Budou nßs zajφmat pouze schopnosti driveru (prvnφ parametr funkce) a nikoliv emulace (druhß parametr), kterß gammu neumφ. Gamma tedy musφ b²t podporovßna hardwarov∞. Nßsledujφcφm p°φkazem zjistφme hodnotu flagu DDCAPS2_PRIMARYGAMMA. Pokud je tato hodnota r∙znß od 0, funkce vracφ TRUE, jinak FALSE.

Funkci Present() ji₧ takΘ znßme z minul²ch lekcφ. Dnes ji obohatφme jen o prßt maliΦkostφ:

void CDisplay::Present()
{
    HRESULT dwResult;
   
//
    // Check initialization

    if(!m_bIsInit) {
        return;
    }
 
  //
    // Check if we want to draw FPS

    if(m_dwFlags & DDFLG_FPS) {
       
//
        // Draw FPS

        dwResult = UpdateFPS();
        if(dwResult != ERROR_SUCCESS) {
            DXERR("Cannot UpdateFPS due", dwResult);
        }
    }
   
//
    // Try to flip surfaces
    // Neverending loop

    while(1)
    {
        dwResult = m_surFront.GetSurface()->Flip(NULL, 0);
       
//we must restore main buffers
        if(dwResult == DDERR_SURFACELOST) {
            DXTRACE("Restoring surfaces");
            m_surFront.Restore();
            m_surBack.Restore();
            if(m_surBackground.IsValid()) {
                m_surBackground.Restore(TRUE);
            }
        }
        if(DD_OK == dwResult) {
            break;
        }
    }
}

Za prvΘ sledujeme, zda-li u₧ivatel mß zßjem o zobrazenφ FPS. V kladnΘm p°φpad∞ FPS obnovφme ve funkci UpdateFPS(). Za zmφnku jeÜt∞ stojφ obnova hlavnφch povrch∙ p°i jejich ztrßt∞ (viz. p°edeÜlΘ lekce). Vyu₧φvßme k tomu ΦlenskΘ metody Restore(). Jinak na tΘto metod∞ nenφ nic zajφmavΘho.

Nßsleduje dvojice metod definujφcφ pozadφ. NßÜ systΘm podporuje dva typy pozadφ. Za prvΘ je to jednobarevnΘ (solid) pozadφ definovanΘ nßsledujφcφ metodou:

HRESULT CDisplay::DefineBackground(COLORREF crColor)
{
  
 //
  
 // Release old surface if initialized
    m_surBackground.Release();
  
 //   
    // Check initialization

    if(!m_bIsInit) {
        return 1;
    }
 
  //
    // Save color of background

    m_BackColor = crColor;
  
 //
    // Enable solid background

    m_dwFlags |= DDFLG_SOLID;
 
  //
    // Disable scrolling

    m_dwFlags &= ~DDFLG_SCROLLING;
    return ERROR_SUCCESS;
}

Parametr crColor urΦuje barvu pozadφ. K definici tΘto barvy pou₧ijeme makro SURFACECOLOR(r,g,b). V souboru Common.h (projektu Common) je n∞kolik p°eddefinovan²ch barev. Na samotnΘ funkci nic nenφ. Uvolnφme povrch pozadφ, kter² zde nenφ pot°eba a musφme poΦφtat s tφm, ₧e u₧ivatel p°ed tφm mohl tento povrch pot°ebovat. Ulo₧φme si barvu pozadφ, abychom pozadφ mohli obnovit na zaΦßtku ka₧dΘho cyklu. Dßle systΘmu dßme v∞d∞t, ₧e chceme jednobarevnΘ pozadφ a vypneme pro jistotu flag dynamickΘho pozadφ, kter² je zde k niΦemu (viz. dßle). VÜimn∞te si, ₧e v ka₧dΘ funkci testujeme inicializaci objektu CDisplay.

Druhß verze definuje pozadφ na zßklad∞ bitmapy:

HRESULT CDisplay::DefineBackground(CString strBMPFile, DWORD dwFlags)
{
    HRESULT dwRet;
    DDSURFACEDESC2 ddsdesc;
    // Init size before use
    ddsdesc.dwSize = sizeof(DDSURFACEDESC2);
    //
    // Check initialization
  
 if(!m_bIsInit) {
        return 1;
    }
 
   //
    // Release old surface if initialized

    m_surBackground.Release();
 
   //
    // Try to create new surface for background bitmap
    dwRet = m_surBackground.Create(m_Res_X, m_Res_Y, dwFlags);
    DXERR("Creating surface for background due", dwRet);
    if(dwRet != ERROR_SUCCESS) {
        return dwRet;
    }
    //
    // Copy bitmap to surface
    dwRet = m_surBackground.CopyBitmap(strBMPFile);
    DXERR("Copying bitmap to surface due", dwRet);
    if(dwRet != ERROR_SUCCESS) {
        return dwRet;
    }
  
 //
    // Save info about character of background

    if(dwFlags & DDFLG_SCROLLING) {
        m_dwFlags |= DDFLG_SCROLLING;
    }
    else {
        m_dwFlags &= ~DDFLG_SCROLLING;
    }
   
//
    // Save info about background
    // Save internal path for restore

    m_BackBMP = strBMPFile;
    // No solid, we want bitmap background
    m_dwFlags &= ~DDFLG_SOLID;
    //
    // Init source rectangle for blitting
  
 m_BackSource.left = 0;
    m_BackSource.top = 0;
    m_BackSource.right = m_surBackground.Width();
    m_BackSource.bottom = m_surBackground.Height();
    return dwRet;
}

Zde je to u₧ o trochu slo₧it∞jÜφ. Za prvΘ op∞t uvolnφme p°edchozφ pozadφ (pokud n∞jakΘ je). Po tΘ vytvo°φme nov² povrch o velikosti rozliÜenφ. Do tohoto povrchu nakopφrujeme bitmapu urΦenou parametrem strBMPFile. Dßle zapneme nebo vypneme dynamickΘ pozadφ. Pokud u₧ivatel chce dynamickΘ pozadφ musφ funkce p°edat flag DDFLG_SCROLLING. Na efekt dynamickΘho pozadφ se podφvejte sami v p°φkladu. Ulo₧φme si jmΘno bitmapy, kterΘ pou₧ijeme p°i obnov∞ pozadφ. Vypneme volbu jednobarevnΘho pozadφ a nastavφme zdrojov² obdΘlnφk pro funkci Blt(). To je vÜe.

Te∩ si vysv∞tlφme mo₧nß principieln∞ nejslo₧it∞jÜφ funkci UpdateBackground():

HRESULT CDisplay::UpdateBackground()
{
    HRESULT dwReturn;
    CRect dest1, src1, dest2, src2;
  
 //
   
// Detect if background is scrolling or not
    if(m_dwFlags & DDFLG_SCROLLING) {
       
//
        // Moving of blitting area

        m_ScrollRect.left += 1;
        m_ScrollRect.right += 1;
       
//
        // Reset m_rectScroll ,
        // End of the screen: m_ScrollRect.left = 0, m_ScrollRect.right = m_Res_X;

        if(m_ScrollRect.left == (int)m_Res_X) {
            m_ScrollRect.left = 0;
            m_ScrollRect.right = m_Res_X;
        }
       
//
        // Compute of right and left parts of blitting source anf destination rectangles
        //

        // Left destination rectangle
        dest1.top = 0;
        dest1.left = 0;
        dest1.right = m_Res_X - m_ScrollRect.left;
        dest1.bottom = m_Res_Y;
       
//
        // Left source rectangle

        src1.top = 0;
        src1.left = m_ScrollRect.right - m_Res_X;
        src1.right = m_Res_X;
        src1.bottom = m_Res_Y;
        //
        // Right destination rectangle
        dest2.top = 0;
        dest2.left = m_Res_X - m_ScrollRect.left;
        dest2.right = m_Res_X;
        dest2.bottom = m_Res_Y;
        //       
        // Right source rectangle
        src2.top = 0;
        src2.left = 0;
        src2.right = m_ScrollRect.right - m_Res_X;
        src2.bottom = m_Res_Y;
        //
        // Blit both part of background to the BS
        //
        // Blit first part of bcg
        if(src1.left != src1.right) {
            dwReturn = m_surBack.Blt(dest1, src1, &m_surBackground);
            if(dwReturn != ERROR_SUCCESS) {
                DXERR("Cannot blit bitmap scrl part 1 background due", dwReturn);
                return dwReturn;
            }
        }
        //
        // Blit second part of bcg
        if(src2.left != src2.right) {
            dwReturn = m_surBack.Blt(dest2, src2, &m_surBackground);
            if(dwReturn != ERROR_SUCCESS) {
                DXERR("Cannot blit bitmap scrl part 2 background due", dwReturn);
                return dwReturn;
            }
        }
    }
    else {
        if(m_dwFlags & DDFLG_SOLID) {
            //
            // Blit solid nonscrolling background to the back buffer
            dwReturn = m_surBack.Blt(CRect(0, 0, m_Res_X, m_Res_Y), m_BackColor);
            if(dwReturn != ERROR_SUCCESS) {
                DXERR("Cannot blit solid background due", dwReturn);
                return dwReturn;
            }
        }
        else {
            //
            // Blit bitmap non scrolling background to the BS
            dwReturn = m_surBack.Blt(CRect(0, 0, m_Res_X, m_Res_Y), m_BackSource, &m_surBackground);
            if(dwReturn != ERROR_SUCCESS) {
                DXERR("Cannot blit bitmap background due", dwReturn);
                return dwReturn;
            }
        }    
    }
    return dwReturn;
}

Funkce obnovuje pozadφ, a¥ u₧ jednobarevnΘ Φi bitmapovΘ (statickΘ nebo dynamickΘ). V prvnφ Φßsti obnovujeme prßv∞ dynamickΘ pozadφ. K vysv∞tlenφ si dovolφm obrßzek:

Princip spoΦφvß ve dvou nezßvisl²ch vykreslenφ. Prvnφ vykreslφ Φßst pozadφ do obdΘlnφku dest1 a druh² do obdΘlnφku dest2. Ka₧d² cyklus se pom∞r mezi dest1 a dest2 m∞nφ: dest1 se zv∞tÜuje a dest2 se zmenÜuje a₧ dest1 vyplnφ cel² zadnφ buffer. V dalÜφm cyklu se zaΦne na novo. Zßrove≥ se takΘ musφ sprßvn∞ inicializovat zdrojovΘ obdΘlnφky. Ty jsou urΦeny pr∙nikem obdΘlnφk∙ dest do obdΘlnφku povrchu pozadφ. Pom∞r obou obdΘlnφku je dßn obdΘlnφkem m_ScrollRect. Vidφme, ₧e hodnoty left a right se ka₧d²m cyklem inkrementujφ a po nabytφ maximßlnφ hodnoty (rozliÜenφ v horizontßlnφm sm∞ru) se hodnota left vynuluje a hodnota right inicializuje na rozliÜenφ m_Res_X. Na konci tΘto sekce je samotnΘ vykreslenφ obou Φßstφ.

V dalÜφ Φßsti funkce, se vykresluje statickΘ pozadφ bu∩ jednobarevnΘ nebo bitmapovΘ. JednobarevnΘ vykreslenφ je velice jednoduchΘ. Prost∞ zavolßme verzi funkce Blt(), kterß kreslφ jednobarevnΘ plochy do povrchu. Pokud chceme vykreslovat bitmapovΘ pozadφ, zavolßme druhou verzi tΘto funkce. Parametry jsou zcela logickΘ.

PokraΦujme dßle s funkcφ UpdateFPS(). Jak nßzev napovφdß, funkce mß na starosti v²poΦet a aktualizaci ukazatele FPS, p°φpadn∞ stav grafickΘ pam∞ti:

HRESULT CDisplay::UpdateFPS()
{
    DWORD dwRet;

    //
    // Show video memory
 
   if(setGetSetupInt(_S_SECTION_GRAPHICS, _S_KEY_SHOWVIDMEM)) {
   
        DDCAPS Driver;
        ZeroMemory(&Driver, sizeof(DDCAPS));
        Driver.dwSize = sizeof(DDCAPS);
  
     //
        // Get capabilities of hardware

        dwRet = m_lpDD->GetCaps(&Driver, NULL);
        if(dwRet != DD_OK) {
            DXERR ("Getting caps about hardware", dwRet);
            Clean();
            return dwRet;
        }
        CString csTMem, csFMem;
        csTMem.Format("Total video memory: %d kB", Driver.dwVidMemTotal / 1024);
        csFMem.Format("Free video memory: %d kB", Driver.dwVidMemFree / 1024);

        fntDrawText(0, 20, csTMem, _S_FONT_ARIAL);
        fntDrawText(0, 40, csFMem, _S_FONT_ARIAL);
    }   
 
   //
    // Get time of system start

    m_StartTime = GetTickCount();
   
//
    // Increment frames counter

    m_Frames++;
   
//
    // Compute number of frames per one second

    if((m_StartTime - m_StopTime) >= FPS_REFRESH_RATE) {
        m_strFrames.Format("%2.1f", m_Frames * 1000 / (m_StartTime - m_StopTime));
        m_Frames = 0;
      
 //
        // Save old-new time

        m_StopTime = m_StartTime;
    }
   
//
    // Draw FPS to the screen

    return fntDrawText(0, 0, m_strFrames, _S_FONT_ARIAL);
}

Pokud si u₧ivatel prost°ednictvφm konfiguraΦnφho souboru p°eje zobrazit stav pam∞ti, musφme tento stav vydolovat pomocφ ji₧ znßmΘ funkce GetCaps(). Struktura DDCAPS skr²vß dva atributy dwVidMemTotal pro celkovΘ mno₧stvφ grafickΘ pam∞ti a dwVidMemFree pro volnΘ mno₧stvφ pam∞ti. Hodnoty, kterΘ jsou v bajtech, d∞lφme Φφslem 1024, abychom dosp∞li ke kB. Pomocφ funkce fntDrawText() vykreslφme °et∞zec na obrazovku. Funkce mß 4 parametry. Prvnφ dva urΦujφ sou°adnice textu na monitoru. DalÜφ parametr je °et∞zec, kter² se bude vykreslovat. Poslednφm parametrem je ID fontu, kter² jsme p°edem vytvo°ili funkcφ fntCreateFont(). Zkuste si vytvo°it metodu, kterß bude fungovat podobn∞ jako funkce printf() tj. bude mφt prom∞nn² poΦet parametr∙ a po₧adovan² °et∞zec automaticky zformßtuje a vykreslφ.

O trochu slo₧it∞jÜφ je to s FPS. FPS se aktualizuje jednou za periodu urΦenou konstantou FPS_REFRESH_RATE. V tΘto dob∞ zvyÜujeme poΦet obnoven²ch snφmk∙ o 1. Pokud je Φas obnovit informaci o stavu FPS, spoΦφtßme FPS tak, ₧e poΦet snφmk∙ vyd∞lφme uplynul²m Φasem od poslednφ aktualizace. Konstanta FPS_REFRESH_RATE je v milisekundßch, ale my chceme frame per second, tak₧e je t°eba vÜe p°evΘst na sekundy. Navφc je pot°eba vynulovat poΦφtadlo snφmk∙. Nakonec vykreslφme aktußlnφ stav FPS stejn²m zp∙sobem jako u pam∞ti.

Zkusme se nynφ rozebrat dvojicφ funkce IncrementGamma() a DecrementGamma(). Ob∞ funkce jsou tΘm∞° identickΘ, tak₧e je tu nebudu rozepisovat ob∞. Na mal² rozdφl samoz°ejm∞ upozornφm:

HRESULT CDisplay::IncrementGamma(int _Amount)
{
    DWORD dwRet;
    DDGAMMARAMP ramp;

    if(m_dwFlags & DDFLG_GAMMA) {
   
        m_CurGamma += _Amount;
        if(m_CurGamma > 256) {
            m_CurGamma = 256;
            return ERROR_SUCCESS;
        }

        ZeroMemory( &ramp, sizeof(ramp) );

        dwRet = m_GammaControl->GetGammaRamp( 0, &ramp);
        if(dwRet != DD_OK) {
            return dwRet;
        }
   
        WORD dwGamma = 0;
        m_CurGamma += _Amount;
// ve funkce DecrementGamma() je zde m_CurGamma -= _Amount;
        if(m_CurGamma > 256) m_CurGamma = 256;
   
            for( int iColor = 0; iColor < 256; iColor++ )
            {
                ramp.red[iColor] = dwGamma;
                ramp.green[iColor] = dwGamma;
                ramp.blue[iColor] = dwGamma;
   
                dwGamma += (WORD) m_CurGamma;
            }

        dwRet = m_GammaControl->SetGammaRamp( 0, &ramp );
        if(dwRet != DD_OK) {
            return dwRet;
        }
    }
    return 1;
//ERROR_NOGAMMA;
}

Princip je jednoduch². Nejd°φve zφskßme aktußlnφ stav gammy, po tΘ p°iΦteme ke vÜem barevn²m slo₧kßm parametr funkce a tento nov² stav nastavφme.

Jak jsem slφbil v ·vodu, nynφ si povφme n∞co blφ₧e k °φzenφ gammy. SystΘm dokß₧e zm∞nit barevnΘ vlastnosti povrch∙, ani₧ by m∞nil jejich obsah. Funkci si m∙₧ete p°edstavit jako filtr skrz kter² pro₧enete vÜechny pixely danΘho povrchu (ve skuteΦnosti to lze jen na p°ednφm povrchu) t∞sn∞ p°edtφm ne₧ se zobrazφ na monitor. Pomocφ rozhranφ IDirectDrawGammaControl m∙₧ete °φdit tento filtr a dosßhnout tak zajφmav²ch efekt∙ jako jsou r∙znΘ zßblesky Φi ztmavenφ scΘny. V naÜem systΘmu je °φzenφ velice jednoduchΘ. ╪φdφme pouze zesv∞tlenφ a ztmavenφ scΘny. To v praxi znamenß, ₧e m∞nφme vÜechny t°i slo₧ky RGB stejn∞. K modifikaci barvy jednotliv²ch pixel∙ se pou₧φvajφ tzv. ramp levels pomocφ nich₧ se definuje zßvislost vstupu a v²stupu filtru. Takovou zßvislost m∙₧ete vid∞t i na nßsledujφcφm obrßzku:

Tyto modifikovanΘ v²stupnφ hodnoty dßle prochßzejφ p°φmo do D/A p°evodnφku grafickΘ karty (DAC) a pak rovnou v analogovΘ podob∞ na monitor.

Nejprve tedy zφskßme objekt typu DDGAMMARAMP obsahujφcφ ramp levels vÜech t°φ barevn²ch slo₧ek. Tyto hodnoty zφskßme pomocφ funkce GetGammaRamp().

Pokud pou₧φvßme gamma korekci je Barva X nahrazena Barvou Y. Pokud graf prochßzφ osou prvnφho kvadrantu, v²stupnφ barva je stejnß jako vstupnφ (jin²mi slovy, barva se nijak nemodifikuje). Ve funkci je smyΦka for, ve kterΘ se hodnoty v²stupnφ barvy modifikujφ podle prom∞nnΘ m_CurGamma. ╚φm vyÜÜφ jsou tyto hodnoty, tφm je v²stupnφ barva sv∞tlejÜφ, proto₧e toto nastavenφ provßdφme u vÜech t°φ slo₧ek zßrove≥. V poli tedy budou vzestupnΘ hodnoty podobn∞ jako na obrßzku. Funkce m∙₧e modifikovat tak, ₧e zßvislost nebude lineßrnφ a m∙₧ete tak nap°φklad ·pln∞ potlaΦit n∞kterΘ barvy na povrchu.

V poslednφm kroku nastavφm novΘ hodnoty gamma ramp pomocφ funkce SetGammaRamp(). Funkce DecrementGamma() se liÜφ v jedinΘm znamΘnku. Ve zdrojovΘm k≤du je na to upozorn∞no v ÜedΘm komentß°i.

KoneΦn∞ tu mßme poslednφ funkci! Je to celkem slo₧itß funkce SetPalette(). Proto₧e paletu nebudeme pou₧φvat, nebudu zde funkci rozebφrat. Funkce zφskß paletu z p°eddefinovanΘ bitmapy a tuto paletu nastavφ. Abyste paletu mohli pou₧φt, musφte vlo₧it do knihovny zdroj (bitmapu), kterou nazv∞te "PALETA". Tato bitmapa m∙₧e b²t nap°φklad 1x1, ale d∙le₧itß je jejφ paleta, kterou vytvo°φte nap°φklad v CorelDraw p°i exportu.

13.4. Export funkcφ Display.dll

Nynφ ji₧ mßme knihovnu p°ipravenou k pou₧itφ. Abychom si to trochu ulehΦili, nebudeme v klientskΘ aplikaci vytvß°et objekt CDisplay, ale vyexportujeme n∞kterΘ jejφ funkce.

Do projektu p°idejte soubory novΘ Common.h a Common.cpp. V t∞chto dvou souborech bude deklarace a definice exportovan²ch funkcφ. V Common.cpp navφc musφme vytvo°it objekt CDisplay, pomocφ kterΘho budeme volat v²Üe definovanΘ metody. Intern∞ takΘ pou₧φvßm objekt CDDFontEngine.

Common.h:

#ifndef DISPLAY_COMMON_H
    #define DISPLAY_COMMON_H
    //
    // Include DD headers

    #include <ddraw.h>

    #include "..\Common\Common.h"
    //
    // Export/import macros
 
   #ifndef DISPLAY_API
        #define DISPLAY_API __declspec( dllimport )
    #endif
// DISPLAY_API

    class CDisplay;
    class CSurface;

    //
    // Flags for CreateFullScreenSystem()
 
   #define DDFLG_CLIPPER 0x00000001
    #define DDFLG_WINDOWMODE 0x00000002
    #define DDFLG_FULLSCREEN 0x00000004
    #define DDFLG_GAMMA 0x00000008
    #define DDFLG_PALETTE 0x00000010
    // Common flags
    #define DDFLG_FPS 0x00000020
    // Flags for DefineBackground()
    #define DDFLG_SYSTEM_MEMORY 0x10000000
    #define DDFLG_VIDEO_MEMORY 0x20000000
    #define DDFLG_SCROLLING 0x40000000
    #define DDFLG_SOLID 0x80000000
    #define DDFLG_COLORKEY 0xF0000000
 
   //
    // Keys
    // Graphics section

    #define _S_KEY_WIDTH _T("ScreenWidth")
    #define _S_KEY_HEIGHT _T("ScreenHeight")
    #define _S_KEY_DEPTH _T("ScreenDepth")
    #define _S_KEY_FPS _T("FPS")
    #define _S_KEY_USEGAMMA _T("UseGamma")
    #define _S_KEY_SHOWVIDMEM _T("ShowVidMem")
   
    #include "Surface.h"
    #include "DDFontEngine.h"
    #include "Core.h"
   
    //exports
    DISPLAY_API HRESULT disInit(HWND hWnd, UINT uFlags);
    DISPLAY_API HRESULT disDefineBackground(COLORREF crColor);
    DISPLAY_API HRESULT disDefineBackground(CString strBMPFile, UINT nFlags);
   
    DISPLAY_API HRESULT disBlt(CRect rectDestin, CRect rectSource, CSurface *surSource);
    DISPLAY_API HRESULT disBlt(CRect rectDestin, COLORREF crColor);
   
    DISPLAY_API CSize     disGetResolution();
    DISPLAY_API HRESULT   disUpdateBackground();

    DISPLAY_API HRESULT disPresent();
    DISPLAY_API HRESULT disDrawText(CString strText, int x = 0, int y = 0,
                                    COLORREF crColor = TC_YELLOW,
                                    LPTSTR szFontName = NULL, int iHeight = 100);

    DISPLAY_API HRESULT disIncreaseGamma(int d = 8);
    DISPLAY_API HRESULT disDecreaseGamma(int d = 8);
    DISPLAY_API HRESULT disFlash(DWORD dwFlashTime = 320, DWORD dwUnflashTime = 500);

    DISPLAY_API CDisplay* disGetDisplay();

    DISPLAY_API HRESULT fntDrawText(int x, int y, CString csText, CString csFont);
    DISPLAY_API HRESULT fntCreateFont(CString csFontFile, CString csFontName, COLORREF crColor = 0);


#endif
// DISPLAY_COMMON_H

V tomto souboru takΘ vidφte n∞kterΘ definice, kterΘ jsem uvedl d°φve.

Common.cpp:

#include "stdafx.h"

#define DISPLAY_API __declspec(dllexport)

#include "Common.h"

CDisplay theDisplay;
CDDFontEngine theFontEngine;

//
// Exports function

DISPLAY_API HRESULT disInit(HWND hWnd, UINT uFlags)
{
    return theDisplay.CreateFullScreenSystem(hWnd, uFlags);
}

DISPLAY_API HRESULT disDefineBackground(COLORREF crColor)
{
    return theDisplay.DefineBackground(crColor);
}

DISPLAY_API HRESULT disDefineBackground(CString strBMPFile, UINT nFlags)
{
    return theDisplay.DefineBackground(strBMPFile, nFlags);
}

DISPLAY_API HRESULT disBlt(CRect rectDestin, CRect rectSource, CSurface* surSource)
{
    return theDisplay.GetBackSurface()->Blt(rectDestin, rectSource, surSource);
}

DISPLAY_API HRESULT disBlt(CRect rectDestin, COLORREF crColor)
{
    return theDisplay.GetBackSurface()->Blt(rectDestin, crColor);
}

DISPLAY_API CSize disGetResolution()
{
    return theDisplay.GetResolution();
}

DISPLAY_API HRESULT disUpdateBackground()
{
    return theDisplay.UpdateBackground();
}

DISPLAY_API HRESULT disPresent()
{
    theDisplay.Present();
    return ERROR_SUCCESS;
}

DISPLAY_API HRESULT disIncreaseGamma(int d)
{
    return theDisplay.IncrementGamma(d);
}

DISPLAY_API HRESULT disDecreaseGamma(int d)
{
    return theDisplay.DecrementGamma(d);
}

DISPLAY_API CDisplay* disGetDisplay()
{
    return &theDisplay;
}

DISPLAY_API HRESULT fntDrawText(int x, int y, CString csText, CString csFont)
{
    return theFontEngine.DrawText(x, y, csText, csFont);
}

DISPLAY_API HRESULT fntCreateFont(CString csFontFile, CString csFontName, COLORREF crColor)
{
    return theFontEngine.CreateFont(csFontFile, csFontName, crColor);
}

Nynφ ji₧ staΦφ vlo₧it hlaviΦkov² soubor Common.h z projektu Display do hlavnφho projektu Game a m∙₧ete pou₧φt vÜechny v²Üe definovanΘ funkce. Pokud by Vßm n∞co neÜlo nebo nefungovalo, podφvejte se do p°φkladu, kter² najdete v sekci Downloads.

V²Üe uveden² postup exportu funkcφ jsme probφrali v minul²ch lekcφch, tak₧e se zde nebudu dßle rozepisovat.

13.5. Zßv∞r

A je tu op∞t konec. DneÜnφ lekce byla celkem rozsßhlß, ₧e? P°esto se nedov∞d∞li tΘm∞° nic novΘho. Jen aplikujeme to, co u₧ znßme.

V p°φÜtφ lekci zapojφme do naÜeho projektu knihovnu Input.dll, kterou ji₧ mßme tΘm∞° p°ipravenou. StaΦφ ji jen malinko modifikovat, abychom vykreslovali kurzor pomocφ DirectDraw a m∙₧eme to celΘ spustit. PotΘ zaΦneme op∞t n∞co novΘho.

T∞Üφm se p°φÜt∞ nashledanou.

Ji°φ Formßnek