mirror of https://github.com/MLXXXp/Arduboy2.git
Make drawLine smarter on PIXEL_SAFE_MODE
The current drawLine leaves all the pixel-safety checks to drawPixel, which is not quite optimal for off-screen lines and partially off-screen lines. This commit changes its behavior by having it skip the draw when both ends are off-screen, and also skip when the "current pixel" goes from on-screen to off-screen. To achieve this end some API changes are done to drawPixel, since it after all does not tell whether a draw has been attempted. A (very internal; not in header) drawPixelMaybe function is now composed of drawPixel's checking part, and a drawPixelRaw for a complete absense of checks in other "safe" functions. The drawPixel signature is unchanged; it is hoped that drawPixelMaybe would be inlined, its returns stripped, exposing the drawPixelRaw call as a tail call.
This commit is contained in:
parent
0eae58c760
commit
ecf87428fd
|
@ -313,14 +313,26 @@ const uint8_t bitshift_left[] PROGMEM = {
|
||||||
};
|
};
|
||||||
|
|
||||||
void Arduboy2Base::drawPixel(int16_t x, int16_t y, uint8_t color)
|
void Arduboy2Base::drawPixel(int16_t x, int16_t y, uint8_t color)
|
||||||
|
{
|
||||||
|
drawPixelMaybe(int16_t x, int16_t y, uint8_t color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a pixel, tell me whether it has been done.
|
||||||
|
// The intent for inlining is to let drawPixel strip away the return part
|
||||||
|
// and make drawPixelRaw a tail call.
|
||||||
|
inline bool drawPixelMaybe(int16_t x, int16_t y, uint8_t color)
|
||||||
{
|
{
|
||||||
#ifdef PIXEL_SAFE_MODE
|
#ifdef PIXEL_SAFE_MODE
|
||||||
if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1))
|
if (!validPixel(x, y))
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
drawPixelRaw(x, y, color);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Arduboy2Base::drawPixelRaw(int16_t x, int16_t y, uint8_t color)
|
||||||
uint16_t row_offset;
|
uint16_t row_offset;
|
||||||
uint8_t bit;
|
uint8_t bit;
|
||||||
|
|
||||||
|
@ -501,6 +513,13 @@ void Arduboy2Base::fillCircleHelper
|
||||||
void Arduboy2Base::drawLine
|
void Arduboy2Base::drawLine
|
||||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color)
|
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color)
|
||||||
{
|
{
|
||||||
|
#ifdef PIXEL_SAFE_MODE
|
||||||
|
// No need to draw
|
||||||
|
if (!(validPixel(x0, y0) || validPixel(x1, y1))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// bresenham's algorithm - thx wikpedia
|
// bresenham's algorithm - thx wikpedia
|
||||||
bool steep = abs(y1 - y0) > abs(x1 - x0);
|
bool steep = abs(y1 - y0) > abs(x1 - x0);
|
||||||
if (steep) {
|
if (steep) {
|
||||||
|
@ -519,6 +538,9 @@ void Arduboy2Base::drawLine
|
||||||
|
|
||||||
int16_t err = dx / 2;
|
int16_t err = dx / 2;
|
||||||
int8_t ystep;
|
int8_t ystep;
|
||||||
|
|
||||||
|
bool initial_validity = steep ? validPixel(y0, x0) : validPixel(x0, y0);
|
||||||
|
bool valid;
|
||||||
|
|
||||||
if (y0 < y1)
|
if (y0 < y1)
|
||||||
{
|
{
|
||||||
|
@ -533,11 +555,16 @@ void Arduboy2Base::drawLine
|
||||||
{
|
{
|
||||||
if (steep)
|
if (steep)
|
||||||
{
|
{
|
||||||
drawPixel(y0, x0, color);
|
valid = drawPixel(y0, x0, color);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
drawPixel(x0, y0, color);
|
valid = drawPixel(x0, y0, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have reached the end of valid pixels.
|
||||||
|
if (initial_validity && !valid) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
err -= dy;
|
err -= dy;
|
||||||
|
@ -561,10 +588,14 @@ void Arduboy2Base::drawRect
|
||||||
void Arduboy2Base::drawFastVLine
|
void Arduboy2Base::drawFastVLine
|
||||||
(int16_t x, int16_t y, uint8_t h, uint8_t color)
|
(int16_t x, int16_t y, uint8_t h, uint8_t color)
|
||||||
{
|
{
|
||||||
|
// Do x bounds checks
|
||||||
|
if (x < 0 || x >= WIDTH)
|
||||||
|
return;
|
||||||
|
|
||||||
int end = y+h;
|
int end = y+h;
|
||||||
for (int a = max(0,y); a < min(end,HEIGHT); a++)
|
for (int a = max(0,y); a < min(end,HEIGHT); a++)
|
||||||
{
|
{
|
||||||
drawPixel(x,a,color);
|
drawPixelRaw(x,a,color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -430,6 +430,20 @@ class Arduboy2Base : public Arduboy2Core
|
||||||
*/
|
*/
|
||||||
void display(bool clear);
|
void display(bool clear);
|
||||||
|
|
||||||
|
/** \brief
|
||||||
|
* Tells whether a given coordinate points to a valid pixel.
|
||||||
|
*
|
||||||
|
* \param x The X coordinate of the pixel.
|
||||||
|
* \param y The Y coordinate of the pixel.
|
||||||
|
*
|
||||||
|
* \details
|
||||||
|
* This function returns true if x is in the interval [0, WIDTH) and y is in
|
||||||
|
* the interval [0, HEIGHT).
|
||||||
|
*/
|
||||||
|
bool validPixel(int16_t x, int16_t y) {
|
||||||
|
return !(x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1));
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief
|
/** \brief
|
||||||
* Set a single pixel in the display buffer to the specified color.
|
* Set a single pixel in the display buffer to the specified color.
|
||||||
*
|
*
|
||||||
|
@ -444,6 +458,10 @@ class Arduboy2Base : public Arduboy2Core
|
||||||
*/
|
*/
|
||||||
void drawPixel(int16_t x, int16_t y, uint8_t color = WHITE);
|
void drawPixel(int16_t x, int16_t y, uint8_t color = WHITE);
|
||||||
|
|
||||||
|
// Draw a pixel without checking.
|
||||||
|
// (Not officially part of the API)
|
||||||
|
void drawPixelRaw(int16_t x, int16_t y, uint8_t color);
|
||||||
|
|
||||||
/** \brief
|
/** \brief
|
||||||
* Returns the state of the given pixel in the screen buffer.
|
* Returns the state of the given pixel in the screen buffer.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue