Home | History | Annotate | Download | only in strip
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 package jme3tools.converters.model.strip;
     34 
     35 import java.util.HashSet;
     36 import java.util.logging.Logger;
     37 
     38 /**
     39  *
     40  */
     41 class Stripifier {
     42     private static final Logger logger = Logger.getLogger(Stripifier.class
     43             .getName());
     44 
     45 	public static int CACHE_INEFFICIENCY = 6;
     46 
     47 	IntVec indices = new IntVec();
     48 
     49 	int cacheSize;
     50 
     51 	int minStripLength;
     52 
     53 	float meshJump;
     54 
     55 	boolean bFirstTimeResetPoint;
     56 
     57 	Stripifier() {
     58 		super();
     59 	}
     60 
     61 	///////////////////////////////////////////////////////////////////////////////////////////
     62 	// FindEdgeInfo()
     63 	//
     64 	// find the edge info for these two indices
     65 	//
     66 	static EdgeInfo findEdgeInfo(EdgeInfoVec edgeInfos, int v0, int v1) {
     67 
     68 		// we can get to it through either array
     69 		// because the edge infos have a v0 and v1
     70 		// and there is no order except how it was
     71 		// first created.
     72 		EdgeInfo infoIter = edgeInfos.at(v0);
     73 		while (infoIter != null) {
     74 			if (infoIter.m_v0 == v0) {
     75 				if (infoIter.m_v1 == v1)
     76 					return infoIter;
     77 
     78 				infoIter = infoIter.m_nextV0;
     79 			} else {
     80 				if (infoIter.m_v0 == v1)
     81 					return infoIter;
     82 
     83 				infoIter = infoIter.m_nextV1;
     84 			}
     85 		}
     86 		return null;
     87 	}
     88 
     89 	///////////////////////////////////////////////////////////////////////////////////////////
     90 	// FindOtherFace
     91 	//
     92 	// find the other face sharing these vertices
     93 	// exactly like the edge info above
     94 	//
     95 	static FaceInfo findOtherFace(EdgeInfoVec edgeInfos, int v0, int v1,
     96 			FaceInfo faceInfo) {
     97 		EdgeInfo edgeInfo = findEdgeInfo(edgeInfos, v0, v1);
     98 
     99 		if ((edgeInfo == null) || (v0 == v1)) {
    100 			//we've hit a degenerate
    101 			return null;
    102 		}
    103 
    104 		return (edgeInfo.m_face0 == faceInfo ? edgeInfo.m_face1
    105 				: edgeInfo.m_face0);
    106 	}
    107 
    108 	static boolean alreadyExists(FaceInfo faceInfo, FaceInfoVec faceInfos) {
    109 		for (int i = 0; i < faceInfos.size(); ++i) {
    110 			FaceInfo o = faceInfos.at(i);
    111 			if ((o.m_v0 == faceInfo.m_v0) && (o.m_v1 == faceInfo.m_v1)
    112 					&& (o.m_v2 == faceInfo.m_v2))
    113 				return true;
    114 		}
    115 		return false;
    116 	}
    117 
    118 	///////////////////////////////////////////////////////////////////////////////////////////
    119 	// BuildStripifyInfo()
    120 	//
    121 	// Builds the list of all face and edge infos
    122 	//
    123 	void buildStripifyInfo(FaceInfoVec faceInfos, EdgeInfoVec edgeInfos,
    124 			int maxIndex) {
    125 		// reserve space for the face infos, but do not resize them.
    126 		int numIndices = indices.size();
    127 		faceInfos.reserve(numIndices / 3);
    128 
    129 		// we actually resize the edge infos, so we must initialize to null
    130 		for (int i = 0; i < maxIndex + 1; i++)
    131 			edgeInfos.add(null);
    132 
    133 		// iterate through the triangles of the triangle list
    134 		int numTriangles = numIndices / 3;
    135 		int index = 0;
    136 		boolean[] bFaceUpdated = new boolean[3];
    137 
    138 		for (int i = 0; i < numTriangles; i++) {
    139 			boolean bMightAlreadyExist = true;
    140 			bFaceUpdated[0] = false;
    141 			bFaceUpdated[1] = false;
    142 			bFaceUpdated[2] = false;
    143 
    144 			// grab the indices
    145 			int v0 = indices.get(index++);
    146 			int v1 = indices.get(index++);
    147 			int v2 = indices.get(index++);
    148 
    149 			//we disregard degenerates
    150 			if (isDegenerate(v0, v1, v2))
    151 				continue;
    152 
    153 			// create the face info and add it to the list of faces, but only
    154 			// if this exact face doesn't already
    155 			//  exist in the list
    156 			FaceInfo faceInfo = new FaceInfo(v0, v1, v2);
    157 
    158 			// grab the edge infos, creating them if they do not already exist
    159 			EdgeInfo edgeInfo01 = findEdgeInfo(edgeInfos, v0, v1);
    160 			if (edgeInfo01 == null) {
    161 				//since one of it's edges isn't in the edge data structure, it
    162 				// can't already exist in the face structure
    163 				bMightAlreadyExist = false;
    164 
    165 				// create the info
    166 				edgeInfo01 = new EdgeInfo(v0, v1);
    167 
    168 				// update the linked list on both
    169 				edgeInfo01.m_nextV0 = edgeInfos.at(v0);
    170 				edgeInfo01.m_nextV1 = edgeInfos.at(v1);
    171 				edgeInfos.set(v0, edgeInfo01);
    172 				edgeInfos.set(v1, edgeInfo01);
    173 
    174 				// set face 0
    175 				edgeInfo01.m_face0 = faceInfo;
    176 			} else {
    177 				if (edgeInfo01.m_face1 != null) {
    178 					logger.info("BuildStripifyInfo: > 2 triangles on an edge"
    179                             + v0 + "," + v1 + "... uncertain consequences\n");
    180 				} else {
    181 					edgeInfo01.m_face1 = faceInfo;
    182 					bFaceUpdated[0] = true;
    183 				}
    184 			}
    185 
    186 			// grab the edge infos, creating them if they do not already exist
    187 			EdgeInfo edgeInfo12 = findEdgeInfo(edgeInfos, v1, v2);
    188 			if (edgeInfo12 == null) {
    189 				bMightAlreadyExist = false;
    190 
    191 				// create the info
    192 				edgeInfo12 = new EdgeInfo(v1, v2);
    193 
    194 				// update the linked list on both
    195 				edgeInfo12.m_nextV0 = edgeInfos.at(v1);
    196 				edgeInfo12.m_nextV1 = edgeInfos.at(v2);
    197 				edgeInfos.set(v1, edgeInfo12);
    198 				edgeInfos.set(v2, edgeInfo12);
    199 
    200 				// set face 0
    201 				edgeInfo12.m_face0 = faceInfo;
    202 			} else {
    203 				if (edgeInfo12.m_face1 != null) {
    204 					logger.info("BuildStripifyInfo: > 2 triangles on an edge"
    205 									+ v1
    206 									+ ","
    207 									+ v2
    208 									+ "... uncertain consequences\n");
    209 				} else {
    210 					edgeInfo12.m_face1 = faceInfo;
    211 					bFaceUpdated[1] = true;
    212 				}
    213 			}
    214 
    215 			// grab the edge infos, creating them if they do not already exist
    216 			EdgeInfo edgeInfo20 = findEdgeInfo(edgeInfos, v2, v0);
    217 			if (edgeInfo20 == null) {
    218 				bMightAlreadyExist = false;
    219 
    220 				// create the info
    221 				edgeInfo20 = new EdgeInfo(v2, v0);
    222 
    223 				// update the linked list on both
    224 				edgeInfo20.m_nextV0 = edgeInfos.at(v2);
    225 				edgeInfo20.m_nextV1 = edgeInfos.at(v0);
    226 				edgeInfos.set(v2, edgeInfo20);
    227 				edgeInfos.set(v0, edgeInfo20);
    228 
    229 				// set face 0
    230 				edgeInfo20.m_face0 = faceInfo;
    231 			} else {
    232 				if (edgeInfo20.m_face1 != null) {
    233 					logger.info("BuildStripifyInfo: > 2 triangles on an edge"
    234 									+ v2
    235 									+ ","
    236 									+ v0
    237 									+ "... uncertain consequences\n");
    238 				} else {
    239 					edgeInfo20.m_face1 = faceInfo;
    240 					bFaceUpdated[2] = true;
    241 				}
    242 			}
    243 
    244 			if (bMightAlreadyExist) {
    245 				if (!alreadyExists(faceInfo, faceInfos))
    246 					faceInfos.add(faceInfo);
    247 				else {
    248 
    249 					//cleanup pointers that point to this deleted face
    250 					if (bFaceUpdated[0])
    251 						edgeInfo01.m_face1 = null;
    252 					if (bFaceUpdated[1])
    253 						edgeInfo12.m_face1 = null;
    254 					if (bFaceUpdated[2])
    255 						edgeInfo20.m_face1 = null;
    256 				}
    257 			} else {
    258 				faceInfos.add(faceInfo);
    259 			}
    260 
    261 		}
    262 	}
    263 
    264 	static boolean isDegenerate(FaceInfo face) {
    265 		if (face.m_v0 == face.m_v1)
    266 			return true;
    267 		else if (face.m_v0 == face.m_v2)
    268 			return true;
    269 		else if (face.m_v1 == face.m_v2)
    270 			return true;
    271 		else
    272 			return false;
    273 	}
    274 
    275 	static boolean isDegenerate(int v0, int v1, int v2) {
    276 		if (v0 == v1)
    277 			return true;
    278 		else if (v0 == v2)
    279 			return true;
    280 		else if (v1 == v2)
    281 			return true;
    282 		else
    283 			return false;
    284 	}
    285 
    286 	///////////////////////////////////////////////////////////////////////////////////////////
    287 	// GetNextIndex()
    288 	//
    289 	// Returns vertex of the input face which is "next" in the input index list
    290 	//
    291 	static int getNextIndex(IntVec indices, FaceInfo face) {
    292 
    293 		int numIndices = indices.size();
    294 
    295 		int v0 = indices.get(numIndices - 2);
    296 		int v1 = indices.get(numIndices - 1);
    297 
    298 		int fv0 = face.m_v0;
    299 		int fv1 = face.m_v1;
    300 		int fv2 = face.m_v2;
    301 
    302 		if (fv0 != v0 && fv0 != v1) {
    303 			if ((fv1 != v0 && fv1 != v1) || (fv2 != v0 && fv2 != v1)) {
    304                 logger.info("GetNextIndex: Triangle doesn't have all of its vertices\n");
    305                 logger.info("GetNextIndex: Duplicate triangle probably got us derailed\n");
    306 			}
    307 			return fv0;
    308 		}
    309 		if (fv1 != v0 && fv1 != v1) {
    310 			if ((fv0 != v0 && fv0 != v1) || (fv2 != v0 && fv2 != v1)) {
    311                 logger.info("GetNextIndex: Triangle doesn't have all of its vertices\n");
    312                 logger.info("GetNextIndex: Duplicate triangle probably got us derailed\n");
    313 			}
    314 			return fv1;
    315 		}
    316 		if (fv2 != v0 && fv2 != v1) {
    317 			if ((fv0 != v0 && fv0 != v1) || (fv1 != v0 && fv1 != v1)) {
    318                 logger.info("GetNextIndex: Triangle doesn't have all of its vertices\n");
    319                 logger.info("GetNextIndex: Duplicate triangle probably got us derailed\n");
    320 			}
    321 			return fv2;
    322 		}
    323 
    324 		// shouldn't get here, but let's try and fail gracefully
    325 		if ((fv0 == fv1) || (fv0 == fv2))
    326 			return fv0;
    327 		else if ((fv1 == fv0) || (fv1 == fv2))
    328 			return fv1;
    329 		else if ((fv2 == fv0) || (fv2 == fv1))
    330 			return fv2;
    331 		else
    332 			return -1;
    333 	}
    334 
    335 	///////////////////////////////////////////////////////////////////////////////////////////
    336 	// FindStartPoint()
    337 	//
    338 	// Finds a good starting point, namely one which has only one neighbor
    339 	//
    340 	static int findStartPoint(FaceInfoVec faceInfos, EdgeInfoVec edgeInfos) {
    341 		int bestCtr = -1;
    342 		int bestIndex = -1;
    343 
    344 		for (int i = 0; i < faceInfos.size(); i++) {
    345 			int ctr = 0;
    346 
    347 			if (findOtherFace(edgeInfos, faceInfos.at(i).m_v0,
    348 					faceInfos.at(i).m_v1, faceInfos.at(i)) == null)
    349 				ctr++;
    350 			if (findOtherFace(edgeInfos, faceInfos.at(i).m_v1,
    351 					faceInfos.at(i).m_v2, faceInfos.at(i)) == null)
    352 				ctr++;
    353 			if (findOtherFace(edgeInfos, faceInfos.at(i).m_v2,
    354 					faceInfos.at(i).m_v0, faceInfos.at(i)) == null)
    355 				ctr++;
    356 			if (ctr > bestCtr) {
    357 				bestCtr = ctr;
    358 				bestIndex = i;
    359 				//return i;
    360 			}
    361 		}
    362 		//return -1;
    363 
    364 		if (bestCtr == 0)
    365 			return -1;
    366 
    367 		return bestIndex;
    368 	}
    369 
    370 	///////////////////////////////////////////////////////////////////////////////////////////
    371 	// FindGoodResetPoint()
    372 	//
    373 	// A good reset point is one near other commited areas so that
    374 	// we know that when we've made the longest strips its because
    375 	// we're stripifying in the same general orientation.
    376 	//
    377 	FaceInfo findGoodResetPoint(FaceInfoVec faceInfos, EdgeInfoVec edgeInfos) {
    378 		// we hop into different areas of the mesh to try to get
    379 		// other large open spans done. Areas of small strips can
    380 		// just be left to triangle lists added at the end.
    381 		FaceInfo result = null;
    382 
    383 		if (result == null) {
    384 			int numFaces = faceInfos.size();
    385 			int startPoint;
    386 			if (bFirstTimeResetPoint) {
    387 				//first time, find a face with few neighbors (look for an edge
    388 				// of the mesh)
    389 				startPoint = findStartPoint(faceInfos, edgeInfos);
    390 				bFirstTimeResetPoint = false;
    391 			} else
    392 				startPoint = (int) (((float) numFaces - 1) * meshJump);
    393 
    394 			if (startPoint == -1) {
    395 				startPoint = (int) (((float) numFaces - 1) * meshJump);
    396 
    397 				//meshJump += 0.1f;
    398 				//if (meshJump > 1.0f)
    399 				//  meshJump = .05f;
    400 			}
    401 
    402 			int i = startPoint;
    403 			do {
    404 
    405 				// if this guy isn't visited, try him
    406 				if (faceInfos.at(i).m_stripId < 0) {
    407 					result = faceInfos.at(i);
    408 					break;
    409 				}
    410 
    411 				// update the index and clamp to 0-(numFaces-1)
    412 				if (++i >= numFaces)
    413 					i = 0;
    414 
    415 			} while (i != startPoint);
    416 
    417 			// update the meshJump
    418 			meshJump += 0.1f;
    419 			if (meshJump > 1.0f)
    420 				meshJump = .05f;
    421 		}
    422 
    423 		// return the best face we found
    424 		return result;
    425 	}
    426 
    427 	///////////////////////////////////////////////////////////////////////////////////////////
    428 	// GetUniqueVertexInB()
    429 	//
    430 	// Returns the vertex unique to faceB
    431 	//
    432 	static int getUniqueVertexInB(FaceInfo faceA, FaceInfo faceB) {
    433 
    434 		int facev0 = faceB.m_v0;
    435 		if (facev0 != faceA.m_v0 && facev0 != faceA.m_v1
    436 				&& facev0 != faceA.m_v2)
    437 			return facev0;
    438 
    439 		int facev1 = faceB.m_v1;
    440 		if (facev1 != faceA.m_v0 && facev1 != faceA.m_v1
    441 				&& facev1 != faceA.m_v2)
    442 			return facev1;
    443 
    444 		int facev2 = faceB.m_v2;
    445 		if (facev2 != faceA.m_v0 && facev2 != faceA.m_v1
    446 				&& facev2 != faceA.m_v2)
    447 			return facev2;
    448 
    449 		// nothing is different
    450 		return -1;
    451 	}
    452 
    453 	///////////////////////////////////////////////////////////////////////////////////////////
    454 	// GetSharedVertices()
    455 	//
    456 	// Returns the (at most) two vertices shared between the two faces
    457 	//
    458 	static void getSharedVertices(FaceInfo faceA, FaceInfo faceB, int[] vertex) {
    459 		vertex[0] = -1;
    460 		vertex[1] = -1;
    461 
    462 		int facev0 = faceB.m_v0;
    463 		if (facev0 == faceA.m_v0 || facev0 == faceA.m_v1
    464 				|| facev0 == faceA.m_v2) {
    465 			if (vertex[0] == -1)
    466 				vertex[0] = facev0;
    467 			else {
    468 				vertex[1] = facev0;
    469 				return;
    470 			}
    471 		}
    472 
    473 		int facev1 = faceB.m_v1;
    474 		if (facev1 == faceA.m_v0 || facev1 == faceA.m_v1
    475 				|| facev1 == faceA.m_v2) {
    476 			if (vertex[0] == -1)
    477 				vertex[0] = facev1;
    478 			else {
    479 				vertex[1] = facev1;
    480 				return;
    481 			}
    482 		}
    483 
    484 		int facev2 = faceB.m_v2;
    485 		if (facev2 == faceA.m_v0 || facev2 == faceA.m_v1
    486 				|| facev2 == faceA.m_v2) {
    487 			if (vertex[0] == -1)
    488 				vertex[0] = facev2;
    489 			else {
    490 				vertex[1] = facev2;
    491 				return;
    492 			}
    493 		}
    494 
    495 	}
    496 
    497 	///////////////////////////////////////////////////////////////////////////////////////////
    498 	// CommitStrips()
    499 	//
    500 	// "Commits" the input strips by setting their m_experimentId to -1 and
    501 	// adding to the allStrips
    502 	//  vector
    503 	//
    504 	static void commitStrips(StripInfoVec allStrips, StripInfoVec strips) {
    505 		// Iterate through strips
    506 		int numStrips = strips.size();
    507 		for (int i = 0; i < numStrips; i++) {
    508 
    509 			// Tell the strip that it is now real
    510 			StripInfo strip = strips.at(i);
    511 			strip.m_experimentId = -1;
    512 
    513 			// add to the list of real strips
    514 			allStrips.add(strip);
    515 
    516 			// Iterate through the faces of the strip
    517 			// Tell the faces of the strip that they belong to a real strip now
    518 			FaceInfoVec faces = strips.at(i).m_faces;
    519 			int numFaces = faces.size();
    520 
    521 			for (int j = 0; j < numFaces; j++) {
    522 				strip.markTriangle(faces.at(j));
    523 			}
    524 		}
    525 	}
    526 
    527 	///////////////////////////////////////////////////////////////////////////////////////////
    528 	// NextIsCW()
    529 	//
    530 	// Returns true if the next face should be ordered in CW fashion
    531 	//
    532 	static boolean nextIsCW(int numIndices) {
    533 		return ((numIndices % 2) == 0);
    534 	}
    535 
    536 	///////////////////////////////////////////////////////////////////////////////////////////
    537 	// UpdateCacheFace()
    538 	//
    539 	// Updates the input vertex cache with this face's vertices
    540 	//
    541 	static void updateCacheFace(VertexCache vcache, FaceInfo face) {
    542 		if (!vcache.inCache(face.m_v0))
    543 			vcache.addEntry(face.m_v0);
    544 
    545 		if (!vcache.inCache(face.m_v1))
    546 			vcache.addEntry(face.m_v1);
    547 
    548 		if (!vcache.inCache(face.m_v2))
    549 			vcache.addEntry(face.m_v2);
    550 	}
    551 
    552 	///////////////////////////////////////////////////////////////////////////////////////////
    553 	// UpdateCacheStrip()
    554 	//
    555 	// Updates the input vertex cache with this strip's vertices
    556 	//
    557 	static void updateCacheStrip(VertexCache vcache, StripInfo strip) {
    558 		for (int i = 0; i < strip.m_faces.size(); ++i) {
    559 			if (!vcache.inCache(strip.m_faces.at(i).m_v0))
    560 				vcache.addEntry(strip.m_faces.at(i).m_v0);
    561 
    562 			if (!vcache.inCache(strip.m_faces.at(i).m_v1))
    563 				vcache.addEntry(strip.m_faces.at(i).m_v1);
    564 
    565 			if (!vcache.inCache(strip.m_faces.at(i).m_v2))
    566 				vcache.addEntry(strip.m_faces.at(i).m_v2);
    567 		}
    568 	}
    569 
    570 	///////////////////////////////////////////////////////////////////////////////////////////
    571 	// CalcNumHitsStrip()
    572 	//
    573 	// returns the number of cache hits per face in the strip
    574 	//
    575 	static float calcNumHitsStrip(VertexCache vcache, StripInfo strip) {
    576 		int numHits = 0;
    577 		int numFaces = 0;
    578 
    579 		for (int i = 0; i < strip.m_faces.size(); i++) {
    580 			if (vcache.inCache(strip.m_faces.at(i).m_v0))
    581 				++numHits;
    582 
    583 			if (vcache.inCache(strip.m_faces.at(i).m_v1))
    584 				++numHits;
    585 
    586 			if (vcache.inCache(strip.m_faces.at(i).m_v2))
    587 				++numHits;
    588 
    589 			numFaces++;
    590 		}
    591 
    592 		return ((float) numHits / (float) numFaces);
    593 	}
    594 
    595 	///////////////////////////////////////////////////////////////////////////////////////////
    596 	// AvgStripSize()
    597 	//
    598 	// Finds the average strip size of the input vector of strips
    599 	//
    600 	static float avgStripSize(StripInfoVec strips) {
    601 		int sizeAccum = 0;
    602 		int numStrips = strips.size();
    603 		for (int i = 0; i < numStrips; i++) {
    604 			StripInfo strip = strips.at(i);
    605 			sizeAccum += strip.m_faces.size();
    606 			sizeAccum -= strip.m_numDegenerates;
    607 		}
    608 		return ((float) sizeAccum) / ((float) numStrips);
    609 	}
    610 
    611 	///////////////////////////////////////////////////////////////////////////////////////////
    612 	// CalcNumHitsFace()
    613 	//
    614 	// returns the number of cache hits in the face
    615 	//
    616 	static int calcNumHitsFace(VertexCache vcache, FaceInfo face) {
    617 		int numHits = 0;
    618 
    619 		if (vcache.inCache(face.m_v0))
    620 			numHits++;
    621 
    622 		if (vcache.inCache(face.m_v1))
    623 			numHits++;
    624 
    625 		if (vcache.inCache(face.m_v2))
    626 			numHits++;
    627 
    628 		return numHits;
    629 	}
    630 
    631 	///////////////////////////////////////////////////////////////////////////////////////////
    632 	// NumNeighbors()
    633 	//
    634 	// Returns the number of neighbors that this face has
    635 	//
    636 	static int numNeighbors(FaceInfo face, EdgeInfoVec edgeInfoVec) {
    637 		int numNeighbors = 0;
    638 
    639 		if (findOtherFace(edgeInfoVec, face.m_v0, face.m_v1, face) != null) {
    640 			numNeighbors++;
    641 		}
    642 
    643 		if (findOtherFace(edgeInfoVec, face.m_v1, face.m_v2, face) != null) {
    644 			numNeighbors++;
    645 		}
    646 
    647 		if (findOtherFace(edgeInfoVec, face.m_v2, face.m_v0, face) != null) {
    648 			numNeighbors++;
    649 		}
    650 
    651 		return numNeighbors;
    652 	}
    653 
    654 	///////////////////////////////////////////////////////////////////////////////////////////
    655 	// IsCW()
    656 	//
    657 	// Returns true if the face is ordered in CW fashion
    658 	//
    659 	static boolean isCW(FaceInfo faceInfo, int v0, int v1) {
    660 		if (faceInfo.m_v0 == v0)
    661 			return (faceInfo.m_v1 == v1);
    662 		else if (faceInfo.m_v1 == v0)
    663 			return (faceInfo.m_v2 == v1);
    664 		else
    665 			return (faceInfo.m_v0 == v1);
    666 
    667 	}
    668 
    669 	static boolean faceContainsIndex(FaceInfo face, int index) {
    670 		return ((face.m_v0 == index) || (face.m_v1 == index) || (face.m_v2 == index));
    671 	}
    672 
    673 	///////////////////////////////////////////////////////////////////////////////////////////
    674 	// FindTraversal()
    675 	//
    676 	// Finds the next face to start the next strip on.
    677 	//
    678 	static boolean findTraversal(FaceInfoVec faceInfos, EdgeInfoVec edgeInfos,
    679 			StripInfo strip, StripStartInfo startInfo) {
    680 
    681 		// if the strip was v0.v1 on the edge, then v1 will be a vertex in the
    682 		// next edge.
    683 		int v = (strip.m_startInfo.m_toV1 ? strip.m_startInfo.m_startEdge.m_v1
    684 				: strip.m_startInfo.m_startEdge.m_v0);
    685 
    686 		FaceInfo untouchedFace = null;
    687 		EdgeInfo edgeIter = edgeInfos.at(v);
    688 		while (edgeIter != null) {
    689 			FaceInfo face0 = edgeIter.m_face0;
    690 			FaceInfo face1 = edgeIter.m_face1;
    691 			if ((face0 != null && !strip.isInStrip(face0)) && face1 != null
    692 					&& !strip.isMarked(face1)) {
    693 				untouchedFace = face1;
    694 				break;
    695 			}
    696 			if ((face1 != null && !strip.isInStrip(face1)) && face0 != null
    697 					&& !strip.isMarked(face0)) {
    698 				untouchedFace = face0;
    699 				break;
    700 			}
    701 
    702 			// find the next edgeIter
    703 			edgeIter = (edgeIter.m_v0 == v ? edgeIter.m_nextV0
    704 					: edgeIter.m_nextV1);
    705 		}
    706 
    707 		startInfo.m_startFace = untouchedFace;
    708 		startInfo.m_startEdge = edgeIter;
    709 		if (edgeIter != null) {
    710 			if (strip.sharesEdge(startInfo.m_startFace, edgeInfos))
    711 				startInfo.m_toV1 = (edgeIter.m_v0 == v); //note! used to be
    712 			// m_v1
    713 			else
    714 				startInfo.m_toV1 = (edgeIter.m_v1 == v);
    715 		}
    716 		return (startInfo.m_startFace != null);
    717 	}
    718 
    719 	////////////////////////////////////////////////////////////////////////////////////////
    720 	// RemoveSmallStrips()
    721 	//
    722 	// allStrips is the whole strip vector...all small strips will be deleted
    723 	// from this list, to avoid leaking mem
    724 	// allBigStrips is an out parameter which will contain all strips above
    725 	// minStripLength
    726 	// faceList is an out parameter which will contain all faces which were
    727 	// removed from the striplist
    728 	//
    729 	void removeSmallStrips(StripInfoVec allStrips, StripInfoVec allBigStrips,
    730 			FaceInfoVec faceList) {
    731 		faceList.clear();
    732 		allBigStrips.clear(); //make sure these are empty
    733 		FaceInfoVec tempFaceList = new FaceInfoVec();
    734 
    735 		for (int i = 0; i < allStrips.size(); i++) {
    736 			if (allStrips.at(i).m_faces.size() < minStripLength) {
    737 				//strip is too small, add faces to faceList
    738 				for (int j = 0; j < allStrips.at(i).m_faces.size(); j++)
    739 					tempFaceList.add(allStrips.at(i).m_faces.at(j));
    740 
    741 			} else {
    742 				allBigStrips.add(allStrips.at(i));
    743 			}
    744 		}
    745 
    746 		boolean[] bVisitedList = new boolean[tempFaceList.size()];
    747 
    748 		VertexCache vcache = new VertexCache(cacheSize);
    749 
    750 		int bestNumHits = -1;
    751 		int numHits;
    752 		int bestIndex = -9999;
    753 
    754 		while (true) {
    755 			bestNumHits = -1;
    756 
    757 			//find best face to add next, given the current cache
    758 			for (int i = 0; i < tempFaceList.size(); i++) {
    759 				if (bVisitedList[i])
    760 					continue;
    761 
    762 				numHits = calcNumHitsFace(vcache, tempFaceList.at(i));
    763 				if (numHits > bestNumHits) {
    764 					bestNumHits = numHits;
    765 					bestIndex = i;
    766 				}
    767 			}
    768 
    769 			if (bestNumHits == -1.0f)
    770 				break;
    771 			bVisitedList[bestIndex] = true;
    772 			updateCacheFace(vcache, tempFaceList.at(bestIndex));
    773 			faceList.add(tempFaceList.at(bestIndex));
    774 		}
    775 	}
    776 
    777 	////////////////////////////////////////////////////////////////////////////////////////
    778 	// CreateStrips()
    779 	//
    780 	// Generates actual strips from the list-in-strip-order.
    781 	//
    782 	int createStrips(StripInfoVec allStrips, IntVec stripIndices,
    783 			boolean bStitchStrips) {
    784 		int numSeparateStrips = 0;
    785 
    786 		FaceInfo tLastFace = new FaceInfo(0, 0, 0);
    787 		int nStripCount = allStrips.size();
    788 
    789 		//we infer the cw/ccw ordering depending on the number of indices
    790 		//this is screwed up by the fact that we insert -1s to denote changing
    791 		// strips
    792 		//this is to account for that
    793 		int accountForNegatives = 0;
    794 
    795 		for (int i = 0; i < nStripCount; i++) {
    796 			StripInfo strip = allStrips.at(i);
    797 			int nStripFaceCount = strip.m_faces.size();
    798 
    799 			// Handle the first face in the strip
    800 			{
    801 				FaceInfo tFirstFace = new FaceInfo(strip.m_faces.at(0).m_v0,
    802 						strip.m_faces.at(0).m_v1, strip.m_faces.at(0).m_v2);
    803 
    804 				// If there is a second face, reorder vertices such that the
    805 				// unique vertex is first
    806 				if (nStripFaceCount > 1) {
    807 					int nUnique = getUniqueVertexInB(strip.m_faces.at(1),
    808 							tFirstFace);
    809 					if (nUnique == tFirstFace.m_v1) {
    810 						int tmp = tFirstFace.m_v0;
    811 						tFirstFace.m_v0 = tFirstFace.m_v1;
    812 						tFirstFace.m_v1 = tmp;
    813 					} else if (nUnique == tFirstFace.m_v2) {
    814 						int tmp = tFirstFace.m_v0;
    815 						tFirstFace.m_v0 = tFirstFace.m_v2;
    816 						tFirstFace.m_v2 = tmp;
    817 					}
    818 
    819 					// If there is a third face, reorder vertices such that the
    820 					// shared vertex is last
    821 					if (nStripFaceCount > 2) {
    822 						if (isDegenerate(strip.m_faces.at(1))) {
    823 							int pivot = strip.m_faces.at(1).m_v1;
    824 							if (tFirstFace.m_v1 == pivot) {
    825 								int tmp = tFirstFace.m_v1;
    826 								tFirstFace.m_v1 = tFirstFace.m_v2;
    827 								tFirstFace.m_v2 = tmp;
    828 							}
    829 						} else {
    830 							int[] nShared = new int[2];
    831 							getSharedVertices(strip.m_faces.at(2), tFirstFace,
    832 									nShared);
    833 							if ((nShared[0] == tFirstFace.m_v1)
    834 									&& (nShared[1] == -1)) {
    835 								int tmp = tFirstFace.m_v1;
    836 								tFirstFace.m_v1 = tFirstFace.m_v2;
    837 								tFirstFace.m_v2 = tmp;
    838 							}
    839 						}
    840 					}
    841 				}
    842 
    843 				if ((i == 0) || !bStitchStrips) {
    844 					if (!isCW(strip.m_faces.at(0), tFirstFace.m_v0,
    845 							tFirstFace.m_v1))
    846 						stripIndices.add(tFirstFace.m_v0);
    847 				} else {
    848 					// Double tap the first in the new strip
    849 					stripIndices.add(tFirstFace.m_v0);
    850 
    851 					// Check CW/CCW ordering
    852 					if (nextIsCW(stripIndices.size() - accountForNegatives) != isCW(
    853 							strip.m_faces.at(0), tFirstFace.m_v0,
    854 							tFirstFace.m_v1)) {
    855 						stripIndices.add(tFirstFace.m_v0);
    856 					}
    857 				}
    858 
    859 				stripIndices.add(tFirstFace.m_v0);
    860 				stripIndices.add(tFirstFace.m_v1);
    861 				stripIndices.add(tFirstFace.m_v2);
    862 
    863 				// Update last face info
    864 				tLastFace.set(tFirstFace);
    865 			}
    866 
    867 			for (int j = 1; j < nStripFaceCount; j++) {
    868 				int nUnique = getUniqueVertexInB(tLastFace, strip.m_faces.at(j));
    869 				if (nUnique != -1) {
    870 					stripIndices.add(nUnique);
    871 
    872 					// Update last face info
    873 					tLastFace.m_v0 = tLastFace.m_v1;
    874 					tLastFace.m_v1 = tLastFace.m_v2;
    875 					tLastFace.m_v2 = nUnique;
    876 				} else {
    877 					//we've hit a degenerate
    878 					stripIndices.add(strip.m_faces.at(j).m_v2);
    879 					tLastFace.m_v0 = strip.m_faces.at(j).m_v0; //tLastFace.m_v1;
    880 					tLastFace.m_v1 = strip.m_faces.at(j).m_v1; //tLastFace.m_v2;
    881 					tLastFace.m_v2 = strip.m_faces.at(j).m_v2; //tLastFace.m_v1;
    882 
    883 				}
    884 			}
    885 
    886 			// Double tap between strips.
    887 			if (bStitchStrips) {
    888 				if (i != nStripCount - 1)
    889 					stripIndices.add(tLastFace.m_v2);
    890 			} else {
    891 				//-1 index indicates next strip
    892 				stripIndices.add(-1);
    893 				accountForNegatives++;
    894 				numSeparateStrips++;
    895 			}
    896 
    897 			// Update last face info
    898 			tLastFace.m_v0 = tLastFace.m_v1;
    899 			tLastFace.m_v1 = tLastFace.m_v2;
    900 			tLastFace.m_v2 = tLastFace.m_v2;
    901 		}
    902 
    903 		if (bStitchStrips)
    904 			numSeparateStrips = 1;
    905 		return numSeparateStrips;
    906 	}
    907 
    908 	///////////////////////////////////////////////////////////////////////////////////////////
    909 	// FindAllStrips()
    910 	//
    911 	// Does the stripification, puts output strips into vector allStrips
    912 	//
    913 	// Works by setting runnning a number of experiments in different areas of
    914 	// the mesh, and
    915 	//  accepting the one which results in the longest strips. It then accepts
    916 	// this, and moves
    917 	//  on to a different area of the mesh. We try to jump around the mesh some,
    918 	// to ensure that
    919 	//  large open spans of strips get generated.
    920 	//
    921 	void findAllStrips(StripInfoVec allStrips, FaceInfoVec allFaceInfos,
    922 			EdgeInfoVec allEdgeInfos, int numSamples) {
    923 		// the experiments
    924 		int experimentId = 0;
    925 		int stripId = 0;
    926 		boolean done = false;
    927 
    928 		int loopCtr = 0;
    929 
    930 		while (!done) {
    931 			loopCtr++;
    932 
    933 			//
    934 			// PHASE 1: Set up numSamples * numEdges experiments
    935 			//
    936 			StripInfoVec[] experiments = new StripInfoVec[numSamples * 6];
    937 			for (int i = 0; i < experiments.length; i++)
    938 				experiments[i] = new StripInfoVec();
    939 
    940 			int experimentIndex = 0;
    941 			HashSet<FaceInfo> resetPoints = new HashSet<FaceInfo>(); /* NvFaceInfo */
    942 			for (int i = 0; i < numSamples; i++) {
    943 				// Try to find another good reset point.
    944 				// If there are none to be found, we are done
    945 				FaceInfo nextFace = findGoodResetPoint(allFaceInfos,
    946 						allEdgeInfos);
    947 				if (nextFace == null) {
    948 					done = true;
    949 					break;
    950 				}
    951 				// If we have already evaluated starting at this face in this
    952 				// slew of experiments, then skip going any further
    953 				else if (resetPoints.contains(nextFace)) {
    954 					continue;
    955 				}
    956 
    957 				// trying it now...
    958 				resetPoints.add(nextFace);
    959 
    960 				// otherwise, we shall now try experiments for starting on the
    961 				// 01,12, and 20 edges
    962 
    963 				// build the strip off of this face's 0-1 edge
    964 				EdgeInfo edge01 = findEdgeInfo(allEdgeInfos, nextFace.m_v0,
    965 						nextFace.m_v1);
    966 				StripInfo strip01 = new StripInfo(new StripStartInfo(nextFace,
    967 						edge01, true), stripId++, experimentId++);
    968 				experiments[experimentIndex++].add(strip01);
    969 
    970 				// build the strip off of this face's 1-0 edge
    971 				EdgeInfo edge10 = findEdgeInfo(allEdgeInfos, nextFace.m_v0,
    972 						nextFace.m_v1);
    973 				StripInfo strip10 = new StripInfo(new StripStartInfo(nextFace,
    974 						edge10, false), stripId++, experimentId++);
    975 				experiments[experimentIndex++].add(strip10);
    976 
    977 				// build the strip off of this face's 1-2 edge
    978 				EdgeInfo edge12 = findEdgeInfo(allEdgeInfos, nextFace.m_v1,
    979 						nextFace.m_v2);
    980 				StripInfo strip12 = new StripInfo(new StripStartInfo(nextFace,
    981 						edge12, true), stripId++, experimentId++);
    982 				experiments[experimentIndex++].add(strip12);
    983 
    984 				// build the strip off of this face's 2-1 edge
    985 				EdgeInfo edge21 = findEdgeInfo(allEdgeInfos, nextFace.m_v1,
    986 						nextFace.m_v2);
    987 				StripInfo strip21 = new StripInfo(new StripStartInfo(nextFace,
    988 						edge21, false), stripId++, experimentId++);
    989 				experiments[experimentIndex++].add(strip21);
    990 
    991 				// build the strip off of this face's 2-0 edge
    992 				EdgeInfo edge20 = findEdgeInfo(allEdgeInfos, nextFace.m_v2,
    993 						nextFace.m_v0);
    994 				StripInfo strip20 = new StripInfo(new StripStartInfo(nextFace,
    995 						edge20, true), stripId++, experimentId++);
    996 				experiments[experimentIndex++].add(strip20);
    997 
    998 				// build the strip off of this face's 0-2 edge
    999 				EdgeInfo edge02 = findEdgeInfo(allEdgeInfos, nextFace.m_v2,
   1000 						nextFace.m_v0);
   1001 				StripInfo strip02 = new StripInfo(new StripStartInfo(nextFace,
   1002 						edge02, false), stripId++, experimentId++);
   1003 				experiments[experimentIndex++].add(strip02);
   1004 			}
   1005 
   1006 			//
   1007 			// PHASE 2: Iterate through that we setup in the last phase
   1008 			// and really build each of the strips and strips that follow to
   1009 			// see how
   1010 			// far we get
   1011 			//
   1012 			int numExperiments = experimentIndex;
   1013 			for (int i = 0; i < numExperiments; i++) {
   1014 
   1015 				// get the strip set
   1016 
   1017 				// build the first strip of the list
   1018 				experiments[i].at(0).build(allEdgeInfos, allFaceInfos);
   1019 				int experimentId2 = experiments[i].at(0).m_experimentId;
   1020 
   1021 				StripInfo stripIter = experiments[i].at(0);
   1022 				StripStartInfo startInfo = new StripStartInfo(null, null, false);
   1023 				while (findTraversal(allFaceInfos, allEdgeInfos, stripIter,
   1024 						startInfo)) {
   1025 
   1026 					// create the new strip info
   1027 					//TODO startInfo clone ?
   1028 					stripIter = new StripInfo(startInfo, stripId++,
   1029 							experimentId2);
   1030 
   1031 					// build the next strip
   1032 					stripIter.build(allEdgeInfos, allFaceInfos);
   1033 
   1034 					// add it to the list
   1035 					experiments[i].add(stripIter);
   1036 				}
   1037 			}
   1038 
   1039 			//
   1040 			// Phase 3: Find the experiment that has the most promise
   1041 			//
   1042 			int bestIndex = 0;
   1043 			double bestValue = 0;
   1044 			for (int i = 0; i < numExperiments; i++) {
   1045 				float avgStripSizeWeight = 1.0f;
   1046 				//float numTrisWeight = 0.0f;
   1047 				float numStripsWeight = 0.0f;
   1048 				float avgStripSize = avgStripSize(experiments[i]);
   1049 				float numStrips = experiments[i].size();
   1050 				float value = avgStripSize * avgStripSizeWeight
   1051 						+ (numStrips * numStripsWeight);
   1052 				//float value = 1.f / numStrips;
   1053 				//float value = numStrips * avgStripSize;
   1054 
   1055 				if (value > bestValue) {
   1056 					bestValue = value;
   1057 					bestIndex = i;
   1058 				}
   1059 			}
   1060 
   1061 			//
   1062 			// Phase 4: commit the best experiment of the bunch
   1063 			//
   1064 			commitStrips(allStrips, experiments[bestIndex]);
   1065 		}
   1066 	}
   1067 
   1068 	///////////////////////////////////////////////////////////////////////////////////////////
   1069 	// SplitUpStripsAndOptimize()
   1070 	//
   1071 	// Splits the input vector of strips (allBigStrips) into smaller, cache
   1072 	// friendly pieces, then
   1073 	//  reorders these pieces to maximize cache hits
   1074 	// The final strips are output through outStrips
   1075 	//
   1076 	void splitUpStripsAndOptimize(StripInfoVec allStrips,
   1077 			StripInfoVec outStrips, EdgeInfoVec edgeInfos,
   1078 			FaceInfoVec outFaceList) {
   1079 		int threshold = cacheSize;
   1080 		StripInfoVec tempStrips = new StripInfoVec();
   1081 		int j;
   1082 
   1083 		//split up strips into threshold-sized pieces
   1084 		for (int i = 0; i < allStrips.size(); i++) {
   1085 			StripInfo currentStrip;
   1086 			StripStartInfo startInfo = new StripStartInfo(null, null, false);
   1087 
   1088 			int actualStripSize = 0;
   1089 			for (j = 0; j < allStrips.at(i).m_faces.size(); ++j) {
   1090 				if (!isDegenerate(allStrips.at(i).m_faces.at(j)))
   1091 					actualStripSize++;
   1092 			}
   1093 
   1094 			if (actualStripSize /* allStrips.at(i).m_faces.size() */
   1095 			> threshold) {
   1096 
   1097 				int numTimes = actualStripSize /* allStrips.at(i).m_faces.size() */
   1098 						/ threshold;
   1099 				int numLeftover = actualStripSize /* allStrips.at(i).m_faces.size() */
   1100 						% threshold;
   1101 
   1102 				int degenerateCount = 0;
   1103 				for (j = 0; j < numTimes; j++) {
   1104 					currentStrip = new StripInfo(startInfo, 0, -1);
   1105 
   1106 					int faceCtr = j * threshold + degenerateCount;
   1107 					boolean bFirstTime = true;
   1108 					while (faceCtr < threshold + (j * threshold)
   1109 							+ degenerateCount) {
   1110 						if (isDegenerate(allStrips.at(i).m_faces.at(faceCtr))) {
   1111 							degenerateCount++;
   1112 
   1113 							//last time or first time through, no need for a
   1114 							// degenerate
   1115 							if ((((faceCtr + 1) != threshold + (j * threshold)
   1116 									+ degenerateCount) || ((j == numTimes - 1)
   1117 									&& (numLeftover < 4) && (numLeftover > 0)))
   1118 									&& !bFirstTime) {
   1119 								currentStrip.m_faces
   1120 										.add(allStrips.at(i).m_faces
   1121 												.at(faceCtr++));
   1122 							} else
   1123 								++faceCtr;
   1124 						} else {
   1125 							currentStrip.m_faces.add(allStrips.at(i).m_faces
   1126 									.at(faceCtr++));
   1127 							bFirstTime = false;
   1128 						}
   1129 					}
   1130 					/*
   1131 					 * threshold; faceCtr < threshold+(j*threshold); faceCtr++) {
   1132 					 * currentStrip.m_faces.add(allStrips.at(i).m_faces.at(faceCtr]); }
   1133 					 */
   1134 					///*
   1135 					if (j == numTimes - 1) //last time through
   1136 					{
   1137 						if ((numLeftover < 4) && (numLeftover > 0)) //way too
   1138 						// small
   1139 						{
   1140 							//just add to last strip
   1141 							int ctr = 0;
   1142 							while (ctr < numLeftover) {
   1143 								if (!isDegenerate(allStrips.at(i).m_faces
   1144 										.at(faceCtr))) {
   1145 									currentStrip.m_faces
   1146 											.add(allStrips.at(i).m_faces
   1147 													.at(faceCtr++));
   1148 									++ctr;
   1149 								} else {
   1150 									currentStrip.m_faces
   1151 											.add(allStrips.at(i).m_faces
   1152 													.at(faceCtr++));
   1153 									++degenerateCount;
   1154 								}
   1155 							}
   1156 							numLeftover = 0;
   1157 						}
   1158 					}
   1159 					//*/
   1160 					tempStrips.add(currentStrip);
   1161 				}
   1162 
   1163 				int leftOff = j * threshold + degenerateCount;
   1164 
   1165 				if (numLeftover != 0) {
   1166 					currentStrip = new StripInfo(startInfo, 0, -1);
   1167 
   1168 					int ctr = 0;
   1169 					boolean bFirstTime = true;
   1170 					while (ctr < numLeftover) {
   1171 						if (!isDegenerate(allStrips.at(i).m_faces.at(leftOff))) {
   1172 							ctr++;
   1173 							bFirstTime = false;
   1174 							currentStrip.m_faces.add(allStrips.at(i).m_faces
   1175 									.at(leftOff++));
   1176 						} else if (!bFirstTime)
   1177 							currentStrip.m_faces.add(allStrips.at(i).m_faces
   1178 									.at(leftOff++));
   1179 						else
   1180 							leftOff++;
   1181 					}
   1182 					/*
   1183 					 * for(int k = 0; k < numLeftover; k++) {
   1184 					 * currentStrip.m_faces.add(allStrips.at(i).m_faces[leftOff++]); }
   1185 					 */
   1186 
   1187 					tempStrips.add(currentStrip);
   1188 				}
   1189 			} else {
   1190 				//we're not just doing a tempStrips.add(allBigStrips[i])
   1191 				// because
   1192 				// this way we can delete allBigStrips later to free the memory
   1193 				currentStrip = new StripInfo(startInfo, 0, -1);
   1194 
   1195 				for (j = 0; j < allStrips.at(i).m_faces.size(); j++)
   1196 					currentStrip.m_faces.add(allStrips.at(i).m_faces.at(j));
   1197 
   1198 				tempStrips.add(currentStrip);
   1199 			}
   1200 		}
   1201 
   1202 		//add small strips to face list
   1203 		StripInfoVec tempStrips2 = new StripInfoVec();
   1204 		removeSmallStrips(tempStrips, tempStrips2, outFaceList);
   1205 
   1206 		outStrips.clear();
   1207 		//screw optimization for now
   1208 		//  for(i = 0; i < tempStrips.size(); ++i)
   1209 		//    outStrips.add(tempStrips[i]);
   1210 
   1211 		if (tempStrips2.size() != 0) {
   1212 			//Optimize for the vertex cache
   1213 			VertexCache vcache = new VertexCache(cacheSize);
   1214 
   1215 			float bestNumHits = -1.0f;
   1216 			float numHits;
   1217 			int bestIndex = -99999;
   1218 
   1219 			int firstIndex = 0;
   1220 			float minCost = 10000.0f;
   1221 
   1222 			for (int i = 0; i < tempStrips2.size(); i++) {
   1223 				int numNeighbors = 0;
   1224 
   1225 				//find strip with least number of neighbors per face
   1226 				for (j = 0; j < tempStrips2.at(i).m_faces.size(); j++) {
   1227 					numNeighbors += numNeighbors(tempStrips2.at(i).m_faces
   1228 							.at(j), edgeInfos);
   1229 				}
   1230 
   1231 				float currCost = (float) numNeighbors
   1232 						/ (float) tempStrips2.at(i).m_faces.size();
   1233 				if (currCost < minCost) {
   1234 					minCost = currCost;
   1235 					firstIndex = i;
   1236 				}
   1237 			}
   1238 
   1239 			updateCacheStrip(vcache, tempStrips2.at(firstIndex));
   1240 			outStrips.add(tempStrips2.at(firstIndex));
   1241 
   1242 			tempStrips2.at(firstIndex).visited = true;
   1243 
   1244 			boolean bWantsCW = (tempStrips2.at(firstIndex).m_faces.size() % 2) == 0;
   1245 
   1246 			//this n^2 algo is what slows down stripification so much....
   1247 			// needs to be improved
   1248 			while (true) {
   1249 				bestNumHits = -1.0f;
   1250 
   1251 				//find best strip to add next, given the current cache
   1252 				for (int i = 0; i < tempStrips2.size(); i++) {
   1253 					if (tempStrips2.at(i).visited)
   1254 						continue;
   1255 
   1256 					numHits = calcNumHitsStrip(vcache, tempStrips2.at(i));
   1257 					if (numHits > bestNumHits) {
   1258 						bestNumHits = numHits;
   1259 						bestIndex = i;
   1260 					} else if (numHits >= bestNumHits) {
   1261 						//check previous strip to see if this one requires it
   1262 						// to switch polarity
   1263 						StripInfo strip = tempStrips2.at(i);
   1264 						int nStripFaceCount = strip.m_faces.size();
   1265 
   1266 						FaceInfo tFirstFace = new FaceInfo(
   1267 								strip.m_faces.at(0).m_v0,
   1268 								strip.m_faces.at(0).m_v1,
   1269 								strip.m_faces.at(0).m_v2);
   1270 
   1271 						// If there is a second face, reorder vertices such
   1272 						// that the
   1273 						// unique vertex is first
   1274 						if (nStripFaceCount > 1) {
   1275 							int nUnique = getUniqueVertexInB(strip.m_faces
   1276 									.at(1), tFirstFace);
   1277 							if (nUnique == tFirstFace.m_v1) {
   1278 								int tmp = tFirstFace.m_v0;
   1279 								tFirstFace.m_v0 = tFirstFace.m_v1;
   1280 								tFirstFace.m_v1 = tmp;
   1281 							} else if (nUnique == tFirstFace.m_v2) {
   1282 								int tmp = tFirstFace.m_v0;
   1283 								tFirstFace.m_v0 = tFirstFace.m_v2;
   1284 								tFirstFace.m_v2 = tmp;
   1285 							}
   1286 
   1287 							// If there is a third face, reorder vertices such
   1288 							// that the
   1289 							// shared vertex is last
   1290 							if (nStripFaceCount > 2) {
   1291 								int[] nShared = new int[2];
   1292 								getSharedVertices(strip.m_faces.at(2),
   1293 										tFirstFace, nShared);
   1294 								if ((nShared[0] == tFirstFace.m_v1)
   1295 										&& (nShared[1] == -1)) {
   1296 									int tmp = tFirstFace.m_v2;
   1297 									tFirstFace.m_v2 = tFirstFace.m_v1;
   1298 									tFirstFace.m_v1 = tmp;
   1299 								}
   1300 							}
   1301 						}
   1302 
   1303 						// Check CW/CCW ordering
   1304 						if (bWantsCW == isCW(strip.m_faces.at(0),
   1305 								tFirstFace.m_v0, tFirstFace.m_v1)) {
   1306 							//I like this one!
   1307 							bestIndex = i;
   1308 						}
   1309 					}
   1310 				}
   1311 
   1312 				if (bestNumHits == -1.0f)
   1313 					break;
   1314 				tempStrips2.at(bestIndex).visited = true;
   1315 				updateCacheStrip(vcache, tempStrips2.at(bestIndex));
   1316 				outStrips.add(tempStrips2.at(bestIndex));
   1317 				bWantsCW = (tempStrips2.at(bestIndex).m_faces.size() % 2 == 0) ? bWantsCW
   1318 						: !bWantsCW;
   1319 			}
   1320 		}
   1321 	}
   1322 
   1323 	///////////////////////////////////////////////////////////////////////////////////////////
   1324 	// Stripify()
   1325 	//
   1326 	//
   1327 	// in_indices are the input indices of the mesh to stripify
   1328 	// in_cacheSize is the target cache size
   1329 	//
   1330 	void stripify(IntVec in_indices, int in_cacheSize, int in_minStripLength,
   1331 			int maxIndex, StripInfoVec outStrips, FaceInfoVec outFaceList) {
   1332 		meshJump = 0.0f;
   1333 		bFirstTimeResetPoint = true; //used in FindGoodResetPoint()
   1334 
   1335 		//the number of times to run the experiments
   1336 		int numSamples = 10;
   1337 
   1338 		//the cache size, clamped to one
   1339 		cacheSize = Math.max(1, in_cacheSize - CACHE_INEFFICIENCY);
   1340 
   1341 		minStripLength = in_minStripLength;
   1342 		//this is the strip size threshold below which we dump the strip into
   1343 		// a list
   1344 
   1345 		indices = in_indices;
   1346 
   1347 		// build the stripification info
   1348 		FaceInfoVec allFaceInfos = new FaceInfoVec();
   1349 		EdgeInfoVec allEdgeInfos = new EdgeInfoVec();
   1350 
   1351 		buildStripifyInfo(allFaceInfos, allEdgeInfos, maxIndex);
   1352 
   1353 		StripInfoVec allStrips = new StripInfoVec();
   1354 
   1355 		// stripify
   1356 		findAllStrips(allStrips, allFaceInfos, allEdgeInfos, numSamples);
   1357 
   1358 		//split up the strips into cache friendly pieces, optimize them, then
   1359 		// dump these into outStrips
   1360 		splitUpStripsAndOptimize(allStrips, outStrips, allEdgeInfos,
   1361 				outFaceList);
   1362 
   1363 	}
   1364 
   1365 }