static void mergeBones( BoneList &a, BoneList& b ) { for (size_t i=0; i<b.size(); ++i) { int c = b[i]; BoneList::iterator it = find(a.begin(), a.end(), c); if ( a.end() == it ) { a.push_back( c ); } } }
static bool containsBones( BoneList& a, BoneList& b ) { for (size_t i=0; i<b.size(); ++i) { int c = b[i]; BoneList::iterator it = find(a.begin(), a.end(), c); if ( a.end() == it ) { return false; } } return true; }
void ColoredPolygon::BindToBone(BoneAnimated *bone) { BoneList bones; bones.push_back(bone); bone->GetBoneList(bones); for (uint j = 0; j < bones.size(); ++j) { bones[j]->FixMatrix(); } float signSq = Math::SignedSquare(_dots); std::vector<uint> skipped; for (uint i = 0; i < _dots.size(); ++i) { FPoint &a = _dots[(i + _dots.size() - 1) % _dots.size()].pos; FPoint &b = _dots[i].pos; FPoint &c = _dots[(i + 1) % _dots.size()].pos; std::vector<std::pair<BoneAnimated *, float> > boneDistance; for (uint j = 0; j < bones.size(); ++j) { BoneAnimated *d = bones[j]; FPoint s(0, 0); FPoint e(d->GetLength(), 0); d->GetMatrix().Mul(s); d->GetMatrix().Mul(e); FPoint center = 0.5f * (s + e); if (Math::VMul(a - center, b - center) * signSq >= 0.f || Math::VMul(b - center, c - center) * signSq >= 0.f) { if ((d->GetParent() == NULL && (s - b).Length() < d->GetLength() / 2) || (!d->HasChild() && (e - b).Length() < d->GetLength() / 2)) { boneDistance.push_back( std::make_pair<BoneAnimated *, float> (d, 0.f) ); } else { boneDistance.push_back(std::make_pair<BoneAnimated *, float>(d, Math::Distance(s, e, b) ) ); } } } if (boneDistance.size() == 1) { _dots[i].p[0].boneName = boneDistance.back().first->GetName(); _dots[i].p[0].bone = boneDistance.back().first; _dots[i].p[0].mass = 1.f; _dots[i].p[1].boneName = ""; _dots[i].p[1].bone = NULL; _dots[i].p[1].mass = 0.f; } else if (boneDistance.size() >= 2) { std::sort(boneDistance.begin(), boneDistance.end(), CmpBoneDistance); float m = boneDistance[0].second + boneDistance[1].second; _dots[i].p[0].boneName = boneDistance[0].first->GetName(); _dots[i].p[0].bone = boneDistance[0].first; _dots[i].p[0].mass = boneDistance[1].second / m; _dots[i].p[1].boneName = boneDistance[1].first->GetName(); _dots[i].p[1].bone = boneDistance[1].first; _dots[i].p[1].mass = boneDistance[0].second / m; } else { skipped.push_back(i); } } if (skipped.size()) { assert(false);// fail } }
void ColoredPolygon::DebugDraw(bool onlyControl) { if (!onlyControl) { Draw(); } _debugDraw = true; Render::SetFiltering(false); Render::PushMatrix(); for (unsigned int i = 0; i < _triangles.GetVB().SizeIndex(); i += 3) { Render::Line(_triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 0)).x, _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 0)).y , _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 1)).x, _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 1)).y, 0x4FFFFFFF); Render::Line(_triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 2)).x, _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 2)).y , _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 1)).x, _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 1)).y, 0x4FFFFFFF); Render::Line(_triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 0)).x, _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 0)).y , _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 2)).x, _triangles.GetVB().VertXY(_triangles.GetVB().Index(i + 2)).y, 0x4FFFFFFF); } //parent = Render::GetCurrentMatrix(); for (unsigned int i = 0; i < _dots.size(); ++i) { Render::Line(_dots[i].pos.x, _dots[i].pos.y, _dots[(i + 1) % _dots.size()].pos.x, _dots[(i + 1) % _dots.size()].pos.y, 0xFFFFFFFF); } Render::SetMatrixUnit(); float alpha = (Render::GetColor() >> 24) / 255.f; Render::SetAlpha(Math::round(0xAF * alpha)); std::set<int> drawBig; for (unsigned int i = 0; i < _dotUnderCursor.size(); ++i) { drawBig.insert(_dotUnderCursor[i]); } for (unsigned int i = 0; i < _selectedDots.size(); ++i) { drawBig.insert(_selectedDots[i]); } for (unsigned int i = 0; i < _screenDots.size(); ++i) { if (drawBig.end() != drawBig.find(i)) { scale->Render(_screenDots[i].x - scale->Width() / 2.f, _screenDots[i].y - scale->Height() / 2.f); } else { scaleSide->Render(_screenDots[i].x - scaleSide->Width() / 2.f, _screenDots[i].y - scaleSide->Height() / 2.f); } } Render::SetAlpha(Math::round(0xFF * alpha)); Render::PopMatrix(); // Render::SetFiltering(TileEditorInterface::Instance()->FilteringTexture()); if (!Animation::Instance()->GetDebugBone()) return; BoneList bones; bones.push_back(Animation::Instance()->GetDebugBone()); Animation::Instance()->GetDebugBone()->GetBoneList(bones); float signSq = Math::SignedSquare(_dots); for (unsigned int j = 0; j < _selectedDots.size(); ++j) { uint i = _selectedDots[j]; FPoint &a = _dots[(i + _dots.size() - 1) % _dots.size()].pos; FPoint &b = _dots[i].pos; FPoint &c = _dots[(i + 1) % _dots.size()].pos; std::vector<std::pair<BoneAnimated *, float> > boneDistance; for (uint j = 0; j < bones.size(); ++j) { BoneAnimated *d = bones[j]; FPoint s(0, 0); FPoint e(d->GetLength(), 0); d->GetMatrix().Mul(s); d->GetMatrix().Mul(e); FPoint center = 0.5f * (s + e); if (Math::VMul(a - center, b - center) * signSq >= 0.f || Math::VMul(b - center, c - center) * signSq >= 0.f) { if ((d->GetParent() == NULL && (s - b).Length() < d->GetLength() / 2) || (!d->HasChild() && (e - b).Length() < d->GetLength() / 2)) { boneDistance.push_back( std::make_pair<BoneAnimated *, float> (d, 0.f) ); } else { boneDistance.push_back(std::make_pair<BoneAnimated *, float>(d, Math::Distance(s, e, b) ) ); } } } std::sort(boneDistance.begin(), boneDistance.end(), CmpBoneDistance); for (uint i = 0; i < std::min((size_t)2, boneDistance.size()); ++i) { boneDistance[i].first->DrawRed(); } } }
ValueNode_Bone::BoneList ValueNode_Bone::get_ordered_bones(etl::handle<const Canvas> canvas) { std::multimap<ValueNode_Bone::Handle, ValueNode_Bone::Handle> uses; std::multimap<ValueNode_Bone::Handle, ValueNode_Bone::Handle> is_used_by; BoneList current_list; { BoneMap bone_map(canvas_map[canvas]); for(BoneMap::const_iterator iter=bone_map.begin();iter!=bone_map.end();++iter) { ValueNode_Bone::Handle user(iter->second); BoneSet ref(get_bones_referenced_by(user, false)); if (ref.empty()) { if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("%s:%d %s doesn't need anybody\n", __FILE__, __LINE__, user->get_bone_name(0).c_str()); current_list.push_back(user); } else for(BoneSet::iterator iter=ref.begin();iter!=ref.end();++iter) { ValueNode_Bone::Handle used(*iter); if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("%s:%d %s is used by %s\n", __FILE__, __LINE__, used->get_bone_name(0).c_str(), user->get_bone_name(0).c_str()); is_used_by.insert(make_pair(used, user)); uses.insert(make_pair(user, used)); } } } BoneList ret; BoneSet seen; BoneList new_list; while (current_list.size()) { if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("%s:%d current_list has %zd members; we have %zd in is_used_by and %zd in uses\n", __FILE__, __LINE__, current_list.size(), is_used_by.size(), uses.size()); for(BoneList::iterator iter=current_list.begin();iter!=current_list.end();++iter) { ValueNode_Bone::Handle bone(*iter); if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("%s:%d bone: %s\n", __FILE__, __LINE__, bone->get_bone_name(0).c_str()); ret.push_back(bone); std::multimap<ValueNode_Bone::Handle, ValueNode_Bone::Handle>::iterator begin(is_used_by.lower_bound(bone)); std::multimap<ValueNode_Bone::Handle, ValueNode_Bone::Handle>::iterator end(is_used_by.upper_bound(bone)); for (std::multimap<ValueNode_Bone::Handle, ValueNode_Bone::Handle>::iterator iter = begin; iter != end; iter++) { ValueNode_Bone::Handle user(iter->second); if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("\t\t\t%s:%d user: %s\n", __FILE__, __LINE__, user->get_bone_name(0).c_str()); // erase (user,bone) from uses if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("%s:%d trying to erase - searching %zd\n", __FILE__, __LINE__, uses.count(user)); std::multimap<ValueNode_Bone::Handle, ValueNode_Bone::Handle>::iterator begin2(uses.lower_bound(user)); std::multimap<ValueNode_Bone::Handle, ValueNode_Bone::Handle>::iterator end2(uses.upper_bound(user)); std::multimap<ValueNode_Bone::Handle, ValueNode_Bone::Handle>::iterator iter2; for (iter2 = begin2; iter2 != end2; iter2++) { if (iter2->second == bone) { uses.erase(iter2); if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("%s:%d found it\n", __FILE__, __LINE__); break; } else { if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("no\n"); } } if (iter2 == end2) { if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("%s:%d didn't find it?!?\n", __FILE__, __LINE__); assert(0); } if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("%s:%d now there are %zd\n", __FILE__, __LINE__, uses.count(user)); if (uses.count(user) == 0) { if (getenv("SYNFIG_DEBUG_ORDER_BONES_FOR_SAVE_CANVAS")) printf("\t\t\t%s:%d adding %s\n", __FILE__, __LINE__, user->get_bone_name(0).c_str()); new_list.push_back(user); } } } current_list = new_list; new_list.clear(); } assert(uses.empty()); return ret; }
NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape, int maxBonesPerPartition, int maxBonesPerVertex ) { NiSkinInstanceRef skinInst = shape->GetSkinInstance(); if ( skinInst == NULL ) { throw runtime_error( "You must bind a skin before setting generating skin partitions. No NiSkinInstance found." ); } NiSkinDataRef skinData = skinInst->GetSkinData(); if ( skinData == NULL ) { throw runtime_error( "You must bind a skin before setting generating skin partitions. No NiSkinData found." ); } NiTriBasedGeomDataRef geomData = DynamicCast<NiTriBasedGeomData>(shape->GetData() ); if ( geomData == NULL ) { throw runtime_error( "Attempted to generate a skin partition on a mesh with no geometry data." ); } // read in the weights from NiSkinData vector<Vector3> verts = geomData->GetVertices(); vector< BoneWeightList > weights; if (verts.empty()){ throw runtime_error( "Attempted to generate a skin partition on a mesh with no vertices." ); } Triangles triangles = geomData->GetTriangles(); if (triangles.empty()) { throw runtime_error( "Attempted to generate a skin partition on a mesh with no triangles." ); } weights.resize( verts.size() ); int numBones = skinData->GetBoneCount(); for ( int bone = 0; bone < numBones; bone++ ) { vector<SkinWeight> vertexWeights = skinData->GetBoneWeights(bone); for (int r = 0; r < int(vertexWeights.size()); ++r ){ int vertex = vertexWeights[r].index; float weight = vertexWeights[r].weight; if ( vertex >= int(weights.size()) ) throw runtime_error( "bad NiSkinData - vertex count does not match" ); weights[vertex].insert( weights[vertex].end(), BoneWeight(bone, weight) ); } } // count min and max bones per vertex int minBones, maxBones; minBones = maxBones = weights[0].size(); for(vector< BoneWeightList >::iterator itr = weights.begin(); itr != weights.end(); ++itr ){ int n = (*itr).size(); minBones = min(n, minBones); maxBones = max(n, maxBones); } if ( minBones <= 0 ) throw runtime_error( "bad NiSkinData - some vertices have no weights at all" ); // reduce vertex influences if necessary if ( maxBones > maxBonesPerVertex ) { int c = 0; for ( vector< BoneWeightList >::iterator it = weights.begin(); it != weights.end(); ++it ) { BoneWeightList & lst = *it; if ( int(lst.size()) > maxBonesPerVertex ) c++; while ( int(lst.size()) > maxBonesPerVertex ) { int j = 0; float weight = lst.front().second; for ( int i = 0; i < int(lst.size()); i++ ) { if ( lst[i].second < weight ) j = i; } BoneWeightList::iterator jit = lst.begin() + j; lst.erase( jit ); } float totalWeight = 0; for (BoneWeightList::iterator bw = lst.begin(); bw != lst.end(); ++bw) { totalWeight += (*bw).second; } for (BoneWeightList::iterator bw = lst.begin(); bw != lst.end(); ++bw) { (*bw).second /= totalWeight; } } //qWarning() << "reduced" << c << "vertices to" << maxBonesPerVertex << "bone influences (maximum number of bones per vertex was" << maxBones << ")"; } maxBones = maxBonesPerVertex; // reduces bone weights so that the triangles fit into the partitions typedef multimap<int,int> matchmap; typedef pair<matchmap::iterator, matchmap::iterator> matchrange; matchmap match; bool doMatch = true; BoneList tribones; int cnt = 0; for (Triangles::iterator itr = triangles.begin(); itr != triangles.end(); ++itr) { Triangle& tri = (*itr); do { tribones.clear(); for ( int c = 0; c < 3; c++ ) { BoneWeightList& bwl = weights[tri[c]]; for (BoneWeightList::iterator bw = bwl.begin(); bw != bwl.end(); ++bw) { if ( tribones.end() == find(tribones.begin(), tribones.end(), (*bw).first ) ) tribones.insert(tribones.end(), (*bw).first ); } } if ( int(tribones.size()) > maxBonesPerPartition ) { // sum up the weights for each bone // bones with weight == 1 can't be removed map<int, float> sum; vector<int> nono; for ( int t = 0; t < 3; t++ ) { BoneWeightList& bwl = weights[tri[t]]; if ( bwl.size() == 1 ) nono.insert(nono.end(), bwl.front().first ); for (BoneWeightList::iterator bw = bwl.begin(); bw != bwl.end(); ++bw) { sum[ (*bw).first ] += (*bw).second; } } // select the bone to remove float minWeight = 5.0; int minBone = -1; for (map<int, float>::iterator sitr = sum.begin(); sitr != sum.end(); ++sitr) { int b = (*sitr).first; if ( (find(nono.begin(), nono.end(), b) == nono.end()) && sum[b] < minWeight) { minWeight = sum[b]; minBone = b; } } if ( minBone < 0 ) // this shouldn't never happen throw runtime_error( "internal error 0x01" ); // do a vertex match detect if ( doMatch ) { for ( size_t a = 0; a < verts.size(); a++ ) { match.insert(matchmap::value_type(a, a)); for ( size_t b = a + 1; b < verts.size(); b++ ) { if ( verts[a] == verts[b] && weights[a] == weights[b] ) { match.insert(matchmap::value_type(a, b)); match.insert(matchmap::value_type(b, a)); } } } } // now remove that bone from all vertices of this triangle and from all matching vertices too for ( int t = 0; t < 3; t++ ) { bool rem = false; matchrange range = match.equal_range(tri[t]); for (matchmap::iterator itr = range.first; itr != range.second; ++itr) { int v = (*itr).second; BoneWeightList & bws = weights[ v ]; BoneWeightList::iterator it = bws.begin(); while ( it != bws.end() ) { BoneWeight & bw = *it; if ( bw.first == minBone ) { it = bws.erase(it); rem = true; } else { ++it; } } float totalWeight = 0; for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) { totalWeight += (*bw).second; } if ( totalWeight == 0 ) throw runtime_error( "internal error 0x02" ); // normalize for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) { (*bw).second /= totalWeight; } } if ( rem ) cnt++; } } } while ( int(tribones.size()) > maxBonesPerPartition ); } //if ( cnt > 0 ) // qWarning() << "removed" << cnt << "bone influences"; PartitionList& parts = skinPartitionBlocks; // split the triangles into partitions while ( ! triangles.empty() ) { SkinPartition part; Triangles::iterator it = triangles.begin(); while ( it != triangles.end() ) { Triangle & tri = *it; BoneList tribones; for ( int c = 0; c < 3; c++ ) { BoneWeightList& bws = weights[tri[c]]; for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) { if ( tribones.end() == find(tribones.begin(), tribones.end(), (*bw).first ) ) tribones.push_back( (*bw).first ); } } if ( part.bones.empty() || containsBones( part.bones, tribones ) ) { mergeBones( part.bones, tribones ); part.triangles.push_back( tri ); it = triangles.erase(it); } else { ++it; } } parts.push_back( part ); } //qWarning() << parts.size() << "small partitions"; // merge partitions bool merged; do { merged = false; // Working backwards through this list minimizes numbers of swaps //for ( int p2 = int(parts.size()-1); p2 >= 0 && ! merged; --p2 ) //{ // Partition& part2 = parts[p2]; // for ( int p1 = int(p2-1); p1 >= 0 && ! merged; --p1 ) // { // Partition& part1 = parts[p1]; for ( int p1 = 0; p1 < int(parts.size()) && ! merged; p1++ ) { Partition& part1 = parts[p1]; for ( int p2 = p1+1; p2 < int(parts.size()) && ! merged; p2++ ) { Partition& part2 = parts[p2]; BoneList mergedBones = part1.bones; mergeBones( mergedBones, part2.bones ); if ( int(mergedBones.size()) <= maxBonesPerPartition ) { PartitionList::iterator p2i = parts.begin() + p2; part1.bones = mergedBones; part1.triangles.insert(part1.triangles.end(), (*p2i).triangles.begin(), (*p2i).triangles.end()); parts.erase(p2i); merged = true; } } } } while ( merged ); //qWarning() << parts.size() << "partitions"; // start writing NiSkinPartition for ( int p = 0; p < int(parts.size()); p++ ) { Partition& part = parts[p]; BoneList& bones = part.bones; sort( bones.begin(), bones.end() ); Triangles& triangles = part.triangles; vector<unsigned short>& vertices = part.vertexMap; for( Triangles::iterator tri = triangles.begin(); tri != triangles.end(); ++tri) { for ( int t = 0; t < 3; t++ ) { if ( vertices.end() == find(vertices.begin(), vertices.end(), (*tri)[t] ) ) vertices.push_back( (*tri)[t] ); } } sort( vertices.begin(), vertices.end() ); part.numVertices = vertices.size(); part.hasVertexMap = true; // map the vertices for ( int tri = 0; tri < int(triangles.size()); tri++ ) { for ( int t = 0; t < 3; t++ ) { triangles[tri][t] = indexOf(vertices.begin(), vertices.end(), triangles[tri][t]); } } SetWeightsPerVertex(p, maxBones); EnableVertexWeights(p, true); EnableVertexBoneIndices(p, true); // strippify the triangles NiTriStripsDataRef data = new NiTriStripsData(triangles, true); int nstrips = data->GetStripCount(); SetStripCount( p, nstrips ); for ( int i=0; i<nstrips; ++i ) { SetStrip(p, i, data->GetStrip(i)); } //// Special case for pre-stripped data //unsigned short *data = new unsigned short[triangles.size() * 3 * 2]; //for (size_t i=0; i< triangles.size(); i++) { // data[i * 3 + 0] = triangles[i][0]; // data[i * 3 + 1] = triangles[i][1]; // data[i * 3 + 2] = triangles[i][2]; //} //PrimitiveGroup * groups = 0; //unsigned short numGroups = 0; //// GF 3+ //SetCacheSize(CACHESIZE_GEFORCE3); //// don't generate hundreds of strips //SetStitchStrips(true); //GenerateStrips(data, triangles.size()*3, &groups, &numGroups); //delete [] data; //if (groups) { // SetStripCount(p, numGroups); // for (int g=0; g<numGroups; g++) { // if (groups[g].type == PT_STRIP) { // vector<Niflib::unsigned short> strip(groups[g].numIndices); // for (size_t s=0; s<groups[g].numIndices; s++) // strip[s] = groups[g].indices[s]; // SetStrip(p, g, strip); // } // } // delete [] groups; //} // fill in vertex weights and bones for (size_t v = 0; v < vertices.size(); ++v) { BoneWeightList& bwl = weights[vertices[v]]; for ( int b = 0; b < maxBones; b++ ) { part.boneIndices[v][b] = (int(bwl.size()) > b) ? indexOf(bones.begin(), bones.end(), bwl[b].first) : 0 ; part.vertexWeights[v][b] = (int(bwl.size()) > b ? bwl[b].second : 0.0f); } } } }
NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape) { NiSkinInstanceRef skinInst = shape->GetSkinInstance(); if ( skinInst == NULL ) { throw runtime_error( "You must bind a skin before setting generating skin partitions. No NiSkinInstance found." ); } NiSkinDataRef skinData = skinInst->GetSkinData(); if ( skinData == NULL ) { throw runtime_error( "You must bind a skin before setting generating skin partitions. No NiSkinData found." ); } NiTriBasedGeomDataRef geomData = DynamicCast<NiTriBasedGeomData>( shape->GetData() ); if ( geomData == NULL ) { throw runtime_error( "Attempted to generate a skin partition on a mesh with no geometry data." ); } int nWeightsPerVertex = 4; vector<WeightList> vertexWeights; BoneList boneMap; vector<unsigned short> vertexMap; Strips strips; vector<BoneList> boneIndexList; Triangles triangles; int totalBones = skinInst->GetBoneCount(); boneMap.resize(totalBones); int nv = geomData->GetVertexCount(); vertexMap.resize(nv); vertexWeights.resize(nv); boneIndexList.resize(nv); for (int i=0; i<totalBones; ++i) { boneMap[i] = i; vector<SkinWeight> skinWeights = skinData->GetBoneWeights(i); for (vector<SkinWeight>::const_iterator skinWeight = skinWeights.begin(); skinWeight != skinWeights.end(); ++skinWeight) { WeightList& vertexWeight = vertexWeights[skinWeight->index]; BoneList& boneIndex = boneIndexList[skinWeight->index]; vertexWeight.push_back(skinWeight->weight); boneIndex.push_back(i); // Adjust upper limit on number of weights per vertex if necessary. int nWeights = vertexWeight.size(); if (nWeights > nWeightsPerVertex) nWeightsPerVertex = nWeights; } } if (nWeightsPerVertex == 0) { throw runtime_error( "Attempted to generate a skin partition on a mesh with no weights specified." ); } for (int i=0; i<nv; ++i) { vertexMap[i] = i; WeightList& vertexWeight = vertexWeights[i]; BoneList& boneIndex = boneIndexList[i]; vertexWeight.reserve(nWeightsPerVertex); boneIndex.reserve(nWeightsPerVertex); for (int j = nWeightsPerVertex - vertexWeight.size(); j>0; --j) { vertexWeight.push_back(0.0f); boneIndex.push_back(0); } } SetNumPartitions(1); SetWeightsPerVertex(0, nWeightsPerVertex); SetBoneMap(0, boneMap); SetNumVertices(0, (unsigned short)(vertexMap.size()) ); SetVertexMap(0, vertexMap); EnableVertexWeights(0, true); EnableVertexBoneIndices(0, true); for (int i=0; i<nv; ++i) { SetVertexWeights(0, i, vertexWeights[i]); SetVertexBoneIndices(0, i, boneIndexList[i]); } // Special case for pre-stripped data if (NiTriStripsDataRef stripData = DynamicCast<NiTriStripsData>(geomData)) { unsigned short nstrips = stripData->GetStripCount(); SetStripCount(0, nstrips); for (int i=0; i<int(nstrips); ++i) { SetStrip(0, i, stripData->GetStrip(i)); } } else { Triangles triangles = geomData->GetTriangles(); SetTriangles(0, triangles); unsigned short *data = new unsigned short[triangles.size() * 3 * 2]; for (size_t i=0; i< triangles.size(); i++) { data[i * 3 + 0] = triangles[i][0]; data[i * 3 + 1] = triangles[i][1]; data[i * 3 + 2] = triangles[i][2]; } PrimitiveGroup * groups = 0; unsigned short numGroups = 0; // GF 3+ SetCacheSize(CACHESIZE_GEFORCE3); // don't generate hundreds of strips SetStitchStrips(true); GenerateStrips(data, triangles.size()*3, &groups, &numGroups); delete [] data; if (groups) { SetStripCount(0, numGroups); for (int g=0; g<numGroups; g++) { if (groups[g].type == PT_STRIP) { vector<unsigned short> strip(groups[g].numIndices); for ( unsigned int s = 0; s<groups[g].numIndices; s++ ) strip[s] = groups[g].indices[s]; SetStrip(0, g, strip); } } delete [] groups; } } }