uEngine4 Serüveni – BasicGLPainter – I

Evet sevgili dostlar daha önce bahsettiğim OpenGL tabanlı Painter sınıfının eksikliklerini tamamlayıp, elini yüzünü düzelterek sizlere sunmaktan büyük mutluluk duyuyorum. Bu yazımda sizlerle, SDLPainter ile aynı mantığı içeren fakat tamamen OpenGL API’sini kullanan BasicGLPainter kütüphanesini paylaşıyor olacağım. Aslında aşağıdaki yazımda bunlara az çok değinmiştim, bu yazımda, ilave eklenen kabiliyetlere ve OpenGL’e değiniyor olacağım.
Bir de yazımı iki bölüme ayırdım açıkçası, bu sayede hem bilgi yüklemesinin daha dengeli olmasını hem de çok uzun bir yazı olmasının önüne geçmeyi umut ediyorum.

Bu yazıma ilişkin hazırladığım örnek uygulamanın, kaynak kodlarına ise aşağıdaki adresten ulaşabilirsiniz:

https://github.com/yazilimperver/uEngine4/tree/main/code/src/apps/gl_example

Şimdi gelelim BasicGLPainter sınıfımıza. Her ne kadar, SDLPainter ile API imzalarını benzer tutmaya çalışsam da, aralarında farklılıklar var. Bunlara ilerleyen bölümlerde değiniyor olacağız. OpenGL detaylarına çok girmeyeceğim, fakat yine de OpenGL ile ilgili dikkat edilmesi gereken konulara olabildiğince değineceğim. Yine de merak ettiğiniz konuları lütfen yorumlar kısmında sormaktan çekinmeyin. 
Arkada pencere sistemi olarak yine SDL2 kullanıyor olacağız (SDLApplication üzerinden), bu sebeple, bu anlamda çok büyük bir farklılık yok.
OpenGL sürümü olarak OpenGL 3.2 ayarlıyor olacağım. Shader’ları kullanmayacağım çünkü painter için şu an çok gerekli değil (ileride duruma göre buna da eğilebiliriz). Amacım, bu sınıfı olabildiğince yalın tutarken, 2B bir oyun, harita ve benzeri CBS tabanlı çizimler için gerekli kabiliyetleri sunacak seviyeye getirmek ki, şu an öyle ve bu Painter sınıfını da CBS raster/vektör katman gösterimleri için kullanıyor olacağız.
Bir önceki yazıdaki GL Painter’a ilave olarak yapılanları aşağıdaki sekmelerde özetlemeye çalıştım:
  • Doku çizim kabiliyeti eklendi,
  • Metin çizim kabiliyeti eklendi,
  • “Stroke” çizimine yönelik güncellemeler,
  • OpenGL çağrılarına ilişkin güncellemeler,
  • API isimlendirmeleri ortaklandı.
Bu arada BasicGLPainter sınfının kabiliyetlerini daha iyi gösterebilmek adına örnek bir uygulamayı da ekledim, gl_example”. Örnek uygulama aslında bir önceki yazımda SDL için hazırladığım örneğe çok benzeyen bir örnek hazırladım (eksiği çok yok ama fazlası var 😉 

SDL2 OpenGL Ayarları

Öncelikle SDL2’yi OpenGL ile kullanmak için neler yaptığıma ufak bir değineceğim. uEngine’nin temel amacı bu tarz detaylar ile sizin boğuşmamanız ama perde arkasında neler olduğunu da kısaca göstermenin faydalı olacağınız düşündüm. Eğer amacınız ekran üzerinde hızlıca bir şeyler görmek ise bu başlığı atlayabilirsiniz.
SDL ile ilgili ayarlamaları, bool SdlApplication::InitializeSDL() API’si içerisinde bulunan InitializeWindows() ve InitializeOpenGL() aracılığı ile yapıyoruz. Bu ayarlamaların her ne kadar bir çoğu varsayılan değer içerse de, bunları bir JSON konfigürasyon dosyasından da yapabiliyorsunuz.
Gelelim InitializeWindows() API’si içerisinde neler yapıyoruz:
  • Öncelikli olarak OpenGL sürüm bilgilerini çeşitli API’ler ile SDL’e geçiriyoruz. Bu geçirdiğiniz parametrelere göre kullanabildiğiniz OpenGL API’leri değişiklik göstermekte, bu sebeple bu ayarlar önemli,
  • Buffer boyutlandırmalarını yapıyoruz (Ör. Stencil buffer vermezseniz/ayarlamazsanız, buna ilişkin kabiliyette sıkıntı yaşarsınız),
  • Son olarak, OpenGL özellikleri ile pencereyi oluşturuyoruz.
InitializeOpenGL() içerisinde de aslında temelde OpenGL extension’larını kullanabilmek için glew kütüphanesini ilklendiriyoruz ve mevcut bilgisayarın desteklediği son OpenGL sürümünü görüntüleyebiliyorsunuz. Aşağıda, SDLApplication uygulamasının benim bilgisayarımda bu anlamda verdiği çıktıyı görebilirsiniz:

Aslına bakarsınız SDL içerisinde yapılan temel ayarlar bu şekilde. Şimdi biraz daha işlevsel API’lere değinelim.

Doku Çizimi

Doku çizimi aslında oyun ve benzeri için en sık kullanacağınız kabiliyetlerden birisidir. Bu vesile ile resimleri ekranda gösterebiliyoruz. GLPainter ile bunu yapabilmek için öncelikle bu resim (daha yaygın terminoloji ile doku “texture”) dosyalarını GPU’ya aktarmamız gerekiyor. Bunun için uEngine, bir çok formatı (.png, .jpg, .vb) destekleyen resim yükleme kabiliyetini sizlere varsayılan olarak sunuyor.  İlave formatlar için ilgili sınıfları yazıp dahil etmeniz gerekmekte.
Bunun arkasında yatan mekanizmaya değinmeden önce, resim göstermek için izlemeniz gereken adımlardan bahsediyor olacağım. 
İlk olarak “STBLoader”’ı kullanıyor olacağız. Öncelikle ilgili doku yükleyiciyi “Asset” servisinden sorguluyoruz ve sonra bununla dokuyu yükleyeceğiz.

Bu kod parçasına ilişkin ilave söylenebilecekler; ASSET_ROOT_PATH’i, resim ve benzeri dosyaların dizinini CMake aracılığı ile kod içerisine aktarıyoruz. Bu amaçla da CMake aracılığı ile configuration.h, configuration.h.in dosyaları ve aşağıdaki betikler ile CMake çalıştırıldığında ilgili yol sabit bir std::string’e geçirilmekte. Aşağıda CMake betiklerini de bulabilirsiniz:


mTextureHandle (std::optional<AssetHandle>) başarılı bir şekilde yüklendikten sonra sıra bunun gösterilmesine geldi. Bunun için yapmanız gereken çağrıları ise aşağıda veriyorum:


Öncelikle yüklediğimiz resmi AssetService’ten çekiyoruz (bunu başta da yapabilirsiniz ya da kendi uygulamanızda özelleştirebilirsiniz).

Sonrasında daha önceki paylaştığım yazıda verdiğim fırçayı da kullanıyoruz, bunu da resmi renklendirmek için yapıyoruz. Resmin kendi renklerin kullanmak için beyaz fırça kullanabilirsiniz. 
Son olarak da, DrawTexture’ı kullanarak ilgili Asset ve çizilecek konuma ilişkin bilgileri kullanıyoruz (merkez, genişlik/yükseklik).
OpenGL için kullanılan dokunun tutulmasından sorumlu sınıflara, “gl/gl_texture” projesi altından ulaşabilirsiniz. Burada da en önemli sınıf TextureAsset, bu sınıf, yüklediğimiz dokulara (farklı yükleyiciler olsa da) ilişkin OpenGL işlevlerini uygulamamıza olanak sağlıyor ve Asset sınıfımızdan türüyor. Zaten, OpenGL için SDL’den farklı sınıfları/asset’leri kullanıyor olsak da mekanizma ve yönetici sınıflar aynı (AssetLoader, Asset, AssetService), meraklı okuyucularım, “infra/asset” projesini inceleyebilir. İnşallah ayrı bir yazıda, bu mekanizmadan da bahsederim.
Sizler de, farklı yükleyiciler ve resimler ile bu kabiliyeti denemeyi unutmayın.

Metin Çizimi

Şimdi gelelim metin çizimine. OpenGL ile bir miktar haşır neşir olanlar, metin çizimlerinin her OpenGL geliştiricisi için farklı bir deneyim olduğunu ve büyük bir kısmı için de, özellikle başlangıçta, zorlayıcı bir deneyim olduğunu ifade ederler (bknz. https://www.reddit.com/r/opengl/comments/qhijjb/i_hate_font_rendering/ 🙂 ) . Burada amacım sizleri bu külfetten kurtarmak. SDLPainter için metin çizimine yönelik bir tık daha fazla imkan olsa da, OpenGL tarafında da oldukça güçlü ve çeşitli yöntem mevcut. Ben, Painter sınıfım için FreeType kütüphanesi kullanılmasına dayanan yöntemi seçtim. Bunun dışında, bir diğer temel yöntem de bitmap fontlar. Belki ileride bunu da sınıfımıza katarız. FreeType kütüphanesine, bunun nasıl kullanıldığını, vb detaylara burada girmiyorum, keza girsem çıkamayabilirim (talebe göre ayrı bir yazı kaleme alabilirim). O nedenle, bu konuda oldukça doyurucu ve güzel olan iki kaynağı, kaynaklar kısmına ekliyorum. Fakat meraklı takipçilerim için bakacakları sınıflar, gl_painter projesi altındaki, gl_font, gl_texture, gl_sprite_sheet ve tabi ki freetype2 projesi.

Şu an için OpenGL tabanlı metin çizim kabiliyetlerinde, SDL’de olduğu gibi italik/kalın çizim ya da sütun çizimi gibi kabiliyetler mevcut değil :(, elbette ileride olabilir 😉 Sadece, boyutlandırma ve renklendirme mevcut (yakında hizalamayı da katıyor olacağız).

Gelelim metin çizimi için izlemeniz gereken yönteme. Öncelikle, SDLPainter’da olduğu gibi kullanacağımız fontları kaydetmemiz gerekiyor. Örnek uygulamada bunu aşağıdaki satırlar ile yapıyoruz.

Burada ilgili fonta verdiğimiz etiket ve dosya dizininden (ASSET_ROOT_PATH’e yukarıda değindim) yükleyerek, ilgili boyut için hazırlıyoruz. SetActiveFont() ile de ilgili aktif fontu atıyoruz. Bu API’lerin dönüş değeri ilgili işlevin başarılı olup olmadığını dönüyor, isterseniz kontrol edebilirsiniz.

Peki çizim için ne yapıyoruz? İlgili kalem nesnesini atayarak, SimpleText() API’si ile çizimi gerçekleştirebiliyoruz.

Evet sevgili yazılımperver dostlarım, bu yazım için yeterince kabiliyet işledik. Bir sonraki yazımda, kalan bir takım kabiliyetlere (stencil,  vb.) değiniyor olacağım. Tabi, bu yazıyı bir ekran görüntüsü vermeden kapatmayacağım 🙂 Aşağıda, yazılımın windows platformu için çalıştırıldığında görülen ekran görüntüsünü görebilirsiniz. Bir sonraki yazımda görüşmek dileğiyle.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.