aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/multiple/Win32/gdisp_lld.c346
-rw-r--r--drivers/multiple/Win32/gdisp_lld_config.h22
-rw-r--r--include/gdisp/gdisp.h494
-rw-r--r--include/gdisp/lld/emulation.c558
-rw-r--r--include/gdisp/lld/gdisp_lld.h202
-rw-r--r--include/gmisc/gmisc.h1
-rw-r--r--src/gdisp/gdisp.c2135
7 files changed, 2094 insertions, 1664 deletions
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);
-
- #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
+ dcScreen = GetDC(winRootWindow);
+ FillRect(dcScreen, &rect, hbr);
+ FillRect(dcBuffer, &rect, hbr);
+ ReleaseDC(winRootWindow, dcScreen);
- 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_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_DRIVER_NAME "Win32"
+#define GDISP_DRIVER_STRUCT GDISP_Win32
+
+#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,289 +303,254 @@ 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 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);
+/* 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.
+ *
+ * @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 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 Test if the GDISP engine is currently drawing.
- * @note This function will always return FALSE if
- * GDISP_NEED_ASYNC is not defined.
+ * @brief Clip all drawing to the defined area.
*
- * @return TRUE if gdisp is busy, FALSE otherwise
+ * @param[in] x,y The start position
+ * @param[in] cx,cy The size of the clip area
*
* @api
*/
- bool_t gdispIsBusy(void);
+ void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy);
+#endif
- /* Drawing Functions */
+/* Circle Functions */
+#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__)
/**
- * @brief Clear the display to the specified color.
+ * @brief Draw a circle.
*
- * @param[in] color The color to use when clearing the screen
+ * @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 gdispClear(color_t color);
+ void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color);
/**
- * @brief Set a pixel in the specified color.
+ * @brief Draw a filled circle.
*
- * @param[in] x,y The position to set the pixel.
- * @param[in] color The color to use
+ * @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 gdispDrawPixel(coord_t x, coord_t y, color_t color);
+ 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 a line.
+ * @brief Draw an ellipse.
*
- * @param[in] x0,y0 The start position
- * @param[in] x1,y1 The end position
- * @param[in] color The color to use
+ * @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 gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
+ void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
/**
- * @brief Fill an area with a color.
+ * @brief Draw a filled ellipse.
*
- * @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
+ * @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 gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
+ 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 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.
+ * @brief Get the color of a pixel.
+ * @return The color of the pixel.
*
- * @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
+ * @param[in] x,y The position of the pixel
*
* @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)
+ 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
-/* These routines are not hardware accelerated
- * - Do not add a hardware accelerated routines here.
- */
+/* 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
-/* Extra drawing functions */
+/* Query driver specific data */
-/**
- * @brief Draw a rectangular box.
- *
- * @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 gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
+#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__)
/**
@@ -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,83 +27,54 @@
* @{
*/
/**
- * @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 accelerated screen clears.
- * @details If set to @p FALSE software emulation is used.
- */
- #ifndef GDISP_HARDWARE_CLEARS
- #define GDISP_HARDWARE_CLEARS FALSE
- #endif
-
- /**
- * @brief Hardware accelerated rectangular fills.
- * @details If set to @p FALSE software emulation is used.
- */
- #ifndef GDISP_HARDWARE_FILLS
- #define GDISP_HARDWARE_FILLS FALSE
- #endif
-
- /**
- * @brief Hardware accelerated fills from an image.
- * @details If set to @p FALSE software emulation is used.
- */
- #ifndef GDISP_HARDWARE_BITFILLS
- #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.
+ * @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_CIRCLEFILLS
- #define GDISP_HARDWARE_CIRCLEFILLS FALSE
+ #ifndef GDISP_HARDWARE_STREAM_END
+ #define GDISP_HARDWARE_STREAM_END FALSE
#endif
/**
- * @brief Hardware accelerated ellipses.
+ * @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_ELLIPSES
- #define GDISP_HARDWARE_ELLIPSES FALSE
+ #ifndef GDISP_HARDWARE_DRAWPIXEL
+ #define GDISP_HARDWARE_DRAWPIXEL FALSE
#endif
/**
- * @brief Hardware accelerated filled ellipses.
+ * @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_ELLIPSEFILLS
- #define GDISP_HARDWARE_ELLIPSEFILLS FALSE
+ #ifndef GDISP_HARDWARE_CLEARS
+ #define GDISP_HARDWARE_CLEARS FALSE
#endif
/**
- * @brief Hardware accelerated arc's.
+ * @brief Hardware accelerated rectangular fills.
* @details If set to @p FALSE software emulation is used.
*/
- #ifndef GDISP_HARDWARE_ARCS
- #define GDISP_HARDWARE_ARCS FALSE
+ #ifndef GDISP_HARDWARE_FILLS
+ #define GDISP_HARDWARE_FILLS FALSE
#endif
/**
- * @brief Hardware accelerated filled arcs.
+ * @brief Hardware accelerated fills from an image.
* @details If set to @p FALSE software emulation is used.
*/
- #ifndef GDISP_HARDWARE_ARCFILLS
- #define GDISP_HARDWARE_ARCFILLS FALSE
+ #ifndef GDISP_HARDWARE_BITFILLS
+ #define GDISP_HARDWARE_BITFILLS FALSE
#endif
/**
@@ -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. */
/*===========================================================================*/
-#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.
- */
+typedef struct GDISPDriver {
+ GDISPControl g;
- /* 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);
- #endif
+ uint16_t flags;
+ #define GDISP_FLG_INSTREAM 0x0001
- #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);
+ // Multithread Mutex
+ #if GDISP_NEED_MULTITHREAD
+ gfxMutex mutex;
#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);
+ // Software clipping
+ #if !GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)
+ coord_t clipx0, clipy0;
+ coord_t clipx1, clipy1; /* not inclusive */
#endif
- /* Text Rendering Functions */
+ // 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
- 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);
+ struct {
+ font_t font;
+ color_t color;
+ color_t bgcolor;
+ coord_t clipx0, clipy0;
+ coord_t clipx1, clipy1;
+ } t;
#endif
+} GDISPDriver;
- /* Pixel readback */
- #if GDISP_NEED_PIXELREAD
- extern color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y);
- #endif
+extern GDISPDriver GDISP_DRIVER_STRUCT;
- /* 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);
- #endif
+#ifdef __cplusplus
+extern "C" {
+#endif
- /* Set driver specific control */
- #if GDISP_NEED_CONTROL
- extern void gdisp_lld_control(unsigned what, void *value);
+ 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
-
- /* Query driver specific data */
- #if GDISP_NEED_QUERY
- extern void *gdisp_lld_query(unsigned what);
+ #if GDISP_HARDWARE_DRAWPIXEL
+ void gdisp_lld_draw_pixel(void); // Uses p.x,p.y p.color
#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_CLEARS
+ void gdisp_lld_clear(void); // Uses p.color
#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_FILLS
+ void gdisp_lld_fill_area(void); // Uses p.x,p.y p.cx,p.cy p.color
+ #endif
+ #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
+ #if GDISP_HARDWARE_PIXELREAD && GDISP_NEED_PIXELREAD
+ color_t gdisp_lld_get_pixel_color(void); // Uses p.x,p.y
+ #endif
+ #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
+ #if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL
+ void gdisp_lld_control(void); // Uses p.x (=what) p.ptr (=value)
+ #endif
+ #if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY
+ void *gdisp_lld_query(void); // Uses p.x (=what);
+ #endif
+ #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 */
+#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
- 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);
+#define NEED_CLIPPING (!GDISP_HARDWARE_CLIP && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP))
+
+/*==========================================================================*/
+/* Internal functions. */
+/*==========================================================================*/
+
+// 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();
+ }
+ #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
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
+// 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 GDISP_NEED_ASYNC
- static DECLARE_THREAD_FUNCTION(GDISPThreadHandler, arg) {
- (void)arg;
- gdisp_lld_msg_t *pmsg;
+#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
- while(1) {
- /* Wait for msg with work to do. */
- pmsg = (gdisp_lld_msg_t *)gfxQueueGet(&gdispQueue, TIME_INFINITE);
+// 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;
+ }
+
+ // 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
- /* OK - we need to obtain the mutex in case a synchronous operation is occurring */
- gfxMutexEnter(&gdispMutex);
+ // 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
+
+ #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
+}
- gdisp_lld_msg_dispatch(pmsg);
+// 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;
+ }
- /* Mark the message as free */
- pmsg->action = GDISP_LLD_MSG_NOP;
+ // 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
- gfxMutexExit(&gdispMutex);
+ // 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;
}
- return 0;
+ #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;
}
- static gdisp_lld_msg_t *gdispAllocMsg(gdisp_msgaction_t action) {
- gdisp_lld_msg_t *p;
+ // Is this a vertical line (or a point)
+ if (GC->p.x == GC->p.x1) {
+ vline_clip();
+ return;
+ }
- while(1) { /* To be sure, to be sure */
+ // Not horizontal or vertical
- /* Wait for a slot */
- gfxSemWait(&gdispMsgsSem, TIME_INFINITE);
+ // 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.
- /* 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;
- }
- }
- gfxMutexExit(&gdispMsgsMutex);
+ 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;
+ }
- /* Oops - none found, try again */
- gfxSemSignal(&gdispMsgsSem);
+ 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;
+ }
+ }
+ } else {
+ dx <<= 1;
+ P = dx - dy;
+ diff = P - dy;
+
+ 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);
-
- /* Initialise driver */
- gfxMutexEnter(&gdispMutex);
- gdisp_lld_init();
- gfxMutexExit(&gdispMutex);
- }
-#elif GDISP_NEED_ASYNC
- void _gdispInit(void) {
- unsigned i;
- gfxThreadHandle hth;
-
- /* Mark all the Messages as free */
- for(i=0; i < GDISP_QUEUE_SIZE; i++)
- gdispMsgs[i].action = GDISP_LLD_MSG_NOP;
-
- /* 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);
-
- hth = gfxThreadCreate(waGDISPThread, sizeof(waGDISPThread), NORMAL_PRIORITY, GDISPThreadHandler, NULL);
- if (hth) gfxThreadClose(hth);
-
- /* Initialise driver - synchronous */
- gfxMutexEnter(&gdispMutex);
- gdisp_lld_init();
- gfxMutexExit(&gdispMutex);
- }
-#else
- void _gdispInit(void) {
- gdisp_lld_init();
- }
-#endif
+void _gdispInit(void) {
+ MUTEX_INIT();
+
+ /* 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();
+}
-#if GDISP_NEED_MULTITHREAD
- bool_t gdispIsBusy(void) {
- return FALSE;
- }
-#elif GDISP_NEED_ASYNC
- bool_t gdispIsBusy(void) {
- return !gfxQueueIsEmpty(&gdispQueue);
- }
-#endif
+void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy) {
+ MUTEX_ENTER();
-#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
+ #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
-#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
+ GC->flags |= GDISP_FLG_INSTREAM;
+
+ #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
+
+ // 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
+
+ // Don't release the mutex as gdispStreamEnd() will do that.
+}
+
+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);
- }
-#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);
+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();
}
-#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)
- 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
+#if GDISP_NEED_CLIP
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);
- }
-#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);
+ 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();
}
#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
+
+#if GDISP_NEED_CIRCLE
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);
+ 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 && 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
+#if GDISP_NEED_ELLIPSE
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);
+ 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_ELLIPSE && GDISP_NEED_MULTITHREAD)
- 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
+#if GDISP_NEED_ELLIPSE
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);
+ 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
+ // 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 && 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
+#if GDISP_NEED_ARC
+ #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) {
- 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);
+ 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();
}
#endif
-#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
+#if GDISP_NEED_ARC
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);
+ coord_t a, b, P;
+ coord_t sy, ey;
+ fixed sxa, sxb, sxd, exa, exb, exd;
+ uint8_t qtr;
+
+ 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();
}
+
#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;
+ 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);
}
- 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 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;
+ 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);
}
- 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_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)
- 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
+#if GDISP_NEED_SCROLL
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;
-
- x1 = x+cx-1;
- y1 = y+cy-1;
-
- 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);
- }
+ if (cx <= 0 || cy <= 0) return;
+ cx = x+cx-1; cy = y+cy-1; // cx, cy are now the end point.
+
+ MUTEX_ENTER();
+
+ 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 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);
- }
-
- typedef struct
- {
- font_t font;
- color_t color[2];
- coord_t x, y;
- coord_t cx, cy;
- } gdispFillString_state_t;
+ 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();
+ }
- /* 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;
+ 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();
+ }
- 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;
+ void gdispDrawString(coord_t x, coord_t y, const char *str, 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_get_string_width(font, str, 0, 0);
+ GC->t.clipy1 = y + font->height;
+ GC->t.color = color;
+
+ 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;
-
- state.font = font;
- state.color[0] = color;
- state.color[1] = bgcolor;
- state.x = x;
- state.y = y;
- state.cx = cx;
- state.cy = 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;
+ 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;
+
+ TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) {
+
+ // 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 */
/** @} */