ZFX
ZFX Neu
Home
Community
Neueste Posts
Chat
FAQ
IOTW
Tutorials
Bücher
zfxCON
ZFXCE
Mathlib
ASSIMP
NES
Wir über uns
Impressum
Regeln
Suchen
Mitgliederliste
Membername:
Passwort:
Besucher:
4440681
Jetzt (Chat):
19 (0)
Mitglieder:
5239
Themen:
24223
Nachrichten:
234554
Neuestes Mitglied:
-insane-
ZFX - KurzartikelDruckversion

16 – Bit Farben mit DirectDraw
Der Kurzartikel von Daniel Lang

© Copyright 2002 [whole tutorial] by Daniel Lang
Die Texte der Tutorials unterliegen dem Copyright und drfen ohne schriftliche Genehmigung vom Author weder komplett noch auszugsweise vervielfltigt, auf einer anderen Homepage verwendet oder in sonst einer Form verffentlicht werden. Die zur Verfgung gestellten Quelltexte hingegen stehen zur freien Weiterverwendung in Software Projekten zur Verfgung.
Die Quelltexte dieses Tutorials werden auf einer "as is" Basis bereit gestellt. Der Autor bernimmt keinerlei Garantie fr die Lauffhigkeit der Quelltexte. Fr eventuelle Schden die sich aus der Anwendung der Quelltexte ergeben wird keinerlei Haftung bernommen.


16 Bit Farben mit DirectDraw

( Daniel Lang alias Fireface, powered by www.game-developers.net )

 

Obwohl sich schon seit langem 32 Bit bei 3D-Spielen standardisiert hat, verwenden die meisten 2D Titel auf dem Markt immer noch 16 Bit Farbtiefe.

Der Grund ist neben der einfacheren Handhabung und der geringeren Speicheranforderung der, dass die mit 16 Bit darstellbaren 65.536 verschiedenen Farben fr ein schnes 2D-Spiel bei weitem ausreichend sind.

Da viele Umsteiger von 8 Bit anscheindend groe Probleme haben, werde ich in diesem Tutorial versuchen die Verwendung von 16 Bit Farbtiefe mit Hilfe von DirectDraw zu erklren,

denn so einfach wie es Stefan Zerbst in seinem Buch gemacht hat ist es in der Realitt schon lange nicht mehr.

Die Folge dieses Fehlers ist dann, dass das fertige Spiel bei manchen Grafikkarten vllig falsche Farben aufweist.

 

Das Problem:

Genau wie bei der Verwendung von 8 Bit (= 255 verschiedene Farben) wird bei 16 Bit Farbtiefe fr jedes Pixel auf dem Bildschirm ein Wert gespeichert.

Bei 8 Bit reicht dieser von 0-255 und jede Zahl gibt eine Farbe an.

Bei der Verwendung von 16 Bit wird eine Farbe durch 3 Faktoren angegeben.

Nmlich durch den Rot-, Grn- und Blauanteil einer Farbe.

Damit htten wir nun 3 verschiedene Zahlen, die es nun gilt in einen 16-Bit Wert unter zu bringen, und auch daraus wieder herauszunehmen.

Wie der Name schon sagt, besteht dieser Wert aus 16 Bits die sich die 3 verschiedenen Zahlen nun teilen mssen.

Da aber 16 dividiert durch 3 einen Rest von 1 ergibt, und man dieses Bit nicht verschenden mchte, muss man einen Farbwert (Rot, Grn oder Blau) bevorzugen und ihm ein Bit mehr zur verfgung stellen:

 

RRRRRGGGGGGBBBBB

 

Dieses Format nennen wir das 5-6-5 Format, da Rot 5, Grn 6 und Blau 5 Bits bekommt.

 

Jetzt mssten wir also nur mehr die 3 Farbwerte aus dem 16-Bit Wert extrahieren.

Leider ist es nicht ganz so einfach, denn es ist jeder Grafikkarte selbst berlassen, welches Format sie verwendet.

So knnte eine Radeon z.B. das 5-5-6 oder das 6-5-5 Format verwenden, whrend die Geforce 3 5-6-5 verwendet.

Das Problem liegt also auf der Hand, wir mssen herausfinden welches Format die Grafikkarte verwendet und dann die 16 Bit-Farben Grafikkarten-spezifisch umzurechnen, damit gewhrleistet ist, dass eine vom Spieleentwickler definierte Farbe immer gleich auf dem Bildschirm aussieht, egal welche Grafikkarte im Computer steckt.

 

Bevor wir jedoch it dem eigentlichen Arbeit beginnen, kommt zuerst noch etwas Theorie ber Bitmasken und Shifting, die ntig fr das weiter verstndnis ist.

 

Bitmasken

In diesem Kapitel werde ich versuchen zu erklre was Bitmasken sind, und wozu man sie verwendet. Wenn Sie bereits darber ausreichend Bescheid wissen, knnen sie dieses Kapitel berspringen.

 

Angenommen wir htten ein 5-6-5 Format, dann knnten die einzelnen Farbwerte folgendermaen aussehen:

rot: 5 Bits, 00011

grn: 6 Bits, 001011

blau: 5 Bits, 00101

 

Der fertige 16 Bit-Wert wrde hier folgendermaen aussehen.

 

0001100101100101

 

Wenn wir nun die einzelnen Farbwerte aus diesem 16-Bit Wert extrahieren wollen, kommen die Bitmasken ins Spiel.

Fr jeden Farbwert bentigen wir eine Bitmaske.

Diese sind in unserem Fall ebenfalls 16-Bit Werte/ bzw. Gebilde, die berall dort eine 1 haben wo wir das Bit extrahieren wollen.

 

Eine Bitmaske fr rot knnte z.B. so aussehen:

 

1111100000000000

 

Oder fr Grn:

 

0000011111100000

 

Toll, jetzt haben wir die Bitmasken, von denen wir wissen wie sie aussehen mssen, knnen aber noch nichts damit anfangen. Also ndern wir diesen Misstand schleinigst.

Damit wir nun mit Hilfe der Bitmasken einzelne Bits aus dem Pixel-Wert extrahieren knnen, bentigen wir den logischen Operator &. Ich setze hier vorraus, das man weis wie dieser Operator funktioniert und das man mit ihm umgehen kann. Sonst hilft nachlernen im alten C++ Buch sicher weiter.

Wenn wir jetzt also eine Bitmaske auf unseren 16-Bit Pixel-Wert mittels des &-Operators anwenden kommt folgendes raus:

 

0001100101100101 & // 16-Bit Pixel Wert

0000011111100000 // Bitmaske fr den grnen Farbanteil

0000000101100000 // Neuer 16 Bit-Wert mit grnen Farbanteit

 

Der neue erhaltene Wert beinhaltet in diesem Fall den grnen Farbanteil.

Das ganze funktioniert mit der Bitmasken fr Rot und Blau natrlich genauso.

 

Einen Haken hat der neue Wert allerdings noch, denn wenn wir jetzt diesen Wert verwenden, so ist dies noch kein gltiger Wert mit dem wir etwas anfangen knnten. Mehr dazu im nchsten Kapitel.

 

Shifting

 

Nachdem wir nun den grnen Farbanteil mittels Bitmasking erfolgreich extrahiert haben, mssen wir feststellen, das wir mit dem erhaltenen Wert noch nichts anfangen knnen.

Sehen wir uns den Wert nochmal genauer an um feststellen zu knnen was nicht stimmt:

 

0000000101100000

 

Richtig! Die Bits die den Farbwert angeben liegen noch an der falschen Stelle.

Bei Zahlen im Bit (Binr) Format muss der eigentliche Wert immer ganz rechts liegen.

Wir mssen jetzt also die fett markierten Bits irgendwie ganz nach rechts bringen.

 

Dazu verwenden wir die Shifting Operatoren >> (fr einen Rechtsverschiebung) und << (fr eine Linksverschiebung).

Nun zhlen wir mal die Anzahl der Bits um die wir nach rechts verschieben wollen.

5 also:

 

0000000101100000 >> 5 =

0000000000001011

 

So, jetzt haben wir einen gltige Zahl, die hier den Grnanteil einer frei gewhlten 16-Bit Farbe reprsentiert.

 

Herausfinden des Pixelformats

Nach diesen kleinen Theorie-Exkurs gehts wieder ans Eingemachte von DirectDraw.

In diesem Kapitel werden wir also versuchen herauszufinden in welchen Format die installierte Grafikkarte 16-Bit Pixel verwendet.

 

Hierbei geht es fr manchen erstaunenderweise nicht darum herauszufinden welches der 3 Formate verwendet wird, sondern wir werden uns Variablen anfertigen, die wir fr die Errechnung eines Pixel-Wertes aus den einzelnen Farbanteilen bentigen.

 

Schauen wir uns doch mal die Methoden eines DirectDraw Surfaces (V. 7) an.

Hier gefllt uns die Methode GetPixelFormat besonders gut und wer htte das gedacht, sie fllt in ihrem Aufruf eine Struktur vom Typ DDPIXELFORMAT.

Der Aufruf gestaltet sich hier unspektakulr einfach:

 

DDPIXELFORMAT ddpf;

ZeroMemory (&ddpf, sizeof(ddpf));

ddpf.dwSize = sizeof (ddpf);

lpDDS->GetPixelFormat (&ddpf);

 

So, jetzt haben wir die Struktur gefllt (solange kein Fehler aufgetreten ist) und erfreuen uns der reichlichen Informationen.

Fr unsere Zwecke bentigen wir aber nur die Felder dwRBitMask, dwGBitMask und dwBBitMask. Diese beinhalten nur die Bitmaske wie wir sie bereits kennen fr den jeweiligen Farbwert. Diese Farbwerte speichern wir wegen unserer Tipp-Faulheit erst mal um.

 

DWORD dwRMask = ddpf.dwRBitMask;

DWORD dwGMask = ddpf.dwGBitMask;

DWORD dwBMask = ddpf.dwBBitMask;

 

Nun ist es unser Ziel herauszufinden wie weit wir die einzelnen Farbwerte von rechts nach links einrcken mssen.

Anders gesagt, wir suchen einfach die Anzahl Nullen rechts von den Einsen in der Bitmaske.

 

z.B.

0000011111100000

Von den hier fett makierten Bits wollen wir also die Anzahl wissen, denn die gibt zugleich an um wieviele Bits wir spter den Farbwert (in dem Fall Grn) nach links rcken mssen.

 

Lange rede - kurzer Sinn, wir shiften in einer Schleife die Bitmasken einfach so lange nach rechts bis das letzte Bit 1 ist, und zhlen zugleich die jeweilige Variable mit.

 

DWORD dwR_SHL = 0; // Anzahl der Shifts nach links fr Rot

DWORD dwG_SHL = 0;

DWORD dwB_SHL = 0;

 

while ((dwRMask & 1) == 0)

{

dwRMask >>= 1;

dwR_SHL++;

}

 

while ((dwGMask & 1) == 0)

{

dwGMask >>= 1;

dwG_SHL++;

}

 

while ((dwBMask & 1) == 0)

{

dwBMask >>= 1;

dwB_SHL++;

}

 

Jetzt haben wir also schon das wichtigste hinter uns, wir haben die Anzahl der bentigten Links-Verschiebungen in den drei Variablen dwR_SHL, dwG_SHL und dwB_SHL gespeichert. Wir mssen jetzt also nur mehr die einzelnen Farbwerte nach links verschieben, und die Bits mittels des inclusiven OR-Operators (= | ) setzen. Hier setze ich wieder voraus, das jeder mit diesem Operator bestens vertraut ist.

Demnach knnten wir jetzt eine 16-Bit Farbwert folgendermaen definieren:

 

Pixel = (Rotanteil << dwR_SHL) | (Gruenanteil << dwG_SHL) |

(Blauanteil << dwB_SHL);

 

So einfach wrde es gehen wenn die einzelnen Farbanteile in Variablen mit schn passender gre gespeichert wren, also z.B. die Blauanteilvariable mit 5 Bit oder die Gruenanteilvariable mit 6 Bit,.

In der Praxis, allerdings, werden die einzelnen Farbanteile alle in dem gleichen Variablentyp gespeichert, nmlich einem mit 8 Bits bzw. 1 Byte.

Deshalb besteht aber das Problem, dass die Farbanteile in ihrer Variable zu weit links stehen, um von uns verwendet werden zu knnen.

Wir mssen also noch fr jeden Farbanteil ein Rechts-Shifting durchfhren, bevor wir dann endlich so wie oben richtig nach links shiften drfen.

 

Damit wir aber wissen wie weit wir die einzelnen Werte zuerst nach rechts shiften mssen, helfen uns wie so oft die 3 Bitmasken von vorher.

Zu beachten ist allerdings, das wir die Bitmasken in den schon von uns vernderten Bits verwenden.

Um jetzt die Anzahl der bentigten Rechts-Shifts fr die Farbanteil-Variablen herauszufinden, shiften wir die Bitmasken in einer Schleife solange nach rechts bis das letzte Bit 0 ist.

Anders gesagt suchen wir einfach die Anzahl der Einsen in der Bitmaske.

 

z.B.

0000000000111111

Wir wollen von den hier fett markierten Bits die Anzahl wissen, denn diese ist von Bedeutung um die Anzahl der bentigten Rechts-Shifts herauszufinden.

 

Da wir unsere Farbanteile in einer 8-Bit Farbe speichern, mssen wir demnach die Anzahl der bentigten Rechts-Shifts von 8 runterzhlen um die richtige Anzahl zu erhalten.

 

DWORD dwR_SHR = 8; // Anzahl der bentigten Shifts nach rechts

DWORD dwG_SHR = 8;

DWORD dwB_SHR = 8;

 

while ((dwRMask & 1) == 1)

{

dwRMask >>= 1;

dwR_SHR--;

}

 

while ((dwGMask & 1) == 1)

{

dwGMask >>= 1;

dwG_SHR--;

}

 

while ((dwBMask & 1) == 1)

{

dwBMask >>= 1;

dwB_SHR--;

}

 

So, nun haben wirs geschafft. Einen 16 Bit Wert zu berechnen ist nach dieser Initialisierung der bentigten Variablen nicht mehr schwer:

 

Pixel = ((Rotanteil>>dwR_SHR) << dwR_SHL) |

((Gruenanteil>>dwR_SHR) << dwG_SHL) |

((Blauanteil>>dwB_SHR) << dwB_SHL);

 

Idealerweise packt man den ganzen Code von vorher in eine Funktion, macht die bentigten Variablen (dwR_SHR, dwG_SHR, dwB_SHR, dwR_SHL, dwG_SHL, dwB_SHL) global und bastelt sich ein Makro, das die ganzen Shifterei erledit.

 

Noch Fragen? Dann wendet euch per E-Mail an mich.

Fireface1@hotmail.com

 

m.f.G.

Daniel Lang



Informationen: " ); ?> " ); ?> " ); ?> " ); ?>
WWW :$wwwtitel
Data:Projektdateien
Mail:$author ($email)
Nick:$nick