/////////////////////////////////////////////////////////////////////////////////////////// // Combine() // // Combines the two input face vectors and puts the result into m_faces // void NvStripInfo::Combine(const NvFaceInfoVec &forward, const NvFaceInfoVec &backward){ // add backward faces int numFaces = backward.size(); for (int i = numFaces - 1; i >= 0; i--) m_faces.push_back(backward[i]); // add forward faces numFaces = forward.size(); for (int i = 0; i < numFaces; i++) m_faces.push_back(forward[i]); }
/////////////////////////////////////////////////////////////////////////////////////////// // FindStartPoint() // // Finds a good starting point, namely one which has only one neighbor // int NvStripifier::FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos) { int bestCtr = -1; int bestIndex = -1; for(size_t i = 0; i < faceInfos.size(); i++) { int ctr = 0; if(FindOtherFace(edgeInfos, faceInfos[i]->m_v0, faceInfos[i]->m_v1, faceInfos[i]) == NULL) ctr++; if(FindOtherFace(edgeInfos, faceInfos[i]->m_v1, faceInfos[i]->m_v2, faceInfos[i]) == NULL) ctr++; if(FindOtherFace(edgeInfos, faceInfos[i]->m_v2, faceInfos[i]->m_v0, faceInfos[i]) == NULL) ctr++; if(ctr > bestCtr) { bestCtr = ctr; bestIndex = i; //return i; } } //return -1; if(bestCtr == 0) return -1; else return bestIndex; }
//////////////////////////////////////////////////////////////////////////////////////// // RemoveSmallStrips() // // allStrips is the whole strip _vector_...all small strips will be deleted from this list, to avoid leaking mem // allBigStrips is an out parameter which will contain all strips above minStripLength // faceList is an out parameter which will contain all faces which were removed from the striplist // void NvStripifier::RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList) { faceList.clear(); allBigStrips.clear(); //make sure these are empty NvFaceInfoVec tempFaceList; for(int i = 0; i < allStrips.size(); i++) { if(allStrips[i]->m_faces.size() < minStripLength) { //strip is too small, add faces to faceList for(int j = 0; j < allStrips[i]->m_faces.size(); j++) tempFaceList.push_back(allStrips[i]->m_faces[j]); //and xr_free memory xr_delete(allStrips[i]); } else { allBigStrips.push_back(allStrips[i]); } } bool *bVisitedList = xr_alloc<bool> (tempFaceList.size()); ZeroMemory (bVisitedList, tempFaceList.size()*sizeof(bool)); VertexCache* vcache = xr_new<VertexCache> (cacheSize); int bestNumHits = -1; int numHits = 0; int bestIndex = 0; while(1) { bestNumHits = -1; //find best face to add next, given the current cache for(int i = 0; i < tempFaceList.size(); i++) { if(bVisitedList[i]) continue; numHits = CalcNumHitsFace(vcache, tempFaceList[i]); if(numHits > bestNumHits) { bestNumHits = numHits; bestIndex = i; } } if(bestNumHits == -1.0f) break; bVisitedList[bestIndex] = true; UpdateCacheFace(vcache, tempFaceList[bestIndex]); faceList.push_back(tempFaceList[bestIndex]); } xr_delete (vcache); xr_free (bVisitedList); }
bool NvStripifier::AlreadyExists(NvFaceInfo* faceInfo, NvFaceInfoVec& faceInfos) { for(size_t i = 0; i < faceInfos.size(); ++i) { if( (faceInfos[i]->m_v0 == faceInfo->m_v0) && (faceInfos[i]->m_v1 == faceInfo->m_v1) && (faceInfos[i]->m_v2 == faceInfo->m_v2) ) return true; } return false; }
/////////////////////////////////////////////////////////////////////////////////////////// // FindStartPoint() // // Finds a good starting point, namely one which has only one neighbor // int NvStripifier::FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos) { for(int i = 0; i < faceInfos.size(); i++) { int ctr = 0; if(FindOtherFace(edgeInfos, faceInfos[i]->m_v0, faceInfos[i]->m_v1, faceInfos[i]) == NULL) ctr++; if(FindOtherFace(edgeInfos, faceInfos[i]->m_v1, faceInfos[i]->m_v2, faceInfos[i]) == NULL) ctr++; if(FindOtherFace(edgeInfos, faceInfos[i]->m_v2, faceInfos[i]->m_v0, faceInfos[i]) == NULL) ctr++; if(ctr > 1) return i; } return -1; }
bool NvStripInfo::Unique(NvFaceInfoVec& faceVec, NvFaceInfo* face) { bool bv0, bv1, bv2; //bools to indicate whether a vertex is in the faceVec or not bv0 = bv1 = bv2 = false; for(size_t i = 0; i < faceVec.size(); i++) { if(!bv0) { if( (faceVec[i]->m_v0 == face->m_v0) || (faceVec[i]->m_v1 == face->m_v0) || (faceVec[i]->m_v2 == face->m_v0) ) bv0 = true; } if(!bv1) { if( (faceVec[i]->m_v0 == face->m_v1) || (faceVec[i]->m_v1 == face->m_v1) || (faceVec[i]->m_v2 == face->m_v1) ) bv1 = true; } if(!bv2) { if( (faceVec[i]->m_v0 == face->m_v2) || (faceVec[i]->m_v1 == face->m_v2) || (faceVec[i]->m_v2 == face->m_v2) ) bv2 = true; } //the face is not unique, all it's vertices exist in the face vector if(bv0 && bv1 && bv2) return false; } //if we get out here, it's unique return true; }
//////////////////////////////////////////////////////////////////////////////////////// //Cleanup strips / faces, used by generatestrips void Cleanup(NvStripInfoVec& tempStrips, NvFaceInfoVec& tempFaces) { //delete strips for(size_t i = 0; i < tempStrips.size(); i++) { for(size_t j = 0; j < tempStrips[i]->m_faces.size(); j++) { delete tempStrips[i]->m_faces[j]; tempStrips[i]->m_faces[j] = NULL; } tempStrips[i]->m_faces.resize(0); delete tempStrips[i]; tempStrips[i] = NULL; } //delete faces for(size_t i = 0; i < tempFaces.size(); i++) { delete tempFaces[i]; tempFaces[i] = NULL; } }
//////////////////////////////////////////////////////////////////////////////////////// // GenerateStrips() // // in_indices: input index list, the indices you would use to render // in_numIndices: number of entries in in_indices // primGroups: array of optimized/stripified PrimitiveGroups // numGroups: number of groups returned // // Be sure to call delete[] on the returned primGroups to avoid leaking mem // bool GenerateStrips(const unsigned short* in_indices, const unsigned int in_numIndices, PrimitiveGroup** primGroups, unsigned short* numGroups, bool validateEnabled) { int i = 0; //put data in format that the stripifier likes WordVec tempIndices; tempIndices.resize(in_numIndices); unsigned short maxIndex = 0; unsigned short minIndex = 0xFFFF; for(i = 0; i < in_numIndices; i++) { tempIndices[i] = in_indices[i]; if (in_indices[i] > maxIndex) maxIndex = in_indices[i]; if (in_indices[i] < minIndex) minIndex = in_indices[i]; } NvStripInfoVec tempStrips; NvFaceInfoVec tempFaces; NvStripifier stripifier; //do actual stripification stripifier.Stripify(tempIndices, cacheSize, minStripSize, maxIndex, tempStrips, tempFaces); //stitch strips together IntVec stripIndices; unsigned int numSeparateStrips = 0; if(bListsOnly) { //if we're outputting only lists, we're done *numGroups = 1; (*primGroups) = new PrimitiveGroup[*numGroups]; PrimitiveGroup* primGroupArray = *primGroups; //count the total number of indices unsigned int numIndices = 0; for(i = 0; i < tempStrips.size(); i++) { numIndices += tempStrips[i]->m_faces.size() * 3; } //add in the list numIndices += tempFaces.size() * 3; primGroupArray[0].type = PT_LIST; primGroupArray[0].numIndices = numIndices; primGroupArray[0].indices = new unsigned short[numIndices]; //do strips unsigned int indexCtr = 0; for(i = 0; i < tempStrips.size(); i++) { for(int j = 0; j < tempStrips[i]->m_faces.size(); j++) { //degenerates are of no use with lists if(!NvStripifier::IsDegenerate(tempStrips[i]->m_faces[j])) { primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v0; primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v1; primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v2; } else { //we've removed a tri, reduce the number of indices primGroupArray[0].numIndices -= 3; } } } //do lists for(i = 0; i < tempFaces.size(); i++) { primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v0; primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v1; primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v2; } } else { stripifier.CreateStrips(tempStrips, stripIndices, bStitchStrips, numSeparateStrips, bRestart, restartVal); //if we're stitching strips together, we better get back only one strip from CreateStrips() assert( (bStitchStrips && (numSeparateStrips == 1)) || !bStitchStrips); //convert to output format *numGroups = numSeparateStrips; //for the strips if(tempFaces.size() != 0) (*numGroups)++; //we've got a list as well, increment (*primGroups) = new PrimitiveGroup[*numGroups]; PrimitiveGroup* primGroupArray = *primGroups; //first, the strips int startingLoc = 0; for(int stripCtr = 0; stripCtr < numSeparateStrips; stripCtr++) { int stripLength = 0; if(!bStitchStrips) { int i; //if we've got multiple strips, we need to figure out the correct length for(i = startingLoc; i < stripIndices.size(); i++) { if(stripIndices[i] == -1) break; } stripLength = i - startingLoc; } else stripLength = stripIndices.size(); primGroupArray[stripCtr].type = PT_STRIP; primGroupArray[stripCtr].indices = new unsigned short[stripLength]; primGroupArray[stripCtr].numIndices = stripLength; int indexCtr = 0; for(int i = startingLoc; i < stripLength + startingLoc; i++) primGroupArray[stripCtr].indices[indexCtr++] = stripIndices[i]; //we add 1 to account for the -1 separating strips //this doesn't break the stitched case since we'll exit the loop startingLoc += stripLength + 1; } //next, the list if(tempFaces.size() != 0) { int faceGroupLoc = (*numGroups) - 1; //the face group is the last one primGroupArray[faceGroupLoc].type = PT_LIST; primGroupArray[faceGroupLoc].indices = new unsigned short[tempFaces.size() * 3]; primGroupArray[faceGroupLoc].numIndices = tempFaces.size() * 3; int indexCtr = 0; for(int i = 0; i < tempFaces.size(); i++) { primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v0; primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v1; primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v2; } } } //validate generated data against input if (validateEnabled) { const int NUMBINS = 100; std::vector<NvFaceInfo> in_bins[NUMBINS]; //hash input indices on first index for (i = 0; i < in_numIndices; i += 3) { NvFaceInfo faceInfo(in_indices[i], in_indices[i + 1], in_indices[i + 2]); in_bins[in_indices[i] % NUMBINS].push_back(faceInfo); } for (i = 0; i < *numGroups; ++i) { switch ((*primGroups)[i].type) { case PT_LIST: { for (int j = 0; j < (*primGroups)[i].numIndices; j += 3) { unsigned short v0 = (*primGroups)[i].indices[j]; unsigned short v1 = (*primGroups)[i].indices[j + 1]; unsigned short v2 = (*primGroups)[i].indices[j + 2]; //ignore degenerates if (NvStripifier::IsDegenerate(v0, v1, v2)) continue; if (!TestTriangle(v0, v1, v2, in_bins, NUMBINS)) { Cleanup(tempStrips, tempFaces); return false; } } break; } case PT_STRIP: { //int brokenCtr = 0; bool flip = false; for (int j = 2; j < (*primGroups)[i].numIndices; ++j) { unsigned short v0 = (*primGroups)[i].indices[j - 2]; unsigned short v1 = (*primGroups)[i].indices[j - 1]; unsigned short v2 = (*primGroups)[i].indices[j]; if (flip) { //swap v1 and v2 unsigned short swap = v1; v1 = v2; v2 = swap; } //ignore degenerates if (NvStripifier::IsDegenerate(v0, v1, v2)) { flip = !flip; continue; } if (!TestTriangle(v0, v1, v2, in_bins, NUMBINS)) { Cleanup(tempStrips, tempFaces); return false; } flip = !flip; } break; } case PT_FAN: default: break; } } } //clean up everything Cleanup(tempStrips, tempFaces); return true; }
/////////////////////////////////////////////////////////////////////////////////////////// // BuildStripifyInfo() // // Builds the list of all face and edge infos // void NvStripifier::BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, const unsigned short maxIndex) { // reserve space for the face infos, but do not resize them. int numIndices = indices.size(); faceInfos.reserve(numIndices / 3); // we actually resize the edge infos, so we must initialize to NULL edgeInfos.resize(maxIndex + 1); for (unsigned short i = 0; i < maxIndex + 1; i++) edgeInfos[i] = NULL; // iterate through the triangles of the triangle list int numTriangles = numIndices / 3; int index = 0; bool bFaceUpdated[3]; for (int i = 0; i < numTriangles; i++) { bool bMightAlreadyExist = true; bFaceUpdated[0] = false; bFaceUpdated[1] = false; bFaceUpdated[2] = false; // grab the indices int v0 = indices[index++]; int v1 = indices[index++]; int v2 = indices[index++]; //we disregard degenerates if(IsDegenerate(v0, v1, v2)) continue; // create the face info and add it to the list of faces, but only if this exact face doesn't already // exist in the list NvFaceInfo *faceInfo = new NvFaceInfo(v0, v1, v2); // grab the edge infos, creating them if they do not already exist NvEdgeInfo *edgeInfo01 = FindEdgeInfo(edgeInfos, v0, v1); if (edgeInfo01 == NULL) { //since one of it's edges isn't in the edge data structure, it can't already exist in the face structure bMightAlreadyExist = false; // create the info edgeInfo01 = new NvEdgeInfo(v0, v1); // update the linked list on both edgeInfo01->m_nextV0 = edgeInfos[v0]; edgeInfo01->m_nextV1 = edgeInfos[v1]; edgeInfos[v0] = edgeInfo01; edgeInfos[v1] = edgeInfo01; // set face 0 edgeInfo01->m_face0 = faceInfo; } else { if (edgeInfo01->m_face1 != NULL) { printf("BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n"); } else { edgeInfo01->m_face1 = faceInfo; bFaceUpdated[0] = true; } } // grab the edge infos, creating them if they do not already exist NvEdgeInfo *edgeInfo12 = FindEdgeInfo(edgeInfos, v1, v2); if (edgeInfo12 == NULL) { bMightAlreadyExist = false; // create the info edgeInfo12 = new NvEdgeInfo(v1, v2); // update the linked list on both edgeInfo12->m_nextV0 = edgeInfos[v1]; edgeInfo12->m_nextV1 = edgeInfos[v2]; edgeInfos[v1] = edgeInfo12; edgeInfos[v2] = edgeInfo12; // set face 0 edgeInfo12->m_face0 = faceInfo; } else { if (edgeInfo12->m_face1 != NULL) { printf("BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n"); } else { edgeInfo12->m_face1 = faceInfo; bFaceUpdated[1] = true; } } // grab the edge infos, creating them if they do not already exist NvEdgeInfo *edgeInfo20 = FindEdgeInfo(edgeInfos, v2, v0); if (edgeInfo20 == NULL) { bMightAlreadyExist = false; // create the info edgeInfo20 = new NvEdgeInfo(v2, v0); // update the linked list on both edgeInfo20->m_nextV0 = edgeInfos[v2]; edgeInfo20->m_nextV1 = edgeInfos[v0]; edgeInfos[v2] = edgeInfo20; edgeInfos[v0] = edgeInfo20; // set face 0 edgeInfo20->m_face0 = faceInfo; } else { if (edgeInfo20->m_face1 != NULL) { printf("BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n"); } else { edgeInfo20->m_face1 = faceInfo; bFaceUpdated[2] = true; } } if(bMightAlreadyExist) { if(!AlreadyExists(faceInfo, faceInfos)) faceInfos.push_back(faceInfo); else { delete faceInfo; //cleanup pointers that point to this deleted face if(bFaceUpdated[0]) edgeInfo01->m_face1 = NULL; if(bFaceUpdated[1]) edgeInfo12->m_face1 = NULL; if(bFaceUpdated[2]) edgeInfo20->m_face1 = NULL; } } else { faceInfos.push_back(faceInfo); } } }
//////////////////////////////////////////////////////////////////////////////////////// // RemoveSmallStrips() // // allStrips is the whole strip vector...all small strips will be deleted from this list, to avoid leaking mem // allBigStrips is an out parameter which will contain all strips above minStripLength // faceList is an out parameter which will contain all faces which were removed from the striplist // void NvStripifier::RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList) { faceList.clear(); allBigStrips.clear(); //make sure these are empty NvFaceInfoVec tempFaceList; for(size_t i = 0; i < allStrips.size(); i++) { if(allStrips[i]->m_faces.size() < (size_t)minStripLength) { //strip is too small, add faces to faceList for(size_t j = 0; j < allStrips[i]->m_faces.size(); j++) tempFaceList.push_back(allStrips[i]->m_faces[j]); //and free memory delete allStrips[i]; } else { allBigStrips.push_back(allStrips[i]); } } if(tempFaceList.size()) { bool *bVisitedList = new bool[tempFaceList.size()]; memset(bVisitedList, 0, tempFaceList.size()*sizeof(bool)); VertexCache* vcache = new VertexCache(cacheSize); int bestNumHits = -1; int numHits; int bestIndex; while(1) { bestNumHits = -1; //find best face to add next, given the current cache for(size_t i = 0; i < tempFaceList.size(); i++) { if(bVisitedList[i]) continue; numHits = CalcNumHitsFace(vcache, tempFaceList[i]); if(numHits > bestNumHits) { bestNumHits = numHits; bestIndex = i; } } if(bestNumHits == -1.0f) break; bVisitedList[bestIndex] = true; UpdateCacheFace(vcache, tempFaceList[bestIndex]); faceList.push_back(tempFaceList[bestIndex]); } delete vcache; delete[] bVisitedList; } }
/////////////////////////////////////////////////////////////////////////////////////////// // Build() // // Builds a strip forward as far as we can go, then builds backwards, and joins the two lists // void NvStripInfo::Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &faceInfos) { // used in building the strips forward and backward WordVec scratchIndices; // build forward... start with the initial face NvFaceInfoVec forwardFaces, backwardFaces; forwardFaces.push_back(m_startInfo.m_startFace); MarkTriangle(m_startInfo.m_startFace); int v0 = (m_startInfo.m_toV1 ? m_startInfo.m_startEdge->m_v0 : m_startInfo.m_startEdge->m_v1); int v1 = (m_startInfo.m_toV1 ? m_startInfo.m_startEdge->m_v1 : m_startInfo.m_startEdge->m_v0); // easiest way to get v2 is to use this function which requires the // other indices to already be in the list. scratchIndices.push_back(v0); scratchIndices.push_back(v1); int v2 = NvStripifier::GetNextIndex(scratchIndices, m_startInfo.m_startFace); scratchIndices.push_back(v2); // // build the forward list // int nv0 = v1; int nv1 = v2; NvFaceInfo *nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, m_startInfo.m_startFace); while (nextFace != NULL && !IsMarked(nextFace)) { //check to see if this next face is going to cause us to die soon int testnv0 = nv1; int testnv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace); NvFaceInfo* nextNextFace = NvStripifier::FindOtherFace(edgeInfos, testnv0, testnv1, nextFace); if( (nextNextFace == NULL) || (IsMarked(nextNextFace)) ) { //uh, oh, we're following a dead end, try swapping NvFaceInfo* testNextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, testnv1, nextFace); if( ((testNextFace != NULL) && !IsMarked(testNextFace)) ) { //we only swap if it buys us something //add a "fake" degenerate face NvFaceInfo* tempFace = new NvFaceInfo(nv0, nv1, nv0, true); forwardFaces.push_back(tempFace); MarkTriangle(tempFace); scratchIndices.push_back(nv0); testnv0 = nv0; ++m_numDegenerates; } } // add this to the strip forwardFaces.push_back(nextFace); MarkTriangle(nextFace); // add the index //nv0 = nv1; //nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace); scratchIndices.push_back(testnv1); // and get the next face nv0 = testnv0; nv1 = testnv1; nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, nextFace); } // tempAllFaces is going to be forwardFaces + backwardFaces // it's used for Unique() NvFaceInfoVec tempAllFaces; for(size_t i = 0; i < forwardFaces.size(); i++) tempAllFaces.push_back(forwardFaces[i]); // // reset the indices for building the strip backwards and do so // scratchIndices.resize(0); scratchIndices.push_back(v2); scratchIndices.push_back(v1); scratchIndices.push_back(v0); nv0 = v1; nv1 = v0; nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, m_startInfo.m_startFace); while (nextFace != NULL && !IsMarked(nextFace)) { //this tests to see if a face is "unique", meaning that its vertices aren't already in the list // so, strips which "wrap-around" are not allowed if(!Unique(tempAllFaces, nextFace)) break; //check to see if this next face is going to cause us to die soon int testnv0 = nv1; int testnv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace); NvFaceInfo* nextNextFace = NvStripifier::FindOtherFace(edgeInfos, testnv0, testnv1, nextFace); if( (nextNextFace == NULL) || (IsMarked(nextNextFace)) ) { //uh, oh, we're following a dead end, try swapping NvFaceInfo* testNextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, testnv1, nextFace); if( ((testNextFace != NULL) && !IsMarked(testNextFace)) ) { //we only swap if it buys us something //add a "fake" degenerate face NvFaceInfo* tempFace = new NvFaceInfo(nv0, nv1, nv0, true); backwardFaces.push_back(tempFace); MarkTriangle(tempFace); scratchIndices.push_back(nv0); testnv0 = nv0; ++m_numDegenerates; } } // add this to the strip backwardFaces.push_back(nextFace); //this is just so Unique() will work tempAllFaces.push_back(nextFace); MarkTriangle(nextFace); // add the index //nv0 = nv1; //nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace); scratchIndices.push_back(testnv1); // and get the next face nv0 = testnv0; nv1 = testnv1; nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, nextFace); } // Combine the forward and backwards stripification lists and put into our own face vector Combine(forwardFaces, backwardFaces); }
/////////////////////////////////////////////////////////////////////////////////////////// // BuildStripifyInfo() // // Builds the list of all face and edge infos // void NvStripifier::BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos){ // reserve space for the face infos, but do not resize them. int numIndices = indices.size(); faceInfos.reserve(numIndices); // we actually resize the edge infos, so we must initialize to NULL edgeInfos.resize (numIndices); for (int i = 0; i < numIndices; i++) edgeInfos[i] = NULL; // iterate through the triangles of the triangle list int numTriangles = numIndices / 3; int index = 0; for (u32 i = 0; i < numTriangles; i++) { // grab the indices int v0 = indices[index++]; int v1 = indices[index++]; int v2 = indices[index++]; // create the face info and add it to the list of faces, but only if this exact face doesn't already // exist in the list NvFaceInfo *faceInfo = xr_new<NvFaceInfo>(v0, v1, v2); if(!AlreadyExists(faceInfo, faceInfos)) { faceInfos.push_back(faceInfo); // grab the edge infos, creating them if they do not already exist NvEdgeInfo *edgeInfo01 = FindEdgeInfo(edgeInfos, v0, v1); if (edgeInfo01 == NULL){ // create the info edgeInfo01 = xr_new<NvEdgeInfo>(v0, v1); // update the linked list on both edgeInfo01->m_nextV0 = edgeInfos[v0]; edgeInfo01->m_nextV1 = edgeInfos[v1]; edgeInfos[v0] = edgeInfo01; edgeInfos[v1] = edgeInfo01; // set face 0 edgeInfo01->m_face0 = faceInfo; } else { if (edgeInfo01->m_face1 != NULL) ; //Msg("! WARNING: BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences"); else edgeInfo01->m_face1 = faceInfo; } // grab the edge infos, creating them if they do not already exist NvEdgeInfo *edgeInfo12 = FindEdgeInfo(edgeInfos, v1, v2); if (edgeInfo12 == NULL){ // create the info edgeInfo12 = xr_new<NvEdgeInfo> (v1, v2); // update the linked list on both edgeInfo12->m_nextV0 = edgeInfos[v1]; edgeInfo12->m_nextV1 = edgeInfos[v2]; edgeInfos[v1] = edgeInfo12; edgeInfos[v2] = edgeInfo12; // set face 0 edgeInfo12->m_face0 = faceInfo; } else { if (edgeInfo12->m_face1 != NULL) ; //Msg("! WARNING: BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences"); else edgeInfo12->m_face1 = faceInfo; } // grab the edge infos, creating them if they do not already exist NvEdgeInfo *edgeInfo20 = FindEdgeInfo(edgeInfos, v2, v0); if (edgeInfo20 == NULL){ // create the info edgeInfo20 = xr_new<NvEdgeInfo>(v2, v0); // update the linked list on both edgeInfo20->m_nextV0 = edgeInfos[v2]; edgeInfo20->m_nextV1 = edgeInfos[v0]; edgeInfos[v2] = edgeInfo20; edgeInfos[v0] = edgeInfo20; // set face 0 edgeInfo20->m_face0 = faceInfo; } else { if (edgeInfo20->m_face1 != NULL) ; //Msg("! WARNING: BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences"); else edgeInfo20->m_face1 = faceInfo; } } } }
/////////////////////////////////////////////////////////////////////////////////////////// // Build() // // Builds a strip forward as far as we can go, then builds backwards, and joins the two lists // void NvStripInfo::Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &faceInfos){ // used in building the strips forward and backward static WordVec scratchIndices; scratchIndices.resize(0); // build forward... start with the initial face NvFaceInfoVec forwardFaces, backwardFaces; forwardFaces.push_back(m_startInfo.m_startFace); MarkTriangle(m_startInfo.m_startFace); int v0 = (m_startInfo.m_toV1 ? m_startInfo.m_startEdge->m_v0 : m_startInfo.m_startEdge->m_v1); int v1 = (m_startInfo.m_toV1 ? m_startInfo.m_startEdge->m_v1 : m_startInfo.m_startEdge->m_v0); // easiest way to get v2 is to use this function which requires the // other indices to already be in the list. scratchIndices.push_back(u16(v0)); scratchIndices.push_back(u16(v1)); int v2 = NvStripifier::GetNextIndex(scratchIndices, m_startInfo.m_startFace); scratchIndices.push_back(u16(v2)); // // build the forward list // int nv0 = v1; int nv1 = v2; NvFaceInfo *nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, m_startInfo.m_startFace); while (nextFace != NULL && !IsMarked(nextFace)) { //this tests to see if a face is "unique", meaning that its vertices aren't already in the list // so, strips which "wrap-around" are not allowed if(!Unique(forwardFaces, nextFace)) break; // add this to the strip forwardFaces.push_back(nextFace); MarkTriangle(nextFace); // add the index nv0 = nv1; nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace); scratchIndices.push_back(u16(nv1)); // and get the next face nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, nextFace); } // tempAllFaces is going to be forwardFaces + backwardFaces // it's used for Unique() NvFaceInfoVec tempAllFaces; for(int i = 0; i < forwardFaces.size(); i++) tempAllFaces.push_back(forwardFaces[i]); // // reset the indices for building the strip backwards and do so // scratchIndices.resize(0); scratchIndices.push_back(u16(v2)); scratchIndices.push_back(u16(v1)); scratchIndices.push_back(u16(v0)); nv0 = v1; nv1 = v0; nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, m_startInfo.m_startFace); while (nextFace != NULL && !IsMarked(nextFace)) { //this tests to see if a face is "unique", meaning that its vertices aren't already in the list // so, strips which "wrap-around" are not allowed if(!Unique(tempAllFaces, nextFace)) break; // add this to the strip backwardFaces.push_back(nextFace); //this is just so Unique() will work tempAllFaces.push_back(nextFace); MarkTriangle(nextFace); // add the index nv0 = nv1; nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace); scratchIndices.push_back(u16(nv1)); // and get the next face nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, nextFace); } // Combine the forward and backwards stripification lists and put into our own face vector3 Combine(forwardFaces, backwardFaces); }
//////////////////////////////////////////////////////////////////////////////////////// // GenerateStrips() // // in_indices: input index list, the indices you would use to render // in_numIndices: number of entries in in_indices // primGroups: array of optimized/stripified PrimitiveGroups // numGroups: number of groups returned // // Be sure to call delete[] on the returned primGroups to avoid leaking mem // void GenerateStrips(const U16* in_indices, const U32 in_numIndices, PrimitiveGroup** primGroups, U16* numGroups) { //put data in format that the stripifier likes WordVec tempIndices; tempIndices.resize(in_numIndices); U16 maxIndex = 0; U32 i; for(i = 0; i < in_numIndices; i++) { tempIndices[i] = in_indices[i]; if(in_indices[i] > maxIndex) maxIndex = in_indices[i]; } NvStripInfoVec tempStrips; NvFaceInfoVec tempFaces; NvStripifier stripifier; //do actual stripification stripifier.Stripify(tempIndices, cacheSize, minStripSize, maxIndex, tempStrips, tempFaces); //stitch strips together IntVec stripIndices; U32 numSeparateStrips = 0; if(bListsOnly) { //if we're outputting only lists, we're done *numGroups = 1; (*primGroups) = new PrimitiveGroup[*numGroups]; PrimitiveGroup* primGroupArray = *primGroups; //count the total number of indices U32 numIndices = 0; U32 i; for(i = 0; i < tempStrips.size(); i++) { numIndices += tempStrips[i]->m_faces.size() * 3; } //add in the list numIndices += tempFaces.size() * 3; primGroupArray[0].type = PT_LIST; primGroupArray[0].numIndices = numIndices; primGroupArray[0].indices = new U16[numIndices]; //do strips U32 indexCtr = 0; for(U32 k = 0; k < tempStrips.size(); k++) { for(U32 j = 0; j < tempStrips[i]->m_faces.size(); j++) { //degenerates are of no use with lists if(!NvStripifier::IsDegenerate(tempStrips[i]->m_faces[j])) { primGroupArray[0].indices[indexCtr++] = tempStrips[k]->m_faces[j]->m_v0; primGroupArray[0].indices[indexCtr++] = tempStrips[k]->m_faces[j]->m_v1; primGroupArray[0].indices[indexCtr++] = tempStrips[k]->m_faces[j]->m_v2; } else { //we've removed a tri, reduce the number of indices primGroupArray[0].numIndices -= 3; } } } //do lists for(i = 0; i < tempFaces.size(); i++) { primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v0; primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v1; primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v2; } } else { stripifier.CreateStrips(tempStrips, stripIndices, bStitchStrips, numSeparateStrips); //if we're stitching strips together, we better get back only one strip from CreateStrips() assert( (bStitchStrips && (numSeparateStrips == 1)) || !bStitchStrips); //convert to output format *numGroups = numSeparateStrips; //for the strips if(tempFaces.size() != 0) (*numGroups)++; //we've got a list as well, increment (*primGroups) = new PrimitiveGroup[*numGroups]; PrimitiveGroup* primGroupArray = *primGroups; //first, the strips S32 startingLoc = 0; for(U32 stripCtr = 0; stripCtr < numSeparateStrips; stripCtr++) { S32 stripLength = 0; if(!bStitchStrips) { //if we've got multiple strips, we need to figure out the correct length U32 i; for(i = startingLoc; i < stripIndices.size(); i++) { if(stripIndices[i] == -1) break; } stripLength = i - startingLoc; } else stripLength = stripIndices.size(); primGroupArray[stripCtr].type = PT_STRIP; primGroupArray[stripCtr].indices = new U16[stripLength]; primGroupArray[stripCtr].numIndices = stripLength; S32 indexCtr = 0; for(S32 i = startingLoc; i < stripLength + startingLoc; i++) primGroupArray[stripCtr].indices[indexCtr++] = stripIndices[i]; //we add 1 to account for the -1 separating strips //this doesn't break the stitched case since we'll exit the loop startingLoc += stripLength + 1; } //next, the list if(tempFaces.size() != 0) { S32 faceGroupLoc = (*numGroups) - 1; //the face group is the last one primGroupArray[faceGroupLoc].type = PT_LIST; primGroupArray[faceGroupLoc].indices = new U16[tempFaces.size() * 3]; primGroupArray[faceGroupLoc].numIndices = tempFaces.size() * 3; S32 indexCtr = 0; for(U32 i = 0; i < tempFaces.size(); i++) { primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v0; primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v1; primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v2; } } } //clean up everything //delete strips for(i = 0; i < tempStrips.size(); i++) { for(U32 j = 0; j < tempStrips[i]->m_faces.size(); j++) { delete tempStrips[i]->m_faces[j]; tempStrips[i]->m_faces[j] = NULL; } delete tempStrips[i]; tempStrips[i] = NULL; } //delete faces for(i = 0; i < tempFaces.size(); i++) { delete tempFaces[i]; tempFaces[i] = NULL; } }