void generateTexCoordsSphere( VertexAttributeSetSharedPtr const& vas, const Sphere3f &sphere, unsigned int tu ) { Buffer::ConstIterator<Vec3f>::Type vertices = vas->getVertices(); std::vector<Vec2f> texCoords( vas->getNumberOfVertices() ); Vec2f tp; for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { Vec3f p = vertices[i] - sphere.getCenter(); if ( fabsf( p[1] ) > FLT_EPSILON ) { tp[0] = 0.5f * atan2f( p[0], -p[1] ) / (float) PI + 0.5f; } else { tp[0] = (float)( ( p[0] >= 0.0f ) ? 0.75f : 0.25f ); } float d = sqrtf( square( p[0] ) + square( p[1] ) ); if ( d > FLT_EPSILON ) { tp[1] = atan2f( p[2], d ) / (float) PI + 0.5f; } else { tp[1] = (float)( ( p[2] >= 0.0f ) ? 1.0f : 0.0f ); } texCoords[i] = tp; } vas->setTexCoords( tu, &texCoords[0], vas->getNumberOfVertices() ); }
void deIndexPrimitiveT( Primitive * p ) { Buffer::DataReadLock indexBuffer( p->getIndexSet()->getBuffer() ); VertexAttributeSetSharedPtr const& vas = p->getVertexAttributeSet(); unsigned int nov = vas->getNumberOfVertices(); unsigned int noi = p->getIndexSet()->getNumberOfIndices(); if ( ( nov != noi ) || ! checkFlat( (const T *)indexBuffer.getPtr(), noi ) || ! checkTrivial( (const T *)indexBuffer.getPtr(), noi ) ) { VertexAttributeSetSharedPtr newVASH = VertexAttributeSet::create(); for ( unsigned int i=0 ; i<VertexAttributeSet::DP_SG_VERTEX_ATTRIB_COUNT ; i++ ) { if ( vas->getSizeOfVertexData(i) ) { Buffer::DataReadLock indexBufferLock( p->getIndexSet()->getBuffer() ); const T * idxPtr = indexBufferLock.getPtr<T>(); dp::DataType type = vas->getTypeOfVertexData(i); unsigned int size = dp::checked_cast<unsigned int>(vas->getSizeOfVertexData(i) * dp::getSizeOf( type )); unsigned int stride = vas->getStrideOfVertexData(i); DP_ASSERT( size <= stride ); unsigned int numIndices = p->getIndexSet()->getNumberOfIndices(); BufferHostSharedPtr newVertexBuffer = BufferHost::create(); newVertexBuffer->setSize( numIndices * size ); { Buffer::DataReadLock oldBufferLock( vas->getVertexData( i ) ); const unsigned char * oldBuffPtr = oldBufferLock.getPtr<unsigned char>(); Buffer::DataWriteLock newBufferLock( newVertexBuffer, Buffer::MAP_WRITE ); unsigned char * newBuffPtr = newBufferLock.getPtr<unsigned char>(); for ( unsigned int idx=0 ; idx < numIndices ; idx++ ) { memcpy( newBuffPtr, oldBuffPtr + stride * idxPtr[idx], size ); newBuffPtr += size; } } newVASH->setVertexData( i, vas->getSizeOfVertexData(i), type, newVertexBuffer, 0, stride, numIndices ); // inherit enable states from source attrib // normalize-enable state only meaningful for generic aliases! newVASH->setEnabled(i, vas->isEnabled(i)); // conventional newVASH->setEnabled(i+16, vas->isEnabled(i+16)); // generic newVASH->setNormalizeEnabled(i+16, vas->isNormalizeEnabled(i+16)); // only generic } } p->setVertexAttributeSet( newVASH ); } }
void UnifyTraverser::unifyVertexAttributeSet( Primitive *p ) { DP_ASSERT( m_unifyTargets & UT_VERTEX_ATTRIBUTE_SET ); DP_ASSERT( p && p->getVertexAttributeSet() ); if( !optimizationAllowed( p->getSharedPtr<Primitive>() ) ) { return; } bool found = false; HashKey hashKey; VertexAttributeSetSharedPtr vertexAttributeSet = p->getVertexAttributeSet(); // get a share count, in case it's deleted below { hashKey = vertexAttributeSet->getHashKey(); typedef multimap<HashKey,VertexAttributeSetSharedPtr>::const_iterator I; pair<I,I> itp = m_vertexAttributeSets.equal_range( hashKey ); for ( I it=itp.first ; it!= itp.second && !found ; ++it ) { found = ( vertexAttributeSet == it->second ) || vertexAttributeSet->isEquivalent( it->second, getIgnoreNames(), false ); if ( found && ( vertexAttributeSet != it->second ) ) { p->setVertexAttributeSet( it->second ); } } #if CHECK_HASH_RESULTS bool checkFound = false; for ( I it = m_vertexAttributeSets.begin() ; it != m_vertexAttributeSets.end() && !checkFound ; ++it ) { checkFound = ( vertexAttributeSet == it->second ) || vertexAttributeSet->isEquivalent( it->second, getIgnoreNames(), false ); DP_ASSERT( !checkFound || ( vertexAttributeSet == it->second ) || ( p->getVertexAttributeSet() == it->second.getWeakPtr() ) ); } DP_ASSERT( found == checkFound ); #endif } if ( ! found ) { m_vertexAttributeSets.insert( make_pair( hashKey, vertexAttributeSet ) ); } }
void convertQuadsToTriangles( IndicesPtrType indices, unsigned int elementCount , const VertexAttributeSetSharedPtr & vasSP, std::vector<unsigned int> & newIndices , unsigned int pri = ~0 ) { // for each quad-face create two triangles Buffer::ConstIterator<Vec3f>::Type vertices = vasSP->getVertices(); newIndices.reserve( 6 * ( elementCount / 4 ) ); // might reserve more than needed, due to pri for ( unsigned int i=3 ; i<elementCount ; i+=4 ) { if ( indices[i-3] == pri ) { i -= 3; } else if ( indices[i-2] == pri ) { i -= 2; } else if ( indices[i-1] == pri ) { i -= 1; } else if ( indices[i] != pri ) { // determine the shorter diagonal if ( lengthSquared( vertices[indices[i-1]] - vertices[indices[i-3]] ) < lengthSquared( vertices[indices[i-0]] - vertices[indices[i-2]] ) ) { // cut diagonal 0-2 => 0,1,2 & 2,3,0 newIndices.push_back( indices[i-3] ); newIndices.push_back( indices[i-2] ); newIndices.push_back( indices[i-1] ); newIndices.push_back( indices[i-1] ); newIndices.push_back( indices[i-0] ); newIndices.push_back( indices[i-3] ); } else { // cut diagonal 1-3 => 1,2,3 & 3,0,1 newIndices.push_back( indices[i-2] ); newIndices.push_back( indices[i-1] ); newIndices.push_back( indices[i-0] ); newIndices.push_back( indices[i-0] ); newIndices.push_back( indices[i-3] ); newIndices.push_back( indices[i-2] ); } } } }
void generateTexCoordsPlane( VertexAttributeSetSharedPtr const& vas, const Sphere3f &sphere, unsigned int tu ) { Buffer::ConstIterator<Vec3f>::Type vertices = vas->getVertices(); // get the bounding box of vas and determine the axes u,v to use to texture along unsigned int u, v, w; getSortedAxes( vertices, vas->getNumberOfVertices(), u, v, w ); // create the texture coordinates std::vector<Vec2f> texCoords( vas->getNumberOfVertices() ); Vec2f tp; float oneOverTwoR = 0.5f / sphere.getRadius(); Vec2f tpMin( 1.0f, 1.0f ); Vec2f tpMax( 0.0f, 0.0f ); for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { Vec3f p = vertices[i] - sphere.getCenter(); tp[0] = p[u] * oneOverTwoR + 0.5f; // 0.0 <= tp[0] <= 1.0 if ( tp[0] < tpMin[0] ) { tpMin[0] = tp[0]; } else if ( tp[0] > tpMax[0] ) { tpMax[0] = tp[0]; } tp[1] = p[v] * oneOverTwoR + 0.5f; // 0.0 <= tp[1] <= 1.0 if ( tp[1] < tpMin[1] ) { tpMin[1] = tp[1]; } else if ( tp[1] > tpMax[1] ) { tpMax[1] = tp[1]; } texCoords[i] = tp; } // scale the texcoords to [0..1] DP_ASSERT( ( FLT_EPSILON < ( tpMax[0] - tpMin[0] ) ) && ( FLT_EPSILON < ( tpMax[1] - tpMin[1] ) ) ); Vec2f tpScale( 1.0f / ( tpMax[0] - tpMin[0] ), 1.0f / ( tpMax[1] - tpMin[1] ) ); for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { texCoords[i] = Vec2f( ( texCoords[i][0] - tpMin[0] ) * tpScale[0], ( texCoords[i][1] - tpMin[1] ) * tpScale[1] ); } vas->setTexCoords( tu, &texCoords[0], vas->getNumberOfVertices() ); }
void generateTexCoordsCylinder( VertexAttributeSetSharedPtr const& vas, const Sphere3f &sphere, unsigned int tu ) { Buffer::ConstIterator<Vec3f>::Type vertices = vas->getVertices(); // get the bounding box of vas and determine the axes u,v to use to texture along unsigned int u, v, w; getSortedAxes( vertices, vas->getNumberOfVertices(), u, v, w ); // create the texture coordinates std::vector<Vec2f> texCoords( vas->getNumberOfVertices() ); Vec2f tp; float oneOverTwoR = 0.5f / sphere.getRadius(); float tpuMin = 1.0f; float tpuMax = 0.0f; for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { Vec3f p = vertices[i] - sphere.getCenter(); // largest axis as the cylinder axis tp[0] = p[u] * oneOverTwoR + 0.5f; // 0.0 <= tp[1] <= 1.0 if ( tp[0] < tpuMin ) { tpuMin = tp[0]; } else if ( tpuMax < tp[0] ) { tpuMax = tp[0]; } if ( FLT_EPSILON < fabsf( p[v] ) ) { tp[1] = 0.5f * atan2f( p[w], -p[v] ) / (float) PI + 0.5f; } else { tp[1] = (float)( ( 0.0f <= p[w] ) ? 0.75f : 0.25f ); } texCoords[i] = tp; } // scale the texcoords to [0..1] DP_ASSERT( FLT_EPSILON < ( tpuMax - tpuMin ) ); float tpuScale = 1.0f / ( tpuMax - tpuMin ); for ( unsigned int i=0 ; i<vas->getNumberOfVertices() ; i++ ) { texCoords[i][0] = ( texCoords[i][0] - tpuMin ) * tpuScale; } vas->setTexCoords( tu, &texCoords[0], vas->getNumberOfVertices() ); }
void UnifyTraverser::handleVertexAttributeSet( VertexAttributeSet * p ) { pair<set<const void *>::iterator,bool> pitb = m_objects.insert( p ); if ( pitb.second ) { OptimizeTraverser::handleVertexAttributeSet( p ); // Check if optimization is allowed if ( optimizationAllowed( p->getSharedPtr<VertexAttributeSet>() ) && (m_unifyTargets & UT_VERTICES) ) { VertexAttributeSetSharedPtr vas = p->getSharedPtr<VertexAttributeSet>(); unsigned int n = p->getNumberOfVertices(); // handle VAS with more than one vertex only if ( 1 < n ) { // *************************************************************** // the algorithm currently only works for float-typed vertex data! // *************************************************************** for ( unsigned int i=0 ; i<VertexAttributeSet::DP_SG_VERTEX_ATTRIB_COUNT ; i++ ) { unsigned int type = p->getTypeOfVertexData(i); if ( type != dp::DT_UNKNOWN // no data is ok! && type != dp::DT_FLOAT_32 ) { DP_ASSERT( !"This algorithm currently only works for float-typed vertex data!" ); return; } } // *************************************************************** // *************************************************************** // count the dimension of the VertexAttributeSet unsigned int dimension = 0; for ( unsigned int i=0 ; i<VertexAttributeSet::DP_SG_VERTEX_ATTRIB_COUNT ; i++ ) { if ( p->getNumberOfVertexData( i ) ) { dimension += p->getSizeOfVertexData( i ); } } vector<float> valueDataIn( n * dimension ); vector<float*> valuesIn( n ); for ( size_t i=0, j=0 ; i<valuesIn.size() ; i++, j+=dimension ) { valuesIn[i] = &valueDataIn[j]; } // fill valuesIn with the vertex attribute data for ( unsigned int i=0, j=0 ; i<VertexAttributeSet::DP_SG_VERTEX_ATTRIB_COUNT ; i++ ) { if ( p->getNumberOfVertexData( i ) != 0 ) { unsigned int dim = p->getSizeOfVertexData( i ); Buffer::ConstIterator<float>::Type vad = p->getVertexData<float>( i ); for ( unsigned int k=0 ; k<n ; k++ ) { const float *value = &vad[k]; for ( unsigned int l=0 ; l<dim ; l++ ) { valuesIn[k][j+l] = value[l]; } } j += dim; } } VUTOctreeNode * octree = new VUTOctreeNode(); octree->init( boundingBox<3, float, Buffer::ConstIterator<Vec3f>::Type >( p->getVertices(), p->getNumberOfVertices() ) , std::max( (unsigned int)32, (unsigned int)pow( p->getNumberOfVertices(), 0.25 ) ) ); unsigned int count = dp::checked_cast<unsigned int>(valuesIn.size()); for ( unsigned int i=0 ; i<count ; i++ ) { octree->addVertex( valuesIn, i, dimension, m_epsilon ); } unsigned int pointCount = octree->getNumberOfPoints(); // if there are less points only if ( pointCount < n ) { // initialize the index mapping to undefined vector<unsigned int> indexMap( n ); for ( unsigned int i=0 ; i<n ; i++ ) { indexMap[i] = ~0; } // create the vector of vertex attribute valuesIn vector<float> valueDataOut( pointCount * dimension ); vector<float*> valuesOut( pointCount ); for ( size_t i=0, j=0 ; i<valuesOut.size() ; i++, j+=dimension ) { valuesOut[i] = &valueDataOut[j]; } // fill valuesOut and the indexMap unsigned int index = 0; octree->mapValues( valuesIn, valuesOut, dimension, indexMap, index ); delete octree; // create a new VertexAttributeSet with the condensed data VertexAttributeSetSharedPtr newVAS = VertexAttributeSet::create(); for ( unsigned int i=0, j=0 ; i<VertexAttributeSet::DP_SG_VERTEX_ATTRIB_COUNT ; i++ ) { if ( p->getNumberOfVertexData( i ) ) { unsigned int dim = p->getSizeOfVertexData( i ); vector<float> vad( dim * valuesOut.size() ); for ( size_t k=0 ; k<valuesOut.size() ; k++ ) { for ( unsigned int l=0 ; l<dim ; l++ ) { vad[dim*k+l] = valuesOut[k][j+l]; } } newVAS->setVertexData( i, dim, dp::DT_FLOAT_32, &vad[0], 0, dp::checked_cast<unsigned int>(vad.size()/dim) ); // inherit enable states from source attrib // normalize-enable state only meaningful for generic aliases! newVAS->setEnabled(i, p->isEnabled(i)); // conventional newVAS->setEnabled(i+16, p->isEnabled(i+16)); // generic newVAS->setNormalizeEnabled(i+16, p->isNormalizeEnabled(i+16)); // generic only! j += dim; } } DP_ASSERT( m_vasReplacements.find( vas ) == m_vasReplacements.end() ); m_vasReplacements[vas] = VASReplacement( newVAS, indexMap ); } else { delete octree; } } } } }
static PrimitiveSharedPtr createGeoSphereObject() { static const float X = 0.525731112119133606f; static const float Z = 0.850650808352039932f; // Setup vertices. Initial vertex pool, subdivision level zero. static const Vec3f verticesBase[12] = { Vec3f( -X, 0.0f, Z ), Vec3f( X, 0.0f, Z ), Vec3f( -X, 0.0f, -Z ), Vec3f( X, 0.0f, -Z ), Vec3f( 0.0f, Z, X ), Vec3f( 0.0f, Z, -X ), Vec3f( 0.0f, -Z, X ), Vec3f( 0.0f, -Z, -X ), Vec3f( Z, X, 0.0f ), Vec3f( -Z, X, 0.0f ), Vec3f( Z, -X, 0.0f ), Vec3f( -Z, -X, 0.0f ) }; // Setup triangles static const unsigned int triangles[20 * 3] = { 0, 1, 4, // 0 0, 4, 9, // 1 0, 9, 11, // 2 0, 6, 1, // 3 0, 11, 6, // 4 1, 6, 10, // 5 1, 10, 8, // 6 1, 8, 4, // 7 2, 3, 7, // 8 2, 5, 3, // 9 2, 9, 5, // 10 2, 11, 9, // 11 2, 7, 11, // 12 3, 5, 8, // 13 3, 8, 10, // 14 3, 10, 7, // 15 4, 5, 9, // 16 4, 8, 5, // 17 6, 7, 10, // 18 6, 11, 7 // 19 }; unsigned int src = 0; unsigned int dst = 1; vector<Vec3f> vertices; vector<unsigned int> indices[2]; vector<unsigned int> indicesPong; // Seed the initial input vectors. for ( unsigned int i = 0 ; i < 12; ++i ) { vertices.push_back( verticesBase[i] ); } for ( unsigned int i = 0 ; i < 20 * 3; ++i ) { indices[src].push_back( triangles[i] ); } // Indices are completely regenerated each time. // New vertices are appended to the input vertices. for (unsigned int subdivisions = 0; subdivisions < NUM_SUBDIVISIONS; ++subdivisions ) { doSubdivision( indices[src], indices[dst], vertices ); src ^= 1; dst ^= 1; } // Find the indices and edges building the twelve holes. // The number of vertices does NOT change during this step, which means all indices stay valid. std::set<unsigned int> holeIndices[12]; std::set<TriangleEdge> holeEdges[12]; // First generate the outer shell with all twelve holes with circular hole edges. float radius = HOLE_RADIUS_SCALE * acos( verticesBase[0] * verticesBase[1] ); for ( unsigned int i = 0; i < 12; ++i ) { doHole( verticesBase[i], radius, indices[src], vertices, indices[dst], holeIndices[i], holeEdges[i] ); // Output. src ^= 1; dst ^= 1; } // Generate the inner shell vertices and normals. unsigned int countVertices = dp::checked_cast<unsigned int>( vertices.size() ); // Important, this is the offset for all inner triangle indices. std::vector<Vec3f> normals = vertices; // The unit vectors of the outer shell are the normals. for ( unsigned int i = 0; i < countVertices; ++i ) { Vec3f v = vertices[i]; normals.push_back( -v ); vertices.push_back( v * (1.0f - THICKNESS_HALF - THICKNESS_HALF) ); } // Now add the inner shell triangles. size_t countTriangles = indices[src].size() / 3; for ( size_t i = 0; i < countTriangles; ++i ) { unsigned int a = indices[src][i * 3 ]; unsigned int b = indices[src][i * 3 + 1]; unsigned int c = indices[src][i * 3 + 2]; // Inverse the winding for the inner shell and use the vertices behind the outer shell. indices[src].push_back( a + countVertices ); indices[src].push_back( c + countVertices ); indices[src].push_back( b + countVertices ); } // Build the rims. for ( unsigned int i = 0; i < 12; ++i ) { doRim( verticesBase[i], radius, holeIndices[i], holeEdges[i], countVertices, indices[src], vertices, normals ); } // Remove the unused vertices and normals from the array here. (At subdivision level 5 these are over 7200.) // The ones trivially inside the holes are still in the two arrays, but the triangles don't index any of them. std::vector<Vec3f> verticesFinal; std::vector<Vec3f> normalsFinal; std::map<unsigned int, unsigned int> remapper; indices[dst].clear(); unsigned int k = 0; // New index. for ( size_t i = 0; i < indices[src].size(); ++i ) { unsigned int j = indices[src][i]; // Old index. std::map<unsigned int, unsigned int>::const_iterator it = remapper.find( j ); if ( it == remapper.end() ) { // remap j to k verticesFinal.push_back( vertices[j] ); // This is the kth vertex now. normalsFinal.push_back( normals[j] ); indices[dst].push_back( k ); remapper[j] = k++; } else { indices[dst].push_back( it->second ); } } src ^= 1; dst ^= 1; // Create a VertexAttributeSet with vertices and normals VertexAttributeSetSharedPtr vertexAttributeSet = VertexAttributeSet::create(); vertexAttributeSet->setVertices( &verticesFinal[0], dp::checked_cast<unsigned int>(verticesFinal.size()) ); vertexAttributeSet->setNormals( &normalsFinal[0], dp::checked_cast<unsigned int>(normalsFinal.size()) ); // Create a Primitive IndexSetSharedPtr indexSet = IndexSet::create(); indexSet->setData( &indices[src][0], dp::checked_cast<unsigned int>(indices[src].size()) ); // create pointer to return PrimitiveSharedPtr primitive = Primitive::create( PrimitiveType::TRIANGLES ); primitive->setVertexAttributeSet( vertexAttributeSet ); primitive->setIndexSet( indexSet ); return primitive; }
void copySelectedVertices( const VertexAttributeSetSharedPtr & from, const VertexAttributeSetSharedPtr & to , std::vector<std::vector<unsigned int> > &indices ) { // indexMap below is intended to hold vertex indices, which should not exceed 32-bit precision by definition! std::vector<unsigned int> indexMap( from->getNumberOfVertices(), ~0 ); std::vector<unsigned int> iFrom; iFrom.reserve(from->getNumberOfVertices()); for ( size_t i=0 ; i<indices.size() ; i++ ) { for ( size_t j=0 ; j<indices[i].size() ; j++ ) { if ( indexMap[indices[i][j]] == ~0 ) { indexMap[indices[i][j]] = dp::checked_cast<unsigned int>(iFrom.size()); iFrom.push_back(indices[i][j]); } } } for ( unsigned int slot=0 ; slot<static_cast<unsigned int>(VertexAttributeSet::AttributeID::VERTEX_ATTRIB_COUNT) ; slot++ ) { VertexAttributeSet::AttributeID id = static_cast<VertexAttributeSet::AttributeID>(slot); if ( from->getSizeOfVertexData( id ) ) { BufferSharedPtr oldData = from->getVertexBuffer(id); Buffer::DataReadLock lock( oldData ); unsigned int size = from->getSizeOfVertexData( id ); dp::DataType type = from->getTypeOfVertexData( id ); to->setVertexData( id, NULL, &iFrom[0], size, type, lock.getPtr() , from->getStrideOfVertexData( id ) , dp::checked_cast<unsigned int>(iFrom.size()) ); // inherit enable states from source id // normalize-enable state only meaningful for generic aliases! to->setEnabled(id, from->isEnabled(id)); // conventional id = static_cast<VertexAttributeSet::AttributeID>(slot+16); // generic to->setEnabled(id, from->isEnabled(id)); to->setNormalizeEnabled(id, from->isNormalizeEnabled(id)); } } for ( size_t i=0 ; i<indices.size() ; i++ ) { for ( size_t j=0 ; j<indices[i].size() ; j++ ) { indices[i][j] = indexMap[indices[i][j]]; } } }
void copy( VertexAttributeSetSharedPtr const& src, VertexAttributeSetSharedPtr const& dst ) { if ( src != dst ) { dst->setName( src->getName() ); dst->setAnnotation( src->getAnnotation() ); dst->setHints( src->getHints() ); dst->setUserData( src->getUserData() ); for ( unsigned int i=0 ; i<2*static_cast<unsigned int>(VertexAttributeSet::AttributeID::VERTEX_ATTRIB_COUNT) ; ++i ) { VertexAttributeSet::AttributeID id = static_cast<VertexAttributeSet::AttributeID>(i); if ( src->getSizeOfVertexData( id ) ) { DP_ASSERT( ( src->getOffsetOfVertexData( id ) == 0 ) && src->isContiguousVertexData( id ) ); dst->setVertexData( id, src->getSizeOfVertexData( id ), src->getTypeOfVertexData( id ) , src->getVertexBuffer( id ), src->getOffsetOfVertexData( id ) , src->getStrideOfVertexData( id ), src->getNumberOfVertexData( id ) ); dst->setEnabled( id, src->isEnabled( id ) ); if ( id >= VertexAttributeSet::AttributeID::VERTEX_ATTRIB_COUNT ) { dst->setNormalizeEnabled( id, src->isNormalizeEnabled( id ) ); } } } } }