SERİ DEMO ÜRETİMİ 1 – DEMO MOTORLARI

Bir coder olarak ilk demonuzu yapmak istediniz. Müzik ve grafikleri hazırlayacak birilerini buldunuz. Onlar uğraşırken siz OpenGL, Direct3D her neyse öğrendiniz. Sonra gelen materyallere göre bir tasarım belirlendi ve bunu hayata geçirmeye başladınız. Partları kodladınız. Beğenmediniz, baştan kodladınız. Gündüz vakti devam edesiniz gelmedi, parti tarihini hatırlayıp geceleri kodladınız. Demonuz, yola çıkma vaktinden ancak birkaç saat önce istediğiniz kıvama ulaştı.

Demonuzu partiye götürdünüz ve herkese izlettiniz. Daha dün kimse sizi duymamıştı, bugün herkes o demoyu kimin yaptığını merak ediyordu.

Bir sonraki partinin tarihini öğrenince “Bir kez daha mı?” diye sordunuz kendinize. İlk demonuzu yaparken ne kadar zaman alacağını kestirememiştiniz. Artık hem nelerden vazgeçmeniz gerektiğini biliyor hem de daha yoğun bir hayat yaşıyordunuz. Mümkün değil baştan benzer bir kod hazırlayamazdınız. Belki ileride devam ederdiniz…

7DX ve Nightshift’e ilgi çekici bir demoyla katılıp daha sonra bir daha adına rastlamadığımız coderların yaşadıkları ve düşündükleri az çok bunlar diye tahmin ediyorum. Bir demoyu yapmak bile o kadar çaba isterken, yabancı gruplar bir senede nasıl üç dört demo birden çıkarıyorlar? İşin içinde uzun zamandır olsalar bile, bir demoyu baştan sonra tekrar yazmaları gerçekten çok zamanlarını alacaktır.

Bu kısıtlama coderın yeteneklerini de aşıp, fiziksel bir sınır haline gelebilir. Yani gece gündüz hatasız çalışsanız bile, o kalitede ürünler o kadar kısa zamanda sıfırdan nasıl hazırlanır? Bu yazıda bunun cevabını arayacağız.

Her şeyden önce ufak bir not: Yazıda önereceğim yöntemlerin hepsini kullanmadım ama tamamı uygulama planımın içinde. O yüzden benzer fikirler ya da eleştirileriniz olursa paylaşmanız benim açımdan da faydalı olacaktır. Belki de birkaç sene sonra “bu yöntemler nerede işe yaradı nerede yaramadı” ekseninde bir başka yazı yazarım.

SERİ ÜRETİM

Seri üretim (ya da rapid production) benzer projelerin ortak yönlerini kullanarak bunları daha kısa sürelerde bitirme işidir. Amacımız hazırlayacağımız demoların aldıkları zamanı giderek düşürmek ve elde ettiğimiz bu ek zamanı kendimizi geliştirmek için kullanmak olacağı için, seri üretimin demolarda nasıl uygulanabileceğini bilmek istiyoruz.

İlk demomuz için altı ay uğraşmış olabiliriz, bu her demoya aynı süreyi adayacağımız anlamına gelmez. En azından bir altı ay daha uğraşırsak, yeni demomuzun ilkini fersah fersah aşmış olması gerekir. Ya da aynı kalitede bir başka demoyu bir ay içinde bir diğer partiye yetiştirebilmeliyiz.

Aslında bahsedeceğim şey tecrübeli olanlarınızın bildiği gibi yeniden kullanım (reuse). Tabii ki bunun, ilk demonun kodunda bir iki parametreyi değiştirip ikinci bir demo yapmayla alakası olmayacak. Asıl hedefimiz, sıfırdan bir sistem tasarlayıp, her demoda bu sistemi bir adım ileri götürmek.

Giderek kalitesi artan ve üretim zamanı düşen demolar elde etmek istiyorsak, kullanabileceğimiz iki farklı bakış açısı var.

Önceki demolardan hangi kodu kullanıp bu adımı aşabilirim.

Bu adımı nasıl çözersem sonraki demolarıma yardımcı olur.

Plan yapmanın her zaman ileriye yönelik olduğunu düşünürsek, ilk yöntemin sakat olduğunu fark edebiliriz. Bu yüzden izlememiz gereken yöntem ikincisi.

DEMO MOTORU

Öncelikle hedefimizi bir tek demo bitirme işinden biraz öteye koyuyoruz. Sayesinde farklı farklı demolar yapabileceğimiz bir altyapı hazırlamalıyız. Demo üretimini sıfırdan kodlanan projeler yerine, hazır rutinlerin birleştirilmesi işine çevirmemiz gerekiyor. İşte bu rutinleri topladığımız sisteme demo motoru adını vereceğiz.

Demo motoruna, bir demonun üretimi esnasında anahtar işleri yapmamızı sağlayacak bir kütüphane gözüyle bakabiliriz. Bu kütüphaneyi büyük ihtimalle sadece kendimiz kullanacağımız için tasarımını gönlümüzce yapmakta özgürüz. Ama yine de göz önünde bulundurmamız gereken bazı şeyler var.

Öncelikle yapacağımız şey olan demoları tanımlayalım. Amacımız gerçek zamanlı olarak çalışacak, görüntünün algoritmik olarak üretileceği bir animasyon hazırlamak ve bu animasyonun üstüne bir müzik eklemek. Müzik, standart bir demoda gerçek zamanlı hesaplanmayacağı için en az dert etmemiz gereken kısım. Dolayısıyla motorumuzun asıl amacı, çizimleri yapmamıza ve görüntüleri oluşturmamıza yardımcı olmak.

Motorumuzu bu çıkarımlar çerçevesinde üçe ayıracağız:

Çizim için kullanılacak belleğin (framebuffer) oluşturulması ve yönetilmesi.

Animasyonun akış kontrolü (timeline).

Çizim işlemlerini kolaylaştıracak bir alt kütüphane (renderer).

Bu kısımları işinin hakkıyla halleden ve görevleri ile ilgili geriye iş bırakmayan kodlar hazırladığımızda motorumuz bitmiş olacak. Bu kodları daha sonra sadece motoru geliştirmek için elleyeceğiz. Demolar ise sırtlarını demo motoruna yasladıkları için sorun çıkarmadan üretilebilecekler.

Framebuffer

Framebuffer ekranda çizilecek piksellerle temasa geçebileceğimiz son yer. Bu belleğin tanımlanması, oluşturulması ve yönetilmesini çalıştığımız platforma göre işletim sistemine bırakabilir ya da elimizle kontrol edebiliriz. İlkini yaptığımızı varsaysak bile, örneğin Windows altında bir OpenGL framebuffer'ı oluşturuyor olsak bile, yazmamız gereken satırlarca kod vardır.

Eğer deneysel takılmak gibi bir amacımız yoksa, yazacağımız her demoda aynı tipte (32bit renk, 16bit derinlik vs.) bir bellek kullanacağız. Haliyle, bu kodu her seferinde baştan yazmamız anlamsız. Bir pencere oluşturup onu bir framebuffer'a bağlayan bir fonksiyon yazmak ve bu fonksiyonu her demonun başında çağırmak iş yükünü hafifletecektir. İşin alt düzey kısmıyla ilgili yapılacak her işi aşağıdaki örnekteki gibi birkaç fonksiyona indirgersek ömrümüzden birkaç yıl kazanabiliriz.

// Demonun başında.

Framebuffer::Create(640, 480, BufferType::DoubleBuffer) ;

// Her frame sonunda.

Framebuffer::Swap() ;

Timeline

Demonuzda tüm zamanlama işlerini her frame'de bir artırdığınız bir tamsayı üzerinden yapabilirsiniz. İstediğiniz hızı elde edip başka bir bilgisayarda yaptığınız şeyi denediğinizde, elde edeceğiniz şey sadece hüsran olacaktır.

Eğer donanımı kesin kurallarla tanımlanmış bir platformda çalışmıyorsak, frame'lerin farklı konfigürasyonlarda farklı süreler alacağını bilmemiz gerek. Dahası tek konfigürasyonda bile tüm demo boyunca sabit bir frame hızı hayalleri kurmayalım.

Yapmamız gereken, tüm zamanlama işlerini sabit bir saat kaynağına göre senkronlamak ve elle tuttuğumuz sayaçlardan medet ummamak. Bunun için, bu sayıdaki derleme yazısında bulunan Timer gibi bir sınıfı kullanabiliriz.

Geriye sadece belli iki süre aralığında belli partları çalıştıran fonksiyonları çağırmak kalıyor. Bunun için her frame başında, demo başında başlattığımız sayacımıza bakıp hangi partları çizmemiz gerektiğini anlamalıyız. En basit yöntem tabii ki şöyle bir şey:

if(sure >= 5.0f && sure <= 12.0f) GirisParti() ;

if(sure >= 11.2f && sure <= 16.6f) Gecis1() ;

Aslında bu yöntem gayet de işe yarıyor ama işleri biraz daha kolaylaştırabiliriz. Tüm partların fonksiyon adreslerini, partların başlangıç ve bitiş süreleriyle birlikte bir listede tutup, bu listeyi bir fonksiyona sayacın o anki değeriyle yollayabiliriz. Bu fonksiyonun amacı sayaca bakıp hangi partların çalışması gerektiğini anlamak ve ilgili fonksiyonları çağırmak olacak.

Bazı partların zaman aralığını negatif sayılara çekip, örneğin -1 zamanıyla bunların çalışmasını sağlayabiliriz. Bunu, loading'te yapmanız gerekenleri yaptıracak bir kısayol olarak da düşünebilirsiniz. Tabii ki birçok if satırı yazmak yerine işleri daha da kolaylaştıracak her türlü yöntem makbuldür.

Ayrıca her partın kendi başlangıç sürelerine göre hangi konumda bulunduklarını bilmeleri iyi olabilir. Bunu, part fonksiyonlarını bu süreyi alacak şekilde tanımlayıp, çağrıldıkları zaman “demo süresi – part başlangıcı”nı bu fonksiyona yollayabilirsiniz. Bu sayede göstereceğiniz her türlü animasyonun zamanlamasının fps bağımsız olmasını garantileyebilirsiniz.

Motorun timeline kısmının hazırlanması belki de en karmaşık işimiz olacak. Kavramları oturtmak için Flash gibi animasyon hazırlama programlarının timeline kavramlarını inceleyebiliriz. Hazırlayacağımız sistem bunlardan çok farklı olmayacak.

Renderer

İnanılmaz OpenGL, Direct3D vs. biliyoruz. Bu kütüphaneleri kullanarak süper efektler hazırlıyoruz. Pek güzel, pek hoş. Tamamen farklı bir demoda, bambaşka bir efekt için yeniden dokuya çizim yapmamız gerekti. Yani ekrana değil direk ekran kartının bellek alanlarında bir yere çizeceğiz. Ne yapıyoruz peki? Eski koddan alıp aynen kopyala yapıştır. Sonra uymayan değişken isimlerini düzeltelim. Denedik, çalışmadı. Farklı bir doku tipi kullanmışız, farklı bir çizim modundayız. Neleri değiştirmemiz lazım? Hmm, tamam oldu gibi. O da nesi? Farklı çözünürlük olduğu için tüm oranlama hesapları yanlış!

OpenGL, Direct3D gibi kütüphaneler ekran kartının en temel özelliklerini kullanmanızı sağlayan son derece “alt düzey” kütüphanelerdir. glBegin(GL_TRIANGLES)’larla, d3dDevice->SetTransform(D3DTS_WORLD, &matrix)’lerle demo yazmaya çalışmanın, kanımca tamamen assembly kullanmaktan çok farkı yoktur.

Bir obje çevirme işi için Direct3D’de üç fonksiyon, Ekrana bir sprite çizmek için OpenGL’de ondan fazla fonksiyon çağırmak abesliktir. Bu kütüphaneler zaten kendilerini olduk olmadık yerlerde çağırmayacağınız düşüncesi ile tasarlanmışlardır. Size sunduğu fonksiyonların amacı kendi grafik kütüphanenizin yapı taşlarını oluşturmaktır.

Dolayısıyla bu alt düzey kütüphaneleri daha verimli kullanmanızı sağlayacak, onları “wrap” edecek bir üst düzey sistem tasarlamalısınız. Bu sistem de en basit şekilde birçok global fonksiyondan oluşan basit bir kütüphane olacak.

Bu kütüphanenin ana işlevi, demolarınızı yazarken sık kullanacağınız çizim işlemlerini size tek fonksiyonla sağlamak olacak. Bunun yanı sıra doku, obje gibi sık kullanacağınız tipleri tanımlamak da yararlı olacaktır.

DrawSprite(logo, logoCercevesi) ;

Rotate(5.0f * time, 0.0f, 1.0f, 0.0f) ;

RenderState state = Renderer::Texture | Renderer::DepthTest ;

DrawMesh(kup, state) ;

Motorun bu kısmı, “grafik programlama” yapacağınız belki de yegane yer olacak. Çizim kütüphanelerinin size sunduğu imkanların dışına çıkmamak için hiçbir sebebiniz olmayacak. Kendi renk sınıflarınızı oluşturabilir, bunların kendi aralarında ilginç birleşme kurallarını belirleyebilirsiniz. Mesh manipülasyonundan başlayıp dokular üzerinde görüntü işleme gibi ufuklara yelken açabilirsiniz.

Demo Motoru Üzerine Son Sözler

Eğer bu üç ana kısmı hakkıyla bitirip yanına ek kütüphanelerle müzik çalmayı da eklerseniz ortalamanın epey üzerinde bir demo sistemine sahip olacaksınız. Bu sistemi kullanarak yaptığınız demolar, sıfırdan kodlanan demolardan çok daha az zaman alacaktır. Dahası işin teknik ayrıntıları yerine direk demoya odaklanacağınız için ortaya çıkacak ürünler de daha kaliteli olacaklardır.

Demo motoru bir kez yazıp ölene kadar kullanacağınız bir sistem değildir. Daha doğrusu, hiçbir sistemin tüm zamanlara uygun olma gibi bir özelliği olamaz. Siz kendinizi geliştirdikçe motorunuzu da geliştirecek; daha hızlı, daha esnek ve daha güçlü hale getireceksiniz. Özellikle renderer diye bahsettiğimiz kısım üzerinde belki demolar kadar vakit harcamanız gerekebilir. Siz tam kıvamında bir çizim kütüphanesi yazsanız bile, teknoloji sizden hızlı gideceği için bu kısmı yenileme ihtiyacı duyacaksınız. Ama tecrübelerim ile söyleyebilirim ki; yeni bir demoda, hem motora hem demoya ayıracağınız toplam süre, ilk demonuz için harcadığınız süreyle kıyaslanamayacak kadar kısa olacak.

Demoscene’de coder olmayan (müzisyen, artist vb.) arkadaşlarda bazen şöyle bir önyargıya rastlıyorum. Farklı iki üründe aynı kodu kullanmayı hoş karşılamıyorlar. Bu sanırım code reuse ve effect recycling kavramlarının karıştırılmasından kaynaklanıyor.

Effect recycling, yani bir efekti ısıtıp ısıtıp izleyenlere sunma, PC de içinde olmak üzere her türlü platformda görülebilecek bir olay. Bunu bir partı iki farklı demoda kullanmak olarak da görebiliriz.

Code reuse, yazılan kodun benzer amaçlar için tekrar tekrar kullanımı ise, demo motoru yazmanın ta kendisidir. Bu iş kesinlikle önceki projelerden kod kopyalayıp yapıştırmak değildir. Aksine kopyala yapıştırmaktan kaçınmak için yeniden kullanabilir, tüm sistemler tasarlama sorunudur. Yazılım gibi mühendislik alanlarında yeniden kullanılabilirlik, bir üründe hedeflenen özelliklerden biri; yeniden kullanılabilir ürün tasarlayabilmek ise bir mühendislik yeteneği olarak kabul edilir.

Karşılaştığınız bir problemin çözümünü, benzer tüm problemlerde işe yarayabilecek şekilde geliştirmek çoğu zaman kolay değildir. Yeniden kullanılabilirlik her ne kadar seri üretim için şart olsa da, ürün boyu ve verimliliğini olumsuz yönde etkileyen bir etmendir. Bir demo sistemi tasarlamak bile, terazinin dengesini kararlı noktada tutabilme yeteneğini oldukça geliştirecektir.

Yeniden kullanılabilir kod yazabilmek bir coder'ın elde etmesi gereken vasıflardan biri olsa da, demo sistemini koddan bağımsız hale getirmek de mümkündür. Lakin bunlardan bir sonraki sayıda bahsedeceğiz. Seri Demo Üretimi 2 – Demomaker'larda görüşmek üzere, esen kalın efendim.