Arduboy FX library

Thanks.

I tried a ‘pip update pillow’ but it says I am already at the latest version.

I will continue googling answers … someone must have found the same problem.

Did you do that from the normal terminal or the version in the arduino tools folder?

If the normal installed version is up to date. Can you locate it’s folder? Maybe you can copy the pillow folder manually into the arduino tools folder.

Try copying the PIL folder from /usr/local/lib/python3.10/site-packages to \sketchbook\tools

I ended up resolving my immediate issue by

  • unistalling all the various Python versions I had on the machine (they breed like rabbits)
  • reinstalling Python3.10.8 with Brew
  • copying the PIL directory into the same folder as you suggested.

This didn’t work the first time. I repeated the process a couple of times with variations - including using pyenv - then trashed it all again and did a basic Brew install. Then for some reason it all worked.

I would have preferred not to have to copy the files into the script directory. It feels like my configuration is missing something as I have never needed to do that previously.

I hate when something starts working but I cannot pinpoint what made it work. Thanks @Mr.Blinky !

2 Likes

Sounds like the same hell I went through before quitting :frowning:

PS - messing about with pyenv (copy&paste from stack overflow) seemed to do more harm than good for me at least…

2 Likes

That’s what I concluded about pyenv too. I guess if you are developing with different versions of Python then it might make sense to persevere with it.

I don’t use Python regularly - in fact I am not a fan of it generally - and really do not know what I am doing when it comes to setting up an environment.

I am just happy its working again. Now I can continue with my PoP remake!

2 Likes

Interesting issue … I am trying to build an FX image, and one of my filenames is 184_Sword_Step_04_Extra1.png.

Building FX data using /Users/filmote/projects/PrinceOfPersia/fxdata/fxdata.txt
Traceback (most recent call last):
  File "/Users/filmote/projects/PrinceOfPersia/fxdata/./Arduboy-Python-Utilities-master/fxdata-build.py", line 224, in <module>
    elif t == 5: bytes += imageData(part)
  File "/Users/filmote/projects/PrinceOfPersia/fxdata/./Arduboy-Python-Utilities-master/fxdata-build.py", line 52, in imageData
    spriteWidth = int(elements[i].split("x")[0])
ValueError: invalid literal for int() with base 10: 'E'
Simons-iMac2-2:fxdata filmote$ 

I have renamed the file to 184_Sword_Step_04_Xtra1.png and it now works. Looks like the parsing for frame sizes within the image name is getting a little confused.

thanks for the report, I’ll look into it

1 Like

fixed now. updated the Arduino plugin and Python utilities

2 Likes

So I ran into another interesting problem when using fxdata-build utility.

I am using tiles to create my scenery and are assuming that all tiles will be a constant size 12px x 31px and a constant size. This allows me to use the code below:

FX::drawBitmap(x, y, Images::Tile_00 + (tile * 70), 0, dbmMasked);

However some of my tiles are complete and have no transparent sections. The utility is ‘clever’ in that it looks for a transparent colour in the RGBA colour codes for each pixel in the image.

  transparency = False
  for i in pixels:
   if i[3] < 255:
    transparency = True
    break

So, unfortunately for me, this results in some of my tiles being encoded with the masking (transparency) and some not. Not ideal for my use case.

I am wondering if we could add an optional parameter that forces the conversion to a masked image even if their is no transparency in it. For example :

image_t Tile_Dungeon_00 = "../images/tiles/tile_dungeon_00.png" 
image_t Tile_Dungeon_01 = "../images/tiles/tile_dungeon_01.png"
image_t Tile_Dungeon_02 = "../images/tiles/tile_dungeon_02.png" dbmMasked
image_t Tile_Dungeon_03 = "../images/tiles/tile_dungeon_03.png"
...

Possible?


As my tiles are all in a single directory, I fudged it like this:

#check for transparency
transparency = False
if '/tiles/' in filename:
  transparency = True
for i in pixels:
  if i[3] < 255:
    transparency = True
    break

Don’t you mean:

FX::drawBitmap(x, y, Images::Tile_00, tile * 70, dbmMasked);

?

Are you using tiles as individual images?
(Yes I should have read your complete post first before I start typing)

You can (should) put the tiles in a single sprite/tile sheet. like:

tilesheet-without-border_16x16.png

tilesheet-without-border_16x16.png

or when sprite/tile sheet is surrounded by a border:

tilesheet-with-1-pixel-border16x16_1

tilesheet-with-1-pixel-border_16x16_1.png

_16x16 is the individual tile width and height and may be any size.

The 1 at the end of 16x16_1 tells the tool the tiles/sprites are surrounded by a border of 1 pixels. The number may be changed to any value to for a wider border (a wider border allows you to add small notes to the tiles).

The order of the tiles will be from left to right and top to bottom. Making the top left tile tile 0. The rows and columns of tiles in the tilesheet do not have to be the same number of tiles. If a sprite/tile sheet would have 21 tiles it could be organised as (1 * 21), (7 * 3), (3 * 7) or (21 * 1) rows * columns

FX::drawBitmap(x, y, Images::Tile_00 + (tile * 70), 0, dbmMasked);

FX::drawBitmap(x, y, Images::Tile_00, tile * 70, dbmMasked);

Aren’t they the same thing?

I haven’t used tilesheets with the FX library before, but does it create one single image with all the images indexed within it (like the Sprites library) or does it create a bunch of individual images?

I guess I could make a tilesheet but I didn’t really see the point as I was working with all the individual images akready. But I guess if it then will check for transparencies in any of the images (well all the images embedded in the tilesheet), then this will work for my use case.

I wonder if there are other instances where you would want to enure that the encoding is done one way or another?

No. with the first you have seperate images each having an uint16_t width and height.
with the seconds you only have a single uint16_t width and height.

If you would have 40 tiles the 2nd saves 156 bytes ((40-1)*4) of image data (and probably more because of simplified math / better optimisation in the calling function)

Exactly

So … a different question.

I have a function that is reading from FX memory using FX::seek() and then a bunch of FX::readPendingUInt8(). Depending on what it reads, it may call a second function that does its own seeking and reading. I understand that I need to FX::readEnd() in the first routine otherwise the second one seems to not seek correctly.

Is there anyway I can save the cursor position from the first function and reposition it after the call to the sub-routine?

For example:

void funcA() {

  FX::seek(posA);

  for (uint8_t i= 0; i < 20; i++) {
 
   uint8_t itemType = FX::readPendingUInt8();

    switch (itemType) {

      case 0 ...
      case 1 ...
      case 2:
        {
          uint24_t curPos = FX::getCursorPos();  << Is this possible??
          FX::readEnd();
          funcB();
          FX::seek(curPos);
        }
       break;

    }
  
}  

  FX::readEnd();

}

void funcB() {

  FX::seek(elsewhere);
  uint8_t helpMe = FX::readPendingUInt8();
  FX::readEnd();

}

Alternatively, the handling could be performed in the sub routine …

void funcA() {

  FX::seek(posA);

  for (uint8_t i= 0; i < 20; i++) {
 
   uint8_t itemType = FX::readPendingUInt8();

    switch (itemType) {

      case 0 ...
      case 1 ...
      case 2:
        funcB();
       break;

    }
  
}  

  FX::readEnd();

}

void funcB() {

  uint24_t cursorPos = FX::getCursorPos();  << Is this possible??

  FX::seek(elsewhere);
  uint8_t helpMe = FX::readPendingUInt8();
  FX::readEnd();

  FX::seek(cursorPos);

}

But this would require funcB to know its supposed to do the trickery. If the call to getCursorPos() returned a 0 if no reading is taking place or the current cursor position if it is then you could simply apply a condition to the final seek().


void funcB() {

  uint24_t cursorPos = FX::getCursorPos();  

  FX::seek(elsewhere);
  uint8_t helpMe = FX::readPendingUInt8();
  FX::readEnd();

  if (cursorPos != 0) {
    FX::seek(cursorPos);
  }

}

Unfortunately not. there is no way of reading out the current FX memory position other then tracking it your self.

Bummer.

Oh well, it was a great idea while it lasted!

if the number of bytes is small you could consider reading them reading into a temporary byte array and ‘parse’ them from there.

Yes … but unfortunately I do not have much memory for this sort of thing. Maybe I could read it into the screen buffer and then take it from there?

1 Like

You can as long as you do not draw in the area you use as a temporary buffer.

1 Like

I tend to do all my player and enemy movement at the start of each loop and render everything at the end, so it could work.

1 Like

You probably know this, but I’ll just leave it here anyway:

struct RelevantData { /*...*/ };

RelevantData & data = *reinterpret_cast<RelevantData *>(arduboy.getBuffer());
1 Like