0
votes

I've tried asking this question on LibGDX forums with no luck.

Basically, I've created my own packer that takes multiple spritesheets like these and packs them into something like this. As a result, I can load these packed files as arrays of TextureRegions with their X and Y offset, so that they can be drawn as if they actually had all these unnecessary transparent pixels.

Anyway, here's what I do:

  • Load chosen images as pixmaps;
  • Iterate over their "tiles" (for example, 128x128px parts of the image);
  • Find offsets for each tile (offsets being amount of rows/columns with only transparent pixels);
  • Draw non-transparent part of the tile into a new, small pixmap (continuing the example, 128-offsetLeft-offsetRight, 128-offsetTop-offsetBottom, format is the same as the loaded image);
  • Save each pixmap with some drawing data (offsets) in a container.
  • Repeat for all tiles and images.
  • Find the most efficient way to pack the tiles from containers into a new, bigger pixmap (again, the same format).
  • Save custom description file.
  • Save pixmap as PNG.

Pixmap-related code snippets:

Image loading:

  final Pixmap image = new Pixmap(imageData.getFileHandle());

Drawing image into smaller pieces:

  final Pixmap tile =
        new Pixmap(imageData.getTileWidth() - offsetLeft - offsetRight, imageData.getTileHeight()
              - offsetTop - offsetBottom, image.getFormat());
  tile.drawPixmap(image, -columnIndex * imageData.getTileWidth() - offsetLeft,
        -rowIndex * imageData.getTileHeight() - offsetTop);

Creating new Pixmap for the packed image:

  Pixmap packedImage =
        new Pixmap(packedImageWidth, packedImageHeight, image.getFormat());

Drawing pieces into pixmap:

     packedImage.drawPixmap(frame.getPixmap(), frame.getOriginX(), frame.getOriginY());

Saving packed image:

  final PixmapIO.PNG png = new PixmapIO.PNG();
  png.setCompression(Deflater.NO_COMPRESSION);
  png.setFlipY(false);
  try {
     png.write(chosenDirectory.child(packedFileName + FILE_FORMAT), packedImage);
  } catch (final IOException exception) {
     throw new RuntimeException(exception);
  } 

As a result, colors are somewhat distorted: SfxPacker

(Left: after packing, right: before packing, loaded and rendered as texture.)

Could any step of the packing I do distort the image or is it the saving part? Do I have to look for another solution (pure Java image processing?) or is there a way to preserve colors using LibGDX API?

1
This is not the answer to your question, but why don't you cut original spritesheet into separate sprites and then use libGDX's TexturePacker or GUI for this utility? It can strip whitespace as you want.Alexander Mironov
It's was a lot easier to introduce my own file description format and file reader, that would link certain frames into animation objects, than cutting each image manually and packing it into an atlas which maps images by strings and makes it pretty tedious to link. In the end, it's all about what requires less work, really - and I've already implemented packing logic, which I considered the most time-consuming part.Czyzby
Also, I've just checked out packer's capabilities and it's not exactly what I need. I have to rendered stripped images as if they had their original size - so I don't care if an image is 12x12px right now, I want it to be rendered as, for example, 128x128px. I've checked out the format and it does seem to keep the information of applied offset, but then again - there's the problem of writing a custom loader (which I already have for my format) and easy packing of frames into animations (which would require manual file naming - that's definitely time consuming).Czyzby
You can cut your sheet automatically with appropriate filenames (that is especially easy if frame's width and height are constant). Sprite created by TextureAtlas.html#createSprite (libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/…) is whitespace-aware, so it will draw the image correctly. Then you only have to write your Animation wrapper.Alexander Mironov

1 Answers

3
votes

Since you don't want these sprites to be blended onto the destination Pixmap, but rather replace the pixels there, I think you want to set Pixmap.setBlending(Blending.None); before you start calling drawPixmap on anything.

Sidenote: as Alexander Mironov said, LibGDX's texture packer handles whitespace stripping, and the TextureAtlas class provides you with a Sprite subclass called AtlasSprite that invisibly handles positioning the image as if the whitespace were still part of it. The various createSprite methods actually return an AtlasSprite if whitespace was stripped from the original source.