Add more structure constructor tests.
[piglit/hramrach.git] / tests / glean / geomrend.cpp
blobfceb24d75f237d018743b841d50f3c053ca5e980
1 // BEGIN_COPYRIGHT -*- glean -*-
2 //
3 // Copyright (C) 1999,2000 Allen Akin All Rights Reserved.
4 //
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
12 // conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
16 // Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
26 //
27 // END_COPYRIGHT
31 // geomrend.h: convenience object for rendering any geometry via
32 // a host of OpenGL paths: immediate mode (glVertex), vertex
33 // arrays with glDrawArrays, vertex arrays with glArrayElement,
34 // vertex arrays with glDrawElements, and any of the preceding
35 // methods stuffed in a display list.
37 #include "geomrend.h"
38 #include "rand.h"
39 #include "glutils.h"
40 #include <algorithm>
41 #include <iostream>
42 #include <cmath>
43 #include <float.h>
44 #include <cassert>
46 using namespace std;
48 namespace GLEAN {
51 // geomrend.h: convenience object for rendering any geometry via
52 // a host of OpenGL paths: immediate mode (glVertex), vertex
53 // arrays with glDrawArrays, vertex arrays with glArrayElement,
54 // vertex arrays with glDrawElements, and any of the preceding
55 // methods stuffed in a display list.
57 // Functions for the helper class ArrayData, which stores the info about each parameter's data.
58 ArrayData::ArrayData()
60 size = 0;
61 type = GL_UNSIGNED_INT;
62 stride = 0;
63 pointer = 0;
66 void ArrayData::setData(GLint sizeIn, GLenum typeIn, GLsizei strideIn, const GLvoid* pointerIn)
68 size = sizeIn;
69 type = typeIn;
70 stride = strideIn;
71 pointer = pointerIn;
72 if (stride == 0)
74 stride = size;
75 switch(type)
77 case GL_BYTE: stride *= sizeof(GLbyte); break;
78 case GL_UNSIGNED_BYTE: stride *= sizeof(GLubyte); break;
79 case GL_SHORT: stride *= sizeof(GLshort); break;
80 case GL_UNSIGNED_SHORT: stride *= sizeof(GLushort); break;
81 case GL_INT: stride *= sizeof(GLint); break;
82 case GL_UNSIGNED_INT: stride *= sizeof(GLuint); break;
83 case GL_FLOAT: stride *= sizeof(GLfloat); break;
84 case GL_DOUBLE: stride *= sizeof(GLdouble); break;
85 default: assert(false);
90 // Only a default constructor.
91 GeomRenderer::GeomRenderer() : vertexData(), colorData(), texCoordData(), normalData()
93 drawMethod = GLVERTEX_MODE;
94 parameterBits = 0;
95 compileArrays = false;
97 indicesCount = 0;
98 indicesType = GL_UNSIGNED_INT;
99 indices = 0;
101 arrayLength = 0;
104 // Used to set the method by which this GeomRenderer will pass the primitive data to the GL.
105 // Default is GLVERTEX_MODE.
106 void GeomRenderer::setDrawMethod(GeomRenderer::DrawMethod method)
108 drawMethod = method;
111 GeomRenderer::DrawMethod GeomRenderer::getDrawMethod() const
113 return drawMethod;
116 // Used to set the various parameters that are either enabled or disabled. Example usage:
117 // to tell the GeomRenderer to pass vertex, color, and texcoord data, but not normals,
118 // call setParameterBits(COLOR_BIT | TEXTURE_COORD_BIT). (Vertex data is implicitly enabled
119 // all the time.) The default is that only vertex data is enabled.
120 void GeomRenderer::setParameterBits(GLuint bits)
122 parameterBits = bits;
125 GLuint GeomRenderer::getParameterBits() const
127 return parameterBits;
130 // Used to specify whether EXT_compiled_vertex_array should be used if present. Default is false.
131 // If set to true, the arrays are kept unlocked and only locked just before rendering calls are issued.
132 // If you call setArraysCompiled(true) and the extension is not present, the function returns false
133 // and acts as though you had passed false in as the argument.
134 bool GeomRenderer::setArraysCompiled(bool compile)
136 // Make sure we have the extension.
137 if (!GLUtils::haveExtension("GL_EXT_compiled_vertex_array") && compile == true)
139 compileArrays = false;
140 return false;
143 compileArrays = compile;
144 return true;
147 bool GeomRenderer::getArraysCompiled() const
149 return compileArrays;
152 // If you're using GLDRAWELEMENTS_MODE, GLARRAYELEMENT_MODE, or GLVERTEX_MODE, you need to give
153 // it the indices to pass into the GL.
154 void GeomRenderer::setVArrayIndices(GLuint count, GLenum type, const GLvoid* indicesIn)
156 assert(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT);
158 indicesCount = count;
159 indicesType = type;
160 indices = indicesIn;
163 // This hands the actual primitive data to the GeomRenderer. It holds onto these as pointers,
164 // rather than copying them, so don't delete the data until you're done with the GeomRenderer.
165 // These are prototypically equivalent to their respective GL calls, except that there's an extra
166 // argument on the front of the vertex function for how many elements are in the array (this is
167 // atomic; if you pass in 5, it means there are 5 vertices, not 5 floats or bytes or whatever).
168 // The lengths of all other arrays are assumed to be >= the size passed in for the vertex array.
169 void GeomRenderer::setVertexPointer(GLuint length, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
171 arrayLength = length;
172 vertexData.setData(size, type, stride, pointer);
175 void GeomRenderer::setColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
177 colorData.setData(size, type, stride, pointer);
180 void GeomRenderer::setTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
182 texCoordData.setData(size, type, stride, pointer);
185 void GeomRenderer::setNormalPointer(GLenum type, GLsizei stride, const GLvoid* pointer)
187 normalData.setData(3, type, stride, pointer);
190 // Finally, the actual calls to do something with all this data. You can either choose to render
191 // it given the configuration, or generate a display list of rendering it with the given
192 // configuration (uses GL_COMPILE mode to build the list). Fails if insufficient data has
193 // been given (i.e. if you don't give it an array for an enabled parameter, if you don't
194 // give it an array of indices when it needs them).
195 // Note that rendering with GLVERTEX_MODE currently involves a lot of CPU overhead to
196 // unpack the data and pass it to the GL; while the results will be correct, it would be
197 // unwise to use this method for rendering that is to be benchmarked, because it will
198 // underestimate performance significantly on some machines.
199 bool GeomRenderer::renderPrimitives(GLenum mode)
201 if (!isReadyToRender())
203 return false;
206 // Okay, different sections here depending on what we're doing.
207 if (drawMethod == GLVERTEX_MODE)
209 glBegin(mode);
210 for (unsigned int x=0; x<indicesCount; x++)
212 int directIndex = getIndex(x);
213 if (parameterBits & COLOR_BIT) sendColor(directIndex);
214 if (parameterBits & TEXTURE_COORD_BIT) sendTexCoord(directIndex);
215 if (parameterBits & NORMAL_BIT) sendNormal(directIndex);
216 sendVertex(directIndex);
218 glEnd();
220 // Otherwise it has something to do with arrays; set up the arrays.
221 else
223 if (parameterBits & COLOR_BIT)
225 glEnableClientState(GL_COLOR_ARRAY);
226 glColorPointer(colorData.size, colorData.type, colorData.stride, colorData.pointer);
227 // std::cout << "Enabled color arrays, size [" << colorData.size << "], type [" << colorData.type
228 // << "], stride [" << colorData.stride << "], pointer [" << colorData.pointer << "]" << std::endl;
230 if (parameterBits & TEXTURE_COORD_BIT)
232 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
233 glTexCoordPointer(texCoordData.size, texCoordData.type, texCoordData.stride, texCoordData.pointer);
234 // std::cout << "Enabled texCoord arrays, size [" << texCoordData.size << "], type [" << texCoordData.type
235 // << "], stride [" << texCoordData.stride << "], pointer [" << texCoordData.pointer << "]" << std::endl;
237 if (parameterBits & NORMAL_BIT)
239 glEnableClientState(GL_NORMAL_ARRAY);
240 glNormalPointer(normalData.type, normalData.stride, normalData.pointer);
241 // std::cout << "Enabled normal arrays, size [" << normalData.size << "], type [" << normalData.type
242 // << "], stride [" << normalData.stride << "], pointer [" << normalData.pointer << "]" << std::endl;
244 glEnableClientState(GL_VERTEX_ARRAY);
245 glVertexPointer(vertexData.size, vertexData.type, vertexData.stride, vertexData.pointer);
246 // std::cout << "Enabled vertex arrays, size [" << vertexData.size << "], type [" << vertexData.type
247 // << "], stride [" << vertexData.stride << "], pointer [" << vertexData.pointer << "]" << std::endl;
249 // Should we lock?
250 if (compileArrays)
252 PFNGLLOCKARRAYSEXTPROC glLockArraysEXT = 0;
253 assert(GLUtils::haveExtension("GL_EXT_compiled_vertex_array"));
254 glLockArraysEXT = reinterpret_cast<PFNGLLOCKARRAYSEXTPROC>
255 (GLUtils::getProcAddress("glLockArraysEXT"));
256 glLockArraysEXT(0, arrayLength);
259 // Okay, arrays configured; what exactly are we doing?
260 if (drawMethod == GLARRAYELEMENT_MODE)
262 glBegin(mode);
263 for (unsigned int x=0; x<indicesCount; x++)
265 glArrayElement(getIndex(x));
267 glEnd();
269 else if (drawMethod == GLDRAWARRAYS_MODE)
271 glDrawArrays(mode, 0, arrayLength);
272 std::cout << "Called glDrawArrays, mode [" << mode << "], from 0 to " << arrayLength << std::endl;
274 else if (drawMethod == GLDRAWELEMENTS_MODE)
276 glDrawElements(mode, indicesCount, indicesType, indices);
279 // Done. If we locked, unlock.
280 if (compileArrays)
282 PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT = 0;
283 assert(GLUtils::haveExtension("GL_EXT_compiled_vertex_array"));
284 glUnlockArraysEXT = reinterpret_cast<PFNGLUNLOCKARRAYSEXTPROC>
285 (GLUtils::getProcAddress("glUnlockArraysEXT"));
286 glUnlockArraysEXT();
290 return true;
293 bool GeomRenderer::generateDisplayList(GLenum mode, GLint& listHandleOut)
295 bool result;
297 if (!isReadyToRender())
299 return false;
302 listHandleOut = glGenLists(1);
303 glNewList(listHandleOut, GL_COMPILE);
304 result = renderPrimitives(mode);
305 assert(result);
306 glEndList();
308 return true;
311 bool GeomRenderer::isReadyToRender()
313 // Make sure we have vertex data.
314 if (vertexData.pointer == 0) return false;
316 // For the enabled parameters, make sure we have them, too.
317 if ((parameterBits & COLOR_BIT ) && (colorData.pointer == 0)) return false;
318 if ((parameterBits & TEXTURE_COORD_BIT) && (texCoordData.pointer == 0)) return false;
319 if ((parameterBits & NORMAL_BIT ) && (normalData.pointer == 0)) return false;
321 // If we need indices, we'd better have them.
322 if ((drawMethod == GLVERTEX_MODE ||
323 drawMethod == GLARRAYELEMENT_MODE ||
324 drawMethod == GLDRAWELEMENTS_MODE) && indices == 0)
326 return false;
329 // Otherwise we're good to go!
330 return true;
333 // This unpacks the indices depending on their format and returns the specified one.
334 GLuint GeomRenderer::getIndex(int indicesIndex)
336 assert(indicesIndex >= 0 && indicesIndex < static_cast<int>(indicesCount));
338 switch (indicesType)
340 case GL_UNSIGNED_BYTE:
341 return ((GLubyte*)indices)[indicesIndex];
342 break;
344 case GL_UNSIGNED_SHORT:
345 return ((GLushort*)indices)[indicesIndex];
346 break;
348 case GL_UNSIGNED_INT:
349 return ((GLuint*)indices)[indicesIndex];
350 break;
352 default:
353 assert(false);
354 break;
357 // It never gets here, but let's quell the compiler warning...
358 return 0;
361 // I thought about making a lookup table for this, but it would involve an STL map of STL vectors
362 // and some weird function casts, so I'm doing it the naive way instead.
363 void GeomRenderer::sendVertex(GLuint vertexIndex)
365 assert(vertexData.size >= 2 && vertexData.size <= 4);
367 switch(vertexData.type)
369 case GL_SHORT:
370 if (vertexData.size == 2) glVertex2sv((const GLshort*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
371 if (vertexData.size == 3) glVertex3sv((const GLshort*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
372 if (vertexData.size == 4) glVertex4sv((const GLshort*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
373 break;
375 case GL_INT:
376 if (vertexData.size == 2) glVertex2iv((const GLint*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
377 if (vertexData.size == 3) glVertex3iv((const GLint*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
378 if (vertexData.size == 4) glVertex4iv((const GLint*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
379 break;
381 case GL_FLOAT:
382 if (vertexData.size == 2) glVertex2fv((const GLfloat*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
383 if (vertexData.size == 3) glVertex3fv((const GLfloat*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
384 if (vertexData.size == 4) glVertex4fv((const GLfloat*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
385 break;
387 case GL_DOUBLE:
388 if (vertexData.size == 2) glVertex2dv((const GLdouble*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
389 if (vertexData.size == 3) glVertex3dv((const GLdouble*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
390 if (vertexData.size == 4) glVertex4dv((const GLdouble*)((const char*)vertexData.pointer + vertexIndex*vertexData.stride));
391 break;
395 void GeomRenderer::sendColor(GLuint colorIndex)
397 assert(colorData.size == 3 || colorData.size == 4);
399 switch(colorData.type)
401 case GL_BYTE:
402 if (colorData.size == 3) glColor3bv((const GLbyte*)((const char*)colorData.pointer + colorIndex*colorData.stride));
403 if (colorData.size == 4) glColor4bv((const GLbyte*)((const char*)colorData.pointer + colorIndex*colorData.stride));
404 break;
406 case GL_UNSIGNED_BYTE:
407 if (colorData.size == 3) glColor3ubv((const GLubyte*)((const char*)colorData.pointer + colorIndex*colorData.stride));
408 if (colorData.size == 4) glColor4ubv((const GLubyte*)((const char*)colorData.pointer + colorIndex*colorData.stride));
409 break;
411 case GL_SHORT:
412 if (colorData.size == 3) glColor3sv((const GLshort*)((const char*)colorData.pointer + colorIndex*colorData.stride));
413 if (colorData.size == 4) glColor4sv((const GLshort*)((const char*)colorData.pointer + colorIndex*colorData.stride));
414 break;
416 case GL_UNSIGNED_SHORT:
417 if (colorData.size == 3) glColor3usv((const GLushort*)((const char*)colorData.pointer + colorIndex*colorData.stride));
418 if (colorData.size == 4) glColor4usv((const GLushort*)((const char*)colorData.pointer + colorIndex*colorData.stride));
419 break;
421 case GL_INT:
422 if (colorData.size == 3) glColor3iv((const GLint*)((const char*)colorData.pointer + colorIndex*colorData.stride));
423 if (colorData.size == 4) glColor4iv((const GLint*)((const char*)colorData.pointer + colorIndex*colorData.stride));
424 break;
426 case GL_UNSIGNED_INT:
427 if (colorData.size == 3) glColor3uiv((const GLuint*)((const char*)colorData.pointer + colorIndex*colorData.stride));
428 if (colorData.size == 4) glColor4uiv((const GLuint*)((const char*)colorData.pointer + colorIndex*colorData.stride));
429 break;
431 case GL_FLOAT:
432 if (colorData.size == 3) glColor3fv((const GLfloat*)((const char*)colorData.pointer + colorIndex*colorData.stride));
433 if (colorData.size == 4) glColor4fv((const GLfloat*)((const char*)colorData.pointer + colorIndex*colorData.stride));
434 break;
436 case GL_DOUBLE:
437 if (colorData.size == 3) glColor3dv((const GLdouble*)((const char*)colorData.pointer + colorIndex*colorData.stride));
438 if (colorData.size == 4) glColor4dv((const GLdouble*)((const char*)colorData.pointer + colorIndex*colorData.stride));
439 break;
443 void GeomRenderer::sendTexCoord(GLuint texCoordIndex)
445 assert(texCoordData.size >= 1 && texCoordData.size <= 4);
447 switch(texCoordData.type)
449 case GL_SHORT:
450 if (texCoordData.size == 1) glTexCoord1sv((const GLshort*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
451 if (texCoordData.size == 2) glTexCoord2sv((const GLshort*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
452 if (texCoordData.size == 3) glTexCoord3sv((const GLshort*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
453 if (texCoordData.size == 4) glTexCoord4sv((const GLshort*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
454 break;
456 case GL_INT:
457 if (texCoordData.size == 1) glTexCoord1iv((const GLint*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
458 if (texCoordData.size == 2) glTexCoord2iv((const GLint*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
459 if (texCoordData.size == 3) glTexCoord3iv((const GLint*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
460 if (texCoordData.size == 4) glTexCoord4iv((const GLint*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
461 break;
463 case GL_FLOAT:
464 if (texCoordData.size == 1) glTexCoord1fv((const GLfloat*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
465 if (texCoordData.size == 2) glTexCoord2fv((const GLfloat*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
466 if (texCoordData.size == 3) glTexCoord3fv((const GLfloat*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
467 if (texCoordData.size == 4) glTexCoord4fv((const GLfloat*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
468 break;
470 case GL_DOUBLE:
471 if (texCoordData.size == 1) glTexCoord1dv((const GLdouble*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
472 if (texCoordData.size == 2) glTexCoord2dv((const GLdouble*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
473 if (texCoordData.size == 3) glTexCoord3dv((const GLdouble*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
474 if (texCoordData.size == 4) glTexCoord4dv((const GLdouble*)((const char*)texCoordData.pointer + texCoordIndex*texCoordData.stride));
475 break;
479 void GeomRenderer::sendNormal(GLuint normalIndex)
481 assert(normalData.size == 3);
483 switch(normalData.type)
485 case GL_BYTE:
486 glNormal3bv((const GLbyte*)((const char*)normalData.pointer + normalIndex*normalData.stride));
487 break;
489 case GL_SHORT:
490 glNormal3sv((const GLshort*)((const char*)normalData.pointer + normalIndex*normalData.stride));
491 break;
493 case GL_INT:
494 glNormal3iv((const GLint*)((const char*)normalData.pointer + normalIndex*normalData.stride));
495 break;
497 case GL_FLOAT:
498 glNormal3fv((const GLfloat*)((const char*)normalData.pointer + normalIndex*normalData.stride));
499 break;
501 case GL_DOUBLE:
502 glNormal3dv((const GLdouble*)((const char*)normalData.pointer + normalIndex*normalData.stride));
503 break;
507 } // namespace GLEAN