Tizen 2.4.0 rev3 SDK Public Release
[framework/graphics/dali.git] / dali / internal / render / renderers / scene-graph-image-renderer.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
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
18 // CLASS HEADER
19 #include <dali/internal/render/renderers/scene-graph-image-renderer.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/internal/common/internal-constants.h>
25 #include <dali/internal/render/common/culling-algorithms.h>
26 #include <dali/internal/render/common/performance-monitor.h>
27 #include <dali/internal/render/common/vertex.h>
28 #include <dali/internal/render/gl-resources/gpu-buffer.h>
29 #include <dali/internal/render/gl-resources/texture.h>
30 #include <dali/internal/render/gl-resources/texture-cache.h>
31 #include <dali/internal/render/gl-resources/texture-units.h>
32 #include <dali/internal/render/renderers/scene-graph-renderer-debug.h>
33 #include <dali/internal/render/shaders/program.h>
34 #include <dali/internal/render/shaders/scene-graph-shader.h>
35 #include <dali/internal/update/controllers/scene-controller.h>
36
37 namespace
38 {
39 #if defined(DEBUG_ENABLED)
40 Debug::Filter* gImageRenderFilter=Debug::Filter::New(Debug::NoLogging, false, "LOG_IMAGE_RENDERER");
41 #endif
42
43 /**
44  * VertexToTextureCoord
45  * Represents a mapping between a 1 dimensional vertex coordinate
46  * and a 1 dimensional texture coordinate.
47  */
48 struct VertexToTextureCoord
49 {
50   /**
51    * @param[in] xVertex Vertex coordinate
52    * @param[in] uTexture Texture coordinate
53    */
54   VertexToTextureCoord(float xVertex, float uTexture)
55   : x(xVertex),
56     u(uTexture)
57   {
58   }
59
60   float x;    ///< 1D Vertex position
61   float u;    ///< 1D Texture position
62 };
63
64 /**
65  * Generates a list of equally spaced intervals along a line, including
66  * intervals at the points specified in insertionList.
67  * The line starts from insertionList.begin() and ends at insertionList.end()-1
68  * The number of intervals and spacing of these intervals is specified by
69  * the caller.
70  * @param[out] intervalList An empty vector to be populated with the list of intervals.
71  * @param[in] intervals The number of intervals to be generated.
72  * @param[in] insertionList A vector containing the points on the line to be inserted.
73  */
74 void GenerateIntervals(std::vector<VertexToTextureCoord>& intervalList, int intervals, const std::vector<VertexToTextureCoord>& insertionList)
75 {
76   DALI_ASSERT_DEBUG(insertionList.size() >= 2);
77   DALI_ASSERT_DEBUG(intervals > 0);
78
79   std::vector<VertexToTextureCoord>::const_iterator iter = insertionList.begin();
80   if( iter != insertionList.end() )
81   {
82     std::vector<VertexToTextureCoord>::const_iterator end = insertionList.end()-1;
83
84     const float length = end->x - iter->x;
85     const float intervalSize = length / static_cast<float>(intervals);
86     float x = iter->x;
87
88     for(;iter!=end;++iter)
89     {
90       float x0 = iter[0].x;
91       float u0 = iter[0].u;
92       float x1 = iter[1].x;
93       float u1 = iter[1].u;
94
95       for(;x<x1;x+=intervalSize)
96       {
97         float progress = (x - x0) / (x1 - x0);  // progress value between current interval and next.
98         float u = u0 + (u1 - u0) * progress;    // u 1D texture coordinate value for this x position.
99         intervalList.push_back( VertexToTextureCoord( x, u ) );
100       }
101       intervalList.push_back( VertexToTextureCoord( x1, u1 ) );
102     }
103   }
104 }
105
106 }
107
108 namespace Dali
109 {
110
111 namespace Internal
112 {
113
114 namespace SceneGraph
115 {
116
117 ImageRenderer* ImageRenderer::New( NodeDataProvider& dataProvider )
118 {
119   return new ImageRenderer( dataProvider );
120 }
121
122 ImageRenderer::~ImageRenderer()
123 {
124   // Note - GL cleanup is done from render-thread in OnRemove()
125 }
126
127 void ImageRenderer::OnRemove()
128 {
129   if ( mTextureId > 0 )
130   {
131     mTextureCacheDELETEME->RemoveObserver(mTextureId, this);
132   }
133
134   GlCleanup();
135
136   // Set back to defaults
137   mDataProvider = NULL;
138   mShader = NULL;
139   mTexture = NULL;
140   mBorder = Vector4( 0.45, 0.45, 0.1, 0.1 );
141   mPixelArea = PixelArea();
142   mGeometrySize = Vector2();
143   mTextureId =  0;
144   mBlendingOptions.SetBlendFunc( DEFAULT_BLENDING_SRC_FACTOR_RGB, DEFAULT_BLENDING_DEST_FACTOR_RGB, DEFAULT_BLENDING_SRC_FACTOR_ALPHA, DEFAULT_BLENDING_DEST_FACTOR_ALPHA );
145   mBlendingOptions.SetBlendEquation( DEFAULT_BLENDING_EQUATION_RGB, DEFAULT_BLENDING_EQUATION_ALPHA );
146   mBlendingOptions.SetBlendColor( Vector4::ZERO );
147   mMeshType = ImageRenderer::QUAD;
148   mIsMeshGenerated = false;
149   mBorderInPixels = false;
150   mUseBlend = false;
151   mUsePixelArea = false;
152 }
153
154 void ImageRenderer::SetTextureId( ResourceId textureId )
155 {
156   if ( mTextureId > 0 )
157   {
158     mTextureCacheDELETEME->RemoveObserver(mTextureId, this);
159   }
160
161   mTextureId = textureId;
162   mTexture = NULL;
163
164   if ( textureId > 0 )
165   {
166     mTextureCacheDELETEME->AddObserver(textureId, this);
167   }
168 }
169
170 void ImageRenderer::SetPixelArea( const ImageRenderer::PixelArea& pixelArea )
171 {
172   mUsePixelArea    = true;
173   mPixelArea       = pixelArea;
174   mIsMeshGenerated = false;
175 }
176
177 void ImageRenderer::SetNinePatchBorder( const Vector4& border, bool inPixels )
178 {
179   mBorder          = border;
180   mBorderInPixels  = inPixels;
181   mIsMeshGenerated = false;
182 }
183
184 void ImageRenderer::SetUseBlend( bool useBlend )
185 {
186   mUseBlend = useBlend;
187 }
188
189 void ImageRenderer::SetBlendingOptions( unsigned int options )
190 {
191   mBlendingOptions.SetBitmask( options );
192 }
193
194 void ImageRenderer::SetBlendColor( const Vector4& color )
195 {
196   mBlendingOptions.SetBlendColor( color );
197 }
198
199 void ImageRenderer::CalculateMeshData( MeshType type, const Vector2& targetSize, bool usePixelArea )
200 {
201   mMeshType        = type;
202   mGeometrySize    = targetSize;
203   mUsePixelArea    = usePixelArea;
204   mIsMeshGenerated = false;
205 }
206
207 void ImageRenderer::TextureDiscarded( ResourceId textureId )
208 {
209   DALI_ASSERT_DEBUG( mTextureId == textureId || mTextureId == 0 );
210
211   mTextureId = 0;
212   mTexture = NULL;
213 }
214
215 void ImageRenderer::GlContextDestroyed()
216 {
217   if( mVertexBuffer )
218   {
219     mVertexBuffer->GlContextDestroyed();
220   }
221   if( mIndexBuffer )
222   {
223     mIndexBuffer->GlContextDestroyed();
224   }
225   // force recreation of the geometry in next render
226   mIsMeshGenerated = false;
227 }
228
229 void ImageRenderer::GlCleanup()
230 {
231   DALI_LOG_INFO( gImageRenderFilter, Debug::Verbose, "GlCleanup() textureId=%d  texture:%p\n", mTextureId, mTexture);
232
233   mVertexBuffer.Reset();
234   mIndexBuffer.Reset();
235 }
236
237 bool ImageRenderer::RequiresDepthTest() const
238 {
239   return false;
240 }
241
242 bool ImageRenderer::CheckResources()
243 {
244   if( mDataProvider == NULL )
245   {
246     return false;
247   }
248
249   if( mTexture == NULL )
250   {
251     if ( mTextureCacheDELETEME )
252     {
253       mTexture = mTextureCacheDELETEME->GetTexture( mTextureId );
254     }
255   }
256
257   if( mTexture == NULL )
258   {
259     return false;
260   }
261
262   if( ( mTexture->GetWidth() <= 0u ) ||
263       ( mTexture->GetHeight() <= 0u ) )
264   {
265     return false;
266   }
267
268   Integration::ResourceId shaderTextureId =  mShader->GetTextureIdToRender() ;
269
270   if( shaderTextureId &&  mTextureCacheDELETEME->GetTexture( shaderTextureId ) == NULL )
271   {
272     return false;
273   }
274
275   return true;
276 }
277
278 bool ImageRenderer::IsOutsideClipSpace( Context& context, const Matrix& modelMatrix, const Matrix& modelViewProjectionMatrix )
279 {
280   context.IncrementRendererCount();
281
282   Rect<float> boundingBox( mGeometrySize.x * -0.5f, mGeometrySize.y * -0.5f, mGeometrySize.x, mGeometrySize.y );
283
284   DEBUG_BOUNDING_BOX( *mContext, boundingBox, modelViewProjectionMatrix );
285
286   if(Is2dBoxOutsideClipSpace( modelMatrix, modelViewProjectionMatrix, boundingBox ) )
287   {
288     context.IncrementCulledCount();
289     return true;
290   }
291   return false;
292 }
293
294 void ImageRenderer::DoRender( Context& context, TextureCache& textureCache, BufferIndex bufferIndex, Program& program, const Matrix& modelViewMatrix, const Matrix& viewMatrix )
295 {
296   DALI_LOG_INFO( gImageRenderFilter, Debug::Verbose, "DoRender() textureId=%d  texture:%p\n", mTextureId, mTexture);
297
298   DALI_ASSERT_DEBUG( 0 != mTextureId && "ImageRenderer::DoRender. mTextureId == 0." );
299   DALI_ASSERT_DEBUG( NULL != mTexture && "ImageRenderer::DoRender. mTexture == NULL." );
300
301   if(! mIsMeshGenerated )
302   {
303     GenerateMeshData( mTexture );
304   }
305
306   DALI_ASSERT_DEBUG( mVertexBuffer );
307
308   mTextureCacheDELETEME->BindTexture( mTexture, mTextureId,  GL_TEXTURE_2D, TEXTURE_UNIT_IMAGE );
309
310   if( mTexture->GetTextureId() == 0 )
311   {
312     return; // early out if we haven't got a GL texture yet (e.g. due to context loss)
313   }
314
315   mTexture->ApplySampler( TEXTURE_UNIT_IMAGE, mSamplerBitfield );
316
317   // Set sampler uniform
318   GLint samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER );
319   if( -1 != samplerLoc )
320   {
321     // set the uniform
322     program.SetUniform1i( samplerLoc, TEXTURE_UNIT_IMAGE );
323   }
324
325   // make sure the vertex is bound, this has to be done before
326   // we call VertexAttribPointer otherwise you get weird output on the display
327   mVertexBuffer->Bind();
328
329   samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER_RECT );
330   if( -1 != samplerLoc )
331   {
332     UvRect uv;
333
334     if ( mUsePixelArea )
335     {
336       mTexture->GetTextureCoordinates( uv, &mPixelArea );
337     }
338     else
339     {
340       mTexture->GetTextureCoordinates( uv, NULL );
341     }
342
343     // set the uniform
344     program.SetUniform4f( samplerLoc, uv.u0, uv.v0, uv.u2, uv.v2 );
345   }
346
347   // Check whether the program supports the expected attributes/uniforms
348   const GLint positionLoc = program.GetAttribLocation( Program::ATTRIB_POSITION );
349   const GLint texCoordLoc = program.GetAttribLocation( Program::ATTRIB_TEXCOORD );
350
351   if ( positionLoc != -1 )
352   {
353     context.EnableVertexAttributeArray( positionLoc );
354
355     const int stride = 4 * sizeof(float);
356     context.VertexAttribPointer( positionLoc, 2, GL_FLOAT, GL_FALSE, stride, 0 );
357   }
358
359   if ( texCoordLoc != -1 )
360   {
361     context.EnableVertexAttributeArray( texCoordLoc );
362
363     const int stride = 4 * sizeof(float);
364     context.VertexAttribPointer( texCoordLoc, 2, GL_FLOAT, GL_FALSE, stride, (const void*) (sizeof(float)*2) );
365   }
366
367   switch(mMeshType)
368   {
369     case QUAD:
370     case NINE_PATCH:
371     case NINE_PATCH_NO_CENTER:
372     {
373       const GLsizei vertexCount = mVertexBuffer->GetBufferSize() / sizeof(Vertex2D); // compiler will optimize this to >> if possible
374       context.DrawArrays( GL_TRIANGLE_STRIP, 0, vertexCount );
375       break;
376     }
377     case GRID_QUAD:
378     case GRID_NINE_PATCH:
379     case GRID_NINE_PATCH_NO_CENTER:
380     {
381       const GLsizei indexCount = mIndexBuffer->GetBufferSize() / sizeof(GLushort); // compiler will optimize this to >> if possible
382       mIndexBuffer->Bind();
383       context.DrawElements( GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0 );
384       break;
385     }
386   }
387
388   if ( positionLoc != -1 )
389   {
390     context.DisableVertexAttributeArray( positionLoc );
391   }
392
393   if ( texCoordLoc != -1 )
394   {
395     context.DisableVertexAttributeArray( texCoordLoc );
396   }
397 }
398
399 void ImageRenderer::DoSetBlending(Context& context, BufferIndex bufferIndex )
400 {
401   // Enables/disables blending mode.
402   context.SetBlend( mUseBlend );
403
404   // Set the blend color
405   const Vector4* const customColor = mBlendingOptions.GetBlendColor();
406   if( customColor )
407   {
408     context.SetCustomBlendColor( *customColor );
409   }
410   else
411   {
412     context.SetDefaultBlendColor();
413   }
414
415   // Set blend source & destination factors
416   context.BlendFuncSeparate( mBlendingOptions.GetBlendSrcFactorRgb(),
417                              mBlendingOptions.GetBlendDestFactorRgb(),
418                              mBlendingOptions.GetBlendSrcFactorAlpha(),
419                              mBlendingOptions.GetBlendDestFactorAlpha() );
420
421   // Set blend equations
422   context.BlendEquationSeparate( mBlendingOptions.GetBlendEquationRgb(),
423                                  mBlendingOptions.GetBlendEquationAlpha() );
424
425 }
426
427 void ImageRenderer::UpdateVertexBuffer( Context& context, GLsizeiptr size, const GLvoid *data )
428 {
429   // create/destroy if needed/not needed.
430   if ( size && !mVertexBuffer )
431   {
432     mVertexBuffer = new GpuBuffer( context, GpuBuffer::ARRAY_BUFFER, GpuBuffer::DYNAMIC_DRAW );
433   }
434   else if ( !size && mVertexBuffer )
435   {
436     mVertexBuffer.Reset();
437   }
438
439   // update
440   if ( mVertexBuffer )
441   {
442     mVertexBuffer->UpdateDataBuffer( size, data );
443   }
444 }
445
446 void ImageRenderer::UpdateIndexBuffer( Context& context, GLsizeiptr size, const GLvoid *data )
447 {
448   // create/destroy if needed/not needed.
449   if ( size && !mIndexBuffer )
450   {
451     mIndexBuffer = new GpuBuffer( context, GpuBuffer::ELEMENT_ARRAY_BUFFER, GpuBuffer::STATIC_DRAW );
452   }
453   else if ( !size && mIndexBuffer )
454   {
455     mIndexBuffer.Reset();
456   }
457
458   // update
459   if ( mIndexBuffer )
460   {
461     mIndexBuffer->UpdateDataBuffer(size,data);
462   }
463 }
464
465 void ImageRenderer::GenerateMeshData( Texture* texture )
466 {
467   const PixelArea* pixelArea = NULL;
468   if( mUsePixelArea )
469   {
470     pixelArea = &mPixelArea;
471   }
472
473   switch( mMeshType )
474   {
475     case ImageRenderer::QUAD:
476     {
477       SetQuadMeshData( texture, mGeometrySize, pixelArea );
478       break;
479     }
480     case ImageRenderer::NINE_PATCH:
481     {
482       SetNinePatchMeshData( texture, mGeometrySize, mBorder, mBorderInPixels, pixelArea, false );
483       break;
484     }
485     case ImageRenderer::NINE_PATCH_NO_CENTER:
486     {
487       SetNinePatchMeshData( texture, mGeometrySize, mBorder, mBorderInPixels, pixelArea, true );
488       break;
489     }
490     case ImageRenderer::GRID_QUAD:
491     {
492       SetGridMeshData( texture, mGeometrySize, NULL, false, pixelArea );
493       break;
494     }
495     case ImageRenderer::GRID_NINE_PATCH:
496     case ImageRenderer::GRID_NINE_PATCH_NO_CENTER:
497     {
498       SetGridMeshData( texture, mGeometrySize, &mBorder, mBorderInPixels, pixelArea );
499       break;
500     }
501   }
502   mIsMeshGenerated = true;
503 }
504
505 void ImageRenderer::SetQuadMeshData( Texture* texture, const Vector2& size, const PixelArea* pixelArea )
506 {
507   const float x0 = -0.5f * size.x;
508   const float y0 = -0.5f * size.y;
509   const float x1 =  0.5f * size.x;
510   const float y1 =  0.5f * size.y;
511
512   /*
513    * Here we render the square as a single square, as texture
514    * coordinates linearly interpolate between the 4 vertices.
515    *
516    * Note: a square (or a quad) is rendered as 2 triangles.
517    * Vertices 0,1,2 represent triangle A.
518    * Vertices 1,2,3 represent triangle B.
519    *
520    * No indices are needed as we tell GL to render in strip mode
521    * (GL_TRIANGLE_STRIP), which is faster, and consumes less
522    * memory.
523    *
524    *  0---------2
525    *  |        /|
526    *  |  A    / |
527    *  |      /  |
528    *  |     /   |
529    *  |    /    |
530    *  |   /     |
531    *  |  /      |
532    *  | /    B  |
533    *  |/        |
534    *  1---------3
535    */
536
537   Vertex2D verts[]={
538                      {x0, y0, 0.0, 0.0},
539                      {x0, y1, 0.0, 1.0},
540                      {x1, y0, 1.0, 0.0},
541                      {x1, y1, 1.0, 1.0}
542                    };
543
544   // We may only be displaying an area of the texture.
545   // Calling MapUV converts the u,v values to correct values for the pixel area
546
547   texture->MapUV( sizeof(verts)/sizeof(Vertex2D), verts, pixelArea );
548
549   UpdateVertexBuffer( *mContextDELETEME, sizeof(verts), verts );
550   UpdateIndexBuffer( *mContextDELETEME, 0, NULL );
551 }
552
553 void ImageRenderer::SetNinePatchMeshData( Texture* texture, const Vector2& size, const Vector4& border, bool borderInPixels, const PixelArea* pixelArea, bool noCenter )
554 {
555   DALI_ASSERT_ALWAYS( mTexture->GetWidth()  > 0.0f && "Invalid Texture width" );
556   DALI_ASSERT_ALWAYS( mTexture->GetHeight() > 0.0f && "Invalid Texture height" );
557
558   float textureWidth  = mTexture->GetWidth();
559   float textureHeight = mTexture->GetHeight();
560
561   float borderLeft, borderTop, borderRight, borderBottom; // pixels from edge
562   float borderX0, borderY0, borderX1, borderY1; // In the range 0 -> 1
563
564   if ( borderInPixels )
565   {
566     borderLeft   = border.x;
567     borderTop    = border.y;
568     borderRight  = border.z;
569     borderBottom = border.w;
570
571     borderX0 = border.x / textureWidth;
572     borderY0 = border.y / textureHeight;
573     borderX1 = 1.0f - ( border.z / textureWidth );
574     borderY1 = 1.0f - ( border.w / textureHeight );
575   }
576   else
577   {
578     borderLeft   = textureWidth  * border.x;
579     borderTop    = textureHeight * border.y;
580     borderRight  = textureWidth  * (1.0f - border.z);
581     borderBottom = textureHeight * (1.0f - border.w);
582
583     borderX0 = border.x;
584     borderY0 = border.y;
585     borderX1 = border.z;
586     borderY1 = border.w;
587   }
588
589   const float u0 = 0.0f;
590   const float u3 = 1.0f;
591   const float u1 = borderX0;
592   const float u2 = borderX1;
593
594   const float v0 = 0.0f;
595   const float v3 = 1.0f;
596   const float v1 = borderY0;
597   const float v2 = borderY1;
598
599   const float x0 = size.x * -0.5;
600   const float x1 = x0 + borderLeft;
601   const float x2 = x0 + size.x - borderRight;
602   const float x3 = x0 + size.x;
603
604   const float y0 = size.y * -0.5;
605   const float y1 = y0 + borderTop;
606   const float y2 = y0 + size.y - borderBottom;
607   const float y3 = y0 + size.y;
608
609
610   if ( !noCenter )
611   {
612     /*
613      * We're breaking a quad in to 9 smaller quads, so that when it's
614      * stretched the corners maintain their size.
615      * For speed the 9-patch is drawn with a single triangle span, the draw
616      * order of the span is 1->9.
617      * Previously it would draw three separate spans (1->3, 4->6, 7->9), but now it
618      * it does it one go by turning the corner when gets to the end of each row.
619      *
620      * No indices are needed as we tell GL to render in strip mode
621      * (GL_TRIANGLE_STRIP), which is faster, and consumes less
622      * memory.
623      *
624      *  |---|---------------|---|
625      *  |  7|    --> 8      | 9 |
626      *  |---|---------------|---|
627      *  |   |               |   |
628      *  | 6 |     <-- 5     | 4 |
629      *  |   |               |   |
630      *  |   |               |   |
631      *  |---|---------------|---|
632      *  | 1 |      2 -->    | 3 |
633      *  |---|---------------|---|
634      */
635
636     Vertex2D vertsWithCenter[]={
637                                  // bottom left
638                                  {  x0, y0, u0, v0 },
639                                  {  x0, y1, u0, v1 },
640                                  {  x1, y0, u1, v0 },
641                                  {  x1, y1, u1, v1 },
642
643                                  // bottom middle
644                                  {  x2, y0, u2, v0 },
645                                  {  x2, y1, u2, v1 },
646
647                                  // bottom right
648                                  {  x3, y0, u3, v0 },
649                                  {  x3, y1, u3, v1 },
650
651                                  // turn the corner
652                                  {  x3, y1, u3, v1 },
653                                  {  x3, y1, u3, v1 },
654
655                                  // 10 verts here
656
657                                  // middle right
658                                  {  x3, y2, u3, v2 },
659                                  {  x2, y1, u2, v1 },
660                                  {  x2, y2, u2, v2 },
661
662                                  // middle left
663
664                                  {  x1, y1, u1, v1 },
665                                  {  x1, y2, u1, v2 },
666                                  {  x0, y1, u0, v1 },
667                                  {  x0, y2, u0, v2 },
668
669                                  // turn the corner
670                                  {  x0, y2, u0, v2 },
671                                  {  x0, y2, u0, v2 },
672
673                                  // top left
674                                  {  x0, y3, u0, v3 },
675                                  {  x1, y2, u1, v2 },
676                                  {  x1, y3, u1, v3 },
677
678                                  // top middle
679                                  {  x2, y2, u2, v2 },
680                                  {  x2, y3, u2, v3 },
681
682                                  // top right
683                                  {  x3, y2, u3, v2 },
684                                  {  x3, y3, u3, v3 },
685                                };
686
687     const size_t vertsSize = sizeof( vertsWithCenter );
688     const unsigned int vertexCount = vertsSize / sizeof( vertsWithCenter[0] );
689     texture->MapUV( vertexCount, vertsWithCenter, pixelArea );
690     UpdateVertexBuffer( *mContextDELETEME, vertsSize, vertsWithCenter );
691   }
692   else
693   {
694     /*
695      * The center part is not going to be rendered. The 9-patch border is drawn with
696      * a single triangle span, and the draw order of the span is 1->8.
697      *
698      *  |---|---------------|---|
699      *  | 7 |    <-- 6      | 5 |
700      *  |---|---------------|---|
701      *  |   |               |   |
702      *  |   |               |   |
703      *  | 8 |               | 4 |
704      *  |   | (not rendered)|   |
705      *  |   |               |   |
706      *  |---|---------------|---|
707      *  | 1 |      2 -->    | 3 |
708      *  |---|---------------|---|
709      */
710
711     Vertex2D vertsWithNoCenter[]={
712                                    // bottom left (1)
713                                    {  x0, y0, u0, v0 },
714                                    {  x0, y1, u0, v1 },
715                                    {  x1, y0, u1, v0 },
716                                    {  x1, y1, u1, v1 },
717
718                                    // bottom middle (2)
719                                    {  x2, y0, u2, v0 },
720                                    {  x2, y1, u2, v1 },
721
722                                    // bottom right (3)
723                                    {  x3, y0, u3, v0 },
724                                    {  x3, y1, u3, v1 },
725
726                                    // reset the starting point to x3, y1
727                                    {  x3, y1, u3, v1 },
728                                    {  x3, y1, u3, v1 },
729
730                                    // middle right (4)
731                                    {  x3, y2, u3, v2 },
732                                    {  x2, y1, u2, v1 },
733                                    {  x2, y2, u2, v2 },
734
735                                    // corner turning
736                                    {  x2, y2, u2, v2 },
737                                    {  x3, y2, u3, v2 },
738                                    {  x3, y2, u3, v2 },
739
740                                    // top right (5)
741                                    {  x3, y3, u3, v3 },
742                                    {  x2, y2, u2, v2 },
743                                    {  x2, y3, u2, v3 },
744
745                                    // top middle (6)
746                                    {  x1, y2, u1, v2 },
747                                    {  x1, y3, u1, v3 },
748
749                                    // reset point to x0,y3
750                                    {  x1, y3, u1, v3 },
751                                    {  x0, y3, u0, v3 },
752                                    {  x0, y3, u0, v3 },
753
754                                    // top left box (starting from (x0,y3)) (7)
755                                    {  x0, y2, u0, v2 },
756                                    {  x1, y3, u1, v3 },
757                                    {  x1, y2, u1, v2 },
758
759                                    // reset point
760                                    {  x1, y2, u1, v2 },
761
762                                    // middle left (8)
763                                    {  x0, y2, u0, v2 },
764                                    {  x1, y1, u1, v2 },
765                                    {  x0, y1, u0, v2 },
766                                  };
767
768     const size_t vertsSize = sizeof( vertsWithNoCenter );
769     const unsigned int vertexCount = vertsSize / sizeof( vertsWithNoCenter[0] );
770     texture->MapUV( vertexCount, vertsWithNoCenter, pixelArea );
771     UpdateVertexBuffer( *mContextDELETEME, vertsSize, vertsWithNoCenter );
772   }
773   // not using an index buffer
774   UpdateIndexBuffer( *mContextDELETEME, 0, NULL );
775
776 }
777
778 void ImageRenderer::SetGridMeshData( Texture* texture, const Vector2& size, const Vector4* border, bool borderInPixels, const PixelArea* pixelArea )
779 {
780   /*
781    * Quad Grid:
782    * In Grid Mode, we tessellate the single quad into smaller quads
783    * at approximately (guideGridSize x guideGridSize) in size.
784    *
785    * Conversion of Quad to Gridded Quad.
786    *
787    * |-----------|    |---|---|---|
788    * |           |    |   |   |   |
789    * |           | -> |---|---|---|
790    * |           |    |   |   |   |
791    * |-----------|    |---|---|---|
792    *
793    * 9-Patch Grid:
794    * In Grid Mode, we tessellate each quad of a 9-patch
795    * (see SetNinePatchMeshData) into smaller quads at approximately
796    * (guideGridSize x guideGridSize) in size.
797    *
798    * This satisfies the two requirements of a 9-patch with grid:
799    *
800    * 1. Texture coordinates within each section of the 9-patch
801    * should change linearly to that 9-patch's rules.
802    * 2. The image as as whole should provide Vertex points at
803    * approximate guideGridSize intervals.
804    *
805    * The result should be the horizontal and vertical lines of
806    * a 9-patch overlayed by the horizontal and vertical lines of
807    * a grid.
808    *
809    * Non-overlayed:
810    *  |     |     |     |     |     |     | <- Grid Markers
811    * -|-------|-------------------|-------|
812    *  |       |                   |       |
813    *  |   1   |         2         |   3   |
814    * -|       |                   |       |
815    *  |-------+-------------------+-------|
816    *  |       |                   |       |
817    * -|       |                   |       |
818    *  |       |                   |       |
819    *  |       |                   |       |
820    * -|   4   |         5         |   6   | <- 9 Patch.
821    *  |       |                   |       |
822    *  |       |                   |       |
823    * -|       |                   |       |
824    *  |       |                   |       |
825    *  |-------+-------------------+-------|
826    * -|       |                   |       |
827    *  |   7   |         8         |   9   |
828    *  |       |                   |       |
829    * -|-------|-------------------|-------|
830    *
831    *
832    * Overlayed:
833    *  |     |     |     |     |     |     | <- Grid Markers
834    * -|-------|-------------------|-------|
835    *  |     | |   |     |     |   | |     |
836    *  |     | |   |     |     |   | |     |
837    * -|-----|-|---|-----|-----|---|-|-----|
838    *  |-------+-------------------+-------|
839    *  |     | |   |     |     |   | |     |
840    * -|-----|-|---|-----|-----|---|-|-----|
841    *  |     | |   |     |     |   | |     |
842    *  |     | |   |     |     |   | |     |
843    * -|-----|-|---|-----|-----|---|-|-----| <- 9 Patch.
844    *  |     | |   |     |     |   | |     |
845    *  |     | |   |     |     |   | |     |
846    * -|-----|-|---|-----|-----|---|-|-----|
847    *  |     | |   |     |     |   | |     |
848    *  |-------+-------------------+-------|
849    * -|-----|-|---|-----|-----|---|-|-----|
850    *  |     | |   |     |     |   | |     |
851    *  |     | |   |     |     |   | |     |
852    * -|-------|-------------------|-------|
853    */
854
855   std::vector<VertexToTextureCoord> horizontalDivisions;
856   std::vector<VertexToTextureCoord> verticalDivisions;
857
858   const float guideGridSize = mShader->GetGridDensity();
859
860   const int textureWidth = texture->GetWidth();
861   const int textureHeight = texture->GetHeight();
862
863   const float halfWidth = size.width * 0.5f;
864   const float halfHeight = size.height * 0.5f;
865
866   // Determine how many rectangles across and down to tesselate image into.
867   const int guideRectX = (size.width / guideGridSize);
868   const int guideRectY = (size.height / guideGridSize);
869
870   // Build up list of points in X axis where vertices need to go.
871   std::vector<VertexToTextureCoord> insertionList;
872   insertionList.reserve(4);
873   insertionList.push_back( VertexToTextureCoord( -halfWidth, 0.0f ) );
874
875   // If 9-Patch Border exists, add additional border points in list.
876   if(border)
877   {
878     float borderX0, borderX1, borderU0, borderU1;
879
880     if ( borderInPixels )
881     {
882       borderX0 = border->x - halfWidth;
883       borderX1 = halfWidth - border->z;
884
885       borderU0 = border->x / textureWidth;
886       borderU1 = 1.0f - (border->z / textureWidth);
887     }
888     else
889     {
890       borderX0 = border->x * textureWidth - halfWidth;
891       borderX1 = halfWidth - (1.0f - border->z) * textureWidth;
892       borderU0 = border->x;
893       borderU1 = border->z;
894     }
895
896     insertionList.push_back( VertexToTextureCoord( borderX0, borderU0 ) );
897     insertionList.push_back( VertexToTextureCoord( borderX1, borderU1 ) );
898   }
899
900   insertionList.push_back( VertexToTextureCoord( halfWidth, 1.0f ) );
901   GenerateIntervals(horizontalDivisions, guideRectX + 2, insertionList);
902
903   // Build up list of points in Y axis where vertices need to go.
904   insertionList.clear();
905   insertionList.push_back( VertexToTextureCoord( -halfHeight, 0.0f ) );
906
907   // If 9-Patch Border exists, add additional border points in list.
908   if(border)
909   {
910     float borderY0, borderY1, borderU0, borderU1;
911
912     if ( borderInPixels )
913     {
914       borderY0 = border->y - halfHeight;
915       borderY1 = halfHeight - border->w;
916
917       borderU0 = border->y / textureHeight;
918       borderU1 = 1.0f - (border->w / textureHeight);
919     }
920     else
921     {
922       borderY0 = border->y * textureHeight - halfHeight;
923       borderY1 = halfHeight - (1.0f - border->w) * textureHeight;
924
925       borderU0 = border->y;
926       borderU1 = border->w;
927     }
928
929     insertionList.push_back( VertexToTextureCoord( borderY0, borderU0 ) );
930     insertionList.push_back( VertexToTextureCoord( borderY1, borderU1 ) );
931   }
932
933   insertionList.push_back( VertexToTextureCoord( halfHeight, 1.0f ) );
934   GenerateIntervals(verticalDivisions, guideRectY + 2, insertionList);
935
936   // Now build up Vertex pattern based on the above X and Y lists.
937   const int totalVertices = horizontalDivisions.size() * verticalDivisions.size();
938   Vertex2D* vertices = new Vertex2D[totalVertices];
939   Vertex2D* vertex = vertices;
940
941   for(std::vector<VertexToTextureCoord>::const_iterator yIter = verticalDivisions.begin(); yIter != verticalDivisions.end(); ++yIter )
942   {
943     for(std::vector<VertexToTextureCoord>::const_iterator xIter = horizontalDivisions.begin(); xIter != horizontalDivisions.end(); ++xIter )
944     {
945       vertex->mX = xIter->x;
946       vertex->mU = xIter->u;
947       vertex->mY = yIter->x;
948       vertex->mV = yIter->u;
949       vertex++;
950     }
951   }
952
953   // Build up Triangle indicies, very predictable pattern.
954   const size_t rectX = horizontalDivisions.size() - 1;
955   const size_t rectY = verticalDivisions.size() - 1;
956   const size_t totalIndices = rectX * rectY * 6;             // 2 triangles per quad (rect) and 3 points to define each triangle.
957   GLushort* indices = new GLushort[totalIndices];
958
959   GenerateMeshIndices(indices, rectX, rectY);
960
961   texture->MapUV( totalVertices, vertices, pixelArea );
962
963   UpdateVertexBuffer( *mContextDELETEME, totalVertices * sizeof(Vertex2D) , vertices );
964   UpdateIndexBuffer( *mContextDELETEME, totalIndices * sizeof(GLushort), indices );
965
966   delete[] vertices;
967   delete[] indices;
968 }
969
970 void ImageRenderer::GenerateMeshIndices(GLushort* indices, int rectanglesX, int rectanglesY)
971 {
972   GLushort *i = indices;
973   const int meshEndIndex = rectanglesY * (rectanglesX + 1);
974
975   int index = 0;
976   while(index < meshEndIndex)
977   {
978     const int rowEndIndex = index + rectanglesX;
979     for (; index < rowEndIndex; index++ )
980     {
981       *i++ = index;
982       *i++ = index + 1 + rectanglesX;
983       *i++ = index + 1;
984
985       *i++ = index + 1;
986       *i++ = index + 1 + rectanglesX;
987       *i++ = index + 2 + rectanglesX;
988     }
989     index++;    // one extra vertex per row than rects.
990   }
991 }
992
993 ImageRenderer::ImageRenderer( NodeDataProvider& dataProvider )
994 : Renderer( dataProvider ),
995   mTexture( NULL ),
996   mBorder( 0.45, 0.45, 0.1, 0.1 ),
997   mPixelArea(),
998   mGeometrySize(),
999   mTextureId( 0 ),
1000   mMeshType( ImageRenderer::QUAD ),
1001   mIsMeshGenerated( false ),
1002   mBorderInPixels( false ),
1003   mUseBlend( false ),
1004   mUsePixelArea( false )
1005 {
1006 }
1007
1008 } // namespace SceneGraph
1009
1010 } // namespace Internal
1011
1012 } // namespace Dali