Giriş
Tasarımsal nedenlerden dolayı OpenGL özelliklerinde pencere
bağımlılığından kaçınılmıştır. Böylelikle oluşan arayüz taşınabilir,
veriyollarıyla bezenmiş bir 2 ve 3 boyutlu görüntüleştirme
kitaplığı niteliğindedir. Pencere açma ve görüntüleştirme yerel
pencere sistemine kalmış bir konudur. OpenGL kitaplığı, yerel sistemle,
yardımcı kitaplıklar aracılığıyla iletişimde bulunur. Sözgelimi,
GLX yardımcı kitaplığı OpenGL ile X pencere sistemi arasında iletişim
sağlar.
OpenGL elaygıt takımı (GLUT: OpenGL Utility Toolkit), pencere
sisteminden bağımsız OpenGL programları yazmak için ANSI C ve
FORTRAN bağlantılarûndan oluşur. Bu yazılım Mark J. Kilgard tarafından
yazılmış olup OpenGL tanımlamalarında açık kalmış olan büyük bir
boşluğu örtmektedir. Erek ortamdan (target platform) bağımsız
olarak ortak bir pencere sistemi kullanımına olanak sağladığı için
GLUT geliştiricilerine şükran borcumuz bulunmaktadır.
GLUT göresel olarak küçük ve öğrenmesi kolay bir yapıdır. Tasarımı
iyi olup yazarı tarafından çok güzel bir bilgi dağarcığı da hazırlanmış
bulunmaktadır. Bu nedenle, burada, Linux
Focus'ta bir yazı serisine başlamak pek de anlamlı
gözükmeyebilir. Ciddi program geliştirmek isteyenlere Mark'ın bilgi
dağarcığını okumalarını salık veririz. Burada, bu GLUT sütununu
yazmaktaki amacımız GLUT kitaplığını ve onun kullanımını,
örneklerle adım adım ve bu derginin OpenGL serisine yandaş bir
okuma kaynağı olarak sunmaktır. Bu yaklaşımın yararlı bir katkı
sağlayacağını ve daha çok sayıda program yapımcısını OpenGL-Linux
vagonuna binmeye iteceğini ummaktayız. Yine de, Mark'ın bilgi
dağarcığını iyi bir kaynak olarak edinmenizde yarar bulunmaktadır. 
GLUT API, OpenGL gibi, bir durum motorudur. Bunun anlamı, GLUT'un
uygulamanın çalıştırılması sürecinde etkin olan durum değişkenlerine
sahip olduğudur. GLUT motorunun başlangıç durumları bir çok uygulamaya
uyabilecek biçimde seçilmiştir. Program, uygun gördükçe, durum değişken
değerlerini değiştirebilir. Herhangi bir GLUT fonksiyonunun uyarılması
durumunda, fonksiyonun etkimesi o andaki durum değişkenlerinin
değerlerine göre ayarlanır. GLUT fonksiyonları kolay yapıda olup
yalnızca bir kaç parametre alırlar. Fonksiyonlardan genellikle
gösterici (pointer) döndürülmez ve fonksiyonlara gönderilen göstericiler
ise yalnızca katar ve geçirgen olmayan fontlar için olanlarla kısıtlanmışlardır.
GLUT fonksiyonları, işlevselliklerine göre, bir kaç alt API'ye
sınıflandırılabilirler:
-
Başlatım
-
Başlangıç Olay İşlemesi
-
Pencere İşletimi
-
Örtükatman (overlay) İşletimi
-
Mönü İşletimi
-
Geriçağırış Kayıdı
-
Renk İndeksi, Renk Haritası İşletimi
-
Duruma Geridönüş
-
Font Görüntüleştirimi
-
Geometric Biçim Görüntüleştirimi
Bu yazıda, basit bir OpenGL programını başlatmak için gerekli olan
başlatım, pencere işletimi, olay işleme fonksiyonlarından bazılarını
inceleyip anlamaya çalışacağız.
Başlatımlar
GLUT kullanan tüm OPenGL programları GLUT durum motorunu
başlatacak biçimde başlamalıdırlar. GLUT başlatım fonksiyonları
glutInit- önekine sahip olmalıdırlar. Ana başlatım yordamı
glutInit'dir:
Kullanım:
glutInit(int **argcp, char
**argv);
argcp
anaprogramdan, programın düzeltilmemiş argc değişkenine bir
göstericidir.Döndürüldüğünde argcp tarafından gösterilmekte olan
argcp değeri güncellenir. Bunun nedeni, glutInit fonksiyonunun,
GLUT kitaplığı ile ilgili olan güdümsatırı seçeneklerini çekip
çıkarmasıdır. Sözgelimi, X pencere sistemi ortamında, X pencere
sistemiyle ilgili seçeneklerden GLUT'la bağlantılı olanların
algılanması gibi.
argv
program'ın, anaprogram için, düzeltilmemiş argv değişkenidir.
glutInit GLUT durum değişkenlerinin başlatımını ve pencere
sistemi ile bir oturum için iletişimin sağlanmasını üstlenir.
glutInit'ten önce başlatılan bir kaç yordam varolup bunlar
glutInit- önekine sahiptirler. Bu yordamlar benimsenen
pencere başlatım durumunu ayarlamakta kullanılırlar.
Sözgelimi:
Kullanım:
glutInitWindowPosition(int x,
int **y);
glutInitWindowSize(int width,
int **height);
x,y =
piksel türünden pencerenin ekrandaki konumu (sol üst köşe)
width,height
piksel türünden pencere en ve boyu.
Tüm OPenGL uygulamasında kaçınılmaz olarak bulunan başka bir
başlatım yordamı, (glutInitDisplayMode()) daha bulunmaktadır:
Kullanım:
glutInitDisplayMode(unsigned int mode);
mode
güsterim modu olup GLUT güsterim modu bit maskelerinin bit türü bir OR'lamasıdır.
Olabilir bit maske değerleri aşağıda verilmektedir
GLUT_RGBA |
Bir RGBA mode pencere seçer. Bu, ne GLUT_RGBA
ne de GLUT_INDEX belirtilmedikçe, benimsenen değer olarak kalır. |
GLUT_RGB |
GLUT_RGBA ile aynı. |
GLUT_INDEX |
Renk indeks pencere modunu seçer. GLUT_RGBA'ya
baskındır. |
GLUT_SINGLE |
Tek bir tamponlu pencere seçer. Bu benimsenen yapıdır. |
GLUT_DOUBLE |
Çift tamponlanmış bir pencere seçer. GLUT_SINGLE'a
baskındır. |
GLUT_ACCUM |
Depolama tamponlu bir pencere seçer. |
GLUT_ALPHA |
Renk tamponuna(larına) alfa bileşenli bir pencere
seçer. |
GLUT_DEPTH |
Derinlik tamponlu bir pencere seçer. |
GLUT_STENCIL |
Örüntü yedekleme tamponlu bir pencere seçer. |
GLUT_MULTISAMPLE |
Multismapling destekli bir pencere seçer. |
GLUT_STEREO |
Bir stereo pencere seçer. |
GLUT_LUMINANCE |
"luminance" renk modelli bir stereo pencere seçer. |
Eğer bu özelliklerin bazılarına yabancı iseniz dert etmeyin, şimdi ya da
sonra, bunlardan sözedeceğiz. Şimdi bir kaç örnek üzerinde duralım.
Önce, tek darbe görüntüleme uygulaması için basit bir başlatım: 
#include <GL/glut.h>
void main(int argcp, char **argv){
/* Set window size and location */
glutInitWindowSize(640, 480);
glutInitWindowPosition(0, 0);
/* Select type of Display mode:
Single buffer & RGBA color */
glutInitDisplayMode(GLUT_RGBA | GLUT_SINGLE);
/* Initialize GLUT state */
glutInit(&argcp, argv);
.....more code
};
İkinci olarak bir canlandırım programı:
#include <GL/glut.h>
void main(int argcp, char **argv){
/* Set window size and location */
glutInitWindowSize(640, 480);
glutInitWindowPosition(0, 0);
/* Select type of Display mode:
Double buffer & RGBA color */
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
/* Initialize GLUT state */
glutInit(&argcp, argv);
.....more code
};
Bu iki örneğe, GLUT hakkında daha çok şey öğrendikçe geri döneceğiz. Bu
ikisi arasındaki ana ayrılık, ikinci örnekte gösterimin bir çift tampon
modunda başlatımıdır. Bu durum canlandırımlar için idealdir, çünkü bu yapı
canlandırım sürecindeki kırpışmaları ortadan kaldırır.
Olay İşleme
Yukarıda sözedildiği gibi, GLUT bir durum motorudur. Şimdi de onun
olay geliştiren bir motor olarak da tasarlandığını öğreneceğiz. Bunun
anlamı, bir sayaç'ın ya da sürekli bir döngünün uygun başlatımlar sonrasında
devreye girıdiğidir. Bunlar, GLUT'a belirtimi yapılan tüm olay ve süreçlerin
başlatılmasını sağlarlar. Olaylar şunlardır: tıklatılan bir fare, kapatılan
bir pencere, bir pencerenin yeniden biçimlendirilmesi, imleç hareketi,
basılan klavye tuşları, ve daha da ilginci, hiçbirşeyin olmadığı boş olay.
Olası olayların her biri GLUT sayaç ya da olay geliştirme döngüsünün
değişkenlerinden birine kaydedilmelidir. Böylece, bu olayların tetiklenip
tetiklenmediği sürekli denetlenebilir duruma gelmiş olur.
Sözgelimi, "fareyi tıklat"ı bir olay olarak GLUT'a kaydedip
gözlemleyebiliriz. Olaylar geriçağırış kayıt yordamlarıyla
kaydedilirler. Tümünde yazımkuralı glut[someEvent]Func
biçimindedir. Fare tıklama durumunda bu glutMouseFunc
biçiminde olacaktır. Bir geriçağırış kaydı GLUT motoruna hangi
kullanıcı tanımlı fonksiyonun olayın tetiklenmesi durumunda
çağırılacağını söyler. Dolayısıyla, farenin sol (ya da sağ,..)
tuşu tıklatıldığında ne yapılacağını tanımlayan MyMouse adlı
kendi yordamımı yazacak olursam o zaman geriçağırış fonksiyonumu main()
içinde glutInit() sonrasında "glutMouseFunc(MyMouse);"
deyimini kullanarak kaydedebilirim.
GLUT içinde hangi geriçağırma fonksiyonlarına ve olaylara olanak
sağlandığını daha sonraya bırakalım. Bu anda önemli olan nokta
uygulamamızdaki tüm önemli olaylar kaydedildikten sonra GLUT'un olay
işleme yordamı olan glutMainLoop()'un uyarılmasıdır. Bu fonksiyonun
geri dönüşü yoktur, programımız temelde sonsuz bir döngüye girer. Bu döngü
gerekli olan önceden kayıtlı geriçağırma fonksiyonları çağırır. Tüm
OpenGL uygulamalı main() fonksiyonları, bu nedenle, bir
glutMainLoop() deyimi ile sona ermelidir. Dolayısıyla, bizim canlandırım
şablonumuzda:
#include <GL/glut.h>
void main(int argcp, char **argv){
/* Initialize GLUT state */
glutInit(&argcp, argv);
glutInitWindowSize(640, 480);
glutInitWindowPosition(0, 0);
/* Open a window */
glutCreateWindow("My OpenGL Application");
/* Select type of Display mode:
Double buffer & RGBA color */
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
/* Register Callback Functions */
.....
/* Start Event Processing Engine */
glutMainLoop();
};
Görüldüğü gibi, uygulamaya önceden sözü edilmeyen fazladan kod
eklemiş bulunmaktayım. Bu, glutCreateWindow(char **name),
GLUT'un pencere işletim yordamlarından biridir. Bu, işte, OpenGL & GLUT
tasarım felsefesinin en çok hoşuma giden bir yanıdır. Yalnızca adına
bakarak yordamın ne yaptığı hakkında bilgi edinmek mümkündür!. Ayrıca,
tabandaki pencere sistemine OpenGL uygulamamız için pencere açtırma
güdümünü de gönderebilmektedir. Açılacak pencere bir katar ile
aktarılan ada sahip olacaktır. X pencere sisteminde bu ad pencerenin
sol üst köşesine yazılacaktır. GLUT'un pencere işletim bölümü
inceleyeceğimiz daha bir çok fonksiyon barındırmaktadır. Bu an için
burada verilen yeterlidir. Öte yandan, burada başlatım yordamlarını
onların glutInit()'den sonra da yerleştirilebileceğini
göstermek üzere yeniden düzenlemiş bulunmaktayım.
Olaylara dönelim... Şimdi, tüm canlandırım programları için
çok temel olan iki geri çağırma kayıt fonksiyonundan sözetmek
istiyorum. Bunlar gösterim fonksiyonunu varolan pencere için
düzenleyen glutDisplayFunc ve boş geriçağırma'ları
düzenleyen glutIdleFunc fonksiyonlarıdır. Her iki
kayıt fonksiyonu da void *(void) türü birer fonksiyondurlar.
Diyelim ki canlandırım şablonumuz için iki tane ek geriçağırma
fonksiyonu yazıyoruz. Bunlar, görüntümüzü pencere üzerine çizen
OpenGL yönermelerini devreye sokan void MyDisplay(void)
ve kullanıcıdan herhangi bir veri girişi olmadığında çağrılan,
yani GLUT'un olay işleme makinası sonsuz döngüde (glutMainLoop())
ilerlerken tetiklenmiş bir olay bulamadığında devreye sokulan,
void MyIdle(void) fonksiyonları olarak düşünülebilirler.
Bir canlandırım programında neden bir Boş geriçağırma fonksiyonu
kaydına gereksinim duyuyorum dersiniz? Yanıt şöyledir: Çünkü,
canlandırım süresince gösterilen, görüntülerin (çerçevelerin) her
birini, kullanıcıdan gelecek verilerden bağımsız olarak düzeltmek
istersem OpenGL programının çalıştırılması süresince sık sık
çağrılarak çerçeveleri MyDisplay() çizilmelerinden önce
değiştirebilen bir fonksiyon (boş geriçağırma) fonksiyonu varolmalıdır.
Canlandırım Örneği
Sonuçta, işte, canlandırım için basit bir şablon:
#include <GL/glut.h>
void MyIdle(void){
/* Some code to modify the variables defining next frame */
....
};
void MyDisplay(void){
/* Some OpenGL code that draws a frame */
....
/* After drawing the frame we swap the buffers */
glutSwapBuffers();
};
void main(int argcp, char **argv){
/* Initialize GLUT state */
glutInit(&argcp, argv);
glutInitWindowSize(640, 480);
glutInitWindowPosition(0, 0);
/* Open a window */
glutCreateWindow("My OpenGL Application");
/* Select type of Display mode:
Double buffer & RGBA color */
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
/* Register Callback Functions */
glutDisplayFunc(MyDisplay)
glutIdleFunc(MyIdle)
/* Start Event Processing Engine */
glutMainLoop();
};
Gördüğınüz gibi MyDisplay sonuna yeni bir GLUT yordamı,
glutSwapBuffers(), eklemiş bulunmaktayım. Bu, canlandırımlarda
çok yararlıdır. Burada, bir gösterilen diğeri gizlenen, çift tampon
modunda pencere kullanıyoruz. Bu durumda OpenGL yönermelerinin
görüntülenmesi daima gizli tampon içine yapılır. glutSwapBuffers,
çağrıldığında, tamponları değiştokuş ederek çizileni pencere içinde
görüntüler. Bu teknik, bilgisayar canlandırımlarında, çerçeve içeriğinin
satır satır oluşturumunu insan gözünden saklaması nedeniyle, genellikle
yeğlenir.
Artık, OpenGL uygulamalarını yazmaya başlamak için yeterince malzeme
elimizde bulunmaktadır. Eksik olan tek şey MyDisplay()
içindeki, gerçekte çizimi gerçekleştiren, OpenGL yönermeleridir...
ama bu da başka bir öyküdür.;-). 
GLUT programlama üzerine olan gelecek yazıda, GLUT'un Pencere İşletimi
bölümünde bize sağlanan işlevsellik üzerinde daha derinlemesine duracak
ve aynı pencerede çok sayıda görüntü oluşturumu üzerinde duracağız.
Ayrıca, taşınabilirliklerini vurgulayarak pro'lar ve con'ları da
içererek, mönülerin kullanımını da göreceğiz
|