Tinyfont for Arduboy

I’ve made a 4x4 font for the Arduboy which conforms to small ASCII from 32-127.

It stores 4 letters in 8 bytes and uses masks to draw the correct letter which makes the sprites 224 bytes in size.

Would appreciate some help optimizing the code since i’ve copied the most from the Sprites class.

9 Likes

The sprites code is probably a lot more complex than what you actually need… you probably could have gotten away with something like: (C/psuedocode)

// incoming x, y
c= character_to_draw;
letter = find_start_letter_address(c);
for (i=0; i< character_width; i++ ) {
  pixels = load_program_memory(letter++);
  // for every odd character, shift pixels to get the correct character
  if (c % 2 == 1) {
    pixels >>= 4;
  }
  for (j=0; j<4; j++ ) {
    // shift our pixel over
    pixel = (pixels >> j) & 0x01;
    drawPixel(x, y++, pixel);
  }
  x++;
}

That would be the entire function to render a character.

I was thinking about doing something like this. Can you list a plaintext of what symbols there are? Also, any space to include some more special symbols?

Yeah you are definetely right and i know that. Sadly i have no idea what is going on there and don’t understand the half of it…¯\(ツ)
I’m pretty sure that someone also can remove the masking stuff/sprite and do that by code.

As said i appreciate any help with this. The best in form of a pull request. :grin:

1 Like

Yeah sure! As said it is ascii from 32 to 127 but i can write a list.

Extending is easy, basically we could use the photoshop file and add any characters to it, convert it to bitmap code and replace the current one.

We would need to remove the “unkown char” lock i’ve built in case a char above 127 is requested. The font then needs to tell how many chars it has. Don’t know what the ideal solution here is.

1 Like

It would be nice if this were made into a library containing a class that inherits the Arduino Print class, like the Arduboy2 library does. This way, like Arduboy2, you would be able to use all the Arduino Print features

#include <Tinyfont.h>

Tinyfont tinyfont;

tinyfont.print("hello");
tinyfont.println(F("hello from PROGMEM"));
tinyfont.print(123);
int val = 0x0c1d;
tinyfont.print(val, HEX);
// etc.

If you wanted to make it more portable (possibly at the expense of slightly larger code size), don’t include Arduboy2.h or reference Arduboy2Base directly. Pass a pointer to the screen buffer to the Tinyfont class:

#include <Arduboy2.h>
#include <Tinyfont.h>

// Use Arduboy2Base instead of Arduboy. We don't need Arduboy2's fonts
Arduboy2Base arduboy; 
Tinyfont tinyfont(arduboy.sBuffer);

Or, to access the screen buffer directly, make your class a template, the way @igvina’s ArdBitmap class does.

If you like, I can help with getting your library included in the Arduino Library Manager, if you get to that point.

2 Likes

Okay, it took me some time to understand what is going on and am surprised that i understand it. :open_mouth:
I’ll gonna try it!

Looks good, I’m sure lots of people will find a good use for it.

v1.2

Changelog:

  • Cleaned up unnecessary code - thx @Dreamer3 for the help
  • removed obsolete mask
  • removed lock for chars above 127. Now you can customize the sprite and use custom symbols above 127.
2 Likes

It would be nice if this were made into a library containing a class that inherits the Arduino Print class1, like the Arduboy2 library does.

I don’t understand how to do it without to be independent from Arduboy2s sBuffer. Any hints here?

I gave you hints in my post above.

Your code only needs access to an area in RAM that represents a screen buffer in the format used by the Arduboy2 library. It doesn’t need anything else related to the Arduboy2 class.

I suggested two ways that your class would be able to access the screen buffer without any specific reference to the Arduboy2 library.

Pass a pointer to the screen buffer as a constructor parameter

In Tinyfont.h:

class Tinyfont : public Print {
  public:
    Tinyfont(uint8_t* sBuffer);
    virtual size_t write(uint8_t); // used by the Arduino Print class
  private:
    uint8_t* sBuf;

In Tinyfont.cpp:

Tinyfont::Tinyfont(uint8_t* sBuffer) {
  sBuf = sBuffer;
}  

size_t Tinyfont::write(uint8_t c) {
    // The write() function used by the Print class
}

Your Tinyfont functions can now use:

  sBuf[x];

instead of:

  Arduboy2::sBuffer[x];

Sketches would pass the buffer pointer to the constructor as follows:

#include <Arduboy2.h>
#include <Tinyfont.h>

Arduboy2 arduboy; // or Arduboy2Base arduboy;
Tinyfont tinyfont(arduboy.sBuffer);

Use a template class to provide direct access to the screen buffer

The above method accesses the screen buffer indirectly via a pointer. Since the buffer location is static, the code would be a bit smaller and faster if we could access it directly. This is difficult with Arduino since libraries are compiled independently from the sketch, so can’t be influenced by #defines in the sketch. However, we can use the “trick” of making the library’s class a template. A template isn’t compiled until the point that it’s #included in the sketch. This allows us to pass #define values to it.

As I said, the ArdBitmap library is an example of using a template to allow accessing the screen buffer directly.

3 Likes

If he’s just going to copy the drawPixel code verbatim though he really should just use the existing drawPixel as then the compiled won’t have to link two different drawPixels (unless it’s smart enough to figure out they are both the same?).

1 Like

True. I didn’t look at the code closely enough to notice that drawPixel() was unchanged. In this case, both the screen buffer and a reference to drawPixel() could be passed to the constructor or template.

1 Like

whoop whoop DOUBLE update

Version 2.0

  • Independent to Arduboy, needs pointer to sBuffer in initializer.
  • Replaced drawpixel() with faster drawbyte() method.

Version 3.0

  • now a subclass of Arduino Print. -> pls test, maybe do code review and give feedback. <3

Roadmap

  • Multiple sprites for different fonts which are selectable.

Get it here: Tinyfont on Github

1 Like

Version 3.2

  • Fixed collision of 2 & Z
  • Fixed collision of 5 & S
  • Safety check for linebreak
    Thanks to egency (dunno your forum name here, tag yourself mate!)

Get it here: Tinyfont on Github

6 Likes

Oh I was thinking the default arduboy.print("whatever_you_want_to_print");
tiny font thing…
But yeah, that fonf was pretty cool. Tiny, yet totally understandable.
Pulling that over to the Windows side…

@CDR_Xavier. Obviously English is a second or third language for you but you need to be careful as some most of your comments are coming out rather blunt and bordering on rude.

1 Like

I wasn’t concerned about the word - more the lack of filter between your thoughts and the keyboard.

5 Likes

That font looks great and I am testing it inside the new game I am making. Is there a function to change the size of the text? Like “arduboy.setTextSize(2)”? I know it won’t be tiny anymore if I do that but I like the square shape of these letters. Thanks!

Sorry, there is none.
Though it is simple to modify the printChar() method to do this with an linear interpolation with some math.

2 Likes