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