123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- #include "draw.h"
- #include "laytext.h"
- #include "dynar.h"
- /** Addinional drawing functions and wrappers for primitive drwaing
- functionality. */
- /** Draws an image on the current target bitmap according to a 9 part scaling
- algorithm. This splits the bitmap in 9 parts, keeps the 4 corners unscaled, but
- scales the 4 edges and the center according to the desired size.
- The 4 corners should be rectangles of identical size corner_w by corner_h in
- the original image. Pass a non-positive number to have the corner sizes
- automatically calculated.
- new_w and new_h are the new dimensions the new image should have.
- This is useful for GUI backgrounds.
- */
- void image_blitscale9(Image * img, int xx, int yy,
- int new_w, int new_h,
- int corner_w, int corner_h) {
- int mid_src_w, mid_src_h, mid_dst_w, mid_dst_h;
- int left_x, right_x, middle_x;
- int dst_y, src_y, part_w;
- int src_w = image_w(img);
- int src_h = image_h(img);
- corner_w = (corner_w > 0) ? (corner_w) : src_w / 16;
- corner_h = (corner_h > 0) ? (corner_h) : src_h / 16;
- CLAMP_MAX(corner_w, corner_w, (new_w / 4));
- CLAMP_MAX(corner_h, corner_h, (new_h / 4));
- mid_src_w = src_w - (corner_w * 2);
- mid_src_h = src_h - (corner_h * 2);
- mid_dst_w = new_w - (corner_w * 2);
- mid_dst_h = new_h - (corner_h * 2);
- // draw top parts first
- left_x = xx; // left side
- right_x = xx + mid_dst_w + corner_w; // right side
- middle_x = xx + corner_w ; // middle
- dst_y = yy; // y is he drawing location for the top 3 draws
- // width of the first corner and middle. the second corner starts here
- part_w = src_w - corner_w;
- // draw, take from the top corner left of the image
- image_drawpart(img, 0, 0, corner_w, corner_h, left_x, dst_y, 0);
- // draw, take from the midle of the image
- image_drawscale(img, corner_w, 0, mid_src_w, corner_h,
- middle_x, dst_y, mid_dst_w, corner_h, 0);
- // draw, take from the right corner of the image
- image_drawpart(img, part_w, 0, corner_w, corner_h, right_x, dst_y, 0);
- // now shift down, mutatis mutandis.
- dst_y = yy + corner_h;
- src_y = corner_h;
- // NOTE the middle left and right must be scaled, unlike the corners
- // that must be copied as they are.
- // draw, take from the middle corner left of the image, stretch vertically
- image_drawscale(img, 0, src_y, corner_w , mid_src_h,
- left_x, dst_y, corner_w , mid_dst_h, 0);
- // draw, take from the midle center of the image
- image_drawscale(img, corner_w, src_y, mid_src_w, mid_src_h,
- middle_x, dst_y, mid_dst_w, mid_dst_h, 0);
- // draw, take from the right center of the image, stretch vertically
- image_drawscale(img, part_w, src_y, corner_w, mid_src_h,
- right_x, dst_y, corner_w , mid_dst_h, 0);
-
- dst_y = yy + new_h - corner_h ; // + mid_dst_h;
- src_y = src_w - corner_h;
- // draw, take from the lower corner left of the image
- image_drawpart(img, 0, src_y, corner_h, corner_w, left_x, dst_y, 0);
- // draw, take from the lower center of the image
- image_drawscale(img, corner_w, src_y, mid_src_w, corner_h,
- middle_x, dst_y, mid_dst_w, corner_h, 0);
-
- // draw, take from the lower corner of the image
- image_drawpart(img, part_w, src_y, corner_h, corner_w, right_x, dst_y, 0);
- }
- /*** Draws a filled rectange at the given position with the given size */
- void draw_slab(int x, int y, int w, int h, Color col) {
- al_draw_filled_rectangle(x, y, x+w, y+h, col);
- }
- /*** Draws a rounded filled rectange at the given position with the given size */
- void draw_roundslab(int x, int y, int w, int h, int rx, int ry, Color col) {
- al_draw_filled_rounded_rectangle(x, y, x+w, y+h, rx, ry, col);
- }
- /*** Draws an open rectange at the given position with the given size */
- void draw_box(int x, int y, int w, int h, Color col, int tt) {
- al_draw_rectangle(x, y, x+w, y+h, col, tt);
- }
- /** Draws a rounded rectangle at the given position with the given size */
- void draw_roundbox(int x, int y, int w, int h, int rx, int ry, Color col, int tt) {
- al_draw_rounded_rectangle(x, y, x+w, y+h, rx, ry, col, tt);
- }
-
- /** Draws a filled frame of the given thickness on the active bitmap.
- * The outer size of the frame will be ww and hh.
- * border color is fg, background color is bg. */
- void draw_frame(int xx, int yy, int ww, int hh, int tt, Color fg, Color bg) {
- // Draw inner frame in bg color.
- draw_slab(xx, yy, ww, hh, bg);
- // Draw outer frame in fg color with the given thickness.
- draw_box(xx, yy, ww, hh, fg, tt);
- }
-
- /** Draws a filled, rounded frame of the given thickness on the active bitmap.
- * The rounding is autocalulated. The outer size of the frame will be ww and hh.
- * border color is fg, background color is bg.
- */
- void draw_roundframe(int xx, int yy, int ww, int hh, int tt, Color fg, Color bg) {
- int rx = 4;
- int ry = 4;
- // draw inner frame in bg color.
- draw_roundslab(xx, yy, ww, hh, rx, ry, bg);
- // draw outer frame in fg color with the given thickness.
- draw_roundbox(xx, yy, ww, hh, rx, ry, fg, tt);
- }
- /* Function that maps black to transparent black, white to transparent white, and
- * any grayscale or color in between to white with an alpha value
- * that corresponds to the average of the r, g and b components. Mosty for use
- * with the "GIN" icons. The color in draw color will be used for the r, g and b
- * of the color (premultiplied by the average as well)
- */
- bool draw_convert_average_to_alpha(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR draw_color)
- {
- ALLEGRO_LOCKED_REGION *lr;
- int x, y;
- float dr, dg, db;
- float avg, r, g, b;
- ALLEGRO_COLOR pixel;
- ALLEGRO_COLOR alpha_pixel;
- ALLEGRO_STATE state;
- if (!(lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY, 0))) {
- return FALSE;
- }
- al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP);
- al_set_target_bitmap(bitmap);
- alpha_pixel = al_map_rgba(0, 0, 0, 0);
- al_unmap_rgb_f(draw_color, &dr, &dg, &db);
- for (y = 0; y < al_get_bitmap_height(bitmap); y++) {
- for (x = 0; x < al_get_bitmap_width(bitmap); x++) {
- pixel = al_get_pixel(bitmap, x, y);
- al_unmap_rgb_f(pixel, &r, &g, &b);
- avg = (r + g + b) / 3.0;
- alpha_pixel = al_map_rgba_f(dr * avg, dg * avg, db * avg, avg);
- al_put_pixel(x, y, alpha_pixel);
- }
- }
- al_unlock_bitmap(bitmap);
- al_restore_state(&state);
- return TRUE;
- }
- /* Helper for drawing multi line text */
- static int laytext_allegro_font_callback
- (char * str, int bytes, void * extra, float * w, float * h) {
- ALLEGRO_USTR_INFO info;
- const ALLEGRO_USTR * ustr;
- ustr = al_ref_buffer(&info, str, bytes);
- (*w) = (float) al_get_ustr_width((ALLEGRO_FONT *)extra, ustr);
- (*h) = 1.0;
- return bytes;
- }
- void draw_multi_line_text(ALLEGRO_FONT * font, ALLEGRO_COLOR color,
- float x, float y, float w, float h,
- int flags,
- char * text)
- {
- int index;
- long start;
- Dynar * result;
- long value = 0;
- int length;
- int line_height = al_get_font_line_height(font);
- ALLEGRO_USTR_INFO info;
- const ALLEGRO_USTR * ustr;
- result = laytext_layout(text, w, laytext_allegro_font_callback, font);
-
- length = strlen(text);
- start = 0;
- for(index = 0; index < dynar_size(result); index++) {
- dynar_get_long(result, index, &value);
- if (value > 0) {
- ustr = al_ref_buffer(&info, text + start, (int) (value - start));
- al_draw_ustr(font, color, x, y, flags, ustr);
- y += line_height;
- }
- start = value + 1;
- }
- ustr = al_ref_cstr(&info, text + start);
- al_draw_ustr(font, color, x, y, flags, ustr);
- dynar_free(result);
- (void) h;
- }
- /** Makes a new image by copying a part from the source image.
- * Allegro drawing flags can be passed to flip the copied image in one go.
- * The result must be freed by calling al_destroy_bitmap.
- */
- Image * image_copy_region
- (Image * source, int x, int y, int wide, int high, int flags) {
- Image * result;
- ALLEGRO_COLOR black, glass, white;
- black = al_map_rgba(0,0,0,255);
- white = al_map_rgba(255,255,255,255);
- glass = al_map_rgba(0,0,0,0);
- // al_set_new_bitmap_flags
- result = al_create_bitmap(wide, high);
- if(!result) {
- return NULL;
- }
- al_set_target_bitmap(result);
- al_clear_to_color(glass);
- al_draw_bitmap_region(source, x, y, wide, high, 0, 0, flags);
- if (al_get_current_display()) {
- al_set_target_backbuffer(al_get_current_display());
- }
- return result;
- }
|