1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include <cstring>
4
5 #include "VertexArray.h"
6
7 //////////////////////////////////////////////////////////////////////
8 // Construction/Destruction
9 //////////////////////////////////////////////////////////////////////
10
CVertexArray(unsigned int maxVerts)11 CVertexArray::CVertexArray(unsigned int maxVerts): maxVertices(maxVerts)
12 {
13 drawArray = new float[VA_INIT_VERTEXES]; // please don't change this, some files rely on specific initial sizes
14 stripArray = new unsigned int[VA_INIT_STRIPS];
15 Initialize();
16 drawArraySize = drawArray + VA_INIT_VERTEXES;
17 stripArraySize = stripArray + VA_INIT_STRIPS;
18 }
19
~CVertexArray()20 CVertexArray::~CVertexArray()
21 {
22 delete[] drawArray;
23 delete[] stripArray;
24 drawArray = NULL;
25 stripArray = NULL;
26 }
27
28
29 //////////////////////////////////////////////////////////////////////
30 //
31 //////////////////////////////////////////////////////////////////////
32
Initialize()33 void CVertexArray::Initialize()
34 {
35 drawArrayPos = drawArray;
36 stripArrayPos = stripArray;
37 }
38
IsReady() const39 bool CVertexArray::IsReady() const
40 {
41 return true;
42 }
43
EndStrip()44 void CVertexArray::EndStrip()
45 {
46 if ((char*)stripArrayPos > ((char*)stripArraySize - 4 * sizeof(unsigned int))) {
47 EnlargeStripArray();
48 }
49
50 *stripArrayPos++ = ((char*)drawArrayPos - (char*)drawArray);
51 }
52
53
54 //////////////////////////////////////////////////////////////////////
55 //
56 //////////////////////////////////////////////////////////////////////
57
58
IsPrimitiveSplitable(GLenum mode)59 static inline bool IsPrimitiveSplitable(GLenum mode)
60 {
61 switch (mode) {
62 case GL_TRIANGLE_FAN:
63 case GL_POLYGON:
64 case GL_LINE_LOOP:
65 { return false; }
66 default:
67 { return true; }
68 }
69 }
70
71
GetPrimitiveRestartEach(GLenum mode)72 static inline int GetPrimitiveRestartEach(GLenum mode)
73 {
74 switch (mode) {
75 case GL_TRIANGLE_STRIP:
76 { return 2; }
77 case GL_QUAD_STRIP:
78 { return 2; }
79 case GL_TRIANGLES:
80 { return 3; }
81 case GL_QUADS:
82 { return 4; }
83 case GL_LINES:
84 { return 2; }
85 default:
86 { return 1; }
87 }
88 }
89
90
GetStripStartOffset(GLenum mode)91 static inline int GetStripStartOffset(GLenum mode)
92 {
93 switch (mode) {
94 case GL_TRIANGLES:
95 case GL_QUAD_STRIP:
96 { return 2; }
97 case GL_LINE_STRIP:
98 { return 1; }
99 default:
100 { return 0; }
101 }
102 }
103
104
DrawArrays(const GLenum mode,const unsigned int stride)105 void CVertexArray::DrawArrays(const GLenum mode, const unsigned int stride)
106 {
107 unsigned int length;
108 unsigned int newIndex, oldIndex = 0;
109 const unsigned int* stripArrayPtr = stripArray;
110
111 if (!IsPrimitiveSplitable(mode)) {
112 //! we can't split this primitive types
113 while (stripArrayPtr < stripArrayPos) {
114 newIndex = (*stripArrayPtr++) / stride;
115 length = newIndex - oldIndex;
116 glDrawArrays(mode, oldIndex, length);
117 oldIndex = newIndex;
118 }
119 } else {
120 //! split the va in optimal strip sizes, to increase the performance
121 const int optVertCount = maxVertices - (maxVertices % GetPrimitiveRestartEach(mode));
122 const int stripOffset = GetStripStartOffset(mode);
123
124 while (stripArrayPtr < stripArrayPos) {
125 newIndex=(*stripArrayPtr++) / stride;
126 length = newIndex - oldIndex;
127
128 if (length > 1.5f * optVertCount) {
129 int spliti = length / optVertCount;
130 do {
131 glDrawArrays(mode, oldIndex, optVertCount);
132 oldIndex += optVertCount - stripOffset;
133 } while (--spliti > 0);
134
135 if (newIndex > oldIndex)
136 glDrawArrays(mode, oldIndex, newIndex - oldIndex);
137 } else {
138 glDrawArrays(mode, oldIndex, length);
139 }
140 oldIndex = newIndex;
141 }
142 }
143 }
144
145
DrawArraysCallback(const GLenum mode,const unsigned int stride,StripCallback callback,void * data)146 void CVertexArray::DrawArraysCallback(const GLenum mode, const unsigned int stride, StripCallback callback, void* data)
147 {
148 unsigned int length;
149 unsigned int newIndex, oldIndex = 0;
150 const unsigned int* stripArrayPtr = stripArray;
151
152 if (!IsPrimitiveSplitable(mode)) {
153 //! we can't split those primitive types
154 while (stripArrayPtr < stripArrayPos) {
155 callback(data);
156 newIndex = (*stripArrayPtr++)/stride;
157 length = newIndex - oldIndex;
158 glDrawArrays(mode, oldIndex, length);
159 oldIndex = newIndex;
160 }
161 } else {
162 //! split the va in optimal strip sizes, to increase the performance
163 const int optVertCount = maxVertices - (maxVertices % GetPrimitiveRestartEach(mode));
164 const int stripOffset = GetStripStartOffset(mode);
165
166 while (stripArrayPtr < stripArrayPos) {
167 callback(data);
168 newIndex = (*stripArrayPtr++) / stride;
169 length = newIndex - oldIndex;
170
171 if (length > 1.25f * optVertCount) {
172 int spliti = length / optVertCount;
173 do {
174 glDrawArrays(mode, oldIndex, optVertCount);
175 oldIndex += optVertCount - stripOffset;
176 } while(--spliti>0);
177
178 if (newIndex > oldIndex)
179 glDrawArrays(mode, oldIndex, newIndex - oldIndex);
180 } else {
181 glDrawArrays(mode, oldIndex, length);
182 }
183 oldIndex=newIndex;
184 }
185 }
186 }
187
188
189
190
191 //////////////////////////////////////////////////////////////////////
192 //
193 //////////////////////////////////////////////////////////////////////
194
DrawArray0(const int drawType,unsigned int stride)195 void CVertexArray::DrawArray0(const int drawType, unsigned int stride)
196 {
197 if (drawIndex() == 0)
198 return;
199
200 CheckEndStrip();
201 glEnableClientState(GL_VERTEX_ARRAY);
202 glVertexPointer(3, GL_FLOAT, stride, drawArray);
203 DrawArrays(drawType, stride);
204 glDisableClientState(GL_VERTEX_ARRAY);
205 }
206
DrawArray2d0(const int drawType,unsigned int stride)207 void CVertexArray::DrawArray2d0(const int drawType, unsigned int stride)
208 {
209 if (drawIndex() == 0)
210 return;
211
212 CheckEndStrip();
213 glEnableClientState(GL_VERTEX_ARRAY);
214 glVertexPointer(2, GL_FLOAT, stride, drawArray);
215 DrawArrays(drawType, stride);
216 glDisableClientState(GL_VERTEX_ARRAY);
217 }
218
DrawArrayN(const int drawType,unsigned int stride)219 void CVertexArray::DrawArrayN(const int drawType, unsigned int stride)
220 {
221 if (drawIndex() == 0)
222 return;
223
224 CheckEndStrip();
225 glEnableClientState(GL_VERTEX_ARRAY);
226 glEnableClientState(GL_NORMAL_ARRAY);
227 glVertexPointer(3, GL_FLOAT, stride, drawArray);
228 glNormalPointer(GL_FLOAT, stride, drawArray + 3);
229 DrawArrays(drawType, stride);
230 glDisableClientState(GL_VERTEX_ARRAY);
231 glDisableClientState(GL_NORMAL_ARRAY);
232 }
233
234
DrawArrayC(const int drawType,unsigned int stride)235 void CVertexArray::DrawArrayC(const int drawType, unsigned int stride)
236 {
237 if (drawIndex() == 0)
238 return;
239
240 CheckEndStrip();
241 glEnableClientState(GL_VERTEX_ARRAY);
242 glEnableClientState(GL_COLOR_ARRAY);
243 glVertexPointer(3, GL_FLOAT, stride, drawArray);
244 glColorPointer(4, GL_UNSIGNED_BYTE, stride, drawArray + 3);
245 DrawArrays(drawType, stride);
246 glDisableClientState(GL_VERTEX_ARRAY);
247 glDisableClientState(GL_COLOR_ARRAY);
248 }
249
250
DrawArrayT(const int drawType,unsigned int stride)251 void CVertexArray::DrawArrayT(const int drawType, unsigned int stride)
252 {
253 if (drawIndex() == 0)
254 return;
255
256 CheckEndStrip();
257 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
258 glEnableClientState(GL_VERTEX_ARRAY);
259 glVertexPointer(3, GL_FLOAT, stride, drawArray);
260 glTexCoordPointer(2, GL_FLOAT, stride, drawArray + 3);
261 DrawArrays(drawType, stride);
262 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
263 glDisableClientState(GL_VERTEX_ARRAY);
264 }
265
266
DrawArray2dT(const int drawType,unsigned int stride)267 void CVertexArray::DrawArray2dT(const int drawType, unsigned int stride)
268 {
269 if (drawIndex() == 0)
270 return;
271
272 CheckEndStrip();
273 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
274 glEnableClientState(GL_VERTEX_ARRAY);
275 glVertexPointer(2, GL_FLOAT, stride, drawArray);
276 glTexCoordPointer(2, GL_FLOAT, stride, drawArray + 2);
277 DrawArrays(drawType, stride);
278 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
279 glDisableClientState(GL_VERTEX_ARRAY);
280 }
281
282
DrawArray2dTC(const int drawType,unsigned int stride)283 void CVertexArray::DrawArray2dTC(const int drawType, unsigned int stride)
284 {
285 if (drawIndex() == 0)
286 return;
287
288 CheckEndStrip();
289 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
290 glEnableClientState(GL_VERTEX_ARRAY);
291 glEnableClientState(GL_COLOR_ARRAY);
292 glVertexPointer(2, GL_FLOAT, stride, drawArray);
293 glTexCoordPointer(2, GL_FLOAT, stride, drawArray + 2);
294 glColorPointer(4, GL_UNSIGNED_BYTE, stride, drawArray + 4);
295 DrawArrays(drawType, stride);
296 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
297 glDisableClientState(GL_VERTEX_ARRAY);
298 glDisableClientState(GL_COLOR_ARRAY);
299 }
300
301
DrawArray2dT(const int drawType,StripCallback callback,void * data,unsigned int stride)302 void CVertexArray::DrawArray2dT(const int drawType, StripCallback callback, void* data, unsigned int stride)
303 {
304 if (drawIndex() == 0)
305 return;
306
307 CheckEndStrip();
308 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
309 glEnableClientState(GL_VERTEX_ARRAY);
310 glVertexPointer(2, GL_FLOAT, stride, drawArray);
311 glTexCoordPointer(2, GL_FLOAT, stride, drawArray + 2);
312 DrawArraysCallback(drawType, stride, callback, data);
313 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
314 glDisableClientState(GL_VERTEX_ARRAY);
315 }
316
317
DrawArrayTN(const int drawType,unsigned int stride)318 void CVertexArray::DrawArrayTN(const int drawType, unsigned int stride)
319 {
320 if (drawIndex() == 0)
321 return;
322
323 CheckEndStrip();
324 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
325 glEnableClientState(GL_VERTEX_ARRAY);
326 glEnableClientState(GL_NORMAL_ARRAY);
327
328 glVertexPointer(3, GL_FLOAT, stride, drawArray);
329 glTexCoordPointer(2, GL_FLOAT, stride, drawArray + 3);
330 glNormalPointer(GL_FLOAT, stride, drawArray + 5);
331 DrawArrays(drawType, stride);
332
333 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
334 glDisableClientState(GL_VERTEX_ARRAY);
335 glDisableClientState(GL_NORMAL_ARRAY);
336 }
337
DrawArrayTNT(const int drawType,unsigned int stride)338 void CVertexArray::DrawArrayTNT(const int drawType, unsigned int stride)
339 {
340 if (drawIndex() == 0)
341 return;
342
343 CheckEndStrip();
344
345 #define SET_ENABLE_ACTIVE_TEX(texUnit) \
346 glClientActiveTexture(texUnit); \
347 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
348 #define SET_DISABLE_ACTIVE_TEX(texUnit) \
349 glClientActiveTexture(texUnit); \
350 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
351
352 glEnableClientState(GL_VERTEX_ARRAY);
353 glEnableClientState(GL_NORMAL_ARRAY);
354
355 SET_ENABLE_ACTIVE_TEX(GL_TEXTURE0); glTexCoordPointer(2, GL_FLOAT, stride, drawArray + 3);
356 SET_ENABLE_ACTIVE_TEX(GL_TEXTURE1); glTexCoordPointer(2, GL_FLOAT, stride, drawArray + 3); // FIXME? (format-specific)
357 SET_ENABLE_ACTIVE_TEX(GL_TEXTURE5); glTexCoordPointer(3, GL_FLOAT, stride, drawArray + 8);
358 SET_ENABLE_ACTIVE_TEX(GL_TEXTURE6); glTexCoordPointer(3, GL_FLOAT, stride, drawArray + 11);
359
360 glVertexPointer(3, GL_FLOAT, stride, drawArray + 0);
361 glNormalPointer(GL_FLOAT, stride, drawArray + 5);
362
363 DrawArrays(drawType, stride);
364
365 SET_DISABLE_ACTIVE_TEX(GL_TEXTURE6);
366 SET_DISABLE_ACTIVE_TEX(GL_TEXTURE5);
367 SET_DISABLE_ACTIVE_TEX(GL_TEXTURE1);
368 SET_DISABLE_ACTIVE_TEX(GL_TEXTURE0);
369
370 glDisableClientState(GL_NORMAL_ARRAY);
371 glDisableClientState(GL_VERTEX_ARRAY);
372
373 #undef SET_ENABLE_ACTIVE_TEX
374 #undef SET_DISABLE_ACTIVE_TEX
375 }
376
377
DrawArrayTC(const int drawType,unsigned int stride)378 void CVertexArray::DrawArrayTC(const int drawType, unsigned int stride)
379 {
380 if (drawIndex() == 0)
381 return;
382
383 CheckEndStrip();
384 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
385 glEnableClientState(GL_VERTEX_ARRAY);
386 glEnableClientState(GL_COLOR_ARRAY);
387 glVertexPointer(3, GL_FLOAT, stride, drawArray);
388 glTexCoordPointer(2, GL_FLOAT, stride, drawArray + 3);
389 glColorPointer(4, GL_UNSIGNED_BYTE, stride, drawArray + 5);
390 DrawArrays(drawType, stride);
391 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
392 glDisableClientState(GL_VERTEX_ARRAY);
393 glDisableClientState(GL_COLOR_ARRAY);
394 }
395
396
397
398
399 //////////////////////////////////////////////////////////////////////
400 //
401 //////////////////////////////////////////////////////////////////////
402
EnlargeDrawArray()403 void CVertexArray::EnlargeDrawArray()
404 {
405 const unsigned int pos = drawArrayPos - drawArray;
406 const unsigned int oldsize = drawArraySize - drawArray;
407 const unsigned int newsize = oldsize * 2;
408
409 float* tempArray = new float[newsize];
410 memcpy(tempArray, drawArray, oldsize * sizeof(float));
411
412 delete[] drawArray;
413
414 drawArray = tempArray;
415 drawArraySize = drawArray + newsize;
416 drawArrayPos = drawArray + pos;
417 }
418
EnlargeStripArray()419 void CVertexArray::EnlargeStripArray()
420 {
421 const unsigned int pos = stripArrayPos - stripArray;
422 const unsigned int oldsize = stripArraySize - stripArray;
423 const unsigned int newsize = oldsize * 2;
424
425 unsigned int* tempArray = new unsigned int[newsize];
426 memcpy(tempArray,stripArray, oldsize * sizeof(unsigned int));
427
428 delete[] stripArray;
429
430 stripArray = tempArray;
431 stripArraySize = stripArray + newsize;
432 stripArrayPos = stripArray + pos;
433 }
434