fd100909433115ec3a9fe952c6b5f9a5e39aa87b
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / scene-graph-image-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-image-renderer.h>
19
20 // EXTERNAL INCLUDES
21 #include <dali/public-api/common/dali-common.h>
22 #include <dali/internal/common/internal-constants.h>
23 #include <dali/internal/render/common/performance-monitor.h>
24 #include <dali/internal/render/common/vertex.h>
25 #include <dali/internal/render/gl-resources/gpu-buffer.h>
26 #include <dali/internal/render/gl-resources/texture.h>
27 #include <dali/internal/render/gl-resources/texture-cache.h>
28 #include <dali/internal/render/shaders/program.h>
29 #include <dali/internal/render/shaders/shader.h>
30 #include <dali/internal/update/controllers/scene-controller.h>
31
32 using namespace std;
33
34 namespace
35 {
36 /**
37  * VertexToTextureCoord
38  * Represents a mapping between a 1 dimensional vertex coordinate
39  * and a 1 dimensional texture coordinate.
40  */
41 struct VertexToTextureCoord
42 {
43   /**
44    * @param[in] xVertex Vertex coordinate
45    * @param[in] uTexture Texture coordinate
46    */
47   VertexToTextureCoord(float xVertex, float uTexture)
48   : x(xVertex),
49     u(uTexture)
50   {
51   }
52
53   float x;    ///< 1D Vertex position
54   float u;    ///< 1D Texture position
55 };
56
57 /**
58  * Generates a list of equally spaced intervals along a line, including
59  * intervals at the points specified in insertionList.
60  * The line starts from insertionList.begin() and ends at insertionList.end()-1
61  * The number of intervals and spacing of these intervals is specified by
62  * the caller.
63  * @param[out] intervalList An empty vector to be populated with the list of intervals.
64  * @param[in] intervals The number of intervals to be generated.
65  * @param[in] insertionList A vector containing the points on the line to be inserted.
66  */
67 void GenerateIntervals(std::vector<VertexToTextureCoord>& intervalList, int intervals, const std::vector<VertexToTextureCoord>& insertionList)
68 {
69   DALI_ASSERT_DEBUG(insertionList.size() >= 2);
70   DALI_ASSERT_DEBUG(intervals > 0);
71
72   std::vector<VertexToTextureCoord>::const_iterator iter = insertionList.begin();
73   std::vector<VertexToTextureCoord>::const_iterator end = insertionList.end()-1;
74
75   const float length = end->x - iter->x;
76   const float intervalSize = length / static_cast<float>(intervals);
77   float x = iter->x;
78
79   for(;iter!=end;++iter)
80   {
81     float x0 = iter[0].x;
82     float u0 = iter[0].u;
83     float x1 = iter[1].x;
84     float u1 = iter[1].u;
85
86     for(;x<x1;x+=intervalSize)
87     {
88       float progress = (x - x0) / (x1 - x0);  // progress value between current interval and next.
89       float u = u0 + (u1 - u0) * progress;    // u 1D texture coordinate value for this x position.
90       intervalList.push_back( VertexToTextureCoord( x, u ) );
91     }
92     intervalList.push_back( VertexToTextureCoord( x1, u1 ) );
93   }
94 }
95
96 }
97
98 namespace Dali
99 {
100
101 namespace Internal
102 {
103
104 namespace SceneGraph
105 {
106
107 ImageRenderer* ImageRenderer::New( RenderDataProvider& dataprovider )
108 {
109   return new ImageRenderer( dataprovider );
110 }
111
112 ImageRenderer::~ImageRenderer()
113 {
114   if ( mTextureId > 0 )
115   {
116     mTextureCache->RemoveObserver(mTextureId, this);
117   }
118
119   GlCleanup();
120 }
121
122 void ImageRenderer::SetTextureId( ResourceId textureId )
123 {
124   if ( mTextureId > 0 )
125   {
126     mTextureCache->RemoveObserver(mTextureId, this);
127   }
128
129   mTextureId = textureId;
130   mTexture = NULL;
131
132   if ( textureId > 0 )
133   {
134     mTextureCache->AddObserver(textureId, this);
135   }
136 }
137
138 void ImageRenderer::SetPixelArea( const ImageRenderer::PixelArea& pixelArea )
139 {
140   mUsePixelArea    = true;
141   mPixelArea       = pixelArea;
142   mIsMeshGenerated = false;
143 }
144
145 void ImageRenderer::SetNinePatchBorder( const Vector4& border, bool inPixels )
146 {
147   mBorder          = border;
148   mBorderInPixels  = inPixels;
149   mIsMeshGenerated = false;
150 }
151
152 void ImageRenderer::CalculateMeshData( MeshType type, const Vector2& targetSize, bool usePixelArea )
153 {
154   mMeshType        = type;
155   mGeometrySize    = targetSize;
156   mUsePixelArea    = usePixelArea;
157   mIsMeshGenerated = false;
158 }
159
160 void ImageRenderer::TextureDiscarded( ResourceId textureId )
161 {
162   DALI_ASSERT_DEBUG( mTextureId == textureId || mTextureId == 0 );
163
164   mTextureId = 0;
165   mTexture = NULL;
166 }
167
168 void ImageRenderer::GlCleanup()
169 {
170   if (mVertexBuffer)
171   {
172     mVertexBuffer.Reset();
173   }
174
175   if (mIndexBuffer)
176   {
177     mIndexBuffer.Reset();
178   }
179 }
180
181 bool ImageRenderer::RequiresDepthTest() const
182 {
183   return false;
184 }
185
186 bool ImageRenderer::CheckResources()
187 {
188   if( mTexture == NULL )
189   {
190     mTexture = mTextureCache->GetTexture( mTextureId );
191   }
192
193   if( mTexture == NULL )
194   {
195     return false;
196   }
197
198   if( ( mTexture->GetWidth() <= 0u ) ||
199       ( mTexture->GetHeight() <= 0u ) )
200   {
201     return false;
202   }
203
204   Integration::ResourceId shaderTextureId =  mShader->GetTextureIdToRender() ;
205
206   if( shaderTextureId &&  mTextureCache->GetTexture( shaderTextureId ) == NULL )
207   {
208     return false;
209   }
210
211   return true;
212 }
213
214 void ImageRenderer::DoRender( BufferIndex bufferIndex, const Matrix& modelViewMatrix, const Matrix& modelMatrix, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector4& color )
215 {
216   DALI_ASSERT_DEBUG( 0 != mTextureId && "ImageRenderer::DoRender. mTextureId == 0." );
217   DALI_ASSERT_DEBUG( NULL != mTexture && "ImageRenderer::DoRender. mTexture == NULL." );
218
219   if(! mIsMeshGenerated )
220   {
221     GenerateMeshData( mTexture );
222   }
223
224   DALI_ASSERT_DEBUG( mVertexBuffer );
225
226   mTextureCache->BindTexture( mTexture, mTextureId,  GL_TEXTURE_2D, GL_TEXTURE0 );
227
228   // make sure the vertex is bound, this has to be done before
229   // we call VertexAttribPointer otherwise you get weird output on the display
230   mVertexBuffer->Bind();
231
232   ShaderSubTypes shaderType = SHADER_DEFAULT;
233
234   // Apply shader effect specific program and common uniforms
235   Program& program = mShader->Apply( *mContext, bufferIndex, GEOMETRY_TYPE_IMAGE, modelMatrix, viewMatrix, modelViewMatrix, projectionMatrix, color, shaderType );
236
237   // Set sampler uniform
238   GLint samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER );
239   if( -1 != samplerLoc )
240   {
241     // set the uniform
242     program.SetUniform1i( samplerLoc, 0 );
243   }
244
245   samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER_RECT );
246   if( -1 != samplerLoc )
247   {
248     UvRect uv;
249
250     if ( mUsePixelArea )
251     {
252       mTexture->GetTextureCoordinates( uv, &mPixelArea );
253     }
254     else
255     {
256       mTexture->GetTextureCoordinates( uv, NULL );
257     }
258
259     // set the uniform
260     program.SetUniform4f( samplerLoc, uv.u0, uv.v0, uv.u2, uv.v2 );
261   }
262
263   // Check whether the program supports the expected attributes/uniforms
264   const GLint positionLoc = program.GetAttribLocation( Program::ATTRIB_POSITION );
265   const GLint texCoordLoc = program.GetAttribLocation( Program::ATTRIB_TEXCOORD );
266
267   if ( positionLoc != -1 )
268   {
269     mContext->EnableVertexAttributeArray( positionLoc );
270
271     const int stride = 4 * sizeof(float);
272     mContext->VertexAttribPointer( positionLoc, 2, GL_FLOAT, GL_FALSE, stride, 0 );
273   }
274
275   if ( texCoordLoc != -1 )
276   {
277     mContext->EnableVertexAttributeArray( texCoordLoc );
278
279     const int stride = 4 * sizeof(float);
280     mContext->VertexAttribPointer( texCoordLoc, 2, GL_FLOAT, GL_FALSE, stride, (const void*) (sizeof(float)*2) );
281   }
282
283   switch(mMeshType)
284   {
285     case QUAD:
286     case NINE_PATCH:
287     {
288       const GLsizei vertexCount = mVertexBuffer->GetBufferSize() / sizeof(Vertex2D); // compiler will optimize this to >> if possible
289       mContext->DrawArrays( GL_TRIANGLE_STRIP, 0, vertexCount );
290       DRAW_ARRAY_RECORD( vertexCount );
291       break;
292     }
293     case GRID_QUAD:
294     case GRID_NINE_PATCH:
295     {
296       const GLsizei indexCount = mIndexBuffer->GetBufferSize() / sizeof(GLushort); // compiler will optimize this to >> if possible
297       mIndexBuffer->Bind();
298       mContext->DrawElements( GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0 );
299       DRAW_ELEMENT_RECORD( indexCount );
300       break;
301     }
302   }
303
304   if ( positionLoc != -1 )
305   {
306     mContext->DisableVertexAttributeArray( positionLoc );
307   }
308
309   if ( texCoordLoc != -1 )
310   {
311     mContext->DisableVertexAttributeArray( texCoordLoc );
312   }
313 }
314
315 void ImageRenderer::UpdateVertexBuffer( GLsizeiptr size, const GLvoid *data )
316 {
317   // create/destroy if needed/not needed.
318   if ( size && !mVertexBuffer )
319   {
320     mVertexBuffer = new GpuBuffer( *mContext, GpuBuffer::ARRAY_BUFFER, GpuBuffer::DYNAMIC_DRAW );
321   }
322   else if ( !size && mVertexBuffer )
323   {
324     mVertexBuffer.Reset();
325   }
326
327   // update
328   if ( mVertexBuffer )
329   {
330     mVertexBuffer->UpdateDataBuffer( size, data );
331   }
332 }
333
334 void ImageRenderer::UpdateIndexBuffer( GLsizeiptr size, const GLvoid *data )
335 {
336   // create/destroy if needed/not needed.
337   if ( size && !mIndexBuffer )
338   {
339     mIndexBuffer = new GpuBuffer( *mContext, GpuBuffer::ELEMENT_ARRAY_BUFFER, GpuBuffer::STATIC_DRAW );
340   }
341   else if ( !size && mIndexBuffer )
342   {
343     mIndexBuffer.Reset();
344   }
345
346   // update
347   if ( mIndexBuffer )
348   {
349     mIndexBuffer->UpdateDataBuffer(size,data);
350   }
351 }
352
353 void ImageRenderer::GenerateMeshData( Texture* texture )
354 {
355   const PixelArea* pixelArea = NULL;
356   if( mUsePixelArea )
357   {
358     pixelArea = &mPixelArea;
359   }
360
361   switch( mMeshType )
362   {
363     case ImageRenderer::QUAD:
364     {
365       SetQuadMeshData( texture, mGeometrySize, pixelArea );
366       break;
367     }
368     case ImageRenderer::NINE_PATCH:
369     {
370       SetNinePatchMeshData( texture, mGeometrySize, mBorder, mBorderInPixels, pixelArea );
371       break;
372     }
373     case ImageRenderer::GRID_QUAD:
374     {
375       SetGridMeshData( texture, mGeometrySize, NULL, false, pixelArea );
376       break;
377     }
378     case ImageRenderer::GRID_NINE_PATCH:
379     {
380       SetGridMeshData( texture, mGeometrySize, &mBorder, mBorderInPixels, pixelArea );
381       break;
382     }
383   }
384   mIsMeshGenerated = true;
385 }
386
387 void ImageRenderer::SetQuadMeshData( Texture* texture, const Vector2& size, const PixelArea* pixelArea )
388 {
389   const float x0 = -0.5f * size.x;
390   const float y0 = -0.5f * size.y;
391   const float x1 =  0.5f * size.x;
392   const float y1 =  0.5f * size.y;
393
394   /*
395    * Here we render the square as a single square, as texture
396    * coordinates linearly interpolate between the 4 vertices.
397    *
398    * Note: a square (or a quad) is rendered as 2 triangles.
399    * Vertices 0,1,2 represent triangle A.
400    * Vertices 1,2,3 represent triangle B.
401    *
402    * No indices are needed as we tell GL to render in strip mode
403    * (GL_TRIANGLE_STRIP), which is faster, and consumes less
404    * memory.
405    *
406    *  0---------2
407    *  |        /|
408    *  |  A    / |
409    *  |      /  |
410    *  |     /   |
411    *  |    /    |
412    *  |   /     |
413    *  |  /      |
414    *  | /    B  |
415    *  |/        |
416    *  1---------3
417    */
418
419   Vertex2D verts[]={
420                      {x0, y0, 0.0, 0.0},
421                      {x0, y1, 0.0, 1.0},
422                      {x1, y0, 1.0, 0.0},
423                      {x1, y1, 1.0, 1.0}
424                    };
425
426   // We may only be displaying an area of the texture.
427   // Calling MapUV converts the u,v values to correct values for the pixel area
428
429   texture->MapUV( sizeof(verts)/sizeof(Vertex2D), verts, pixelArea );
430
431   UpdateVertexBuffer( sizeof(verts), verts );
432   UpdateIndexBuffer( 0, NULL );
433 }
434
435 void ImageRenderer::SetNinePatchMeshData( Texture* texture, const Vector2& size, const Vector4& border, bool borderInPixels, const PixelArea* pixelArea )
436 {
437   DALI_ASSERT_ALWAYS( mTexture->GetWidth()  > 0.0f && "Invalid Texture width" );
438   DALI_ASSERT_ALWAYS( mTexture->GetHeight() > 0.0f && "Invalid Texture height" );
439
440   float textureWidth  = mTexture->GetWidth();
441   float textureHeight = mTexture->GetHeight();
442
443   float borderLeft, borderTop, borderRight, borderBottom; // pixels from edge
444   float borderX0, borderY0, borderX1, borderY1; // In the range 0 -> 1
445
446   if ( borderInPixels )
447   {
448     borderLeft   = border.x;
449     borderTop    = border.y;
450     borderRight  = border.z;
451     borderBottom = border.w;
452
453     borderX0 = border.x / textureWidth;
454     borderY0 = border.y / textureHeight;
455     borderX1 = 1.0f - ( border.z / textureWidth );
456     borderY1 = 1.0f - ( border.w / textureHeight );
457   }
458   else
459   {
460     borderLeft   = textureWidth  * border.x;
461     borderTop    = textureHeight * border.y;
462     borderRight  = textureWidth  * (1.0f - border.z);
463     borderBottom = textureHeight * (1.0f - border.w);
464
465     borderX0 = border.x;
466     borderY0 = border.y;
467     borderX1 = border.z;
468     borderY1 = border.w;
469   }
470
471   const float u0 = 0.0f;
472   const float u3 = 1.0f;
473   const float u1 = borderX0;
474   const float u2 = borderX1;
475
476   const float v0 = 0.0f;
477   const float v3 = 1.0f;
478   const float v1 = borderY0;
479   const float v2 = borderY1;
480
481   const float x0 = size.x * -0.5;
482   const float x1 = x0 + borderLeft;
483   const float x2 = x0 + size.x - borderRight;
484   const float x3 = x0 + size.x;
485
486   const float y0 = size.y * -0.5;
487   const float y1 = y0 + borderTop;
488   const float y2 = y0 + size.y - borderBottom;
489   const float y3 = y0 + size.y;
490
491   /*
492    * We're breaking a quad in to 9 smaller quads, so that when it's
493    * stretched the corners maintain their size.
494    * For speed the 9-patch is drawn with a single triangle span, the draw
495    * order of the span is 1->9.
496    * Previously it would draw three separate spans (1->3, 4->6, 7->9), but now it
497    * it does it one go by turning the corner when gets to the end of each row.
498    *
499    * No indices are needed as we tell GL to render in strip mode
500    * (GL_TRIANGLE_STRIP), which is faster, and consumes less
501    * memory.
502    *
503    *  |---|---------------|---|
504    *  |  7|    --> 8      | 9 |
505    *  |---|---------------|---|
506    *  |   |               |   |
507    *  | 6 |     <-- 5     | 4 |
508    *  |   |               |   |
509    *  |   |               |   |
510    *  |-------------------|---|
511    *  | 1 |      2 -->    | 3 |
512    *  |---|---------------|---|
513    */
514
515   Vertex2D verts[]={
516                      // bottom left
517                      {  x0, y0, u0, v0 },
518                      {  x0, y1, u0, v1 },
519                      {  x1, y0, u1, v0 },
520                      {  x1, y1, u1, v1 },
521
522                      // bottom right
523                      {  x2, y0, u2, v0 },
524                      {  x2, y1, u2, v1 },
525                      {  x3, y0, u3, v0 },
526                      {  x3, y1, u3, v1 },
527
528                      // turn the corner
529                      {  x3, y1, u3, v1 },
530                      {  x3, y1, u3, v1 },
531
532                      // 10 verts here
533
534                      // middle right
535                      {  x3, y2, u3, v2 },
536                      {  x2, y1, u2, v1 },
537                      {  x2, y2, u2, v2 },
538
539                      // middle left
540
541                      {  x1, y1, u1, v1 },
542                      {  x1, y2, u1, v2 },
543                      {  x0, y1, u0, v1 },
544                      {  x0, y2, u0, v2 },
545
546                      // turn the corner
547                      {  x0, y2, u0, v2 },
548                      {  x0, y2, u0, v2 },
549
550                      // top left
551                      {  x0, y3, u0, v3 },
552                      {  x1, y2, u1, v2 },
553                      {  x1, y3, u1, v3 },
554
555                      // top right
556
557                      {  x2, y2, u2, v2 },
558                      {  x2, y3, u2, v3 },
559                      {  x3, y2, u3, v2 },
560                      {  x3, y3, u3, v3 },
561                    };
562
563   const unsigned int vertexCount = sizeof( verts ) / sizeof( verts[0] );
564
565   texture->MapUV( vertexCount, verts, pixelArea );
566   UpdateVertexBuffer( sizeof(verts), verts );
567   UpdateIndexBuffer( 0, NULL );
568 }
569
570 void ImageRenderer::SetGridMeshData( Texture* texture, const Vector2& size, const Vector4* border, bool borderInPixels, const PixelArea* pixelArea )
571 {
572   /*
573    * Quad Grid:
574    * In Grid Mode, we tessellate the single quad into smaller quads
575    * at approximately (guideGridSize x guideGridSize) in size.
576    *
577    * Conversion of Quad to Gridded Quad.
578    *
579    * |-----------|    |---|---|---|
580    * |           |    |   |   |   |
581    * |           | -> |---|---|---|
582    * |           |    |   |   |   |
583    * |-----------|    |---|---|---|
584    *
585    * 9-Patch Grid:
586    * In Grid Mode, we tessellate each quad of a 9-patch
587    * (see SetNinePatchMeshData) into smaller quads at approximately
588    * (guideGridSize x guideGridSize) in size.
589    *
590    * This satisfies the two requirements of a 9-patch with grid:
591    *
592    * 1. Texture coordinates within each section of the 9-patch
593    * should change linearly to that 9-patch's rules.
594    * 2. The image as as whole should provide Vertex points at
595    * approximate guideGridSize intervals.
596    *
597    * The result should be the horizontal and vertical lines of
598    * a 9-patch overlayed by the horizontal and vertical lines of
599    * a grid.
600    *
601    * Non-overlayed:
602    *  |     |     |     |     |     |     | <- Grid Markers
603    * -|-------|-------------------|-------|
604    *  |       |                   |       |
605    *  |   1   |         2         |   3   |
606    * -|       |                   |       |
607    *  |-------+-------------------+-------|
608    *  |       |                   |       |
609    * -|       |                   |       |
610    *  |       |                   |       |
611    *  |       |                   |       |
612    * -|   4   |         5         |   6   | <- 9 Patch.
613    *  |       |                   |       |
614    *  |       |                   |       |
615    * -|       |                   |       |
616    *  |       |                   |       |
617    *  |-------+-------------------+-------|
618    * -|       |                   |       |
619    *  |   7   |         8         |   9   |
620    *  |       |                   |       |
621    * -|-------|-------------------|-------|
622    *
623    *
624    * Overlayed:
625    *  |     |     |     |     |     |     | <- Grid Markers
626    * -|-------|-------------------|-------|
627    *  |     | |   |     |     |   | |     |
628    *  |     | |   |     |     |   | |     |
629    * -|-----|-|---|-----|-----|---|-|-----|
630    *  |-------+-------------------+-------|
631    *  |     | |   |     |     |   | |     |
632    * -|-----|-|---|-----|-----|---|-|-----|
633    *  |     | |   |     |     |   | |     |
634    *  |     | |   |     |     |   | |     |
635    * -|-----|-|---|-----|-----|---|-|-----| <- 9 Patch.
636    *  |     | |   |     |     |   | |     |
637    *  |     | |   |     |     |   | |     |
638    * -|-----|-|---|-----|-----|---|-|-----|
639    *  |     | |   |     |     |   | |     |
640    *  |-------+-------------------+-------|
641    * -|-----|-|---|-----|-----|---|-|-----|
642    *  |     | |   |     |     |   | |     |
643    *  |     | |   |     |     |   | |     |
644    * -|-------|-------------------|-------|
645    */
646
647   std::vector<VertexToTextureCoord> horizontalDivisions;
648   std::vector<VertexToTextureCoord> verticalDivisions;
649
650   const float guideGridSize = mShader->GetGridDensity();
651
652   const int textureWidth = texture->GetWidth();
653   const int textureHeight = texture->GetHeight();
654
655   const float halfWidth = size.width * 0.5f;
656   const float halfHeight = size.height * 0.5f;
657
658   // Determine how many rectangles across and down to tesselate image into.
659   const int guideRectX = (size.width / guideGridSize);
660   const int guideRectY = (size.height / guideGridSize);
661
662   // Build up list of points in X axis where vertices need to go.
663   std::vector<VertexToTextureCoord> insertionList;
664   insertionList.reserve(4);
665   insertionList.push_back( VertexToTextureCoord( -halfWidth, 0.0f ) );
666
667   // If 9-Patch Border exists, add additional border points in list.
668   if(border)
669   {
670     float borderX0, borderX1, borderU0, borderU1;
671
672     if ( borderInPixels )
673     {
674       borderX0 = border->x - halfWidth;
675       borderX1 = halfWidth - border->z;
676
677       borderU0 = border->x / textureWidth;
678       borderU1 = 1.0f - (border->z / textureWidth);
679     }
680     else
681     {
682       borderX0 = border->x * textureWidth - halfWidth;
683       borderX1 = halfWidth - (1.0f - border->z) * textureWidth;
684       borderU0 = border->x;
685       borderU1 = border->z;
686     }
687
688     insertionList.push_back( VertexToTextureCoord( borderX0, borderU0 ) );
689     insertionList.push_back( VertexToTextureCoord( borderX1, borderU1 ) );
690   }
691
692   insertionList.push_back( VertexToTextureCoord( halfWidth, 1.0f ) );
693   GenerateIntervals(horizontalDivisions, guideRectX + 2, insertionList);
694
695   // Build up list of points in Y axis where vertices need to go.
696   insertionList.clear();
697   insertionList.push_back( VertexToTextureCoord( -halfHeight, 0.0f ) );
698
699   // If 9-Patch Border exists, add additional border points in list.
700   if(border)
701   {
702     float borderY0, borderY1, borderU0, borderU1;
703
704     if ( borderInPixels )
705     {
706       borderY0 = border->y - halfHeight;
707       borderY1 = halfHeight - border->w;
708
709       borderU0 = border->y / textureHeight;
710       borderU1 = 1.0f - (border->w / textureHeight);
711     }
712     else
713     {
714       borderY0 = border->y * textureHeight - halfHeight;
715       borderY1 = halfHeight - (1.0f - border->w) * textureHeight;
716
717       borderU0 = border->y;
718       borderU1 = border->w;
719     }
720
721     insertionList.push_back( VertexToTextureCoord( borderY0, borderU0 ) );
722     insertionList.push_back( VertexToTextureCoord( borderY1, borderU1 ) );
723   }
724
725   insertionList.push_back( VertexToTextureCoord( halfHeight, 1.0f ) );
726   GenerateIntervals(verticalDivisions, guideRectY + 2, insertionList);
727
728   // Now build up Vertex pattern based on the above X and Y lists.
729   const int totalVertices = horizontalDivisions.size() * verticalDivisions.size();
730   Vertex2D* vertices = new Vertex2D[totalVertices];
731   Vertex2D* vertex = vertices;
732
733   for(std::vector<VertexToTextureCoord>::const_iterator yIter = verticalDivisions.begin(); yIter != verticalDivisions.end(); ++yIter )
734   {
735     for(std::vector<VertexToTextureCoord>::const_iterator xIter = horizontalDivisions.begin(); xIter != horizontalDivisions.end(); ++xIter )
736     {
737       vertex->mX = xIter->x;
738       vertex->mU = xIter->u;
739       vertex->mY = yIter->x;
740       vertex->mV = yIter->u;
741       vertex++;
742     }
743   }
744
745   // Build up Triangle indicies, very predictable pattern.
746   const size_t rectX = horizontalDivisions.size() - 1;
747   const size_t rectY = verticalDivisions.size() - 1;
748   const size_t totalIndices = rectX * rectY * 6;             // 2 triangles per quad (rect) and 3 points to define each triangle.
749   GLushort* indices = new GLushort[totalIndices];
750
751   GenerateMeshIndices(indices, rectX, rectY);
752
753   texture->MapUV( totalVertices, vertices, pixelArea );
754
755   UpdateVertexBuffer( totalVertices * sizeof(Vertex2D) , vertices );
756   UpdateIndexBuffer( totalIndices * sizeof(GLushort), indices );
757
758   delete[] vertices;
759   delete[] indices;
760 }
761
762 void ImageRenderer::GenerateMeshIndices(GLushort* indices, int rectanglesX, int rectanglesY)
763 {
764   GLushort *i = indices;
765   const int meshEndIndex = rectanglesY * (rectanglesX + 1);
766
767   int index = 0;
768   while(index < meshEndIndex)
769   {
770     const int rowEndIndex = index + rectanglesX;
771     for (; index < rowEndIndex; index++ )
772     {
773       *i++ = index;
774       *i++ = index + 1 + rectanglesX;
775       *i++ = index + 1;
776
777       *i++ = index + 1;
778       *i++ = index + 1 + rectanglesX;
779       *i++ = index + 2 + rectanglesX;
780     }
781     index++;    // one extra vertex per row than rects.
782   }
783 }
784
785 ImageRenderer::ImageRenderer( RenderDataProvider& dataprovider )
786 : Renderer( dataprovider ),
787   mTexture( NULL ),
788   mBorder( 0.45, 0.45, 0.1, 0.1 ),
789   mPixelArea(),
790   mGeometrySize(),
791   mTextureId( 0 ),
792   mMeshType( ImageRenderer::QUAD ),
793   mIsMeshGenerated( false ),
794   mBorderInPixels( false ),
795   mUsePixelArea( false )
796 {
797 }
798
799 } // namespace SceneGraph
800
801 } // namespace Internal
802
803 } // namespace Dali