Using frame buffering to solidify tft displayed objects

Status
Not open for further replies.
Thank you!!!! Almost there. Now it compiles but the teensy never comes on after applying power.

Also how many colors can be used for a bitmap using 2bpp? Most of sprites use 5 to 8 colors
 
Last edited:
Do you have a converter you link me to for converting my png to hex 4bpp? The digole page only goes up to 3bpp

It will be painfully tedious to do but I can write them out by hand like your 4bpp example in the FB and clip example. I even figured out how to customize the pallets for each one. But if there is a converter please point it out. I have over 150 character sprites to use. 60 tiles for the tile map and 40 monster bitmaps.

im thinking it might be easier and better to control every thing to use single bitmaps instead of stacked. Definitely saves space as Paul front in color is 360 bytes where he is split up he equals 1150b.
 
Last edited:
Sorry, I don't know what conversion apps that are out there and what data formats that they support. Maybe someone else might?

I also don't know the format that digole uses to hold 3bpp?

The current code (ili9341_t3n) assumes that the number of bits per pixel will evenly divide into 8... So if you are doing 2bpp, it will hold 4 pixels data in 1 byte.

Note the code may handle 3bpp if each byte is stored like: x x 2 2 2 1 1 1
That is where the low order 3 bits is the first pixel, the next 3 bits is pixel two and the last two bits are ignored... It your stored format is like this than:
The generic function writeRectNBPP can handle it if you pass in 3 for number of bits. As you see that for example the 2BPP implementation is:
Code:
void ILI9341_t3n::writeRect2BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, const uint16_t * palette )
{
	// Simply call through our helper
	writeRectNBPP(x, y, w, h,  2, pixels, palette );

}
However I am guessing that this will not be the case, but instead the bits are all packed as a continuous stream of N bits per pixel. In which case the code is not setup to handle this, but someone could build a version that can handle this form of packing of data.
 
That's ok I can do them by hand. It's just tedious and slow and I have a lot. But on the other hand I no longer have to split the bitmaps into separates to stack. I might even be able to use the functions for the tilemap. I made a function for it but haven't tested it just yet. Still have to finish my main character and a few tiles for testing.

I played with it last night and the 4bpp works fine with up to 8 colors so far and can print under 8 colors no problem. For example my main character Sprite uses only 7 colors.
 
Last edited:
Looking at the dig-ole documentation, they have a mode that encodes a color pixel into a single byte (3 bits of red, 3 bits of green, 2 bits of blue), two bytes (5 bits of red, 6 bits of green, 5 bits of blue) or three bytes (6 bits for each color):

  • one byte represent one pixel, so, the color depth is 256, the color format is (MSB-LSB): RRRGGGBB (332)
  • 2 bytes to represent one pixel, the color depth is 64K, the color format is: (MSB-LSB): RRRRRGGG, GGGBBBBB (565)
  • 3 bytes to represent one pixel, but only the 6 MSB used for a color, the color depth is 262K, the color format is: (MSB-LSB): 00RRRRRR, 00GGGGGG, 00BBBBBB (666)

You can download the manual from:
 
Last edited:
Ok here's a good question. My palette exists with 12 colors for the whole game. If I'm using the way Kurt uses in the frameBuffer and clip test, which goes

Ox00,0x11,0x22 and so on. Each integer above zero is a color. Would I use 0x1212 if I want to use the colors 10 and up?
 
Last edited:
0x indicates a HEX number follows. Each of the hex characters represents 4 bits [0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f]. One byte is 8 bits - you show two bytes that would be 16 bits.

If you only need 12 bits that would be: 0x000 [all bits 0/off] to 0xFFF [all bits 1/on] or 0x0000 to 0x0FFF. That is 4096 possible values.

That would give 12 bits - perhaps 4 each for RGB, and not cover the full range of intensity with 65536 values possible.

If you only want twelve unique full value colors you could map that with a lookup in 4 bits with values 0,1,2,3,4,5,6,7,8,9,a,b,c. Then use that number to indicate the desired full scale color value in 565 format in a lookup table of some sort?
 
@DuhJoker- My impression is you are saying that your program only uses 12 unique colors. So saving your bitmaps as 4 bit colors makes sense.

And as defragster mentioned 0x number is a way to specify hex values. This is all some of the standard c/c++ for number constants. https://www.arduino.cc/en/Reference/IntegerConstants

The frame buffer in my version of the library holds 16 bit colors for each pixel using the 5 6 5 format...

But I still wonder if any of this is addressing the issues of screen flash?
 
Im hoping by using the single bitmap method will help with the flashing. I have a couple things to try from the fb and clip test example that I think might work.


I don't know why I didn't think of using a,b,c as palette names. This is how I have it set up now........

Code:
//////// a bitmap
const byte paul_front[] = {14,16,
0x00,0x00,0x33,0x77,0x33,0x00,0x00,
0x00,0x03,0x43,0x33,0x34,0x30,0x00,
0x00,0x37,0x33,0x77,0x33,0x73,0x00,
0x07,0x33,0x66,0x33,0x66,0x33,0x70,
0x03,0x76,0x66,0x66,0x66,0x67,0x30,
0x16,0x36,0x33,0x66,0x33,0x63,0x61,
0x16,0x66,0x62,0x66,0x26,0x66,0x61,
0x01,0x16,0x62,0x66,0x26,0x61,0x10,
0x01,0x11,0x66,0x66,0x66,0x11,0x10,
0x16,0x61,0x16,0x66,0x61,0x16,0x61,
0x16,0x61,0x66,0x66,0x66,0x16,0x61,
0x01,0x11,0x22,0x11,0x44,0x11,0x10,
0x00,0x15,0x11,0x22,0x11,0x51,0x00,
0x00,0x15,0x22,0x11,0x22,0x51,0x00,
0x00,0x02,0x21,0x00,0x12,0x20,0x00,
0x00,0x01,0x11,0x00,0x11,0x10,0x00};

///////now we add the palettes in the void loop
 palette[1] = BLACK;
        palette[2] = BLUE;
               palette[3] = BROWN;
                      palette[4] = DARKGREEN;
                             palette[5] = GREY;
                                    palette[6] = PINK;
                                           palette[7] = RED;
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////                                                
                                           palette[8] = LIGHTBROWN;
                                     palette[9] = GREEN;
                              palette[a]= DARKGREY;
                      palette[b]= LIGHTGREY;
               palette[c]= YELLOW; 
        palette[d]= PURPLE; 
 palette[e]= WHITE;

////////now we call it
if (ButtonDown.fallingEdge()){
   tft.writeRectNBPP(player_x, player_y,16,16,4,paul_frontwalk1,palette);

               player_direction = 2;
            player_y = player_y + 5;}
//            if(checkcolision())player_y++;}
            if(player_y >= 216){
              player_y = 216;}

zero is not named so it should be null or no visible pixels.
 
My assumption is the above will not compile:
Example palette[a] = ...
Unless a is defined somewhere either a #define or a variable. again either simply say 10 or 0xa ...

Also for Palette[0] it will use whatever happened to be in it.... if this is a global variable, than most likely 0 or BLACK.
If this is a fixed palette, you could simply define it like:
const uint16_t palette[] = {0, BLACK, BLUE, BROWN, DARKGREEN, GREY, PINK, RED, ...};
 
Ok fixing the abc stuff was easy I just added int a; int b; int c; etc. what I need is a color called blank that has no color value. I know that 0x0000 is black and 0xFFFF is white, but what is the code for transparent?

Edit:::::
Ok i assume since you have 0 listed before black that i can use 0 as well in my palette as pallette like shown above. And that acts as a transparent pixel? It only really matters with the player and character sprites.

My theory is that since i was calling so many bitmaps at once and in the same place, even though they werent overlapped until they were drawn over the tilemap, was causing some of the problems i was having. The library wasnt really made to do that any way.
 
Last edited:
Ok guys I spent the last couple days converting by hand my player Sprite and tiles into 4bpp bitmaps. 78 tiles total, 10 for the player and 68 tiles. Really saved some space at 15.5kb!!!!! 300+ to go with monsters, main characters and generic characters. Still need items like potions and weapons and armor, inn sign, weapons sign, pots, bed, and a counter for placing shop clerks behind and last but most important, monsters. I'm thinking I can convert all that in under 250kb. I think I might release the first game as the second book. Then go back and do the first book.

Any way. The total amount of sprites in my main sketch file would be enormous. Especially with the tilemap. So I got the idea to make an ino file that just contains bitmaps and tilemaps. I dropped it into the main sketch folder after cleaning up and removing the tiles and bitmaps so it's just functions for the bitmaps in the other ino file.

The problem is that it keeps giving me not declared errors. I've tried adding include "bitmaps.i" and .ino and I just can't figure out how to include my bitmaps.ino file.


Edit::::: got it. I changed it to an .h file using sublime text and then included it into my sketch and folder.
 
Last edited:
Not sure 'int a,b,c;' is the ideal solution. Would work as 0xA, 0xB, 0xC - or just 10,11,12.

Not sure if it was one of your threads but I recently pointed to the on Audio Tutorial sample that includes a .cpp of array data. a .h with an extern definition and the example I:\arduino-1.8.1\hardware\teensy\avr\libraries\Audio\examples\Tutorial\Part_3_02_Fourier_Transform\Part_3_02_Fourier_Transform.ino that includes the header. There is something unique and functional about that setup that works with the Arduino toolchain.

What does the bitmap 'source' input look like? If there a mechanical process you are doing 'by hand' for the conversion where you are able to take the 'source' input by hand to make the desired output, there should be no reason you couldn't write a Teensy sketch to do that for you. I did a variation of that for my Windowed buttons on my Touch screen sample. Compile the sketch with the raw 'source' data if you have it as a data array - process it in a loop emulating what you do by hand - then SPEW a formatted output with Serial.print() as needed? In your case you can put the source data into a 'variable' and process that variable - or perhaps send it in through Seral and .read the data until is 'ends' and manipulate it in memory and then SPEW it out in a block like below - formatted to fit your needs of course.

In this sample I just programmatically create a button output array using an inner and outer loop - what is dumped is text output you can copy from the screen and drop into code (as noted above) as a usable structure that (in my case) looks like this IIRC:

TS_BUTTON mybuttons2[] = { {(char *)"Rot", 5, 5, 50, 50, 65535, 15, TS_FBUTN, 0, 0, 2, 1, 0} ,
{(char *)"P_2", 65, 5, 50, 50, 65535, 992, TS_FBUTN, 0, 0, 2, 2, 0} ,
{(char *)"P_3", 125, 5, 50, 50, 65535, 1007, TS_FBUTN, 0, 0, 2, 3, 0} ,
{(char *)"P_4", 15, 85, 70, 60, 65535, 30720, TS_FBUTN, 0, 0, 2, 4, 0} ,
{(char *)"5", 95, 85, 70, 60, 65535, 30735, TS_FBUTN, 0, 0, 3, 5, 0} ,
{(char *)"6", 175, 85, 70, 60, 65535, 31712, TS_FBUTN, 0, 0, 3, 6, 0} ,
{(char *)"7", 15, 155, 70, 60, 0, 50712, TS_FBUTN, 0, 0, 3, 7, 0} ,
{(char *)"8", 95, 155, 70, 60, 65535, 31727, TS_FBUTN, 0, 0, 3, 8, 0} ,
{(char *)"9", 175, 155, 70, 60, 65535, 31, TS_FBUTN, 0, 0, 3, 9, 0} ,
{(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
};
 
The int a; seems to work and compile. Changing the file into a header file then including it in the main sketch works fine.

I am having a problem though that needs a second pair of eyes or a third. Basically I want to use the 4bpp and the nbpp function wit h the tilemap function. Im trying this.....

Code:
 void GrafxT3::writeRect4BPPtm(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, uint16_t dx, uint16_t dy, uint16_t dw, uint16_t dh, const uint16_t * palette )
{
	dw += dx;
	dh += dy;{
//	int32_t largest = 0;
//	int32_t largesty = 0;
		int32_t drawX = x;
				int32_t drawY = y;

				if (drawX >= dx && drawX < dw && drawY >= dy && drawY < dh){
	// Simply call through our helper
	writeRectNBPP(x, y, w, h,  4, pixels, palette );
        }
    }
}

I used this function to derive it from. I didn't add the byte stuff since it comes from the nbpp function........
Code:
void GrafxT3::drawBitmapTM(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t *bitmap, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, uint16_t color) {
	int32_t i, j, byteWidth = (w + 7) / 8;
	dw += dx;
	dh += dy;
//	int32_t largest = 0;
//	int32_t largesty = 0;
	for (j = 0; j < h; j++) {
		for (i = 0; i < w; i++) {
			if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (B10000000 >> (i % 8))) {
				int32_t drawX = x + i;
				int32_t drawY = y + j;

				if (drawX >= dx && drawX < dw && drawY >= dy && drawY < dh){
					drawPixel(drawX, drawY, color);
				}
			}
		}
	}
}

And here is the actual tilemap functions updated.........
Code:
	uint32_t tilemap_width = pgm_read_byte(tilemap);
	uint32_t tilemap_height = pgm_read_byte(tilemap + 1);
	uint32_t tile_width = pgm_read_byte(tilemap + 2);
	uint32_t tile_height = pgm_read_byte(tilemap + 3);
	tilemap += 4; // now the first tiyleis at tilemap
	uint32_t ddw = dw + dx;
	uint32_t ddh = dh + dy;
	uint32_t maxDdx = (dw - x + tile_width - 1) / tile_width;
	uint32_t maxDdy = (dh - y + tile_height - 1) / tile_height;
	if (tilemap_width < maxDdx){
		maxDdx = tilemap_width;
	}
	if (tilemap_height < maxDdy){
		maxDdy = tilemap_height;
	}
	int32_t startDdx = (-x) / tile_width;
	int32_t startDdy = (-y) / tile_height;
	if (startDdx < 0){
		startDdx = 0;
	}
	if (startDdy < 0){
		startDdy = 0;
	}
	if (flagcollision)numcolision = 0;                                 //Line 735 - clear numcolision - ADD by Summoner123

	for (uint32_t ddy = startDdy; ddy < maxDdy; ddy++){
		for (uint32_t ddx = startDdx; ddx < maxDdx; ddx++){
			int32_t drawX = ddx*tile_width + x + dx;
			int32_t drawY = ddy*tile_height + y + dy;
			uint32_t tile = pgm_read_byte(tilemap + ddy*tilemap_width + ddx);
			if (drawX >= dx && drawY >= dy && drawX <= (ddw - tile_width) && drawY <= (ddh - tile_height)){
				writeRectNBPP(drawX, drawY,tile_width, tile_height, spritesheet[tile],4, const uint16_t * palette );

				if (flagcollision){
					solid[numcolision].x = drawX;                     //Save X coordinate      - ADD by Summoner123
					solid[numcolision].y = drawY;                     //Save Y coordinate      - ADD by Summoner123
					solid[numcolision].spritecol = spritesheet[tile]; //Save Sprite of tile    - ADD by Summoner123
					numcolision++;                                    //Increment numcolision  - ADD by Summoner123
				}
			}
			else{ // we need to draw a partial bitmap
				writeRect4BPPtm(drawX, drawY, tile_width, tile_height, spritesheet[tile], 4, dx, dy, dw, dh, palette);
			}
		}
	}
}

It gives me warnings about the 4bpptm function but errors on the part about the color or palette. Cant figure this one out. I tried changing a few things but nothing is right.........

Code:
Arduino: 1.8.2 (Windows 7), TD: 1.36, Board: "Teensy 3.6, Serial, 180 MHz, Faster, US English"

C:\Users\Duhjoker\Desktop\GameR-Iot_4bpp_splitfile\GameR-Iot_4bpp_splitfile.ino: In function 'void loop()':

C:\Users\Duhjoker\Desktop\GameR-Iot_4bpp_splitfile\GameR-Iot_4bpp_splitfile.ino:166:48: warning: large integer implicitly truncated to unsigned type [-Woverflow]

                                     palette[6] = PINK;

                                                ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp: In member function 'void GrafxT3::drawBitmapTM(int32_t, int32_t, int32_t, int32_t, const uint8_t*, uint32_t, uint32_t, uint32_t, uint32_t, uint16_t)':

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1244:15: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

     if (drawX >= dx && drawX < dw && drawY >= dy && drawY < dh){

               ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1244:30: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

     if (drawX >= dx && drawX < dw && drawY >= dy && drawY < dh){

                              ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1244:44: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

     if (drawX >= dx && drawX < dw && drawY >= dy && drawY < dh){

                                            ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1244:59: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

     if (drawX >= dx && drawX < dw && drawY >= dy && drawY < dh){

                                                           ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp: In member function 'void GrafxT3::drawTilemap(int, int, const uint8_t*, const uint8_t**, uint32_t, uint32_t, uint32_t, uint32_t, uint16_t)':

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1290:14: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

    if (drawX >= dx && drawY >= dy && drawX <= (ddw - tile_width) && drawY <= (ddh - tile_height)){

              ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1290:29: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

    if (drawX >= dx && drawY >= dy && drawX <= (ddw - tile_width) && drawY <= (ddh - tile_height)){

                             ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1290:44: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

    if (drawX >= dx && drawY >= dy && drawX <= (ddw - tile_width) && drawY <= (ddh - tile_height)){

                                            ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1290:75: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

    if (drawX >= dx && drawY >= dy && drawX <= (ddw - tile_width) && drawY <= (ddh - tile_height)){

                                                                           ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1291:78: error: expected primary-expression before 'const'

     writeRectNBPP(drawX, drawY,tile_width, tile_height, spritesheet[tile],4, const uint16_t * palette );

                                                                              ^

C:\Users\Duhjoker\Documents\Arduino\libraries\GameRIot_T3_only\GrafxT3.cpp:1301:98: error: 'palette' was not declared in this scope

     writeRect4BPPtm(drawX, drawY, tile_width, tile_height, spritesheet[tile], 4, dx, dy, dw, dh, palette);

                                                                                                  ^

Error compiling for board Teensy 3.6.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
 
I suggest you start at the top of the errors/warnings and figure them out...

For example if it complains about palette[6] = PINK;
Look where palette is defined as well as PiNK... If for example PINK has a value that takes more than 16 bits...

All of the signed and unsigned errors are because your function:
void GrafxT3::drawBitmapTM(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t *bitmap, uint32_t dx, uint32_t dy, uint32_t dw, uint32_t dh, uint16_t color) {

You have a mix of signed and unsigned (int32_t and uint32_t), so you either need to make them the same or let the compiler know that it is ok by casting one to another...

It errors out on the line: writeRectNBPP(drawX, drawY,tile_width, tile_height, spritesheet[tile],4, const uint16_t * palette );

Why do you have a type specified as part of the usage? const uint16_t * palette?
If palette is defined properly, should simply be: writeRectNBPP(drawX, drawY,tile_width, tile_height, spritesheet[tile],4, palette );

But again don't know where palette is defined? Is it passed in or some global? If some global is it defined in the same file, above where it is used?
if in some external file, do you have a forward reference setup for it, before it is used? Either directly in the file or by header file?

Something like: extern uint16_t palette[];
or maybe: extern const uint16_t palette[];
...
 
Thank you for the second look. After building so many bitmaps in two days my ability to see the int32 stuff was diminished. Not even gonna lie, I spent a half hour running in a circle before I got it all straightened out. All right so the warning for pink is because the color pink defined in the library is a lil too pink so I changed it to a much lighter pink. The define uses 6 characters after the 0x part. The rrr ggg bbb is 255,214,214. Now that I have it compiling I just get the one error for all my bitmap functions.

Code:
byte may be used uninitialized in this function

if (i & 7) byte <<= 1;


Code:
void GrafxT3::drawBitmap1(int16_t x, int16_t y,
const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {

	int16_t i, j, byteWidth = (w + 7) / 8;
	uint16_t byte;

	for (j = 0; j<h; j++) {
		for (i = 0; i<w; i++) {
			if (i & 7) byte <<= 1;
			else      byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
			if (byte & 0x80) drawPixel(x + i, y + j, color);
		}
	}
}

I used the Fb and clip test example for how to set up everything to use the writerectbpp functions. I set the palette in the loop of the sketch the same way.
Code:
 palette[0] = 0;
       palette[1] = BLACK;
             palette[2] = BLUE;
                   palette[3] = BROWN;
                         palette[4] = DARKGREEN;
                              palette[5] = GREY;
                                    palette[6] = PINK;
                                          palette[7] = RED;
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////                                                
                                           palette[8] = LIGHTBROWN;
                                     palette[9] = GREEN;
                               palette[a ]= DARKGREY;
                         palette[b] = LIGHTGREY;
                   palette[c] = YELLOW; 
             palette[d] = PURPLE; 
       palette[e] = WHITE;
 palette[f] = NAVY;

with this included in the includes
Code:
uint16_t palette[16];  // Should probably be 256, but I don't use many colors...
uint16_t pixel_data[2500];

this allows the user to make a custom palette that all the bitmaps will use. Heres the sketch....

Code:
#include <GrafxT3.h>
#include <SPIN.h>
#include "SPI.h"
#include <Bounce.h>
#include "bitmaps.h"
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST 7
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
uint8_t use_fb = 0;
uint8_t use_clip_rect = 0;
uint8_t use_set_origin = 0;
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
GrafxT3 tft = GrafxT3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO, &SPIN);
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
 int player_x = 100;
 int player_y = 70;
 int player_direction = 2;
 int x=-0,y=0;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
 int camerax = 216 ;
 int cameray = 90 ;
 int xmax = 216;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////Pixel Color Includes////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
uint16_t palette[16];  // Should probably be 256, but I don't use many colors...
uint16_t pixel_data[2500];

//Extra integers for color palette
int a; int b; int c; 
int d; int e;int f;

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////Button assignments//////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//////dpad + select buttons
const int buttonUp = 33; //up button
Bounce ButtonUp = Bounce(buttonUp, 10);  // 10 ms debounce
const int buttonDown = 38; //down_button
Bounce ButtonDown = Bounce(buttonDown, 10);  // 10 ms debounce
const int buttonLeft = 35; //left button
Bounce ButtonLeft = Bounce(buttonLeft, 10);  // 10 ms debounce
const int buttonRight = 17; //right button
Bounce ButtonRight = Bounce(buttonRight, 10);  // 10 ms debounce
const int buttonS = 21; //select button
Bounce ButtonS = Bounce(buttonS, 10);  // 10 ms debounce

//////action + start buttons
const int buttonX = 32; // X button up
Bounce ButtonX = Bounce(buttonX, 10);  // 10 ms debounce
const int buttonY = 26; // Y button left
Bounce ButtonY = Bounce(buttonY, 10);  // 10 ms debounce
const int buttonA = 21; // A button right
Bounce ButtonA = Bounce(buttonA, 10);  // 10 ms debounce
const int buttonB = 28; // B buttun down
Bounce ButtonB = Bounce(buttonB, 10);  // 10 ms debounce
const int buttonT = 4; // Start button
Bounce ButtonT = Bounce(buttonT, 10);  // 10 ms debounce

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////Set-up//////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void setup() {
  while (!Serial && (millis() < 4000)) ;
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(BLACK);
  //tft.setFrameRate(60);
  tft.persistence = false;
   pinMode(buttonUp, INPUT_PULLUP);
   pinMode(buttonDown, INPUT_PULLUP);
   pinMode(buttonLeft, INPUT_PULLUP);
   pinMode(buttonRight, INPUT_PULLUP);
   pinMode(buttonS, INPUT_PULLUP);
   pinMode(buttonX, INPUT_PULLUP);
   pinMode(buttonY, INPUT_PULLUP);
   pinMode(buttonA, INPUT_PULLUP);
   pinMode(buttonB, INPUT_PULLUP);
   pinMode(buttonT, INPUT_PULLUP); 
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////Loop////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void loop(void) {
   //updates the GameRIot (the display, the sound, the buttons, everyyhing)
  //returns true when it's time to render a new frame (20 times/second)
//   if(tft.updateAll()){

///////////////////////////////////////////////////////////////////////////////
////////////////////////////////camera controls////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

//        if(player_x > 216 && camerax < 0 && camerax > -216) {player_x = 216;camerax--;}
//value 59 equals player position on right when camera will start to follow 
//value 0 and -52 equals camers boundary positions
//      else  if(player_x < 216 && camerax <  0 && camerax  > -216){player_x = 216;camerax++;}
//value 15 equals player position on left when camera will start to follow
//value 0 and -52 equals camera boundary positions 
//      else  if(player_x > 216 && camerax <= 0 && camerax >= -216)camerax--;
//      else  if(player_x < 216 && camerax <= 0 && camerax >= -216)camerax++;
//      if(player_y > 216 && cameray < 0 && cameray >  -216){player_y = 216;cameray--;}
//value 28 equals player position on right when camera will start to folow
//value 0 and -40 equals camera boundary positions 
//      else  if(player_y < 90 && cameray < 0 && cameray >  -90){player_y = 90;cameray++;}
//value 15 equals player position on left when camera will start to follow
//value 0 and -40 equals camera boundary positions
//     else  if(player_y > 90 && cameray <= 0 && cameray >= -90)cameray--;
//     else  if(player_y < 90 && cameray <= 0 && cameray >= -90)cameray++;

//           if(camerax > 0)camerax= 0;
//     else  if(camerax < -216) camerax = -216;
//value 0 and -52 equals camera boundary positions
//           if(cameray > 0)cameray= 0;
//     else  if(cameray < -90) cameray = -90;
//value 0 and -40 equals camera boundary positions

/////////////////////////////////////////////////////////////////
///////////////////////Tilemap///////////////////////////////////
/////////////////////////////////////////////////////////////////

//if(tft.useFrameBuffer(use_fb));{
//  tft.setFrameRate(60);
//  tft.drawTilemap(x, y, tilemap1, spritesheet1, BLACK);
//   tft.drawTilemap(x, y, tilemap2, spritesheet2, BROWN);
//     tft.drawTilemap(x, y, tilemap3, spritesheet3, LIGHTBROWN);
//      tft.updateScreen();
//       tft.freeFrameBuffer(); //clear the buffer
//}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////Buttons/////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////  
       if (ButtonUp.update());
               if (ButtonDown.update());
                       if (ButtonLeft.update());
                             if (ButtonRight.update());
                                       if (ButtonA.update());
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
                                       ButtonUp.rebounce(10);
                               ButtonDown.rebounce(10);
                       ButtonLeft.rebounce(10);
            ButtonRight.rebounce(10);
     ButtonA.rebounce(10);
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////Palette////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
 palette[0] = 0;
       palette[1] = BLACK;
             palette[2] = BLUE;
                   palette[3] = BROWN;
                         palette[4] = DARKGREEN;
                              palette[5] = GREY;
                                    palette[6] = PINK;
                                          palette[7] = RED;
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////                                                
                                           palette[8] = LIGHTBROWN;
                                     palette[9] = GREEN;
                               palette[a ]= DARKGREY;
                         palette[b] = LIGHTGREY;
                   palette[c] = YELLOW; 
             palette[d] = PURPLE; 
       palette[e] = WHITE;
 palette[f] = NAVY;
///////////////////////////////////////////////////////////////////////////////
//////////////////////////Down/////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
 if (ButtonUp.fallingEdge()){
   tft.writeRectNBPP(player_x, player_y,16,16,4,paul_rearwalk1,palette);

                   player_direction = 1;
             player_y = player_y - 5;}
//             if(checkcolision())player_y--;} 
           if(player_y <= 16){
              player_y = 16;}
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////////Up///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
 if (ButtonDown.fallingEdge()){
   tft.writeRectNBPP(player_x, player_y,16,16,4,paul_frontwalk1,palette);

               player_direction = 2;
            player_y = player_y + 5;}
//            if(checkcolision())player_y++;}
            if(player_y >= 216){
              player_y = 216;}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////Left////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
 if (ButtonLeft.fallingEdge()){
   tft.writeRectNBPP(player_x, player_y,16,16,4,paul_leftwalk,palette);

                player_direction = 3;
             player_x = player_x - 5;}
//             if(checkcolision())player_x--;}  
            if(player_x >= 288){
              player_x = 288;}
//////////////////////////////////////////////////////////////////////////////
////////////////////////////Right////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
if (ButtonRight.fallingEdge()){
  tft.writeRectNBPP(player_x, player_y,16,16,4,paul_rightwalk,palette);
  
               player_direction = 4;
            player_x = player_x + 5;}
//           if(checkcolision())player_x++;}
            if(player_x <= 16){
              player_x = 16;}
///////////////////////////////////////////////////////////////////////////////     
//////////////////////////////PLAYER DIRECTION/////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
if (player_direction == 1){
  tft.writeRectNBPP(player_x, player_y,16,16,4,paul_rear,palette);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
else if (player_direction == 2){
   tft.writeRectNBPP(player_x, player_y,16,16,4,paul_front,palette);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
else if (player_direction == 3){
    tft.writeRectNBPP(player_x, player_y,16,16,4,paul_left,palette);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
else if (player_direction == 4){
     tft.writeRectNBPP(player_x, player_y,16,16,4,paul_right,palette);
        }
     }
//}
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////collision/////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
   bool checkcolision() { // Transformed it into a function 
    uint16_t i;  
     for(i=0; i < tft.numcolision + 1; i++)
   {
    if(tft.collideRectRect(player_x, player_y,16,16,tft.solid[i].x,tft.solid[i].y,16,16))
{
     if(tft.solid[i].spritecol == blank_tile)return false; //Do nothing because it's floor - this line not needed
else if(tft.solid[i].spritecol == rock)return true;
else if(tft.solid[i].spritecol == sand)return false;
else if(tft.solid[i].spritecol == tree)return true;
else if(tft.solid[i].spritecol == grass)return false;
else if(tft.solid[i].spritecol == grasstl)return false;
else if(tft.solid[i].spritecol == grasstr)return false;
else if(tft.solid[i].spritecol == grassbl)return false;
else if(tft.solid[i].spritecol == grassbr)return false;
else if(tft.solid[i].spritecol == rocktl)return true;
else if(tft.solid[i].spritecol == rocktr)return true;
else if(tft.solid[i].spritecol == rockbl)return true;
else if(tft.solid[i].spritecol == rockbr)return true;
else if(tft.solid[i].spritecol == stairsl)return true;
else if(tft.solid[i].spritecol == stairsr)return true;
else if(tft.solid[i].spritecol == cave)return true;
else if(tft.solid[i].spritecol == seitch)return true;
   }
}
return false; // Return false if don't touch anything
}
//////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
 
Code:
	int16_t i, j, byteWidth = (w + 7) / 8;
	uint16_t byte;

	for (j = 0; j<h; j++) {
		for (i = 0; i<w; i++) {
			if (i & 7) byte <<= 1;
			else      byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
			if (byte & 0x80) drawPixel(x + i, y + j, color);
		}
	}
}
The compiler did not do a complete logic analyzes to see that in this case it will typically have a value.

That is you the code sees that first byte is unitialized with the statement: uint16_t byte... Not sure why it is size 16 when byte, but...
Then it sees the statement: if (i & 7) byte <<= 1;
And so far it has not seen anything assigned to byte. It probably won't be an issue as the first iteration i will == 0, so this won't be done and insted it will read in byte...
 
Not sure where these are initialized?

//Extra integers for color palette
int a=0xA; int b=0xB; int c=0xC;
int d=0xD; int e=0xE; int f=0xF;

And I never meant to suggest usage as [a] ... It will be slower to reference than a constant at runtime.
 
Ok when I uploaded the sketch as it was it didn't do very well, the colors were off. So I made the correction defragster posted in the above this post. I got my colors right but it has a problem. It puts the pixels in a sort of ramdom pattern like scattered. You can kind of see what it's supposed be but it looks like the pixels are out of order.

I also tried the tilemap and it prints a pattern on screen of what it's supposed to look like but only one two colors black and grey. They should be brown, light brown and black. Also my camera controls won't scroll the map.

I would love to show a pic but photobucket now wants an exorbitant amount of cash to share photos on an app meant to share photos. TG you tube is free so I'll update with a short video. Sorry its not it the right direction.

https://youtu.be/fm8JvRybagA

Am I supposed to call another function first before calling writeRectnbpp
 
Last edited:
Random pixels - from the items you hand crafted from the source files? Seems like the 565 math is wrong.

Pics - PNG and JPG can be uploaded directly here
 
Ok the tilemap was using black as its last argument and I had forgot to switch the last argument to palette. So when I did that the tilemap showed up in the right color. But I also moved the palette defines above the the call for tilemap. Oddly it's displaying the wrong tiles, but that's not a problem.

So it's just my character sprites that are being errored. The tilemap uses my updated writeRect4BPP() function but I'm using the Nbpp for the player Sprite. I don't see why that would matter though since its helper uses Nbpp.

Edit :::: so weird I just tried to use 4bpp but it does the same thing. But the tilemap shows up the right
 
Last edited:
Ok guys. I know what the problem is just not how to fix it. As an experiment I replaced one of my sprites with a rock Sprite and it prints out the rock just fine. What's happening is I'm using palette[0] =0;. The zero's are causing it to re-arrange the pixels to make up for palette 0.

But I need a color that's invisible so my player sprites will look right sitting on top of the tiles. Else he would have black pixels surrounding him.

Edit::: might help if the bitmaps were actually 16x16. Some are 14x16 others are 12x16. When I changed the tile width and height to 12x16 it worked a lil better. So I need to make sure all sprites are 16x16.
 
Last edited:
So far the these draw functions have no concept of drawing transparent.

It would not be hard to add to the frame buffer code. That is you simply need to make a version of the function that changes the line:
Code:
*pfbPixel++ = palette[((*pixels)>>pixel_shift) & pixel_bit_mask];

To detect some way that you want a transparent bit.

Example if you wish for 0 as the palette index to imply transparent... I would not put it into my version of the library as it would potentially break other users...

But the code could looks something like:
Code:
#define TRANSPARENT_INDEX 0
...   
    uint8_t palette_index = (*pixels)>>pixel_shift) & pixel_bit_mask];
    if (palette_index != TRANSPARENT_INDEX)
        *pfbPixel = palette[palette_index];
    *pfbPixel++;

Lots of other options as well. Above I defined a constant to check the index, could instead be a variable. Where maybe you set the transparent index by new member method, or maybe special value in palette tells you...

As for doing it in the non frame buffer code. Logically you could do it similar, but
Code:
			writedata16_cont(palette[((*pixels)>>pixel_shift) & pixel_bit_mask]);
changing the above to not output things would not work properly as we told the display we are downloading a rectangle of colors, so not outputting something would just screw up the alignment. Instead you would need to change the whole output code to instead output one pixel at a time, which would really slow it down. The code would look very similar to the drawChar function, that breaks up into two main parts. Transparent text (fgcolor == bgcolor), which runs reasonably slow and the opaque text which outputs the whole character as one output rectangle...
 
Quite a while ago I played with bit plane animation on the VGA but using it in EGA mode. The reference text was one of Michael Abrash's books. Would the technique used for that type of animation work for these small displays? The VGA hardware features would need to be done in software of course.

bipe.jpg
In the attached very small photo, you see 4 back ground colors, two fore ground colors and the shadow may be in its own bit plane or a fore ground, but in all 7 colors from a 16 color palette. The colors in the palette are arranged such that you can draw objects in the fore ground without worrying about the background at all.

For a simulation of what the VGA hardware provided, you would need to make some bits as fore ground and some as background, like FFBB, 4 bits, giving 4 fore ground colors and 4 background colors from 16 palette entries. For more colors, just use a more palette entries.

The magic happens when you want to write to the screen. You would just take your backgound bits, add the fore ground bits and get an index to the color in the palette. Write that color and the fore ground and background stay separated and always correct.

And an Abrash article can explain this much better than I can. http://www.phatcode.net/res/224/files/html/ch43/43-01.html

Ron
 
Status
Not open for further replies.
Back
Top