diff -r d5e36ca9085f -r c51265b518ce brewpanel/sdlgui.c --- a/brewpanel/sdlgui.c Thu Nov 19 15:05:19 2015 +0100 +++ b/brewpanel/sdlgui.c Thu Nov 19 20:45:09 2015 +0100 @@ -495,6 +495,116 @@ /* + * SDL_Surface 32-bit circle-fill algorithm without using trig + * + * While I humbly call this "Celdecea's Method", odds are that the + * procedure has already been documented somewhere long ago. All of + * the circle-fill examples I came across utilized trig functions or + * scanning neighbor pixels. This algorithm identifies the width of + * a semi-circle at each pixel height and draws a scan-line covering + * that width. + * + * The code is not optimized but very fast, owing to the fact that it + * alters pixels in the provided surface directly rather than through + * function calls. + */ +void SDLGui_fill_circle(SDL_Surface *surface, int cx, int cy, int radius, Uint32 pixel) +{ + /* + * Note that there is more to altering the bitrate of this + * method than just changing this value. See how pixels are + * altered at the following web page for tips: + * http://www.libsdl.org/intro.en/usingvideo.html + */ + static const int BPP = 4; + double r = (double)radius; + double dy; + + for (dy = 1; dy <= r; dy += 1.0) { + /* + * This loop is unrolled a bit, only iterating through half of the + * height of the circle. The result is used to draw a scan line and + * its mirror image below it. + * + * The following formula has been simplified from our original. We + * are using half of the width of the circle because we are provided + * with a center and we need left/right coordinates. + */ + double dx = floor(sqrt((2.0 * r * dy) - (dy * dy))); + int x = cx - dx; + + // Grab a pointer to the left-most pixel for each half of the circle + Uint8 *target_pixel_a = (Uint8 *)surface->pixels + ((int)(cy + r - dy)) * surface->pitch + x * BPP; + Uint8 *target_pixel_b = (Uint8 *)surface->pixels + ((int)(cy - r + dy)) * surface->pitch + x * BPP; + + for (; x <= cx + dx; x++) { + *(Uint32 *)target_pixel_a = pixel; + *(Uint32 *)target_pixel_b = pixel; + target_pixel_a += BPP; + target_pixel_b += BPP; + } + } +} + + + +static void SDLGUI_DrawLEDRed(const SGOBJ *bdlg, int objnum) +{ + Uint32 color; + + if (bdlg[objnum].state & SG_SELECTED) { + color = SDL_MapRGB(pSdlGuiScrn->format, 255, 64, 0); + } else { + color = SDL_MapRGB(pSdlGuiScrn->format, 128, 16, 0); + } + SDLGui_fill_circle(pSdlGuiScrn, bdlg[objnum].x, bdlg[objnum].y, bdlg[objnum].w, color); +} + + + +static void SDLGUI_DrawLEDBlue(const SGOBJ *bdlg, int objnum) +{ + Uint32 color; + + if (bdlg[objnum].state & SG_SELECTED) { + color = SDL_MapRGB(pSdlGuiScrn->format, 64, 160, 255); + } else { + color = SDL_MapRGB(pSdlGuiScrn->format, 16, 48, 112); + } + SDLGui_fill_circle(pSdlGuiScrn, bdlg[objnum].x, bdlg[objnum].y, bdlg[objnum].w, color); +} + + + +static void SDLGUI_DrawLEDGreen(const SGOBJ *bdlg, int objnum) +{ + Uint32 color; + + if (bdlg[objnum].state & SG_SELECTED) { + color = SDL_MapRGB(pSdlGuiScrn->format, 80, 240, 0); + } else { + color = SDL_MapRGB(pSdlGuiScrn->format, 32, 112, 0); + } + SDLGui_fill_circle(pSdlGuiScrn, bdlg[objnum].x, bdlg[objnum].y, bdlg[objnum].w, color); +} + + + +static void SDLGUI_DrawLEDYellow(const SGOBJ *bdlg, int objnum) +{ + Uint32 color; + + if (bdlg[objnum].state & SG_SELECTED) { + color = SDL_MapRGB(pSdlGuiScrn->format, 255, 255, 0); + } else { + color = SDL_MapRGB(pSdlGuiScrn->format, 160, 144, 0); + } + SDLGui_fill_circle(pSdlGuiScrn, bdlg[objnum].x, bdlg[objnum].y, bdlg[objnum].w, color); +} + + + +/* * Draw a whole dialog. */ void SDLGui_DrawDialog(const SGOBJ *dlg) @@ -518,6 +628,18 @@ case SGBUTTON: SDLGui_DrawButton(dlg, i); break; + case SGLEDRED: + SDLGUI_DrawLEDRed(dlg, i); + break; + case SGLEDBLUE: + SDLGUI_DrawLEDBlue(dlg, i); + break; + case SGLEDGREEN: + SDLGUI_DrawLEDGreen(dlg, i); + break; + case SGLEDYELLOW: + SDLGUI_DrawLEDYellow(dlg, i); + break; } }