Emscripten workarounds and llvm syntax fixes
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / scene-graph-text-renderer.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
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
7 //
8 //     http://floralicense.org/license/
9 //
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.
15 //
16
17 // CLASS HEADER
18 #include <dali/internal/render/renderers/scene-graph-text-renderer.h>
19
20 // INTERNAL INCLUDES
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>
33
34 using namespace std;
35
36 #if defined(DEBUG_ENABLED)
37 namespace
38 {
39 Debug::Filter* gTextFilter = Debug::Filter::New(Debug::Concise, false, "LOG_SCENE_GRAPH_TEXT_RENDERER");
40 }
41 #endif
42
43 namespace Dali
44 {
45
46 namespace Internal
47 {
48
49 namespace SceneGraph
50 {
51
52 TextRenderer* TextRenderer::New( RenderDataProvider& dataprovider )
53 {
54   return new TextRenderer( dataprovider );
55 }
56
57 TextRenderer::~TextRenderer()
58 {
59   if(mTextureId > 0)
60   {
61     mTextureCache->RemoveObserver(mTextureId, this);
62   }
63
64   GlCleanup();
65
66   delete mTextColor;
67 }
68
69 void TextRenderer::TextureDiscarded( ResourceId textureId )
70 {
71   DALI_ASSERT_DEBUG( mTextureId == textureId || mTextureId == 0 );
72
73   mTextureId = 0;
74   mTexture = NULL;
75 }
76
77 void TextRenderer::AllocateTextParameters()
78 {
79   if( !mTextParameters )
80   {
81     mTextParameters = new TextParameters;
82   }
83 }
84
85 void TextRenderer::SetTextureId( ResourceId textureId )
86 {
87   DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::SetTextureId(%d)\n", textureId );
88
89   if(mTextureId > 0)
90   {
91     mTextureCache->RemoveObserver(mTextureId, this);
92   }
93
94   mTextureId = textureId;
95   mTexture = NULL;
96
97   if(textureId > 0)
98   {
99     mTextureCache->AddObserver(textureId, this);
100   }
101 }
102
103 void TextRenderer::UpdateIndexBuffer( std::size_t size )
104 {
105   if( size == 0)
106   {
107     return;
108   }
109   DALI_ASSERT_DEBUG( (size % 4 == 0) && "Invalid vertex length");
110
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).
113
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);
118
119   std::size_t numberQuads =  size >> 2;  // quads = verts / 4
120
121   GLushort* indices = new GLushort[ numberIndices  ];
122
123   std::size_t n = 0;
124   for( std::size_t i = 0; i < numberQuads; ++i )
125   {
126     /*
127      * 1 --- 2
128      * |    /|
129      * |  A  |
130      * | /   |
131      * 0 --- 3
132      *
133      * Draw 2 triangles with clock wise winding: 0->1->2 and 0->2->3
134      */
135     std::size_t vertIndex = i << 2;  // vert index = i * 4
136
137     indices[ n++ ] = 0 + vertIndex;
138     indices[ n++ ] = 1 + vertIndex;
139     indices[ n++ ] = 2 + vertIndex;
140
141     indices[ n++ ] = 0 + vertIndex;
142     indices[ n++ ] = 2 + vertIndex;
143     indices[ n++ ] = 3 + vertIndex;
144   }
145
146   mIndexBuffer->UpdateDataBuffer( numberIndices * sizeof(GLushort),indices );
147
148   delete []indices;
149 }
150
151 void TextRenderer::SetVertexData( TextVertexBuffer* vertexData )
152 {
153   DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::SetVertexData(this: %p, vertexData: %p)\n", this, vertexData );
154
155   if( !vertexData )
156   {
157     DALI_ASSERT_DEBUG( 0 && "No vertex data");  // vertex data structure is required even for empty strings
158     return;
159   }
160   if( vertexData->mVertices.size() > 0 )
161   {
162     SetTextureId(vertexData->mTextureId);
163
164     if ( !mVertexBuffer )
165     {
166       mVertexBuffer = new GpuBuffer( *mContext, GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW );
167     }
168
169     if ( !mIndexBuffer )
170     {
171       mIndexBuffer = new GpuBuffer( *mContext, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW );
172     }
173
174     mVertexBuffer->UpdateDataBuffer( vertexData->mVertices.size() * sizeof(TextVertex2D), &vertexData->mVertices[0] );
175
176     UpdateIndexBuffer( vertexData->mVertices.size() ); // Used in DoRender()
177
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;
184   }
185   else
186   {
187     // no text to display, delete the GPU buffers, this will stop anything rendering.
188     mVertexBuffer.Reset();
189     mIndexBuffer.Reset();
190   }
191   // vertex data no longer required.
192   delete vertexData;
193 }
194
195 void TextRenderer::SetGradientColor( const Vector4& color )
196 {
197   AllocateTextParameters();
198
199   mTextParameters->mGradientColor = color;
200 }
201
202 void TextRenderer::SetGradientStartPoint( const Vector2& position )
203 {
204   AllocateTextParameters();
205
206   mTextParameters->mGradientStartPoint = position;
207   mTextParameters->mGradientEnabled = mTextParameters->mGradientEndPoint != mTextParameters->mGradientStartPoint;
208 }
209
210 void TextRenderer::SetGradientEndPoint( const Vector2& position )
211 {
212   AllocateTextParameters();
213
214   mTextParameters->mGradientEndPoint = position;
215   mTextParameters->mGradientEnabled = mTextParameters->mGradientEndPoint != mTextParameters->mGradientStartPoint;
216 }
217
218 void TextRenderer::SetTextColor( const Vector4& color )
219 {
220   if( NULL == mTextColor )
221   {
222     mTextColor = new Vector4( color );
223   }
224   else
225   {
226     *mTextColor = color;
227   }
228 }
229
230 void TextRenderer::SetOutline( const bool enable, const Vector4& color, const Vector2& params )
231 {
232   AllocateTextParameters();
233
234   mTextParameters->SetOutline( enable, color, params );
235 }
236
237 void TextRenderer::SetGlow( const bool enable, const Vector4& color, const float params )
238 {
239   AllocateTextParameters();
240
241   mTextParameters->SetGlow( enable, color, params );
242 }
243
244 void TextRenderer::SetDropShadow( const bool enable, const Vector4& color, const Vector2& offset, const float size )
245 {
246   AllocateTextParameters();
247
248   mTextParameters->SetShadow( enable, color, offset, size );
249 }
250
251 void TextRenderer::SetSmoothEdge( const float params )
252 {
253   mSmoothing = params;
254 }
255
256 void TextRenderer::GlCleanup()
257 {
258   mVertexBuffer.Reset();
259   mIndexBuffer.Reset();
260 }
261
262 bool TextRenderer::RequiresDepthTest() const
263 {
264   return false;
265 }
266
267 bool TextRenderer::CheckResources()
268 {
269   if ( ! ( mVertexBuffer && mIndexBuffer ) )
270   {
271     // This character has no geometry, must be a white space
272     return true;
273   }
274
275   if( !mVertexBuffer->BufferIsValid() )
276   {
277     return false;
278   }
279
280   if( mTexture == NULL )
281   {
282     mTexture = mTextureCache->GetTexture( mTextureId );
283
284     if( mTexture == NULL )
285     {
286       // texture atlas hasn't been created yet
287       return false;
288     }
289   }
290   if( mTexture->GetTextureId() == 0 )
291   {
292     return false;
293   }
294
295   return true;
296 }
297
298 void TextRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color )
299 {
300   if ( ! ( mVertexBuffer && mIndexBuffer ) )
301   {
302     // This character has no geometry, must be a white space
303     return;
304   }
305
306   DALI_ASSERT_DEBUG( NULL != mTexture && "TextRenderer::DoRender. mTexture == NULL." );
307
308   DALI_LOG_INFO( gTextFilter, Debug::General, "TextRenderer::DoRender(this: %p) textureId:%d\n", this, mTextureId );
309
310   // If we have a color gradient, then we cannot use the default shader.
311   ShaderSubTypes shaderType( SHADER_DEFAULT );
312   if( mTextParameters )
313   {
314     if( mTextParameters->mOutlineEnabled )
315     {
316       if( mTextParameters->mGlowEnabled )
317       {
318         shaderType = SHADER_GRADIENT_OUTLINE_GLOW;
319       }
320       else
321       {
322         shaderType = SHADER_GRADIENT_OUTLINE;
323       }
324     }
325     else if( mTextParameters->mGlowEnabled )
326     {
327       shaderType = SHADER_GRADIENT_GLOW;
328     }
329     else if( mTextParameters->mDropShadowEnabled )
330     {
331       shaderType = SHADER_GRADIENT_SHADOW;
332     }
333     else
334     {
335       shaderType = SHADER_GRADIENT;
336     }
337   }
338
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 );
341
342   // Set sampler uniform
343   GLint samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER );
344   if( Program::UNIFORM_UNKNOWN != samplerLoc )
345   {
346     // set the uniform
347     program.SetUniform1i( samplerLoc, 0 );
348   }
349
350   const int smoothingLoc = program.GetUniformLocation( Program::UNIFORM_SMOOTHING );
351   if( Program::UNIFORM_UNKNOWN != smoothingLoc )
352   {
353     program.SetUniform1f( smoothingLoc, mSmoothing );
354   }
355
356   if( mTextParameters )
357   {
358     if( mTextParameters->mOutlineEnabled )
359     {
360       const int outlineLoc = program.GetUniformLocation( Program::UNIFORM_OUTLINE );
361       const int outlineColorLoc = program.GetUniformLocation( Program::UNIFORM_OUTLINE_COLOR );
362
363       if( Program::UNIFORM_UNKNOWN != outlineLoc && Program::UNIFORM_UNKNOWN != outlineColorLoc )
364       {
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);
367       }
368     }
369
370     if( mTextParameters->mGlowEnabled )
371     {
372       const int glowLoc = program.GetUniformLocation( Program::UNIFORM_GLOW );
373       const int glowColorLoc = program.GetUniformLocation( Program::UNIFORM_GLOW_COLOR );
374
375       if( Program::UNIFORM_UNKNOWN != glowLoc && Program::UNIFORM_UNKNOWN != glowColorLoc )
376       {
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);
380       }
381     }
382
383     if( mTextParameters->mDropShadowEnabled )
384     {
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 );
388
389       if( Program::UNIFORM_UNKNOWN != shadowLoc && Program::UNIFORM_UNKNOWN != shadowColorLoc && Program::UNIFORM_UNKNOWN != shadowSmoothingLoc )
390       {
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 ) );
396       }
397     }
398   }
399
400   // Set the text color uniform
401   const int textColorLoc = program.GetUniformLocation( Program::UNIFORM_TEXT_COLOR );
402   if( Program::UNIFORM_UNKNOWN != textColorLoc )
403   {
404     Vector4 textColor( (NULL != mTextColor) ? *mTextColor : TextStyle::DEFAULT_TEXT_COLOR );
405
406     program.SetUniform4f(textColorLoc, textColor.r, textColor.g, textColor.b, textColor.a);
407   }
408
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 )
412   {
413     Vector2 projection( Vector2::ZERO );
414     Vector2 startPoint( TextStyle::DEFAULT_GRADIENT_START_POINT );
415
416     if( mTextParameters )
417     {
418       startPoint = mTextParameters->mGradientStartPoint;
419       projection = mTextParameters->mGradientEndPoint - startPoint;
420       if( mTextParameters->mGradientEnabled ) // same as: mGradientEndPoint != mGradientStartPoint
421       {
422         projection /= projection.LengthSquared();
423
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 );
427
428         if( Program::UNIFORM_UNKNOWN != gradientColorLoc && Program::UNIFORM_UNKNOWN != textSizeLoc )
429         {
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 );
433         }
434       }
435     }
436
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 )
443     {
444       program.SetUniform4f( gradientLineLoc,
445                             startPoint.x - 0.5f,
446                             startPoint.y - 0.5f,
447                             projection.x,
448                             projection.y );
449     }
450   }
451
452   const int positionLoc = program.GetAttribLocation(Program::ATTRIB_POSITION);
453   const int texCoordLoc = program.GetAttribLocation(Program::ATTRIB_TEXCOORD);
454
455   mTexture->Bind(GL_TEXTURE_2D, GL_TEXTURE0);
456
457   mContext->EnableVertexAttributeArray( positionLoc );
458   mContext->EnableVertexAttributeArray( texCoordLoc );
459
460   // bind the buffers
461   DALI_ASSERT_DEBUG( mVertexBuffer->BufferIsValid() );
462   mVertexBuffer->Bind();
463   DALI_ASSERT_DEBUG( mIndexBuffer->BufferIsValid() );
464   mIndexBuffer->Bind();
465
466   TextVertex2D* v = 0;
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);
469
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 );
473
474   mContext->DisableVertexAttributeArray( positionLoc );
475   mContext->DisableVertexAttributeArray( texCoordLoc );
476 }
477
478 TextRenderer::TextRenderer( RenderDataProvider& dataprovider )
479 : Renderer( dataprovider ),
480   mTextureId( 0 ),
481   mTexture( NULL ),
482   mTextColor( NULL ),
483   mSmoothing( Dali::TextStyle::DEFAULT_SMOOTH_EDGE_DISTANCE_FIELD )
484 {
485 }
486
487 } // namespace SceneGraph
488
489 } // namespace Internal
490
491 } // namespace Dali