Ostatnie zmiany AGE pod Linuxem

28 09 2008

Ostatnio wprowadzone w AGE zmiany zostały pomyślnie przyjęte przez Ubuntu ;) Kod wymagał jedynie dwóch drobnych poprawek i wszystko już działa jak należy.

Wspomniane przeze mnie ostatnio zamierzane zmiany również zostały już wprowadzone. No może z wyjątkiem tej dotyczacej edytowania tekstury bezpośrednio – strasznie mi się nie chce tego robić ;)

Zastanawia mnie natomiast co innego. Jedną z dwu wprowadzonych zmian była zmiana koordynatów tekstury wymagana ze względu na to, że były pokazywane do góry nogami… Dość dziwne – biorąc pod uwagę, że w Windowsie działało inaczej…





Code::Blocks Tools

27 09 2008

Jak każdy wie (przynajmniej niektórzy ;) ) w Code::Blocks istnieje menu Tools. Do tej pory nie korzystałem z tego zbynio bo nie przychodziło mi do głowy cóż mogę tam wrzucić. Dzisiaj wpadłem na pomysł jak można wykorzystać ten feature (tak – wiem, że tego wyrazu nie lubią niektórzy z Warsztatu).

Otóż jak trzeba coś robić często i na dodatek pożera to więcej czasu niz powinno to zaczyna to być wkurzające. Taka jest również moja (w tym wypadku niezbyt smutna) historia. Chodzi o przejście do folderu projektu. W moim przypadku chciałem pozmieniać conieco w plikach graficznych itp. i za każdym razem musiałem wchodzić w kilka podfolderów dysku. Dziś postanowiłem powiedzieć takiej pracy stanowcze “NIE!” i sprawdzić czy da się wykorzystać te narzędzia Code::Blocks aby robiły to za mnie. Okazało się, że tak!

Na początku kliknąłem “Tools->Configure Tools”. W okienku nie było zbyt wielkiego wyboru: “Add”. W nowowyskoczonym, że tak to ujmę, okienku pojawiło się kilka pól tekstowych i lista zmiennych jakich można użyć. Fajnie – nie trzeba tego szukać w internecie albo helpie. Wpisałem nazwę dla tego “nadrzędzia”, następnie w polu Executable wpisałem explorer, a jako parametr: ${PROJECT_DIR}. Na końcu wystarczyło wybrać sposób uruchamiania i kliknąć OK.

Werble, klik, chwila niepewności, napięcie rośnie, udało się! Moim oczom ukazał się folder z projektem. Pozostaje pytanie – dlaczego nie wpadłem na to wcześniej?





Zmiany w AGE

27 09 2008

Ostatnio miałem trochę czasu aby posiedzieć chwilę dłużej nad kodem z czego oczywiście skorzystałem.

Największą zmianą było wyrzucenie menedżera zasobów na rzecz wczytywania z wirtualnego systemu plików. Doszedłem do wniosku, że menedżer w tamtej postaci był nieprzydatny. W końcu nietrudno jest zrobić coś bezużytecznego i się przy tym napracować ;)

Kolejną zmianą było zastąpienie biblioteki SDL_image biblioteką DevIL, która jest po prostu wygodniejsza w użyciu. Miałem z nią pewne problemy ale jak się później okazało wynikały z tego, że kilka innych rzeczy też nie działały jak powinny. Dodałem także kilka wersji funkcji CreateTexture() która pozwala ładować tekstury z plików graficznych, z pamięci, z wirtualnego systemu plików oraz po prostu tworzyć pustą białą teksturę o podanych rozmiarach. Jeśli chodzi o ostatnią wersję to jest ona teraz najmniej użyteczna bo nie zrobiłem jeszcze możliwości edycji pikseli tekstury, ale wszystko przed nami ;)

Następną zmianą jaką postaram się wprowadzić będzie wspomniana właśnie edycja tekstury oraz możliwość definiowania, którą część tekstury chcemy wyświetlać na obrazku. Pozwoli to na stworzenie klasy obsługującej sprajty i korzystającej z jednej tekstury. W tej chwili obrazek wyświetla teksturę jako całość i przy takim jej traktowaniu rozdział na teksturę oraz obrazek zupełnie nie ma sensu.

Ostatnią z rzeczy, którą planuję jest zapis aktualnego ekranu do tekstury. Można powiedzieć, że to bedzie renderowanie do tekstury. Oczywiście z tym od razu kojarzy się robienie zrzutów ekranu oraz zapis tekstury do pliku więc i to trzeba będzie zrobić :)





Odpowiedzi

21 09 2008

Ostatnio na blogu Xiona ukazał się post na temat udzielania odpowiedzi na pytania początkujących programistów. Pytania te często wydają się doświadczonym koderom irytujące ze względu na to, że odpowiedź jest dla nich oczywista. Ciśnie się na usta powiedzenie: Zapomniał wół jak cielakiem był…

Nie mam jednak zamiaru zastanawiać się czy lepsza jest odpowiedź krótka i rozwiązująca problem ale nie wyjaśniająca młodemu programiście dlaczego, ani czy lepsza bedzie długa wyczerpująca odpowiedź, której nikt nie przeczyta – bo kto ma na to czas? ;)

Ja zamierzam podzielić się własnymi spostrzezeniami na temat Dobrej Odpowiedzi. W życiu każdego z nas zdarza się odpowiadać na pytania kolegów odnośnie jakiegoś materiału przerabianego w szkole, na studiach czy nawet wyjasnienia o co chodzi w tej cholernej instrukcji obsługi… Jak wiemy niektórzy mają do tłumaczenia wrodzony talent, a inni tłumaczą tak, że nikt nic z tego nie rozumie. Dlaczego?

Podstawą do udzielenia dobrej odpowiedzi na pytanie jest zrozumienie tematu – jest to dość oczywiste. Czasem oczywiście ludzie, którzy nie wiedzą o co chodzi też starają się udzielić odpowiedzi (patrz dział o programowaniu na forum o2.pl).  Jednak zrozumienie tematu przez tłumaczącego jest często niedostateczne - czy raczej dobre na chwilę. Później i tak będzie trzeba stawić czola podobnym pytaniom zadawanym przez tę samą osobę ponieważ nie zrozumie ona skąd wzięła się tamta odpowiedź więc i następnym razem nie będzie w stanie sobie sama odpowiedzieć.

Aby udzielić dobrej odpowiedzi trzeba samemu się wysilić i zrozumieć skąd wzięło się to potencjalnie głupie pytanie. Zadający je przecież na pewno nie chciał aby takie było. Pytanie jest kreowane przez wizję podanego tematu, zatem jeśli ktoś źle nauczy się jakiejś części drabiny wiedzy z danej dziedziny to później mogą się w jego głowie rodzić zagwostki, których nie bedzie w stanie rozwiązać. Z drugiej strony – jeśli spojrzyna to pytanie bardziej doświadczony gość to pomysli, że jest ono durne.

Z poprzedniego akapitu wynika więc, że bardzo możliwe, że wystarczy naprostować tylko sposób myślenia danej osobie tłumacząc jej inne zagadnienie, które zostało błędnie zrozumiane a przez które osoba ta ma błędną wizję tego o co pyta. Stąd trzeba najpierw zadać kilka pytań pomocniczych aby dowiedzieć, się z czego wynika zadane pytanie.

Warto jednak pamietać, że nie zawsze warto tłumaczyć. Przykłądowo, mamy świeże mięcho – młody programista, zaczyna robić jakiś projekt wieloplikowy z kilkoma różnymi klasami w C++. Niech w pliku nagłówkowym umieści definicję jakiejś klasy (używając oczywiście #pragma once lub #ifndef/#endif) zapominając jedynie o średniku po klamrze zamykającej klasę. Po załączeniu takiego nagłówka w jakimś pliku okazuje się, że kompilator wywala błąd w pliku cpp, do którego jest załączony wspomniany nagłówek, a nie powie, że to brak średnika po definicji.

Doświadczony programista od razu wie o co chodzi, a nowicjusz zacznie się zastanawiać co jest źle w linijce wskazanej  przez kompilator. No i w końcu zada pytanie na forum. Odpowiadający może – tak jak napisałem – zdiagnozować problem i udzielić wyjaśnienia bądź odpowiedzieć po prostu, że brakuje średnika. W tym wypadku lepiej jest powiedzieć o braku średnika bo bardzo wątpliwym jest aby młody programista pojął sposób działania kompilatora. (bo to właśnie trzebaby mu wytlumaczyć chcąc aby miał kompletną wizję i rozumiał skąd ten błąd)

Jak widać nadal chodzi o sztukę wyboru mniejszego zła, a przy odpowiadaniu na pytanie problematyczne jest aby zrozumieć skąd ono się wzięło, a nie znalezienie faktycznego rozwiązania.





SDL + OpenGL oraz SDL_GL_SwapBuffers()

16 09 2008

Ostatnio, pisząc AGE, natknąłem się na pewien mały problem wydajnościowy związany z funkcją SDL_GL_SwapBuffers(). Okazało się bowiem, że gdy rysowałem w okienku wszystko było w miarę, ale po przełączeniu do pełnego ekranu kolory były jakieś nienormalne i wydajność spadła do ~70FPS. Przy pustym ekranie…

Po szybkim zastosowaniu metody włączeń i wyłączeń (lub jeśli ktoś woli: zkomenć, odkomenć ;) ) odnalazłem winowajcę – nieszczęsną funkcję podmieniającą bufory. Rozpocząłem więc poszukiwania w internecie i oczywiście wiele było takich problemów, ale wszyscy genialnie radzili wyłączyć synchronizację…
Rozpocząłem się testować z różnymi wartościami przy opcjach ustawień obrazu i po jakiejś chwili odkryłem, ze wina była oczywiście moja. Problematyczne okazały się dwie instrukcje:

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 24);
SDL_SetVideoMode(width, height, 16,
 SDL_OPENGL | SDL_GL_ACCELERATED_VISUAL |
 (full?SDL_FULLSCREEN:0);

Cudownym lekiem okazała się być zmiana z głębi 16 na 24 bity w SDL_SetVideoMode(). FPS od razu wskoczyło na kilka tysięcy, a po narysowaniu kilku obrazków spadło do ~660. Jest więc tak jak być powinno.

Mała rzecz, a tyle może przysporzyć kłopotów…





Mądrości życiowe

14 09 2008

I uczen zapytal Mistrza: “Oto jest programista, ktory nigdy nie
projektuje, nie dokumentuje ani nie testuje swoich programow.
Mimo to kazdy kto go zna, uwaza go za najlepszego programiste
na swiecie. Dlaczego tak jest?”

Mistrz odpowiedzial: “Ten programista poznal Tao. On uniosl sie
ponad potrzebe projektowania; nie gniewa sie gdy system wysiada,
lecz odbiera rzeczywistosc nie oceniajac. On uniosl sie ponad
potrzebe dokumentowania; nie dba czy ktokolwiek bedzie ogladal
jego kod. On uniosl sie ponad potrzebe testowania; kazdy z jego
programow jest doskonaloscia sama w sobie, piekny i elegancki,
a jego funkcje sa oczywiste. Zaprawde, on poznal tajemnice Tao.”

Powyższy cytat pochodzi z Tao Programowania: http://rudy.mif.pg.gda.pl/~bogdro/tao_programowania.txt które pojawiło się na forum.gamedev.pl, a wcześniej na wykopie ;) Całkiem przyjemna lektura – aż chce się coś zakodzić ;)





Pthread na Windows

7 09 2008

Ten post ma na celu przyznanie się do błędu ;)

Otóż niedawno napisałem, że obsługa pthread pod Win32 ma jakieś problemy i wywala błędy. Jest to oczywiście be-zdura! Tzn, nie wiem jak to dokładnie jest bo nie analizowałem całej biblioteki, ale wiem teraz na pewno, że błąd, który pojawiał się u mnie był spowodowany… no właśnie… czym?

Błąd dość ciekawy i początkowo patrząc na niego nawet nie zdawałem sobie sprawy z tego, że to akurat ten kawałek kodu jest winny ;) Kod wyglądał jakoś tak:

SThread st = { this, arg };
pthread_create( &tid, NULL, RunThreadFunc, &st );

No i fajnie, gdzie tu problem?

Wprawni programiści zapewne już wiedzą co się święci. Możliwe, też że mnie wprawni również to widzą :P W gruncie rzeczy nie trzeba mieć nawet wiele wspólnego z kodem…

Chodzi oczywiście o to, że st (którego adres przekazuję jako parametr do nowego wątku) jest niszczone po zakończeniu funkcji, w której powyższy kod jest zawarty. Jednak funkcja pthread_create tworzy nowy wątek, który może zacząć wykonywanie w tym samym czasie, ale najczęściej pewnie tak się nie stanie. Stąd od razu wiadomo dlaczego błąd czasem się pojawiał, a czasem nie. Jeśli nowy wątek zaczął się wykonywać jeszcze przed zakończeniem funkcji, w której został utworzony to wtedy nic się nie działo. Częściej jednak zdarzało się, że zaczynał się później i próbował odczytać adres st, który był już zwolniony.

Dlatego też proszę o wybaczenie urażonych moim postem o ułomności pthreads pod Win32 ;)  

Ciekawostką jest, że w Ubuntu NIGDY mi się nie zdarzyło, aby powstał ten błąd więc widocznie potrafi on znacznie szybciej uruchomić nowo utworzony wątek ^^





AGE VFS

7 09 2008

Ostatnio do AGE dodałem obsługę wirtualnego systemu plików. Zainspirował mnie artykuł Tomasza Dąbrowskiego: http://dabroz.scythe.pl/2008/07/17/wirtualny-system-plikow-vfs .

O ile funkcjonalność jaką oferuje ten “VFS” można podpiąć pod wirtualny system plików. Tak na prawdę chodziło raczej o wrzucenie danych plików do jednego wielkiego pliku. Ogromną zaletą rozwiązań przedstawionych w artykule jest szybkość działania. Potraktowanie nazw plików funkcją hashującą wpływa mocno na prędkość wyszukiwania i dodatkowo sprawia, że wpis w hash-table dla każdego pliku ma taki sam rozmiar. To z kolei pozwala łatwiej stworzyć takie pliki VFS bo nie trzeba zapisywać nazw plików zawartych wewnątrz.

Tutaj jednak pojawia się problem. Nie powoduje on wielkich problemów, ale jednak istnieje i może stać się uciążliwy – z takiego pliku z danymi nie da sie odczytać nazw plików (bo są tam tylko hashe), a to jest pewien problem, jeśli programista pracujący nad projektem zapomni co wrzucił do pliku.

Można ten problem rozwiązać na dwa sposoby:

  1. Dodać na końcu pliku tablicę nazw plików, a na początku informację, gdzie jest nazwa każdego pliku
  2. Utworzyć w programie generującym pliki VFS możliwość zapisu projektu

Rozwiązanie pierwsze pozwala na podgląd jakie pliki są zapisane w systemie, a to z kolei pozwala na ich łatwy eksport z pliku.

Drugie zaś pozostawia plik systemu plików “niedostępnym” oraz pozwala na modyfikowanie systemu plików po prostu przez stworzenie go od nowa z nowymi plikami.

Ja postanowiłem wybrać drugie rozwiązanie i napisałem program AGE-VFS. Narzędzie napisane jest z pomocą wxWidgets więc powinno kompilować się też pod Linuxem (co sprawdzę w pszyszłości ;) ).

Ostatnią fażą dodawania do AGE wirtualnego systemu plików było oczywiście dodanie klas obsługujących wczytywanie i wyszukiwanie danych w pliku. To jednak okazało się być mało pracochłonne.

Ostatecznie postanowiłem sprawdzić jak działa VFS i wczytać jakiegoś WAVe’a. Szybko okazało się, że w moim programie do tworzenia VFS był mały błąd, który skutecznie psuł tworzone pliki ;) Naprawiłem go jednak i w końcu mogę powiedzieć, że AGE potrafi obsługiwać bardzo prosty system plików (o ile można go tak nazwać…)





Garstka nowości

5 09 2008

Odnośnie egzaminów, jeśli kogoś interesuje mój los – niestety nie udało mi się zaliczyć analizy. Udało mi się natomiast zdać egzamin z Algorytmów no i czekam jeszcze na egzamin z Matematyki Dyskretnej.

No to tyle o rzeczach mało fajnych.

Ostatnimi czasy więcej siedzę na Windowsie (pogrywam w UO ;) ) więc postanowiłem wreszcie skompilować AGE pod Windą. Na początek ściągnąłem SDl, SDL_mixer i SDL_image. Przy kompilacji poinformowany zostałem, że grakuje jeszcze Freetype2 i pthread. Zainstalowałem więc i te biblioteki.

Wreszcie projekt się skompilował i wywalił kilka błędów “unresolved external” – zapomniałem załączyć liby ;) Kiedy już ostatecznie wszystko się zlinkowało i na moim dysku powstał plik EXE gotowy do uruchomienia, po prostu go uruchomilem…

Chwilka oczekiwania, ładowanie zasobów, ustawianie okna, bla bla i… błąd. Włączył mi się OllyDbg, który jest moim domyślnym debuggerem w systemie. Zastanowiłem się chwile o co chodzi. I odkryłem – nie skopiowałem zasobów do odpowiedniego folderu ;) Poczyniłem to teraz i po uruchomieniu znów wyskoczył błąd.

Zakomentowałem więc wszystko tak, zebym miał tylko puste czarne okno. Uruchomiło się wreszcie. Później odkomentowałem obsługę klawiatury (ESC ;) ) no i znów się wywalił. Zatem to nie problem zasobów. Nie wierzyłem ten, że to problem z klawiaturą bo tam po prostu nie ma co nie działać ;)

Postanowiłem wreszcie spojrzeć do tego co pokazał OllyDbg… Chwilka oglądania stosu i od razu widać o co chodzi – moduł pthread się wywala.

Jest to chyba jakiś wewnętrzny błąd pthread na Win32 bo w Linuxie nie miałem z tym problemów. Najciekawszym jest to, że czasem się uruchamiał dobrze a czasem wywalał błąd. Tak więc zakomentowałem Timer, który korzystał z wątków i teraz wszystko już działa bez problemów.

Wniosek z tego taki, że niestety ageThread będę musiał w Windowsie napisać osobno. Ech… a tak dobrze korzystało mi się z gotowych bibliotek ;)