Giriş
Bu yazı, OpenGL uygulamaları için Mark Kilgard tarafından
yazılmış olan GL kullanım elaygıttakımı (Utility Toolkit)
GLUT ile ilgili serinin devamıdır. Daha önceki yazımızda
belirttiğimiz gibi (
Pencereler ve Canlandırımlar)
GLUT, herhangi bir OpenGL geliştiricisi için ilginç ve kullanışlı
bir elaygıttakımıdır. Çünkü, taşınabilir düzgü (code) yazmanıza
olanak tanır. GLUT, pencere yönetiminin ve GUI arayüzünün altında
yatan pis ayrıntıları geliştiriciden gizler.
GLUT, bir kesim subAPI'lere bölünmüştür. Bu ayki sayıda
Pencereler Yönetimi subAPI'si betimlnecektir. Adından da
anlaşıldığı üzere, OpenGL uygulamanız tarafından kullanılan
pencereler ile ilgili görevlere bakar. Bu bağlamda, Yaratım,
yokedim, pencere ikonu olusturumu; itim, pat diye ortaya çıkarım,
gizlenim, hareket ettirim; başlıkların, bulunulan yerlerin
ayarlanımı, vs..
Pencere Yonetimi Sub-Api'si
Burada GLUT'da pencerelerin yönetimi tarafından desteklenen
fonksiyonların tam bir dizelgesi (listesi) verilmektedir.
(Sürüm 3.6):
int glutCreateWindow(char *name) |
Yeni bir üst düzey penceresi yaratır. |
int glutCreateSubWindow(int win,
int x, int y, int width, int height) |
Bir alt pencere yaratır. |
void glutSetWindow(int winId) |
O anki pencerenin winID'si (pencere kimliği) biçimindeki ID
(kimlik) ile pencereyi oluşturur. |
int glutGetWindow(void) |
O anki pencere için kimliklendirici ister. |
void glutDestroyWindow(int winId) |
WinId tarafından belirtilen pencereyi yok eder. |
void glutPostRedisplay(void) |
O anki pencerenin yeniden görüntülenme icin gereksinimi olan
olay işlemcisini GLUT'a söyler. |
void glutSwapBuffers(void) |
O anki pencere için tampon bölge değiştokuşu yapar. |
void glutPositionWindow(int x, int y) |
Pencerenin konumunda değişiklik isteminde bulunur. |
void glutReshapeWindow(int width, int height) |
Pencerenin ölçülerinde değişiklik isteminde bulunur. |
void glutFullScreen() |
O anki pencerenin tüm ekranı kaplaması isteminde bulunur. |
void glutPopWindow(void)
void glutPushWindow(void) |
O anki pencereyi yığıttaki diğer pencerelere göre iter
veya üste çıkarır. |
void glutShowWindow(void)
void glutHideWindow(void)
void glutIconifyWindow(void) |
O anki pencereyi gösterir, saklar veya ikonlaştırır. |
void glutSetWindowTitle(char *name)
void glutSetIconTitle(char *name) |
Penceredeki veya ikonlaştırılmış penceredeki bağlık
çubuğunu ayarlar. |
Alt Pencerelerin
Kullanımı
Yukar}daki fonksiyonların birçoğunun kullanımı oldukça basittir.
Bunlardan bazıları ilk yazımızda gözden geçirilmişti:
glutPostRedisplay, glutCreateWindow, glutPositionWindow,
glutSwapBuffers,..vs. Diğerleri yeni olmalarına karşın
kullanım açısından önemsizdirler ve glutSetIconTitle,
glutFullScreen, ...vs. hakkında yukarıdaki açıklamalar
işlevleri konusunda yeterlidir. Fakat alt pencerelerin
kullanımları o kadar da basit değildir. Bu yüzden size basit bir
örnek vermeye ve onun kullanımı için gerekli olan
ayrıntıları kısaca tartışmaya karar verdik.
Aşağıda küçük bir OpenGL-GLUT örnekgösterimi (demo) icin kaynak
düzgüsü (kodu) sunulmaktadır. (../../common/March1998/example1.c,
../../common/March1998/Makefile). Bu örnekgösterimin amacı size:
(a) Bir alt pencerenin nasıl yönetileceğini,
(b) Klavyenizin OpenGL uygulamanız ile etkileşimli olarak nasıl
kullanılabilecegini,
(c) Bir OpenGL penceresinde bir metni nasıl görüntüleştireceğinizi
(render) göstermektir.
(Tartışmaları izlerken ../../common/March1998/example1.c'nin kaynak düzgüsünün çıktı
olarak bir biçimde elinizde olmasıná lutfen özen gösteriniz.)
İlk önce main() fonksiyonuna bir göz atalım. Diğer GLUT
uygulamalarında olduğu gibi başlangıç tanımlamaları ile başlıyor:
Güdüm satırı seçeneklerinin yazılması, görıntı kipinin seçilmesi,
öncelikli pencerenin yerinin ve boyutunun ayarlanması.
Uygulamamızın birden çok pencerenin yönetimine yönelik olmasindan
dolayı, glutCreateWindow tarafından verilen tamsayı
değerli pencere kimlik (ID) numarasını depolamak önemlidir.
winIdMain değişkeni pencere tutamağıdır (handle).
Bundan sonra, winIdMain penceresi ile ilgili olaylar
içn geriçağırım (callback) fonksiyonlarının ayarlanmasına sıra gelir.
Birçok geriçağırım (callback) fonksiyonu tanımlanır ve tümü
ana pencerede bir görev üstlenir: görüntüyü çizen
(mainDisplay) görüntü fonksiyonu, pencere çerçevelerinin
tüm dönüşımlerini yöneten (mainReshape) fonksiyonu,
klavye ve baska olayların sırada beklemediği zaman canlandırımı
(animasyonu) yöneten boşakoşum (idle) tarafından başlatılan
etkinlikleri yöneten klavye. (idle'nin rolunun daha
ayrıntılı anlatımı için
Pencereler ve Canlandırımlar bölümüne bakınız.)
Bilinmesi gereken ilk önemli konu, bir GLUT uygulamasında
yalnızca bir tane boşakoşan geriçağırım (callback)
fonksiyonu olabileceğidir. Uygulamada boşakoşum (idle) fonksiyonu
tım pencereler icin bütüneyaygındır (global). Bunu, idle()
fonksiyonlarinızı biçimlendirirken dikkate alınız. Tüm pencerelerin
ve alt pencerelerin yenilenmesinde uygulamanızda görev
almalılardır.
Program düzgüsüunde (kodunda) bir alt pencerenin yaratılması
gelir (winIDSub). Alt pencere yapmak için üst düzey
pencereye bir kimlik (ID) sağlamak gerekir. Bulunulan durumda
ilgili alt pencerenin winIDMain'in iç koordinatlarına göre
piksel türünden x ve y koordinatları ve istenilen alt pencerenin
piksel türünden yükseklik ve genişliği kimlik olarak düşünülebilir.
Alt pencereyi yarattıktan sonra GLUT programımıza bir tutamak
(handle) gönderir ve winIDSub için uygun geriçağırım
(callback) fonksiyonlarının ayarlanması için hazır duruma gelinir.
Örnekgösterimimizde iki tane geriçağırım (callback) fonksiyonunun
ayarını yapmaktayız: görüntü (subDisplay) ve yeniden biçimlendirme
(subReshape).
GLUT bir alt pencere açtığında, bunu tüm OpenGL çevre koşulları
ile destekler. Alt pencerelerin kullanımı sırasında bir başarım
(performans) kısıtı ortaya çıkar. Çünkü, grafik kartının
sürücüsü pencereler arası her geçişte bu pencereler için ayrılmış
olan bellek alanlarını yenilemek zorundadır. Her pencere bağımsız
OpenGL koşulları sayesinde kendi koordinat sistemine sahiptir.
../../common/March1998/example1.c' de koordinat sistemleri sırasıyla mainDisplay()
ve subDisplay()' da ayarlanmıştır. Şimdi bu iki görüntü
fonksiyonunu kendiniz deneyebilirsiniz ve eğer Ocak ayında OpenGL
hakkındaki yazımızı izlediyseniz (
"")
anlama konusunda bir sorun çıkmayacaktır.
mainDisplay() fonksiyonu köşeleri kırmızı, yeşil ve mavi
renklerde bir üçgen çizer. OpenGL, köşeler arasında renkleri
inrepolasyonla üreterek çokgeni doldurur. Üçgeni görüntüleştirmeden
önce dönen bir şekil izlenimi elde edebilmek için, üçgenin z-ekseni
etrafında dönmesini (pencere ekranına dik olarak) sa\u glayan
glRotate deyimi eklenmiş ve dönme açısı (spin)
idle()' da yavaşça arttırılarak kullanılmıştır.
winIdSub'a eçlik eden görüntü fonksiyonunda olduğu
gibi süreç çok kestirmedir. Önce arka planı gri bir renkle
temizler, sonra alt pencereye yeşil bir çevreselsınır çizer
ve son olarak metni görüntüleştirir. GLUT altinda metin
görüntüleştirmenin nasil yapıldığı daha sonra açıklanacaktır.
Bu an icin, glRasterPos2f(x, y) ile metnin nereye
çizileceğinin ayarlarının yapilabileceğine, ve ayni zamanda,
kullanılan x, y koordinatlarının alt pencerenin koordinat
sistemine (subReshape()' de tanımlanmıştı) göre
verildiğine dikkat çekmek yeterlidir.
Alt pencere canlandırımdan gelen veriler icin metin ortamı
olarak rol oynar. Bu aptalca bir uygulamadır; metin ortamı ana
pencerede oluşturulabilir ve aynı sonuca başarıyla ulaşılabilirdi
(üstelik daha verimli bir şekilde). Bununla beraber, Ozel
durumlarda metin ortamı için bir alt pencere açmak bir anlam
kazanabilir. Ornegin, canlandırımın ışıklar ve çevresel etkilerle
bezenmiş 3 boyutlu olması durumunda metin ortamını ışıklar,
perspektif etkiler, gölgelemeler ve sislerle bozmak
istemediğinizde geçerlidir. Böyle durumlarda alt pencere 3 boyutlu
canlandırımdan bütünüyle ayrıldığı için kullanışlı olur.
Üst düzey pencere ile alt pencere için kullanılan yeniden
biçimlendirme (reshape) geriçağırım (callback) fonksiyonları
arasında cok önemli fark bulunmaktadır. Bir yeniden
biçimlendirme (reshape) olayı başlatıldığında yalnızca üst
düzey pencere yeniden biçimlendirme geriçağırım fonksiyonu
(örneğimizde mainReshape()) devreye sokulur.
subReshape yeniden biçimlendirme geriçağırım fonksiyonu
mainReshape'in içinden çağrılmalıdır.
Bu durum, alt pencerelerin yerleşim ve biçimlerinin üst düzey
pencerenin büyüklük ve biçimiyle sınırlandırılmış olmasından
dolayı etkilidir. Bu yüzden, eğer mainReshape() icin
program düzgüsünü (kodunu) okuyacak olursanız, önce üst düzey
pencere için izdüşüm matrisini oluşturduğumuzu, sonra da
winIDsub ile belirtilen alt pencereye çevrildiğini ve
alt pencerenin yeniden biçimlendirme fonksiyonunun
sonradan kullanmak istediğimiz winIDMain'e göre verilen
yükseklik ve genişlik ile beraber çağrıldıgını göreceksiniz.
OpenGL uygulamasında idle() geriçağırım fonksiyonunun
tum üst düzey ve alt pencereleri güncellemesi gerektiğini daha
önce belirtmiştik. Örneğimizde, idle() ilk once
canlandırım durum değişkenlerini (time ve spin)
güncellemekte ve sonra hem ana hem de alt pencereyi yeniden
görüntülenmesi isteminde bulunmaktadır.
Klavye
Programa iki tane etkin tuş eklenmiştir. ("i" tuşuna basarak
metin ortamını kapatıp açabilirsiniz ve "q" tuşu ile uygulama
ortamından çıkabilirsiniz. Deneyin, göreceksiniz :)
Klavyenizden bir tuşa her bastığınızda GLUT'un olay işlemci
sürücüsü bunu bir klavye olayı olarak yazmaçlar. Bu olaylar klavye
geriçağırım (callback) fonksiyonları tarafından yönetilir.
İlke olarak her pencere kendi geriçağırım fonksiyonuna sahiptir.
Fare (mouse) verilen bir pencere (veya alt pencere) içindeki
(x, y) konumunda bulunduğunda ve bir klavye olayi başlatıldığında
o pencere ile ilgili olan klavye geriçağırım fonksiyonu devreye
sokulur. Bu geriçağırım fonksiyonu argümanlar olarak tuşa ait
olan ASCII simgesini (imlenmemiş simge: unsigned char ve
imlecin o anki x, y konumunu alır. ../../common/March1998/example2.c' de x, y icin bir
kullanım sunulmamaktadır ama, bu güzel özelliğin üstünlüklerini
kendi uygulamalarınızda kullanacagınıza eminim.
Örnekgösterimimizde yalnızca üst düzey penceresi
klavye geriçağırımına sahiptir. Eger, imleç alt pencere içindeyken
"i" veya "q" tuşlarına basarsanız hiçbir şeyin olmadığını
göreceksiniz. Benimsenmiş olarak, bir pencere yaratıldığında ve
hiç klavye geriçağırımı yazmaçlanmadığında (registered) tüm tuş
vuruşları gözardı edilir. Bunu, ileride birden fazla pencere
kullandığınızda ve klavyeyi etkinleştirmek istediğinizde
unutmamanız gerekir.
Son olarak, glutKeyBoardFunc(). fonksiyonuna NULL
degeri atanarak klavye geriçağırımlarının üretilmesinin
önlenebileceğini vurgulayabiliriz.
Metin Görüntüleştirimi
OpenGL ve GLUT altında metin oluşturma olanaği oldukça
yetersizdir. Bunu söylediğim için üzgünüm ama bu doğrudur.
OpenGL kitaplığında metin oluşturmanın neden bu kadar
gözardı edildiğinden tam olarak emin değilim. SGI'in eski
GL kitaplığının grafik kipinde metin oluşturmayı yöneten
birkaç yüksek düzeyli fonksiyonu vardı ve ayrıca ek olarak da
fontları değiştirmek için yardımcı kitaplığı bulunmaktaydı.
OpenGL sıfırbirharitası oluşturmak için çok ilkel
yönergeleri destekler ve bunun anlamı her simge için
sıfırbirharitalarını oluşturan kitaplığı çözınırlığe,
fontların ölçeklerine ve bu gibi özeliklere dikkat ederek
kendinizin yapacak olmasıdır.
GLUT, OpenGL ile metin kullanımındaki ikilemi biraz da olsa
çözmektedir. O, yeri glRasterPos tarafından tanımlanan
tek bir simgeyi ekranda oluşturan glutBitmapCharacter'i
sağlamaktadır. katarları olustururken yaşamı kolaylaştıran
drawString() ve drawStringBig() fonksiyon
ikilisi de ayrıca eklenmiştir.
Sonuç
Burada, GLUT alt pencerelerinin kullanımına çok basit bir
giriş yapılmış bulunulmaktadır. Bu anda, bunlarla denemeler
yapmanın ve değişik çalışmatabanlarında (platformlarda)
sınamanın yararlı olacagını belirtirken vurgulanması gereken
nokta GLUT alt pencerelerinin, ne yazıkki, her yerde tam etkin
olmadığıdır. 3Dfx tabanlı kartları bulunan kullanıcılar donanım
kısıtlamalarından dolayi alt pencerelerin kullanımının olmadığınğ
goreceklerdir. Aynı zamanda, bazı özel çalışmatabanlarında
(platformlarda) alt pencereleri kullanırken büyük bir başarım
sorunu bulunmuştu. Örneğin, 2Mb Matrox Millenium'lu bir Linux
Alpha altinda bir alt pencere kullanımı uygulamanın iki kat
yavaş çalışmasına sebep olmaktadır. Çünkü, büyük olasılıkla
Alpha için olan X sunucusu halen herhangi bir donanım ivmesini
desteklememektedir. Öte yandan, SGI'in OpenGL sürücülü bir
2Mb ATI RageII'li Windows 95 altında aynı uygulama olağanüstü
bir şekilde çalışmaktadır.
Linux'un çok hızlı bir şekilde gelişim göstermesinden dolayı
yakın bir gelecekte bu başarım sorunlarının ve uyumsuzlukların
giderilmesi çok olasıdır. Bu an için bunların farkında olup
çoklu pencere kullanımında dikkatli olmak gerekmektedir.
Kuşkusuz, üst düzey kullanıcılar matris yığıtı ile
oynayarak alt pencerelerin kullanımı ile ilgili bir yol
bulabilirler ama bunu, henüz calismamamizdan dolayı, sonraya
bırakacağım için beni bağışlayın.. ;)).
|