#include "evas_common_soft8.h" #include "evas_soft8_scanline_fill.c" /* * All functions except by evas_common_soft8_line_draw() expect x0 <= x1. */ static inline int _in_range(int value, int min, int max) { return min <= value && value <= max; } static inline int _is_xy_inside_clip(int x, int y, const struct RGBA_Draw_Context_clip clip) { if (!clip.use) return 1; if (!_in_range(x, clip.x, clip.x + clip.w - 1)) return 0; if (!_in_range(y, clip.y, clip.y + clip.h - 1)) return 0; return 1; } static inline int _is_x_inside_clip(int x, const struct RGBA_Draw_Context_clip clip) { if (!clip.use) return 1; return _in_range(x, clip.x, clip.x + clip.w - 1); } static inline int _is_y_inside_clip(int y, const struct RGBA_Draw_Context_clip clip) { if (!clip.use) return 1; return _in_range(y, clip.y, clip.y + clip.h - 1); } static inline int _is_xy_inside_rect(int x, int y, int w, int h) { return _in_range(x, 0, w - 1) && _in_range(y, 0, h - 1); } static inline int _is_empty_clip(const struct RGBA_Draw_Context_clip clip) { return clip.w < 1 || clip.h < 1; } static void _soft8_line_point(Soft8_Image * dst, RGBA_Draw_Context * dc, int x, int y) { DATA8 gry8, *dst_itr; DATA8 alpha; if (!_is_xy_inside_rect(x, y, dst->cache_entry.w, dst->cache_entry.h)) return; if (!_is_xy_inside_clip(x, y, dc->clip)) return; dst_itr = dst->pixels + (dst->stride * y) + x; alpha = A_VAL(&dc->col.col); gry8 = GRY_8_FROM_RGB(&dc->col.col); if (alpha == 0xff) _soft8_pt_fill_solid_solid(dst_itr, gry8); else if (alpha > 0) { alpha++; _soft8_pt_fill_transp_solid(dst_itr, gry8, alpha); } } static void _soft8_line_horiz(Soft8_Image * dst, RGBA_Draw_Context * dc, int x0, int x1, int y) { DATA8 gry8, *dst_itr; DATA8 alpha; int w; if (!_is_y_inside_clip(y, dc->clip)) return; if (x0 < dc->clip.x) x0 = dc->clip.x; if (x1 >= dc->clip.x + dc->clip.w) x1 = dc->clip.x + dc->clip.w - 1; w = x1 - x0; if (w < 1) return; dst_itr = dst->pixels + (dst->stride * y) + x0; alpha = A_VAL(&dc->col.col); gry8 = GRY_8_FROM_RGB(&dc->col.col); if (alpha == 0xff) _soft8_scanline_fill_solid_solid(dst_itr, w, gry8); else if (alpha > 0) { alpha++; _soft8_scanline_fill_transp_solid(dst_itr, w, gry8, alpha); } } static void _soft8_line_vert(Soft8_Image * dst, RGBA_Draw_Context * dc, int x, int y0, int y1) { DATA8 gry8, *dst_itr; DATA8 alpha; int h; if (!_is_x_inside_clip(x, dc->clip)) return; if (y1 < y0) { int t; t = y0; y0 = y1; y1 = t; } if (y0 < dc->clip.y) y0 = dc->clip.y; if (y1 >= dc->clip.y + dc->clip.h) y1 = dc->clip.y + dc->clip.h - 1; h = y1 - y0; if (h < 1) return; dst_itr = dst->pixels + (dst->stride * y0) + x; alpha = A_VAL(&dc->col.col); gry8 = GRY_8_FROM_RGB(&dc->col.col); if (alpha == 0xff) { for (; h > 0; h--, dst_itr += dst->stride) _soft8_pt_fill_solid_solid(dst_itr, gry8); } else if (alpha > 0) { alpha++; for (; h > 0; h--, dst_itr += dst->stride) _soft8_pt_fill_transp_solid(dst_itr, gry8, alpha); } } static inline void _soft8_line_45deg_adjust_boundaries(const struct RGBA_Draw_Context_clip clip, int *p_x0, int *p_y0, int *p_x1, int *p_y1) { int diff, dy, x0, y0, x1, y1; x0 = *p_x0; y0 = *p_y0; x1 = *p_x1; y1 = *p_y1; dy = y1 - y0; diff = clip.x - x0; if (diff > 0) { x0 = clip.x; y0 += (dy > 0) ? diff : -diff; } diff = x1 - (clip.x + clip.w); if (diff > 0) { x1 = clip.x + clip.w; y1 += (dy > 0) ? -diff : diff; } if (dy > 0) { diff = clip.y - y0; if (diff > 0) { y0 = clip.y; x0 += diff; } diff = y1 - (clip.y + clip.h); if (diff > 0) { y1 = clip.y + clip.h; x1 -= diff; } } else { diff = clip.y - y1; if (diff > 0) { y1 = clip.y; x1 -= diff; } diff = y0 - (clip.y + clip.h - 1); if (diff > 0) { y0 = clip.y + clip.h - 1; x0 += diff; } } *p_x0 = x0; *p_y0 = y0; *p_x1 = x1; *p_y1 = y1; } static void _soft8_line_45deg(Soft8_Image * dst, RGBA_Draw_Context * dc, int x0, int y0, int x1, int y1) { int dy, step_dst_itr, len; DATA8 alpha; DATA8 *dst_itr, gry8; alpha = A_VAL(&dc->col.col); if (alpha < 1) return; gry8 = GRY_8_FROM_RGB(&dc->col.col); dy = y1 - y0; step_dst_itr = 1 + ((dy > 0) ? dst->stride : -dst->stride); _soft8_line_45deg_adjust_boundaries(dc->clip, &x0, &y0, &x1, &y1); len = (dy > 0) ? (y1 - y0) : (y0 - y1); if (len < 1) return; dst_itr = dst->pixels + dst->stride * y0 + x0; if (alpha == 0xff) { for (; len > 0; len--, dst_itr += step_dst_itr) _soft8_pt_fill_solid_solid(dst_itr, gry8); } else { alpha++; for (; len > 0; len--, dst_itr += step_dst_itr) _soft8_pt_fill_transp_solid(dst_itr, gry8, alpha); } } EFL_ALWAYS_INLINE void _soft8_line_aliased_pt(DATA8 * dst_itr, DATA8 gry8, DATA8 alpha) { if (alpha == 32) _soft8_pt_fill_solid_solid(dst_itr, gry8); else _soft8_pt_fill_transp_solid(dst_itr, gry8, alpha); } static void _soft8_line_aliased(Soft8_Image * dst, RGBA_Draw_Context * dc, int x0, int y0, int x1, int y1) { int dx, dy, step_y, step_dst_itr; DATA8 gry8; DATA8 alpha; alpha = A_VAL(&dc->col.col); if (alpha == 0) return; alpha++; gry8 = GRY_8_FROM_RGB(&dc->col.col); dx = x1 - x0; dy = y1 - y0; if (dy >= 0) { step_y = 1; step_dst_itr = dst->stride; } else { dy = -dy; step_y = -1; step_dst_itr = -dst->stride; } if (dx > dy) { DATA8 *dst_itr; int e, x, y; e = -(dx / 2); y = y0; dst_itr = dst->pixels + dst->stride * y0 + x0; for (x = x0; x <= x1; x++, dst_itr++) { if (_is_xy_inside_clip(x, y, dc->clip)) _soft8_line_aliased_pt(dst_itr, gry8, alpha); e += dy; if (e >= 0) { dst_itr += step_dst_itr; y += step_y; e -= dx; } } } else { DATA8 *dst_itr; int e, x, y; e = -(dy / 2); x = x0; dst_itr = dst->pixels + dst->stride * y0 + x0; for (y = y0; y != y1; y += step_y, dst_itr += step_dst_itr) { if (_is_xy_inside_clip(x, y, dc->clip)) _soft8_line_aliased_pt(dst_itr, gry8, alpha); e += dx; if (e >= 0) { dst_itr++; x++; e -= dy; } } } } void evas_common_soft8_line_draw(Soft8_Image * dst, RGBA_Draw_Context * dc, int x0, int y0, int x1, int y1) { struct RGBA_Draw_Context_clip c_bkp, c_tmp; int dx, dy; int x, y, w, h; c_tmp.use = 1; c_tmp.x = 0; c_tmp.y = 0; c_tmp.w = dst->cache_entry.w; c_tmp.h = dst->cache_entry.h; /* save out clip info */ c_bkp = dc->clip; if (c_bkp.use) { RECTS_CLIP_TO_RECT(c_tmp.x, c_tmp.y, c_tmp.w, c_tmp.h, c_bkp.x, c_bkp.y, c_bkp.w, c_bkp.h); if (_is_empty_clip(c_tmp)) return; } x = MIN(x0, x1); y = MIN(y0, y1); w = MAX(x0, x1) - x + 1; h = MAX(y0, y1) - y + 1; RECTS_CLIP_TO_RECT(c_tmp.x, c_tmp.y, c_tmp.w, c_tmp.h, x, y, w, h); if (_is_empty_clip(c_tmp)) return; /* Check if the line doesn't cross the clip area */ if (x0 < c_tmp.x && x1 < c_tmp.x) return; if (x0 >= c_tmp.x + c_tmp.w && x1 >= c_tmp.x + c_tmp.w) return; if (y0 < c_tmp.y && y1 < c_tmp.y) return; if (y0 >= c_tmp.y + c_tmp.h && y1 >= c_tmp.y + c_tmp.h) return; dc->clip = c_tmp; dx = x1 - x0; dy = y1 - y0; if (dx < 0) { int t; t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; } if (dx == 0 && dy == 0) _soft8_line_point(dst, dc, x0, y0); else if (dx == 0) _soft8_line_vert(dst, dc, x0, y0, y1); else if (dy == 0) _soft8_line_horiz(dst, dc, x0, x1, y0); else if (dy == dx || dy == -dx) _soft8_line_45deg(dst, dc, x0, y0, x1, y1); else _soft8_line_aliased(dst, dc, x0, y0, x1, y1); /* restore clip info */ dc->clip = c_bkp; }