#include "lv_draw_dave2d.h" #if LV_USE_DRAW_DAVE2D #include "../../../misc/lv_area_private.h" static void dave2d_draw_border_complex(lv_draw_dave2d_unit_t * draw_unit, const lv_area_t * outer_area, const lv_area_t * inner_area, int32_t rout, int32_t rin, lv_color_t color, lv_opa_t opa); static void dave2d_draw_border_simple(lv_draw_dave2d_unit_t * draw_unit, const lv_area_t * outer_area, const lv_area_t * inner_area, lv_color_t color, lv_opa_t opa); void lv_draw_dave2d_border(lv_draw_dave2d_unit_t * draw_unit, const lv_draw_border_dsc_t * dsc, const lv_area_t * coords) { if(dsc->opa <= LV_OPA_MIN) return; if(dsc->width == 0) return; if(dsc->side == LV_BORDER_SIDE_NONE) return; int32_t coords_w = lv_area_get_width(coords); int32_t coords_h = lv_area_get_height(coords); int32_t rout = dsc->radius; int32_t short_side = LV_MIN(coords_w, coords_h); if(rout > short_side >> 1) rout = short_side >> 1; /*Get the inner area*/ lv_area_t area_inner; lv_area_copy(&area_inner, coords); area_inner.x1 += ((dsc->side & LV_BORDER_SIDE_LEFT) ? dsc->width : - (dsc->width + rout)); area_inner.x2 -= ((dsc->side & LV_BORDER_SIDE_RIGHT) ? dsc->width : - (dsc->width + rout)); area_inner.y1 += ((dsc->side & LV_BORDER_SIDE_TOP) ? dsc->width : - (dsc->width + rout)); area_inner.y2 -= ((dsc->side & LV_BORDER_SIDE_BOTTOM) ? dsc->width : - (dsc->width + rout)); int32_t rin = rout - dsc->width; if(rin < 0) rin = 0; if(rout == 0 && rin == 0) { dave2d_draw_border_simple(draw_unit, coords, &area_inner, dsc->color, dsc->opa); } else { dave2d_draw_border_complex(draw_unit, coords, &area_inner, rout, rin, dsc->color, dsc->opa); } } static void dave2d_draw_border_simple(lv_draw_dave2d_unit_t * u, const lv_area_t * outer_area, const lv_area_t * inner_area, lv_color_t color, lv_opa_t opa) { lv_area_t clip_area; lv_area_t local_outer_area; lv_area_t local_inner_area; int32_t x; int32_t y; bool is_common; is_common = lv_area_intersect(&clip_area, outer_area, u->base_unit.clip_area); if(!is_common) return; #if LV_USE_OS lv_result_t status; status = lv_mutex_lock(u->pd2Mutex); LV_ASSERT(LV_RESULT_OK == status); #endif local_outer_area = *outer_area; local_inner_area = *inner_area; x = 0 - u->base_unit.target_layer->buf_area.x1; y = 0 - u->base_unit.target_layer->buf_area.y1; lv_area_move(&clip_area, x, y); lv_area_move(&local_outer_area, x, y); lv_area_move(&local_inner_area, x, y); #if D2_RENDER_EACH_OPERATION d2_selectrenderbuffer(u->d2_handle, u->renderbuffer); #endif // // Generate render operations // d2_framebuffer_from_layer(u->d2_handle, u->base_unit.target_layer); d2_setcolor(u->d2_handle, 0, lv_draw_dave2d_lv_colour_to_d2_colour(color)); d2_setalpha(u->d2_handle, opa); d2_cliprect(u->d2_handle, (d2_border)clip_area.x1, (d2_border)clip_area.y1, (d2_border)clip_area.x2, (d2_border)clip_area.y2); lv_area_t a; bool top_side = local_outer_area.y1 <= local_inner_area.y1; bool bottom_side = local_outer_area.y2 >= local_inner_area.y2; bool left_side = local_outer_area.x1 <= local_inner_area.x1; bool right_side = local_outer_area.x2 >= local_inner_area.x2; /*Top*/ a.x1 = local_outer_area.x1; a.x2 = local_outer_area.x2; a.y1 = local_outer_area.y1; a.y2 = local_inner_area.y1 - 1; if(top_side) { d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1), (d2_point)D2_FIX4(a.y1), (d2_point)D2_FIX4(lv_area_get_width(&a)), (d2_point)D2_FIX4(lv_area_get_height(&a))); } /*Bottom*/ a.y1 = local_inner_area.y2 + 1; a.y2 = local_outer_area.y2; if(bottom_side) { d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1), (d2_point)D2_FIX4(a.y1), (d2_point)D2_FIX4(lv_area_get_width(&a)), (d2_point)D2_FIX4(lv_area_get_height(&a))); } /*Left*/ a.x1 = local_outer_area.x1; a.x2 = local_inner_area.x1 - 1; a.y1 = (top_side) ? local_inner_area.y1 : local_outer_area.y1; a.y2 = (bottom_side) ? local_inner_area.y2 : local_outer_area.y2; if(left_side) { d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1), (d2_point)D2_FIX4(a.y1), (d2_point)D2_FIX4(lv_area_get_width(&a)), (d2_point)D2_FIX4(lv_area_get_height(&a))); } /*Right*/ a.x1 = local_inner_area.x2 + 1; a.x2 = local_outer_area.x2; if(right_side) { d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(a.x1), (d2_point)D2_FIX4(a.y1), (d2_point)D2_FIX4(lv_area_get_width(&a)), (d2_point)D2_FIX4(lv_area_get_height(&a))); } // // Execute render operations // #if D2_RENDER_EACH_OPERATION d2_executerenderbuffer(u->d2_handle, u->renderbuffer, 0); d2_flushframe(u->d2_handle); #endif #if LV_USE_OS status = lv_mutex_unlock(u->pd2Mutex); LV_ASSERT(LV_RESULT_OK == status); #endif } static void dave2d_draw_border_complex(lv_draw_dave2d_unit_t * u, const lv_area_t * orig_outer_area, const lv_area_t * orig_inner_area, int32_t rout, int32_t rin, lv_color_t color, lv_opa_t opa) { /*Get clipped draw area which is the real draw area. *It is always the same or inside `coords`*/ lv_area_t draw_area; lv_area_t outer_area; lv_area_t inner_area; int32_t x; int32_t y; d2_s32 result; d2_u32 flags = 0; outer_area = *orig_outer_area; inner_area = *orig_inner_area; if(!lv_area_intersect(&draw_area, &outer_area, u->base_unit.clip_area)) return; #if LV_USE_OS lv_result_t status; status = lv_mutex_lock(u->pd2Mutex); LV_ASSERT(LV_RESULT_OK == status); #endif x = 0 - u->base_unit.target_layer->buf_area.x1; y = 0 - u->base_unit.target_layer->buf_area.y1; lv_area_move(&draw_area, x, y); lv_area_move(&outer_area, x, y); lv_area_move(&inner_area, x, y); #if D2_RENDER_EACH_OPERATION d2_selectrenderbuffer(u->d2_handle, u->renderbuffer); #endif // // Generate render operations // d2_framebuffer_from_layer(u->d2_handle, u->base_unit.target_layer); d2_setcolor(u->d2_handle, 0, lv_draw_dave2d_lv_colour_to_d2_colour(color)); d2_setalpha(u->d2_handle, opa); d2_cliprect(u->d2_handle, (d2_border)draw_area.x1, (d2_border)draw_area.y1, (d2_border)draw_area.x2, (d2_border)draw_area.y2); lv_area_t blend_area; /*Calculate the x and y coordinates where the straight parts area are */ lv_area_t core_area; core_area.x1 = LV_MAX(outer_area.x1 + rout, inner_area.x1); core_area.x2 = LV_MIN(outer_area.x2 - rout, inner_area.x2); core_area.y1 = LV_MAX(outer_area.y1 + rout, inner_area.y1); core_area.y2 = LV_MIN(outer_area.y2 - rout, inner_area.y2); bool top_side = outer_area.y1 <= inner_area.y1; bool bottom_side = outer_area.y2 >= inner_area.y2; /*No masks*/ bool left_side = outer_area.x1 <= inner_area.x1; bool right_side = outer_area.x2 >= inner_area.x2; /*Draw the straight lines first */ if(top_side) { blend_area.x1 = core_area.x1; blend_area.x2 = core_area.x2; blend_area.y1 = outer_area.y1; blend_area.y2 = inner_area.y1 - 1; d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(blend_area.x1), (d2_point)D2_FIX4(blend_area.y1), (d2_point)D2_FIX4(lv_area_get_width(&blend_area)), (d2_point)D2_FIX4(lv_area_get_height(&blend_area))); } if(bottom_side) { blend_area.x1 = core_area.x1; blend_area.x2 = core_area.x2; blend_area.y1 = inner_area.y2 + 1; blend_area.y2 = outer_area.y2; d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(blend_area.x1), (d2_point)D2_FIX4(blend_area.y1), (d2_point)D2_FIX4(lv_area_get_width(&blend_area)), (d2_point)D2_FIX4(lv_area_get_height(&blend_area))); } if(left_side) { blend_area.x1 = outer_area.x1; blend_area.x2 = inner_area.x1 - 1; blend_area.y1 = core_area.y1; blend_area.y2 = core_area.y2; d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(blend_area.x1), (d2_point)D2_FIX4(blend_area.y1), (d2_point)D2_FIX4(lv_area_get_width(&blend_area)), (d2_point)D2_FIX4(lv_area_get_height(&blend_area))); } if(right_side) { blend_area.x1 = inner_area.x2 + 1; blend_area.x2 = outer_area.x2; blend_area.y1 = core_area.y1; blend_area.y2 = core_area.y2; d2_renderbox(u->d2_handle, (d2_point)D2_FIX4(blend_area.x1), (d2_point)D2_FIX4(blend_area.y1), (d2_point)D2_FIX4(lv_area_get_width(&blend_area)), (d2_point)D2_FIX4(lv_area_get_height(&blend_area))); } /*Draw the corners*/ int32_t blend_w; /*Left corners*/ blend_area.x1 = draw_area.x1; blend_area.x2 = LV_MIN(draw_area.x2, core_area.x1 - 1); blend_w = lv_area_get_width(&blend_area); if(blend_w > 0) { d2_s32 aa; aa = d2_getantialiasing(u->d2_handle); d2_setantialiasing(u->d2_handle, 0); //Don't blend with the background according to coverage value if(left_side || top_side) { lv_area_t arc_area; lv_area_t clip_arc; arc_area.x1 = core_area.x1 - rout; arc_area.y1 = core_area.y1 - rout; arc_area.x2 = core_area.x1; arc_area.y2 = core_area.y1; if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) { d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2, (d2_border)clip_arc.y2); result = d2_renderwedge(u->d2_handle, (d2_point)D2_FIX4(core_area.x1), (d2_point) D2_FIX4(core_area.y1), (d2_width) D2_FIX4(rout), (d2_width) D2_FIX4((rout - rin)), (d2_s32) D2_FIX16(0), // 180 Degrees (d2_s32) D2_FIX16((int16_t) -1), (d2_s32) D2_FIX16((int16_t) -1),//( 270 Degrees (d2_s32) D2_FIX16(0), flags); LV_ASSERT(D2_OK == result); } } if(left_side || bottom_side) { lv_area_t arc_area; lv_area_t clip_arc; arc_area.x1 = core_area.x1 - rout; arc_area.y1 = core_area.y2; arc_area.x2 = core_area.x1; arc_area.y2 = core_area.y2 + rout; if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) { d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2, (d2_border)clip_arc.y2); result = d2_renderwedge(u->d2_handle, (d2_point)D2_FIX4(core_area.x1), (d2_point) D2_FIX4(core_area.y2), (d2_width) D2_FIX4(rout), (d2_width) D2_FIX4((rout - rin)), (d2_s32) D2_FIX16((int16_t) -1), //90 degrees (d2_s32) D2_FIX16(0), (d2_s32) D2_FIX16(0), //180 degrees (d2_s32) D2_FIX16(1), flags); LV_ASSERT(D2_OK == result); } } /*Right corners*/ blend_area.x1 = LV_MAX(draw_area.x1, blend_area.x2 + 1); /*To not overlap with the left side*/ blend_area.x1 = LV_MAX(draw_area.x1, core_area.x2 + 1); blend_area.x2 = draw_area.x2; blend_w = lv_area_get_width(&blend_area); if(blend_w > 0) { if(right_side || top_side) { lv_area_t arc_area; lv_area_t clip_arc; arc_area.x1 = core_area.x2; arc_area.y1 = core_area.y1 - rout; arc_area.x2 = core_area.x2 + rout; arc_area.y2 = core_area.y1; if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) { d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2, (d2_border)clip_arc.y2); result = d2_renderwedge(u->d2_handle, (d2_point)D2_FIX4(core_area.x2), (d2_point) D2_FIX4(core_area.y1), (d2_width) D2_FIX4(rout), (d2_width) D2_FIX4((rout - rin)), (d2_s32) D2_FIX16((int16_t)1), // 270 Degrees (d2_s32) D2_FIX16(0), (d2_s32) D2_FIX16(0),// 0 degrees (d2_s32) D2_FIX16(-1), flags); LV_ASSERT(D2_OK == result); } } if(right_side || bottom_side) { lv_area_t arc_area; lv_area_t clip_arc; arc_area.x1 = core_area.x2; arc_area.y1 = core_area.y2; arc_area.x2 = core_area.x2 + rout; arc_area.y2 = core_area.y2 + rout; if(lv_area_intersect(&clip_arc, &arc_area, &draw_area)) { d2_cliprect(u->d2_handle, (d2_border)clip_arc.x1, (d2_border)clip_arc.y1, (d2_border)clip_arc.x2, (d2_border)clip_arc.y2); result = d2_renderwedge(u->d2_handle, (d2_point)D2_FIX4(core_area.x2), (d2_point) D2_FIX4(core_area.y2), (d2_width) D2_FIX4(rout), (d2_width) D2_FIX4((rout - rin)), (d2_s32) D2_FIX16(0),// 0 degrees (d2_s32) D2_FIX16(1), (d2_s32) D2_FIX16(1),// 90 degrees (d2_s32) D2_FIX16(0), flags); LV_ASSERT(D2_OK == result); } } } d2_setantialiasing(u->d2_handle, aa); //restore original setting } // // Execute render operations // #if D2_RENDER_EACH_OPERATION d2_executerenderbuffer(u->d2_handle, u->renderbuffer, 0); d2_flushframe(u->d2_handle); #endif #if LV_USE_OS status = lv_mutex_unlock(u->pd2Mutex); LV_ASSERT(LV_RESULT_OK == status); #endif } #endif /*LV_USE_DRAW_DAVE2D*/