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