Vector based Masking in Corona --> HERE! ;-)

Yup, that’s right.

I’m pretty excited about this … I searched a little … I think I’m the only one to post about how to get this done, so I claim the right to name this comet if that’s the case. :wink:

– note I’m using the crawlspacelib in all my code, so screenWidth/screenHeight and centerX/centerY are based on the device, per the awesome library from Adam. :slight_smile:

Anyway, here you go:

 -- let's make a "mask" group for our vector...  
 local dynamicMask = display.newGroup();  
  
 -- paint a screen sized background white and put it in the group.  
 local thisRect = display.newRect (0,0,screenWidth, screenHeight)  
 dynamicMask:insert(thisRect);  
  
 -- create the vector rectangle that i want for my mask and put it in the group  
 local thisRect = display.newRect (0,0,screenWidth-40, screenHeight-100)  
 dynamicMask:insert(thisRect);  
  
 -- paint the mask black - i want this area to SHOW THROUGH the mask.  
 thisRect:setFillColor(0,0,0);  
  
 -- position it. i want a scroll view in the center of the screen -- so i need   
 -- to position this rectangle in the middle of the screen, leaving some extra   
 -- room up top for a title that doesn't scroll.  
 thisRect.x =centerX;  
 thisRect.y = centerY +20  
  
 -- you could add addition vector objects here to create a complex mask.  
  
 -- now the magic:  
 display.save (dynamicMask, "tmp.jpg", system.TemporaryDirectory)  
  
 -- we don't need no stickin' badges -- get rid of the group.  
 dynamicMask:removeSelf();  
  
 -- but we do need our dynamically created, vector mask! ;-)  
 local mask = graphics.newMask( "tmp.jpg", system.TemporaryDirectory )  
  
 -- ta da!  
 objectToMask:setMask(mask)   

Hope this helps. :wink:

… and am I the first to figure this little tidbit out???
… I think there was maybe some hold up with the official corona UI elements because of issues with putting scrolling area “anywhere”. This definitely solves the problem for me pretty cleanly. I don’t know how well it will translate to other cases, but I’d imagine pretty well?

Here’s how I put the floating scrollView in the middle of the screen with the above mask generation:

 -- take a pic of the screen...  
 local screenCap = display.captureScreen( false )  
 screenCap:setMask(mask)   
  
 -- depending on your setup, insert this masked screencap to the group   
 -- display group for neatness.  

(Though I only care about iOS and came up with the dynamic mask because I didn’t want to worry about iPad vs iPhone 3Gs vs iPhone 4/5… etc – no clue how well this ports to Android as I saw the screencap stuff may not work there?)

Best,
~~Kenn
[import]uid: 13859 topic_id: 11527 reply_id: 311527[/import]

PS, I didn’t know where else to post this. It likely belongs somewhere else and isn’t just for subscribers, unless masking hasn’t made it to the masses yet … i believe it has though. [import]uid: 13859 topic_id: 11527 reply_id: 41838[/import]

Do you have a quickie sample app that shows this off?

Jay
[import]uid: 9440 topic_id: 11527 reply_id: 42000[/import]

… Not in anything in the app store yet … and aside from the code snip above, no, I didn’t actually write anything else to post here. But maybe at some point… :slight_smile: [import]uid: 13859 topic_id: 11527 reply_id: 42036[/import]

I just meant a self-contained example that one could run in the simulator, not a full-blown app. In other words, have you tried what you clipped out above? Or is it theoretical? :slight_smile:

Jay
[import]uid: 9440 topic_id: 11527 reply_id: 42037[/import]

Done:

  
--[[  
TapFingerShot -- a demo of vector based masking with Corona  
By Kenn Wagenheim   
June 23rd, 2011  
  
This paints a blue screen in the front with a red screen behind it.  
Between the screens, there's lots of letters to prove we're masking. ;-)  
  
As you tap the screen, shots are fired through the blue and the red   
and words from behind is shown.  
]]--  
--[[###########################################]]--  
function onTap ( event )  
  
 -- paint our 'bullet hole' black...  
 local thisCirc = display.newCircle (event.x, event.y, 30)  
 dynamicMask:insert(thisCirc);  
 thisCirc:setFillColor(0,0,0);  
  
 -- now the magic:  
 display.save (dynamicMask, "tmp.jpg", system.TemporaryDirectory)  
   
 -- load the last saved image as our mask.  
 local mask = graphics.newMask( "tmp.jpg", system.TemporaryDirectory )  
  
 -- apply or re-apply the mask.  
 thisMainImage:setMask(nil)  
 thisMainImage:setMask(mask)  
  
 -- this next bit is due to some weird bug in corona with masks...  
 -- if you nil a mask, the next maskX and maskY are not right...   
 -- and setting them to 0 is ignored.   
 -- setting them to .01 doesn't move anything   
 -- but it does make sure they're in the right spot.  
 thisMainImage.maskX = .01;--display.contentWidth/4  
 thisMainImage.maskY = .01;--display.contentHeight/4  
 return true  
  
end  
  
--[[###########################################]]--  
-- rather than include an image to mask with this sample, we'll just create one.  
local fakeImg = display.newGroup();  
local thisRect = display.newRect (0,0,display.contentWidth, display.contentHeight)  
thisRect:setFillColor(0,0,150);  
fakeImg:insert(thisRect);  
display.save (fakeImg, "fake.jpg", system.TemporaryDirectory)  
thisRect:removeSelf();  
-- all done  
--[[###########################################]]--  
  
-- load our fake image and set the tap.  
thisMainImage = display.newImage ("fake.jpg", system.TemporaryDirectory, 0, 0);  
thisMainImage:addEventListener ("tap", onTap);  
--[[###########################################]]--  
-- create a red background. when you shoot the blue, red will show through.  
local thisRect = display.newRect (-50, -50, display.contentWidth+100, display.contentHeight+100);  
thisRect:setFillColor(150, 0, 0);  
  
--[[###########################################]]--  
-- but wait, to prove we're actually using a mask and not just putting circles on the screen,  
-- we'll put some text between our image and our background. ;-)  
local x;  
for x=-1, 40 do  
 local thisTxt = display.newText("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", -10, x\*28, "Arial-BoldMT", 30);  
 thisTxt:setTextColor(0,0,0);  
end  
  
-- now move the fake BLUE image to the front.  
thisMainImage:toFront();  
--[[###########################################]]--  
-- let's make a "mask" group for our vector...  
dynamicMask = display.newGroup();  
dynamicMask:toBack();  
local thisRect = display.newRect (-50, -50,display.contentWidth+100, display.contentHeight+100)  
dynamicMask:insert(thisRect);  
thisRect.x =display.contentWidth/2;  
thisRect.y = display.contentHeight/2  
  
-- That's all folks.  
--[[###########################################]]--  
  

I’ll post it in the code snippets thing too. Thanks for the motivation Jay!! :smiley:
[import]uid: 13859 topic_id: 11527 reply_id: 42039[/import]

… code exchange’d.

http://developer.anscamobile.com/code/vector-bitmap-masking-snippet-app

[import]uid: 13859 topic_id: 11527 reply_id: 42040[/import]

… err, right… you can mask a rect object … I didn’t realize that at first. so the above code does extra stuff. i updated the one in the code exchange to be more normal. :wink: [import]uid: 13859 topic_id: 11527 reply_id: 42041[/import]

Great example, thank!

Very neat technique to know about. I can see using that in quite a few ways.

Jay
[import]uid: 9440 topic_id: 11527 reply_id: 42053[/import]