diff --git a/examples/Tunes/Tunes.ino b/examples/Tunes/Tunes.ino index 29a1691..0c572f8 100644 --- a/examples/Tunes/Tunes.ino +++ b/examples/Tunes/Tunes.ino @@ -155,14 +155,16 @@ const byte PROGMEM score [] = { 0x80, 0x81, 0x90,0x45, 0,91, 0,136, 0x80, 0x82, 0x90,0x45, 0x91,0x2D, 7,83, 0x80, 0x81, 0xf0}; Arduboy arduboy; +AbPrinter text(arduboy); void setup() { arduboy.begin(); - arduboy.setTextSize(4); - arduboy.setCursor(0,0); - arduboy.print("Music\nDemo"); + text.setSize(4); + text.setCursor(0,0); + text.print("Music\nDemo"); arduboy.display(); + } @@ -191,8 +193,8 @@ void loop () } arduboy.clear(); - arduboy.setCursor(x,y); - arduboy.print("Music\nDemo"); + text.setCursor(x,y); + text.print("Music\nDemo"); arduboy.display(); // play the tune if we aren't already diff --git a/src/Arduboy.cpp b/src/Arduboy.cpp index 87e9654..ec3ef6b 100644 --- a/src/Arduboy.cpp +++ b/src/Arduboy.cpp @@ -9,14 +9,10 @@ Arduboy::Arduboy() frameCount = 0; nextFrameStart = 0; post_render = false; + // init not necessary, will be reset after first use // lastFrameStart // lastFrameDurationMs - - // font rendering - cursor_x = 0; - cursor_y = 0; - textsize = 1; } void Arduboy::start() // deprecated @@ -714,47 +710,6 @@ void Arduboy::drawChar } } -void Arduboy::setCursor(int16_t x, int16_t y) -{ - cursor_x = x; - cursor_y = y; -} - -void Arduboy::setTextSize(uint8_t s) -{ - // textsize must always be 1 or higher - textsize = max(1,s); -} - -void Arduboy::setTextWrap(boolean w) -{ - wrap = w; -} - -size_t Arduboy::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, 1, 0, textsize); - cursor_x += textsize*6; - if (wrap && (cursor_x > (WIDTH - textsize*6))) - { - // calling ourselves recursively for 'newline' is - // 12 bytes smaller than doing the same math here - write('\n'); - } - } -} - void Arduboy::display() { this->paintScreen(sBuffer); @@ -765,7 +720,6 @@ unsigned char* Arduboy::getBuffer() return sBuffer; } - boolean Arduboy::pressed(uint8_t buttons) { return (buttonsState() & buttons) == buttons; diff --git a/src/Arduboy.h b/src/Arduboy.h index a0d15ed..d2a8c50 100644 --- a/src/Arduboy.h +++ b/src/Arduboy.h @@ -2,6 +2,7 @@ #define Arduboy_h #include "core/core.h" +#include "ab_printer.h" #include #include @@ -28,7 +29,8 @@ // compare temperature to 2.5 internal reference and _BV(MUX5) #define ADC_TEMP (_BV(REFS0) | _BV(REFS1) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0)) -class Arduboy : public Print, public ArduboyCore + +class Arduboy : public ArduboyCore { public: Arduboy(); @@ -156,24 +158,8 @@ public: /// 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 screen cursor. - void setCursor(int16_t x, int16_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 setTextSize(uint8_t s); - - /// Sets whether text will wrap at screen edges. - void setTextWrap(boolean w); - unsigned char* getBuffer(); - /// Writes a single ASCII character to the screen. - virtual size_t write(uint8_t); /// Seeds the random number generator with entropy from the temperature, voltage reading, and microseconds since boot. /** @@ -216,7 +202,6 @@ protected: unsigned char sBuffer[(HEIGHT*WIDTH)/8]; -// Adafruit stuff protected: int16_t cursor_x; int16_t cursor_y; diff --git a/src/ab_printer.cpp b/src/ab_printer.cpp new file mode 100644 index 0000000..d648ef3 --- /dev/null +++ b/src/ab_printer.cpp @@ -0,0 +1,54 @@ +#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 new file mode 100644 index 0000000..2f82e66 --- /dev/null +++ b/src/ab_printer.h @@ -0,0 +1,63 @@ +#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