draw.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include "draw.h"
  2. #include "laytext.h"
  3. #include "dynar.h"
  4. /** Addinional drawing functions and wrappers for primitive drwaing
  5. functionality. */
  6. /** Draws an image on the current target bitmap according to a 9 part scaling
  7. algorithm. This splits the bitmap in 9 parts, keeps the 4 corners unscaled, but
  8. scales the 4 edges and the center according to the desired size.
  9. The 4 corners should be rectangles of identical size corner_w by corner_h in
  10. the original image. Pass a non-positive number to have the corner sizes
  11. automatically calculated.
  12. new_w and new_h are the new dimensions the new image should have.
  13. This is useful for GUI backgrounds.
  14. */
  15. void image_blitscale9(Image * img, int xx, int yy,
  16. int new_w, int new_h,
  17. int corner_w, int corner_h) {
  18. int mid_src_w, mid_src_h, mid_dst_w, mid_dst_h;
  19. int left_x, right_x, middle_x;
  20. int dst_y, src_y, part_w;
  21. int src_w = image_w(img);
  22. int src_h = image_h(img);
  23. corner_w = (corner_w > 0) ? (corner_w) : src_w / 16;
  24. corner_h = (corner_h > 0) ? (corner_h) : src_h / 16;
  25. CLAMP_MAX(corner_w, corner_w, (new_w / 4));
  26. CLAMP_MAX(corner_h, corner_h, (new_h / 4));
  27. mid_src_w = src_w - (corner_w * 2);
  28. mid_src_h = src_h - (corner_h * 2);
  29. mid_dst_w = new_w - (corner_w * 2);
  30. mid_dst_h = new_h - (corner_h * 2);
  31. // draw top parts first
  32. left_x = xx; // left side
  33. right_x = xx + mid_dst_w + corner_w; // right side
  34. middle_x = xx + corner_w ; // middle
  35. dst_y = yy; // y is he drawing location for the top 3 draws
  36. // width of the first corner and middle. the second corner starts here
  37. part_w = src_w - corner_w;
  38. // draw, take from the top corner left of the image
  39. image_drawpart(img, 0, 0, corner_w, corner_h, left_x, dst_y, 0);
  40. // draw, take from the midle of the image
  41. image_drawscale(img, corner_w, 0, mid_src_w, corner_h,
  42. middle_x, dst_y, mid_dst_w, corner_h, 0);
  43. // draw, take from the right corner of the image
  44. image_drawpart(img, part_w, 0, corner_w, corner_h, right_x, dst_y, 0);
  45. // now shift down, mutatis mutandis.
  46. dst_y = yy + corner_h;
  47. src_y = corner_h;
  48. // NOTE the middle left and right must be scaled, unlike the corners
  49. // that must be copied as they are.
  50. // draw, take from the middle corner left of the image, stretch vertically
  51. image_drawscale(img, 0, src_y, corner_w , mid_src_h,
  52. left_x, dst_y, corner_w , mid_dst_h, 0);
  53. // draw, take from the midle center of the image
  54. image_drawscale(img, corner_w, src_y, mid_src_w, mid_src_h,
  55. middle_x, dst_y, mid_dst_w, mid_dst_h, 0);
  56. // draw, take from the right center of the image, stretch vertically
  57. image_drawscale(img, part_w, src_y, corner_w, mid_src_h,
  58. right_x, dst_y, corner_w , mid_dst_h, 0);
  59. dst_y = yy + new_h - corner_h ; // + mid_dst_h;
  60. src_y = src_w - corner_h;
  61. // draw, take from the lower corner left of the image
  62. image_drawpart(img, 0, src_y, corner_h, corner_w, left_x, dst_y, 0);
  63. // draw, take from the lower center of the image
  64. image_drawscale(img, corner_w, src_y, mid_src_w, corner_h,
  65. middle_x, dst_y, mid_dst_w, corner_h, 0);
  66. // draw, take from the lower corner of the image
  67. image_drawpart(img, part_w, src_y, corner_h, corner_w, right_x, dst_y, 0);
  68. }
  69. /*** Draws a filled rectange at the given position with the given size */
  70. void draw_slab(int x, int y, int w, int h, Color col) {
  71. al_draw_filled_rectangle(x, y, x+w, y+h, col);
  72. }
  73. /*** Draws a rounded filled rectange at the given position with the given size */
  74. void draw_roundslab(int x, int y, int w, int h, int rx, int ry, Color col) {
  75. al_draw_filled_rounded_rectangle(x, y, x+w, y+h, rx, ry, col);
  76. }
  77. /*** Draws an open rectange at the given position with the given size */
  78. void draw_box(int x, int y, int w, int h, Color col, int tt) {
  79. al_draw_rectangle(x, y, x+w, y+h, col, tt);
  80. }
  81. /** Draws a rounded rectangle at the given position with the given size */
  82. void draw_roundbox(int x, int y, int w, int h, int rx, int ry, Color col, int tt) {
  83. al_draw_rounded_rectangle(x, y, x+w, y+h, rx, ry, col, tt);
  84. }
  85. /** Draws a filled frame of the given thickness on the active bitmap.
  86. * The outer size of the frame will be ww and hh.
  87. * border color is fg, background color is bg. */
  88. void draw_frame(int xx, int yy, int ww, int hh, int tt, Color fg, Color bg) {
  89. // Draw inner frame in bg color.
  90. draw_slab(xx, yy, ww, hh, bg);
  91. // Draw outer frame in fg color with the given thickness.
  92. draw_box(xx, yy, ww, hh, fg, tt);
  93. }
  94. /** Draws a filled, rounded frame of the given thickness on the active bitmap.
  95. * The rounding is autocalulated. The outer size of the frame will be ww and hh.
  96. * border color is fg, background color is bg.
  97. */
  98. void draw_roundframe(int xx, int yy, int ww, int hh, int tt, Color fg, Color bg) {
  99. int rx = 4;
  100. int ry = 4;
  101. // draw inner frame in bg color.
  102. draw_roundslab(xx, yy, ww, hh, rx, ry, bg);
  103. // draw outer frame in fg color with the given thickness.
  104. draw_roundbox(xx, yy, ww, hh, rx, ry, fg, tt);
  105. }
  106. /* Function that maps black to transparent black, white to transparent white, and
  107. * any grayscale or color in between to white with an alpha value
  108. * that corresponds to the average of the r, g and b components. Mosty for use
  109. * with the "GIN" icons. The color in draw color will be used for the r, g and b
  110. * of the color (premultiplied by the average as well)
  111. */
  112. bool draw_convert_average_to_alpha(ALLEGRO_BITMAP *bitmap, ALLEGRO_COLOR draw_color)
  113. {
  114. ALLEGRO_LOCKED_REGION *lr;
  115. int x, y;
  116. float dr, dg, db;
  117. float avg, r, g, b;
  118. ALLEGRO_COLOR pixel;
  119. ALLEGRO_COLOR alpha_pixel;
  120. ALLEGRO_STATE state;
  121. if (!(lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY, 0))) {
  122. return FALSE;
  123. }
  124. al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP);
  125. al_set_target_bitmap(bitmap);
  126. alpha_pixel = al_map_rgba(0, 0, 0, 0);
  127. al_unmap_rgb_f(draw_color, &dr, &dg, &db);
  128. for (y = 0; y < al_get_bitmap_height(bitmap); y++) {
  129. for (x = 0; x < al_get_bitmap_width(bitmap); x++) {
  130. pixel = al_get_pixel(bitmap, x, y);
  131. al_unmap_rgb_f(pixel, &r, &g, &b);
  132. avg = (r + g + b) / 3.0;
  133. alpha_pixel = al_map_rgba_f(dr * avg, dg * avg, db * avg, avg);
  134. al_put_pixel(x, y, alpha_pixel);
  135. }
  136. }
  137. al_unlock_bitmap(bitmap);
  138. al_restore_state(&state);
  139. return TRUE;
  140. }
  141. /* Helper for drawing multi line text */
  142. static int laytext_allegro_font_callback
  143. (char * str, int bytes, void * extra, float * w, float * h) {
  144. ALLEGRO_USTR_INFO info;
  145. const ALLEGRO_USTR * ustr;
  146. ustr = al_ref_buffer(&info, str, bytes);
  147. (*w) = (float) al_get_ustr_width((ALLEGRO_FONT *)extra, ustr);
  148. (*h) = 1.0;
  149. return bytes;
  150. }
  151. void draw_multi_line_text(ALLEGRO_FONT * font, ALLEGRO_COLOR color,
  152. float x, float y, float w, float h,
  153. int flags,
  154. char * text)
  155. {
  156. int index;
  157. long start;
  158. Dynar * result;
  159. long value = 0;
  160. int length;
  161. int line_height = al_get_font_line_height(font);
  162. ALLEGRO_USTR_INFO info;
  163. const ALLEGRO_USTR * ustr;
  164. result = laytext_layout(text, w, laytext_allegro_font_callback, font);
  165. length = strlen(text);
  166. start = 0;
  167. for(index = 0; index < dynar_size(result); index++) {
  168. dynar_get_long(result, index, &value);
  169. if (value > 0) {
  170. ustr = al_ref_buffer(&info, text + start, (int) (value - start));
  171. al_draw_ustr(font, color, x, y, flags, ustr);
  172. y += line_height;
  173. }
  174. start = value + 1;
  175. }
  176. ustr = al_ref_cstr(&info, text + start);
  177. al_draw_ustr(font, color, x, y, flags, ustr);
  178. dynar_free(result);
  179. (void) h;
  180. }
  181. /** Makes a new image by copying a part from the source image.
  182. * Allegro drawing flags can be passed to flip the copied image in one go.
  183. * The result must be freed by calling al_destroy_bitmap.
  184. */
  185. Image * image_copy_region
  186. (Image * source, int x, int y, int wide, int high, int flags) {
  187. Image * result;
  188. ALLEGRO_COLOR black, glass, white;
  189. black = al_map_rgba(0,0,0,255);
  190. white = al_map_rgba(255,255,255,255);
  191. glass = al_map_rgba(0,0,0,0);
  192. // al_set_new_bitmap_flags
  193. result = al_create_bitmap(wide, high);
  194. if(!result) {
  195. return NULL;
  196. }
  197. al_set_target_bitmap(result);
  198. al_clear_to_color(glass);
  199. al_draw_bitmap_region(source, x, y, wide, high, 0, 0, flags);
  200. if (al_get_current_display()) {
  201. al_set_target_backbuffer(al_get_current_display());
  202. }
  203. return result;
  204. }