sw_rotate.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #include <display/sw_draw.h>
  2. #include <display/sw_rotate.h>
  3. #ifdef CONFIG_GUI_API_BROM
  4. #include <brom_interface.h>
  5. #endif
  6. #ifndef MAX
  7. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  8. #endif
  9. #ifndef MIN
  10. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  11. #endif
  12. /*
  13. * compute x range in pixels inside the src image
  14. *
  15. * The routine will update the range value [*x_min, *x_max].
  16. *
  17. * @param x_min address of minimum range value in pixels
  18. * @param x_max address of maximum range value in pixels
  19. * @param img_w source image width in pixels
  20. * @param img_h source image height in pixels
  21. * @param start_x X coord of start point in fixedpoint-16, corresponding to the original *x_min value
  22. * @param start_y Y coord of start point in fixedpoint-16, corresponding to the original *x_min value
  23. * @param dx_x X coord of point delta in x direction in fixedpoint-16
  24. * @param dx_y Y coord of point delta in x direction in fixedpoint-16
  25. *
  26. * @return N/A
  27. */
  28. static inline void sw_rotate_compoute_x_range(
  29. int32_t *x_min, int32_t *x_max, int16_t img_w, int16_t img_h,
  30. int32_t start_x, int32_t start_y, int32_t dx_x, int32_t dx_y)
  31. {
  32. const int32_t img_w_m1 = FIXEDPOINT16(img_w - 1);
  33. const int32_t img_h_m1 = FIXEDPOINT16(img_h - 1);
  34. int x_1, x_2;
  35. /* FIXME: the compiler seems to divide towards to zero. */
  36. if (dx_x != 0) {
  37. /*
  38. * floor(Δx * dx_x + start_x) >= FIXEDPOINT16(0)
  39. * ceil(Δx * dx_x + start_x) <= img_w_m1
  40. */
  41. if (dx_x > 0) {
  42. x_1 = (FIXEDPOINT16(0) - start_x + dx_x - 1) / dx_x;
  43. x_2 = (img_w_m1 - start_x) / dx_x;
  44. } else {
  45. x_2 = (FIXEDPOINT16(0) - start_x) / dx_x;
  46. x_1 = (img_w_m1 - start_x + dx_x + 1) / dx_x;
  47. }
  48. *x_min = MAX(*x_min, x_1);
  49. *x_max = MIN(*x_max, x_2);
  50. } else if (start_x < FIXEDPOINT16(0) || start_x > img_w_m1) {
  51. *x_max = *x_min - 1;
  52. return;
  53. }
  54. if (dx_y != 0) {
  55. /*
  56. * floor(Δy * dx_y + start_y) >= FIXEDPOINT16(0)
  57. * ceil(Δy * dx_y + start_y) <= img_h_m1
  58. */
  59. if (dx_y > 0) {
  60. x_1 = (FIXEDPOINT16(0) - start_y + dx_y - 1) / dx_y;
  61. x_2 = (img_h_m1 - start_y) / dx_y;
  62. } else {
  63. x_2 = (FIXEDPOINT16(0) - start_y) / dx_y;
  64. x_1 = (img_h_m1 - start_y + dx_y + 1) / dx_y;
  65. }
  66. *x_min = MAX(*x_min, x_1);
  67. *x_max = MIN(*x_max, x_2);
  68. } else if (start_y < FIXEDPOINT16(0) || start_y > img_h_m1) {
  69. *x_max = *x_min - 1;
  70. return;
  71. }
  72. }
  73. void sw_rotate_configure(int16_t draw_x, int16_t draw_y, int16_t img_x, int16_t img_y,
  74. int16_t pivot_x, int16_t pivot_y, uint16_t angle, sw_rotate_config_t *cfg)
  75. {
  76. #ifdef CONFIG_GUI_API_BROM
  77. p_brom_libgui_api->p_sw_rotate_configure(
  78. draw_x, draw_y, img_x, img_y, pivot_x, pivot_y, angle, cfg);
  79. #else
  80. uint16_t reverse_angle = 3600 - angle;
  81. /* destination coordinate system */
  82. cfg->src_coord_x0 = PX_FIXEDPOINT16(draw_x);
  83. cfg->src_coord_y0 = PX_FIXEDPOINT16(draw_y);
  84. cfg->src_coord_dx_ax = FIXEDPOINT16(1);
  85. cfg->src_coord_dy_ax = FIXEDPOINT16(0);
  86. cfg->src_coord_dx_ay = FIXEDPOINT16(0);
  87. cfg->src_coord_dy_ay = FIXEDPOINT16(1);
  88. /* map to the source coordinate system */
  89. sw_rotate_point32(&cfg->src_coord_x0, &cfg->src_coord_y0,
  90. cfg->src_coord_x0, cfg->src_coord_y0,
  91. FIXEDPOINT16(pivot_x), FIXEDPOINT16(pivot_y), reverse_angle);
  92. sw_rotate_point32(&cfg->src_coord_dx_ax, &cfg->src_coord_dy_ax,
  93. cfg->src_coord_dx_ax, cfg->src_coord_dy_ax, 0, 0, reverse_angle);
  94. sw_rotate_point32(&cfg->src_coord_dx_ay, &cfg->src_coord_dy_ay,
  95. cfg->src_coord_dx_ay, cfg->src_coord_dy_ay, 0, 0, reverse_angle);
  96. /* map to the source pixel coordinate system */
  97. cfg->src_coord_x0 -= PX_FIXEDPOINT16(img_x);
  98. cfg->src_coord_y0 -= PX_FIXEDPOINT16(img_y);
  99. #endif /* CONFIG_GUI_API_BROM */
  100. }
  101. void sw_rotate_rgb565_over_rgb565(void *dst, const void *src,
  102. uint16_t dst_stride, uint16_t src_w, uint16_t src_h,
  103. int16_t x, int16_t y, uint16_t w, uint16_t h,
  104. const sw_rotate_config_t *cfg)
  105. {
  106. #ifdef CONFIG_GUI_API_BROM
  107. p_brom_libgui_api->p_sw_rotate_rgb565_over_rgb565(
  108. dst, src, dst_stride, src_w, src_h, x, y, w, h, cfg);
  109. #else
  110. uint16_t * dst16 = dst;
  111. uint16_t src_pitch = src_w * 2;
  112. uint16_t src_bytes_per_pixel = 2;
  113. int32_t src_coord_x = cfg->src_coord_x0 +
  114. y * cfg->src_coord_dx_ay + x * cfg->src_coord_dx_ax;
  115. int32_t src_coord_y = cfg->src_coord_y0 +
  116. y * cfg->src_coord_dy_ay + x * cfg->src_coord_dy_ax;
  117. for (int j = h; j > 0; j--) {
  118. int32_t p_x = src_coord_x;
  119. int32_t p_y = src_coord_y;
  120. uint16_t *tmp_dst = dst16;
  121. int x1 = 0, x2 = w - 1;
  122. sw_rotate_compoute_x_range(&x1, &x2, src_w, src_h,
  123. p_x, p_y, cfg->src_coord_dx_ax, cfg->src_coord_dy_ax);
  124. if (x1 > x2) {
  125. goto next_line;
  126. } else if (x1 > 0) {
  127. p_x += cfg->src_coord_dx_ax * x1;
  128. p_y += cfg->src_coord_dy_ax * x1;
  129. tmp_dst += x1;
  130. }
  131. for (int i = x2 - x1; i >= 0; i--) {
  132. int x = FLOOR_FIXEDPOINT16(p_x);
  133. int y = FLOOR_FIXEDPOINT16(p_y);
  134. int x_frac = p_x - FIXEDPOINT16(x);
  135. int y_frac = p_y - FIXEDPOINT16(y);
  136. uint8_t *src1 = (uint8_t *)src + y * src_pitch + x * src_bytes_per_pixel;
  137. uint8_t *src2 = src1 + src_bytes_per_pixel;
  138. uint8_t *src3 = src1 + src_pitch;
  139. uint8_t *src4 = src2 + src_pitch;
  140. *tmp_dst = bilinear_rgb565_fast_m6(*(uint16_t*)src1,
  141. *(uint16_t*)src2, *(uint16_t*)src3, *(uint16_t*)src4,
  142. x_frac >> 10, y_frac >> 10, 6);
  143. p_x += cfg->src_coord_dx_ax;
  144. p_y += cfg->src_coord_dy_ax;
  145. tmp_dst += 1;
  146. }
  147. next_line:
  148. src_coord_x += cfg->src_coord_dx_ay;
  149. src_coord_y += cfg->src_coord_dy_ay;
  150. dst16 += dst_stride;
  151. }
  152. #endif /* CONFIG_GUI_API_BROM */
  153. }
  154. void sw_rotate_argb8565_over_rgb565(void *dst, const void *src,
  155. uint16_t dst_stride, uint16_t src_w, uint16_t src_h,
  156. int16_t x, int16_t y, uint16_t w, uint16_t h,
  157. const sw_rotate_config_t *cfg)
  158. {
  159. uint16_t * dst16 = dst;
  160. uint16_t src_pitch = src_w * 3;
  161. uint16_t src_bytes_per_pixel = 3;
  162. int32_t src_coord_x = cfg->src_coord_x0 +
  163. y * cfg->src_coord_dx_ay + x * cfg->src_coord_dx_ax;
  164. int32_t src_coord_y = cfg->src_coord_y0 +
  165. y * cfg->src_coord_dy_ay + x * cfg->src_coord_dy_ax;
  166. for (int j = h; j > 0; j--) {
  167. int32_t p_x = src_coord_x;
  168. int32_t p_y = src_coord_y;
  169. uint16_t *tmp_dst = dst16;
  170. int x1 = 0, x2 = w - 1;
  171. sw_rotate_compoute_x_range(&x1, &x2, src_w, src_h,
  172. p_x, p_y, cfg->src_coord_dx_ax, cfg->src_coord_dy_ax);
  173. if (x1 > x2) {
  174. goto next_line;
  175. } else if (x1 > 0) {
  176. p_x += cfg->src_coord_dx_ax * x1;
  177. p_y += cfg->src_coord_dy_ax * x1;
  178. tmp_dst += x1;
  179. }
  180. for (int i = x2 - x1; i >= 0; i--) {
  181. int x = FLOOR_FIXEDPOINT16(p_x);
  182. int y = FLOOR_FIXEDPOINT16(p_y);
  183. int x_frac = p_x - FIXEDPOINT16(x);
  184. int y_frac = p_y - FIXEDPOINT16(y);
  185. uint8_t *src1 = (uint8_t *)src + y * src_pitch + x * src_bytes_per_pixel;
  186. uint8_t *src2 = src1 + src_bytes_per_pixel;
  187. uint8_t *src3 = src1 + src_pitch;
  188. uint8_t *src4 = src2 + src_pitch;
  189. uint16_t color = bilinear_rgb565_fast_m6(
  190. ((uint16_t)src1[1] << 8) | src1[0],
  191. ((uint16_t)src2[1] << 8) | src2[0],
  192. ((uint16_t)src3[1] << 8) | src3[0],
  193. ((uint16_t)src4[1] << 8) | src4[0],
  194. x_frac >> 10, y_frac >> 10, 6);
  195. *tmp_dst = blend_rgb565_over_rgb565(*tmp_dst, color, src1[2]);
  196. p_x += cfg->src_coord_dx_ax;
  197. p_y += cfg->src_coord_dy_ax;
  198. tmp_dst += 1;
  199. }
  200. next_line:
  201. src_coord_x += cfg->src_coord_dx_ay;
  202. src_coord_y += cfg->src_coord_dy_ay;
  203. dst16 += dst_stride;
  204. }
  205. }
  206. void sw_rotate_argb8888_over_rgb565(void *dst, const void *src,
  207. uint16_t dst_stride, uint16_t src_w, uint16_t src_h,
  208. int16_t x, int16_t y, uint16_t w, uint16_t h,
  209. const sw_rotate_config_t *cfg)
  210. {
  211. #ifdef CONFIG_GUI_API_BROM
  212. p_brom_libgui_api->p_sw_rotate_argb8888_over_rgb565(
  213. dst, src, dst_stride, src_w, src_h, x, y, w, h, cfg);
  214. #else
  215. uint16_t * dst16 = dst;
  216. uint16_t src_pitch = src_w * 4;
  217. uint16_t src_bytes_per_pixel = 4;
  218. int32_t src_coord_x = cfg->src_coord_x0 +
  219. y * cfg->src_coord_dx_ay + x * cfg->src_coord_dx_ax;
  220. int32_t src_coord_y = cfg->src_coord_y0 +
  221. y * cfg->src_coord_dy_ay + x * cfg->src_coord_dy_ax;
  222. for (int j = h; j > 0; j--) {
  223. int32_t p_x = src_coord_x;
  224. int32_t p_y = src_coord_y;
  225. uint16_t *tmp_dst = dst16;
  226. int x1 = 0, x2 = w - 1;
  227. sw_rotate_compoute_x_range(&x1, &x2, src_w, src_h,
  228. p_x, p_y, cfg->src_coord_dx_ax, cfg->src_coord_dy_ax);
  229. if (x1 > x2) {
  230. goto next_line;
  231. } else if (x1 > 0) {
  232. p_x += cfg->src_coord_dx_ax * x1;
  233. p_y += cfg->src_coord_dy_ax * x1;
  234. tmp_dst += x1;
  235. }
  236. for (int i = x2 - x1; i >= 0; i--) {
  237. int x = FLOOR_FIXEDPOINT16(p_x);
  238. int y = FLOOR_FIXEDPOINT16(p_y);
  239. int x_frac = p_x - FIXEDPOINT16(x);
  240. int y_frac = p_y - FIXEDPOINT16(y);
  241. uint8_t *src1 = (uint8_t *)src + y * src_pitch + x * src_bytes_per_pixel;
  242. uint8_t *src2 = src1 + src_bytes_per_pixel;
  243. uint8_t *src3 = src1 + src_pitch;
  244. uint8_t *src4 = src2 + src_pitch;
  245. uint32_t color = bilinear_argb8888_fast_m8(*(uint32_t*)src1,
  246. *(uint32_t*)src2, *(uint32_t*)src3, *(uint32_t*)src4,
  247. x_frac >> 8, y_frac >> 8, 8);
  248. *tmp_dst = blend_argb8888_over_rgb565(*tmp_dst, color);
  249. p_x += cfg->src_coord_dx_ax;
  250. p_y += cfg->src_coord_dy_ax;
  251. tmp_dst += 1;
  252. }
  253. next_line:
  254. src_coord_x += cfg->src_coord_dx_ay;
  255. src_coord_y += cfg->src_coord_dy_ay;
  256. dst16 += dst_stride;
  257. }
  258. #endif /* CONFIG_GUI_API_BROM */
  259. }
  260. void sw_rotate_argb8888_over_argb8888(void *dst, const void *src,
  261. uint16_t dst_stride, uint16_t src_w, uint16_t src_h,
  262. int16_t x, int16_t y, uint16_t w, uint16_t h,
  263. const sw_rotate_config_t *cfg)
  264. {
  265. #ifdef CONFIG_GUI_API_BROM
  266. p_brom_libgui_api->p_sw_rotate_argb8888_over_argb8888(
  267. dst, src, dst_stride, src_w, src_h, x, y, w, h, cfg);
  268. #else
  269. uint32_t * dst32 = dst;
  270. uint16_t src_pitch = src_w * 4;
  271. uint16_t src_bytes_per_pixel = 4;
  272. int32_t src_coord_x = cfg->src_coord_x0 +
  273. y * cfg->src_coord_dx_ay + x * cfg->src_coord_dx_ax;
  274. int32_t src_coord_y = cfg->src_coord_y0 +
  275. y * cfg->src_coord_dy_ay + x * cfg->src_coord_dy_ax;
  276. for (int j = h; j > 0; j--) {
  277. int32_t p_x = src_coord_x;
  278. int32_t p_y = src_coord_y;
  279. uint32_t *tmp_dst = dst32;
  280. int x1 = 0, x2 = w - 1;
  281. sw_rotate_compoute_x_range(&x1, &x2, src_w, src_h,
  282. p_x, p_y, cfg->src_coord_dx_ax, cfg->src_coord_dy_ax);
  283. if (x1 > x2) {
  284. goto next_line;
  285. } else if (x1 > 0) {
  286. p_x += cfg->src_coord_dx_ax * x1;
  287. p_y += cfg->src_coord_dy_ax * x1;
  288. tmp_dst += x1;
  289. }
  290. for (int i = x2 - x1; i >= 0; i--) {
  291. int x = FLOOR_FIXEDPOINT16(p_x);
  292. int y = FLOOR_FIXEDPOINT16(p_y);
  293. int x_frac = p_x - FIXEDPOINT16(x);
  294. int y_frac = p_y - FIXEDPOINT16(y);
  295. uint8_t *src1 = (uint8_t *)src + y * src_pitch + x * src_bytes_per_pixel;
  296. uint8_t *src2 = src1 + src_bytes_per_pixel;
  297. uint8_t *src3 = src1 + src_pitch;
  298. uint8_t *src4 = src2 + src_pitch;
  299. uint32_t color = bilinear_argb8888_fast_m8(*(uint32_t*)src1,
  300. *(uint32_t*)src2, *(uint32_t*)src3, *(uint32_t*)src4,
  301. x_frac >> 8, y_frac >> 8, 8);
  302. *tmp_dst = blend_argb8888_over_argb8888(*tmp_dst, color);
  303. p_x += cfg->src_coord_dx_ax;
  304. p_y += cfg->src_coord_dy_ax;
  305. tmp_dst += 1;
  306. }
  307. next_line:
  308. src_coord_x += cfg->src_coord_dx_ay;
  309. src_coord_y += cfg->src_coord_dy_ay;
  310. dst32 += dst_stride;
  311. }
  312. #endif /* CONFIG_GUI_API_BROM */
  313. }