Archive for the ‘Projects’ Category.

Shaderki

AplikacjaPostanowiłem wreszcie zająć się wyświetlaniem grafiki opartej na shaderach. Stworzyłem sobie prosty framework oparty na moim “silniku”, który jest aktualnie tylko szkieletem aplikacji. Framework składa się z kilku klas, których zadaniem jest uprościć wykonywanie różnych rzeczy. Aktualnie w zestawie jest kamerka FPP, prosty system cząsteczek oraz klasy do wczytywania modeli i zarządzania efektami.

Na dole tej notki znajduje się link do aplikacji, która reprezentuje aktualny stan kodu. Aplikacja wyświetla 4 modele wczytane z plików w formacie .x, 1 model z formatu .sdkmesh oraz cząsteczki, których pozycja obliczana jest w shaderze. Światło użyte w scenie jest punktowe, a obliczenia są wykonywane w pixel shaderze. Materiały modeli pochodzą z ich plików, dlatego nie wszystko wygląda super ;).

Kamerkę obsługuje się za pomocą myszy i klawiszy WSAD, a światło za pomocą strzałek oraz klawiszy PG_UP i PG_DN.

Pobierz

NViDo v0.3 Release

Tym razem chciałbym przedstawić mój nowy program. NViDo jest to aplikacja do pobierania filmów z serwisów takich jak Youtube. Zaletą programu jest prostota obsługi, która może sprowadzić się do skopiowania linku do schowka i wciśnięciu skrótu klawiszowego “SHIFT + ALT + D”. Innymi funkcjami aplikacji są:

  • NViDoodtworzenie filmu zaraz po ściągnięciu
  • tworzenie historii pobranych plików wideo (z której można bezpośrednio odpalić dany plik)
  • pobieranie również wersji HD jeżeli istnieje w serwisie

Aktualnie ilość serwisów, które NViDo obsługuje nie jest szałowa, ponieważ są to tylko (już wspomniany) Youtube i Vimeo (w przyszłości pewnie dodam więcej). Aplikacja jest w miarę odbugowana, jeśli wystąpią jakieś błędy to postaram się naprawić (choć nie obiecuję).

Pobierz

W tym miejscu chciałbym zareklamować również inną aplikację tego typu, a mianowicie jDownloader. Ten program, oprócz tego, że automatycznie pobiera pliki z takich serwisów jak rapidshare, potrafi ściągać filmy z większości znanych serwisów podobnych do Youtube.

jDownloader

Systemy operacyjne

Już od jakiegoś czasu zanoszę się z wrzuceniem programów, które musiałem przygotowywać na zajęcia laboratoryjne z Systemów operacyjnych. Oczywiście wiadomo że “chęci największe, gdy możliwości najmniejsze”, więc wrzucam je dopiero teraz, gdy mam dostęp do komputera. Wszystko przez firmę ASUS, która zapewniła mi odwyk od komputera dzięki długoterminowej naprawie notebooka (niech będą przeklęci! :P).

Wracając do tematu, programy które należało przygotowywać miały symulować działania algorytmów takich jak:
– planowanie dostępu do procesora
– planowanie dostępu do dysku twardego
– pamięć wirtualna

Programy te nie są zbyt wyszukane, ale spełniają założenia. Oczywiście na przekór temu, czego używamy na wydziale (Java), swoje programy pisałem w C++. Programy są “prawie” multiplatformowe. Aby ruszyły pod linuksem wystarczy zamienić kilka funkcji i nagłówków na ich odpowiedniki.

Zadanie 1
Zadanie 2
Zadanie 3
Zadanie 4

Interfejs IMesh, klasa Mesh i loadery.

Nawiązując do poprzedniej notki chcę tylko zamieścić jak wyglądają klasy, które napisałem i czemu są takie fajne:

// Interfejs
class IMesh
{
public:
	/*
	...
	*/
	// Funkcja aktualizująca mesha
	virtual void SetMesh(LPD3DXMESH mesh) = 0;
	// Funkcja dodająca materiał do wektora
	virtual void AddMaterial(const Material& mat) = 0;
	// Funkcja zwraca materiał o podanym indeksie
	virtual Material GetMaterial(Dword index) = 0;
	/*
	...
	*/
};
 
// Główna klasa Mesh
class Mesh : public IMesh
{
public:
	// Konstruktor
	Mesh();
	// Destruktor
	~Mesh();
 
public:
	/* Funkcje używane do rysowania modelu
	...
	*/
 
protected:
	/*
	...
	*/
	// Funkcja aktualizująca mesha
	virtual void SetMesh(LPD3DXMESH mesh) = 0;
	// Funkcja dodająca materiał do wektora
	virtual void AddMaterial(const Material& mat) = 0;
	// Funkcja zwraca materiał o podanym indeksie
	virtual Material GetMaterial(Dword index) = 0;
	/*
	...
	*/
};
 
// Przykład loadera
class X_file
{
public:
	// Konstruktor
	X_file(IMesh* mesh) { m_mesh = mesh; }
	// Funkcja ładująca
	RESULT LoadMesh(String filename)
	{
		LPD3DXMESH mesh;
		/*
		... cuda-niewidy...
		*/
		m_mesh->AddMesh(mesh); // Wywołanie funkcji interfejsu
	}
 
private:
	// Obiekt na którym działam
	IMesh* m_mesh;
};

Nie lubię się rozpisywać. Jak można zauważyć dzięki interfejsowi IMesh można załadować dowolny model do klasy Mesh, ponieważ są publiczne wszystkie funkcje umożliwiające to zadanie, natomiast klasa Mesh posiada publiczne funkcje służące tylko i wyłącznie do rysowania modelu. Dzięki takiemu rozwiązaniu kod jest przejrzysty.

Programowania ciąg dalszy

Minęło trochę czasu od mojej ostatniej notki, ale co poradzić, studia są trochę wymagające, więc trzeba się czasem pouczyć, zwłaszcza, że jest to styczeń czyli ostatni miesiąc przed sesją. W momencie, gdy piszę tę notkę, upływa właśnie pierwszy tydzień tej najbardziej nielubianej przez studentów pory roku :). Wracając jednak do tematyki tego devBloga należałoby powiedzieć czym ciekawym zajmowałem się przez ten czas, przecież nie samą nauką człowiek żyje.

Postanowiłem dodać do mojego silnika możliwość wczytywania różnego rodzaju plików z meshami. Na początek napisałem prostą klasę opakowującą interfejs ID3DXMesh, w której umieściłem strukturę przechowującą materiały danego mesha. Następnie napisałem funkcje automatyzujące odczyt i zapis plików w formacie .x. Schody zaczęły się, gdy chciałem dodać obsługę dodatkowego formatu – zdecydowałem, że będą to pliki .obj (Object files). OBJ są to pliki tekstowe, przechowujące informacje o całym meshu (fajna specyfikacja tego formatu znajduje się tutaj), z którymi w parze są jeszcze pliki .mtl, gdzie trzymane są informacje o materiałach dla danego subsetu (więcej info tutaj). Najważniejszą sprawą w całym tym przedsięwzięciu było napisanie parsera dla tego formatu. Na szczęście z pomocą przychodzi Microsoft DirectX SDK, w którym znajduje się przykładowy program (“MeshFromOBJ”) wczytujący pliki OBJ.

Pisząc klasy obsługujące różne modele chciałem, aby istniała możliwość konwersji między tymi formatami. Powstała więc koncepcja dwóch rodzajów klas – klasa Mesh oraz klasy obsługujące formaty. Klasy te mają być od siebie w jak największym stopniu niezależne, czyli ma istnieć możliwość dodawania funkcjonalności do klasy Mesh bez konfliktu z klasami wczytującym oraz musi istnieć możliwość pisania dodatkowych klas obsługujących różne formaty. Szczerze mówiąc, pierwszy raz zetknąłem się z takim problemem, ale na szczęście udało mi się znaleźć proste i eleganckie rozwiązanie. Mianowicie zastosowałem prosty interfejs, po którym dziedziczy klasa Mesh, z tym wyjątkiem, że klasa interfejsu posiada funkcje abstrakcyjne public, a klasa Mesh definiuje te funkcje jako protected, bądź private. Dzięki takiemu podejściu klasy korzystające z interfejsu, mogą operować na tych funkcjach, a klasa Mesh ma te funkcje ukryte :).

Małe programy

Postanowiłem udostępnić dwie pomocne aplikacje, które były mi potrzebne kiedyś, więc sobie je na szybko skodziłem w ramach treningu. Oto one:

  • FileListing – aplikacja zapisuje ponumerowaną listę plików w katalogu, w którym została uruchomiona
  • NewLineFix -aplikacja naprawia wszystkie znaki nowej linii dodając do nich \r, przydatna przy czytaniu plików pisanych pod linuksem.

Mam nadzieję, że komuś się przydadzą :).

Paczka

Właśnie opublikowałem paczkę dotychczasowej pracy. Nie jest tego dużo, ale zawsze coś. Muszę przyznać, że ostatnio pogrywam sobie w L2 więc czasu trochę mniej. Paczka zawiera prostą aplikację wykorzystującą mój menadżer scen, dzięki któremu można przełączać dowolnie między scenami. Więcej w pliku ReadMe.
NineTester

Pobierz

Ciąg dalszy kodzenia

Udało mi się napisać manager scen, na którym będę mógł oprzeć moją grę, dzięki temu sceny można przełączać (jak w grze). Ostatnio zająłem się efektami, które są w książce Programowanie gier w DirectX. Póki co mam efekt ognia i efekt wody, między którymi można się dowolnie przełączać. Postaram się zakodzić resztę i udostępnić.

Moduł 2D

Postanowiłem napisać do mojego silnika moduł 2D, gdyż od jakiegoś czasu mnie nosiło, aby napisać symulacje rzutów fizycznych (głównie ukośnego – pewnie przez to, że zbliżają się matury). Po raz pierwszy jednak udało mi się napisać własny shader, co uważam za niebywałe osiągniecie, chociaż jedyną czynnością jaką on wykonuje jest wyświetlenie tekstur. Wracając do modułu. Jest on bardzo prosty, ponieważ składa się tylko z 2 klas: ImageBox oraz Image. Klasa ImageBox jest pojemnikiem na obiekty typu Image. Jej zadaniami są:

  • Tworzenie i likwidacja obiektów Image
  • Zarządzanie wewnętrznym Vertex Bufferem
  • Zarządzanie shaderem (który służy tylko do próbkowania tekstury)
  • Likwidacja i przywracanie zasobów na czas resetowania urządzenia

Funkcja rysująca i zestaw funkcji do manipulowania obrazkami są dostępne w klasie Image, dzięki czemu można samodzielnie kontrolować czy obrazek ma zostać narysowany oraz co zostanie zmienione. Z racji tego, że przed narysowaniem czegokolwiek, konieczne jest ustawienie shadera, rysowanie odbywa się w bloku BeginPainting() (…) EndPainting(). Podobnie jest z manipulacją obiektami, gdyż trzeba zablokować VertexBuffer.

Oto prosty przykład zastosowania tego modułu w “symulacji” rzutu ukośnego.

Download – wymaga sm 1.1

Zmiany na lepsze?

Postanowiłem, że należałoby wreszcie zrobić porządek z biblioteką NLib oraz z silnikiem NIne. Niestety jak się okazało przy projektowaniu gry (myślę nad klonem Tetrisa w 3D), aktualny stan silnika nie pozwala na jego rozbudowę i pisanie w oparciu o niego jakiejkolwiek gry. Dlatego stwierdziłem, że lepszym pomysłem byłoby zaprojektować grę, a następnie do niej odpowiedni interfejs, mając na uwadze ponowne użycie kodu do tworzenia innych gier.

Na początek zająłem się biblioteką NLib. Zamierzam kompletnie uniezależnić się od wyjątków, ponieważ uważam, że są one dobre do zwykłych programów, w których występuje wiele sytuacji wyjątkowych. W grze są niepotrzebne, gdyż jeżeli nastąpi sytuacja wyjątkowa, to grę i tak należy zamknąć, a poza tym podobno obsługa wyjątków spowalnia kod. Zamiast tego błędami będzie sie zajmował Logger, do którego będą trafiać wszystkie komunikaty (nawet te najmniej ważne), dzięki temu będzie wiadomo co i kiedy poszło nie tak. Dlatego będzie wymagany do używania jakiegokolwiek modułu z biblioteki.
Ważną zmianą jest też wprowadzenie obsługi Unicode. Niestety standardowe strumienie zapisujące do plików, nie zapisują ich w tym kodowaniu, dlatego zacząłem pisać własny strumień oparty na funkcjach WinApi. Z początku będzie obsługiwał tylko Little Endian, ale myślę nad dodaniem obsługi plików zapisanych jako Big Endian i ANSI (w trybie Unicode projektu). Z tego strumienia będzie korzystał również Logger. Oczywiście Unicode będzie obsługiwany tylko wtedy, gdy w ustawieniach projektu kodowanie będzie w tym trybie. W trybie ANSI, strumień będzie zapisywał tylko w ANSI.

Uważam, że należy iść z duchem czasu, a nie pozostawać w epoce kamienia łupanego :D.