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