[dali_1.2.0] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-geometry.cpp
1 /*
2  * Copyright (c) 2015 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 #include <dali/internal/render/renderers/render-geometry.h>
18 #include <dali/internal/common/buffer-index.h>
19 #include <dali/internal/render/gl-resources/context.h>
20 #include <dali/internal/render/gl-resources/gpu-buffer.h>
21 #include <dali/internal/render/renderers/render-property-buffer.h>
22 #include <dali/internal/render/shaders/program.h>
23
24 namespace Dali
25 {
26 namespace Internal
27 {
28 namespace Render
29 {
30
31 Geometry::Geometry()
32 : mIndices(),
33   mIndexBuffer(NULL),
34   mGeometryType( Dali::Geometry::TRIANGLES ),
35   mIndicesChanged(false),
36   mHasBeenUpdated(false),
37   mAttributesChanged(true)
38 {
39 }
40
41 Geometry::~Geometry()
42 {
43 }
44
45 void Geometry::GlContextCreated( Context& context )
46 {
47 }
48
49 void Geometry::GlContextDestroyed()
50 {
51 }
52
53 void Geometry::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer)
54 {
55   mVertexBuffers.PushBack( propertyBuffer );
56   mAttributesChanged = true;
57 }
58
59 void Geometry::SetIndexBuffer( Dali::Vector<unsigned short>& indices )
60 {
61   mIndices.Swap( indices );
62   mIndicesChanged = true;
63 }
64
65 const Dali::Vector<unsigned short>* Geometry::GetIndexBuffer() const
66 {
67   return &mIndices;
68 }
69
70 void Geometry::RemovePropertyBuffer( const Render::PropertyBuffer* propertyBuffer )
71 {
72   size_t bufferCount = mVertexBuffers.Size();
73   for( size_t i(0); i<bufferCount; ++i )
74   {
75     if( propertyBuffer == mVertexBuffers[i] )
76     {
77       //This will delete the gpu buffer associated to the RenderPropertyBuffer if there is one
78       mVertexBuffers.Remove( mVertexBuffers.Begin()+i );
79       mAttributesChanged = true;
80       break;
81     }
82   }
83 }
84
85 const Render::PropertyBuffer* Geometry::GetPropertyBuffer( size_t index ) const
86 {
87   if( index < mVertexBuffers.Size() )
88   {
89     return mVertexBuffers[ index ];
90   }
91   return NULL;
92 }
93
94 void Geometry::GetAttributeLocationFromProgram( Vector<GLint>& attributeLocation, Program& program, BufferIndex bufferIndex ) const
95 {
96   attributeLocation.Clear();
97
98   for( size_t i(0); i< mVertexBuffers.Size(); ++i )
99   {
100     unsigned int attributeCount = mVertexBuffers[i]->GetAttributeCount();
101     for( unsigned int j = 0; j < attributeCount; ++j )
102     {
103       const std::string& attributeName = mVertexBuffers[i]->GetAttributeName( j );
104       unsigned int index = program.RegisterCustomAttribute( attributeName );
105       GLint location = program.GetCustomAttributeLocation( index );
106
107       if( -1 == location )
108       {
109         DALI_LOG_WARNING( "Attribute not found in the shader: %s\n", attributeName.c_str() );
110       }
111
112       attributeLocation.PushBack( location );
113     }
114   }
115 }
116
117 void Geometry::OnRenderFinished()
118 {
119   mHasBeenUpdated = false;
120   mAttributesChanged = false;
121 }
122
123 void Geometry::UploadAndDraw(
124     Context& context,
125     BufferIndex bufferIndex,
126     Vector<GLint>& attributeLocation,
127     size_t elementBufferOffset,
128     size_t elementBufferCount )
129 {
130   if( !mHasBeenUpdated )
131   {
132     // Update buffers
133     if( mIndicesChanged )
134     {
135       if( mIndices.Empty() )
136       {
137         mIndexBuffer = NULL;
138       }
139       else
140       {
141         if ( mIndexBuffer == NULL )
142         {
143           mIndexBuffer = new GpuBuffer( context );
144         }
145
146         std::size_t bufferSize =  sizeof( unsigned short ) * mIndices.Size();
147         mIndexBuffer->UpdateDataBuffer( bufferSize, &mIndices[0], GpuBuffer::STATIC_DRAW, GpuBuffer::ELEMENT_ARRAY_BUFFER );
148       }
149
150       mIndicesChanged = false;
151     }
152
153     size_t count = mVertexBuffers.Count();
154     for( unsigned int i = 0; i < count; ++i )
155     {
156
157       if( !mVertexBuffers[i]->Update( context ) )
158       {
159         //Vertex buffer is not ready ( Size, data or format has not been specified yet )
160         return;
161       }
162     }
163
164     mHasBeenUpdated = true;
165   }
166
167   //Bind buffers to attribute locations
168   unsigned int base = 0u;
169   size_t vertexBufferCount(mVertexBuffers.Count());
170   for( unsigned int i = 0; i < vertexBufferCount; ++i )
171   {
172     mVertexBuffers[i]->BindBuffer( GpuBuffer::ARRAY_BUFFER );
173     base += mVertexBuffers[i]->EnableVertexAttributes( context, attributeLocation, base );
174   }
175
176   size_t numIndices(0u);
177   intptr_t firstIndexOffset(0u);
178   if( mIndexBuffer )
179   {
180     numIndices = mIndices.Size();
181
182     if( elementBufferOffset != 0u )
183     {
184       elementBufferOffset = elementBufferOffset >= numIndices ? numIndices - 1 : elementBufferOffset;
185       firstIndexOffset = elementBufferOffset * sizeof(GLushort);
186       numIndices -= elementBufferOffset;
187     }
188
189     if( elementBufferCount != 0u )
190     {
191       numIndices = std::min( elementBufferCount, numIndices );
192     }
193   }
194
195   GLenum geometryGLType(GL_NONE);
196   switch(mGeometryType)
197   {
198     case Dali::Geometry::TRIANGLES:
199     {
200       geometryGLType = GL_TRIANGLES;
201       break;
202     }
203     case Dali::Geometry::LINES:
204     {
205       geometryGLType = GL_LINES;
206       break;
207     }
208     case Dali::Geometry::POINTS:
209     {
210       geometryGLType = GL_POINTS;
211       break;
212     }
213     case Dali::Geometry::TRIANGLE_STRIP:
214     {
215       geometryGLType = GL_TRIANGLE_STRIP;
216       break;
217     }
218     case Dali::Geometry::TRIANGLE_FAN:
219     {
220       geometryGLType = GL_TRIANGLE_FAN;
221       break;
222     }
223     case Dali::Geometry::LINE_LOOP:
224     {
225       geometryGLType = GL_LINE_LOOP;
226       break;
227     }
228     case Dali::Geometry::LINE_STRIP:
229     {
230       geometryGLType = GL_LINE_STRIP;
231       break;
232     }
233   }
234
235   //Draw call
236   if( mIndexBuffer && geometryGLType != GL_POINTS )
237   {
238     //Indexed draw call
239     mIndexBuffer->Bind( GpuBuffer::ELEMENT_ARRAY_BUFFER );
240     context.DrawElements(geometryGLType, numIndices, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(firstIndexOffset));
241   }
242   else
243   {
244     //Unindex draw call
245     unsigned int numVertices(0u);
246     if( vertexBufferCount > 0 )
247     {
248       numVertices = mVertexBuffers[0]->GetElementCount();
249     }
250
251     context.DrawArrays( geometryGLType, 0, numVertices );
252   }
253
254   //Disable attributes
255   for( unsigned int i = 0; i < attributeLocation.Count(); ++i )
256   {
257     if( attributeLocation[i] != -1 )
258     {
259       context.DisableVertexAttributeArray( attributeLocation[i] );
260     }
261   }
262 }
263
264 } // namespace SceneGraph
265 } // namespace Internal
266 } // namespace Dali