www.codeworx.org/directx_tuts/Wie blitte ich ein Bild auf die primäre Surface?

Wie blitte ich ein Bild auf die primäre Surface?
(von Jens Konerow)

Was ist überhaupt eine Surface?

Eine Surface kann man sich als ein Blatt Papier vorstellen, auf dem dann das Bild gezeichnet wird. Die Surface ist ein zusammenhängender Speicherbereich. Dieser kann im Videospeicher liegen oder im Systemspeicher. Der Systemspeicher ist aber wesentlich langsamer als der Videospeicher.
Es werden 5 Surface-Typen unterschieden. Wir wollen jetzt allerdings nur auf 2 eingehen.
Die eine ist die primäre Surface und die zweite ist die Offscreen-Surface. Der Anwender sieht aber nur die primäre Surface. Das Bild wird erst auf der Offscreen-Surface, auch BackBuffer genannt, aufgebaut; wenn es dann vollständig ist, dann wird es auf einen Schlag auf die primäre Surface kopiert. Durch dieses Verfahren wird sichergestellt, das der Anwender vom Aufbau des Bildes nichts mitbekommt und kein flackerndes Bild sieht.

Wie erstelle ich eine Surface?

Wir erstellen ein Standard-EXE-Projekt und ordnen auf dem Formular eine Picture-Box an, auf der das Bild später zu sehen sein wird. Dann müssen wir die DirectX-API in unser VB-Projekt einbinden. Das machen wie, indem wir unter Projekt --> Verweise in der Liste DirectX7 for Visual Basic Library ankreuzen und dann auf OK klicken. Jetzt müssen wir erst ein DirectX-Objekt erstellen und anschließend werden wir die Variable für das DirectDraw-Objekt deklarieren. Das sieht dann wie folgt aus:

Dim objDX As New DirectX7
Dim objDD As DirectDraw7

Jetzt wollen wir die Variablen für die Surface und die Variablen vom Typ DDSURFACEDESC2 deklarieren. DDSURFACEDESC2 enthält die Beschreibung einer DirectDrawSurface. Ok, als erstes deklarieren wir die Variablen für die Surface:

Dim objPrimSurf As DirectDrawSurface7
Dim objBackSurf As DirectDrawSurface7

Nun kommen die Variablen vom Typ DDSURFACEDESC2 an die Reihe:

Dim ddsdPrimSurf As DDSURFACEDESC2
Dim ddsdBackSurf As DDSURFACEDESC2

Das waren die Deklarationen! Nun werden wir die Variablen initialisieren, sprich: wir werden die Objekte erstellen. Als erstes werde ich den Zugriff auf die Grafikkarte erzeugen:

Set objDD = objDX.DirectDrawCreate("")

Wurde der String leer gelassen, wird der primäre Display-Device genutzt. Nun legen wir fest, dass wir einen Fenster-Anwendung haben wollen:

Call objDD.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL)

Me.hWnd gibt uns das Handle des aktiven Form-Objekts und DDSCL_NORMAL gibt an, dass wir eine normale Anwendung möchten. Nun wollen wir die Beschreibungen der primären Surface festlegen:

ddsdPrimSurf.lFlags = DDSD_CAPS
ddsdPrimSurf.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE

Nun wird die primäre Surface erstellt:

Set objPrimSurf = DD.CreateSurface(ddsdPrimSurf)

DDSD_CAPS gibt uns den Zugriff auf die ddsCaps-Datenstruktur frei und DDSCAPS_PRIMARYSURFACE legt fest, dass das eine primäre Surface sein soll.
Mit Set objPrimSurf = DD.CreateSurface(ddsdPrimSurf) wird die primäre Surface erstellt. Jetzt kommen wir zur der zweiten Surface, die Offscreen-Surface. Von dieser wird das Bild dann auf die primäre Surface geblittet (kopiert).
Wir gehen erstmal genauso vor, wie oben beschrieben:

ddsdBackSurf.lFlags = DDSD_CAPS
ddsdBackSurf.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
Set objBackSurf = DD.CreateSurfaceFromFile(App.Path & _
"\Iron.bmp", dsdBackSurf))

DDSD_CAPS gibt uns den Zugriff auf die ddsCaps-Datenstruktur frei und DDSCAPS_PRIMARYSURFACE legt fest, dass das eine primäre Surface sein soll.
Der einzige Unterschied ist hier, das wir anstatt der CreateSurface-Methode die CreateSurfaceFromFile-Methode nehmen. Hiermit laden wir das angegebene Bild gleich in die Offscreen-Surface. Jetzt sehen wir das Bild aber noch nicht auf unseren Bildschirm! Dazu müssen wir das Bild erst noch auf die primäre Surface blitten. Zuerst legen wir aber die RECT-Variablen fest und füllen diese mit Daten:

Dim rPrimSurf As RECT
Dim rBackSurf As RECT
Call objDX.GetWindowRect(Picture1.hWnd, rPrimSurf)
rBackSurf.Bottom = ddsdBackSurf.lHeight
rBackSurf.Right = ddsdBackSurf.lWidth

Jetzt stellt sich die Frage, wozu wir dieses benötigen. Zum Blitten benötigen wir eine Angabe zu der Quelle und zum Ziel, sprich: wir müssen den Bereich definieren, von wo die Daten kommen und wo sie hin sollen. Das Ziel ist ja unsere Picture-Box.
Um die Größe dieser Picture-Box zu ermitteln, verwenden wir die GetWindowRect-Methode. Diese Methode schreibt uns die Daten (auf die das Handle verweist) in die rPrimSurf-Variable. Die Größe der Offscreen-Surface können wir ganz leicht ermitteln, da wir die Surface durch die CreateSurfaceFromFile-Methode schon mit Daten gefüllt haben.
Zum Schluss blitten wir das Bild auf die primäre Surface:

Call objPrimSurf.blt(rPrimSurf, objBackSurf, _
rBackSurf,DDBLT_WAIT)

Ich denke, was rPrimSurf und rBackSurf in dieser Blit-Funktion bedeutet, brauche ich nicht weiter erklären. Zwischen den beiden Variablen vom Typ RECT wird die Surface angegeben, von der das Bild auf die primäre Surface geblittet werden soll, und DDBLT_WAIT gibt lediglich an, dass DirectDraw auf die Fertigstellung des Blitvorgangs warten soll.

Download TutorialBlitten.zip

Das wars! Ich hoffe, ich habe alles einleuchtend erklärt. Wenn ihr Fragen, Hinweise oder Kritik habt, dann schreibt mir an: JensK@vbpc.de