Merge 'remotes/trunk'
[0ad.git] / source / renderer / VertexArray.cpp
blob20061ffc88eabc3430c31dda891eb4c54df5d929
1 /* Copyright (C) 2015 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
20 #include "lib/alignment.h"
21 #include "lib/ogl.h"
22 #include "lib/sysdep/rtl.h"
23 #include "maths/Vector3D.h"
24 #include "maths/Vector4D.h"
25 #include "ps/CLogger.h"
26 #include "graphics/Color.h"
27 #include "graphics/SColor.h"
28 #include "renderer/VertexArray.h"
29 #include "renderer/VertexBuffer.h"
30 #include "renderer/VertexBufferManager.h"
33 VertexArray::VertexArray(GLenum usage, GLenum target)
35 m_Usage = usage;
36 m_Target = target;
37 m_NumVertices = 0;
39 m_VB = 0;
40 m_BackingStore = 0;
41 m_Stride = 0;
45 VertexArray::~VertexArray()
47 Free();
50 // Free all resources on destruction or when a layout parameter changes
51 void VertexArray::Free()
53 rtl_FreeAligned(m_BackingStore);
54 m_BackingStore = 0;
56 if (m_VB)
58 g_VBMan.Release(m_VB);
59 m_VB = 0;
64 // Set the number of vertices stored in the array
65 void VertexArray::SetNumVertices(size_t num)
67 if (num == m_NumVertices)
68 return;
70 Free();
71 m_NumVertices = num;
75 // Add vertex attributes like Position, Normal, UV
76 void VertexArray::AddAttribute(Attribute* attr)
78 ENSURE(
79 (attr->type == GL_FLOAT || attr->type == GL_SHORT || attr->type == GL_UNSIGNED_SHORT || attr->type == GL_UNSIGNED_BYTE)
80 && "Unsupported attribute type"
82 ENSURE(attr->elems >= 1 && attr->elems <= 4);
84 attr->vertexArray = this;
85 m_Attributes.push_back(attr);
87 Free();
91 // Template specialization for GetIterator().
92 // We can put this into the source file because only a fixed set of types
93 // is supported for type safety.
94 template<>
95 VertexArrayIterator<CVector3D> VertexArray::Attribute::GetIterator<CVector3D>() const
97 ENSURE(vertexArray);
98 ENSURE(type == GL_FLOAT);
99 ENSURE(elems >= 3);
101 return vertexArray->MakeIterator<CVector3D>(this);
104 template<>
105 VertexArrayIterator<CVector4D> VertexArray::Attribute::GetIterator<CVector4D>() const
107 ENSURE(vertexArray);
108 ENSURE(type == GL_FLOAT);
109 ENSURE(elems >= 4);
111 return vertexArray->MakeIterator<CVector4D>(this);
114 template<>
115 VertexArrayIterator<float[2]> VertexArray::Attribute::GetIterator<float[2]>() const
117 ENSURE(vertexArray);
118 ENSURE(type == GL_FLOAT);
119 ENSURE(elems >= 2);
121 return vertexArray->MakeIterator<float[2]>(this);
124 template<>
125 VertexArrayIterator<SColor3ub> VertexArray::Attribute::GetIterator<SColor3ub>() const
127 ENSURE(vertexArray);
128 ENSURE(type == GL_UNSIGNED_BYTE);
129 ENSURE(elems >= 3);
131 return vertexArray->MakeIterator<SColor3ub>(this);
134 template<>
135 VertexArrayIterator<SColor4ub> VertexArray::Attribute::GetIterator<SColor4ub>() const
137 ENSURE(vertexArray);
138 ENSURE(type == GL_UNSIGNED_BYTE);
139 ENSURE(elems >= 4);
141 return vertexArray->MakeIterator<SColor4ub>(this);
144 template<>
145 VertexArrayIterator<u16> VertexArray::Attribute::GetIterator<u16>() const
147 ENSURE(vertexArray);
148 ENSURE(type == GL_UNSIGNED_SHORT);
149 ENSURE(elems >= 1);
151 return vertexArray->MakeIterator<u16>(this);
154 template<>
155 VertexArrayIterator<u16[2]> VertexArray::Attribute::GetIterator<u16[2]>() const
157 ENSURE(vertexArray);
158 ENSURE(type == GL_UNSIGNED_SHORT);
159 ENSURE(elems >= 2);
161 return vertexArray->MakeIterator<u16[2]>(this);
164 template<>
165 VertexArrayIterator<u8> VertexArray::Attribute::GetIterator<u8>() const
167 ENSURE(vertexArray);
168 ENSURE(type == GL_UNSIGNED_BYTE);
169 ENSURE(elems >= 1);
171 return vertexArray->MakeIterator<u8>(this);
174 template<>
175 VertexArrayIterator<u8[4]> VertexArray::Attribute::GetIterator<u8[4]>() const
177 ENSURE(vertexArray);
178 ENSURE(type == GL_UNSIGNED_BYTE);
179 ENSURE(elems >= 4);
181 return vertexArray->MakeIterator<u8[4]>(this);
184 template<>
185 VertexArrayIterator<short> VertexArray::Attribute::GetIterator<short>() const
187 ENSURE(vertexArray);
188 ENSURE(type == GL_SHORT);
189 ENSURE(elems >= 1);
191 return vertexArray->MakeIterator<short>(this);
194 template<>
195 VertexArrayIterator<short[2]> VertexArray::Attribute::GetIterator<short[2]>() const
197 ENSURE(vertexArray);
198 ENSURE(type == GL_SHORT);
199 ENSURE(elems >= 2);
201 return vertexArray->MakeIterator<short[2]>(this);
204 static size_t RoundStride(size_t stride)
206 if (stride <= 0)
207 return 0;
208 if (stride <= 4)
209 return 4;
210 if (stride <= 8)
211 return 8;
212 if (stride <= 16)
213 return 16;
215 return Align<32>(stride);
218 // Re-layout by assigning offsets on a first-come first-serve basis,
219 // then round up to a reasonable stride.
220 // Backing store is also created here, VBOs are created on upload.
221 void VertexArray::Layout()
223 Free();
225 m_Stride = 0;
227 //debug_printf("Layouting VertexArray\n");
229 for (ssize_t idx = m_Attributes.size()-1; idx >= 0; --idx)
231 Attribute* attr = m_Attributes[idx];
233 if (!attr->type || !attr->elems)
234 continue;
236 size_t attrSize = 0;
237 switch(attr->type)
239 case GL_UNSIGNED_BYTE:
240 attrSize = sizeof(GLubyte);
241 break;
242 case GL_SHORT:
243 attrSize = sizeof(GLshort);
244 break;
245 case GL_UNSIGNED_SHORT:
246 attrSize = sizeof(GLushort);
247 break;
248 case GL_FLOAT:
249 attrSize = sizeof(GLfloat);
250 break;
251 default:
252 attrSize = 0;
253 debug_warn(L"Bad Attribute::type"); break;
256 attrSize *= attr->elems;
258 attr->offset = m_Stride;
260 m_Stride += attrSize;
262 if (m_Target == GL_ARRAY_BUFFER)
263 m_Stride = Align<4>(m_Stride);
265 //debug_printf("%i: offset: %u\n", idx, attr->offset);
268 if (m_Target == GL_ARRAY_BUFFER)
269 m_Stride = RoundStride(m_Stride);
271 //debug_printf("Stride: %u\n", m_Stride);
273 if (m_Stride)
274 m_BackingStore = (char*)rtl_AllocateAligned(m_Stride * m_NumVertices, 16);
277 void VertexArray::PrepareForRendering()
279 m_VB->m_Owner->PrepareForRendering(m_VB);
282 // (Re-)Upload the attributes.
283 // Create the VBO if necessary.
284 void VertexArray::Upload()
286 ENSURE(m_BackingStore);
288 if (!m_VB)
289 m_VB = g_VBMan.Allocate(m_Stride, m_NumVertices, m_Usage, m_Target, m_BackingStore);
291 if (!m_VB)
293 LOGERROR("Failed to allocate VBO for vertex array");
294 return;
297 m_VB->m_Owner->UpdateChunkVertices(m_VB, m_BackingStore);
301 // Bind this array, returns the base address for calls to glVertexPointer etc.
302 u8* VertexArray::Bind()
304 if (!m_VB)
305 return NULL;
307 u8* base = m_VB->m_Owner->Bind();
308 base += m_VB->m_Index*m_Stride;
309 return base;
313 // Free the backing store to save some memory
314 void VertexArray::FreeBackingStore()
316 // In streaming modes, the backing store must be retained
317 ENSURE(!CVertexBuffer::UseStreaming(m_Usage));
319 rtl_FreeAligned(m_BackingStore);
320 m_BackingStore = 0;
325 VertexIndexArray::VertexIndexArray(GLenum usage) :
326 VertexArray(usage, GL_ELEMENT_ARRAY_BUFFER)
328 m_Attr.type = GL_UNSIGNED_SHORT;
329 m_Attr.elems = 1;
330 AddAttribute(&m_Attr);
333 VertexArrayIterator<u16> VertexIndexArray::GetIterator() const
335 return m_Attr.GetIterator<u16>();