Tired of having to do these conversions myself, I quickly decided to code a dedicated tool to do the job for me: Image Transcoder. The arrival of a new team at the helm of the Gamebuino ship made me want to upgrade my tool and give it a coat of varnish.
First of all, I suggest you to download the assets, i.e. the graphic resources of the project, which we will convert into C++ code. This will save you from having to redraw everything, unless you want to discover Piskel or another graphic tool of your choice…
Once downloaded, store them in a folder named artwork
, at the root of your project:
You will notice that the palette defined in the palette-1x16.png
file has exactly 16 pixels, although the last one is completely transparent. This was not mandatory, the transcoder can handle an incomplete palette. In general, I encourage you to make the most of the 16 colors allowed with the indexed color display modes.
Transparent pixels in an incomplete color palette (with less than 16 colors) will be assigned the color code with index 0x0
by default. If this color is itself transparent then it will be assigned the 0x0000
code of black.
Using the transcoder is very simple. I guess a video demo will be enough. For example, let’s convert our tileset for use with an indexed color display mode:
It’s quick and easy. In a flash, the conversions are done!
In the case of indexed color display modes, if you do not provide a palette file, the Gamebuino palette will be applied by default:
Therefore, if the image to be converted does not contain any of these colors, all pixels in the image will be assigned the default index color 0x0
(i.e. black).
Now it’s your turn. Convert the project assets for RGB565 and indexed color display modes, setting the transcoder correctly:
We will split the asset codes into two separate files:
rgb565.h
for RGB565 display modeindexed.h
for indexed color display modesI suggest you download them:
We will then place these files in a directory named assets
to structure our project and not to put everything in bulk at the root. The disadvantage with the Arduino IDE is that by isolating the asset files in a specific folder instead of putting them in the root of the project, it is as if the editor does not see them. You’ll see that you can’t open the assets
folder. To get around this silly quirk, just create an empty assets.ino
file in the assets
folder:
This way, you can make it look like you’re opening another sketch next to the main sketch:
This is an easy way to access the rgb565.h
or indexed.h
files from the Arduino IDE code editor when you need to make changes to them.
But the main my-stunning-game
sketch is the one from which you should always start compiling and uploading to your Gamebuino. It is the starting point for the whole compilation process. The idea is to include the right asset file depending on the display mode you have chosen and defined in the config-gamebuino.h
file.
DISPLAY_MODE_RGB565
my-stunning-game.ino
#include <Gamebuino-Meta.h>
#include "assets/rgb565.h"
void setup() {
gb.begin();
}
void loop() {
gb.waitForUpdate();
}
DISPLAY_MODE_INDEX or DISPLAY_MODE_INDEX_HALFRES
my-stunning-game.ino
#include <Gamebuino-Meta.h>
#include "assets/indexed.h"
void setup() {
gb.begin();
}
void loop() {
gb.waitForUpdate();
}
Converted and ready-to-use assets for C++
Now let’s see the details of these two asset files. The SPRITE_DATA
and TILESET_DATA
arrays characterizing the spritesheet and the tileset are gathered here. To avoid multiple inclusions, you should also remember to add the #pragma once
precompilation directive at the beginning of each of these two files:
assets/rgb565.h
#pragma once
const uint16_t SPRITE_DATA[] = {
// metadata
8, // frame width
8, // frame height
4, // frames
4, // frame loop
0xf81f, // transparent color
0, // 16-bits color mode
// colormap
// frame 1/4
0xf81f, 0xf81f, 0x632c, 0xad55, 0xad55, 0xad55, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0xff36, 0xff36, 0xff36, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0x0000, 0xff36, 0x0000, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0xff36, 0xff36, 0xff36, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xff36, 0xb4df, 0xb4df, 0xb4df, 0xff36, 0xf81f,
0xf81f, 0xf81f, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0x6217, 0xf81f, 0xf81f, 0x6217, 0xf81f, 0xf81f,
// frame 2/4
0xf81f, 0xf81f, 0x632c, 0xad55, 0xad55, 0xad55, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0xff36, 0xff36, 0xff36, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0x0000, 0xff36, 0x0000, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0xff36, 0xff36, 0xff36, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0xff36, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0x7afa, 0xff36,
0xf81f, 0xf81f, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xf81f, 0x7afa, 0x6217, 0xf81f, 0xf81f, 0xf81f,
// frame 3/4
0xf81f, 0xf81f, 0x632c, 0xad55, 0xad55, 0xad55, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0xff36, 0xff36, 0xff36, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0x0000, 0xff36, 0x0000, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0xff36, 0xff36, 0xff36, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xff36, 0xb4df, 0xb4df, 0xb4df, 0xff36, 0xf81f,
0xf81f, 0xf81f, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0x6217, 0xf81f, 0xf81f, 0x6217, 0xf81f, 0xf81f,
// frame 4/4
0xf81f, 0xf81f, 0x632c, 0xad55, 0xad55, 0xad55, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0xff36, 0xff36, 0xff36, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0x0000, 0xff36, 0x0000, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0xee2f, 0xff36, 0xff36, 0xff36, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0x7afa, 0x7afa, 0xff36, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0xf81f, 0x7afa, 0xb4df, 0xb4df, 0xb4df, 0xf81f, 0xf81f,
0xf81f, 0x6217, 0xf81f, 0xf81f, 0xf81f, 0xf81f, 0x7afa, 0xf81f
};
const uint16_t TILESET_DATA[] = {
// metadata
16, // frame width
8, // frame height
4, // frames
0, // frame loop
0xf81f, // transparent color
0, // 16-bits color mode
// colormap
// frame 1/4
0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x1926, 0x0000,
0x1926, 0x1926, 0x10e4, 0x1926, 0x10e4, 0x1926, 0x10e4, 0x1926, 0x10e4, 0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862,
0x1926, 0x10e4, 0x1926, 0x10e4, 0x1926, 0x10e4, 0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862,
0x1926, 0x1926, 0x10e4, 0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862,
0x1926, 0x10e4, 0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862,
0x1926, 0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862,
0x1926, 0x10e4, 0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862, 0x0862,
0x1926, 0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862,
// frame 2/4
0x4228, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c, 0x632c,
0xad55, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228,
0x632c, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228, 0x4228,
0x0000, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186,
0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000,
0x0000, 0x18c3, 0x0000, 0x3186, 0x0000, 0x18c3, 0x0000, 0x3186, 0x0000, 0x18c3, 0x0000, 0x3186, 0x0000, 0x18c3, 0x0000, 0x3186,
0x3186, 0x0000, 0x3186, 0x0000, 0x3186, 0x0000, 0x3186, 0x0000, 0x3186, 0x0000, 0x3186, 0x0000, 0x3186, 0x0000, 0x3186, 0x0000,
0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3,
// frame 3/4
0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862, 0x0862,
0x1926, 0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862, 0x10e4, 0x0862,
0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862, 0x0862,
0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862, 0x10e4, 0x0862,
0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862, 0x10e4, 0x0862, 0x0862,
0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862, 0x10e4, 0x0862, 0x10e4, 0x0862, 0x10e4, 0x0862,
0x1926, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x10e4, 0x0862, 0x10e4, 0x0862, 0x10e4, 0x0862, 0x10e4, 0x0862, 0x10e4, 0x0862, 0x0862,
0x0000, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0862, 0x0000,
// frame 4/4
0x0000, 0x632c, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x3186, 0x18c3,
0x632c, 0x3186, 0x18c3, 0x3186, 0x18c3, 0x3186, 0x18c3, 0x3186, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x0000,
0x3186, 0x18c3, 0x3186, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x0000,
0x3186, 0x3186, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x0000,
0x3186, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x0000, 0x0000,
0x3186, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000,
0x3186, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x18c3, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x18c3
};
In the case of the assets file for the indexed color display modes, the definition of the color palette, which is common to SPRITE_DATA
and TILESET_DATA
, has also been added. The header file <Gamebuino-Meta.h>
must also be included since it contains the declaration of the Color
class that is used for the palette definition :
assets/indexed.h
#pragma once
#include <Gamebuino-Meta.h>
const Color PALETTE[] = {
(Color) 0x0000, // 0x0
(Color) 0x18c3, // 0x1
(Color) 0x3186, // 0x2
(Color) 0x4228, // 0x3
(Color) 0x632c, // 0x4
(Color) 0xad55, // 0x5
(Color) 0xee2f, // 0x6
(Color) 0xff36, // 0x7
(Color) 0x0862, // 0x8
(Color) 0x10e4, // 0x9
(Color) 0x1926, // 0xa
(Color) 0x6217, // 0xb
(Color) 0x7afa, // 0xc
(Color) 0xb4df, // 0xd
(Color) 0xf81f, // 0xe
(Color) 0x0000 // 0xf
};
const uint8_t SPRITE_DATA[] = {
// metadata
8, // frame width
8, // frame height
0x04, // frames (lower byte)
0x00, // frames (upper byte)
4, // frame loop
0xe, // transparent color
1, // indexed color mode
// colormap
// frame 1/4
0xee, 0x45, 0x55, 0xee,
0xee, 0x67, 0x77, 0xee,
0xee, 0x60, 0x70, 0xee,
0xee, 0x67, 0x77, 0xee,
0xee, 0xcd, 0xdd, 0xee,
0xee, 0x7d, 0xdd, 0x7e,
0xee, 0xcd, 0xdd, 0xee,
0xee, 0xbe, 0xeb, 0xee,
// frame 2/4
0xee, 0x45, 0x55, 0xee,
0xee, 0x67, 0x77, 0xee,
0xee, 0x60, 0x70, 0xee,
0xee, 0x67, 0x77, 0xee,
0xee, 0xcd, 0xdd, 0xee,
0xe7, 0xcd, 0xdd, 0xc7,
0xee, 0xcd, 0xdd, 0xee,
0xee, 0xec, 0xbe, 0xee,
// frame 3/4
0xee, 0x45, 0x55, 0xee,
0xee, 0x67, 0x77, 0xee,
0xee, 0x60, 0x70, 0xee,
0xee, 0x67, 0x77, 0xee,
0xee, 0xcd, 0xdd, 0xee,
0xee, 0x7d, 0xdd, 0x7e,
0xee, 0xcd, 0xdd, 0xee,
0xee, 0xbe, 0xeb, 0xee,
// frame 4/4
0xee, 0x45, 0x55, 0xee,
0xee, 0x67, 0x77, 0xee,
0xee, 0x60, 0x70, 0xee,
0xee, 0x67, 0x77, 0xee,
0xee, 0xcd, 0xdd, 0xee,
0xee, 0xcc, 0x7d, 0xee,
0xee, 0xcd, 0xdd, 0xee,
0xeb, 0xee, 0xee, 0xce
};
const uint8_t TILESET_DATA[] = {
// metadata
16, // frame width
8, // frame height
0x04, // frames (lower byte)
0x00, // frames (upper byte)
0, // frame loop
0xe, // transparent color
1, // indexed color mode
// colormap
// frame 1/4
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0,
0xaa, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x98,
0xa9, 0xa9, 0xa9, 0xa9, 0x99, 0x99, 0x99, 0x98,
0xaa, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98,
0xa9, 0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98,
0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98,
0xa9, 0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88,
0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98,
// frame 2/4
0x34, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
0x53, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0x43, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0x02, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
// frame 3/4
0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88,
0xaa, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x98,
0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x88,
0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x98,
0xa9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x89, 0x88,
0xa9, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98,
0xa9, 0x99, 0x99, 0x89, 0x89, 0x89, 0x89, 0x88,
0x08, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x80,
// frame 4/4
0x04, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21,
0x42, 0x12, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
0x21, 0x21, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10,
0x22, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x10,
0x21, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00,
0x21, 0x11, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10,
0x21, 0x11, 0x11, 0x01, 0x01, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
};
Now everything is ready to display our beautiful assets on the screen. There was a lot of things to say and do before we started programming. But I hope that everything is now clearer in your mind about how to prepare your assets before bringing them to life with code. See you in the next chapter for the rest.