Ana Menü
· Ana Sayfa
· Dosyalar
· Dökümanlar
· Forum
· Günün Resmi
· Haber Arşivi
· WWW Linkleri
· Üye Listesi

     Forumlar

 strncpy ve strncpy_s
 Konu adi : Borland c++ Builder ile Amiral Batti
 Rady10 - YerliOyun
 Kabusta Kaybolmak
 Konsol da programı bekletmek
 Oyun programlama icin hangi programlama dilli ?
 flash! şanlıurfa bilgisayar oyununda(no rapid)
 Sevgilim Olur musun?
 Directx'e başlamak isteyenler bi bakın
 PSP programlama
 Flash tan php
 Bilgisyr oyunu yapmam için üniverstde hangi bölüme girmeliym
 www.arshiv.gen.ms
 Cimg.h ilgilenenler icin
 müttefik oyunu

Konu Disi
 Emraah
 Yeni sitemiz açıldı
 Kalp krizi durumunda ne yapılmalı?
 Oyun sektöründe hangi görevde çalışmak isterdiniz?
 Takım arkadaşı sorunu
 msn de renklı nıck
 pc hata veriyor ! YARDIM!!
 Gülmek isteyenler Buraya
 İnanılmaz hl 2 modu görüntüsü
 Computer Languages History

[ Forumlara Git ]


SDL Kütüphanesi Kullanımı

(7576 kelime)
(1240 okuma)   Yazdırılabilir Sayfa




1. SDL 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, Emülatorlerde, 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 olmasada 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.

2. SDL Kurulum

Bu konu aslında basit olmasına rağmen yeni başlayanları biraz zorlayabilir. Yine de elimden geldiğince her platform'da SDL'i nasıl kurup kullanmaya hazır hale getireceğimizi yazmaya çalışacağım.

2.1. Windows

Windows ortamında en yaygın olarak MS Visual Studio, Borland C++ Builder ve Dev-C++ IDE'leri kullanılmaktadır. Ama ben daha önce hiç C++ 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ış. Yinede pek sorun yaşayacağınızı sanmıyorum.

2.1.1. 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ış ingilizce derslerden topladığım bilgi ile yardımcı olmaya çalışacağım.
   
1) http://www.libsdl.org/download-1.2.php adresinden download bölümünen 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.
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:\Program Files\Microsoft Visual Studio\VC98\Lib (büyük ihtimalle sizin bilgisayarınızdada aynı klasördür ama eğer MS VC++'ı kurduğunuz yer farklı ise bu yoluda 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\SDL (diğeri ile aynı şekilde farklı bir klasör olabilir sizin ki, artık duruma göre değişikliği siz yaparsınız. Birde include'un altında SDL
klasörü yok onu sizin yaratmanız gerek.) klasörü altına kopyalayın.
3) Şimdi Visual C++'ı ç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.
4) 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.
5) 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.
6) 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.

2.1.2. Dev-Cpp

Dev-C++ 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-C++ 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 yinede bunları düzeltmek oldukça kolay. İşinizi daha da kolaylaştırmak için ben düzeltilmiş versiyonu sizin için hazırladım, buyrun. Diğer yol ise yukarıdaki gibi geliştirme paketini indirip her dosyayı yerine kurmak. Bu yolu izlerken yapmamız
gerekenler;

1) http://www.libsdl.org/download-1.2.php adresinden download bölümünen 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ğilde 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 -I"<INCLUDE>\SDL" -Dmain=SDL_main parametrelerini girin. Linker başlığı altına ise -lmingw32 -lSDLmain -lSDL 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.

2.1.3 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.

2.2. Linux

Daha sonra ekleyeceğim.     

3. 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, sekiz 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önetmi SDL_Init komutu ile de kullanabiliriz.

Alt sistem bayrakları(flag) listesi:
SDL_INIT_TIMER - Zamanlayıcı -
SDL_INIT_AUDIO - ses -
SDL_INIT_VIDEO - grafik -
SDL_INIT_CDROM - cdrom -
SDL_INIT_JOYSTICK - joystick -
SDL_INIT_EVERYTHING - Bütün sistemleri aktif hale getirir -
SDL_INIT_NOPARACHUTE - SDL'in hata sinyallerini yakalamasını önler -
SDL_INIT_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_Quit();

şeklindedir. Bu komut ile hali hazı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_QuitSubSystem ( 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 yüklü.\n");
else
printf("Video alt sistemi yüklü değil.\n");

şimdi öğrendiklerimizle örnek bir SDL programı yazalım.

Örnek program:

#include "SDL.h"  /* SDL header dosyası. Bütün SDL programları buna ihtiyaç duyar */
#include <stdio.h>

int main() {
    
printf("SDL programı başlatılıyor.\n");
    
/* SDL programı başlatılıp Video ve Ses sistemleri aktif hale getiriliyor */
if((SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)==-1)) {
fprintf(stderr,"SDL programı başlatılamadı: %s.\n", SDL_GetError());
exit(-1);
}

fprintf(stdout,"SDL programı başlatılamadı.\n");

fprintf(stdout,"SDL programı kapatılıyor.\n");
    
/* SDL programı ve bütün alt sistemleri kapatılıyor */
SDL_Quit();
    
fprintf(stdout,"Kapatılıyor....\n");

exit(0);
}

4. 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;

içeriği ise şöyledir:

typedef struct SDL_Surface {
Uint32 flags;                           /* Salt okunur */
SDL_PixelFormat *format;                /* Salt okunur */
int w, h;                               /* Salt okunur */
Uint16 pitch;                           /* Salt okunur */
void *pixels;                           /* oku-yaz */

/* kırpma bilgisi */
SDL_Rect clip_rect;                     /* Salt okunur */

/* Referans sayacı -- yüzey boşaltılırken kullanılır */
int refcount;                           /* çoğunlukla 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şkende yüzeyin her pixel'inin renk bilgisini taşıyor 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şadığaki gibidir.

screen = SDL_SetVideoMode(640, 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 yaratırız. Ekrandaki pixel başına düşen bit 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 herzaman 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 değil.\n");
else
printf("Ekran modu uygun.\n");

şeklindedir. Bunun dışında SDL_GetVideoInfo, SDL_GetVideoSurface, SDL_GetVideoDriverName ve SDL_ListModes gidi fonksiyonlarda 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ında 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ğı heryerde 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:\a.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 parametreyede 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 struct{
Sint16 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ımlamayılız. Eğer amacımız resmimini belirli bir koordinata koymak ise şu yöntemi kullanmalıyız:

SDL_Rect hedef;
hedef.x = x; // resmi koymak istediğimiz noktanın x koordinatı
hedef.y = y; // resmi koymak istediğimiz noktanın y koordinatı
SDL_BlitSurface(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 dortgen1,dortgen2;

dortgen1.x = x; // resmin ekran üzerine yerleştirileceği x noktası
dortgen1.y = y; // resmin ekran üzerine yerleştirileceği y noktası
dortgen1.w = w; // resmin ekran üzerine çizilecek genişliği
dortgen1.h = h; // resmin ekran üzerine çizilecek uzunluğu

dortgen2.x = x2; // resmin çizilirken x düzlemindeki başlangıç noktası
dortgen2.y = y2; // resmin çizilirken y düzlemindeki başlangıç noktası

SDL_BlitSurface(image, &dortgen2, screen, &dortgen1);

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 dortgen1,dortgen2;

dortgen1.x = x1; // ekrandan kopyalanacak parçanın sol üst noktasının x koordinatı
dortgen1.y = y1; // ekrandan kopyalanacak parçanın sol üst noktasının y koordinatı
dortgen1.w = x2; // ekrandan kopyalanacak parçanın sağ alt noktasının x koordinatı
dortgen1.h = y2; // ekrandan kopyalanacak parçanın sağ alt noktasının y koordinatı
    
dortgen2.x = x1; // yukarıdakinin aynısı
dortgen2.y = y1; // yukarıdakinin aynısı
    
SDL_BlitSurface(screen, &dortgen2, temp, &dortgen1);

Bunun dışında SDL_Rect kullanarak ekrana bir dikdörtgen çizdirmenizde 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 noktası
dortgen.y = y; // dörtgeni ekran üzerinde yerleştireceğimiz y noktası
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ır 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 durmakta. İş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);

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 birde SDL_UpdateRect fonksiyonunun SDL_UpdateRects adında birden fazla dörtgeni aynı anda tazeleyen farklı bir versiyonuda 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ğeride seçtiğimiz yüzeydeki istediğimiz pixel'in renk değerini almamıza yarayacak.

Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
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)
{

case 1:
return *p;
case 2:
return *(Uint16 *)p;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 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 + y * surface->pitch + x * bpp;

Satırında yaptığımız işlemde x değerini bpp değişkeni ile çarpıyoruz. bpp değişkeninde yüzeyin pixel başına düşen byte sayısını saklıyor. Yukarıda dizinin bir sonraki elemanının koordinat sisteminde ki 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 üçün 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, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
/* p yerleştirmek istediğimiz pixel'in adresi */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

switch(bpp) {
case 1:
*p = pixel;
break;

case 2:
*(Uint16 *)p = pixel;
break;

case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;

case 4:
*(Uint32 *)p = pixel;
break;
}
}

getpixel fonksiyonuna oldukça benziyor. getpixel fonksiyonunda hedef pixel'in adresini bulup ordaki değerleri alıyorduk, burda 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 verilerilerine direk ulaşırken ilk olarak üzerinde çalışacağınız yüzeyi kilitlemelisiniz. Açıkcası dalgınlık ve merak ile kilitlemeden de çalıştırdığım oldu. Bunun nedeni ise bütün yüzeylerin kilitlenmeye 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 ) {
fprintf(stderr, "Yuzey kilitlenemiyor: %s\n", SDL_GetError());
return;
}
}

Burda 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 oluncada devreye SDL_LockSurface fonksiyonu devreye girer ve parametre olarak girilen yüzey kilitlenir ama bir sorun olurda kilitlenemezse fprintf fonksiyonu ile stderr dosyasına "Yüzey kilitlenemiyor: Hata mesajı" şeklinde bir hata bildirimi yazdırırız.
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.

5. SDL ve Grafik - Bölüm II

Hala grafik konusundayız ama temel konularda fazla birşey kalmadı. Sadece birkaç grafik fonksiyonu ve birkaç yardımcı fonksiyonu anlatacağım. Ardından Event'lara geçeceğiz. İlk olarak SDL_MapRGB fonksiyonundan bahsedeceğim. Bu fonksiyon girdiğiniz parametreler ile RGB cinsinden belirttiğiniz renk değerini Uint32 tipi bir değişkene atar. Bu değişkenin birde SDL_MapRGBA versiyonu bulunmaktadır. Kullanımı aynıdır. Tek fark RGBA değerini girmeniz gerekir. Kullanımları;

Uint32 renk;
renk = SDL_MapRGB (surface->format, kirmizi, yesil, mavi);

Uint32 renk;
renk = SDL_MapRGB (surface->format, kirmizi, yesil, mavi, alfa);
    
surface olarak renk paletini kullanacağınız bir yüzeyi ya da en basiti ekrana çizdirdiğiniz yüzeyi kullanın. Renk değeri seçtiğiniz değer yüzeyin pixel formatında belirtilen palet değerlerine göre belirlenir. Pixel format'ı yüzeylerin pixel verilerinin biçiminin saklandığı veri yapısıdır.

typedef struct{
SDL_Palette *palette; // renk paleti
Uint8  BitsPerPixel; // pixel başına düşen bit sayısı (8,16,24,32)
Uint8  BytesPerPixel; // pixel başına düşen byte sayısı (1,3,4)
Uint32 Rmask, Gmask, Bmask, Amask; /* her renk elementinin tek başına renk değerlerini getirmek için kullanılan
  maske değeri */
Uint8  Rshift, Gshift, Bshift, Ashift; // sola kaydırma değeri gibi bişey önemli değil pek
Uint8  Rloss, Gloss, Bloss, Aloss; // bu da veri kaybı değeri gibi birşey
Uint32 colorkey; // transparan olacak rengin değeri
Uint8  alpha; // bütün yüzeyin alfa değeri
} SDL_PixelFormat;

Pixel formatının içeriğinde colorkey adlı değişkeni ve transparan bir renk sağladığını gördük. Ama bunu nasıl yapabileceğinizi anlatmadım. Şimdi anlatacağım. Bunun yolu SDL_SetColorKey fonksiyonundan geçmekte. Yazılışı;

int SDL_SetColorKey(SDL_Surface *yuzey, Uint32 bayrak, Uint32 maskelenecek_renk);

kullanımı;

SDL_SetColorKey(yuzey, SDL_SRCCOLORKEY,SDL_MapRGB(yuzey->format, r, g, b));
    
Örnekte de gördüğünüz gibi ilk olarak renk anahtarı belirlemek istediğimiz yüzeyi, ardından da işlem bayrağını giriyoruz, en son olarakta transparan olmasını istediğimiz rengi giriyoruz. Bayrak olarak SDL_SRCCOLORKEY değerini vererek belirttiğimiz rengin, belirttiğimiz yüzeyde transparan olmasını sağlıyoruz. Daha önce belirlenmiş bir colorkey'i kaldırmak için bayrak olarak 0 değerini vermeniz yeterli.

Grafik konusunda bahsedeceğim son fonksiyon SDL_DisplayFormat. Bu fonksiyon en basit hali ile uyguladığınız yüzeyin bitlerinin kopyalama ve aynı zamanda çizdirme (sonuçta çizdirirken yaptığınız iş ekrana çizdirdiğiniz yüzeye kopyalamak olduğu için aynı şey oluyor) hızını arttırmaya yarıyor. Yazılışı;

SDL_Surface *SDL_DisplayFormat(SDL_Surface *yuzey);

kullanımı ise;

yeni_hizlandirilmis_yuzey = SDL_DisplayFormat(eskiyuzey);

Bu fonksiyonun yaptığı şey yüzeyin pixel verisini RLE hızlandırma kodlaması ile kodlamak.Grafik konusunu şimdilik bitiriyorum. Şimdi sırada olaylar (event) var.

6. SDL ve Olaylar (Events)

SDL'de olay yakalama işlemleri için her tip olaya ait bir yapıyı içerisinde bulunduran bir olay yapısı bulunmaktadır. Oluşan olaylar bir kuyruğa atılır. Ve bu kuyruktan SDL_PollEvent fonksiyonu yardımı ile çekilir. Kuyruktan alınan bilgide SDL_Event yapısı içerisinde olayın tipi ve olay hakkında bilinmesi gerekilen diğer bilgiler bulunmaktadır. Örnek bir kod için;

SDL_Event olay;

while (SDL_PollEvent(&olay)) {
switch (olay.type){
case SDL_KEYDOWN:
// tuşa basıldı durumu
break;
}
}

Yukarıda SDL içerisinde olay yakalama ve işlemeyi gösteren basit bir örnek var. Bu örneği SDL_Event yapısının içeriğinde bulunan diğer tipler yardımı ile geliştirebilirsiniz. Aşağıda SDL_Event yapısının ve bu yapının içinde bulunan diğer alt yapıların içeriklerini bulacaksınız.

SDL_Event yapı tanımlaması:

typedef union{
Uint8 type;
SDL_ActiveEvent active;
SDL_KeyboardEvent key;
SDL_MouseMotionEvent motion;
SDL_MouseButtonEvent button;
SDL_JoyAxisEvent jaxis;
SDL_JoyBallEvent jball;
SDL_JoyHatEvent jhat;
SDL_JoyButtonEvent jbutton;
SDL_ResizeEvent resize;
SDL_QuitEvent quit;
SDL_UserEvent user;
SDL_SywWMEvent syswm;
} SDL_Event;

Yapı içeriği:

type
Olayın tipi
active
Aktifleşme olayı
key
Klavye olayları
motion
Mouse hakeret olayları
button
Mouse buton olayları
jaxis
Joystick axis motion event
jball
Joystick trackball motion event
jhat
Joystick hat motion event
jbutton
Joystick button event
resize
Uygulama pencere yeniden boyutlandırma olayı
quit
Uygulama çıkış isteği
user
Kullacını tanımlı olay
syswm
Tanımlanmamış pencere yöneticisi olayı

Olay Tipi    Olay yapısı
SDL_ACTIVEEVENT SDL_ActiveEvent
SDL_KEYDOWN/UP
SDL_KeyboardEvent
SDL_MOUSEMOTION
SDL_MouseMotionEvent
SDL_MOUSEBUTTONDOWN/UP 
SDL_MouseButtonEvent
SDL_JOYAXISMOTION SDL_JoyAxisEvent
SDL_JOYBALLMOTION SDL_JoyBallEvent
SDL_JOYHATMOTION SDL_JoyHatEvent
SDL_JOYBUTTONDOWN/UP SDL_JoyButtonEvent
SDL_QUIT SDL_QuitEvent
SDL_SYSWMEVENT SDL_SysWMEvent
SDL_VIDEORESIZE SDL_ResizeEvent
SDL_USEREVENT SDL_UserEvent

SDL'i kullanmaktaki -en azından bu dökümanda- asıl amacımız oyun yapımı olduğu için burada sadece oyun yapımında en çok ihtiyaç duyacağınız olay yapılarının detaylarını vereceğim, diğerleri için SDL'in resmi dökümanına başvurmalısınız. İlk olarak klavye olaylarından bahsedelim. İçeriği;

Yapı tanımlanması:

typedef struct{
Uint8 type;
Uint8 state;
SDL_keysym keysym;
} SDL_KeyboardEvent;

Yapı içeriği:

type    SDL_KEYDOWN veya SDL_KEYUP
state    SDL_PRESSED veya SDL_RELEASED
keysym    basılan tuşun bilgisini saklar

Burda gördüğünüz üzere iki tip olay bulunmakta. Tuşun basılması ve kaldırılması. SDL_KEYDOWN ve SDL_PRESSED bir tuşa basıldığını, SDL_KEYUP ve SDL_RELEASED ise bir tuşun bırakıldığını belirtir. Bu ikisi arasında fark yoktur. Sadece farklı değişkenler tarafından belirtiliyorlar. Hangi tuşa basıldığına ait bilgi ise keysym yapısında tutuluyor.

keysym'nini içeriği ise;

Yapı tanımlanması:

typedef struct{
Uint8 scancode;
SDLKey sym;
SDLMod mod;
Uint16 unicode;
} SDL_keysym;

Yapı içeriği:

scancode    donanıma özel tarama kodu
sym        SDL sanal keysym
mod        o an ki tuş modifiyesi(kötü çeviri, türkçesi shift, control veya alt tuşuna basıldı mı acaba gibi
        birşey)
unicode        dönüştürülmüş karakter

scancode değişkeni klavyeden dönen donanıma özel veridir ve genellikle dokunulmaz, kurcalanmaz. sym en önemli ve en kullanışlı alandır. sym içerisinde SDL'de tanımlı tuş değerleri saklanır. Bu tuşların tanımları için SDLKey yapısının içeriğine bakmak gerekiyor ama bu yapının içeriği çok uzun olduğu için en sona bırakıyorum.Bunlar dışında mod değişkeninde yukarıda da belirttiğim gibi shift, control, alt tuşları gibi tuşlara basılması durumunda basılan tuşa ait veriyi içinde saklar. Bu veriye ulaşmanın bir diğer yoluda SDL_GetModState fonksiyonunu kullanmaktır. Kullanımı;

SDLMod mod;
mod=SDL_GetModState();

SDLMod yapısı içeriği;

typedef enum {
KMOD_NONE  = 0x0000, //herhangi bir modifier'a basılı değil
KMOD_LSHIFT= 0x0001, // sol shift tuşu
KMOD_RSHIFT= 0x0002, // sağ shift tuşu
KMOD_LCTRL = 0x0040, // sol control tuşu
KMOD_RCTRL = 0x0080, // sağ control tuşu
KMOD_LALT  = 0x0100, // sol alt tuşu
KMOD_RALT  = 0x0200, // sağ alt tuşu
KMOD_LMETA = 0x0400, // sol meta?? -bu ne beah- tuşu
KMOD_RMETA = 0x0800, // sağ meta?? -galiba şu yeni windows tuşlarından biri- tuşu
KMOD_NUM   = 0x1000, // numlock tuşu
KMOD_CAPS  = 0x2000, // capslock tuşu
KMOD_MODE  = 0x4000, // bunun ne olduğu konusunda hiç bir fikrim yok
} SDLMod;

SDL içerisinde ayrıca şu tanımlamalarda mevcut;

#define KMOD_CTRL (KMOD_LCTRL|KMOD_RCTRL) // herhangi bir control tuşu
#define KMOD_SHIFT  (KMOD_LSHIFT|KMOD_RSHIFT) // herhangi bir shift tuşu
#define KMOD_ALT  (KMOD_LALT|KMOD_RALT) // herhangi bir alt tuşu
#define KMOD_META (KMOD_LMETA|KMOD_RMETA) // herhangi bir meta tuşu

SDL'de SDL_GetModState gibi iki tane de normal tuşların değerini alabileceğimiz bir fonksiyon bulunmaktadır, adı da SDL_GetKeyState ve SDL_GetKeyName. Kullanımları ise aynı. Sadece bu sefer SDLMod değilde SDLKey tipinde bir değişken tanımlıyoruz. SDLKey'in içeriği ise;

SDLKey            ASCII değeri    Bilinen adı
SDLK_BACKSPACE        '\b'        backspace
SDLK_TAB        '\t'        tab
SDLK_CLEAR                 clear
SDLK_RETURN        '\r'        return
SDLK_PAUSE                 pause
SDLK_ESCAPE        '^['        escape
SDLK_SPACE        ' '        space
SDLK_EXCLAIM        '!'        exclaim
SDLK_QUOTEDBL        '"'        quotedbl
SDLK_HASH        '#'        hash
SDLK_DOLLAR        '$'        dollar
SDLK_AMPERSAND        '&'        ampersand
SDLK_QUOTE        '''        quote
SDLK_LEFTPAREN        '('        left parenthesis
SDLK_RIGHTPAREN        ')'        right parenthesis
SDLK_ASTERISK        '*'        asterisk
SDLK_PLUS        '+'        plus sign
SDLK_COMMA        ','        comma
SDLK_MINUS        '-'        minus sign
SDLK_PERIOD        '.'        period
SDLK_SLASH        '/'        forward slash
SDLK_0            '0'        0
SDLK_1            '1'        1
SDLK_2            '2'        2
SDLK_3            '3'        3
SDLK_4            '4'        4
SDLK_5            '5'        5
SDLK_6            '6'        6
SDLK_7            '7'        7
SDLK_8            '8'        8
SDLK_9            '9'        9
SDLK_COLON        ':'        colon
SDLK_SEMICOLON        ';'        semicolon
SDLK_LESS        '<'        less-than sign
SDLK_EQUALS        '='        equals sign
SDLK_GREATER        '>'        greater-than sign
SDLK_QUESTION        '?'        question mark
SDLK_AT            '@'        at
SDLK_LEFTBRACKET    '['        left bracket
SDLK_BACKSLASH        '\'        backslash
SDLK_RIGHTBRACKET    ']'        right bracket
SDLK_CARET        '^'        caret
SDLK_UNDERSCORE        '_'        underscore
SDLK_BACKQUOTE        '`'        grave
SDLK_a            'a'        a
SDLK_b            'b'        b
SDLK_c            'c'        c
SDLK_d            'd'        d
SDLK_e            'e'        e
SDLK_f            'f'        f
SDLK_g            'g'        g
SDLK_h            'h'        h
SDLK_i            'i'        i
SDLK_j            'j'        j
SDLK_k            'k'        k
SDLK_l            'l'        l
SDLK_m            'm'        m
SDLK_n            'n'        n
SDLK_o            'o'        o
SDLK_p            'p'        p
SDLK_q            'q'        q
SDLK_r            'r'        r
SDLK_s            's'        s
SDLK_t            't'        t
SDLK_u            'u'        u
SDLK_v            'v'        v
SDLK_w            'w'        w
SDLK_x            'x'        x
SDLK_y            'y'        y
SDLK_z            'z'        z
SDLK_DELETE        '^?'        delete
SDLK_KP0                 keypad 0
SDLK_KP1                 keypad 1
SDLK_KP2                 keypad 2
SDLK_KP3                 keypad 3
SDLK_KP4                 keypad 4
SDLK_KP5                 keypad 5
SDLK_KP6                 keypad 6
SDLK_KP7                 keypad 7
SDLK_KP8                 keypad 8
SDLK_KP9                 keypad 9
SDLK_KP_PERIOD        '.'        keypad period
SDLK_KP_DIVIDE        '/'        keypad divide
SDLK_KP_MULTIPLY    '*'        keypad multiply
SDLK_KP_MINUS        '-'        keypad minus
SDLK_KP_PLUS        '+'        keypad plus
SDLK_KP_ENTER        '\r'        keypad enter
SDLK_KP_EQUALS        '='        keypad equals
SDLK_UP                     up arrow
SDLK_DOWN                 down arrow
SDLK_RIGHT                 right arrow
SDLK_LEFT                 left arrow
SDLK_INSERT                 insert
SDLK_HOME                 home
SDLK_END                 end
SDLK_PAGEUP                 page up
SDLK_PAGEDOWN                 page down
SDLK_F1                     F1
SDLK_F2                     F2
SDLK_F3                     F3
SDLK_F4                     F4
SDLK_F5                     F5
SDLK_F6                     F6
SDLK_F7                     F7
SDLK_F8                     F8
SDLK_F9                     F9
SDLK_F10                 F10
SDLK_F11                 F11
SDLK_F12                 F12
SDLK_F13                 F13
SDLK_F14                 F14
SDLK_F15                 F15
SDLK_NUMLOCK                 numlock
SDLK_CAPSLOCK                 capslock
SDLK_SCROLLOCK                 scrollock
SDLK_RSHIFT                 right shift
SDLK_LSHIFT                 left shift
SDLK_RCTRL                 right ctrl
SDLK_LCTRL                 left ctrl
SDLK_RALT                 right alt
SDLK_LALT                 left alt
SDLK_RMETA                 right meta
SDLK_LMETA                 left meta
SDLK_LSUPER                 left windows key
SDLK_RSUPER                 right windows key
SDLK_MODE                 mode shift
SDLK_HELP                 help
SDLK_PRINT                 print-screen
SDLK_SYSREQ                 SysRq
SDLK_BREAK                 break
SDLK_MENU                 menu
SDLK_POWER                 power
SDLK_EURO                 euro

Gördüğünüz gibi uzun. Fonksiyonun kullanımı ise;

SDLKey key;
key=SDL_GetKeyState();

şeklindedir.Son olarak keysym veri yapısı içerisindeki son değişken olan unicode'da ise basılan tuşun unicode verisi saklanır. Tabii bunun için önceden SDL_EnableUNICODE fonksiyonu ile Unicode'u aktif hale getirmek gerekir. Detaylar için SDL'in resmi dökümantasyonuna bakın. Oyun yapımı konusunda çokta gerekli olmadığı için burda anlatmayacağım.Bunun yerine size çok işe yarar bulduğum bir fonksiyonu tanıtmak istiyorum, SDL_EnableKeyRepeat foksiyonunu.Bu fonksiyon basılı tuttuğunuz tuşun tekrar oranını belirler veya tekrar özelliğini etkisiz hale getirir. Kullanımı;

int SDL_EnableKeyRepeat(int delay, int interval);

şeklindedir. delay değişkeni tuş tekrar edilmeden önce ne kadar basılı tutulması gerektiği belirtir. interval ise tekrar hızını belirtir. İkisininde değeri milisaniye cinsindendir. Eğer delay değişkenini 0 yaparsanız tekrar özelliği tamamiyle etkisiz hale gelir. Uygun varsayılan değerler SDL içerisinde SDL_DEFAULT_REPEAT_DELAY ve SDL_DEFAULT_REPEAT_INTERVAL adları ile tanımlanmıştır.

Klavye olayları ile ilgili anlatacaklarım bu kadar sırada mouse olayları var. Mouse ile ilgili olaylar için kullanılan iki tane yapı var. Bunlar SDL_MouseMotionEvent ve SDL_MouseButtonEvent. Bu yapılar SDL_Event yapısı içerisinde motion ve button adları ile tanımlanmışlardır. Motion mouse'un hareket etmesi ile oluşan olayları kapsar. Button ise mouse'un tuşlarına bastığınızda oluşan olayları kapsar. İlk olarak motion'dan bahsedelim.

SDL_MouseMotionEvent yapısının içeriği;

typedef struct{
Uint8 type;
Uint8 state;
Uint16 x, y;
Sint16 xrel, yrel;
} SDL_MouseMotionEvent;

şeklindedir. Ve;

type        için tek bir tip bulunmaktadır ve o da SDL_MOUSEMOTION 'dur.
state        o an ki mouse tuşlarının durumları
x, y        mouse'un X/Y koordinatları
xrel, yrel    mouse'un X/Y koordinatlarındaki göreceli hareketi

temsil eder.

SDL_MouseButtonEvent yapısının içeriği ise;

typedef struct{
Uint8 type;
Uint8 button;
Uint8 state;
Uint16 x, y;
} SDL_MouseButtonEvent;

şeklindedir. Açıklamak gerekirse;

type    SDL_MOUSEBUTTONDOWN veya SDL_MOUSEBUTTONUP tipleri
button    Olayın hangi tuşla alakalı olduğu (SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE, SDL_BUTTON_RIGHT)
state    SDL_PRESSED veya SDL_RELEASED yani tuşa basıldı mı? yoksa tuş bırakıldı mı?
x, y    Basılma veya bırakılma anındaki X/Y koordinatları

dır.

Mouse olaylarını yakalamak için klavye olaylarında olduğu gibi en başta belirttiğimden farklı bir yol daha vardır. Bu yol ise SDL_GetMouseState fonksiyonundan geçer.

Uint8 SDL_GetMouseState(int *x, int *y);

şeklinde yazılır. X veya Y koordinatlarını girmek istemezseniz NULL değeri girebilirsiniz. Bu fonksiyon geriye basılan tuşa ait bilgiyi geri döndürür. Tuşa ait bilgiye ulaşmak için SDL_BUTTON(X) makrosunu kullanabilirsiniz. Bir örnek vereyim.

SDL_PumpEvents();
if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(1))
printf("Sol Mouse tuşuna basıldı.\n");

Yukarıda SDL_PumpEvents fonksiyonunu kullandık. Bu fonksiyon oluşan olaylardan gelen bilgileri derleyip olay kuyruğuna koyar. Bir olayın olay kuyruğuna konması için bu fonksiyonun çağrılması gerekir ama SDL_PollEvent ya da SDL_WaitEvent fonksiyonlarını kullanıyorsanız bu fonksiyonu kullanmanıza gerek kalmaz. SDL_WaitEvent fonksiyonu ise özel olarak belirtilmiş bir olayın gerçekleşmesini bekler. Bu olay gerçekleşene kadar programın kapanmasını engeller. Kullanımı;

int SDL_WaitEvent(SDL_Event *event);

Kullanımı nerede ise SDL_PollEvent'ın aynısıdır ama aradaki fark SDL_WaitEvent bir olay gerçekleşene kadar programı bekletir. SDL_PollEvent ise gerçekleşen olay var mı diye bakar, varsa işlem yapar, yoksa devam eder.

7. SDL ve Ses (Audio)

SDL içerisindeki ses fonksiyonları genel olarak aşağı seviye (low level) ses programlaması kullanılacak yazılımlar için tasarlanmıştır. Bu nedenle ses konusunda SDL'e kendi yazdığınız kod ile taklalar attırmak istemiyorsanız ya da tek yapacağınız basit bir wav dosyasını açıp çalmak değilse size kolaylıklar ve gelişmiş özellikler sunan bir ses kütüphanesi olan SDL_Mixer'ı kullanmanızı tavsiye ederim. Bu kütüphane SDL üzerinden çalışıyor ve size oldukça gelişmiş bir çok özelliği kolayca kullanım imkanı sunuyor. Bu kütüphaneye SDL'in websitesinden "Libraries" bölümünden ulaşabilirsiniz. SDL içerisindeki ses fonksiyonlarına dönelim. İlk olarak bilmeniz gereken bu fonksiyonları kullanmak için önce SDL_INIT_AUDIO alt sistemini aktif hale getirmelisiniz. Basitçe açıklamak gerekirse ilk olarak ses sistemini açacağız. Ardından ses dosyasından veriyi ki bu dosya Wav uzantılı olmalı, hafizaya yükleyeceğiz. Daha sonra ise bu veriyi ses sistemine çalması için ileteceğiz. Şimdi fazla detaya inmeden basitçe ses sistemini nasıl açacağınızı ve bir ses dosyasını nasıl yükleyip, çalacağınızı anlatacağım. İlk önce ses sistemini nasıl açacağımızdan bahsedeceğim.

SDL_AudioSpec fmt;  /* SDL_AudioSpec ses ayarlarına ait bilgilerin saklandığı veri yapısı.
             ılk olarak bu tip bir yapı tanımlayıp ona istediğimiz değerleri giriyoruz.
             Ardındanda bu yapıyı SDL_OpenAudio fonksiyonunda parametre olarak kullanarak
             istediğimiz değerlerde ses sistemini açıyoruz */

/* 22 Khz 'de 16 bit stereo ses */
fmt.freq = 22050;        // frekans değeri
fmt.format = AUDIO_S16;    // veri formatı
fmt.channels = 2;        // kanal sayısı 1- mono, 2- stereo
fmt.samples = 512;        // sample'ların tampon büyüklüğü
fmt.callback = mixaudio;    // ses tamponunu doldurmak için çağırılacak fonksiyon
// bu fonksiyonu aşağıda yazacağım
fmt.userdata = NULL;    // fonksiyona girilecek parametrelerin işaretçisi

/* Yukarıdaki değerler oyunlar için uygun değerlerdir */

/* SDL_OpenAudio fonksiyonuna parametre olarak yukarıda değerlerini
girdiğimiz SDL_AudioSpec veri yapısı verilir ve "Voila!" ses sistemi açılır.
Geriye -1 değeri dönerse bir sorun çıkmış ve ses sistemi açılamamış demektir. */

if ( SDL_OpenAudio(&fmt, NULL) < 0 ) {
fprintf(stderr, "Ses sistemi açılamıyor : %s\n", SDL_GetError());
exit(1);
}
    
/* Bu satırı girmeden programınızdan ses gelmeyecektir.
Bunun nedeni SDL'in program hazır olana kadar istediğiniz
ses ayarlarını yapabilmenize imkan tanımasıdır */

SDL_PauseAudio(0);

    ....


/* ses ile işiniz bitince SDL_CloseAudio fonksiyonunu kullanarak ses sistemini kapatmayı unutmayın. */
SDL_CloseAudio();


Ses sistemini açmak kısaca böyle. Sırada bir ses dosyasını hafizaya yüklemek ve çalmak var.

Örnek kodumuzda ilk olarak ses verisini saklayacağımız veri yapısını tanımlıyoruz.

#define NUM_SOUNDS 2
struct sample {
Uint8 *data;
Uint32 dpos;
Uint32 dlen;
} sounds[NUM_SOUNDS];

Ses stereo olacağı için ses sayısını 2 yaptık. data ses verileri için, dpos verilerin pozisyonu için ve dlen ise ise verinin uzunluğuna ulaşmak için kullanılıyor.    

Bu fonksiyon ile yaptığımız şey temel olarak SDL_LoadWav fonksiyonu ile hafızaya yükleyeceğimiz bir ses dosyasının verilerini SDL için uygun şekilde formatlamak. Bu fonksiyon yukarıdaki ses sistemini açmak için kullanabileceğimiz kodlar arasında kullanılıyor.
    
void mixaudio(void *unused, Uint8 *stream, int len)
{
int i;
Uint32 amount;
    
for ( i=0; i<NUM_SOUNDS; ++i ) {
amount = (sounds[i].dlen-sounds[i].dpos);
if ( amount > len ) {
amount = len;
}
SDL_MixAudio(stream, &sounds[i].data[sounds[i].dpos], amount, SDL_MIX_MAXVOLUME);
sounds[i].dpos += amount;
}
}

    
Bu fonksiyon ise kendisine parametre olarak girilen dosyayı yükler ve çalar. Ama önceden ses sisteminin açılması gerekir. Yukarıdaki fonksiyonu ise ses sistemini açarken kullandığımız kodlar arasında kullanmıştık. Aklınızda bulunsun.

void PlaySound(char *file)
{
int index;             //sayaç değişkeni
SDL_AudioSpec wave;    //ses verisi ayarları
Uint8 *data;        //ses verisi
Uint32 dlen;        //uzunluğu
SDL_AudioCVT cvt;    //ses verisinin formatını değiştirirken kullanılan veri yapısı
    
/* Boş veya bitmiş bir ses slotu aranır */
for ( index=0; index<NUM_SOUNDS; ++index ) {
if ( sounds[index].dpos == sounds[index].dlen ) {
break;
}
}
if ( index == NUM_SOUNDS )
return;
    
/* Ses dosyası yüklenir ve 22kHz 16-bit stereo ya çevrilir */
if ( SDL_LoadWAV(file, &wave, &data, &dlen) == NULL ) {
fprintf(stderr, "Yüklenemiyor %s: %s\n", file, SDL_GetError());
return;
}
SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq,AUDIO_S16,   2, 22050);
cvt.buf = malloc(dlen*cvt.len_mult);
memcpy(cvt.buf, data, dlen);
cvt.len = dlen;
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(data);
    
/* Ses verisini slota yerleştir (hemen çalmaya başlar) */
if ( sounds[index].data ) {
free(sounds[index].data);
}
SDL_LockAudio();
sounds[index].data = cvt.buf;
sounds[index].dlen = cvt.len_cvt;
sounds[index].dpos = 0;
SDL_UnlockAudio();
}


Fazla detaylı değil biliyorum. Ama yakın zamanda sizin için daha kullanışlı olacağını düşündüğüm SDL_Mixer kütüphanesi içinde bir dökümantasyon hazırlayacağım. Orda istediğiniz miktarda bilgiye erişebileceksiniz. şimdilik hepsi bu kadar.

8. SDL ve Zaman

Sıra geldi SDL içerisindeki zamanla ilgili fonksiyonlara. İlk olarak SDL_Delay fonksiyonunu anlatacağım. Yazılışı;

Uint32 zaman=10;
SDL_Delay(zaman);

Bu fonksiyon girilen parametre kadar milisaniye süresince programı bekletir. Ekrana yeni bir çizim yapmadan hemen öncesine ya da bütün çizimler bittikten hemen sonrasına bir adet SDL_Delay(1); satırı eklemeniz programınızın güçlü makinalarda beklediğinizden hızlı çalışmasını engeller. [ ed: Günümüzde bu yöntem kesinlikle tavsiye edilmez. Programınızın her bilgisayarda beklediğiniz sabit hızda çalışmasını istiyorsanız dökümanlar bölümünde yer alan "Oyun Programlarında Doğru Zamanlama" isimli dökümanda anlatılan yönemlere benzer teknikleri uygulamanız gerekir ]

Bunun dışında SDL_GetTicks fonksiyonu oldukça işinize yarayabilecek bir fonksiyondur. Bu fonksiyon SDL programı çalıştırıldığından beri kaç milisaniye geçtiği değerini verir. 49 günden sonra değer başa dönüyormuş sanırım. Kullanımı;

Uint32 gecenzaman;
gecenzaman=SDL_GetTicks();

Bunlar dışında 3 tanede timer fonksiyonu bulunmaktadır. Bunlar SDL_AddTimer, SDL_RemoveTimer ve SDL_SetTimer dır. Ve SDL_Delay ve SDL_GetTicks fonksiyonları için gerekmese de, bu fonksiyonları kulllanabilmek için SDL_INIT_TIMER alt sistemini aktif hale getirmeniz gerekmektedir. SDL_AddTimer fonksiyonu belirtilen miktarda milisaniye geçince belirtilen bir fonksiyonu çağıran bir timer ekler. Yazılışı;

my_timer_id = SDL_AddTimer(30, cagrilan_fonk, fonk_parametreleri);

şeklindedir. SDL_RemoveTimer() fonksiyonu ise eklenmiş bir timer'ı kaldırmak için kullanılır. Bunun için fonksiyona parametre olarak kaldırmak istediğiniz timer'ın id'si girilir. Bu fonksiyonun yazılışı;

SDL_RemoveTimer(my_timer_id);

şeklindedir.SDL_SetTimer fonksiyonu ise belirtilen miktarda milisaniye geçince belirtilen fonksiyonu çağırır. Yazılışı;

SDL_SetTimer(30, cagrilan_fonk);

şeklindedir. SDL_SetTimer ile çalıştırılan bir timer'ı iptal etmek için;

SDL_SetTimer(0, NULL);

kodunu kullanmalıyız. Aslında bu fonksiyon eski sürümlerle uyumluluğu bozmamak için saklanmıştır ama SDL_AddTimer ve SDL_RemoveTimer fonksiyonları bu fonksiyondan daha yeni ve daha üstündür ayrıca birden çok timer'ı kullanmanıza imkan tanırlar.Dikkat edilmesi gereken nokta Timer fonksiyonları çalışırken ayrı bir thread veya alarm sinyalleri (alarm signals) kullanırlar ve makinaya bağımlıdırlar. Bu nedenle kullanırken dikkatli olunmalıdır.
Ozan Emirhan Bayyurt {ragnor}
Website: http://www.geocities.com/ragnor_whr/
E-mail: ragnor_whr@yahoo.com
Tarih: 27/06/2005

www.oyunyapimi.org
  

[ Geri Dön: Oyun Yapımı (Genel) | Bölümler İndeksi ]




Web site powered by PHP-Nuke
Web site engine\'s code is Copyright © 2002 by PHP-Nuke. All Rights Reserved. PHP-Nuke is Free Software released under the GNU/GPL license.
Sayfa Üretimi: 0.050 Saniye