Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plan to support Trim feature of TexturePacker #48

Open
nsxdavid opened this issue Dec 3, 2011 · 6 comments
Open

Plan to support Trim feature of TexturePacker #48

nsxdavid opened this issue Dec 3, 2011 · 6 comments

Comments

@nsxdavid
Copy link
Contributor

nsxdavid commented Dec 3, 2011

This is a proposed plan to support TexturePacker's trim feature in UIToolkit. The changes would touch a lot of files, so looking for feedback before attempting.

The current code does not support the Trim feature of TexturePacker. This is perhaps one of the more important ones.

Trim finds the smallest rect that encompasses the pixels of an image that are not alpha=0 for each sprite that is packed into the atlas. Many times artists will animate things in sprites and rely on trim to remove this information during packing. This can result in huge savings in texture space.

However, to properly display trimmed sprites from the atlas, the sprites vertices must be moved to account for the discarded part of the image.

To make this work in UIToolkit, I've identified the following changes so far:

The UITextureInfo structure needs to keep track of the original size of the sprite (before it as packed and trimmed). TexturePacker emits this as "sourceSize". Unfortunately the identifier sourceSize was improperly already used in UITextureInfo for the property "sourceSpriteSize" in the control file. But to keep things simple, I suggest:

public struct UITextureInfo
{
    public UIUVRect uvRect;
    public Rect frame;
    public Rect sourceSize;
    public Vector2 originalSize;
}

Original size will need to be parsed (snipet from loadTexturesFromTexturePackerJSON):

        var originalSize = (Hashtable)((Hashtable)item.Value)["sourceSize"];
        var originalW =   int.Parse( originalSize["w"].ToString() );
        var originalH = int.Parse(originalSize["h"].ToString());

        var ti = new UITextureInfo();
        ti.frame = new Rect( frameX, frameY, frameW, frameH );
        ti.uvRect = new UIUVRect( frameX, frameY, frameW, frameH, textureSize );
        ti.sourceSize = new Rect( sourceSizeX, sourceSizeY, sourceSizeW, sourceSizeH );
        ti.originalSize = new Vector2(originalW, originalH);

Optimally, an optimization would be to also maintain a bool which tells us if the image was trimmed. This is the "trimmed" property in the control file.

To use this information the code will have to be refactored to understand that when the UVs are changed the vertices might have to also change.

The following code is an example of how this logic would work for a centerized sprite. This is the code I use for camera facing sprites in 3D space (my own custom extension to UIToolkit):

void  AssignUV(UITextureInfo textureInfo)   // EXAMPLE ONLY
{

    float w = textureInfo.originalSize.x;
    float h = textureInfo.originalSize.y;

    float hw = w / 2.0f;
    float hh = h / 2.0f;

    float left   = (textureInfo.sourceSize.xMin - hw);
    float right  = (textureInfo.sourceSize.xMax - hw);
    float top    = (textureInfo.sourceSize.yMax - hh);
    float bottom = (textureInfo.sourceSize.yMin - hh);

    Vector3[] vertices = new Vector3[4];
    vertices[0] = new Vector3(left, top, 0);
    vertices[1] = new Vector3(left, bottom, 0);
    vertices[2] = new Vector3(right, bottom, 0);
    vertices[3] = new Vector3(right, top, 0);

    OurMesh.vertices = vertices;

    Vector2[] UVs = new Vector2[4];

    UVs[0] = textureInfo.uvRect.lowerLeftUV + Vector2.up * textureInfo.uvRect.uvDimensions.y; // Upper-left
    UVs[1] = textureInfo.uvRect.lowerLeftUV; // Lower-left
    UVs[2] = textureInfo.uvRect.lowerLeftUV + Vector2.right * textureInfo.uvRect.uvDimensions.x; // Lower-right
    UVs[3] = textureInfo.uvRect.lowerLeftUV + textureInfo.uvRect.uvDimensions; // Upper-right

    OurMesh.uv = UVs;

}

This basic strategy would be adapted in UIToolkit.

The difficulty in this change is that UIToolkit currently makes the assumption that UV changes are very distinct of Vertex changes. And in many places where it will need to keep track of UV information it keeps and passes the UIUVRect of the UITextureInfo struct. For example, the Sprite Animaiton system has an array of UIUVRects for the animation frames. This will have to be refactored to an array of UITextureInfo structs. Similarly with many other places in the code.

It is the passing/tracking ofUI UVRects instead of UITextureInfo throughout the code that makes this refactor tricky.

I've not looked into how clipping might be impacted by this as I don't quite yet have my head around the clipping implementation.

There are other implications, as the actual "size" of the sprite is represented by something other than how the verts are positioned on the screen. This might impact touchable areas as well.

It is worth noting that support for the rotated property (another key feature of TexturePacker) can easily be part of this refactor. In fact to support rotated, moving from passing/storing UITextureInfo's instead of UIUVRects is pretty much required anyway.

@nsxdavid
Copy link
Contributor Author

nsxdavid commented Dec 3, 2011

Plan now is to make a separate branch for Trimming and Rotation support.

The first step can be done incrementally. Here's what I suggest:

We expand the UITextureInfo structure to have members for all of the TexturePacker properties.

We parse in the missing ones and store them in the struct.

We do a global rename refactor on the one property that has an incorrect name (relative to TP).

These changes would no impact on the behavior of UIToolkit but prepare it for what comes next. Furthermore, it makes this extra information available for any custom extensions that are leveraging UIToolkit's TexturePacker parsing mechanism even before we finish the big refactor.

This small change can be easily vetted and then merged back into mainline with little to no risk.

@prime31
Copy link
Contributor

prime31 commented Dec 4, 2011

Those changes all sound good to me and won't have any effect on anything else.

To add to this, it might be a good idea to separate out a bounds property (a Rect). Bounds would be the actual size of the object and have nothing to do with where the verts are. It could be the base size for touch frames as well as the property used for layout in containers/positioning.

@nsxdavid
Copy link
Contributor Author

nsxdavid commented Dec 4, 2011

A rect that defines the world-space bounds of the sprite (regardless of how the verts are layed out in worldspace) is a good idea, in the face of trimming. I think this would most logically be owned by UISprite, yes?

@prime31
Copy link
Contributor

prime31 commented Dec 4, 2011

Yeah, UISprite should probably get it. UIObject doesn't yet have any view associated with it.

@nsxdavid
Copy link
Contributor Author

nsxdavid commented Dec 4, 2011

I pushed up a trimsupport branch that has the first step in these changes (the expansion of the struct and parsing of the additional properties).

After the Positioning pull request is merged into master, I'll make a pull request for this.

@rischkong
Copy link

hi all, is there an update for the trimming/cropping issue in UIToolkit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants