Local transform / pivot point for art

We’re trying to enable use of a “reference point” for art.

TexturePacker calls this the “Pivot Point”; see https://www.codeandweb.com/texturepacker/documentation#settings-sprites for a picture (scroll down just a bit). I’ve also seen this called a “sprite origin” and sometimes even an “anchor point”, although “anchor” sometimes has other connotations.

The way we’ve done this in the past (various non-Haxe engines) is a local-only translation from the object origin to the texture/bitmap top-left, applied after the usual built-up world transform. It allows us to specify that a e.g. character’s sprite should always be placed relative to a point between her feet, or similar, and has been helpful in decoupling code from art.

This additional translation (or possibly full matrix transform) is not inherited by children; children are effectively positioned relative to the pivot point.

This presumably would affect at least Bitmap instances; possibly also Sprite instances.

We’ve thought of various things to accomplish this in OpenFL, and tried a few. We would be very curious to hear if there’s any accepted/idiomatic pattern here (what has worked for others?), or anything we’ve missed.

Here’s what we’re considering and/or have tried:

  • Have all our sprites be a DisplayObjectContainer that contains a leaf Bitmap (without its own children) plus any other children as usual. The leaf transform effectively becomes a full local-only transform.
  • Client code became more complicated because it has to reach into the DOC to grab the Bitmap to do things like change bitmapData.
  • We also saw performance problems on some browsers when targeting HTML5 – can provide details if needed, but speculation was that we might have been running into something that angered the JIT and caused it to drop back to interpreted mode, based on profile data.
  • Subclass Bitmap (and maybe Sprite), and override the various __render methods as well as __getBounds and the various __hitTest methods to deal with a reference point offset (or full local transform). This seems feasible but would love to hear additional opinions; we may be missing a few invariants we need to preserve here. Presumably we could create only the subclassed object type here and pass it back as either Bitmap or Sprite to users; typical inheritance problems notwithstanding, this might work?
  • Patch Bitmap (or even DisplayObject) directly to provide a .pivot or .localtransform with setters/getters and upstream. Has performance / size implications for code that doesn’t care (but maybe can ameliorate some of this with hasLocalTransform flag or similar).
  • Subclass or wrap and override the transform, x, and y setters to mix in a pivot-point offset, but keep the existing bounds/hittest/render methods. Has problems with transform inheritance; the offset has to be “unmixed” transparently in children, and would need to be updated on any graph change (which are admittedly somewhat rare).
  • DisplayObject's members __offset (and __worldOffset, although that’s inherited) seem to be fairly closely related to the functionality we want, but are in service of scrollRect mostly, and may not fit the use-case exactly? They seem to be reset/overwritten fairly frequently.
  • Could scrollRect itself be used this way? Doesn’t appear to be a good fit (more like U/V texture animation), and we’ve observed a bit of buggy behavior with this on certain targets/browsers (9-arg version of CanvasRenderingContext2D's drawImage() seems to be a bit flaky in places).
  • Use Tilesheet's centerPoint functionality, but we don’t get the rest of the object-hierarchy stuff here, and the additional overhead/copy of Graphics.drawTiles might be high? This is also a significant departure from existing code, and seems to want single-sheet sources, which we may not always have.
  • (Why does Graphics have a seemingly unused __bitmap field?)

As a note, we already sometimes need to change hittest and we’ve wrapped some of the uses of Bitmap to do this – for example, we often want bounding-boxes that are slightly larger or smaller than the source images for various reasons. But this certainly isn’t everywhere yet.

Thanks for any thoughts or help here!

Your first bullet point is the “correct” way to do this.

To address the first issue you had with it, make a subclass with appropriate getters and setters:

private var bitmap:Bitmap;

public var bitmapData(get, set):BitmapData;
private inline function get_bitmapData():BitmapData {
    return bitmap.bitmapData;
}
private inline function set_bitmapData(value:BitmapData):BitmapData {
    return bitmap.bitmapData = value;
}

Unfortunately, I can’t help you with HTML5 performance. I’ve barely done anything in HTML5.

1 Like