2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include <dali/internal/render/renderers/scene-graph-text-renderer.h>
21 #include <dali/public-api/common/dali-common.h>
22 #include <dali/public-api/actors/text-actor.h>
23 #include <dali/internal/common/text-parameters.h>
24 #include <dali/internal/common/text-vertex-2d.h>
25 #include <dali/internal/render/gl-resources/context.h>
26 #include <dali/internal/render/common/performance-monitor.h>
27 #include <dali/internal/render/shaders/program.h>
28 #include <dali/internal/render/common/vertex.h>
29 #include <dali/internal/render/shaders/shader.h>
30 #include <dali/internal/render/gl-resources/texture-cache.h>
31 #include <dali/internal/update/controllers/scene-controller.h>
32 #include <dali/internal/render/gl-resources/texture.h>
36 #if defined(DEBUG_ENABLED)
39 Debug::Filter* gTextFilter = Debug::Filter::New(Debug::Concise, false, "LOG_SCENE_GRAPH_TEXT_RENDERER");
52 TextRenderer* TextRenderer::New( RenderDataProvider& dataprovider )
54 return new TextRenderer( dataprovider );
57 TextRenderer::~TextRenderer()
61 mTextureCache->RemoveObserver(mTextureId, this);
69 void TextRenderer::TextureDiscarded( ResourceId textureId )
71 DALI_ASSERT_DEBUG( mTextureId == textureId || mTextureId == 0 );
77 void TextRenderer::AllocateTextParameters()
79 if( !mTextParameters )
81 mTextParameters = new TextParameters;
85 void TextRenderer::SetTextureId( ResourceId textureId )
87 DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::SetTextureId(%d)\n", textureId );
91 mTextureCache->RemoveObserver(mTextureId, this);
94 mTextureId = textureId;
99 mTextureCache->AddObserver(textureId, this);
103 void TextRenderer::UpdateIndexBuffer( std::size_t size )
109 DALI_ASSERT_DEBUG( (size % 4 == 0) && "Invalid vertex length");
111 // @todo need to create a simple gpu-buffer-manager class which allow us
112 // to use a single indice buffer for all text-renderers and image renderers (minus 9 patch).
114 // number of indices(points) = number of (vertices / 4 ) = number of quads * 6
115 // to display the quad as two triangles (each triangle has 3 points).
116 // equivalent to 1.5 * number verts, which can be done with bit shifting.
117 std::size_t numberIndices = size + (size >> 1);
119 std::size_t numberQuads = size >> 2; // quads = verts / 4
121 GLushort* indices = new GLushort[ numberIndices ];
124 for( std::size_t i = 0; i < numberQuads; ++i )
133 * Draw 2 triangles with clock wise winding: 0->1->2 and 0->2->3
135 std::size_t vertIndex = i << 2; // vert index = i * 4
137 indices[ n++ ] = 0 + vertIndex;
138 indices[ n++ ] = 1 + vertIndex;
139 indices[ n++ ] = 2 + vertIndex;
141 indices[ n++ ] = 0 + vertIndex;
142 indices[ n++ ] = 2 + vertIndex;
143 indices[ n++ ] = 3 + vertIndex;
146 mIndexBuffer->UpdateDataBuffer( numberIndices * sizeof(GLushort),indices );
151 void TextRenderer::SetVertexData( TextVertexBuffer* vertexData )
153 DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::SetVertexData(this: %p, vertexData: %p)\n", this, vertexData );
157 DALI_ASSERT_DEBUG( 0 && "No vertex data"); // vertex data structure is required even for empty strings
160 if( vertexData->mVertices.size() > 0 )
162 SetTextureId(vertexData->mTextureId);
164 if ( !mVertexBuffer )
166 mVertexBuffer = new GpuBuffer( *mContext, GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW );
171 mIndexBuffer = new GpuBuffer( *mContext, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW );
174 mVertexBuffer->UpdateDataBuffer( vertexData->mVertices.size() * sizeof(TextVertex2D), &vertexData->mVertices[0] );
176 UpdateIndexBuffer( vertexData->mVertices.size() ); // Used in DoRender()
178 // Get inverted text size, as this is faster for the shader to operate on,
179 // and shader won't throw any errors performing a multiplication rather than a divide by zero
180 // on a bad size value.
181 mInvTextSize = vertexData->mVertexMax;
182 mInvTextSize.x = mInvTextSize.x > Math::MACHINE_EPSILON_1 ? 1.0f / mInvTextSize.x : 1.0f;
183 mInvTextSize.y = mInvTextSize.y > Math::MACHINE_EPSILON_1 ? 1.0f / mInvTextSize.y : 1.0f;
187 // no text to display, delete the GPU buffers, this will stop anything rendering.
188 mVertexBuffer.Reset();
189 mIndexBuffer.Reset();
191 // vertex data no longer required.
195 void TextRenderer::SetGradientColor( const Vector4& color )
197 AllocateTextParameters();
199 mTextParameters->mGradientColor = color;
202 void TextRenderer::SetGradientStartPoint( const Vector2& position )
204 AllocateTextParameters();
206 mTextParameters->mGradientStartPoint = position;
207 mTextParameters->mGradientEnabled = mTextParameters->mGradientEndPoint != mTextParameters->mGradientStartPoint;
210 void TextRenderer::SetGradientEndPoint( const Vector2& position )
212 AllocateTextParameters();
214 mTextParameters->mGradientEndPoint = position;
215 mTextParameters->mGradientEnabled = mTextParameters->mGradientEndPoint != mTextParameters->mGradientStartPoint;
218 void TextRenderer::SetTextColor( const Vector4& color )
220 if( NULL == mTextColor )
222 mTextColor = new Vector4( color );
230 void TextRenderer::SetOutline( const bool enable, const Vector4& color, const Vector2& params )
232 AllocateTextParameters();
234 mTextParameters->SetOutline( enable, color, params );
237 void TextRenderer::SetGlow( const bool enable, const Vector4& color, const float params )
239 AllocateTextParameters();
241 mTextParameters->SetGlow( enable, color, params );
244 void TextRenderer::SetDropShadow( const bool enable, const Vector4& color, const Vector2& offset, const float size )
246 AllocateTextParameters();
248 mTextParameters->SetShadow( enable, color, offset, size );
251 void TextRenderer::SetSmoothEdge( const float params )
256 void TextRenderer::GlCleanup()
258 mVertexBuffer.Reset();
259 mIndexBuffer.Reset();
262 bool TextRenderer::RequiresDepthTest() const
267 bool TextRenderer::CheckResources()
269 if ( ! ( mVertexBuffer && mIndexBuffer ) )
271 // This character has no geometry, must be a white space
275 if( !mVertexBuffer->BufferIsValid() )
280 if( mTexture == NULL )
282 mTexture = mTextureCache->GetTexture( mTextureId );
284 if( mTexture == NULL )
286 // texture atlas hasn't been created yet
290 if( mTexture->GetTextureId() == 0 )
298 void TextRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color )
300 if ( ! ( mVertexBuffer && mIndexBuffer ) )
302 // This character has no geometry, must be a white space
306 DALI_ASSERT_DEBUG( NULL != mTexture && "TextRenderer::DoRender. mTexture == NULL." );
308 DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::DoRender(this: %p) textureId:%d\n", this, mTextureId );
310 // If we have a color gradient, then we cannot use the default shader.
311 ShaderSubTypes shaderType( SHADER_DEFAULT );
312 if( mTextParameters )
314 if( mTextParameters->mOutlineEnabled )
316 if( mTextParameters->mGlowEnabled )
318 shaderType = SHADER_GRADIENT_OUTLINE_GLOW;
322 shaderType = SHADER_GRADIENT_OUTLINE;
325 else if( mTextParameters->mGlowEnabled )
327 shaderType = SHADER_GRADIENT_GLOW;
329 else if( mTextParameters->mDropShadowEnabled )
331 shaderType = SHADER_GRADIENT_SHADOW;
335 shaderType = SHADER_GRADIENT;
339 // Apply shader effect specific program and common uniforms
340 Program& program = mShader->Apply( *mContext, bufferIndex, GEOMETRY_TYPE_TEXT, modelMatrix, viewMatrix, modelViewMatrix, projectionMatrix, color, shaderType );
342 // Set sampler uniform
343 GLint samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER );
344 if( Program::UNIFORM_UNKNOWN != samplerLoc )
347 program.SetUniform1i( samplerLoc, 0 );
350 const int smoothingLoc = program.GetUniformLocation( Program::UNIFORM_SMOOTHING );
351 if( Program::UNIFORM_UNKNOWN != smoothingLoc )
353 program.SetUniform1f( smoothingLoc, mSmoothing );
356 if( mTextParameters )
358 if( mTextParameters->mOutlineEnabled )
360 const int outlineLoc = program.GetUniformLocation( Program::UNIFORM_OUTLINE );
361 const int outlineColorLoc = program.GetUniformLocation( Program::UNIFORM_OUTLINE_COLOR );
363 if( Program::UNIFORM_UNKNOWN != outlineLoc && Program::UNIFORM_UNKNOWN != outlineColorLoc )
365 program.SetUniform2f(outlineLoc, mTextParameters->mOutline[0], mTextParameters->mOutline[1]);
366 program.SetUniform4f(outlineColorLoc, mTextParameters->mOutlineColor.r, mTextParameters->mOutlineColor.g, mTextParameters->mOutlineColor.b, mTextParameters->mOutlineColor.a);
370 if( mTextParameters->mGlowEnabled )
372 const int glowLoc = program.GetUniformLocation( Program::UNIFORM_GLOW );
373 const int glowColorLoc = program.GetUniformLocation( Program::UNIFORM_GLOW_COLOR );
375 if( Program::UNIFORM_UNKNOWN != glowLoc && Program::UNIFORM_UNKNOWN != glowColorLoc )
377 // if mGlow is > mSmoothing we get an inverted glyph, so clamp the value
378 program.SetUniform1f(glowLoc, std::min(mTextParameters->mGlow, mSmoothing));
379 program.SetUniform4f(glowColorLoc, mTextParameters->mGlowColor.r, mTextParameters->mGlowColor.g, mTextParameters->mGlowColor.b, mTextParameters->mGlowColor.a);
383 if( mTextParameters->mDropShadowEnabled )
385 const int shadowLoc = program.GetUniformLocation( Program::UNIFORM_SHADOW );
386 const int shadowColorLoc = program.GetUniformLocation( Program::UNIFORM_SHADOW_COLOR );
387 const int shadowSmoothingLoc = program.GetUniformLocation( Program::UNIFORM_SHADOW_SMOOTHING );
389 if( Program::UNIFORM_UNKNOWN != shadowLoc && Program::UNIFORM_UNKNOWN != shadowColorLoc && Program::UNIFORM_UNKNOWN != shadowSmoothingLoc )
391 // convert shadow offset from tile to atlas coordinates
392 const Vector2 offset( mTextParameters->mDropShadow / mTexture->GetWidth());
393 program.SetUniform2f(shadowLoc, offset.x, offset.y);
394 program.SetUniform4f(shadowColorLoc, mTextParameters->mDropShadowColor.r, mTextParameters->mDropShadowColor.g, mTextParameters->mDropShadowColor.b, mTextParameters->mDropShadowColor.a);
395 program.SetUniform1f( shadowSmoothingLoc, std::max(0.0f, mSmoothing - mTextParameters->mDropShadowSize ) );
400 // Set the text color uniform
401 const int textColorLoc = program.GetUniformLocation( Program::UNIFORM_TEXT_COLOR );
402 if( Program::UNIFORM_UNKNOWN != textColorLoc )
404 Vector4 textColor( (NULL != mTextColor) ? *mTextColor : TextStyle::DEFAULT_TEXT_COLOR );
406 program.SetUniform4f(textColorLoc, textColor.r, textColor.g, textColor.b, textColor.a);
409 // All shaders except default shader require the uGradientLine.zw uniform to be set
410 // at the very least. (setting it to vec2(0.0, 0.0) will disable gradient)
411 if( shaderType != SHADER_DEFAULT )
413 Vector2 projection( Vector2::ZERO );
414 Vector2 startPoint( TextStyle::DEFAULT_GRADIENT_START_POINT );
416 if( mTextParameters )
418 startPoint = mTextParameters->mGradientStartPoint;
419 projection = mTextParameters->mGradientEndPoint - startPoint;
420 if( mTextParameters->mGradientEnabled ) // same as: mGradientEndPoint != mGradientStartPoint
422 projection /= projection.LengthSquared();
424 // For valid gradients Gradient Color and Text Size information must be set.
425 const int gradientColorLoc = program.GetUniformLocation( Program::UNIFORM_GRADIENT_COLOR );
426 const int textSizeLoc = program.GetUniformLocation( Program::UNIFORM_INVERSE_TEXT_SIZE );
428 if( Program::UNIFORM_UNKNOWN != gradientColorLoc && Program::UNIFORM_UNKNOWN != textSizeLoc )
430 const Vector4& color = mTextParameters->mGradientColor;
431 program.SetUniform4f( gradientColorLoc, color.r, color.g, color.b, color.a );
432 program.SetUniform2f( textSizeLoc, mInvTextSize.width, mInvTextSize.height );
437 // If we don't have a gradient present (mGradientEnabled) but the shader requires
438 // gradient information (gradientRequired), then we set
439 // uGradientLine.zw = vec2(0.0, 0.0) to force vColor = uColor in the expression.
440 // If we do have a gradient present, then we set up all information.
441 const int gradientLineLoc = program.GetUniformLocation( Program::UNIFORM_GRADIENT_LINE );
442 if( Program::UNIFORM_UNKNOWN != gradientLineLoc )
444 program.SetUniform4f( gradientLineLoc,
452 const int positionLoc = program.GetAttribLocation(Program::ATTRIB_POSITION);
453 const int texCoordLoc = program.GetAttribLocation(Program::ATTRIB_TEXCOORD);
455 mTexture->Bind(GL_TEXTURE_2D, GL_TEXTURE0);
457 mContext->EnableVertexAttributeArray( positionLoc );
458 mContext->EnableVertexAttributeArray( texCoordLoc );
461 DALI_ASSERT_DEBUG( mVertexBuffer->BufferIsValid() );
462 mVertexBuffer->Bind();
463 DALI_ASSERT_DEBUG( mIndexBuffer->BufferIsValid() );
464 mIndexBuffer->Bind();
467 mContext->VertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, sizeof(TextVertex2D), &v->mX);
468 mContext->VertexAttribPointer(texCoordLoc, 4, GL_FLOAT, GL_FALSE, sizeof(TextVertex2D), &v->mU);
470 const GLsizei indexCount = mIndexBuffer->GetBufferSize() / sizeof(GLushort); // compiler will optimize this to >> if possible
471 mContext->DrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, (void *) 0);
472 DRAW_ELEMENT_RECORD( indexCount );
474 mContext->DisableVertexAttributeArray( positionLoc );
475 mContext->DisableVertexAttributeArray( texCoordLoc );
478 TextRenderer::TextRenderer( RenderDataProvider& dataprovider )
479 : Renderer( dataprovider ),
483 mSmoothing( Dali::TextStyle::DEFAULT_SMOOTH_EDGE_DISTANCE_FIELD )
487 } // namespace SceneGraph
489 } // namespace Internal