ATTENTION READERS! Lucky's VB Gaming Site is no longer active. For updated game programming information and tutorials, please visit The Game Programming Wiki!
Een bitmap laden en afbeelden
Het eerste dat je moet doen vooraleer aan een DirectX project te beginnen, is naar de DX7 Type Library verwijzen in je project. Dit doe je als volgt: start een niew project and klik op het 'References' item in het 'Project' menu. Een dialoogvenster komt dan tevoorschijn. Scroll naar beneden en kruis het vakje naast "DirectX 7 for Visual Basic Type Library" aan. Dit laat je toe om de DirectX API aan te spreken vanuit je project.
Om nu een bitmap te laden en af te beelden, moeten we eerst de DirectX variabelen en zogenaamde 'screen modes' initialiseren.
Dim dx As New DirectX7
Dim dd As New DirectDraw7
Set dd = dx.DirectDrawCreate("")
Call dd.SetCooperativeLevel(Me.hWnd, DDSCL_FULLSCREEN Or DDSCL_EXCLUSIVE Or DDSCL_ALLOWREBOOT)
Call dd.SetDisplayMode(640, 480, 16, 0, DDSDM_DEFAULT)
De variabele "dx" is een instantie van de DirectX7 variabele zelf. Dit wel zeggen dat "dx" ondergeschikt is aan het DirectX7 object. Van dit object maken we namelijk alle afgeleide objecten zoals het DirectDraw7 object dat gemaakt wordt door de DirectDrawCreate methode aan te roepen en het een lege string door te geven. Dit zorgt ervoor dat DirectX de huidige display driver gaat gebruiken. Het resultaat van deze functie is de creatie van een DirectDraw7 object dat we gaan alloceren als de variabele "dd". Vanuit "dd" kunnen we de 'Cooperative Level' bepalen van ons programma. Dit bepaalt de eigenschappen van het DirectX venster, bv: Fullscreen of Windowed Mode, hoe we het scherm gaan 'aanspreken' en hoe andere programma's, die tegelijkertijd actief zijn, het scherm mogen aanspreken.
Het eerste argument dat we doorgeven is de 'handle' van het venster dat we als hoofdvenster voor DirectX willen gebruiken, dit kan door bv: Me.hWnd, als we de code invoeren in het venster zelf. Het tweede argument is een 'flag' die bepaalt hoe het venster zich moet gedragen. DDSCL_FULLSCREEN zorgt ervoor dat we in fullscreen mode zullen werken (we zouden ook DDSCL_NORMAL kunnen gebruiken voor een Windows-Venster, maar dit is aanzienlijk trager). DDSCL_EXCLUSIVE betekent dat we de enigen willen zijn met toegang tot het scherm en DDSCL_ALLOWREBOOT ten slotte staat toe om 'soft reboots' (CTRL-ALT-DEL) uit te voeren.
Het volgende dat we moeten doen is een primair tekengebied of 'Primary Surface' definiëren en een flippable backbuffer eraan vasthangen.
Dim Primary As DirectDrawSurface7 'Primary surface
Dim BackBuffer As DirectDrawSurface7 'Backbuffer surface
Dim ddsdPrimary As DDSURFACEDESC2 'Primary surface description
Dim caps As DDSCAPS2 'Capabilities description
ddsdPrimary.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT
ddsdPrimary.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Or DDSCAPS_FLIP Or DDSCAPS_COMPLEX
ddsdPrimary.lBackBufferCount = 1
Set Primary = dd.CreateSurface(ddsdPrimary)
caps.lCaps = DDSCAPS_BACKBUFFER
Set BackBuffer = Primary.GetAttachedSurface(caps)
Oké, hier is dus duidelijk wat uitleg nodig! :)
Eerst de variabelen. "Primary" and "Backbuffer" zijn eerste gewone surfaces (=teken gebieden), maar worden later de 'Primary Display Device' (=Eerste buffer; wat je uiteindelijk ziet op je scherm) en de 'Backbuffer' (=De buffer waarop je tekent en pas als je klaar bent flipt naar de Primary).
"ddsdPrimary" is een DirectDraw Surface description, dit bepaalt het gedrag van de surface. Ten slotte, is er de variable "caps". Dit is een DirectDraw capabilities description die gebruikt wordt om de Primary Surface te binden aan de Backbuffer.
Nu moeten we nog de surface description van de primary surface "ddsdPrimary" bepalen. De "ddsdPrimary.lFlags" instellingen worden gebruikt om de "dd.CreateSurface" methode te zeggen welke "ddsdPrimary" waarden in acht genomen moeten worden om de surface aan te maken. Klint redelijk moeilijk maar is zéér logisch als je het volgende weet...
Door "DDSD_CAPS" door te geven wordt er met "ddsdPrimary.ddsCaps.lCaps" rekening gehouden. Door DDSD_BACKBUFFERCOUNT door te geven wordt er rekening gehouden met "ddsdPrimary.lBackBufferCount". Capiche?
Oké... Nu geven we "ddsdPrimary.ddsCaps.lCaps" de DDSCAPS_PRIMARYSURFACE flag om het te definieren als, inderdaad, onze primary surface. DDSCAPS_FLIP laat DirectX weten dat deze surface deel uitmaakt van een zogenaamde flipping chain. Je kan namelijk meer dan 2 surfaces hebben ! DDSCAPS_COMPLEX laat deze andere surfaces, bv. de Backbuffer, toe om aan de Primary Surface aangehangen te worden.
En ten slotte wordt "ddsdPrimary.lBackBufferCount" op "1" gezet. Dit betekent dat we slechts 1 backbuffer gaan gebruiken met onze Primary Surface.
OPMERKING: Je kan er meerdere hebben! Mor dees is gewoon om't wa simpelkes t'houden, hé!
Nu dat we hebben beschreven hoe de Primary Surface gemaakt moet worden, kunnen we ze eindelijk aanmaken. Om dit te doen stellen we de Primary Surface gelijk aan de 'return value' (=teruggegeven waarde van een functie) van "dd.CreateSurface(ddsdPrimary)". Deze methode geeft een surface terug, gebaseerd op de descriptie die we doorgeven als argument. Dit levert dus kortweg een surface op met de beschrijving die we hadden gedefinieerd!
Eens we de Primary Surface klaar hebben, kunnen we de Backbuffer eraan vasthangen. "caps.lCaps" beschrijft het type 'capabilities' dat we zouden willen verkrijgen van de Primary Surface. We geven "caps" door aan de "Primary.GetAttachedSurface" methode en als 'output' krijgen we een surface dat gebruikt kan worden als backbuffer.
Samengevat hebben we nu onze Primary Surface en onze Backbuffer surface klaar. Als we nu nog van plan zijn om een bitmap af te beelden met behulp van deze surfaces, moeten we een bitmap laden in nog een andere surface en dan deze blitten (=snel overteken door het uitvoeren van een BIT BLOCK TRANSFER, kopieren dus...) naar de Backbuffer. Zo doen we dat:
Dim Sprite as DirectDrawSurface7
Dim ddsdNewSprite As DDSURFACEDESC2
ddsdNewSprite.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT
ddsdNewSprite.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
ddsdNewSprite.lWidth = 60
ddsdNewSprite.lHeight = 60
Set Sprite = dd.CreateSurfaceFromFile(App.Path & "\Ships\Vegan00.BMP", ddsdNewSprite)
Sprite wordt de surface waarin we onze bitmap gaan laden. Zoals we al eerder gedaan hebben, gaan we nu ook een DirectDraw surface description aanmaken: "ddsdNewSprite". Merk op dat "ddsd..." staat voor DirectDraw Surface Description. De namen van deze variabelen zijn dus nie zomaar willekeurig!
Terug naar de code. We hebben dus een nieuwe variabele (object om meer precies te zijn), maar deze gaan we anders instellen. We gaan nu "DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT" gebruiken als "lFlags" eigenschap. DDSD_CAPS wordt terug gebruikt, maar DDSD_WIDTH en DDSD_HEIGHT worden nu gebruikt om aan te tonen dat er rekening gehouden moet worden met de breedte en hoogte variabelen van de descriptie wanneer de surface wordt aangemaakt.
"ddsdNewSprite.ddsCaps" wordt gezet op "DDSDCAPS_OFFSCREENPLAIN" zodat deze surface gememoriseerd, alloceert of hoe je het ook wil zeggen, wordt als een 'off screen', niet getoonde surface. De "lWidth" en "lHeight" eigenschappen van "ddsdNewSprite" krijgen de waarden van het aantal pixels van de breedte en hoogte van de bitmap die we nog moeten laden.
Oké, nu dat de surface description klaar is, kunnen we eindelijk onze bitmap laden.
Dit kan op twee mogelijkheden: ofwel laad je de afbeelding vanuit een bitmap-bestand, ofwel vanuit een resource bestand. Een resource bestand omvat verschillende multimedia bestanden. Als je kiest om een bitmap-bestand af te beelden, gebruik je de "CreateSurfaceFromFile" methode, anders gebruik je de "CreateSurfaceFromResource" methode. Bijde zijn te vinden in het "dd" object.
In dit geval gaan we een bitmap-bestand laden. Dit gebeurt, zoals eerder vermeld, met de "CreateSurfaceFromFile" methode. Deze functie geeft een return value, deze wordt onze surface. We alloceren deze surface door "Set Sprite = ..." te gebruiken.
Bovenaan de code zie je dat "Sprite" een DirectDrawSurface7 object is. Dit moeten we dus op het scherm afgebeeld zien te krijgen.
Dim SrcRect As RECT
Dim DestRect As RECT
With SrcRect
.Bottom = 60
.Left = 0
.Right = 60
.Top = 0
End With
With DestRect
.Bottom = 60
.Left = 0
.Right = 60
.Top = 0
End With
BackBuffer.Blt DestRect, Sprite, SrcRect, DDBLT_WAIT
Wat ons nu rest is onze sprite (=bitmap) afbeelden of 'blitten' op de Backbuffer. Vooraleer we dit kunnen doen, moeten we de size rectangles (=rechthoekige gebieden) bepalen waarvan en waarop we gaan blitten. De "SrcRect" is het gebied waarvan we gaan blitten, de bron eigenlijk, en "DestRect" is het gebied waarop we gaan blitten. Al vlug heb je door dat de variabelen overeenstemmen met de "lWidth" en "lHeight" properties van de surface.
Door wat te spelen met deze variabelen kan je interessante effected bekomen. Als je bijvoorbeeld de hoogte en/of breedte waarden verandert van "DestRect", bekom je een zoom-effect!
Nu kunnen we "Backbuffer.Blt" aanroepen om de sprite op de backbuffer te blitten. Zoals gewoonlijk geven we de gepaste argumenten door samen met de "DDBLT_WAIT" flag. Dit zorgt ervoor dat er pas getekend wordt op de backbuffer als deze vrij is, en daardoor mogelijke fouten vermijdt.
Het laatste dat ons nu rest is de backbuffer flippen naar de Primary. Dit doe je als volgt:
Primary.Flip Nothing, DDFLIP_WAIT
Dit is het enige dat nog nodig is. "Primary.Flip" zorgt evoor dat de volgende surface in de flipping chain naar de Primary geflipt wordt en andersom. Als argumenten geven we eerst "Nothing" door en daarna de "DDFLIP_WAIT" flag. In plaats van "Nothing" zouden we evengoed "Backbuffer" kunnen gebruiken of eenderwelke surface die aan de Primary vasthangt, maar aangezien we maar 1 backbuffer hebben en de volgorde van de flipping chain niet willen wijzigen, volstaat het om "Nothing" door te geven.
"DDFLIP_WAIT" is een flag die DirectX eerst alle vorige 'flips' laat uitvoeren, vooraleer aan deze te beginnen.
Voilà! Zo simpel is het! De bitmap zou nu correct in de linkerbovenhoek van je scherm moeten komen.
Hier kan je
één van Lucky's DirectX tutorials downloaden die dit onderwerp behandelt.