Posts from 2009

Powtórka z DirectX

2009-10-29 20:58

Za sprawą przedmiotu o nazwie Grafika Komputerowa 3D musiałem ostatnio przypomnieć sobie, jak tak naprawdę i w praktyce koduje się w DirectX. Pewnie brzmi to dziwnie, ale w rzeczywistości przez ładnych kilka miesięcy nie pisałem większych ilości kodu, który by z tej biblioteki korzystał.

GK3D - screen
Piękna scena ;-)

Projekt, który musiałem teraz napisać, nie był ani trochę ambitny, bo polegał li tylko na wyświetleniu zupełnie statycznej sceny z kilkoma modelami, oświetleniu jej i zapewnieniu możliwości poruszania się w stylu strzelanek FPP. Oczywiście nie było też mowy o żadnych shaderach.

Niby banalne, ale jednak rzecz zajęła mi w sumie jakieś cztery znormalizowane wieczory (czyli od 3 do 4 godzin każdy). Częściowo było tak pewnie dlatego, że pokusiłem się jeszcze o teksturowanie, możliwość regulacji paru opcji renderowania czy bardzo, bardzo prosty menedżer sceny – czytaj: drzewko obiektów + stos macierzy ;)
Wydaje mi się jednak, że ważniejszą przyczyną był nieszczęsny fixed pipeline, którego byłem zmuszony używać. Jeszcze kilka lat temu nigdy bym nie przypuszczał, że to powiem, ale… shadery są po prostu łatwiejsze w użyciu. Porównując chociażby trywialne mieszanie koloru diffuse wierzchołka z teksturą przy użyciu pixel shadera:

  1. psOut.color = psIn.diffuse * tex2D(tex0, psIn.Tex0)

oraz stanów urządzenia:

  1. device->SetTextureStageState (0, D3DTSS_COLORARG1, D3DTA_CURRENT);
  2. device->SetTextureStageState (0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
  3. device->SetTextureStageState (0, D3DTSS_COLOROP, D3DTOP_MODULATE);

nietrudno jest ocenić, w której znacznie lepiej widać, co faktycznie dzieje się z kolorem piksela. No, chyba że dla kogoś multum stałych w rodzaju D3DABC_SOMESTRANGEOPTION jest czytelniejsze niż po prostu mnożenie ;P

Inną sprawą jest też to, że w DirectX napisanie aplikacji od podstaw jest stosunkowo pracochłonne. Brak “złych” funkcji typu glVertex* ma rzecz jasna swoje zalety, lecz jest też jednym z powodów, dla których tak opłaca się posiadanie własnego frameworka, a może nawet i – tfu tfu – silnika ;-)

Pola i akcesory wewnątrz klasy

2009-10-26 23:53

Zgodnie z zasadami programowania obiektowego pola klas nie powinny być bezpośrednio dostępne na zewnątrz. Należy jest zawsze opakowywać w akcesory: właściwości lub krótkie metody typu get i set. Z nich właśnie korzysta potem kod zewnętrzny, dzięki czemu nie może on (w dobrze napisanej klasie) niczego zepsuć poprzez – chociażby – ustawienie jakiegoś pola na nieprzewidzianą wartość.
Taka praktyka jest powszechnie przyjęta i raczej nie budzi wątpliwości. Inaczej jest z używaniem tychże pól lub akcesorów wewnątrz klasy, a więc w jej własnych metodach. Tutaj często mamy wybór: czy odwołać się do “gołego” pola, czy też poprzez odpowiednią właściwość/metodę.

Które podejście jest właściwsze? C#/.NET od wersji 3.0 zdaje się to rozstrzygać, umożliwiając półautomatyczne tworzenie właściwości:

  1. public class SomeClass
  2. {
  3.     public int Foo { get; set; }
  4. }

Nie ma tutaj nie tylko bloków get i set, ale i ukrytą pod tą właściwością pola. Przy korzystaniu z tego feature‘a żadnego dylematu więc nie ma.
Wydaje mi się jednak, że wybór nie jest taki oczywisty i że niekoniecznie należy używać akcesorów wewnątrz klasy. Argumentem przeciw, który od razu przychodzi do głowy, jest troska o wydajność – zwykle jednak przesadzona, bo proste gettery i settery są bez problemu rozwijane w miejscu użycia. Drugim ‘ale’ jest wygląd kodu w językach bez właściwości; zwłaszcza dotyczy to Javy, w której odpowiednik C#-owego:

  1. Foo.Bar.Baz.Qux.Thud = 5;

roiłby się od getów. W końcu można by się jeszcze pokusić o uzasadnienie na wpół merytoryczne: skoro bądź co bądź prywatne pole jest składnikiem klasy do jej wyłącznej dyspozycji, to dlaczego metody miałyby obchodzić je dokoła zamiast odwoływać się doń bezpośrednio? A może jednak lepiej jest skorzystać z tej dodatkowej warstwy pośredniczącej (mogącej np. wykrywać jakieś błędy)?…

Na razie – mimo całkiem przyzwoitego doświadczenia w programowaniu w językach wszelakich – trudno jest mi na te pytania odpowiedzieć. Ostatnio aczkolwiek skłaniam się ku bezpośredniemu dostępowi do pól w metodach klas. Chętnie poznałbym jednak opinie innych koderów na ten temat.

Tags: , , , , ,
Author: Xion, posted under Programming » 3 comments

Jak naprawić GRUB-a

2009-10-24 23:38

"Logo" GRUB-aJeśli oprócz systemu okienkowego rodem z Microsoftu mamy też jakiegoś *niksa, to reinstalacja Windows będzie dla nas miała jeden nieprzyjemny efekt uboczny. Otóż instalatory Okienek radośnie nadpisują sektor startowy dysku (czyli MBR – Master Boot Sector), przez co Windows staje się jedynym systemem dającym się uruchomić w zwykły sposób. Ot, zwyczajowe MS-owe praktyki monopolistyczne ;-)

Jak temu zaradzić? Trzeba oczywiście przywrócić boot sector do właściwego stanu, co oznacza ponowne zainstalowanie używanego przez nas wcześniej bootloadera. W większości przypadków (jeśli mówimy o Linuksie jako drugim systemie) jest nim GRUB; w takim wypadku jego ponowne zainstalowanie wymaga:

  1. Uruchomienia Linuksa przy użyciu płytki typu LiveCD, dystrybucji uruchamianej z pendrive‘a, itp. Graficzny interfejs jest niepotrzebny, bo jak to zwykle w Linuksie, wszystko można zrobić z konsoli.
  2. Następnie należy uruchomić GRUB-a – koniecznie z prawami roota, a więc np. poprzez sudo grub.
  3. Z poziomu jego wiersza poleceń należy najpierw ustawić partycję, w której znajdują się pliki z danymi bootloadera. Jeśli nie wiemy, która to, najlepiej użyć polecenia find /boot/grub/stage1. Potem rezultat przekazujemy do komendy root, np. root (hd0,5).
  4. Na koniec komendą setup instalujemy GRUB-a na wybranym dysku fizycznym – zazwyczaj jest to setup (hd0).

Tyle powinno wystarczyć, by po ponownym uruchomieniu komputera z tego dysku pojawiło się nam menu bootowania GRUB-a. Przy odrobinie szczęścia oba systemy będą więc uruchamiały się normalnie ;)

Tags: , , , ,
Author: Xion, posted under Applications » 10 comments

Operacja reinstalacja

2009-10-23 19:02

Wczorajsza premiera Windows 7 to dobry pretekst, żeby nowy system w końcu przetestować – zwłaszcza, że większość opinii, których o nim słyszałem, była zdecydowanie przychylna. W połączeniu z faktem, iż system operacyjny na moim laptopie już od dobrych paru miesięcy domaga się skrócenia swoich cierpień, otrzymujemy tylko jeden logiczny wniosek: czas zakasać rękawy i zabrać się za reinstalację!

Ktokolwiek choć raz zajmował się ponownym stawianiem systemu od zera wie, że czynność ta nie należy do relaksujących. Chociaż drobne komplikacje są praktycznie gwarantowane: a to zapomnimy o jakimś sterowniku, a to zapodziejemy gdzieś numer seryjny systemu, i tak dalej. Posiadanie komputera “zapasowego” (w moim przypadku tradycyjnego – stacjonarnego) znacznie redukuje dolegliwość takich problemów, ale nawet i w tej sytuacji warto się do całej operacji dobrze przygotować.
I właśnie dlatego sporządziłem poniższą listę kontrolną czynności, które dobrze jest wykonać przed rozpoczęciem zabawy w reinstalację systemu. Nie gwarantuję oczywiście, że da się przy jej użyciu uniknąć wszelkich kłopotów. Powinna być ona jednak w dużym stopniu pomocna. A wygląda ona następująco:

  1. Zrób kopie zapasowe. Jest to oczywiste, a jednocześnie na tyle ważne, że warto o tym wspomnieć na początku. Niestety we współczesnych systemach dane, które chciałoby się zachować, prawie nigdy nie znajdują się w jednym miejscu. Dlatego właśnie można niemal zagwarantować, że przy robieniu przedinstalacyjnego backupu uda nam się coś pominąć.
    Żeby zminimalizować prawdopodobieństwo tego zdarzenia, warto do robienia kopii podejść dwojako:

    • Najpierw pomyślmy, co chcemy zachować. Edytowane dokumenty czy pisane programy są pewnie najważniejsze, ale to zdecydowanie nie wszystko. Co z ustawieniami używanych przez nas programów? Ulubionymi łączami w przeglądarce? Ciastkami (cookies)? Zapisanymi stanami gier (save‘ami)? Co z wszelkiego rodzaju przydatnymi materiałami, które kiedyś ściągnęliśmy nie wiadomo skąd i które jeszcze mogą się przydać? O różnego typu multimediach (muzyka, filmy) też nie wypadałoby zapomnieć. W sumie więc lista robi się całkiem pokaźna i pewnie każdy jeszcze mógłby coś na nią wpisać.
    • Następnie upewnijmy się, że o niczym nie zapomnieliśmy, przeglądając typowe miejsca, w których mogły się ukryć przydatne pliki. Moje dokumenty czy katalog /home będą pierwszym przystankiem. Potem warto odwiedzić Program Files (tudzież /usr/bin itp.) w poszukiwaniu aplikacji, których katalogi mogą zawierać ustawienia do skopiowania. W końcu warto spojrzeć do głównego katalogu dysku, do folderu z plikami ściąganymi z sieci, a w końcu na… Pulpit. Zwłaszcza jeśli tego ostatniego dawno nie sprzątaliśmy ;)
  2. Sprawdź, czy masz pod ręką odpowiednie płyty z systemami operacyjnymi. Celowo użyłem tu liczby mnogiej, bowiem nierzadko w grę wchodzi tutaj więcej niż jeden system. W szczególności chodzi więc tutaj o:
    • dysk z systemem, który będziemy instalować – dość oczywiste :)
    • dysk z systemem, którego aktualnie używamy – jeśli jest on inny niż ten instalowany, dobrze jest mieć na wszelki wypadek możliwość powrotu, gdyby up/downgrade okazał się porażką
    • dyski od pozostałych systemów, których używamy – jak chociażby LiveCD jakiegoś Linuksa, jeśli zdarza nam się mieć takowego

    Pamiętaj też o wszelkich kluczach produktów czy numerach seryjnych, jeśli któryś z systemów ich wymaga.

  3. Wyciągnij na wierzch dyski ze sterownikami do urządzeń, których używa twój komputer. Większość z nich pewnie będzie działała od razu, ale i tak warto mieć płytki pod ręką. Alternatywnie możemy zaufać sieci i stamtąd zaopatrzyć się w drivery – upewnijmy się jednak wpierw, że posiadamy sterowniki do modemu :)
  4. Przygotuj też wersje instalacyjne dużych programów, których używasz do pracy. Chodzi tu o takie rzeczy jak pakiet biurowy, środowisko programistyczne (wraz z wszystkimi SDK-ami!), program graficzny, itp. Nawet jeśli można się w nie zaopatrzyć poprzez sieć, dobrze jest mieć je nagrane na nośnikach DVD/CD.
  5. Nie zapomnij o programie antywirusowym i firewallu. Nie ma co, rzecz jasna, wierzyć przeróżnym badaniom stwierdzającym, że niezabezpieczony komputer podłączony do Internetu już po kilku minutach złapie megabajty wszelkiego rodzaju złośliwych programów. Nawet w przypadku Windows standardowy Windows Defender na początek w zupełności wystarczy. Tym niemniej warto w miarę szybko wyposażyć nowy system w aplikacje zabezpieczające.
  6. Zaopatrz się w listę małych programów, których używasz. Zachowywanie ich wersji instalacyjnej zwykle nie ma sensu, ale dobrze jest mieć przynajmniej ich nazwy, aby dało się je szybko odnaleźć w sieci i zainstalować na nowym systemie.
  7. Znajdź sobie jakieś zajęcie na czas instalacji systemu i większych programów; to może długo potrwać. Niewątpliwym utrudnieniem będzie tu oczywiście fakt, że zajęcie to nie może wymagać komputera ;-) (No, chyba że masz zapasowy :]). Tym niemniej przez te parę godzin warto skupić się na czymś bardziej produktywnym niż obserwowanie paska postępu.

Uff, spora ta lista. Jej rygorystyczne przestrzeganie może nie zawsze jest konieczne, ale nie wydaje mi się, żeby mogło komukolwiek zaszkodzić :) Akurat w przypadku tej nieczęsto (i coraz rzadziej) wykonywanej czynności, jaką jest reinstalacja systemu, zbytnia przezorność na pewno nie zawadzi.

Lepszy pasek przewijania

2009-10-22 14:41

RockScrollZorientowanie się w dużym pliku z kodem (gdzie przez ‘duży’ rozumiem przynajmniej taki, który przekracza tysiąc linii) może niekiedy przysparzać kłopotów. W IDE są oczywiście narzędzia nawigacyjne, pozwalające na przejście do poszczególnych klas, metod czy deklaracji, o ile tylko znamy chociaż ich nazwy. Nie zawsze jednak tak jest. Jeśli o danej metodzie pamiętamy tylko to, że “była długa i skomplikowana”, a o jakiejś właściwości jedynie tyle, iż “jest gdzieś wśród parunastu innych deklaracji”, to najpewniej oznacza, że w ich poszukiwaniu będziemy musieli przeglądnąć cały plik od początku do końca.
Chyba że… No właśnie – chyba że dałoby się spojrzeć na kod z daleka, by zobaczyć jego ogólną strukturę. Wiadomo bowiem, że metoda “długa i skomplikowana” będzie miała najpewniej sporą ilość wcięć, a długi ciąg deklaracji, jedna pod drugą, też były łatwy do odróżnienia od innych kawałków kodu. W książce o wiele mówiącej nazwie Czytanie kodu znalazłem kiedyś radę, że do uzyskania takiego ogólnego spojrzenia można wykorzystać edytor tekstu typu Word, pozwalający na podgląd wydruku wielu stron naraz.

O wiele wygodniej byłoby jednak mieć podobną możliwość wprost w IDE. NetBeans posiada namiastkę czegoś takiego, jednak za jej pomocą można tylko szybko stwierdzić, gdzie w kodzie znajdują się błędy kompilacji (pisałem zresztą o tym trochę ponad rok temu). Porządną, wielkoskalową, a w dodatku całkiem funkcjonalną “mapę kodu” da się za to znaleźć w… Visual Studio.
Mówię tu o darmowym pluginie o nazwie RockScroll, będącym zresztą początkowo wewnętrznym narzędziem Microsoftu. Tym, co wtyczka ta robi, jest zastąpienie standardowego pionowego paska przewijania przez szerszy pionowy pasek, pokazujący podgląd aktualnie edytowanego w postaci długiej “miniaturki” z kolorowaną składnią. RockScroll działa przy tym podobnie jak zwyczajny pasek przewijania, a więc pozwala na przejście kliknięciem do wybranego miejsca w pliku. Ponadto potrafi też zaznaczać breakpointy oraz koloruje wszystkie wystąpienia wskazanego (dwukrotnie klikniętego) słowa w danym pliku – całkiem przydatne. Jedynym mankamentem jest chyba tylko brak wsparcia dla zwijanych i rozwijanych regionów kodu oraz ewentualnie fakt, że w poziomie plugin zajmuje jakieś cztery razy więcej miejsca niż standardowy pasek przewijania. Na szerokoekranowych monitorach ciężko jednak uznać to za wadę :)

Tags: ,
Author: Xion, posted under Applications, Programming » 10 comments

W matematyce jest odwrotnie

2009-10-19 23:53

Współrzędne biegunoweW pewnych sprawach kiedyś występowała alternatywa dwóch równoważnych możliwości i trzeba było w końcu zdecydować się na wybór jednej z nich. Matematycy często ustalają w ten sposób coś “dla porządku” lub dla tzw. ustalenia uwagi. Jak na ironię zauważyłem jednak, że zwykle to właśnie w matematyce niektóre powszechnie obowiązujące umowy wcale nie wprowadzają porządku, gdyż są dokładnie odwrotne względem intuicji lub codziennego doświadczenia. Oto przykłady:

  • Kąty w kartezjańskim układzie współrzędnych na płaszczyźnie – ze szczególnym uwzględnieniem współrzędnych biegunowych – są tak określone, że większe ich wartości oznaczają coraz większe przesunięcie w kierunku przeciwnym do ruchu wskazówek zegara.
  • Tzw. główna przekątna macierzy przy jej zwykłej reprezentacji tablicowej obejmuje komórki od lewego górnego do prawego dolnego rogu. Linia, która jest pochylona w ten sposób, przypomina znak backslash :)
  • Wykres funkcji wypukłej
    Ta funkcja jest wypukła :)

    Funkcje rzeczywiste nazywane wypukłymi narysowane w postaci wykresu przyjmują postać krzywej wygiętej do dołu, co sugeruje nazywać je raczej… wklęsłymi (obrazuje to rysunek po prawej).

  • Tradycyjnie wektory w matematyce zapisuje się jako kolumnowe (czyli macierze n \times 1), a nie wierszowe (1 \times n). To niby nic specjalnego, ale skutek “uboczny” jest taki, że macierze przekształceń (obrotu, translacji, itp.) w stosunku do takich wektorów należy aplikować w kolejności odwrotnej względem rzeczywistej kolejności transformacji, którą chcemy uzyskać (kiedyś już pisałem więcej na ten temat).

Na pewno nie są to wszystkie przypadki podobnych “niefortunnych” rozstrzygnięć; z pewnością dałoby się znaleźć ich więcej. Na pewno też każdy z nich daje się w zadowalający sposób uzasadnić (jak chociażby przekątną macierzy – jest ona po prostu definiowana przez te komórki, których numer wiersza jest równy numerowi kolumny). I paradoksalnie to właśnie jest w nich najgorsze: nie da się z nimi nic zrobić, jak tylko zwyczajnie zapamiętać :)

Tags: , ,
Author: Xion, posted under Math » 7 comments

Ściąga z modyfikatorów dostępu

2009-10-16 16:08

W prawie wszystkich językach obiektowych istnieją tak zwane specyfikatory dostępu, przykładem których jest choćby public czy private. Pozwalają one ustalać, jak szeroko dostępne są poszczególne składniki klas w stosunku do reszty kodu. Modyfikatory te występują m.in. w trzech najpopularniejszych, kompilowalnych językach obiektowych: C++, C# i Javie.

Problem polega na tym, że w każdym z nich działają one inaczej. Mało tego: każdy z tych języków posiada inny zbiór tego rodzaju modyfikatorów. Dla kogoś, komu zdarza się pisać regularnie w przynajmniej dwóch spośród nich, może to być przyczyną pomyłek i nieporozumień.
Dlatego też przygotowałem prostą ściągawkę w postaci tabelki, którą prezentuję poniżej. Symbol języka występujący w komórce oznacza tutaj, że dany modyfikator (z wiersza) powoduje widoczność składnika klasy w określonym miejscu (z kolumny).

Specyfikator Klasa Podklasa Pakiet Reszta
public C++ C# Java C++ C# Java C# Java C++ C# Java
protected C++ C# Java C++ C# Java Java
protected internal C# C# C#
internal C# Java C# Java
private C++ C# Java

Parę uwag gwoli ścisłości:

  • Znaczek C++ nie występuje w kolumnie Pakiet nawet dla modyfikatora public, jako że w tym języku w ogóle nie istnieje pojęcie pakietu.
  • Sam termin ‘pakiet’ jest poza tym właściwy dla Javy. W .NET (C#) jego odpowiednikiem jest assembly, jakby ktoś nie wiedział :)
  • Z kolei internal jest słowem specyficznym dla C#, a jego ekwiwalentem w Javie jest po prostu pominięcie modyfikatora w deklaracji (np. int x; zamiast internal int x;).
  • W końcu, protected internal jest modyfikatorem występującym wyłącznie w C#/.NET.
Tags: , , , , , ,
Author: Xion, posted under Programming » 10 comments
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.