Przyszedł czas na rysowanie własnych figur, czyli prymitywy, obracanie bitmap, oraz alpha blending-czyli półprzezroczystość. Będę opisywał tylko rzeczy nowe-nie ma potrzeby abym się powtarzał. Zaczynajmny więc. : ) Druga aplikacja Prymitywy, alpha blending, obracanie bitmap oraz mały zestaw przydatnych funkcji wyświetlających własnej roboty. Na początku oprócz naszego bufora deklarujemy także bitmapę o jakże oryginalnej nazwie bitmapa. Posłuży nam ona za płótno, na którym będziemy malować nasze prymitywy. Będziemy potrzebowali również dwóch pomocniczych zmiennych: angle oraz alpha, obie najlepiej zmiennoprzecinkowe. Pierwsza z nich będzie pamietała kąt obrotu naszego sprita(na początku najlepiej ją wyzerować), a druga będzie robiła za składową alpha. Cóż to takiego? Otóż alfa to czwarta składowa koloru i oznacza poziom widoczności piksela. 255 to pełna widoczność, 0 to całkowity jej brak. Następnie w funkcji load() tworzymy sobie naszą bitmapkę(proponuję rozmiar 100x100), oraz wyczyścimy ją na różowo(255,0,255), aby przy rysowaniu nie było widać tła. Teraz pokolorujemy ją: circlefill(bitmapa,50,50,45,makecol(200,200,0)); ellipsefill(bitmapa,30,30,15,10,makecol(255,255,255)); circlefill(bitmapa,30,30,5,makecol(0,0,0)); ellipsefill(bitmapa,70,30,15,10,makecol(255,255,255)); circlefill(bitmapa,70,30,5,makecol(0,0,0)); rectfill(bitmapa,30,70,70,80,makecol(255,0,0)); rectfill(bitmapa,10,00,90,15,makecol(0,0,0)); triangle(bitmapa,40,60,60,60,50,35,makecol(180,180,0)); Pojawiają się tu nowe funkcje, więc omówię je: void circlefill(bitmap *bmp, int x, int y, int radius, int color); Rysuje koło. Jako argumenty pobiera bitmapę docelową, współrzędne środka koła, jego promień oraz kolor. void ellipsefill(bitmap *bmp, int x, int y, int rx, int ry, int color); Rysuje wypełnioną elipsę. Jako argumenty pobiera to samo, co circlefill, z tą różnicą, że tu musimy podać dwa promienie: poziomy oraz pionowy. void rectfill(bitmap *bmp, int x1, int y1, int x2, int y2, int color); Rysuje wypełniony prostokąt. Jako argumenty pobiera bitmapę docelową, współrzędne lewego górnego i prawego dolnego wierzchołka oraz kolor. void triangle(bitmap *bmp, int x1, y1, x2, y2, x3, y3, int color); Rysuje wypełniony trójkąt. Jako argumenty przyjmuje bitmapę docelową, współrzędne trzech wierzchołków oraz kolor. Funkcji rysujących prymitywy jest oczywiście wiele więcej, należy ich szukać w dokumentacji(dla niepełnosprawnych link: http://www.allegro.cc/manual/api/drawing-primitives/ ). Przyszedł czas na wyświetlenie naszego obrazka. W tym celu napiszemy sobie kilka pomocniczych funkcji, takich jak:
void draw_centre_sprite(bitmap *dest, BITMAP *sprite, float x, float y); void draw_centre_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, float alpha); void rotate_centre_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle); void rotate_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle, float a); void rotate_centre_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle, float a); Dość łatwo domyślić się co one robią: draw_centre_sprite rysuje sprite tak, aby jego środek wypadł w podanej pozycji(w normalnym draw_sprite w podanej pozycji wypada lewy górny wierzchołek sprita). draw_centre_trans_sprite robi to samo, co draw_centre_sprite, tylko, że wykorzystując alphablending. Następne trzy analogicznie, z tym, że dodatkowo obracają obrazek. void draw_centre_sprite(bitmap *dest, BITMAP *sprite, float x, float y) draw_sprite(dest,sprite,x-sprite->w/2,y-sprite->h/2); Ciało tej funkcji jest chyba dość zrozumiałe-wywołujemy zwykłe draw_sprite odejmując od x połowę szerokości obrazka, a od y połowę wysokości. void draw_centre_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, float alpha) set_trans_blender(255,255,255,alpha); draw_trans_sprite(dest,sprite,x-sprite->w/2,y-sprite->h/2); Tu już pojawia się coś nowego. Funkcja void set_trans_blender(int r, int g, int b, int a) przygotowuje nas do blendingu. My wykorzystujemy alpha-blending, więc zmieniamy tylko alphę. void draw_trans_sprite(bitmap *bmp, BITMAP *sprite, int x, int y); zaś robi to samo co, zwykły draw_sprite, tylko, że wykorzystuje blending. void rotate_centre_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle) rotate_sprite(dest,sprite,x-sprite->w/2,y-sprite->h/2,angle); Ta funkcja jest bardzo podobna do draw_centre_sprite. Jedyne czym się róźni to to, że wykorzystuje nową instrukcję void rotate_sprite(bitmap *bmp, BITMAP *sprite, int x, int y, fixed angle). Jako argumenty pobiera ona dokładnie to samo, co draw_sprite(), z tą różnicą, że dodatkowo potrzebuje kąta obrotu obrazka. Jest on w jednostkach z zakresu 0-255, do tego musi zostać przekonwertowany do allegrowskiego formatu fixed-pomoże nam w tym funkcja fixed itofix(int x) konwertująca inty na fixed. void rotate_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle, float a) temp=create_bitmap(sprite->w*2,sprite->h*2); draw_trans_sprite(dest,temp,x-sprite->w/2,y-sprite->h/2); Ta funkcja jest już bardziej skomplikowana-rysuje nam obrócony obrazek wykorzystując alphablending. Na początku wywołujemy set_trans_blender przygotowując allegro do wykorzystania blendingu, później tworzymy tymczasową bitmapę temp. Następnie tworzymy ją nadając jej rozmiar 2h*2w, gdzie w i h to wymiary naszego sprita, ponieważ obrazek po obróceniu może zmienić
wymiary swojego AABB(axis-aligned bounding box-prostokąta o bokach równoległych do osi opisanego na naszym obrazku). Czyścimy naszą bitmapę na różowo, aby ukryć jej tło, po czym rysujemy na niej nasz obrazek obracając go. Teraz rysujemy naszą tymczasową bitmapkę i usuwamy ją. void rotate_centre_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle, float a) temp=create_bitmap(sprite->w*2,sprite->h*2); draw_trans_sprite(dest,temp,x-sprite->w,y-sprite->h); Ta funkcja od poprzedniej różni się tylko tym, że przy rysowaniu odejmując wymiary obrazka od x i y nie dzielimy ich przez 2. Gotowe. Teraz w końcu narysujemy sobie naszą bitmapkę w kilku wariantach (oczywiście w funkcji draw()). rotate_sprite(bufor,bitmapa,100,100,itofix(angle)); rotate_trans_sprite(bufor,bitmapa,200,100,itofix(angle),alpha); rotate_centre_trans_sprite(bufor,bitmapa,200,100,itofix(-angle),255-alpha); Na początku rysujemy naszą bitmapkę bez żadnych udziwnień-poprostu ją obracamy. Następnie wykorzystujemy naszą funkcję, aby narysować obrazek obrócony wykorzystując alpha-blending. Na końcu rysujemy naszą bitmapę centralnie w podanym miejscu, do tego obracając ją w drugą stronę i wykorzystując odwrotność alphy. W funkcji logic() dodamy możliwość ruszania naszymi obrazkami: if(key[key_left]) angle-=2; if(key[key_right]) angle+=2; if(key[key_up]) alpha+=10; if(key[key_down]) alpha-=10; if(alpha>255) alpha=255; if(alpha<0) alpha=0; Myślę, że nie muszę tego tłumaczyć. Na końcu standardowo sprzątamy po naszym programieusuwamy bitmapy oraz zamykamy allegro. Oto screen z programu i kod:
#include <allegro.h> #pragma comment(lib,"alleg.lib") #define WIDTH 800 #define HEIGHT 600 BITMAP *bufor; BITMAP *bitmapa; float angle=0; float alpha=128; int ticks=0; bool wyjscie; void timerproc() ticks++; void draw_centre_sprite(bitmap *dest, BITMAP *sprite, float x, float y) draw_sprite(dest,sprite,x-sprite->w/2,y-sprite->h/2); void draw_centre_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, float alpha) set_trans_blender(255,255,255,alpha); draw_trans_sprite(dest,sprite,x-sprite->w/2,y-sprite->h/2);
void rotate_centre_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle) rotate_sprite(dest,sprite,x-sprite->w/2,y-sprite->h/2,angle); void rotate_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle, float a) temp=create_bitmap(sprite->h*2,sprite->w*2); draw_trans_sprite(dest,temp,x-sprite->w/2,y-sprite->h/2); void rotate_centre_trans_sprite(bitmap *dest, BITMAP *sprite, float x, float y, fixed angle, float a) temp=create_bitmap(sprite->w*2,sprite->h*2); draw_trans_sprite(dest,temp,x-sprite->w,y-sprite->h); void init() allegro_init(); install_keyboard(); set_color_depth(32); set_gfx_mode(gfx_autodetect_windowed, WIDTH, HEIGHT, 0, 0); install_int(timerproc,30); void load() bufor=create_bitmap(width,height); bitmapa=create_bitmap(100,100); clear_to_color(bitmapa,makecol(255,0,255)); circlefill(bitmapa,50,50,45,makecol(200,200,0)); ellipsefill(bitmapa,30,30,15,10,makecol(255,255,255)); circlefill(bitmapa,30,30,5,makecol(0,0,0)); ellipsefill(bitmapa,70,30,15,10,makecol(255,255,255)); circlefill(bitmapa,70,30,5,makecol(0,0,0)); rectfill(bitmapa,30,70,70,80,makecol(255,0,0)); rectfill(bitmapa,10,00,90,15,makecol(0,0,0)); triangle(bitmapa,40,60,60,60,50,35,makecol(180,180,0)); void draw() clear_to_color(bufor,makecol(0,0,255)); rotate_sprite(bufor,bitmapa,100,100,itofix(angle)); rotate_trans_sprite(bufor,bitmapa,200,100,itofix(angle),alpha); rotate_centre_trans_sprite(bufor,bitmapa,200,100,itofix(-angle),255-alpha); blit(bufor,screen,0,0,0,0,width,height);
void logic() if(key[key_left]) angle-=2; if(key[key_right]) angle+=2; if(key[key_up]) alpha+=10; if(key[key_down]) alpha-=10; if(alpha>255) alpha=255; if(alpha<0) alpha=0; if(key[key_esc]) wyjscie=true; void release() destroy_bitmap(bitmapa); destroy_bitmap(bufor); allegro_exit(); int main() init(); load(); while(!wyjscie) draw(); while(ticks>0) logic(); ticks--; release(); return 0; END_OF_MAIN()