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.


vorheriges
Index
nächstes