Merhaba. Bu yazı dizisinde VGA'da renk paleti kullanımından söz edeceğim. Palet detaylı bir konu olduğundan birden fazla yazıda ele almayı düşündüm. Bu bölümde renk paleti nedir, nasıl okunur, nasıl değiştirilir; bunları ilk önce metin moduyla VGA 640 x 480 (nam-ı diğer screen 12) moda odaklanarak ele alacağım. Mod 13h'ü ayrı bir yazıda sonra ele alacak ve paletle yapılacak bazı görsel efektlere değineceğim.
VGA'nın getirdiği iki tane önemli grafik ekran modu var. Biri 640 x 480 x 16 renkten oluşan mod 12h ve diğeri de 320 x 200 x 256 renkten oluşan malum mod 13h. Diğerleri eski ekran kartlarına uyumluluk için bırakılmış modlar. VGA ekran kartının DAC'i (Dijitalden analoğa dönüştürücü) 18 bit RGB renk gamutundaki renkleri (218 = 256 K = 262 144 renk) ekranda gösterebilse [1] de mod 13h'te bunlardan yalnızca 256'sını ve mod 12h'de 16'sını aynı anda ekranda gösterebilir. İşte bu renk gamutundan (gamından) ekranda gösterilmek üzere seçilen renk altkümesine palet adı verilir.
Renk bilgisi, bir indis ve VGA için 6+6+6 olmak üzere 18 bitlik bir RGB renk değerinden oluşur. Örneğin indis 1 ve RGB kodu 0,0,63 ise birinci renk mavi, indis 2 ve RGB kodu 24,24,24 ise ikinci renk gridir vb.. İndis değeri sıfırdan başlar ve sıfırıncı renk arkaplan rengidir. Dolayısıyla sıfırıncı renk genellikle siyahtır (RGB 0,0,0). Eğer 0'dan 255'e kadar olan indisleri doğrusal artan ardışık t değerleriyle RGB t,t,t şeklinde doldurulursa gri tonlu (greyscale) veya RGB 0,r,0 şeklinde doldurulursa yalnız yeşil tonlu bir görüntü elde edilir.
Renkler ekran kartının DAC'i aracılığıyla işlenir. Dolayısıyla palet işlemleri VGA kartının DAC yazmaçlarıyla yapılır. Bunlar üç* tanedir [3]:
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| DAC Read Address | |||||||
Aslında 3C7h'nın iki görevi vardır. Bu yazmaç okunursa, en düşük anlamlı iki bit DAC'ın okuma modunda mı yoksa yazma modunda mı olduğunu gösterir. Ancak, zaten bir out işlemi yapmışsam yazıyorumdur, in işlemi yapmışsam okuyorumdur. Bu yüzden bu işlevi pek kullanılmaz. Paleti okumak içinse bu yazmaca indis değeri yazılır. Ardından 3C9h portundaki DAC data yazmacı byte uzunlukta üç kere okunur:
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| DAC Data | |||||||
Palete yazılacağı zaman renk indisi 3C8h portuna yazılır ve DAC data yazmacına üç tane byte uzunluklu değer gönderilir.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| DAC Write Address | |||||||
*Aslında DAC yazmaçları dört tanedir. Yukarıda söz etmediğim DAC maskeleme yazmacına 3C6h portundan erişilir ve her zaman 0FFh değerini içerir. Buraya başka bir değer yazılması DAC'ı erişime kapatır [2].
Yukarıda byte uzunluklu değer okunur veya yazılır ifadesiyle kast edilen in al,dx ve out dx,al işlemleridir. Ancak okunan ve yazılan değerin en düşük 6 biti anlamlıdır. Renk gamutunun 6+6+6=18 bit olduğunu hatırlayınız.
İlk olarak metin modu ve mod 12h'ya odaklanalım. Bu iki modda ekranda en fazla 16 renk gösterilebilir. Bu bakımdan birbirine benzerler. Dikkatlerden kaçan bir ayrıntı, metin modunda da paletin değiştirilebilir olmasıdır. İlk VGA yazısında [5] metin modda yazı ve arkaplan renklerinin nasıl değiştirilebildiğini göstermiştim. Şimdi basit bir BASIC koduyla metin ekrandaki palete bakalım:
OUT &H3C7, I%
PRINT "("; I%; "="; INP(&H3C9); INP(&H3C9); INP(&H3C9); ")";
NEXT I%
DEF SEG = &HB800
FOR J% = 1 TO 15
FOR I% = 1 TO 159 STEP 2
POKE (I% + J% * 160), J%
NEXT I%
NEXT J%
İlk bölümde 3C7h'den indis değerini gönderip, sonra 3C9h'dan renk kodlarını okuyup ekrana yazdırdım. İkinci bölümde metin mod ekran belleğine erişip birinci satırı birinci, ikinci satırı ikinci renk kodu vb. olmak üzere renklendirdim:
Metin modunda 16 renk kullanılabildiğini söyledim, ama ekrana 64 renk kodu yazdırdım, ve ilginç biçimde [16, 63] arasındaki indislere de bir kod atanmış olduğu görülüyor. [64, 255] arası indislerin kodu sıfır, bu yüzden onları yazdırmadım ama istenirse onlara da renk kodu atanabilir. Peki bu ne demek? Normalde metin ekranda bir karakter, bellekte bir byte karakterin ASCII kodu, diğeri renk kodu olmak üzere 2 byte'dan oluşur. Renk byte'ının düşük anlamlı 4 biti karakterin rengi, yüksek anlamlı 4 biti karakterin arkaplan rengi olduğunu biliyoruz. Renk için 4 bit ayrılmışken 16 ve üstü indislere renk kodu atamanın ilk bakışta anlamı yok görünüyor, ama burada bir trick devreye giriyor: VGA Attribute Register (3C0h) [4] ile bir rengin palet indisi değiştirilebilir. Çok ayrıntıya girmeden basit bir kod parçasıyla:
OUT &H3C0, 5
OUT &H3C0, 60
OUT &H3C0, &H20
Yukarıda beşinci attribute yazmacına 60 değerini yazarak 60. rengi beşinci renge atamış oldum.
Ekran görüntüsüne geri dönersek, bir önceki kodla ekrana yazdırdığım palette sekizinci renk (0, 0, 21) lacivert / koyu mavi, dokuzuncu renk (0, 0, 63) yani mavi olarak görünüyor. Ancak sıfırdan başlayarak saymak koşuluyla sekizinci satırın koyu mavi olmasını beklerken aslında koyu gri, ve dokuzuncu satırın daha baskın bir mavi olmasını beklerken neon mavisi tabir edilen soluk bir mavi olduğu görülüyor. Eğer ekrandaki renk kodları gerçekten satırların rengi olsaydı aslında ekran aşağıdaki görselin sağ tarafı gibi görünürdü. Gerçekte görünen sol taraf. Daha kolay karşılaştırılması için iki görseli yan yana koydum:
Buradan çıkarılacak sonuç, aslında metin modunun [8, 15] renkleri için attribute yazmaçlarını zaten kullanıyor olduğu. Ben görselin sol yanını elde etmek için ilk [1,15] renk aralığını elle paletteki [1,15] renklerine eşledim.
Metin moddaki herşey mod 12h için de geçerli. 16 renk kullanılabilmesine rağmen palette 64 renk kayıtlı. Bu noktada bir de ek bilgi: Eğer mod 13h'ten sonra mod 12h'ye veya metin moduna geçilirse, mod 13h'e geçişte yüklenen palet diğer modlarda da geçerli olur. Yani bilgisayarın (veya DosBox'ın) açılışında [64, 255] arası renklerin hepsi (0, 0, 0) iken mod 13h'e girip tekrar metin moduna veya mod 12h'ye geçince bunlar sıfırdan farklı değerler alır.
Yine metin moddakine benzer şekilde ekrandaki renkler paletle seçilir ama attribute register da ikinci bir dönüştürme katmanı sağlar. Aşağıda tüm bunları görselleştirmek için bir BASIC kodu var:
CONST K = 20
FOR I% = 0 TO 63
OUT &H3C7, I%
PRINT "("; I%; "="; INP(&H3C9); INP(&H3C9); INP(&H3C9); ")";
NEXT I%
SLEEP
FOR I% = 0 TO 15
' PRINTING RECTANGLES
LINE (0, I% * K)-(640, (I% + 1) * K), I%, BF
NEXT I%
FOR I% = 0 TO 15
' SETTING PALETTE
OUT &H3C8, I%
OUT &H3C9, I% * 4
OUT &H3C9, I% * 0
OUT &H3C9, 63 - I% * 4
NEXT I%
SLEEP
' Change fifth color
A% = INP(&H3DA)
OUT &H3C0, 5
OUT &H3C0, 60
OUT &H3C0, &H20
Birinci kısımda [0, 63] arası renk paletindeki renk kodları ekrana yazdırılıyor. Sonraki kısımda ekrana [0, 15] arası renklerle boyutu K sabitiyle ayarlanan 16 dikdörtgen bastırılıp sonra palete maviden kırmızıya kayan 16 renk atanıyor. Görüldüğü gibi palete renk ataması, palet indisinin 3C8h portuna yazılıp, renk verisinin 3C9h portundan gönderilmesiyle yapılıyor.
Burada sıfırıncı renge mavi atandığı için arkaplan rengi mavi oluyor. Son bölümdeyse yine beşinci renk altmışıncı palet girdisiyle eşleştirilip renk farkı belirgin bir biçimde ortaya konuyor.
[1]: https://en.wikipedia.org/wiki/Video_Graphics_Array
[2]: https://wiki.osdev.org/VGA_Hardware#Port_0x3C6
[3]: http://www.osdever.net/FreeVGA/vga/colorreg.htm
[4]: http://www.osdever.net/FreeVGA/vga/attrreg.htm
[5]: https://trapflag.blogspot.com/2025/11/vga-metin-kipinde-yumusak-kaydrma.html


Hiç yorum yok:
Yorum Gönder