Tento seriál bude venovaný programovaniu s použitím knižnice Allegro (vetva 4.2). U čitateľov sa predpokladá znalosť programovania v jazyku C aspoň na mierne pokročilej úrovni, základy C++ a STL, ako aj stredoškolskej geometrie, fyziky a algoritmov.
V tomto seriáli sa pokúsim predstaviť možnosti knižnice Allegro a oboznámiť čitateľov s jej vlastnosťami a možnosťami. Ako programovací jazyk bude zvolený C s využítím niektorých prvkov z C++ (hlavne STL). Všetok kód bude multiplatformový a bude ho možné kompilovať minimálne v systéme GNU/Linux (GCC) a MS Windows (MinGW). Čitateľov vopred upozorňujem, že nebudú spomenuté úplne všetky možnosti knižnice Allegro a taktiež sa nebudú využívať žiadne rozšírenia, ktoré pre knižnicu Allegro existujú. Tempo bude s pribúdajúcimi dielmi pomerne rýchlo narastať.
Motivácia
Knižnica Allegro umožňuje veľmi jednoducho a rýchlo tvoriť multiplatformové aplikácie využívajúce grafiku, zvuky, vstupy z klávesnice a myši bez nutnosti poznať špecifiká jednotlivých operačných systémov. Samotná knižnica je určená na tvorbu hier a keďže každé ľudské snaženie má mať stanovený cieľ, výsledkom tohto seriálu by mala byť hrateľná, hoci pomerne jednoduchá, počítačová hra. Ak máte radi Sokoban, no zdá sa Vám málo akčný a zároveň máte radi Pac-mana, no zdá sa Vám príliš "primitívny", mali by ste byť výsledkom nadšení. Budeme totiž tvoriť ich zjednotenie - hru Packoban.
Samozrejme, knižnica Allegro sa dá využiť aj na íné aplikácie, než hry. Vďaka schopnosti používať framebuffer je vhodná na tvorbu vizualizácii stavu systému pre servery bez X-iek (na to ju často využíva aj autor tohto seriálu) alebo grafických front-endov pre minidistribúcie.
Získanie Allegra
Knižnicu Allegro obsahuje väčšina slušných distribúcií priamo v oficiálnych repozitároch s názvom allegro, prípadne allegro-devel. V prípade, ak si chcete skompilovať vlastnú verziu, môžete navštíviť stránku http://www.allegro.cc/files/, ktorá slúži aj ako komunitný portál, prípadne oficiálnu stránku http://alleg.sourceforge.net/. V čase písania tohto seriálu bola stabilná verzia 4.2.2.
So zdrojovými kódmi získate aj kompletný manuál a viacero užitočných príkladov. Čitateľov dopredu upozorňujem, že príklady uvádzané v tomto seriáli nebudú fungovať s budúcou stabilnou vetvou 5 a vývojovou vetvou 4.9.
Náš prvý program
Aby sme mohli využívať možnosti Allegra v našich programoch, je nutné v zdrojovom kóde načítať hlavičkový súbor allegro.h a pri linkovaní pridať všetky potrebné knižnice. Zdrojový kód by mohol teda vyzerať nasledovne (priklad.cpp
):
#include <allegro.h>
int main(void)
{
}
Kompilácia bude potom vyzerať nasledovne:
g++ -Wall priklad.cpp -o priklad `allegro-config --libs`
Príkaz allegro-config --libs
vráti zoznam knižníc vo formáte pre GCC, ktoré je potrebné použiť pre správne zlinkovanie programu s knižnicou Allegro.
Program sa nám teda podarilo úspešne skompilovať, ale nevyužili sme ešte žiadnu funkciu z Allegra. Pred ich použitím musíme Allegro inicializovať zavolaním funkcie int allegro_init();. Pred ukončením programu je slušné uvoľniť rezervovanú pamäť volaním funkcie (alebo procedúry) void allegro_exit();. Keďže má byť náš program multiplatformový, je potrebné zavolať po ukončení funkcie main
ešte makro END_OF_MAIN(). Informácie o parametroch a návratových hodnotách jednotlivých funkcií nájdete v prehľadne spracovanom manuáli na adrese http://alleg.sourceforge.net/stabledocs/en/allegro.html alebo http://www.allegro.cc/manual/. Jednotlivé cesty sa môžu stať s príchodom novej vetvy neaktuálne, preto som pripravil stabilný obraz na mojom serveri a budem naň smerovať všetky daľsie odkazy.
#include <allegro.h>
#include <cstdio>
int main(void)
{
if(allegro_init()!=0){
fputs("Inicializacia allegra zlyhala!\n",stderr);
return 1;
}
allegro_exit();
return 0;
}
END_OF_MAIN()
Príklad kompilujeme opäť rovnakým príkazom.
Grafický režim
Inicializácia grafického režimu je pomocou Allegra otázkou niekoľkých príkazov. Dôležité je si uvedomiť, že každý operačný systém používa iný spôsob vykresľovania grafiky (alebo aj viac možných spôsobov). Z toho dôvodu obsahuje Allegro "ovládače" pre každý operačný systém. Pri inicializácii si môžete konkrétny ovládač vyžiadať, alebo môžete použiť univerzálneho zástupcu, ktorý bude fungovať na viacerých (alebo dokonca aj všetkých podporovaných) platformách s podobným výsledkom. Zoznam grafikcých ovládačov pre systém GNU/Linux je dostupný na tejto adrese. Pre našu hru budeme používať ovládač GFX_AUTODETECT_WINDOWED
, ktorý na každej platforme podporujúcej okienka vyberie ten najvhodnejší zo všetkých dostupných. Zaujímať nás bude taktiež GFX_TEXT
, ktorý nás vráti nazad do textového režimu, resp. vypne grafický režim a GFX_AUTODETECT
, ktorý skúša vyhľadať najprv vhodný ovládač pre celú obrazovku a my ho použijeme ako zálohu, ak okienkový režim zlyhá.
Grafický režim je špecifikovaný viacerými parametrami. Rozlíšenie určuje počet rôznych bodov (pixelov), ktoré sa naraz dajú výkresliť na obrazovku (do nášho okna). Farebná hĺbka označuje, koľko rôznych farieb vie nadobudnúť jeden pixel. Allegro podporuje maximálne 8 bitov na jeden farebný kanál a režimy 8, 15, 16, 24 a 32 bitové. Farebný model je RGB (teda maximálne 16 777 216 farieb). V našej hre použijeme farebnú hĺbku zhodnú s hĺbkou používateľovho grafického režimu. Tá sa dá zistiť zavolaním funkcie int desktop_color_depth();. Následne ju zadáme Allegru zavolaním funkcie void set_color_depth(int depth);. Samotný grafický režim sa inicializuje zavolaním int set_gfx_mode(int card, int w, int h, int v_w, int v_h);.
#include <allegro.h>
#include <cstdio>
#define RES_W 800
#define RES_H 600
int main(void)
{
if(allegro_init()!=0){
fputs("Inicializacia allegra zlyhala!\n",stderr);
return 1;
}
int depth=0;
if((depth=desktop_color_depth())==0){
depth=32;
}
if(depth<16){
fputs("Je potrebna aspon 16-bitova farebna hlbka!\n",stderr);
return 2;
}
set_color_depth(depth);
if(set_gfx_mode(GFX_AUTODETECT_WINDOWED,RES_W,RES_H,0,0)!=0){
if(set_gfx_mode(GFX_AUTODETECT,RES_W,RES_H,0,0)!=0){
fputs("Nepodarilo sa inicializovat graficky rezim!\n",stderr);
return 3;
}
}
set_gfx_mode(GFX_TEXT,0,0,0,0);
allegro_exit();
return 0;
}
END_OF_MAIN()
Máme okno
Predchádzajúci príklad nám (pokiaľ je to možné) vytvorí okno s vnútornými rozmermi RES_W x RES_H
. V jeho nadpise bude ale názov binárky. Vlastný názov môžeme nastaviť pomocou funkcie void set_window_title(const char *name); ešte pred samotnou inicializáciou grafického režimu. Ďalšou zaujímavou možnosťou je zatvorenie aplikácie kliknutím na príslušné tlačidlo (často s krížikom). Na to použijeme funkciu int set_close_button_callback(void (*proc)(void));, ktorá nam umožňuje definovať si vlastnú funkciu zavolanú pri kliknutí na tlačidlo. Tú je dobré chrániť pred prerušením. Na to slúži dvojica makier LOCK_FUNCTION(function_name); a END_OF_FUNCTION(function_name);.
Ďalšou funkciou, ktorú využijeme, je void rest(unsigned int time);. Jej úlohou je ukončiť program na zadaný počet milisekúnd. Na to, aby mohla správne fungovať, je potrebné inicializovať časovače knižnice Allegro zavolaním funkcie int install_timer();. Keďže počet inicializovaných vecí nám narastá, je dobré si definovať funkciu, ktorú môžeme zavolať pri ukončení programu (či už normálnom alebo chybovom), ktorá po nás uprace a podľa potreby aj zobrazí chybové hlásenie. Na to môžeme využiť funkciu void allegro_message(const char *text_format, ...);, ktorá podľa platformy vypíše hlásenie na konzolu alebo zobrazí grafické informačné dialógové okno.
#include <allegro.h>
#include <cstdio>
#define RES_W 800
#define RES_H 600
volatile int close_button_pressed = FALSE;
void close_button_handler(void)
{
close_button_pressed = TRUE;
}
END_OF_FUNCTION(close_button_handler)
void main_koniec(int ret,const char *str)
{
set_gfx_mode(GFX_TEXT,0,0,0,0);
if(ret>0){
allegro_message("CHYBA %d: %s\n",ret,str);
}
allegro_exit();
exit(ret);
}
void main_koniec(void)
{
main_koniec(0,"");
}
void main_koniec(int ret)
{
main_koniec(ret,"Neznama chyba");
}
int main(void)
{
if(allegro_init()!=0){
fputs("Inicializacia allegra zlyhala!\n",stderr);
return 1;
}
if(install_timer()!=0){
fputs("Inicializacia timeru zlyhala!\n",stderr);
return 1;
}
int depth=0;
if((depth=desktop_color_depth())==0){
depth=32;
}
if(depth<16){
main_koniec(2,"Je potrebna aspon 16-bitova farebna hlbka!");
}
LOCK_FUNCTION(close_button_handler);
set_close_button_callback(close_button_handler);
set_window_title("Packoban");
set_color_depth(depth);
if(set_gfx_mode(GFX_AUTODETECT_WINDOWED,RES_W,RES_H,0,0)!=0){
if(set_gfx_mode(GFX_AUTODETECT,RES_W,RES_H,0,0)!=0){
main_koniec(3,"Nepodarilo sa inicializovat graficky rezim!");
}
}
while(!close_button_pressed){
rest(10);
}
main_koniec();
return 0;
}
END_OF_MAIN()
Získali sme základ, s ktorým budeme pracovať v ďalších dieloch tohto seriálu. Najbližšie si ukážeme základnú prácu s grafikou, vykresľovanie geometrických tvarov a načítavanie a ukladanie obrázkov do súborov.
prosil by som niekoho kto sa vyzna ci by mi vedel pomoct s jednou vecou..
ňv mojom projekte pouzivam kniznicu allegpng na nacitanie png obrazkov. pouzivam pri tom nacitanie obrazka ktory je priehliadny.. teda nema podkladovu vrstvu.. problem je ze neviem tento obrazok zvecsit bez toho aby som neprisiel o prehliadnost. tu je kod ktory pouzivam teraz:
// the centre point
int xc = w()/2;
int yc = h()/2;
// the radius of the clock
int r = MIN(xc, yc);
BITMAP *bm_ico;
char *ms = new char [aloclong];
strcpy(ms, ICONPATH""SEP);
strcat(ms, Name);
// if the clock has focus, fill the tick with green
if (HasFocus()) {
strcat(ms, "_big.png");
bm_ico = load_tgabmppcxpng_bitmap(ms);
//draw_scaled_image_to_screen(canvas, xc-bm_ico->w/2, yc-bm_ico->h/2, bm_ico->w, bm_ico->h, "Setup/datafiles/users/mycomp.png");
//rect(canvas, 0, 0, w()/2, h()/2, Color::black);
set_alpha_blender();
draw_trans_sprite(canvas, bm_ico, xc-bm_ico->w/2, yc-bm_ico->h/2);
show_text_under_image(canvas, 2, 2, Color::black, Text);
} else {
strcat(ms, ".png");
bm_ico = load_tgabmppcxpng_bitmap(ms);
//draw_scaled_image_to_screen(canvas, xc-bm_ico->w/2, yc-bm_ico->h/2, bm_ico->w, bm_ico->h, "Setup/datafiles/users/mycomp.png");
//rect(canvas, 0, 0, w()/2, h()/2, Color::black);
set_alpha_blender();
draw_trans_sprite(canvas, bm_ico, xc-bm_ico->w/2, yc-bm_ico->h/2);
}
destroy_bitmap(bm_ico);
delete [] ms;
Teda pouzivam klasicky draw_trans_sprite...... ale tento nezvecsuje..
Tu je cely moj projekt.. momentalne ide len pod linuxom.. v blizkej buducnosti port na freedos.
www.skywaker.7crows.net/ampire8x/afree.tgz