################################################################################
    Resource Manager
################################################################################
Autor  : Adam Sawicki
Wersja : 2.1
Data   : 7 grudnia 2006


Zasb
=====

Manager zasobw - zarzdza zasobami gry. Co to moe by zasb:

- tekstura, shader Direct3D
- efekt, czcionka D3DX
- siatka modelu
- dwik FMOD

A co nie powinno by zasobem:

- materia
- sprite
- potworek
- itp.

Zasoby nie powinny si nawzajem uywa, mie podzasobw, tworzy hierarchii ani
w aden sposb ze sob wiza. Powinny by niezalene i reprezentowa co
niskopoziomowego, co albo:

- Moe ulec utraceniu na skutek zdarze systemowych od systemu np. Direct3D
- Zajmowa duo pamici (RAM czy Video)
- Wymaga powolnego i pracochonnego pozyskiwania, np. wczytania z pliku albo
  wygenerowania proceduralnego.


Cechy
=====

Jest uoglniony wzgldem typu zasobw - definiuje interfejs (abstrakcyjn klas
bazow), z ktrej mona dziedziczy wasne rodzaje zasobw.

Jest dynamiczny - mona wczytywa definicje listy zasobw z pliku, ale mona te
tworzy i niszczy zasoby w czasie pracy programu, w dowolnym momencie.

Nie jest uoglniony wzgldem rda danych - zasoby same odpowiedzialne s za
wczytanie si, zapewne z pliku. Ooglnienie mogoby polega na wczytywaniu si
zasobu z dowolnego, podanego strumienia - moe to na przyszo, razem z VFS...


Skadnia
========

Skadnia zasobu w jzyku parsowanym przez modu Tokenizer z CommonLib:

  <typ> <nazwa> [stan] <parametr1> <parametr2> ... ;

typ (identyfikator)
  Jeden z zarejestrowanych typw zasobw
nazwa (string)
  Nazwa zasobu
stan (identifikator, opcjonalny)
  brak, LOAD, LOCK
parametry
  zalenie od typu


Predefiniowane typy zasobw
===========================

Modu res_d3d
-------------

>>> D3dTexture <<<

Tekstura Direct3D wczytywana do puli pamici MANAGED.

Skadnia:

  texture <nazwa> [stan] <nazwa-pliku> [ KeyColor = <kolor> ] [ DisableMipMapping ] ;

nazwa-pliku (string) - Nazwa pliku graficznego
kolor (uint4 lub string) - Kolor kluczowy
  uint4 - liczba np. 0xFFFFFFFF
  string - dowolny acuch konwertowalny do koloru, np. "FFFFFFFF" albo "red"

>>> D3dCubeTexture <<<

Tekstura szecienna Direct3D wczytywana do puli MANAGED.

Skadnia:

  CubeTexture <nazwa> [stan] <nazwa-pliku> [ DisableMipMapping ] ;

nazwa-pliku (string) - Nazwa pliku graficznego

>>> D3dFont <<<

Czcionka D3DX.

Skadnia:

  d3dxfont <nazwa> [stan] <nazwa-czcionki> <rozmiar> [bold] [italic] ;

nazwa-czcionki (string) - nazwa systemowej czcionki
rozmiar (int) - rozmiar
  Rozmiar jest wyraony w jednostkach wirtualnych, czcionka sama po zmianie
  rozdzielczoci tworzy si od nowa z nowym rozmiarem.
bold (identyfikator, opcjonalny) - pogrubienie
italic (identyfikator, opcjonalny) - pochylenie

>>> D3dEffect <<<

Efekt D3DX.
Plik FXO. Nie akceptuje plikw rdowych FX - trzeba samemu kompilowa.

Skadnia:

  d3dxeffect <nazwa> <nazwa-pliku> ;
  d3dxeffect <nazwa> <nazwa-pliku> params { <nazwa1> , <nazwa2> , ... } ;

nazwa-pliku (string) - nazwa pliku FXO
nazwa1, nazwa2, ... (string) - nazwy parametrw

>>> Font <<<

Wasna czcionka font managera.

Skadnia:

  font <nazwa> [stan] <plik-fnt> , <plik-tekstury> ;

plik-fnt (string) - nazwa pliku FNT
plik-tekstury (string) - nazwa pliku obrazka

>>> D3dTextureSurface <<<

Reprezentuje pojedyncz surface lub tekstur + jej surface.

Skadnia:

  TextureSurface <nazwa> [stan] <IsTexture> <Width> <Height> <Pool> <Usage> <Format>

IsTexture (identyfikator) - texture | surface
Width, Height (uint4) - szeroko, wysoko
Pool (identyfikator lub string, D3DPOOL) - pula pamici
Usage (identyfikator lub string, D3DUSAGE) - sposb uycia (np. RENDERTARGET, DEPTHSTENCIL, DYNAMIC)
Format (identyfikator lub string, D3DFORMAT) - format

>>> D3dCubeTextureSurface <<<

Reprezentuje pojedyncz tekstur szecienn i jej surfaces.

Skadnia:

  CubeTextureSurface <nazwa> [stan] <Size> <Pool> <Usage> <Format>

Size (uint4) - szeroko i wysoko
Pool (identyfikator lub string, D3DPOOL) - pula pamici
Usage (identyfikator lub string, D3DUSAGE) - sposb uycia (np. RENDERTARGET, DEPTHSTENCIL, DYNAMIC)
Format (identyfikator lub string, D3DFORMAT) - format

>>> Multishader <<<

Reprezentuje kod rdowy shadera (plik FX), ktry jest na danie kompilowany
z podanymi makrami preprocesora tworzc potrzebne shadery.

Skadnia:

  Multishader "<nazwa>" [stan]
    Source = "<plik-rdowy>"
    Cache = "<maska-plikw-tymczasowych>"
    Macros { "<nazwa>" <bit>, "<nazwa>" <bit>, ... }
    Params { "<nazwa>", "<nazwa>", ... }

Gdzie:
- plik-rdowy (string) - nazwa pliku FX
- maska-plikw-tymczasowych (string) - maska dla nazwy plikw w ktrych
  skadowane bd skompilowane shadery, np. "Shaders\Cache\MainShader_#.fxo"
  Znak '#' jest zastpowany identyfikatorem konkretnego shadera.
- nazwa (string) - nazwy kolejnych makr czy parametrw
- bit (uint) - numer bitu od ktrego zaczyna si warto danego parametru


Stan
====

Zasoby mona tworzy na wiele sposobw oraz niszczy. Mona to robi
dynamicznie, w czasie pracy programu, w dowolnym momencie.

Kady istniejcy zasb:

- posiada unikatow nazw : string
  Nazw mona przerobi na wskanik. Mona jej te bezporednio uywa.
- posiada obiekt : IResource
  Przez wskanik do niego naley zasobu uywa, eby byo szybko.
- naley do jakiej grupy, by moe domylnej
  Grupy mona uywa eby wywoywa funkcje dla caego zbioru zasobw.

Kady zasb jest w jednym ze stanw:

- UNLOADED
  Zasb istnieje, jego obiekt istnieje (bo instnieje zawsze), ale
  reprezentowany przez niego zasb nie jest wczytany. Przed uyciem trzeba go
  wczyta.
- LOADED
  Zasb jest wczytany, ale w kadej chwili (nie dokadnie w kadej, tylko midzy
  klatkami) manager moe go odadowa.
- LOCKED
  Zasb jest wczytany i zablokowany tak, e na pewno nie zostanie automatycznie
  odadowany.

Do tego warto przeczyta komentarze do metod: Load, Unload, Lock, Unlock,
a take zwrci uwag, e stan pocztkowy mona poda przy tworzeniu zasobu bd
jego definiowaniu w XNL2.

Typowe techniki uycia managera zasobw:

1. Zasoby statyczne

- Piszemy definicje tych zasobw w pliku XNL2.
  Przy kadej dopisujemy "LOCK".
- Podczas inicjalizacji aplikacji wczytujemy zasoby z tego pliku.
- Jak najwczeniej i jak najrzadziej przerabiamy nazwy tych zasobw na wskaniki
  IResource* (czy odpowiednie pochodne).
- Uywamy tych wskanikw w programie.

2. Zasoby dynamicznie adowane

- Piszemy definicje tych zasobw w pliku XNL2.
- Podczas inicjalizacji aplikacji wczytujemy zasoby z tego pliku.
- Jak najwczeniej i jak najrzadziej przerabiamy nazwy tych zasobw na wskaniki
  IResource* (czy odpowiednie pochodne).
- Uywamy tych wskanikw w programie. Przed kadym uyciem zasobu ktry taki
  obiekt reprezentuje (zwykle metoda Get) wywoujemy jego Load. To daje pewno,
  e zasb zostanie natychchmiast wczytany i w takim stanie pozostanie
  przynajmniej do koca biecej klatki. Wielokrotne wywoywanie Load w jednej
  klatce niczemu nie zaszkodzi.

3. Zasoby dynamicznie tworzone

Jak wyej, ale trzeba samemu zarzdza tworzeniem i niszczeniem zasobw. Trzeba
szczeglnie uwaa, aby nie stosowa wskanikw do zniszczonych zasobw ani
nie otrzymywa ich metodami MustGetResource*.

Inne moliwoci:

- Stosowanie grup do zarzdzania caymi grupami zasobw na raz.

- Stosowanie metody Unload do jawnego odadowywania zasobw o ktrych wiemy, e
  nie bd ju na razie potrzebne.

- Okresowe stosowanie Lock do zasobw, ktre nie chcemy eby zostay odadowane,
np. ekran "Loading".


Inne informacje
===============

- Zasb na nazw, ktra jednoznacznie go identyfikuje i jest acuchem.
adowany zasb dowiaduje si o swojej nazwie i moe j wykorzysta jako jeden
z parametrw, np. jako nazwa pliku (ale nie powinien!).

- Zasb moe mie nazw pust. Wwczas nie da si go odnale, trzeba pamita
wskanik do niego.

- Zasb ma parametry. Te zasoby statyczne s opisne w pliku za pomoc parametrw
w XNL2, a podczas dodawania dynamicznego mona je podawa te jako acuch XNL2
lub jako zwyke parametry konstruktora obiektu zasobu.

- Na podstawie nazwy zasobu (albo od razu podczas dynamicznego tworzenia) mona
uzyska jego wskanik. Ze wskanika mona dowiedzie si, czy zasb jest
wczytany lub nie jest wczytany albo e jest zablokowany.

- Dynamiczny bufor wierzchokw czy indeksw, dynamiczna tekstura, tekstura
render target itp. rzeczy nie bd zasobami, bo i tak nie uniknie si rcznego
zarzdzania nimi. Niestety. Tak wic obsuga utrata urzdzenia D3D czy
deinicjalizacja systemu dwikowego nie moe by ukryta przez resource manager,
musi siga dalej - do odpowiednio silnika graficznego czy moduu dwikowego.
EDIT: Zdecydowaem, e jednak dynamiczne zasoby D3D da si uzna za zasoby
Resource Managera i tak ich uywa, napisaem odpowiednie klasy, wic to ju
jest nieaktualne.

- Menader zasobw monitoruje ilo wolnej pamici RAM i pamici video. Daje
do tych statystyk dostp do odczytu. Na ich podstawie podejmuje te decyjzje
o wymianie. Polityka wymiany: Zasoby ktre s w stanie LOADED (nie UNLOADED i
nie LOCKED) mog zosta autoamtycznie przez manager odadowane, przy czym
pierwszestwo przy odadowywaniu maj te najdawniej nie uywane.

- Mona zasb zablokowa i odblokowa. Zablokowanie blokujco da jego
natychmiastowego wczytania. Zasb zablokowany pozostanie zawsze wczytany.
Odblokowanie umoliwi kiedytam jego usunicie. Blokowanie ma licznik - dopiero
odblokowanie tyle razy ile zosta zablokowany czyni zasb faktycznie
odblokowanym.

- Jest te funkcja informujca, eby zwolni zasb, bo nie bdzie ju potrzebny.

- Stan wczytywania (zacz wczytywa w tle, wczyta natychmiast, wczyta
natychmiast i zablokowa) mona te okreli podczas definicji zasobu w pliku.

- Czy bdzie jeden resource manager, czy osobne dla rnych typw zasobw?
DECYZJA: Bdzie jeden.

- Jak informowa resource manager o utracie i usuniciu urzdzenia D3D dla
zasobw graficznych czy usuniciu systemu dwikowego dla zasobw dwikowych?
DECYZJA: Bdzie uoglniony interfejs - metoda powiadamiajca managera, ktra
przyjmuje:
> typ komunikatu : uint4
> parametry komunikatu : void*
I wywouje to samo dla wszystkich istniejych zasobw.

- Dostpne s te z menadera zasobw statystyki - ilo zasobw oglnie i
w poszczeglnych stanach (wczytane, wczytujce si, zakolejkowane, zablokowane,
niewczytane).

- Grupowanie zasobw i wywoywanie operacji dla caej grupy.

- DECYZJA: Obiekty klas implementujcych IResource bd istniay cay czas,
kiedy zasb jest zarejestrowany w managerze (na podstawie pliku, acucha lub
jawnie wywoanego konstruktora) i tylko bd zmieniay swj stan potrafic si
wczyta i od-czyta.

- DECYZJA: Nie ma jednego centralnego pliku z definicjami zasobw - to kod
wywouje w dowolnym momencie dla managera zasobw funkcj wczytujc z podanego
pliku.


Font manager
============

Klasa res::Font to zasb reprezentujcy wasny font manager. Uywa zestawu plik
FNT + tekstura (koniecznie tylko jedna!) generowanych przez Bitmap Font
Generator autorstwa AngelCode.

Plik FNT wczytuje w momencie tworzenia. Dlatego wszystkie informacje o czcionce
i zapewniane przez ni obliczenia s dostpne zawsze kiedy zasb istnieje.
Jedynie rysowa tekst mona tylko wtedy, gdy zasb jest wczytany.

Do rysowania krele (podkrelenia, nadkrelenie, przekrelenie) i prostoktw
uytkownika uywa tekstury z wntrza znaku '-'.

Funkcje rysujce klasy Font rysuj tylko geometri (quady ze znakami). Wszelkie
stany urzdzenia D3D (efekt, kolor, nawet tekstura) trzeba ustawi samemu
na zewntrz.

Jako Flags trzeba podawa:
- Zawsze jedn z flag trybu zawijania wiersza - FLAG_WRAP_*.
- Zawsze jedn z flag dosunicia poziomego - FLAG_H*.
- Zawsze jedn z flag dosunicia pionowego - FLAG_V*.
- Opcjonalnie podkrelenie pojedyncze lub podkrelenie podwjne.
- Opcjonalnie nadkrelenie, opcjonalnie przekrelenie (lub obydwa).

Rysowanie w trybie FLAG_SINGLELINE jest szybsze ni z zawijaniem wierszy.

Klasa Font jest uywana przez Canvas do rysowania grafiki 2D.

Klasa wszystkie znaki traktuje jednakowo. Jedynie spacji nie rysuje. W miejsce
znaku ktrego nie ma na czcionce rysuje znak '?'. Nie traktuje specjalnie
tabulacji.

IMPLEMENTACJA:

Klasa uywa jednego, wspdzielonego midzy obiekty tej klasy bufora
wierzchokw i indeksw.


OcclusionQueries
================================================================================

To zasb niedefiniowalny tekstowo, do tworzenia tylko z poziomu kodu. Nie ma
wikszego sensu tworzy wiele obiektw tej klasy, aczkolwiek mona. Przechowuje
on kolekcj podanej liczby zapyta Occlusion Query i wirtualizuje je dajc
wygodny dostp do tych zapyta. Udostpnia wasne zapytania, ktre od tych
systemowych rni si:

- Mona i trzeba tworzy je od nowa i niszczy za kadym razem, w kadej klatce,
gdy s jednorazowego uytku
- Mona ich na raz stworzy i uywa (zadawa zapytania jedno za drugim, potem
oczekiwa na wyniki) dowolnie duo, bardzo duo.

Sposb uycia
-------------

// Na pocztku aplikacji stworzy obiekt klasy zasobu
res::OcclusionQueries *res = new res::OcclusionQueries(string(), string(), 30);
// Na kocu aplikacji usun go
delete res;

// Na pocztku klatki lub gdzie w klatce stworzy obiekty zapyta
res::OcclusionQueries::Query *Queries[N];
for (int i = 0; i < N; i++)
	Queries[i] = res->Create();
// Zada zapytania
for (int i = 0; i < N; i++)
{
	res::OcclusionQueries::Issue query_issue_obj(Queries[i]);
	RysujCos(); // ZEnable=true, ZWriteEnable=false, ColorWriteEnable=false
}
// Odebra i wykorzysta wyniki
for (int i = 0; i < N; i++)
	if (Queries[i]->GetResult() > 0)
		// obiekt i jest widoczny - narysuj go.
// Przed zakoczeniem tej klatki koniecznie usun obiekty zapyta
for (int i = 0; i < N; i++)
	res->Destroy(Queries[i]);

Uwagi
-----

Nie naley na raz rozpoczyna zadawania (Issue) wielu zapyta. To powinno
dziaa do progu tolerancji takiego, jaka podana zostaa ilo Occlusion Queries
jako parametr konstruktora klasy zasobu, ale przekroczenie tego limitu skoczy
si najprawdopodobniej Debug Assertion Failed. Najlepiej w ogle tego nie
prbowa.

Obiektw zapyta moe by wicej, ni wynosi pula prawdziwych Direct3D Queries.
Zapytania s wirtualizowane i w takim przypadku tworzenie nowego zapytania czeka
na zakocznie i odebranie wynikw od jednego z istniejcych.

Jedyna prawidowa sekwencja uywania obiektw zapyta klasy
res::OcclusionQueries::Query to:

1. Utworzy obiekt metod res::OcclusionQueries::Create.
2. Zada zapytanie tworzc na czas rysowania na stercie obiekt klasy
   res::OcclusionQueries::Issue i podajc do jego konstruktora obiekt zapytania.
3. Opcjonalnie odpytywa co jaki czas o wynik metod CheckResult.
4. Ostatecznie poczeka i odebra wynik (liczb narysowanych pikseli) metod
   GetResult.
5. Usun obiekt metod res::OcclusionQueries::Destroy.

Wynik mona odbiera metod CheckResult i GetResult wiele razy.

