efl/legacy/evas/src/lib/engines/common_16/evas_soft16_line.c

446 lines
8.8 KiB
C

#include "evas_common_soft16.h"
#include "evas_soft16_scanline_fill.c"
/*
* All functions except by evas_common_soft16_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
_soft16_line_point(Soft16_Image *dst, RGBA_Draw_Context *dc, int x, int y)
{
DATA16 rgb565, *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) >> 3;
rgb565 = RGB_565_FROM_COMPONENTS(R_VAL(&dc->col.col),
G_VAL(&dc->col.col),
B_VAL(&dc->col.col));
if (alpha == 31)
_soft16_pt_fill_solid_solid(dst_itr, rgb565);
else if (alpha > 0)
{
DATA32 rgb565_unpack;
rgb565_unpack = RGB_565_UNPACK(rgb565);
alpha++;
_soft16_pt_fill_transp_solid(dst_itr, rgb565_unpack, alpha);
}
}
static void
_soft16_line_horiz(Soft16_Image *dst, RGBA_Draw_Context *dc, int x0, int x1, int y)
{
DATA16 rgb565, *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) >> 3;
rgb565 = RGB_565_FROM_COMPONENTS(R_VAL(&dc->col.col),
G_VAL(&dc->col.col),
B_VAL(&dc->col.col));
if (alpha == 31)
_soft16_scanline_fill_solid_solid(dst_itr, w, rgb565);
else if (alpha > 0)
{
DATA32 rgb565_unpack;
rgb565_unpack = RGB_565_UNPACK(rgb565);
alpha++;
_soft16_scanline_fill_transp_solid(dst_itr, w, rgb565_unpack, alpha);
}
}
static void
_soft16_line_vert(Soft16_Image *dst, RGBA_Draw_Context *dc, int x, int y0, int y1)
{
DATA16 rgb565, *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) >> 3;
rgb565 = RGB_565_FROM_COMPONENTS(R_VAL(&dc->col.col),
G_VAL(&dc->col.col),
B_VAL(&dc->col.col));
if (alpha == 31)
{
for (; h > 0; h--, dst_itr += dst->stride)
_soft16_pt_fill_solid_solid(dst_itr, rgb565);
}
else if (alpha > 0)
{
DATA32 rgb565_unpack;
rgb565_unpack = RGB_565_UNPACK(rgb565);
alpha++;
for (; h > 0; h--, dst_itr += dst->stride)
_soft16_pt_fill_transp_solid(dst_itr, rgb565_unpack, alpha);
}
}
static inline void
_soft16_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
_soft16_line_45deg(Soft16_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1)
{
int dy, step_dst_itr, len;
DATA8 alpha;
DATA16 *dst_itr, rgb565;
alpha = A_VAL(&dc->col.col) >> 3;
if (alpha < 1)
return;
rgb565 = RGB_565_FROM_COMPONENTS(R_VAL(&dc->col.col),
G_VAL(&dc->col.col),
B_VAL(&dc->col.col));
dy = y1 - y0;
step_dst_itr = 1 + ((dy > 0) ? dst->stride : -dst->stride);
_soft16_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 == 31)
{
for (; len > 0; len--, dst_itr += step_dst_itr)
_soft16_pt_fill_solid_solid(dst_itr, rgb565);
}
else
{
DATA32 rgb565_unpack;
rgb565_unpack = RGB_565_UNPACK(rgb565);
alpha++;
for (; len > 0; len--, dst_itr += step_dst_itr)
_soft16_pt_fill_transp_solid(dst_itr, rgb565_unpack, alpha);
}
}
static always_inline void
_soft16_line_aliased_pt(DATA16 *dst_itr, DATA16 rgb565, DATA32 rgb565_unpack, DATA8 alpha)
{
if (alpha == 32)
_soft16_pt_fill_solid_solid(dst_itr, rgb565);
else
_soft16_pt_fill_transp_solid(dst_itr, rgb565_unpack, alpha);
}
static void
_soft16_line_aliased(Soft16_Image *dst, RGBA_Draw_Context *dc, int x0, int y0, int x1, int y1)
{
int dx, dy, step_y, step_dst_itr;
DATA32 rgb565_unpack;
DATA16 rgb565;
DATA8 alpha;
alpha = A_VAL(&dc->col.col) >> 3;
if (alpha == 0)
return;
alpha++;
rgb565 = RGB_565_FROM_COMPONENTS(R_VAL(&dc->col.col),
G_VAL(&dc->col.col),
B_VAL(&dc->col.col));
rgb565_unpack = RGB_565_UNPACK(rgb565);
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)
{
DATA16 *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))
_soft16_line_aliased_pt(dst_itr, rgb565, rgb565_unpack, alpha);
e += dy;
if (e >= 0)
{
dst_itr += step_dst_itr;
y += step_y;
e -= dx;
}
}
}
else
{
DATA16 *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))
_soft16_line_aliased_pt(dst_itr, rgb565, rgb565_unpack, alpha);
e += dx;
if (e >= 0)
{
dst_itr++;
x++;
e -= dy;
}
}
}
}
void
evas_common_soft16_line_draw(Soft16_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.mask = NULL;
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)
_soft16_line_point(dst, dc, x0, y0);
else if (dx == 0)
_soft16_line_vert(dst, dc, x0, y0, y1);
else if (dy == 0)
_soft16_line_horiz(dst, dc, x0, x1, y0);
else if (dy == dx || dy == -dx)
_soft16_line_45deg(dst, dc, x0, y0, x1, y1);
else
_soft16_line_aliased(dst, dc, x0, y0, x1, y1);
/* restore clip info */
dc->clip = c_bkp;
}