-//
// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Flora License, Version 1.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://floralicense.org/license/
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an AS IS BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#include <dali-toolkit/internal/controls/image-view/image-view-impl.h>
-#include <dali-toolkit/public-api/shader-effects/distance-field-effect.h>
+// CLASS HEADER
+#include "image-view-impl.h"
-using namespace Dali;
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
-namespace
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/object/type-registry-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+
+namespace Dali
{
-//Type registration
-BaseHandle Create()
+
+namespace Toolkit
{
- return Toolkit::ImageView::New();
-}
-TypeRegistration mType( typeid(Toolkit::ImageView), typeid(Toolkit::Control), Create );
- /**
- * CameraDetailConstraint, generates detail value
- * based on camera's position and ImageView's position.
- */
- struct CameraDetailConstraint
- {
- CameraDetailConstraint(float detailFactor)
- : mDetailFactor(detailFactor)
- {
+namespace Internal
+{
- }
+namespace
+{
- float operator()(const float& current,
- const PropertyInput& propertyTargetPosition,
- const PropertyInput& propertySourcePosition)
- {
- const Vector3& targetPosition = propertyTargetPosition.GetVector3();
- const Vector3& sourcePosition = propertySourcePosition.GetVector3();
- const float distance = (targetPosition - sourcePosition).Length();
- const float detail = mDetailFactor / distance;
+#define MAKE_SHADER(A)#A
- return detail;
- }
+const char* VERTEX_SHADER = MAKE_SHADER(
+ attribute mediump vec2 aPosition;
+ attribute highp vec2 aTexCoord;
+ varying mediump vec2 vTexCoord;
+ uniform mediump mat4 uMvpMatrix;
+ uniform mediump vec3 uSize;
- const float mDetailFactor;
- };
+ void main()
+ {
+ mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
+ // TODO scale by the actor size when we are using RendererFactor generated renderers with a shared unit sized mesh: vertexPosition.xyz *= uSize;
+ vertexPosition = uMvpMatrix * vertexPosition;
-} // unnamed namespace
+ vTexCoord = aTexCoord;
+ gl_Position = vertexPosition;
+ }
+);
-namespace Dali
-{
+const char* FRAGMENT_SHADER = MAKE_SHADER(
+ varying mediump vec2 vTexCoord;
+ uniform sampler2D sTexture;
+ uniform lowp vec4 uColor;
-namespace Toolkit
-{
+ void main()
+ {
+ gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;
+ }
+);
-namespace Internal
+//TODO: remove when RendererFactory is implemented, so if there are multiple images that render as quads we only end up with one instance of geometry
+Geometry CreateGeometry( int width, int height )
{
+ // Create vertices
+ const float halfWidth = width * .5f;
+ const float halfHeight = height * .5f;
+ struct TexturedQuadVertex { Vector2 position; Vector2 textureCoordinates; };
+ TexturedQuadVertex texturedQuadVertexData[4] = { { Vector2(-halfWidth, -halfHeight), Vector2(0.f, 0.f) },
+ { Vector2( halfWidth, -halfHeight), Vector2(1.f, 0.f) },
+ { Vector2(-halfWidth, halfHeight), Vector2(0.f, 1.f) },
+ { Vector2( halfWidth, halfHeight), Vector2(1.f, 1.f) } };
+
+ Property::Map texturedQuadVertexFormat;
+ texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
+ texturedQuadVertexFormat["aTexCoord"] = Property::VECTOR2;
+ PropertyBuffer texturedQuadVertices = PropertyBuffer::New( texturedQuadVertexFormat, 4 );
+ texturedQuadVertices.SetData(texturedQuadVertexData);
+
+ // Create indices
+ unsigned int indexData[6] = { 0, 3, 1, 0, 2, 3 };
+ Property::Map indexFormat;
+ indexFormat["indices"] = Property::INTEGER;
+ PropertyBuffer indices = PropertyBuffer::New( indexFormat, 6 );
+ indices.SetData(indexData);
+
+ // Create the geometry object
+ Geometry texturedQuadGeometry = Geometry::New();
+ texturedQuadGeometry.AddVertexBuffer( texturedQuadVertices );
+ texturedQuadGeometry.SetIndexBuffer( indices );
+
+ return texturedQuadGeometry;
+}
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// ImageView
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-Dali::Toolkit::ImageView ImageView::New()
+BaseHandle Create()
{
- // Create the implementation
- ImageViewPtr imageView(new ImageView());
+ return Toolkit::ImageView::New();
+}
- // Pass ownership to CustomActor via derived handle
- Dali::Toolkit::ImageView handle(*imageView);
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ImageView, Toolkit::Control, Create );
+DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "resource-url", STRING, RESOURCE_URL )
+DALI_TYPE_REGISTRATION_END()
- // Second-phase init of the implementation
- // This can only be done after the CustomActor connection has been made...
- imageView->Initialize();
+} // anonymous namespace
- return handle;
-}
+using namespace Dali;
ImageView::ImageView()
-: ControlImpl(true)
+: Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) )
{
}
-void ImageView::Initialize()
+ImageView::~ImageView()
{
- Actor self = Self();
- // Register property that represents the level of detail.
- mPropertyDetail = self.RegisterProperty(Toolkit::ImageView::DETAIL_PROPERTY_NAME, 0.0f);
-
- // Create an empty image actor, filling the entire size of this ImageView.
- Image emptyImage;
- mImageActor = ImageActor::New( emptyImage );
- self.Add( mImageActor );
- mImageActor.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
- mImageActor.SetParentOrigin( ParentOrigin::CENTER );
}
-ImageView::~ImageView()
+Toolkit::ImageView ImageView::New()
{
+ ImageView* impl = new ImageView();
+
+ Dali::Toolkit::ImageView handle = Dali::Toolkit::ImageView( *impl );
+ // Second-phase init of the implementation
+ // This can only be done after the CustomActor connection has been made...
+ impl->Initialize();
+
+ return handle;
}
-void ImageView::SetImage(const std::string& filename, ImageType type, float min, float max)
+/////////////////////////////////////////////////////////////
+
+void ImageView::SetImage( Image image )
{
- switch(type)
+ mImage = image;
+
+ ResourceImage resourceImage = ResourceImage::DownCast( mImage );
+ if( resourceImage )
{
- case Toolkit::ImageView::BitmapType:
+ mImageUrl = resourceImage.GetUrl();
+ }
+ else
+ {
+ mImageUrl.clear();
+ }
+
+ if( mImage )
+ {
+ if( Self().OnStage() )
{
- SetImageBitmap(filename, min, max);
- break;
+ AttachImage();
}
- case Toolkit::ImageView::DistanceFieldType:
+ RelayoutRequest();
+ }
+ else
+ {
+ if( mRenderer )
{
- SetImageDistanceField(filename);
- break;
+ Self().RemoveRenderer( mRenderer );
}
+ mSampler.Reset();
+ mMaterial.Reset();
+ mMesh.Reset();
+ mRenderer.Reset();
}
}
-void ImageView::SetImageBitmap(const std::string& filename, float min, float max)
+Image ImageView::GetImage() const
{
- int minLevel = ceilf(logf(min) / logf(2.0f));
- int maxLevel = ceilf(logf(max) / logf(2.0f));
+ return mImage;
+}
- ImageAttributes attributes;
- const Vector3 size = Self().GetCurrentSize();
+Vector3 ImageView::GetNaturalSize()
+{
+ // if no image then use Control's natural size
+ Vector3 size;
- if(minLevel==maxLevel)
- { // Single image detail level, no need for any notifications.
- const float detail = powf(2.0f, maxLevel);
- attributes.SetSize( size.x * detail, size.y * detail );
- Image image = Image::New( filename, attributes);
- mImageActor.SetImage( image );
+ if( mImage )
+ {
+ size.x = mImage.GetWidth();
+ size.y = mImage.GetHeight();
+ size.z = std::min(size.x, size.y);
}
else
- { // Multi image detail level...
- for( int level = minLevel; level <= maxLevel; level++)
- {
- const float minDetail = powf(2.0f, level - 1);
- const float maxDetail = powf(2.0f, level);
- ImageRequest req(filename, size.x * maxDetail, size.y * maxDetail );
-
- if(level==minLevel)
- {
- AddImage(req, LessThanCondition(maxDetail) );
- }
- else if(level==maxLevel)
- {
- AddImage(req, GreaterThanCondition(minDetail) );
- }
- else
- {
- AddImage(req, InsideCondition(minDetail, maxDetail) );
- }
- }
+ {
+ size = Control::GetNaturalSize();
}
+ return size;
}
-void ImageView::SetImageDistanceField(const std::string& filename)
+float ImageView::GetHeightForWidth( float width )
{
- ImageAttributes attributes = Dali::ImageAttributes::NewDistanceField(1.0f, 1);
- const Vector3 size = Self().GetCurrentSize();
-
- attributes.SetSize( size.x, size.y );
- Image image = Image::NewDistanceField(filename, attributes);
- mImageActor.SetImage( image );
-
- DistanceFieldEffect effect = DistanceFieldEffect::New();
- Self().SetShaderEffect( effect );
+ if( mImage )
+ {
+ return GetHeightForWidthBase( width );
+ }
+ else
+ {
+ return Control::GetHeightForWidth( width );
+ }
}
-void ImageView::SetImage(Image image)
+float ImageView::GetWidthForHeight( float height )
{
- mImageActor.SetImage( image );
+ if( mImage )
+ {
+ return GetWidthForHeightBase( height );
+ }
+ else
+ {
+ return Control::GetWidthForHeight( height );
+ }
}
-void ImageView::AddImage(ImageRequest& req, PropertyCondition condition)
+///////////////////////////////////////////////////////////
+//
+// Private methods
+//
+
+void ImageView::AttachImage()
{
- Actor self = Self();
+ if( !mRenderer )
+ {
+ Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+ mMaterial = Material::New( shader );
- PropertyNotification notification = self.AddPropertyNotification( mPropertyDetail, condition );
+ mSampler = Sampler::New( mImage, "sTexture" );
+ mMaterial.AddSampler( mSampler );
- notification.NotifySignal().Connect( this, &ImageView::OnDetailChange );
+ Vector3 size = Self().GetCurrentSize();
+ mMesh = CreateGeometry( size.width, size.height );
+ mRenderer = Renderer::New( mMesh, mMaterial );
+ Self().AddRenderer( mRenderer );
+ }
+ else
+ {
+ mSampler.SetImage( mImage );
+ }
+}
+
+void ImageView::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+ Control::OnRelayout( size, container );
- mNotifications[notification] = req;
+ if( mRenderer )
+ {
+ mMesh = CreateGeometry( size.width, size.height );
+ mRenderer.SetGeometry( mMesh );
+ }
}
-void ImageView::SetDetail(float detail)
+void ImageView::OnStageConnection( int depth )
{
- Self().SetProperty( mPropertyDetail, detail );
+ if( mImage )
+ {
+ AttachImage();
+ }
}
-void ImageView::SetCameraActor(CameraActor camera, float detailFactor)
+///////////////////////////////////////////////////////////
+//
+// Properties
+//
+
+void ImageView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
{
- Constraint constraint = Constraint::New<float>( mPropertyDetail,
- LocalSource( Actor::WORLD_POSITION ),
- Source( camera, Actor::WORLD_POSITION ),
- CameraDetailConstraint(detailFactor));
- Self().RemoveConstraints();
- Self().ApplyConstraint(constraint);
+ Toolkit::ImageView imageView = Toolkit::ImageView::DownCast( Dali::BaseHandle( object ) );
+
+ if ( imageView )
+ {
+ switch ( index )
+ {
+ case Toolkit::ImageView::Property::RESOURCE_URL:
+ {
+ std::string imageUrl;
+ if( value.Get( imageUrl ) )
+ {
+ ImageView& impl = GetImpl( imageView );
+ impl.mImageUrl = imageUrl;
+
+ Image image = ResourceImage::New( imageUrl );
+ impl.SetImage( image );
+ }
+ break;
+ }
+ }
+ }
}
-void ImageView::OnDetailChange( PropertyNotification& notification )
+Property::Value ImageView::GetProperty( BaseObject* object, Property::Index propertyIndex )
{
- ImageRequest& req = mNotifications[notification];
- Image image = Image::New( req.mFilename, req.mAttributes );
- mImageActor.SetImage( image );
+ Property::Value value;
+
+ Toolkit::ImageView imageview = Toolkit::ImageView::DownCast( Dali::BaseHandle( object ) );
+
+ if ( imageview )
+ {
+ switch ( propertyIndex )
+ {
+ case Toolkit::ImageView::Property::RESOURCE_URL:
+ {
+ value = GetImpl( imageview ).mImageUrl;
+ break;
+ }
+ }
+ }
+
+ return value;
}
} // namespace Internal
-
} // namespace Toolkit
-
} // namespace Dali