Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://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 //-----------------------------------------------------------------------------