Bu sayfadaki yazılar
Sayfanın metni
Sayfa 77
Renderer::Translate /* ya da renderTranslate */ float dx, float dy, float dz
Evet, glTranslate’in on bin farklı versiyonunu da kullanmayacaksınız. Kullanacağınız tek bir versiyonu (glTranslate3f) kullanan başka bir fonksiyon yazın. Her yere glBegin, glEnd koymak yerine, üçgen, dikdörtgen çizen bir iki fonksiyon hazırlayın. Anahtar nokta şu ki; bu fonksiyonların hepsini tek bir kaynak dosyasında tanımlayın ve gl.h’ı sadece buradan ekleyin. Artık demonun bütün kaynak dosyaları için derleme bekleme derdi kalmadı.
Aslında bu sayede derleme süresini azaltmanın yanında önemli bir iş daha başarmış olduk. OpenGL’i demonun kodlarından büyük ölçüde soyutladık. İleride DirectX’e ya da software bir motora, hatta textmode motora geçmek isterseniz işinizin ne kadar kolay olacağını bir düşünün. Tüm kodları baştan yazmak yerine sadece bu fonksiyonların bulunduğu kaynak dosyası hedefiniz olacak. Kısa sürede farklı bir çizim motoruyla demo yapmaya başlayabileceksiniz. Nested’tan Caret’e geçiş aynen böyle olmuştur. Hatta tecrübeli okuyucuların fark edeceği gibi, eski motorun kodunu yeni motorda çalıştırabilirsiniz, hem de Renderer.cpp haricinde hiçbir kaynağı derlemeden!
WinAPI’yi kullanırken de benzer bir yöntem izleyebilirsiniz. En rahatı tüm kütüphaneyi çevrelemek yerine; bellekle uğraşan, disk işlemleri ile uğraşan, pencere işlemleri ile uğraşan farklı farklı subAPI’ler hazırlamak. Bu şekilde kod yönetimi kolaylaşacaktır. Tüm projenin bellek ihtiyaçlarını karşılayan tek bir ara yüz hazırlamak, sık karşılaşılan bellek sorunlarının çözülmesine de yardım edecektir (her yerde new ve delete kullanmayla kıyaslandığında).
—Hepsi
çok iyi, hepsi çok güzel anesoğlan. Ancak bu API’ler bana yetmiyor. Deli gönlüm sınıflar oluşturmak, hiyerarşiler yaratmak istiyor. Lakin sınıf tanımlarını headerlarda yapıyoruz ve sen de takdir edersin ki bunların kullandığı tipleri gizli de olsa headerı ekleyene göstermek icap eder. Var mıdır bu derde de bir dermanın ha evlat?
Private Parts are Evil!
Çok güzel bir noktaya parmak bastınız. Global fonksiyonlar için sorunumuz yok ama bir sınıfın dışarıya gözükmeyen kısımlarının tanımını bile headerda yapmak zorundayız; çünkü sınıfı parçalayıp tanımlayamıyoruz. Haliyle bu kısımların ihtiyacı olan headerlar, sınıfın kullanıcısı tarafından ihtiyaç duyulmasa da eklenmek zorunda kalıyor.
Sorunumuzu bir örnekle anlatalım. Zamanlama için bir timer sınıfı hazırlıyoruz, bu sınıfa ait objeleri bir kronometre gibi başlatacağız, durduracağız, aritmetik işlemlerde gönlümüzce kullanacağız. Ama WinAPI’ye özgü yüksek hassaslıkta zamanlayıcıları kullanmazsak da ölürüz. Mevzu yaklaşık şöyle:
class Timer { public:
Klavyeyle gezinmek için ← ve → tuşları.
Sayfa 76
Compiler Firewall Yöntemi
Bu gibi header dosyalarının işlenme sürelerinin azaltılması için zaten çok bilindik yöntemler mevcut. Bunların en temeli compiler firewall adı verilen ön derleme (preprocessing) komutları. Bunların amacı aynı kaynak kodunu derlerken bir header dosyasının birden çok kez işlenmemesi. Bunun için, ilk işleme ile bir makro tanımlayıp sadece bu makro tanımlı iken headerı işlemek bir yöntem, “#pragma once” satırı bir başka yöntem.
Ama bunlar windows.h gibi dosyalarda zaten var (bendekinde ilk yöntem kullanılıyor). Bu ancak kendi headerlarınız için kullanabileceğiniz (ve kullanmanız gereken) ve çok ufak çapta hızlandırmalar sağlayan bir yöntem. Zaten sorunumuz bu headerların tüm kaynak dosyalarınız için tekrar tekrar işlenmesi idi.
Bir kaynak dosyasının windows.h’ın yeniden işlememesinin tek bir yolu var: windows.h’ı eklememesi! Ama nasıl olur? Onu kullanarak bellek yönetimi yapıyoruz, zamanlama yapıyoruz, DirectX hatta ve hatta OpenGL kullanıyoruz. Bir çırpıda nasıl atarız? Bir çırpıda atamayacağız zaten. Bunun için DirectX, OpenGL, WinAPI gibi dev kütüphanelerin sadece kullanacağınız kısımlarını ayırıp bir bir wrap etmeniz gerekiyor.
SubAPI Yöntemi
OpenGL ile bir demo yaptığınızı ele alalım. Demonuzun her yerinde üçgenlerden oluşan objeler çiziyor, etrafta çizgiler uçuşturuyor, dikdörtgenler basarak resimler gösteriyorsunuz. Gayet iyi, gayet hoş. Lakin OpenGL, Bézier eğrileri de hesaplayabiliyor, ufak çapta görüntü işleme de yapabiliyor, isterseniz ekranda çizilen cisimlerin çetelesini de tutuyor. Çok daha kötüsü OpenGL, Windows altında windows.h’ı ekliyor!
Her kaynak dosyanızda gl.h eklemek, her kaynak dosyası için birkaç saniye beklemeniz demek. 30 kaynak dosyalı bir projede, 30 kaynak dosyanızın da kullandığı ve gl.h’ı çağıran bir headerı sürekli değiştirmenizin gerekmesi demek, yakında çıldıracaksınız demek. Bu yüzden OpenGL gibi dev bir kütüphanenin tüm proje çapında görülmemesi lazım.
Bunu engellemek için OpenGL’in kullandığımız kısımlarını projenin kalan kısmına sunan ufak çaplı bir API (application programming interface) hazırlayabilirsiniz. Bu API, örneğin C++’ta Renderer adı verilen bir namespace altındaki ya da C’de render öneki ile başlayan global fonksiyonlardan ibaret olabilir.
Renderer::DrawSprite2D /* ya da renderDrawSprite2D */ float left, float right, float top, float bottom