RGB im 256-Farbenmodus 1/10
Hintergrundwissen / Design und Technik
Worum geht's?
In vielen Grafikmodi stehen nur 256 Farben zur verfügung, z.B. 'SCREEN 13'. Wenn sie jemals mit mehr Farben gearbeitet habenalso mit 65536 oder sogar 16777216 Farben, haben Sie sicher bemerkt, das man Farben als RGB-Wert angibt (z.B. verwenet man bei der Future.Lib die Funktion RGB2Color(r, g, b)). Wenn Sie jemals mit solchen RGB-Werten gearbeitet haben, wllen sie nicht mehr ohne arbeiten. Man muss nicht darüber nachdenken, welcher Index welcher Farbe entspricht. Man mischt die Farbe einfach aus eine rot, einer grün und einer blauen Komponente. Dadurch ist Transparenz kein Problem mehr. Man nimmt einfach die drei Komponnenten der bereits vorhandenen Farbe und die der neuen Farbe, mischt Sie und erhält die Farbe, die so ausieht, als wäre der neue Punkt trnsparent. 'neuesRot = vorhandenesRot * a + zuMalendesRot * (1 - a)' genauso vrfährt man mit den anderen Farben. 'a' ist der Grad der Tansparenz zwischen 0 und 1.
Paletten
Um RGB-Werte zu verwenden müssen wir eine neue Palette erstellen, damit sich der Index einfach aus den drei Komponenten berechnen lässt.
Wir haben 256 Farben und drei Werte, aus denen wir den Index berechnen. Der erste Ansatz sieht natürlich so aus: Wir ziehen einfach die dritte Wurzel und erhalten '6,34960420787279789900682255708923...' (die Genauigkeit ist natürlich Blödsinn :P ). Also können wir 6 Werte für die drei Komponenten verwenden. '6 * 6 * 6 = 216'. Als verwenden wir 216 Farben. Wir könnten die Anzahl erhöhen, indem wir einen der Werte von 0 bis 7 laufen lassen. '6 * 7 * 6 = 252', also werden nur nch vier Farben verschwendet, statt wie vorher 40.Aber wir hätten 6 rot-, 7 grün- und 6 blau-Werte. Ich habe grün gewählt, weil das Menschliche auge auf grün besnders empfindlich reagiert. Aber die Palette hat einen großen Nachteil: Es gibt kein richtiges grau, da 7 kein ganzzahliges vielfaches von 6 ist.
Gibt es nicht noch einen anderen Weg die 256 Farben aufzuteilen? Natürlioch gibt's die. Wir könnten uns beispielsweise mal die Bits ansehen. Man benötigt 8 Bits um 256 Farben darzustellen (28 = 256). Die könnten wir in 3 Bit + 3 Bit + 2 Bit aufteilen (Rotabstufungen sind wichtiger als Blauabstufungen für den Menschen). Rot und grün haben je 23 = 8 verschiedene Werte, blue 22 = 4. Der Vorteil dieser Palette ist, das alle 256 Farben verwendet werden.
Allerdings sind 4 Wete für blau recht wenig. Wenn in ihren Bildern mehr Rot, grün, gelb und / oder braun vorkommt ist die Palette passabel. Für blau, violett und cyan ist die Palette hingegen überhauptnicht geeignet. Man kann die Palette natürlich anders Verteilen, also z.B. 4 Bit Rot und je 8Bit für Grün und blau, wodurch die Aussage von eben quasi umkehrt.
Ich schlage jedoch vor die erste Palette mit je 6 Werten für die Kmponenten zu verwenden. Die 40 übrigen Farben können für irgendwelche Spezialeffekte verwendet werden
Die Palette
Natürlich verwenden wir, wie im Tipps-Kapitel gelernt direkt die Ports 3C8h und 2C9h statt 'PALETTE'. Das heißt, wir brauchen Werte zwischen 0 und 63. Wir haben Werte zwischen 0 und 5 (6 Werte). Also ist der Umrechnungsfaktor 63 / 5.
DEFINT A-Z SUB SetRGBPalette DIM faktor AS SINGLE faktor = 63 / 5 DIM i AS INTEGER FOR r = 0 TO 5 FOR g = 0 TO 5 FOR b = 0 TO 5 OUT &H3C8, i OUT &H3C9, CINT(b * faktor) OUT &H3C9, CINT(g * faktor) OUT &H3C9, CINT(b * faktor) i = i + 1 NEXT NEXT NEXT END SUB
Jetzt haben Sie die gewünschte palette. Falls Sie die 8*8*4 Palette beforzugen, verwenden Sie folgendes:
DEFINT A-Z SUB SetRGBPalette884 DIM faktor8 AS SINGLE, faktor4 AS SINGLE faktor8 = 63 / 7 faktor4 = 63 / 3 DIM i AS INTEGER FOR r = 0 TO 7 FOR g = 0 TO 7 FOR b = 0 TO 3 OUT &H3C8, i OUT &H3C9, CINT(b * faktor8) OUT &H3C9, CINT(g * faktor8) OUT &H3C9, CINT(b * faktor4) i = i + 1 NEXT NEXT NEXT END SUB
Wie konvertiert man RGB-Werte in Paletten-Indizes?
Jetzt haben wir zwar die Palette, müsse aber immernoch Indizes verwenden. Jetzt müssen wir eine Funktion zum Konvertieren schreiben. Im Code sieht man drei Schleifen. Die innerste verändert den Blauwert, die mittlere den Grünwert und die äußerste den Rotwert.
Also jedesmal, wenn blau durchgelaufen ist wird grün erhöht und blau zurückgesetzt. Das selbe gilt für grün und rot. Daraus flgt eindeutig die Formel 'index = blue + 6 * green + 6 * 6 * red' oder in der richtigen Reihenfolge und vereinfacht: 'index = red * 36 + green * 6 + blue'. (Für die 8*8*4-Palette gilt 'index = red * 32 + green * 4 + blue'). Jetzt kommt der leichteste Teil: Wir müssen die Formel nurnoch in eine Funtion packen:
DEFINT A-Z FUNCTION RGB2Index(r, g, b) RGB2Index = r * 36 + g * 6 + b END FUNCTION
Oder für die 8*8*4-Palette:
DEFINT A-Z FUNCTION RGB2Index(r, g, b) RGB2Index = r * 32 + g * 4 + b END FUNCTION
Falls Sie tatsächlich die 8*8*4-Palette verwenden wollen würde ich die Funktion etwas modifizieren, damit sie nicht 0-7, 0-7, 0-3, sondern 0-7,0-7,0-7 angeben können:
DEFINT A-Z FUNCTION RGB2Index(r, g, b) RGB2Index = r * 32 + g * 4 + CINT(b / 2.333333) END FUNCTION
Falls Sie Werte zwischen 0 und 255 beforzugen, wie beispielsweise die Future.Lib sie verwndet, habe ich auch die Funktionen vorbereitet (die zweite ist für die 8*8*4-Palette):
DEFINT A-Z FUNCTION RGB2Index(r, g, b) tmpR = CINT(r / 51) tmpG = CINT(g / 51) tmpB = CINT(b / 51) RGB2Index = tmpR * 36 + tmpG * 6 + tmpB END FUNCTION
DEFINT A-Z FUNCTION RGB2Index(r, g, b) tmpR = CINT(r / 36.42857) tmpG = CINT(g / 36.42857) tmpB = CINT(b / 85) RGB2Index = tmpR * 32 + tmpG * 4 + tmpB END FUNCTION
Wie war das mit der Transparenz?
Wie es prinzipiell geht wurde eingangs bereits erwähnt. Jedoch brauchen Sie die Komponenten der Farbe, die sich bereits am Bildschirm befindet. Mit 'POINT' erhalten Sie jedch nur den Index in der Palette. Also müssen wir den Index zurückwandeln. Natürlich könnte man direkt die Grafikkarte fragen (siehe Tipps-Kapitel) und durch skalieren aus den drei Werten dann die gewünschten Werte berechnen. Das ist jedoch viel zu Zeitaufwendig. Also berechnen wir die Anteile direkt aus dem Index:
Als erstes erhalten wir den Blauanteil indem wir dien Index modulo dividieren. 'blue = color mod 6'. Der grrünanteil wurde mit 6 multipliziert. Also dividieren wir durch 6 und schneiden den Rotanteil durch modulo ab. (Wir verwenden natürlich '\' und nicht '/', da der Nachkommaanteil nur den Blauanteil enthielte.) 'green = color \ 6 mod 6'. Der Rotantiel wurde mit 36 multipliziert, also tielen wir wieder durch 36. Die Moduosdivisin können wir uns sparen, da oberhalb des Rotanteils nichts mehr existiert: 'red = color \ 36'.
DEFINT A-Z SUB Index2RGB (color, r, g, b) b = color MOD 6 g = color \ 6 MOD 6 r = color \ 36 END FUNCTION
Wie sehen ist es recht einfach. Für die 8*8*4-Palette: b = color mod 4; g = color \ 4 mod 8; r = color \ 32.
Jetzt noch ein Beispiel für Transparnz:
DEFINT A-Z SUB TransparentPset (x, y, c) oldC = POINT(x,y) Index2RGB oldC, oldR, oldG, oldB Index2RGB c, newR, newG, newB PSET (x,y), RGB2Index((oldR + newR) \ 2, (oldG + newG) \ 2, (oldB + newB) \2) END SUB
Vielleicht kennen Sie bereits durchscheineffekte, die mit jeder beliebigen Palette funktionieren mit hilfe einer lookup-Tabelle. Aber echte Transparenz sieht einfach besser aus. Und Sie können sogar den Grad der Transparenz angeben:
DEFINT A-Z SUB TransparentPset (x, y, c, alpha AS SINGLE) DIM ralpha AS SINGLE ralpha = 1 - alpha oldC = POINT(x, y) Index2RGB oldC, oldR, oldG, oldB Index2RGB c, newR, newG, newB resultR = oldR * alpha + newR * ralpha resultG = oldG * alpha + newG * ralpha resultB = oldB * alpha + newB * ralpha PSET (x,y), RGB2Index(resultR, resultG, resultB) END SUB
'alpha' ist ein Wert zwischen '0' und '1'. Mit einem Wert von '.5' erhalten Sie das selbe ergebnis, wie mit der anderen Version.
Ich denke jetzt ist alles pber RGB in 256-Farbenmodie gesagt.
Dennoch gibt es etwas, was sie nch interessieren könnte:
Wie konvertiert man eine belibige Palette in eine RGB-Palette
Das ist gar nicht so schwer. Speichern Sie die RGB-Werte der alten Palette (OUT &H3C7, i ; r = INP(&H3C9) ; g = INP(&H3C9) ; b = INP(&H3C9) ), setze die RGB-Palette, lies die Pixel aus, und verwende die vorher gesicherten RGB-Werte um die neuen Farben zu berechnen:
DEFINT A-Z TYPE PaletteType r AS INTEGER g AS INTEGER b AS INTEGER END TYPE ' Laden Sie hier ihre alte Paltette und anschließend ihr Bild DIM pal(256) AS PaletteType ' zum sichern der alten Palette SavePalette pal() SetRGBPalette ' Male das Bild erneut mit den neune Farben FOR y = 0 TO ImageSizeY FOR x = 0 TO ImageSizeX c = POINT(x, y) PSET (x, y), RGB2Index(pal(c).r, pal(c).g, pal(c).b) NEXT NEXT SUB SavePalette (pal() AS PaletteType) FOR i = 0 TO 255 OUT &H3C7, i pal(i).r = INP(&H3C9) * 4.047619 pal(i).g = INP(&H3C9) * 4.047619 pal(i).b = INP(&H3C9) * 4.047619 ' 4.047619 ist der Faktor, um werte zwischen 0 und 63 ' auf Werte zwischen 0 und 255 zu mappen NEXT END SUB
Das Beisiel verwndet die 'RGB2Index()'-Funktion, die Werte zwischen 0 und 255 erwartet.