fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / NodeCores / Drawables / Geometry / Util / OSGGeoFunctions.cpp
blob21a68bfa3bbee3cc2cec82201eae8ac898ada2c3
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
8 * *
9 \*---------------------------------------------------------------------------*/
10 /*---------------------------------------------------------------------------*\
11 * License *
12 * *
13 * This library is free software; you can redistribute it and/or modify it *
14 * under the terms of the GNU Library General Public License as published *
15 * by the Free Software Foundation, version 2. *
16 * *
17 * This library is distributed in the hope that it will be useful, but *
18 * WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
20 * Library General Public License for more details. *
21 * *
22 * You should have received a copy of the GNU Library General Public *
23 * License along with this library; if not, write to the Free Software *
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
25 * *
26 \*---------------------------------------------------------------------------*/
27 /*---------------------------------------------------------------------------*\
28 * Changes *
29 * *
30 * *
31 * *
32 * *
33 * *
34 * *
35 \*---------------------------------------------------------------------------*/
37 //---------------------------------------------------------------------------
38 // Includes
39 //---------------------------------------------------------------------------
40 #include <cstdlib>
41 #include <cstdio>
43 #include <set>
45 #include "OSGConfig.h"
47 #include "OSGGeoFunctions.h"
48 #include "OSGGeoProperties.h"
49 #include "OSGGeoPropertyFactory.h"
50 #include "OSGTriangleIterator.h"
51 #include "OSGFaceIterator.h"
52 #include "OSGTypedGeoIntegralProperty.h"
53 #include "OSGStriperHalfEdgeGraph.h"
54 #include "OSGPrimeMaterial.h"
55 #include "OSGFieldContainerUtils.h"
57 // #include "OSGSingletonHolder.ins"
59 OSG_BEGIN_NAMESPACE
61 /*---------------------------------------------------------------------*/
62 /*! \name Merge helper struct */
63 /*! \{ */
65 /*! \ingroup GrpDrawablesGeometryUtils
66 \nohierarchy
68 struct IndexDic
70 typedef std::vector<Int32> Int32Vec;
72 public:
74 Int32 entry (Int32Vec &indexVec);
76 const Int32Vec &entry (Int32 index );
78 UInt32 entryCount(void ) const;
80 IndexDic(void) : _indexMap(), _indexVec() {}
82 private:
84 typedef std::map<Int32Vec, Int32> IndexMap;
86 IndexMap _indexMap;
88 std::vector<const Int32Vec *> _indexVec;
91 inline
92 Int32 IndexDic::entry(Int32Vec &indexVec)
94 IndexMap::iterator iI = _indexMap.find(indexVec);
96 if(iI == _indexMap.end())
98 std::pair < IndexMap::iterator, bool > mapRes =
99 _indexMap.insert(IndexMap::value_type(indexVec, UInt32(_indexVec.size())));
101 if(mapRes.second)
103 iI = mapRes.first;
105 _indexVec.push_back(&(iI->first));
107 else
109 FFATAL(("IndexDic::entry() map insert error\n"));
113 return iI->second;
116 inline
117 const IndexDic::Int32Vec &IndexDic::entry(Int32 index)
119 return *(_indexVec[index]);
122 inline
123 UInt32 IndexDic::entryCount(void) const
125 return UInt32(_indexVec.size());
128 /*! \ingroup GrpDrawablesGeometryUtils
129 \nohierarchy
130 memory comparison
132 template <class TypeT>
133 struct memless
135 bool operator ()(const TypeT &a, const TypeT &b) const
137 if(a.second && b.second)
139 if(a.second == b.second)
141 return (memcmp(a.first, b.first, a.second) < 0) ? true : false;
143 else
145 FFATAL(("a.memSize != b.memSize in memless::operator()\n"));
148 else
150 FFATAL(("memSize is NULL in memless::operator()\n"));
152 return false;
156 /*! \} */
157 /*---------------------------------------------------------------------*/
161 /*! \ingroup GrpDrawablesGeometryUtils
163 Calculate vertex normals for the given geometry.
165 It just averages all normals that use a given vertex (as indicated by its
166 index). It is smart enough to only change the normals that are used by this
167 Geometry, and tries to reuse indices if they're not shared on other
168 properties.
170 \warning This doesn't do anything for nonindexed geometries!
173 void calcVertexNormals(Geometry *geo)
175 GeoVectorPropertyUnrecPtr norms;
176 GeoIntegralPropertyUnrecPtr normsIndex;
177 GeoIntegralPropertyUnrecPtr posIndex;
179 posIndex = geo->getIndex(Geometry::PositionsIndex);
181 if(posIndex == NULL)
183 FWARNING(("calcVertexNormals: Geometry is not indexed, ignored!\n"));
184 return;
187 norms = geo->getNormals();
189 if(norms == NULL)
191 norms = GeoVec3fProperty::create();
194 norms->resize(geo->getPositions()->size());
197 normsIndex = geo->getIndex(Geometry::NormalsIndex);
199 // No indices reuse positions
200 if(normsIndex == NULL)
202 normsIndex = geo->getIndex(Geometry::PositionsIndex);
205 // Shared with something except posIndex, create new
206 // Might have side effects on the other instances
207 if(normsIndex != posIndex && geo->indexOccurrence(normsIndex) > 1)
209 normsIndex = GeoUInt32Property::create();
212 if(normsIndex != posIndex)
214 normsIndex->resize(posIndex->size());
216 normsIndex->clear();
218 for(UInt32 i = 0; i < posIndex->size(); ++i)
220 UInt32 val;
222 posIndex ->getValue(val, i);
223 normsIndex->addValue(val );
227 // problem: not all of the points of the property might be used by this
228 // geometry. If the property has more than 1 users, be careful.
229 UInt32 idx;
231 for(UInt32 i = 0; i < posIndex->size(); ++i)
233 posIndex->getValue(idx, i);
235 norms->setValue(Vec3f(0, 0, 0), idx);
238 for(TriangleIterator t = geo->beginTriangles();
239 t != geo->endTriangles ();
240 ++t)
242 Pnt3f p0 = t.getPosition(0);
243 Pnt3f p1 = t.getPosition(1);
244 Pnt3f p2 = t.getPosition(2);
246 Plane p(p0, p1, p2);
248 Int32 i0 = t.getPositionIndex(0);
249 Int32 i1 = t.getPositionIndex(1);
250 Int32 i2 = t.getPositionIndex(2);
252 Vec3f v;
254 norms->getValue(v, i0);
256 v += p.getNormal();
257 norms->setValue(v , i0);
260 norms->getValue(v, i1);
261 v += p.getNormal();
263 norms->setValue(v, i1);
266 norms->getValue(v, i2);
267 v += p.getNormal();
269 norms->setValue(v, i2 );
272 for(UInt32 i = 0; i < posIndex->size(); ++i)
274 posIndex->getValue(idx, i);
276 Vec3f n;
278 norms->getValue(n, idx);
279 n.normalize();
280 norms->setValue(n, idx);
283 geo->setNormals(norms);
284 geo->setIndex(normsIndex, Geometry::NormalsIndex);
288 /*! \ingroup GrpDrawablesGeometryUtils
290 Calculate vertex normals for the given geometry. Only vertices whose
291 triangles have an angle less than \a creaseAngle radians to each other are
292 merged.
294 \warning This doesn't do anything for nonindexed geometries!
297 void calcVertexNormals(Geometry *geo,
298 Real32 creaseAngle)
300 GeoVectorPropertyUnrecPtr norms;
301 GeoVectorPropertyUnrecPtr positions;
302 GeoIntegralPropertyUnrecPtr normsIndex;
303 GeoIntegralPropertyUnrecPtr posIndex;
305 if(creaseAngle >= Pi)
307 calcVertexNormals(geo);
308 return;
311 // Get the positions property
312 if(geo->getProperty(Geometry::PositionsIndex) == NULL)
314 FINFO(("Geo without positions in calcVertexNormals()\n"));
315 return;
317 else
319 positions = geo->getProperty(Geometry::PositionsIndex);
322 if(positions->size() < 3)
324 FINFO(("Geo with less than 3 positions in calcVertexNormals()\n"));
325 return;
328 posIndex = geo->getIndex(Geometry::PositionsIndex);
330 if(posIndex == NULL)
332 FINFO(("Geo without position index in calcVertexNormals()\n"));
333 return;
336 norms = geo->getProperty(Geometry::NormalsIndex);
338 // Get normal property, create if needed
339 if(norms == NULL)
341 norms = GeoVec3fProperty::create();
343 geo->setProperty(norms, Geometry::NormalsIndex);
346 normsIndex = geo->getIndex(Geometry::NormalsIndex);
348 // No indices reuse positions
349 if(normsIndex == NULL || geo->indexOccurrence(normsIndex) > 1)
351 normsIndex = GeoUInt32Property::create();
353 geo->setIndex(normsIndex, Geometry::NormalsIndex);
356 UInt32 nind = posIndex->size32();
358 normsIndex->resize(nind);
361 // now calc the normals
362 // if creaseAngle is 0, it's simple: every face uses its own.
363 if(creaseAngle == 0)
365 norms->resize(nind);
367 for(UInt32 i = 0; i < nind; ++i)
368 normsIndex->setValue(i, i);
370 for(TriangleIterator ti = geo->beginTriangles();
371 ti != geo->endTriangles();
372 ++ti)
374 Vec3f d1 = ti.getPosition(1) - ti.getPosition(0);
375 Vec3f d2 = ti.getPosition(2) - ti.getPosition(0);
377 d1.crossThis(d2);
378 d1.normalize();
380 norms->setValue(d1, ti.getNormalIndex(0));
381 norms->setValue(d1, ti.getNormalIndex(1));
382 norms->setValue(d1, ti.getNormalIndex(2));
385 return;
389 // opt + normal share code (written by jbehr)
390 // collect a map from points to faces using this point
391 // collect the face normals in a separate vector
392 //FLOG (("Run calcVertexNormals(%g)\n", creaseAngle));
394 std::vector < Vec3f > faceNormals;
395 std::vector < std::vector < UInt32 > > pntFaceDic;
397 TriangleIterator ti;
398 UInt32 iTri, pN = positions->size32();
400 pntFaceDic.resize(pN);
402 for( ti = geo->beginTriangles(), iTri = 0;
403 ti != geo->endTriangles();
404 ++ti, ++iTri)
406 Int32 v0 = ti.getPositionIndex(0);
407 Int32 v1 = ti.getPositionIndex(1);
408 Int32 v2 = ti.getPositionIndex(2);
410 if(v0 != v1 && v0 != v2)
412 Vec3f d1 = ti.getPosition(1) - ti.getPosition(0);
413 Vec3f d2 = ti.getPosition(2) - ti.getPosition(0);
415 d1.crossThis(d2);
417 if(d1.squareLength() >= 0)
419 d1.normalize();
421 faceNormals.push_back(d1);
423 pntFaceDic[ti.getPositionIndex(0)].push_back(iTri);
424 pntFaceDic[ti.getPositionIndex(1)].push_back(iTri);
425 pntFaceDic[ti.getPositionIndex(2)].push_back(iTri);
427 else
429 faceNormals.push_back(Vec3f(0, 0, 0));
432 else
434 faceNormals.push_back(Vec3f(0, 0, 0));
438 norms->clear();
440 Real32 cosCrease = osgCos(creaseAngle);
441 Vec3f norm;
443 std::vector < UInt32 > normset;
444 std::vector < std::map < std::vector < UInt32 > , UInt32 > > normDic;
445 std::map < std::vector < UInt32 > , UInt32 >::iterator ndI;
447 UInt32 normalIndex = 0;
449 normDic.resize(pN);
451 for(ti = geo->beginTriangles(); ti != geo->endTriangles(); ++ti)
453 UInt32 tind = ti.getIndex();
454 Vec3f faceNorm(faceNormals[tind]);
456 if(faceNorm.squareLength() != 0.0)
458 for(UInt16 i = 0; i < 3; ++i)
460 // calculate the normal: average all different normals
461 // that use a point. Simple addition or weighted addition
462 // doesn't work, as it depends on the triangulation
463 // of the object. :(
465 UInt32 p = ti.getPositionIndex(i);
466 UInt32 pf, f, fN = UInt32(pntFaceDic[p].size());
467 UInt32 n, nN;
469 normset.clear();
471 for(f = 0; f < fN; f++)
473 if(((pf = pntFaceDic[p][f]) == tind) ||
474 (faceNorm.dot(faceNormals[pf]) > cosCrease))
476 normset.push_back(pf);
480 if((nN = UInt32(normset.size())))
482 // find normal
483 //std::sort ( normset.begin(), normset.end() );
484 ndI = normDic[p].find(normset);
486 if(ndI == normDic[p].end())
488 norm = faceNormals[normset[0]];
490 for(n = 1; n < nN; ++n)
491 norm += faceNormals[normset[n]];
493 norm.normalize();
494 normalIndex = norms->size32();
495 norms->push_back(norm);
496 normDic[p][normset] = normalIndex;
498 else
500 normalIndex = ndI->second;
503 else
505 // keep normalIndex
506 FWARNING(("Empty normset for %d faces pos %d: %f/%f/%f\n",
507 fN, i, ti.getPosition(i).x(),
508 ti.getPosition(i).y(), ti.getPosition(i).z()
512 normsIndex->setValue(normalIndex, ti.getIndex(i));
515 else
517 // keep normal for degenerated triangle
519 normalIndex = norms->size32();
520 norms->push_back(norm);
522 normsIndex->setValue(normalIndex, ti.getIndex(0));
523 normsIndex->setValue(normalIndex, ti.getIndex(1));
524 normsIndex->setValue(normalIndex, ti.getIndex(2));
529 /*! \ingroup GrpDrawablesGeometryUtils
532 void calcFaceNormals(Geometry *geo)
534 FFATAL(("calcFaceNormals:: NYI!\n"));
537 /*! \ingroup GrpDrawablesGeometryUtils
540 void calcVertexTangentsProp(Geometry *geo,
541 UInt32 srcTexProp,
542 UInt32 srcNormalProp,
543 UInt32 dstPropTan,
544 UInt32 dstPropBin)
546 GeoVec4fPropertyUnrecPtr tangentP;
547 GeoVec4fPropertyUnrecPtr binormalP;
548 GeoUInt32PropertyUnrecPtr tanBinIndexP;
550 std::vector<Vec3f> tangent, binormal, normal;
552 // can't eval what combination was meant
553 if( (srcTexProp > Geometry::LastIndex) ||
554 (srcNormalProp > Geometry::LastIndex) ||
555 (dstPropTan > Geometry::LastIndex) ||
556 (dstPropBin > Geometry::LastIndex) ||
557 (dstPropTan == dstPropBin ) ||
559 (dstPropTan == srcTexProp ) ||
560 (dstPropTan == srcNormalProp ) ||
562 (dstPropBin == srcTexProp ) ||
563 (dstPropBin == srcNormalProp ) ||
565 (srcTexProp == srcNormalProp ) )
567 FFATAL(("Index set %d %d %d %d not supported in "
568 "calcVertexTangents()\n",
569 srcTexProp,
570 srcNormalProp,
571 dstPropTan,
572 dstPropBin));
573 return;
576 GeoIntegralProperty *posIdx = geo->getIndex(Geometry::PositionsIndex);
578 // HACK but without indices it crashes
579 if(posIdx == NULL || posIdx->size() == 0)
581 FFATAL(("Geo without pos indices in calcVertexTangents()\n"));
582 return;
585 GeoVectorProperty *positions = geo->getPositions();
587 // Get the positions property
588 if(positions == NULL)
590 FFATAL(("Geo without positions in calcVertexTangents()\n"));
591 return;
594 GeoVectorProperty *srcTexCoords = geo->getProperty(srcTexProp);
596 // Get the positions property
597 if(srcTexCoords == NULL)
599 FFATAL(("Geo without srcTexCoords in calcVertexTangents()\n"));
600 return;
603 GeoVectorProperty *srcNormals = geo->getProperty(srcNormalProp);
605 // Get the positions property
606 if(srcNormals == NULL)
608 FFATAL(("Geo without srcNormals in calcVertexTangents()\n"));
609 return;
612 UInt32 posIdxCount = posIdx->size32();
614 tangentP = GeoVec4fProperty::create();
615 binormalP = GeoVec4fProperty::create();
617 tanBinIndexP = GeoUInt32Property::create();
618 tanBinIndexP->resize(posIdxCount);
620 geo->setProperty(tangentP, dstPropTan);
621 geo->setIndex (tanBinIndexP, dstPropTan);
623 geo->setProperty(binormalP, dstPropBin);
624 geo->setIndex (tanBinIndexP, dstPropBin);
626 TriangleIterator tI;
627 IndexDic indexDic;
628 Int32 k, v[3];
629 Vec4f vect(0, 0, 0, 0);
631 UInt32 propSize = 0;
632 std::vector<Int32> indexVec;
634 indexVec.resize(3);
636 // Size of properties is number of unique index tuples, which requires
637 // looking at all of them - we take a best effort guess here and resize
638 // in the loop below
639 tangent .resize(posIdxCount, Vec3f::Null);
640 binormal.resize(posIdxCount, Vec3f::Null);
641 normal .resize(posIdxCount, Vec3f::Null);
643 Int32 iTri = 0;
645 for( tI = geo->beginTriangles(), iTri = 0;
646 tI != geo->endTriangles();
647 ++tI, ++iTri)
649 for(k = 0; k < 3; ++k)
651 indexVec[0] = tI.getPropertyIndex(Geometry::PositionsIndex, k);
652 indexVec[1] = tI.getPropertyIndex(srcNormalProp, k);
653 indexVec[2] = tI.getPropertyIndex(srcTexProp, k);
655 v[k] = indexDic.entry(indexVec);
657 if(v[k] >= Int32(propSize))
658 propSize = v[k] + 1;
661 // resize properties if inital guess was too small
662 if(propSize >= tangent.size())
664 tangent .resize(1.5f * tangent .size() + 1, Vec3f::Null);
665 binormal.resize(1.5f * binormal.size() + 1, Vec3f::Null);
666 normal .resize(1.5f * normal .size() + 1, Vec3f::Null);
669 // second, calculate tangent and binormal for every tri
670 Vec2f t0, t1, t2, tex1, tex2;
671 Vec3f edge1, edge2, sdir, tdir;
673 t0 = tI.getTexCoords(srcTexProp, 0);
674 t1 = tI.getTexCoords(srcTexProp, 1);
675 t2 = tI.getTexCoords(srcTexProp, 2);
677 edge1 = tI.getPosition(1) - tI.getPosition(0),
678 edge2 = tI.getPosition(2) - tI.getPosition(0);
680 tex1 = t1 - t0;
681 tex2 = t2 - t0;
683 Real32 invDet = (tex1[0]*tex2[1] - tex2[0]*tex1[1]);
685 if(invDet != 0.0f)
687 invDet = 1.0f / invDet;
689 else
691 invDet = 0.0f;
694 sdir = invDet * (tex2[1]*edge1 - tex1[1]*edge2); // tangent
695 tdir = invDet * (tex1[0]*edge2 - tex2[0]*edge1); // binormal
697 for(k = 0; k < 3; ++k)
699 tangent [v[k]] += sdir;
700 binormal[v[k]] += tdir;
701 normal [v[k]] = tI.getNormal(srcNormalProp, k);
703 tanBinIndexP->setValue(v[k], tI.getIndex(k));
707 // adjust size - resizing above may have been to big
708 if(tangent.size() > propSize)
710 tangent .resize(propSize);
711 binormal.resize(propSize);
712 normal .resize(propSize);
715 // orthogonalize vectors (Gram-Schmidt) and calc handedness
716 Vec3f T, B, N;
718 Real32 sign = 0;
720 tangentP ->clear();
721 binormalP->clear();
723 for(UInt32 i = 0; i < tangent.size(); i++)
725 T = tangent [i];
726 B = binormal[i];
727 N = normal [i]; // must be normalized: n*n = 1
729 sign = ((N.cross(T)).dot(B) < 0) ? -1 : 1;
731 T = T - N.dot(T) * N;
733 T.normalize();
735 B = B - N.dot(B) * N - T.dot(B) * T;
737 B.normalize();
739 vect.setValues(T[0], T[1], T[2], sign);
741 tangentP->editField().push_back(vect);
743 vect.setValues(B[0], B[1], B[2], sign);
745 binormalP->editField().push_back(vect);
749 /*! \ingroup GrpDrawablesGeometryUtils
752 void calcVertexTangents(Geometry *geo,
753 UInt32 srcTexIndex,
754 UInt32 dstPropTan,
755 UInt32 dstPropBin)
757 calcVertexTangentsProp(geo,
758 srcTexIndex + Geometry::TexCoordsIndex,
759 Geometry::NormalsIndex,
760 dstPropTan,
761 dstPropBin);
764 /*! \ingroup GrpDrawablesGeometryUtils
767 void calcVertexTexCoordsProp2D(Geometry *geo,
768 UInt32 propIndex)
770 struct Key
772 Real32 value;
773 Int32 pos;
774 } key[3], rem;
776 Int32 S = -1, T = -1, n = 3, i, j;
777 Real32 sDenom, tDenom, sMin, tMin;
779 GeoIntegralPropertyUnrecPtr ip = geo->getIndices ();
780 GeoVectorPropertyUnrecPtr posP = geo->getPositions();
781 GeoVectorPropertyUnrecPtr texP;
783 if(posP == NULL || !posP->size() || ip == NULL || !ip->size())
785 FFATAL(("Geo without indices/ positions in calcVertexTexCoords()\n"));
786 return;
789 if(propIndex > Geometry::LastIndex)
791 FFATAL(("invalid propIndex %d in calcVertexTexCoords()\n",
792 propIndex));
793 return;
796 MFParentFieldContainerPtr::const_iterator pnI;
798 for( pnI = geo->getMFParents()->begin();
799 pnI != geo->getMFParents()->end ();
800 ++pnI)
802 Node *node = dynamic_cast<Node *>(*pnI);
804 if(node != NULL)
806 BoxVolume &bVol = node->editVolume(true);
808 Pnt3f min, max;
810 bVol.getBounds(min, max);
812 Vec3f dia(max - min);
814 for(i = 0; i < 3; i++)
816 key[i].value = dia[i];
817 key[i].pos = i;
820 for(i = 1; i < n; i++)
822 for(j = n-1; j >= i; j--)
824 if (key[j-1].value > key[j].value)
826 rem = key[j];
827 key[j] = key[j-1];
828 key[j-1] = rem;
833 S = key[2].pos;
834 T = key[1].pos;
836 sDenom = dia[S];
837 tDenom = dia[T];
839 sMin = min[S];
840 tMin = min[T];
842 break;
846 if(S < 0 || T < 0)
848 FFATAL(("Geo without parents in calcVertexTexCoords()\n"));
849 return;
852 texP = GeoPnt2fProperty::create();
854 geo->setProperty(texP, propIndex);
855 geo->setIndex (ip, propIndex);
857 Pnt3f point;
858 Vec2f texCoord;
860 Int32 len = posP->size32();
862 texP->resize(len);
864 for(i = 0; i < len; i++)
866 posP->getValue(point, i);
868 texCoord[0] = (point[S] - sMin) / sDenom;
869 texCoord[1] = (point[T] - tMin) / tDenom;
871 texP->setValue(texCoord, i);
875 void calcVertexTexCoords(Geometry *geo,
876 UInt32 texIndex)
878 calcVertexTexCoordsProp2D(geo, texIndex + Geometry::TexCoordsIndex);
881 /*! \ingroup GrpDrawablesGeometryUtils
883 setIndexFromVRMLData creates an OSG::Geometry's interleaved index data
884 from VRML-style separate indices, see \ref PageSystemGeoFunctionsMakeGeo
885 for a description.
887 \a coordIndex, \a normalIndex, \a colorIndex and \a texCoordIndex are
888 VRML97-style indices. \a ccw sets whether poylgons are defined
889 counter-clockwise or clockwise, \a normalPerVertex and \a colorPerVertex
890 specify bindings, and \a faceSet defines whether a VRML IndexedFaceSet or
891 an IndexedLineSet is being generated. See the VRML97 specification at
892 http://www.vrml.org/XXX for details.
894 Note: the \a convex and \a createNormals parameters are ignored right now!
897 Int32 setIndexFromVRMLData( Geometry *geoPtr,
898 std::vector<Int32> &coordIndex,
899 std::vector<Int32> &normalIndex,
900 std::vector<Int32> &colorIndex,
901 std::vector<Int32> &texCoordIndex,
902 bool convex,
903 bool ccw,
904 bool normalPerVertex,
905 bool colorPerVertex,
906 bool createNormal,
907 bool faceSet )
909 /** define the bag type */
910 typedef std::vector<Int32> *IndexBagP;
912 /** defines the Index Types */
913 enum IndexType
915 UNKNOWN_IT = 0,
916 EMPTY_IT,
917 VERTEX_COORD_IT,
918 VERTEX_IT,
919 VERTEX_DUP_IT,
920 VERTEX_CREATE_IT,
921 PRIMITIVE_IT,
922 PRIMITIVE_INDEX_IT,
923 PRIMITIVE_CREATE_IT
926 /** holds the Index types as str, mainly for log/debug outputs */
927 #ifdef OSG_DEBUG
928 static const char *indexTypeStr[] =
930 "UNKNOWN_IT",
931 "EMPTY_IT",
932 "VERTEX_COORD_IT",
933 "VERTEX_IT",
934 "VERTEX_DUP_IT",
935 "VERTEX_CREATE_IT",
936 "PRIMTIVE_IT",
937 "PRIMITIVE_INDEX_IT",
938 "PRIMITIVE_CREATE_IT"
940 #endif
942 GeoVectorPropertyUnrecPtr posPtr;
943 GeoVectorPropertyUnrecPtr normalPtr;
944 GeoVectorPropertyUnrecPtr colorPtr;
945 GeoVectorPropertyUnrecPtr texCoordsPtr;
946 GeoIntegralPropertyUnrecPtr lensPtr;
947 GeoIntegralPropertyUnrecPtr geoTypePtr;
949 GeoIntegralPropertyUnrecPtr posIndexPtr = NULL;
951 Int32 index, pi, typei, primitiveN = 0, vN = 0; // i
952 Int32 pType = 0, localPType;
953 Int32 maxPType = (faceSet ? 5 : 3);
954 Int32 minPType = (faceSet ? 3 : 2);
955 Int32 beginIndex, endIndex, step, len, sysPType = 0;
956 Int32 piN = 0, ciN = 0, niN = 0, tiN = 0;
957 Int32 pN = 0, nN = 0, cN = 0, tN = 0;
958 IndexType indexType[4];
959 IndexType &coordIT = indexType[0];
960 IndexType &normalIT = indexType[1];
961 IndexType &colorIT = indexType[2];
962 IndexType &textureIT = indexType[3];
963 Int32 primitiveTypeCount[6];
964 UInt32 triCount = 0;
965 // Int16 indexMap[4], indexMapID[4];
966 // UInt32 uiNumTextures = 0;
968 IndexBagP indexBag[4] =
970 &coordIndex,
971 &normalIndex,
972 &colorIndex,
973 &texCoordIndex
976 GeoIntegralPropertyUnrecPtr indexOutBag[4] =
978 NULL,
979 NULL,
980 NULL,
981 NULL
984 UInt16 indexOutBagID[4] =
986 Geometry::PositionsIndex,
987 Geometry::NormalsIndex,
988 Geometry::ColorsIndex,
989 Geometry::TexCoordsIndex
992 //----------------------------------------------------------------------
993 // init
994 coordIT = VERTEX_IT;
995 // indexMap[0] = Geometry::MapPosition;
997 //----------------------------------------------------------------------
998 // get the property pointer and element count
999 posPtr = geoPtr->getPositions();
1000 pN = ((posPtr == NULL) ? 0 : posPtr->size32());
1002 normalPtr = geoPtr->getNormals();
1003 nN = ((normalPtr == NULL) ? 0 : normalPtr->size32());
1005 colorPtr = geoPtr->getColors();
1006 cN = ((colorPtr == NULL) ? 0 : colorPtr->size32());
1008 texCoordsPtr = geoPtr->getTexCoords();
1009 tN = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1011 texCoordsPtr = geoPtr->getTexCoords1();
1013 texCoordsPtr = geoPtr->getTexCoords2();
1015 texCoordsPtr = geoPtr->getTexCoords3();
1017 FDEBUG(("vertex attrib count P/N/C/T: %d/%d/%d/%d\n", pN, nN, cN, tN));
1019 //----------------------------------------------------------------------
1020 // check the vertex index and count the primitives
1021 primitiveN = index = 0;
1023 for(pType = 0; pType < 6; pType++)
1024 primitiveTypeCount[pType] = 0;
1026 if(!pN)
1028 FWARNING(("No points in OSG::setIndexFromVRMLData()\n"));
1029 return 0;
1031 else
1033 piN = UInt32(coordIndex.size());
1035 if(piN)
1037 for(Int32 i = 0; i <= piN; i++)
1039 index = (i == piN) ? -1 : coordIndex[i];
1041 if((index < 0) && vN)
1043 primitiveTypeCount[(vN > maxPType) ? maxPType : vN]++;
1044 primitiveN++;
1045 vN = 0;
1047 else
1049 if(index >= pN && i != piN)
1051 FWARNING(("Point index (%d/%d) out of range\n",
1052 index, pN));
1054 coordIndex[i] = 0;
1057 vN++;
1061 else
1063 FWARNING(("No coordIndex in OSG::setIndexFromVRMLData()\n"));
1064 return 0;
1068 //----------------------------------------------------------------------
1069 // check the normal index
1071 normalIT = UNKNOWN_IT;
1073 niN = UInt32(normalIndex.size());
1075 if(nN)
1076 { // have normal elements
1077 if(normalPerVertex)
1079 // normal per vertex
1080 if(niN >= piN)
1082 // valid normal index number
1083 for(Int32 i = 0; i < piN; i++)
1084 { // check if normal index equals the coord index
1085 if(normalIndex[i] != coordIndex[i])
1087 normalIT = VERTEX_IT;
1088 break;
1092 if(normalIT == UNKNOWN_IT)
1094 // if equal than delete unneeded normal index
1095 normalIT = VERTEX_DUP_IT;
1098 else
1100 // no or not enough normal index
1101 normalIT = VERTEX_COORD_IT;
1102 if(niN)
1104 FWARNING(("Not enough normal index (%" PRISize ",%d)\n",
1105 normalIndex.size(), piN));
1106 normalIndex.clear();
1110 else
1112 // normal per primitive
1113 if(niN >= primitiveN)
1115 // use one normal index per primitive
1116 normalIT = PRIMITIVE_INDEX_IT;
1118 else
1120 if(nN >= primitiveN)
1122 // use one normal per primitive
1123 normalIT = PRIMITIVE_IT;
1125 else
1127 FINFO(("not enough normal index (%d,%d)\n",
1128 nN, primitiveN));
1133 else
1135 /* not yet !!!
1136 if (createNormal)
1137 if (normalPerVertex)
1138 normalIT = VERTEX_CREATE_IT;
1139 else
1140 normalIT = PRIMITIVE_CREATE_IT;
1141 else
1143 normalIT = EMPTY_IT;
1146 //----------------------------------------------------------------------
1147 // check the color index
1149 colorIT = UNKNOWN_IT;
1151 ciN = UInt32(colorIndex.size());
1153 if(cN)
1154 { // have color elements
1155 if(colorPerVertex)
1157 // color per vertex
1158 if(ciN >= piN)
1160 // valid color index number
1161 for(Int32 i = 0; i < piN; i++)
1162 { // check if color index equals the coord index
1163 if(colorIndex[i] != coordIndex[i])
1165 colorIT = VERTEX_IT;
1166 break;
1170 if(colorIT == UNKNOWN_IT)
1172 // if equal than delete unneeded color index
1173 colorIT = VERTEX_DUP_IT;
1176 else
1178 // no or not enough color index
1179 colorIT = VERTEX_COORD_IT;
1180 if(ciN)
1182 FWARNING(("Not enough color index (%" PRISize ",%d)\n",
1183 colorIndex.size(), piN));
1184 colorIndex.clear();
1188 else
1190 // color per primitive
1191 if(ciN >= primitiveN)
1193 // use one color index per primitive
1194 colorIT = PRIMITIVE_INDEX_IT;
1196 else
1198 if(cN >= primitiveN)
1200 // use one color per primitive
1201 colorIT = PRIMITIVE_IT;
1203 else
1205 FINFO(("not enough color index (%d,%d)\n",
1206 cN, primitiveN));
1211 else
1213 colorIT = EMPTY_IT;
1216 //----------------------------------------------------------------------
1217 // check the texture index
1219 textureIT = UNKNOWN_IT;
1220 tiN = UInt32(texCoordIndex.size());
1221 if(tN)
1222 { // have texture elemnts
1223 if(tiN >= piN)
1225 // valid texture index number
1226 for(Int32 i = 0; i < piN; i++)
1227 { // check if texture index equals the coord index
1228 if(texCoordIndex[i] != coordIndex[i])
1230 textureIT = VERTEX_IT;
1231 break;
1235 if(textureIT == UNKNOWN_IT)
1237 // if equal than delete unneeded texture index
1238 textureIT = VERTEX_DUP_IT;
1241 else
1243 // no or not enough texture index
1244 textureIT = VERTEX_COORD_IT;
1245 if(ciN)
1247 FWARNING(("Not enough texCoord index (%" PRISize ",%d)\n",
1248 texCoordIndex.size(), piN));
1249 texCoordIndex.clear();
1253 else
1255 textureIT = EMPTY_IT;
1258 if(faceSet)
1260 FDEBUG(("primitiveN: %d, 0/%d 1/%d 2/%d 3/%d 4/%d poly/%d\n",
1261 primitiveN, primitiveTypeCount[0],
1262 primitiveTypeCount[1], primitiveTypeCount[2],
1263 primitiveTypeCount[3], primitiveTypeCount[4],
1264 primitiveTypeCount[5]));
1266 else
1268 FDEBUG(("primitiveN: %d, 0/%d 1/%d 2/%d 3/%d\n", primitiveN,
1269 primitiveTypeCount[0], primitiveTypeCount[1],
1270 primitiveTypeCount[2], primitiveTypeCount[3]));
1273 FDEBUG(("IndexType: coord: %s, color: %s, normal: %s, texture: %s \n",
1274 indexTypeStr[coordIT], indexTypeStr[colorIT], indexTypeStr[
1275 normalIT], indexTypeStr[textureIT]));
1277 //----------------------------------------------------------------------
1278 // check/create the indexPtr/lengthsPtr/geoTypePtr
1279 posIndexPtr = geoPtr->getIndex(Geometry::PositionsIndex);
1281 if(posIndexPtr == NULL)
1283 posIndexPtr = GeoUInt32Property::create();
1285 else
1287 posIndexPtr->clear();
1290 for(Int32 i = 1; i < 4; ++i)
1292 indexOutBag[i] = geoPtr->getIndex(indexOutBagID[i]);
1294 if(indexOutBag[i] != NULL)
1296 indexOutBag[i]->clear();
1300 lensPtr = geoPtr->getLengths();
1302 if(lensPtr == NULL)
1304 lensPtr = GeoUInt32Property::create();
1306 else
1308 lensPtr->clear();
1311 geoTypePtr = geoPtr->getTypes();
1313 if(geoTypePtr == NULL)
1315 geoTypePtr = GeoUInt8Property::create();
1317 else
1319 geoTypePtr->clear();
1322 //----------------------------------------------------------------------
1323 // set lens/geoType/index/mapping the index mapping
1325 geoPtr->setLengths(lensPtr );
1326 geoPtr->setTypes (geoTypePtr);
1328 geoPtr->setIndex(posIndexPtr, Geometry::PositionsIndex);
1330 //----------------------------------------------------------------------
1331 // create index face/line data
1333 for(pType = minPType; pType <= maxPType; pType++)
1335 // check for the pType count
1336 if(primitiveTypeCount[pType])
1338 // calc len/sysPType
1339 if(faceSet)
1341 if(pType < 5)
1343 len = primitiveTypeCount[pType] * pType;
1345 sysPType = (pType == 3) ? GL_TRIANGLES : GL_QUADS;
1347 else
1349 sysPType = 0;
1352 else
1354 if(pType == 2)
1356 len = primitiveTypeCount[pType] * pType;
1357 sysPType = GL_LINES;
1359 else
1361 sysPType = 0;
1365 // set len/sysPType
1366 if(sysPType)
1368 lensPtr->push_back(len);
1370 geoTypePtr->push_back(sysPType);
1373 primitiveN = 0;
1374 beginIndex = endIndex = -1;
1376 for(Int32 i = 0; i <= piN; i++)
1378 if(((i == piN) && (coordIndex[i - 1] >= 0)) ||
1379 ((i < piN) && (coordIndex[i] < 0)))
1381 len = i - beginIndex;
1383 if(ccw)
1385 endIndex = i;
1386 step = 1;
1388 else
1390 endIndex = beginIndex - 1;
1392 beginIndex = i - 1;
1394 step = -1;
1397 localPType = (len > maxPType) ? maxPType : len;
1399 if((beginIndex >= 0) && (localPType == pType))
1401 if(len >= maxPType)
1403 sysPType = faceSet ? GL_POLYGON : GL_LINE_STRIP;
1405 lensPtr->push_back(len);
1407 geoTypePtr->push_back(sysPType);
1410 // add index data
1411 for(pi = beginIndex; pi != endIndex; pi += step)
1413 posIndexPtr->push_back(coordIndex[pi]);
1415 for(typei = 1; typei <= 3; typei++)
1417 index = -1;
1419 switch(indexType[typei])
1421 case UNKNOWN_IT:
1422 case EMPTY_IT:
1423 case VERTEX_COORD_IT:
1424 break;
1426 case VERTEX_IT:
1428 index = (*indexBag[typei])[pi];
1430 break;
1431 case PRIMITIVE_IT:
1433 index = primitiveN;
1435 break;
1436 case PRIMITIVE_INDEX_IT:
1438 index = (*indexBag[typei])[
1439 primitiveN];
1441 break;
1443 default: //X_CREATE_IT
1444 break;
1447 if(index != -1)
1449 if(indexOutBag[typei] == NULL)
1451 indexOutBag[typei] = GeoUInt32Property::create();
1454 indexOutBag[typei]->push_back(index);
1461 triCount += len - 2;
1464 primitiveN++;
1465 beginIndex = endIndex = -1;
1467 else if(beginIndex < 0)
1469 beginIndex = i;
1476 for(UInt32 i = 1; i < 4; ++i)
1478 if((indexType [i] == VERTEX_COORD_IT || indexType [i] == VERTEX_DUP_IT) &&
1479 (indexOutBag[i] == NULL || indexOutBag[i]->size() == 0 ) )
1481 geoPtr->setIndex(posIndexPtr, indexOutBagID[i]);
1483 else if(indexOutBag[i] != NULL && indexOutBag[i]->size() != 0)
1485 geoPtr->setIndex(indexOutBag[i], indexOutBagID[i]);
1489 return triCount;
1493 /*! \ingroup GrpDrawablesGeometryUtils
1495 setIndexFromIndexedX3DData creates an OSG::Geometry's interleaved index data
1496 from X3D-style separate indices, see \ref PageSystemGeoFunctionsMakeGeo
1497 for a description.
1499 The \a primitiveType defines the GL-Primtive (e.g. GL_LINE, GL_TRIANGLE_STRIP,
1500 GL_POLYGON) which should be used.
1502 \a coordIndex, \a normalIndex, \a colorIndex and \a texCoordIndex are
1503 X3D-style indices. \a ccw sets whether poylgons are defined
1504 counter-clockwise or clockwise, \a normalPerVertex and \a colorPerVertex
1505 specify bindings. See the X3D specification at
1506 http://www.web3d.org for details.
1508 Note: the \a convex and \a createNormals parameters are ignored right now!
1511 Int32 setIndexFromIndexedX3DData ( Geometry *geoPtr,
1512 std::vector<Int32> &coordIndex,
1513 std::vector<Int32> &normalIndex,
1514 std::vector<Int32> &colorIndex,
1515 std::vector<Int32> &texCoordIndex,
1516 Int32 primitiveType,
1517 bool convex,
1518 bool ccw,
1519 bool normalPerVertex,
1520 bool colorPerVertex,
1521 bool createNormal )
1523 /** define the bag type */
1524 typedef std::vector<Int32> *IndexBagP;
1526 /** defines the Index Types */
1527 enum IndexType
1529 UNKNOWN_IT = 0,
1530 EMPTY_IT,
1531 VERTEX_COORD_IT,
1532 VERTEX_IT,
1533 VERTEX_DUP_IT,
1534 VERTEX_CREATE_IT,
1535 PRIMITIVE_IT,
1536 PRIMITIVE_INDEX_IT,
1537 PRIMITIVE_CREATE_IT
1540 /** holds the Index types as str, mainly for log/debug outputs */
1541 static const char *indexTypeStr[] =
1543 "UNKNOWN_IT",
1544 "EMPTY_IT",
1545 "VERTEX_COORD_IT",
1546 "VERTEX_IT",
1547 "VERTEX_DUP_IT",
1548 "VERTEX_CREATE_IT",
1549 "PRIMTIVE_IT",
1550 "PRIMITIVE_INDEX_IT",
1551 "PRIMITIVE_CREATE_IT"
1554 GeoVectorPropertyUnrecPtr posPtr;
1555 GeoVectorPropertyUnrecPtr normalPtr;
1556 GeoVectorPropertyUnrecPtr colorPtr;
1557 GeoVectorPropertyUnrecPtr texCoordsPtr;
1559 GeoIntegralPropertyUnrecPtr lensPtr;
1560 GeoIntegralPropertyUnrecPtr geoTypePtr;
1561 GeoIntegralPropertyUnrecPtr posIndexPtr = NULL;
1563 //bool faceSet = (primitiveType == GL_POLYGON);
1564 Int32 index, pi, typei, primitiveN = 0, vN = 0;
1565 Int32 pType = 0, localPType;
1566 Int32 maxPType = 0; // = (faceSet ? 5 : 3);
1567 Int32 minPType = 0; // = (faceSet ? 3 : 2);
1568 Int32 beginIndex, endIndex, step, len, sysPType = 0;
1569 Int32 piN = 0, ciN = 0, niN = 0, tiN = 0;
1570 Int32 pN = 0, nN = 0, cN = 0, tN = 0;
1571 IndexType indexType[4];
1572 IndexType &coordIT = indexType[0];
1573 IndexType &normalIT = indexType[1];
1574 IndexType &colorIT = indexType[2];
1575 IndexType &textureIT = indexType[3];
1576 Int32 primitiveTypeCount[6];
1577 UInt32 triCount = 0;
1579 IndexBagP indexBag[4] =
1581 &coordIndex,
1582 &normalIndex,
1583 &colorIndex,
1584 &texCoordIndex
1587 GeoIntegralPropertyUnrecPtr indexOutBag[4] =
1589 NULL,
1590 NULL,
1591 NULL,
1592 NULL
1595 UInt16 indexOutBagID[4] =
1597 Geometry::PositionsIndex,
1598 Geometry::NormalsIndex,
1599 Geometry::ColorsIndex,
1600 Geometry::TexCoordsIndex
1603 static const UInt32 uiNumTexCoords = 8;
1605 UInt32 texCoordN[uiNumTexCoords] =
1617 UInt16 texCoordIdx[uiNumTexCoords] =
1619 Geometry::TexCoordsIndex,
1620 Geometry::TexCoords1Index,
1621 Geometry::TexCoords2Index,
1622 Geometry::TexCoords3Index,
1623 Geometry::TexCoords4Index,
1624 Geometry::TexCoords5Index,
1625 Geometry::TexCoords6Index,
1626 Geometry::TexCoords7Index
1629 //----------------------------------------------------------------------
1630 // init
1631 coordIT = VERTEX_IT;
1633 //----------------------------------------------------------------------
1634 // set maxPType and minPTypr from primitiveType
1635 switch (primitiveType)
1637 case GL_POINTS:
1638 minPType = 1;
1639 maxPType = 1;
1640 break;
1641 case GL_LINES:
1642 minPType = 2;
1643 maxPType = 3;
1644 break;
1645 case GL_LINE_STRIP:
1646 minPType = 2;
1647 maxPType = 3;
1648 break;
1649 case GL_LINE_LOOP:
1650 minPType = 2;
1651 maxPType = 3;
1652 break;
1653 case GL_TRIANGLES:
1654 minPType = 3;
1655 maxPType = 3;
1656 break;
1657 case GL_TRIANGLE_STRIP:
1658 minPType = 3;
1659 maxPType = 3;
1660 break;
1661 case GL_TRIANGLE_FAN:
1662 minPType = 3;
1663 maxPType = 3;
1664 break;
1665 case GL_QUADS:
1666 minPType = 3;
1667 maxPType = 4;
1668 break;
1669 case GL_QUAD_STRIP:
1670 minPType = 3;
1671 maxPType = 4;
1672 break;
1673 case GL_POLYGON:
1674 minPType = 3;
1675 maxPType = 5;
1676 break;
1677 default:
1678 FFATAL (( "Can not fill index; Invalid primitiveType: %d\n",
1679 primitiveType ));
1680 break;
1683 //----------------------------------------------------------------------
1684 // get the property pointer and element count
1685 posPtr = geoPtr->getPositions();
1686 pN = ((posPtr == NULL) ? 0 : posPtr->size32());
1688 normalPtr = geoPtr->getNormals();
1689 nN = ((normalPtr == NULL) ? 0 : normalPtr->size32());
1691 colorPtr = geoPtr->getColors();
1692 cN = ((colorPtr == NULL) ? 0 : colorPtr->size32());
1694 texCoordsPtr = geoPtr->getTexCoords();
1695 tN = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1696 texCoordN[0] = tN;
1698 texCoordsPtr = geoPtr->getTexCoords1();
1699 texCoordN[1] = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1701 texCoordsPtr = geoPtr->getTexCoords2();
1702 texCoordN[2] = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1704 texCoordsPtr = geoPtr->getTexCoords3();
1705 texCoordN[3] = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1707 texCoordsPtr = geoPtr->getTexCoords4();
1708 texCoordN[4] = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1710 texCoordsPtr = geoPtr->getTexCoords5();
1711 texCoordN[5] = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1713 texCoordsPtr = geoPtr->getTexCoords6();
1714 texCoordN[6] = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1716 texCoordsPtr = geoPtr->getTexCoords7();
1717 texCoordN[7] = ((texCoordsPtr == NULL) ? 0 : texCoordsPtr->size32());
1719 FDEBUG(("vertex attrib count P/N/C/T: %d/%d/%d/%d\n", pN, nN, cN, tN));
1721 //----------------------------------------------------------------------
1722 // check the vertex index and count the primitives
1723 primitiveN = index = 0;
1725 for(pType = 0; pType < 6; pType++)
1726 primitiveTypeCount[pType] = 0;
1728 if(!pN)
1730 FINFO(("No points in OSG::setIndexFromVRMLData()\n"));
1731 return 0;
1733 else
1735 piN = UInt32(coordIndex.size());
1737 if(piN)
1739 for(Int32 i = 0; i <= piN; i++)
1741 index = (i == piN) ? -1 : coordIndex[i];
1743 if((index < 0) && vN)
1745 primitiveTypeCount[(vN > maxPType) ? maxPType : vN]++;
1746 primitiveN++;
1747 vN = 0;
1749 else
1751 if(index >= pN && i != piN)
1753 FWARNING(("Point index (%d/%d) out of range", index, pN));
1754 coordIndex[i] = 0;
1757 vN++;
1761 else
1763 FWARNING(("No coordIndex in OSG::setIndexFromVRMLData()\n"));
1764 return 0;
1768 //----------------------------------------------------------------------
1769 // check the normal index
1771 normalIT = UNKNOWN_IT;
1773 niN = UInt32(normalIndex.size());
1775 if(nN)
1776 { // have normal elements
1777 if(normalPerVertex)
1779 // normal per vertex
1780 if(niN >= piN)
1782 // valid normal index number
1783 for(Int32 i = 0; i < piN; i++)
1784 { // check if normal index equals the coord index
1785 if(normalIndex[i] != coordIndex[i])
1787 normalIT = VERTEX_IT;
1788 break;
1792 if(normalIT == UNKNOWN_IT)
1794 // if equal than delete unneeded normal index
1795 normalIT = VERTEX_DUP_IT;
1798 else
1800 // no or not enough normal index
1801 normalIT = VERTEX_COORD_IT;
1803 if(niN)
1805 FWARNING(("Not enough normal index (%" PRISize ",%d)\n",
1806 normalIndex.size(), piN));
1807 normalIndex.clear();
1811 else
1813 // normal per primitive
1814 if(niN >= primitiveN)
1816 // use one normal index per primitive
1817 normalIT = PRIMITIVE_INDEX_IT;
1819 else
1821 if(nN >= primitiveN)
1823 // use one normal per primitive
1824 normalIT = PRIMITIVE_IT;
1826 else
1828 FINFO(("not enough normal index (%d,%d)\n", nN, primitiveN));
1833 else
1835 /* not yet !!!
1836 if (createNormal)
1837 if (normalPerVertex)
1838 normalIT = VERTEX_CREATE_IT;
1839 else
1840 normalIT = PRIMITIVE_CREATE_IT;
1841 else
1843 normalIT = EMPTY_IT;
1846 //----------------------------------------------------------------------
1847 // check the color index
1848 colorIT = UNKNOWN_IT;
1849 ciN = UInt32(colorIndex.size());
1850 if(cN)
1851 { // have color elements
1852 if(colorPerVertex)
1854 // color per vertex
1855 if(ciN >= piN)
1857 // valid color index number
1858 for(Int32 i = 0; i < piN; i++)
1859 { // check if color index equals the coord index
1860 if(colorIndex[i] != coordIndex[i])
1862 colorIT = VERTEX_IT;
1863 break;
1867 if(colorIT == UNKNOWN_IT)
1869 // if equal than delete unneeded color index
1870 colorIT = VERTEX_DUP_IT;
1873 else
1875 // no or not enough color index
1876 colorIT = VERTEX_COORD_IT;
1877 if(ciN)
1879 FWARNING(("Not enough color index (%" PRISize ",%d)\n",
1880 colorIndex.size(), piN));
1881 colorIndex.clear();
1885 else
1887 // color per primitive
1888 if(ciN >= primitiveN)
1890 // use one color index per primitive
1891 colorIT = PRIMITIVE_INDEX_IT;
1893 else
1895 if(cN >= primitiveN)
1897 // use one color per primitive
1898 colorIT = PRIMITIVE_IT;
1900 else
1902 FINFO(("not enough color index (%d,%d)\n", cN, primitiveN));
1907 else
1909 colorIT = EMPTY_IT;
1912 //----------------------------------------------------------------------
1913 // check the texture index
1914 textureIT = UNKNOWN_IT;
1915 tiN = UInt32(texCoordIndex.size());
1916 if(tN)
1917 { // have texture elemnts
1918 if(tiN >= piN)
1920 // valid texture index number
1921 for(Int32 i = 0; i < piN; i++)
1922 { // check if texture index equals the coord index
1923 if(texCoordIndex[i] != coordIndex[i])
1925 textureIT = VERTEX_IT;
1926 break;
1930 if(textureIT == UNKNOWN_IT)
1932 // if equal than delete unneeded texture index
1933 textureIT = VERTEX_DUP_IT;
1936 else
1938 // no or not enough texture index
1939 textureIT = VERTEX_COORD_IT;
1940 if(tiN)
1942 FWARNING(("Not enough texCoord index (%" PRISize ",%d)\n",
1943 texCoordIndex.size(), piN));
1944 texCoordIndex.clear();
1948 else
1950 textureIT = EMPTY_IT;
1953 FNOTICE (( "primitiveN: %d, %d, 0/%d 1/%d 2/%d 3/%d 4/%d 5/%d\n",
1954 primitiveType,
1955 primitiveN, primitiveTypeCount[0],
1956 primitiveTypeCount[1], primitiveTypeCount[2],
1957 primitiveTypeCount[3], primitiveTypeCount[4],
1958 primitiveTypeCount[5]));
1960 FNOTICE (( "IndexType: coord: %s, color: %s, normal: %s, texture: %s \n",
1961 indexTypeStr[coordIT], indexTypeStr[colorIT],
1962 indexTypeStr[normalIT], indexTypeStr[textureIT]));
1964 //----------------------------------------------------------------------
1965 // check/create the indexPtr/lengthsPtr/geoTypePtr
1967 posIndexPtr = geoPtr->getIndex(Geometry::PositionsIndex);
1969 if(posIndexPtr == NULL)
1971 posIndexPtr = GeoUInt32Property::create();
1973 else
1975 posIndexPtr->clear();
1978 for(Int32 i = 1; i < 4; ++i)
1980 indexOutBag[i] = geoPtr->getIndex(indexOutBagID[i]);
1982 if(indexOutBag[i] != NULL)
1984 indexOutBag[i]->clear();
1988 for(UInt32 i = 0; i < uiNumTexCoords; ++i)
1990 geoPtr->setIndex(NULL, texCoordIdx[i]);
1993 lensPtr = geoPtr->getLengths();
1995 if(lensPtr == NULL)
1997 lensPtr = GeoUInt32Property::create();
1999 else
2001 lensPtr->clear();
2004 geoTypePtr = geoPtr->getTypes();
2006 if(geoTypePtr == NULL)
2008 geoTypePtr = GeoUInt8Property::create();
2010 else
2012 geoTypePtr->clear();
2015 //----------------------------------------------------------------------
2016 // set lens/geoType/index/mapping the index mapping
2018 geoPtr->setLengths(lensPtr);
2019 geoPtr->setTypes(geoTypePtr);
2021 geoPtr->setIndex(posIndexPtr, Geometry::PositionsIndex);
2023 //----------------------------------------------------------------------
2024 // create index face/line data
2026 for(pType = minPType; pType <= maxPType; pType++)
2028 // check for the pType count
2029 if(primitiveTypeCount[pType])
2031 // calc len/sysPType
2033 if(pType < maxPType)
2035 len = primitiveTypeCount[pType] * pType;
2037 switch (pType)
2039 case 1:
2040 sysPType = GL_POINTS;
2041 break;
2042 case 2:
2043 sysPType = GL_LINES;
2044 break;
2045 case 3:
2046 sysPType = GL_TRIANGLES;
2047 break;
2048 case 4:
2049 sysPType = GL_QUADS;
2050 break;
2053 else
2055 sysPType = 0;
2058 // set len/sysPType
2059 if(sysPType)
2061 lensPtr->push_back(len);
2063 geoTypePtr->push_back(sysPType);
2066 primitiveN = 0;
2067 beginIndex = endIndex = -1;
2069 for(Int32 i = 0; i <= piN; i++)
2071 if(((i == piN) && (coordIndex[i - 1] >= 0)) ||
2072 ((i < piN) && (coordIndex[i] < 0)))
2074 len = i - beginIndex;
2076 if(ccw)
2078 endIndex = i;
2079 step = 1;
2081 else
2083 endIndex = beginIndex - 1;
2084 beginIndex = i - 1;
2085 step = -1;
2088 localPType = (len > maxPType) ? maxPType : len;
2090 if((beginIndex >= 0) && (localPType == pType))
2092 if(len >= maxPType)
2094 sysPType = primitiveType;
2096 lensPtr->push_back(len);
2097 geoTypePtr->push_back(sysPType);
2100 // add index data
2101 for(pi = beginIndex; pi != endIndex; pi += step)
2103 posIndexPtr->push_back(coordIndex[pi]);
2105 for(typei = 1; typei <= 3; typei++)
2107 index = -1;
2109 switch(indexType[typei])
2111 case UNKNOWN_IT:
2112 case EMPTY_IT:
2113 case VERTEX_COORD_IT:
2114 case VERTEX_DUP_IT:
2115 break;
2116 case VERTEX_IT:
2117 index = (*indexBag[typei])[pi];
2118 break;
2119 case PRIMITIVE_IT:
2120 index = primitiveN;
2121 break;
2122 case PRIMITIVE_INDEX_IT:
2123 index = (*indexBag[typei])[primitiveN];
2124 break;
2125 default: //X_CREATE_IT
2126 break;
2130 if(index != -1)
2132 if(indexOutBag[typei] == NULL)
2134 indexOutBag[typei] =
2135 GeoUInt32Property::create();
2138 indexOutBag[typei]->push_back(index);
2144 triCount += len - 2;
2147 primitiveN++;
2148 beginIndex = endIndex = -1;
2150 else if(beginIndex < 0)
2152 beginIndex = i;
2158 for(UInt32 i = 1; i < 4; ++i)
2160 if((indexType [i] == VERTEX_COORD_IT || indexType [i] == VERTEX_DUP_IT) &&
2161 (indexOutBag[i] == NULL || indexOutBag[i]->size() == 0 ) )
2163 geoPtr->setIndex(posIndexPtr, indexOutBagID[i]);
2165 else if(indexOutBag[i] != NULL && indexOutBag[i]->size() != 0)
2167 geoPtr->setIndex(indexOutBag[i], indexOutBagID[i]);
2169 else if(indexOutBag[i] != NULL && indexOutBag[i]->size() == 0)
2171 geoPtr->setIndex(NULL, indexOutBagID[i]);
2175 for(UInt32 i = 1; i < uiNumTexCoords; ++i)
2177 if(texCoordN[i] != 0)
2179 if((indexType [3] == VERTEX_COORD_IT ||
2180 indexType [3] == VERTEX_DUP_IT) &&
2181 (indexOutBag[3] == NULL ||
2182 indexOutBag[3]->size() == 0 ) )
2184 geoPtr->setIndex(posIndexPtr, texCoordIdx[i]);
2186 else if(indexOutBag[3] != NULL && indexOutBag[3]->size() != 0)
2188 geoPtr->setIndex(indexOutBag[3], texCoordIdx[i]);
2194 for(UInt32 i = 1; i < 4; ++i)
2196 indexOutBag[i] = NULL;
2199 return triCount;
2202 /*! \ingroup GrpDrawablesGeometryUtils
2204 Int32 createOptimizedPrimitives(Geometry *geo,
2205 UInt32 iteration,
2206 bool createStrips,
2207 bool createFans,
2208 UInt32 minFanEdgeCount,
2209 bool colorCode,
2210 bool stitchStrips )
2212 if (geo == NULL)
2214 return 0;
2217 StriperHalfEdgeGraph graph;
2219 UInt32 cost = 0;
2220 UInt32 startCost = 0;
2221 UInt32 bestCost = 0;
2222 UInt32 worstCost = 0;
2223 UInt32 triN = 0;
2224 UInt32 lineN = 0;
2225 UInt32 pointN = 0;
2226 UInt32 patchesN = 0;
2227 Int32 invalidTriCount = 0;
2229 Time time;
2230 Time inputT;
2231 Time optimizeT;
2232 Time outputT;
2235 Geometry::IndexBag oGeoIndexBag = geo->getUniqueIndexBag();
2238 UInt32 indexMapSize = UInt32(oGeoIndexBag.size());
2239 bool remapIndex = (indexMapSize > 1) ? true : false;
2241 IndexDic indexDic;
2244 calcPrimitiveCount(geo, triN, lineN, pointN, patchesN);
2246 GeoVectorProperty *posPtr = geo->getPositions();
2248 UInt32 pN = ((posPtr == NULL) ? 0 : posPtr->size32());
2250 GeoIntegralProperty *posIndexPtr =
2251 geo->getIndex(Geometry::PositionsIndex);
2253 // Calculate startCost.
2254 if(posIndexPtr == NULL)
2256 startCost = pN;
2258 else
2260 startCost = posIndexPtr->size32();
2263 // Leave early if we have no indices or positions.
2264 if (pN == 0 || posIndexPtr == NULL)
2266 return 0;
2269 FDEBUG(("GeoOpt: start/tri cost: %d/%d imp: %d tri/line/point: %d/%d/%d\n",
2270 startCost, (triN * 3), indexMapSize, triN, lineN, pointN));
2272 inputT = getSystemTime();
2274 invalidTriCount = 0;
2276 if (!remapIndex && (pN > (triN * 3)))
2278 FINFO(("Force index remap for unusual vertex/tri count: %d/%d\n",
2279 pN, triN ));
2281 indexMapSize = 1;
2282 remapIndex = true;
2285 if(remapIndex)
2287 graph.reserve(triN * 3, triN, 8);
2289 std::vector < Int32 > indexVec(indexMapSize);
2291 UInt32 triCount = 0;
2293 for(TriangleIterator tI = geo->beginTriangles();
2294 (triCount < triN) && (tI != geo->endTriangles());
2295 ++tI)
2297 Int32 v[3];
2299 for(Int32 i = 0; i < 3; i++)
2301 Int32 index = tI.getIndex(i);
2303 for(UInt32 j = 0; j < indexMapSize; j++)
2305 indexVec[j] = oGeoIndexBag[j].first->getValue(index);
2308 v[i] = indexDic.entry(indexVec);
2311 invalidTriCount += graph.addTriangle(v[0], v[1], v[2]) ? 0 : 1;
2313 ++triCount;
2316 FDEBUG(("Multi-index dic entry: %d/%d\n", indexDic.entryCount(),
2317 (triN * 3)));
2319 else
2321 graph.reserve(osgMin(pN, triN * 3), triN, 8);
2323 UInt32 triCount = 0;
2325 for(TriangleIterator tI = geo->beginTriangles();
2326 (triCount < triN) && (tI != geo->endTriangles());
2327 ++tI)
2329 invalidTriCount +=
2330 graph.addTriangle(tI.getPositionIndex(0),
2331 tI.getPositionIndex(1),
2332 tI.getPositionIndex(2)) ? 0 : 1;
2333 ++triCount;
2338 if(invalidTriCount)
2340 FNOTICE(("%d invalid tri during halfegde construction found\n",
2341 invalidTriCount));
2344 #ifdef OSG_DEBUG
2345 graph.verify();
2346 #endif
2348 time = getSystemTime();
2349 inputT = time - inputT;
2350 optimizeT = time;
2351 bestCost = triN * 3 + 1;
2352 worstCost = 0;
2354 cost = graph.calcOptPrim(iteration,
2355 createStrips,
2356 createFans,
2357 minFanEdgeCount);
2359 if(cost)
2361 if(cost < bestCost)
2362 bestCost = cost;
2364 if(cost > worstCost)
2365 worstCost = cost;
2367 else
2369 bestCost = worstCost = 0;
2372 // valid result
2373 if(bestCost && (bestCost < startCost))
2375 GeoIntegralPropertyUnrecPtr lensPtr;
2376 GeoIntegralPropertyUnrecPtr geoTypePtr;
2378 // check/create the indexPtr/lengthsPtr/geoTypePtr
2380 lensPtr = geo->getLengths();
2382 if(lensPtr == NULL)
2384 lensPtr = OSG::GeoUInt32Property::create();
2386 geo->setLengths(lensPtr);
2389 geoTypePtr = geo->getTypes();
2391 if(geoTypePtr == NULL)
2393 geoTypePtr = OSG::GeoUInt8Property::create();
2395 geo->setTypes(geoTypePtr);
2399 time = getSystemTime();
2400 optimizeT = time - optimizeT;
2401 outputT = time;
2403 lensPtr ->clear();
2404 geoTypePtr->clear();
2406 for(UInt32 i = 0; i < indexMapSize; ++i)
2408 oGeoIndexBag[i].first->clear();
2412 FDEBUG(("Start graph.getPrimitive() loop (triN: %d)\n", triN));
2414 UInt32 numPrimitives = graph.primitiveCount();
2416 std::vector< std::vector<UInt32> > primIndex(numPrimitives);
2418 const Int32 typeVec[] =
2420 GL_TRIANGLES,
2421 GL_TRIANGLE_STRIP,
2422 GL_TRIANGLE_FAN
2425 const Int32 typeN = sizeof(typeVec) / sizeof(Int32);
2427 cost = 0;
2429 for(Int32 t = 0; t < typeN; ++t)
2431 UInt32 triCount = 0;
2433 bool stitch = false;
2434 UInt32 windingCorrection = 0;
2435 UInt32 lastTriStripIndex = 0;
2436 UInt32 totalTriStripLength = 0;
2438 for(Int32 i = 0; i < Int32(numPrimitives); ++i)
2440 graph.getPrimitive(primIndex[i], typeVec[t]);
2442 const Int32 n = UInt32(primIndex[i].size());
2444 cost += n;
2446 if(!n)
2448 break;
2451 if(typeVec[t] == GL_TRIANGLES)
2453 triCount += (n / 3);
2455 else if (typeVec[t] == GL_TRIANGLE_STRIP)
2457 if (stitchStrips)
2459 if (stitch)
2461 // add the previous index and the first of the
2462 // new one, but make sure winding is still correct.
2463 if(remapIndex)
2465 for(UInt32 j = 0; j < 1+windingCorrection; ++j)
2467 for(UInt32 k = 0; k < indexMapSize; ++k)
2469 oGeoIndexBag[k].first->push_back(
2470 indexDic.entry(
2471 lastTriStripIndex)[k]);
2474 for(UInt32 k = 0; k < indexMapSize; ++k)
2476 oGeoIndexBag[k].first->push_back(
2477 indexDic.entry(primIndex[i][0])[k]);
2480 else
2482 for(UInt32 j = 0; j < 1+windingCorrection; ++j)
2484 posIndexPtr->push_back(lastTriStripIndex);
2487 posIndexPtr->push_back(primIndex[i][0]);
2490 totalTriStripLength += 2 + windingCorrection;
2493 stitch = true;
2494 windingCorrection = n % 2;
2495 lastTriStripIndex = primIndex[i][n - 1];
2497 else
2499 lensPtr ->push_back(n);
2500 geoTypePtr->push_back(typeVec[t]);
2503 else
2505 lensPtr ->push_back(n);
2506 geoTypePtr->push_back(typeVec[t]);
2509 if(remapIndex)
2511 for(Int32 j = 0; j < n; ++j)
2513 for(UInt32 k = 0; k < indexMapSize; ++k)
2515 Int32 index = indexDic.entry(primIndex[i][j])[k];
2516 oGeoIndexBag[k].first->push_back(index);
2520 else
2522 for(Int32 j = 0; j < n; ++j)
2524 posIndexPtr->push_back(primIndex[i][j]);
2528 totalTriStripLength += n;
2531 if(triCount && typeVec[t] == GL_TRIANGLES)
2533 lensPtr ->push_back(triCount * 3);
2534 geoTypePtr->push_back(GL_TRIANGLES);
2537 if(stitchStrips && totalTriStripLength &&
2538 typeVec[t] == GL_TRIANGLE_STRIP)
2540 lensPtr ->push_back(totalTriStripLength);
2541 geoTypePtr->push_back(GL_TRIANGLE_STRIP);
2545 time = getSystemTime();
2546 outputT = time - outputT;
2548 FNOTICE(("Graph in/opt/out timing: %g/%g/%g \n", inputT, optimizeT,
2549 outputT));
2551 if(cost != bestCost)
2553 FWARNING(("cost != bestCost: %d/%d; we lost some nodes !\n",
2554 cost, bestCost));
2556 else
2558 FINFO(("OptResult: %2g%%, Sampling (%di): cost %d/%d \n",
2559 double(double(bestCost) / double(
2560 startCost) * 100.0
2561 ), iteration, bestCost, worstCost));
2564 else
2566 FINFO(("startCost (%d) <= bestCost (%d), triCost(%d); keep geo data\n",
2567 startCost, bestCost, (triN * 3)));
2570 return bestCost;
2573 /*! \ingroup GrpDrawablesGeometryUtils
2576 void createConvexPrimitives(Geometry *geo)
2578 FFATAL(("createConvexPrimitives:: NYI!\n"));
2581 /*! Adjusts the indices of \a geoPtr such that data is as much as possible
2582 reused.
2584 \ingroup GrpDrawablesGeometryUtils
2586 Int32 createSharedIndex(Geometry *geoPtr)
2588 UInt32 indexSharedCount = 0, dataRemapCount = 0, indexRemapCount = 0;
2589 UInt32 iN, index, si, sN;
2590 UInt32 indexBlock = 0, masterDSize;
2592 GeoVectorProperty *masterProp = NULL, *slaveProp = NULL;
2594 const UInt8 *masterData;
2596 std::vector<UInt32 > slaveDSizeVec;
2597 std::vector<const UInt8 *> slaveDataVec;
2599 // data pointer and size pair
2600 typedef std::pair<const UInt8 *, UInt32> Mem;
2602 Mem masterMem;
2604 std::map<Mem, UInt32, memless<Mem> > memMap;
2605 std::map<Mem, UInt32, memless<Mem> >::iterator mmI;
2607 GeoIntegralProperty *indexPtr;
2609 const UChar8 *dataElem;
2611 std::vector < Int32 > indexRemap;
2613 Geometry::IndexBag indexBag;
2615 if(geoPtr != NULL)
2617 if(geoPtr->getPositions() != NULL)
2619 // check/create indexPtr
2620 iN = geoPtr->getPositions()->size32();
2622 indexBag = geoPtr->getUniqueIndexBag();
2624 if(indexBag.size() == 0)
2626 #if 0
2627 indexPtr = GeoIndicesUI32::create();
2628 indexPtr->resize(iN);
2630 for(i = 0; i < iN; i++)
2631 indexPtr->setValue(i, i);
2633 beginEditCP(geoPtr);
2635 geoPtr->setIndices(indexPtr);
2638 endEditCP(geoPtr);
2639 #else
2640 FNOTICE(("non indexed geo not handled in createSharedIndex()\n"));
2641 return 0;
2642 #endif
2645 else
2647 FNOTICE(("Invalid geoPtr->getPositions() in createSharedIndex()\n"));
2648 return 0;
2651 else
2653 FNOTICE(("Invalid geoPtr in createSharedIndex()\n"));
2654 return 0;
2658 // reset stat counter
2659 indexSharedCount = 0;
2660 dataRemapCount = 0;
2661 indexRemapCount = 0;
2663 // iterator over all index properties
2664 for(UInt32 i = 0; i < indexBag.size(); ++i)
2666 // first property indexed by index i is the master property
2667 masterProp = geoPtr->getProperty(indexBag[i].second[0]);
2668 masterData = masterProp->getData();
2670 if(masterProp != NULL && masterData != NULL)
2672 // calc master data element size
2673 masterDSize =
2674 masterProp->getFormatSize() *
2675 masterProp->getDimension () +
2676 masterProp->getStride ();
2678 // all other properties indexed by index i are slave properties
2679 // find and store slave property data and sizes
2680 slaveDataVec .clear();
2681 slaveDSizeVec.clear();
2683 // store pointers to data and sizes of slave properties
2684 for(UInt32 j = 1; j < indexBag[i].second.size(); ++j)
2686 slaveProp = geoPtr->getProperty(indexBag[i].second[j]);
2688 // there may be no property to the index
2689 if(slaveProp == NULL)
2690 continue;
2692 if(slaveProp->getData() != NULL)
2694 slaveDataVec .push_back(slaveProp->getData () );
2695 slaveDSizeVec.push_back(slaveProp->getFormatSize() *
2696 slaveProp->getDimension () );
2698 else
2700 FWARNING(("createSharedIndex: slaveProp %d has no data!\n",
2701 indexBag[i].second[j]));
2705 indexPtr = indexBag[i].first; // index i
2707 sN = UInt32(slaveDataVec. size()); // number of slave properties
2708 iN = UInt32(indexPtr ->size()); // number of indices
2710 memMap.clear();
2712 indexRemap.clear();
2713 indexRemap.resize(masterProp->size(), -1);
2715 masterMem.second =
2716 masterProp->getFormatSize() * masterProp->getDimension();
2718 for(UInt32 j = 0; j < iN; ++j)
2720 index = indexPtr->getValue(j);
2722 if(indexRemap[index] >= 0)
2724 if(indexRemap[index] == Int32(index))
2726 indexSharedCount++;
2728 else
2730 indexPtr->setValue(indexRemap[index], j);
2731 indexRemapCount++;
2734 else
2736 // find/include the data block
2737 dataElem = masterData + (index * masterDSize);
2739 masterMem.first = dataElem;
2741 mmI = memMap.find(masterMem);
2743 if(mmI == memMap.end())
2745 // index not found; store new data/index
2746 memMap [masterMem] = index;
2747 indexRemap[index ] = index;
2749 else
2751 // data found; check slave property
2752 for(si = 0; si < sN; si++)
2754 if(memcmp(slaveDataVec[si] + (index * slaveDSizeVec[si]),
2755 slaveDataVec[si] + (mmI->second * slaveDSizeVec[si]),
2756 slaveDSizeVec[si]))
2757 break;
2760 if(si == sN)
2762 // no or valid slave data; remap the index
2763 indexPtr->setValue(mmI->second, j);
2765 indexRemap[index] = mmI->second;
2766 dataRemapCount++;
2768 else
2770 // invalid slave data; cannot remap index
2771 indexRemap[index] = index;
2777 else
2779 FWARNING(("Invalid masterProp %p, block: %d\n",
2780 static_cast<void *>(masterProp), indexBlock));
2783 FINFO(("Create sharedIndex: %d pass; "
2784 "data/index remap: %d/%d \n",
2785 indexBlock, dataRemapCount,
2786 indexRemapCount));
2789 return indexRemapCount + dataRemapCount;
2792 Int32 createSingleIndex(Geometry *geo)
2794 typedef std::vector<UInt16>::iterator IndexIt;
2796 Int32 returnValue = -1;
2798 if(geo == NULL)
2799 return returnValue;
2801 Geometry::IndexBag oGeoIndexBag = geo->getUniqueIndexBag();
2803 if(oGeoIndexBag.size() == 1 || oGeoIndexBag.size() == 0)
2804 return 0;
2807 #if 0
2808 Geometry::IndexBag::iterator bIt = oGeoIndexBag.begin();
2809 Geometry::IndexBag::iterator bEnd = oGeoIndexBag.end ();
2811 for(; bIt != bEnd; ++bIt)
2813 Geometry::IndexBag::iterator rIt = bIt + 1;
2815 for(; rIt != bEnd; )
2817 if(compareContainerEqual(bIt->first, rIt->first, true, true))
2819 bIt->second.insert(bIt->second.end (),
2820 rIt->second.begin(),
2821 rIt->second.end ());
2823 rIt = oGeoIndexBag.erase(rIt);
2825 bEnd = oGeoIndexBag.end();
2827 else
2829 ++rIt;
2834 if(oGeoIndexBag.size() == 1)
2836 GeoIntegralProperty *pIndex = oGeoIndexBag.front().first;
2838 IndexIt pIt = oGeoIndexBag.front().second.begin();
2839 IndexIt pEnd = oGeoIndexBag.front().second.end ();
2841 for(; pIt != pEnd; ++pIt)
2843 geo->setIndex(pIndex, *pIt);
2846 return 0;
2848 #endif
2850 std::vector<Int32> indexVec;
2851 std::vector<Int32> sIndex;
2853 IndexDic indexDic;
2855 Int32 indexMapSize = UInt32(oGeoIndexBag.size());
2856 Int32 vCount = 0;
2858 indexVec.resize(indexMapSize);
2860 Int32 indexCount = oGeoIndexBag.front().first->size32();
2862 sIndex.resize(indexCount);
2864 for(Int32 i = 0; i < indexCount; i++)
2866 for(Int32 j = 0; j < indexMapSize; j++)
2868 indexVec[j] = oGeoIndexBag[j].first->getValue(i);
2871 sIndex[i] = indexDic.entry(indexVec);
2874 vCount = indexDic.entryCount();
2876 if(vCount)
2878 for(Int32 i = 0; i < indexMapSize; i++)
2880 if(i != 0)
2882 oGeoIndexBag[0].second.insert(oGeoIndexBag[0].second.end (),
2883 oGeoIndexBag[i].second.begin(),
2884 oGeoIndexBag[i].second.end ());
2887 for(UInt32 j = 0; j < oGeoIndexBag[i].second.size(); ++j)
2889 GeoVectorProperty *pP =
2890 geo->getProperty(oGeoIndexBag[i].second[j]);
2892 if(pP == NULL || pP->getData() == NULL)
2893 continue;
2895 UInt32 valueSize = (pP->getFormatSize() *
2896 pP->getDimension () +
2897 pP->getStride ());
2899 const UInt8 *data = pP->getData();
2901 GeoPropertyRefPtr pCloneProp = pP->clone();
2903 GeoVectorProperty *pClone =
2904 dynamic_cast<GeoVectorProperty *>(pCloneProp.get());
2906 pClone->resize(vCount);
2908 UInt8 *pData = pClone->editData();
2910 for(Int32 k = 0; k < vCount; k++)
2912 UInt32 index = indexDic.entry(k)[i];
2914 memcpy(pData + (valueSize * k),
2915 data + (valueSize * index),
2916 valueSize);
2919 geo->setProperty(pClone,
2920 oGeoIndexBag[i].second[j]);
2925 oGeoIndexBag.front().first->clear();
2927 for(Int32 i = 0; i < indexCount; i++)
2929 oGeoIndexBag.front().first->push_back(sIndex[i]);
2932 GeoIntegralProperty *pIndex = oGeoIndexBag.front().first;
2934 IndexIt pIt = oGeoIndexBag.front().second.begin();
2935 IndexIt pEnd = oGeoIndexBag.front().second.end ();
2937 for(; pIt != pEnd; ++pIt)
2939 geo->setIndex(pIndex, *pIt);
2943 return vCount;
2947 /*! \ingroup GrpDrawablesGeometryUtils
2949 Calculate some basic statistics of the Geometry.
2951 UInt32 calcPrimitiveCount(Geometry *geo,
2952 UInt32 &triangle,
2953 UInt32 &line,
2954 UInt32 &point,
2955 UInt32 &patches)
2957 GeoIntegralProperty *geoTypePtr;
2958 GeoIntegralProperty *lensPtr;
2960 UInt32 lN, tN, len, type;
2962 // TODO; should we really reset the values ?
2963 triangle = line = point = patches = 0;
2965 if(geo == NULL)
2967 FINFO(("No geo in calcPrimitiveCount\n"));
2968 return 0;
2971 lensPtr = geo->getLengths();
2973 lN = (lensPtr == NULL) ? 0 : lensPtr->size32();
2976 geoTypePtr = geo->getTypes();
2978 tN = (geoTypePtr == NULL) ? 0 : geoTypePtr->size32();
2980 if((tN == 0) || (lN != 0 && tN != lN) || (lN == 0 && tN != 1))
2982 return 0;
2985 for(UInt32 i = 0; i < geoTypePtr->size(); ++i)
2987 geoTypePtr->getValue(type, i);
2989 if(lN != 0)
2991 lensPtr->getValue(len, i);
2993 else
2995 GeoVectorProperty *pos = geo->getPositions();
2997 if(pos == NULL)
2999 FINFO(("calcPrimitiveCount: no Points!\n"));
3000 return 0;
3003 len = pos->size32();
3006 switch(type)
3008 case GL_POINTS:
3009 point += len;
3010 break;
3011 case GL_LINES:
3012 line += len / 2;
3013 break;
3014 case GL_LINE_LOOP:
3015 line += len;
3016 break;
3017 case GL_LINE_STRIP:
3018 line += len - 1;
3019 break;
3020 case GL_TRIANGLES:
3021 triangle += len / 3;
3022 break;
3023 case GL_TRIANGLE_STRIP:
3024 triangle += len - 2;
3025 break;
3026 case GL_TRIANGLE_FAN:
3027 triangle += len - 2;
3028 break;
3029 case GL_QUADS:
3030 triangle += len / 2;
3031 break;
3032 case GL_QUAD_STRIP:
3033 triangle += len - 2;
3034 break;
3035 case GL_POLYGON:
3036 triangle += len - 2;
3037 break;
3038 case GL_PATCHES:
3039 patches += 1;
3040 break;
3041 default:
3042 FWARNING(("calcPrimitiveCount(): Invalid geoType: %d\n",
3043 type));
3044 break;
3049 return triangle + line + point;
3052 /*! \ingroup GrpDrawablesGeometryUtils
3054 Create a geometry of the vertex normals of the object. Useful for Visualizing
3055 the normals.
3057 \warning It does not check whether the normals are actually vertex normals,
3058 it just uses them as if.
3061 NodeTransitPtr calcVertexNormalsGeo(Geometry *geo,
3062 Real32 length)
3064 GeoPnt3fPropertyUnrecPtr pnts = GeoPnt3fProperty::create();
3066 // calculate
3068 PrimitiveIterator pi(geo);
3070 if(1 /* no easy way to check right now */ )
3072 for(pi = geo->beginPrimitives(); pi != geo->endPrimitives(); ++pi)
3074 for(UInt32 k = 0; k < pi.getLength(); k++)
3076 pnts->push_back(pi.getPosition(k));
3077 pnts->push_back(pi.getPosition(k) + length * pi.getNormal(k));
3081 else
3083 Pnt3f center(0, 0, 0);
3085 for(pi = geo->beginPrimitives(); pi != geo->endPrimitives(); ++pi)
3087 for(UInt32 k = 0; k < pi.getLength(); k++)
3089 center[0] += pi.getPosition(k)[0];
3090 center[1] += pi.getPosition(k)[1];
3091 center[2] += pi.getPosition(k)[2];
3094 pnts->push_back(center);
3095 pnts->push_back(center + length * pi.getNormal(0));
3099 GeoIntegralPropertyUnrecPtr type = GeoUInt8Property::create();
3101 type->push_back(GL_LINES);
3103 GeoIntegralPropertyUnrecPtr lens = GeoUInt32Property::create();
3105 lens->push_back(pnts->size32());
3107 GeometryUnrecPtr g = Geometry::create();
3109 g->setTypes (type );
3110 g->setLengths (lens );
3111 g->setPositions(pnts );
3112 g->setMaterial (getDefaultUnlitMaterial());
3114 return makeNodeFor(g);
3117 /*! \ingroup GrpDrawablesGeometryUtils
3119 void updateVertexNormalsGeo( Geometry *pGeo,
3120 Real32 length,
3121 const Geometry *pRefGeo)
3123 GeoPnt3fProperty *pnts =
3124 dynamic_cast<GeoPnt3fProperty *>(
3125 pGeo->getProperty(Geometry::PositionsIndex));
3127 GeoIntegralProperty *type = pGeo->getTypes();
3128 GeoIntegralProperty *lens = pGeo->getLengths();
3130 if(pnts == NULL || type == NULL || lens == NULL)
3131 return;
3133 pnts->clear();
3134 type->clear();
3135 lens->clear();
3137 // calculate
3139 PrimitiveIterator pi(pRefGeo);
3141 if(1 /* no easy way to check right now */ )
3143 for(pi = pRefGeo->beginPrimitives();
3144 pi != pRefGeo->endPrimitives (); ++pi)
3146 for(UInt32 k = 0; k < pi.getLength(); k++)
3148 pnts->push_back(pi.getPosition(k));
3149 pnts->push_back(pi.getPosition(k) + length * pi.getNormal(k));
3154 type->push_back(GL_LINES);
3156 lens->push_back(pnts->size());
3160 /*! \ingroup GrpDrawablesGeometryUtils
3162 Create a geometry of the face normals of the object. Useful for Visualizing
3163 the normals.
3165 \warning It does not check whether the normals are actually face normals,
3166 it just uses them as if.
3169 NodeTransitPtr calcFaceNormalsGeo(Geometry *geo,
3170 Real32 length)
3172 NodeTransitPtr p = Node::create();
3173 GeometryUnrecPtr g = Geometry::create();
3174 GeoPnt3fPropertyUnrecPtr pnts = GeoPnt3fProperty::create();
3175 GeoUInt32PropertyUnrecPtr index = GeoUInt32Property::create();
3176 GeoUInt8PropertyUnrecPtr type = GeoUInt8Property::create();
3177 GeoUInt32PropertyUnrecPtr lens = GeoUInt32Property::create();
3179 // calculate
3181 FaceIterator faceIter = geo->beginFaces();
3182 Pnt3f center;
3184 for(; faceIter != geo->endFaces(); ++faceIter)
3186 center[0] = 0;
3187 center[1] = 0;
3188 center[2] = 0;
3190 for(UInt16 i = 0; i < faceIter.getLength(); ++i)
3192 center[0] += faceIter.getPosition(i)[0] / faceIter.getLength();
3193 center[1] += faceIter.getPosition(i)[1] / faceIter.getLength();
3194 center[2] += faceIter.getPosition(i)[2] / faceIter.getLength();
3197 pnts->push_back(center);
3199 switch(faceIter.getType())
3201 case GL_TRIANGLE_STRIP:
3202 pnts->push_back(center + length * faceIter.getNormal(2));
3203 break;
3204 case GL_TRIANGLE_FAN:
3205 pnts->push_back(center + length * faceIter.getNormal(2));
3206 break;
3207 case GL_QUAD_STRIP:
3208 pnts->push_back(center + length * faceIter.getNormal(3));
3209 break;
3210 default:
3211 //does not matter which point's normal
3212 pnts->push_back(center + length * faceIter.getNormal(0));
3213 break;
3217 for(UInt32 i = 0; i < pnts->size(); i++)
3218 index->push_back(i);
3220 type->push_back(GL_LINES);
3222 lens->push_back(index->size32());
3224 g->setTypes (type );
3225 g->setLengths (lens );
3226 g->setIndices (index );
3227 g->setPositions(pnts );
3228 g->setMaterial (getDefaultUnlitMaterial());
3230 p->setCore(g);
3232 return p;
3235 /*! \ingroup GrpDrawablesGeometryUtils
3237 void separateProperties(Geometry *geo)
3239 FFATAL(("separateProperties: not implemented yet!\n"));
3243 /*! \ingroup GrpDrawablesGeometryUtils
3245 void mergeGeometries(std::vector<Node *> &nodes,
3246 std::vector<Node *> &results)
3248 FFATAL(("mergeGeometries: not implemented yet!\n"));
3253 namespace
3255 // this anonymous namespace contains functions that are implementation
3256 // details for geometry merging
3258 /*! Returns the format to be used when merging a property of \a format1 with
3259 one of \a format2.
3261 UInt32 calcMergeFormat(UInt32 format1, UInt32 format2)
3263 UInt32 format = GL_BYTE ;
3265 switch(format1)
3267 case GL_BYTE:
3268 switch(format2)
3270 case GL_BYTE: format = GL_BYTE; break;
3271 case GL_UNSIGNED_BYTE: format = GL_SHORT; break;
3272 case GL_SHORT: format = GL_SHORT; break;
3273 case GL_UNSIGNED_SHORT: format = GL_INT; break;
3274 case GL_INT: format = GL_INT; break;
3275 case GL_UNSIGNED_INT: format = GL_INT; break;
3277 case GL_FLOAT: format = GL_FLOAT; break;
3278 #ifndef OSG_OGL_NO_DOUBLE
3279 case GL_DOUBLE: format = GL_DOUBLE; break;
3280 #endif
3282 break;
3284 case GL_UNSIGNED_BYTE:
3285 switch(format2)
3287 case GL_BYTE: format = GL_SHORT; break;
3288 case GL_UNSIGNED_BYTE: format = GL_UNSIGNED_BYTE; break;
3289 case GL_SHORT: format = GL_SHORT; break;
3290 case GL_UNSIGNED_SHORT: format = GL_UNSIGNED_SHORT; break;
3291 case GL_INT: format = GL_INT; break;
3292 case GL_UNSIGNED_INT: format = GL_UNSIGNED_INT; break;
3294 case GL_FLOAT: format = GL_FLOAT; break;
3295 #ifndef OSG_OGL_NO_DOUBLE
3296 case GL_DOUBLE: format = GL_DOUBLE; break;
3297 #endif
3299 break;
3301 case GL_SHORT:
3302 switch(format2)
3304 case GL_BYTE: format = GL_SHORT; break;
3305 case GL_UNSIGNED_BYTE: format = GL_SHORT; break;
3306 case GL_SHORT: format = GL_SHORT; break;
3307 case GL_UNSIGNED_SHORT: format = GL_INT; break;
3308 case GL_INT: format = GL_INT; break;
3309 case GL_UNSIGNED_INT: format = GL_INT; break;
3311 case GL_FLOAT: format = GL_FLOAT; break;
3312 #ifndef OSG_OGL_NO_DOUBLE
3313 case GL_DOUBLE: format = GL_DOUBLE; break;
3314 #endif
3316 break;
3318 case GL_UNSIGNED_SHORT:
3319 switch(format2)
3321 case GL_BYTE: format = GL_INT; break;
3322 case GL_UNSIGNED_BYTE: format = GL_UNSIGNED_SHORT; break;
3323 case GL_SHORT: format = GL_INT; break;
3324 case GL_UNSIGNED_SHORT: format = GL_UNSIGNED_SHORT; break;
3325 case GL_INT: format = GL_INT; break;
3326 case GL_UNSIGNED_INT: format = GL_UNSIGNED_INT; break;
3328 case GL_FLOAT: format = GL_FLOAT; break;
3329 #ifndef OSG_OGL_NO_DOUBLE
3330 case GL_DOUBLE: format = GL_DOUBLE; break;
3331 #endif
3333 break;
3335 case GL_INT:
3336 switch(format2)
3338 case GL_BYTE: format = GL_INT; break;
3339 case GL_UNSIGNED_BYTE: format = GL_INT; break;
3340 case GL_SHORT: format = GL_INT; break;
3341 case GL_UNSIGNED_SHORT: format = GL_INT; break;
3342 case GL_INT: format = GL_INT; break;
3343 case GL_UNSIGNED_INT: format = GL_INT; break;
3345 case GL_FLOAT: format = GL_FLOAT; break;
3346 #ifndef OSG_OGL_NO_DOUBLE
3347 case GL_DOUBLE: format = GL_DOUBLE; break;
3348 #endif
3350 break;
3352 case GL_UNSIGNED_INT:
3353 switch(format2)
3355 case GL_BYTE: format = GL_INT; break;
3356 case GL_UNSIGNED_BYTE: format = GL_UNSIGNED_INT; break;
3357 case GL_SHORT: format = GL_INT; break;
3358 case GL_UNSIGNED_SHORT: format = GL_UNSIGNED_INT; break;
3359 case GL_INT: format = GL_INT; break;
3360 case GL_UNSIGNED_INT: format = GL_UNSIGNED_INT; break;
3362 case GL_FLOAT: format = GL_FLOAT; break;
3363 #ifndef OSG_OGL_NO_DOUBLE
3364 case GL_DOUBLE: format = GL_DOUBLE; break;
3365 #endif
3367 break;
3369 case GL_FLOAT:
3370 switch(format2)
3372 case GL_BYTE: format = GL_FLOAT; break;
3373 case GL_UNSIGNED_BYTE: format = GL_FLOAT; break;
3374 case GL_SHORT: format = GL_FLOAT; break;
3375 case GL_UNSIGNED_SHORT: format = GL_FLOAT; break;
3376 case GL_INT: format = GL_FLOAT; break;
3377 case GL_UNSIGNED_INT: format = GL_FLOAT; break;
3379 case GL_FLOAT: format = GL_FLOAT; break;
3380 #ifndef OSG_OGL_NO_DOUBLE
3381 case GL_DOUBLE: format = GL_DOUBLE; break;
3382 #endif
3384 break;
3386 #ifndef OSG_OGL_NO_DOUBLE
3387 case GL_DOUBLE:
3388 switch(format2)
3390 case GL_BYTE: format = GL_DOUBLE; break;
3391 case GL_UNSIGNED_BYTE: format = GL_DOUBLE; break;
3392 case GL_SHORT: format = GL_DOUBLE; break;
3393 case GL_UNSIGNED_SHORT: format = GL_DOUBLE; break;
3394 case GL_INT: format = GL_DOUBLE; break;
3395 case GL_UNSIGNED_INT: format = GL_DOUBLE; break;
3397 case GL_FLOAT: format = GL_DOUBLE; break;
3398 case GL_DOUBLE: format = GL_DOUBLE; break;
3400 break;
3401 #endif
3404 return format;
3407 /*! Determines a format to store the combination of \a prop1 and \a prop2.
3408 If \a combineValues is \c true the contents are scanned to ensure the
3409 determined format can store the sum of the largest entries.
3411 void calcMergePropertyType(
3412 const GeoIntegralProperty *prop1,
3413 const GeoIntegralProperty *prop2,
3414 bool combineValues,
3415 UInt32 &format )
3417 UInt32 form1 = prop1->getFormat();
3418 UInt32 form2 = prop2->getFormat();
3420 format = calcMergeFormat(form1, form2);
3422 if(combineValues && format != GL_INT && format != GL_UNSIGNED_INT)
3424 Int64 max1 = TypeTraits<Int64>::getMin();
3425 Int64 max2 = TypeTraits<Int64>::getMin();
3427 for(UInt32 i = 0; i < prop1->size(); ++i)
3429 if(max1 < prop1->getValue<Int64>(i))
3430 max1 = prop1->getValue<Int64>(i);
3433 for(UInt32 i = 0; i < prop2->size(); ++i)
3435 if(max2 < prop2->getValue<Int64>(i))
3436 max2 = prop2->getValue<Int64>(i);
3439 if(format == GL_BYTE &&
3440 (max1 + max2) > TypeTraits<Int8>::getMax() )
3442 format = GL_SHORT;
3444 else if(format == GL_UNSIGNED_BYTE &&
3445 (max1 + max2) > TypeTraits<UInt8>::getMax() )
3447 format = GL_UNSIGNED_SHORT;
3449 else if(format == GL_SHORT &&
3450 (max1 + max2) > TypeTraits<Int16>::getMax() )
3452 format = GL_INT;
3454 else if(format == GL_UNSIGNED_SHORT &&
3455 (max1 + max2) > TypeTraits<UInt16>::getMax() )
3457 format = GL_UNSIGNED_INT;
3462 /*! Determines a format to store the combination of \a prop1 and \a prop2.
3464 void calcMergePropertyType(
3465 const GeoVectorProperty *prop1,
3466 const GeoVectorProperty *prop2,
3467 UInt32 &format, UInt32 &dim,
3468 UInt32 &vecType, UInt32 &normalize)
3470 UInt32 dim1 = prop1->getDimension ();
3471 UInt32 dim2 = prop2->getDimension ();
3472 UInt32 form1 = prop1->getFormat ();
3473 UInt32 form2 = prop2->getFormat ();
3474 UInt32 vecType1 = prop1->getVectorType();
3475 UInt32 vecType2 = prop2->getVectorType();
3476 bool normalize1 = prop1->getNormalize ();
3477 bool normalize2 = prop2->getNormalize ();
3479 format = calcMergeFormat(form1, form2);
3480 dim = osgMax (dim1, dim2 );
3482 if(vecType1 != vecType2)
3484 FWARNING(("calcMergePropertyType: Can not merge properties with "
3485 "conflicting vecTypes.\n"));
3487 else
3489 vecType = vecType1;
3492 if(normalize1 != normalize2)
3494 FWARNING(("calcMergePropertyType: Can not merge normalizing and "
3495 "non-normalizing property.\n"));
3497 else
3499 normalize = normalize1;
3503 GeoIntegralPropertyTransitPtr mergeIntegralProp(
3504 const GeoIntegralProperty *src1Prop,
3505 const GeoIntegralProperty *src2Prop ) OSG_UNUSED_ATTRIB;
3507 /*! Merges integral properties by appending \a src1Prop and \a src2Prop to a
3508 new property.
3509 \note It is intended to merge the types and length properties.
3511 GeoIntegralPropertyTransitPtr mergeIntegralProp(
3512 const GeoIntegralProperty *src1Prop,
3513 const GeoIntegralProperty *src2Prop )
3515 GeoIntegralPropertyTransitPtr dstProp;
3516 UInt32 dstFormat;
3518 calcMergePropertyType(src1Prop, src2Prop, false, dstFormat);
3519 dstProp = GeoPropertyFactory::the()->create(dstFormat);
3521 UInt32 szSrc1 = src1Prop->size32();
3522 UInt32 szSrc2 = src2Prop->size32();
3524 // TODO: Optimize for matching src and dst types by not using generic
3525 // interface
3526 for(UInt32 i = 0; i < szSrc1; ++i)
3527 dstProp->addValue(src1Prop->getValue(i));
3529 for(UInt32 i = 0; i < szSrc2; ++i)
3530 dstProp->addValue(src2Prop->getValue(i));
3532 return dstProp;
3535 class IndexMap
3537 public:
3538 UInt32 get(UInt32 idx ) const;
3539 void set(UInt32 idx, UInt32 val);
3541 IndexMap(void) : _iMap() {}
3543 private:
3544 typedef std::vector<UInt32> IMap;
3546 IMap _iMap;
3549 inline
3550 UInt32 IndexMap::get(UInt32 idx) const
3552 UInt32 returnValue;
3554 if(idx >= _iMap.size())
3555 returnValue = TypeTraits<UInt32>::getMax();
3556 else
3557 returnValue = _iMap[idx];
3559 return returnValue;
3562 inline
3563 void IndexMap::set(UInt32 idx, UInt32 val)
3565 if(idx >= _iMap.size())
3566 _iMap.resize(idx + 1, TypeTraits<UInt32>::getMax());
3568 _iMap[idx] = val;
3572 /*! Copies and rewrites the index \a srcIdx to \a dstIdx storing the mapping
3573 between old and new indices in \a idxMap.
3574 This function must be called with a correct type argument.
3576 \warning \a dstIdx is expected to have sufficient storage allocated.
3578 template <class DescTypeT> inline
3579 void copyIndex( GeoIntegralProperty *dstIdx,
3580 const GeoIntegralProperty *srcIdx,
3581 UInt32 srcSz,
3582 IndexMap &idxMap,
3583 UInt32 &offset,
3584 UInt32 dstOffset)
3586 typedef TypedGeoIntegralProperty<DescTypeT> TypedProp;
3587 typedef typename TypedProp::StoredType StoredType;
3588 typedef typename TypedProp::StoredFieldType StoredField;
3590 TypedProp *typedDst = dynamic_cast< TypedProp *>(dstIdx);
3591 const TypedProp *typedSrc = dynamic_cast<const TypedProp *>(srcIdx);
3592 StoredField &dstF = typedDst->editField();
3593 const StoredField &srcF = typedSrc->getField ();
3595 for(UInt32 i = 0; i < srcSz; ++i)
3597 StoredType si = srcF[i];
3598 UInt32 di = idxMap.get(si);
3600 if(di == TypeTraits<UInt32>::getMax())
3602 di = offset++;
3603 idxMap.set(si, di);
3606 dstF[i + dstOffset] = di;
3611 /*! Copies and rewrites the index \a srcIdx to \a dstIdx storing the mapping
3612 between old and new indices in \a idxMap.
3614 \warning \a dstIdx is expected to have sufficient storage allocated.
3616 inline
3617 void copyIndex( GeoIntegralProperty *dstIdx,
3618 const GeoIntegralProperty *srcIdx,
3619 UInt32 srcSz,
3620 IndexMap &idxMap,
3621 UInt32 &offset,
3622 UInt32 dstOffset)
3624 UInt32 dstFormat = dstIdx->getFormat();
3625 UInt32 srcFormat = srcIdx->getFormat();
3627 if(dstFormat == srcFormat)
3629 // if the types are equal, use more efficient copying
3631 switch(srcFormat)
3633 case GL_UNSIGNED_BYTE:
3634 copyIndex<GeoUInt8PropertyDesc>(
3635 dstIdx, srcIdx, srcSz, idxMap, offset, dstOffset);
3636 break;
3638 case GL_UNSIGNED_SHORT:
3639 copyIndex<GeoUInt16PropertyDesc>(
3640 dstIdx, srcIdx, srcSz, idxMap, offset, dstOffset);
3641 break;
3643 case GL_UNSIGNED_INT:
3644 copyIndex<GeoUInt32PropertyDesc>(
3645 dstIdx, srcIdx, srcSz, idxMap, offset, dstOffset);
3646 break;
3650 else
3652 // fallback to using the generic interface
3654 typedef GeoIntegralProperty::MaxTypeT IndexType;
3656 for(UInt32 i = 0; i < srcSz; ++i)
3658 IndexType si = srcIdx->getValue<IndexType>(i);
3659 IndexType di = idxMap.get(si);
3661 if(di == TypeTraits<UInt32>::getMax())
3663 di = offset++;
3664 idxMap.set(si, di);
3667 dstIdx->setValue(di, i + dstOffset);
3672 /*! Copies from \a srcProp to \a dstProp the first srcSz values and stores them
3673 at positions starting at \a dstOffset.
3674 This function must be called with a correct type argument.
3676 \warning \a dstProp is expected to have sufficient storage allocated.
3678 template <class DescTypeT> inline
3679 void copyIntegral( GeoIntegralProperty *dstProp,
3680 const GeoIntegralProperty *srcProp,
3681 UInt32 srcSz,
3682 UInt32 dstOffset)
3684 typedef TypedGeoIntegralProperty<DescTypeT> TypedProp;
3685 typedef typename TypedProp::StoredFieldType StoredField;
3687 TypedProp *typedDst = dynamic_cast< TypedProp *>(dstProp);
3688 const TypedProp *typedSrc = dynamic_cast<const TypedProp *>(srcProp);
3689 StoredField &dstF = typedDst->editField();
3690 const StoredField &srcF = typedSrc->getField ();
3692 for(UInt32 i = 0; i < srcSz; ++i)
3693 dstF[dstOffset + i] = srcF[i];
3696 /*! Copies from \a srcProp to \a dstProp the first srcSz values and stores them
3697 at positions starting at \a dstOffset.
3699 \warning \a dstProp is expected to have sufficient storage allocated.
3701 inline
3702 void copyIntegral( GeoIntegralProperty *dstProp,
3703 const GeoIntegralProperty *srcProp,
3704 UInt32 srcSz,
3705 UInt32 dstOffset)
3707 UInt32 dstFormat = dstProp->getFormat();
3708 UInt32 srcFormat = srcProp->getFormat();
3710 if(dstFormat == srcFormat)
3712 // if the types are equal, use more efficient copying
3714 switch(srcFormat)
3716 case GL_UNSIGNED_BYTE:
3717 copyIntegral<GeoUInt8PropertyDesc>(
3718 dstProp, srcProp, srcSz, dstOffset);
3719 break;
3721 case GL_UNSIGNED_SHORT:
3722 copyIntegral<GeoUInt16PropertyDesc>(
3723 dstProp, srcProp, srcSz, dstOffset);
3724 break;
3726 case GL_UNSIGNED_INT:
3727 copyIntegral<GeoUInt32PropertyDesc>(
3728 dstProp, srcProp, srcSz, dstOffset);
3729 break;
3732 else
3734 // fallback to using the generic interface
3736 typedef GeoIntegralProperty::MaxTypeT ValueType;
3738 for(UInt32 i = 0; i < srcSz; ++i)
3739 dstProp->setValue(srcProp->getValue<ValueType>(i), dstOffset + i);
3743 template <class DescTypeT> inline
3744 void copyVectorMapped( GeoVectorProperty *dstProp,
3745 const GeoVectorProperty *srcProp,
3746 const GeoIntegralProperty *srcIdx,
3747 UInt32 srcSz,
3748 const IndexMap &idxMap )
3750 typedef GeoIntegralProperty::MaxTypeT IndexType;
3751 typedef TypedGeoVectorProperty<DescTypeT> TypedProp;
3752 typedef typename TypedProp::StoredFieldType StoredField;
3754 TypedProp *typedDst = dynamic_cast< TypedProp *>(dstProp);
3755 const TypedProp *typedSrc = dynamic_cast<const TypedProp *>(srcProp);
3756 StoredField &dstF = typedDst->editField();
3757 const StoredField &srcF = typedSrc->getField ();
3759 for(UInt32 i = 0; i < srcSz; ++i)
3761 IndexType si = srcIdx->getValue<IndexType>(i);
3762 IndexType di = idxMap .get(si);
3764 dstF[di] = srcF[si];
3768 /*! Copies from \a srcProp to \a dstProp values indexed by the first \a srcSz
3769 indices from \a srcIdx. The values are stored at the positions indicated
3770 by \a idxMap.
3772 \warning \a dstProp is expected to have sufficient storage allocated.
3774 inline
3775 void copyVectorMapped( GeoVectorProperty *dstProp,
3776 const GeoVectorProperty *srcProp,
3777 const GeoIntegralProperty *srcIdx,
3778 UInt32 srcSz,
3779 const IndexMap &idxMap )
3781 UInt32 dstFormat = dstProp->getFormat ();
3782 UInt32 dstDim = dstProp->getDimension ();
3783 UInt32 dstVecType = dstProp->getVectorType();
3785 UInt32 srcFormat = srcProp->getFormat ();
3786 UInt32 srcDim = srcProp->getDimension ();
3787 UInt32 srcVecType = srcProp->getVectorType();
3789 if(dstFormat == srcFormat && dstFormat == GL_FLOAT)
3791 if(dstVecType == srcVecType &&
3792 dstVecType == GeoProperty::VectorTypePoint)
3794 if(dstDim == srcDim && dstDim == 1)
3796 copyVectorMapped<GeoPnt1fPropertyDesc>(
3797 dstProp, srcProp, srcIdx, srcSz, idxMap);
3798 return;
3800 else if(dstDim == srcDim && dstDim == 2)
3802 copyVectorMapped<GeoPnt2fPropertyDesc>(
3803 dstProp, srcProp, srcIdx, srcSz, idxMap);
3804 return;
3806 else if(dstDim == srcDim && dstDim == 3)
3808 copyVectorMapped<GeoPnt3fPropertyDesc>(
3809 dstProp, srcProp, srcIdx, srcSz, idxMap);
3810 return;
3812 else if(dstDim == srcDim && dstDim == 4)
3814 copyVectorMapped<GeoPnt4fPropertyDesc>(
3815 dstProp, srcProp, srcIdx, srcSz, idxMap);
3816 return;
3819 else if(dstVecType == srcVecType &&
3820 dstVecType == GeoProperty::VectorTypeVector)
3822 if(dstDim == srcDim && dstDim == 1)
3824 copyVectorMapped<GeoVec1fPropertyDesc>(
3825 dstProp, srcProp, srcIdx, srcSz, idxMap);
3826 return;
3828 else if(dstDim == srcDim && dstDim == 2)
3830 copyVectorMapped<GeoVec2fPropertyDesc>(
3831 dstProp, srcProp, srcIdx, srcSz, idxMap);
3832 return;
3834 else if(dstDim == srcDim && dstDim == 3)
3836 copyVectorMapped<GeoVec3fPropertyDesc>(
3837 dstProp, srcProp, srcIdx, srcSz, idxMap);
3838 return;
3840 else if(dstDim == srcDim && dstDim == 4)
3842 copyVectorMapped<GeoVec4fPropertyDesc>(
3843 dstProp, srcProp, srcIdx, srcSz, idxMap);
3844 return;
3849 // if we get to this point: fallback to using the generic interface
3851 typedef GeoIntegralProperty::MaxTypeT IndexType;
3852 typedef GeoVectorProperty ::MaxTypeT ValueType;
3854 for(UInt32 i = 0; i < srcSz; ++i)
3856 IndexType si = srcIdx->getValue<IndexType>(i);
3857 IndexType di = idxMap .get(si);
3859 dstProp->setValue(srcProp->getValue<ValueType>(si), di);
3863 // TODO: Optimize copyVector like the above.
3865 /*! Copies from \a srcProp to \a dstProp the first \a srcSz values and stores
3866 them at positions starting at \a dstOffset.
3868 \warning \a dstProp is expected to have sufficient storage allocated.
3870 inline
3871 void copyVector( GeoVectorProperty *dstProp,
3872 const GeoVectorProperty *srcProp,
3873 UInt32 srcSz,
3874 UInt32 dstOffset)
3876 // fallback to using the generic interface
3878 typedef GeoVectorProperty::MaxTypeT ValueType;
3880 for(UInt32 i = 0; i < srcSz; ++i)
3881 dstProp->setValue(srcProp->getValue<ValueType>(i), dstOffset + i);
3884 void mergeGeoTypes(
3885 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
3887 GeoIntegralPropertyUnrecPtr dstTypes;
3888 UInt32 dstFormat;
3890 calcMergePropertyType(srcGeo1->getSFTypes()->getValue(),
3891 srcGeo2->getSFTypes()->getValue(), false, dstFormat);
3892 dstTypes = GeoPropertyFactory::the()->create(dstFormat);
3894 UInt32 src1Sz = srcGeo1->getSFTypes()->getValue()->size32();
3895 UInt32 src2Sz = srcGeo2->getSFTypes()->getValue()->size32();
3897 dstTypes->resize(src1Sz + src2Sz);
3899 copyIntegral(dstTypes, srcGeo1->getSFTypes()->getValue(), src1Sz, 0 );
3900 copyIntegral(dstTypes, srcGeo2->getSFTypes()->getValue(), src2Sz, src1Sz);
3902 dstGeo->setTypes(dstTypes);
3905 void mergeGeoLengths(
3906 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
3908 GeoIntegralPropertyUnrecPtr dstLengths;
3909 UInt32 dstFormat;
3911 calcMergePropertyType(srcGeo1->getSFLengths()->getValue(),
3912 srcGeo2->getSFLengths()->getValue(), false, dstFormat);
3913 dstLengths = GeoPropertyFactory::the()->create(dstFormat);
3915 UInt32 src1Sz = srcGeo1->getSFLengths()->getValue()->size32();
3916 UInt32 src2Sz = srcGeo2->getSFLengths()->getValue()->size32();
3918 dstLengths->resize(src1Sz + src2Sz);
3920 copyIntegral(dstLengths, srcGeo1->getSFLengths()->getValue(), src1Sz, 0 );
3921 copyIntegral(dstLengths, srcGeo2->getSFLengths()->getValue(), src2Sz, src1Sz);
3923 dstGeo->setLengths(dstLengths);
3926 // The following functions are implementing merges between all different
3927 // indexing variants for geometries.
3928 // The last four letters indicate the indexing that is assumed for the
3929 // arguments. NI - non indexed, SI - single indexed, MI - multi indexed
3932 /*! Merge geometry \a srcGeo1 and \a srcGeo2 into \a dstGeo, assuming they have
3933 the same set of properties and both are unindexed.
3935 void mergeGeoNINI(
3936 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
3938 FDEBUG(("mergeGeoNINI: srcGeo1 [%p] srcGeo2 [%p]\n",
3939 static_cast<const void *>(srcGeo1),
3940 static_cast<const void *>(srcGeo2)));
3942 mergeGeoTypes (dstGeo, srcGeo1, srcGeo2);
3943 mergeGeoLengths(dstGeo, srcGeo1, srcGeo2);
3945 // count number of _used_ property elements
3946 UInt32 src1Used = 0;
3947 UInt32 src2Used = 0;
3949 for(UInt32 i = 0; i < srcGeo1->getSFLengths()->getValue()->size(); ++i)
3950 src1Used += srcGeo1->getSFLengths()->getValue()->getValue<UInt32>(i);
3952 for(UInt32 i = 0; i < srcGeo2->getSFLengths()->getValue()->size(); ++i)
3953 src2Used += srcGeo2->getSFLengths()->getValue()->getValue<UInt32>(i);
3955 const Geometry::MFPropertiesType *src1PropF = srcGeo1->getMFProperties ();
3956 const Geometry::MFPropertiesType *src2PropF = srcGeo2->getMFProperties ();
3958 UInt32 szProp = osgMin(src1PropF->size32(), src2PropF->size32());
3960 for(UInt32 i = 0; i < szProp; ++i)
3962 const GeoVectorProperty *src1Prop = (*src1PropF)[i];
3963 const GeoVectorProperty *src2Prop = (*src2PropF)[i];
3965 FFASSERT(!((src1Prop != NULL) ^ (src2Prop != NULL)), 1,
3966 ("mergeGeoNINI: Inconsistent properties!\n");)
3968 if(src1Prop == NULL || src2Prop == NULL)
3969 continue;
3971 UInt32 dstFormat;
3972 UInt32 dstDim;
3973 UInt32 dstVecType;
3974 UInt32 dstNorm;
3976 calcMergePropertyType(src1Prop, src2Prop,
3977 dstFormat, dstDim, dstVecType, dstNorm);
3978 GeoVectorPropertyUnrecPtr dstProp =
3979 GeoPropertyFactory::the()->create(dstFormat, dstDim,
3980 dstVecType, dstNorm != 0);
3982 dstProp->resize(src1Used + src2Used);
3984 copyVector(dstProp, src1Prop, src1Used, 0 );
3985 copyVector(dstProp, src2Prop, src2Used, src1Used);
3987 dstGeo->setProperty(dstProp, i);
3992 /*! Merge geometry \a srcGeo1 and \a srcGeo2 into \a dstGeo, assuming they have
3993 the same set of properties and \a srcGeo1 is not indexed, \a srcGeo2 is
3994 single indexed. The result \a dstGeo will be single indexed.
3996 void mergeGeoNISI(
3997 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
3999 FDEBUG(("mergeGeoNISI: srcGeo1 [%p] srcGeo2 [%p]\n",
4000 static_cast<const void *>(srcGeo1),
4001 static_cast<const void *>(srcGeo2)));
4003 // 1. merge types and lengths
4004 mergeGeoTypes (dstGeo, srcGeo1, srcGeo2);
4005 mergeGeoLengths(dstGeo, srcGeo1, srcGeo2);
4007 // 2. merge properties
4009 // find number of _used_ properties/indices in both geometries
4010 UInt32 src1Used = 0;
4011 UInt32 src2Used = 0;
4013 for(UInt32 i = 0; i < srcGeo1->getSFLengths()->getValue()->size(); ++i)
4014 src1Used += srcGeo1->getSFLengths()->getValue()->getValue<UInt32>(i);
4016 for(UInt32 i = 0; i < srcGeo2->getSFLengths()->getValue()->size(); ++i)
4017 src2Used += srcGeo2->getSFLengths()->getValue()->getValue<UInt32>(i);
4019 // get index bag for single indexed geo
4020 Geometry::IndexBag src2IBag = srcGeo2->getUniqueIndexBag();
4022 FFASSERT(src2IBag.size() == 1, 1, ("mergeGeoNISI: Not single indexed!\n");)
4024 const GeoIntegralProperty *src2Idx = src2IBag[0].first;
4026 // create new index - be conservative and use UInt32 indices
4027 GeoIntegralPropertyUnrecPtr dstIdx =
4028 GeoPropertyFactory::the()->create(GL_UNSIGNED_INT);
4030 // allocate storage
4031 dstIdx->resize(src1Used + src2Used);
4033 // populate index with entries for srcGeo1
4034 for(UInt32 i = 0; i < src1Used; ++i)
4035 dstIdx->setValue(i, i);
4037 IndexMap idxMap;
4038 UInt32 offset = src1Used;
4039 copyIndex(dstIdx, src2Idx, src2Used, idxMap, offset, src1Used);
4041 // copy each property
4042 for(UInt32 i = 0; i < src2IBag[0].second.size(); ++i)
4044 const GeoVectorProperty *src1Prop =
4045 srcGeo1->getProperty(src2IBag[0].second[i]);
4046 const GeoVectorProperty *src2Prop =
4047 srcGeo2->getProperty(src2IBag[0].second[i]);
4049 FFASSERT(!((src1Prop != NULL) ^ (src2Prop != NULL)), 1,
4050 ("mergeGeoNISI: Inconsistent properties!\n");)
4052 if(src1Prop == NULL || src2Prop == NULL)
4053 continue;
4055 UInt32 dstFormat;
4056 UInt32 dstDim;
4057 UInt32 dstVecType;
4058 UInt32 dstNorm;
4060 // create destination property
4061 calcMergePropertyType(src1Prop, src2Prop,
4062 dstFormat, dstDim, dstVecType, dstNorm);
4063 GeoVectorPropertyUnrecPtr dstProp =
4064 GeoPropertyFactory::the()->create(dstFormat, dstDim,
4065 dstVecType, dstNorm != 0);
4067 // allocate storage
4068 dstProp->resize(offset);
4070 copyVector (dstProp, src1Prop, src1Used, 0 );
4071 copyVectorMapped(dstProp, src2Prop, src2Idx, src2Used, idxMap);
4073 dstGeo->setProperty(dstProp, src2IBag[0].second[i]);
4074 dstGeo->setIndex (dstIdx, src2IBag[0].second[i]);
4078 inline
4079 void mergeGeoSINI(
4080 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
4082 mergeGeoNISI(dstGeo, srcGeo2, srcGeo1);
4085 /*! Merge geometry \a srcGeo1 and \a srcGeo2 into \a dstGeo, assuming they
4086 have the same set of properties and \a srcGeo1 is not indexed, \a srcGeo2 is
4087 multi indexed. The result \a dstGeo will be multi indexed.
4089 void mergeGeoNIMI(
4090 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
4092 FDEBUG(("mergeGeoNIMI: srcGeo1 [%p] srcGeo2 [%p]\n",
4093 static_cast<const void *>(srcGeo1),
4094 static_cast<const void *>(srcGeo2)));
4096 // 1. merge types and lengths
4097 mergeGeoTypes (dstGeo, srcGeo1, srcGeo2);
4098 mergeGeoLengths(dstGeo, srcGeo1, srcGeo2);
4100 // 2. merge properties
4102 // find number of _used_ properties/indices in both geometries
4103 UInt32 src1Used = 0;
4104 UInt32 src2Used = 0;
4106 for(UInt32 i = 0; i < srcGeo1->getSFLengths()->getValue()->size(); ++i)
4107 src1Used += srcGeo1->getSFLengths()->getValue()->getValue<UInt32>(i);
4109 for(UInt32 i = 0; i < srcGeo2->getSFLengths()->getValue()->size(); ++i)
4110 src2Used += srcGeo2->getSFLengths()->getValue()->getValue<UInt32>(i);
4112 // get index bag for multi indexed geo
4113 Geometry::IndexBag src2IBag = srcGeo2->getUniqueIndexBag();
4115 for(UInt32 i = 0; i < src2IBag.size(); ++i)
4117 const GeoIntegralProperty *src2Idx = src2IBag[i].first;
4119 // create new index - be conservative and use UInt32 indices
4120 GeoIntegralPropertyUnrecPtr dstIdx =
4121 GeoPropertyFactory::the()->create(GL_UNSIGNED_INT);
4123 // allocate storage
4124 dstIdx->resize(src1Used + src2Used);
4126 // populate index with entries for srcGeo1
4127 for(UInt32 j = 0; j < src1Used; ++j)
4128 dstIdx->setValue(j, j);
4130 IndexMap idxMap;
4131 UInt32 offset = src1Used;
4132 copyIndex(dstIdx, src2Idx, src2Used, idxMap, offset, src1Used);
4134 // copy properties indexed by this index
4135 for(UInt32 j = 0; j < src2IBag[i].second.size(); ++j)
4137 const GeoVectorProperty *src1Prop =
4138 srcGeo1->getProperty(src2IBag[i].second[j]);
4139 const GeoVectorProperty *src2Prop =
4140 srcGeo2->getProperty(src2IBag[i].second[j]);
4142 FFASSERT(!((src1Prop != NULL) ^ (src2Prop != NULL)), 1,
4143 ("mergeGeoNIMI: Inconsistent properties!\n");)
4145 if(src1Prop == NULL || src2Prop == NULL)
4146 continue;
4148 UInt32 dstFormat;
4149 UInt32 dstDim;
4150 UInt32 dstVecType;
4151 UInt32 dstNorm;
4153 // create destination property
4154 calcMergePropertyType(src1Prop, src2Prop,
4155 dstFormat, dstDim, dstVecType, dstNorm);
4156 GeoVectorPropertyUnrecPtr dstProp =
4157 GeoPropertyFactory::the()->create(dstFormat, dstDim,
4158 dstVecType, dstNorm != 0);
4160 // allocate storage
4161 dstProp->resize(offset);
4163 copyVector (dstProp, src1Prop, src1Used, 0 );
4164 copyVectorMapped(dstProp, src2Prop, src2Idx, src2Used, idxMap);
4166 dstGeo->setProperty(dstProp, src2IBag[i].second[j]);
4167 dstGeo->setIndex (dstIdx, src2IBag[i].second[j]);
4172 inline
4173 void mergeGeoMINI(
4174 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
4176 mergeGeoNIMI(dstGeo, srcGeo2, srcGeo1);
4179 /*! Merge geometry \a srcGeo1 and \a srcGeo2 into \a dstGeo, assuming they have
4180 the same set of properties and both are single indexed.
4182 void mergeGeoSISI(
4183 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
4185 FDEBUG(("mergeGeoSISI: srcGeo1 [%p] srcGeo2 [%p]\n",
4186 static_cast<const void *>(srcGeo1),
4187 static_cast<const void *>(srcGeo2)));
4189 // 1. merge types and lengths
4190 mergeGeoTypes (dstGeo, srcGeo1, srcGeo2);
4191 mergeGeoLengths(dstGeo, srcGeo1, srcGeo2);
4193 // 2. merge properties
4195 // find number of _used_ indices in both geometries
4196 UInt32 src1Used = 0;
4197 UInt32 src2Used = 0;
4199 for(UInt32 i = 0; i < srcGeo1->getSFLengths()->getValue()->size(); ++i)
4200 src1Used += srcGeo1->getSFLengths()->getValue()->getValue<UInt32>(i);
4202 for(UInt32 i = 0; i < srcGeo2->getSFLengths()->getValue()->size(); ++i)
4203 src2Used += srcGeo2->getSFLengths()->getValue()->getValue<UInt32>(i);
4205 const GeoIntegralProperty *src1Idx = NULL;
4206 const GeoIntegralProperty *src2Idx = NULL;
4208 for(UInt32 i = 0; i < srcGeo1->getMFPropIndices()->size(); ++i)
4210 if((*srcGeo1->getMFPropIndices())[i] != NULL)
4212 src1Idx = (*srcGeo1->getMFPropIndices())[i];
4213 break;
4217 for(UInt32 i = 0; i < srcGeo2->getMFPropIndices()->size(); ++i)
4219 if((*srcGeo2->getMFPropIndices())[i] != NULL)
4221 src2Idx = (*srcGeo2->getMFPropIndices())[i];
4222 break;
4226 // create new index
4227 UInt32 dstIdxFormat;
4228 calcMergePropertyType(src1Idx, src2Idx, true, dstIdxFormat);
4229 GeoIntegralPropertyUnrecPtr dstIdx =
4230 GeoPropertyFactory::the()->create(dstIdxFormat);
4232 dstIdx->resize(src1Used + src2Used);
4234 // copy index values to destination
4235 IndexMap idxMap1;
4236 IndexMap idxMap2;
4237 UInt32 offset = 0;
4238 copyIndex(dstIdx, src1Idx, src1Used, idxMap1, offset, 0 );
4239 copyIndex(dstIdx, src2Idx, src2Used, idxMap2, offset, src1Used);
4241 // copy each property
4242 UInt32 minPropSz = osgMin(srcGeo1->getMFProperties()->size32(),
4243 srcGeo2->getMFProperties()->size32() );
4245 for(UInt32 i = 0; i < minPropSz; ++i)
4247 const GeoVectorProperty *src1Prop = srcGeo1->getProperty(i);
4248 const GeoVectorProperty *src2Prop = srcGeo2->getProperty(i);
4250 // skip missing properties
4251 if(src1Prop == NULL || src2Prop == NULL)
4252 continue;
4254 UInt32 dstFormat;
4255 UInt32 dstDim;
4256 UInt32 dstVecType;
4257 UInt32 dstNorm;
4259 // create destination property
4260 calcMergePropertyType(src1Prop, src2Prop,
4261 dstFormat, dstDim, dstVecType, dstNorm);
4262 GeoVectorPropertyUnrecPtr dstProp =
4263 GeoPropertyFactory::the()->create(dstFormat, dstDim,
4264 dstVecType, dstNorm != 0);
4266 // allocate storage
4267 dstProp->resize(offset);
4269 // copy property values - only those referenced by an index are copied
4270 // and stored to the new position indicated by idxMap
4271 copyVectorMapped(dstProp, src1Prop, src1Idx, src1Used, idxMap1);
4272 copyVectorMapped(dstProp, src2Prop, src2Idx, src2Used, idxMap2);
4274 dstGeo->setProperty(dstProp, i);
4275 dstGeo->setIndex (dstIdx, i);
4279 /*! Merge geometry \a srcGeo1 and \a srcGeo2 into \a dstGeo, assuming they have
4280 the same set of properties and \a srcGeo1 is single indexed, \a srcGeo2 is
4281 multi indexed. The result \a dstGeo will be multi indexed.
4283 void mergeGeoSIMI(
4284 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
4286 FDEBUG(("mergeGeoSIMI: srcGeo1 [%p] srcGeo2 [%p]\n",
4287 static_cast<const void *>(srcGeo1),
4288 static_cast<const void *>(srcGeo2)));
4290 // 1. merge types and lengths
4291 mergeGeoTypes (dstGeo, srcGeo1, srcGeo2);
4292 mergeGeoLengths(dstGeo, srcGeo1, srcGeo2);
4294 // 2. merge properties
4296 // find number of _used_ indices in both geometries
4297 UInt32 src1Used = 0;
4298 UInt32 src2Used = 0;
4300 for(UInt32 i = 0; i < srcGeo1->getSFLengths()->getValue()->size(); ++i)
4301 src1Used += srcGeo1->getSFLengths()->getValue()->getValue<UInt32>(i);
4303 for(UInt32 i = 0; i < srcGeo2->getSFLengths()->getValue()->size(); ++i)
4304 src2Used += srcGeo2->getSFLengths()->getValue()->getValue<UInt32>(i);
4306 // get indices sorted by the properties they index
4307 Geometry::IndexBag src1IBag = srcGeo1->getUniqueIndexBag();
4308 Geometry::IndexBag src2IBag = srcGeo2->getUniqueIndexBag();
4310 for(UInt32 i = 0; i < src2IBag.size(); ++i)
4312 const GeoIntegralProperty *src1Idx = src1IBag[0].first;
4313 const GeoIntegralProperty *src2Idx = src2IBag[i].first;
4315 // create new index
4316 UInt32 dstIdxFormat;
4317 calcMergePropertyType(src1Idx, src2Idx, true, dstIdxFormat);
4318 GeoIntegralPropertyUnrecPtr dstIdx =
4319 GeoPropertyFactory::the()->create(dstIdxFormat);
4321 // allocate storage
4322 dstIdx->resize(src1Used + src2Used);
4324 // copy index values to destination
4325 IndexMap idxMap1;
4326 IndexMap idxMap2;
4327 UInt32 offset = 0;
4328 copyIndex(dstIdx, src1Idx, src1Used, idxMap1, offset, 0 );
4329 copyIndex(dstIdx, src2Idx, src2Used, idxMap2, offset, src1Used);
4331 // copy properties indexed by this index
4332 for(UInt32 j = 0; j < src2IBag[i].second.size(); ++j)
4334 const GeoVectorProperty *src1Prop =
4335 srcGeo1->getProperty(src2IBag[i].second[j]);
4336 const GeoVectorProperty *src2Prop =
4337 srcGeo2->getProperty(src2IBag[i].second[j]);
4339 FFASSERT(!((src1Prop != NULL) ^ (src2Prop != NULL)), 1,
4340 ("mergeGeoSIMI: Inconsistent properties!");)
4342 if(src1Prop == NULL || src2Prop == NULL)
4343 continue;
4345 UInt32 dstFormat;
4346 UInt32 dstDim;
4347 UInt32 dstVecType;
4348 UInt32 dstNorm;
4350 // create destination property
4351 calcMergePropertyType(src1Prop, src2Prop,
4352 dstFormat, dstDim, dstVecType, dstNorm);
4353 GeoVectorPropertyUnrecPtr dstProp =
4354 GeoPropertyFactory::the()->create(dstFormat, dstDim,
4355 dstVecType, dstNorm != 0);
4357 // allocate storage
4358 dstProp->resize(offset);
4360 copyVectorMapped(dstProp, src1Prop, src1Idx, src1Used, idxMap1);
4361 copyVectorMapped(dstProp, src2Prop, src2Idx, src2Used, idxMap2);
4363 dstGeo->setProperty(dstProp, src2IBag[i].second[j]);
4364 dstGeo->setIndex (dstIdx, src2IBag[i].second[j]);
4369 inline
4370 void mergeGeoMISI(
4371 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
4373 mergeGeoSIMI(dstGeo, srcGeo2, srcGeo1);
4376 /*! Merge geometry \a srcGeo1 and \a srcGeo2 into \a dstGeo, assuming they have
4377 the same set of properties and both are multi indexed.
4379 void mergeGeoMIMI(
4380 Geometry *dstGeo, const Geometry *srcGeo1, const Geometry *srcGeo2)
4382 FDEBUG(("mergeGeoMIMI: srcGeo1 [%p] srcGeo2 [%p]\n",
4383 static_cast<const void *>(srcGeo1),
4384 static_cast<const void *>(srcGeo2)));
4386 // 1. merge types and lengths
4387 mergeGeoTypes (dstGeo, srcGeo1, srcGeo2);
4388 mergeGeoLengths(dstGeo, srcGeo1, srcGeo2);
4390 // 2. merge properties
4392 // find number of _used_ indices in both geometries
4393 UInt32 src1Used = 0;
4394 UInt32 src2Used = 0;
4396 for(UInt32 i = 0; i < srcGeo1->getSFLengths()->getValue()->size(); ++i)
4397 src1Used += srcGeo1->getSFLengths()->getValue()->getValue<UInt32>(i);
4399 for(UInt32 i = 0; i < srcGeo2->getSFLengths()->getValue()->size(); ++i)
4400 src2Used += srcGeo2->getSFLengths()->getValue()->getValue<UInt32>(i);
4402 // get indices sorted by the properties they index
4403 Geometry::IndexBag src1IBag = srcGeo1->getUniqueIndexBag();
4404 Geometry::IndexBag src2IBag = srcGeo2->getUniqueIndexBag();
4406 // Property N may be indexed by different indices in both geometries.
4407 // We build a 2D map (mipMap) that is indexed by i1, i2 and gives the list
4408 // of properties that is indexed by the concatenation of indices
4409 // src1IBag[i1].first and src2IBag[i2].first
4411 typedef std::vector<std::vector< std::vector<UInt32> > > MergedIndexPropMap;
4413 MergedIndexPropMap mipMap;
4414 mipMap.resize(src1IBag.size());
4416 // find indices that index the same property
4417 for(UInt32 i1 = 0; i1 < src1IBag.size(); ++i1)
4419 mipMap[i1].resize(src2IBag.size());
4421 for(UInt32 j1 = 0; j1 < src1IBag[i1].second.size(); ++j1)
4423 for(UInt32 i2 = 0; i2 < src2IBag.size(); ++i2)
4425 for(UInt32 j2 = 0; j2 < src2IBag[i2].second.size(); ++j2)
4427 if(src1IBag[i1].second[j1] == src2IBag[i2].second[j2])
4429 mipMap[i1][i2].push_back(src1IBag[i1].second[j1]);
4436 // iterate over mipMap concatenating corresponding indices and copy
4437 // the indexed properties.
4439 for(UInt32 i1 = 0; i1 < mipMap.size(); ++i1)
4441 for(UInt32 i2 = 0; i2 < mipMap[i1].size(); ++i2)
4443 if(mipMap[i1][i2].empty())
4444 continue;
4446 const GeoIntegralProperty *src1Idx = src1IBag[i1].first;
4447 const GeoIntegralProperty *src2Idx = src2IBag[i2].first;
4449 // create new index
4450 UInt32 dstIdxFormat;
4451 calcMergePropertyType(src1Idx, src2Idx, true, dstIdxFormat);
4452 GeoIntegralPropertyUnrecPtr dstIdx =
4453 GeoPropertyFactory::the()->create(dstIdxFormat);
4455 // allocate storage
4456 dstIdx->resize(src1Used + src2Used);
4458 // copy index values to destination
4459 IndexMap idxMap1;
4460 IndexMap idxMap2;
4461 UInt32 offset = 0;
4462 copyIndex(dstIdx, src1Idx, src1Used, idxMap1, offset, 0 );
4463 copyIndex(dstIdx, src2Idx, src2Used, idxMap2, offset, src1Used);
4465 for(UInt32 j = 0; j < mipMap[i1][i2].size(); ++j)
4467 const GeoVectorProperty *src1Prop =
4468 srcGeo1->getProperty(mipMap[i1][i2][j]);
4469 const GeoVectorProperty *src2Prop =
4470 srcGeo2->getProperty(mipMap[i1][i2][j]);
4472 if(src1Prop == NULL || src2Prop == NULL)
4473 continue;
4475 UInt32 dstFormat;
4476 UInt32 dstDim;
4477 UInt32 dstVecType;
4478 UInt32 dstNorm;
4480 // create destination property
4481 calcMergePropertyType(src1Prop, src2Prop,
4482 dstFormat, dstDim, dstVecType, dstNorm);
4483 GeoVectorPropertyUnrecPtr dstProp =
4484 GeoPropertyFactory::the()->create(dstFormat, dstDim,
4485 dstVecType, dstNorm != 0);
4487 // allocate storage
4488 dstProp->resize(offset);
4490 copyVectorMapped(dstProp, src1Prop, src1Idx, src1Used, idxMap1);
4491 copyVectorMapped(dstProp, src2Prop, src2Idx, src2Used, idxMap2);
4493 dstGeo->setProperty(dstProp, mipMap[i1][i2][j]);
4494 dstGeo->setIndex (dstIdx, mipMap[i1][i2][j]);
4500 } // namespace
4503 /*! Returns whether the two geometries \a geo1 and \a geo2 can be merged, based
4504 on the properties and indexing they use.
4505 Geometries are mergeable if they have the same set of properties.
4507 \warning Materials are not considered in this function!
4509 \ingroup GrpDrawablesGeometryUtils
4511 bool mergeableGeo(const Geometry *geo1, const Geometry *geo2)
4513 if(geo1->getTypes() == NULL || geo2->getTypes() == NULL)
4515 SWARNING << "mergeableGeo: Geometry without types, can not merge."
4516 << std::endl;
4518 return false;
4521 if(geo1->getLengths() == NULL || geo2->getLengths() == NULL)
4523 SWARNING << "mergeableGeo: Geometry without lengths, can not merge."
4524 << std::endl;
4526 return false;
4529 const Geometry::MFPropertiesType &prop1 = *(geo1->getMFProperties());
4530 const Geometry::MFPropertiesType &prop2 = *(geo2->getMFProperties());
4532 // number of properties may differ, but additional entries must be NULL.
4533 // first compare common entries
4534 UInt32 minSize = osgMin(prop1.size32(), prop2.size32());
4535 UInt32 maxSize = osgMax(prop1.size32(), prop2.size32());
4536 UInt32 i;
4538 // common entries must either be both present or both absent
4539 for(i = 0; i < minSize; ++i)
4541 if((prop1[i] != NULL) ^ (prop2[i] != NULL))
4542 return false;
4545 // additional entries must be NULL
4546 for(; i < maxSize; ++i)
4548 if(i < prop1.size() && prop1[i] != NULL)
4549 return false;
4551 if(i < prop2.size() && prop2[i] != NULL)
4552 return false;
4555 // geometries have the same properties, now check indexing
4557 UInt32 szIBag1 = UInt32(geo1->getUniqueIndexBag().size());
4558 UInt32 szIBag2 = UInt32(geo2->getUniqueIndexBag().size());
4560 if(szIBag1 == 0 && szIBag2 == 0)
4562 // no index + no index -> no index
4563 return true;
4565 else if(szIBag1 == 1 && szIBag2 == 1)
4567 // single + single -> single
4568 return true;
4570 else if(szIBag1 > 1 && szIBag2 > 1)
4572 // multi + multi -> multi
4573 return true;
4575 else if(szIBag1 == 0 && szIBag2 == 1)
4577 // no index + single -> single
4578 return true;
4580 else if(szIBag1 == 1 && szIBag2 == 0)
4582 // single + no index -> single
4583 return true;
4585 else if(szIBag1 > 1 && szIBag2 == 0)
4587 // multi + no index -> multi
4588 return true;
4590 else if(szIBag1 == 0 && szIBag2 > 1)
4592 // no index + multi -> multi
4593 return true;
4595 else if(szIBag1 == 1 && szIBag2 > 1)
4597 // single + multi -> multi
4598 return true;
4600 else if(szIBag1 > 1 && szIBag2 == 1)
4602 // multi + single -> multi
4603 return true;
4606 // should not happen
4607 FWARNING(
4608 ("mergeableGeo: Unrecognized indexing. Geometry may be invalid.\n"));
4610 return false;
4613 /*! Attempts to merge \a geo1 and \a geo2 and returns the merged geometry or a
4614 NULL pointer if merging is not possible.
4616 \warning Materials are not considered in this function!
4618 \ingroup GrpDrawablesGeometryUtils
4620 GeometryTransitPtr mergeGeo(const Geometry *geo1, const Geometry *geo2)
4622 GeometryUnrecPtr returnValue;
4624 if(geo1->getTypes() == NULL || geo2->getTypes() == NULL)
4626 SWARNING << "mergeGeo: Geometry without types, can not merge."
4627 << std::endl;
4629 return GeometryTransitPtr();
4632 if(geo1->getLengths() == NULL || geo2->getLengths() == NULL)
4634 SWARNING << "mergeGeo: Geometry without lengths, can not merge."
4635 << std::endl;
4637 return GeometryTransitPtr();
4640 const Geometry::MFPropertiesType &prop1 = *(geo1->getMFProperties());
4641 const Geometry::MFPropertiesType &prop2 = *(geo2->getMFProperties());
4643 // number of properties may differ, but additional entries must be NULL.
4644 // first compare common entries
4645 UInt32 minSize = osgMin(prop1.size32(), prop2.size32());
4646 UInt32 maxSize = osgMax(prop1.size32(), prop2.size32());
4647 UInt32 i;
4649 // common entries must either be both present or both absent
4650 for(i = 0; i < minSize; ++i)
4652 if((prop1[i] != NULL) ^ (prop2[i] != NULL))
4654 FWARNING(("mergeGeo: Geometries have different properties, "
4655 "can not merge.\n"));
4657 return GeometryTransitPtr();
4661 // additional entries must be NULL
4662 for(; i < maxSize; ++i)
4664 if(i < prop1.size() && prop1[i] != NULL)
4666 FWARNING(("mergeGeo: Geometries have different properties, "
4667 "can not merge.\n"));
4669 return GeometryTransitPtr();
4672 if(i < prop2.size() && prop2[i] != NULL)
4674 FWARNING(("mergeGeo: Geometries have different properties, "
4675 "can not merge.\n"));
4677 return GeometryTransitPtr();
4681 // geometries have the same properties, now check indexing
4683 UInt32 szIBag1 = UInt32(geo1->getUniqueIndexBag().size());
4684 UInt32 szIBag2 = UInt32(geo2->getUniqueIndexBag().size());
4686 if(szIBag1 == 0 && szIBag2 == 0)
4688 // no index + no index -> no index
4689 returnValue = Geometry::create();
4690 mergeGeoNINI(returnValue, geo1, geo2);
4692 else if(szIBag1 == 1 && szIBag2 == 1)
4694 // single + single -> single
4695 returnValue = Geometry::create();
4696 mergeGeoSISI(returnValue, geo1, geo2);
4698 else if(szIBag1 > 1 && szIBag2 > 1)
4700 // multi + multi -> multi
4701 returnValue = Geometry::create();
4702 mergeGeoMIMI(returnValue, geo1, geo2);
4704 else if(szIBag1 == 0 && szIBag2 == 1)
4706 // no index + single -> single
4707 returnValue = Geometry::create();
4708 mergeGeoNISI(returnValue, geo1, geo2);
4710 else if(szIBag1 == 1 && szIBag2 == 0)
4712 // single + no index -> single
4713 returnValue = Geometry::create();
4714 mergeGeoSINI(returnValue, geo1, geo2);
4716 else if(szIBag1 > 1 && szIBag2 == 0)
4718 // multi + no index -> multi
4719 returnValue = Geometry::create();
4720 mergeGeoMINI(returnValue, geo1, geo2);
4722 else if(szIBag1 == 0 && szIBag2 > 1)
4724 // no index + multi -> multi
4725 returnValue = Geometry::create();
4726 mergeGeoNIMI(returnValue, geo1, geo2);
4728 else if(szIBag1 == 1 && szIBag2 > 1)
4730 // single + multi -> multi
4731 returnValue = Geometry::create();
4732 mergeGeoSIMI(returnValue, geo1, geo2);
4734 else if(szIBag1 > 1 && szIBag2 == 1)
4736 // multi + single -> multi
4737 returnValue = Geometry::create();
4738 mergeGeoMISI(returnValue, geo1, geo2);
4741 return GeometryTransitPtr(returnValue);
4744 /*! \ingroup GrpDrawablesGeometryUtils
4747 void setVBOUsageOnPropertyProtos(bool bVal)
4749 DerivedFieldContainerTypeIterator dtIt =
4750 FieldContainerFactory::the()->begin(GeoProperty::getClassType());
4752 DerivedFieldContainerTypeIterator dtEnd =
4753 FieldContainerFactory::the()->end();
4755 while(dtIt != dtEnd)
4757 FieldContainer *pProto = dtIt->getPrototype();
4759 if(pProto != NULL)
4761 GeoProperty *pProp = dynamic_cast<GeoProperty *>(pProto);
4763 OSG_ASSERT(pProp != NULL);
4765 pProp->setUseVBO(bVal);
4769 ++dtIt;
4773 OSG_END_NAMESPACE