buffer.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include "buffer.h"
  2. #include "helpers.h"
  3. #include <memory.h>
  4. #include <furi.h>
  5. static RenderSettings default_render = DEFAULT_RENDER;
  6. uint16_t pixel(uint8_t x, uint8_t y, uint8_t w) {
  7. return (y * w + x) / 8;
  8. }
  9. unsigned long buffer_size(uint8_t width, uint8_t height) {
  10. return sizeof(uint8_t) * (int)ceil(width / 8.0) * ceil(height);
  11. }
  12. uint8_t* malloc_buffer(uint8_t width, uint8_t height) {
  13. return (uint8_t*)malloc(buffer_size(width, height));
  14. }
  15. Buffer* buffer_create(uint8_t width, uint8_t height, bool double_buffered) {
  16. Buffer* b = (Buffer*)malloc(sizeof(Buffer));
  17. b->double_buffered = double_buffered;
  18. b->width = width;
  19. b->height = height;
  20. b->data = malloc_buffer(width, height);
  21. if(double_buffered)
  22. b->back_buffer = malloc_buffer(width, height);
  23. else
  24. b->back_buffer = NULL;
  25. return b;
  26. }
  27. void buffer_release(Buffer* buffer) {
  28. free(buffer->data);
  29. if(buffer->double_buffered) free(buffer->back_buffer);
  30. free(buffer);
  31. }
  32. bool buffer_test_coordinate(Buffer* const buffer, int x, int y) {
  33. return (x >= 0 && x < buffer->width && y >= 0 && y < buffer->height);
  34. }
  35. bool buffer_get_pixel(Buffer* const buffer, int x, int y) {
  36. return buffer->data[pixel(x, y, buffer->width)] & (1 << (x & 7));
  37. }
  38. void buffer_set_pixel(Buffer* buffer, int16_t x, int16_t y, enum PixelColor draw_mode) {
  39. uint8_t bit = 1 << (x & 7);
  40. uint8_t* p = &(buffer->data[pixel(x, y, buffer->width)]);
  41. switch(draw_mode) {
  42. case Black:
  43. *p |= bit;
  44. break;
  45. case White:
  46. *p &= ~bit;
  47. break;
  48. case Flip:
  49. *p ^= bit;
  50. break;
  51. }
  52. }
  53. Buffer* buffer_copy(Buffer* buffer) {
  54. Buffer* new_buffer = (Buffer*)malloc(sizeof(Buffer));
  55. new_buffer->double_buffered = buffer->double_buffered;
  56. new_buffer->width = buffer->width;
  57. new_buffer->height = buffer->height;
  58. new_buffer->data = malloc_buffer(buffer->width, buffer->height);
  59. memcpy(new_buffer->data, buffer->data, buffer_size(buffer->width, buffer->height));
  60. if(buffer->double_buffered) {
  61. new_buffer->back_buffer = malloc_buffer(buffer->width, buffer->height);
  62. memcpy(
  63. new_buffer->back_buffer,
  64. buffer->back_buffer,
  65. buffer_size(buffer->width, buffer->height));
  66. } else {
  67. new_buffer->back_buffer = NULL;
  68. }
  69. return new_buffer;
  70. }
  71. void buffer_swap_back(Buffer* buffer) {
  72. check_pointer(buffer);
  73. check_pointer(buffer->data);
  74. if(buffer->double_buffered) {
  75. check_pointer(buffer->back_buffer);
  76. uint8_t* temp = buffer->data;
  77. buffer->data = buffer->back_buffer;
  78. buffer->back_buffer = temp;
  79. }
  80. }
  81. void buffer_clear(Buffer* buffer) {
  82. check_pointer(buffer);
  83. check_pointer(buffer->data);
  84. buffer->data = (uint8_t*)memset(buffer->data, 0, buffer_size(buffer->width, buffer->height));
  85. }
  86. void buffer_swap_with(Buffer* buffer_a, Buffer* buffer_b) {
  87. check_pointer(buffer_a);
  88. check_pointer(buffer_b);
  89. uint8_t* temp = buffer_a->data;
  90. buffer_a->data = buffer_b->data;
  91. buffer_b->data = temp;
  92. }
  93. void buffer_draw_internal(
  94. Buffer* target,
  95. Buffer* const sprite,
  96. bool is_black,
  97. enum PixelColor color,
  98. Vector* const position,
  99. uint8_t x_cap,
  100. uint8_t y_cap,
  101. float rotation,
  102. Vector anchor) {
  103. Vector center = {
  104. .x = anchor.x * sprite->width,
  105. .y = anchor.y * sprite->height,
  106. };
  107. Vector transform;
  108. int max_w = fmin(sprite->width, x_cap);
  109. int max_h = fmin(sprite->height, y_cap);
  110. bool isOn;
  111. int16_t finalX, finalY;
  112. for(int y = 0; y < max_h; y++) {
  113. for(int x = 0; x < max_w; x++) {
  114. Vector curr = {x, y};
  115. vector_sub(&curr, &center, &transform);
  116. vector_rotate(&transform, rotation, &transform);
  117. vector_add(&transform, position, &transform);
  118. finalX = (int16_t)roundf(transform.x);
  119. finalY = (int16_t)roundf(transform.y);
  120. if(buffer_test_coordinate(target, finalX, finalY)) {
  121. isOn = buffer_get_pixel(sprite, x, y) == is_black;
  122. if(isOn) buffer_set_pixel(target, finalX, finalY, color);
  123. }
  124. }
  125. }
  126. }
  127. void buffer_draw_all(Buffer* target, Buffer* const sprite, Vector* position, float rotation) {
  128. check_pointer(target);
  129. check_pointer(sprite);
  130. check_pointer(position);
  131. buffer_draw(
  132. target, sprite, position, sprite->width, sprite->height, rotation, &default_render);
  133. }
  134. void buffer_draw(
  135. Buffer* target,
  136. Buffer* const sprite,
  137. Vector* position,
  138. uint8_t x_cap,
  139. uint8_t y_cap,
  140. float rotation,
  141. RenderSettings* settings) {
  142. check_pointer(target);
  143. check_pointer(sprite);
  144. check_pointer(position);
  145. switch(settings->drawMode) {
  146. default:
  147. case BlackOnly:
  148. buffer_draw_internal(
  149. target, sprite, true, Black, position, x_cap, y_cap, rotation, settings->anchor);
  150. break;
  151. case WhiteOnly:
  152. buffer_draw_internal(
  153. target, sprite, false, White, position, x_cap, y_cap, rotation, settings->anchor);
  154. break;
  155. case WhiteAsBlack:
  156. buffer_draw_internal(
  157. target, sprite, false, Black, position, x_cap, y_cap, rotation, settings->anchor);
  158. break;
  159. case BlackAsWhite:
  160. buffer_draw_internal(
  161. target, sprite, true, White, position, x_cap, y_cap, rotation, settings->anchor);
  162. break;
  163. case WhiteAsInverted:
  164. buffer_draw_internal(
  165. target, sprite, false, Flip, position, x_cap, y_cap, rotation, settings->anchor);
  166. break;
  167. case BlackAsInverted:
  168. buffer_draw_internal(
  169. target, sprite, true, Flip, position, x_cap, y_cap, rotation, settings->anchor);
  170. break;
  171. }
  172. }
  173. void buffer_render(Buffer* buffer, Canvas* const canvas) {
  174. check_pointer(buffer);
  175. canvas_draw_xbm(canvas, 0, 0, buffer->width, buffer->height, buffer->data);
  176. }
  177. void buffer_draw_line(Buffer* buffer, int x0, int y0, int x1, int y1, enum PixelColor draw_mode) {
  178. check_pointer(buffer);
  179. int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
  180. int dy = abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
  181. int err = (dx > dy ? dx : -dy) / 2;
  182. while(true) {
  183. if(buffer_test_coordinate(buffer, x0, y0)) {
  184. buffer_set_pixel(buffer, x0, y0, draw_mode);
  185. }
  186. if(x0 == x1 && y0 == y1) break;
  187. int e2 = err;
  188. if(e2 > -dx) {
  189. err -= dy;
  190. x0 += sx;
  191. }
  192. if(e2 < dy) {
  193. err += dx;
  194. y0 += sy;
  195. }
  196. }
  197. }
  198. void buffer_draw_rbox(
  199. Buffer* buffer,
  200. int16_t x0,
  201. int16_t y0,
  202. int16_t x1,
  203. int16_t y1,
  204. enum PixelColor draw_mode) {
  205. for(int16_t x = x0; x < x1; x++) {
  206. for(int16_t y = y0; y < y1; y++) {
  207. if(((x == x0 || x == x1 - 1) && (y == y0 || y == y1 - 1)) ||
  208. !buffer_test_coordinate(buffer, x, y))
  209. continue;
  210. buffer_set_pixel(buffer, x, y, draw_mode);
  211. }
  212. }
  213. }
  214. void buffer_draw_rbox_frame(
  215. Buffer* buffer,
  216. int16_t x0,
  217. int16_t y0,
  218. int16_t x1,
  219. int16_t y1,
  220. enum PixelColor draw_mode) {
  221. buffer_draw_line(buffer, x0 + 1, y0, x1 - 1, y0, draw_mode);
  222. buffer_draw_line(buffer, x0 + 1, y1, x1 - 1, y1, draw_mode);
  223. buffer_draw_line(buffer, x0, y0 + 1, x0, y1 - 1, draw_mode);
  224. buffer_draw_line(buffer, x1, y0 + 1, x1, y1 - 1, draw_mode);
  225. }
  226. void buffer_draw_box(
  227. Buffer* buffer,
  228. int16_t x0,
  229. int16_t y0,
  230. int16_t x1,
  231. int16_t y1,
  232. enum PixelColor draw_mode) {
  233. for(int16_t x = x0 + 1; x < x1 - 1; x++) {
  234. for(int16_t y = y0 + 1; y < y1 - 1; y++) {
  235. if(!buffer_test_coordinate(buffer, x, y)) continue;
  236. buffer_set_pixel(buffer, x, y, draw_mode);
  237. }
  238. }
  239. }
  240. void buffer_set_pixel_with_check(Buffer* buffer, int16_t x, int16_t y, enum PixelColor draw_mode) {
  241. if(buffer_test_coordinate(buffer, x, y)) buffer_set_pixel(buffer, x, y, draw_mode);
  242. }
  243. void buffer_draw_circle(Buffer* buffer, int x, int y, int r, enum PixelColor color) {
  244. int16_t a = r;
  245. int16_t b = 0;
  246. int16_t decision = 1 - a;
  247. while(b <= a) {
  248. buffer_set_pixel_with_check(buffer, a + x, b + y, color);
  249. buffer_set_pixel_with_check(buffer, b + x, a + y, color);
  250. buffer_set_pixel_with_check(buffer, -a + x, b + y, color);
  251. buffer_set_pixel_with_check(buffer, -b + x, a + y, color);
  252. buffer_set_pixel_with_check(buffer, -a + x, -b + y, color);
  253. buffer_set_pixel_with_check(buffer, -b + x, -a + y, color);
  254. buffer_set_pixel_with_check(buffer, a + x, -b + y, color);
  255. buffer_set_pixel_with_check(buffer, b + x, -a + y, color);
  256. b++;
  257. if(decision <= 0) {
  258. decision += 2 * b + 1;
  259. } else {
  260. a--;
  261. decision += 2 * (b - a) + 1;
  262. }
  263. }
  264. }