Mask from polygon

Hello everyone!

Is it possible to create a mask from polygon(or rect, or circle) so display group will be clipped by this polygon?

As far as I see the only way to create mask is to use mask image from app bundle.

Basically, you’d want something like this:

  • Get the contentBounds of the object

  • Extend it by three pixels in each direction

  • Draw a black rect in this region

  • Set the fill color of your object to black

  • Apply filter.invert to your object to turn it white

  • Put it over the black rect

  • display.captureBounds

  • display.save the capture

At some point schroederapps  mentioned something along these lines. I’m not sure where that’s at right now.

The mask also must be evenly divisible by 4 in both directions. So I would say extend it by 3 or more pixels in all directions to point where it’s divisible by 4.

Rob

Thank you for answers! I tried to implement them in my app; there was some interesting point and caveats, so I’m going to share the story with other developers.

In my game I tried to implement some vessels, fully or partially filled with water. Vessels will have different shape and size, so the only suitable way to draw water that I found – draw it as rect and then clip it by edges of the vessel. That’s how I encountered this problem of polygon clipping. 

You can see my code in this gist – https://gist.github.com/alexdoloz/65e71b6ee6e0309e5432

There are two gotchas:

  • Notice that isFullResolution = true  when I call display.save. Without this everything brokes and bunch of errors printed to console:
    Jan 22 13:18:40  Corona Simulator[36758] <Error>: CGImageCreate: unsupported image width: 2147483648.
    Jan 22 13:18:40  Corona Simulator[36758] <Error>: Unsupported dimensions - 0 x, 0 y, 2147483648 width, 184 height, 8589934592 bytes-per-row

Jan 22 13:18:40  Corona Simulator[36758] <Error>: CGBitmapContextCreateWithData: failed to create delegate.

Jan 22 13:18:40  Corona Simulator[36758] <Error>: CGContextDrawImage: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.

Jan 22 13:18:40  Corona Simulator[36758] <Error>: CGBitmapContextCreateImage: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.

I don’t know why do this errors happen and why this workaround resolved them – looks like this is bug of Corona SDK itself. Also there was topics on forum which discuss the same problem.

Mask image has double size, so to work properly, it has to be scaled by 0.5 or less. 

Also I have a question to StarCrunch – you suggested make object black and then filter.invert it. But why, if it’s possible to just make object white?

Yes, captures are full of surprises.  :slight_smile:

As for making the object black, it’s just a concession to how the colors work. The fill color is a tint, so black really will make an object black, but “white” only leaves its color intact.

I should point out that I’m allowing for the possibility of using images and sprites when you make a mask. If it’s only shapes, then of course they will already be white.

I have made this work in very specific circumastances, but my solution involves saving a new captured PNG and loading it as a mask. If you know the device’s resolution (like if you are making an iPad-only app), then it is possible. But if you are using dynamic scaling to support multiple resolutions then it gets very hard to guarantee that the outputted image meets the “divide by 4” requirement for masks (because the outputted image is set to the device’s native resolution, not in stage coordinates). I’m traveling today so it’ll take some time, but I do have an “automask” module that I was working in last year. It works, but only when you can control the screen resolution. I’ll post it here (fair warning - it won’t be commented and may be horribly formatted).

Basically, you’d want something like this:

  • Get the contentBounds of the object

  • Extend it by three pixels in each direction

  • Draw a black rect in this region

  • Set the fill color of your object to black

  • Apply filter.invert to your object to turn it white

  • Put it over the black rect

  • display.captureBounds

  • display.save the capture

At some point schroederapps  mentioned something along these lines. I’m not sure where that’s at right now.

The mask also must be evenly divisible by 4 in both directions. So I would say extend it by 3 or more pixels in all directions to point where it’s divisible by 4.

Rob

Thank you for answers! I tried to implement them in my app; there was some interesting point and caveats, so I’m going to share the story with other developers.

In my game I tried to implement some vessels, fully or partially filled with water. Vessels will have different shape and size, so the only suitable way to draw water that I found – draw it as rect and then clip it by edges of the vessel. That’s how I encountered this problem of polygon clipping. 

You can see my code in this gist – https://gist.github.com/alexdoloz/65e71b6ee6e0309e5432

There are two gotchas:

  • Notice that isFullResolution = true  when I call display.save. Without this everything brokes and bunch of errors printed to console:
    Jan 22 13:18:40  Corona Simulator[36758] <Error>: CGImageCreate: unsupported image width: 2147483648.
    Jan 22 13:18:40  Corona Simulator[36758] <Error>: Unsupported dimensions - 0 x, 0 y, 2147483648 width, 184 height, 8589934592 bytes-per-row

Jan 22 13:18:40  Corona Simulator[36758] <Error>: CGBitmapContextCreateWithData: failed to create delegate.

Jan 22 13:18:40  Corona Simulator[36758] <Error>: CGContextDrawImage: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.

Jan 22 13:18:40  Corona Simulator[36758] <Error>: CGBitmapContextCreateImage: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.

I don’t know why do this errors happen and why this workaround resolved them – looks like this is bug of Corona SDK itself. Also there was topics on forum which discuss the same problem.

Mask image has double size, so to work properly, it has to be scaled by 0.5 or less. 

Also I have a question to StarCrunch – you suggested make object black and then filter.invert it. But why, if it’s possible to just make object white?

Yes, captures are full of surprises.  :slight_smile:

As for making the object black, it’s just a concession to how the colors work. The fill color is a tint, so black really will make an object black, but “white” only leaves its color intact.

I should point out that I’m allowing for the possibility of using images and sprites when you make a mask. If it’s only shapes, then of course they will already be white.

I have made this work in very specific circumastances, but my solution involves saving a new captured PNG and loading it as a mask. If you know the device’s resolution (like if you are making an iPad-only app), then it is possible. But if you are using dynamic scaling to support multiple resolutions then it gets very hard to guarantee that the outputted image meets the “divide by 4” requirement for masks (because the outputted image is set to the device’s native resolution, not in stage coordinates). I’m traveling today so it’ll take some time, but I do have an “automask” module that I was working in last year. It works, but only when you can control the screen resolution. I’ll post it here (fair warning - it won’t be commented and may be horribly formatted).