Bu sayfadaki yazılar
Sayfanın metni
Sayfa 29
Ş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.
Klavyeyle gezinmek için ← ve → tuşları.
Sayfa 28
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);