accel_canvas.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. // This file is Copyright (c) 2025 Victor Suarez Rovere <suarezvictor@gmail.com>
  2. // SPDX-License-Identifier: AGPL-3.0-only
  3. // line clipping algorithm Copyright (c) 2017 Sagar Ganiga MIT License
  4. #ifndef __ACCEL_CANVAS_H__
  5. #define __ACCEL_CANVAS_H__
  6. #include <stdlib.h> //avoids including a incorrect one by <string> in font_cache.h
  7. #include <assert.h>
  8. #define _USE_MATH_DEFINES
  9. #include <math.h>
  10. #ifndef M_PI
  11. #define M_PI 3.14159265358979323846
  12. #endif
  13. #include "misc.h"
  14. #include "graphics.h"
  15. #include "accel_cores.h" //defines ACCEL_LINE32_REGION & others
  16. #include "agg_pixfmt_rgba.h"
  17. #include "agg_rasterizer_scanline_aa.h"
  18. #include "agg_renderer_base.h"
  19. #include "agg_renderer_scanline.h"
  20. #include "agg_rounded_rect.h"
  21. #include "agg_ellipse.h"
  22. #include "agg_scanline_p.h"
  23. #include "agg_scanline_u.h"
  24. #include "agg_path_storage.h"
  25. #include "agg_conv_transform.h"
  26. #include "agg_conv_stroke.h"
  27. #include "agg_font_cache_manager.h"
  28. #include "agg_font_freetype.h"
  29. namespace agg
  30. {
  31. enum CohenBorder
  32. {
  33. INSIDE = 0,
  34. LEFT = 1,
  35. RIGHT = 2,
  36. BOTTOM = 4,
  37. TOP = 8
  38. };
  39. // Compute the region code for a point (x, y) based on the clipping window
  40. int computeRegionCode(int x, int y, int xmin, int xmax, int ymin, int ymax)
  41. {
  42. int code = INSIDE;
  43. if (x < xmin)
  44. code |= LEFT;
  45. else if (x > xmax)
  46. code |= RIGHT;
  47. if (y < ymin)
  48. code |= BOTTOM;
  49. else if (y > ymax)
  50. code |= TOP;
  51. return code;
  52. }
  53. //line clipping algorithm
  54. // https://github.com/SagarGaniga/computer-graphics/blob/master/Cohen%20Sutherland/CohenSutherland.cpp
  55. bool cohenSutherlandClip(int xmin, int ymin, int xmax, int ymax,
  56. int& x1, int& y1, int& x2, int& y2)
  57. {
  58. int code1, code2;
  59. bool accept = false;
  60. // Compute the region codes for the two endpoints
  61. code1 = computeRegionCode(x1, y1, xmin, xmax, ymin, ymax);
  62. code2 = computeRegionCode(x2, y2, xmin, xmax, ymin, ymax);
  63. while (true)
  64. {
  65. if ((code1 == INSIDE) && (code2 == INSIDE))
  66. {
  67. // Both points are inside, accept the line
  68. accept = true;
  69. break;
  70. }
  71. else if (code1 & code2)
  72. {
  73. // Logical AND is non-zero, both points are outside, reject the line
  74. break;
  75. }
  76. else
  77. {
  78. // Line needs clipping
  79. int codeOut;
  80. float x, y;
  81. // Choose one of the points that is outside
  82. if (code1 != 0)
  83. codeOut = code1;
  84. else
  85. codeOut = code2;
  86. // Find the intersection point
  87. if (codeOut & TOP)
  88. { // point is above the clip window
  89. x = x1 + (x2 - x1) * (ymax - y1) / (y2 - y1);
  90. y = ymax;
  91. }
  92. else if (codeOut & BOTTOM)
  93. { // point is below the clip window
  94. x = x1 + (x2 - x1) * (ymin - y1) / (y2 - y1);
  95. y = ymin;
  96. }
  97. else if (codeOut & RIGHT)
  98. { // point is to the right of the clip window
  99. y = y1 + (y2 - y1) * (xmax - x1) / (x2 - x1);
  100. x = xmax;
  101. }
  102. else if (codeOut & LEFT)
  103. { // point is to the left of the clip window
  104. y = y1 + (y2 - y1) * (xmin - x1) / (x2 - x1);
  105. x = xmin;
  106. }
  107. // Replace the outside point with the intersection point
  108. if (codeOut == code1)
  109. {
  110. x1 = x;
  111. y1 = y;
  112. code1 = computeRegionCode(x1, y1, xmin, xmax, ymin, ymax);
  113. }
  114. else
  115. {
  116. x2 = x;
  117. y2 = y;
  118. code2 = computeRegionCode(x2, y2, xmin, xmax, ymin, ymax);
  119. }
  120. }
  121. }
  122. return accept;
  123. }
  124. #ifdef ACCEL_LINE32_REGION
  125. struct display_pixel_format : pixfmt_rgba32
  126. {
  127. typedef pixfmt_rgba32 base;
  128. using base::base;
  129. AGG_INLINE void line(int x, int y, int dx, int dy, const color_type& c)
  130. {
  131. uint32_t color = rgba2raw(c.r, c.g, c.b, c.a);
  132. int x0 = x, x1 = x + dx, y0 = y, y1 = y+dy;
  133. if(cohenSutherlandClip(0, 0, FRAME_WIDTH, FRAME_HEIGHT, x0, y0, x1, y1))
  134. accel_line(accel_line32_regs, x0, y0, x1, y1, color);
  135. }
  136. //this is used by the renderer_base's clear function
  137. AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c)
  138. {
  139. accel_line(accel_line32_regs, x, y, x+len, y, rgba2raw(c.r, c.g, c.b, c.a));
  140. }
  141. //used for the solid fill portions
  142. AGG_INLINE void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover)
  143. {
  144. if(cover > 127)
  145. copy_hline(x, y, len, c);
  146. }
  147. void attach(rbuf_type& rb) { m_rbuf2 = &rb; base::attach(rb); }
  148. protected:
  149. rbuf_type* m_rbuf2; //FIXME: duplicated!!
  150. };
  151. #else
  152. #error ACCEL_LINE32_REGION not defined
  153. typedef pixfmt_rgba32 display_pixel_format; //pure software implementation
  154. #endif
  155. } //namespace agg
  156. class FontManager
  157. {
  158. typedef agg::font_engine_freetype_int32 FontEngine;
  159. typedef agg::font_cache_manager<FontEngine> FontCacheManager;
  160. FontEngine m_fontEngine;
  161. FontCacheManager m_fontCacheManager;
  162. double m_fontHeight;
  163. public:
  164. FontManager() : m_fontEngine(), m_fontCacheManager(m_fontEngine) { m_fontEngine.flip_y(true); }
  165. void load_font(const char *name, double height, const void *buf = nullptr, size_t bufsize = 0)
  166. {
  167. m_fontEngine.load_font(name, 0, agg::glyph_ren_outline, (const char *) buf, bufsize);
  168. m_fontEngine.height(height);
  169. m_fontHeight = height;
  170. }
  171. agg::path_storage text(const char* str, double x, double y)
  172. {
  173. double start_x = x;
  174. double start_y = y;
  175. agg::trans_affine mtx; //FIXME: needed?
  176. agg::conv_transform<FontCacheManager::path_adaptor_type> tr(m_fontCacheManager.path_adaptor(), mtx);
  177. agg::path_storage path;
  178. int i;
  179. for (i = 0; str[i]; i++)
  180. {
  181. const agg::glyph_cache* glyph = m_fontCacheManager.glyph(str[i]);
  182. if(glyph)
  183. {
  184. if(i)
  185. m_fontCacheManager.add_kerning(&start_x, &start_y);
  186. m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);
  187. path.concat_path(tr, 0);
  188. start_x += glyph->advance_x;
  189. start_y += glyph->advance_y;
  190. }
  191. }
  192. return path;
  193. }
  194. };
  195. class CanvasBase
  196. {
  197. static FontManager *m_fontManager;
  198. public:
  199. typedef agg::rgba8 color_t;
  200. typedef color_t::value_type color_channel_t;
  201. typedef agg::path_storage path_t;
  202. typedef float coord_t;
  203. typedef float angle_radians_t, angle_degrees_t;
  204. protected:
  205. typedef agg::renderer_base<agg::display_pixel_format> renderer_base_t;
  206. typedef agg::rendering_buffer rendering_buffer_t;
  207. typedef agg::conv_curve<path_t> conv_path_t;
  208. renderer_base_t m_ren;
  209. agg::rendering_buffer m_renderbuf;
  210. agg::display_pixel_format m_pixf;
  211. agg::rasterizer_scanline_aa<> m_ras;
  212. agg::scanline_bin m_scanline;
  213. agg::renderer_scanline_bin_solid<renderer_base_t> m_renderer;
  214. int m_width, m_height, m_pitch;
  215. static FontManager& fontManager()
  216. {
  217. if(!m_fontManager)
  218. m_fontManager = new FontManager; //this cannot be initialized at startup
  219. return *m_fontManager;
  220. }
  221. public:
  222. CanvasBase(int width = FRAME_WIDTH, int height = FRAME_HEIGHT, size_t pitch = FRAME_PITCH)
  223. : m_width(width), m_height(height), m_pitch(pitch), m_renderer(m_ren)
  224. {
  225. m_renderbuf.attach((unsigned char *) VIDEO_FRAMEBUFFER_BASE, width, height, pitch);
  226. m_pixf.attach(m_renderbuf);
  227. m_ren.attach(m_pixf);
  228. }
  229. protected:
  230. template <class T>
  231. void render_fill(T& v, color_t color)
  232. {
  233. m_ras.add_path(v);
  234. m_renderer.color(color);
  235. agg::render_scanlines(m_ras, m_scanline, m_renderer);
  236. m_ras.reset();
  237. }
  238. typedef agg::conv_stroke<conv_path_t> conv_stroke_t;
  239. template <class T>
  240. void render_stroke(T& v, color_t color, coord_t width)
  241. {
  242. if (width > 0)
  243. {
  244. conv_path_t conv(v); //FIXME: is conversion allways needed?
  245. conv_stroke_t stroke_curve(conv);
  246. stroke_curve.width(width);
  247. render_fill(stroke_curve, color);
  248. }
  249. }
  250. };
  251. #endif //__ACCEL_CANVAS_H__