#----------------------------------------------------------------
# $Id: //src/racer/VertOpt.py#2 $
# $Date: 2005/06/08 $
#----------------------------------------------------------------
# This file may be copied.  However, if you make improvements,
# please send me a copy.
#
# Brent Burton <brentb@relro.net>
# Originally released: July 2003
# RaceSimCentral: vizor_atx
#----------------------------------------------------------------
#
# Optimize vertex storage by looking for duplicated
# verts.  A vertex is the 8-dimensional vector 
# (X, Y, Z, U, V, I, J, K)
# or, 3D position with 2D texture coordinates and a 
# 3-dimensional normal vector.
#
# Instead of using trees/octtrees/etc, use a dictionary to map
# XYZUVIJK to unique integers.  Keys are binary strings of 
# length 32 bytes, values are integer indices.

import struct

# VertexOptimizer
class VO:
    def __init__(self):
        self._dict = {}
        self._reverse = {}
        self._lastIndex = -1

    def _makeKey(self, v):
        # xyzuvijk is a sequence type
        return struct.pack("ffffffff", v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])

    def hasVertex(self, face):
        """Is a particular coordinate already in the optimizer?
        Return the index in [0...numVerts) if so.  -1 if not."""
        if len(face) != 8: return -1
        key = self._makeKey(face)
        if not self._dict.has_key(key): return -1
        return self._dict[key]

    def addVertex(self, face):
        "Add a new 5-tuple to the optimizer.  Return its index."
        if len(face) != 8: return -1
        key = self._makeKey(face)
        if self._dict.has_key(key):
            return self._dict[key]
        self._lastIndex += 1
        self._dict[key] = self._lastIndex   # forward mapping: key->index
        self._reverse[self._lastIndex] = key # reverse mapping: index->key
        return self._lastIndex

    def numVertices(self):
        "Return the number of unique vertices in the optimizer."
        return self._lastIndex+1

    def getVertex(self, idx):
        "Return the 8-tuple XYZUVIJK stored at the index."
        if idx >= len(self._reverse): return None
        if not self._reverse.has_key(idx): return None
        return struct.unpack("ffffffff", self._reverse[idx])

#----------------
#if __name__ == "__main__":
#    vo = VO()
#    print "has 0,0,0,0,0: %d" % (vo.hasVertex((0.0, 0.0, 0.0, 0.0, 0.0)))
#    vo.addVertex((0.0, 0.0, 0.0, 0.0, 0.0))
#    vo.addVertex((0.0, 0.0, 0.0, 0.0, 1.0))
#    vo.addVertex((0.0, 0.0, 0.0, 1.0, 1.0))
#    vo.addVertex((0.0, 0.0, 0.0, 1.0, 0.0)) # should stay at 4
#
#    vo.addVertex((0.0, 0.0, 0.0, 1.0, 0.0))
#    vo.addVertex((0.0, 0.0, 0.0, 1.0, 0.0))
#    vo.addVertex((0.0, 0.0, 0.0, 1.0, 0.0))
#    vo.addVertex((0.0, 0.0, 0.0, 1.0, 0.0))
#    vo.addVertex((0.0, 0.0, 0.0, 1.0, 0.0))
#
#    print "has 0,0,0,0,0: %d" % (vo.hasVertex((0.0, 0.0, 0.0, 0.0, 0.0)))
#    print "has 0,0,0,1,0: %d" % (vo.hasVertex((0.0, 0.0, 0.0, 1.0, 0.0)))
#    print "vo has %d verts" % (vo.numVertices())
#    print "vo[3] is " + str(vo.getVertex(3))
