#include #include #include #include typedef struct { float x, y; } point_t; typedef struct { float x1, y1, x2, y2; } rect_t; rect_t rect_clip(const rect_t in, const rect_t clip) { return (rect_t) { in.x1 >= clip.x1 ? in.x1 : clip.x1, in.y1 >= clip.y1 ? in.y1 : clip.y1, in.x2 <= clip.x2 ? in.x2 : clip.x2, in.y2 <= clip.y2 ? in.y2 : clip.y2 }; } typedef struct { point_t pos; float zoom; } camera_t; typedef struct { rect_t rect; point_t focus; camera_t *camera; } view_t; float view_to_camera_space_x(const view_t *const view, const float x) { return (x - view->focus.x) / view->camera->zoom + view->camera->pos.x; } float view_to_camera_space_y(const view_t *const view, const float y) { return (y - view->focus.y) / view->camera->zoom + view->camera->pos.y; } float view_from_camera_space_x(const view_t *const view, const float x) { return (x - view->camera->pos.x) * view->camera->zoom + view->focus.x; } float view_from_camera_space_y(const view_t *const view, const float y) { return (y - view->camera->pos.y) * view->camera->zoom + view->focus.y; } point_t view_point_to_camera_space(const view_t *const view, const point_t point) { return (point_t) { view_to_camera_space_x(view, point.x), view_to_camera_space_y(view, point.y) }; } point_t view_point_from_camera_space(const view_t *const view, const point_t point) { return (point_t) { view_from_camera_space_x(view, point.x), view_from_camera_space_y(view, point.y) }; } rect_t view_rect_to_camera_space(const view_t *const view, const rect_t rect) { return (rect_t) { view_to_camera_space_x(view, rect.x1), view_to_camera_space_y(view, rect.y1), view_to_camera_space_x(view, rect.x2), view_to_camera_space_y(view, rect.y2) }; } rect_t view_rect_from_camera_space(const view_t *const view, const rect_t rect) { return (rect_t) { view_from_camera_space_x(view, rect.x1), view_from_camera_space_y(view, rect.y1), view_from_camera_space_x(view, rect.x2), view_from_camera_space_y(view, rect.y2) }; } void rect_image(BITMAP *const src, const rect_t src_rect, BITMAP *const dest, const rect_t dest_rect) { stretch_blit(src, dest, src_rect.x1, src_rect.y1, src_rect.x2 - src_rect.x1, src_rect.y2 - src_rect.y1, dest_rect.x1, dest_rect.y1, dest_rect.x2 - dest_rect.x1, dest_rect.y2 - dest_rect.y1); /* V3D_f vertices[4] = { {dest_rect.x1, dest_rect.y1, 0, src_rect.x1, src_rect.y1, 0}, {dest_rect.x2, dest_rect.y1, 0, src_rect.x2, src_rect.y1, 0}, {dest_rect.x2, dest_rect.y2, 0, src_rect.x2, src_rect.y2, 0}, {dest_rect.x1, dest_rect.y2, 0, src_rect.x1, src_rect.y2, 0} }; V3D_f *vertex_pointers[4] = {&(vertices[0]), &(vertices[1]), &(vertices[2]), &(vertices[3])}; polygon3d_f(dest, POLYTYPE_ATEX, src, 4, vertex_pointers);*/ } void view_draw(const view_t *const view, BITMAP *bitmap, BITMAP *const image) { rect_t image_rect = {0, 0, image->w, image->h}, view_rect, image_rect_clipped, view_rect_clipped; view_rect = view_rect_from_camera_space(view, image_rect); view_rect_clipped = rect_clip(view_rect, view->rect); image_rect_clipped = view_rect_to_camera_space(view, view_rect_clipped); rect_image(image, image_rect_clipped, bitmap, view_rect_clipped); } int main(void) { const int video_depth = 8, video_w = 640, video_h = 480; camera_t camera; view_t view; BITMAP *image; int redraw = TRUE; int mickeys_x, mickeys_y; PALETTE palette; allegro_init(); install_timer(); install_mouse(); install_keyboard(); view.rect.x1 = 0; view.rect.y1 = 0; view.rect.x2 = video_w - 1; view.rect.y2 = video_h - 1; view.focus.x = (view.rect.x1 + view.rect.x2) / 2; view.focus.y = (view.rect.y1 + view.rect.y2) / 2; view.camera = &camera; camera.pos.x = camera.pos.y = 0; camera.zoom = 1; set_color_depth(video_depth); set_gfx_mode(GFX_AUTODETECT, video_w, video_h, 0, 0); image = load_bitmap("test.bmp", palette); set_palette(palette); show_mouse(screen); camera.pos.x = image->w / 2; camera.pos.y = image->h / 2; if (image) { while (poll_keyboard(), !key[KEY_ESC]) { poll_mouse(); get_mouse_mickeys(&mickeys_x, &mickeys_y); if (mouse_b & 2 && (mickeys_x || mickeys_y)) { camera.pos.x -= mickeys_x; camera.pos.y -= mickeys_y; if (camera.pos.x < 0) camera.pos.x = 0; else if (camera.pos.x > image->w) camera.pos.x = image->w; if (camera.pos.y < 0) camera.pos.y = 0; else if (camera.pos.y > image->h) camera.pos.y = image->h; redraw = TRUE; } if (mouse_z) { if (mouse_z > 0) camera.zoom *= 1 << mouse_z; else camera.zoom /= 1 << ABS(mouse_z); position_mouse_z(0); redraw = TRUE; } if (redraw) { vsync(); scare_mouse(); clear(screen); view_draw(&view, screen, image); unscare_mouse(); redraw = FALSE; } } destroy_bitmap(image); } return EXIT_SUCCESS; } END_OF_MAIN()