Java, SWT i uruchomienie z pliku JAR (Ubuntu i Windows)

Pokombinowałem troche, poczytałem fora internetowe poczytałem różne artykuły na temat tego w jaki sposób uruchomić stworzony przez Eclipse plik JAR.

Wszystko na marnę.

Dziś rano jednak pomyślałem, że musi być jakieś prostsze rozwiązanie - bo widziałem jedno które miało 10k kroków, a wyjaśnione było tak, że zgubiłem się już po drugim.

Ubuntu

Moim problemem w Linuxie było to, że nie java.library.path nie zawierała ścieżki do Java Native Interface (JNI) zatem wystarczyło tylko dodać do polecenia uruchomieniowego jedną rzecz:

java -Djava.library.path=/usr/lib/jni helloworld.jar

Takie wklepywanie jest jednak uciążliwe, a przy uruchamianiu aplikacji przez dwuklik na ikonie - wręcz niemożliwe. Dlateg - jak zawsze - można (nawet trzeba) to sobie uprościć.

Okazuje się, że wystarczy ustawić zmienną LD_LIBRARY_PATH tak aby zawierała wspomnianą ścieżkę /usr/lib/jni.

“Wystarczy” to za mało. W ubuntu niełatwo jest ustawić tę zmienną - nie potrafię wyjaśnić dlaczego tak jest bo sam tego nie wiem. Wiem natomiast, że zadziałało utworzenie w katalogu użytkownika pliku .bashrc i wpisanie do niego nastepującej treści pomogło:

LD_LIBRARY_PATH="${LD_LIBRARY_PATH}":/usr/lib/jni
export LD_LIBRARY_PATH

Od teraz po wykonaniu polecenia env w liście zmiennych widać LD_LIBRARY_PATH ustawioną w odpowiedni sposób.

Windows

W windowsie z kolei wszystko “prawie” działa. Problemem nie są dzielone biblioteki tylko brak pewnych rzeczy w pliku jar z programem. U mnie objawiało się to okienkiem informującym mnie, że nie można znaleźć głównej klasy do uruchomienia czy coś w ten deseń. Tak czy inaczej - nie to było problemem.

Po wyeksportowaniu programu z Eclipse do pliku *.jar i otworzeniu go w jakimś WinZIPie czy innym programie do rozpakowywania znajduje się tam kadalog META-INF, pliki .classpath i .project oraz pliki *.class (u mnie był jeden - Main.class). Te pliki nie są interesujące. Bardziej ciekawe jest to co dzieje się w katalogu META-INF. Jest tam plik MANIFEST.MF.

Otworzyłem MANIFEST.MF i moim oczom ukazało się coś takiego:

Manifest-Version: 1.0
Main-Class: Main

Wpadłem więc na pomysł, aby ściągnąć z www.eclipse.org/swt wersję SWT dla Windows i ze ściągniętego ZIPa wydostać plik swt.jar. Później wystarczy wrzucić go do naszego pliku *.jar, który chcemy uruchomić (do głównego “katalogu” - tam gdzie pliki *.class) i dodać do pliku MANIFEST.MF jedna linię:

Class-Path: swt.jar ./

I tyle wystarczy. Po tym zabiegu wystarczyło tylko dwa razy kliknąć na plik *.jar i uruchamiało się okienko o które chodziło.

Java

Obudziłem się dziś rano i postanowiłem… pouczyć się Javy ;)

Jak dotąd skutecznie omijałem ten język wszelkimi sposobami ale w końcu i tak się go nauczę gdyż będę miał o nim zajęcia w ciągu nastepnego roku. Uznałem, że lepiej samemu trochę już zaznajomić się z nim ponieważ później w galopie może być ciężko…

Od rana pokombinowałem trochę z aplikacjami konsolowymi pokroju Hello World, ale szybko mi się znudziły. Teraz rzuciłem się na GUI i realizuję je za pomocą SWT.  Kod piszę używając Eclipse w Ubuntu 8.

O ile CTRL+F11 działa bezproblemowo o tyle nie potrafię zmusić go do stworzenia pliku JAR z którego da się odpalić bezproblemowo mojego programu z okienkiem.

Trzeba nad tym trochę popracować :)

Konsola AGE

Konsola do AGE wreszcie skończona. Na początek zmagałem się z obsługą wyświetlania, dodawania linii i opcjami takimi jak “przewijanie” konsoli i czyszczenie ekranu konsoli. Następnym krokiem było wprowadzanie komend do konsoli. Tutaj na początku wydawało mi się to bardzo trudne ze względu na to że musiałbym sobie sam zakodować obsługę klawisza SHIFT. Tutaj jednak z pomocą przyszedł mi unikod. Można go w SDLu włączyć za pomocą wywołania:

SDL_EnableUNICODE(true);

Wtedy struktura eventu klawiatury otrzymywanego od SDL jest wypełniona dodatkowo o kod wciśniętej kombinacji klawiszy w unikodzie. To bardzo mi pomogło ponieważ po wciśnięciu SHIFT+0 od razu dostałem znak ‘)‘ zatem nie musiałem się już martwić o takie rzeczy.

Później dodałem jeszcze obsługę klawiszy:

  • PageUp, PageDown, Strzałki - dół, góra: przewijanie konsoli
  • Strzałki - prawo, lewo: przesuwanie karetki w prawo/lewo
  • CTRL + prawo/lewo: przesuwanie karetki o całe wyrazy
  • (CTRL +) Backspace/Delete: usuwanie znaków/wyrazów przed i za karetką
  • Home/End: przejście na początek/koniec linii

Możliwe, że w przyszłości dodam jeszcze uzupełnianie komendy za pomocą klawisza TAB.

Końcąwą fazą tworzenia konsoli był jej kluczowy element - dodanie obsługi wpisywanych komend. Rozwiązanie już mialem (z poprzedniej wersji AGE). Teraz wystarczyło prawie skopiować kod i troszkę go przystosować.

Planuję jeszcze dodać wbudowaną komendę help która pokazywałaby pomoc dla komendy podanej jako argument. Oczywiście użytkownik AGE mógłby stworzyć ją sam, ale wtedy miałby z tym więcej pracy. Co o tym sądzicie?

Czcionki w AGE

Dodanie obsługi czcionek TTF do AGE tak aby utrzymać wieloplatformowość małym kosztem wydawało się początkowo trudne. Jednak dzięki bibliotece FreeType2 i Google okazało się to znacznie prostsze niż myślałem.

W tej chwili AGE posiada możliwość wyświetlania tekstu z automatycznym dzieleniem na linie przy pomocy znaku ‘\n’ oraz potrafi obliczyć prostokąt, w którym podany tekst zostałby wyświetlony. Możliwe, że w przyszłości dodam funkcje wyświetlające tekst w danym obszarze z wyrównaniem lub podobne. Przy obecnej implementacji tego wszystkiego dodanie takich funkcji jest dość prostą rzeczą.

Całą zabawę z czcionkami TTF postanowiłem podjąć dlatego, że planuję dodać konsolę, a ciężko byłoby to uczynić bez wyświetlania tekstu, prawda? :)

Niestety po tym jak nauczyłem AGE wyświetlać tekst zdałem sobie sprawę, że trzeba mieć jakąś czcionkę aby wyświetlać tekst konsoli i musi to być czcionka, która bedzie dostępna niezależnie od systemu operacyjnego. Rozważałem instalowanie jakiejś czcionki wraz z biblioteką jednak ten pomysł niezbyt mi się podobał. Postanowiłem więc zrobić najbardziej bezczelną rzecz jaka przyszła mi do głowy - wrzuciłem czcionkę wprost do kodu jako tablicę bajtów. Będzie to niestety kilkadziesiąt kilobajtów więcej dla biblioteki, ale z drugiej strony będę miał pewność, że czcionka będzie zawsze dostępna.

Dzięki tym kilku prostym i czasem spartańskim zabiegom mogę wreszcie rozpocząć kodowanie obsługi konsoli dla AGE :)

Co tam z AGE

Niedawno całkiem miałem nieprzyjemne zdarzenie w wyniku którego utraciłem aktualną na tamten czas wersję AGE. Na szczęście podczas testów pod Windowsem robiłem kopię wszystkich plików źródłowych więc nie muszę zaczynać wszystkiego od nowa. Po wstępnym obejrzeniu kodów “z odzysku” stwierdziłem, ze nie straciłem zbyt wiele więc jest dobrze :)

Ostatnio jednak nie miałem weny do kodzenia więc wykorzystałem czas inaczej. Rozbudowałem trochę dokumentację. Urozmaiciłem ją kilkoma przykładami wykorzystania AGE, a w planach mam jeszcze włączenie w dokumentację krótkiego tutoriala.

To tyle - wreszcie jakaś krótka notka ;)

Napisane w Programowanie. Tagi: . Bez komentarzy

Nowe rzeczy

Projektowanie aplikacji/biblioteki od nowa - jeśli napisało się ją już wcześniej, ma swoje ogromne zalety. Można poprawić wszelkie niedoróbki i usprawnić to co usprawnienia wymagało.

Przykładem takiego usprawnienia jest wreszcie napisany przeze mnie (jednak jeszcze nie do końca) Resource Manager. Zastosowanych kilka reguł OOP-u i już mamy całkiem fajny kawałek kodu, który jednocześnie daje się rozszerzać bez większych problemów.

Aktualnie Resource Manager składa się z dwóch części - menedżera zasobów oraz fabryki zasobów. Fabrykę można uczyć tworzenia nowych zasobów w trakcie działania programu więc programista używający AGE będzie mógł sam dodać nowy typ zasobu w zależności od potrzeb.

Obiekty tworzy się za pomocą linii tekstowych postaci:

{resource type} "{resource name}" "{resource arguments}"

Przy czym: {resource type} jest nazwą typu zasobu (np. texture, sample itp.), {resource name} jest nazwą zasobu używaną do zidentyfikowania go przez Resource Manager’a. Ostatni argument {resource arguments} jest już argumentem zależnym od typu zasobu jaki dodajemy. Przykładowo dla tekstury będzie to tylko ścieżka do obrazka.

Kolejną dobrą wiadomością jest to, że udało mi się zmusić AGE do odtwarzania utworów. Tutaj mamy dwie możliwości:

  • odtwarzanie sampli (w kółko lub pojedyńczo)
  • odtwarzanie całych utworów

O ile odtwarzanie sampli jest raczej prostą sprawą - załadować, włączyć i gra - o tyle utwory są zorganizowane trochę inaczej. Otóż utwory można ładować za pomocą ageMusicPlayer. Ten to również obiekt pozwala wybrać i zacząć odtwarzanie losowego utworu załadowanego do listy lub też odtwarzanie utworu o konkretnym numerze. Opcjonalnie można także ustawić losowanie następnego (innego niż przed chwilą grał) utworku. W ten sposób otrzymujemy coś na kształt MP3 player’a ^^

Klasy od dźwięku wymagają jeszcze drobnych usprawnień i kosmetycznych zmian, ale już potrafią zrobić trochę hałasu :)

To właściwie tyle z rzeczy które ostatnio robiłem. Teraz powinienem dopracować menedżer zasobów oraz odtwarzanie dźwięku, a później… to się jeszcze zobaczy ^^

Napisane w Programowanie. Tagi: . Bez komentarzy

AGE

Niestety nie było mnie stać na wymyślenie jakiegoś ciekawego tytułu notki więc niestety jest jaki jest… Ale nie tytuł jest najważniejszy! Zebraliśmy się tutaj, aby dowiedzieć się czegoś na temat tego co dzieje się z AGE.

Na początek - postanowiłem wreszcie porzucić zestaw GEdit+Makefile na rzecz środowiska Code::Blocks. Na początku w GEdicie było fajnie, ale niestety w miarę jak rozrastał się projekt przestał mi wystarczać taki zestaw ^^

Drugą, równie ważną, sprawą, jest to, że sprawdziłem wczoraj wieczorem (ok - w nocy) czy AGE skompiluje się pod Windowsem. Bałem się, że nie będzie to należało do przyjemnych doświadczeń. Jak się okazało - nie taki diabeł straszny jak go malują :) Najwięcej czasu zajęło mi ściąganie bibliotek SDL oraz Code::Blocks pod windowsa ;) Potem stworzyłem projekt, dodałem pliki z kodem źródłowym i włączyłem kompilację. Wyrzucił kilka warning’ów odnośnie porównywania signed-unsigned, i jeden błąd.

Okazało, się że w użyłem w jednym miejscu nazwy jaka istniała już jako definicja preprocesora w windows.h. Na szczęście poprawienie tego stanu rzeczy nie zajęło więcej niż minutę. Ponowna próba kompilacji i…. udało się :) AGE skompilowało się na Windows z drobnymi poprawkami!

Okazuje się, że decyzja o użyciu SDL+OpenGL była całkiem dobra - przynajmniej względem przenośności kodu. Osiągnąłem całkiem zadowalające efekty dość niskim kosztem.

Ech.. uruchomienie tego samego kodu i zobaczenie go w akcji w 2 systemach sprawia ogromną radochę ;) Polecam wszystkim wypróbowanie ^^

Raport z pola bitwy: AGE

Ostatnio niewiele miewam czasu na programowanie dla siebie więc i postęp prac jest raczej marny. Główna zmiana jaka nastąpiła to pozbycie się GLUT na rzecz SDL do spółki z OpenGL. Postanowiłem wykorzystać jednak SDL ze względu na to, że mam więcej dane z urzędu bez straty wieloplatformowości.

Druga rzecz, o której wypadałoby napisać to dodanie (w końcu) wczytywania tekstur oraz renderowania ich jako obrazków na ekranie. Jak widać na załączonym obrazku (^^) działa ona całkiem dobrze.

W kwestii wydajności - to jest jeszcze do poprawy :) W tej chwili przy rozdzielczości 640×480 renderowanie 500 takich kwadracików spowalnia AGE do ~45 FPS. Nie jest źle, ale sądzę, że może być lepiej - to wymaga głębszej analizy tego co się dzieje podczas rysowania ;)

Następnym moim krokiem będzie dodanie większej ilości obsługiwanych formatów plików. Aktualnie działa tylko BMP, a to nie jest szczyt marzeń ;) Nie wiem jeszcze czym powinienem zająć się dalej - menedżer zasobów czy obsługa dźwięku? Skłaniam się w stronę dźwięku, ale to głównie dlatego, że menedżer zasobów to poważna sprawa, a aktualnie nie chce mi się specjalnie nad tym myśleć :P

Jaką decyzje podjąłem dowiecie się w następnym odcinku… :)

Napisane w Programowanie. Tagi: . Komentarzy: 7 »

AGE pod Linuxa, vol. 2

Mimo iż sądziłem, że nie będę pisał wszystkiego od nowa - rzeczywistość chciała inaczej. Po obejrzeniu tego co miałem napisane stwierdziłem że strasznym bezsensem byłoby używanie tego kodu drugi raz skoro jest napisany jakby moja mama mówiła do mnie za młodu w Pascalu.

Straszliwy i wszechobecny bałagan nakłonił mnie do podzielenia wszystkiego na odpowiednie namespace typu: core, video, io, system… etc. Oczywiście wszystko to zamknięte jest w namespace-u age. Popełniłem także coś co tygryski lubią najbardziej - napisałem własne klasy do obsługi list i do obsługi łańcuchów znaków.

Aktualnie zakodzone i działające rzeczy to:

  • ageString
  • ageList<>
  • ageLog - to jest jeszcze ro rozbudowania
  • i/o klawiatury oraz myszy
  • ageTaskManager oraz ageTask - klasa bazowa dla tasków menu albo samej gry
  • ageVector - do obsługi wektorów
  • ageMatrix - do obsługi macierzy
  • ageRect - reprezentacja prostokąta + kilka funkcji takich jak Intersection czy Union
  • wyświetlanie linii, krzywych, prostokątów oraz zamalowanych prostokątów w różnych kolorach

Następną rzeczą do zrobienia jest wreszcie jakieś ładowanie tekstur, menedżer zasobów i jakaś klasa do wyświetlania obrazków na ekranie ^^. Warto byłoby także dodać jakąś obsługę wyświetlania tekstu.

Z takimi planami na przyszłość muszę jednak poczekać bo nadchodzi kolokwium z Analizy Matematycznej i Systemów Operacyjnych…

AGE pod Linuxa

Jako, że ostatnio korzystam z Ubuntu, a kod z MS VC++2k8 używający DX9 jest średnio chętny do działania w tym środowisku, postanowiłem napisać AGE w pewnym sensie od nowa.

Nie jest to oczywiście takie zupełnie “od nowa” ale czeka mnie dużo pracy, ponieważ chcę na początek pogrupować klasy w jakieś moduły i dodać trochę zalet obiektowości. Dodatkowo mam plan aby kod, który napiszę działał także pod Windows.

Oczywiście wykorzystam do tego celu OpenGL i wątpię abym zrobił możliwość wyboru pomiędzy OpenGL a DX pod Windows - tak jak to jest np. w Irrlichcie. Chcę po prostu wykorzystać to czego się nauczyłem podczas programowania AGE do tego aby zaprogramować je jeszcze raz, tylko że lepiej :)

Pierwsze testy pisania aplikacji OpenGL dla Linuxa mam już za sobą (ech te kolorowe trójkąty :D). Teraz czeka mnie raczej praca bardziej projektowa niż kodowanie, ale postaram się ciągnąć jakoś oba w miarę równolegle aby praca szła szybciej.

Wish me luck ^^