Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlGraphics/Geometry.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
00029 /*                                                                                    */
00030 /**************************************************************************************/
00031 
00032 #include <vlGraphics/Geometry.hpp>
00033 #include <vlGraphics/OpenGLContext.hpp>
00034 #include <vlGraphics/DoubleVertexRemover.hpp>
00035 #include <vlGraphics/MultiDrawElements.hpp>
00036 #include <vlGraphics/DrawRangeElements.hpp>
00037 #include <cmath>
00038 #include <algorithm>
00039 
00040 using namespace vl;
00041 
00042 //-----------------------------------------------------------------------------
00043 // Geometry
00044 //-----------------------------------------------------------------------------
00045 Geometry::Geometry()
00046 {
00047   VL_DEBUG_SET_OBJECT_NAME()
00048   mVertexAttribArrays.setAutomaticDelete(false);
00049   mTexCoordArrays.setAutomaticDelete(false);
00050   mDrawCalls.setAutomaticDelete(false);
00051 }
00052 //-----------------------------------------------------------------------------
00053 Geometry::~Geometry()
00054 {
00055 }
00056 //-----------------------------------------------------------------------------
00057 void Geometry::computeBounds_Implementation()
00058 {
00059   const ArrayAbstract* coords = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00060 
00061   if (coords == NULL)
00062   {
00063     Log::debug("Geometry::computeBounds_Implementation() failed! No vertex buffer present!\n");
00064     return;
00065   }
00066 
00067   if (coords->size() == 0)
00068   {
00069     Log::debug("Geometry::computeBounds_Implementation() failed! No vertices present in the local buffer! Did you forget to call setBoundingBox() and setBoundingSphere()?\n");
00070     return;
00071   }
00072 
00073   AABB aabb;
00074   for(int i=0; i<drawCalls()->size(); ++i)
00075   {
00076     for(IndexIterator iit = drawCalls()->at(i)->indexIterator(); iit.hasNext(); iit.next())
00077     {
00078       aabb += coords->getAsVec3( iit.index() );
00079     }
00080   }
00081 
00082   real radius = 0, r = 0;
00083   vec3 center = aabb.center();
00084   for(int i=0; i<drawCalls()->size(); ++i)
00085   {
00086     for(IndexIterator iit = drawCalls()->at(i)->indexIterator(); iit.hasNext(); iit.next())
00087     {
00088       r = (coords->getAsVec3(iit.index()) - center).lengthSquared();
00089       if (r > radius)
00090         radius = r;
00091     }
00092   }
00093 
00094   setBoundingBox( aabb );
00095   setBoundingSphere( Sphere(center, radius) );
00096 }
00097 //-----------------------------------------------------------------------------
00098 ref<Geometry> Geometry::deepCopy() const
00099 {
00100   ref<Geometry> geom = new Geometry;
00101   geom->deepCopyFrom(*this);
00102   return geom;
00103 }
00104 //-----------------------------------------------------------------------------
00105 Geometry& Geometry::deepCopyFrom(const Geometry& other)
00106 {
00107   // copy the base class Renderable
00108   super::operator=(other);
00109 
00110   // copy Geometry
00111   mVertexArray         = other.mVertexArray         ? other.mVertexArray->clone().get()         : NULL;
00112   mNormalArray         = other.mNormalArray         ? other.mNormalArray->clone().get()         : NULL;
00113   mColorArray          = other.mColorArray          ? other.mColorArray->clone().get()          : NULL;
00114   mSecondaryColorArray = other.mSecondaryColorArray ? other.mSecondaryColorArray->clone().get() : NULL;
00115   mFogCoordArray       = other.mFogCoordArray       ? other.mFogCoordArray->clone().get()       : NULL;
00116 
00117   mTexCoordArrays.resize( other.mTexCoordArrays.size() );
00118   for(int i=0; i<mTexCoordArrays.size(); ++i)
00119     mTexCoordArrays[i] = new TextureArray(other.mTexCoordArrays[i]->mTextureSampler, other.mTexCoordArrays[i]->mTexCoordArray ? other.mTexCoordArrays[i]->mTexCoordArray->clone().get() : NULL);
00120 
00121   // custom arrays
00122   mVertexAttribArrays.resize( other.mVertexAttribArrays.size() );
00123   for(int i=0; i<mVertexAttribArrays.size(); ++i)
00124   {
00125     mVertexAttribArrays[i] = new VertexAttribInfo;
00126     mVertexAttribArrays[i]->setNormalize( other.mVertexAttribArrays[i]->normalize() );
00127     mVertexAttribArrays[i]->setInterpretation( other.mVertexAttribArrays[i]->interpretation() );
00128     mVertexAttribArrays[i]->setAttribLocation( other.mVertexAttribArrays[i]->attribLocation() );
00129     mVertexAttribArrays[i]->setData( other.mVertexAttribArrays[i]->data() ? other.mVertexAttribArrays[i]->data()->clone().get() : NULL );
00130   }
00131 
00132   // primitives
00133   mDrawCalls.clear();
00134   for(int i=0; i<other.mDrawCalls.size(); ++i)
00135     mDrawCalls.push_back( other.mDrawCalls[i]->clone().get() );
00136 
00137   return *this;
00138 }
00139 //-----------------------------------------------------------------------------
00140 ref<Geometry> Geometry::shallowCopy() const
00141 {
00142   ref<Geometry> geom = new Geometry;
00143   geom->shallowCopyFrom(*this);
00144   return geom;
00145 }
00146 //-----------------------------------------------------------------------------
00147 Geometry& Geometry::shallowCopyFrom(const Geometry& other)
00148 {
00149   // copy the base class Renderable
00150   super::operator=(other);
00151 
00152   // copy Geometry attributes
00153   mVertexArray = other.mVertexArray;
00154   mNormalArray = other.mNormalArray;
00155   mColorArray = other.mColorArray;
00156   mSecondaryColorArray = other.mSecondaryColorArray;
00157   mFogCoordArray = other.mFogCoordArray;
00158   mTexCoordArrays = other.mTexCoordArrays;
00159   mVertexAttribArrays = other.mVertexAttribArrays;
00160   mDrawCalls = other.mDrawCalls;
00161 
00162   return *this;
00163 }
00164 //-----------------------------------------------------------------------------
00165 void Geometry::setVertexArray(ArrayAbstract* data)
00166 {
00167   // if one of this checks fail read the OpenGL Programmers Guide or the Reference Manual 
00168   // to see what "size" and "type" are allowed for glVertexPointer
00169   VL_CHECK( !data || (data->glSize() >=2 && data->glSize()<=4) )
00170 
00171   mVertexArray = data;
00172 }
00173 //-----------------------------------------------------------------------------
00174 void Geometry::setNormalArray(ArrayAbstract* data)
00175 {
00176   // if one of this checks fail read the OpenGL Programmers Guide or the Reference Manual 
00177   // to see what "size" and "type" are allowed for glNormalPointer
00178   VL_CHECK( !data || data->glSize() == 3 )
00179   VL_CHECK( !data || (data->glType() == GL_BYTE||
00180                       data->glType() == GL_SHORT ||
00181                       data->glType() == GL_INT ||
00182                       data->glType() == GL_FLOAT ||
00183                       data->glType() == GL_DOUBLE) );
00184 
00185   mNormalArray = data;
00186 }
00187 //-----------------------------------------------------------------------------
00188 void Geometry::setColorArray(ArrayAbstract* data)
00189 {
00190   // if one of this checks fail read the OpenGL Programmers Guide or the Reference Manual 
00191   // to see what "size" and "type" are allowed for glColorPointer
00192   VL_CHECK( !data || (data->glSize() >=3 && data->glSize()<=4) )
00193   VL_CHECK( !data || (data->glType() == GL_BYTE ||
00194                       data->glType() == GL_SHORT ||
00195                       data->glType() == GL_INT ||
00196                       data->glType() == GL_UNSIGNED_BYTE ||
00197                       data->glType() == GL_UNSIGNED_SHORT ||
00198                       data->glType() == GL_UNSIGNED_INT ||
00199                       data->glType() == GL_FLOAT ||
00200                       data->glType() == GL_DOUBLE) );
00201 
00202   mColorArray = data;
00203 }
00204 //-----------------------------------------------------------------------------
00205 void Geometry::setSecondaryColorArray(ArrayAbstract* data)
00206 {
00207   // if one of this checks fail read the OpenGL Programmers Guide or the Reference Manual 
00208   // to see what "size" and "type" are allowed for glSecondaryColorPointer
00209   VL_CHECK( !data || (data->glSize() >=3 && data->glSize()<=4) )
00210   VL_CHECK( !data || (data->glType() == GL_BYTE ||
00211                       data->glType() == GL_SHORT ||
00212                       data->glType() == GL_INT ||
00213                       data->glType() == GL_UNSIGNED_BYTE ||
00214                       data->glType() == GL_UNSIGNED_SHORT ||
00215                       data->glType() == GL_UNSIGNED_INT ||
00216                       data->glType() == GL_FLOAT ||
00217                       data->glType() == GL_DOUBLE) );
00218 
00219   mSecondaryColorArray = data;
00220 }
00221 //-----------------------------------------------------------------------------
00222 void Geometry::setFogCoordArray(ArrayAbstract* data)
00223 {
00224   // if one of this checks fail read the OpenGL Programmers Guide or the Reference Manual 
00225   // to see what "size" and "type" are allowed for glFogCoordPointer
00226   VL_CHECK( !data || (data->glSize() == 1) )
00227   VL_CHECK( !data || (data->glType() == GL_FLOAT || data->glType() == GL_DOUBLE) );
00228   
00229   mFogCoordArray = data;
00230 }
00231 //-----------------------------------------------------------------------------
00232 void Geometry::setTexCoordArray(int tex_unit, ArrayAbstract* data)
00233 {
00234   // if one of this checks fail read the OpenGL Programmers Guide or the Reference Manual 
00235   // to see what "size" and "type" are allowed for glTexCoordPointer
00236   VL_CHECK( !data || (data->glSize() == 1 || data->glSize() == 2 || data->glSize() == 3 || data->glSize() == 4) )
00237   VL_CHECK( !data || (data->glType() == GL_FLOAT  || 
00238                       data->glType() == GL_DOUBLE ||
00239                       data->glType() == GL_SHORT  ||
00240                       data->glType() == GL_INT) );
00241 
00242   VL_CHECK(tex_unit<VL_MAX_TEXTURE_UNITS);
00243 
00244   for(int i=0; i<mTexCoordArrays.size(); ++i)
00245   {
00246     if (mTexCoordArrays.at(i)->mTextureSampler == tex_unit)
00247     {
00248       if (data)
00249         mTexCoordArrays.at(i)->mTexCoordArray = data;
00250       else
00251         mTexCoordArrays.erase(i,1); // removes if NULL
00252       return;
00253     }
00254   }
00255   if (data)
00256     mTexCoordArrays.push_back(new TextureArray(tex_unit,data));
00257 }
00258 //-----------------------------------------------------------------------------
00259 void Geometry::clearArrays(bool clear_draw_calls)
00260 {
00261   setBufferObjectDirty(true);
00262   mVertexArray = NULL;
00263   mNormalArray = NULL;
00264   mColorArray = NULL;
00265   mSecondaryColorArray = NULL;
00266   mFogCoordArray = NULL;
00267   mTexCoordArrays.clear();
00268   mVertexAttribArrays.clear();
00269   if (clear_draw_calls)
00270     mDrawCalls.clear();
00271 }
00272 //-----------------------------------------------------------------------------
00273 bool Geometry::flipNormals()
00274 {
00275   ArrayAbstract* normarr = normalArray() ? normalArray() : vertexAttribArray(vl::VA_Normal) ? vertexAttribArray(vl::VA_Normal)->data() : NULL;
00276 
00277   if (normarr)
00278   {
00279     ArrayFloat3* norm3f = normarr->as<ArrayFloat3>();
00280     if (norm3f)
00281     {
00282       for(u32 i=0; i<norm3f->size(); ++i)
00283       {
00284         norm3f->at(i) = -norm3f->at(i);
00285       }
00286       return true;
00287     }
00288   }
00289   return false;
00290 }
00291 //-----------------------------------------------------------------------------
00292 void Geometry::convertToVertexAttribs()
00293 {
00294   std::map<int, ref<ArrayAbstract> > attrib_map;
00295 
00296   if (vertexArray())
00297   {
00298     attrib_map[VA_Position] = vertexArray();
00299     setVertexArray(NULL);
00300   }
00301   
00302   if (normalArray())
00303   {
00304     attrib_map[VA_Normal] = normalArray();
00305     setNormalArray(NULL);
00306   }
00307   
00308   if (colorArray())
00309   {
00310     attrib_map[VA_Color] = colorArray();
00311     setColorArray(NULL);
00312   }
00313 
00314   // Texture coordinates starting from VA_TexCoord0
00315   for(int i=0; i<mTexCoordArrays.size(); i++)
00316   {
00317     attrib_map[VA_TexCoord0+i] = mTexCoordArrays[i]->mTexCoordArray;
00318   }
00319   mTexCoordArrays.clear();
00320   
00321   // Secondary color and fog are packed right after the texture coordinates
00322   int index = VA_TexCoord0 + mTexCoordArrays.size();
00323   if (secondaryColorArray())
00324   {
00325     attrib_map[index++] = secondaryColorArray();
00326     setSecondaryColorArray(NULL);
00327   }
00328 
00329   if (fogCoordArray())
00330   {
00331     attrib_map[index++] = fogCoordArray();
00332     setFogCoordArray(NULL);
00333   }
00334 
00335   // copy over the collected attributes
00336   // note: we override eventual existing vertex attributes if they are in busy positions, the other are left where they are
00337   for(std::map<int, ref<ArrayAbstract> >::iterator it=attrib_map.begin(); it != attrib_map.end(); ++it)
00338   {
00339     if (vertexAttribArray(it->first) != NULL)
00340       Log::warning( Say("Geometry::convertToVertexAttribs(): vertex attrib index #%n is already in use, it will be overwritten.\n") << it->first );
00341     setVertexAttribArray(it->first, it->second.get());
00342   }
00343 
00344 }
00345 //-----------------------------------------------------------------------------
00346 void Geometry::computeNormals(bool verbose)
00347 {
00348   // Retrieve vertex position array
00349   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00350   if (!posarr || posarr->size() == 0)
00351   {
00352     Log::warning("Geometry::computeNormals() failed: no vertices found!\n");
00353     return;
00354   }
00355 
00356   ref<ArrayFloat3> norm3f = new ArrayFloat3;
00357   norm3f->resize( posarr->size() );
00358 
00359   // Install the normal array
00360   if (vertexArray())
00361     setNormalArray( norm3f.get() );
00362   else
00363     setVertexAttribArray(VA_Normal, norm3f.get());
00364 
00365   // zero the normals
00366   for(u32 i=0; i<norm3f->size(); ++i)
00367     (*norm3f)[i] = 0;
00368 
00369   // iterate all draw calls
00370   for(int prim=0; prim<(int)drawCalls()->size(); prim++)
00371   {
00372     // iterate all triangles, if present
00373     for(TriangleIterator trit = mDrawCalls[prim]->triangleIterator(); trit.hasNext(); trit.next())
00374     {
00375       u32 a = trit.a();
00376       u32 b = trit.b();
00377       u32 c = trit.c();
00378 
00379       if (verbose)
00380       if (a == b || b == c || c == a)
00381       {
00382         Log::warning( Say("Geometry::computeNormals(): skipping degenerate triangle %n %n %n\n") << a << b << c );
00383         continue;
00384       }
00385 
00386       VL_CHECK( a < posarr->size() )
00387       VL_CHECK( b < posarr->size() )
00388       VL_CHECK( c < posarr->size() )
00389 
00390       vec3 n, v0, v1, v2;
00391 
00392       v0 = posarr->getAsVec3(a);
00393       v1 = posarr->getAsVec3(b);
00394       v2 = posarr->getAsVec3(c);
00395 
00396       if (verbose)
00397       if (v0 == v1 || v1 == v2 || v2 == v0)
00398       {
00399         Log::warning("Geometry::computeNormals(): skipping degenerate triangle (same vertex coodinate).\n");
00400         continue;
00401       }
00402 
00403       v1 -= v0;
00404       v2 -= v0;
00405 
00406       n = cross(v1, v2);
00407       n.normalize();
00408       if (verbose)
00409       if ( fabs(1.0f - n.length()) > 0.1f )
00410       {
00411         Log::warning("Geometry::computeNormals(): skipping degenerate triangle (normalization failed).\n");
00412         continue;
00413       }
00414 
00415       (*norm3f)[a] += (fvec3)n;
00416       (*norm3f)[b] += (fvec3)n;
00417       (*norm3f)[c] += (fvec3)n;
00418     }
00419   }
00420 
00421   // normalize the normals
00422   for(int i=0; i<(int)norm3f->size(); ++i)
00423     (*norm3f)[i].normalize();
00424 }
00425 //-----------------------------------------------------------------------------
00426 void Geometry::deleteBufferObject()
00427 {
00428   if (!Has_BufferObject)
00429     return;
00430 
00431   for(int i=0; i<(int)drawCalls()->size(); ++i)
00432     drawCalls()->at(i)->deleteBufferObject();
00433 
00434   if (mVertexArray)
00435     mVertexArray->bufferObject()->deleteBufferObject();
00436   
00437   if (mNormalArray)
00438     mNormalArray->bufferObject()->deleteBufferObject();
00439   
00440   if (mColorArray)
00441     mColorArray->bufferObject()->deleteBufferObject();
00442   
00443   if (mSecondaryColorArray)
00444     mSecondaryColorArray->bufferObject()->deleteBufferObject();
00445   
00446   if (mFogCoordArray)
00447     mFogCoordArray->bufferObject()->deleteBufferObject();
00448   
00449   for (int i=0; i<mTexCoordArrays.size(); ++i)
00450     mTexCoordArrays[i]->mTexCoordArray->bufferObject()->deleteBufferObject();
00451 
00452   for(int i=0; i<vertexAttribArrays()->size(); ++i)
00453     if ( vertexAttribArrays()->at(i)->data() )
00454       vertexAttribArrays()->at(i)->data()->bufferObject()->deleteBufferObject();
00455 }
00456 //-----------------------------------------------------------------------------
00457 void Geometry::updateDirtyBufferObject(EBufferObjectUpdateMode mode)
00458 {
00459   if (!Has_BufferObject)
00460     return;
00461 
00462   bool force_update = (mode & BUF_ForceUpdate) != 0;
00463 
00464   if ( mVertexArray && (mVertexArray->isBufferObjectDirty() || force_update) )
00465     mVertexArray->updateBufferObject(mode);
00466   
00467   if ( mNormalArray && (mNormalArray->isBufferObjectDirty() || force_update) )
00468     mNormalArray->updateBufferObject(mode);
00469   
00470   if ( mColorArray && (mColorArray->isBufferObjectDirty() || force_update) )
00471     mColorArray->updateBufferObject(mode);
00472   
00473   if ( mSecondaryColorArray && (mSecondaryColorArray->isBufferObjectDirty() || force_update) )
00474     mSecondaryColorArray->updateBufferObject(mode);
00475   
00476   if ( mFogCoordArray && (mFogCoordArray->isBufferObjectDirty() || force_update) )
00477     mFogCoordArray->updateBufferObject(mode);
00478   
00479   for(int i=0; i<mTexCoordArrays.size(); ++i)
00480   {
00481     if ( mTexCoordArrays[i]->mTexCoordArray->isBufferObjectDirty() || force_update )
00482       mTexCoordArrays[i]->mTexCoordArray->updateBufferObject(mode);
00483   }
00484   
00485   for(int i=0; i<vertexAttribArrays()->size(); ++i)
00486     if ( vertexAttribArrays()->at(i)->data() && (vertexAttribArrays()->at(i)->data()->isBufferObjectDirty() || force_update) )
00487       vertexAttribArrays()->at(i)->data()->updateBufferObject(mode);
00488 
00489   for(int i=0; i<drawCalls()->size(); ++i)
00490     drawCalls()->at(i)->updateDirtyBufferObject(mode);
00491 }
00492 //-----------------------------------------------------------------------------
00493 void Geometry::render_Implementation(const Actor*, const Shader*, const Camera*, OpenGLContext* gl_context) const
00494 {
00495   VL_CHECK_OGL()
00496 
00497   // bind Vertex Attrib Set
00498 
00499   bool vbo_on = Has_BufferObject && isBufferObjectEnabled() && !isDisplayListEnabled();
00500   gl_context->bindVAS(this, vbo_on, false);
00501 
00502   // actual draw
00503 
00504   for(int i=0; i<(int)drawCalls()->size(); i++)
00505     if (drawCalls()->at(i)->isEnabled())
00506       drawCalls()->at(i)->render( vbo_on );
00507 
00508   VL_CHECK_OGL()
00509 }
00510 //-----------------------------------------------------------------------------
00511 void Geometry::transform(const mat4& m, bool normalize)
00512 {
00513   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00514   if (posarr)
00515     posarr->transform(m);
00516 
00517   ArrayAbstract* normarr = normalArray() ? normalArray() : vertexAttribArray(vl::VA_Normal) ? vertexAttribArray(vl::VA_Normal)->data() : NULL;
00518   if (normarr)
00519   {
00520     mat4 nmat = m.as3x3().invert().transpose();
00521     normarr->transform(nmat);
00522     if (normalize)
00523       normarr->normalize();
00524   }
00525 }
00526 //-----------------------------------------------------------------------------
00527 void Geometry::setVertexAttribArray(const VertexAttribInfo& info)
00528 {
00529   for(int i=0; i<vertexAttribArrays()->size(); ++i)
00530   {
00531     VL_CHECK(vertexAttribArrays()->at(i))
00532     if (vertexAttribArrays()->at(i)->attribLocation() == info.attribLocation())
00533     {
00534       *vertexAttribArrays()->at(i) = info;
00535       return;
00536     }
00537   }
00538   mVertexAttribArrays.push_back( new VertexAttribInfo(info) );
00539 }
00540 //-----------------------------------------------------------------------------
00541 const VertexAttribInfo* Geometry::vertexAttribArray(unsigned int attrib_location) const
00542 {
00543   for(int i=0; i<vertexAttribArrays()->size(); ++i)
00544     if (vertexAttribArrays()->at(i)->attribLocation() == attrib_location)
00545       return vertexAttribArrays()->at(i);
00546   return NULL;
00547 }
00548 //-----------------------------------------------------------------------------
00549 VertexAttribInfo* Geometry::vertexAttribArray(unsigned int attrib_location)
00550 {
00551   for(int i=0; i<vertexAttribArrays()->size(); ++i)
00552     if (vertexAttribArrays()->at(i)->attribLocation() == attrib_location)
00553       return vertexAttribArrays()->at(i);
00554   return NULL;
00555 }
00556 //-----------------------------------------------------------------------------
00557 DrawCall* Geometry::mergeTriangleStrips()
00558 {
00559   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00560 
00561   if (!posarr)
00562     return NULL;
00563 
00564   std::vector< ref<DrawElementsBase> > de_vector;
00565   std::vector<u32> indices;
00566 
00567   // collect DrawElementsUInt
00568   for(int i=drawCalls()->size(); i--; )
00569   {
00570     ref<DrawElementsBase> deb = cast<DrawElementsBase>( drawCalls()->at(i) );
00571     if (deb && deb->primitiveType() == PT_TRIANGLE_STRIP)
00572     {
00573       // preserve order
00574       de_vector.push_back( deb );
00575       drawCalls()->eraseAt(i);
00576     }
00577   }
00578   // preseve rendering order
00579   std::reverse(de_vector.begin(), de_vector.end());
00580 
00581   // generate new strip
00582   indices.reserve( posarr->size()*2 );
00583   for(u32 i=0; i<de_vector.size(); ++i)
00584   {
00585     u32 index_count = 0;
00586     for(IndexIterator it=de_vector[i]->indexIterator(); it.hasNext(); it.next(), ++index_count)
00587       indices.push_back(it.index());
00588 
00589     if (index_count == 0)
00590       continue;
00591     
00592     // odd -> even
00593     if ( index_count % 2 )
00594       indices.push_back( indices.back() );
00595 
00596     // concatenate next strip inserting degenerate triangles
00597     if ( i != de_vector.size()-1 )
00598     {
00599       // grab the first two indices of the next draw call
00600       IndexIterator it = de_vector[i+1]->indexIterator();
00601       int A = it.index();
00602       it.next();
00603       int B = it.index();
00604 
00605       if (A == -1 || B == -1)
00606         continue;
00607 
00608       indices.push_back( indices.back() );
00609       indices.push_back(A);
00610       indices.push_back(A);
00611       indices.push_back(B);
00612     }
00613   }
00614 
00615   if (indices.size())
00616   {
00617     ref<DrawElementsUInt> draw_elems = new DrawElementsUInt(PT_TRIANGLE_STRIP);
00618     draw_elems->indexBuffer()->resize(indices.size());
00619     memcpy(draw_elems->indexBuffer()->ptr(), &indices[0], sizeof(indices[0])*indices.size());
00620     drawCalls()->push_back(draw_elems.get());
00621     return draw_elems.get();
00622   }
00623   else
00624     return NULL;
00625 }
00626 //-----------------------------------------------------------------------------
00627 void Geometry::mergeDrawCallsWithPrimitiveRestart(EPrimitiveType primitive_type)
00628 {
00629   u32 total_index_count = 0;
00630   std::vector< ref<DrawCall> > mergendo_calls;
00631   for( u32 i=drawCalls()->size(); i--; )
00632   {
00633     if (drawCalls()->at(i)->primitiveType() == primitive_type)
00634     {
00635       int index_count = drawCalls()->at(i)->countIndices();
00636       VL_CHECK(index_count >= 0);
00637       total_index_count += index_count;
00638       // insert at the head to preserve the primitive rendering order
00639       mergendo_calls.push_back( drawCalls()->at(i) );
00640       drawCalls()->eraseAt(i);
00641     }
00642   }
00643   // preseve rendering order
00644   std::reverse(mergendo_calls.begin(), mergendo_calls.end());
00645 
00646   Log::debug( Say("%n draw calls will be merged using primitive restart.\n") << mergendo_calls.size() );
00647 
00648   if (mergendo_calls.empty())
00649     return;
00650 
00651 #ifndef NDEBUG
00652   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00653 #endif
00654 
00655   ref<DrawElementsUInt> de_prim_restart = new DrawElementsUInt(primitive_type);
00656   // make space for all the indices plus the primitive restart markers.
00657   de_prim_restart->indexBuffer()->resize(total_index_count + mergendo_calls.size()-1);
00658   GLuint* index = de_prim_restart->indexBuffer()->begin();
00659   // merge draw calls using primitive restart!
00660   for( u32 i=0; i<mergendo_calls.size(); ++i )
00661   {
00662     for( IndexIterator it = mergendo_calls[i]->indexIterator(); it.hasNext(); it.next(), ++index )
00663     {
00664       *index = it.index();
00665       VL_CHECK(*index < posarr->size());
00666     }
00667     if ( i != mergendo_calls.size() -1 )
00668     {
00669       *index = DrawElementsUInt::primitive_restart_index;
00670       ++index;
00671     }
00672   }
00673   VL_CHECK( index == de_prim_restart->indexBuffer()->end() )
00674 
00675   // enable primitive restart!
00676   de_prim_restart->setPrimitiveRestartEnabled(true);
00677 
00678   drawCalls()->push_back( de_prim_restart.get() );
00679 }
00680 //-----------------------------------------------------------------------------
00681 void Geometry::mergeDrawCallsWithMultiDrawElements(EPrimitiveType primitive_type)
00682 {
00683   u32 total_index_count = 0;
00684   std::vector< ref<DrawCall> > mergendo_calls;
00685   std::vector<GLsizei> count_vector;
00686   for( u32 i=drawCalls()->size(); i--; )
00687   {
00688     if (drawCalls()->at(i)->primitiveType() == primitive_type)
00689     {
00690       int index_count = drawCalls()->at(i)->countIndices();
00691       VL_CHECK(index_count >= 0);
00692       total_index_count += index_count;
00693       count_vector.push_back( index_count );
00694       mergendo_calls.push_back( drawCalls()->at(i) );
00695       drawCalls()->eraseAt(i);
00696     }
00697   }
00698   // preseve rendering order
00699   std::reverse(mergendo_calls.begin(), mergendo_calls.end());
00700   std::reverse(count_vector.begin(), count_vector.end());
00701 
00702   Log::debug( Say("%n draw calls will be merged using MultiDrawElements.\n") << mergendo_calls.size() );
00703 
00704   if (mergendo_calls.empty())
00705     return;
00706 
00707 #ifndef NDEBUG
00708   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00709 #endif
00710 
00711   ref<MultiDrawElementsUInt> de_multi = new MultiDrawElementsUInt(primitive_type);
00712   // make space for all the indices plus the primitive restart markers.
00713   de_multi->indexBuffer()->resize(total_index_count);
00714   GLuint* index = de_multi->indexBuffer()->begin();
00715   // merge draw calls using primitive restart!
00716   for( u32 i=0; i<mergendo_calls.size(); ++i )
00717   {
00718     for( IndexIterator it = mergendo_calls[i]->indexIterator(); it.hasNext(); it.next(), ++index )
00719     {
00720       *index = it.index();
00721       VL_CHECK(*index < posarr->size());
00722     }
00723   }
00724   VL_CHECK( index == de_multi->indexBuffer()->end() )
00725 
00726   // Specify primitive boundaries. This must be done last!
00727   de_multi->setCountVector( count_vector );
00728 
00729   drawCalls()->push_back( de_multi.get() );
00730 }
00731 //-----------------------------------------------------------------------------
00732 void Geometry::mergeDrawCallsWithTriangles(EPrimitiveType primitive_type)
00733 {
00734   u32 triangle_count = 0;
00735   std::vector< ref<DrawCall> > mergendo_calls;
00736   for( u32 i=drawCalls()->size(); i--; )
00737   {
00738     const DrawCall& dc = *drawCalls()->at(i);
00739 
00740     // ignore primitives that cannot be triangulated
00741     switch(dc.primitiveType())
00742     {
00743     case PT_TRIANGLES:
00744     case PT_TRIANGLE_STRIP:
00745     case PT_TRIANGLE_FAN:
00746     case PT_QUADS:
00747     case PT_QUAD_STRIP:
00748     case PT_POLYGON:
00749       break;
00750     default:
00751       continue;
00752     }
00753 
00754     if (primitive_type == PT_UNKNOWN || dc.primitiveType() == primitive_type || dc.primitiveType() == PT_TRIANGLES)
00755     {
00756       triangle_count += dc.countTriangles();
00757       // insert at the head to preserve the primitive rendering order
00758       mergendo_calls.insert( mergendo_calls.begin(), drawCalls()->at(i) );
00759       drawCalls()->eraseAt(i);
00760     }
00761   }
00762   // preseve rendering order
00763   std::reverse(mergendo_calls.begin(), mergendo_calls.end());
00764 
00765   if (mergendo_calls.empty())
00766     return;
00767 
00768   // if there was one single PT_TRIANGLES draw calls then we are done.
00769   if ( mergendo_calls.size() == 1 && mergendo_calls[0]->primitiveType() == PT_TRIANGLES )
00770   {
00771     drawCalls()->push_back( mergendo_calls[0].get() );
00772     return;
00773   }
00774 
00775 #ifndef NDEBUG
00776   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00777 #endif
00778 
00779   ref<DrawElementsUInt> de = new DrawElementsUInt;
00780   ArrayUInt1& index_buffer = *de->indexBuffer();
00781   index_buffer.resize( triangle_count * 3 );
00782   u32 idx = 0;
00783   for(u32 i=0; i<mergendo_calls.size(); ++i)
00784   {
00785     for(TriangleIterator it = mergendo_calls[i]->triangleIterator(); it.hasNext(); it.next(), idx+=3)
00786     {
00787       VL_CHECK( idx+2 < index_buffer.size() );
00788 
00789       index_buffer[idx+0] = it.a();
00790       index_buffer[idx+1] = it.b();
00791       index_buffer[idx+2] = it.c();
00792 
00793       // some sanity checks since we are here...
00794       VL_CHECK( it.a() < (int)posarr->size() && it.b() < (int)posarr->size() && it.c() < (int)posarr->size() );
00795       VL_CHECK( it.a() >= 0 && it.b() >= 0 && it.c() >= 0 );
00796     }
00797   }
00798   VL_CHECK( idx == index_buffer.size() );
00799   drawCalls()->push_back(de.get());
00800 }
00801 //-----------------------------------------------------------------------------
00802 void Geometry::fixTriangleWinding()
00803 {
00804   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00805 
00806   ArrayAbstract* normarr = normalArray() ? normalArray() : vertexAttribArray(vl::VA_Normal) ? vertexAttribArray(vl::VA_Normal)->data() : NULL;
00807 
00808   // fixing the triangle winding requires normals
00809   if ( normarr == NULL || posarr == NULL )
00810     return;
00811 
00812   u32 triangle_count = 0;
00813   std::vector< ref<DrawCall> > mergendo_calls;
00814   for( u32 i=drawCalls()->size(); i--; )
00815   {
00816     const DrawCall& dc = *drawCalls()->at(i);
00817 
00818     // ignore primitives that cannot be triangulated
00819     switch(dc.primitiveType())
00820     {
00821     case PT_TRIANGLES:
00822     case PT_TRIANGLE_STRIP:
00823     case PT_TRIANGLE_FAN:
00824     case PT_QUADS:
00825     case PT_QUAD_STRIP:
00826     case PT_POLYGON:
00827       break;
00828     default:
00829       continue;
00830     }
00831 
00832     triangle_count += dc.countTriangles();
00833     // insert at the head to preserve the primitive rendering order
00834     mergendo_calls.insert( mergendo_calls.begin(), drawCalls()->at(i) );
00835     drawCalls()->eraseAt(i);
00836   }
00837   // preseve rendering order
00838   std::reverse(mergendo_calls.begin(), mergendo_calls.end());
00839 
00840   ref<DrawElementsUInt> de = new DrawElementsUInt;
00841   ArrayUInt1& index_buffer = *de->indexBuffer();
00842   index_buffer.resize( triangle_count * 3 );
00843   u32 idx = 0;
00844   for(u32 i=0; i<mergendo_calls.size(); ++i)
00845   {
00846     for(TriangleIterator it = mergendo_calls[i]->triangleIterator(); it.hasNext(); it.next(), idx+=3)
00847     {
00848       VL_CHECK( idx+2 < index_buffer.size() );
00849 
00850       vec3 p0 = posarr->getAsVec3(it.a());
00851       vec3 p1 = posarr->getAsVec3(it.b());
00852       vec3 p2 = posarr->getAsVec3(it.c());
00853       p1 = (p1 - p0).normalize();
00854       p2 = (p2 - p0).normalize();
00855       vec3 n1 = vl::cross(p1, p2);
00856 
00857       vec3 v0 = normarr->getAsVec3(it.a());
00858       vec3 v1 = normarr->getAsVec3(it.b());
00859       vec3 v2 = normarr->getAsVec3(it.c());
00860       vec3 n2 = (v0+v1+v2).normalize();
00861 
00862       if (dot(n1, n2) > 0)
00863       {
00864         index_buffer[idx+0] = it.a();
00865         index_buffer[idx+1] = it.b();
00866         index_buffer[idx+2] = it.c();
00867       }
00868       else
00869       {
00870         index_buffer[idx+0] = it.a();
00871         index_buffer[idx+1] = it.c();
00872         index_buffer[idx+2] = it.b();
00873       }
00874 
00875       // some sanity checks since we are here...
00876       VL_CHECK( it.a() < (int)posarr->size() && it.b() < (int)posarr->size() && it.c() < (int)posarr->size() );
00877       VL_CHECK( it.a() >= 0 && it.b() >= 0 && it.c() >= 0 );
00878     }
00879   }
00880   VL_CHECK( idx == index_buffer.size() );
00881   drawCalls()->push_back(de.get());
00882 }
00883 //-----------------------------------------------------------------------------
00884 void Geometry::regenerateVertices(const std::vector<u32>& map_new_to_old)
00885 {
00886   VertexMapper mapper;
00887 
00888   if (vertexArray())
00889     setVertexArray( mapper.regenerate( vertexArray(), map_new_to_old ).get() );
00890 
00891   if (normalArray())
00892     setNormalArray( mapper.regenerate( normalArray(), map_new_to_old ).get() );
00893 
00894   if (colorArray())
00895     setColorArray( mapper.regenerate( colorArray(), map_new_to_old ).get() );
00896 
00897   if (secondaryColorArray())
00898     setSecondaryColorArray( mapper.regenerate( secondaryColorArray(), map_new_to_old ).get() );
00899 
00900   if (fogCoordArray())
00901     setFogCoordArray( mapper.regenerate( fogCoordArray(), map_new_to_old ).get() );
00902 
00903   for(int itex=0; itex<VL_MAX_TEXTURE_UNITS; ++itex)
00904     if (texCoordArray(itex))
00905       setTexCoordArray( itex, mapper.regenerate( texCoordArray(itex), map_new_to_old ).get() );
00906 
00907   for(int i=0; i<vertexAttribArrays()->size(); ++i)
00908     vertexAttribArrays()->at(i)->setData( mapper.regenerate(vertexAttribArrays()->at(i)->data(), map_new_to_old ).get() );
00909 }
00910 //-----------------------------------------------------------------------------
00911 void Geometry::convertDrawCallToDrawArrays()
00912 {
00913   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00914 
00915   // generate mapping 
00916   std::vector<u32> map_new_to_old;
00917   map_new_to_old.reserve( posarr ? (posarr->size() * 3) : (1024 * 64) );
00918 
00919   for(int i=drawCalls()->size(); i--; )
00920   {
00921     int start = (int)map_new_to_old.size();
00922     for(IndexIterator it=drawCalls()->at(i)->indexIterator(); it.hasNext(); it.next())
00923       map_new_to_old.push_back(it.index());
00924     int count = (int)map_new_to_old.size() - start;
00925 
00926     // substitute with DrawArrays
00927     ref<DrawArrays> da = new vl::DrawArrays( drawCalls()->at(i)->primitiveType(), start, count, drawCalls()->at(i)->instances() );
00928     drawCalls()->erase(i,1);
00929     drawCalls()->push_back(da.get());
00930   }
00931 
00932   regenerateVertices(map_new_to_old);
00933 }
00934 //-----------------------------------------------------------------------------
00935 void Geometry::triangulateDrawCalls()
00936 {
00937   // converts PT_QUADS, PT_QUADS_STRIP and PT_POLYGON into PT_TRIANGLES
00938   for( int idraw=this->drawCalls()->size(); idraw--; )
00939   {
00940     DrawCall* dc = this->drawCalls()->at(idraw);
00941     switch(dc->primitiveType())
00942     {
00943     case PT_QUADS:
00944     case PT_QUAD_STRIP:
00945     case PT_POLYGON:
00946       break;
00947     default:
00948       continue;
00949     }
00950 
00951     u32 tri_count = dc->countTriangles();
00952 
00953     ref<DrawElementsUInt> triangles = new DrawElementsUInt(PT_TRIANGLES, dc->instances());
00954     triangles->indexBuffer()->resize( tri_count*3 );
00955     unsigned int* ptr = triangles->indexBuffer()->begin();
00956     for( TriangleIterator it = dc->triangleIterator(); it.hasNext(); ++it, ptr+=3 )
00957     {
00958       ptr[0] = it.a();
00959       ptr[1] = it.b();
00960       ptr[2] = it.c();
00961     }
00962     VL_CHECK( ptr == triangles->indexBuffer()->end() )
00963     // substitute the draw call
00964     (*drawCalls())[idraw] = triangles;
00965   }
00966 }
00967 //-----------------------------------------------------------------------------
00968 void Geometry::shrinkDrawCalls()
00969 {
00970 #ifndef NDEBUG
00971   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
00972   VL_CHECK(posarr);
00973 #endif
00974 
00975   for( int idraw=this->drawCalls()->size(); idraw--; )
00976   {
00977     ref<DrawCall> dc = this->drawCalls()->at(idraw);
00978 
00979     unsigned int restart_idx = dc->primitiveRestartIndex();
00980     bool restart_on = dc->primitiveRestartEnabled();
00981 
00982     // find max index
00983     int max_idx = -1;
00984     int idx_count = 0;
00985     for( vl::IndexIterator it = dc->indexIterator(); it.hasNext(); it.next(), ++idx_count )
00986     {
00987       // skip primitive restart indices
00988       if (restart_on && it.index() == (int)restart_idx)
00989         continue;
00990       else
00991         max_idx = it.index() > max_idx ? it.index() : max_idx;
00992     }
00993     
00994     // can use UByte
00995     if ( max_idx < 0xFF || (max_idx == 0xFF && !restart_on) )
00996     {
00997       if (dc->isOfType(DrawElementsBase::Type()))
00998       {
00999         ref<DrawElementsUByte> de = new DrawElementsUByte( dc->primitiveType(), dc->instances() );
01000         // prim restart
01001         de->setPrimitiveRestartEnabled( dc->primitiveRestartEnabled() );
01002         // base vertex
01003         de->setBaseVertex( dc->as<DrawElementsBase>()->baseVertex() );
01004         // regenerate indices
01005         de->indexBuffer()->resize( idx_count );
01006         u32 i=0;
01007         for( vl::IndexIterator it = dc->indexIterator(); it.hasNext(); ++it, ++i )
01008         {
01009           // skip primitive restart indices
01010           if (restart_on && it.index() == (int)restart_idx)
01011             de->indexBuffer()->at(i) = DrawElementsUByte::primitive_restart_index;
01012           else
01013           {
01014             VL_CHECK( it.index() >= 0 && it.index() < (int)posarr->size() );
01015             de->indexBuffer()->at(i) = (DrawElementsUByte::index_type)it.index();
01016           }
01017         }
01018         VL_CHECK( i == de->indexBuffer()->size() );
01019         // substitute new draw call
01020         (*drawCalls())[idraw] = de;
01021       }
01022       else
01023       if (dc->isOfType(DrawRangeElementsBase::Type()))
01024       {
01025         ref<DrawRangeElementsUByte> de = new DrawRangeElementsUByte( dc->primitiveType(), dc->instances() );
01026         // prim restart
01027         de->setPrimitiveRestartEnabled( dc->primitiveRestartEnabled() );
01028         // base vertex
01029         de->setBaseVertex( dc->as<DrawRangeElementsBase>()->baseVertex() );
01030         // range
01031         de->setRangeStart( dc->as<DrawRangeElementsBase>()->rangeStart() );
01032         de->setRangeEnd( dc->as<DrawRangeElementsBase>()->rangeEnd() );
01033         // regenerate indices
01034         de->indexBuffer()->resize( idx_count );
01035         u32 i=0;
01036         for( vl::IndexIterator it = dc->indexIterator(); it.hasNext(); ++it, ++i )
01037         {
01038           // skip primitive restart indices
01039           if (restart_on && it.index() == (int)restart_idx)
01040             de->indexBuffer()->at(i) = DrawRangeElementsUByte::primitive_restart_index;
01041           else
01042             de->indexBuffer()->at(i) = (DrawRangeElementsUByte::index_type)it.index();
01043         }
01044         VL_CHECK( i == de->indexBuffer()->size() );
01045         // substitute new draw call
01046         (*drawCalls())[idraw] = de;
01047       }
01048       else
01049       if (dc->isOfType(MultiDrawElementsBase::Type()))
01050       {
01051         ref<MultiDrawElementsUByte> de = new MultiDrawElementsUByte( dc->primitiveType() );
01052         // regenerate indices
01053         de->indexBuffer()->resize( idx_count );
01054         u32 i=0;
01055         for( vl::IndexIterator it = dc->indexIterator(); it.hasNext(); ++it, ++i )
01056         {
01057           // skip primitive restart indices
01058           if (restart_on && it.index() == (int)restart_idx)
01059             de->indexBuffer()->at(i) = DrawElementsUByte::primitive_restart_index;
01060           else
01061             de->indexBuffer()->at(i) = (MultiDrawElementsUByte::index_type)it.index();
01062         }
01063         VL_CHECK( i == de->indexBuffer()->size() );
01064         // prim restart
01065         de->setPrimitiveRestartEnabled( dc->primitiveRestartEnabled() );
01066         // base vertex
01067         de->setBaseVertices( dc->as<MultiDrawElementsBase>()->baseVertices() );
01068         // count vector
01069         de->setCountVector( dc->as<MultiDrawElementsBase>()->countVector() );
01070         // substitute new draw call
01071         (*drawCalls())[idraw] = de;
01072       }
01073     } // can use UByte
01074     else
01075     // can use UShort
01076     if ( max_idx < 0xFFFF || (max_idx == 0xFFFF && !restart_on) )
01077     {
01078       if (dc->isOfType(DrawElementsBase::Type()))
01079       {
01080         ref<DrawElementsUShort> de = new DrawElementsUShort( dc->primitiveType(), dc->instances() );
01081         // prim restart
01082         de->setPrimitiveRestartEnabled( dc->primitiveRestartEnabled() );
01083         // base vertex
01084         de->setBaseVertex( dc->as<DrawElementsBase>()->baseVertex() );
01085         // regenerate indices
01086         de->indexBuffer()->resize( idx_count );
01087         u32 i=0;
01088         for( vl::IndexIterator it = dc->indexIterator(); it.hasNext(); ++it, ++i )
01089         {
01090           // skip primitive restart indices
01091           if (restart_on && it.index() == (int)restart_idx)
01092             de->indexBuffer()->at(i) = DrawElementsUShort::primitive_restart_index;
01093           else
01094           {
01095             VL_CHECK( it.index() >= 0 && it.index() < (int)posarr->size() );
01096             de->indexBuffer()->at(i) = (DrawElementsUShort::index_type)it.index();
01097           }
01098         }
01099         VL_CHECK( i == de->indexBuffer()->size() );
01100         // substitute new draw call
01101         (*drawCalls())[idraw] = de;
01102       }
01103       else
01104       if (dc->isOfType(DrawRangeElementsBase::Type()))
01105       {
01106         ref<DrawRangeElementsUShort> de = new DrawRangeElementsUShort( dc->primitiveType(), dc->instances() );
01107         // prim restart
01108         de->setPrimitiveRestartEnabled( dc->primitiveRestartEnabled() );
01109         // base vertex
01110         de->setBaseVertex( dc->as<DrawRangeElementsBase>()->baseVertex() );
01111         // range
01112         de->setRangeStart( dc->as<DrawRangeElementsBase>()->rangeStart() );
01113         de->setRangeEnd( dc->as<DrawRangeElementsBase>()->rangeEnd() );
01114         // regenerate indices
01115         de->indexBuffer()->resize( idx_count );
01116         u32 i=0;
01117         for( vl::IndexIterator it = dc->indexIterator(); it.hasNext(); ++it, ++i )
01118         {
01119           // skip primitive restart indices
01120           if (restart_on && it.index() == (int)restart_idx)
01121             de->indexBuffer()->at(i) = DrawRangeElementsUShort::primitive_restart_index;
01122           else
01123             de->indexBuffer()->at(i) = (DrawRangeElementsUShort::index_type)it.index();
01124         }
01125         VL_CHECK( i == de->indexBuffer()->size() );
01126         // substitute new draw call
01127         (*drawCalls())[idraw] = de;
01128       }
01129       else
01130       if (dc->isOfType(MultiDrawElementsBase::Type()))
01131       {
01132         ref<MultiDrawElementsUShort> de = new MultiDrawElementsUShort( dc->primitiveType() );
01133         // regenerate indices
01134         de->indexBuffer()->resize( idx_count );
01135         u32 i=0;
01136         for( vl::IndexIterator it = dc->indexIterator(); it.hasNext(); ++it, ++i )
01137         {
01138           // skip primitive restart indices
01139           if (restart_on && it.index() == (int)restart_idx)
01140             de->indexBuffer()->at(i) = DrawElementsUShort::primitive_restart_index;
01141           else
01142             de->indexBuffer()->at(i) = (MultiDrawElementsUShort::index_type)it.index();
01143         }
01144         VL_CHECK( i == de->indexBuffer()->size() );
01145         // prim restart
01146         de->setPrimitiveRestartEnabled( dc->primitiveRestartEnabled() );
01147         // base vertex
01148         de->setBaseVertices( dc->as<MultiDrawElementsBase>()->baseVertices() );
01149         // count vector
01150         de->setCountVector( dc->as<MultiDrawElementsBase>()->countVector() );
01151         // substitute new draw call
01152         (*drawCalls())[idraw] = de;
01153       }
01154     } // can use UShort
01155 
01156   } // for()
01157 }
01158 //-----------------------------------------------------------------------------
01159 void Geometry::makeGLESFriendly()
01160 {
01161   // converts legacy vertex arrays into generic vertex attributes
01162 #if defined(VL_OPENGL_ES2)
01163   convertToVertexAttribs();
01164 #endif
01165 
01166   // converts quads and polygons into triangles
01167   triangulateDrawCalls();
01168   
01169   // use short or byte instead of int
01170   shrinkDrawCalls();
01171 
01172   // check primitive type is supported by OpenGL ES
01173   for(int i=0; i<drawCalls()->size(); ++i)
01174   {
01175     DrawCall* dc = drawCalls()->at(i);
01176     // check supported primitive types
01177     switch(dc->primitiveType())
01178     {
01179     case GL_POINTS:
01180     case GL_LINE_STRIP:
01181     case GL_LINE_LOOP:
01182     case GL_LINES:
01183     case GL_TRIANGLE_STRIP:
01184     case GL_TRIANGLE_FAN:
01185     case GL_TRIANGLES:
01186       break;
01187 
01188     case PT_QUADS:
01189     case PT_QUAD_STRIP:
01190     case PT_POLYGON:
01191     case PT_LINES_ADJACENCY:
01192     case PT_LINE_STRIP_ADJACENCY:
01193     case PT_TRIANGLES_ADJACENCY:
01194     case PT_TRIANGLE_STRIP_ADJACENCY:
01195     case PT_PATCHES:
01196       dc->setEnabled(false);
01197       Log::error("Geometry::makeGLESFriendly(): primitive type illegal under GLES, draw call disabled.\n");
01198       break;
01199 
01200     default:
01201       VL_TRAP();
01202       break;
01203     }
01204   }
01205 }
01206 //-----------------------------------------------------------------------------
01207 bool Geometry::sortVertices()
01208 {
01209   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
01210 
01211   if (!posarr)
01212   {
01213     Log::warning("Geometry::sortVertices() failed. No vertices found.\n");
01214     return false;
01215   }
01216 
01217   // supports only DrawElements* and generates DrawElementsUInt
01218 
01219   std::vector< ref<DrawElementsUInt> > de_u32_set;
01220 
01221   // collect DrawElements
01222   for(int i=0; i<drawCalls()->size(); ++i)
01223   {
01224     DrawCall* dc = drawCalls()->at(i);
01225     if (dc->primitiveRestartEnabled())
01226     {
01227       Log::error("Geometry::sortVertices() does not support DrawCalls with primitive restart enabled.\n");
01228       return false;
01229     }
01230 
01231     DrawElementsUInt*   de_u32 = dc->as<DrawElementsUInt>();
01232     DrawElementsUShort* de_u16 = dc->as<DrawElementsUShort>();
01233     DrawElementsUByte*  de_u8  = dc->as<DrawElementsUByte>();
01234     if (de_u32)
01235     {
01236       ref<DrawElementsUInt> de = new DrawElementsUInt(de_u32->primitiveType(), de_u32->instances());
01237       de_u32_set.push_back(de);
01238       de->indexBuffer()->resize( de_u32->indexBuffer()->size() );
01239       for(unsigned int j=0; j<de_u32->indexBuffer()->size(); ++j)
01240         de->indexBuffer()->at(j) = de_u32->indexBuffer()->at(j) + de_u32->baseVertex(); // bake base vertex
01241     }
01242     else
01243     if(de_u16)
01244     {
01245       ref<DrawElementsUInt> de = new DrawElementsUInt(de_u16->primitiveType(), de_u16->instances());
01246       de_u32_set.push_back(de);
01247       de->indexBuffer()->resize( de_u16->indexBuffer()->size() );
01248       for(unsigned int j=0; j<de_u16->indexBuffer()->size(); ++j)
01249         de->indexBuffer()->at(j) = de_u16->indexBuffer()->at(j) + de_u16->baseVertex(); // bake base vertex
01250     }
01251     else
01252     if(de_u8)
01253     {
01254       ref<DrawElementsUInt> de = new DrawElementsUInt(de_u8->primitiveType(), de_u8->instances());
01255       de_u32_set.push_back(de);
01256       de->indexBuffer()->resize( de_u8->indexBuffer()->size() );
01257       for(unsigned int j=0; j<de_u8->indexBuffer()->size(); ++j)
01258         de->indexBuffer()->at(j) = de_u8->indexBuffer()->at(j) + de_u8->baseVertex(); // bake base vertex
01259     }
01260     else
01261     {
01262       Log::error("Geometry::sortVertices() supports only DrawElements* draw calls.\n");
01263       return false;
01264     }
01265   }
01266 
01267   // erase all draw calls
01268   drawCalls()->clear();
01269 
01270   // reset tables
01271   std::vector<u32> map_new_to_old;
01272   map_new_to_old.resize( posarr->size() );
01273   memset(&map_new_to_old[0], 0xFF, map_new_to_old.size()*sizeof(map_new_to_old[0])); // fill with 0xFF for debugging
01274 
01275   std::vector<u32> map_old_to_new;
01276   map_old_to_new.resize( posarr->size() );
01277   memset(&map_old_to_new[0], 0xFF, map_old_to_new.size()*sizeof(map_old_to_new[0])); // fill with 0xFF for debugging
01278 
01279   std::vector<u32> used;
01280   used.resize( posarr->size() );
01281   memset(&used[0], 0, used.size()*sizeof(used[0]));
01282 
01283   // assign new vertex indices in order of appearence
01284   u32 new_idx = 0;
01285   for(u32 i=0; i<de_u32_set.size(); ++i)
01286   {
01287     ArrayUInt1* index_buffer = de_u32_set[i]->indexBuffer();
01288     for(u32 idx=0; idx<index_buffer->size(); ++idx)
01289     {
01290       if (!used[index_buffer->at(idx)])
01291       {
01292         const DrawElementsUInt::index_type& old_idx = index_buffer->at(idx);
01293         map_new_to_old[new_idx] = old_idx;
01294         map_old_to_new[old_idx] = new_idx;
01295         used[old_idx] = 1;
01296         ++new_idx;
01297       }
01298     }
01299   }
01300 
01301   // regenerate vertices
01302   regenerateVertices(map_new_to_old);
01303 
01304   // regenerate draw calls
01305   for(u32 i=0; i<de_u32_set.size(); ++i)
01306   {
01307     drawCalls()->push_back(de_u32_set[i].get());
01308     ArrayUInt1* index_buffer = de_u32_set[i]->indexBuffer();
01309     for(u32 j=0; j<index_buffer->size(); ++j)
01310     {
01311       index_buffer->at(j) = map_old_to_new[index_buffer->at(j)];
01312     }
01313   }
01314 
01315   return true;
01316 }
01317 //-----------------------------------------------------------------------------
01318 void Geometry::colorizePrimitives()
01319 {
01320   ArrayAbstract* posarr = vertexArray() ? vertexArray() : vertexAttribArray(vl::VA_Position) ? vertexAttribArray(vl::VA_Position)->data() : NULL;
01321 
01322   if (!posarr)
01323     return;
01324 
01325   ref<ArrayFloat4> col = new vl::ArrayFloat4;
01326   col->resize( posarr->size() );
01327 
01328   if (vertexArray())
01329     setColorArray( col.get() );
01330   else
01331     setVertexAttribArray( vl::VA_Color, col.get() );
01332 
01333   for(int i=0; i<drawCalls()->size(); ++i)
01334   {
01335     fvec4 c;
01336     c.r() = rand()%100 / 99.0f;
01337     c.g() = rand()%100 / 99.0f;
01338     c.b() = rand()%100 / 99.0f;
01339     c.a() = 1.0f;
01340 
01341     for(IndexIterator it=drawCalls()->at(i)->indexIterator(); it.hasNext(); it.next())
01342       col->at( it.index() ) = c;
01343   }
01344 }
01345 //-----------------------------------------------------------------------------
01346 void Geometry::computeTangentSpace(
01347   u32 vert_count, 
01348   const fvec3 *vertex, 
01349   const fvec3* normal,
01350   const fvec2 *texcoord, 
01351   const DrawCall* prim,
01352   fvec3 *tangent, 
01353   fvec3 *bitangent )
01354 {
01355   std::vector<fvec3> tan1;
01356   std::vector<fvec3> tan2;
01357   tan1.resize(vert_count);
01358   tan2.resize(vert_count);
01359   
01360   for ( TriangleIterator trit = prim->triangleIterator(); trit.hasNext(); trit.next() )
01361   {
01362     int tri[] = { trit.a(), trit.b(), trit.c() };
01363 
01364     VL_CHECK(tri[0] < (int)vert_count );
01365     VL_CHECK(tri[1] < (int)vert_count );
01366     VL_CHECK(tri[2] < (int)vert_count );
01367     
01368     const fvec3& v1 = vertex[tri[0]];
01369     const fvec3& v2 = vertex[tri[1]];
01370     const fvec3& v3 = vertex[tri[2]];
01371     
01372     const fvec2& w1 = texcoord[tri[0]];
01373     const fvec2& w2 = texcoord[tri[1]];
01374     const fvec2& w3 = texcoord[tri[2]];
01375     
01376     float x1 = v2.x() - v1.x();
01377     float x2 = v3.x() - v1.x();
01378     float y1 = v2.y() - v1.y();
01379     float y2 = v3.y() - v1.y();
01380     float z1 = v2.z() - v1.z();
01381     float z2 = v3.z() - v1.z();
01382     
01383     float s1 = w2.x() - w1.x();
01384     float s2 = w3.x() - w1.x();
01385     float t1 = w2.y() - w1.y();
01386     float t2 = w3.y() - w1.y();
01387     
01388     float r = 1.0F / (s1 * t2 - s2 * t1);
01389     fvec3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
01390     fvec3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
01391 
01392     tan1[tri[0]] += sdir;
01393     tan1[tri[1]] += sdir;
01394     tan1[tri[2]] += sdir;
01395 
01396     tan2[tri[0]] += tdir;
01397     tan2[tri[1]] += tdir;
01398     tan2[tri[2]] += tdir;
01399   }
01400 
01401   for ( u32 a = 0; a < vert_count; a++)
01402   {
01403     const fvec3& n = normal[a];
01404     const fvec3& t = tan1[a];
01405 
01406     // Gram-Schmidt orthogonalize
01407     tangent[a] = (t - n * dot(n, t)).normalize();
01408 
01409     if ( bitangent )
01410     {
01411       // Calculate handedness
01412       float w = (dot(cross(n, t), tan2[a]) < 0.0F) ? -1.0F : 1.0F;
01413       bitangent[a] = cross( n, tangent[a] ) * w;
01414     }
01415   }
01416 }
01417 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:37.
Permission is granted to use this page to write and publish articles regarding Visualization Library.