diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 0bac0fde..91b86616 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -17,6 +17,13 @@ #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#include "gdisp/lld/gdisp_lld.h" + +// Declare our driver object +GDISPDriver GDISP_Win32; + +#define GC (&GDISP_Win32) + #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -45,9 +52,6 @@ #include "ginput/lld/mouse.h" #endif -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" - /*===========================================================================*/ /* Driver local routines . */ /*===========================================================================*/ @@ -329,86 +333,59 @@ bool_t gdisp_lld_init(void) { Sleep(1); /* Initialise the GDISP structure to match */ - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = 100; - GDISP.Contrast = 50; - GDISP.Width = wWidth; - GDISP.Height = wHeight; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + GC->g.Orientation = GDISP_ROTATE_0; + GC->g.Powermode = powerOn; + GC->g.Backlight = 100; + GC->g.Contrast = 50; + GC->g.Width = wWidth; + GC->g.Height = wHeight; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - HDC dc; - #if WIN32_USE_MSG_REDRAW - RECT rect; - #endif - #if GDISP_NEED_CONTROL - coord_t t; - #endif - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - break; - case GDISP_ROTATE_90: - t = GDISP.Height - 1 - y; - y = x; - x = t; - break; - case GDISP_ROTATE_180: - x = GDISP.Width - 1 - x; - y = GDISP.Height - 1 - y; - break; - case GDISP_ROTATE_270: - t = GDISP.Width - 1 - x; - x = y; - y = t; - break; - } - #endif +#if GDISP_HARDWARE_DRAWPIXEL + void gdisp_lld_draw_pixel(void) { + HDC dcScreen; + int x, y; + COLORREF color; - // Draw the pixel in the buffer - color = COLOR2BGR(color); - SetPixel(dcBuffer, x, y, color); + color = COLOR2BGR(GC->p.color); - #if WIN32_USE_MSG_REDRAW - rect.left = x; rect.right = x+1; - rect.top = y; rect.bottom = y+1; - InvalidateRect(winRootWindow, &rect, FALSE); - UpdateWindow(winRootWindow); - #else - // Draw the pixel again directly on the screen. - // This is cheaper than invalidating a single pixel in the window - dc = GetDC(winRootWindow); - SetPixel(dc, x, y, color); - ReleaseDC(winRootWindow, dc); - #endif -} + #if GDISP_NEED_CONTROL + switch(GC->g.Orientation) { + case GDISP_ROTATE_0: + x = GC->p.x; + y = GC->p.y; + break; + case GDISP_ROTATE_90: + x = GC->g.Height - 1 - GC->p.y; + y = GC->p.x; + break; + case GDISP_ROTATE_180: + x = GC->g.Width - 1 - GC->p.x; + y = GC->g.Height - 1 - GC->p.y; + break; + case GDISP_ROTATE_270: + x = GC->p.y; + y = GC->g.Width - 1 - GC->p.x; + break; + } + #else + x = GC->p.x; + y = GC->p.y; + #endif + + // Draw the pixel on the screen and in the buffer. + dcScreen = GetDC(winRootWindow); + SetPixel(dcScreen, x, y, color); + SetPixel(dcBuffer, x, y, color); + ReleaseDC(winRootWindow, dcScreen); + } +#endif /* ---- Optional Routines ---- */ -#if GDISP_HARDWARE_LINES || defined(__DOXYGEN__) +#if 0 +#if GDISP_HARDWARE_LINES /** * @brief Draw a line. * @note Optional - The high level driver can emulate using software. @@ -439,57 +416,57 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #endif #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: #if GDISP_NEED_CLIP // Clip post orientation change - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.clipx0, GDISP.clipy0, GDISP.clipx1, GDISP.clipy1); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.clipx0, GC->g.clipy0, GC->g.clipx1, GC->g.clipy1); #endif break; case GDISP_ROTATE_90: - t = GDISP.Height - 1 - y0; + t = GC->g.Height - 1 - y0; y0 = x0; x0 = t; - t = GDISP.Height - 1 - y1; + t = GC->g.Height - 1 - y1; y1 = x1; x1 = t; #if GDISP_NEED_CLIP // Clip post orientation change - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.Height-1-GDISP.clipy1, GDISP.clipx0, GDISP.Height-1-GDISP.clipy0, GDISP.clipx1); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.Height-1-GC->g.clipy1, GC->g.clipx0, GC->g.Height-1-GC->g.clipy0, GC->g.clipx1); #endif break; case GDISP_ROTATE_180: - x0 = GDISP.Width - 1 - x0; - y0 = GDISP.Height - 1 - y0; - x1 = GDISP.Width - 1 - x1; - y1 = GDISP.Height - 1 - y1; + x0 = GC->g.Width - 1 - x0; + y0 = GC->g.Height - 1 - y0; + x1 = GC->g.Width - 1 - x1; + y1 = GC->g.Height - 1 - y1; #if GDISP_NEED_CLIP // Clip post orientation change - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.Width-1-GDISP.clipx1, GDISP.Height-1-GDISP.clipy1, GDISP.Width-1-GDISP.clipx0, GDISP.Height-1-GDISP.clipy0); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.Width-1-GC->g.clipx1, GC->g.Height-1-GC->g.clipy1, GC->g.Width-1-GC->g.clipx0, GC->g.Height-1-GC->g.clipy0); #endif break; case GDISP_ROTATE_270: - t = GDISP.Width - 1 - x0; + t = GC->g.Width - 1 - x0; x0 = y0; y0 = t; - t = GDISP.Width - 1 - x1; + t = GC->g.Width - 1 - x1; x1 = y1; y1 = t; #if GDISP_NEED_CLIP // Clip post orientation change - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.clipy0, GDISP.Width-1-GDISP.clipx1, GDISP.clipy1, GDISP.Width-1-GDISP.clipx0); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.clipy0, GC->g.Width-1-GC->g.clipx1, GC->g.clipy1, GC->g.Width-1-GC->g.clipx0); #endif break; } #else #if GDISP_NEED_CLIP clip = NULL; - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.clipx0, GDISP.clipy0, GDISP.clipx1, GDISP.clipy1); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.clipx0, GC->g.clipy0, GC->g.clipx1, GC->g.clipy1); #endif #endif @@ -535,85 +512,58 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { } } #endif +#endif -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - HDC dc; - RECT rect; - HBRUSH hbr; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif +#if GDISP_HARDWARE_FILLS + void gdisp_lld_fill_area(void) { + HDC dcScreen; + RECT rect; + HBRUSH hbr; + COLORREF color; + color = COLOR2BGR(GC->p.color); #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: - rect.top = y; - rect.bottom = rect.top+cy; - rect.left = x; - rect.right = rect.left+cx; + rect.top = GC->p.y; + rect.bottom = rect.top + GC->p.cy; + rect.left = GC->p.x; + rect.right = rect.left + GC->p.cx; break; case GDISP_ROTATE_90: - rect.top = x; - rect.bottom = rect.top+cx; - rect.right = GDISP.Height - y; - rect.left = rect.right-cy; + rect.top = GC->p.x; + rect.bottom = rect.top + GC->p.cx; + rect.right = GC->g.Height - GC->p.y; + rect.left = rect.right - GC->p.cy; break; case GDISP_ROTATE_180: - rect.bottom = GDISP.Height - y; - rect.top = rect.bottom-cy; - rect.right = GDISP.Width - x; - rect.left = rect.right-cx; + rect.bottom = GC->g.Height - GC->p.y; + rect.top = rect.bottom - GC->p.cy; + rect.right = GC->g.Width - GC->p.x; + rect.left = rect.right - GC->p.cx; break; case GDISP_ROTATE_270: - rect.bottom = GDISP.Width - x; - rect.top = rect.bottom-cx; - rect.left = y; - rect.right = rect.left+cy; + rect.bottom = GC->g.Width - GC->p.x; + rect.top = rect.bottom - GC->p.cx; + rect.left = GC->p.y; + rect.right = rect.left + GC->p.cy; break; } #else - rect.top = y; - rect.bottom = rect.top+cy; - rect.left = x; - rect.right = rect.left+cx; + rect.top = GC->p.y; + rect.bottom = rect.top + GC->p.cy; + rect.left = GC->p.x; + rect.right = rect.left + GC->p.cx; #endif - color = COLOR2BGR(color); hbr = CreateSolidBrush(color); - if (hbr) { - // Fill the area - FillRect(dcBuffer, &rect, hbr); + dcScreen = GetDC(winRootWindow); + FillRect(dcScreen, &rect, hbr); + FillRect(dcBuffer, &rect, hbr); + ReleaseDC(winRootWindow, dcScreen); - #if WIN32_USE_MSG_REDRAW - InvalidateRect(winRootWindow, &rect, FALSE); - UpdateWindow(winRootWindow); - #else - // Filling the area directly on the screen is likely to be cheaper than invalidating it - dc = GetDC(winRootWindow); - FillRect(dc, &rect, hbr); - ReleaseDC(winRootWindow, dc); - #endif - - DeleteObject(hbr); - } + DeleteObject(hbr); } #endif @@ -626,7 +576,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { coord_t i, j; // Shortcut. - if (GDISP.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx) + if (GC->g.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx) return (pixel_t *)buffer; // Allocate the destination buffer @@ -635,7 +585,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { return 0; // Copy the bits we need - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: for(dst = dstbuf, src = buffer+srcx, j = 0; j < cy; j++) for(i = 0; i < cx; i++, src += srccx - cx) @@ -665,7 +615,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) +#if GDISP_HARDWARE_BITFILLS /** * @brief Fill an area with a bitmap. * @note Optional - The high level driver can emulate using software. @@ -687,12 +637,12 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP // Clip pre orientation change - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } + if (x < GC->g.clipx0) { cx -= GC->g.clipx0 - x; srcx += GC->g.clipx0 - x; x = GC->g.clipx0; } + if (y < GC->g.clipy0) { cy -= GC->g.clipy0 - y; srcy += GC->g.clipy0 - y; y = GC->g.clipy0; } if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; + if (cx <= 0 || cy <= 0 || x >= GC->g.clipx1 || y >= GC->g.clipy1) return; + if (x+cx > GC->g.clipx1) cx = GC->g.clipx1 - x; + if (y+cy > GC->g.clipy1) cy = GC->g.clipy1 - y; #endif // Make everything relative to the start of the line @@ -719,7 +669,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { srcimg = rotateimg(cx, cy, srcx, srccx, buffer); if (!srcimg) return; - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: bmpInfo.bV4Width = cx; bmpInfo.bV4Height = -cy; /* top-down image */ @@ -733,21 +683,21 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { bmpInfo.bV4Height = -cx; /* top-down image */ rect.top = x; rect.bottom = rect.top+cx; - rect.right = GDISP.Height - y; + rect.right = GC->g.Height - y; rect.left = rect.right-cy; break; case GDISP_ROTATE_180: bmpInfo.bV4Width = cx; bmpInfo.bV4Height = -cy; /* top-down image */ - rect.bottom = GDISP.Height - y; + rect.bottom = GC->g.Height - y; rect.top = rect.bottom-cy; - rect.right = GDISP.Width - x; + rect.right = GC->g.Width - x; rect.left = rect.right-cx; break; case GDISP_ROTATE_270: bmpInfo.bV4Width = cy; bmpInfo.bV4Height = -cx; /* top-down image */ - rect.bottom = GDISP.Width - x; + rect.bottom = GC->g.Width - x; rect.top = rect.bottom-cx; rect.left = y; rect.right = rect.left+cy; @@ -793,24 +743,24 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP // Clip pre orientation change - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; + if (x < 0 || x >= GC->g.Width || y < 0 || y >= GC->g.Height) return 0; #endif #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: break; case GDISP_ROTATE_90: - t = GDISP.Height - 1 - y; + t = GC->g.Height - 1 - y; y = x; x = t; break; case GDISP_ROTATE_180: - x = GDISP.Width - 1 - x; - y = GDISP.Height - 1 - y; + x = GC->g.Width - 1 - x; + y = GC->g.Height - 1 - y; break; case GDISP_ROTATE_270: - t = GDISP.Width - 1 - x; + t = GC->g.Width - 1 - x; x = y; y = t; break; @@ -842,11 +792,11 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP // Clip pre orientation change - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; + if (x < GC->g.clipx0) { cx -= GC->g.clipx0 - x; x = GC->g.clipx0; } + if (y < GC->g.clipy0) { cy -= GC->g.clipy0 - y; y = GC->g.clipy0; } + if (!lines || cx <= 0 || cy <= 0 || x >= GC->g.clipx1 || y >= GC->g.clipy1) return; + if (x+cx > GC->g.clipx1) cx = GC->g.clipx1 - x; + if (y+cy > GC->g.clipy1) cy = GC->g.clipy1 - y; #endif if (lines > cy) lines = cy; @@ -856,7 +806,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { hbr = CreateSolidBrush(bgcolor); #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: rect.top = y; rect.bottom = rect.top+cy; @@ -867,13 +817,13 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { case GDISP_ROTATE_90: rect.top = x; rect.bottom = rect.top+cx; - rect.right = GDISP.Height - y; + rect.right = GC->g.Height - y; rect.left = rect.right-cy; goto horizontal_scroll; case GDISP_ROTATE_180: - rect.bottom = GDISP.Height - y; + rect.bottom = GC->g.Height - y; rect.top = rect.bottom-cy; - rect.right = GDISP.Width - x; + rect.right = GC->g.Width - x; rect.left = rect.right-cx; vertical_scroll: srect.left = frect.left = rect.left; @@ -891,7 +841,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { ScrollDC(dcBuffer, 0, lines, &srect, 0, 0, 0); break; case GDISP_ROTATE_270: - rect.bottom = GDISP.Width - x; + rect.bottom = GC->g.Width - x; rect.top = rect.bottom-cx; rect.left = y; rect.right = rect.left+cy; @@ -963,36 +913,36 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { void gdisp_lld_control(unsigned what, void *value) { switch(what) { case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + if (GC->g.Orientation == (gdisp_orientation_t)value) return; switch((gdisp_orientation_t)value) { case GDISP_ROTATE_0: - GDISP.Width = wWidth; - GDISP.Height = wHeight; + GC->g.Width = wWidth; + GC->g.Height = wHeight; break; case GDISP_ROTATE_90: - GDISP.Height = wWidth; - GDISP.Width = wHeight; + GC->g.Height = wWidth; + GC->g.Width = wHeight; break; case GDISP_ROTATE_180: - GDISP.Width = wWidth; - GDISP.Height = wHeight; + GC->g.Width = wWidth; + GC->g.Height = wHeight; break; case GDISP_ROTATE_270: - GDISP.Height = wWidth; - GDISP.Width = wHeight; + GC->g.Height = wWidth; + GC->g.Width = wHeight; break; default: return; } #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; + GC->g.clipx0 = 0; + GC->g.clipy0 = 0; + GC->g.clipx1 = GC->g.Width; + GC->g.clipy1 = GC->g.Height; #endif - GDISP.Orientation = (gdisp_orientation_t)value; + GC->g.Orientation = (gdisp_orientation_t)value; return; /* case GDISP_CONTROL_POWER: diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index b6fa874a..357febe4 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -22,14 +22,20 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "Win32" +#define GDISP_DRIVER_NAME "Win32" +#define GDISP_DRIVER_STRUCT GDISP_Win32 -#define GDISP_HARDWARE_LINES TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_SCROLL TRUE -#define GDISP_HARDWARE_PIXELREAD TRUE -#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_HARDWARE_STREAM FALSE +#define GDISP_HARDWARE_STREAM_END FALSE +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_CLEARS FALSE +#define GDISP_HARDWARE_FILLS TRUE +//#define GDISP_HARDWARE_BITFILLS TRUE +//#define GDISP_HARDWARE_SCROLL TRUE +//#define GDISP_HARDWARE_PIXELREAD TRUE +//#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_HARDWARE_QUERY FALSE +#define GDISP_HARDWARE_CLIP FALSE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index b82c9f3c..3a1968ed 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -76,20 +76,16 @@ typedef enum powermode {powerOff, powerSleep, powerDeepSleep, powerOn} gdisp_pow * Applications should always use the routines and macros defined * below to access it in case the implementation ever changed. */ -typedef struct GDISPDriver_t { +typedef struct GDISPControl { coord_t Width; coord_t Height; gdisp_orientation_t Orientation; gdisp_powermode_t Powermode; uint8_t Backlight; uint8_t Contrast; - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - coord_t clipx0, clipy0; - coord_t clipx1, clipy1; /* not inclusive */ - #endif - } GDISPDriver; + } GDISPControl; -extern GDISPDriver GDISP; +extern GDISPControl *GDISP; /*===========================================================================*/ /* Constants. */ @@ -129,6 +125,7 @@ extern GDISPDriver GDISP; */ #define GDISP_PIXELFORMAT_MONO 1 #define GDISP_PIXELFORMAT_RGB565 565 +#define GDISP_PIXELFORMAT_BGR565 9565 #define GDISP_PIXELFORMAT_RGB888 888 #define GDISP_PIXELFORMAT_RGB444 444 #define GDISP_PIXELFORMAT_RGB332 332 @@ -219,10 +216,20 @@ extern GDISPDriver GDISP; #define MASKCOLOR FALSE #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF8)<<8) | (((g) & 0xFC)<<3) | (((b) & 0xF8)>>3))) #define HTML2COLOR(h) ((color_t)((((h) & 0xF80000)>>8) | (((h) & 0x00FC00)>>5) | (((h) & 0x0000F8)>>3))) - #define RED_OF(c) (((c) & 0xF800)>>8) + #define RED_OF(c) (((c)&0xF800)>>8) #define GREEN_OF(c) (((c)&0x07E0)>>3) #define BLUE_OF(c) (((c)&0x001F)<<3) +#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_BGR565 + typedef uint16_t color_t; + #define COLOR(c) ((color_t)(c)) + #define MASKCOLOR FALSE + #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF8)>>3) | (((g) & 0xFC)<<3) | (((b) & 0xF8)<<8))) + #define HTML2COLOR(h) ((color_t)((((h) & 0x0000F8)>>3) | (((h) & 0x00FC00)>>5) | (((h) & 0xF80000)>>8))) + #define RED_OF(c) (((c)&0x001F)<<3) + #define GREEN_OF(c) (((c)&0x07E0)>>3) + #define BLUE_OF(c) (((c)& 0xF800)>>8) + #elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 typedef uint32_t color_t; #define COLOR(c) ((color_t)(((c) & 0xFFFFFF))) @@ -296,278 +303,82 @@ typedef color_t pixel_t; extern "C" { #endif -#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC || defined(__DOXYGEN__) - /* These routines can be hardware accelerated - * - Do not add a routine here unless it has also been added to the hardware acceleration layer - */ +/* Base Functions */ - /* Base Functions */ - - /** - * @brief Test if the GDISP engine is currently drawing. - * @note This function will always return FALSE if - * GDISP_NEED_ASYNC is not defined. - * - * @return TRUE if gdisp is busy, FALSE otherwise - * - * @api - */ - bool_t gdispIsBusy(void); - - /* Drawing Functions */ - - /** - * @brief Clear the display to the specified color. - * - * @param[in] color The color to use when clearing the screen - * - * @api - */ - void gdispClear(color_t color); - - /** - * @brief Set a pixel in the specified color. - * - * @param[in] x,y The position to set the pixel. - * @param[in] color The color to use - * - * @api - */ - void gdispDrawPixel(coord_t x, coord_t y, color_t color); - - /** - * @brief Draw a line. - * - * @param[in] x0,y0 The start position - * @param[in] x1,y1 The end position - * @param[in] color The color to use - * - * @api - */ - void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); - - /** - * @brief Fill an area with a color. - * - * @param[in] x,y The start position - * @param[in] cx,cy The size of the box (outside dimensions) - * @param[in] color The color to use - * - * @api - */ - void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); - - /** - * @brief Fill an area using the supplied bitmap. - * @details The bitmap is in the pixel format specified by the low level driver - * @note If a packed pixel format is used and the width doesn't - * match a whole number of bytes, the next line will start on a - * non-byte boundary (no end-of-line padding). - * @note If GDISP_NEED_ASYNC is defined then the buffer must be static - * or at least retained until this call has finished the blit. You can - * tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE. - * - * @param[in] x,y The start position - * @param[in] cx,cy The size of the filled area - * @param[in] srcx,srcy The bitmap position to start the fill form - * @param[in] srccx The width of a line in the bitmap - * @param[in] buffer The bitmap in the driver's pixel format - * - * @api - */ - void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer); - - /* Clipping Functions */ - - #if GDISP_NEED_CLIP || defined(__DOXYGEN__) - /** - * @brief Clip all drawing to the defined area. - * - * @param[in] x,y The start position - * @param[in] cx,cy The size of the clip area - * - * @api - */ - void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy); - #endif - - /* Circle Functions */ - - #if GDISP_NEED_CIRCLE || defined(__DOXYGEN__) - /** - * @brief Draw a circle. - * - * @param[in] x,y The center of the circle - * @param[in] radius The radius of the circle - * @param[in] color The color to use - * - * @api - */ - void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color); - - /** - * @brief Draw a filled circle. - * - * @param[in] x,y The center of the circle - * @param[in] radius The radius of the circle - * @param[in] color The color to use - * - * @api - */ - void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color); - #endif - - /* Ellipse Functions */ - - #if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__) - /** - * @brief Draw an ellipse. - * - * @param[in] x,y The center of the ellipse - * @param[in] a,b The dimensions of the ellipse - * @param[in] color The color to use - * - * @api - */ - void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); - - /** - * @brief Draw a filled ellipse. - * - * @param[in] x,y The center of the ellipse - * @param[in] a,b The dimensions of the ellipse - * @param[in] color The color to use - * - * @api - */ - void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); - #endif - - /* Arc Functions */ - - #if GDISP_NEED_ARC || defined(__DOXYGEN__) - /* - * @brief Draw an arc. - * - * @param[in] x0,y0 The center point - * @param[in] radius The radius of the arc - * @param[in] start The start angle (0 to 360) - * @param[in] end The end angle (0 to 360) - * @param[in] color The color of the arc - * - * @api - */ - void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); - - /* - * @brief Draw a filled arc. - * @note Not very efficient currently - does lots of overdrawing - * - * @param[in] x0,y0 The center point - * @param[in] radius The radius of the arc - * @param[in] start The start angle (0 to 360) - * @param[in] end The end angle (0 to 360) - * @param[in] color The color of the arc - * - * @api - */ - void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); - #endif - - /* Read a pixel Function */ - - #if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__) - /** - * @brief Get the color of a pixel. - * @return The color of the pixel. - * - * @param[in] x,y The position of the pixel - * - * @api - */ - color_t gdispGetPixelColor(coord_t x, coord_t y); - #endif - - /* Scrolling Function - clears the area scrolled out */ - - #if GDISP_NEED_SCROLL || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @pre GDISP_NEED_SCROLL must be set to TRUE in gfxconf.h - * @note Optional. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @api - */ - void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor); - #endif - - /* Set driver specific control */ - - #if GDISP_NEED_CONTROL || defined(__DOXYGEN__) - /** - * @brief Control hardware specific parts of the display. eg powermodes, backlight etc - * @note Depending on the hardware implementation this function may not - * support some codes. They will be ignored. - * - * @param[in] what what you want to control - * @param[in] value The value to be assigned - * - * @api - */ - void gdispControl(unsigned what, void *value); - #endif - - /* Query driver specific data */ - - #if GDISP_NEED_QUERY || defined(__DOXYGEN__) - /** - * @brief Query a property of the display. - * @note The result must be typecast to the correct type. - * @note An unsupported query will return (void *)-1. - * - * @param[in] what What to query - * - * @api - */ - void *gdispQuery(unsigned what); - #endif - -#else - /* Include the low level driver information */ - #include "gdisp/lld/gdisp_lld.h" - - /* The same as above but use the low level driver directly if no multi-thread support is needed */ - #define gdispIsBusy() FALSE - #define gdispClear(color) gdisp_lld_clear(color) - #define gdispDrawPixel(x, y, color) gdisp_lld_draw_pixel(x, y, color) - #define gdispDrawLine(x0, y0, x1, y1, color) gdisp_lld_draw_line(x0, y0, x1, y1, color) - #define gdispFillArea(x, y, cx, cy, color) gdisp_lld_fill_area(x, y, cx, cy, color) - #define gdispBlitAreaEx(x, y, cx, cy, sx, sy, scx, buf) gdisp_lld_blit_area_ex(x, y, cx, cy, sx, sy, scx, buf) - #define gdispSetClip(x, y, cx, cy) gdisp_lld_set_clip(x, y, cx, cy) - #define gdispDrawCircle(x, y, radius, color) gdisp_lld_draw_circle(x, y, radius, color) - #define gdispFillCircle(x, y, radius, color) gdisp_lld_fill_circle(x, y, radius, color) - #define gdispDrawArc(x, y, radius, sangle, eangle, color) gdisp_lld_draw_arc(x, y, radius, sangle, eangle, color) - #define gdispFillArc(x, y, radius, sangle, eangle, color) gdisp_lld_fill_arc(x, y, radius, sangle, eangle, color) - #define gdispDrawEllipse(x, y, a, b, color) gdisp_lld_draw_ellipse(x, y, a, b, color) - #define gdispFillEllipse(x, y, a, b, color) gdisp_lld_fill_ellipse(x, y, a, b, color) - #define gdispGetPixelColor(x, y) gdisp_lld_get_pixel_color(x, y) - #define gdispVerticalScroll(x, y, cx, cy, lines, bgcolor) gdisp_lld_vertical_scroll(x, y, cx, cy, lines, bgcolor) - #define gdispControl(what, value) gdisp_lld_control(what, value) - #define gdispQuery(what) gdisp_lld_query(what) - -#endif - -/* These routines are not hardware accelerated - * - Do not add a hardware accelerated routines here. +/** + * @brief Blend 2 colors according to the alpha + * @return The combined color + * + * @param[in] fg The foreground color + * @param[in] bg The background color + * @param[in] alpha The alpha value (0-255). 0 is all background, 255 is all foreground. + * + * @api */ +color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); -/* Extra drawing functions */ +/* Drawing Functions */ + +/** + * @brief Clear the display to the specified color. + * + * @param[in] color The color to use when clearing the screen + * + * @api + */ +void gdispClear(color_t color); + +/** + * @brief Set a pixel in the specified color. + * + * @param[in] x,y The position to set the pixel. + * @param[in] color The color to use + * + * @api + */ +void gdispDrawPixel(coord_t x, coord_t y, color_t color); + +/** + * @brief Draw a line. + * + * @param[in] x0,y0 The start position + * @param[in] x1,y1 The end position + * @param[in] color The color to use + * + * @api + */ +void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); + +/** + * @brief Fill an area with a color. + * + * @param[in] x,y The start position + * @param[in] cx,cy The size of the box (outside dimensions) + * @param[in] color The color to use + * + * @api + */ +void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); + +/** + * @brief Fill an area using the supplied bitmap. + * @details The bitmap is in the pixel format specified by the low level driver + * @note If a packed pixel format is used and the width doesn't + * match a whole number of bytes, the next line will start on a + * non-byte boundary (no end-of-line padding). + * @note If GDISP_NEED_ASYNC is defined then the buffer must be static + * or at least retained until this call has finished the blit. You can + * tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE. + * + * @param[in] x,y The start position + * @param[in] cx,cy The size of the filled area + * @param[in] srcx,srcy The bitmap position to start the fill form + * @param[in] srccx The width of a line in the bitmap + * @param[in] buffer The bitmap in the driver's pixel format + * + * @api + */ +void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer); /** * @brief Draw a rectangular box. @@ -580,6 +391,167 @@ extern "C" { */ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); +/* Clipping Functions */ + +#if GDISP_NEED_CLIP || defined(__DOXYGEN__) + /** + * @brief Clip all drawing to the defined area. + * + * @param[in] x,y The start position + * @param[in] cx,cy The size of the clip area + * + * @api + */ + void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy); +#endif + +/* Circle Functions */ + +#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__) + /** + * @brief Draw a circle. + * + * @param[in] x,y The center of the circle + * @param[in] radius The radius of the circle + * @param[in] color The color to use + * + * @api + */ + void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color); + + /** + * @brief Draw a filled circle. + * + * @param[in] x,y The center of the circle + * @param[in] radius The radius of the circle + * @param[in] color The color to use + * + * @api + */ + void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color); +#endif + +/* Ellipse Functions */ + +#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__) + /** + * @brief Draw an ellipse. + * + * @param[in] x,y The center of the ellipse + * @param[in] a,b The dimensions of the ellipse + * @param[in] color The color to use + * + * @api + */ + void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + + /** + * @brief Draw a filled ellipse. + * + * @param[in] x,y The center of the ellipse + * @param[in] a,b The dimensions of the ellipse + * @param[in] color The color to use + * + * @api + */ + void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); +#endif + +/* Arc Functions */ + +#if GDISP_NEED_ARC || defined(__DOXYGEN__) + /* + * @brief Draw an arc. + * + * @param[in] x0,y0 The center point + * @param[in] radius The radius of the arc + * @param[in] start The start angle (0 to 360) + * @param[in] end The end angle (0 to 360) + * @param[in] color The color of the arc + * + * @api + */ + void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + + /* + * @brief Draw a filled arc. + * @note Not very efficient currently - does lots of overdrawing + * + * @param[in] x0,y0 The center point + * @param[in] radius The radius of the arc + * @param[in] start The start angle (0 to 360) + * @param[in] end The end angle (0 to 360) + * @param[in] color The color of the arc + * + * @api + */ + void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); +#endif + +/* Read a pixel Function */ + +#if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__) + /** + * @brief Get the color of a pixel. + * @return The color of the pixel. + * + * @param[in] x,y The position of the pixel + * + * @api + */ + color_t gdispGetPixelColor(coord_t x, coord_t y); +#endif + +/* Scrolling Function - clears the area scrolled out */ + +#if GDISP_NEED_SCROLL || defined(__DOXYGEN__) + /** + * @brief Scroll vertically a section of the screen. + * @pre GDISP_NEED_SCROLL must be set to TRUE in gfxconf.h + * @note Optional. + * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. + * + * @param[in] x, y The start of the area to be scrolled + * @param[in] cx, cy The size of the area to be scrolled + * @param[in] lines The number of lines to scroll (Can be positive or negative) + * @param[in] bgcolor The color to fill the newly exposed area. + * + * @api + */ + void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor); +#endif + +/* Set driver specific control */ + +#if GDISP_NEED_CONTROL || defined(__DOXYGEN__) + /** + * @brief Control hardware specific parts of the display. eg powermodes, backlight etc + * @note Depending on the hardware implementation this function may not + * support some codes. They will be ignored. + * + * @param[in] what what you want to control + * @param[in] value The value to be assigned + * + * @api + */ + void gdispControl(unsigned what, void *value); +#endif + +/* Query driver specific data */ + +#if GDISP_NEED_QUERY || defined(__DOXYGEN__) + /** + * @brief Query a property of the display. + * @note The result must be typecast to the correct type. + * @note An unsupported query will return (void *)-1. + * + * @param[in] what What to query + * + * @api + */ + void *gdispQuery(unsigned what); +#endif + #if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__) /** * @brief Draw an enclosed polygon (convex, non-convex or complex). @@ -803,19 +775,6 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color); #endif - -/** - * @brief Blend 2 colors according to the alpha - * @return The combined color - * - * @param[in] fg The foreground color - * @param[in] bg The background color - * @param[in] alpha The alpha value (0-255). 0 is all background, 255 is all foreground. - * - * @api - */ -color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); - /* Support routine for packed pixel formats */ #if !defined(gdispPackPixels) || defined(__DOXYGEN__) /** @@ -890,42 +849,42 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); * * @api */ -#define gdispGetWidth() (GDISP.Width) +#define gdispGetWidth() (GDISP->Width) /** * @brief Get the display height in pixels. * * @api */ -#define gdispGetHeight() (GDISP.Height) +#define gdispGetHeight() (GDISP->Height) /** * @brief Get the current display power mode. * * @api */ -#define gdispGetPowerMode() (GDISP.Powermode) +#define gdispGetPowerMode() (GDISP->Powermode) /** * @brief Get the current display orientation. * * @api */ -#define gdispGetOrientation() (GDISP.Orientation) +#define gdispGetOrientation() (GDISP->Orientation) /** * @brief Get the current display backlight brightness. * * @api */ -#define gdispGetBacklight() (GDISP.Backlight) +#define gdispGetBacklight() (GDISP->Backlight) /** * @brief Get the current display contrast. * * @api */ -#define gdispGetContrast() (GDISP.Contrast) +#define gdispGetContrast() (GDISP->Contrast) /* More interesting macro's */ @@ -936,7 +895,6 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); */ #define gdispUnsetClip() gdispSetClip(0,0,gdispGetWidth(),gdispGetHeight()) - #ifdef __cplusplus } #endif diff --git a/include/gdisp/lld/emulation.c b/include/gdisp/lld/emulation.c deleted file mode 100644 index cb0c9c4b..00000000 --- a/include/gdisp/lld/emulation.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file include/gdisp/lld/emulation.c - * @brief GDISP emulation routines for stuff the driver dosen't support - * - * @addtogroup GDISP - * - * @details Even though this is a software emulation of a low level driver - * most validation doesn't need to happen here as eventually - * we call a real low level driver routine and if validation is - * required - it will do it. - * - * @{ - */ -#ifndef GDISP_EMULATION_C -#define GDISP_EMULATION_C - -#if GFX_USE_GDISP - -/* Include the low level driver information */ -#include "gdisp/lld/gdisp_lld.h" - -/* Declare the GDISP structure */ -GDISPDriver GDISP; - -#if !GDISP_HARDWARE_CLEARS - void gdisp_lld_clear(color_t color) { - gdisp_lld_fill_area(0, 0, GDISP.Width, GDISP.Height, color); - } -#endif - -#if !GDISP_HARDWARE_LINES - void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { - int16_t dy, dx; - int16_t addx, addy; - int16_t P, diff, i; - - #if GDISP_HARDWARE_FILLS || GDISP_HARDWARE_SCROLL - // speed improvement if vertical or horizontal - if (x0 == x1) { - if (y1 > y0) - gdisp_lld_fill_area(x0, y0, 1, y1-y0+1, color); - else - gdisp_lld_fill_area(x0, y1, 1, y0-y1+1, color); - return; - } - if (y0 == y1) { - if (x1 > x0) - gdisp_lld_fill_area(x0, y0, x1-x0+1, 1, color); - else - gdisp_lld_fill_area(x1, y0, x0-x1+1, 1, color); - return; - } - #endif - - if (x1 >= x0) { - dx = x1 - x0; - addx = 1; - } else { - dx = x0 - x1; - addx = -1; - } - if (y1 >= y0) { - dy = y1 - y0; - addy = 1; - } else { - dy = y0 - y1; - addy = -1; - } - - if (dx >= dy) { - dy *= 2; - P = dy - dx; - diff = P - dx; - - for(i=0; i<=dx; ++i) { - gdisp_lld_draw_pixel(x0, y0, color); - if (P < 0) { - P += dy; - x0 += addx; - } else { - P += diff; - x0 += addx; - y0 += addy; - } - } - } else { - dx *= 2; - P = dx - dy; - diff = P - dy; - - for(i=0; i<=dy; ++i) { - gdisp_lld_draw_pixel(x0, y0, color); - if (P < 0) { - P += dx; - y0 += addy; - } else { - P += diff; - x0 += addx; - y0 += addy; - } - } - } - } -#endif - -#if !GDISP_HARDWARE_FILLS - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - #if GDISP_HARDWARE_SCROLL - gdisp_lld_vertical_scroll(x, y, cx, cy, cy, color); - #elif GDISP_HARDWARE_LINES - coord_t x1, y1; - - x1 = x + cx - 1; - y1 = y + cy; - for(; y < y1; y++) - gdisp_lld_draw_line(x, y, x1, y, color); - #else - coord_t x0, x1, y1; - - x0 = x; - x1 = x + cx; - y1 = y + cy; - for(; y < y1; y++) - for(x = x0; x < x1; x++) - gdisp_lld_draw_pixel(x, y, color); - #endif - } -#endif - -#if !GDISP_HARDWARE_BITFILLS - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t x0, x1, y1; - - x0 = x; - x1 = x + cx; - y1 = y + cy; - buffer += srcy*srccx+srcx; - srccx -= cx; - for(; y < y1; y++, buffer += srccx) - for(x=x0; x < x1; x++) - gdisp_lld_draw_pixel(x, y, *buffer++); - } -#endif - -#if GDISP_NEED_CLIP && !GDISP_HARDWARE_CLIP - void gdisp_lld_set_clip(coord_t x, coord_t y, coord_t cx, coord_t cy) { - #if GDISP_NEED_VALIDATION - if (x >= GDISP.Width || y >= GDISP.Height || cx < 0 || cy < 0) - return; - if (x < 0) x = 0; - if (y < 0) y = 0; - if (x+cx > GDISP.Width) cx = GDISP.Width - x; - if (y+cy > GDISP.Height) cy = GDISP.Height - y; - #endif - GDISP.clipx0 = x; - GDISP.clipy0 = y; - GDISP.clipx1 = x+cx; - GDISP.clipy1 = y+cy; - } -#endif - -#if GDISP_NEED_CIRCLE && !GDISP_HARDWARE_CIRCLES - void gdisp_lld_draw_circle(coord_t x, coord_t y, coord_t radius, color_t color) { - coord_t a, b, P; - - a = 0; - b = radius; - P = 1 - radius; - - do { - gdisp_lld_draw_pixel(x+a, y+b, color); - gdisp_lld_draw_pixel(x+b, y+a, color); - gdisp_lld_draw_pixel(x-a, y+b, color); - gdisp_lld_draw_pixel(x-b, y+a, color); - gdisp_lld_draw_pixel(x+b, y-a, color); - gdisp_lld_draw_pixel(x+a, y-b, color); - gdisp_lld_draw_pixel(x-a, y-b, color); - gdisp_lld_draw_pixel(x-b, y-a, color); - if (P < 0) - P += 3 + 2*a++; - else - P += 5 + 2*(a++ - b--); - } while(a <= b); - } -#endif - -#if GDISP_NEED_CIRCLE && !GDISP_HARDWARE_CIRCLEFILLS - void gdisp_lld_fill_circle(coord_t x, coord_t y, coord_t radius, color_t color) { - coord_t a, b, P; - - a = 0; - b = radius; - P = 1 - radius; - - do { - gdisp_lld_draw_line(x-a, y+b, x+a, y+b, color); - gdisp_lld_draw_line(x-a, y-b, x+a, y-b, color); - gdisp_lld_draw_line(x-b, y+a, x+b, y+a, color); - gdisp_lld_draw_line(x-b, y-a, x+b, y-a, color); - if (P < 0) - P += 3 + 2*a++; - else - P += 5 + 2*(a++ - b--); - } while(a <= b); - } -#endif - -#if GDISP_NEED_ELLIPSE && !GDISP_HARDWARE_ELLIPSES - void gdisp_lld_draw_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - int dx = 0, dy = b; /* im I. Quadranten von links oben nach rechts unten */ - long a2 = a*a, b2 = b*b; - long err = b2-(2*b-1)*a2, e2; /* Fehler im 1. Schritt */ - - do { - gdisp_lld_draw_pixel(x+dx, y+dy, color); /* I. Quadrant */ - gdisp_lld_draw_pixel(x-dx, y+dy, color); /* II. Quadrant */ - gdisp_lld_draw_pixel(x-dx, y-dy, color); /* III. Quadrant */ - gdisp_lld_draw_pixel(x+dx, y-dy, color); /* IV. Quadrant */ - - e2 = 2*err; - if(e2 < (2*dx+1)*b2) { - dx++; - err += (2*dx+1)*b2; - } - if(e2 > -(2*dy-1)*a2) { - dy--; - err -= (2*dy-1)*a2; - } - } while(dy >= 0); - - while(dx++ < a) { /* fehlerhafter Abbruch bei flachen Ellipsen (b=1) */ - gdisp_lld_draw_pixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */ - gdisp_lld_draw_pixel(x-dx, y, color); - } - } -#endif - -#if GDISP_NEED_ELLIPSE && !GDISP_HARDWARE_ELLIPSEFILLS - void gdisp_lld_fill_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - int dx = 0, dy = b; /* im I. Quadranten von links oben nach rechts unten */ - long a2 = a*a, b2 = b*b; - long err = b2-(2*b-1)*a2, e2; /* Fehler im 1. Schritt */ - - do { - gdisp_lld_draw_line(x-dx,y+dy,x+dx,y+dy, color); - gdisp_lld_draw_line(x-dx,y-dy,x+dx,y-dy, color); - - e2 = 2*err; - if(e2 < (2*dx+1)*b2) { - dx++; - err += (2*dx+1)*b2; - } - if(e2 > -(2*dy-1)*a2) { - dy--; - err -= (2*dy-1)*a2; - } - } while(dy >= 0); - - while(dx++ < a) { /* fehlerhafter Abbruch bei flachen Ellipsen (b=1) */ - gdisp_lld_draw_pixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */ - gdisp_lld_draw_pixel(x-dx, y, color); - } - } -#endif - -#if GDISP_NEED_ARC && !GDISP_HARDWARE_ARCS - - #include <math.h> - - /* - * @brief Internal helper function for gdispDrawArc() - * - * @note DO NOT USE DIRECTLY! - * - * @param[in] x, y The middle point of the arc - * @param[in] start The start angle of the arc - * @param[in] end The end angle of the arc - * @param[in] radius The radius of the arc - * @param[in] color The color in which the arc will be drawn - * - * @notapi - */ - static void _draw_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) { - if (/*start >= 0 && */start <= 180) { - float x_maxI = x + radius*cos(start*M_PI/180); - float x_minI; - - if (end > 180) - x_minI = x - radius; - else - x_minI = x + radius*cos(end*M_PI/180); - - int a = 0; - int b = radius; - int P = 1 - radius; - - do { - if(x-a <= x_maxI && x-a >= x_minI) - gdisp_lld_draw_pixel(x-a, y-b, color); - if(x+a <= x_maxI && x+a >= x_minI) - gdisp_lld_draw_pixel(x+a, y-b, color); - if(x-b <= x_maxI && x-b >= x_minI) - gdisp_lld_draw_pixel(x-b, y-a, color); - if(x+b <= x_maxI && x+b >= x_minI) - gdisp_lld_draw_pixel(x+b, y-a, color); - - if (P < 0) { - P = P + 3 + 2*a; - a = a + 1; - } else { - P = P + 5 + 2*(a - b); - a = a + 1; - b = b - 1; - } - } while(a <= b); - } - - if (end > 180 && end <= 360) { - float x_maxII = x+radius*cos(end*M_PI/180); - float x_minII; - - if(start <= 180) - x_minII = x - radius; - else - x_minII = x+radius*cos(start*M_PI/180); - - int a = 0; - int b = radius; - int P = 1 - radius; - - do { - if(x-a <= x_maxII && x-a >= x_minII) - gdisp_lld_draw_pixel(x-a, y+b, color); - if(x+a <= x_maxII && x+a >= x_minII) - gdisp_lld_draw_pixel(x+a, y+b, color); - if(x-b <= x_maxII && x-b >= x_minII) - gdisp_lld_draw_pixel(x-b, y+a, color); - if(x+b <= x_maxII && x+b >= x_minII) - gdisp_lld_draw_pixel(x+b, y+a, color); - - if (P < 0) { - P = P + 3 + 2*a; - a = a + 1; - } else { - P = P + 5 + 2*(a - b); - a = a + 1; - b = b - 1; - } - } while (a <= b); - } - } - - void gdisp_lld_draw_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color) { - if(endangle < startangle) { - _draw_arc(x, y, startangle, 360, radius, color); - _draw_arc(x, y, 0, endangle, radius, color); - } else { - _draw_arc(x, y, startangle, endangle, radius, color); - } - } -#endif - -#if GDISP_NEED_ARC && !GDISP_HARDWARE_ARCFILLS - /* - * @brief Internal helper function for gdispDrawArc() - * - * @note DO NOT USE DIRECTLY! - * - * @param[in] x, y The middle point of the arc - * @param[in] start The start angle of the arc - * @param[in] end The end angle of the arc - * @param[in] radius The radius of the arc - * @param[in] color The color in which the arc will be drawn - * - * @notapi - */ - static void _fill_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) { - if (/*start >= 0 && */start <= 180) { - float x_maxI = x + radius*cos(start*M_PI/180); - float x_minI; - - if (end > 180) - x_minI = x - radius; - else - x_minI = x + radius*cos(end*M_PI/180); - - int a = 0; - int b = radius; - int P = 1 - radius; - - do { - if(x-a <= x_maxI && x-a >= x_minI) - gdisp_lld_draw_line(x, y, x-a, y-b, color); - if(x+a <= x_maxI && x+a >= x_minI) - gdisp_lld_draw_line(x, y, x+a, y-b, color); - if(x-b <= x_maxI && x-b >= x_minI) - gdisp_lld_draw_line(x, y, x-b, y-a, color); - if(x+b <= x_maxI && x+b >= x_minI) - gdisp_lld_draw_line(x, y, x+b, y-a, color); - - if (P < 0) { - P = P + 3 + 2*a; - a = a + 1; - } else { - P = P + 5 + 2*(a - b); - a = a + 1; - b = b - 1; - } - } while(a <= b); - } - - if (end > 180 && end <= 360) { - float x_maxII = x+radius*cos(end*M_PI/180); - float x_minII; - - if(start <= 180) - x_minII = x - radius; - else - x_minII = x+radius*cos(start*M_PI/180); - - int a = 0; - int b = radius; - int P = 1 - radius; - - do { - if(x-a <= x_maxII && x-a >= x_minII) - gdisp_lld_draw_line(x, y, x-a, y+b, color); - if(x+a <= x_maxII && x+a >= x_minII) - gdisp_lld_draw_line(x, y, x+a, y+b, color); - if(x-b <= x_maxII && x-b >= x_minII) - gdisp_lld_draw_line(x, y, x-b, y+a, color); - if(x+b <= x_maxII && x+b >= x_minII) - gdisp_lld_draw_line(x, y, x+b, y+a, color); - - if (P < 0) { - P = P + 3 + 2*a; - a = a + 1; - } else { - P = P + 5 + 2*(a - b); - a = a + 1; - b = b - 1; - } - } while (a <= b); - } - } - - void gdisp_lld_fill_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color) { - if(endangle < startangle) { - _fill_arc(x, y, startangle, 360, radius, color); - _fill_arc(x, y, 0, endangle, radius, color); - } else { - _fill_arc(x, y, startangle, endangle, radius, color); - } - } -#endif - -#if GDISP_NEED_CONTROL && !GDISP_HARDWARE_CONTROL - void gdisp_lld_control(unsigned what, void *value) { - (void)what; - (void)value; - /* Ignore everything */ - } -#endif - -#if GDISP_NEED_QUERY && !GDISP_HARDWARE_QUERY -void *gdisp_lld_query(unsigned what) { - (void) what; - return (void *)-1; -} -#endif - -#if GDISP_NEED_MSGAPI - void gdisp_lld_msg_dispatch(gdisp_lld_msg_t *msg) { - switch(msg->action) { - case GDISP_LLD_MSG_NOP: - break; - case GDISP_LLD_MSG_INIT: - gdisp_lld_init(); - break; - case GDISP_LLD_MSG_CLEAR: - gdisp_lld_clear(msg->clear.color); - break; - case GDISP_LLD_MSG_DRAWPIXEL: - gdisp_lld_draw_pixel(msg->drawpixel.x, msg->drawpixel.y, msg->drawpixel.color); - break; - case GDISP_LLD_MSG_FILLAREA: - gdisp_lld_fill_area(msg->fillarea.x, msg->fillarea.y, msg->fillarea.cx, msg->fillarea.cy, msg->fillarea.color); - break; - case GDISP_LLD_MSG_BLITAREA: - gdisp_lld_blit_area_ex(msg->blitarea.x, msg->blitarea.y, msg->blitarea.cx, msg->blitarea.cy, msg->blitarea.srcx, msg->blitarea.srcy, msg->blitarea.srccx, msg->blitarea.buffer); - break; - case GDISP_LLD_MSG_DRAWLINE: - gdisp_lld_draw_line(msg->drawline.x0, msg->drawline.y0, msg->drawline.x1, msg->drawline.y1, msg->drawline.color); - break; - #if GDISP_NEED_CLIP - case GDISP_LLD_MSG_SETCLIP: - gdisp_lld_set_clip(msg->setclip.x, msg->setclip.y, msg->setclip.cx, msg->setclip.cy); - break; - #endif - #if GDISP_NEED_CIRCLE - case GDISP_LLD_MSG_DRAWCIRCLE: - gdisp_lld_draw_circle(msg->drawcircle.x, msg->drawcircle.y, msg->drawcircle.radius, msg->drawcircle.color); - break; - case GDISP_LLD_MSG_FILLCIRCLE: - gdisp_lld_fill_circle(msg->fillcircle.x, msg->fillcircle.y, msg->fillcircle.radius, msg->fillcircle.color); - break; - #endif - #if GDISP_NEED_ELLIPSE - case GDISP_LLD_MSG_DRAWELLIPSE: - gdisp_lld_draw_ellipse(msg->drawellipse.x, msg->drawellipse.y, msg->drawellipse.a, msg->drawellipse.b, msg->drawellipse.color); - break; - case GDISP_LLD_MSG_FILLELLIPSE: - gdisp_lld_fill_ellipse(msg->fillellipse.x, msg->fillellipse.y, msg->fillellipse.a, msg->fillellipse.b, msg->fillellipse.color); - break; - #endif - #if GDISP_NEED_ARC - case GDISP_LLD_MSG_DRAWARC: - gdisp_lld_draw_circle(msg->drawarc.x, msg->drawarc.y, msg->drawarc.radius, msg->drawarc.startangle, msg->drawarc.endangle, msg->drawarc.color); - break; - case GDISP_LLD_MSG_FILLARC: - gdisp_lld_fill_circle(msg->fillarc.x, msg->fillarc.y, msg->fillarc.radius, msg->fillarc.startangle, msg->fillarc.endangle, msg->fillarc.color); - break; - #endif - #if GDISP_NEED_PIXELREAD - case GDISP_LLD_MSG_GETPIXELCOLOR: - msg->getpixelcolor.result = gdisp_lld_get_pixel_color(msg->getpixelcolor.x, msg->getpixelcolor.y); - break; - #endif - #if GDISP_NEED_SCROLL - case GDISP_LLD_MSG_VERTICALSCROLL: - gdisp_lld_vertical_scroll(msg->verticalscroll.x, msg->verticalscroll.y, msg->verticalscroll.cx, msg->verticalscroll.cy, msg->verticalscroll.lines, msg->verticalscroll.bgcolor); - break; - #endif - #if GDISP_NEED_CONTROL - case GDISP_LLD_MSG_CONTROL: - gdisp_lld_control(msg->control.what, msg->control.value); - break; - #endif - #if GDISP_NEED_QUERY - case GDISP_LLD_MSG_QUERY: - msg->query.result = gdisp_lld_query(msg->query.what); - break; - #endif - } - } -#endif - -#endif /* GFX_USE_GDISP */ -#endif /* GDISP_EMULATION_C */ -/** @} */ - diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 98c7569c..46d5488a 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -27,16 +27,35 @@ * @{ */ /** - * @brief Hardware accelerated line drawing. + * @brief Hardware streaming interface is supported. * @details If set to @p FALSE software emulation is used. + * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver */ - #ifndef GDISP_HARDWARE_LINES - #define GDISP_HARDWARE_LINES FALSE + #ifndef GDISP_HARDWARE_STREAM + #define GDISP_HARDWARE_STREAM FALSE + #endif + + /** + * @brief Hardware streaming requires an explicit end call. + * @details If set to @p FALSE if an explicit stream end call is not required. + */ + #ifndef GDISP_HARDWARE_STREAM_END + #define GDISP_HARDWARE_STREAM_END FALSE + #endif + + /** + * @brief Hardware accelerated draw pixel. + * @details If set to @p FALSE software emulation is used. + * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + */ + #ifndef GDISP_HARDWARE_DRAWPIXEL + #define GDISP_HARDWARE_DRAWPIXEL FALSE #endif /** * @brief Hardware accelerated screen clears. * @details If set to @p FALSE software emulation is used. + * @note This clears the entire display surface regardless of the clipping area currently set */ #ifndef GDISP_HARDWARE_CLEARS #define GDISP_HARDWARE_CLEARS FALSE @@ -58,54 +77,6 @@ #define GDISP_HARDWARE_BITFILLS FALSE #endif - /** - * @brief Hardware accelerated circles. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_CIRCLES - #define GDISP_HARDWARE_CIRCLES FALSE - #endif - - /** - * @brief Hardware accelerated filled circles. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_CIRCLEFILLS - #define GDISP_HARDWARE_CIRCLEFILLS FALSE - #endif - - /** - * @brief Hardware accelerated ellipses. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_ELLIPSES - #define GDISP_HARDWARE_ELLIPSES FALSE - #endif - - /** - * @brief Hardware accelerated filled ellipses. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_ELLIPSEFILLS - #define GDISP_HARDWARE_ELLIPSEFILLS FALSE - #endif - - /** - * @brief Hardware accelerated arc's. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_ARCS - #define GDISP_HARDWARE_ARCS FALSE - #endif - - /** - * @brief Hardware accelerated filled arcs. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_ARCFILLS - #define GDISP_HARDWARE_ARCFILLS FALSE - #endif - /** * @brief Hardware accelerated scrolling. * @details If set to @p FALSE there is no support for scrolling. @@ -141,9 +112,14 @@ /** * @brief The driver supports a clipping in hardware. * @details If set to @p FALSE there is no support for non-standard queries. + * @note If this is defined the driver must perform its own clipping on all calls to + * the driver and respond appropriately if a parameter is outside the display area. + * @note If this is not defined then the software ensures that all calls to the + * driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION + * has been set). */ #ifndef GDISP_HARDWARE_CLIP - #define GDISP_HARDWARE_CLIP FALSE + #define GDISP_HARDWARE_CLIP FALSE #endif /** @} */ @@ -161,6 +137,7 @@ * @brief The native pixel format for this device * @note Should be set to one of the following: * GDISP_PIXELFORMAT_RGB565 + * GDISP_PIXELFORMAT_BGR565 * GDISP_PIXELFORMAT_RGB888 * GDISP_PIXELFORMAT_RGB444 * GDISP_PIXELFORMAT_RGB332 @@ -208,76 +185,85 @@ /* External declarations. */ /*===========================================================================*/ +typedef struct GDISPDriver { + GDISPControl g; + + uint16_t flags; + #define GDISP_FLG_INSTREAM 0x0001 + + // Multithread Mutex + #if GDISP_NEED_MULTITHREAD + gfxMutex mutex; + #endif + + // Software clipping + #if !GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + coord_t clipx0, clipy0; + coord_t clipx1, clipy1; /* not inclusive */ + #endif + + // Driver call parameters + struct { + coord_t x, y; + coord_t cx, cy; + coord_t x1, y1; + coord_t x2, y2; + color_t color; + void *ptr; + } p; + + // Text rendering parameters + #if GDISP_NEED_TEXT + struct { + font_t font; + color_t color; + color_t bgcolor; + coord_t clipx0, clipy0; + coord_t clipx1, clipy1; + } t; + #endif +} GDISPDriver; + +extern GDISPDriver GDISP_DRIVER_STRUCT; + #ifdef __cplusplus extern "C" { #endif - /* Core functions */ - extern bool_t gdisp_lld_init(void); - - /* Some of these functions will be implemented in software by the high level driver - depending on the GDISP_HARDWARE_XXX macros defined in gdisp_lld_config.h. - */ - - /* Drawing functions */ - extern void gdisp_lld_clear(color_t color); - extern void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color); - extern void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); - extern void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer); - extern void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); - - /* Circular Drawing Functions */ - #if GDISP_NEED_CIRCLE - extern void gdisp_lld_draw_circle(coord_t x, coord_t y, coord_t radius, color_t color); - extern void gdisp_lld_fill_circle(coord_t x, coord_t y, coord_t radius, color_t color); + bool_t gdisp_lld_init(void); + #if GDISP_HARDWARE_STREAM + void gdisp_lld_stream_start(void); // Uses p.x,p.y p.cx,p.cy + void gdisp_lld_stream_color(void); // Uses p.color + #if GDISP_HARDWARE_STREAM_END + void gdisp_lld_stream_stop(void); // Uses no parameters + #endif #endif - - #if GDISP_NEED_ELLIPSE - extern void gdisp_lld_draw_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); - extern void gdisp_lld_fill_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + #if GDISP_HARDWARE_DRAWPIXEL + void gdisp_lld_draw_pixel(void); // Uses p.x,p.y p.color #endif - - /* Arc Drawing Functions */ - #if GDISP_NEED_ARC - extern void gdisp_lld_draw_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); - extern void gdisp_lld_fill_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + #if GDISP_HARDWARE_CLEARS + void gdisp_lld_clear(void); // Uses p.color #endif - - /* Text Rendering Functions */ - #if GDISP_NEED_TEXT - extern void gdisp_lld_draw_char(coord_t x, coord_t y, uint16_t c, font_t font, color_t color); - extern void gdisp_lld_fill_char(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor); + #if GDISP_HARDWARE_FILLS + void gdisp_lld_fill_area(void); // Uses p.x,p.y p.cx,p.cy p.color #endif - - /* Pixel readback */ - #if GDISP_NEED_PIXELREAD - extern color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y); + #if GDISP_HARDWARE_BITFILLS + void gdisp_lld_blit_area_ex(void); // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer) #endif - - /* Scrolling Function - clears the area scrolled out */ - #if GDISP_NEED_SCROLL - extern void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor); + #if GDISP_HARDWARE_PIXELREAD && GDISP_NEED_PIXELREAD + color_t gdisp_lld_get_pixel_color(void); // Uses p.x,p.y #endif - - /* Set driver specific control */ - #if GDISP_NEED_CONTROL - extern void gdisp_lld_control(unsigned what, void *value); + #if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL + void gdisp_lld_vertical_scroll(void); // Uses p.x,p.y p.cx,p.cy, p.y1 (=lines) p.color #endif - - /* Query driver specific data */ - #if GDISP_NEED_QUERY - extern void *gdisp_lld_query(unsigned what); + #if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL + void gdisp_lld_control(void); // Uses p.x (=what) p.ptr (=value) #endif - - /* Clipping Functions */ - #if GDISP_NEED_CLIP - extern void gdisp_lld_set_clip(coord_t x, coord_t y, coord_t cx, coord_t cy); + #if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY + void *gdisp_lld_query(void); // Uses p.x (=what); #endif - - /* Messaging API */ - #if GDISP_NEED_MSGAPI - #include "gdisp_lld_msgs.h" - extern void gdisp_lld_msg_dispatch(gdisp_lld_msg_t *msg); + #if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + void gdisp_lld_set_clip(void); // Uses p.x,p.y p.cx,p.cy #endif #ifdef __cplusplus diff --git a/include/gmisc/gmisc.h b/include/gmisc/gmisc.h index 998dda50..5943e642 100644 --- a/include/gmisc/gmisc.h +++ b/include/gmisc/gmisc.h @@ -51,6 +51,7 @@ typedef int32_t fixed; */ #define FIXED(x) ((fixed)(x)<<16) /* @< integer to fixed */ #define NONFIXED(x) ((x)>>16) /* @< fixed to integer */ +#define FIXED0_5 32768 /* @< 0.5 as a fixed (used for rounding) */ #define FP2FIXED(x) ((fixed)((x)*65536.0)) /* @< floating point to fixed */ #define FIXED2FP(x) ((double)(x)/65536.0) /* @< fixed to floating point */ /* @} */ diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 22773908..1aecd26c 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -19,438 +19,1526 @@ /* Include the low level driver information */ #include "gdisp/lld/gdisp_lld.h" +#if !GDISP_HARDWARE_STREAM && !GDISP_HARDWARE_DRAWPIXEL + #error "GDISP Driver: Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be defined" +#endif + +#if 1 + #undef INLINE + #define INLINE inline +#else + #undef INLINE + #define INLINE +#endif + /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ -#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC - static gfxMutex gdispMutex; +#define GC ((GDISPDriver *)GDISP) +GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; + +#if GDISP_NEED_MULTITHREAD + #define MUTEX_INIT() gfxMutexInit(&GC->mutex) + #define MUTEX_ENTER() gfxMutexEnter(&GC->mutex) + #define MUTEX_EXIT() gfxMutexExit(&GC->mutex) +#else + #define MUTEX_INIT() + #define MUTEX_ENTER() + #define MUTEX_EXIT() #endif -#if GDISP_NEED_ASYNC - #define GDISP_THREAD_STACK_SIZE 256 /* Just a number - not yet a reflection of actual use */ - #define GDISP_QUEUE_SIZE 8 /* We only allow a short queue */ - - static gfxQueue gdispQueue; - static gfxMutex gdispMsgsMutex; - static gfxSem gdispMsgsSem; - static gdisp_lld_msg_t gdispMsgs[GDISP_QUEUE_SIZE]; - static DECLARE_THREAD_STACK(waGDISPThread, GDISP_THREAD_STACK_SIZE); +#if GDISP_HARDWARE_STREAM_END + #define STREAM_CLEAR() if ((GC->flags & GDISP_FLG_INSTREAM)) { \ + gdisp_lld_stream_end(); \ + GC->flags &= ~GDISP_FLG_INSTREAM; \ + } +#else + #define STREAM_CLEAR() GC->flags &= ~GDISP_FLG_INSTREAM #endif -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ +#define NEED_CLIPPING (!GDISP_HARDWARE_CLIP && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP)) -#if GDISP_NEED_ASYNC - static DECLARE_THREAD_FUNCTION(GDISPThreadHandler, arg) { - (void)arg; - gdisp_lld_msg_t *pmsg; +/*==========================================================================*/ +/* Internal functions. */ +/*==========================================================================*/ - while(1) { - /* Wait for msg with work to do. */ - pmsg = (gdisp_lld_msg_t *)gfxQueueGet(&gdispQueue, TIME_INFINITE); - - /* OK - we need to obtain the mutex in case a synchronous operation is occurring */ - gfxMutexEnter(&gdispMutex); - - gdisp_lld_msg_dispatch(pmsg); - - /* Mark the message as free */ - pmsg->action = GDISP_LLD_MSG_NOP; - - gfxMutexExit(&gdispMutex); +// drawpixel_clip() +// Parameters: x,y +// Alters: cx, cy (if using streaming) +#if GDISP_HARDWARE_DRAWPIXEL + // Best is hardware accelerated pixel draw + #if NEED_CLIPPING + static INLINE void drawpixel_clip(void) { + if (GC->p.x >= GC->clipx0 && GC->p.x < GC->clipx1 && GC->p.y >= GC->clipy0 && GC->p.y < GC->clipy1) + gdisp_lld_draw_pixel(); } - return 0; + #else + #define drawpixel_clip() gdisp_lld_draw_pixel() + #endif +#else + // Worst is streaming + static INLINE void drawpixel_clip(void) { + #if NEED_CLIPPING + if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1 || GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) + return; + #endif + + GC->cx = GC->cy = 1; + gdisp_lld_stream_start(); + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + } +#endif + +// fillarea() +// Parameters: x,y cx,cy and color +// Alters: nothing +// Note: This is not clipped +#if GDISP_HARDWARE_FILLS + // Best is hardware accelerated area fill + #define fillarea() gdisp_lld_fill_area() +#elif GDISP_HARDWARE_STREAM + // Next best is hardware streaming + static INLINE void fillarea(void) { + uint32_t area; + + area = (uint32_t)GC->p.cx * GC->p.cy; + + gdisp_lld_stream_start(); + for(; area; area--) + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(gc); + #endif + } +#else + // Worst is drawing pixels + static INLINE void fillarea(void) { + coord_t x0, y0, x1, y1; + + x0 = GC->p.x; + y0 = GC->p.y; + x1 = GC->p.x + GC->p.cx; + y1 = GC->p.y + GC->p.cy; + for(; GC->p.y < y1; GC->p.y++, GC->p.x = x0) + for(; GC->p.x < x1; GC->p.x++) + gdisp_lld_draw_pixel(); + GC->p.y = y0; + } +#endif + +#if NEED_CLIPPING + #define TEST_CLIP_AREA(x,y,cx,cy) \ + if ((x) < GC->clipx0) { (cx) -= GC->clipx0 - (x); (x) = GC->clipx0; } \ + if ((y) < GC->clipy0) { (cy) -= GC->clipy0 - (y); (y) = GC->clipy0; } \ + if ((x) + (cx) > GC->clipx1) (cx) = GC->clipx1 - (x); \ + if ((y) + (cy) > GC->clipy1) (cy) = GC->clipy1 - (y); \ + if ((cx) > 0 && (cy) > 0) +#else + #define TEST_CLIP_AREA(x,y,cx,cy) +#endif + +// Parameters: x,y and x1 +// Alters: x,y x1,y1 cx,cy +static void hline_clip(void) { + // Swap the points if necessary so it always goes from x to x1 + if (GC->p.x1 < GC->p.x) { + GC->p.cx = GC->p.x; GC->p.x = GC->p.x1; GC->p.x1 = GC->p.cx; } - static gdisp_lld_msg_t *gdispAllocMsg(gdisp_msgaction_t action) { - gdisp_lld_msg_t *p; + // Clipping + #if NEED_CLIPPING + if (GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) return; + if (GC->p.x < GC->clipx0) GC->p.x = GC->clipx0; + if (GC->p.x1 >= GC->clipx1) GC->p.x1 = GC->clipx1 - 1; + if (GC->p.x1 < GC->p.x) return; + #endif - while(1) { /* To be sure, to be sure */ + // This is an optimization for the point case. It is only worthwhile however if we + // have hardware fills or if we support both hardware pixel drawing and hardware streaming + #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM) + // Is this a point + if (GC->p.x == GC->p.x1) { + #if GDISP_HARDWARE_DRAWPIXEL + // Best is hardware accelerated pixel draw + gdisp_lld_draw_pixel(); + #else + // Worst is streaming + GC->p.cx = GC->p.cy = 1; + gdisp_lld_stream_start(); + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + #endif + return; + } + #endif - /* Wait for a slot */ - gfxSemWait(&gdispMsgsSem, TIME_INFINITE); + #if GDISP_HARDWARE_FILLS + // Best is hardware accelerated area fill + GC->p.cx = GC->p.x1 - GC->p.x + 1; + GC->p.cy = 1; + gdisp_lld_fill_area(); + #elif GDISP_HARDWARE_STREAM + // Next best is streaming + GC->p.cx = GC->p.x1 - GC->p.x; + gdisp_lld_stream_start(); + do { gdisp_lld_stream_color(); } while(GC->p.cx--); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + #else + // Worst is drawing pixels + for(; GC->p.x <= GC->p.x1; GC->p.x++) + gdisp_lld_draw_pixel(); + #endif +} - /* Find the slot */ - gfxMutexEnter(&gdispMsgsMutex); - for(p=gdispMsgs; p < &gdispMsgs[GDISP_QUEUE_SIZE]; p++) { - if (p->action == GDISP_LLD_MSG_NOP) { - /* Allocate it */ - p->action = action; - gfxMutexExit(&gdispMsgsMutex); - return p; - } +// Parameters: x,y and y1 +// Alters: x,y x1,y1 cx,cy +static void vline_clip(void) { + // Swap the points if necessary so it always goes from y to y1 + if (GC->p.y1 < GC->p.y) { + GC->p.cy = GC->p.y; GC->p.y = GC->p.y1; GC->p.y1 = GC->p.cy; + } + + // Clipping + #if NEED_CLIPPING + if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1) return; + if (GC->p.y < GC->clipy0) GC->p.y = GC->clipy0; + if (GC->p.y1 >= GC->clipy1) GC->p.y1 = GC->clipy1 - 1; + if (GC->p.y1 < GC->p.y) return; + #endif + + // This is an optimization for the point case. It is only worthwhile however if we + // have hardware fills or if we support both hardware pixel drawing and hardware streaming + #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM) + // Is this a point + if (GC->p.y == GC->p.y1) { + #if GDISP_HARDWARE_DRAWPIXEL + // Best is hardware accelerated pixel draw + gdisp_lld_draw_pixel(); + #else + // Worst is streaming + GC->p.cx = GC->p.cy = 1; + gdisp_lld_stream_start(); + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + #endif + return; + } + #endif + + #if GDISP_HARDWARE_FILLS + // Best is hardware accelerated area fill + GC->p.cy = GC->p.y1 - GC->p.y + 1; + GC->p.cx = 1; + gdisp_lld_fill_area(); + #elif GDISP_HARDWARE_STREAM + // Next best is streaming + GC->p.cy = GC->p.y1 - GC->p.y; + gdisp_lld_stream_start(); + do { gdisp_lld_stream_color(); } while(GC->p.cy--); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + #else + // Worst is drawing pixels + for(; GC->p.y <= GC->p.y1; GC->p.y++) + gdisp_lld_draw_pixel(); + #endif +} + +// Parameters: x,y and x1,y1 +// Alters: x,y x1,y1 cx,cy +static void line_clip(void) { + int16_t dy, dx; + int16_t addx, addy; + int16_t P, diff, i; + + // Is this a horizontal line (or a point) + if (GC->p.y == GC->p.y1) { + hline_clip(); + return; + } + + // Is this a vertical line (or a point) + if (GC->p.x == GC->p.x1) { + vline_clip(); + return; + } + + // Not horizontal or vertical + + // Use Bresenham's line drawing algorithm. + // This should be replaced with fixed point slope based line drawing + // which is more efficient on modern processors as it branches less. + // When clipping is needed, all the clipping could also be done up front + // instead of on each pixel. + + if (GC->p.x1 >= GC->p.x) { + dx = GC->p.x1 - GC->p.x; + addx = 1; + } else { + dx = GC->p.x - GC->p.x1; + addx = -1; + } + if (GC->p.y1 >= GC->p.y) { + dy = GC->p.y1 - GC->p.y; + addy = 1; + } else { + dy = GC->p.y - GC->p.y1; + addy = -1; + } + + if (dx >= dy) { + dy <<= 1; + P = dy - dx; + diff = P - dx; + + for(i=0; i<=dx; ++i) { + drawpixel_clip(); + if (P < 0) { + P += dy; + GC->p.x += addx; + } else { + P += diff; + GC->p.x += addx; + GC->p.y += addy; } - gfxMutexExit(&gdispMsgsMutex); + } + } else { + dx <<= 1; + P = dx - dy; + diff = P - dy; - /* Oops - none found, try again */ - gfxSemSignal(&gdispMsgsSem); + for(i=0; i<=dy; ++i) { + drawpixel_clip(); + if (P < 0) { + P += dx; + GC->p.y += addy; + } else { + P += diff; + GC->p.x += addx; + GC->p.y += addy; + } } } -#endif +} /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ /* Our module initialiser */ -#if GDISP_NEED_MULTITHREAD - void _gdispInit(void) { - /* Initialise Mutex */ - gfxMutexInit(&gdispMutex); +void _gdispInit(void) { + MUTEX_INIT(); - /* Initialise driver */ - gfxMutexEnter(&gdispMutex); - gdisp_lld_init(); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void _gdispInit(void) { - unsigned i; - gfxThreadHandle hth; + /* Initialise driver */ + MUTEX_ENTER(); + gdisp_lld_init(); + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + #if GDISP_HARDWARE_CLIP + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + gdisp_lld_set_clip(); + #else + GC->clipx0 = 0; + GC->clipy0 = 0; + GC->clipx1 = GC->g.Width; + GC->clipy1 = GC->g.Height; + #endif + #endif + MUTEX_EXIT(); +} - /* Mark all the Messages as free */ - for(i=0; i < GDISP_QUEUE_SIZE; i++) - gdispMsgs[i].action = GDISP_LLD_MSG_NOP; +void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy) { + MUTEX_ENTER(); - /* Initialise our Queue, Mutex's and Counting Semaphore. - * A Mutex is required as well as the Queue and Thread because some calls have to be synchronous. - * Synchronous calls get handled by the calling thread, asynchronous by our worker thread. - */ - gfxQueueInit(&gdispQueue); - gfxMutexInit(&gdispMutex); - gfxMutexInit(&gdispMsgsMutex); - gfxSemInit(&gdispMsgsSem, GDISP_QUEUE_SIZE, GDISP_QUEUE_SIZE); + #if NEED_CLIPPING + // Test if the area is valid - if not then exit + if (x < GC->clipx0 || x+cx >= GC->clipx1 || y < GC->clipy0 || y+cy >= GC->clipy1) { + MUTEX_EXIT(); + return; + } + #endif - hth = gfxThreadCreate(waGDISPThread, sizeof(waGDISPThread), NORMAL_PRIORITY, GDISPThreadHandler, NULL); - if (hth) gfxThreadClose(hth); + GC->flags |= GDISP_FLG_INSTREAM; - /* Initialise driver - synchronous */ - gfxMutexEnter(&gdispMutex); - gdisp_lld_init(); - gfxMutexExit(&gdispMutex); - } -#else - void _gdispInit(void) { - gdisp_lld_init(); - } -#endif + #if GDISP_HARDWARE_STREAM + // Best is hardware streaming + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + gdisp_lld_stream_start(); + #else + // Worst - save the parameters and use pixel drawing -#if GDISP_NEED_MULTITHREAD - bool_t gdispIsBusy(void) { - return FALSE; - } -#elif GDISP_NEED_ASYNC - bool_t gdispIsBusy(void) { - return !gfxQueueIsEmpty(&gdispQueue); - } -#endif + // Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position + GC->p.x1 = GC->p.x = x; + GC->p.y1 = GC->p.y = y; + GC->p.x2 = GC->p.x + GC->p.cx; + GC->p.x2 = GC->p.x + GC->p.cx; + #endif -#if GDISP_NEED_MULTITHREAD - void gdispClear(color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_clear(color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void gdispClear(color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_CLEAR); - p->clear.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif + // Don't release the mutex as gdispStreamEnd() will do that. +} -#if GDISP_NEED_MULTITHREAD - void gdispDrawPixel(coord_t x, coord_t y, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_pixel(x, y, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void gdispDrawPixel(coord_t x, coord_t y, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWPIXEL); - p->drawpixel.x = x; - p->drawpixel.y = y; - p->drawpixel.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif +void gdispStreamColor(color_t color) { + // Don't touch the mutex as we should already own it + + // Ignore this call if we are not streaming + if (!(GC->flags & GDISP_FLG_INSTREAM)) + return; + + #if GDISP_HARDWARE_STREAM + // Best is hardware streaming + GC->p.color = color; + gdisp_lld_stream_color(); + #else + // Worst is using pixel drawing + GC->p.color = color; + gdisp_lld_draw_pixel(); + + // Just wrap at end-of-line and end-of-buffer + if (++GC->p.x >= GC->p.x2) { + GC->p.x = GC->p.x1; + if (++GC->p.y >= GC->p.x2) + GC->p.y = GC->p.y1; + } + #endif +} + +void gdispStreamEnd(void) { + // Only release the mutex and end the stream if we are actually streaming. + if (!(GC->flags & GDISP_FLG_INSTREAM)) + return; + + #if GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + GC->flags &= ~GDISP_FLG_INSTREAM; + MUTEX_EXIT(); +} + +void gdispDrawPixel(coord_t x, coord_t y, color_t color) { + MUTEX_ENTER(); + GC->p.x = x; + GC->p.y = y; + GC->p.color = color; + drawpixel_clip(); + MUTEX_EXIT(); +} -#if GDISP_NEED_MULTITHREAD - void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_line(x0, y0, x1, y1, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWLINE); - p->drawline.x0 = x0; - p->drawline.y0 = y0; - p->drawline.x1 = x1; - p->drawline.y1 = y1; - p->drawline.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif +void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { + MUTEX_ENTER(); + GC->p.x = x0; + GC->p.y = y0; + GC->p.x1 = x1; + GC->p.y1 = y1; + GC->p.color = color; + line_clip(); + MUTEX_EXIT(); +} -#if GDISP_NEED_MULTITHREAD - void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_area(x, y, cx, cy, color); - gfxMutexExit(&gdispMutex); +void gdispClear(color_t color) { + // Note - clear() ignores the clipping area. It clears the screen. + MUTEX_ENTER(); + + #if GDISP_HARDWARE_CLEARS + // Best is hardware accelerated clear + GC->p.color = color; + gdisp_lld_clear(); + #elif GDISP_HARDWARE_FILLS + // Next best is hardware accelerated area fill + GC->p.x = GC->p.y = 0; + GC->p.cx = GC->g.Width; + GC->p.cy = GC->g.Height; + GC->p.color = color; + gdisp_lld_fill_area(); + #elif GDISP_HARDWARE_STREAM + // Next best is streaming + uint32_t area; + + GC->p.x = GC->p.y = 0; + GC->p.cx = GC->g.Width; + GC->p.cy = GC->g.Height; + GC->p.color = color; + area = (uint32_t)GC->p.cx * GC->p.cy; + + gdisp_lld_stream_start(); + for(; area; area--) + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(gc); + #endif + #else + // Worst is drawing pixels + GC->p.color = color; + for(GC->p.y = 0; GC->p.y < GC->g.Height; GC->p.y++) + for(GC->p.x = 0; GC->p.x < GC->g.Width; GC->p.x++) + gdisp_lld_draw_pixel(); + #endif + MUTEX_EXIT(); +} + +void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { + MUTEX_ENTER(); + TEST_CLIP_AREA(x,y,cx,cy) { + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + GC->p.color = color; + fillarea(); } -#elif GDISP_NEED_ASYNC - void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLAREA); - p->fillarea.x = x; - p->fillarea.y = y; - p->fillarea.cx = cx; - p->fillarea.cy = cy; - p->fillarea.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif + MUTEX_EXIT(); +} -#if GDISP_NEED_MULTITHREAD - void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_blit_area_ex(x, y, cx, cy, srcx, srcy, srccx, buffer); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_BLITAREA); - p->blitarea.x = x; - p->blitarea.y = y; - p->blitarea.cx = cx; - p->blitarea.cy = cy; - p->blitarea.srcx = srcx; - p->blitarea.srcy = srcy; - p->blitarea.srccx = srccx; - p->blitarea.buffer = buffer; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif +void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { + MUTEX_ENTER(); + + #if NEED_CLIPPING + // This is a different cliping to fillarea() as it needs to take into account srcx,srcy + if (x < GC->clipx0) { cx -= GC->clipx0 - x; srcx += GC->clipx0 - x; x = GC->clipx0; } + if (y < GC->clipy0) { cy -= GC->clipy0 - y; srcy += GC->clipy0 - x; y = GC->clipy0; } + if (x+cx > GC->clipx1) cx = GC->clipx1 - x; + if (y+cy > GC->clipy1) cy = GC->clipy1 - y; + if (srcx+cx > srccx) cx = srccx - srcx; + if (cx <= 0 || cy <= 0) { MUTEX_EXIT(); return; } + #endif + + #if GDISP_HARDWARE_BITFILLS + // Best is hardware bitfills + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + GC->p.x1 = srcx; + GC->p.y1 = srcy; + GC->p.x2 = srccx; + GC->p.ptr = (void *)buffer; + gdisp_lld_blit_area_ex(); + #elif GDISP_HARDWARE_STREAM + // Next best is hardware streaming + + // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap + buffer += srcy*srccx+srcx; + srcx = x + cx; + srcy = y + cy; + srccx -= cx; + + gdisp_lld_stream_start(gc); + for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { + for(GC->p.x = x; GC->p.x < srcx; GC->p.x++) { + GC->p.color = *buffer++; + gdisp_lld_stream_color(); + } + } + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(gc); + #endif + #else + // Worst is drawing pixels + + // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap + buffer += srcy*srccx+srcx; + srcx = x + cx; + srcy = y + cy; + srccx -= cx; + + for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { + for(GC->p.x=x; GC->p.x < srcx; GC->p.x++) { + GC->p.color = *buffer++; + gdisp_lld_draw_pixel(); + } + } + #endif + MUTEX_EXIT(); +} -#if (GDISP_NEED_CLIP && GDISP_NEED_MULTITHREAD) +#if GDISP_NEED_CLIP void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_set_clip(x, y, cx, cy); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_CLIP && GDISP_NEED_ASYNC - void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_SETCLIP); - p->setclip.x = x; - p->setclip.y = y; - p->setclip.cx = cx; - p->setclip.cy = cy; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); + MUTEX_ENTER(); + #if GDISP_HARDWARE_CLIP + // Best is using hardware clipping + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + gdisp_lld_set_clip(); + #else + // Worst is using software clipping + if (x < 0) { cx += x; x = 0; } + if (y < 0) { cy += y; y = 0; } + if (cx <= 0 || cy <= 0 || x >= GC->g.Width || y >= GC->g.Height) { MUTEX_EXIT(); return; } + GC->clipx0 = x; + GC->clipy0 = y; + GC->clipx1 = x+cx; if (GC->clipx1 > GC->g.Width) GC->clipx1 = GC->g.Width; + GC->clipy1 = y+cy; if (GC->clipy1 > GC->g.Height) GC->clipy1 = GC->g.Height; + #endif + MUTEX_EXIT(); } #endif -#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD) +#if GDISP_NEED_CIRCLE void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_circle(x, y, radius, color); - gfxMutexExit(&gdispMutex); + coord_t a, b, P; + + MUTEX_ENTER(); + + // Calculate intermediates + a = 1; + b = radius; + P = 4 - radius; + GC->p.color = color; + + // Away we go using Bresenham's circle algorithm + // Optimized to prevent double drawing + GC->p.x = x; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x; GC->p.y = y - b; drawpixel_clip(); + GC->p.x = x + b; GC->p.y = y; drawpixel_clip(); + GC->p.x = x - b; GC->p.y = y; drawpixel_clip(); + do { + GC->p.x = x + a; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip(); + GC->p.x = x + b; GC->p.y = y + a; drawpixel_clip(); + GC->p.x = x - b; GC->p.y = y + a; drawpixel_clip(); + GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip(); + GC->p.x = x + b; GC->p.y = y - a; drawpixel_clip(); + GC->p.x = x - b; GC->p.y = y - a; drawpixel_clip(); + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + GC->p.x = x + a; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip(); + GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip(); + MUTEX_EXIT(); } -#elif GDISP_NEED_CIRCLE && GDISP_NEED_ASYNC - void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWCIRCLE); - p->drawcircle.x = x; - p->drawcircle.y = y; - p->drawcircle.radius = radius; - p->drawcircle.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); +#endif + +#if GDISP_NEED_CIRCLE + void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) { + coord_t a, b, P; + + MUTEX_ENTER(); + + // Calculate intermediates + a = 1; + b = radius; + P = 4 - radius; + GC->p.color = color; + + // Away we go using Bresenham's circle algorithm + // This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + GC->p.y = y+b; GC->p.x = x; drawpixel_clip(); + GC->p.y = y-b; GC->p.x = x; drawpixel_clip(); + do { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + if (P < 0) { + P += 3 + 2*a++; + } else { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); + P += 5 + 2*(a++ - b--); + } + } while(a < b); + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + MUTEX_EXIT(); + } +#endif + +#if GDISP_NEED_ELLIPSE + void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { + coord_t dx, dy; + int32_t a2, b2; + int32_t err, e2; + + MUTEX_ENTER(); + + // Calculate intermediates + dx = 0; + dy = b; + a2 = a*a; + b2 = b*b; + err = b2-(2*b-1)*a2; + GC->p.color = color; + + // Away we go using Bresenham's ellipse algorithm + do { + GC->p.x = x + dx; GC->p.y = y + dy; drawpixel_clip(); + GC->p.x = x - dx; GC->p.y = y + dy; drawpixel_clip(); + GC->p.x = x - dx; GC->p.y = y - dy; drawpixel_clip(); + GC->p.x = x + dx; GC->p.y = y - dy; drawpixel_clip(); + + e2 = 2*err; + if(e2 < (2*dx+1)*b2) { + dx++; + err += (2*dx+1)*b2; + } + if(e2 > -(2*dy-1)*a2) { + dy--; + err -= (2*dy-1)*a2; + } + } while(dy >= 0); + MUTEX_EXIT(); } #endif -#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD) - void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_circle(x, y, radius, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_CIRCLE && GDISP_NEED_ASYNC - void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLCIRCLE); - p->fillcircle.x = x; - p->fillcircle.y = y; - p->fillcircle.radius = radius; - p->fillcircle.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif - -#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD) - void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_ellipse(x, y, a, b, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ELLIPSE && GDISP_NEED_ASYNC - void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWELLIPSE); - p->drawellipse.x = x; - p->drawellipse.y = y; - p->drawellipse.a = a; - p->drawellipse.b = b; - p->drawellipse.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif - -#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD) +#if GDISP_NEED_ELLIPSE void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_ellipse(x, y, a, b, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ELLIPSE && GDISP_NEED_ASYNC - void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLELLIPSE); - p->fillellipse.x = x; - p->fillellipse.y = y; - p->fillellipse.a = a; - p->fillellipse.b = b; - p->fillellipse.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif + coord_t dx, dy; + int32_t a2, b2; + int32_t err, e2; -#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) - void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_arc(x, y, radius, start, end, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ARC && GDISP_NEED_ASYNC - void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWARC); - p->drawarc.x = x; - p->drawarc.y = y; - p->drawarc.radius = radius; - p->drawarc.start = start; - p->drawarc.end = end; - p->drawarc.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif + MUTEX_ENTER(); -#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) - void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_arc(x, y, radius, start, end, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ARC && GDISP_NEED_ASYNC - void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLARC); - p->fillarc.x = x; - p->fillarc.y = y; - p->fillarc.radius = radius; - p->fillarc.start = start; - p->fillarc.end = end; - p->fillarc.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); + // Calculate intermediates + dx = 0; + dy = b; + a2 = a*a; + b2 = b*b; + err = b2-(2*b-1)*a2; + GC->p.color = color; + + // Away we go using Bresenham's ellipse algorithm + // This is optimized to prevent overdrawing by drawing a line only when a y is about to change value + do { + e2 = 2*err; + if(e2 < (2*dx+1)*b2) { + dx++; + err += (2*dx+1)*b2; + } + if(e2 > -(2*dy-1)*a2) { + GC->p.y = y + dy; GC->p.x = x - dx; GC->p.x1 = x + dx; hline_clip(); + if (y) { GC->p.y = y - dy; GC->p.x = x - dx; GC->p.x1 = x + dx; hline_clip(); } + dy--; + err -= (2*dy-1)*a2; + } + } while(dy >= 0); + MUTEX_EXIT(); } #endif #if GDISP_NEED_ARC -void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { - if (2*radius > cx || 2*radius > cy) { - gdispDrawBox(x, y, cx, cy, color); - return; + #if !GMISC_NEED_FIXEDTRIG && !GMISC_NEED_FASTTRIG + #include <math.h> + #endif + + void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { + coord_t a, b, P, sedge, eedge; + uint8_t full, sbit, ebit, tbit; + + // Normalize the angles + if (start < 0) + start -= (start/360-1)*360; + else if (start >= 360) + start %= 360; + if (end < 0) + end -= (end/360-1)*360; + else if (end >= 360) + end %= 360; + + sbit = 1<<(start/45); + ebit = 1<<(end/45); + full = 0; + if (start == end) { + full = 0xFF; + } else if (end < start) { + for(tbit=sbit<<1; tbit; tbit<<=1) full |= tbit; + for(tbit=ebit>>1; tbit; tbit>>=1) full |= tbit; + } else if (sbit < 0x80) { + for(tbit=sbit<<1; tbit < ebit; tbit<<=1) full |= tbit; + } + + MUTEX_ENTER(); + GC->p.color = color; + + if (full) { + // Draw full sectors + // Optimized to prevent double drawing + a = 1; + b = radius; + P = 4 - radius; + if (full & 0x60) { GC->p.y = y+b; GC->p.x = x; drawpixel_clip(); } + if (full & 0x06) { GC->p.y = y-b; GC->p.x = x; drawpixel_clip(); } + if (full & 0x81) { GC->p.y = y; GC->p.x = x+b; drawpixel_clip(); } + if (full & 0x18) { GC->p.y = y; GC->p.x = x-b; drawpixel_clip(); } + do { + if (full & 0x01) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } + if (full & 0x02) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (full & 0x04) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (full & 0x08) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } + if (full & 0x10) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } + if (full & 0x20) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (full & 0x40) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (full & 0x80) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + if (full & 0xC0) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (full & 0x0C) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (full & 0x03) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (full & 0x30) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (full == 0xFF) + return; + } + + #if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG + sedge = NONFIXED(radius * ((sbit & 0x99) ? ffsin(start) : ffcos(start)) + FIXED0_5); + eedge = NONFIXED(radius * ((ebit & 0x99) ? ffsin(end) : ffcos(end)) + FIXED0_5); + #elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG + sedge = round(radius * ((sbit & 0x99) ? fsin(start) : fcos(start))); + eedge = round(radius * ((ebit & 0x99) ? fsin(end) : fcos(end))); + #else + sedge = round(radius * ((sbit & 0x99) ? sin(start*M_PI/180) : cos(start*M_PI/180))); + eedge = round(radius * ((ebit & 0x99) ? sin(end*M_PI/180) : cos(end*M_PI/180))); + #endif + if (sbit & 0xB4) sedge = -sedge; + if (ebit & 0xB4) eedge = -eedge; + + if (sbit != ebit) { + // Draw start and end sectors + // Optimized to prevent double drawing + a = 1; + b = radius; + P = 4 - radius; + if ((sbit & 0x20) || (ebit & 0x40)) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } + if ((sbit & 0x02) || (ebit & 0x04)) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } + if ((sbit & 0x80) || (ebit & 0x01)) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } + if ((sbit & 0x08) || (ebit & 0x10)) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + do { + if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } + if (((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } + if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } + if (((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge) || ((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) + { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge) || ((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) + { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge) || ((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) + { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge) || ((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) + { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + } else if (end < start) { + // Draw start/end sector where it is a non-internal angle + // Optimized to prevent double drawing + a = 1; + b = radius; + P = 4 - radius; + if (sbit & 0x60) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } + if (sbit & 0x06) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } + if (sbit & 0x81) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } + if (sbit & 0x18) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + do { + if ((sbit & 0x01) && (a >= sedge || a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } + if ((sbit & 0x02) && (a <= sedge || a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if ((sbit & 0x04) && (a >= sedge || a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if ((sbit & 0x08) && (a <= sedge || a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } + if ((sbit & 0x10) && (a >= sedge || a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } + if ((sbit & 0x20) && (a <= sedge || a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if ((sbit & 0x40) && (a >= sedge || a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if ((sbit & 0x80) && (a <= sedge || a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + if (((sbit & 0x04) && (a >= sedge || a <= eedge)) || ((sbit & 0x08) && (a <= sedge || a >= eedge))) + { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x40) && (a >= sedge || a <= eedge)) || ((sbit & 0x80) && (a <= sedge || a >= eedge))) + { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x01) && (a >= sedge || a <= eedge)) || ((sbit & 0x02) && (a <= sedge || a >= eedge))) + { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x10) && (a >= sedge || a <= eedge)) || ((sbit & 0x20) && (a <= sedge || a >= eedge))) + { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + } else { + // Draw start/end sector where it is a internal angle + // Optimized to prevent double drawing + a = 1; + b = radius; + P = 4 - radius; + if (((sbit & 0x20) && !eedge) || ((sbit & 0x40) && !sedge)) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x02) && !eedge) || ((sbit & 0x04) && !sedge)) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x80) && !eedge) || ((sbit & 0x01) && !sedge)) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } + if (((sbit & 0x08) && !eedge) || ((sbit & 0x10) && !sedge)) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + do { + if (((sbit & 0x01) && a >= sedge && a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } + if (((sbit & 0x02) && a <= sedge && a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x04) && a >= sedge && a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x08) && a <= sedge && a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } + if (((sbit & 0x10) && a >= sedge && a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } + if (((sbit & 0x20) && a <= sedge && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x40) && a >= sedge && a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x80) && a <= sedge && a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + if (((sbit & 0x04) && a >= sedge && a <= eedge) || ((sbit & 0x08) && a <= sedge && a >= eedge)) + { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x40) && a >= sedge && a <= eedge) || ((sbit & 0x80) && a <= sedge && a >= eedge)) + { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x01) && a >= sedge && a <= eedge) || ((sbit & 0x02) && a <= sedge && a >= eedge)) + { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x10) && a >= sedge && a <= eedge) || ((sbit & 0x20) && a <= sedge && a >= eedge)) + { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + } + MUTEX_EXIT(); } - gdispDrawArc(x+radius, y+radius, radius, 90, 180, color); - gdispDrawLine(x+radius+1, y, x+cx-2-radius, y, color); - gdispDrawArc(x+cx-1-radius, y+radius, radius, 0, 90, color); - gdispDrawLine(x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color); - gdispDrawArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color); - gdispDrawLine(x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color); - gdispDrawArc(x+radius, y+cy-1-radius, radius, 180, 270, color); - gdispDrawLine(x, y+radius+1, x, y+cy-2-radius, color); -} #endif #if GDISP_NEED_ARC -void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { - coord_t radius2; + void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { + coord_t a, b, P; + coord_t sy, ey; + fixed sxa, sxb, sxd, exa, exb, exd; + uint8_t qtr; - radius2 = radius*2; - if (radius2 > cx || radius2 > cy) { - gdispFillArea(x, y, cx, cy, color); - return; + MUTEX_ENTER(); + + // Do the trig to get the formulas for the start and end lines. + sxa = exa = FIXED(x)+FIXED0_5; + #if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG + sxb = radius*ffcos(start); sy = -NONFIXED(radius*ffsin(start) + FIXED0_5); + exb = radius*ffcos(end); ey = -NONFIXED(radius*ffsin(end) + FIXED0_5); + #elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG + sxb = FP2FIXED(radius*fcos(start)); sy = -round(radius*fsin(start)); + exb = FP2FIXED(radius*fcos(end)); ey = -round(radius*fsin(end)); + #else + sxb = FP2FIXED(radius*cos(start*M_PI/180)); sy = -round(radius*sin(start*M_PI/180)); + exb = FP2FIXED(radius*cos(end*M_PI/180)); ey = -round(radius*sin(end*M_PI/180)); + #endif + sxd = sy ? sxb/sy : sxb; + exd = ey ? exb/ey : exb; + + // Calculate which quarters and which direction we are traveling + qtr = 0; + if (sxb > 0) qtr |= 0x01; // S1=0001(1), S2=0000(0), S3=0010(2), S4=0011(3) + if (sy > 0) qtr |= 0x02; + if (exb > 0) qtr |= 0x04; // E1=0100(4), E2=0000(0), E3=1000(8), E4=1100(12) + if (ey > 0) qtr |= 0x08; + if (sy > ey) qtr |= 0x10; // order of start and end lines + + // Calculate intermediates + a = 1; + b = radius; + P = 4 - radius; + GC->p.color = color; + sxb += sxa; + exb += exa; + + // Away we go using Bresenham's circle algorithm + // This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value + + switch(qtr) { + case 0: // S2E2 sy <= ey + case 1: // S1E2 sy <= ey + if (ey && sy) { + GC->p.x = x; GC->p.x1 = x; // E2S + sxa -= sxd; exa -= exd; + } else if (sy) { + GC->p.x = x-b; GC->p.x1 = x; // C2S + sxa -= sxd; + } else if (ey) { + GC->p.x = x; GC->p.x1 = x+b; // E2C + exa -= exd; + } else { + GC->p.x = x-b; GC->p.x1 = x+b; // C2C + } + GC->p.y = y; + hline_clip(); + do { + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + sxa -= sxd; exa -= exd; + } else if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + sxa -= sxd; + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= ey) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = NONFIXED(sxb); hline_clip(); // E2S + sxb += sxd; exb += exd; + } else if (-b >= sy) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + sxb += sxd; + } else if (qtr & 1) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + } else if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 2: // S3E2 sy <= ey + case 3: // S4E2 sy <= ey + case 6: // S3E1 sy <= ey + case 7: // S4E1 sy <= ey + case 18: // S3E2 sy > ey + case 19: // S4E2 sy > ey + case 22: // S3E1 sy > ey + case 23: // S4E1 sy > ey + GC->p.y = y; GC->p.x = x; GC->p.x1 = x+b; hline_clip(); // SE2C + sxa += sxd; exa -= exd; + do { + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + exa -= exd; + } else if (!(qtr & 4)) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= ey) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + exb += exd; + } else if (!(qtr & 4)) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + if (b <= sy) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (!(qtr & 4)) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+a; hline_clip(); // S2C + } else if (!(qtr & 1)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+a; hline_clip(); // C2C + } + break; + + case 4: // S2E1 sy <= ey + case 5: // S1E1 sy <= ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + do { + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + sxa -= sxd; exa -= exd; + } else if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + sxa -= sxd; + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= ey) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + sxb += sxd; exb += exd; + } else if (-b >= sy) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + sxb += sxd; + } else if (qtr & 1) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + break; + + case 8: // S2E3 sy <= ey + case 9: // S1E3 sy <= ey + case 12: // S2E4 sy <= ey + case 13: // S1E4 sy <= ey + case 24: // S2E3 sy > ey + case 25: // S1E3 sy > ey + case 28: // S2E3 sy > ey + case 29: // S1E3 sy > ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x; hline_clip(); // C2SE + sxa -= sxd; exa += exd; + do { + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + sxa -= sxd; + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + exa += exd; + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= sy) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + sxb += sxd; + } else if (qtr & 1) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + if (b <= ey) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + exb -= exd; + } else if (qtr & 4) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+a; hline_clip(); // C2C + } + break; + + case 10: // S3E3 sy <= ey + case 14: // S3E4 sy <= ey + GC->p.y = y; GC->p.x = x; drawpixel_clip(); // S2E + sxa += sxd; exa += exd; + do { + if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + sxa += sxd; exa += exd; + } else if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + exa += exd; + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (b <= sy) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = NONFIXED(exb); hline_clip(); // S2E + sxb -= sxd; exb -= exd; + } else if (b <= ey) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + exb -= exd; + } else if (qtr & 4) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + } else if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 11: // S4E3 sy <= ey + case 15: // S4E4 sy <= ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + do { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (a <= sy) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; exa += exd; + } else if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + exa += exd; + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + if (b <= sy) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; exb -= exd; + } else if (b <= ey) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + exb -= exd; + } else if (qtr & 4) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (a <= sy) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 16: // S2E2 sy > ey + case 20: // S2E1 sy > ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + sxa -= sxd; exa -= exd; + do { + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + sxa -= sxd; exa -= exd; + } else if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + exa -= exd; + } else if (!(qtr & 4)){ + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= sy) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + sxb += sxd; exb += exd; + } else if (-b >= ey) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + exb += exd; + } else if (!(qtr & 4)){ + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (!(qtr & 4)){ + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + break; + + case 17: // S1E2 sy > ey + case 21: // S1E1 sy > ey + if (sy) { + GC->p.x = x; GC->p.x1 = x; // E2S + sxa -= sxd; exa -= exd; + } else { + GC->p.x = x; GC->p.x1 = x+b; // E2C + exa -= exd; + } + GC->p.y = y; + hline_clip(); + do { + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + sxa -= sxd; exa -= exd; + } else if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + exa -= exd; + } else if (!(qtr & 4)) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= sy) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = NONFIXED(sxb); hline_clip(); // E2S + sxb += sxd; exb += exd; + } else if (-b >= ey) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + exb += exd; + } else if (!(qtr & 4)) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + } else if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (!(qtr & 4)) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 26: // S3E3 sy > ey + case 27: // S4E3 sy > ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + do { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; exa += exd; + } else if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + if (b <= ey) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; exb -= exd; + } else if (b <= sy) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (!(qtr & 4)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 30: // S3E4 sy > ey + case 31: // S4E4 sy > ey + do { + if (a <= ey) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + sxa += sxd; exa += exd; + } else if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (b <= ey) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = NONFIXED(exb); hline_clip(); // S2E + sxb -= sxd; exb -= exd; + } else if (b <= sy) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (a <= ey) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (!(qtr & 4)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + } + + MUTEX_EXIT(); } - gdispFillArc(x+radius, y+radius, radius, 90, 180, color); - gdispFillArea(x+radius+1, y, cx-radius2, radius, color); - gdispFillArc(x+cx-1-radius, y+radius, radius, 0, 90, color); - gdispFillArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color); - gdispFillArea(x+radius+1, y+cy-radius, cx-radius2, radius, color); - gdispFillArc(x+radius, y+cy-1-radius, radius, 180, 270, color); - gdispFillArea(x, y+radius, cx, cy-radius2, color); -} + #endif -#if (GDISP_NEED_PIXELREAD && (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC)) +#if GDISP_NEED_ARC + void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { + if (2*radius > cx || 2*radius > cy) { + gdispDrawBox(x, y, cx, cy, color); + return; + } + gdispDrawArc(x+radius, y+radius, radius, 90, 180, color); + gdispDrawLine(x+radius+1, y, x+cx-2-radius, y, color); + gdispDrawArc(x+cx-1-radius, y+radius, radius, 0, 90, color); + gdispDrawLine(x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color); + gdispDrawArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color); + gdispDrawLine(x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color); + gdispDrawArc(x+radius, y+cy-1-radius, radius, 180, 270, color); + gdispDrawLine(x, y+radius+1, x, y+cy-2-radius, color); + } +#endif + +#if GDISP_NEED_ARC + void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { + coord_t radius2; + + radius2 = radius*2; + if (radius2 > cx || radius2 > cy) { + gdispFillArea(x, y, cx, cy, color); + return; + } + gdispFillArc(x+radius, y+radius, radius, 90, 180, color); + gdispFillArea(x+radius+1, y, cx-radius2, radius, color); + gdispFillArc(x+cx-1-radius, y+radius, radius, 0, 90, color); + gdispFillArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color); + gdispFillArea(x+radius+1, y+cy-radius, cx-radius2, radius, color); + gdispFillArc(x+radius, y+cy-1-radius, radius, 180, 270, color); + gdispFillArea(x, y+radius, cx, cy-radius2, color); + } +#endif + +#if GDISP_NEED_PIXELREAD color_t gdispGetPixelColor(coord_t x, coord_t y) { color_t c; /* Always synchronous as it must return a value */ - gfxMutexEnter(&gdispMutex); - c = gdisp_lld_get_pixel_color(x, y); - gfxMutexExit(&gdispMutex); + MUTEX_ENTER(); + GC->p.x = x; + GC->p.y = y; + c = gdisp_lld_get_pixel_color(); + MUTEX_EXIT(); return c; } #endif -#if (GDISP_NEED_SCROLL && GDISP_NEED_MULTITHREAD) +#if GDISP_NEED_SCROLL void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_vertical_scroll(x, y, cx, cy, lines, bgcolor); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_SCROLL && GDISP_NEED_ASYNC - void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_VERTICALSCROLL); - p->verticalscroll.x = x; - p->verticalscroll.y = y; - p->verticalscroll.cx = cx; - p->verticalscroll.cy = cy; - p->verticalscroll.lines = lines; - p->verticalscroll.bgcolor = bgcolor; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); + MUTEX_ENTER(); + #if NEED_CLIPPING + if (x < GC->clipx0) { cx -= GC->clipx0 - x; x = GC->clipx0; } + if (y < GC->clipy0) { cy -= GC->clipy0 - y; y = GC->clipy0; } + if (cx <= 0 || cy <= 0 || x >= GC->clipx1 || y >= GC->clipy1) { MUTEX_EXIT(); return; } + if (x+cx > GC->clipx1) cx = GC->clipx1 - x; + if (y+cy > GC->clipy1) cy = GC->clipy1 - y; + #endif + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + GC->p.y1 = lines; + GC->p.color = bgcolor; + gdisp_lld_vertical_scroll(); + MUTEX_EXIT(); } #endif -#if (GDISP_NEED_CONTROL && GDISP_NEED_MULTITHREAD) - void gdispControl(unsigned what, void *value) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_control(what, value); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_CONTROL && GDISP_NEED_ASYNC - void gdispControl(unsigned what, void *value) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_CONTROL); - p->control.what = what; - p->control.value = value; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } +#if GDISP_NEED_CONTROL + #if GDISP_HARDWARE_CONTROL + void gdispControl(unsigned what, void *value) { + MUTEX_ENTER(); + GC->p.x = what; + GC->p.ptr = value; + gdisp_lld_control(); + #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION + if (what == GDISP_CONTROL_ORIENTATION) { + #if GDISP_HARDWARE_CLIP + // Best is hardware clipping + GC->p.x = 0; + GC->p.y = 0; + GC->p.cx = GC->g.Width; + GC->p.cy = GC->g.Height; + gdisp_lld_set_clip(); + #else + // Worst is software clipping + GC->clipx0 = 0; + GC->clipy0 = 0; + GC->clipx1 = GC->g.Width; + GC->clipy1 = GC->g.Height; + #endif + } + #endif + MUTEX_EXIT(); + } + #else + void gdispControl(unsigned what, void *value) { + (void)what; + (void)value; + /* Ignore everything */ + } + #endif #endif -#if (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC) && GDISP_NEED_QUERY - void *gdispQuery(unsigned what) { - void *res; +#if GDISP_NEED_QUERY + #if GDISP_HARDWARE_QUERY + void *gdispQuery(unsigned what) { + void *res; - gfxMutexEnter(&gdispMutex); - res = gdisp_lld_query(what); - gfxMutexExit(&gdispMutex); - return res; - } + MUTEX_ENTER(); + GC->p.x = (coord_t)what; + res = gdisp_lld_query(); + MUTEX_EXIT(); + return res; + } + #else + void *gdispQuery(unsigned what) { + (void) what; + return (void *)-1; + } + #endif #endif /*===========================================================================*/ @@ -458,29 +1546,30 @@ void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t r /*===========================================================================*/ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - /* No mutex required as we only call high level functions which have their own mutex */ - coord_t x1, y1; + if (cx <= 0 || cy <= 0) return; + cx = x+cx-1; cy = y+cy-1; // cx, cy are now the end point. - x1 = x+cx-1; - y1 = y+cy-1; + MUTEX_ENTER(); - if (cx > 2) { - if (cy >= 1) { - gdispDrawLine(x, y, x1, y, color); - if (cy >= 2) { - gdispDrawLine(x, y1, x1, y1, color); - if (cy > 2) { - gdispDrawLine(x, y+1, x, y1-1, color); - gdispDrawLine(x1, y+1, x1, y1-1, color); - } + GC->p.color = color; + + if (cx - x > 2) { + GC->p.x = x; GC->p.y = y; GC->p.x1 = cx; hline_clip(); + if (y != cy) { + GC->p.x = x; GC->p.y = cy; GC->p.x1 = cx; hline_clip(); + if (cy - y > 2) { + y++; cy--; + GC->p.x = x; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip(); } } - } else if (cx == 2) { - gdispDrawLine(x, y, x, y1, color); - gdispDrawLine(x1, y, x1, y1, color); - } else if (cx == 1) { - gdispDrawLine(x, y, x, y1, color); + } else { + GC->p.x = x; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + if (x != cx) { + GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + } } + MUTEX_EXIT(); } #if GDISP_NEED_CONVEX_POLYGON @@ -488,9 +1577,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { const point *epnt, *p; epnt = &pntarray[cnt-1]; - for(p = pntarray; p < epnt; p++) - gdispDrawLine(tx+p->x, ty+p->y, tx+p[1].x, ty+p[1].y, color); - gdispDrawLine(tx+p->x, ty+p->y, tx+pntarray->x, ty+pntarray->y, color); + + MUTEX_ENTER(); + GC->p.color = color; + for(p = pntarray; p < epnt; p++) { + GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+p[1].x; GC->p.y1=ty+p[1].y; line_clip(); + } + GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+pntarray->x; GC->p.y1=ty+pntarray->y; line_clip(); + MUTEX_EXIT(); } void gdispFillConvexPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) { @@ -510,21 +1604,21 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { y = rpnt->y; /* Work out the slopes of the two attached line segs */ - lpnt = rpnt <= pntarray ? epnts : rpnt-1; - while (lpnt->y == y) { + for (lpnt = rpnt <= pntarray ? epnts : rpnt-1; lpnt->y == y; cnt--) { + if (!cnt) return; lx = FIXED(lpnt->x); lpnt = lpnt <= pntarray ? epnts : lpnt-1; - if (!cnt--) return; } - rpnt = rpnt >= epnts ? pntarray : rpnt+1; - while (rpnt->y == y) { - rx = rpnt->x<<16; + for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) { + if (!cnt) return; + rx = FIXED(rpnt->x); rpnt = rpnt >= epnts ? pntarray : rpnt+1; - if (!cnt--) return; } lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y); rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y); + MUTEX_ENTER(); + GC->p.color = color; while(1) { /* Determine our boundary */ ymax = rpnt->y < lpnt->y ? rpnt->y : lpnt->y; @@ -539,38 +1633,40 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { * of pixels. */ if (lxc < rxc) { - if (rxc - lxc == 1) - gdispDrawPixel(tx+lxc, ty+y, color); - else - gdispDrawLine(tx+lxc, ty+y, tx+rxc-1, ty+y, color); + GC->p.x=tx+lxc; GC->p.y=ty+y; GC->p.x1=tx+rxc-1; hline_clip(); } else if (lxc > rxc) { - if (lxc - rxc == 1) - gdispDrawPixel(tx+rxc, ty+y, color); - else - gdispDrawLine(tx+rxc, ty+y, tx+lxc-1, ty+y, color); + GC->p.x=tx+rxc; GC->p.y=ty+y; GC->p.x1=tx+lxc-1; hline_clip(); } lx += lk; rx += rk; } - if (!cnt--) return; + if (!cnt) { + MUTEX_EXIT(); + return; + } + cnt--; /* Replace the appropriate point */ if (ymax == lpnt->y) { - lpnt = lpnt <= pntarray ? epnts : lpnt-1; - while (lpnt->y == y) { + for (lpnt = lpnt <= pntarray ? epnts : lpnt-1; lpnt->y == y; cnt--) { + if (!cnt) { + MUTEX_EXIT(); + return; + } lx = FIXED(lpnt->x); lpnt = lpnt <= pntarray ? epnts : lpnt-1; - if (!cnt--) return; } lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y); } else { - rpnt = rpnt >= epnts ? pntarray : rpnt+1; - while (rpnt->y == y) { + for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) { + if (!cnt) { + MUTEX_EXIT(); + return; + } rx = FIXED(rpnt->x); rpnt = rpnt >= epnts ? pntarray : rpnt+1; - if (!cnt--) return; } rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y); } @@ -582,146 +1678,130 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { #include "mcufont.h" #if GDISP_NEED_ANTIALIAS && GDISP_NEED_PIXELREAD - static void text_draw_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; if (alpha == 255) { - if (count == 1) - gdispDrawPixel(x, y, ((color_t *)state)[0]); - else - gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; GC->p.color = GC->t.color; + hline_clip(); } else { - while (count--) { - gdispDrawPixel(x, y, gdispBlendColor(((color_t *)state)[0], gdispGetPixelColor(x, y), alpha)); - x++; + for (; count; count--, x++) { + GC->p.x = x; GC->p.y = y; + GC->p.color = gdispBlendColor(GC->t.color, gdisp_lld_get_pixel_color(), alpha); + drawpixel_clip(); } } } #else - static void text_draw_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + (void) state; + if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; if (alpha > 0x80) { // A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased - if (count == 1) - gdispDrawPixel(x, y, ((color_t *)state)[0]); - else - gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; GC->p.color = GC->t.color; + hline_clip(); } } #endif - void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { - /* No mutex required as we only call high level functions which have their own mutex */ - mf_render_character(font, x, y, c, text_draw_char_callback, &color); - } - #if GDISP_NEED_ANTIALIAS - static void text_fill_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + static void fillcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + (void) state; + if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; if (alpha == 255) { - if (count == 1) - gdispDrawPixel(x, y, ((color_t *)state)[0]); - else - gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + GC->p.color = GC->t.color; } else { - while (count--) { - gdispDrawPixel(x, y, gdispBlendColor(((color_t *)state)[0], ((color_t *)state)[1], alpha)); - x++; - } + GC->p.color = gdispBlendColor(GC->t.color, GC->t.bgcolor, alpha); } + GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; + hline_clip(); } #else - #define text_fill_char_callback text_draw_char_callback + #define fillcharline drawcharline #endif - void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) { - /* No mutex required as we only call high level functions which have their own mutex */ - color_t state[2]; - - state[0] = color; - state[1] = bgcolor; - - gdispFillArea(x, y, mf_character_width(font, c) + font->baseline_x, font->height, bgcolor); - mf_render_character(font, x, y, c, text_fill_char_callback, state); + /* Callback to render characters. */ + static uint8_t drawcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { + (void) state; + return mf_render_character(GC->t.font, x, y, ch, drawcharline, 0); } - typedef struct - { - font_t font; - color_t color; - coord_t x, y; - coord_t cx, cy; - } gdispDrawString_state_t; - /* Callback to render characters. */ - static uint8_t gdispDrawString_callback(int16_t x, int16_t y, mf_char character, void *state) - { - gdispDrawString_state_t *s = state; - uint8_t w; - - w = mf_character_width(s->font, character); - if (x >= s->x && x+w < s->x + s->cx && y >= s->y && y+s->font->height <= s->y + s->cy) - mf_render_character(s->font, x, y, character, text_draw_char_callback, &s->color); - return w; + static uint8_t fillcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { + (void) state; + return mf_render_character(GC->t.font, x, y, ch, fillcharline, 0); + } + + void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { + MUTEX_ENTER(); + GC->t.font = font; + GC->t.clipx0 = x; + GC->t.clipy0 = y; + GC->t.clipx1 = x + mf_character_width(font, c) + font->baseline_x; + GC->t.clipy1 = y + font->height; + GC->t.color = color; + mf_render_character(font, x, y, c, drawcharline, 0); + MUTEX_EXIT(); + } + + void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) { + MUTEX_ENTER(); + GC->p.cx = mf_character_width(font, c) + font->baseline_x; + GC->p.cy = font->height; + GC->t.font = font; + GC->t.clipx0 = GC->p.x = x; + GC->t.clipy0 = GC->p.y = y; + GC->t.clipx1 = GC->p.x+GC->p.cx; + GC->t.clipy1 = GC->p.y+GC->p.cy; + GC->t.color = color; + GC->t.bgcolor = GC->p.color = bgcolor; + + TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { + fillarea(); + mf_render_character(font, x, y, c, fillcharline, 0); + } + MUTEX_EXIT(); } void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color) { - /* No mutex required as we only call high level functions which have their own mutex */ - gdispDrawString_state_t state; - - state.font = font; - state.color = color; - state.x = x; - state.y = y; - state.cx = GDISP.Width - x; - state.cy = GDISP.Height - y; - - x += font->baseline_x; - mf_render_aligned(font, x, y, MF_ALIGN_LEFT, str, 0, gdispDrawString_callback, &state); - } + MUTEX_ENTER(); + GC->t.font = font; + GC->t.clipx0 = x; + GC->t.clipy0 = y; + GC->t.clipx1 = x + mf_get_string_width(font, str, 0, 0); + GC->t.clipy1 = y + font->height; + GC->t.color = color; - typedef struct - { - font_t font; - color_t color[2]; - coord_t x, y; - coord_t cx, cy; - } gdispFillString_state_t; - - /* Callback to render characters. */ - static uint8_t gdispFillString_callback(int16_t x, int16_t y, mf_char character, void *state) - { - gdispFillString_state_t *s = state; - uint8_t w; - - w = mf_character_width(s->font, character); - if (x >= s->x && x+w < s->x + s->cx && y >= s->y && y+s->font->height <= s->y + s->cy) - mf_render_character(s->font, x, y, character, text_fill_char_callback, s->color); - return w; + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, 0); + MUTEX_EXIT(); } void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) { - /* No mutex required as we only call high level functions which have their own mutex */ - gdispFillString_state_t state; - - state.font = font; - state.color[0] = color; - state.color[1] = bgcolor; - state.x = x; - state.y = y; - state.cx = mf_get_string_width(font, str, 0, 0); - state.cy = font->height; - - gdispFillArea(x, y, state.cx, state.cy, bgcolor); - mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, gdispFillString_callback, &state); + MUTEX_ENTER(); + GC->p.cx = mf_get_string_width(font, str, 0, 0); + GC->p.cy = font->height; + GC->t.font = font; + GC->t.clipx0 = GC->p.x = x; + GC->t.clipy0 = GC->p.y = y; + GC->t.clipx1 = GC->p.x+GC->p.cx; + GC->t.clipy1 = GC->p.y+GC->p.cy; + GC->t.color = color; + GC->t.bgcolor = GC->p.color = bgcolor; + + TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { + fillarea(); + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, 0); + } + MUTEX_EXIT(); } void gdispDrawStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) { - /* No mutex required as we only call high level functions which have their own mutex */ - gdispDrawString_state_t state; - - state.font = font; - state.color = color; - state.x = x; - state.y = y; - state.cx = cx; - state.cy = cy; - + MUTEX_ENTER(); + GC->t.font = font; + GC->t.clipx0 = x; + GC->t.clipy0 = y; + GC->t.clipx1 = x+cx; + GC->t.clipy1 = y+cy; + GC->t.color = color; + /* Select the anchor position */ switch(justify) { case justifyCenter: @@ -736,39 +1816,45 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { } y += (cy+1 - font->height)/2; - mf_render_aligned(font, x, y, justify, str, 0, gdispDrawString_callback, &state); + mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, 0); + MUTEX_EXIT(); } void gdispFillStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) { - /* No mutex required as we only call high level functions which have their own mutex */ - gdispFillString_state_t state; + MUTEX_ENTER(); + GC->p.cx = cx; + GC->p.cy = cy; + GC->t.font = font; + GC->t.clipx0 = GC->p.x = x; + GC->t.clipy0 = GC->p.y = y; + GC->t.clipx1 = x+cx; + GC->t.clipy1 = y+cy; + GC->t.color = color; + GC->t.bgcolor = GC->p.color = bgcolor; - state.font = font; - state.color[0] = color; - state.color[1] = bgcolor; - state.x = x; - state.y = y; - state.cx = cx; - state.cy = cy; + TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { - gdispFillArea(x, y, cx, cy, bgcolor); - - /* Select the anchor position */ - switch(justify) { - case justifyCenter: - x += (cx + 1) / 2; - break; - case justifyRight: - x += cx; - break; - default: // justifyLeft - x += font->baseline_x; - break; + // background fill + fillarea(); + + /* Select the anchor position */ + switch(justify) { + case justifyCenter: + x += (cx + 1) / 2; + break; + case justifyRight: + x += cx; + break; + default: // justifyLeft + x += font->baseline_x; + break; + } + y += (cy+1 - font->height)/2; + + /* Render */ + mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, 0); } - y += (cy+1 - font->height)/2; - - /* Render */ - mf_render_aligned(font, x, y, justify, str, 0, gdispFillString_callback, &state); + MUTEX_EXIT(); } coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) { @@ -831,5 +1917,6 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha) } #endif + #endif /* GFX_USE_GDISP */ /** @} */