mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
Graphics: Allow 'scroll' method to only scroll inside clipRect
This commit is contained in:
parent
7e4d10cda2
commit
b0249aa436
@ -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)
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@ -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 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user