Louis Mayencourt
/
NRF_OLED
Arduboy lib for NRF and mbed
core.cpp@0:2b6d7af79c9c, 2016-12-27 (annotated)
- Committer:
- lmayencou
- Date:
- Tue Dec 27 11:27:14 2016 +0000
- Revision:
- 0:2b6d7af79c9c
first publish
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
lmayencou | 0:2b6d7af79c9c | 1 | #include "core.h" |
lmayencou | 0:2b6d7af79c9c | 2 | |
lmayencou | 0:2b6d7af79c9c | 3 | unsigned char Arduboy::sBuffer[]; |
lmayencou | 0:2b6d7af79c9c | 4 | |
lmayencou | 0:2b6d7af79c9c | 5 | Arduboy::Arduboy() : |
lmayencou | 0:2b6d7af79c9c | 6 | i2c(SDA,SCL), |
lmayencou | 0:2b6d7af79c9c | 7 | Adafruit_SSD1306_I2c(i2c,p13) |
lmayencou | 0:2b6d7af79c9c | 8 | { } |
lmayencou | 0:2b6d7af79c9c | 9 | |
lmayencou | 0:2b6d7af79c9c | 10 | void Arduboy::start() |
lmayencou | 0:2b6d7af79c9c | 11 | { |
lmayencou | 0:2b6d7af79c9c | 12 | #if F_CPU == 8000000L |
lmayencou | 0:2b6d7af79c9c | 13 | slowCPU(); |
lmayencou | 0:2b6d7af79c9c | 14 | #endif |
lmayencou | 0:2b6d7af79c9c | 15 | |
lmayencou | 0:2b6d7af79c9c | 16 | // init pin |
lmayencou | 0:2b6d7af79c9c | 17 | DigitalOut led1(LED1); |
lmayencou | 0:2b6d7af79c9c | 18 | |
lmayencou | 0:2b6d7af79c9c | 19 | bootLCD(); |
lmayencou | 0:2b6d7af79c9c | 20 | |
lmayencou | 0:2b6d7af79c9c | 21 | #ifdef SAFE_MODE |
lmayencou | 0:2b6d7af79c9c | 22 | if (pressed(LEFT_BUTTON + UP_BUTTON)) |
lmayencou | 0:2b6d7af79c9c | 23 | safeMode(); |
lmayencou | 0:2b6d7af79c9c | 24 | #endif |
lmayencou | 0:2b6d7af79c9c | 25 | |
lmayencou | 0:2b6d7af79c9c | 26 | |
lmayencou | 0:2b6d7af79c9c | 27 | audio.setup(); |
lmayencou | 0:2b6d7af79c9c | 28 | saveMuchPower(); |
lmayencou | 0:2b6d7af79c9c | 29 | } |
lmayencou | 0:2b6d7af79c9c | 30 | |
lmayencou | 0:2b6d7af79c9c | 31 | #if F_CPU == 8000000L |
lmayencou | 0:2b6d7af79c9c | 32 | // if we're compiling for 8Mhz we need to slow the CPU down because the |
lmayencou | 0:2b6d7af79c9c | 33 | // hardware clock on the Arduboy is 16MHz |
lmayencou | 0:2b6d7af79c9c | 34 | void Arduboy::slowCPU() |
lmayencou | 0:2b6d7af79c9c | 35 | { |
lmayencou | 0:2b6d7af79c9c | 36 | |
lmayencou | 0:2b6d7af79c9c | 37 | } |
lmayencou | 0:2b6d7af79c9c | 38 | #endif |
lmayencou | 0:2b6d7af79c9c | 39 | |
lmayencou | 0:2b6d7af79c9c | 40 | void Arduboy::bootLCD() |
lmayencou | 0:2b6d7af79c9c | 41 | { |
lmayencou | 0:2b6d7af79c9c | 42 | clearDisplay(); |
lmayencou | 0:2b6d7af79c9c | 43 | display(); |
lmayencou | 0:2b6d7af79c9c | 44 | } |
lmayencou | 0:2b6d7af79c9c | 45 | |
lmayencou | 0:2b6d7af79c9c | 46 | // Safe Mode is engaged by holding down both the LEFT button and UP button |
lmayencou | 0:2b6d7af79c9c | 47 | // when plugging the device into USB. It puts your device into a tight |
lmayencou | 0:2b6d7af79c9c | 48 | // loop and allows it to be reprogrammed even if you have uploaded a very |
lmayencou | 0:2b6d7af79c9c | 49 | // broken sketch that interferes with the normal USB triggered auto-reboot |
lmayencou | 0:2b6d7af79c9c | 50 | // functionality of the device. |
lmayencou | 0:2b6d7af79c9c | 51 | void Arduboy::safeMode() |
lmayencou | 0:2b6d7af79c9c | 52 | { |
lmayencou | 0:2b6d7af79c9c | 53 | display(); // too avoid random gibberish |
lmayencou | 0:2b6d7af79c9c | 54 | while (true) {}; |
lmayencou | 0:2b6d7af79c9c | 55 | } |
lmayencou | 0:2b6d7af79c9c | 56 | |
lmayencou | 0:2b6d7af79c9c | 57 | /* Power Management */ |
lmayencou | 0:2b6d7af79c9c | 58 | |
lmayencou | 0:2b6d7af79c9c | 59 | void Arduboy::idle() |
lmayencou | 0:2b6d7af79c9c | 60 | { |
lmayencou | 0:2b6d7af79c9c | 61 | } |
lmayencou | 0:2b6d7af79c9c | 62 | |
lmayencou | 0:2b6d7af79c9c | 63 | void Arduboy::saveMuchPower() |
lmayencou | 0:2b6d7af79c9c | 64 | { |
lmayencou | 0:2b6d7af79c9c | 65 | } |
lmayencou | 0:2b6d7af79c9c | 66 | |
lmayencou | 0:2b6d7af79c9c | 67 | |
lmayencou | 0:2b6d7af79c9c | 68 | /* Frame management */ |
lmayencou | 0:2b6d7af79c9c | 69 | |
lmayencou | 0:2b6d7af79c9c | 70 | void Arduboy::setFrameRate(uint8_t rate) |
lmayencou | 0:2b6d7af79c9c | 71 | { |
lmayencou | 0:2b6d7af79c9c | 72 | frameRate = rate; |
lmayencou | 0:2b6d7af79c9c | 73 | eachFrameMillis = 1000 / rate; |
lmayencou | 0:2b6d7af79c9c | 74 | } |
lmayencou | 0:2b6d7af79c9c | 75 | |
lmayencou | 0:2b6d7af79c9c | 76 | bool Arduboy::everyXFrames(uint8_t frames) |
lmayencou | 0:2b6d7af79c9c | 77 | { |
lmayencou | 0:2b6d7af79c9c | 78 | return frameCount % frames == 0; |
lmayencou | 0:2b6d7af79c9c | 79 | } |
lmayencou | 0:2b6d7af79c9c | 80 | |
lmayencou | 0:2b6d7af79c9c | 81 | bool Arduboy::nextFrame() |
lmayencou | 0:2b6d7af79c9c | 82 | { |
lmayencou | 0:2b6d7af79c9c | 83 | long now = millis(); |
lmayencou | 0:2b6d7af79c9c | 84 | uint8_t remaining; |
lmayencou | 0:2b6d7af79c9c | 85 | |
lmayencou | 0:2b6d7af79c9c | 86 | // post render |
lmayencou | 0:2b6d7af79c9c | 87 | if (post_render) { |
lmayencou | 0:2b6d7af79c9c | 88 | lastFrameDurationMs = now - lastFrameStart; |
lmayencou | 0:2b6d7af79c9c | 89 | frameCount++; |
lmayencou | 0:2b6d7af79c9c | 90 | post_render = false; |
lmayencou | 0:2b6d7af79c9c | 91 | } |
lmayencou | 0:2b6d7af79c9c | 92 | |
lmayencou | 0:2b6d7af79c9c | 93 | // if it's not time for the next frame yet |
lmayencou | 0:2b6d7af79c9c | 94 | if (now < nextFrameStart) { |
lmayencou | 0:2b6d7af79c9c | 95 | remaining = nextFrameStart - now; |
lmayencou | 0:2b6d7af79c9c | 96 | // if we have more than 1ms to spare, lets sleep |
lmayencou | 0:2b6d7af79c9c | 97 | // we should be woken up by timer0 every 1ms, so this should be ok |
lmayencou | 0:2b6d7af79c9c | 98 | if (remaining > 1) |
lmayencou | 0:2b6d7af79c9c | 99 | idle(); |
lmayencou | 0:2b6d7af79c9c | 100 | return false; |
lmayencou | 0:2b6d7af79c9c | 101 | } |
lmayencou | 0:2b6d7af79c9c | 102 | |
lmayencou | 0:2b6d7af79c9c | 103 | // pre-render |
lmayencou | 0:2b6d7af79c9c | 104 | |
lmayencou | 0:2b6d7af79c9c | 105 | // technically next frame should be last frame + each frame but if we're |
lmayencou | 0:2b6d7af79c9c | 106 | // running a slow render we would constnatly be behind the clock |
lmayencou | 0:2b6d7af79c9c | 107 | // keep an eye on this and see how it works. If it works well the |
lmayencou | 0:2b6d7af79c9c | 108 | // lastFrameStart variable could be eliminated completely |
lmayencou | 0:2b6d7af79c9c | 109 | nextFrameStart = now + eachFrameMillis; |
lmayencou | 0:2b6d7af79c9c | 110 | lastFrameStart = now; |
lmayencou | 0:2b6d7af79c9c | 111 | post_render = true; |
lmayencou | 0:2b6d7af79c9c | 112 | return post_render; |
lmayencou | 0:2b6d7af79c9c | 113 | } |
lmayencou | 0:2b6d7af79c9c | 114 | |
lmayencou | 0:2b6d7af79c9c | 115 | // returns the load on the CPU as a percentage |
lmayencou | 0:2b6d7af79c9c | 116 | // this is based on how much of the time your app is spends rendering |
lmayencou | 0:2b6d7af79c9c | 117 | // frames. This number can be higher than 100 if your app is rendering |
lmayencou | 0:2b6d7af79c9c | 118 | // really slowly. |
lmayencou | 0:2b6d7af79c9c | 119 | int Arduboy::cpuLoad() |
lmayencou | 0:2b6d7af79c9c | 120 | { |
lmayencou | 0:2b6d7af79c9c | 121 | return lastFrameDurationMs * 100 / eachFrameMillis; |
lmayencou | 0:2b6d7af79c9c | 122 | } |
lmayencou | 0:2b6d7af79c9c | 123 | |
lmayencou | 0:2b6d7af79c9c | 124 | // seed the random number generator with entropy from the temperature, |
lmayencou | 0:2b6d7af79c9c | 125 | // voltage reading, and microseconds since boot. |
lmayencou | 0:2b6d7af79c9c | 126 | // this method is still most effective when called semi-randomly such |
lmayencou | 0:2b6d7af79c9c | 127 | // as after a user hits a button to start a game or other semi-random |
lmayencou | 0:2b6d7af79c9c | 128 | // events |
lmayencou | 0:2b6d7af79c9c | 129 | void Arduboy::initRandomSeed() |
lmayencou | 0:2b6d7af79c9c | 130 | { |
lmayencou | 0:2b6d7af79c9c | 131 | } |
lmayencou | 0:2b6d7af79c9c | 132 | |
lmayencou | 0:2b6d7af79c9c | 133 | uint16_t Arduboy::rawADC(byte adc_bits) |
lmayencou | 0:2b6d7af79c9c | 134 | { |
lmayencou | 0:2b6d7af79c9c | 135 | return 0; |
lmayencou | 0:2b6d7af79c9c | 136 | } |
lmayencou | 0:2b6d7af79c9c | 137 | |
lmayencou | 0:2b6d7af79c9c | 138 | |
lmayencou | 0:2b6d7af79c9c | 139 | unsigned char* Arduboy::getBuffer() { |
lmayencou | 0:2b6d7af79c9c | 140 | return sBuffer; |
lmayencou | 0:2b6d7af79c9c | 141 | } |
lmayencou | 0:2b6d7af79c9c | 142 | |
lmayencou | 0:2b6d7af79c9c | 143 | uint8_t Arduboy::width() { |
lmayencou | 0:2b6d7af79c9c | 144 | return WIDTH; |
lmayencou | 0:2b6d7af79c9c | 145 | } |
lmayencou | 0:2b6d7af79c9c | 146 | |
lmayencou | 0:2b6d7af79c9c | 147 | uint8_t Arduboy::height() { |
lmayencou | 0:2b6d7af79c9c | 148 | return HEIGHT; |
lmayencou | 0:2b6d7af79c9c | 149 | } |
lmayencou | 0:2b6d7af79c9c | 150 | |
lmayencou | 0:2b6d7af79c9c | 151 | |
lmayencou | 0:2b6d7af79c9c | 152 | void Arduboy::poll() |
lmayencou | 0:2b6d7af79c9c | 153 | { |
lmayencou | 0:2b6d7af79c9c | 154 | previousButtonState = currentButtonState; |
lmayencou | 0:2b6d7af79c9c | 155 | currentButtonState = getInput(); |
lmayencou | 0:2b6d7af79c9c | 156 | } |
lmayencou | 0:2b6d7af79c9c | 157 | |
lmayencou | 0:2b6d7af79c9c | 158 | // returns true if the button mask passed in is pressed |
lmayencou | 0:2b6d7af79c9c | 159 | // |
lmayencou | 0:2b6d7af79c9c | 160 | // if (pressed(LEFT_BUTTON + A_BUTTON)) |
lmayencou | 0:2b6d7af79c9c | 161 | boolean Arduboy::pressed(uint8_t buttons) |
lmayencou | 0:2b6d7af79c9c | 162 | { |
lmayencou | 0:2b6d7af79c9c | 163 | uint8_t button_state = getInput(); |
lmayencou | 0:2b6d7af79c9c | 164 | return (button_state & buttons) == buttons; |
lmayencou | 0:2b6d7af79c9c | 165 | } |
lmayencou | 0:2b6d7af79c9c | 166 | |
lmayencou | 0:2b6d7af79c9c | 167 | // returns true if the button mask passed in not pressed |
lmayencou | 0:2b6d7af79c9c | 168 | // |
lmayencou | 0:2b6d7af79c9c | 169 | // if (not_pressed(LEFT_BUTTON)) |
lmayencou | 0:2b6d7af79c9c | 170 | boolean Arduboy::notPressed(uint8_t buttons) |
lmayencou | 0:2b6d7af79c9c | 171 | { |
lmayencou | 0:2b6d7af79c9c | 172 | uint8_t button_state = getInput(); |
lmayencou | 0:2b6d7af79c9c | 173 | return (button_state & buttons) == 0; |
lmayencou | 0:2b6d7af79c9c | 174 | } |
lmayencou | 0:2b6d7af79c9c | 175 | |
lmayencou | 0:2b6d7af79c9c | 176 | // returns true if a button has just been pressed |
lmayencou | 0:2b6d7af79c9c | 177 | // if the button has been held down for multiple frames this will return |
lmayencou | 0:2b6d7af79c9c | 178 | // false. You should only use this to poll a single button. |
lmayencou | 0:2b6d7af79c9c | 179 | boolean Arduboy::justPressed(uint8_t button) |
lmayencou | 0:2b6d7af79c9c | 180 | { |
lmayencou | 0:2b6d7af79c9c | 181 | uint8_t button_state = getInput(); |
lmayencou | 0:2b6d7af79c9c | 182 | return (!(previousButtonState & button) && (currentButtonState & button)); |
lmayencou | 0:2b6d7af79c9c | 183 | } |
lmayencou | 0:2b6d7af79c9c | 184 | |
lmayencou | 0:2b6d7af79c9c | 185 | |
lmayencou | 0:2b6d7af79c9c | 186 | |
lmayencou | 0:2b6d7af79c9c | 187 | uint8_t Arduboy::getInput() |
lmayencou | 0:2b6d7af79c9c | 188 | { |
lmayencou | 0:2b6d7af79c9c | 189 | uint8_t buttons; |
lmayencou | 0:2b6d7af79c9c | 190 | |
lmayencou | 0:2b6d7af79c9c | 191 | return buttons; |
lmayencou | 0:2b6d7af79c9c | 192 | } |
lmayencou | 0:2b6d7af79c9c | 193 | |
lmayencou | 0:2b6d7af79c9c | 194 | void Arduboy::swap(int16_t& a, int16_t& b) { |
lmayencou | 0:2b6d7af79c9c | 195 | int temp = a; |
lmayencou | 0:2b6d7af79c9c | 196 | a = b; |
lmayencou | 0:2b6d7af79c9c | 197 | b = temp; |
lmayencou | 0:2b6d7af79c9c | 198 | } |
lmayencou | 0:2b6d7af79c9c | 199 | |
lmayencou | 0:2b6d7af79c9c | 200 | |
lmayencou | 0:2b6d7af79c9c | 201 | /* AUDIO */ |
lmayencou | 0:2b6d7af79c9c | 202 | |
lmayencou | 0:2b6d7af79c9c | 203 | void ArduboyAudio::on() { |
lmayencou | 0:2b6d7af79c9c | 204 | |
lmayencou | 0:2b6d7af79c9c | 205 | audio_enabled = true; |
lmayencou | 0:2b6d7af79c9c | 206 | } |
lmayencou | 0:2b6d7af79c9c | 207 | |
lmayencou | 0:2b6d7af79c9c | 208 | bool ArduboyAudio::enabled() { |
lmayencou | 0:2b6d7af79c9c | 209 | return audio_enabled; |
lmayencou | 0:2b6d7af79c9c | 210 | } |
lmayencou | 0:2b6d7af79c9c | 211 | |
lmayencou | 0:2b6d7af79c9c | 212 | void ArduboyAudio::off() { |
lmayencou | 0:2b6d7af79c9c | 213 | |
lmayencou | 0:2b6d7af79c9c | 214 | audio_enabled = false; |
lmayencou | 0:2b6d7af79c9c | 215 | } |
lmayencou | 0:2b6d7af79c9c | 216 | |
lmayencou | 0:2b6d7af79c9c | 217 | void ArduboyAudio::saveOnOff() { |
lmayencou | 0:2b6d7af79c9c | 218 | } |
lmayencou | 0:2b6d7af79c9c | 219 | |
lmayencou | 0:2b6d7af79c9c | 220 | void ArduboyAudio::setup() { |
lmayencou | 0:2b6d7af79c9c | 221 | |
lmayencou | 0:2b6d7af79c9c | 222 | } |
lmayencou | 0:2b6d7af79c9c | 223 | |
lmayencou | 0:2b6d7af79c9c | 224 | void ArduboyAudio::tone(unsigned int frequency, unsigned long duration) |
lmayencou | 0:2b6d7af79c9c | 225 | { |
lmayencou | 0:2b6d7af79c9c | 226 | |
lmayencou | 0:2b6d7af79c9c | 227 | } |
lmayencou | 0:2b6d7af79c9c | 228 | |
lmayencou | 0:2b6d7af79c9c | 229 | |
lmayencou | 0:2b6d7af79c9c | 230 | ///////////////////////// |
lmayencou | 0:2b6d7af79c9c | 231 | // Sprites by Dreamer3 // |
lmayencou | 0:2b6d7af79c9c | 232 | ///////////////////////// |
lmayencou | 0:2b6d7af79c9c | 233 | Sprites::Sprites(Arduboy &a) |
lmayencou | 0:2b6d7af79c9c | 234 | { |
lmayencou | 0:2b6d7af79c9c | 235 | arduboy = &a; |
lmayencou | 0:2b6d7af79c9c | 236 | sBuffer = arduboy->getBuffer(); |
lmayencou | 0:2b6d7af79c9c | 237 | } |
lmayencou | 0:2b6d7af79c9c | 238 | |
lmayencou | 0:2b6d7af79c9c | 239 | // new API |
lmayencou | 0:2b6d7af79c9c | 240 | |
lmayencou | 0:2b6d7af79c9c | 241 | void Sprites::drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap, |
lmayencou | 0:2b6d7af79c9c | 242 | const uint8_t *mask, uint8_t frame, uint8_t mask_frame) |
lmayencou | 0:2b6d7af79c9c | 243 | { |
lmayencou | 0:2b6d7af79c9c | 244 | draw(x, y, bitmap, frame, mask, mask_frame, SPRITE_MASKED); |
lmayencou | 0:2b6d7af79c9c | 245 | } |
lmayencou | 0:2b6d7af79c9c | 246 | |
lmayencou | 0:2b6d7af79c9c | 247 | void Sprites::drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) |
lmayencou | 0:2b6d7af79c9c | 248 | { |
lmayencou | 0:2b6d7af79c9c | 249 | draw(x, y, bitmap, frame, NULL, 0, SPRITE_OVERWRITE); |
lmayencou | 0:2b6d7af79c9c | 250 | } |
lmayencou | 0:2b6d7af79c9c | 251 | |
lmayencou | 0:2b6d7af79c9c | 252 | void Sprites::drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) |
lmayencou | 0:2b6d7af79c9c | 253 | { |
lmayencou | 0:2b6d7af79c9c | 254 | draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK_ERASE); |
lmayencou | 0:2b6d7af79c9c | 255 | } |
lmayencou | 0:2b6d7af79c9c | 256 | |
lmayencou | 0:2b6d7af79c9c | 257 | void Sprites::drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) |
lmayencou | 0:2b6d7af79c9c | 258 | { |
lmayencou | 0:2b6d7af79c9c | 259 | draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK); |
lmayencou | 0:2b6d7af79c9c | 260 | } |
lmayencou | 0:2b6d7af79c9c | 261 | |
lmayencou | 0:2b6d7af79c9c | 262 | void Sprites::drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) |
lmayencou | 0:2b6d7af79c9c | 263 | { |
lmayencou | 0:2b6d7af79c9c | 264 | draw(x, y, bitmap, frame, NULL, 0, SPRITE_PLUS_MASK); |
lmayencou | 0:2b6d7af79c9c | 265 | } |
lmayencou | 0:2b6d7af79c9c | 266 | |
lmayencou | 0:2b6d7af79c9c | 267 | |
lmayencou | 0:2b6d7af79c9c | 268 | //common functions |
lmayencou | 0:2b6d7af79c9c | 269 | void Sprites::draw(int16_t x, int16_t y, |
lmayencou | 0:2b6d7af79c9c | 270 | const uint8_t *bitmap, uint8_t frame, |
lmayencou | 0:2b6d7af79c9c | 271 | const uint8_t *mask, uint8_t sprite_frame, |
lmayencou | 0:2b6d7af79c9c | 272 | uint8_t drawMode |
lmayencou | 0:2b6d7af79c9c | 273 | ) |
lmayencou | 0:2b6d7af79c9c | 274 | { |
lmayencou | 0:2b6d7af79c9c | 275 | unsigned int frame_offset; |
lmayencou | 0:2b6d7af79c9c | 276 | |
lmayencou | 0:2b6d7af79c9c | 277 | if (bitmap == NULL) |
lmayencou | 0:2b6d7af79c9c | 278 | return; |
lmayencou | 0:2b6d7af79c9c | 279 | |
lmayencou | 0:2b6d7af79c9c | 280 | uint8_t width = pgm_read_byte(bitmap); |
lmayencou | 0:2b6d7af79c9c | 281 | uint8_t height = pgm_read_byte(++bitmap); |
lmayencou | 0:2b6d7af79c9c | 282 | bitmap++; |
lmayencou | 0:2b6d7af79c9c | 283 | if (frame > 0 || sprite_frame > 0) { |
lmayencou | 0:2b6d7af79c9c | 284 | frame_offset = (width * ( height / 8 + ( height % 8 == 0 ? 0 : 1))); |
lmayencou | 0:2b6d7af79c9c | 285 | // sprite plus mask uses twice as much space for each frame |
lmayencou | 0:2b6d7af79c9c | 286 | if (drawMode == SPRITE_PLUS_MASK) { |
lmayencou | 0:2b6d7af79c9c | 287 | frame_offset *= 2; |
lmayencou | 0:2b6d7af79c9c | 288 | } else if (mask != NULL) { |
lmayencou | 0:2b6d7af79c9c | 289 | mask += sprite_frame * frame_offset; |
lmayencou | 0:2b6d7af79c9c | 290 | } |
lmayencou | 0:2b6d7af79c9c | 291 | bitmap += frame * frame_offset; |
lmayencou | 0:2b6d7af79c9c | 292 | } |
lmayencou | 0:2b6d7af79c9c | 293 | |
lmayencou | 0:2b6d7af79c9c | 294 | // if we're detecting the draw mode then base it on whether a mask |
lmayencou | 0:2b6d7af79c9c | 295 | // was passed as a separate object |
lmayencou | 0:2b6d7af79c9c | 296 | if (drawMode == SPRITE_AUTO_MODE) { |
lmayencou | 0:2b6d7af79c9c | 297 | drawMode = mask == NULL ? SPRITE_UNMASKED : SPRITE_MASKED; |
lmayencou | 0:2b6d7af79c9c | 298 | } |
lmayencou | 0:2b6d7af79c9c | 299 | |
lmayencou | 0:2b6d7af79c9c | 300 | drawBitmap(x, y, bitmap, mask, width, height, drawMode); |
lmayencou | 0:2b6d7af79c9c | 301 | } |
lmayencou | 0:2b6d7af79c9c | 302 | |
lmayencou | 0:2b6d7af79c9c | 303 | void Sprites::drawBitmap(int16_t x, int16_t y, |
lmayencou | 0:2b6d7af79c9c | 304 | const uint8_t *bitmap, const uint8_t *mask, |
lmayencou | 0:2b6d7af79c9c | 305 | int8_t w, int8_t h, uint8_t draw_mode) { |
lmayencou | 0:2b6d7af79c9c | 306 | // no need to draw at all of we're offscreen |
lmayencou | 0:2b6d7af79c9c | 307 | if (x + w <= 0 || x > WIDTH - 1 || y + h <= 0 || y > HEIGHT - 1) |
lmayencou | 0:2b6d7af79c9c | 308 | return; |
lmayencou | 0:2b6d7af79c9c | 309 | |
lmayencou | 0:2b6d7af79c9c | 310 | if (bitmap == NULL) |
lmayencou | 0:2b6d7af79c9c | 311 | return; |
lmayencou | 0:2b6d7af79c9c | 312 | |
lmayencou | 0:2b6d7af79c9c | 313 | // xOffset technically doesn't need to be 16 bit but the math operations |
lmayencou | 0:2b6d7af79c9c | 314 | // are measurably faster if it is |
lmayencou | 0:2b6d7af79c9c | 315 | uint16_t xOffset, ofs; |
lmayencou | 0:2b6d7af79c9c | 316 | int8_t yOffset = abs(y) % 8; |
lmayencou | 0:2b6d7af79c9c | 317 | int8_t sRow = y / 8; |
lmayencou | 0:2b6d7af79c9c | 318 | uint8_t loop_h, start_h, rendered_width; |
lmayencou | 0:2b6d7af79c9c | 319 | |
lmayencou | 0:2b6d7af79c9c | 320 | if (y < 0 && yOffset > 0) { |
lmayencou | 0:2b6d7af79c9c | 321 | sRow--; |
lmayencou | 0:2b6d7af79c9c | 322 | yOffset = 8 - yOffset; |
lmayencou | 0:2b6d7af79c9c | 323 | } |
lmayencou | 0:2b6d7af79c9c | 324 | |
lmayencou | 0:2b6d7af79c9c | 325 | // if the left side of the render is offscreen skip those loops |
lmayencou | 0:2b6d7af79c9c | 326 | if (x < 0) { |
lmayencou | 0:2b6d7af79c9c | 327 | xOffset = abs(x); |
lmayencou | 0:2b6d7af79c9c | 328 | } else { |
lmayencou | 0:2b6d7af79c9c | 329 | xOffset = 0; |
lmayencou | 0:2b6d7af79c9c | 330 | } |
lmayencou | 0:2b6d7af79c9c | 331 | |
lmayencou | 0:2b6d7af79c9c | 332 | // if the right side of the render is offscreen skip those loops |
lmayencou | 0:2b6d7af79c9c | 333 | if (x + w > WIDTH - 1) { |
lmayencou | 0:2b6d7af79c9c | 334 | rendered_width = ((WIDTH - x) - xOffset); |
lmayencou | 0:2b6d7af79c9c | 335 | } else { |
lmayencou | 0:2b6d7af79c9c | 336 | rendered_width = (w - xOffset); |
lmayencou | 0:2b6d7af79c9c | 337 | } |
lmayencou | 0:2b6d7af79c9c | 338 | |
lmayencou | 0:2b6d7af79c9c | 339 | // if the top side of the render is offscreen skip those loops |
lmayencou | 0:2b6d7af79c9c | 340 | if (sRow < -1) { |
lmayencou | 0:2b6d7af79c9c | 341 | start_h = abs(sRow) - 1; |
lmayencou | 0:2b6d7af79c9c | 342 | } else { |
lmayencou | 0:2b6d7af79c9c | 343 | start_h = 0; |
lmayencou | 0:2b6d7af79c9c | 344 | } |
lmayencou | 0:2b6d7af79c9c | 345 | |
lmayencou | 0:2b6d7af79c9c | 346 | loop_h = h / 8 + (h % 8 > 0 ? 1 : 0); // divide, then round up |
lmayencou | 0:2b6d7af79c9c | 347 | |
lmayencou | 0:2b6d7af79c9c | 348 | // if (sRow + loop_h - 1 > (HEIGHT/8)-1) |
lmayencou | 0:2b6d7af79c9c | 349 | if (sRow + loop_h > (HEIGHT / 8)) { |
lmayencou | 0:2b6d7af79c9c | 350 | loop_h = (HEIGHT / 8) - sRow; |
lmayencou | 0:2b6d7af79c9c | 351 | } |
lmayencou | 0:2b6d7af79c9c | 352 | |
lmayencou | 0:2b6d7af79c9c | 353 | // prepare variables for loops later so we can compare with 0 |
lmayencou | 0:2b6d7af79c9c | 354 | // instead of comparing two variables |
lmayencou | 0:2b6d7af79c9c | 355 | loop_h -= start_h; |
lmayencou | 0:2b6d7af79c9c | 356 | |
lmayencou | 0:2b6d7af79c9c | 357 | sRow += start_h; |
lmayencou | 0:2b6d7af79c9c | 358 | ofs = (sRow * WIDTH) + x + xOffset; |
lmayencou | 0:2b6d7af79c9c | 359 | uint8_t *bofs = (uint8_t *)bitmap + (start_h * w) + xOffset; |
lmayencou | 0:2b6d7af79c9c | 360 | uint8_t *mask_ofs; |
lmayencou | 0:2b6d7af79c9c | 361 | if (mask != 0) |
lmayencou | 0:2b6d7af79c9c | 362 | mask_ofs = (uint8_t *)mask + (start_h * w) + xOffset; |
lmayencou | 0:2b6d7af79c9c | 363 | uint8_t data; |
lmayencou | 0:2b6d7af79c9c | 364 | |
lmayencou | 0:2b6d7af79c9c | 365 | uint8_t mul_amt = 1 << yOffset; |
lmayencou | 0:2b6d7af79c9c | 366 | uint16_t mask_data; |
lmayencou | 0:2b6d7af79c9c | 367 | uint16_t bitmap_data; |
lmayencou | 0:2b6d7af79c9c | 368 | |
lmayencou | 0:2b6d7af79c9c | 369 | switch (draw_mode) { |
lmayencou | 0:2b6d7af79c9c | 370 | case SPRITE_UNMASKED: |
lmayencou | 0:2b6d7af79c9c | 371 | // we only want to mask the 8 bits of our own sprite, so we can |
lmayencou | 0:2b6d7af79c9c | 372 | // calculate the mask before the start of the loop |
lmayencou | 0:2b6d7af79c9c | 373 | mask_data = ~(0xFF * mul_amt); |
lmayencou | 0:2b6d7af79c9c | 374 | // really if yOffset = 0 you have a faster case here that could be |
lmayencou | 0:2b6d7af79c9c | 375 | // optimized |
lmayencou | 0:2b6d7af79c9c | 376 | for (uint8_t a = 0; a < loop_h; a++) { |
lmayencou | 0:2b6d7af79c9c | 377 | for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { |
lmayencou | 0:2b6d7af79c9c | 378 | bitmap_data = pgm_read_byte(bofs) * mul_amt; |
lmayencou | 0:2b6d7af79c9c | 379 | |
lmayencou | 0:2b6d7af79c9c | 380 | if (sRow >= 0) { |
lmayencou | 0:2b6d7af79c9c | 381 | data = sBuffer[ofs]; |
lmayencou | 0:2b6d7af79c9c | 382 | data &= (uint8_t)(mask_data); |
lmayencou | 0:2b6d7af79c9c | 383 | data |= (uint8_t)(bitmap_data); |
lmayencou | 0:2b6d7af79c9c | 384 | sBuffer[ofs] = data; |
lmayencou | 0:2b6d7af79c9c | 385 | } |
lmayencou | 0:2b6d7af79c9c | 386 | if (yOffset != 0 && sRow < 7) { |
lmayencou | 0:2b6d7af79c9c | 387 | data = sBuffer[ofs + WIDTH]; |
lmayencou | 0:2b6d7af79c9c | 388 | data &= (*((unsigned char *) (&mask_data) + 1)); |
lmayencou | 0:2b6d7af79c9c | 389 | data |= (*((unsigned char *) (&bitmap_data) + 1)); |
lmayencou | 0:2b6d7af79c9c | 390 | sBuffer[ofs + WIDTH] = data; |
lmayencou | 0:2b6d7af79c9c | 391 | } |
lmayencou | 0:2b6d7af79c9c | 392 | ofs++; |
lmayencou | 0:2b6d7af79c9c | 393 | bofs++; |
lmayencou | 0:2b6d7af79c9c | 394 | } |
lmayencou | 0:2b6d7af79c9c | 395 | sRow++; |
lmayencou | 0:2b6d7af79c9c | 396 | bofs += w - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 397 | ofs += WIDTH - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 398 | } |
lmayencou | 0:2b6d7af79c9c | 399 | break; |
lmayencou | 0:2b6d7af79c9c | 400 | |
lmayencou | 0:2b6d7af79c9c | 401 | case SPRITE_IS_MASK: |
lmayencou | 0:2b6d7af79c9c | 402 | for (uint8_t a = 0; a < loop_h; a++) { |
lmayencou | 0:2b6d7af79c9c | 403 | for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { |
lmayencou | 0:2b6d7af79c9c | 404 | bitmap_data = pgm_read_byte(bofs) * mul_amt; |
lmayencou | 0:2b6d7af79c9c | 405 | if (sRow >= 0) { |
lmayencou | 0:2b6d7af79c9c | 406 | sBuffer[ofs] |= (uint8_t)(bitmap_data); |
lmayencou | 0:2b6d7af79c9c | 407 | } |
lmayencou | 0:2b6d7af79c9c | 408 | if (yOffset != 0 && sRow < 7) { |
lmayencou | 0:2b6d7af79c9c | 409 | sBuffer[ofs + WIDTH] |= (*((unsigned char *) (&bitmap_data) + 1)); |
lmayencou | 0:2b6d7af79c9c | 410 | } |
lmayencou | 0:2b6d7af79c9c | 411 | ofs++; |
lmayencou | 0:2b6d7af79c9c | 412 | bofs++; |
lmayencou | 0:2b6d7af79c9c | 413 | } |
lmayencou | 0:2b6d7af79c9c | 414 | sRow++; |
lmayencou | 0:2b6d7af79c9c | 415 | bofs += w - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 416 | ofs += WIDTH - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 417 | } |
lmayencou | 0:2b6d7af79c9c | 418 | break; |
lmayencou | 0:2b6d7af79c9c | 419 | |
lmayencou | 0:2b6d7af79c9c | 420 | case SPRITE_IS_MASK_ERASE: |
lmayencou | 0:2b6d7af79c9c | 421 | for (uint8_t a = 0; a < loop_h; a++) { |
lmayencou | 0:2b6d7af79c9c | 422 | for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { |
lmayencou | 0:2b6d7af79c9c | 423 | bitmap_data = pgm_read_byte(bofs) * mul_amt; |
lmayencou | 0:2b6d7af79c9c | 424 | if (sRow >= 0) { |
lmayencou | 0:2b6d7af79c9c | 425 | sBuffer[ofs] &= ~(uint8_t)(bitmap_data); |
lmayencou | 0:2b6d7af79c9c | 426 | } |
lmayencou | 0:2b6d7af79c9c | 427 | if (yOffset != 0 && sRow < 7) { |
lmayencou | 0:2b6d7af79c9c | 428 | sBuffer[ofs + WIDTH] &= ~(*((unsigned char *) (&bitmap_data) + 1)); |
lmayencou | 0:2b6d7af79c9c | 429 | } |
lmayencou | 0:2b6d7af79c9c | 430 | ofs++; |
lmayencou | 0:2b6d7af79c9c | 431 | bofs++; |
lmayencou | 0:2b6d7af79c9c | 432 | } |
lmayencou | 0:2b6d7af79c9c | 433 | sRow++; |
lmayencou | 0:2b6d7af79c9c | 434 | bofs += w - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 435 | ofs += WIDTH - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 436 | } |
lmayencou | 0:2b6d7af79c9c | 437 | break; |
lmayencou | 0:2b6d7af79c9c | 438 | |
lmayencou | 0:2b6d7af79c9c | 439 | case SPRITE_MASKED: |
lmayencou | 0:2b6d7af79c9c | 440 | for (uint8_t a = 0; a < loop_h; a++) { |
lmayencou | 0:2b6d7af79c9c | 441 | for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { |
lmayencou | 0:2b6d7af79c9c | 442 | // NOTE: you might think in the yOffset==0 case that this results |
lmayencou | 0:2b6d7af79c9c | 443 | // in more effort, but in all my testing the compiler was forcing |
lmayencou | 0:2b6d7af79c9c | 444 | // 16-bit math to happen here anyways, so this isn't actually |
lmayencou | 0:2b6d7af79c9c | 445 | // compiling to more code than it otherwise would. If the offset |
lmayencou | 0:2b6d7af79c9c | 446 | // is 0 the high part of the word will just never be used. |
lmayencou | 0:2b6d7af79c9c | 447 | |
lmayencou | 0:2b6d7af79c9c | 448 | // load data and bit shift |
lmayencou | 0:2b6d7af79c9c | 449 | // mask needs to be bit flipped |
lmayencou | 0:2b6d7af79c9c | 450 | mask_data = ~(pgm_read_byte(mask_ofs) * mul_amt); |
lmayencou | 0:2b6d7af79c9c | 451 | bitmap_data = pgm_read_byte(bofs) * mul_amt; |
lmayencou | 0:2b6d7af79c9c | 452 | |
lmayencou | 0:2b6d7af79c9c | 453 | if (sRow >= 0) { |
lmayencou | 0:2b6d7af79c9c | 454 | data = sBuffer[ofs]; |
lmayencou | 0:2b6d7af79c9c | 455 | data &= (uint8_t)(mask_data); |
lmayencou | 0:2b6d7af79c9c | 456 | data |= (uint8_t)(bitmap_data); |
lmayencou | 0:2b6d7af79c9c | 457 | sBuffer[ofs] = data; |
lmayencou | 0:2b6d7af79c9c | 458 | } |
lmayencou | 0:2b6d7af79c9c | 459 | if (yOffset != 0 && sRow < 7) { |
lmayencou | 0:2b6d7af79c9c | 460 | data = sBuffer[ofs + WIDTH]; |
lmayencou | 0:2b6d7af79c9c | 461 | data &= (*((unsigned char *) (&mask_data) + 1)); |
lmayencou | 0:2b6d7af79c9c | 462 | data |= (*((unsigned char *) (&bitmap_data) + 1)); |
lmayencou | 0:2b6d7af79c9c | 463 | sBuffer[ofs + WIDTH] = data; |
lmayencou | 0:2b6d7af79c9c | 464 | } |
lmayencou | 0:2b6d7af79c9c | 465 | ofs++; |
lmayencou | 0:2b6d7af79c9c | 466 | mask_ofs++; |
lmayencou | 0:2b6d7af79c9c | 467 | bofs++; |
lmayencou | 0:2b6d7af79c9c | 468 | } |
lmayencou | 0:2b6d7af79c9c | 469 | sRow++; |
lmayencou | 0:2b6d7af79c9c | 470 | bofs += w - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 471 | mask_ofs += w - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 472 | ofs += WIDTH - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 473 | } |
lmayencou | 0:2b6d7af79c9c | 474 | break; |
lmayencou | 0:2b6d7af79c9c | 475 | |
lmayencou | 0:2b6d7af79c9c | 476 | |
lmayencou | 0:2b6d7af79c9c | 477 | case SPRITE_PLUS_MASK: |
lmayencou | 0:2b6d7af79c9c | 478 | // *2 because we use double the bits (mask + bitmap) |
lmayencou | 0:2b6d7af79c9c | 479 | bofs = (uint8_t *)(bitmap + ((start_h * w) + xOffset) * 2); |
lmayencou | 0:2b6d7af79c9c | 480 | |
lmayencou | 0:2b6d7af79c9c | 481 | uint8_t xi = rendered_width; // used for x loop below |
lmayencou | 0:2b6d7af79c9c | 482 | uint8_t yi = loop_h; // used for y loop below |
lmayencou | 0:2b6d7af79c9c | 483 | |
lmayencou | 0:2b6d7af79c9c | 484 | asm volatile( |
lmayencou | 0:2b6d7af79c9c | 485 | "push r28\n" // save Y |
lmayencou | 0:2b6d7af79c9c | 486 | "push r29\n" |
lmayencou | 0:2b6d7af79c9c | 487 | "mov r28, %A[buffer_page2_ofs]\n" // Y = buffer page 2 offset |
lmayencou | 0:2b6d7af79c9c | 488 | "mov r29, %B[buffer_page2_ofs]\n" |
lmayencou | 0:2b6d7af79c9c | 489 | "loop_y:\n" |
lmayencou | 0:2b6d7af79c9c | 490 | "loop_x:\n" |
lmayencou | 0:2b6d7af79c9c | 491 | // load bitmap and mask data |
lmayencou | 0:2b6d7af79c9c | 492 | "lpm %A[bitmap_data], Z+\n" |
lmayencou | 0:2b6d7af79c9c | 493 | "lpm %A[mask_data], Z+\n" |
lmayencou | 0:2b6d7af79c9c | 494 | |
lmayencou | 0:2b6d7af79c9c | 495 | // shift mask and buffer data |
lmayencou | 0:2b6d7af79c9c | 496 | "tst %[yOffset]\n" |
lmayencou | 0:2b6d7af79c9c | 497 | "breq skip_shifting\n" |
lmayencou | 0:2b6d7af79c9c | 498 | "mul %A[bitmap_data], %[mul_amt]\n" |
lmayencou | 0:2b6d7af79c9c | 499 | "mov %A[bitmap_data], r0\n" |
lmayencou | 0:2b6d7af79c9c | 500 | "mov %B[bitmap_data], r1\n" |
lmayencou | 0:2b6d7af79c9c | 501 | "mul %A[mask_data], %[mul_amt]\n" |
lmayencou | 0:2b6d7af79c9c | 502 | "mov %A[mask_data], r0\n" |
lmayencou | 0:2b6d7af79c9c | 503 | // "mov %B[mask_data], r1\n" |
lmayencou | 0:2b6d7af79c9c | 504 | |
lmayencou | 0:2b6d7af79c9c | 505 | |
lmayencou | 0:2b6d7af79c9c | 506 | // SECOND PAGE |
lmayencou | 0:2b6d7af79c9c | 507 | // if yOffset != 0 && sRow < 7 |
lmayencou | 0:2b6d7af79c9c | 508 | "cpi %[sRow], 7\n" |
lmayencou | 0:2b6d7af79c9c | 509 | "brge end_second_page\n" |
lmayencou | 0:2b6d7af79c9c | 510 | // then |
lmayencou | 0:2b6d7af79c9c | 511 | "ld %[data], Y\n" |
lmayencou | 0:2b6d7af79c9c | 512 | // "com %B[mask_data]\n" // invert high byte of mask |
lmayencou | 0:2b6d7af79c9c | 513 | "com r1\n" |
lmayencou | 0:2b6d7af79c9c | 514 | "and %[data], r1\n" // %B[mask_data] |
lmayencou | 0:2b6d7af79c9c | 515 | "or %[data], %B[bitmap_data]\n" |
lmayencou | 0:2b6d7af79c9c | 516 | // update buffer, increment |
lmayencou | 0:2b6d7af79c9c | 517 | "st Y+, %[data]\n" |
lmayencou | 0:2b6d7af79c9c | 518 | |
lmayencou | 0:2b6d7af79c9c | 519 | "end_second_page:\n" |
lmayencou | 0:2b6d7af79c9c | 520 | "skip_shifting:\n" |
lmayencou | 0:2b6d7af79c9c | 521 | |
lmayencou | 0:2b6d7af79c9c | 522 | |
lmayencou | 0:2b6d7af79c9c | 523 | // FIRST PAGE |
lmayencou | 0:2b6d7af79c9c | 524 | "ld %[data], %a[buffer_ofs]\n" |
lmayencou | 0:2b6d7af79c9c | 525 | // if sRow >= 0 |
lmayencou | 0:2b6d7af79c9c | 526 | "tst %[sRow]\n" |
lmayencou | 0:2b6d7af79c9c | 527 | "brmi end_first_page\n" |
lmayencou | 0:2b6d7af79c9c | 528 | // then |
lmayencou | 0:2b6d7af79c9c | 529 | "com %A[mask_data]\n" |
lmayencou | 0:2b6d7af79c9c | 530 | "and %[data], %A[mask_data]\n" |
lmayencou | 0:2b6d7af79c9c | 531 | "or %[data], %A[bitmap_data]\n" |
lmayencou | 0:2b6d7af79c9c | 532 | |
lmayencou | 0:2b6d7af79c9c | 533 | "end_first_page:\n" |
lmayencou | 0:2b6d7af79c9c | 534 | // update buffer, increment |
lmayencou | 0:2b6d7af79c9c | 535 | "st %a[buffer_ofs]+, %[data]\n" |
lmayencou | 0:2b6d7af79c9c | 536 | |
lmayencou | 0:2b6d7af79c9c | 537 | |
lmayencou | 0:2b6d7af79c9c | 538 | // "x_loop_next:\n" |
lmayencou | 0:2b6d7af79c9c | 539 | "dec %[xi]\n" |
lmayencou | 0:2b6d7af79c9c | 540 | "brne loop_x\n" |
lmayencou | 0:2b6d7af79c9c | 541 | |
lmayencou | 0:2b6d7af79c9c | 542 | // increment y |
lmayencou | 0:2b6d7af79c9c | 543 | "next_loop_y:\n" |
lmayencou | 0:2b6d7af79c9c | 544 | "dec %[yi]\n" |
lmayencou | 0:2b6d7af79c9c | 545 | "breq finished\n" |
lmayencou | 0:2b6d7af79c9c | 546 | "mov %[xi], %[x_count]\n" // reset x counter |
lmayencou | 0:2b6d7af79c9c | 547 | // sRow++; |
lmayencou | 0:2b6d7af79c9c | 548 | "inc %[sRow]\n" |
lmayencou | 0:2b6d7af79c9c | 549 | "clr __zero_reg__\n" |
lmayencou | 0:2b6d7af79c9c | 550 | // sprite_ofs += (w - rendered_width) * 2; |
lmayencou | 0:2b6d7af79c9c | 551 | "add %A[sprite_ofs], %A[sprite_ofs_jump]\n" |
lmayencou | 0:2b6d7af79c9c | 552 | "adc %B[sprite_ofs], __zero_reg__\n" |
lmayencou | 0:2b6d7af79c9c | 553 | // buffer_ofs += WIDTH - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 554 | "add %A[buffer_ofs], %A[buffer_ofs_jump]\n" |
lmayencou | 0:2b6d7af79c9c | 555 | "adc %B[buffer_ofs], __zero_reg__\n" |
lmayencou | 0:2b6d7af79c9c | 556 | // buffer_ofs_page_2 += WIDTH - rendered_width; |
lmayencou | 0:2b6d7af79c9c | 557 | "add r28, %A[buffer_ofs_jump]\n" |
lmayencou | 0:2b6d7af79c9c | 558 | "adc r29, __zero_reg__\n" |
lmayencou | 0:2b6d7af79c9c | 559 | |
lmayencou | 0:2b6d7af79c9c | 560 | "rjmp loop_y\n" |
lmayencou | 0:2b6d7af79c9c | 561 | "finished:\n" |
lmayencou | 0:2b6d7af79c9c | 562 | // put the Y register back in place |
lmayencou | 0:2b6d7af79c9c | 563 | "pop r29\n" |
lmayencou | 0:2b6d7af79c9c | 564 | "pop r28\n" |
lmayencou | 0:2b6d7af79c9c | 565 | "clr __zero_reg__\n" // just in case |
lmayencou | 0:2b6d7af79c9c | 566 | : [xi] "+&r" (xi), |
lmayencou | 0:2b6d7af79c9c | 567 | [yi] "+&r" (yi), |
lmayencou | 0:2b6d7af79c9c | 568 | [sRow] "+&a" (sRow), // CPI requires an upper register |
lmayencou | 0:2b6d7af79c9c | 569 | [data] "+&r" (data), |
lmayencou | 0:2b6d7af79c9c | 570 | [mask_data] "+&r" (mask_data), |
lmayencou | 0:2b6d7af79c9c | 571 | [bitmap_data] "+&r" (bitmap_data) |
lmayencou | 0:2b6d7af79c9c | 572 | : |
lmayencou | 0:2b6d7af79c9c | 573 | [x_count] "r" (rendered_width), |
lmayencou | 0:2b6d7af79c9c | 574 | [y_count] "r" (loop_h), |
lmayencou | 0:2b6d7af79c9c | 575 | [sprite_ofs] "z" (bofs), |
lmayencou | 0:2b6d7af79c9c | 576 | [buffer_ofs] "x" (sBuffer+ofs), |
lmayencou | 0:2b6d7af79c9c | 577 | [buffer_page2_ofs] "r" (sBuffer+ofs+WIDTH), // Y pointer |
lmayencou | 0:2b6d7af79c9c | 578 | [buffer_ofs_jump] "r" (WIDTH-rendered_width), |
lmayencou | 0:2b6d7af79c9c | 579 | [sprite_ofs_jump] "r" ((w-rendered_width)*2), |
lmayencou | 0:2b6d7af79c9c | 580 | [yOffset] "r" (yOffset), |
lmayencou | 0:2b6d7af79c9c | 581 | [mul_amt] "r" (mul_amt) |
lmayencou | 0:2b6d7af79c9c | 582 | : |
lmayencou | 0:2b6d7af79c9c | 583 | ); |
lmayencou | 0:2b6d7af79c9c | 584 | break; |
lmayencou | 0:2b6d7af79c9c | 585 | |
lmayencou | 0:2b6d7af79c9c | 586 | } |
lmayencou | 0:2b6d7af79c9c | 587 | } |
lmayencou | 0:2b6d7af79c9c | 588 | |
lmayencou | 0:2b6d7af79c9c | 589 | |
lmayencou | 0:2b6d7af79c9c | 590 | ///////////////////////////////// |
lmayencou | 0:2b6d7af79c9c | 591 | // Basic Collision by Dreamer3 // |
lmayencou | 0:2b6d7af79c9c | 592 | ///////////////////////////////// |
lmayencou | 0:2b6d7af79c9c | 593 | bool Arduboy::collide(Point point, Rect rect) |
lmayencou | 0:2b6d7af79c9c | 594 | { |
lmayencou | 0:2b6d7af79c9c | 595 | // does point fall within the bounds of rect |
lmayencou | 0:2b6d7af79c9c | 596 | return ((point.x >= rect.x) && (point.x < rect.x + rect.width) && |
lmayencou | 0:2b6d7af79c9c | 597 | (point.y >= rect.y) && (point.y < rect.y + rect.height)); |
lmayencou | 0:2b6d7af79c9c | 598 | } |
lmayencou | 0:2b6d7af79c9c | 599 | |
lmayencou | 0:2b6d7af79c9c | 600 | bool Arduboy::collide(Rect rect1, Rect rect2) |
lmayencou | 0:2b6d7af79c9c | 601 | { |
lmayencou | 0:2b6d7af79c9c | 602 | return !( rect2.x >= rect1.x + rect1.width || |
lmayencou | 0:2b6d7af79c9c | 603 | rect2.x + rect2.width <= rect1.x || |
lmayencou | 0:2b6d7af79c9c | 604 | rect2.y >= rect1.y + rect1.height || |
lmayencou | 0:2b6d7af79c9c | 605 | rect2.y + rect2.height <= rect1.y); |
lmayencou | 0:2b6d7af79c9c | 606 | } |