diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 93a25ea..50e9f78 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -5,6 +5,7 @@ - Ross (@rogosher) - Andrew (@ace-dent) - Josh Goebel (@yyyc514) +- Scott Allen (@MLXXXp) # Included code from other open source projects diff --git a/LICENSE b/LICENSE index 01d4bc4..20c38a5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,9 @@ Software License Agreement (BSD License) -Copyright (c) 2015, Kevin "Arduboy" Bates -Copyright (c) 2015, Chris Martinez -Copyright (c) 2015, Josh Goebel +Copyright (c) 2016, Kevin "Arduboy" Bates +Copyright (c) 2016, Chris Martinez +Copyright (c) 2016, Josh Goebel +Copyright (c) 2016, Scott Allen All rights reserved. Please see CONTRIBUTORS.md for license information and copyright diff --git a/library.properties b/library.properties index f579326..79460bf 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ -name=Arduboy -version=1.2.0-alpha +name=Arduboy2 +version=0.9.0 author=Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen, Ross O. Shoger maintainer=Ross O. Shoger ros@arduboy.com sentence=The Arduboy core library. paragraph=This library is for content creation on the Arduboy, a portable gaming platform. The library provides access to the sound, display, and input of the Arduboy. category=Other -url=https://github.com/arduboy/arduboy +url=https://github.com/arduboy/arduboy2 architectures=avr diff --git a/src/Arduboy.cpp b/src/Arduboy2.cpp similarity index 81% rename from src/Arduboy.cpp rename to src/Arduboy2.cpp index 2da4d6c..6fbb637 100644 --- a/src/Arduboy.cpp +++ b/src/Arduboy2.cpp @@ -1,8 +1,12 @@ -#include "Arduboy.h" -#include "glcdfont.c" +#include "Arduboy2.h" #include "ab_logo.c" +#include "glcdfont.c" -Arduboy::Arduboy() +//======================================== +//========== class Arduboy2Base ========== +//======================================== + +Arduboy2Base::Arduboy2Base() { // frame management setFrameRate(60); @@ -15,7 +19,7 @@ Arduboy::Arduboy() // lastFrameDurationMs } -void Arduboy::start() // deprecated +void Arduboy2Base::start() // deprecated { begin(); } @@ -23,7 +27,7 @@ void Arduboy::start() // deprecated // functions called here should be public so users can create their // own init functions if they need different behavior than `begin` // provides by default -void Arduboy::begin() +void Arduboy2Base::begin() { boot(); // raw hardware @@ -37,7 +41,7 @@ void Arduboy::begin() audio.begin(); } -void Arduboy::flashlight() +void Arduboy2Base::flashlight() { // sendLCDCommand(OLED_ALL_PIXELS_ON); // smaller than allPixelsOn() blank(); @@ -48,7 +52,7 @@ void Arduboy::flashlight() setRGBled(0,0,0); } -void Arduboy::bootLogo() +void Arduboy2Base::bootLogo() { // setRGBled(10,0,0); for(int8_t y = -18; y<=24; y++) { @@ -71,18 +75,18 @@ void Arduboy::bootLogo() /* Frame management */ -void Arduboy::setFrameRate(uint8_t rate) +void Arduboy2Base::setFrameRate(uint8_t rate) { frameRate = rate; eachFrameMillis = 1000/rate; } -bool Arduboy::everyXFrames(uint8_t frames) +bool Arduboy2Base::everyXFrames(uint8_t frames) { return frameCount % frames == 0; } -bool Arduboy::nextFrame() +bool Arduboy2Base::nextFrame() { long now = millis(); uint8_t remaining; @@ -129,19 +133,19 @@ bool Arduboy::nextFrame() return post_render; } -int Arduboy::cpuLoad() +int Arduboy2Base::cpuLoad() { return lastFrameDurationMs*100 / eachFrameMillis; } -void Arduboy::initRandomSeed() +void Arduboy2Base::initRandomSeed() { power_adc_enable(); // ADC on randomSeed(~rawADC(ADC_TEMP) * ~rawADC(ADC_VOLTAGE) * ~micros() + micros()); power_adc_disable(); // ADC off } -uint16_t Arduboy::rawADC(byte adc_bits) +uint16_t Arduboy2Base::rawADC(byte adc_bits) { ADMUX = adc_bits; // we also need MUX5 for temperature check @@ -158,17 +162,17 @@ uint16_t Arduboy::rawADC(byte adc_bits) /* Graphics */ -void Arduboy::clearDisplay() // deprecated +void Arduboy2Base::clearDisplay() // deprecated { clear(); } -void Arduboy::clear() +void Arduboy2Base::clear() { fillScreen(BLACK); } -void Arduboy::drawPixel(int x, int y, uint8_t color) +void Arduboy2Base::drawPixel(int x, int y, uint8_t color) { #ifdef PIXEL_SAFE_MODE if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1)) @@ -188,14 +192,14 @@ void Arduboy::drawPixel(int x, int y, uint8_t color) } } -uint8_t Arduboy::getPixel(uint8_t x, uint8_t y) +uint8_t Arduboy2Base::getPixel(uint8_t x, uint8_t y) { uint8_t row = y / 8; uint8_t bit_position = y % 8; return (sBuffer[(row*WIDTH) + x] & _BV(bit_position)) >> bit_position; } -void Arduboy::drawCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color) +void Arduboy2Base::drawCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color) { int16_t f = 1 - r; int16_t ddF_x = 1; @@ -232,7 +236,7 @@ void Arduboy::drawCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color) } } -void Arduboy::drawCircleHelper +void Arduboy2Base::drawCircleHelper (int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, uint8_t color) { int16_t f = 1 - r; @@ -277,13 +281,13 @@ void Arduboy::drawCircleHelper } } -void Arduboy::fillCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color) +void Arduboy2Base::fillCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color) { drawFastVLine(x0, y0-r, 2*r+1, color); fillCircleHelper(x0, y0, r, 3, 0, color); } -void Arduboy::fillCircleHelper +void Arduboy2Base::fillCircleHelper (int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, int16_t delta, uint8_t color) { @@ -321,7 +325,7 @@ void Arduboy::fillCircleHelper } } -void Arduboy::drawLine +void Arduboy2Base::drawLine (int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color) { // bresenham's algorithm - thx wikpedia @@ -372,7 +376,7 @@ void Arduboy::drawLine } } -void Arduboy::drawRect +void Arduboy2Base::drawRect (int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color) { drawFastHLine(x, y, w, color); @@ -381,7 +385,7 @@ void Arduboy::drawRect drawFastVLine(x+w-1, y, h, color); } -void Arduboy::drawFastVLine +void Arduboy2Base::drawFastVLine (int16_t x, int16_t y, uint8_t h, uint8_t color) { int end = y+h; @@ -391,7 +395,7 @@ void Arduboy::drawFastVLine } } -void Arduboy::drawFastHLine +void Arduboy2Base::drawFastHLine (int16_t x, int16_t y, uint8_t w, uint8_t color) { // Do bounds/limit checks @@ -438,7 +442,7 @@ void Arduboy::drawFastHLine } } -void Arduboy::fillRect +void Arduboy2Base::fillRect (int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color) { // stupidest version - update in subclasses if desired! @@ -448,7 +452,7 @@ void Arduboy::fillRect } } -void Arduboy::fillScreen(uint8_t color) +void Arduboy2Base::fillScreen(uint8_t color) { // C version : // @@ -486,7 +490,7 @@ void Arduboy::fillScreen(uint8_t color) ); } -void Arduboy::drawRoundRect +void Arduboy2Base::drawRoundRect (int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color) { // smarter version @@ -501,7 +505,7 @@ void Arduboy::drawRoundRect drawCircleHelper(x+r, y+h-r-1, r, 8, color); } -void Arduboy::fillRoundRect +void Arduboy2Base::fillRoundRect (int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color) { // smarter version @@ -512,7 +516,7 @@ void Arduboy::fillRoundRect fillCircleHelper(x+r, y+r, r, 2, h-2*r-1, color); } -void Arduboy::drawTriangle +void Arduboy2Base::drawTriangle (int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color) { drawLine(x0, y0, x1, y1, color); @@ -520,7 +524,7 @@ void Arduboy::drawTriangle drawLine(x2, y2, x0, y0, color); } -void Arduboy::fillTriangle +void Arduboy2Base::fillTriangle (int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color) { @@ -623,7 +627,7 @@ void Arduboy::fillTriangle } } -void Arduboy::drawBitmap +void Arduboy2Base::drawBitmap (int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color) { @@ -663,10 +667,10 @@ void Arduboy::drawBitmap } -void Arduboy::drawSlowXYBitmap +void Arduboy2Base::drawSlowXYBitmap (int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color) { - // no need to dar at all of we're offscreen + // no need to draw at all of we're offscreen if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1) return; @@ -681,16 +685,82 @@ void Arduboy::drawSlowXYBitmap } -void Arduboy::drawChar -(int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size) +void Arduboy2Base::display() +{ + this->paintScreen(sBuffer); +} + +unsigned char* Arduboy2Base::getBuffer() +{ + return sBuffer; +} + +boolean Arduboy2Base::pressed(uint8_t buttons) +{ + return (buttonsState() & buttons) == buttons; +} + +boolean Arduboy2Base::notPressed(uint8_t buttons) +{ + return (buttonsState() & buttons) == 0; +} + +void Arduboy2Base::swap(int16_t& a, int16_t& b) +{ + int temp = a; + a = b; + b = temp; +} + +Arduboy2::Arduboy2() +{ + cursor_x = 0; + cursor_y = 0; + textColor = 1; + textBackground = 0; + textSize = 1; + textWrap = 0; +} + + +//==================================== +//========== class Arduboy2 ========== +//==================================== + +size_t Arduboy2::write(uint8_t c) +{ + if (c == '\n') + { + cursor_y += textSize * 8; + cursor_x = 0; + } + else if (c == '\r') + { + // skip em + } + else + { + drawChar(cursor_x, cursor_y, c, textColor, textBackground, textSize); + cursor_x += textSize * 6; + if (textWrap && (cursor_x > (WIDTH - textSize * 6))) + { + // calling ourselves recursively for 'newline' is + // 12 bytes smaller than doing the same math here + write('\n'); + } + } +} + +void Arduboy2::drawChar + (int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size) { boolean draw_background = bg != color; - if ((x >= WIDTH) || // Clip right - (y >= HEIGHT) || // Clip bottom - ((x + 5 * size - 1) < 0) || // Clip left - ((y + 8 * size - 1) < 0) // Clip top - ) + if ((x >= WIDTH) || // Clip right + (y >= HEIGHT) || // Clip bottom + ((x + 5 * size - 1) < 0) || // Clip left + ((y + 8 * size - 1) < 0) // Clip top + ) { return; } @@ -723,30 +793,43 @@ void Arduboy::drawChar } } -void Arduboy::display() +void Arduboy2::setCursor(int16_t x, int16_t y) { - this->paintScreen(sBuffer); + cursor_x = x; + cursor_y = y; } -unsigned char* Arduboy::getBuffer() -{ - return sBuffer; +uint16_t Arduboy2::getCursorX() { + return cursor_x; } -boolean Arduboy::pressed(uint8_t buttons) -{ - return (buttonsState() & buttons) == buttons; +uint16_t Arduboy2::getCursorY() { + return cursor_y; } -boolean Arduboy::notPressed(uint8_t buttons) +void Arduboy2::setTextColor(uint8_t color) { - return (buttonsState() & buttons) == 0; + textColor = color; } -void Arduboy::swap(int16_t& a, int16_t& b) +void Arduboy2::setTextBackground(uint8_t bg) { - int temp = a; - a = b; - b = temp; + textBackground = bg; +} + +void Arduboy2::setTextSize(uint8_t s) +{ + // size must always be 1 or higher + textSize = max(1, s); +} + +void Arduboy2::setTextWrap(boolean w) +{ + textWrap = w; +} + +void Arduboy2::clear() { + Arduboy2Base::clear(); + cursor_x = cursor_y = 0; } diff --git a/src/Arduboy.h b/src/Arduboy2.h similarity index 76% rename from src/Arduboy.h rename to src/Arduboy2.h index 752e8e4..7f51361 100644 --- a/src/Arduboy.h +++ b/src/Arduboy2.h @@ -1,8 +1,7 @@ -#ifndef Arduboy_h -#define Arduboy_h +#ifndef Arduboy2_h +#define Arduboy2_h #include "core/core.h" -#include "ab_printer.h" #include #include @@ -10,7 +9,7 @@ // For a version number in the form of x.y.z the value of the define will be // ((x * 10000) + (y * 100) + (z)) as a decimal number. // So, it will read as xxxyyzz, with no leading zeros on x. -#define ARDUBOY_LIB_VER 10200 +#define ARDUBOY_LIB_VER 20000 // EEPROM settings #define EEPROM_VERSION 0 @@ -36,10 +35,16 @@ #define ADC_TEMP (_BV(REFS0) | _BV(REFS1) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0)) -class Arduboy : public ArduboyCore +//================================== +//========== Arduboy2Base ========== +//================================== + +class Arduboy2Base : public ArduboyCore { public: - Arduboy(); + Arduboy2Base(); + + ArduboyAudio audio; /// Returns true if the button mask passed in is pressed. /** @@ -54,21 +59,17 @@ public: boolean notPressed(uint8_t buttons); /// Initialize hardware, boot logo, boot utilities, etc. - void begin(); - - /// Init just hardware, no logo, no boot utilities. /** - * Look at the source for `begin()` and just rip out what you do not - * need and start there. Calling just `boot()` might work also - * depending on your requirements. - * - * The minimum recommended `begin` replacement: - * - * arduboy.boot() // raw hardware init - * arduboy.audio.begin() // if you need audio + * To free up some code space for use by the sketch, you can use "boot()" + * instead of "begin()" to eliminate some of the some of the things that + * aren't really required, such as displaying the boot logo. + * + * Look at the source for "begin()" and after calling "boot()" call + * whatever functions "begin()" does that you still want to keep. + * If your sketch uses the speaker, it's probably a good idea to at least + * call "audio.begin()". */ - // void boot(); // defined in core.cpp - + void begin(); void start() __attribute__((deprecated, warning("use begin() instead"))); /// Scrolls in the Arduboy logo @@ -161,12 +162,9 @@ public: */ void drawSlowXYBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color); - /// Draws an ASCII character at a point. - void drawChar(int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size); - + /// Get a pointer to the display buffer. unsigned char* getBuffer(); - /// Seeds the random number generator with entropy from the temperature, voltage reading, and microseconds since boot. /** * This method is still most effective when called semi-randomly such @@ -178,8 +176,6 @@ public: /// Swap the references of two pointers. void swap(int16_t& a, int16_t& b); - ArduboyAudio audio; - void setFrameRate(uint8_t rate); bool nextFrame(); bool everyXFrames(uint8_t frames); @@ -205,13 +201,61 @@ public: protected: unsigned char sBuffer[(HEIGHT*WIDTH)/8]; +}; +//============================== +//========== Arduboy2 ========== +//============================== + +class Arduboy2 : public Print, public Arduboy2Base +{ +public: + Arduboy2(); + + /// Writes a single ASCII character to the screen. + virtual size_t write(uint8_t); + + /// Draws an ASCII character at a point. + void drawChar(int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size); + + /// Sets the location of the text cursor. + void setCursor(int16_t x, int16_t y); + + /// Get the text cursor X position + uint16_t getCursorX(); + + /// Get the text cursor Y position + uint16_t getCursorY(); + + /// Sets the text foreground color + void setTextColor(uint8_t color); + + /// Sets the text background color + void setTextBackground(uint8_t bg); + + /// Set the text size + /** + * Individual ASCII characters are 6x8 pixels + * (5x7 with spacing on two edges). The size is a pixel multiplier, + * so a size of 2 means each character will be 12x16, etc. + */ + void setTextSize(uint8_t s); + + /// Sets whether text will wrap at screen edges. + void setTextWrap(boolean w); + + /// Clears the display and sets the cursor to 0, 0 + void clear(); + protected: int16_t cursor_x; int16_t cursor_y; - uint8_t textsize; - boolean wrap; // If set, 'wrap' text at right edge of display + uint8_t textColor; + uint8_t textBackground; + uint8_t textSize; + boolean textWrap; // If set, 'wrap' text at right edge of display }; #endif + diff --git a/src/ab_printer.cpp b/src/ab_printer.cpp deleted file mode 100644 index d648ef3..0000000 --- a/src/ab_printer.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "Arduboy.h" -#include "ab_printer.h" -#include "glcdfont.c" - -AbPrinter::AbPrinter(Arduboy &ab) -{ - arduboy = &ab; - - // font rendering - cursor_x = 0; - cursor_y = 0; - size = 1; -} - -size_t AbPrinter::write(uint8_t c) -{ - if (c == '\n') - { - cursor_y += size*8; - cursor_x = 0; - } - else if (c == '\r') - { - // skip em - } - else - { - arduboy->drawChar(cursor_x, cursor_y, c, 1, 0, size); - cursor_x += size*6; - if (wrap && (cursor_x > (WIDTH - size*6))) - { - // calling ourselves recursively for 'newline' is - // 12 bytes smaller than doing the same math here - write('\n'); - } - } -} - -void AbPrinter::setCursor(int16_t x, int8_t y) -{ - cursor_x = x; - cursor_y = y; -} - -void AbPrinter::setSize(uint8_t s) -{ - // size must always be 1 or higher - size = max(1,s); -} - -void AbPrinter::setWrap(boolean w) -{ - wrap = w; -} \ No newline at end of file diff --git a/src/ab_printer.h b/src/ab_printer.h deleted file mode 100644 index 2f82e66..0000000 --- a/src/ab_printer.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef AbPrinter_h -#define AbPrinter_h - -#include -#include "Arduboy.h" -#include - -class Arduboy; - -/// Separate class to break out Print subclassing -/** - * This is necessary because C++ keeps a virtual function lookup table around - * for the virtual function "write" that the Print subclass requires. That - * single reference to the "write" function in the vtable means "write" will - * always be compiled and including in the final ouput (even if it's never - * actually used in your sketch) - which means it's dependencies are also - # included: - * - * - drawChar - * - font (256 bytes!) - * - drawRect (for large font 'pixels') - * - cursor_x, cursor_y, wrap_mode, etc. - * - * This quickly adds up to 1 to 2kb of wasted space that many graphics - * based games never take advantage of. By breaking printing out into a - * separate class we prevent this. If you need it use it, if not then it - * will get dropped by the compiler during building. - * - */ -class AbPrinter : public Print -{ -public: - AbPrinter(Arduboy &ab); - - /// Writes a single ASCII character to the screen. - virtual size_t write(uint8_t); - - /// Sets the location of the screen cursor. - void setCursor(int16_t x, int8_t y); - - /// Set text size - /** - * As mentioned in drawChar(), individual ASCII characters are 6x8 pixels - * (5x7 with spacing on two edges). The size is a pixel multiplier, - * so a size of 2 means each character will be 12x16, etc. - */ - void setSize(uint8_t s); - - /// Sets whether text will wrap at screen edges. - void setWrap(boolean w); - -private: - Arduboy *arduboy; - -protected: - int16_t cursor_x; - int8_t cursor_y; - uint8_t size; - boolean wrap; // If set, 'wrap' text at right edge of display - -}; - -#endif diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 5785e00..b82d337 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -1,4 +1,4 @@ -#include "Arduboy.h" +#include "Arduboy2.h" #include "audio.h" bool ArduboyAudio::audio_enabled = false; diff --git a/src/core/core.h b/src/core/core.h index 7bab3b4..a607187 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -255,7 +255,7 @@ public: void static sendLCDCommand(uint8_t command); /// set the light output of the RGB LEB - void setRGBled(uint8_t red, uint8_t green, uint8_t blue); + void static setRGBled(uint8_t red, uint8_t green, uint8_t blue); /// boots the hardware /**