Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef DrawElements_INCLUDE_ONCE
00033 #define DrawElements_INCLUDE_ONCE
00034
00035 #include <vlGraphics/DrawCall.hpp>
00036 #include <vlGraphics/TriangleIterator.hpp>
00037 #include <vlGraphics/LineIterator.hpp>
00038 #include <vlGraphics/Array.hpp>
00039 #include <vlCore/Log.hpp>
00040 #include <vlCore/Say.hpp>
00041 #include <algorithm>
00042
00043 namespace vl
00044 {
00045
00046
00047
00048
00054 class DrawElementsBase: public DrawCall
00055 {
00056 VL_INSTRUMENT_ABSTRACT_CLASS(vl::DrawElementsBase, DrawCall)
00057
00058 public:
00060 virtual bool primitiveRestartEnabled() const { return mPrimitiveRestartEnabled; }
00061
00063 void setPrimitiveRestartEnabled(bool enabled) { mPrimitiveRestartEnabled = enabled; }
00064
00066 void setInstances(int instances) { mInstances = instances; }
00067
00069 int instances() const { return mInstances; }
00070
00075 void setBaseVertex(int base_vertex) { mBaseVertex = base_vertex; }
00076
00079 int baseVertex() const { return mBaseVertex; }
00080
00081 protected:
00082 int mInstances;
00083 bool mPrimitiveRestartEnabled;
00084 GLuint mBaseVertex;
00085 };
00086
00087
00088
00118 template <class arr_type>
00119 class DrawElements: public DrawElementsBase
00120 {
00121 VL_INSTRUMENT_CLASS(vl::DrawElements<arr_type>, DrawElementsBase)
00122
00123 public:
00124 typedef typename arr_type::scalar_type index_type;
00126 static const index_type primitive_restart_index = index_type(~0);
00127 virtual unsigned int primitiveRestartIndex() { return (unsigned int)primitive_restart_index; }
00128
00129 private:
00130 template<typename T>
00131 class Triangle
00132 {
00133 public:
00134 T ABC[3];
00135 bool operator<(const Triangle<index_type>& b) const
00136 {
00137 if (ABC[0] != b.ABC[0])
00138 return ABC[0] < b.ABC[0];
00139 else
00140 if (ABC[1] != b.ABC[1])
00141 return ABC[1] < b.ABC[1];
00142 else
00143 return ABC[2] < b.ABC[2];
00144 }
00145 void rotate()
00146 {
00147 if (ABC[0] > ABC[1])
00148 { T tmp = ABC[0]; ABC[0] = ABC[1]; ABC[1] = ABC[2]; ABC[2] = tmp; }
00149 if (ABC[0] > ABC[1])
00150 { T tmp = ABC[0]; ABC[0] = ABC[1]; ABC[1] = ABC[2]; ABC[2] = tmp; }
00151 }
00152 };
00153
00154 public:
00156 DrawElements(EPrimitiveType primitive = PT_TRIANGLES, int instances = 1)
00157 {
00158 VL_DEBUG_SET_OBJECT_NAME()
00159 mType = primitive;
00160 mInstances = instances;
00161 mIndexBuffer = new arr_type;
00162 mPrimitiveRestartEnabled = false;
00163 mBaseVertex = 0;
00164 mCount = -1;
00165 mOffset = 0;
00166 }
00167
00169 DrawElements& operator=(const DrawElements& other)
00170 {
00171 super::operator=(other);
00172 *indexBuffer() = *other.indexBuffer();
00173 mInstances = other.mInstances;
00174 mPrimitiveRestartEnabled = other.mPrimitiveRestartEnabled;
00175 mBaseVertex = other.mBaseVertex;
00176 mCount = other.mCount;
00177 mOffset = other.mOffset;
00178 return *this;
00179 }
00180
00182 virtual ref<DrawCall> clone() const
00183 {
00184 ref<DrawElements> de = new DrawElements;
00185 *de = *this;
00186 return de;
00187 }
00188
00190 void setCount(i32 count) { mCount = count; }
00191
00193 i32 count() const { return mCount; }
00194
00196 void setOffset(u32 offset) { mOffset = offset; }
00197
00199 u32 offset() const { return mOffset; }
00200
00202 void setIndexBuffer(arr_type* index_buffer) { mIndexBuffer = index_buffer; }
00203
00205 arr_type* indexBuffer() { return mIndexBuffer.get(); }
00206
00208 const arr_type* indexBuffer() const { return mIndexBuffer.get(); }
00209
00210 virtual void updateDirtyBufferObject(EBufferObjectUpdateMode mode)
00211 {
00212 if (indexBuffer()->isBufferObjectDirty() || (mode & BUF_ForceUpdate))
00213 indexBuffer()->updateBufferObject(mode);
00214 }
00215
00216 virtual void deleteBufferObject()
00217 {
00218 indexBuffer()->bufferObject()->deleteBufferObject();
00219 }
00220
00221 virtual void render(bool use_bo) const
00222 {
00223 VL_CHECK_OGL()
00224 VL_CHECK(!use_bo || (use_bo && Has_BufferObject))
00225
00226 #if !defined(NDEBUG) && (defined(VL_OPENGL_ES1) || defined(GL_OPENGL_ES2))
00227 bool error = true;
00228
00229 switch(primitiveType())
00230 {
00231 case PT_QUADS: Log::error("vl::DrawElements does not support PT_QUADS under OpenGL ES!\n"); break;
00232 case PT_QUAD_STRIP: Log::error("vl::DrawElements does not support PT_QUAD_STRIP under OpenGL ES!\n"); break;
00233 case PT_POLYGON: Log::error("vl::DrawElements does not support PT_POLYGON under OpenGL ES!\n"); break;
00234 case PT_LINES_ADJACENCY: Log::error("vl::DrawElements does not support PT_LINES_ADJACENCY under OpenGL ES!\n"); break;
00235 case PT_LINE_STRIP_ADJACENCY: Log::error("vl::DrawElements does not support PT_LINE_STRIP_ADJACENCY under OpenGL ES!\n"); break;
00236 case PT_TRIANGLES_ADJACENCY: Log::error("vl::DrawElements does not support PT_TRIANGLES_ADJACENCY under OpenGL ES!\n"); break;
00237 case PT_TRIANGLE_STRIP_ADJACENCY: Log::error("vl::DrawElements does not support PT_TRIANGLE_STRIP_ADJACENCY under OpenGL ES!\n"); break;
00238 case PT_PATCHES: Log::error("vl::DrawElements does not support PT_PATCHES under OpenGL ES!\n"); break;
00239 default:
00240 error = false;
00241 break;
00242 }
00243
00244 if (indexBuffer()->glType() != GL_UNSIGNED_BYTE && indexBuffer()->glType() != GL_UNSIGNED_SHORT)
00245 {
00246 Log::error("vl::DrawElements only supports GL_UNSIGNED_BYTE and GL_UNSIGNED_SHORT under OpenGL ES!\n");
00247 error = true;
00248 }
00249 VL_CHECK(!error)
00250 #endif
00251
00252 use_bo &= Has_BufferObject;
00253 if ( !use_bo && !indexBuffer()->size() )
00254 return;
00255
00256
00257 applyPatchParameters();
00258
00259
00260 if(primitiveRestartEnabled())
00261 {
00262 VL_CHECK(Has_Primitive_Restart);
00263 glEnable(GL_PRIMITIVE_RESTART); VL_CHECK_OGL();
00264 glPrimitiveRestartIndex(primitive_restart_index); VL_CHECK_OGL();
00265 }
00266
00267
00268
00269 const GLvoid* ptr = indexBuffer()->bufferObject()->ptr();
00270 if (use_bo && indexBuffer()->bufferObject()->handle())
00271 {
00272 VL_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer()->bufferObject()->handle()); VL_CHECK_OGL()
00273 ptr = 0;
00274 }
00275 else
00276 {
00277 VL_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); VL_CHECK_OGL()
00278 }
00279
00280
00281
00282 const char*ptr_end = NULL;
00283 if(mCount < 0)
00284 {
00285
00286 ptr_end = (char*)ptr + sizeof(index_type)*(use_bo ? indexBuffer()->sizeBufferObject() : indexBuffer()->size());
00287
00288
00289 ptr = (char*)ptr + mOffset;
00290 }
00291 else
00292 {
00293
00294 ptr = (char*)ptr + mOffset;
00295
00296
00297 ptr_end = (char*)ptr + sizeof(index_type)*mCount;
00298 }
00299
00300
00301 const GLsizei count = (GLsizei)((index_type*)ptr_end - (index_type*)ptr);
00302
00303 if (mBaseVertex == 0)
00304 {
00305 if ( instances() == 1 )
00306 {
00307 glDrawElements( primitiveType(), count, arr_type::gl_type, ptr ); VL_CHECK_OGL()
00308 }
00309 else
00310 {
00311 VL_CHECK(Has_Primitive_Instancing)
00312 VL_glDrawElementsInstanced( primitiveType(), count, arr_type::gl_type, ptr, instances() ); VL_CHECK_OGL()
00313 }
00314 }
00315 else
00316 {
00317 VL_CHECK(Has_Base_Vertex)
00318 if ( instances() == 1 )
00319 {
00320 VL_glDrawElementsBaseVertex( primitiveType(), count, arr_type::gl_type, ptr, mBaseVertex ); VL_CHECK_OGL()
00321 }
00322 else
00323 {
00324 VL_CHECK(Has_Primitive_Instancing)
00325 VL_glDrawElementsInstancedBaseVertex( primitiveType(), count, arr_type::gl_type, ptr, instances(), mBaseVertex ); VL_CHECK_OGL()
00326 }
00327 }
00328
00329
00330
00331 if(primitiveRestartEnabled())
00332 {
00333 glDisable(GL_PRIMITIVE_RESTART); VL_CHECK_OGL()
00334 }
00335
00336 #ifndef NDEBUG
00337 unsigned int glerr = glGetError();
00338 if (glerr != GL_NO_ERROR)
00339 {
00340 String msg( getGLErrorString(glerr) );
00341 Log::error( Say("glGetError() [%s:%n]: %s\n") << __FILE__ << __LINE__ << msg );
00342 Log::warning( "- If you are using geometry instancing in conjunction with display lists you will have to disable one of them.\n" );
00343 Log::warning( "- If you are using OpenGL ES you must not use GL_QUADS, GL_QUAD_STRIP and GL_POLYGON primitive types.\n" );
00344 VL_TRAP()
00345 }
00346 #endif
00347 }
00348
00349 TriangleIterator triangleIterator() const
00350 {
00351 ref< TriangleIteratorIndexed<arr_type> > it =
00352 new TriangleIteratorIndexed<arr_type>( mIndexBuffer.get(), primitiveType(),
00353 baseVertex(), primitiveRestartEnabled(), primitive_restart_index );
00354 it->initialize();
00355 return TriangleIterator(it.get());
00356 }
00357
00358 LineIterator lineIterator() const
00359 {
00360 ref< LineIteratorIndexed<arr_type> > it =
00361 new LineIteratorIndexed<arr_type>( mIndexBuffer.get(), primitiveType(),
00362 baseVertex(), primitiveRestartEnabled(), primitive_restart_index );
00363 it->initialize();
00364 return LineIterator(it.get());
00365 }
00366
00367 IndexIterator indexIterator() const
00368 {
00369 ref< IndexIteratorElements<arr_type> > iie = new IndexIteratorElements<arr_type>;
00370 iie->initialize( mIndexBuffer.get(), NULL, NULL, mBaseVertex, mPrimitiveRestartEnabled, primitive_restart_index );
00371 IndexIterator iit;
00372 iit.initialize( iie.get() );
00373 return iit;
00374 }
00375
00376 protected:
00377 ref< arr_type > mIndexBuffer;
00378 i32 mCount;
00379 u32 mOffset;
00380 };
00381
00382
00383
00385 class DrawElementsUInt: public DrawElements<ArrayUInt1>
00386 {
00387 VL_INSTRUMENT_CLASS(vl::DrawElementsUInt, DrawElements<ArrayUInt1>)
00388
00389 public:
00390 DrawElementsUInt(EPrimitiveType primitive = PT_TRIANGLES, int instances = 1)
00391 :DrawElements<ArrayUInt1>(primitive, instances)
00392 {
00393 VL_DEBUG_SET_OBJECT_NAME();
00394 }
00395 };
00396
00398 class DrawElementsUShort: public DrawElements<ArrayUShort1>
00399 {
00400 VL_INSTRUMENT_CLASS(vl::DrawElementsUShort, DrawElements<ArrayUShort1>)
00401
00402 public:
00403 DrawElementsUShort(EPrimitiveType primitive = PT_TRIANGLES, int instances = 1)
00404 :DrawElements<ArrayUShort1>(primitive, instances)
00405 {
00406 VL_DEBUG_SET_OBJECT_NAME();
00407 }
00408 };
00409
00411 class DrawElementsUByte: public DrawElements<ArrayUByte1>
00412 {
00413 VL_INSTRUMENT_CLASS(vl::DrawElementsUByte, DrawElements<ArrayUByte1>)
00414
00415 public:
00416 DrawElementsUByte(EPrimitiveType primitive = PT_TRIANGLES, int instances = 1)
00417 :DrawElements<ArrayUByte1>(primitive, instances)
00418 {
00419 VL_DEBUG_SET_OBJECT_NAME();
00420 }
00421 };
00422
00423 }
00424
00425 #endif