MBED NRF51 Arduboy port

Committer:
lmayencou
Date:
Sat Jan 07 12:43:36 2017 +0000
Revision:
3:df305b314063
Parent:
2:e3ef9f476913
Child:
4:63cfe7ff1c02
add frame timer - game working - bug with high scores

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