1 // BEGIN_COPYRIGHT -*- glean -*-
3 // Copyright (C) 1999,2000 Allen Akin All Rights Reserved.
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
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
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.
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.
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()
61 type
= GL_UNSIGNED_INT
;
66 void ArrayData::setData(GLint sizeIn
, GLenum typeIn
, GLsizei strideIn
, const GLvoid
* pointerIn
)
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
;
95 compileArrays
= false;
98 indicesType
= GL_UNSIGNED_INT
;
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
)
111 GeomRenderer::DrawMethod
GeomRenderer::getDrawMethod() const
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;
143 compileArrays
= compile
;
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
;
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())
206 // Okay, different sections here depending on what we're doing.
207 if (drawMethod
== GLVERTEX_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
);
220 // Otherwise it has something to do with arrays; set up the arrays.
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;
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
)
263 for (unsigned int x
=0; x
<indicesCount
; x
++)
265 glArrayElement(getIndex(x
));
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.
282 PFNGLUNLOCKARRAYSEXTPROC glUnlockArraysEXT
= 0;
283 assert(GLUtils::haveExtension("GL_EXT_compiled_vertex_array"));
284 glUnlockArraysEXT
= reinterpret_cast<PFNGLUNLOCKARRAYSEXTPROC
>
285 (GLUtils::getProcAddress("glUnlockArraysEXT"));
293 bool GeomRenderer::generateDisplayList(GLenum mode
, GLint
& listHandleOut
)
297 if (!isReadyToRender())
302 listHandleOut
= glGenLists(1);
303 glNewList(listHandleOut
, GL_COMPILE
);
304 result
= renderPrimitives(mode
);
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)
329 // Otherwise we're good to go!
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
));
340 case GL_UNSIGNED_BYTE
:
341 return ((GLubyte
*)indices
)[indicesIndex
];
344 case GL_UNSIGNED_SHORT
:
345 return ((GLushort
*)indices
)[indicesIndex
];
348 case GL_UNSIGNED_INT
:
349 return ((GLuint
*)indices
)[indicesIndex
];
357 // It never gets here, but let's quell the compiler warning...
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
)
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
));
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
));
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
));
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
));
395 void GeomRenderer::sendColor(GLuint colorIndex
)
397 assert(colorData
.size
== 3 || colorData
.size
== 4);
399 switch(colorData
.type
)
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
443 void GeomRenderer::sendTexCoord(GLuint texCoordIndex
)
445 assert(texCoordData
.size
>= 1 && texCoordData
.size
<= 4);
447 switch(texCoordData
.type
)
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
));
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
));
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
));
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
));
479 void GeomRenderer::sendNormal(GLuint normalIndex
)
481 assert(normalData
.size
== 3);
483 switch(normalData
.type
)
486 glNormal3bv((const GLbyte
*)((const char*)normalData
.pointer
+ normalIndex
*normalData
.stride
));
490 glNormal3sv((const GLshort
*)((const char*)normalData
.pointer
+ normalIndex
*normalData
.stride
));
494 glNormal3iv((const GLint
*)((const char*)normalData
.pointer
+ normalIndex
*normalData
.stride
));
498 glNormal3fv((const GLfloat
*)((const char*)normalData
.pointer
+ normalIndex
*normalData
.stride
));
502 glNormal3dv((const GLdouble
*)((const char*)normalData
.pointer
+ normalIndex
*normalData
.stride
));