2443 lines
63 KiB
C
2443 lines
63 KiB
C
/*
|
|
* File : dc_blend.c
|
|
* This file is part of RT-Thread GUI
|
|
* COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2013-10-04 Bernard porting SDL software render to RT-Thread GUI
|
|
* 2014-05-06 Bernard Add the SDL2_gfx copyright for aa_ecllipse/
|
|
* thick_line etc.
|
|
*/
|
|
|
|
/*
|
|
Simple DirectMedia Layer
|
|
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
|
|
/*
|
|
SDL2_gfx: graphics primitives for SDL
|
|
Copyright (C) 2012 Andreas Schiffler
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source
|
|
distribution.
|
|
|
|
Andreas Schiffler -- aschiffler at ferzkopp dot net
|
|
*/
|
|
|
|
#include <rtgui/dc.h>
|
|
#include <rtgui/dc_draw.h>
|
|
#include <rtgui/color.h>
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#ifdef __CC_ARM
|
|
/* Keil define `abs` in stdlib... */
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#define hw_driver (rtgui_graphic_driver_get_default())
|
|
#define _int_swap(x, y) do {x ^= y; y ^= x; x ^= y;} while (0)
|
|
|
|
rt_inline rt_uint8_t _dc_get_bits_per_pixel(struct rtgui_dc* dc)
|
|
{
|
|
rt_uint8_t bits_per_pixel = 0;
|
|
|
|
if (dc->type == RTGUI_DC_HW || dc->type == RTGUI_DC_CLIENT)
|
|
bits_per_pixel = hw_driver->bits_per_pixel;
|
|
else if (dc->type == RTGUI_DC_BUFFER)
|
|
{
|
|
struct rtgui_dc_buffer *buffer = (struct rtgui_dc_buffer*)dc;
|
|
|
|
bits_per_pixel = rtgui_color_get_bits(buffer->pixel_format);
|
|
}
|
|
|
|
return bits_per_pixel;
|
|
}
|
|
|
|
rt_inline rt_uint16_t _dc_get_pitch(struct rtgui_dc* dc)
|
|
{
|
|
rt_uint16_t pitch = 0;
|
|
|
|
if (dc->type == RTGUI_DC_HW || dc->type == RTGUI_DC_CLIENT)
|
|
pitch = hw_driver->pitch;
|
|
else if (dc->type == RTGUI_DC_BUFFER)
|
|
{
|
|
struct rtgui_dc_buffer *dc_buffer;
|
|
|
|
dc_buffer = (struct rtgui_dc_buffer*)dc;
|
|
pitch = dc_buffer->pitch;
|
|
}
|
|
|
|
return pitch;
|
|
}
|
|
|
|
rt_inline rt_uint8_t* _dc_get_pixel(struct rtgui_dc* dc, int x, int y)
|
|
{
|
|
rt_uint8_t *pixel = RT_NULL;
|
|
|
|
if ((dc->type == RTGUI_DC_HW) || (dc->type == RTGUI_DC_CLIENT))
|
|
{
|
|
pixel = (rt_uint8_t*)(hw_driver->framebuffer);
|
|
if (pixel == RT_NULL) return RT_NULL;
|
|
|
|
pixel = pixel + y * hw_driver->pitch + x * (_UI_BITBYTES(hw_driver->bits_per_pixel));
|
|
}
|
|
else if (dc->type == RTGUI_DC_BUFFER)
|
|
{
|
|
struct rtgui_dc_buffer *dc_buffer;
|
|
|
|
dc_buffer = (struct rtgui_dc_buffer*)dc;
|
|
|
|
pixel = dc_buffer->pixel + y * dc_buffer->pitch +
|
|
x * rtgui_color_get_bpp(dc_buffer->pixel_format);
|
|
}
|
|
|
|
return pixel;
|
|
}
|
|
|
|
/* Use the Cohen-Sutherland algorithm for line clipping */
|
|
#define CODE_BOTTOM 1
|
|
#define CODE_TOP 2
|
|
#define CODE_LEFT 4
|
|
#define CODE_RIGHT 8
|
|
|
|
static int ComputeOutCode(const rtgui_rect_t * rect, int x, int y)
|
|
{
|
|
int code = 0;
|
|
if (y < rect->y1)
|
|
{
|
|
code |= CODE_TOP;
|
|
}
|
|
else if (y > rect->y2)
|
|
{
|
|
code |= CODE_BOTTOM;
|
|
}
|
|
|
|
if (x < rect->x1)
|
|
{
|
|
code |= CODE_LEFT;
|
|
}
|
|
else if (x > rect->x2)
|
|
{
|
|
code |= CODE_RIGHT;
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
static rt_bool_t _intersect_rect_line(const rtgui_rect_t* rect,
|
|
int *X1, int *Y1,
|
|
int *X2, int *Y2)
|
|
{
|
|
int x = 0;
|
|
int y = 0;
|
|
int x1, y1;
|
|
int x2, y2;
|
|
int rectx1;
|
|
int recty1;
|
|
int rectx2;
|
|
int recty2;
|
|
int outcode1, outcode2;
|
|
|
|
x1 = *X1;
|
|
y1 = *Y1;
|
|
x2 = *X2;
|
|
y2 = *Y2;
|
|
rectx1 = rect->x1;
|
|
recty1 = rect->y1;
|
|
rectx2 = rect->x2 - 1;
|
|
recty2 = rect->y2 - 1;
|
|
|
|
/* Check to see if entire line is inside rect */
|
|
if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 &&
|
|
y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) {
|
|
return RT_TRUE;
|
|
}
|
|
|
|
/* Check to see if entire line is to one side of rect */
|
|
if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) ||
|
|
(y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) {
|
|
return RT_FALSE;
|
|
}
|
|
|
|
if (y1 == y2) {
|
|
/* Horizontal line, easy to clip */
|
|
if (x1 < rectx1) {
|
|
*X1 = rectx1;
|
|
} else if (x1 > rectx2) {
|
|
*X1 = rectx2;
|
|
}
|
|
if (x2 < rectx1) {
|
|
*X2 = rectx1;
|
|
} else if (x2 > rectx2) {
|
|
*X2 = rectx2;
|
|
}
|
|
return RT_TRUE;
|
|
}
|
|
|
|
if (x1 == x2) {
|
|
/* Vertical line, easy to clip */
|
|
if (y1 < recty1) {
|
|
*Y1 = recty1;
|
|
} else if (y1 > recty2) {
|
|
*Y1 = recty2;
|
|
}
|
|
if (y2 < recty1) {
|
|
*Y2 = recty1;
|
|
} else if (y2 > recty2) {
|
|
*Y2 = recty2;
|
|
}
|
|
return RT_TRUE;
|
|
}
|
|
|
|
/* More complicated Cohen-Sutherland algorithm */
|
|
outcode1 = ComputeOutCode(rect, x1, y1);
|
|
outcode2 = ComputeOutCode(rect, x2, y2);
|
|
while (outcode1 || outcode2) {
|
|
if (outcode1 & outcode2) {
|
|
return RT_FALSE;
|
|
}
|
|
|
|
if (outcode1) {
|
|
if (outcode1 & CODE_TOP) {
|
|
y = recty1;
|
|
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
|
} else if (outcode1 & CODE_BOTTOM) {
|
|
y = recty2;
|
|
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
|
} else if (outcode1 & CODE_LEFT) {
|
|
x = rectx1;
|
|
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
|
} else if (outcode1 & CODE_RIGHT) {
|
|
x = rectx2;
|
|
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
|
}
|
|
x1 = x;
|
|
y1 = y;
|
|
outcode1 = ComputeOutCode(rect, x, y);
|
|
} else {
|
|
if (outcode2 & CODE_TOP) {
|
|
y = recty1;
|
|
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
|
} else if (outcode2 & CODE_BOTTOM) {
|
|
y = recty2;
|
|
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
|
} else if (outcode2 & CODE_LEFT) {
|
|
x = rectx1;
|
|
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
|
} else if (outcode2 & CODE_RIGHT) {
|
|
x = rectx2;
|
|
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
|
}
|
|
x2 = x;
|
|
y2 = y;
|
|
outcode2 = ComputeOutCode(rect, x, y);
|
|
}
|
|
}
|
|
|
|
*X1 = x1;
|
|
*Y1 = y1;
|
|
*X2 = x2;
|
|
*Y2 = y2;
|
|
|
|
return RT_TRUE;
|
|
}
|
|
|
|
static void
|
|
_dc_draw_line1(struct rtgui_dc * dst, int x1, int y1, int x2, int y2, rtgui_color_t color,
|
|
rt_bool_t draw_end)
|
|
{
|
|
if (y1 == y2) {
|
|
int length;
|
|
int pitch = _dc_get_pitch(dst);
|
|
rt_uint8_t *pixel;
|
|
if (x1 <= x2) {
|
|
pixel = (rt_uint8_t *)_dc_get_pixel(dst, x1, y1);
|
|
length = draw_end ? (x2-x1+1) : (x2-x1);
|
|
} else {
|
|
pixel = (rt_uint8_t *)_dc_get_pixel(dst, x2, y1);
|
|
if (!draw_end) {
|
|
++pixel;
|
|
}
|
|
length = draw_end ? (x1-x2+1) : (x1-x2);
|
|
}
|
|
rt_memset(pixel, color, length);
|
|
} else if (x1 == x2) {
|
|
VLINE(rt_uint8_t, DRAW_FASTSETPIXEL1, draw_end);
|
|
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
|
|
DLINE(rt_uint8_t, DRAW_FASTSETPIXEL1, draw_end);
|
|
} else {
|
|
BLINE(x1, y1, x2, y2, DRAW_FASTSETPIXELXY1, draw_end);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_dc_draw_line2(struct rtgui_dc * dst, int x1, int y1, int x2, int y2, rtgui_color_t c,
|
|
rt_bool_t draw_end)
|
|
{
|
|
rt_uint16_t color;
|
|
|
|
if (rtgui_dc_get_pixel_format(dst) == RTGRAPHIC_PIXEL_FORMAT_RGB565)
|
|
color = rtgui_color_to_565(c);
|
|
else
|
|
color = rtgui_color_to_565p(c);
|
|
|
|
if (y1 == y2) {
|
|
HLINE(rt_uint16_t, DRAW_FASTSETPIXEL2, draw_end);
|
|
} else if (x1 == x2) {
|
|
VLINE(rt_uint16_t, DRAW_FASTSETPIXEL2, draw_end);
|
|
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
|
|
DLINE(rt_uint16_t, DRAW_FASTSETPIXEL2, draw_end);
|
|
} else {
|
|
rt_uint8_t _r, _g, _b, _a;
|
|
|
|
_r = RTGUI_RGB_R(c);
|
|
_g = RTGUI_RGB_G(c);
|
|
_b = RTGUI_RGB_B(c);
|
|
_a = RTGUI_RGB_A(c);
|
|
|
|
if (rtgui_dc_get_pixel_format(dst) == RTGRAPHIC_PIXEL_FORMAT_RGB565)
|
|
{
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB565,
|
|
draw_end);
|
|
}
|
|
else if (rtgui_dc_get_pixel_format(dst) == RTGRAPHIC_PIXEL_FORMAT_BGR565)
|
|
{
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_BGR565,
|
|
draw_end);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_dc_draw_line4(struct rtgui_dc * dst, int x1, int y1, int x2, int y2, rtgui_color_t color,
|
|
rt_bool_t draw_end)
|
|
{
|
|
if (y1 == y2) {
|
|
HLINE(rt_uint32_t, DRAW_FASTSETPIXEL4, draw_end);
|
|
} else if (x1 == x2) {
|
|
VLINE(rt_uint32_t, DRAW_FASTSETPIXEL4, draw_end);
|
|
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
|
|
DLINE(rt_uint32_t, DRAW_FASTSETPIXEL4, draw_end);
|
|
} else {
|
|
rt_uint8_t _r, _g, _b, _a;
|
|
_r = RTGUI_RGB_R(color);
|
|
_g = RTGUI_RGB_G(color);
|
|
_b = RTGUI_RGB_B(color);
|
|
_a = RTGUI_RGB_A(color);
|
|
|
|
if (rtgui_dc_get_pixel_format(dst) == RTGRAPHIC_PIXEL_FORMAT_RGB888)
|
|
{
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_RGB888,
|
|
draw_end);
|
|
}
|
|
else if (rtgui_dc_get_pixel_format(dst) == RTGRAPHIC_PIXEL_FORMAT_ARGB888)
|
|
{
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_ARGB8888,
|
|
draw_end);
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef void (*DrawLineFunc) (struct rtgui_dc * dst,
|
|
int x1, int y1, int x2, int y2,
|
|
rtgui_color_t color, rt_bool_t draw_end);
|
|
|
|
static DrawLineFunc
|
|
_dc_calc_draw_line_func(int bpp)
|
|
{
|
|
switch (bpp) {
|
|
case 1:
|
|
return _dc_draw_line1;
|
|
case 2:
|
|
return _dc_draw_line2;
|
|
case 4:
|
|
return _dc_draw_line4;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void _do_draw_line(struct rtgui_dc * dst,
|
|
rtgui_color_t color,
|
|
int x1, int y1,
|
|
int x2, int y2,
|
|
rt_bool_t draw_end)
|
|
{
|
|
int bpp;
|
|
DrawLineFunc func;
|
|
|
|
bpp = _dc_get_bits_per_pixel(dst);
|
|
if (bpp < 8)
|
|
return;
|
|
|
|
func = _dc_calc_draw_line_func(bpp/8);
|
|
if (!func)
|
|
{
|
|
rt_kprintf("dc_draw_line(): Unsupported pixel format\n");
|
|
return;
|
|
}
|
|
|
|
/* perform clip */
|
|
if (dst->type == RTGUI_DC_CLIENT)
|
|
{
|
|
rtgui_widget_t *owner;
|
|
|
|
/* get owner */
|
|
owner = RTGUI_CONTAINER_OF(dst, struct rtgui_widget, dc_type);
|
|
|
|
x1 = x1 + owner->extent.x1;
|
|
x2 = x2 + owner->extent.x1;
|
|
y1 = y1 + owner->extent.y1;
|
|
y2 = y2 + owner->extent.y1;
|
|
|
|
if (owner->clip.data == RT_NULL)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
|
|
/* no clip */
|
|
prect = &(owner->clip.extents);
|
|
|
|
/* calculate line intersect */
|
|
if (_intersect_rect_line(prect, &x1, &y1, &x2, &y2) == RT_FALSE)
|
|
return;
|
|
|
|
/* draw line */
|
|
func(dst, x1, y1, x2, y2, color, draw_end);
|
|
}
|
|
else
|
|
{
|
|
register rt_base_t index;
|
|
|
|
for (index = 0; index < rtgui_region_num_rects(&(owner->clip)); index ++)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
int draw_x1, draw_x2;
|
|
int draw_y1, draw_y2;
|
|
|
|
prect = ((rtgui_rect_t *)(owner->clip.data + index + 1));
|
|
draw_x1 = x1; draw_x2 = x2;
|
|
draw_y1 = y1; draw_y2 = y2;
|
|
|
|
/* calculate line intersect */
|
|
if (_intersect_rect_line(prect, &draw_x1, &draw_y1, &draw_x2, &draw_y2) == RT_FALSE)
|
|
continue;
|
|
|
|
/* draw line */
|
|
func(dst, draw_x1, draw_y1, draw_x2, draw_y2, color, draw_end);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dst->type == RTGUI_DC_HW)
|
|
{
|
|
rtgui_widget_t *owner;
|
|
rtgui_rect_t *prect;
|
|
/* no clip */
|
|
struct rtgui_dc_hw *dc_hw = (struct rtgui_dc_hw*)dst;
|
|
|
|
owner = dc_hw->owner;
|
|
|
|
x1 = x1 + owner->extent.x1;
|
|
x2 = x2 + owner->extent.x1;
|
|
y1 = y1 + owner->extent.y1;
|
|
y2 = y2 + owner->extent.y1;
|
|
|
|
prect = &(owner->clip.extents);
|
|
if (_intersect_rect_line(prect, &x1, &y1, &x2, &y2) == RT_FALSE)
|
|
return;
|
|
}
|
|
else if (dst->type == RTGUI_DC_BUFFER)
|
|
{
|
|
rtgui_rect_t rect;
|
|
struct rtgui_dc_buffer *pbf = (struct rtgui_dc_buffer *)dst;
|
|
|
|
rect.x1 = rect.y1 = 0;
|
|
rect.x2 = pbf->width;
|
|
rect.y2 = pbf->height;
|
|
if (_intersect_rect_line(&rect, &x1, &y1, &x2, &y2) == RT_FALSE)
|
|
return;
|
|
}
|
|
|
|
func(dst, x1, y1, x2, y2, color, draw_end);
|
|
}
|
|
}
|
|
|
|
void rtgui_dc_draw_aa_line(struct rtgui_dc * dst, int x1, int y1, int x2, int y2)
|
|
{
|
|
rtgui_color_t color;
|
|
|
|
RT_ASSERT(dst != RT_NULL);
|
|
if (!rtgui_dc_get_visible(dst))
|
|
return;
|
|
/* we do not support pixel DC */
|
|
if (_dc_get_pixel(dst, 0, 0) == RT_NULL)
|
|
return;
|
|
|
|
color = rtgui_dc_get_gc(dst)->foreground;
|
|
|
|
_do_draw_line(dst, color, x1, y1, x2, y2, RT_FALSE);
|
|
}
|
|
RTM_EXPORT(rtgui_dc_draw_aa_line);
|
|
|
|
void rtgui_dc_draw_aa_lines(struct rtgui_dc * dst, const struct rtgui_point * points, int count)
|
|
{
|
|
int i;
|
|
int x1, y1;
|
|
int x2, y2;
|
|
rtgui_color_t color;
|
|
|
|
RT_ASSERT(dst);
|
|
if (!rtgui_dc_get_visible(dst))
|
|
return;
|
|
/* we do not support pixel DC */
|
|
if (_dc_get_pixel(dst, 0, 0) == RT_NULL)
|
|
return;
|
|
|
|
color = rtgui_dc_get_gc(dst)->foreground;
|
|
|
|
for (i = 1; i < count; ++i)
|
|
{
|
|
rt_bool_t draw_end;
|
|
|
|
x1 = points[i-1].x;
|
|
y1 = points[i-1].y;
|
|
x2 = points[i].x;
|
|
y2 = points[i].y;
|
|
|
|
/* Draw the end if it was clipped */
|
|
draw_end = (x2 != points[i].x || y2 != points[i].y);
|
|
_do_draw_line(dst, color, x1, y1, x2, y2, draw_end);
|
|
}
|
|
|
|
if (points[0].x != points[count-1].x || points[0].y != points[count-1].y)
|
|
{
|
|
rtgui_dc_draw_point(dst, points[count-1].x, points[count-1].y);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
static int
|
|
_dc_blend_point_rgb565(struct rtgui_dc * dst, int x, int y, enum RTGUI_BLENDMODE blendMode, rt_uint8_t r,
|
|
rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
unsigned inva = 0xff - a;
|
|
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
DRAW_SETPIXELXY_BLEND_RGB565(x, y);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
DRAW_SETPIXELXY_ADD_RGB565(x, y);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
DRAW_SETPIXELXY_MOD_RGB565(x, y);
|
|
break;
|
|
default:
|
|
DRAW_SETPIXELXY_RGB565(x, y);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_dc_blend_point_bgr565(struct rtgui_dc * dst, int x, int y, enum RTGUI_BLENDMODE blendMode, rt_uint8_t r,
|
|
rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
unsigned inva = 0xff - a;
|
|
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
DRAW_SETPIXELXY_BLEND_BGR565(x, y);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
DRAW_SETPIXELXY_ADD_BGR565(x, y);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
DRAW_SETPIXELXY_MOD_BGR565(x, y);
|
|
break;
|
|
default:
|
|
DRAW_SETPIXELXY_BGR565(x, y);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_dc_blend_point_rgb888(struct rtgui_dc * dst, int x, int y, enum RTGUI_BLENDMODE blendMode, rt_uint8_t r,
|
|
rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
unsigned inva = 0xff - a;
|
|
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
DRAW_SETPIXELXY_BLEND_RGB888(x, y);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
DRAW_SETPIXELXY_ADD_RGB888(x, y);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
DRAW_SETPIXELXY_MOD_RGB888(x, y);
|
|
break;
|
|
default:
|
|
DRAW_SETPIXELXY_RGB888(x, y);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_dc_blend_point_argb8888(struct rtgui_dc * dst, int x, int y, enum RTGUI_BLENDMODE blendMode,
|
|
rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
unsigned inva = 0xff - a;
|
|
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
DRAW_SETPIXELXY_BLEND_ARGB8888(x, y);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
DRAW_SETPIXELXY_ADD_ARGB8888(x, y);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
DRAW_SETPIXELXY_MOD_ARGB8888(x, y);
|
|
break;
|
|
default:
|
|
DRAW_SETPIXELXY_ARGB8888(x, y);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
rtgui_dc_blend_point(struct rtgui_dc * dst, int x, int y, enum RTGUI_BLENDMODE blendMode, rt_uint8_t r,
|
|
rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
RT_ASSERT(dst != RT_NULL);
|
|
|
|
/* Negative coordinates are always invisible. */
|
|
if (x < 0 || y < 0)
|
|
return;
|
|
|
|
if (!rtgui_dc_get_visible(dst)) return;
|
|
/* we do not support pixel DC */
|
|
if (_dc_get_pixel(dst, 0, 0) == RT_NULL) return;
|
|
|
|
/* Perform clipping */
|
|
if (dst->type == RTGUI_DC_CLIENT)
|
|
{
|
|
rtgui_widget_t *owner;
|
|
rtgui_rect_t rect;
|
|
|
|
/* get owner */
|
|
owner = RTGUI_CONTAINER_OF(dst, struct rtgui_widget, dc_type);
|
|
|
|
x = x + owner->extent.x1;
|
|
y = y + owner->extent.y1;
|
|
|
|
if (rtgui_region_contains_point(&(owner->clip), x, y, &rect) != RT_EOK)
|
|
return ;
|
|
}
|
|
else if (dst->type == RTGUI_DC_HW)
|
|
{
|
|
struct rtgui_dc_hw *dc = (struct rtgui_dc_hw *) dst;
|
|
|
|
x = x + dc->owner->extent.x1;
|
|
y = y + dc->owner->extent.y1;
|
|
if (x >= dc->owner->extent.x2)
|
|
return;
|
|
if (y >= dc->owner->extent.y2)
|
|
return;
|
|
}
|
|
else if (dst->type == RTGUI_DC_BUFFER)
|
|
{
|
|
struct rtgui_dc_buffer *dc = (struct rtgui_dc_buffer *) dst;
|
|
|
|
if (x >= dc->width || y >= dc->height)
|
|
return;
|
|
}
|
|
|
|
if (blendMode == RTGUI_BLENDMODE_BLEND || blendMode == RTGUI_BLENDMODE_ADD) {
|
|
r = DRAW_MUL(r, a);
|
|
g = DRAW_MUL(g, a);
|
|
b = DRAW_MUL(b, a);
|
|
}
|
|
|
|
switch (rtgui_dc_get_pixel_format(dst)) {
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB565:
|
|
_dc_blend_point_rgb565(dst, x, y, blendMode, r, g, b, a);
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_BGR565:
|
|
_dc_blend_point_bgr565(dst, x, y, blendMode, r, g, b, a);
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB888:
|
|
_dc_blend_point_rgb888(dst, x, y, blendMode, r, g, b, a);
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
|
|
_dc_blend_point_argb8888(dst, x, y, blendMode, r, g, b, a);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
RTM_EXPORT(rtgui_dc_blend_point);
|
|
|
|
void
|
|
rtgui_dc_blend_points(struct rtgui_dc *dst, const rtgui_point_t *points, int count,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
int i;
|
|
int x, y;
|
|
int (*func)(struct rtgui_dc * dst, int x, int y,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a) = NULL;
|
|
|
|
RT_ASSERT(dst != RT_NULL);
|
|
if (!rtgui_dc_get_visible(dst)) return;
|
|
/* we do not support pixel DC */
|
|
if (_dc_get_pixel(dst, 0, 0) == RT_NULL) return;
|
|
|
|
if (blendMode == RTGUI_BLENDMODE_BLEND || blendMode == RTGUI_BLENDMODE_ADD)
|
|
{
|
|
r = DRAW_MUL(r, a);
|
|
g = DRAW_MUL(g, a);
|
|
b = DRAW_MUL(b, a);
|
|
}
|
|
|
|
/* FIXME: Does this function pointer slow things down significantly? */
|
|
switch (rtgui_dc_get_pixel_format(dst))
|
|
{
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB565:
|
|
func = _dc_blend_point_rgb565;
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB888:
|
|
func = _dc_blend_point_rgb888;
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
|
|
func = _dc_blend_point_argb8888;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
/* get owner */
|
|
if (dst->type == RTGUI_DC_CLIENT)
|
|
{
|
|
rtgui_widget_t *owner;
|
|
rtgui_rect_t rect;
|
|
|
|
owner = RTGUI_CONTAINER_OF(dst, struct rtgui_widget, dc_type);
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
x = points[i].x;
|
|
y = points[i].y;
|
|
|
|
/* Perform clipping */
|
|
x = x + owner->extent.x1;
|
|
y = y + owner->extent.y1;
|
|
|
|
if (rtgui_region_contains_point(&(owner->clip), x, y, &rect) != RT_EOK)
|
|
continue;
|
|
|
|
func(dst, x, y, blendMode, r, g, b, a);
|
|
}
|
|
}
|
|
else if (dst->type == RTGUI_DC_HW)
|
|
{
|
|
struct rtgui_dc_hw *dc = (struct rtgui_dc_hw *) dst;
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
x = points[i].x;
|
|
y = points[i].y;
|
|
|
|
x = x + dc->owner->extent.x1;
|
|
y = y + dc->owner->extent.y1;
|
|
if (x > dc->owner->extent.x2) return;
|
|
if (y > dc->owner->extent.y2) return;
|
|
|
|
func(dst, x, y, blendMode, r, g, b, a);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
x = points[i].x;
|
|
y = points[i].y;
|
|
|
|
func(dst, x, y, blendMode, r, g, b, a);
|
|
}
|
|
}
|
|
}
|
|
RTM_EXPORT(rtgui_dc_blend_points);
|
|
|
|
static void
|
|
_dc_blend_line_rgb565(struct rtgui_dc * dst, int x1, int y1, int x2, int y2,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t _r, rt_uint8_t _g, rt_uint8_t _b, rt_uint8_t _a,
|
|
rt_bool_t draw_end)
|
|
{
|
|
unsigned r, g, b, a, inva;
|
|
|
|
if (blendMode == RTGUI_BLENDMODE_BLEND || blendMode == RTGUI_BLENDMODE_ADD) {
|
|
r = DRAW_MUL(_r, _a);
|
|
g = DRAW_MUL(_g, _a);
|
|
b = DRAW_MUL(_b, _a);
|
|
a = _a;
|
|
} else {
|
|
r = _r;
|
|
g = _g;
|
|
b = _b;
|
|
a = _a;
|
|
}
|
|
inva = (a ^ 0xff);
|
|
|
|
if (y1 == y2) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
HLINE(rt_uint16_t, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
HLINE(rt_uint16_t, DRAW_SETPIXEL_ADD_RGB565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
HLINE(rt_uint16_t, DRAW_SETPIXEL_MOD_RGB565, draw_end);
|
|
break;
|
|
default:
|
|
HLINE(rt_uint16_t, DRAW_SETPIXEL_RGB565, draw_end);
|
|
break;
|
|
}
|
|
} else if (x1 == x2) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
VLINE(rt_uint16_t, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
VLINE(rt_uint16_t, DRAW_SETPIXEL_ADD_RGB565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
VLINE(rt_uint16_t, DRAW_SETPIXEL_MOD_RGB565, draw_end);
|
|
break;
|
|
default:
|
|
VLINE(rt_uint16_t, DRAW_SETPIXEL_RGB565, draw_end);
|
|
break;
|
|
}
|
|
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
DLINE(rt_uint16_t, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
DLINE(rt_uint16_t, DRAW_SETPIXEL_ADD_RGB565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
DLINE(rt_uint16_t, DRAW_SETPIXEL_MOD_RGB565, draw_end);
|
|
break;
|
|
default:
|
|
DLINE(rt_uint16_t, DRAW_SETPIXEL_RGB565, draw_end);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_BLEND_RGB565, DRAW_SETPIXELXY_BLEND_RGB565,
|
|
draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_ADD_RGB565, DRAW_SETPIXELXY_ADD_RGB565,
|
|
draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_MOD_RGB565, DRAW_SETPIXELXY_MOD_RGB565,
|
|
draw_end);
|
|
break;
|
|
default:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_RGB565, DRAW_SETPIXELXY_BLEND_RGB565,
|
|
draw_end);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_dc_blend_line_bgr565(struct rtgui_dc * dst, int x1, int y1, int x2, int y2,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t _r, rt_uint8_t _g, rt_uint8_t _b, rt_uint8_t _a,
|
|
rt_bool_t draw_end)
|
|
{
|
|
unsigned r, g, b, a, inva;
|
|
|
|
if (blendMode == RTGUI_BLENDMODE_BLEND || blendMode == RTGUI_BLENDMODE_ADD) {
|
|
r = DRAW_MUL(_r, _a);
|
|
g = DRAW_MUL(_g, _a);
|
|
b = DRAW_MUL(_b, _a);
|
|
a = _a;
|
|
} else {
|
|
r = _r;
|
|
g = _g;
|
|
b = _b;
|
|
a = _a;
|
|
}
|
|
inva = (a ^ 0xff);
|
|
|
|
if (y1 == y2) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
HLINE(rt_uint16_t, DRAW_SETPIXEL_BLEND_BGR565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
HLINE(rt_uint16_t, DRAW_SETPIXEL_ADD_BGR565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
HLINE(rt_uint16_t, DRAW_SETPIXEL_MOD_BGR565, draw_end);
|
|
break;
|
|
default:
|
|
HLINE(rt_uint16_t, DRAW_SETPIXEL_BGR565, draw_end);
|
|
break;
|
|
}
|
|
} else if (x1 == x2) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
VLINE(rt_uint16_t, DRAW_SETPIXEL_BLEND_BGR565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
VLINE(rt_uint16_t, DRAW_SETPIXEL_ADD_BGR565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
VLINE(rt_uint16_t, DRAW_SETPIXEL_MOD_BGR565, draw_end);
|
|
break;
|
|
default:
|
|
VLINE(rt_uint16_t, DRAW_SETPIXEL_BGR565, draw_end);
|
|
break;
|
|
}
|
|
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
DLINE(rt_uint16_t, DRAW_SETPIXEL_BLEND_BGR565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
DLINE(rt_uint16_t, DRAW_SETPIXEL_ADD_BGR565, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
DLINE(rt_uint16_t, DRAW_SETPIXEL_MOD_BGR565, draw_end);
|
|
break;
|
|
default:
|
|
DLINE(rt_uint16_t, DRAW_SETPIXEL_BGR565, draw_end);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_BLEND_BGR565, DRAW_SETPIXELXY_BLEND_BGR565,
|
|
draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_ADD_BGR565, DRAW_SETPIXELXY_ADD_BGR565,
|
|
draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_MOD_BGR565, DRAW_SETPIXELXY_MOD_BGR565,
|
|
draw_end);
|
|
break;
|
|
default:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_BGR565, DRAW_SETPIXELXY_BLEND_BGR565,
|
|
draw_end);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_dc_blend_line_rgb888(struct rtgui_dc * dst, int x1, int y1, int x2, int y2,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t _r, rt_uint8_t _g, rt_uint8_t _b, rt_uint8_t _a,
|
|
rt_bool_t draw_end)
|
|
{
|
|
unsigned r, g, b, a, inva;
|
|
|
|
if (blendMode == RTGUI_BLENDMODE_BLEND || blendMode == RTGUI_BLENDMODE_ADD) {
|
|
r = DRAW_MUL(_r, _a);
|
|
g = DRAW_MUL(_g, _a);
|
|
b = DRAW_MUL(_b, _a);
|
|
a = _a;
|
|
} else {
|
|
r = _r;
|
|
g = _g;
|
|
b = _b;
|
|
a = _a;
|
|
}
|
|
inva = (a ^ 0xff);
|
|
|
|
if (y1 == y2) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
HLINE(rt_uint32_t, DRAW_SETPIXEL_BLEND_RGB888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
HLINE(rt_uint32_t, DRAW_SETPIXEL_ADD_RGB888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
HLINE(rt_uint32_t, DRAW_SETPIXEL_MOD_RGB888, draw_end);
|
|
break;
|
|
default:
|
|
HLINE(rt_uint32_t, DRAW_SETPIXEL_RGB888, draw_end);
|
|
break;
|
|
}
|
|
} else if (x1 == x2) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
VLINE(rt_uint32_t, DRAW_SETPIXEL_BLEND_RGB888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
VLINE(rt_uint32_t, DRAW_SETPIXEL_ADD_RGB888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
VLINE(rt_uint32_t, DRAW_SETPIXEL_MOD_RGB888, draw_end);
|
|
break;
|
|
default:
|
|
VLINE(rt_uint32_t, DRAW_SETPIXEL_RGB888, draw_end);
|
|
break;
|
|
}
|
|
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
DLINE(rt_uint32_t, DRAW_SETPIXEL_BLEND_RGB888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
DLINE(rt_uint32_t, DRAW_SETPIXEL_ADD_RGB888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
DLINE(rt_uint32_t, DRAW_SETPIXEL_MOD_RGB888, draw_end);
|
|
break;
|
|
default:
|
|
DLINE(rt_uint32_t, DRAW_SETPIXEL_RGB888, draw_end);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_BLEND_RGB888, DRAW_SETPIXELXY_BLEND_RGB888,
|
|
draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_ADD_RGB888, DRAW_SETPIXELXY_ADD_RGB888,
|
|
draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_MOD_RGB888, DRAW_SETPIXELXY_MOD_RGB888,
|
|
draw_end);
|
|
break;
|
|
default:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_RGB888, DRAW_SETPIXELXY_BLEND_RGB888,
|
|
draw_end);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_dc_blend_line_argb8888(struct rtgui_dc * dst, int x1, int y1, int x2, int y2,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t _r, rt_uint8_t _g, rt_uint8_t _b, rt_uint8_t _a,
|
|
rt_bool_t draw_end)
|
|
{
|
|
unsigned r, g, b, a, inva;
|
|
|
|
if (blendMode == RTGUI_BLENDMODE_BLEND || blendMode == RTGUI_BLENDMODE_ADD) {
|
|
r = DRAW_MUL(_r, _a);
|
|
g = DRAW_MUL(_g, _a);
|
|
b = DRAW_MUL(_b, _a);
|
|
a = _a;
|
|
} else {
|
|
r = _r;
|
|
g = _g;
|
|
b = _b;
|
|
a = _a;
|
|
}
|
|
inva = (a ^ 0xff);
|
|
|
|
if (y1 == y2) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
HLINE(rt_uint32_t, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
HLINE(rt_uint32_t, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
HLINE(rt_uint32_t, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
|
|
break;
|
|
default:
|
|
HLINE(rt_uint32_t, DRAW_SETPIXEL_ARGB8888, draw_end);
|
|
break;
|
|
}
|
|
} else if (x1 == x2) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
VLINE(rt_uint32_t, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
VLINE(rt_uint32_t, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
VLINE(rt_uint32_t, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
|
|
break;
|
|
default:
|
|
VLINE(rt_uint32_t, DRAW_SETPIXEL_ARGB8888, draw_end);
|
|
break;
|
|
}
|
|
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
DLINE(rt_uint32_t, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
DLINE(rt_uint32_t, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
DLINE(rt_uint32_t, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
|
|
break;
|
|
default:
|
|
DLINE(rt_uint32_t, DRAW_SETPIXEL_ARGB8888, draw_end);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_BLEND_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888,
|
|
draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_ADD_ARGB8888, DRAW_SETPIXELXY_ADD_ARGB8888,
|
|
draw_end);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_MOD_ARGB8888, DRAW_SETPIXELXY_MOD_ARGB8888,
|
|
draw_end);
|
|
break;
|
|
default:
|
|
AALINE(x1, y1, x2, y2,
|
|
DRAW_SETPIXELXY_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888,
|
|
draw_end);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef void (*BlendLineFunc) (struct rtgui_dc * dst,
|
|
int x1, int y1, int x2, int y2,
|
|
enum RTGUI_BLENDMODE blendMode,
|
|
rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a,
|
|
rt_bool_t draw_end);
|
|
|
|
static BlendLineFunc
|
|
_dc_calc_blend_line_func(rt_uint8_t pixel_format)
|
|
{
|
|
switch (pixel_format)
|
|
{
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB565:
|
|
return _dc_blend_line_rgb565;
|
|
case RTGRAPHIC_PIXEL_FORMAT_BGR565:
|
|
return _dc_blend_line_bgr565;
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB888:
|
|
return _dc_blend_line_rgb888;
|
|
case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
|
|
return _dc_blend_line_argb8888;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void _do_blend_line(struct rtgui_dc * dst,
|
|
rtgui_color_t color,
|
|
int x1, int y1,
|
|
int x2, int y2,
|
|
enum RTGUI_BLENDMODE blendMode,
|
|
rt_bool_t draw_end)
|
|
{
|
|
BlendLineFunc func;
|
|
rt_uint8_t pixel_format;
|
|
rt_uint8_t r, g, b, a;
|
|
rtgui_widget_t *owner;
|
|
|
|
pixel_format = rtgui_dc_get_pixel_format(dst);
|
|
func = _dc_calc_blend_line_func(pixel_format);
|
|
if (!func)
|
|
{
|
|
rt_kprintf("dc_blend_line(): Unsupported pixel format\n");
|
|
return;
|
|
}
|
|
|
|
r = RTGUI_RGB_R(color);
|
|
g = RTGUI_RGB_G(color);
|
|
b = RTGUI_RGB_B(color);
|
|
a = RTGUI_RGB_A(color);
|
|
|
|
/* perform clip */
|
|
if (dst->type == RTGUI_DC_CLIENT)
|
|
{
|
|
/* get owner */
|
|
owner = RTGUI_CONTAINER_OF(dst, struct rtgui_widget, dc_type);
|
|
|
|
x1 = x1 + owner->extent.x1;
|
|
x2 = x2 + owner->extent.x1;
|
|
y1 = y1 + owner->extent.y1;
|
|
y2 = y2 + owner->extent.y1;
|
|
|
|
if (owner->clip.data == RT_NULL)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
|
|
/* no clip */
|
|
prect = &(owner->clip.extents);
|
|
|
|
/* calculate line intersect */
|
|
if (_intersect_rect_line(prect, &x1, &y1, &x2, &y2) == RT_FALSE)
|
|
return;
|
|
|
|
/* draw line */
|
|
func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, RT_TRUE);
|
|
}
|
|
else
|
|
{
|
|
register rt_base_t index;
|
|
|
|
for (index = 0; index < rtgui_region_num_rects(&(owner->clip)); index ++)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
int draw_x1, draw_x2;
|
|
int draw_y1, draw_y2;
|
|
|
|
prect = ((rtgui_rect_t *)(owner->clip.data + index + 1));
|
|
draw_x1 = x1; draw_x2 = x2;
|
|
draw_y1 = y1; draw_y2 = y2;
|
|
|
|
/* calculate line intersect */
|
|
if (_intersect_rect_line(prect, &draw_x1, &draw_y1, &draw_x2, &draw_y2) == RT_FALSE)
|
|
continue;
|
|
|
|
/* draw line */
|
|
func(dst, draw_x1, draw_y1, draw_x2, draw_y2, blendMode, r, g, b, a, RT_TRUE);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dst->type == RTGUI_DC_HW)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
struct rtgui_dc_hw *dc_hw = (struct rtgui_dc_hw*)dst;
|
|
|
|
owner = dc_hw->owner;
|
|
x1 = x1 + owner->extent.x1;
|
|
x2 = x2 + owner->extent.x1;
|
|
y1 = y1 + owner->extent.y1;
|
|
y2 = y2 + owner->extent.y1;
|
|
|
|
prect = &(owner->clip.extents);
|
|
if (_intersect_rect_line(prect, &x1, &y1, &x2, &y2) == RT_FALSE)
|
|
return;
|
|
}
|
|
|
|
func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, RT_TRUE);
|
|
}
|
|
}
|
|
|
|
void
|
|
rtgui_dc_blend_line(struct rtgui_dc * dst, int x1, int y1, int x2, int y2,
|
|
enum RTGUI_BLENDMODE blendMode, rtgui_color_t color)
|
|
{
|
|
RT_ASSERT(dst != RT_NULL);
|
|
if (!rtgui_dc_get_visible(dst))
|
|
return;
|
|
/* we do not support pixel DC */
|
|
if (_dc_get_pixel(dst, 0, 0) == RT_NULL)
|
|
return;
|
|
|
|
_do_blend_line(dst, color, x1, y1, x2, y2, blendMode, RT_FALSE);
|
|
}
|
|
RTM_EXPORT(rtgui_dc_blend_line);
|
|
|
|
void
|
|
rtgui_dc_blend_lines(struct rtgui_dc * dst, const rtgui_point_t * points, int count,
|
|
enum RTGUI_BLENDMODE blendMode, rtgui_color_t color)
|
|
{
|
|
int i;
|
|
|
|
RT_ASSERT(dst != RT_NULL);
|
|
if (!rtgui_dc_get_visible(dst))
|
|
return;
|
|
/* we do not support pixel DC */
|
|
if (_dc_get_pixel(dst, 0, 0) == RT_NULL)
|
|
return;
|
|
|
|
for (i = 1; i < count; ++i)
|
|
{
|
|
rt_bool_t draw_end;
|
|
int x1, y1, x2, y2;
|
|
|
|
x1 = points[i-1].x;
|
|
y1 = points[i-1].y;
|
|
x2 = points[i].x;
|
|
y2 = points[i].y;
|
|
|
|
/* Draw the end if it was clipped */
|
|
draw_end = (x2 != points[i].x || y2 != points[i].y);
|
|
_do_blend_line(dst, color, x1, y1, x2, y2, blendMode, draw_end);
|
|
}
|
|
|
|
if (points[0].x != points[count-1].x || points[0].y != points[count-1].y)
|
|
{
|
|
rt_uint8_t r, g, b, a;
|
|
|
|
r = RTGUI_RGB_R(color);
|
|
g = RTGUI_RGB_G(color);
|
|
b = RTGUI_RGB_B(color);
|
|
a = RTGUI_RGB_A(color);
|
|
|
|
rtgui_dc_blend_point(dst, points[count-1].x, points[count-1].y,
|
|
blendMode, r, g, b, a);
|
|
}
|
|
}
|
|
RTM_EXPORT(rtgui_dc_blend_lines);
|
|
|
|
static void
|
|
_dc_blend_fill_rect_rgb565(struct rtgui_dc * dst, const rtgui_rect_t * rect,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
unsigned inva = 0xff - a;
|
|
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
FILLRECT(rt_uint16_t, DRAW_SETPIXEL_BLEND_RGB565);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
FILLRECT(rt_uint16_t, DRAW_SETPIXEL_ADD_RGB565);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
FILLRECT(rt_uint16_t, DRAW_SETPIXEL_MOD_RGB565);
|
|
break;
|
|
default:
|
|
FILLRECT(rt_uint16_t, DRAW_SETPIXEL_RGB565);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_dc_blend_fill_rect_bgr565(struct rtgui_dc * dst, const rtgui_rect_t * rect,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
unsigned inva = 0xff - a;
|
|
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
FILLRECT(rt_uint16_t, DRAW_SETPIXEL_BLEND_RGB565);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
FILLRECT(rt_uint16_t, DRAW_SETPIXEL_ADD_RGB565);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
FILLRECT(rt_uint16_t, DRAW_SETPIXEL_MOD_RGB565);
|
|
break;
|
|
default:
|
|
FILLRECT(rt_uint16_t, DRAW_SETPIXEL_RGB565);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_dc_blend_fill_rect_rgb888(struct rtgui_dc * dst, const rtgui_rect_t * rect,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
unsigned inva = 0xff - a;
|
|
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
FILLRECT(rt_uint32_t, DRAW_SETPIXEL_BLEND_RGB888);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
FILLRECT(rt_uint32_t, DRAW_SETPIXEL_ADD_RGB888);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
FILLRECT(rt_uint32_t, DRAW_SETPIXEL_MOD_RGB888);
|
|
break;
|
|
default:
|
|
FILLRECT(rt_uint32_t, DRAW_SETPIXEL_RGB888);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_dc_blend_fill_rect_argb8888(struct rtgui_dc * dst, const rtgui_rect_t * rect,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a)
|
|
{
|
|
unsigned inva = 0xff - a;
|
|
|
|
switch (blendMode) {
|
|
case RTGUI_BLENDMODE_BLEND:
|
|
FILLRECT(rt_uint32_t, DRAW_SETPIXEL_BLEND_ARGB8888);
|
|
break;
|
|
case RTGUI_BLENDMODE_ADD:
|
|
FILLRECT(rt_uint32_t, DRAW_SETPIXEL_ADD_ARGB8888);
|
|
break;
|
|
case RTGUI_BLENDMODE_MOD:
|
|
FILLRECT(rt_uint32_t, DRAW_SETPIXEL_MOD_ARGB8888);
|
|
break;
|
|
default:
|
|
FILLRECT(rt_uint32_t, DRAW_SETPIXEL_ARGB8888);
|
|
break;
|
|
}
|
|
}
|
|
|
|
typedef void (*BlendFillFunc)(struct rtgui_dc * dst, const rtgui_rect_t * rect,
|
|
enum RTGUI_BLENDMODE blendMode, rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a);
|
|
|
|
void
|
|
rtgui_dc_blend_fill_rect(struct rtgui_dc* dst, const rtgui_rect_t *rect,
|
|
enum RTGUI_BLENDMODE blendMode, rtgui_color_t color)
|
|
{
|
|
unsigned r, g, b, a;
|
|
BlendFillFunc func = RT_NULL;
|
|
|
|
RT_ASSERT(dst != RT_NULL);
|
|
|
|
if (!rtgui_dc_get_visible(dst)) return;
|
|
/* This function doesn't work on surfaces < 8 bpp */
|
|
if (_dc_get_bits_per_pixel(dst) < 8) {
|
|
rt_kprintf("dc_blend_fill_rect(): Unsupported pixel format\n");
|
|
return ;
|
|
}
|
|
|
|
r = RTGUI_RGB_R(color);
|
|
g = RTGUI_RGB_G(color);
|
|
b = RTGUI_RGB_B(color);
|
|
a = RTGUI_RGB_A(color);
|
|
|
|
if (blendMode == RTGUI_BLENDMODE_BLEND || blendMode == RTGUI_BLENDMODE_ADD) {
|
|
r = DRAW_MUL(r, a);
|
|
g = DRAW_MUL(g, a);
|
|
b = DRAW_MUL(b, a);
|
|
}
|
|
|
|
switch (rtgui_dc_get_pixel_format(dst))
|
|
{
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB565:
|
|
func = _dc_blend_fill_rect_rgb565;
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_BGR565:
|
|
func = _dc_blend_fill_rect_bgr565;
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB888:
|
|
func = _dc_blend_fill_rect_rgb888;
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
|
|
func = _dc_blend_fill_rect_argb8888;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (func == RT_NULL)
|
|
{
|
|
rt_kprintf("dc_blend_fill_rect(): Unsupported pixel format\n");
|
|
return ;
|
|
}
|
|
|
|
if (dst->type == RTGUI_DC_CLIENT)
|
|
{
|
|
register rt_base_t index;
|
|
rtgui_widget_t *owner;
|
|
rtgui_rect_t draw_rect;
|
|
|
|
/* get owner */
|
|
owner = RTGUI_CONTAINER_OF(dst, struct rtgui_widget, dc_type);
|
|
|
|
if (owner->clip.data == RT_NULL)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
prect = &(owner->clip.extents);
|
|
|
|
/* convert logic to device */
|
|
draw_rect = *rect;
|
|
rtgui_rect_moveto(&draw_rect,owner->extent.x1, owner->extent.y1);
|
|
|
|
/* calculate rect intersect */
|
|
if (prect->y1 > draw_rect.y2 || prect->y2 <= draw_rect.y1) return ;
|
|
if (prect->x2 <= draw_rect.x1 || prect->x1 > draw_rect.x2 ) return ;
|
|
rtgui_rect_intersect(prect, &draw_rect);
|
|
|
|
func(dst, &draw_rect, blendMode, r, g, b, a);
|
|
}
|
|
else
|
|
{
|
|
for (index = 0; index < rtgui_region_num_rects(&(owner->clip)); index ++)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
|
|
prect = ((rtgui_rect_t *)(owner->clip.data + index + 1));
|
|
|
|
draw_rect = *rect;
|
|
rtgui_rect_moveto(&draw_rect,owner->extent.x1, owner->extent.y1);
|
|
|
|
/* calculate rect intersect */
|
|
if (prect->y1 > draw_rect.y2 || prect->y2 <= draw_rect.y1) continue;
|
|
if (prect->x2 <= draw_rect.x1 || prect->x1 > draw_rect.x2 ) continue;
|
|
rtgui_rect_intersect(prect, &draw_rect);
|
|
|
|
func(dst, &draw_rect, blendMode, r, g, b, a);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
func(dst, rect, blendMode, r, g, b, a);
|
|
}
|
|
}
|
|
RTM_EXPORT(rtgui_dc_blend_fill_rect);
|
|
|
|
void
|
|
rtgui_dc_blend_fill_rects(struct rtgui_dc * dst, const rtgui_rect_t *rects, int count,
|
|
enum RTGUI_BLENDMODE blendMode, rtgui_color_t color)
|
|
{
|
|
int i;
|
|
rtgui_rect_t rect;
|
|
BlendFillFunc func = RT_NULL;
|
|
rt_uint8_t r, g, b, a;
|
|
rtgui_widget_t *owner = RT_NULL;
|
|
|
|
RT_ASSERT(dst != RT_NULL);
|
|
|
|
if (!rtgui_dc_get_visible(dst)) return;
|
|
/* This function doesn't work on surfaces < 8 bpp */
|
|
if (_dc_get_bits_per_pixel(dst)< 8) {
|
|
rt_kprintf("dc_blend_fill_rects(): Unsupported pixel format\n");
|
|
return;
|
|
}
|
|
|
|
r = RTGUI_RGB_R(color);
|
|
g = RTGUI_RGB_G(color);
|
|
b = RTGUI_RGB_B(color);
|
|
a = RTGUI_RGB_A(color);
|
|
|
|
if (blendMode == RTGUI_BLENDMODE_BLEND || blendMode == RTGUI_BLENDMODE_ADD) {
|
|
r = DRAW_MUL(r, a);
|
|
g = DRAW_MUL(g, a);
|
|
b = DRAW_MUL(b, a);
|
|
}
|
|
|
|
switch (rtgui_dc_get_pixel_format(dst))
|
|
{
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB565:
|
|
func = _dc_blend_fill_rect_rgb565;
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_BGR565:
|
|
func = _dc_blend_fill_rect_bgr565;
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_RGB888:
|
|
func = _dc_blend_fill_rect_rgb888;
|
|
break;
|
|
case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
|
|
func = _dc_blend_fill_rect_argb8888;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (func == RT_NULL)
|
|
{
|
|
rt_kprintf("dc_blend_fill_rects(): Unsupported pixel format\n");
|
|
return;
|
|
}
|
|
|
|
if (dst->type == RTGUI_DC_CLIENT)
|
|
{
|
|
/* get owner */
|
|
owner = RTGUI_CONTAINER_OF(dst, struct rtgui_widget, dc_type);
|
|
}
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
rect = rects[i];
|
|
|
|
if (dst->type == RTGUI_DC_CLIENT)
|
|
{
|
|
register rt_base_t index;
|
|
rtgui_rect_t draw_rect;
|
|
|
|
if (owner->clip.data == RT_NULL)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
prect = &(owner->clip.extents);
|
|
|
|
/* convert logic to device */
|
|
draw_rect = rect;
|
|
rtgui_rect_moveto(&draw_rect,owner->extent.x1, owner->extent.y1);
|
|
|
|
/* calculate rect intersect */
|
|
if (prect->y1 > draw_rect.y2 || prect->y2 <= draw_rect.y1) return ;
|
|
if (prect->x2 <= draw_rect.x1 || prect->x1 > draw_rect.x2 ) return ;
|
|
rtgui_rect_intersect(prect, &draw_rect);
|
|
|
|
func(dst, &draw_rect, blendMode, r, g, b, a);
|
|
}
|
|
else
|
|
{
|
|
for (index = 0; index < rtgui_region_num_rects(&(owner->clip)); index ++)
|
|
{
|
|
rtgui_rect_t *prect;
|
|
|
|
prect = ((rtgui_rect_t *)(owner->clip.data + index + 1));
|
|
|
|
draw_rect = rect;
|
|
rtgui_rect_moveto(&draw_rect,owner->extent.x1, owner->extent.y1);
|
|
|
|
/* calculate rect intersect */
|
|
if (prect->y1 > draw_rect.y2 || prect->y2 <= draw_rect.y1) continue;
|
|
if (prect->x2 <= draw_rect.x1 || prect->x1 > draw_rect.x2 ) continue;
|
|
rtgui_rect_intersect(prect, &draw_rect);
|
|
|
|
func(dst, &draw_rect, blendMode, r, g, b, a);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
func(dst, &rect, blendMode, r, g, b, a);
|
|
}
|
|
}
|
|
}
|
|
RTM_EXPORT(rtgui_dc_blend_fill_rects);
|
|
|
|
/* Windows targets do not have lrint, so provide a local inline version */
|
|
#if defined(_MSC_VER)
|
|
/* Detect 64bit and use intrinsic version */
|
|
#ifdef _M_X64
|
|
#include <emmintrin.h>
|
|
static __inline long
|
|
lrint(float f)
|
|
{
|
|
return _mm_cvtss_si32(_mm_load_ss(&f));
|
|
}
|
|
#elif defined(_M_IX86)
|
|
__inline long int
|
|
lrint (double flt)
|
|
{
|
|
int intgr;
|
|
_asm
|
|
{
|
|
fld flt
|
|
fistp intgr
|
|
};
|
|
return intgr;
|
|
}
|
|
#elif defined(_M_ARM)
|
|
#include <armintr.h>
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4716)
|
|
__declspec(naked) long int
|
|
lrint (double flt)
|
|
{
|
|
__emit(0xEC410B10); // fmdrr d0, r0, r1
|
|
__emit(0xEEBD0B40); // ftosid s0, d0
|
|
__emit(0xEE100A10); // fmrs r0, s0
|
|
__emit(0xE12FFF1E); // bx lr
|
|
}
|
|
#pragma warning(pop)
|
|
#else
|
|
#error lrint needed for MSVC on non X86/AMD64/ARM targets.
|
|
#endif
|
|
#endif
|
|
|
|
rt_inline void _draw_pixel_weight(struct rtgui_dc * dc, rt_int16_t x, rt_int16_t y,
|
|
rt_uint8_t r, rt_uint8_t g, rt_uint8_t b, rt_uint8_t a, rt_uint32_t weight)
|
|
{
|
|
/*
|
|
* Modify Alpha by weight
|
|
*/
|
|
rt_uint32_t ax = a;
|
|
ax = ((ax * weight) >> 8);
|
|
if (ax > 255) {
|
|
a = 255;
|
|
} else {
|
|
a = (rt_uint8_t)(ax & 0x000000ff);
|
|
}
|
|
|
|
rtgui_dc_blend_point(dc, x, y, RTGUI_BLENDMODE_BLEND, r, g, b, a);
|
|
}
|
|
|
|
void rtgui_dc_draw_aa_ellipse(struct rtgui_dc *dc, rt_int16_t x, rt_int16_t y, rt_int16_t rx, rt_int16_t ry)
|
|
{
|
|
int i;
|
|
int a2, b2, ds, dt, dxt, t, s, d;
|
|
rt_int16_t xp, yp, xs, ys, od, dyt, xx, yy, xc2, yc2;
|
|
int cp;
|
|
double sab;
|
|
rt_uint8_t weight, iweight;
|
|
rt_uint8_t r, g, b, a;
|
|
|
|
/* Sanity check radii */
|
|
if ((rx < 0) || (ry < 0)) return ;
|
|
|
|
/*
|
|
* Special case for rx=0 - draw a vline
|
|
*/
|
|
if (rx == 0) {
|
|
rtgui_dc_draw_vline(dc, x, y - ry, y + ry);
|
|
return;
|
|
}
|
|
/*
|
|
* Special case for ry=0 - draw an hline
|
|
*/
|
|
if (ry == 0) {
|
|
rtgui_dc_draw_hline(dc, x - rx, x + rx, y);
|
|
return;
|
|
}
|
|
|
|
/* Variable setup */
|
|
r = RTGUI_RGB_R(RTGUI_DC_FC(dc));
|
|
g = RTGUI_RGB_G(RTGUI_DC_FC(dc));
|
|
b = RTGUI_RGB_B(RTGUI_DC_FC(dc));
|
|
a = RTGUI_RGB_A(RTGUI_DC_FC(dc));
|
|
|
|
a2 = rx * rx;
|
|
b2 = ry * ry;
|
|
|
|
ds = 2 * a2;
|
|
dt = 2 * b2;
|
|
|
|
xc2 = 2 * x;
|
|
yc2 = 2 * y;
|
|
|
|
sab = sqrt((double)(a2 + b2));
|
|
od = (rt_int16_t)lrint(sab*0.01) + 1; /* introduce some overdraw */
|
|
dxt = (rt_int16_t)lrint((double)a2 / sab) + od;
|
|
|
|
t = 0;
|
|
s = -2 * a2 * ry;
|
|
d = 0;
|
|
|
|
xp = x;
|
|
yp = y - ry;
|
|
|
|
/* Draw */
|
|
|
|
/* "End points" */
|
|
rtgui_dc_blend_point(dc, xp, yp, RTGUI_BLENDMODE_NONE, r, g, b, a);
|
|
rtgui_dc_blend_point(dc, xc2 - xp, yp, RTGUI_BLENDMODE_NONE, r, g, b, a);
|
|
rtgui_dc_blend_point(dc, xp, yc2 - yp, RTGUI_BLENDMODE_NONE, r, g, b, a);
|
|
rtgui_dc_blend_point(dc, xc2 - xp, yc2 - yp, RTGUI_BLENDMODE_NONE, r, g, b, a);
|
|
|
|
for (i = 1; i <= dxt; i++)
|
|
{
|
|
xp--;
|
|
d += t - b2;
|
|
|
|
if (d >= 0)
|
|
ys = yp - 1;
|
|
else if ((d - s - a2) > 0)
|
|
{
|
|
if ((2 * d - s - a2) >= 0)
|
|
ys = yp + 1;
|
|
else {
|
|
ys = yp;
|
|
yp++;
|
|
d -= s + a2;
|
|
s += ds;
|
|
}
|
|
} else {
|
|
yp++;
|
|
ys = yp + 1;
|
|
d -= s + a2;
|
|
s += ds;
|
|
}
|
|
|
|
t -= dt;
|
|
|
|
/* Calculate alpha */
|
|
if (s != 0) {
|
|
cp = 255 * abs(d) / abs(s);
|
|
if (cp > 255) {
|
|
cp = 255;
|
|
}
|
|
} else {
|
|
cp = 255;
|
|
}
|
|
|
|
/* Calculate weights */
|
|
weight = cp;
|
|
iweight = 255 - weight;
|
|
|
|
/* Upper half */
|
|
xx = xc2 - xp;
|
|
_draw_pixel_weight(dc, xp, yp, r, g, b, a, iweight);
|
|
_draw_pixel_weight(dc, xx, yp, r, g, b, a, iweight);
|
|
|
|
_draw_pixel_weight(dc, xp, ys, r, g, b, a, weight);
|
|
_draw_pixel_weight(dc, xx, ys, r, g, b, a, weight);
|
|
|
|
/* Lower half */
|
|
yy = yc2 - yp;
|
|
_draw_pixel_weight(dc, xp, yy, r, g, b, a, iweight);
|
|
_draw_pixel_weight(dc, xx, yy, r, g, b, a, iweight);
|
|
|
|
yy = yc2 - ys;
|
|
_draw_pixel_weight(dc, xp, yy, r, g, b, a, weight);
|
|
_draw_pixel_weight(dc, xx, yy, r, g, b, a, weight);
|
|
}
|
|
|
|
/* Replaces original approximation code dyt = abs(yp - yc); */
|
|
dyt = (rt_int16_t)lrint((double)b2 / sab ) + od;
|
|
for (i = 1; i <= dyt; i++)
|
|
{
|
|
yp++;
|
|
d -= s + a2;
|
|
|
|
if (d <= 0)
|
|
xs = xp + 1;
|
|
else if ((d + t - b2) < 0)
|
|
{
|
|
if ((2 * d + t - b2) <= 0)
|
|
xs = xp - 1;
|
|
else {
|
|
xs = xp;
|
|
xp--;
|
|
d += t - b2;
|
|
t -= dt;
|
|
}
|
|
} else {
|
|
xp--;
|
|
xs = xp - 1;
|
|
d += t - b2;
|
|
t -= dt;
|
|
}
|
|
|
|
s += ds;
|
|
|
|
/* Calculate alpha */
|
|
if (t != 0) {
|
|
cp = 255 * abs(d) / abs(t);
|
|
if (cp > 255) {
|
|
cp = 255;
|
|
}
|
|
} else {
|
|
cp = 255;
|
|
}
|
|
|
|
/* Calculate weight */
|
|
weight = cp;
|
|
iweight = 255 - weight;
|
|
|
|
/* Left half */
|
|
xx = xc2 - xp;
|
|
yy = yc2 - yp;
|
|
_draw_pixel_weight(dc, xp, yp, r, g, b, a, iweight);
|
|
_draw_pixel_weight(dc, xx, yp, r, g, b, a, iweight);
|
|
|
|
_draw_pixel_weight(dc, xp, yy, r, g, b, a, iweight);
|
|
_draw_pixel_weight(dc, xx, yy, r, g, b, a, iweight);
|
|
|
|
/* Right half */
|
|
xx = xc2 - xs;
|
|
_draw_pixel_weight(dc, xs, yp, r, g, b, a, weight);
|
|
_draw_pixel_weight(dc, xx, yp, r, g, b, a, weight);
|
|
|
|
_draw_pixel_weight(dc, xs, yy, r, g, b, a, weight);
|
|
_draw_pixel_weight(dc, xx, yy, r, g, b, a, weight);
|
|
}
|
|
}
|
|
RTM_EXPORT(rtgui_dc_draw_aa_ellipse);
|
|
|
|
void rtgui_dc_draw_aa_circle(struct rtgui_dc *dc, rt_int16_t x, rt_int16_t y, rt_int16_t r)
|
|
{
|
|
rtgui_dc_draw_aa_ellipse(dc, x, y, r, r);
|
|
}
|
|
RTM_EXPORT(rtgui_dc_draw_aa_circle);
|
|
|
|
/*!
|
|
\brief The structure passed to the internal Bresenham iterator.
|
|
*/
|
|
typedef struct {
|
|
rt_int16_t x, y;
|
|
int dx, dy, s1, s2, swapdir, error;
|
|
rt_uint32_t count;
|
|
} _BresenhamIterator;
|
|
|
|
/*!
|
|
\brief The structure passed to the internal Murphy iterator.
|
|
*/
|
|
typedef struct {
|
|
rt_uint32_t color;
|
|
struct rtgui_dc *dst;
|
|
int u, v; /* delta x , delta y */
|
|
int ku, kt, kv, kd; /* loop constants */
|
|
int oct2;
|
|
int quad4;
|
|
rt_int16_t last1x, last1y, last2x, last2y, first1x, first1y, first2x, first2y, tempx, tempy;
|
|
} _MurphyIterator;
|
|
|
|
/*!
|
|
\brief Internal function to initialize the Bresenham line iterator.
|
|
|
|
Example of use:
|
|
_BresenhamIterator b;
|
|
_bresenhamInitialize (&b, x1, y1, x2, y2);
|
|
do {
|
|
plot(b.x, b.y);
|
|
} while (_bresenhamIterate(&b)==0);
|
|
|
|
\param b Pointer to struct for bresenham line drawing state.
|
|
\param x1 X coordinate of the first point of the line.
|
|
\param y1 Y coordinate of the first point of the line.
|
|
\param x2 X coordinate of the second point of the line.
|
|
\param y2 Y coordinate of the second point of the line.
|
|
|
|
\returns Returns 0 on success, -1 on failure.
|
|
*/
|
|
int _bresenhamInitialize(_BresenhamIterator *b, rt_int16_t x1, rt_int16_t y1, rt_int16_t x2, rt_int16_t y2)
|
|
{
|
|
int temp;
|
|
|
|
if (b==NULL) {
|
|
return(-1);
|
|
}
|
|
|
|
b->x = x1;
|
|
b->y = y1;
|
|
|
|
/* dx = abs(x2-x1), s1 = sign(x2-x1) */
|
|
if ((b->dx = x2 - x1) != 0) {
|
|
if (b->dx < 0) {
|
|
b->dx = -b->dx;
|
|
b->s1 = -1;
|
|
} else {
|
|
b->s1 = 1;
|
|
}
|
|
} else {
|
|
b->s1 = 0;
|
|
}
|
|
|
|
/* dy = abs(y2-y1), s2 = sign(y2-y1) */
|
|
if ((b->dy = y2 - y1) != 0) {
|
|
if (b->dy < 0) {
|
|
b->dy = -b->dy;
|
|
b->s2 = -1;
|
|
} else {
|
|
b->s2 = 1;
|
|
}
|
|
} else {
|
|
b->s2 = 0;
|
|
}
|
|
|
|
if (b->dy > b->dx) {
|
|
temp = b->dx;
|
|
b->dx = b->dy;
|
|
b->dy = temp;
|
|
b->swapdir = 1;
|
|
} else {
|
|
b->swapdir = 0;
|
|
}
|
|
|
|
b->count = (b->dx<0) ? 0 : (unsigned int)b->dx;
|
|
b->dy <<= 1;
|
|
b->error = b->dy - b->dx;
|
|
b->dx <<= 1;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*!
|
|
\brief Internal function to move Bresenham line iterator to the next position.
|
|
|
|
Maybe updates the x and y coordinates of the iterator struct.
|
|
|
|
\param b Pointer to struct for bresenham line drawing state.
|
|
|
|
\returns Returns 0 on success, 1 if last point was reached, 2 if moving past end-of-line, -1 on failure.
|
|
*/
|
|
int _bresenhamIterate(_BresenhamIterator *b)
|
|
{
|
|
if (b==NULL) {
|
|
return (-1);
|
|
}
|
|
|
|
/* last point check */
|
|
if (b->count==0) {
|
|
return (2);
|
|
}
|
|
|
|
while (b->error >= 0) {
|
|
if (b->swapdir) {
|
|
b->x += b->s1;
|
|
} else {
|
|
b->y += b->s2;
|
|
}
|
|
|
|
b->error -= b->dx;
|
|
}
|
|
|
|
if (b->swapdir) {
|
|
b->y += b->s2;
|
|
} else {
|
|
b->x += b->s1;
|
|
}
|
|
|
|
b->error += b->dy;
|
|
b->count--;
|
|
|
|
/* count==0 indicates "end-of-line" */
|
|
return ((b->count) ? 0 : 1);
|
|
}
|
|
|
|
|
|
/*!
|
|
\brief Internal function to to draw parallel lines with Murphy algorithm.
|
|
|
|
\param m Pointer to struct for murphy iterator.
|
|
\param x X coordinate of point.
|
|
\param y Y coordinate of point.
|
|
\param d1 Direction square/diagonal.
|
|
*/
|
|
void _murphyParaline(_MurphyIterator *m, rt_int16_t x, rt_int16_t y, int d1)
|
|
{
|
|
int p;
|
|
d1 = -d1;
|
|
|
|
for (p = 0; p <= m->u; p++) {
|
|
rtgui_dc_draw_point(m->dst, x, y);
|
|
|
|
if (d1 <= m->kt) {
|
|
if (m->oct2 == 0) {
|
|
x++;
|
|
} else {
|
|
if (m->quad4 == 0) {
|
|
y++;
|
|
} else {
|
|
y--;
|
|
}
|
|
}
|
|
d1 += m->kv;
|
|
} else {
|
|
x++;
|
|
if (m->quad4 == 0) {
|
|
y++;
|
|
} else {
|
|
y--;
|
|
}
|
|
d1 += m->kd;
|
|
}
|
|
}
|
|
|
|
m->tempx = x;
|
|
m->tempy = y;
|
|
}
|
|
|
|
/*!
|
|
\brief Internal function to to draw one iteration of the Murphy algorithm.
|
|
|
|
\param m Pointer to struct for murphy iterator.
|
|
\param miter Iteration count.
|
|
\param ml1bx X coordinate of a point.
|
|
\param ml1by Y coordinate of a point.
|
|
\param ml2bx X coordinate of a point.
|
|
\param ml2by Y coordinate of a point.
|
|
\param ml1x X coordinate of a point.
|
|
\param ml1y Y coordinate of a point.
|
|
\param ml2x X coordinate of a point.
|
|
\param ml2y Y coordinate of a point.
|
|
|
|
*/
|
|
void _murphyIteration(_MurphyIterator *m, rt_uint8_t miter,
|
|
rt_uint16_t ml1bx, rt_uint16_t ml1by, rt_uint16_t ml2bx, rt_uint16_t ml2by,
|
|
rt_uint16_t ml1x, rt_uint16_t ml1y, rt_uint16_t ml2x, rt_uint16_t ml2y)
|
|
{
|
|
int atemp1, atemp2;
|
|
int ftmp1, ftmp2;
|
|
rt_uint16_t m1x, m1y, m2x, m2y;
|
|
rt_uint16_t fix, fiy, lax, lay, curx, cury;
|
|
int px[4], py[4];
|
|
_BresenhamIterator b;
|
|
|
|
if (miter > 1) {
|
|
if (m->first1x != -32768) {
|
|
fix = (m->first1x + m->first2x) / 2;
|
|
fiy = (m->first1y + m->first2y) / 2;
|
|
lax = (m->last1x + m->last2x) / 2;
|
|
lay = (m->last1y + m->last2y) / 2;
|
|
curx = (ml1x + ml2x) / 2;
|
|
cury = (ml1y + ml2y) / 2;
|
|
|
|
atemp1 = (fix - curx);
|
|
atemp2 = (fiy - cury);
|
|
ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
|
|
atemp1 = (lax - curx);
|
|
atemp2 = (lay - cury);
|
|
ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
|
|
|
|
if (ftmp1 <= ftmp2) {
|
|
m1x = m->first1x;
|
|
m1y = m->first1y;
|
|
m2x = m->first2x;
|
|
m2y = m->first2y;
|
|
} else {
|
|
m1x = m->last1x;
|
|
m1y = m->last1y;
|
|
m2x = m->last2x;
|
|
m2y = m->last2y;
|
|
}
|
|
|
|
atemp1 = (m2x - ml2x);
|
|
atemp2 = (m2y - ml2y);
|
|
ftmp1 = atemp1 * atemp1 + atemp2 * atemp2;
|
|
atemp1 = (m2x - ml2bx);
|
|
atemp2 = (m2y - ml2by);
|
|
ftmp2 = atemp1 * atemp1 + atemp2 * atemp2;
|
|
|
|
if (ftmp2 >= ftmp1) {
|
|
ftmp1 = ml2bx;
|
|
ftmp2 = ml2by;
|
|
ml2bx = ml2x;
|
|
ml2by = ml2y;
|
|
ml2x = ftmp1;
|
|
ml2y = ftmp2;
|
|
ftmp1 = ml1bx;
|
|
ftmp2 = ml1by;
|
|
ml1bx = ml1x;
|
|
ml1by = ml1y;
|
|
ml1x = ftmp1;
|
|
ml1y = ftmp2;
|
|
}
|
|
|
|
_bresenhamInitialize(&b, m2x, m2y, m1x, m1y);
|
|
do {
|
|
rtgui_dc_draw_color_point(m->dst, b.x, b.y, m->color);
|
|
} while (_bresenhamIterate(&b)==0);
|
|
|
|
_bresenhamInitialize(&b, m1x, m1y, ml1bx, ml1by);
|
|
do {
|
|
rtgui_dc_draw_color_point(m->dst, b.x, b.y, m->color);
|
|
} while (_bresenhamIterate(&b)==0);
|
|
|
|
_bresenhamInitialize(&b, ml1bx, ml1by, ml2bx, ml2by);
|
|
do {
|
|
rtgui_dc_draw_color_point(m->dst, b.x, b.y, m->color);
|
|
} while (_bresenhamIterate(&b)==0);
|
|
|
|
_bresenhamInitialize(&b, ml2bx, ml2by, m2x, m2y);
|
|
do {
|
|
rtgui_dc_draw_color_point(m->dst, b.x, b.y, m->color);
|
|
} while (_bresenhamIterate(&b)==0);
|
|
|
|
px[0] = m1x;
|
|
px[1] = m2x;
|
|
px[2] = ml1bx;
|
|
px[3] = ml2bx;
|
|
py[0] = m1y;
|
|
py[1] = m2y;
|
|
py[2] = ml1by;
|
|
py[3] = ml2by;
|
|
rtgui_dc_draw_polygon(m->dst, px, py, 4);
|
|
}
|
|
}
|
|
|
|
m->last1x = ml1x;
|
|
m->last1y = ml1y;
|
|
m->last2x = ml2x;
|
|
m->last2y = ml2y;
|
|
m->first1x = ml1bx;
|
|
m->first1y = ml1by;
|
|
m->first2x = ml2bx;
|
|
m->first2y = ml2by;
|
|
}
|
|
|
|
#define HYPOT(x,y) sqrt((double)(x)*(double)(x)+(double)(y)*(double)(y))
|
|
|
|
/*!
|
|
\brief Internal function to to draw wide lines with Murphy algorithm.
|
|
|
|
Draws lines parallel to ideal line.
|
|
|
|
\param m Pointer to struct for murphy iterator.
|
|
\param x1 X coordinate of first point.
|
|
\param y1 Y coordinate of first point.
|
|
\param x2 X coordinate of second point.
|
|
\param y2 Y coordinate of second point.
|
|
\param width Width of line.
|
|
\param miter Iteration count.
|
|
|
|
*/
|
|
void _murphyWideline(_MurphyIterator *m, rt_int16_t x1, rt_int16_t y1, rt_int16_t x2, rt_int16_t y2, rt_uint8_t width, rt_uint8_t miter)
|
|
{
|
|
float offset = (float)width / 2.f;
|
|
|
|
rt_int16_t temp;
|
|
rt_int16_t ptx, pty, ml1x, ml1y, ml2x, ml2y, ml1bx, ml1by, ml2bx, ml2by;
|
|
|
|
int d0, d1; /* difference terms d0=perpendicular to line, d1=along line */
|
|
|
|
int q; /* pel counter,q=perpendicular to line */
|
|
int tmp;
|
|
|
|
int dd; /* distance along line */
|
|
int tk; /* thickness threshold */
|
|
double ang; /* angle for initial point calculation */
|
|
double sang, cang;
|
|
|
|
/* Initialisation */
|
|
m->u = x2 - x1; /* delta x */
|
|
m->v = y2 - y1; /* delta y */
|
|
|
|
if (m->u < 0) { /* swap to make sure we are in quadrants 1 or 4 */
|
|
temp = x1;
|
|
x1 = x2;
|
|
x2 = temp;
|
|
temp = y1;
|
|
y1 = y2;
|
|
y2 = temp;
|
|
m->u *= -1;
|
|
m->v *= -1;
|
|
}
|
|
|
|
if (m->v < 0) { /* swap to 1st quadrant and flag */
|
|
m->v *= -1;
|
|
m->quad4 = 1;
|
|
} else {
|
|
m->quad4 = 0;
|
|
}
|
|
|
|
if (m->v > m->u) { /* swap things if in 2 octant */
|
|
tmp = m->u;
|
|
m->u = m->v;
|
|
m->v = tmp;
|
|
m->oct2 = 1;
|
|
} else {
|
|
m->oct2 = 0;
|
|
}
|
|
|
|
m->ku = m->u + m->u; /* change in l for square shift */
|
|
m->kv = m->v + m->v; /* change in d for square shift */
|
|
m->kd = m->kv - m->ku; /* change in d for diagonal shift */
|
|
m->kt = m->u - m->kv; /* diag/square decision threshold */
|
|
|
|
d0 = 0;
|
|
d1 = 0;
|
|
dd = 0;
|
|
|
|
ang = atan((double) m->v / (double) m->u); /* calc new initial point - offset both sides of ideal */
|
|
sang = sin(ang);
|
|
cang = cos(ang);
|
|
|
|
if (m->oct2 == 0) {
|
|
ptx = x1 + (rt_int16_t)lrint(offset * sang);
|
|
if (m->quad4 == 0) {
|
|
pty = y1 - (rt_int16_t)lrint(offset * cang);
|
|
} else {
|
|
pty = y1 + (rt_int16_t)lrint(offset * cang);
|
|
}
|
|
} else {
|
|
ptx = x1 - (rt_int16_t)lrint(offset * cang);
|
|
if (m->quad4 == 0) {
|
|
pty = y1 + (rt_int16_t)lrint(offset * sang);
|
|
} else {
|
|
pty = y1 - (rt_int16_t)lrint(offset * sang);
|
|
}
|
|
}
|
|
|
|
/* used here for constant thickness line */
|
|
tk = (int) (4. * HYPOT(ptx - x1, pty - y1) * HYPOT(m->u, m->v));
|
|
|
|
if (miter == 0) {
|
|
m->first1x = -32768;
|
|
m->first1y = -32768;
|
|
m->first2x = -32768;
|
|
m->first2y = -32768;
|
|
m->last1x = -32768;
|
|
m->last1y = -32768;
|
|
m->last2x = -32768;
|
|
m->last2y = -32768;
|
|
}
|
|
|
|
for (q = 0; dd <= tk; q++) { /* outer loop, stepping perpendicular to line */
|
|
|
|
_murphyParaline(m, ptx, pty, d1); /* call to inner loop - right edge */
|
|
if (q == 0) {
|
|
ml1x = ptx;
|
|
ml1y = pty;
|
|
ml1bx = m->tempx;
|
|
ml1by = m->tempy;
|
|
} else {
|
|
ml2x = ptx;
|
|
ml2y = pty;
|
|
ml2bx = m->tempx;
|
|
ml2by = m->tempy;
|
|
}
|
|
if (d0 < m->kt) { /* square move */
|
|
if (m->oct2 == 0) {
|
|
if (m->quad4 == 0) {
|
|
pty++;
|
|
} else {
|
|
pty--;
|
|
}
|
|
} else {
|
|
ptx++;
|
|
}
|
|
} else { /* diagonal move */
|
|
dd += m->kv;
|
|
d0 -= m->ku;
|
|
if (d1 < m->kt) { /* normal diagonal */
|
|
if (m->oct2 == 0) {
|
|
ptx--;
|
|
if (m->quad4 == 0) {
|
|
pty++;
|
|
} else {
|
|
pty--;
|
|
}
|
|
} else {
|
|
ptx++;
|
|
if (m->quad4 == 0) {
|
|
pty--;
|
|
} else {
|
|
pty++;
|
|
}
|
|
}
|
|
d1 += m->kv;
|
|
} else { /* double square move, extra parallel line */
|
|
if (m->oct2 == 0) {
|
|
ptx--;
|
|
} else {
|
|
if (m->quad4 == 0) {
|
|
pty--;
|
|
} else {
|
|
pty++;
|
|
}
|
|
}
|
|
d1 += m->kd;
|
|
if (dd > tk) {
|
|
_murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
|
|
return; /* breakout on the extra line */
|
|
}
|
|
_murphyParaline(m, ptx, pty, d1);
|
|
if (m->oct2 == 0) {
|
|
if (m->quad4 == 0) {
|
|
pty++;
|
|
} else {
|
|
|
|
pty--;
|
|
}
|
|
} else {
|
|
ptx++;
|
|
}
|
|
}
|
|
}
|
|
dd += m->ku;
|
|
d0 += m->kv;
|
|
}
|
|
|
|
_murphyIteration(m, miter, ml1bx, ml1by, ml2bx, ml2by, ml1x, ml1y, ml2x, ml2y);
|
|
}
|
|
|
|
|
|
/*!
|
|
\brief Draw a thick line with alpha blending.
|
|
|
|
\param dst The surface to draw on.
|
|
\param x1 X coordinate of the first point of the line.
|
|
\param y1 Y coordinate of the first point of the line.
|
|
\param x2 X coordinate of the second point of the line.
|
|
\param y2 Y coordinate of the second point of the line.
|
|
\param width Width of the line in pixels. Must be >0.
|
|
\param color The color value of the line to draw (0xRRGGBBAA).
|
|
|
|
\returns Returns 0 on success, -1 on failure.
|
|
*/
|
|
int rtgui_dc_draw_thick_line(struct rtgui_dc * dst, rt_int16_t x1, rt_int16_t y1, rt_int16_t x2, rt_int16_t y2, rt_uint8_t width)
|
|
{
|
|
int wh;
|
|
_MurphyIterator m;
|
|
|
|
if (dst == NULL) return -1;
|
|
if (width < 1) return -1;
|
|
|
|
/* Special case: thick "point" */
|
|
if ((x1 == x2) && (y1 == y2))
|
|
{
|
|
struct rtgui_rect rect;
|
|
wh = width / 2;
|
|
|
|
rtgui_rect_init(&rect, x1 - wh, y1 - wh, x2 + width, y2 + width);
|
|
rtgui_dc_fill_rect(dst, &rect);
|
|
}
|
|
|
|
m.dst = dst;
|
|
m.color = RTGUI_DC_FC(dst);
|
|
|
|
_murphyWideline(&m, x1, y1, x2, y2, width, 0);
|
|
_murphyWideline(&m, x1, y1, x2, y2, width, 1);
|
|
|
|
return(0);
|
|
}
|
|
RTM_EXPORT(rtgui_dc_draw_thick_line);
|