> DirectX > Direct 3D’ ye Giriş – Bölüm 1

Direct 3D’ ye Giriş – Bölüm 1

"Direct 3D’ye Giriş" isimli makale serimizde, DirectX’in üçüncü boyut ayağı olan Direct3D’nin bazı temel noktalarına değineceğiz. Direct3D nesnesinin nasıl oluşturulacağı, bunu penceremizle nasıl ilişkilendireceğimiz bu makalenin konuları arasında. Direct3D uygulamaları genelde C++’da yazıldığından, başka dillerde yazılamayacağı ya da eksik ve yavaş çalışacağına dair düşüncelere sahip olabilirsiniz. Fakat, DirectX nesneleri esasında COM nesneleri olduğundan, DirectX uygulamaları COM nesnelerine ulaşabilen herhangi bir programlama dili ile de yazılabilir. Yeterki DirectX’e ait sınıf ve fonksiyon tanımlamaları, sizin dilinizde tanımlanmış olsun. Yoksa kendiniz tek tek el ile bu tanımlamaları yapmak zorundasınız. Biz bu makalemizde kodları, C++ ve Delphi olarak vermeye çalışacağız. Hazırsanız buyrun.

İçindekiler

Başlamadan Önce

Giriş

Kendi Penceremizi Oluşturalım

Penceremizi Kayıt Ettirelim

Pencere Mesajlarının Yakalanması

Pencerenin Oluşturulması

Mesaj Döngüsü

Başlamadan Önce

DirectX ile 3 boyutlu programlamaya giriş yapanların ilk karşılaşacakları konulardan biri hiç şüphesiz Direct3D’ yi bir pencere üzerinde çizim yapmak üzere hazırlamaktır. Her nekadar 3 boyut mantığı, vektörel işlemler ve Direct3D yapısı öncelik taşısa da biz bu makalemizde bunlara değinmeyeceğiz.

Bu makaleye devam edebilmek için bir kaç şeye ihtiyacınız olacak. Bu makaleyi hazırlarken bilgisayarımda DirectX SDK December 2005 versiyonu kurulu idi. Ama daha yeni DirectX 9 SDK’sı ya da DirectX10 da işinizi göreceği kanaatindeyim. Kodlar C++ ve Delphi üzerine olacaktır. Bu sebeple bunları derleyebilecek bir derleyiciniz olmak zorunda. Ama bu makalede bunların kurulum işlemleri anlatılmayacak. Vereceğim kodlar Visual C++ 2005 ve Delphi for Win32 2006 üzerinde denemiştir. Ama eski versiyonlar ile de çalışabilirler. C++ için başlık dosyaları sdk ile birlikte geliyor. Delphi için ise internette kısa bir arama ile bir çok header(başlık) dosyasına erişebilirsiniz.

Ayrıca class ve interface yapıları hakkında bilgi sahibi olduğunuzu ve en az bir iki sınıf yazdığınızı kabul ediyorum. Bu yapılar hakkında bilgi alabilmek için, ilgili programlama dilinin help dosyalarını karıştırmanızda fayda var.

Eğer bunları elde ettik ve kurulum ve ayarlamaları doğru bir şekilde yaptı isek başlayabiliriz.

Giriş

3 boyutlu bir çizim ortamını oluşturabilmek için Direct3D’ yi nereye ve nasıl çizim yapacağı noktasında bilgilendirmemiz şart. Direct3D, çizimi yapabilmek için bir pencerenin handle numarasına ihtiyaç duyar. Her ne kadar çizim yapabilmek için Windows’u kullanmasa da, Direct3D, uygulama üzerinde açma, kapama ve diğer işlemleri yerine getirmek için Windows penceresine ihtiyaç duyar..

Bu yüzden, Direct3D nesnemizi oluşturmadan önce standart bir Windows penceresine ihtiyacımız olacak. 3 boyutlu çizim yapan uygulamarda performans önemli bir yer tuttuğundan, penceremizi kendi başımıza oluşturmamız gerekecektir. "Kendi başımıza" kelimelerinden kastımız, hazır pencere sınıf ve kütüphanelerinden faydalanamayacağımızdır. Yani ne MFC ne de VLC form’ larını kullanmadan, "native" yani tabii windows penceresi oluşturmalıyız. Hem windows mesajlarını kontrol noktasında hem de ihtiyacımız olmayacak sınıf, metod ve özelliklerden kurtulmak için bu gereklidir. Kısacası performans ve kontrol noktasındaki sorunlardan dolayı, kendi penceremizi kendimiz oluşturacağız.

O zaman, şimdi gelin bir pencereyi kendi kendimize nasıl oluşturabiliriz görelim. Eğer bu işi kalıcı bir şekilde öğrenmek isitiyorsanız, verilen örnekleri kopyala yapıştır yapmadan, kendiniz yazarak ve anlayarak yapınız.

Kendi Penceremizi Oluşturalım

İşletim sistemi ya da herhangi bir çalıştırma ortamı (.net, jre, vs..), uygulamayı çalıştırabilmek için, başlangıç fonksiyon veya sınıfına ihtiyaç duyar. Bahsi geçen penceremiz Win32 ortamında tanımlanacağı için, Windows’ un ihtiyaç duyduğu WinMain fonksiyonunu tanımlamamız gerekecek. Bu fonksiyon, uygulamamız Windows tarafından çalıştırılmaya başlatıldığı anda çağrılır. Aşağıda C++ tanımlamasını göreceğiniz bu fonksiyon, dilden dile, kişiden kişiye farklılık göstermektedir.



		

Bu fonksiyon, Win32 Platform SDK’ da tanımlanmıştır. Dediğim gibi bu yapı dilden dile farklılık gösterebilir. Mesela Object Pascal yani Delphi’de bir program begin-end. bloğunda yazıldığı için, WinMain fonksiyonunun tanımlanacağı adres bloğunda, begin-end. bloğu bulunacaktır. Yani Delphi ile program yazarken WinMain fonksiyonunu tanımlamanız bir şey ifade etmez. Çünkü WinMain fonksiyonun kendisi begin-end. bloğudur.

Å?imdi eğer VC++ kullanıyorsak boş bir proje ve boş bir cpp dosyası açalım, Delphi kullanıyorsak dpr uzantılı boş bir dosya oluşturalım. Başlangıç için aşağıdaki kodları yazalım:

C++:

		

Delphi:

		

 

Ek Bilgi

WinMain fonksiyonunun bu parametreleri kişiden kişiye farklılık gösterebilir. Windows, sadece fonksiyonun parametrelerinin veri tiplerine bakar. Yani bunun manası, sizin parametrelere vereceğiniz isimleri Windows görmeyecektir. O sadece, ilk iki parametrenin HINSTANCE ve son iki parametrenin LPSTR ve int olmasına bakar. C++ kodlarında genelde macar notasyonu kullanılmaktadır. C++ da bu notasyona bağlı kalınmaya çalışıldığından Delphi’ deki parametre isimleri ile farklılık gösterebilir. Mesela C++’da lpCmdLine olan parametre yerine Delphi’de sadece CmdLine kullanılır.

Derlediğinizde exe dosyası oluşacaktır. Ama çalıştıktan sonra hemen geri kapanacaktır. Çünkü işletim sistemi WinMain fonksiyonuna dallanma yaptığı zaman hiç bir kod olmadığından fonksiyondan geri çıkacaktır.

hInstance parametresi, uygulamamızın handle’ ını tutar. hPrevInstance (Delphi’de hPrevInst şeklinde..) parameresi ise 16-bit Windows’dan kalma bir parametredir. Win32’de daima NULL dönderir. lpCmdLine (Delphi’de CmdLine) parametresi, uygulamamızın çılıştırıldığı komut satırdır. Bu parametre ile programımıza gönderilen parametreleri öğrenebiliriz. nShowCmd (D: CmdShow) ise pencerenin ne şekilde görünceğini belirleyen parametredir. Mesela minimize yapılmış şekilde göstermek gibi…

Penceremizi Kayıt Ettirelim

WinMain fonksiyonumuzu tanımladıktan sonra, sırada oluşturacağımız ana pencerenin sınıfını Windows’a kayıt ettirmek var. Bunun için Win32 SDK belgelerine baktığımızda RegisterClassEx fonksiyonunun kullanıldığını göreceğiz. Bu fonksiyon WNDCLASSEX tipinde bir yapı(struct) almaktadır. Aşağıda örnek bir sınıfın kayıt işlemi görülmektedir:

C++:

		

Delphi:

		

Ek Bilgi – C++ Kullanıcıları İçin…

ClassName alanında "L" komutunu kullandığımıza dikkat ediniz. Eğer VS 2003 kullanıyor olsaydınız, bunu kullanmak zorunda kalmayacaktınız. VS 2005 ile beraber tüm api komutları default olarak ismi W ile biten unicode fonksiyonlarına yönlenmektedir. Bu yüzden verdiğimiz bu string değerinin unicode olduğunu belirtmek için başında L kullandık. Aynı şekilde tchar.h dosyasını include ederek _T makrosunu da kullanabilirsiniz.

Burada bulunan parametreler, Windows pencere yapısını anlayabilmek için gerçekten önemlidir. Karmaşık gibi dursa da bir kaç defa kendiniz baştan yazdığınızda alışacaksınız. Üstelik ileride yapacağınız bir sınıf tanımlaması sayesinde bu kodları bir daha yazmak zorunda kalmayacaksınız. Ama şimdilik sıkılmadan yola devam edelim. Çünkü bu yapı temel konulardandır. Å?imdi bu parametreleri açıklamaya çalışalım.

İlk olarak gördüğümüz ZeroMemory fonksiyonu, WNDCLASSEX yapımız için hafızadan yer ayırıyor. Bunun için bir adet yapımızın işaretçisi ve yapımızın veri tipi olan WNDCLASSEX yapısının büyüklüğünü parametre olarak giriyoruz. İkinci parametrenin anlamı, struct’a ait tüm alanlar için yer ayrıldığı anlamına gelmektedir. Aksi halde Windows bu oluşturduğumuz yapının (struct, record) boyutundan doğru bir şekilde haberdar olamayacaktır. Aynı şekilde yapımızın cbSize alanına da bu değeri girmeliyiz. Burada dikkat etmemiz gereken şey, bu yapının tüm alanlarınıa bir değer atanması gerekmesidir. Aksi halde register sorunları yaşayabilirsiniz.

Diğer alanlarda bilmeniz gerekenlerden birisi de hInstance alanıdır. Bu alana, WinMain’ den gelen handle parametresini geçiriyoruz. lpssClassName alanı ise, ileride oluşturacağımız pencere için önem arz ediyor. Çünkü penceremizi bu sınıf ismi altında oluşturacağız. style ise, pencerenin hangi durumlarda kendini yenileyeceğini belirtiyor. Biz burada hem yatay hem de dikey yöndeki pencerenin boyut değişimlerinde, pencere içeriğinin yeniden çizilmesini istemişiz. Background ve Cursor alanlarına girmiyorum. Buradaki en önemli alan ise lpfnWndProc alanıdır. Bu alana WindowProc cinsinden bir fonskiyon girmeliyiz. Böylelikle uygulamamıza gelecek bütün mesajlar bu fonksiyonumuza gelecektir. Bir WndProc fonksiyonu, windows mesajlarının işlendiği bölümdür. Buraya kadar isterseniz bir kahve molası verin ve burayı bir daha okuyup tekrar edin. Hazır olduğunuzda ikinci sayfadan devam edelim.

Sayfalar: 1 2

» Tags: , , , , ,

4 Comments

  • At 2007.11.07 00:41, furkan bulut said:

    makeleniz yayımlanalı neredeyse bir sene olmuş. Yeni gördüm. Büyük bi kayıp benim için. Gerek anlatılış tarzı olsun gerek bilgilerin işe yararlılığı oldukça takdire şayan.
    Devamını bekliyorum.

    • At 2007.11.07 01:36, Fatih Tolga Ata said:

      Aslında bu makale belki o tarihten 6-7 ay önce yazılmıştır. Çünkü sitemizi bir ara yenilemiştik. Devam noktasına gelince, ben directX ile zamanında üniversite tezi hariç genelde hobi olarak uğraştım. Bu yüzden bu konuda her zaman makale yazamayabiliyorum. Yorumunuz için teşekkürler.

      • At 2008.01.07 20:09, Volkan SAÄž said:

        TEşekkürler
        beNİM aradığım öğrenmek istediğim birşeydi

        • At 2008.03.29 04:14, Mesut KAYMAK said:

          Merhalar ,

          bende yeni gördüm bu yazıyı. Daha doğrusu yeni Directx ile alakadar olmaya başladım. uzun senelerdir delphi ve vb dillerinde program geliştiridim fakat bu directx konusunda ilk defa dalıyorum ve benim içşn bu makale gerçekten çok aydınlatıcı oldu çok teşşekkürler güzel açlışmalarınızın devamını bekliyorum.

          (Required)
          (Required, will not be published)