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