#include #define MASKWIDTH 110 #define MASKHEIGHT 88 class mask{//: public Pokitto::Display{ private: inline std::size_t getIndex(int x, int y){return (y * BufferWidth) + x;} const std::size_t BufferWidth = MASKWIDTH; const std::size_t BufferHeight = MASKHEIGHT; std::bitset<(MASKWIDTH * MASKHEIGHT)> BufferMask; uint8_t clipLine(int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1); void drawFastVLine(int16_t x, int16_t y, int16_t h); void drawFastHLine(int16_t x, int16_t y, int16_t w); void drawColumn(int16_t x, int16_t sy, int16_t ey); void drawRow(int16_t x0, int16_t x1, int16_t y); //Pokitto::Display disp; public: void setPixel(int x, int y, bool value){ if((x < 0) || (x >= BufferWidth) || (y < 0) || (y >= BufferHeight)) return; BufferMask.set(getIndex(x, y), value); } void drawPixel(int16_t x,int16_t y) {setPixel(x,y, true);} bool getPixel(int x, int y){ if((x < 0) || (x >= BufferWidth) || (y < 0) || (y >= BufferHeight)) return false; return BufferMask[getIndex(x, y)]; } void clear(){BufferMask.reset();}; void drawSprite(int16_t x, int16_t y, const uint8_t *bitmap); void maskedPixel(int x, int y, uint8_t col){ if(getPixel(x,y))game.display.drawPixel(x,y, col); } void drawCircle(int16_t x0, int16_t y0, int16_t r); void drawTriangle(int16_t x0, int16_t y0,int16_t x1, int16_t y1,int16_t x2, int16_t y2); void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1); void fillTriangle(int16_t x0, int16_t y0,int16_t x1, int16_t y1,int16_t x2, int16_t y2); }; void mask::drawSprite(int16_t x, int16_t y, const uint8_t *bitmap) { uint8_t w = *bitmap; uint8_t h = *(bitmap + 1); bitmap = bitmap + 2; //add an offset to the pointer to start after the width and height int16_t i, j; //int8_t byteNum, bitNum, byteWidth = (w + 7) >> 3; for (j = 0; j < h; j+=1) { for (i = 0; i < w; i+=2) { uint16_t col = *bitmap>>4; //higher nibble maskedPixel(x + i, y + j,col); col = *bitmap&0xF; // lower nibble maskedPixel(x + i + 1, y + j,col); bitmap++; } } } //////////////////////////////////////////////// //////////////////draw shapes ////////////////// //////////////////////////////////////////////// void mask::drawCircle(int16_t x0, int16_t y0, int16_t r) { int16_t f = 1 - r; int16_t ddF_x = 1; int16_t ddF_y = -2 * r; int16_t x = 0; int16_t y = r; setPixel(x0, y0 + r ,true); setPixel(x0, y0 - r ,true); setPixel(x0 + r, y0 ,true); setPixel(x0 - r, y0 ,true); while (x < y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; setPixel(x0 + x, y0 + y ,true); setPixel(x0 - x, y0 + y ,true); setPixel(x0 + x, y0 - y ,true); setPixel(x0 - x, y0 - y ,true); setPixel(x0 + y, y0 + x ,true); setPixel(x0 - y, y0 + x ,true); setPixel(x0 + y, y0 - x ,true); setPixel(x0 - y, y0 - x ,true); } } void mask::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2) { drawLine(x0, y0, x1, y1); drawLine(x1, y1, x2, y2); drawLine(x2, y2, x0, y0); } void mask::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { if ((uint16_t)x0 >= BufferWidth || (uint16_t)y0 >= BufferHeight || (uint16_t)x1 >= BufferWidth || (uint16_t)y1 >= BufferHeight ) { if (clipLine (&x0,&y0,&x1,&y1)==0) return; // line out of bounds } if (x0 == x1) drawColumn(x0,y0,y1); else if (y0 == y1) drawRow(x0,x1,y0); else { int e; signed int dx,dy,j, temp; signed char s1,s2, xchange; signed int x,y; x = x0; y = y0; //take absolute value if (x1 < x0) { dx = x0 - x1; s1 = -1; } else if (x1 == x0) { dx = 0; s1 = 0; } else { dx = x1 - x0; s1 = 1; } if (y1 < y0) { dy = y0 - y1; s2 = -1; } else if (y1 == y0) { dy = 0; s2 = 0; } else { dy = y1 - y0; s2 = 1; } xchange = 0; if (dy>dx) { temp = dx; dx = dy; dy = temp; xchange = 1; } e = ((int)dy<<1) - dx; for (j=0; j<=dx; j++) { drawPixel(x,y); if (e>=0) { if (xchange==1) x = x + s1; else y = y + s2; e = e - ((int)dx<<1); } if (xchange==1) y = y + s2; else x = x + s1; e = e + ((int)dy<<1); } } } uint8_t mask::clipLine(int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1){ // Check X bounds if (*x1 < *x0) { //std::swap (*x1,*x0); // swap so that we dont have to check x1 also swapWT(int16_t*, x1, x0); //std::swap (*y1,*y0); // y needs to be swaaped also swapWT(int16_t*, y1, y0); } if (*x0 >= BufferWidth) return 0; // whole line is out of bounds // Clip against X0 = 0 if (*x0 < 0) { if (*x1 < 0) return 0; // nothing visible int32_t dx = (*x1 - *x0); int32_t dy = ((*y1 - *y0) << 16); // 16.16 fixed point calculation trick int32_t m = dy/dx; *y0 = *y0 + ((m*-*x0) >> 16); // get y0 at boundary *x0 = 0; } // Clip against x1 >= width if (*x1 >= BufferWidth) { int32_t dx = (*x1 - *x0); int32_t dy = ((*y1 - *y0) << 16); // 16.16 fixed point calculation trick int32_t m = dy / dx; *y1 = *y1 + ((m * ((BufferWidth - 1) - *x1)) >> 16); // get y0 at boundary *x1 = BufferWidth-1; } // Check Y bounds if (*y1 < *y0) { //std::swap (*x1,*x0); // swap so that we dont have to check x1 also swapWT(int16_t*, x1, x0); //std::swap (*y1,*y0); // y needs to be swaaped also swapWT(int16_t*, y1, y0); } if (*y0 >= BufferHeight) return 0; // whole line is out of bounds if (*y0 < 0) { if (*y1 < 0) return 0; // nothing visible int32_t dx = (*x1 - *x0) << 16; int32_t dy = (*y1 - *y0); // 16.16 fixed point calculation trick int32_t m = dx / dy; *x0 = *x0 + ((m * -(*y0)) >> 16); // get x0 at boundary *y0 = 0; } // Clip against y1 >= height if (*y1 >= BufferHeight) { int32_t dx = (*x1 - *x0) << 16; int32_t dy = (*y1 - *y0); // 16.16 fixed point calculation trick int32_t m = dx / dy; *x1 = *x1 + ((m * ((BufferHeight - 1) - *y1)) >> 16); // get y0 at boundary *y1 = BufferHeight-1; } return 1; // clipped succesfully } void mask::drawColumn(int16_t x, int16_t sy, int16_t ey){ if ((uint16_t)sy>=BufferHeight && (uint16_t)ey>=BufferHeight) return; //completely out of bounds if ((uint16_t)x>=BufferWidth) return; //completely out of bounds if (sy>ey) { int y=sy; sy=ey; ey=y; // swap around so that x0 is less than x1 } for (int y=sy; y <= ey; y++) { drawPixel(x,y); } } void mask::drawRow(int16_t x0, int16_t x1, int16_t y){ if ((uint16_t)x0>=BufferWidth && (uint16_t)x1>=BufferWidth) return; //completely out of bounds if ((uint16_t)y>=BufferHeight) return; //completely out of bounds if (x0>x1) { int x=x0; x0=x1; x1=x; // swap around so that x0 is less than x1 } for (int x=x0; x <= x1; x++) { drawPixel(x,y); } } void mask::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2) { int16_t a, b, y, last; // Sort coordinates by Y order (y2 >= y1 >= y0) if (y0 > y1) { swapWT(int16_t,y0, y1); swapWT(int16_t,x0, x1); } if (y1 > y2) { swapWT(int16_t,y2, y1); swapWT(int16_t,x2, x1); } if (y0 > y1) { swapWT(int16_t,y0, y1); swapWT(int16_t,x0, x1); } if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing a = b = x0; if (x1 < a) a = x1; else if (x1 > b) b = x1; if (x2 < a) a = x2; else if (x2 > b) b = x2; drawFastHLine(a, y0, b - a + 1); return; } int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0, dx12 = x2 - x1, dy12 = y2 - y1, sa = 0, sb = 0; if (y1 == y2) last = y1; // Include y1 scanline else last = y1 - 1; // Skip it for (y = y0; y <= last; y++) { a = x0 + sa / dy01; b = x0 + sb / dy02; sa += dx01; sb += dx02; /* longhand: a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); */ if (a > b) swapWT(int16_t,a, b); drawFastHLine(a, y, b - a + 1); } // For lower part of triangle, find scanline crossings for segments // 0-2 and 1-2. This loop is skipped if y1=y2. sa = dx12 * (y - y1); sb = dx02 * (y - y0); for (; y <= y2; y++) { a = x1 + sa / dy12; b = x0 + sb / dy02; sa += dx12; sb += dx02; if (a > b) swapWT(int16_t,a, b); drawFastHLine(a, y, b - a + 1); } } void mask::drawFastVLine(int16_t x, int16_t y, int16_t h){ if (h<0) {y += h; h = -h;} drawColumn(x,y,y+h); } void mask::drawFastHLine(int16_t x, int16_t y, int16_t w){ if (w<0) {x += w; w = -w;} drawRow(x,x+w-1,y); }