Graphics: Allow 'scroll' method to only scroll inside clipRect

This commit is contained in:
Gordon Williams 2021-05-27 13:26:35 +01:00
parent 7e4d10cda2
commit b0249aa436
7 changed files with 72 additions and 60 deletions

View File

@ -13,6 +13,7 @@
Bangle.js: Switch beep/buzz to IRQs (keeps time correct even when JS is busy)
Add E.decodeUTF8 to allow UTF8 to be decoded into standard 8 bit characters
Util timer: account for 'drift' in timer when adding new tasks if running it continuously
Graphics: Allow 'scroll' method to only scroll inside clipRect
2v09 : Bangle.js: increase default advertising interval from 375 to 200ms to ease connections
Fix Math.acos for negative values (fix #1950)

View File

@ -71,20 +71,6 @@ void graphicsFallbackFillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, u
graphicsSetPixelDevice(gfx,x,y, col);
}
void graphicsFallbackScrollX(JsGraphics *gfx, int xdir, int yfrom, int yto) {
int x;
if (xdir<=0) {
int w = gfx->data.width+xdir;
for (x=0;x<w;x++)
gfx->setPixel(gfx, (int)x,(int)yto,
gfx->getPixel(gfx, (int)(x-xdir),(int)yfrom));
} else { // >0
for (x=gfx->data.width-xdir-1;x>=0;x--)
gfx->setPixel(gfx, (int)(x+xdir),(int)yto,
gfx->getPixel(gfx, (int)x,(int)yfrom));
}
}
void graphicsFallbackBlit(JsGraphics *gfx, int x1, int y1, int w, int h, int x2, int y2) {
for (int y=0;y<h;y++)
for (int x=0;x<w;x++)
@ -92,23 +78,31 @@ void graphicsFallbackBlit(JsGraphics *gfx, int x1, int y1, int w, int h, int x2,
gfx->getPixel(gfx, (int)(x+x1),(int)(y+y1)));
}
void graphicsFallbackScroll(JsGraphics *gfx, int xdir, int ydir) {
void graphicsFallbackScrollX(JsGraphics *gfx, int xdir, int yfrom, int yto, int x1, int x2) {
int x;
if (xdir<=0) {
int w = x2+xdir;
for (x=x1;x<w;x++)
gfx->setPixel(gfx, (int)x,(int)yto,
gfx->getPixel(gfx, (int)(x-xdir),(int)yfrom));
} else { // >0
for (x=x2-xdir;x>=x1;x--)
gfx->setPixel(gfx, (int)(x+xdir),(int)yto,
gfx->getPixel(gfx, (int)x,(int)yfrom));
}
}
void graphicsFallbackScroll(JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2) {
if (xdir==0 && ydir==0) return;
int y;
if (ydir<=0) {
int h = gfx->data.height+ydir;
for (y=0;y<h;y++)
graphicsFallbackScrollX(gfx, xdir, y-ydir, y);
int h = y2+ydir;
for (y=y1;y<=h;y++)
graphicsFallbackScrollX(gfx, xdir, y-ydir, y, x1, x2);
} else { // >0
for (y=gfx->data.height-ydir-1;y>=0;y--)
graphicsFallbackScrollX(gfx, xdir, y, y+ydir);
for (y=y2-ydir;y>=y1;y--)
graphicsFallbackScrollX(gfx, xdir, y, y+ydir, x1, x2);
}
#ifndef NO_MODIFIED_AREA
gfx->data.modMinX=0;
gfx->data.modMinY=0;
gfx->data.modMaxX=(short)(gfx->data.width-1);
gfx->data.modMaxY=(short)(gfx->data.height-1);
#endif
}
// ----------------------------------------------------------------------------------------------
@ -784,12 +778,24 @@ void graphicsScroll(JsGraphics *gfx, int xdir, int ydir) {
if (ydir>gfx->data.height) { ydir=gfx->data.height; scroll=false; }
if (ydir<-gfx->data.height) { ydir=-gfx->data.height; scroll=false; }
// do the scrolling
if (scroll) gfx->scroll(gfx, xdir, ydir);
#ifdef NO_MODIFIED_AREA
x1=0;
y1=0;
x2=gfx->data.width-1;
x2=gfx->data.height-1;
#else
x1=gfx->data.clipRect.x1;
y1=gfx->data.clipRect.y1;
x2=gfx->data.clipRect.x2;
y2=gfx->data.clipRect.y2;
#endif
if (scroll) gfx->scroll(gfx, xdir, ydir, x1,y1,x2,y2);
graphicsSetModified(gfx, x1,y1,x2,y2);
// fill the new area
if (xdir>0) gfx->fillRect(gfx,0,0,xdir-1,gfx->data.height-1, gfx->data.bgColor);
else if (xdir<0) gfx->fillRect(gfx,gfx->data.width+xdir,0,gfx->data.width-1,gfx->data.height-1, gfx->data.bgColor);
if (ydir>0) gfx->fillRect(gfx,0,0,gfx->data.width-1,ydir-1, gfx->data.bgColor);
else if (ydir<0) gfx->fillRect(gfx,0,gfx->data.height+ydir,gfx->data.width-1,gfx->data.height-1, gfx->data.bgColor);
if (xdir>0) gfx->fillRect(gfx,x1,y1,x1+xdir-1,y2, gfx->data.bgColor);
else if (xdir<0) gfx->fillRect(gfx,x2+1+xdir,y1,x2,y2, gfx->data.bgColor);
if (ydir>0) gfx->fillRect(gfx,x1,y1,x2,y1+ydir-1, gfx->data.bgColor);
else if (ydir<0) gfx->fillRect(gfx,x1,y2+1+ydir,x2,y2, gfx->data.bgColor);
}
static void graphicsDrawString(JsGraphics *gfx, int x1, int y1, const char *str) {

View File

@ -125,7 +125,7 @@ typedef struct JsGraphics {
void (*fillRect)(struct JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col); ///< x/y guaranteed to be in range
unsigned int (*getPixel)(struct JsGraphics *gfx, int x, int y); ///< x/y guaranteed to be in range
void (*blit)(struct JsGraphics *gfx, int x1, int y1, int w, int h, int x2, int y2); ///< blit a WxH area of x1y1 to x2y2 - all guaranteed to be in range
void (*scroll)(struct JsGraphics *gfx, int xdir, int ydir); ///< scroll - leave unscrolled area undefined (xdir/ydir guaranteed to be in range)
void (*scroll)(struct JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2); ///< scroll - leave unscrolled area undefined (all values guaranteed to be in range)
} PACKED_FLAGS JsGraphics;
typedef void (*JsGraphicsSetPixelFn)(struct JsGraphics *gfx, int x, int y, unsigned int col);
@ -190,7 +190,7 @@ unsigned int graphicsGetPixel(JsGraphics *gfx, int x, int y);
void graphicsClear(JsGraphics *gfx);
void graphicsFillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col);
void graphicsFallbackFillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col); // Simple fillrect - doesn't call device-specific FR
void graphicsFallbackScroll(JsGraphics *gfx, int xdir, int ydir);
void graphicsFallbackScroll(JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2);
void graphicsDrawRect(JsGraphics *gfx, int x1, int y1, int x2, int y2);
void graphicsDrawEllipse(JsGraphics *gfx, int x, int y, int x2, int y2);
void graphicsFillEllipse(JsGraphics *gfx, int x, int y, int x2, int y2);

View File

@ -272,13 +272,20 @@ void lcdFillRect_ArrayBuffer_flat8(JsGraphics *gfx, int x1, int y1, int x2, int
}
}
void lcdScroll_ArrayBuffer_flat8(JsGraphics *gfx, int xdir, int ydir) {
int pixels = -(xdir + ydir*gfx->data.width);
int l = gfx->data.width*gfx->data.height;
// Don't use memcpy here because memmove is smart enough to handle
// overlapping memory
if (pixels>0) memmove(&((uint8_t*)gfx->backendData)[0],&((uint8_t*)gfx->backendData)[pixels],(size_t)(l-pixels));
else if (pixels<0) memmove(&((uint8_t*)gfx->backendData)[-pixels],&((uint8_t*)gfx->backendData)[0],(size_t)(l+pixels));
void lcdScroll_ArrayBuffer_flat8(JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2) {
int clipWidth = x2 - x1;
int clipHeight = y2 - y1;
int pixels = -(xdir + ydir*clipWidth);
int startPixel = gfx->data.width * (y1 - ydir) + x1;
int row;
for (row=0; row<(clipHeight+ydir); row++) {
if (pixels<0) {
memcpy(&((uint8_t*)gfx->backendData)[startPixel-pixels],&((uint8_t*)gfx->backendData)[startPixel],(size_t)(clipWidth+xdir));
} else {
memcpy(&((uint8_t*)gfx->backendData)[startPixel],&((uint8_t*)gfx->backendData)[startPixel+pixels],(size_t)(clipWidth-xdir));
}
startPixel += gfx->data.width;
}
}
#endif

View File

@ -20,4 +20,4 @@ void lcdSetCallbacks_ArrayBuffer(JsGraphics *gfx);
void lcdSetPixel_ArrayBuffer_flat8(JsGraphics *gfx, int x, int y, unsigned int col);
unsigned int lcdGetPixel_ArrayBuffer_flat8(struct JsGraphics *gfx, int x, int y);
void lcdFillRect_ArrayBuffer_flat8(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col);
void lcdScroll_ArrayBuffer_flat8(JsGraphics *gfx, int xdir, int ydir);
void lcdScroll_ArrayBuffer_flat8(JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2);

View File

@ -62,25 +62,23 @@ void lcdMemLCD_setPixel(JsGraphics *gfx, int x, int y, unsigned int col) {
#endif
}
void lcdMemLCD_scroll(struct JsGraphics *gfx, int xdir, int ydir) {
if (xdir) return graphicsFallbackScroll(gfx, xdir, ydir);
int l = LCD_STRIDE - LCD_ROWHEADER;
void lcdMemLCD_scroll(struct JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2) {
// if we have to shift X, go with the slow method
if (xdir) return graphicsFallbackScroll(gfx, xdir, ydir, x1,y1,x2,y2);
// otherwise use memcpy
int xl = ((x2+1-x1)*LCD_BPP+7)>>3;
int xo = LCD_ROWHEADER + ((x1*LCD_BPP+7)>>3);
if (ydir<0) {
for (int y=0;y<LCD_HEIGHT+ydir;y++) {
int y2 = y-ydir;
memcpy(&lcdBuffer[y*LCD_STRIDE + LCD_ROWHEADER],&lcdBuffer[y2*LCD_STRIDE + LCD_ROWHEADER],l);
for (int y=y1;y<y2+ydir;y++) {
int yx = y-ydir;
memcpy(&lcdBuffer[y*LCD_STRIDE + xo],&lcdBuffer[yx*LCD_STRIDE + xo],xl);
}
} else if (ydir>0) {
for (int y=LCD_HEIGHT-ydir-1;y>=0;y--) {
int y2 = y+ydir;
memcpy(&lcdBuffer[y2*LCD_STRIDE + LCD_ROWHEADER],&lcdBuffer[y*LCD_STRIDE + LCD_ROWHEADER],l);
for (int y=y2-ydir-1;y>=y1;y--) {
int yx = y+ydir;
memcpy(&lcdBuffer[yx*LCD_STRIDE + xo],&lcdBuffer[y*LCD_STRIDE + xo],xl);
}
}
// set area modified
gfx->data.modMinX=0;
gfx->data.modMinY=0;
gfx->data.modMaxX=(short)(gfx->data.width-1);
gfx->data.modMaxY=(short)(gfx->data.height-1);
}
// -----------------------------------------------------------------------------

View File

@ -524,11 +524,11 @@ void lcdST7789_fillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigne
}
#endif
void lcdST7789_scroll(JsGraphics *gfx, int xdir, int ydir) {
if (lcdMode != LCDST7789_MODE_UNBUFFERED) {
// No way this is going to work double buffered!
return;
}
void lcdST7789_scroll(JsGraphics *gfx, int xdir, int ydir, int x1, int y1, int x2, int y2) {
// No way this is going to work double buffered!
if (lcdMode != LCDST7789_MODE_UNBUFFERED) return;
// we can't scroll a window either
if (x1!=0 || y1!=0 || x2!=LCD_HEIGHT-1 || y2!=LCD_HEIGHT-1) return;
/* We can't read data back, so we can't do left/right scrolling!
However we can change our index in the memory buffer window
which allows us to use the LCD itself for scrolling */