├── .gitattributes ├── .gitignore ├── Font3x5.ino ├── src └── fonts │ ├── Font3x5.h │ └── Font3x5.cpp └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .vscode/c_cpp_properties.json 3 | .vscode/arduino.json 4 | .vscode/tasks.json 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /Font3x5.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "src/fonts/Font3x5.h" 3 | 4 | Arduboy2Base arduboy; 5 | Font3x5 font3x5 = Font3x5(); 6 | 7 | void setup() { 8 | 9 | arduboy.boot(); 10 | 11 | } 12 | 13 | void loop() { 14 | 15 | if (!(arduboy.nextFrame())) return; 16 | 17 | arduboy.clear(); 18 | font3x5.setCursor(12, 12); 19 | font3x5.print(F("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); 20 | font3x5.print(F("\nabcdefghijklmnopqrstuvwxyz")); 21 | font3x5.print(F("\n0123456789")); 22 | font3x5.print(F("\n!.")); 23 | 24 | arduboy.display(); 25 | 26 | } -------------------------------------------------------------------------------- /src/fonts/Font3x5.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Font3x5 : public Print { 7 | 8 | public: 9 | 10 | Font3x5(uint8_t lineSpacing = 8); 11 | 12 | virtual size_t write(uint8_t); // used by the Arduino Print class 13 | void printChar(const char c, const int8_t x, int8_t y); 14 | void setCursor(const int8_t x, const int8_t y); 15 | 16 | void setTextColor(const uint8_t color); 17 | void setHeight(const uint8_t color); 18 | 19 | 20 | private: 21 | 22 | int8_t _cursorX; // Default is 0. 23 | int8_t _baseX; // needed for linebreak. 24 | int8_t _cursorY; // Default is 0. 25 | 26 | int8_t _textColor; // BLACK == 0, everything else is WHITE. Default is WHITE. 27 | 28 | uint8_t _letterSpacing; // letterSpacing controls the distance between letters. Default is 1. 29 | uint8_t _lineHeight; // lineHeight controls the height between lines breakend by \n. Default is 8. 30 | 31 | }; 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Filmote 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/fonts/Font3x5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "Font3x5.h" 5 | 6 | #define USE_LOWER_CASE 7 | 8 | #define FONT3X5_WIDTH 3 9 | #define FONT3X5_HEIGHT 6 10 | 11 | #define CHAR_EXCLAMATION 33 12 | #define CHAR_PERIOD 46 13 | #define CHAR_LETTER_A 65 14 | #define CHAR_LETTER_Z 90 15 | #define CHAR_LETTER_A_LOWER 97 16 | #define CHAR_LETTER_Z_LOWER 122 17 | #define CHAR_NUMBER_0 48 18 | #define CHAR_NUMBER_9 57 19 | 20 | #ifdef USE_LOWER_CASE 21 | #define FONT_EXCLAMATION_INDEX 62 22 | #define FONT_PERIOD_INDEX 63 23 | #define FONT_NUMBER_INDEX 52 24 | #else 25 | #define FONT_EXCLAMATION_INDEX 36 26 | #define FONT_PERIOD_INDEX 37 27 | #define FONT_NUMBER_INDEX 26 28 | #endif 29 | 30 | const uint8_t PROGMEM font_images[] = { 31 | 3, 8, 32 | 33 | // #65 Letter 'A'. 34 | 0x1F, // ░░░▓▓▓▓▓ 35 | 0x05, // ░░░░░▓░▓ 36 | 0x1F, // ░░░▓▓▓▓▓ 37 | 38 | // #66 Letter 'B'. 39 | 0x1F, // ░░░▓▓▓▓▓ 40 | 0x15, // ░░░▓░▓░▓ 41 | 0x1B, // ░░░▓▓░▓▓ 42 | 43 | // #67 Letter 'C'. 44 | 0x1F, // ░░░▓▓▓▓▓ 45 | 0x11, // ░░░▓░░░▓ 46 | 0x11, // ░░░▓░░░▓ 47 | 48 | // #68 Letter 'D'. 49 | 0x1F, // ░░░▓▓▓▓▓ 50 | 0x11, // ░░░▓░░░▓ 51 | 0x0E, // ░░░░▓▓▓░ 52 | 53 | // #69 Letter 'E'. 54 | 0x1F, // ░░░▓▓▓▓▓ 55 | 0x15, // ░░░▓░▓░▓ 56 | 0x11, // ░░░▓░░░▓ 57 | 58 | // #70 Letter 'F'. 59 | 0x1F, // ░░░▓▓▓▓▓ 60 | 0x05, // ░░░░░▓░▓ 61 | 0x01, // ░░░░░░░▓ 62 | 63 | // #71 Letter 'G'. 64 | 0x1F, // ░░░▓▓▓▓▓ 65 | 0x11, // ░░░▓░░░▓ 66 | 0x1D, // ░░░▓▓▓░▓ 67 | 68 | // #72 Letter 'H'. 69 | 0x1F, // ░░░▓▓▓▓▓ 70 | 0x04, // ░░░░░▓░░ 71 | 0x1F, // ░░░▓▓▓▓▓ 72 | 73 | // #73 Letter 'I'. 74 | 0x00, // ░░░░░░░░ 75 | 0x1F, // ░░░▓▓▓▓▓ 76 | 0x00, // ░░░░░░░░ 77 | 78 | // #74 Letter 'J'. 79 | 0x10, // ░░░▓░░░░ 80 | 0x10, // ░░░▓░░░░ 81 | 0x1F, // ░░░▓▓▓▓▓ 82 | 83 | // #75 Letter 'K'. 84 | 0x1F, // ░░░▓▓▓▓▓ 85 | 0x04, // ░░░░░▓░░ 86 | 0x1B, // ░░░▓▓░▓▓ 87 | 88 | // #76 Letter 'L'. 89 | 0x1F, // ░░░▓▓▓▓▓ 90 | 0x10, // ░░░▓░░░░ 91 | 0x10, // ░░░▓░░░░ 92 | 93 | // #77 Letter 'M'. 94 | 0x1F, // ░░░▓▓▓▓▓ 95 | 0x06, // ░░░░░▓▓░ 96 | 0x1F, // ░░░▓▓▓▓▓ 97 | 98 | // #78 Letter 'N'. 99 | 0x1F, // ░░░▓▓▓▓▓ 100 | 0x01, // ░░░░░░░▓ 101 | 0x1F, // ░░░▓▓▓▓▓ 102 | 103 | // #79 Letter 'O'. 104 | 0x1F, // ░░░▓▓▓▓▓ 105 | 0x11, // ░░░▓░░░▓ 106 | 0x1F, // ░░░▓▓▓▓▓ 107 | 108 | // #80 Letter 'P'. 109 | 0x1F, // ░░░▓▓▓▓▓ 110 | 0x05, // ░░░░░▓░▓ 111 | 0x07, // ░░░░░▓▓▓ 112 | 113 | // #81 Letter 'Q'. 114 | 0x1F, // ░░░▓▓▓▓▓ 115 | 0x31, // ░░▓▓░░░▓ 116 | 0x1F, // ░░░▓▓▓▓▓ 117 | 118 | // #82 Letter 'R'. 119 | 0x1F, // ░░░▓▓▓▓▓ 120 | 0x05, // ░░░░░▓░▓ 121 | 0x1B, // ░░░▓▓░▓▓ 122 | 123 | // #83 Letter 'S'. 124 | 0x17, // ░░░▓░▓▓▓ 125 | 0x15, // ░░░▓░▓░▓ 126 | 0x1D, // ░░░▓▓▓░▓ 127 | 128 | // #84 Letter 'T'. 129 | 0x01, // ░░░░░░░▓ 130 | 0x1F, // ░░░▓▓▓▓▓ 131 | 0x01, // ░░░░░░░▓ 132 | 133 | // #85 Letter 'U'. 134 | 0x1F, // ░░░▓▓▓▓▓ 135 | 0x10, // ░░░▓░░░░ 136 | 0x1F, // ░░░▓▓▓▓▓ 137 | 138 | // #86 Letter 'V'. 139 | 0x0F, // ░░░░▓▓▓▓ 140 | 0x10, // ░░░▓░░░░ 141 | 0x0F, // ░░░░▓▓▓▓ 142 | 143 | // #87 Letter 'W'. 144 | 0x1F, // ░░░▓▓▓▓▓ 145 | 0x0C, // ░░░░▓▓░░ 146 | 0x1F, // ░░░▓▓▓▓▓ 147 | 148 | // #88 Letter 'X'. 149 | 0x1B, // ░░░▓▓░▓▓ 150 | 0x04, // ░░░░░▓░░ 151 | 0x1B, // ░░░▓▓░▓▓ 152 | 153 | // #89 Letter 'Y'. 154 | 0x07, // ░░░░░▓▓▓ 155 | 0x1C, // ░░░▓▓▓░░ 156 | 0x07, // ░░░░░▓▓▓ 157 | 158 | // #90 Letter 'Z'. 159 | 0x19, // ░░░▓▓░░▓ 160 | 0x15, // ░░░▓░▓░▓ 161 | 0x13, // ░░░▓░░▓▓ 162 | 163 | #ifdef USE_LOWER_CASE 164 | 165 | // #97 Letter 'a'. 166 | 0x0C, // ░░░░▓▓░░ 167 | 0x12, // ░░░▓░░▓░ 168 | 0x1E, // ░░░▓▓▓▓░ 169 | 170 | // #98 Letter 'b'. 171 | 0x1F, // ░░░▓▓▓▓▓ 172 | 0x12, // ░░░▓░░▓░ 173 | 0x0C, // ░░░░▓▓░░ 174 | 175 | // #99 Letter 'c'. 176 | 0x1E, // ░░░▓▓▓▓░ 177 | 0x12, // ░░░▓░░▓░ 178 | 0x12, // ░░░▓░░▓░ 179 | 180 | // #100 Letter 'd'. 181 | 0x0C, // ░░░░▓▓░░ 182 | 0x12, // ░░░▓░░▓░ 183 | 0x1F, // ░░░▓▓▓▓▓ 184 | 185 | // #101 Letter 'e'. 186 | 0x0C, // ░░░░▓▓░░ 187 | 0x1A, // ░░░▓▓░▓░ 188 | 0x14, // ░░░▓░▓░░ 189 | 190 | // #102 Letter 'f'. 191 | 0x04, // ░░░░░▓░░ 192 | 0x1F, // ░░░▓▓▓▓▓ 193 | 0x05, // ░░░░░▓░▓ 194 | 195 | // #103 Letter 'g'. 196 | 0x2E, // ░░▓░▓▓▓░ 197 | 0x2A, // ░░▓░▓░▓░ 198 | 0x1E, // ░░░▓▓▓▓░ 199 | 200 | // #104 Letter 'h'. 201 | 0x1F, // ░░░▓▓▓▓▓ 202 | 0x02, // ░░░░░░▓░ 203 | 0x1C, // ░░░▓▓▓░░ 204 | 205 | // #105 Letter 'i'. 206 | 0x00, // ░░░░░░░░ 207 | 0x1D, // ░░░▓▓▓░▓ 208 | 0x00, // ░░░░░░░░ 209 | 210 | // #106 Letter 'j'. 211 | 0x20, // ░░▓░░░░░ 212 | 0x1D, // ░░░▓▓▓░▓ 213 | 0x00, // ░░░░░░░░ 214 | 215 | // #107 Letter 'k'. 216 | 0x1F, // ░░░▓▓▓▓▓ 217 | 0x04, // ░░░░░▓░░ 218 | 0x1A, // ░░░▓▓░▓░ 219 | 220 | // #108 Letter 'l'. 221 | 0x01, // ░░░░░░░▓ 222 | 0x1F, // ░░░▓▓▓▓▓ 223 | 0x00, // ░░░░░░░░ 224 | 225 | // #109 Letter 'm'. 226 | 0x1E, // ░░░▓▓▓▓░ 227 | 0x04, // ░░░░░▓░░ 228 | 0x1E, // ░░░▓▓▓▓░ 229 | 230 | // #110 Letter 'n'. 231 | 0x1E, // ░░░▓▓▓▓░ 232 | 0x02, // ░░░░░░▓░ 233 | 0x1E, // ░░░▓▓▓▓░ 234 | 235 | // #111 Letter 'o'. 236 | 0x1E, // ░░░▓▓▓▓░ 237 | 0x12, // ░░░▓░░▓░ 238 | 0x1E, // ░░░▓▓▓▓░ 239 | 240 | // #112 Letter 'p'. 241 | 0x3E, // ░░▓▓▓▓▓░ 242 | 0x12, // ░░░▓░░▓░ 243 | 0x0C, // ░░░░▓▓░░ 244 | 245 | // #113 Letter 'q'. 246 | 0x0C, // ░░░░▓▓░░ 247 | 0x12, // ░░░▓░░▓░ 248 | 0x3E, // ░░▓▓▓▓▓░ 249 | 250 | // #114 Letter 'r'. 251 | 0x1E, // ░░░▓▓▓▓░ 252 | 0x02, // ░░░░░░▓░ 253 | 0x06, // ░░░░░▓▓░ 254 | 255 | // #115 Letter 's'. 256 | 0x14, // ░░░▓░▓░░ 257 | 0x12, // ░░░▓░░▓░ 258 | 0x0A, // ░░░░▓░▓░ 259 | 260 | // #116 Letter 't'. 261 | 0x02, // ░░░░░░▓░ 262 | 0x0F, // ░░░░▓▓▓▓ 263 | 0x12, // ░░░▓░░▓░ 264 | 265 | // #117 Letter 'u'. 266 | 0x1E, // ░░░▓▓▓▓░ 267 | 0x10, // ░░░▓░░░░ 268 | 0x1E, // ░░░▓▓▓▓░ 269 | 270 | // #118 Letter 'v'. 271 | 0x0E, // ░░░░▓▓▓░ 272 | 0x10, // ░░░▓░░░░ 273 | 0x0E, // ░░░░▓▓▓░ 274 | 275 | // #119 Letter 'w'. 276 | 0x1E, // ░░░▓▓▓▓░ 277 | 0x08, // ░░░░▓░░░ 278 | 0x1E, // ░░░▓▓▓▓░ 279 | 280 | // #120 Letter 'x'. 281 | 0x1A, // ░░░▓▓░▓░ 282 | 0x04, // ░░░░░▓░░ 283 | 0x1A, // ░░░▓▓░▓░ 284 | 285 | // #121 Letter 'y'. 286 | 0x2E, // ░░▓░▓▓▓░ 287 | 0x28, // ░░▓░▓░░░ 288 | 0x1E, // ░░░▓▓▓▓░ 289 | 290 | // #122 Letter 'z'. 291 | 0x1A, // ░░░▓▓░▓░ 292 | 0x12, // ░░░▓░░▓░ 293 | 0x16, // ░░░▓░▓▓░ 294 | 295 | #endif 296 | 297 | // #48 Number '0'. 298 | 0x1F, // ░░░▓▓▓▓▓ 299 | 0x11, // ░░░▓░░░▓ 300 | 0x1F, // ░░░▓▓▓▓▓ 301 | 302 | // #49 Number '1'. 303 | 0x00, // ░░░░░░░░ 304 | 0x1F, // ░░░▓▓▓▓▓ 305 | 0x00, // ░░░░░░░░ 306 | 307 | // #50 Number '2'. 308 | 0x1D, // ░░░▓▓▓░▓ 309 | 0x15, // ░░░▓░▓░▓ 310 | 0x17, // ░░░▓░▓▓▓ 311 | 312 | // #51 Number '3'. 313 | 0x11, // ░░░▓░░░▓ 314 | 0x15, // ░░░▓░▓░▓ 315 | 0x1F, // ░░░▓▓▓▓▓ 316 | 317 | // #52 Number '4'. 318 | 0x07, // ░░░░░▓▓▓ 319 | 0x04, // ░░░░░▓░░ 320 | 0x1F, // ░░░▓▓▓▓▓ 321 | 322 | // #53 Number '5'. 323 | 0x17, // ░░░▓░▓▓▓ 324 | 0x15, // ░░░▓░▓░▓ 325 | 0x1D, // ░░░▓▓▓░▓ 326 | 327 | // #54 Number '6'. 328 | 0x1F, // ░░░▓▓▓▓▓ 329 | 0x15, // ░░░▓░▓░▓ 330 | 0x1D, // ░░░▓▓▓░▓ 331 | 332 | // #55 Number '7'. 333 | 0x01, // ░░░░░░░▓ 334 | 0x01, // ░░░░░░░▓ 335 | 0x1F, // ░░░▓▓▓▓▓ 336 | 337 | // #56 Number '8'. 338 | 0x1F, // ░░░▓▓▓▓▓ 339 | 0x15, // ░░░▓░▓░▓ 340 | 0x1F, // ░░░▓▓▓▓▓ 341 | 342 | // #57 Number '9'. 343 | 0x17, // ░░░▓░▓▓▓ 344 | 0x15, // ░░░▓░▓░▓ 345 | 0x1F, // ░░░▓▓▓▓▓ 346 | 347 | // #33 Symbol '!'. 348 | 0x00, // ░░░░░░░░ 349 | 0x17, // ░░░▓░▓▓▓ 350 | 0x00, // ░░░░░░░░ 351 | 352 | // #46 Symbol '.'. 353 | 0x00, // ░░░░░░░░ 354 | 0x10, // ░░░▓░░░░ 355 | 0x00 // ░░░░░░░░ 356 | 357 | }; 358 | 359 | 360 | Font3x5::Font3x5(uint8_t lineSpacing) { 361 | 362 | _lineHeight = lineSpacing; 363 | _letterSpacing = 1; 364 | 365 | _cursorX = _cursorY = _baseX = 0; 366 | _textColor = 1; 367 | 368 | } 369 | 370 | size_t Font3x5::write(uint8_t c) { 371 | 372 | if (c == '\n') { _cursorX = _baseX; _cursorY += _lineHeight; } 373 | else { 374 | 375 | printChar(c, _cursorX, _cursorY); 376 | _cursorX += FONT3X5_WIDTH + _letterSpacing; 377 | 378 | } 379 | 380 | return 1; 381 | 382 | } 383 | 384 | void Font3x5::printChar(const char c, const int8_t x, int8_t y) { 385 | 386 | int8_t idx = -1; 387 | 388 | ++y; 389 | 390 | switch (c) { 391 | 392 | case CHAR_LETTER_A ... CHAR_LETTER_Z: 393 | idx = c - CHAR_LETTER_A; 394 | break; 395 | 396 | #ifdef USE_LOWER_CASE 397 | case CHAR_LETTER_A_LOWER ... CHAR_LETTER_Z_LOWER: 398 | idx = c - CHAR_LETTER_A_LOWER + 26; 399 | break; 400 | #endif 401 | 402 | case CHAR_NUMBER_0 ... CHAR_NUMBER_9: 403 | idx = c - CHAR_NUMBER_0 + FONT_NUMBER_INDEX; 404 | break; 405 | 406 | case CHAR_EXCLAMATION: 407 | idx = FONT_EXCLAMATION_INDEX; 408 | break; 409 | 410 | case CHAR_PERIOD: 411 | idx = FONT_PERIOD_INDEX; 412 | break; 413 | 414 | } 415 | 416 | if (idx > -1) { 417 | 418 | if (_textColor == WHITE) { 419 | Sprites::drawSelfMasked(x, y, font_images, idx); 420 | } 421 | else { 422 | Sprites::drawErase(x, y, font_images, idx); 423 | } 424 | 425 | } 426 | 427 | } 428 | 429 | void Font3x5::setCursor(const int8_t x, const int8_t y) { 430 | _cursorX = _baseX = x; 431 | _cursorY = y; 432 | } 433 | 434 | void Font3x5::setTextColor(const uint8_t color){ 435 | _textColor = color; 436 | } 437 | 438 | void Font3x5::setHeight(const uint8_t color){ 439 | _lineHeight = color; 440 | } 441 | --------------------------------------------------------------------------------