コード例 #1
0
class CogdoFlyingCameraManager:
    def __init__(self, cam, parent, player, level):
        self._toon = player.toon
        self._camera = cam
        self._parent = parent
        self._player = player
        self._level = level
        self._enabled = False

    def enable(self):
        if self._enabled:
            return
        self._toon.detachCamera()
        self._prevToonY = 0.0
        levelBounds = self._level.getBounds()
        l = Globals.Camera.LevelBoundsFactor
        self._bounds = (
            (levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]),
            (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]),
            (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]),
        )
        self._lookAtZ = self._toon.getHeight() + Globals.Camera.LookAtToonHeightOffset
        self._camParent = NodePath("CamParent")
        self._camParent.reparentTo(self._parent)
        self._camParent.setPos(self._toon, 0, 0, 0)
        self._camParent.setHpr(180, Globals.Camera.Angle, 0)
        self._camera.reparentTo(self._camParent)
        self._camera.setPos(0, Globals.Camera.Distance, 0)
        self._camera.lookAt(self._toon, 0, 0, self._lookAtZ)
        self._cameraLookAtNP = NodePath("CameraLookAt")
        self._cameraLookAtNP.reparentTo(self._camera.getParent())
        self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr())
        self._levelBounds = self._level.getBounds()
        self._enabled = True
        self._frozen = False
        self._initCollisions()

    def _initCollisions(self):
        self._camCollRay = CollisionRay()
        camCollNode = CollisionNode("CameraToonRay")
        camCollNode.addSolid(self._camCollRay)
        camCollNode.setFromCollideMask(
            OTPGlobals.WallBitmask
            | OTPGlobals.CameraBitmask
            | ToontownGlobals.FloorEventBitmask
            | ToontownGlobals.CeilingBitmask
        )
        camCollNode.setIntoCollideMask(0)
        self._camCollNP = self._camera.attachNewNode(camCollNode)
        self._camCollNP.show()
        self._collOffset = Vec3(0, 0, 0.5)
        self._collHandler = CollisionHandlerQueue()
        self._collTrav = CollisionTraverser()
        self._collTrav.addCollider(self._camCollNP, self._collHandler)
        self._betweenCamAndToon = {}
        self._transNP = NodePath("trans")
        self._transNP.reparentTo(render)
        self._transNP.setTransparency(True)
        self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon)
        self._transNP.setBin("fixed", 10000)

    def _destroyCollisions(self):
        self._collTrav.removeCollider(self._camCollNP)
        self._camCollNP.removeNode()
        del self._camCollNP
        del self._camCollRay
        del self._collHandler
        del self._collOffset
        del self._betweenCamAndToon
        self._transNP.removeNode()
        del self._transNP

    def freeze(self):
        self._frozen = True

    def unfreeze(self):
        self._frozen = False

    def disable(self):
        if not self._enabled:
            return
        self._destroyCollisions()
        self._camera.wrtReparentTo(render)
        self._cameraLookAtNP.removeNode()
        del self._cameraLookAtNP
        self._camParent.removeNode()
        del self._camParent
        del self._prevToonY
        del self._lookAtZ
        del self._bounds
        del self._frozen
        self._enabled = False

    def update(self, dt=0.0):
        self._updateCam(dt)
        self._updateCollisions()

    def _updateCam(self, dt):
        toonPos = self._toon.getPos()
        camPos = self._camParent.getPos()
        x = camPos[0]
        z = camPos[2]
        toonWorldX = self._toon.getX(render)
        maxX = Globals.Camera.MaxSpinX
        toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX)
        spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (maxX * maxX)
        newH = 180.0 + spinAngle
        self._camParent.setH(newH)
        spinAngle = spinAngle * (pi / 180.0)
        distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle)
        distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle)
        d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0])
        if abs(d) > Globals.Camera.LeewayX:
            if d > Globals.Camera.LeewayX:
                x = toonPos[0] + Globals.Camera.LeewayX
            else:
                x = toonPos[0] - Globals.Camera.LeewayX
        x = self._toon.getX(render) + distToRightOfToon
        boundToonZ = min(toonPos[2], self._bounds[2][1])
        d = z - boundToonZ
        if d > Globals.Camera.MinLeewayZ:
            if self._player.velocity[2] >= 0 and toonPos[1] != self._prevToonY or self._player.velocity[2] > 0:
                z = boundToonZ + d * INVERSE_E ** (dt * Globals.Camera.CatchUpRateZ)
            elif d > Globals.Camera.MaxLeewayZ:
                z = boundToonZ + Globals.Camera.MaxLeewayZ
        elif d < -Globals.Camera.MinLeewayZ:
            z = boundToonZ - Globals.Camera.MinLeewayZ
        if self._frozen:
            y = camPos[1]
        else:
            y = self._toon.getY(render) - distBehindToon
        self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z))
        if toonPos[2] < self._bounds[2][1]:
            h = self._cameraLookAtNP.getH()
            if d >= Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ)
            elif d <= -Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ)
            self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0)
            self._camera.setHpr(smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr()))
        self._prevToonY = toonPos[1]

    def _updateCollisions(self):
        pos = self._toon.getPos(self._camera) + self._collOffset
        self._camCollRay.setOrigin(pos)
        direction = -Vec3(pos)
        direction.normalize()
        self._camCollRay.setDirection(direction)
        self._collTrav.traverse(render)
        nodesInBetween = {}
        if self._collHandler.getNumEntries() > 0:
            self._collHandler.sortEntries()
            for entry in self._collHandler.getEntries():
                name = entry.getIntoNode().getName()
                if name.find("col_") >= 0:
                    np = entry.getIntoNodePath().getParent()
                    if not nodesInBetween.has_key(np):
                        nodesInBetween[np] = np.getParent()

        for np in nodesInBetween.keys():
            if self._betweenCamAndToon.has_key(np):
                del self._betweenCamAndToon[np]
            else:
                np.setTransparency(True)
                np.wrtReparentTo(self._transNP)
                if np.getName().find("lightFixture") >= 0:
                    if not np.find("**/*floor_mesh").isEmpty():
                        np.find("**/*floor_mesh").hide()
                elif np.getName().find("platform") >= 0:
                    if not np.find("**/*Floor").isEmpty():
                        np.find("**/*Floor").hide()

        for np, parent in self._betweenCamAndToon.items():
            np.wrtReparentTo(parent)
            np.setTransparency(False)
            if np.getName().find("lightFixture") >= 0:
                if not np.find("**/*floor_mesh").isEmpty():
                    np.find("**/*floor_mesh").show()
            elif np.getName().find("platform") >= 0:
                if not np.find("**/*Floor").isEmpty():
                    np.find("**/*Floor").show()

        self._betweenCamAndToon = nodesInBetween
コード例 #2
0
class CogdoFlyingCameraManager:
    def __init__(self, cam, parent, player, level):
        self._toon = player.toon
        self._camera = cam
        self._parent = parent
        self._player = player
        self._level = level
        self._enabled = False

    def enable(self):
        if self._enabled:
            return
        self._toon.detachCamera()
        self._prevToonY = 0.0
        levelBounds = self._level.getBounds()
        l = Globals.Camera.LevelBoundsFactor
        self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]),
                        (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]),
                        (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]))
        self._lookAtZ = self._toon.getHeight(
        ) + Globals.Camera.LookAtToonHeightOffset
        self._camParent = NodePath('CamParent')
        self._camParent.reparentTo(self._parent)
        self._camParent.setPos(self._toon, 0, 0, 0)
        self._camParent.setHpr(180, Globals.Camera.Angle, 0)
        self._camera.reparentTo(self._camParent)
        self._camera.setPos(0, Globals.Camera.Distance, 0)
        self._camera.lookAt(self._toon, 0, 0, self._lookAtZ)
        self._cameraLookAtNP = NodePath('CameraLookAt')
        self._cameraLookAtNP.reparentTo(self._camera.getParent())
        self._cameraLookAtNP.setPosHpr(self._camera.getPos(),
                                       self._camera.getHpr())
        self._levelBounds = self._level.getBounds()
        self._enabled = True
        self._frozen = False
        self._initCollisions()

    def _initCollisions(self):
        self._camCollRay = CollisionRay()
        camCollNode = CollisionNode('CameraToonRay')
        camCollNode.addSolid(self._camCollRay)
        camCollNode.setFromCollideMask(OTPGlobals.WallBitmask
                                       | OTPGlobals.CameraBitmask
                                       | ToontownGlobals.FloorEventBitmask
                                       | ToontownGlobals.CeilingBitmask)
        camCollNode.setIntoCollideMask(0)
        self._camCollNP = self._camera.attachNewNode(camCollNode)
        self._camCollNP.show()
        self._collOffset = Vec3(0, 0, 0.5)
        self._collHandler = CollisionHandlerQueue()
        self._collTrav = CollisionTraverser()
        self._collTrav.addCollider(self._camCollNP, self._collHandler)
        self._betweenCamAndToon = {}
        self._transNP = NodePath('trans')
        self._transNP.reparentTo(render)
        self._transNP.setTransparency(True)
        self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon)
        self._transNP.setBin('fixed', 10000)

    def _destroyCollisions(self):
        self._collTrav.removeCollider(self._camCollNP)
        self._camCollNP.removeNode()
        del self._camCollNP
        del self._camCollRay
        del self._collHandler
        del self._collOffset
        del self._betweenCamAndToon
        self._transNP.removeNode()
        del self._transNP

    def freeze(self):
        self._frozen = True

    def unfreeze(self):
        self._frozen = False

    def disable(self):
        if not self._enabled:
            return
        self._destroyCollisions()
        self._camera.wrtReparentTo(render)
        self._cameraLookAtNP.removeNode()
        del self._cameraLookAtNP
        self._camParent.removeNode()
        del self._camParent
        del self._prevToonY
        del self._lookAtZ
        del self._bounds
        del self._frozen
        self._enabled = False

    def update(self, dt=0.0):
        self._updateCam(dt)
        self._updateCollisions()

    def _updateCam(self, dt):
        toonPos = self._toon.getPos()
        camPos = self._camParent.getPos()
        x = camPos[0]
        z = camPos[2]
        toonWorldX = self._toon.getX(render)
        maxX = Globals.Camera.MaxSpinX
        toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX)
        spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (
            maxX * maxX)
        newH = 180.0 + spinAngle
        self._camParent.setH(newH)
        spinAngle = spinAngle * (pi / 180.0)
        distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle)
        distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle)
        d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0])
        if abs(d) > Globals.Camera.LeewayX:
            if d > Globals.Camera.LeewayX:
                x = toonPos[0] + Globals.Camera.LeewayX
            else:
                x = toonPos[0] - Globals.Camera.LeewayX
        x = self._toon.getX(render) + distToRightOfToon
        boundToonZ = min(toonPos[2], self._bounds[2][1])
        d = z - boundToonZ
        if d > Globals.Camera.MinLeewayZ:
            if self._player.velocity[2] >= 0 and toonPos[
                    1] != self._prevToonY or self._player.velocity[2] > 0:
                z = boundToonZ + d * INVERSE_E**(dt *
                                                 Globals.Camera.CatchUpRateZ)
            elif d > Globals.Camera.MaxLeewayZ:
                z = boundToonZ + Globals.Camera.MaxLeewayZ
        elif d < -Globals.Camera.MinLeewayZ:
            z = boundToonZ - Globals.Camera.MinLeewayZ
        if self._frozen:
            y = camPos[1]
        else:
            y = self._toon.getY(render) - distBehindToon
        self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z))
        if toonPos[2] < self._bounds[2][1]:
            h = self._cameraLookAtNP.getH()
            if d >= Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ)
            elif d <= -Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._camParent, 0, 0,
                                            self._lookAtZ)
            self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0)
            self._camera.setHpr(
                smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr()))
        self._prevToonY = toonPos[1]

    def _updateCollisions(self):
        pos = self._toon.getPos(self._camera) + self._collOffset
        self._camCollRay.setOrigin(pos)
        direction = -Vec3(pos)
        direction.normalize()
        self._camCollRay.setDirection(direction)
        self._collTrav.traverse(render)
        nodesInBetween = {}
        if self._collHandler.getNumEntries() > 0:
            self._collHandler.sortEntries()
            for entry in self._collHandler.getEntries():
                name = entry.getIntoNode().getName()
                if name.find('col_') >= 0:
                    np = entry.getIntoNodePath().getParent()
                    if not np in nodesInBetween:
                        nodesInBetween[np] = np.getParent()

        for np in nodesInBetween.keys():
            if np in self._betweenCamAndToon:
                del self._betweenCamAndToon[np]
            else:
                np.setTransparency(True)
                np.wrtReparentTo(self._transNP)
                if np.getName().find('lightFixture') >= 0:
                    if not np.find('**/*floor_mesh').isEmpty():
                        np.find('**/*floor_mesh').hide()
                elif np.getName().find('platform') >= 0:
                    if not np.find('**/*Floor').isEmpty():
                        np.find('**/*Floor').hide()

        for np, parent in self._betweenCamAndToon.items():
            np.wrtReparentTo(parent)
            np.setTransparency(False)
            if np.getName().find('lightFixture') >= 0:
                if not np.find('**/*floor_mesh').isEmpty():
                    np.find('**/*floor_mesh').show()
            elif np.getName().find('platform') >= 0:
                if not np.find('**/*Floor').isEmpty():
                    np.find('**/*Floor').show()

        self._betweenCamAndToon = nodesInBetween
コード例 #3
0
ファイル: AreaMapper.py プロジェクト: satire6/Anesidora
class AreaMapper(object):
    def __init__(self, environment):
        '''
        Create a map of the free space in a given area.
        '''
        self.csRadius = 1
        self.csHeight = 2
        self.avatarRadius = 1.4
        self.cs = CollisionSphere(0, 0, 0, 1)

        self.csNode = CollisionNode("AreaMapperCollisionSphere")
        self.csNode.setFromCollideMask(OTPGlobals.WallBitmask)
        self.csNode.setIntoCollideMask(BitMask32.allOff())
        self.csNode.addSolid(self.cs)

        self.environment = environment

        self.csNodePath = self.environment.getTop().attachNewNode(self.csNode)

        self.floorRay = CollisionRay()
        self.floorRay.setDirection(0, 0, -1)
        self.floorRay.setOrigin(0, 0, 0)

        self.floorRayNode = CollisionNode("AreaMapperFloorRay")
        self.floorRayNode.setFromCollideMask(OTPGlobals.FloorBitmask)
        self.floorRayNode.setIntoCollideMask(BitMask32.allOff())
        self.floorRayNode.addSolid(self.floorRay)

        self.floorRayNodePath = self.environment.getTop().attachNewNode(
            self.floorRayNode)

        self.chq = CollisionHandlerQueue()
        self.traverser = CollisionTraverser()

        self.startX = 0
        self.startY = 0
        self.startZ = 0

        self.frontierSquares = {(0, 0): 1}
        self.frontierSquaresQueue = [(0, 0)]
        self.walkableSquares = {(0, 0): 1}
        self.blockedSquares = {}

        self.setSquareSize(2)
        self.startAtPlayerSpawn()

        self.visGeom = None
        self.visGN = None
        self.visNodePath = None

        self.triVertexLookup = {}
        self.triList = []

        self.minX = 500
        self.maxX = -500
        self.minY = 500
        self.maxY = -500

        self.quadTree = QuadTree(width=1024)
        self.squares = []

        self.runDiscovery(100000)

        self._subdivide()

        #self._fixZValues()

        self.csNodePath.removeNode()
        self.floorRayNodePath.removeNode()

##     def _unstashEnvironment(self):
##         # Would be nice if we could just do this  :(
##         #for np in self.environment.findAllMatches("**/+CollisionNode;+s"):
##         #    np.unstash()
##         b = self.environment.builder
##         for s in b.sections.values():
##             s.unstash()
##         for o in b.largeObjects.values():
##             o.unstash()

    def setStart(self, x, y):
        self.startX = x
        self.startY = y
        self.startZ = self.findFloor(x, y)

    def startAtLocalAvatar(self):
        startPos = localAvatar.getPos(self.environment)
        self.setStart(startPos.getX(), startPos.getY())

    def startAtPlayerSpawn(self):
        # XXX Bleugh, this is really pirates-specific.  Nasty.
        for spawnPt in self.environment.world.getAllPlayerSpawnPts():
            parentDoId = self.environment.world.uidMgr.getDoId(spawnPt[1])
            if parentDoId == self.environment.doId:
                # Sweet, we found a spawn point for this grid's gamearea.  Use it!

                z = self.findFloor(spawnPt[0][0], spawnPt[0][1])
                if not self.isSphereBlocked(spawnPt[0][0], spawnPt[0][1], z):
                    self.setStart(spawnPt[0][0], spawnPt[0][1])
                    return

        raise "No player spawn points found for the given game area!  D:"

    def setSquareSize(self, size):
        self.squareSize = size
        self.csRadius = math.sqrt(
            2 * (self.squareSize * self.squareSize / 4)) + self.avatarRadius
        self.csNodePath.setScale(self.environment, self.csRadius,
                                 self.csRadius, self.csRadius)
        self.csHeight = self.csRadius * 2

    def findFloor(self, x, y):
        self.floorRayNodePath.setPos(self.environment, x, y, 50000)

        self.chq.clearEntries()

        self.traverser.clearColliders()
        self.traverser.addCollider(self.floorRayNodePath, self.chq)
        self.traverser.traverse(self.environment)

        highestZ = -50000

        for e in self.chq.getEntries():
            assert e.hasInto()
            assert e.getInto().isTangible()
            assert e.hasSurfacePoint()

            z = e.getSurfacePoint(self.environment).getZ()

            if z > highestZ:
                highestZ = z

        return highestZ

    def isSphereBlocked(self, x, y, z):
        if z < self.csHeight:
            return True

        self.csNodePath.setPos(self.environment, x, y, z)

        self.chq.clearEntries()

        self.traverser.clearColliders()
        self.traverser.addCollider(self.csNodePath, self.chq)
        self.traverser.traverse(self.environment)

        for entry in self.chq.getEntries():
            if entry.hasInto():
                if entry.getInto().isTangible():
                    return True

        return False

    def _neighbors(self, x, y):
        return [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]

    def _explore(self, p):
        x, y = p
        x1 = self.startX + self.squareSize * x
        y1 = self.startY + self.squareSize * y
        z1 = self.findFloor(x1, y1)
        if self.isSphereBlocked(x1, y1, z1 + self.csHeight):
            self.blockedSquares[p] = z1
            return
        else:
            self.walkableSquares[p] = z1
            self.quadTree.fill(x, y)
            for n in self._neighbors(x, y):
                if not (n in self.frontierSquares or n in self.walkableSquares
                        or n in self.blockedSquares):
                    self.frontierSquares[n] = 1
                    self.frontierSquaresQueue.append(n)

    def _exploreFrontier(self):
        if len(self.frontierSquaresQueue) == 0:
            assert len(self.frontierSquares.keys()) == 0
            return 0
        else:
            qlen = len(self.frontierSquaresQueue)
            for i in xrange(qlen):
                p = self.frontierSquaresQueue.pop(0)
                del self.frontierSquares[p]
                self._explore(p)
            return qlen

    def runDiscovery(self, maxSquares):
        print "Discovering walkable space (this will take 30-60 seconds)..."
        #self._unstashEnvironment()
        squaresExplored = 1

        self.walkableSquares[(0, 0)] = self.findFloor(self.startX, self.startY)

        while (squaresExplored < maxSquares) and (len(
                self.frontierSquaresQueue) > 0):
            squaresExplored += self._exploreFrontier()

##     def visualize(self):
##         gFormat = GeomVertexFormat.getV3cp()
##         self.vertexData = GeomVertexData("OMGVERTEXDATA", gFormat, Geom.UHDynamic)
##         self.vertexWriter = GeomVertexWriter(self.vertexData, "vertex")
##         self.colorWriter = GeomVertexWriter(self.vertexData, "color")

##         numVerts = 0

##         for xa,ya,xb,yb in self.squares:
##             x1 = self.startX + self.squareSize*(xa) - self.squareSize*0.5
##             y1 = self.startY + self.squareSize*(ya) - self.squareSize*0.5

##             x2 = self.startX + self.squareSize*(xb) + self.squareSize*0.5
##             y2 = self.startY + self.squareSize*(yb) + self.squareSize*0.5

##             self.vertexWriter.addData3f(x1,y1,self.findFloor(x1,y1)+0.1)
##             self.colorWriter.addData4f(0.0, 1.0, 0.0, 0.5)

##             self.vertexWriter.addData3f(x2,y1,self.findFloor(x2,y1)+0.1)
##             self.colorWriter.addData4f(0.0, 1.0, 0.0, 0.5)

##             self.vertexWriter.addData3f(x2,y2,self.findFloor(x2,y2)+0.1)
##             self.colorWriter.addData4f(0.0, 1.0, 0.0, 0.5)

##             self.vertexWriter.addData3f(x1,y2,self.findFloor(x1,y2)+0.1)
##             self.colorWriter.addData4f(0.0, 1.0, 0.0, 0.5)

##             numVerts += 4

##         print "NUMVERTS: ", numVerts

##         self.pointVis = GeomLinestrips(Geom.UHStatic)

##         for i in xrange(numVerts/4):
##             self.pointVis.addVertex(i*4)
##             self.pointVis.addVertex(i*4+1)
##             self.pointVis.addVertex(i*4+2)
##             self.pointVis.addVertex(i*4+3)
##             self.pointVis.addVertex(i*4)
##             self.pointVis.closePrimitive()

##         self.visGeom = Geom(self.vertexData)
##         self.visGeom.addPrimitive(self.pointVis)

##         self.visGN = GeomNode("NavigationGridVis")
##         self.visGN.addGeom(self.visGeom)

##         self.visNodePath = self.environment.attachNewNode(self.visGN)

##         self.visNodePath.setTwoSided(True)
##         self.visNodePath.setRenderModeThickness(4)
##         #self.visNodePath.setTransparency(1)

# ---------- Begin Triangulation Code ------------

##     def _addTriVertex(self,x,y):
##         '''
##         lookup[(x,y)] is a reference to the vert located to the UPPER-LEFT of grid square (x,y)
##         '''
##         if (x,y) not in self.gridCoordToVertexId:
##             vId = self.vertexCounter
##             self.vertexCounter += 1

##             self.gridCoordToVertexId[(x,y)] = vId

##             x1 = self.startX + self.squareSize*x - (0.5 * self.squareSize)
##             y1 = self.startY + self.squareSize*y - (0.5 * self.squareSize)
##             z1 = self.findFloor(x1,y1)
##             self.vertexIdToXYZ[vId] = (x1,y1,z1)

##             self.vertexToTris[vId] = []

##         return self.gridCoordToVertexId[(x,y)]

##     def _triangulateGridSquare(self,x,y,left=True):
##         a = self._addTriVertex(x,y)
##         b = self._addTriVertex(x+1,y)
##         c = self._addTriVertex(x+1,y+1)
##         d = self._addTriVertex(x,y+1)

##         if x < self.minX:
##             self.minX = x
##         if x > self.maxX:
##             self.maxX = x
##         if y < self.minY:
##             self.minY = y
##         if y > self.maxY:
##             self.maxY = y

##         if left:
##             self.triToVertices[self.triCounter] = [a,b,d]
##             self.triToAngles[self.triCounter] = [90,45,45]

##             self.triToVertices[self.triCounter+1] = [b,c,d]
##             self.triToAngles[self.triCounter+1] = [45,90,45]

##             self.vertexToTris[a].append(self.triCounter)
##             self.vertexToTris[b].append(self.triCounter)
##             self.vertexToTris[b].append(self.triCounter+1)
##             self.vertexToTris[c].append(self.triCounter+1)
##             self.vertexToTris[d].append(self.triCounter)
##             self.vertexToTris[d].append(self.triCounter+1)
##         else:
##             self.triToVertices[self.triCounter] = [a,b,c]
##             self.triToAngles[self.triCounter] = [45,90,45]

##             self.triToVertices[self.triCounter+1] = [a,c,d]
##             self.triToAngles[self.triCounter+1] = [45,45,90]

##             self.vertexToTris[a].append(self.triCounter)
##             self.vertexToTris[a].append(self.triCounter+1)
##             self.vertexToTris[b].append(self.triCounter)
##             self.vertexToTris[c].append(self.triCounter)
##             self.vertexToTris[c].append(self.triCounter+1)
##             self.vertexToTris[d].append(self.triCounter+1)

##         self.triCounter += 2

##     def countCruft(self):
##         count = 0
##         for s in self.squares:
##             if (s[0] == s[2]) and (s[1] == s[3]):
##                 x = s[0]
##                 y = s[1]
##                 numNeighbors = 0
##                 for (x1,y1) in [(x+1,y),(x-1,y),(x,y+1),(x,y-1)]:
##                     if (x1,y1) in self.walkableSquares:
##                         numNeighbors += 1
##                 if numNeighbors < 3:
##                     count += 1
##         return count

##     def killCruft(self):
##         for i in xrange(len(self.squares)):
##             s = self.squares[i]
##             if (s[0] == s[2]) and (s[1] == s[3]):
##                 x = s[0]
##                 y = s[1]
##                 numNeighbors = 0
##                 for (x1,y1) in [(x+1,y),(x-1,y),(x,y+1),(x,y-1)]:
##                     if (x1,y1) in self.walkableSquares:
##                         numNeighbors += 1
##                 if numNeighbors < 3:
##                     self.squares[i] = None

##         self.squares = [s for s in self.squares if s != None]

    def _addVertexByGridCoords(self, x, y):
        '''
        lookup[(x,y)] is a reference to the vert located at (-0.5,-0.5) from grid square (x,y)
        '''
        if (x, y) not in self.gridCoordToVertexId:
            vId = self.vertexCounter
            self.vertexCounter += 1

            self.gridCoordToVertexId[(x, y)] = vId

            x1 = self.startX + self.squareSize * x - (0.5 * self.squareSize)
            y1 = self.startY + self.squareSize * y - (0.5 * self.squareSize)
            z1 = self.findFloor(x1, y1)
            self.vertexIdToXYZ[vId] = (x1, y1, z1)

            self.vertToPolys[vId] = []

        return self.gridCoordToVertexId[(x, y)]

    def _addOpenSquare(self, gridX1, gridY1, gridX2, gridY2):
        curSpot = [gridX1, gridY1]

        verts = []
        angles = []

        while curSpot[0] <= gridX2:
            verts.append(self._addVertexByGridCoords(curSpot[0], curSpot[1]))
            if curSpot[0] == gridX1:
                angles.append(90)
            else:
                angles.append(180)
            self.vertToPolys[verts[-1]].append(self.polyCounter)
            curSpot[0] += 1

        while curSpot[1] <= gridY2:
            verts.append(self._addVertexByGridCoords(curSpot[0], curSpot[1]))
            if curSpot[1] == gridY1:
                angles.append(90)
            else:
                angles.append(180)
            self.vertToPolys[verts[-1]].append(self.polyCounter)
            curSpot[1] += 1

        while curSpot[0] > gridX1:
            verts.append(self._addVertexByGridCoords(curSpot[0], curSpot[1]))
            if curSpot[0] == gridX2 + 1:
                angles.append(90)
            else:
                angles.append(180)
            self.vertToPolys[verts[-1]].append(self.polyCounter)
            curSpot[0] -= 1

        while curSpot[1] > gridY1:
            if curSpot[1] == gridY2 + 1:
                angles.append(90)
            else:
                angles.append(180)
            verts.append(self._addVertexByGridCoords(curSpot[0], curSpot[1]))
            self.vertToPolys[verts[-1]].append(self.polyCounter)
            curSpot[1] -= 1

        self.polyToVerts[self.polyCounter] = verts
        self.polyToAngles[self.polyCounter] = angles
        self.polyCounter += 1

    def _subdivide(self):
        print "Growing squares..."
        self.vertexCounter = 0
        self.polyCounter = 0

        self.gridCoordToVertexId = {}
        self.vertexIdToXYZ = {}

        self.polyToVerts = {}
        self.polyToAngles = {}
        self.vertToPolys = {}

        self.squares = self.quadTree.squarify()

        for (gridX1, gridY1, gridX2, gridY2) in self.squares:
            self._addOpenSquare(gridX1, gridY1, gridX2, gridY2)