ATTENTION READERS! Lucky's VB Gaming Site is no longer active. For updated game programming information and tutorials, please visit The Game Programming Wiki!
Ändern der Darstellung mit der "Gamma Contol"
Zieht euch eure Windeln an, weil ihr kurz davor seit euch in
die Hosen zu machen. Ich habe das "GammaControl"-Objekt
entschlüsselt, welches in DirectX7 enthalten ist, und habe jetzt
die Möglichkeit die ausgegebenen Bildschirmfarben nach belieben
zu verändern. Ich kann Einblenden, Ausblenden und den Rot-,
Blau-, Grünkanal oder eine beliebige Farbkombination
herauszufiltern. Ich kann Lichtblitze erzeugen (so wie das rote
Aufleuchten des Bildschirmes, wenn ihr in Quake getroffen werdet)
und jede Menge andere coole Sachen. Na, habt ihr euch schon nass
gemacht?
Es gab ein paar Hindernisse, die VB-Programmierer davon
abgehalten haben, "GammaControl" zu benutzen. Der
Hauptgrund war der, dass die sog. "Gamma Ramps"
Datenfelder sind, die sog. "unsigned" Integer-Variablen
enthalten. Visual Basic unterstützt diese "unsigned"
Integer aber nicht, also habe ich zwei schöne kleine Funktionen
geschrieben, die diese Konvertierung übernehmen:
Public Function ConvToUnSignedValue(intValue As Integer) As Long
If intValue >= 0 Then
ConvToUnSignedValue = intValue
Exit Function
End If
ConvToUnSignedValue = intValue + 65535
End Function
Public Function ConvToSignedValue(lngValue As Long) As Integer
If lngValue <= 32767 Then
ConvToSignedValue = CInt(lngValue)
Exit Function
End If
ConvToSignedValue = CInt(lngValue - 65535)
End Function
Wie ihr sehen könnt, reicht ein "unsigned" Integer
von 0 bis 65355, wobei ein "signed" Integer von -32767
bis 32767 reicht. Ja, es ist die gleiche Anzahl an Werten, aber
die Bits werden anders interpretiert. Wenn wir die
"GammaControl" verwenden, erhalten wir
"unsigned" Integer als Daten zurück. Visual Basic
interpretiert diese jedoch als "signed" Integer und die
Daten sind falsch. Jeder Wert unter 32767 wird zwar richtig
behandelt, aber jedes Ergebnis darüber (z. B. 32768 bis 65535)
werden das negative Gegenteil ergeben. Die Funktionen oben
korrigieren diese Fehler. Sicherlich hätte ich sie eleganter
schreiben können (vielleicht unter verwendung von Hexzahlen)
aber sie erfüllen ihre Aufgabe gut genug.
Halten wir dieses Wissen also im Hinterkopf und fahren fort.
Es wäre empfehlenswert, sich erst zu versichern, ob die Hardware
"GammaRamp"-Unterstützung bietet, bevor wir weiter
gehen:
Dim dx As New DirectX7
Dim dd As DirectDraw7
Dim hwCaps As DDCAPS
Dim helCaps As DDCAPS
Set dd = dx.DirectDrawCreate("")
dd.GetCaps hwCaps, helCaps
If (hwCaps.lCaps2 And DDCAPS2_PRIMARYGAMMA) = 0 Then
MsgBox "Your system does not have Gamma Ramp Support", vbOKOnly, "No Gamma Support"
End
End If
Dieser Code erstellt das DirectDraw-Objekt und überprüft
dann seine Fähigkeiten. Wenn die
DDSCAPS2_PRIMARYGAMMA-Fähigkeit nicht inerhalb der hwCaps.lCaps2
vorhanden ist, dann erscheint eine Fehlermeldung, und das
Programm wird beendet.
Jetzt, da der Computer den Test bestanden hat, können wir die
Primary Surface und eine "GammaControl"
erstellen.Beachtet, dass die "GammaControl" NUR auf
eine Primary Surface angewendet werden kann. Der folgende Code
setzt voraus, das eine Primary Surface bereit korrekt
eingerichtet wurde:
Dim GammaControler As DirectDrawGammaControl
Set GammaControler = Primary.GetDirectDrawGammaControl
Es gibt zwei Dinge, die ihr mit der "GammaControl"
anstellen könnt, sobald sie erstellt wurde:
"GetGammaRamp" und "SetGammaRamp". Benutzt
"GetGammaRamp" um den derzeitigen Status des
Bildschirms festzustellen. Benutzt "SetGammaRamp" um
den derzeitigen Status des Bildschirms zu verändern. Einfach
genug... also lasst uns erstmal zwei DDGAMMARAMP-Objekte
erstellen. Eines werden wir dazu verwenden, um die
ursprünglichen Bildschirmeinstellungen zu sichern, und mit dem
anderen werden wir den Bildschirm so anpassen wie es uns
gefällt:
Dim GammaRamp As DDGAMMARAMP
Dim OriginalRamp As DDGAMMARAMP
GammaControler.GetGammaRamp DDSGR_DEFAULT, OriginalRamp
Jetzt haben wir die derzeitigen Bildschirm-GammaRamp-Daten in
unsere "OriginalRamp"-Variable geschrieben. Es ist
wichtig, diese Kopie der Originalbildschirmdaten zu erhalten, da
das Anwenden einer nicht linearen GammaRamp zu unerwarteten
Ergebnissen führen kann, falls das System keine
GammaCalibration-Unterstützung aufweist (die lCaps2
DDCAPS2_CANCALIBRATEGAMMA flag). Der Code oben verwendet
die DDSGR_DEFAULT flag anstatt der DDSGR_CALIBRATE flag,
da einige Computer keine Unterstützung für die Kalibration
aufweisen (natürlich könnten wir diese Fähigkeiten, wie oben
gezeigt abfragen und nutzen, falls vorhanden). Für unsere Zwecke
werden einfache lineare GammaRamps ausreichen. Der einfachste Weg
um diese zu erstellen ist, dass man einfach einen prozentualen
Anteil der original GammaRamp-Werte verwendet. Die folgende
Routine wird die GammaRamp-Werte des Bildschirms um einen
steigenden Prozentsatz ändern:
Public Sub SetGamma(bytRed As Byte, bytGreen As Byte, bytBlue As Byte)
Dim i as Integer
For i = 0 To 255
GammaRamp.red(i) = ConvToSignedValue(ConvToUnSignedValue(OriginalRamp.red(i)) * bytRed / 100)
GammaRamp.green(i) = ConvToSignedValue(ConvToUnSignedValue(OriginalRamp.green(i)) * bytGreen / 100)
GammaRamp.blue(i) = ConvToSignedValue(ConvToUnSignedValue(OriginalRamp.blue(i)) * bytBlue / 100)
Next
GammaControler.SetGammaRamp DDSGR_DEFAULT, GammaRamp
End Sub
Das DDGAMMARAMP-Objekt besteht aus drei Datenfeldern, einer
für jeden Farbkanal. Diese Arrays enthalten "unsigned"
Integer, die einer bestimmten Ausgabe entsprechen, welche
erstellt wird, wenn ein Wert übergeben wird. Durch das
Verändern dieser Werte um einen prozentualen Anteil erhalten wir
die Linearität, die für konstante, gleichbleibende Ergebnisse
unerlässlich ist. Zum Beispiel bewirkt das Aufrufen von
"SetGamma 50, 50, 50" die Verringerung der Intensität
aller Farben um die Hälfte (halb abgeblendet). Durch das
Aufrufen von "SetGamma 100, 0, 0" würden wir alle
Farben außer den Rotfarbtönen entfernen, eine Überblendung auf
Rot.
Der technische Aspekt der mit der Benutzung der
"GammaControl" verbunden ist, könnte jetzt zwar etwas
entmutigent klingen, aber ich versichere euch, es ist wirklich
einfach. Schaut euch einfach das Beispielprojekt
an, und ihr werdet erkennen wie leicht es ist.