2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/render/renderers/scene-graph-image-renderer.h>
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>
39 #if defined(DEBUG_ENABLED)
40 Debug::Filter* gImageRenderFilter=Debug::Filter::New(Debug::NoLogging, false, "LOG_IMAGE_RENDERER");
44 * VertexToTextureCoord
45 * Represents a mapping between a 1 dimensional vertex coordinate
46 * and a 1 dimensional texture coordinate.
48 struct VertexToTextureCoord
51 * @param[in] xVertex Vertex coordinate
52 * @param[in] uTexture Texture coordinate
54 VertexToTextureCoord(float xVertex, float uTexture)
60 float x; ///< 1D Vertex position
61 float u; ///< 1D Texture position
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
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.
74 void GenerateIntervals(std::vector<VertexToTextureCoord>& intervalList, int intervals, const std::vector<VertexToTextureCoord>& insertionList)
76 DALI_ASSERT_DEBUG(insertionList.size() >= 2);
77 DALI_ASSERT_DEBUG(intervals > 0);
79 std::vector<VertexToTextureCoord>::const_iterator iter = insertionList.begin();
80 if( iter != insertionList.end() )
82 std::vector<VertexToTextureCoord>::const_iterator end = insertionList.end()-1;
84 const float length = end->x - iter->x;
85 const float intervalSize = length / static_cast<float>(intervals);
88 for(;iter!=end;++iter)
95 for(;x<x1;x+=intervalSize)
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 ) );
101 intervalList.push_back( VertexToTextureCoord( x1, u1 ) );
117 ImageRenderer* ImageRenderer::New( NodeDataProvider& dataProvider )
119 return new ImageRenderer( dataProvider );
122 ImageRenderer::~ImageRenderer()
124 // Note - GL cleanup is done from render-thread in OnRemove()
127 void ImageRenderer::OnRemove()
129 if ( mTextureId > 0 )
131 mTextureCacheDELETEME->RemoveObserver(mTextureId, this);
136 // Set back to defaults
137 mDataProvider = NULL;
140 mBorder = Vector4( 0.45, 0.45, 0.1, 0.1 );
141 mPixelArea = PixelArea();
142 mGeometrySize = Vector2();
144 mBlendingOptions.SetBlendFunc( DEFAULT_BLENDING_SRC_FACTOR_RGB, DEFAULT_BLENDING_DEST_FACTOR_RGB, DEFAULT_BLENDING_SRC_FACTOR_ALPHA, DEFAULT_BLENDING_DEST_FACTOR_ALPHA );
145 mBlendingOptions.SetBlendEquation( DEFAULT_BLENDING_EQUATION_RGB, DEFAULT_BLENDING_EQUATION_ALPHA );
146 mBlendingOptions.SetBlendColor( Vector4::ZERO );
147 mMeshType = ImageRenderer::QUAD;
148 mIsMeshGenerated = false;
149 mBorderInPixels = false;
151 mUsePixelArea = false;
154 void ImageRenderer::SetTextureId( ResourceId textureId )
156 if ( mTextureId > 0 )
158 mTextureCacheDELETEME->RemoveObserver(mTextureId, this);
161 mTextureId = textureId;
166 mTextureCacheDELETEME->AddObserver(textureId, this);
170 void ImageRenderer::SetPixelArea( const ImageRenderer::PixelArea& pixelArea )
172 mUsePixelArea = true;
173 mPixelArea = pixelArea;
174 mIsMeshGenerated = false;
177 void ImageRenderer::SetNinePatchBorder( const Vector4& border, bool inPixels )
180 mBorderInPixels = inPixels;
181 mIsMeshGenerated = false;
184 void ImageRenderer::SetUseBlend( bool useBlend )
186 mUseBlend = useBlend;
189 void ImageRenderer::SetBlendingOptions( unsigned int options )
191 mBlendingOptions.SetBitmask( options );
194 void ImageRenderer::SetBlendColor( const Vector4& color )
196 mBlendingOptions.SetBlendColor( color );
199 void ImageRenderer::CalculateMeshData( MeshType type, const Vector2& targetSize, bool usePixelArea )
202 mGeometrySize = targetSize;
203 mUsePixelArea = usePixelArea;
204 mIsMeshGenerated = false;
207 void ImageRenderer::TextureDiscarded( ResourceId textureId )
209 DALI_ASSERT_DEBUG( mTextureId == textureId || mTextureId == 0 );
215 void ImageRenderer::GlContextDestroyed()
219 mVertexBuffer->GlContextDestroyed();
223 mIndexBuffer->GlContextDestroyed();
225 // force recreation of the geometry in next render
226 mIsMeshGenerated = false;
229 void ImageRenderer::GlCleanup()
231 DALI_LOG_INFO( gImageRenderFilter, Debug::Verbose, "GlCleanup() textureId=%d texture:%p\n", mTextureId, mTexture);
233 mVertexBuffer.Reset();
234 mIndexBuffer.Reset();
237 bool ImageRenderer::RequiresDepthTest() const
242 bool ImageRenderer::CheckResources()
244 if( mDataProvider == NULL )
249 if( mTexture == NULL )
251 if ( mTextureCacheDELETEME )
253 mTexture = mTextureCacheDELETEME->GetTexture( mTextureId );
257 if( mTexture == NULL )
262 if( ( mTexture->GetWidth() <= 0u ) ||
263 ( mTexture->GetHeight() <= 0u ) )
268 Integration::ResourceId shaderTextureId = mShader->GetTextureIdToRender() ;
270 if( shaderTextureId && mTextureCacheDELETEME->GetTexture( shaderTextureId ) == NULL )
278 bool ImageRenderer::IsOutsideClipSpace( Context& context, const Matrix& modelMatrix, const Matrix& modelViewProjectionMatrix )
280 context.IncrementRendererCount();
282 Rect<float> boundingBox( mGeometrySize.x * -0.5f, mGeometrySize.y * -0.5f, mGeometrySize.x, mGeometrySize.y );
284 DEBUG_BOUNDING_BOX( *mContext, boundingBox, modelViewProjectionMatrix );
286 if(Is2dBoxOutsideClipSpace( modelMatrix, modelViewProjectionMatrix, boundingBox ) )
288 context.IncrementCulledCount();
294 void ImageRenderer::DoRender( Context& context, TextureCache& textureCache, BufferIndex bufferIndex, Program& program, const Matrix& modelViewMatrix, const Matrix& viewMatrix )
296 DALI_LOG_INFO( gImageRenderFilter, Debug::Verbose, "DoRender() textureId=%d texture:%p\n", mTextureId, mTexture);
298 DALI_ASSERT_DEBUG( 0 != mTextureId && "ImageRenderer::DoRender. mTextureId == 0." );
299 DALI_ASSERT_DEBUG( NULL != mTexture && "ImageRenderer::DoRender. mTexture == NULL." );
301 if(! mIsMeshGenerated )
303 GenerateMeshData( mTexture );
306 DALI_ASSERT_DEBUG( mVertexBuffer );
308 mTextureCacheDELETEME->BindTexture( mTexture, mTextureId, GL_TEXTURE_2D, TEXTURE_UNIT_IMAGE );
310 if( mTexture->GetTextureId() == 0 )
312 return; // early out if we haven't got a GL texture yet (e.g. due to context loss)
315 mTexture->ApplySampler( TEXTURE_UNIT_IMAGE, mSamplerBitfield );
317 // Set sampler uniform
318 GLint samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER );
319 if( -1 != samplerLoc )
322 program.SetUniform1i( samplerLoc, TEXTURE_UNIT_IMAGE );
325 // make sure the vertex is bound, this has to be done before
326 // we call VertexAttribPointer otherwise you get weird output on the display
327 mVertexBuffer->Bind();
329 samplerLoc = program.GetUniformLocation( Program::UNIFORM_SAMPLER_RECT );
330 if( -1 != samplerLoc )
336 mTexture->GetTextureCoordinates( uv, &mPixelArea );
340 mTexture->GetTextureCoordinates( uv, NULL );
344 program.SetUniform4f( samplerLoc, uv.u0, uv.v0, uv.u2, uv.v2 );
347 // Check whether the program supports the expected attributes/uniforms
348 const GLint positionLoc = program.GetAttribLocation( Program::ATTRIB_POSITION );
349 const GLint texCoordLoc = program.GetAttribLocation( Program::ATTRIB_TEXCOORD );
351 if ( positionLoc != -1 )
353 context.EnableVertexAttributeArray( positionLoc );
355 const int stride = 4 * sizeof(float);
356 context.VertexAttribPointer( positionLoc, 2, GL_FLOAT, GL_FALSE, stride, 0 );
359 if ( texCoordLoc != -1 )
361 context.EnableVertexAttributeArray( texCoordLoc );
363 const int stride = 4 * sizeof(float);
364 context.VertexAttribPointer( texCoordLoc, 2, GL_FLOAT, GL_FALSE, stride, (const void*) (sizeof(float)*2) );
371 case NINE_PATCH_NO_CENTER:
373 const GLsizei vertexCount = mVertexBuffer->GetBufferSize() / sizeof(Vertex2D); // compiler will optimize this to >> if possible
374 context.DrawArrays( GL_TRIANGLE_STRIP, 0, vertexCount );
378 case GRID_NINE_PATCH:
379 case GRID_NINE_PATCH_NO_CENTER:
381 const GLsizei indexCount = mIndexBuffer->GetBufferSize() / sizeof(GLushort); // compiler will optimize this to >> if possible
382 mIndexBuffer->Bind();
383 context.DrawElements( GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0 );
388 if ( positionLoc != -1 )
390 context.DisableVertexAttributeArray( positionLoc );
393 if ( texCoordLoc != -1 )
395 context.DisableVertexAttributeArray( texCoordLoc );
399 void ImageRenderer::DoSetBlending(Context& context, BufferIndex bufferIndex )
401 // Enables/disables blending mode.
402 context.SetBlend( mUseBlend );
404 // Set the blend color
405 const Vector4* const customColor = mBlendingOptions.GetBlendColor();
408 context.SetCustomBlendColor( *customColor );
412 context.SetDefaultBlendColor();
415 // Set blend source & destination factors
416 context.BlendFuncSeparate( mBlendingOptions.GetBlendSrcFactorRgb(),
417 mBlendingOptions.GetBlendDestFactorRgb(),
418 mBlendingOptions.GetBlendSrcFactorAlpha(),
419 mBlendingOptions.GetBlendDestFactorAlpha() );
421 // Set blend equations
422 context.BlendEquationSeparate( mBlendingOptions.GetBlendEquationRgb(),
423 mBlendingOptions.GetBlendEquationAlpha() );
427 void ImageRenderer::UpdateVertexBuffer( Context& context, GLsizeiptr size, const GLvoid *data )
429 // create/destroy if needed/not needed.
430 if ( size && !mVertexBuffer )
432 mVertexBuffer = new GpuBuffer( context, GpuBuffer::ARRAY_BUFFER, GpuBuffer::DYNAMIC_DRAW );
434 else if ( !size && mVertexBuffer )
436 mVertexBuffer.Reset();
442 mVertexBuffer->UpdateDataBuffer( size, data );
446 void ImageRenderer::UpdateIndexBuffer( Context& context, GLsizeiptr size, const GLvoid *data )
448 // create/destroy if needed/not needed.
449 if ( size && !mIndexBuffer )
451 mIndexBuffer = new GpuBuffer( context, GpuBuffer::ELEMENT_ARRAY_BUFFER, GpuBuffer::STATIC_DRAW );
453 else if ( !size && mIndexBuffer )
455 mIndexBuffer.Reset();
461 mIndexBuffer->UpdateDataBuffer(size,data);
465 void ImageRenderer::GenerateMeshData( Texture* texture )
467 const PixelArea* pixelArea = NULL;
470 pixelArea = &mPixelArea;
475 case ImageRenderer::QUAD:
477 SetQuadMeshData( texture, mGeometrySize, pixelArea );
480 case ImageRenderer::NINE_PATCH:
482 SetNinePatchMeshData( texture, mGeometrySize, mBorder, mBorderInPixels, pixelArea, false );
485 case ImageRenderer::NINE_PATCH_NO_CENTER:
487 SetNinePatchMeshData( texture, mGeometrySize, mBorder, mBorderInPixels, pixelArea, true );
490 case ImageRenderer::GRID_QUAD:
492 SetGridMeshData( texture, mGeometrySize, NULL, false, pixelArea );
495 case ImageRenderer::GRID_NINE_PATCH:
496 case ImageRenderer::GRID_NINE_PATCH_NO_CENTER:
498 SetGridMeshData( texture, mGeometrySize, &mBorder, mBorderInPixels, pixelArea );
502 mIsMeshGenerated = true;
505 void ImageRenderer::SetQuadMeshData( Texture* texture, const Vector2& size, const PixelArea* pixelArea )
507 const float x0 = -0.5f * size.x;
508 const float y0 = -0.5f * size.y;
509 const float x1 = 0.5f * size.x;
510 const float y1 = 0.5f * size.y;
513 * Here we render the square as a single square, as texture
514 * coordinates linearly interpolate between the 4 vertices.
516 * Note: a square (or a quad) is rendered as 2 triangles.
517 * Vertices 0,1,2 represent triangle A.
518 * Vertices 1,2,3 represent triangle B.
520 * No indices are needed as we tell GL to render in strip mode
521 * (GL_TRIANGLE_STRIP), which is faster, and consumes less
544 // We may only be displaying an area of the texture.
545 // Calling MapUV converts the u,v values to correct values for the pixel area
547 texture->MapUV( sizeof(verts)/sizeof(Vertex2D), verts, pixelArea );
549 UpdateVertexBuffer( *mContextDELETEME, sizeof(verts), verts );
550 UpdateIndexBuffer( *mContextDELETEME, 0, NULL );
553 void ImageRenderer::SetNinePatchMeshData( Texture* texture, const Vector2& size, const Vector4& border, bool borderInPixels, const PixelArea* pixelArea, bool noCenter )
555 DALI_ASSERT_ALWAYS( mTexture->GetWidth() > 0.0f && "Invalid Texture width" );
556 DALI_ASSERT_ALWAYS( mTexture->GetHeight() > 0.0f && "Invalid Texture height" );
558 float textureWidth = mTexture->GetWidth();
559 float textureHeight = mTexture->GetHeight();
561 float borderLeft, borderTop, borderRight, borderBottom; // pixels from edge
562 float borderX0, borderY0, borderX1, borderY1; // In the range 0 -> 1
564 if ( borderInPixels )
566 borderLeft = border.x;
567 borderTop = border.y;
568 borderRight = border.z;
569 borderBottom = border.w;
571 borderX0 = border.x / textureWidth;
572 borderY0 = border.y / textureHeight;
573 borderX1 = 1.0f - ( border.z / textureWidth );
574 borderY1 = 1.0f - ( border.w / textureHeight );
578 borderLeft = textureWidth * border.x;
579 borderTop = textureHeight * border.y;
580 borderRight = textureWidth * (1.0f - border.z);
581 borderBottom = textureHeight * (1.0f - border.w);
589 const float u0 = 0.0f;
590 const float u3 = 1.0f;
591 const float u1 = borderX0;
592 const float u2 = borderX1;
594 const float v0 = 0.0f;
595 const float v3 = 1.0f;
596 const float v1 = borderY0;
597 const float v2 = borderY1;
599 const float x0 = size.x * -0.5;
600 const float x1 = x0 + borderLeft;
601 const float x2 = x0 + size.x - borderRight;
602 const float x3 = x0 + size.x;
604 const float y0 = size.y * -0.5;
605 const float y1 = y0 + borderTop;
606 const float y2 = y0 + size.y - borderBottom;
607 const float y3 = y0 + size.y;
613 * We're breaking a quad in to 9 smaller quads, so that when it's
614 * stretched the corners maintain their size.
615 * For speed the 9-patch is drawn with a single triangle span, the draw
616 * order of the span is 1->9.
617 * Previously it would draw three separate spans (1->3, 4->6, 7->9), but now it
618 * it does it one go by turning the corner when gets to the end of each row.
620 * No indices are needed as we tell GL to render in strip mode
621 * (GL_TRIANGLE_STRIP), which is faster, and consumes less
624 * |---|---------------|---|
626 * |---|---------------|---|
631 * |---|---------------|---|
633 * |---|---------------|---|
636 Vertex2D vertsWithCenter[]={
687 const size_t vertsSize = sizeof( vertsWithCenter );
688 const unsigned int vertexCount = vertsSize / sizeof( vertsWithCenter[0] );
689 texture->MapUV( vertexCount, vertsWithCenter, pixelArea );
690 UpdateVertexBuffer( *mContextDELETEME, vertsSize, vertsWithCenter );
695 * The center part is not going to be rendered. The 9-patch border is drawn with
696 * a single triangle span, and the draw order of the span is 1->8.
698 * |---|---------------|---|
700 * |---|---------------|---|
704 * | | (not rendered)| |
706 * |---|---------------|---|
708 * |---|---------------|---|
711 Vertex2D vertsWithNoCenter[]={
726 // reset the starting point to x3, y1
749 // reset point to x0,y3
754 // top left box (starting from (x0,y3)) (7)
768 const size_t vertsSize = sizeof( vertsWithNoCenter );
769 const unsigned int vertexCount = vertsSize / sizeof( vertsWithNoCenter[0] );
770 texture->MapUV( vertexCount, vertsWithNoCenter, pixelArea );
771 UpdateVertexBuffer( *mContextDELETEME, vertsSize, vertsWithNoCenter );
773 // not using an index buffer
774 UpdateIndexBuffer( *mContextDELETEME, 0, NULL );
778 void ImageRenderer::SetGridMeshData( Texture* texture, const Vector2& size, const Vector4* border, bool borderInPixels, const PixelArea* pixelArea )
782 * In Grid Mode, we tessellate the single quad into smaller quads
783 * at approximately (guideGridSize x guideGridSize) in size.
785 * Conversion of Quad to Gridded Quad.
787 * |-----------| |---|---|---|
789 * | | -> |---|---|---|
791 * |-----------| |---|---|---|
794 * In Grid Mode, we tessellate each quad of a 9-patch
795 * (see SetNinePatchMeshData) into smaller quads at approximately
796 * (guideGridSize x guideGridSize) in size.
798 * This satisfies the two requirements of a 9-patch with grid:
800 * 1. Texture coordinates within each section of the 9-patch
801 * should change linearly to that 9-patch's rules.
802 * 2. The image as as whole should provide Vertex points at
803 * approximate guideGridSize intervals.
805 * The result should be the horizontal and vertical lines of
806 * a 9-patch overlayed by the horizontal and vertical lines of
810 * | | | | | | | <- Grid Markers
811 * -|-------|-------------------|-------|
815 * |-------+-------------------+-------|
820 * -| 4 | 5 | 6 | <- 9 Patch.
825 * |-------+-------------------+-------|
829 * -|-------|-------------------|-------|
833 * | | | | | | | <- Grid Markers
834 * -|-------|-------------------|-------|
837 * -|-----|-|---|-----|-----|---|-|-----|
838 * |-------+-------------------+-------|
840 * -|-----|-|---|-----|-----|---|-|-----|
843 * -|-----|-|---|-----|-----|---|-|-----| <- 9 Patch.
846 * -|-----|-|---|-----|-----|---|-|-----|
848 * |-------+-------------------+-------|
849 * -|-----|-|---|-----|-----|---|-|-----|
852 * -|-------|-------------------|-------|
855 std::vector<VertexToTextureCoord> horizontalDivisions;
856 std::vector<VertexToTextureCoord> verticalDivisions;
858 const float guideGridSize = mShader->GetGridDensity();
860 const int textureWidth = texture->GetWidth();
861 const int textureHeight = texture->GetHeight();
863 const float halfWidth = size.width * 0.5f;
864 const float halfHeight = size.height * 0.5f;
866 // Determine how many rectangles across and down to tesselate image into.
867 const int guideRectX = (size.width / guideGridSize);
868 const int guideRectY = (size.height / guideGridSize);
870 // Build up list of points in X axis where vertices need to go.
871 std::vector<VertexToTextureCoord> insertionList;
872 insertionList.reserve(4);
873 insertionList.push_back( VertexToTextureCoord( -halfWidth, 0.0f ) );
875 // If 9-Patch Border exists, add additional border points in list.
878 float borderX0, borderX1, borderU0, borderU1;
880 if ( borderInPixels )
882 borderX0 = border->x - halfWidth;
883 borderX1 = halfWidth - border->z;
885 borderU0 = border->x / textureWidth;
886 borderU1 = 1.0f - (border->z / textureWidth);
890 borderX0 = border->x * textureWidth - halfWidth;
891 borderX1 = halfWidth - (1.0f - border->z) * textureWidth;
892 borderU0 = border->x;
893 borderU1 = border->z;
896 insertionList.push_back( VertexToTextureCoord( borderX0, borderU0 ) );
897 insertionList.push_back( VertexToTextureCoord( borderX1, borderU1 ) );
900 insertionList.push_back( VertexToTextureCoord( halfWidth, 1.0f ) );
901 GenerateIntervals(horizontalDivisions, guideRectX + 2, insertionList);
903 // Build up list of points in Y axis where vertices need to go.
904 insertionList.clear();
905 insertionList.push_back( VertexToTextureCoord( -halfHeight, 0.0f ) );
907 // If 9-Patch Border exists, add additional border points in list.
910 float borderY0, borderY1, borderU0, borderU1;
912 if ( borderInPixels )
914 borderY0 = border->y - halfHeight;
915 borderY1 = halfHeight - border->w;
917 borderU0 = border->y / textureHeight;
918 borderU1 = 1.0f - (border->w / textureHeight);
922 borderY0 = border->y * textureHeight - halfHeight;
923 borderY1 = halfHeight - (1.0f - border->w) * textureHeight;
925 borderU0 = border->y;
926 borderU1 = border->w;
929 insertionList.push_back( VertexToTextureCoord( borderY0, borderU0 ) );
930 insertionList.push_back( VertexToTextureCoord( borderY1, borderU1 ) );
933 insertionList.push_back( VertexToTextureCoord( halfHeight, 1.0f ) );
934 GenerateIntervals(verticalDivisions, guideRectY + 2, insertionList);
936 // Now build up Vertex pattern based on the above X and Y lists.
937 const int totalVertices = horizontalDivisions.size() * verticalDivisions.size();
938 Vertex2D* vertices = new Vertex2D[totalVertices];
939 Vertex2D* vertex = vertices;
941 for(std::vector<VertexToTextureCoord>::const_iterator yIter = verticalDivisions.begin(); yIter != verticalDivisions.end(); ++yIter )
943 for(std::vector<VertexToTextureCoord>::const_iterator xIter = horizontalDivisions.begin(); xIter != horizontalDivisions.end(); ++xIter )
945 vertex->mX = xIter->x;
946 vertex->mU = xIter->u;
947 vertex->mY = yIter->x;
948 vertex->mV = yIter->u;
953 // Build up Triangle indicies, very predictable pattern.
954 const size_t rectX = horizontalDivisions.size() - 1;
955 const size_t rectY = verticalDivisions.size() - 1;
956 const size_t totalIndices = rectX * rectY * 6; // 2 triangles per quad (rect) and 3 points to define each triangle.
957 GLushort* indices = new GLushort[totalIndices];
959 GenerateMeshIndices(indices, rectX, rectY);
961 texture->MapUV( totalVertices, vertices, pixelArea );
963 UpdateVertexBuffer( *mContextDELETEME, totalVertices * sizeof(Vertex2D) , vertices );
964 UpdateIndexBuffer( *mContextDELETEME, totalIndices * sizeof(GLushort), indices );
970 void ImageRenderer::GenerateMeshIndices(GLushort* indices, int rectanglesX, int rectanglesY)
972 GLushort *i = indices;
973 const int meshEndIndex = rectanglesY * (rectanglesX + 1);
976 while(index < meshEndIndex)
978 const int rowEndIndex = index + rectanglesX;
979 for (; index < rowEndIndex; index++ )
982 *i++ = index + 1 + rectanglesX;
986 *i++ = index + 1 + rectanglesX;
987 *i++ = index + 2 + rectanglesX;
989 index++; // one extra vertex per row than rects.
993 ImageRenderer::ImageRenderer( NodeDataProvider& dataProvider )
994 : Renderer( dataProvider ),
996 mBorder( 0.45, 0.45, 0.1, 0.1 ),
1000 mMeshType( ImageRenderer::QUAD ),
1001 mIsMeshGenerated( false ),
1002 mBorderInPixels( false ),
1004 mUsePixelArea( false )
1008 } // namespace SceneGraph
1010 } // namespace Internal