Ładowanie
popup

Kolorowanie

2010-04-24 13:09:56

(dziś trochę "lanie wody" :) )

W przerwie między kodowaniem silnika, nauką C#, modyfikowaniem (nieziemsko tragicznego) kodu osCommerce i innych PHP-owych dziwolągów, postanowiłem podjąć się czegoś innego - bardziej ambitnego - mianowicie: zmienić kolorowanie składni mojego edytora (VC++) :> Od dawna w każdym edytorze używam kolorowania pododnego do klasycznego Borlandowego, które trochę zmieniłem. Oto rezultat:

Mój schemat kolorów Visual C++
Mój schemat kolorów Visual C++

Używam czcionki Lucida Console. Wygląda prawie identycznie jak Consolas, z tym że jest trochę "niższa" i tekst jest bardziej zbity (taki preferuję).

Dla zainteresowanych pliki z ustawieniami kolorowania dla VC++2008 (działają też z VC++2010):

Tagi: Inne Visual Studio | Komentarze (1)

Eksportowanie geometrii z Blender-a

2010-02-16 12:17:34

Ostatnio przerabiałem eksporter geometrii z blendera. aktualny skrypt był bardzo stary i potrzebował natychmiastowej przeróbki, wiec napisałem nowy. Przedstawię kilka porad na podstawie moich ostatnich doświadczeń na tym polu. Używam Blendera 2.49

Najwazniejsze to określić co będziemy eksportować. Czy to będzie jedna siatka, czy cały model (model składa się z x siatek (mesh))?, czy format będzie 'końcowy' czy przetwarzany?, jakie dane eksportować? jak i czy eksportować animacje? jak eksportować materiały? czy to będzie format binarny czy tekstowy? postaram się pomoc w odpowiedzi na niektóre z nich

to mniej - więcej tyle. resztę informacji można znaleźć w dokumentacji Blendera, czy w źródłach innych eksporterów dołączonych do programu.

a to test mojego eksportera porsche: 24000 wierzchołków
a to test mojego eksportera porsche: 24000 wierzchołków
palma 3500, a to sama palma (mojej produkcji :P)
palma 3500, a to sama palma (mojej produkcji :P)

//~

Tagi: Programowanie Engine Blender Python | Komentarze (2)

Tekstury NPOT w OpenGL

2009-12-01 12:07:35

Ostatnio przyszło mi skorzystać z tekstur nie mających wymiarów będących potęgami liczby 2 (NonPowerOfTwo). Dawniej radziłem sobie z takimi teksturami rozciągając mniejszą teksturę na większą mającą rozmiar będący potęgą 2 lub wklejając ją na fragment takiej tekstury. Dostępne są jeszcze dwa rozszerzenia wspomagające pracę z teksturami NPOT: texture_non_power_of_two i texture_rectangle. Oba są w standardzie OpenGL, texture_rectangle jest troche starsze. Przyjrzyjmy się im bliżej.

cechy texture_rectangle:

cechy texture_non_power_of_two:

Jak widać używanie texture_rectangle jest problematyczne, natomiast texture_non_power_of_two nie zmusza do wprowadzania zmian w programie: po prostu tworzymy teksturę podając 'dowolny' wymiar i używamy jak zwykłą teksturę. Wybieram ARB_texture_non_power_of_two.

W moim przypadku nie obyło się bez niespodzianek :) Oczywiście mój Radeon 9600 obsługuje oba rozszerzenia, ale nie do końca... Czasem działa, czasem nie - pełna losowość. A jak renderuję do tekstury NPOT to w ogóle nie działa. Szybka zmiana parametrów tekstury i wniosek: Po wyłączeniu filtrowania, ustawieniu zawijania na GL_CLAMP_TO_EDGE i nie generowaniu mipmap wszystko działa. Działa tak jak texture_rectangle, a ma ograniczenia jak texture_non_power_of_two, achh te 'ogl-owskie' sterowniki ATI...

Tagi: Programowanie OpenGL | Dodaj komentarz

GUI

2009-11-28 21:35:05

Niedawno skończyłem pisać system GUI do swojego silnika. Zawiera podstawowe kontrolki, obsługę skórek, rożych typów czcionek, prosty tryb 3d i takie tam :P Nie chcę sie rozpisywać, chyba wszystko widać na screenach i na filmikach. Teraz zabieram sie za ciekawsze rzeczy niż pisanie interfejsów :)

GUI#1
GUI#1
GUI#2
GUI#2
GUI#3
GUI#3
GUI#4
GUI#4
GUI#5
GUI#5

Tagi: Programowanie Engine | Komentarze (2)

Jak (nie) optymalizować kodu #1

2009-10-18 01:22:00

Pierwszą próbą optymalizacji bylo użycie FPU (czyli jednostka zmiennoprzecinkowa CPU) do zbudowania funkcji zastepujacych odpowiedniki z cmath. Pierwsze testy w trybie debug z domyslnymi ustawieniami wygladaly bardzo pozytywnie. Liczyłem w pętli kilka operacji, uzywajac odpowiednio funkcji z biblioteki standardowej cmath i z moich funkcji z uzyciem FPU. Czasy moich funkcji byly około 3 razy krótsze. Po włączeniu optymalizacji w kompilatorze - /fp:fast i /Oi (ten przełacznik włącza wstawianie instrinsic-ów w miejsce niektórych funkcji, w tym wiekszości tych z cmath) czasy moich funkcji byly juz tylko 2 razy krotsze. Po przełączeniu do trybu release stało sie to czego sie spodziewałem(?), cmath był szybszy... o wiele. Opcje /fp:precise i /Ox dały od kilku do kilkusetkrotne przyspieszenie. Nie pomogło też wstawienie do funkcji __forceinline. Przełączyłem więc się na podgląd instrukcji Asemblera. Hmm... kod dla funkcji z cmath nie byl wogóle generowany (nadal mowa o trybie Release). Stąd takie kosmiczne czasy ;) Rozwiązaniem tego 'problemu' jest wyłączenie optymalizacji (C++/Optimalization/Optimalization=Disabled (/Od)) lub zmiana sposobu mierzenia obliczeń. Dla przykładu w takim kodzie NIE zostanie wywolana funkcja sqrt:

float x=std::sqrt(xxx); x=sth;

kompilator zapewne ufa że brak wywołania funkcji sqrt nie spowoduje jakiegoś błedu w dalszych obliczeniach, bo za chwile w miejsce zmiennej x zostanie zapisana nowa wartość. Więc na przykład taka metoda mierzenia wydajności jest chyba bez sensu:

TIMER_START; for(int i=0;i<99999;++i){ xx3=std::sqrt(rrr); rrr+=0.56f; } TIMER_END;

Zmiana ustawień kompilatora moze spowodować że wyniki będa troche niesprawiedliwe. Pozostaje zmiana metody mierzenia. Ustawiem spowrotem opcje (C++/Optimalization/Optimalization=Full Optimization (/Ox)). Trzeba zmusic kompilator do uruchomienia funkcji z cmath. Kod:

float sth=...; TIMER_START; for(int i=0;i<99999;++i){ xx3=std::sqrt(rrr); sth+=xx3; // np. tak rrr+=0.56f; } TIMER_END;

Dodałem zmienna sth ktora będzie zainteresowana wynikiem funkcji std::sqrt. Ale to za mało nadal funkcja sqrt nie bedzie wywołana, ba - wogóle cała pętla będzie 'wyrzucona'. Działanie programu nie zmieni sie czy będzie ta pętla czy nie. Wystarczy wypisac dalej printf("%f",sth) i juz działa... Swoją drogą spryciarz z tego kompilatora :) Ostateczne pomiary sa pozytywne:

fpu_math time= 0.004849s cmath time= 0.005963s fpu_math time= 0.004900s cmath time= 0.010668s fpu_math time= 0.001266s cmath time= 0.002462s ...

Ostatecznie można powiedzieć że przyspieszenie jest, choć nie wiem czy to wszystko warte zachodu (dla satysfakcji można duzo zrobic) :P Jeszcze dodam kilka przykładów funkcji których użyłem w teście jak kogoś to interesuje (w komentarzach bardziej złożonych funkcji opisałem zawartości stosu):

float Cosf(float x) { __asm { fld x fcos } } float Sqrtf(float x) { __asm { fld x fsqrt } } // oszczedze miejsce (wiekszosc wyglada jak powyzsze) :) i podam dalej tylko te trudniejsze do napisania: float Powf(float x,float y) { __asm { fld y fld x fyl2x ;log2(x)*y fst st(1) ;log,log frndint ;int(log),log fxch st(1) fsub st(0),st(1) ;float(log),int(log) f2xm1 ;2^float(log)-1,int(log) fld1 faddp st(1),st(0) ;2^float(log),int(log) fscale ;2^int(log)*2^float(log) } } float Expf(float x) { // exp(x) == e^x __asm { ;y==e fld x fld GE_E fyl2x ;log2(x)*y fst st(1) ;log,log frndint ;int(log),log fxch st(1) fsub st(0),st(1) ;float(log),int(log) f2xm1 ;2^float(log)-1,int(log) fld1 faddp st(1),st(0) ;2^float(log),int(log) fscale ;2^int(log)*2^float(log) } } float Logf(float x) { // ln(x) (naturalny!) __asm { fld1 fld x fyl2x ;log2(x) fldl2e ;log2(e) fdivp st(1),st(0) } } float Log10f(float x) { __asm { fld1 fld x fyl2x ;log2(x) fldl2t ;log2(10) fdivp st(1),st(0) } }

Dodatkowo funkcje których nie ma w standardowej bibliotece matematycznej, a mogą sie przydać jak ktoś sie interesuje tematem :) :

void Sincosf(float x,float *oSin,float *oCos) { // sinus i cosinus od x __asm { mov eax,oSin mov edx,oCos fld x fsincos fstp dword ptr[edx] fstp dword ptr[eax] } } float Log2f(float x) { // log2(x) __asm { fld1 fld x fyl2x ; sciagnie sam st(1) } } float Logxf(float x,float y) { /* oblicza logarytm dowolnej podstawy: logx(y) sposob liczenia: logx(y)=log2(y)/log2(x) */ __asm { fld1 fld y fyl2x ;log2(y) zwija 1 ze stosu fld1 fld x fyl2x ;log2(x) zwija 1 ze stosu fdivp st(1),st(0) } }

Tagi: Programowanie C++ Optymalizacja Asembler Visual Studio | Dodaj komentarz

Dynamiczne tablice wielowymiarowe "w jednym kawałku pamięci"

2009-08-24 22:18:00

Jak wiadomo tworzenie wielu "małych" obiektów na stercie (new) może powodować znaczna fragmentacje pamięci, wiec należy tego unikać. Dla bardzo dużej ilości obiektów, potrzebującej bardzo dużej ilości operacji zwalniania i alokowania można stosować ręcznie "placement new" lub bardziej zaawansowane "upraszczacze" jak np. "FreeList". a co ze zwykła tablica? Standardowa funkcja alokująca tablice 2-wymiarowa może wyglądać tak:

template<typename T>T **alloc2d(int width,int height){ T **mem=new T*[width]; for(int x=0;x<width;++x) mem[x]=new T[height]; return mem; }

jak widać tablice mamy w pamięci 'w kawałkach' o rozmiarze odpowiadającym zmiennej height. Jak to zmienić? Trzeba zastosować "placement new". Nowa wersja wygląda tak (typ int8 odpowiada 1 bajtowi):

template<typename T>T **alloc2d(int iX,int iY){ // alokuje wszystko w jednym bloku (dane i wskazniki na dane) int8 *raw=new int8[iX*iY*sizeof(T)+iX*sizeof(T*)]; // przydziela pamiec z bloku dla wskaznikow // wskazniki sa przed danymi-stad offset o rozmiarze wskaznikow ponizej T **ret=new(raw) T*[iX]; // przydziela pamiec z bloku dla danych (znajduja sie za wskaznikami) T *data=new(&raw[iX*sizeof(T*)]) T[iX*iY]; // przypisuje do wskaznikow adresy danych for(int i=0;i<iX;++i,data+=iY) ret[i]=data; return ret; }

Co nam to daje (oprócz umiejscowienia w jednym kawałku pamięci)?

Jak sie dostać bezpośrednio do danych takiej tablicy?. Można sie posłużyć taka prosta funkcja:

template<typename T>T *Get2d(T **iA,int iX){ // mijamy wskazniki return (T*)(((int8*)iA)+iX*sizeof(T*)); }

Na koniec trzeba usunac taka tablice:

template<typename T>void Free2d(T **iA){ int8 *ptr=(int8*)iA; delete []ptr; iA=NULL; }

jak można sie domyślić można sobie łatwo zrobić tez wersje 3,4,... wymiarowa.

Tagi: Programowanie C++ | Dodaj komentarz

Start

2009-03-15 12:34:00

Hello World!

Tagi: Inne | Dodaj komentarz

<< Starsze Nowsze >>