Merge "Moved TextureSet::SetImage() to separate devel-api module" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / renderers / npatch / npatch-renderer.cpp
index 8e509a9..677d5ad 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <dali/integration-api/platform-abstraction.h>
 #include <dali/public-api/images/buffer-image.h>
 #include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/images/texture-set-image.h>
 
 // INTERNAL IINCLUDES
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
 
@@ -41,13 +43,7 @@ namespace Internal
 
 namespace
 {
-const char * const RENDERER_TYPE("renderer-type");
-const char * const RENDERER_TYPE_VALUE("n-patch-renderer");
-
-const char * const IMAGE_URL_NAME("image-url");
-const char * const BORDER_ONLY("border-only");
-
-std::string TEXTURE_UNIFORM_NAME = "sTexture";
+const char * const BORDER_ONLY("borderOnly");
 
 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
   attribute mediump vec2 aPosition;\n
@@ -123,28 +119,24 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
  * @param[in]  indices              The indices to generate the geometry from
  * @return The geometry formed from the vertices and indices
  */
-Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned int >& indices )
+Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned short >& indices )
 {
   Property::Map vertexFormat;
   vertexFormat[ "aPosition" ] = Property::VECTOR2;
-  PropertyBuffer vertexPropertyBuffer = PropertyBuffer::New( vertexFormat, vertices.Size() );
+  PropertyBuffer vertexPropertyBuffer = PropertyBuffer::New( vertexFormat );
   if( vertices.Size() > 0 )
   {
-    vertexPropertyBuffer.SetData( &vertices[ 0 ] );
+    vertexPropertyBuffer.SetData( &vertices[ 0 ], vertices.Size() );
   }
 
-  Property::Map indexFormat;
-  indexFormat[ "indices" ] = Property::INTEGER;
-  PropertyBuffer indexPropertyBuffer = PropertyBuffer::New( indexFormat, indices.Size() );
+  // Create the geometry object
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer( vertexPropertyBuffer );
   if( indices.Size() > 0 )
   {
-    indexPropertyBuffer.SetData( &indices[ 0 ] );
+    geometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
   }
 
-  // Create the geometry object
-  Geometry geometry = Geometry::New();
-  geometry.AddVertexBuffer( vertexPropertyBuffer );
-  geometry.SetIndexBuffer( indexPropertyBuffer );
 
   return geometry;
 }
@@ -156,7 +148,7 @@ Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsi
  * @param[in]  rowIdx      The row index to start the quad
  * @param[in]  nextRowIdx  The index to the next row
  */
-void AddQuadIndices( Vector< unsigned int >& indices, unsigned int rowIdx, unsigned int nextRowIdx )
+void AddQuadIndices( Vector< unsigned short >& indices, unsigned int rowIdx, unsigned int nextRowIdx )
 {
   indices.PushBack( rowIdx );
   indices.PushBack( nextRowIdx + 1 );
@@ -172,7 +164,7 @@ void AddVertex( Vector< Vector2 >& vertices, unsigned int x, unsigned int y )
   vertices.PushBack( Vector2( x, y ) );
 }
 
-void RegisterStretchProperties( Material& material, const char * uniformName, const NinePatchImage::StretchRanges& stretchPixels, uint16_t imageExtent)
+void RegisterStretchProperties( Renderer& renderer, const char * uniformName, const NinePatchImage::StretchRanges& stretchPixels, uint16_t imageExtent)
 {
   uint16_t prevEnd = 0;
   uint16_t prevFix = 0;
@@ -188,7 +180,7 @@ void RegisterStretchProperties( Material& material, const char * uniformName, co
 
     std::stringstream uniform;
     uniform << uniformName << "[" << i << "]";
-    material.RegisterProperty( uniform.str(), Vector2( fix, stretch ) );
+    renderer.RegisterProperty( uniform.str(), Vector2( fix, stretch ) );
 
     prevEnd = end;
     prevFix = fix;
@@ -199,7 +191,7 @@ void RegisterStretchProperties( Material& material, const char * uniformName, co
     prevFix += imageExtent - prevEnd;
     std::stringstream uniform;
     uniform << uniformName << "[" << i << "]";
-    material.RegisterProperty( uniform.str(), Vector2( prevFix, prevStretch ) );
+    renderer.RegisterProperty( uniform.str(), Vector2( prevFix, prevStretch ) );
   }
 }
 
@@ -217,12 +209,12 @@ NPatchRenderer::~NPatchRenderer()
 {
 }
 
-void NPatchRenderer::DoInitialize( const Property::Map& propertyMap )
+void NPatchRenderer::DoInitialize( Actor& actor, const Property::Map& propertyMap )
 {
   Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
   if( imageURLValue )
   {
-    //Read the border-only property first since InitialiseFromImage relies on mBorderOnly to be properly set
+    //Read the borderOnly property first since InitialiseFromImage relies on mBorderOnly to be properly set
     Property::Value* borderOnlyValue = propertyMap.Find( BORDER_ONLY );
     if( borderOnlyValue )
     {
@@ -272,10 +264,9 @@ void NPatchRenderer::SetOffset( const Vector2& offset )
   //ToDo: renderer applies the offset
 }
 
-void NPatchRenderer::InitializeRenderer( Renderer& renderer )
+Geometry NPatchRenderer::CreateGeometry()
 {
   Geometry geometry;
-  Shader shader;
   if( mStretchPixelsX.Size() == 1 && mStretchPixelsY.Size() == 1 )
   {
     if( !mBorderOnly )
@@ -296,48 +287,86 @@ void NPatchRenderer::InitializeRenderer( Renderer& renderer )
         mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, geometry );
       }
     }
-
-    shader = mFactoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER );
-    if( !shader )
-    {
-      shader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER );
-      mFactoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, shader );
-    }
   }
   else if( mStretchPixelsX.Size() > 0 || mStretchPixelsY.Size() > 0)
   {
     Uint16Pair gridSize( 2 * mStretchPixelsX.Size() + 1,  2 * mStretchPixelsY.Size() + 1 );
     geometry = !mBorderOnly ? CreateGeometry( gridSize ) : CreateGeometryBorder( gridSize );
+  }
 
-    std::stringstream vertexShader;
-    vertexShader << "#define FACTOR_SIZE_X " << mStretchPixelsX.Size() + 2 << "\n"
-                 << "#define FACTOR_SIZE_Y " << mStretchPixelsY.Size() + 2 << "\n"
-                 << VERTEX_SHADER;
+  return geometry;
+}
 
-    shader = Shader::New( vertexShader.str(), FRAGMENT_SHADER );
-  }
-  else
+Shader NPatchRenderer::CreateShader()
+{
+  Shader shader;
+  if( !mImpl->mCustomShader )
   {
-    DALI_LOG_ERROR("The 9 patch image '%s' doesn't have any valid stretch borders and so is not a valid 9 patch image\n", mImageUrl.c_str() );
-    InitializeFromBrokenImage();
-  }
+    if( mStretchPixelsX.Size() == 1 && mStretchPixelsY.Size() == 1 )
+    {
+      shader = mFactoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER );
+      if( !shader )
+      {
+        shader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER );
+        mFactoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, shader );
+      }
+    }
+    else if( mStretchPixelsX.Size() > 0 || mStretchPixelsY.Size() > 0)
+    {
+      std::stringstream vertexShader;
+      vertexShader << "#define FACTOR_SIZE_X " << mStretchPixelsX.Size() + 2 << "\n"
+                   << "#define FACTOR_SIZE_Y " << mStretchPixelsY.Size() + 2 << "\n"
+                   << VERTEX_SHADER;
 
-  if( !renderer )
-  {
-    Material material = Material::New( shader );
-    renderer = Renderer::New( geometry, material );
+      shader = Shader::New( vertexShader.str(), FRAGMENT_SHADER );
+    }
   }
   else
   {
-    mImpl->mRenderer.SetGeometry( geometry );
-    Material material = mImpl->mRenderer.GetMaterial();
-    if( material )
+    const char* fragmentShader = FRAGMENT_SHADER;
+    Dali::Shader::ShaderHints hints = Dali::Shader::HINT_NONE;
+
+    if( !mImpl->mCustomShader->mFragmentShader.empty() )
+    {
+      fragmentShader = mImpl->mCustomShader->mFragmentShader.c_str();
+    }
+    hints = mImpl->mCustomShader->mHints;
+
+    if( mStretchPixelsX.Size() == 1 && mStretchPixelsY.Size() == 1 )
+    {
+      shader = Shader::New( VERTEX_SHADER_3X3, fragmentShader, hints );
+    }
+    else if( mStretchPixelsX.Size() > 0 || mStretchPixelsY.Size() > 0)
     {
-      material.SetShader( shader );
+      std::stringstream vertexShader;
+      vertexShader << "#define FACTOR_SIZE_X " << mStretchPixelsX.Size() + 2 << "\n"
+                   << "#define FACTOR_SIZE_Y " << mStretchPixelsY.Size() + 2 << "\n"
+                   << VERTEX_SHADER;
+
+      shader = Shader::New( vertexShader.str(), fragmentShader, hints );
     }
   }
+
+  return shader;
 }
 
+void NPatchRenderer::InitializeRenderer()
+{
+  Geometry geometry = CreateGeometry();
+  Shader shader = CreateShader();
+
+  if( !geometry || !shader )
+  {
+    DALI_LOG_ERROR("The 9 patch image '%s' doesn't have any valid stretch borders and so is not a valid 9 patch image\n", mImageUrl.c_str() );
+    InitializeFromBrokenImage();
+  }
+
+  TextureSet textureSet = TextureSet::New();
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+  mImpl->mRenderer.SetTextures( textureSet );
+}
+
+
 void NPatchRenderer::DoSetOnStage( Actor& actor )
 {
   if( !mCroppedImage )
@@ -351,10 +380,11 @@ void NPatchRenderer::DoSetOnStage( Actor& actor )
     {
       InitializeFromImage( mImage );
     }
-
-    InitializeRenderer( mImpl->mRenderer );
   }
 
+  //initialize the renderer after initializing from the image since we need to know the grid size from the image before creating the geometry
+  InitializeRenderer();
+
   if( mCroppedImage )
   {
     ApplyImageToSampler();
@@ -364,12 +394,14 @@ void NPatchRenderer::DoSetOnStage( Actor& actor )
 void NPatchRenderer::DoSetOffStage( Actor& actor )
 {
   mCroppedImage.Reset();
+  actor.RemoveRenderer( mImpl->mRenderer );
+  mImpl->mRenderer.Reset();
 }
 
 void NPatchRenderer::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
-  map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
+  map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
   if( !mImageUrl.empty() )
   {
     map.Insert( IMAGE_URL_NAME, mImageUrl );
@@ -381,8 +413,48 @@ void NPatchRenderer::DoCreatePropertyMap( Property::Map& map ) const
   map.Insert( BORDER_ONLY, mBorderOnly );
 }
 
+void NPatchRenderer::ChangeRenderer( bool oldBorderOnly, size_t oldGridX, size_t oldGridY )
+{
+  //check to see if the border style has changed
+
+  bool borderOnlyChanged = oldBorderOnly != mBorderOnly;
+  bool gridChanged = oldGridX != mStretchPixelsX.Size() || oldGridY != mStretchPixelsY.Size();
+
+  if( borderOnlyChanged || gridChanged )
+  {
+    Geometry geometry = CreateGeometry();
+    if( geometry )
+    {
+      mImpl->mRenderer.SetGeometry( geometry );
+    }
+    else
+    {
+      InitializeFromBrokenImage();
+    }
+  }
+
+  if( gridChanged )
+  {
+    Shader shader = CreateShader();
+    TextureSet textureSet;
+    if( shader )
+    {
+      textureSet = mImpl->mRenderer.GetTextures();
+      if( !textureSet )
+      {
+        InitializeFromBrokenImage();
+      }
+      mImpl->mRenderer.SetShader( shader );
+    }
+  }
+}
+
 void NPatchRenderer::SetImage( const std::string& imageUrl, bool borderOnly )
 {
+  bool oldBorderOnly = mBorderOnly;
+  size_t oldGridX = mStretchPixelsX.Size();
+  size_t oldGridY = mStretchPixelsY.Size();
+
   mBorderOnly = borderOnly;
   mImage.Reset();
   if( mImageUrl == imageUrl )
@@ -391,17 +463,26 @@ void NPatchRenderer::SetImage( const std::string& imageUrl, bool borderOnly )
   }
 
   mImageUrl = imageUrl;
-  NinePatchImage nPatch = NinePatchImage::New( mImageUrl );
-  InitializeFromImage( nPatch );
-
-  if( mCroppedImage && mImpl->mIsOnStage )
+  if( mImpl->mRenderer )
   {
-    ApplyImageToSampler();
+    NinePatchImage nPatch = NinePatchImage::New( mImageUrl );
+    InitializeFromImage( nPatch );
+
+    ChangeRenderer( oldBorderOnly, oldGridX, oldGridY );
+
+    if( mCroppedImage )
+    {
+      ApplyImageToSampler();
+    }
   }
 }
 
 void NPatchRenderer::SetImage( NinePatchImage image, bool borderOnly )
 {
+  bool oldBorderOnly = mBorderOnly;
+  size_t oldGridX = mStretchPixelsX.Size();
+  size_t oldGridY = mStretchPixelsY.Size();
+
   mBorderOnly = borderOnly;
   mImageUrl.empty();
   if( mImage == image )
@@ -410,11 +491,15 @@ void NPatchRenderer::SetImage( NinePatchImage image, bool borderOnly )
   }
 
   mImage = image;
-  InitializeFromImage( mImage );
-
-  if( mCroppedImage && mImpl->mIsOnStage )
+  if( mImpl->mRenderer )
   {
-    ApplyImageToSampler();
+    InitializeFromImage( mImage );
+    ChangeRenderer( oldBorderOnly, oldGridX, oldGridY );
+
+    if( mCroppedImage )
+    {
+      ApplyImageToSampler();
+    }
   }
 }
 
@@ -447,18 +532,10 @@ void NPatchRenderer::InitializeFromBrokenImage()
 
 void NPatchRenderer::ApplyImageToSampler()
 {
-  Material material = mImpl->mRenderer.GetMaterial();
-  if( material )
+  TextureSet textureSet = mImpl->mRenderer.GetTextures();
+  if( textureSet )
   {
-    int index = material.GetTextureIndex( TEXTURE_UNIFORM_NAME );
-    if( index > -1 )
-    {
-      material.SetTextureImage( index, mCroppedImage );
-    }
-    else
-    {
-      material.AddTexture(  mCroppedImage, TEXTURE_UNIFORM_NAME );
-    }
+    TextureSetImage( textureSet, 0u, mCroppedImage );
 
     if( mStretchPixelsX.Size() == 1 && mStretchPixelsY.Size() == 1 )
     {
@@ -469,18 +546,18 @@ void NPatchRenderer::ApplyImageToSampler()
       uint16_t stretchWidth = stretchX.GetY() - stretchX.GetX();
       uint16_t stretchHeight = stretchY.GetY() - stretchY.GetX();
 
-      material.RegisterProperty( "uFixed[0]", Vector2::ZERO );
-      material.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) );
-      material.RegisterProperty( "uFixed[2]", Vector2( mImageSize.GetWidth() - stretchWidth, mImageSize.GetHeight() - stretchHeight ) );
-      material.RegisterProperty( "uStretchTotal", Vector2( stretchWidth, stretchHeight ) );
+      mImpl->mRenderer.RegisterProperty( "uFixed[0]", Vector2::ZERO );
+      mImpl->mRenderer.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) );
+      mImpl->mRenderer.RegisterProperty( "uFixed[2]", Vector2( mImageSize.GetWidth() - stretchWidth, mImageSize.GetHeight() - stretchHeight ) );
+      mImpl->mRenderer.RegisterProperty( "uStretchTotal", Vector2( stretchWidth, stretchHeight ) );
     }
     else
     {
-      material.RegisterProperty( "uNinePatchFactorsX[0]", Vector2::ZERO );
-      material.RegisterProperty( "uNinePatchFactorsY[0]", Vector2::ZERO );
+      mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsX[0]", Vector2::ZERO );
+      mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsY[0]", Vector2::ZERO );
 
-      RegisterStretchProperties( material, "uNinePatchFactorsX", mStretchPixelsX, mImageSize.GetWidth() );
-      RegisterStretchProperties( material, "uNinePatchFactorsY", mStretchPixelsY, mImageSize.GetHeight() );
+      RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsX", mStretchPixelsX, mImageSize.GetWidth() );
+      RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsY", mStretchPixelsY, mImageSize.GetHeight() );
     }
   }
 }
@@ -504,7 +581,7 @@ Geometry NPatchRenderer::CreateGeometry( Uint16Pair gridSize )
 
   // Create indices
   //TODO: compare performance with triangle strip when Geometry supports it
-  Vector< unsigned int > indices;
+  Vector< unsigned short > indices;
   indices.Reserve( gridWidth * gridHeight * 6 );
 
   unsigned int rowIdx     = 0;
@@ -561,7 +638,7 @@ Geometry NPatchRenderer::CreateGeometryBorder( Uint16Pair gridSize )
 
   // Create indices
   //TODO: compare performance with triangle strip when Geometry supports it
-  Vector< unsigned int > indices;
+  Vector< unsigned short > indices;
   indices.Reserve( gridWidth * gridHeight * 6 );
 
   //top