directX mit visual basic programmieren praxis und referenz
uwe kettermann christian schmelzer
new technology Markt+Technik Verlag
Die Deutsche Bibliothek – CIP-Einheitsaufnahme Ein Titeldatensatz für diese Publikation ist bei Der Deutschen Bibliothek erhältlich. Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar.
Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden. Umwelthinweis: Dieses Buch wurde auf chlorfrei gebleichtem Papier gedruckt. Die Einschrumpffolie – zum Schmutz vor Verschmutzung – ist aus umweltverträglichem und recyclingfähigem PE-Material.
10 9 8 7 6 5 4 3 2 1 03 02 01 00
ISBN 3-8272-5766-2
© 2000 by Markt+Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH, Martin-Kollar-Straße 10–12, D 81829 München/Germany Alle Rechte vorbehalten Lektorat: Erik Franz,
[email protected] Herstellung: Ulrike Hempel,
[email protected] Satz: reemers publishing services gmbh, Krefeld Druck und Verarbeitung: Bercker, Kevelaer Printed in Germany
Inhaltsverzeichnis Kapitel 1
Kapitel 2
DirectDraw
17
1.1
DirectDraw-Grundlagen 1.1.1 Der Aufbau von DirectDraw
22 22
1.1.2
Cooperative Level
25
1.1.3
Display Mode
26
1.1.4
Colorkey
29
1.1.5
Surface
30
1.1.6
Palette
38
1.1.7
Clipper
39
1.1.8
Blitting
40
1.1.9
Page Flipping
41
1.2
Blitting
42
1.3
Sprites durch Transparenz
51
1.4 1.5
Fullscreen Fullscreen und Spriteanimation
65 72
1.6 1.7
Hintergrund-Scrolling Spritekollision
75 78
1.8 1.9
Bienenjagd Methoden zum Zeichnen
88 93
Direct3D
101
2.1 2.2 2.3
3D-Koordinatensystem 3D-Primitives Zeichnen eines Dreiecks
104 105 106
2.4 2.5 2.6
Dreieck-Raster-Regeln World-, View- und Projection-Matrix Matrix-Berechnungen
118 120 122
2.6.1
Translation
122
2.6.2
Rotation
123
2.6.3
Scaling
130
6
Inhaltsverzeichnis
2.7 2.8
2.9
2.10
2.11 2.12 2.13
Kapitel 3
Polygone Licht
132 137
2.8.1
Indirektes Licht (Ambientlight)
139
2.8.2
Direktes Licht
139
2.8.3
Licht, Schatten und Polygone
146
2.8.4
Licht aktivieren / deaktivieren
148
2.8.5
Beispiel (Licht)
151
2.9.1
Setzen von Material
159
2.9.2
Beispiel (Material)
161
Material
157
Texturen
165
2.10.1 Beispiel (Textur 1)
166
2.10.2 Textur-Koordinaten
170
2.10.3 Texture Filtering
184
2.10.4 Texture Blending
201
Z-Buffer (Tiefenspeicher) Die SetRenderState()-Methode
212 218
Effekte
225
2.13.1 Nebel
225
2.13.2 Billboarding
236
2.13.3 Feuer und Explosionen
240
2.13.4 Antialiasing
246
DirectInput
253
3.1
Objekthierarchie
254
3.2
Cooperative Level
257
3.3
Datenformat 3.3.1 Standard-Datenformat
258 259
3.3.2
259
Benutzerdefiniertes Datenformat
3.4 3.5
Beispiel: Tastatur Beispiel: Joystick
260 262
3.6 3.7 3.8
Beispiel: Maus Beispiel: DirectInput und Direct3D Bewegung im 3D-Raum
268 272 279
Inhaltsverzeichnis
Kapitel 4
7
DirectSound
283
4.1 4.2 4.3
DirectSound-Architektur Datenformat HAL und HEL
285 285 286
4.4 4.5
Systemintegration Initialisieren von DirectSound
286 287
4.6
Erstellen des DirectSound-Objektes
288
4.7 4.8 4.9
Buffer-Grundlagen Primary Soundbuffer Static und Streaming Soundbuffer
290 291 291
4.10 4.11 4.12 4.13
Erzeugen von Soundbuffern Buffer-Einstellungen Buffer Playback Controls Ein einfaches Soundbeispiel
292 294 294 296
4.14 4.15
Der PlayCursor Playbuffer-Benachrichtigungen
299 301
4.16
Direct3DSound
301
4.16.1 Grundlagen
302
4.16.2 Mono- und Stereo-Soundquellen
303
DirectSound3DBuffer
304
4.17.1 Parameter-Manipulation
305
4.17.2 Entfernungen
307
4.17.3 Auswählen von Schallquellen
308
4.17.4 Operation Mode
309
4.17.5 Position
310
4.17.6 Soundprojektion und -ausrichtung
311
4.17.7 Geschwindigkeit
314
DirectSound3DListener
315
4.18.1 Parameter-Manipulation
316
4.18.2 Verzögerungseinstellungen
317
4.18.3 Entfernungsfaktoren
317
4.18.4 Dopplerfaktoren
317
4.18.5 Auswahlmöglichkeiten
318
4.18.6 Ausrichtung
318
4.17
4.18
8
Inhaltsverzeichnis
4.19
Kapitel 5
Anhang A
4.18.7 Position
320
4.18.8 Abschwächung
320
4.18.9 Geschwindigkeit
322
4.18.10 Beispiel (Klangquellen im 3D-Raum)
323
DirectSound Capture 4.19.1 Erstellen eines Capturebuffers
328 328
4.19.2 Erläuterung zur Aufnahme
330
DirectPlay
337
5.1 5.2
DirectPlay-Basis Beispiel (Chatsystem)
341 352
5.3
Kommunikationsmodelle 5.3.1 Peer-to-Peer-Session
355 355
5.3.2
356
Client/Server-Session
5.4
Lobbies
357
5.5
Service Provider
358
5.6 5.7
Sicherheit Nachrichten 5.7.1 Nachrichten empfangen
358 359 360
5.7.2
363
Synchronisation
5.8 5.9 5.10
DirectPlay-Adresse DirectPlay-Protokoll Session
363 364 365
5.11
Spieler
369
5.12
Bienenjagd Multiplayer Demo
372
Methoden
377
A.1 A.2
Globale DirectX7-Methoden DirectDraw-Methoden
378 390
A.2.1
DirectDraw7
390
A.2.2
DirectDrawClipper
400
A.2.3
DirectDrawColorControl
402
A.2.4
DirectDrawEnum
403
A.2.5
DirectDrawEnumModes
404
Inhaltsverzeichnis
A.3
A.4
A.5
A.6
9
A.2.6
DirectDrawEnumSurfaces
405
A.2.7
DirectDrawGammaControl
406
A.2.8
DirectDrawIdentifier
406
A.2.9
DirectDrawPalette
409
A.2.10 DirectDrawSurface7
410
Direct3D-Methoden A.3.1 Direct3D7
430 430
A.3.2
Direct3DDevice7
432
A.3.3
Direct3DEnumDevices
452
A.3.4
Direct3DEnumPixelFormats
453
A.3.5
Direct3DVertexBuffer7
454
DirectSound-Methoden
457
A.4.1
DirectSound
457
A.4.2
DirectSound3DBuffer
460
A.4.3
DirectSound3DListener
466
A.4.4
DirectSoundBuffer
472
A.4.5
DirectSoundCapture
478
A.4.6
DirectSoundCaptureBuffer
479
A.4.7
DirectSoundEnum
482
DirectInput A.5.1 DirectInput
483 483
A.5.2
DirectInputDevice
484
A.5.3
DirectInputDeviceInstance
494
A.5.4
DirectInputDeviceObjectInstance
496
A.5.5
DirectInputEffect
499
A.5.6
DirectInputEnumDeviceObjects
501
A.5.7
DirectInputEnumDevices
502
A.5.8
DirectInputEnumEffects
503
DirectPlay-Methoden A.6.1 DirectPlay4-Methoden
505 505
A.6.2
DirectPlayEnumConnections
524
A.6.3
DirectPlayEnumLocalApplications
526
A.6.4
DirectPlayEnumPlayers
527
10
Anhang B
Anhang C
Inhaltsverzeichnis
A.6.5
DirectPlayEnumSessions
529
A.6.6
DirectPlayLobby3
530
A.6.7
DirectPlayLobbyConnection
537
A.6.8
DirectPlayMessage
540
A.6.9
DirectPlaySessionData
546
Konstanten
553
B.1 B.2 B.3
DirectDraw Enum Direct3DEnum DirectSoundEnum
554 565 583
B.4
DirectInput Enum
588
B.5
DirectPlay Enum
595
Typen C.1
C.2
601 DirectDraw-Typen C.1.1 DDBLTFX
602 602
C.1.2
DDCAPS
602
C.1.3
DDCOLORCONTROL
604
C.1.4
DDCOLORKEY
604
C.1.5
DDGAMMARAMP
604
C.1.6
DDOVERLAYFX
604
C.1.7
DDPIXELFORMAT
605
C.1.8
DDSCAPS2
605
C.1.9
DDSURFACEDESC2
606
C.1.10 PALETTEENTRY
606
C.1.11 RECT
606
Direct3D-Typen C.2.1 D3DCLIPSTATUS
607 607
C.2.2
D3DCOLORVALUE
607
C.2.3
D3DDEVICEDESC7
607
C.2.4
D3DDEVINFO_TEXTUREMANAGER
608
C.2.5
D3DDEVINFO_TEXTURING
608
C.2.6
D3DLIGHT7
609
Inhaltsverzeichnis
C.3
C.4
11
C.2.7
D3DLIGHTINGCAPS
609
C.2.8
D3DLINEPATTERN
609
C.2.9
D3DLVERTEX
609
C.2.10 D3DMATERIAL7
610
C.2.11 D3DMATRIX
610
C.2.12 D3DPRIMCAPS
610
C.2.13 D3DRECT
611
C.2.14 D3DTLVERTEX
611
C.2.15 D3DVECTOR
611
C.2.16 D3DVERTEX
611
C.2.17 D3DVERTEXBUFFERDESC
612
C.2.18 D3DVIEWPORT7
612
C.2.19 DXDRIVERINFO
612
DirectSound-Typen C.3.1 DS3DBUFFER
612 612
C.3.2
DS3DLISTENER
613
C.3.3
DSBCAPS
613
C.3.4
DSBPOSITIONNOTIFY
613
C.3.5
DSBUFFERDESC
613
C.3.6
DSCAPS
614
C.3.7
DSCBCAPS
614
C.3.8
DSCBUFFERDESC
615
C.3.9
DSCCAPS
615
C.3.10 DSCURSORS
615
C.3.11 DXDRIVERINFO
615
C.3.12 WAVEFORMATEX
615
DirectInput-Typen C.4.1 DICONDITION
616 616
C.4.2
DICONSTANTFORCE
616
C.4.3
DIDATAFORMAT
616
C.4.4
DIDEVCAPS
616
C.4.5
DIDEVICEOBJECTDATA
617
C.4.6
DIEFFECT
617
12
Inhaltsverzeichnis
C.5
Anhang D
C.4.7
DIENVELOPE
617
C.4.8
DIJOYSTATE
618
C.4.9
DIJOYSTATE2
618
C.4.10 DIKEYBOARDSTATE
619
C.4.11 DIMOUSESTATE
619
C.4.12 DIOBJECTDATAFORMAT
619
C.4.13 DIPERIODICFORCE
619
C.4.14 DIPROPLONG
619
C.4.15 DIPROPRANGE
620
C.4.16 DIRAMPFORCE
620
DirectPlay-Typen
620
C.5.1
DPAPPLICATIONDESC2
620
C.5.2
DPCAPS
620
C.5.3
DPCREDENTIALS
621
C.5.4
DPSECURITYDESC
621
Glossar
623
D.1 D.2
Alpha Blending Antialiasing
624 624
D.3 D.4 D.5
Bilineares Filtering Bump Mapping Clipping
624 624 624
D.6 D.7
Color Key Direct3D
625 625
D.8 D.9
DirectX Dithering
625 625
D.10 D.11 D.12
Double Buffer Fenster / Full-Screen Flat Shading / Gouraud Shading
625 626 626
D.13 D.14 D.15
Fogging Hidden Surface Removal Mipmapping
626 626 626
D.16 D.17
Overlay Planes Perspektivenkorrektur
627 627
Inhaltsverzeichnis
Anhang E
13
D.18 D.19
Polygon Rendern
627 627
D.20 D.21 D.22
Shading Specular Highlights Texel
627 627 627
D.23 D.24 D.25
Texture Mapping Textur Trilineares Filtering
628 628 628
D.26
Wireframe
628
D.27 D.28
WRAM Z-Buffer
628 628
Das finden Sie auf der CD
629
E.1
DirectX-API
630
E.2
Magellan 3D
630
E.3
Beispielprogramme E.3.1 DirectDraw
630 630
E.3.2
Direct3D
631
E.3.3
DirectSound
632
E.3.4
DirectInput
633
E.3.5
DirectPlay
634
Stichwortverzeichnis
635
Vorwort Die Programmiersprache Visual Basic ist für Büroanwendungen wie Datenbankanwendungen oder Verwaltungsprogramme entwickelt worden. Die Anhänger dieser Sprache suchen vergeblich nach leistungsstarken Multimediakomponenten. Diese werden aber von einer modernen Anwendung erwartet. So ist es kein Wunder, dass gerade grafisch anspruchsvolle Anwendungen in Hochsprachen wie C++ erstellt werden. Dieser Missstand wurde mit der Einführung von DirectX für Visual Basic im September 1999 aufgelöst. Mit dieser Schnittstelle dringt der VB-Programmierer in die letzte Nische der klassischen Hochsprachen vor. Obwohl Visual Basic nach wie vor eine Interpretersprache ist, sind die Anwendungsgrenzen nicht mehr so deutlich abgesteckt, wie sie es vor DirectX waren. Ihnen als Programmierer wird nicht oft die Chance geboten, von Anfang an in eine Technologie einzusteigen. DirectX ist natürlich nicht neu, dem VB-Programmierer steht sie jedoch erstmalig zur Verfügung. Die Einbindung der DirectX-API läutet den Beginn einer aufregenden Zeit ein. Der Traum von aufwendigen Mulimedia-Anwendungen ist nun Realität geworden. Obwohl wir versierte C++ Programmierer sind, hat sich das Traumpaar Visual Basic und DirectX einen sicheren Weg in unser Herz erobert. Das liegt zum einen an der zeitsparenden Entwicklung im VB-Umfeld und zum anderen an der robusten und schnellen DirectX Implementierung. Alle Komponenten von DirectX sind ausgezeichnet umgesetzt worden. DirectDraw sorgt für eine schnelle und trickreiche Umsetzung von 2D-Grafiken. Die Anforderungen an 3D-Grafiken werden von Direct3D außerordentlich gut übernommen. Die dreidimensionale Darstellung ist in einer modernen Multimediaanwendung zu einem Pflichtteil geworden. Dies gilt insbesondere für Spiele; dehnt sich aber auf die unterschiedlichsten Anwendungen immer weiter aus. DirectSound sorgt für den guten Ton. Auch dieses Feature beschränkt sich nicht auf eine zweidimensionale Akustik. Sie können Soundquellen frei im Raum platzieren, die je nach Standort und Hörrichtung des Zuhörers unterschiedlich einwirken. Mit DirectInput bekommen Sie Tastatur, Maus oder Joystick fest in den Griff. Hier wurde wirklich eine leicht einsetzbare COM-Schnittstelle geschaffen, die dennoch allen Anforderungen stand hält. Was wäre das tollste Spiel, wenn man es alleine spielen muss. DirectPlay schafft die richtige Verbindung zu anderen Computern. Ob über das Internet oder per Netzwerk, DirectPlay stellt hierzu die richtigen Methoden bereit.
16
Systemvoraussetzungen
Systemvoraussetzungen Die Frage, welche Systemanforderungen für eine DirectX-Anwendung benötigt werden, ist nicht eindeutig zu beantworten. Was die Hardware leisten muss, hängt im Wesentlichen von der Komplexität der Anwendung ab. Die besten Leistungswerte werden Sie durch eine direkte Unterstützung der Hardware erhalten. Sie können zwar die meisten DirectX-Techniken durch eine robuste Softwareemulation betreiben, dies wird jedoch durch starke Leistungseinbußen quittiert. Als hervorragend geeignet haben wir die AMD Athlon CPU kennengelernt. Unserer Ansicht nach hat AMD mit diesem Prozessor einen Volltreffer gelandet. Sein Leistungsniveau konnte uns immer wieder ins Staunen versetzen. Diese CPU bildet eine Referenz, an der sich alle anderen Hersteller messen müssen. Außer dem wirklich sehr gut gelungenem Produkt bietet AMD auch einen hervorragenden Support. Wir fanden für Fragen immer ein offenes Ohr und die Antworten kamen schnell und kompetent. Bei den Grafikkarten lernten wir die Produkte von ATI schätzen. Die Produkte stehen vielleicht nicht immer an der Spitze der Leistungskurve, dennoch haben sie sich als schnell und robust herausgestellt. So fanden wir Unterstützung für Features von DirectX, die man bei anderen Herstellern nicht findet. Auch die Qualität der Umsetzung ist außerordentlich gut gelungen. Abschließend können wir Ihnen nur noch den Hinweis geben, dass Sie nach Möglichkeit nur solche Hardware einsetzen sollten, die eine hundertprozentige DirectX-Unterstützung bietet. Dies gilt insbesondere für die verwendete Grafikkarte. Sie und die CPU bilden den Rahmen, der die Leistungsfähigkeit Ihres Systems bildet.
Kapitel 1 DirectDraw 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9
DirectDraw-Grundlagen Blitting Sprites durch Transparenz Fullscreen Fullscreen und Spriteanimation Hintergrund-Scrolling Spritekollision Bienenjagd Methoden zum Zeichnen
22 42 51 65 72 75 78 88 93
18
Visual Basic und Grafik? Ist es möglich, mit Visual Basic schnelle Grafikoperationen durchzuführen? Diese Fragen wird sich jeder Visual Basic-Programmierer früher oder später stellen. Trotz der Beschränkungen durch die Visual Basic-Standardkomponenten ist es machbar. Das Windows-Grafiksubsystem GDI ist bestens dazu geeignet, Textverarbeitungen oder Tabellenkalkulationen zu unterstützen, verfügt jedoch nicht über eine schnelle Grafikumgebung. Anfänglich sollte dieses Defizit von Subsystemen wie WinG korrigiert werden. Dies führte aber nicht zu den gewünschten Ergebnissen. Die Wende kam mit Windows 95. Es folgten DirectX und schließlich DirectDraw, das Standbein von DirectX, das den Zugriff auf schnelle 2D-Grafikaktionen ermöglicht. Durch DirectDraw (DD) erhalten Sie den direkten Zugriff auf den Grafikchipsatz sowie den Videospeicher der Grafikkarte. Die meisten Aktionen von DirectDraw werden für den Anwender unsichtbar im Speicher des Computers ausgeführt. Im Idealfall werden die Grafikaktionen im Videospeicher der Grafikkarte bearbeitet. Dass die Grafikinformationen im Videospeicher liegen, ist enorm wichtig, denn dann kann eine moderne Grafikkarte ohne Unterstützung der CPU anstehende Arbeiten selbstständig berechnen. So arbeiten zwei CPUs gleichzeitig. Durch diese Arbeitsweise wird die Grafikanzeige enorm beschleunigt. »Das Kopieren von Daten aus einem Speicherbereich in einen anderen.« – Das ist die Hauptaufgabe von DirectDraw. Diese Definition trifft den Kern, auch wenn die komplexen Möglichkeiten von DirectDraw nicht angesprochen werden. Das DirectDraw-Gebilde ist immer gleich aufgebaut. D.h. eine DirectDraw-Anwendung ist immer nach einem festen Schema strukturiert. Zu diesem Zweck werden verschiedene Oberflächen (Surfaces) eingerichtet. Es wird unterschieden zwischen sichtbaren und unsichtbaren Surfaces. Die sichtbare Surface ist die so genannte primäre Surface, alle anderen sind Backbuffer bzw. Offscreensurfaces. Nachdem wir festgestellt haben, dass sich DD hauptsächlich auf Kopierarbeiten spezialisiert hat, können wir eine relativ feste Struktur erkennen. Sie ist folgendermaßen aufgebaut: Alles fängt damit an, dass ein DD-Objekt erzeugt wird. Dies geschieht mit der DirectDrawCreate()-Methode. Anschließend werden mit der CreateSurface()-Methode die verschiedenen Surfaces erstellt. Von den Offscreensurfaces wird auf der Backbuffersurface eine Grafik zusammengestellt. Hier nutzt man die Blt()- oder BltFast()-Methoden. Die neu erstellte Grafik ist für den Anwender noch unsichtbar. Um sie sichtbar zu machen, muss die Grafik auf die primäre Surface. Sie haben dazu drei Möglichkeiten: die Blt()- bzw. BltFast()-Methode und die Flip()-Methode. Welche Technik Sie einsetzen, ist von der Konstruktion Ihrer DD-Anwendung abhängig und wird später genau erläutert.
Kapitel 1 • DirectDraw
19
DirectDrawCreate() CreateSurface()
primäre Surface
Backbuffer Surface Flip() Blt() BltFast()
Offscreen Surface
5
Bild 1.1:
Blt() BltFast()
4
3
2
1
Aufbau einer DirectDraw-Anwendung
An der Abbildung erkennen Sie den grundsätzlichen Aufbau einer DD-Anwendung. Sie nutzen eine oder mehrere unsichtbare Surfaces, um eine Grafik zu erstellen. Dies geschieht komplett im Speicher des Computers. Die Technik, eine Backbuffersurface einzusetzen, wird DoubleBuffer genannt und sichert Ihnen eine flimmerfreie Anzeige. Zusätzlich ist der Aufbau der Grafik vor den Augen des Anwenders geschützt. Der dritte Vorteil ist eine Geschwindigkeitssteigerung. In wenigen Anwendungen kommt das TripleBuffer-Verfahren zum Einsatz. Hierbei wird eine zweite Backbuffersurface erstellt. Während der Inhalt des ersten Backbuffers auf die primäre Surface kopiert wird, wird auf dem zweiten Backbuffer die neue Grafik erstellt. Die zugeordneten Backbuffer werden der Reihe nach auf die primäre Surface geflippt. Dieses Verfahren macht aber nur Sinn, wenn das verwendete Computersystem noch ungenutzte Rechenreserven besitzt. Wie bereits erwähnt, kommt diese Technik nur selten zum Einsatz und ist im Regelfall nicht nötig.
20
Blt(), BltFast() kontra Flip()! Die Flip()-Methode ist schneller als die Blt()- oder BltFast()-Methode. Nachteil: Sie kann nur eingesetzt werden, um den Inhalt einer Backbuffersurface auf die primäre Surface zu kopieren. Nutzt man die Flip()Methode, wird im Vorfeld eine Komplexe Surface erstellt, die fest mit einem oder zwei Backbuffer verbunden ist (Double- oder TripleBuffer). Das Flippen der primären Surface kann mit dem Umdrehen eines Blatt Papiers verglichen werden. Die Seite, die zuvor sichtbar war, wird nach dem Umdrehen zur Unterseite. Moderne Grafikkarten bieten einen weiteren Anreiz, die Flip()-Methode zu nutzen. Diese Karten müssen den Surfaceinhalt nicht mehr hin und her kopieren. Der RAMDAC dieser Karten macht es möglich, den Zeiger auf den Speicherbereich zur Bildschirmausgabe neu zu setzen. Die Kopiergeschwindigkeit ist in erster Linie von der verfügbaren Hardware abhängig. Grafikkartenspeicher, Grafikchipsatz, Systemspeicher, CPU ... sind Faktoren, welche einen unmittelbaren Einfluss auf die Performance haben. Sie als Programmierer können die Hardware des Anwenders nicht ändern. Dennoch sind Sie an der Performance einer Anwendung nicht unbeteiligt. Klassifizieren wir doch einfach mal die DirectDraw-Geschwindigkeiten. So werden wir drei Beschleunigungsstufen unterscheiden. 1. Performancestufe ist das Arbeiten mit Videospeicher und Systemspeicher. 2. Performancestufe ist das Arbeiten im Videospeicher. Die beste Performancestufe ist die dritte, die Sie durch den Einsatz der Flip()-Methode erreichen. Unabhängig von der eingesetzten Hardware können folgende Optimierungsregeln deklariert werden. •
Surfaces sollten im Videospeicher erstellt werden. Falls der vorhandene Videospeicher nicht ausreicht, um den Backbuffer sowie Offscreensurfaces aufzunehmen, müssen diese Surfaces im Systemspeicher abgelegt werde. Damit ist der Datentransfer aller Surfaces auf normale Kopierbefehle der CPU angewiesen. Diese Befehle sind zum einen sehr langsam und zum anderen wird die CPU für andere Aufgaben blockiert. Sollte die Grafikkarte genügend Speicher besitzen, um auch den Backbuffer aufzunehmen, werden die Kopierarbeiten vom Grafikchipsatz der Grafikkarte übernommen. Die CPU muss in den Datentransfer nicht eingreifen und steht für weitere Aufgaben zur Verfügung.
•
Nutzen Sie die Flip()-Methode Die Flip()-Methode ist wesentlich effizienter als die Blt()- bzw. BltFast()-Methoden. Dies hängt natürlich mit der engen Bindung von der Backbuffersurface mit der primären Surface zusammen. Moderne Grafikkarten können über die Flip()-Methode den sichtbaren Grafikkartenspeicher durch einfaches Umprogrammieren des Grafikchipsatzes ändern. Es ist nicht mehr notwendig Daten zu kopieren. Lediglich der Zeiger auf den Anfang der primären Surface wird verschoben.
Kapitel 1 • DirectDraw
•
21
Sparen Sie Videospeicher DirectDraw wird hauptsächlich zur Darstellung von Animationen eingesetzt. Diese Animationen setzten sich aus vielen kleinen Grafiken zusammen, welche nacheinander sichtbar gemacht werden. Dies können Sie am besten mit einem Daumenkino vergleichen. Die gesamte Szene wird aus Offscreensurfaces zusammengebaut. Legen Sie die wichtigsten Offscreensurfaces zuerst an. DirectDraw wird so lange den Videospeicher verwenden, bis dieser aufgebraucht ist. Nutzen Sie viele kleine Surfaces. So können Sie sicherstellen, das möglichst viel vom kostbaren Videospeicher verwendet wird. DirectDraw legt entweder eine Surface komplett in den Videospeicher oder gar nicht.
Wie geht es weiter? Sie werden anhand von einfachen Beispielen an die verschiedenen Facetten von DirectDraw herangeführt. Wir fangen an mit dem Blitten einer Grafik aus einer Offscreensurface auf die primäre Surface. Hierzu werden wir erklären, was notwendig ist, um DirectDraw-Objekte zu erstellen, wie die DirectX-Schnittstelle eingebunden wird und welche Bedeutung RECT-Strukturen haben. Im Verlauf des Kapitels werden wir uns über eine fensterbasierende Anwendung bis zur FullScreen-Darstellung inklusive Spriteanimation und Hintergrundscrolling vorarbeiten. •
Blitting Demonstriert den Blitvorgang einer Hintergrundgrafik auf die sichtbare primäre Surface.
•
Sprites durch Transparenz In diesem Themenbereich werden wir auf einer Offscreensurface eine Grafik mit Hilfe weiterer Offscreensurfaces zusammenstellen. Wir nutzen den Colorkey (Farbschlüssel) um Farben transparent erscheinen zu lassen. Hierdurch erwecken wir die Illusion von nicht rechteckigen Sprites.
•
Full Screen Mode Um unsere Performance zu steigern, verlassen wir die fensterbasierende Anwendung und wechseln auf den Full Screen Mode. Die Flip()-Methode kommt zum Einsatz.
•
Background Scrolling Full Screen Mode, Spriteanimation, Flip()-Methode und Hintergrundanimation.
•
Sprite-Kollision Eine Kollision von Sprite-Objekten zu erkennen ist nicht ganz einfach. Wir werden zwei Möglichkeiten demonstrieren. Ganz nebenbei erfahren Sie auch einiges über Palettenhandling sowie direkte Speichermanipulation.
22
DirectDraw-Grundlagen
•
Bienenjagd Bienenjagd ist ein kleines Spielprogramm, welches komplett mit DirectDrawTechniken umgesetzt wurde.
Bevor wir jedoch zur praktischen Arbeit kommen, stellen wir etwas Theorie voran. Das Kapitel DirectDraw-Grundlagen erklärt die Bestandteile der DirectDraw-Anwendung.
1.1
DirectDraw-Grundlagen
1.1.1
Der Aufbau von DirectDraw In diesem Abschnitt möchten wir Ihnen den Zusammenhang zwischen Direct Draw und den restlichen DirectX-Komponenten darlegen.
Anwendung Grafik Device Interface (GDI)
Display Device Interface(DDI) DirectDraw
Hardware Emulation Layer HEL
Hardware Abstraction Layer Grafikkarte Bild 1.2:
Einbindung von DirectDraw in der DirectX-Umgebung
Kapitel 1 • DirectDraw
23
DirectDraw stellt über den HAL (Hardware Abstraction Layer) einen direkten Zugriff auf die Grafikkarte zur Verfügung. Sollte dies nicht möglich sein, wird der HEL (Hardware Emulation Layer) verwendet. Hierbei kommt es zu einer erweiterten Kommunikation mit dem GDI (Graphic Device Interface), sowie dem DDI (Device Display Interface). Der HEL emuliert das von DirectDraw angeforderte Leistungsmerkmal. Dennoch besitzt der HEL einen direkten Zugriff auf die Grafikkarte. Die GDI besitzt keinen direkten Zugriff auf die Hardware der Grafikkarte. Objekttypen DirectX organisiert alle Methoden und Techniken in Objektklassen. Möchten Sie z.B. eine Surface manipulieren, so bearbeiten Sie das zugehörige DirectDraw Surface7-Objekt. Möchten Sie die Palette einer Anwendung ändern, so werden Sie das DirectDrawPalette-Objekt bearbeiten. •
DirectDraw-Objekt Das DirectDraw-Objekt ist der zentrale Knotenpunkt aller DD-Anwendungen. Es ist das erste Objekt, welches erzeugt wird. Mit dem DirectDraw-Objekt wird die Verbindung zu DirectX7 geschaffen. Mit der DirextX7.DirectDraw Create()-Methode wird ein DirectDraw-Objekt erstellt.
•
DirectDrawSurface-Objekt Das DirectDrawSurface-Objekt repräsentiert einen Speicherbereich, welcher das aktuelle Monitorbild darstellt. Außerdem wird dieser Bereich zum Kopieren von Bildern verwendet. Mit den DirectDraw7.CreateSurface(), Direct Draw7.CreateSurfaceFromFile(), DirectDraw7.DuplicateSurface() oder Direct-Draw7.CreateSurfaceFromResource-Methoden wird das DirectDraw Surface-Objekt erstellt. Das DirectDrawSurface-Objekt wird im Allgemeinen als Surface bezeichnet.
•
DirectDrawPalette-Objekt Das DirectDrawPalette-Objekt (kurz Palette) repräsentiert einen 16- oder 256Farben-Index. Dieser Index wird von einer Surface benutzt. Er beinhaltet eine Liste von RGB-Drillingen, welche die Farbanteile einer Farbe definieren. Sie können keine Paletten nutzen, wenn eine Surface mit einer Farbtiefe größer 8 Bit arbeitet. Mit der DirectDraw7.CreatePalette()-Methode erstellen Sie eine Palette.
•
DirectDrawClipper-Objekt Das DirectDrawClipper-Objekt hilft Ihnen zu verhindern, dass Grafikdaten in Bereiche außerhalb einer gültigen Surface kopiert werden. Das Clipper-Objekt wird mit der DirectDraw7.CreateClipper-Methode erzeugt.
24
DirectDraw-Grundlagen
Aufbau der DirectDraw7-Objekte: DirectX7
DirectDraw Objekte
DirectDrawSurface Objekt
DirectDrawSurface Objekt
DirectDrawSurface Objekt Bild 1.3:
DirectDraw-Objekte
Hardware Abstraktion Layer Der Hardware Abstraktion Layer (HAL) unterstützt alle spezifischen Eigenschaften einer Grafikkarte. Diese Eigenschaften werden durch eine grafikkartenspezifische Schnittstelle beschrieben. Diese Grafikkarten-Treiber werden im Regelfall vom Hersteller zur Verfügung gestellt und in das Windows Device Management Concept eingebunden. Dieser Treiber wird entweder als 16- oder 32-Bit-Code bereit gestellt. Unter Windows NT / Windows 2000 ist dies immer ein 32-BitCode. In einigen Fällen gehört der HAL nicht zu dem Grafikkarten-Treiber, sondern wird durch eine separate DLL eingebunden. Der HAL unterstützt nur Eigenschaften speziell für die Grafikkarte, für die er entwickelt wurde. Sollte der HAL Techniken von DirectDraw nicht unterstützen, so werden diese auch nicht emuliert. Dies macht sich bei älteren Systemen beim Einsatz von erweiterten Techniken wie OverlaySurfaces oder BLTFX bemerkbar. Hardware Emulation Layer Wenn der Hardware Abstraktion Layer der Grafikkarte ein Merkmal von Direct Draw nicht unterstützt, kann DirectDraw versuchen dieses Merkmal zu emulieren. Diese Emulation wird durch den Hardware Emulation Layer (HEL) beschrieben. Der HEL präsentiert die Leistungsfähigkeit von DirectDraw, so wie es der HAL tun würde. Bei dem HEL handelt es sich um eine Softwarelösung. Diese Emulationssoftware ist wesentlich langsamer als die direkte Hardwareunterstützung des HALs. Andererseits gibt es keine Grafikkarten, welche alle Leis-
Kapitel 1 • DirectDraw
25
tungsmerkmale von DirectDraw unterstützen. Somit ist der Einsatz der HEL durchaus legitim. Beachtet man, dass die Computersysteme immer schneller werden, können wir damit rechnen, das viele Leistungsmerkmale durch den HEL umgesetzt werden.
1.1.2
Cooperative Level Der Cooperative Level beschreibt, wie DirectDraw mit dem Display interagiert. Ebenfalls wird beschrieben, wie sich Ereignisse auf das Display auswirken. Um den Cooperative-Level zu setzen, benutzen Sie die DirectDraw7.SetCooperative Level-Methode. Im Regelfall wird der Cooperative Level eingesetzt, um Direct Draw als Full Screen oder als Fensteranwendung zu starten. Full Screen beinhaltet, dass DirectDraw einen exklusiven Zugriff auf die Grafikkarte erhält. Folgende Einstellungen sind möglich: •
DirectDraw erlauben, Mode X-Auflösungen zu verwenden (s. Mode X).
•
(CTRL) + (ALT) + (DEL) erlauben oder verhindern.
•
Fenster verkleinern oder vergrößern, zulassen oder verhindern (minimize oder maximize).
Der normale Cooperative Level beschreibt eine fensterbasierende Anwendung. Es können keine Änderungen an der Farbpalette oder Auflösung vorgenommen werden. Ebenfalls ist Pageflipping nicht möglich. Der Full-Screen Modus lässt die beste Nutzung der Hardware zu. Hierbei werden die besten Performancewerte erreicht. Ebenfalls ist der Einfluss auf das Display gewachsen. Softwareentwickler nutzen Ereignisse wie WM_ACTIVATEAPP oder WM_DIS PLAYCHANGE um die verwendeten Oberflächen der Anwendung zu aktualisieren. In einigen Fällen kommt es vor, dass die Aktualisierungen vorgenommen werden, obwohl dies nicht notwendig ist. Ebenso unterbleibt eine dringend notwendige Aktualisierung. Mit der DirectDraw7.TestCooperativeLevel()-Methode können Sie den aktuellen Status des Cooperative Levels ermitteln. Sie sind somit in der Lage, individuell auf den Status zu reagieren. Die Methode liefert ein DD_OK (Wert 0) zurück, wenn alles in Ordnung ist. Fehler werden nach der Art des verwendeten Cooperative Levels der Anwendung unterschieden. •
Full-Screen-Anwendung Sie erhalten die Fehlermeldung DDER_NOEXCLUSIVEMODE, falls Ihre Anwendung den exklusiven Zugriff auf die Grafikkarte verloren hat. Dies tritt z.B. ein, wenn der Anwender (ALT) + (ÿ_) drückt. In diesem Fall sollten Sie TestCooperativeLevel() so lange in einer Schleife laufen lassen, bis Sie den exklusiven Status wieder erhalten. Alternativ können auch Funktionen wie Wait Message() oder Sleep() eingesetzt werden.
26
DirectDraw-Grundlagen
•
1.1.3
Fensteranwendung Bei einer Fenster-Anwendung können zwei Fehlermeldungen auftreten. DD ERR_ECXLUSIVEMODEALREADYSET und DDERR_WRONGMODE. Im ersten Fall wurde von DirectDraw bereits ein Exklusiv-Mode vergeben. Somit kann keine weitere DirectDraw-Anwendung auf die Grafikkarte zugreifen. Ohne direkten Grafikkartenzugriff ist auch keine DirectDraw-Anwendung möglich. Im zweiten Fall wurde der Display Mode geändert. Hierdurch sind die DirectDrawSurface-Objekte zerstört worden und müssen neu erstellt oder restauriert werden.
Display Mode Der Display Mode beschreibt die Dimensionen und die Farbtiefe der Hardwareeinstellung, diese werden von der primären Surface an den Monitor gesendet. Ein gebräuchlicher Display Mode ist 640 X 480 X 8. Dieser beschreibt eine Monitordarstellung mit 640 Pixel Breite, 480 Pixel Höhe und 8 Bit Farbtiefe. (Dieser Mode ist ein zu DirectDraw konformer Modus. Es lässt sich ohne Probleme ein DirectDrawPalette-Objekt erzeugen. Bei Einstellungen mit einer größeren Farbtiefe muss man etwas mehr Arbeit investieren.) Je größer der Display Mode wird desto mehr Videospeicher wird verwendet. Gleiches gilt wenn die Farbtiefe erhöht wird. Sie sollten die Kapazitäten Ihrer Grafikkarte kennen, bevor Sie den Display Mode für Ihre Anwendung wählen. Aufbauend auf dem Display Mode werden im Regelfall die Oberflächen (Surfaces) erstellt. Diese sollten aus Performancegründen im Videospeicher liegen. Die unterschiedlichen Grafikkarten unterstützen unterschiedliche Display Modes. Welche Modes unterstützt werden, hängt von dem verfügbaren Speicher der Grafikkarte ab. Mit der DirectDraw7.GetDisplayModesEnum()-Methode können Sie die zur Verfügung stehenden Modes ermitteln. Siehe Listing: Dim m_dx As New DirectX7 Private Sub Combo1_Click() List1.Clear Dim ddEnum As DirectDrawEnum Dim strGuid As String Set ddEnum = m_dx.GetDDEnum() i = Combo1.ItemData(Combo1.ListIndex) List1.AddItem " Index " + Str(i) List1.AddItem " Name " + ddEnum.GetDescription(i) List1.AddItem " GUID " + ddEnum.GetGuid(i) List1.AddItem "" strGuid = ddEnum.GetGuid(i) GetDisplayModes strGuid End Sub Private Sub Form_Load()
Kapitel 1 • DirectDraw
27
Me.Show GetDisplayCards Combo1.ListIndex = 0 End Sub Sub GetDisplayModes(sGuid As String) Dim DisplayModesEnum As DirectDrawEnumModes Dim ddsd2 As DDSURFACEDESC2 Dim dd As DirectDraw7 Set dd = m_dx.DirectDrawCreate(sGuid) dd.SetCooperativeLevel Me.hWnd, DDSCL_NORMAL Set DisplayModesEnum = _ dd.GetDisplayModesEnum(DDEDM_DEFAULT, ddsd2) List2.Clear For i = 1 To DisplayModesEnum.GetCount() DisplayModesEnum.GetItem i, ddsd2 List2.AddItem " Index " + Str(i) List2.AddItem " Width " + Str(ddsd2.lWidth) List2.AddItem " Height " + Str(ddsd2.lHeight) List2.AddItem " Bits Per Pixel" + _ Str(ddsd2.ddpfPixelFormat.lRGBBitCount) List2.AddItem " Refresh Rate " + _ Str(ddsd2.lRefreshRate) List2.AddItem "" Next End Sub Sub GetDisplayCards() Dim ddEnum As DirectDrawEnum Dim strGuid As String Set ddEnum = m_dx.GetDDEnum() For i = 1 To ddEnum.GetCount() Combo1.AddItem (ddEnum.GetDescription(i))Combo1.ItemData(Combo1.NewIndex) = I Next End Sub
Setzen und Restaurieren des Display Mode Sie setzen den Display Mode mit der DirectDraw7.SetDisplayMode()-Methode. Diese beinhaltet fünf Parameter: Weite, Höhe, Farbtiefe, Wiederherstellungsgeschwindigkeit (Refresh Rate) der Grafikkarte und ein Mode Flag. Das Mode Flag hat zur Zeit nur einen gültigen Wert DDSDM_STANDARDVGAMODE. Dieser wird genutzt, wenn Sie den Mode 13 (320 X 200 X 8) verwenden wollen. Alle anderen Mode X verwenden DDSDM_DEFAULT (Wert 0).
28
DirectDraw-Grundlagen
Bild 1.4:
Display Mode
Für viele Anwendungen ist es von Bedeutung zu wissen, welches Pixelformat verwendet wird. Sie können mit SetDisplayMode() die Farbtiefe Ihrer Anwendung angeben, aber Sie wissen nicht, welches Bitmuster zum Erzeugen einer Farbe von Ihre Grafikkarte verwendet wird. Um dies zu erfahren, lesen Sie die Mode-Informationen, nachdem Sie den DisplayMode gesetzt haben, aus der Grafikkarte heraus. Sie bedienen sich der DirectDraw7.GetDisplayMode()-Methode. Diese Methode füllt eine Variable vom Typ DDSURFACEDESC2. In dieser Variablen ist das Typen-Array DDPIXELFORMAT enthalten. Dieses enthält die Bitmaske zu IRBitMask, IGBitMask und IBBitMask. Abschließend beachten Sie, dass Sie beim Beenden Ihrer Anwendung den Display Mode auf den Originalzustand zurücksetzen. Dies erreichen Sie durch die Kombination von DirectDraw7.RestoreDisplayMode() und DirectDraw7.SetDis playMode(). Mit RestoreDisplayMode() werden die Einstellung wiederhergestellt, welche vor dem ersten Aufruf von SetDisplayMode() herrschten. Mit dem erneuten Aufruf von SetDisplayMode() werden die alten Einstellungen wirksam.
Kapitel 1 • DirectDraw
29
Mode X und Mode 13 DirectDraw unterstützt beide Modes: Mode 13 sowie Mode X. Mode 13 besitzt die Parameter 320 Weite X 200 Höhe X 8 Farbtiefe. Dieser Mode unterstützt kein Seitenflipping (siehe Surface). Er erhielt seinen Namen durch den hexadezimalen Bios-Eintrag: Nummer 13. Mode 13 ist ein linearer. Mode X ist ein Mischmodus. Er erlaubt die Adressierung von bis zu 256 Kilobyte des Display-Speichers (Mode 13 erlaubt nur 64 Kilobyte). Die verfügbaren Mode X sind von der verwendeten Grafikkarte abhängig. Diese können über die Direct Draw7.GetDisplayModesEnum()-Methode ermittelt werden. Wenn Sie einen Mode X verwenden wollen, müssen folgende Flags gesetzt werden: DDSCL_ ALLOWMODEX, DDSCL_FULLSCREEN und DDSCL_EXCLUSIVE. Im Mode X können Sie die Blt()-Methode sowie die Lock()-Methode nicht auf die primäre Surface anwenden. Stattdessen werden diese Techniken auf Offscreensurfaces angewandt (siehe Surface). Der Mode X wird durch das DDSCAPS_ MODEX-Flag des DDSCAPS2-Typen-Arrays angezeigt. Dieses ist Mitglied der DDSURFACEDESC2-Typen-Arrays, welche durch die DirectDraw7.GetCaps()Methode sowie der DirectDrawEnumModes()-Methode ermittelt werden.
1.1.4
Colorkey Mit dem Colorkey (Farbschlüssel) wird ein Farbbereich gekennzeichnet, welcher beim Kopieren einer Grafik nicht berücksichtigt wird. Dieser Farbbereich bleibt durchsichtig. DirectDraw unterstützt einen Source Colorkey und einen Destination Colorkey. Der Source Colorkey beschreibt einen Farbbereich der Quellgrafik. Alle Pixel, welche in das Farbschema passen, werden beim Kopieren der Grafik ignoriert. Ähnlich agiert der Destination Colorkey. Der Unterschied liegt darin, dass diesmal die Pixel, welche durch das Farbschema beschrieben werden, beim Kopieren der Grafik nicht überschrieben werden. Der Destination Colorkey wird nicht von allen Grafikkarten unterstützt. Der Colorkey ist folgendermaßen definiert: Type COLORKEY high As Long low As Long End Type
Die Parameter low und high geben den Anfang und das Ende des Farbbereichs an. Diese Werte müssen unter Berücksichtigung des Surface-Pixel-Formats benannt werden. Bei einer 8-Bit-Palette werden die Farbindexe angegeben. Eine 16-BitFarbtiefe verwendet ein Pixelformat von 5:6:5. Eine 24-Bit-Farbtiefe nutzt das Pixelformat 8:8:8. Das Pixelformat kann sich von Grafikkarte zu Grafikkarte ändern.
30
DirectDraw-Grundlagen
Mit DirectDrawSurface7.SetColorkey() wird der Colorkey für die Surface gesetzt.
1.1.5
Surface Eine Surface können Sie sich am besten als ein Blatt Papier vorstellen. Auf diesem können Sie dann mit DirectDraw etwas zeichnen. Genauer betrachtet ist eine DirectDraw-Oberfläche (Surface) ein zusammenhängender Speicherbereich. Dieser liegt idealerweise im Videospeicher der Grafikkarte. Da dieser Speicherbereich oftmals sehr begrenzt ist, kann eine Surface auch im Systemspeicher des Computers existieren. Werden beim Erzeugen einer Surface keine spezifischen Parameter gesetzt, so wird zuerst der verfügbare Videospeicher verwendet. Wenn eine Surface im Videospeicher existiert, so werden auftretende Kopierarbeiten vom Grafikkartenchipsatz übernommen. Dadurch wird die CPU des Computers weitgehend entlastet. Im Regelfall arbeiten CPU und Grafikkartenchipsatz parallel zueinander. Das macht sich natürlich bei der Performance bemerkbar. Es werden fünf Surface-Typen unterschieden. Die wichtigsten Surfaces sind die primäre Surface und die Offscreensurface. Mit diesen beiden Typen werden den meisten Aufgaben von DirectDraw bewältigt. Wir werden uns auch im Wesentlichen auf diese beiden Surfacearten berufen. Später werden wir den Einsatz von Fullscreen Anwendungen besprechen. Diese nutzen eine so genannte komplexe Surface. Hierbei handelt es sich um eine Kombination von primärer Surface mit einer fest verbundenen Offscreensurface, welche dann als Backbuffer bezeichnet wird. Den Einsatz von Surfaces können Sie am besten anhand unserer Beispielanwendungen erkennen, dennoch sollten Sie sich die Informationen zu den Surfaces durchlesen. Betrachten Sie die Vorstellung der verschiedenen Surface-Typen als hilfreiche Informationen, auf die Sie später zurückgreifen können. •
Primäre Surface Eine primäre Surface ist die aktuell auf dem Monitor sichtbare Surface. Sie wird durch das DDSCAPS_PRIMARYSURFACE-Flag identifiziert. Ein DirectDraw-Objekt kann nur eine primäre Surface besitzen.
Siehe Listing: Dim ddsd2 As DDSURFACEDESC2 ddsd2.lFlags = DDSD_CAPS ddsd2.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE
•
Offscreensurface Eine Offscreensurface ist für den Anwender nicht sichtbar. Sie wird durch das DDSCAPS_OFFSCREENPLAIN-Flag identifiziert. Es können beliebig viele Offscreensurfaces erstellt werden. Der Hauptverwendungszweck ist es, Grafikdaten zu speichern. Oftmals wird eine Offscreensurface als Backbuffer bezeichnet. Auf dieser Backbuffersurface werden alle Grafikoperationen ausgeführt, bevor sie auf die primäre Surface kopiert werden. Einer Offscreensur-
Kapitel 1 • DirectDraw
31
face muss man Ihre Dimensionen mitteilen. Hierzu werden die Flags DDSCAPS_WIDTH und DDSCAPS_HEIGHT gesetzt. Anschließend erhält man auf die Mitgliedsdaten lWidth und lHeight Zugriff. Die Dimensionen einer Surface werden in Pixeln angegeben. Siehe Listing: Dim ddsd2 As DDSURFACEDESC2 ddsd2.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
Alternativ kann die Surface auch im Systemspeicher erstellt werden. Lediglich das DDSCAPS_SYSTEMMEMORY-Flag müsste hinzugefügt werden. Dies würde so aussehen: ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Or DDSCAPS_SYSTEMMEMORY
In dem Sie die Parameter lHeight und lWidth setzten, legen Sie die Höhe und Weite der Offscreensurface fest. ddsd2.lHeight = 200 ddsd2.lWidth = 250
Wie bereits erwähnt, ist der Videospeicher begrenzt. Um Videospeicher zu sparen und die Performance zu steigern, kann eine Offscreensurface eine von der primären Surface unabhängige Farbtiefe erhalten. Sie erweitern die Surface-Beschreibungen, indem Sie das Pixelformat genauer benennen. Als Beispiel zeigen wir eine 8-Bit-Farbtiefe: ddsd2.ddpfPixelFormat.lRGBBitCount = 8
Die Dimensionen einer Offscreensurface können die Dimensionen der primären Surface nicht überschreiten. Zu diesem Zweck würde eine Wide Surface erstellt. Nicht alle Grafikkarten sind in der Lage Wide Surfaces zu erstellen. Ebenfalls sollte der Speicher der Grafikkarte genau im Auge behalten werden. Eine Wide Surface kann schnell die Grenzen der Grafikkarte sprengen. •
Complex Surface Eine komplexe Surface ist eine primäre Surface, welche mit einer (oder mehreren) Offscreensurface (Backbuffersurface) fest verbunden ist. Eine komplexe Surface wird durch das DDSCAPS_COMPLEX-Flag identifiziert. Wird es notwendig die Surface zu restaurieren, reicht ein Aufruf von DirecDrawSurface7.Restore() und alle mit der primären Surface verbundenen Backbuffer werden ebenfalls restauriert. Eine komplexe Surface erlaubt das Page-Flipping.
Wird eine Backbuffersurface verwendet, so spricht man vom Doublebuffer. Verwendet man zwei Backbuffer, so wird diese Technik als Triplebuffer bezeichnet.
32
DirectDraw-Grundlagen
Dies lässt sich beliebig fortsetzen. Angemerkt sei, dass im Regelfall alles, was den Doublebuffer übersteigt, selten sinnvoll ist. Sinnvoll wird dies erst dann, wenn Ihre Anwendung eine neue Grafik schneller berechnen kann, als sie von der Grafikkarte dargestellt wird. Mehrere Backbuffer werden durch eine Flipping Chain (Seiten-Umschlage-Kette) verbunden. Da wir uns hauptsächlich mit dem Doublebuffer-Verfahren beschäftigen, werden wir auf die Flipping Chain nur begrenzt eingehen. Folgende Abbildung verdeutlicht die Flipping Chain. Primäre Surface
1
5
3 Backbuffer 1
Backbuffer 2 2
Backbuffer 3 4
6
N Bild 1.5:
Schritt 1 bis 6
Flipping Chain
Um den Inhalt der Backbuffer auf der primären Surface sichtbar zu machen, werden die Backbuffer der Reihe nach durchgeschaltet. Am Ende angelangt, geht alles wieder von vorne los. Betrachten Sie das Listing für eine Komplexe Surface mit einem Backbuffer. Dim ddsd2 As DDSURFACEDESC2 ddsd2.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT ddsd2.ddsCaps.lCaps = DDSCAPS_COMPLEX Or DDSCAPS_FLIP Or _ DDSCAPS_PRIMARYSURFACE ddsd2.lBackbufferCount = 1
•
Wide Surface Mit DirectDraw sind Sie in der Lage eine Offscreensurface zu erstellen, welche die Dimensionen der primären Surface überschreitet. Idealerweise wird auch die Wide Surface im Videospeicher erzeugt. Dies ist aber nur dann möglich, wenn die angesprochene Grafikkarte dies unterstützt. Leider ist dies nicht immer der Fall. Sie können mit der DirectDraw7.GetCaps()-Methode prüfen, ob diese Eigenschaft unterstützt wird. Den entsprechenden Eintrag finden Sie in dem DDCAPS-Typen-Array unter lCaps2.
Kapitel 1 • DirectDraw
33
Wide Surfaces können jederzeit im Systemspeicher erstellt werden. Hierzu werden die normalen Parameter einer Offscreensurface eingesetzt. Ein bevorzugtes Einsatzgebiet für eine Wide Surface ist das Hintergrundscrolling. Eine entsprechende Beispielanwendung finden Sie in einem späteren Kapitel. •
Client Memory Surface Eine Client Memory Surface ist eine normale DirectDraw-Surface, welche im Systemspeicher erstellt wird. Sie wird verwendet um Grafikdaten zu speichern, die nicht permanent zum Einsatz kommen. Diese Surface ist immer dann sinnvoll, wenn Ihre Anwendung den Videospeicher für wichtigere Surfaces belegt. Durch Angabe des Pixelformats wird ein fester Speicherbereich reserviert. Auf diesen Speicherbereich kann der Programmierer gezielt zugreifen. Nach Beenden der Anwendung wird der Speicherbereich der Client Memory Surface nicht automatisch freigegeben. Siehe Listing: Dim ddsd2 As DDSURFACEDESC2 Dim dds As DirectDrawSurface7 With ddsd2 .lFlags = DDSD_WIDTH Or DDSD_HEIGHT Or DDSD_PITCH Or _ DDSD_PIXELFORMAT Or DDSD_CAPS .ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Or _ DDSCAPS_SYSTEMMEMORY .lWidth = 100 .lHeight = 100 .lPitch = 3*100 With .ddpfPixelFormat .lFlags = DDPF_RGB .lRGBBitCount = 3 * 8 .lRBitMask = &HFF0000 .lGBitMask = &HFF00& .lBBitMask = &HFF& End With End With
Width contra Pitch • Width Die Entfernung zwischen zwei Adressen im Speicher, welche den Anfang und das Ende einer Grafiklinie angibt. Zusätzlicher Speicher zum Erreichen der folgenden Linie wird nicht berücksichtigt. •
Pitch Die Entfernung (in Byte) zwischen zwei Adressen im Speicher, welche den Anfang einer Grafiklinie und den Anfang der folgenden Grafiklinie beschreibt. Benötigter Zusatzspeicher wird berücksichtigt.
34
DirectDraw-Grundlagen
DirectDraw verwendet das DDSURFACEDESC2-Typen-Array, um Informationen einer Surface zu speichern. Unter anderem werden Informationen zu den Dimensionen der Surface erfasst. Die Mitgliedsdaten lHeight und lWidth erfassen die logische Größe der Surface in Pixel. Bei diesen Angaben wird die Farbtiefe einer Surface nicht berücksichtigt. Surface 1 lHeight 640 lWidth 800 Farbtiefe 8 Bit
Surface 2 640
800 Bild 1.6:
640
lHeight 640 lWidth 800 Farbtiefe 24 Bit 800
Width
Die Werte lHeight (640) und lWidth (800) sind bei beiden Surfaces gleich. Da die Surfaces unterschiedliche Farbtiefen haben, wird aber unterschiedlich viel Speicherplatz benötigt. Pitch erfasst die tatsächliche Größe des reservierten Speicherbereiches in Byte. Es ist falsch, anzunehmen, dass Pitch durch lWidth * lHeight * Farbtiefe zu berechnen ist. Betrachten Sie hierzu folgende Abbildung: Front Buffer einer Surface
benötigter Cache einer Surface
Width Pitch Bild 1.7:
Pitch
Der Pitch-Wert ist hilfreich, wenn Sie den Surface-Speicher direkt manipulieren möchten. Diese Technik wird z.B. bei der Farbenanimation genutzt. Zugriff auf den Speicherbereich erhalten Sie durch die DirectDrawSurface.Lock()-Methode. Bitte beachten Sie, dass Sie bei solchen Speichermanipulationen direkt an der Hardware arbeiten. Bei solch einem hardwarenahen Arbeiten wird der kleinste Fehler mit einem Systemabsturz belohnt. Beispielsweise dürfen Sie niemals den geschützten Speicherbereich der Surface verlassen. Sie würden in Speicherbereiche schreiben, welche von irgendwelchen Modulen belegt sind. Dies hat im Regelfall fatale Auswirkungen.
Kapitel 1 • DirectDraw
35
Overlay Surface Eine Overlay Surface ist eine Surface, welche auf die primäre Surface gelegt wird. Bisher gingen wir davon aus, dass die primäre die einzig sichtbare Surface sei. Mit der Overlay Surface müssen wir die Annahme etwas modifizieren. Vergleichen Sie die Overlay Surface mit einer Folie, welche auf den Monitor geklebt wird. Auf dieser Folie können sie dann Bitmaps abbilden. Hauptsächlich wird diese Surface zur Darstellung von Videos eingesetzt. Natürlich können Sie auch einfache Bitmaps darstellen. Overlay Surfaces sind immer auf die Hardwareunterstützung der Grafikkarte angewiesen. Sie können nicht emuliert werden. Da die Overlay Surface mit einer klaren Folie vergleichbar ist und sie sich vor der primären Surface befindet, können Sie beide Surfaces gemeinsam sehen. Entfernen Sie die Overlay Surface, so ist die Grafik der primären Surface unbeschädigt sichtbar.
primäre Surface
Overlay Surface
Bild 1.8:
Overlay Surface über einer primären Surface
Die Hardware der Grafikkarte überprüft für jedes Pixel der primären Surface, ob es durch ein Overlay-Surface-Pixel verdeckt wird. Ist dies der Fall, so wird das Pixel (soweit vorhanden) sichtbar. Die Grafikkarte kombiniert die Bitmap der primären Surface mit der Overlay Surface, unter Verwendung von Transparenz und Dehnung der Overlay Surface. Die Overlay Surface wird durch die normale DirectDraw7.CreatSurface()Methode erzeugt. Benötigt wird das DDSCAPS_OVERLAY-Flag des DDSCAPS2-Typen-Arrays. Da die Overlay Surface im Videospeicher erstellt werden muss, müssen Sie auch noch das DDSCAPS_VIDEOMEMORY-Flag setzten. Die Position der Overlay Surface wird mit der DirectDraw Surface7.SetOverlay Position()-Methode bestimmt. Sie nutzt nur zwei Parameter. X und Y geben die Koordinaten auf der primären Surface an.
36
DirectDraw-Grundlagen
Wenn Sie mehr als eine Overlay Surface nutzen, müssen Sie die Reihenfolge (ZOrder) der Überlagerungen definieren. Die DirectDrawSurface7.UpdateOverlay ZOrder()-Methode übernimmt das für Sie. Beachten Sie die beiden Parameter dieser Methode. Zuerst benötigen wir ein Flag. Dieses Flag definiert die Tiefenposition. Folgende Auswahl steht zur Verfügung: DDOVERZ_INSERTINBACKOF DDOVERZ_INSERTINFRONTOF DDOVERZ_MOVEBACKWARD DDOVERZ_MOVEFORWARD DDOVERZ_SENDTOBACK DDOVERZ_SENDTOFRONT
= = = = = =
5 4 3 2 1 0
Der zweite Parameter ist dds vom Typ DirectDrawSurface7. Er bestimmt, von welcher Overlay Surface das Z-Order-Attribut geändert werden soll. Overlay Surfaces werden durch den Einsatz einer Blitting-Methode nicht sichtbar. Um Sie sichtbar zu machen, müssen Sie den Colorkey nutzen. Overlay Color Key Im Vergleich zu anderen Surfaces können Sie eine Overlay Surface nicht durch die gebräuchlichen Blitting Methoden für den Anwender sichtbar machen. Dies ist dadurch begründet, das die Overlay Surface über die primäre Surface gelegt wird. Da uns DirectDraw diese Technik verwehrt, greifen wir zu einem Trick. Wir nutzen den Colorkey. Mit der DirectDrawSurface7.UpdateOverlay()-Methode aktualisieren Sie die Overlay Surface. Sie können den Source Colorkey nutzen. Damit legen Sie fest, welche Pixel der Overlay Surface transparent sein sollen. Gleichermaßen ist es erlaubt, den Destination Colorkey einzusetzen. Mit ihm bestimmen Sie, welche Pixel der primären Surface von der Overlay Surface überschrieben werden. Kombinationen beider Möglichkeiten sind erlaubt. Compressed Texture Surfaces Ein hochgelobtes Feature von DirectX ist die Texturkompression. Dieses 1998 mit DirectX6 eingeführte Feature basiert auf einem Algorithmus von S3. Bekannt unter der Bezeichnung S3TC wurde er von Microsoft lizenziert. S3TC – Algorithmus: Ein Texel ist ein Pixel auf einer Textur. DirectDraw nutzt eine Kompressionstechnik (S3TC), welche die Textur in 4X4-Texel-Blöcke teilt. Jedes Texel wird mit 2 Bit beschrieben. Zusätzlich wird jeder Block mit zwei 16-Bit-Farben (RGB565) versehen. Der S3TC-Algorithmus bildet nun aus diesen beiden Wertegruppen und zwei weiteren über die ersten Werte interpolierten Farbwerten eine so genannte »Color Look-Up-Table« (CLUT). Diese CLUT wird verwendet, um die richtigen Farbwerte des jeweiligen Texel in der Matrix zu bestimmen. Insgesamt benötigen die 16 Texel der Matrix nun 64 Bit, d.h. durchschnittlich nur 4 Bit pro Pixel. Bei Transparenzeffekten kommen weitere 64 Bit dazu.
Kapitel 1 • DirectDraw
37
Texturkompression erhält eine besondere Bedeutung, da die Bildqualität erheblich gesteigert werden kann. Ohne Texturkompression ist der Programmierer darauf angewiesen, möglichst kleine Texturen zu verwenden. Es sollten möglichst viele Texturen im Speicher der Grafikkarte Platz finden. Mit diesem Ziel vor Augen wurden Texturen mit acht Bit Farbtiefe erstellt. Zu Zeiten von 32 Bit Rendering machte dies natürlich wenig Sinn. Alternativ können 16 Bit Farbtiefe eingesetzt werden, aber dann wurde oftmals an der Auflösung gespart. Wie man es auch drehen und wenden mag, das Ergebnis konnte nie recht überzeugen. Texturkompression steigert den Spielraum des Programmierers. So ist es möglich, Texturen, welche ohne Kompression ca. 20 MB verschlingen würden, auf ca. 6,5 MB zu reduzieren. Kompressionsraten von über 50 % sind kein Problem. So hilfreich die Texturkompression auch sein mag, kann man nicht leugnen, das diese Technik an Bedeutung verliert. Wir haben mit Grafikkarten von bis zu 64 MB Speicher gearbeitet. Mit solchen Grafikkarten kommt man recht selten in die Verlegenheit, dass der Speicherplatz nicht mehr ausreicht. Außerdem arbeiten die Computer mit sehr schnellem Systemspeicher. Der Datenaustausch erfolgt über einen 100 MHz (oder schneller) schnellem Frontside Bus. Werden Texture Surfaces in den Systemspeicher ausgelagert, können Sie dennoch mit einer akzeptablen Performance eingesetzt werden. Zum Erzeugen einer komprimierten Texture Surface setzen Sie das DDSCAPS_ TEXTURE-Flag in den lCaps-Parameter des DDSCAPS2-Typen-Arrays. Die Höhe und die Breite der Surface muss ein Vielfaches von 4 (Pixel) sein. Der IfourCC-Parameter des DDPIXELFORMAT-Typen-Arrays muss auf einen DXT-Code (siehe unten) gesetzt werden. Zu guter Letzt setzen Sie das DDPF_ FOURCC-Flag des Parameters lFlags des DDPIXELFORMAT-Typen-Arrays. Mögliche DXT-Codes: Über den DXT-Code werden interne Informationen der komprimierten Texture Surface organisiert. Genaue Kenntnisse über die interne Struktur werden für die Nutzung nicht benötigt. Sie werden erst hilfreich, wenn Sie eine komprimierte Texture Surface direkt manipulieren wollen. Moderne Grafikkarten nutzen Speicher von bis zu 64 MB. So hat dieses hilfreiche Feature an Nutzen verloren. Da sich der Trend, immer mehr Speicher auf der Grafikkarte zu platzieren, fortsetzt, werden wir die DXT-Codes und somit die Texturekompression nicht ausgiebig besprechen. FORCC
Beschreibung
vormultiplizierter AlphaKanal
DXT1
Lichtdurchlässigkeit / ein Bit Alpha
DXT2
ausdrücklich Alpha
Ja
DXT3
ausdrücklich Alpha
Nein
DXT4
interpoliert Alpha
Ja
DXT5
interpoliert Alpha
Nein
38
DirectDraw-Grundlagen
Jede einzelne Texture muss spezifiziert sein, dass sie 64 oder 128 Bits für eine Gruppe von 16 Texel speichert. Ein 64 Bit Block wird durch den DXT1-Code gekennzeichnet. Werden 128 Bit Blocks verwendet so sind dies die DXT2- und DXT3-Formate. Im interpoliertem Modus sind es die DXT4- und DXT5-Formate. Es gibt zwei Wege, um eine Grafik in ein komprimierte Texture Surface zu laden.
1.1.6
•
Erstellen Sie eine normale Surface mit einer Bitmap. Benutzen Sie die Blt()Methode oder die BltFast()-Methode, um die Bitmap von der normalen Surface in die komprimierte Surface zu blitten. DirectDraw komprimiert die Bitmap automatisch.
•
Als zweite Möglichkeit können Sie eine komprimierte Bitmap direkt in den Speicher der komprimierten Surface laden.
Palette Eine DirectDraw-Palette ist ein Array von 2, 4, 16 oder 256 Farben. In dem Array sind die Farbanteile für Rot, Grün und Blau gespeichert. Eine Palette kann maximal 8 Bit tief sein. Die Paletteneinträge von 0 bis 255 werden aus einer Bandbreite von 16 oder 24 Bit selektiert. Farbe1 Rotanteil
Farbe1 Grünanteil
Farbe1 Blauanteil
Farbe2 Rotanteil
Farbe2 Grünanteil
Farbe2 Blauanteil
Farbe3 Rotanteil
Farbe3 Grünanteil
Farbe3 Blauanteil
RGB Farben
8 Bit 16 Bit Farbe256 Rotanteil Bild 1.9:
Farbe256 Grünanteil
Farbe256 Blauanteil
24 Bit
Palettenmodell von DirectX
Die Palette können wir uns als Malkasten vorstellen. In diesem Malkasten werden 256 Farben abgelegt. Mit einer Palette ist der Programmierer in der Lage, 8-BitSurfaces zu erstellen, welche aber ein besonderes Farbniveau haben. Z.B. Paletten in bestimmte Farbrichtungen: viele Blautöne. 8-Bit-Surfaces sparen im Ver-
Kapitel 1 • DirectDraw
39
gleich zu 16- oder 24-Bit-Surfaces viel Speicherplatz. Ebenfalls wirkt sich eine 8-Bit-Surface auf die Performance positiv aus. Mit der DirectDraw7.CreatePalette()-Methode wird eine Palette erstellt. Mit der DirectDrawSurface7.SetParlette()-Methode wird die erstellte Palette einer oder mehrerer Surfaces zugewiesen. Auf die einzelnen Paletteneinträge könne Sie mit den Methoden DirectDrawPalette.GetEntries() und DirectDrawPalette.SetEn tries() zugreifen. Bei der DirectDraw7.CreatePalette()-Methode müssen Sie die DDPCAPS_1Bit-, DDPCAPS_2Bit-, DDPCAPS_4Bit- und DDPCAPS_8Bit-Flags setzen. Somit kennzeichnen Sie die Anzahl der Paletteneinträge. Mit dem DDPCAPS_AL LOW256- Flag erhalten Sie den Zugriff auf die Paletteneinträge. Dim Dim Dim Dim For
Palette As DirectDrawPalette Surface As DirectDrawSurface7 DDraw As DirectDraw7 Pal(255) As PALETTEENTRY I = 0 To 255 'Farbverlauf Blau Pal(i).red = 0 Pal(i).green = 0 Pal(i).blue = I Next I Set Palette = DDraw.CreatePalette(DDPCAPS_8Bit Or _ DDPCAPS_ALLOW256, Pal()) Surface.SetPalette Palette
1.1.7
Clipper Das DirectDrawClipper-Objekt erlaubt es, auf selektierte Bereiche einer Surface zu blitten. Ein Clipper wird als rechteckiger Bereich definiert. Alle Blitter-Methoden, welche innerhalb des definierten Bereichs liegen, sind für den Anwender sichtbar. So ist es möglich, mit Hilfe des Clippers Teile des Bildschirms vor den Augen des Anwenders zu verbergen. Sie dürfen für eine Surface mehrere ClipperBereiche festlegen. Diese werden durch eine Clipper-Liste (Clip List) verwaltet. Das einfachste und häufigste Einsatzgebiet des Clippers ist es, die Grenzen eines Fensters oder Bildschirm zu markieren. Ein weiteres häufig genutztes Einsatzgebiet steht im Zusammenhang mit der Sprite-Animation. Hierbei ist es gewünscht, das ein Sprite sanft in einen sichtbaren Bildschirmbereich bewegt wird. Ohne Clipper würde das Sprite so lange unsichtbar bleiben, bis seine gesamte RECT Struktur innerhalb des sichtbaren Bereichs liegt. Erst dann würde das Sprite auf einen Schlag sichtbar. Mit Hilfe des Clippers ist DirectDraw in der Lage zu entscheiden, welche Teile des Sprites innerhalb des sichtbaren Bereichs (Clipper) liegen, und nur diese würden für den Anwender sichtbar. Der Teil des Sprites, welcher außerhalb des Clippers liegt, bleibt unsichtbar.
40
DirectDraw-Grundlagen
Bereich 1
Bereich 2
sichtbar für den Anwender
sichtbar für den Anwender
unsichtbar für den Anwender Bild 1.10: Clipperbereiche
In einer Fullscreen-Anwendung kann der Clipper nicht eingesetzt werden.
1.1.8
Blitting Blitting (BitBlock Transfer) bedeutet nichts anderes, als Grafikdaten aus dem Speicher auf eine Surface zu kopieren. Da die Surface ebenfalls im Speicher existiert, werden die entsprechenden Daten im Speicher verschoben. Es stehen fünf Blitting-Methoden zur Verfügung. •
DirectDrawSurface7.Blt() Dies ist die Standart-Blit-Methode. Es wird ein definierter rechteckiger Bereich in einen anderen definierten rechteckigen Bereich kopiert. Sollten diese Bereiche unterschiedliche Dimensionen haben, so wird die Bitmap automatisch angepasst (Stretch). Diese Methode unterstützt synchrones und unsynchrones Blitten. Weiterhin können die Daten in unterschiedlichen Speicherbereichen liegen. •
Video-Speicher->Video-Speicher
•
Video-Speicher ->System-Speicher
•
System-Speicher->Video-Speicher
•
System-Speicher->System-Speicher
Die Blt()-Methode ist in der Lage, den Source Colorkey sowie den Destination Colorkey zu nutzen. •
DirectDrawSurface7.BltFast Die BltFast()-Methode ist (wie es der Name bereits sagt) schneller als die Blt()-Methode. Die Performancesteigerung liegt bei etwa 10%. Sie birgt aber auch Nachteile. So wird Sie nicht von allen Grafikkarten unterstützt (Sollten Sie eine einigermaßen moderne Grafikkarte besitzen, brauchen Sie sich nicht
Kapitel 1 • DirectDraw
41
zu sorgen.). Sie arbeitet ausschließlich mit Surfaces, welche im Videospeicher erstellt wurden. Sie ist nicht in der Lage das Clipper-Objekt zu nutzen. Sie ist nicht fähig, eine Bitmap zu dehnen. •
DirectDrawSurface7.BltColorFill() Sie füllt einen rechteckigen Bereich mit einer Farbe.
•
DirecDrawSurface7.BltToDC() Diese Methode blittet eine Bitmap auf ein beliebiges Objekt mit einem Handle. Es müssen zwei rechteckige Bereiche angegeben werden, welche exakt die gleichen Dimensionen haben. Die Lage der Bereiche kann variieren.
•
DirectDrawSurface7.BltFx() Dies ist der Trickkünstler unter den Blitting-Methoden. Als Besonderheit werden BltFx Parameter übergeben. Diese Parameter beschreiben Trickeffekte wie Spiegeln einer Bitmap oder Rotieren einer Bitmap. Von DirectDraw werden eine Reihe dieser Effekte unterstützt. Leider findet man nur selten eine Grafikkarte, welche alle Möglichkeiten von DirectDraw umsetzen kann. Effekte wie horizontales oder vertikales Spiegeln sind Standardeffekte, welche von nahezu allen Grafikkarten unterstützt werden.
Nun ist es Zeit etwas über das Blit Timing zu sagen. Im Zusammenhang mit Blitter-Methoden versteht man unter Timing ein synchrones oder unsynchrones Blitten von Grafikdaten. Synchron bedeutet, dass sich die Blitter-Methode nach dem Zeilenaufbau der Grafikkarte und somit des Monitors richtet. Wenn Sie eine der oben vorgestellten Blit-Methoden einsetzen und der Hardware Blitter ist mit seiner aktuellen Aufgabe noch nicht fertig, so wird eine Fehler verursacht. Sie erhalten die Fehlernachricht DDERR_WASSSTILLDRAWING. Um sicher zu stellen, dass der Hardware Blitter seine Arbeit vollständig beendet, wird das DDBLT_WAIT-Flag der Blt()-Methode gesetzt. DDBLTFAST_WAIT ist das entsprechende Äquivalent für die BltFast()-Methode. DirectDraw akzeptiert eine unsynchrone Arbeitsweise. Hierzu wird das DDBLT_ ASYNC-Flag gesetzt. Diese Technik ist von den Möglichkeiten der Grafikkarte abhängig. Sie wird erst sinnvoll, wenn Sie Blt-Methoden schneller aufrufen, als sie vom Zeilenraster des Monitors aufgebaut werden. Um eine möglichst hohe Kompatibilität zu anderen Systemen zu wahren, sollten Sie auf eine unsynchrone Arbeitsweise verzichten oder zumindest dem Anwender die Wahl überlassen.
1.1.9
Page Flipping Das Flippen können Sie sich am besten am Beispiel eines Blatt Papiers verdeutlichen. Während die Oberseite für Sie sichtbar ist, wird auf der Unterseite gezeichnet. Ist die Grafik erstellt, wird das Blatt umgedreht und die neu erstellte Grafik wir für Sie sichtbar. Man spricht hierbei von dem so genannten Page Flipping. Moderne Grafikkarten beherrschen einen besonderen Trick. Sie müssen die Grafikkarten nicht mehr von der Unterseite auf die Oberseite kopieren, sondern ver-
42
Blitting
schieben lediglich einen Zeiger auf den sichtbaren Bereich des Videospeichers. Diese Technik wird durch das DACRAM der Grafikkarte ermöglicht. Page Flipping wird vor allem bei der Double- und Triplebuffer Technik eingesetzt. Bei der Doublebuffer Technik wird nur eine Backbuffersurface eingesetzt. Die Anwendung schaltet nun immer zwischen der sichtbaren und der unsichtbaren Surface hin und her. Jedes Mal, wenn sich die Grafik auf der nicht sichtbaren Surface geändert hat, wird sie mit Hilfe der Flip()-Methode zu einer sichtbaren Surface gemacht. Bei der Triplebuffer-Technik werden zwei Backbuffersurfaces eingesetzt. Die Surfaces werden durch eine Flipping Chain miteinander verbunden. Die Flip()-Methode stellt eine gewaltige Anforderung dar. Sie kann nur eingesetzt werden, wenn Ihre Anwendung im Fullscreen-Modus arbeitet. Der Fullscreen-Modus verlangt einen exklusiven Zugriff auf die Grafikkarte. Natürlich lohnt sich der Aufwand, denn die Flip()-Methode ist im Vergleich zu den Blitteraktionen schneller. Die Flip()-Methode wird von fast allen Grafikkarten unterstützt. In wenigen Fällen kommt es vor, dass DirectDraw die Flip()-Methode emulieren muss. Diese Emulation wirkt sich negativ auf die Performance aus, da diese Arbeit von der CPU des Computers verrichtet wird. Mögliche Gründe für eine Emulation können sein: •
Die Grafikkarte unterstützt die Flip()-Methode nicht
•
Die Surfaces wurden nicht oder nur teilweise im Videospeicher erstellt.
Synchron oder Unsynchron? Die Flip()-Methode ist unsynchron. Unsynchron bedeutet, Sie richtet sich nicht nach dem vertikalem Zeilenaufbau des Monitors. Dies führt natürlich zu einem Problem. Wird die Flip()-Methode aufgerufen, obwohl der letzten Grafikaufbau noch nicht beendet wurde, werden Sie eine eventuell eine fehlerhafte Grafikdarstellung erhalten. Dies macht sich oftmals als Doppelbilder oder Umrissschatten bemerkbar. Dieses Problem können Sie mit dem DDFLIP_WAIT-Flag schnell und elegant lösen. Durch dieses Flag zwingen Sie DirectDraw, auf die Fertigstellung eines aktuellen Grafikaufbaus zu warten. In vielen Fällen können Sie dennoch auf ein synchrones Arbeiten verzichten. Durch ein unsynchrones Arbeiten können Sie Darstellung von Einzelbildern (Bilder pro Sekunde) deutlich steigern und schaffen zusätzliche frei verfügbare Rechenzeit.
1.2
Blitting Mit dem Kapittel »Blitting« demonstrieren wir, wie Sie eine primäre Surface sowie eine Offscreensurface erstellen. Um die Grafik von der Offscreensurface auf die primäre Surface zu kopieren, wird die Blt()-Methode zum Einsatz kommen. Weiterhin erklären wir die Einbindung von DirectX und DirectDraw in Ihre VB-Anwendung. Unser Ziel ist es, eine Grafik aus der Offscreensurface auf die
Kapitel 1 • DirectDraw
43
primäre Surface zu blitten. An der folgenden Grafik können Sie gut erkennen, welche Objekte wir erstellen müssen und wie die Objekte eingebunden sind. DirectDrawCreate() CreateSurface()
primäre Surface
Backbuffer Surface
Blt()
Bild 1.11: Einfaches Blitten vom Backbuffer auf die primäre Surface mit der Blt()-Methode
Folgende Methoden werden in diesem Abschnitt vorgestellt. Sie sind die Grundlage für alle DirectDraw-Anwendungen. DirectDrawCreate() Erzeugt ein DirectDraw7-Objekt object.DirectDrawCreate (guid As Long) As DirectDraw7 object
ein gültiges DirectX7-Objekt
guid
Adresse zu einem eindeutigen Display-Treiber, der erzeugt werden soll. Der String kann leer sein, dann wird der zur Zeit aktive Display-Treiber genommen. DDCREATE_EMULATIONONLY Es werden keine Hardware-Eigenschaften unterstützt. Alle Eigenschaften werden emuliert. DDCREATE_HARDWAREONLY Hardware-Eigenschaften werden niemals emuliert. Werden Eigenschaften genutzt, welche von der Hardware nicht unterstützt werden, so führt dies zu einem Fehler.
44
Blitting
TestCooperativeLevel() Ermittelt den aktuellen CooperativeLevelStatus für eine Fensteranwendung oder Fullscreen-Anwendung object.TestCooperativeLevel() As Long object
ein gültiges DirectDraw7-Objekt
CreateSurface() Erzeugt ein DirectDrawSurface-Objekt object.CreateSurface( _ dd As DDSURFACEDESC2) As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
dd
Eine Variable vom Typ DDSURFACEDESC2 → enthält die Beschreibungen der Surface
CreateSurfaceFromFile() Erzeugt ein DirectDrawSurface-Objekt aus einer Bitmap. object.CreateSurfaceFromFile( _ dd As DDSURFACEDESC2) As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
dd
Eine Variable vom Typ DDSURFACEDESC2 → enthält die Beschreibungen der Surface
GetWindowsRect() Ermittelt die Eckwerte eines Rechtecks, welche den Clientbereich eines Fensters beschreibt. Call object.GetWindowRect(hwnd As Long, r As RECT) object
ein gültiges DirectDraw7-Objekt
hwnd
Handle eines Fensters, dessen Clientbereich ermittelt werden soll.
r
Eine Variable vom Typ RECT, welche die ermittelten Werte aufnimmt.
Blt() Kopiert Daten per Bit Block Transfer aus einem Speicherbereich in einen anderen object.Blt(destRect As RECT, ddS As DirectDrawSurface7, srcRect As RECT, flags As CONST_DDBLTFLAGS) As Long object
ein gültiges DirectDrawSurface7-Objekt
Kapitel 1 • DirectDraw
45
Blt() destRect
Variablen vom Typ RECT, welche die Punkte oben links und unten rechts eines Rechtecks beschreiben. Wird dieser Wert nicht angegeben oder sind die Werte der Variablen leer, so wird der gesamte Bereicht der Ziel-Surface angenommen.
dds
Ein gültiges Surface-Objekt, welches die Daten aufnehmen soll.
srcRect
Variable vom Typ RECT, welche die Punkte oben links und unten rechts eines Rechtecks beschreiben. Wird dieser Wert nicht angegeben oder sind die Werte der Variablen leer, so wird der gesamte Bereicht der Quell-Surface angenommen.
Flags
Eine Kombination von Argumenten aus der CONST_DDBLTFLAGS-Liste.
Blitting bildet die Grundlage aller DirectDraw-Anwendungen. Deshalb erklären wir diese Technik von A bis Z. Das angestrebte Ziel ist nicht besonders spektakulär. Wir wollen lediglich ein Bild auf dem Monitor sichtbar machen. Das hört sich nach keiner besonderen Herausforderung an, aber um dies zu erreichen, müssen wir einiges an Arbeit leisten. Um die Schematik zu verdeutlichen, können wir die anstehenden Aufgaben in vier Schritte unterteilen. Schritt 1
Erstellen einer Form
Schritt 2
Variablen benennen
Schritt 3
Variablen initialisieren
Schritt 4
Blit
Schritt1: Erstellen einer Form Öffnen Sie ein Standard-Visual-Basic-Projekt. Platzieren Sie eine Picturebox. Die Left- und die Top-Eigenschaften setzen Sie auf den Wert »0«. Die Name-Eigenschaft der Picturebox belassen Sie auf dem Wert »Picture1«. In der Picturebox wird später die Grafik dargestellt. Es ist nicht nötig, die Grafik in der Picturebox darzustellen, ebenso könnte die Grafik direkt auf dem Form Objekt dargestellt werden. Welche Objekte als Empfänger für die Grafik geeignet sind, wird durch die Objekt-Eigenschaften bestimmt. So ist z.B. die Objekt-Zugriffsnummer (Handle) zwingend erforderlich. Das Handle ist ein ganzzahliger Wert, der von der Betriebsumgebung vergeben wird. Anhand von diesem Wert ist das Objekt eindeutig gekennzeichnet. Grundlegend kann man feststellen, das die Windows API auf solche Zugriffsnummern angewiesen ist. Schritt 2: Variablen benennen Zuerst müssen wir die DirectX7-Klassen einbinden.
46
Blitting
Die Einbindung erfolgt folgendermaßen: Öffnen Sie unter Visual Basic die Symbolleiste Projekt > Verweise. Es wird das Dialogfeld »Verweise« geöffnet. Aktivieren Sie den Eintrag DirectX 7 for Visual Basic Type Library. Bestätigen Sie mit OK. Die eigentliche Einbindung für Ihr Projekt erreichen Sie folgendermaßen: Dim objDX as New DirectX7
Die DirectX7-Klasse kann man als Ursprung der DirectX-Technologie betrachten. Von diesem Punkt aus wird in alle Sektionen von DirectX verzweigt. Der grobe Rahmen wird durch DirectDraw, Direct3D, DirectSound, DirectInput, DirectPlay und DirectMusic gebildet. Dim objDD As DirectDraw7
Wird benötigt um DirectDraw-Objekte zu erzeugen. DirectDraw-Objekte sind der Kern jeder DirectDraw-Anwendung. DirectDraw-Objekte kann man als Repräsentanten der Display-Devices betrachten. Insofern das Display-Device Hardwarebeschleunigungen zulässt, werden diese über das DirectDraw-Objekt umgesetzt. Dim objDDSurf As DirectDrawSurface7 Dim objDDPrimSurf As DirectDrawSurface7
Wird benötigt um DirectDrawSurface-Objekte zu erzeugen. Als Surface wird ein zusammenhängender Speicherbereich bezeichnet. Surfaces werden normalerweise im Speicherbereich der Grafikkarte erzeugt, können aber auch im Systemspeicher existieren. Da die Verwaltung der Videografikspeichers von der Videografikkarte übernommen wird, kann eine Surface parallel zum normalen CPUTakt abgearbeitet werden. Dies macht sich natürlich auch durch einen erheblichen Performancegewinn bemerkbar. Es werden in der Regel mehr als eine Surface erzeugt. Dim ddsd1 As DDSURFACEDESC2 Dim ddsd2 As DDSURFACEDESC2
Enthält die Beschreibung einer DirectDrawSurface. DDSURFACEDESC2 steht vor der DirectDraw.CreateSurface()-Methode. Schritt 3: Variablen initialisieren Mit dem Initialisieren der Variablen ist das Erzeugen der notwendigen Direct Draw-Objekte gemeint. Als Erstes wird der Zugriff auf die Grafikkarte erzeugt. Set objDD = objDX.DirectDrawCreate("")
Kapitel 1 • DirectDraw
47
Der leere String bei der DirectDrawCreate()-Methode besagt, dass das primäre Display-Device genutzt werden soll. Call objDD.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL)
Mit der SetCooperativeLevel()-Methode wird die grundlegende Darstellungsform bestimmt. Me.hWnd gibt uns das Handle (Zugriffsnummer) des aktiven FormObjeks. DDSCL_NORMAL besagt, dass eine normale Windows-Anwendung vorliegt. Es werden keine Änderungen an der Farbtiefe oder am Display vorgenommen. Direct Draw passt sich dem aktuellen Form-Objekt an. Wir benötigen zwei Surfaces. Eine sichtbare und eine unsichtbare. Der Trick mit der Geschwindigkeit liegt darin, dass alle anfallenden Arbeiten auf der unsichtbaren Surface vorgenommen werden. Nach Abschluss der Arbeiten wird der Inhalt der unsichtbaren auf die sichtbare geblittet. Surface 1: Jetzt folgen die genauen Beschreibungen der DirectDraw-Surface. ddsd1.lFlags = DDSD_CAPS
Gibt uns den Zugriff auf die ddsCaps-Datenstruktur frei. Somit ist die ddsCapsDatenstruktur als gültiges Mitglied definiert. ddsd1.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE
Hiermit wird festgelegt, dass ddsd1 eine primäre, für den Anwender sichtbare Surface sein soll. Nun können wir die primäre DirectDraw-Surface erzeugen. Set objDDPrimSurf = objDD.CreateSurface(ddsd1)
Das Erzeugen erfolgt problemlos, da alle Parameter in ddsd1 definiert wurden. Surface 2: ddsd2.lFlags = DDSD_CAPS
Auch bei der Surface 2 geben wir die ddsCaps-Datenstruktur als gültiges Mitglied frei. ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
ddsd2 wird diesmal nicht als sichtbare Surface definiert, sondern als unsichtbare Offscreensurface. Die generelle Aufgabe einer Offscreensurface ist es, Grafikdaten zu speichern. Diese Daten werden dann auf die primäre Surface geblittet. Set objDDSurf = objDD.CreateSurfaceFromFile("Beispielbitmap", _ ddsd2)
48
Blitting
Auch beim Erzeugen der eigentlichen Surface macht sich eine kleine Änderung bemerkbar. Die eingesetzte Methode ist nicht mehr CreateSurface(), sondern CreateSurfaceFromFile(). Der Unterschied lässt ich bereits vom Namen ableiten. Diesmal wird die Surface direkt mit den Grafikdaten einer Bitmap gefüllt. Surface 1 und Surface 2 sind definiert. Also steht dem Blitting nichts mehr im Weg. Schritt 4: Blit Zum Blitten benötigen wir nur einen Befehl. Vorher müssen wir zwei rechteckige Bereiche definieren, welche uns zeigen, von wo die Grafikdaten kommen und wohin Sie sollen. r1 und r2 sind jeweils Zeiger auf eine RECT-Datenstruktur. Um die genaue Größe des Ziels zu ermitteln, bedienen wir uns der Methode GetWin dowRect(). Diese Methode schreibt uns die Daten des Clientbereiches (auf den das Handel weist) in die RECT-Struktur von r1. Die Struktur von r2 können wir durch einfache Zuweisungen füllen. Dies ist möglich, da diese Surface durch die Methode CreateSurfaceFromFile() erzeugt wurde und somit schon mit Daten gefüllt ist und eine logische Größe besitzt. Ist die Größe des Zielrechtecks ungleich der Größe des Quellrechtecks, so werden die Grafikdaten automatisch angepasst. Dim r1 As RECT Dim r2 As RECT Call objDX.GetWindowRect(Picture1.hWnd, r1) r2.Bottom = ddsd2.lHeight r2.Right = ddsd2.lWidth
Jetzt sind alle Daten komplett. Es folgt das lang erwartete Ergebnis. Blitting per DirectX. ddrval = objDDPrimSurf.blt(r1, objDDSurf, r2, DDBLT_WAIT)
Der Vollständigkeit halber sei noch DDBLT_WAIT erklärt. Dieses Flag gibt lediglich an, das DirectDraw auf die Fertigstellung des Blitvorgangs warten soll. Dieses Warten wird auch als synchrones Arbeiten bezeichnet. Beispiel (Blitting) Nachdem Sie das Kapitel Blitting gelesen haben, sollte dieses Beispiel kein Problem darstellen. Folgende Grafik zeigt die Bitmap, welche dargestellt werden soll. Im Deklarationsabschnitt werden die Surfaces sowie die notwendigen DDSURFACEDESC2 definiert. Natürlich werden auch die Knotenpunkte von DirectX und dem untergeordneten DirectDraw eingerichtet.
Kapitel 1 • DirectDraw
49
Bild 1.12: Bitmap für das Blitting-Beispiel Dim Dim Dim Dim Dim Dim
objDX As New DirectX7 objDD As DirectDraw7 objDDSurf As DirectDrawSurface7 objDDPrimSurf As DirectDrawSurface7 ddsd1 As DDSURFACEDESC2 ddsd2 As DDSURFACEDESC2
Um die Übersicht in den Programmen zu wahren, werden alle notwendigen Arbeiten über Subroutinen erledigt. Somit bleibt für die Abschnitte Form_Load() und Picture1_Paint() nur der Aufruf von Init() und Blt(). Private Sub Form_Load() Init End Sub
Der Aufruf der Blt() Routine wurde mit Absicht in das Paint-Ereignis von Picture1 gelegt. Dadurch wird die Grafik der Anwendung immer aktualisiert sobald das Fernster z.B. verschoben, überlagert oder in der Größe geändert wird. Eben immer wenn das Paint-Ereignis ausgelöst wird.
50
Blitting
Private Sub Picture1_Paint() Blt End Sub
Die Subroutine Init() erledigt die meiste Arbeit. Zugriff auf die Grafikkarte herstellen, Top Level der Anwendung setzen und die beiden Surfaces einrichten und erstellen. Private Sub Init() Set objDD = objDX.DirectDrawCreate("") Call objDD.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL) 'Surface 1 erzeugen ddsd1.lFlags = DDSD_CAPS ddsd1.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Set objDDPrimSurf = objDD.CreateSurface(ddsd1) ' Surface 2 erzeugen ddsd2.lFlags = DDSD_CAPS ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Set objDDSurf = objDD.CreateSurfaceFromFile(App.Path & _ "\BlittingToTheScreen.bmp", ddsd2) End Sub
Für den kleinen Blitabschnitt bleibt nicht mehr viel zu tun. Das Zielrechteck in der Größe der Picturebox definieren. Die Größe der Quellgrafik ermitteln und in einer RECT-Struktur speichern. Zum Abschluss bleibt noch die eigentliche Blit()Methode. Private Sub Blt() Dim r1 As RECT Dim r2 As RECT Call objDX.GetWindowRect(Picture1.hWnd, r1) r2.Bottom = ddsd2.lHeight r2.Right = ddsd2.lWidth ddrval = objDDPrimSurf.Blt(r1, objDDSurf, r2, DDBLT_WAIT) End Sub
Sollten Zielrechteck und Quellrechteck nicht die gleiche Größe besitzen, wird die Grafik automatisch angepasst. Dies ist eine recht praktische Eigenschaft der Blt()Methode. Dieses automatische Dehnen oder Stauchen einer Bitmap verbraucht allerdings viel Rechenzeit des Systems. Wenn Sie später High-PerformanceAnwendungen erstellen möchten, sollten Sie akribisch auf die Einhaltung der Bitmapgrößen achten.
Kapitel 1 • DirectDraw
1.3
51
Sprites durch Transparenz Transparentes Blitting basiert auf dem Konzept von Blitting. Bei dieser Technik wird die Illusion erzeugt, als würde ein nicht rechteckiger Bereich geblittet. Dies ist wie gesagt eine Illusion. Blit bezieht sich immer auf einen rechteckigen Bereich. Der Eindruck einen nicht rechteckigen Bereich zu blitten, entsteht bei der Darstellung von Sprites. Sprites sind in der Regel nicht rechteckig. Wird nun ein Sprite dargestellt, sieht es so aus, als würde nur das eigentliche Sprite bewegt. In Wirklichkeit ist es jedoch ein Rechteck. Die Illusion wird erzeugt, indem alle Pixel welche nicht zum Sprite gehören als transparent betrachtet werden und die Pixel auf der Ziel-Surface nicht überschreiben. Die Kunst beim Erzeugen eines Sprites liegt bei der Definition einer transparenten Farbe oder eines transparenten Farbbereiches. Diese transparenten Farben werden in einem Farbschlüssel gespeichert. Dieser Farbschlüssel wird genutzt, um Farbbereiche der Sprite Surface für die Blitter Methoden zu sperren. CreateClipper() Erzeugt ein DirectDrawClipper-Objekt → DirectDrawSurface7.GetClipper, DirectDrawSurface7.SetClipper object.CreateClipper(flags As Long) As DirectDrawClipper object
Ein gültiges DirectDraw7-Objekt.
flags
Wird zur Zeit nicht verwendet. Muss 0 sein.
BltFast() Kopiert Daten per Bit Block Transfer aus einem Speicherbereich in einen anderen. Diese Methode kann nicht auf einen Clipper-Bereich zugreifen. Siehe die Blt()-Methode. object.BltFast( dx As Long, dy As Long, ddS As DirectDrawSurface7, _ srcRect As RECT, trans As CONST_DDBLTFASTFLAGS) As Long object
Ein gültiges DirectDrawSurface7-Objekt.
dx, dy
Koordinatenpaar auf der Zielsurface.
dds
Quellsurface, aus der die Grafik kopiert werden soll.
srcRect
Eine gültige RECT-Struktur, welche den Bereich auf der Quellsurface beschreibt, von der die Grafikdaten kopiert werden sollen.
trans
DDBLTFAST_DESTCOLORKEY = 2 Transparentes Blit unter Verwendung des Ziel-Farbschlüssels. DDBLTFAST_DONOTWAIT = 32 Wartet nicht, bis der Blitter fertig ist. DDBLTFAST_NOCOLORKEY = 0
52
Sprites durch Transparenz
BltFast() Normales Blit ohne Farbschlüssel ohne Transparenz. DDBLTFAST_SRCCOLORKEY = 1 Transparentes Blit unter Verwendung des Source-Farbschlüssels. DDBLTFAST_WAIT = 16 Wartet, bis der Blitter fertig ist.
Wir werden eine primäre Surface sowie drei Offscreensurfaces erstellen. Eine Offscreensurface verwenden wir als Backbuffer. Die zweite wird als Container für das Hintergrundbild benötigt. In der dritten Surface wird das Sprite gespeichert. Auf der Backbuffersurface werden Hintergrund und Sprite miteinander kombiniert und anschließend auf die primäre Surface geblittet. Zusätzlich richten wir noch das Clipper-Objekt ein. Dieses sichert uns eine saubere Darstellung in der Windowsumgebung. Das eigentliche DirectDraw-Fenster kann von anderen Fenstern überlagert werden. Ohne den Clipper würde die Grafik des DirectDrawFensters immer im Vordergrund gezeichnet. Die Auswirkungen des ClipperObjekts können Sie am besten im direkten Vergleich mit der Beispielanwendung »Blitting« erkennen. In dieser Anwendung ist es nicht möglich, das DirectDrawFenster zu überlagern. Die folgende Grafik zeigt Ihnen die benötigten DirectX-Objekte sowie deren Einbindung. Zum einfachen Verständnis können wir diese Technik in fünf Schritte zerlegen. Schritt 1: Erstellen einer Form Öffnen Sie ein Standard-Visual-Basic-Projekt. Platzieren Sie eine Picturebox. Die Left- und die Top-Eigenschaften setzen Sie auf den Wert »0«. Die Name-Eigenschaft der Picturebox setzen Sie auf den Wert »Picture1«. In der Picturebox wird später die Grafik dargestellt. Schritt 2: Variablen benennen Dim objDX As New DirectX7 Dim objDD As DirectDraw7
Standard-DirectX-Einbindungen (siehe Projekt »Blitting«). Dim Dim Dim Dim
objDDBackgroundSurf As DirectDrawSurface7 objDDSpriteSurf As DirectDrawSurface7 objDDScreenSurf As DirectDrawSurface7 objDDBackbufferSurf As DirectDrawSurface7
Kapitel 1 • DirectDraw
53
DirectDrawCreate() CreateSurface()
primäre Surface
Backbuffer Surface
Blt()
Offscreen Surface
2
1
Blt() BltFast()
Bild 1.13: Erweitertes Blitten
Wir benötigen vier Surfaces. ObjDDScreenSurf wird die primäre Surface. ObjDDBackgroundSurf wird die unsichtbare Surface mit der Hintergrundgrafik. ObjDDSpriteSurf wird die Grafikdaten des Sprites aufnehmen. ObjBackbuffer wird das gemischte Bild von objDDBackgroundSurf und objDDSpriteSurf aufnehmen, bevor es der primären Surface objDDScreenSurf übergeben wird. Dim objDDClip As DirectDrawClipper
Das Clipper-Objekt ist neu. Mit dem Clipper-Objekt erhalten Sie den Zugriff auf einen ausgewählten rechteckigen Bereich einer Surface. Der ausgewählte Bereich wird wiederum durch eine RECT-Struktur beschrieben. Dim Dim Dim Dim
ddsdBackground As DDSURFACEDESC2 ddsdSprite As DDSURFACEDESC2 ddsdScreen As DDSURFACEDESC2 ddsdBackbuffer As DDSURFACEDESC2
54
Sprites durch Transparenz
Die DDSURFACEDESC2 nehmen wieder die Surface-Beschreibungen auf. Dim rBackbuffer As RECT Dim rBackground As RECT Dim rSprite As RECT
Zum Abschluss werden die Variablen für die RECT-Strukturen festgelegt. Schritt 3: Variablen initialisieren Insgesamt müssen wir vier Surfaces, ein Clipper Objekt und drei RECT-Strukturen einrichten. Beginnen wir mit den vier Surfaces. Surface 1 (primäre Surface) ddsdScreen.lFlags = DDSD_CAPS ddsdScreen.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Set objDDScreenSurf= objDD.CreateSurface(ddsdScreen)
Hier ist nichts Neues zu entdecken. Farbtiefe und Auflösung der Anwendung werden nicht geändert. Sie wird als primäre Surface bestimmt und ist somit für den Anwender sichtbar. Surface 2 (Hintergrundbild) ddsdBackground.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT
Wir geben uns den Zugriff auf die ddsCaps- sowie Width- und Height-Eigenschaften frei. ddsdBackground.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
Die zukünftige Surface ddsdBackground wird als unsichtbare Offscreenoberfläche definiert. ddsdBackground.lWidth = Picture1.Width ddsdBackground.lHeight = Picture1.Height
Durch die Freigabe der Width- und Height-Eigenschaften als gültige Mitgliedsdaten können wir nun Zuweisungen treffen. Hier wird die Größe des Hintergrundes der Größe des Vordergrundes angepasst. Da wir ein aus verschiedenen Surfaces gemischtes Bild ausgeben möchten, sind die Größen der primären (sichtbaren) Surface und der unsichtbaren (sekundären) Surface von großer Bedeutung. Sie sollten gleich groß sein. Set objDDBackgroundSurf = _ objDD.CreateSurfaceFromFile("Bild.bmp", ddsdBackground)
Die Hintergrundsurface erstellen und mit den Bilddaten füllen.
Kapitel 1 • DirectDraw
55
Surface 3 (Sprite) ddsdSprite.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ddsdSprite.lWidth = 64 ddsdSprite.lHeight = 64 ddsdSprite.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Set objDDSpriteSurf = _ objDD.CreateSurfaceFromFile("Sprite.bmp", ddsdSprite)
Hier wird genau das Gleiche wie bei Surface 2 gemacht. Nur die Größe der Sprite Surface wird auf 64 x 64 Pixel begrenzt. Mehr ist nicht notwendig. Surface 4 (Backbuffer) Die Backbuffersurface wird benötigt, um das aus Surface 2 und 3 gemischte Bild auf der Surface 1 auszugeben.
Surface 3 Sprite
Surface 2 Hintergrund
Surface 4 Backbuffer
Surface 1 primäre Surface
Bild 1.14: Zusammenbau von Hintergrund und Sprite
Warum wird der Umweg über den Backbuffer gemacht? Bedeutet dies nicht einen Performanceverlust? Die Performance wird durch das Zwischenspeichern der Grafikdaten positiv beeinflusst. Eine direkte Zusammenführung auf der sichtbaren Surface würde in Zusammenhang mit Aktualisierungen der gesamten Windowsoberfläche stehen. Dadurch wirkt sich der Backbuffer als hilfreiches Instrument zur Performance-
56
Sprites durch Transparenz
steigerung aus. Würde man die Grafiken von Surface 2 und 3 auf der Surface 1 direkt durchführen, würde der Aufbau durch ein unangenehmes Flimmern überschattet. Außerdem ist ein Arbeiten im Backbuffer (also rein im Speicher des Computers) von der Hardwareverarbeitung des angeschlossenen Bildschirms nicht abhängig. Ein Arbeiten auf einer sichtbaren Surface bedeutet immer ein Warten auf den Rasterstrahl des Monitors. Dies entfällt beim Arbeiten im Speicher. In diesem Beispiel werden lediglich 2 Surfaces zusammengeführt. Stellen Sie sich einmal vor, Sie wollen aber 10, 20 oder 100 Surfaces zusammenführen, so ist es sinnvoll, dies im schnellen Speicher zu tun und anschließend alles in einem Schwung auf die sichtbare Surface zu blitten. Das Handling der Surfaces wird oftmals von den Prozessoren der Grafikkarte übernommen und entlastet somit die ohnehin schon überarbeitet CPU des Computers. Die Technik des Backbuffers: ddsdBackbuffer.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH
Den Zugriff auf die ddsCaps-Struktur sowie der Height- und Width-Eigenschaften freigeben. ddsdBackbuffer.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Or _ DDSCAPS_SYSTEMMEMORY
Auch der Backbuffer wird als Offscreensurface festgelegt. Zusätzlich wird der Speicherort explizit in den Systemspeicher verlagert. Dies ist nicht unbedingt notwendig und führt zu einem ganz erheblichen Geschwindigkeitsverlust. Dadurch stellen wir aber sicher, das genug Speicher zur Verfügung steht. Dennoch sei nochmals ausdrücklich gesagt, das der Backbuffer im Videospeicher besser aufgehoben wäre und die Anwendung eine deutlich höhere Performance hätte. ddsdBackbuffer.lWidth = Picture1.Width ddsdBackbuffer.lHeight = Picture1.Height
Der Backbuffer wird auf die Größe der Picturebox begrenzt. Es soll schließlich kein Speicher vergeudet werden. Ein zu kleiner Backbuffer wäre ebenfalls nicht gut. Außerdem müsste DirectX die unterschiedlichen Größen skalieren und dies würde sehr viel Rechenzeit beanspruchen. Set objDDBackbufferSurf = objDD.CreateSurface(ddsdBackbuffer)
Das Erstellen der Surface kennen wir ja schon. Das Clipper-Objekt: Nachdem die Surfaces eingerichtet sind, wird nun das Clipper-Objekt definiert. Der normale Gebrauch eines Clipper-Objekts ist es, die Grenzen einer Surface oder eines Fensters festzulegen. Der Sinn wird anhand eines Beispiels am besten deutlich. Wir wollen ein Sprite von links nach rechts über den Bildschirm bewegen. Natürlich soll der Sprite sanft in den Bildschirm bewegt werden und auch
Kapitel 1 • DirectDraw
57
wieder sanft aus dem Bildschirm verschwinden. Dazu ist es notwendig, Teile des Sprites außerhalb des definierten Bildschirmbereiches auszulagern. Dies würde zu einem Fehler führen, da die ausgelagerten Spritegrafiken in einen nicht reservierten Speicherbereich geschrieben würden. Durch das Clipper-Objekt weiß DirectDraw, welcher Teil des Sprites kopiert werden darf und welcher nicht. Das Clipper-Objekt wird im Regelfall in der gleichen Größe wie die Zielsurface erstellt. Somit ist der gesamte Bereich für den Bit Block Transfer erlaubt.
Ziel Surface Sprite normaler Blitterbereich außerhalb des normalen Blitterbereichs Bild 1.15: Blitterbereiche
Die Funktionsweise des Clipper-Objekts können Sie an einem weiteren Merkmal erkennen. Vergleichen Sie die beiden Anwendungen Blitting und Tranzparenz. Blitting arbeitet ohne Clipper. Wenn Sie nun irgendein Windowsfenster nehmen und über das Blittingfenster schieben, so wird das Blittingfenster durch das Windowsfenster scheinen. Dies ist natürlich ein ungewünschter Effekt. Wenn Sie das Clipper-Objekt nutzen, tritt dieser Effekt nicht mehr auf. Kommen wir nun zur Einbindung des Clipper-Objekts in die DD-Anwendung. Set objDDClip = objDD.CreateClipper(0)
Die CreateClipper() Methode erzeugt ein Clipper-Objekt. objDDClip.SetHWnd Picture1.hWnd
Verbindet die Picturebox, in der die Grafik dargestellt werden soll, mit dem Clipper-Objekt. objDDScreenSurf.SetClipper objDDClip
Die primäre Surface wird mit dem Clipper-Objekt verbunden.
58
Sprites durch Transparenz
Jetzt ist es an der Zeit, die RECT-Strukturen zu bestimmen. Wie zum Anfang dieses Abschnitts bereits erwähnt, sind insgesamt drei RECT-Strukturen zu bestimmen. Da wäre einmal die RECT-Struktur des Hintergrundbildes. Da wir immer den gesamten Hintergrund sehen möchten, können wir die gesamte Größe des Hintergrundes festlegen. Dies tun wir mit folgenden Anweisungen: rBackground.Bottom = ddsdBackground.lHeight rBackground.Right = ddsdBackground.lWidth
Es folgt die RECT-Struktur des Sprites. Auch hier wollen wir das ganze Sprite sehen. Somit definieren wir: rSprite.Bottom = ddsdSprite.lHeight rSprite.Right = ddsdSprite.lWidth
Da wir Hintergrund und Sprite im Backbuffer zusammenführen und der Backbuffer die gleiche Größe wie das Hintergrundbild hat, wird auch hier die gesamte Größe definiert. rBackbuffer.Bottom = ddsdBackbuffer.lHeight rBackbuffer.Right = ddsdBackbuffer.lWidth
An dieser Stelle sei schon einmal erwähnt, das wir später noch weitere RECTStrukturen benötigen. Diese sind in Ihrer Position aber variabel und werden auf lokaler Ebene definiert. Schritt 4: Erstellen des Farbschlüssels Um den Hintergrund des Sprites transparent erscheinen zu lassen, ist es notwendig, diesen durch einen Farbschlüssel zu kennzeichnen. Dieser Farbschlüssel ist definiert durch eine Variable vom Typ DDCOLORKEY. Der Farbschlüssel bezieht sich nicht nur auf eine Farbe, sondern definiert einen Farbbereich. Der Aufbau der Variable DDCOLORKEY ist wie folgt: Type COLORKEY high As Long low As Long End Type
Die Einbindung in die Anwendung gestaltet sich recht einfach. Zuerst wird eine Variable als DDCOLORKEY definiert. Dim Colorkey As DDCOLORKEY
Anschließend wird der Farbbereich definiert. Colorkey.low = 0 Colorkey.high = 0
Kapitel 1 • DirectDraw
59
Somit ist die transparente Farbe als Schwarz definiert. Es fehlt noch die Zuweisung an die richtige Surface. In diesem Fall ist das die Spirtesurface. objDDSpriteSurf.SetColorkey DDCKEY_SRCBLT, Colorkey
DDCKEY_SRCBLT besagt, dass es sich um einen Farbschlüssel für eine Quellsurface handelt. Ebenso wird festgelegt, das es sich um Blitter-Aktionen handelt. Die schwarze Hintergrundfarbe der Sprite Surface wird bei allen Blitter-Aktionen nicht kopiert. Sie wird einfach ignoriert. Schritt 5: Blit Der Blit-Vorgang ist eigentlich ganz einfach. Von der Technik sieht es folgendermaßen aus. Die Grafik, die wir später auf dem Bildschirm sehen werden, wird vorher im Backbuffer zusammengesetzt. Hierzu könnten wir den gesamten Hintergrund und anschließend das Sprite in den Backbuffer kopieren und dann auf die primäre Surface. Diese Technik würde funktionieren, wäre aber eine sinnlose Vergeudung von Systemressourcen. Eine wesentlich schnellere Methode ist es, nur die veränderten Grafikdaten der Backbuffersurface zu bearbeiten. Wenn man nun überlegt, welche Einflüsse den Backbuffer verändern können, kann man sehr schnell eine Lösung finden. Zum einen wäre da der Hintergrund. Dieser wird in den Backbuffer kopiert. Dieser wird sich im Laufe der Anwendung aber nicht mehr ändern. Somit bleibt nur noch das Sprite. Das Sprite bewegt sich über den Bildschirm und kopiert somit immer wieder neue Daten in den Backbuffer. Da das Sprite aber nur einmal erscheinen soll, müssen die alten Grafikdaten korrigiert werden. Lange Rede kurzer Sinn – fangen wir an. 1. Wiederherstellen des Backbuffers Backbuffer und Hintergrund haben genau die gleichen Dimensionen. Das erleichtert die Arbeit ungemein. Wir bestimmen die alte Position des Sprites und eine temporäre RECT-Struktur mit den Maßen der Sprite Surface. Dann schneiden wir diesen Bereich aus der Hintergrundsurface aus und kopieren Ihn in den Backbuffer. Somit ist der Hintergrund wieder hergestellt. Damit dies noch etwas schneller geht, nutzen wir die Methode BltFast(). Dim rClean As RECT rClean.Left = lastX rClean.Top = lastY rClean.Right = lastX + ddsdSprite.lWidth rClean.Bottom = lastY + ddsdSprite.lHeight Call objDDBackbufferSurf.BltFast(lastX, lastY, _ objDDBackgroundSurf, rClean, DDBLTFAST_WAIT)
2. Kopieren des Sprites an die neue Position
60
Sprites durch Transparenz
Wir bestimmen die neue Position des Sprites. Anschließend definieren wir eine temporäre RECT-Struktur mit den Maßen der Spritesurface. Abschließend wird die Spritesurface an die neue Position in die Backbuffersurface kopiert. Hierzu verwenden wir nicht die BltFast()-Methode, sondern die Blt()Methode. Die BltFast()-Methode können wir nicht verwenden, da wir mit dem Sprite oder Teilen des Sprites in den Clipperbereich geraten könnten. Bei der Blt()-Methode ist das Flag DDBLT_KEYSRC zu beachten. Dieses Flag besagt, dass auf die Quellsurface der Farbschlüssel anzuwenden ist. Dim rtemp As RECT rtemp.Left = x rtemp.Top = y rtemp.Right = x + ddsdSprite.lWidth rtemp.Bottom = y + ddsdSprite.lHeight objDDBackbufferSurf.Blt rtemp, objDDSpriteSurf, rSprite, _ DDBLT_KEYSRC Or DDBLT_WAIT
3. Den erstellten Backbuffer auf die primäre Surface kopieren Dieser Teil ist identisch mit dem Blit-Vorgang aus dem Kapitel Blitting. Dim rPrim As RECT Call objDX.GetWindowRect(Picture1.hWnd, rPrim) Call objDDScreenSurf.Blt(rPrim, objDDBackbufferSurf, _ rBackbuffer, DDBLT_WAIT)
Beispiel (Sprites durch Transparenz) Dieses Beispiel beginnt mit einem kleinen Auswahlfenster. Hier werden Sie gefragt, ob Sie den Backbuffer in den Systemspeicher oder in den Videospeicher legen wollen. Probieren Sie beides einmal aus. Sie werden sehen, das der Videospeicher wesentlich schneller ist. Den Backbuffer in den Videospeicher zu legen ist nicht immer möglich; da wir hier aber sehr kleine Grafikdaten verwenden, kommt es zu keinen Problemen. Betrachten Sie das Bildschirmfoto für dieses Beispiel. Ihnen wird sicherlich die kleine Biene auffallen. Diese Biene ist unser Sprite. Im Deklarationsabschnitt fallen natürlich die vier Surfaces auf. Im Gegensatz zu dem Beispiel Blitting benötigen wir diesmal zwei Surfaces mehr. Zum einen ist das die Backbuffersurface und zum anderen die Sprite Surface. Dim Dim Dim Dim Dim Dim Dim Dim
objDX As New DirectX7 objDD As DirectDraw7 objDDBackgroundSurf As DirectDrawSurface7 objDDScreenSurf As DirectDrawSurface7 objDDSpriteSurf As DirectDrawSurface7 objDDBackbufferSurf As DirectDrawSurface7 ddsdBackground As DDSURFACEDESC2 ddsdScreen As DDSURFACEDESC2
Kapitel 1 • DirectDraw
Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim
61
ddsdSprite As DDSURFACEDESC2 ddsdBackbuffer As DDSURFACEDESC2 rBackground As RECT rScreen As RECT rSprite As RECT rBackbuffer As RECT lastX As Single lastY As Single objDDClip As DirectDrawClipper MoveX As Single GameLoop As Boolean Richtung As Boolean
Bild 1.16: Hintergrund mit einem nicht animierten Sprite
In dem Form_Load-Ereignis verzweigen wir in die Init()-Routine und anschließend in die Game()-Routine. Die Init erledigt wieder einmal die meiste Arbeit. Bevor es in die Game()-Routine geht, wird noch eine Indexvariable gesetzt, welche der Game()-Routine das Arbeiten erlaubt.
62
Sprites durch Transparenz
Private Sub Form_Load() Init GameLoop = True game End Sub Private Sub Init() Me.Show Set objDD = objDX.DirectDrawCreate("") Call objDD.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL) 'Surface 1 erzeugen (Bildschirm) ddsdScreen.lFlags = DDSD_CAPS ddsdScreen.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Set objDDScreenSurf = objDD.CreateSurface(ddsdScreen) ' Surface 2 erzeugen (Hintergrund) ddsdBackground.lFlags = DDSD_CAPS Or DDSD_WIDTH Or _ DDSD_HEIGHT ddsdBackground.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN ddsdBackground.lWidth = Picture1.Width ddsdBackground.lHeight = Picture1.Height Set objDDBackgroundSurf = _ objDD.CreateSurfaceFromFile(App.Path & _ "\UsingTransparancy.bmp", ddsdBackground) ' Surface 3 erzeugen (Sprite) ddsdSprite.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ddsdSprite.lWidth = 64 ddsdSprite.lHeight = 81 ddsdSprite.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Set objDDSpriteSurf = objDD.CreateSurfaceFromFile _ (App.Path & "\Biene.bmp", ddsdSprite) ' Surface 4 erzeugen (Backbuffer) ddsdBackbuffer.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or _ DDSD_WIDTH
Jetzt macht sich die Auswahl des Speicherortes beim Login bemerkbar. Systemspeicher oder Videospeicher? Das ist hier die Frage. If Form2.Option1.Value = True Then ddsdBackbuffer.ddsCaps.lCaps = _ DDSCAPS_OFFSCREENPLAIN Or DDSCAPS_SYSTEMMEMORY Else ddsdBackbuffer.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN End If ddsdBackbuffer.lWidth = Picture1.Width ddsdBackbuffer.lHeight = Picture1.Height Set objDDBackbufferSurf = _ objDD.CreateSurface(ddsdBackbuffer) ' Clipper Objekt erzeugen
Kapitel 1 • DirectDraw
63
Set objDDClip = objDD.CreateClipper(0) objDDClip.SetHWnd Picture1.hWnd objDDScreenSurf.SetClipper objDDClip ' RectStrukturen rBackground.Bottom = ddsdBackground.lHeight rBackground.Right = ddsdBackground.lWidth rSprite.Bottom = ddsdSprite.lHeight rSprite.Right = ddsdSprite.lWidth rBackbuffer.Bottom = ddsdBackbuffer.lHeight rBackbuffer.Right = ddsdBackbuffer.lWidth
Der Farbschlüssel filtert die Farbe Schwarz aus der Spritegrafik heraus. Somit wird der Hintergrund des Sprites unsichtbar, da er bei den Blitteraktionen ignoriert wird. Die RGB-Funktion gibt uns einen Wert vom Typ Long zurück. So wird er von der DDCOLORKEY-Struktur verlangt. ' Farbschlüssel definieren Dim Colorkey As DDCOLORKEY Colorkey.low = RGB(0, 0, 0) Colorkey.high = RGB(0, 0, 0) objDDSpriteSurf.SetColorkey DDCKEY_SRCBLT, Colorkey ' Kopieren des Hintergrundbildes in den Backbuffer Call objDDBackbufferSurf.Blt(rBackbuffer, _ objDDBackgroundSurf, rBackground, DDBLT_WAIT) End Sub
Die Sub game() sorgt für die Bewegung des Sprites. Hier läuft eine Do...LoopSchleife. Wichtig ist die Anweisung DoEvents. Somit kann das Betriebssystem neben dieser Schleife auch noch andere Aufgaben übernehmen, z.B. auf einen Mausklick reagieren. Private Sub game() Do While GameLoop = True If Richtung = True Then MoveX = MoveX + 2 Else MoveX = MoveX – 2 End If If MoveX > Picture1.ScaleWidth – ddsdSprite.lWidth Then _ Richtung = False If MoveX < 3 Then Richtung = True Blt MoveX, 200 DoEvents Loop If GameLoop = False Then End End Sub
64
Sprites durch Transparenz
Jetzt kommt es zur eigentlichen Blitteraktion. Dies funktioniert immer nach dem gleichen Prinzip: den Hintergrund an der Stelle, wo das Sprite verschwinden soll, restaurieren. Anschließend das Sprite an die neue Stelle in den Backbuffer kopieren. Zum Abschluss den neu erstellten Backbuffer auf die sichtbare primäre Surface blitten. Private Sub Blt(ByVal X As Single, ByVal Y As Single)
Hintergrund restaurieren! If lastX <> 0 Then Dim rClean As RECT rClean.Left = lastX rClean.Top = lastY rClean.Right = lastX + ddsdSprite.lWidth rClean.Bottom = lastY + ddsdSprite.lHeight Call objDDBackbufferSurf.BltFast(lastX, lastY, _ objDDBackgroundSurf, rClean, DDBLTFAST_WAIT) End If
Sprite an die neue Position kopieren! Dim rTemp As RECT rTemp.Left = X rTemp.Top = Y rTemp.Right = X + ddsdSprite.lWidth rTemp.Bottom = Y + ddsdSprite.lHeight objDDBackbufferSurf.Blt rTemp, objDDSpriteSurf, rSprite, _ DDBLT_KEYSRC Or DDBLT_WAIT lastX = X lastY = Y Call objDX.GetWindowRect(Picture1.hWnd, rScreen)
Neu erstellten Backbuffer in die primäre Surface kopieren! Call objDDScreenSurf.Blt(rScreen, objDDBackbufferSurf, _ rBackbuffer, DDBLT_WAIT) End Sub
Es bleiben noch zwei Subroutinen übrig. Die müssen eigentlich auch nicht erklärt werden. Sie dienen legendlich als Möglichkeit das Programm zu beenden. Das MausDown-Ereignis wäre nicht möglich, wenn die DoEvents-Anweisung in der game()-Routine fehlen würde. Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As _ Integer) GameLoop = False End Sub
Kapitel 1 • DirectDraw
65
Private Sub Picture1_MouseDown(Button As Integer, Shift As _ Integer, X As Single, Y As Single) GameLoop = False End Sub
1.4
Fullscreen Full Screen Mode bedeutet, dass die Anwendung nicht mehr in einem Windowsfenster ausgeführt wird, sondern exklusiv auf einer eigenen Oberfläche. Die Anwendungen unterscheiden sich im Wesentlichen kaum von einer normalen Windows-Anwendung. Dieses Kapitel baut auf dem Kapitel »Sprites durch Transparenz« auf und zeigt nur die Änderungen die Sie durchführen müssen. Die neuen Methoden werden hauptsächlich dafür verwendet, um einen exklusiven Zugriff auf die Grafikkarte zu erhalten. Dieser Zugriff ist bei einer FullscreenAnwendung erforderlich. Da wir uns die exklusiven Rechte der Grafikkarte sichern, steht der Anwendung eine größere Performance zur Verfügung. Die Performancesteigerung wird nicht unbedingt sichtbar, da im Regelfall die Flip()Methode mit dem Zeilenaufbau des Monitors synchronisiert wird. Die Flip()Methode ersetzt die Blt()-Methode. Alternativ kann man mit der Flip()-Methode auch unsynchron arbeiten. Dies kann aber zu Fehlern bei der Bilddarstellung führen. SetDisplayMode() Setzt einen gültigen Displaymode einer Grafikkarte. Der gewählte Mode muss von der Grafikkarte unterstützt werden. → DirectDraw7.RestoreDisplayMode, DirectDraw7.GetDisplayModesEnum, DirectDraw7.SetCooperativeLevel object.SetDisplayMode( w As Long, h As Long, bpp As Long, _ ref As Long, _ mode As CONST_DDSDMFLAGS) object
ein gültiges DirectDraw7-Objekt
w und h
Weite und Höhe des neuen Modes
bpp
Auflösung in Bits per Pixel
ref
Wiederholfrequenz. Dieser Wert kann auf 0 gesetzt werden, dann wird die voreingestellte Wiederholfrequenz der Garfikkarte verwendet.
mode
Eine Konstante aus der CONST_DDSDMFLAGS-Liste. Zur Zeit ist der einzig gültige Eintrag DDSDM_STANDARDVGAMODE.
GetAttachedSurface() Liest die Surface-Eigenschaften aus. object.GetAttachedSurface( caps As DDSCAPS2) As
DirectDrawSurface7
66
Fullscreen
GetAttachedSurface() object
ein gültiges DirectDrawSurface7-Objekt
caps
Eine Variable vom Typ DDSCAPS2, welche als Empfänger der SurfaceEigenschaften dient.
GetSurfaceDesc() Liest die Surface-Beschreibungen aus. object.GetSurfaceDesc(surface As DDSURFACEDESC2) object
ein gültiges DirectDrawSurface7-Objekt
Surface
Eine Variable vom Typ DDSURFACEDESC2, welche als Empfänger der Surface-Beschreibungen dient.
Flip() Wechselt von Backbuffer-Speicher zum Frontbuffer-Speicher object.Flip( ddS As DirectDrawSurface7, flags As CONST_DDFLIPFLAGS) object
ein gültiges DirectDrawSurface7-Objekt
dds
Dieser stellt die Verbindung zu einer beliebigen Surface aus der Flipping-Kette her. Die Defaulteinstellung ist Nothing. In diesem Fall würde DirectDraw in der Reihenfolge der einzelnen Kettenglieder die Surfaces flippen. Ist dieser Wert nicht Nothing, so flippt DirectDraw zu der angegeben Surface.
flags
eine Konstante aus der CONST_DDFLIPFLAGS-Konstantenliste
RestoreDisplyMode() Restauriert den Display Mode der primären Surface auf den Zustand, der vor dem Aufruf der Methode DirectDraw7.SetDisplayMode() herrschte. → DirectDraw7.SetDisplayMode, DirectDrawEnumModes, DirectDraw7.SetCooperativeLevel object.RestoreDisplayMode() object
ein gültiges DirectDraw7-Objekt
DrawText() Zeichnet Text auf eine Surface. object.DrawText(x As Long, y As Long, text As String, b As Boolean) object
ein gültiges DirectDrawSurface7-Objekt
x und y
Horizontale und vertikale Position auf der Surface
Kapitel 1 • DirectDraw
67
DrawText() text
der zu zeichnende Text
b
Boolean Wert, welcher definiert, ob der Text an den zugewiesenen xund y-Positionen oder an der aktuellen Cursorposition gezeichnet wird. Ist der Wert FALSE, werden die angegebenen x- und y-Koordinaten genommen.
Mode X DDSDM_STANDARDVGAMODE Mode 13, 320x200x8 DDSDM_DEFAULT Jeder andere Modus
Auch hierbei können wir die Änderungen in vier Schritte gliedern. Schritt 1: Setzen des Cooperative Level und des Display Mode Call objDD.SetCooperativeLevel(Me.hWnd, DDSCL_FULLSCREEN _ Or DDSCL_ALLOWMODEX Or DDSCL_EXCLUSIVE
Beim Cooperative Level fallen drei neue Flags auf. DDSCL_FULLSCREEN, DDSCL_ALLOWMODEX und DDSCL_EXCLUSIVE. Das DDSCL_FULLSCREEN-Flag legt fest, dass die primäre Surface alleine auf die Grafikoberfläche zugreift. Mit diesem Flag muss auch das DDSCL_EXCLUSIVE-Flag gesetzt werden. Dieses legt das alleinige Zugriffsrecht der primären Surface auf die Grafikoberfläche fest. DDSCL_ALLOWMODEX legt fest, dass die Bildschirmauflösung geändert werden darf. Dies entspricht den Richtlinien von Mode X. Nun wird der Display Mode gesetzt. objDD.SetDisplayMode 640, 480, 16, 0, DDSDM_DEFAULT
Die ersten beiden Parameter definieren die Breite und die Höhe des neuen Modus. Der dritte Parameter gibt die Auflösung in Bits per Pixel an. Der vierte Parameter bestimmt die Refresh Rate der Grafikkarte. Da dieser auf 0 gesetzt ist, wird die Defaulteinstellung aus dem Grafikkartentreiber übernommen. Der letzte Parameter setzt die Mode X-Einstellung. Schritt 2: Erstellen einer komplexen Surface Im vorherigen Kapitel »Sprites durch Transparenz« wurde der Backbuffer als Offscreen-Surface erstellt. Der Backbuffer wurde genutzt, um die Grafikdaten aus der Hintergrundsurface und der Spritesurface zu kombinieren und anschließend durch die Blt()-Methode auf die sichtbare primäre Surface zu blitten. Auch dies-
68
Fullscreen
mal wird ein Backbuffer benötigt, aber jetzt ist der Backbuffer ein Teil der primären Surface. Somit wird keine eigenständige Surface benötigt. Die Technik, um die kombinierten Grafikdaten von Hintergrund und Sprite sichtbar zu machen, hat sich geändert. Es wird nicht mehr die Blt()-Methode genutzt, sondern die Flip()Methode der primären Surface. Zur Flip()-Methode kommen wir etwas später. Fangen wir mit dem Erstellen der primären Surface an. Da die primäre Surface und der Backbuffer eine feste Einheit bilden, spricht man von einer komplexen Surface. Um eine komplexe Surface zu erstellen, werden eigentlich nur ein paar Flags gesetzt. ddsdScreen.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT
Hier wird der Zugriff auf die ddsCaps-Struktur sowie den Backbuffer-Zähler freigegeben. ddsdScreen.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Or _ DDSCAPS_FLIP Or DDSCAPS_COMPLEX
In der ddsCaps-Struktur legen wir fest: Die Surface soll die primäre Surface sein, die Surface soll die Flip-Eigenschaft besitzen und die Surface ist eine komplexe Surface. ddsdScreen.lBackbufferCount = 1
Wir wollen in der komplexen Surface einen Backbuffer einrichten. Set objDDScreenSurf = objDD.CreateSurface(ddsdScreen)
Die Surface wird erstellt. Da der Backbuffer keine eigenständige Surface ist, müssen wir die SurfaceBeschreibungen von der primären Surface zurücklesen. Dazu ist es notwendig eine Hilfsstruktur zu definieren. Dim caps As DDSCAPS2 caps.lCaps = DDSCAPS_BACKBUFFER
Der Variablentyp DDSCAPS2 nimmt die Definitionen aller Eigenschaften einer Surface auf. Diese Struktur wird als Backbuffer definiert. Jetzt können wir mit GetAttachedSurface() die genauen Strukturen des Backbuffers unserer komplexen Surface auslesen. Set ddsdBackbuffer =objDDScreen.GetAttachedSurface(caps)
Somit sind alle Eigenschaften und Beschreibungen des Backbuffers ordnungsgemäß übergeben worden.
Kapitel 1 • DirectDraw
69
Schritt 3: Surfaces einrichten Das Einrichten der Offscreensurfaces für die Hintergrundsurface sowie der Sprite-Surface ist im Wesentlichem gleich der Technik, wie Sie im Kapitel »Sprites durch Transparenz« beschrieben wurde. Der einzige Unterschied liegt darin, das die Hintergrundsurface mit den Beschreibungen der Backbuffersurface erstellt wird. Backbuffer.GetSurfaceDesc ddsdBackbuffer
Wir nutzen die GetSurfaceDesc()-Methode, um der Variablen ddsdBackbuffer alle Eigenschaften der Backbuffersurface zu übergeben. Die Variable ddsdBackbuffer ist vom Typ DDSURFACEDESC2. Anschließend werden die Strukturen der Hintergrundsurface festgelegt. ddsdHintergrund.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or _ DDSD_WIDTH ddsdHintergrund.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN ddsdHintergrund.lWidth = ddsdBackbuffer.lWidth ddsdHintergrund.lHeight = ddsdBackbuffer.lHeight Set objDDHintergrundSurf = objDD.CreateSurfaceFromFile _ ("Hintergrund.bmp",ddsdHintergrund)
Hier gibt es eigentlich nichts Neues zu berichten. Schritt 4: Flipping statt Blitting objDDScreenSruf.Flip Nothing, DDFLIP_WAIT
Die Flip()-Methode enthält zwei Parameter. Der erste Parameter ist dds. Dieser stellt die Verbindung zu einer beliebigen Suface aus der Flipping-Kette her. Die Defaulteinstellung ist Nothing. In diesem Fall würde DirectDraw in der Reihenfolge der einzelnen Kettenglieder die Surfaces flippen. Ist dieser Wert nicht Nothing, so flippt DirectDraw zu der angegeben Surface. Der zweite Parameter ist der obligatorische Flag-Parameter. Hier wird eine Konstante aus der CONST_ DDFLIPFLAGS-Liste angegeben. In unserm Beispiel wird das Flag DDFLIP_ WAIT gesetzt. Hierdurch wird DirectDraw aufgefordert, den aktuellen Flipp-Vorgang abzuwarten, bevor mit einem neuen begonnen wird. Achten Sie darauf, dass nach Beendigung der Anwendung der Display Mode wieder zurückgestellt wird. Dies erreichen Sie mit der RestoreDisplayMode()Methode. Anschließend noch den CooperativeLevel auf Normalzustand setzen, und alles ist beim Alten. Call objDD.RestoreDisplayModeCall objDD.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL)
70
Fullscreen
Beispiel (Fullscreen) In diesem Beispiel werden ein paar Änderungen deutlich. Diese Änderungen beziehen sich hauptsächlich auf die Darstellungsart der primären Surface. In dem Kapitel »Sprites durch Transparenz« haben wir die Hintergrundgrafik einmal in den Backbuffer kopiert. Dies haben wir direkt in der Subroutine Init() getan. In der Subroutine Blt() wurde das Sprite bewegt. Um eine saubere Darstellung zu erreichen, haben wir folgendes Prinzip angewendet: •
Hintergrund restaurieren
•
Es wurde nur der Teil des Hintergrunds restauriert, welcher von dem Sprite verdeckt war. Dadurch brauchten wir nur einen kleinen Teil des Hintergrunds in den Backbuffer blitten und erreichen somit einen Performancegewinn.
•
Sprite an die neuen Koordinaten zeichnen
•
Den neu erstellten Backbuffer auf die primäre Surface blitten
Von diesem Prinzip weichen wir diesmal ab. Der Teil, in dem der Hintergrund restauriert wird, verwendet diesmal nicht einen kleinen Ausschnitt, sondern bezieht sich auf den gesamten Backbuffer. Es scheint unlogisch den gesamten Backbuffer zu restaurieren, wenn doch nur ein kleiner Teil verändert werden muss. Führt dies nicht zu Performanceverlust? Diese Frage ist mit Ja und Nein zu beantworten. In unserem Beispiel macht sich das Restaurieren des gesamten Backbuffers negativ bemerkbar. Dennoch haben wir diese Technik bewusst ausgewählt. Nehmen wir einmal an, Sie wollen nicht nur ein Sprite bewegen, sondern 30, 50 oder mehr. Um den Hintergrund zu restaurieren, würde es nach alter Technik bedeuten, dass sie für jedes Sprite die Blt()- bzw. BltFast()-Methode aufrufen müssten. Anschließend würden Sie genauso oft diese Methode aufrufen, um das Sprite an die neuen Koordinaten zu blitten. Ich denke, dass Sie das Problem erkannt haben. Viele kleine Blitteraktionen sind eben nicht schneller, als eine etwas komplexere. An dem Bildschirmfoto können Sie erkennen, das wir die normalen Fensterelemente nicht mehr finden. In der Fullscreenanwendung wird eben die ganze Bildschirmgröße genutzt. So sieht die neue Blt()-Sub aus: Private Sub Blt(ByVal X As Single, ByVal Y As Single)
Hier wird der Hintergrund restauriert. Der gesamte Backbuffer wird mit einem Befehlsaufruf wieder hergestellt. Call objDDBackbufferSurf.BltFast(0, 0, objDDBackgroundSurf, _ rBackground, DDBLTFAST_WAIT)
Dieser Abschnitt zeigt Ihnen eine Technik, um die Frames per Second zu zählen. Ebenso sehen Sie die DrawText()-Methode. Diese muss nicht genauer erklärt werden. Dieser Abschnitt gehört nicht zur eigentlichen Technik, ist aber recht hilfreich.
Kapitel 1 • DirectDraw
71
Bild 1.17: Fullscreen-Bildschirmfoto If Zeit = 30 Then If tLast <> 0 Then fps = 30 / (Timer – tLast) tLast = Timer Zeit = 0 End If Zeit = Zeit + 1 Call objDDBackbufferSurf.DrawText _ (10, 10, "640x480x16 Frames per Second " + Format$(fps, _ "#.0"), False) Call objDDBackbufferSurf.DrawText _ (500, 10, "Maus Klick für Ende", False) Call objDDBackbufferSurf.DrawText _ (550, 440, "Full Screen", False)
Nachdem wir den Informationstext auf den Backbuffer gezeichnet haben, können wir nun das Sprite an die neuen Koordinaten blitten. objDDBackbufferSurf.BltFast X, 200, objDDSpriteSurf, rSprite, _ DDBLTFAST_SRCCOLORKEY Or DDBLTFAST_WAIT
Flipping statt Blitting. Wie bereits erklärt, wird die komplexe Surface einfach einmal gedreht. Wirklich einfach, oder? objDDScreenSurf.Flip Nothing, DDFLIP_WAIT End Sub
72
1.5
Fullscreen und Spriteanimation
Fullscreen und Spriteanimation In der Theorie ist die Spriteanimation wirklich simpel. In der Praxis bedarf es bei sehr komplexen Anwendungen etwas Organisationstalent. Bleiben wir bei der Theorie. Schauen wir uns einmal an, wie die Spritegrafiken bisher ausgesehen haben.
Bild 1.18: Nicht animiertes Sprite
Bisher hatten wir eine Bitmap, auf der ein einzelnes Sprite dargestellt wurde. Somit konnten wir die Sprite-RECT-Struktur immer in der gesamten Größe der Spritebitmap erstellen. Die Darstellung solch einen Sprites ist natürlich nicht animiert. Schauen wir uns an, was wir für ein animiertes Sprite benötigen. In Bild 1.19 haben wir eine Bitmap, auf der viele Sprites dargestellt werden. Sinnvollerweise bilden die Einzelbilder eine Animation (vergleichen Sie das mit einem Daumenkino). In dem Beispiel könnte man sagen, dass das Männchen mit dem rechten Arm winkt. Legen Sie über die gesamte Grafik ein Raster von 3 x 2 Feldern. Diese Felder sind nichts anderes als die RECT-Strukturen, welche Sie zum blitten verwenden müssen. Sie nehmen also immer den richtigen Ausschnitt der Gesamtgrafik und blitten diesen an die richtige Stelle der Backbuffersurface. Das ist das ganze Geheimnis der Spriteanimation. Für die programmtechnische Umsetzung betrachten wir zuerst, wie die richtigen RECT-Strukturen ermittelt werden. Bekannt ist die Anzahl der Rows sowie die Anzahl der Cols. Damit ist die Spritebreite und Spritehöhe gleich: SpriteBreite = ddsdSprite.lWidth / Anzahl Col SpriteHöhe = ddsdSprite.lHeight / Anzahl Row
Jetzt ist die richtige Navigation in der großen Sprite Surface gefragt.
Kapitel 1 • DirectDraw
73
Col 0
Col 1
Col 2
Row 0
Row 1
Bild 1.19: Animiertes Sprite
Als Beispiel nehmen wir das winkende Männlein mit einem Raster von 3 x 2 Feldern. Ein Algorithmus, um alle Sprites der Reihe nach darzustellen, könnte so aussehen. Dim SpriteRect as RECT For Row = 0 to 1 For Col = 0 to 2 SpriteRect.Left = Col * SpriteBreite SpriteRect.Top = Row * SpriteHöhe SpriteRect.Right = Col * SpriteBreite + SpriteBreite SpriteRect.Bottom = Row * SpriteHöhe + SpriteHöhe Next Col Next Row
Mit dieser kleinen Routine wird das Sprite in einer flüssigen Bewegung einmal durchlaufen. Schauen Sie sich das Beispiel zur Spriteanimation an. Beispiel (Spriteanimation) Diese Beispiel baut auf dem Beispiel Full Screen auf. Im Grunde sind diese beiden Demos identisch. Der einzige Unterschied liegt in der Spritedarstellung. Diesmal ist das Sprite animiert und sieht so aus:
74
Fullscreen und Spriteanimation
Bild 1.20: Animierte Biene zur Darstellung eines animierten Sprites
Um die animierte Biene darzustellen, wurden folgende Änderungen und Ergänzungen gemacht. Die Definition der Sprite-RECT-Struktur wurde aus der Init()Sub herausgenommen und in die Blt()-Sub verlegt. Diese sieht jetzt so aus: Private Sub Blt(ByVal X As Single, ByVal Y As Single) Call objDDBackbufferSurf.BltFast(0, 0, objDDBackgroundSurf, _ rBackground, DDBLTFAST_WAIT) If Zeit = 30 Then If tLast <> 0 Then fps = 30 / (Timer – tLast) tLast = Timer Zeit = 0 End If Zeit = Zeit + 1 Call objDDBackbufferSurf.DrawText _ (10, 10, "640x480x16 Frames per Second " + Format$(fps, #.0"),_ False) Call objDDBackbufferSurf.DrawText _ (500, 10, "Maus Klick für Ende", False) Call objDDBackbufferSurf.DrawText _ (520, 440, "Sprite Animation", False)
Erst hier finden die Änderungen statt. Da das Sprite der Reihe nach animiert werden soll, muss die richtige RECT-Struktur definiert werden. Diese ist abhängig von den aktuellen Col- und Row-Werten. Die Col- und Row-Werte werden in der game()-Sub festgelegt. 'Den richtigen Spriteausschnitt wählen rSprite.Left = Col * SpriteBreite rSprite.Top = Row * SpriteHöhe rSprite.Right = Col * SpriteBreite + SpriteBreite rSprite.Bottom = Row * SpriteHöhe + SpriteHöhe objDDBackbufferSurf.BltFast X, 200, objDDSpriteSurf, _ rSprite, DDBLTFAST_SRCCOLORKEY Or DDBLTFAST_WAIT objDDScreenSurf.Flip Nothing, DDFLIP_WAIT End Sub
In der game()-Sub werden die Col- und Row-Werte festgelegt. Dies sieht so aus: Private Sub game() Do While GameLoop = True If Richtung = True Then MoveX = MoveX + 2
Kapitel 1 • DirectDraw
75
Befindet sich das Sprite in der Bewegung von links nach rechts, so soll die obere Spritereihe der Spritebitmap genommen werden. Dazu wird der Row-Wert auf Null festgelegt. Row = 0 Else
Die zweite Spritereihe wird genommen, wenn sich das Sprite in der Bewegung von rechts nach links befindet. Einfach den Row-Wert mit 1 definieren. Row = 1 MoveX = MoveX – 2 End If
Hier werden die Sprites immer schön der Reihe nach durchgeschaltet. Ist das letzte Sprite der Reihe erreicht, fängt alles wieder von vorne an. Welches Sprite an der Reihe ist, bestimmt der Col-Wert. Col = Col + 1 If Col > 3 Then Col = 0 If MoveX > 637 – SpriteBreite Then Richtung = False If MoveX < 3 Then Richtung = True Blt MoveX, 200 DoEvents Loop If GameLoop = False Then End End Sub
1.6
Hintergrund-Scrolling Hintergrund- (Background-) Scrolling bedeutet, dass Sie eine Hintergrundgrafik an dem sichtbaren Bereich der primären Surface vorbeilaufen lassen. Zu diesem Zweck ist die Hintergrundgrafik größer als die primäre Surface. Betrachten wir uns dieses mit einem Beispiel. Unsere Hintergrundgrafik ist ebenso hoch wie die primäre Surface. Sie ist aber doppelt so breit. Unser Ziel ist es, die Hintergrundgrafik einmal von links nach rechts darzustellen. Somit schneiden wir aus der Hintergrundgrafik immer den Teil aus, welchen wir gerade betrachten wollen (s. Bild 1.21). Den richtigen Teil der Hintergrundsurface definieren wir mit der HintergrundRECT-Struktur. Nachdem die RECT-Struktur festgelegt wurde, blitten wir diesen Bereich in den Backbuffer. Anschließend würden die Sprites geblittet. Wenn alles fertig ist wird das ganze per Blt()-Methode oder Flip()-Methode sichtbar gemacht. Hier ein kleiner Algorythmus zur Auswahl des richtigen RECT-Bereiches.
76
Hintergrund-Scrolling
sichtbarer Bereich der primären Surface Hintergrundgrafik
Bild 1.21: Hintergrund-Scrolling For i = 0 to Hintergrundbreite HintergrundRECT.Left = i HintergrundRECT.Top = 0 HintergrundRECT.Right = i + PrimäreSurface.Width HintergrundRECT.Bottom = PrimäreSurface.Height Next i
Die Hintergrund-RECT-Struktur wird nun in die Blt()-Methode eingesetzt. Unser Beispiel Background Scrolling zeigt das noch etwas genauer. Beispiel (Hintergrund-Scrolling) Dieses Beispiel baut auf dem Beispiel Fullscreen und Spriteanimation auf. In der Init()-Sub haben wir die Background Surface in der Breite verdoppelt. Dies ist kein Problem, da DirectDraw die Grafikdaten automatisch auf die passende Größe dehnt. Private Sub Init() . . . ddsdBackground.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ddsdBackground.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Or _ DDSCAPS_SYSTEMMEMORY
Bisher waren die Backbuffersurface und die Hintergrundsurface immer gleich groß. Etwas anderes wäre auch nicht sinnvoll gewesen, da wir immer den gesamten Hintergrund darstellen wollten. Jetzt zeigen wir das Prinzip des Background
Kapitel 1 • DirectDraw
77
Scrollings. Hierzu benötigen wir eine größere Hintergrundsurface. In unserem Beispiel erzeugen wir eine übergroße Hintergrundsurface. Dazu multiplizieren wir den Parameter lWidth mit dem Faktor 2. Somit haben wir einen Hintergrund erzeugt, welcher doppelt so breit ist wie die Backbuffersurface. Die Grafikdaten (für die Hintergrundsurface) werden von DirectDraw automatisch angepasst. Da die Hintergrundsurface eine statische Surface ist, werden wir nicht einmal Performanceverluste hinnehmen müssen. Die Hintergrundsurface bezeichnen wir als statische Surface, da sie nicht unmittelbar für den Bildschirmaufbau verwendet wird. Aus ihr werden lediglich Bildbereiche ausgeschnitten und auf die Backbuffersurface kopiert. So muss DirectDraw den Grafikinhalt der Hintergrundsurface nicht immer neu erstellen und es entfällt das Performance verschlingende Dehnen der Grafikdaten. ddsdBackground.lWidth = ddsdBackbuffer.lWidth * 2 ddsdBackground.lHeight = ddsdBackbuffer.lHeight Set objDDBackgroundSurf = objDD.CreateSurfaceFromFile _ (App.Path & "\Backgroundscrolling.bmp ", ddsdBackground) . . . ' RectStrukturen rBackground.Bottom = ddsdBackground.lHeight
Da wir vorher die Breite des Backgrounds verdoppelt haben, legen wir jetzt die neue Breite des sichtbaren Backgrounds fest. Sichtbar natürlich nur, nachdem wir den Background in den Backbuffer geblittet und diesen wiederum in die primäre Surface geflippt haben. rBackground.Right = ddsdBackground.lWidth / 2 . . . End Sub
Die nächsten Änderungen finden wir in der game()-Sub. Dort legen wir die gültige RECT-Struktur für den Hintergrund fest. Das sieht so aus: Private Sub game() Do While GameLoop = True If Richtung = True Then MoveX = MoveX + 2 Row = 0
Befinden wir uns in der Bewegung von links nach rechts, so addieren wir auf die Ränder der RECT-Struktur jeweils zwei Pixel auf. Somit verschiebt sich das Rechteck permanent. Obwohl wir uns in der Bewegung von links nach rechts befinden, wird der Hintergrund von rechts nach links scrollen.
78
Spritekollision
rBackground.Left = rBackground.Left + 2 rBackground.Right = rBackground.Right + 2 Else Row = 1 MoveX = MoveX – 2
Jetzt befinden wir uns in der Bewegung von rechts nach links. Der Hintergrund soll wiederum entgegengesetzt scrollen. Somit ziehen wir bei jedem Durchlauf zwei Pixel ab. Die RECT-Struktur ist wieder neu definiert und steht für die nächste Blitteraktion bereit. rBackground.Left = rBackground.Left – 2 rBackground.Right = rBackground.Right – 2 End If Col = Col + 1 If Col > 3 Then Col = 0 If MoveX > 637 – SpriteBreite Then Richtung = False If MoveX < 3 Then Richtung = True Blt MoveX, 200 DoEvents Loop If GameLoop = False Then End End Sub
1.7
Spritekollision Das Erkennen einer Kollision zwischen zwei Sprites ist ein komplexes Thema. Es gibt viele unterschiedliche Arten um eine Kollision zu registrieren. Welche Technik zum Einsatz kommt, hängt im Wesentlichen von der Art der Applikation ab. Die verschiedenen Möglichkeiten, eine Kollision zu erkennen, kann man in zwei Kategorien einteilen. Diese Einteilung ist zum einen die grobe Kollisionskontrolle und zum anderen die feine Kollisionskontrolle. Die feine Kollisionskontrolle überprüft die einzelnen Pixel der Sprites. Hierfür müssen wir direkt auf den Speicher der Surfaces zugreifen. Die folgenden Methoden werden für den direkten Zugriff auf den Surfacespeicher benötigt. Diese Speichermanipulationen sind ein heikles Thema, denn Fehler werden erbarmungslos bestraft. Dennoch sollte diese Kapitel Ihnen helfen, den Surfacespeicher sicher in den Griff zu bekommen. Lock() Erstellt einen Zeiger auf den Surface-Speicher. Gleichzeitig wird der Speicherbereich geschützt. object.Lock(r As RECT, desc As DDSURFACEDESC2, _ flags As CONST_DDLOCKFLAGS, hnd As Long)
Kapitel 1 • DirectDraw
79
Lock() object
ein gültiges DirectDrawSurface7-Objekt
r
Eine RECT-Struktur, welche den Speicherbereich beschreibt. Wird eine leere RECT-Struktur übergeben, so wird die gesamte Surface geschützt.
desc
Eine Varibale vom Typ DDSURFACEDESC2, welche mit den relevanten Details der Surface gefüllt wird.
flags
Eine Konstante aus der CONST_DDLOCKFLAGS-Liste; sie beschreibt, in welcher Art der Speicherbereich gesperrt werden soll.
hnd
Wird zur Zeit nicht genutzt. Muss auf 0 gesetzt werden.
Unlock() Hebt die Lock() Methode wieder auf. Sie signalisiert DirectDraw, das die Surfacemanipulationen abgeschlossen sind. object.Unlock(r As RECT) object
ein gültiges DirectDrawSurface7-Objekt
r
Eine RECT-Struktur, welche den Speicherbereich beschreibt. Dieser Parameter kann nur dann leer (Nothing) sein, wenn zuvor mit der Lock()-Methode die gesamte Surface geschützt wurde.
GetLockedArray() Erstellt einen Zeiger auf ein Array von geschützten Pixel nach dem Aufruf der Lock() Methode. object.GetLockedArray( array() As Byte) object
ein gültiges DirectDrawSurface7-Objekt
array()
Feld von geschützten Pixel in Byte
GetDisplayMode() Liest den aktuellen DisplayMode. → DirectDraw7.SetDisplayMode, DirectDraw7.RestoreDisplayMode, DirectDraw7.GetDisplayModesEnum object.GetDirect3D() As Direct3D7 object
ein gültiges DirectDraw7-Objekt
surface
Eine Variable vom Type DDSURFACEDESC2, welche die Beschreibungen des aktuellen Display-Modes aufnimmt.
80
Spritekollision
Die grobe Kollisionskontrolle beschränkt sich darauf, eine Überlappung zweier RECT-Strukturen zu erkennen. Diese Art ist mit Sicherheit die schnellste Technik. Sie birgt aber ein gewaltiges Problem. Dazu schauen wir uns folgende Grafik an:
Sprite 1 Sprite 2 Bild 1.22: Spites mit RECT-Struktur
Sprite 1 und Sprite 2 bewegen sich aufeinander zu. Im Laufe der Bewegung werden die beiden RECT-Strukturen aufeinander stoßen. Wenn sich die beiden RECT-Strukturen überlappen, hat eine Kollision stattgefunden.
Sprite 1 Sprite 2 Bild 1.23: Keine echte Kollision
Diese Annahme ist nur zum Teil richtig. Schauen Sie sich nochmals die beiden Sprites genau an. Sie werden feststellen, das die RECT-Strukturen wesentlich größer sind als die eigentlichen Sprites. Der gesamte Hintergrund wird bei der Darstellung auf dem Bildschirm für den Anwender unsichtbar sein. Dies haben wir in Kapitel »Sprites durch Transparenz« dargestellt. Der Computer würde eine
Kapitel 1 • DirectDraw
81
Kollision erkennen, obwohl der Kreis und das Dreieck noch nicht zusammengestoßen sind. Dazu vorherige Grafik. Analysieren wir das Problem. Was uns das Leben im Moment schwer macht ist, dass der Computer nur mit rechteckigen Dimensionen arbeiten kann. Alles was DirectDraw als nicht rechteckige Objekte darstellt, ist in Wirklichkeit eine normale RECT-Struktur. Um nun eine Kollision von Kreis und Dreieck zu registrieren müssen wir eine Möglichkeit finden, das eigentliche Objekt vom Hintergrund zu trennen. Anschließend können wir auf eine Überlappung der Objekte prüfen. Hier kommt die Maus ... äh, die Lösung. Als Grundlage zur Lösung nehmen wir den Colorkey, welcher für die jeweilige Sprite Surface definiert wurde. Dieser Colorkey trennt den Hintergrund vom eigentlichen Sprite. Jetzt legen wir fest, welches Sprite wir auf eine Kollision prüfen möchten. In unserem Fall wird das Sprite 1 sein. Dies ist wichtig, da wir programmtechnisch das zu überprüfende Sprite vor allen anderen Sprites in den Backbuffer kopieren müssen. Wir kopieren also Sprite 1 in den Backbuffer. Anschließend kopieren wir Sprite 2 in den Backbuffer. Sollte der Kreis oder ein Teil des Kreises von dem Dreieck im Backbuffer überlagert sein, können wir dieses anhand eines Mustervergleiches mit der Sprite-1-Surface feststellen. Schauen wir uns die Überlagerung einmal an.
Sprite 1 Sprite 2 Bild 1.24: Echte Kollision
Wie Sie sehen, wurde Sprite 1 von Sprite 2 überlagert. Wenn wir jetzt einen Mustervergleich der RECT-Struktur von Sprite 1 des Backbuffers mit der RECTStruktur von Sprite 1 der Sprite-1-Surface durchführen, werden wir feststellen, dass diese Muster nicht übereinstimmen. Siehe Grafik.
82
Spritekollision
RECT-Struktur von
RECT-Struktur von
Sprite 1 auf der
Sprite 1 auf der
Backbuffer Surface
Sprite 1 Surface
Bild 1.25: Echte Kollision
Sie können deutlich die Änderung der RECT-Struktur erkennen. Nun können wir einen Mustervergleich vornehmen. Der Mustervergleich: Beim Mustervergleich werden nur die Farbinformationen der Pixel innerhalb der beiden RECT-Strukturen verglichen. Hierbei ist die Farbtiefe der Surfaces zu beachten. Hauptsächlich werden drei Farbtiefen verwendet. 8 Bit für 256 Farben, 16 Bit für 65536 Farben und 24 Bit für 16777216 Farben. Die Farbtiefe ist insofern wichtig, da wir die Farbinformationen nur aus dem Speicherbereich lesen können. Um die Farbe für ein Surface-Pixel im 24 Bit Mode zu erhalten, müssen wir drei aufeinander folgende Bytes des Speicherbereiches lesen. Diese Bytes haben Werte im Bereich von 0 bis 255. Sie repräsentieren der Reihe nach den Blau-, Grün- und Rotanteil der Farbe. Hierbei spricht man auch von der RGBFarbe. Bei der RGB-Farbe werden die Farbanteile Rot, Grün und Blau angegeben. Im Speicher liegen diese Informationen jedoch gespiegelt vor. Als Blau-, Grünund Rot-Werte. Mit der folgenden Funktion sind Sie in der Lage, die Farbinformationen der drei unterschiedlichen Farbtiefen herauszulesen. Als Voraussetzungen wird angenommen, das wir eine Fullscreen-Anwendung (komplexe Surface) erstellt haben. Die notwendige DDSURFACEDESC2-Variable ist mit ddsdScreen bezeichnet. Die Farbe soll aus dem Backbuffer gelesen werden. Function GetColor( x, y) On Error GoTo fehler
Die GetDisplayMode()-Methode überträgt die notwendigen Daten in die Variable ddsdScreen. Anschließend können wir über ddpfPixelFormat.lGGBBitCount() die Farbtiefe entnehmen.
Kapitel 1 • DirectDraw
83
objDD.GetDisplayMode ddsdScreen Cobit = ddsdScreen.ddpfPixelFormat.lRGBBitCount If Cobit = 8 Then mp = 1 If Cobit = 16 Then mp = 2 If Cobit = 24 Then mp = 3 Dim pict1() As Byte
Die Lock()-Methode liefert uns den Zeiger auf den Speicherbereich der Surface. Hierbei verwenden wir eine RECT-Struktur, welche die gesamte Surface abdeckt. Diese RECT-Struktur ist mit rSurface bezeichnet. ddsdBackbuffer erstellt den Verweis auf den Backbuffer der komplexen Surface. Backbuffer.Lock rSurface, ddsdBackbuffer, DDLOCK_WAIT, 0
Mit der GetLockedArray()-Methode füllen wir das Array pict1() mit den Farbwerten als Byte. Surface.GetLockedArray pict1()
Der folgende Abschnitt liest die einzelnen Farbanteile aus dem Speicher und setzt Sie anschließend zu dem gewünschten Farbwert vom Typ Long zusammen. Je nach Farbtiefe müssen wir die Farbanteile selektiert auslesen. sx = x * mp sy = y If mp = 3 Then byte1 = pict1(sx, sy) byte2 = pict1(sx + 1, sy) byte3 = pict1(sx + 2, sy) ccolor = (byte3 * 65536) + (byte2 * 256) + (byte1 * 1) End If If mp = 2 Then byte1 = pict1(sx, sy) byte2 = pict1(sx + 1, sy) ccolor = (byte2 * 256) + (byte1 * 1) End If If mp = 1 Then byte1 = pict1(sx, sy) ccolor = (byte1 * 1) End If
Der Funktion wird der Rückgabewert zugewiesen. GetColor = ccolor
Sollte ein Fehler auftreten, müssen wir den geschützten Bereich wieder freigeben. Dieses geschieht mit der Unlock()-Methode.
84
Spritekollision
fehler: Backbuffer.Unlock rSurface End Function
Kehren wir zum Mustervergleich zurück. Wir wollen über den Mustervergleich eine mögliche Kollision feststellen. Um eine Kollision festzustellen, vergleichen wir die Farben. Jetzt ist es wichtig, das wir nur die Farbbereiche überprüfen, welche nicht zum Hintergrund der RECT-Struktur auf der Sprite-1-Surface gehören. Würden wir den Hintergrundbereich in den Mustervergleich einbeziehen, würden eine Kollision festgestellt, sobald das Dreieck von Sprite 2 die RECT-Struktur von Sprite 1 überlappt. Dies ist nicht gewollt. Wir wollen nur die Überlagerung von Kreis und Dreieck registrieren. Beispiel (Spritekollision) In unserm Kollisionsbeispiel bewegt sich das Dreieck auf den Kreis zu. Wenn das Dreieck den Kreis berührt, wird das Programm beendet. Um die Kollision zu erkennen, verwenden wir zwei Techniken. Die erste Technik ist die grobe Kollisionserkennung durch die RECT-Strukturen der beiden Objekte. Da uns die RECTStrukturen keine echte Kollision anzeigen, verwenden wir noch eine feine Kollisionserkennung, sobald sich die RECT-Strukturen überlappen.
Bild 1.26: Bildschirmfoto Spritekollision
Kapitel 1 • DirectDraw
85
Zum einfacheren Verständnis ist der VB-Code nun in Module unterteilt. Aufrufen der Module zum Initialisieren von DirectX und Einrichten der Backgrounds, Sprite1 und Sprite 2 sowie des Backbuffers und Screensurface. Zu Beginn erstellen Sie ein Standard-Exe-Projekt und füllen die Form_Load()Routine mit folgenden Anweisungen: Private Sub Form_Load() Init Form1 InitScreen InitSurface 1, App.Path & "\Back.bmp" InitSurface 2, App.Path & "\Sprite1.bmp" InitSurface 3, App.Path & "\Sprite2.bmp" CreateSpriteBuffer 4
Zuweisen der RECT-Strukturen durch Auslesen der ddsdSurface.Caps For i = 1 To 4 rSurface(i).Right = ddsdSurface(i).lWidth rSurface(i).Bottom = ddsdSurface(i).lHeight Next End Sub
In der Form_Paint()-Sub steht die eigentliche Routine zum Bewegen der SpriteObjekte und dem Aufruf der Kollisionsabfrage. Private Sub Form_Paint()
Wir benötigen als Erstes eine Schleife, in der wir die X-Position des zweiten Sprite-Objekts von 500 auf 50 herunterzählen. For xx = 500 To 50 Step -1
Da wir in diesem Projekt die Flip()-Methode einsetzen, müssen wir bei jedem Bildschirmaufbau auch den Hintergrund wieder neu zeichnen. Dazu kopieren wir das Hintergrundbild (Surface Index 1) in den Backbuffer. BlitSurfaceInBuffer 1, 0, 0, 640, 480, 0, 0, 640, 480, False
Als Nächstes legen wir den Colorkey für die transparente Darstellung des rechteckigen Bereichs der beiden Sprite-Objekte fest und kopieren beide Sprites (Surface Index 2 und 3) ebenfalls in den Backbuffer. SetColorkey 2, RGB(255, 0, 255) BlitSurfaceInBuffer 2, 0, 0, 60, 60, 100, 100, 160, 160, True SetColorkey 3, RGB(255, 0, 255) BlitSurfaceInBuffer 3, 0, 0, 60, 60, xx, 120, xx + 60, 180, _ True
86
Spritekollision
Um nun zu überprüfen, ob es eine Überlappung der beiden Sprite-RECT-Strukturen gibt, rufen wir die Funktion GetOverlapRect() auf. Als Rückgabewert erhalten wir eine 1 wenn eine Überlappung vorhanden ist und eine 0 wenn keine Überlappung stattfindet. Erst wenn eine Überlappung der beiden Sprite-Objekte stattfindet, verzweigen wir in die Subroutine DetectCollision(), die dann pixelweise nach einer Kollision überprüft. In der Variable coli bekommen wir nun eine 1 nach einer Kollision auf Pixelebene zurück und beenden damit das Programm. msg = GetOverlapRect(100, 100, xx, 120, 2, 3) If msg = 1 Then coli = DetectCollision(2, 100, 100, RGB(255, 0, 255)) If coli = 1 Then End End If
Nach der Kollisionsüberprüfung wird der Backbuffer auf den sichtbaren Bildschirm geflippt. Flip DoEvents Next End Sub
Beschreibung der Module: Als Erstes die Funktion zur Überprüfung, ob die beiden Sprite-RECT-Strukturen überlappen. Hierzu benötigt die Routine die Koordinaten beider Sprites. Diese übergeben wir an die Funktion mit Sprite1_X,Sprite1_Y . Die Größe der Sprites bekommen wir aus der Surface-Beschreibung. Weiterhin sind noch die Indexnummern mit denen wir die Sprites erzeugt haben von Nutzen, um auf die richtigen Surface-Beschreibungen zugreifen zu können. Function GetOverlapRect(Sprite1_X, Sprite1_Y, Sprite2_X, _ Sprite2_Y, Sprite1_Index, Sprite2_Index) X1 = Sprite1_X X2 = X1 + ddsdSurface(Sprite1_Index).lWidth Y1 = Sprite1_Y Y2 = Y1 + ddsdSurface(Sprite1_Index).lHeight q1 = Sprite2_X q2 = q1 + ddsdSurface(Sprite2_Index).lWidth w1 = Sprite2_Y w2 = w1 + ddsdSurface(Sprite2_Index).lHeight GetOverlapRect = 0: pp = 0
Kapitel 1 • DirectDraw
87
Um eine Überlappung feststellen zu können, überprüfen wir, ob die linke obere Ecke von Sprite 1 (X1,Y1) größer als die rechte obere Ecke (q1,w1) von Sprite 2 und gleichzeitig X1,Y1 kleiner als die rechte untere Ecke von Sprite 2 ist. Wenn ja, liegt eine Überschneidung vor. Dieses Spiel treiben wir noch in umgekehrter Reihenfolge mit Sprite 2. Je nach Resultat der Überprüfung geben wir als Rückgabewert an die Funktion GetOverlapRect() eine 0 oder 1 zurück. If X1 >= q1 And X1 <= q2 Then pp If q1 >= X1 And q1 <= X2 Then pp If pp = 0 Then Exit Function If Y1 > q1 And Y1 < q2 Then pp = If q1 > Y1 And q1 < Y2 Then pp = If pp = 1 Then Exit Function GetOverlapRect = 1 End Function
= 1 = 1 2 2
Sollte eine Überlappung der RECT-Strukturen stattgefunden haben, verzweigt die Hauptroutine in folgendes Modul zur Überprüfung einer Kollision auf Bitebene. Hierzu benötigen wir den Surface Index des zu prüfenden Sprites, die X- und YPosition sowie die transparente Farbe der Surface. Function DetectCollision(SpriteIndex As Integer, Sprite_X, _ Sprite_Y, TransColor As Long) On Error GoTo fehler
Die Surfacegröße bekommen wir wieder von den Caps-Eigenschaften der Surface-Beschreibung geliefert. d_Width = rSurface(SpriteIndex).Right – _ rSurface(SpriteIndex).Left d_Height = rSurface(SpriteIndex).Bottom – _ rSurface(SpriteIndex).Top DetectCollision = 0
Zur eigentlichen bitweisen Abfrage des Spritesurfaces lassen wir zwei verschachtelte Schleifen in X- und Y-Richtung laufen. Um Rechenzeit zu sparen, fragen wir nur jedes 5. Pixel ab, dies reicht für gewöhnlich aus. For y = 0 To d_Height – 1 Step 5 For x = 0 To d_Width – 1 Step 5
Über die Subroutine GetColor() ermitteln wir den Farbwert des Pixels (x, y). spcolor beinhaltet den Pixelwert des Sprite-Orginals aus der Spritesurface, bucolor hingegen den Pixelwert der Sprite-Kopie auf dem Backbuffer.
88
Bienenjagd
Beide Werte sollten, bis auf die Ausnahme des transparenten Hintergrundes der Spritekopie oder einer vorhandenen Kollision, gleich sein. spcolor = GetColor(SpriteIndex, x, y, FROM_SURFACE) bucolor = GetColor(0, Sprite_X + x, Sprite_Y + y, _ FROM_BACKBUFFER)
Um eine Nichtübereinstimmung des transparenten Bereichs der Kopie mit der transparenten Farbe des Originals zu vermeiden, führen wir einen Vergleich von spcolor mit bucolor nur durch, wenn spcolor nicht der Transparentfarbe entspricht. Sollte nun der RECT-Bereich der Kopie nicht mit der Spritesurface übereinstimmen, setzten wir als Funktion für den Rückgabewert eine eins. If spcolor <> TransColor Then If spcolor <> bucolor Then DetectCollision = 1 Exit For End If End If Next Next fehler: End Function
1.8
Bienenjagd Bienenjagd ist ein kleines Spiel, welches auf Techniken von DirectDraw basiert. Ziel dieser Anwendung ist es, die Handhabung von mehreren Surfaces zu demonstrieren. Auf dem Startbildschirm können Sie die Spielzeit und Anzahl der Bienen einstellen. Reizen Sie ruhig einmal die Anzahl der Bienen etwas aus, so können Sie (im kleinen Rahmen) die 2D-Leistungsfähigkeit Ihres Systems testen. Wir konnten z.B. bei der Darstellung von 1000 Bienen über 30 Frames erzielen. Da wir diesmal nicht nur ein Sprite bewegen möchten, haben wir einen eigenen Typ für Sprite-Arrays definiert. Type SpriteArray Breite As Single Höhe As Single Col As Integer Row As Integer ACol As Integer ARow As Integer Speed As Long Richtung As String Posx As Long Posy As Long
Kapitel 1 • DirectDraw
89
StartZeit As Long Visible As Boolean Bildausschnitt As RECT End Type Public Sprite() As SpriteArray
Bild 1.27: Bildschirmfoto Bienenjagd
Mit Hilfe eines solchen Arrays können wir die Bewegungen der Sprites besser organisieren. Durch die Dimensionierung des Arrays können wir die Anzahl der Sprites problemlos variieren. Weiterhin werden durch das Array Eigenschaften der Sprites beschrieben. So wird die Flugrichtung oder ob das jeweilige Sprite sichtbar ist in dem Array gespeichert. Indem wir jedem Sprite individuelle Eigenschafen mitgeben, können wir die Spites über eine zentrale Schleife abarbeiten und dennoch reagieren sie individuell. Betrachten wir zunächst die InitDD()-Subroutine. Diese wird Ihnen mitlerweile vertraut vorkommen. Im Grunde wird hier nicht viel anderes getan, als wenn wir ein einzelnes Sprite über den Bildschirm bewegen. Public Sub InitDD() ReDim tempRect(MaxSprite) ReDim Sprite(MaxSprite) Set g_DD = g_DX.DirectDrawCreate("") Call g_DD.SetCooperativeLevel(Form1.hWnd, DDSCL_FULLSCREEN Or _
90
Bienenjagd
DDSCL_ALLOWMODEX Or DDSCL_EXCLUSIVE) g_DD.SetDisplayMode 640, 480, 16, 0, DDSDM_DEFAULT ddsdPrimäry.lFlags = DDSD_CAPS ddsdPrimäry.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Set PrimärySurf = g_DD.CreateSurface(ddsdPrimary) ' Surface erzeugen (HintergrundBild) ddsdOffScreen1.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ddsdOffScreen1.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Set OffScreen1surf = g_DD.CreateSurfaceFromFile(App.Path & _ "\hintergrund.bmp ", ddsdOffScreen1) rectHintergrund.Bottom = ddsdOffScreen1.lHeight rectHintergrund.Right = ddsdOffScreen1.lWidth ' Surface erzeugen (Zum Mischen) ddsdOffScreen2.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ddsdOffScreen2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN ddsdOffScreen2.lWidth = ScreenWidth + 200 ddsdOffScreen2.lHeight = ScreenHeight + 200
Da wir uns in einer Fullscreen-Anwendung befinden, können wir das ClipperObjekt nicht einsetzen. Dennoch möchten wir, dass die Sprites sanft in den Bildschirm scrollen. Deshalb erzeugen wir eine Offscreensurface, welche größer ist als die primäre Surface. Dies ist nicht mit jeder Grafikkarte möglich. Sollten Sie beim Erzeugen dieser Surface Probleme bekommen, können Sie die Surface explizit in des Systemspeicher auslagern. Dies schafft in den meisten Fällen Abhilfe. Set OffScreen2surf = g_DD.CreateSurface(ddsdOffScreen2) OffScreen2surf.SetForeColor RGB(255, 255, 255) rectMischen.Left = 100 rectMischen.Top = 100 rectMischen.Bottom = ScreenHeight + rectMischen.Top rectMischen.Right = ScreenWidth + rectMischen.Left ' Surface erzeugen (Sprite) ddsdSprite1.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ddsdSprite1.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Set Sprite1Surf = g_DD.CreateSurfaceFromFile(App.Path & _ ”\biene2.bmp", ddsdSprite1) CK.high = RGB(0, 0, 0) CK.low = RGB(0, 0, 0) Sprite1Surf.SetColorkey DDCKEY_SRCBLT, CK rectSprite1.Right = ddsdSprite1.lWidth rectSprite1.Bottom = ddsdSprite1.lHeight Dim i As Integer For i = 1 To MaxSprite Sprite(i).Posy = Int((460 * Rnd) + 100) Sprite(i).Speed = Int((MaxSpriteSpeed * Rnd) + _ MinSpriteSpeed)
Kapitel 1 • DirectDraw
91
If Int((2 * Rnd) + 1) = 1 Then Sprite(i).Richtung = Rechts"_ Else Sprite(i).Richtung = "Links" Sprite(i).Row = 2 Sprite(i).Col = 7 Sprite(i).Breite = rectSprite1.Right / Sprite(1).Col Sprite(i).Höhe = rectSprite1.Bottom / Sprite(1).Row Sprite(i).Visible = True Next I
Die For…Next()-Schleife initialisiert die Sprites für den ersten Start. Hierbei wird per Zufall die Flugrichtung, Flughöhe und Fluggeschwindigkeit zugeordnet. GameLoop = True End Sub
Die nächste Subroutine welche wir uns anschauen ist DrawSprite(). Sie ist für die Darstellung der Sprites verantwortlich. Public Sub DrawSprite() Dim i As Integer For i = 1 To MaxSprite If g_DX.TickCount > Sprite(i).StartZeit + Sprite(i).Speed _ Then Sprite(i).StartZeit = g_DX.TickCount Select Case Sprite(i).Richtung Case "Rechts" Sprite(i).ARow = 0 Sprite(i).ACol = Sprite(i).ACol + 1 If Sprite(i).ACol >= Sprite(i).Col Then _ Sprite(i).ACol = 0 Sprite(i).Posx = Sprite(i).Posx + 2 If Sprite(i).Posx > ddsdOffScreen2.lWidth Then _ Sprite(i).Posx = 1 Case "Links" Sprite(i).ARow = 1 Sprite(i).ACol = Sprite(i).ACol + 1 If Sprite(i).ACol > Sprite(i).Col – 1 Then _ Sprite(i).ACol = 0 Sprite(i).Posx = Sprite(i).Posx – 2 If Sprite(i).Posx < 1 Then Sprite(i).Posx _ = ddsdOffScreen2.lWidth End Select
Wenn Sie sich die Spritebitmap anschauen, werden Sie feststellen, dass die Bienen in einem 7 X 2 großen Raster abgelegt sind. Die Case...Select-Abfrage ist für die Navigation auf dieser Bitmap zuständig. Hierbei unterscheiden wir, ob die
92
Bienenjagd
Biene sich von links nach rechts oder von rechts nach links über den Bildschirm bewegt. Entsprechend der Bewegungsrichtung legen wir die aktuelle Zeile Acol und Spalte Arow fest. Da uns die Breite und die Höhe der Zellen bekannt ist, können wir mit diesen beiden Werten die Position und die Größe der aktuellen RECT-Struktur auf der Spritebitmap bestimmen. Sprite(i).Bildausschnitt.Left = Sprite(i).Breite * _ Sprite(i).Acol Sprite(i).Bildausschnitt.Right = (Sprite(i).Breite * _ Sprite(i).ACol) + Sprite(i).Breite Sprite(i).Bildausschnitt.Top = Sprite(i).Höhe * _ Sprite(i).Arow Sprite(i).Bildausschnitt.Bottom = (Sprite(i).Höhe * _ Sprite(i).ARow) + Sprite(i).Höhe
Dieser kleine Block definiert die passenden RECT-Struktur von der Spritesurface. tempRect(i).Left = Sprite(i).Posx tempRect(i).Top = Sprite(i).Posy tempRect(i).Right = Sprite(i).Breite + tempRect(i).Left tempRect(i).Bottom = Sprite(i).Höhe + tempRect(i).Top
In der tempRect() RECT-Struktur wird die neue Position des Sprites definiert. Diese ändert sich natürlich permanent. End If
Wenn ein Sprite im Laufe des Spieles getroffen wurde, wird seine Visible Eigenschaft auf False gesetzt. Dies ist für uns ein Indikator um die Eigenschaften des Sprites neu zu definieren. Dadurch erscheint das Sprite mit veränderten Flugeigenschaften erneut am Rande des Bildschirms. If Sprite(i).Visible = True Then OffScreen2surf.BLT tempRect(i), Sprite1Surf, _ Sprite(i).Bildausschnitt, DDBLT_ASYNC Or DDBLT_KEYSRC Else Sprite(i).Posy = Int((460 * Rnd) + 100) Sprite(i).Speed = Int((MaxSpriteSpeed * Rnd) + _ MinSpriteSpeed) If Int((2 * Rnd) + 1) = 1 Then Sprite(i).Richtung = "Rechts" Sprite(i).Posx = 0 Else Sprite(i).Richtung = "Links" Sprite(i).Posx = ddsdOffScreen2.lWidth End If Sprite(i).Visible = True End If Next i End Sub
Kapitel 1 • DirectDraw
1.9
93
Methoden zum Zeichnen Vielleicht ist es Ihnen bereits aufgefallen, eine DirectDraw-Surface beinhaltet eine Reihe von Methoden zum Zeichnen von Linien, Kreisen oder Rechtecken. Diese Fähigkeiten können Sie mit den Grafikeigenschaften eines Visual BasicForm-Objekts vergleichen. Sicherlich gehört die Darstellung von Linien, Kreisen, Rechtecken ... nicht zur Hauptaufgabe von DirectDraw, dennoch stellen diese Methoden eine hilfreiche Ergänzung dar. Diese Methoden können auch auf eine primäre Surface angewandt werden. Mit den folgenden Methoden können Sie einfache Zeichenaktionen ausführen: DrawBox() Zeichnet ein Rechteck auf eine Surface. object.DrawBox(x1 As Long, y1 As Long, x2 As Long, y2 As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
legt die linke obere Ecke des Rechtecks fest
x2, y2
legt die rechte untere Ecke des Rechtecks fest
DrawCircle() Zeichnet einen Kreis auf eine Surface. object.DrawCircle(x1 As Long, y1 As Long, r As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
legt den Mittelpunkt des Kreises fest
r
bestimmt den Radius des Kreises in Pixel
DrawEllipse() Zeichnet ein Oval auf eine Surface. Die Parameter x1,y1 sowie x2,y2 legen ein Rechteck fest, dieses wird als Oval umgeformt. object.DrawEllipse(x1 As Long, y1 As Long, x2 As Long, y2 As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
legt die linke obere Ecke fest
x2, y2
legt die rechte untere Ecke fest
DrawLine() Zeichnet ein Linie auf eine Surface. object.DrawLine(x1 As Long, y1 As Long, x2 As Long, y2 As Long) object
ein gültiges DirectDrawSurface7-Objekt
94
Methoden zum Zeichnen
DrawLine() x1, y1
Legt ein Koordinatenpaar fest, ab wo die Linie gezeichnet werden soll.
x2, y2
Legt ein Koordinatenpaar fest, bis wo die Linie gezeichnet werden soll.
DrawRoundedBox() Zeichnet ein Rechteck mit abgerundeten Ecken auf eine Surface. object.DrawLine(x1 As Long, y1 As Long, x2 As Long, y2 As Long, _ rw As Long, rh As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
Legt die linke obere Ecke fest.
x2, y2
Legt die rechte untere Ecke fest.
rw
Bestimmt die horizontale Größe der Rundung.
rh
Bestimmt die vertikale Größe der Rundung.
Um Text auf einer Surface auszugeben, steht folgende Methode zur Verfügung: DrawText() Zeichnet einen String auf eine Surface object.DrawLine(x As Long, y As Long, text As Long, b As Long,) object
ein gültiges DirectDrawSurface7-Objekt
x, y
Bestimmt ein Koordinatenpaar, an dem der Text gezeichnet werden soll.
text
Der Text der gezeichnet werden soll. Sie können eine Variable vom Typ Sring übergeben oder direkt einen Text in Hochkommata angeben.
b
True Der Text wird an der aktuellen Cursorposition gezeichnet. Die Parameter x,y werden ignoriert. False Der Text wird an dem Koordinatenpaar gezeichnet, welches durch die Parameter x,y beschrieben wurde.
Neben den eigentlichen Zeichenmethoden bietet DirectDraw eine Reihe von Methoden, mit denen Sie das Erscheinungsbild der Zeichenmethoden beeinflussen können. Dies funktioniert genauso wie bei dem Visual Basic-Form-Objekt. Erst legen Sie das Erscheinungsbild fest, dann zeichnen Sie z.B. die Linie.
Kapitel 1 • DirectDraw
95
SetDrawStyle() Setzt den Zeichenstil object.SetDrawStyle(drawStyle As Long) object
ein gültiges DirectDrawSurface7-Objekt
drawStyle
0 → voll (Solid), massiv 1 → gestrichelt 2 → gepunktet 3 → Strich und Punkt wechseln sich ab 4 → erst ein Strich, dann zwei Punkte 5 → durchsichtig 6 → gefüllt (Bei einem Rechteck wird nicht nur der Rahmen gezeichnet, sondern das Rechteck wird gefüllt. Gleiches gilt bei einem Kreis, Oval oder abgerundetem Rechteck.)
SetDrawWidth() Setzt die Strichbreite für Zeichenmethoden object.SetDrawWidth(drawWidth As Long) object
ein gültiges DirectDrawSurface7-Objekt
drawWidth
Strichbreite in Pixel Der voreingestellte Wert ist 1. Der erlaubte Wertebereich liegt zwischen 1 und 32,767.
SetFillColor() Setzt die Füllfarbe für Zeichenmethoden. object.SetFillColor(color As Long) object
ein gültiges DirectDrawSurface7-Objekt
color
Farbe Der voreingestellte Wert ist Schwarz (&H00000000).
SetFillStyle() Setzt das Füllmuster für Zeichenmethoden. object.SetFillStyle(fillStyle As Long) object
ein gültiges DirectDrawSurface7-Objekt
96
Methoden zum Zeichnen
SetFillStyle() fillStyle
0 1 2 3 4 5 6 7
→ → → → → → → →
voll (solid), massiv durchsichtig horizontale Linien vertikale Linien diagonal aufwärts diagonal abwärts horizontale und vertikale Linien diagonale horizontale und diagonale vertikale Linien
SetFont() Setzt einen neuen Zeichensatz für die DrawText()-Methode. object.SetFont(font As Ifont) object
ein gültiges DirectDrawSurface7-Objekt
font
Zeichensatz
SetFontBackColor() Setzt eine Hintergrundfarbe für einen Zeichensatz. object.SetFontBackColor(color As Long) object
ein gültiges DirectDrawSurface7-Objekt
color
Farbe
SetFontTransparency() Legt fest, ob der aktuelle Zeichensatz transparent sein soll. object.SetFontTransparency(b As Boolean) object
ein gültiges DirectDrawSurface7-Objekt
b
True → transparent False → nicht transparent
SetForeColor() Setzt die Zeichenfarbe, welche von den Zeichenmethoden verwendet wird. object.SetForeColor(color As Long) object
ein gültiges DirectDrawSurface7-Objekt
color
Farbe
Kapitel 1 • DirectDraw
97
Beispiel (Zeichnen) Die allgemeinen Zeichenmethoden sind gänzlich unkompliziert einzusetzen. Wir werden eine primäre Surface sowie eine Offscreensurface erstellen. Das Blitten wird über einen Timer gesteuert. Dies ist zwar unüblich, aber für unser Beispiel durchaus ausreichend. An der rechten Seite finden Sie einige Option-Buttons. Mit diesen können Sie einige der Zeichen Methoden ausprobieren.
Bild 1.28: Anwendung Zeichnen
Wir beginnen mit den Definitionen der Variablen. Diese sind Ihnen bestens bekannt und werden nicht weiter erklärt. Auch die Init()-Subroutine stellt keine Herausforderung dar. Die eigentlichen Zeichenmethoden werden erst in der Blt()Subroutine eingesetzt. Dim objDX As New DirectX7 Dim objDD As DirectDraw7 Dim objDDSurf As DirectDrawSurface7 Dim objDDPrimSurf As DirectDrawSurface7 Dim ddsd1 As DDSURFACEDESC2 Dim ddsd2 As DDSURFACEDESC2 Private Sub Form_Load() Init
98
Methoden zum Zeichnen
End Sub Private Sub Init() Set objDD = objDX.DirectDrawCreate("") Call objDD.SetCooperativeLevel(Me.hWnd, DDSCL_NORMAL) 'Surface 1 erzeugen ddsd1.lFlags = DDSD_CAPS ddsd1.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE Set objDDPrimSurf = objDD.CreateSurface(ddsd1) ' Surface 2 erzeugen ddsd2.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT ddsd2.lWidth = Picture1.ScaleWidth ddsd2.lHeight = Picture1.ScaleHeight ddsd2.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Set objDDSurf = objDD.CreateSurface(ddsd2) End Sub
In der Blt()-Soubroutine werden die Zeichenmethoden ausgeführt. Diese Routine wird all 100 Millisekunden per Timer aufgerufen. Private Sub Blt() Dim r1 As RECT Dim r2 As RECT Call objDX.GetWindowRect(Picture1.hWnd, r1) r2.Bottom = ddsd2.lHeight r2.Right = ddsd2.lWidth objDDSurf.BltColorFill r2, &HFFFFFFFF
Da wir immer eine saubere Zeichenfläche haben möchten, löschen wir die Offscreensurface mit der DirectDrawSurface7.BltColorFill()-Methode. Löschen ist eigentlich nicht der richtige Ausdruck, wir übermalen mit der Farbe Weiß den aktuellen Inhalt der Surface. If Option1(1).Value = True Then objDDSurf.DrawLine 0, 0, 500, 500
Zeichnen einer Linie. ElseIf Option1(2).Value = True Then objDDSurf.DrawCircle 250, 250, 200
Zeichnen eines Kreises. Eine Ellipse kann mit dieser Methode nicht dargestellt werden. Dazu verwenden Sie die DirectDrawSurface7.DrawEllipse()-Methode. ElseIf Option1(3).Value = True Then objDDSurf.DrawBox 100, 100, 300, 300
Kapitel 1 • DirectDraw
99
Zeichnen eines Rechtecks. In diesem Beispiel wird ein Quadrat dargestellt. Natürlich muss das Rechteck nicht quadratisch sein. ElseIf Option1(4).Value = True Then objDDSurf.DrawRoundedBox 100, 100, 300, 300, 40, 40
Die DirectDrawSurface7.DrawRoundedBox()-Methode erstellt ebenfalls ein Rechteck. Diesmal sind die Ecken abgerundet. Die rw- und rh-Parameter bestimmen die Ausdehnung der Rundung. Haben Sie z.B. ein Quadrat mit einer Seitenlänge von 200 Pixel erstellt und anschließend weisen Sie den Parametern rw und rh den Wert »200« zu, so werden Sie einen Kreis erhalten. Probieren Sie dies an unserem Beispiel aus. ElseIf Option1(5).Value = True Then objDDSurf.DrawText 100, 100, "This is a Demo!", False
Mit der DirectDrawSurface7.DrawText()-Methode können Sie Text auf eine Surface zeichnen. Die Parameter x und y bestimmen die Position, an der ein Text eingeblendet werden soll. Diese Koordinaten werden aber nur dann wirksam, wenn Sie den Parameter b auf False setzten. Ansonsten wird die aktuelle Cursorposition übernommen. End If ddrval = objDDPrimSurf.Blt(r1, objDDSurf, r2, DDBLT_WAIT)
Nachdem mit einer Zeichen-Methode die Offscreensurface geändert wurde, blitten wir diese auf die primäre Surface. End Sub
Kapitel 2 Direct3D 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13
3D-Koordinatensystem 3D-Primitives Zeichnen eines Dreiecks Dreieck-Raster-Regeln World-, View- und Projection-Matrix Matrix-Berechnungen Polygone Licht Material Texturen Z-Buffer (Tiefenspeicher) Die SetRenderState()-Methode Effekte
104 105 106 118 120 122 132 137 157 165 212 218 225
102
Direct3D (D3D) ist das Tor von DirectX, welches den Weg zur 3D-Computergrafik öffnet. Es wurde konzipiert, um High-Performance-Grafik umzusetzen. Im Gegensatz zu Techniken wie Glide oder OpenGL arbeitet die D3D-API mit allen modernen Grafikkarten zusammen. Obwohl D3D eine leistungsfähige Softwareemulation beinhaltet, entwickelt es seine volle Leistungsfähigkeit erst bei der direkten Nutzung der Hardware. In der Vergangenheit stellte dies oftmals ein Problem dar. Viele Grafikkarten waren nicht in der Lage, den Leistungsumfang von D3D zu unterstützen. Somit weichen viele Softwareentwickler auf die alternativen Glide bzw. OpenGL aus. Mit den modernen Grafikkarten vollzog sich ein Wandel. Eine starke D3D-Unterstützung gehört mittlerweile zum Standard. Mit der DirectX Version 7 kommt auch der VB-Programmierer in den Genuss der dritten Dimension. Direct3D stellt zwei verschiedene Modes zur Verfügung. Zum einen ist da der Retained Mode (RM). Der zweite Weg ist der Immediate Mode (IM). Der RM ist ein High Level Interface. Er ist vergleichbar mit einer kleinen 3D-Engine. Hier werden bereits eine Reihe von fortgeschrittenen Techniken bereitgestellt. Mit wenig Quellcode lassen sich anschauliche Ergebnisse erzeugen. Er ist relativ einfach zu erlernen. (Dies muss ein bisschen modifiziert werden. Obwohl der RMMode einfacher als der IM-Mode anzuwenden ist, kommt man auch hierbei nicht ohne entsprechende Hintergrundinformationen aus.) Die beiden Hauptgründe für uns, auf den RM zu verzichten, heißen Performance und Flexibilität. Im Vergleich zum IM ist der RM langsamer. Außerdem sind Sie in der Gestaltung Ihres 3DRaums nicht so flexibel. Da Sie sich für die Programmierung von Grafik entschieden haben, stoßen Sie zwangsläufig an die Grenzen der Computerperformance. Hierbei sollte man nicht auf Leistung verzichten, nur um eine etwas bequemere Programmiertechnik zu nutzen. Außerdem würden sich irgendwann die Fähigkeiten von RM ausreizen und Sie zu einer leistungsfähigeren Technik zwingen. Also können wir auch sofort mit IM beginnen. Letztendlich sparen wir viel Zeit und erreichen schnelle und beeindruckende Ergebnisse. Sie werden Sich wundern, was Sie mit VB und DirectX im IM erreichen. Stellen wir beide Wege einmal gegenüber: Immediate Mode Pro 1. flexibler für Spezialeffekte 2. schneller Contra 1. schwieriger zu programmieren 2. schwieriger zu verwalten
Kapitel 2 • Direct3D
103
Retained Mode Pro 1. einfacher zu programmieren 2. einfacher zu erlernen 3. einfacher zu verwalten Contra 1. langsamer 2. unflexibel Kommen wir zu unserm favorisiertem Weg. Der Immediate Mode ist ein Low Level Interface. Wie es der Name bereitst verrät (immediate = direkt, unverzüglich), erhalten Sie den direkten Zugriff auf 3D-Grafik-Pipelines. Sollte eine direkte Verbindung zu verfügbaren Hardware fehlen, so tritt eine robuste Softwareemulation in Aktion. IM stellt einfache und offene Methoden zum Initialisieren und Rendern einer Szene zur Verfügung. Um diesen kraftvollen Mode zu nutzen, müssen Sie aber auch einen Preis bezahlen. Dieser Preis besteht darin, das Sie alle Elemente einer 3D-Szene explizit benennen müssen. Sie benötigen genaue Kenntnisse über die verfügbare Hardware. Ebenfalls werden Sie Ihre 3DObjekte durch Matrizenmanipulationen berechnen. Hierdurch werden Form, Lage, Perspektive... definiert. Betrachten wir zuerst die Einbindung von D3D im Windows-System. Win32 Anwendung
GDI
Direct3D
Windows DDI
Hardware Abstraction Layer Hardware Emulation Layer
Grafikkarte
Bild 2.1:
Einbindung von Direct3D in die Systemumgebung
Weitere 3D API’s
104
2.1
3D-Koordinatensystem
3D-Koordinatensystem Typische 3D-Anwendungen verwenden zwei Arten von Koordinatensystemen. Linkshändig oder rechtshändig. In beiden Systemen liegt die positive X-Achse zur rechten Seite und die positive Y-Achse senkrecht nach oben. Bei dem linkshändigen System liegt die positive Z-Achse zwischen der X- und Y-Achse. Y
Y Z
linkshändig
rechtshändig
X
X
Z
Bild 2.2:
Koordinatensystem
Direct3D benutzt das linkshändige Koordinatensystem. Falls Sie eine Anwendung basierend auf dem rechtshändigen Koordinatensystem erstellen möchten, ist es notwendig zwei Änderungen an den Daten zur Übergabe an Direct3D vorzunehmen. (Diese Änderungen sind nur dann notwendig, wenn Sie von dem normalen linkshändigen System abweichen. Für das normale Koordinatensystem sind diese Änderungen absolut überflüssig und können von Ihnen ignoriert werden.) •
Drehen Sie die Dreiecks-Scheitelpunkte so, dass sie sich aus der Vorderansicht im Uhrzeigersinn bewegen. aus V0, V1, V2 wird V0, V2, V1
•
Tauschen Sie die Vorzeichen der Mitgliedsdaten rc31, rc32, rc32 und rc34 der D3DMATRIX-Struktur. Type D3DMATRIX rc11 As Single rc12 As Single rc13 As Single
Kapitel 2 • Direct3D
rc14 rc21 rc22 rc23 rc24 rc31 rc32 rc33 rc34 rc41 rc42 rc43 rc44 End Type
105
As As As As As As As As As As As As As
Single Single Single Single Single Single Single Single Single Single Single Single Single
Natürlich gibt es noch weitere Koordinatensysteme, aber das linkshändige und das rechtshändige sind die am weitesten verbreiteten Systeme. Das Koordinatensystem bildet die Grundlage für alle wesentlichen Techniken, welche ein Objekt im 3D-Koordinatensystem benötigen. Techniken wie Translation, Rotation oder Scalling beruhen auf dem Koordinatensystem und werden in einer TransformMatrix miteinander kombiniert.
2.2
3D-Primitives Eine 3D-Primitive ist eine Sammlung von Scheitelpunkten, die eine einzelne 3DStruktur bilden. Die einfachste Primitive ist eine Sammlung von Punkten im 3DKoordinatensystem. Solch eine Sammlung wird als Pointlist bezeichnet. Wesentlich öfter werden Polygone (Vielecke) als Primitive verwendet. Ein Polygon ist eine geschlossene 3D-Figur. Das kleinste Polygon besteht aus drei Scheitelpunkten (Vertex). Solch ein Dreieck wird verwendet, um komplexere 3D-Figuren zu erstellen. Dreiecke sind besonders beliebt, da sie quasi dafür bürgen, eine geschlossene Figur zu bilden. Außerdem sind Dreiecke von D3D extrem schnell zu berechnen. Betrachten Sie das Dreieck als primitivstes Polygon. Es stellt die Grundlage für komplexere 3D-Objekte dar. Aus einer Ansammlung von vielen Dreiecken lassen sich quasi alle 3D-Objekte einer 3D-Welt (eines 3D-Raums) konstruieren. Das folgende Beispiel zeigt einen Würfel. Jede Seite des Würfels wurde aus zwei Dreiecken gebildet. Natürlich ist es auch möglich komplexere Figuren zu gestalten. Als Beispiel sei eine Kugel oder ein Zylinder genannt.
106
Zeichnen eines Dreiecks
Bild 2.3:
2.3
Würfel aus Dreiecken erstellt
Zeichnen eines Dreiecks Es hört sich verrückt an, aber zum Konstruieren einer komplexen 3D-Welt benötigen Sie lediglich eine Vielzahl von Dreiecken. Wie bereits erwähnt sind Dreiecke die primitivste Form eines Polygons. Es stellt die ideale Basis zum Gestalten komplexerer 3D-Objekte dar. Die Eckpunkte eines Dreiecks werden durch Vertexe dargestellt. Diese Vertexe fließen anschließend (unbemerkt vom Programmieren) in die Matrixstrukturen von D3D ein. Natürlich können Sie die Matrixstrukturen auch manuell transformieren. Dies werden wir später genauer erläutern. Es werden eine Reihe von Methoden vorgestellt, die quasi als Basis für alle Direct3D-Anwendungen betrachtet werden können. Zum jetzigen Zeitpunkt wollen wir die Methoden nicht besprechen, sondern Ihnen einen kleinen Überblick vermitteln. Sicherlich ist Ihnen bewusst, dass dies nur die Spitze des Eisbergs ist. CreateDevice() Erzeugt ein Direct3D-Device welches mit den DrawPrimitive-Methoden genutzt wird. object.CreateDevice(guid As String, surf As DirectDrawSurface7)) _ As Direct3Ddevice7 Objekt
ein gültiges Direct3D7-Objekt
Guid
IID_IDirect3DHALDevice Nutzen der Hardwareeigenschaften der Grafikkarte IID_IDirect3DRGBDevice Verwendet den Software-Emulations-Modus IID_IDirect3DrefDevice Erzeugt ein Referenzdevice. Wird zum Testen oder Demonstrationsaufgaben eingesetzt.
Kapitel 2 • Direct3D
107
CreateDevice() surf
Eine DirectDrawSurface, auf welcher gerendert werden soll. (Zielsurface) Die Surface muss als 3D-Device mit dem Flag DDSCAPS_ 3DDEVICE erstellt worden sein.
SetViewport() Setzt die Viewport-Parameter für ein Device. object.SetViewport(Viewport As D3Dviewport7) Objekt
ein gültiges Direct3DDevice7-Objekt
Viewport
Eine Variable vom Typ D3DVIEWPORT7, welche die zu setzenden Viewportparameter enthält.
IdentityMatrix() Erzeugt eine einheitliche Matrix. (Alle Einträge auf »0« außer die diagonalen Werte von links oben nach rechts unten auf »1«) object.IdentityMatrix(Matrix As D3DMATRIX) Objekt
ein gültiges DirectX7-Objekt
mDest
Eine Variable vom Typ D3DMATRIX, welche die einheitliche Matrix aufnimmt.
SetTransform() Weist eine einzelne Transformation einem Device zu. object.SetTransform(transformType As D3DMATRIX, matrix As D3DMATRIX) object
ein gültiges Direct3DDevice7-Objekt
transformType
Eine Variable vom Typ CONST_D3DTRANSFORMSTATETYPE
matrix
Eine Matrix vom Typ D3DMATRIX, welche die aktuelle Transformation modifiziert.
ViewMatrix() Erzeugt eine Viewmatrix basierend auf den Koordinaten (Betrachterposition) der Kamera. Call object.ViewMatrix(mDest As D3DMATRIX, vFrom As D3DVECTOR, _ vTo As D3DVECTOR, vUp As D3DVECTOR, roll As Single) object
ein gültiges DirectX7-Objekt
mDest
Nimmt die neue transformierte Matrix auf.
108
Zeichnen eines Dreiecks
ViewMatrix() vFrom
Beschreibt die aktuelle Position der Kamera (des Betrachters).
vTo
Beschreibt die Koordinaten, wohin die Kamera schauen soll. (Wohin der Betrachter schauen soll)
vUp
Definiert die Lage der gesamten 3D Welt. Für gewöhnlich wird dieser Vektor mit 0,1,0 festgelegt.
roll
Bestimmt den Winkel, mit dem die Kamera (im Uhrzeigersinn) um die Blickrichtung rotiert. Für gewöhnlich 0.
ProjectionMatrix() Diese Methode setzt den Renderbereich (clipping plane). Ebenfalls wird der Blickwinkel des Betrachters festgelegt. object.ViewMatrix(mDest As D3DMATRIX, nearPlane As Single, _ farPlane As Single, fov As Single) object
ein gültiges DirectX7-Objekt
mDest
Nimmt die neue transformierte Matrix auf.
nearPlane
Bestimmt die Entfernung zum Anfang des Zeichenbereichs (Clipping Plane).
farPlane
Bestimmt die Entfernung zum Ende des Zeichenbereichs (Clipping Plane).
fov
Definiert den Radius des Blickwinkels. Das menschliche Auge hat einen Blickwinkel von ungefähr 150 Grad.
CreateD3DVertex() Diese Methode füllt ein D3DVERTEX-Typen-Array. object.ViewMatrix(x As Single, y As Single, z As Single, nx As _ Single, ny As Single, nz As Single, tu As Single, tv As Single, _ v As D3DVERTEX) object
ein gültiges DirectX7 Objekt
x, y und z
Beschreiben die Koordinaten im 3D Raum eines Vektors.
nx, ny und nz
Beschreiben die Orientierung des normalen Vektors.
tu und tv
Enthalten die Texturkoordinaten für den Vektor.
v
Eine Variable vom Typ D3DVERTEX, welche mit den erzeugten Vertexkomponenten gefüllt wird.
Kapitel 2 • Direct3D
109
Clear() Diese Methode löscht einen Viewport (oder Teile des Viewport) mit einer bestimmten Farbe. Ebenfalls löscht Sie den Stencil Buffer oder Z Buffer mit einem angegebenen Wert. object.Clear(count As Long, recs() As D3DRECT, flags As CONST_ D3DCLEARFLAGS, color As Long, z As Single, stencil As Long) object
ein gültiges Direct3DDevice7-Objekt
count
Anzahl der Rechtecke im recs() Array.
recs()
Ein Array von D3DRECT-Typen, welche die Bereiche definieren, die gelöscht werden sollen. Wird ein Rechteck auf die Dimensionen des Renderziels gesetzt, so wird das gesamte Ziel gelöscht.
flags
Diese Flags indizieren, welches Ziel (Surface) gelöscht werden soll. Hierbei sind Kombinationen verschiedener Ziele zugelassen. D3DCLEAR_TARGET Löscht das Renderziel (im Regelfall die Backbuffersurface) mit der angegebenen Farbe. D3DCLEAR_STENCIL Überschreibt den Stencil Buffer mit dem stencil-Wert. D3DCLEAR_ZBUFFER Überschreibt den Z Buffer mit dem z Wert.
color
Definiert die Farbe zum Löschen einer Surface (oder Teile der Surface). Die Farbe kann mit der DirectX7.CreateColorRGBA()-Methode erzeugt werden.
z
Neuer Wert mit dem der Z Buffer gelöscht werden soll. Zugelassen ist ein Wert zwischen 0.0 und 1.0.
stencil
Neuer Wert mit dem der Stencil-Buffer gelöscht werden soll. Zugelassen ist ein Wert zwischen 0 und 2 n -1 inklusive.
BeginScene() Mit dieser Methode wird das Rendern einer Szene eingeleitet. Bevor BeginScene() erneut aufgerufen wird, muss die aktuelle Szene mit der Direct3DDevice7.EndScene()Methode abgeschlossen sein. object.BeginScene() object
ein gültiges Direct3DDevice7-Objekt
110
Zeichnen eines Dreiecks
EndScene() Mit dieser Methode wird das Ende einer Szene signalisiert. Der Anfang einer Szene wurde mit der Direct3DDevice7.BeginScene Methode eingeleitet. object.EndScene() object
ein gültiges Direct3DDevice7-Objekt
DrawPrimitive() Diese Methode rendert einen definierten Block von Vertexes als Sequenz eines typischen geometrischen Polygons. object.DrawPrimitive(d3Dpt As CONST_D3DPRIMITIVETYPE, _ d3dfvf As CONST_D3DFVFFLAGS, vertices As Any, vertexCount As _ Long, flags As CONST_D3DDPFLAGS) object
ein gültiges Direct3DDevice7-Objekt
d3Dpt
Eine Variable vom Typ CONST_D3DPRIMITIVETYPE. Er definiert die Art des Polygontyps (Type of primitive), mit dem die Szene gerendert werden soll.
d3dfvf
Eine Variabel vom Typ CONST_D3DFVFFLAGS. Er beschreibt das verwendete Vertexformat.
vertices
Das erste Element in einem Vertex-Array
vertexCount
Anzahl der Vertexe, welche gerendert werden sollen. Das Maximum ist auf 65535 (&HFFFF) begrenzt.
flags
Variable vom Typ CONST_D3DDPFLAGS. Sie definiert, wie das Polygon gezeichnet werden soll.
Wir werden ein Dreieck im Koordinatensystem der 3D-Welt definieren und auf dem Bildschirm darstellen. Dabei werden wir weder Licht noch Material des Dreiecks berücksichtigen. Dies ist normalerweise ein gewaltiger Fehler. Dennoch begehen wir diesen Fehler, schließlich wollen wir das Listing recht übersichtlich gestalten. Licht sowie Objektmaterial werden später ausgiebig besprochen. In dieser ersten Demonstration der Leistungsfähigkeit von D3D sollten Sie nicht zu viel erwarten, denn es geht nur um die Technik und nicht um gestalterische Höchstleistungen. Betrachten Sie das Bildschirmfoto zu unserem Beispiel. Zerlegen wir die anstehenden Aufgaben in Einzelschritte: Schritt 1:
Variablen benennen
Schritt 2:
Variablen initialisieren
Schritt 3:
Koordinaten für das Dreieck bestimmen
Schritt 4:
Zeichnen des Dreiecks
Kapitel 2 • Direct3D
Bild 2.4:
111
Ein einfaches Polygon
Schritt 1: Variablen benennen In dieser Grundanwendung fließen die Komponenten aus DirectDraw und Direct3D zusammen. Schauen wir uns direkt die Dimensionierungen der Variablen an. Dim Dim Dim Dim Dim
g_dx As New DirectX7 g_dd As DirectDraw g_ddsd As DDSURFACEDESC2 g_ddsPrimary As DirectDrawSurface7 g_ddsBackBuffer As DirectDrawSurface7
Bis hierher sieht das alles recht vertraut aus. Sollten Sie Probleme mit diesen Strukturen haben, dann schauen Sie einfach in den Fullscreen-Abschnitt von DirectDraw. Dim g_d3d As Direct3D7
Das Direct3D7-Objekt stellt die Verbindung zu Direct3D von DirectX her. Dim g_d3dDevice As Direct3DDevice7
Über das Direct3DDevice7-Objekt laufen alle Aufgaben, welche zum Rendern einer Szene notwendig sind.
112
Zeichnen eines Dreiecks
Dim vPort As D3DVIEWPORT7
Den Viewport können Sie mit einem Fenster vergleichen. Durch dieses Fenster können wir in die 3D-Welt hineinsehen. Mit Hilfe des D3DVIEWPORT7-Typen-Arrays werden die Dimensionen des Renderziels definiert. Normalerweise werden die Szenen auf der Backbuffersurface gerendert. Somit werden wir später die Dimensionen der Backbuffersurface übergeben. Dieses Typenarray beinhaltet zwei Mitglieder (maxz und minz), die für unser Beispiel noch keine Bedeutung besitzen, dennoch erklären wir jetzt deren Aufgabe. Das Array ist folgendermaßen aufgebaut: Type D3DVIEWPORT7 lHeight As Long lWidth As Long lX As Long lY As Long maxz As Single minz As Single End Type
Die ersten vier Einträge sind recht einfach erklärt. lX und lY bestimmen die linke obere Ecke des Zielrechtecks. lHeight und lWidth bestimmen die Dimensionen (in Pixel) des Zielrechtecks. Diese Daten sind zwingend erforderlich. Die letzen beiden Mitglieder erhalten erst eine Bedeutung, wenn wir mit dem Z Buffer arbeiten. Über den Z Buffer definieren Sie, welches Objekt im 3D-Raum vor einem anderen Objekt gezeichnet wird. Die meisten Anwendungen setzen diese Einträge auf die Werte 1.0 (für maxz) und 0.0 (für minz). Somit werden die Deklarationen des Z Buffers berücksichtigt. Werden beide Werte auf 0.0 gesetzt, so zwingen Sie D3D dazu, das Objekt in den Vordergrund zu rendern. Vorerst ignorieren wir diese Einträge. Dim g_d3drcViewport(0) As D3DRECT
Hierbei handelt es sich um eine fast normale RECT-Struktur. Der Unterschied liegt in der Dimensionierung der Mitglieder. Diese sind jetzt vom Typ Long. Dim matProj As D3DMATRIX Dim matView As D3DMATRIX Dim matWorld As D3DMATRIX
Diese drei Matrizen bestimmen alles, was Sie auf Ihrem Bildschirm zu sehen bekommen. Sie werden noch ausgiebig besprochen. In diesem Anfangsbeispiel können wir auf eine Transformation der Worldmatrix verzichten. Später wird dies aber notwendig sein. Dim Vertex(100) As D3DVERTEX
Kapitel 2 • Direct3D
113
In den Vertex-Strukturen werden die Vektordaten der Polygoneckpunkte gespeichert. Schritt 2: Variablen initialisieren Die Initialisierungssequenz beginnt mit dem initialisieren der DirectDraw-Strukturen. Diese ist uns aus dem DirectDraw-Abschnitt bestens bekannt. Die einzige Erneuerung besteht in der lCaps-Deklaration. Hier wird ein zusätzliches Flag DDSCAPS_3DDEVICE gesetzt. Es ermöglicht den Zugriff auf das notwendige Direct3Ddevice. Set g_dx = New DirectX7 Set g_dd = g_dx.DirectDrawCreate("") g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_FULLSCREEN Or _ DDSCL_EXCLUSIVE g_dd.SetDisplayMode 640, 480, 16, 0, DDSDM_DEFAULT Dim ddsd2 As DDSURFACEDESC2 ddsd2.lFlags = DDSD_BACKBUFFERCOUNT Or DDSD_CAPS ddsd2.ddsCaps.lCaps = DDSCAPS_COMPLEX Or DDSCAPS_FLIP Or _ DDSCAPS_PRIMARYSURFACE Or DDSCAPS_VIDEOMEMORY Or _ DDSCAPS_3DDEVICE ddsd2.lBackBufferCount = 1 Set g_ddsPrimary = g_dd.CreateSurface(ddsd2) Dim Caps As DDSCAPS2 Caps.lCaps = DDSCAPS_BACKBUFFER Set g_ddsBackBuffer = g_ddsPrimary.GetAttachedSurface(Caps)
Ab hier wird es interessanter. Wir initialisieren die direkte Verbindung zur gewünschten 3D-Welt. Set g_d3d = g_dd.GetDirect3D
Die DirectDraw7.GetDirect3D()-Methode kreiert das zuvor dimensionierte Direcet3D7-Objekt. Es wird über die Set-Anweisung ohne Angabe von Parametern zugewiesen und ist somit gänzlich unkompliziert. Set g_d3dDevice = g_d3d.CreateDevice _ ("IID_IDirect3DHALDevice", g_ddsBackBuffer)
Jetzt erzeugen wir das Direct3DDevice. Es müssen zwei Parameter berücksichtigt werden. Als ersten Parameter müssen wir den guid As String übergeben. IID_ IDirect3DHALDevice, IID_IDirect3DRGBDevice oder IID_IDirect3DRef Device stehen zur Auswahl. Mit IID_IDirect3DHALDevice erreichen Sie die beste Performance. Sie adressieren die Grafikkarte auf direktem Weg. Welche Möglichkeiten zur Auswahl stehen, können Sie mit der Direct3D7.GetDevicesEnum()-Methode abfragen. vPort.lX = 0 vPort.lY = 0
114
Zeichnen eines Dreiecks
vPort.lHeight = 480 vPort.lWidth = 640 g_d3dDevice.SetViewport vPort
Bei diesen Zuweisungen muss nicht viel erklärt werden. Die ersten beiden Parameter lX und lY definieren die linke obere Ecke des Viewports. Die beiden anderen Parameter bestimmen die Dimension des Viewports. Anschließend weisen wir den definierten Viewport dem Direct3DDevice zu. With g_d3drcViewport(0) .X1 = 0: .Y1 = 0 .X2 = 640 .Y2 = 480 End With
Diese 3D-RECT-Struktur benötigen wir nur, um zum späteren Zeitpunkt den Viewport über die Direct3DDevice7.Clear()-Methode zu bereinigen. (Wird gleich noch genauer erklärt.) g_dx.IdentityMatrix matView
Die DirectX7.IdentityMatrix()-Methode erstellt eine identische Matrix. Die Koeffizienten dieser Matrix sind mit »0« gefüllt, mit Ausnahme der Einträge rc11, rc22, rc33 und rc44. Diese Einträge haben den Wert 1. Diese Matrix ist die Ausgangsmatrix für Transformationen wie Rotation. Call g_dx.ViewMatrix(matView, MakeVector(0, 0, -15), _ MakeVector(0, 0, 0), MakeVector(0, 1, 0), 0)
Hiermit wird eine Viewmatrix erstellt. Sie basiert auf der aktuellen Kameraposition. DirectX7.ViewMatrix() beinhaltet vier Parameter. vFrom As D3DVector bestimmt die Position, an der die Kamera steht. vTo As D3DVector legt fest, wohin die Kamera ausgerichtet ist. vUp As D3DVector beschreibt, wie sich die 3D-Welt zur Kamera verhält. Für gewöhnlich steht dieser Wert auf [0,1,0]. Experimentieren Sie mit diesen Werten. Die Effekte sind verblüffend und durchaus einsetzbar. Der letzte Parameter heißt roll As Single. Mit ihm können Sie einen Winkel angeben, auf den die Kamera (um die Blickrichtung) rotiert werden soll. g_d3dDevice.SetTransform D3DTRANSFORMSTATE_VIEW, matView
Die Direct3DDevice7.SetTransform()-Methode weist eine einzelnen Transformation dem Device zu. Diese Methode besitzt zwei Parameter. Zum einen transformType as CONST_D3DTRANSFORMSTATETYPE. Die wichtigsten Definitionen sind D3DTRANSFORMSTATE_WORLD, D3DTRANSFORMSTATE_ VIEW, und D3DTRANSFORMSTATE_PROJECTION. Der zweite Parameter verlangt eine Matrix As D3DMATRIX. matView wurde von uns als D3DMATRIX definiert und jetzt für Transformationen zur Verfügung gestellt.
Kapitel 2 • Direct3D
115
g_dx.IdentityMatrix matProj Call g_dx.ProjectionMatrix(matProj, 1, 100, 3.14159 / 2) _ g_d3dDevice.SetTransform D3DTRANSFORMSTATE_PROJECTION,_ matProj
Die Projektionsmatrix berechnet, von wo (nearPlane As Single) und bis wo (farPlane As Single) Objekte im 3D-Raum dargestellt werden. Zusätzlich können Sie die Blickwinkel (fov As Single) des Betrachters (Kamera) einstellen. Natürlich wird auch eine Matrix (mDest As D3DMATRIX) verlangt. g_d3dDevice.SetRenderTarget g_ddsBackBuffer
Mit der Direct3DDevice7.SetRenderTarget()-Methode legen Sie das Ziel zum Rendern fest. Der einzige Parameter dieser Methode verlangt eine gültige Surface. Schritt 3: Koordinaten für das Dreieck bestimmen g_dx.CreateD3DVertex 2.5, -2.5, 0, 0, 0, -1, 0, 0, Vertex(0) g_dx.CreateD3DVertex -2.5, -2.5, 0, 0, 0, -1, 0, 0, Vertex(1) g_dx.CreateD3DVertex 0, 2.5, 0, 0, 0, -1, 0, 0, Vertex(2)
Die Koordinaten für einen Punkt in einem 3D-Raum werden in Vektoren organisiert. Vertex übersetzt heißt Spitze oder Scheitelpunkt. Die DirectX7.Create D3Dvertex()-Methode erfasst die relevanten Daten eine Punktes (Spitze) im 3DRaum. Die ersten drei (x As Single, y As Single und z As Single) Parameter sind die absoluten Werte im 3D-Raum, welche den Punkt beschreiben. Die folgenden drei Parameter (nx As Single, ny As Single und nz As Single) beschreiben die Orientierung (Ausrichtung) des Normalvektors. Der Normalvektor ist ein senkrechtes Lot auf die Dreiecksflächen (Eigentlich von den Vertexen eines Dreiecks). Er gewinnt an Bedeutung in Verbindung mit Lichteinflüssen. Es folgen die nächsten beiden Parameter tu As Single und tv As Single. Dies sind Texturkoordinaten und für den jetzigen Zeitpunkt noch uninteressant. Der letzte Parameter v As D3DVertex verlangt eine Vertexvariable. Diese haben wir bereits dimensioniert und sie wird jetzt zugewiesen. Schritt 4: Zeichnen des Dreiecks g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET, _ RGB(255, 0, 0), 0, 0
Die Direct3DDevice7.Clear()-Methode ermöglicht das Löschen des Viewports (oder Teilen des Viewports) mit einer bestimmten Farbe. Des Weiteren können Sie den Z Buffer und den Stencil Buffer löschen. Wir benötigen sie zum Löschen des Viewports. count As Long enthält die Anzahl der Rechtecke des folgenden recs As D3DRECT-Arrays. Der dritte Parameter flags As CONST_ D3DCLEARFLAGS bestimmt das Ziel, welches Sie löschen wollen. Zur Auswahl stehen 3DCLEAR_TARGET, D3DCLEAR_STENCIL und D3DCLEAR_
116
Zeichnen eines Dreiecks
ZBUFFER. Der Parameter color As Long versteht sich von alleine. Natürlich wird hier die Farbe definiert, mit welcher der Viewport gelöscht werden soll. Am besten nutzen Sie die DirectX7.CreateColorRGBA()-Methode. Alternativ können Sie auch die normale RGB()-Methode nutzen. Die letzten beiden Parameter z und stencil sind noch uninteressant und werden auf den Wert »0« gesetzt. g_d3dDevice.BeginScene
Mit der Direct3DDevice7.BeginScene()-Methode leiten Sie das Rendern einer Szene ein. Es sind keine Parameter zu berücksichtigen. g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, D3DFVF_VERTEX, Vertex(0), 3, D3DDP_WAIT
Um das Dreieck zu rendern, bedienen wir uns der Direct3DDevice7.Draw Primitive()-Methode. g_d3dDevice.EndScene
Das Ende einer Szene wird mit der Direct3DDevice7.EndScene()-Methode markiert. g_ddsPrimary.Flip Nothing, DDFLIP_WAIT
Zum Abschluss bleibt nur noch eins zu tun. Mit der bekannten Flip()-Methode kopieren wir die gerenderte Szene vom Backbuffer auf die sichtbare primäre Surface. Beispiel Dreieck Unser Beispielprogramm zum Darstellen eines einfachen Dreiecks, ohne Berücksichtigung von Material und Licht, beginnt mit der Subroutine Form_Load(). Im allgemeinen Deklarationsabschnitt finden Sie alle verwendeten Variablen des Programms. Private Declare Function GetAsyncKeyState Lib "user32" (ByVal _ vKey As Long) As Integer
Diese allgemein zugängliche API-Methode verwenden wir, um das Programm über die Escape-Taste zu beenden. Natürlich könnte dieses auch mit DirectInput erledigt werden, würde aber die Transparenz des Beispielprogramms verschleiern und der eigentliche Kontext ginge verloren. Somit haben wir uns für eine einfachere Methode entschieden. Dim g_dx As New DirectX7 Dim g_dd As DirectDraw7 Dim g_d3d As Direct3D7
Kapitel 2 • Direct3D
117
Initialisierung der DirectX-Knotenpunkte. Dim ddsd As DDSURFACEDESC2 Dim g_ddsPrimary As DirectDrawSurface7 Dim g_ddsBackBuffer As DirectDrawSurface7
Surfaces definieren. ddsd dient als zentrale Surfacebeschreibung. Dim g_d3dDevice As Direct3DDevice7 Dim vPort As D3DVIEWPORT7 Dim g_d3drcViewport(0) As D3DRECT
Direct3D-Objekte dimensionieren. Dim matProj As D3DMATRIX Dim matView As D3DMATRIX
Die notwendigen Matrizen festlegen. (In diesem Beispiel wird auf die Weltmatrix verzichtet.) Dim Vertex(2) As D3DVERTEX
Das Vertex-Array wird die drei Eckpunkte des Dreiecks aufnehmen. Private Sub Form_Load() InitDDraw InitD3D
Nach dem Starten des Programms wird zuerst in die Initialisierungsroutinen InitDDraw() und InitD3D() verzweigt. Diese werden nicht mit aufgelistet, da sie in dem vorherigem Abschnitt erklärt sind. g_dx.CreateD3DVertex 2.5, -2.5, 0, 0, 0, -1, 0, 0, Vertex(0) g_dx.CreateD3DVertex -2.5, -2.5, 0, 0, 0, -1, 0, 0, Vertex(1) g_dx.CreateD3DVertex 0, 2.5, 0, 0, 0, -1, 0, 0, Vertex(2)
Anschließend erstellen wir die Eckpunkte des Dreiecks. Diese werden in den Array-Elementen Vertex(0 bis 2) gespeichert. Do g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET, _ &HFF, 0, 0 g_d3dDevice.BeginScene 'Anfang Szene g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, _ D3DFVF_VERTEX, Vertex(0), 3, D3DDP_WAIT g_d3dDevice.EndScene 'Ende Szene g_ddsPrimary.Flip Nothing, DDFLIP_WAIT Loop Until GetAsyncKeyState(vbKeyEscape) <> 0
In der Do...Loop Until GetAsyncKeyState(vbKeyEscape) <> 0-Schleife tun wir Folgendes. Mit der Clear()-Methode löschen wir den gesamten Viewport.
118
Dreieck-Raster-Regeln
Anschließend starten wir eine neue Szene mit der BeginSzene()-Methode. Das eigentliche Dreieck wird mit der DrawPrimitive()-Methode gerendert. Jetzt bleibt nur noch, die aktuelle Szene mit der EndScene()-Methode zu beenden und auf die primäre Surface zu kopieren. g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_NORMAL g_dd.RestoreDisplayMode Set g_dd = Nothing Set g_d3dDevice = Nothing Set g_dx = Nothing End
Die Do...Loop Schleife läuft so lange, bis die Escape-Taste gedrückt wird. Ist dies der Fall, sorgen wir für ein ordentliches Verlassen des Programms. End Sub
2.4
Dreieck-Raster-Regeln Oft ist es so, dass die Koordinaten, welche einen Scheitelpunkt beschreiben, die Pixel des Bildschirms nicht genau treffen. Wenn dies passiert, werden die Dreieck-Raster-Regeln angewendet. Sie bestimmen welche Pixel des Bildschirms zu der erstellten Figur gehören. Direct3D baut die Figuren immer von links oben nach rechts unten (top-left filling convention) auf. Dies ist die gleiche Technik, wie sie von GDI und OpenGL benutzt wird. Direct3D geht immer davon aus, dass die Koordinaten das Zentrum eines Pixel beschreiben. Ist das Zentrum innerhalb eines Dreiecks so, ist das Pixel ein Teil des Dreiecks. Pixelzentren werden immer als Ganzzahl (Integer) angegeben. Folgende Grafik zeigt eine Matrix mit 25 Pixeln. Sie beginnt mit (0, 0) und endet mit (5, 5). Die Breite des Rechtecks wird beschrieben mit: Rechts minus Links. Die Höhe wird beschrieben durch: Unten minus Oben. Die top-left filling convention besagen, das eine Kante keine obere Kante (top edge) sein kann, außer sie verläuft horizontal. An der Grafik oben können Sie erkennen, wann eine Kante als top Edge bezeichnet wird. Nun wird es selten vorkommen, das eine Kante horizontal verläuft. Somit haben die meisten Dreiecke nur eine linke und rechte Kante. Sollten Sie in Ihrem Koordinatensystem zwei Dreiecke definieren, welche teilweise die gleichen Pixel verwenden, so werden die gemeinsamen Pixel dem ersten Dreieck zugeordnet. Siehe Grafik. Die gemeinsamen Pixel in der Diagonalen von links oben nach rechts unten werden Dreieck 1 zugeordnet, da dieses früher definiert wurde. Die Scheitelpunkte (Spitzen) der Dreieck sind wie folgt definiert.
Kapitel 2 • Direct3D
Bild 2.5:
119
Pixeldarstellung eines Rechtecks
0 Top Edge
1
2
3
4
5
0 1 2
keine obere Kante
3
würde als rechte Kante beschrieben
4 5 Bild 2.6:
Obere Kante
120
World-, View- und Projection-Matrix
Dreieck 1
Dreieck 2 Bild 2.7:
Pixelzuweisung
Dreieck 1: (0, 0) ; (5, 0) ; (5, 5) Dreieck 2: (0, 0) ; (5, 5) ; (0, 5)
2.5
World-, View- und Projection-Matrix Das zweidimensionale Computerbild, welches wir auf dem Monitor zu sehen bekommen, wird durch die Welt-Matrix, Sicht-Matrix sowie Projektions-Matrix bestimmt. Alle 3D-Grafiken haben mit einem gemeinsamen Problem zu kämpfen. Wie stellt man ein 3D-Objekt auf einer 2D-Fläche dar? Die wichtigste Grundlage für 3D-Applikationen bildete das Koordinatensystem. Das kartesische Koordinatensystem mit drei Dimensionen x, y und z bildet die Basis für Direct3D. Die Beschreibung und Berechnung unserer dreidimensionalen Welt findet zunächst nur im Speicher des Computers statt, ohne dass eine visuelle Ausgabe erfolgt. Damit eine ordentliche 2D-Ausgabe über den Monitor erfolgen kann, nutzten alle Objekte dieser Welt drei verschiedene Koordinatensysteme. Sie bedienen sich drei verschiedener Matrizen. •
World-Matrix (World Transformation) Jedes Objekt in der 3D-Welt hat ein eigenes Koordinatensystem. So werden die Koordinaten für das Objekt relativ zu seinem eigenen Ursprung (vollkommen unabhängig von den Weltkoordinaten) definiert. Über die Welt-Transformation werden diese Objekte in das Gefüge der Weltkoordinaten eingefügt.
Kapitel 2 • Direct3D
121
lokale Koordinaten
Y
Y
Z
Y Z
X Z X Weltkoordinaten Bild 2.8:
•
X
Lokale Objektkoordinaten in dem Weltkoordinatensystem
View-Matrix (View-Transformation) Die View-Transformation ermittelt den Betrachter (die Kamera) in der 3DWelt und transformiert die Polygone wie sie der Betrachter mit seiner aktuellen Blickrichtung sehen würde. Ein wesentlicher Faktor ist die Tiefe (welche Objekte werden durch andere Objekte für den Betrachter verdeckt) des Objektes im 3D-Raum. Beachten Sie, dass für diese Berechnungen das linkshändige Koordinatensystem (siehe Koordinatensystem) zugrunde gelegt wird. Es gibt viele Wege um eine View-Matrix zu erstellen. In allen Fällen hat die Kamera eine logische Position und eine logische Orientierung im 3D-Raum. Das ist der Ursprung der View-Matrix. Die View-Matrix übersetzt und rotiert die Objekte einer 3D-Welt so, wie Sie der Betrachter sehen würde. hintere Seite
vordere Seite
3D Welt Bild 2.9:
3D-Welt mit den Sichtbegrenzungen
122
Matrix-Berechnungen
•
2.6
Projektions-Matrix (Projektion-Transformation) Die Projektions-Transformation ist für die richtige perspektivische Darstellung des 3D-Raums auf den 2D-Monitor zuständig. Die Objekte im 3D-Raum sind in einem würfelähnlichem Gebilde definiert. Die vordere Seite des Gebildes ist kleiner als die hintere Seite. Vergleichbar ist dieses Gebilde mit einer Pyramide, bei der die Spitze abgeschnitten wurde. Da solch ein Gebilde nicht einfach auf eine zweidimensionale Fläche übertragbar ist, wird es über die ProjektionsMatrix berechnet.
Matrix-Berechnungen Matrizen werden Ihnen vielleicht etwas fremdartig anmuten. Dennoch werden wir uns mit diesem Thema beschäftigen müssen. Matrizen sind die Basis für Ihre gesamte 3D-Welt. Matrizen werden in D3D als einheitliche 4 X 4-Matrix repräsentiert. Hierzu dient das D3DMATRIX (siehe 3D-Koordinatensystem) Typen-Array. 3D-Transformation (Umformung) ist der Schlüssel zu allen Aktionen im 3DRaum. Mit der Matrix-Transformation bestimmen Sie die Größe sowie die Position eines Objektes (relativ zu den Weltkoordinaten). Sie definieren die Position, Blickrichtung und Perspektive des Betrachters. Sie können Objekte in Bezug auf Rotation oder Verzerrung beeinflussen. Um es auf einen Nenner zu bringen, mit der Matrix-Transformation bestimmen Sie alle Berechnungen zum Navigieren im 3D-Raum, sowie das Verhalten aller Objekte relativ zum 3D-Raum. Sie können jeden Punkt im 3D-Raum in einen anderen transformieren. Sie nutzen dann die homogene 4 X 4-Matrix. [x’ y’ z’ 1] = [x y z 1]
M11 M21 M31 M41
M12 M22 M32 M42
M13 M23 M33 M43
M14 M24 M34 M44
x’ = (x * M11) + (y * M21) + (z * M31) + (1 * M41) y’ = (x * M12) + (y * M22) + (z * M32) + (1 * M42) z’ = (x * M13) + (y * M23) + (z * M33) + (1 * M43)
2.6.1
Translation Um ein Objekt im 3D-Raum zu positionieren, müssen die Koordinaten auf die aktuellen Welt-Koordinaten übersetzt werden. Hierzu können Sie folgende Subroutine nutzen. Sub TranslateMatrix(m As D3DMATRIX, v As D3DVECTOR) Call dx.IdentityMatrix(m) m.rc41 = v.x m.rc42 = v.y m.rc43 = v.z End Sub
Kapitel 2 • Direct3D
123
Diese Routine können Sie explizit in Ihrem Quelltext einfügen oder sie binden das Math.bas Modul ein. Als Matrix sieht die Übersetzung so aus : [x’ y’ z’]=[x y z]
2.6.2
1 0
0 1
0 0
0 0
0 TX
0 TY
1 TZ
0 1
Rotation Jedes Objekt im 3D-Raum besitzt drei Achsen. Um jede dieser Achsen kann das Objekt rotieren. Diese Rotation können Sie für eine effektreiche Gestaltung Ihrer 3D-Welt einsetzen. Denken Sie dabei einfach an die Rotation eines Deckenventilators. Die Rotationsberechnungen sind aber auch notwendig, um ein Objekt im 3D-Raum zu platzieren. Die Rotationsberechnungen werden mit Hilfe von Matrizen vorgenommen. Bevor wir zu den eigentlichen Berechnungen kommen, schauen Sie sich die folgenden Methoden an. Diese Methoden erleichtern die Matrizenrechnungen und werden von DirectX zur Verfügung gestellt. RotateXMatrix() Rotiert den Punkt (x,y,z) um die X-Achse und erzeugt den neuen Punkt (x’,y’,z’). object.RotateXMatrix(mDest As D3DMATRIX, radians As Single) object
ein gültiges DirectX7-Objekt
mDest
Nimmt die transformierten Koordinaten des Punktes (x,y,z) auf.
radians
Der Winkel der Rotation um die X-Achse. Wird angegeben im Uhrzeigersinn um die X-Achse (betrachtet vom Ursprung der Achse).
RotateYMatrix() Rotiert den Punkt (x,y,z) um die Y-Achse und erzeugt den neuen Punkt (x’,y’,z’). object.RotateYMatrix(mDest As D3DMATRIX, radians As Single) object
ein gültiges DirectX7-Objekt
mDest
Nimmt die transformierten Koordinaten des Punktes (x,y,z) auf.
radians
Der Winkel der Rotation um die Y-Achse wird angegeben im Uhrzeigersinn um die Y-Achse (betrachtet vom Ursprung der Achse).
124
Matrix-Berechnungen
RotateZMatrix() Rotiert den Punkt (x,y,z) um die Z-Achse und erzeugt den neuen Punkt (x’,y’,z’). object.RotateZMatrix(mDest As D3DMATRIX, radians As Single) object
ein gültiges DirectX7-Objekt
mDest
Nimmt die transformierten Koordinaten des Punkes (x,y,z) auf.
radians
Der Winkel der Rotation um die Z-Achse. Wird angegeben im Uhrzeigersinn um die Z-Achse (betrachtet vom Ursprung der Achse).
Die folgenden drei Matrizen beschreiben die Rotationsmöglichkeiten um die XAchse, Y-Achse sowie Z-Achse. Als DirectX-Programmierer sind Sie nicht zwingend darauf angewiesen, diese Berechnungen direkt an Matrizen vorzunehmen. Sie können auf die oben vorgestellten Rotationsmethoden RotateZMatrix(), RotateZMatrix() und RotateZMatrix() zurückgreifen. Dennoch ist es hilfreich, zu wissen was diese Methoden eigentlich tun. •
Rotation um die X-Achse
[x’ y’ z’]=[x y z] 1
•
0 cosθ
0 sinθ
0 0
0 0
-sinθ 0
cosθ 0
0 1
cosθ 0
0 1
-sinθ 0
0 0
sinθ 0
0 0
cosθ 0
0 1
cosθ -sinθ
sinθ cosθ
0 0
0 0
0 0
0 0
1 0
0 1
Rotation um die Y-Achse
[x’ y’ z’]=[x y z]
•
0 0
Rotation um die Z-Achse
[x’ y’ z’]=[x y z]
Das griechische Zeichen Theta (θ) steht für den Rotationsgrad (Radiant-Winkel). Der Winkel wird im Uhrzeigersinn gemessen, entlang der entsprechenden Achse) Die Umsetzung auf die D3D-Matrix sieht für eine Rotation der X-Achse so aus: Sub CreateXRotation(ret As D3DMATRIX, rads As Single) Call dx.IdentityMatrix(ret) ret.rc22 = Cos(rads)
Kapitel 2 • Direct3D
125
ret.rc23 = Sin(rads) ret.rc32 = – Sin(rads) ret.rc33 = Cos(rads) End Sub
Glücklicherweise kann der VB-Programmierer vorgefertigte Methoden von Direct3D nutzen. Für die Rotation der drei Achsen stehen die Methoden DirectX7.RotateXMatrix(), DirectX7.RotateYMatrix() sowie DirectX7.RotateZMatrix() bereit. Diese Methoden beinhalten zwei Parameter. mDest As D3DMATRIX dient als Empfänger der Transformation. Radians As Single gibt den Winkel der Rotation an. Es folgt die Syntax der Methoden: object.RotateXMatrix(mDest As D3DMATRIX, radians As Single) object.RotateYMatrix(mDest As D3DMATRIX, radians As Single) object.RotateZMatrix(mDest As D3DMATRIX, radians As Single)
Beispiel (Rotation um die Y-Achse) Dieses Beispiel ist im Wesentlichen identisch mit der Applikation zum Erstellen eines Dreiecks. Wiederum werden wir Material und Licht gänzlich ignorieren. Wichtig ist es zu erwähnen, dass wir ein einzelnes Objekt im 3D-Raum rotieren lassen. Dies ist komplizierter, als die gesamte 3D-Welt rotieren zu lassen. Auch dieses Demo können wir mit der Escape-Taste verlassen. Da sich in unserem Rotationsbeispiel im Vergleich zur Darstellung eines einfachen Dreiecks kaum Änderungen einstellen, betrachten wir nur die Form_Load()-Subroutine. Diese enthält alle relevanten Aufgaben. Private Sub Form_Load() InitDDraw InitD3D
Die beiden Initialisierungsroutinen beinhalten keine Änderungen und brauchen nicht weiter erklärt werden. g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex
2.5, -2.5, 0, 0, 0, -1, 0, 0, Vertex(0) -2.5, -2.5, 0, 0, 0, -1, 0, 0, Vertex(1) 0, 2.5, 0, 0, 0, -1, 0, 0, Vertex(2) 7.5, -2.5, 0, 0, 0, -1, 0, 0, Vertex(3) 2.5, -2.5, 0, 0, 0, -1, 0, 0, Vertex(4) 5, 2.5, 0, 0, 0, -1, 0, 0, Vertex(5)
Quasi als Beweis, dass wir ein Objekt drehen und nicht die ganze 3D-Welt, erstellen wir zwei Dreiecke. Ein Dreieck wird gedreht, das andere nicht. Dim Winkel As Single Dim ObjectMatrix(2) As D3DMATRIX g_dx.IdentityMatrix ObjectMatrix(0) g_dx.IdentityMatrix ObjectMatrix(1)
126
Matrix-Berechnungen
Wir erstellen zwei einheitliche Matrizen. ObjectMatrix(0) wird dem rotierendem Dreieck zugeordnet. Do Winkel = Winkel + 1: If Winkel > 360 Then Winkel = 0 g_dx.RotateYMatrix ObjectMatrix(0), Winkel / 57.296
Über den Ausdruck Winkel / 57.296 erfolgt die Umrechnung des in Grad angegebenen Winkels in Radiant. Der Wert 57.296 ergibt sich aus 180o geteilt durch die Kreiszahl PI(3.14159...). Hier lassen wir die ObjectMatrix(0) immer um ein Grad weiter rotieren. g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET, _ _ &HFF, 0, 0 g_d3dDevice.BeginScene g_d3dDevice.SetTransform D3DTRANSFORMSTATE_WORLD, _ ObjectMatrix(0)
Jetzt wird es wirklich interessant. Wir transformieren die World Matrix auf die manipulierte Matrix von Dreieck 1. Diese Matrix wird bei jedem Durchlauf der Do...Loop Schleife neu berechnet. g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, _ D3DFVF_VERTEX, Vertex(0), 3, D3DDP_WAIT
Nachdem wir die ganze Welt etwas gedreht haben, rendern wir mit der Draw Primitive()-Methode das erste Dreieck. g_d3dDevice.SetTransform D3DTRANSFORMSTATE_WORLD, _ ObjectMatrix(1)
Das zweite Dreieck soll nicht rotieren. Deshalb transformieren wir die WorldMatrix zurück auf den Ausgangswert. Löschen Sie diese Zeile aus dem Quelltext, dann rotiert die gesamte Welt. Somit auch alle Objekte in der Welt. g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, _ D3DFVF_VERTEX, Vertex(3), 3, D3DDP_WAIT
Nachdem die Welt wieder gerade gerückt wurde, können wir das zweite Dreieck zeichnen. g_d3dDevice.EndScene g_ddsPrimary.Flip Nothing, DDFLIP_WAIT Loop Until GetAsyncKeyState(vbKeyEscape) <> 0
Die Vorgehensweise wird so lange wiederholt, bis die Escape-Taste gedrückt wird. Fassen wir noch einmal zusammen. Die Technik besteht aus fünf Schritten.
Kapitel 2 • Direct3D
127
•
Mit Hilfe der Hilfsmatrix ObjectMatrix(0) wird die gesamte Welt gedreht.
•
Nachdem die Welt gedreht wurde, wird das erste Objekt gerendert.
•
Die Welt wird auf die Ausgangswerte zurück gesetzt. Dazu dient uns Object Matrix(1). Wir könnten auch jedes Mal die IdentitiyMatrix()-Methode aufrufen.
•
Nachdem die Welt wieder in Ordnung ist, wird das zweite Objekt gerendert.
•
Anschließend wird die gerenderte Szene auf die primäre Surface geflippt.
g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_NORMAL g_dd.RestoreDisplayMode Set g_dd = Nothing Set g_d3dDevice = Nothing Set g_dx = Nothing End
Wir sorgen dafür, dass wir das Programm ordentlich verlassen. End Sub
Sicherlich stellen Sie sich die Frage: Warum ist das Dreieck nur von einer Seite sichtbar? Das ist kein größeres Problem. Es gibt zwei Wege zur Lösung. Der eine Weg ist, einfach ein weiteres Dreieck an die gleichen Koordinaten zu zeichnen. Bei diesem Dreieck müssen die Vektoren gegen den Uhrzeigersinn angegeben werden. Dadurch wird der Normalvektor entgegen dem Normalvektor des ersten Dreiecks erzeugt. Der zweite Weg benutzt den Cull-Status. Über den Cull-Status können Sie definieren, welche Seite sichtbar sein soll bzw. ob beide Seiten sichtbar sein sollen. Beispiel (Rotation 2) In dem ersten Rotationsbeispiel haben wir ein Objekt um den Ursprung der 3DWelt erstellt. Anschließend haben wir die Welt gedreht und das Objekt an der richtige Position in der 3D-Welt platziert. Diese Technik ist eine äußerst schnelle Technik. Leider bringt Sie auch Nachteile mit sich. Da das Objekt eigentlich an den Koordinaten [0, 0, 0] steht und nachträglich in der Welt positioniert wird, werden die aktuellen Lichteinflüsse falsch berücksichtigt. Aus diesem Grund haben wir uns entschieden, Ihnen eine weitere Technik zu präsentieren. Die neue Technik ist nicht ganz so schnell wie die alte Technik, sie ergibt aber eine realistischere Darstellung der Szene. Im Beispiel zum Nebeleffekt werden wir die Technik richtig nutzen. Jetzt begnügen wir uns mit der eigentlichen Rotation. Betrachten Sie zuerst das Bildschirmfoto. Sie werden zwei Dreieck erkennen; das linke Dreieck rotiert, das rechte Dreieck ist statisch.
128
Matrix-Berechnungen
Bild 2.10: Bildschirmfoto Rotation 2
Unser Ziel ist es, ein Objekt im 3D-Raum zu platzieren und dann an Ort und Stelle rotieren zu lassen. Um dies zu erreichen, müssen wir die Vertexe des Objektes manipulieren. Wir lassen alle Vertexe um einen Mittelpunkt drehen. Der Mittelpunkt ist insofern wichtig, da er den Bezugspunkt für das gesamte Objekt darstellt. Wenn wir einen Mittelpunkt wählen, welcher nicht das Zentrum des Objektes darstellt, sondern z.B. außerhalb des Objektes liegt, so wird das Objekt wie ein Satellit den Punkt umkreisen. Wollen wir eine Rotation ohne dass sich die Position des Objektes ändert, so müssen wir das genaue Zentrum des Objektes als Rotationsmittelpunkt festlegen. Bei komplexeren Objekten hilft es Ihnen, wenn Sie zur Ermittlung des Mittelpunkes die kleinsten und größten x-, y-, z-Koordinaten ermitteln und davon die Mitte wählen. Mitte_X = (Größter_X – Kleinster_X) / 2 Mitte_Y = (Größter_Y – Kleinster_Y) / 2 Mitte_Z = (Größter_Z – Kleinster_Z) / 2
Diese übergeben wir an eine Variable vom Typ D3DVECTOR. Dim Mitte Mitte.x = Mitte.y = Mitte.z =
As D3DVECTOR Mitte_X Mitte_Y Mitte_Z
Kapitel 2 • Direct3D
129
Anschließend übergeben wir die x-, y-, z-Werte der Vertexe einer Variablen vom Typ D3DVECTOR. Dim Temp1 Temp1.x = Temp1.y = Temp1.z =
As D3DVECTOR Vertex(n).x Vertex(n).y Vertex(n).z
Jetzt benötigen wir noch die Variable Temp2 vom Typ D3DVECTOR. In dieser Variablen werden wir die transformierten x-, y-, z-Koordinaten zwischenspeichern. Nun können wir die Rotation()-Subroutine aufrufen. Wir übergeben folgende Parameter: Rotation Temp1, Temp2, Mitte, Winkelveränderung
Der letzte Parameter Winkelveränderung definiert, um wie viel Grad sich das Objekt drehen soll. Die Rotation()-Subroutine sieht so aus: Public Sub Rotation(VecIn As D3DVECTOR, VecOut As D3DVECTOR, _ Mitte As D3DVECTOR, ByVal Winkelveränderung As Single) Dim RMat As D3DMATRIX Dim PMat As D3DMATRIX Dim DMat As D3DMATRIX g_dx.IdentityMatrix Rmat g_dx.IdentityMatrix Pmat g_dx.IdentityMatrix DMat g_dx.RotateYMatrix RMat, Winkel / 57.296 PMat.rc41 = VecIn.x – Mitte.x PMat.rc42 = VecIn.y – Mitte.y PMat.rc43 = VecIn.z – Mitte.z RMat.rc41 = Mitte.x RMat.rc42 = Mitte.y RMat.rc43 = Mitte.z g_dx.MatrixMultiply DMat, PMat, Rmat VecOut.x = DMat.rc41 VecOut.y = DMat.rc42 VecOut.z = DMat.rc43 End Sub
Das Ergebnis der Rotation erhalten wir in dem VecOut-Vektor. Diesen haben wir als Temp2-Vektor übergeben und können die manipulierten Daten dem originalen Vertex wieder zuweisen. Vertex(n).x = Temp2.x Vertex(n).y = Temp2.y Vertex(n).z = Temp2.z
130
Matrix-Berechnungen
Beim nächsten Rendern der Szene macht sich die Manipulation der Vertexe bemerkbar. Das Objekt wird sich mit jedem Durchlauf der Rotation()-Subroutine um ein Grad mehr drehen. In unserem Beispiel wenden wir diese Technik auf ein Dreieck an. Das Dreieck hat drei Vertexe. Wir können natürlich auch ein Objekt wählen, welches aus eintausend (oder mehr) Vertexen konstruiert wurde. Irgendwann wird sich dieses Verfahren als zu langsam entpuppen, aber dann können Sie immer noch auf die erste Technik zurückgreifen. Wann diese Technik zur Bremse wird, hängt von der CPU-Performance des eingesetzten PC ab. Der Vorteil dieser Technik ist jedoch offensichtlich. Da das Objekt an Ort und Stelle in der 3D-Welt gedreht wird, werden auch die Licht- und Schattenberechnungen auf das Objekt angewandt. Dadurch wirkt das Objekt wesentlich realistischer. In unserm jetzigen Beispiel bermerken Sie keinen Unterschied. Dies liegt natürlich daran, das wir die Lichteinflüsse einer Szene sowie die Materialeigenschaften des Dreiecks nicht berücksichtigen. Unser Nebelbeispiel verwendet diese Technik. Dort können Sie die Einflüsse von Licht und Schatten bestens beobachten.
2.6.3
Scaling Mit der Scaling-Matrix können Sie den Maßstab von jedem Punkt mit einem beliebigen Wert transformieren. Somit können Sie die Größe eines Objektes ändern. [x’ y’ z’]=[x y z]
ScaleX 0 0 0 ScaleY 0 0 0
0 0
0 0
ScaleZ 0 0 1
Beispiel (Scaling) Mit dem Scaling-Beispiel erkennen Sie, wie Sie die Größe eines einzelnen Objektes im 3D-Raum verändern können. Betrachten Sie dazu das Bildschirmfoto und vergleichen dieses mit dem Bildschirmfoto unserer ersten Beispielanwendung. Wir ignorieren erneut Licht und Material des Objektes. Auch die Initialisierungsroutinen sind unkompliziert. Schauen wir uns direkt die Do...Loop-Schleife in der Form_Load()-Subroutine an. Verlassen können Sie das Programm mit der Escape-Taste. Bei diesem Beispielprogramm kann man schnell den Eindruck bekommen, als würden wir uns auf das Dreieck zubewegen und wieder entfernen. Das ist aber nicht der Fall. Wir verändern unsere Position nicht. Auch das Dreieck verändert seine Position nicht.
Kapitel 2 • Direct3D
131
Bild 2.11: Bildschirmfoto Scale Do If Richtung = 0 Then ScaleFaktor = ScaleFaktor + 0.1 Else ScaleFaktor = ScaleFaktor – 0.1 End If If ScaleFaktor > 6 Then Richtung = 1 If ScaleFaktor < 0 Then Richtung = 0
Hier lassen wir den Vergrößerungsfaktor (ScaleFaktor) zwischen 0 und 6 pendeln. ObjectMatrix(0).rc11 = ScaleFaktor ObjectMatrix(0).rc22 = ScaleFaktor
Diese unscheinbare Zuordnung des Vergrößerungsfaktors zu den Mitgliedsdaten rc11 und rc12 sorgen für die Änderung der Größe. g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET, _ &HFF, 0, 0 g_d3dDevice.BeginScene g_d3dDevice.SetTransform D3DTRANSFORMSTATE_WORLD, _ ObjectMatrix(0)
132
Polygone
Die transformierte Matrix ObjectMatrix(0) wird der Welt-Matrix zugewiesen. Mit der folgenden DrawPrimitive()-Methode wird das Objekt in den neuen Größenverhältnissen gerendert. g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, D3DFVF_VERTEX, _ Vertex(0), 3, D3DDP_WAIT g_d3dDevice.EndScene g_ddsPrimary.Flip Nothing, DDFLIP_WAIT Loop Until GetAsyncKeyState(vbKeyEscape) <> 0
2.7
Polygone Die Überschrift ist eigentlich falsch. Direct3D unterscheidet keine Polygontypen, sondern arbeitet nur mit einem Polygontyp. Die einzige Form eines Polygons, welches von D3D verwendet wird, ist das Dreieck. Mit dem Dreieck erstellen Sie alle Objekte einer 3D-Welt. Die Eckpunkte des Polygons werden in Vektoren organisiert. Unter Direct3D bedienen wir uns der Vertex-Strukturen. D3D stellt Ihnen verschiedene Techniken zur Verfügung, um entweder die Vertexe sichtbar zu machen oder miteinander zu verbinden. •
Pointlist Eine Punktliste ist eine Sammlung von Vertexen, welche als alleinstehender Punkt gerendert werden. Eine Punktliste sieht auf dem Monitor wie ein Sternenfeld aus. Eigentlich kann man dieser Technik nur wenig Bedeutung beimessen, dennoch lässt sich eine Punktliste aller Vertexe zur Entwicklungszeit eines Programms gut nutzen. Dim Verts(6) As D3DVERTEX Verts(0) = dx.CreateD3DVertex(0, 0, 0, 0, 0, -1, 0, 0) Verts(1) = dx.CreateD3DVertex(3, 3, 0, 0, 0, -1, 0, 0) Verts(2) = dx.CreateD3DVertex(6, 0, 0, 0, 0, -1, 0, 0) Verts(3) = dx.CreateD3DVertex(9, 3, 0, 0, 0, -1, 0, 0) Verts(4) = dx.CreateD3DVertex(12, 0, 0, 0, 0, -1, 0, 0) Verts(5) = dx.CreateD3DVertex(15, 3, 0, 0, 0, -1, 0, 0) Call d3ddev.DrawPrimitive(D3DPT_POINTLIST, D3DFVF_VERTEX, _ Verts(0), 6, D3DDP_WAIT)
Da die Tiefenwerte (Z-Achse) bei allen Punkten 0 ist, können wir die Punkte auf ein zweidimensionales Koordinatensystem übertragen und abbilden. Betrachen wir es einmal. Sie können zwar den einzelnen Punkten Material oder Texturen zuweisen, jedoch sind diese nur direkt auf dem Punkt sichtbar. Da wir hier von einem Monitorpixel sprechen, hat dies kaum einen Sinn. Was sich wohl die Entwickler von DirectX dabei gedacht haben?
Kapitel 2 • Direct3D
133
Y Achse
3,3,0 0,0,0
15,3,0
9,3,0 6,0,0
12,0,0 X Achse
Bild 2.12: Pointlist
•
Linelist Eine Linienliste ist ein Liste von geraden Linien. Dabei wird immer ein Vertex mit dem folgendem Vertex verbunden. Da eine Linie immer einen Anfangspunkt und einen Endpunkt, hat muss die Anzahl der verwendeten Vertexe ein Vielfaches von zwei sein. Eine Linelist können Sie hervorragend einsetzen, um z.B. starken Regen oder Schneeregen zu simulieren. Dim Verts(6) As D3DVERTEX Verts(0) = dx.CreateD3DVertex(0, 0, 0, 0, 0, -1, 0, 0) Verts(1) = dx.CreateD3DVertex(3, 3, 0, 0, 0, -1, 0, 0) Verts(2) = dx.CreateD3DVertex(6, 0, 0, 0, 0, -1, 0, 0) Verts(3) = dx.CreateD3DVertex(9, 3, 0, 0, 0, -1, 0, 0) Verts(4) = dx.CreateD3DVertex(12, 0, 0, 0, 0, -1, 0, 0) Verts(5) = dx.CreateD3DVertex(15, 3, 0, 0, 0, -1, 0, 0) Call d3ddev.DrawPrimitive(D3DPT_LINELIST, D3DFVF_VERTEX, _ Verts(0), 6, D3DDP_WAIT)
Y Achse
3,3,0 0,0,0
15,3,0
9,3,0 6,0,0
12,0,0 X Achse
Bild 2.13: Linelist
134
Polygone
Sie können den Linien Materialien und Texturen zuweisen. Diese sind aber nur auf der Linie sichtbar. Die Zwischenräume von einer Linie zur anderen bleiben unberührt. •
Linestrip Mit Linestrip (frei übersetzt: ein Streifen von Linien) verbinden Sie die Vertexe nacheinander. Sie können Linestrip nutzen, um Polygone zu erzeugen, welche nicht geschlossen sind. Ein geschlossenes Polygon ist nur dann geschlossen, wenn der letzte Punkt mit dem ersten Punkt verbunden ist. Dim Verts(6) As D3DVERTEX Verts(0) = dx.CreateD3DVertex(0, 0, 0, 0, 0, -1, 0, 0) Verts(1) = dx.CreateD3DVertex(3, 3, 0, 0, 0, -1, 0, 0) Verts(2) = dx.CreateD3DVertex(6, 0, 0, 0, 0, -1, 0, 0) Verts(3) = dx.CreateD3DVertex(9, 3, 0, 0, 0, -1, 0, 0) Verts(4) = dx.CreateD3DVertex(12, 0, 0, 0, 0, -1, 0, 0) Verts(5) = dx.CreateD3DVertex(15, 3, 0, 0, 0, -1, 0, 0) Call d3ddev.DrawPrimitive(D3DPT_LINESTRIP, D3DFVF_VERTEX, _ Verts(0), 6, D3DDP_WAIT)
Y Achse 3,3,0
0,0,0
9,3,0
6,0,0
15,3,0
12,0,0 X Achse
Bild 2.14: Linestrip
•
Trianglelist Die Dreiecksliste ist durchaus mit der Linienliste vergleichbar. Natürlich werden bei diesem Verfahren sofort ganze Dreiecke erzeugt. Dabei werden immer drei Vertexe genommen, um ein Dreieck zu erstellen. Die Anzahl der Vertexe muss durch drei teilbar sein. Nutzen Sie diese Technik immer dann, wenn Sie Objekte erzeugen wollen, welche aus vielen einzelnen Teile bestehen. Auch für Spezialeffekte können Sie diese Technik nutzen. Wollen Sie z.B. einen Schutzschild erzeugen, dann platzieren Sie eine Vielzahl von kleinen Dreiecken vor dem Objekt. Belegen Sie die Dreiecke mit Material und Textur. Diese nehmen nun das Umgebungslicht auf und das Objekt im Hintergrund ist durch die Lücken der Dreiecke sichtbar.
Kapitel 2 • Direct3D
135
Dim Verts(6) As D3DVERTEX Verts(0) = dx.CreateD3DVertex(0, 0, 0, 0, 0, -1, 0, 0) Verts(1) = dx.CreateD3DVertex(3, 3, 0, 0, 0, -1, 0, 0) Verts(2) = dx.CreateD3DVertex(6, 0, 0, 0, 0, -1, 0, 0) Verts(3) = dx.CreateD3DVertex(9, 3, 0, 0, 0, -1, 0, 0) Verts(4) = dx.CreateD3DVertex(12, 0, 0, 0, 0, -1, 0, 0) Verts(5) = dx.CreateD3DVertex(15, 3, 0, 0, 0, -1, 0, 0) Call d3ddev.DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX, _ Verts(0), 6, D3DDP_WAIT)
Y Achse 3,3,0
0,0,0
9,3,0
6,0,0
15,3,0
12,0,0 X Achse
Bild 2.15: Trianglelist
Sie können die Dreiecke mit Material und Texturen überziehen. •
Trianglestrip Bei Trianglestrip handelt es sich um eine Serie von verbundenen Dreiecken. Das erste Dreieck wird aus den Vertexen eins, zwei und drei gebildet. Das folgende Dreieck wird aus den Vertexen zwei und drei des ersten Dreiecks sowie einem neuen Vertex gebildet. Dies setzt sich so fort. Beachten Sie, dass alle Vertexe eines Dreiecks im Uhrzeigersinn erstellt werden müssen. Ansonsten sind sie für den Betrachter nicht sichtbar. Dim Verts(6) As D3DVERTEX Verts(0) = dx.CreateD3DVertex(0, 0, 0, 0, 0, -1, 0, 0) Verts(1) = dx.CreateD3DVertex(3, 3, 0, 0, 0, -1, 0, 0) Verts(2) = dx.CreateD3DVertex(6, 0, 0, 0, 0, -1, 0, 0) Verts(3) = dx.CreateD3DVertex(9, 3, 0, 0, 0, -1, 0, 0) Verts(4) = dx.CreateD3DVertex(12, 0, 0, 0, 0, -1, 0, 0) Verts(5) = dx.CreateD3DVertex(15, 3, 0, 0, 0, -1, 0, 0) Call d3ddev.DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX, _ Verts(0), 6, D3DDP_WAIT)
136
Polygone
Y Achse 3,3,0
0,0,0
9,3,0
6,0,0
15,3,0
12,0,0 X Achse
Bild 2.16: Trianglestrip
Sie können die Dreiecke mit Material und Texturen überziehen. Diese Technik ist äußerst beliebt. Zum einen lassen sich komplexe Objekte erstellen, zum anderen ist dieses Verfahren speicherschonend und sehr schnell. Sie erreichen mit Trianglestrip die beste Performance. •
Trianglefan Die letzte Technik ist der Dreiecksfächer. Der Fächer hat einen Anfangspunkt, auf den sich alle folgenden Vertexe beziehen. Zwischen allen Vertexen werden Verbindungen geschlossen. Vertex 1 Vertex 2
Vertex 0
Vertex 3
Vertex 4 Vertex 7 Vertex 5 Vertex 6 Bild 2.17: Trianglefan Dim Verts(6) As D3DVERTEX Verts(0) = dx.CreateD3DVertex(1, 1, 0, 0, 0, -1, 0, 0) Verts(1) = dx.CreateD3DVertex(4, 8, 0, 0, 0, -1, 0, 0) Verts(2) = dx.CreateD3DVertex(6, 6, 0, 0, 0, -1, 0, 0)
Kapitel 2 • Direct3D
137
Verts(3) = dx.CreateD3DVertex(7, 4, 0, 0, 0, Verts(4) = dx.CreateD3DVertex(7, 2, 0, 0, 0, Verts(5) = dx.CreateD3DVertex(6, 0, 0, 0, 0, Call d3ddev.DrawPrimitive(D3DPT_TRIANGLEFAN, Verts(0), 6, D3DDP_WAIT)
-1, 0, 0) -1, 0, 0) -1, 0, 0) D3DFVF_VERTEX, _
4,8,0 Y Achse 6,6,0
7,4,0
7,2,0 1,1,0 6,0,0 X Achse Bild 2.18: Trianglefan
2.8
Licht Licht und Material eines Objektes im 3D-Raum sind als zusammenhängende Komponenten zu betrachten. Ein Objekt ohne Material kann durch einfallendes Licht nicht reflektiert werde. Ebenso wird ein Objekt mit Material aber ohne Licht immer schwarz bleiben. In diesem Abschnitt wollen wir uns auf die Einflüsse von Lichtquellen in einer 3D-Welt konzentrieren. Direct3D übernimmt die Berechnung von Licht und Material, dennoch ist der erfahrene Programmierer in der Lage, D3D so zu leiten, wie er es für notwendig hält. Der Umgang mit Beleuchtung und Material hat einen entscheidenden Anteil am Erscheinungsbild der gerenderten Szene. Material bestimmt, wie ein Objekt das einströmende Licht reflektieren soll. Direktes Licht oder indirektes Licht definieren die Lichtquellen, welche reflektiert werden sollen. Das Licht von D3D wird mathematisch berechnet. Anders als in der Natur, sind diese Berechnungen von ein paar überschaubaren Parametern abhängig. In der Natur wird eine Lichtquelle von tausenden Objekten reflektiert, bevor sie das Auge des Betrachters erreicht. Von jedem Lichtteilchen welches reflektiert wird, wird auch ein Teil vom reflektierendem Objekt aufgenommen. Andere Teilchen
138
Licht
werden in verschiedene Richtungen gestreut. Irgendwann gelangen einige Lichtteilchen zum Betrachter. D3D steht nun vor der unlösbaren Aufgabe, das natürliche Licht zu simulieren. Um das natürliche Licht möglichst perfekt zu simulieren und dennoch den Performanceansprüchen zu genügen, spaltet D3D jede Lichtquelle in ihre Rot-, Grün- und Blauanteile. Die endgültige Farbe eines Objektes ist eine mathematische Mischung von Lichtanteilen und Materialanteilen. D3D unterteilt Licht in zwei Gruppen: indirektes Licht (Ambientlight) und direktes Licht. Beide haben unterschiedliche Eigenschaften und agieren unterschiedlich mit der Materialoberfläche des Objektes. Indirektes Licht flutet die gesamte Welt mit einer definierten Lichtstärke und Lichtfarbe. Dieses Licht ist überall sichtbar. Es ist gut vergleichbar mit indirektem Licht beim Fotografen. Auch dieses Licht erhellt den gesamten Raum, ohne ein Objekt im besonderen Maße zu erhellen. Oftmals wird indirektes Licht (Ambientlight) dazu eingesetzt, um eine gewisse Grundhelligkeit aufrechtzuerhalten. Ambientlight verursacht keine spiegelnden (specular) Reflektionen eines Objektes. Direktes Licht in einer Szene hat immer einen Ursprung. Zu seinen Eigenschaften gehört Lichtstärke und Farbe. Zusätzlich wird dem direktem Licht eine Orientierung der Lichtstrahlen zugeordnet. (Dies gilt auch für ein Punktlicht (Pointlight). Die Richtung wird aber nicht explizit angegeben. Es strahlt in alle Richtungen wie z.B. die Sonne.) Die Richtung der Lichtquelle fließt in die Berechung für Schatten ein. Wird das direkte Licht von Objekten reflektiert, so bleibt die allgemeine Lichtstärke in der Szene davon unberührt. Welche Lichtart besser oder schlechter ist kann nicht beantwortet werden. Die beste Beleuchtung einer Szene werden Sie durch die Kombination aller Lichtmöglichkeiten erhalten. Indirektes Licht als Grundlicht und direktes Licht um Highlights zu erzeugen. Scheuen Sie nicht die Kombination verschiedener Lichtquellen, um auch nur ein Objekt richtig zu erhellen. Die Lichtfarbe wird durch das D3DCOLORVALUE-Typen-Array erfasst. Die Anteile von Rot, Grün, Blau sowie einer Alpha-Komponente ergeben die endgültige Farbe. Die Alpha-Komponente ermöglicht das Mischen der Farben mit dem Hintergrund. Type D3DCOLORVALUE a As Single b As Single g As Single r As Single End Type
Jede beliebige Farbe können Sie mit einem Wertebereich von b (Blau), g (Grün) und r (Rot) zwischen 0.0 und 1.0 bestimmen. Werte größer 1.0 erzeugen ein extrem starkes Licht, welches dazu neigt die Szene zu überblenden. Werte kleiner
Kapitel 2 • Direct3D
139
0.0 erzeugen ein Schwarzlicht. Dieses Schwarzlicht entfernt Licht aus einer Szene. Anzumerken ist, dass Licht die Alpha-Komponente ignoriert. Da das D3DCOLORVALUE Typen Array auch für die Materialfarbe genutzt wird, ist der Alphawert enthalten. Mit der Direct3Ddevice7.SetRenderState()-Methode können Sie das Licht einoder ausschalten. Das Ein- oder Ausschalten der Lichtberechnungen bezieht sich auf die gesamte Lichtberechnung von Direct3D. Ausschalten: Direct3Ddevice7.SetRenderState D3DRENDERSTATE_LIGHTING, 0
Einschalten: Direct3Ddevice7.SetRenderState D3DRENDERSTATE_LIGHTING, 1
2.8.1
Indirektes Licht (Ambientlight) Ambientlight können Sie mit der Direct3Ddevive7.SetRenderState()-Methode erstellen. Dieser Lichttyp ist unkompliziert, da wir zum Erzeugen lediglich zwei Parameter beachten müssen. Der erste Parameter heißt state. Zur Auswahl steht eine Konstante aus der CONST_D3DRENDERSTATETYPEListe. Für uns ist der Eintrag D3DRENDERSTATE_AMBIENT von Bedeutung. Der folgende Parameter renderstate ist von dem zuvor gewählten state Parameter abhängig. Beziehen wir dies auf unser Status D3DRENDERSTATE_AMBIENT, so wird nun eine Farbe erwartet. Diese erzeugen wir mit der DirectX7.CreateColorRGBA()-Methode. Direct3DDevice7.SetRenderState D3DRENDERSTATE_AMBIENT, _ DirectX7.CreateColorRGBA(1#, 1#, 1#, 1#)
Wenn Sie diese Befehlszeile Ihrem Programmcode hinzufügen, wird Ihre gesamte 3D-Welt mit einem einheitlichem weißen Licht geflutet. Natürlich werden Sie die Auswirkungen erst dann merken, wenn Sie Ihren Objekten Materialeigenschaften zugewiesen haben.
2.8.2
Direktes Licht Zur Verwendung von direktem Licht, stellt uns D3D drei unterschiedliche Lichtarten bereit: Punktlicht (Pointlight), Scheinwerferlicht (Spotlight), sowie eine richtungsorientierte Lichtquelle (Directional Light). Diesen Lichttypen müssen unterschiedliche Eigenschaften zugewiesen werden.
140
Licht
Lichteigenschaften Die Lichteigenschaften aller drei Lichttypen werden in einem zentralem TypenArray gesammelt. Das D3DLIGHT7-Typen-Array besitzt folgenden Aufbau: Type D3DLIGHT7 ambient As D3DCOLORVALUE attenuation0 As Single attenuation1 As Single attenuation2 As Single diffuse As D3DCOLORVALUE direction As D3DVECTOR dltType As CONST_D3DLIGHTTYPE falloff As Single phi As Single position As D3DVECTOR range As Single specular As D3DCOLORVALUE theta As Single End Type
Die Lichtfarbe wird durch die Mitgliedsdaten ambient, diffuse und specular bestimmt. Sie werden durch das Direct3D-Beleuchtungsmodell miteinander verschmolzen. Zusammen mit dem Gegenstück des Objektmaterials (Materialeigenschaften beinhalten ebenfalls ambient, diffuse und specular Anteile) ergibt sich die endgültige Farbe. Über die Mitgliedsdaten position beschreiben Sie die Position der Lichtquelle. Dazu nutzen Sie das D3DVECTOR-Typen-Array. Das Koordinatentrio x, y und z stehen relativ zu den Weltkoordinaten. Anders als bei dem indirektem Licht können Sie bei dem direktem Licht eine Reichweite definieren. Die Variable range ist auf einen Maximalwert von 18.446+e18 begrenzt. Um das natürliche Licht möglichst optimal zu simulieren, müssen Objekte, welche von der Lichtquelle weiter entfernt liegen, dunkler dargestellt werden als Objekte, welche näher an der Lichtquelle liegen. Direct3D stellt drei Parameter bereit, um solch eine Abschwächung zu simulieren. Mit den Mitgliedsdaten attenuation0, attenuation1 und attenuation2 beschreiben Sie, wie sich die Lichtintensivität über die Lichtreichweite verhalten soll. Der normale Wertebereich liegt zwischen 0.0 und 1.0. Erlaubt sind aber auch Zuweisungen von kleiner 0 und größer 1. Für eine gleichmäßige Lichtverteilung über die gesamte Strecke können Sie folgende Einstellung wählen. attenuation0 = 0.0 attenuation1 = 1.0 attenuation2 = 0.0
Kapitel 2 • Direct3D
141
Sie dürfen den normalen Wertebereich für die Abschwächung von Licht verlassen. So können Sie mit Werten größer 1.0 eine Verstärkung der jeweiligen Abschwächung erreichen. Diese Abschwächung könnte manchmal etwas befremdend wirken. Mit Werten kleiner 0.0 erreichen Sie ein helleres Licht über die gesamte Reichweite. Den Lichttypen Spotlight und Directional Light können Sie eine Richtung zuweisen. Der direction-Vektor beschreibt die Entfernung vom logischen Ursprung, unabhängig von der Lichtposition in der Szene. Dementsprechend leuchtet ein Spotlight mit dem Richtungsvektor 0,0,1 entlang der positiven Z-Achse. Eine richtungsorientierte Lightquelle mit dem Richtungsvektor 0,-1,0 würde direkt von oben in die Szene leuchten. Natürlich können Sie auch einen Punkt im 3D-Raum fixieren. Einen Richtungsvektor mit den Daten 0,0,0 dürfen Sie allerdings nicht verwenden. Wenn Sie einen Punkt im 3D-Raum fixieren möchten, reicht es nicht aus, die Koordinaten des Punktes anzugeben. Der direction-Vector ist lediglich ein Richtungszeiger. Um einen Punkt im 3D-Raum zu treffen, müssen die Richtungszeiger entsprechend umgerechnet werden. Die verbleibenden vier Parameter dltType, falloff, phi und theta werden bei den Zuweisungen der Eigenschaften (direkt im Anschluss) erläutert. Betrachten wir, welche Einträge für welchen Lichttyp benötigt werden. Pointlight dltType As CONST_D3DLIGHTTYPE = D3DLIGHT_POINT
Bild 2.19: Pointlight
Ein Pointlight können Sie am besten mit einer kleinen Sonne vergleichen. Es strahlt gleichmäßig in alle Richtungen.
142
Licht
Eigenschaften D3DLIGHT7. ambient D3DLIGHT7.diffuse D3DLIGHT7.specular D3DLIGHT7.position D3DLIGHT7.range D3DLIGHT7.attenuation0 D3DLIGHT7.attenuation1 D3DLIGHT7.attenuation2
Beispiel Dim Light As D3DLIGHT7 Dim Farbe As D3DCOLORVALUE Dim Position As D3DVECTOR With Position .x = 5 .y = 5 .z = 5 End With With Farbe .r = 255 .g = 255 .b = 255 End With With Light .dltType = D3DLIGHT_POINT .Ambient = Farbe .diffuse = Farbe .specular = Farbe .Position = Position .range = 10 .attenuation0 = 0 .attenuation1 = 1 .attenuation2 = 0 End With
Mit der Methode Direct3Ddevice7.SetLight() setzen Sie die Lichtquelle in Ihre Szene. Nun muss Sie noch eingeschaltet werde. Hierbei hilft uns die Methode Direct3DDevice7.LightEnable(). Sie können jederzeit die Lichteigenschaften mit einem erneuten Aufruf der SetLight() Methode überschreiben. Die Änderungen werden beim Rendern der Szene sofort wirksam. In diesem Beispiel verwenden wir die Variable Position As D3DVECTOR. Diesem Vektor weisen wir die Koordinatenwerte zu. Anschließend wird dieser Vektor den Lichteigenschaften (.Position = Position) zugewiesen. Diese Vorgehensweise
Kapitel 2 • Direct3D
143
ist nicht zwingend notwendig. Wir hätten die Lichtposition auch wie folgt bestimmen können: Light.Position.x = 5 Light.Position.y = 5 Light.Position.z = 5
Die gleiche Vorgehensweise finden Sie bei der Zuordnung der Lichtfarbe. Eine direkte Zuweisung and die Lichteigenschaften sieht so aus: Light.Ambient.r = 255 Light.Ambient.g = 255 Light.Ambient.b = 255 Light.diffuse.r = 255 Light.diffuse.g = 255 Light.diffuse.b = 255 Light.specular.r = 255 Light.specular.g = 255 Light.specular.b = 255
Diese Einstellung erzielt ein hell leuchtendes weißes Licht. Directional Light
L i c h t
Koordinatensystem Bild 2.20: Directional Light
Directional (richtungsorientiertes) Licht besitzt als Eigenschaften Farbe und Richtung. Diese Lichtquelle erzeugt ein paralleles Licht, welches in einer einheitlichen Richtung durch die gesamte Szene wandert. Richtungsorientiertes Licht wird weder von Reichweiten noch von Abschwächungsfaktoren beeinflusst.
144
Licht
Eigenschaften D3DLIGHT7. ambient D3DLIGHT7.diffuse D3DLIGHT7.specular D3DLIGHT7.direction
Beispiel Dim Light As D3DLIGHT7 Dim Farbe As D3DCOLORVALUE Dim Richtung As D3DVECTOR With Richtung .x = 5 .y = 5 .z = 5 End With With Farbe .r = 255 .g = 255 .b = 255 End With With Light .dltType = D3DLIGHT_POINT .Ambient = Farbe .diffuse = Farbe .specular = Farbe .direction = Richtung End With
Spotlight Spotlight ist exakt mit einer Taschenlampe vergleichbar. Spotlight ist das am aufwendigsten zu programmierende Licht. Es nutzt alle Mitgliedsdaten des D3DLIGHT7 Typen Arrays. Der helle innere Lichtkegel wird mit dem ThetaWert festgelegt. Entsprechend wird der äußere Lichtkegel mit dem Phi-Wert bestimmt. Das falloff-Mitglied aus dem D3DLIGHT7-Typen-Array definiert, wie sich das Licht zwischen Zentrum und äußerem Rand abschwächen soll. Der Phi-Wert ist eine Winkelangabe (radiant). Er liegt zwischen 0.0 und 3.14159. Der Theta-Wert ist ebenfalls eine Winkelangabe und liegt zischen 0.0 und
Kapitel 2 • Direct3D
145
Phi Theta innerer Lichtkegel
äußerer Lichtkegel Bild 2.21: Spotlight
Eigenschaften D3DLIGHT7.ambient D3DLIGHT7.diffuse D3DLIGHT7.specular D3DLIGHT7.position D3DLIGHT7.direction D3DLIGHT7.range D3DLIGHT7.attenuation0 D3DLIGHT7.attenuation1 D3DLIGHT7.attenuation2 D3DLIGHT7.phi D3DLIGHT7.theta D3DLIGHT7.falloff
Beispiel Dim Light As D3DLIGHT7 Dim Farbe As D3DCOLORVALUE Dim Position As D3DVECTOR Dim Richtung As D3DVECTOR With Position .x = 5 .y = 5 .z = 5 End With With Richtung .x = 5 .y = -1 .z = 5 End With
146
Licht
With Farbe .r = 255 .g = 255 .b = 255 End With With Light .dltType = D3DLIGHT_SPOT .Ambient = Farbe .diffuse = Farbe .specular = Farbe .Position = Position .Direction = Richtung .range = 10 .attenuation0 = 0 .attenuation1 = 1 .attenuation2 = 0 .phi = 180 / 57.296 .theta = 20 / 57.296 .falloff =1.0 End With
2.8.3
Licht, Schatten und Polygone DirectX unterscheidet zwei Schattenmodelle. Je nachdem welches Schattenmodel Sie verwenden, beeinflussen Sie das Erscheinungsbild der gerenderten Szene. Flat Shading und Gouraud Shading unterscheiden sich sehr stark von einander. Über das Schattenmodel beeinflussen Sie die Farbe und Beleuchtung jedes einzelnen Pixels eines Polygons. Flat Shading liegt ein einfaches, nicht lineares Berechnungssystem zu Grunde. Das Gouraud Shading Verfahren ist eine sehr viel feinere Technik. Diese Technik ermöglicht uns für jedes Pixel, (in Abhängigkeit von Material, Licht und Normalvektor) eine individuelle Farbe zu berechnen. Diese Berechnung wird glücklicherweise von D3D übernommen. Dieses individuelle Pixeldesign bezeichnet man als Schatten. Verwechseln Sie diesen Schatten bitte nicht mit einem Schatten, der durch ein Objekt verursacht wird, z.B. ein Baum, der seinen Schatten auf eine Wiese wirft. Dies ist ein gänzlich anderes Verfahren und muss explizit berechnet werden. •
Flat Shading Mit dem Flat Shading Mode berechnet Direct3D das gesamte Polygon mit der Materialfarbe der ersten Vertexstruktur. Betrachtet man das gesamte Objekt, so ist das Ergebnis eine Aufteilung in Klötzchen. Zwischen den vielen Polygonen eines Objektes bilden sich scharfe, deutlich sichtbare Kanten. In einigen Fällen wird diese Methode bewusst eingesetzt, allerdings liegt der wahre Vorteil bei der Performancesteigerung. Bei modernen Anwendungen ist diese Technik quasi nicht mehr zu finden. Das begründet sich mit der gestiegenen Leistungsfähigkeit eines modernen PC. Alle modernen Grafikkarten beherrschen neben
Kapitel 2 • Direct3D
147
dem Flat Shading auch die verbesserte Gouraud Shading Technik. Oftmals sogar ohne bzw. mit kaum merklichem Performanceverlust. So können Sie den Renderstatus von D3D auf Flat Shading stellen: Dim ShadeMode As CONST_D3DSHADEMODE ShadeMode = D3DSHADE_FLAT Direct3Ddevice7.SetRenderState D3DRENDERSTATE_SHADEMODE, _ ShadeMode
Sicherlich werden Sie feststellen, dass Ihnen bei der Auswahl der Variablen ShadeMode As CONST_D3DSHADEMODE eine dritte Variante angeboten wird. D3DSHADE_PHONG steht uns zurzeit nicht zur Verfügung. Der Phong-Algorithmus würde eine weitere Verbesserung darstellen. Allerdings würden wir auch einen Performanceverlust hinnehmen müssen. Warten wir einfach auf die nächste DirectX-Version. Der Aufruf dieser Technik wird wahrscheinlich analog zu den bereits bekannten Algorithmen implementiert. •
Gouraud Shading Gouraud Shading ist die zur Zeit einzige Alternative zu der bekannten FlatShading-Technik. Verglichen mit der Alternative, benötigt diese Technik mehr Rechenzeit. Der Verlust an Performance ist aber mehr als gerechtfertigt. Die Voreinstellung von Direct3D ist Gouraud Shading. Anders als bei der Flat Shading-Methode wird nicht nur die erste Vertexstruktur als Berechnungsgrundlage genommen. D3D berechnet jede Vertexstruktur einzeln und interpoliert alle anderen Pixel des Polygons. Die Interpolation wird linear berechnet. Als Beispiel: Der Rotanteil von Vertex eins ist 0.8. Der Rotanteil von Vertex zwei ist 0.4. Der Mittelpunkt zwischen den beiden Vertexstrukturen beträgt 0.6. Diese lineare Berechnung wird für alle Pixel zwischen Vertex eins und Vertex zwei durchgeführt. Das Ergebnis ist ein feiner Farbverlauf. Die unangenehme Klötzchenbildung der Flat-Shading-Methode entfällt.
So können Sie den Renderstatus von D3D auf Flat Shading stellen: Dim ShadeMode As CONST_D3DSHADEMODE ShadeMode = D3DSHADE_GOURAUD Direct3Ddevice7.setRenderState D3DRENDERSTATE_SHADEMODE, _ ShadeMode
Wie schon im Vorfeld erklärt wurde, sorgt die Gouraud Shading Methode für einen feinen Farbverlauf eines Polygons. Dies kann aber auch zu Problemen führen. Die Probleme werden immer dann deutlich, wenn eine Lichtquelle so klein ist, das Sie die Ecken des Polygons nicht erreicht. In der Abbildung können Sie erkennen, dass die Lichtquelle (in unserem Fall ein Spotlight) die Ecke der Polygone nicht erreicht. Somit liegt keine Vertexstruktur innerhalb des Lichtes. Gouraud Shading steht nun vor dem Problem, dass dieser Methode die Berechnungsgrundlage fehlt. Das Ergebnis ist, dass wir überhaupt kein Licht sehen werden. D3D tut so, als würde es nicht existieren.
148
Licht
Polygon 2
Spot Light Polygon 1 Bild 2.22: Der Lichtpunkt trifft keine Ecke eines Polygons
Die Lösung dieses Problems besteht darin, dass Sie sehr viel detaillierter arbeiten müssen. Kleinere Polygone, Erhöhen der Bildschirmauflösung oder Steigern der Farbtiefe können Abhilfe schaffen. Insbesondere durch den Einsatz kleinerer Polygone können Sie sehr viel realistischere Szenen erzeugen. Viele Polygone bedeuten aber auch, dass die Performance stärker belastet wird. Wie bei allen Dingen des Lebens sollten Sie ein ausgewogenes Verhältnis schaffen. In manchen Bereichen der Szene, in denen Sie eine sehr feine Verteilung des Lichts benötigen, vergrößern Sie die Anzahl der Polygone. In anderen Bereichen können Sie etwas gröber arbeiten.
2.8.4
Licht aktivieren / deaktivieren Die Lichteigenschaften werden in dem D3DLIGHT7 Typen Array (siehe Abschnitt Direktes Licht) erfasst. Diese Informationen müssen Sie jetzt an das Renderdevice weiterleiten. Genau diese Aufgabe wird von der Direct3D Device7.SetLight()-Methode übernommen. Anschließend muss die zugewiesene Lichtquelle eingeschaltet werden. Für das Ein- und Ausschalten einer Lichtquelle ist die Direct3DDevice7.LightEnable()-Methode verantwortlich. Sollten Sie LightEnable() aufrufen, ohne zuvor die Lichteigenschaften bestimmt zu haben, dann wird von D3D eine Lichtquelle mit den folgenden Standartwerten erstellt: Mitgliedsdaten des D3DLIGHT7-TypenArrays
Standardwert
dltType
D3DLIGHT_DIRECTIONAL
Diffuse
(R:1, G:1, B:1, A:0)
Specular
(R:0, G:0, B:0, A:0)
Ambient
(R:0, G:0, B:0, A:0)
Kapitel 2 • Direct3D
149
Mitgliedsdaten des D3DLIGHT7-TypenArrays
Standardwert
Position
(0, 0, 0)
Direction
(0, 0, 1)
Range
0
Falloff
0
Attenuation0
0
Attenuation1
0
Attenuation2
0
Theta
0
Phi
0
Die folgenden Methoden helfen Ihnen, die Lichtquellen sicher in den Griff zu bekommen. Sie geben Ihnen die Möglichkeit, die Parameter einer Lichtquelle zu ändern oder deren Parameter auszulesen. Es ist wichtig, dass die zugewiesenen Parameter innerhalb des erlaubten Wertebereichs liegen und zu der gewählten Lichtquelle passen. Ansonsten wird die Lichtquelle nicht aktiviert und ein Fehler ist die Folge. SetLight() Setzt die Lichteigenschaften für eine Lichtquelle. object.SetLight(LightIndex As Long, Light As D3DLIGHT7) object
ein gültiges Direct3DDevice7-Objekt
LightIndex
Ein Index für eine Lichtquelle. Jede Lichtquelle wird durch diesen Index identifiziert. Ist eine Lichtquelle mit dem gleichen Index bereits vorhanden, so werden die Lichteigenschaften überschrieben.
Light
Variable vom Typ D3DLIGHT7, welche die notwendigen Parameter der Lichtquelle enthält.
LightEnable() Aktiviert oder deaktiviert eine Lichtquelle. object.LightEnable(LightIndex As Long, bEnable As Boolean) object
ein gültiges Direct3DDevice7-Objekt
LightIndex
Ein Index für eine Lichtquelle. Jede Lichtquelle wird durch diesen Index identifiziert. Ist eine Lichtquelle mit dem gleichen Index bereits vorhanden, so werden die Lichteigenschaften überschrieben.
bEnable
True aktiviert die Lichtquelle False deaktiviert die Lichtquelle
150
Licht
GetLight() Liest die Lichteigenschaften einer Lichtquelle und übergibt sie an das Light-As D3DLIGHT7-Typen-Array. object.GetLight(LightIndex As Long, Light As D3DLIGHT7) object
ein gültiges Direct3DDevice7-Objekt
LightIndex
Ein Index für eine Lichtquelle. Jede Lichtquelle wird durch diesen Index identifiziert.
Light
Variable vom Typ D3DLIGHT7, welche die notwendigen Parameter der Lichtquelle aufnimmt.
GetLightEnable() Empfängt den aktiven Status einer Lichtquelle. Das Ergebnis wird als Boolean-Wert zurückgeliefert. (True = aktiv; False = inaktiv) object.GetLightEnable(LightIndex As Long) As Boolean object
ein gültiges Direct3DDevice7-Objekt
LightIndex
Ein Index für eine Lichtquelle. Jede Lichtquelle wird durch diesen Index identifiziert.
Um eine Lichtquelle zu aktivieren, müssen Sie zwei Schritte durchführen. Schritt 1:
Zuweisen der Lichteigenschaften
Schritt 2:
Einschalten der Lichtquelle
Schritt 1: Zuweisen der Lichteigenschaften Dim Light As D3DLIGHT7 With Light .dltType = D3DLIGHT_POINT .Ambient.r = 1 .Ambient.g = 1 .Ambient.b =1 .Position.x = 5 .Position.y = 5 .Position.z = 5 .range = 10 .attenuation1 = 1 End With Call Direct3DDevice7.SetLight (1, Light) Call Direct3DDevice7.LightEnable(1, True)
Kapitel 2 • Direct3D
151
Die Lichtquelle mit dem Index eins können Sie deaktivieren, indem Sie die LightEnable()-Methode aufrufen und dem Parameter bEnable den Wert False zuweisen. Zu der Laufzeit des Programms ist es hilfreich, wenn Sie die Parameter und den Status Ihrer Lichtquellen abfragen können. Natürlich bietet uns D3D auch für diese Aufgaben entsprechende Methoden an. Ob eine Lichtquelle ein- oder ausgeschaltet ist, können Sie mit der Direct3DDevice7.GetLightEnable()-Methode abfragen. Der Aufruf ist unkompliziert und liefert den aktuellen Status. Dim Msg As Boolean Msg = Direct3DDevice7.GetLightEnable(1)
Ist Msg = True, so ist die Lichtquelle mit dem Index 1 eingeschaltet. Ist der Rückgabewert = False, so ist die Lichtquelle ausgeschaltet. In unserem Beispiel erhalten Sie den Wert True. Die Lichteigenschaften können Sie mit der Direct3DDevice7.GetLight()Methode in Erfahrung bringen. Die gesammelten Informationen werden in dem Parameter Light As D3DLIGHT7 gespeichert. Die Mitgliedsdaten dieses Typen Arrays können Sie nach belieben abfragen. Dim TempLight AS D3DLIGHT7 Dim Range As Single Call Direct3DDevice7.GetLight (1, TempLight) Range = TempLight.range
In unserm Beispiel würde die Variable Range den Wert 10 enthalten.
2.8.5
Beispiel (Licht) Unser Lichtbeispiel zeigt Ihnen alle verfügbaren Lichtquellen. Im Quelltext finden Sie Abschnitte speziell für Pointlight, Spotlight, Directional Light und Ambient Licht. Zusätzlich drehen wir den Betrachter bei Pointlight und Ambientlight. Damit wir die Lichteinflüsse gut beobachten können, haben wir die Wände mit jeweils 50 Dreiecken erstellt. Wir wollten weder Ihnen noch uns zumuten, die Vektoren der Dreiecke per Hand anzugeben. Dies wären immerhin ca. 300 Programmzeilen. Deshalb nutzen wir die CreateWall()-Subroutine. Sie erstellt die benötigten Wände automatisch. Wir werden Texturen verwenden, ohne den Aufbau einer Texturesurface zu erklären. Wir benötigen die Texturen, um die Auswirkungen der Lichtquellen besser beobachten zu können. Hoffentlich sind Sie uns nicht böse, dass wir die Texturen ohne Erläuterungen verwenden. Dies werden wir im Textureabschnitt des Buches ausgiebig nachholen. Bei den Dimensionierungen der Variablen gibt es keine Neuerungen über die wir berichten müssten. Hier finden wir nur alte Bekannte, die momentan keine Herausforderungen darstellen.
152
Licht
Bild 2.23: Bildschirmfoto Light
Das Programm startet mit der Form_Load()-Routine. Direkt am Anfang finden wir die Subroutinen InitDDraw() und InitD3D(). Diese Routinen sind uns ebenfalls bekannt und werden nicht erklärt. Private Sub Form_Load() InitDDraw InitD3D LichtText(0) = "Point-Light" LichtText(1) = "Spot-Light" LichtText(2) = "Directional-Light" LichtText(3) = "Ambient-Light"
Diesen Text können Sie oben links am Bildschirm lesen. Er dient zur Information. Dim Anzahl(6) As Long Dim First(6) As Long First(0) = 0 Anzahl(0) = CreateWall(Vector(-5, 5, 5), _ Vector(5, -5, 5), 5, 5, First(0), 0, Vector(0, 1, -1)) First(1) = First(0) + Anzahl(0) Anzahl(1) = CreateWall(Vector(-5, 5, -5), _ Vector(5, -5, -5), 5, 5, First(1), 0, Vector(0, 1, 1)) First(2) = First(1) + Anzahl(1)
Kapitel 2 • Direct3D
153
Anzahl(2) = CreateWall(Vector(-5, 5, -5), _ Vector(-5, -5, 5), 5, 5, First(2), 0, Vector(1, 1, 0)) First(3) = First(2) + Anzahl(2) Anzahl(3) = CreateWall(Vector(5, 5, -5), _ Vector(5, -5, 5), 5, 5, First(3), 0, Vector(-1, 1, 0)) First(4) = First(3) + Anzahl(3) Anzahl(4) = CreateWall(Vector(-5, 5, 5), _ Vector(5, 5, -5), 5, 5, First(4), 1, Vector(0, 1, 0)) First(5) = First(4) + Anzahl(4) Anzahl(5) = CreateWall(Vector(-5, -5, 5), _ Vector(5, -5, -5), 5, 5, First(5), 1, Vector(0, 1, 0))
Wir rufen die Funktion CreateWall() insgesamt sechsmal auf. Für jede Wand einen Aufruf. In dem Array Anzahl As Array erhalten wir die Anzahl der verwendeten Vertexe. Die Elemente des Array First speichern einen Index, der den Anfang einer Wand repräsentiert. Dieser wird später beim Rendern benötigt. CreateTextur App.Path & "\Mauer.bmp"
Die CreateTexture() Subroutine ist eine kleine Eigenentwicklung. In ihr erstellen wir die benötigte Texturesurface und laden gleichzeitig die Texture von der Festplatte. Zu diesem Zeitpunkt stehen wir vor dem Problem, dass wir Texturen benutzen, ohne sie vorher erläutert zu haben. Dies ist ein kleiner Teufelskreis. Ohne Licht sind Texturen nicht sichtbar. Ohne Texturen können die Lichtvariationen nicht richtig beobachtet werden. Nun können wir Sie nur bitten, die Texturen als gegeben anzusehen. Genauere Erklärungen zu Texturen erfolgen später im Textureabschnitt des Buches. Deshalb werden wir die Texturen zu diesem Zeitpunkt nicht erklären und vertrösten Sie auf später. Dim mat As D3DMATERIAL7 mat.diffuse.r = 1 mat.diffuse.g = 1 mat.diffuse.b = 0 mat.diffuse.a = 1 mat.Ambient.r = 1 mat.Ambient.g = 1 mat.Ambient.b = 0 mat.Ambient.a = 1 g_d3dDevice.SetMaterial mat
Wir benutzen ein Material, welches in der Lage ist, diffuses sowie ambientes Licht zu reflektieren. Die Reflexion der Blauanteile klammern wir aus. Do g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET, _ RGB(255, 0, 0), 0, 0 g_d3dDevice.BeginScene r = r + 1: If r > 360 Then r = 0
154
Licht
g_dx.IdentityMatrix matView Call g_dx.ViewMatrix(matView, Vector(5 * Sin(r / 5 * Cos(r / 57.296)), Vector(0, 0, 0), Vector(0, If AktTyp = LT_POINT Or AktTyp = LT_AMBIENT Then g_d3dDevice.SetTransform D3DTRANSFORMSTATE_VIEW,
57.296) , 0, _ 1, 0), 0) _ _ matView
Bei den Lichttypen Pointlight und Ambientlight soll sich der Betrachter im Kreis drehen. If If If If
AktTyp AktTyp AktTyp AktTyp
= = = =
LT_POINT Then PointLicht LT_SPOT Then SpotLicht r LT_DIRECT Then DirectLicht r LT_AMBIENT Then AmbientLicht
Bei den Lichttypen Spotlight und Directionallight soll sich die Lichtquelle drehen. Dafür übergeben wir den Routinen den Paramater r. Dieser enthält den aktuellen Winkel für die Rotation. Hier verzeigen wir in die entsprechende Subroutine, um das richtige Licht zu initialisieren. g_d3dDevice.SetTexture 0, TextureSurf g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, Vertex(First(0)), Anzahl(0), D3DDP_WAIT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, Vertex(First(1)), Anzahl(1), D3DDP_WAIT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, Vertex(First(2)), Anzahl(2), D3DDP_WAIT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, Vertex(First(3)), Anzahl(3), D3DDP_WAIT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, Vertex(First(4)), Anzahl(4), D3DDP_WAIT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, Vertex(First(5)), Anzahl(5), D3DDP_WAIT g_d3dDevice.EndScene
D3DFVF_VERTEX, _ D3DFVF_VERTEX, _ D3DFVF_VERTEX, _ D3DFVF_VERTEX, _ D3DFVF_VERTEX, _ D3DFVF_VERTEX, _
Mit der DrawPrimitive()-Methode werden die sechs Wände gerendert. g_ddsBackBuffer.SetForeColor (RGB(255, 255, 255)) g_ddsBackBuffer.DrawText 10, 10, LichtText(AktTyp), False g_ddsBackBuffer.DrawText 10, 450, "PRESS SPACEBAR FOR NEXT _ LIGHT-TYP OR <ESC> TO EXIT DEMO", False g_ddsBackBuffer.DrawText 10, 420, "PRESS <S> FOR SOLID", False g_ddsBackBuffer.DrawText 10, 390, "PRESS <W> FOR WIREFRAME", _ False
Hier werden ein paar Informationen für den Anwender auf den Bildschirm geschrieben. g_ddsPrimary.Flip Nothing, DDFLIP_WAIT
Kapitel 2 • Direct3D
155
Die gerenderte Szene wird auf die primäre Surface geflippt und die Szene ist auf dem Monitor sichtbar. DoEvents
Die DoEvents-Anweisung ist sehr wichtig, da wir auf Tastatureingaben reagieren wollen. Loop Until GetAsyncKeyState(vbKeyEscape) <> 0 g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_NORMAL g_dd.RestoreDisplayMode Set g_dd = Nothing Set g_d3dDevice = Nothing Set g_dx = Nothing End End Sub
Nun brauchen wir uns nur noch die vier Subroutinen für die Lichtinitialisierung anzuschauen. Beginnen wir mit dem Pointlight. Pointlight: Private Sub PointLicht() g_d3dDevice.SetRenderState D3DRENDERSTATE_AMBIENT, RGB(0, 0, 0)
Da wir nur das Pointlight beobachten wollen, schalten wir ein möglicherweise aktives, indirektes Licht aus. Einfach die Lichtfarbe auf Schwarz setzen. Dim LC As D3DCOLORVALUE LC.r = 20 LC.g = 20 LC.b = 20 Dim LightPos As D3DVECTOR LightPos = Vector(5, 6, 5) Dim Licht As D3DLIGHT7 Licht.diffuse = LC Licht.attenuation1 = 5 Licht.dltType = D3DLIGHT_POINT Licht.position = LightPos Licht.range = 20
Für Pointlight benötigen wir die Definitionen für Position, Reichweite und Lichtfarbe. Diese werden hier zugewiesen. g_d3dDevice.SetLight 0, Licht g_d3dDevice.LightEnable 0, True
Abschließend brauchen wir die Lichtquelle nur noch zuweisen und einschalten. End Sub
156
Licht
Directional Light: Private Sub DirectLicht(ByVal Ang As Single) g_d3dDevice.SetRenderState D3DRENDERSTATE_AMBIENT, RGB(0, 0, 0) Dim LC As D3DCOLORVALUE LC.r = 20 LC.g = 20 LC.b = 20 Dim LightPos As D3DVECTOR Dim LightDir As D3DVECTOR LightPos = Vector(0, 0, 0) LightDir = Vector(10 * Sin((360 – Ang) / 57.296), 0, _ 10 * Cos((360 – Ang) / 57.296))
Wir möchten, dass sich die Richtung des direktionalen Lichts dreht. Dies erreichen wir, indem wir den Richtungsvektor verändern. Der aktuelle Winkel wird der Subroutine übergeben und findet sich im Parameter Ang. Dim Licht As D3DLIGHT7 Licht.diffuse = LC Licht.attenuation1 = 2 Licht.dltType = D3DLIGHT_DIRECTIONAL Licht.direction = LightDir Licht.range = 10 g_d3dDevice.SetLight 0, Licht g_d3dDevice.LightEnable 0, True End Sub
Spotlight: Private Sub SpotLicht(ByVal Ang As Single) g_d3dDevice.SetRenderState D3DRENDERSTATE_AMBIENT, RGB(0, 0, 0) Dim LC As D3DCOLORVALUE LC.r = 20 LC.g = 20 LC.b = 20 Dim LightPos As D3DVECTOR Dim LightDir As D3DVECTOR LightPos = Vector(0, 0, 0) LightDir = Vector(10 * Sin((360 – Ang) / 57.296), 0,_ 10 * Cos((360 – Ang) / 57.296))
Auch das Spotlight soll sich drehen. Ebenfalls wird der Winkel an den Parameter Ang übergeben. Dim Licht As D3DLIGHT7 Licht.diffuse = LC Licht.attenuation1 = 2 Licht.dltType = D3DLIGHT_SPOT
Kapitel 2 • Direct3D
157
Licht.position = LightPos Licht.direction = LightDir Licht.range = 10 Licht.phi = 160 / 57.296 Licht.theta = 2 / 57.296 Licht.falloff = 1 g_d3dDevice.SetLight 0, Licht g_d3dDevice.LightEnable 0, True End Sub
Ambient Light: Private Sub AmbientLicht() g_d3dDevice.LightEnable 0, False g_d3dDevice.SetRenderState D3DRENDERSTATE_AMBIENT, _ RGB(255, 255, 255) End Sub
Beim indirekten Licht sind quasi keine Parameter zu berücksichtigen. Lediglich die Lichtfarbe muss angegeben werden.
2.9
Material Material beschreibt, wie ein Polygon das einfallende Licht reflektieren oder absorbieren soll. Die Materialeigenschaften werden in dem D3DMATERIAL7Typen-Array erfasst. Type D3DMATERIAL7 ambient As D3DCOLORVALUE diffuse As D3DCOLORVALUE emissive As D3DCOLORVALUE power As Single specular As D3DCOLORVALUE End Type
Dieses Array beinhaltet die gesamte Materialbeschreibung. Im Detail werden die Parameter ambient, diffuse (beide für das Reflexionsverhalten verantwortlich), emmisiv (beschreibt die Eigenleuchtkraft) und specular sowie power (regeln Glanzlichter) gesetzt. Die einzelnen Parameter werden im Folgenden beschrieben. •
diffuse und ambient Das Material wird mit einer Lichtquelle beleuchtet. Die Lichtquelle enthält unter anderem die Eigenschaften für diffuse und ambient. Die Eigenschaften diffuse und ambient beschreiben, wie viel von dem Licht reflektiert werden soll. Dabei teilt D3D die Farbe in Ihre Einzelkomponenten (Rot-, Grün- und Blauanteil). Der Alphawert der Materialbeschreibung bestimmt wie sich die Komponenten mischen sollen (blending factor).
158
Material
Wie viel von dem eintreffenden Licht reflektiert wird, steht in einem engen Zusammenhang mit dem Normalvektor eines Polygons. Die Summe des reflektierenden Lichtes ist der Kosinus (Winkel) zwischen einfallendem Licht und dem Normalvektor.
Normalvektor Licht
θ
Summe des reflektierenden Lichts = cos θ Bild 2.24: Lichtreflexion
Trifft das Licht annähernd parallel zum Normalvektor auf das Polygon, so verzeichnen wir die stärkste Reflexion. Die entgegengesetzte Wirkung tritt ein, wenn das Licht annähernd parallel zum Polygon verläuft. diffuse und ambient arbeiten eng zusammen, um das Erscheinungsbild der Materialfarbe zu bestimmen. Gewöhnlich nutzen beide Parameter die gleichen Werte. Wollen Sie z.B. eine rot glühende Oberfläche erzeugen, so wählen Sie ein Material mit den Werten: ambient.r ambient.g ambient.b diffuse.r diffuse.g diffuse.b
= = = = = =
1 0 0 1 0 0
Wird diese Oberfläche mit einer weißen Lichtquelle beleuchtet, so werden nur die Rotanteile der Lichtquelle reflektiert. Das Material wirkt rot glühend.
Kapitel 2 • Direct3D
159
Einstellungen für ein weißes Licht: ambient.r ambient.g ambient.b diffuse.r diffuse.g diffuse.b
= = = = = =
1 1 1 1 1 1
Sollten Sie die Oberfläche (mit den ersten Werten für ambient & diffuse) mit einem blauem Licht beleuchten, so bleibt die Oberfläche schwarz. Mit den Materialeinstellungen werden nur die Rotanteile des Lichtes reflektiert. Da bei einem blauen Licht keine Rotanteile vorhanden sind, wir auch nichts reflektiert. •
Emission Über den emissive-Parameter des D3DMATERIAL-Typen-Arrays können Sie ein Material dazu anregen, von sich aus zu leuchten. Dieser Parameter beeinflusst die Materialfarbe. Ein möglicher Einsatz ist es, ein dunkles Objekt heller wirken zu lassen. Sie können den Eindruck erwecken, als würde ein Objekt beleuchtet, ohne zusätzliche Lichtquellen setzen zu müssen. Ein Objekt, welches den emissive-Parameter nutzt, erscheint so als würde es Licht ausstrahlen. Dies ist aber nicht der Fall. Somit wird dieses scheinbare Licht auch nicht von anderen Oberflächen (Objekten) reflektiert.
•
Specular Reflexion (Glanzpunkte auf einer Oberfläche) Mit dem specular-Parameter des D2DMATERIAL-Typen-Arrays erzeugen Sie Glanzpunkte auf der Materialoberfläche. Beeinflusst wird der Glanzeffekt durch den Parameter power. Die am weitesten verbreitete Einstellung für die Glanzfarbe ist weiß. specular.r = 1 specular.g = 1 specular.b = 1
Wie stark der Glanzeffekt ausfallen soll, wird mit dem power Parameter bestimmt. Ein Wert von 0 bedeutet keinen Glanz. Ein angemessener Wert von etwa 10 erzeugt einen deutlichen Glanzeffekt.
2.9.1
Setzen von Material Bevor Sie ein Polygon zeichnen, sollten Sie die Materialeigenschaften definiert haben. Einem Polygon können Sie mit der SetMaterial()-Methode ein Material zuweisen. Genauer gesagt wird es nicht dem Polygon direkt zugewiesen, sondern Sie informieren Direct3D, dass alle Polygone die ab der Zuweisung gerendert werden die Materialeigenschaften erhalten. Während eine Szene gerendert wird, können Sie die Materialeigenschaften beliebig oft ändern. Mit der GetMaterial()Methode können Sie die zurzeit aktuellen Materialparameter auslesen.
160
Material
SetMaterial() Setzt die Materialeigenschaften für ein Polygon. object.SetMaterial(mat As D3DMATERIAL7) object
ein gültiges Direct3DDevice7-Objekt
mat
Eine Variable vom Typ D3DMATERIAL7. Sie enthält die Beschreibungen für die Materialeigenschaften.
GetMaterial() Liest die aktuellen Materialeigenschaften, welche D3D nutzen würde, um das nächste Polygon zu erstellen. object.GetMaterial(Material As D3DMATERIAL7) object
ein gültiges Direct3DDevice7-Objekt
Material
Eine Variable vom Typ D3DMATERIAL7. Sie empfängt die Beschreibungen der aktuellen Materialeigenschaften.
Zeichnen Sie ein Polygon, ohne ein Material gesetzt zu haben, so verwendet D3D die Materialgrundeinstellungen. Diese sehen wie folgt aus: Dim Material As D3DMATERIAL7 Material.diffuse.r = 0.5 Material.diffuse.g = 0 Material.diffuse.b = 0.5 Material.diffuse.a = 1 Material.ambient.r = 0.5 Material.ambient.g = 0 Material.ambient.b = 0.5 Material.ambient.a = 1 Material.specular.r = 1 Material.specular.g = 1 Material.specular.b = 1 Material.specular.a = 1 Material.power = 50 Call Direct3DDevice7.SetMaterial (Material)
Die aktuellen Materialeigenschaften können Sie wie folgt auslesen: Dim Material As D3DMATERIAL7 Call Direct3DDevice7.GetMaterial (Material) Ambient_Rot = Material.ambien.r Ambient_Grün = Material.ambien.g Ambient_Blau = Material.ambien.b Ambient_Alpha = Material.ambien.a Diffuse_Rot = Material.diffuse.r Diffuse_Grün = Material.diffuseg.g
Kapitel 2 • Direct3D
161
. . . Power = Material.power
2.9.2
Beispiel (Material) Unser Materialdemo wir Ihnen die Zusammenhänge zwischen Material und Licht veranschaulichen. Es ist nicht möglich, Material darzustellen ohne eine Lichtquelle zu platzieren. (Mit Ausnahme des Emissivanteils des Material. Dieser leuchtet aus eigener Kraft und benötigt kein Licht.) Wir haben vier Wände erzeugt und um den Mittelpunkt der 3D-Welt platziert. Der Betrachter umkreist den Mittelpunkt. Zur Beleuchtung verwenden wir ein Spotlight welches sich immer an den Koordinaten des Betrachters befindet. Ausgerichtet ist das Spotlight auf die Mitte. Hierzu ist es notwendig, bei jeder Positionsveränderung der Lichtquelle die Lichtrichtung neu zu berechnen.
Bild 2.25: Bildschirmfoto Material
162
Material
Auf der linken Bildschirmseite finden Sie alle Parameter für die Materialeinstellungen. Die rechte Seite ist für die Lichteinstellungen reserviert. Mit den Pfeiltasten rauf und runter können Sie die einzelnen Parameter erreichen, mit den Pfeiltasten rechts und links verändern Sie die Einstellungen. Obwohl wir den Einsatz von Texturen noch nicht besprochen haben, werden wir diese zum Einsatz bringen. Wir tun dies, da sich ein Objekt mit Textur anders verhält als ein Objekt ohne Textur. Wir beginnen mit der Form_Load()-Subroutine. Private Sub Form_Load() InitDDraw InitD3D DefaultWerte
In der DefaultWerte()-Subroutine setzen wir einen Standardparameter für Material und Licht. Dies ist auch deshalb wichtig, damit wir beim Initialisieren von Licht und Material keine ungültigen Werte übergeben. Dies würde natürlich eine Fehlermeldung zur Folge haben. LichtIndex = True TextureKachelX = 1 TextureKachelY = 1 CreateWall
Die CreateWall()-Subroutine enthält alle Vertexe für die eingesetzten Polygone. . . . r = r + 1: If r > 360 Then r = 0 g_dx.IdentityMatrix matView Call g_dx.ViewMatrix(matView, Vector(10 * Cos(r / 57.296), 0, _ 10 * Sin(r / 57.296)), Vector(0, 0, 0), Vector(0, 1, 0), 0) g_d3dDevice.SetTransform D3DTRANSFORMSTATE_VIEW, matView
Mit dieser kleinen Berechnung lassen wir den Betrachter um den Mittelpunkt rotieren. Die Variable r definiert den aktuellen Winkel. SpotLicht r
Da wir das Spotlight mit dem Betrachter rotieren lassen wollen, rufen wir die Subroutine SpotLicht() auf. Diese betrachten wir uns gleich noch etwas genauer, denn dort wird nicht nur die Position der Lichtquelle festgelegt, sonder auch die Lichtrichtung.
Kapitel 2 • Direct3D
163
. . . End Sub
Nun werfen wir einen Blick in die SpotLicht()-Subroutine. Private Sub SpotLicht(ByVal Ang As Single) On Error Resume Next Dim LightPos As D3DVECTOR Dim LightDir As D3DVECTOR x = 1 * Cos((360 – Ang) / 57.296) – 1 z = 1 * Sin((360 – Ang) / 57.296) + 1 LightPos = Vector(15 * Cos((Ang) / 57.296), 0, _ 15 * Sin((Ang) / 57.296))
Für die Berechnung der Lichtposition verwenden wir den Algorithmus zur Positionsbestimmung des Betrachters. LightDir = Vector(1 * Cos((Ang + 180) / 57.296), 0, 1 * _ Sin((Ang + 180) / 57.296))
Die Lichtrichtung soll immer auf die Mitte der 3D-Welt gerichtet sein. Dazu wählen wir den um 180 Grad versetzten Winkel von unserer Positionsberechnung. Dies ist möglich, da sich der Winkel zur Positionsberechnung im Ursprung der 3D-Welt befindet. In unserem Beispiel zu Billboarding finden Sie einen Algorithmus, welcher die Winkel zu einem frei platzierten Objekt ermittelt. Licht.position = LightPos Licht.direction = LightDir g_d3dDevice.SetLight 0, Licht If LichtIndex = True Then g_d3dDevice.LightEnable 0, True
Wichtig ist es, dass wir die geänderten Lichtparameter neu zuweisen. Tun wir dies nicht, so werden sich auch keine Änderungen ergeben. Das reine Zuweisen an die Parameter des Lichtobjektes reicht nicht aus. Die Änderungen müssen auch Direct3D mitgeteilt werden. End Sub
Sie sollten noch einen Blick in die CreateWall()-Subroutine werfen. Diese ist nicht sonderlich spektakulär, dennoch ist die Ausrichtung des Normalvektors interessant. Diese muss für die vier Wände unterschiedlich sein. Würden alle in eine Richtung weisen, würden wir das umkreisende Licht nur aus einem bestimmten Winkel sehen. Private Function CreateWall() . .
164
Material
. posz = 2 g_dx.CreateD3DVertex 0 + posx, 0 + posy, 0 + posz, 0, 0, 1, 0 * _ Texturefaktorx, 4 * texturefaktory, Vertex(0)
Für die vordere Wand richten wir den Normalvektor auf 0, 0, 1. Interessant ist der Parameter Vertex.nz, den wir auf 1 setzten. . . . posz = -2 g_dx.CreateD3DVertex 0 + posx, 0 + posy, 0 + posz, 0, 0, -1, 0 * _ Texturefaktorx, 4 * texturefaktory, Vertex(40)
Für die hintere Wand richten wir den Normalvektor auf 0, 0, -1. Wiederum ist der Parameter Vertex.nz interessant. . . . posz = -2 posx = -2 g_dx.CreateD3DVertex 0 + posx, 0 + posy, 0 + posz, -1, 0, 0, _ 0 * Texturefaktorx, 4 * texturefaktory, Vertex(80)
Bei der linken Wand verliert der Parameter Vertex.nz an Bedeutung. Wichtiger wurde der Parameter Vertex.nx diesen setzten wir auf -1. . . . posz = -2 posx = 2 g_dx.CreateD3DVertex 0 + posx, 0 + posy, 0 + posz, 1, 0, 0, _ 0 * Texturefaktorx, 4 * texturefaktory, Vertex(120)
Für die rechte Wand gilt das Gleiche wie für die linke Wand. Die größte Bedeutung erlangt der Vertex.nx-Parameter. Dieser wird auf 1 gesetzt. . . . End Function
Sie haben natürlich erkannt, wie die Normalvektoren ausgerichtet wurden. Immer nach außen, sozusagen in den freien Raum. Kreist nun die Lichtquelle um die Wände, so können die Wände das Licht optimal reflektieren.
Kapitel 2 • Direct3D
165
Der Normalvektor ist kein Punkt im Koordinatensystem, sondern eine Richtung. Besonders bei drehenden Objekten ist es manchmal recht schwer den Normalvektor optimal zur Lichtquelle auszurichten. Deshalb wird bei vielen Spielen darauf verzichtet. Meistens bemerkt das der Anwender nicht. Dies hängt damit zusammen, dass im Regelfall nicht nur eine Lichtquelle ein Objekt beeinflusst. Oftmals ist sogar ein allgemeines (ambientes) Licht gesetzt. Dies ist in der gesamten 3DWelt vorhanden, also auch von allen Seiten des Objektes.
2.10
Texturen Die meisten Objekte in der Realität sind nicht einfarbig, sondern haben ein Oberflächenmuster. Dieses Oberflächenmuster wird in der Computergrafik Texture genannt. Texturen sind zweidimensionale Felder von Farbinformationen (Bitmaps). Die Bitmaps werden auf eine Texturesurface aufgezogen. Die einzelnen Pixel einer Texturesurface werden Texel genannt. Texturen sind zweidimensional. Da sie zweidimensional sind, verleihen sie einer Oberfläche auch keine dreidimensionalen Eigenschaften. Dennoch können Texturen einer Oberfläche den Anschein verleihen, als wäre sie dreidimensional. Diese Illusion kann aber nur aufrechterhalten werden, solange der Betrachter die Textur aus einer bestimmten Perspektive sieht. Bewegt sich der Betrachter um die Oberfläche herum, so fällt dieser Schwindel schnell auf. Komplexe Texturen, welche z.B. einen Horizont oder eine Häuserwand entlang einer Straße darstellen, werden meistens nur aus fest definierten Positionen mit fest definierten Blickrichtungen betrachtet. Bei solch einem Einsatz fällt der Schwindel oftmals nicht auf. Natürlich werden Texturen nicht nur dazu eingesetzt, um ganze Bilder darzustellen. Die primäre Aufgabe der Textur ist es, ein einzelnes 3D-Objekt realistisch zu gestalten. Erstellen Sie z.B. eine Schachtel mit einem Deckel. In diesem Beispiel können Sie der Außenseite der Schachtel ein Schmuckdesign zuweisen und der Innenseite ein einfaches Papiermuster. Für den Deckel verfahren Sie genauso. Betrachtet man nun die Schachtel im 3D-Raum, so wirkt diese sehr viel realistischer. Diese Effekte erreichen Sie nicht, indem Sie nur Materialeigenschaften verwenden. Oberflächen, die nur mit Materialeigenschaften konstruiert wurden, wirken immer künstlich. Um eine Textur für D3D verfügbar zu machen, müssen wir eine Textursurface erstellen. Diese besondere Art einer Surface dient als Container. Diese Textursurface steht allen Polygonen einer 3D-Welt zur Verfügung. Bevor wir tiefer in die Theorie gehen, schauen wir uns direkt ein Texturbeispiel an.
166
Texturen
2.10.1 Beispiel (Textur 1) In unserem ersten Texturenbeispiel erstellen wir zwei Dreiecke, die ein Quadrat bilden. Auf dem erstellten Quadrat werden wir eine Textur einblenden. Dieses Beispiel sollte für Sie kein Problem darstellen. Sie werden ein paar neue Elemente entdecken. Diese werden im Verlauf des Kapitels Textur erläutert. Schauen Sie sich das folgende Beispiel einfach einmal im Schnelldurchgang an.
Bild 2.26: Bildschirmfoto Textur_1
Beginnen wir mit den Dimensionierungen. Dabei fällt die TextureSurf As DirectDrawSurface7 auf. Sie wird die eingesetzte Textursurface sein. Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey _ As Long) As Integer Dim g_dx As New DirectX7 Dim g_dd As DirectDraw7 Dim g_d3d As Direct3D7 Dim ddsd As DDSURFACEDESC2 Dim g_ddsPrimary As DirectDrawSurface7 Dim g_ddsBackBuffer As DirectDrawSurface7 Dim TextureSurf As DirectDrawSurface7
Zusätzlich zu unseren normalen Surfaces benötigen wir eine Textursurface. Diese dimensionieren wir mit TextureSurf As DirectDrawSurface7.
Kapitel 2 • Direct3D
Dim Dim Dim Dim Dim Dim
167
g_d3dDevice As Direct3DDevice7 vPort As D3DVIEWPORT7 g_d3drcViewport(0) As D3DRECT matProj As D3DMATRIX matView As D3DMATRIX Vertex(5) As D3DVERTEX
Private Sub Form_Load() InitDDraw InitD3D
In der Form_Load()-Subroutine verzweigen wir nach InitDDraw() und InitD3D(). Diese beiden Subroutinen sind Ihnen bereits bekannt. Die Routinen finden Sie etwas später im Listing. Nachdem wir aus den Initialisierungsroutinen zurückgekehrt sind, geht es mit den Objektkoordinaten weiter. g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex
-2.5, -2.5, 0, 0, 0, -1, 0, 1, Vertex(0) -2.5, 2.5, 0, 0, 0, -1, 0, 0, Vertex(1) 2.5, 2.5, 0, 0, 0, -1, 1, 0, Vertex(2) 2.5, 2.5, 0, 0, 0, -1, 1, 0, Vertex(3) 2.5, -2.5, 0, 0, 0, -1, 1, 1, Vertex(4) -2.5, -2.5, 0, 0, 0, -1, 0, 1, Vertex(5)
Beim Erstellen der beiden Dreiecke sind die Parameter tu und tv interessant. Sie bestimmen, wie die Textur über die beiden Dreiecke verteilt werden soll. CreateTextur App.Path & "\Lake.bmp"
CreateTexture() ist ebenfalls eine eigene Subroutine. Sie sorgt dafür, das wir der Texturesurface die ausgewählte Bitmap zuweisen. In dem Zusammenhang wird natürlich auch die eigentliche Textursurface erstellt. g_d3dDevice.SetRenderState D3DRENDERSTATE_AMBIENT, _ &HFFFFFF
Wir setzten einfach ein allgemeines Licht. Ohne Licht wäre die Textur nicht sichtbar. Dim mat As D3DMATERIAL7 mat.Ambient.r = 1 mat.Ambient.g = 1 mat.Ambient.b = 1 mat.Ambient.a = 1 g_d3dDevice.SetMaterial mat
Ebenfalls müssen wir die Materialeigenschaften für die Dreiecke setzen. Würden wir das 3D-Objekt ohne Material rendern, so könnte das eintreffende Licht nicht reflektiert werden.
168
Texturen
Do g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET, _ RGB(255, 0, 0), 0, 0 g_d3dDevice.BeginScene g_d3dDevice.SetTexture 0, TextureSurf g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, _ D3DFVF_VERTEX, Vertex(0), 6, D3DDP_WAIT g_d3dDevice.EndScene g_ddsPrimary.Flip Nothing, DDFLIP_WAIT DoEvents Loop Until GetAsyncKeyState(vbKeyEscape) <> 0
In der Do...Loop Until()-Schleife wird das 3D-Objekt gerendert und anschließend auf die primäre Surface geflippt. g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_NORMAL g_dd.RestoreDisplayMode Set g_dd = Nothing Set g_d3dDevice = Nothing Set g_dx = Nothing End
Nachdem die Escape-Taste gedrückt wurde, verlassen wir das Programm. End Sub
Jetzt folgen die beiden Initialisierungsroutinen InitDDraw() und InitD3D(). Beide Routinen sind bereits bekannt und brauchen nicht weiter erklärt werden. Private Sub InitDDraw() Set g_dx = New DirectX7 Set g_dd = g_dx.DirectDrawCreate("") g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_FULLSCREEN Or _ DDSCL_EXCLUSIVE g_dd.SetDisplayMode 640, 480, 16, 0, DDSDM_DEFAULT ddsd.lFlags = DDSD_BACKBUFFERCOUNT Or DDSD_CAPS ddsd.ddsCaps.lCaps = DDSCAPS_COMPLEX Or DDSCAPS_FLIP _ Or DDSCAPS_PRIMARYSURFACE Or DDSCAPS_VIDEOMEMORY Or _ DDSCAPS_3DDEVICE ddsd.lBackBufferCount = 1 Set g_ddsPrimary = g_dd.CreateSurface(ddsd) Dim Caps As DDSCAPS2 Caps.lCaps = DDSCAPS_BACKBUFFER Set g_ddsBackBuffer = g_ddsPrimary.GetAttachedSurface(Caps) End Sub Private Sub InitD3D() Set g_d3d = g_dd.GetDirect3D Set g_d3dDevice = g_d3d.CreateDevice _
Kapitel 2 • Direct3D
169
("IID_IDirect3DHALDevice", g_ddsBackBuffer) vPort.lX = 0 vPort.lY = 0 vPort.lHeight = 480 vPort.lWidth = 640 g_d3dDevice.SetViewport vPort With g_d3drcViewport(0) .X1 = 0: .Y1 = 0 .X2 = 640 .Y2 = 480 End With g_dx.IdentityMatrix matView Call g_dx.ViewMatrix(matView, MakeVector _ (0, 0, -5),MakeVector(0, 0, 0), MakeVector(0, 1, 0), 0) g_d3dDevice.SetTransform D3DTRANSFORMSTATE_VIEW, matView g_dx.IdentityMatrix matProj Call g_dx.ProjectionMatrix(matProj, 1, 100, 3.14159 / 2) d3dDevice.SetTransform D3DTRANSFORMSTATE_PROJECTION, matProj g_d3dDevice.SetRenderTarget g_ddsBackBuffer End Sub
Private Function MakeVector(a As Double, b As Double, c As _ Double) As _ D3DVECTOR Dim vecOut As D3DVECTOR With vecOut .x = a .y = b .z = c End With MakeVector = vecOut End Function
Nun folgt der wichtigste Teil des Listings. Die CreateTexture()-Subroutine übernimmt alle Aufgaben um eine Textursurface zu erzeugen. Private Sub CreateTextur(sFile As String) Dim ddsd3 As DDSURFACEDESC2 Dim TextureEnum As Direct3DenumPixelFormats Set TextureEnum = g_d3dDevice.GetTextureFormatsEnum() TextureEnum.GetItem 1, ddsd3.ddpfPixelFormat ddsd3.ddsCaps.lCaps = DDSCAPS_TEXTURE
Grundsätzlich ist eine Textursurface eine ganz normale Surface. Sie unterscheidet sich von einer primären oder Offscreensurface nur durch die gesetzten Flags. Für unseren Fall ist das DDSCAPS_TEXTURE-Flag wichtig.
170
Texturen
Set TextureSurf = g_dd.CreateSurfaceFromFile(sFile, ddsd3) End Sub
2.10.2 Textur-Koordinaten Texturen sind zweidimensionale Bilder. Ein 3D-Objekt wird aus vielen kleinen Polygonen zusammengebaut. Das zweidimensionale Bild muss nun auf die gesamte Fläche aller Polygone verteilt werden. Ist die Bitmap genauso groß wie die Fläche aller Polygone, so werden die Pixel 1:1 auf das 3D-Objekt übertragen.
Bitmap
Polygon
Bild 2.27: Bitmap mit gleich großer Polygonfläche
Dabei besitzt jedes Texel (Pixel auf einer Textursurface) eine eindeutige Adresse. Glücklicherweise brauchen wir nicht jede Texeladresse definieren. Unsere Aufgabe beschränkt sich auf die Vertexe der Polygone. Betrachten wir uns einmal die Eckpunkte der Bitmap. Die Bitmap hat eine Gesamtlänge von 1. Ebenfalls hat Sie eine Gesamthöhe von 1. Dies ist völlig unabhängig davon, welche tatsächlichen Dimensionen die Bitmap besitzt.
Kapitel 2 • Direct3D
171
(0,0)
(1,0)
Bitmap
(0,1)
(1,1)
Bild 2.28: Bitmap
Das heißt, eine Bitmap mit den Dimensionen 128,128 wird genauso wie eine Bitmap mit den Dimensionen 64,64 auf 1,1 (generic addressing scheme)gesetzt. Dies hat natürlich den Vorteil, das man die Bitmap mathematisch leicht berechnen kann. Da für D3D alle Bitmaps quasi gleich groß sind, braucht man sich um die tatsächlichen Größen nicht weiter zu kümmern. Möchten Sie diese Bitmap nun auf ein 3D-Objekt auftragen, so können Sie dieses tun, indem Sie den einzelnen Vektoren eines Polygons mitteilen, welchen Anteil Sie von der gesamten Bitmap erhalten sollen. (0,0)
(1,0) Polygon 1
Polygon 2 (0,1)
(1,1)
Bild 2.29: Quadrat aus zwei Polygonen
Dies ist die einfachste Zuweisung eines Bitmaps. Mit zwei Dreiecken haben wir ein Rechteck gebildet. Schauen wir uns die Vertextrukturen für die beiden Polygone an:
172
Texturen
Dim Vert(5) As D3DVERTEX 'Polygon 1 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Polygon 2 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex
0, 0, 0 , -1, 0, -1, 0, 1, Vert(0) 0, 5, 0 , -1, 0, -1, 0, 0, Vert(1) 5, 5, 0 , -1, 0, -1, 1, 0, Vert(2) 5, 5, 0, -1, 0, -1, 1, 0, Vert(3) 5, 0 ,0, -1, 0, -1, 1, 1, Vert(4) 0, 0 ,0, -1, 0, -1, 0, 1, Vert(5)
Rufen wir uns nochmals die CreateD3Dvertex()-Methode in Erinnerung. DirectX7.CreateD3DVertex( x As Single, _ y As Single, _ z As Single, _ nx As Single, _ ny As Single, _ nz As Single, _ tu As Single, _ tv As Single, _ v As D3DVERTEX)
Für die Texturkoordinaten sind die Mitgliedsdaten tu und tv von Bedeutung. Projizieren Sie die Bitmap auf das rechteckige 3D-Objekt. So können Sie erkennen, wie die tu- und tv- Parameter gefüllt werden müssen. Wir haben zuerst das erste Dreieck im Uhrzeigersinn erstellt. Dies beschreibt den Bitmapbereich von links unten nach links oben und anschließend nach rechts oben. Wir weisen den Parametern tu und tv der Vertexe die Werte 0,0, 0,1 und 1,1 zu. Anschließend haben wir das zweite Dreieck erstellt. Dieses verläuft von rechts oben nach rechts unten und anschließend nach links unten. Die zugewiesenen Werte lauten diesmal 1,1, 1,0 und 0,0. Beide Dreiecke zusammen beschreiben nun die gesamten Dimensionen der Bitmap. Da die Bitmap und das 3D-Objekt die gleichen Dimensionen haben, wird die Textur in der gerenderten Szene ohne Verzerrungen dargestellt. Natürlich nur dann, wenn Sie die Textur gerade von vorne betrachten. Betrachten Sie die Textur von der Seite, so wird die Textur perspektivisch entsprechend gerendert. Dieses Beispiel ist recht einfach zu verstehen. Aber wie sieht es aus, wenn wir ein Rechteck bilden, welches aus mehr als zwei Dreiecken erstellt wurde. Verdeutlichen wir uns das Problem mit einem rechteckigen 3D-Objekt, das aus acht Dreiecken gebildet wird. Wir haben die einzelnen Dreiecke nummeriert. So können Sie erkennen, in welcher Reihenfolge wir die Polygone erstellt haben. Natürlich dürfen Sie auch eine andere Reihenfolge wählen. Die Parameter tu und tv ändern sich dadurch nicht. (Außer Sie ändern nicht nur die Reihenfolge, sondern auch die Parameter x, y und z.)
Kapitel 2 • Direct3D
0, 0
0, 0.5
0, 1
173
0.5, 0
1, 0
0.5, 0.5
0.5, 1
1, 0.5
Bitmap
1, 1
Bild 2.30: Rechteck aus acht Polygonen Dim Vert(23) As D3DVERTEX 'Dreieck 1 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex Vert(1) DirectX7.CreateD3DVertex Vert(2) 'Dreieck 2 DirectX7.CreateD3DVertex Vert(3) DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Dreieck 3 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Dreieck 4 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex Vert(10) DirectX7.CreateD3DVertex Vert(11) 'Dreieck 5 DirectX7.CreateD3DVertex Vert(12) DirectX7.CreateD3DVertex Vert(13) DirectX7.CreateD3DVertex 'Dreieck 6
0, 0, 0 , -1, 0, -1, 0, 1, Vert(0) 0, 2.5, 0 , -1, 0, -1, 0, 0.5, _ 2.5, 2.5, 0 , -1, 0, -1, 0.5, 0.5, _
2.5, 2.5, 0, -1, 0, -1, 0.5, 0.5, _ 2.5, 0 ,0, -1, 0, -1, 0.5, 1, Vert(4) 0, 0 ,0, -1, 0, -1, 0, 1, Vert(5) 0, 2.5, 0, -1, 0, -1, 0, 0.5, Vert(6) 0, 5 ,0, -1, 0, -1, 0, 0, Vert(7) 2.5, 5 ,0, -1, 0, -1, 0.5, 0, Vert(8) 2.5, 5, 0, -1, 0, -1, 0.5, 0, Vert(9) 2.5, 2.5 ,0, -1, 0, -1, 0.5, 0.5, _ 0, 2.5 ,0, -1, 0, -1, 0, 0.5, _
2.5, 2.5, 0, -1, 0, -1, 0.5, 0.5, _ 2.5, 5 ,0, -1, 0, -1, 0.5, 0, _ 5, 5 ,0, -1, 0, -1, 1, 0, Vert(14)
174
Texturen
DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex Vert(16) DirectX7.CreateD3DVertex Vert(17) 'Dreieck 7 DirectX7.CreateD3DVertex Vert(18) DirectX7.CreateD3DVertex Vert(19) DirectX7.CreateD3DVertex Vert(20) 'Dreieck 8 DirectX7.CreateD3DVertex Vert(21) DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex Vert(23)
5, 5, 0, -1, 0, -1, 1, 0, Vert(15) 5, 2.5 ,0, -1, 0, -1, 1, 0.5, _ 2.5, 2.5 ,0, -1, 0, -1, 0.5, 0.5, _
2.5, 0, 0, -1, 0, -1, 0.5, 1, _ 2.5, 2.5 ,0, -1, 0, -1, 0.5, 0.5, _ 5, 2.5 ,0, -1, 0, -1, 1, 0.5, _
5, 2.5, 0, -1, 0, -1, 1, 0.5, _ 5, 0 ,0, -1, 0, -1, 1, 1, Vert(22) 2.5, 0 ,0, -1, 0, -1, 0.5, 1, _
Anhand dieses Beispiels sehen Sie, dass den Vertexen der Polygone immer ein entsprechender Anteil der Gesamttextur zugewiesen wird. Beachten Sie, dass Sie die Polygone im Uhrzeigersinn erstellen. Dadurch richten Sie den Normalvektor der Polygone zum Betrachter und das Polygon ist sichtbar. Ist der Normalvektor vom Betrachter abgewandt, so ist das gesamte Polygon nicht sichtbar. Sie müssten das Polygon umlaufen und von der anderen Seite betrachten, damit es sichtbar wird. Was passiert eigentlich, wenn das 3D-Objekt nicht rechteckig ist? In diesem Fall werden Sie vor eine Entscheidung gestellt. Sie haben die Möglichkeit, entweder die Textur zu dehnen oder Sie entscheiden sich dafür, nur einen bestimmten Ausschnitt aus der Textur herauszuschneiden. Nehmen wir als Beispiel ein Trapez, welches aus zwei Dreiecken erstellt wurde. Dehnen / Stauchen der Textur: Die obere Kante des Trapezes ist länger als die untere Kante. Interpolieren wir die Länge beider Kanten auf [1], so wird die aufgezogene Textur gestaucht. Dim Vert(5) As D3DVERTEX 'Polygon 1 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Polygon 2 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex
1, 0, 0 , -1, 0, -1, 0, 1, Vert(0) 0, 5, 0 , -1, 0, -1, 0, 0, Vert(1) 4, 0, 0 , -1, 0, -1, 1, 1, Vert(2) 0, 5, 0, -1, 0, -1, 0, 0, Vert(3) 5, 5 ,0, -1, 0, -1, 1, 0, Vert(4) 4, 0 ,0, -1, 0, -1, 1, 1, Vert(5)
Kapitel 2 • Direct3D
175
0, 0
1, 0
Polygon 2
Polygon 1 0, 1
1, 1
Bild 2.31: Gestauchte Polygone
Wenn Sie sich das Texturbeispiel 3 auf der CD anschauen, dann können Sie einen seltsamen Effekt beobachten. Wir verwenden zwei Dreiecke. Diese bilden ein Trapez. Nun sollte die Bitmap nach unten hin zusammenlaufen. Dies ist aber nicht der Fall. Sie können erkennen, das die vertikalen Linien der Textur zwar schräg verlaufen aber nicht gestaucht werden. Dies liegt hauptsächlich an einer Vereinfachung der Algorithmen. Direct3D steht immer zwischen den Fronten. Auf der eine Seite erwartet der Anwender eine optimale Qualität. Auf der anderen Seite wird optimale Performance erwartet. Optimale Qualität und optimale Performance lassen sich nie richtig verbinden. Im Zweifelsfall wird sich D3D für eine Lösung entscheiden, welche die besseren Performance bietet. In diesem Fall ist das sowieso kein echtes Problem. Dass eine rechteckige Bitmap auf eine Trapez aufgezogen wird, kommt recht selten vor. Sollten Sie diesen Effekt benötigen, dann nutzen Sie ein 3D-Objekt, welches aus vielen Polygonen besteht. In der 3DWelt werden Sie den vereinfachten Algorithmus nicht mehr erkennen können. (Außer Sie verwenden eine so deutlich strukturierte Bitmap, wie wir es in unserem Beispiel tun.) Ausschneiden der Textur: Dim Vert(5) As D3DVERTEX 'Polygon 1 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Polygon 2 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex
0, 0, 0 , -1, 0, -1, 0.25, 1, Vert(0) 0, 5, 0 , -1, 0, -1, 0, 0, Vert(1) 5, 5, 0 , -1, 0, -1, 0.75, 1, Vert(2) 5, 5, 0, -1, 0, -1, 0, 0, Vert(3) 5, 0 ,0, -1, 0, -1, 1, 0, Vert(4) 0, 0 ,0, -1, 0, -1, 0.75, 1, Vert(5)
176
Texturen
0, 0
1, 0
Polygon 2
Polygon 1 0.25, 0
0.75, 0
Bild 2.32: Ausgeschnittene Textur
In diesem Beispiel setzten wir die obere Kante und die untere Kante in das richtige Verhältnis. Der Vorteil ist, das wir die Bitmap ohne Verzerrungen betrachten können. Der Nachteil ist, das uns Daten von der Bitmap verloren gehen. Die verlorenen Bitmapdaten finden wir an den Seitenteilen des Trapezes. Da wir nun aus einer rechteckigen Bitmap die Daten für die Textur heraustrennen, werden die abgeschnittenen Bitmapteile nicht angezeigt. Folgende Abbildung verdeutlicht dies Welches Verfahren Sie wann einsetzen, ist von der jeweiligen Situation abhängig. Texturen welche z.B. ein verworrenes Muster (rauer Beton, Felsen) darstellen, können Sie meistens dehnen oder stauchen, ohne einen sichtbaren Fehler zu bemerken. Für strukturierte Texturen wie Mauerwerk oder Bilder eignet sich dieses Verfahren nicht. Am besten entscheiden Sie beim Konstruieren Ihrer Szene, wie die Texturen dargestellt werden sollen. Texture Warp Bisher haben wir behauptet, dass die Texturadressen für die Vertexe eines Polygons zwischen 0.0 und 1.0 liegen. Diese Aussage wollen wir etwas modifizieren. Stellen Sie sich vor, Sie wollen in Ihrer 3D-Welt eine lange Wand mit einer kleinen Mauerstruktur einbauen. Jetzt haben Sie zwei Möglichkeiten. Zum einen können Sie eine sehr große Textur benutzen. Dies ist allerdings vom Speicherhandling her problematisch, wenn nicht sogar unmöglich. Als Alternative zu einer sehr großen Textur steht uns das Kacheln der Textur zur Verfügung. Diese Technik wird als Warp Texture Address Mode bezeichnet. Diese Technik wird nicht von allen Grafikkarten unterstützt. Dennoch besitzen alle moderneren Grafikkarten diese Fähigkeit.
Kapitel 2 • Direct3D
177
0, 0
1, 0
Polygon 2
Polygon 1 0.25, 0
0.75, 0 Verlust an Bitmapdaten
Verlust an Bitmapdaten Bild 2.33: Ausgeschnittene Textur
Kombinationen mit dem Border-, Mirror- und Clamp-Mode sind erlaubt. 0, 0
1, 0
2, 0
5 Bitmap
11 Bitmap
17 Bitmap
0, 1
1, 1
6
12 2, 1
3 Bitmap
9 Bitmap
0, 2
1, 2
4
3, 0
18 3, 1
15 Bitmap
10 2, 2
16 3, 2
1 Bitmap
7 Bitmap
13 Bitmap
0, 3
1, 3
2, 3
2
Bild 2.34: Warp
8
14 3, 3
Bitmap
178
Texturen
Das Bildschirmfoto zeigt den Warp-Effekt in der Realität.
Bild 2.35: Bildschirmfoto Warp
Hier sehen Sie, dass der Adressbereich nicht mehr auf den Wertebereich zwischen 0.0 und 1.0 begrenzt ist. Der Warp Address Mode wird nun die Bitmap auf jede Ganzzahl dehnen bzw. stauchen. Die Bitmap wird sich in diesem Beispiel insgesamt neunmal wiederholen. Betrachten wir die Zuweisungen der tu- und tv-Parameter des D3DVERTEX-Typen-Arrays. Dim Vert(53) As D3DVERTEX 'Dreieck 1 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Dreieck 2 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Dreieck 3 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Dreieck 4
0, 0, 0 , -1, 0, -1, 0, 0, Vert(0) 0, 5, 0 , -1, 0, -1, 0, 1, Vert(1) 5, 5, 0 , -1, 0, -1, 1, 1, Vert(2) 5, 5, 0, -1, 0, -1, 1, 1, Vert(3) 5, 0 ,0, -1, 0, -1, 1, 0, Vert(4) 0, 0 ,0, -1, 0, -1, 0, 0, Vert(5) 0, 5, 0, -1, 0, -1, 0, 1, Vert(6) 0, 10 ,0, -1, 0, -1, 0, 2, Vert(7) 5, 10 ,0, -1, 0, -1, 1, 2, Vert(8)
Kapitel 2 • Direct3D
DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex . . . 'Dreieck 15 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Dreieck 16 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Dreieck 17 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex 'Dreieck 18 DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex DirectX7.CreateD3DVertex
179
5, 10, 0, -1, 0, -1, 1, 2, Vert(9) 5, 5 ,0, -1, 0, -1, 1, 1, Vert(10) 0, 5 ,0, -1, 0, -1, 0, 1, Vert(11)
10, 5, 0, -1, 0, -1, 2, 1, Vert(42) 10, 10 ,0, -1, 0, -1, 2, 2, Vert(43) 15, 10 ,0, -1, 0, -1, 3, 2, Vert(44) 15, 10, 0, -1, 0, -1, 3, 2, Vert(45) 15, 5 ,0, -1, 0, -1, 3, 1, Vert(46) 10, 5 ,0, -1, 0, -1, 2, 1, Vert(47) 10, 10, 0, -1, 0, -1, 2, 2, Vert(48) 10, 15 ,0, -1, 0, -1, 2, 3, Vert(49) 15, 15 ,0, -1, 0, -1, 3, 3, Vert(50) 15, 15, 0, -1, 0, -1, 3, 3, Vert(51) 15, 10 ,0, -1, 0, -1, 3, 2, Vert(52) 10, 10 ,0, -1, 0, -1, 2, 2, Vert(53)
Einschalten des WARP-Modus für die Parameter tu und tv: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_WARP Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESS, _ TextureAD
Dieses Beispiel aktiviert den Warp-Modus für die Parameter tu und tv. Alternativ können Sie auch selektiert auf einen der Parameter zugreifen. Einschalten des WARP-Modus für den Parameter tu: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_WARP Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESSU, _ TextureAD
Einschalten des WARP-Modus für den Parameter tv: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_WARP Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESSV, _ TextureAD
Der Warp-Modus ist der voreingestellte Modus von D3D. Um den Modus explizit zuzuweisen, dimensionieren Sie eine Variable vom Typ CONST_D3DTEXTURE ADDRESS. Somit stehen Ihnen folgende Möglichkeiten zur Verfügung:
180
Texturen
Enum CONST_D3DTEXTUREADDRESS D3DTADDRESS_WARP D3DTADDRESS_MIRROR D3DTADDRESS_CLAMP D3DTADDRESS_BORDER End Enum
= = = =
1 2 3 4
Texture Mirror Der Mirror-Modus spiegelt Texturen horizontal und vertikal oder nur horizontal bzw. nur vertikal. Dabei wird die Textur ebenfalls gekachelt wie in dem WarpModus. Die Spiegelung wirkt sich immer auf eine volle Ganzzahl der gesamten Texturdimension aus. In der Abbildung unten spiegeln wir in horizontaler und vertikaler Richtung. Die erste Textur von 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 bis 0.0, 1.0 wird normal dargestellt. Die horizontal benachbarte Textur wird horizontal gespiegelt. Die vertikal benachbarte Textur wird vertikal gespiegelt. Die diagonal liegende Textur wird horizontal und vertikal gespiegelt. Anschließend wiederholt sich alles. Kombinationen mit dem Warp-, Border- und Clamp-Mode sind erlaubt.
1,0
2,0
0,0 Bitmap normal
Bitmap Bitmap tu gespiegelt normal
0,1
1,1
2,1
3,0 Bitmap 3,1
Bitmap Bitmap Bitmap tv gespiegelt tu gespiegelt tv gespiegelt 0,2
1,2
2,2
Bitmap normal
Bitmap tu gespiegelt
Bitmap normal
0,3
1,3
2,3
3,2
3,3
Bild 2.36: Mirror
Einschalten des MIRROR-Modus für die Parameter tu und tv: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_MIRROR Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESS, _ TextureAD
Kapitel 2 • Direct3D
181
Bild 2.37: Bildschirmfoto Mirror
Einschalten des MIRROR-Modus für den Parameter tu: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_MIRROR Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESSU, _ TextureAD
Einschalten des MIRROR-Modus für den Parameter tv: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_MIRROR Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESSV, _ TextureAD
Texture Clamp Der Clamp-Mode stellt im Bereich von 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 bis 0.0, 1.0 die Textur normal dar. Die aktuellen Pixel am Ende der Zeilen und Spalten werden auf die gesamt Texturdimension erweitert. Das wirkt so, als hätten Sie die Textur über eine nasse Farbe gezogen. Kombinationen mit dem Warp-, Mirror- und Border-Mode sind erlaubt.
182
Texturen
0, 0
1, 0
2, 0
3, 0
Bitmap normal
Bitmap
0, 1
1, 1
2, 1
3, 1
0, 2
1, 2
2, 2
3, 2
0, 3
1, 3
2, 3
3, 3
Bild 2.38: Clamp
Bild 2.39: Bildschirmfoto Clamp
Kapitel 2 • Direct3D
183
Einschalten des CLAMP-Modus für die Parameter tu und tv: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_CLAMP Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESS, _ TextureAD
Einschalten des CLAMP-Modus für den Parameter tu: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_CLAMP Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESSU, _ TextureAD
Einschalten des CLAMP-Modus für den Parameter tv: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_CLAMP Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESSV, _ TextureAD
Texture Border Der Border-Mode stellt im Bereich von 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 bis 0.0, 1.0 die Textur normal dar. Der Rest der gesamten Texturdimension wird mit der aktuellen Zeichenfarbe gefüllt. Kombinationen mit dem Warp-, Mirror- und Clamp- Mode sind erlaubt. 0, 0
1, 0
2, 0
3, 0
Bitmap normal
Bitmap
0, 1
1, 1
2, 1
3, 1
0, 2
1, 2
2, 2
3, 2
0, 3
1, 3
2, 3
3, 3
Bild 2.40: Border
aktuelle Zeichenfarbe
184
Texturen
Bild 2.41: Bildschirmfoto Border
Einschalten des BORDER-Modus für die Parameter tu und tv: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_BORDER Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESS, _ TextureAD
Einschalten des BORDER-Modus für den Parameter tu: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_BORDER Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESSU, _ TextureAD
Einschalten des BORDER-Modus für den Parameter tv: Dim TextureAD As CONST_D3DTEXTUREADDRESS TextureAD = D3DTADDRESS_BORDER Direct3DDevice7.SetTextureStageState 0, D3DTSS_ADDRESSV, _ TextureAD
2.10.3 Texture Filtering Direct3D rendert ein dreidimensionales Polygon auf einen zweidimensionalen Bildschirm. Ist dieses Polygon mit einer Textur überzogen, so muss D3D die Texel (Pixel auf einer Textursurface) der Textur auf die Pixel des Monitors
Kapitel 2 • Direct3D
185
umrechnen. Dies bringt Darstellungsprobleme mit sich, da eine Textur nur zweidimensional und nicht unendlich genau ist. Einerseits soll die Textur perspektivisch korrekt auf das Polygon gelegt werden, anderseits kann die Textur aufgrund fehlender Bandbreite und Speicherplatz nicht unendlich groß sein, so dass normalerweise relativ kleine Texturen gezoomt werden, wenn man sich dem Objekt nähert. Auch das Gegenteil, das Verkleinern einer Textur, bringt Probleme mit sich. Es müssen Lösungen gesucht werden, um die fehlenden Pixel und die aus der Ungenauigkeit entstehenden visuellen Artefakte zu vermindern. Vergrößerungsproblem:
Texel
Texture
Texel
Monitorbild
Bild 2.42: Vergrößerungsproblem
Stellen Sie sich vor, Sie haben eine Wand mit einer Textur erzeugt. Diese positionieren Sie in Ihrer 3D-Welt. Aus der Ferne betrachtet, sieht die Wand recht gut aus. Je mehr Sie sich der Wand nähern, desto gröber werden die Texel auf dem Monitorbild dargestellt. Stehen Sie unmittelbar vor der Wand, so wirkt die Wand, als wäre sie aus groben Klötzchen erstellt worden. Vergleichen Sie das mit einem Blick durch ein Mikroskop. Dort sieht eine scheinbar glatte Oberfläche wie eine Mondlandschaft aus. Da Direct3D große Farbfelder bildet, wirkt das noch viel schlimmer. Verkleinerungsproblem: Stehen wir in der 3D-Welt sehr weit entfernt von unserer Wand, treten folgende Probleme auf. Auf der Textur sind z.B. vier Texel; diese sollen in Pixel des Monitorbildes umgerechnet werden. Bei der Darstellung der Wand auf dem Monitor ist aber nur Platz für z.B. ein Pixel. Direct3D muss nun entscheiden, welches von den vier Texeln dargestellt werden soll. Welches Texel gewählt wird, ändert sich je nach Position und Blickrichtung des Betrachters. Nun tritt der so genannte Shimmering-Effekt auf.
186
Texturen
Texel
Texture
Texel
Monitorbild
Bild 2.43: Verkleinerungsproblem
»Shimmering«: Bildfehler, bei dem einem einzelnen Pixel eines Objekts je nach Betrachtungsstandort eine andere Farbe zugewiesen wird. Bei 30 Bildern pro Sekunde wirkt dies wie ein schnelles Flackern. Problemlösung: Um die beschriebenen Probleme zu lösen, gibt es eine Vielzahl von Vorschlägen. Direct3D stellt uns vier Techniken bereit. •
Nearest Point Sampling Nearest Point Sampling war eine der ersten Techniken zur Verbesserung der Bildqualität von Texturen. Diese Technik, wenn man überhaupt von einer Technik sprechen kann, ist recht einfach erklärt. Der Grundgedanke ist, dass Pixel auf dem Monitor immer als Ganzzahlkoordinaten angegeben werden. Also ging man hin und hat die Fließkommawerte einfach gerundet. Somit sollte das wahrscheinlichste Texel selektiert werden. Wurde von D3D das Koordinatenpaar [x = 103,8] und [y = 103,2] errechnet, so wird das entsprechende Texel letztendlich am Koordinatenpaar [x = 104] und [y = 103] dargestellt. Sie können sich vorstellen, dass diese Technik mit wenig Rechenzeit auskommt. Damit erhält dieses Verfahren eine große Beliebtheit. Ob diese Technik den Begriff Technik verdient, sollten Sie selber entscheiden.
Natürlich verliert diese Technik mit steigenden Rechnerkapazitäten ihre Bedeutung. •
Linear Texture Filtering •
Bilineares Filtering: Nähert man sich einer Textur, bilden sich Blöcke. Mit dem bilinearen Fil-
Kapitel 2 • Direct3D
187
tering werden weiche Übergänge berechnet. Durch Aliasing verursachtes Flimmern wurde ebenfalls durch Filtering beseitigt. •
•
•
Trilineares Filtering: Ähnlich dem bilinearen Filtering, jedoch um einiges rechenaufwendiger (ca. 8 mal aufwendiger als bilinerar), da der Mittelwert von zwei bilinear gefilterten Pixeln genommen werden muss! Dieser Effekt wird unter anderem für das Mipmapping verwendet.
Anisotropic Texture Filtering •
Anisotropic Filtering: Eine neue Filtertechnik für Texturen, damit diese auch unter flachen Winkeln anschaulich bleiben und Texte darauf lesbar bleiben.
•
Texture Filtering mit Mipmaps
Mipmapping: (MIP abk. für Multum In Parvum; viele unter gleichen) Um bei Annäherung an ein Objekt mehr Details erkennen zu können, werden diesem Objekt mehrere Texturen zugeordnet. Je näher der Betrachter kommt, umso mehr Details werden sichtbar. Hochauflösende Texturen werden in der Nähe verwendet, niedrigauflösende für entfernte Objekte. In Zusammenhang mit linearem Filtering sehr wirkungsvoll.
Nearest Point Sampling Die Nearest-Point-Sampling-Technik kann die Bildung von Artefakten nicht verhindern. Diese Artefakte entstehen an den Grenzen eines Polygons in einem 3DObjekt. Begründet wird dieses Verhalten dadurch, das diese Technik lediglich ein Texel aus einer Auswahl von vielen darzustellenden Texel auf dem Monitor auswählt. Diese Auswahl könnte man auf Bezug der Texelfarbe als willkürlich bezeichnen. Die folgenden zwei Abbildungen verdeutlichen das Problem. Wir erstellen eine 3D-Fläche aus insgesamt achtzehn Polygonen. Über diese Fläche spannen wir eine Textur mit horizontalen Streifen. Das Ergebnis bei der Darstellung auf dem Monitor könnte so aussehen. Konzentrieren Sie sich lediglich auf die Grenze zwischen Polygon 17 und 18. In unserem Beispiel sind die Texel der Streifentextur überdimensional groß dargestellt. Dennoch können Sie die Entstehung eines Artefaktes gut erkennen. Eigentlich sollte sich das Streifenmuster beim Übergang von Polygon 17 nach 18 ganz normal fortsetzten. Dies ist aber nicht der Fall. Direct3D hat den Ansatz des Streifenmusters für Polygon 18 etwas nach unten verschoben. Dies erklärt sich durch die simple Berechnungsmethode der Nearest Point Sampling Technik. Die Position des Texels auf dem Bildschirm wird durch einfaches Auf- und Abrunden der errechneten Pixelkoordinaten bestimmt. In Abhängigkeit von der Position und Blickrichtung des Betrachters treten diese Artefakte willkürlich auf.
188
Texturen
0, 0
1, 0
2, 0
5
11
17
0, 1
6
3 0, 2
12 2, 1
9 4
1 0, 3
1, 1
18 3, 1
15
1, 2
10 2, 2
7 2
3, 0
16 3, 2
13
1, 3
8
2, 3
14 3, 3
Bild 2.44: Fläche aus 18 Polygonen
0, 0
1, 0
2, 0
3, 0
0, 1
3, 1
0, 2
3, 2
Artefakt
3, 3 0, 3
1, 3
2, 3
Bild 2.45: Texturfehler bei Polygon 18
Bei Polygon 17 wurde für den Betrachter noch richtig gerundet und bei Polygon 18 kam es für den Betrachter zu einer fehlerhaften Rundung. Aktivieren der Nearest-Point-Sampling-Technik: Sie müssen die Filtertechnik für den Fall der Vergrößerung sowie für den Fall der Verkleinerung einzeln setzen. Direct3D bezeichnet diese Elemente als magnificaption filering modes und minification filtering modes.
Kapitel 2 • Direct3D
189
Vergrößerung: Dim TextureMagFilter As CONST_D3DTEXTUREMAGFILTER TextureMagFilter = D3DTFG_POINT Direct3DDevice7.SetTextureStageState 0, D3DTSS_MAGFILTER, _ TextureMagFilter
Verkleinerung: Dim TextureMinFilter As CONST_D3DTEXTUREMAGFILTER TextureMinFilter = D3DTFG_POINT Direct3DDevice7.SetTextureStageState 0, D3DTSS_MINFILTER, _ TextureMinFilter
Linear Filter Eine deutliche Verbesserung der Bildqualität biete die lineare Filterung. Diese Technik wird auch als Bilinear Filtering bezeichnet. Das bilineare Filtern ist die heute am weitesten verbreitete Technik. Sie sorgt weitgehend dafür, das die lästigen Artefakte verschwinden. Mit aktivierter bilinearer Filterung wirken Texturen auf den ersten Blick etwas verwaschen. Objekte haben oftmals keine scharfen Kanten mehr. Dies kann dazu führen, dass Ihr Auge ein Objekt fokussieren möchte, das nicht zu fokussieren ist. Dennoch vermittelt diese Technik ein sehr viel harmonischeres, weicheres Bild, als es die Nearest-Point-Sampling-Technik vermag. Der Wischi-Waschi-Effekt ist besonders bei Texturen mit einer geringen Detailtiefe zu beobachten. Mit zunehmend steigender Performance werden immer detailliertere Texturen eingesetzt. Dies vermindert den Wischi-Waschi-Effekt. Bei der Nearest-Point-Sampling-Technik wurde das auf dem Monitor sichtbare Pixel durch einfaches Runden des Koordinatenpaars ermittelt. Dies führte zu abrupten Farbübergängen und zu unangenehmen Artefakten. Die bilineare Filterung benutzt vier Texel der Textur, zur Berechnung des endgültigen Pixels auf dem Monitor. Aus diesen vier Textur-Texeln wird ein gewichteter Mittelwert ermittelt. Dieser Mittelwert stellt die neue Farbe des Pixels auf dem Monitor dar. Wurde z.B. das Koordinatenpaar x = 12.2 und y = 20.2 ermittelt, so werden die Texel 12,20, 11,20, 12,19 und 11,19, als Berechnungsgrundlage genommen. Diese Texel fließen nicht zu gleichen Anteilen in die Berechnung ein, sondern sie werden entsprechend dem Abstand zum berechneten Koordinatenpaar vermischt. Als Gewicht wird das Verhältnis der Abstände der jeweiligen Texel zum genauen Wert bezeichnet. Gehen wir einmal davon aus, dass die oben abgebildeten Texel zur Berechnung des Pixels benutzt werden. Der Farbwert des neuen Pixel würde sich wie folgt ergeben Um die neue Farbe zu ermitteln, muss erst die Farbe des jeweiligen Texels in die RGB-Bestandteile zerlegt werden. Nachdem die neuen Anteile ermittelt wurden, kann die neue Pixelfarbe wieder zusammengesetzt werden.
190
Texturen
Bild 2.46: Texturfehler bei Polygon 18
Gewicht *
+ Gewicht *
+
Gewicht *
+ Gewicht *
=
neue Farbe
?
Bild 2.47: Gewichtete neue Farbe
Rotanteil der Farbe: Gewicht(1) * Rotanteil(1) + Gewicht(2) * Rotanteil(2) + Gewicht(3) * Rotanteil(3) + Gewicht(4) * Rotanteil(4) = Rotanteil der neuen Farbe
Blauanteil der Farbe: Gewicht(1) * Blauanteil(1) + Gewicht(2) * Blauanteil(2) + Gewicht(3) * Blauanteil(3) + Gewicht(4) * Blauanteil(4) = Blauanteil der neuen Farbe
Grünanteil der Farbe: Gewicht(1) * Grünanteil(1) + Gewicht(2) * Grünanteil(2) + Gewicht(3) * Grünanteil(3) + Gewicht(4) * Grünanteil(4) = Grünanteil der neuen Farbe
Neue Farbe: RGB(Rotanteil der neuen Farbe, Blauanteil der neuen Farbe, Grünanteil der neuen Farbe)
Sie sehen, dass die neue Farbe nur mit einigem Rechenaufwand erstellt werden kann. Um die einzelnen Farbanteile der neuen Farbe zu ermitteln, werden 12 Multiplikationen und 9 Additionen benötigt. Sollte Ihre Grafikkarte die Fähigkeit des bilinearen Filterns nicht besitzen, so werden Sie mit einem Performancever-
Kapitel 2 • Direct3D
191
lust rechnen müssen. Es ist allerdings recht unwahrscheinlich, dass Ihre Grafikkarte diese Technik nicht unterstützt. Wir kennen keine Grafikkarte mit 3DUnterstützung, die bilineares Filtern nicht unterstützt. Aktivieren des linearen Filters: Auch bei dieser Technik müssen Sie die Filtertechnik für den Fall der Vergrößerung sowie für den Fall der Verkleinerung einzeln setzen. Direct3D bezeichnet diese Elemente als magnification filering modes und minification filtering modes. Vergrößerung: Dim TextureMagFilter As CONST_D3DTEXTUREMAGFILTER TextureMagFilter = D3DTFG_LINEAR Direct3DDevice7.SetTextureStageState 0, D3DTSS_MAGFILTER, _ TextureMagFilter
Verkleinerung: Dim TextureMinFilter As CONST_D3DTEXTUREMAGFILTER TextureMinFilter = D3DTFG_LINEAR Direct3DDevice7.SetTextureStageState 0, D3DTSS_MINFILTER, _ TextureMinFilter
Diese Filterung funktioniert perfekt, wenn die Dreiecke senkrecht zum Betrachter stehen. Dies ist aber sehr unwahrscheinlich. Im Regelfall ist es so, dass das Dreieck etwas geneigt ist, dann bietet diese Technik keine hundertprozentigen Ergebnisse. Auf jeden Fall bietet bilineare Filterung eine deutliche Verbesserung zur Nearest-Point-Sampling-Technik. Uneinheitlicher Filter Das uneinheitliche Filtern wird auch als anisotropic filtering bezeichnet. Nach unseren Informationen besteht für diese Technik kein einheitlicher Algorithmus. Die Hardwarehersteller sind somit ziemlich frei in der Art, wie sie dieses Feature unterstützen wollen. Dies führt natürlich dazu, das es immer Hersteller geben wird, welche einen minderwertigen Algorithmus verwenden. Dies wird die Performance der Grafikkarte zwar steigern, aber der gewünschte grafische Vorteil leidet darunter am meisten. Die Softwareemulation von Direct3D benutzt einen absolut reinen Algorithmus. Diesen betrachten wir als Referenz zu denen, welche von diversen Grafikkartenherstellern eingesetzt werden. Die teilweise wirklich schlechte Qualität ist dann am ehesten mit einem bilinearen Filter zu vergleichen. Im Gegensatz zum bilinearen Filtern werden nicht mehr viereckige Texelbereiche zur Interpolation der neuen Pixelfarbe berücksichtigt, sondern unregelmäßige Formen. Beim linearen Filtern werden bei geneigten Flächen die räumlich tiefen Pixel zuwenig stark gefiltert, die räumlich näheren Pixel werden leicht überfiltert. Anisotropisches Filtern berücksichtigt die perspektivischen Verzerrungen und
192
Texturen
nutzt umso mehr Texel für ein Pixel, je weiter sich das jeweilige Pixel in der Tiefe des Raums befindet. Besonders gut lässt sich die Verbesserung der Bildqualität beobachten an Texten, die in die Tiefe scrollen. Aktivieren des anisotropischen Filters: Auch bei dieser Technik müssen Sie die Filtertechnik für den Fall der Vergrößerung sowie für den Fall der Verkleinerung einzeln setzen. Direct3D bezeichnet diese Elemente als magnification filering modes und minification filtering modes. Zusätzlich müssen Sie dem Renderdevice noch mitteilen, wie sich die anisotropische Filterung auswirken soll. Nutzen Sie hierfür die D3DTSS_MAXANI SOTROPY- Parameter der SetTextureStage()-Methode. Ein Wert größer eins aktiviert den Filter. Der Standardwert ist eins. Vergrößerung: Dim TextureMagFilter As CONST_D3DTEXTUREMAGFILTER TextureMagFilter = D3DTFG_ANISOTROPIC Direct3DDevice7.SetTextureStageState 0, D3DTSS_MAGFILTER, _ TextureMagFilter Direct3DDevice.SetTextureStageState 0, D3DTSS_MAXANISOTROPY, 2
Verkleinerung: Dim TextureMinFilter As CONST_D3DTEXTUREMAGFILTER TextureMinFilter = D3DTFG_ANISOTROPIC Direct3DDevice7.SetTextureStageState 0, D3DTSS_MINFILTER, _ TextureMinFilter Direct3DDevice.SetTextureStageState 0, D3DTSS_MAXANISOTROPY, 2
Filter mit Mipmaps Die Erfinder der Mipmap-Filter-Technik sind des Lateinischen wohl mächtig. MIP steht für Multum in Parvo. Zeitgemäß in die deutsche Sprache übersetzt bedeutet es so viel wie »Viele unter Gleichen«. Eine Mipmap ist eine Reihe von Texturen. Jede Textur stellt die gleiche Bitmap dar, jedoch mit abnehmender Auflösung. Eine Textur mit niedriger Auflösung wird eingesetzt, wenn der Betrachter noch sehr weit entfernt ist. Je näher der Betrachter sich nähert, desto höher werden die aufgelösten Texturen von D3D eingesetzt. Dabei ist D3D eigenständig in der Lage abzuschätzen, welche Textur im Moment am besten geeignet ist. Direct3D verwaltet die Texturreihe als Kette. Die Textur mit der größten Auflösung steht am Anfang der Kette. Betrachten wir den elementaren Vorteil dieser Technik. Stellen Sie sich eine Wand vor, die sehr weit entfernt ist. Die Texture die auf die Wand projiziert wird, muss stark verkleinert werden. Trotz Filtertechnik entstehen die bekannten, hässlichen Shimmering-Effekte. Außerdem ist es unlogisch immer eine große Textur (z.B. 512 x 512 Pixel) zu verwenden, wenn lediglich 20 x 20 Pixel dargestellt werden.
Kapitel 2 • Direct3D
193
Diese Textur mit einer relativ hohen Auflösung von 256 * 256 Pixel wird verwendet, wenn sich der Betrachter recht nah an der Textur befindet. Der Text ist gut lesbar.
Bild 2.48: Gewichtete neue Farbe
Diese Textur besitzt eine kleine Auflösung. Sie wird verwendet, wenn sich der Betrachter aus dem lesbaren Bereich entfernt. Die Auflösung beträgt 128 * 128 Pixel.
Bild 2.49: Gewichtete neue Farbe
Die folgende Textur ist sehr schlecht lesbar. Sie besitzt eine Auflösung von 64 * 64 Pixel. Sie wird benötigt, wenn sich der Betrachter der Textur langsam nähert, aber den Text noch nicht lesen soll.
194
Texturen
Bild 2.50: Gewichtete neue Farbe
Natürlich kann man die Auflösung der Texturen noch weiter verkleinern. Dies ist bis zu 1 * 1 Pixel möglich. Um Mipmap-Filter zu verwenden, müssen Sie eine Mipmap-Kette erstellen. Die normale Mipmap-Kette verwendet fünf Surfacelevel mit den Größen [256 * 256], [128 * 128], [64 * 64], [32 * 32] und [16 * 16]. Den Texturesurfaces müssen zu dem normalem DDSCAPS_TEXTURE-Flag noch die Flags DDSCAPS_ MIPMAP und DDSCAPS_COMPLEX zugewiesen werden. Der folgende Source-Code zeigt die notwendigen Schritte zum Einrichten einer Mipmapsurface. Dim ddsd As DDSURFACEDESC2 Dim DDMipmap As DirectDrawSurface7 ddsd.lFlags = DDSD_CAPS Or DDSD_MIPMAPCOUNT
Das DDSD_MIPMAPCOUNT-Flag müssen wir setzen, damit wir im Anschluss angeben können, wie viele Mipmap-Level verwendet werden. ddsd.lMipmapCount = 5
Hiermit geben wir die Anzahl der verwendeten Mipmap-Level an. ddsd.ddsCaps.lCaps = DDSCAPS_TEXTURE Or DDSCAPS_MIPMAP Or _ DDSCAPS_COMPLEX ddsd.lWidth = 256 ddsd.lHeight = 256
Mit den Parametern lWidth und lHeight bestimmen wir den Toplevel der Mipmap-Textur. Dies ist wichtig für D3D, da anhand dieser Angaben die Größen der untergeordneten Mipmap-Level berechnet werden. In unserem Beispiel definieren wir die Parameter lWidth mit 256 und lHeight mit 256. Somit ergeben sich die Mipmap-Level: Level 0 Level 1 Level 2 Level 3 Level 4
[256 * 256] [128 * 128] [64 * 64] [32 * 32] [16 * 16]
Kapitel 2 • Direct3D
195
Sie müssen mit den Parametern vorsichtig umgehen. So wäre die Kombination von lMipmapCount 5 und lWidth 8 sowie lHeight 8 nicht zulässig. Dies wird zu einem Fehler führen. Level 0 Level 1 Level 2 Level 3 Level 4
[8 * 8] [4 * 4] [2 * 2] [1 * 1] [F E H L E R]
Jeder folgende Level einer Mipmap-Kette besitzt die halben Dimensionen des vorangegangenen Levels. Dies führt in dem zweiten Beispiel bei Level 4 zu einem Wert kleiner eins und somit zu einem Fehler. Set DDMipmap = DD.CreateSurface(ddsd)
Leider können wir der Mipmapsurface nicht direkt eine Bitmap zuordnen. Diese müssen wir explizit über eine kleine Routine erledigen. Jetzt begnügen wir uns mit der CreateSurface()-Methode. Betrachten wir uns einmal, was wir bisher geschaffen haben. Wir haben eine Surface mit vier Untersurfaces (Untersurface ist nicht ganz richtig, denn alle Level einer Mipmapsurface sind gleichberechtigt.) erstellt. Diese sind durch eine Kette miteinander verbunden. Level 0
256 *256
Level 1
128 * 128
Level 2
64 * 64
Level 3
32 * 32
Level 4
16 * 16
Level 0
Level 1 Bild 2.51: Mipmap-Kette
Level 2
Level 3
Level 4
196
Texturen
Wie Sie erkennen, sind die Surfaces vorbereitet, aber die Bitmaps fehlen noch. Die anstehende Aufgabe besteht darin, dass wir eine Bitmap mit fünf verschiedenen Auflösungen erstellen und auf die Mipmapsurface kopieren. Wir nutzen eine kleine Routine: On Local Error Resume Next Dim DDLevel As DirectDrawSurface7 Dim DDNextLevel As DirectDrawSurface7 Dim TempSurface As DirectDrawSurface7 Dim DestRect As RECT Dim SourcRect As RECT Dim ddsCaps As DDSCAPS2 Dim DDsdTemp As DDSURFACEDESC2 Dim ddsd2 As DDSURFACEDESC2 Set DDLevel = DDMipmap
Hiermit setzen wir die Surface DDLevel gleich der zuvor erstellten DDMipmapSurface. While Err.Number = DD_OK
Die While…Wend-Schleife läuft so lange, bis ein Fehler auftritt. So lange zu Arbeiten, bis ein Fehler auftritt, ist durchaus legitim. Immerhin sorgen wir dafür, dass der Fehler ordentlich abgefangen wird und das Programm somit störungsfrei weiterarbeitet. DDLevel.GetSurfaceDesc DdsdTemp
Die aktuellen Surface-Beschreibungen der DDLevel-Surface werden der Variablen DdsdTemp übergeben. Dadurch sind wir später in der Lage, die Dimensionen der aktuellen Mipmapsurface auszulesen. Set TempSurface = g_dd.CreateSurfaceFromFile(sFile & _ Trim(Str(i)) & ".bmp", ddsd2)
Mit Hilfe der Tempsurface laden wir die unterschiedlich großen Texturen. Sie dient lediglich als Container der Bitmapdaten. Von ihr werden später die Bitmapdaten in die entsprechende Mipmapsurface geblittet. DestRect.Right = DDsdTemp.lWidth DestRect.Bottom = DDsdTemp.lHeight
Für die folgende Blitteraktion benötigen wir die richtigen Dimensionen. Diese werden dem Typen-Array DestRect As RECT übergeben. DDLevel.Blt DestRect, TempSurface, SourcRect, DDBLT_WAIT
Mit der Blt()-Methode füllen wir die aktuelle Mipmapsurface mit der Bitmap der Tempsurface.
Kapitel 2 • Direct3D
197
ddsCaps.lCaps = DDSCAPS_TEXTURE Or DDSCAPS_MIPMAP Set DDLevel = DDLevel.GetAttachedSurface(ddsCaps)
Hiermit schalten wir auf den nächsten Mipmap-Level weiter. Sobald kein weiterer Level zur Verfügung steht, wird eine Fehler erzeugt. Der Fehler sorgt dafür, dass wir die While...Wend-Schleife verlassen. i = i + 1 Wend
Beispiel (Mipmap) Das Mipmap-Beispiel demonstriert den gewaltigen Qualitätsgewinn der MipmapFiltertechnik. Sie sehen eine Wand. Die linke Hälfte der Wand nutzt die Mipmap sowie die lineare Filtertechnik. Die rechte Hälfte der Wand wird nur mit der linearen Filtertechnik gerendert. In diesem Teil der Wand können wir ganz eindeutig die grafischen Artefakte beobachten. Der größte Teil des Listings wird Ihnen vertraut sein. Somit erklären wir hauptsächlich den Mipmap-relevanten Teil. Private Declare Function GetAsyncKeyState Lib "user32" (ByVal _ vKey As Long) As Integer Dim TimerStatus As Boolean Dim Zähler As Double Dim g_dx As New DirectX7 Dim g_dd As DirectDraw7 Dim g_d3d As Direct3D7 Dim ddsd As DDSURFACEDESC2 Dim g_ddsPrimary As DirectDrawSurface7 Dim g_ddsBackBuffer As DirectDrawSurface7 Dim g_d3dDevice As Direct3DDevice7 Dim vPort As D3DVIEWPORT7 Dim g_d3drcViewport(0) As D3DRECT Dim matProj As D3DMATRIX Dim matView As D3DMATRIX Dim Vertex(11) As D3DVERTEX
Bis hierher gehören die Dimensionierungen zu den Standardobjekten von DirectX. Dim Dim Dim Dim Dim Dim Dim Dim
DDLevel As DirectDrawSurface7 TempSurface As DirectDrawSurface7 DDMipmap As DirectDrawSurface7 DestRect As RECT SourcRect As RECT ddsCaps As DDSCAPS2 DDsdTemp As DDSURFACEDESC2 ddsd2 As DDSURFACEDESC2
198
Texturen
Dieser Abschnitt ist für Mipmap interessanter. Die DDMipmap-Surface benötigen wir, um die eigentliche Mipmap Surface zu erstellen. Da wir an dieser Surface keine direkten Grafikzuweisungen vornehmen, nutzen wir die DDLevel-Surface als Hilfsmittel (sozusagen als Zwischensurface). Die dritte Surface, Tempsurface, benötigen wir nur, um die Bitmap von der Festplatte laden zu können. Private Sub Form_Load() Zähler = -6 InitDDraw InitD3D
Die beiden Subroutinen InitDDraw() und InitD3D() sind bereits bekannt und werden nicht weiter erklärt. Sie werden auch nur genutzt, um die normalen Surfaces zu erstellen bzw. das Direct3D-Device einzurichten. ' Dreieck erstellen g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex
-5, -2.5, 0, 0, 0, -1, 0, 1, Vertex(0) -5, 2.5, 0, 0, 0, -1, 0, 0, Vertex(1) 0, 2.5, 0, 0, 0, -1, 1, 0, Vertex(2) 0, 2.5, 0, 0, 0, -1, 1, 0, Vertex(3) 0, -2.5, 0, 0, 0, -1, 1, 1, Vertex(4) -5, -2.5, 0, 0, 0, -1, 0, 1, Vertex(5) 0, -2.5, 0, 0, 0, -1, 0, 1, Vertex(6) 0, 2.5, 0, 0, 0, -1, 0, 0, Vertex(7) 5, 2.5, 0, 0, 0, -1, 1, 0, Vertex(8) 5, 2.5, 0, 0, 0, -1, 1, 0, Vertex(9) 5, -2.5, 0, 0, 0, -1, 1, 1, Vertex(10) 0, -2.5, 0, 0, 0, -1, 0, 1, Vertex(11)
Diese Vertexe ergeben eine Mauer aus vier Dreiecken. CreateTextur App.Path & "\mauer"
Die CreateTexture()-Subroutine wurde ein wenig modifiziert. Normalerweise übergeben wir als Argument den kompletten Filenamen der Bitmap. Dies tun wir diesmal nicht. Statt dessen übergeben wir nun den Stamm des Filenamens. Dadurch erhalten wir die Möglichkeit alle fünf Mipmap Surfaces über eine indexgesteuerte Schleife zu initialisieren. Der komplette Filename setzt sich damit wie folgt zusammen: Stamm + Index + Endung = Filename
z.B. Mauer + 0 + .bmp = Mauer0.bmp g_d3dDevice.SetRenderState D3DRENDERSTATE_AMBIENT, &HFFFFFF
Kapitel 2 • Direct3D
199
Wir setzen ein indirektes Licht. Dim mat As D3DMATERIAL7 mat.Ambient.r = 1 mat.Ambient.g = 1 mat.Ambient.b = 1 mat.Ambient.a = 1 g_d3dDevice.SetMaterial mat
Wir weisen ein Standardmaterial zu. Do g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET,_ RGB(255, 0, 0), 0, 0 g_d3dDevice.BeginScene g_d3dDevice.SetTextureStageState 0, D3DTSS_MIPFILTER, _ D3DTFP_LINEAR
Hier wird der Mipmap-Modus eingeschaltet. Dieser wird durch den Parameter D3DTFP_LINEAR mit der linearen Filtertechnik verbunden. Wenn Sie sich das Demo anschauen, sollten Sie auf die eingeblendete Zahl unten rechts achten. Die verschiedenen Mipmap-Level werden sanft überblendet. Sie können Rechenzeit sparen, indem Sie den Parameter D3DTFP_POINT anstelle des Parameters D3DTFP_LINEAR verwenden. Dann werden die einzelnen Mipmap-Level aber nicht mehr sanft überblendet, sondern schalten abrupt um. g_d3dDevice.SetTexture 0, DDMipmap g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, D3DFVF_VERTEX, _ Vertex(0), 6, D3DDP_WAIT g_d3dDevice.SetTextureStageState 0, D3DTSS_MIPFILTER, _ D3DTFP_NONE
Für die rechte Hälfte der Wand schalten wir den Mipmap-Modus wieder aus. Beobachten Sie den Unterschied. g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, D3DFVF_VERTEX, _ Vertex(6), 6, D3DDP_WAIT g_d3dDevice.EndScene g_ddsPrimary.Flip Nothing, DDFLIP_WAIT DoEvents Loop Until GetAsyncKeyState(vbKeyEscape) <> 0 ' DirectX Zurücksetzen und Bildschirm herstellen g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_NORMAL g_dd.RestoreDisplayMode Set g_dd = Nothing Set g_d3dDevice = Nothing Set g_dx = Nothing End
200
Texturen
Nach einem Druck auf die Escape-Taste wird das Programm verlassen. End Sub Private Function MakeVector(a As Double, b As Double, c As _ Double) As D3DVECTOR Dim vecOut As D3DVECTOR With vecOut .x = a .y = b .z = c End With MakeVector = vecOut End Function Private Sub CreateTextur(sFile As String) On Local Error Resume Next
Die Anweisung On Local Error Resume Next muss enthalten sein. Später nehmen wir einen Fehler absichtlich in Kauf. ddsd2.lFlags = DDSD_CAPS Or DDSD_MIPMAPCOUNT Or DDSD_WIDTH Or _ DDSD_HEIGHT ddsd2.lMipmapCount = 5 ddsd2.ddsCaps.lCaps = DDSCAPS_TEXTURE Or DDSCAPS_MIPMAP Or _ DDSCAPS_COMPLEX ddsd2.lWidth = 256 ddsd2.lHeight = 256 Set DDMipmap = g_dd.CreateSurface(ddsd2)
Mit den paar Zeilen haben wir bereits die gesamte Mipmapsurface erstellt. Sie beinhaltet fünf Level. Der größte Level besitzt die Dimensionen [256 * 256]. Die Mipmapsurface ist zwar erstellt, aber es sind noch keine Bitmapdaten geladen. Dies können wir auch nicht direkt an der Mipmapsurface durchführen. Wir benötigen einige Hilfsstrukturen. Set DDLevel = DDMipmap
Der DDLevel-Surface übergeben wir alle Eigenschaften der DDMipmap-Surface. Mit Ihr können wir freier arbeiten. While Err.Number = DD_OK DDLevel.GetSurfaceDesc DDsdTemp
Wir lesen die zurzeit aktuellen Surface-Beschreibungen und speichern diese in der Variablen DDsdTemp.
Kapitel 2 • Direct3D
201
Set TempSurface = g_dd.CreateSurfaceFromFile(sFile & _ Trim(Str(i)) & ".bmp", ddsd2)
Wie anfangs bereits erwähnt, benötigen wir die Tempsurface als Container für Bitmaps. Die CreateSurfaceFromFile()-Methode ist uns bekannt und muss nicht weiter erläutert werden. DestRect.Right = DDsdTemp.lWidth DestRect.Bottom = DDsdTemp.lHeight DDLevel.Blt DestRect, TempSurface, SourcRect, DDBLT_WAIT ddsCaps.lCaps = DDSCAPS_TEXTURE Or DDSCAPS_MIPMAP Set DDLevel = DDLevel.GetAttachedSurface(ddsCaps)
Mit der GetAttachedSurface()-Methode verzweigt Direct3D auf das nächste Mitglied der Mipmap-Kette. i = i + 1 Wend End Sub
Die Timer()-Routine sorgt lediglich für die Bewegung. Wir verändern die Position des Betrachters. Dadurch wirkt es so, als würde die Wand sich uns nähern und anschließend wieder entfernen. Natürlich hat die Wand ihre Position nie verlassen. Private Sub Timer1_Timer() If TimerStatus = True Then Zähler = Zähler – 1 If Zähler < -70 Then TimerStatus = False Else Zähler = Zähler + 1 If Zähler > -6 Then TimerStatus = True End If g_dx.IdentityMatrix matView Call g_dx.ViewMatrix(matView, MakeVector(0, 0, Zähler), _ MakeVector(0, 0, 0), MakeVector(0, 1, 0), 0) g_d3dDevice.SetTransform D3DTRANSFORMSTATE_VIEW, matView g_dx.IdentityMatrix matProj Call g_dx.ProjectionMatrix(matProj, 1, 100, 3.14159 / 2) g_d3dDevice.SetTransform D3DTRANSFORMSTATE_PROJECTION, _ matProj End Sub
2.10.4 Texture Blending Direct3D kann Transparenzeffekte durch Mischen einer Textur mit einer einfachen Farbe erzeugen. Ebenfalls können Transparenzeffekte durch Mischen mehrerer Texturen erstellt werden. Texture-Blending beschreibt das Mischen von Texturen. Dies kann in folgende Verfahren eingestuft werden:
202
Texturen
•
Alpha Texture Blending
•
Multipass Texture Blending
•
Multiple Texture Blending
Die Performance ist im Wesentlichen von den Fähigkeiten der Grafikkarte abhängig. Für moderne Grafikkarten gehört die Unterstützung von Blendingtechniken zum Pflichtteil. Ältere Grafikkarten (insbesondere Grafikkarten ohne 3D-Unterstützung) haben bei diesen Techniken große Probleme. Alpha Texture Blending Alpha-Blending erzeugt eine Mischfarbe aus einem Texturpixel (Texel) mit dem Hintergrundpixel einer Szene. Bei dieser Berechnung fließen die Materialeigenschaften des Polygons sowie die Lichtinformationen der Szene ein. Folgende Formel beschreibt die endgültige Farbe, die der Anwender auf dem Monitor sieht. FinalColor = TexelColor * Source-Blend-Faktor + PixelColor * Dest-Blend-Faktor
TexelColor beschreibt das aktuelle Pixel des Polygons. Der Source-Blend-Faktor ist der prozentuale Anteil, mit dem das aktuelle Texel in die endgültige Farbe (FinalColor) einfließen soll. Der Source-Blend-Faktor wird durch den AlphaWert der Materialeigenschaften des Polygons beschrieben. Dieser wird mit den einzelnen Farbanteilen des Materials multipliziert. Rot_Anteil * Alpha_Wert Grün_Anteil * Alpha_Wert Blau_Anteil * Alpha_Wert
Der Alpha-Wert liegt in einem Wertebereich von 0.0 bis 1.0. Die PixelColor ist die Farbe eines Pixels (des Pixels welches mit dem Texel des Polygons gemischt werden soll) aus der Szene. Der Dest-Blend-Faktor ist der prozentuale Anteil, mit dem das Szenenpixel in die FinalColor einfließt. Der Wertebereich liegt zwischen 0.0 und 1.0. Daraus können wir ableiten, dass ein Polygon gänzlich undurchsichtig ist, wenn der Source-Blend-Faktor 1.0 und der Dest-Blend-Faktor 0.0 ist. Für die endgültige Farbe werden keine Anteile des Hintergrundbildes berücksichtigt. Hingegen werden zu 100% alle Farben des aktuellen Polygons berücksichtigt. Komplett durchsichtig wird das Polygon sein, wenn der Sourc-Blend-Faktor 0.0 und der Dest-Blend-Faktor 1.0 ist. Die Einstellungen des Mischfaktors können Sie über die Direct3DDevice7. SetRenderState()-Methode kontrollieren.
Kapitel 2 • Direct3D
203
Für den Source-Blend-Faktor: Direct3DDevice7.SetRenderState D3DRENDERSTATE_SRCBLEND, _ CONST_D3DBLEND
Für den Dest-Blend-Faktor: Direct3DDevice7.SetRenderState D3DRENDERSTATE_DESTBLEND, _ CONST_ D3DBLEND
Diese Methode beinhaltet zwei Parameter. Der erste Parameter benennt, welchen Blend-Faktor Sie beeinflussen. Der zweite Parameter beschreibt, wie Sie den Blend-Faktor beeinflussen. Für den zweiten Parameter stehen folgende Konstanten bereit: Enum CONST_D3DBLEND D3DBLEND_ZERO D3DBLEND_ONE D3DBLEND_SRCCOLOR D3DBLEND_INVSRCCOLOR D3DBLEND_SRCALPHA D3DBLEND_INVSRCALPHA D3DBLEND_DESTALPHA D3DBLEND_INVDESTALPHA D3DBLEND_DESTCOLOR D3DBLEND_INVDESTCOLOR D3DBLEND_SRCALPHASAT D3DBLEND_BOTHINVSRCALPHA End Enum
= = = = = = = = = = = =
1 2 3 4 5 6 7 8 9 10 11 13
Schauen Sie sich die Berechnungsgrundlage der Konstantenliste an: D3DBLEND_ZERO BlendFaktor (0, 0, 0, 0). D3DBLEND_ONE BlendFaktor (1, 1, 1, 1). D3DBLEND_SRCCOL OR BlendFaktor (Rs, Gs, Bs, As). D3DBLEND_INVSRCCOLOR BlendFaktor (1-Rs, 1-Gs, 1-Bs, 1-As). D3DBLEND_SRCALPHA BlendFaktor (As, As, As, As). D3DBLEND_INVSRCALPHA BlendFaktor (1-As, 1-As, 1-As, 1-As). D3DBLEND_DESTALPHA BlendFaktor (Ad, Ad, Ad, Ad). D3DBLEND_INVDESTALPHA BlendFaktor (1-Ad, 1-Ad, 1-Ad, 1-Ad). D3DBLEND_DESTCOLOR BlendFaktor (Rd, Gd, Bd, Ad).
204
Texturen
D3DBLEND_INVDESTCOLOR BlendFaktor (1-Rd, 1-Gd, 1-Bd, 1-Ad). D3DBLEND_SRCALPHASAT BlendFaktor (f, f, f, 1); f = min(As, 1-Ad). D3DBLEND_BOTHINVSRCALPHA
SourceBlendFaktor (1-As, 1-As, 1-As, 1-As), und DestBlendFaktor (As, As, As, As) Wie Sie sehen, wird der Blend-Faktor auf diverse Arten erzeugt. Welche für Ihre Anwendung die geeignetste ist, können Sie experimentell erforschen. Wir haben mit der Konstante D3DBLEND_BOTHINVSRCALPHA hervorragende Ergebnisse erzielt. Ebenfalls ist die Konstante D3DBLEND_ONE für den schnellen unkomplizierten Einsatz geeignet. Diese Berechnungsart kommt ohne AlphaWerte des Materials aus und erzeugt meistens eine gute Transparenz zwischen Szene und Polygon. Beispiel Alpha Blending Unser Alpha-Blending-Beispiel demonstriert eine stufenlose Transparenz eines Polygons. Das im Vordergrund sichtbare Polygon wird langsam transparent und anschließend wieder voll sichtbar. Hierzu nutzen wir die Berechnungsmethode D3DBLEND_BOTHINVSRCALPHA. Da nicht alle Grafikkarten Alpha Blending unterstützen, führen wir eine kleine Prüfung dieser Eigenschaft durch. Leider können wir diese Blending-Technik nicht softwareemuliert darstellen, so wird es zu einem Programmabbruch kommen, wenn Ihre Grafikkarte die Technik nicht beherrscht. Das Beispiel ist im Wesentlichen identisch mit den ersten Texturbeispielen im Abschnitt Texturen. Somit können wir uns auf die Änderungen konzentrieren. Private Sub CreateTextur(ByVal Index As Integer, sFile As _ String) Dim ddsd3 As DDSURFACEDESC2 Dim TextureEnum As Direct3DenumPixelFormats Set TextureEnum = g_d3dDevice.GetTextureFormatsEnum() TextureEnum.GetItem 1, ddsd3.ddpfPixelFormat ddsd3.ddsCaps.lCaps = DDSCAPS_TEXTURE Set TextureSurf(Index) = g_dd.CreateSurfaceFromFile(sFile, _ dsd3) End Sub
Der CreateTexture()-Methode haben wir einen weiteren Übergabeparameter Index mitgegeben. Somit sind wir in der Lage, mit der Routine mehrere Texturesurfaces zu erstellen. Der Aufruf der Routine sieht so aus: CreateTextur 0, App.Path & "\Boden.bmp" CreateTextur 1, App.Path & "\lake.bmp"
Kapitel 2 • Direct3D
205
Der erste Parameter als Index und der zweite Parameter als Filename des zu ladenen Bildes. Die nächste Änderung finden wir in der Form_Load()-Routine. g_d3dDevice.SetRenderState D3DRENDERSTATE_DESTBLEND, _ D3DBLEND_BOTHINVSRCALPHA g_d3dDevice.SetRenderState D3DRENDERSTATE_SRCBLEND, _ D3DBLEND_BOTHINVSRCALPHA
Hier setzten wir die Berechnungsmethode für Überblendungen. D3DBLEND_ BOTHINVSRCALPHA sorgt für ein weiches Ein- und Ausblenden. Diese Berechnungsart berücksichtigt den Alpha-Wert des aktuellen Materials zum Mischen der Texel mit den Pixeln. An dieser Stelle können Sie etwas experimentieren. Tauschen Sie den D3DBLEND_BOTHINVSRCALPHA-Eintrag mit einem beliebigen aus der CONST_D3DBLEND-Auflistung. Sie können wunderbar beobachten, wie sich die Transparenz des Polygons verändert. Beachten Sie, das ein Eintrag aus der CONST_D3DBLEND-Auflistung von dem Alpha-Wert des Materials unabhängig ist. Sie werden nur eine statische Transparenz erhalten, ohne dass sich die Änderungen des Alpha-Werts bemerkbar macht. Einer dieser Einträge ist z.B. die D3DBLEND_ONE-Konstante. Do g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET, _ RGB(0, 0, 0), 0, 0 g_d3dDevice.BeginScene g_d3dDevice.SetRenderState D3DRENDERSTATE_ALPHABLENDENABLE, _ False
Das erste Polygon mit dem Hintergrundmotiv rendern wir ohne Alpha Blending. Wir schalten das Alpha Blending über die SetRenderState()-Methode aus. Dazu setzen wir den zweiten Parameter der Methode auf False. g_d3dDevice.SetTexture 0, TextureSurf(1) g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, D3DFVF_VERTEX, _ Vertex(0), 6, D3DDP_WAIT g_d3dDevice.SetRenderState D3DRENDERSTATE_ALPHABLENDENABLE, _ True
Das Polygon, welches im Vordergrund gerendert wird, soll mit Transparenzeffekten dargestellt werden. Natürlich müssen wir über die SetRenderState()-Methode das Alpha Blending aktivieren. Der zweite Parameter wird auf True gesetzt. g_d3dDevice.SetTexture 0, TextureSurf(0) g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, D3DFVF_VERTEX, _ Vertex(6), 6, D3DDP_WAIT g_d3dDevice.EndScene
206
Texturen
g_ddsBackBuffer.SetForeColor &HFFFFFFFF g_ddsBackBuffer.DrawText 10, 10, "Alpha-Wert : " & _ Str(AlphaWert), False
Hiermit wird lediglich der aktuelle Alpha-Wert des Materials auf den BackBuffer geschrieben. g_ddsPrimary.Flip Nothing, DDFLIP_WAIT DoEvents Loop Until GetAsyncKeyState(vbKeyEscape) <> 0
Nun fehlt noch eine Technik, mit der wir den aktuellen Alpha-Wert des Materials verändern können. Wir nutzen ein Timerobjekt von Visual Basic. Im Timer addieren oder subtrahieren wir den Alpha-Wert um 0.01. Anschließend weisen wir den geänderten Wert über die SetMaterial()-Methode, dem aktuellen Material zu. Somit wird er bei dem nächsten Renderaufruf berücksichtig. Private Sub Timer1_Timer() If TimerStatus = True Then AlphaWert = AlphaWert + 0.01 If AlphaWert > 1 Then AlphaWert = 1: TimerStatus = False Else AlphaWert = AlphaWert – 0.01 If AlphaWert < 0 Then AlphaWert = 0: TimerStatus = True End If mat.diffuse.a = AlphaWert g_d3dDevice.SetMaterial mat End Sub
Multiple Texture Blending Direct3D kann bis zu acht Texturen gleichzeitig auf ein Polygon rendern. Das gleichzeitige Rendern von mehreren Texturen ermöglicht eine Reihe von Spezialeffekten. So können Sie z.B. Licht und Schatten simulieren. Ebenso können Sie den Eindruck von Glanzeffekten erzeugen. Moderne Grafikkarten unterstützen Multi Texture Blending. Alternativ sind die meisten Multi-Texture-Effekte durch einfaches Texture Blending nachzuahmen. Die unterschiedlichen Texturen werden in Stufen (Blending Stages) organisiert. Gemeinsam ergeben Sie die Texture Blending-Kaskade. Die Texture-BlendingKaskade beschreibt, wie die einzelne Textur in die für den Anwender sichtbare Textur integriert wird. Beim mischen von bis zu acht Texturen ergeben sich einige Dutzend Kombinationsmöglichkeiten. Es ist schwer einzuschätzen, wie sich die Mischparameter der einzelnen Texturen auswirken. Hier hilft eigentlich nur Erfahrung und Freude am Ausprobieren.
Kapitel 2 • Direct3D
207
Die meisten Anwendungen kommen mit zwei oder drei Texturstufen aus. Je weniger Texturstufen eingesetzt werden, desto überschaubarer sind die Mischparameter. Ebenfalls wird die Performance des Systems nicht zu stark belastet. Die folgende Abbildung visualisiert die Textur Blending-Kaskade. Texturestufe 0
Mischparameter
Texturestufe 0 Texturestufe 1
Mischparameter
Texturestufe 2 Mischparameter
Texturestufe n Mischparameter
für den Anwender sichtbare Texture
Bild 2.52: Multi Texture
Im Grunde ist diese Kaskade ein Aufruf von mehreren Alpha-Blending-Aktionen. Texturstufe 0 wird mit dem Hintergrund gemischt. Das Ergebnis erzeugt einen neuen Hintergrund. Anschließend wird Texturstufe 1 mit dem Hintergrund gemischt. Wieder entsteht ein neuer Hintergrund. Das wiederholt sich bis Texturstufe n. Sie können Multi Texture Blending durch Aufrufen mehrer Alpha-Blending-Aktionen simulieren. Das bringt natürlich den Nachteil, dass Sie für jede Alpha-Blending-Aktion auch eine DrawPrimitive()-Methode aufrufen müssen. Bei Multi Texture Blending werden alle Texturstufen mit einem Aufruf der DrawPrimitive()-Methode gemischt. Im Vergleich erhalten Sie mit Multi Texture
208
Texturen
Blending einen Performancegewinn. Außerdem ist das programmtechnische Handling einfacher. Sie können für jede Textur ein Farbmischverhalten und ein Alphamischverhalten definieren. Dabei unterscheidet man zwischen Mischoperation und Mischargument. Sie werden in der CONST_D3DTEXTURESTAGESTATETYPE-Liste definiert. Enum CONST_D3DTEXTURESTAGESTATETYPE D3DTSS_ADDRESS = 12 D3DTSS_ADDRESSU = 13 D3DTSS_ADDRESSV = 14 D3DTSS_ALPHAARG1 = 5 D3DTSS_ALPHAARG2 = 6 D3DTSS_ALPHAOP = 4 D3DTSS_BORDERCOLOR = 15 D3DTSS_COLORARG1 = 2 D3DTSS_COLORARG2 = 3 D3DTSS_COLOROP = 1 D3DTSS_MAGFILTER = 16 D3DTSS_MAXANISOTROPY = 21 D3DTSS_MAXMIPLEVEL = 20 D3DTSS_MINFILTER = 17 D3DTSS_MIPFILTER = 18 D3DTSS_TEXCOORDINDEX = 11 D3DTSS_TEXTURETRANSFORMFLAGS = 24 End Enum
Aus dieser Liste sind die Operatoren D3DTSS_COLOROP und D3DTSS_ ALPHAOP interessant. Sie werden mit der Direct3DDevice7.SetTextureStageState()-Methode aufgerufen. Diese Methode benötigt einen zweiten Parameter. Der zweite Parameter wird durch die CONST_D3DTEXTUREOP-Konstantenliste beschrieben. Enum CONST_D3DTEXTUREOP D3DTOP_DISABLE = 1 D3DTOP_SELECTARG1 = 2 D3DTOP_SELECTARG2 = 3 D3DTOP_MODULATE = 4 D3DTOP_MODULATE2X = 5 D3DTOP_MODULATE4X = 6 D3DTOP_ADD = 7 D3DTOP_ADDSIGNED = 8 D3DTOP_ADDSIGNED2X = 9 D3DTOP_SUBTRACT = 10 D3DTOP_ADDSMOOTH = 11 D3DTOP_BLENDDIFFUSEALPHA = 12 D3DTOP_BLENDTEXTUREALPHA= 13
Kapitel 2 • Direct3D
209
D3DTOP_BLENDFACTORALPHA = 14 D3DTOP_BLENDTEXTUREALPHAPM = 15 D3DTOP_BLENDCURRENTALPHA = 16 D3DTOP_PREMODULATE = 17 D3DTOP_MODULATEALPHA_ADDCOLOR = 18 D3DTOP_MODULATECOLOR_ADDALPHA = 19 D3DTOP_MODULATEINVALPHA_ADDCOLOR = 20 D3DTOP_MODULATEINVCOLOR_ADDALPHA = 21 D3DTOP_BUMPENVMAP = 22 D3DTOP_BUMPENVMAPLUMINANCE = 23 D3DTOP_DOTPRODUCT3 = 24 End Enum
Die Mischargumente werden durch die Texturargument-Flags beschrieben. D3DTA_CURRENT Das Mischargument resultiert aus der vorherigen Texturstufe. In der ersten Texturstufe (Stufe 0) ist dieses Argument äquivalent zu D3DTA_DIFFUSE. D3DTA_DIFFUSE Das Mischargument ist die diffuse Farbe der Vertexkomponente. Der voreingestellte Farbwert ist 0xFFFFFFFF. D3DTA_TEXTURE Das Mischargument ist die Texturfarbe der Texturstufe. Es ist nur für die ersten Texturargumente D3DTSS_COLORARG1 und D3DTSS_ALPHAARG1 gültig. D3DTA_SPECULAR Das Mischargument ist die Specularfarbe der Vertexkomponente. Der voreingestellte Farbwert ist 0xFFFFFFFF. Nun wird es Zeit, dass wir die Texturoperatoren und deren Texturargumente praxisnah betrachten. Wir konstruieren folgenden Fall. Auf das aktuelle Polygon möchten wir zwei Texturen mischen. Texturstufe 0 wird ohne Mischfaktoren angegeben. Texturstufe 1 soll mit der Texturstufe 0 gemischt werden. Wir setzten also folgende Parameter: Direct3DDevice7.SetTextureStageState D3DTA_TEXTURE Direct3DDevice7.SetTextureStageState D3DTA_CURRENT Direct3DDevice7.SetTextureStageState D3DTOP_MODULATE Direct3DDevice7.SetTextureStageState D3DTOP_DIFFUSE Direct3DDevice7.SetTextureStageState D3DTOP_SELECTARG2
1, D3DTSS_COLORARG1, _ 1, D3DTSS_COLORARG2, _ 1, D3DTSS_COLOROP, _ 1, D3DTSS_ALPHAARG2, _ 1, D3DTSS_ALPHAOP, _
210
Texturen
Direct3DDevice7.SetTexture 0, Texture1 Direct3DDevice7.SetTexture 1, Texture2
Beispiel Multi Texture Blending In unserem Beispiel verwenden wir zwei Texturen. Wir simulieren einen Lichtkegel, welcher die Hintergrundtextur beleuchtet. Natürlich ist dies keine Lichtquelle, sondern eine Textur, welche mit dem Hintergrund gemischt wird. Beachten Sie, dass wir beide Texturen durch einen Aufruf der Direct3DDevice. DrawPrimitiv()-Methode mischen. Im Vergleich zu dem Alpha-Texture-Blending-Verfahren benötigen wir nur noch ein Polygon. Erinnern Sie sich, dass wir beim Alpha-Texture-Blending-Verfahren zwei Polygone benötigen. Somit würden wir auch zwei Direct3DDevice7.DrawPrimitiv()-Methoden benötigen. Das gesamte Blending-Verfahren haben wir in der Form_Load()-Subroutine untergebracht. Private Sub Form_Load() InitDDraw InitD3D g_dx.CreateD3DVertex -2.5, -2.5, 2, 0, 0, -1, 0, 1, Vertex(0) g_dx.CreateD3DVertex -2.5, 2.5, 2, 0, 0, -1, 0, 0, Vertex(1) g_dx.CreateD3DVertex 2.5, 2.5, 2, 0, 0, -1, 1, 0, Vertex(2) g_dx.CreateD3DVertex 2.5, 2.5, 2, 0, 0, -1, 1, 0, Vertex(3) g_dx.CreateD3DVertex 2.5, -2.5, 2, 0, 0, -1, 1, 1, Vertex(4) g_dx.CreateD3DVertex -2.5, -2.5, 2, 0, 0, -1, 0, 1, Vertex(5)
Hier erstellen wir ein Polygon aus zwei Dreiecken. Natürlich werden zwei Polygone erzeugt, dennoch werden diese mit einem Direct3DDevice7.DrawPrimitive()-Aufruf gerendert. Also betrachten wir die beiden Dreiecke als ein Polygon. CreateTextur 0, App.Path & "\lake.bmp" CreateTextur 1, App.Path & "\spotlite.bmp"
Unsere Subroutine CreateTexture() ist Ihnen bereits bekannt. Sie erzeugt die notwendigen Textursurfaces. g_d3dDevice.SetRenderState D3DRENDERSTATE_AMBIENT, &HFFFFFFFF
Damit wir die Polygone mit den Texturen sehen können, müssen wir eine Lichtquelle aktivieren. Wir haben uns für ein indirektes (Ambient-) Licht entschieden. Dim Farbe As D3DCOLORVALUE With Farbe .a = 1 .b = 1 .g = 1 .r = 1 End With mat.Ambient = Farbe
Kapitel 2 • Direct3D
211
mat.diffuse = Farbe mat.specular = Farbe g_d3dDevice.SetMaterial mat
Wir setzen ein allgemeines Material. Indem wir alle Werte auf 1.0 setzen, werden die Farben der Texturbitmap nicht verändert. Do g_d3dDevice.Clear 1, g_d3drcViewport(), D3DCLEAR_TARGET, _ RGB(0, 0, 0), 0, 0
Die Direct3DDevice7.Clear()-Methode kennen Sie bereits. Mit ihr löschen wir das Renderziel. In unserm Fall ist das der BackBuffer. g_d3dDevice.BeginScene g_d3dDevice.SetTextureStageState 1, D3DTSS_MAGFILTER, _ D3DTFG_LINEAR
Diese Anweisung hat mit dem eigentlichen Texturmischen nichts zu tun. Eine lineare Filterung sieht einfach schöner aus. g_d3dDevice.SetTextureStageState D3DTA_TEXTURE g_d3dDevice.SetTextureStageState D3DTA_CURRENT g_d3dDevice.SetTextureStageState D3DTOP_MODULATE g_d3dDevice.SetTextureStageState D3DTOP_DIFFUSE g_d3dDevice.SetTextureStageState D3DTOP_SELECTARG2
1, D3DTSS_COLORARG1, _ 1, D3DTSS_COLORARG2, _ 1, D3DTSS_COLOROP, _ 1, D3DTSS_ALPHAARG2, _ 1, D3DTSS_ALPHAOP, _
Diese Anweisungen bestimmen das Mischverhalten der Texturen. Mit diesen Kombinationen konnten wir einen Lichtkegel gut simulieren. g_d3dDevice.SetTexture 0, TextureSurf(0) g_d3dDevice.SetTexture 1, TextureSurf(1)
Das Setzen der Texturen ist ebenfalls bekannt. Interessant ist es, dass wir die Textur 1 auf Texturstufe 1 setzen. Damit haben wir Multi Texture Blending bereits erzeugt. g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, _ D3DFVF_VERTEX, Vertex(0), 6, D3DDP_WAIT
Wir benötigen nur einen Aufruf der Direct3DDevice7.DrawPrimitive()-Methode. Dennoch werden beide Texturen miteinander gemischt.
212
Z-Buffer (Tiefenspeicher)
g_d3dDevice.EndScene g_ddsBackBuffer.SetForeColor &HFFFFFFFF g_ddsBackBuffer.DrawText 10, 10, "Multi Texture Beispiel", _ False g_ddsPrimary.Flip Nothing, DDFLIP_WAIT DoEvents Loop Until GetAsyncKeyState(vbKeyEscape) <> 0 g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_NORMAL g_dd.RestoreDisplayMode Set g_dd = Nothing Set g_d3dDevice = Nothing Set g_dx = Nothing End End Sub
2.11
Z-Buffer (Tiefenspeicher) Ein Tiefenspeicher wird auch als Z-Buffer oder W-Buffer bezeichnet. Er ist eine Direct Draw Surface, welche Tiefeninformationen von Polygonen für Direct3D speichert. Direct3D nutzt den Z-Buffer um zu unterscheiden, welches Polygon vor einem anderen Polygon sichtbar ist. Betrachten Sie eine Szene, in der zwei Polygone gerendert werden. Polygon 1 wird von Polygon 2 überlagert. Jetzt betrachten Sie die gleiche Szene von der Rückseite: Polygon 2 sollte von Polygon 1 überlagert werden. Dies ist aber nicht der Fall. Da der Renderaufruf für Polygon 2 nach Polygon 1 erfolgt, wird Polygon 2 immer im Vordergrund liegen. Dies stellt ein gewaltiges Problem dar. Sie müssen jedes Mal, wenn Sie die Position des Betrachters ändern, entscheiden, welche Polygone im Vordergrund liegen sollen. Diese müssen Sie dann als letzte rendern. Praktisch ist dies fast unmöglich. Glücklicherweise übnimmt der Z-Buffer diese Aufgaben. Im Z-Buffer werden also die Z-Werte der Polygone gespeichert. Anhand dieser Informationen ist Direct3D in der Lage zu entscheiden, welche Polygone in den Vordergrund gehören. Trotz der eigentlich komplizierten Aufgabenstellung lässt sich der Z-Buffer recht problemlos in ein Programm integrieren. Der Z-Buffer wird vor dem Direct3DDevice-Objekt erzeugt. Unterteilen wir die notwendigen Aufgaben in vier Schritte. •
Schritt 1: Auslesen des Z-Bufferformats und des Pixelformats
Es ist wichtig zu wissen, welche Formate die aktuelle Grafikkarte unterstützt. Mit der Direct3D7.GetEnumZBufferFormats()-Methode können wir die gewünschten Informationen auslesen. Dim ddpfZBuffer As DDPIXELFORMAT Dim d3dEnumPFs As Direct3DenumPixelFormats Set g_d3d = g_dd.GetDirect3D
Kapitel 2 • Direct3D
213
Set d3dEnumPFs = _ g_d3d.GetEnumZBufferFormats("IID_IDirect3DHALDevice") Dim I As Long For I = 1 To d3dEnumPFs.GetCount() Call d3dEnumPFs.GetItem(I, ddpfZBuffer) If ddpfZBuffer.lFlags = DDPF_ZBUFFER Then Exit For End If Next I
•
Schritt 2: Vorbereiten des DDSURFACEDESC2-Typen-Arrays für die Z-Buffer Surface
Dim g_ddsd As DDSURFACEDESC2 g_ddsd.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT Or _ DDSD_PIXELFORMAT g_ddsd.ddsCaps.lCaps = DDSCAPS_ZBUFFER g_ddsd.lWidth = 640 g_ddsd.lHeight = 480 g_ddsd.ddpfPixelFormat = ddpfZBuffer
•
Schritt 3: Erzeugen der Z-Buffer Surface
Dim g_ddsZBuffer As DirectDrawSurface7 g_ddsd.ddsCaps.lCaps = g_ddsd.ddsCaps.lCaps Or _ DDSCAPS_SYSTEMMEMORY
Alternativ können Sie die Z-Buffersurface auch in den Videospeicher legen. Der Aufruf würde so aussehen: g_ddsd.ddsCaps.lCaps = g_ddsd.ddsCaps.lCaps Or _ DDSCAPS_VIDEOMEMORY Set g_ddsZBuffer = g_dd.CreateSurface(g_ddsd)
•
Schritt 4: Verbinden der Z-Buffer Surface mit der Rendersurface
Die Render Surface ist im Regelfall die Backbuffer Surface. g_ddsBackBuffer.AddAttachedSurface g_ddsZBuffer
Nachdem der Z-Buffer erzeugt wurde, muss dieser zum Rendern bereitgestellt werden. Dies erfolgt durch einen einfachen Aufruf der Direct3DDevice7.SetRenderState()-Methode. Für den ersten Parameter wählen wir den Eintrag D3DREN DERSTATE_ZENABLE. Der zweite Parameter wird durch die CONST_ D3DZBUFFERTYPE-Konstantenliste beschrieben. Zur Auswahl stehen: Enum CONST_D3DZBUFFERTYPE D3DZB_FALSE = 0 D3DZB_TRUE = 1
214
Z-Buffer (Tiefenspeicher)
D3DZB_USEW End Enum
= 2
D3DZB_FALSE deaktiviert den Z-Buffer D3DZB_TRUE
aktiviert den Z-Buffer D3DZB_USEW
aktiviert den W-Buffer (W-Buffer wird heute kaum noch benutzt und wird deshalb von uns vernachlässigt.) Der komplette Aufruf der Direct3DDevice7.SetRenderState()-Methode zum Aktivieren des Z-Buffers sieht so aus: Direct3DDevice7.SetRenderState D3DRENDERSTATE_ZENABLE, _ D3DZB_TRUE
Zum Deaktivieren ändern Sie den zweiten Parameter der SetRenderState()Methode. Direct3DDevice7.SetRenderState D3DRENDERSTATE_ZENABLE, _ D3DZB_FALSE
Es ist notwendig, den Z-Buffer vor jeder neuen Renderaktion zu löschen. Hierbei hilft uns die Direct3DDevice7.Clear()-Methode. Direct3DDevice7.Clear 1, Viewport, D3DCLEAR_ZBUFFER, 0, 1, 0
Sie können den Schreibstatus des Z-Buffers aktivieren oder deaktivieren. Im Regelfall ist das Beschreiben des Z-Buffers erlaubt. Diese Einstellung erlaubt einen korrekten Aufbau einer Szene. Einige Spezialeffekte sperren das Beschreiben des Z-Buffers. Aktivieren des Schreibzugriffs auf den Z-Buffer: Direct3DDevice7.SetRenderState D3DRENDERSTATE_ZWRITEENABLE, 1
Deaktivieren des Schreibzugriffs auf den Z-Buffer: Direct3DDevice7.SetRenderState D3DRENDERSTATE_ZWRITEENABLE, 0
Beispiel (Z-Buffer) In dem Z-Buffer-Beispiel werden zwei Polygone dargestellt. Dem ersten Polygon wird eine feste Position zugewiesen. Das zweite Polygon verändert stetig die ZPosition. Es pulsiert vor und zurück. Ohne Z-Buffer wird das zweite Dreieck
Kapitel 2 • Direct3D
215
immer im Vordergrund gerendert. Das ist perspektivisch nicht korrekt. Sobald sich das zweite Dreieck von der Z-Koordinate hinter dem ersten Dreieck befindet, sollte es im Hintergrund gerendert werden. Dies erreichen wir durch den Einsatz des Z-Buffers. An dem Bildschirmfoto können Sie erkennen, wie das gelbe Dreieck von dem roten Dreieck überlagert wird. Das gelbe Dreieck wird überlagert, obwohl es nach dem roten Dreieck gerendert wird.
Bild 2.53: Bildschirmfoto Z-Buffer
Über die Space-Taste können Sie den Z-Buffer aktivieren oder deaktivieren. Mit der Escape-Taste verlassen Sie das Programm. In der InitDDraw()-Subroutine richten wir den Z-Buffer ein. Private Sub InitDDraw() Set g_dx = New DirectX7 Set g_dd = g_dx.DirectDrawCreate("") Set d3d = g_dd.GetDirect3D g_dd.SetCooperativeLevel Form1.hWnd, DDSCL_FULLSCREEN Or _ DDSCL_EXCLUSIVE Or DDSCL_ALLOWREBOOT g_dd.SetDisplayMode 640, 480, 16, 0, DDSDM_DEFAULT Dim ddsd2 As DDSURFACEDESC2 ddsd2.lFlags = DDSD_BACKBUFFERCOUNT Or DDSD_CAPS
216
Z-Buffer (Tiefenspeicher)
ddsd2.ddsCaps.lCaps = DDSCAPS_COMPLEX Or DDSCAPS_FLIP _ Or DDSCAPS_PRIMARYSURFACE Or DDSCAPS_VIDEOMEMORY _ Or DDSCAPS_3DDEVICE ddsd2.lBackBufferCount = 1 Set g_ddsPrimary = g_dd.CreateSurface(ddsd2) Dim Caps As DDSCAPS2 Caps.lCaps = DDSCAPS_BACKBUFFER Set g_ddsBackBuffer = g_ddsPrimary.GetAttachedSurface(Caps)
Bis hierher wird eine normale komplexe Surface mit dem zugehörigen Backbuffer eingerichtet. Dim Dim Dim Set For
fenum As Direct3DenumPixelFormats ddsdZ As DDSURFACEDESC2 ddpfZBuffer As DDPIXELFORMAT fenum = d3d.GetEnumZBufferFormats("IID_IDirect3DHALDevice") i = 1 To fenum.GetCount() Call fenum.GetItem(i, ddpfZBuffer) If ddpfZBuffer.lFlags = DDPF_ZBUFFER Then Exit For Next
In diesem Abschnitt prüfen wir, ob die Grafikkarte Z-Buffer unterstützt. Finden wir die Z-Buffer-Unterstützung, so verlassen wir die Schleife. ddsdZ.lFlags = DDSD_CAPS Or DDSD_WIDTH Or DDSD_HEIGHT _ Or DDSD_PIXELFORMAT ddsdZ.ddsCaps.lCaps = DDSCAPS_ZBUFFER Or DDSCAPS_VIDEOMEMORY ddsdZ.lWidth = 640 ddsdZ.lHeight = 480 ddsdZ.ddpfPixelFormat = ddpfZBuffer
Hier werden die Z-Buffer-Surfacebeschreibungen zugewiesen. In unserem Beispiel erstellen wir den Z-Buffer im Videospeicher der Grafkikkarte. Beachten Sie, dass Sie das DDSCAPS_ZBUFFER-Flag setzen müssen. Ansonsten weiß Direct3D nicht, dass es sich um einen Z-Buffer handelt. Set g_ddsZBuffer = g_dd.CreateSurface(ddsdZ) g_ddsBackBuffer.AddAttachedSurface g_ddsZBuffer
Wir erzeugen den Z-Buffer mit der CreateSurface()-Methode. Anschließend stellen wir mit der AddAttachedSurface()-Methode die Verbindung zum Renderziel her. In diesem Fall handelt es sich um die Backbuffer Surface. End Sub
In der InitD3D()-Subroutine hat sich eine kleine Änderung eingestellt. Beim Einrichten des Viewports müssen wir die Viewportparameter erweitern.
Kapitel 2 • Direct3D
217
Private Sub InitD3D() . . . vPort.lX = 0 vPort.lY = 0 vPort.lHeight = 480 vPort.lWidth = 640 vPort.minz = 0 vPort.maxz = 1
Die Parameter minz und maxz werden beim Einsatz des Z-Buffers benötigt. Bisher haben wir diese Paramerter ignoriert. Jetzt sind sie zwingend notwendig. Sie beschreiben die Reichweite der Tiefenwerte, mit der eine Szene gerendert wird. Ein normales Rendern nach der Z-Buffer-Philosophie erreichen Sie, indem Sie den minz-Wert auf 0.0 und den maxz-Wert auf 1.0 setzten. Wenn Sie beide Werte auf 0.0 setzen, zwingen Sie Direct3D ein Objekt in den Vordergrund zu rendern. Solche Einstellungen müssen aber sorgfältig eingesetzt werden. g_d3dDevice.SetViewport vPort . . . End Sub
In der Form_Load()-Subroutine aktivieren wir den Z-Buffer. Über die SpaceTaste können Sie den Z-Buffer aktivieren oder deaktivieren. Den Tastendruck bearbeiten wir in der Form_KeyDown()-Subroutine. Hier wir die Indexvariable ZBufferIndex auf True oder False gesetzt. Betrachten wir die Form_Load()-Subroutine: Private Sub Form_Load() . . . Dim BewegungZ As Single Dim Richtung As Byte Do If Richtung = 0 Then BewegungZ = BewegungZ + 0.2 Else BewegungZ = BewegungZ – 0.2 End If If BewegungZ > 10 Then Richtung = 1 End If If BewegungZ < -10 Then Richtung = 0 ObjectMatrix(1).rc43 = BewegungZ
218
Die SetRenderState()-Methode
Dieser Abschnitt ist für die Bewegung des zweiten Dreiecks zuständig. Wir verändern die Z-Position der Vertexe, indem wir die Objektmatrix manipulieren. If ZBufferIndex = False Then g_d3dDevice.SetRenderState D3DRENDERSTATE_ZENABLE, _ D3DZB_FALSE Else g_d3dDevice.SetRenderState D3DRENDERSTATE_ZENABLE, _ D3DZB_TRUE End If
Abhängig von dem Wert der Indexvariablen ZBufferIndex wird der Z-Buffer aktiviert oder deaktiviert. ZBufferIndex verändern Sie durch die Space-Taste. g_ddsBackBuffer.SetForeColor &HFFFFFFFF g_ddsBackBuffer.DrawText 10, 10, "Press Space to aktivate / _ deaktivate Z Buffer", False Dim Text As String If ZBufferIndex = True Then Text = "Z Buffer --> A K T I V <--" If ZBufferIndex = False Then Text = _ "Z Buffer --> nicht A K T I V <--" g_ddsBackBuffer.DrawText 10, 30, Text, False
Abschließend lassen wir noch einen Informationstext auf den Backbuffer schreiben. Der Text ist von der Indexvariablen ZBufferIndex abhängig.
2.12
Die SetRenderState()-Methode Der Direct3DDevice7.SetRenderState()-Methode wollen wir ein eigenes Kapitel widmen. Diese Methode ist ein wahres Multitalent. Mit dieser Methode werden alle Parameter, die das Erscheinungsbild einer Szene beeinflussen, gesetzt. Die vollständige Syntax lautet: Direct3DDevice7.SetRenderState ( _ state As CONST_D3DRENDERSTATETYPE, _ renderstate As Long)
Sicherlich ist Ihnen aufgefallen, dass wir in den vorangegangenen Kapiteln diese Methode in den verschiedensten Zusammenhängen eingesetzt haben. Obwohl die Methode nur zwei Parameter beinhaltet, ist sie die vielseitigste Methode von Direct3D. Dies liegt an ihrer Variationsfähigkeit. Betrachten wir den ersten Parameter. Dieser wird durch die Konstantenliste CONST_D3DRENDERSTATE TYPE beschrieben. Enum CONST_D3DRENDERSTATETYPE D3DRENDERSTATE_ALPHABLENDENABLE D3DRENDERSTATE_ALPHAFUNC D3DRENDERSTATE_ALPHAREF
= 27 = 25 = 24
Kapitel 2 • Direct3D
D3DRENDERSTATE_ALPHATESTENABLE D3DRENDERSTATE_AMBIENT D3DRENDERSTATE_AMBIENTMATERIALSOURCE D3DRENDERSTATE_ANTIALIAS D3DRENDERSTATE_CLIPPING D3DRENDERSTATE_CLIPPLANEENABLE D3DRENDERSTATE_COLORKEYBLENDENABLE D3DRENDERSTATE_COLORKEYENABLE D3DRENDERSTATE_COLORVERTEX D3DRENDERSTATE_CULLMODE D3DRENDERSTATE_DESTBLEND D3DRENDERSTATE_DIFFUSEMATERIALSOURCE D3DRENDERSTATE_DITHERENABLE D3DRENDERSTATE_EDGEANTIALIAS D3DRENDERSTATE_EMISSIVEMATERIALSOURCE D3DRENDERSTATE_EXTENTS D3DRENDERSTATE_FILLMODE D3DRENDERSTATE_FOGCOLOR D3DRENDERSTATE_FOGENABLE D3DRENDERSTATE_FOGTABLEMODE D3DRENDERSTATE_FOGVERTEXMODE D3DRENDERSTATE_LASTPIXEL D3DRENDERSTATE_LIGHTING D3DRENDERSTATE_LINEPATTERN D3DRENDERSTATE_LOCALVIEWER D3DRENDERSTATE_NORMALIZENORMALS D3DRENDERSTATE_RANGEFOGENABLE D3DRENDERSTATE_SHADEMODE D3DRENDERSTATE_SPECULARENABLE D3DRENDERSTATE_SPECULARMATERIALSOURCE D3DRENDERSTATE_SRCBLEND D3DRENDERSTATE_STENCILENABLE D3DRENDERSTATE_STENCILFAIL D3DRENDERSTATE_STENCILFUNC D3DRENDERSTATE_STENCILMASK D3DRENDERSTATE_STENCILPASS D3DRENDERSTATE_STENCILREF D3DRENDERSTATE_STENCILWRITEMASK D3DRENDERSTATE_STENCILZFAIL D3DRENDERSTATE_STIPPLEDALPHA D3DRENDERSTATE_TEXTUREFACTOR D3DRENDERSTATE_TEXTUREPERSPECTIVE D3DRENDERSTATE_VERTEXBLEND D3DRENDERSTATE_WARP0 D3DRENDERSTATE_WARP1 D3DRENDERSTATE_WARP2 D3DRENDERSTATE_WARP3
219
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
15 139 147 2 136 152 144 41 141 22 20 145 26 40 148 138 8 34 28 35 140 16 137 10 142 143 48 9 29 146 19 52 53 56 58 55 57 59 54 33 60 4 151 128 129 130 131
220
Die SetRenderState()-Methode
D3DRENDERSTATE_WARP4 D3DRENDERSTATE_WARP5 D3DRENDERSTATE_WARP6 D3DRENDERSTATE_WARP7 D3DRENDERSTATE_ZBIAS D3DRENDERSTATE_ZENABLE D3DRENDERSTATE_ZFUNC D3DRENDERSTATE_ZVISIBLE D3DRENDERSTATE_ZWRITEENABLE End Type
= = = = = = = = =
132 133 134 135 47 7 23 30 14
Was macht diese Methode zum wahren Multitalent? Die Antwort liegt im zweiten Parameter. Anders als bei den meisten Methoden wird der zweite Parameter nicht durch einen festen Wertebereich beschrieben. Der Parameter renderstate ist abhängig vom ersten Parameter. Verdeutlichen wir dies mit zwei Beispielen. Beispiel 1: Der erste Parameter soll D3DRENDERSTATE_SRCBLEND sein. Somit wird der zweite Parameter durch die Konstantenliste CONST_D3DBLEND beschrieben. Enum CONST_D3DBLEND D3DBLEND_ZERO D3DBLEND_ONE D3DBLEND_SRCCOLOR D3DBLEND_INVSRCCOLOR D3DBLEND_SRCALPHA D3DBLEND_INVSRCALPHA D3DBLEND_DESTALPHA D3DBLEND_INVDESTALPHA D3DBLEND_DESTCOLOR D3DBLEND_INVDESTCOLOR D3DBLEND_SRCALPHASAT D3DBLEND_BOTHSRCALPHA D3DBLEND_BOTHINVSRCALPHA End Enum
= = = = = = = = = = = = =
1 2 3 4 5 6 7 8 9 10 11 12 13
Beispiel 2: Der erste Parameter ist D3DRENDERSTATE_SHADEMODE. Der zweite Parameter wird dann durch die Konstantenliste CONST_D3DSHAREMODE festgelegt. Enum CONST_D3DSHADEMODE D3DSHADE_FLAT D3DSHADE_GOURAUD D3DSHADE_PHONG
= 1 = 2 = 3
Kapitel 2 • Direct3D
221
End Enum
Der zweite Parameter muss nicht immer durch eine Konstantenliste definiert werden. Er kann z.B. eine Farbe enthalten oder einen Boolean-Ausdruck, True oder False. Diese doch recht komplexen Zusammenhänge haben wir in der folgenden Liste zusammengefasst. Parameter 1
Parameter 2
D3DRENDERSTATE_ALPHABLENDENABLE
True, um Alphablending zu erlauben, und False, um Alphablending zu deaktivieren. Default -> False
D3DRENDERSTATE_ALPHAFUNC
CONST_D3DCMPFUNC Default -> D3DCMP_ALWAYS
D3DRENDERSTATE_ALPHAREF
Wert zwischen 0.0 und 1.0 Default -> 0.0
D3DRENDERSTATE_ALPHATESTENABLE
True, um alpha Test zu erlauben, und False, um alpha Test nicht zu erlauben. Default -> False
D3DRENDERSTATE_AMBIENT
Eine ambiente Lichtfarbe z.B. für die Farbe Weiß &HFFFFFFFF oder RGB (255, 255, 255). Default -> 0
D3DRENDERSTATE_AMBIENTMATERIALSOURCE
CONST_D3DMATERIALCOLORSOURCE Default -> D3DMCS_COLOR2
D3DRENDERSTATE_ANTIALIAS
CONST_D3DANTIALIASMODE Default -> D3DANTIALIAS_NONE
D3DRENDERSTATE_CLIPPING
ungleich 0, um Clipping zu erlauben, und gleich 0, um Clipping nicht zu erlauben Default -> ungleich 0
D3DRENDERSTATE_CLIPPLANEENABLE
CONST_D3DCLIPPLANEFLAGS Default -> D3DCPF_DISABLEALL.
D3DRENDERSTATE_COLORKEYBLENDENABLE
ungleich 0, um alpha-blend Colorkey zu erlauben, und gleich [0], um alpha-blend Colorkey nicht zu erlauben
D3DRENDERSTATE_COLORKEYENABLE
True, um Colorkey-Transparenz zu erlauben, und False, um Colorkey-Transparenz nicht zu erlauben. Default -> False
D3DRENDERSTATE_COLORVERTEX
ungleich [0], um per-vertex-Farbe zu erlauben, und gleich [0], um per-vertex-Farbe nicht zu erlauben. Default -> ungleich 0
222
Die SetRenderState()-Methode
Parameter 1
Parameter 2
D3DRENDERSTATE_CULLMODE
CONST_D3DCULL Default -> D3DCULL_CCW
D3DRENDERSTATE_DESTBLEND
CONST_D3DBLEND Default -> D3DBLEND_ZERO
D3DRENDERSTATE_DIFFUSEMATERIALSOURCE
CONST_D3DMATERIAL COLORSOURCE Default -> D3DMCS_COLOR1
D3DRENDERSTATE_DITHERENABLE
True, um Dithering zu erlauben Default -> False
D3DRENDERSTATE_EDGEANTIALIAS
True, um Linienantialias zu erlauben Default -> False
D3DRENDERSTATE_EMISSIVEMATERIALSOURCE
CONST_D3DMATERIAL COLORSOURCE Default -> D3DMCS_MATERIAL
D3DRENDERSTATE_EXTENTS
ungleich 0, um Screenupdates zu erlauben Default -> gleich 0
D3DRENDERSTATE_FILLMODE
CONST_D3DFILLMODE Default -> D3DFILL_SOLID
D3DRENDERSTATE_FOGCOLOR
Nebelfarbe vom Typ Long. z.B. mit der Directx7.CreateColorRGB()-Methode erzeugt Default -> 0
D3DRENDERSTATE_FOGENABLE
True, um Nebel zu erlauben Default -> False
D3DRENDERSTATE_FOGTABLEMODE
CONST_D3DFOGMODE Default -> D3DFOG_NONE
D3DRENDERSTATE_FOGVERTEXMODE
CONST_D3DFOGMODE Default -> D3DFOG_NONE
D3DRENDERSTATE_LASTPIXEL
False, um das Zeichnen des letzten Pixels in einer Linie oder Dreiecks zu erlauben Default -> True
D3DRENDERSTATE_LIGHTING
ungleich 0, um Lichtberechnungen zu erlauben, oder gleich 0, um Lichtberechnungen nicht zu erlauben Default -> ungleich 0
Kapitel 2 • Direct3D
223
Parameter 1
Parameter 2
D3DRENDERSTATE_LINEPATTERN
Das D3DLINEPATTERN-Typen-Array beschreibt das Linienmuster. Type D3DLINEPATTERN linePattern Long repeatFactor As Long End Type Default linePattern -> 0 Default repentFactor -> 0
D3DRENDERSTATE_LOCALVIEWER
ungleich 0, um relative Betrachter-SpecularGlanzlichter zu erlauben, oder gleich 0, um senkrechte Specular-Glanzlichter zu erlauben Default -> ungleich 0
D3DRENDERSTATE_NORMALIZENORMALS
ungleich 0, um ein automatisches Normalisieren des Normalvektors zu erlauben, oder gleich 0, um dies nicht zu erlauben Default -> 0
D3DRENDERSTATE_RANGEFOGENABLE
True, um Range-Based Vertex Fog zu erlauben, oder False, um Range-Based Vertex Fog nicht zu erlauben Default -> False
D3DRENDERSTATE_SHADEMODE
CONST_D3DSHADEMODE Default -> D3DSHADE_GOURAUD
D3DRENDERSTATE_SPECULARENABLE
True, um Specular-Glanzlicher zu erlauben Default -> False
D3DRENDERSTATE_SPECULARMATERIALSOURCE
CONST_D3DMATERIAL COLORSOURCE Default -> D3DMCS_COLOR2
D3DRENDERSTATE_SRCBLEND
CONST_D3DBLEND Default -> D3DBLEND_ONE
D3DRENDERSTATE_STENCILENABLE
True, um Stencil zu erlauben Default -> False
D3DRENDERSTATE_STENCILFAIL
CONST_D3DSTENCILOP Default -> kein Default (wird zum Testen des Stencil verwendet)
D3DRENDERSTATE_STENCILFUNC
CONST_D3DCMPFUNC Default -> D3DCMP_ALWAYS
D3DRENDERSTATE_STENCILMASK
Stencil-Maske Default -> 0xFFFFFFFF
D3DRENDERSTATE_STENCILPASS
CONST_D3DSTENCILOP Default -> D3DSTENCILOP_KEEP
224
Die SetRenderState()-Methode
Parameter 1
Parameter 2
D3DRENDERSTATE_STENCILREF
Referenzwert für den Stenciltest Default -> 0
D3DRENDERSTATE_STENCILWRITEMASK
Schreibmaske für Stencil Default -> 0xFFFFFFFF
D3DRENDERSTATE_STENCILZFAIL
CONST_D3DSTENCILOP Default -> D3DSTENCILOP_KEEP
D3DRENDERSTATE_STIPPLEDALPHA
True, um Tüpfel-Alpha zu erlauben Default -> False
D3DRENDERSTATE_TEXTUREFACTOR
Farbe als Berechnungsfaktor bei Multitexturberechnungen Default -> abhängig von D3DTA_TFACTOR oder D3DTOP_BLENDFACTORALPHA
D3DRENDERSTATE_TEXTUREPERSPECTIVE
True, um perspektivisch korrektes Mipmap zu erlauben Default -> True
D3DRENDERSTATE_VERTEXBLEND
CONST_D3DVERTEXBLENDFLAGS Default -> D3DVBLEND_DISABLE
D3DRENDERSTATE_WARP0
CONST_D3D Default -> 0
D3DRENDERSTATE_WARP1
CONST_D3D Default -> 0
D3DRENDERSTATE_WARP2
CONST_D3D Default -> 0
D3DRENDERSTATE_WARP3
CONST_D3D Default -> 0
D3DRENDERSTATE_WARP4
CONST_D3D Default -> 0
D3DRENDERSTATE_WARP5
CONST_D3D Default -> 0
D3DRENDERSTATE_WARP6
CONST_D3D Default -> 0
D3DRENDERSTATE_WARP7
CONST_D3D Default -> 0
D3DRENDERSTATE_ZBIAS
Integer-Wert zwischen 0 und 16 Default -> 0
D3DRENDERSTATE_ZENABLE
CONST_D3DZBUFFERTYPE Default -> D3DZB_TRUE ist der Z-Buffer mit dem Renderziel verbunden, ist der Default -> D3DZB_FALSE
Kapitel 2 • Direct3D
2.13
225
Parameter 1
Parameter 2
D3DRENDERSTATE_ZFUNC
CONST_D3DCMPFUNC Default -> D3DCMP_LESSEQUAL
D3DRENDERSTATE_ZVISIBLE
wird nicht verwendet
D3DRENDERSTATE_ZWRITEENABLE
True, um das Beschreiben des Z-Buffers zu erlauben Default -> True
Effekte
2.13.1 Nebel Nebel kann das Erscheinungsbild einer Szene wesentlich realistischer wirken lassen. Geht man durch den Nebel auf ein weit entferntes Objekt zu, so wird es immer deutlicher sichtbar. Außerdem vermindert der Einsatz von Nebel die beim Rendern eventuell auftretenden Artefakte. Letztendlich können Sie die Sichtweite mit Nebel begrenzen. Diese Begrenzung wird aber nicht abrupt sein, sondern ermöglicht ein weiches Ausblenden. Direct3D unterstützt zwei Nebelmodelle, Pixel Fog und Vertex Fog. Beim Einsatz von Nebel werden die Farben der Szene mit der eingestellten Nebelfarbe gemischt. Beim Mischen der Objekte in der Szene werden die Entfernungen zum Betrachter berücksichtigt. Weiter enfernte Objekte werden vom Nebel stärker überlagert als näher liegende Objekte. Objekte, die an der maximalen Nebelreichweite liegen, sind nicht mehr sichtbar. Sie werden komplett von der Nebelfarbe überblendet. Hingegen werden Objekte, welche sich unmittelbar vor dem Betrachter befinden, vom Nebel nicht beeinflusst. Moderne Grafikkarten unterstützen beide Nebelmodelle. Um sicherzustellen, welche Nebelmodelle von der aktuellen Grafikkarte unterstützt werden, müssen wir die Grafikkarte prüfen. Prüfen der Grafikkarte auf die verfügbaren Nebelmodelle: Set g_d3d = g_dd.GetDirect3D Set g_d3dDevice = g_d3d.CreateDevice _ ("IID_IDirect3DHALDevice", g_ddsBackBuffer) Dim d3ddevdesc As D3DDEVICEDESC7 g_d3dDevice.GetCaps d3ddevdesc If (d3ddevdesc.dpcTriCaps.lRasterCaps And _ D3DPRASTERCAPS_FOGVERTEX) = D3DPRASTERCAPS_FOGVERTEX Then VertexFogIndex = True Else VertexFogIndex = False End If
226
Effekte
In diesem Abschnitt prüfen wir die Grafikkarte auf die Fähigkeit, Vertex Nebel darzustellen. If (d3ddevdesc.dpcTriCaps.lRasterCaps And _ D3DPRASTERCAPS_FOGTABLE) = _ D3DPRASTERCAPS_FOGTABLE Then PixelFogIndex = True Else PixelFogIndex = False End If
Dieser Teil ist für die Prüfung auf Pixelnebel zuständig. Pixelnebel wird auch als Table Fog bezeichnet. Diese Prüfroutine finden Sie in unserem Nebelbeispiel auf der CD. Berechnungsarten Direct3D unterscheidet zwischen drei Berechnungsarten zur Darstellung von Nebel. Linear, EXP und EXP2 liefern die geeigneten Ergebnisse für eine individuelle Nebeldarstellung. Die CONST_D3DFOGMODE-Konstantenliste identifiziert die Berechnungstechniken. Enum CONST_D3DFOGMODE D3DFOG_NONE D3DFOG_EXP D3DFOG_EXP2 D3DFOG_LINEAR End Enum
= = = =
0 1 2 3
D3DFOG_LINEAR F = end – d / end – start Die Parameter end und start werden von Ihnen angegeben. Der Parameter d ist ein Tiefenwert. Dieser ist von der jeweiligen Szene und der aktuellen Position des Betrachters abhängig. Sie werden sicherlich erkennen, dass hier eine einfache lineare Verteilung der Nebelintensivität stattfindet. Explizit können Sie die Intensivität des Nebels nicht angeben. Wollen Sie einen schwächeren Nebel, so müssen Sie die Entfernung zwischen end und start erhöhen. D3DFOG_EXP F = 1 / e^d*density D3DFOG_EXP2 F = 1 / e^(d*density)^2 Diese beiden Berechnungsmodelle sind logarithmischer Natur. Der Parameter e hat ungefähr den Wert 2.71828. Der Parameter density (Dichte) wird von Ihnen angegeben und liegt in dem Wertebereich zwischen 0.0 und 1.0. Der Parameter d ist widerum ein Tiefenwert.
Kapitel 2 • Direct3D
227
Im Grunde ist die Nebeldarstellung eine weitere Form von Blending. Das Erscheinungsbild der Szene ist von den Lichteinflüssen genauso abhängig wie von der Nebelfarbe oder Materialfarbe der Polygone. Alle Faktoren ergeben die gerenderte Szene. Vertex Fog Vertex Fog berechnet den Nebeleinfluss für jeden Vertex eines Polygons. Anschließend wird der Nebel über das gesamte Polygon verteilt. Diese Berechnungen werden von der D3D Licht- und Transformationsroutine übernommen. Vertex Fog bietet Ihnen die Möglichkeit, auf die genaue Entfernung zum Objekt in der 3D-Welt den Nebel zu berechnen. Die Berechnung berücksichtigt die Ausrichtung des Viewports. Diese Technik wird als Range Based Fog bezeichnet. Alle uns bekannten Grafikkarten, die Vertex Fog unterstützen, bieten ebenfalls die Unterstützung für Range Based Fog an. Dies ist keine eigenständige Berechnungsmethode, sondern eine Erweiterung für die Vertex-Fog-Technik. Über die Direct3DDevice7.SetRenderState()-Methode können Sie Range Based Fog aktivieren oder deaktivieren. Aktivieren des Range-Based-Fog-Modus: Direct3DDevice7.SetRenderState _ D3DRENDERSTATE_RANGEFOGENABLE, True
Deaktivieren des Range-Based-Fog-Modus: Direct3DDevice7.SetRenderState _ D3DRENDERSTATE_RANGEFOGENABLE, False
Um den Vertex Fog in eine Anwendung einzubinden sind vier Schritte notwendig. •
Schritt 1: Allgemeines Einschalten des Nebels Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGENABLE, True
Mit diesem SetRenderState()-Aufruf erlauben Sie die Verwendung von Nebel. Setzen Sie den zweiten Parameter auf False, so wird die Berechnung für Nebel deaktiviert. •
Schritt 2: Setzen der Nebelfarbe Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGCOLOR, Farbe
Der zweite Parameter Farbe enthält einen gültigen Farbwert. Diesen können Sie hexadezimal (z.B. &HFFFFFFFF für Farbe Weiß) oder per Befehlsargument (z.B. RGB (255, 255, 255)) übergeben. Eine beliebte Nebelfarbe ist ein helles Grau (RGB(200, 200, 200)). Ein reines Weiß ist nicht so gut geeignet. Es würden ungewünschte Blendeffekte auftreten. Die eingesetzte Farbe sollte die gewünschte Szene unterstützen und wird meistens den verwendeten Lichtverhältnissen angepasst.
228
Effekte
•
Schritt 3: Wählen der Berechnungsmethode Direct3DDevice7.SetRenderState _ D3DRENDERSTATE_FOGVERTEXMODE, Mode
Der Parameter Mode ist eine Konstante aus der CONST_D3DFOGMODEKonstantenliste. Genauere Informationen erhalten Sie im Abschnitt Berechnungsarten. •
Schritt 4: Setzen der Nebelparameter Die Nebelparameter stehen in Abhängigkeit der verwendeten Nebelberechnungsmethode. So werden für eine lineare Berechnung die Parameter D3DRENDERSTATE_FOGSTART und D3DRENDERSTATE_FOGEND benötigt. Hingegen wird für die Berechnungsmethoden EXP und EXP2 lediglich der Parameter D3DRENDERSTATE_FOGDENSITY benötigt.
Berechnungsmethode D3DFOG_LINEAR: Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGSTART, _ Fstart Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGEND, FEnd
Der Parameter FStart bestimmt, ab wo der Nebel sichtbar sein soll. Der Parameter FEnd definiert, bis wo der Nebel sichtbar sein soll. Über die gesamte Distanz wird die Nebelintensität linear ansteigen. Berechnungsmethode D3DFOG_EXP und D3DFOG_EXP2: Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGDENSITY, _ Density
Der Parameter Density bildet die Grundlage der logarithmischen Berechnung der Nebeldichte. Da die Nebeldichte logarithmisch berechnet wird, sind Angaben wie FStart oder FEnd nicht notwendig. Je gößer der Wert Density ist, desto dichter ist der Nebel. Der Wertebereich für Density liegt zwischen 0.0 und 1.0. Pixel Fog Pixel Fog bildet seine Berechnung nicht aus den Vertexinformationen eines Polygons, sondern kalkuliert für jedes Pixel einer Szene einen individuellen Nebelwert. Diese Berechnung per Pixelbasis unterscheidet sich somit von der VertexFog-Berechnungsmethode. Pixel Fog unterstützt nicht die Range-Based-FogBerechnung. Einige ältere Grafikkarten unterstützen anstelle des Pixel Fogs den WFog. Dieser ist zu der normalen Berechnung eines Z-Buffer-basierenden Systems nicht kompatibel. Um WFog zu unterstützen, müssten Sie die gesamte Projektionsmatrix umrechnen. Da alle modernen Grafikkarten den normalen Pixel Fog unterstützen, werden wir die Umrechnung nicht erläutern.
Kapitel 2 • Direct3D
229
Der Einsatz von Pixel Fog verläuft simultan zum Einsatz von Vertex Fog. Die verwendeten Parameter sind ebenfalls identisch. Die verwendeten RenderState()Aufrufe unterscheiden sich ein wenig, deshalb stellen wir die gesamte Prozedur nochmals vor. •
Schritt 1: Allgemeines Einschalten des Nebels Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGENABLE, True
Der Parameter True aktiviert den Nebel. False würde ihn deaktivieren. •
Schritt 2: Setzen der Nebelfarbe Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGCOLOR, Farbe
Über den Parameter Farbe setzen Sie die aktuelle Nebelfarbe. Die DirectX7.CreateColorRGB()-Methode ist für die Definition der Farbe bestens geeignet. •
Schritt 3: Wählen der Berechnungsmethode Direct3DDevice7.SetRenderState _ D3DRENDERSTATE_FOGTABLEMODE, Mode
Der Parameter Mode ist eine Konstante aus der CONST_D3DFOGMODEKonstantenliste. Mode bestimmt die Berechungsmethode der Nebelintensität. •
Schritt 4: Setzen der Nebelparameter Die Nebelparameter stehen in Abhängigkeit zu der verwendeten Nebelberechnungsmethode. So werden für eine lineare Berechnung die Parameter D3DRENDERSTATE_FOGSTART und D3DRENDERSTATE_FOGEND benötigt. Hingegen wird für die Berechnungsmethoden EXP und EXP2 lediglich der Parameter D3DRENDERSTATE_FOGDENSITY benötigt.
Berechnungsmethode D3DFOG_LINEAR: Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGSTART, _ Fstart Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGEND, FEnd
Der Parameter FStart bestimmt, ab wo der Nebel sichtbar sein soll. Der Parameter FEnd definiert, bis wo der Nebel sichtbar sein soll. Über die gesamte Distanz wird die Nebelintensität linear ansteigen. Berechnungsmethode D3DFOG_EXP und D3DFOG_EXP2: Direct3DDevice7.SetRenderState D3DRENDERSTATE_FOGDENSITY, _ Density
230
Effekte
Der Parameter Density bildet die Grundlage der logarithmischen Berechnung der Nebeldichte. Da die Nebeldichte logarithmisch berechnet wird, sind Angaben wie FStart oder FEnd nicht notwendig. Je gößer der Wert Density ist, desto dichter ist der Nebel. Der Wertebereich für Density liegt zwischen 0.0 und 1.0. Beispiel (Nebel) Unser Nebelbeispiel ist etwas umfangreicher ausgefallen. Wir haben einen langen Raum erzeugt. In diesem Raum haben wir insgesamt sieben Lichtquellen platziert. Zusätzlich haben wir noch vier drehende Objekte eingebunden. Diesen Aufwand haben wir betrieben, damit Sie die Wirkungsweise des Nebeleffekts besser beobachten können. Zum besseren Vergleich zwischen Vertex und Pixel Fog können Sie über die V-Taste auf Vertex Fog, über die V- + Shift-Taste auf Vertex Fog ohne Range-Based-Fog-Berechung, P-Taste auf Pixel Fog und N-Taste auf ohne Nebel umschalten. Über die Escape-Taste verlassen Sie das Programm.
Bild 2.54: Bildschirmfoto Nebel
Das Programm startet mit der Form_Load()-Routine. Am Anfang der Routine verzweigen wir in einige Subroutinen. Private Sub Form_Load() InitDDraw
Kapitel 2 • Direct3D
231
PrüfeNebelModel InitD3D Licht RenderState MakeVertex
Die Subroutinen InitDDraw() sowie InitD3D() sind Ihnen bereits bekannt. Mit der Subroutine Licht() werden die Lichtquellen initialisiert und gesetzt. In der Subroutine RenderState() haben wir alle allgemeinen Direct3DDevice7.Set RenderState()-Aufrufe zusammengefasst. Dies dient vor allem der Übersichtlichkeit. MakeVertex() ist eine Subroutine in der die Vertexe für die verwendeten Polygone abgelegt wurden. Die PrüfeNebelModel()-Subroutine ist eine Prüfroutine. Sie überprüft ob die aktuelle Grafikkarte Vertex- und / oder Pixel Fog darstellen kann. In ihr werden Indexvariabeln gesetzt, die ein späteres Einschalten des entsprechenden Nebelmodels zulassen. CreateTextur CreateTextur CreateTextur CreateTextur
0, 1, 2, 3,
App.Path App.Path App.Path App.Path
& & & &
"\mauer3.bmp" "\bholz03.bmp" "\arbpl19.bmp" "\bild36.bmp"
Die CreateTexture()-Subroutine kennen Sie bereits. Sie initialisiert und erstellt die verwendeten Texture Surfaces. . . . Do If GetTickCount > TimerZeit + ZeitInterval Then
Mit dieser If...Then Abfrage lassen wir das Rendern nur alle 15 Millisekunden zu. Bei der Drehung des Betrachters am Ende und Anfang des Raums verkürzt sich die Zeit auf 1 Millisekunde. If TimerStatus = True Then TimerIndex = TimerIndex + 0.05 If TimerIndex >= 14.8 Then If BlickRichtungWinkel > -90 Then ZeitInterval = 1 BlickRichtungWinkel = BlickRichtungWinkel – 2 BlickrichtungX = 1 + 100 * _ Cos(BlickRichtungWinkel / 57.296) BlickrichtungZ = 14.8 + 100 * _ Sin(BlickRichtungWinkel /57.296) TimerIndex = 14.8 Else ZeitInterval = 15 TimerStatus = False
232
Effekte
End If End If Else TimerIndex = TimerIndex – 0.05 If TimerIndex <= 0.2 Then If BlickRichtungWinkel < 90 Then ZeitInterval = 1 BlickRichtungWinkel = BlickRichtungWinkel + 2 BlickrichtungX = 1 + 100 * _ Cos(BlickRichtungWinkel / 57.296) BlickrichtungZ = 0.2 + 100 * _ Sin(BlickRichtungWinkel / 57.296) TimerIndex = 0.2 Else ZeitInterval = 15 TimerStatus = True End If End If End If g_dx.IdentityMatrix matView Call g_dx.ViewMatrix(matView, MakeVector(1, 0.2, TimerIndex), _ MakeVector(BlickrichtungX, BlickrichtungY, BlickrichtungZ), _ MakeVector(0, 1, 0), 0) g_d3dDevice.SetTransform D3DTRANSFORMSTATE_VIEW, matView
Dieser Block ist für die Bewegung und für das Drehen des Betrachters zuständig. Beachten Sie, dass Sie jedes Mal, wenn sich die Position des Betrachters ändert, diese Änderung in die Viewmatrix einfließen muss. Dim Temp1 As D3DVECTOR Dim Temp2 As D3DVECTOR Dim Mitte As D3DVECTOR Mitte.z = 10 For i = 136 To 151 Select Case I Case 136, 137, 138, Mitte.x = 1.75 Mitte.z = 10 Case 140, 141, 142, Mitte.x = 0.25 Mitte.z = 5 Case 144, 145, 146, Mitte.x = 0.25 Mitte.z = 14 Case 148, 149, 150, Mitte.x = 1.75 Mitte.z = 1 End Select
139
143
147
151
Kapitel 2 • Direct3D
233
Temp1.x = Vertex(i).x Temp1.y = Vertex(i).y Temp1.z = Vertex(i).z Rotation Temp1, Temp2, Mitte, 1 Vertex(i).x = Temp2.x Vertex(i).y = Temp2.y Vertex(i).z = Temp2.z Next i
Wir lassen die vier Anzeigetafeln im Raum rotieren. Hierzu manipulieren wir die Vertexdaten der entsprechenden Polygone. . . . Loop Until GetAsyncKeyState(vbKeyEscape) <> 0 . . . End Sub
Die Aktivierung des Nebeleffekts wird von der Form_KeyDown()-Routine übernommen. Diese verzweigt in die Subroutinen SetupPixelFog() und SetupVertex Fog(). Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) Select Case KeyCode Case vbKeyV If Shift = 0 Then If VertexFogIndex = True Then SetupPixelFog RGB(200, 200, 200), _ D3DFOG_NONE, 0.3, 0, 10 SetupVertexFog RGB(200, 200, 200), D3DFOG_EXP, True, _ 0.3, 0,10 InfoText = "Vertex Fog / D3DFOG_EXP / Density -> 0.3" Else InfoText = _ "Ihre Grafikkarte unterstützt keinen Vertex Fog" End If Else If VertexFogIndex = True Then SetupPixelFog RGB(200, 200, 200), _ D3DFOG_NONE, 0.3, 0, 10 SetupVertexFog RGB(200, 200, 200), _ D3DFOG_EXP, False, 0.3, 0, 10
234
Effekte
InfoText = "Vertex Fog / D3DFOG_EXP / Density -> 0.3" Else InfoText = _ "Ihre Grafikkarte unterstützt keinen Vertex Fog" End If End If
Beim Drücken der V-Taste verzweigen wir in die eigenliche Vertex-Nebelroutine. Beachten Sie, dass wir den Pixel Fog vorher deaktivieren. Case vbKeyN g_d3dDevice.SetRenderState D3DRENDERSTATE_FOGENABLE, False InfoText = "N O N E" Case vbKeyP If PixelFogIndex = True Then SetupVertexFog RGB(200, 200, 200), D3DFOG_NONE, False, _ 0.3, 0, 10 SetupPixelFog RGB(200, 200, 200), D3DFOG_EXP, 0.3, 0, 10 InfoText = "Pixel Fog / D3DFOG_EXP / Density -> 0.3" Else InfoText = _ "Ihre Grafikkarte unterstützt keinen Pixel Fog" End If
Beim Drücken der [P]-Taste verzweigen wir in die eigenliche Pixel-Nebelroutine. Beachten Sie, dass wir den Vertex Fog vorher deaktivieren. End Select End Sub
Wir verwenden bei dem Einsatz von Vertex Fog und Pixel Fog die gleichen Parameter. Dies ermöglicht es, genau zu vergleichen, wie sich die beiden Typen auf die Gestaltung der Szene auswirken. Sie sollten auf jeden Fall die Parameter der SetupPixelFog() und SetupVertexFog() Subroutinen mal verändern. So lernen Sie alle Varianten genau kennen. Nun kommen wir endlich zu den eigentlichen Subroutinen, welche für die Darstellung der Nebeleffekte verantwortlich sind. Vertex Fog: Sub SetupVertexFog(lColor As Long, Mode As CONST_D3DFOGMODE, _ bUseRange As Boolean, Optional Density As Single, _ Optional StartFog As Single, Optional EndFog As Single) g_d3dDevice.SetRenderState D3DRENDERSTATE_FOGENABLE, True g_d3dDevice.SetRenderState D3DRENDERSTATE_FOGCOLOR, lColor If Mode = D3DFOG_LINEAR Then g_d3dDevice.SetRenderState _ D3DRENDERSTATE_FOGVERTEXMODE, Mode
Kapitel 2 • Direct3D
235
g_d3dDevice.SetRenderStateSingle _ D3DRENDERSTATE_FOGSTART, StartFog g_d3dDevice.SetRenderStateSingle _ D3DRENDERSTATE_FOGEND, EndFog Else g_d3dDevice.SetRenderState _ D3DRENDERSTATE_FOGVERTEXMODE, Mode g_d3dDevice.SetRenderStateSingle _ D3DRENDERSTATE_FOGDENSITY, Density End If If bUseRange = True Then g_d3dDevice.SetRenderState _ D3DRENDERSTATE_RANGEFOGENABLE, True Else g_d3dDevice.SetRenderState _ D3DRENDERSTATE_RANGEFOGENABLE, False End If End Sub
Pixel Fog: Sub SetupPixelFog(lColor As Long, Mode As CONST_D3DFOGMODE, _ Optional Density As Single, Optional StartFog As Single, _ Optional EndFog As Single) g_d3dDevice.SetRenderState D3DRENDERSTATE_FOGENABLE, True g_d3dDevice.SetRenderState D3DRENDERSTATE_FOGCOLOR, lColor If Mode = D3DFOG_LINEAR Then g_d3dDevice.SetRenderState _ D3DRENDERSTATE_FOGTABLEMODE, Mode g_d3dDevice.SetRenderStateSingle _ D3DRENDERSTATE_FOGSTART, StartFog g_d3dDevice.SetRenderStateSingle _ D3DRENDERSTATE_FOGEND, EndFog Else g_d3dDevice.SetRenderState _ D3DRENDERSTATE_FOGTABLEMODE, Mode g_d3dDevice.SetRenderStateSingle _ D3DRENDERSTATE_FOGDENSITY, Density End If End Sub
Die MakeVertex()-Subroutine erfasst alle Vertexe, die wir zur Darstellung der Polygone benötigen. Public Sub MakeVertex() 'Linke Wand
236
Effekte
g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex . . . 'drehendes Dreieck4 g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex g_dx.CreateD3DVertex
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 1, 1, 2, 2, 3, 3, 4,
1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 2, 2, 3, 3, 4,
1, 0, 1, 0, 1, 0, 1, 0, 1,
Vertex(0) Vertex(1) Vertex(2) Vertex(3) Vertex(4) Vertex(5) Vertex(6) Vertex(7) Vertex(8)
1.5, 0.25, 1, -1, 0, -1, 0, 1, Vertex(148) 1.5, 0.75, 1, -1, 0, -1, 0, 0, Vertex(149) 2, 0.25, 1, -1, 0, -1, 1, 1, Vertex(150) 2, 0.75, 1, -1, 0, -1, 1, 0, Vertex(151)
Insgesamt definieren wir 152 Vertexe. Sie können sich leicht vorstellen, das eine Menge Arbeit auf einen zukommt, wenn die 3D-Welt komplexer wird. Letztendlich wird man an einem 3D-Editor mit entsprechender 3D-Engine nicht vorbeikommen. Schauen Sie sich doch einmal unseren mitgelieferten 3D-Editor an. Auf der CD finden Sie eine small Version, mit der Sie allerding schon einiges anstellen können. Durch den Kauf des Buches können Sie das Vollprodukt zu einem absoluten Sonderpreis von 69,-- DM erwerben. Der normale Verkaufspreis beträgt immerhin 129,-- DM.
2.13.2 Billboarding Mit Billboarding ist Direct3D in Lage ein 2D-Objekt so zu rendern, dass es wie ein 3D-Objekt aussieht. Um diese Sinnestäuschung zu verwirklichen, wird ein normales Polygon erzeugt. Auf das Polygon wird eine Textur gelegt. Das Polygon wird nun immer zum Betrachter ausgerichtet. Sie werden das Polygon also nie von der Seite sehen. Ein typisches Beispiel für den Einsatz von Billboarding ist die Darstellung eines Baumes. Ein Baum mit seinen vielen Ästen und Blättern ist als 3D-Objekt nur mit sehr viel Mühe zu erstellen. Außerdem wäre eine sehr hohe Anzahl von Polygonen notwendig. Das Auflegen einer Textur wäre ebenfalls nicht einfach. Wenn wir Billboarding nutzen, können wir uns die Arbeit wesentlich erleichtern. Wir erstellen aus mehreren Dreiecken ein Rechteck. Auf das Rechteck legen wir eine Textur. Nun aktivieren wir den Farbschlüssel, um alle nicht zum Baum gehörenden Bildpixel transparent zu rendern. Wenn wir das Rechteck immer auf den Betrachter ausrichten, wird der Baum dreidimensional wirken.
Kapitel 2 • Direct3D
237
Natürlich wird der künstliche 3D-Baum nicht die gleichen Eigenschaften haben wie ein echter 3D-Baum. So ist es nicht möglich sich in den 3D-Raum des Baumes zu begeben. Der Baum selber wird etwas starr wirken. Als Kulisse einer Szene wird man diese Mankos nicht bemerken. Beispiel (Billboarding) Wir haben eine Bodenplatte mit insgesamt 2646 Vertexen erstellt. Zusätzlich wurden vier Bäume und ein Schild eingebunden. Das Schild wurde mit 486 Vertexen aufgelöst. Die Bäume bestehen aus je 4 Vertexen. Bei jedem Baum haben wir eine Pointlicht platziert. Bei der weißen Lichtquelle befindet sich noch ein Spotlicht. Dieses ist auf das Schild gerichtet und enthält nur speculare Lichtanteile. Dadurch erhalten wir ein Glanzlicht immer dann, wenn sich das Schild zu der weißen Lichtquelle dreht. Mit der B-Taste können Sie Billboarding aktivieren. Die N-Taste deaktiviert Billboarding. Mit der Space-Taste können Sie den Text ein- oder ausblenden. Die Escape-Taste dient zum Verlassen des Programms.
Bild 2.55: Bildschirmfoto Billboarding
Die Technik von Billboarding: Die fünf Objekte auf der Bodenplatte sind einfache Polygone. Sie sind im Grunde unendlich dünn. Um Billboarding einzusetzen müssen wir dem Betrachter vorgaukeln, die Objekte würden eine Tiefe besitzen. Dies ist nicht ganz einfach, denn
238
Effekte
jedes Mal wenn sich der Betrachter einem Objekt von der Seite nähert, wird er sofort erkennen, dass die Objekte keine Tiefe besitzen. Der Weg von Billboarding besteht darin, es einfach nicht zuzulassen, dass sich der Betrachter ein Objekt von der Seite betrachten kann. Wir müssen die Polygone bei jeder Änderung von Position oder Blickrichtung des Betrachters immer wieder zum Betrachter ausrichten. Der Betracher wird das Objekt dann immer direkt von vorne sehen. Es ist ihm dadurch nicht möglich zu erkennen, wie dick das Objekt ist. Unser Beispiel beginnt mit der Form_Load()-Subroutine. Nach den üblichen Initialisierungsroutinen geht es in die Do...Loop()-Schleife. Bevor wir die Objekte zum Betrachter ausrichten können, müssen wir die jeweiligen Winkel der Objekte zum Betrachter ermitteln. Private Sub Form_Load() . . . Do If GetTickCount > TimerZeit + ZeitInterval Then w = w + 0.5: If w > 360 Then w = 0
Die Variable w ist eine Hilfsvariable. Mit ihr können wir uns kreisend über die Bodenplatte bewegen. g_dx.IdentityMatrix matView posx = 10 * Cos(w / 57.296) posz = (-15 * Sin(w / 57.296)) – 10
Die Variablen posx und posz speichern die X- und Z-Koordinate des Betrachters. Seine Blickrichtung ist immer auf die Mitte der Bodenplatte gerichtet und wird auch nicht verändert. baumwinkel1 baumwinkel2 baumwinkel3 baumwinkel4 baumwinkel5
= = = = =
360 360 360 360 360
– – – – –
(ATAN2(-5 – posx, 5 – posz) * 57.296) (ATAN2(5 – posx, 5 – posz) * 57.296) (ATAN2(-5 – posx, -5 – posz) * 57.296) (ATAN2(5 – posx, -5 – posz) * 57.296) (ATAN2(0 – posx, 0 – posz) * 57.296)
In den Variablen baumwinkel1 bis 5 speichern wir die Winkel der Objekte (auf der Bodenplatte) zum Betrachter. Die Subroutine ATAN2() ist dabei sehr nützlich. Dim DestVect As D3DVECTOR If Billboard = True Then For i = 0 To 502 Select Case I Case 0 To 3 Rotation MakeVector(Vertex(i).X, Vertex(i).Y, _ Vertex(i).z), DestVect, MakeVector(-5, 0, 5), baumwinkel1 TempVertex(i).X = DestVect.X
Kapitel 2 • Direct3D
239
TempVertex(i).Y = DestVect.Y TempVertex(i).z = DestVect.z Case 4 To 7 Rotation MakeVector(Vertex(i).X, Vertex(i).Y, _ Vertex(i).z), DestVect, MakeVector(5, 0, 5), baumwinkel2 TempVertex(i).X = DestVect.X TempVertex(i).Y = DestVect.Y TempVertex(i).z = DestVect.z
An dieser Stelle manipulieren wir die Vertexdaten der platzierten Objekte. Sie werden immer in Richtung des Betrachters gedreht. Das ist eigentlich schon der gesamte Trick von Billboarding. Beachten Sie bitte, dass wir die manipulierten Vertexdaten an die temporäre Vertexvariable TempVertex(i) übergeben. Somit bleiben die Originaldaten der Objekte erhalten. . . . Case 16 To 502 Rotation MakeVector(Vertex(i).X, Vertex(i).Y, _ Vertex(i).z), DestVect, MakeVector(0, 0, 0), baumwinkel5 TempVertex(i).X = DestVect.X TempVertex(i).Y = DestVect.Y TempVertex(i).z = DestVect.z TempVertex(i).nx = -1 * Sin((360 – baumwinkel5) / 57.296) TempVertex(i).nz = -1 * Cos((360 – baumwinkel5) / 57.296) TempVertex(i).ny = 0
In diesem Teil der Select-Case-Abfrage manipulieren wir die Vertexe von dem Schild in der Mitte. Das Besondere an dieser Manipulation ist, dass wir nicht nur die x-, y-, z-Einträge verändern, sondern auch eine Anpassung an den nx- und nzEinträgen vornehmen. Diese beschreiben die Ausrichtung des Normalvektors eines Vertex. Indem wir den Normalvektor immer senkrecht (nach vorne blickend) zum Schild ausrichten, kann das Schild die verschiedenen Lichtquellen reflektieren. Dadurch wirken die Lichtverhältnisse sehr viel realistischer. End Select Next i . . . End Sub
Werfen Sie doch vielleicht noch einen Blick in die Subroutine Licht(). Als Lichtquelle fünf legen wir die Parameter für das Spotlicht fest. Interessant ist, dass wir nur speculare Lichtanteile zuweisen. Diese Lichtquelle dient also ausschließlich zum Erzeugen von Glanzlichtern. Natürlich muss das verwendete Material entsprechende Specularanteile beinhalten und die Specularreflexion über die SetRenderState()-Methode aktiviert sein.
240
Effekte
Direct3DDevice7.SetRenderState _ D3DRENDERSTATE_SPECULARENABLE, True
Ansonsten ist ein Glanzlichteffekt unmöglich. Public Sub Licht() . . . With Licht_5 .specular = Farbe_2 .range = 10 .attenuation0 = 0.8 .dltType = D3DLIGHT_SPOT .position.X = 5 .position.Y = 3 .position.z = 5 wi = 225 .direction.X = Cos(wi / 57.296) – 0.3 .direction.Y = 0.1 .direction.z = Sin(wi / 57.296) .phi = 20 / 57.296 .theta = 2 / 57.296 .falloff = 2 End With . . . End Sub
2.13.3 Feuer und Explosionen Feuer und Explosionen sind mit der Technik zur animierten Darstellung von Sprites (Abschnitt DirectDraw) fast identisch. Überlegen wir uns einmal, was wir für die Darstellung einer Flamme benötigen. Zunächst stellen wir fest, dass eine Flamme als normale Textursurface in D3D eingebunden wird. Dennoch unterscheidet sie sich von der Darstellung von z.B. einer Mauer. Die Mauer verändert ihr Erscheinungsbild nicht. Im Gegensatz dazu wird eine Flamme pulsieren. Sie wird ständig kleiner, größer, heller, breiter oder verändert die Farbe. Wir benötigen also eine animierte Flamme. Abbildung 2.56 zeigt eine Flamme mit 32 Einzelbildern. Zur Darstellung der Flamme in der 3D-Welt werden wir nun nacheinander die einzelnen Flammen ausschneiden und auf die passende Textursurface kopieren (blitten). Das verhält sich genauso wie bei der animierten Spritedarstellung.
Kapitel 2 • Direct3D
241
Bild 2.56: Animierte Flamme
Um die Flamme realistisch erscheinen zu lassen, werden wir die Flamme etwas transparent darstellen. Damit nur die Elemente der Flamme auf dem Bildschirm sichtbar sind, werden wir den Hintergrund mit Hilfe des Farbschlüssels herausfiltern. Fassen wir die Aufgaben zusammen: Einschalten der RenderStates für Transparenz und Aktivieren des Farbschlüssels um den Hintergrund der Flamme zu entfernen. Wir erzeugen eine Textursurface, welche die gesamte animierte Flamme enthält (Textursurface 1). Wir erzeugen eine Textursurface, welche die Dimension einer einzelnen Flamme hat. Diese ist zum Anfang noch leer (Textursurface 2). Wir erzeugen ein Polygon (üblicherweise ein Rechteck), welchem wir die leere Textursurface zuweisen. Wir kopieren die erste Flamme von Textursurface 1 auf Textursurface 2. Da Textursurface 2 bereits einem Polygon in der 3D-Welt zugeordnet ist, wird die Flamme beim nächsten Zeichnen der Szene dargestellt. Vor dem nächsten Rendern der Szene kopieren wir die zweite Flamme von Textursurface 1 auf Textursurface 2. Diese wird bei dem folgenden Rendern dargestellt. Wir wiederholen Schritt 5, bis alle Flammen einmal dargestellt wurden. Anschließend fangen wir wieder bei der ersten Flamme an. Explosionen werden mit der gleichen Technik realisiert. Programmtechnisch werden Explosionen durch ein Ereignis ausgelöst. Bei der Explosion lassen Sie die Animationsfolge nur einmal durchlaufen.
242
Effekte
Wenn Sie eine Flamme oder Explosion nicht direkt an einer Wand platzieren, sondern frei im Raum, so sollten Sie die Billboardingtechnik noch einsetzen. Ansonsten wird es vorkommen, dass Sie die Textur von der Seite betrachten und diese ist dann natürlich unendlich dünn. Beispiel (Feuer) Unser Feuerdemo baut auf dem Demoprogramm der Billboardingtechnik auf. Wiederum haben wir eine drehende Bodenplatte. Auf der Bodenplatte haben wir vier Fackelflammen platziert. Bei jeder Fackel befinden sich zwei Lichtquellen. Die eine Lichtquelle strahlt ein gelbes Licht, die andere strahlt ein rotes Licht. Die Intensität der Lichtquellen wird per Zufall ermittelt. Dadurch erhalten wir realistisches Fackellicht. An einer Flamme haben wir einen virtuellen Scheinwerfer platziert. Das erzeugte Spotlight erzeugt das Glanzlicht auf dem Schild in der Mitte. Diese ist nur in einem bestimmten Winkelbereich zu sehen. Die Normalvektoren des Schildes richten wir immer zum Betrachter, dadurch haben wir eine natürliche Reflexion der Flammen auf dem Schild.
Bild 2.57: Bildschirmfoto Feuer
Kapitel 2 • Direct3D
243
Mit der B-Taste können Sie Billboarding aktivieren. Mit der N-Taste deaktivieren Sie Billboarding. Die Escape-Taste dient zum Verlassen des Progamms. Alles beginnt mit der Form_Load()-Subroutine. Private Sub Form_Load() . . . CreateTextur 1, False, App.Path & "\bholz03.bmp"
TextureSurf(1) benutzen wir für die Textur der Bodenplatte. CreateTextur 3, False, App.Path & "\logo.bmp"
TextureSurf(3) wird für die Darstellung des Schilds benötigt. CreateTextur 4, False, App.Path & "\feuer.bmp"
Die vierte Textursurface enthält die gesamte Bildreihe der Flamme. Aus ihr werden wir später die benötigten Teile herauskopieren und an TextureSurf(2) übergeben. Auf der Flammenbitmap befinden sich vier Reihen mit jeweils acht Spalten. Die Breite der Bitmap beträt 256 Pixel, die Höhe beträgt 256 Pixel. Somit ergibt sich für die einzelne Flamme eine Breite von 32 Pixeln und eine Höhe von 64 Pixeln. CreateTextur 2, True, ""
Die TextureSurf(2) wird als leere Surface erstellt. Entsprechend der Animationsfolge wird sie mit Bitmapdaten von der TextureSurf(4) gefüllt. . . . Feuer
Die Subroutine Feuer() kopiert den richtigen Ausschnitt von TextureSurf(4) auf TextureSurf(2). Das werden wir uns noch genauer anschauen. Licht
Wir wollen ein Flackerlicht erzeugen. Dazu ist es notwendig die Lichtparmeter permanent zu ändern. Anschließend müssen diese Änderungen Direct3D mitgeteilt werden. Dies übernimmt die Subroutine Licht(). . . . g_d3dDevice.SetTexture 0, TextureSurf(2) g_d3dDevice.SetRenderState D3DRENDERSTATE_DESTBLEND, _ D3DBLEND_ONE
244
Effekte
g_d3dDevice.SetRenderState D3DRENDERSTATE_ALPHABLENDENABLE, _ True
Bevor wir die Flammen rendern, aktivieren wir die Alpahtransparenz. Zum Mischen der Textur verwenden wir den Mischmodus D3DBLEND_ONE. Dieser ist von den Alphawerten des Materials nicht abhängig und erzeugt eine für die Flammen gute Transparenz. g_d3dDevice.SetMaterial Material(DXColor(1, 1, 1, 1), _ DXColor(1, 1, 1, 1), DXColor(1, 1, 1, 1), _ DXColor(1, 1, 1, 1), 0.1, 0) g_d3dDevice.DrawPrimitive D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX, TempVertex(0), 4, D3DDP_WAIT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX, TempVertex(4), 4, D3DDP_WAIT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX, TempVertex(8), 4, D3DDP_WAIT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX, TempVertex(12), 4, D3DDP_WAIT g_d3dDevice.SetRenderState D3DRENDERSTATE_ALPHABLENDENABLE, _ False
_ _ _ _
Nachdem wir die vier Flammen gerendert haben, deaktivieren wir die Alphatransparenz. Ansonsten würden beim nächsten Renderdurchlauf die Bodenplatte sowie das Schild ebenfalls transparent dargestellt. Da liegt natürlich nicht in unserer Absicht. Vielleicht ist Ihnen aufgefallen, dass wir im Vergleich zu dem Billboardingdemo die Renderreihenfolge der Polygone umgestellt haben. Die Flammen werden als Letztes gerendert. Da die Flammen transparent sein sollen, müssen wir sie mit dem Hintergrund mischen. Würden wir die Flammen z.B. vor dem Schild rendern so könnte die Transparenz zum Schild nicht berechnet werden. Das Schild würde ja noch gar nicht existieren, also könnte sich auch nichts mischen. . . . End Sub
Bevor wir uns die Subroutine Feuer() betrachten, betrachten wir die CreateTexture()-Subroutine. Diese wurde von uns etwas modifiziert, sodass wir auch Textursurfaces ohne Textur erstellen können. Außerdem legen wir fest, ob auf die zu erstellende Textursurface der Farbschlüssel angewendet werden soll. Private Sub CreateTextur(ByVal Index As Integer, ColorKey As _ Boolean, sFile As String) Dim ddsd3 As DDSURFACEDESC2 Dim TextureEnum As Direct3DenumPixelFormats Set TextureEnum = g_d3dDevice.GetTextureFormatsEnum()
Kapitel 2 • Direct3D
245
TextureEnum.GetItem 1, ddsd3.ddpfPixelFormat If sFile <> "" Then ddsd3.ddsCaps.lCaps = DDSCAPS_TEXTURE Set TextureSurf(Index) = g_dd.CreateSurfaceFromFile(sFile, _ ddsd3)
Bis hierher ist Ihnen die Routine bekannt. Else ddsd3.lFlags = DDSD_WIDTH Or DDSD_HEIGHT ddsd3.lHeight = 64 ddsd3.lWidth = 32 ddsd3.ddsCaps.lCaps = DDSCAPS_TEXTURE Set TextureSurf(Index) = g_dd.CreateSurface(ddsd3)
In diesem Teil erstellen wir eine Textursurface, ohne gleichzeitig eine Textur von der Festplatte zu laden. Die Dimensionen der Textur legen wir mit den Parametern lHeight und lWidth fest. Sie entsprechen in unserem Beispielprogramm genau den Dimensionen einer einzelnen Flamme. End If Dim ck As DDCOLORKEY If ColorKey = True Then TextureSurf(Index).SetColorKey _ DDCKEY_SRCBLT, ck End Sub
Nun kommen wir endlich zum Kernstück des Feuertricks. Die Subroutine Feuer() sorgt für die Animation der Flammen. Die Variablen CelX und CelY sind global dimensioniert worden. Mit ihnen bewegen wir uns auf der TextureSurf(2) so, dass sie die Koordinaten für die linke obere Ecke einer Rechtstruktur festlegen. Public Sub Feuer() If g_dx.TickCount > FeuerZeit + 40 Then FeuerZeit = g_dx.TickCount CelX = CelX + 1 If CelX > 7 Then CelX = 0 CelY = CelY + 1 End If If CelY > 3 Then CelX = 0 CelY = 0 End If Dim Rect1 As RECT Dim Rect2 As RECT Rect1.Left = CelX * 32 Rect1.Right = Rect1.Left + 32 Rect1.Top = CelY * 64 Rect1.Bottom = Rect1.Top + 64
246
Effekte
Da wir die Breite und Höhe der einzelnen Flamme kennen, ist es ein Kinderspiel, die gesamte RECT-Struktur zu füllen. Innerhalb dieser Struktur befindet sich immer eine einzelne Flamme. TextureSurf(2).Blt Rect2, TextureSurf(4), Rect1, DDBLT_WAIT
Zum Abschluss brauchen wird nur noch die Flamme auf die TextureSurf(2) blitten. Diese wird beim Rendern der Flammen verwendet. End If End Sub
2.13.4 Antialiasing Antialiasing ist eine Technik um die Treppenbildung von Linien zu reduzieren. Linien, welche nicht hundertprozentig horizontal oder vertikal verlaufen, werden immer als Treppe dargestellt. Die Ausprägung der Treppe ist von der verwendeten Auflösung abhängig. Mit eingeschaltetem Antialiasing wird zwischen der Linie und dem Hintergrund eine Mischfarbe erstellt. Da diese im Prinzip von Linienfarbe und Hintergrundfarbe einen gewissen Anteil enthält, wirkt der Übergang viel weicher und die Kanten sind nicht mehr deutlich zu erkennen. Antialiasing könnte man nur einen Nachteil vorwerfen. Die Bildschärfe nimmt ab. Alles wirkt ein wenig verwischt. Besonders in Szenen, in denen eine Kantenschärfe zur Gesamtstimmung gehört, erweist sich Antialiasing als nachteilig.
Bild 2.58: Antialiasing
Direct3D unterstützt zwei Antialiasing-Techniken: Kanten-Antialiasing und Fullscreen-Antialiasing. Welche Technik die geeignete ist, hängt im Wesentlichen von der verfügbaren Performance ab.
Kapitel 2 • Direct3D
247
Leider unterstützen längst nicht alle Grafikkarten Antialiasing. Für moderne Grafikkarten gehört dieses Merkmal zum Pflichtteil. Dennoch sollten Sie die Grafikkarte zuvor prüfen. •
Prüfung der Grafikkarte auf Antialiasing
•
Zur Prüfung der Grafikkarte benutzen wir die Direct3DDevice7.GetCaps()Methode. Unterstützt die Grafikkarte Kanten-Antialiasing finden wir das notwendigen Flag in den Mitgliedsdaten IRasterCaps des D3DprimCaps-TypenArrays. Dim PrimCaps As D3DDEVICEDESC7 g_d3dDevice.GetCaps PrimCaps If (PrimCaps.dpcTriCaps.lRasterCaps And _ D3DPRASTERCAPS_ANTIALIASEDGES) = _ D3DPRASTERCAPS_ANTIALIASEDGES Then
Ist das Flag vorhanden, so wird die If...Then-Abfrage mit True beantwortet. End If
Bei der Prüfung auf Fullscreen-Antialiasing fragen wir die Sortierart für Fullscreen-Antialiasing ab. Wir suchen nach den Flags D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT und D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT. Sind beide Flags nicht vorhanden, so wird FullscreenAntialiasing nicht unterstützt. Sortierter Aufbau der Polygone von hinten nach vorne: Dim PrimCaps As D3DDEVICEDESC7 g_d3dDevice.GetCaps PrimCaps If (PrimCaps.dpcTriCaps.lRasterCaps And _ D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT) = _ D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT Then
Ist das Flag vorhanden, so wird die If...Then-Abfrage mit True beantwortet. End If
Unsortierter Aufbau der Polygone: Dim PrimCaps As D3DDEVICEDESC7 g_d3dDevice.GetCaps PrimCaps If (PrimCaps.dpcTriCaps.lRasterCaps And _ D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT) = _ D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT Then
Ist das Flag vorhanden, so wird die If...Then-Abfrage mit True beantwortet. End If
248
Effekte
•
Kanten-Antialiasing
•
Mit der Kanten-Antialiasing-Technik rendern Sie die Szene wie gewohnt. Anschließend müssen Sie die Umrisse der Objekte mit eingeschaltetem KantenAntialiasing nochmals rendern. Dabei werden die beiden Linien miteinander verwischt. Durch das Verwischen der Linien sind die einzelnen Treppen nicht mehr klar zu erkennen. Sie sind immer noch vorhanden, wirken aber sehr viel weicher und somit realistischer. Beim zweiten Rendern der Szene benutzen Sie ebenfalls die Direct3DDevice7.DrawPrimitive()-Methode. Diesmal setzen Sie allerdings die Parameter D3DPT_LINESTRIP oder D3DPT_LINELIST. Welchen Parameter Sie nutzen, ist natürlich von dem ersten DrawPrimitive()Aufruf abhängig. Bei diesem stehen Ihnen die Parameter D3DPT_TRIANG LESTRIP und D3DPT_TRIANGLELIST zur Verfügung.
Aktivieren von Kanten-Antialiasing: Kanten-Antialiasing aktivieren Sie, indem Sie den zweiten Parameter der SetRenderState()-Methode auf ungleich 0 setzen. Direct3DDevice7.SetRenderState D3DRENDERSTATE_EDGEANTIALIAS, 1
Deaktivieren von Kanten-Antialiasing: Wenn Sie den Renderstate-Parameter der SetRenderState()-Methode auf 0 setzen deaktivieren Sie den Kanten-Antialiasing-Modus. Direct3DDevice7.SetRenderState D3DRENDERSTATE_EDGEANTIALIAS, 0
•
Fullscreen-Antialiasing
•
Fullscreen-Antialiasing verwischt die Kanten aller Polygone in einer Szene. Im Gegensatz zum Kanten-Antialiasing muss die Szene nicht zweimal gerendert werden. Diese Technik zeigt ihre Wirkung nur bei Dreiecken oder Gruppen von Dreiecken. Einzelnen Linien beleiben unberührt. Einige Grafikkarten sind nur in der Lage, Fullscreen-Antialiasing einzusetzen, wenn die Szene von hinten nach vorne aufgebaut wird. Bei der Prüfung der Grafikkarte auf die Unterstützung von Antialiasing-Techniken haben wir bereits gezeigt, wie Sie die Fähigkeit der aktuellen Grafikkarte abfragen. Das Ergebnis dieser Prüfung entscheidet, wie die notwendige Direct3DDevice7.SetRenderState()-Methode aufgerufen werden muss.
Zum Aktivieren des Fullscreen-Antialiasing-Modus bestehen somit zwei Alternativen: sortiert: Direct3DDevice7.SetRenderState D3DRENDERSTATE_ANTIALIAS, _ D3DANTIALIAS_SORTDEPENDENT
Kapitel 2 • Direct3D
249
unsortiert: Direct3DDevice7.SetRenderState D3DRENDERSTATE_ANTIALIAS, _ D3DANTIALIAS_SORTINDEPENDENT
Zum Deaktivieren des Fullscreen-Antialiasing-Modus wählen Sie folgenden Aufruf: Direct3DDevice7.SetRenderState D3DRENDERSTATE_ANTIALIAS, _ D3DANTIALIAS_NONE
Antialiasing ist eine feine Technik, um eine Szene wesentlich realistischer darzustellen. Die unangenehme Treppenbildung bleibt aus. Besonders beim FullscreenAntialiasing wird die Bildung von Artefakten gemindert. Leider benötigt diese Technik viel Rechenzeit. Einige moderne Grafikkarten können Antialiasing allerding fast ohne Performanceverluste einbinden. Manchmal wird dies auf Kosten der Qualität verwirklicht. Einen kleinen Performancetrick haben wir aber noch für Sie. Beim Erstellen der Render Surface (im Regelfall ist das die Backbuffer Surface) sollen Sie das DDSCAPS_HINTANTIALIASING-Flag setzten. Einige Grafikkarten verlangen dieses Flag, ansonsten wird Antialiasing ohne Erfolg bleiben. Die genaue Initialisierung der Surface können Sie sich in unserem Antialiasing-Beispiel anschauen. Dim ddsd2 As DDSURFACEDESC2 ddsd2.lFlags = DDSD_BACKBUFFERCOUNT Or DDSD_CAPS ddsd2.ddsCaps.lCaps2 = DDSCAPS2_HINTANTIALIASING ddsd2.ddsCaps.lCaps = DDSCAPS_COMPLEX Or DDSCAPS_FLIP Or _ DDSCAPS_PRIMARYSURFACE Or DDSCAPS_3DDEVICE Or _ DDSCAPS_SYSTEMMEMORY ddsd2.lBackBufferCount = 1 Set g_ddsPrimary = g_dd.CreateSurface(ddsd2)
Noch ein Hinweis: Antialiasing können Sie beim Aufbau einer Szene ein- und ausschalten. Sie können also die Objekte, bei denen sich Anitaliasing positiv bemerkbar macht, mit eingeschaltetem Antialiasing rendern und die übrigen mit ausgeschaltetem Antialiasing. Nicht zuletzt können Sie mit dem Ein- und Ausschalten auch Rechenzeit sparen. Beispiel (Antialiasing) Dieses Beispiel zeigt zwei Dreiecke. Das linke Dreieck wurde mit Antialiasing gerendert. An der Diagonalen des Dreiecks kommen die Auswirkungen von Antialiasing besonders gut zur Wirkung. Leider haben wir festgestellt, dass weitaus weniger Grafikkarten diese feine Technik unterstützen. Einige Grafikkarten, welche Antialiasing anbieten, arbeiten offensichtlich mit einem minderwertigen Algorithmus. Dadurch sind die Auswirkungen von Antialisasing kaum wahrzunehmen. Aus diesem Grund haben wir uns entschlossen, dieses Beispielprogramm nicht im HAL oder RGB (Hardware- oder Software-Emulation) zu betrei-
250
Effekte
ben, sondern wählen den Referenz Rasterizer. Dieser Modus von Direct3D ist ein Testmodus. Für den praktischen Einsatz ist er allerdings ungeeignet. Zur Demonstration von Antialiasing ist er dennoch geeignet. Das Beispielprogramm beginnt mit der Form_Load()-Subroutine. Da wir den Referenz Rasterizer nutzen, haben sich die Initialisierungsroutinen InitDDraw() und InitD3D() geändert. In der InitDDraw() erstellen wir das DirectDraw-Objekt im Software-Emulations-Modus. Alle Surfaces werden nicht im Videospeicher der Grafikkarte, sondern im Systemspeicher erstellt. Beim Erstellen des D3D-Device wählen wir die Auswahl IID_IDirect 3DREFDevice. Somit ist der Referenz Rasterizer zugeordnet und alle Renderaufgaben laufen über ihn. Als Nächstes prüfen wir den Referenz Rasterizer auf seine Anitaliasing-Fähigkeiten. Dies übernimmt die AnitaliasingPrüfen() Subroutine. Public Sub AntialiasingPrüfen() Dim AntialiasingMode As D3DDEVICEDESC7 g_d3dDevice.GetCaps AntialiasingMode If (AntialiasingMode.dpcTriCaps.lRasterCaps And _ D3DPRASTERCAPS_ANTIALIASEDGES) = _ D3DPRASTERCAPS_ANTIALIASEDGES Then EdgeAntialiasing = "TRUE" Else EdgeAntialiasing = "FALSE" End If
Prüfung auf Kanten-Antialiasing. If (AntialiasingMode.dpcTriCaps.lRasterCaps And _ D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT) = _ D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT Then UnsortAntialiasing = "TRUE" Else UnsortAntialiasing = "FALSE" End If
Prüfung auf unsortiertes Fullscreen-Antialiasing. If (AntialiasingMode.dpcTriCaps.lRasterCaps And _ D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT) = _ D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT Then SortAntialiasing = "TRUE" Else SortAntialiasing = "FALSE" End If
Prüfung auf sortiertes Fullscreen-Antialiasing.
Kapitel 2 • Direct3D
251
End Sub
Je nachdem welche Prüfung erfolgreich ist, wird eine Infotext gespeichert. Dieser wird in der Do...Loop()-Schleife aus der Form_Load()-Subroutine auf dem Bildschirm angezeigt. Das eigentliche Aktivieren des Antialiasing Modes finden wir beim Rendern der Szene. g_d3dDevice.BeginScene g_d3dDevice.SetRenderState D3DRENDERSTATE_ANTIALIAS, _ D3DANTIALIAS_SORTINDEPENDENT g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, _ D3DFVF_VERTEX, Vertex(0), 3, D3DDP_WAIT
Das linke Dreieck wird mit eingeschaltetem Antialiasing gerendert. g_d3dDevice.SetRenderState D3DRENDERSTATE_ANTIALIAS, _ D3DANTIALIAS_NONE
Bevor wir das rechte Dreieck rendern, deaktivieren wir den Antialiasing Mode. g_d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, _ D3DFVF_VERTEX, Vertex(3), 3, D3DDP_WAIT g_d3dDevice.EndScene
Kapitel 3 DirectInput 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8
Objekthierarchie Cooperative Level Datenformat Beispiel: Tastatur Beispiel: Joystick Beispiel: Maus Beispiel: DirectInput und Direct3D Bewegung im 3D-Raum
254 257 258 260 262 268 272 279
254
Objekthierarchie
DirectInput (DI) ist eine API für Eingabegeräte. Durch die Bereitstellung allgemeiner Device Interfaces bietet DirectInput die Sicherheit, auch in der Zukunft auf eine Vielzahl von Geräten zugreifen zu können, deren technische Möglichkeiten heute noch nicht definiert sind. DirectInput unterscheidet drei Typen von I/OGeräten. •
Standard-System-Tastatur
•
Maus oder mausähnliche Geräte (Maus, Trackball, Touchpad ...)
•
Joysticks bzw alle übrigen Geräte (Joystick, Gamepad, Lenkräder...)
Die normale Windows API bietet eine Reihe von unterstüzenden Methoden zur Steuerung von I/O-Geräten, dennoch werden diese durch DirectInput ersetzt. Dies hat zum einen den Grund, dass mit DI eine freie (für die Zukunft offene) Schnittstelle geschaffen wurde, zum anderen wurde die Geschwindigkeit der bestehenden Technik problematisch. Der Grundkonzeption von DirectX entsprechend, wurde auch bei den Eingabegeräten Wert auf hohe Performance gelegt. Natürlich finden wir auch bei DI einen direkten Zugriff auf die Hardware. Dabei wird das übliche Nachrichtensystem von Windows ignoriert. Dies garantiert quasi eine schnelle Reaktionszeit. Das Verhalten von DirectInput ist vom Programmierer konfigurierbar. Je nach Einsatzzweck wird er unterschiedliche Konfigurationen festlegen.
3.1
Objekthierarchie •
DirectInput Interface Das DirectInput Interface stellt die erste Verbindung zum I/O Gerät her. Es dient zur Konfiguration und Initialisierung.
•
Devices Mit DirectInput Device werden die Ein- / Ausgabegeräte bezeichnet. Diese Objekte (Maus, Tastatur, Joystick...) bestehen aus verschiedenen Objekten.
•
Objekte Objekte sind die Bestandteile eines Devices. Objekte können Tasten, Knöpfe, Achsen, Drehräder ... sein.
•
Effekte Neben den Objekten existieren noch die Effekte. Effekte finden vor allem bei neueren Geräten Verwendung. Insbesondere sei der Force Feedback Joystick genannt.
Die verschiedenen Bestandteile der DirectInput Architekture erfassen im Regelfall Daten. Dabei ist es ohne Bedeutung, wie die Daten erfasst wurden. Ob eine Maus die Koordinaten mechanisch per Kugel und Zahnrad oder optisch an DirectInput weiterleitet spielt keine Rolle. Betrachten wir die Architektur an einem Beispiel, so würden wir eine einfache Maus folgendermaßen skizzieren.
Kapitel 3 • DirectInput
255
Bild 3.1:
Objekthierarchie
Device
→
Maus
Objekte
→
zwei Tasten zwei Achsen (X- und Y-Achse)
Effekte
→
keine
Auflisten der verfügbaren Geräte und Objekte Anhand eines Beispielprogramms werden wir demonstrieren, wie Sie Informationen über die angeschlossene Inputhardware sammeln. Diese Informationen bilden die Grundlage für alle späteren Aktionen. Anders als bei Direct3D oder DirectDraw können die Inputgeräte von DirectX nicht simuliert werden. Unser Beispielprogramm erkennt alle eingetragenen I/O-Geräte. Die Geräte müssen nicht angeschlossen sein, es reicht wenn die Geräte von Windows als I/OGeräte registriert wurden. So können Sie z.B. über die Systemsteuerung/Gamecontroller weitere Joysticks eintragen. Diese werden dann ebenfalls mit aufgelistet. Beginnen wir mit den Dimensionierungen. Dim Dim Dim Dim Dim
dx As New DirectX7 di As DirectInput diDEV As DirectInputDevice diEnumDev As DirectInputEnumDevices diEnumOBJ As DirectInputEnumDeviceObjects
Um auf die Geräteliste sowie auf die Objektliste zugreifen zu können, benötigen wir die Variablen vom Typ DirectInputEnumDevices und DirectInputEnum DeviceObjects. Diese werden die gewünschten Informationen beinhalten. Wir beginnen mit der Form_Load()-Subroutine.
256
Objekthierarchie
Bild 3.2:
Geräteliste
Private Sub Form_Load() Set di = dx.DirectInputCreate()
Zuerst benötigen wir das DirectInput-Objekt. Dieses erzeugen wir mit der DirectX7.DirectInputCreate() Methode. Diese Methode besitzt keine Parameter. Set diEnumDev = di.GetDIEnumDevices(0 , DIEDFL_INCLUDEPHANTOMS)
Mit der DirectInput.GetDiEnumDevices() Methode weisen wir das DirectInput EnumDevices Objekt zu. Der erste Parameter ist vom Typ CONST_DIDEVICE TYPE, der zweite Parameter ist ein Flag aus der CONST_DIENUMDEVICES FLAGS Konstantenliste. Indem wir den ersten Parameter einfach auf 0 setzten, werden uns später alle Geräte (Maus, Tastatur, Joystick ...) aufgelistet werden. Das Flag DIEDFL_INCLUDEPHANTOMS des zweiten Parameters sorgt dafür, dass auch die Geräte aufglistet werden, welche zurzeit nicht angeschlossen sind.
Kapitel 3 • DirectInput
257
DeviceCount = diEnumDev.GetCount() For i = 1 To DeviceCount Set diDEV = _ di.CreateDevice(diEnumDev.GetItem(i).GetGuidInstance) Combo1.AddItem (diEnumDev.GetItem(i).GetProductName)
Der Reihe nach werden alle gefundenen Geräte mit der DirectInput.Create Device()-Methode erzeugt und die Namen der Geräte ausgelesen. Next i Combo1.Text = Combo1.List(0) Listen 1 End Sub
Mit der Subroutine Listen() aktualisieren wir die Listboxen auf Form1. Wiederum zusätzlich zu dem Device erzeugen wir noch das DirectInput-Objekt. In diesem Objekt finden wir Informationen über das Gerät selber. Diese übertragen wir an die jeweiligen Listboxen. Public Sub Listen(Index As Integer) List1.Clear List2.Clear Set diDEV = _ di.CreateDevice(diEnumDev.GetItem(Index).GetGuidInstance) DeviceCount = diEnumDev.GetCount() List1.AddItem "ProductName :" & _ (diEnumDev.GetItem(Index).GetProductName) List1.AddItem "InstanceName :" & _ (diEnumDev.GetItem(Index).GetInstanceName) List1.AddItem "GuidInstance :" & _ (diEnumDev.GetItem(Index).GetGuidInstance) List1.AddItem "GuidProduct :" & _ (diEnumDev.GetItem(Index).GetGuidProduct) Set diEnumOBJ = diDEV.GetDeviceObjectsEnum(DIDFT_ALL) ObjectCount = diEnumOBJ.GetCount() For u = 1 To ObjectCount List2.AddItem (diEnumOBJ.GetItem(u).GetName) Next u End Sub
3.2
Cooperative Level Der Cooperative Level bestimmt, wie ein Gerät mit anderen Anwendungen oder dem Windowssystem geteilt wird. Für den Zugriff auf einzelnen I/O-Geräte stehen eine gewisse Zahl von Cooperative Levels zur Wahl. Die korrekte Festlegung des Cooperative Levels kann einige Probleme beim Umgang mit DirectX-Anwendungen in Windows vermeiden helfen.
258
Datenformat
Werden z.B. die I/O-Geräte nur abgefragt, wenn sich die Anwendung im Vordergrund befindet, kann es passieren (falls die Anwendung den Fokus verliert), dass eine gestartete Aktion beim Loslassen einer Taste nicht beendet wird. Die möglichen Cooperative Levels sind: Cooperativ Level
Kurzbeschreibung
DISCL_NONEXCLUSIVE
Die Anwendung erhält den Zugriff auf das Gerät nicht exklusiv (zwingend für die Tastatur).
DISCL_EXCLUSIVE
Andere Anwendungen können nicht exklusiv auf das Gerät zugreifen (zwingend für Force Feedback).
DISCL_FORDERGROUND
Die Anwendung erhält nur Daten, wenn sie sich im Vordergrund befindet.
DISCL_BACKGROUND
Die Anwendung erhält Daten im Vordergund und Hintergrund.
Die folgende Tabelle gibt an, welche Kombinationen für welche I/O-Geräte zulässig sind. Cooperative Level
Kurzbeschreibung
DISCL_NONEXCLUSIVE DISCL_BACKGROUND
alle Geräte ohne Force Feedback → Default
DISCL_NONEXCLUSIVE DISCL_FORDERGROUND
alle Geräte ohne Force Feedback
DISCL_EXCLUSIVE DISCL_FORDERGROUND
alle außer Tastatur
DISCL_EXCLUSIVE DISCL_BACKGROUND
Joysticks sowie Geräte mit Force Feedback → nicht zulässig für Tastatur und Maus
Wenn eine Anwendung den exklusiven Zugriff auf die Tastatur erhält, unterdrückt DirectInput alle Tastaturnachrichten außer [Strg]+[Alt]+[Del] sowie [Alt)+ [ÿ].
3.3
Datenformat Um gegenüber neuen Entwicklungen offen zu sein, bietet DirectInput eine sehr allgemeine Möglichkeit um auf die Hardware zuzugreifen. So existieren weitreichende Möglichkeiten zur Erstellung selbstdefinierter Datenformate. Für die normalen I/O-Geräte existieren bereits vordefinierte Datenformate. Diese können Sie der folgenden Tabelle entnehmen.
Kapitel 3 • DirectInput
259
Datenformat
Beschreibung
DIFORMAT_KEYBOARD
Tastatur: Für jede Taste ein Byte. Wird eine Taste momentan gedrückt, so ist das oberste Bit des entsprechenden Bytes gesetzt.
DIFORMAT_MOUSE
Maus: vier Tasten, drei Achsen
DIFORMAT_JOYSTICK
Joystick: <= 32 Knöpfe, <= 6 Achsen, <= 2 Schieberegler, <= 4 Richtungsschalter
DIFORMAT_JOYSTICK2
Datenformat für erweiterte Joysticks
Die DirectInputDevice.SetCommonDataFormat()- und DirectInputDevice.SetDateFormat()-Methoden teilen DirectInput mit, welche Objekte benutzt und wie die Daten empfangen werden.
3.3.1
Standard-Datenformat Mit der DirectInputDevice.SetCommonDataFormat()-Methode können wir die Standard Datenformate festlegen. Die Methode beinhaltet nur einen Parameter. Der Parameter format ist vom Typ CONST_DICOMMONDATAFORMATS. Enum CONST_DICOMMONDATAFORMATS DIFORMAT_JOYSTICK DIFORMAT_JOYSTICK2 DIFORMAT_KEYBOARD DIFORMAT_MOUSE End Enum
= = = =
3 4 1 2
Um das Datenformat z.B. für die Tastatur zu setzen, wählen Sie folgende Syntax: DirectInputDevice.SetCommonDataFormat DIFORMAT_KEYBOARD
Bevor Sie auf ein Gerät zugreifen können, muss das Datenformat festgelegt werden. Während Sie auf das Gerät zugreifen, können Sie das Datenformat nicht ändern.
3.3.2
Benutzerdefiniertes Datenformat Mit der DirectInputDevice.SetDataFormat()-Methode können Sie ein benutzerdefiniertes Datenformat festlegen. Diese Methode beinhaltet zwei Parameter. Der erste Parameter format empfängt Daten über des Gerät selber. Der zweite Parameter formatArray() ist für die Objekte des Gerätes reserviert. Bevor wir die Methode aufrufen dürfen, müssen wir die Eigenschaften für die beiden Parameter bestimmen. Das folgende Listing definiert das Datenformat für eine Maus mit zwei Achsen, allerdings ohne Knöpfe.
260
Beispiel: Tastatur
Dim dx As New DirectX7 Dim di As DirectInput Dim diDev As DirectInputDevice Dim DataFormat As DIDATAFORMAT Dim ObjektFormat(1) As DIOBJECTDATAFORMAT Private Sub Form_Load() Set di = dx.DirectInputCreate() Set did = di.CreateDevice("GUID_SysMouse") ObjektFormat (0).lFlags = DIDOI_POLLED ObjektFormat (0).lOfs = 0 ObjektFormat (0).lType = DIDFT_RELAXIS ObjektFormat (0).strGuid = "GUID_XAxis" ObjektFormat (1).lFlags = DIDOI_POLLED ObjektFormat (1).lOfs = 4 ObjektFormat (1).lType = DIDFT_RELAXIS ObjektFormat (1).strGuid = "GUID_YAxis" DataFormat.dataSize = 8 DataFormat.lFlags = DIDF_RELAXIS DataFormat.lObjSize = 4 DataFormat.numObjs = 2 diDev.SetDataFormat DataFormat, fDA() End Sub
3.4
Beispiel: Tastatur Für die Eingabe über die Tastatur erstellen wir zuerst das DirectInput-Objekt. Anschließend wird das DirectInput-Device erstellt, welches die Tastatur repräsentiert. Es bestimmt das Verhalten der Tastatur und empfängt die Daten, welche von der Tastatur gesendet werden. Unser Beispielprogramm zeigt eine Listbox. In dieser werden die gedrückten Tasten angezeigt. Schritt 1: Erstellen des DirectInput-Objektes und des Tastaturgerätes Schritt 2: Tastaturparameter setzen Schritt 3: Verbindung zur Tastatur herstellen Schritt 4: Daten von der Tastatur empfangen Für unser Beispielprogramm dimensionieren wir folgende Variablen. Dim dx As New DirectX7 Dim di As DirectInput Dim diDev As DirectInputDevice Dim TastaturStatus As DIKEYBOARDSTATE Dim Tasten(255) As String Private Sub Form_Load()
Kapitel 3 • DirectInput
Bild 3.3:
261
Bildschirmfoto Tastatur
Schritt 1: Erstellen des DirectInput-Objektes und des Tastaturgerätes Set di = dx.DirectInputCreate() Set diDev = di.CreateDevice("GUID_SysKeyboard")
Schritt 2: Tastaturparameter setzen Für das Standardgerät Tastatur können wir auf ein vordefiniertes Datenformat zugreifen. Deshalb benutzen wir die SetCommonDataFormat()-Methode mit dem Parameter DIFORMAT_KEYBOARD. Für Cooperative Level brauchen wir keinen exklusiven Zugriff (ist für die Tastatur auch nicht erlaubt), aber gleichzeitig möchten wir die Tastaturdaten empfangen, auch wenn die Anwendung den Focus verliert. diDev.SetCommonDataFormat DIFORMAT_KEYBOARD diDev.SetCooperativeLevel Me.hWnd, DISCL_NONEXCLUSIVE Or _ DISCL_BACKGROUND
Schritt 3: Verbindung zur Tastatur herstellen Die Methode Acquire() besitzt keine Parameter und erstellt die Verbindung zum Eingabegerät. Zu welchem Eingabegerät die Verbindung hergestellt werden soll, wird durch die DirectInput.CreateDevice()-Methode festgelegt. diDev.Acquire Timer1.Enabled = True End Sub
262
Beispiel: Joystick
Schritt 4: Daten von der Tastatur empfangen Über das Timerobjekt fragen wir die Tastaturdaten ab. Die DirectInput.Get DeviceStateKeyboard()-Methode empfängt unverzüglich die gewünschten Daten. Private Sub Timer1_Timer() List1.Clear diDev.GetDeviceStateKeyboard TastaturStatus For i = 0 To 255 If TastaturStatus.Key(i) <> 0 Then List1.AddItem KeyNames(i)
Die Funktion KeyNames() interpertiert den in TastaturStatus.Key() gespeicherten Rückgabewert. So erhalten wir eine aussagefähige Information auf dem Bildschirm angezeigt. End If Next End Sub
Interpretation der empfangenen Tastaturdaten: Function KeyNames(ByVal iNum As Integer) As String Tasten(1) = "DIK_ESCAPE" Tasten(2) = "DIK_1 On main keyboard" Tasten(3) = "DIK_2 On main keyboard" . . . Tasten(220) = "DIK_RWIN Right Windows key" Tasten(221) = "DIK_APPS Application key" Tasten(116) = "DIK_PAUSE" KeyNames = Tasten(iNum) End Function
3.5
Beispiel: Joystick Bei dem Joystickdemo werden wir zuerst die angeschlossenen Joysticks abfragen. Anschließend werden die Joystickfähigkeiten ermittelt und die notwendigen Parameter gesetzt. Zum Abschluss werden die Joystickdaten empfangen. Bei dem Tastaturdemo konnten wir voraussetzen, dass eine Tastatur am Computer angeschlossen ist. Die Annahme, das ein Joystick angeschlossen ist, können wir nicht treffen. Es ist deshalb notwendig abzufragen, welcher Joystick zur Zeit verfügbar ist. Gleichzeitig ist es wichtig, dass wir genaue Informationen über die Fähigkeiten des Eingabegerätes erhalten. Zu diesem Zeitpunkt wäre es verfrüht, wenn wir auf die vielfältigen Möglichkeiten des Force Feedback Joysticks eingehen würden, deshalb werden wir diese etwas vernachlässigen.
Kapitel 3 • DirectInput
Bild 3.4:
263
Bildschirmfoto Joystick
Die Abfrage der Joystickdaten gestaltet sich komplizierter als bei dem Tastaturdemo. Die eintreffenden Daten per Timer-Objekt abzufragen wäre viel zu langsam. Der übliche Weg zum Empfangen von Joystickdaten ist es, eine CallbackFunktion einzurichten. Diese wird immer dann aufgerufen wenn neue Daten eintreffen. Der Joystick liefert allerdings permanent Daten. Schritt 1: Auflisten der verfügbaren Joysticks und Erzeugen des Joystick-Objektes Schritt 2: Abfragen der Joystickfähigkeiten Schritt 3: Setzen der Joystickeigenschaften Schritt 4: Direktes Empfangen der Joystickdaten per Callback-Funktion Für unser Beispielprogramm dimensionieren wir folgende Variablen: Implements DirectXEvent
Da wir die Joystickdaten per Callback abrufen wollen, treffen wir mit der Implements-Anweisung die Vorbereitung. DirectXEvent ist eine eigene Klasse. Sie beinhaltet nur eine Methode: DirectXEvent.DXCallback() Dim Dim Dim Dim Dim Dim Dim Dim
dx As New DirectX7 di As DirectInput diDev As DirectInputDevice diDevEnum As DirectInputEnumDevices EventHandle As Long joyCaps As DIDEVCAPS js As DIJOYSTATE Achsen(8) As Boolean
264
Beispiel: Joystick
Dim Dim Dim Dim Dim Dim Dim
Knöpfe(32) As Boolean Pov(4) As Boolean JoyGuid(16) As String Fd As DIDATAFORMAT fda(1) As DIOBJECTDATAFORMAT Running As Boolean JoyAngeschlossen As Boolean
Schritt 1: Auflisten der verfügbaren Joysticks und Erzeugen des JoystickObjektes Mit diesem Beispielprogramm führen wir die Subroutine InitDirectInput() ein. Sie wird jetzt und in Zukunft die Initialisierungsaufgaben übernehmen. Gleichzeitig werden wir dieser Routine diverse Prüfungsaufgen anvertrauen. In dem jetzigem Beispielprogramm prüfen wir das System auf alle registrierten Joysticks. Wird ein gültiger Joystick gefunden, so können wir das notwendige Gerät erstellen. Wir aber kein Joystick gefunden, so beenden wir das Programm. Das Ergebnis der Prüfung übergeben wir an die Combobox1 auf Form1 unserer Anwendung. Sub InitDirectInput() Set di = dx.DirectInputCreate() Set diDevEnum = di.GetDIEnumDevices(DIDEVTYPE_JOYSTICK, _ DIEDFL_INCLUDEPHANTOMS)
Die DirectInput.GetDIEnumDevices()-Methode füllt das Typen-Arrays diDev Enum. Die Parameter der DirectInput.GetDIEnumDevices()-Methode bestimmen, dass wir Informationen über Joysticks erhalten möchten. Die Konstante DIEDFL_INCLUDEPHANTOMS im zweiten Parameter informiert DirectInput, dass Informationen über alle vom System registrierten Joysticks gewünscht sind. Es wird nicht unterschieden, ob der Joystick angeschlossen ist oder nicht. If diDevEnum.GetCount = 0 Then MsgBox "Es wurde kein Joystick gefunden." Unload Me End If
Die Prüfung, ob überhaupt ein Joystick verfügbar ist, können wir mit DirectInput EnumDevices.GetCount()-Methode durchführen. Liefert diese Methode eine 0 zurück, so wissen wir, das kein Joystick angeschlossen ist. Ansonsten wird die Methode die Anzahl der angeschlossenen Joysticks bekannt geben. Dim i As Integer For i = 1 To diDevEnum.GetCount Combo1.AddItem diDevEnum.GetItem(i).GetInstanceName JoyGuid(i) = diDevEnum.GetItem(i).GetGuidInstance Next i
Kapitel 3 • DirectInput
265
Nacheinander lassen wir alle Joystickbezeichnungen in die Combobox eintragen. Zusätzlich merken wir uns den Guid der gefundenen Joysticks, dieser wird beim Erstellen des Gerätes benötigt. Über diese Box können wir dann einen der gelisteten Joysticks wählen und testen. EventHandle = dx.CreateEvent(Me)
Die DirectX7.CreateEvent() liefert das Handle des Event-Objektes, welches in der Form eingebunden ist. Für den vollautomatischen Callback ist das Handle unverzichtbar. End Sub
Schritt 2: Abfragen der Joystickfähigkeiten Wenn das Combo1_Click()-Ereignis ausgelöst wird, ermitteln wir die Fähigkeiten des selektierten Joysticks. Ebenso ermitten wir, ob der selektierte Joystick mit dem Computer verbunden ist. Set diDevEnum = di.GetDIEnumDevices(DIDEVTYPE_JOYSTICK, _ DIEDFL_ATTACHEDONLY) For EunmCount = 1 To diDevEnum.GetCount If JoyGuid(Index + 1) = _ diDevEnum.GetItem(EunmCount).GetGuidInstance Then Label3 = "Joystick ist mit dem Computer verbunden" Else Label3 = _ "Joystick ist --> N I C H T <-- mit dem Computer verbunden" End If Next EunmCount If diDevEnum.GetCount = 0 Then Label3 = "Joystick ist _ --> N I C H T <-- mit dem Computer verbunden"
Entsprechend der Prüfung ob der gewählte Joystick mit dem System verbunden ist, verändern wir den Infotext von Label3. Nur von den angeschlossenen Joysticks werden wir später die Daten empfangen und auf dem Bildschirm anzeigen. Die eigentliche Prüfung der Joystickfähigkeiten übernimmt die CheckCaps()Subroutine. Diese haben wir in drei Abschnitte unterteilt. Für die Abfrage der Achsen, Knöpfe und Coolie Steuerungen (Richtungsschalter) nutzen wir die DirectInputDevice.GetDeviceObjectsEnum()-Methode. Sie verlangt den Parameter flags As CONST_DIDFTFLAGS. Er bestimmt welche Fähigkeit des Joysticks abgefragt werden soll. Set didoEnum = diDev.GetDeviceObjectsEnum(DIDFT_AXIS)
Mit der For...Next-Schleife überprüfen wir die gefundnen Joystickfähigkeiten. Zum Vergleich stellt uns DirectInput die CONST_DIJOYSTICKOFS-Konstantenliste zur Verfügung.
266
Beispiel: Joystick
For i = 1 To didoEnum.GetCount Set dido = didoEnum.GetItem(i) Select Case dido.GetOfs Case DIJOFS_X Achsen(1) = True Case DIJOFS_Y Achsen(2) = True Case DIJOFS_Z Achsen(3) = True Case DIJOFS_RY Achsen(4) = True Case DIJOFS_RX Achsen(5) = True Case DIJOFS_RY Achsen(6) = True Case DIJOFS_SLIDER0 Achsen(7) = True Case DIJOFS_SLIDER1 Achsen(8) = True End Select Next
In unserm Beispiel übertragen eine eine positive Prüfung der möglichen Achsen in das Array Achsen(). Die Auswertung für die Bildschirmanzeige ist gänzlich unkompliziert und muss nicht erläutert werden. For i = 1 To 8 If Achsen(i) = True Then Check1(i – 1).Value = 1 Check1(i – 1).Enabled = True Text1(i – 1).Visible = True Else Check1(i – 1).Value = 0 Check1(i – 1).Enabled = False Text1(i – 1).Visible = False End If Next i
Schritt 3: Setzen der Joystickeigenschaften Unterschiedliche Joysticks liefern unterschiedliche Wertebereiche bei der Achsenabfrage. Da Sie als Programmierer nicht wissen können, welchen Joystick der Anwender einmal nutzen wird, legen wir den gültigen Wertebereich einfach fest. Die Joystick werden die selbstdefinierten Grenzen beachten, sodass wir eine einheitliche Interpretation der empfangenen Daten erstellen können. Bevor wir uns um die Interpretation kümmern, setzen wir nun die Joystickeigenschaften. Hierzu nutzen wir die SetProperties()-Subroutine.
Kapitel 3 • DirectInput
267
Public Sub SetProperties() Dim DiProp_Range As DIPROPRANGE With DiProp_Range .lHow = DIPH_DEVICE
Da wir den Wertebereich für alle Achsen begrenzen möchten, wählen wir die Einstellung DIPH_DEVICE. .lSize = Len(DiProp_Range) .lMin = 0 .lMax = 10000
Durch die Parameter lMin und lMax wird der Wertebereich der Achsen begrenzt. Diese Berenzung wirkt sich auf alle Joysticks aus. Programmtechnisch ist solch eine Einschränkung von Nutzen, denn dadurch wird es möglich, über eine einheitliche Routine die Daten unterschiedliche Joysticks auszuwerten. Ohne solch eine Einschränkung müsste man für verschieden Joysticks auch unterschiedliche Auswertungen erstellen. End With diDev.SetProperty "DIPROP_RANGE", DiProp_Range
Die folgenden Geräteeigenschaften definieren die Deadzone. Die Deadzone ist ein Wertebereich in dem der Joystick nicht reagieren soll. Die Mitte des Wertebereichs ist die Nullstellung (wenn Sie den Joystick nicht bewegen). Dim DiProp_Dead As DIPROPLONG With DiProp_Dead .lData = 1000
Die Deadzone wird in unserem Beispiel mit 1000 (10% der Maximalwerte) festgelegt. Setzen Sie diesen Wert doch mal auf 1, Sie werden beobachten, dass die Daten des Joysticks immer etwas schwanken, obwohl er sich in Nullstellung befindet. .lSize = Len(DiProp_Dead) .lHow = DIPH_BYOFFSET .lObj = DIJOFS_X diDev.SetProperty "DIPROP_DEADZONE", DiProp_Dead
Zuerst legen wir die Deadzone für die X Achse fest. Anschließend folgt die Definition für die Y Achse. .lObj = DIJOFS_Y diDev.SetProperty "DIPROP_DEADZONE", DiProp_Dead End With End Sub
268
Beispiel: Maus
Schritt 4: Direktes Empfangen der Joystickdaten per Callback-Funktion Die Joystickdaten werden über die DirectXEvent_DXCallback()-Subroutine empfangen. Bevor wir an die Daten gelangen, müssen wir das Gerät erstellen, das Datenformat festlegen, den Cooperativ Level festlegen, die Callbackbenachrichtigung einschalten und die Verbindung zu dem Gerät schaffen. Dies wird von uns im letzten Abschnitt der Combo1_Click()-Subroutine erledigt. Private Sub Combo1_Click() . . . Set diDev = di.CreateDevice(JoyGuid(Index + 1)) diDev.SetCommonDataFormat DIFORMAT_JOYSTICK diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or _ DISCL_NONEXCLUSIVE Call diDev.SetEventNotification(EventHandle) SetProperties diDev.Acquire Do While Running = True diDev.Poll
Die DirectInputDevice.Poll()-Methode stellt die Joystickdaten zur Verfügung. Der Joystick wird ohne Unterbrechung Daten senden, deshalb wird auch unterbrechungsfrei die Callback-Routine aufgerufen. DoEvents Loop
3.6
Beispiel: Maus Der Zugriff auf die Systemmaus als Eingabegerät ist vergleichbar mit der eingesetzten Joysticktechnik. In unserem Beispiel gehen wir davon aus, dass nur eine Maus angeschlossen ist. Es entfällt somit die Auflistung der verfügbaren Eingabegeräte und wir konzentrieren uns aus die Systemmaus. Je nachdem welche Maus der Anwender angeschlossen hat, besitzt die Maus unterschiedliche Fähigkeiten. DirectInput unterstützt folgende Objekte: •
3 Achsen (X-Achse, Y-Achse und Z-Achse)
•
4 Knöpfe
Per Callback-Funktion fragen wir die Joystickdaten ab. Im Gegensatz zum Joystick sendet die Maus nicht permanent Daten, sondern nur dann, wenn Sie die Maus bewegen oder eine Taste drücken.
Kapitel 3 • DirectInput
Bild 3.5:
269
Bildschirmfoto Maus
Schritt 1: Erzeugen des Maus-Objektes Schritt 2: Abfragen der Mausfähigkeiten Schritt 3: Setzen der Mauseigenschaften Schritt 4: Direktes Empfangen der Mausdaten per Callback-Funktion Neben den benötigten DirectInput-Methoden müssen wir noch einige API-Funktionen deklarieren. Diese sind für die Abfrage der Mausinformationen nicht notwendig, werden aber für eine ordentliche Auswertung benötigt. In einer DirectXAnwendung, in der Sie nicht unmittelbar mit der Windowsoberfläche arbeiten, können Sie auf diese getrost verzichten. Implements DirectXEvent Private Declare Function GetCursorPos Lib "user32" _ (lpPoint As POINTAPI) As Long Private Declare Function SetCursorPos Lib "user32" _ (ByVal X As Long, ByVal Y As Long) As Long Private Declare Function ScreenToClient Lib "user32" _ (ByVal hWnd As Long, lpPoint As POINTAPI) As Long Private Type POINTAPI X As Long Y As Long End Type Dim dx As New DirectX7 Dim di As DirectInput Dim diDev As DirectInputDevice Dim diDevEnum As DirectInputEnumDevices Dim Achsen(8) As Boolean
270
Beispiel: Maus
Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim
Knöpfe(32) As Boolean EventHandle As Long MausCaps As DIDEVCAPS js As DIMOUSESTATE Running As Boolean JoyAngeschlossen As Boolean MouseX As Long MouseY As Long CursorPos As POINTAPI ClientWindowsLeft As Long ClientWindowsTop As Long ZeichenModus As Boolean Speed As Long
Schritt 1: Erzeugen des Maus-Objektes Sub InitDirectInput() Set di = dx.DirectInputCreate() Set diDevEnum = di.GetDIEnumDevices(DIDEVTYPE_MOUSE, _ DIEDFL_ATTACHEDONLY) If diDevEnum.GetCount = 0 Then MsgBox "Es wurde kein Mouse gefunden." End End If
Sollte keine Maus gefunden werden, so beenden wir das Programm. Diesmal ist es nur notwendig, das System auf angeschlossene Geräte zu prüfen. Von den angeschlossenen Geräten interessiert uns auch nur die Maus. Für den ersten Parameter der DirectInput.GetDIEnumDevices()-Methode wählen wir DIDEVTYPE_ MOUSE. Dieser besagt, das wir nur nach einem Gerät vom Typ Maus suchen. Der zweite Parameter DIEDFL_ATTACHEDONLY besagt, dass wir nur angeschlossene Geräte suchen. EventHandle = dx.CreateEvent(Me) Set diDev = di.CreateDevice("guid_SysMouse")
Nachdem eine Maus gefunden wurde, können wir das Gerät erstellen. Zum Erstellen einer Systemmaus verwenden wir die Konstante guid_SysMouse. CheckCaps
Die Prüfung der Mausfähigkeiten übernimmt die CheckCaps()-Subroutine. Diese betrachten wir im Anschluss. diDev.SetCommonDataFormat DIFORMAT_MOUSE diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or ISCL_NONEXCLUSIVE Call diDev.SetEventNotification(EventHandle) SetProperties
Kapitel 3 • DirectInput
271
Nachdem wir das Gerät erstellt haben und bevor wir die Verbindung zum Gerät herstellen, können wir die Eigenschaften des Geräts festlegen. Dies übernimmt die SetProperties()-Subroutine. diDev.Acquire Running = True Do While Running = True DoEvents Loop End Sub
Schritt 2: Abfragen der Mausfähigkeiten Public Sub CheckCaps() diDev.GetCapabilities MausCaps
Wir übergeben die Mausfähigkeiten an MausCaps As DIDEVCAPS. Aus MausCaps benötigen wir eigentlich nur die Anzahl der Mausknöpfe. Programmtechnisch können Sie das auch anders lösen, dies würde aber der DirectX Philosophie etwas widersprechen. Dim didoEnum As DirectInputEnumDeviceObjects Dim dido As DirectInputDeviceObjectInstance . . .
Prüfung der Achsen. Set didoEnum = diDev.GetDeviceObjectsEnum(DIDFT_AXIS) For i = 1 To didoEnum.GetCount Set dido = didoEnum.GetItem(i) Select Case dido.GetOfs Case DIMOFS_X Achsen(1) = True Case DIMOFS_Y Achsen(2) = True Case DIMOFS_Z Achsen(3) = True End Select Next
Prüfung der Knöpfe. Set didoEnum = diDev.GetDeviceObjectsEnum(DIDFT_BUTTON) For i = 1 To didoEnum.GetCount Set dido = didoEnum.GetItem(i) a = dido.GetOfs Select Case dido.GetOfs
272
Beispiel: DirectInput und Direct3D
Case DIMOFS_BUTTON0 Knöpfe(1) = True Case DIMOFS_BUTTON1 Knöpfe(2) = True Case DIMOFS_BUTTON2 Knöpfe(3) = True Case DIMOFS_BUTTON3 Knöpfe(4) = True End Select Next . . . End Sub
Schritt 3: Setzen der Mauseigenschaften Public Sub SetProperties() Dim DiProp_Range As DIPROPRANGE Dim diProp As DIPROPLONG diProp.lHow = DIPH_DEVICE diProp.lData = DIPROPAXISMODE_REL
Die Konstante DIPROPAXISMODE_REL besagt, dass die von der Maus gesendeten Daten relative Daten sind. Dem Programmierer werden nur die Änderungen von einer Abfrage zur darauf folgenden Abfrage mitgeteilt. Sie können auch die Konstante DIPROPAXISMODE_ABS verwenden, dann erhalten Sie absolute Werte. In unserem Beispiel sind relative Daten besser auszuwerten. diProp.lSize = Len(diProp) Call diDev.SetProperty("DIPROP_AXISMODE", diProp) End Sub
3.7
Beispiel: DirectInput und Direct3D Mit diesem Beispielprogramm demonstrieren wir die Integration von DirectInput in einer Direct3D-Anwendung. Nach dem Starten des Programms erhalten Sie ein Auswahlfenster. Hier können Sie zwischen einer Steuerung per Tastatur oder per Joystick wählen. Es werden Ihnen nur Joysticks, welche mit dem System verbunden sind, angezeigt. Benutzen Sie einen analogen Joystick, so wird die Laufgeschwindigkeit entsprechend der Joystickintensität angepasst. Zusätzlich haben wir eine einfache Technik einer Kollisionserkennung eingebunden. Die Tastatur wir diesmal per Callback abgefragt. In unserem ersten Beispiel wurde die Abfrage noch per Timerobjekt ausgeführt. Diese Lösung wäre für dieses Beispiel nicht so geeignet. Da wir für den Joystick eine Callback-Funktion einrichten, bietet es sich an, die Tastaturabfrage in der gleichen Subroutine durchzuführen.
Kapitel 3 • DirectInput
Bild 3.6:
273
Bildschirmfoto Bewegung
Zuerst betrachten wir das Auswahlfenster für die verfügbaren Eingabegeräte. Bevor wir ein Eingabegerät auswählen können, müssen die verfügbaren Geräte angezeigt werden. Wir gehen davon aus, dass eine Tastatur immer angeschlossen ist, sodass wir diese nicht testen und auflisten müssen. Für die Auswahl eines Joysticks sieht das ganz anders aus. Private Sub Form_Load() Set di = dx.DirectInputCreate() Set diEnumDev = di.GetDIEnumDevices(DIDEVTYPE_JOYSTICK, _ DIEDFL_ATTACHEDONLY) devicecount = diEnumDev.GetCount() . . . For i = 1 To devicecount Set diDev = _ di.CreateDevice(diEnumDev.GetItem(i).GetGuidInstance) Combo1.AddItem (diEnumDev.GetItem(i).GetProductName)
274
Beispiel: DirectInput und Direct3D
Bild 3.7:
Bildschirmfoto Bewegung (Login)
Alle angeschlossenen Joysticks werden in die Comb1-Combobox eingetragen. Diese Prozedur ist Ihnen bereits bekannt und kann im Beispielprogramm »Auflisten der verfügbaren Geräte und Objekte« nachgelesen werden. Next i Combo1.Text = Combo1.List(0) Listen 1
Die Subroutine Listen() zeigt die Joystickfähigkeiten an. Auch diese ist Ihnen bekannt und wird jetzt nicht näher erklärt. End Sub
Nachdem Sie das Eingabegerät gewählt haben, klicken Sie auf die Schaltfläche Weiter. Private Sub Command1_Click() If Label5 = "N/A" Or Label6 = "N/A" Then MsgBox "Sie haben _ keine Eingabegerät gewählt!": Exit Sub
Sollten Sie kein Eingabegerät gewählt haben, verlassen wir die Subroutine direkt.
Kapitel 3 • DirectInput
275
InputName = Label5 InputGuid = Label6
Die Variablen InputName und InputGuid nutzen wir, um später das Eingabegerät zu erzeugen. InputName dient hauptsächlich dazu, um die beiden Eingabegeräte (Tastatur oder Joystick) zu unterscheiden. Unload Me Load Form1 End Sub
Weiter geht es mit der Subroutine Form_Load() von Form1. Private Sub Form_Load() InitDDraw InitD3D InitInput Licht RenderState MakeVertex . . . End Sub
Die Subroutine InitInput() richtet das Eingabegerät ein. Bevor wir auf weitere Elemente der Form_Load()-Subroutine eingehen, schauen wir uns die InitInput()-Subroutine genauer an. Public Sub InitInput() Select Case Form2.InputName Case "Tastatur" Set di = g_dx.DirectInputCreate() EventHandle = g_dx.CreateEvent(Me) Set diDev = di.CreateDevice("GUID_SysKeyboard")
Beim Einrichten der Tastatur sind wir auf eine individuelle Guid nicht angewiesen. Wir können die feste Kennung GUID_SysKeyboard verwenden. diDev.SetCommonDataFormat DIFORMAT_KEYBOARD diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or _ DISCL_NONEXCLUSIVE Call diDev.SetEventNotification(EventHandle) diDev.Acquire Case Else Set di = g_dx.DirectInputCreate() EventHandle = g_dx.CreateEvent(Me) Set diDev = di.CreateDevice(Form2.InputGuid)
276
Beispiel: DirectInput und Direct3D
Für das Erzeugen des Joysticks benötigen wir eine individuelle Guid. Diese wurde bei der Joystickauswahl ermittelt und in der Variablen InputGuid gespeichert. diDev.SetCommonDataFormat DIFORMAT_JOYSTICK diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or _ DISCL_NONEXCLUSIVE Call diDev.SetEventNotification(EventHandle) SetProperties diDev.Acquire End Select End Sub
Um die Eingabedaten zu empfangen, haben wir uns bei beiden Eingabemöglichkeiten für eine Callback-Funktion entschieden. Private Sub DirectXEvent_DXCallback(ByVal eventid As Long) On Local Error Resume Next If InputFrei = False Then Exit Sub InputFrei = False If diDev Is Nothing Then Exit Sub If Form2.InputName <> "Tastatur" Then diDev.GetDeviceStateJoystick js SpeedY = (5000 – js.y) / 5000 SpeedX = ((5000 – js.x) / 500) * -1
Als wir den Joystick erzeugt haben, wurden auch die Joystickeigenschaften neu definiert. Die Subroutine SetProperties() beschränkt den Wertebereich der Joystickachsen auf 0 bis 10000. Die Mittelstellung liegt also bei 5000. Wir werden also von allen Joysticks Daten in einem gemeinsamen Wertebereich erhalten, somit sind wir in der Lage, die Daten programmtechnisch auszuwerten. Die Daten übergeben wir an die globalen Variablen SpeedY und SpeedX. Else diDev.GetDeviceStateKeyboard If ks.Key(200) And OldButton SpeedY = 0.3 OldButton = 200 End If If ks.Key(208) And OldButton SpeedY = -0.3 OldButton = 208 End If If ks.Key(203) And OldButton SpeedX = -4 OldButton = 203 End If If ks.Key(205) And OldButton
ks <> 200 Then
<> 208 Then
<> 203 Then
<> 205 Then
Kapitel 3 • DirectInput
SpeedX = 4 OldButton = 205 End If If ks.Key(200) = 0 And ks.Key(208) = 0 SpeedY = 0 OldButton = 0 End If If ks.Key(203) = 0 And ks.Key(205) = 0 SpeedX = 0 OldButton = 0 End If If ks.Key(200) <> 0 And ks.Key(208) <> SpeedY = 0 OldButton = 0 End If If ks.Key(203) <> 0 And ks.Key(205) <> SpeedX = 0 OldButton = 0 End If
277
Then
Then
0 Then
0 Then
Für die Datenauswertung der Tastatur mussten wir die Tastatureigenschaften nicht neu definieren. Schließlich gibt es für eine Taste nur zwei Zustände (gedrückt oder nicht gedrückt). Anders als beim Joystick werden die empfangenen Daten auch nicht weiter interpretiert. Drücken Sie z.B. die Vorwärtstaste, so wird die Geschwindigkeit direkt auf einen festen Wert gesetzt. In unserem Beispiel auf 0.3. Analoge Zwischenwerte existieren nicht. End Sub
Nachdem wir die Eingabegeräte erzeugt haben und in der Lage sind, die Eingabedaten zu empfangen, werden die Informationen in der Form_Load()-Subroutine von Form1 weiter ausgewertet. Private Sub Form_Load() . . . Do If g_dx.TickCount > TimerZeit + ZeitInterval Then TimerZeit = g_dx.TickCount tempVector.x = BetrachterPos.x tempVector.z = BetrachterPos.z
Wir haben eine kleine Kollisionserkennung in das Programm eingebunden. Diese soll folgende Aufgabe lösen: »Erkennen einer Kollision mit einem Baum zwei Einheiten vor unserer aktuellen Laufrichtung«. Es ist wichtig, dass Sie eine mögliche Kollision vor Ihrer aktuellen Position prüfen. Wir haben uns für zwei Einheiten vor uns entschieden. Wenn wir den Abstand zu unserer Position zu klein
278
Beispiel: DirectInput und Direct3D
wählen, treten unschöne Effekte (der Betrachter steht halb in dem Baum, der Betrachter kann durch den Baum sehen ...) auf. If SpeedY > 0 Then If speed > 2 Then xx = speed Else tempVector2.x = BetrachterPos.x + Sin(BetrachterWinkel / 57.296)) tempVector2.z = BetrachterPos.z + Cos(BetrachterWinkel / 57.296)) Else If speed < 2 Then xx = speed * -1 tempVector2.x = BetrachterPos.x – Sin(BetrachterWinkel / 57.296)) tempVector2.z = BetrachterPos.z – Cos(BetrachterWinkel / 57.296)) End If
xx = 2 (xx * _ (xx * _
Else xx = 2 (xx * _ (xx * _
Beim Erzeugen der Bäume in der MakeVertex()-Subroutine haben wir das TypenArrays Kollision mit den Baumkoordinaten gefüllt. Diese Daten können wir nun für die Kollisionserkennung nutzen. Dazu fragen wir eine rechteckigen Bereich um den Baum herum ab. Befinden wir uns in diesem Bereich, dann wird eine Kollision erkannt. For i = 1 To 60 If tempVector2.x > Kollision(i).PosX – 0.5 And _ tempVector2.x < Kollision(i).PosX + 0.5 And _ tempVector2.z > Kollision(i).PosZ – 0.5 And _ tempVector2.z < Kollision(i).PosZ + 0.5 Then BetrachterPos.x = tempVector.x BetrachterPos.z = tempVector.z kolli = 1 Exit For
Wenn eine Kollision erkannt wurde, wird die Betrachterposition nicht verändert. Der Betrachter verharrt an einer Stelle, ohne sich in die angestrebte Richtung bewegen zu können. Else kolli = 0 End If Next i If kolli = 0 Then BetrachterPos.x = BetrachterPos.x + _ (SpeedY * Sin(BetrachterWinkel / 57.296)) BetrachterPos.z = BetrachterPos.z + _ (SpeedY * Cos(BetrachterWinkel / 57.296))
Kapitel 3 • DirectInput
279
Wurde keine Kollision erkannt, so darf der Betrachter die neue Position einnehmen. End If BetrachterWinkel = BetrachterWinkel + SpeedX BetrachterSicht.x = BetrachterPos.x + _ 100 * Sin(BetrachterWinkel / 57.296) BetrachterSicht.z = BetrachterPos.z + _ 100 * Cos(BetrachterWinkel / 57.296) BetrachterPos.y = 1.5 BetrachterSicht.y = 1.5 Call g_dx.ViewMatrix(matView, BetrachterPos,_ BetrachterSicht, MakeVector(0, 1, 0), 0) g_d3dDevice.SetTransform D3DTRANSFORMSTATE_VIEW, matView
Durch die Transformation der ViewMatrix werden die Veränderungen von Betrachterposition und Betrachterblickwinkel für den Anwender sichtbar. . . . End Sub
3.8
Bewegung im 3D-Raum Position, Ausrichtung und Blickrichtung des Betrachters oder der Spielfigur wird im Allgemeinen über die Viewmatrix berechnet. Diese Parameter werden über verschiedene Vektoren festgelegt. Als Erstes haben wir die absolute Position im dreidimensionalen Raum. Diese Werte splitten sich in die drei Vektorkoordinaten x, y und z auf. Als Nächstes benötigen wir xyz Koordinaten für den Punkt auf den wir blicken, weiterhin können wir die Kopfneigung und Drehung festlegen. In unserem Beispiel beschränken wir uns zunächst auf die ersten beiden Parameter. Das Problem: Über den ersten 3D-Vektor sind wir generell in der Lage uns durch einen beliebigen Raum zu bewegen. Allerdings würden wir immer auf einen bestimmten Punkt (0,0,0) im Raum schauen. Würden wir zum Beispiel ein Objekt umkreisen, wäre diese Technik angebracht. Die Position des Betrachters würde sich stets verändern und der Blick fiele immer auf das umkreiste Objekt. Diese Vorhergehensweise macht bei einsetzbaren Anwendungen wenig Sinn. Vielmehr versucht man die Realität nachzuahmen, getreu dem Motto » Ich gehe, wohin ich sehe.« Viele Programme benutzen hierzu eine bewährte Steuerungstechnik. Betätigt man die Links-Rechts-Cursortasten, so dreht sich der Betrachter um die eigene Achse. Drückt man nun die Vor-Zurück-Cursortasten, bewegt man sich in die Richtung, in die man gerade schaut.
280
Bewegung im 3D-Raum
Bild 3.8:
Umkreisen eines Objekts im 3D-Raum
Um diese Eigenart zu simulieren, benötigen wir einen Blickrichtungsvektor. Stellen wir uns vor, wir könnten genau 5 Meter weit sehen und wir würden uns einmal um unsere eigene Achse drehen. So würde das Ende unseres Blickfeldes einen Kreis mit einem Radius von 5 Metern um uns ziehen. Das hieße also, die Blickrichtung liegt auf einem Kreisbogen um uns herum und unsere jetzige Standposition ist der Mittelpunkt dieses Kreises.
Bild 3.9:
Blickrichtung
Kapitel 3 • DirectInput
281
Anhand der Grafik sehen wir, dass der Blickpunkt über einfache geometrische Kreisberechnungen ermittelt werden kann. Berücksichtigt werden muss nur noch, dass wir weiter sehen können, als wir mit einem Schritt gehen können. Hierzu berechnen wir einfach einen neuen Standort auf einem kleineren Kreisbogen, den wir dann der alten Position hinzuaddieren können.
Bild 3.10: Berechnung des neuen Standorts auf einen neuen Blickpunkt hin
So viel zur Theorie. Was nun folgt, ist die Praxis. Unsere aktuellen Standortvariablen benennen wir (AktX,AktZ). Als Weiteres benötigen wir die aktuelle Blickrichtung in Grad. Nennen wir diese AktBR. Um nun eine Drehung auszuführen, müssen wir AktBR in einem Bereich von 0-359 Grad verändern. Für die Tastaturabfrage eignet sich der API-Aufruf GetAsyncKeyState, den wir in einer DoEvents-Endlosschleife auf einen vorhandenen Tastendruck abfragen. Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer Dim AktX as Single Dim AktZ as Single Dim AktBR as Single Private Sub Schleife() Do
Drehung links um die Y-Achse If GetAsyncKeyState(vbKeyLeft) <> 0 then AktBR = AktBR -1 If AktBR <0 then AktBR=359 End If
282
Bewegung im 3D-Raum
Drehung rechts um die Y-Achse If GetAsyncKeyState(vbKeyRight) <> 0 then AktBR = AktBR+1 If AktBR >359 then AktBR=0 end if
Berechnung des Positionsabgleichs Vorwärtsbewegung. If GetAsyncKeyState(vbKeyUp) <> 0 then px = 0.5 * Cos( AktBR / 180 / Pi ) pz = 0.5 * Sin( AktBR / 180 / Pi ) AktX = AktX + px AktZ = AktZ + pz End If
Berechnung des neuen Blickpunktes. BlickX = 100 * Cos (AktBR / 180 / Pi ) BlickY = 100 * Sin (AktBR / 180 / Pi ) Call g_dx.ViewMatrix(matView, _ MakeVector(AktX,0,AktZ), MakeVector(BlickX, _ 0, BlickY), MakeVector(0, 1, 0), 0) Loop End Sub Private Function MakeVector( a As Double, b As Double, _ c As Double ) as D3DVECTOR Dim vecOut as D3DVECTOR vecOut.x = a vecOut.y = b vecOut.z = c MakeVector = vecOut End Function
Bild 3.11: Berechnung der neuen Position im Koordinatensystem
Kapitel 4 DirectSound 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 4.12 4.13 4.14 4.15 4.16 4.17 4.18 4.19
DirectSound-Architektur Datenformat HAL und HEL Systemintegration Initialisieren von DirectSound Erstellen des DirectSound-Objektes Buffer-Grundlagen Primary Soundbuffer Static und Streaming Soundbuffer Erzeugen von Soundbuffern Buffer-Einstellungen Buffer Playback Controls Ein einfaches Soundbeispiel Der PlayCursor Playbuffer-Benachrichtigungen Direct3DSound DirectSound3DBuffer DirectSound3DListener DirectSound Capture
285 285 286 286 287 288 290 291 291 292 294 294 296 299 301 301 304 315 328
284
DirectX ist nicht nur ein hervorragendes Werkzeug zum Erstellen von atemberaubenden 2D-und 3D-Grafiken sowie Landschaften, sondern eignet sich auch sehr gut für den Einsatz im musikalischen Bereich. Die Entwickler von DirectX haben sich auch bei der Erstellung und Wiedergabe von Soundeffekten und Musik mächtig ins Zeug gelegt. Bei modernen Spielen wird heutzutage ebenso viel Wert auf eine brillante Soundwiedergabe mit realistischen Effekten wie auf Grafik und Animation gelegt. Richtig eingesetzte Klangeffekte sowie gut abgestimmte Hintergrundmusik verleihen einem Spiel erst das gewisse Etwas. Ein Spiel soll den Spieler fesseln und wie bei einem Spielfilm in die Handlungsperson versetzen. Bei DirectSound handelt es sich nicht nur um ein gewöhnliches Modul zum einfachen Abspielen von Soundeffekten und Samples, sondern um ein leistungsfähiges Werkzeug zum Erstellen von zwei- und dreidimensionalen Klangbildern. Bei der Entwicklung wurde Wert auf eine möglichst realistische und naturgetreue Wiedergabe gelegt. So werden z.B. Effekte dem menschlichen Hörvermögen mathematisch so angepasst, dass sie den Zuhörer in eine virtuelle dreidimensionale Klangwelt versetzen. Die Aufgabenstellung an die Entwickler von DirectSound war es, ein Modul zu erschaffen, dass das gleichzeitige Abspielen mehrerer Sounds ermöglicht. Einige Klänge sollten dabei vielleicht immer wieder abgespielt werden, beispielsweise in einer Endlosschleife, andere hingegen nur einmal oder zu bestimmten Zeiten. Außerdem müssen die einzelnen Lautstärkepegel aufeinander abgestimmt und mit unterschiedlichen klanglichen Effekten räumlich bewegt werden können. Man benötigt also eine möglichst große Anzahl von Tonkanälen die annähernd verzögerungsfrei abgespielt werden sollen, um somit zu verhindern, dass keine zeitlichen Verzögerungen zwischen Ursache eines Geräusches und Wiedergabe des passenden Samples auftritt. Natürlich kann die Funktionalität von DirectSound nicht nur für Computerspiele eingesetzt werden, sondern findet auch in anderen Anwendungsgebieten ihre Aufgaben und Einsatzgebiete. DirectSound stellt dem Anwender die zuvor beschriebenen Möglichkeiten zur Verfügung. Für das Mischen von Sounds, das Anwenden verschiedener Effekte sowie die räumliche Positionierung von Schallquellen kann die Hardware der Soundkarte (HAL, 3D-HAL), soweit diese die speziellen Eigenschaften zur Verfügung stellt, übernehmen. Ebenso kann auch, vergleichbar mit der Grafikausgabe, auf einen Emulationsmodus (HEL) zurückgegriffen werden. Die Schnittstelle für das Aufzeichnen von Klangdaten, das DirectSound Capture Interface, unterstützt keine Hardwareoptimierung, sondern wird allein über die HEL (Win32 Funktionen) abgewickelt. Aber hierzu kommen wir noch ausgiebig im weiteren Verlauf dieses Buches.
Kapitel 4 • DirectSound
4.1
285
DirectSound-Architektur DirectSound beinhaltet alle Module zum Abspielen und Aufzeichnen von digitalen Sound-Samples. Die meisten Funktionen können über die Soundkartenhardware verarbeitet werden. Sollten spezielle Funktionen von der Hardware nicht unterstützt werden, greift DirectSound auf softwareemulierte Funktionen zurück. DirectSound beinhaltet zum Abspielen und Manipulieren von Sounddaten folgende Klassen: •
DirectSoundBuffer
•
DirectSound3DBuffer
•
DirectSound3DListener
•
DirectSoundCapture
•
DirectSoundCaptureBuffer
weiterhin wird über die DirectX7-Klasse •
DirectXEvent
auf die DirectX7.CreateEvent()-Methode zurückgegriffen.
4.2
Datenformat DirectSound und DirectSoundCapture arbeiten mit Wellenform-Audiodaten, welche als digitale Samples eines Sounds vorliegen. Das genaue Format eines Samples wird in einem Typenblock, dem WAVEFOR MATEX, beschrieben. Type WAVEFORMATEX lAvgBytesPerSec As Long lExtra As Long lSamplesPerSec As Long nBitsPerSample As Integer nBlockAlign As Integer nChannels As Integer nFormatTag As Integer nSize As Integer End Type
•
nChannels beschreibt die Anzahl von Kanälen (Normal 1= Mono oder 2= Stereo).
•
lSamplesPerSec beschreibt die Samplingrate in Hertz (Hz). Typische Werte sind 11.025, 22.050 und 44.100.
•
nBitsPerSample beschreibt die Bitbreite des Samples 8 oder 16 Bit.
286
4.3
HAL und HEL
•
nBlockAlign – Anzahl der Bytes, die für einen kompletten Sample benötigt werden. Berechnungsgrundlage (nBitsPerSample * nChannels / 8).
•
lAvgBytesPerSec ist das Produkt aus nBlockAlign * lSamplesPerSec.
•
nSize gibt die Größe der Felder an, die für spezielle Sampleinformationen benötigt wird.
HAL und HEL DirectSound HAL (Hardware Abstraction Layer) ist vorgesehen für folgende Funktionen •
Freier Zugriff und Kontrolle auf die Audiohardware (Soundkarte).
•
Beschreiben der Leistungsfähigkeit der Audiohardware.
•
Ausführen von soundkartenspezifischen Methoden.
Rückgabe von Fehlermeldungen, die durch die Audiohardware gemeldet wurden. Sollten beim Ausführen von hardwarespezifischen Methoden mögliche Fehler durch die Audiohardware gemeldet werden, z.B. weil die Soundkarte einige Eigenschaften nicht unterstützt, so leitet DirectSound diese Prozedur zum HEL (Hardware Emulations Layer) um.
4.4
Systemintegration Win32 Programm
DirectSound HAL Emulation
MIDI DirectSound HAL
Windows Audio DDI
Soundkarte Bild 4.1:
Wave
Systemintegration
Kapitel 4 • DirectSound
4.5
287
Initialisieren von DirectSound Um DirectSound zu verwenden, müssen zuvor verschiedene Parameter angegeben werden. Die folgenden Methoden werden für die Initialisierung von DirectSound eingesetzt. GetCount() Gibt die Anzahl der Einträge im Enumerationsobjekt zurück. object.GetCount() As Long object
ein gültiges DirectSoundEnum-Objekt
GetDescription() Gibt die Treiberbeschreibung des ausgewählten DirectSound-Gerätes zurück. object.GetDescription(index As Long) As String object
ein gültiges DirectSoundEnum-Objekt
index
Index des DirectSound-Gerätes in der Aufzählung
GetGuid() Gibt die Identifikationsnummer des DirectSound-Gerätes zurück. object.GetGuid(index As Long) As String object
ein gültiges DirectSoundEnum-Objekt
index
Index des DirectSound-Gerätes in der Aufzählung
GetName() Gibt die Bezeichnung des DirectSound-Gerätes zurück. object.GetName(index As Long) As String object
ein gültiges DirectSoundEnum-Objekt
index
Index des DirectSound-Gerätes in der Aufzählung
DirectX7-Objekt und DirectSound vorbereiten: Dim g_dx as DirectX7 Dim m_ds as DirectSound Dim g_dx as new DirectX7
Auslesen der Enumeration von DirectSound: Dim dsEnum as DirectSoundEnum Set dsEnum = g_dx.GetDSEnum
288
Erstellen des DirectSound-Objektes
For i = 1 to dsEnum.GetCount Debug.Print dsEnum.GetDescription (i) Next i
Über die dsEnum können nun folgende Parameter ausgelesen werden: Enthält die Anzahl der auszulesenden Audiogeräte dsEnum.GetCount
Herstellerbezeichnungen und Soundkartentypen dsenum.GetDescription (index)
Zusatzbezeichnungen und andere Infos zum Audiogerät dsEnum.GetName (Index)
Identifizierungsstring der Audiohardware. Dieser wird zum Erstellen des Direct Sound Objektes benötigt. dsEnum.GetGuid (index)
Es wird Ihnen nicht entgangen sein, dass Ihnen, obwohl Sie nur eine Soundkarte in Ihrem System haben, zwei Audiogeräte angezeigt werden. Dies ist ähnlich wie bei den im Kapitel DirectDraw beschriebenen Grafikkarten Guid’s. Die erste Guid stellt den primären Audiotreiber dar und repräsentiert somit das aktive Audiogerät in Ihrem System, wobei die zweite das eigentliche physische Audiogerät ist.
4.6
Erstellen des DirectSound-Objektes SetCooperativeLevel() Setzt den Cooperative Level der Applikation auf die Soundkarte. object.SetCooperativeLevel(hwnd As Long, _ level As CONST_DSSCLFLAGS) object
ein gültiges DirectSound-Objekt
hwnd
Windows-Handle der Aplikation
level
Prioritätsstufe CONST_DSSCLFLAGS
Um nun das DirectSound-Objekt zu erstellen und zu aktivieren, fügen wir in unser Beispiellisting die DirectSoundCreate()-Methode ein und übergeben dieser die Guid des aktiven Audiogerätes. Set m_ds = g_dx.DirectSoundCreate (dsEnum.GetGuit(1))
Kapitel 4 • DirectSound
289
Da Windows eine Multitaskingumgebung besitzt und mehrere Applikationen auf die Soundkarte gleichzeitig zugreifen können, setzen wir ähnlich wie bei DirectDraw den Cooperative Level und schützen somit unsere Anwendung vor fehlerhaften Zugriffen auf geschützte Bereiche. m_ds.SetCooperativeLevel Form1.hWnd, DSSCL_NORMAL
•
Normal Cooperative Level Im normalen Cooperative Level ist es nicht möglich, das Format des primären SoundBuffers zu ändern sowie in diesen zu schreiben. Alle Applikationen mit diesem CooperativeLevel nutzen das Primärbufferformat 22KHz Stereo Sound und 8 Bit Sampling. In diesem Modus ist es möglich, das Audiogerät zwischen verschiedenen Applikationen hin und her zu schalten.
•
Priority Cooperative Level Wenn DirectSound im Priority Cooperative Level Modus ausgeführt wird, hat Ihre Applikation das erste Recht auf die Hardwarerecourcen des Audiogerätes. Das Format des primären Soundbuffers sowie das Komprimieren des OnBoard-Speichers des Audiogerätes ist möglich.
•
Exclusive Cooperative Level Im Exlusive Cooperative Level hat, wie der Name schon sagt, Ihre Applikation alle exclusiven Zugriffsrechte auf das Audiogerät. Ist die Anwendung aktiv, ist der Soundbuffer ausschließlich Ihrer Applikation zugeordnet. Andere laufende Anwendungen haben keinen Zugriff mehr auf das Audiogerät.
•
Write-primary Cooperative Level Der höchste Cooperative Level ist der Write-primary Cooperative Level. Wenn DirectSound mit dieser Einstellung ausgeführt wird, hat Ihre Anwendung direkten Zugriff auf den primären Soundbuffer. In diesem Modus muss von Ihrer Applikation direkt in den primären Soundbuffer geschrieben werden. Wird Direct Sound nicht in dieser Einstellung ausgeführt, führen alle Versuche, mit DirectSoundBuffer.ReadBuffer und DirectSoundBuffer.WriteBuffer auf den Primärbuffer zuzugreifen, zwangsläufig zu einem Fehler.
Wenn Sie diesen Modus benutzen und Ihre Anwendung hat den Fokus, stoppen alle Sekundärbuffer anderer Applikationen. Wenn Ihre Applikation den Fokus verliert, wird der Primärbuffer als verloren gekennzeichnet. Um Ihre Anwendung fortzusetzen, muss der Primärbuffer erneuert werden. Mehr Informationen hierzu unter Buffer-Management. objekt.SetCooperativeLevel (hwnd as Long, level As_ CONST_DSSCLFLAGS)
290
4.7
Buffer-Grundlagen
Buffer-Grundlagen Die DirectSoundBuffer repräsentieren einen Speicherbereich, in dem die Sounddaten abgelegt werden. Bufferobjekte werden für Start, Stopp, Pause und zum Ablegen der Sampledaten eines Sounds benötigt. Sie enthalten die Attribute von Frequenz und Sampleformat. Wenn Sie DirectSound in Ihrer Applikation initialisiert haben, wird automatisch der primäre Soundbuffer zum Mischen von SoundSampleDaten und zur Ausgabe auf Ihrem Audiogerät angelegt. Sie müssen lediglich noch von Hand die Sekundärbuffer zum Speichern und Abspielen ihrer individuellen Sounds erstellen. Hierzu aber mehr in den nächsten Kapiteln. Sekundärbuffer werden von Ihrer Applikation erstellt und können, wenn Sie nicht mehr benötigt werden, auch wieder gelöscht werden. Sie speichern SoundSample-Daten und spielen sie bei Bedarf in einer Endlosschleife oder zu einem bestimmten Ereignis nur einmal ab. Sekundärbuffer können zur Laufzeit auch mit neuen Sounddaten gefüllt werden. Sollte die Datenmenge größer der Aufnahmefähigkeit der Soundkarte sein oder diese nicht über einen eigenen Speicher verfügen, so werden die Streamdaten im Speicher des Computers abgelegt. Dieses wirkt sich allerdings negativ auf die Performance aus. Typische Zugriffszeiten sind bei vorhandenem Soundkartenspeicher < 10 ms und bei Zugriff auf den Speicherbereich des PCs ca. 100 – 150 ms. Dieses ist aber meist für den Hörer nicht wahrnehmbar, sodass quasi keine Verzögerung zwischen Ursache und Auswirkung bemerkt wird. Die Anzahl der Sekundärbuffern ist theoretisch unbegrenzt und wird nur durch den physikalischen Speicher limitiert. Mehr Informationen zu verschiedenen Arten von Sekundärbuffern bekommen Sie unter Static-und Streaming Soundbuffer. Unter Verwendung der DirectSound.DuplicateSoundBuffer()-Methode kann eine Kopie eines existierenden Soundbuffers erstellt werden. Diese teilt sich den selben Speicherbereich mit dem Original, kann aber autonom gesteuert werden. Der primäre Soundbuffer kann nicht dupliziert werden, da er sich im Audiogerät befindet und diese Eigenschaften nicht zur Verfügung stehen. Ein Versuch, den primären Soundbuffer zu duplizieren, führt zu einem Fehler. Sie brauchen sich nicht um die Angelegenheiten des primären Soundbuffers zu kümmern. Dieser managt sich zum größten Teil von ganz allein. Wollen Sie Performance einsparen, so können Sie auch sofort in den Primärbuffer schreiben. Sie verzichten damit auf die Mischeigenschaften und es können keine Sekundärbuffer mehr erzeugt werden. Mehr Informationen hierzu im folgenden Kapitel. objekt.DuplicateSoundBuffer (original as DirectSoundBuffer) As_ DirectSoundBuffer
Kapitel 4 • DirectSound
291
Buffer Primary Buffer
Secondary Buffer
Streaming Buffer
Static Buffer
3D Buffer Bild 4.2:
4.8
Buffer
Primary Soundbuffer Der primäre Soundbuffer enthält die momentan abgespielten Sounddaten. Der sekundäre Soundbuffer enthält ein gesamtes Sample. DirectSound erstellt automatisch einen Primärbuffer. Die Sekundärbuffer hingegen müssen in Ihrer Applikation erstellt werden. Wenn ein Sound aus einem Sekundärbuffer abgespielt wird, so wird dieser von DirectSound automatisch dem Primärbuffer hinzugemischt. Sollten mehrere Sekundärbuffer gleichzeitig abgespielt werden, so enthält der Primärbuffer eine Mischung aller laufenden Audiodaten. Man kann sich diesen Vorgang als eine Art Audiomischpult vorstellen, wobei die Sekundärbuffer die klangerzeugenden Geräte widerspiegeln und der Primärbuffer das Mischpult repräsentiert. Die gemischten Daten im Primärbuffer werden dann zum Augabegerät weitergeleitet.
4.9
Static und Streaming Soundbuffer Wenn Sie einen SecoundarySoundBuffer erzeugen, müssen Sie DirectSound mitteilen, ob es sich um einen Static oder einem Streaming Soundbuffer handelt. Ein Static Soundbuffer speichert einen kompletten Sound in seinem Speicherbereich, ein Streaming Soundbuffer hingegen speichert immer nur einen Ausschnitt des gesamten Samples, wobei Ihre Applikation periodisch neue Daten in den Streamingbuffer schreiben muss.
292
Erzeugen von Soundbuffern
Hat Ihre Audiohardware einen eigenen Speicher, wird DirectSound versuchen, einen Static Soundbuffer in diesem zu erzeugen. Um ein effizientes Schreiben von Sounddaten zu gewährleisten, werden im Allgemeinen Streaming Soundbuffer im Systemspeicher erzeugt.
2D-Ausgabe Secondary Buffer Static Streaming Static Streaming Buffer Buffer Buffer Buffer
Primary Buffer Streaming Buffer
Ausgabe Bild 4.3:
4.10
2D-Soundausgabe
Erzeugen von Soundbuffern Um Audiodaten in einem Soundbuffer zu speichern, müssen wir diesen zuerst einmal erzeugen. Hierzu dient die von DirectSound bereitgestellte CreateSoundBuffer()-Methode.
Kapitel 4 • DirectSound
293
CreateSoundBuffer() Erstellt einen DirectSoundBuffer → DirectSound.DuplicateSoundBuffer(), DirectSound.SetCooperativeLevel(), DirectSoundBuffer.GetFormat(), DirectSoundBuffer.GetVolume(), DirectSoundBuffer.Play(), DirectSoundBuffer.SetFormat(), DirectSoundBuffer.SetFrequency() object.CreateSoundBuffer(bufferDesc As DSBUFFERDESC, _ format As WAVEFORMATEX) As DirectSoundBuffer Object
ein gültiges DirectSound-Objekt
BufferDesc
DSBUFFERDESC-Typ beinhaltet die Beschreibung zum Erstellen eines Soundbuffers.
format
WAVEFORMATEX-Typ beschreibt das Wellenformat der Audiodaten.
Anhand eines Beispiels erstellen wir einen Secondary Static-Soundbuffer. Public Sub CreateSoundBuffer() Dim m_dsb As DirectSoundBuffer Dim buffdesc As DSBUFFERDESC Dim format As WAVEFORMATEX
Zuerst muss das Waveformat bestimmt werden. format.nFormatTag = WAVE_FORMAT_PCM format.nChannels = 2 format.lSamplesPerSec = 22050 format.nBitsPerSample = 16 format.nBlockAlign = _ (format.nChannels * format.nBitsPerSample)/ 8 format.lAvgBytesPerSec = _ format.lSamplesPerSec * format.nBlockAlign format.nSize = 0
Beschreibung des Soundbuffers buffdesc.lBufferBytes = format.lAvgBytesPerSec buffdesc.lFlags = DSBCAPS_CTRLPAN Or DSBCAPS_CTRLVOLUME Or DSBCAPS_CTRLFREQUENCY Or DSBCAPS_STATIC
_
Soundbuffer erzeugen Set m_dsb = m_ds.CreateSoundBuffer(buffdesc, format) End Sub
Sie sollten für Ihre Applikation die Soundbuffer, die am meisten abgespielt werden, zuerst erstellen. Dies wirkt sich positiv auf die Performance der Anwendung aus, da Hardwareressourcen der Soundkarte zuerst aufgebraucht werden.
294
Buffer-Einstellungen
Möchten Sie hingegen selbst bestimmen, ob ein Sound in den Speicher der Soundkarte oder im Systemspeicher des Rechners geladen werden soll, so können Sie dieses über die Flags DSBCAPS_LOCHARDWARE oder DSBCAPS_ LOCSOFTWARE festlegen. Über das DSBCAPS_STATIC-Flag teilen Sie Direct Sound den Buffertype mit. Ist dieses Flag gesetzt, wird ein Static Soundbuffer erzeugt, ansonsten geht DirectSound davon aus, das es sich bei diesem Buffer um einen Streaming Soundbuffer handelt. objekt.CreateSoundBuffer(bufferDesc as DSBUFFERDESC, format as_ WAVEFORMATEX) as DirectSoundBuffer
4.11
Buffer-Einstellungen Wenn Sie Soundbuffer erzeugen, muss Ihre Applikation diese über die lFlags im DSBUFFERDESC spezifizieren. Zulässige Werte bekommen Sie über die Konstanten-Enumeration DSBCAPS_CTRL. •
3D-Einstellungen
•
Frequenz
•
Pan
•
Lautstärke
•
Positionsmitteilungen
Um einen dieser Parameter eines Soundbuffers zu verändern, muss dieser beim Erstellen des Soundbuffers über die lFlags freigegeben werden. Wurde dieses unterlassen, führt z.B. eine Änderung der Lautstärke über die DirectSound Buffer.SetVolume()-Methode zwangsläufig zu einem Fehler.
4.12
Buffer Playback Controls Zum Einstellen und Auslesen der aktuellen Lautstärke eines Soundbuffers benutzen Sie in Ihrer Applikation die DirectSoundBuffer.GetVolume()- und Direct SoundBuffer.SetVolume()-Methoden. Verändern Sie die Lautstärkeeinstellung des Primary Soundbuffers, so verändern Sie damit die Masterlautstärke Ihrer Soundkarte. GetFrequency() Empfängt die Frequenz in Samples pro Sekunde → DirectSoundBuffer.SetFrequency() object.GetFrequency() As Long object
ein gültiges DirectSoundBuffer-Objekt
Kapitel 4 • DirectSound
295
GetFrequency() Gültige Werte liegen im Bereich von DSBFREQUENCY_MIN und DSBFREQUENCY_MAX (100 – 100.000 Samples pro Sekunde) object
ein gültiges DirectSoundBuffer-Objekt
volume
neuer Lautstärkewert
Gültige Werte liegen im Bereich von DSBVOLUME_MIN (keine Abschwächung 0db) und DSBVOLUME_MAX (größte Abschwächung 100db) SetFrequency() Setzt die Frequenz, in der Audiosamples abgespielt werden. object.SetFrequency(frequency As Long) object
ein gültiges DirectSoundBuffer-Objekt
frequency
neue Frequenz in Hertz (Hz)
Gültige Werte liegen im Bereich von DSBFREQUENCY_MIN und DSBFREQUENCY_MAX (100 – 100.000 Samples pro Sekunde) Gültige Werte liegen im Bereich von DSBVOLUME_MIN (keine Abschwächung 0db) und DSBVOLUME_MAX (größte Abschwächung 100db) GetPan() Empfängt einen Panwert, der die Lautstärkebalance der Lautsprecher beschreibt. → DirectSoundBuffer.SetPan() object.GetPan() As Long object
ein gültiges DirectSoundBuffer-Objekt
Gültige Werte liegen im Bereich von DSBPAN_LEFT (-10.000) 100db Abschwächung rechts und DSBPAN_RIGHT (+10.000) 100db Abschwächung links. DSBPAN_CENTER ( 0 ) beschreibt die normale Mittelstellung. SetVolume() Setzt die aktuelle Lautstärke eines Soundbuffers object.SetVolume(volume As Long) SetPan() Setzt einen Panwert, der die Lautstärkebalance der Lautsprecher beschreibt. → DirectSoundBuffer.GetPan() object.SetPan(pan As Long) object
ein gültiges DirectSoundBuffer-Objekt
296
Ein einfaches Soundbeispiel
SetPan() pan
neuer Panoramawert
Gültige Werte liegen im Bereich von DSBPAN_LEFT (-10.000) 100db Abschwächung rechts und DSBPAN_RIGHT (+10.000) 100db Abschwächung links. DSBPAN_CENTER ( 0 ) beschreibt die normale Mittelstellung. GetVolume() Empfängt die aktuelle Lautstärke eines Soundbuffers object.GetVolume() As Long object
ein gültiges DirectSoundBuffer-Objekt
Über die Methoden DirectSoundBuffer.GetFrequency() und DirectSound Buffer.SetFrequency() verändern Sie die Geschwindigkeit, mit der DirectSound ein Sample abspielt. Je höher die Abspielgeschwindigkeit, desto höher ist die Tonlage des Sounds und umgekehrt. Sie kennen diesen Effekt von Harmonizern, z.B. die Stimme der Schlümpfe wurde auf diese Weise erzeugt, indem man die Stimmen schneller abspielen ließ, als sie aufgenommen wurden. Veränderungen dieses Parameters können Sie nur auf dem sekundären Soundbuffer anwenden. Frequenzänderungen am primären Soundbuffer bleiben ohne Auswirkung. Mit der DirectSoundBuffer.GetPan()- und DirectSoundBuffer.SetPan()-Methode verändern Sie das Lautstärkeverhältnis der Lautsprecher zueinander. Diese Funktion ist vergleichbar mit dem Panoramaregler an einer normalen Stereoanlage.
4.13
Ein einfaches Soundbeispiel Dim m_dx As New DirectX7 Dim m_ds As DirectSound Dim m_dsBuffer As DirectSoundBuffer Dim m_bLoaded As Boolean Private Sub Form_Load() Me.Show On Local Error Resume Next
DirectSound-Objekt mit primären Audiotreiber erstellen Set m_ds = m_dx.DirectSoundCreate("") If Err.Number <> 0 Then MsgBox "Audiohardware nicht gefunden !" End End If
Kapitel 4 • DirectSound
297
Zugriff anderer Applikationen auf das Audiogerät über den DirectSound-Cooperative-Level schützen. m_ds.SetCooperativeLevel Me.hWnd, DSSCL_PRIORITY End Sub Sub LoadWave(sfile As String) Dim bufferDesc As DSBUFFERDESC Dim waveFormat As WAVEFORMATEX
Zugriff auf Frequenz, Pan, Volumen erlauben und Soundbuffer als Staticbuffer deklarieren. bufferDesc.lFlags = DSBCAPS_CTRLFREQUENCY Or _ DSBCAPS_CTRLPAN Or DSBCAPS_CTRLVOLUME Or DSBCAPS_STATIC
Wellenformformat festlegen waveFormat.nFormatTag = WAVE_FORMAT_PCM waveFormat.nChannels = 2 waveFormat.lSamplesPerSec = 22050 waveFormat.nBitsPerSample = 16 waveFormat.nBlockAlign = waveFormat.nBitsPerSample / 8 * _ waveFormat.nChannels waveFormat.lAvgBytesPerSec = waveFormat.lSamplesPerSec _ * waveFormat.nBlockAlign Set m_dsBuffer = _ m_ds.CreateSoundBufferFromFile(sfile, bufferDesc,waveFormat) End Sub Private Sub Command1_Click() LoadWave App.Path & "\Test.wav"
Wavefile abspielen m_dsBuffer.Play DSBPLAY_DEFAULT End Sub
•
DirectSoundBuffer.Play
•
DirectSoundBuffer.Stop
Zum einfachen Abspielen der geladenen Samples reicht nun der Aufruf m_ds Buffer.play(). Als mögliche Übergabeparameter stehen zur Auswahl DSBPLAY_ DEFAULT und DSBPLAY_LOOPING. Der erste Parameter spielt den eingelesenen Sound einmal ab und beendet dann die Playroutine. Der zweite Übergabewert setzt die Playroutine in eine Endlosschleife, die nur über m_dsBuffer.stop() angehalten werden kann. Ein erneutes Aufrufen der Play()-Methode startet das Sample von vorn. objekt.Play(flags as CONST_DSBPLAYFLAGS)
298
Ein einfaches Soundbeispiel
objekt.Stop()
•
DirectSoundBuffer.SetVolume()
•
DirectSoundBuffer.GetVolume()
Um die Abspiellautstärke eines Samples zu ändern, wird die SetVolume()Methode benötigt. Diese setzt die Lautstärke in einem gültigen Bereich von -10.000 bis 0 ( in x / 100 db), wobei -10.000 die kleinste und 0 die größte Lautstärke wiedergibt. (Abschwächung von 0 – 100 db) Zu beachten ist, dass die Lautstärke erst nach dem Laden eines Wavefiles und vor dem Aufruf der Play()-Methode gesetzt wird. Ein Sample wird immer mit der Lautstärke 0 (am lautesten) geladen. Man kann über die Lautstärkereglung prinzipiell nur eine Abschwächung der Lautstärke erreichen. objekt.SetVolume(volume as Long) objekt.GetVolume() as Long
•
DirectSoundBuffer.SetPan
•
DirectSoundBuffer.GetPan
Die Balanceregelung zwischen zwei Lautsprechern wird mit der Methode DirectSoundBuffer.SetPan() verändert. Ein großer negativer Wert bewirkt, dass der Sound nur noch auf dem linken Lautsprecher zu hören ist, wobei hingegen ein großer positiver Wert die Ausgabe auf den rechten Lautsprecher bewirkt. Ein Wert von Null setzt die Ausgabe, linker Kanal zu rechter Kanal, auf ein Verhältnis 1:1. Das Panorama ist stufenlos in einem gültigen Wertebereich von -10.000 bis +10.000 anzugeben (Abschwächung links < > rechts 100 db ← 0 db / 0 db → 100 db). objekt.SetPan(pan as Long) objekt.GetPan() as Long
•
DirectSoundBuffer.SetFrequency()
•
DirectSoundBuffer.GetFrequency()
Auch Veränderungen an der Abspielgeschwindigkeit und damit an der Tonhöhe des abzuspielenden Samples sind über die Soundbuffer möglich. Empfehlenswert ist es nach dem Laden einer Wavedatei mit der Methode DirectSoundBuffer.GetFrequency() die original Samplefrequenz auszulesen. Nur ein Abspielen in dieser Frequenz hält die Original-Tonhöhe bei. Wird mit DirectSoundBuffer.Set Frequency() die Geschwindigkeit nicht verändert, so wird DirectSound das Sample in seiner Ursprungsfrequenz abspielen.
Kapitel 4 • DirectSound
299
Gültige Breiche für Frequenzänderungen mit SetFrequency() sind 100-100.000 (100 Hz bis 100 kHz). Werte außerhalb dieses Bereichs führen zu einem Fehler. objekt.SetFrequency(frequency as Long) objekt.GetFrequency() as Long
•
DirectSoundBuffer.SetFormat()
•
DirectSoundBuffer.GetFormat()
DirectSoundBuffer.SetFormat() setzt das Waveformat des primären Soundbuffers für die Applikation. Immer dann, wenn eine Anwendung den Fokus erhält, setzt DirectSound für die Anwendung das spezifische Waveformat. objekt.SetFormat(format as WAVEFORMATEX) objekt.GetFormat(format as WAVEFORMATEX)
•
DirectSoundBuffer.SetCurrentPosition()
•
DirectSoundBuffer.GetCurrentPosition()
DirectSoundBuffer.SetCurrenPosition() setzt die aktuelle Abspielposition (play cursor) auf den angegebenen Wert. DirectSoundBuffer.GetCurrentPosition() liest die aktuelle Abspielposition und Aufnahmeposition und schreibt sie in den Typenblock DSCURSORS. objekt.SetCurrentPosition(newPosition as Long) objekt.GetCurrentPosition(cursor as DSCURSORS) Type DSCURSORS lPlay as Long lWrite as Long End Type
4.14
Der PlayCursor DirectSound setzt zwei Zeiger im Soundbuffer. Zum einen die aktuelle Abspielposition (PlayCursor) und zum anderen die aktuelle Aufnahmeposition (Write Cursor). Diese Werte repräsentieren einen Offsetadresse im Speicher und sind keine absoluten Adressen, sondern die Differenz zwischen aktueller Position und Startadresse des Buffers. Play() Gibt den Befehl zum Abspielen eines Soundbuffers. object.Play(flags As CONST_DSBPLAYFLAGS)
300
Der PlayCursor
Play() object
ein gültiges DirectSoundBuffer-Objekt
flags
vom Typ CONST_DSBPLAYFLAGS
Stop() Gibt den Befehl zum Anhalten eines Soundbuffers. object.Stop() object
ein gültiges DirectSoundBuffer-Objekt
GetCurrentPosition() Empfängt die aktuelle Lese- und Schreibeposition des Cursors. → DirectSoundBuffer.SetCurrentPosition() object.GetCurrentPosition(cursors As DSCURSORS) object
ein gültiges DirectSoundBuffer-Objekt
cursors
Playcursor vom Typ DSCURSORS
SetCurrentPosition() Setzt den Soundcursor auf die angegebene Position. object.SetCurrentPosition(newPosition As Long) object
ein gültiges DirectSoundBuffer-Objekt
newPosition
neue Position in Bytes vom Anfang des Buffers
Die DirectSoundBuffer.Play()-Methode startet das Abspielen eines Sounds immer ab der aktuellen Abspielposition. Wenn der Soundbuffer gerade erzeugt wurde, steht der PlayCursor auf Position Null. Beim Abspielen des Sounds bewegt sich der PlayCursor stetig von Byte zu Byte und gibt somit die nächste Position der abzuspielenden Daten an. Wird die Ausgabe des Samples gestoppt, bleibt der PlayCursor beim nächsten abzuspielenden Byte stehen. Bei einer Aufnahme läuft der PlayCursor leicht versetzt und in der gleichen Geschwindigkeit hinter dem WriteCursor her. Daten die einmal vom WriteCursor geschrieben wurden, werden auf jeden Fall vom PlayCursor abgespielt. Die aktuellen Positionen des PlayCursors und des WriteCursors erhalten Sie über die Methoden DirectSoundBuffer.GetCurrentPosition() und DirectSoundBuffer. SetCurrentPosition(). Die aktuelle Schreibposition kann nicht verändert werden.
Kapitel 4 • DirectSound
301
Um zu garantieren, das die aktuelle Abspielposition richtig ist, setzen Sie beim Erstellen des Buffers das lFlag DSBCAPS_GETCURRENTPOSITION2 in der Bufferbeschreibung DSBUFFERDESC.
4.15
Playbuffer-Benachrichtigungen Es kann erwünscht sein, dass beim Abspielen von Samples Ihrer Applikation an einer oder mehreren Stellen über den aktuellen Stand des Soundbuffers informiert werden soll. Mit DirectSoundBuffer.SetNotificationPosition() (setze Benachrichtigungsposition) können beliebige Punkte im Soundbuffer als Ereignispunkte gesetzt werden. Das Anlegen dieser Punkte funktioniert nicht, wenn ein Sound abgespielt wird. Um ein Benachrichtigungsereignis im Soundbuffer zu setzen, muss zuerst das DirectXEvent-Objekt implementiert werden. Dann erst können Ereignisse über die DirectX7.CreateEvent()-Methode gesetzt werden. SetNotificationPositions() Setzt die Notifications Position in einem Soundbuffer. object.SetNotificationPositions(nElements As Long, _ psa() As DSBPOSITIONNOTIFY)
4.16
object
ein gültiges DirectSoundBuffer-Objekt
nElements
Nummer vom Typ DSBPOSITIONNOTIFY
psa()
ein Array von DSBPOSITIONNOTIFY
Direct3DSound Sicherlich lassen sich mit den Eigenschaften von DirectSound, wie wir sie bisher kennengelernt haben, viele Dinge realisieren. Stellen Sie sich jetzt mal vor, Sie programmieren ein 3D-Abenteuerspiel und würden nun die Soundeffekte in Ihr Programm einfügen. Ok, Sie könnten zur richtigen Zeit den richtigen Sample abspielen, dieses hätte aber den Nachteil, dass ein Geräusch, das vielleicht durch einen Gegner, der in Ihrer 3D-Welt zehn Meter von Ihnen entfernt steht, genauso laut ist wie eine andere Geräuschquelle, die direkt vor Ihnen steht. Weiterhin würden Sie vom Klangbild immer hören, dass der Gegner immer von vorne kommt, obwohl sich Ihre Spielfigur von der Klangquelle wegdreht. Manche werden nun sagen, das macht nichts, dann verändere ich eben die Lautstärke permanent im Verhältnis zur Distanz zu meinem Gegner. Weiterhin regele ich über die Panoramaregelung die Richtung aus der die Schallwellen zu hören sind. Sie merken schon, dass dieses Verfahren wohl recht umfangreich und kompliziert werden könnte und nicht im Sinne des Erfinders sein kann.
302
Direct3DSound
Glücklicherweise haben uns die Entwickler von DirectSound dieses Problem schon abgenommen. Mit Direct3DSound erhält der Anwender ein leistungsstarkes Tool zum richtigen Positionieren von Geräuschquellen und anderen Soundeffekten im 3D-Raum. Berechnungen über die Richtung oder Lautstärke, ja selbst mathematische Funktionen, die annähernd das menschliche Hören nachempfinden, sind in DirectSound verwirklicht worden und unterstützen die Entwickler von 3D-Spielen und anderen Anwendungen mit erstklassigen und ausgereiften Funktionen.
4.16.1 Grundlagen Die DirectSound3DBuffer- und DirectSound3DListener-Schnittstellen arbeiten gemeinsam mit Direct3D. Positionierungsvektoren, die z.B. die Position eines virtuellen Gegners in einem Spiel darstellen, können sofort in ein räumliches Klangbild übernommen werden. GetDistanceFactor() Empfängt den aktuellen Entfernungsfaktor. → DirectSound3DListener.SetDistanceFactor() object.GetDistanceFactor() As Single object
ein gültiges DirectSound3DListener-Objekt
SetDistanceFactor() Setzt den aktuellen Entfernungsfaktor. → DirectSound3DListener.GetDistanceFactor() object.SetDistanceFactor(distanceFactor As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
distanceFactor
neuer Entfernungsfaktor
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound unterscheidet zwischen zwei Arten von Soundpositionen im Raum •
DirectSound3DBuffer
•
DirectSound3DListener
Der DirectSound3DBuffer stellt die Schallquelle da. Diese beinhaltet einen Static Soundbuffer, in dem sich das eigentliche Sample befindet. Sie kann über dreidimensionale Positionskoordinaten frei im Raum bewegt werden.
Kapitel 4 • DirectSound
303
Das DirectSound3DListener-Objekt symbolisiert den Zuhörer. Wie der DirectSound3DBuffer kann auch dieser Buffertype im 3D-Raum eine beliebige Position einnehmen. Die Entfernungen und Positionen werden bei DirectSound in Metern angegeben. Alle Berechnungen, die DirectSound vornimmt, legen diesen Maßstab zugrunde. Sollten Sie den Maßstab in der grafischen Ebene anders gewählt haben, können sie einen Distanzfaktor angeben. DirectSound wird dann alle akustischen Positionsdaten mit diesem Faktor multiplizieren.
4.16.2 Mono- und Stereo-Soundquellen Stereo Samples sind nicht besonders nützlich in einer 3D-Soundumgebung von DirectSound. In der Realität sind natürliche Schallquellen immer mono. Erst durch die Positionierung im Raum und durch das Verhältnis der Lautstärken, Richtungen und Entfernungen zum Hörer (Listener) und anderen Klangquellen ergibt sich aus der Summe ein realistischer Stereosound. Nicht anders geschieht dies bei DirectSound. Sie positionieren mehrere Soundbuffer die Monosamples enthalten an verschiedenen Stellen im virtuellen 3DRaum. Diese werden dann von DirectSound, je nach Abstand und Ausrichtung zum Listener, dem primären Soundbuffer zugemischt. In der realen Welt hängt das Hören von Geräuschen von vielen Faktoren ab. •
Volume Beschreibt die Abnahme der Lautstärke mit der Entfernung der Schallquelle vom Zuhörer. Die zwei anzugebenden Größen sind die minimale und maximale Distanz.
•
Interaural Intensity Difference
•
Dieses Phänomen beschreibt die Frequenzverschiebung einer Schallwelle, wenn Sender und Empfänger sich relativ zueinander bewegen. Bewegt sich eine Geräuschquelle auf einen Zuhörer zu, werden die Schallwellen zusammengestaucht. Dadurch wird der zu hörende Ton in seiner Stimmlage höher. Bewegt er sich vom Zuhörer weg, werden Schallwellen auseinander gezogen und klingen somit tiefer.
Dieser Effekt ist sehr gut bei einem herankommenden Feuerwehrwagen zu erkennen. Die Sirene wird sofort eine Stimmlage tiefer, wenn der Wagen an einem vorbeigefahren ist und sich somit von Ihnen entfernt. Diesen Effekt bezeichnet man auch als Dopplereffekt. •
Interaural Time Difference Aufgrund des kürzeren Weges erreichen Geräusche, die von einer bestimmten Richtung zum Zuhörer kommen, das dieser Richtung zugewandte Ohr (Lautsprecher) früher als das jeweils andere. Diese Laufzeiten sind allerdings sehr gering und bewegen sich im Millisekundenbereich.
304
DirectSound3DBuffer
•
4.17
Muffling Dieser Parameter bestimmt ebenfalls die Lautstärke des Sounds anhand der Richtung, aus der die Schallwellen einfallen. Dabei werden Geräusche, die von hinten zu hören sind, beidseitig, und Schallwellen, die von links oder rechts kommen, jeweils auf der entgegengesetzten Seite mit gedämpfter Lautstärke wiedergegeben.
DirectSound3DBuffer Die Methoden von DirectSound3DBuffer benötigen wir zum Einstellen der Parameter für Positionierung, Ausrichtung und für die Geräuschkulisse im dreidimensionalen Raum. Die Methoden von DirectSound3DBuffer können in folgende Gruppen eingeteilt werden:
3D-Ausgabe Secondary Buffer Static Streaming Static Streaming Buffer Buffer Buffer Buffer
3D-Buffer
3D-Buffer
Primary Buffer Streaming Buffer
Listener
Ausgabe Bild 4.4:
•
3D-Soundausgabe
Parameter-Manipulation •
GetAllParameters()
•
SetAllParameters()
Kapitel 4 • DirectSound
•
•
•
•
•
•
305
Entfernungen •
GetMaxDistance()
•
GetMinDistance()
•
SetMaxDistance()
•
SetMinDistance()
Auswählen von Schallquellen •
GetDirectSound3Dlistener()
•
GetDirectSoundBuffer()
Operation Modes •
GetMode()
•
SetMode()
Position •
GetPosition()
•
SetPosition()
Soundprojektion und -ausrichtung •
GetConeAngles()
•
GetConeOrientation()
•
GetConeOutsideVolume()
•
SetConeAngles()
•
SetConeOrientation()
•
SetConeOutsideVolume()
Geschwindigkeit •
GetVelocity()
•
SetVelocity()
4.17.1 Parameter-Manipulation Mit Hilfe von DirectSound3DBuffer.GetAllParameters() können alle relevanten Einstellungen eines 3DBuffer-Objektes ausgelesen werden. DirectSound3DBuffer.SetAllParameters() schreibt einen vordefinierten Buffertypenblock in ein 3DBuffer-Objekt. Hier stehen allerdings zwei Möglichkeiten zur Verfügung, die über das apply-Flag vom Typ DS3DAPPLYFLAGS unterschieden werden.
306
DirectSound3DBuffer
DS3D_IMMEDIATE schreibt einen kompletten Bufferblock in das 3DBufferObjekt. DS3D_DEFERRED hingegen verändert nur die gesetzten Parameter. Sollten Sie die DS3D_DEFERRED Einstellung verwenden, wird ein Update des 3DBufferObjektes erst ausgeführt, nachdem die DirectSound3DListener.CommitDeferredSettings() Methode aufgerufen wurde. Hierdurch ist es möglich, mehrere vordefinierten Bufferblöcke verschiedenen 3DBuffer-Objekten zuzuweisen und sie gleichzeitig anzupassen. DirectSound3DBuffer.GetAllParameters (buffer As DS3DBUFFER) DirectSound3DBuffer.SetAllParameters (buffer As DS3DBUFFER, _ applyFlag As DS3DAPPLYFLAGS) GetAllParameters() Empfängt Informationen über die 3D-Charakteristik eines Soundbuffers zu einer bestimmten Zeit. object.GetAllParameters(buffer As DS3DBUFFER) object
ein gültiges DirectSound3DBuffer-Objekt
buffer
DS3DBUFFER-Typ
SetAllParameters() Setzt Informationen über die 3D-Charakteristik eines Soundbuffers zu einer bestimmten Zeit. → DirectSound3DBuffer.GetAllParameters() object.SetAllParameters(buffer As DS3DBUFFER, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
buffer
ein gültiges DirectSoundBuffer-Objekt
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
CommitDeferredSettings() Übergibt die zuvor eingestellten Werte unter Verwendung des applyFlags → CONST_DS3DAPPLYFLAGS object.CommitDeferredSettings() object
ein gültiges DirectSound3DListener-Objekt
Kapitel 4 • DirectSound
307
4.17.2 Entfernungen Die DirectSound3DBuffer.GetMaxDistance()-Methode gibt die maximale Entfernung eines 3DBuffer-Objekts zurück. Die maximale und minimale Distanz eines 3DBuffers beschreibt, ab welcher Entfernung ein Geräusch nicht mehr zu hören ist (maximale Distanz) und ab welcher Entfernung die maximale Lautstärke einer Klangquelle erreicht ist (minimale Distanz). GetMaxDistance() Empfängt die Maximale Entfernung eines 3D-Buffer-Objekts. → DirectSound3DBuffer.GetMinDistance(), DirectSound3DBuffer.SetMaxDistance(), DirectSound3DBuffer.SetMinDistance() object.GetMaxDistance() As Single object
ein gültiges DirectSound3DBuffer-Objekt
SetMaxDistance() Setzt die Maximale Entfernung eines 3D-Buffer-Objekts. → DirectSound3DBuffer.GetMinDistance(), DirectSound3DBuffer.GetMaxDistance(), DirectSound3DBuffer.SetMinDistance() object.SetMaxDistance(maxDistance As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
maxDistance
neuer Wert der größten Entfernung
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
GetMinDistance() Empfängt die Minimale Entfernung eines 3D-Buffer-Objekts. → DirectSound3DBuffer.GetMaxDistance(), DirectSound3DBuffer.SetMaxDistance(), DirectSound3DBuffer.SetMinDistance() object.GetMinDistance() As Single object
ein gültiges DirectSound3DBuffer-Objekt
SetMinDistance() Setzt die Minimale Entfernung eines 3D-Buffer-Objekts. → DirectSound3DBuffer.GetMinDistance(), DirectSound3DBuffer.GetMaxDistance(), DirectSound3DBuffer.SetMaxDistance() object.SetMinDistance(minDistance As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS)
308
DirectSound3DBuffer
SetMinDistance() object
ein gültiges DirectSound3DBuffer-Objekt
minDistance
neuer Wert der kleinsten Entfernung
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Stellen Sie sich vor, Sie stehen in einem Garten und eine Biene nähert sich. Sie werden die Biene erst ab ca. 5 Meter hören können. Nachdem sie auf 10 cm herangekommen ist, hat das Tierchen seine relative maximale Lautstärke erreicht, da es nicht noch näher an Sie herankommen wird. Plötzlich hören Sie in der Weite einen Düsenjäger heranfliegen. Die gleiche Lautstärke, die zuvor die Biene bei 10 Metern hatte, hat nun der Düsenjäger bei 10 km. Seine relative maximale Lautstärke wird dieser bei 500 Metern haben, da er nicht näher an Sie herankommen wird. (Es sei denn, er stürzte in Ihren Garten, aber dann hätte sich für Sie dieses Problem erledigt.) Um diesen Lautstärkeeffekt nachzuahmen, ist es nötig, jedem 3D-Buffer-Objekt eine minimale und eine maximale Entfernung (Distanz) mitzuteilen. Benötigt werden hierzu die unten beschriebenen Methoden. Für das Setzen der Distanzen wird, wie schon zuvor beschrieben, das apply-Flag verwendet. objekt.SetMaxDistance(maxDistance As Single, applyFlag As _ CONST_DS3DAPPLYFLAGS) objekt.GetMaxDistance() As Single objekt.SetMinDistance(minDistance As Single, applyFlag As _ CONST_DS4DAPPLYFLAGS) objekt.GetMinDistance() As Single
4.17.3 Auswählen von Schallquellen GetDirectSound3DListener() Gibt ein DirectSound3DListener Objekt zurück. object.GetDirectSound3DListener() As DirectSound3Dlistener object
ein gültiges DirectSound3DBuffer-Objekt
GetDirectSoundBuffer() Gibt ein DirectSoundBuffer Objekt zurück. object.GetDirectSoundBuffer() As DirectSoundBuffer object
ein gültiges DirectSound3DBuffer-Objekt
Kapitel 4 • DirectSound
309
Die DirectSound3DBuffer.GetDirectSound3DListener()-Methode DirectSound3DListener-Objekt zurück.
gibt
das
Über den Aufruf der DirectSound3DBuffer.GetDirectSoundBuffer()-Methode bekommen Sie einen DirectSoundBuffer. objekt.GetDirectSound3DListener() As DirectSound3DListener objekt.GetDirectSoundBuffer() As DirectSoundBuffer
4.17.4 Operation Mode Über die Methode DirectSound3DBuffer.SetMode() stehen Ihnen drei Eigenschaften der CONST_DS3DMODEFLAGS zur Verfügung. DS3DMODE_DISABLE schaltet die 3D Soundausgabe aus. Alle nun abgespielten Sounds werden mittig über die Lautsprecher ausgegeben. Der DS3DMODE_HEADRELATIVE Modus verändert die Soundparameter (Position, Velocity und Ausrichtung) relativ zu den Einstellungen des ListenerObjektes. Bei Bewegung der Schallquelle sowie des Listeners verändern sich alle Daten automatisch. Die Einstellung DS3DMODE_NORMAL setzt den Operationsmode in die Defaulteinstellung zurück. Auch hierbei ist zu beachten, das Änderungen an diesen Parameter erst nach einem DirectSound3DListener.CommitDeferredSettings()-Aufruf übergeben werden. GetMode() Empfängt den Operationsmode des aktuellen 3D-Sound-Prozesses. → DirectSound3DBuffer.SetMode() object.GetMode() As CONST_DS3DMODEFLAGS object
ein gültiges DirectSound3DBuffer-Objekt
Rückgabewerte vom Typ CONST_DS3DMODEFLAGS SetMode() Setzt den Operationsmode des aktuellen 3D-Sound-Prozesses. → DirectSound3DBuffer.GetMode() object.SetMode(mode As CONST_DS3DMODEFLAGS, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
mode
Wert vom Typ CONST_DS3DMODEFLAGS
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
310
DirectSound3DBuffer
CommitDeferredSettings() Übergibt die zuvor eingestellten Werte in Verwendung des applyFlags. → CONST_DS3DAPPLYFLAGS object.CommitDeferredSettings() object
ein gültiges DirectSound3DListener-Objekt
objekt.DirectSound3DBuffer.SetMode _ (mode As CONST_DS3DMODEFLAGS, _ applyFlag As CONST_DS3DAPPLYFLAGS) objekt.DirectSound3DBuffer.GetMode() as CONST_DS3DMODEFLAGS
4.17.5 Position Die Position einer Schallquelle (DirectSound3DBufferObjekt) kann beliebig über die DirectSound3DBuffer.SetPosition()-Methode verändert werden. Somit können Bewegungen von grafischen Komponenten im 3D-Raum auch akustisch hörbar gemacht werden. Die Positionen werden in x-, y-, z-Koordinaten angegeben. Über einen Distanzfaktor DirectSound3DListener.SetDistanceFactor() kann die akustische Position der grafischen Komponente angepasst werden. Es empfiehlt sich allerdings, den grafischen Maßstab in Metern festzulegen. DirectSound verwendet die metrische Aufteilung, um Laufzeiten von Schallwellen zu berechnen. Auch hierbei gilt die Übernahme durch das apply-Flag. Die Rückgabe der Position mit DirectSound3DBuffer.GetPosition() erfolgt in einem Vektor (v.x, v.y, v.z) vom Typ D3DVECTOR. GetPosition() Empfängt die Position eines 3DSoundBuffers im 3D-Raum. → DirectSound3DBuffer.SetPosition() object.GetPosition(position As D3DVECTOR) object
ein gültiges DirectSound3DBuffer-Objekt
position
3D-Position (x, y, z) in Metern
SetPosition() Setzt die Position eines 3DSoundBuffers im 3D-Raum. → DirectSound3DBuffer.GetPosition() object.SetPosition(x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
Kapitel 4 • DirectSound
311
SetPosition() x,y,z
Koordinaten der neuen Position
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
GetDistanceFactor() Empfängt den aktuellen Entfernungsfaktor. à DirectSound3DListener.SetDistanceFactor() object.GetDistanceFactor() As Single object
ein gültiges DirectSound3DListener-Objekt
SetDistanceFactor() Setzt den aktuellen Entfernungsfaktor. à DirectSound3DListener.GetDistanceFactor() object.SetDistanceFactor(distanceFactor As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
distanceFactor
neuer Distancefaktor
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
objekt.SetPosition(x As Single, y As Single, z As Single, _ applyFlag as CONST_DS3DAPPLYFLAGS) objekt.GetPosition(position as D3DVECTOR)
4.17.6 Soundprojektion und -ausrichtung Um eine realistische Soundprojektion zu erhalten, ist es wichtig, dass Parameter wie Abstrahlwinkel und Abstrahlverhalten einer Geräuschquelle berücksichtigt werden. DirectSound stellt hierzu mehrere Parameter zur Verfügung. Über einen Trichter, den so genannten Cone, werden Ausbreitung und Richtung einer Schallquelle angegeben. GetConeAngles() Empfängt die Winkel des inneren und äußeren Klangtrichters. → DirectSound3DBuffer.SetConeAngles() object.GetConeAngles(inCone As Long, outCone As Long) object
ein gültiges DirectSound3Dbuffer-Objekt
inCone
Winkel des inneren Klangtrichters
outCone
Winkel des äußeren Klangtrichters
312
DirectSound3DBuffer
GetConeOrientation() Empfängt die Ausrichtung des Klangtrichters. → DirectSound3DBuffer.SetConeOrientation() object.GetConeOrientation(orientation As D3DVECTOR) object
ein gültiges DirectSound3DBuffer-Objekt
orientation
dieser Vektor stellt die Mitte des Klangtrichters dar
GetConeOutsideVolume() Empfängt die Lautstärke des äußeren Klangtrichters. → DirectSound3DBuffer.SetConeOutsideVolume() object.GetConeOutsideVolume() As Long object
ein gültiges DirectSound3DBuffer-Objekt
Die Lautstärke wird als Abschwächung angegeben. Ein größerer Wert bedeutet größere Abschwächung und somit eine geringere Lautstärke. Gültige Bereiche liegen zwischen DSBVOLUME_MAX (keine Abschwächung) und DSBVOLUME_MIN (größte Abschwächung). Der Standardwert ist DS3D_DEFAULTCONEOUTSIDEVOLUME (keine Abschwächung) SetConeAngles() Setzt die Winkel des inneren und äußeren Klangtrichters. → DirectSound3DBuffer.GetConeAngles() object.SetConeAngles(inCone As Long, outCone As Long, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
inCone
Winkel des inneren Klangtrichters
outCone
Winkel des äußeren Klangtrichters
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
SetConeOrientation() Setzt die Ausrichtung des Klangtrichters. → DirectSound3DBuffer.GetConeOrientation() object.SetConeOrientation( x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
x,y,z
Koordinaten der neuen Ausrichtung
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Kapitel 4 • DirectSound
313
SetConeOutsideVolume() Setzt die Lautstärke des äußeren Klangtrichters. → DirectSound3DBuffer.GetConeOutsideVolume() object.SetConeOutsideVolume(coneOutsideVolume As Long, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
coneOutsideVolume
erlaubte Werte liegen im Bereich von DSBVOLUME_MAX (keine Abschwächung), DSBVOLUME_MIN (größte Abschächung)
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Wir unterscheiden zwei Arten von Cones: des inneren (Inside Cone) und dem äußeren (Outside Cone). Für das bessere Verständnis empfiehlt es sich, sich eine Schallquelle als einen Lautsprecher vorzustellen. Sie können den Lautsprecher in eine beliebige Richtung drehen, dies hat schon mal den Effekt, dass diejenigen Zuhörer, die Sie direkt anstrahlen, den Ton am lautesten hören werden. Der Öffnungswinkel des trichterförmigen Bereichs, der sich am lautesten ausbreitet, wird als Inside Cone angegeben. Den Schalltrichterbereich um diesen herum bezeichnet man als Outside Cone. Beide Trichtergrößen werden als Winkelgröße definiert. InCone und OutCone werden in Radiant (0 – 360 Grad) / (180/pi) oder (WinkelInGrad / 57.2957) angegeben und repräsentieren den Öffnungswinkel des inneren und äußeren Schalltrichters. objekt.SetConeAngles(inCone As Long, outCone As Long, _ applyFlag as CONST_DS3DAPPLYFLAGS) objekt.GetConeAngles(inCone As Long, outCone As Long)
Die Ausrichtung der Schalltrichter wird über einen Vektor (x,y,z) angegeben und über die SetConeOrientation()-Methode bestimmt. objekt.SetConeOrientation(x As Single, y As Single, z As _ Single, applyFlag as CONST_DS3DAPPLYFLAGS) objekt.GetConeOrientation(orientation as D3DVECTOR)
Die Laustärke außerhalb des äußeren Schalltrichters wird über die Methode SetConeOutsideVolume() beschrieben. Die Lautstärke ist in (x * 100 db) anzugeben. Erlaubte Werte sind DSBVOLUME_MAX (keine Abschwächung – laut) und DSBVOLUME_MIN (größte Abschwächung – leise) objekt.SetConeOutsideVolume(coneOutsideVolume As Long, _ applyFlag as CONST_DS3DAPPLYFLAGS) objekt.GetConeOutsideVolume() As Long
314
DirectSound3DBuffer
Sound Cones
Schallquelle
z
n si ta
D
Äußere Cone
Äußere Cone
Innere Cone
Inside Volume Transitional Volume Bild 4.5:
Schallkegel
4.17.7 Geschwindigkeit Über die SetVelocity()-Methode werden Dopplereffekte erzeugt. Der VelocityWert repräsentiert eine Geschwindigkeit, mit der sich die Schallquelle oder der Zuhörer relativ zu einem Objekt hin- oder fortbewegt. Der Velocity-Wert wird als Vektor angegeben. Die Länge des Vektors beschreibt die Geschwindigkeit in Meter pro Sekunde, die Richtung des Vektors beschreibt die Bewegungsrichtung der Schallquelle. GetVelocity() Empfängt die Geschwindigkeit, mit der sich ein 3DBuffer im Raum bewegt. → DirectSound3DBuffer.SetVelocity() object.GetVelocity(velocity As D3DVECTOR) object
ein gültiges DirectSound3DBuffer-Objekt
velocity
Wert in Meter pro Sekunde
Velocity wird zum Errechnen des Dopplereffektes benötigt.
Kapitel 4 • DirectSound
315
SetVelocity() Empfängt die Geschwindigkeit, mit der sich ein 3DBuffer im Raum bewegt. → DirectSound3DBuffer.GetVelocity() object.SetVelocity(x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
x,y,z
Koordinaten des Richtungsvektors
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Velocity wird zum Errechnen des Dopplereffektes benötigt. objekt.SetVelocity (x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) objekt.GetVelocity (velocity As D3DVECTOR)
4.18
DirectSound3DListener Der DirectSound3DListener repräsentiert in DirectSound den Zuhörer und damit den Anwender, der vor seinem Computer sitzt und das Geschehen auf dem Bildschirm verfolgt. Um ihn nun nicht nur grafisch in eine andere Welt zu versetzen, sondern auch akustisch, simuliert DirectSound einen beweglichen Zuhörer in einem Raum. Man geht sogar noch weiter, als nur die Position des Listeners zu verändern. Über verschiedene Parameter können auch die Kopfausrichtung und Kopfneigung sowie die relative Geschwindigkeit bestimmt werden. Weiterhin ist es auch hier wie bei den Soundquellen möglich, einen Distanzfaktor zur Umrechnung des grafischen in den akustischen Maßstabes anzugeben. Hierbei sei nochmals erwähnt, dass es sich anbietet, von vornherein den grafischen Maßstab in Metern zu wählen, da dieses die Umsetzung in den akustischen Raum wesentlich erleichtert. Für das DirectSound3DListener-Objekt stehen folgende Klassen zur Verfügung: •
•
Parameter-Manipulation •
GetAllParameters()
•
SetAllParameters()
Verzögerungseinstellungen •
•
CommitDeferredSettings()
Entfernungsfaktoren •
GetDistanceFactor()
•
SetDistanceFactor()
316
DirectSound3DListener
•
•
Dopplerfaktoren •
GetDopplerFactor()
•
SetDopplerFactor()
Auswahlmöglichkeiten •
•
•
•
•
GetDirectSoundBuffer()
Ausrichtung •
GetOrientation()
•
SetOrientation()
Position •
GetPosition()
•
SetPosition()
Abschwächung •
GetRolloffFactor()
•
SetRolloffFaktor()
Geschwindigkeit •
GetVelocity()
•
SetVelocity()
4.18.1 Parameter-Manipulation Über die GetAllParameters()- und SetAllParameters()-Methoden haben Sie die Möglichkeit, dem Listener-Objekt eine Liste vom Typ DS3DLISTENER zu übergeben oder diese zu empfangen. objekt.GetAllParameters(listener As DS3DLISTENER) objekt.SetAllParameters(listener As DS3DLISTENER, _ applyFlag As CONST_DS3DAPPLYFLAGS) Type DS3DLISTENER distanceFactor As Single dopplerFactor As Single rolloffFactor As Single vOrientFront As D3DVECTOR vOrientTop As D3DVECTOR vPosition As D3DVECTOR vVelocity As D3DVECTOR End Type
Kapitel 4 • DirectSound
317
4.18.2 Verzögerungseinstellungen Die DirectSound3DListener.CommitDeferredSettings()-Methode übermittelt an DirectSound die für den 3DBuffer und den 3DListener eingestellten oder veränderten Parameter. Über die Art der Übergabe entscheidet das zuvor mit dem Aufruf übergebene apply-Flag. DirectSound3DListener.CommitDeferredSettings()
4.18.3 Entfernungsfaktoren DirectSound3DListener.SetDistanceFactor() verändert den Faktor mit dem DirectSound Positionsdaten einer Klangquelle im 3D-Raum multipliziert. Diese Methode dient zur Anpassung des grafischen an den akustischen Maßstabes. Die DirectSound3DListener.GetDistanceFactor()-Methode liest den aktuellen Distanzfaktor ab. DirectSound3DListener.SetDistanceFactor(distanceFaktor As _ Single, applyFlag As CONST_DS3DAPPLYFLAGS) DirectSound3DListener.GetDistanceFactor() As Single
4.18.4 Dopplerfaktoren Die Methoden DirectSound3DListener.GetDopplerFactor() und DirectSound 3DListener.SetDopplerFactor() lesen und setzen den Dopplerfaktor. Dieser Wert bestimmt die Berechnung des Dopplereffektes. Gültige Werte liegen im Bereich von DS3D_MINDOPPLERFACTOR (kein Dopplereffekt) und DS3D_MAX DOPPLERFACTOR (das 10-fache des normalen Wertes, der real herrscht). Die Standardeinstellung liegt bei DS3D_DEFAULTDOPPLERFACTOR (1.0 ). GetDopplerFactor() Empfängt den aktuellen Wert des Dopplereffektes. → DirectSound3DListener.SetDopplerFactor() object.GetDopplerFactor() As Single object
ein gültiges DirectSound3DListener-Objekt
Gültige Werte liegen im Bereich DS3D_MINDOPPLERFACTOR (kein Dopplereffekt) und DS3D_MAXDOPPLERFACTOR (maximaler Dopplereffekt); die Grundeinstellung ist DS3D_DEFAULTDOPPLERFACTOR. SetDopplerFactor() Setzt den aktuellen Wert des Dopplereffektes. → DirectSound3DListener.GetDopplerFactor()
318
DirectSound3DListener
SetDopplerFactor() object.SetDopplerFactor(dopplerFactor As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
dopplerFactor
neuer Dopplerfaktor-Wert
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
4.18.5 Auswahlmöglichkeiten Die DirectSound3DListener.GetDirectSoundBuffer()-Methode gibt ein gültiges Objekt vom Typ DirectSoundBuffer zurück. DirectSound3DListener.GetDirectSoundBuffer() As _ DirectSoundBuffer
4.18.6 Ausrichtung Die DirectSound3DListener.SetOrientation()-Methode setzt den Zuhörer auf eine neue aktuelle Ausrichtung anhand zweier Vektoren, dem Frontvektor und dem Topvektor. GetOrientation() Empfängt die Ausrichtung des Listenerobjektes. → DirectSound3DListener.SetOrientation() object.GetOrientation(orientFront As D3DVECTOR, _ orientTop As D3DVECTOR) object
ein gültiges DirectSound3DListener-Objekt
orientFront
Vektor für die horizontale Ausrichtung
orientTop
Vektor für die vertikale Ausrichtung
SetOrientation() Setzt die Ausrichtung des Listenerobjektes → DirectSound3DListener.GetOrientation() object.SetOrientation(xFront As Single, yFront As Single, _ zFront As Single, xTop As Single, yTop As Single, zTop As _ Single, applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
Kapitel 4 • DirectSound
319
SetOrientation() Front x,y,z
Vektor der horizontalen Ausrichtung
Top x,y,z
Vektor der vertikalen Ausrichtung
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Der Frontvektor zeigt in Blickrichtung des Listener, der Topvektor zeigt aus dem Kopf des Listeners senkrecht nach oben. Die Grundeinstellung des Frontvektors beträgt (xyz) (0,0,1) die des Topvektors (0,1,0). Der Topvektor muss im richtigen Verhältnis zum Frontvektor angegeben werden. DirectSound aktualisiert erst den Frontvektor, dann den Topvektor.
Top Vector
Front Vector
Bild 4.6:
Ausrichtung
Der Frontvektor bestimmt die Blickrichtung, der Topvektor die seitliche Schieflage des Kopfes. Beide Vektoren müssen in einem Verhältnis von 90° zueinander ausgerichtet sein. DirectSound3DListener.SetOrientation(xFront As Single, _ yFront As Single, zFront As Single, xTop As Single, _ yTop As Single, zTop As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) DirectSound3DListener.GetOrientation(orientFront As D3DVECTOR, orientTop As D3DVECTOR)
320
DirectSound3DListener
4.18.7 Position Die DirectSound3DListener.SetPosition()-Methode setzt für den Listener (Zuhörer) die aktuelle Position in Metern. Sollte der Maßstab vom grafischen abweichen, kann die Position der Schallquelle über die DirectSound3DListener.Set DistanceFactor()-Methode angepasst werden. GetPosition() Empfängt die Position des Listenerobjektes. → DirectSound3DListener.SetPosition() object.GetPosition(position As D3DVECTOR) object
ein gültiges DirectSound3DListener-Objekt
position
Koordinate der Position im 3D-Raum
SetPosition() Setzt die Position des Listenerobjektes. → DirectSound3DListener.GetPosition() object.SetPosition(x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
x,y,z
Koordinate der neuen Position
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DListener.SetPosition(x As Single, _ y As Single, z As Single, applyFlag As CONST_DS3DAPPLYFLAGS) DirectSound3DListener.GetPosition(position as D3DVECTOR)
4.18.8 Abschwächung Der Rolloff-Faktor beschreibt die Abschwächung eines Sounds in Abhängigkeit der Entfernung der Schallquelle zum Zuhörer. Je größer der Rolloff-Faktor, desto leiser wird ein Geräusch bei einer konstanten Entfernung beim Zuhörer ankommen. Ein Wert von 0.0 verursacht, dass an jedem Punkt im Raum die gleiche Lautstärke herrscht. Der Wert 1.0 ist als Defaulteinstellung vorgegeben und simuliert natürliche Verhältnisse. Der Wertebereich für den Rolloff-Faktor liegt zwischen DS3D_MINROLLOFFFACTOR (0.0) und DS3D_MAXROLLOFFFACTOR (10.0). Den Defaultwert können Sie aus der Konstanten DS3D_ DEFAULTROLLOFFFACTOR (1.0) entnehmen. GetRolloffFactor() Empfängt den Rolloff-Faktor des Listenerobjektes. → DirectSound3DListener.SetRolloffFactor()
Kapitel 4 • DirectSound
321
GetRolloffFactor() object.GetRolloffFactor() As Single object
ein gültiges DirectSound3DListener-Objekt
Gültige Werte liegen im Bereich von DS3D_MINROLLOFFFACTOR (keinRolloffeffekt) und DS3D_MAXROLLOFFFACTOR (größter Rolloffeffekt); die Grundeinstellung beträgt DS3D_DEFAULTROLLOFFFACTOR SetRolloffFactor() Setzt den Rolloff-Faktor des Listenerobjektes. → DirectSound3DListener.GetRolloffFactor() object.SetRolloffFactor(rolloffFactor As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
rolloffFactor
neuer RollOff-Faktor
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Gültige Werte liegen im Bereich von DS3D_MINROLLOFFFACTOR (kein RolloffEffekt) und DS3D_MAXROLLOFFFACTOR (größter Rolloff-Effekt); die Grundeinstellung beträgt DS3D_DEFAULTROLLOFFFACTOR
Rolloff Faktor
Lautstärke
(0.0) (1.0) (5.0) Entfernung Bild 4.7:
Rolloff
322
DirectSound3DListener
DirectSound3DListener.SetRolloffFactor(rolloffFactor As Single, applyFlag As CONST_DS3DAPPLYFLAGS) DirectSound3DListener.GetRolloffFactor() As Single
4.18.9 Geschwindigkeit Der Velocity-Vektor stellt anders als die Vektoren zur Positionsbestimmung keine feste Distanz oder Richtungswert da. Er repräsentiert vielmehr eine virtuelle Größe der Geschwindigkeit in Verbindung mit einer Richtung, in die der Vektor zeigt. Der Betrag des Velocity-Vektors ist das Äquivalent zur Geschwindigkeit, mit der sich der Hörer im Raum in eine bestimmte Richtung bewegt. Diesen Wert benötigt DirectSound, um den Dopplereffekt zu errechnen. Je schneller sich der Zuhörer auf eine Schallquelle hin bewegt, desto größer der Dopplereffekt. GetVelocity() Empfängt den aktuellen Velocity-Wert des Listenerobjektes. → DirectSound3DListener.SetVelocity() object.GetVelocity() As D3DVECTOR object
ein gültiges DirectSound3DListener-Objekt
Velocity wird zum Errechnen des Dopplereffektes benötigt. SetVelocity() Setzt den aktuellen Velocity-Wert des Listenerobjektes. → DirectSound3DListener.GetVelocity() object.SetVelocity(x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
x,y,z
Neuer Vektor, der die Geschwindigkeit beschreibt.
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Velocity wird zum Errechnen des Dopplereffektes benötigt. DirectSound3DListener.SetVelocity(x As Single, _ y As Single, z As Single, applyFlag As CONST_DS3DAPPLYFLAGS) DirectSound3DListener.GetVelocity() As D3DVECTOR
Kapitel 4 • DirectSound
323
Velocity (2,0,2)
(2,0,2)
(4,0,4) (7,0,6)
langsamme Bewegung Bild 4.8:
schnelle Bewegung
Velocity
4.18.10 Beispiel (Klangquellen im 3D-Raum) Anhand des nachfolgenden Listings zeigen wir die Möglichkeiten einer dreidimensionalen Schallquelle auf. Den Quellcode finden Sie auch auf der beiligenden CD-Rom. CreateSoundBufferFromFile() Erstellt einen DirectSoundBuffer von einer Wavedatei. object.CreateSoundBufferFromFile(filename As String, _ bufferDesc As DSBUFFERDESC, _ format As WAVEFORMATEX) As DirectSoundBuffer object
ein gültiges DirectSound-Objekt
filename
Dateiname eines Wavefiles
bufferDesc
DSBUFFERDESC Typ beinhaltet die Beschreibung zum Erstellen eines Soundbuffers.
format
WAVEFORMATEX Typ beschreibt das Wellenformat der Audiodaten.
CreateSoundBuffer() Erstellt einen DirectSoundBuffer. → DSBUFFERDESC, DirectSound.DuplicateSoundBuffer(), DirectSound.SetCooperativeLevel(), DirectSoundBuffer(), DirectSoundBuffer.GetFormat(), DirectSoundBuffer.GetVolume(), DirectSoundBuffer.Play(), DirectSoundBuffer.SetFormat(), DirectSoundBuffer.SetFrequency() object.CreateSoundBuffer(bufferDesc As DSBUFFERDESC, _ format As WAVEFORMATEX) As DirectSoundBuffer
324
DirectSound3DListener
CreateSoundBuffer() Object
ein gültiges DirectSound-Objekt
BufferDesc
DSBUFFERDESC Typ beinhaltet die Beschreibung zum Erstellen eines Soundbuffers.
format
WAVEFORMATEX Typ beschreibt das Wellenformat der Audiodaten.
GetDirectSound3DBuffer() Gibt ein DirectSound3DBuffer Objekt zurück. object.GetDirectSound3DBuffer() As DirectSound3DBuffer object
ein gültiges DirectSoundBuffer-Objekt
Variablendeklaration: Dim m_dx As New DirectX7 Dim m_ds As DirectSound Dim m_dsBuffer(2) As DirectSoundBuffer Dim m_ds3dBuffer(2) As DirectSound3Dbuffer Dim m_dsPrimaryBuffer As DirectSoundBuffer Dim m_dsListener As DirectSound3Dlistener Dim m_pos(2) As D3DVECTOR Private Sub Form_Load() Dim i As Integer Me.Show DoEvents On Local Error Resume Next Set m_ds = m_dx.DirectSoundCreate("") If Err.Number <> 0 Then MsgBox "DirectSound ist nicht installiert oder Audiogerät _ wurde nicht gefunden" End End If m_ds.SetCooperativeLevel Me.hWnd, DSSCL_PRIORITY Dim primDesc As DSBUFFERDESC, format As WAVEFORMATEX
Flags für primären 3D-Buffer setzen und Listener zuweisen: primDesc.lFlags = DSBCAPS_CTRL3D Or DSBCAPS_PRIMARYBUFFER Set m_dsPrimaryBuffer = m_ds.CreateSoundBuffer(primDesc, _ format) Set m_dsListener = m_dsPrimaryBuffer.GetDirectSound3DListener()
Zwei Schallquellen laden: LoadWave 0, App.Path & "\Sound_5.wav" LoadWave 1, App.Path & "\Sound_6.wav"
Kapitel 4 • DirectSound
325
Koordinaten im 3D-Raum der beiden Schallquellen festlegen: m_pos(0).x = 10: m_pos(0).z = 50 m_pos(1).x = -10: m_pos(1).z = 50 HScroll1_Change i Slider1_Change DrawPositions End Sub
Routine zum Einlesen der Sounds: Sub LoadWave(i As Integer, file As String) Dim bufferDesc1 As DSBUFFERDESC Dim waveFormat1 As WAVEFORMATEX
Flags für Frequenz, Pan, Lautstärke, statischen Buffertyp und zusätzlichen 3DSound setzen: bufferDesc1.lFlags = (DSBCAPS_CTRL3D Or DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLPAN Or DSBCAPS_CTRLVOLUME) Or DSBCAPS_STATIC
Soundbuffer erzeugen und Sounds einlesen. Beim Laden werden die Bufferbeschreibung BufferDesc1 und das Waveformat waveFormat1 gesetzt. Set m_dsBuffer(i) = m_ds.CreateSoundBufferFromFile (file, _ bufferDesc1, waveFormat1)
Soundbuffer einem 3D-Buffer zuweisen: Set m_ds3dBuffer(i) = m_dsBuffer(i).GetDirectSound3Dbuffer HScroll1_Change i
Abstrahlrichtung der Soundquelle: m_ds3dBuffer(i).SetConeAngles DS3D_MINCONEANGLE, 100, _ DS3D_IMMEDIATE m_ds3dBuffer(i).SetConeOutsideVolume -400, DS3D_IMMEDIATE
Position im 3D-Raum setzen: m_ds3dBuffer(i).SetPosition m_pos(i).x / 50, 0, _ m_pos(i).z / 50, DS3D_IMMEDIATE End Sub
Soundbuffer über die Play-Methode abspielen: Private Sub Command1_Click() m_dsBuffer(0).Play 1 m_dsBuffer(1).Play 1 End Sub
326
DirectSound3DListener
Soundbuffer anhalten und Play-Cursor auf Position 0 zurücksetzen: Private Sub Command3_Click() m_dsBuffer(0).Stop m_dsBuffer(1).Stop m_dsBuffer(0).SetCurrentPosition 0 m_dsBuffer(1).SetCurrentPosition 0 End Sub Private Sub HScroll1_Scroll(Index As Integer) HScroll1_Change Index End Sub Private Sub Slider1_Change() m_dsBuffer(0).SetVolume Slider1.Value m_dsBuffer(1).SetVolume Slider1.Value End Sub
Ausrichtung der Schallquelle errechnen: Private Sub HScroll1_Change(Index As Integer) Dim x As Single Dim z As Single x = 5 * Cos(3.141 * HScroll1(0).Value / 180) z = 5 * Sin(3.141 * HScroll1(0).Value / 180) DrawPositions m_ds3dBuffer(i).SetConeOrientation x, 0, z, DS3D_IMMEDIATE End Sub Private Sub UpdatePosition(ByVal i As Integer, _ ByVal x As Single, ByVal z As Single) m_pos(i).x = x – Picture2.ScaleWidth / 2 m_pos(i).z = z – Picture2.ScaleHeight / 2 DrawPositions m_ds3dBuffer(i).SetPosition m_pos(i).x / 50, 0, _ m_pos(i).z / 50, DS3D_IMMEDIATE End Sub Private Sub Picture2_MouseDown(Button As Integer, _ Shift As Integer, x As Single, z As Single) If Button = 2 Then i = 1 UpdatePosition i, x, z End Sub Private Sub Picture2_MouseMove(Button As Integer, _ Shift As Integer, x As Single, z As Single) If Button = 0 Then Exit Sub If Button = 2 Then i = 1
Kapitel 4 • DirectSound
UpdatePosition i, x, z End Sub Private Sub Picture2_Paint() DrawPositions End Sub Sub DrawPositions() Dim x As Integer Dim z As Integer Picture2.Cls DrawTriangle 0, Picture2.ScaleWidth / 2, _ Picture2.ScaleHeight / 2, 90 x = CInt(m_pos(0).x) + Picture2.ScaleWidth / 2 z = CInt(m_pos(0).z) + Picture2.ScaleHeight / 2 DrawTriangle RGB(255, 0, 0), x, z, HScroll1(0).Value x = CInt(m_pos(1).x) + Picture2.ScaleWidth / 2 z = CInt(m_pos(1).z) + Picture2.ScaleHeight / 2 DrawTriangle RGB(0, 0, 255), x, z, HScroll1(1).Value End Sub Sub DrawTriangle(col As Long, x As Integer, z As Integer, _ ByVal a As Single) Dim x1 As Integer Dim z1 As Integer Dim x2 As Integer Dim z2 As Integer Dim x3 As Integer Dim z3 As Integer Dim q As Integer a = 3.14159 * (a – 90) / 180 q = 10 x1 = q * Sin(a) + x z1 = q * Cos(a) + z x2 = q * Sin(a + 3.141 / 1.3) + x z2 = q * Cos(a + 3.141 / 1.3) + z x3 = q * Sin(a – 3.141 / 1.3) + x z3 = q * Cos(a – 3.141 / 1.3) + z Picture2.Line (x1, z1)-(x2, z2), col Picture2.Line (x1, z1)-(x3, z3), col Picture2.Line (x2, z2)-(x3, z3), col End Sub
327
328
4.19
DirectSound Capture
DirectSound Capture DirectSound ist nicht nur in der Lage, Wavedateien und andere Soundfiles abzuspielen, sondern eignet sich auch hervorragend zur Aufnahme von Samples. Die Aufnahme von Geräuschen erfolgt ebenso wie das Abspielen über Bufferobjekte. Allerdings stellt DirectSound für diesen Zweck eine eigene Bufferart zur Verfügung, den so genannten Capturebuffer. Wie auch der Soundbuffer stellt der Capturebuffer Befehle zur Steuerung und zur Abfrage der Aufnahmeposition sowie Statusinformationen bereit.
4.19.1 Erstellen eines Capturebuffers Anders als bei DirectSound, wo mehrere Sounds zu einem Mastersound zusammengemischt werden und dann über die Soundkarte zu hören sind, wird nun vom Eingang der Soundkarte, genauer gesagt vom Ausgang des Windows-Mixers, das Summensignal aufgezeichnet. DirectSoundCapture erlaubt nur die Existenz eines Capturebuffers. CreateCaptureBuffer() Erstellt einen Capturebuffer der die Sounddaten aufnimmt. object.CreateCaptureBuffer(bufferDesc As DSCBUFFERDESC) _ As DirectSoundCaptureBuffer object
ein gültiges DirectSoundCapture-Objekt
bufferDesc
Bufferbeschreibung vom Typ DSCBUFFERDESC
GetCaps() Beschreibt die Fähigkeiten des Aufnahmegeräts. object.GetCaps(caps As DSCCAPS) object
ein gültiges DirectSoundCapture-Objekt
caps
vom Typ DSCCAPS
ReadBuffer() Liest ein Segment aus einem Soundbuffer und speichert dieses in einer Variablen vom Typ Array. object.ReadBuffer(start As Long, size As Long, buffer As Any, _ flags As CONST_DSBLOCKFLAGS) object
ein gültiges DirectSoundBuffer-Objekt
start
Offset in Bytes (Position, ab der gelesen werden wird)
Kapitel 4 • DirectSound
329
ReadBuffer() size
Anzahl der Bytes, die gelesen werden.
buffer
Variable vom Typ Any, die die Sounddaten aufnimmt.
flags
vom Typ CONST_DSBLOCKFLAGS
WriteBuffer() Schreibt ein Segment in einen Soundbuffer. object.WriteBuffer(start As Long, size As Long, buffer As Any, _ flags As CONST_DSBLOCKFLAGS) object
ein gültiges DirectSoundBuffer-Objekt
start
Offset in Bytes, ab wo geschrieben werden soll.
size
Anzahl der Bytes, die geschrieben werden.
buffer
Variable die die Sounddaten enthällt.
flags
vom Typ CONST_DSBLOCKFLAGS
Start() Setzt den Capturebuffer in den Aufnahmezustand und beginnt mit dem Schreiben der ankommenden Sounddaten in den Capturebuffer. Befindet sich der Capturebuffer im Aufnahmezustand, hat diese Methode keine Auswirkung. object.Start(flags As CONST_DSCBSTARTFLAGS) object
ein gültiges DirectSoundCaptureBuffer-Objekt
flags
vom Typ CONST_DSCBSTARTFLAGS
Stop() Setzt den Capturebuffer in den Ruhezustand und hält die Aufzeichnung der Sounddaten an. Befindet sich der Capturebuffer im Ruhezustand, hat diese Methode keine Auswirkung. object.Stop() object
ein gültiges DirectSoundCaptureBuffer-Objekt
WriteBuffer() Schreibt Sounddaten aus einem Array in ein Segment des Capturebuffers. → DirectSoundCaptureBuffer.ReadBuffer() object.WriteBuffer(start As Long, size As Long, buffer As Any, _ flags As CONST_DSCBLOCKFLAGS) object
ein gültiges DirectSoundCaptureBuffer-Objekt
330
DirectSound Capture
WriteBuffer() start
Offset in Bytes (Position, ab der geschrieben wird)
size
Anzahl der Bytes, die geschrieben werden.
buffer
Variable vom Typ Any, die die Sounddaten enthält.
flags
vom Typ CONST_DSCBLOCKFLAGS
GetCurrentPosition() Empfängt die aktuelle Aufnahme- und Abspielposition im Buffer. object.GetCurrentPosition(cursors As DSCURSORS) object
ein gültiges DirectSoundCaptureBuffer-Objekt
cursors
vom Typ DSCURSORS
GetStatus() Gibt den aktuellen Zustand eines Capturebuffers zurück. object.GetStatus() As CONST_DSCBSTATUSFLAGS object
ein gültiges DirectSoundCaptureBuffer-Objekt
Ein Capturebuffer wird über die Methode DirectSoundCapture.CreateCaptureBuffer() erstellt. Mit den zu übergebenden Einstellungen, die in der Bufferbeschreibung DSCBUFFERDESC vordefiniert werden, gibt die CreateCaptureBuffer-Funktion ein gültiges Capturebuffer-Objekt zurück. objekt.CreateCaptureBuffer(bufferDesc As DSCBUFFERDESC) As DirectSoundCaptureBuffer Type DSCBUFFERDESC fxFormat As WAVEFORMATEX lBufferBytes As Long lFlags As CONST_DSCBCAPSFLAGS End Type
Eigenschaften über das Aufnahmegerät werden mit der DirectSoundCapture.GetCaps()-Methode zurückgegeben. Sie enthalten Informationen über die eingestellte Kanalzahl, Aufnahmeparameter und das aktuelle Wellenformformat. DirectSoundCapture.GetCaps(caps As DSCCAPS)
4.19.2 Erläuterung zur Aufnahme Das Beispiel finden Sie auf der CD unter DirectSound – Beispiel 7. Dim dx As New DirectX7 Dim ds As DirectSound
Kapitel 4 • DirectSound
Dim dsb As DirectSoundBuffer Dim dsd As DSBUFFERDESC Dim dscb As DirectSoundCaptureBuffer Dim dscd As DSCBUFFERDESC Dim CaptureWave As WAVEFORMATEX Dim capCURS As DSCURSORS Dim ByteBuffer() As Integer Dim CNT As Integer Dim cCaps As DSCCAPS Dim gfPlay As Boolean Private Sub Form_Load()
DirectSoundCapture-Objekt erstellen: Set dsc = dx.DirectSoundCaptureCreate(vbNullString)
DirectSound Objekt erstellen: Set ds = dx.DirectSoundCreate(vbNullString) gfPlay = True
Zugriff für andere Anwendungen bestimmen: ds.SetCooperativeLevel Me.hWnd, DSSCL_NORMAL
Capture initialisieren: InitCapture
Schaltflächen vorbereiten: cmdSaveToFile.Enabled = False cmdPlayRec.Enabled = False cmdStopPlaying.Enabled = False cmdStopRec.Enabled = False Label1.Caption = vbNullString End Sub Private Sub cmdSaveToFile_Click() On Error Goto Fehler Dim FileLocal As String
Aufgenommene Daten in Soundbuffer konvertieren: ConvertToSBuffer CmdStopPlaying.Enabled = False Timer1.Enabled = False Label1.Caption = vbNullString CNT = 0 svFile.Filter = "*.wav"
331
332
DirectSound Capture
svFile.DialogTitle = "Save Wave File" svFile.ShowSave FileLocal = svFile.filename
Sound abspeichern: dsb.SaveToFile FileLocal Fehler: End Sub Private Sub cmdPlayRec_Click()
Überspielen der Sounddaten vom Capturebuffer in den Soundbuffer: ConvertToSBuffer dsb.Play DSBPLAY_DEFAULT Timer1.Enabled = True CNT = 0 Label1.Caption = vbNullString If gfPlay Then cmdStopPlaying.Enabled = True End Sub Private Sub cmdStartRec_Click() Set dscb = Nothing
Capturebuffer initialisieren: Call InitCapture
Aufnahme starten: dscb.start DSCBSTART_DEFAULT
Schaltflächen einstellen: Timer1.Interval = 1000 Timer1.Enabled = True cmdStopRec.Enabled = True cmdStartRec.Enabled = False End Sub Private Sub cmdStopPlaying_Click() Dim l_st As Long Dim l_soundStatus As Long
Soundbuffer anhalten und Position zurücksetzen: dsb.Stop dsb.SetCurrentPosition 0 Timer1.Enabled = False
Kapitel 4 • DirectSound
CNT = 0 Label1.Caption = vbNullString cmdStopPlaying.Enabled = False End Sub Private Sub cmdStopRec_Click() Dim l_bufferS As Long cmdSaveToFile.Enabled = True
Aufnahme anhalten: dscb.Stop Timer1.Enabled = False CNT = 0 Label1.Caption = vbNullString cmdStartRec.Enabled = True cmdStopRec.Enabled = False End Sub Private Sub ConvertToSBuffer()
Statischen Soundbuffer erzeugen: dscb.GetCurrentPosition capCURS dsd.lBufferBytes = capCURS.lWrite * dscd.fxFormat.nBlockAlign dsd.lFlags = DSBCAPS_CTRLVOLUME Or DSBCAPS_STATIC Set dsb = ds.CreateSoundBuffer(dsd, dscd.fxFormat)
Sounddaten von Capture in Soundbuffer überspielen: ReDim ByteBuffer(capCURS.lWrite * _ dscd.fxFormat.nBlockAlign + 1) dscb.ReadBuffer 0, capCURS.lWrite * _ dscd.fxFormat.nBlockAlign, ByteBuffer(0), DSCBLOCK_DEFAULT dsb.WriteBuffer 0, capCURS.lWrite * _ dscd.fxFormat.nBlockAlign, ByteBuffer(0), DSBLOCK_DEFAULT End Sub Private Function WaveEx(Hz As Long, _ Channels As Integer, BITS As Integer)
Wellenformat einstellen: With WaveEx .nFormatTag = WAVE_FORMAT_PCM .nChannels = Channels .lSamplesPerSec = Hz .nBitsPerSample = BITS .nBlockAlign = Channels * BITS / 8
333
334
DirectSound Capture
.lAvgBytesPerSec = WaveEx.lSamplesPerSec *_ .nBlockAlign .nSize = 0 End With End Function Private Sub InitCapture()
Capturebuffer vorbereiten und erzeugen: dsc.GetCaps cCaps If cCaps.lFormats And WAVE_FORMAT_2M08 Then CaptureWave = WaveEx(22050, 1, 8) ElseIf cCaps.lFormats And WAVE_FORMAT_1M08 Then CaptureWave = WaveEx(11025, 1, 8) Else MsgBox "Aufnahmen sind mit dieser _ Soundkarte nicht möglich!", vbApplicationModal End End If dscd.fxFormat = CaptureWave dscd.lBufferBytes = CaptureWave.lAvgBytesPerSec * 20 dscd.lFlags = DSCBCAPS_WAVEMAPPED Set dscb = dsc.CreateCaptureBuffer(dscd) End Sub Private Sub Form_QueryUnload(Cancel As Integer, _ UnloadMode As Integer) Call CleanUp End End Sub Private Sub CleanUp()
DirectSound Reset: Set dx = Nothing Set ds = Nothing Set dsb = Nothing Set dsc = Nothing Set dscb = Nothing Erase ByteBuffer End Sub Private Sub mnuExit_Click() Unload Me End Sub Private Sub Timer1_Timer()
Kapitel 4 • DirectSound
On Error Resume Next CNT = CNT + 1
Abfragen, ob Aufnahmelänge von 19 Sekunden überschritten ist: If CNT = 19 Then dscb.Stop Label1.Caption = "Full" Form1.Refresh Timer1.Enabled = False cmdSaveToFile.Enabled = True If gfPlay Then cmdPlayRec.Enabled = True If gfPlay Then cmdStopPlaying.Enabled = True Exit Sub End If Label1.Caption = CNT
Überprüfen des Soundbuffer-Zustandes: Dim l_sBs As Long If Not (dsb Is Nothing) Then l_sBs = dsb.GetStatus() If (l_sBs And DSBSTATUS_PLAYING) Then Else If cmdStartRec.Enabled = True Then Timer1.Enabled = False CNT = 1 Label1.Caption = vbNullString cmdStopPlaying.Enabled = False End If End If End If End Sub
335
Kapitel 5 DirectPlay 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10 5.11 5.12
DirectPlay-Basis Beispiel (Chatsystem) Kommunikationsmodelle Lobbies Service Provider Sicherheit Nachrichten DirectPlay-Adresse DirectPlay-Protokoll Session Spieler Bienenjagd Multiplayer Demo
341 352 355 357 358 358 359 363 364 365 369 372
338
Mit DirectPlay ist es möglich, Multispieler-Games, Chat Clients, Gameserver und andere Netztwerkanwendungen zu erstellen. Der Programmierer muss sich dabei nicht (oder nur wenig) um die verwendeten Übertrgungsprotokolle kümmern, sondern findet durch DirectPlay einen einheitlichen Befehlssatz. Die unterstüzten Provider reichen von Internetsystemen über Modem- oder LAN-Verbindungen bis zu PC-Direktverbindungen.
Anwendung DirectPlay Interface DirectPlay Service Provider TCP/IP Internet Bild 5.1:
IPX LAN
TAPI Modem
NetX private Netzwerke
DirectPlay im Überblick
Möchte man eine DirectX-Anwendung eine Verbindung zu anderen Rechnern aufbauen, um über diese Verbindung Daten zur Verwaltung und zum Betrieb einer Spielesitzung auszutauschen, so ist nach folgendem Muster vorzugehen: •
Erzeugung eines DirectPlay-Objekts.
•
Ermittlung der Connection. Dabei handelt es sich um Datenblöcke, die Informationen zum Verbindungsaufbau mit einem Service-Provider enthalten.
•
Abschluss der Initialisierung des DirectPlay-Objekts nach erfolgter Auswahl einer bestimmten Verbindung.
•
Bestimmung der bereits existierenden Sessions. Eine solche Sitzung besteht hierbei aus einem oder mehreren Spielern, die über DirectPlay eine entsprechende Verbindung aufgebaut haben.
•
Eintreten in eine bestehende oder Erzeugung einer neuen Sitzung.
•
Session-Management
Kapitel 5 • DirectPlay
339
Bei einer Session handelt es sich, wie bereits gesagt, um eine gewisse Zahl von Spielern, die sich jeweils über ein eigenes DirectPlay-Objekt einem gemeinsamen Kommunikationskanal angeschlossen haben. Es soll nun in kurzen Worten der Aufbau einer solchen Sitzung beschrieben werden. Nach dem Anlegen eines Spielers in einer bereits bestehenden oder in einer neuen Sitzung kann dieser Nachrichten mit Teilnehmern der Session austauschen. Jede DirectPlay-Sitzung besitzt gewisse Eigenschaften. Um diese zu verwalten, existiert im Allgemeinen ein Besitzer (host) für jede Session, der als einziger die Einstellungen verändern kann. Verlässt dieser Gastgeber die Sitzung, so gibt es folgende beiden Möglichkeiten: Die Verwaltung der Sitzung geht an einen anderen Rechner über, der von diesem Zeitpunkt an als Gastgeber fungiert. Welchem Rechner diese neue Aufgabe zugewiesen wird, kann von den Teilnehmern der Session nicht beeinflusst werden. Die Sitzung wird ohne einen definierten »host« weitergeführt. Dies hat jedoch zur Folge, dass keine Kommunikationseinstellungen mehr verändert werden und auch keine neuen Teilnehmer mehr in die Sitzung eintreten können. Die Session wird nach außen hin unzugänglich/verborgen. Computer 4
Computer 1 Host
DirectPlay Session
Computer 3
Computer 2
Bild 5.2:
Session
Eine der gerade angesprochenen Einstellungen ist beispielsweise der Schutz der Sitzung. Abgesehen von der nach außen offenen Sitzung existieren noch die Möglichkeiten, Sitzungen mit den Prädikaten wie password protected (dies erfordert ein Passwort für den Beitritt, die Sitzung ist jedoch nach außen hin sichtbar) oder private (eine solche Sitzung ist von außen nur mit dem gültigen Paßwort sichtbar, sodass auch nur nach einer entsprechenden Authentifikation der Anschluss an eine solche Session möglich ist) anzulegen. •
Spieler & Gruppen
340
DirectPlay kennt nur den Spieler (oder eine Gruppe) als einzelnes Objekt innerhalb einer Session. Die Rechner, auf denen die verschiedenen DirectPlay-Objekte angelegt wurden, sind innerhalb einer Sitzung nicht weiter von Belang. So sind auch die Spieler Ausgangs- und Zielpunkt jedes Nachrichtentransfers. Aus diesem Grund benötigt jedes DirectPlay-Objekt mindestens einen Spieler. Andernfalls wäre die entsprechende Instanz innerhalb der Sitzung nicht mehr zu Interaktionen fähig. Lokale Spieler, sind Spieler, die auf dem gerade betrachteten Rechner angesiedelt sind, gibt es also pro Rechner mindestens einen. Entfernte (remote) Spieler, also Spieler, zu denen über die jeweilige Netzwerkverbindung Kontakt besteht, kann es geben, dies muss aber nicht der Fall sein. Besonders interessant ist die Möglichkeit, mehrere Spieler pro DirectPlay-Objekt anlegen zu können. Auf diese Weise können Spieler erzeugt werden, die vom Rechner gesteuert werden (Computerspieler). Des Weiteren unterstützt das DirectPlay-Interface den Zusammenschluss einer gewissen Anzahl von Spielern zu Gruppen. Diese Gemeinschaften müssen dabei nicht notwendigerweise disjunkt sein, sodass ein einzelner Spieler Mitglied in mehreren Gruppen sein kann. Spieler 1
Gruppe 1
Spieler 2 Spieler 3 Spieler 4
Gruppe 2
DirectPlay Session
Gruppe 3
Spieler 5 Spieler 6
Bild 5.3:
Gruppen
Nachrichten- und Datenaustausch: Die Unterscheidung von lokalen und entfernten Spielern sowie der Zusammenschluss verschiedener Spieler zu Gruppen haben unter anderem Einfluss auf den Nachrichtentransport. So werden Informationen zwischen lokalen Spielern nicht über das Netzwerk weitergeleitet, sondern vor Ort auf dem gemeinsamen Rechner ausgetauscht. Die Bildung von Gruppen bietet ein weiteres Mittel zur Bandbrei-
Kapitel 5 • DirectPlay
341
ten-Einsparung. Durch das Verwenden von multicasting kann die Belastung des Netzwerks vermindert werden, falls der Empfänger einer Nachricht eine Gruppe von Spielern ist. Bei einer Nachricht handelt es sich im Kontext von DirectPlay stets um eine der beiden folgenden Arten: custom messages: Dies sind selbstdefinierte Nachrichten mit einer expliziten Länge. Der übliche Austausch von Informationen zwischen Spielern verwendet diese Nachrichtenart. system messages: Hierbei handelt es sich um Nachrichten über die Verwaltung der Sitzung, die vom System selbstständig generiert werden. Zum Beispiel bewirkt der Eintritt eines neuen Spielers in eine Session die Benachrichtigung aller bisherigen Mitspieler. Der Austausch von Daten zwischen den einzelnen DirectPlay-Objekten erfolgt über lokale oder remote shared data areas, wobei eine automatische Propagierung etwaiger Datenänderungen an alle Teilnehmer einer Sitzung unterstützt wird. Für alle Nachrichten können noch folgende Optionen ausgewählt werden: Verschlüsselung, Signierung sowie die Einhaltung einer Garantie der Datensicherheit. Diese Option bewirkt, dass nur Daten, deren Integrität sichergestellt wurde, in die entsprechende Warteschlange (queue) aufgenommen werden.
5.1
DirectPlay-Basis DirectPlayCreate() Erzeugt ein DirectPlay4-Objekt. object. DirectPlayCreate (guid As String) As DirectPlay4 object
ein gültiges DirectX7-Objekt
guid
Identifikationsnummer des Service-Providers, an dem DirectPlay angemeldet wird. Wird ein leerer String übergeben, wird die Verbindung nicht initialisiert und die Applikation muss die DirectPlay4.InitializeConnection()-Methode ausführen.
In diesem Kapitel wollen wir den Basisweg zum Erstellen einer DirectPlayAnwendung demonstrieren. Wir benötigen acht Schritte für eine erste Basisanwendung.
342
DirectPlay-Basis
Schritt 1: Erstellen des DirectPlay-Objektes Das DirectPlay-Objekt wird mit der DirectX7.DirectPlayCreate()-Methode erstellt. Diese Methode beinhaltet nur den Parameter guid. Über ihn wird der Provider eindeutig identifiziert. Da man normalerweise noch nicht weiß, über welchen Provider die Verbindung hergestellt werden soll, übergeben wir einen leeren String. Dies hat zur Folge, dass wir später die Verbindung initialisieren müssen. Dim Dim Set Set
g_dx g_dp g_dx g_dp
As DirectX7 As DirectPlay4 = New DirectX7 = g_dx.DirectPlayCreate("")
Schritt 2: Auflisten der Provider GetDPEnumConnections() Erzeugt eine Liste mit allen registrierten Service sowie Lobby-Providern. object.GetDPEnumConnections(guid As String, flags As CONST_DPENUMCONNECTIONFLAGS) As DirectPlayEnumConnections object
ein gültiges DirectPlay4-Objekt
guid
Guid für die Anwendung
flags
DPCONNECTION_DIRECTPLAY Auflistung für DirectPlay-Service-Provider DPCONNECTION_DIRECTPLAYLOBBY Auflistung für DirectPlay-Lobby-Provider
GetCount() Ermittelt die Anzahl der Elemente im Auflistungsobjekt. object.GetCount() As Long object
ein gültiges DirectPlayEnumConnections-Objekt
GetName() Ermittelt den Namen einer Verbindung aus dem Auflistungsobjekt. object.GetName(index As Long) As String object
ein gültiges DirectPlayEnumConnections-Objekt
index
Element aus dem Auflistungsobjekt, von welchem die Information ermittelt werden soll.
Kapitel 5 • DirectPlay
343
Der Provider wird durch das DirectPlayEnumConnections-Objekt aufgelistet. Bevor wir an diese Auflistung herankommen, muss dieses Objekt erstellt werden. DirectPlay4.GetDPEnumConnections()-Methode übernimmt diese Aufgabe. Die Methode beinhaltet zwei Parameter. Der erste Parameter guid verlangt einen eindeutige Identifizierung. Übergeben wir einen leeren String, so werden alle Provider (Service-Provider und Lobby-Provider) dem DirectPlayEnumConnec tions-Objekt übergeben. Der zweite Parameter flags definiert, welche Art von Provider gesucht werden soll. Diese werden durch die CONST_DPENUMCON NECTIONSFLAGS-Konstantenliste beschrieben. Enum CONST_DPENUMCONNECTIONFLAGS DPCONNECTION_DIRECTPLAY = 1 DPCONNECTION_DIRECTPLAYLOBBY = 2 End Enum
Nachdem das DirectPlayEnumConnections-Objekt erstellt wurde, können wir die durch Windows registrierten Provider auslesen. Unter Windows98 werden Sie im Regelfall folgende Provider erhalten: •
IPX-Verbindung für DirectPlay
•
Internet TCP/IP-Verbindung für DirectPlay
•
Modemverbindung für DirectPlay
•
Serielle Verbindung für DirectPlay
Nicht alle aufgelisteten Provider stehen auch zur Verfügung. Das DirectPlayEnumConnections-Objekt liefert alle registrierten Provider. Diese sind aber erst einsatzbereit, wenn Sie die notwendigen Übertragungsprotokolle installiert haben. Wir werden vorzugsweise die IPX-Verbindung für DirectPlay benutzen. Da unsere Beispielanwendungen auf dieser Verbindung basieren, sollten Sie diese Verbindung unbedingt einrichten. Sollten Sie dies nicht wollen, so probieren Sie die Internet-TCP/IP-Verbindung für DirectPlay. Um das notwendige Protokoll zu installieren, führen Sie folgende Schritte durch: •
Öffnen Sie den Ordner »Systemsteuerung«.
•
Doppelklicken Sie auf das Symbol »Netzwerk«.
•
Wählen Sie »Hinzufügen«.
•
Selektieren Sie »Protokoll« und bestätigen Sie anschließend mit »Hinzufügen«.
•
Auf der linken Seite selektieren Sie »Microsoft« und auf der rechten Seite »IPX/SPX-kompatibles Protokoll«.
•
Bestätigen Sie mit »OK«.
344
DirectPlay-Basis
Kehren wir zum Auslesen der Provider zurück. Das folgende Listing überträgt die Provider an eine Listbox. Dim DirectPlayEnum As DirectPlayEnumConnections Set DirectPlayEnum = g_dp.GetDPEnumConnections("", _ DPCONNECTION_DIRECTPLAY) For i = 1 To DirectPlayEnum.GetCount List1.AddItem (DirectPlayEnum.GetName(i)) Next i
Schritt 3: Initialisieren der Verbindung GetAddress() Ermittelt ein Address-Objekt vom Auflistungsobjekt. object.GetAddress(index As Long) As DirectPlayAddress object
ein gültiges DirectPlayEnumConnections-Objekt
index
Element aus dem Auflistungsobjekt, von welchem die Information ermittelt werden soll.
InitializeConnection() Initialisiert eine DirectPlay-Verbindung. → DirectPlayAddress object. InitializeConnection (addr As DirectPlayAdress) object
ein gültiges DirectPlay4-Objekt
addr
ein DirectPlayAddress-Objekt Das DirectPlayAddress Objekt wird mit der DirectPlay4.GetDPEnumConnections()-Methode abgefragt.
Mit der DirectPlay4.InitializeConnection()-Methode richten wir die Verbindung ein. Sie verlangt den Parameter addr As DirectPlayAddress. Diesen Parameter erhalten wir von dem DirectPlayEnumConnections-Objekt. Hierzu steht uns die DirectPlayEnumConnections.GetAddress()-Methode bereit. Dim DirectPlayAdresse As DirectPlayAddress Set DirectPlayAdresse = DirectPlayEnum.GetAddress(i) g_dp.InitializeConnection DirectPlayAdresse
Kapitel 5 • DirectPlay
345
Schritt 5: Auflisten der bestehenden Sessions CreateSessionData() Erzeugt ein DirectPlaySessionData-Objekt object.CreateSessionData() As DirectPlaySessionData object
ein gültiges DirectPlay4-Objekt
GetDPEnumSessions() Erzeugt eine Liste mit allen aktiven Sessions. Die Auswahl der Sessions wird durch den Parametern flags eingegrenzt. object.GetDPEnumSessions( sessionDesc As DirectPlaySessionData, _ timeOut As Long, flags As CONST_DPENUMSESSIONFLAGS) _ As DirectPlayEnumSessions object
ein gültiges DirectPlay4-Objekt
sessionDesc
Ein DirectPlaySessionData-Objekt, welches die Liste der Sessions aufnimmt.
timeOut
Wartezeit in Millisekunden. Der Parameter kann 0 sein, dann wird die voreingestellte Wartezeit des Service-Providers genommen. Die Wartezeit des Service-Providers kann mit der DirectPlay4.GetCaps()Methode abgefragt werden.
flags
eine Konstante aus der CONST_DPENUMSESSIONSFLAGS-Liste
GetCount() Ermittelt die Anzahl der Elemente in dem DirectPlayEnumSessions-Objekt. object.GetType(index As Long) As Long object
ein gültiges DirectPlayEnumSessions-Objekt
GetItem() Erzeugt ein DirectPlaySessionData-Objekt, welches mit den repräsentativen Informationen der Session gefüllt ist. object.GetType(index As Long) As Long object
ein gültiges DirectPlayEnumSessions-Objekt
index
ein Element aus dem DirectPlayEnumSession-Objekt.
In Schritt 6 werden wir entscheiden, ob eine neue Session erstellt werden soll oder ob wir einer bestehenden Session beitreten. Um diese Entscheidung treffen zu können, müssen wir in Erfahrung bringen, welche Sessions bereits geöffnet sind. Die Informationen über die bestehenden Sessions werden in dem Direct
346
DirectPlay-Basis
PlayEnumSessions-Objekt erfasst. Um dieses Objekt zu füllen, benötigen wir noch ein DirectPlaySessionData-Objekt. Dieses wird die detaillierteren Informationen einer Session aufnehmen. Zum Erzeugen des DirectPlayEnumSessionsObjekts nutzen wir die DirectPlay4.GetDPEnumSessions()-Methode. Set SessionData = g_dp.CreateSessionData Set Session = g_dp.GetDPEnumSessions(SessionData, 0,_ DPENUMSESSIONS_ALL) For i = 1 To Session.GetCount List1.AddItem (Session.GetItem(i).GetSessionName) Next i
Schritt 6: Eine Session erzeugen oder einer Session beitreten Open() Erzeugt oder schließt sich einer Session an. → DirectPlay4.Close() object.Open(sessionDesc As DirectPlaySessionData, _ flags As CONST_DPOPENFLAGS) object
ein gültiges DirectPlay4-Objekt
sessionDesc
Ein DirectPlaySessionData-Objekt, welches die Informationen der Session enthält. Dieses Objekt wird mit der DirectPlay4CreateSessionData()-Methode erzeugt.
flags
DPOPEN_CREATE DPOPEN_JOIN DPOPEN_RETURNSTATUS
SetSessionName() Setzt den Sessionnamen. object.SetSessionName(val As String) object
ein gültiges DirectPlaySessionData-Objekt
val
Name der Session
SetMaxPlayers() Setzt die Anzahl der maximal zulässigen Spieler einer Session. object.SetMaxPlayers(val As Long) object
ein gültiges DirectPlaySessionData-Objekt
val
Anzahl der maximal zulässigen Spieler.
Kapitel 5 • DirectPlay
347
SetFlags() Setzt die Flags (Kennzeichnungen) einer Session. object.SetFlags(val As CONST_DPSESSIONFLAGS) object
ein gültiges DirectPlaySessionData-Objekt
val
Eine Konstante aus der CONST_DPSESSIONFLAGS-Liste
Für beide Möglichkeiten steht die DirectPlay4.Open()-Methode bereit. Sie verlangt zwei Parameter. Der erste Parameter sessionDesc ist ein Typenarray vom Typ DierctPlaySessionData. Dieses Typenarray haben wir in Schritt 5 mit der DirectPlay4.CreateSessionData()-Methode erzeugt und mit der DirectPlay4. GetDPEnumSessions()-Methode gefüllt. Der zweite Parameter flags kennzeichnet, ob wir einer Session beitreten oder eine neue Session erzeugen wollen. Einer Session beitreten: Um einer Session beizutreten, müssen wir lediglich die DirectPlay4.Open()Methode aufrufen. g_dp.Open SessionData, DPOPEN_JOIN
Eine Session erzeugen: Bevor wir eine Session erzeugen, können wir diese genauer beschreiben. Das DirectPlaySessionData-Objekt wurde bereits in Schritt 5 erzeugt. Diesem Typenarray müssen wir zumindest einen Sessionnamen mitteilen. Weiterhin können wir die Anzahl der maximal zulässigen Sessionmitglieder festlegen. Über das Setzen von Flags können wir das Verhalten der Session beeinflussen. Das DirectPlaySessionData Objekt werden wir noch genauer beschreiben. SessionData.SetSessionName “Session 1” SessionData.SetMaxPlayers 2 SessionData.SetFlags DPSESSION_MIGRATEHOST
Das Flag DPSESSION_MIGRATEHOST ist recht interessant. Es beeinflusst das Verhalten der Session. Sollte sich der Hostteilnehmer einer Session abmelden, so werden die Sessionmitglieder über dessen Ausscheiden informiert. Somit ist ein Sessionmitglied in der Lage, die Aufgaben des Hostteilnehmers zu übernehmen. g_dp.Open SessionData, DPOPEN_CREATE
348
DirectPlay-Basis
Schritt 7: Erzeugen eines Sessionmitglieds (Player) CreatePlayer() Erzeugt einen lokalen Spieler für die aktuelle Session. object.CreatePlayer(friendlyName As String, formalName As String, _ receiveEvent As Long, flags As CONST_DPPLAYERFLAGS) As Long object
ein gültiges DirectPlay4-Objekt
friendlyName
Rufname
formalName
Hausname
receiveEvent
Handle für ein Ereignis, welches ausgelöst wird, wenn eine Nachricht für diesen Spieler eintrift.
flags
DPPLAYER_SERVERPLAYER DPPLAYER_SPECTATOR Defaultwert ist 0 → Weder Serverplayer noch Spectator
Anhand der Namensgebung der Sessionmitglieder als Player können wir den bevorzugten Anwendungsbereich von DirectPlay erkennen. Es ist konzipiert um Netzwerkspiele zu realisieren. Dies ist kein Nachteil, sondern entspricht der Zielsetzung eines DirectX-Programmierers. Ein Player wird mit der DirectPlay4.CreatePlayer()-Methode erzeugt. Sie verlangt vier Parameter. Die ersten beiden Parameter friendlyName und und formal Name können Sie mit dem Rufnamen und dem Hausnamen vergleichen. Beide werden als String übergeben. Der dritte Parameter receiveEvent ist das Handel zu einem Event. Dieses wird immer dann aufgerufen, wenn eine Nachricht nur für diesen Player eingetroffen ist. Diesen Parameter kann man auf 0 setzten. Den letzten Parameter flags können wir ebenfalls auf 0 setzten. Er beschreibt den Playertyp. Zur Auswahl stehen die Konstanten DDPLAYER_SERVERPLAYER oder DPPLAYER_SPECTATOR. Der DDPLAYER_SERVERPLAYER kann nur vom Host eingesetzt werden. Die DirectPlay4.CreatePlayer()-Methode liefert als Rückgabewert eine Player ID. Diese ID ist einmalig in einer Session und wird zur Verwaltung der Teilnehmer verwendet. So können mehrere Teilnehmer mit dem gleichen Namen und dem gleichen Rufnamen einer Session beitreten und dennoch können Sie über die ID eindeutig identifiziert werden. PlayerName = "Player1" PlayerHandle = "HandelPlayer1" PlayerID1 = g_dp.CreatePlayer(PlayerName, PlayerHandle, 0, 0)
Kapitel 5 • DirectPlay
349
Schritt 8: Senden und Empfangen von Nachrichten CreateMessage() Erzeugt ein Message Objekt, welches mit Daten zum Senden gefüllt werden kann. → DirectPlay4.Send() object.CreateMessage() As DirectPlayMessage object
ein gültiges DirectPlay4-Objekt
Send() Sendet eine Nachricht an einen Spieler oder eine Gruppe von Spielern oder alle Spieler. → DirectPlay4.Receive(), DirectPlay4.SendChatMessage() object.Send(fromPlayerId As Long, toPlayerId As Long, _ flags As CONST_DPSENDFLAGS, msg As DirectPlayMessage) object
ein gültiges DirectPlay4-Objekt
fromPlayerId
Index des Spielers, welcher die Nachricht gesendet hat.
toPlayerId
Index des Spielers, für welchen die Nachricht bestimmt ist.
flags
DPSEND_ENCRYPTED DPSEND_GUARANTEED DPSEND_SIGNED
msg
Ein DirectPlayMessage-Objekt, welches die Nachricht enthält, die versendet werden soll.
WriteLong() Schreibt ein Long in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteLong(val As Long) object
ein gültiges DirectPlayMessage-Objekt
val
Wert
WriteString() Schreibt eine Zeichenkette in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteString(val As String) object
ein gültiges DirectPlayMessage-Objekt
val
Zeichenkette
350
DirectPlay-Basis
GetMessageCount() Ermittelt die Anzahl von Nachrichten in der Nachrichtenwareschlange für einen definierten lokalen Spieler. → DirectPlay4.Receive() object.GetMessageCount(playerId As Long) As Long object
ein gültiges DirectPlay4-Objekt
playerId
Index für einen Spieler
Receive() Empfängt Nachrichten aus der Nachrichtenwarteschlange. → DirectPlay4.Send() object.Receive(fromPlayerId As Long, toPlayerId As Long, _ flags As CONST_DPRECEIVEFLAGS) As DirectPlayMessage object
ein gültiges DirectPlay4-Objekt
fromPlayerId
Index des Spielers, welcher die Nachricht gesendet hat.
toPlayerId
Index des Spielers, für welchen die Nachricht bestimmt ist.
flags
DPRECEIVE_ALL DPRECEIVE_PEEK DPRECEIVE_TOPLAYER PRECEIVE_FROMPLAYER
ReadLong() Liest ein Long von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadLong() As Long object
ein gültiges DirectPlayMessage-Objekt
ReadString() Liest ein String von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadString() As String object
ein gültiges DirectPlayMessage-Objekt
Das Senden von Nachrichten ist recht einfach. Wir werden dabei von den DirectPlay4.Send()- und DirectPlay4.SendEx()-Methoden unterstützt. Dabei ist die DirectPlay4.SendEx()-Methode eine erweiterte Form der DirectPlay4 .Send()-Methode. Die DirectPlay4.Send()-Methode enthält vier Parameter. Mit den ersten beiden Parametern fromPlayerId und toPlayerId wird angegeben, von
Kapitel 5 • DirectPlay
351
wem die Nachricht kommt und an wen die Nachricht gerichtet ist. Die PlayerID wurde in Schritt 7 erzeugt. Der dritte Parameter flags indiziert, wie die Nachricht gesendet werden soll. Zur Auswahl stehen die Konstanten DPSEND_ENCRYPTED, DPSEND_GUARANTEED und DPSEND_SIGNED. Als letzter Parameter msg folgt die eigentliche Nachricht. Diese wird als DirectPlayMessageObjekt übergeben. Dieses wird mit der DirectPlay4.CreateMessage()-Methode erzeugt. Nachdem das Objekt existiert, wird dieses mit den gewünschten Informationen gefüllt und dann versandt. Dim ChatMsg As DirectPlayMessage Set ChatMsg = g_dp.CreateMessage Call ChatMsg.WriteLong(DPSYS_CHAT) Call ChatMsg.WriteString(”Testnachricht”) Call g_dp.Send(PlayerID1, DPID_ALLPLAYERS, DPSEND_GUARANTEED, _ ChatMsg)
Das Empfangen der Nachrichten kann man auf zwei Arten gestalten. Zum einen kann man ein Event einrichten. Dieses wird dann immer aktiviert, wenn eine neue Nachricht eintrifft. Der andere Weg ist, dass Sie regelmäßig die Nachrichten abfragen. Diese manuelle Abfrage kann man recht gut mit einer Do...Loop() Schleife verbinden. Die Nachrichten werden in zwei Kategorien eingeteilt. Die erste Kategorie sind die Systemnachrichten. Diese werden über das Netzwerk versandt, ohne dass Sie dies beeinflussen können. Dazu zählen Informationen wie das Eintreten eines neuen Players in einer Session oder das Ausscheiden des Hostteilnehmers. Die zweite Kategorie sind die Spielernachrichten. Diese werden explizit erzeugt. Die Unterscheidung der beiden Kategorien ist wichtig, da Sie bei der Auswertung der Nachrichten auf die unterschiedlichen Typen unterschiedlich reagieren können. Die Abfrage der Nachrichtenwarteschlange erfolgt mit der DirectPlay4.Receive()-Methode. Sie beinhaltet drei Parameter. Die beiden ersten Parameter fromPlayerId und toPlayerId benennen, von wem die Nachricht kommt und an wen die Nachricht gerichtet ist. Hierzu muss als drittes Argument DPRECEIVE_FROMPLAYER bzw. DPRECEIVE_TOPLAYER hinzugefügt werden. Um alle Nachrichten zu empfangen, setzen Sie den dritten Parameter auf DPRECEIVE_ALL. Public Sub GetMessages() Dim MsgCount As Long Dim MsgType As Long Dim FromPlayerID As Long Dim ToPlayerID As Long Dim dpMsg As DirectPlayMessage MsgCount = g_dp.GetMessageCount(0) For x = 1 To MsgCount Set dpMsg = g_dp.Receive(FromPlayerID, ToPlayerID, _ DPRECEIVE_ALL) MsgType = dpMsg.ReadLong()
352
Beispiel (Chatsystem)
Select Case MsgType Case DPSYS_DESTROYPLAYERORGROUP
Wird ausgelöst, wenn ein Player die Session verlässt. Case DPSYS_CREATEPLAYERORGROUP
Wird ausgelöst, wenn ein Player der Session beitritt. Case DPSYS_HOST
Wird ausgelöst bei Nachrichten, welche den Host Teilnehmer betreffen. Case DPSYS_CHAT
Wird ausgelöst bei Nachrichten, welche als Chat deklariert sind. Beim Senden der Nachricht haben wir die Nachricht als Chat definiert. Call ChatMsg.WriteLong(DPSYS_CHAT).
Jetzt können wir die Nachricht spezifisch wieder auslesen. Dim Nachricht As String Nachricht = dpMsg.ReadString End Select Next x End Sub
5.2
Beispiel (Chatsystem) Dieses Beispiel richtet ein kleines Netzwerkkommunikationssystem ein. Sie haben die Möglichkeit, eine neue Session zu erstellen oder einer Session beizutreten. Der Hostteilnehmer wird über das Eintreten oder Ausscheiden eines neuen Teilnehmers informiert. Sollte sich der Hostteilnehmer abmelden, so wird der Gastteilnehmer darüber informiert und das Programm beendet. Zum Kommunikationssystem gehört das Austauschen von Nachrichten. Diese Nachrichten werden als Chatnachrichten deklariert. Das Programm beginnt mit Form2. Hier erhalten Sie eine Auswahl der verfügbaren Provider. Für die Auflistung der Provider ist die Form_Load()-Subroutine zuständig. Private Sub Form_Load() Set g_dx = New DirectX7 Set g_dp = g_dx.DirectPlayCreate("")
Direkt zum Anfang des Programms richten wir das DirectX7 sowie das DirectPlay4-Objekt ein.
Kapitel 5 • DirectPlay
Bild 5.4:
353
Bildschirmfoto Chatsystem
Set DirectPlayEnum = g_dp.GetDPEnumConnections("", _ DPCONNECTION_DIRECTPLAY) If DirectPlayEnum.GetCount = 0 Then End For i = 1 To DirectPlayEnum.GetCount List1.AddItem (DirectPlayEnum.GetName(i)) Next i
Wir füllen das DirectPlayEnumConnections-Objekt mit Hilfe der Direct Play4.GetDPEnumConnections()-Methode. Nachdem wir die Daten erhalten haben, können wir dieses Objekt über eine kleine For...Next-Schleife auslesen. Label1(4) = DirectPlayEnum.GetGuid(1) Label1(5) = DirectPlayEnum.GetName(1) Set DirectPlayAdresse = DirectPlayEnum.GetAddress(1)
354
Beispiel (Chatsystem)
Wichtig ist es, dass wir uns die Provideradresse merken. Diese benötigen wir zum Initialisieren der Verbindung. End Sub
Nachdem wir uns für einen Provider entschieden haben können wir das Programm mit dem weiter-Button fortsetzten. Die Form_Load()-Subroutine von Form1 initialisiert die Verbindung und sammelt Informationen über die bestehenden Sessions. Private Sub Form_Load() g_dp.InitializeConnection DirectPlayAdresse
Mit der DirectPlay4.InitializeConnection()-Methode wird die DirectPlay-Verbindung hergestellt. Alle Informationen über die Verbindung wie Provider, Netzwerkadresse des Servers oder Guid der Session sind in dem DirectPlayAddressObjekt enthalten. Set SessionData = g_dp.CreateSessionData Set Session = g_dp.GetDPEnumSessions(SessionData, 0, _ DPENUMSESSIONS_ALL)
Nun benötigen wir Informationen über geöffnete Sessions. Hierzu erstellen wir mit der DirectPlay4.CreateSessionData()-Methode eine DirectPlaySessionDataObjekt. Dieses wird mit der DirectPlay4.GetDPEnumSessions()-Methode gefüllt. Anschließend können wir uns die geöffneten Sessions in der ListBox List1 anzeigen lassen. Je nachdem, ob wir eine offene Session gefunden haben, erlauben wir das Erzeugen einer neuen Session oder lediglich das Eintreten in eine bestehende Session. List1.Clear For i = 1 To Session.GetCount List1.AddItem (Session.GetItem(i).GetSessionName) Next i If Session.GetCount = 0 Then Command2.Enabled = False Command1.Enabled = True Else Command2.Enabled = True Command1.Enabled = False Text1(0).Enabled = False End If Form1.Visible = True Form1.ZOrder 0 Do While DoEvents() GetMessages Loop
Kapitel 5 • DirectPlay
355
Die Do...Loop-Schleife fängt bereits jetzt mit der Abfrage von DirectPlay-Nachrichten an. Sie ist so lange aktiv, bis alle Fenster geschlossen wurden. End Sub
Sollten wir keine offene Session gefunden haben, können Sie eine neue Session erstellen.
5.3
Kommunikationsmodelle
5.3.1
Peer-to-Peer-Session In einer Peer-to-Peer-Session sind mehrere Computer gleichberechtigt miteinander verbunden. Einer der angeschlossenen Computer übernimmt die Aufgabe des Servers. Gleichzeitig werden diesem Teilnehmer die Aufgaben des Gastgebers einer Session übertragen. Er verwaltet die restlichen Teilnehmer der Session. So vergibt er ID’s für neue Spieler oder Gruppen oder stellt die Sessioninformationen zur Verfügung. Neben den verwaltenden Aufgaben ist der Gastgeber (Host) gleichzeitig ein normales Mitglied der aktuellen Session. Nachrichten müssen nicht über den Host an andere Mitglieder verteilt werden, sondern können direkt von einem Spieler zu einem anderen Spieler geleitet werden. Ebenfalls ist der Host nicht für alle Systemnachrichten verantwortlich. Jeder an die Session angeschlossene Computer generiert eigene Systemnachrichten, welche (je nach Typ) automatisch verteilt werden. Anwendung Computer A
Kommunikation Anwendung Computer B
Anwendung Computer D Host
Bild 5.5:
Anfragen um sich der Session anzuschließen
Peer-to-Peer
Sessioninformationen
Anwendung Computer C
356
Kommunikationsmodelle
In einer Peer-to-Peer DirectPlay Session kommunizieren die einzelnen Computer direkt miteinander. Wenn ein Teilnehmer eine Nachricht an alle Teilnehmer der Session senden möchte, so kann er die Multisendemöglichkeiten des Providers nutzen. Sollte der Provider das Versenden von Nachrichten an mehrere oder alle Teilnehmer nicht unterstützen, so muss die Nachricht expliziet an jeden Teilnehmer geleitet werden. Anwendung Computer A
Anwendung Computer B
Anwendung Computer C
Anwendung Computer D Host Bild 5.6:
5.3.2
Nachrichtenaustausch Peer-to-Peer
Client/Server-Session Eine Client/Server-Session unterscheidet sich von der Peer-to-Peer-DirectPlaySession. Genauso wie bei der Peer-to-Peer-Session übernimmt ein Computer die Aufgaben des Servers. Im Regelfall läuft auf dem Server ein spezielles Serverprogramm. Auf den Clientcomputern laufen spezielle Clientprogramme. Auch in diesem Kommunikationsmodell übernimmt der Server alle verwaltenden Aufgaben. Er vergibt neue IDs für eintretende Teinehmer oder Gruppen. Die einzelnen Computer stehen in keiner direkten Verbindung zueinander. Alle Nachrichten werden über den Server geleitet. Wenn ein Teilnehmer eine Nachricht an alle Teilnehmer der Session senden möchte, so wird er die Nachricht zuerst an den Server leiten. Diese Nachricht ist mit der Bitte verbunden, diese an alle Teilnehmer der Session zu leiten. Das spezielle Serverprogramm entscheidet nun, ob es der Bitte nachkommen soll. Wenn dies der Fall ist, so wird jeder Teilnehmer der Session vom Server mit der Nachricht versorgt. Im Regelfall gehört der Server nicht zu den Spielern einer Session. Es besteht allerdings die Möglichkeit, eine Kombination aus Peer-to-Peer und Client/Server zu erstellen. In dieser Mischform einer Session stehen den Teilnehmern alle Vor-
Kapitel 5 • DirectPlay
357
züger der Peer-to-Peer-DirectPlay-Session inklusive eines Serverspielers zur Verfügung. Diese Form unterscheidet sich von einer reinen Peer-to-Peer-Session nur geringfügig. Der Unterschied liegt darin, dass alle Nachrichten über den Server geleitet werden. In der reinen Client/Server-Session existiert kein Serverspieler. Alle Nachrichten werden an den Server geleitet. Dieser ist dann in der Lage zu entscheiden, was mit den Nachrichten geschehen soll. Nicht nur explizit von den Teilnehmern versendete Nachrichten gelangen zum Server, sondern auch automatisch erstellte Systemnachrichten finden den Weg zum Server.
Anwendung Computer A
Anwendung Computer B
Computer D Server
Anwendung Computer E
Anwendung Computer C Bild 5.7:
5.4
Nachrichten Client/Server
Lobbies Eine DirectPlay-Lobby ist ein zentraler Platz im Netzwerk. An diesem Ort findet man geöffnete Sessions sowie teilnehmende Spieler. Der Teilnehmer kann sich an diesem Ort frei bewegen und wenn etwas sein Interesse erweckt, so kann er der jeweiligen Session betreten. Natürlich kann der Teilnehmer auch eine eigene Session gründen. Die neu gegründete Session steht für die Besucher der Lobby dann bereit.
358
Service Provider
Die Architektur der DirectPlay-Lobby sieht so aus: Lobby Client Anwendung 1
DirectPlay Objekt
Lobby Provider
Lobby Server
Lobby Client Anwendung 2
Bild 5.8:
5.5
DirectPlay Objekt
Lobby Provider
Lobby-Architektur
Service Provider Der Service Provider ist eine gemeinsame Schnittstelle zum managen von Sessions, Spielern und Gruppen. Weiterhin sorgt der Provider für die Verbreitung von Informationen und organisiert den Service einer Lobby sowie weiterer Spieler im Netzwerk. Direct Play beinhaltet vier generische Service Provider: •
IPX
•
Internet TCP/IP
•
Serielle Verbindungen
•
Modem-Verbindungen
DirectPlay verbirgt die Komplexität dieser Verbindungen; so sind die eingesetzten Methoden auf alle Provider anwendbar. Der Programmierer muss sich nicht um das Übertragungsprotokoll der Provider kümmern. So wird eine Anwendung, welche für eine IPX-Verbindung erstellt wurde, auch über eine TCP/IP-Verbindung funktionieren. Wenn man berücksichtigt, dass die verschiedenen Provider auch verschiedene Übertragungsprotokolle nutzen, ist dies ein beachtlicher Service von DirectPlay.
5.6
Sicherheit Mit DirectPlay ist es möglich eine erhöhte Sicherheit für eine Session zu erzeugen. Für diesen Zweck werden Secure Sessions eingerichtet. Dabei wird die Sicherheit in das Windowssicherheitssystem (SSPI: Security Support Provider Interface) integriert.
Kapitel 5 • DirectPlay
359
Folgende Sicherheitsmerkmale werden von DirectPlay gefördert. •
Passwortschutz: Die Identität eines Teilnehmers kann überprüft werden. Erst nach der Überprüfung der Identität kann eine Kommunikation zwischen Client und Server stattfinden.
•
Digitale Signaturen für Systemnachrichten: Anhand der Signatur kann die Identität des Teilnehmers festgestellt werden.
•
Verschlüsselung: Empfindliche Nachrichten können verschlüsselt und somit vor einem ungewünschten Lesen geschützt werden. Anwendung Verschlüsselung
MS RSA BASE CP CAPI
Andere
DirectPlay Objekt Digitale Signatur
Bild 5.9:
5.7
NTML SSPI
Andere
Sicherheit
Nachrichten Nachdem eine Anwendung einen Spieler erstellt hat, kann der Spieler mit anderen Spielern Nachrichten austauschen. Neben den eigens vom Spieler erstellten Nachrichten werden vom System die Systemnachrichten erstellt. Dies sind Nachrichten, welche z.B. den Zugang eines Spielers in eine Session signalisieren. Nachrichten können vom Spieler an einen speziellen Spieler gesendet werden oder an alle Spieler. Ebenfalls kann er die Nachricht an eine Untergruppe der Session senden. Dann empfangen alle Spieler dieser Gruppe die Nachricht. Systemnachrichten werden an alle Spieler einer Session gesendet. Systemnachrichten haben spezielle Absenderidentifikationen. Diese werden in Form von Konstanten übergeben wie z.B. DPID_SYSMSG. Alle Nachrichten, welche von einer Anwendung empfangen wurden, werden in eine Nachrichtenwarteschlange eingereiht. Die Anwendung muss eigenverantwortlich dafür sorgen, das die Nachrichtenwarteschlange abgefragt wird. Ebenfalls unterliegt es der Anwendung, die empfangenen Nachrichten zu interpretieren.
360
5.7.1
Nachrichten
Nachrichten empfangen Nachrichten werden mit der DirectPlay4.Receive()-Methode empfangen. Hierzu erzeugt die Methode ein DirectPlayMessage-Objekt, welches mit den relevanten Informationen gefüllt wird. Die Methode ist nur in der Lage jeweils eine Nachricht zu empfangen. Um die gesamte Nachrichtenwarteschlange abzuarbeiten, können Sie die Anzahl der Nachrichten mit der DirectPlay4.GetMessageCount()Methode abfragen. Das DirectPlayMessage-Objekt beinhaltet eine Vielzahl von Übergabeplätzen. Unter anderem finden wir dort auch einen Speicherplatz für Variabeln vom Typ Long. Systemnachrichten werden anhand dieses Typs identifiziert. So ist es allgemein üblich, das man auch die Spielernachrichten über diesen Parameter identifiziert. Das ermöglicht eine einheitliche Abarbeitung der Nachrichtenwarteschlange und eine einheitliche Interpretation der empfangenen Daten. Folgendes Listing empfängt alle Nachrichten aus der Nachrichtenwarteschlange: Dim g_DP As DirectPlay4 is the DirectPlay4 object. Sub Nachrichten_Empfangen() Dim Count as Long Dim Type as Long Dim FromPlayerID As Long Dim ToPlayerID As Long Dim Nachricht as DirectPlayMessage Count = g_DP.GetMessageCount(PlayerId)
PlayerId identifiziert den Spieler, für den die Nachrichtenwarteschlange abgefragt werden soll. Die Spieleridentifikation erhalten Sie, wenn Sie einen neuen Spieler erzeugen oder ein Spieler sich der Session anschließt. For X = 1 to Count Set Nachricht = g_DP.Receive(FromPlayerID, _ ToPlayerID, DPRECEIVE_ALL) If FromPlayerID = DPID_SYSMSG Then Type = Nachricht.ReadLong()
Hier können Sie die Auswertung der Systemnachrichten vornehmen. Else
Hier können Sie die Auswertung der Spielernachrichten vornehmen. End If Next X End Sub
Kapitel 5 • DirectPlay
361
Systemnachrichten Um Systemnachrichten auszuwerten, werden Konstanten aus der CONST_ DPSYSMSGTYPES-Liste übergeben. Diese werden beim Aufruf der Methode ReadLong() des DirectPlayMessage-Objekts zurückgegeben. Enum CONST_DPSYSMSGTYPES DPLSYS_APPTERMINATED DPLSYS_CONNECTIONSETTINGSREAD DPLSYS_DPLAYCONNECTFAILED DPLSYS_DPLAYCONNECTSUCCEEDED DPLSYS_GETPROPERTY DPLSYS_GETPROPERTYRESPONSE DPLSYS_NEWCONNECTIONSETTINGS DPLSYS_NEWSESSIONHOST DPLSYS_SETPROPERTY DPLSYS_SETPROPERTYRESPONSE DPSYS_ADDGROUPTOGROUP DPSYS_ADDPLAYERTOGROUP DPSYS_CHAT DPSYS_CREATEPLAYERORGROUP DPSYS_DELETEGROUPFROMGROUP DPSYS_DELETEPLAYERFROMGROUP DPSYS_DESTROYPLAYERORGROUP DPSYS_HOST DPSYS_SECUREMESSAGE DPSYS_SENDCOMPLETE DPSYS_SESSIONLOST DPSYS_SETGROUPOWNER DPSYS_SETPLAYERORGROUPDATA DPSYS_SETPLAYERORGROUPNAME DPSYS_SETSESSIONDESC DPSYS_STARTSESSION End Enum
= = = = = = = = = = = = = = = = = = = = = = = = = =
4 1 2 3 7 8 10 9 5 6 261 (&H105) 7 265 (&H109) 3 262 (&H106) 33 (&H21) 5 257 (&H101) 263 (&H107) 269 (&H10D) 49 (&H31) 266 (&H10A) 258 (&H102) 259 (&H103) 260 (&H104) 264 (&H108)
Wie Sie sehen, informiert uns das System bei einer ganzen Reihe von Aktionen. So erhalten wir die DPSYS_CREATEPLAYERORGROUP-Nachricht, wenn ein Spieler oder eine Gruppe der Session beitritt. Zusätzlich zu den normalen Möglichkeiten die Daten einer Nachricht zu lesen, bietet DirectPlay folgende Methoden, um Standardsystemnachrichten zu lesen: •
DirectPlayMessage.MoveToSecureMessage()
•
DirectPlayMessage.ReadSysMsgData()
•
DirectPlayMessage.ReadSysChatString()
•
DirectPlayMessage.ReadSysMsgConnection()
•
DirectPlayMessage.ReadSysMsgSessionDesc()
362
Nachrichten
Spielernachrichten Die Spielernachrichten sind nicht darauf angewiesen, die Auswertung der Nachrichtenart über den Long-Parameter des DirectPlayMessage-Objekts durchzuführen. Dennoch sollten Sie auch die Spielernachrichten über diesen Eintrag identifizieren. So können Sie z.B. eine eigene Konstantenliste erzeugen und diese für die Nachrichtenidentifizierung verwenden. Enum CONST_SpielerNachrichten Spieler_nach_rechts Spieler_nach_links . . . End Enum
Neben dem Beschreiben der einzelnen Elemente des DirectPlayMessage-Objektes kann der Spieler auch einen eigenen Datenblock erstellen und versenden. Die meisten Anwendungen verwenden das Beschreiben der DirectPlayMessage-Elemente. Dies liegt zum einen an der Einfachheit und zum anderen reichen die Möglichkeiten für fast alle Anwendungen aus. Sollten Sie sich dazu entscheiden, einen eigenen Datenblock zu versenden, so wird dieser Datenblock mit der DirectPlayMessage.SetMessageData()-Methode an das DirectPlayMessageObjekt übergeben. Dazu müssen Sie aber die genaue Größe des Datenblocks kennen. Dies ist nicht immer eine leichte Aufgabe. Die gesendeten Daten können dann mit der DirectPlayMessage.GetMessageData()-Methode ausgewertet werden. Auswerten von Nachrichten Das Auswerten von Nachrichten unterliegt einer festen Konvention. Sie müssen die Daten so auslesen, wie sie geschrieben wurden. Verdeutlichen wir uns das an einem Beispiel. Dim Nachricht As DirectPlayMessage With Nachricht .WriteLong 1 .WriteString “Hallo” .WriteByte 10 End With
Wir haben das Nachrichtenobjekt mit ein paar Werten gefüllt. Wenn die Nachricht beim Empfänger ankommt, muss dieser die Nachrichten in der gleichen Reihenfolge auslesen wie wir es beschrieben haben. Dim nLong As Long Dim nString As String Dim nByte As Byte With nachricht
Kapitel 5 • DirectPlay
363
nLong = .ReadLong nString = .ReadString nByte = .ReadByte End With
Sollten Sie die Nachrichten in einer anderen Reihenfolge auswerten, so werden Sie unsinnige Werte erhalten. Senden und Empfangen müssen synchronisiert sein.
5.7.2
Synchronisation Nachrichten, welche gesendet wurden, müssen auch gelesen werden. Dazu gibt es zwei Wege. Der eine Weg ist, Sie fragen die Nachrichtenwarteschlange regelmäßig ab. Das lässt sich mit einer Do...Loop-Schleife gut vereinbaren. Do While DoEvents() Nachrichten_Empfangen() Loop
Die Alternative ist, Sie erzeugen ein Event. Das Event wird immer dann ausgelöst, wenn eine neue Nachricht eintrifft. Wie Sie ein Event einrichten, können Sie an den Beispielen für DirectInput erkennen.
5.8
DirectPlay-Adresse Eine DirectPlay-Adresse ist eine Datenformat, welches DirectPlay benötigt, um Verbindungen zu Lobby-Servern, Anwendungen oder Service-Providern herzustellen. Das DirectPlayAddress-Objekt wird zur Initialisierung einer DirectPlayAnwendung benötigt. Es beinhaltet Informationen über den gewählten Provider. Sie initialisieren eine Verbindung mit der DirectPlay4.InitializeConnection()Methode. DirectPlay4.InitioalizeConnection(addr As DirectPlayAddress)
Sie können die DirectPlay-Adresse manipulieren oder sogar eine eigene Adresse erstellen. Dazu stehen folgende Methoden bereit: •
CreateComPortAddress()
•
CreateCustomAddress()
•
CreateINetAddress()
•
CreateLobbyProviderAddress()
•
CreateModemAddress()
•
CreateServiceProviderAddress()
364
DirectPlay-Protokoll
Die Manipulation der DirectPlay-Adresse ist im Regelfall überflüssig. Beachten Sie, dass Ihnen die Verbindungsmöglichkeiten über die Netzwerkumgebung des eingesetzten Computersystems zur Verfügung gestellt wird. Dort können Sie die Manipulationen wesentlich komfortabler durchführen. Explizit betrachten wir dabei die Modemverbindungen. Wie Sie sich auch entscheiden, gehen Sie behutsam vor, den jeder Fehler wird mit nicht funktionierenden Verbindungen bestraft. Die Fehlersuche ist dann nicht ganz einfach. Schließlich stehen Sie immer vor dem Problem: Liegt der Fehler am Quellcode oder an falschen Parametern des Providers?
5.9
DirectPlay-Protokoll Das DirectPlay-Protokoll ist eine Umsetzung für einen garantierten Nachrichtentransport bei Service-Providern, welche diesen Service eigentlich nicht bieten. Der IPX-Service-Provider unterstützt normalerweise keinen garantierten Nachrichtentransport. Möchten Sie über diesen Service-Provider einen garantierten Nachrichtentransport umsetzen, so müssen Sie alle Vorkehrungen treffen um dies zu realisieren. Allgemein wird dies mit Handshaking bezeichnet. DirectPlay hilft uns bei diesem Problem aus der Patsche. Um das DirectPlay-Protokoll zu verwenden, müssen Sie beim Erzeugen der Session das DPSESSION_ DIRECTPLAYPROTOCOL-Flag setzen. SessionData.SetFlags DPSESSION_MIGRATEHOST Or_ DPSESSION_DIRECTPLAYPROTOCOL g_dp.Open SessionData, DPOPEN_CREATE
Systemnachrichten werden jetzt garantiert übermittelt. Für Nicht-Systemnachrichten müssen Sie jeder Nachricht explizit mitteilen, ob die Übermittlung garantiert oder nicht garantiert erfolgen soll. Die garantierte Übermittlung erreichen wir mit einem Flag der Sendemethoden. g_dp.Send PlayerID, DPID_ALLPLAYERS, DPSEND_GUARANTEED, _ ChatMsg
Das DPSEND_GUARANTEED-Flag signalisiert DirectPlay, dass es sich um eine garantierte Nachrichtenübermittlung handeln soll. Weisen Sie beim Erzeugen der Session das DPSESSION_DIRECTPLAY PROTOCOL-Flag nicht ausdrücklich zu, dann können Nachrichten nur dann garantiert übermittelt werden, wenn es der Provider unterstützt. Betrachten wir die Fähigkeiten der Provider:
Kapitel 5 • DirectPlay
365
Das DPSESSION_DIRECTPLAYPROTOCOL ist nicht gesetzt: Service Provider
garantiert
nicht garantiert
IPX
Nein
Ja
TCP/IP
Ja
Ja
Modem
Nein
Ja
Das DPSESSION_DIRECTPLAYPROTOCOL ist gesetzt: Service Provider
garantiert
nicht garantiert
IPX
Ja
Ja
TCP/IP
Ja
Ja
Modem
Ja
Ja
Eine garantierte Datenübermittlung dauert länger als eine nicht garantierte. In vielen Fällen kann man auf eine Garantie verzichten. So z.B. wenn Sie die Position des gegnerischen Spielers in einem Netzwerkspiel übermitteln. Solch eine Information wird im Regelfall mehrmals pro Sekunde übertragen. Geht dabei eine Nachricht verloren, so macht sich das nicht bemerkbar. Nachrichten, die nur einmal gesendet werden, können auf eine garantierte Übermittlung nicht verzichten. Geht diese Nachricht verloren, so hat das erhebliche Auswirkungen auf die gesamte Anwendung.
5.10
Session Eine Session ist ein Kommunikationskanal zwischen zwei oder mehr Anwendungen. Dabei ist es nicht notwendig, dass die Anwendungen auf verschiedenen Computern existieren. Mit den IPX- bzw. TCP/IP-Providern können Sie auf einem Computer die Verbindung von mehreren Programmen herstellen. Dies ist eine hilfreiche Möglichkeit, die Funktionsweise der eigenen Anwendung zu testen. Wenn Sie eine Netzwerkanwendung starten, stehen Sie immer vor dem Problem, ob Sie sich einer Session anschließen möchten oder eine neue Session gründen wollen. Um diese Entscheidung treffen zu können, müssen Sie darüber informiert sein, welche Sessions geöffnet sind und welchen Sessions Sie beitreten können. Die DirectPlay4.GetDPEnumSessions()-Methode erstellt eine Liste aller Sessions. Mit dem flags-Parameter der Methode können Sie die Liste der Sessions eingrenzen. So wird Ihnen die Konstante DPENUMSESSIONS_ALL alle Sessions (unabhängig ob Sie der Session beitreten können) auflisten. Die Konstante DPENUMSESSIONS_AVAILABLE begrenzt die Liste auf solche Sessions, welche noch neue Mitglieder akzeptieren. Passwortgeschützte Sessions werden eben-
366
Session
falls vor den Augen des Anwenders verbogen. Die Kombination DPENUMSESSIONS_AVAILABLE und DPENUMSESSIONS_PASSWORD REQUIRED wird eine Liste aller Sessions erstellen, welche neue Mitglieder zulassen und ein Passwort benötigen. Nachdem Sie über die existierenden Sessions informiert sind, können Sie sich mit der DirectPlay4.Open()-Methode einer Session anschließen. Die gleiche Methode nutzen Sie, um eine neue Session zu erstellen. Wie sich die Methode verhält, wird natürlich über den flags-Parameter entschieden. So wird die Konstante DPOPEN_ CREATE eine neue Session erstellen. Um sich einer Session anzuschließen, verwenden Sie die DPOPEN_JOIN-Konstante. Beispiel (Session) Auf der CD finden Sie in dem Ordner DirectPlay den Unterordner Sessions. Dort haben wir zwei Miniprogramme abgelegt. Das eine Programm erzeugt eine Session. Nach dem Starten können Sie zwischen 1 bis 4 Teilnehmern wählen. Die maximale Anzahl der Teilnehmer in der Session beträgt vier. Nachdem Sie die Session erstellt haben, können Sie mit dem zweiten Programm herausfinden, ob die Session offen für neue Spieler ist oder nicht.
Bild 5.10: Bildschirmfoto Session
Die GetGuid()-Methode verwenden wir, um den richtigen Provider zu ermitteln. Da wir zwei Programme verwenden, ist es notwendig, dass beide Programme über den gleichen Provider miteinander kommunizieren.
Kapitel 5 • DirectPlay
367
GetGuid() Ermittelt die Guid einer Verbindung aus dem Auflistungsobjekt. object.GetGuid(index As Long) as String object
ein gültiges DirectPlayEnumConnections-Objekt
index
Element aus dem Auflistungsobjekt, von welchem die Information ermittelt werden soll.
Session erzeugen: Private Private Private Private Private Private Private
g_dx As DirectX7 g_dp As DirectPlay4 DirectPlayEnum As DirectPlayEnumConnections DirectPlayAdresse As DirectPlayAddress Session As DirectPlayEnumSessions Player As DirectPlayEnumPlayers SessionData As DirectPlaySessionData
Private Sub Form_Load() Set g_dx = New DirectX7 Set g_dp = g_dx.DirectPlayCreate("") Set DirectPlayEnum = g_dp.GetDPEnumConnections("", _ DPCONNECTION_DIRECTPLAY) If DirectPlayEnum.GetCount = 0 Then End For i = 1 To DirectPlayEnum.GetCount If DirectPlayEnum.GetGuid(i) = "DPSPGUID_IPX" Then Exit For Next I Set DirectPlayAdresse = DirectPlayEnum.GetAddress(i) g_dp.InitializeConnection DirectPlayAdresse End Sub
In der Form_Load()-Subroutine initialisieren wir die notwendigen DirectXObjekte und erstellen das DirectPlay-Objekt. Anschließend wählen wir den Provider und initialisieren die Verbindung. Dabei haben wir den IPX-Provider ausgewählt. Diesen können Sie natürlich ändern. Private Sub Command1_Click() Set SessionData = g_dp.CreateSessionData SessionData.SetSessionName "Session 1" SessionData.SetMaxPlayers 4 SessionData.SetFlags DPSESSION_DIRECTPLAYPROTOCOL Or _ PSESSION_MIGRATEHOST g_dp.Open SessionData, DPOPEN_CREATE Check1(0).Value = 1
Wir erstellen eine Session mit maximal vier Teilnehmern.
368
Session
PlayerName = "Session1 Spieler 1" PlayerHandle = "S1Spieler1" PlayerID1 = g_dp.CreatePlayer(PlayerName, PlayerHandle, 0, 0)
Mindestens ein Spieler wird erstellt. If Check1(2).Value = 1 Then PlayerName = "Session1 Spieler 2" PlayerHandle = "S1Spieler2" PlayerID2 = g_dp.CreatePlayer(PlayerName, _ PlayerHandle, 0, 0) End If If Check1(3).Value = 1 Then PlayerName = "Session1 Spieler 3" PlayerHandle = "S1Spieler3" PlayerID3 = g_dp.CreatePlayer(PlayerName, _ PlayerHandle, 0, 0) End If If Check1(4).Value = 1 Then PlayerName = "Session1 Spieler 4" PlayerHandle = "S1Spieler5" PlayerID4 = g_dp.CreatePlayer(PlayerName, _ PlayerHandle, 0, 0) End If
Abhängig von von Ihrer Auswahl werden Spieler zwei, drei und vier erstellt. Erstellen Sie vier Spieler, dann haben Sie die maximal zulässige Anzahl von Spielern erreicht und die Session steht für weitere Spieler nicht mehr offen. Check1(5).Value = 1 Command1.Enabled = False End Sub
Das zweite Programm überprüft, ob die Session für zusätzliche Spieler offen ist. Private g_dx As DirectX7 Private g_dp As DirectPlay4 Private DirectPlayEnum As DirectPlayEnumConnections Private DirectPlayAdresse As DirectPlayAddress Private Session As DirectPlayEnumSessions Private SessionData As DirectPlaySessionData Private Sub Form_Load() Set g_dx = New DirectX7 Set g_dp = g_dx.DirectPlayCreate("") Set DirectPlayEnum = g_dp.GetDPEnumConnections("", _ DPCONNECTION_DIRECTPLAY) If DirectPlayEnum.GetCount = 0 Then End For i = 1 To DirectPlayEnum.GetCount If DirectPlayEnum.GetGuid(i) = "DPSPGUID_IPX" Then Exit For
Kapitel 5 • DirectPlay
369
Next I Set DirectPlayAdresse = DirectPlayEnum.GetAddress(i) g_dp.InitializeConnection DirectPlayAdresse
Wiederum wählen wir den Provider und initialisieren die Verbindung. Sollte kein Provider gefunden werden, wird das Programm vorzeitig beendet. Set SessionData = g_dp.CreateSessionData Set Session = g_dp.GetDPEnumSessions(SessionData, 0, _ DPENUMSESSIONS_AVAILABLE) If Session.GetCount <> 0 Then Check1(0).Value = 1 Else _ Check1(1).Value = 1 End Sub
Um zu prüfen, ob die Session für weitere Spieler offen ist, wählen wir das Flag DPENUMSESSIONS_AVAILABLE. Sollten wir bei der anschließenden Abfrage der verfügbaren Sessions eine 0 erhalten, so wurde keine (für weitere Spieler) offene Session gefunden.
5.11
Spieler Aus der Betrachtungsweise einer Session ist ein Spieler ein Objekt, welches Daten sendet oder empfängt. Um die Spieler eindeutig zu identifizieren, vergibt die Session einen eindeutigen Index für jeden Spieler. Ein Spieler kann ein lokaler oder ein entfernter Spieler sein. Ein lokaler Spieler existiert auf dem Computer, welcher die Session erzeugt hat. Ein entfernter Spieler existiert somit auf einem andern System. Die Systeme sind über Netzwerkverbindungen verbunden. Jeder Computer benötigt mindestens einen lokalen Spieler, bevor eine Kommunikation mit andern Spielern stattfinden kann. Jedes Computersystem kann mehr als einen Spieler haben. Eine Kommunikation richtet sich immer an einen Spieler, niemals an einen Computer. Dabei stehen dem Sender verschiedene Arten der Nachrichtenverbreitung zur Verfügung. Die Nachricht kann zielgerichtet an einen speziellen Spieler erfolgen oder an eine Gruppe oder an alle anderen Spieler. Das Versenden von Nachrichten an alle Spieler ist vergleichbar mit einer Systemnachricht. Diese wird auch an alle Spieler gesendet. Für das Verbreiten von Spielerinformationen bietet DirectPlay einige Möglichkeiten. So ist es möglich, einen rein lokalen Spieler zu erzeugen. Dessen Identität ist für andere Spieler nicht erkennbar. Natürlich kann auch ein normaler Spieler erzeugt werden, der sich artig bei allen anderen Spielern vorstellt. Mit der DirectPlay4.CreatePlayer()-Methode erzeugen Sie neue Spieler. Diese können mit der DirectPlay4.GetDPEnumPlayers()-Methode aus einer Session aufgelistet werden. Über Methoden wie DirectPlay4.SetPlayerName() oder DirectPlay4.SetPlayerData() können die Spielerinformationen geändert werden.
370
Spieler
Beispiel (Spieler) Auf der CD finden Sie in dem Ordner DirectPlay den Unterordner Spieler. Dort haben wir wiederum zwei Miniprogramme abgelegt. Das erste Programm ist identisch mit dem Session-Beispiel. Das zweite Programm ermittelt Informationen über die Spieler der Session.
Bild 5.11: Bildschirmfoto Spieler
Starten Sie zuerst das Programm Session erzeugen. Anschließend starten Sie das Programm Lesen. Ihnen werden drei Spieler angezeigt. Sie haben jetzt die Möglichkeit einen weiteren Spieler der Session anzuschließen. Die Informationen über die Session werden dann aktualisiert. Private Sub Form_Load() Set g_dx = New DirectX7 Set g_dp = g_dx.DirectPlayCreate("") Set DirectPlayEnum = g_dp.GetDPEnumConnections("", _ DPCONNECTION_DIRECTPLAY) If DirectPlayEnum.GetCount = 0 Then End For i = 1 To DirectPlayEnum.GetCount If DirectPlayEnum.GetGuid(i) = "DPSPGUID_IPX" Then Exit For Next i Set DirectPlayAdresse = DirectPlayEnum.GetAddress(i)
Kapitel 5 • DirectPlay
371
g_dp.InitializeConnection DirectPlayAdresse Set SessionData = g_dp.CreateSessionData Set Session = g_dp.GetDPEnumSessions(SessionData, 0, _ DPENUMSESSIONS_AVAILABLE) If Session.GetCount = 0 Then MsgBox "keine offene Session" Check1(1).Value = 1 Check1(0).Value = 0 End Else SessionGuid = Session.GetItem(1).GetGuidInstance Check1(1).Value = 0 Check1(0).Value = 1 Command1.Enabled = True End If
Bis hierher ist alles bekannt. Wir richten die DirectX-Objekte ein und initialisieren die Verbindung. Anschließend prüfen wir, ob eine offene Session existiert. Ist dies der Fall, so merken wir uns die SessionGuid. Set SessionData = Session.GetItem(1) g_dp.Open SessionData, DPOPEN_JOIN
Um Informationen über die Spieler zu erhalten, müssen wir uns der Session anschließen. Dies übernimmt die DirectPlay4.Open()-Methode. Set Spieler = g_dp.GetDPEnumPlayers(SessionGuid, _ DPENUMPLAYERS_ALL)
Die Informationen über die Spieler erhalten wir durch die DirectPlay4.GetDP EnumPlayers()-Methode. Für diese Methode benötigen wir die SessionGuid, die wir uns zuvor gemerkt haben. List1.Clear For i = 1 To Spieler.GetCount List1.AddItem ("Rufname: " & Spieler.GetShortName(i)) List1.AddItem ("Hausname: " & Spieler.GetLongName(i)) List1.AddItem ("Typ: " & Spieler.GetType(i)) List1.AddItem ("ID: " & Spieler.GetDPID(i)) List1.AddItem ("------------------------------------") Next I
Die Informationen über die Spieler lassen wir in eine Listbox eintragen. End Sub
Sie haben die Möglichkeit, einen neuen Spieler hinzuzufügen. Dies übernimmt wiederum die DirectPlay4.CreatePlayer()-Methode. Anschließend nehmen wir den neuen Spieler in die Listbox auf.
372
Bienenjagd Multiplayer Demo
PlayerName = "entfernter Spieler 1" PlayerHandle = "S1entfernterSpieler1" PlayerID1 = g_dp.CreatePlayer(PlayerName, PlayerHandle, 0, 0) Set Spieler = g_dp.GetDPEnumPlayers(SessionGuid, _ DPENUMPLAYERS_ALL) List1.Clear For i = 1 To Spieler.GetCount List1.AddItem ("Rufname: " & Spieler.GetShortName(i)) List1.AddItem ("Hausname: " & Spieler.GetLongName(i)) List1.AddItem ("Typ: " & Spieler.GetType(i)) List1.AddItem ("ID: " & Spieler.GetDPID(i)) List1.AddItem ("------------------------------------") Next I
5.12
Bienenjagd Multiplayer Demo Abschließend möchten wir noch ein kleines Netzwerkspiel vorstellen. Dieses ist Ihnen bereits aus dem DirectDraw-Abschnitt bekannt. Dort konnten Sie das Spiel Bienenjagd bereits im Single-Player-Modus spielen. Den richtige Reiz erhält das Spiel aber erst im Duell mit einem Freund. Das Spiel ist folgendermaßen konzipiert. Wir nutzen zwei Computer. Auf jedem der Computer läuft das Spiel autonom. Lediglich wenn ein Spieler eine Biene trifft, wird der andere Computer (Spieler) darüber informiert. Die Information wird in eine Aktion umgewandelt und die getroffene Biene verschwindet auf beiden Monitoren. Das Spiel läuft autonom! Das bedeutet, dass die Positionen der Bienen auf den Monitoren nicht identisch sind. Jeder Computer berechnet für sich die Geschwindigkeit und Position der Bienen. Da dies per Zufall entschieden wird, ist es für beide Spieler gleichermaßen gerecht. Das Programm beginnt mit der Auswahl des Providers. Wir wählen im Regelfall das IPX-Protokoll. Set g_DX = New DirectX7 Set g_DP = g_DX.DirectPlayCreate("") List1.Clear Set DirectPlayEnum = g_DP.GetDPEnumConnections("", _ DPCONNECTION_DIRECTPLAY) If DirectPlayEnum.GetCount = 0 Then End For i = 1 To DirectPlayEnum.GetCount List1.AddItem (DirectPlayEnum.GetName(i)) Next I
Nach der Auswahl des Providers geht es mit der InitDP()-Subroutine in Module2 weiter.
Kapitel 5 • DirectPlay
Bild 5.12: Bildschirmfoto Bienenjagd Login Public Sub InitDP() g_DP.InitializeConnection DirectPlayAdresse Set SessionData = g_DP.CreateSessionData Set Session = g_DP.GetDPEnumSessions(SessionData, 0, _ DPENUMSESSIONS_ALL) If Session.GetCount = 0 Then Set SessionData = g_DP.CreateSessionData SessionData.SetSessionName "Biene" SessionData.SetGuidApplication AppGuid SessionData.SetMaxPlayers 2 SessionData.SetFlags DPSESSION_MIGRATEHOST g_DP.Open SessionData, DPOPEN_CREATE SessionGuid = SessionData.GetGuidInstance PlayerName = "Host" PlayerHandle = "HandelHost" PlayerID = g_DP.CreatePlayer(PlayerName, _ PlayerHandle, 0, 0) HostIndex = True Waiting = True Unload Form2 Form3.Visible = True Form3.ZOrder 0 Else Set SessionData = Session.GetItem(1) g_DP.Open SessionData, DPOPEN_JOIN PlayerName = "Gast"
373
374
Bienenjagd Multiplayer Demo
PlayerHandle = "HandleGast" PlayerID = g_DP.CreatePlayer(PlayerName, _ PlayerHandle, 0, 0) Dim PlayerEnum As DirectPlayEnumPlayers Set PlayerEnum = g_DP.GetDPEnumPlayers("", 0) HostIndex = False End If End Sub
Je nachdem ob eine Session existiert, eröffnen wir eine neue Session oder schließen uns einer bestehenden Session an. Die InitDP()-Subroutine sollte für Sie leicht verständlich sein. Wenn noch keine Session existiert, dann erstellen wir eine neue Session mit einem Spieler. Die Anwendung wartet nun so lange, bis sich eine Gegenspieler der Session anschließt. Dann geht es los. Wenn eine Biene getroffen wurde, senden wir eine Nachricht. Diese Nachricht wird von Ihrem Gegenspieler empfangen und das Programm reagiert entsprechend. Schauen wir uns zuerst das Senden der Nachricht an. Public Sub SendMessage(Index As Double) Dim ChatMsg As DirectPlayMessage Set ChatMsg = g_DP.CreateMessage Call ChatMsg.WriteLong(DPSYS_CHAT) Call ChatMsg.WriteDouble(Index) Call g_DP.Send(PlayerID, DPID_ALLPLAYERS, DPSEND_GUARANTEED, _ ChatMsg) End Sub
Wir definieren den Treffer einer Biene als DPSYS_CHAT-Nachricht. Sie können natürlich auch eine andere Form der Identifikation wählen. Zum Senden gehört auch das Empfangen von Nachrichten. Public Sub GetMessages() Dim MsgCount As Long Dim MsgType As Long Dim FromPlayerID As Long Dim ToPlayerID As Long Dim dpMsg As DirectPlayMessage MsgCount = g_DP.GetMessageCount(0) For x = 1 To MsgCount Set dpMsg = g_DP.Receive(FromPlayerID, ToPlayerID, _ DPRECEIVE_ALL) MsgType = dpMsg.ReadLong() Select Case MsgType Case DPSYS_DESTROYPLAYERORGROUP End Case DPSYS_CREATEPLAYERORGROUP Waiting = False
Kapitel 5 • DirectPlay
375
Case DPSYS_HOST End Case DPSYS_CHAT Sprite(dpMsg.ReadDouble).Visible = False If HostIndex = True Then PunkteGast = _ PunkteGast +1 Else PunkteHost = PunkteHost + 1
Wenn die Nachricht eintrifft, dass eine Biene getroffen wurde, wird die VisibleEigenschaft des Sprites auf False gesetzt. Dies ist für den Computer das Zeichen, die Geschwindigkeit und die Position der Biene neu zu errechnen. Gleichzeitig wird dem entsprechendem Spielerkonto der Treffer gutgeschrieben. End Select Next X End Sub
Anhang A Methoden A.1 A.2 A.3 A.4 A.5 A.6
Globale DirectX7-Methoden DirectDraw-Methoden Direct3D-Methoden DirectSound-Methoden DirectInput DirectPlay-Methoden
378 390 430 457 483 505
378
A.1
Globale DirectX7-Methoden
Globale DirectX7-Methoden DirectX7.ColorGetAlpha ColorGetAlpha () Gibt den Alphaanteil eines Farbwertes zurück. → DirectX7.ColorGetRed(), DirectX7.ColorGetBlue(), DirectX7.ColorGetGreen() object. ColorGetAlpha (color As Long) As Single object
ein gültiges DirectX7-Objekt
color
Farbe, von der die Alphakomponente zurückgegeben wird, im Bereich von 0-255.
DirectX7.ColorGetBlue ColorGetBlue() Gibt den Blauanteil eines Farbwertes zurück. → DirectX7.ColorGetAlpha(), DirectX7.ColorGetRed(), DirectX7.ColorGetGreen() object. ColorGetBlue (color As Long) As Single object
ein gültiges DirectX7-Objekt
color
Farbe, von der die Alphakomponente zurückgegeben wird, im Bereich von 0-255.
DirectX7.ColorGetGreen ColorGetGreen() Gibt den Grünanteil eines Farbwertes zurück. → DirectX7.ColorGetAlpha(), DirectX7.ColorGetBlue(), DirectX7.ColorGetRed() object. ColorGetGreen (color As Long) As Single object
ein gültiges DirectX7-Objekt
color
Farbe, von der die Alphakomponente zurückgegeben wird, im Bereich von 0-255.
DirectX7.ColorGetRed ColorGetRed () Gibt den Rotanteil eines Farbwertes zurück. → DirectX7.ColorGetAlpha(), DirectX7.ColorGetBlue(), DirectX7.ColorGetGreen() object. ColorGetRed (color As Long) As Single
Anhang A • Methoden
379
ColorGetRed () object
ein gültiges DirectX7-Objekt
color
Farbe, von der die Alphacomponente zurückgegeben wird, im Bereich von 0-255.
DirectX7.CopyMatrix CopyMatrix() Kopiert eine Quellmatrix in eine Zielmatrix. object. CopyMatrix (mDest As D3DMATRIX, mSrc As D3DMATRIX) As String object
ein gültiges DirectX7-Objekt
mDest
Ziel vom Typ D3DMATRIX
mSrc
Quelle vom Typ D3DMATRIX
DirectX7.CreateColorRGB CreateColorRGB() Erstellt eine RGB Farbe von den Farbanteilen. Rot, Grün und Blau. → DirectX7.CreateColorRGBA() object. CreateColorRGB (r As Single, g As Single, b As Single) As _ Long object
ein gültiges DirectX7-Objekt
r,g,b
Komponenten der RGB-Farbe
DirectX7.CreateColorRGBA CreateColorRGBA() Erstellt eine RGBA Farbe aus den Farbanteilen. Rot, Grün, Blau und Alpha. → DirectX7.CreateColorRGB() object. CreateColorRGBA (r As Single, g As Single, b As Single, _ a As Single) As Long object
ein gültiges DirectX7-Objekt
r,g,b,a
Komponenten der RGBA-Farbe
380
Globale DirectX7-Methoden
DirectX7.CreateD3DLVertex CreateD3DLVertex() Erstellt einen D3DLVertex und übergibt diesen an v vom Typ D3DLVERTEX. → DirectX7.CreateD3DTLVertex(), DirectX7.CreateD3Dvertex() object. CreateD3DLVertex (x As Single, y As Single, z As Single, _ color As Long, specular As Long, tu As Single, tv As Single, _ v As D3DLVERTEX) object
ein gültiges DirectX7-Objekt
x,y,z
Koordinaten des Vertexes
color, specular
Farbwerte zum Einstellen der RGBA-Farbe des Diffuse- und Specularanteils des Vertexes
tu,tv
Texturkoordinaten des Vertexes
V
Variable vom Typ D3DLVERTEX, die die LVertexdaten aufnimmt.
DirectX7.CreateD3DTLVertex CreateD3DTLVertex() Erstellt einen D3DTLVertex und übergibt diesen an v vom Typ D3DTLVERTEX. → DirectX7.CreateD3DLVertex(), DirectX7.CreateD3Dvertex() object. CreateD3DTLVertex (sx As Single, sy As Single, sz As _ Single, rhw As Single, color As Long, specular As Long, tu As _ Single, tv As Single, v As D3DTLVERTEX) object
ein gültiges DirectX7-Objekt
sx,sy,sz
Koordinaten des Vertexes in Bildschirmkoordinaten
rhw
Gegenteil des einheitlichen W des Vertex.
color, specular
Farbwerte zum Einstellen der RGBA-Farbe des Diffuse- und Specularanteils des Vertexes.
tu,tv
Texturekoordinaten des Vertexes
v
Variable vom Typ D3DTLVERTEX, die die TLVertexdaten aufnimmt.
DirectX7.CreateD3DVertex CreateD3Dvertex() Erstellt einen D3DVertex und übergibt diesen an v vom Typ D3DVERTEX. →DirectX7.CreateD3DLVertex(), DirectX7.CreateD3DTLVertex()
Anhang A • Methoden
381
CreateD3Dvertex() object. CreateD3DVertex (x As Single, y As Single, z As Single, nx As Single, _ ny As Single, nz As Single, tu As Single, tv As Single, v As D3DVERTEX) object
ein gültiges DirectX7-Objekt
x,y,z
Koordinaten des Vertexes
nx,ny,nz
Normalvektorausrichtung für den Abstrahlwinkel von Diffuse- und Specular-Licht
tu,tv
Texturkoordinaten des Vertexes
v
Variable vom Typ D3DVERTEX, die die Vertexdaten aufnimmt.
DirectX7.CreateEvent CreateEvent() Übergibt ein Handle an das Ereignisobjekt, das in einer Form implementiert wurde. → DirectX7.SetEvent(), DirectX7.DestroyEvent(), DirectSoundBuffer.SetNotificationPosition(), DirectSoundCaptureBuffer.SetNotificationPosition(), DirectInputDevice.SetEventNotification(), DirectPlayLobby3.SetLobbyMessageEvent(), DirectMusicPerformance.SetNotificationHandle() object.GetDescription(event As DirectXEvent) As Long object
ein gültiges DirectX7-Objekt
event
Ein DirectXEvent-Objekt, das in einer Form implementiert wurde.
DirectX7.CreateNewGuid CreateNewGuid() Generiert eine global einmalige Indentifizierungskennzahl. object. CreateNewGuid () As String object
ein gültiges DirectX7-Objekt
DirectX7.DestroyEvent DestroyEvent() Löscht ein Eventhandle, das mit der DirectX.CreateEvent()-Methode erzeugt wurde. object. DestroyEvent (eventid As Long) object
ein gültiges DirectX7-Objekt
eventid
Handle des zu löschenden Ereignisses
382
Globale DirectX7-Methoden
DirectX7.Direct3DRMCreate Direct3DRMCreate() Erzeugt ein Direct3DRM3-Objekt. object. Direct3DRMCreate () As Direct3DRM3 object
ein gültiges DirectX7-Objekt
DirectX7.DirectDrawCreate DirectDrawCreate() Erzeugt ein DirectDraw7-Objekt. object. DirectDrawCreate (guid As String) As DirectDraw7 object
ein gültiges DirectX7-Objekt
guid
Identifikationsnummer des Ausgabegerätes. Die Übergabe eines leeren Strings setzt den aktiven Displaytreiber als Ausgabegerät für DirectDraw.
DirectX7.DirectInputCreate DirectInputCreate() Erzeugt ein DirectInput-Objekt. object. DirectInputCreate () As DirectInput object
ein gültiges DirectX7-Objekt
DirectX7.DirectMusicComposerCreate DirectMusicComposerCreate() Erzeugt ein DirectMusicComposer-Objekt. object. DirectMusicComposerCreate () As DirectMusicComposer object
ein gültiges DirectX7-Objekt
DirectX7.DirectMusicLoaderCreate DirectMusicLoaderCreate() Erzeugt ein DirectMusicLoader-Objekt. object. DirectMusicLoaderCreate () As DirectMusicLoader object
ein gültiges DirectX7-Objekt
Anhang A • Methoden
383
DirectX7.DirectMusicPerformanceCreate DirectMusicPerformanceCreate() Erzeugt ein DirectMusicPerformance-Objekt. object. DirectMusicPerformanceCreate () As DirectMusicPerformance object
ein gültiges DirectX7-Objekt
DirectX7.DirectPlayCreate DirectPlayCreate() Erzeugt ein DirectPlay4-Objekt. object. DirectPlayCreate (guid As String) As DirectPlay4 object
ein gültiges DirectX7-Objekt
guid
Identifikationsnummer des Service-Providers, an dem DirectPlay angemeldet wird. Wird ein leerer String übergeben, wird die Verbindung nicht initialisiert und die Applikation muss die DirectPlay4.InitializeConnection()-Methode ausführen.
DirectX7.DirectPlayLobbyCreate DirectPlayLobbyCreate() Erzeugt ein DirectPlayLobby3-Objekt. object. DirectPlayLobbyCreate () As DirectPlayLobby3 object
ein gültiges DirectX7-Objekt
DirectX7.DirectSoundCaptureCreate DirectSoundCaptureCreate() Erzeugt ein DirectSoundCapture-Objekt. object. DirectSoundCaptureCreate (guid As String) As _ DirectSoundCapture object
ein gültiges DirectX7-Objekt
guid
Identifikationsnummer des Soundaufnahmegerätes. Ein leerer String bewirkt, dass das aktuelle Aufnahmegerät verwendet wird.
384
Globale DirectX7-Methoden
DirectX7.DirectSoundCreate DirectSoundCreate() Erzeugt ein DirectSound-Objekt. object. DirectSoundCreate (guid As String) As DirectSound object
ein gültiges DirectX7-Objekt
guid
Identifikationsnummer des Soundausgabegerätes. Ein leerer String bewirkt, dass das aktuelle Ausgabegerät verwendet wird.
DirectX7.GetDDEnum GetDDEnum() Erstellt ein DirectDrawEnum-Objekt, welches zum Auslesen der im System installierten primären Bildschirmausgabegeräte dient. object. GetDDEnum() As DirectDrawEnum object
ein gültiges DirectX7-Objekt
DirectX7.GetDSCaptureEnum GetDSCaptureEnum() Erzeugt ein DirectSoundEnum-Objekt, welches zum Auslesen der im System installierten Aufnahmegeräte dient. object. GetDSCaptureEnum () As DirectSoundEnum object
ein gültiges DirectX7-Objekt
DirectX7.GetDSEnum GetDSEnum() Erzeugt ein DirectSoundEnum-Objekt, welches zum Auslesen der im System installierten Soundausgabegeräte dient. object. GetDSEnum () As DirectSoundEnum object
ein gültiges DirectX7-Objekt
DirectX7.GetWindowRect GetWindowRect() Übergibt die Position, Höhe und Breite einer grafischen Komponente, deren Handle an die Rotine übergeben wird, an eine Rect-Struktur vom Typ RECT.
Anhang A • Methoden
385
GetWindowRect() object.GetWindowRect (hwnd As Long, r As RECT) object
ein gültiges DirectX7-Objekt
hwnd
Handle der grafischen Komponente
r
Variable vom Typ RECT zum Aufnehmen der Koordinaten.
DirectX7.IdentityMatrix IdentityMatrix() Füllt eine Variable vom Typ D3DMATRIX mit ihren Grundeinstellungen. Grundeinstellungen einer 4x4 Matrix (1,1) (2,2) (3,3) (4,4) auf Wert 1 object. IdentityMatrix (mDest As D3DMATRIX) object
ein gültiges DirectX7-Objekt
mDest
Variable vom Typ D3DMATRIX, die die Werte aufnimmt.
DirectX7.MatrixMultiply MatrixMultiply() Multipliziert zwei Matrizen miteinander. object. MatrixMultiply (mDest As D3DMATRIX, mA As D3DMATRIX, _ mB As D3DMATRIX) object
ein gültiges DirectX7-Objekt
mDest
Variable vom Typ D3DMATRIX, die die errechneten Werte aufnimmt.
mA
Variable vom Typ D3DMATRIX als Multiplikator.
mB
Variable vom Typ D3DMATRIX als Multiplikationsfaktor.
mDest = mA * mB
DirectX7.ProjectionMatrix ProjectionMatrix() Setzt die Koordinaten des nächsten und des am weitesten sichtbaren Vertexes. object. ProjectionMatrix (mDest As D3DMATRIX, _ nearPlane As Single, farPlane As Single, fov As Single) object
ein gültiges DirectX7-Objekt
mDest
Variable vom Typ D3DMatrix, die die errechneten Daten aufnimmt.
nearPlane
nächster sichtbarer Punkt im 3D-Raum
386
Globale DirectX7-Methoden
ProjectionMatrix() farPlane
weitester sichtbarer Punkt im 3D-Raum
fov
Breite des Sichtfeldes in Radiant [ Winkel /(180/Pi)]
DirectX7.RotateXMatrix RotateXMatrix() Dreht eine Matrix um die X-Achse. object. RotateXMatrix (mDest As D3DMATRIX, radiant As Single) object
ein gültiges DirectX7-Objekt
mDest
Variable vom Typ D3DMATRIX, die die Daten aufnimmt.
radians
Winkel in Radiant, um den gedreht wird; Radiant=(Winkel / (180 / Pi)).
DirectX7.RotateYMatrix RotateYMatrix() Dreht eine Matrix um die Y-Achse. object. RotateYMatrix (mDest As D3DMATRIX, radiant As Single) object
ein gültiges DirectX7-Objekt
mDest
Variable vom Typ D3DMATRIX, die die Daten aufnimmt.
radians
Winkel in Radiant, um den gedreht wird; Radiant=(Winkel / (180 / Pi)).
DirectX7.RotateZMatrix RotateZMatrix() Dreht eine Matrix um die Z-Achse. object. RotateZMatrix (mDest As D3DMATRIX, radiant As Single) object
ein gültiges DirectX7-Objekt
mDest
Variable vom Typ D3DMATRIX, die die Daten aufnimmt.
radians
Winkel in Radiant, um den gedreht wird; Radiant=(Winkel / (180 / Pi)).
DirectX7.SetEvent SetEvent() Setzt das Eventobjekt auf Signalisieren. object. SetEvent (eventid As Long)
Anhang A • Methoden
387
SetEvent() object
ein gültiges DirectX7-Objekt
eventid
Handle des Ereignisses, das auf Signal gesetzt wird.
DirectX7.SystemBpp SystemBpp() Empfängt die aktuelle Bits pro Pixel-Einstellung des Systems. object. SystemBpp () As Long object
ein gültiges DirectX7-Objekt
DirectX7.TickCount TickCount() Empfängt das System TickCount in Millisekunden. (API: GetTickCount). object. TickCount () As Long object
ein gültiges DirectX7-Objekt
DirectX7.VectorAdd VectorAdd() Addiert zwei Vektoren miteinander. object.VectorAdd (v As D3DVECTOR, vA As D3DVECTOR, _ vB As D3DVECTOR) object
ein gültiges DirectX7-Objekt
v
Variable vom Typ D3DVECTOR, die die Daten aufnimmt.
vA, vB
Variablen vomTyp D3DVECTOR, die addiert werden.
DirectX7.VectorCopy VectorCopy() Erstellt eine Kopie eines Vektors. object. VectorCopy (vDest As D3DVECTOR, vSrc As D3DVECTOR) object
ein gültiges DirectX7-Objekt
VDest
Variable vom Typ D3DVECTOR, die die Daten aufnimmt (Ziel).
vSrc
Variable vom Typ D3DVECTOR, die kopiert wird (Quelle).
388
Globale DirectX7-Methoden
DirectX7.VectorCrossProduct VectorCrossProduct() Erstellt das Kreuzprodukt zweier Vektoren. object. VectorCrossProduct (v As D3DVECTOR, vA As D3DVECTOR, _ vB As D3DVECTOR) object
ein gültiges DirectX7-Objekt
v
Variable vom Typ D3DVECTOR, die die Daten aufnimmt.
vA, vB
Variablen vom Typ D3DVECTOR, von denen das Kreuzprodukt berechnet wird.
DirectX7.VectorDotProduct VectorDotProduct() Erstellt das Skalarprodukt zweier Vektoren. object. VectorDotProduct (vA As D3DVECTOR, _ vB As D3DVECTOR) As Single object
ein gültiges DirectX7-Objekt
vA, vB
Variablen vom Typ D3DVECTOR, von denen das Skalarprodukt berechnet wird.
DirectX7.VectorModulus VectorModulus() Berechnet die Länge eines Vektors (Länge = SQR(x^2+y^2+z^2)). object. VectorModulus (vA As D3DVECTOR) As Single object
ein gültiges DirectX7-Objekt
vA
Variable vom Typ D3DVECTOR, deren Länge berechnet wird.
DirectX7.VectorNormalize VectorNormalize() Scaliert einen Vektor soweit bis seine Länge = 1 ist. object. VectorNormalize (v As D3DVECTOR) object
ein gültiges DirectX7-Objekt
v
Variable vom Typ D3DVECTOR, die die Daten aufnimmt.
Anhang A • Methoden
389
DirectX7.VectorRotate VectorRotate() Dreht einen Vektor um eine beliebige Achse. object. VectorRotate (vDest As D3DVECTOR, vA As D3DVECTOR, _ vAxis As D3DVECTOR, theta As Single) object
ein gültiges DirectX7-Objekt
vDest
Variable vom Typ D3DVECTOR, die die errechneten Daten aufnimmt.
vA
Variable vom Typ D3DVECTOR, die den Originalvektor enthält.
vAxis
Variable vom Typ D3DVECTOR, die die Drehachse beschreibt.
theta
Winkel in Radiant, um den gedreht wird.
DirectX7.VectorScale VectorScale() Verändert die Länge eines Vektors in allen drei Achsen. object. VectorScale (vDest As D3DVECTOR, vA As D3DVECTOR, _ factor As Single) object
ein gültiges DirectX7-Objekt
vDest
Variable vom Typ D3DVECTOR, die die errechneten Daten aufnimmt.
vA
Variable vom Typ D3DVECTOR, die den Originalvektor enthält.
factor
Faktor der Größenänderung.
DirectX7.VectorSubtract VectorSubtract() Subtrahiert zwei Vektoren voneinander. object. VectorSubtract (v As D3DVECTOR, vA As D3DVECTOR, _ vB As D3DVECTOR) object
ein gültiges DirectX7-Objekt
v
Variable vom Typ D3DVECTOR, die die Daten aufnimmt.
vA
Variable vom Typ D3DVECTOR, von der subtrahiert wird.
vB
Variable vom Typ D3DVECTOR, die subtrahiert wird.
390
DirectDraw-Methoden
DirectX7.ViewMatrix ViewMatrix() Erstellt eine Viewmatrix basierend auf der Kameraposition. object. ViewMatrix (mDest As D3DMATRIX, vFrom As D3DVECTOR, vTo As D3DVECTOR, vUp As D3DVECTOR, roll As Single) object
ein gültiges DirectX7-Objekt
mDest
Variable vom Typ D3DMATRIX, die die Daten aufnimmt.
vFrom
Variable vom Typ D3DVECTOR, die die Kameraposition angibt.
vTo
Variable vom Typ D3DVECTOR, die die Sichtposition angibt.
vUp
Variable vom Typ D3DVECTOR, die die aktuelle Weltmatrix beschreibt (0,1,0).
roll
Drehung der Kamera um den Sichtbereich.
DirectX7.ZeroMatrix ZeroMatrix() Setzt alle Einträge einer Matrix auf 0. object. ZeroMatrix (mDest As D3DMatrix) Object
ein gültiges DirectX7-Objekt
MDest
Variable vom Typ D3DMATRIX, die auf Null gesetzt wird.
DirectXEvent.DXCallback DXCallback() Managt die Rückrufroutinen der Ereignisse. object. DXCallback (eventid As Long) Object
ein gültiges DirectXEvent-Objekt
Eventid
Ereignisshandle
A.2
DirectDraw-Methoden
A.2.1
DirectDraw7 Die DirectDraw7-Klasse erzeugt Objekte und arbeitet mit der Systemumgebung. Die Methoden der DirectDraw7-Klasse werden in folgenden Gruppen organisiert:
Anhang A • Methoden
391
Cooperative Levels
SetCooperativeLevel TestCooperativeLevel
Erzeugen
CreateClipper CreatePalette CreateSurface CreateSurfaceFromFile CreateSurfaceFromResource GetDirect3D LoadPaletteFromBitmap
Fähigkeiten
GetCaps
Display Modes
GetDisplayMode GetDisplayModesEnum GetMonitorFrequency RestoreDisplayMode SetDisplayMode WaitForVerticalBlank
Display Zustand
GetScanLine GetVerticalBlankStatus
Verschiedenes
GetAvailableTotalMem GetDeviceIdentifier GetFourCCCodes GetFreeMem GetNumFourCCCodes
Oberflächen
DuplicateSurface FlipToGDISurface GetGDISurface GetSurfaceFromDC GetSurfacesEnum RestoreAllSurfaces
DirectDraw7.CreateClipper CreateClipper() Erzeugt ein DirectDrawClipper-Objekt. → DirectDrawSurface7.GetClipper, DirectDrawSurface7.SetClipper object.CreateClipper(flags As Long) As DirectDrawClipper object
ein gültiges DirectDraw7-Objekt
flags
Wird zurzeit nicht verwendet. Muss 0 sein.
392
DirectDraw-Methoden
DirectDraw7.CreatePalette CreatePalette() Erzeugt ein DirectDrawPalette-Objekt. object.CreatePalette( flags As CONST_DDPCAPSFLAGS, _ pe() As PALETTEENTRY) As DirectDrawPalette object
ein gültiges DirectDraw7-Objekt
flags
CONST_DDPCAPSFLAGS
pe()
Array von 2, 4, 16 oder 256 vom Typ PALETTEENTRY
DirectDraw7.CreateSurface CreateSurface() Erzeugt ein DirectDrawSurface-Objekt. object.CreateSurface( dd As DDSURFACEDESC2) As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
dd
Eine Variable vom Typ DDSURFACEDESC2; enthält die Beschreibungen der Surface.
DirectDraw7.CreateSurfaceFromFile CreateSurfaceFromFile() Erzeugt ein DirectDrawSurface-Objekt von einer Bitmap. object.CreateSurfaceFromFile(dd As DDSURFACEDESC2) _ As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
dd
Eine Variable vom Typ DDSURFACEDESC2; enthält die Beschreibungen der Surface.
Wenn Sie 256 Farben verwenden, sollten Sie zuerst den Displaymode und die Palette setzen. Sonst könnte die Surface mit falschen Farben dargestellt werden.
DirectDraw7.CreateSurfaceFromResource CreateSurfaceFromResource() Erzeugt ein DirectDrawSurface-Objekt von einer Ressource. object.CreateSurfaceFromResource(file As String, resName As String, _ ddsd As DDSURFACEDESC2) As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
Anhang A • Methoden
393
CreateSurfaceFromResource() file
Filename der Ressource. Ist die Ressource ein Teil des ausführbaren Programms, so bleibt dieser Parameter ein leerer String. Dieser Parameter kann auch der Name einer OCX sein.
resName
Name der Ressource
ddsd
eine Variable vom Typ DDSURFACEDESC2.
Wenn Sie einen leeren String als Modulnamen angeben und die Anwendung in der VisualBasic-Umgebung läuft, wird die Resource nicht gefunden. Verwenden Sie einen leeren Sting nur bei ausführbaren *.exe-Anwendungen.
DirectDraw7.DuplicateSurface DuplicateSurface() Erzeugt ein genaue Kopie eines DirectDrawSurface-Objekts. object.DuplicateSurface( ddIn As DirectDrawSurface7) _ As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
ddIn
Eine DirectDrawSurface, welche dupliziert werden soll
Die duplizierte Surface verweist auf den gleichen Speicher wie die Orginalsurface. Eine primäre oder 3D-Surface kann nicht dupliziert werden.
DirectDraw7.FlipToGDISurface FlipToGDISurface() Macht die Surface, auf welche das GDI-Grafiksystem schreibt zur primären Surface. → DirecDraw7.GetGDISurface object.FlipToGDISurface() object
ein gültiges DirectDraw7-Objekt
Um sicherzustellen, dass der vom GDI geschriebene Speicher sichtbar ist, wird diese Methode nach dem Page Flipping aufgerufen.
DirectDraw7.GetAvailableTotalMem GetAvailableTotalMem() Liest die Größe des verwendeten Videospeichers einer Surface. object.GetAvailableTotalMem( ddsCaps As DDSCAPS2) As Long object
ein gültiges DirectDraw7-Objekt
394
DirectDraw-Methoden
GetAvailableTotalMem() ddsCaps
Eine Variable vom Typ DDSCAPS2, welche die Leistungsfähigkeit einer Surface beschreibt.
Diese Methode unterstützt lediglich eine Momentaufname des Videospeichers.
DirectDraw7.GetCaps GetCaps() Liest das Leistungsvermögen einer Grafikkarte (HAL) oder des Hardware Emulators (HEL). object.GetCaps(hwCaps As DDCAPS, helCaps As DDCAPS) object
ein gültiges DirectDraw7-Objekt
hwCaps
Eine Variable vom Typ DDCAPS, welche die Leistungsfähigkeit des Hardwaretreibers aufnimmt.
helCaps
Eine Variable vom Typ DDCAPS, welche die Leistungsfähigkeit des Hardware-Emulations-Treibers aufnimmt.
DirectDraw7.GetDeviceIdentifier GetDevideIdentifier() Liest die Informationen des DirectDraw-Device-Treibers. object.GetDeviceIdentifier( flags As CONST_DDDEVICEIDFLAGS ) _ As DirectDrawIdentifier object
ein gültiges DirectDraw7-Objekt
flags
eine Variable vom Typ CONST_DDDEVICEIDFLAGS
DirectDraw7.GetDirect3D GetDirect3D() Erzeugt ein Direct3D7-Objekt. object.GetDirect3D() As Direct3D7 object
ein gültiges DirectDraw7-Objekt
Die Methode liefert ein Direct3D7-Objekt. Dieses muss zuvor dimensioniert und zugeordnet sein. Dim Direct3D as Direct3D7 Set Direct3D = object.GetDirect3D()
Anhang A • Methoden
395
DirectDraw7.GetDisplayMode GetDisplayMode() Liest den aktuellen Display Mode. → DirectDraw7.SetDisplayMode(), DirectDraw7.RestoreDisplayMode(), DirectDraw7.GetDisplayModesEnum() object.GetDirect3D() As Direct3D7 object
ein gültiges DirectDraw7-Objekt
surface
Eine Variable vom Typ DDSURFACEDESC2, welche die Beschreibungen des aktuellen Display Mode aufnimmt.
Benutzen Sie diese Methode nicht, um den Display Mode wiederherzustellen. Dazu verwenden Sie die Methode DirectDraw7.RestoreDisplayMode().
DirectDraw7.GetDisplayModesEnum GetDisplyModesEnum() Liest die aktuellen Display-Mode-Informationen der Grafikkarte. → DirectDraw7.SetDisplayMode(), DirectDraw7.RestoreDisplayMode(), DirectDraw7. GetDisplayModesEnum() object.GetDisplayModesEnum(flags As CONST_DDEDMFLAGS, _ ddsd As DDSURFACEDESC2) As DirectDrawEnumModes object
ein gültiges DirectDraw7-Objekt
flags
eine Konstante aus der CONST_DDEDMFLAGS-Liste
ddsd
Eine Variable vom Typ DDSURFACEDESC2, welche die möglichen Display Modes der Grafikkarte aufnimmt.
DirectDraw7.GetFourCCCodes GetFourCCCodes() Liest die FOURCC-Codes, welche vom ausgewählten DirectDraw Objekt unterstützt werden. object.GetFourCCCodes(ccCodes() As Long) object
ein gültiges DirectDraw7-Objekt
ccCodes()
Ein Array, welches mit den FOURCC-Codes gefüllt wird.
Um die Anzahl der unterstüzten FOURCC-Codes zu ermitteln, benutzen Sie die DirectDraw7.GetNumFourCCCodes()-Methode.
396
DirectDraw-Methoden
DirectDraw7.GetFreeMem GetFreeMem() Liest die Größe des zurzeit freien Videospeichers. object.GetFreeMem(ddsCaps As DDSCAPS2) As Long object
ein gültiges DirectDraw7-Objekt
ddsCaps
Eine Variable vom Typ DDSCAPS2, welche die Hardwareeigenschaften einer Surface beschreibt.
Diese Methode liefert lediglich eine Momentaufname des verfügbaren Videospeichers.
DirectDraw7.GetGDISurface GetGDISurface() Ermittelt die Surface, welche vom GDI-Grafiksystem als primäre Surface verwendet wird. → DirectDraw7.FlipToGDISurface() object.GetGDISurface() As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
DirectDraw7.GetMonitorFrequency GetMonitorFrequency() Ermittelt die aktuelle Monitorfrequenz in Hz. object.GetGDISurface() As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
DirectDraw7.GetNumFourCCCodes GetNumFourCCCodes() Ermittelt die Anzahl der unterstützten FOURCC-Codes. object.GetGDISurface() As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
Diese Methode wird im Regelfall vor der DirectDraw7.GetFourCCodes()-Methode aufgerufen.
Anhang A • Methoden
397
DirectDraw7.GetScanLine GetScanLine() Ermittelt die aktuelle Scanline, welche in diesem Augenblick gezeichnet wird. → DirectDraw7.GetVerticalBlankStatus(), DirectDraw7.WaitForVerticalBlank() object.GetScanLine(lines As Long) As Long object
ein gültiges DirectDraw7-Objekt
lines
aktuelle Scanline
DirectDraw7.GetSurfaceFromDC GetSurfaceFromDC() Ermittelt ein DirectDrawSurface7-Objekt, welches durch das Handle der GDI-Umgebung beschrieben wird. object.GetSurfaceFromDC(hdc As Long) As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
hdc
Handle eines Gerätekontexts
DirectDraw7.GetSurfacesEnum GetSurfacesEnum() Ermittelt ein DirectDrawEnumSurfaces-Objekt, welches die mit einem DirectDraw7Objekt verbundenen Surfaces auflisten kann. object.GetSurfaceFromDC(hdc As Long) As DirectDrawSurface7 object
ein gültiges DirectDraw7-Objekt
flags
Eine Konstante aus der CONST_DDENUMSURFACESFLAGS-Liste. Sie beschreibt, wie die Methode nach verbundenen Surfaces suchen soll.
desc
Eine Variable vom Typ DDSURFACEDESC2, welche die Suchkriterien festlegt.
DirectDraw7.GetVerticalBlankStatus GetVerticalBlankStatus() Ermittelt den Status des Vertialleerlaufs. → DirectDraw7.GetScanLine(), DirectDraw7.WaitForVerticalBlank() object.GetVerticalBlankStatus() As Long object
ein gültiges DirectDraw7-Objekt
398
DirectDraw-Methoden
DirectDraw7.GetWindowsRect GetWindowsRect() Ermittelt die Eckwerte eines Rechtecks, welches den Clientbereich eines Fensters beschreibt. Call object.GetWindowRect(hwnd As Long, r As RECT) object
ein gültiges DirectDraw7-Objekt
hwnd
Handle eines Fensters, dessen Clientbereich ermittelt werden soll.
r
Eine Variable vom Typ RECT, welche die ermittelten Werte aufnimmt.
DirectDraw7.LoadPaletteFromBitmap LoadPaletteFromBitmap() Erzeugt ein DirectDrawPalette-Objekt auf der Basis einer Bitmap. object.GetVerticalBlankStatus() As Long object
ein gültiges DirectDraw7-Objekt
bName
Name der Bitmap
DirectDraw7.RestoreAllSurfaces RestoreAllSurfaces() Stellt alle Surfaces, welche mit dem DirectDraw7-Objekt erzeugt wurden, wieder her. → DirectDrawSurface7.Restore() object.GetVerticalBlankStatus() As Long object
ein gültiges DirectDraw7-Objekt
DirectDraw7.RestoreDisplayMode RestoreDisplyMode() Restauriert den Displaymode der primären Surface auf den Zustand, der vor dem Aufruf der Methode DirectDraw7.SetDisplyMode() herrschte. → DirectDraw7.SetDisplayMode(), DirectDrawEnumModes(), DirectDraw7.SetCooperativeLevel() object.RestoreDisplayMode() object
ein gültiges DirectDraw7-Objekt
Anhang A • Methoden
399
DirectDraw7.SetCooperativeLevel SetCooperativeLevel() Beschreibt den Toplevel einer Anwendung. Toplevel für Fensterdarstellung oder Fullscreen. → DirectDraw7.SetDisplayMode(), DirectDraw7.GetDisplayModesEnum() object.SetCooperativeLevel(hdl As Long, flags As CONST_DDSCLFLAGS) object
ein gültiges DirectDraw7-Objekt
hdl
Ein Windows-Handle für die Anwendung. Im Regelfall wird das Handle eines Formobjektes oder eines Pictureobjektes verwendet. Dieser Parameter kann 0 sein, wenn als flags DDSCL_NORMAL gewählt wird.
flags
Eine Konstante aus der CONST_DDSCLFLAGS-Liste. Sie beschreibt den Kooperativlevel an sich.
DirectDraw7.SetDisplayMode SetDisplayMode() Setzt einen gültigen Displaymode einer Grafikkarte. Der gewählte Mode muss von der Grafikkarte unterstützt werden. → DirectDraw7.RestoreDisplayMode(), DirectDraw7.GetDisplayModesEnum(), DirectDraw7.SetCooperativeLevel() object.SetDisplayMode( w As Long, h As Long, bpp As Long, ref As Long, _ mode As CONST_DDSDMFLAGS) object
ein gültiges DirectDraw7-Objekt
w und h
Weite und Höhe des neuen Modes
bpp
Auflösung in Bits per Pixel
ref
Wiederholfrequenz. Dieser Wert kann auf 0 gesetzt werden, dann wird die voreingestellte Wiederholfrequenz der Garfikkarte verwendet.
mode
Eine Konstant aus der CONST_DDSDMFLAGS-Liste. Zurzeit ist der einzig gültige Eintrag DDSDM_STANDARDVGAMODE.
DirectDraw7.TestCooperativeLevel TestCooperativeLevel() Ermittelt den aktuellen CooperativeLevelStatus für eine Fenster- oder FullscreenAnwendung. object.TestCooperativeLevel() As Long object
ein gültiges DirectDraw7-Objekt
400
DirectDraw-Methoden
TestCooperativeLevel() Die Methode liefert ein DD_Ok, wenn alles in Ordnung ist.
DirectDraw7.WaitForVerticalBlank WaitForVerticalBlank() Diese Methode wartet auf den vertikalen Leerlauf des Monitorrasterstrahls. → DirectDraw7.GetVerticalBlankStatus(), DirectDraw7.GetScanLine() object.WaitForVerticalBlank( flags As CONST_DDWAITVBFLAGS, _ handle As Long) As Long
A.2.2
object
ein gültiges DirectDraw7-Objekt
flags
Eine Konstante aus der CONST_DDWAITVBFLAGS-Liste, welche die Wartezeit auf den vertikalen Leerlauf festlegt.
handle
Handle eines Ereignisses. Dieser Parameter ist optional.
DirectDrawClipper Die DirectDrawClipper-Klasse handelt die Clipliste. Die DirectDrawClipper-Methoden sind in folgende Klassen organisiert: Clipliste
GetClipList GetClipListSize IsClipListChanged SetClipList
Handles
GetHWnd SetHWnd
DirectDrawClipper.GetClipList GetClipList() Ermittelt die Clipliste, welche mit dem Clipper-Objekt verbunden ist. → DirectDrawClipper.SetClipList() object.GetClipList(rects() As RECT) object
ein gültiges DirectDrawClipper-Objekt
rects()
Ein Array, welches die Clipliste aufnimmt.
Anhang A • Methoden
401
DirectDrawClipper.GetClipListSize GetClipListSize() Ermittelt die Cliplistengröße in Bytes. object.GetClipList(rects() As RECT) object
ein gültiges DirectDrawClipper-Objekt
DirectDrawClipper.GetHWnd GetHWnd() Ermittelt das Windows-Handle, welches mit dem Clipper-Objekt verbunden ist. → DirectDrawClipper.SetHWnd() object.GetHWnd() As Long object
ein gültiges DirectDrawClipper-Objekt
DirectDrawClipper.IsClipListChanged IsClipListChanged() Ermittelt den Status der Clipliste, wenn sie mit dem Clipper-Objekt verbunden ist. object.IsClipListChanged() As Long object
ein gültiges DirectDrawClipper-Objekt
Ist das Ergebnis =0, so wurde die Clipliste nicht verändert.
DirectDrawClipper.SetClipList SetClipList() Setzt oder löscht eine Clipliste. → DirectDrawClipper.GetClipList(), DirectDrawSurface7.Blt(), DirectDrawSurface7.BltFast() object.SetClipList( count As Long, rects() as RECT object
ein gültiges DirectDrawClipper-Objekt
count
die Anzahl der RECT-Strukturen in dem rects() Array
rects()
Array mit RECT-Strukturen, welche die Clipliste beschreiben.
Die Clipliste kann nicht gesetzt werden, wenn das Windows-Handle mit dem ClipperObjekt verbunden ist. Die DirectDraw7.BltFast()-Methode kann nicht clippen.
402
DirectDraw-Methoden
DirectDrawClipper.SetHWnd SetHWnd() Setzt das Windows-Handle, welches die Clippinginformationen enthält. → DirectDrawClipper.GetHWnd() object.SetHWnd(hdl As Long)
A.2.3
object
ein gültiges DirectDrawClipper-Objekt
hdl
Windows-Handle
DirectDrawColorControl Die DirectDrawColorControl-Klasse erlaubt es, auf das Farbkontrollelement zuzugreifen. Die DirectDrawColorControl-Methoden sind in folgende Klassen organisiert: Color controls
GetColorControls SetColorControls
DirectDrawColorControl.GetColorControls GetColoControl() Ermittelt die aktuellen Color-Control-Einstellungen, welche mit einer Overlay- oder primären Surface verbunden sind. → DirectDrawColorControl.SetColorControls() object.GetColorControls(colorControl As DDCOLORCONTROL) object
ein gültiges DirectDrawColorControl-Objekt
ColorControl
Eine Variable vom Typ DDCOLORCONTROL, welche die Informationen aufnimmt.
Die Methode verursacht einen Fehler, wenn das Gafikgerät Color Control nicht unterstützt.
DirectDrawColorControl.SetColorControls SetColorControl() Setzt die aktuellen Color-Control-Einstellungen, welche mit einer Overlay- oder primären Surface verbunden sind. → DirectDrawColorControl.GetColorControls() object.SetColorControls(colorControl As DDCOLORCONTROL) object
ein gültiges DirectDrawColorControl-Objekt
Anhang A • Methoden
403
SetColorControl() colorControl
A.2.4
Eine Variable vom Typ DDCOLORCONTROL, welche die Informationen enthält.
DirectDrawEnum Die DirectDrawEnum Klasse liefert Informationen über die installierten Grafikkarten. Das DirectDrawEnum-Objekt wird mit der DirectX7.GetDDEnum()-Methode erzeugt. Folgende Methoden gehören zu der DirectDrawEnum-Klasse: Geräte
GetCount GetDescription GetGuid GetMonitorHandle GetName
DirectDrawEnum.GetCount GetCount() Emittelt die Anzahl der installierten DirectDraw-Treiber. object.GetCount() As Long object
ein gültiges DirectDrawEnum-Objekt
DirectDrawEnum.GetDescription GetDescription() Ermittelt die Gerätebeschreibung des selektierten DirectDraw-Gerätes. object.GetDescription(index As Long) As String object
ein gültiges DirectDrawEnum-Objekt
index
ein DirectDraw-Gerät im DirectDrawEnum-Objekt
DirectDrawEnum.GetGuid GetGuid() Ermittelt den Guid des selektierten DirectDraw-Gerätes. object.GetGuid(index As Long) As String
404
DirectDraw-Methoden
GetGuid() object
ein gültiges DirectDrawEnum-Objekt
index
ein DirectDraw-Gerät im DirectDrawEnum-Objekt
DirectDrawEnum.GetMonitorHandle GetMonitorHandle() Ermittelt das Monitor-Handle des selektierten DirectDraw Gerätes. object.GetName(index As Long) As Long object
ein gültiges DirectDrawEnum-Objekt
index
ein DirectDraw-Gerät im DirectDrawEnum-Objekt
DirectDrawEnum.GetName GetName() Ermittelt den Namen des selektierten DirectDraw-Gerätes. object.GetName(index As Long) As String
A.2.5
object
ein gültiges DirectDrawEnum-Objekt
index
ein DirectDraw-Gerät im DirectDrawEnum-Objekt
DirectDrawEnumModes Die DirectDrawEnumModes-Klasse erzeugt eine Liste mit verfügbaren Videomodes für ein System. Das DirectDrawEnumModes-Objekt wird mit der DiretDraw7.GetDisplayModesEnum()-Methode erzeugt. Folgende Methoden gehören zu der DirectDrawEnumModes-Klasse: Display Mode
GetCount GetItem
DirectDrawEnumModes.GetCount GetCount() Ermittelt die Anzahl der verfügbaren Videomodes. object.GetCount() As Long object
ein gültiges DirectDrawEnumModes-Objekt
Anhang A • Methoden
405
DirectDrawEnumModes.GetItem GetItem() Ermittelt die Beschreibung des selektierten Videomodes. object.GetItem(index As Long, info As DDSURFACEDESC2)
A.2.6
object
ein gültiges DirectDrawEnumModes-Objekt
index
ein Element aus dem DirectDrawEnumModes-Objekt
info
Eine Variable vom Typ DDSURFACEDESC2, welche die Informationen des Videomodes aufnimmt.
DirectDrawEnumSurfaces Die Methode DirectDrawEnumSurfaces() erstellt eine Liste mit allen erzeugten Surfaces. Das DirectDrawEnumSurfaces-Objekt wird mit der DirectDraw7.GetAttachedSurfaceEum()-Methode erzeugt. Folgende Methoden gehören zu der DirectDrawEnumSurfaces-Klasse: Oberflächen
GetCount GetItem
DirectDrawEnumSurfaces.GetCount GetCount() Ermittelt die Anzahl der erzeugten Surfaces. object.GetCount() As Long object
ein gültiges DirectDrawEnumSurfaces-Objekt
DirectDrawEnumSurfaces.GetItem GetItem() Ermittelt die Surfacebeschreibungen der selektierten Surface. object.GetItem(index As Long) As DirectDrawSurface7 object
ein gültiges DirectDrawEnumSurfaces-Objekt
index
ein Element aus dem DirectDrawEnumSurfaces-Objekt
406
A.2.7
DirectDraw-Methoden
DirectDrawGammaControl Anwendungen nutzen die Methoden der DirectDrawGamaControl-Klasse um die Rot-, Grün- und Blaulevel der primären Surface einzustellen. Das DirectDrawGammaControl-Objekt wird mit der DiretDrawSurface7.GetDirectDrawGammaControl()-Methode erzeugt. Folgende Methoden gehören zu der DirectDrawGammaControl-Klasse: Gamma-Kontroll-Element
GetGammaRamp SetGammaRamp
DirectDrawGammaControl.GetGammaRamp GetGamaRamp() Ermittelt die Rot-, Grün- und Blaulevel der primären Surface. → DirectDrawGammaControl.SetGammaRamp() object.GetGammaRamp( flags As CONST_DDSGRFLAGS, _ gammaRamp As DDGAMMARAMP) object
ein gültiges DirectDrawGammaControl-Objekt
flags
eine Konstante der CONST_DDSGRFLAGS-Liste
gammaRamp
Eine Variable vom Typ DDGAMMARAMP, welche die ermittelten Informationen aufnimmt.
DirectDrawGammaControl.SetGammaRamp SetGammaRamp() Setzt die Rot-, Grün- und Blaulevel der primären Surface. → DirectDrawGammaControl.GetGammaRamp() object.GetGammaRamp( flags As CONST_DDSGRFLAGS, _ gammaRamp As DDGAMMARAMP)
A.2.8
object
ein gültiges DirectDrawGammaControl-Objekt
flags
eine Konstante der CONST_DDSGRFLAGS-Liste
gammaRamp
Eine Variable vom Typ DDGAMMARAMP, welche die ermittelten Informationen aufnimmt.
DirectDrawIdentifier Anwendungen verwenden die Methoden der DirectDrawIdentifier-Klasse, um Informationen über den DirectDraw-Treiber zu erhalten.
Anhang A • Methoden
407
Das DirectDrawIdentifier-Objekt wird mit der DirectDraw7.GetDrviceIdentifier()-Methode erzeugt. Folgende Methoden gehören zu der DirectDrawIdentifier-Klasse: Treiberinformation
GetDescription GetDeviceId GetDeviceIdentifier GetDriver GetDriverSubVersion GetDriverVersion GetRevision GetSubSysId GetVendorId GetWHQLLevel
DirectDrawIdentifier.GetDescription GetDescription() Ermittelt die Treiberbeschreibung. object.GetDescription() As String object
ein gültiges DirectDrawIdentifier-Objekt
DirectDrawIdentifier.GetDeviceId GetDeviceId() Ermittelt die Treiber ID. object.GetDeviceId() As Long object
ein gültiges DirectDrawIdentifier-Objekt
DirectDrawIdentifier.GetDeviceIdentifier GetDeviceIdentifier() Ermittelt eine eindeutige Identifizierung des Treibers. object.GetDeviceIndentifier() As String object
ein gültiges DirectDrawIdentifier-Objekt
408
DirectDraw-Methoden
DirectDrawIdentifier.GetDriver GetDriver() Ermittelt den Namen des Treibers. object.GetDriver() As String object
ein gültiges DirectDrawIdentifier-Objekt
DirectDrawIdentifier.GetDriverVersion GetDriverVersion() Ermittelt den ersten Teil (high) der Treiberversion. object.GetDriverVersion() As Long object
ein gültiges DirectDrawIdentifier-Objekt
DirectDrawIdentifier.GetDriverSubVersion GetDriverSubVersion() Ermittelt den zweiten Teil (low) der Treiberversion. object.GetDriverSubVersion() As Long object
ein gültiges DirectDrawIdentifier-Objekt
DirectDrawIdentifier.GetRevision GetRevision() Ermittelt die Revisionsnummer des Treibers. object.GetRevision() As Long object
ein gültiges DirectDrawIdentifier-Objekt
DirectDrawIdentifier.GetSubSysId GetSubSysId() Ermittelt die ID des Treibersubsystems. object.GetSubSysId() As Long object
ein gültiges DirectDrawIdentifier-Objekt
Anhang A • Methoden
409
DirectDrawIdentifier.GetVendorId GetVendorld() Ermittelt den Hersteller des Treibers. object.GetVendorId() As Long object
ein gültiges DirectDrawIdentifier-Objekt
DirectDrawIdentifier.GetWHQLLevel GetWHQLLevel() Ermittelt den Hardwarequalitätslevel. object.GetWHQLLevel() As Long object
A.2.9
ein gültiges DirectDrawIdentifier-Objekt
DirectDrawPalette Die DirectDrawPalette-Klasse behandelt den Umgang mit der Systempalette. Das DirectDrawPalette-Objekt wird mit der DirectDrawSurface7.GetPalette()Methode erzeugt. Folgende Methoden gehören zu der DirectDrawPalette-Klasse: Palette capabilities
GetCaps
Palette entries
GetEntries SetEntries
DirectDrawPalette.GetCaps GetCaps() Ermittelt die Eigenschaften des Palette-Objekts. object.GetCaps() As CONST_DDPCAPSFLAGS object
ein gültiges DirectDrawPalette-Objekt
DirectDrawPalette.GetEntries GetEntries() Ermittelt die einzelnen Werte eines Palette-Objekts. → DirectDrawPalette.SetEntries()
410
DirectDraw-Methoden
GetEntries() object.GetEntries( start As Long, count As Long, val() As PALETTEENTRY) object
ein gültiges DirectDrawPalette-Objekt
start
ab wo die Einträge gelesen werden sollen
count
wie viele Einträge gelesen werden sollen.
val()
Ein Array vom Typ PALETTEENTRY, welches die Informationen aufnimmt.
Haben Sie eine 8-Bit-Palette mit der DirectDraw7.CreatePalette()-Methode erzeugt, sind die Paletteneinträge 1 Byte groß, andererseits sind die Einträge 4 Byte groß.
DirectDrawPalette.SetEntries SetEntries() Setzt die einzelnen Werte eines Palette Objekts. → DirectDrawPalette.GetEntries(), DirectDrawSurface7.SetPalette() object.GetEntries( start As Long, count As Long, val() As _ PALETTEENTRY) object
ein gültiges DirectDrawPalette-Objekt
start
ab wo die Einträge gesetzt werden sollen
count
wie viele Einträge gesetzt werden sollen.
val()
Ein Array vom Typ PALETTEENTRY, welches die Informationen enthält.
A.2.10 DirectDrawSurface7 Die DirectDrawSurface7-Klasse verwaltet den Umgang mit Surfaces. Folgende Methoden gehören zu der DirectDrawSurface7-Klasse: Speicher
IsLost Restore
Surfaces verbinden
AddAttachedSurface DeleteAttachedSurface GetAttachedSurface GetAttachedSurfaceEnum
Anhang A • Methoden
411
Blitting
Blt BltColorFill BltFast BltFx BltToDC GetBltStatus
Farbschlüssel
GetColorKey SetColorKey
Geräteumgebung
GetDC ReleaseDC
Zeichnen und Text
DrawBox DrawCircle DrawEllipse DrawLine DrawRoundedBox DrawText GetDrawStyle GetDrawWidth GetFillColor GetFillStyle GetFontBackColor GetFontTransparency GetForeColor SetDrawStyle SetDrawWidth SetFillColor SetFillStyle SetFont SetFontBackColor SetFontTransparency SetForeColor
Flipping
Flip GetFlipStatus
Locking
GetLockedArray GetLockedPixel Lock SetLockedPixel Unlock
Verschiedenes
GetDirectDraw GetDirectDrawColorControl GetDirectDrawGammaControl
412
DirectDraw-Methoden
Overlays
GetOverlayPosition GetOverlayZOrdersEnum SetOverlayPosition UpdateOverlay UpdateOverlayFx UpdateOverlayZOrder
Surface Fähigkeiten
GetCaps
Clipper
GetClipper SetClipper
Surface Merkmale
ChangeUniquenessValue GetPixelFormat GetSurfaceDesc GetUniquenessValue
Surface Paletten
GetPalette SetPalette
Texturen
GetLOD GetPriority SetLOD SetPriority
DirectDrawSurface7.AddAttachedSurface AddAttachedSurface() Verbindet die spezifizierte Surface mit dieser Surface. object.AddAttachedSurface(ddS As DirectDrawSurface7) object
ein gültiges DirectDrawSurface7-Objekt
dds
die zu verbindende Surface
DirectDrawSurface7.Blt Blt() Kopiert Daten per Bit-Block-Transfer aus einem Speicherbereich in einen anderen. object.Blt(destRect As RECT, ddS As DirectDrawSurface7, _ srcRect As RECT, flags As CONST_DDBLTFLAGS) As Long object
ein gültiges DirectDrawSurface7-Objekt
destRect
Variablen vom Typ RECT, welche die Punkte oben links und unten rechts eines Rechtecks beschreiben. Wird dieser Wert nicht angegeben oder sind die Werte der Variablen leer, so wird der gesamte Bereicht der Ziel-Surface angenommen.
dds
Ein gültiges Surface-Objekt, welches die Daten aufnehmen soll.
Anhang A • Methoden
413
Blt() srcRect
Variablen vom Typ RECT, welche die Punkte oben links und unten rechts eines Rechtecks beschreiben. Wird dieser Wert nicht angegeben oder sind die Werte der Variablen leer, so wird der gesamte Bereicht der Quell-Surface angenommen.
Flags
Eine Kombination von Argumenten aus der CONST_DDBLTFLAGSListe.
DirectDrawSurface7.BltColorFill BltColorFill() Füllt einen rechteckigen Bereich mit einer Farbe. object.BltColorFill( destRect As RECT, fillvalue As Long) As Long object
ein gültiges DirectDrawSurface7-Objekt
destRect
Ein rechteckiger Bereich, welcher mit einer Farbe gefüllt werden soll.
fillvalue
Farbe
DirectDrawSurface7.BltFast BltFast() Kopiert Daten per Bit-Block-Transfer aus einem Speicherbereich in einen anderen. Diese Methode kann nicht auf einen Clipper-Bereich zugreifen. Siehe die Blt()Methode. object.BltFast( dx As Long, dy As Long, ddS As DirectDrawSurface7, _ srcRect As RECT, trans As CONST_DDBLTFASTFLAGS) As Long object
ein gültiges DirectDrawSurface7-Objekt
dx, dy
Koordinatenpaar auf der Ziel-Surface
dds
Quell-Surface -> von wo die Grafik kopiert werden soll
srcRect
Eine gültige RECT-Struktur, welche den Bereich auf der Quell-Surface beschreibt, von der die Grafikdaten kopiert werden sollen.
trans
DDBLTFAST_DESTCOLORKEY = 2 transparentes Blit unter Verwendung des Ziel-Farbschlüssels DDBLTFAST_DONOTWAIT = 32 Wartet nicht, bis der Blitter fertig ist. DDBLTFAST_NOCOLORKEY = 0
414
DirectDraw-Methoden
BltFast() normales Blit ohne Farbschlüssel ohne Transparenz DDBLTFAST_SRCCOLORKEY = 1 transparentes Blit unter Verwendung des Source-Farbschlüssel DDBLTFAST_WAIT = 16 Wartet bis der Blitter fertig ist.
DirectDrawSurface7.BltFx BltFx() Kopiert Daten per Bit-Block-Transfer aus einem Speicherbereich in einen anderen. Dabei können erweiterte Effekte genutzt werden. object.BltFx( destRect As RECT, ddS As DirectDrawSurface7, _ srcRect As RECT, flags As CONST_DDBLTFLAGS, _ BltFx As DDBLTFX) As Long object
ein gültiges DirectDrawSurface7-Objekt
destRect
Eine RECT-Struktur, in welche die Daten kopiert werden soll.
ddS
Eine Surface, welche als Quelle für den Blitvorgang dient.
srcRect
eine RECT-Struktur auf der Quellsurface
flags
CONST_DDBLTFLAGS
BltFx
DDBLTFX Typen-Array, welches den Effekt beschreibt, der beim Kopieren der Daten berücksichtigt werden soll.
DirectDrawSurface7.BltToDC BltToDC() Kopiert Daten per Bit-Block-Transfer aus einem Speicherbereich in einen anderen. Die Ziel-Surface wird durch den hdc-Parameter identifiziert. object.BltToDC( hdc As LONG, srcRect As RECT, destRect As RECT) object
ein gültiges DirectDrawSurface7-Objekt
hdc
Handle eines Device
srcRect
eine RECT-Struktur auf der Quellsurface
destRect
eine RECT-Struktur auf der Zielsurface
Anhang A • Methoden
415
DirectDrawSurface7.ChangeUniquenessValue ChangeUniquenessValue() Manuelle Aktualisierung der Surface-Werte object.ChangeUniquenessValue() object
ein gültiges DirectDrawSurface7-Objekt
DirectDraw aktualisiert die Surface-Werte automatisch immer dann, wenn sich der Inhalt ändert.
DirectDrawSurface7.DeleteAttachedSurface DeleteAttachedSurface() Trennt zwei miteinander verbundene Surfaces. object.DeleteAttachedSurface(ddS As DirectDrawSurface7) object
ein gültiges DirectDrawSurface7-Objekt
ddS
Surface, welche von der aktuellen Surface getrennt werden soll.
DirectDrawSurface7.DrawBox DrawBox() Zeichnet ein Rechteck auf eine Surface. object.DrawBox(x1 As Long, y1 As Long, x2 As Long, y2 As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
Legt die linke obere Ecke des Rechtecks fest.
x2, y2
Legt die rechte untere Ecke des Rechtecks fest.
DirectDrawSurface7.DrawCircle DrawCircle() Zeichnet einen Kreis auf eine Surface. object.DrawCircle(x1 As Long, y1 As Long, r As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
Legt den Mittelpunkt des Kreises fest.
r
Bestimmt den Radius des Kreises in Pixel.
416
DirectDraw-Methoden
DirectDrawSurface7.DrawEllipse DrawEllipse() Zeichnet ein Oval auf eine Surface. Die Parameter x1,y1 sowie x2,y2 legen ein Rechteck fest, dieses wird zu einem Oval umgeformt. object.DrawEllipse(x1 As Long, y1 As Long, x2 As Long, y2 As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
Legt die linke obere Ecke fest.
x2, y2
Legt die rechte untere Ecke fest.
DirectDrawSurface7.DrawLine DrawLine() Zeichnet ein Linie auf eine Surface. object.DrawLine(x1 As Long, y1 As Long, x2 As Long, y2 As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
Legt ein Koordinatenpaar fest, ab wo die Linie gezeichnet werden soll.
x2, y2
Legt ein Koordinatenpaar fest, bis wohin die Linie gezeichnet werden soll.
DirectDrawSurface7.DrawRoundedBox DrawRoundedBox() Zeichnet ein Rechteck mit abgerundeten Ecken auf eine Surface. object.DrawLine(x1 As Long, y1 As Long, x2 As Long, y2 As Long, _ rw As Long, rh As Long) object
ein gültiges DirectDrawSurface7-Objekt
x1, y1
Legt die linke obere Ecke fest.
x2, y2
Legt die rechte untere Ecke fest.
rw
Bestimmt die horizontale Größe der Rundung.
rh
Bestimmt die vertikale Größe der Rundung.
DirectDrawSurface7.DrawText DrawText() Zeichnet einen String auf eine Surface. object.DrawLine(x As Long, y As Long, text As Long, b As Long,)
Anhang A • Methoden
417
DrawText() object
ein gültiges DirectDrawSurface7-Objekt
x, y
Bestimmt ein Koordinatenpaar, an dem der Text gezeichnet werden soll.
text
Der Text der gezeichnet werden soll. Sie können eine Variable vom Typ Sring übergeben oder direkt einen Text in Hochkommata angeben.
b
True Der Text wird an der aktuellen Cursorposition gezeichnet. Die Parameter x,y werden ignoriert. False Der Text wird an dem Koordinatenpaar gezeichnet, welches durch die Parameter x,y beschrieben wurde.
DirectDrawSurface7.Flip Flip() Wechselt den Backbufferspeicher zum Frontbufferspeicher. object.Flip( ddS As DirectDrawSurface7, flags As CONST_DDFLIPFLAGS) object
ein gültiges DirectDrawSurface7-Objekt
dds
Dieser stellt die Verbindung zu einer beliebigen Suface aus der FlippingKette her. Die Defaulteinstellung ist Nothing. In diesem Fall würde DirectDraw in der Reihenfolge der einzelnen Kettenglieder die Surfaces flippen. Ist dieser Wert nicht Nothing, so flippt DirectDraw zu der angegeben Surface.
flags
Eine Konstante aus der CONST_DDFLIPFLAGS-Konstantenliste
DirectDrawSurface7.GetAttachedSurface GetAttachedSurface() Liest die Surface-Eigenschaften aus. object.GetAttachedSurface( caps As DDSCAPS2) As
DirectDrawSurface7
object
ein gültiges DirectDrawSurface7-Objekt
caps
Eine Variable vom Typ DDSCAPS2, welche als Empfänger der Surfaceeigenschaften dient.
418
DirectDraw-Methoden
DirectDrawSurface7.GetAttachedSurfaceEnum GetAttachedSurfaceEnum() Erstellt eine Liste von allen Surfaces, welche mit der aktuellen Surface verbunden sind. object.GetAttachedSurfaceEnum() As DirectDrawEnumSurfaces object
ein gültiges DirectDrawSurface7-Objekt
Dim SurfaceEnum as DirectDrawEnumSurfaces Set SurfaceEnum = object.GetAttachedSurfacesEnum()
DirectDrawSurface7.GetBltStatus GetBltStatus() Ermittelt den aktuellen Blitter-Status. object.GetBltStatus(flags As CONST_DDGBSFLAGS) As Long object
ein gültiges DirectDrawSurface7-Objekt
flags
eine Konstante aus der CONST_DDGBSFLAGS-Liste
DirectDrawSurface7.GetCaps GetCaps() Ermittelt die Leistungsfähigkeit einer Surface. object.GetCaps(caps As DDSCAPS2) object
ein gültiges DirectDrawSurface7-Objekt
caps
DDSCAPS2 Typen-Array, welches die Informationen der Surface aufnimmt.
DirectDrawSurface7.GetClipper GetClipper() Ermittelt den DirectDrawClipper, welcher mit der Surface verbunden ist. object.GetClipper() As DirectDrawClipper object
ein gültiges DirectDrawSurface7-Objekt
Dim Clipper as DirectDrawClipper Set Clipper = object.GetClipper()
Anhang A • Methoden
419
DirectDrawSurface7.GetColorKey GetColorKey() Ermittelt den Farbschlüssel, welcher mit der Surface verbunden ist. → DirectDrawSurface7.SetColorKey() object.GetColorKey(flags As Long, val As DDCOLORKEY) object
ein gültiges DirectDrawSurface7-Objekt
flags
Beschreibt, welcher Farbschlüssel ermittelt werden soll. DDCKEY_DESTBLT DDCKEY_DESTOVERLAY DDCKEY_SRCBLT DDCKEY_SRCOVERLAY
val
Farbschlüssel, welcher die Informationen aufnimmt.
DirectDrawSurface7.GetDC GetDC() Erzeugt ein GDI-kompatibeles Handle für die Surface. → DirectDrawSurface7.Lock() object.GetDC() As Long object
ein gültiges DirectDrawSurface7-Objekt
Diese Methode benutzt eine interne Variante der DirectDraw7.Lock()-Methode. Die Surface bleibt solange geschützt, bis die DirectDraw7.ReleaseDC()-Methode aufgerufen wird.
DirectDrawSurface7.GetDirectDraw GetDirectDraw() Ermittelt das DirectDraw-Objekt, welches benutzt wurde, um die Surface zu erstellen. object.GetDirectDraw() As DirectDraw7 object
ein gültiges DirectDrawSurface7-Objekt
Dim DDrawObject as DirectDraw7 Set DDrawObject = object.GetDDInterface()
DirectDrawSurface7.GetDirectDrawColorControl GetDirectDrawColorControl() Ermittelt das DirectDrawColor-Objekt, welches von der Surface benutzt wird.
420
DirectDraw-Methoden
GetDirectDrawColorControl() object.GetDirectDrawColorControl() As DirectDrawColorControl object
ein gültiges DirectDrawSurface7-Objekt
DirectDrawSurface7.GetDirectDrawGammaControl GetDirectDrawGammaControl() Ermittelt das DirectDrawGammaControl-Objekt, welches von der Surface benutzt wird. object.GetDirectDrawGammaControl() As DirectDrawGammaControl object
ein gültiges DirectDrawSurface7-Objekt
DirectDrawSurface7.GetDrawStyle GetDrawStyle() Ermittelt den Zeichenstil, welcher durch die DirectDraw7.SetDrawStyle()-Methode gesetzt wurde. object.GetDrawStyle() As Long object
ein gültiges DirectDrawSurface7-Objekt
DirectDrawSurface7.GetDrawWidth GetDrawWidth() Ermittelt die Stiftbreite, welche durch die DirectDraw7.SetDrawWidth()-Methode gesetzt wurde. Die voreingestellte Stiftbreite ist 1. object.GetDrawWidth() As Long object
ein gültiges DirectDrawSurface7-Objekt
DirectDrawSurface7.GetFillColor GetFillColor() Ermittelt die Füllfarbe, welche durch die DirectDraw7.SetFillColor()-Methode gesetzt wurde. Die voreingestellte Füllfarbe ist schwarz. object.GetFillColor() As Long object
ein gültiges DirectDrawSurface7-Objekt
Anhang A • Methoden
421
DirectDrawSurface7.GetFillStyle GetFillStyle() Ermittelt das Füllmuster, welches durch die DirectDraw7.SetFillStyle()-Methode gesetzt wurde. Der voreingestellte Wert ist transparent. object.GetFillStyle() As Long object
ein gültiges DirectDrawSurface7-Objekt
DirectDrawSurface7.GetFlipStatus GetFlipStatus() Ermittelt den aktuellen Flippstatus. object.GetFlipStatus(flags As CONST_DDGFSFLAGS) As Long object
ein gültiges DirectDrawSurface7-Objekt
flags
DDGFS_CANFLIP DDGFS_ISFLIPDONE
DirectDrawSurface7.GetFontBackColor GetFontBackColor() Ermittelt die Hintergrundfarbe des Zeichensatz. → DirectDrawSurface7.SetFontBackColor() object.GetFontBackColor() As Long object
ein gültiges DirectDrawSurface7-Objekt
DirectDrawSurface7.GetFontTransparency GetFontTransparency() Ermittelt, ob der Hintergrund des Zeichensatzes transparent ist. Die Transparenz wurde durch die directDrawSurface7.SetFontTransparency()-Methode zugeordnet. object.GetFontTransparency() As Boolean object
ein gültiges DirectDrawSurface7-Objekt
DirectDrawSurface7.GetForeColor GetForeColor() Ermittelt die Vordergrundfarbe des Zeichensatzes. object.GetForeColor() As Long
422
DirectDraw-Methoden
GetForeColor() object
ein gültiges DirectDrawSurface7-Objekt
DirectDrawSurface7.GetLockedArray GetLockedArray() Ermittelt einen Zeiger auf Surfacepixel, welche durch die DirectDrawSurface7.Lock() Methode geschützt wurden. object.GetLockedArray( array() As Byte) object
ein gültiges DirectDrawSurface7-Objekt
array()
Feld von geschützten Pixeln in Byte
Diese Methode darf nur zwischen den DirectDrawSurface7.Lock()- und DirectDrawSurface7.Unlock()-Methoden aufgerufen werden. Stellen Sie sicher, dass Sie nicht in ungeschützte Speicherbereiche schreiben.
DirectDrawSurface7.GetLockedPixel GetLockedPixel() Ermittelt ein Pixel, welches mit der DirectDrawSurface7.SetLockedPixel()-Methode gesetzt wurde. object.GetLockedPixel( x As Long, y As Long) As Long object
ein gültiges DirectDrawSurface7-Objekt
x, y
Koordinaten des geschützten Pixels
DirectDrawSurface7.GetLOD GetLOD() Ermittelt den Detailevel einer MipMap-Surface. → DirectDrawSurface7.SetLOD() object.GetLOD() As Long object
ein gültiges DirectDrawSurface7-Objekt
Diese Methode kann nur für Managed-Texturen (DDSCAPS_TEXTUREMANAGE) aufgerufen werden. Gehen wir von dem Beispiel aus, dass eine Mipmap-Surface erstellt wurde. Die größte Textur-Surface hat die Dimensionen von 256x256. Sie erhalten von der GetLOD()-Methode den Index 2 zurück. Dieser besagt, dass nur Texturen mit einer maximalen Größe von 64x64 im lokalen Videospeicher abgelegt werden.
Anhang A • Methoden
423
DirectDrawSurface7.GetOverlayPosition GetOverlayPosition() Ermittelt die Bildschirmkoordinaten einer existierenden Overlay-Surface. object.GetOverlayPosition(x As Long, y As Long) object
ein gültiges DirectDrawSurface7-Objekt
x, y
Koordinaten der Surface auf dem Bildschirm
DirectDrawSurface7.GetOverlayZOrdersEnum GetOverlayZOrdersEnum() Erstellt eine Liste aller Overlay-Surfaces entweder in der Reihenfolge front-to-back oder back-to-front. object.(flags As CONST_DDENUMOVERLAYZFLAGS) _ As DirectDrawEnumSurfaces object
ein gültiges DirectDrawSurface-Objekt
flags
DDENUMOVERLAYZ_BACKTOFRONT DDENUMOVERLAYZ_FRONTTOBACK
DirectDrawSurface7.GetPalette GetPalette() Ermittelt das DirectDrawPalette-Objekt, welches mit der Surface verbunden ist. → DirectDrawSurface7.SetPalette() object.GetPalette() As DirectDrawPalette object
ein gültiges DirectDrawSurface-Objekt
Dim DDPalette as DirectDrawPalette Set DDPalette = object.GetPalette()
DirectDrawSurface7.GetPixelFormat GetPixelFormat() Ermittelt das Pixelformat. object.GetPixelFormat(pf As DDPIXELFORMAT) object
ein gültiges DirectDrawSurface-Objekt
pf
Wird mit detaillierten Informationen über das Pixelformat gefüllt.
424
DirectDraw-Methoden
DirectDrawSurface7.GetPriority GetPriority() Ermittelt die Texturemanaged-Stufe einer Textursurface. object.GetPriority() As Long object
ein gültiges DirectDrawSurface-Objekt
DirectDrawSurface7.GetSurfaceDesc GetSurfaceDesc() Liest die Surface-Beschreibungen aus. object.GetSurfaceDesc(surface As DDSURFACEDESC2) object
ein gültiges DirectDrawSurface7-Objekt
surface
Eine Variable vom Typ DDSURFACEDESC2, welche als Empfänger der Surfacebeschreibungen dient.
DirectDrawSurface7.IsLost IsLost() Ermittelt, ob der Surfacespeicher freigegeben wurde. object.IsLost() As Long object
ein gültiges DirectDrawSurface-Objekt
DirectDrawSurface7.Lock Lock() Erstellt einen Zeiger auf den Surfacespeicher. Gleichzeitig wird der Speicherbereich geschützt. object.Lock(r As RECT, desc As DDSURFACEDESC2, _ flags As CONST_DDLOCKFLAGS, hnd As Long) object
ein gültiges DirectDrawSurface7-Objekt
r
Eine RECT-Struktur, welche den Speicherbereich beschreibt. Wird eine leere RECT-Struktur übergeben, so wird die gesamte Surface geschützt.
desc
Eine Variable vom Typ DDSURFACEDESC2, welche mit den relevanten Details der Surface gefüllt wird.
flags
Eine Konstante aus der CONST_DDLOCKFLAGS-Liste. Sie beschreibt, in welcher Art der Speicherbereich gesperrt werden soll.
hnd
Wird zurzeit nicht genutzt. Muss auf 0 gesetzt werden.
Anhang A • Methoden
425
DirectDrawSurface7.ReleaseDC ReleaseDC() Gibt das Handle einer Surface frei. object.ReleaseDC(hdc As Long) object
ein gültiges DirectDrawSurface-Objekt
hdc
Handle des Gerätes
DirectDrawSurface7.SetClipper SetClipper() Setzt das Clipper-Objekt. object.SetClipper(val As DirectDrawClipper) object
ein gültiges DirectDrawSurface-Objekt
val
DirectDrawClipper-Objekt
DirectDrawSurface7.SetColorKey SetColorKey() Setzt den Farbschlüssel. object.SetColorKey( flags As CONST_DDCKEYFLAGS, _ val As DDCOLORKEY) object
ein gültiges DirectDrawSurface-Objekt
flags
eine Variable aus der CONST_DDCKEYFLAGS-Liste
val
Farbschlüssel
DirectDrawSurface7.SetDrawStyle SetDrawStyle() Setzt den Zeichenstil . object.SetDrawStyle(drawStyle As Long) object
ein gültiges DirectDrawSurface7-Objekt
426
DirectDraw-Methoden
SetDrawStyle() drawStyle
0 1 2 3 4 5 6
→ → → → → → →
voll (solid), massiv gestrichelt gepunktet Strich und Punkt wechseln sich ab erst ein Strich, dann zwei Punkte durchsichtig gefüllt (bei einem Rechteck wird nicht nur der Rahmen gezeichnet, sondern das Rechteck wird gefüllt. Gleiches gilt bei einem Kreis, Oval oder abgerundeten Rechteck.
DirectDrawSurface7.SetDrawWidth SetDrawWidth() Setzt die Strichbreite für Zeichenmethoden. object.SetDrawWidth(drawWidth As Long) object
ein gültiges DirectDrawSurface7-Objekt
drawWidth
Strichbreite in Pixeln. Der voreingestellte Wert ist 1. Der erlaubte Wertebereiche liegt zwischen 1 und 32,767.
DirectDrawSurface7.SetFillColor SetFillColor() Setzt die Füllfarbe für Zeichenmethoden. object.SetFillColor(color As Long) object
ein gültiges DirectDrawSurface7-Objekt
color
Farbe. Der voreingestellte Wert ist Schwarz (&H00000000)
DirectDrawSurface7.SetFillStyle SetFillStyle() Setzt das Füllmuster für Zeichenmethoden. object.SetFillStyle(fillStyle As Long) object
ein gültiges DirectDrawSurface7-Objekt
Anhang A • Methoden
427
SetFillStyle() fillStyle
0 1 2 3 4 5 6 7
→ → → → → → → →
voll (solid), massiv durchsichtig horizontale Linien vertikale Linien diagonal aufwärts diagonal abwärts horizontale und vertikale Linien diagonale horizontale und diagonale vertikale Linien
DirectDrawSurface7.SetFont SetFont() Setzt einen neuen Zeichensatz für die DrawText()-Methode. object.SetFont(font As IFont) object
ein gültiges DirectDrawSurface7-Objekt
font
Zeichensatz
DirectDrawSurface7.SetFontBackColor SetFontBackColor() Setzt eine Hintergrundfarbe für einen Zeichensatz. object.SetFontBackColor(color As Long) object
ein gültiges DirectDrawSurface7-Objekt
color
Farbe
DirectDrawSurface7.SetFontTransparency SetFontTransparency() Legt fest, ob der aktuelle Zeichensatz transparent sein soll. object.SetFontTransparency(b As Boolean) object
ein gültiges DirectDrawSurface7-Objekt
b
True → transparent False → nicht transparent
428
DirectDraw-Methoden
DirectDrawSurface7.SetForeColor SetForeColor() Setzt die Zeichenfarbe, welche von den Zeichenmethoden verwendet wird. object.SetForeColor(color As Long) object
ein gültiges DirectDrawSurface7-Objekt
color
Farbe
DirectDrawSurface7.SetLockedPixel SetLockedPixel() Setzt ein einzelnes Pixel auf die spezifizierte Farbe. object.SetLockedPixel( x As Long, y As Long, col As Long) object
ein gültiges DirectDrawSurface7-Objekt
x, y
Koordinaten des Pixel
col
Farbe
DirectDrawSurface7.SetLOD SetLOD() Setzt die Detailstufe einer Managed-Mipmap-Surface. object.SetLOD(lod As Long) object
ein gültiges DirectDrawSurface7-Objekt
lod
Detailstufe
Diese Methode kann nur für Managed-Texturen (DDSCAPS_TEXTUREMANAGE) aufgerufen werden. Gehen wir von dem Beispiel aus, dass eine Mipmap-Surface erstellt wurde. Die größte Surface hat die Dimensionen von 256x256. Sie setzen mit der SetLOD()-Methode den Index 2. Dieser besagt, dass nur Texturen mit einer maximalen Größe von 64x64 im lokalen Videospeicher abgelegt werden.
DirectDrawSurface7.SetOverlayPosition SetOverlayPosition() Setzt die Bildschirmkoordinaten für eine Overlay-Surface. object.SetOverlayPosition(x As Long, y As Long) object
ein gültiges DirectDrawSurface7-Objekt
x, y
Koordinaten auf dem Bildschirm in Pixeln
Anhang A • Methoden
429
DirectDrawSurface7.SetPalette SetPalette() Verbindet oder entfernt eine Palette-Objekt von einer Surface. Die Surface wird ohne Wartezeit oder Refreshzeit die neue Palette nutzen. → DirectDrawSurface7.GetPalette, DirectDraw7.CreatePalette object.SetPalette(ddp As DirectDrawPalette) object
ein gültiges DirectDrawSurface7-Objekt
ddp
Eine Palette, welche gesetzt werden soll.
DirectDrawSurface7.Unlock Unlock() Hebt die Lock()-Methode wieder auf. Sie signalisiert DirectDraw, dass die Surfacemanipulationen abgeschlossen sind. object.Unlock(r As RECT) object
ein gültiges DirectDrawSurface7-Objekt
r
Eine RECT-Struktur, welche den Speicherbereich beschreibt. Dieser Parameter kann nur dann leer (Nothing) sein, wenn zuvor mit der Lock()-Methode die gesamte Surface geschützt wurde.
DirectDrawSurface7.UpdateOverlay UpdateOverlay() Repositioniert oder modifiziert die sichtbaren Attribute einer Overlay-Surface. Der Overlay-Surface muss das DDSCAPS_OVERLAY-Flag zugewiesen sein. object.UpdateOverlay(RECT As RECT, ddS As DirectDrawSurface7, _ rectD As RECT, flags As CONST_DDOVERFLAGS) object
ein gültiges DirectDrawSurface7-Objekt
rect
Definiert eine RECT-Struktur auf der Surface, welche von der OverlaySurface genutzt wird.
ddS
Surface, welche von der Overlay-Surface überlagert wird.
rectD
Definiert eine RECT-Struktur auf der Overlay-Surface, welche aktualisiert werden soll.
flags
Eine Konstante aus der CONST_DDOVERFLAGS-Liste
430
Direct3D-Methoden
DirectDrawSurface7.UpdateOverlayFx UpdateOverlayFx() Repositioniert oder modifiziert die sichtbaren Attribute einer Overlay-Surface mit speziellen Effekten. Der Overlay-Surface muss das DDSCAPS_OVERLAY-Flag zugewiesen sein. object.UpdateOverlayFx(RECT As RECT, ddS As DirectDrawSurface7, _ rectD As RECT, flags As CONST_DDOVERFLAGS object
ein gültiges DirectDrawSurface-Objekt
rect
Definiert eine RECT-Struktur auf der Surface, welche von der OverlaySurface genutzt wird.
ddS
Surface, welche von der Overlay-Surface überlagert wird.
rectD
Definiert eine RECT-Struktur auf der Overlay Surface, welche aktualisiert werden soll.
flags
eine Konstante aus der CONST_DDOVERFLAGS-Liste
ddoverfx
Definiert den anzuwendenden Effekt. DDOVERLAYFX Typen-Array.
DirectDrawSurface7.UpdateOverlayZOrder UpdateOverlayZOrder() Setzt die Tiefenreihenfolge der Overlay-Surface. object.UpdateOverlayZOrder( flags As CONST_DDOVERZFLAGS, _ ddS As DirectDrawSurface7) object
ein gültiges DirectDrawSurface-Objekt
flags
DDOVERZ_INSERTINBACKOF DDOVERZ_INSERTINFRONTOF DDOVERZ_MOVEBACKWARD DDOVERZ_MOVEFORWARD DDOVERZ_SENDTOBACK DDOVERZ_SENDTOFRONT
ddS
Definiert die Surface, deren Tiefenreihenfolge geändert werden soll.
A.3
Direct3D-Methoden
A.3.1
Direct3D7 Anwendungen verwenden die Direct3D7-Klasse, um Direct3D-Objekte zu erzeugen.
Anhang A • Methoden
431
Das Direct3D7-Objekt wird mit der DirectDraw7.GetDirect3D()-Methode erzeugt. Folgende Methoden gehören zu der Direct3D7-Klasse: Erzeugen
CreateDevice CreateVertexbuffer
Listen
GetDevicesEnum GetEnumZBufferFormats
Verschiedenes
EvictManagedTextures GetDirectDraw
Direct3D7.CreateDevice CreateDevice() Erzeugt ein Direct3D-Device, welches von der DrawPrimitive()-Methode genutzt wird. object.CreateDevice( guid As String, surf As DirectDrawSurface7) _ As Direct3DDevice7 Object
ein gültiges Direct3D7-Objekt
Guid
IID_Direct3DHALDevice IID_Direct3DRGBDevice
Surf
Eine Surface, welche als Renderziel verwendet wird. Die Surface muss mit dem DDSCAPS_3DDEVICE-Flag indiziert sein.
Direct3D7.CreateVertexbuffer CreateVertexBuffer() Erstellt ein Vertexbuffer-Objekt. object.CreateVertexbuffer( desc As D3DVERTEXBUFFERDESC, _ flags As CONST_D3DDPFLAGS) As Direct3DVertexbuffer7 object
ein gültiges Direct3D7-Objekt
desc
D3DVERTEXBUFFERDESC Typen-Array, welches das Format und die Anzahl der Vertexe des Vertexbuffers enthält.
flags
eine Konstante aus der CONST_D3DDPFLAGS-Liste
Direct3D7.EvictManagedTextures EvictManagedTextures() Löscht alle Managed-Texturen aus dem lokalen Videospeicher.
432
Direct3D-Methoden
EvictManagedTextures() object.EvictManagedTextures() object
ein gültiges Direct3D7-Objekt
Entfernt alle Texturen aus dem lokalen Videospeicher, welche mit dem DDSCAPS2_ TEXTUREMANAGE- oder DDSCAPS2_D3DTEXTUREMANAGE-Flag erstellt wurden.
Direct3D7.GetDevicesEnum GetDevicesEnum() Erzeugt ein Direct3DenumDevices-Objekt. object.GetDevicesEnum() As Direct3DenumDevices object
ein gültiges Direct3D7-Objekt
Direct3D7.GetDirectDraw GetDirctDraw() Ermittelt das DirectDraw-Objekt, welches mit dem Direct3D-Objekt verbunden ist. object.GetDirectDraw() As DirectDraw7 object
ein gültiges Direct3D7-Objekt
Direct3D7.GetEnumZBufferFormats GetEnumZBufferFormats() Erzeugt ein Direct3DenumPixelFormats-Objekt. object.GetEnumZBufferFormats( guid As String) As Direct3DenumPixelFormats
A.3.2
object
ein gültiges Direct3D7-Objekt
guid
Eine global eindeutige Identifizierung für das Device, für welches das Objekt erstellt werden soll.
Direct3DDevice7 Die Direct3DDevice7-Klasse ermöglicht das Rendern einer Szene. Das Direct3DDevice7 wird mit der Direct3D.CreateDevice()-Methode erstellt. Folgende Methoden gehören zu der Direct3DDevice7-Klasse:
Anhang A • Methoden
433
Information
GetCaps GetDirect3D GetInfo GetDeviceGuid
Gerätezustand
ApplyStateBlock BeginStateBlock CaptureStateBlock CreateStateBlock DeleteStateBlock EndStateBlock GetClipStatus GetRenderState GetRenderStateSingle GetRenderTarget GetTransform SetClipStatus SetRenderState SetRenderStateSingle SetRenderTarget SetTransform
Lighting and Materials
GetMaterial GetLight GetLightEnable LightEnable SetMaterial SetLight
Verschiedenes
ComputeSphereVisibility MultiplyTransform
Rendering
DrawIndexedPrimitive DrawIndexedPrimitiveVB DrawPrimitive DrawPrimitiveVB
Szenen
BeginScene EndScene
Texturen
GetTexture GetTextureFormatsEnum GetTextureStageState GetTextureStageStateSingle Load PreLoad SetTexture SetTextureStageState SetTextureStageStateSingle ValidateDevice
434
Direct3D-Methoden
ClipPlanes
GetClipPlane SetClipPlane
Viewport
Clear GetViewport SetViewport
Direct3DDevice7.ApplyStateBlock ApplyStateBlock() Setzt einen existierenden Stateblock ein. → Direct3DDevice7.BeginStateBlock(), Direct3DDevice7.CaptureStateBlock(), Direct3DDevice7.CreateStateBlock(), Direct3DDevice7.DeleteStateBlock(), Direct3DDevice7.EndStateBlock() object.ApplyStateBlock( blockHandle As Long) object
ein gültiges Direct3DDevice7-Objekt
blockHandle
Handle des StateBlocks
Ein Stateblock kann nicht eingesetzt werden, solange ein anderer Stateblock aufgezeichnet wird.
Direct3DDevice7.BeginScene BeginScene() Signalisiert den Anfang einer Szene. → Direct3Ddevice7.EndScene() object.BeginScene() object
ein gültiges Direct3DDevice7-Objekt
Vor einem erneuten Aufruf der Direct3Ddevice7.BeginScene()-Methode muss die Direct3Ddevice7.EndScene()-Methode aufgerufen worden sein.
Direct3DDevice7.BeginStateBlock BeginStateBlock() Signalisiert, dass die Aufzeichnung eines Stateblocks beginnt. → Direct3DDevice7.BeginStateBlock(), Direct3DDevice7.CaptureStateBlock(), Direct3DDevice7.CreateStateBlock(), Direct3DDevice7.DeleteStateBlock(), Direct3DDevice7.EndStateBlock() object.BeginStateBlock() object
ein gültiges Direct3DDevice7-Objekt
Anhang A • Methoden
435
BeginStateBlock() Folgende Methoden können in einem StateBlock aufgezeichnet werden: Direct3DDevice7.LightEnable() Direct3DDevice7.SetClipPlane() Direct3DDevice7.SetLight() Direct3DDevice7.SetMaterial() Direct3DDevice7.SetRenderState() Direct3DDevice7.SetTexture() Direct3DDevice7.SetTextureStageState() Direct3DDevice7.SetTransform() Direct3DDevice7.SetViewport()
Direct3DDevice7.CaptureStateBlock CaptureStateBlock() Aktualisiert die Werte eines Stateblock auf die für ein Device zurzeit gültigen Werte. → Direct3DDevice7.BeginStateBlock(), Direct3DDevice7.CaptureStateBlock(), Direct3DDevice7.CreateStateBlock(), Direct3DDevice7.DeleteStateBlock(), Direct3DDevice7.EndStateBlock() object.CaptureStateBlock( blockHandle As Long) object
ein gültiges Direct3DDevice7-Objekt
blockHandle
Handle für einen Stateblock
Direct3DDevice7.CreateStateBlock CreateStateBlock() Erzeugt einen Stateblock mit den aktuellen Werten eines Devices. Die übergebenen Werte können durch den d3dsbType Parameter eingeschränkt werden. → Direct3DDevice7.BeginStateBlock(), Direct3DDevice7.CaptureStateBlock(), Direct3DDevice7.CreateStateBlock(), Direct3DDevice7.DeleteStateBlock(), Direct3DDevice7.EndStateBlock() object.CreateStateBlock( d3dsbType As CONST_D3DSTATEBLOCKTYPE, _ blockHandle As Long) object
ein gültiges Direct3DDevice7-Objekt
d3sbType
eine Konstate aus der CONST_D3DSTATEBLOCKTYPE-Liste
blockHandle
Handle für einen Stateblock
436
Direct3D-Methoden
Direct3DDevice7.Clear Clear() Löscht den Viewport oder eine Gruppe von RECT-Strukturen in dem Viewport mit einer definierten Farbe oder löscht den Z-Buffer oder löscht den Stencilbuffer object.Clear( count As Long, recs() As D3DRECT, _ flags As CONST_D3DCLEARFLAGS, color As Long, z As Single, _ stencil As Long) object
ein gültiges Direct3DDevice7-Objekt
count
Anzahl der RECT Strukturen in dem recs()-Parameter
recs()
ein Array mit RECT-Strukturen, welche rechteckige Bereiche auf dem Viewport beschreiben.
flags
D3DCLEAR_TARGET D3DCLEAR_STENCIL D3DCLEAR_ZBUFFER
color
Farbe
z
Neuer Tiefenwerte, welcher im Z-Buffer gespeichert wird. Der Wertebereich liegt zwischen 0.0 und 1.0. Der Wert 0.0 ist die kürzeste Entfernung zum Betrachter.
stencil
Neuer Stencilbuffer-Wert, welcher in jedem Element des Stencilbuffer eingetragen wird. Der Wertebereich liegt zwischen 0.0 und 2n-1.
Die Methode führt zu einem Fehler, wenn beim flags-Parameter die Einträge D3DCLEAR_STENCIL oder D3DCLEAR_ZBUFFER verwendet werden, ohne dass diese Flags beim Renderziel gesetzt wurden.
Direct3DDevice7.ComputeSphereVisibility ComputeSphereVisibility() Überprüft die Sichtbarkeit eines Bereiches auf dem Viewport. object.ComputeSphereVisibility( center As D3DVECTOR, _ radius As Single) As Long object
ein gültiges Direct3DDevice7-Objekt
center
Mittelpunkt
radius
Radius
Sie können diese Methode einsetzen, um zu prüfen, ob Objekte oder Vertexe im sichtbaren Bereich des Betrachters liegen. Ist dies nicht der Fall, so brauchen die Objekte oder Vertexe nicht gerendert zu werden. Eine hilfreiche Methode, um eine Performancesteigerung zu erlangen.
Anhang A • Methoden
437
Direct3DDevice7.DeleteStateBlock DeleteStateBlock() Löscht einen zuvor aufgezeichneten Stateblock. → Direct3DDevice7.BeginStateBlock(), Direct3DDevice7.CaptureStateBlock(), Direct3DDevice7.CreateStateBlock(), Direct3DDevice7.DeleteStateBlock(), Direct3DDevice7.EndStateBlock() object.DeleteStateBlock(blockHandle As Long) object
ein gültiges Direct3DDevice7-Objekt
blockHandle
Handle eines Stateblocks
Direct3DDevice7.DrawIndexedPrimitive DrawIndexedPrimitive() Rendert ein Array von Vertexen. → Direct3DDevice7.DrawPrimitive(), Direct3DDevice7.DrawPrimitiveVB(), Direct3DDevice7.DrawIndexedPrimitiveVB() object.DrawIndexedPrimitive( d3Dpt As CONST_D3DPRIMITIVETYPE, _ d3dfvf As CONST_D3DFVFFLAGS, vertices As Any, vertexCount As _ Long, indices() As Integer, IndicesCount As Long, _ flags As CONST_D3DDPFLAGS) object
ein gültiges Direct3DDevice7-Objekt
d3Dpt
eine Konstante aus der CONST_D3DPRIMITIVETYPE-Liste
d3dfvf
Eine Kombination aus: D3DFVF_DIFFUSE D3DFVF_LVERTEX D3DFVF_NORMAL D3DFVF_SPECULAR D3DFVF_TLVERTEX D3DFVF_VERTEX D3DFVF_XYZ D3DFVF_XYZRHW D3DFVF_XYZB1 bis D3DFVF_XYZB5 D3DFVF_TEX0 bis D3DFVF_TEX8
vertices
das erste Element aus einem Vertex-Array
vertexCount
Anzahl der Vertexe, die gerendert werden sollen.
indices()
Ein Array, welches zum Indizieren der Vertexe verwendet wird.
IndicesCount
Anzahl der Indexe im indices()-Parameter
flags
Eine Konstante aus der CONST_D3DDPFLAGS-Liste
438
Direct3D-Methoden
Direct3DDevice7.DrawIndexedPrimitiveVB DrawIndexedPrimitiveVB() Rendert ein Array von Vertexen mit einem Vertexbuffer. → Direct3DDevice7.DrawPrimitive(), Direct3DDevice7.DrawPrimitiveVB(), Direct3DDevice7.DrawIndexedPrimitiveVB() object.DrawIndexedPrimitiveVB( d3Dpt As CONST_D3DPRIMITIVETYPE, _ vertexBuffer As Direct3DVertexbuffer7, StartVertex As Long, _ NumVertices As Long, indexArray() As Integer, indexcount _ As Long, flags As CONST_D3DDPFLAGS) object
ein gültiges Direct3DDevice7 Objekt
d3Dpt
eine Konstante aus der CONST_D3DPRIMITIVETYPE-Liste.
vertexBuffer
ein Direct3DVertexBuffer7-Objekt
StartVertex
Index des ersten Vertex im Vertexbuffer
NumVertices
Anzahl der Vertexe, die gerendert werden sollen.
indexArray()
Ein Array, welches zum Indizieren der Vertexe verwendet wird.
indexcount
Anzahl der Indexe in dem indexArray()-Parameter
flags
Eine Konstante aus der CONST_D3DDPFLAGS-Liste
Direct3DDevice7.DrawPrimitive DrawPrimitive() Rendert ein Array von Vertexen. → Direct3DDevice7.DrawPrimitiveVB(), Direct3DDevice7.DrawIndexedPrimitive(), Direct3DDevice7.DrawIndexedPrimitiveVB() object.DrawPrimitive( d3Dpt As CONST_D3DPRIMITIVETYPE, _ d3dfvf As CONST_D3DFVFFLAGS, vertices As Any, vertexCount As _ Long, flags As CONST_D3DDPFLAGS) object
ein gültiges Direct3DDevice7-Objekt
d3Dpt
eine Konstante aus der CONST_D3DPRIMITIVETYPE-Liste
Anhang A • Methoden
439
DrawPrimitive() d3dfvf
Eine Kombination aus: D3DFVF_DIFFUSE D3DFVF_LVERTEX D3DFVF_NORMAL D3DFVF_SPECULAR D3DFVF_TLVERTEX D3DFVF_VERTEX D3DFVF_XYZ D3DFVF_XYZRHW D3DFVF_XYZB1 bis D3DFVF_XYZB5 D3DFVF_TEX0 bis D3DFVF_TEX8
vertices
das erste Element aus dem Array mit Vertexen
vertexCount
Anzahl der Vertexe, die gerendert werden sollen.
flags
eine Konstante aus der CONST_D3DDPFLAGS-Liste
Direct3DDevice7.DrawPrimitiveVB DrawPrimitiveVB() Rendert ein Array von Vertexen in einem Vertexbuffer → Direct3DDevice7.DrawPrimitiveVB(), Direct3DDevice7.DrawIndexedPrimitive(), Direct3DDevice7.DrawIndexedPrimitiveVB() object.DrawPrimitiveVB( d3dpt As CONST_D3DPRIMITIVETYPE, _ vertexBuffer As Direct3DVertexbuffer7, startVertex As Long, _ numVertices As Long, flags As CONST_D3DDPFLAGS) object
ein gültiges Direct3DDevice7-Objekt
d3dpt
eine Konstante aus der CONST_D3DPRIMITIVETYPE Liste
vertexBuffer
ein Direct3DVertexBuffer7-Objekt
startVertex
Index des ersten Vertex, das gerendert werden soll.
numVertices
Anzahl der Vertexe, die gerendert werden sollen.
flags
eine Konstante aus der CONST_D3DDPFLAGS-Liste
440
Direct3D-Methoden
Direct3DDevice7.EndScene EndScene() Signalisiert das Ende einer Szene. → Direct3Ddevice7.BeginScene() object.EndScene() object
ein gültiges Direct3DDevice7-Objekt
Direct3DDevice7.EndStateBlock EndStateBlock() Signalisiert das Ender einer Aufzeichnung für einen Stateblock. → Direct3DDevice7.BeginStateBlock(), Direct3DDevice7.CaptureStateBlock(), Direct3DDevice7.CreateStateBlock(), Direct3DDevice7.DeleteStateBlock(), Direct3DDevice7.EndStateBlock() object.EndStateBlock( blockHandle As Long) object
ein gültiges Direct3DDevice7-Objekt
blockHandle
Handle des Stateblocks
Direct3DDevice7.GetCaps GetCaps() Ermittelt die Fähigkeiten eines Direct3D-Devices. object.GetCaps( desc As D3DDEVICEDESC7) object
ein gültiges Direct3DDevice7-Objekt
desc
D3DDEVICEDESC7 Typen-Array, welches die Informationen aufnimmt.
Direct3DDevice7.GetClipPlane GetClipPlane() Ermittelt die Koeffizienten der Benutzer-definierten Clippingplane. → Direct3DDevice7.SetClipPlane() object.GetClipPlane( Index As Long, a As Single, b As Single, c As Single, _ d As Single) object
ein gültiges Direct3DDevice7-Objekt
Anhang A • Methoden
441
GetClipPlane() Index
Index der Clippingplane
a, b, c, d
nehmen die ermittelten Werte auf.
Direct3DDevice7.GetClipStatus GetClipStatus() Ermittelt den aktuellen Clipstatus. → Direct3DDevice7.SetClipsStatus() object.GetClipStatus(clipStatus As D3DCLIPSTATUS) object
ein gültiges Direct3DDevice7-Objekt
clipStatus
D3DCLIPSTATUS Typen-Array, welches den Clipstatus aufnimmt.
Direct3DDevice7.GetDeviceGuid GetDeviceGuid() Ermittelt die Guid für das Device. object.GetDeviceGuid() As String object
ein gültiges Direct3DDevice7-Objekt
Direct3DDevice7.GetDirect3D GetDirect3D() Ermittelt das Direct3D Objekt für das Device. object.GetDirect3D() As Direct3D7 object
ein gültiges Direct3DDevice7-Objekt
Direct3DDevice7.GetInfo GetInfo() Ermittelt Informationen über das Renderdevice. → D3DDEVINFO_TEXTUREMANAGER() object.GetInfo( lDevInfoID As CONST_D3DDEVINFOID, _ DevInfoType As Any, lSize As Long) object
ein gültiges Direct3DDevice7-Objekt
442
Direct3D-Methoden
GetInfo() lDevInfoID
D3DDEVINFOID_D3DTEXTUREMANAGER D3DDEVINFOID_TEXTUREMANAGER D3DDEVINFOID_TEXTURING
DevInfoType
Eine Variable, welche die ermittelten Informationen aufnimmt.
lSize
Größe des DevInfoType-Parameters. Diese kann mit der VisualBasic-Funktion Len() ermittelt werden.
Direct3DDevice7.GetLight GetLight() Ermittelt die Eigenschaften eines Lichtobjektes. → Direct3DDevice7.SetLight(), Direct3DDevice7.GetLightEnable(),
Direct3D, Device7.LightEnable() object.GetLight( LightIndex As Long, Light As D3DLIGHT7) object
ein gültiges Direct3DDevice7-Objekt
LightIndex
Index der Lichtquelle
Light
D3DLIGHT Typen-Array, welches die ermittelten Werte aufnimmt.
Direct3DDevice7.GetLightEnable GetLightEnable() Ermittelt, ob eine Lichtquelle verfügbar ist. → Direct3DDevice7.SetLight(), Direct3DDevice7.GetLightEnable(), Direct3DDevice7.LightEnable() object.GetLightEnable( LightIndex As Long) As Boolean object
ein gültiges Direct3DDevice7-Objekt
LightIndex
Index der Lichtquelle
Direct3DDevice7.GetMaterial GetMaterial() Ermittelt die aktuellen Materialeigenschaften für das Device. → Direct3Ddevice7.SetMaterial() object.GetMaterial(
Material As D3DMATERIAL7)
Anhang A • Methoden
443
GetMaterial() object
ein gültiges Direct3DDevice7-Objekt
Material
D3DMATERIAL7-Typen-Array, welches die Informationen aufnimmt.
Direct3DDevice7.GetRenderState GetRenderState() Ermittelt den aktuellen Renderzustand des Devices. → Direct3DDevice7.SetRenderState() object.GetRenderState( state As CONST_D3DRENDERSTATETYPE) As Long object
ein gültiges Direct3DDevice7-Objekt
state
eine Konstante aus der CONST_D3DRENDERSTATETYPE-Liste
Direct3DDevice7.GetRenderStateSingle GetRenderStateSingle() Ermittelt den aktuellen Renderzustand des Devices. → Direct3DDevice7.SetRenderState(), Direct3DDevice7.SetRenderStateSingle() object.GetRenderStateSingle( _ state As CONST_D3DRENDERSTATESINGLE) As Single object
ein gültiges Direct3DDevice7-Objekt
state
D3DRENDERSTATE_FOGDENSITY D3DRENDERSTATE_ FOGEND D3DRENDERSTATE_FOGSTART
Direct3DDevice7.GetRenderTarget GetRenderTarget() Ermittelt die DirectDraw7-Surface, welche als Renderziel dient. → Direct3DDevice7.SetRenderTarget() object.GetRenderTarget() As DirectDrawSurface7 object
ein gültiges Direct3DDevice7-Objekt
444
Direct3D-Methoden
Direct3DDevice7.GetTexture GetTexture() Ermittelt die Textur, welche mit einer gegebenen Texturstufe verbunden ist, für das Device. → Direct3DDevice7.SetTexture(), Direct3DDevice7.GetTextureStageState(), Direct3DDevice7.SetTextureStageState() object.GetTexture(stage As Long) As DirectDrawSurface7 object
ein gültiges Direct3DDevice7-Objekt
stage
Texturestufe zwischen 0 und 7.
Direct3DDevice7.GetTextureFormatsEnum GetTextureFormatsEnum() Ermittelt das Pixelformat für das Device. object.GetTextureFormatsEnum() As Direct3DEnumPixelFormats object
ein gültiges Direct3DDevice7-Objekt
Direct3DDevice7.GetTextureStageState GetTextureStageState() Ermittelt den Zustand für die aktuelle Textur. → Direct3DDevice7.SetTextureStageState(), Direct3DDevice7.GetTexture(), Direct3DDevice7.SetTexture() object.GetTextureStageState( stage As Long, _ state As CONST_D3DTEXTURESTAGESTATETYPE) As Long object
ein gültiges Direct3DDevice7-Objekt
stage
Texturstufe, für welche der Zustand ermittelt werden soll.
state
eine Konstante aus der CONST_D3DTEXTURESTAGESTATE TYPE- Liste
Direct3DDevice7.GetTextureStageStateSingle GetTextureStageSingle() Ermittelt den Zustand für die aktuelle Textur. → Direct3DDevice7.SetTextureStageState(), Direct3DDevice7.GetTexture(), Direct3DDevice7.SetTexture() object.GetTextureStageStateSingle( stage As Long, _ state As CONST_D3DTEXTURESTAGESINGLE) As Single
Anhang A • Methoden
445
GetTextureStageSingle() object
ein gültiges Direct3DDevice7-Objekt
stage
Texturstufe, für welche der Zustand ermittelt werden soll.
state
eine Konstante aus der CONST_D3DTEXTURESTAGESTATE TYPE-Liste
Direct3DDevice7.GetTransform GetTransform() Ermittelt die Matrixbeschreibung einer Transformationsart. → Direct3DDevice7.SetTransform() object.GetTransform( _ transformType As CONST_D3DTRANSFORMSTATETYPE, _ matrix As D3DMATRIX) object
ein gültiges Direct3DDevice7-Objekt
transformType
D3DTRANSFORMSTATE_WORLD D3DTRANSFORMSTATE_WORLD1 D3DTRANSFORMSTATE_WORLD2 D3DTRANSFORMSTATE_WORLD3 D3DTRANSFORMSTATE_VIEW D3DTRANSFORMSTATE_PROJECTION D3DTRANSFORMSTATE_TEXTURE0 D3DTRANSFORMSTATE_TEXTURE1 D3DTRANSFORMSTATE_TEXTURE2 D3DTRANSFORMSTATE_TEXTURE3 D3DTRANSFORMSTATE_TEXTURE4 D3DTRANSFORMSTATE_TEXTURE5 D3DTRANSFORMSTATE_TEXTURE6 D3DTRANSFORMSTATE_TEXTURE7
matrix
D3DMATRIX-Typen-Array, welches die Beschreibung aufnimmt.
Direct3DDevice7.GetViewport GetViewport() Ermittelt die Viewport-Parameter für den Viewport, der aktuell für das Device gesetzt ist. → Direct3DDevice7.SetViewport() object.GetViewport( Viewport As D3DVIEWPORT7) object
ein gültiges Direct3DDevice7-Objekt
Viewport
D3DVIEWPORT7-Typen-Array, welches die Informationen aufnimmt.
446
Direct3D-Methoden
Direct3DDevice7.LightEnable LightEnable() Aktiviert oder deaktiviert eine Lichtquelle. → Direct3DDevice7.GetLight(), Direct3DDevice7.GetLightEnable(), Direct3DDevice7.SetLight() object.LightEnable( LightIndex As Long, bEnable As Boolean) object
ein gültiges Direct3DDevice7-Objekt
LightIndex
Index der Lichtquelle
bEnable
True oder False
Wird eine Lichtquelle eingeschaltet, ohne dass zuvor die Parameter bestimmt wurden, werden die voreingestellten Werte verwendet. dltType = D3DLIGHT_DIRECTIONAL dcvDiffuse (R:1, G:1, B:1, A:0) dcvSpecular (R:0, G:0, B:0, A:0) dcvAmbient (R:0, G:0, B:0, A:0) dvPosition (0, 0, 0) dvDirection (0, 0, 1) dvRange = 0 dvFalloff = 0 dvAttenuation0 = 0 dvAttenuation1 = 0 dvAttenuation2 = 0 dvTheta = 0 dvPhi = 0
Direct3DDevice7.Load Load() Lädt eine RECT-Struktur der Quelltexture in einen definierten Punkt der Zielsurface. object.Load( DestTex As DirectDrawSurface7, xDest As Long, _ yDest As Long, SrcTex As DirectDrawSurface7, rcSrcRect As RECT, _ flags As Long) object
ein gültiges Direct3DDevice7-Objekt
DestTex
Zielsurface
xDest, yDest
Koordinaten auf der Zielsurface
SrcTex
Quellsurface
rcSrcRect
RECT-Struktur auf der Quellsurface
Anhang A • Methoden
447
Load() flags
0 → benötigt eine gemanagte Textur DDSCAPS2_CUBEMAP_ALLFACES DDSCAPS2_CUBEMAP_NEGATIVEX DSCAPS2_CUBEMAP_NEGATIVEY DSCAPS2_CUBEMAP_NEGATIVEZ DDSCAPS2_CUBEMAP_POSITIVEX DSCAPS2_CUBEMAP_POSITIVEY DSCAPS2_CUBEMAP_POSITIVEZ
Direct3DDevice7.MultiplyTransform MultiplyTransform() Mulitpliziert die World-, View- oder Projektionsmatrix mit dem Matrix-Parameter. → Direct3DDevice7.DrawPrimitive(), Direct3DDevice7.SetTransform() object.MultiplyTransform( _ dstTransformStateType As CONST_D3DTRANSFORMSTATETYPE, _ matrix As D3DMATRIX) object
ein gültiges Direct3DDevice7-Objekt
destTransformStateType
eine Konstante aus der CONST_ D3DTRANSFORMSTATETYPE-Liste
matrix
Matrix, mit der multipliziert wird.
Direct3DDevice7.PreLoad PreLoad() Weist Direct3D an, eine verwaltete Textur in den Videospeicher zu laden. object.PreLoad(Texture As DirectDrawSurface7) object
ein gültiges Direct3DDevice7-Objekt
Texture
Verweis auf die Surface, welche in den Speicher geladen werden soll.
Direct3DDevice7.SetClipPlane SetClipPlane() Setzt die Koeffizienten für eine benutzerdefinierte Clippingplane. object.SetClipPlane( Index As Long, a As Single, b As Single, c As Single, _ d As Single)
448
Direct3D-Methoden
SetClipPlane() object
ein gültiges Direct3DDevice7-Objekt
Index
Index der Clippingplane
a, b, c, d
Werte, die gesetzt werden.
Direct3DDevice7.SetClipStatus SetClipStatus() Setzt den aktuellen Clipstatus. → Direct3DDevice7.GetClipStatus() object.SetClipStatus(clipStatus As D3DCLIPSTATUS) object
ein gültiges Direct3DDevice7-Objekt
clipStatus
D3DCLIPSTATUS-Typen-Array, welches die Informationen für den Clipstatus enthält.
Direct3DDevice7.SetLight SetLight() Setzt die Eigenschaften einer Lichtquelle. → Direct3DDevice7.GetLight(), Direct3DDevice7.GetLightEnable(), Direct3DDevice7.LightEnable() object.SetLight(LightIndex As Long, Light As D3DLIGHT7) object
ein gültiges Direct3DDevice7-Objekt
LightIndex
Index der Lichtquelle
Light
D3DLIGHT7 Typen-Array, welches die Eigenschaften der Lichtquelle speichert.
Direct3DDevice7.SetMaterial SetMaterial() Setzt die Materialeigenschaften des Devices. → Direct3DDevice7.GetMaterial() object.SetMaterial(mat As D3DMATERIAL7) object
ein gültiges Direct3DDevice7-Objekt
mat
D3DMATERIAL7-Typen-Array, welches die Materialeigenschaften enthält.
Anhang A • Methoden
449
Direct3DDevice7.SetRenderState SetRenderState() Setzt den Renderzustand des Devices. → Direct3Ddevice7.GetRenderState(), Direct3DDevice7.SetTransform() object.SetRenderState(state As CONST_D3DRENDERSTATETYPE, _ renderstate As Long) object
ein gültiges Direct3DDevice7-Objekt
state
eine Konstante der CONST_D3DRENDERSTATETYPE-Liste
renderstate
eine Konstante der CONST_D3DSHADEMODE-Liste
Direct3DDevice7.SetRenderStateSingle SetRenderStateSingle() Setzt den Renderzustand des Devices. → Direct3DDevice7.GetRenderState(), Direct3DDevice7.GetRenderStateSingle(), Direct3DDevice7.SetTransform() object.SetRenderStateSingle( state As CONST_D3DRENDERSTATESINGLE, _ renderstate As Single) object
ein gültiges Direct3DDevice7-Objekt
state
eine Konstante der CONST_D3DRENDERSTATESINGLE-Liste
renderstate
eine Konstante der CONST_D3DSHADEMODE-Liste
Direct3DDevice7.SetRenderTarget SetRenderTarget() Setzt ein neue Renderziel. → Direct3DDevice7.GetRenderTarget() object.SetRenderTarget(surface As DirectDrawSurface7) object
ein gültiges Direct3DDevice7-Objekt
surface
Surface, welche das neue Renderziel sein soll.
450
Direct3D-Methoden
Direct3DDevice7.SetTexture SetTexture() Setzt die Textur für eine Texturstufe für das Device. → Direct3DDevice7.GetTexture(), Direct3DDevice7.GetTextureStageState(), Direct3DDevice7.SetTextureStageState() object.SetTexture( stage As Long, texture As DirectDrawSurface7) object
ein gültiges Direct3DDevice7-Objekt
stage
Texturstufe
texture
Textursurface
Wenn die Texture nicht länger benötigt wird, dann setzen Sie die Texture auf Nothing. Tun Sie dies nicht, so verlieren Sie den Speicher der Surface, wenn Sie das Programm schließen.
Direct3DDevice7.SetTextureStageState SetTextureStageState() Setzt den Texturzustand der zugewiesenen Textur. → Direct3DDevice7.GetTextureStageState(), Direct3DDevice7.GetTexture(), Direct3DDevice7.SetTexture() object.SetTextureStageState( stage As Long, _ state As CONST_D3DTEXTURESTAGESTATETYPE, value As Long) object
ein gültiges Direct3DDevice7-Objekt
stage
Texturstufe
state
eine Konstante aus der CONST_D3DTEXTURESTAGESTATE TYPE-Liste
value
Wert
Direct3DDevice7.SetTextureStageStateSingle SetTextureStageStateSingle() Setzt den Texturzustand der zugewiesenen Textur. → Direct3DDevice7.GetTextureStageStateSingle(), Direct3DDevice7.GetTextureStageState(), Direct3DDevice7.GetTexture(), Direct3DDevice7.SetTexture() object.SetTextureStageStateSingle( stage As Long, _ state As CONST_D3DTEXTURESTAGESINGLE, value As Single) object
ein gültiges Direct3DDevice7-Objekt
stage
Texturstufe
Anhang A • Methoden
451
SetTextureStageStateSingle() state
eine Konstante aus der CONST_D3DTEXTURESTAGESINGLE-Liste
value
Wert
Direct3DDevice7.SetTransform SetTransform() Setzt einen einzelnen Transformationszustand. → Direct3DDevice7.GetTransform(), Direct3DDevice7.SetRenderState() object.SetTransform( _ transformType As CONST_D3DTRANSFORMSTATETYPE, _ matrix As D3DMATRIX) object
ein gültiges Direct3DDevice7-Objekt
transformType
eine Konstante aus der CONST_D3DTRANSFORMSTATETYPEListe
matrix
Matrix, welche die aktuelle Transformation modifiziert.
Direct3DDevice7.SetViewport SetViewport() Setzt den Viewport für das Device. → Direct3DDevice7.GetViewport() object.SetViewport( viewport As D3DVIEWPORT7) object
ein gültiges Direct3DDevice7-Objekt
viewport
D3DVIEWPORT7-Typen-Array, welches die Informationen über den Viewport enthält.
Direct3DDevice7.ValidateDevice ValidateDevice() Prüft, ob das Device in der Lage ist, die aktuellen Textureblending-Parameter in einem Durchgang zu rendern. → Direct3DDevice7.GetTextureStageState(), Direct3DDevice7.SetTextureStageState() object.ValidateDevice() As Long object
ein gültiges Direct3DDevice7-Objekt
452
A.3.3
Direct3D-Methoden
Direct3DEnumDevices Die Direct3DEnumDevices-Klasse ermittelt Informationen über die installierten 3D-Geräte. Das Direct3DEnumDevices-Objekt wird mit der Direct3D7.GetDevicesEnum()Methode erzeugt. Folgende Methoden gehören zu der Direct3DEnumDevices-Klasse: Device count
GetCount
Device information
GetDescription GetGuid GetDesc GetName
Direct3DEnumDevices.GetCount GetCount() Ermittelt die Anzahl der Direct3D-Devices, welche auf dem aktuellen System installiert sind. object.GetCount() As Long object
ein gültiges Direct3DEnumDevices-Objekt
Direct3DEnumDevices.GetDesc GetDesc() Ermittelt die Fähigkeiten eines gewünschten Direct3D-Devices. object.GetDesc(index As Long, hwDesc As D3DDEVICEDESC7) object
ein gültiges Direct3DEnumDevices-Objekt
index
Identifiziert das installierte Direct3D-Device.
hwDesc
D3DDEVICEDESC7-Typen-Array, welches die ermittelten Werte aufnimmt.
Direct3DEnumDevices.GetDescription GetDescription() Ermittelt eine allgemein verständliche Beschreibung des Direct3D-Devices. object.GetDescription(index As Long) As String object
ein gültiges Direct3DenumDevices-Objekt
Anhang A • Methoden
453
GetDescription() index
Identifiziert das installierte Direct3D-Device.
Direct3DEnumDevices.GetGuid GetGuid() Ermittelt den Guid eines Direct3D-Devices. object.GetGuid(index As Long) As String object
ein gültiges Direct3DenumDevices-Objekt
index
Identifiziert das installierte Direct3D-Device.
Die möglichen Rückgabewerte sind: IID_IDirect3DHALDevice IID_IDirect3DtnLHalDevice IID_IDirect3DRGBDevice
Direct3DEnumDevices.GetName GetName() Ermittelt einen allgemein verständlichen Namen des Direct3D-Devices. object.GetName(index As Long) As String
A.3.4
object
ein gültiges Direct3DenumDevices-Objekt
index
Identifiziert das installierte Direct3D-Device.
Direct3DEnumPixelFormats Die Direct3DEnumPixelFormats-Klasse liefert Informationen über die Pixelformate, welche von dem 3D-Gerät unterstützt werden. Das Direct3DEnumPixelFormats-Objekt wird mit den Direct3DDevice7. GetTextureFormatsEnum()- und Direct3D7.GetEnumZBufferFormats()-Methoden erzeugt. Folgende Methoden gehören zu der Direct3DEnumPixelFormats-Klasse: Information
GetCount GetItem
454
Direct3D-Methoden
Direct3DEnumPixelFormats.GetCount GetCount() Ermittelt die Anzahl der unterstützten Pixelformate des Direct3D-Devices. object.GetCount() As Long object
ein gültiges Direct3DEnumPixelFormats-Objekt
Direct3DenumPixelFormats.GetItem GetItem() Ermittelt die Beschreibung eines Pixelformats. object.GetCount() As Long
A.3.5
Object
ein gültiges Direct3DEnumPixelFormats-Objekt
Desc
DDPIXELFORMAT Typen-Array, welches die ermittelte Beschreibung aufnimmt.
Direct3DVertexBuffer7 Die Direct3DVertexbuffer7-Klasse wird verwendet, um eine Sammlung von Vertexen zu manipulieren. Die Vertexe werden von der Direct3DDevice7.DrawPrimitiveVB()- und Direct3DDevice7.DrawIndexedPrimitiveVB()-Methode verwendet. Folgende Methoden gehören zu der Direct3DVertexbuffer7-Klasse: Information
GetVertexBufferDesc
Vertex data
GetVertices Lock Optimize ProcessVertices SetVertices Unlock
Direct3DVertexBuffer7.GetVertexbufferDesc GetVertexbufferDesc() Ermittelt die Beschreibung eines Vertexbuffers. object.GetVertexbufferDesc(desc As D3DVERTEXBUFFERDESC) Object
ein gültiges Direct3DVertexBuffer7-Objekt
Anhang A • Methoden
455
GetVertexbufferDesc() Desc
D3DVERTEXBUFFERDESC Typen-Array, welches die ermittelte Beschreibung aufnimmt.
Direct3DVertexBuffer7.GetVertices GetVertices() Ermittelt die Vertexe in einem Vertexbuffer. object.GetVertices(startIndex As Long, count As Long, verts As Any) Object
ein gültiges Direct3DVertexBuffer7-Objekt
startIndex
das erste Element in einem Vertexbuffer
Count
Anzahl der zu ermittelnden Vertexe.
Verts
Erstes Element eines Arrays, welches mit den Informationen gefüllt werden soll.
Direct3DVertexBuffer7.Lock Lock() Schützt einen Vertex-Buffer. → Direct3DVertexbuffer7.Unlock() object.Lock(flags As CONST_DDLOCKFLAGS) object
ein gültiges Direct3DVertexBuffer7-Objekt
flags
DDLOCK_NOSYSLOCK DDLOCK_READONLY DDLOCK_WAIT DDLOCK_WRITEONLY DDLOCK_DISCARDCONTENTS DDLOCK_NOOVERWRITE
Solange der Vertexbuffer geschützt ist, können Sie die Vertexe in dem Buffer manipulieren. Hierzu verwenden Sie die Methoden: Direct3DVertexBuffer7.GetVertices und Direct3DVertexBuffer7.SetVertices(). Aus einen geschützten Vertexbuffer können Sie nicht rendern.
Direct3DVertexBuffer7.Optimize Optimize() Konvertiert einen nichtoptimierten Vertexbuffer in einen optimierten Vertexbuffer. object.Optimize(dev As Direct3DDevice7) object
ein gültiges Direct3DVertexBuffer7-Objekt
456
Direct3D-Methoden
Optimize() dev
ein Direct3DDevice7-Objekt für welches der Vertexbuffer optimiert werden soll.
Direct3DVertexBuffer7.ProcessVertices ProcessVertices() Wandelt untransformierte Vertexe in einen transformierten oder optimierten Vertexbuffer. object.ProcessVertices( vertexOp As CONST_D3DVOPFLAGS, _ destIndex As Long, count As Long, srcBuffer As Direct3DVertexbuffer7, _ srcIndex As Long, dev As Direct3DDevice7, _ flags As CONST_D3DPROCESSVERTICESFLAGS) object
ein gültiges Direct3DVertexBuffer7-Objekt
vertexOp
D3DVOP_CLIP D3DVOP_EXTENTS D3DVOP_LIGHT D3DVOP_TRANSFORM
destIndex
Index im Ziel-Vertexbuffer, in dem die Vertexe nach der Transformation untergebracht werden.
count
Anzahl der Vertexe im Quell-Vertexbuffer
srcBuffer
ein Direct3DVertexBuffer7-Objekt
srcIndex
Index des ersten Vertex im Quell-Vertexbuffer
dev
Ein Direct3DDevice7-Objekt, welches die transformierten Vertexe verwendet.
flags
D3DPV_DEFAULT D3DPV_DONOTCOPYDATA
Direct3DVertexBuffer7.SetVertices SetVertices() Setzt die Vertexe in einen geschützen Vertexbuffer. → Direct3DVertexbuffer7.GetVertices(), Direct3DVertexbuffer7.Lock() object.SetVertices(startIndex As Long, count As Long, verts As Any) object
ein gültiges Direct3DVertexBuffer7-Objekt
startIndex
Index des ersten Vertex, welches gesetzt werden soll.
Anhang A • Methoden
457
SetVertices() count
Anzahl der Vertexe, die gesetzt werden sollen.
verts
erstes Element der Vertexdaten
Direct3DVertexBuffer7.Unlock Unlock() Hebt den Schutz des Vertexbuffers auf. object.Unlock() object
ein gültiges Direct3DVertexBuffer7-Objekt
A.4
DirectSound-Methoden
A.4.1
DirectSound Programme benutzen die Methoden der DirectSound-Klasse zum Erstellen von DirectSound-Objekten und zum Einstellen der Umgebungskonfiguration. Das DirectSound-Objekt wird mit der DirectX7.DirectSoundCreate()-Methode erzeugt. Die Methoden der DirectSound-Klasse können in folgende Gruppen unterteilt werden: Initialisierung
SetCooperativeLevel
Erstellen von Bufferobjekten
CreateSoundBuffer CreateSoundBufferFromFile CreateSoundBufferFromResource DuplicateSoundBuffer
Device-Beschreibungen
GetCaps
Lautsprecherkonfiguration
GetSpeakerConfig SetSpeakerConfig
458
DirectSound-Methoden
DirectSound.CreateSoundBuffer CreateSoundBuffer() Erstellt einen DirectSoundBuffer. → DirectSound.DuplicateSoundBuffer(), DirectSound.SetCooperativeLevel(), DirectSoundBuffer(), DirectSoundBuffer.GetFormat(), DirectSoundBuffer. GetVolume(), DirectSoundBuffer.Play(), DirectSoundBuffer.SetFormat(), DirectSoundBuffer.SetFrequency() object.CreateSoundBuffer(bufferDesc As DSBUFFERDESC, _ format As WAVEFORMATEX) As DirectSoundBuffer Object
ein gültiges DirectSound-Objekt
BufferDesc
DSBUFFERDESC Typ beinhaltet die Beschreibung zum Erstellen eines Soundbuffers.
format
WAVEFORMATEX Typ beschreibt das Wellenformat der Audiodaten.
DirectSound.CreateSoundBufferFromFile CreateSoundBufferFromFile() Erstellt einen DirectSoundBuffer aus einer Wavedatei. object.CreateSoundBufferFromFile(filename As String, _ bufferDesc As DSBUFFERDESC, _ format As WAVEFORMATEX) As DirectSoundBuffer object
ein gültiges DirectSound-Objekt
filename
Dateiname eines Wavefiles
bufferDesc
DSBUFFERDESC Typ beinhaltet die Beschreibung zum Erstellen eines Soundbuffers.
format
WAVEFORMATEX Typ beschreibt das Wellenformat der Audiodaten.
DirectSound.CreateSoundBufferFromResource CreateSoundBufferFromResource() Erstellt einen DirectSoundBuffer von einer Ressource. object.CreateSoundBufferFromResource( dll As String, _ resourceName As String, bufferDesc As DSBUFFERDESC, _ format As WAVEFORMATEX) As DirectSoundBuffer object
ein gültiges DirectSound-Objekt
dll
Name der dll, die die Ressource beinhaltet.
Anhang A • Methoden
459
CreateSoundBufferFromResource() resourceName
Name der Ressource
bufferDesc
DSBUFFERDESC Typ beinhaltet die Beschreibung zum Erstellen eines Soundbuffers.
format
WAVEFORMATEX Typ beschreibt das Wellenformat der Audiodaten.
DirectSound.DuplicateSoundBuffer DuplicateSoundBuffer() Erstellt ein neues DirectSoundBuffer-Objekt, das den gleichen Speicherbereich wie das Originalobjekt benutzt. object.DuplicateSoundBuffer( original As DirectSoundBuffer) _ As DirectSoundBuffer object
ein gültiges DirectSound-Objekt
original
DirectSoundBuffer, von dem eine Kopie angefertigt werden soll.
Das Original sowie die Kopie können autonom gesteuert werden. Änderungen an den Sound-Daten wirken sich auf beide Bufferobjekte aus.
DirectSound.GetCaps GetCaps() Gibt die Fähigkeiten der Soundhardware zurück. object.GetCaps(caps As DSCAPS) object
ein gültiges DirectSound-Objekt
caps
ein DSCAPS Typ, der die Beschreibung aufnimmt.
Der DSCAPS-Typ beinhaltet alle Fähigkeiten der Soundhardware, die zur Verfügung stehen, die Anzahl der Sound-Mischkanäle sowie die Größe des Soundkartenspeichers.
DirectSound.GetSpeakerConfig GetSpeakerConfig() Gibt die Lautsprecherkonfiguration zurück. object.GetSpeakerConfig() As CONST_DSSPEAKERFLAGS object
ein gültiges DirectSound-Objekt
460
DirectSound-Methoden
DirectSound.SetCooperativeLevel SetCooperativeLevel() Setzt den CooperativeLevel der Applikation auf die Soundkarte. object.SetCooperativeLevel(hwnd As Long, _ level As CONST_DSSCLFLAGS) object
ein gültiges DirectSound-Objekt
hwnd
Windows-Handle der Applikation
level
Prioritätsstufe CONST_DSSCLFLAGS
DirectSound.SetSpeakerConfig SetSpeakerConfig() Stellt die Lautsprecherkonfiguration des DirectSound-Objekts ein. object.SetSpeakerConfig( speakerConfig As CONST_DSSPEAKERFLAGS)
A.4.2
object
ein gültiges DirectSound-Objekt
speakerConfig
Lautsprecherkonfiguration aus CONST_DSSPEAKERFLAGS
DirectSound3DBuffer Die Methoden der DirectSound3DBuffer-Klasse empfängt und setzt die Parameter zum Positionieren und Ausrichten eines Sounds im 3D-Raum. Das DirectSound3DBuffer-Objekt wird mit der DirectSoundBuffer.Query Interface()-Methode erzeugt. Die Methoden der DirectSound3DBuffer-Klasse werden in folgende Gruppen unterteilt. Parameterveränderung
GetAllParameters SetAllParameters
Entfernung
GetMaxDistance GetMinDistance SetMaxDistance SetMinDistance
Objekte
GetDirectSound3Dlistener GetDirectSoundBuffer
Operatonsmodus
GetMode SetMode
Anhang A • Methoden
461
Position
GetPosition SetPosition
Klangprojektion und Abstrahlung
GetConeAngles GetConeOrientation GetConeOutsideVolume SetConeAngles SetConeOrientation SetConeOutsideVolume
Geschwindigkeit
GetVelocity SetVelocity
DirectSound3DBuffer.GetAllParameters GetAllParameters() Empfängt Informationen über die 3D-Charakterristik eines Soundbuffers zu einer bestimmten Zeit. object.GetAllParameters(buffer As DS3DBUFFER) object
ein gültiges DirectSound3DBuffer-Objekt
buffer
DS3DBUFFER-Typ
DirectSound3DBuffer.GetConeAngles GetConeAngles() Empfängt die Winkel des inneren und äußeren Klangtrichters. → DirectSound3DBuffer.SetConeAngles() object.GetConeAngles(inCone As Long, outCone As Long) object
ein gültiges DirectSound3Dbuffer-Objekt
inCone
Winkel des inneren Klangtrichters
outCone
Winkel des äußeren Klangtrichters
DirectSound3DBuffer.GetConeOrientation GetConeOrientation() Empfängt die Ausrichtung des Klangtrichters. → DirectSound3DBuffer.SetConeOrientation() object.GetConeOrientation(orientation As D3DVECTOR) object
ein gültiges DirectSound3DBuffer-Objekt
orientation
Dieser Vektor stellt die Mitte des Klangtrichters dar.
462
DirectSound-Methoden
DirectSound3DBuffer.GetConeOutsideVolume GetConeOutsideVolume() Empfängt die Lautstärke des äußeren Klangtrichters. → DirectSound3DBuffer.SetConeOutsideVolume() object.GetConeOutsideVolume() As Long object
ein gültiges DirectSound3DBuffer-Objekt
Die Lautstärke wird als Abschwächung angegeben. Ein größerer Wert bedeutet größere Abschwächung und somit eine geringere Lautstärke. Gültige Bereiche liegen zwischen DSBVOLUME_MAX (keine Abschwächung) und DSBVOLUME_MIN (größte Abschwächung). Der Standardwert ist DS3D_DEFAULTCONEOUTSIDEVOLUME (keine Abschwächung).
DirectSound3DBuffer.GetDirectSound3DListener GetDirectSound3DListener() Gibt ein DirectSound3DListener-Objekt zurück. object.GetDirectSound3DListener() As DirectSound3DListener object
ein gültiges DirectSound3DBuffer-Objekt
DirectSound3DBuffer.GetDirectSoundBuffer GetDirectSoundBuffer() Gibt ein DirectSoundBuffer Objekt zurück. object.GetDirectSoundBuffer() As DirectSoundBuffer object
ein gültiges DirectSound3DBuffer-Objekt
DirectSound3DBuffer.GetMaxDistance GetMaxDistance() Empfängt die maximale Entfernung eines 3D-Buffer-Objekts. → DirectSound3DBuffer.GetMinDistance(), DirectSound3DBuffer.SetMaxDistance(), DirectSound3DBuffer.SetMinDistance() object.GetMaxDistance() As Single object
ein gültiges DirectSound3DBuffer-Objekt
Anhang A • Methoden
463
DirectSound3DBuffer.GetMinDistance GetMinDistance() Empfängt die minimale Entfernung eines 3D-Buffer-Objekts. → DirectSound3DBuffer.GetMaxDistance(), DirectSound3DBuffer.SetMaxDistance(), DirectSound3DBuffer.SetMinDistance() object.GetMinDistance() As Single object
ein gültiges DirectSound3DBuffer-Objekt
DirectSound3DBuffer.GetMode GetMode() Empfängt den Operationsmode des aktuellen 3D-Soundprozesses. → DirectSound3DBuffer.SetMode object.GetMode() As CONST_DS3DMODEFLAGS object
ein gültiges DirectSound3DBuffer-Objekt
Rückgabewerte vom Typ CONST_DS3DMODEFLAGS
DirectSound3DBuffer.GetPosition GetPosition() Empfängt die Position eines 3DSoundBuffers im 3D-Raum. → DirectSound3DBuffer.SetPosition() object.GetPosition(position As D3DVECTOR) object
ein gültiges DirectSound3DBuffer-Objekt
position
3D-Position (xyz) in Metern
DirectSound3DBuffer.GetVelocity GetVelocity() Empfängt die Geschwindigkeit, mit der sich ein 3D-Buffer im Raum bewegt. → DirectSound3DBuffer.SetVelocity() object.GetVelocity(velocity As D3DVECTOR) object
ein gültiges DirectSound3DBuffer-Objekt
velocity
Wert in Meter pro Sekunde
Velocity wird zum Errechnen des Dopplereffektes benötigt.
464
DirectSound-Methoden
DirectSound3DBuffer.SetAllParameters SetAllParameters() Setzt Informationen über die 3D-Charakteristik eines Soundbuffers zu einer bestimmten Zeit. → DirectSound3DBuffer.GetAllParameters() object.SetAllParameters(buffer As DS3DBUFFER, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
buffer
ein gültiges DirectSoundBuffer-Objekt
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DBuffer.SetConeAngles SetConeAngles() Setzt die Winkel des inneren und äußeren Klangtrichters. → DirectSound3DBuffer.GetConeAngles() object.SetConeAngles(inCone As Long, outCone As Long, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
inCone
Winkel des inneren Klangtrichters
outCone
Winkel des äußeren Klangtrichters
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DBuffer.SetConeOrientation SetConeOrientation() Setzt die Ausrichtung des Klangtrichters. → DirectSound3DBuffer.GetConeOrientation() object.SetConeOrientation( x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
x,y,z
Koordinaten der neuen Ausrichtung
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Anhang A • Methoden
465
DirectSound3DBuffer.SetConeOutsideVolume SetConeOutsideVolume() Setzt die Lautstärke des äußeren Klangtrichters. → DirectSound3DBuffer.GetConeOutsideVolume() object.SetConeOutsideVolume(coneOutsideVolume As Long, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
coneOutsideVolume
erlaubte Werte liegen im Bereich von DSBVOLUME_MAX (keine Abschwächung), DSBVOLUME_MIN (größte Abschwächung)
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DBuffer.SetMaxDistance SetMaxDistance() Setzt die maximale Entfernung eines 3D-Buffer Objekts. → DirectSound3DBuffer.GetMinDistance(), DirectSound3DBuffer.GetMaxDistance(), DirectSound3DBuffer.SetMinDistance() object.SetMaxDistance(maxDistance As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
maxDistance
neuer Wert der größten Entfernung
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DBuffer.SetMinDistance SetMinDistance() Setzt die minimale Entfernung eines 3D-Buffer Objekts. → DirectSound3DBuffer.GetMinDistance(), DirectSound3DBuffer.GetMaxDistance(), DirectSound3DBuffer.SetMaxDistance() object.SetMinDistance(minDistance As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
minDistance
neuer Wert der kleinsten Entfernung
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
466
DirectSound-Methoden
DirectSound3DBuffer.SetMode SetMode() Setzt den Operationsmodus des aktuellen 3D-Sound-Prozesses. → DirectSound3DBuffer.GetMode() object.SetMode(mode As CONST_DS3DMODEFLAGS, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
mode
Wert vom Typ CONST_DS3DMODEFLAGS
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DBuffer.SetPosition SetPosition() Setzt die Position eines 3D-Soundbuffers im 3D-Raum. → DirectSound3DBuffer.GetPosition() object.SetPosition(x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
x,y,z
Koordinaten der neuen Position
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DBuffer.SetVelocity SetVelocity() Empfängt die Geschwindigkeit, mit der sich ein 3D-Buffer im Raum bewegt. → DirectSound3DBuffer.GetVelocity() object.SetVelocity(x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DBuffer-Objekt
x,y,z
Koordinaten des Richtungsvektors
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Velocity wird zum Errechnen des Dopplereffektes benötigt.
A.4.3
DirectSound3DListener Programme benutzen die Methoden der DirectSound3DListener-Klasse zum Empfangen und Setzen der Position und Ausrichtung des Listeners im 3D-Raum.
Anhang A • Methoden
467
Das DirectSound3DListener-Objekt wird mit der DiertsSoundBuffer.GetDirectSound3DListener()-Methode erzeugt. Die Methoden der DirectSound3DListener-Klasse organisieren sich in folgenden Gruppen: Batch parameters
GetAllParameters SetAllParameters
Verzögerung
CommitDeferredSettings
Entfernungsfaktoren
GetDistanceFactor SetDistanceFactor
Dopplereffekt
GetDopplerFactor SetDopplerFactor
Objekte
GetDirectSoundBuffer
Ausrichtung
GetOrientation SetOrientation
Position
GetPosition SetPosition
Neigung
GetRolloffFactor SetRolloffFactor
Geschwindigkeit
GetVelocity SetVelocity
DirectSound3DListener.CommitDeferredSettings CommitDeferredSettings() Übergibt die zuvor eingestellten Werte unter Verwendung des Applyflags. object.CommitDeferredSettings() object
ein gültiges DirectSound3DListener-Objekt
DirectSound3DListener.GetAllParameters GetAllParameters() Empfängt alle Einstellungen des Listenerobjekts. → DirectSound3DListener.SetAllParameters() object.GetAllParameters(listener As DS3DLISTENER) object
ein gültiges DirectSound3DListener-Objekt
listener
ein gültiges DS3DLISTENER-Objekt
468
DirectSound-Methoden
DirectSound3DListener.GetDirectSoundBuffer GetDirectSoundBuffer() Empfängt ein DirectSoundBuffer und übergibt diesen dem Listenerobjekt. object.GetDirectSoundBuffer() As DirectSoundBuffer object
ein gültiges DirectSound3DListener-Objekt
DirectSound3DListener.GetDistanceFactor GetDistanceFactor() Empfängt den aktuellen Entfernungsfaktor. → DirectSound3DListener.SetDistanceFactor() object.GetDistanceFactor() As Single object
ein gültiges DirectSound3DListener-Objekt
DirectSound3DListener.GetDopplerFactor GetDopplerFactor() Empfängt den aktuellen Wert des Doppler-Effektes. → DirectSound3DListener.SetDopplerFactor() object.GetDopplerFactor() As Single object
ein gültiges DirectSound3DListener-Objekt
Gültige Werte liegen im Bereich DS3D_MINDOPPLERFACTOR (kein Dopplereffekt) und DS3D_MAXDOPPLERFACTOR (maximaler Dopplereffekt) die Grundeinstellung ist DS3D_DEFAULTDOPPLERFACTOR.
DirectSound3DListener.GetOrientation GetOrientation() Empfängt die Ausrichtung des Listenerobjektes. → DirectSound3DListener.SetOrientation() object.GetOrientation(orientFront As D3DVECTOR, _ orientTop As D3DVECTOR) object
ein gültiges DirectSound3DListener-Objekt
orientFront
Vektor für die horizontale Ausrichtung
orientTop
Vektor für die vertikale Ausrichtung
Anhang A • Methoden
469
DirectSound3DListener.GetPosition GetPosition() Empfängt die Position des Listenerobjektes. → DirectSound3DListener.SetPosition() object.GetPosition(position As D3DVECTOR) object
ein gültiges DirectSound3DListener-Objekt
position
Koordinate der Position im 3D-Raum
DirectSound3DListener.GetRolloffFactor GetRolloffFactor() Empfängt den Rolloff -Faktor des Listenerobjektes. → DirectSound3DListener.SetRolloffFactor() object.GetRolloffFactor() As Single object
ein gültiges DirectSound3DListener-Objekt
Gültige Werte liegen im Bereich von DS3D_MINROLLOFFFACTOR (keinRolloffEffekt) und DS3D_MAXROLLOFFFACTOR (größter Rolloff-Effekt) die Grundeinstellung beträgt DS3D_DEFAULTROLLOFFFACTOR.
DirectSound3DListener.GetVelocity GetVelocity() Empfängt den aktuellen Velocitywert des Listenerobjektes. → DirectSound3DListener.SetVelocity() object.GetVelocity() As D3DVECTOR object
ein gültiges DirectSound3DListener-Objekt
Velocity wird zum Errechnen des Dopplereffektes benötigt.
DirectSound3DListener.SetAllParameters SetAllParameters() Setzt alle Einstellungen des Listenerobjekts. → DirectSound3DListener.GetAllParameters() object.SetAllParameters(listener As DS3DLISTENER, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
listener
vom Typ DS3DLISTENER
470
DirectSound-Methoden
SetAllParameters() applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DListener.SetDistanceFactor SetDistanceFactor() Setzt den aktuellen Entfernungsfaktor. → DirectSound3DListener.GetDistanceFactor() object.SetDistanceFactor(distanceFactor As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
distanceFactor
neuer Distancefaktor
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DListener.SetDopplerFactor SetDopplerFactor() Setzt den aktuellen Wert des Dopplereffektes. → DirectSound3DListener.GetDopplerFactor() object.SetDopplerFactor(dopplerFactor As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
dopplerFactor
neuer Dopplerfaktor-Wert
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Gültige Werte liegen im Bereich DS3D_MINDOPPLERFACTOR (kein Dopplereffekt) und DS3D_MAXDOPPLERFACTOR (maximaler Dopplereffekt); die Grundeinstellung ist DS3D_DEFAULTDOPPLERFACTOR.
DirectSound3DListener.SetOrientation SetOrientation() Setzt die Ausrichtung des Listenerobjektes. → DirectSound3DListener.GetOrientation() object.SetOrientation(xFront As Single, yFront As Single, _ zFront As Single, xTop As Single, yTop As Single, zTop As _ Single, applyFlag As CONST_DS3DAPPLYFLAGS)
Anhang A • Methoden
471
SetOrientation() object
ein gültiges DirectSound3DListener-Objekt
Front x,y,z
Vektor der horizontalen Ausrichtung
Top x,y,z
Vektor der vertikalen Ausrichtung
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Der Front-Vektor zeigt in Blickrichtung des Listeners, der Top-Vektor zeigt aus dem Kopf des Listeners senkrecht nach oben. Die Grundeinstellung des Front-Vektors beträgt (xyz) 0,0,1, die des Top-Vektors 0,1,0. Der Top-Vektor muss im richtigen Verhältnis zum Front-Vektor angegeben werden. DirectSound aktualisiert erst den FrontVektor, dann den Top-Vektor.
DirectSound3DListener.SetPosition SetPosition() Setzt die Position des Listenerobjektes. → DirectSound3DListener.GetPosition() object.SetPosition(x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
x,y,z
Koordinate der neuen Position
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
DirectSound3DListener.SetRolloffFactor SetRolloffFactor() Setzt den Rolloff Faktor des Listenerobjektes. → DirectSound3DListener.GetRolloffFactor() object.SetRolloffFactor(rolloffFactor As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
rolloffFactor
neuer Rolloff-Faktor
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Gültige Werte liegen im Bereich von DS3D_MINROLLOFFFACTOR (kein RolloffEffekt) und DS3D_MAXROLLOFFFACTOR (größter Rolloff-Effekt); die Grundeinstellung beträgt DS3D_DEFAULTROLLOFFFACTOR.
472
DirectSound-Methoden
DirectSound3DListener.SetVelocity SetVelocity() Setzt den aktuellen Velocitywert des Listenerobjektes. → DirectSound3DListener.GetVelocity() object.SetVelocity(x As Single, y As Single, z As Single, _ applyFlag As CONST_DS3DAPPLYFLAGS) object
ein gültiges DirectSound3DListener-Objekt
x,y,z
Neuer Vektor, der die Geschwindigkeit beschreibt.
applyFlag
Flag vom Typ CONST_DS3DAPPLYFLAGS
Velocity wird zum Errechnen des Dopplereffektes benötigt.
A.4.4
DirectSoundBuffer Die Methoden der DirectSoundBuffer-Klasse werden zum Erstellen von DirectSoundBuffer-Objekten benötigt. Das DirectSoundBuffer-Objekt wird mit der DirectSound.CreateSoundBuffer()Methode erzeugt. Die DirectSoundBuffer-Methoden unterteilen sich in folgende Gruppen: Information
GetCaps GetFormat GetStatus SetFormat
Speichermanagement
Restore
Verschiedenes
SaveToFile
Erhalten von Objekten
GetDirectSound3Dbuffer GetDirectSound3Dlistener
Steuerung
GetCurrentPosition Play ReadBuffer SetCurrentPosition SetNotificationPositions Stop WriteBuffer
Anhang A • Methoden
473
Soundmanagement
GetFrequency GetPan GetVolume SetFrequency SetPan SetVolume
DirectSoundBuffer.GetCaps GetCaps() Empfängt die Fähigkeiten des DirectSoundBuffers. object.GetCaps(caps As DSBCAPS) object
ein gültiges DirectSoundBuffer-Objekt
caps
vom Typ DSBCAPS
DirectSoundBuffer.GetCurrentPosition GetCurrentPosition() Empfängt die aktuelle Lese- und Schreibe-Position des Cursors. → DirectSoundBuffer.SetCurrentPosition() object.GetCurrentPosition(cursors As DSCURSORS) object
ein gültiges DirectSoundBuffer-Objekt
cursors
Playcursor vom Typ DSCURSORS
DirectSoundBuffer.GetDirectSound3DBuffer GetDirectSound3DBuffer() Gibt ein DirectSound3DBuffer-Objekt zurück. object.GetDirectSound3DBuffer() As DirectSound3DBuffer object
ein gültiges DirectSoundBuffer-Objekt
DirectSoundBuffer.GetDirectSound3DListener GetDirectSound3DListener() Gibt ein DirectSound3DListener-Objekt zurück. object.GetDirectSound3DListener() As DirectSound3DListener object
ein gültiges DirectSoundBuffer-Objekt
474
DirectSound-Methoden
DirectSoundBuffer.GetFormat GetFormat() Empängt die Formatbeschreibung der Sounddaten im Soundbuffer. → DirectSoundBuffer.SetFormat() object.GetFormat(format As WAVEFORMATEX) object
ein gültiges DirectSoundBuffer-Objekt
format
vom Typ WAVEFORMATEX
DirectSoundBuffer.GetFrequency GetFrequency() Empfängt die Frequenz in Samples pro Sekunde. → DirectSoundBuffer.SetFrequency() object.GetFrequency() As Long object
ein gültiges DirectSoundBuffer-Objekt
Gültige Werte liegen im Bereich von DSBFREQUENCY_MIN und DSBFREQUENCY_MAX (100 – 100.000 Samples pro Sekunde)
DirectSoundBuffer.GetPan GetPan() Empfängt einen Panwert, der die Lautstärkebalance der Lautsprecher beschreibt. → DirectSoundBuffer.SetPan() object.GetPan() As Long object
ein gültiges DirectSoundBuffer-Objekt
Gültige Werte liegen im Bereich von DSBPAN_LEFT (-10.000) 100db Abschwächung rechts und DSBPAN_RIGHT (+10.000) 100db Abschwächung links. DSBPAN_CENTER ( 0 ) beschreibt die normale Mittelstellung.
DirectSoundBuffer.GetStatus GetStatus() Empfängt den aktuellen Zustand eines DirectSoundBuffers. object.GetStatus() As CONST_DSBSTATUSFLAGS object
ein gültiges DirectSoundBuffer-Objekt
Rückgabe
vom Typ CONST_DSBSTATUSFLAGS
Anhang A • Methoden
475
DirectSoundBuffer.GetVolume GetVolume() Empfängt die aktuelle Lautstärke eines Soundbuffers. object.GetVolume() As Long object
ein gültiges DirectSoundBuffer-Objekt
Gültige Werte liegen im Bereich von DSBVOLUME_MIN (keine Abschwächung 0db) und DSBVOLUME_MAX (größte Abschwächung 100db).
DirectSoundBuffer.Play Play() Gibt den Befehl zum Abspielen eines Soundbuffers. object.Play(flags As CONST_DSBPLAYFLAGS) object
ein gültiges DirectSoundBuffer-Objekt
flags
vom Typ CONST_DSBPLAYFLAGS
DirectSoundBuffer.ReadBuffer ReadBuffer() Liest ein Segment aus einem Soundbuffer und speichert dieses in einer Variablen vom Typ Array. object.ReadBuffer(start As Long, size As Long, buffer As Any, _ flags As CONST_DSBLOCKFLAGS) object
ein gültiges DirectSoundBuffer-Objekt
start
Offset in Bytes (Position, ab der gelesen werden wird)
size
Anzahl der Bytes, die gelesen werden.
buffer
Variable vom Typ Any, die die Sounddaten aufnimmt.
flags
vom Typ CONST_DSBLOCKFLAGS
DirectSoundBuffer.Restore Restore() Stellt einen verlorenen Speicherbereich wieder her. object.Restore() object
ein gültiges DirectSoundBuffer-Objekt
476
DirectSound-Methoden
DirectSoundBuffer.SaveToFile SaveToFile() Speichert die Einträge eines DirectSoundBuffers in eine Datei. object.SaveToFile(filename As String) object
ein gültiges DirectSoundBuffer-Objekt
filename
Filename
DirectSoundBuffer.SetCurrentPosition SetCurrentPosition() Setzt die Soundcursor auf die angegebene Position. object.SetCurrentPosition(newPosition As Long) object
ein gültiges DirectSoundBuffer-Objekt
newPosition
neue Position in Bytes vom Anfang des Buffers
DirectSoundBuffer.SetFormat SetFormat() Setzt das Format des primären Soundbuffers der Anwendung. object.SetFormat(format As WAVEFORMATEX) object
ein gültiges DirectSoundBuffer-Objekt
format
vom Typ WAVEFORMATEX
DirectSoundBuffer.SetFrequency SetFrequency() Setzt die Frequenz, in der Audiosamples abgespielt werden. object.SetFrequency(frequency As Long) object
ein gültiges DirectSoundBuffer-Objekt
frequency
neue Frequenz in Hertz (Hz)
Gültige Werte liegen im Bereich von DSBFREQUENCY_MIN und DSBFREQUENCY_MAX (100 – 100.000 Samples pro Sekunde).
Anhang A • Methoden
477
DirectSoundBuffer.SetNotificationPositions SetNotificationPositions() Setzt die Notifications-Position in einem Soundbuffer. object.SetNotificationPositions(nElements As Long, _ psa() As DSBPOSITIONNOTIFY) object
ein gültiges DirectSoundBuffer-Objekt
nElements
Nummer vom Typ DSBPOSITIONNOTIFY
psa()
Ein Array von DSBPOSITIONNOTIFY
DirectSoundBuffer.SetPan SetPan() Setzt einen Panwert, der die Lautstärkebalance der Lautsprecher beschreibt. → DirectSoundBuffer.GetPan() object.SetPan(pan As Long) object
ein gültiges DirectSoundBuffer-Objekt
pan
neuer Panoramawert
Gültige Werte liegen im Bereich von DSBPAN_LEFT (-10.000) 100db Abschwächung rechts und DSBPAN_RIGHT (+10.000) 100db Abschwächung links. DSBPAN_CENTER ( 0 ) beschreibt die normale Mittelstellung.
DirectSoundBuffer.SetVolume SetVolume() Setzt die aktuelle Lautstärke eines Soundbuffers. object.SetVolume(volume As Long) object
ein gültiges DirectSoundBuffer-Objekt
volume
neuer Lautstärkewert
Gültige Werte liegen im Bereich von DSBVOLUME_MIN (keine Abschwächung 0db) und DSBVOLUME_MAX (größte Abschwächung 100db)
DirectSoundBuffer.Stop Stop() Gibt den Befehl zum Anhalten eines Soundbuffers. object.Stop()
478
DirectSound-Methoden
Stop() object
ein gültiges DirectSoundBuffer-Objekt
DirectSoundBuffer.WriteBuffer WriteBuffer() Schreibt ein Segment in einen Soundbuffer. object.WriteBuffer(start As Long, size As Long, buffer As Any, _ flags As CONST_DSBLOCKFLAGS)
A.4.5
object
ein gültiges DirectSoundBuffer-Objekt
start
Offset in Bytes, ab wo geschrieben werden soll.
size
Anzahl der Bytes, die geschrieben werden.
buffer
Variable, die die Sounddaten enthält.
flags
vom Typ CONST_DSBLOCKFLAGS
DirectSoundCapture Die Methoden der DirectSoundCapture-Klasse werden zum Erstellen von Capturebuffern benötigt. Das DirectSoundCapture-Objekt wird mit der DirectX7.DirectSoundCaptureCreate()-Methode erzeugt. Folgende Methoden gehören zu der DirectSoundCapture-Klasse: Erzeugen
CreateCaptureBuffer
Eigenschaften
GetCaps
DirectSoundCapture.CreateCaptureBuffer CreateCaptureBuffer() Erstellt einen Capturebuffer, der die Sounddaten aufnimmt. object.CreateCaptureBuffer(bufferDesc As DSCBUFFERDESC) _ As DirectSoundCaptureBuffer object
ein gültiges DirectSoundCapture-Objekt
bufferDesc
Bufferbeschreibung vom Typ DSCBUFFERDESC
Anhang A • Methoden
479
DirectSoundCapture.GetCaps GetCaps() Beschreibt die Fähigkeiten des Aufnahmegeräts. object.GetCaps(caps As DSCCAPS)
A.4.6
object
ein gültiges DirectSoundCapture-Objekt
caps
vom Typ DSCCAPS
DirectSoundCaptureBuffer Die Methoden der DirectSoundCaptureBuffer-Klasse werden für die Manipulation der CaptureBuffer eingesetzt. Das DirectSoundCaptureBuffer-Objekt wird mit der DirectSoundCaputer.CreateCaptureBuffer()-Methode erzeugt. Folgende Methoden gehören zu der DierctSoundCaptureBuffer-Klasse: Informationen
GetCaps GetCurrentPosition GetFormat GetStatus
Speichermanagement
ReadBuffer WriteBuffer
Ereignissteuerung
SetNotificationPositions
Aufnahmemanagement
Start Stop
DirectSoundCaptureBuffer.GetCaps GetCaps() Empfängt die Eigenschaften eines Capturebuffers. object.GetCaps(caps As DSCBCAPS) object
ein gültiges DirectSoundCaptureBuffer-Objekt
caps
vom Typ DSCBCAPS
DirectSoundCaptureBuffer.GetCurrentPosition GetCurrentPosition() Empfängt die aktuelle Aufnahme und Abspielposition im Buffer.
480
DirectSound-Methoden
GetCurrentPosition() object.GetCurrentPosition(cursors As DSCURSORS) object
ein gültiges DirectSoundCaptureBuffer-Objekt
cursors
vom Typ DSCURSORS
DirectSoundCaptureBuffer.GetFormat GetFormat() Gibt das aktuelle Waveformat eines Capturebuffers zurück. object.GetFormat(waveformat As WAVEFORMATEX) object
ein gültiges DirectSoundCaptureBuffer-Objekt
waveformat
vom Typ WAVEFORMATEX
DirectSoundCaptureBuffer.GetStatus GetStatus() Gibt den aktuellen Zustand eines Capturebuffers zurück. object.GetStatus() As CONST_DSCBSTATUSFLAGS object
ein gültiges DirectSoundCaptureBuffer-Objekt
DirectSoundCaptureBuffer.ReadBuffer ReadBuffer() Liest ein Segment aus dem Capturebuffer und speichert dieses in einer Variablen vom Typ Array. → DirectSoundCaptureBuffer.WriteBuffer() object.ReadBuffer(start As Long, size As Long, buffer As Any, _ flags As CONST_DSCBLOCKFLAGS) object
ein gültiges DirectSoundCaptureBuffer-Objekt
start
Offset in Bytes (Position, ab der gelesen wird).
size
Anzahl der Bytes, die gelesen werden.
buffer
Variable vom Typ Any, die die Sounddaten aufnimmt.
flags
vom Typ CONST_DSCBLOCKFLAGS
Anhang A • Methoden
481
DirectSoundCaptureBuffer.SetNotificationPositions SetNotificationPositions() Setzt die Notifikations-Position in einem SoundCaptureBuffer. object.SetNotificationPositions(nElements As Long, _ psa() As DSBPOSITIONNOTIFY) object
ein gültiges DirectSoundCaptureBuffer-Objekt
nElements
Nummer vom Typ DSBPOSITIONNOTIFY
psa()
ein Array vom Typ DSBPOSITIONNOTIFY
DirectSoundCaptureBuffer.Start Start() Setzt den CaptureBuffer in den Aufnahmezustand und beginnt mit dem Schreiben der ankommenden Sounddaten in den Capturebuffer. Befindet sich der Capturebuffer im Aufnahmezustand, hat diese Methode keine Auswirkung. object.Start(flags As CONST_DSCBSTARTFLAGS) object
ein gültiges DirectSoundCaptureBuffer-Objekt
flags
vom Typ CONST_DSCBSTARTFLAGS
DirectSoundCaptureBuffer.Stop Stop() Setzt den Capturebuffer in den Ruhezustand und hält die Aufzeichnung der Sounddaten an. Befindet sich der Capturebuffer im Ruhezustand, hat diese Methode keine Auswirkung. object.Stop() object
ein gültiges DirectSoundCaptureBuffer Objekt
DirectSoundCaptureBuffer.WriteBuffer WriteBuffer() Schreibt von die Sounddaten aus einem Array in ein Segment des Capturebuffers. → DirectSoundCaptureBuffer.ReadBuffer() object.WriteBuffer(start As Long, size As Long, buffer As Any, _ flags As CONST_DSCBLOCKFLAGS) object
ein gültiges DirectSoundCaptureBuffer Objekt
start
Offset in Bytes (Position, ab der geschrieben wird)
482
DirectSound-Methoden
WriteBuffer()
A.4.7
size
Anzahl der Bytes, die geschrieben werden.
buffer
Variable vom Typ Any, die die Sounddaten enthällt.
flags
vom Typ CONST_DSCBLOCKFLAGS
DirectSoundEnum Die Methoden der DirectSoundEnum-Klasse beinhalten eine Auflistung der im System installierten DirectSound-Treiber. Folgende Methoden gehören zu der DirectSoundEnum-Klasse: DirectSoundEnum
GetCount GetDescription GetGuid GetName
DirectSoundEnum.GetCount GetCount() Gibt die Anzahl der Einträge im Enumeration-Objekt zurück. object.GetCount() As Long object
ein gültiges DirectSoundEnum-Objekt
DirectSoundEnum.GetDescription GetDescription() Gibt die Treiberbeschreibung des ausgewählten DirectSound-Gerätes zurück. object.GetDescription(index As Long) As String object
ein gültiges DirectSoundEnum-Objekt
index
Index des DirectSound-Gerätes in der Aufzählung.
DirectSoundEnum.GetGuid GetGuid() Gibt die Identifikationsnummer des DirectSound-Gerätes zurück. object.GetGuid(index As Long) As String object
ein gültiges DirectSoundEnum-Objekt
Anhang A • Methoden
483
GetGuid() index
Index des DirectSound-Gerätes in der Aufzählung.
DirectSoundEnum.GetName GetName() Gibt die Bezeichnung des DirectSound Gerätes zurück. object.GetName(index As Long) As String object
ein gültiges DirectSoundEnum-Objekt
index
Index des DirectSound-Gerätes in der Aufzählung.
A.5
DirectInput
A.5.1
DirectInput Die DirectInput-Klasse repräsentiert das DirectInput-System. Die Klasse wird benutzt, um verfügbare Geräte aufzulisten, Geräte zu erzeugen oder den Status der Geräte zu erfragen. Das DirectInput-Objekt wird mit der DirectX7.DirectInputCreate()-Methode erzeugt. Folgenden Methoden gehöhren zu der DirectInput-Klasse: Geräteorganisation
CreateDevice GetDeviceStatus GetDIEnumDevices
Verschiedenes
RunControlPanel
DirectInput.CreateDevice CreateDevice() Erzeugt ein DirectInputDevice. object.CreateDevice(guid As String) As DirectInputDevice object
ein gültiges DirectInput-Objekt
guid
Guid für das Gerät
484
DirectInput
DirectInput.GetDeviceStatus GetDeviceStatus() Prüft ob ein Gerät mit dem System verbunden ist. object.GetDeviceStatus(guid As String) As Boolean object
ein gültiges DirectInput-Objekt
guid
Guid für das Gerät.
DirectInput.GetDIEnumDevices GetDIEnumDevices() Erzeugt eine Liste mit Inputgeräten. Dazu wird ein DirectInputEnumDevices-Objekt mit den Informationen gefüllt. object.GetDIEnumDevices( deviceType As CONST_DIDEVICETYPE, _ flags As CONST_DIENUMDEVICESFLAGS) _ As DirectInputEnumDevices object
ein gültiges DirectInput-Objekt
deviceType
Beschreibt, für welche Art von Geräten die Liste erzeugt werden soll. DIDEVTYPE_MOUSE DIDEVTYPE_KEYBOARD DIDEVTYPE_JOYSTICK DIDEVTYPE_DEVICE
flags
DIEDFL_ALLDEVICES DIEDFL_ATTACHEDONLY
DirectInput.RunControlPanel RunControlPanel() Startet das Windows-Kontrollelement. object.RunControlPanel(hwndOwner As Long)
A.5.2
object
ein gültiges DirectInput Objekt
hwndOwner
Handle zu dem Windows-Fenster, auf dem das Windows-Kontrollelement angezeigt werden soll. Diese Parameter kann 0 sein.
DirectInputDevice Die DirectInputDevice-Klasse handelt den Zugriff auf ein Inputgerät. Sie managt die Deviceeigenschaften und initialisiert die Geräte.
Anhang A • Methoden
485
Das DirectInputDevice-Objekt wird mit der DirectInputCreatDevice()-Methode erzeugt. Folgende Methoden gehören zu der DirectInputDevice-Klasse: Zugriff
Acquire SetCooperativeLevel Unacquire
Objekte
GetDeviceObjectsEnum GetObjectInfo
Eigenschaften
GetCapabilities GetDeviceInfo GetProperty SetCommonDataFormat SetDataFormat SetProperty
Daten empfangen
GetDeviceData GetDeviceState GetDeviceStateJoystick GetDeviceStateJoystick2 GetDeviceStateKeyboard GetDeviceStateMouse Poll SetEventNotification
Force-Feedback
CreateCustomEffect CreateEffect GetEffectsEnum GetForceFeedbackState SendForceFeedbackCommand
Verschiedenes
RunControlPanel SendDeviceData
DirectInputDevice.Acquire Acquire() Stellt die Verbindung zum Inputgerät her. → DirectInputDevice.Unacquire() object.Acquire() object
ein gültiges DirectInputDevice-Objekt
486
DirectInput
DirectInputDevice.CreateCustomEffect CreateCustomEffect() Erzeugt einen Force-Feedback-Effekt. object.CreateCustomEffect(effectinfo As DIEFFECT, channels As Long, _ samplePeriod As Long, nSamples As Long, sampledata() As Long) _ As DirectInputEffect object
ein gültiges DirectInputDevice-Objekt
effectinfo
Ein DIEDDECT Typen-Array, welches die Effektparameter beschreibt.
channels
Anzahl der Kanäle (Achsen), die von dem Effekt betroffen sind.
samplePeriod
Effektdauer in Millisekunden
nSamples
Anzahl der Elemente in dem sampledata-Parameter
sampledata
Array vom Typ Long
DirectInputDevice.CreateEffect CreateEffect() Erzeugt einen Force-Feedback-Effekt. → DirectInputEffect.Download(), DirectInputEffect.Start() object.CreateEffect(effectGuid As String, _ effectinfo As DIEFFECT) As DirectInputEffect object
ein gültiges DirectInputDevice-Objekt
effectGuid
GUID_ConstantForce GUID_RampForce GUID_Square GUID_Sine GUID_Triangle GUID_SawtoothUp GUID_SawtoothDown GUID_Spring GUID_Damper GUID_Inertia GUID_Friction
effectinfo
Ein DIEDDECT Typen-Array, welches die Effektparameter beschreibt.
Anhang A • Methoden
487
DirectInputDevice.GetCapabilities GetCapabilities() Ermittelt die Fähigkeiten eines DirectInputDevice-Objekts. object.GetCapabilities(caps As DIDEVCAPS) object
ein gültiges DirectInputDevice-Objekt
caps
Ein DIDEVCAPS-Typen-Array, welches mit den Fähigkeiten des Inputgerätes gefüllt wird
DirectInputDevice.GetDeviceData GetDeviceData() Ermittelt die gespeicherten Daten eines Inputgerätes. object.GetDeviceData(deviceObjectDataArray() As DIDEVICEOBJECTDATA,_ flags As CONST_DIDGDDFLAGS) As Long object
ein gültiges DirectInputDevice-Objekt
deviceObject DataArray
Ein Array von DIDEVICEOBJECTDATA-Typen-Arrays, welches die Daten empfängt.
flags
DIGDD_DEFAULT DIGDD_PEEK
DirectInputDevice.GetDeviceInfo GetDeviceInfo() Ermittelt Informationen über die Identität des Inputgeräts. object.GetDeviceInfo() As DirectInputDeviceInstance object
ein gültiges DirectInputDevice-Objekt
DirectInputDevice.GetDeviceObjectsEnum GetDeviceObjectsEnum() Ermittelt die Objekte eines Gerätes. Typische Objekte sind Achsen oder Knöpfe. object.GetDeviceObjectsEnum( flags As CONST_DIDFTFLAGS) _ As DirectInputEnumDeviceObjects object
ein gültiges DirectInputDevice-Objekt
flags
Eine Konstante aus der CONST_DIDFTFLAGS-Liste, welche die zu ermittelnden Objekte einschränkt.
488
DirectInput
DirectInputDevice.GetDeviceState GetDeviceState() Ermittelt den augenblicklichen Zustand eines Gerätes. → DirectInputDevice.GetDeviceStateJoystick(), DirectInputDevice.GetDeviceStateJoystick2(), DirectInputDevice.GetDeviceStateKeyboard(), DirectInputDevice.GetDeviceStateMouse(), DirectInputDevice.SetDataFormat() object.GetDeviceState(cb As Long, state As Any) object
ein gültiges DirectInputDevice-Objekt
cb
Größe des Arrays
state
Erstes Element von einem Array, welches die Daten empfängt.
DirectInputDevice.GetDeviceStateJoystick GetDeviceStateJoystick() Ermittelt Informationen über die Objekte von einem Joystick. object.GetDeviceStateJoystick(state As DIJOYSTATE) object
ein gültiges DirectInputDevice-Objekt
state
buttons (0 To 31) POV (0 To 3) rx ry rz slider (0 To 1) x y z
DirectInputDevice.GetDeviceStateJoystick2 GetDeviceStateJoystick2() Ermittelt Informationen über die Objekte von einem Joystick mit erweiterten Funktionen. → DirectInputDevice.Poll() object.GetDeviceStateJoystick2(state As DIJOYSTATE2) object
ein gültiges DirectInputDevice-Objekt
Anhang A • Methoden
489
GetDeviceStateJoystick2() state
buttons (0 To 31) frx fry frz fslider (0 To 1) fx fy fz POV (0 To 3) rx ry rz slider (0 To 1) vrx vry vrz vslider (0 To 1) vx vy vz x y z
DirectInputDevice.GetDeviceStateKeyboard GetDeviceStateKeyboard() Ermittelt Informationen über die Objekte von einer Tastatur. object.GetDeviceStateKeyboard(state As DIKEYBOARDSTATE) object
ein gültiges DirectInputDevice-Objekt
state
key(0 to 255)
Dim keyState as DIKEYBOARDSTATE Call diDevice.GetDeviceStateKeyboard(keyState) If (keyState.key(DIK_ESCAPE) And &H80) Then ' Escape-Taste ist gedrückt End If
490
DirectInput
DirectInputDevice.GetDeviceStateMouse GetDeviceStateMouse() Ermittelt Informationen über die Objekte von einer Maus. → DirectInputDevice.Poll() object.GetDeviceStateMouse(state As DIMOUSESTATE) object
ein gültiges DirectInputDevice-Objekt
state
buttons (0 To 3) x y z
DirectInputDevice.GetEffectsEnum GetEffectsEnum() Erstellt eine Liste mit Force-Feedback-Effekten, welche von dem Gerät unterstützt werden. object.GetEffectsEnum( _ effType As CONST_DIEFTFLAGS) As DirectInputEnumEffects object
ein gültiges DirectInputDevice-Objekt
effType
Begrenzt die Liste. DIEFT_ALL DIEFT_CONDITION DIEFT_CONSTANTFORCE DIEFT_CUSTOMFORCE DIEFT_HARDWARE DIEFT_PERIODIC DIEFT_RAMPFORCE
DirectInputDevice.GetForceFeedbackState GetForceFeedbackState() Ermittelt den Zustand eines Force-Feedback-Gerätesystems. object.GetForceFeedbackState() As CONST_DIGFFSFLAGS object
ein gültiges DirectInputDevice-Objekt
Anhang A • Methoden
491
DirectInputDevice.GetObjectInfo GetObjectInfo() Ermittelt Informationen über ein Geräteobjekt wie Knöpfe oder Achsen. object.GetObjectInfo( Obj As Long, how As CONST_DIPHFLAGS) _ As DirectInputDeviceObjectInstance object
ein gültiges DirectInputDevice-Objekt
Obj
Kennung für das Objekt
how
DIPH_DEVICE DIPH_BYID DIPH_BYOFFSET
DirectInputDevice.GetProperty GetProperty() Ermittelt Informationen über das Inputgerät. → DirectInputDevice.SetProperty() object.GetProperty(
guid As String,
propertyInfo As Any)
object
ein gültiges DirectInputDevice-Objekt
guid
DIPROP_AUTOCENTER DIPROP_AXISMODE DIPROP_BUFFERSIZE DIPROP_DEADZONE DIPROP_FFGAIN DIPROP_FFLOAD DIPROP_GRANULARITY DIPROP_RANGE DIPROP_SATURATION
property Info
Ein DIPROPLONG-Typen-Array oder ein DIPROPRANGE-TypenArray für die lObj-, lHow- und lSize-Mitglieder.
DirectInputDevice.Poll Poll() Macht Daten von einem Poll-Objekt eines Gerätes verfügbar. object.Poll() object
ein gültiges DirectInputDevice-Objekt
492
DirectInput
DirectInputDevice.RunControlPanel RunControlPanel() Öffnet die Control-Panel Eigenschaftenseite für das Gerät. object.RunControlPanel(hwnd As Long) object
ein gültiges DirectInputDevice-Objekt
hwnd
Handle zu dem Fenster, auf dem das Control-Panal dargestellt werden soll. Dieser Parameter kann 0 sein.
DirectInputDevice.SendDeviceData SendDeviceData() Sendet Daten an ein Gerät, welches dies erlaubt. object.SendDeviceData(count As Long, data() As DIDEVICEOBJECTDATA, _ flags As CONST_DESDDFLAGS) As Long object
ein gültiges DirectInputDevice-Objekt
count
Anzahl der Elemente in dem data()-Array
data()
Daten
flags
0 oder DISDD_CONTINUE
Wenn die Daten gesendet werden, muss das Gerät im Acquired-Zustand sein.
DirectInputDevice.SendForceFeedbackCommand SendForceFeedbackCommand() Sendet einen Befehl an ein Force-Feedback-Gerätesystem. object.SendForceFeedbackCommand(flags As Long) object
ein gültiges DirectInputDevice-Objekt
flags
DISFFC_CONTINUE DISFFC_PAUSE DISFFC_RESET DISFFC_SETACTUATORSOFF DISFFC_SETACTUATORSON DISFFC_STOPALL
DirectInputDevice.SetCommonDataFormat SendCommonDataFormat() Setzt das Standardinputformat für ein Gerät.
Anhang A • Methoden
493
SendCommonDataFormat() object.SetCommonDataFormat( _ format As CONST_DICOMMONDATAFORMATS) object
ein gültiges DirectInputDevice-Objekt
format
DIFORMAT_JOYSTICK DIFORMAT_JOYSTICK2 DIFORMAT_KEYBOARD DIFORMAT_MOUSE
DirectInputDevice.SetCooperativeLevel SendCooperativeLevel() Setzt den Cooperative Level des Gerätes. object.SetCooperativeLevel(hwnd As Long, _ flags As CONST_DISCLFLAGS) object
ein gültiges DirectInputDevice-Objekt
hwnd
Ein Windowshandle, welches mit dem Gerät verbunden wird.
flags
DISCL_BACKGROUND DISCL_EXCLUSIVE DISCL_FOREGROUND DISCL_NONEXCLUSIVE
DirectInputDevice.SetDataFormat SetDataFormat() Setzt ein Datenformat für ein Gerät, welches von den Standardformaten abweicht. → DirectInputDevice.SetCommonDataFormat() object.SetDataFormat(format As DIDATAFORMAT, _ formatArray() As DIOBJECTDATAFORMAT)) object
ein gültiges DirectInputDevice-Objekt
format
Ein DIDATAFORMAT Typen-Array, welches das Datenformat beschreibt.
formatArray()
Ein Array von DIOBJECTDATAFORMAT-Typen-Arrays, welches die Formate der Geräteobjekte beschreiben.
494
DirectInput
DirectInputDevice.SetEventNotification SetEventNotification() Setzt den Benachrichtigungszustand. Das gesetzte Event wird immer dann aufgerufen, wenn sich der Gerätezustand ändert. object.SetEventNotification(hEvent As Long) object
ein gültiges DirectInputDevice-Objekt
hEvent
Handle für ein Event
DirectInputDevice.SetProperty SetProperty() Setzt die Geräteeigenschaften, die das Verhalten der Gerätes beschreiben. object.SetProperty( guid As String, propertyInfo As Any) object
ein gültiges DirectInputDevice-Objekt
guid
DIPROP_AXISMODE DIPROP_BUFFERSIZE DIPROP_CALIBRATIONMODE DIPROP_DEADZONE DIPROP_RANGE DIPROP_SATURATION
properyInfo
Ein DIPROPLONG Typen-Array oder ein DIPROPRANGE-TypenArray für die lObj-, lHow- und lSize-Mitglieder.
DirectInputDevice.Unacquire Unacquire() Löst die Verbindung zu einem Gerät. → DirectInputDevice.Acquire() object.Unacquire() object
A.5.3
ein gültiges DirectInputDevice-Objekt
DirectInputDeviceInstance Die DirectInputDeviceInstance-Klasse beinhaltet Informationen über die Geräteinstanz. Das DirectInputDeviceInstance-Objekt wird mit den DirectInputDevice.GetDeviceInfo()- oder DirectInputEnumDevices.GetItem()-Methoden erzeugt.
Anhang A • Methoden
495
Folgende Methoden gehören zu der DirectInputDeviceInstance-Klasse: Information
GetDevType GetGuidFFDriver GetGuidInstance GetGuidProduct GetInstanceName GetProductName GetUsage GetUsagePage
DirectInputDeviceInstance.GetDevType GetDevType() Ermittelt den Gerätetyp. object.GetDevType() As Long object
ein gültiges DirectInputDeviceInstance-Objekt
DirectInputDeviceInstance.GetGuidFFDriver GetGuidFFDriver() Ermittelt die einmalige Kennung des Force-Feedback Treibers. object.GetGuidFFDriver() As String object
ein gültiges DirectInputDeviceInstance-Objekt
DirectInputDeviceInstance.GetGuidInstance GetGuidInstance() Ermittelt die einmalige Kennung der Geräteinstanz. object.GetGuidInstance() As String object
ein gültiges DirectInputDeviceInstance-Objekt
DirectInputDeviceInstance.GetGuidProduct GetGuidProduct() Ermittelt die Herstellerkennung für ein Gerät. object.GetGuidProduct() As String object
ein gültiges DirectInputDeviceInstance-Objekt
496
DirectInput
DirectInputDeviceInstance.GetInstanceName GetInstanceName() Ermittelt den Instanznamen eines Gerätes. object.GetInstanceName() As String object
ein gültiges DirectInputDeviceInstance-Objekt
DirectInputDeviceInstance.GetProductName GetProductName() Ermittelt den Produktnamen eines Gerätes. object.GetProductName() As String object
ein gültiges DirectInputDeviceInstance-Objekt
DirectInputDeviceInstance.GetUsage GetUsage() Ermittelt den Verwendungscode eines »Human Interface Device«. object.GetUsage() As Integer object
ein gültiges DirectInputDeviceInstance-Objekt
DirectInputDeviceInstance.GetUsagePage GetUsagePage() Ermittelt die Verwendungsseite eines »Human Interface Device«. object.GetUsagePage() As Integer object
A.5.4
ein gültiges DirectInputDeviceInstance-Objekt
DirectInputDeviceObjectInstance Die DirectInputDeviceObjectInstance-Klasse repräsentiert die DirectInput-Geräte. Das DirectInputDeviceObjectInstance-Objekt wird durch die DirectInputDevice. GetObjectInfo()- oder DirectInputEnumDeviceObjects.GetItem()-Methoden erzeugt.
Anhang A • Methoden
497
Folgende Methoden gehören zu der DirectInputDeviceObjectInstance-Klasse: Information
GetCollectionNumber GetDesignatorIndex GetDimension GetExponent GetFlags GetGuidType GetName GetOfs GetType GetUsage GetUsagePage
DirectInputDeviceObjectInstance.GetCollectionNumber GetCollectionNumber() Ermittelt die Anzahl der Human-Interface-Devices- (HID-) Verweise. object.GetCollectionNumber() As Integer object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetDesignatorIndex GetDesignatorIndex() Ermittelt die Kennzeichnung eines Objektes auf einem HID-Device. object.GetDesignatorIndex() As Integer object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetDimension GetDimension() Ermittelt den Code für die Einheitendimension eines Objektes in der es berichtet wird. → DirectInputDeviceObjectInstance.GetExponent() object.GetDimension() As Long object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetExponent GetExponent() Ermittelt den Exponenten.
498
DirectInput
GetExponent() object.GetExponent() As Integer object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetFlags GetFlags() Ermittelt die Kennzeichnungen (Flags) eines Gerätes. object.GetFlags() As CONST_DIDEVICEOBJINSTANCEFLAGS object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetGuidType GetGuidType() Ermittet die Guid eines Objekttyps. object.GetGuidType() As String object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetName GetName() Ermittelt den Rufnamen eines Geräteobjektes. object.GetName() As String object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetOfs GetOfs() Ermittelt den Offset eines Gerätes. object.GetOfs() As Long object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetType GetType() Ermittelt den Typ eines Geräteobjekts. object.GetType() As Long
Anhang A • Methoden
499
GetType() object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetUsage GetUsage() Ermittelt den HID Verwendungscode für ein Geräteobjekt. object.GetUsage() As Integer object
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputDeviceObjectInstance.GetUsagePage GetUsagePage() Ermittelt die HID Verwendungsseite für ein Geräteobjekt. object.GetUsagePage() As Integer object
A.5.5
ein gültiges DirectInputDeviceObjectInstance-Objekt
DirectInputEffect Die DirectInputEffect-Klasse repräsentiert die Force-Feedback-Effekte, welche durch die Anwendung erstellt werden. Das DirectInputEffect-Objekt wird mit der DirectInputDevice.CreateEffect()Methode erzeugt. Folgende Methoden gehören zu der DirectInputEffect-Klasse: Information
GetEffectGuid GetEffectStatus GetParameters
Manipulation
Download SetParameters Start Stop Unload
DirectInputEffect.Download Download() Platziert einen Effekt auf einem Gerät.
500
DirectInput
Download() object.Download() object
ein gültiges DirectInputEffect-Objekt
DirectInputEffect.GetEffectGuid GetEffectGuid() Ermittelt die Guid von einem Effekt. Der Effekt wird von dem DirectInputEffect Objekt repräsentiert. object.GetEffectGuid() As String object
ein gültiges DirectInputEffect-Objekt
DirectInputEffect.GetEffectStatus GetEffectStatus() Ermittelt den Status von einem Effekt. object.GetEffectStatus() As Long object
ein gültiges DirectInputEffect-Objekt
DirectInputEffect.GetParameters GetParameters() Ermittelt die Parameter von einem Effekt. object.GetParameters(effectinfo As DIEFFECT) object
ein gültiges DirectInputEffect-Objekt
effectinfo
Ein DIEFFECT-Typen-Array, welches die Informationen aufnimmt.
DirectInputEffect.SetParameters SetParameters() Setzt die Effektparameter für einen Effekt. object.SetParameters(effectinfo As DIEFFECT, flags As CONST_DIEPFLAGS) object
ein gültiges DirectInputEffect-Objekt
effectinfo
Ein DIEFFECT-Typen-Array, welches die Parameter für den Effekt enthält.
Anhang A • Methoden
501
SetParameters() flags
eine Konstante aus der CONST_DIEPFLAGS-Liste
DirectInputEffect.Start Start() Startet einen Effekt. Ist der Effekt bereits gestartet, so wird der Effekt erneut gestartet. object.Start(iterations As Long, flags As Long) object
ein gültiges DirectInputEffect-Objekt
iterations
Zeit, die der Effekt dauern soll.
flags
DIES_SOLO DIES_NODOWNLOAD
DirectInputEffect.Stop Stop() Hält einen Effekt an. object.Stop() object
ein gültiges DirectInputEffect-Objekt
DirectInputEffect.Unload Unload() Entfernt einen Effekt von einem Gerät. object.Unload() object
A.5.6
ein gültiges DirectInputEffect-Objekt
DirectInputEnumDeviceObjects Die DirectinputEnumDeviceObjects-Klasse ermittelt die installierten Geräteobjekte. Das DirectInputEnumDeviceObjects-Objekt wird mit der DirectInputDevice.GetDeviceObjectsEnum()-Methode erzeugt. Folgende Methoden gehören zu der DirectInputEnumDeviceObjects-Klasse: Information
GetCount GetItem
502
DirectInput
DirectInputEnumDeviceObjects.GetCount GetCount() Ermittelt die Anzahl von Elementen in dem DirectInputEnumDeviceObjects-Objekt. object.GetCount() As Long object
ein gültiges DirectInputEnumDeviceObjects-Objekt
DirectInputEnumDeviceObjects.GetItem GetItem() Ermittelt die Objektbeschreibung von einem Element aus dem DirectInputEnumDevice Objects-Objekt. object.GetItem(index As Long) As DirectInputDeviceObjectInstance
A.5.7
object
ein gültiges DirectInputEnumDeviceObjects-Objekt
index
Element
DirectInputEnumDevices Die DirectInputEnumDevices-Klasse beinhaltet Informationen über die installierten Inputgeräte. Das DirectInputEnumDevices-Objekt wird mit der DirectInput.GetDirectInput EnumDevices()-Methode erzeugt. Folgende Methoden gehören zu der DirectInputEnumDevices-Klasse: Information
GetCount GetItem
DirectInputEnumDevices.GetCount GetCount() Ermittelt die Anzahl der Elemente in dem DirectInputEnumDevices-Objekt. object.GetCount() As Long object
ein gültiges DirectInputEnumDevices-Objekt
DirectInputEnumDevices.GetItem GetItem() Ermittelt Informationen über ein Element aus dem DirectInputEnumDevices-Objekt.
Anhang A • Methoden
503
GetItem() object.GetItem(index As Long) As DirectInputDeviceInstance
A.5.8
object
ein gültiges DirectInputEnumDevices-Objekt
index
Element
DirectInputEnumEffects Die DirectInputEnumEffects-Klasse repräsentiert die Force-Feedback-Effekte eines Gerätes. Sie liefert Informationen über die einzelnen Effekte. Das DirectInputEnumEffects-Objekt wird mit der DirectInputDevices.GetEffects Enum()-Methode erzeugt. Folgende Methoden gehören zu der DirectInputEnumEffects-Klasse: Information
GetCount GetDynamicParams GetEffectGuid GetName GetStaticParams GetType
DirectInputEnumEffects.GetCount GetCount() Ermittelt die Anzahl der Elemente in dem DirectInputEnumEffects-Objekt. object.GetCount() As Long object
ein gültiges DirectInputEnumEffects-Objekt
DirectInputEnumEffects.GetDynamicParams GetDynamicParams() Ermittelt die Effekte, deren Parameter geändert werden können, ohne den Effekt zuvor anzuhalten. → DirectInputEffect.SetParameters() object.GetDynamicParams(i As Long) As CONST_DIEPFLAGS object
ein gültiges DirectInputEnumEffects-Objekt
i
Effekt
504
DirectInput
DirectInputEnumEffects.GetEffectGuid GetEffectGuid() Ermittelt die Guid eines Effekts. object.GetEffectGuid(i As Long) As String object
ein gültiges DirectInputEnumEffects-Objekt
i
Effekt
DirectInputEnumEffects.GetName GetName() Ermittelt den Namen eines Effekts. object.GetName(i As Long) As String object
ein gültiges DirectInputEnumEffects-Objekt
i
Effekt
DirectInputEnumEffects.GetStaticParams GetStaticParams() Ermittelt die Parameter, welche ein Gerät für einen Effekt unterstützt. object.GetStaticParams(i As Long) As CONST_DIEPFLAGS object
ein gültiges DirectInputEnumEffects-Objekt
i
Effekt
DirectInputEnumEffects.GetType GetType() Ermittelt den Typ und die Fähigkeiten eines Effekts. object.GetType(i As Long) As CONST_DIEFTFLAGS object
ein gültiges DirectInputEnumEffects-Objekt
i
Effekt
Anhang A • Methoden
A.6
DirectPlay-Methoden
A.6.1
DirectPlay4-Methoden
505
Anwendungen nutzen die Methoden der DirectPlay4-Klasse, um DirectPlay4Objekte zu erzeugen, Informationslisten zu erstellen, Verbindungen einzurichten oder um Sessions, Player und Gruppen zu organisieren. Ein einzelnes DirectPlay4-Objekt wird mit der DirectX7.DirectPlayCreate()Methode erzeugt. Die DirectPlay4-Klasse ist in folgenden Gruppen organisiert: Verbindung
GetDPEnumConnections InitializeConnection SetGroupConnectionSettings
Sessions
Close CreateSessionData GetDPEnumSessions GetCaps GetSessionDesc Open SecureOpen SetSessionDesc StartSession
Spieler
CreatePlayer DestroyPlayer GetDPEnumPlayers GetPlayerAccountId GetPlayerAddress GetPlayerCaps GetPlayerData GetPlayerFlags GetPlayerFormalName GetPlayerFriendlyName SetPlayerData SetPlayerName
Nachrichten
CancelMessage CancelPriority CreateMessage GetMessageCount GetMessageQueue Receive Send SendChatMessage SendEx
506
DirectPlay-Methoden
Gruppen
AddGroupToGroup AddPlayerToGroup CreateGroup CreateGroupInGroup DeleteGroupFromGroup
GetDPEnumConnections GetDPEnumConnections() Erzeugt eine Liste mit allen registrierten Service-Providern sowie Lobby-Providern. object.GetDPEnumConnections(guid As String, flags As CONST_DPENUMCONNECTIONFLAGS) As DirectPlayEnumConnections object
ein gültiges DirectPlay4-Objekt
guid
Guid für die Anwendung
flags
DPCONNECTION_DIRECTPLAY Auflistung für DirectPlay-Service-Provider. DPCONNECTION_DIRECTPLAYLOBBY Auflistung für DirectPlay-Lobby-Provider.
InitializeConnection InitializeConnection() Initialisiert eine DirectPlay-Verbindung. object. InitializeConnection (addr As DirectPlayAdress) Object
Ein gültiges DirectPlay4-Objekt.
Addr
Ein DirectPlayAddress-Objekt. Das DirectPlayAddress-Objekt wird mit der DirectPlay4.GetDPEnum Connections()-Methode abgefragt.
SetGroupConnectionSettings SetGroupConnectionSettings() Setzt die Verbindungsparameter für eine Session, welche von einer Gruppe gestartet werden soll. Diese Methode kann nur in einer Lobbysession eingesetzt werden. → DirectPlayLobby3.RunApplication() object.SetGroupConnectionSettings(id As Long, _ connection As DirectPlayLobbyConnection) object
ein gültiges DirectPlay4-Objekt
id
ID der Gruppe
Anhang A • Methoden
507
SetGroupConnectionSettings() connection
ein DirectPlayLobbyConnection-Objekt
Close Close() Schließt eine zuvor geöffnete Session. → DirectPlay4.DestroyPlayer(), DirectPlay4.Open() object.Close() object
ein gültiges DirectPlay4-Objekt
CreateSessionData CreateSessionData() Erzeugt ein DirectPlaySessionData-Objekt. object.CreateSessionData() As DirectPlaySessionData object
ein gültiges DirectPlay4-Objekt
GetDPEnumSessions GetDPEnumSessions() Erzeugt eine Liste mit allen aktiven Sessions. Die Auswahl der Sessions wird durch den flags-Parameter eingegrenzt. object.GetDPEnumSessions( sessionDesc As DirectPlaySessionData, _ timeOut As Long, flags As CONST_DPENUMSESSIONFLAGS) _ As DirectPlayEnumSessions Object
ein gültiges DirectPlay4-Objekt
Session Desc
Ein DirectPlaySessionData-Objekt, welches die Liste der Sessions aufnimmt.
TimeOut
Wartezeit in Millisekunden. Der Parameter kann 0 sein, dann wird die voreingestellte Wartezeit des Service-Providers genommen. Die Wartezeit des Service-Providers kann mit der DirectPlay4.GetCaps()-Methode abgefragt werden.
Flags
Eine Konstante aus der CONST_DPENUMSESSIONSFLAGSListe
508
DirectPlay-Methoden
GetCaps GetCaps() Fragt die Leistungsfähigkeit der aktuellen DirectPlay Verbindung und Session ab. → DirectPlay4.GetPlayerCaps(), DirectPlay4.InitializeConnection() object.GetCaps(caps As DPCAPS, flags As CONST_DPGETCAPSFLAGS) As DirectPlayEnumSessions object
ein gültiges DirectPlay4-Objekt
caps
Ein DPCAPS Typen-Array, welches die ermitteltetn Merkmale aufnimmt.
flags
eine Konstante aus der CONST_DPGETCAPSFLAGS-Liste
GetSessionDesc GetSessionDesc() Erfragt die Eigenschaften der aktuell geöffneten Session. object.GetSessionDesc(sessionDesc As DirectPlaySessionData) Object
ein gültiges DirectPlay4-Objekt
Session Desc
Ein DirectPlaySessionData-Objekt, welches die Informationen aufnimmt. Dieses Objekt wird mit der DirectPlay4CreateSessionData()Methode erzeugt
Open Open() Erzeugt oder schließt sich einer Session an. → DirectPlay4.Close() object.Open(sessionDesc As DirectPlaySessionData, _ flags As CONST_DPOPENFLAGS) Object
ein gültiges DirectPlay4-Objekt
Session Desc
Ein DirectPlaySessionData-Objekt, welches die Informationen der Sessinon enthält. Dieses Objekt wird mit der DirectPlay4CreateSessionData()-Methode erzeugt.
Flags
DPOPEN_CREATE DPOPEN_JOIN DPOPEN_RETURNSTATUS
Anhang A • Methoden
509
SecureOpen SecureOpen() Erzeugt oder schließt sich einer Sicherheits-Session an. object.SecureOpen(sessionDesc DirectPlaySessionData, _ flags As CONST_DPOPENFLAGS, security As DPSECURITYDESC, _ credentials As DPCREDENTIALS)) Object
ein gültiges DirectPlay4-Objekt
SessionDesc
Ein DirectPlaySessionData-Objekt, welches die Informationen der Sessinon enthält. Dieses Objekt wird mit der DirectPlay4CreateSession-Data()-Methode erzeugt.
Flags
eine Konstante aus der CONST_DPOPENFLAGS-Liste
Security
Ein DPSECURITYDESC Typen-Array, welches die Sicherheitsinformationen enthält.
Credentials
Ein DPCREDENTIALS Typen-Array, welches LogOn-Name, Passwort und die Domäne enthält. Diese werden benötigt, um vom Server initialisiert zu werden.
SetSessionDesc SetSessionDesc() Ändert die Eigenschaften der aktuellen Session. Nur der Host-Teilnehmer einer Session kann dies tun. → DirectPlay4.GetSessionDesc() object.SetSessionDesc(sessionDesc As DirectPlaySessionData) object
ein gültiges DirectPlay4-Objekt
sessionDesc
Ein DirectPlaySessionData-Objekt, welches die Informationen der Sessinon enthält. Dieses Objekt wird mit der DirectPlay4CreateSession-Data()-Methode erzeugt.
StartSession StartSession() Startet eine DirectPlay4 Session von einer Startebene aus. object.StartSession(id As Long) Object
ein gültiges DirectPlay4-Objekt
Id
Kennung einer Gruppe. Die Gruppe muss der Veranstalter der Session sein.
510
DirectPlay-Methoden
CreatePlayer CreatePlayer() Erzeugt einen lokalen Spieler für die aktuelle Session. object.CreatePlayer(friendlyName As String, formalName As String, _ receiveEvent As Long, flags As CONST_DPPLAYERFLAGS) As Long Object
ein gültiges DirectPlay4-Objekt
Friendly Name
Rufname
Formal Name
Hausname
Receive Event
Handle für ein Ereignis, welches ausgelöst wird, wenn eine Nachricht für diesen Spieler eintrifft.
Flags
DPPLAYER_SERVERPLAYER DPPLAYER_SPECTATOR Defaultwert ist 0 → nonserverplayer und nonspectator.
DestroyPlayer DestroyPlayer() Löscht einen lokalen Spieler aus einer Session. object.DestroyPlayer(playerId As Long) Object
ein gültiges DirectPlay4-Objekt
PlayerId
Kennung des Spielers
GetDPEnumPlayers GetDPEnumPlayers() Erstellt eine Liste aller Spieler oder / und Gruppen in der aktuellen geöffneten Session. object.GetDPEnumPlayers(sessionGuid As String, _ flags As CONST_DPENUMPLAYERFLAGS) As DirectPlayEnumPlayers Object
ein gültiges DirectPlay4-Objekt
Session Guid
Der Parameter muss eine leere Zeichenkette sein, um die Spieler der aktuellen geöffneten Session aufzulisten.
Flags
Eine Konstante aus der CONST_DPENUMPLAYERFLAGS-Liste. Sie nimmt Einschränkungen an der Auflistung vor.
Anhang A • Methoden
511
GetPlayerAccountId GetPlayerAccountId() Liest die Account-Identifizierung eines Spielers. object.GetPlayerAccountId(playerId As Long) As String Object
ein gültiges DirectPlay4-Objekt
PlayerId
Kennung des Spielers, von dem die Information ermittelt werden soll.
GetPlayerAddress GetPlayerAddress() Liest die Adresse eines Spielers. object.GetPlayerAddress(playerId As Long) As String Object
ein gültiges DirectPlay4-Objekt
PlayerId
Kennung des Spielers, von dem die Information ermittelt werden soll.
GetPlayerCaps GetPlayerCaps() Ermittelt die aktuellen Eigenschaften eines Spielers. → DirectPlay4.GetCaps(), DirectPlay4.Send() object.GetPlayerCaps(playerId As Long, caps As DPCAPS, _ flags As CONST_DPGETCAPSFLAGS) object
ein gültiges DirectPlay4-Objekt
playerId
Kennung des Spielers, von dem die Information ermittelt werden soll.
caps
Ein DPCAPS Typen-Array, welches die Informationen aufnimmt.
flags
eine Konstante aus der CONST_DPGETCAPSFLAGS-Liste.
GetPlayerData GetPlayerData() Ermittelt die aktuellen Informationen über einen Spieler. Diese Informationen sind anwendungsspezifisch und werden mit der DirectPlay4.SetPlayerData()-Methode gesetzt. Der Rückgabewert ist ein Datenblock in Form einer Zeichenkette. object.GetPlayerData(playerId As Long, flags As CONST_DPGETFLAGS) _ As String Object
ein gültiges DirectPlay4-Objekt
512
DirectPlay-Methoden
GetPlayerData() PlayerId
Kennung des Spielers, von dem die Information ermittelt werden soll.
Flags
Eine Konstante aus der CONST_DPGETFLAGS-Liste.
GetPlayerFlags GetPlayerFlags() Ermittelt die Flags, welche zur Beschreibung des Spielers verwendet wurden, als der Spieler erstellt wurde. Mögliche Rückgabewerte sind: DPPLAYER_LOCAL DPPLAYER_SERVERPLAYER DPPLAYER_SPECTATOR object.GetPlayerFlags(id As Long) As CONST_DPPLAYERFLAGS Object
ein gültiges DirectPlay4-Objekt
Id
Kennung des Spielers, von dem die Information ermittelt werden soll.
GetPlayerFormalName GetPlayerFormalName() Ermittelt den Hausnamen des Spielers. object.GetPlayerFormalName(playerId As Long) As String Object
ein gültiges DirectPlay4-Objekt
PlayerId
Kennung des Spielers, von dem die Information ermittelt werden soll.
GetPlayerFriendlyName GetPlayerFriendlyName() Ermittelt den Rufnamen des Spielers. object.GetPlayerFriendlyName(playerId As Long) As String Object
ein gültiges DirectPlay4-Objekt
PlayerId
Kennung des Spielers, von dem die Information ermittelt werden soll.
SetPlayerData SetPlayerData() Setzt einen anwendungsspezifischen Datenblock für einen Spieler.
Anhang A • Methoden
513
SetPlayerData() object.SetPlayerData(playerId As Long, data As String, _ flags As CONST_DPSETFLAGS) Object
ein gültiges DirectPlay4-Objekt
PlayerId
Kennung des Spielers, dem die Information zugeordnet werden soll.
Data
Dieser Datenblock kann eine leere Zeichenkette sein, dann werden alle Daten gelöscht.
Flags
eine Konstante aus der CONST_DPSETFLAGS-Liste
SetPlayerName SetPlayerData() Setzt einen anwendungsspezifischen Datenblock für einen Spieler. object.SetPlayerName(playerId As Long, friendlyName As String, _ formalName As String, flags As CONST_DPSETFLAGS) Object
ein gültiges DirectPlay4-Objekt
PlayerId
Kennung des Spielers, dem die Information zugeordnet werden soll.
Friendly Name
Rufname
Formal Name
Hausname
Flags
Eine Konstante aus der CONST_DPSETFLAGS-Liste, welche beschreibt, wie die Informationen verbreitet werden sollen.
CancelMessage CancelMessage() Löscht eine spezifische oder alle Nachrichten der Nachrichtenwarteschlange. Um diese Nachricht / Nachrichten zu löschen, muss die Nachrichten-ID gespeichert worden sein. Dies ist Aufgabe der Anwendung. object.CancelMessage(msgid As Long) Object
ein gültiges DirectPlay4-Objekt
Msgid
Kennung der Nachricht, welche gelöscht werden soll.
CancelPriority CancelPriority() Löscht alle Nachrichten einer definierten Priorität bzw. eines Bereichs von Prioritäten.
514
DirectPlay-Methoden
CancelPriority() object.CancelPriority(minPriority As Long,
maxPriority As Long)
Object
ein gültiges DirectPlay4-Objekt
MinPriority
unterer Wert für einen Prioritätenbereich
MaxPriority
oberer Wert für einen Prioritätenbereich
CreateMessage CreateMessage() Erzeugt ein Message-Objekt, welches mit Daten zum Senden gefüllt werden kann. → DirectPlay4.Send() object.CreateMessage() As DirectPlayMessage Object
ein gültiges DirectPlay4-Objekt
GetMessageCount GetMessageCount() Ermittelt die Anzahl von Nachrichten in der Nachrichtenwarteschlange für einen definierten lokalen Spieler. → DirectPlay4.Receive() object.GetMessageCount(playerId As Long) As Long Object
ein gültiges DirectPlay4-Objekt
PlayerId
Index für einen Spieler
GetMessageQueue GetMessageQueue() Ermittelt Informationen über die gesendeten oder empfangenen Nachrichten aus der Nachrichtenwarteschlange für einen lokalen Spieler. object.GetMessageQueue(from As Long, to As Long, _ flags As CONST_DPMESSAGEQUEUEFLAGS, nMessage As Long, _ nBytes As Long) Object
ein gültiges DirectPlay4-Objekt
From
Index des Spielers, der Nachrichten sendet.
To
Index des Spielers, der Nachrichten empfängt.
Anhang A • Methoden
515
GetMessageQueue() Flags
DPMESSAGEQUEUE_SEND DPMESSAGEQUEUE_RECEIVE
NMessage
Nimmt die Anzahl der Nachrichten in der Nachrichtenwarteschlange auf.
NBytes
Nimmt die Anzahl der Bytes aller Nachrichten in der Nachrichtenwarteschlange auf.
Diese Methode ist hervorragend dazu geeignet, den Nachrichtenfluss zu regulieren.
Receive Receive() Empfängt Nachrichten aus der Nachrichtenwarteschlange. → DirectPlay4.Send() object.Receive(fromPlayerId As Long, toPlayerId As Long, _ flags As CONST_DPRECEIVEFLAGS) As DirectPlayMessage Object
ein gültiges DirectPlay4-Objekt
From PlayerId
Index des Spielers, welcher die Nachricht gesendet hat.
ToPlayer Id
Index des Spielers, für welchen die Nachricht bestimmt ist.
Flags
DPRECEIVE_ALL DPRECEIVE_PEEK DPRECEIVE_TOPLAYER PRECEIVE_FROMPLAYER
Send Send() Sendet eine Nachricht an einen Spieler oder eine Gruppe von Spielern oder allen Spielern. → DirectPlay4.Receive(), DirectPlay4.SendChatMessage() object.Send(fromPlayerId As Long, toPlayerId As Long, _ flags As CONST_DPSENDFLAGS, msg As DirectPlayMessage) object
ein gültiges DirectPlay4-Objekt
from PlayerId
Index des Spielers, welcher die Nachricht gesendet hat.
toPlayer Id
Index des Spielers, für welchen die Nachricht bestimmt ist.
516
DirectPlay-Methoden
Send() flags
DPSEND_ENCRYPTED DPSEND_GUARANTEED DPSEND_SIGNED
msg
Ein DirectPlayMessage Objekt, welches die Nachricht enthält, die versendet werden soll.
SendChatMessage SendChatMessage() Sendet eine Textnachricht an einen Spieler oder einer Gruppe von Spielern oder allen Spielern. object.SendChatMessage(fromPlayerId As Long, toPlayerId As Long, _ flags As CONST_DPSENDFLAGS, message As String) Object
ein gültiges DirectPlay4-Objekt
From PlayerId
Index des Spielers, welcher die Nachricht gesendet hat.
ToPlayer Id
Index des Spielers, für welchen die Nachricht bestimmt ist.
Flags
DPSEND_GUARANTEED Ist dieser Parameter 0, so ist das Ankommen der Nachricht nicht garantiert.
Msg
Nachricht die gesendet werden soll.
SendEx SendEx() Sendet eine Textnachricht an einen Spieler oder einer Gruppe von Spielern oder allen Spielern. SendEx() ist eine erweiterte Version der Send()-Methode. object.SendEx(fromPlayerId As Long, toPlayerId As Long, _ flags As CONST_DPSENDFLAGS, msg As DirectPlayMessage, _ priority As Long, timeOut As Long, context As Long) As Long Object
ein gültiges DirectPlay4-Objekt
fromPlayerId
Index des Spielers, welcher die Nachricht gesendet hat.
toPlayerId
Index des Spielers, für welchen die Nachricht bestimmt ist.
Anhang A • Methoden
517
SendEx() Flags
DPSEND_ASYNC DPSEND_ENCRYPTED DPSEND_GUARANTEED DPSEND_NOSENDCOMPLETEMSG DPSEND_SIGNED
Msg
Ein DirectPlayMessage-Objekt, welches die Nachricht enthält, die versendet werden soll.
Priority
Priorität der Nachricht. Liegt im Wertebereich zwischen 0 und 65535.
timeOut
Zeit in Millisekunden, die gewartet wird, bis die Nachricht abgeliefert wurde.
Context
Anwendungsbezogener Kontex, welcher zur Vervollständigung der Nachricht gehört. Kann 0 sein.
AddGroupToGroup AddGroupToGroup() Addiert eine Gruppe zu einer anderen Gruppe. → DirectPlay4.CreateGroupInGroup() object.AddGroupToGroup(ParentGroupId As Long, GroupId As Long) object
ein gültiges DirectPlay4-Objekt
Parent GroupId
Index der Gruppe, in die eine Gruppe eingefügt werden soll.
GroupId
Index der Gruppe, welche in eine Gruppe eingefügt werden soll.
Die Systemnachricht DPSYS_ADDGROUPTOGROUP wird erzeugt, um die anderen Spieler von diesem Wechsel in Kenntnis zu setzen.
AddPlayerToGroup AddPlayerToGroup() Integriert einen Spieler in eine bestehende Gruppe. → DirectPlay4.CreateGroup(), DirectPlay4.DeletePlayerFromGroup() object.AddPlayerToGroup(GroupId As Long, playerId As Long) object
ein gültiges DirectPlay4-Objekt
ParentGroupId
Index der Gruppe, in die ein Spieler eintreten möchte.
playerId
Index des Spielers, welcher der Gruppe beitreten möchte.
Ein Spieler kann Mitglied in mehreren Gruppen sein. Dabei muss der Spieler nicht unbedingt ein lokaler Spieler sein.
518
DirectPlay-Methoden
CreateGroup CreateGroup() Erzeugt eine Gruppe in der aktuellen Session. → DirectPlay4.AddGroupToGroup(), DirectPlay4.DestroyGroup(), DirectPlay4.GetDPEnumGroupPlayers(), DirectPlay4.GetGroupFlags(), DirectPlay4.SetGroupData(), DirectPlay4.SetGroupName() object.CreateGroup(friendlyName As String, formalName As String, _ flags As CONST_DPGROUPFLAGS) As Long object
ein gültiges DirectPlay4-Objekt
friendly Name
Rufname
formal Name
Hausname
flags
DPGROUP_DEFAULT DPGROUP_HIDDEN DPGROUP_STAGINGAREA
Ist die Gruppe in einer Client/Server-Session erzeugt worden, werden keine Gruppeninformationsnachrichten erzeugt. Gruppen sind nur auf dem Computer sichtbar, auf dem sie erzeugt wurden, unabhängig davon, ob es sich um den Client, oder Host-Rechner handelt. In einer Peer-to-Peer Session wird die Nachricht DPSYS_CREATEPLAYERORGROUP erzeugt und an alle Spieler der Session gesendet.
CreateGroupInGroup CreateGroupInGroup() Erzeugt eine Gruppe in einer existierenden Gruppe. object.CreateGroupInGroup(parentid As Long, friendlyName As String, _ formalName As String, flags As CONST_DPGROUPFLAGS) As Long Object
ein gültiges DirectPlay4-Objekt
Parentid
Index der Gruppe, in der eine Gruppe erzeugt werden soll.
Friendly Name
Rufname
Formal Name
Hausname
Flags
DPGROUP_LOCAL DPGROUP_STAGINGAREA
Anhang A • Methoden
519
CreateGroupInGroup() Um sich die erzeugten Gruppen in einer Gruppe anzeigen zu lassen, muss die DirectPlay4.GetDPEnumGroupsInGroup()-Methode verwendet werden. Ist die Gruppe in einer Client/Server-Session erzeugt worden, werden keine Gruppeninformations Nachrichten erzeugt. Gruppen sind nur auf dem Computer sichtbar, auf dem sie erzeugt wurden, unabhängig davon, ob es sich um den Client- oder Host-Rechner handelt. In einer Peer-to-Peer Session wird die Nachricht DPSYS_CREATEPLAYEROR GROUP erzeugt und an alle Spieler der Session gesendet.
DeleteGroupFromGroup DeleteGroupFromGroup() Entfernt eine Gruppe aus einer bestehenden Gruppe. Die Gruppe wurde zuvor mit der DirectPlay4.AddGroupToGroup()-Methode eingefügt. object. DeleteGroupFromGroup(ParentGroupId As Long, GroupId As Long) Object
ein gültiges DirectPlay4-Objekt
Parent GroupId
Index der Gruppe, aus der eine Gruppe entfernt werden soll.
GroupId
Index der Gruppe, die entfernt werden soll.
Die DPSYS_DELETEGROUPFROMGROUP-Systemnachricht wird erzeugt und informiert alle Spieler über den Wechsel.
DeletePlayerFromGroup DeletePlayerFromGroup() Entfernt einen Spieler aus einer Gruppe. → DirectPlay4.AddPlayerToGroup() object.DeletePlayerFromGroup(GroupId As Long, playerId As Long) Object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, aus der ein Spieler entfernt werden soll.
playerId
Index des Spielers, der entfernt werden soll.
Die DPSYS_DELETEPLAYERFROMGROUP-Systemnachricht wird erzeugt und informiert alle Spieler über den Wechsel.
DestroyGroup DestroyGroup() Löscht eine Gruppe aus einer Session. → DirectPlay4.CreateGroup()
520
DirectPlay-Methoden
DestroyGroup() object.DestroyGroup(GroupId As Long) object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, die gelöscht werden soll.
Die DPSYS_DELETEPLAYERFROMGROUP-Systemnachricht wird für jeden Spieler aus der Gruppe erzeugt. Anschließend wird die DPSYS_DESTROYPLAYEROR GROUP-Systemnachricht erzeugt.
GetDPEnumGroupPlayers GetDPEnumGroupPlayers() Erzeugt eine Liste von allen Spielern in einer definierten Gruppe in einer geöffneten Session. → DirectPlay4.CreatePlayer(), DirectPlay4.DestroyPlayer(), DirectPlay4.AddPlayerToGroup(), DirectPlay4.DeletePlayerFromGroup() GetDPEnumGroupPlayers(GroupId As Long, sessionGuid As String, _ flags As CONST_DPENUMPLAYERFLAGS) As DirectPlayEnumPlayers object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, aus der die Spieler ermittelt werden sollen.
session Guid
Eine Guid, welche die Session eindeutig identifiziert.
flags
Definiert, welche Spieler aufgelistet werden sollen. DPENUMPLAYERS_LOCAL DPENUMPLAYERS_OWNER DPENUMPLAYERS_REMOTE DPENUMPLAYERS_SERVERPLAYER DPENUMPLAYERS_SESSION DPENUMPLAYERS_SPECTATOR
GetDPEnumGroups GetDPEnumGroups() Erzeugt eine Liste aller Gruppen einer Session. Die Gruppen müssen mit der DirectPlay4.CreateGroup()-Methode erzeugt worden sein. Gruppen in Gruppen werden nicht aufgelistet. → DirectPlay4.DestroyGroup(), DirectPlay4.GetDPEnumSessions() object.GetDPEnumGroups(sessionGuid As String, _ flags As CONST_DPENUMGROUPFLAGS) As DirectPlayEnumPlayers object
ein gültiges DirectPlay4-Objekt
Anhang A • Methoden
521
GetDPEnumGroups() session Guid
Eine Guid, welche die Session eindeutig identifiziert.
flags
DPENUMGROUPS_ALL DPENUMGROUPS_LOCAL DPENUMGROUPS_REMOTE DPENUMGROUPS_SESSION DPENUMGROUPS_STAGINGAREA
GetDPEnumGroupsInGroup GetDPEnumGroupsInGroup() Erzeugt eine Liste aller Second-Level-Gruppen. Damit sind Gruppen gemeint, die in einer Top-Level-Gruppe existieren. Diese Gruppen wurden mit den DirectPlay4.CreateGroupInGroup()- oder DirectPlay4.AddGroupToGroup()-Methoden erzeugt. → DirectPlay4.DeleteGroupFromGroup(), DirectPlay4.DestroyGroup() object.GetDPEnumGroupsInGroup(GroupId As Long, sessionGuid As String, _ flags As CONST_DPENUMGROUPFLAGS) As DirectPlayEnumPlayers object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, aus der die Second-Level-Gruppen aufgelistet werden sollen.
session Guid
Eine Guid, welche die Session eindeutig identifiziert.
flags
DPENUMGROUPS_ALL DPENUMGROUPS_HIDDEN DPENUMGROUPS_LOCAL DPENUMGROUPS_REMOTE DPENUMGROUPS_SESSION DPENUMGROUPS_SHORTCUT DPENUMGROUPS_STAGINGAREA
GetGroupData GetGroupData() Ermittelt eine anwendungsspezifische Zeichenkette, welche mit der Gruppe verknüpft ist. object.GetGroupData(GroupId As Long, flags As CONST_DPGETFLAGS) _ As String Object
ein gültiges DirectPlay4-Objekt
GroupId
Index des Spielers, welcher die Nachricht gesendet hat.
522
DirectPlay-Methoden
GetGroupData() Flags
DPGET_LOCAL DPGET_REMOTE
GetGroupFlags GetGroupFlags() Ermittelt die Flag-Beschreibungen einer definierten Gruppe. → DirectPlay4.CreateGroup() object.GetGroupFlags(GroupId As Long) As Long Object
ein gültiges DirectPlay4-Objekt
GetGroupLongName GetGroupLongName() Ermittelt den Long-Namen (Hausnamen) einer Gruppe. object.GetGroupLongName(GroupId As Long) As String Object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, von welcher der Name ermittelt werden soll.
GetGroupShortName GetGroupLongName() Ermittelt den Short-Namen (Rufnamen) einer Gruppe. object.GetGroupShortName(GroupId As Long) As String Object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, von welcher der Name ermittelt werden soll.
GetGroupOwner GetGroupOwner() Ermittelt den Eigentümer einer definierten Gruppe. Der Eigentümer einer Gruppe wurde mit der DirectPlay4.SetGroupOwner()-Methode gesetzt. object.GetGroupOwner(GroupId As Long) As Long Object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, von welcher der Eigentümer ermittelt werden soll.
Die Methode ist nur für eine Lobby-Session gültig.
Anhang A • Methoden
523
GetGroupParent GetGroupParent() Ermittelt die Kennung einer Gruppe, welche die definierte Gruppe beinhaltet. → DirectPlay4.CreateGroupInGroup() object.GetGroupParent(GroupId As Long) As Long object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, für welche die Top-Level-Gruppe ermittelt werden soll.
SetGroupData SetGroupData() Setzt einen spezifizierten Datenblock für eine Gruppe. Nur der Computer der die Gruppe erzeugt hat, kann den Datenblock ändern. → DirectPlay4.GetGroupData() object.SetGroupData(GroupId As Long, data As String, _ flags As CONST_DPSETFLAGS) object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, von welcher der Datenblock geändert werden soll.
data
Datenblock der gesetzt werden soll. DPGETCAPS_DEFAULT DPGETCAPS_GUARANTEED
Ist der Data-Parameter eine leere Zeichenkette, so wird der Datenblock der Gruppe gelöscht.
SetGroupName SetGroupName() Setzt den Rufnamen sowie den Hausnamen einer Gruppe. Die Gruppe muss zuvor erzeugt worden sein. → DirectPlay4.GetGroupLongName(), DirectPlay4.GetGroupShortName(), DirectPlay4.Send() object.SetGroupName(GroupId As Long, friendlyName As String, _ formalName As String, flags As CONST_DPSETFLAGS) Object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, deren Namen geändert werden sollen.
Friendly Name
Rufname
524
DirectPlay-Methoden
SetGroupName() FormalName
Hausname
Flags
DPSET_GUARANTEED DPSET_LOCAL DPSET_REMOTE
SetGroupOwner SetGroupOwner() Setzt den Eigentümer einer Gruppe. Dies Methode kann nur in einer Lobby-Session eingesetzt werden. → DirectPlay4.GetGroupOwner() object.SetGroupOwner(GroupId As Long, ownerId As Long)
A.6.2
object
ein gültiges DirectPlay4-Objekt
GroupId
Index der Gruppe, für welche ein neuer Eigentümer festgelegt werden soll.
ownerId
Index des Spielers, der als neuer Eigentümer der Gruppe gültig sein soll.
DirectPlayEnumConnections Die DirectPlayEnumConnections-Klasse erzeugt Listen über die bestehenden Verbindungen. Anwendungen nutzen diese Klasse, um Informationen über die Verbindungen zu erhalten. Das DirectPlayEnumConnections-Objekt wird mit der DirectPlay4.GetDPEnumConnections()-Methode erzeugt. Folgende Methoden gehören zu der DirectPlayEnumConnections-Klasse: Auflistung
GetAddress GetCount GetFlags GetGuid GetName
GetAddress GetAddress() Ermittelt ein Address-Objekt vom Auflistungsobjekt. object.GetAddress(index As Long) As DirectPlayAddress Object
ein gültiges DirectPlayEnumConnections-Objekt
Anhang A • Methoden
525
GetAddress() Index
Element aus dem Auflistungsobjekt, von welchem die Information ermittelt werden soll.
GetCount GetCount() Ermittelt die Anzahl der Elemente im Auflistungsobjekt. object.GetCount() As Long Object
ein gültiges DirectPlayEnumConnections-Objekt
GetFlags GetFlags() Ermittelt die Flags für eine aufgelistete Verbindung aus dem Auflistungsobjekt. object.GetFlags(index As Long) As Long Object
ein gültiges DirectPlayEnumConnections-Objekt
Index
Element aus dem Auflistungsobjekt, von welchem die Information ermittelt werden soll.
Der Rückgabewert ist identisch mit den Flags, die zusammen mit der DirectPlay4.GetDPEnumConnections()-Methode übergeben wurden.
GetGuid GetGuid() Ermittelt die Guid einer Verbindung aus dem Auflistungsobjekt. object.GetGuid(index As Long) as String Object
ein gültiges DirectPlayEnumConnections-Objekt
Index
Element aus dem Auflistungsobjekt, von welchem die Information ermittelt werden soll.
GetName GetName() Ermittelt den Namen einer Verbindung aus dem Auflistungsobjekt. object.GetName(index As Long) As String Object
ein gültiges DirectPlayEnumConnections-Objekt
526
DirectPlay-Methoden
GetName() Index
A.6.3
Element aus dem Auflistungsobjekt, von welchem die Information ermittelt werden soll.
DirectPlayEnumLocalApplications Die DirectPlayEnumLocalApplications-Klasse erzeugt eine Liste mit lokalen Anwendungen. Anwendungen nutzen diese Klasse, um Informationen über die lokalen Anwendungen zu erhalten. Das DirectPlayEnumLocalApplications-Objekt wird mit der DirectPlay-Lobby3. GetDPEnumLocalApplications()-Methode erzeugt. Folgende Methoden gehören zu der DirectPlayEnumLocalApplications-Klasse: Auflistung
GetCount GetGuid GetName
GetCount GetCount() Ermittelt die Anzahl der Elemente im DirectPlayEnumLocalApplications-Objekt. object.GetCount() As Long Object
ein gültiges DirectPlayEnumLocalApplications-Objekt
GetGuid GetGuid() Ermittelt die Guid eines definierten Elementes aus dem DirectPlayEnumLocalApplications-Objekt. object.GetItem(index As Long) as String Object
ein gültiges DirectPlayEnumLocalApplications-Objekt
Index
Element aus dem DirectPlayEnumLocalApplications-Objekt, von welchem die Guid ermittelt werden soll.
Anhang A • Methoden
527
GetName GetName() Ermittelt den Namen eines definierten Elementen aus dem DirectPlayEnumLocalApplications-Objekt. object.GetItem(index As Long) as String
A.6.4
Object
ein gültiges DirectPlayEnumLocalApplications-Objekt
Index
Element aus dem DirectPlayEnumLocalApplications-Objekt, von welchem die Information ermittelt werden soll.
DirectPlayEnumPlayers Die DirectPlayEnumPlayers-Klasse erzeugt eine Liste mit Spielern oder Gruppen einer Session oder Gruppe. Anwendungen nutzen diese Klasse, um Informationen über Spieler oder Gruppen zu erhalten. Das DirectPlayEnumPlayer-Objekt wird von folgenden Methoden erzeugt: DirectPlay4.GetDPEnumGroups() DirectPlay4.GetDPEnumGroupsInGroup() DirectPlay4.GetDPEnumGroupPlayers() DirectPlay4.GetDPEnumPlayers()
Folgende Methoden gehören zu der DirectPlayEnumPlayers-Klasse: Auflistung
GetCount GetDPID GetFlags GetLongName GetShortName GetType
GetCount GetCount() Ermittelt die Anzahl der Elemente in dem DirectPlayEnumPlayer-Objekt. object.GetCount() As Long Object
ein gültiges DirectPlayEnumPlayers-Objekt
528
DirectPlay-Methoden
GetDPID GetDPID() Ermittelt eine numerische Identifizierung eines Spielers oder einer Gruppe. object.GetDPID(index As Long) As Long Object
ein gültiges DirectPlayEnumPlayers-Objekt
Index
ein Element aus dem DirectPlayEnumPlayer-Objekt
GetFlags GetFlags() Ermittelt unterschiedlichste Informationen über einen gelisteten Spieler oder Gruppe. → DirectPlay4.GetDPEnumGroups(), DirectPlay4.GetDPEnumGroupsInGroup(), DirectPlay4.GetDPEnumPlayers(), DirectPlay4.GetDPEnumGroupPlayers() object.GetFlags(index As Long) As Long object
ein gültiges DirectPlayEnumPlayers-Objekt
index
ein Element aus dem DirectPlayEnumPlayer-Objekt
GetLongName GetLongName() Ermittelt den Hausnamen (Long) von einem Spieler oder einer Gruppe. object.GetLongName(index As Long) As String Object
ein gültiges DirectPlayEnumPlayers-Objekt
Index
ein Element aus dem DirectPlayEnumPlayer-Objekt
GetShortName GetShortName() Ermittelt den Rufnamen (Short) von einem Spieler oder einer Gruppe. object.GetShortName(index As Long) As String Object
ein gültiges DirectPlayEnumPlayers-Objekt
Index
ein Element aus dem DirectPlayEnumPlayer-Objekt
Anhang A • Methoden
529
GetType GetType() Prüft, ob ein Element aus dem DirectPlayEnumPlayer-Objekt ein Spieler oder eine Gruppe ist. object.GetType(index As Long) As Long Object
ein gültiges DirectPlayEnumPlayers-Objekt
Index
ein Element aus dem DirectPlayEnumPlayer-Objekt
Ist der Rückgabewert DPPLAYERTYPE_GROUP handelt es sich um eine Gruppe. Bei einem Spieler ist der Rückgabewert DPPLAYERTYPE_PLAYER
A.6.5
DirectPlayEnumSessions Die DirectPlayEnumSession-Klasse erzeugt eine Liste mit alle aktiven Sessions. Anwendungen nutzen diese Klasse, um Informationen über die Sessions zu erhalten. Das DirectPlayEnumSessions-Objekt wird mit der DirectPlay4.GetDPEnum Sessions()-Methode erzeugt. Folgende Methoden gehören zu der DirectPlayEnumSessions-Klasse: Auflistung
GetCount GetItem
GetCount GetCount() Ermittelt die Anzahl der Elemente in dem DirectPlayEnumSessions-Objekt. object.GetType(index As Long) As Long Object
ein gültiges DirectPlayEnumSessions-Objekt
GetItem GetItem() Erzeugt ein DirectPlaySessionData Objekt, welches mit den repräsentativen Informationen der Session gefüllt ist. object.GetType(index As Long) As Long Object
ein gültiges DirectPlayEnumSessions-Objekt
Index
ein Element aus dem DirectPlayEnumSession-Objekt
530
A.6.6
DirectPlay-Methoden
DirectPlayLobby3 Anwendungen nutzen die Methoden der DirectPlayLobby3-Klasse, um Anwendungen und deren Daten zu managen. Das DirectPlayLobby3 Objekt wird mit der DirectX7.DirectPlayLobbyCreate()Methode erzeugt. Folgende Methoden gehören zu der DirectPlayEnumSessions-Klasse: Adresse
CreateComPortAddress CreateCustomAddress CreateInetAddress CreateIPXAddress CreateLobbyProviderAddress CreateModemAddress CreateServiceProviderAddress GetModemCount GetModemName
Anwendung
Connect GetDPEnumLocalApplications RegisterApplication RunApplication UnregisterApplication WaitForConnectionSettings
Nachrichten
CreateMessage ReceiveLobbyMessage SendLobbyMessage SetLobbyMessageEvent
Verbindung
CreateConnectionData GetConnectionSettings SetConnectionSettings
CreateComPortAdress CreateComPortAdress() Erzeugt eine DirectPlay-Adresse für den Com Port. object.CreateComPortAddress(port As Long, baudRate As Long, _ stopBits As Long, parity As Long, flowcontrol As Long) As DirectPlayAddress Object
ein gültiges DirectPlayLobby3-Objekt
Port
Nummer des Com-Ports: 1, 2, 3 oder 4
Anhang A • Methoden
531
CreateComPortAdress() baudRate
Mögliche Werte: 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200, 128000, 256000
StopBits
Anzahl der Stop-Bits 0 (1 Stop-Bit), 1 (1,5 Stop-Bits), 2 (2 Stop-Bits)
Parity
0 1 2 3
→ → → →
No parity Odd parity Even parity Mark parity
flow control
0 1 2 3 4
→ → → → →
No flow control Software flow control (xon/xoff) Hardware flow control mit RTS Hardware flow control mit DTR Hardware flow control mit RTS und DTR
CreateCustomAddress CreateCustomAddress() Erzeugt eine DirectPlay-Adresse für eine von anderen Modellen nicht unterstütztes Format. object.CreateCustomAddress(size As Long, data As Any) As DirectPlayAddress Object
ein gültiges DirectPlayLobby3-Objekt
Size
Größe der Daten
Data
Daten für das DirectPlayAddress-Objekt
CreateInetAddress CreateInetAddress() Erzeugt eine DirectPlay-Adresse für eine Internetadresse. object.CreateINetAddress(addr As String, port As Long) As DirectPlayAddress Object
ein gültiges DirectPlayLobby3-Objekt
Addr
IP-Adresse (z.B. 193.168.0.1) oder (»LightDesk.de«)
Port
Tor für die Verbindung. Der voreingestellte Port ist TCP/IP mit dem Wert 0.
532
DirectPlay-Methoden
CreateIPXAddress CreateIPXAddress() Erzeugt eine DirectPlay-Adresse für einen IPX-Service Provider. object.CreateIPXAddress() As DirectPlayAddress Object
ein gültiges DirectPlayLobby3-Objekt
CreateLobbyProviderAddress CreateLobbyProviderAddress() Erzeugt eine DirectPlay-Adresse für einen Lobby Provider. object.CreateLobbyProviderAddress( guid As String) As DirectPlay Address Object
ein gültiges DirectPlayLobby3-Objekt
Guid
Kennung für den Lobby-Provider.
CreateModemAddress CreateModemAddress() Erzeugt eine DirectPlay-Adresse für ein Modem. object.CreateModemAddress( modem As String, _ phone as String) As DirectPlayAddress Object
ein gültiges DirectPlayLobby3-Objekt
Modem
Name des Modems
Phone
Telefonnummer
Der Name des Modems kann mit der DirectPlayLobby3.GetModemName()-Methode ermittelt werden.
CreateServiceProviderAddress CreateServiceProviderAddress() Erzeugt eine DirectPlay-Adresse für einen Service-Provider. object.CreateServiceProviderAddress( guid as String) As _ DirectPlayAddress Object
ein gültiges DirectPlayLobby3-Objekt
Guid
Kennung für den Service-Provider
Anhang A • Methoden
533
GetModemCount GetModemCount() Ermittelt die Anzahl der Modems, welche für das System zur Verfügung steht. object.GetModemCount() As Long Object
ein gültiges DirectPlayLobby3-Objekt
GetModemName GetModemName() Ermittelt den Namen eines Modems. object.GetModemName(index As Long) As String Object
ein gültiges DirectPlayLobby3-Objekt
Index
Index für ein Modem. Der Wertebereich liegt zwischen 1 und DirectPlayLobby3.GetModemCount().
Connect Connect() Verbindet eine Anwendung mit einer Session. object.Connect(flags As Long) As DirectPlay4 Object
ein gültiges DirectPlayLobby3-Objekt
Flags
eine Konstante aus der CONST_DPCONNECTFLAGS-Liste
GetDPEnumLocalApplications GetDPEnumLocalApplications() Erzeugt eine Liste von Anwendungen, die mit DirectPlay registriert sind. object.GetDPEnumLocalApplications() As _ DirectPlayEnumLocalApplications Object
ein gültiges DirectPlayLobby3-Objekt
RegisterApplication RegisterApplication() Registriert eine Lobby-Aware-Anwendung mit DirectPlay. → DirectPlayLobby3.UnregisterApplication()
534
DirectPlay-Methoden
RegisterApplication() object.RegisterApplication( ApplicationInfo As DPAPPLICATIONDESC2) Object
ein gültiges DirectPlayLobby3-Objekt
ApplicationInfo
Ein DPAPPLICATIONDESC2 Typen-Array, welches die Anwendung beschreibt, die registriert werden soll.
Eine Anwendung muss registriert sein, damit sie von einer DirectPlay-Lobby gestartet werden kann. Eine Anwendung muss nur einmal registriert werden. Wenn die Anwendung deinstalliert wird, so muss die Registrierung der Anwedung gelöscht werden.
RunApplication RunApplication() Startet eine registrierte Anwendung und übermittelt alle Informationen, welche benötigt werden, um die Verbindung zu einer Session herzustellen. → DirectPlayLobby3.GetConnectionSettings(), DirectX7.CreateEvent() object.RunApplication( connection As DirectPlayLobbyConnection, _ receiveEvent As Long) As Long object
ein gültiges DirectPlayLobby3 Objekt
connection
Ein Interface, welches alle Informationen definiert, die die Anwendung benötigt, um eine Verbindung zu einer Session herzustellen.
receive Event
Handle zu einem Event
UnregisterApplication UnregisterApplication() Löscht die Registrierungseinträge von einer DirectPlay-Anwendung. → DirectPlayLobby3.RegisterApplication() object.UnregisterApplication(GuidApplication As String) object
ein gültiges DirectPlayLobby3-Objekt
Guid Application
Kennung der Anwendung, deren Registrierung gelöscht werden soll.
WaitForConnectionsSettings WaitForConnectionsSettings() Setzt eine Anwendung in den Wartezustand. object.WaitForConnectionSettings(flags As CONST_DPLWAIT)
Anhang A • Methoden
535
WaitForConnectionsSettings() object
ein gültiges DirectPlayLobby3-Objekt
flags
DPLWAIT_CANCEL DPLWAIT_DEFAULT
CreateMessage CreateMessage() Erzeugt eine Lobby-Nachricht. object.CreateMessage() As DirectPlayMessage object
ein gültiges DirectPlayLobby3-Objekt
ReceiveLobbyMessage ReceiveLobbyMessage() Empfängt Lobby-Nachrichten, welche zwischen den Lobby-Clients versendet werden. → DirectPlayLobby3.ReceiveLobbyMessage(), DirectPlayLobby3.SendLobbyMessage() object.ReceiveLobbyMessage(applicationId As Long, _ messageFlags As Long) As DirectPlayMessage object
ein gültiges DirectPlayLobby3-Objekt
applicationId
Kennung der Anwendung, von welcher die Nachricht gesendet wurde.
messageFlags
DPLMSG_STANDARD DPLMSG_SYSTEM DPLMSG_USERDEFINED
SendLobbyMessage SendLobbyMessage() Sendet eine Lobby-Nachricht zwischen der Anwendung und den Lobby-Clients. → DirectPlayLobby3.ReceiveLobbyMessage() object.SendLobbyMessage(flags As CONST_DPLMSG, _ applicationId As Long, msg As DirectPlayMessage) object
ein gültiges DirectPlayLobby3-Objekt
flags
DPLMSG_STANDARD DPLMSG_SYSTEM DPLMSG_USERDEFINED
536
DirectPlay-Methoden
SendLobbyMessage() applicationId
Kennung der Anwendung, welche die Nachricht sendet.
msg
Nachricht
SetLobbyMessageEvent SetLobbyMessageEvent() Registriert ein Event-Handling, welches gesetzt wird, wenn die Lobby-Nachricht eintrifft. → DirectPlayLobby3.ReceiveLobbyMessage(), DirectPlayLobby3.SendLobbyMessage(), DirectX7.CreateEvent() object.SetLobbyMessageEvent(applicationId As Long, receiveEvent As Long) object
ein gültiges DirectPlayLobby3-Objekt
applicationId
Kennung der Anwendung, welche die Nachricht sendet.
receiveEvent
Handle des Events, welches gesetzt wird, wenn die Nachricht eintrifft.
CreateConnectionData CreateConnectionData() Erzeugt ein DirectPlayLobbyConnection-Objekt. object.CreateConnectionData() As DirectPlayLobbyConnection object
ein gültiges DirectPlayLobby3-Objekt
GetConnectionSettings GetConnectionSettings () Empfängt ein DirectPlayLobbyConnection-Objekt, welches die Informationen beinhaltet, die zum Starten und zum Verbinden der Anwendung benötigt werden. → DirectPlayLobby3.WaitForConnectionSettings() object.GetConnectionSettings(applicationId As Long) _ As DirectPlayLobbyConnection object
ein gültiges DirectPlayLobby3-Objekt
applicationId
Identifikation, von welcher Anwendung die Informationen sind.
Anhang A • Methoden
537
SetConnectionSettings SetConnectionSettings () Modifiziert die Verbindungsinformationen einer Anwendung. object.SetConnectionSettings(applicationId As Long, _ connection As DirectPlayLobbyConnection)
A.6.7
object
ein gültiges DirectPlayLobby3-Objekt
applicationId
Kennung der Anwendung
connection
modifizierte Daten
DirectPlayLobbyConnection Anwendungen nutzen die Methoden der DirectPlayLobbyConnection-Klasse um Informationen zu managen, welche für die Verbindung einer Anwendung mit einer Session benötigt werden. Das DirectPlayLobbyConnection-Objekt wird mit den DirectPlayLobby3.CreateConnectionData()- und DirectPlayLobby3.GetConnectionSettings()-Methoden erzeugt. Folgende Methoden gehören zu der DirectPlayLobbyConnection-Klasse: Erhalten
GetAddress GetFlags GetGuidSP GetPlayerLongName GetPlayerShortName GetSessionDesc
Setzen
SetAddress SetFlags SetGuidSP SetPlayerLongName SetPlayerShortName SetSessionDesc
GetAddress GetAddress() Ermittelt DirectPlay Adresse. object.GetAddress() As DirectPlayAddress
538
DirectPlay-Methoden
GetAddress() object
ein gültiges DirectPlayLobbyConnection-Objekt
GetFlags GetFlags() Ermittelt Informationen, wie die Session geöffnet wurde. object.GetFlags() As Long object
ein gültiges DirectPlayLobbyConnection-Objekt
Die Rückgabewerte können sein: DPLCONNECTION_CREATESESSION DPLCONNECTION_JOINSESSION
GetGuidSP GetGuidSP() Ermittelt die Guid des Service Providers, welcher für die Verbindung mit der Session verwendet wurde. object.GetGuidSP() As String object
ein gültiges DirectPlayLobbyConnection-Objekt
GetPlayerLongName GetPlayerLongName() Ermittelt den Hausnamen (Long) eines Spielers. → DirectPlayLobbyConnection.SetPlayerLongName() object.GetPlayerLongName() As String object
ein gültiges DirectPlayLobbyConnection-Objekt
GetPlayerShortName GetPlayerShortName() Ermittelt den Rufnamen (Short) eines Spielers. → DirectPlayLobbyConnection.SetPlayerShortName() object.GetPlayerShortName() As String object
ein gültiges DirectPlayLobbyConnection-Objekt
Anhang A • Methoden
539
GetSessionDesc GetSessionDesc() Ermittelt die Beschreibung einer Session. → DirectPlay4.Open(), DirectPlay4.SecureOpen(), DirectPlay4.SetSessionDesc() object.GetSessionDesc() As DirectPlaySessionData object
ein gültiges DirectPlayLobbyConnection-Objekt
SetAddress SetAddress() Setzt die DirectPlay Adresse, welche der Service Provider benötigt, um eine Verbindung mit der Session herzustellen. object.SetAddress(address As DirectPlayAddress) object
ein gültiges DirectPlayLobbyConnection-Objekt
address
DirectPlayAddress-Objekt
SetFlags SetFlags() Indiziert, wie eine Session geöffnet werden soll. object.SetFlags(flags As CONST_DPLCONNECTIONFLAGS) object
ein gültiges DirectPlayLobbyConnection-Objekt
flags
DPLCONNECTION_CREATESESSION DPLCONNECTION_JOINSESSION
SetGuidSP SetGuidSP() Setzt die Guid für den Service Provider. object.SetGuidSP(guid As String) object
ein gültiges DirectPlayLobbyConnection-Objekt
guid
DPSPGUID_IPX DPSPGUID_TCPIP DPSPGUID_SERIAL DPSPGUID_MODEM
540
DirectPlay-Methoden
SetPlayerLongName SetPlayerLongName() Setzt den Hausnamen (Long) für einen Spieler. → DirectPlayLobbyConnection.SetPlayerShortName() object.SetPlayerLongName(name As String) object
ein gültiges DirectPlayLobbyConnection-Objekt
name
Hausname
SetPlayerShortName SetPlayerShortName() Setzt den Rufnamen (Short) für einen Spieler. → DirectPlayLobbyConnection.SetPlayerLongName() object.SetPlayerShortName(name As String) object
ein gültiges DirectPlayLobbyConnection-Objekt
name
Rufname
SetSessionDesc SetSessionDesc() Setzt die Informationen einer Session, welche benötigt werden um eine Session zu erstellen oder sich einer Session anzuschließen. object.SetSessionDesc(sessionDesc As DirectPlaySessionData)
A.6.8
object
ein gültiges DirectPlayLobbyConnection-Objekt
sessionDesc
Beschreibung der Session
DirectPlayMessage Anwendungen nutzen die Methoden der DirectPlayMessage-Klasse, um Daten in eine Nachricht zu schreiben oder Daten aus einer Nachricht zu lesen. Das DirectPlayMessage-Objekt wird mit der DirectPlay4.CreateMessage()Methode erzeugt. Das DirectPlayMessage-Objekt wird mit der DirectPlay4. Receive()- oder DirectPlayLobby3.ReceiveLobbyMessage()-Methode empfangen. Alle Systemnachrichten beinhalten als erstes Element einen Long-Eintrag. Dieser dient zur Identifizierung des Nachrichtentyps.
Anhang A • Methoden
541
Folgende Methoden gehören zu der DirectPlayMessage-Klasse: Daten lesen
GetMessageData MoveToSecureMessage MoveToTop ReadByte ReadDouble ReadGuid ReadLong ReadShort ReadSingle ReadString ReadSysChatString ReadSysMsgConnection ReadSysMsgData ReadSysMsgSessionDesc
Daten schreiben
SetMessageData WriteByte WriteDouble WriteGuid WriteLong WriteShort WriteSingle WriteString
Verschiedenes
Clear GetMessageSize
GetMessageData GetMessageData() Ermittelt unformatierte (raw) Daten einer Nachricht. object.GetMessageData(userDefinedType As Any) object
ein gültiges DirectPlayMessage-Objekt
userDefined Type
Definition, wie die Daten interpretiert werden sollen.
MoveToSecureMessage MoveToSecureMessage() Setzt den Lesezeiger an den Anfang der gesicherten Nachrichten. object.MoveToSecureMessage() object
ein gültiges DirectPlayMessage-Objekt
542
DirectPlay-Methoden
MoveToTop MoveToTop() Setzt den Lesezeiger an den Anfang der Nachrichtenwarteschlange. object.MoveToTop() object
ein gültiges DirectPlayMessage-Objekt
ReadByte ReadByte() Liest ein Byte von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadByte() As Byte object
ein gültiges DirectPlayMessage-Objekt
ReadDouble ReadDouble() Liest ein Double von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadDouble() As Double object
ein gültiges DirectPlayMessage-Objekt
ReadGuid ReadGuid() Liest die Guid von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadGuid() As String object
ein gültiges DirectPlayMessage-Objekt
ReadLong ReadLong() Liest einen Long von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadLong() As Long object
ein gültiges DirectPlayMessage-Objekt
Anhang A • Methoden
543
ReadShort ReadShort() Liest einen Short von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadShort() As Integer object
ein gültiges DirectPlayMessage-Objekt
ReadSingle ReadSingle() Liest einen Single von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadSingle() As Single object
ein gültiges DirectPlayMessage-Objekt
ReadString ReadString() Liest einen String von der Nachricht und setzt den Lesezeiger auf den nächsten Eintrag. object.ReadString() As String object
ein gültiges DirectPlayMessage-Objekt
ReadSysChatString ReadSysChatString() Liest einen String der DPSYS_CHAT-Nachricht. object.ReadSysChatString() As String object
ein gültiges DirectPlayMessage-Objekt
ReadSysMsgConnection ReadSysMsgConnection() Füllt ein DirectPlayLobbyConnections-Objekt von einer DPSYS_STARTSESSION Nachricht. object.ReadSysMsgConnection() As DirectPlayLobbyConnection object
ein gültiges DirectPlayMessage-Objekt
544
DirectPlay-Methoden
ReadSysMsgData ReadMsgData() Empfängt einen String von der DPSYS_CREATEPLAYERORGROUP- oder DPSYS_ DESTROYPLAYERORGROUP- oder DPSYS_SETPLAYERORGROUPDATANachricht. object.ReadSysMsgData() As String object
ein gültiges DirectPlayMessage-Objekt
ReadSysMsgSessionDesc ReadSysMsgSessionDesc() Füllt ein DirectPlaySessionData-Objekt mit Informationen aus einer DPSYS_SETSESSIONDESC-Systemnachricht. object.ReadSysMsgSessionDesc() As DirectPlaySessionData object
ein gültiges DirectPlayMessage-Objekt
SetMessageData SetMessageData() Schreibt einen selbst definierten Datenblock in das DirectPlayMessage-Objekt. object.SetMessageData(userDefinedType As Any, size As Long) object
ein gültiges DirectPlayMessage-Objekt
user DefinedType
Datenblock
size
Größe des Datenblocks
WriteByte WriteByte() Schreibt ein Byte in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteByte(val As Byte) object
ein gültiges DirectPlayMessage-Objekt
val
Wert
Anhang A • Methoden
545
WriteDouble WriteDouble() Schreibt einen Double in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteDouble(val As Double) object
ein gültiges DirectPlayMessage-Objekt
val
Wert
WriteGuid WriteGuid() Schreibt die Guid in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteGUID(val As String) object
ein gültiges DirectPlayMessage-Objekt
val
Guid
WriteLong WriteLong() Schreibt einen Long in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteLong(val As Long) object
ein gültiges DirectPlayMessage-Objekt
val
Wert
WriteShort WriteShort() Schreibt einen Short in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteShort(val As Integer) object
ein gültiges DirectPlayMessage-Objekt
val
Wert
546
DirectPlay-Methoden
WriteSingle WriteSingle() Schreibt einen Single in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteSingle(val As Single) object
ein gültiges DirectPlayMessage-Objekt
val
Wert
WriteString WriteString() Schreibt eine Zeichenkette in das DirectPlayMessage-Objekt und setzt den Schreibpositonszeiger auf den nächsten Eintrag. object.WriteString(val As String) object
ein gültiges DirectPlayMessage-Objekt
val
Zeichenkette
Clear Clear() Löscht alle Daten aus dem DirectPlayMessage-Objekt. object.Clear() object
ein gültiges DirectPlayMessage-Objekt
GetMessageSize GetMessageSize() Ermittelt die Größe einer Nachricht. object.GetMessageSize() As Long object
A.6.9
ein gültiges DirectPlayMessage-Objekt
DirectPlaySessionData Die Methoden der DiretPlaySessionData-Klasse enthalten beschreibende Daten, welche mit einer Session verbunden sind.
Anhang A • Methoden
547
Das DirectPlaySessionData Objekt wird mit der DirectPlay4.CreateSessionData()-Methode erzeugt und wird an die DirectPlay4.Open()- sowie Direct Play4.SecureOpen()-Methode übergeben. Folgende Methoden gehören zu der DirectPlayMessage-Klasse: Daten ermitteln
GetCurrentPlayers GetFlags GetGuidApplication GetGuidInstance GetMaxPlayers GetSessionName GetSessionPassword GetUser1 GetUser2 GetUser3 GetUser4
Daten setzen
SetFlags SetGuidApplication SetGuidInstance SetMaxPlayers SetSessionName SetSessionPassword SetUser1 SetUser2 SetUser3 SetUser4
GetCurrentPlayers GetCurrentPlayers() Ermittelt die Anzahl der Spieler in der aktuellen Session. object.GetCurrentPlayers() As Long object
ein gültiges DirectPlaySessionData-Objekt
GetFlags GetFlags() Ermittelt die Flags (Kennzeichnungen) der aktuellen Session. object.GetFlags() As Long object
ein gültiges DirectPlaySessionData-Objekt
548
DirectPlay-Methoden
GetGuidApplication GetGuidApplication() Ermitttelt die Guid der Anwendung, welche die Session erzeugt hat. object.GetGuidApplication() As String object
ein gültiges DirectPlaySessionData-Objekt
GetGuidInstance GetGuidInstance() Ermittelt die Guid einer Session. object.GetGuidInstance() As String object
ein gültiges DirectPlaySessionData-Objekt
GetMaxPlayers GetMaxPlayers() Ermittelt die Anzahl der maximal zulässigen Spieler einer Session. object.GetMaxPlayers() As Long object
ein gültiges DirectPlaySessionData-Objekt
GetSessionName GetSessionName() Ermittelt den Namen einer Session. object.GetSessionName() As String object
ein gültiges DirectPlaySessionData-Objekt
GetSessionPassword GetSessionPassword() Ermittelt das Passwort einer Session. object.GetSessionPassword() As String object
ein gültiges DirectPlaySessionData-Objekt
Das Passwort wird benötigt, um sich der Session anzuschließen.
Anhang A • Methoden
549
GetUser1 GetUser1() Ermittelt anwendungsbezogene Daten einer Session. object.GetUser1() As Long object
ein gültiges DirectPlaySessionData-Objekt
GetUser2 GetUser2() Ermittelt anwendungsbezogene Daten einer Session. object.GetUser2() As Long object
ein gültiges DirectPlaySessionData-Objekt
GetUser3 GetUser3() Ermittelt anwendungsbezogene Daten einer Session. object.GetUser3() As Long object
ein gültiges DirectPlaySessionData-Objekt
GetUser4 GetUser4() Ermittelt anwendungsbezogene Daten einer Session. object.GetUser4() As Long object
ein gültiges DirectPlaySessionData-Objekt
SetFlags SetFlags() Setzt die Flags (Kennzeichnungen) einer Session. object.SetFlags(val As CONST_DPSESSIONFLAGS) object
ein gültiges DirectPlaySessionData-Objekt
val
Eine Konstante aus der CONST_DPSESSIONFLAGS-Liste
550
DirectPlay-Methoden
SetGuidApplication SetGuidApplication() Setzt die Guid der Anwendung in die Sessionbeschreibung. object.SetGuidApplication(guid As String) object
ein gültiges DirectPlaySessionData-Objekt
guid
Guid der Anwendung
SetGuidInstance SetGuidInstance() Setzt die Guid der Session. object.SetGuidInstance(guid As String) object
ein gültiges DirectPlaySessionData-Objekt
guid
Guid der Session
SetMaxPlayers SetMaxPlayers() Setzt die Anzahl der maximal zulässigen Spieler einer Session. object.SetMaxPlayers(val As Long) object
ein gültiges DirectPlaySessionData-Objekt
val
Anzahl der maximal zulässigen Spieler.
SetSessionName SetSessionName() Setzt den Session-Namen. object.SetSessionName(val As String) object
ein gültiges DirectPlaySessionData-Objekt
val
Name der Session
SetSessionPassword SetSessionPassword() Setzt das Session-Passwort. object.SetSessionPassword(val As String)
Anhang A • Methoden
551
SetSessionPassword() object
ein gültiges DirectPlaySessionData-Objekt
val
Passwort
SetUser1 SetUser1() Setzt anwendungsbezogene Daten einer Session. object.SetUser1(val As Long) object
ein gültiges DirectPlaySessionData-Objekt
val
Wert
SetUser2 SetUser2() Setzt anwendungsbezogene Daten einer Session. object.SetUser2(val As Long) object
ein gültiges DirectPlaySessionData-Objekt
val
Wert
SetUser3 SetUser3() Setzt anwendungsbezogene Daten einer Session. object.SetUser3(val As Long) object
ein gültiges DirectPlaySessionData-Objekt
val
Wert
SetUser4 SetUser4() Setzt anwendungsbezogene Daten einer Session. object.SetUser4(val As Long) object
ein gültiges DirectPlaySessionData-Objekt
val
Wert
Anhang B Konstanten B.1 B.2 B.3 B.4 B.5
DirectDraw Enum Direct3DEnum DirectSoundEnum DirectInput Enum DirectPlay Enum
554 565 583 588 595
554
DirectDraw Enum
B.1
DirectDraw Enum
B.1.1
CONST_DDBITDEPTHFLAGS Enum CONST_DDBITDEPTHFLAGS DDBD_1 DDBD_16 DDBD_2 DDBD_24 DDBD_32 DDBD_4 DDBD_8 End Enum
B.1.2
= = = = = = =
16384 1024 8192 512 256 4096 2048
= = = = =
2 32 0 1 16
CONST_DDBLTFASTFLAGS Verwendung in: DirectDrawSurface7.BltFast() Enum CONST_DDBLTFASTFLAGS DDBLTFAST_DESTCOLORKEY DDBLTFAST_DONOTWAIT DDBLTFAST_NOCOLORKEY DDBLTFAST_SRCCOLORKEY DDBLTFAST_WAIT End Enum
B.1.3
CONST_DDBLTFLAGS Verwendung in: DirectDrawSurface7.Blt(), DirectDrawSurface7.BltFx() Enum CONST_DDBLTFLAGS DDBLT_ASYNC DDBLT_COLORFILL DDBLT_DDFX DDBLT_DDROPS DDBLT_DEPTHFILL DDBLT_DONOTWAIT DDBLT_KEYDEST DDBLT_KEYDESTOVERRIDE DDBLT_KEYSRC DDBLT_KEYSRCOVERRIDE DDBLT_ROP DDBLT_ROTATIONANGLE DDBLT_WAIT End Enum
= = = = = = = = = = = = =
512 1024 2048 4096 33554432 134217728 8192 16384 32768 65536 131072 262144 16777216
Anhang B • Konstanten
B.1.4
555
CONST_DDBLTFXFLAGS Verwendung in: DDBLTFX – lDDFX Enum CONST_DDBLTFXFLAGS DDBLTFX_ARITHSTRETCHY DDBLTFX_MIRRORLEFTRIGHT DDBLTFX_MIRRORUPDOWN DDBLTFX_NOTEARING DDBLTFX_ROTATE180 DDBLTFX_ROTATE270 DDBLTFX_ROTATE90 DDBLTFX_ZBUFFERBASEDEST DDBLTFX_ZBUFFERRANGE End Enum
B.1.5
= = = = = = = = =
1 2 4 8 16 32 64 256 128
CONST_DDCAPS1FLAGS Verwendung in: DDCAPS – lCaps, lNLVBCaps, lSSBCaps, lSVBCaps, IVSBCaps Enum CONST_DDCAPS1FLAGS DDCAPS_3D DDCAPS_ALIGNBOUNDARYDEST DDCAPS_ALIGNBOUNDARYSRC DDCAPS_ALIGNSIZEDEST DDCAPS_ALIGNSIZESRC DDCAPS_ALIGNSTRIDE DDCAPS_ALPHA DDCAPS_BANKSWITCHED DDCAPS_BLT DDCAPS_BLTCOLORFILL DDCAPS_BLTDEPTHFILL DDCAPS_BLTFOURCC DDCAPS_BLTQUEUE DDCAPS_BLTSTRETCH DDCAPS_CANBLTSYSMEM DDCAPS_CANCLIP DDCAPS_CANCLIPSTRETCHED DDCAPS_COLORKEY DDCAPS_COLORKEYHWASSIST DDCAPS_GDI DDCAPS_NOHARDWARE DDCAPS_OVERLAY DDCAPS_OVERLAYCANTCLIP DDCAPS_OVERLAYFOURCC DDCAPS_OVERLAYSTRETCH DDCAPS_PALETTE
= = = = = = = = = = = = = = = = = = = = = = = = = =
1 2 8 4 16 32 8388608 134217728 64 67108864 268435456 256 128 512 -2147483648 536870912 1073741824 4194304 16777216 1024 33554432 2048 4096 8192 16384 32768
556
DirectDraw Enum
DDCAPS_PALETTEVSYNC DDCAPS_READSCANLINE DDCAPS_VBI DDCAPS_ZBLTS DDCAPS_ZOVERLAYS End Enum
B.1.6
65536 131072 524288 1048576 2097152
= = = = = = = = = = = = = = = = = = = = = = =
8 16384 16 32 1048576 256 8192 8388608 524288 1 64 128 32768 2097152 4194304 2 512 1024 2048 131072 33554432 4 4096
= = = = = = = =
1 2 4 8 16 32 64 128
CONST_DDCAPS2FLAGS Enum CONST_DDCAPS2FLAGS DDCAPS2_AUTOFLIPOVERLAY DDCAPS2_CANBOBHARDWARE DDCAPS2_CANBOBINTERLEAVED DDCAPS2_CANBOBNONINTERLEAVED DDCAPS2_CANCALIBRATEGAMMA DDCAPS2_CANDROPZ16BIT DDCAPS2_CANFLIPODDEVEN DDCAPS2_CANMANAGETEXTURE DDCAPS2_CANRENDERWINDOWED DDCAPS2_CERTIFIED DDCAPS2_COLORCONTROLOVERLAY DDCAPS2_COLORCONTROLPRIMARY DDCAPS2_COPYFOURCC DDCAPS2_FLIPINTERVAL DDCAPS2_FLIPNOVSYNC DDCAPS2_NO2DDURING3DSCENE DDCAPS2_NONLOCALVIDMEM DDCAPS2_NONLOCALVIDMEMCAPS DDCAPS2_NOPAGELOCKREQUIRED DDCAPS2_PRIMARYGAMMA DDCAPS2_STEREO DDCAPS2_VIDEOPORT DDCAPS2_WIDESURFACES End Enum
B.1.7
= = = = =
CONST_DDCKEYCAPSFLAGS Enum CONST_DDCKEYCAPSFLAGS DDCKEYCAPS_DESTBLT DDCKEYCAPS_DESTBLTCLRSPACE DDCKEYCAPS_DESTBLTCLRSPACEYUV DDCKEYCAPS_DESTBLTYUV DDCKEYCAPS_DESTOVERLAY DDCKEYCAPS_DESTOVERLAYCLRSPACE DDCKEYCAPS_DESTOVERLAYCLRSPACEYUV DDCKEYCAPS_DESTOVERLAYONEACTIVE
Anhang B • Konstanten
DDCKEYCAPS_DESTOVERLAYYUV DDCKEYCAPS_SRCBLT DDCKEYCAPS_SRCBLTCLRSPACE DDCKEYCAPS_SRCBLTCLRSPACEYUV DDCKEYCAPS_SRCBLTYUV DDCKEYCAPS_SRCOVERLAY DDCKEYCAPS_SRCOVERLAYCLRSPACE DDCKEYCAPS_SRCOVERLAYCLRSPACEYUV DDCKEYCAPS_SRCOVERLAYONEACTIVE DDCKEYCAPS_SRCOVERLAYYUV End Enum
B.1.8
= = = = = = = = = =
262144 512 1024 2048 4096 8192 16384 32768 65536 131072
= = = = =
1 2 4 8 16
= = = = = = =
1 64 2 32 4 8 16
CONST_DDCKEYFLAGS Enum CONST_DDCKEYFLAGS DDCKEY_COLORSPACE DDCKEY_DESTBLT DDCKEY_DESTOVERLAY DDCKEY_SRCBLT DDCKEY_SRCOVERLAY End Enum
B.1.9
557
CONST_DDCOLORFLAGS Enum CONST_DDCOLORFLAGS DDCOLOR_BRIGHTNESS DDCOLOR_COLORENABLE DDCOLOR_CONTRAST DDCOLOR_GAMMA DDCOLOR_HUE DDCOLOR_SATURATION DDCOLOR_SHARPNESS End Enum
B.1.10 CONST_DDDEVICEIDFLAGS Verwendung in: DirectDraw7.GetDeviceIdentifier() Enum CONST_DDDEVICEIDFLAGS DDGDI_DEFAULT DDGDI_GETHOSTIDENTIFIER End Enum
= 0 = 1
B.1.11 CONST_DDEDMFLAGS Verwendung in: DirectDraw7.GetDisplayModesEnum()
558
DirectDraw Enum
Enum CONST_DDEDMFLAGS DDEDM_DEFAULT DDEDM_REFRESHRATES DDEDM_STANDARDVGAMODES End Enum
= 0 = 1 = 2
B.1.12 CONST_DDENUMOVERLAYZFLAGS Verwendung in: DirectDrawSurface7.GetOverlayZOrdersEnum() Enum CONST_DDENUMSURFACESFLAGS DDENUMOVERLAYZ_BACKTOFRONT DDENUMOVERLAYZ_FRONTTOBACK End Enum
= 0 = 1
B.1.13 CONST_DDENUMSURFACESFLAGS Verwendung in: DirectDraw7.GetSurfacesEnum() Enum CONST_DDENUMSURFACESFLAGS DDENUMSURFACES_ALL DDENUMSURFACES_CANBECREATED DDENUMSURFACES_DOESEXIST DDENUMSURFACES_MATCH DDENUMSURFACES_NOMATCH End Enum
= = = = =
1 8 16 2 4
B.1.14 CONST_DDFLIPFLAGS Verwendung in: DirectDrawSurface7.Flip() Enum CONST_DDFLIPFLAGS DDFLIP_DONOTWAIT DDFLIP_EVEN DDFLIP_INTERFVAL2 DDFLIP_INTERFVAL3 DDFLIP_INTERFVAL4 DDFLIP_NOVSYNC DDFLIP_ODD DDFLIP_WAIT DDFLIP_STEREO End Enum
= = = = = = = = =
32 2 536870912 805306368 1073741824 8 4 1 16
B.1.15 ONST_DDFXCAPSFLAGS Verwendung in: DDCAPS – lFXCaps, lNLVBFXCaps, lSSBFXCaps, lSVBFXCaps, lVSBFXCaps
Anhang B • Konstanten
Enum CONST_DDFXCAPSFLAGS DDFXCAPS_BLTALPHA DDFXCAPS_BLTARITHSTRETCHY DDFXCAPS_BLTARITHSTRETCHYN DDFXCAPS_BLTFILTER DDFXCAPS_BLTMIRRORLEFTRIGHT DDFXCAPS_BLTMIRRORUPDOWN DDFXCAPS_BLTROTATION DDFXCAPS_BLTROTATION90 DDFXCAPS_BLTSHRINKX DDFXCAPS_BLTSHRINKXN DDFXCAPS_BLTSHRINKY DDFXCAPS_BLTSHRINKYN DDFXCAPS_BLTSTRETCHX DDFXCAPS_BLTSTRETCHXN DDFXCAPS_BLTSTRETCHY DDFXCAPS_BLTSTRETCHYN DDFXCAPS_BLTTRANSFORM DDFXCAPS_OVERLAYALPHA DDFXCAPS_OVERLAYARITHSTRETCHY DDFXCAPS_OVERLAYARITHSTRETCHYN DDFXCAPS_OVERLAYFILTER DDFXCAPS_OVERLAYMIRRORLEFTRIGHT DDFXCAPS_OVERLAYMIRRORUPDOWN DDFXCAPS_OVERLAYSHRINKX DDFXCAPS_OVERLAYSHRINKXN DDFXCAPS_OVERLAYSHRINKY DDFXCAPS_OVERLAYSHRINKYN DDFXCAPS_OVERLAYSTRETCHX DDFXCAPS_OVERLAYSTRETCHXN DDFXCAPS_OVERLAYSTRETCHY DDFXCAPS_OVERLAYSTRETCHYN DDFXCAPS_OVERLAYTRANSFORM End Enum
559
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
1 32 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 2 4 262144 8 262144 134217728 268435456 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 536870912
B.1.16 CONST_DDGBSFLAGS Verwendung in: DirectDrawSurface7.GetBltStatus() Enum CONST_DDGBSFLAGS DDGBS_CANBLT DDGBS_ISBLTDONE End Enum
= 1 = 2
B.1.17 CONST_DDGFSFLAGS Verwendung in: DirectDrawSurface7.GetFlipStatus()
560
DirectDraw Enum
Enum CONST_DDGFSFLAGS DDGFS_CANFLIP DDGFS_ISFLIPDONE End Enum
= 1 = 2
B.1.18 CONST_DDLOCKFLAGS Verwendung in: DirectDrawSurface7.Lock(), Direct3DVertexBuffer7.Lock() Enum CONST_DDLOCKFLAGS DDLOCK_DONOTWAIT DDLOCK_EVENT DDLOCK_NOSYSLOCK DDLOCK_READONLY DDLOCK_SURFACEMEMORYPTR DDLOCK_WAIT DDLOCK_WRITEONLY End Enum
= = = = = = =
16384 2 2048 16 0 1 32
B.1.19 CONST_DDOVERFLAGS Verwendung in: DirectDrawSurface7.UpdateOverlay() Enum CONST_DDOVERFLAGS DDOVER_ADDDIRTYRECT DDOVER_ALPHADEST DDOVER_ALPHADESTCONSTOVERRIDE DDOVER_ALPHADESTNEG DDOVER_ALPHADESTSURFACEOVERRIDE DDOVER_ALPHAEDGEBLEND DDOVER_ALPHASRC DDOVER_ALPHASRCCONSTOVERRIDE DDOVER_ALPHASRCNEG DDOVER_ALPHASRCSURFACEOVERRIDE DDOVER_ARGBSCALEFACTORS DDOVER_AUTOFLIP DDOVER_BOB DDOVER_DDFX DDOVER_DEGRADEARGBSCALING DDOVER_HIDE DDOVER_INTERLEAVED DDOVER_KEYDEST DDOVER_KEYDESTOVERRIDE DDOVER_KEYSRC DDOVER_KEYSRCOVERRIDE DDOVER_OVERRIDEBOBWEAVE DDOVER_REFRESHALL DDOVER_REFRESHDIRTYRECTS
= = = = = = = = = = = = = = = = = = = = = = = =
32768 1 2 4 8 16 32 64 128 256 33554432 1048576 2097152 524288 67108864 512 8388608 1024 2048 4096 8192 4194304 131072 65536
Anhang B • Konstanten
DDOVER_SHOW End Enum
561
= 16384
B.1.20 CONST_DDOVERFXFLAGS Verwendung in: DDOVERLAYFX Enum CONST_DDPALFLAGS DDOVERFX_ARITHSTRETCHY DDOVERFX_MIRRORLEFTRIGHT DDOVERFX_MIRRORUPDOWN End Enum
= 1 = 2 = 4
B.1.21 CONST_DDOVERZFLAGS Verwendung in: DirectDrawSurface7.UpdateOverlayZOrder() Enum CONST_DDPALFLAGS DDOVERZ_INSERTINBACKOF DDOVERZ_INSERTINFRONTOF DDOVERZ_MOVEBACKWARD DDOVERZ_MOVEFORWARD DDOVERZ_SENDTOBACK DDOVERZ_SENDTOFRONT End Enum
= = = = = =
5 4 3 2 1 0
= = = =
0 2 4 1
B.1.22 CONST_DDPALFLAGS Verwendung in: PALETTEENTRY Enum CONST_DDPALFLAGS PC_DEFAULT PC_EXPLICIT PC_NOCOLLAPSE PC_RESERVED End Enum
B.1.23 CONST_DDPCAPSFLAGS Verwendung in: DirectDraw7.CreatePalette(), DirectDrawPalette.GetCaps(), DCAPS – lPalCaps Enum CONST_DDPCAPSFLAGS DDPCAPS_1BIT DDPCAPS_2BIT DDPCAPS_4BIT DDPCAPS_8BIT
= = = =
256 512 1 4
562
DirectDraw Enum
DDPCAPS_8BITENTRIES DDPCAPS_ALLOW256 DDPCAPS_ALPHA DDPCAPS_INITIALIZE DDPCAPS_PRIMARYSURFACE DDPCAPS_PRIMARYSURFACELEFT DDPCAPS_VSYNC End Enum
= = = = = = =
2 64 1024 8 16 32 128
= = = = = = = = = = = = = = = = = = =
2 1 32768 524288 262144 128 4 131072 2048 4096 8 32 16 64 256 16384 512 1024 8192
B.1.24 CONST_DDPIXELFORMATFLAGS Verwendung in: DDPIXELFORMAT Enum CONST_DDPIXELFORMATFLAGS DDPF_ALPHA DDPF_ALPHAPIXELS DDPF_ALPHAPREMULT DDPF_BUMPDUDV DDPF_BUMPLUMINANCE DDPF_COMPRESSED DDPF_FOURCC DDPF_LUMINANCE DDPF_PALETTEINDEXED1 DDPF_PALETTEINDEXED2 DDPF_PALETTEINDEXED4 DDPF_PALETTEINDEXED8 DDPF_PALETTEINDEXEDTO8 DDPF_RGB DDPF_RGBTOYUV DDPF_STENCILBUFFER DDPF_YUV DDPF_ZBUFFER DDPF_ZPIXELS End Enum
B.1.25 CONST_DDRAW Enum CONST_DDRAW DD_ROP_SPACE End Enum
= 8
B.1.26 CONST_DDSCLFLAGS Verwendung in: DirectDraw7.SetCooperativeLevel() Enum CONST_DDSCLFLAGS
Anhang B • Konstanten
DDSCL_ALLOWMODEX DDSCL_ALLOWREBOOT DDSCL_CREATEDEVICEWINDOW DDSCL_EXCLUSIVE DDSCL_FULLSCREEN DDSCL_MULTITHREADED DDSCL_NORMAL DDSCL_NOWINDOWCHANGES DDSCL_SETDEVICEWINDOW DDSCL_SETFOCUSWINDOW End Enum
563
= = = = = = = = = =
64 2 512 16 1 1024 8 4 256 128
B.1.27 CONST_DDSDMFLAGS Verwendung in: DirectDraw7.SetDisplayMode() Enum CONST_DDSDMFLAGS DDSDM_DEFAULT DDSDM_STANDARDVGAMODE End Enum
= 0 = 1
B.1.28 CONST_DDSGRFLAGS Verwendung in: DirectDrawGammaControl.SetGammaRamp() Enum CONST_DDSGRFLAGS DDSGR_CALIBRATE DDSGR_DEFAULT End Enum
= 1 = 0
B.1.29 CONST_DDSTEREOCAPSFLAGS Verwendung in: DDCAPS – lSVCaps Enum CONST_DDSTEREOCAPSFLAGS DDSVCAPS_ENIGMA DDSVCAPS_FLICKER DDSVCAPS_REDBLUE DDSVCAPS_SPLIT DDSVCAPS_STEREOSEQUENTIAL End Enum
= = = = =
1 2 4 8 16
B.1.30 CONST_DDSURFACECAPS2FLAGS Verwendung in: DDSCAPS2 – lCaps2 Enum CONST_DDSURFACECAPS2FLAGS DDSCAPS2_CUBEMAP
= 512
564
DirectDraw Enum
DDSCAPS2_CUBEMAP_ALLFACES DDSCAPS2_CUBEMAP_NEGATIVEX DDSCAPS2_CUBEMAP_NEGATIVEY DDSCAPS2_CUBEMAP_NEGATIVEZ DDSCAPS2_CUBEMAP_POSITIVEX DDSCAPS2_CUBEMAP_POSITIVEY DDSCAPS2_CUBEMAP_POSITIVEZ DDSCAPS2_D3DTEXTUREMANAGE DDSCAPS2_HARDWAREDEINTERLACE DDSCAPS2_HINTANTIALIASING DDSCAPS2_HINTDYNAMIC DDSCAPS2_HINTSTATIC DDSCAPS2_MIPMAPSUBLEVEL DDSCAPS2_OPAQUE DDSCAPS2_STEREOSURFACELEFT DDSCAPS2_TEXTUREMANAGE End Enum
= = = = = = = = = = = = = = = =
65024 2048 8192 32768 1024 4096 16384 131072 2 256 4 8 65536 128 524288 16
= = = = = = = = = = = = = = = = = = = = = = = =
8192 67108864 2 4 8 16 32 1048576 524288 268435456 4194304 2097152 536870912 64 -2147483648 128 262144 256 512 8388608 1073741824 2048 4096 16384
B.1.31 CONST_DDSURFACECAPSFLAGS Verwendung in: DDSCAPS2 – lCaps Enum CONST_DDSURFACECAPSFLAGS DDSCAPS_3DDEVICE DDSCAPS_ALLOCONLOAD DDSCAPS_ALPHA DDSCAPS_BACKBUFFER DDSCAPS_COMPLEX DDSCAPS_FLIP DDSCAPS_FRONTBUFFER DDSCAPS_HWCODEC DDSCAPS_LIVEVIDEO DDSCAPS_LOCALVIDMEM DDSCAPS_MIPMAP DDSCAPS_MODEX DDSCAPS_NONLOCALVIDMEM DDSCAPS_OFFSCREENPLAIN DDSCAPS_OPTIMIZED DDSCAPS_OVERLAY DDSCAPS_OWNDC DDSCAPS_PALETTE DDSCAPS_PRIMARYSURFACE DDSCAPS_RESERVED2 DDSCAPS_STANDARDVGAMODE DDSCAPS_SYSTEMMEMORY DDSCAPS_TEXTURE DDSCAPS_VIDEOMEMORY
Anhang B • Konstanten
DDSCAPS_VIDEOPORT DDSCAPS_VISIBLE DDSCAPS_WRITEONLY DDSCAPS_ZBUFFER End Enum
565
= = = =
134217728 32768 65536 131072
= = = = = = = = = = = = = = = = = =
1047022 128 32 1 16384 8192 65536 32768 2 524288 2048 131072 8 4096 262144 1048576 4 64
B.1.32 CONST_DDSURFACEDESCFLAGS Verwendung in: DDSURFACEDESC2 – lFlags DDSD_ALL DDSD_ALPHABITDEPTH DDSD_BACKBUFFERCOUNT DDSD_CAPS DDSD_CKDESTBLT DDSD_CKDESTOVERLAY DDSD_CKSRCBLT DDSD_CKSRCOVERLAY DDSD_HEIGHT DDSD_LINEARSIZE DDSD_LPSURFACE DDSD_MIPMAPCOUNT DDSD_PITCH DDSD_PIXELFORMAT DDSD_REFRESHRATE DDSD_TEXTURESTAGE DDSD_WIDTH DDSD_ZBUFFERBITDEPTH End Enum
B.1.33 CONST_DDWAITVBFLAGS Verwendung in: DirectDraw7.WaitForVerticalBlank() Enum CONST_DDWAITVBFLAGS DDWAITVB_BLOCKBEGIN DDWAITVB_BLOCKBEGINEVENT DDWAITVB_BLOCKEND End Enum
B.2
Direct3DEnum
B.2.1
CONST_D3D Enum CONST_D3D D3DDP_MAXTEXCOORD
= 1 = 2 = 4
= 8
566
Direct3DEnum
D3DRENDERSTATE_WRAPBIAS D3DWRAPCOORD_0 D3DWRAPCOORD_1 D3DWRAPCOORD_2 D3DWRAPCOORD_3 End Enum
B.2.2
128 1 2 4 8
CONST_D3DANTIALIASMODE Enum CONST_D3DANTIALIASMODE D3DANTIALIAS_NONE D3DANTIALIAS_SORTDEPENDENT D3DANTIALIAS_SORTINDEPENDENT End Enum
B.2.3
= = = = =
= 0 = 1 = 2
CONST_D3DBLEND Verwendung in: CONST_D3DRENDERSTATETYPE Enum CONST_D3DBLEND D3DBLEND_ZERO D3DBLEND_ONE D3DBLEND_SRCCOLOR D3DBLEND_INVSRCCOLOR D3DBLEND_SRCALPHA D3DBLEND_INVSRCALPHA D3DBLEND_DESTALPHA D3DBLEND_INVDESTALPHA D3DBLEND_DESTCOLOR D3DBLEND_INVDESTCOLOR D3DBLEND_SRCALPHASAT D3DBLEND_BOTHSRCALPHA D3DBLEND_BOTHINVSRCALPHA End Enum
B.2.4
= = = = = = = = = = = = =
1 2 3 4 5 6 7 8 9 10 11 12 13
CONST_D3DCAPSBLEND Verwendung in: D3DPRIMCAPS – lSrcBlendCaps und lDestBlendCaps Enum CONST_D3DCAPSBLEND D3DPBLENDCAPS_BOTHINVSRCALPHA D3DPBLENDCAPS_BOTHSRCALPHA D3DPBLENDCAPS_DESTALPHA D3DPBLENDCAPS_DESTCOLOR D3DPBLENDCAPS_INVDESTALPHA D3DPBLENDCAPS_INVDESTCOLOR D3DPBLENDCAPS_INVSRCALPHA
= = = = = = =
4096 2048 64 256 128 512 32
Anhang B • Konstanten
D3DPBLENDCAPS_INVSRCCOLOR D3DPBLENDCAPS_ONE D3DPBLENDCAPS_SRCALPHA D3DPBLENDCAPS_SRCALPHASAT D3DPBLENDCAPS_SRCCOLOR D3DPBLENDCAPS_ZERO End Enum
B.2.5
567
= = = = = =
8 2 16 1024 4 1
CONST_D3DCAPSCMP Verwendung in: D3DPRIMCAPS – lZCmpCaps und lAlphaCmpCaps Enum CONST_D3DCAPSCMP D3DPCMPCAPS_ALWAYS D3DPCMPCAPS_EQUAL D3DPCMPCAPS_GREATER D3DPCMPCAPS_GREATEREQUAL D3DPCMPCAPS_LESS D3DPCMPCAPS_LESSEQUAL D3DPCMPCAPS_NEVER D3DPCMPCAPS_NOTEQUAL End Enum
B.2.6
= = = = = = = =
128 4 16 64 2 8 1 32
= = = = = = =
8 64 32 16 4 1 2
= = = = = =
131072 4096 1024 1 65536 256
CONST_D3DCAPSMISC Verwendung in: D3DPRIMCAPS – lMiscCaps Enum CONST_D3DCAPSMISC D3DPMISCCAPS_CONFORMANT D3DPMISCCAPS_CULLCCW D3DPMISCCAPS_CULLCW D3DPMISCCAPS_CULLNONE D3DPMISCCAPS_LINEPATTERNREP D3DPMISCCAPS_MASKPLANES D3DPMISCCAPS_MASKZ End Enum
B.2.7
CONST_D3DCAPSRASTER Verwendung in: D3DPRIMCAPS – lRasterCaps Enum CONST_D3DCAPSRASTER D3DPRASTERCAPS_ANISOTROPY D3DPRASTERCAPS_ANTIALIASEDGES D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT D3DPRASTERCAPS_DITHER D3DPRASTERCAPS_FOGRANGE D3DPRASTERCAPS_FOGTABLE
568
Direct3DEnum
D3DPRASTERCAPS_FOGVERTEX D3DPRASTERCAPS_MIPMAPLODBIAS D3DPRASTERCAPS_PAT D3DPRASTERCAPS_ROP2 D3DPRASTERCAPS_STIPPLE D3DPRASTERCAPS_SUBPIXEL D3DPRASTERCAPS_SUBPIXELX D3DPRASTERCAPS_XOR D3DPRASTERCAPS_ZBIAS D3DPRASTERCAPS_ZBUFFERLESSHSR D3DPRASTERCAPS_ZTEST End Enum
B.2.8
= = = = = = = = = = =
128 8192 8 2 512 32 64 4 16384 32768 16
= = = = = = = = = = = = = = = = = = = = =
4096 8192 16384 32768 65536 131072 1 2 4 8 16 32 262144 524288 1048576 64 128 256 512 1024 2048
CONST_D3DCAPSSHADE Verwendung in: D3DPRIMCAPS – lShadeCaps Enum CONST_D3DCAPSSHADE D3DPSHADECAPS_ALPHAFLATBLEND D3DPSHADECAPS_ALPHAFLATSTIPPLED D3DPSHADECAPS_ALPHAGOURAUDBLEND D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED D3DPSHADECAPS_ALPHAPHONGBLEND D3DPSHADECAPS_ALPHAPHONGSTIPPLED D3DPSHADECAPS_COLORFLATMONO D3DPSHADECAPS_COLORFLATRGB D3DPSHADECAPS_COLORGOURAUDMONO D3DPSHADECAPS_COLORGOURAUDRGB D3DPSHADECAPS_COLORPHONGMONO D3DPSHADECAPS_COLORPHONGRGB D3DPSHADECAPS_FOGFLAT D3DPSHADECAPS_FOGGOURAUD D3DPSHADECAPS_FOGPHONG D3DPSHADECAPS_SPECULARFLATMONO D3DPSHADECAPS_SPECULARFLATRGB D3DPSHADECAPS_SPECULARGOURAUDMONO D3DPSHADECAPS_SPECULARGOURAUDRGB D3DPSHADECAPS_SPECULARPHONGMONO D3DPSHADECAPS_SPECULARPHONGRGB End Enum
B.2.9
CONST_D3DCAPSTEXTURE Verwendung in: D3DPRIMCAPS – lTextureCaps Enum CONST_D3DCAPSTEXTURE D3DPTEXTURECAPS_ALPHA D3DPTEXTURECAPS_BORDER
= 4 = 16
Anhang B • Konstanten
D3DPTEXTURECAPS_COLORKEYBLEND D3DPTEXTURECAPS_CUBEMAP D3DPTEXTURECAPS_NONPOW2CONDITIONAL D3DPTEXTURECAPS_PERSPECTIVE D3DPTEXTURECAPS_POW2 D3DPTEXTURECAPS_SQUAREONLY D3DPTEXTURECAPS_TRANSPARENCY End Enum
569
= = = = = = =
4096 1024 256 1 2 32 8
B.2.10 CONST_D3DCAPSTEXTUREADDRESS Verwendung in: D3DPRIMCAPS – lTextureAddressCaps Enum CONST_D3DCAPSTEXTUREADDRESS D3DPTADDRESSCAPS_BORDER D3DPTADDRESSCAPS_CLAMP D3DPTADDRESSCAPS_INDEPENDENTUV D3DPTADDRESSCAPS_MIRROR D3DPTADDRESSCAPS_WRAP End Enum
= = = = =
8 4 16 2 1
B.2.11 CONST_D3DCAPSTEXTUREFILTER Verwendung in: D3DPRIMCAPS – lTextureFilterCaps Enum CONST_D3DCAPSTEXTUREFILTER D3DPTFILTERCAPS_LINEAR D3DPTFILTERCAPS_LINEARMIPLINEAR D3DPTFILTERCAPS_LINEARMIPNEAREST D3DPTFILTERCAPS_MAGFAFLATCUBIC D3DPTFILTERCAPS_MAGFANISOTROPIC D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC D3DPTFILTERCAPS_MAGFLINEAR D3DPTFILTERCAPS_MAGFPOINT D3DPTFILTERCAPS_MINFANISOTROPIC D3DPTFILTERCAPS_MINFLINEAR D3DPTFILTERCAPS_MINFPOINT D3DPTFILTERCAPS_MIPFLINEAR D3DPTFILTERCAPS_MIPFPOINT D3DPTFILTERCAPS_MIPLINEAR D3DPTFILTERCAPS_MIPNEAREST D3DPTFILTERCAPS_NEAREST End Enum
B.2.12 CONST_D3DCLEARFLAGS Verwendung in: Direct3DDevice7.Clear()
= = = = = = = = = = = = = = = =
2 32 16 134217728 67108864 268435456 16777216 8388608 1024 512 256 131072 65536 8 4 1
570
Direct3DEnum
Enum CONST_D3DCLEARFLAGS D3DCLEAR_ALL D3DCLEAR_STENCIL D3DCLEAR_TARGET D3DCLEAR_ZBUFFER End Enum
= = = =
7 4 1 2
B.2.13 CONST_D3DCLIPFLAGS Verwendung in: Direct3DDevice7.ComputeSphereVisibility() Enum CONST_D3DCLIPFLAGS D3DSTATUS_CLIPINTERSECTIONALL D3DSTATUS_CLIPUNIONALL D3DSTATUS_DEFAULT D3DSTATUS_ZNOTVISIBLE 'Clip Schnittpunkt Flags D3DSTATUS_CLIPINTERSECTIONBACK D3DSTATUS_CLIPINTERSECTIONBOTTOM D3DSTATUS_CLIPINTERSECTIONFRONT D3DSTATUS_CLIPINTERSECTIONGEN0 D3DSTATUS_CLIPINTERSECTIONGEN5 D3DSTATUS_CLIPINTERSECTIONLEFT D3DSTATUS_CLIPINTERSECTIONRIGHT D3DSTATUS_CLIPINTERSECTIONTOP 'Clip Vereinigung Flags D3DSTATUS_CLIPUNIONBACK D3DSTATUS_CLIPUNIONBOTTOM D3DSTATUS_CLIPUNIONFRONT D3DSTATUS_CLIPUNIONGEN0 D3DSTATUS_CLIPUNIONGEN5 D3DSTATUS_CLIPUNIONLEFT D3DSTATUS_CLIPUNIONRIGHT D3DSTATUS_CLIPUNIONTOP 'Normal Clipping Flags D3DCLIP_BACK D3DCLIP_BOTTOM D3DCLIP_FRONT D3DCLIP_GEN0 D3DCLIP_GEN5 D3DCLIP_LEFT D3DCLIP_RIGHT D3DCLIP_TOP End Enum
= = = =
17891328 17891328 34668544 16777216
= = = = = = = =
131072 32768 65536 262144 8388608 4096 8192 16384
= = = = = = = =
32 8 16 64 2048 1 2 4
= = = = = = = =
32 8 16 64 2048 1 2 4
Anhang B • Konstanten
571
B.2.14 CONST_D3DCLIPPLANEFLAGS Verwendung in: D3DRENDERSTATE_CLIPPLANEENABLE Type CONST_D3DCLIPPLANEFLAGS D3DCPF_DISABLEALL D3DCPF_ENABLEPLANE0 D3DCPF_ENABLEPLANE31 End Type
= 0 = 1 = -2147483648
B.2.15 CONST_D3DCLIPSTATUSFLAGS Verwendung in: D3DCLIPSTATUS Enum CONST_D3DCLIPSTATUSFLAGS D3DCLIPSTATUS_EXTENTS2 D3DCLIPSTATUS_EXTENTS3 D3DCLIPSTATUS_STATUS End Enum
= 2 = 4 = 1
B.2.16 CONST_D3DCMPFUNC Verwendung in: D3DRENDERSTATE_ZFUNC, D3DRENDERSTATE_ALPHAFUNC, D3DRENDERSTATE_STENCILFUNC Enum CONST_D3DCMPFUNC D3DCMP_NEVER D3DCMP_LESS D3DCMP_EQUAL D3DCMP_LESSEQUAL D3DCMP_GREATER D3DCMP_NOTEQUAL D3DCMP_GREATEREQUAL D3DCMP_ALWAYS End Enum
= = = = = = = =
1 2 3 4 5 6 7 8
B.2.17 CONST_D3DCOLORMODEL Verwendung in: D3DDEVICEDESC7 Enum CONST_D3DCOLORMODEL D3DCOLOR_MONO D3DCOLOR_RGB End Enum
= 1 = 2
B.2.18 CONST_D3DCULL Verwendung in: D3DRENDERSTATE_CULLMODE
572
Direct3DEnum
Enum CONST_D3DCULL D3DCULL_NONE D3DCULL_CW D3DCULL_CCW End Enum
= 1 = 2 = 3
B.2.19 CONST_D3DDEVICEDESCCAPS Verwendung in: D3DDEVICEDESC7 – lDevCaps Enum CONST_D3DDEVICEDESCCAPS D3DDEVCAPS_CANBLTSYSTONONLOCAL D3DDEVCAPS_CANRENDERAFTERFLIP D3DDEVCAPS_DRAWPRIMTLVERTEX D3DDEVCAPS_FLOATTLVERTEX D3DDEVCAPS_HWRASTERIZATION D3DDEVCAPS_HWTRANSFORMANDLIGHT D3DDEVCAPS_SEPARATETEXTUREMEMORIES D3DDEVCAPS_SORTDECREASINGZ D3DDEVCAPS_SORTEXACT D3DDEVCAPS_SORTINCREASINGZ D3DDEVCAPS_TEXTURENONLOCALVIDMEM D3DDEVCAPS_TEXTURESYSTEMMEMORY D3DDEVCAPS_TEXTUREVIDEOMEMORY D3DDEVCAPS_TLVERTEXSYSTEMMEMORY D3DDEVCAPS_TLVERTEXVIDEOMEMORY End Enum
= = = = = = = = = = = = = = =
131072 2048 1024 1 524288 65536 16384 4 8 2 4096 256 512 64 128
= = = = = = = = = =
16 2 128 256 8 32 512 1024 4 64
B.2.20 CONST_D3DDEVICEDESCFLAGS Verwendung in: D3DDEVICEDESC7 – lFlags Enum CONST_D3DDEVICEDESCFLAGS D3DDD_BCLIPPING D3DDD_DEVCAPS D3DDD_DEVICERENDERBITDEPTH D3DDD_DEVICEZBUFFERBITDEPTH D3DDD_LIGHTINGCAPS D3DDD_LINECAPS D3DDD_MAXBUFFERSIZE D3DDD_MAXVERTEXCOUNT D3DDD_TRANSFORMCAPS D3DDD_TRICAPS End Enum
Anhang B • Konstanten
573
B.2.21 CONST_D3DDEVINFOID Verwendung in: Direct3DDevice7.GetInfo() Enum CONST_D3DDEVINFOID D3DDEVINFOID_D3DTEXTUREMANAGER D3DDEVINFOID_TEXTUREMANAGER D3DDEVINFOID_TEXTURING End Enum
= 2 = 1 = 3
B.2.22 CONST_D3DDPFLAGS Verwendung in: Direct3DDevice7.DrawPrimitive(), Direct3DDevice7.DrawIndexedPrimitive(), Direct3DDevice7.DrawPrimitiveVB(), Direct3DDevice7.DrawIndexedPrimitiveVB() Enum CONST_D3DDPFLAGS D3DDP_DEFAULT D3DDP_WAIT End Enum
= 0 = 1
B.2.23 CONST_D3DFILLMODE Verwendung in: D3DRENDERSTATE_FILLMODE Enum CONST_D3DFILLMODE D3DFILL_POINT D3DFILL_WIREFRAME D3DFILL_SOLID End Enum
= 1 = 2 = 3
B.2.24 CONST_D3DFOGMODE Verwendung in: D3DRENDERSTATE_FOGTABLEMODE, D3DRENDERSTATE_FOGVERTEXMODE Enum CONST_D3DFOGMODE D3DFOG_NONE D3DFOG_EXP D3DFOG_EXP2 D3DFOG_LINEAR End Enum
= = = =
B.2.25 CONST_D3DFVFCAPSFLAGS Verwendung in: D3DDEVICEDESC7 – lFVFCaps Enum CONST_D3DFVFCAPSFLAGS
0 1 2 3
574
Direct3DEnum
D3DFVFCAPS_DONOTSTRIPELEMENTS D3DFVFCAPS_TEXCOORDCOUNTMASK End Enum
= 524288 = 65535
B.2.26 CONST_D3DLIGHTCAPSFLAGS Verwendung in: D3DLIGHTINGCAPS – lCaps Enum CONST_D3DLIGHTCAPSFLAGS D3DLIGHTCAPS_DIRECTIONAL D3DLIGHTCAPS_POINT D3DLIGHTCAPS_SPOT End Enum
= 4 = 1 = 2
B.2.27 CONST_D3DLIGHTINGMODELFLAGS Verwendung in: D3DLIGHTINGCAPS – lLightingModel Enum CONST_D3DLIGHTINGMODELFLAGS D3DLIGHTINGMODEL_MONO D3DLIGHTINGMODEL_RGB End Enum
= 2 = 1
B.2.28 CONST_D3DLIGHTTYPE Verwendung in: D3DLIGHT7 – lType Enum CONST_D3DLIGHTTYPE D3DLIGHT_DIRECTIONAL D3DLIGHT_POINT D3DLIGHT_SPOT End Enum
= 3 = 1 = 2
B.2.29 CONST_D3DMATERIALCOLORSOURCE Enum CONST_D3DMATERIALCOLORSOURCE D3DMCS_MATERIAL D3DMCS_COLOR1 D3DMCS_COLOR2 End Enum
= 0 = 1 = 2
B.2.30 CONST_D3DPRIMITIVETYPE Verwendung in: DrawPrimitive Enum CONST_D3DPRIMITIVETYPE D3DPT_POINTLIST
= 1
Anhang B • Konstanten
D3DPT_LINELIST D3DPT_LINESTRIP D3DPT_TRIANGLELIST D3DPT_TRIANGLESTRIP D3DPT_TRIANGLEFAN End Enum
575
= = = = =
2 3 4 5 6
B.2.31 CONST_D3DPROCESSVERTICESFLAGS Verwendung in: Direct3DVertexBuffer7 Enum CONST_D3DPROCESSVERTICESFLAGS D3DPV_DEFAULT D3DPV_DONOTCOPYDATA End Enum
= 0 = 1
B.2.32 CONST_D3DRENDERSTATESINGLE Verwendung in: Direct3DDevice7.SetRenderStateSingle(), Direct3DDevice7.GetRenderStateSingle() Enum CONST_D3DRENDERSTATESINGLE D3DRENDERSTATE_FOGDENSITY D3DRENDERSTATE_FOGEND D3DRENDERSTATE_FOGSTART End Enum
= 38 = 37 = 36
B.2.33 CONST_D3DRENDERSTATETYPE Verwendung in: Direct3DDevice7.SetRenderState(), Direct3DDevice7.GetRenderState() Enum CONST_D3DRENDERSTATETYPE D3DRENDERSTATE_ALPHABLENDENABLE D3DRENDERSTATE_ALPHAFUNC D3DRENDERSTATE_ALPHAREF D3DRENDERSTATE_ALPHATESTENABLE D3DRENDERSTATE_AMBIENT D3DRENDERSTATE_AMBIENTMATERIALSOURCE D3DRENDERSTATE_ANTIALIAS D3DRENDERSTATE_CLIPPING D3DRENDERSTATE_CLIPPLANEENABLE D3DRENDERSTATE_COLORKEYBLENDENABLE D3DRENDERSTATE_COLORKEYENABLE D3DRENDERSTATE_COLORVERTEX D3DRENDERSTATE_CULLMODE D3DRENDERSTATE_DESTBLEND D3DRENDERSTATE_DIFFUSEMATERIALSOURCE
= = = = = = = = = = = = = = =
27 25 24 15 139 147 2 136 152 144 41 141 22 20 145
576
Direct3DEnum
D3DRENDERSTATE_DITHERENABLE D3DRENDERSTATE_EDGEANTIALIAS D3DRENDERSTATE_EMISSIVEMATERIALSOURCE D3DRENDERSTATE_EXTENTS D3DRENDERSTATE_FILLMODE D3DRENDERSTATE_FOGCOLOR D3DRENDERSTATE_FOGENABLE D3DRENDERSTATE_FOGTABLEMODE D3DRENDERSTATE_FOGVERTEXMODE D3DRENDERSTATE_LASTPIXEL D3DRENDERSTATE_LIGHTING D3DRENDERSTATE_LINEPATTERN D3DRENDERSTATE_LOCALVIEWER D3DRENDERSTATE_NORMALIZENORMALS D3DRENDERSTATE_RANGEFOGENABLE D3DRENDERSTATE_SHADEMODE D3DRENDERSTATE_SPECULARENABLE D3DRENDERSTATE_SPECULARMATERIALSOURCE D3DRENDERSTATE_SRCBLEND D3DRENDERSTATE_STENCILENABLE D3DRENDERSTATE_STENCILFAIL D3DRENDERSTATE_STENCILFUNC D3DRENDERSTATE_STENCILMASK D3DRENDERSTATE_STENCILPASS D3DRENDERSTATE_STENCILREF D3DRENDERSTATE_STENCILWRITEMASK D3DRENDERSTATE_STENCILZFAIL D3DRENDERSTATE_STIPPLEDALPHA D3DRENDERSTATE_TEXTUREFACTOR D3DRENDERSTATE_TEXTUREPERSPECTIVE D3DRENDERSTATE_VERTEXBLEND D3DRENDERSTATE_WRAP0 D3DRENDERSTATE_WRAP7 D3DRENDERSTATE_ZBIAS D3DRENDERSTATE_ZENABLE D3DRENDERSTATE_ZFUNC D3DRENDERSTATE_ZVISIBLE D3DRENDERSTATE_ZWRITEENABLE
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
26 40 148 138 8 34 28 35 140 16 137 10 142 143 48 9 29 146 19 52 53 56 58 55 57 59 54 33 60 4 151 128 135 47 7 23 30 14 End Type
B.2.34 CONST_D3DSHADEMODE Verwendung in: D3DRENDERSTATE_SHADEMODE Enum CONST_D3DSHADEMODE D3DSHADE_FLAT D3DSHADE_GOURAUD D3DSHADE_PHONG
= 1 = 2 = 3
Anhang B • Konstanten
577
End Enum
B.2.35 CONST_D3DSTATEBLOCKTYPE Verwendung in: Direct3DDevice7.CreateStateBlock() Type D3DSTATEBLOCKTYPE D3DSBT_ALL D3DSBT_PIXELSTATE D3DSBT_VERTEXSTATE End Type
= 1 = 2 = 3
B.2.36 CONST_D3DSTENCILCAPSFLAGS Verwendung in: D3DDEVICEDESC7 – lStencilCaps Enum CONST_D3DSTENCILCAPSFLAGS D3DSTENCILCAPS_DECR D3DSTENCILCAPS_DECRSAT D3DSTENCILCAPS_INCR D3DSTENCILCAPS_INCRSAT D3DSTENCILCAPS_INVERT D3DSTENCILCAPS_KEEP D3DSTENCILCAPS_REPLACE D3DSTENCILCAPS_ZERO End Enum
= = = = = = = =
128 16 64 8 32 1 4 2
B.2.37 CONST_D3DSTENCILOP Verwendung in: D3DRENDERSTATE_STENCILFAIL, D3DRENDERSTATE_ STENCILZFAIL, D3DRENDERSTATE_STENCILPASS Enum CONST_D3DSTENCILOP D3DSTENCILOP_DECR D3DSTENCILOP_DECRSAT D3DSTENCILOP_INCR D3DSTENCILOP_INCRSAT D3DSTENCILOP_INVERT D3DSTENCILOP_KEEP D3DSTENCILOP_REPLACE D3DSTENCILOP_ZERO End Enum
= = = = = = = =
B.2.38 CONST_D3DTEXCOORDINDEXFLAGS Verwendung in: D3DTSS_TEXCOORDINDEX Type CONST_D3DTEXCOORDINDEXFLAGS
8 5 7 4 6 1 3 2
578
Direct3DEnum
D3DTSS_TCI_CAMERASPACENORMAL D3DTSS_TCI_CAMERASPACEPOSITION D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR D3DTSS_TCI_PASSTHRU End Type
= = = =
65536 131072 196608 0
B.2.39 CONST_D3DTEXOPCAPSFLAGS Verwendung in: D3DDEVICEDESC7 – lTextureOpCaps Enum CONST_D3DTEXOPCAPSFLAGS D3DTEXOPCAPS_ADD D3DTEXOPCAPS_ADDSIGNED D3DTEXOPCAPS_ADDSIGNED2X D3DTEXOPCAPS_ADDSMOOTH D3DTEXOPCAPS_BLENDCURRENTALPHA D3DTEXOPCAPS_BLENDDIFFUSEALPHA D3DTEXOPCAPS_BLENDFACTORALPHA D3DTEXOPCAPS_BLENDTEXTUREALPHA D3DTEXOPCAPS_BLENDTEXTUREALPHAPM D3DTEXOPCAPS_BUMPENVMAP D3DTEXOPCAPS_BUMPENVMAPLUMINANCE D3DTEXOPCAPS_DISABLE D3DTEXOPCAPS_DOTPRODUCT3 D3DTEXOPCAPS_MODULATE D3DTEXOPCAPS_MODULATE2X D3DTEXOPCAPS_MODULATE4X D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA D3DTEXOPCAPS_PREMODULATE D3DTEXOPCAPS_SELECTARG1 D3DTEXOPCAPS_SELECTARG2 D3DTEXOPCAPS_SUBTRACT End Enum
= = = = = = = = = = = = = = = = = = = = = = = =
64 128 256 1024 32768 2048 8192 4096 16384 2097152 4194304 1 8388608 8 16 32 131072 262144 524288 1048576 65536 2 4 512
B.2.40 CONST_D3DTEXTUREADDRESS Verwendung in: D3DTSS_ADDRESS, D3DTSS_ADDRESSU, D3DTSS_ADDRESSV Enum CONST_D3DTEXTUREADDRESS D3DTADDRESS_WRAP D3DTADDRESS_MIRROR D3DTADDRESS_CLAMP D3DTADDRESS_BORDER End Enum
= = = =
1 2 3 4
Anhang B • Konstanten
579
B.2.41 CONST_D3DTEXTUREMAGFILTER Enum CONST_D3DTEXTUREMAGFILTER D3DTFG_POINT D3DTFG_LINEAR D3DTFG_FLATCUBIC D3DTFG_GAUSSIANCUBIC D3DTFG_ANISOTROPIC End Enum
= = = = =
1 2 3 4 5
B.2.42 CONST_D3DTEXTUREMINFILTER Enum CONST_D3DTEXTUREMINFILTER D3DTFN_POINT D3DTFN_LINEAR D3DTFN_ANISOTROPIC End Enum
= 1 = 2 = 3
B.2.43 CONST_D3DTEXTUREMIPFILTER Enum CONST_D3DTEXTUREMIPFILTER D3DTFP_NONE D3DTFP_POINT D3DTFP_LINEAR End Enum
= 1 = 2 = 3
B.2.44 CONST_D3DTEXTUREOP Verwendung in: Direct3DDevice7.SetTextureStageState() Enum CONST_D3DTEXTUREOP D3DTOP_DISABLE D3DTOP_SELECTARG1 D3DTOP_SELECTARG2 D3DTOP_MODULATE D3DTOP_MODULATE2X D3DTOP_MODULATE4X D3DTOP_ADD D3DTOP_ADDSIGNED D3DTOP_ADDSIGNED2X D3DTOP_SUBTRACT D3DTOP_ADDSMOOTH D3DTOP_BLENDDIFFUSEALPHA D3DTOP_BLENDTEXTUREALPHA D3DTOP_BLENDFACTORALPHA D3DTOP_BLENDTEXTUREALPHAPM D3DTOP_BLENDCURRENTALPHA
= = = = = = = = = = = = = = = =
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
580
Direct3DEnum
D3DTOP_PREMODULATE D3DTOP_MODULATEALPHA_ADDCOLOR D3DTOP_MODULATECOLOR_ADDALPHA D3DTOP_MODULATEINVALPHA_ADDCOLOR D3DTOP_MODULATEINVCOLOR_ADDALPHA D3DTOP_BUMPENVMAP D3DTOP_BUMPENVMAPLUMINANCE D3DTOP_DOTPRODUCT3 End Enum
= = = = = = = =
17 18 19 20 21 22 23 24
B.2.45 CONST_D3DTEXTURESTAGESINGLE Verwendung in: Direct3DDevice7.GetTextureStageStateSingle(), Direct3D-Device7.SetTextureStageStateSingle() Enum CONST_D3DTEXTURESTAGESINGLE D3DTSS_BUMPENVLOFFSET D3DTSS_BUMPENVLSCALE D3DTSS_BUMPENVMAT00 D3DTSS_BUMPENVMAT01 D3DTSS_BUMPENVMAT10 D3DTSS_BUMPENVMAT11 D3DTSS_MIPMAPLODBIAS End Enum
= = = = = = =
23 22 7 8 9 10 19
B.2.46 CONST_D3DTEXTURESTAGESTATETYPE Verwendung in: Direct3DDevice7.GetTextureStageState(), Direct3DDevice7.SetTextureStageState() Enum CONST_D3DTEXTURESTAGESTATETYPE D3DTSS_ADDRESS D3DTSS_ADDRESSU D3DTSS_ADDRESSV D3DTSS_ALPHAARG1 D3DTSS_ALPHAARG2 D3DTSS_ALPHAOP D3DTSS_BORDERCOLOR D3DTSS_COLORARG1 D3DTSS_COLORARG2 D3DTSS_COLOROP D3DTSS_MAGFILTER D3DTSS_MAXANISOTROPY D3DTSS_MAXMIPLEVEL D3DTSS_MINFILTER D3DTSS_MIPFILTER D3DTSS_TEXCOORDINDEX D3DTSS_TEXTURETRANSFORMFLAGS
= = = = = = = = = = = = = = = = =
12 13 14 5 6 4 15 2 3 1 16 21 20 17 18 11 24
Anhang B • Konstanten
581
End Enum
B.2.47 CONST_D3DTEXTURETRANSFORMFLAGS Verwendung in: D3DTSS_TEXTURETRANSFORMFLAGS Enum CONST_D3DTEXTURETRANSFORMFLAGS D3DTTFF_COUNT1 D3DTTFF_COUNT2 D3DTTFF_COUNT3 D3DTTFF_COUNT4 D3DTTFF_DISABLE D3DTTFF_PROJECTED End Enum
= = = = = =
1 2 3 4 0 256
B.2.48 CONST_D3DTRANSFORMSTATETYPE Enum CONST_D3DTRANSFORMSTATETYPE D3DTRANSFORMSTATE_WORLD D3DTRANSFORMSTATE_WORLD1 D3DTRANSFORMSTATE_WORLD2 D3DTRANSFORMSTATE_WORLD3 D3DTRANSFORMSTATE_VIEW D3DTRANSFORMSTATE_PROJECTION D3DTRANSFORMSTATE_TEXTURE0 D3DTRANSFORMSTATE_TEXTURE1 D3DTRANSFORMSTATE_TEXTURE2 D3DTRANSFORMSTATE_TEXTURE3 D3DTRANSFORMSTATE_TEXTURE4 D3DTRANSFORMSTATE_TEXTURE5 D3DTRANSFORMSTATE_TEXTURE6 D3DTRANSFORMSTATE_TEXTURE7 End Enum
= = = = = = = = = = = = = =
1 4 5 6 2 3 16 17 18 19 20 21 22 23
B.2.49 CONST_D3DVBCAPSFLAGS Verwendung in: D3DVERTEXBUFFERDESC – lCaps Enum CONST_D3DVBCAPSFLAGS D3DVBCAPS_DEFAULT D3DVBCAPS_DONOTCLIP D3DVBCAPS_OPTIMIZED D3DVBCAPS_SYSTEMMEMORY D3DVBCAPS_WRITEONLY End Enum
= = = = =
0 1 2147483648 2048 65536
582
Direct3DEnum
B.2.50 CONST_D3DVERTEXBLENDFLAGS Verwendung in: D3DRENDERSTATE_VERTEXBLEND Enum CONST_D3DVERTEXBLENDFLAGS D3DVBLEND_1WEIGHT D3DVBLEND_2WEIGHTS D3DVBLEND_3WEIGHTS D3DVBLEND_DISABLE End Enum
= = = =
1 2 3 0
B.2.51 CONST_D3DVOPFLAGS Verwendung in: Direct3DVertexBuffer7.ProcessVertices() Enum CONST_D3DVOPFLAGS D3DVOP_CLIP D3DVOP_EXTENTS D3DVOP_LIGHT D3DVOP_TRANSFORM End Enum
= = = =
2 4 1024 1
B.2.52 CONST_D3DVTXPCAPS Verwendung in: D3DDEVICEDESC7 – lVertexProcessingCaps Enum CONST_D3DVTXPCAPS D3DVTXPCAPS_DIRECTIONALLIGHTS D3DVTXPCAPS_MATERIALSOURCE7 D3DVTXPCAPS_NONLOCALVIEWER D3DVTXPCAPS_POSITIONALLIGHTS D3DVTXPCAPS_TEXGEN D3DVTXPCAPS_VERTEXFOG End Enum
= 8 = 2 = 32 = 16 = 1 = 4
B.2.53 CONST_D3DZBUFFERTYPE Verwendung in: D3DRENDERSTATE_ZENABLE Enum CONST_D3DZBUFFERTYPE D3DZB_FALSE D3DZB_TRUE D3DZB_USEW End Enum
= 0 = 1 = 2
Anhang B • Konstanten
B.3
DirectSoundEnum
B.3.1
CONST_DS3DAPPLYFLAGS
583
Verwendung in: DirectSound3DBuffer, DirectSound3DListener Enum CONST_DS3DAPPLYFLAGS DS3D_DEFERRED DS3D_IMMEDIATE End Enum
B.3.2
= 1 = 0
CONST_DS3DMODEFLAGS Verwendung in: DirectSound3DBuffer.GetMode(), DirectSound3DBuffer.SetMode() Enum CONST_DS3DMODEFLAGS DS3DMODE_DISABLE DS3DMODE_HEADRELATIVE DS3DMODE_NORMAL End Enum
B.3.3
= 2 = 1 = 0
CONST_DSBCAPSFLAGS Verwendung in: DSBUFFERDESC – DSBCAPS – lFlags Enum CONST_DSBCAPSFLAGS DSBCAPS_CTRL3D DSBCAPS_CTRLFREQUENCY DSBCAPS_CTRLPAN DSBCAPS_CTRLPOSITIONNOTIFY DSBCAPS_CTRLVOLUME DSBCAPS_GETCURRENTPOSITION2 DSBCAPS_GLOBALFOCUS DSBCAPS_LOCHARDWARE DSBCAPS_LOCSOFTWARE DSBCAPS_MUTE3DATMAXDISTANCE DSBCAPS_PRIMARYBUFFER DSBCAPS_STATIC DSBCAPS_STICKYFOCUS End Enum
B.3.4
CONST_DSBLOCKFLAGS Verwendung in: DirectSoundBuffer.ReadBuffer()
= = = = = = = = = = = = =
16 32 64 256 128 65536 32768 4 8 131072 1 2 16384
584
DirectSoundEnum
Enum CONST_DSBLOCKFLAGS DSBLOCK_DEFAULT DSBLOCK_ENTIREBUFFER DSBLOCK_FROMWRITECURSOR End Enum
B.3.5
= 0 = 2 = 1
CONST_DSBPLAYFLAGS Verwendung in: DirectSoundBuffer.Play() Enum CONST_DSBPLAYFLAGS DSBPLAY_DEFAULT DSBPLAY_LOOPING End Enum
B.3.6
= 0 = 1
CONST_DSBSTATUSFLAGS Verwendung in: DirectSoundBuffer.GetStatus() Enum CONST_DSBSTATUSFLAGS DSBSTATUS_BUFFERLOST DSBSTATUS_LOOPING DSBSTATUS_PLAYING End Enum
B.3.7
= 2 = 4 = 1
CONST_DSCAPSFLAGS Verwendung in: DSCAPS – lFlags Enum CONST_DSCAPSFLAGS DSCAPS_CERTIFIED DSCAPS_CONTINUOUSRATE DSCAPS_EMULDRIVER DSCAPS_PRIMARY16BIT DSCAPS_PRIMARY8BIT DSCAPS_PRIMARYMONO DSCAPS_PRIMARYSTEREO DSCAPS_SECONDARY16BIT DSCAPS_SECONDARY8BIT DSCAPS_SECONDARYMONO DSCAPS_SECONDARYSTEREO End Enum
B.3.8
CONST_DSCBCAPSFLAGS Verwendung in: DSCBCAPS – lFlags
= = = = = = = = = = =
64 16 32 8 4 1 2 2048 1024 256 512
Anhang B • Konstanten
Enum CONST_DSCBCAPSFLAGS DSCBCAPS_DEFAULT DSCBCAPS_WAVEMAPPED End Enum
B.3.9
585
= 0 = -2147483648
CONST_DSCBLOCKFLAGS Verwendung in: DirectSoundCaptureBuffer.ReadBuffer(), DirectSoundCaptureBuffer.WriteBuffer() Enum CONST_DSCBLOCKFLAGS DSCBLOCK_DEFAULT DSCBLOCK_ENTIREBUFFER End Enum
= 0 = 1
B.3.10 CONST_DSCBSTARTFLAGS Verwendung in: DirectSoundCaptureBuffer.Start() Enum CONST_DSCBSTARTFLAGS DSCBSTART_DEFAULT DSCBSTART_LOOPING End Enum
= 0 = 1
B.3.11 CONST_DSCBSTATUSFLAGS Verwendung in: DirectSoundCaptureBuffer.GetStatus() Enum CONST_DSCBSTATUSFLAGS DSCBSTATUS_CAPTURING DSCBSTATUS_LOOPING End Enum
= 1 = 2
B.3.12 CONST_DSCCAPSFLAGS Verwendung in: DSCCAPS – lFlags Enum CONST_DSCCAPSFLAGS DSCCAPS_DEFAULT DSCCAPS_EMULDRIVER End Enum
= 0 = 32
B.3.13 CONST_DSOUND Enum CONST_DSOUND DS3D_DEFAULTCONEANGLE DS3D_DEFAULTCONEOUTSIDEVOLUME
= 360 = 0
586
DirectSoundEnum
DS3D_DEFAULTDISTANCEFACTOR DS3D_DEFAULTDOPPLERFACTOR DS3D_DEFAULTMAXDISTANCE DS3D_DEFAULTMINDISTANCE DS3D_DEFAULTROLLOFFFACTOR DS3D_MAXCONEANGLE DS3D_MAXDISTANCEFACTOR DS3D_MAXDOPPLERFACTOR DS3D_MAXROLLOFFFACTOR DS3D_MINCONEANGLE DS3D_MINDISTANCEFACTOR DS3D_MINDOPPLERFACTOR DS3D_MINROLLOFFFACTOR DSBFREQUENCY_MAX DSBFREQUENCY_MIN DSBFREQUENCY_ORIGINAL DSBPAN_CENTER DSBPAN_LEFT DSBPAN_RIGHT DSBPN_OFFSETSTOP DSBSIZE_MAX DSBSIZE_MIN DSBVOLUME_MAX DSBVOLUME_MIN WAVE_FORMAT_PCM End Enum
= = = = = = = = = = = = = = = = = = = = = = = = =
1 1 1000000000 1 1 360 10 10 10 0 0 0 0 100000 100 0 0 -10000 10000 -1 268435455 4 0 -10000 1
B.3.14 CONST_DSSCLFLAGS Verwendung in: DirectSound.SetCooperativeLevel() Enum CONST_DSSCLFLAGS DSSCL_EXCLUSIVE DSSCL_NORMAL DSSCL_PRIORITY DSSCL_WRITEPRIMARY End Enum
= = = =
3 1 2 4
B.3.15 CONST_DSSPEAKERFLAGS Verwendung in: DirectSound.GetSpeakerConfig(), DirectSound.SetSpeakerConfig() Enum CONST_DSSPEAKERFLAGS DSSPEAKER_GEOMETRY_MAX DSSPEAKER_GEOMETRY_MIN DSSPEAKER_GEOMETRY_NARROW DSSPEAKER_GEOMETRY_WIDE
= = = =
180 5 10 20
Anhang B • Konstanten
DSSPEAKER_HEADPHONE DSSPEAKER_MONO DSSPEAKER_QUAD DSSPEAKER_STEREO DSSPEAKER_SURROUND End Enum
587
= = = = =
1 2 3 4 5
= = = = = = = = = = = =
1 4 2 8 16 64 32 128 256 1024 512 2048
B.3.16 CONST_WAVEFORMATFLAGS Verwendung in: DSCCAPS – lFormats Enum CONST_WAVEFORMATFLAGS WAVE_FORMAT_1M08 WAVE_FORMAT_1M16 WAVE_FORMAT_1S08 WAVE_FORMAT_1S16 WAVE_FORMAT_2M08 WAVE_FORMAT_2M16 WAVE_FORMAT_2S08 WAVE_FORMAT_2S16 WAVE_FORMAT_4M08 WAVE_FORMAT_4M16 WAVE_FORMAT_4S08 WAVE_FORMAT_4S16 End Enum Wert
Bedeutung
WAVE_FORMAT_1M08
11.025 kHz, mono, 8-bit
WAVE_FORMAT_1M16
11.025 kHz, mono, 16-bit
WAVE_FORMAT_1S08
11.025 kHz, stereo, 8-bit
WAVE_FORMAT_1S16
11.025 kHz, stereo, 16-bit
WAVE_FORMAT_2M08
22.05 kHz, mono, 8-bit
WAVE_FORMAT_2M16
22.05 kHz, mono, 16-bit
WAVE_FORMAT_2S08
22.05 kHz, stereo, 8-bit
WAVE_FORMAT_2S16
22.05 kHz, stereo, 16-bit
WAVE_FORMAT_4M08
44.1 kHz, mono, 8-bit
WAVE_FORMAT_4M16
44.1 kHz, mono, 16-bit
WAVE_FORMAT_4S08
44.1 kHz, stereo, 8-bit
WAVE_FORMAT_4S16
44.1 kHz, stereo, 16-bit
588
DirectInput Enum
B.4
DirectInput Enum
B.4.1
CONST_DICOMMONDATAFORMATS Verwendung in: DirectInputDevice.SetCommonDataFormat() Enum CONST_DICOMMONDATAFORMATS DIFORMAT_JOYSTICK = 3 DIFORMAT_JOYSTICK2 = 4 DIFORMAT_KEYBOARD = 1 DIFORMAT_MOUSE = 2 End Enum
B.4.2
CONST_DICONDITIONFLAGS Enum CONST_DICONDITIONFLAGS DICONDITION_USE_BOTH_AXES = 1 DICONDITION_USE_DIRECTION = 2 End Enum
B.4.3
CONST_DIDATAFORMATFLAGS Verwendung in: DIDATAFORMAT – lFlags Enum CONST_DIDATAFORMATFLAGS DIDF_ABSAXIS = 1 DIDF_RELAXIS = 2 End Enum
B.4.4
CONST_DIDEVCAPSFLAGS Verwendung in: DIDEVCAPS – lFlags Enum CONST_DIDEVCAPSFLAGS DIDC_ATTACHED DIDC_DEADBAND DIDC_EMULATED DIDC_FFATTACK DIDC_FFFADE DIDC_FORCEFEEDBACK DIDC_POLLEDDATAFORMAT DIDC_POLLEDDEVICE DIDC_POSNEGCOEFFICIENTS DIDC_POSNEGSATURATION DIDC_SATURATION End Enum
= = = = = = = = = = =
1 16384 4 512 1024 256 8 2 4096 8192 2048
Anhang B • Konstanten
B.4.5
589
CONST_DIDEVICEOBJINSTANCEFLAGS Verwendung in: DirectInputDeviceObjectInstance.GetFlags(), DirectInputDevice.SetDataFormat() Enum CONST_DIDEVICEINSTANCEFLAGS DIDOI_ASPECTACCEL DIDOI_ASPECTFORCE DIDOI_ASPECTMASK DIDOI_ASPECTPOSITION DIDOI_ASPECTVELOCITY DIDOI_FFACTUATOR DIDOI_FFEFFECTTRIGGER DIDOI_POLLED End Enum
B.4.6
= = = = = = = =
768 1024 3840 256 512 1 2 32768
CONST_DIDEVICETYPE Verwendung in: DirectInputDeviceInstance.GetDevType(), DIDEVCAPS – lDevType DirectInputDevice.GetCapabilities(), DirectInput.GetDIEnumDevices() Enum CONST_DIDEVICETYPE DIDEVTYPE_DEVICE DIDEVTYPE_HID DIDEVTYPE_JOYSTICK DIDEVTYPE_KEYBOARD DIDEVTYPE_MOUSE DIDEVTYPEJOYSTICK_FLIGHTSTICK DIDEVTYPEJOYSTICK_GAMEPAD DIDEVTYPEJOYSTICK_HEADTRACKER DIDEVTYPEJOYSTICK_RUDDER DIDEVTYPEJOYSTICK_TRADITIONAL DIDEVTYPEJOYSTICK_UNKNOWN DIDEVTYPEJOYSTICK_WHEEL DIDEVTYPEKEYBOARD_J3100 DIDEVTYPEKEYBOARD_JAPAN106 DIDEVTYPEKEYBOARD_JAPANAX DIDEVTYPEKEYBOARD_NEC98 DIDEVTYPEKEYBOARD_NEC98106 DIDEVTYPEKEYBOARD_NEC98LAPTOP DIDEVTYPEKEYBOARD_NOKIA1050 DIDEVTYPEKEYBOARD_NOKIA9140 DIDEVTYPEKEYBOARD_OLIVETTI DIDEVTYPEKEYBOARD_PCAT DIDEVTYPEKEYBOARD_PCENH DIDEVTYPEKEYBOARD_PCXT DIDEVTYPEKEYBOARD_UNKNOWN
= = = = = = = = = = = = = = = = = = = = = = = = =
1 65536 4 3 2 3 4 7 5 2 1 6 12 10 11 7 9 8 5 6 2 3 4 1 0
590
DirectInput Enum
DIDEVTYPEMOUSE_FINGERSTICK DIDEVTYPEMOUSE_TOUCHPAD DIDEVTYPEMOUSE_TRACKBALL DIDEVTYPEMOUSE_TRADITIONAL DIDEVTYPEMOUSE_UNKNOWN End Enum
B.4.7
= = = = =
3 4 5 2 1
CONST_DIDFTFLAGS Verwendung in: DirectInputDevice.GetDeviceObjectsEnum(), DirectInputDeviceObjectInstance.GetFlags() Enum CONST_DIDFTFLAGS DIDFT_ABSAXIS DIDFT_ALL DIDFT_ANYINSTANCE DIDFT_AXIS DIDFT_BUTTON DIDFT_COLLECTION DIDFT_FFACTUATOR DIDFT_FFEFFECTTRIGGER DIDFT_INSTANCEMASK DIDFT_NOCOLLECTION DIDFT_NODATA DIDFT_POV DIDFT_PSHBUTTON DIDFT_RELAXIS DIDFT_TGLBUTTON End Enum
B.4.8
= = = = = = = = = = = = = = =
2 0 16776960 3 12 64 16777216 33554432 16776960 16776960 128 16 4 1 8
CONST_DIDGDDFLAGS Verwendung in: DirectInputDevice.GetDeviceData() Enum CONST_DIDGDDFLAGS DIGDD_DEFAULT = 0 DIGDD_PEEK = 1 End Enum
B.4.9
CONST_DIEFFFLAGS Verwendung in: DIEFFECT – lFlags Enum CONST_DIEFFFLAGS DIEFF_CARTESIAN = 16 DIEFF_OBJECTOFFSETS = 2 DIEFF_POLAR = 32 End Enum
Anhang B • Konstanten
591
B.4.10 CONST_DIEFTFLAGS Verwendung in: DirectInputDevice.GetEffectsEnum(), DirectInputEnumEffects.GetType() Enum CONST_DIEFTFLAGS DIEFT_ALL DIEFT_CONDITION DIEFT_CONSTANTFORCE DIEFT_CUSTOMFORCE DIEFT_DEADBAND DIEFT_FFATTACK DIEFT_FFFADE DIEFT_HARDWARE DIEFT_PERIODIC DIEFT_POSNEGCOEFFICIENTS DIEFT_POSNEGSATURATION DIEFT_RAMPFORCE DIEFT_SATURATION End Enum
= = = = = = = = = = = = =
0 4 1 5 16384 512 1024 255 3 4096 8192 2 2048
B.4.11 CONST_DIEGESFLAGS Verwendung in: DirectInputEffect.GetEffectStatus() Enum CONST_DIEGESFLAGS DIEGES_EMULATED = 2 DIEGES_PLAYING = 1 End Enum
B.4.12 CONST_DIENUMDEVICESFLAGS Verwendung in: DirectInput.GetDIEnumDevices() Enum CONST_DIENUMDEVICESFLAGS DIEDFL_ALLDEVICES DIEDFL_ATTACHEDONLY End Enum
= 0 = 1
B.4.13 CONST_DIEPFLAGS Verwendung in: DirectInputEffect.SetParameters(), DirectInputEnumEffects.GetStaticParams(), DirectInputEnumEffects.GetDynamicParams() Enum CONST_DIEPFLAGS DIEP_ALLPARAMS DIEP_AXES DIEP_DIRECTION
= 511 = 32 = 64
592
DirectInput Enum
DIEP_DURATION DIEP_ENVELOPE DIEP_GAIN DIEP_NODOWNLOAD DIEP_NORESTART DIEP_SAMPLEPERIOD DIEP_START DIEP_TRIGGERBUTTON DIEP_TRIGGERREPEATINTERVAL DIEP_TYPESPECIFICPARAMS End Enum
= = = = = = = = = =
1 128 4 -2147483648 1073741824 2 536870912 8 16 256
B.4.14 CONST_DIESFLAGS Enum CONST_DIESFLAGS DIES_NODOWNLOAD = -2147483648 DIES_SOLO End Enum
= 1
B.4.15 CONST_DIGFFSFLAGS Verwendung in: DirectInputDevice.GetForceFeedbackState() Enum CONST_DIGFFSFLAGS DIGFFS_ACTUATORSOFF DIGFFS_ACTUATORSON DIGFFS_DEVICELOST DIGFFS_EMPTY DIGFFS_PAUSED DIGFFS_POWEROFF DIGFFS_POWERON DIGFFS_SAFETYSWITCHOFF DIGFFS_SAFETYSWITCHON DIGFFS_STOPPED DIGFFS_USERFFSWITCHOFF DIGFFS_USERFFSWITCHON End Enum
= = = = = = = = = = = =
32 16 -2147483648 1 4 128 64 512 256 2 2048 1024
= = = = = =
48 49 58 59 60 61
B.4.16 CONST_DIJOYSTICKOFS Enum CONST_DIJOYSTICKOFS DIJOFS_BUTTON0 DIJOFS_BUTTON1 DIJOFS_BUTTON10 DIJOFS_BUTTON11 DIJOFS_BUTTON12 DIJOFS_BUTTON13
Anhang B • Konstanten
DIJOFS_BUTTON14 DIJOFS_BUTTON15 DIJOFS_BUTTON16 DIJOFS_BUTTON17 DIJOFS_BUTTON18 DIJOFS_BUTTON19 DIJOFS_BUTTON2 DIJOFS_BUTTON20 DIJOFS_BUTTON21 DIJOFS_BUTTON22 DIJOFS_BUTTON23 DIJOFS_BUTTON24 DIJOFS_BUTTON25 DIJOFS_BUTTON26 DIJOFS_BUTTON27 DIJOFS_BUTTON28 DIJOFS_BUTTON29 DIJOFS_BUTTON3 DIJOFS_BUTTON30 DIJOFS_BUTTON31 DIJOFS_BUTTON4 DIJOFS_BUTTON5 DIJOFS_BUTTON6 DIJOFS_BUTTON7 DIJOFS_BUTTON8 DIJOFS_BUTTON9 DIJOFS_POV0 DIJOFS_POV1 DIJOFS_POV2 DIJOFS_POV3 DIJOFS_RX DIJOFS_RY DIJOFS_RZ DIJOFS_SLIDER0 DIJOFS_SLIDER1 DIJOFS_X DIJOFS_Y DIJOFS_Z End Enum
593
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
62 63 64 65 66 67 50 68 69 70 71 72 73 74 75 76 77 51 78 79 52 53 54 55 56 57 32 36 40 44 12 16 20 24 28 0 4 8
= = = =
12 13 14 15
B.4.17 CONST_DIMOUSEOFS Enum CONST_DIMOUSEOFS DIMOFS_BUTTON0 DIMOFS_BUTTON1 DIMOFS_BUTTON2 DIMOFS_BUTTON3
594
DirectInput Enum
DIMOFS_X DIMOFS_Y DIMOFS_Z End Enum
= = =
0 4 8
B.4.18 CONST_DINPUT Enum CONST_DINPUT DIPROPAXISMODE_ABS DIPROPAXISMODE_REL DIPROPCALIBRATIONMODE_COOKED DIPROPCALIBRATIONMODE_RAW DIPROPRANGE_NOMAX DIPROPRANGE_NOMIN End Enum
= = = = = =
0 1 0 1 2147483647 -2147483648
B.4.19 CONST_DIPHFLAGS Verwendung in: DirectInputDevice.GetObjectInfo() Enum CONST_DIPHFLAGS DIPH_DEVICE DIPH_BYID DIPH_BYOFFSET End Enum
= 0 = 2 = 1
B.4.20 CONST_DISCLFLAGS Verwendung in: DirectInputDevice.SetCooperativeLevel() Enum CONST_DISCLFLAGS DISCL_BACKGROUND DISCL_EXCLUSIVE DISCL_FOREGROUND DISCL_NONEXCLUSIVE End Enum
= = = =
8 1 4 2
B.4.21 CONST_DISDDFLAGS Verwendung in: DirectInputDevice.SendDeviceData() Enum CONST_DISDDCFLAGS DISDD_CONTINUE DISDD_DEFAULT End Enum
= 1 = 0
Anhang B • Konstanten
595
B.4.22 CONST_DISFFCFLAGS Verwendung in: DirectInputDevice.SendForceFeedbackCommand() Enum CONST_DISFFCFLAGS DISFFC_CONTINUE DISFFC_PAUSE DISFFC_RESET DISFFC_SETACTUATORSOFF DISFFC_SETACTUATORSON DISFFC_STOPALL End Enum
B.5
DirectPlay Enum
B.5.1
CONST_DPCAPSFLAGS Enum CONST_DPCAPSFLAGS DPCAPS_ASYNCCANCELALLSUPPORTED DPCAPS_ASYNCCANCELSUPPORTED DPCAPS_ASYNCSUPPORTED DPCAPS_ENCRYPTIONSUPPORTED DPCAPS_GROUPOPTIMIZED DPCAPS_GUARANTEEDOPTIMIZED DPCAPS_GUARANTEEDSUPPORTED DPCAPS_ISHOST DPCAPS_KEEPALIVEOPTIMIZED DPCAPS_SENDPRIORITYSUPPORTED DPCAPS_SENDTIMEOUTSUPPORTED DPCAPS_SIGNINGSUPPORTED End Enum
B.5.2
= = = = = =
= = = = = = = = = = = =
8 4 1 32 16 2
8192 4096 65536 256 8 32 64 2 16 32768 16384 128
CONST_DPCONNECTFLAGS Enum CONST_DPCONNECTFLAGS DPCONNECTION_DEFAULT = 0 DPCONNECTION_RETURNSTATUS = 128 End Enum
B.5.3
CONST_DPENUMCONNECTIONFLAGS Enum CONST_DPENUMCONNECTIONFLAGS DPCONNECTION_DIRECTPLAY = 1 DPCONNECTION_DIRECTPLAYLOBBY = 2 End Enum
596
B.5.4
DirectPlay Enum
CONST_DPENUMGROUPFLAGS Enum CONST_DPENUMGROUPFLAGS DPENUMGROUPS_ALL DPENUMGROUPS_HIDDEN DPENUMGROUPS_LOCAL DPENUMGROUPS_REMOTE DPENUMGROUPS_SESSION DPENUMGROUPS_SHORTCUT DPENUMGROUPS_STAGINGAREA End Enum
B.5.5
= = = = = = =
CONST_DPENUMPLAYERFLAGS Enum CONST_DPENUMPLAYERFLAGS DPENUMPLAYERS_ALL DPENUMPLAYERS_GROUP DPENUMPLAYERS_LOCAL DPENUMPLAYERS_OWNER DPENUMPLAYERS_REMOTE DPENUMPLAYERS_SERVERPLAYER DPENUMPLAYERS_SESSION DPENUMPLAYERS_SPECTATOR End Enum
B.5.6
0 4096 8 16 128 1024 2048
= = = = = = = =
0 32 8 8192 16 200 128 512
CONST_DPENUMSESSIONFLAGS Enum CONST_DPENUMSESSIONFLAGS DPENUMSESSIONS_ALL DPENUMSESSIONS_ASYNC DPENUMSESSIONS_AVAILABLE DPENUMSESSIONS_PASSWORDREQUIRED DPENUMSESSIONS_RETURNSTATUS DPENUMSESSIONS_STOPASYNC End Enum
B.5.7
CONST_DPGETCAPSFLAGS Enum CONST_DPGETCAPSFLAGS DPGETCAPS_DEFAULT = 0 DPGETCAPS_GUARANTEED = 1 End Enum
= = = = = =
2 16 1 64 128 16
Anhang B • Konstanten
B.5.8
597
CONST_DPGETFLAGS Enum CONST_DPGETFLAGS DPGET_LOCAL = 1 DPGET_REMOTE = 0 End Enum
B.5.9
CONST_DPGROUPFLAGS Enum CONST_DPGROUPFLAGS DPGROUP_DEFAULT DPGROUP_HIDDEN DPGROUP_LOCAL DPGROUP_STAGINGAREA End Enum
= = = =
0 4096 8 2048
B.5.10 CONST_DPIDFLAGS Enum CONST_DPIDFLAGS DPID_ALLPLAYERS DPID_SERVERPLAYER DPID_SYSMSG DPID_UNKNOWN End Enum
= 0 = 1 = 0 =-1
B.5.11 CONST_DPLCONNECTIONFLAGS Enum CONST_DPLCONNECTIONFLAGS DPLCONNECTION_CREATESESSION = 2 DPLCONNECTION_JOINSESSION = 1 End Enum
B.5.12 CONST_DPLMSG Enum CONST_DPLMSG DPLMSG_STANDARD = 2 DPLMSG_SYSTEM = 1 DPLMSG_USERDEFINED = 0 End Enum
B.5.13 CONST_DPLWAIT Enum CONST_DPLWAIT DPLWAIT_CANCEL = 1 DPLWAIT_DEFAULT = 0 End Enum
598
DirectPlay Enum
B.5.14 CONST_DPMESSAGEQUEUEFLAGS Enum CONST_DPMESSAGEQUEUEFLAGS DPMESSAGEQUEUE_RECEIVE = 2 DPMESSAGEQUEUE_SEND = 1 End Enum
B.5.15 CONST_DPOPENFLAGS Enum CONST_DOPENFLAGS DPOPEN_CREATE = 2 DPOPEN_JOIN = 1 DPOPEN_RETURNSTATUS = 128 End Enum
B.5.16 CONST_DPPLAYERFLAGS Enum CONST_DPPLAYERFLAGS DPPLAYER_LOCAL = 8 DPPLAYER_SERVERPLAYER = 256 DPPLAYER_SPECTATOR = 512 End Enum
B.5.17 CONST_DPPLAYERTYPEFLAGS Enum CONST_DPPLAYERTYPEFLAGS DPPLAYERTYPE_GROUP = 0 DPPLAYERTYPE_PLAYER = 1 End Enum
B.5.18 CONST_DPRECEIVEFLAGS Enum CONST_DPRECEIVEFLAGS DPRECEIVE_ALL = DPRECEIVE_FROMPLAYER = DPRECEIVE_PEEK = DPRECEIVE_TOPLAYER = End Enum
1 4 8 2
B.5.19 CONST_DPSENDFLAGS Enum CONST_DPSENDFLAGS DPSEND_ASYNC DPSEND_DEFAULT DPSEND_ENCRYPTED
= 512 = 0 = 64
Anhang B • Konstanten
DPSEND_GUARANTEED DPSEND_NOSENDCOMPLETEMSG DPSEND_SIGNED End Enum
599
= 1 = 1024 = 32
B.5.20 CONST_DPSESSIONFLAGS Enum CONST_DPSESSIONFLAGS DPSESSION_CLIENTSERVER DPSESSION_DIRECTPLAYPROTOCOL DPSESSION_JOINDISABLED DPSESSION_KEEPALIVE DPSESSION_MIGRATEHOST DPSESSION_MULTICASTSERVER DPSESSION_NEWPLAYERSDISABLED DPSESSION_NODATAMESSAGES DPSESSION_NOMESSAGEID DPSESSION_NOPRESERVEORDER DPSESSION_OPTIMIZELATENCY DPSESSION_PASSWORDREQUIRED DPSESSION_PRIVATE DPSESSION_SECURESERVER End Enum
= = = = = = = = = = = = = =
4096 8192 32 64 4 2048 1 128 8 16384 32768 1024 512 256
B.5.21 CONST_DPSETFLAGS Enum CONST_DPSETFLAGS DPSET_GUARANTEED DPSET_LOCAL DPSET_REMOTE End Enum
= 2 = 1 = 0
B.5.22 CONST_DPSYSMSGTYPES Enum CONST_DPSYSMSGTYPES DPLSYS_APPTERMINATED DPLSYS_CONNECTIONSETTINGSREAD DPLSYS_DPLAYCONNECTFAILED DPLSYS_DPLAYCONNECTSUCCEEDED DPLSYS_GETPROPERTY DPLSYS_GETPROPERTYRESPONSE DPLSYS_NEWCONNECTIONSETTINGS DPLSYS_NEWSESSIONHOST DPLSYS_SETPROPERTY DPLSYS_SETPROPERTYRESPONSE DPSYS_ADDGROUPTOGROUP
= = = = = = = = = = =
4 1 2 3 7 8 10 9 5 6 261
600
DirectPlay Enum
DPSYS_ADDPLAYERTOGROUP DPSYS_CHAT DPSYS_CREATEPLAYERORGROUP DPSYS_DELETEGROUPFROMGROUP DPSYS_DELETEPLAYERFROMGROUP DPSYS_DESTROYPLAYERORGROUP DPSYS_HOST DPSYS_SECUREMESSAGE DPSYS_SENDCOMPLETE DPSYS_SESSIONLOST DPSYS_SETGROUPOWNER DPSYS_SETPLAYERORGROUPDATA DPSYS_SETPLAYERORGROUPNAME DPSYS_SETSESSIONDESC DPSYS_STARTSESSION End Enum
= = = = = = = = = = = = = = =
7 265 3 262 33 5 257 263 269 49 266 258 259 260 264
Anhang C Typen C.1 C.2 C.3 C.4 C.5
DirectDraw-Typen Direct3D-Typen DirectSound-Typen DirectInput-Typen DirectPlay-Typen
602 607 612 616 620
602
DirectDraw-Typen
C.1
DirectDraw-Typen
C.1.1
DDBLTFX DirectDrawSurface7.Blt() Type DDBLTFX ddckDestColorKey_high As Long ddckDestColorKey_low As Long ddckSrcColorKey_high As Long ddckSrcColorKey_low As Long lAlphaDestConst As Long lAlphaDestConstBitDepth As Long lAlphaEdgeBlend As Long lAlphaEdgeBlendBitDepth As Long lAlphaSrcConst As Long lAlphaSrcConstBitDepth As Long lDDFX As CONST_DDBLTFXFLAGS lDDROP As Long lFill As Long lReserved As Long lROP As Long lRotationAngle As Long lZBufferBaseDest As Long lZBufferHigh As Long lZBufferLow As Long lZBufferOpCode As Long lZDestConst As Long lZDestConstBitDepth As Long lZSrcConst As Long lZSrcConstBitDepth As Long End Type
C.1.2
DDCAPS DirectDraw7.GetCaps() Type DDCAPS ddsCaps As DDSCAPS2 lAlignBoundaryDest As Long lAlignBoundarySrc As Long lAlignSizeDest As Long lAlignSizeSrc As Long lAlignStrideAlign As Long lAlphaBltConstBitDepths As Long lAlphaBltPixelBitDepths As Long lAlphaBltSurfaceBitDepths As Long
Anhang C • Typen
lAlphaOverlayConstBitDepths As Long lAlphaOverlayPixelBitDepths As Long lAlphaOverlaySurfaceBitDepths As Long lCaps As CONST_DDCAPS1FLAGS lCaps2 As CONST_DDCAPS2FLAGS lCKeyCaps As CONST_DDCKEYCAPSFLAGS lCurrVideoPorts As Long lCurrVisibleOverlays As Long lFXCaps As CONST_DDFXCAPSFLAGS lMaxHwCodecStretch As Long lMaxLiveVideoStretch As Long lMaxOverlayStretch As Long lMaxVideoPorts As Long lMaxVisibleOverlays As Long lMinHwCodecStretch As Long lMinLiveVideoStretch As Long lMinOverlayStretch As Long lNLVBCaps As CONST_DDCAPS1FLAGS lNLVBCaps2 As CONST_DDCAPS2FLAGS lNLVBCKeyCaps As CONST_DDCKEYCAPSFLAGS lNLVBFXCaps As CONST_DDFXCAPSFLAGS lNLVBRops (0 To 7) As Long lNumFourCCCodes As Long lPalCaps As CONST_DDPCAPSFLAGS lReserved1 As Long lReserved2 As Long lReserved3 As Long lReservedCaps As Long lRops (0 To 7) As Long lSSBCaps As CONST_DDCAPS1FLAGS lSSBCKeyCaps As CONST_DDCKEYCAPSFLAGS lSSBFXCaps As CONST_DDFXCAPSFLAGS lSSBRops (0 To 7) As Long lSVBCaps As CONST_DDCAPS1FLAGS lSVBCaps2 As CONST_DDCAPS2FLAGS lSVBCKeyCaps As CONST_DDCKEYCAPSFLAGS lSVBFXCaps As CONST_DDFXCAPSFLAGS lSVBRops (0 To 7) As Long lSVCaps As CONST_DDSTEREOCAPSFLAGS lVidMemFree As Long lVidMemTotal As Long lVSBCaps As CONST_DDCAPS1FLAGS lVSBCKeyCaps As CONST_DDCKEYCAPSFLAGS lVSBFXCaps As CONST_DDFXCAPSFLAGS lVSRops (0 To 7) As Long lZBufferBitDepths As Long End Type
603
604
C.1.3
DirectDraw-Typen
DDCOLORCONTROL Type DDCOLORCONTROL lBrightness As Long lColorEnable As Long lContrast As Long lFlags As CONST_DDCOLORFLAGS lGamma As Long lHue As Long lReserved1 As Long lSaturation As Long lSharpness As Long End Type
C.1.4
DDCOLORKEY DirectDrawSurface7.GetColorKey(), DirectDrawSurface7.SetColorKey() Type COLORKEY high As Long low As Long End Type
C.1.5
DDGAMMARAMP DirectDrawGammaControl.GetGammaRamp() DirectDrawGammaControl.SetGammaRamp() Type DDGAMMARAMP blue(0 To 255) As Integer green(0 To 255) As Integer red(0 To 255) As Integer End Type
C.1.6
DDOVERLAYFX DirectDrawSurface7.UpdateOverlay() Type DDOVERLAYFX dckDestColorkey As DDCOLORKEY dckSrcColorkey As DDCOLORKEY lAlphaDestConst As Long lAlphaDestConstBitDepth As Long lAlphaEdgeBlend As Long lAlphaEdgeBlendBitDepth As Long lAlphaSrcConst As Long lAlphaSrcConstBitDepth As Long
Anhang C • Typen
lDDFX As CONST_DDOVERFXFLAGS lFlags As Long End Type
C.1.7
DDPIXELFORMAT DirectDrawSurface7.GetPixelFormat() Type DDPIXELFORMAT lAlphaBitDepth As Long lBBitMask As Long lBumpBitCount As Long lBumpDuBitMask As Long lBumpDvBitMask As Long lBumpLuminanceBitMask As Long lFlags As CONST_DDPIXELFORMATFLAGS lFourCC As Long lGBitMask As Long lLuminanceAlphaBitMask As Long lLuminanceBitCount As Long lLuminanceBitMask As Long lRBitMask As Long lRGBAlphaBitMask As Long lRGBBitCount As Long lRGBZBitMask As Long lStencilBitDepth As Long lStencilBitMask As Long lUBitMask As Long lVBitMask As Long lYBitMask As Long lYUVAlphaBitMask As Long lYUVBitCount As Long lYUVZBitMask As Long lZBitMask As Long lZBufferBitDepth As Long End Type
C.1.8
DDSCAPS2 DDSURFACEDESC2() Type DDSCAPS2 lCaps As CONST_DDSURFACECAPSFLAGS lCaps2 As CONST_DDSURFACECAPS2FLAGS lCaps3 As Long lCaps4 As Long End Type
605
606
C.1.9
DirectDraw-Typen
DDSURFACEDESC2 DirectDraw7.CreateSurface() Type DDSURFACEDESC2 ddckCKDestBlt As DDCOLORKEY ddckCKDestOverlay As DDCOLORKEY ddckCKSrcBlt As DDCOLORKEY ddckCKSrcOverlay As DDCOLORKEY ddpfPixelFormat As DDPIXELFORMAT ddsCaps As DDSCAPS2 lAlphaBitDepth As Long lBackBufferCount As Long lFlags As CONST_DDSURFACEDESCFLAGS lHeight As Long lLinearSize As Long lMipMapCount As Long lPitch As Long lRefreshRate As Long lTextureStage As Long lWidth As Long lZBufferBitDepth As Long End Type
C.1.10 PALETTEENTRY Type PALETTEENTRY blue As Byte flags As Byte green As Byte red As Byte End Type
C.1.11 RECT Type RECT Bottom As Long Left As Long Right As Long Top As Long End Type
Anhang C • Typen
C.2
Direct3D-Typen
C.2.1
D3DCLIPSTATUS Direct3DDevice7.GetClipStatus(), Direct3DDevice7.SetClipStatus() Type D3DCLIPSTATUS lFlags As Long lStatus As Long maxx As Single maxy As Single maxz As Single minx As Single miny As Single minz As Single End Type
C.2.2
D3DCOLORVALUE Type D3DCOLORVALUE a As Single b As Single g As Single r As Single End Type
C.2.3
D3DDEVICEDESC7 Direct3DDevice7.GetCaps() Type D3DDeviceDesc7 dpcLineCaps As D3DPRIMCAPS dpcTriCaps As D3DPRIMCAPS dvExtentsAdjust As Single dvGuardBandBottom As Single dvGuardBandLeft As Single dvGuardBandRight As Single dvGuardBandTop As Single dvMaxVertexW As Single lDevCaps As CONST_D3DDEVICEDESCCAPS lDeviceRenderBitDepth As Long lDeviceZBufferBitDepth As Long lFVFCaps As CONST_D3DFVFCAPSFLAGS lMaxActiveLights As Long lMaxAnisotropy As Long lMaxTextureAspectRatio As Long lMaxTextureHeight As Long
607
608
Direct3D-Typen
lMaxTextureRepeat As Long lMaxTextureWidth As Long lMinTextureHeight As Long lMinTextureWidth As Long lStencilCaps As CONST_D3DSTENCILCAPSFLAGS lTextureOpCaps As CONST_D3DTEXOPCAPSFLAGS lVertexProcessingCaps As CONST_D3DVTXPCAPS nMaxSimultaneousTextures As Integer nMaxTextureBlendStages As Integer nMaxUserClipPlanes As Integer nMaxVertexBlendMatrices As Integer End Type
C.2.4
D3DDEVINFO_TEXTUREMANAGER Direct3DDevice7.GetInfo() Type D3DDEVINFO_TEXTUREMANAGER bThrashing As Boolean lLastPri As Long lNumEvicts As Long lNumTexturesUsed As Long lNumUsedTexInVid As Long lNumVidCreates As Long lTotalBytes As Long lTotalManaged As Long lWorkingSet As Long lWorkingSetBytes As Long End Type
C.2.5
D3DDEVINFO_TEXTURING Direct3DDevice7.GetInfo() Type D3DDEVINFO_TEXTURING lApproxBytesLoaded As Long lNumCreates As Long lNumDestroys As Long lNumGetDCs As Long lNumLoads As Long lNumLocks As Long lNumPreLoads As Long lNumSet As Long lNumSetLODs As Long lNumSetPriorities As Long End Type
Anhang C • Typen
C.2.6
D3DLIGHT7 Direct3DDevice7.SetLight(), Direct3DDevice7.GetLight() Type D3DLIGHT7 ambient As D3DCOLORVALUE attenuation0 As Single attenuation1 As Single attenuation2 As Single diffuse As D3DCOLORVALUE direction As D3DVECTOR dltType As CONST_D3DLIGHTTYPE falloff As Single phi As Single position As D3DVECTOR range As Single specular As D3DCOLORVALUE theta As Single End Type
C.2.7
D3DLIGHTINGCAPS Type D3DLIGHTINGCAPS lCaps As CONST_D3DLIGHTCAPSFLAGS lLightingModel As CONST_D3DLIGHTINGMODELFLAGS lNumLights As Long End Type
C.2.8
D3DLINEPATTERN Type D3DLINEPATTERN linePattern Long repeatFactor As Long End Type
C.2.9
D3DLVERTEX Type D3DLVERTEX color As Long specular As Long tu As Single tv As Single x As Single y As Single z As Single End Type
609
610
Direct3D-Typen
C.2.10 D3DMATERIAL7 Direct3DDevice7.GetMaterial(), Direct3DDevice7.SetMaterial() Type D3DMATERIAL7 ambient As D3DCOLORVALUE diffuse As D3DCOLORVALUE emissive As D3DCOLORVALUE power As Single specular As D3DCOLORVALUE End Type
C.2.11 D3DMATRIX Direct3DDevice7.MultiplyTransform(), Direct3DDevice7.GetTransform(), Direct3DDevice7.SetTransform() Type D3DMATRIX rc11 As Single rc12 As Single rc13 As Single rc14 As Single rc21 As Single rc22 As Single rc23 As Single rc24 As Single rc31 As Single rc32 As Single rc33 As Single rc34 As Single rc41 As Single rc42 As Single rc43 As Single rc44 As Single End Type
C.2.12 D3DPRIMCAPS Type D3DprimCaps lAlphaCmpCaps As CONST_D3DCAPSCMP lDestBlendCaps As CONST_D3DCAPSBLEND lMiscCaps As CONST_D3DCAPSMISC lRasterCaps As CONST_D3DCAPSRASTER lReserved1 As Long lShadeCaps As CONST_D3DCAPSSHADE lSrcBlendCaps As CONST_D3DCAPSBLEND lStippleHeight As Long lStippleWidth As Long
Anhang C • Typen
lTextureAddressCaps As CONST_D3DCAPSTEXTUREADDRESS lTextureCaps As CONST_D3DCAPSTEXTURE lTextureFilterCaps As CONST_D3DCAPSTEXTUREFILTER lZCmpCaps As CONST_D3DCAPSCMP End Type
C.2.13 D3DRECT Type D3DRECT x1 As Long x2 As Long y1 As Long y2 As Long End Type
C.2.14 D3DTLVERTEX Type D3DTLVERTEX color As Long rhw As Single specular As Long sx As Single sy As Single sz As Single tu As Single tv As Single End Type
C.2.15 D3DVECTOR Type D3DVECTOR x As Single y As Single z As Single End Type
C.2.16 D3DVERTEX Type D3DVERTEX nx As Single ny As Single nz As Single tu As Single tv As Single x As Single
611
612
DirectSound-Typen
y As Single z As Single End Type
C.2.17 D3DVERTEXBUFFERDESC Direct3D7.CreateVertexBuffer(), Direct3DVertexBuffer7.GetVertexBufferDesc() Type D3DVERTEXBUFFERDESC lCaps As CONST_D3DVBCAPSFLAGS lFVF As CONST_D3DFVFFLAGS lNumVertices As Long End Type
C.2.18 D3DVIEWPORT7 Direct3DDevice7.GetViewport(), Direct3DDevice7.SetViewport() Type D3DVIEWPORT7 lHeight As Long lWidth As Long lX As Long lY As Long maxz As Single minz As Single End Type
C.2.19 DXDRIVERINFO Type DXDRIVERINFO strDescription As String strGuid As String strName As String End Type
C.3
DirectSound-Typen
C.3.1
DS3DBUFFER DirectSound3DBuffer.GetAllParameters(), DirectSound3DBuffer.SetAllParameters() Type DS3DBUFFER lConeOutsideVolume As Long lInsideConeAngle As Long lMode As CONST_DS3DMODEFLAGS
Anhang C • Typen
lOutsideConeAngle As Long maxDistance As Single minDistance As Single vConeOrientation As D3DVECTOR vPosition As D3DVECTOR vVelocity As D3DVECTOR End Type
C.3.2
DS3DLISTENER DirectSound3DListener.GetAllParameters(), DirectSound3DListener.SetAllParameters() Type DS3DLISTENER distanceFactor As Single dopplerFactor As Single rolloffFactor As Single vOrientFront As D3DVECTOR vOrientTop As D3DVECTOR vPosition As D3DVECTOR vVelocity As D3DVECTOR End Type
C.3.3
DSBCAPS DirectSoundBuffer.GetCaps() Type DSBCAPS lBufferBytes As Long lFlags As CONST_DSBCAPSFLAGS lPlayCpuOverhead As Long lUnlockTransferRate As Long End Type
C.3.4
DSBPOSITIONNOTIFY DirectSoundBuffer.SetNotificationPositions(), DirectSoundCaptureBuffer.SetNotificationPositions() Type DSBPOSITIONNOTIFY hEventNotify As Long lOffset As Long End Type
C.3.5
DSBUFFERDESC DirectSound.CreateSoundBuffer()
613
614
DirectSound-Typen
Type DSBUFFERDESC lBufferBytes As Long lFlags As CONST_DSBCAPSFLAGS End Type
C.3.6
DSCAPS DirectSound.GetCaps() Type DSCAPS lFlags As CONST_DSCAPSFLAGS lFreeHw3DAllBuffers As Long lFreeHw3DStaticBuffers As Long lFreeHw3DStreamingBuffers As Long lFreeHwMemBytes As Long lFreeHwMixingAllBuffers As Long lFreeHwMixingStaticBuffers As Long lFreeHwMixingStreamingBuffers As Long lMaxContigFreeHwMemBytes As Long lMaxHw3DAllBuffers As Long lMaxHw3DStaticBuffers As Long lMaxHw3DStreamingBuffers As Long lMaxHwMixingAllBuffers As Long lMaxHwMixingStaticBuffers As Long lMaxHwMixingStreamingBuffers As Long lMaxSecondarySampleRate As Long lMinSecondarySampleRate As Long lPlayCpuOverheadSwBuffers As Long lPrimaryBuffers As Long lReserved1 As Long lReserved2 As Long lTotalHwMemBytes As Long lUnlockTransferRateHwBuffers As Long End Type
C.3.7
DSCBCAPS DirectSoundCaptureBuffer.GetCaps() Type DSCBCAPS lBufferBytes As Long lFlags As CONST_DSCBCAPSFLAGS lReserved As Long End Type
Anhang C • Typen
C.3.8
DSCBUFFERDESC DirectSoundCapture.CreateCaptureBuffer() Type DSCBUFFERDESC fxFormat As WAVEFORMATEX lBufferBytes As Long lFlags As CONST_DSCBCAPSFLAGS End Type
C.3.9
DSCCAPS DirectSoundCapture.GetCaps() Type DSCCAPS lChannels As Long lFlags As CONST_DSCCAPSFLAGS lFormats As CONST_WAVEFORMATFLAGS End Type
C.3.10 DSCURSORS DirectSoundBuffer.GetCurrentPosition(), DirectSoundCaptureBuffer.GetCurrentPosition() Type DSCURSORS lPlay As Long lWrite As Long End Type
C.3.11 DXDRIVERINFO Type DXDRIVERINFO strDescription As String strGuid As String strName As String End Type
C.3.12 WAVEFORMATEX Type WAVEFORMATEX lAvgBytesPerSec As Long lExtra As Long lSamplesPerSec As Long nBitsPerSample As Integer nBlockAlign As Integer nChannels As Integer
615
616
DirectInput-Typen
nFormatTag As Integer nSize As Integer End Type
C.4
DirectInput-Typen
C.4.1
DICONDITION Type DICONDITION lDeadBand As Long lNegativeCoefficient As Long lNegativeSaturation As Long lOffset As Long lPositiveCoefficient As Long lPositiveSaturation As Long End Type
C.4.2
DICONSTANTFORCE Type DICONSTANTFORCE lMagnitude As Long End Type
C.4.3
DIDATAFORMAT DirectInputDevice.SetDataFormat() Type DIDATAFORMAT dataSize As Long lFlags As Long lObjSize As Long numObjs As Long End Type
C.4.4
DIDEVCAPS DirectInputDevice.GetCapabilities() Type DIDEVCAPS lAxes As Long lButtons As Long lDevType As CONST_DIDEVICETYPE lDriverVersion As Long lFFMinTimeResolution As Long lFFSamplePeriod As Long lFirmwareRevision As Long
Anhang C • Typen
lFlags As CONST_DIDEVCAPSFLAGS lHardwareRevision As Long lPOVs As Long End Type
C.4.5
DIDEVICEOBJECTDATA DirectInputDevice.GetDeviceData() Type DIDEVICEOBJECTDATA lData As Long lOfs As Long lSequence As Long lTimeStamp As Long End Type
C.4.6
DIEFFECT DirectInputDevice.CreateEffect(), DirectInputEffect.SetParameters(), DirectInputEffect.GetParameters() Type DIEFFECT bUseEnvelope As Long conditionFlags As CONST_DICONDITIONFLAGS conditionX As DICONDITION conditionY As DICONDITION constantForce As DICONSTANTFORCE envelope As DIENVELOPE lDuration As Long lFlags As Long lGain As Long lSamplePeriod As Long lStartDelay As Long lTriggerButton As Long lTriggerRepeatInterval As Long periodicForce As DIPERIODICFORCE rampForce As DIRAMPFORCE x As Long y As Long End Type
C.4.7
DIENVELOPE Type DIENVELOPE lAttackLevel As Long lAttackTime As Long lFadeLevel As Long
617
618
DirectInput-Typen
lFadeTime As Long End Type
C.4.8
DIJOYSTATE DirectInputDevice.GetDeviceStateJoystick() Type DIJOYSTATE buttons(0 To 31) As Byte POV(0 To 3) As Long rx As Long ry As Long rz As Long slider(0 To 1) As Long x As Long y As Long z As Long End Type
C.4.9
DIJOYSTATE2 DirectInputDevice.GetDeviceStateJoystick2(), DirectInputDevice.GetDeviceStateJoystick() Type DIJOYSTATE2 buttons(0 To 31) As Byte frx As Long fry As Long frz As Long fslider(0 To 1) As Long fx As Long fy As Long fz As Long POV(0 To 3) As Long rx As Long ry As Long rz As Long slider(0 To 1) As Long vrx As Long vry As Long vrz As Long vslider(0 To 1) As Long vx As Long vy As Long vz As Long x As Long y As Long z As Long End Type
Anhang C • Typen
C.4.10 DIKEYBOARDSTATE DirectInputDevice.GetDeviceStateKeyboard() Type DIKEYBOARDSTATE key(0 To 255) As Byte End Type
C.4.11 DIMOUSESTATE DirectInputDevice.GetDeviceStateMouse() Type DIMOUSESTATE buttons(0 To 3) As Byte x As Long y As Long z As Long End Type
C.4.12 DIOBJECTDATAFORMAT DirectInputDevice.SetDataFormat() Type DIOBJECTDATAFORMAT lFlags As CONST_DIDEVICEOBJINSTANCEFLAGS lOfs As Long lType As CONST_DIDFTFLAGS strGuid As String End Type
C.4.13 DIPERIODICFORCE Type DIPERIODICFORCE lMagnitude As Long lOffset As Long lPhase As Long lPeriod As Long End Type
C.4.14 DIPROPLONG DirectInputDevice.SetProperty(), DirectInputDevice.GetProperty() Type DIPROPLONG lData As Long lHow As Long lObj As Long lSize As Long End Type
619
620
DirectPlay-Typen
C.4.15 DIPROPRANGE DirectInputDevice.SetProperty(), DirectInputDevice.GetProperty() Type DIPROPRANGE lHow As Long lMax As Long lMin As Long lObj As Long lSize As Long End Type
C.4.16 DIRAMPFORCE Type DIRAMPFORCE lRangeEnd As Long lRangeStart As Long End Type
C.5
DirectPlay-Typen
C.5.1
DPAPPLICATIONDESC2 Type DPAPPLICATIONDESC2 lFlags As Long strAppLauncherName As String strApplicationName As String strCommandLine As String strCurrentDirectory As String strDescription As String strFilename As String strGuid As String strPath As String End Type
C.5.2
DPCAPS Type DPCAPS lFlags As Long lHeaderLength As Long lHundredBaud As Long lLatency As Long lMaxBufferSize As Long lMaxLocalPlayers As Long lMaxPlayers As Long
Anhang C • Typen
lMaxQueueSize As Long lTimeout As Long End Type
C.5.3
DPCREDENTIALS Type DPCREDENTIALS lFlags As Long strDomain As String strPassword As String strUsername As String End Type
C.5.4
DPSECURITYDESC Type DPSECURITYDESC lCAPIProviderType As Long lEncryptionAlgorithm As Long lFlags As Long strCAPIProvider As String strSSPIProvider As String End Type
621
Anhang D Glossar
624
D.1
Alpha Blending
Alpha Blending Diese Technik erzeugt Transparenzeffekte wie zum Beispiel ein durch eine farbige Glasscheibe hindurchschimmerndes Objekt. Die Pixel auf einer solchen Glasscheibe besitzen neben der üblichen RGB – Farbinformationen (Rot/Grün/ Blau) noch einen Wert für die Transparenz, den so genannten Alpha-Channel.
D.2
Antialiasing Zur Vermeidung von hässlichen Pixeltreppen bei schrägen Linien vermischt der Grafikprozessor am Rand der beiden angrenzenden Flächen deren Farben. Dadurch erscheinen Kanten höher aufgelöst und wesentlich glatter.
D.3
Bilineares Filtering Wenn ein Polygon samt Textur nah an den Betrachter heranzoomt, werden die einzelnen Pixel enorm groß, die Szenerie wirkt dadurch sehr grob und unrealistisch. Bilineares Filtering verhindert die Bildung großer, einfarbiger Pixelblöcke, indem es die Farbwerte angrenzender Bildpunkte vermischt und so weiche, fließende Übergänge schafft. Beim Aufbringen einer Textur auf entfernte Objekte überdeckt ein Pixel meist mehrere Textur-Bildpunkte (Texel). Um durch Aliasing – Effekte verursachtes Flimmern zu verhindern, bildet man den Mittelwert aus vier oder mehr benachbarten Texeln. Je nach Filterimplementierung des Chips, Konfiguration des Treibers und Entfernung des Objekts werden zwischen einem Texel (filter to nearest, also nicht interpoliert), 2-4 Texel (linear interpoliert), 4-12 Texel (bilinear interpoliert) und 6-24 Texel (trilinear interpoliert) verwendet. Üblich sind 4 Texel ohne Mip-Mapping oder 8 Texel mit Mip-Mapping (trilinear). Über mehr Texel zu interpolieren macht Übergänge weicher, benötigt aber auch mehr Speicherzugriffe.
D.4
Bump Mapping Durch Modulation der Beleuchtung lässt sich der Eindruck von zusätzlichen räumlichen Details erwecken. Die Modulationswerte entnimmt der Pixel-Prozessor der zweiten Textur.
D.5
Clipping Bei diesem Prozess wird jedes Polygon daraufhin überprüft, ob es teilweise sichtbar ist oder ganz außerhalb des Zeichenbereichs liegt. Die nicht sichtbaren Flächen oder Teilbereiche des Objekts werden entfernt.
Anhang D • Glossar
D.6
625
Color Key Sein oder nicht sein. Im Gegensatz zu Alpha Blending arbeitet Color Key nicht mit stufenloser Transparenz, sondern mit der 1 oder 0 Strategie. Entweder muss es etwas transparent sein oder nicht. 0,5 etwa, also eine halb transparente Oberfläche, wie z.B. bei verschmutztem Wasser, gibt es nicht. Wird beispielsweise ein Baum dargestellt, ermöglicht Color Key das Definieren der Transparenten und Nicht-Transparenten Texturen. Unterstützt etwa die Karte oder deren Treiber diese Funktion nicht, werden die Stellen zwischen den sichtbaren Baumtexturen, schwarz gezeichnet.
D.7
Direct3D Direct3D ist Bestandteil von Direct X und ermöglicht den Einsatz von 3DBeschleunigern in Spielen, ohne dass die Programmierer eines Spieles für jede einzelne Karte Treiber schreiben müssen. Dies hat zur Folge, dass manche Karten nicht ihre volle Leistung ausspielen können.
D.8
DirectX Eine von Microsoft für Windows95 und Windows NT entwickelte Schnittstelle, die z.B. zur Beschleunigung von Spielen und als Treiberersatz für Grafikkarten, Soundkarten, 3D Beschleuniger usw. dient. Derzeitiger Stand ist Version 7.0.
D.9
Dithering Bei Farbtiefen unter 24 Bit pro Pixel gehen beim Rendern Farbinformationen verloren. Beim Dithern wird versucht diesen Farbfehler über mehrere Pixel zu verteilen, um so mit den Farben benachbarter Pixel Zwischenfarben zu simulieren. Die beiden gängigen Verfahren addieren entweder die fehlenden Farbanteile auf einen benachbarten Pixel (relativ genau), oder sie runden die Farbwerte je nach Position des Pixels unterschiedlich (schnell).
D.10 Double Buffer Um den Aufbau einer 3D-Darstellung zu verdecken, lässt man den Grafikchip in einem nicht sichtbaren Bereich des Bildspeichers (Backbuffer) zeichnen. Ist der Bildaufbau abgeschlossen, überträgt man die Daten in den sichtbaren Teil des Bildspeichers (Frontbuffer) oder schaltet zwischen den beiden Buffern um (Pageflipping). Durch Synchronisieren mit dem Bildwechsel beseitigt man letzte Störungen (Tearing), verliert wegen der entstehenden Wartezeiten aber etwas Performance. Einige Treiber verwenden deshalb drei Puffer in Rotation, einen zum Zeichnen, einen zum Darstellen und einen für das Pageflipping. Da man noch
626
Fenster / Full-Screen
Speicher für den Z-Buffer und Texturen braucht, geht das natürlich nur bei kleinen Auflösungen oder mit viel Speicher.
D.11 Fenster / Full-Screen Der Voodoo-Chip beherrscht in der aktuellen Implementierung (sowie auch der Voodoo2) nur den Full-Screen Modus, während andere Chipsätze 3D-Operationen auch in Fenstern (z.B. unter Windows) beschleunigen können.
D.12 Flat Shading / Gouraud Shading Während beim Flat Shading ein Dreieck einheitlich gefärbt ist, besitzt beim Gouraud Shading jede Ecke eine eigene Farbinformation. Aus der Zwischenberechnung dieser Eck-Farbwerte ergibt sich ein sehr weicher Verlauf, der sogar mit weniger Dreiecken für deutlich bessere Ergebnisse sorgt als das Flat Shading.
D.13 Fogging Die Pixel eines Objektes werden dabei mit einer festen Farbe vermischt, deren Intensität mit wachsender Entfernung zunimmt. Sorgt bei Mischung mit Weiß zum Beispiel für atmosphärische Nebeleffekte. Fogging spart außerdem Rechenzeit, da Körper erst ab einer bestimmten Distanz gezeichnet werden müssen.
D.14 Hidden Surface Removal Es wird überprüft, welche Oberflächen der Polygone für den Benutzer im Endeffekt sichtbar sein werden. Nur diese werden dann gerendert, um Rechenzeit zu sparen.
D.15 Mipmapping MIP steht für »multum in paro« (Vieles unter Gleichem) und meint die Speicherung einer Textur in verschiedenen Größenabstufungen. Man nutzt hochaufgelöste Bitmaps für nahe Objekte und kleinere für entferntere. Beim trilinearen Mipmapping wird zunächst innerhalb der nächst größeren und der nächstkleineren Textur jeweils bilinear gefiltert und schließlich zwischen diesen beiden Texeln noch einmal gemittelt. Auf diese Weise lassen sich Klötzcheneffekte im Nahbereich und Aliasing bei entfernten Objekten sehr wirkungsvoll unterdrücken.
Anhang D • Glossar
627
D.16 Overlay Planes Zusätzliche Speicherbreiche auf der Grafikkarte, in der Buttons, Fadenkreuze oder andere Grafikelemente verwaltet werden. Moderne Grafikchips enthalten eigene Funktionseinheiten zur Verwaltung dieser Planes. Diese Elemente können entgegen dem – auch bei Low-Cost-Chips vorhandenen – Hardware-Cursor zur Darstellung des Mauszeigers auch die Größe des Desktops annehmen.
D.17 Perspektivenkorrektur Texturen müssen entsprechend dem Blickwinkel und der Ausleuchtung korrekt dargestellt werden, um realitätsnah zu wirken. Jede Änderung dieser Parameter führt dabei zu einer Neuberechnung der sichtbaren Polygone.
D.18 Polygon Polygone sind Vielecke, welche u.a. die 3D-Landschaften eines Spieles bevölkern. Polygone sind lediglich Drahtgittermodelle, die erst mit Texturen belegt einen »lebendigen« Eindruck vermitteln.
D.19 Rendern Der für die Darstellung oder Visualisierung eines 3D-Objektes oder einer 3DSzenerie erforderliche Rechenprozess.
D.20 Shading Damit Texturen einen realistischeren Eindruck auf das menschliche Auge machen, werden unterschiedliche Schattierungsverfahren angewandt, die einen Farbverlauf erzeugen. Bekannte Verfahren sind: Flat Shading, was aber mittlerweile nicht oder nur noch sehr selten angewandt wird, und das heute übliche Gouraud Shading.
D.21 Specular Highlights Glanzlichter. Unter anderem Sonnenstrahlen, die von Metall oder Glas reflektiert werden. Rechenaufwendig!
D.22 Texel Ein Pixel einer Textur.
628
Texture Mapping
D.23 Texture Mapping Überlagerung eines Polygons mit einer perspektivisch korrekt dargestellten Textur.
D.24 Textur Muster, das 3D-Beschleuniger auf beliebig geformte 3D-Körper projizieren können und das ein Objekt wie eine Tapete bedecken kann. Ohne geeignete Wand-, Boden- oder Deckenverzierungen wäre ein Spiel äußerst kahl. Um dies zu ändern, setzt man Texturen ein, die dann u.a. auf Polygone »geklebt« werden.
D.25 Trilineares Filtering Um zwischen zwei Mipmaps weichere Übergänge zu schaffen, fließen in die Berechnungen eines Bildpunktes noch die Farbwerte der beiden Maps mit ein, d.h. es wird zwischen den beiden Maps interpoliert, was die nötigen Speicherzugriffe verdoppelt. Das ergibt die besten Resultate hinsichtlich der Bildqualität, ist aber auch sehr rechenaufwendig.
D.26 Wireframe Eine auch als Drahtgitter bezeichnete Darstellung, die alle Objekte auf ihren Kanten reduziert. Da nur Linien gezogen werden müssen, ist der Bildaufbau besonders schnell.
D.27 WRAM Hat wie VRAM einen zusätzlichen seriellen Ausgangsbus für die RAMDAC, ist üblicherweise etwas schneller als Ersteres, dafür ist der Videoport etwas langsamer, was aber nur bei sehr hohen Auflösungen eine Rolle spielt.
D.28 Z-Buffer Der so genannte Z-Buffer speichert die Positionierung eines Pixels auf der ZAchse (also in der Tiefe des Raumes). Bei gleicher Bildschirmposition mehrerer Pixel wird aufgrund der Tiefeninformation entschieden, ob der jeweilige Bildpunkt für den Betrachter sichtbar wäre und deshalb zu zeichnen ist oder nicht. Auf Hochleistungs-3D-Grafikhardware ist der Z-Buffer meist als seperates EDODRAM ausgeführt (Local Buffer). Bei komplexen Objekten sollte der Grafikchip Z-Werte mit einer Genauigkeit von 24 oder 32 Bit verarbeiten, um Darstellungsfehler bei feinen Details zu vermeiden.
Anhang E Das finden Sie auf der CD E.1 E.2 E.3
DirectX-API Magellan 3D Beispielprogramme
630 630 630
630
E.1
DirectX-API
DirectX-API In dem Ordner »Buchdaten/DX« finden Sie die benötigte DirectX-API für Visual Basic. Kopieren Sie die Datei in den Ordner »c:\windows\system«. Bitte beachten Sie, dass diese Datei nur dann kopiert werden muss, wenn sie in dem angegebenen Ordner fehlen sollte. Um DirectX nutzen zu können, muss es auf Ihrem System installiert sein.
E.2
Magellan 3D Im Ordner »Programme« finden Sie einen 3D-Editor inklusive 3D-Engine. Dieses Programm stellen wir als eingeschränkte Demoversion zur Verfügung. Die Vollversion können Sie bei SK-Software (02938/484750) beziehen. Ohne die Unterstützung eines ausgereiften Editors ist es quasi unmöglich, komplexere 3D-Welten zu erschaffen. Die schnelle und robuste 3D-Engine bindet die MagellanProjekte in Ihre VB-Anwendung ein.
E.3
Beispielprogramme Im Root-Verzeichnis der CD finden Sie den Ordner »Buchdaten«. Er enthält alle Quelldateien zu den Beispielprogrammen aus dem Buch. Zur besseren Übersicht haben wir fünf Unterordner angelegt:
E.3.1
•
DirectDraw
•
Direct3D
•
DirectSound
•
DirectInput
•
DirectPlay
DirectDraw DirectDraw ist für das Handling von 2D-Grafiken verantwortlich. Außer für die flache Grafikwelt ist DirectDraw auch die Grundlage für alle 3D-Anwendungen. •
Display-Mode Dieses Programm ermittelt die verfügbaren Display-Modes der installierten Grafikkarten. Es erkennt automatisch, ob eine oder mehrere Grafikkarten installiert sind.
Anhang E • Das finden Sie auf der CD
E.3.2
631
•
Blitting Mit Blitting demonstrieren wir die Hauptaufgabe von DirectDraw. Das Darstellen einer Bitmap auf dem Monitor hört sich nicht sonderlich spektakulär an, dennoch wird hiermit die Grundlage von jeder DirectDraw- und Direct3D-Anwendung geschaffen.
•
Sprites durch Transparenz Dies ist eine fensterbasierende Anwendung. Es wird eine Hintergrundgrafik dargestellt und im Vordergrund erkennen Sie ein bewegtes Sprite.
•
Fullscreen Fullscreen erfüllt die gleiche Aufgabe wie »Sprites_durch_Transparenz«. Der Unterschied besteht darin, dass wir diesesmal eine nicht fensterbasierende Anwendung erstellt haben.
•
Sprite-Animation Ein animiertes Spirte darzustellen ist nicht ganz einfach. Organisation und Technik werden mit diesem Beispielprogramm erläutert.
•
Background-Scrolling Background-Scrolling und Sprite-Animation sind die Themen dieser Anwendung. Die Kombination sorgt für das wahre Gameplaygefühl.
•
Spritekollision Ohne eine gut funktionierende Kollisionserkennung kommt wohl kein Spiel aus. Dieses Beispiel erklärt eine grobe sowie eine feine Kollisionsabfrage.
•
Zeichnen DirectDraw beherrscht nicht nur das Handling von komplexen Bitmaps, sondern stellt auch eine Reihe von einfachen Zeichentechniken bereit.
•
Bienenjagd Bienenjagd ist ein kleines Spiel, welches die Techniken von DirectDraw nutzt. Mit der Maus gehen Sie auf Bienenjagd und sammeln wertvolle Punkte für Ihre persönliche Highscore-Liste. Im Kapitel DirectPlay werden wir eine Netzwerkvariante dieses Spiels vorstellen.
Direct3D Die acht Unterordner von Direct3D beinhalten eine Sammlung von kontextbezogenen Beispielanwendungen. Direct3D ist wohl die gefragteste Schnittstelle der DirectX-Sammlung. Moderne Spiele werden fast immer mit dreidimensionalen Elementen erstellt. •
Polygone Anhand einer Vielzahl von Polygonen konstruieren Sie die gesamte 3D-Welt. Sie sind die Basis für jede Direct3D-Anwendung. Die Anwendungen verdeutlichen den Umgang mit Polygonen und geben einen Einblick in die Wichtigkeit von Matrizen sowie Vektoren.
632
E.3.3
Beispielprogramme
•
Textur Dieser Ordner enthält sieben Anwendungen, welche die Auswirkungen der verschiedenen Texture-Flags darstellen. Ein vernünftiges Texturhandling ist für viele Spezialeffekte unentbehrlich.
•
Light In diesem Ordner finden Sie ein Beispielprogramm zum Thema Licht. Ambiente-, Point-, Spot- und Direktional-Light werden hier erklärt. Als Bonus können Sie die Wirkung von Specular-Light (Glanzlichter) beobachten.
•
Material Da Material und Licht eine Einheit bilden, erhalten Sie mit diesem Beispielprogramm eine komplexe Anwendung, welche das Wechselspiel von Licht und Material veranschaulicht. Neben Material und Licht sind die eingesetzten Texturen für das Erscheinungsbild der 3D-Objekte von Bedeutung.
•
Texturfilter Mit Texturfilter sind Techniken gemeint, welche unangenehme Artefakte (Bildstörungen) beheben. Mit dem Mipmap-Demo erläutern wir eine der besten Methoden.
•
Blending Mit Blending sind Alpha Blending sowie Multiple Texture Blending gemeint. Diese Techniken werden im Regelfall für Transparenteffekte genutzt. Eine moderne Direct3D-Anwendung kommt ohne diese Techniken nicht aus.
•
Z-Buffer Der Z-Buffer ist ein Tiefenspeicher für Polygone. Er sorgt dafür, dass ein im Vordergrund liegendes Objekt nicht von einen Objekt aus dem Hintergrund verdeckt wird. Ohne ihn wäre eine Szene aus einer 3D-Welt ein wirres Durcheinander von diversen Objekten.
•
Effekte Kein anspruchsvolles Programm kann auf grafische Höchstleistungen verzichten. So gehören Effekte wie Nebel, Feuer, Blitze, Antialiasing oder Billbording eigentlich schon zum Standard. Hier zeigen wir Ihnen, wie es geht.
DirectSound Zu einem echten Multimediaprogramm gehört natürlich die passende akustische Unterstützung. Die Anwendungen zum Thema Sound werden Ihnen die verschiedenen Einsatzmöglichkeiten und Techniken vorführen. •
DSEnum Ermittelt die installierte Soundkarte.
Anhang E • Das finden Sie auf der CD
E.3.4
633
•
Beispiel 1 (abspielen einer Wavedatei *.wav) Das Laden und Abspielen einer Wavedatei ist das am häufigsten eingesetzte DirectSound-Feature. Diese Anwendung zeigt Ihnen, was Sie beachten müssen.
•
Beispiel 2 (Volumen) Die Lautstärke voll im Griff, so lautet das Motto dieses Beispiels.
•
Beispiel 3 (Balance) Mit dem Einsatz des richtigen Balanceverhaltens können Sie den Realismus einer Anwendung bestens steigern.
•
Beispiel 4 (Pitch) Durch die Manipulation der Tonhöhe werden Wavedateien der Spielumgebung angepasst. So erhalten z.B. Comicfiguren meistens eine hohe Stimmlage.
•
Beispiel 5 (3D-Sound) DirectSound bietet die fantastische Möglichkeit, Soundquellen in einem 3DRaum zu verteilen. Diese haben einen natürlichen Charakter. So werden die Quellen lauter wahrgenommen, wenn man sich ihnen nähert. Ebenfalls fließen Balance sowie Blickrichtung (Hörrichtung) in die Wahrnehmung ein.
•
Beispiel 6 (Steaming-Buffer) Bei großen Wavedateien ist es nicht ratsam, die gesamte Wavedatei in den Systemspeicher zu laden. So werden diese Dateien in kleinen Paketen eingelesen und zusammenhängend abgespielt. Dieses Beispiel erklärt die notwendige Technik.
•
Beispiel 7 (Aufnahme) Natürlich ist DirectSound auch in der Lage, Wavedateien aufzunehmen. Hier finden Sie die passende Beispielanwendung.
DirectInput Mit DirectInput werden I/O-Geräte wie Tastatur, Maus oder Joystick gehandelt. Die offene Struktur von DirectInput lässt viel Spielraum für neue Hardwareentwicklungen. Dennoch ist es möglich, mit einheitlichen Methoden verschiedenste I/O-Geräte zu kontrollieren. •
Geräteliste Dieses Programm ermittelt alle installierten Eingabegeräte. Ganz nebenbei ermittelt es die Fähigkeiten dieser Geräte.
•
Tastatur Die Abfrage der Tastatur wird immer wieder benötigt. Dieses Programm zeigt Ihnen, was alles zu beachten ist.
634
E.3.5
Beispielprogramme
•
Maus Ein weiteres Standardeingabegerät ist die Maus. Im Vergleich zu der Tastatur ermitteln wir die Mausinformationen per Call Back Funktion.
•
Ein ordentliches Spiel benötigt natürlich eine ordentliche Joystickunterstützung. Mit DirectInput wird dies fast zum Kinderspiel.
•
Bewegung In DirectX-Anwendungen werden die Eingabegeräte oft für die Bewegung der Spielerfigur genutzt. Natürlich verraten wir Ihnen wie das geht. Mit diesem Beispiel kombinieren wir die Themenbereiche Direct3D und DirectInput. So erhalten Sie eine Spielersteuerung inklusive Kollisionserkennung.
DirectPlay •
DirectPlay ist für Netzwerk- oder Internetverbindungen verantwortlich. Da mit DirectX eine Multimediaschnittstelle entstanden ist, werden diese Fähigkeiten hauptsächlich für den Spielbetrieb eingesetzt.
•
Chatsystem Der Austausch von Nachrichten ist im Spielbetrieb äußerst reizvoll. Natürlich wird das Nachrichtensystem von DirectPlay auch für Verwaltungsaufgaben genutzt. Dies wird von DirectPlay mit protokollübergreifenden Methoden umgesetzt, sodass sich der Programmierer fast nicht mehr um das eingesetzte Verbindungsprotokoll kümmern muss.
•
Sessions In diesem Beispiel dreht sich alles um eine Session. Die Anwendungen demonstrieren, wie Sie eine Session erstellen oder wie Sie erkennen, welche Sessions momentan geöffnet sind.
•
Spieler Eine Session lebt von den Mitspielern, welche der Session beitreten. Hier erfahren Sie, wie Sie einer Session beitreten oder das Beitreten eines Spielers bemerken. Natürlich erfahren Sie auch, wie Sie einen Spieler erstellen.
•
Bienenjagd Dies ist die Netzwerkvariante aus dem DirectDraw-Kapitel. Gegen einen Mitspieler kommt erst das richtige Gameplay auf.
Stichwortverzeichnis A Antialiasing 246 – Fullscreen-Antialiasing 246 – Kanten-AnPialiasing 246 B Bewegung im 3D-Raum Bit-Block-Transfer 40 Blitting 40, 48 – Timing 41
279
C Capture-Buffer 328 – erstellen 328 Chatsystem 352 Clipper-Liste 39 Clipper 39, 52 Colorkey 29, 58 Cooperative Level 25, 67 D Direct3D 101 – 3D-Primitives 105 – Anwendungen 106, 125, 127, 130, 151, 161, 166, 197, 204, 214, 230, 237, 242, 249 – Grundlagen 102 – initialisieren 106, 110 – Koordinatensystem 104 – Methoden 101, 218, 430 – Objekt-Typen 111 Direct3DDevice 114 Direct3DSound 301 – Aufnahme 328 – Ausrichtung 311 – Entfernung 307
– Geschwindigkeit 314 – Grundlagen 302 – Mode 309 – Parameter 305 – Position 310 – Schallquelle 308 DirectDraw 17 – Anwendungen 48, 60, 70, 73, 76, 84, 88, 97 – Grundlagen 22 – initialisieren 46 – Methoden 18, 390 – Objekt-Typen 23 DirectInput 253 – Anwendungen 260, 262, 268, 272 – Cooperative Level 257 – Datenformat 258 – initialisieren 254 – Joystick 262 – Methoden 253, 483 – Maus 268 – Objekt-Typen 254 – Tastatur 260 DirectPlay 337 – Adresse 363 – Anwendungen 352, 370, 372 – Chat 352 – initialisieren 341 – Lobbies 355 – Methoden 337, 505 – Multiplayer 372 – Nachrichten 359 – Objekt-Typen 338 – Protokoll 364 – Provider 358 – Session 365
636
Stichwortverzeichnis
– Sicherheit 358 – Spieler 369 DirectSound 283 – Anwendungen 296, 323, 330 – Benachrichtigung 301 – Buffer 290 – Cursor 299 – Datenformat 285 – initialisieren 287 – Methoden 283, 457 – Objekt-Typen 285 DirectSound3DBuffer 303 DirectSound3DListener 315 – Abschwächung 320 – Ausrichtung 318 – Dopplerfaktoren 317 – Entfernung 317 – Geschwindigkeit 322 – Parameter 316 – Position 320 – Verzögerung 317 Display Mode 26, 67 – auslesen 28 – restaurieren 28 – setzten 27 DoEvents 63 DoubleBuffer 19, 42 E Effekte 225 – Billboarding 236 – Explosionen 240 – Feuer 240 – Nebel 225 F Farbtiefe 29 Flipping-Chain 32 FORCC 37 Fullscreen 65 G GDI
18
H HAL 23 HEL 23 Hintergrund-Scrolling
75
I Immediate Mode 102 K Kommunikationsmodelle 355 – Client/Server 355 – Peer-to-Peer 356 Kollision 78 – echte Kollision 81 – Mustervergleich 80 – RECT-Kollision 82 L Lautstärke 294 Licht 137 – aktivieren / deaktivieren 148 – Directional Light 143 – indirektes Licht (Ambientlight) 139 – Pointlight 141 – Spotlight 144 Lobbies 357 M Material 157 – ambient 157 – diffuse 157 – Emission 159 – Material setzen 159 – Normalvektor 158 – Specular Reflektion 159 Methoden, Direct3D 101 – BeginScene() 109, 434 – Clear() 109, 436 – CreateDevice() 106, 431 – DrawPrimitive() 110, 438 – EndScene() 110, 440 – GetCaps() 247, 440 – GetDeviceEnum() 113, 432
Stichwortverzeichnis
– GetLight() 150, 442 – GetLightEnable() 150, 442 – GetMaterial() 160, 442 – LightEnable() 149, 446 – SetLight() 149, 448 – SetMaterial() 160, 448 – SetTexture() 165, 450 – SetTransform() 107, 451 – SetViewPort() 107, 451 Methoden, DirectDraw 18, 43, 390 – Blt() 18, 40, 412 – BltColorFill() 41, 413 – BltFast() 18, 40, 51, 413 – BltFx() 41, 414 – BltToDC() 41, 414 – CreateClipper() 23, 51, 391 – CreatePalette() 23, 417 – CreatePalette() 39, 392 – CreateSurface() 18, 23, 44, 392 – CreateSurfaceFromFile() 23, 44, 392 – CreateSurfaceFromResource() 23, 392 – DrawBox() 93, 415 – DrawCircle() 93, 415 – DrawEllipse() 93, 416 – DrawLine() 93, 416 – DrawRoundedBox() 94, 416 – DrawText() 66, 94, 416 – Flip() 18, 42, 66, 417 – GetAttachedSurface 65, 417 – GetDirect3D() 113, 394 – GetDisplayMode() 28, 79, 395 – GetDisplayModesEnum 26, 395 – GetEntries() 39, 409 – GetLockedArray() 79, 422 – GetSurfaceDesc() 65, 424 – GetWindowsRect() 44, 398 – Lock() 34, 78, 424 – RestoreDisplayMode() 28, 66, 398 – SetClipper() 51, 425 – SetColorKey() 58, 425 – SetCooperativeLevel() 25, 44, 399 – SetDisplayMode() 27, 65, 399 – SetDrawStyle() 95, 425
637
– SetDrawWidth() 95, 426 – SetEntries() 39, 410 – SetFillColor() 95, 426 – SetFillStyle() 95, 426 – SetFont() 96, 427 – SetFontBackColor() 96, 427 – SetFontTransparency() 96, 427 – SetForeColor() 96, 428 – SetOverlayPosition() 35,428 – SetPalette() 39, 429 – TestCooperativeLevel() 25, 399 – Unlock() 79, 429 – UpdateOverlayZOrder() 36, 430 Methoden, DirectInput 483 – Acquire() 261, 485 – CreateDevice() 257, 483 – GetCount() 264, 502 – GetDeviceObjectsEnum() 265, 487 – GetDeviceStateKeyboard() 262, 489 – GetDiEnumDevices() 256, 484 – Poll() 268, 491 – SetCommonDataFormat() 259, 492 – SetDataFormat() 259, 493 Methoden, DirectPlay 337, 505 – CreateMessage() 349, 514 – CreatePlayer() 348, 510 – CreateSessionData() 345, 507 – GetAddress() 344, 537 – GetCount() 342, 525, 526 – GetDPEnumConnections() 342, 506 – GetDPEnumSessions() 345, 507 – GetItem() 345, 529 – GetMessageCount() 350 – GetName() 342, 525, 526 – InitializeConnection() 344, 506 – Open() 346, 508 – ReadLong() 350, 542 – ReadString() 350, 543 – Receive() 350, 515 – Send() 349, 515 – SetFlags() 347, 539 – SetMaxPlayers() 346, 550 – SetSessionName() 346, 550
638
– WriteLong() 349, 545 – WriteString() 349, 546 Methoden, DirectSound 457 – CommitDeferredSettings() 306, 467 – CreateCaptureBuffer() 328, 478 – CreateSoundBuffer() 323, 458 – CreateSoundBufferFromFile() 323, 458 – GetAllParameter() 305, 461, 467 – GetCaps() 328, 459, 473 – GetConeAngles() 311, 461 – GetConeOrientation() 312, 461 – GetConeOutsideVolume() 312, 462 – GetCount() 287, 482 – GetCurrentPosition() 300, 473 – GetCurrentPosition() 330, 479 – GetDescription() 287, 482 – GetDirectSound3DBuffer() 324, 473 – GetDirectSound3DListener() 308, 462, 473 – GetDirectSoundBuffer() 308, 462, 468 – GetDistanceFactor() 311, 468 – GetDopplerFactor() 317, 468 – GetGuid() 287, 482 – GetMaxDistance() 307, 462 – GetMinDistance() 307, 463 – GetMode() 309, 463 – GetName() 287, 483 – GetOrientation() 318, 468 – GetPan() 295, 474 – GetPosition() 310, 463, 469 – GetRolloffFactor() 320, 469 – GetStatus() 331, 480 – GetVelocity() 314, 463, 469 – GetVolumen() 296, 475 – Play() 299, 475 – ReadBuffer() 328, 479, 480 – SetAllParameter() 305, 464, 469 – SetConeAngles() 312, 464 – SetConeOrientation() 312, 464 – SetConeOutsideVolume() 313, 465 – SetCooperativeLevel() 288, 460 – SetCurrentPosition() 300, 470, 476 – SetDopplerFactor() 317, 470
Stichwortverzeichnis
– SetFrequency() 295, 476 – SetMaxDistance() 307, 465 – SetMinDistance() 307, 465 – SetMode() 309, 466 – SetOrientation() 318, 470 – SetPan() 295, 477 – SetPosition() 310, 466, 471 – SetRolloffFactor() 321, 471 – SetVelocity() 315, 466, 471 – SetVolume() 295, 477 – Start() 329, 481 – Stop() 300, 477 – Stop() 329, 481 – WriteBuffer() 329, 478, 481 Methoden, DirectX7 18, 23, 378 – CreateD3DVertex() 108, 380 – CreateEvent() 265, 381 – DirectDrawCreate() 18, 23, 43, 382 – DirectInputCreate() 256, 383 – DirectPlayCreate() 341, 383 – DXCallback() 263, 390 – IdentityMatrix() 107, 385 – ProjectionMatrix() 108, 385 – RotateXMatrix() 123, 386 – RotateYMatrix() 123, 386 – RotateZMatrix() 124, 386 – ViewMatrix() 107, 390 Mode X, Mode 13 29, 67 Multiplayer 372 N Nachrichten 359 – auswerten 362 – empfangen 360 – Spielernachrichten 362 – Systemnachrichten 361 Nebel 225 – D3DFOG_LINEAR 226 – EXP 226 – EXP2 226 – Pixel Fog 228 – Vertex Fog 227
Stichwortverzeichnis
P Page-Flipping 31, 41 Palette 38 Performance 20, 50 – Optimierungsregeln 20 Pitch 33 Polygone 132 – Pointlist 132 – Linelist 133 – Linestrip 134 – Trianglelist 134 – Trianglestrip 135 – Trianglefan 136 Projection-Matrix 120 R RAMDAC 20. 42 RECT 48 RECT-3D 114 Retained Mode 103 Rotation 123 S S3TC-Algorithmus 36 Scaling 130 SetRenderState 218 Shading 146 – Flat 146 – Gouraud 147 Soundaufnahme 328 SoundBuffer 290 – erzeugen 292 – Primär 291 – Static 291 – Streaming 291 Sprite 51 – Animation 72 – Bewegung 64 – Kollision 78 Stereo 295, 303 Surface 30 – Backbuffer 18 – Client Memory Surface 33
639
– Complex Surface 31, 67 – Compressed Texture Surface 36 – Offscreensurface 18, 30 – Overlay Surface 35 – Primärsurface 18, 30 – Wide Surface 32 Systemspeicher 62 T Texture-Blending 201 – Alpha Textur Blending 202 – Multiple Textur Blending 206 Texture-Filtering 184 – Anisotropic Tectur Filtering 187, 191 – Linear Textur Filtering 186, 189 – Mip-Mapping 187, 192 – Nearest Point Sampling 186, 187 – Trilineares Filtering 187 Texturen 165 – ausschneiden 176 – Blending 201 – Border 183 – Clamp 181 – Filtering 184 – Mirror 180 – stauchen 175 – Textur-Koordinaten 170 – Warp 176 Top-Left-Filling-Convention 118 Triple-Buffer 19, 42 V Videospeicher 20, 62 View-Matrix 120 W Wide 33 WinG 18 World-Matrix
120
Z Z-Buffer 212 Zeichnen 93, 97