X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Frenderers%2Fnpatch%2Fnpatch-renderer.cpp;h=677d5ad6823318888236488b6603ace09410bb87;hb=refs%2Fchanges%2F23%2F79523%2F2;hp=63e2f5d44323f680bfa50570914cb5c4bfa97443;hpb=21b42a30e8a6e94e5e523ebdaec055a91a38f046;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.cpp b/dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.cpp index 63e2f5d..677d5ad 100644 --- a/dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.cpp +++ b/dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.cpp @@ -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. @@ -22,10 +22,12 @@ #include #include #include +#include // INTERNAL IINCLUDES #include #include +#include #include #include @@ -41,13 +43,33 @@ namespace Internal namespace { -const char * const RENDERER_TYPE("renderer-type"); -const char * const RENDERER_TYPE_VALUE("n-patch-renderer"); +const char * const BORDER_ONLY("borderOnly"); -const char * const IMAGE_URL_NAME("image-url"); -const char * const BORDER_ONLY("border-only"); - -std::string TEXTURE_UNIFORM_NAME = "sTexture"; +const char* VERTEX_SHADER = DALI_COMPOSE_SHADER( + attribute mediump vec2 aPosition;\n + varying mediump vec2 vTexCoord;\n + uniform mediump mat4 uMvpMatrix;\n + uniform mediump vec3 uSize;\n + uniform mediump vec2 uNinePatchFactorsX[ FACTOR_SIZE_X ];\n + uniform mediump vec2 uNinePatchFactorsY[ FACTOR_SIZE_Y ];\n + \n + void main()\n + {\n + mediump vec2 fixedFactor = vec2( uNinePatchFactorsX[ int( ( aPosition.x + 1.0 ) * 0.5 ) ].x, uNinePatchFactorsY[ int( ( aPosition.y + 1.0 ) * 0.5 ) ].x );\n + mediump vec2 stretch = vec2( uNinePatchFactorsX[ int( ( aPosition.x ) * 0.5 ) ].y, uNinePatchFactorsY[ int( ( aPosition.y ) * 0.5 ) ].y );\n + \n + mediump vec2 fixedTotal = vec2( uNinePatchFactorsX[ FACTOR_SIZE_X - 1 ].x, uNinePatchFactorsY[ FACTOR_SIZE_Y - 1 ].x );\n + mediump vec2 stretchTotal = vec2( uNinePatchFactorsX[ FACTOR_SIZE_X - 1 ].y, uNinePatchFactorsY[ FACTOR_SIZE_Y - 1 ].y );\n + \n + mediump vec4 vertexPosition = vec4( ( fixedFactor + ( uSize.xy - fixedTotal ) * stretch / stretchTotal ), 0.0, 1.0 );\n + vertexPosition.xy -= uSize.xy * vec2( 0.5, 0.5 );\n + vertexPosition = uMvpMatrix * vertexPosition;\n + \n + vTexCoord = ( fixedFactor + stretch ) / ( fixedTotal + stretchTotal );\n + \n + gl_Position = vertexPosition;\n + }\n +); const char* VERTEX_SHADER_3X3 = DALI_COMPOSE_SHADER( attribute mediump vec2 aPosition;\n @@ -97,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; } @@ -130,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 ); @@ -146,6 +164,37 @@ void AddVertex( Vector< Vector2 >& vertices, unsigned int x, unsigned int y ) vertices.PushBack( Vector2( x, y ) ); } +void RegisterStretchProperties( Renderer& renderer, const char * uniformName, const NinePatchImage::StretchRanges& stretchPixels, uint16_t imageExtent) +{ + uint16_t prevEnd = 0; + uint16_t prevFix = 0; + uint16_t prevStretch = 0; + unsigned int i = 1; + for( NinePatchImage::StretchRanges::ConstIterator it = stretchPixels.Begin(); it != stretchPixels.End(); ++it, ++i ) + { + uint16_t start = it->GetX(); + uint16_t end = it->GetY(); + + uint16_t fix = prevFix + start - prevEnd; + uint16_t stretch = prevStretch + end - start; + + std::stringstream uniform; + uniform << uniformName << "[" << i << "]"; + renderer.RegisterProperty( uniform.str(), Vector2( fix, stretch ) ); + + prevEnd = end; + prevFix = fix; + prevStretch = stretch; + } + + { + prevFix += imageExtent - prevEnd; + std::stringstream uniform; + uniform << uniformName << "[" << i << "]"; + renderer.RegisterProperty( uniform.str(), Vector2( prevFix, prevStretch ) ); + } +} + } //unnamed namespace /////////////////NPatchRenderer//////////////// @@ -160,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 ) { @@ -175,11 +224,11 @@ void NPatchRenderer::DoInitialize( const Property::Map& propertyMap ) if( imageURLValue->Get( mImageUrl ) ) { NinePatchImage nPatch = NinePatchImage::New( mImageUrl ); - InitialiseFromImage( nPatch ); + InitializeFromImage( nPatch ); } else { - CreateErrorImage(); + InitializeFromBrokenImage(); DALI_LOG_ERROR( "The property '%s' is not a string\n", IMAGE_URL_NAME ); } } @@ -191,17 +240,17 @@ void NPatchRenderer::GetNaturalSize( Vector2& naturalSize ) const { naturalSize.x = mImage.GetWidth(); naturalSize.y = mImage.GetHeight(); - return; } else if( !mImageUrl.empty() ) { ImageDimensions dimentions = ResourceImage::GetImageSize( mImageUrl ); naturalSize.x = dimentions.GetWidth(); naturalSize.y = dimentions.GetHeight(); - return; } - - naturalSize = Vector2::ZERO; + else + { + naturalSize = Vector2::ZERO; + } } void NPatchRenderer::SetClipRect( const Rect& clipRect ) @@ -215,51 +264,109 @@ void NPatchRenderer::SetOffset( const Vector2& offset ) //ToDo: renderer applies the offset } -void NPatchRenderer::InitializeRenderer( Renderer& renderer ) +Geometry NPatchRenderer::CreateGeometry() { Geometry geometry; - if( !mBorderOnly ) + if( mStretchPixelsX.Size() == 1 && mStretchPixelsY.Size() == 1 ) { - geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY ); - if( !geometry ) + if( !mBorderOnly ) { - geometry = CreateGeometry( Uint16Pair( 3, 3 ) ); - mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY, geometry ); + geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY ); + if( !geometry ) + { + geometry = CreateGeometry( Uint16Pair( 3, 3 ) ); + mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_GEOMETRY, geometry ); + } } - } - else - { - geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY ); - if( !geometry ) + else { - geometry = CreateGeometryBorder( Uint16Pair( 3, 3 ) ); - mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, geometry ); + geometry = mFactoryCache.GetGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY ); + if( !geometry ) + { + geometry = CreateGeometryBorder( Uint16Pair( 3, 3 ) ); + mFactoryCache.SaveGeometry( RendererFactoryCache::NINE_PATCH_BORDER_GEOMETRY, geometry ); + } } } - - Shader shader = mFactoryCache.GetShader( RendererFactoryCache::NINE_PATCH_SHADER ); - if( !shader ) + else if( mStretchPixelsX.Size() > 0 || mStretchPixelsY.Size() > 0) { - shader = Shader::New( VERTEX_SHADER_3X3, FRAGMENT_SHADER ); - mFactoryCache.SaveShader( RendererFactoryCache::NINE_PATCH_SHADER, shader ); + Uint16Pair gridSize( 2 * mStretchPixelsX.Size() + 1, 2 * mStretchPixelsY.Size() + 1 ); + geometry = !mBorderOnly ? CreateGeometry( gridSize ) : CreateGeometryBorder( gridSize ); } - if( !renderer ) + return geometry; +} + +Shader NPatchRenderer::CreateShader() +{ + Shader shader; + if( !mImpl->mCustomShader ) { - Material material = Material::New( shader ); - renderer = Renderer::New( geometry, material ); + 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; + + 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 ) @@ -267,14 +374,17 @@ void NPatchRenderer::DoSetOnStage( Actor& actor ) if( !mImageUrl.empty() ) { NinePatchImage nPatch = NinePatchImage::New( mImageUrl ); - InitialiseFromImage( nPatch ); + InitializeFromImage( nPatch ); } else if( mImage ) { - InitialiseFromImage( mImage ); + InitializeFromImage( mImage ); } } + //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(); @@ -284,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 ); @@ -301,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 ) @@ -311,17 +463,26 @@ void NPatchRenderer::SetImage( const std::string& imageUrl, bool borderOnly ) } mImageUrl = imageUrl; - NinePatchImage nPatch = NinePatchImage::New( mImageUrl ); - InitialiseFromImage( 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 ) @@ -330,21 +491,25 @@ void NPatchRenderer::SetImage( NinePatchImage image, bool borderOnly ) } mImage = image; - InitialiseFromImage( mImage ); - - if( mCroppedImage && mImpl->mIsOnStage ) + if( mImpl->mRenderer ) { - ApplyImageToSampler(); + InitializeFromImage( mImage ); + ChangeRenderer( oldBorderOnly, oldGridX, oldGridY ); + + if( mCroppedImage ) + { + ApplyImageToSampler(); + } } } -void NPatchRenderer::InitialiseFromImage( NinePatchImage nPatch ) +void NPatchRenderer::InitializeFromImage( NinePatchImage nPatch ) { mCroppedImage = nPatch.CreateCroppedBufferImage(); if( !mCroppedImage ) { DALI_LOG_ERROR("'%s' specify a valid 9 patch image\n", mImageUrl.c_str() ); - CreateErrorImage(); + InitializeFromBrokenImage(); return; } @@ -354,21 +519,10 @@ void NPatchRenderer::InitialiseFromImage( NinePatchImage nPatch ) mStretchPixelsY = nPatch.GetStretchPixelsY(); } -void NPatchRenderer::CreateErrorImage() +void NPatchRenderer::InitializeFromBrokenImage() { - mImageSize = ImageDimensions( 1, 1 ); - - BufferImage bufferImage = BufferImage::New( mImageSize.GetWidth(), mImageSize.GetHeight(), Pixel::RGBA8888 ); - mCroppedImage = bufferImage; - PixelBuffer* pixbuf = bufferImage.GetBuffer(); - - for( size_t i = 0; i < mImageSize.GetWidth() * mImageSize.GetHeight() * 4u; ) - { - pixbuf[ i++ ] = 0; - pixbuf[ i++ ] = 0; - pixbuf[ i++ ] = 0; - pixbuf[ i++ ] = 255; - } + mCroppedImage = RendererFactory::GetBrokenRendererImage(); + mImageSize = ImageDimensions( mCroppedImage.GetWidth(), mCroppedImage.GetHeight() ); mStretchPixelsX.Clear(); mStretchPixelsX.PushBack( Uint16Pair( 0, mImageSize.GetWidth() ) ); @@ -378,38 +532,32 @@ void NPatchRenderer::CreateErrorImage() void NPatchRenderer::ApplyImageToSampler() { - Material material = mImpl->mRenderer.GetMaterial(); - if( material ) + TextureSet textureSet = mImpl->mRenderer.GetTextures(); + if( textureSet ) { - Sampler sampler; - for( std::size_t i = 0; i < material.GetNumberOfSamplers(); ++i ) - { - sampler = material.GetSamplerAt( i ); - if( sampler.GetUniformName() == TEXTURE_UNIFORM_NAME ) - { - sampler.SetImage( mCroppedImage ); - break; - } - } - if( !sampler ) - { - sampler = Sampler::New( mCroppedImage, TEXTURE_UNIFORM_NAME ); - material.AddSampler( sampler ); - } + TextureSetImage( textureSet, 0u, mCroppedImage ); - if( mStretchPixelsX.Size() > 0 && mStretchPixelsY.Size() > 0 ) + if( mStretchPixelsX.Size() == 1 && mStretchPixelsY.Size() == 1 ) { - //only 9 patch supported for now + //special case for 9 patch Uint16Pair stretchX = mStretchPixelsX[ 0 ]; Uint16Pair stretchY = mStretchPixelsY[ 0 ]; uint16_t stretchWidth = stretchX.GetY() - stretchX.GetX(); uint16_t stretchHeight = stretchY.GetY() - stretchY.GetX(); - sampler.RegisterProperty( "uFixed[0]", Vector2::ZERO ); - sampler.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) ); - sampler.RegisterProperty( "uFixed[2]", Vector2( mImageSize.GetWidth() - stretchWidth, mImageSize.GetHeight() - stretchHeight ) ); - sampler.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 + { + mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsX[0]", Vector2::ZERO ); + mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsY[0]", Vector2::ZERO ); + + RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsX", mStretchPixelsX, mImageSize.GetWidth() ); + RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsY", mStretchPixelsY, mImageSize.GetHeight() ); } } } @@ -433,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; @@ -490,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