diff --git a/librtt/Display/Rtt_BitmapMask.cpp b/librtt/Display/Rtt_BitmapMask.cpp index 14dea21df..939d846f7 100644 --- a/librtt/Display/Rtt_BitmapMask.cpp +++ b/librtt/Display/Rtt_BitmapMask.cpp @@ -23,41 +23,50 @@ namespace Rtt // ---------------------------------------------------------------------------- BitmapMask* -BitmapMask::Create( Runtime& runtime, const FilePath& maskData ) +BitmapMask::Create( Runtime& runtime, const FilePath& maskData, bool onlyForHitTests ) { - BitmapPaint *paint = BitmapPaint::NewBitmap( runtime, maskData, PlatformBitmap::kIsBitsFullResolution, true ); + BitmapPaint *paint = BitmapPaint::NewBitmap( runtime, maskData, PlatformBitmap::kIsBitsFullResolution, true, onlyForHitTests ); BitmapMask *result = NULL; - if ( Rtt_VERIFY( paint ) ) + if ( Rtt_VERIFY( paint || onlyForHitTests ) ) { - result = Rtt_NEW( runtime.GetAllocator(), BitmapMask( paint ) ); + result = Rtt_NEW( runtime.GetAllocator(), BitmapMask( paint, onlyForHitTests ) ); } return result; } -BitmapMask::BitmapMask( BitmapPaint *paint ) +BitmapMask::BitmapMask( BitmapPaint *paint, bool onlyForHitTests, bool isTemporary ) : fPaint( paint ), fTransform(), fContentWidth( Rtt_REAL_NEG_1 ), - fContentHeight( Rtt_REAL_NEG_1 ) + fContentHeight( Rtt_REAL_NEG_1 ), + fOnlyForHitTests( onlyForHitTests ), + fIsTemporary( isTemporary ) { - Rtt_ASSERT( paint ); + Rtt_ASSERT( paint || onlyForHitTests ); } BitmapMask::BitmapMask( BitmapPaint *paint, Real contentW, Real contentH ) : fPaint( paint ), fTransform(), fContentWidth( contentW > Rtt_REAL_0 ? contentW : Rtt_REAL_NEG_1 ), - fContentHeight( contentH > Rtt_REAL_0 ? contentH : Rtt_REAL_NEG_1 ) + fContentHeight( contentH > Rtt_REAL_0 ? contentH : Rtt_REAL_NEG_1 ), + fOnlyForHitTests( false ), + fIsTemporary( false ) { } BitmapMask::~BitmapMask() { - Rtt_DELETE( fPaint ); + if ( !fIsTemporary ) + { + Rtt_DELETE( fPaint ); + } } +const char BitmapMask::kHitTestOnlyTable[] = "hitTestOnlyTableKey"; + void BitmapMask::GetSelfBounds( Rect& rect ) const { diff --git a/librtt/Display/Rtt_BitmapMask.h b/librtt/Display/Rtt_BitmapMask.h index acfa0f31d..122d916f8 100644 --- a/librtt/Display/Rtt_BitmapMask.h +++ b/librtt/Display/Rtt_BitmapMask.h @@ -28,18 +28,24 @@ class UserdataWrapper; class BitmapMask { public: - static BitmapMask* Create( Runtime& runtime, const FilePath& maskData ); + static BitmapMask* Create( Runtime& runtime, const FilePath& maskData, bool onlyForHitTests ); public: - BitmapMask( BitmapPaint *paint ); + BitmapMask( BitmapPaint *paint, bool onlyForHitTests, bool isTemporary = false ); BitmapMask( BitmapPaint *paint, Real contentW, Real contentH ); public: ~BitmapMask(); + public: + static const char kHitTestOnlyTable[]; + public: const BitmapPaint* GetPaint() const { return fPaint; } BitmapPaint* GetPaint() { return fPaint; } + + public: + bool GetOnlyForHitTests() const { return fOnlyForHitTests; } public: const Transform& GetTransform() const { return fTransform; } @@ -58,6 +64,8 @@ class BitmapMask Transform fTransform; Real fContentWidth; Real fContentHeight; + bool fOnlyForHitTests; + bool fIsTemporary; }; // ---------------------------------------------------------------------------- diff --git a/librtt/Display/Rtt_BitmapPaint.cpp b/librtt/Display/Rtt_BitmapPaint.cpp index 46da8f657..5a84ae874 100755 --- a/librtt/Display/Rtt_BitmapPaint.cpp +++ b/librtt/Display/Rtt_BitmapPaint.cpp @@ -66,16 +66,21 @@ BitmapPaint::NewBitmap( Runtime& runtime, const char* filename, MPlatform::Direc } BitmapPaint* -BitmapPaint::NewBitmap( Runtime& runtime, const FilePath& data, U32 flags, bool isMask ) +BitmapPaint::NewBitmap( Runtime& runtime, const FilePath& data, U32 flags, bool isMask, bool onlyForHitTests ) { BitmapPaint *result = NULL; const char *filename = data.GetFilename(); MPlatform::Directory baseDir = data.GetBaseDir(); + + if ( onlyForHitTests && '\0' == *filename ) + { + return NULL; + } TextureFactory& factory = runtime.GetDisplay().GetTextureFactory(); SharedPtr< TextureResource > pTexture = - factory.FindOrCreate( filename, baseDir, flags, isMask ); + factory.FindOrCreate( filename, baseDir, flags, isMask, onlyForHitTests ); if ( pTexture.NotNull() ) { diff --git a/librtt/Display/Rtt_BitmapPaint.h b/librtt/Display/Rtt_BitmapPaint.h index a93afca68..84bad3aa4 100755 --- a/librtt/Display/Rtt_BitmapPaint.h +++ b/librtt/Display/Rtt_BitmapPaint.h @@ -40,7 +40,7 @@ class BitmapPaint : public Paint static BitmapPaint* NewBitmap( Runtime& runtime, const char* filename, MPlatform::Directory baseDir, U32 flags ); // Load bitmap mask from file or reuse bitmap from image cache - static BitmapPaint* NewBitmap( Runtime& runtime, const FilePath& data, U32 flags, bool isMask ); + static BitmapPaint* NewBitmap( Runtime& runtime, const FilePath& data, U32 flags, bool isMask, bool onlyForHitTests = false ); // Wrap platform bitmap in Paint-compatible interface. Typically used // in conjunction with PlatformImageProvider diff --git a/librtt/Display/Rtt_DisplayObject.cpp b/librtt/Display/Rtt_DisplayObject.cpp index ed9662b86..464785710 100644 --- a/librtt/Display/Rtt_DisplayObject.cpp +++ b/librtt/Display/Rtt_DisplayObject.cpp @@ -19,6 +19,7 @@ #include "Display/Rtt_BitmapPaint.h" #include "Display/Rtt_Scene.h" #include "Display/Rtt_StageObject.h" +#include "Display/Rtt_ShapeObject.h" #include "Rtt_Event.h" #include "Rtt_LuaContext.h" #include "Rtt_LuaProxy.h" @@ -318,7 +319,32 @@ DisplayObject::UpdateSelfBounds( Rect& rRect ) const if ( IsHitTestMasked() ) { Rect maskBounds; - fMask->GetSelfBounds( maskBounds ); + + if ( fMask->GetOnlyForHitTests() && !fMask->GetPaint() ) + { + if ( !ShapeObject::IsShapeObject( *this ) ) + { + return; + } + + const ShapeObject &o = static_cast( *this ); + const BitmapPaint* tempPaint = o.GetBitmapPaint(); + + if ( !tempPaint ) + { + return; + } + + BitmapMask temp( const_cast( tempPaint ), true, true ); + + temp.GetSelfBounds( maskBounds ); + } + + else + { + fMask->GetSelfBounds( maskBounds ); + } + rRect.Intersect( maskBounds ); } } @@ -1302,7 +1328,7 @@ DisplayObject::UpdateMask() { Rtt_ASSERT( ! IsValid( kMaskFlag ) ); - if ( fMask ) + if ( fMask && !fMask->GetOnlyForHitTests() ) { /* Matrix xform = GetSrcToDstMatrix(); @@ -1333,7 +1359,7 @@ DisplayObject::SetMask( Rtt_Allocator *allocator, BitmapMask *mask ) if ( mask ) { - if( ! fMaskUniform ) + if( ! fMaskUniform && !fMask->GetOnlyForHitTests() ) { fMaskUniform = Rtt_NEW( allocator, Uniform( allocator, Uniform::kMat3 ) ); } diff --git a/librtt/Display/Rtt_GroupObject.cpp b/librtt/Display/Rtt_GroupObject.cpp index cdd4b6d1b..b62ce2b6a 100644 --- a/librtt/Display/Rtt_GroupObject.cpp +++ b/librtt/Display/Rtt_GroupObject.cpp @@ -202,7 +202,7 @@ GroupObject::Draw( Renderer& renderer ) const const BitmapMask *mask = GetMask(); - if ( mask ) + if ( mask && !fMask->GetOnlyForHitTests() ) { Texture *texture = const_cast< BitmapPaint * >( mask->GetPaint() )->GetTexture(); Uniform *uniform = const_cast< Self * >( this )->GetMaskUniform(); @@ -221,7 +221,7 @@ GroupObject::Draw( Renderer& renderer ) const } } - if ( mask ) + if ( mask && !fMask->GetOnlyForHitTests() ) { renderer.PopMask(); } diff --git a/librtt/Display/Rtt_LuaLibGraphics.cpp b/librtt/Display/Rtt_LuaLibGraphics.cpp index 8313d3b68..37d9d23c9 100644 --- a/librtt/Display/Rtt_LuaLibGraphics.cpp +++ b/librtt/Display/Rtt_LuaLibGraphics.cpp @@ -71,6 +71,8 @@ class GraphicsLibrary public: static int newMask( lua_State *L ); + static int newHitTestOnlyMask( lua_State *L ); + static int newHitTestOnlyMaskFromPaint( lua_State *L ); static int newGradient( lua_State *L ); static int newImageSheet( lua_State *L ); static int defineEffect( lua_State *L ); @@ -113,6 +115,8 @@ GraphicsLibrary::Open( lua_State *L ) const luaL_Reg kVTable[] = { { "newMask", newMask }, + { "newHitTestOnlyMask", newHitTestOnlyMask }, + { "newHitTestOnlyMaskFromPaint", newHitTestOnlyMaskFromPaint }, // { "newVertexArray", newVertexArray }, { "newGradient", newGradient }, { "newImageSheet", newImageSheet }, @@ -202,6 +206,43 @@ GraphicsLibrary::newMask( lua_State *L ) return result; } +// graphics.newHitTestOnlyMask( filename [, baseDir] ) +int +GraphicsLibrary::newHitTestOnlyMask( lua_State *L ) +{ + int result = GraphicsLibrary::newMask( L ); + + if ( result ) + { + lua_getfield( L, LUA_REGISTRYINDEX, BitmapMask::kHitTestOnlyTable ); + + if ( lua_istable( L, -1 ) ) + { + lua_pushvalue( L, -2 ); + lua_pushboolean( L, 1 ); + lua_rawset( L, -3 ); + lua_pop( L, 1 ); + } + + else + { + result = 0; + } + } + + return result; +} + +// graphics.newHitTestOnlyMaskFromPaint( [opts] ) +int +GraphicsLibrary::newHitTestOnlyMaskFromPaint( lua_State *L ) +{ + lua_settop( L, 0 ); // TODO: any options? + lua_pushliteral( L, "" ); + + return newHitTestOnlyMask( L ); +} + // graphics.newVertexArray( x1, y1 [,x2, y2, ... ] ) /* static int @@ -901,6 +942,13 @@ LuaLibGraphics::Initialize( lua_State *L, Display& display ) CoronaLuaPushModule( L, GraphicsLibrary::kName ); lua_setglobal( L, GraphicsLibrary::kName ); // graphics = library + + lua_newtable( L ); + lua_createtable( L, 0, 1 ); + lua_pushliteral( L, "k" ); + lua_setfield( L, -2, "__mode" ); + lua_setmetatable( L, -2 ); + lua_setfield( L, LUA_REGISTRYINDEX, BitmapMask::kHitTestOnlyTable ); } // ---------------------------------------------------------------------------- diff --git a/librtt/Display/Rtt_PlatformBitmap.cpp b/librtt/Display/Rtt_PlatformBitmap.cpp index acb552ecf..629d0f50d 100644 --- a/librtt/Display/Rtt_PlatformBitmap.cpp +++ b/librtt/Display/Rtt_PlatformBitmap.cpp @@ -61,8 +61,17 @@ PlatformBitmap::HitTest( Rtt_Allocator *context, int i, int j, U8 threshold ) co break; default: - // TODO: Use GetColorByteIndexesFor() - Rtt_ASSERT_NOT_IMPLEMENTED(); + { + int alphaIndex, redIndex, greenIndex, blueIndex; + GetColorByteIndexesFor( format, &alphaIndex, &redIndex, &greenIndex, &blueIndex ); + #ifdef Rtt_ANDROID_ENV // cf. GraphicsLibrary::newOutline et al. + alphaIndex = 3; + #endif + const U8 *pixels = ((const U8*)data); + U8 alpha = pixels[index + alphaIndex]; + /* TODO? use r,g,b...*/ + result = alpha > threshold; + } break; } } diff --git a/librtt/Display/Rtt_ShapeObject.cpp b/librtt/Display/Rtt_ShapeObject.cpp index 90784f6f0..6d65f9468 100644 --- a/librtt/Display/Rtt_ShapeObject.cpp +++ b/librtt/Display/Rtt_ShapeObject.cpp @@ -55,6 +55,37 @@ ShapeObject::~ShapeObject() Rtt_DELETE( fPath ); } +bool +ShapeObject::IsShapeObject( const DisplayObject &object ) +{ + const LuaProxyVTable* t = &object.ProxyVTable(), * shapeVTable = &LuaShapeObjectProxyVTable::Constant(); + + while ( shapeVTable != t ) + { + const LuaProxyVTable* parent = &t->Parent(); + + if ( parent == t ) + { + return false; + } + + else + { + t = parent; + } + } + + return true; +} + +const BitmapPaint* +ShapeObject::GetBitmapPaint() const +{ + Rtt_ASSERT( fPath ); + + return (BitmapPaint*)fPath->GetFill()->AsPaint( Paint::kBitmap ); +} + bool ShapeObject::UpdateTransform( const Matrix& parentToDstSpace ) { @@ -271,12 +302,25 @@ ShapeObject::SetSelfBounds( Real width, Real height ) void ShapeObject::DidSetMask( BitmapMask *mask, Uniform *uniform ) { - Texture *maskTexture = ( mask ? mask->GetPaint()->GetTexture() : NULL ); + Rtt_ASSERT( !mask || mask->GetPaint() || mask->GetOnlyForHitTests() ); + + Texture *maskTexture = ( mask && !mask->GetOnlyForHitTests() ? mask->GetPaint()->GetTexture() : NULL ); fFillData.fMaskTexture = maskTexture; fFillData.fMaskUniform = uniform; fStrokeData.fMaskTexture = maskTexture; fStrokeData.fMaskUniform = uniform; + + if ( mask && !mask->GetPaint() ) + { + const BitmapPaint *bitmapPaint = GetBitmapPaint(); + + if ( bitmapPaint ) + { + SetMaskGeometricProperty( kScaleX, GetGeometricProperty( kWidth ) / bitmapPaint->GetBitmap()->Width() ); + SetMaskGeometricProperty( kScaleY, GetGeometricProperty( kHeight ) / bitmapPaint->GetBitmap()->Height() ); + } + } } void @@ -315,6 +359,21 @@ ShapeObject::SetFill( Paint* newValue ) fPath->SetFill( newValue ); DidChangePaint( fFillData ); + + BitmapMask *mask = GetMask(); + + if ( mask && !mask->GetPaint() ) + { + Rtt_ASSERT( mask->GetOnlyForHitTests() ); + + const BitmapPaint *paint = GetBitmapPaint(); + + if ( paint ) + { + SetMaskGeometricProperty( kScaleX, GetGeometricProperty( kWidth ) / paint->GetBitmap()->Width() ); + SetMaskGeometricProperty( kScaleY, GetGeometricProperty( kHeight ) / paint->GetBitmap()->Height() ); + } + } } void diff --git a/librtt/Display/Rtt_ShapeObject.h b/librtt/Display/Rtt_ShapeObject.h index 72820a2da..d62fc3943 100644 --- a/librtt/Display/Rtt_ShapeObject.h +++ b/librtt/Display/Rtt_ShapeObject.h @@ -44,6 +44,10 @@ class ShapeObject : public DisplayObject public: ShapeObject( ClosedPath *path ); ~ShapeObject(); + + static bool IsShapeObject( const DisplayObject& object ); + + const BitmapPaint* GetBitmapPaint() const; public: // MDrawable diff --git a/librtt/Display/Rtt_TextureFactory.cpp b/librtt/Display/Rtt_TextureFactory.cpp index 0271f72b9..c1f6709f4 100644 --- a/librtt/Display/Rtt_TextureFactory.cpp +++ b/librtt/Display/Rtt_TextureFactory.cpp @@ -182,14 +182,14 @@ SharedPtr< TextureResource > TextureFactory::CreateAndAdd( const std::string& key, PlatformBitmap *bitmap, bool useCache, - bool isRetina ) + bool isRetina, bool onlyForHitTests ) { TextureResource *resource = TextureResourceBitmap::Create( * this, bitmap, isRetina ); SharedPtr< TextureResource > result = SharedPtr< TextureResource >( resource ); bool shouldPreload = fDisplay.GetDefaults().ShouldPreloadTextures(); - if ( shouldPreload ) + if ( shouldPreload && !onlyForHitTests ) { // Add to create queue AddToPreloadQueue( result ); @@ -234,7 +234,7 @@ TextureFactory::FindOrCreate( const char *filename, MPlatform::Directory baseDir, U32 flags, - bool isMask ) + bool isMask, bool onlyForHitTests ) { SharedPtr< TextureResource > result; @@ -277,7 +277,7 @@ TextureFactory::FindOrCreate( if ( result.IsNull() ) { PlatformBitmap *bitmap = CreateBitmap( filePath.GetString(), flags, isMask ); - result = CreateAndAdd( key, bitmap, true, isRetina ); + result = CreateAndAdd( key, bitmap, true, isRetina, onlyForHitTests ); } return result; diff --git a/librtt/Display/Rtt_TextureFactory.h b/librtt/Display/Rtt_TextureFactory.h index 9d5a09aeb..740245df8 100644 --- a/librtt/Display/Rtt_TextureFactory.h +++ b/librtt/Display/Rtt_TextureFactory.h @@ -57,14 +57,14 @@ class TextureFactory SharedPtr< TextureResource > CreateAndAdd( const std::string& key, PlatformBitmap *bitmap, bool useCache, - bool isRetina ); + bool isRetina, bool onlyForHitTests = false ); // Cached texture resources public: SharedPtr< TextureResource > FindOrCreate( const char *filename, MPlatform::Directory baseDir, U32 flags, - bool isMask ); + bool isMask, bool onlyForHitTests = false ); SharedPtr< TextureResource > FindOrCreate( const FilePath& filePath, diff --git a/librtt/Rtt_Event.cpp b/librtt/Rtt_Event.cpp index 6066ccab5..ca5a8c3d1 100755 --- a/librtt/Rtt_Event.cpp +++ b/librtt/Rtt_Event.cpp @@ -1657,7 +1657,34 @@ TestMask( Rtt_Allocator *allocator, DisplayObject& child, const Matrix& srcToDst Vertex2 p = { dstX, dstY }; inverse.Apply( p ); - PlatformBitmap *bitmap = mask->GetPaint()->GetBitmap(); + PlatformBitmap *bitmap; + const Paint *paint = mask->GetPaint(); + + if ( paint ) + { + bitmap = paint->GetBitmap(); + } + + else + { + Rtt_ASSERT( mask->GetOnlyForHitTests() ); + + if ( !ShapeObject::IsShapeObject( child ) ) + { + return false; + } + + ShapeObject &o = static_cast( child ); + paint = o.GetBitmapPaint(); + + if ( !paint ) + { + return false; + } + + bitmap = paint->GetBitmap(); + } + if ( Rtt_VERIFY( bitmap ) ) { Real w = bitmap->Width(); @@ -1678,7 +1705,7 @@ TestMask( Rtt_Allocator *allocator, DisplayObject& child, const Matrix& srcToDst Rtt_RealToInt( x ), Rtt_RealToInt( y ) ) ); #endif - result = mask->HitTest( allocator, Rtt_RealToInt( x ), Rtt_RealToInt( y ) ); + result = bitmap->HitTest( allocator, Rtt_RealToInt( x ), Rtt_RealToInt( y ) ); // TODO: mask->HitTest() seems to be unnecessary (remove?) } return result; @@ -1738,7 +1765,7 @@ HitEvent::Test( HitTestObject& hitParent, const Matrix& srcToDstSpace ) const child.SetForceDraw( oldValue ); // Only do deeper testing if a mask exists and the "isHitTestMasked" property is true - if ( didHit && child.IsHitTestMasked() && child.GetMask() ) + if ( didHit && child.IsHitTestMasked() ) { Matrix childToDst( xform ); childToDst.Concat( child.GetMatrix() ); @@ -1766,7 +1793,7 @@ HitEvent::Test( HitTestObject& hitParent, const Matrix& srcToDstSpace ) const hitTestChildren = child.StageBounds().HitTest( x, y ); // Only do deeper testing if a mask exists and the "isHitTestMasked" property is true - if ( hitTestChildren && child.GetMask() ) + if ( hitTestChildren ) { Matrix childToDst( xform ); childToDst.Concat( child.GetMatrix() ); diff --git a/librtt/Rtt_LuaProxyVTable.cpp b/librtt/Rtt_LuaProxyVTable.cpp index 2bd65d23c..d962f76ec 100644 --- a/librtt/Rtt_LuaProxyVTable.cpp +++ b/librtt/Rtt_LuaProxyVTable.cpp @@ -532,7 +532,28 @@ setMask( lua_State *L ) FilePath *maskData = *ud; if ( maskData ) { - mask = BitmapMask::Create( * runtime, * maskData ); + bool onlyForHitTests = false; + + lua_getfield( L, LUA_REGISTRYINDEX, BitmapMask::kHitTestOnlyTable ); + + if ( lua_istable( L, -1 )) + { + lua_pushvalue( L, 2 ); + lua_rawget( L, -2 ); + + onlyForHitTests = lua_toboolean( L, -1 ); + + lua_pop( L, 1 ); + } + + else + { + Rtt_TRACE_SIM( ( "WARNING: Hit test only table missing for masks.\n" ) ); + } + + lua_pop( L, 1 ); + + mask = BitmapMask::Create( * runtime, * maskData, onlyForHitTests ); } } } diff --git a/platform/windows/Corona.Native.Library.Win32/Rtt/Rtt_WinBitmap.cpp b/platform/windows/Corona.Native.Library.Win32/Rtt/Rtt_WinBitmap.cpp index 5637f3b75..7d5210766 100644 --- a/platform/windows/Corona.Native.Library.Win32/Rtt/Rtt_WinBitmap.cpp +++ b/platform/windows/Corona.Native.Library.Win32/Rtt/Rtt_WinBitmap.cpp @@ -112,6 +112,13 @@ WinBitmap::Lock() if ( fBitmap == NULL ) return; + if ( fLockedBitmapData ) + { + Rtt_ASSERT( fData ); + + return; + } + Gdiplus::Rect rect; rect.X = rect.Y = 0;