2 * Copyright (c) 2014 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/internal/render/renderers/scene-graph-text-renderer.h>
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/public-api/actors/text-actor.h>
24 #include <dali/internal/common/text-parameters.h>
25 #include <dali/internal/common/text-vertex-2d.h>
26 #include <dali/internal/event/text/font-impl.h>
27 #include <dali/internal/render/gl-resources/context.h>
28 #include <dali/internal/render/common/culling-algorithms.h>
29 #include <dali/internal/render/common/performance-monitor.h>
30 #include <dali/internal/render/common/vertex.h>
31 #include <dali/internal/render/renderers/scene-graph-renderer-debug.h>
32 #include <dali/internal/render/shaders/program.h>
33 #include <dali/internal/render/shaders/shader.h>
34 #include <dali/internal/render/gl-resources/texture-cache.h>
35 #include <dali/internal/render/gl-resources/texture.h>
36 #include <dali/internal/update/controllers/scene-controller.h>
40 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gTextFilter = Debug::Filter::New(Debug::Concise, false, "LOG_SCENE_GRAPH_TEXT_RENDERER");
56 TextRenderer* TextRenderer::New( RenderDataProvider& dataprovider )
58 return new TextRenderer( dataprovider );
61 TextRenderer::~TextRenderer()
65 mTextureCache->RemoveObserver(mTextureId, this);
73 void TextRenderer::TextureDiscarded( ResourceId textureId )
75 DALI_ASSERT_DEBUG( mTextureId == textureId || mTextureId == 0 );
81 void TextRenderer::AllocateTextParameters()
83 if( !mTextParameters )
85 mTextParameters = new TextParameters;
89 void TextRenderer::SetTextureId( ResourceId textureId )
91 DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::SetTextureId(%d)\n", textureId );
95 mTextureCache->RemoveObserver(mTextureId, this);
98 mTextureId = textureId;
103 mTextureCache->AddObserver(textureId, this);
107 void TextRenderer::UpdateIndexBuffer( std::size_t size )
113 DALI_ASSERT_DEBUG( (size % 4 == 0) && "Invalid vertex length");
115 // @todo need to create a simple gpu-buffer-manager class which allow us
116 // to use a single indice buffer for all text-renderers and image renderers (minus 9 patch).
118 // number of indices(points) = number of (vertices / 4 ) = number of quads * 6
119 // to display the quad as two triangles (each triangle has 3 points).
120 // equivalent to 1.5 * number verts, which can be done with bit shifting.
121 std::size_t numberIndices = size + (size >> 1);
123 std::size_t numberQuads = size >> 2; // quads = verts / 4
125 GLushort* indices = new GLushort[ numberIndices ];
128 for( std::size_t i = 0; i < numberQuads; ++i )
137 * Draw 2 triangles with clock wise winding: 0->1->2 and 0->2->3
139 std::size_t vertIndex = i << 2; // vert index = i * 4
141 indices[ n++ ] = 0 + vertIndex;
142 indices[ n++ ] = 1 + vertIndex;
143 indices[ n++ ] = 2 + vertIndex;
145 indices[ n++ ] = 0 + vertIndex;
146 indices[ n++ ] = 2 + vertIndex;
147 indices[ n++ ] = 3 + vertIndex;
150 mIndexBuffer->UpdateDataBuffer( numberIndices * sizeof(GLushort),indices );
155 void TextRenderer::SetVertexData( TextVertexBuffer* vertexData )
157 DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::SetVertexData(this: %p, vertexData: %p)\n", this, vertexData );
161 DALI_ASSERT_DEBUG( 0 && "No vertex data"); // vertex data structure is required even for empty strings
164 if( vertexData->mVertices.size() > 0 )
166 SetTextureId(vertexData->mTextureId);
168 if ( !mVertexBuffer )
170 mVertexBuffer = new GpuBuffer( *mContext, GpuBuffer::ARRAY_BUFFER, GpuBuffer::DYNAMIC_DRAW );
175 mIndexBuffer = new GpuBuffer( *mContext, GpuBuffer::ELEMENT_ARRAY_BUFFER, GpuBuffer::STATIC_DRAW );
178 mVertexBuffer->UpdateDataBuffer( vertexData->mVertices.size() * sizeof(TextVertex2D), &vertexData->mVertices[0] );
180 UpdateIndexBuffer( vertexData->mVertices.size() ); // Used in DoRender()
182 // Get inverted text size, as this is faster for the shader to operate on,
183 // and shader won't throw any errors performing a multiplication rather than a divide by zero
184 // on a bad size value.
185 mGeometryExtent = vertexData->mGeometryExtent;
189 // no text to display, delete the GPU buffers, this will stop anything rendering.
190 mVertexBuffer.Reset();
191 mIndexBuffer.Reset();
193 // vertex data no longer required.
197 void TextRenderer::SetFontSize( float pixelSize )
199 mPixelSize = pixelSize;
202 void TextRenderer::SetGradient( const Vector4& color, const Vector2& startPoint, const Vector2& endPoint )
204 AllocateTextParameters();
205 mTextParameters->SetGradient( color, startPoint, endPoint );
208 void TextRenderer::SetTextColor( const Vector4& color )
210 if( NULL == mTextColor )
212 mTextColor = new Vector4( color );
220 void TextRenderer::SetOutline( const bool enable, const Vector4& color, const Vector2& params )
222 AllocateTextParameters();
224 mTextParameters->SetOutline( enable, color, params );
227 void TextRenderer::SetGlow( const bool enable, const Vector4& color, const float params )
229 AllocateTextParameters();
231 mTextParameters->SetGlow( enable, color, params );
234 void TextRenderer::SetDropShadow( const bool enable, const Vector4& color, const Vector2& offset, const float size )
236 AllocateTextParameters();
238 mTextParameters->SetShadow( enable, color, offset, size );
241 void TextRenderer::SetSmoothEdge( float params )
246 void TextRenderer::GlContextDestroyed()
250 mVertexBuffer->GlContextDestroyed();
254 mIndexBuffer->GlContextDestroyed();
258 void TextRenderer::GlCleanup()
260 mVertexBuffer.Reset();
261 mIndexBuffer.Reset();
264 bool TextRenderer::RequiresDepthTest() const
269 bool TextRenderer::CheckResources()
271 if ( ! ( mVertexBuffer && mIndexBuffer ) )
273 // This character has no geometry, must be a white space
277 if( !mVertexBuffer->BufferIsValid() )
282 if( mTexture == NULL )
284 mTexture = mTextureCache->GetTexture( mTextureId );
286 if( mTexture == NULL )
288 // texture atlas hasn't been created yet
292 if( mTexture->GetTextureId() == 0 )
300 void TextRenderer::ResolveGeometryTypes( BufferIndex bufferIndex, GeometryType& outType, ShaderSubTypes& outSubType )
302 outType = GEOMETRY_TYPE_TEXT;
304 // If we have a color gradient, then we cannot use the default shader.
306 outSubType = SHADER_DEFAULT;
307 if( mTextParameters )
309 if( mTextParameters->IsOutlineEnabled() )
311 if( mTextParameters->IsGlowEnabled() )
313 outSubType = SHADER_GRADIENT_OUTLINE_GLOW;
317 outSubType = SHADER_GRADIENT_OUTLINE;
320 else if( mTextParameters->IsGlowEnabled() )
322 outSubType = SHADER_GRADIENT_GLOW;
324 else if( mTextParameters->IsDropShadowEnabled() )
326 outSubType = SHADER_GRADIENT_SHADOW;
330 outSubType = SHADER_GRADIENT;
335 bool TextRenderer::IsOutsideClipSpace( const Matrix& modelMatrix, const Matrix& modelViewProjectionMatrix )
337 mContext->IncrementRendererCount();
339 Rect<float> boundingBox(mGeometryExtent.width*-0.5f, mGeometryExtent.height*-0.5f, mGeometryExtent.width, mGeometryExtent.height);
340 DEBUG_BOUNDING_BOX( *mContext, boundingBox, modelViewProjectionMatrix );
342 if(Is2dBoxOutsideClipSpace( modelMatrix, modelViewProjectionMatrix, boundingBox ) )
344 mContext->IncrementCulledCount();
350 void TextRenderer::DoRender( BufferIndex bufferIndex, Program& program, const Matrix& modelViewMatrix, const Matrix& viewMatrix )
352 DALI_ASSERT_DEBUG( NULL != mTexture && "TextRenderer::DoRender. mTexture == NULL." );
354 DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::DoRender(this: %p) textureId:%d\n", this, mTextureId );
356 // Set sampler uniform
357 const GLint samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER );
358 if( Program::UNIFORM_UNKNOWN != samplerLoc )
361 program.SetUniform1i( samplerLoc, 0 );
364 const float SMOOTHING_ADJUSTMENT( 12.0f );
365 const float SMOOTHING_ADJUSTMENT_PIXEL_SIZE( 32.0f );
367 float smoothWidth = SMOOTHING_ADJUSTMENT / mPixelSize;
368 float smoothing = mSmoothing;
370 const GLint smoothingLoc = program.GetUniformLocation( Program::UNIFORM_SMOOTHING );
371 if( Program::UNIFORM_UNKNOWN != smoothingLoc )
373 smoothWidth = min( min(mSmoothing, 1.0f - mSmoothing), smoothWidth );
375 if( mPixelSize < SMOOTHING_ADJUSTMENT_PIXEL_SIZE )
377 smoothing *= Lerp( mPixelSize / SMOOTHING_ADJUSTMENT_PIXEL_SIZE, 0.5f, 1.0f );
380 program.SetUniform2f( smoothingLoc, std::max(0.0f, smoothing - smoothWidth), std::min(1.0f, smoothing + smoothWidth) );
383 if( mTextParameters )
385 if( mTextParameters->IsOutlineEnabled() )
387 const GLint outlineLoc = program.GetUniformLocation( Program::UNIFORM_OUTLINE );
388 const GLint outlineColorLoc = program.GetUniformLocation( Program::UNIFORM_OUTLINE_COLOR );
390 if( Program::UNIFORM_UNKNOWN != outlineLoc && Program::UNIFORM_UNKNOWN != outlineColorLoc )
392 const Vector2& outline = mTextParameters->GetOutlineThickness();
393 const Vector4& outlineColor = mTextParameters->GetOutlineColor();
394 float outlineWidth = outline[1] + smoothWidth;
395 float outlineStart = outline[0];
396 float outlineEnd = min( 1.0f, outlineStart + outlineWidth );
398 program.SetUniform2f(outlineLoc, outlineStart, outlineEnd);
399 program.SetUniform4f(outlineColorLoc, outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a);
403 if( mTextParameters->IsGlowEnabled() )
405 const GLint glowLoc = program.GetUniformLocation( Program::UNIFORM_GLOW );
406 const GLint glowColorLoc = program.GetUniformLocation( Program::UNIFORM_GLOW_COLOR );
408 if( Program::UNIFORM_UNKNOWN != glowLoc && Program::UNIFORM_UNKNOWN != glowColorLoc )
410 // if mGlow is > mSmoothing we get an inverted glyph, so clamp the value
411 program.SetUniform1f(glowLoc, std::min(mTextParameters->GetGlowIntensity(), mSmoothing));
412 const Vector4& glowColor = mTextParameters->GetGlowColor();
413 program.SetUniform4f(glowColorLoc, glowColor.r, glowColor.g, glowColor.b, glowColor.a);
417 if( mTextParameters->IsDropShadowEnabled() )
419 const GLint shadowLoc = program.GetUniformLocation( Program::UNIFORM_SHADOW );
420 const GLint shadowColorLoc = program.GetUniformLocation( Program::UNIFORM_SHADOW_COLOR );
421 const GLint shadowSmoothingLoc = program.GetUniformLocation( Program::UNIFORM_SHADOW_SMOOTHING );
423 if( Program::UNIFORM_UNKNOWN != shadowLoc && Program::UNIFORM_UNKNOWN != shadowColorLoc && Program::UNIFORM_UNKNOWN != shadowSmoothingLoc )
425 // convert shadow offset from tile to atlas coordinates
426 const Vector2& offset( mTextParameters->GetDropShadowOffset() / mTexture->GetWidth());
427 float shadowSmoothing = std::max(0.0f, smoothing - mTextParameters->GetDropShadowSize() );
428 program.SetUniform2f(shadowLoc, offset.x, offset.y);
429 const Vector4& dropShadowColor = mTextParameters->GetDropShadowColor();
430 program.SetUniform4f(shadowColorLoc, dropShadowColor.r, dropShadowColor.g, dropShadowColor.b, dropShadowColor.a);
431 program.SetUniform2f( shadowSmoothingLoc, std::max(0.0f, shadowSmoothing - smoothWidth), std::min(1.0f, shadowSmoothing + smoothWidth) );
436 // Set the text color uniform
437 const GLint textColorLoc = program.GetUniformLocation( Program::UNIFORM_TEXT_COLOR );
438 if( Program::UNIFORM_UNKNOWN != textColorLoc )
440 Vector4 textColor( (NULL != mTextColor) ? *mTextColor : TextStyle::DEFAULT_TEXT_COLOR );
442 program.SetUniform4f(textColorLoc, textColor.r, textColor.g, textColor.b, textColor.a);
445 if( mTextParameters )
447 // All shaders except default shader require the uGradientLine.zw uniform to be set
448 // at the very least. (setting it to vec2(0.0, 0.0) will disable gradient)
449 Vector2 projection( Vector2::ZERO );
450 Vector2 startPoint( TextStyle::DEFAULT_GRADIENT_START_POINT );
451 startPoint = mTextParameters->GetGradientStartPoint();
452 projection = mTextParameters->GetGradientEndPoint() - startPoint;
453 if( mTextParameters->IsGradientEnabled() ) // same as: mGradientEndPoint != mGradientStartPoint
455 projection /= projection.LengthSquared();
457 // For valid gradients Gradient Color and Text Size information must be set.
458 const GLint gradientColorLoc = program.GetUniformLocation( Program::UNIFORM_GRADIENT_COLOR );
459 const GLint textSizeLoc = program.GetUniformLocation( Program::UNIFORM_INVERSE_TEXT_SIZE );
461 if( Program::UNIFORM_UNKNOWN != gradientColorLoc && Program::UNIFORM_UNKNOWN != textSizeLoc )
463 const Vector4& color = mTextParameters->GetGradientColor();
464 program.SetUniform4f( gradientColorLoc, color.r, color.g, color.b, color.a );
466 Vector2 invTextSize( mGeometryExtent );
467 invTextSize.x = invTextSize.x > Math::MACHINE_EPSILON_1 ? 1.0f / invTextSize.x : 1.0f;
468 invTextSize.y = invTextSize.y > Math::MACHINE_EPSILON_1 ? 1.0f / invTextSize.y : 1.0f;
470 program.SetUniform2f( textSizeLoc, invTextSize.width, invTextSize.height );
474 // If we don't have a gradient present (mGradientEnabled) but the shader requires
475 // gradient information (gradientRequired), then we set
476 // uGradientLine.zw = vec2(0.0, 0.0) to force vColor = uColor in the expression.
477 // If we do have a gradient present, then we set up all information.
478 const GLint gradientLineLoc = program.GetUniformLocation( Program::UNIFORM_GRADIENT_LINE );
479 if( Program::UNIFORM_UNKNOWN != gradientLineLoc )
481 program.SetUniform4f( gradientLineLoc,
489 const GLint positionLoc = program.GetAttribLocation(Program::ATTRIB_POSITION);
490 const GLint texCoordLoc = program.GetAttribLocation(Program::ATTRIB_TEXCOORD);
492 mTexture->Bind(GL_TEXTURE_2D, GL_TEXTURE0);
493 mTexture->ApplySampler( mSamplerBitfield );
495 mContext->EnableVertexAttributeArray( positionLoc );
496 mContext->EnableVertexAttributeArray( texCoordLoc );
499 DALI_ASSERT_DEBUG( mVertexBuffer->BufferIsValid() );
500 mVertexBuffer->Bind();
501 DALI_ASSERT_DEBUG( mIndexBuffer->BufferIsValid() );
502 mIndexBuffer->Bind();
505 mContext->VertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, sizeof(TextVertex2D), &v->mX);
506 mContext->VertexAttribPointer(texCoordLoc, 4, GL_FLOAT, GL_FALSE, sizeof(TextVertex2D), &v->mU);
508 const GLsizei indexCount = mIndexBuffer->GetBufferSize() / sizeof(GLushort); // compiler will optimize this to >> if possible
509 mContext->DrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, (void *) 0);
510 DRAW_ELEMENT_RECORD( indexCount );
512 mContext->DisableVertexAttributeArray( positionLoc );
513 mContext->DisableVertexAttributeArray( texCoordLoc );
517 TextRenderer::TextRenderer( RenderDataProvider& dataprovider )
518 : Renderer( dataprovider ),
526 mSmoothing( Dali::TextStyle::DEFAULT_SMOOTH_EDGE_DISTANCE_FIELD ),
531 } // namespace SceneGraph
533 } // namespace Internal