piątek, 7 sierpnia 2009

Resource Manager


Witam, witam, witam jestem Higgold, wielki, znany w calym Faerunie rezyser. Jestem po prostu maniakiem BG2 i Fallouta. Nigdy nie przeszlem BG2 do konca i musze skonczyc ta gre bo mi nie da zyc tak jak Cywilizacja4.

Dobra mial byc manager obiektów, mamy widze maly poslizg, ale w koncu to nadrobimy. Musze o tym napisac bo ciagle zapominam dlaczego to tak wlasnie dziala. Art jest streszczeniem rozdzialu „The Beauty of Weak References and Null Objects” z perelek chyba 5-tych. Perelki lubie za takie wlasnie rozdzialy o programowaniu ogólnym, o rozwiazaniach programistycznych, których was nie naucza na studiach, pierdole studia, to byla kupa.

Po pierwsze manager obiektów to kontener wskazników do obiektów, który trzyma obiekty, udostepnia je po unikalnym kluczu(String , IDek, Guid) i zarzadza nimi, dzieki czemu mamy w jednym miejscu kod obslugujacy obiekty(tworzenie, uaktualnianie, zwalnianie etc..) no i nasze obiekty.

Moze wystepowac w róznych rolach:
- Manager pluginów – musi wtedy byc przygotowany na obsluge typów obiektów, które nie sa mu znane w momencie kompilacji. W perelkach to jest kolejny rozdzial, moze sie kiedys o tym napisze.

- Manager obiektów bazy danych – czyli w momencie startu aplikacji(serwera, ten manager siedzi na serwerze i posredniczy miedzy klientem a baza) laduje wszystkie obiekty z bazy tworzac odpowiadajace im interfejsy i dba o ich uaktualnianie, tworzenie nowych obiektów, usuwanie istniejacych. Dzieki temu klient proszac o
interfejs do obiektu dostaje aktualny z managera, bez potrzeby ladowania z bazy co by bylo czasochlonne(utwórz polaczenie, wykonaj query etc).

- Prosty manager po stronie klienta. Po prostu chcemy trzymac wszystkie obiekty np. gry w kontenerku, który bedac singletonem umozliwia nam dostep do obiektu z dowolnego miejsca w kodzie po kluczu np.: nazwie. Obiekty mozemy np.; zdefiniowac sobie w XML-ku lub jakims skrypcie. Nawiasem mówiac wszystkie managery to singletony.

- Manager zasobów – o i oto nam sie rozchodzi, po to jest ten art. A wiec czy nie móglby to byc ten manager poprzedni, czyli bezposrednio pointery do obiektów zasobów? Jest problem, te pointery moga przestac byc aktualne i wtedy w kodzie mamy odwolanie do Null-a lub do nieaktualnego adresu alc. Leo why? Jesli mamy doczynienia z obiektami graficznymi i nastapi uniewaznienie kontekstu graficznego(Hdc), lub bedziemy manipulowac oknem renderingu(directx), lub stracimy polaczenie sieciowe, z baza etc to nasze obiekty przestaja sie nadawac do czegokolwiek i trzeba je utworzyc od nowa dla nowego kontekstu etc.

Sa dwa rozwiazania problemu:
1) Trzymamy idki do obiektów i za kazdym razem odwolujemy sie do managera zeby dał nam aktualny obiekt przez idka, uchwyt. To jest dobre acz nienaturalne podejscie, i troche kosztuje nas szukanie w mapie obiektu( kilka tysiecy obiektów na klatke, jakis algorytm n kwadrat i jest problem). Ale na domowe programowanie zupelnie wystarcza.

2) Trzymamy obiekt opakowujacy pointer do zasobu(smart pointer) nazwijmy go ResPtr, który trzyma obiekt przechowujacy wskaznik PtrHolder, który to opakowuje nasz wskaznik, który sie moze zmieniac do woli. Kontener managera przechowuje obiekty PtrHolder, a te z kolei opakowane sa przez ResPtr(smart pointer). Po co nam jeszcze ten ResPtr, nie moglibysmy uzywac bezposrednio PtrHoldera? Otóz chcemy uniknac sytuacji, w której uzytkownik zrobi jakas glupia rzecz z bezposrednim wpisem w mapie, bedzie próbowal usunac przez delete itd., oczywiscie mozemy sie chronic robiac protected i frienda do managera w klasie PtrHolder. Otóz manager potrzebuje tylko prostej logiki opakowujacej pointer, natomiast klient potrzebuje czegos wiecej,
klasa ResPtr posiada przeciazone operatory ->, *, pozwala na wymienianie PtrHoldera trzymanego w mapie na inny w czytelny sposób, bezpieczny sposób. Mozemy tez potrzebowac specjalizowac szablon ResPtr-a dla konkretnych typów. Jak widac tej logiki troche jest.

Na poczatek pierwsze rozwiazanie, czyli dostajemy obiekty przez idki.



//prosty manager trzymajacy obiekty w mapie
template <class T>
class DLLEXPORT BasicManager
{
protected:
std::map<std::string, long> mapNameToID;
std::map<long, T*> mapObject;
public:

//wrzuc do mapy i zwróc id
long AddObject(std::string _name, T* _object);
void Remove(std::string _name);
long GetID(std::string _name);
T* GetObject(std::string _name);
T* GetObject(long _id);
void RestoreAll(){};
void Clear();
};



Oczywiscie wszystkie managery stoja na szablonach, aczkolwiek moglibysmy uniknac tego trzymajac pointery do wspólnej klasy bazowej, potem trzeba by rzutowac na wlasciwy typ, mozna by dodac tylko jedna funkcje szablonowa T* GetObject(long id) i byloby ok. Nie ma tutaj o czym pisac, wyszukiwanie po long jest duuuzo szybsze niz po String, ale czasami w inicjalizacji wygodniej uzyc stringa, natomiast w reszcie kodu uzywamy longa.

Rozwiazanie drugie:
Na poczatek PtrHolder, czyli proste opakowanie wskaznika. Ale zesmy nafrendowali, po prostu nie chcemy zeby user zrobil z ta klasa cokolwiek, to jest klasa dla managera.



template <class T>
class DLLEXPORT PtrHolder
{
template <class T>
friend class BaseManager;
template <class T>
friend class FileManager;
template <class T>
friend class ResPtr;
protected:
T* pointer;
~PtrHolder(){RemovePointer();}
void RemovePointer()
{
if(pointer)
delete pointer;
pointer = NULL;
}
PtrHolder(T* _ptr) {pointer = _ptr; }

T* GetPointer(){return pointer; }
};



Teraz nasz smart pointer ResPtr uzywany przez klientów. Dzieki przeciazonym operatorom mozemy uzywac tego obiektu tak samo jak wskaznika.



template <class ResType>
class DLLEXPORT ResPtr
{
protected:
PtrHolder<ResType>* ptr;
public:
ResPtr(){ptr = NULL; }
ResPtr(PtrHolder<ResType>* _ptr) { ptr = _ptr; }

ResType* operator->(){return ptr ? ptr->GetPointer() : 0; }

ResType& operator*(){return *(ptr->GetPointer());}

void SetPtr(PtrHolder<ResType>* _ptr) {ptr = _ptr;}

ResType* GetPtr(){ return ptr ? ptr->GetPointer() : 0; }
};



Przyszedl czas na managery. Zrobilem bazowa.



//bazowy manager, trzeba wyprowadzac klasy pochodne i pisac ladowanie zasobu, zwracamy wrapper do zasobu i nic wiecej.
template <class T>
class DLLEXPORT BaseManager
{
protected:
PtrHolder<T>* defaultObject;
std::map<std::string, pad::PtrHolder<T>* > mapRemovedHolders;
std::map<std::string, pad::PtrHolder<T>* > mapObject;
public:
~BaseManager();
bool AddObject(std::string _name, T* _object, ResPtr<T>& _outPtr);
virtual bool GetObject(std::string _name, ResPtr<T>& _outPtr);
virtual bool Restore(std::string _name);
void GetDefaultObject(ResPtr<T>& outPtr);
void SetDefaultObject(T* _object);
void RestoreAll();
void Dispose(std::string _name);
void DisposeAll();
void Remove(std::string _name);
void Clear();
};

//bazowy manager dla zasobów plikowych
template <class Res>
class DLLEXPORT FileManager : public BaseManager<Res>
{
protected:
std::string path;
virtual bool LoadRes(std::string _fileName, Res** _res);
public:
FileManager(std::string _folderPath);
~FileManager(){};
void SetResFolderPath(std::string _path);
virtual bool GetObject(std::string _name, ResPtr<Res>& _outPtr);
virtual bool Restore(std::string _name);
};



O a tu juz mamy klase której uzywam w kodzie, jakis manager do obslugi bitmap, przeslaniam metode ladowania tego konkretnego zasobu(LoadRes), móglbym jeszcze w imoplementacji obsluzyc rózne typy tekstur na podstawie rozszerzen np.: jpg, png. Singleton w postaci statycznej metody i statycznego pola w metodzie, a nie jako membera, co powoduje bklopoty z inicjalizacja tego membera w róznych przestrzeniach adresowych(dll-ka a exe), no i jakas konkretna dla tego managera metoda do tworzenia recznego teksturki.



class DLLEXPORT Image2DMgr : public FileManager<Image2D>
{
protected:
bool LoadRes(std::string _fileName, Image2D** _image);
Image2DMgr();
public:
static Image2DMgr* GetInst();
Image2D* CreateImage(std::string name, int width, int height);
};


Podobnie mam zrobiony shader manager.


class DLLEXPORT ShaderMgr : public FileManager<Shader>
{
protected:
BasicManager<ShaderProgram> m_Programs;
bool LoadRes(std::string _fileName, Shader** _shader);
ShaderMgr();
public:
static ShaderMgr* GetInst();
bool CreateShader(std::string _name, std::string _program, EShader _type, PadPtr<Shader>& _res);
};


A juz manager programów nie dziedziczy po FileManager, bo obsluguje nie plikowe zasoby.


class DLLEXPORT ProgramMgr : public BaseManager<ShaderProgram>
{
protected:
ProgramMgr();
public:
static ProgramMgr* GetInst();
bool CreateShaderProgram(std::string _name, std::string _vertexShader, std::string _pixelShader, PadPtr<ShaderProgram>& _outPtr);
};



No i jak uzyc tego w kodzie:


void QuadricScene::Init(int _width, int _height)
{
MyScene::Init(_width, _height);

ResPtr<Shader> shaderVert;
ResPtr<Shader> shaderFrag;
ResPtr<ShaderProgram> program;

ShaderMgr::GetInst()->SetResFolderPath("D://media//shader//");
ShaderMgr::GetInst()->GetObject("diffuse.vert", shaderVert);
ShaderMgr::GetInst()->GetObject("diffuse.frag", shaderFrag);
ProgramMgr::GetInst()->CreateShaderProgram("program0", "diffuse.vert", "diffuse.frag", program);

ShaderMgr::GetInst()->GetObject("PerPixel.vert", shaderVert);
ShaderMgr::GetInst()->GetObject("PerPixel.frag", shaderFrag);
ProgramMgr::GetInst()->CreateShaderProgram("program1", "PerPixel.vert", "PerPixel.frag", program);


sphereGeom = new GeomSphereQuadric(2, 20, 20);
cylinderGeom = new GeomCylinderQuadric(2, 2, 2, 20, 20);
coneGeom = new GeomCylinderQuadric(0, 3, 2, 20, 20);
discGeom = new GeomDiskQuadric(1, 3, 30, 30);
partialDiscGeom = new GeomCylinderQuadric(0, 3, 2, 50, 50);

meshSphere = new Mesh(sphereGeom);
meshCylinder = new Mesh(cylinderGeom);
meshCone = new Mesh(coneGeom);
meshDisc = new Mesh(discGeom);
meshPartialDisc = new Mesh(partialDiscGeom);
meshSphere2 = new Mesh(sphereGeom);
meshCylinder2 = new Mesh(cylinderGeom);

meshSphere->SetPosition( 5, 1, -3);
meshCylinder->SetPosition( 5, 1, -10);
meshSphere2->SetPosition( 12, 1, -3);
meshCylinder2->SetPosition( 12, 1, -10);
meshCone->SetPosition( 17, 1, -3);
meshDisc->SetPosition( 17, 1, -10);
meshPartialDisc->SetPosition( 17, 1, -15);

meshCylinder->GetMaterial().SetBase("Copper");
meshCylinder->GetMaterial().SetShaderProgram("program1");
meshCylinder2->GetMaterial().SetBase("Copper");
meshCylinder2->GetMaterial().SetShaderProgram("program1");

meshCone->GetMaterial().SetBase("PolishedGold");

meshDisc->GetMaterial().SetBase("Ruby");
meshDisc->GetMaterial().SetShaderProgram("program1");
meshPartialDisc->GetMaterial().SetBase("Ruby");
meshPartialDisc->GetMaterial().SetShaderProgram("program1");

meshSphere->GetMaterial().SetBase("Ruby");
meshSphere->GetMaterial().SetShaderProgram("program0");
meshSphere2->GetMaterial().SetBase("Ruby");
meshSphere2->GetMaterial().SetShaderProgram("program1");

meshCone->Rotate(90, 0, 0);
meshPartialDisc->Rotate(90, 0, 0);

scene3D->AddObject(meshSphere);
scene3D->AddObject(meshCylinder);
scene3D->AddObject(meshSphere2);
scene3D->AddObject(meshCylinder2);
scene3D->AddObject(meshCone);
scene3D->AddObject(meshDisc);
scene3D->AddObject(meshPartialDisc);
}



Zostala ostatnia kwestia, napisalem metody w managerku GetDefaultObject, SetDefaultObject. Jesli dostajemy z managera wskaznik do zasobu, to trzeba by sprawdzic czy jest NULL i dopiero wtedy bezpiecznie uzyc go, fuck, pieprzone NULLe.
Moga sie nam te NULLe pojawic, nie pytajcie jak, takie jest zycie, jak uniknac obslugi tych nieszczesnych przypadków? Otóz zapewniajac jakis defaultowy zasób np.: dla bitmap moze to byc bitmapa 1x1 w bialym kolorze, dla dzwieków, 1 sekundowy
pusty dzwiek lub cokolwiek. Cos co nie zalamie programu, trzeba utworzyc taki zasób i wrzucic go na samym poczatku do managera, np. w konstruktorze przez SetDefaultObject. Trzeba jeszcze wyspecjalizowac nasze ResPtr-y dla takich zasobów, czyli operatory wyluskania.



//specjalizacja operatorów dla zasobu typu Text
template<>
Text* ResPtr<Text>::operator->()
{
return ptr && ptr->GetPointer() ? ptr->GetPointer() : TextManager::GetInst()->GetDefaultRes();
};

template<>
Text& ResPtr<Text>::operator*()
{
return ptr && ptr->GetPointer() ? *ptr->GetPointer() : *TextManager::GetInst()->GetDefaultRes();
};


Dziekuje i do uslyszenia.

środa, 1 lipca 2009

Introwertyzm to zaleta

Cześć ludzie, żyje i mam się dobrze, zmieniamy dekoracje, won mi z tym informatycznym bełkotem, jaką to ma wartość, skoro po śmierci to już nikomu nie będzie potrzebne. Dziś rzecz poważna, pogadamy o człowieku a nie o bezdusznej technologii.


Kto z was wie co oznacza termin „introwertyzm”, no kto rączka w górę, ha ha nie wielu z was, bo ten kto wie zapewne jest od dawna introwertykiem i szuka rozpaczliwie pomocy. A niewielu nas jest, a wielu nieświadomych swego przeznaczenia.
Nie możesz się odnaleźć w otaczającej rzeczywistości? Czujesz się jak istota z innej bajki? Przytłacza cię samotność, brak zrozumienia? Ludzie wytykają cię palcami i krzyczą odmieniec :)? Nie masz dziewczyny albo chłopaka? Nie uprawiałeś-aś seksu od lat lub wcale? Tak, tak, tak, rozumiem cię, jesteś podobny do mnie. Ale nie martw się, otóż okazuje się że to buheheh nie jest wada, nie jesteś gorszy od innych, od tych wstrętnych i hałaśliwych ekstrawertyków, nie lubię ich, myślą że świat należy do nich, wredne kanalie.

Jest nas mniej, jesteśmy w cieniu, ale jakże by ten świat wyglądał bez naszych odkryć, bez bomby atomowej:), bez naszych głębokich rozważań o głębi tego i owego.

Jam to odkrył, studiując starożytne manuskrypty i pergaminy znalazłem nadzieję. Teraz będzie poważniej. Jestem introwertykiem jak cholera, niewielu z was może się ze mną równać, mam 12 dan w introwertyźmie, jestem tak cholernie zamknięty w sobie, że nie jestem pewien czy to ja pisze czy moja druga osobowość, zły Smeagol, błazen, nie wiem kto. Od dłuższego czasu próbuję poznać siebie, i od około pól roku mam rezultaty. Nie możemy siebie zmienić w ekstrawertyków, taka konwersja jest raczej niemożliwa i pochłonie ogromne zasoby cennej życiowej energii nie dając wyraźnych rezultatów. Nie tędy droga, jest inna koncepcja, polegająca na akceptacji swojego charakteru, na pozbyciu się najgroźniejszego wroga introwertyka, czyli na pokonaniu samego siebie, swojego wstydu, strachu, niskiej samooceny.
Jeśli pokonacie tego wroga, będzie z górki, poczujecie wyraźną ulgę, a może nawet poczujecie jak rośnie w was potężny mag :).

Ok, ok, spokojnie, cisza na Sali, małe zamieszanie, głupie uśmieszki, widzę zwątpienie na waszych nędznych, poskręcanych od introwertycznej niedoli gębach. Jam se tego sam nie wymyślił, znalazłem potwierdzenie w starożytnych księgach, kiedy byłem w Minas Tirith.
Dotarłem to ciekawych zapisów w księdze „Introwertyzm to zaleta”. Kilka ciekawych fragmentów wam przytoczę.

„Do Przemyślenia:
- 75 procent ludności to ekstrawertycy, reszta to my.
- Fakt bycia introwertykiem wpływa na wszystkie dziedziny naszego życia.
- Wszystko jest z tobą w porządku.
- Introwertycy często czują się wyczerpani i przytłoczeni nadmiarem bodźców.
- Bycie introwertykiem to coś, z czego należy się cieszyć.„

„Introwertyzm jest zasadniczo typem temperamentu. Nie jest równoznaczny z nieśmiałością lub separowaniem się od ludzi i nie stanowi patologii. Nie jest również zestawem cech, które można zmienić. Natomiast możesz się nauczyć żyć z nim, zamiast przeciw niemu.”

Introwertycy czerpią energię z wewnątrz, w samotności, a tracą ją bardzo szybko w towarzystwie, ekstrawertycy mają odwrotnie, czerpią energię z zewnątrz przebywając w towarzystwie. Ekstrawertycy nie muszą się tak jak introwertycy przejmować się wydatkami energii, introwertycy muszą ją oszczędzać bo łatwo dochodzi u nich do przeładowania bodźcami ze świata zewnętrznego, które powoduje apatię, zniecierpliwienie. Muszą zachowywać odpowiednie proporcje między spędzaniem czasu w samotności i poza domem. Ekstrawertycy raczej nie muszą się tym przejmować.

„Dla introwertyków odtwarzanie energii wewnętrznej nie jest prostą sprawą, szczególnie przy dzisiejszym tempie życia. Zabiera im to więcej czasu, a energia zużywa się szybciej niż u ekstrawertyków. Muszą zatem przewidywać, ile energii potrzeba na dane przedsięwzięcie – zgromadzić jej odpowiednią ilość i odpowiednio planować zajęcia.”

„Introwertycy lubią trudne zadania, kiedy mogą skupić się na jednej, dwóch dziedzinach i nic ich nie pogania. Jednak kiedy muszą się zajmować jednocześnie zbyt wieloma sprawami, szybko czują się przytłoczeni”

„Dla introwertyków samo przebywanie w towarzystwie innych ludzi może być nadmiernie pobudzające. W tłumie, w szkole czy hałaśliwym, natrętnym otoczeniu ich energia szybko się wyczerpuje. Nawet jeśli bardzo lubią ludzi, to po rozmowie kimkolwiek zaczynają odczuwać potrzebę żeby odejść na bok, zrobić sobie przerwę i odetchnąć. To jest właśnie powód wyłączania się umysłu. Przy nadmiernym dopływie bodźców umysł introwertyka zamyka się jakby mówił: Dość danych. Ekran gaśnie.”

„Introwertycy lubią głębię – ograniczają swoje doświadczenia, ale każde z nich głęboko przeżywają. Często mają mniej przyjaciół, ale ich związki są z nimi bliższe. Lubią zagłębiać się w temat i szukają raczej jakości niż ilości. Dlatego muszą ograniczać się do jednego lub dwóch zagadnień na raz, bo inaczej poczują się przytłoczeni. Ich umysł przyswaja informacje z zewnątrz, a następnie zastanawia się nad nimi i je rozwija. Jeszcze długo po tym jak się czegoś dowiedzą, obracają w myślach i przeżuwają tą informacje – trochę podobnie jak krowy przeżuwające paszę. Któż inny niż introwertyk miałby cierpliwość badać zwyczaje godowe afrykańskiej much tse-tse? Dlatego też nie lubią, kiedy im się przerywa. Trudno im się wydobyć z głębokiej studni koncentracji. Ponadto ponowne skupienie uwagi pochłania im mnóstwo energii, której nie mają w nadmiarze.”

„Na początku XX wieku psychoanalityk Carl Jung współpracował z Zygmuntem Freudem i Alfredem Adlerem, dwoma innymi pionierami psychoanalizy i zauważył coś zaskakującego. Kiedy Freud i Adler dyskutowali o przypadkach tych samych pacjentów, każdy z nich zwracał uwagę na zupełnie inne informacje. W rezultacie wysuwali niemal przeciwstawne teorie. Jung uważał, że każdy z nich uchwycił coś ważnego. Po dłuższym czasie( zgadnijcie czy Jung był ekstra czy introwertykiem?) opracował własną teorię.

Jung uznał, że Freud jest ekstrawertykiem, gdyż jego uwaga był a skierowana na zewnątrz – świat ludzi, miejsc i rzeczy. Wiele jego teorii powstało na podstawie intensywnej korespondencji i niezliczonych dyskusji z innymi badaczami. Freud uważał, że celem rozwoju psychicznego jest znalezienie satysfakcji w świecie zewnętrznej rzeczywistości. Natomiast Adler był zdaniem Jung introwertykiem, gdyż koncentrował się na wewnętrznym świecie człowieka, jego myślach i uczuciach. Teorie Adlera dotyczyły wewnętrznej walki o przezwyciężenie poczucia bezradności wyrażającego się w tym, co nazwał kompleksem niższości. Adler postrzegał ludzi jako twórczych artystów kształtujących swoje życie.

Różnice poglądów doprowadziły do zaostrzenia stosunków miedzy Freudem a Adlerem i Jungiem. Każdy z nich poszedł własną drogą. Od tej pory Freud zaczął przedstawiać introwersję jako cechę negatywną- na przykład pisząc o narcyzmie, sugerował że jest związany ze zwróceniem się ku swojemu wnętrzu. Spowodowało to postrzeganie introwersji jako dysfunkcji – i ten mylny pogląd pokutuje do dziś.

Jung pracował dalej nad rozwinięciem swojej teorii. Przypuszczał że przychodzimy na świat z wrodzonym temperamentem mieszczącym się gdzieś na skali pomiędzy bardzo introwersyjnym a bardzo ekstrawersyjnym. Sadził że musza istnieć fizjologiczne podstawy takiego a nie innego usposobienia. Obecnie nauka wykazuje, że jego przewidywania były trafne. Jung zdawał sobie sprawę, że bylibyśmy najlepiej przystosowani do życia, gdybyśmy mogli z łatwością przesuwać się po tej skali między introwersją a ekstrawersją, w zależności od potrzeb. Jednak wiedział że ludzie nie funkcjonują tak. Jung doszedł do wniosku, że każdy z nas ma naturalną niszę, w której najlepiej funkcjonuje. Uważał również, że poza punktami każde miejsce na skali jest zdrowe. Nie wolno zmuszać dziecka do wyjścia poza jego normalny zakres temperamentu – gdyż narusza to jego indywidualne wrodzone usposobienie. Sądził nawet że jest to przyczyną niektórych psychicznych.

Jednak zaznaczył, że nie musimy się ograniczać do swojej niszy. Nasza zdolność poruszania się po skali może się poprawić wraz z zyskaniem świadomości tego procesu. Na przykład, możesz się nauczyć gromadzić energię, a potem korzystać z tej rezerwy przy mniej naturalnych dla siebie zachowaniach. Wyobraź sobie, że piszesz przez cały dzień mniej dominującą ręką. Jest to wykonalne, ale bardzo wyczerpujące i wymaga dużej koncentracji. Zdaniem Junga tak właśnie odczuwa się funkcjonowanie poza własną naturalną niszą. Potrafisz to zrobić, lecz pochłania to dodatkową energię, a nie wytwarza nowej.


Dalej znalazłem test psychologiczny. 29 pytań o introwertyzm, mój wynik 28/29 odpowiedzi potwierdzających przypadłość. Ciekawe jest to że w miarę jak przybywa nam lat, przesuwamy się bliżej środkowi skali między ekstra a introwertyzmem. Aby na świecie panowała równowaga potrzebne są zalety wszystkich typów temperamentów.

„Wnosimy na to przyjecie jakim jest życie, ważne cechy: zdolność głębokiej koncentracji, zrozumienie, jak dana zmiana wpływa na wszystkich, których dotyczy, umiejętność obserwacji, skłonność do myślenia wykraczającego poza utarte schematy, siłę pozwalającą podejmować niepopularne decyzje i potencjał, żeby zwolnić odrobinę tempo, z jakim świat pędzi naprzód. Oczywiście, introwertycy najchętniej zostawiliby te wszystkie atuty na przyjęciu i czym prędzej wrócili do domu!”

„Do przemyślenia:
Introwertycy są inni i nie ma w tym nic złego.
Introwertycy naprawdę lubią ludzi.
Świat potrzebuje introwertyków z ich wyjątkowymi i cennymi cechami.”

Introwertyczne postaci można znaleźć w filmach:
Amelia – idealny przykład
Szeregowiec Ryan – Tom Hanks jako tajemniczy introwertyczny kapitan
Szósty zmysł – ten mały Anakin Skywalker

Niektórzy znani introwertycy:
Hitchcock
Michael Jordan
Bill Gates – wiedziałem
Clint Eastwood – ha ha spróbujcie wkurzyć introwertyka to dostaniecie wpierdol jak od Brudnego Harrego
Steve Martin – nie spodziewałem się
Harrison Ford – Han Solo introwertykiem?, to żart, albo gość jest naprawdę dobrym aktorem

I na koniec nasza introwertyczna gwiazda, nasza nuklearna perełka.
Albert Einstein – koleżka dusił się w szwabskim systemie edukacji, dopiero wyjazd do Włoch i Szwajcarii pozwolił mu się w pełni rozwinąć. Dlatego wspomniałem o atomówce na początku.

„Kiedy introwertyk nie odzywa się albo mówi powoli, często nie budzi zainteresowania ekstrawertyków. Może się im wydawać (podobnie jak innym introwertykom), że nie ma nic do powiedzenia. Introwertycy nie lubią przerywać innym, więc mogą coś powiedzieć po cichu lub bez nacisku. Ich uwagi bywają znacznie głębsze niż ogólny poziom rozmowy a wtedy pozostali rozmówcy je ignorują, gdyż czują się nieswojo. Po pewnym czasie inna osoba może powiedzieć dokładnie to samo i spotkać się z żywą reakcją. W rezultacie introwertyk czuje się niedostrzegany co jest dla niego frustrujące i krępujące.”

„Większość introwersyjnych dzieci przez cały okres dorastania, odbiera bezpośrednie i pośrednie informacje, że coś jest z nimi nie tak. Muszą wysłuchiwać wymówek (Dlaczego nie możesz szybciej odpowiadać na pytania) i oszczerstw (Może nie jesteś zbyt bystry). 49-cioro introwertyków z którymi przeprowadziłam wywiady, miało poczucie, że czyniono im wyrzuty i niesprawiedliwie traktowano za to jacy byli. Tylko 50-ty z nich, Greg, który był pastorem, nie miał takich doświadczeń. Pochodził z rodziny, gdzie wszyscy byli introwertykami, toteż nigdy nie doświadczył tego uczucia, że jest rybą wyrzuconą z wody. Stworzył harmonijne introwertyczne życie, dzięki temu, że wcześnie zaakceptował samego siebie. Ten przykład pokazuje jak ważne dla naszego charakteru jest sprzyjające środowisko.”

„Żyjemy w kulturze która sławi ekstrawertyków i jest do nich adresowana. Nie wątpliwie uczymy się, że powinniśmy być ekstrawertykami.”

„Introwertycy muszą się nauczyć radzić sobie ze wstydem i poczuciem winy, gdyż inaczej przez większość życia będą nieszczęśliwi.”

„Jeśli odczuwasz okropny, dręczący wstyd, spróbuj ustalić co go wywołało. Na przykład jeśli koleżanka zada ci pytanie w trakcie zebrania, a ty chcesz odpowiedzieć, ale nie potrafisz nic wymyśleć, to zapewne poczujesz wstyd. Masz wówczas ochotę zapaść się pod ziemię. Jestem do niczego, jestem głupi, myślisz. Nie rób tego! Powiedz sobie: (Mój mózg tak pracuje, nie zawsze potrafię szybko odnaleźć odpowiedź. Albert Einstein też tego nie umiał. Mogę powiedzieć koleżance, że muszę przemyśleć to pytanie i później dam jej odpowiedź.) Potem nie wracaj już do tego. Głównym antidotum na wstyd jest wysokie poczucie własnej wartości. Wytłumacz sobie, że wcale nie jesteś wadliwie skonstruowany. Wszystko jest w porządku, po prostu twój mózg pracuje w inny sposób. Dokładne przemyślenie zagadnień jest pożyteczne. Dobrze jest być sobą.”

piątek, 13 marca 2009

Mapa, królowa kontenerów.


Hej tam świecie, co słychać? Miałem coś zrobić na dzień kobiet i udało mi się, rzutem na taśmę, o 18 zazwyczaj mam porządną depresje i myślałem, że już nic nie zrobię, na szczęście o 22 już pełen wiary przystąpiłem do pracy i znalazłem pomysł, wykorzystałem swój Particle System ale dość oszczędnie, wyszło nieźle. Najważniejszy był pomysł i dobra muzyka, ale nie wysłałem swego dzieła choć było blisko, w ostatniej chwili postanowiłem przetestować demko na innym kompiutrze i oczywiście nie zadziałało, zapomniałem o dll-kach Visuala. Większym koszmarem były dla mnie jajca z Stl-em przy zmianie trybu pracy aplikacji z domyślnego Multi-threaded Debug DLL (/MDd) na Multi-threaded Debug (/MTd) zakładka C++->CodeGeneration, co miało zapobiec dodawania visualowych dll-ek do execa. Pieprzone kontenerki zaczęły się sypać w destruktorach na potęgę i to w dosyć losowych miejscach, kurwa …, musiałem powrócić do MDd, taką w sumie radę znalazłem w necie, podobno visualowy Stl jest trochę zjebany i nie ma rady. Poza tym wszystko w porządku.

Dzisiaj na rozkładzie std::map, std::multimap, stdext::hash_map, miał być Object Manager, ale wcześniej trzeba sobie przypomnieć mapę, poza tym chciałem wypróbować jakiegoś hasha i zrobić testy wydajnościowe, jest o czym pisać.

Mapa jest królem, ponieważ jest chyba najczęściej wykorzystywanym kontenerem, a to dlatego, że niemal każdy ObjectManager trzyma obiekty w mapie. Mapa implementowana jako drzewo binarne zrównoważone. Taka struktura zapewnia szybkie wyszukiwanie elementu O(ln N) co jest podstawą jej popularności, wisienką na tym torcie jest fakt, że jest to struktura zawsze posortowana po kluczu,iiihhhha.

Wstawiamy przez [] lub insert(make_pair(key,value)).

Usuwamy przez erase(key), erase(iterator), erase(itBegin, itEnd). Zwracam uwagę na usuwanie it-ka w pętli.

Szukamy elementu przez find(key), która zwraca iterator do obiektu, iterator mapy posiada pola first, second, czyli wskaźniki na klucz i wartość.

Klucz jest unikalny, i próba jego zmiany się nie powiedzie, trzeba usunąć obiekt z mapy i wstawić go od nowa z innymkluczem. Jeśli spróbujemy pobrać wartość przez value = map[key], to w przypadku braku klucza w mapie zwróci nam obiekt
zbudowany przez domyślny konstruktor typu, np. 0 dla long.

Dla mapek mamy iteratory, begin() wskazuje na lewy skrajny węzeł, przejście przez mapę odbywa się w porządku In-order, czyli od lewego do skrajnie prawego węzła powodując przejście w sposób uporządkowany malejąco lub rosnąco.



//kryteria sortowania funktor less, greater
map<long, long, less <long> > mapLong;
map<long, long, less <long> >::iterator itLong;
map<string, string, greater &ltstring> > mapStr;

//mapLong
mapLong[1] = 1;
mapLong[2] = 2;
mapLong[3] = 3;
mapLong[4] = 4;
value = mapLong[5];//przyjmie 0, domyslny konstruktor
itLong = mapLong.begin();

//nie można zmieniać wartości klucza
//można zmienić wartość jeśli nie stała
//można usuwać i wstawiać istniejące lub nie elementy
itLong->second = 5;
mapLong.erase(itLong);// usun przez iterator
mapLong.erase(mapLong.begin(), mapLong.end());//usun zakres mapy
mapLong.erase(7);//usun klucz 7
mapLong.insert(pair <long,long>(8, 8));
mapLong.insert(pair <long,long>(8, 8));
mapLong.insert(pair <long,long>(6, 6));
mapLong.insert(make_pair(7,7));

//przy usuwaniu trzeba uważać, żeby zachować ważny iterator
//wyrażenie itLong++ zwraca itLong po czym robi ++itLong
for(itLong = mapLong.begin(); itLong != mapLong.end(); )
{
if(itLong->second == 8)
mapLong.erase(itLong++);
else
++itLong;
}



Osobna kwestia to mapka dla typów zdefiniowanych przez użytkownika. Tutaj aby mapa umiała ocenić gdzie wstawić nasze obiekty, musimy dostarczyć funktor z operatorem bool operator(const Obiekt& o1, const Obiekt& o2), który zwraca
false gdy o1 <>, można sobie zmienić na greater.



class PersonLess;
class Person
{
friend class PersonLess;
public:
string firstName;
string lastName;

Person(string _firstName, string _lastName) : firstName(_firstName), lastName(_lastName){}
friend ostream& operator<<(ostream& os, const Person& per)
{
os<<per.firstName<<" "<<per.lastName;
return os;
}
};

class PersonLess
{
public:
bool operator()(const Person& p1, const Person& p2) const
{
if(p1.lastName < lastname ="="">& mapa)
{
map<Person, long, PersonLess>::iterator it = mapa.begin();
for(; it != mapa.end(); ++it)
cout<<it->first<<" "<<it->second<<endl;
cout<<endl;
}

map <Person, long, PersonLess> mapPerson;
Person per1("hari","oli"), per2("mati","hautameki"), per3("mati","nykanen"), per4("jane","ahonen");
mapPerson[per1] = 120;
mapPerson[per2] = 130;
mapPerson[per3] = 140;
mapPerson[per4] = 150;
PrintMap(mapPerson);



Obok mapy, która zapewnia unikalność klucza mamy multimapę, która umożliwia gromadzenie wielu wartości pod danym kluczem, szczerze mówiąc nigdy jej nie używałem, ale może się okazać pomocna jeśli ObjectManager grupuje obiekty po jakimś kryterium np. typie, iterator multimapy działa tak samo jak w mapie. Nie mamy tutaj operatora [], mamy metodę count(key) zwracającą liczbę wystąpień danego klucza. Metoda find(key) zwraca iterator do pierwszego z wielu kluczy key w kolekcji.Istnieje wiele metod, których nie ma w mapie, a których po prostu nie chciało mi się testować.



multimap <long, long> multmap;
multimap <long, long>::iterator itMultMap;
long i = 0;

multmap.insert(make_pair(1,1));
multmap.insert(make_pair(1,1));
multmap.insert(make_pair(2,2));
multmap.insert(make_pair(2,2));

//klucze moga sie powtarzac
cout<<"multimapa"<<endl;
cout<<"z kluczem 1: "<<multmap.count(2)<<endl;
cout<<"z kluczem 2: "<<multmap.count(2)<<endl;

cout <<"klucz 1" <<endl;
value = multmap.count(1);
for(i = 0, itMultMap = multmap.find(1); (itMultMap != multmap.end()) && i <>first <<" " <<itMultMap->second <<endl;

cout <<"klucz 2" <<endl;
value = multmap.count(2);
for(i = 0, itMultMap = multmap.find(2); (itMultMap != multmap.end()) && i <>first <<" " <<itMultMap->second <<endl;

cout <<"entire multmap" <<endl;
for(itMultMap = multmap.begin(); itMultMap != multmap.end(); ++itMultMap)
cout<<itMultMap->first <<" "<<itMultMap->second <<endl;
;


Ostatnim rodzynkiem w tej grupie kontenerów jest stdext::hash_map, jest to struktura mieszająca tzn. miejsce wstawienia elementu determinuje specjalna funkcja przyjmująca jako parametr klucz elementu. Nie jest to struktura uporządkowana, dzięki temu operacje wstawiania i usuwania są szybsze niż w zwykłej mapie, ale najważniejszą właściwością struktur mieszających jest bardzo szybka operacja wyszukiwania elementu o złożoność rzędu 0(1), szybciej niż w mapie ale oczywiście wolniej niż indeksowanie w tablicy, to o ile wolniej zależy od implementacji hasha. Prezentowana tutaj stdext::hash_map nie jest częścią standardu STL, ale dostarczaną do środowiska Visual ulubionej firmy, inne implementacje można znaleźć w sieci np.: STLPort. Nowy standard C++ powinien mieć już w std struktury mieszające. Używanie nowego kontenera nie różni się wielce od używania mapy, find(), iterator, wszystko to wygląda tak samo.

Na koniec testy wydajnościowe stdext::hash_map VS std::map.
No cóż, wstawianie elementów do hasha nie jest porażająco szybkie, za to wyszukiwanie elementów jest realnie ze 2-4 razy szybsze, zależnie od wielkości struktury, im większa tym hash ma większą przewagę nad mapą. Nieźle ale jak znajdę czas
spróbuje napisać własną strukturę i wtedy zobaczymy, oczywiście co innego pisać w domu na własne potrzeby a co innego pisać
bezpieczny kod dla mas.Należy używać iteratora w pętli, jest dużo szybciej, widać też ogromną przepaść między szukaniem
w tym hashu a indeksowaniem vectora, stąd wniosek, że można samemu coś lepszego wykombiniować, w sieci można znaleźć
o wiele szybsze hashe od stdext::hash_map. Do standardowych zastosowań mapa będzie lepsza, natomiast w wąskich gardłach
przy dużej ilości iteracji i dużej ilości elementów w mapie musimy użyć hasha, póki co jeszcze takiego miejsca w moim kodzie
nie ma.



//używanie tych kontenerów jest identyczne
//declaration
std::map <long, long> mapLong;
stdext::hash_map <long, long> hashLong;
long l = 0;

//fill
for(long i = 0; i < i =" 0;" itmaplong =" mapLong.begin();" l =" itMapLong-">second;
for(itHashLong = hashLong.begin(); itHashLong != itHashLongEnd; ++itHashLong)
l = itHashLong->second;

//find by random index
for(long i = 0; i < itmaplong =" mapLong.find(tabLong[i]))" l =" itMapLong-">second;
for(long i = 0; i < ithashlong =" hashLong.find(tabLong[i]))" l =" itHashLong-">second;

String w formacie alamakota_kotmaale_ + liczba odpowiadająca indeksowi
Czas w milisekundach.
1000 000 iteracji przy Fetch.

Fill containers
Map size: 10tys 1mln
vector: 1 6
map: 21 2079
hash: 20 2527
vector: 1637 21702
map: 342 15511
hash: 133 15298

Fetch by index
vector: 1 1
map: 88 219
hash: 64 131
vector: 67 70
map: 793 1256
hash: 265 513

Fetch by iterator
vector: 9 9
map: 17 31
hash: 9 105
vector: 67 69
map: 23 62
hash: 11 109

Find random key
vector: 3 3
map: 197 1128
hash: 62 281
vector: 87 250
map: 1034 3022
hash: 341 1038

środa, 4 marca 2009

Tablica, vector, chleb powszedni.


Hej ludzie, co słychać? Jak tam wasze zajebiste projekty, moje chwilowo stoją w miejscu, powód?, Civilization 3, fuck, nie pamietam ile razy już łamałem, niszczylem, sprzedawałem płyty z tą grą, jest zabójczo uzależniająca, wiedziałem to a mimo to kupiłem ją znowu, masakra.

Dziś na tapecie mamy tablice z języka C i pytanie o sens ich istnienia w obliczu wektora i potęgi szablonów z C++. Pytanie to mnie naszło gdy natknąłem sie na klase carray z księgi "C++ biblioteka standardowa", jest to klasa osłonowa na zwykłą tablice posiadająca interfejs STL-owy, którą wam pokaże za moment. 

Na razie zwykła tablica i jej zastosowania. Oczywiście nie znamy rozmiaru tablicy w momencie jej deklaracji stąd musimy użyć wskaaźnika na typ tablicowy. Ważne jest dla nas, żeby w dowolnym momencie utworzyć tablice o dowolnym rozmiarze i pozbyć się jej gdy nam przyjdzie ochota. Jedziemy szablonem ponieważ nie wiemy jakiego typy wierzchołki będa nam potrzebne a w każdej chwili może nam przyjść do głowy zmiana koncepcji, kod powinien być gotowy na zmiany. Wszystko gra i bucy, jedyny minus to zmienna numVerts, w której musimy trzymać rozmiar, nie idzie tego inaczej rozwiązać sizeof(verts) zwróci rozmiar pointera, sizeof(*verts) rozmiar elementu, nie mam pojęcia czy da sie to jakoś zrzutować na tablice, raczej nie. Drugi minus to brak STL-wego interfejsu, stąd nie użyjemy np: algorytmów std::copy czy std::sort. Duża zaleta tablicy to ciągły obszar pamieci jaki zajmuje, dlatego możemy pojechać z funkcjami takimi jak: 

memcpy - kopiowanie bloku pamięci 
memset - wypełnianie pamięci wartością zdaje sie int lub unsigned int

Dzięki ciągłemu blokowi pamięci unikamy też fragmentacji pamięci, toteż tablica idelanie nadaje sie do przechowywania danych cząstkach systemu cząstkowego, których jest zwykle bardzo wiele, ale o tym kiedy indziej.



template
class Geometry
{
protected:
VERTEX* verts;
long    numVerts;
void CreateArrays(long _numVerts)
{
   Clear();
   numVerts = _numVerts;
   verts    = new VERTEX[_numVerts];
}
void Clear(){ SAFE_DELETE_ARRAY(verts); }
public:
Geometry(long _numVerts)
{
   verts = 0;
   CreateArrays(_numVerts);
}
~Geometry(){ Clear();}

VERTEX* GetVerts(){ return verts; }
long    GetNumVerts(){ return numVerts; }
virtual void Draw()
{
   printf("verts size = %d\n", numVerts);
     //glVertexPointer(numVerts, GL_FLOAT, 0, verts);
   //glDrawArrays(GL_POINTS,0, numVerts);
}
}
;


Druga klasa, którą chce pokazać to Carray z książki do STL, jako wrapper na zwykłą tablice. Jej zaletą jest to że posiada interfejs typowy dla innych kontenerów, stąd cały arsenał gotowych algorytmów stoi przed nami otworem, praktyka pokazuje jednak, że nie będziemy z tego w ogóle korzystać, ponieważ tablic danych, nie wskaźników używamy tylko po to aby przekazać, skopiować, wyzerować dane. Przy czym od nadmiaru dobrego głowa nie boli, więc mogę ją dodać do swojego commona.dll. Bezczelnie nazwałem to cudo MyArray ponieważ dodałem kilka poprawek, bewzględnie należy zapomnieć o podawaniu rozmiaru jako parametru szablonu, bo wtedy naszą tablicę możemy o kant dupy rozbić. Musi być elastyczna. Zgodnie z STL-ową manierą nazwy metod są z małej literki, niech im będzie, zresztą nazwy muszą sie zgadzać aby zachować interfejs kontenerów.



template
class MyArray
{
protected:
T*          v;
std::size_t sizeV;
public:
typedef T*          iterator;
typedef const T*    const_iterator;
typedef T&          reference;
typedef const T&    const_reference;
typedef std::size_t size_type;

MyArray(std::size_t _size)
{
   sizeV = _size;
   v     = new T[sizeV];
}
void                 clear(){ SAFE_DELETE_ARRAY(v); }
iterator             begin(){ return v; }
const_iterator       begin() const { return v; }
iterator             end() { return v+sizeV; }
const_iterator       end() const { return v+sizeV; }
reference            operator[](std::size_t i){ return v[i]; }
const_reference      operator[](std::size_t i) const { return v[i]; }
reference            at(std::size_t elem){ return v[elem]; }
const_reference      at(std::size_t elem) const { return v[elem]; }
size_type            size(){ return sizeV; }
size_type            max_size(){ return sizeV; }
T*                   as_array(){ return v; }
};

//przykład MyArray
MyGeometry* geom3  = new MyGeometry(5);
Vertex3*    verts3 = geom3->GetVerts();
MyArray     arr    = geom3->GetVertObject();
arr[0].x = 9;
geom3->Draw();



Ostatni element dzisiejszego wywodu to sławetny std::vector. Jest znany pod każdą szerokoscią geograficzną, nawet na Madaskarze go używają. Ma jedną podstawową przewage nad tablicą, umie sie rozszerzać, jego problem jest niestety taki że rośnie razy dwa, gdy mu braknie miejsca. Na szczęście możemy mu zarezerwować określone miejsce z góry. Możemy go używać zamiennie z tablicą i przekazywać &vec[0] wszędzie tam gdzie jej oczekują. Myśle że może być z powodzeniem wykorzystywany tam gdzie chcemy mieć dynamiczny bufor wierzchołków, ze wskazaniem na rozszerzanie bufora, bo niestety nasz cudowny std::vector nie umie zmiejszać swojego rozmiaru. tzn zmniejszać zapotrzebowania na zużywaną pamięć. Ponieważ jest to ciągły blok, więc możemy łatwo i szybko kopiować cały vector lub jego część przez memcpy().
Ale o wiele wygodniej jest używać algorytmów STL.



//kopiowanie vector
std::vector vec1;
std::vector vec2;
std::vector vec3;
//rezerwuj pamięć na 4 elementy
vec1.reserve(4); vec2.reserve(4);
vec1.push_back(1);
vec1.push_back(2);
vec1.push_back(3);
vec1.push_back(4);
vec2.push_back(5);
vec2.push_back(6);
vec2.push_back(7);
vec2.push_back(8);
//kopiowanie vec1 do vec3
vec3.insert(vec3.end(), vec1.begin(), vec1.end());
//kopiowanie vec1 do vec2
std::copy(vec1.begin(), vec1.end(), vec2.begin());

//tablica a vector
int* tab = NULL;
tab = &vec2[0];
memset(&vec2[0], 0, vec2.size()*sizeof(int));
memcpy(&vec3[0], &vec2[0], vec2.size()*sizeof(int));
std::copy(vec1.begin(), vec1.end(), vec2.begin());

//iteratory
//iteratory powinny być szybsze, gdyż są to poitery na obiekty, nie ma kopiowania całego obiektu
std::vector::iterator it = vec3.begin();
for(; it != vec3.end(); ++it)
   printf("value = %d ", *it);

// wyciągaj obliczenie rozmiaru przed pętle
int vecSize = vec3.size();
//++i jest szybszy od i++, brak obiektu tymczasowego
for(int i = 0; i < vecSize; ++i)
    printf("value: %d",vec3[i]);


                                                                                   
W książce do pisania gier piszą żeby używać std::vector wszędzie tam gdzie można użyć tablicy. Na pewno tak, najważniejsze, że możemy go używać zamiennie z tablicą, dzięki czemu przekażemy nasz wektor jako tablice do np: jakiejś funkcji OpenGL. Ważne jest żeby prawidłowo zalokować od razu całą pamięć i nie zrobić później głupiego push_backa, bo nam rozwali pamięć. Dlatego też wacham się trochę, ze wskazaniem na wektor. Ważny jest szablon na typ, dzięki temu mamy duże pole manewru, ale ile z tego powodu może być problemów to jeszcze kiedyś napisze.

niedziela, 1 marca 2009

Witaj wielki świecie.

Witaj świecie, nie moge sie dostać do ftpa starej stronki pawelad.ovh.org stąd musze sie bawić w bloga. Troche mnie wkurwia to całe bogowanie, facebooki i inne internetowe gówna, ale w tą stronę poszła cywilizacja to i ja musze sie z tym pierdolić. Nawiasem mówiąc mam mały problem z przeklinaniem, nauczyłem sie i teraz nie idzie sie tego zmienić, ale próbuje kurna.

Z nowym rokiem 2009 AD zacząłem sobie nowy projekt kilka dll-ek dźwięk na fmod, graficzka w opengl, jakiś common, input itp. Planuje sobie zrobić jakieś ciekawe demo, na razie udało mi sie strzelić walentynke, wiecie tasowanie zdjęciami, muzyczka w tle i napisy do niej zapierdalające z głebi ekranu. Oczywiście nie wysłałem bo w ostatniej chwili złapałem cykora, ale może to i lepiej, po co narażać dziewczyne na stres, jakoś to przełknąłem, ale planuje nowe demko, tym razem na dzień kobiet. Będzie się dziać, użyje napisanego niedawno lecz nie testowanego particle systemu, kwiaty bedą zapierdalać po całym ekranie, fontanna kwiatów, kwiatki z głebi, kwiatki z góry, płatki ala American Beauty .... 

Walentynki wam nie moge pokazać, ale kod już tak.
Źródła projektu dla ciekawych

środa, 26 grudnia 2007

Ssstart

Usprawiedliwiam się tym, że ... jestem wysoko cenionym specjalistom, ale w innej dziedzinie, stąd ciężar strony domowej leci na tego oto (hmm, jakie to ma fajne ułatwienia), tego oto bloga. Nie wiem czy to będzie miało jakąś wartośc programistyczną, ale przynajmniej będzie pamiętnik. Na pewno ułatwi mi życie (hmm chłopaki zasłużyli na piwko). Tematyka kodersko-wsiowa, język C++ głownie z pewnymi ozdobnikami hrmm(wolno mi tu zaklnąc?, takie niewinne kurwa? uff od razu mi lepiej). Zobaczymy jak sie to ułoży, postaram sie napisac kilka postów w tematyce C++, 3D, do zobaczenia.