/* * Example program for the Allegro library, by Grzegorz Ludorowski. * * This example demonstrates how to use datafiles, various sprite * drawing routines and flicker-free animation. * * Why is the animate() routine coded in that way? As you * probably know, VIDEO RAM is much slower than "normal" * RAM, so it's advisable to reduce VRAM blits to a minimum. * Drawing sprite on the screen (meaning in VRAM) and then * clearing a background for it is not very fast. This example * uses a different method which is much faster, but require a * bit more memory. * * First the buffer is cleared (it's a normal BITMAP), then the * sprite is drawn on it, and when the drawing is finished this * buffer is copied directly to the screen. So the end result is * that there is a single VRAM blit instead of blitting/clearing * the background and drawing a sprite on it. It's a good method * even when you have to restore the background. And of course, * it completely removes any flickering effect. * * When one uses a big (ie. 800x600 background) and draws * something on it, it's wise to use a copy of background * somewhere in memory and restore background using this * "virtual background". When blitting from VRAM in SVGA modes, * it's probably, that drawing routines have to switch banks on * video card. I think, I don't have to remind how slow is it. * * Note that on modern systems, the above isn't true anymore, and * you usually get the best performance by caching all your * animations in video ram and doing only VRAM->VRAM blits, so * there is no more RAM->VRAM transfer at all anymore. And usually, * such transfers can run in parallel on the graphics card's * processor as well, costing virtually no main cpu time at all. * See the exaccel example for an example of this. */ #include #include #include "running.h" #define FRAMES_PER_SECOND 30 /* set up a timer for animation */ volatile int ticks = 0; void ticker(void) { ticks++; } END_OF_FUNCTION(ticker) /* pointer to data file */ DATAFILE *running_data; /* current sprite frame number */ int frame, frame_number = 0; /* pointer to a sprite buffer, where sprite will be drawn */ BITMAP *sprite_buffer; /* a boolean - if true, skip to next part */ int next; void animate(void) { /* Wait for animation timer. */ while (frame > ticks) { /* Avoid a spinlock. */ rest(1); } /* Ideally, instead of using a timer, we would set the monitor refresh rate * to a multiple of the animation speed, and synchronize with the vertical * blank interrupt (vsync) - to get a completely smooth animation. But this * doesn't work on all setups (e.g. in X11 windowed modes), so should only * be used after performing some tests first or letting the user enable it. * Too much for this simple example */ frame++; /* blits sprite buffer to screen */ blit(sprite_buffer, screen, 0, 0, (SCREEN_W - sprite_buffer->w) / 2, (SCREEN_H - sprite_buffer->h) / 2, sprite_buffer->w, sprite_buffer->h); /* clears sprite buffer with color 0 */ clear_bitmap(sprite_buffer); /* if key pressed set a next flag */ if (keypressed()) next = TRUE; else next = FALSE; if (frame_number == 0) play_sample(running_data[SOUND_01].dat, 128, 128, 1000, FALSE); /* increase frame number, or if it's equal 9 (last frame) set it to 0 */ if (frame_number == 9) frame_number = 0; else frame_number++; } int main(int argc, char *argv[]) { char datafile_name[256]; int angle = 0; int x, y; int text_y; int color; if (allegro_init() != 0) return 1; install_keyboard(); install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL); install_timer(); LOCK_FUNCTION(ticker); LOCK_VARIABLE(ticks); install_int_ex(ticker, BPS_TO_TIMER(30)); if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) { if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) != 0) { set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); allegro_message("Unable to set any graphic mode\n%s\n", allegro_error); return 1; } } /* loads datafile and sets user palette saved in datafile */ replace_filename(datafile_name, argv[0], "running.dat", sizeof(datafile_name)); running_data = load_datafile(datafile_name); if (!running_data) { set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); allegro_message("Error loading %s!\n", datafile_name); return 1; } /* select the palette which was loaded from the datafile */ set_palette(running_data[PALETTE_001].dat); /* create and clear a bitmap for sprite buffering, big * enough to hold the diagonal(sqrt(2)) when rotating */ sprite_buffer = create_bitmap((int)(82 * sqrt(2) + 2), (int)(82 * sqrt(2) + 2)); clear_bitmap(sprite_buffer); x = (sprite_buffer->w - 82) / 2; y = (sprite_buffer->h - 82) / 2; color = makecol(0, 80, 0); text_y = SCREEN_H - 10 - text_height(font); frame = ticks; /* write current sprite drawing method */ textout_centre_ex(screen, font, "Press a key for next part...", SCREEN_W / 2, 10, palette_color[1], -1); textout_centre_ex(screen, font, "Using draw_sprite", SCREEN_W / 2, text_y, palette_color[15], -1); do { hline(sprite_buffer, 0, y + 82, sprite_buffer->w - 1, color); draw_sprite(sprite_buffer, running_data[frame_number].dat, x, y); animate(); } while (!next); clear_keybuf(); rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0); textout_centre_ex(screen, font, "Using draw_sprite_h_flip", SCREEN_W / 2, text_y, palette_color[15], -1); do { hline(sprite_buffer, 0, y + 82, sprite_buffer->w - 1, color); draw_sprite_h_flip(sprite_buffer, running_data[frame_number].dat, x, y); animate(); } while (!next); clear_keybuf(); rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0); textout_centre_ex(screen, font, "Using draw_sprite_v_flip", SCREEN_W / 2, text_y, palette_color[15], -1); do { hline(sprite_buffer, 0, y - 1, sprite_buffer->w - 1, color); draw_sprite_v_flip(sprite_buffer, running_data[frame_number].dat, x, y); animate(); } while (!next); clear_keybuf(); rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0); textout_centre_ex(screen, font, "Using draw_sprite_vh_flip", SCREEN_W / 2, text_y, palette_color[15], -1); do { hline(sprite_buffer, 0, y - 1, sprite_buffer->w - 1, color); draw_sprite_vh_flip(sprite_buffer, running_data[frame_number].dat, x, y); animate(); } while (!next); clear_keybuf(); rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0); textout_centre_ex(screen, font, "Now with rotating - pivot_sprite", SCREEN_W / 2, text_y, palette_color[15], -1); do { /* The last argument to pivot_sprite() is a fixed point type, * so I had to use itofix() routine (integer to fixed). */ circle(sprite_buffer, x + 41, y + 41, 47, color); pivot_sprite(sprite_buffer, running_data[frame_number].dat, sprite_buffer->w / 2, sprite_buffer->h / 2, 41, 41, itofix(angle)); animate(); angle -= 4; } while (!next); clear_keybuf(); rectfill(screen, 0, text_y, SCREEN_W, SCREEN_H, 0); textout_centre_ex(screen, font, "Now using pivot_sprite_v_flip", SCREEN_W / 2, text_y, palette_color[15], -1); do { /* The last argument to pivot_sprite_v_flip() is a fixed point type, * so I had to use itofix() routine (integer to fixed). */ circle(sprite_buffer, x + 41, y + 41, 47, color); pivot_sprite_v_flip(sprite_buffer, running_data[frame_number].dat, sprite_buffer->w / 2, sprite_buffer->h / 2, 41, 41, itofix(angle)); animate(); angle += 4; } while (!next); unload_datafile(running_data); destroy_bitmap(sprite_buffer); return 0; } END_OF_MAIN()