SDL Kursu 1
Retro bilgisayarSDL Nedir?
SDL, Simple DirectMedia Layer yani basit direkmedya katmanıdır. Biraz motamot bir çeviri oldu. Anlaşılır bir ifade ile SDL ses, klavye, mouse, joystick, 3d donanımı ve 2d grafik çizimi için hazırlanmış platform bağımsız bir çokluortam (multimedia) kütüphanesidir. Mpeg oynatıcılarda, Emulatorlerde, birçok popüler oyunda ve Linux'a port edilen birçok Windows oyununda kullanılmaktadır.
SDL Linux, Windows, BeOS, MacOS Classic, MacOS X, FreeBSD, OpenBSD, BSD/OS, Solaris, IRIX ve QNX ortamlarını destekler. Ayrıca resmi olmasa da kod açık olduğu için gönüllü çalışmalar sonucunda Windows CE, AmigaOS, Dreamcast, Atari, NetBSD, AIX, OSF/Tru64, RISC OS ve SymbianOS üzerinde de çalışması sağlanmıştır.
SDL C dili ile yazılmış olmasına rağmen C++ ile doğal hali ile çalışmakta ve Ada, Eiffel, Java, Lua, ML, Perl, PHP, Pike, Python ve Ruby gibi birçok dil içinde uyarlamaları bulunmaktadır.
Neden SDL?
Çünkü SDL öğrenmesi ve kullanması kolay ama karşılığında çok güçlü bir kütüphanedir. Grafik konusunda OpenGL ile beraber çok kolay bir şekilde çalışabilmesine ek olarak eksik kaldığı her alan içinde SDL'i destekleyen ek kütüphaneler bulunmaktadır. Ses ve müzik için SDL mixer, resimler için SDL image, true type font desteği için SDL ttf, ek çizim komutları için SDL gfx ve network için SDL net bunların en bilinen, en çok kullanılanlarındandır.
Bütün bunların yanında SDL platformdan bağımsızdır. Yazdığınız kod bir başka platformda neredeyse hiçbir değişikliğe gerek duymadan aynen çalışabilmektedir.
SDL Kurulum
Bu konu aslında basit olmasına rağmen yeni başlayanları biraz zorlayabilir. Yine de elimden geldiğince her platformda SDL'i nasıl kurup kullanmaya hazır hale getireceğimizi yazmaya çalışacağım.
Windows
Windows ortamında en yaygın olarak MS Visual Studio, Borland C++ Builder ve IDE'leri kullanılmaktadır. Ama ben daha önce hiç Builder kullanmadığım ve internette de C++ Builder için yazılmış bir kurulum yazısı bulamadığım için size tahmini bilgi verebileceğim, gerisi size kalmış. Yine de pek sorun yaşayacağınızı sanmıyorum.
Visual Studio
İlk olarak MS'in IDE'si Visual Studio ile başlayalım. Ben Dev-C++ kullandığım için bu IDE hakkında pek bilgim yok ama internette yayınlanmış İngilizce derslerden topladığım bilgi ile yardımcı olmaya çalışacağım.
http://www.libsdl.org/download-1.2.php adresinden download bölümünden, Development Libraries başlığı altındaki Visual C++ için olan dosyayı (SDL-devel-1.2.8-VC6.zip gibi bir adı olması lazım) indirin.
Sıkıştırılmış dosyayı açın. Zip dosyasının içinden çıkan dosyalar arasında iki tane önemli klasör var. Bunlar "include" ve "lib" klasörleri. "lib" klasörünün içinden çıkanları C:\Program Files\Microsoft Visual Studio\VC98\Lib (büyük ihtimalle sizin bilgisayarınızda da aynı klasördür ama eğer MS'i kurduğunuz yer farklı ise bu yolu da ona göre değiştirin.) klasörü altına kopyalayın. "include" klasörü içindeki dosyaları da C:\Program Files\Microsoft Visual Studio\VC98\Include (diğeri ile aynı şekilde farklı bir klasör olabilir sizinki, artık duruma göre değişikliği siz yaparsınız. Bir de include'un altında SDL klasörü yok onu sizin yaratmanız gerek.) klasörü altına kopyalayın.
Şimdi Visual Studio'yu çalıştırın ve yeni bir proje yaratın. "Win32 Application" seçeneğini ve "empty project" seçeneğini seçin. File menüsündeki New seçeneği ile yeni bir C++ kaynak dosyası (C++ source file) yaratın ve adını main.cpp koyun.
Daha sonra proje ayarları (project settings) (project->settings menüsü yolu ile) bölümüne gidin. LINK tabına tıklayın listelenmiş diğer lib dosyalarının altına sdl.lib ve sdlmain.lib dosyalarını ekleyin.
Ardından yine proje ayarları bölümünde C/C++ tabına tıklayın. Drop-down menüden "Code Generation" seçeneğini seçin. Ardından da 'Use run-time library' drop-down menüsünden 'Multithreaded DLL' seçeneğini seçin.
Son bir şey daha. Sıkıştırılmış dosyanın içinde son bir önemli dosya bulunmakta. SDL.DLL dosyası. Bu dosyayı alıp ister işletim sisteminizin system klasörüne (Win 95, 98, ME için C:\windows\system klasörü ya da Windows NT, 2000 and XP için C:\windows\system32 klasörü), ister uygulamanızın exe dosyasının çalışacağı klasöre kopyalayın. Eğer DLL dosyasını system klasörüne kopyalarsanız yapacağınız her SDL programı için DLL dosyasını baştan baştan kopyalamanıza gerek kalmaz. Aksi takdirde her programın klasörüne koymanız gerekir. Ayrıca programlarınızı dağıtırken de bu DLL dosyasını programınız ile vermeniz gerekiyor. Aksi halde yaptığınız program başka bilgisayarlarda çalışmaz.
MS Visual Studio ile işimiz bu kadar, bütün bu adımları gerçekleştirdikten sonra MS VC SDL ile program geliştirmeye hazır hale geliyor.
Dev-Cpp
için SDL yüklemenin iki yolu var. Birincisi http://www.devpaks.org sitesine gidip SDL için gerekli devpak dosyasını indirmek ve Dev-Cpp içerisindeki Package Manager ile bu devpak dosyasını yüklemek. Bu sayede hem SDL kütüphanesi sorunsuzca bilgisayarınıza yüklenecek hem de elinizin altında hızla program yazmaya başlamanız için hazır bir SDL kodu olacak.
Ama ne yazık ki hazır SDL kodu içerisinde birkaç hata bulunmakta, yine de bunları düzeltmek oldukça kolay.
Diğer yol ise yukarıdaki gibi geliştirme paketini indirip her dosyayı yerine kurmak. Bu yolu izlerken yapmamız gerekenler;
1. adresinden download bölümünden Development Libraries başlığı altındaki MinGW32 için olan dosyayı (SDL-devel-1.2.8-mingw32.tar.gz gibi bir adı olması lazım) indirin.
2. Sıkıştırılmış dosyayı açın. Zip dosyasının içinden çıkan dosyalar arasında iki tane önemli klasör var. Bunlar "include" ve "lib" klasörleri. "lib" klasörünün içinden çıkanları C:\Dev-Cpp\lib klasörü altına kopyalayın. "include" klasörü içindeki dosyaları da C:\Dev-Cpp\include\SDL (include'un altında SDL klasörü yok, onu sizin yaratmanız gerek.) klasörü altına kopyalayın.
3. Sıkıştırılmış dosyanın içinde son bir önemli dosya bulunmakta: SDL.DLL dosyası. Bu dosyayı alıp ister işletim sisteminizin system klasörüne (Win 95, 98, ME için C:\windows\system klasörü ya da Windows NT, 2000 and XP için C:\windows\system32 klasörü), ister uygulamanızın exe dosyasının çalışacağı klasöre kopyalayın. Eğer DLL dosyasını system klasörüne kopyalarsanız yapacağınız her SDL programı için DLL dosyasını baştan baştan kopyalamanıza gerek kalmaz. Ayrıca SDL.DLL dosyasını C:\Dev-Cpp\dll klasörünün altına da kopyalayın.
4. Dev-Cpp'ı çalıştırın. New Project butonu ile yeni bir proje açın. Eğer Devpak'ı yüklediyseniz proje şablonları arasında Multimedia tabı altında SDL için hazır bir şablon hazır bulunmakta. Verdiğim dosya ile bu şablondaki dosyayı değiştirdiyseniz bu şablon sorunsuzca çalışacaktır. Bu şablon üzerinden dilediğinizce SDL uygulamalarınızı geliştirebilirsiniz. Ama eğer Devpak ile değil de SDL'in sitesinden indirdiğiniz sıkıştırılmış dosyadan kurduysanız proje ayarlarını elle yapmalısınız. İlk olarak yeni bir proje açın (New Project). Ardından Project Browser'da çıkan projenizin adına sağ tuşla tıklayın ve Project Options'ı seçin. Burda ilk olarak Type bölümünden Win32 GUI seçeneğini seçin. Eğer Win32 Console'u seçerseniz SDL programınız her çalıştığında önce DOS penceresi açılır. Ardından programınız çalışır. Devamında aynı pencerede Parameters tabını açın. Compiler başlığı altına -Dmain=SDL_main parametrelerini girin. Linker başlığı altına ise -lmingw32 -lSDLmain parametrelerini girin.
Ayarlamalar bu kadar. İsterseniz şimdi projenizi kaydedin ve SDL projesine başlayacakken ayarları hazır olduğundan bu proje üzerinden başlayın. Geriye bir tek kod yazmanız kaldı. O da sonraki bölümlerde anlatılacak. MinGW32
Dev-Cpp'ta kendi içerisinde MinGW32 derleyicisi kullandığı için aşağı yukarı aynı ayarlar geçerli. Uzun uzadıya anlatmayacağım. Yukarıdaki açıklamalar yardımı ile sorunsuzca ayarlamaları yapabilirsiniz diye düşünüyorum.
Linux
Linux'ta SDL yüklemenin en kolay yolu kullandığınız dağıtımın paket yöneticisinden SDL paketini seçip indirmenizdir. Bir diğer yol da www.libsdl.org adresinden kaynak kodlarını indirip sırayla "./configure", "make" ve "make install" komutlarını vermeniz yeterlidir. Kodunuzu SDL ile derlemek için de kodun içine '#include "SDL.h"' satırını eklemeniz ve derleyici parametrelerine de '-I/usr/include/SDL' ve '-lSDL' parametrelerini eklemeniz gereke-
SDL'e giriş
SDL öğrenmesi oldukça kolay bir kütüphanedir. Bu nedenle hızla kod yazmaya girişeceğim. Kısa sürede öğreneceksiniz zaten. SDL, 8 alt sistemin bileşiminden oluşmaktadır. Bunlar Ses(Audio), CDROM, Olay yönetimi(Event Handling), Dosya G/Ç(File I/O), Joystick yönetimi(Joystick Handling), Çoklu Görev(Threading), Zamanlayıcı(Timers) ve Grafik(Video)'dur. Bu alt sistemleri kullanmak için ilk önce bu sistemleri çalıştırmanız gerekir. Bunun için iki komut bulunmaktadır. Bunlar SDL_Init ve SDL_InitSubSystem'dir. SDL_Init bütün SDL kodlarından önce çalıştırılmalıdır. Bu komut SDL sistemini çalıştırmaya başlar. SDL_InitSubSystem ise çalışma anında istediğiniz alt sistemin çalışmasını sağlar.
Kullanımları şu şekildedir:
SDL Init ( SDL INIT VIDEO );
Bu komutla SDL programı çalıştırılır ve SDL'in video alt sistemi aktif hale getirilir.
SDL InitSubSystem ( SDL INIT AUDIO | SDL INIT TIMER
Bu komutla çalışmakta olan SDL programında ses ve zamanlayıcı alt sistemleri aktif hale getirildi. | işareti ile aynı anda birden fazla SDL alt sistemini seçebiliriz. Bu yöntemi SDL_Init komutu ile de kullanabiliriz.
Alt sistem bayrakları(flag) listesi:
1. SDL_INIT_TIMER - Zamanlayıcı - 2. SDL_INIT_AUDIO - ses - 3. SDL_INIT_VIDEO - grafik -
4. SDL_INIT_CDROM - cdrom -
5. SDL JOYSTICK - joystick - 6. SDL EVERYTHING - Bütün sistemleri aktif hale getirir 7. SDL INIT NOPARACHUTE - SDL'in hata sinyallerini yakalamasını önler - 8. SDL EVENTTHREAD - çok görevlilik -
Alt sistemleri çalıştırmayı öğrendik ama ya çalışan sistemleri kapatmayı? Şimdi de çalıştırdığımız SDL programını ve alt sistemleri nasıl kapatacağımızı öğreneceğiz.
İlk komutumuz SDL Quit. Bu komut SDL Init komutunun yaptığı işin tam tersini yapar ve başlattığınız SDL programını kapatır. Bu programı kullanırken herhangi bir argüman girmenize gerek yoktur. Kullanışı:
SDL
şeklindedir. Bu komut ile halihazırda çalışan bütün SDL alt sistemleri ve SDL programı kapanır. Diğer komutumuz ise SDL QuitSubSystem. Bu komut ile çalışmakta olan istediğimiz alt sistemi kapatabiliriz. Kullanımı:
( SDL INIT TIMER );
şeklindedir. Örneğimizde zamanlayıcı alt sistemini kapattık ama SDL programımız çalışmaya devam etti.
Ayrıca SDL WasInit fonksiyonu ile istediğiniz alt sistemin yüklü olup olmadığını kontrol edebilirsiniz. Bu fonksiyonunun yazılışı şöyledir:
if(SDL WasInit(SDL INIT VIDEO)!-0)
printf ("Video alt sistemi
else
printf ("Video alt sistemi yuklu
Şimdi öğrendiklerimizle örnek bir SDL programı yazalım.
/* SDL header dosyas#. Butun SDL programlari
buna ihtiyac duyar */
#include "SDL.h"
#include <stdio.h>
int main() (
printf ("SDL programi ba#lat#l#yor.n");
/* SDL programi baslatilip Video ve Ses
sistemleri aktif hale getiriliyor */
İZ£((SDL Initi
SDL INIT VIDEO
|SDL INIT AUDIO)---1)
)
1
İptinti |
stderr,
"SDL programi baslatilamadi:
SDL GetError()
Vi
exit(-l1);
)
$s.Vna",
fprintf (stdout,"SDL programi baslatilamadi
fprintf (stdout,"SDL programi kapatiliyor.ln");
/* SDL programi ve butun alt sistemleri
kapatiliyor */
SDL
Eprint?f (Stdout,
exit (0);
SDL ve Grafik
Sırada grafik komutlarını kullanmayı öğrenmek var. İlk olarak yapmamız gereken şey video alt sistemini aktif hale getirmek. Ardından bir yüzey (surface) tanımlamalı ve SDL SetVideoMode komutu ile bu yüzeyi kullanarak istediğimiz çözünürlükte bir pencere yaratmamız gerekir.
İlk olarak yüzey terimini açıklamak istiyorum. SDL'de ekrana çizdirmek istediğiniz bilgiler bir yüzeyde saklanır. Bu yüzeyler aslında önceden tanımlanmış yapılardır (struct). Bir yüzeyi şöyle tanımlayabiliriz:
SDL Surface *screen;
İçeriği ise şöyledir:
typedef struct SDL Surface (|
Uint32 flags; /* Salt okunur */
SDL PixelFormat *format;/* Salt okunur */
int w, h; /* Salt okunur */
Ülnt16 pitch; /* Salt okunur */
void *pixels; /* oku-yaz */
/* kirpma bilgisi */
SDL Rect clip rect; /* Salt okunur */
/* Referans sayac# yuzey
bosaltilirken kullanilir */
int refcount; /* cogunlukla okunur */
/* Bu yap# ayn# zamanda burda gösterilmeyen
baz# özel alanlara sahiptir */
SDL Surface;
Gördüğünüz gibi SDL Surface yapısı ile uğraşırken sadece pixels değişkenini kullanabilirsiniz. Bu değişken yüzeyin her pixel'inin renk bilgisini taşır ve isterseniz her pixel'i teker teker değiştirebilirsiniz. Bu konuya ileride daha detaylı olarak bakacağız ama şimdi devam edelim.
Programın başında ekrana yansıtacağımız görüntüler için bir yüzey tanımlarız ve bu yüzey ile bir pencere açarız. Bunu SDL SetVideoMode komutu ile yaparız. Kullanımı aşağıdaki gibidir.
screen
640,
SDL SetVideoMode (
480, 8, SDL SWSURFACE);
Bu komut ile screen yüzeyini ekrana yansıtacağımız ana yüzey olarak tanımlar ve 640'a 480 pixel çözünürlükte bir pencere ya-
ratırız. Ekrandaki bit başına düşen pixel sayısı 8 olur. Ve
SDL SWSURFACE bayrağı ile screen yüzeyine ait verilerin sistem belleğinde tutulması sağlanır. Burada kullanmak için birçok farklı bayrak bulunmaktadır. SDL SetVideoMode komutu ile kullanabileceğimiz bayrakların listesi:
SDL SWSURFACE -> yüzeye ait bilgilerin sistem belleğinde tutulmasını sağlar.
SDL HWSURFACE -> yüzeye ait bilgilerin ekran kartının belleğinde tutulmasını sağlar.
SDL ASYNCBLIT -> asenkron yüzey göstermeyi aktif hale getirir. Bu genellikle tek işlemcili makinalarda bit işlemeyi (blit - bit block transfer - bit bloğu değişimi) yavaşlatır ama SMP sistemlerde hız artışı sağlayabilir.
SDL ANYFORMAT -> Normalde eğer video yüzeyi kullanılamayacak bir ekran derinliği (bpp) isterse SDL gölge bir yüzey ile bunu emule eder. SDL ANYFORMAT bayrağı ile SDL'in bunu yapması engellenir ve SDL'in yüzeyin derinliğini umursamadan onu kullanması sağlanır.
SDL HWPALETTE -> SDL'e ayrıcalıklı palet erişimi verir. Bu bayrak olmadan SDL SetColors komutu ile istediğiniz renge her zaman ulaşamayabilirsiniz.
SDL_DOUBLEBUF -> Çifte tamponlamayı etkin hale getirir. Sadece SDL_HWSURFACE bayrağı ile beraber kullanılabilir. SDL_Flip komutu tamponların içeriğini değiştirir ve ekranı tazeler. Eğer çifte tamponlama etkinleştirilmemişse SDL_Flip bütün ekran üzerine SDL_UpdateRect komutu uygulanmış gibi davranır.
SDL_FULLSCREEN -> SDL tam ekran çalıştırmaya çalışıyor.
SDL_OPENGL -> OpenGL render ekranı yaratır. SDL_GL_SetAttribute komutu ile OpenGL ayarlamalarına başlamadan önce bu bayrağın etkinleştirilmesi gerekir.
SDL_OPENGLBLIT -> Üstteki gibidir ama aynı zamanda blitting (*yardım*) işlemlerine izin verir.
SDL_RESIZABLE -> Boyutlandırılabilir bir pencere yaratır. Pencere boyutları değiştirildiği zaman SDL_VIDEORESIZE olayı tetiklenir ve SDL_SetVideoMode yeni boyut ile tekrar çağırılabilir.
SDL_NOFRAME -> Mümkün ise çerçevesiz bir pencere yaratır. Tam ekran modu otomatik olarak bu bayrağı etkinleştirir.
Eğer istediğiniz ekran modunun uygun olup olmadığını öğrenmek istiyorsanız SDL_VideoModeOK fonksiyonunu kullanabilirsiniz. Yazılışı:
if (!SDL VideoModeoK (
640, 480, 16, SDL HWSURFACE))
£
printf ("Ekran modu uygun degil.4n");
)
else
(
printf ("Ekran modu uygun.4n");
şeklindedir. Bunun dışında SDL_GetVideoInfo, SDL_GetVideoSurface, SDL_GetVideoDriverName ve SDL_ListModes gibi fonksiyonlar da bulunmakta ama şimdilik işin başında olduğunuz için işin başındaki sizlerin ihtiyaç duymadığı fonksiyonlar. Bunlara ileride detaylı değineceğiz ama şimdi sadece başka fonksiyonların da olduğunu bilin yeter.
Şu ana kadar öğrendiklerimizle bir SDL programını başlatıp SDL penceresini açabiliyoruz. Ama karşımızdaki simsiyah pencere oldukça sıkıcı değil mi? Hadi ortamı biraz renklendirelim. İlk olarak oldukça basit olduğu için bir BMP dosyasını okuyup ekrana yazdırmayı göstereceğim.
Bunun için ilk olarak okuyacağımız BMP dosyasının içeriğini saklayacağımız bir yüzey oluşturmalıyız. Yüzeyler SDL'de resim bilgisi saklanılacağı her yerde kullanılır.
SDL Surface *image;
SDL'in kendi içerisinde BMP uzantılı dosyaları okuyup hafızaya alan hazır bir fonksiyonu bulunmakta. Adı SDL_LoadBMP. Kullanışı:
image-SDL LoadBMP ("c:Va.bmp");
şeklindedir. Bu sayede image adlı yüzeye a.bmp dosyasını yüklemiş bulunmaktayız. Şimdi sıra bu resmi ekrana çizdirmekte. Bunun içinse SDL_BlitSurface fonksiyonunu kullanacağız.
SDL BlitSurface(image, NULL, screen, NULL);
Bu komut ile image yüzeyindeki resmi screen yüzeyine yani ekrandaki görüntünün saklanacağı yüzeye çizdiririz. NULL değer verilen parametrelerde çizdirilecek yüzeylerin boyutları ve koordinatları belirlenir. Eğer iki parametreye de NULL girersek image yüzeyinin tamamı screen yüzeyinin 0,0 noktasından başlayarak çizdirilir. Eğer resmin belirli bir kısmını çizdirmek istersek veya ekranda 0,0 noktasından başka bir noktaya koymak istersek ne yapacağız? SDL_Rect kullanarak.
SDL_Rect SDL içerisinde kare alan tanımlamak için kullanılan yapıdır. İçeriğinde sadece enine ve boyuna uzunluğu ile x,y düzlemlerindeki koordinatlarını saklayan değişkenler bulunur.
typedef
Sintl6 x, yı
Uint16 w, h;
) SDL Rect;
x ve y koordinatları üst sol köşenin koordinatlarıdır. w ve h ise genişlik ve uzunluğudur. Oldukça basit ama niye böyle bir yapıya ihtiyacımız var diye düşünebilirsiniz. Bu yapıya ihtiyacımız var çünkü yüzeylerdeki resim alanları aslen dikdörtgen ve bunları kırpmak ya da belirli koordinatlara yerleştirmek isterseniz bu dikdörtgen yapısı oldukça kullanışlı oluyor. Yapmamız gereken şu:
SDL Rect dikdortgen;
şeklinde tanımlamalıyız. Eğer amacımız resmimizi belirli bir koordinata koymak ise şu yöntemi kullanmalıyız:
SDL Rect hedef;
hedef.x x; //
#4
//
#4
resmi koymak istedi#imiz
noktan#n x
resmi koymak istedi#imiz
noktan#n y
hedef.y - y;
SDL BlitSurface(l
image, NULL, screen, &hedef);
Ama eğer amacımız resmin sadece bir bölümünü çizdirmek ise bu yöntemi kullanmalıyız:
SDL Rect dortgenl,dortgen2;
dortgenl.x x; // resmin ekran üzerine
// yerle#tirilece#i x noktast#
dortgenl.y y; // resmin ekran üzerine
// yerle#tirilece#i y noktast#
dortgenl.w — w; // resmin ekran üzerine
// çizilecek geni#li#i
dortgenl.h - h; // resmin ekran üzerine
// çizilecek uzunlu#u
dortgen2.x — x2; // x düzlemindeki ba#lang#ç
//
dortgen2.y — y2; // y düzlemindeki ba#lang#ç
//
SDL BlitSurface(l
image, &dortgen2, screen, &dortgenl1);
Peki ya ekrandaki görüntünün bir kısmını bir yüzeye aktarmak istersek? Onu da bu yöntem ile yapabilirsiniz:
SDL Rect dortgenl,dortgen2;
dortgenl.x xl; ekrandan kopyalanacak
parçan#n sol üst
noktas#n#n x koordinat$
ekrandan kopyalanacak
parçan#n sol üst
noktas#n#n y koordinat#
ekrandan kopyalanacak
parçan#n sa# alt
noktas#n#n x koordinat#
ekrandan kopyalanacak
parçan#n sa# alt
noktas#n#n y koordinat#
dortgenl.y yl;
dortgenl.w
dortgenl.h ya;
//
dortgen2.x
dortgen2.y
xl;
yl;
- yukar#dakinin ayn#s#
yukar#dakinin ayn#s#
SDL BlitSurface(screen,
temp, &dortgenl);
&dortgen2,
Bunun dışında SDL_Rect kullanarak ekrana bir dikdörtgen çizdirmeniz de mümkün. Bunun için bir SDL_Rect tanımlıyorsunuz. Bu dörtgeni yerleştireceğiniz x ve y koordinatlarını, dörtgenin genişliği ile uzunluğunu ve rengini belirledikten sonra SDL_FillRect fonksiyonu ile ekrana istediğiniz koordinata istediğiniz boyutlarda ve istediğiniz renkte bir dörtgen çiziyor. Kod şöyle:
Uint32 renk; // dörtgenimizin renk de#eri
SDL Rect dortgen;
dortgen.x — x; dörtgeni ekran üzerinde
// yerle#tirece#imiz x noktast#
dortgen.y y; // dörtgeni ekran üzerinde
// yerle#tirece#imiz y
dortgen.w — w; // dörtgenimizin geni#li#i
dortgen.h - h; // dörtgenimizin uzunlu#u
SDL FillRect (screen, &dortgen, renk);
Oldukça kolay değil mi? Sanırım rengi nasıl belirttiğimizi merak ediyorsunuz. Ama şimdilik renk konularına girmeyeceğim ama ileride (az ilerde :)) detaylı olarak anlatacağım. Şimdi ise size ekran tazeleme fonksiyonlarını anlatacağım.
2D grafik programlamasında ekrana çizdireceğimiz görüntüleri önce çizdirmek, sonra ekranı tazelemek ve sonra tekrar çizdirmek gerekir. Tazelemezsek ne olacağını basit bir örnek ile açıklayayım. Diyelim ki arkaplanda tam ekran çalışmakta olan bir penceredeki uygulamanız kilitlendi. Onun önündeki daha küçük bir pencerede çalışan uygulamanızın penceresini taşırsanız fark edeceğiniz üzere küçük pencerenin eski bulunduğu yerde görüntüsü (en azından görüntüsünün bir kısmı) hala durur. İşte ekrana çizim yaptıktan sonra ekranı tazelemezsek bu ve buna benzer bir sonuç alırız.
Peki ekranı nasıl temizleyeceğiz? Bunun iki yolu bulunmakta. Birincisi SDL_UpdateRect fonksiyonu ile.
SDL UpdateRect (screen, 0, 0, image->w, image->h);
Ekrandaki görüntüyü sakladığımız screen yüzeyinin 0,0 koordinatından ekrana çizdireceğimiz image yüzeyinin genişliği ve yüksekliği boyunca uzanan alanı tazele komutudur bu. Bunun yerine bütün çizim işlemini bitirince ekranın tamamını tazeleyecek bir SDL_UpdateRect komutu daha kullanışlı olabilir. Şöyle ki: SDL_UpdateRect(screen, 0, 0, 0, 0);
0, 0);
Ekranı tazelemek için kullanabileceğimiz bir diğer yöntem ise SDL_Flip fonksiyonudur. Bu fonksiyon sadece Video modu seçilirken çifte tamponlama (Double Buffering) bayrağı (SDL_DOUBLEBUF) seçilmiş ise kullanılabilir. Çünkü bu komut tamponların değişmesini sağlamak yolu ile ekranı tazeler. Eğer çifte tamponlama özelliğini kullanamıyorsanız bu komut yerine yukarıdaki bütün ekranı tazeleyen SDL_UpdateRect(screen, 0, 0, 0, 0); komutunu kullanın. Ama imkanınız varsa SDL_Flip'i seçmeye gayret edin. Kullanımı:
SDL Flip(screen);
Bunun dışında bir de SDL_UpdateRect fonksiyonunun SDL_UpdateRects adında birden fazla dörtgeni aynı anda tazeleyen farklı bir versiyonu da bulunmaktadır. Bu fonksiyonun kullanımı ise şöyledir:
SDL UpdateRects (
screen, dortgensayisi, *dortgenler);
Şimdi ise birkaç pixel fonksiyonu göreceğiz. Surface'lerin yapısını tanıtırken sadece pixels değişkeninin değiştirilebilir olduğu belirtilmişti. Bu değişkende yüzeyin pixellerinin renk bilgisi saklanmaktadır. Bu değişken dizisinin değerleri değiştirilebilir ve bu değişiklikler sayesinde ekrandaki pixellerin rengi değiştirilir. Bu işi yapan basit iki pixel fonksiyonu yazalım. Biri seçtiğimiz yüzeye istediğimiz renkte bir pixel yerleştirmeye, diğeri de seçtiğimiz yüzeydeki istediğimiz pixel'in renk değerini almamıza yarayacak.
Uint32 getpixel(
SDL Surface *surface,
1
int bpp © surface->format->BytesPerPixel;
/* p renk de#erini almak
istedi#imiz pixel'in adresi */
Uint8 *p - (Uint8 *)surface->pixels
* y * surface->pitch * x * bpp;
switch (bpp)
1
case 1:
return *p;
case 2:
return *(Uint16 *)p;
case 3:
if(SDL BYTEORDER -- SDL BIG ENDIAN)
return << 16 | << 8 | pi2l;
int x, int y)
else
return | plill << 8 | pi2l << 16;
case 4:
return *(Uint32 *)p;
default:
return 0; /* Bu sonuç ç#kmaz ama
ne olur ne olmaz. */
Pixel dizisinde koordinatlar ilk 0,0 koordinatından başlar ilk elemanı ve her elemanda ilk olarak x değeri büyür. Bu büyüme pixel başına düşen bit kadar olur. Pixel başına 1 bit düşüyorsa her bit ayrı bir koordinattır. Ama 3 bit düşüyorsa 3 bitte bir koordinatları bir ileri gider. x koordinatı değeri limitine ulaştığında sıfırlanır ve y değeri bir artar.
Uint8 *p (Uint8 *) surface->pixels
* * surface->piteh * x * bpp;
Satırında yaptığımız işlemde x değerini bpp değişkeni ile çarpıyoruz. bpp değişkeni yüzeyin pixel başına düşen byte sayısını saklıyor. Yukarıda dizinin bir sonraki elemanının koordinat sistemindeki bir sonraki noktanın rengini saklar demiştik ama eğer yüzeyde pixel başına düşen byte sayısı 1 ise doğrudur. Ama bazı durumlarda pixel başına düşen byte sayısı 2 veya 3'e çıkabilir. Mesela RGB renk paleti kullanıldığında her koordinat için ilk byte kırmızı renk değeri, ikincisi yeşil ve üçüncüsü mavi renk değeridir. RGBA renk paletinde ise ilk üçü RGB gibi dördüncüsü ise alfa değeridir. İşte bu yüzden x değerini bpp ile çarptık. Pitch değişkeninde ise yüzeyin bir satırının uzunluğu tutuluyor. y değeri için bir demek x koordinatının limiti kadar gitmiş olmak ve bir nokta daha ileri gitmek demektir.
void putpixel(
SDL Surface *surface,
1
int bpp - surface->format->BytesPerPixel;
/* p yerle#tirmek istedi#imiz pixel'in adresi
int x, int Y;
Uint8 *p - (Uint8 *)surface->pixels
* y * surface->piteh * x *
switch(bpp)
case 1:
*p pixel;
break;
case 2:
*(Uintl16 *)p pixel;
break;
case 3:
if(SDL BYTEORDER -- SDL BIG ENDIAN) (
#5 (pixel >> 16) & Oxff;
pll) (pixel >> 8) & Oxff;
pl2|) 5” pixel & Oxff;
) else |
pl0|J 5 pixel & Oxff;
plll #5 (pixel >> 8) & Oxff;
pl21) # (pixel >> 16) & Oxff;
)
break;
case 4:
*(Uint32 *)p pixel;
break;
j
getpixel fonksiyonuna oldukça benziyor. getpixel fonksiyonunda hedef pixel'in adresini bulup oradaki değerleri alıyorduk, burada ise yine hedef pixel'in adresini buluyoruz, ardından hedef pixel'in değerlerini istediğimiz renk değeri ile değiştiriyoruz. Dikkat edilecek nokta ise renk değerini değiştirirken pixel başına düşen bit sayısına göre hesaplama yapıyoruz. Oldukça basit ama kullanışlı.
Bu arada bu pixel fonksiyonlarını kullanırken veya bir yüzeyin pixel verilerine direk ulaşırken ilk olarak üzerinde çalışacağınız yüzeyi kilitlemelisiniz. Açıkçası dalgınlık ve merak ile kilitlemeden de çalıştırdığım oldu. Bunun nedeni ise bütün yüzeylerin ihtiyacı olmamasıdır. Neden diye sormayın bilmiyorum. Ama öyle.
Peki bunu nasıl anlayacaksınız? SDL_MUSTLOCK fonksiyonu ile. En iyisi size bunu yapan bir kod ile açıklamak.
if ( SDL MUSTLOCK(screen) ) (
if ( SDL LockSurface(screen) < 0 ) (
İprintf |
stderr,
"Yuzey kilitlenemiyor: $shn",
SDL GetError()
Vi
return;
)
Burada ilk olarak screen yüzeyini SDL_MUSTLOCK fonksiyonu ile kontrol eder ve kilitlenmeyi gerektirip gerektirmediğine bakarız. 0 değeri dönerse istediğiniz zaman istediğiniz pixele veri yazabilir, istediğiniz pixelden veri okuyabilirsiniz. Ama 0 verisi dönmezse bu yüzeyi kilitlemeniz gerekir. Böyle olunca da SDL_LockSurface fonksiyonu devreye girer ve parametre olarak girilen yüzey kilitlenir ama bir sorun olur da kilitlenemezse fprintf fonksiyonu ile stderr dosyasına "Yüzey kilitlenemiyor: Hata mesajı" şeklinde bir hata bildirimi yazdırırız.
Uint32 pixel)
Bu arada SDL 1.1.8'den beri yüzey kilitlemek rekürsif, yani ardarda istediğiniz kadar kilit atabilirsiniz bir yüzeye ama bu gibi durumlarda da attığınız her kilit için yüzeyi bir kez daha açmanız gerekir.
Peki kilitlenen yüzeyi nasıl açacağız? SDL_UnlockSurface komutu ile. Kullanımı şöyledir:
SDL UnlockSurface(screen);
Ama SDL_MUSTLOCK fonksiyonu ile beraber kullanmak istiyorsanız -ki tavsiye ederim- şöyle olacak:
if ( SDL MUSTLOCK(screen) ) (|
SDL UnlockSurface(screen);
)
Bu kadar basit.
İlk ders için bu kadarı yeterli. Şu noktaya kadar anlattıklarım ile SDL programları yazmaya başlayabilirsiniz.