2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/text/text-scroller.h>
22 #include <dali/public-api/common/stage.h>
23 #include <dali/public-api/images/frame-buffer-image.h>
24 #include <dali/public-api/render-tasks/render-task-list.h>
25 #include <dali/public-api/rendering/geometry.h>
26 #include <dali/public-api/rendering/renderer.h>
27 #include <dali/public-api/rendering/sampler.h>
28 #include <dali/public-api/rendering/shader.h>
29 #include <dali/devel-api/images/texture-set-image.h>
30 #include <dali/integration-api/debug.h>
33 #include <dali-toolkit/internal/text/text-scroller-interface.h>
34 #include <dali-toolkit/internal/text/text-scroller-data.h>
44 extern const int MINIMUM_SCROLL_SPEED;
50 #if defined ( DEBUG_ENABLED )
51 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_SCROLLING");
54 const char* VERTEX_SHADER_SCROLL = DALI_COMPOSE_SHADER(
55 attribute mediump vec2 aPosition;\n
56 varying highp vec2 vTexCoord;\n
57 varying highp float vRatio;\n
58 uniform mediump mat4 uMvpMatrix;\n
59 uniform mediump vec3 uSize;\n
60 uniform mediump float uDelta;\n
61 uniform mediump vec2 uTextureSize;
62 uniform mediump float uGap;\n
63 uniform mediump float uRtl;\n
68 mediump vec4 vertexPosition = vec4(aPosition*uSize.xy, 0.0, 1.0);\n
69 float smallTextPadding = max(uSize.x - uTextureSize.x, 0. );\n
70 float gap = max( uGap, smallTextPadding );\n
71 vTexCoord.x = ( uDelta + ( uRtl * ( uTextureSize.x - uSize.x ) ) + ( aPosition.x * uSize.x ) )/ ( uTextureSize.x+gap );\n
72 vTexCoord.y = aPosition.y;\n
73 vRatio = uTextureSize.x / ( uTextureSize.x + gap );\n
74 gl_Position = uMvpMatrix * vertexPosition;\n
79 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
80 varying mediump vec2 vTexCoord;\n
81 varying highp float vRatio;\n
82 uniform sampler2D sTexture;\n
86 mediump vec2 texCoord;\n
87 texCoord.y = vTexCoord.y;\n
88 texCoord.x = fract( vTexCoord.x ) / vRatio;\n
89 if ( texCoord.x > 1.0 )\n
92 gl_FragColor = texture2D( sTexture, texCoord );\n
97 * @brief Create and set up a camera for the render task to use
99 * @param[in] sizeOfTarget size of the source camera to look at
100 * @param[out] offscreenCamera custom camera
102 void CreateCameraActor( const Size& sizeOfTarget, CameraActor& offscreenCamera )
104 offscreenCamera = CameraActor::New();
105 offscreenCamera.SetOrthographicProjection( sizeOfTarget );
106 offscreenCamera.SetInvertYAxis( true );
110 * @brief Create a render task
112 * @param[in] sourceActor actor to be used as source
113 * @param[in] cameraActor camera looking at source
114 * @param[in] offscreenTarget resulting image from render task
115 * @param[out] renderTask render task that has been setup
117 void CreateRenderTask( Actor sourceActor, CameraActor cameraActor , FrameBufferImage offscreenTarget, RenderTask& renderTask )
119 Stage stage = Stage::GetCurrent();
120 RenderTaskList taskList = stage.GetRenderTaskList();
121 renderTask = taskList.CreateTask();
122 renderTask.SetSourceActor( sourceActor );
123 renderTask.SetExclusive( true );
124 renderTask.SetInputEnabled( false );
125 renderTask.SetClearEnabled( true );
126 renderTask.SetCameraActor( cameraActor );
127 renderTask.SetTargetFrameBuffer( offscreenTarget );
128 renderTask.SetClearColor( Color::TRANSPARENT );
129 renderTask.SetCullMode( false );
133 * @brief Create quad geometry for the mesh
135 * @param[out] geometry quad geometry that can be used for a mesh
137 void CreateGeometry( Geometry& geometry )
139 struct QuadVertex { Vector2 position; };
141 QuadVertex quadVertexData[4] =
143 { Vector2( 0.0f, 0.0f) },
144 { Vector2( 1.0f, 0.0f) },
145 { Vector2( 0.0f, 1.0f) },
146 { Vector2( 1.0f, 1.0f) },
149 const unsigned short indices[6] =
154 Property::Map quadVertexFormat;
155 quadVertexFormat["aPosition"] = Property::VECTOR2;
156 PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
157 quadVertices.SetData(quadVertexData, 4 );
159 geometry = Geometry::New();
160 geometry.AddVertexBuffer( quadVertices );
161 geometry.SetIndexBuffer( indices, sizeof(indices)/sizeof(indices[0]) );
166 * @brief Create a renderer
168 * @param[in] frameBufferImage texture to be used
169 * @param[out] renderer mesh renderer using the supplied texture
171 void CreateRenderer( FrameBufferImage frameBufferImage, Dali::Renderer& renderer )
173 Shader shader = Shader::New( VERTEX_SHADER_SCROLL , FRAGMENT_SHADER, Shader::Hint::NONE );
175 Sampler sampler = Sampler::New();
176 sampler.SetFilterMode(FilterMode::NEAREST, FilterMode::NEAREST );
178 TextureSet textureSet = TextureSet::New();
179 TextureSetImage( textureSet, 0u, frameBufferImage );
180 textureSet.SetSampler( 0u, sampler );
182 Geometry meshGeometry;
183 CreateGeometry( meshGeometry );
185 renderer = Renderer::New( meshGeometry, shader );
186 renderer.SetTextures( textureSet );
194 TextScrollerPtr TextScroller::New( ScrollerInterface& scrollerInterface )
196 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::New\n" );
198 TextScrollerPtr textScroller( new TextScroller( scrollerInterface) );
202 Actor TextScroller::GetSourceCamera() const
204 return mOffscreenCameraActor;
207 Actor TextScroller::GetScrollingText() const
209 return mScrollingTextActor;
212 TextScroller::TextScroller( ScrollerInterface& scrollerInterface )
213 : mScrollerInterface( scrollerInterface ),
214 mScrollDeltaIndex( Property::INVALID_INDEX )
216 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller Default Constructor\n" );
219 TextScroller::~TextScroller()
224 void TextScroller::StartScrolling( Actor sourceActor,
225 const ScrollerData& data )
227 DALI_LOG_INFO( gLogFilter,
229 "TextScroller::StartScrolling controlSize[%f,%f] offscreenSize[%f,%f] direction[%d] alignmentOffset[%f]\n",
230 data.mControlSize.x, data.mControlSize.y,
231 data.mOffscreenSize.x, data.mOffscreenSize.y,
232 data.mAutoScrollDirectionRTL,
233 data.mAlignmentOffset );
235 FrameBufferImage offscreenRenderTargetForText = FrameBufferImage::New( data.mOffscreenSize.width, data.mOffscreenSize.height, Pixel::RGBA8888 );
238 CreateCameraActor( data.mOffscreenSize, mOffscreenCameraActor );
239 CreateRenderer( offscreenRenderTargetForText, renderer );
240 CreateRenderTask( sourceActor, mOffscreenCameraActor, offscreenRenderTargetForText, mRenderTask );
242 // Reposition camera to match alignment of target, RTL text has direction=true
243 if( data.mAutoScrollDirectionRTL )
245 mOffscreenCameraActor.SetX( data.mAlignmentOffset + data.mOffscreenSize.width * 0.5f );
249 mOffscreenCameraActor.SetX( data.mOffscreenSize.width * 0.5f );
252 mOffscreenCameraActor.SetY( data.mOffscreenSize.height * 0.5f );
254 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters mWrapGap[%f]\n", data.mWrapGap )
256 mScrollingTextActor = Actor::New();
257 mScrollingTextActor.AddRenderer( renderer );
258 mScrollingTextActor.RegisterProperty( "uTextureSize", data.mOffscreenSize );
259 mScrollingTextActor.RegisterProperty( "uRtl", ( data.mAutoScrollDirectionRTL ? 1.f : 0.f ) );
260 mScrollingTextActor.RegisterProperty( "uGap", data.mWrapGap );
261 mScrollingTextActor.SetSize( data.mControlSize.width, std::min( data.mOffscreenSize.height, data.mControlSize.height ) );
262 mScrollDeltaIndex = mScrollingTextActor.RegisterProperty( "uDelta", 0.0f );
264 float scrollAmount = std::max( data.mOffscreenSize.width + data.mWrapGap, data.mControlSize.width );
265 float scrollSpeed = std::max( MINIMUM_SCROLL_SPEED, data.mScrollSpeed );
266 float scrollDuration = scrollAmount / scrollSpeed;
268 if( data.mAutoScrollDirectionRTL )
270 scrollAmount = -scrollAmount; // reverse direction of scrollung
273 mScrollAnimation = Animation::New( scrollDuration );
274 mScrollAnimation.AnimateTo( Property( mScrollingTextActor, mScrollDeltaIndex ), scrollAmount );
275 mScrollAnimation.SetEndAction( Animation::Discard );
276 mScrollAnimation.SetLoopCount( data.mLoopCount );
277 mScrollAnimation.FinishedSignal().Connect( this, &TextScroller::AutoScrollAnimationFinished );
278 mScrollAnimation.Play();
281 void TextScroller::StopScrolling()
283 if( mScrollAnimation &&
284 ( mScrollAnimation.GetState() == Animation::PLAYING ) )
286 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetLoopCount Single loop forced\n" );
287 mScrollAnimation.SetLoopCount( 1 ); // As animation already playing this allows the current animation to finish instead of trying to stop mid-way
291 void TextScroller::AutoScrollAnimationFinished( Dali::Animation& animation )
293 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::AutoScrollAnimationFinished\n" );
295 mScrollerInterface.ScrollingFinished();
298 void TextScroller::CleanUp()
300 if ( Stage::IsInstalled() )
302 Stage stage = Stage::GetCurrent();
303 RenderTaskList taskList = stage.GetRenderTaskList();
304 UnparentAndReset( mScrollingTextActor );
305 UnparentAndReset( mOffscreenCameraActor );
306 taskList.RemoveTask( mRenderTask );
312 } // namespace Toolkit