MBED NRF51 Arduboy port

Committer:
lmayencou
Date:
Fri Jan 06 22:10:20 2017 +0000
Revision:
1:c53e766082b4
Child:
2:e3ef9f476913
display circle and hello on SPI screen !

Who changed what in which revision?

UserRevisionLine numberNew contents of line
lmayencou 1:c53e766082b4 1 #include "abstractarduboy.h"
lmayencou 1:c53e766082b4 2
lmayencou 1:c53e766082b4 3 #define _BV(b) (1UL << (b))
lmayencou 1:c53e766082b4 4 #define min(a,b) (((a)<(b))?(a):(b))
lmayencou 1:c53e766082b4 5 #define max(a,b) (((a)>(b))?(a):(b))
lmayencou 1:c53e766082b4 6 #define abs(a) (((a) < 0) ? -(a) : (a))
lmayencou 1:c53e766082b4 7 #define pgm_read_byte(a) 1
lmayencou 1:c53e766082b4 8
lmayencou 1:c53e766082b4 9 AbstractArduboy::AbstractArduboy()
lmayencou 1:c53e766082b4 10 {
lmayencou 1:c53e766082b4 11 frameRate = 60;
lmayencou 1:c53e766082b4 12 frameCount = 0;
lmayencou 1:c53e766082b4 13 eachFrameMillis = 1000 / 60;
lmayencou 1:c53e766082b4 14 lastFrameStart = 0;
lmayencou 1:c53e766082b4 15 nextFrameStart = 0;
lmayencou 1:c53e766082b4 16 post_render = false;
lmayencou 1:c53e766082b4 17 lastFrameDurationMs = 0;
lmayencou 1:c53e766082b4 18
lmayencou 1:c53e766082b4 19 currentButtonState = 0;
lmayencou 1:c53e766082b4 20 previousButtonState = 0;
lmayencou 1:c53e766082b4 21
lmayencou 1:c53e766082b4 22 textcolor = WHITE;
lmayencou 1:c53e766082b4 23 textbgcolor = BLACK;
lmayencou 1:c53e766082b4 24 textsize = 1;
lmayencou 1:c53e766082b4 25 }
lmayencou 1:c53e766082b4 26
lmayencou 1:c53e766082b4 27 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 28 // default virtual function
lmayencou 1:c53e766082b4 29 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 30 void AbstractArduboy::idle()
lmayencou 1:c53e766082b4 31 {}
lmayencou 1:c53e766082b4 32
lmayencou 1:c53e766082b4 33 void AbstractArduboy::saveMuchPower()
lmayencou 1:c53e766082b4 34 {}
lmayencou 1:c53e766082b4 35
lmayencou 1:c53e766082b4 36 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 37 // frame management
lmayencou 1:c53e766082b4 38 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 39 void AbstractArduboy::setFrameRate(uint8_t rate)
lmayencou 1:c53e766082b4 40 {
lmayencou 1:c53e766082b4 41 frameRate = rate;
lmayencou 1:c53e766082b4 42 eachFrameMillis = 1000 / rate;
lmayencou 1:c53e766082b4 43 }
lmayencou 1:c53e766082b4 44
lmayencou 1:c53e766082b4 45 bool AbstractArduboy::everyXFrames(uint8_t frames)
lmayencou 1:c53e766082b4 46 {
lmayencou 1:c53e766082b4 47 return frameCount % frames == 0;
lmayencou 1:c53e766082b4 48 }
lmayencou 1:c53e766082b4 49
lmayencou 1:c53e766082b4 50 bool AbstractArduboy::nextFrame()
lmayencou 1:c53e766082b4 51 {
lmayencou 1:c53e766082b4 52 long now = getTime();
lmayencou 1:c53e766082b4 53 uint8_t remaining;
lmayencou 1:c53e766082b4 54
lmayencou 1:c53e766082b4 55 // post render
lmayencou 1:c53e766082b4 56 if (post_render) {
lmayencou 1:c53e766082b4 57 lastFrameDurationMs = now - lastFrameStart;
lmayencou 1:c53e766082b4 58 frameCount++;
lmayencou 1:c53e766082b4 59 post_render = false;
lmayencou 1:c53e766082b4 60 }
lmayencou 1:c53e766082b4 61
lmayencou 1:c53e766082b4 62 // if it's not time for the next frame yet
lmayencou 1:c53e766082b4 63 if (now < nextFrameStart) {
lmayencou 1:c53e766082b4 64 remaining = nextFrameStart - now;
lmayencou 1:c53e766082b4 65 // if we have more than 1ms to spare, lets sleep
lmayencou 1:c53e766082b4 66 // we should be woken up by timer0 every 1ms, so this should be ok
lmayencou 1:c53e766082b4 67 if (remaining > 1)
lmayencou 1:c53e766082b4 68 idle();
lmayencou 1:c53e766082b4 69 return false;
lmayencou 1:c53e766082b4 70 }
lmayencou 1:c53e766082b4 71
lmayencou 1:c53e766082b4 72 // pre-render
lmayencou 1:c53e766082b4 73
lmayencou 1:c53e766082b4 74 // technically next frame should be last frame + each frame but if we're
lmayencou 1:c53e766082b4 75 // running a slow render we would constnatly be behind the clock
lmayencou 1:c53e766082b4 76 // keep an eye on this and see how it works. If it works well the
lmayencou 1:c53e766082b4 77 // lastFrameStart variable could be eliminated completely
lmayencou 1:c53e766082b4 78 nextFrameStart = now + eachFrameMillis;
lmayencou 1:c53e766082b4 79 lastFrameStart = now;
lmayencou 1:c53e766082b4 80 post_render = true;
lmayencou 1:c53e766082b4 81 return post_render;
lmayencou 1:c53e766082b4 82 }
lmayencou 1:c53e766082b4 83
lmayencou 1:c53e766082b4 84 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 85 // info
lmayencou 1:c53e766082b4 86 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 87 // returns the load on the CPU as a percentage
lmayencou 1:c53e766082b4 88 // this is based on how much of the time your app is spends rendering
lmayencou 1:c53e766082b4 89 // frames. This number can be higher than 100 if your app is rendering
lmayencou 1:c53e766082b4 90 // really slowly.
lmayencou 1:c53e766082b4 91 int AbstractArduboy::cpuLoad()
lmayencou 1:c53e766082b4 92 {
lmayencou 1:c53e766082b4 93 return lastFrameDurationMs * 100 / eachFrameMillis;
lmayencou 1:c53e766082b4 94 }
lmayencou 1:c53e766082b4 95
lmayencou 1:c53e766082b4 96
lmayencou 1:c53e766082b4 97 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 98 // buttons
lmayencou 1:c53e766082b4 99 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 100
lmayencou 1:c53e766082b4 101 void AbstractArduboy::poll()
lmayencou 1:c53e766082b4 102 {
lmayencou 1:c53e766082b4 103 previousButtonState = currentButtonState;
lmayencou 1:c53e766082b4 104 currentButtonState = getInput();
lmayencou 1:c53e766082b4 105 }
lmayencou 1:c53e766082b4 106
lmayencou 1:c53e766082b4 107 // returns true if the button mask passed in is pressed
lmayencou 1:c53e766082b4 108 //
lmayencou 1:c53e766082b4 109 // if (pressed(LEFT_BUTTON + A_BUTTON))
lmayencou 1:c53e766082b4 110 bool AbstractArduboy::pressed(uint8_t buttons)
lmayencou 1:c53e766082b4 111 {
lmayencou 1:c53e766082b4 112 uint8_t button_state = getInput();
lmayencou 1:c53e766082b4 113 return (button_state & buttons) == buttons;
lmayencou 1:c53e766082b4 114 }
lmayencou 1:c53e766082b4 115
lmayencou 1:c53e766082b4 116 // returns true if the button mask passed in not pressed
lmayencou 1:c53e766082b4 117 //
lmayencou 1:c53e766082b4 118 // if (not_pressed(LEFT_BUTTON))
lmayencou 1:c53e766082b4 119 bool AbstractArduboy::notPressed(uint8_t buttons)
lmayencou 1:c53e766082b4 120 {
lmayencou 1:c53e766082b4 121 uint8_t button_state = getInput();
lmayencou 1:c53e766082b4 122 return (button_state & buttons) == 0;
lmayencou 1:c53e766082b4 123 }
lmayencou 1:c53e766082b4 124
lmayencou 1:c53e766082b4 125 // returns true if a button has just been pressed
lmayencou 1:c53e766082b4 126 // if the button has been held down for multiple frames this will return
lmayencou 1:c53e766082b4 127 // false. You should only use this to poll a single button.
lmayencou 1:c53e766082b4 128 bool AbstractArduboy::justPressed(uint8_t button)
lmayencou 1:c53e766082b4 129 {
lmayencou 1:c53e766082b4 130 uint8_t button_state = getInput();
lmayencou 1:c53e766082b4 131 return (!(previousButtonState & button) && (currentButtonState & button));
lmayencou 1:c53e766082b4 132 }
lmayencou 1:c53e766082b4 133
lmayencou 1:c53e766082b4 134 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 135 // graphics
lmayencou 1:c53e766082b4 136 ////////////////////////////////////////////////
lmayencou 1:c53e766082b4 137
lmayencou 1:c53e766082b4 138 void AbstractArduboy::blank()
lmayencou 1:c53e766082b4 139 {
lmayencou 1:c53e766082b4 140 fillScreen(0);
lmayencou 1:c53e766082b4 141 }
lmayencou 1:c53e766082b4 142
lmayencou 1:c53e766082b4 143 void AbstractArduboy::clearDisplay()
lmayencou 1:c53e766082b4 144 {
lmayencou 1:c53e766082b4 145 fillScreen(0);
lmayencou 1:c53e766082b4 146 }
lmayencou 1:c53e766082b4 147
lmayencou 1:c53e766082b4 148 void AbstractArduboy::drawPixel(int x, int y, uint8_t color)
lmayencou 1:c53e766082b4 149 {
lmayencou 1:c53e766082b4 150 #ifdef PIXEL_SAFE_MODE
lmayencou 1:c53e766082b4 151 if (x < 0 || x > (WIDTH - 1) || y < 0 || y > (HEIGHT - 1))
lmayencou 1:c53e766082b4 152 {
lmayencou 1:c53e766082b4 153 return;
lmayencou 1:c53e766082b4 154 }
lmayencou 1:c53e766082b4 155 #endif
lmayencou 1:c53e766082b4 156
lmayencou 1:c53e766082b4 157 uint8_t row = (uint8_t)y / 8;
lmayencou 1:c53e766082b4 158 if (color)
lmayencou 1:c53e766082b4 159 {
lmayencou 1:c53e766082b4 160 sBuffer[(row * WIDTH) + (uint8_t)x] |= _BV((uint8_t)y % 8);
lmayencou 1:c53e766082b4 161 }
lmayencou 1:c53e766082b4 162 else
lmayencou 1:c53e766082b4 163 {
lmayencou 1:c53e766082b4 164 sBuffer[(row * WIDTH) + (uint8_t)x] &= ~ _BV((uint8_t)y % 8);
lmayencou 1:c53e766082b4 165 }
lmayencou 1:c53e766082b4 166 }
lmayencou 1:c53e766082b4 167
lmayencou 1:c53e766082b4 168 uint8_t AbstractArduboy::getPixel(uint8_t x, uint8_t y)
lmayencou 1:c53e766082b4 169 {
lmayencou 1:c53e766082b4 170 uint8_t row = y / 8;
lmayencou 1:c53e766082b4 171 uint8_t bit_position = y % 8;
lmayencou 1:c53e766082b4 172 return (sBuffer[(row * WIDTH) + x] & _BV(bit_position)) >> bit_position;
lmayencou 1:c53e766082b4 173 }
lmayencou 1:c53e766082b4 174
lmayencou 1:c53e766082b4 175 void AbstractArduboy::drawCircle(int16_t x0, int16_t y0, int16_t r, uint8_t color)
lmayencou 1:c53e766082b4 176 {
lmayencou 1:c53e766082b4 177 int16_t f = 1 - r;
lmayencou 1:c53e766082b4 178 int16_t ddF_x = 1;
lmayencou 1:c53e766082b4 179 int16_t ddF_y = -2 * r;
lmayencou 1:c53e766082b4 180 int16_t x = 0;
lmayencou 1:c53e766082b4 181 int16_t y = r;
lmayencou 1:c53e766082b4 182
lmayencou 1:c53e766082b4 183 drawPixel(x0, y0 + r, color);
lmayencou 1:c53e766082b4 184 drawPixel(x0, y0 - r, color);
lmayencou 1:c53e766082b4 185 drawPixel(x0 + r, y0, color);
lmayencou 1:c53e766082b4 186 drawPixel(x0 - r, y0, color);
lmayencou 1:c53e766082b4 187
lmayencou 1:c53e766082b4 188 while (x < y)
lmayencou 1:c53e766082b4 189 {
lmayencou 1:c53e766082b4 190 if (f >= 0)
lmayencou 1:c53e766082b4 191 {
lmayencou 1:c53e766082b4 192 y--;
lmayencou 1:c53e766082b4 193 ddF_y += 2;
lmayencou 1:c53e766082b4 194 f += ddF_y;
lmayencou 1:c53e766082b4 195 }
lmayencou 1:c53e766082b4 196
lmayencou 1:c53e766082b4 197 x++;
lmayencou 1:c53e766082b4 198 ddF_x += 2;
lmayencou 1:c53e766082b4 199 f += ddF_x;
lmayencou 1:c53e766082b4 200
lmayencou 1:c53e766082b4 201 drawPixel(x0 + x, y0 + y, color);
lmayencou 1:c53e766082b4 202 drawPixel(x0 - x, y0 + y, color);
lmayencou 1:c53e766082b4 203 drawPixel(x0 + x, y0 - y, color);
lmayencou 1:c53e766082b4 204 drawPixel(x0 - x, y0 - y, color);
lmayencou 1:c53e766082b4 205 drawPixel(x0 + y, y0 + x, color);
lmayencou 1:c53e766082b4 206 drawPixel(x0 - y, y0 + x, color);
lmayencou 1:c53e766082b4 207 drawPixel(x0 + y, y0 - x, color);
lmayencou 1:c53e766082b4 208 drawPixel(x0 - y, y0 - x, color);
lmayencou 1:c53e766082b4 209 }
lmayencou 1:c53e766082b4 210 }
lmayencou 1:c53e766082b4 211
lmayencou 1:c53e766082b4 212 void AbstractArduboy::drawCircleHelper
lmayencou 1:c53e766082b4 213 (int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint8_t color)
lmayencou 1:c53e766082b4 214 {
lmayencou 1:c53e766082b4 215 int16_t f = 1 - r;
lmayencou 1:c53e766082b4 216 int16_t ddF_x = 1;
lmayencou 1:c53e766082b4 217 int16_t ddF_y = -2 * r;
lmayencou 1:c53e766082b4 218 int16_t x = 0;
lmayencou 1:c53e766082b4 219 int16_t y = r;
lmayencou 1:c53e766082b4 220
lmayencou 1:c53e766082b4 221 while (x < y)
lmayencou 1:c53e766082b4 222 {
lmayencou 1:c53e766082b4 223 if (f >= 0)
lmayencou 1:c53e766082b4 224 {
lmayencou 1:c53e766082b4 225 y--;
lmayencou 1:c53e766082b4 226 ddF_y += 2;
lmayencou 1:c53e766082b4 227 f += ddF_y;
lmayencou 1:c53e766082b4 228 }
lmayencou 1:c53e766082b4 229
lmayencou 1:c53e766082b4 230 x++;
lmayencou 1:c53e766082b4 231 ddF_x += 2;
lmayencou 1:c53e766082b4 232 f += ddF_x;
lmayencou 1:c53e766082b4 233
lmayencou 1:c53e766082b4 234 if (cornername & 0x4)
lmayencou 1:c53e766082b4 235 {
lmayencou 1:c53e766082b4 236 drawPixel(x0 + x, y0 + y, color);
lmayencou 1:c53e766082b4 237 drawPixel(x0 + y, y0 + x, color);
lmayencou 1:c53e766082b4 238 }
lmayencou 1:c53e766082b4 239 if (cornername & 0x2)
lmayencou 1:c53e766082b4 240 {
lmayencou 1:c53e766082b4 241 drawPixel(x0 + x, y0 - y, color);
lmayencou 1:c53e766082b4 242 drawPixel(x0 + y, y0 - x, color);
lmayencou 1:c53e766082b4 243 }
lmayencou 1:c53e766082b4 244 if (cornername & 0x8)
lmayencou 1:c53e766082b4 245 {
lmayencou 1:c53e766082b4 246 drawPixel(x0 - y, y0 + x, color);
lmayencou 1:c53e766082b4 247 drawPixel(x0 - x, y0 + y, color);
lmayencou 1:c53e766082b4 248 }
lmayencou 1:c53e766082b4 249 if (cornername & 0x1)
lmayencou 1:c53e766082b4 250 {
lmayencou 1:c53e766082b4 251 drawPixel(x0 - y, y0 - x, color);
lmayencou 1:c53e766082b4 252 drawPixel(x0 - x, y0 - y, color);
lmayencou 1:c53e766082b4 253 }
lmayencou 1:c53e766082b4 254 }
lmayencou 1:c53e766082b4 255 }
lmayencou 1:c53e766082b4 256
lmayencou 1:c53e766082b4 257 void AbstractArduboy::fillCircle(int16_t x0, int16_t y0, int16_t r, uint8_t color)
lmayencou 1:c53e766082b4 258 {
lmayencou 1:c53e766082b4 259 drawFastVLine(x0, y0 - r, 2 * r + 1, color);
lmayencou 1:c53e766082b4 260 fillCircleHelper(x0, y0, r, 3, 0, color);
lmayencou 1:c53e766082b4 261 }
lmayencou 1:c53e766082b4 262
lmayencou 1:c53e766082b4 263 void AbstractArduboy::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint8_t color)
lmayencou 1:c53e766082b4 264 {
lmayencou 1:c53e766082b4 265 // used to do circles and roundrects!
lmayencou 1:c53e766082b4 266 int16_t f = 1 - r;
lmayencou 1:c53e766082b4 267 int16_t ddF_x = 1;
lmayencou 1:c53e766082b4 268 int16_t ddF_y = -2 * r;
lmayencou 1:c53e766082b4 269 int16_t x = 0;
lmayencou 1:c53e766082b4 270 int16_t y = r;
lmayencou 1:c53e766082b4 271
lmayencou 1:c53e766082b4 272 while (x < y)
lmayencou 1:c53e766082b4 273 {
lmayencou 1:c53e766082b4 274 if (f >= 0)
lmayencou 1:c53e766082b4 275 {
lmayencou 1:c53e766082b4 276 y--;
lmayencou 1:c53e766082b4 277 ddF_y += 2;
lmayencou 1:c53e766082b4 278 f += ddF_y;
lmayencou 1:c53e766082b4 279 }
lmayencou 1:c53e766082b4 280
lmayencou 1:c53e766082b4 281 x++;
lmayencou 1:c53e766082b4 282 ddF_x += 2;
lmayencou 1:c53e766082b4 283 f += ddF_x;
lmayencou 1:c53e766082b4 284
lmayencou 1:c53e766082b4 285 if (cornername & 0x1)
lmayencou 1:c53e766082b4 286 {
lmayencou 1:c53e766082b4 287 drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color);
lmayencou 1:c53e766082b4 288 drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color);
lmayencou 1:c53e766082b4 289 }
lmayencou 1:c53e766082b4 290
lmayencou 1:c53e766082b4 291 if (cornername & 0x2)
lmayencou 1:c53e766082b4 292 {
lmayencou 1:c53e766082b4 293 drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color);
lmayencou 1:c53e766082b4 294 drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color);
lmayencou 1:c53e766082b4 295 }
lmayencou 1:c53e766082b4 296 }
lmayencou 1:c53e766082b4 297 }
lmayencou 1:c53e766082b4 298
lmayencou 1:c53e766082b4 299 void AbstractArduboy::drawLine
lmayencou 1:c53e766082b4 300 (int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color)
lmayencou 1:c53e766082b4 301 {
lmayencou 1:c53e766082b4 302 // bresenham's algorithm - thx wikpedia
lmayencou 1:c53e766082b4 303 bool steep = abs(y1 - y0) > abs(x1 - x0);
lmayencou 1:c53e766082b4 304 if (steep) {
lmayencou 1:c53e766082b4 305 swap(x0, y0);
lmayencou 1:c53e766082b4 306 swap(x1, y1);
lmayencou 1:c53e766082b4 307 }
lmayencou 1:c53e766082b4 308
lmayencou 1:c53e766082b4 309 if (x0 > x1) {
lmayencou 1:c53e766082b4 310 swap(x0, x1);
lmayencou 1:c53e766082b4 311 swap(y0, y1);
lmayencou 1:c53e766082b4 312 }
lmayencou 1:c53e766082b4 313
lmayencou 1:c53e766082b4 314 int16_t dx, dy;
lmayencou 1:c53e766082b4 315 dx = x1 - x0;
lmayencou 1:c53e766082b4 316 dy = abs(y1 - y0);
lmayencou 1:c53e766082b4 317
lmayencou 1:c53e766082b4 318 int16_t err = dx / 2;
lmayencou 1:c53e766082b4 319 int8_t ystep;
lmayencou 1:c53e766082b4 320
lmayencou 1:c53e766082b4 321 if (y0 < y1)
lmayencou 1:c53e766082b4 322 {
lmayencou 1:c53e766082b4 323 ystep = 1;
lmayencou 1:c53e766082b4 324 }
lmayencou 1:c53e766082b4 325 else
lmayencou 1:c53e766082b4 326 {
lmayencou 1:c53e766082b4 327 ystep = -1;
lmayencou 1:c53e766082b4 328 }
lmayencou 1:c53e766082b4 329
lmayencou 1:c53e766082b4 330 for (; x0 <= x1; x0++)
lmayencou 1:c53e766082b4 331 {
lmayencou 1:c53e766082b4 332 if (steep)
lmayencou 1:c53e766082b4 333 {
lmayencou 1:c53e766082b4 334 drawPixel(y0, x0, color);
lmayencou 1:c53e766082b4 335 }
lmayencou 1:c53e766082b4 336 else
lmayencou 1:c53e766082b4 337 {
lmayencou 1:c53e766082b4 338 drawPixel(x0, y0, color);
lmayencou 1:c53e766082b4 339 }
lmayencou 1:c53e766082b4 340
lmayencou 1:c53e766082b4 341 err -= dy;
lmayencou 1:c53e766082b4 342 if (err < 0)
lmayencou 1:c53e766082b4 343 {
lmayencou 1:c53e766082b4 344 y0 += ystep;
lmayencou 1:c53e766082b4 345 err += dx;
lmayencou 1:c53e766082b4 346 }
lmayencou 1:c53e766082b4 347 }
lmayencou 1:c53e766082b4 348 }
lmayencou 1:c53e766082b4 349
lmayencou 1:c53e766082b4 350 void AbstractArduboy::drawRect
lmayencou 1:c53e766082b4 351 (int16_t x, int16_t y, int16_t w, int16_t h, uint8_t color)
lmayencou 1:c53e766082b4 352 {
lmayencou 1:c53e766082b4 353 drawFastHLine(x, y, w, color);
lmayencou 1:c53e766082b4 354 drawFastHLine(x, y + h - 1, w, color);
lmayencou 1:c53e766082b4 355 drawFastVLine(x, y, h, color);
lmayencou 1:c53e766082b4 356 drawFastVLine(x + w - 1, y, h, color);
lmayencou 1:c53e766082b4 357 }
lmayencou 1:c53e766082b4 358
lmayencou 1:c53e766082b4 359 void AbstractArduboy::drawFastVLine
lmayencou 1:c53e766082b4 360 (int16_t x, int16_t y, int16_t h, uint8_t color)
lmayencou 1:c53e766082b4 361 {
lmayencou 1:c53e766082b4 362 int end = y + h;
lmayencou 1:c53e766082b4 363 for (int a = max(0, y); a < min(end, HEIGHT); a++)
lmayencou 1:c53e766082b4 364 {
lmayencou 1:c53e766082b4 365 drawPixel(x, a, color);
lmayencou 1:c53e766082b4 366 }
lmayencou 1:c53e766082b4 367 }
lmayencou 1:c53e766082b4 368
lmayencou 1:c53e766082b4 369 void AbstractArduboy::drawFastHLine
lmayencou 1:c53e766082b4 370 (int16_t x, int16_t y, int16_t w, uint8_t color)
lmayencou 1:c53e766082b4 371 {
lmayencou 1:c53e766082b4 372 int end = x + w;
lmayencou 1:c53e766082b4 373 for (int a = max(0, x); a < min(end, WIDTH); a++)
lmayencou 1:c53e766082b4 374 {
lmayencou 1:c53e766082b4 375 drawPixel(a, y, color);
lmayencou 1:c53e766082b4 376 }
lmayencou 1:c53e766082b4 377 }
lmayencou 1:c53e766082b4 378
lmayencou 1:c53e766082b4 379 void AbstractArduboy::fillRect
lmayencou 1:c53e766082b4 380 (int16_t x, int16_t y, int16_t w, int16_t h, uint8_t color)
lmayencou 1:c53e766082b4 381 {
lmayencou 1:c53e766082b4 382 // stupidest version - update in subclasses if desired!
lmayencou 1:c53e766082b4 383 for (int16_t i = x; i < x + w; i++)
lmayencou 1:c53e766082b4 384 {
lmayencou 1:c53e766082b4 385 drawFastVLine(i, y, h, color);
lmayencou 1:c53e766082b4 386 }
lmayencou 1:c53e766082b4 387 }
lmayencou 1:c53e766082b4 388
lmayencou 1:c53e766082b4 389 void AbstractArduboy::fillScreen(uint8_t color)
lmayencou 1:c53e766082b4 390 {
lmayencou 1:c53e766082b4 391 // C version :
lmayencou 1:c53e766082b4 392 if(color != 0) color = 0xFF; //change any nonzero argument to b11111111 and insert into screen array.
lmayencou 1:c53e766082b4 393 for(int16_t i=0; i<1024; i++) { sBuffer[i] = color; } //sBuffer = (128*64) = 8192/8 = 1024 bytes.
lmayencou 1:c53e766082b4 394 }
lmayencou 1:c53e766082b4 395
lmayencou 1:c53e766082b4 396 void AbstractArduboy::drawRoundRect
lmayencou 1:c53e766082b4 397 (int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint8_t color)
lmayencou 1:c53e766082b4 398 {
lmayencou 1:c53e766082b4 399 // smarter version
lmayencou 1:c53e766082b4 400 drawFastHLine(x + r, y, w - 2 * r, color); // Top
lmayencou 1:c53e766082b4 401 drawFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
lmayencou 1:c53e766082b4 402 drawFastVLine(x, y + r, h - 2 * r, color); // Left
lmayencou 1:c53e766082b4 403 drawFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right
lmayencou 1:c53e766082b4 404 // draw four corners
lmayencou 1:c53e766082b4 405 drawCircleHelper(x + r, y + r, r, 1, color);
lmayencou 1:c53e766082b4 406 drawCircleHelper(x + w - r - 1, y + r, r, 2, color);
lmayencou 1:c53e766082b4 407 drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
lmayencou 1:c53e766082b4 408 drawCircleHelper(x + r, y + h - r - 1, r, 8, color);
lmayencou 1:c53e766082b4 409 }
lmayencou 1:c53e766082b4 410
lmayencou 1:c53e766082b4 411 void AbstractArduboy::fillRoundRect
lmayencou 1:c53e766082b4 412 (int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint8_t color)
lmayencou 1:c53e766082b4 413 {
lmayencou 1:c53e766082b4 414 // smarter version
lmayencou 1:c53e766082b4 415 fillRect(x + r, y, w - 2 * r, h, color);
lmayencou 1:c53e766082b4 416
lmayencou 1:c53e766082b4 417 // draw four corners
lmayencou 1:c53e766082b4 418 fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
lmayencou 1:c53e766082b4 419 fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color);
lmayencou 1:c53e766082b4 420 }
lmayencou 1:c53e766082b4 421
lmayencou 1:c53e766082b4 422 void AbstractArduboy::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint8_t color) {
lmayencou 1:c53e766082b4 423 // no need to dar at all of we're offscreen
lmayencou 1:c53e766082b4 424 if (x + w < 0 || x > WIDTH - 1 || y + h < 0 || y > HEIGHT - 1)
lmayencou 1:c53e766082b4 425 return;
lmayencou 1:c53e766082b4 426
lmayencou 1:c53e766082b4 427 int yOffset = abs(y) % 8;
lmayencou 1:c53e766082b4 428 int sRow = y / 8;
lmayencou 1:c53e766082b4 429 if (y < 0) {
lmayencou 1:c53e766082b4 430 sRow--;
lmayencou 1:c53e766082b4 431 yOffset = 8 - yOffset;
lmayencou 1:c53e766082b4 432 }
lmayencou 1:c53e766082b4 433 int rows = h / 8;
lmayencou 1:c53e766082b4 434 if (h % 8 != 0) rows++;
lmayencou 1:c53e766082b4 435 for (int a = 0; a < rows; a++) {
lmayencou 1:c53e766082b4 436 int bRow = sRow + a;
lmayencou 1:c53e766082b4 437 if (bRow > (HEIGHT / 8) - 1) break;
lmayencou 1:c53e766082b4 438 if (bRow > -2) {
lmayencou 1:c53e766082b4 439 for (int iCol = 0; iCol < w; iCol++) {
lmayencou 1:c53e766082b4 440 if (iCol + x > (WIDTH - 1)) break;
lmayencou 1:c53e766082b4 441 if (iCol + x >= 0) {
lmayencou 1:c53e766082b4 442 if (bRow >= 0) {
lmayencou 1:c53e766082b4 443 if (color) this->sBuffer[ (bRow * WIDTH) + x + iCol ] |= pgm_read_byte(bitmap + (a * w) + iCol) << yOffset;
lmayencou 1:c53e766082b4 444 else this->sBuffer[ (bRow * WIDTH) + x + iCol ] &= ~(pgm_read_byte(bitmap + (a * w) + iCol) << yOffset);
lmayencou 1:c53e766082b4 445 }
lmayencou 1:c53e766082b4 446 if (yOffset && bRow < (HEIGHT / 8) - 1 && bRow > -2) {
lmayencou 1:c53e766082b4 447 if (color) this->sBuffer[ ((bRow + 1)*WIDTH) + x + iCol ] |= pgm_read_byte(bitmap + (a * w) + iCol) >> (8 - yOffset);
lmayencou 1:c53e766082b4 448 else this->sBuffer[ ((bRow + 1)*WIDTH) + x + iCol ] &= ~(pgm_read_byte(bitmap + (a * w) + iCol) >> (8 - yOffset));
lmayencou 1:c53e766082b4 449 }
lmayencou 1:c53e766082b4 450 }
lmayencou 1:c53e766082b4 451 }
lmayencou 1:c53e766082b4 452 }
lmayencou 1:c53e766082b4 453 }
lmayencou 1:c53e766082b4 454 }
lmayencou 1:c53e766082b4 455
lmayencou 1:c53e766082b4 456
lmayencou 1:c53e766082b4 457
lmayencou 1:c53e766082b4 458 typedef struct CSESSION {
lmayencou 1:c53e766082b4 459 int byte;
lmayencou 1:c53e766082b4 460 int bit;
lmayencou 1:c53e766082b4 461 const uint8_t *src;
lmayencou 1:c53e766082b4 462 int src_pos;
lmayencou 1:c53e766082b4 463 } CSESSION;
lmayencou 1:c53e766082b4 464 static CSESSION cs;
lmayencou 1:c53e766082b4 465
lmayencou 1:c53e766082b4 466 static int getval(int bits)
lmayencou 1:c53e766082b4 467 {
lmayencou 1:c53e766082b4 468 int val = 0;
lmayencou 1:c53e766082b4 469 int i;
lmayencou 1:c53e766082b4 470 for (i = 0; i < bits; i++)
lmayencou 1:c53e766082b4 471 {
lmayencou 1:c53e766082b4 472 if (cs.bit == 0x100)
lmayencou 1:c53e766082b4 473 {
lmayencou 1:c53e766082b4 474 cs.bit = 0x1;
lmayencou 1:c53e766082b4 475 cs.byte = pgm_read_byte(&cs.src[cs.src_pos]);
lmayencou 1:c53e766082b4 476 cs.src_pos ++;
lmayencou 1:c53e766082b4 477 }
lmayencou 1:c53e766082b4 478 if (cs.byte & cs.bit)
lmayencou 1:c53e766082b4 479 val += (1 << i);
lmayencou 1:c53e766082b4 480 cs.bit <<= 1;
lmayencou 1:c53e766082b4 481 }
lmayencou 1:c53e766082b4 482 return val;
lmayencou 1:c53e766082b4 483 }
lmayencou 1:c53e766082b4 484
lmayencou 1:c53e766082b4 485 void AbstractArduboy::drawCompressed(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t color)
lmayencou 1:c53e766082b4 486 {
lmayencou 1:c53e766082b4 487 int bl, len;
lmayencou 1:c53e766082b4 488 int col;
lmayencou 1:c53e766082b4 489 int i;
lmayencou 1:c53e766082b4 490 int a, iCol;
lmayencou 1:c53e766082b4 491 int x, y;
lmayencou 1:c53e766082b4 492 int byte = 0;
lmayencou 1:c53e766082b4 493 int bit = 0;
lmayencou 1:c53e766082b4 494 int w, h;
lmayencou 1:c53e766082b4 495
lmayencou 1:c53e766082b4 496 // set up decompress state
lmayencou 1:c53e766082b4 497
lmayencou 1:c53e766082b4 498 cs.src = bitmap;
lmayencou 1:c53e766082b4 499 cs.bit = 0x100;
lmayencou 1:c53e766082b4 500 cs.byte = 0;
lmayencou 1:c53e766082b4 501 cs.src_pos = 0;
lmayencou 1:c53e766082b4 502
lmayencou 1:c53e766082b4 503 // read header
lmayencou 1:c53e766082b4 504
lmayencou 1:c53e766082b4 505 w = getval(8) + 1;
lmayencou 1:c53e766082b4 506 h = getval(8) + 1;
lmayencou 1:c53e766082b4 507
lmayencou 1:c53e766082b4 508 col = getval(1); // starting colour
lmayencou 1:c53e766082b4 509
lmayencou 1:c53e766082b4 510 // no need to draw at all if we're offscreen
lmayencou 1:c53e766082b4 511 if (sx + w < 0 || sx > WIDTH - 1 || sy + h < 0 || sy > HEIGHT - 1)
lmayencou 1:c53e766082b4 512 return;
lmayencou 1:c53e766082b4 513
lmayencou 1:c53e766082b4 514 // sy = sy - (frame*h);
lmayencou 1:c53e766082b4 515
lmayencou 1:c53e766082b4 516 int yOffset = abs(sy) % 8;
lmayencou 1:c53e766082b4 517 int sRow = sy / 8;
lmayencou 1:c53e766082b4 518 if (sy < 0) {
lmayencou 1:c53e766082b4 519 sRow--;
lmayencou 1:c53e766082b4 520 yOffset = 8 - yOffset;
lmayencou 1:c53e766082b4 521 }
lmayencou 1:c53e766082b4 522 int rows = h / 8;
lmayencou 1:c53e766082b4 523 if (h % 8 != 0) rows++;
lmayencou 1:c53e766082b4 524
lmayencou 1:c53e766082b4 525 a = 0; // +(frame*rows);
lmayencou 1:c53e766082b4 526 iCol = 0;
lmayencou 1:c53e766082b4 527
lmayencou 1:c53e766082b4 528 byte = 0; bit = 1;
lmayencou 1:c53e766082b4 529 while (a < rows) // + (frame*rows))
lmayencou 1:c53e766082b4 530 {
lmayencou 1:c53e766082b4 531 bl = 1;
lmayencou 1:c53e766082b4 532 while (!getval(1))
lmayencou 1:c53e766082b4 533 bl += 2;
lmayencou 1:c53e766082b4 534
lmayencou 1:c53e766082b4 535 len = getval(bl) + 1; // span length
lmayencou 1:c53e766082b4 536
lmayencou 1:c53e766082b4 537 // draw the span
lmayencou 1:c53e766082b4 538
lmayencou 1:c53e766082b4 539
lmayencou 1:c53e766082b4 540 for (i = 0; i < len; i++)
lmayencou 1:c53e766082b4 541 {
lmayencou 1:c53e766082b4 542 if (col)
lmayencou 1:c53e766082b4 543 byte |= bit;
lmayencou 1:c53e766082b4 544 bit <<= 1;
lmayencou 1:c53e766082b4 545
lmayencou 1:c53e766082b4 546 if (bit == 0x100) // reached end of byte
lmayencou 1:c53e766082b4 547 {
lmayencou 1:c53e766082b4 548 // draw
lmayencou 1:c53e766082b4 549
lmayencou 1:c53e766082b4 550 int bRow = sRow + a;
lmayencou 1:c53e766082b4 551
lmayencou 1:c53e766082b4 552 //if (byte) // possible optimisation
lmayencou 1:c53e766082b4 553 if (bRow <= (HEIGHT / 8) - 1)
lmayencou 1:c53e766082b4 554 if (bRow > -2)
lmayencou 1:c53e766082b4 555 if (iCol + sx <= (WIDTH - 1))
lmayencou 1:c53e766082b4 556 if (iCol + sx >= 0) {
lmayencou 1:c53e766082b4 557
lmayencou 1:c53e766082b4 558 if (bRow >= 0)
lmayencou 1:c53e766082b4 559 {
lmayencou 1:c53e766082b4 560 if (color)
lmayencou 1:c53e766082b4 561 this->sBuffer[ (bRow * WIDTH) + sx + iCol] |= byte << yOffset;
lmayencou 1:c53e766082b4 562 else
lmayencou 1:c53e766082b4 563 this->sBuffer[ (bRow * WIDTH) + sx + iCol] &= ~(byte << yOffset);
lmayencou 1:c53e766082b4 564 }
lmayencou 1:c53e766082b4 565 if (yOffset && bRow < (HEIGHT / 8) - 1 && bRow > -2)
lmayencou 1:c53e766082b4 566 {
lmayencou 1:c53e766082b4 567 if (color)
lmayencou 1:c53e766082b4 568 this->sBuffer[((bRow + 1)*WIDTH) + sx + iCol] |= byte >> (8 - yOffset);
lmayencou 1:c53e766082b4 569 else
lmayencou 1:c53e766082b4 570 this->sBuffer[((bRow + 1)*WIDTH) + sx + iCol] &= ~(byte >> (8 - yOffset));
lmayencou 1:c53e766082b4 571 }
lmayencou 1:c53e766082b4 572
lmayencou 1:c53e766082b4 573 }
lmayencou 1:c53e766082b4 574
lmayencou 1:c53e766082b4 575 // iterate
lmayencou 1:c53e766082b4 576 iCol ++;
lmayencou 1:c53e766082b4 577 if (iCol >= w)
lmayencou 1:c53e766082b4 578 {
lmayencou 1:c53e766082b4 579 iCol = 0;
lmayencou 1:c53e766082b4 580 a ++;
lmayencou 1:c53e766082b4 581 }
lmayencou 1:c53e766082b4 582
lmayencou 1:c53e766082b4 583 // reset byte
lmayencou 1:c53e766082b4 584 byte = 0; bit = 1;
lmayencou 1:c53e766082b4 585 }
lmayencou 1:c53e766082b4 586 }
lmayencou 1:c53e766082b4 587
lmayencou 1:c53e766082b4 588 col = 1 - col; // toggle colour for next span
lmayencou 1:c53e766082b4 589 }
lmayencou 1:c53e766082b4 590 }
lmayencou 1:c53e766082b4 591
lmayencou 1:c53e766082b4 592 uint8_t AbstractArduboy::writeChar(uint8_t c)
lmayencou 1:c53e766082b4 593 {
lmayencou 1:c53e766082b4 594 if (c == '\n')
lmayencou 1:c53e766082b4 595 {
lmayencou 1:c53e766082b4 596 cursor_y += textsize*8;
lmayencou 1:c53e766082b4 597 cursor_x = 0;
lmayencou 1:c53e766082b4 598 }
lmayencou 1:c53e766082b4 599 else if (c == '\r')
lmayencou 1:c53e766082b4 600 cursor_x = 0;
lmayencou 1:c53e766082b4 601 else
lmayencou 1:c53e766082b4 602 {
lmayencou 1:c53e766082b4 603 drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
lmayencou 1:c53e766082b4 604 cursor_x += textsize*6;
lmayencou 1:c53e766082b4 605 if (wrap && (cursor_x > (WIDTH - textsize*6)))
lmayencou 1:c53e766082b4 606 {
lmayencou 1:c53e766082b4 607 cursor_y += textsize*8;
lmayencou 1:c53e766082b4 608 cursor_x = 0;
lmayencou 1:c53e766082b4 609 }
lmayencou 1:c53e766082b4 610 }
lmayencou 1:c53e766082b4 611 return 1;
lmayencou 1:c53e766082b4 612 }
lmayencou 1:c53e766082b4 613
lmayencou 1:c53e766082b4 614 // draw a character
lmayencou 1:c53e766082b4 615 void AbstractArduboy::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)
lmayencou 1:c53e766082b4 616 {
lmayencou 1:c53e766082b4 617 if(
lmayencou 1:c53e766082b4 618 (x >= WIDTH) || // Clip right
lmayencou 1:c53e766082b4 619 (y >= HEIGHT) || // Clip bottom
lmayencou 1:c53e766082b4 620 ((x + 5 * size - 1) < 0) || // Clip left
lmayencou 1:c53e766082b4 621 ((y + 8 * size - 1) < 0) // Clip top
lmayencou 1:c53e766082b4 622 )
lmayencou 1:c53e766082b4 623 return;
lmayencou 1:c53e766082b4 624
lmayencou 1:c53e766082b4 625 for (int8_t i=0; i<6; i++ )
lmayencou 1:c53e766082b4 626 {
lmayencou 1:c53e766082b4 627 uint8_t line = 0;
lmayencou 1:c53e766082b4 628
lmayencou 1:c53e766082b4 629 if (i == 5)
lmayencou 1:c53e766082b4 630 line = 0x0;
lmayencou 1:c53e766082b4 631 else
lmayencou 1:c53e766082b4 632 line = font[(c*5)+i];
lmayencou 1:c53e766082b4 633
lmayencou 1:c53e766082b4 634 for (int8_t j = 0; j<8; j++)
lmayencou 1:c53e766082b4 635 {
lmayencou 1:c53e766082b4 636 if (line & 0x1)
lmayencou 1:c53e766082b4 637 {
lmayencou 1:c53e766082b4 638 #if defined(GFX_WANT_ABSTRACTS) || defined(GFX_SIZEABLE_TEXT)
lmayencou 1:c53e766082b4 639 if (size == 1) // default size
lmayencou 1:c53e766082b4 640 drawPixel(x+i, y+j, color);
lmayencou 1:c53e766082b4 641 else // big size
lmayencou 1:c53e766082b4 642 fillRect(x+(i*size), y+(j*size), size, size, color);
lmayencou 1:c53e766082b4 643 #else
lmayencou 1:c53e766082b4 644 drawPixel(x+i, y+j, color);
lmayencou 1:c53e766082b4 645 #endif
lmayencou 1:c53e766082b4 646 }
lmayencou 1:c53e766082b4 647 else if (bg != color)
lmayencou 1:c53e766082b4 648 {
lmayencou 1:c53e766082b4 649 #if defined(GFX_WANT_ABSTRACTS) || defined(GFX_SIZEABLE_TEXT)
lmayencou 1:c53e766082b4 650 if (size == 1) // default size
lmayencou 1:c53e766082b4 651 drawPixel(x+i, y+j, bg);
lmayencou 1:c53e766082b4 652 else // big size
lmayencou 1:c53e766082b4 653 fillRect(x+i*size, y+j*size, size, size, bg);
lmayencou 1:c53e766082b4 654 #else
lmayencou 1:c53e766082b4 655 drawPixel(x+i, y+j, bg);
lmayencou 1:c53e766082b4 656 #endif
lmayencou 1:c53e766082b4 657 }
lmayencou 1:c53e766082b4 658 line >>= 1;
lmayencou 1:c53e766082b4 659 }
lmayencou 1:c53e766082b4 660 }
lmayencou 1:c53e766082b4 661 }
lmayencou 1:c53e766082b4 662
lmayencou 1:c53e766082b4 663 void AbstractArduboy::swap(int16_t &a, int16_t &b)
lmayencou 1:c53e766082b4 664 {
lmayencou 1:c53e766082b4 665 int16_t t = a;
lmayencou 1:c53e766082b4 666
lmayencou 1:c53e766082b4 667 a = b;
lmayencou 1:c53e766082b4 668 b = t;
lmayencou 1:c53e766082b4 669 }
lmayencou 1:c53e766082b4 670
lmayencou 1:c53e766082b4 671 void AbstractArduboy::display()
lmayencou 1:c53e766082b4 672 {
lmayencou 1:c53e766082b4 673 this->drawScreen(sBuffer);
lmayencou 1:c53e766082b4 674 }