MBED NRF51 Arduboy port

Committer:
lmayencou
Date:
Fri Jan 06 22:29:05 2017 +0000
Revision:
2:e3ef9f476913
Parent:
1:c53e766082b4
Child:
3:df305b314063
add printf support

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