Anasayfa Eğitseller Oyun Yapımı DirectX Eğitselleri Bölüm 5 - Ortak Kod Oluşturma - Fps Hesaplama - Kayıp Aygıt

DirectX Eğitselleri Bölüm 5 - Ortak Kod Oluşturma - Fps Hesaplama - Kayıp Aygıt PDF Yazdır e-Posta
Kullanıcı Değerlendirmesi: / 0
ZayıfEn iyi 
Eğitseller - Oyun Yapımı
Salı, 19 Ağustos 2008 00:06

Daha önce yazdığımız pencere açma ve directx başlatma kodlarını bir sınıfa gömerek bundan sonra tekrar tekrar yazmak yerine bu sınıfı kullanacağız. Öncekilerden farklı olarak burada:

-Directx başlatımı biraz detaylandırılacak

-Saniyede görüntülenen kare sayısı(fps) hesaplanacak

-Lost device olayından ve kurtulma yönteminden bahsedilecek

#include "Ortak.h"
#include "Aygit.h"

Aygit* aygit;

void oyun_dongusu()
{
//esc çıkış
if(GetAsyncKeyState(VK_ESCAPE))aygit->end();
}

int WINAPI WinMain(HINSTANCE hinstance, //program göstericisi
HINSTANCE prevInstance, //kullanılmıyor
PSTR cmdLine, //komut satırı argümanı (char*)
int showCmd) //pencere durumu
{
aygit = new Aygit(hinstance,"BosPencere",false,800,600);
aygit->dongu(oyun_dongusu); return 0;
}

Gördüğünüz gibi bir aygit sınıfı nesnesi oluşturuyoruz. Parametreler sırasıyla program göstericisi, pencere başlığı, tam ekran değeri, genişlik ve yükseklik değerleri. Nesneyi oluşturduktan sonra program döngüsünü oluşturan metodu belirterek bitiriyoruz. Böylece daha derli toplu bir kodumuz oldu ve bu sınıfı tekrar tekrar kullanabiliriz. şimdi ortak.h dosyasının içine bir bakalım.

#pragma once
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment (lib,"winmm.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

//güvenli silme makroları
#define SAFE_RELEASE(x)if( x ) { (x)->Release(); (x) = NULL; }
#define SAFE_DELETE(x)if( x ) { delete(x); (x) = NULL; }
#define SAFE_DELETE_ARRAY(x)if( x ) { delete[] (x); (x) = NULL; }

Öncekilerden farklı olarak burada winmm.lib kütüphanesini bağladık, onuda timeGetTime isimli metodu kullanmak amacıyla ekledik, ne olduğuna daha sonra değineceğiz. Şimdi aygıt sınıfına en baştan göz atalım.

Aygit::Aygit(HINSTANCE instance,char* caption,bool fullscreen,int width,int height)
{
....

Bu sınıfın yapıcı metodu daha önce yaptığımız gibi bir pencere oluşturarak başlıyor. Kod neredeyse birebir olduğu için sadece farklı yerlere değineceğiz.

//pencereyi ortala
int startx,starty;
int window_width = GetSystemMetrics(SM_CXSCREEN);
int window_height = GetSystemMetrics(SM_CYSCREEN);

if (window_width>width && window_height>height)
{
startx = (window_width-width)/2;
starty = (window_height-height)/2;
}
else
{
startx = 0;
starty = 0;
}

Daha önc pencereyi 0,0 konumudan başlatıyorduk, aşağıdaki kodda pencere boyutu ekran boyutundan küçük ise pencereyi ortalayacak başlangıç konumlarını hesaplıyoruz.

Daha önce directx parametrelerinin çoğuna değinmemiştik, şimdi bunlardan bahsedelim:

d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = !fullscreen;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

d3dpp.BackBufferWidth : Tam ekran için arka tamponun(bkz. back buffer) genişliği, pencere bazlı uygulamalarda bu değer pencerenin genişliğine eşittir.

d3dpp.BackBufferHeight : Tam ekran için arka tamponun(bkz. back buffer) yüksekliği, pencere bazlı uygulamalarda bu değer pencerenin yüksekliğine eşittir.

d3dpp.BackBufferFormat : Tam ekran için arka tamponun piksel formatı, pencere bazlı uygulamalar için bu değer o anki formattır.

d3dpp.BackBufferCount : Arka tampon sayısı. 1 iken double buffering, 2 iken triple.....

d3dpp.MultiSampleType : Bkz. antialiasing.

d3dpp.MultiSampleQuality : Bkz. antialiasing.

d3dpp.SwapEffect : Tamponlar arası geçiş efekti. En etkini D3DSWAPEFFECT_DISCARD'dir.

d3dpp.hDeviceWindow : Hedef pencere.

d3dpp.Windowed : Penceremi tam ekran mı...

d3dpp.EnableAutoDepthStencil : True ise directx depth/stencil bufferları kendi yönetir.

d3dpp.AutoDepthStencilFormat : Depth/stencil buffer formatı. Örneğin 24bit depth+8bit stencil => D3DFMT_D24S8, verilen formatın donanım tarafından destekleniyor olması lazım.

d3dpp.Flags :Ekstra ayarlar. Bkz. D3DPRESENTFLAG

d3dpp.FullScreen_RefreshRateInHz : Tam ekran tazeleme hızı.

d3dpp.PresentationInterval : Tamponlar arası geçişte bekleme durumu. Bkz. vsync.

//HARDWARE_VERTEXPROCESSING kontrolü
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
int vp = 0;
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
{
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
}
else
{
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}

Burada donanımsal transformasyon&ışıklandırmanın desteklenip desteklenmediğin kontrol edip, aygıtı yaratırken ona uygun parametreyi veriyoruz. Bkz. T&L. Direct3d'nin başlatılmasında daha detaylı işlemlerde yapılabilinir. Sistemde bulunan aygıtların listelenmesi, istenen piksel vb. formatlarına uygunluk gibi özelliklerin kontrol edilmesi aslında önemlidir. Örnek bir kod parçası için bkz. Aygıt Bilgisi kodu.

Şimdi program döngüsünü inceleyelim.

void Aygit::dongu( void (*ptr_dongu)() )
{
MSG msg;
while(loop)
{
if(PeekMessage(&msg,0,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
...........

device->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0x00000000,1.0f,0);
device->BeginScene();

ptr_dongu();

device->EndScene();
device->Present(0, 0, 0, 0);

...........

Görüldüğü üzere program loop isimli sınıf değişkeni true olduğu sürece dönüyor. Mesaj işlenişi aynı şekilde ve dongu metoduna parametre olarak verilen metod Begin&End Scene metod çağrıları arasında çalıştırılıyor. Clear metodunda öncekiden farklı olarak z-buffer'ıda temizliyoruz. Bkz. z-buffer

if(PeekMessage(&msg,0,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//zaman
currTime = timeGetTime();
deltaTime = currTime - lastTime;

..........

//zaman & fps
lastTime = currTime;
totalFrames++;
totalTime += deltaTime;
if (totalTime>1000)
{
fps = totalFrames;
totalFrames = 0;
totalTime -= 1000;

.........

timeGetTime metodu 1 milisaniye çözünürlük ile bize şu anki zamanı veriyor. Burada çizim işleminden önce ve sonra aldığımız değerleri kullanarak iki çizim arasında geçen zamanı hesaplayabiliyoruz. Ayrıca toplam zamanıda kontrol ederek bir saniyede kaç kere çizim yapıldığınıda kolayca buluyoruz.

Son olarak lost device olayından bahsedelim. Bazen aygıt kaynaklarını yitirir ve resetlenene kadar tekrar çizim yapamaz. Bunun en tipik örneği tam ekran modunda iken Alt+Tab yaparak pencere odağını kaybetmektir. Bunu engellemek için aygıtın durumu sürekli kontrol edilmeli ve gerektiğinde resetlenerek işine devam etmesi sağlanmalıdır.

//lost device
HRESULT hr = device->TestCooperativeLevel();
if (!SUCCEEDED(hr))
{
if(hr == D3DERR_DEVICELOST)
{
Sleep(50);
//free_things
}

if(hr == D3DERR_DEVICENOTRESET)
{
hr = device->Reset(&d3dpp);
if (SUCCEEDED(hr))
{
//redo_things
}
}
}

TestCooperativeLevel metodu bize aygıtın durumunu bildirir. Bu metod başarısız olduğunda aygıt kaybedilmiş demektir. Bu durumda kısa bir süre beklenerek aygıt resetlenmeye çalışılır. Aygıt resetlenebilir konuma geldiğinde aygıtı yaratırken doldurduğumuz parametreler ile resetler ve tekrar çalışır hale getiririz. Bu işleme ek olarak D3DPOOL_DEFAULT sabiti ile oluşturlmuş tüm kaynaklar reset işleminde silinip tekrar yüklenmelidir. Bu konuda daha detaylı bilgiyi directx sdk dökümanında bulabilirsiniz.

Kaynak Kodu İndir



-------- EKSTRALAR --------

Ekran Kartı Bilgisi Kodu:

http://directx.oyungelistirici.net/dx/onbilgi.rar

Kavramlar:
 
http://www.oyungelistirici.net/index.php/egitseller/14-oyunyapimi/233-kavramlar

DirectX Kaynakları:

http://www.chadvernon.com/blog/tutorials/
http://www.directxtutorial.com/
http://www.zanir.szm.sk/index.html
http://www.pieterg.com/
http://www.32bits.co.uk/
http://triplebuffer.devmaster.net/tutorials/archive/
http://www.two-kings.de/
http://www.mvps.org/directx/indexes/index.htm
http://www.drunkenhyena.com/cgi-bin/directx.pl

DirectX Kitapları:

http://www.amazon.com/ adresinde DirectX'i aratmanız yeterli.

-------- ÖNEMLİ --------

-Bu sitedeki dökümanlar Türkçe kaynak eksikliği yüzünden hazırlanmış ve ihtiyaç duyanların serbest kullanımına sunulmuştur.

-Sunulan kodlar ve bilgilerin doğruluk ve etkinlikleri konusunda bir garanti verilmemekle beraber her türlü talep ve düzeltmelerinizi mail yada ilgili forum başlığı yoluyla iletebilirsiniz

-Dökümanlarda daha çok genel kavramlara değinilmiş olup detaylı bilgi edinmek için directx dökümanını ve çeşitli kaynakları (özellikle kitap) okumanız tavsiye edilir. Farklı kaynakların bağlantılarını bu dökümanın sonunda bulabilirsiniz.

-Bu eğitsellerden verim alabilmek için orta düzeyde c++ bilgisi yeterlidir. Onun dışında winAPI hakkında bilgi sahibi olmak directx'i kavramakta size yardımcı olacaktır. Ayrıca eğitseller ardışık bağlantılı olduğu için bu işte yeni iseniz sırayla gitmeniz tavsiye edilir.

-Örnek kodlar Virusl Studio 2003 projeleridir, vs2005 ile de kullanılabilir.

-Kavramları Türkçeleştirmek için çok çaba sarfedilmemiştir, çoğu yerde İngilizce isimler kullanılmıştır. Merak ettikleriniz için kavram sözlüğüne bakabilirsiniz.

-İndireceğiniz yazılımlardan dolayı PC'nizin ya da bünyenizin zarar görmesi durumunda sorumluluk kabul etmeyiz, geçmiş olsuna gelebiliriz :)

-Yazılanların hakkı saklı değildir, sağda solda ben yaptım diye dağıtabilirsiniz :)
 
Yunus KARA
Son Güncelleme ( Salı, 19 Ağustos 2008 01:22 )
  Yorum yok.
Yorum ekle. (0 yorum)

 

OyunGelistirici.net - Türk Oyun Yapımcılarının Buluşma Noktası

Bu sitede yazılan tüm yazıların hakları yazarlarına aittir. İzin alınmadan yayınlanamaz.

Bu sitede Firefox kullanmanız önerilir. En az 1024 x 768 masaüstü çözünürlüğü tavsiye edilir.