Example #1
0
class MyApp(ShowBase):
	
	def __init__(self):
		ShowBase.__init__(self)
		
		
		#standard GeoMipTerrain usage
		self.terrain = GeoMipTerrain("worldTerrain")
		self.terrain.setHeightfield("mapheight.png")
		self.terrain.setColorMap("maptexture.png")
		#self.terrain.setBruteforce(True)
		#set dynamically updated terrain
		self.terrain.setBlockSize(32)
		self.terrain.setNearFar(128, 256) #distance in terrain coordinates
		self.terrain.setMinLevel(0) #low means high quality
		self.terrain.setFocalPoint(base.camera) #a NodePath
		#get root
		root = self.terrain.getRoot()
		root.reparentTo(render)
		root.setSz(100)
		self.terrain.generate()
		taskMgr.add(self.updateTask,  "update")
		
		self.camera.setPos(0, 0, 0)
		
		#add person
		self.player = Actor("girl4.x", {"girl03_03": "girl"})
		print("girl loaded")
		self.player.setPos(0, 5, -1)
		self.player.reparentTo(self.render)
		print("girl reparented")
	
	def updateTask(self, task):
		self.terrain.update()
		return task.cont
Example #2
0
    def createGround(self, terrainData):
        """Create ground using a heightmap"""

        # Create heightfield for physics
        heightRange = terrainData["heightRange"]

        # Image needs to have dimensions that are a power of 2 + 1
        heightMap = PNMImage(self.basePath + terrainData["elevation"])
        xdim = heightMap.getXSize()
        ydim = heightMap.getYSize()
        shape = BulletHeightfieldShape(heightMap, heightRange, ZUp)
        shape.setUseDiamondSubdivision(True)

        np = self.outsideWorldRender.attachNewNode(BulletRigidBodyNode("terrain"))
        np.node().addShape(shape)
        np.setPos(0, 0, 0)
        self.physicsWorld.attachRigidBody(np.node())

        # Create graphical terrain from same height map
        terrain = GeoMipTerrain("terrain")
        terrain.setHeightfield(heightMap)

        terrain.setBlockSize(32)
        terrain.setBruteforce(True)
        rootNP = terrain.getRoot()
        rootNP.reparentTo(self.worldRender)
        rootNP.setSz(heightRange)

        offset = xdim / 2.0 - 0.5
        rootNP.setPos(-offset, -offset, -heightRange / 2.0)
        terrain.generate()

        # Apply texture
        diffuse = self.loader.loadTexture(Filename(self.basePath + terrainData["texture"]))
        diffuse.setWrapU(Texture.WMRepeat)
        diffuse.setWrapV(Texture.WMRepeat)
        rootNP.setTexture(diffuse)
        textureSize = 6.0
        ts = TextureStage.getDefault()
        rootNP.setTexScale(ts, xdim / textureSize, ydim / textureSize)

        # Create planes around area to prevent player flying off the edge
        # Levels can define barriers around them but it's probably a good
        # idea to leave this here just in case
        sides = (
            (Vec3(1, 0, 0), -xdim / 2.0),
            (Vec3(-1, 0, 0), -xdim / 2.0),
            (Vec3(0, 1, 0), -ydim / 2.0),
            (Vec3(0, -1, 0), -ydim / 2.0),
        )
        for sideNum, side in enumerate(sides):
            normal, offset = side
            sideShape = BulletPlaneShape(normal, offset)
            sideNode = BulletRigidBodyNode("side%d" % sideNum)
            sideNode.addShape(sideShape)
            self.physicsWorld.attachRigidBody(sideNode)
Example #3
0
 def generate(self):
     '''(Re)generate the entire terrain erasing any current changes'''
     factor = self.blockSize*self.chunkSize
     #print "Factor:", factor
     for terrain in self.terrains:
         terrain.getRoot().removeNode()
     self.terrains = []
     # Breaking master heightmap into subimages
     heightmaps = []
     self.xchunks = (self.heightfield.getXSize()-1)/factor
     self.ychunks = (self.heightfield.getYSize()-1)/factor
     #print "X,Y chunks:", self.xchunks, self.ychunks
     n = 0
     for y in range(0, self.ychunks):
         for x in range(0, self.xchunks):
             heightmap = PNMImage(factor+1, factor+1)
             heightmap.copySubImage(self.heightfield, 0, 0, xfrom = x*factor, yfrom = y*factor)
             heightmaps.append(heightmap)
             n += 1
     
     # Generate GeoMipTerrains
     n = 0
     y = self.ychunks-1
     x = 0
     for heightmap in heightmaps:
         terrain = GeoMipTerrain(str(n))
         terrain.setHeightfield(heightmap)
         terrain.setBruteforce(self.bruteForce)
         terrain.setBlockSize(self.blockSize)
         terrain.generate()
         self.terrains.append(terrain)
         root = terrain.getRoot()
         root.reparentTo(self.root)
         root.setPos(n%self.xchunks*factor, (y)*factor, 0)
         
         # In order to texture span properly we need to reiterate through every vertex
         # and redefine the uv coordinates based on our size, not the subGeoMipTerrain's
         root = terrain.getRoot()
         children = root.getChildren()
         for child in children:
             geomNode = child.node()
             for i in range(geomNode.getNumGeoms()):
                 geom = geomNode.modifyGeom(i)
                 vdata = geom.modifyVertexData()
                 texcoord = GeomVertexWriter(vdata, 'texcoord')
                 vertex = GeomVertexReader(vdata, 'vertex')
                 while not vertex.isAtEnd():
                     v = vertex.getData3f()
                     t = texcoord.setData2f((v[0]+ self.blockSize/2 + self.blockSize*x)/(self.xsize - 1),
                                                     (v[1] + self.blockSize/2 + self.blockSize*y)/(self.ysize - 1))
         x += 1
         if x >= self.xchunks:
             x = 0
             y -= 1
         n += 1
 def createTile(self, x, y):
     # Set up the GeoMipTerrain
     terrain = GeoMipTerrain("terrain")
     terrain.setHeightfield("./height-map.png")
     # Set terrain properties
     terrain.setBlockSize(32)
     terrain.setNear(40)
     terrain.setFar(100)
     terrain.setFocalPoint(self.showBase.camera)
     #terrain.setAutoFlatten(GeoMipTerrain.AFMStrong)
     terrain.getRoot().setScale(1, 1, 1)
     terrain.getRoot().setPos(x * 128 - 64, y * 128 - 64, 0)
     terrain.getRoot().setTexture(TextureStage.getDefault(), self.showBase.loader.loadTexture("./grass-texture.png"))
     terrain.getRoot().setTexScale(TextureStage.getDefault(), 50)
     # Store the root NodePath for convenience
     root = terrain.getRoot()
     root.reparentTo(self.showBase.render)
     root.setSz(100)
     # Generate it.
     terrain.generate()
     return terrain
class SMWorld(DirectObject):

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Constructor
    # (Game state, Map name, Height of death plane)
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def __init__(self, mapID, tObj, aObj):

        self.mapID = mapID

        # EX: maps/map-1/map-1.yetimap
        metaFile = open(
            "../maps/map" + str(self.mapID) + "/map" + str(self.mapID) +
            ".yetimap", 'r')
        metaLines = metaFile.readlines()
        lineCount = len(metaLines)
        self.snowflakeCount = lineCount - 2
        self.snowCount = 0

        # First Line: Player's starting position
        # EX: 50,50,50 (NO SPACES)
        playerLine = metaLines[0]
        playerPosList = playerLine.split(",")
        playerInitX = int(playerPosList[0])
        playerInitY = int(playerPosList[1])
        playerInitZ = int(playerPosList[2])
        self.playerStart = Point3(playerInitX, playerInitY, playerInitZ)

        # 2nd Line: Deathzone Height
        # ONE INTEGER
        self.deathHeight = int(metaLines[1])

        # Get dem snowflakes
        self.snowflakePositions = []
        print("Snowflake Count: " + str(self.snowflakeCount))
        for i in xrange(0, self.snowflakeCount):
            sfline = metaLines[i + 2]
            sfList = sfline.split(",")
            sfx = int(sfList[0])
            sfy = int(sfList[1])
            sfz = int(sfList[2])
            self.snowflakePositions.append(Point3(sfx, sfy, sfz))
            print("New snowflake to add: (" + str(sfx) + "," + str(sfy) + "," +
                  str(sfz) + ")")

        #load in controls
        ctrlFl = open("ctrConfig.txt")
        #will skip n lines where [n,]
        #makes a list of controls
        self.keymap = eval(ctrlFl.read())
        #close file
        ctrlFl.close()

        # Create new instances of our various objects
        self.mapName = str(mapID)
        self.audioMgr = aObj
        self.worldObj = self.setupWorld()
        self.heightMap = self.setupHeightmap(self.mapName)
        self.deathZone = self.setupDeathzone(self.deathHeight)
        self.debugNode = self.setupDebug()

        # Player Init
        self.playerObj = SMPlayer(self.worldBullet, self.worldObj, self,
                                  self.playerStart, self.audioMgr)
        self.playerNP = self.playerObj.getNodePath()
        self.playerNP.setH(180)
        self.canUseShift = True
        self.canAirDash = True

        # Snowball Init
        self.ballObj = SMBall(self.worldBullet, self.worldObj, self.playerObj,
                              self.playerNP)
        self.sbCollideFlag = False
        self.ballNP = self.ballObj.getNodePath()

        # Key Handler
        self.kh = SMKeyHandler()
        self.lastMousePos = self.kh.getMouse()

        # Collision Handler
        self.colObj = self.setupCollisionHandler()

        # Lighting
        self.ligObj = SMLighting(Vec4(.4, .4, .4, 1), Vec3(-5, -5, -5),
                                 Vec4(2.0, 2.0, 2.0, 1.0))

        # Camera
        self.camObj = SMCamera(self.playerObj, self.worldBullet, self.worldObj)
        self.cameraControl = False

        # GUI
        self.GUI = SMGUI()
        self.snowflakeCounter = SMGUICounter(
            "snowflake",
            self.snowflakeCount)  # Replace 3 with # of snowflakes in level.
        self.snowMeter = SMGUIMeter(100)
        self.GUI.addElement("snowflake", self.snowflakeCounter)
        self.GUI.addElement("snowMeter", self.snowMeter)

        #Snowy Outside
        # base.enableParticles()
        # self.p = ParticleEffect()
        # self.p.cleanup()
        # self.p = ParticleEffect()
        # self.p.loadConfig('snow.ptf')
        # self.p.start(self.camObj.getNodePath())
        # self.p.setPos(0.00, 0.500, 0.000)

        # AI
        # self.goat1 = SMAI("../res/models/goat.egg", 75.0, self.worldBullet, self.worldObj, -70, -95, 5)
        # self.goat1.setBehavior("flee", self.playerNP)
        # self.goat2 = SMAI("../res/models/goat.egg", 75.0, self.worldBullet, self.worldObj, -80, -83, 5)
        # self.goat2.setBehavior("flee", self.playerNP)
        # print("AI Initialized")

        # Debug Text
        self.textObj = tObj
        self.textObj.addText("yetiPos", "Position: ")
        self.textObj.addText("yetiVel", "Velocity: ")
        self.textObj.addText("yetiFric", "Friction: ")
        self.textObj.addText("onIce", "Ice(%): ")
        self.textObj.addText("onSnow", "Snow(%): ")
        self.textObj.addText("terrHeight", "T Height: ")
        self.textObj.addText("terrSteepness", "Steepness: ")

        # Pause screen transition
        self.transition = Transitions(loader)

        # Method-based keybindings
        # self.accept('b', self.spawnBall)
        self.accept('escape', base.userExit)
        self.accept('enter', self.pauseUnpause)
        self.accept('f1', self.toggleDebug)

        self.accept('lshift-up', self.enableShiftActions)
        self.accept('mouse1', self.enableCameraControl)
        self.accept('mouse1-up', self.disableCameraControl)
        self.accept('wheel_up', self.camObj.zoomIn)
        self.accept('wheel_down', self.camObj.zoomOut)

        self.pauseUnpause()

        # Disable the mouse
        base.disableMouse()
        props = WindowProperties()
        props.setCursorHidden(True)
        base.win.requestProperties(props)

        # Uncomment this to see everything being rendered.
        self.printSceneGraph()

        # Play the BGM
        self.audioMgr.playBGM("snowmanWind")

        # Skybox formed
        skybox = loader.loadModel("../res/models/skybox.egg")
        # skybox.set_two_sided(true)
        skybox.setScale(500)
        skybox.setPos(0, 0, -450)
        skybox.reparentTo(render)

        mountain = loader.loadModel("../res/models/mountain.egg")
        mountain.reparentTo(render)
        mountain.setPos(650, 800, 20)
        mountain.setScale(120)

        self.colObjects = []

        self.caveNew = SMCollide("../res/models/cave_new.egg",
                                 self.worldBullet, self.worldObj,
                                 Point3(-50, 95, -13), 11, Vec3(0, 0, 0))
        self.colObjects.append(self.caveNew)

        self.planeFront = SMCollide("../res/models/plane_front",
                                    self.worldBullet, self.worldObj,
                                    Point3(190, -100,
                                           -15), 8, Vec3(190, 0, 30))
        self.colObjects.append(self.planeFront)

        self.caveModel = SMCollide("../res/models/cave_tunnel.egg",
                                   self.worldBullet, self.worldObj,
                                   Point3(233, 68, 32), 4, Vec3(135, 180, 0))
        self.colObjects.append(self.caveModel)

        self.planeTail = SMCollide("../res/models/plane_tail.egg",
                                   self.worldBullet, self.worldObj,
                                   Point3(-40, -130, -7), 10, Vec3(230, 0, 0))
        self.colObjects.append(self.planeTail)

        self.ropeBridge = SMCollide("../res/models/rope_bridge.egg",
                                    self.worldBullet, self.worldObj,
                                    Point3(180, 115, 30), 6, Vec3(50, 0, 0))
        self.colObjects.append(self.ropeBridge)

        self.colObjectCount = len(self.colObjects)

        print("World initialized.")

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Enables the camera to be rotated by moving the mouse horizontally.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def enableCameraControl(self):
        self.cameraControl = True

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Disables the camera control.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def disableCameraControl(self):
        self.cameraControl = False

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Enables the use of shift actions again.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def enableShiftActions(self):
        self.canUseShift = True

    def disableShiftActions(self):
        self.canUseShift = False

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Respawns the yeti's snowball.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def spawnBall(self):
        if (not (self.playerObj.getAirborneFlag())):
            self.ballObj.respawn()

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Toggles the pause screen
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def pauseUnpause(self):
        if taskMgr.hasTaskNamed('UpdateTask'):
            taskMgr.remove('UpdateTask')
            self.transition.fadeScreen(0.5)
        else:
            taskMgr.add(self.update, 'UpdateTask')
            self.transition.noFade()

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Sets up the world and returns a NodePath of the BulletWorld
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def setupWorld(self):
        self.worldBullet = BulletWorld()
        self.worldBullet.setGravity(Vec3(0, 0, -GRAVITY))
        self.terrSteepness = -1
        wNP = render.attachNewNode('WorldNode')

        self.audioMgr.loadSFX("snowCrunch01")
        self.audioMgr.loadBGM("snowmanWind")

        return wNP

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Prints all nodes that are a child of render.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def printSceneGraph(self):
        print(render.ls())

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Initializes and returns a DebugNode NodePath.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def setupDebug(self):
        debug = BulletDebugNode()
        debug.showWireframe(
            False
        )  # Yeah, don't set this to true unless you want to emulate an 80's computer running Crysis on Ultra settings.
        debug.showConstraints(True)
        debug.showBoundingBoxes(True)  # This is the main use I have for it.
        debug.showNormals(True)
        debugNP = render.attachNewNode(debug)
        self.worldBullet.setDebugNode(debugNP.node())
        debugNP.hide()
        return debugNP

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Initializes and returns a BulletRigidBodyNode of the terrain, which loads the map with the specified name.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def setupHeightmap(self, name):

        # Automatically generate a heightmap mesh from a monochrome image.
        self.hmHeight = 120
        hmPath = "../maps/map" + name + "/map" + name + "-h.png"
        imPath = "../maps/map" + name + "/map" + name + "-i.png"
        smPath = "../maps/map" + name + "/map" + name + "-s.png"
        scmPath = "../maps/map" + name + "/map" + name + "-sc.png"
        print(hmPath)
        print(imPath)
        print(smPath)
        print(scmPath)
        hmImg = PNMImage(Filename(hmPath))
        hmShape = BulletHeightfieldShape(hmImg, self.hmHeight, ZUp)
        hmNode = BulletRigidBodyNode('Terrain')
        hmNode.addShape(hmShape)
        hmNode.setMass(0)
        self.hmNP = render.attachNewNode(hmNode)
        self.worldBullet.attachRigidBody(hmNode)
        self.hmOffset = hmImg.getXSize() / 2.0 - 0.5
        self.hmTerrain = GeoMipTerrain('gmTerrain')
        self.hmTerrain.setHeightfield(hmImg)

        # Optimizations and fixes
        self.hmTerrain.setBruteforce(
            True)  # I don't think this is actually needed.
        self.hmTerrain.setMinLevel(3)  # THIS is what triangulates the terrain.
        self.hmTerrain.setBlockSize(
            128)  # This does a pretty good job of raising FPS.
        # Level-of-detail (not yet working)
        # self.hmTerrain.setNear(40)
        # self.hmTerrain.setFar(200)

        self.hmTerrain.generate()

        self.hmTerrainNP = self.hmTerrain.getRoot()
        self.hmTerrainNP.setSz(self.hmHeight)
        self.hmTerrainNP.setPos(-self.hmOffset, -self.hmOffset,
                                -self.hmHeight / 2.0)
        self.hmTerrainNP.flattenStrong(
        )  # This only reduces the number of nodes; nothing to do with polys.
        self.hmTerrainNP.analyze()

        # Here begins the scenery mapping
        treeModel = loader.loadModel("../res/models/tree_1.egg")
        rockModel = loader.loadModel("../res/models/rock_1.egg")
        rock2Model = loader.loadModel("../res/models/rock_2.egg")
        rock3Model = loader.loadModel("../res/models/rock_3.egg")
        # caveModel = loader.loadModel("../res/models/cave_new.egg")
        # planeFrontModel = loader.loadModel("../res/models/plane_front.egg")
        # planeWingModel = loader.loadModel("../res/models/plane_wing.egg")
        texpk = loader.loadTexture(scmPath).peek()

        # GameObject nodepath for flattening
        self.objNP = render.attachNewNode("gameObjects")
        self.treeNP = self.objNP.attachNewNode("goTrees")
        self.rockNP = self.objNP.attachNewNode("goRocks")
        self.rock2NP = self.objNP.attachNewNode("goRocks2")
        self.rock3NP = self.objNP.attachNewNode("goRocks3")
        # self.caveNP = self.objNP.attachNewNode("goCave")
        # self.planeFrontNP = self.objNP.attachNewNode("goPlaneFront")
        # self.planeWingNP = self.objNP.attachNewNode("goPlaneWing")

        for i in range(0, texpk.getXSize()):
            for j in range(0, texpk.getYSize()):
                color = VBase4(0, 0, 0, 0)
                texpk.lookup(color,
                             float(i) / texpk.getXSize(),
                             float(j) / texpk.getYSize())
                if (int(color.getX() * 255.0) == 255.0):
                    newTree = self.treeNP.attachNewNode("treeNode")
                    treeModel.instanceTo(newTree)
                    newTree.setPos(
                        i - texpk.getXSize() / 2, j - texpk.getYSize() / 2,
                        self.hmTerrain.get_elevation(i, j) * self.hmHeight -
                        self.hmHeight / 2)
                    # newTree.setScale(randint(0,4))
                    newTree.setScale(2)

                if (int(color.getX() * 255.0) == 128):
                    newRock = self.rockNP.attachNewNode("newRock")
                    newRock.setPos(
                        i - texpk.getXSize() / 2, j - texpk.getYSize() / 2,
                        self.hmTerrain.get_elevation(i, j) * self.hmHeight -
                        self.hmHeight / 2)
                    rockModel.instanceTo(newRock)

                if (int(color.getX() * 255.0) == 77):
                    newRock2 = self.rock2NP.attachNewNode("newRock2")
                    newRock2.setPos(
                        i - texpk.getXSize() / 2, j - texpk.getYSize() / 2,
                        self.hmTerrain.get_elevation(i, j) * self.hmHeight -
                        self.hmHeight / 2)
                    rock2Model.instanceTo(newRock2)

                if (int(color.getX() * 255.0) == 102):
                    newRock3 = self.rock3NP.attachNewNode("newRock3")
                    newRock3.setPos(
                        i - texpk.getXSize() / 2, j - texpk.getYSize() / 2,
                        self.hmTerrain.get_elevation(i, j) * self.hmHeight -
                        self.hmHeight / 2)
                    rock3Model.instanceTo(newRock3)

                # if(int(color.getX() * 255.0) == 64):
                # newCave = self.caveNP.attachNewNode("newCave")
                # newCave.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
                # newCave.setScale(5)
                # newCave.setP(180)
                # caveModel.instanceTo(newCave)

                # if(int(color.getX() * 255.0) == 191):
                # newPlaneFront = self.planeFrontNP.attachNewNode("newPlaneFront")
                # newPlaneFront.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
                # newPlaneFront.setScale(6)
                # planeFrontModel.instanceTo(newPlaneFront)

                # if(int(color.getX() * 255.0) == 179):
                # newPlaneWing = self.planeWingNP.attachNewNode("newPlaneWing")
                # newPlaneWing.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
                # newPlaneWing.setScale(6)
                # newPlaneWing.setH(250)
                # newPlaneWing.setR(180)
                # newPlaneWing.setP(135)
                # planeWingModel.instanceTo(newPlaneWing)

        self.snowflakes = []

        for i in xrange(0, self.snowflakeCount):
            print("Call " + str(i))
            sf = SMCollect(self.worldBullet, self.worldObj,
                           self.snowflakePositions[i])
            self.snowflakes.append(sf)

        # render.flattenStrong()
        self.hmTerrainNP.reparentTo(render)

        # Here begins the attribute mapping
        ts = TextureStage("stage-alpha")
        ts.setSort(0)
        ts.setPriority(1)
        ts.setMode(TextureStage.MReplace)
        ts.setSavedResult(True)
        self.hmTerrainNP.setTexture(ts, loader.loadTexture(imPath, smPath))

        ts = TextureStage("stage-stone")
        ts.setSort(1)
        ts.setPriority(1)
        ts.setMode(TextureStage.MReplace)
        self.hmTerrainNP.setTexture(
            ts, loader.loadTexture("../res/textures/stone_tex.png"))
        self.hmTerrainNP.setTexScale(ts, 32, 32)

        ts = TextureStage("stage-ice")
        ts.setSort(2)
        ts.setPriority(1)
        ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture,
                         TextureStage.COSrcColor, TextureStage.CSPrevious,
                         TextureStage.COSrcColor,
                         TextureStage.CSLastSavedResult,
                         TextureStage.COSrcColor)
        self.hmTerrainNP.setTexture(
            ts, loader.loadTexture("../res/textures/ice_tex.png"))
        self.hmTerrainNP.setTexScale(ts, 32, 32)

        ts = TextureStage("stage-snow")
        ts.setSort(3)
        ts.setPriority(0)
        ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture,
                         TextureStage.COSrcColor, TextureStage.CSPrevious,
                         TextureStage.COSrcColor,
                         TextureStage.CSLastSavedResult,
                         TextureStage.COSrcAlpha)
        self.hmTerrainNP.setTexture(
            ts, loader.loadTexture("../res/textures/snow_tex_1.png"))
        self.hmTerrainNP.setTexScale(ts, 32, 32)

        # print(self.snowflakes)

        return hmNode

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Sets up and returns the death zone plane (returns its NodePath) with the specified height.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def setupDeathzone(self, height):
        planeShape = BulletPlaneShape(Vec3(0, 0, 1), 1)
        planeNode = BulletRigidBodyNode('DeathZone')
        planeNode.addShape(planeShape)
        planeNP = render.attachNewNode(planeNode)
        planeNP.setPos(0, 0, height)
        self.worldBullet.attachRigidBody(planeNode)
        return planeNP

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Sets up and returns the collision handler.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def setupCollisionHandler(self):
        colHand = SMCollisionHandler(self.worldBullet)
        return colHand

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Toggles showing bounding boxes.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def toggleDebug(self):
        if self.debugNode.isHidden():
            self.debugNode.show()
        else:
            self.debugNode.hide()

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Returns the terrain height of the nearest vertical descending raycast from the passed Point3.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def getTerrainHeight(self, pos):
        result = 0
        x = pos.getX()
        y = pos.getY()
        z = pos.getZ()
        rayTerrA = Point3(x, y, z)
        rayTerrB = Point3(x, y, z - 256)
        rayTest = self.worldBullet.rayTestClosest(rayTerrA, rayTerrB)

        rayNode = rayTest.getNode()
        if (rayTest.hasHit()):
            rayPos = rayTest.getHitPos()
            result = rayPos.getZ()
        else:
            self.playerObj.respawn()
        return result
        # return self.hmTerrain.get_elevation(x + self.hmOffset, y + self.hmOffset) * self.hmHeight

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Handles player movement
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def playerMove(self):

        # Go through the collision and flag tests, and update them
        self.doPlayerTests()

        # Rotation and camera movement
        if self.kh.poll(self.keymap['Left']):
            self.playerObj.turn(True)
        elif self.kh.poll(self.keymap['Right']):
            self.playerObj.turn(False)
        elif (self.cameraControl):
            newMousePos = self.kh.getMouse()
            mx = newMousePos.getX()
            self.camObj.rotateCamera(mx)

        self.camObj.calculatePosition()

        # Movement
        if self.kh.poll(self.keymap['Forward']):
            self.playerObj.move(True)
            self.camObj.rotateTowards(90)
        elif self.kh.poll(self.keymap['Back']):

            self.playerObj.move(False)
        else:
            self.playerObj.stop()

        # Jump
        if (self.kh.poll(self.keymap['Space']) and self.terrSteepness <
                0.25):  #and not(self.ballObj.isRolling())):
            self.playerObj.jump()
        else:
            self.playerObj.resetJump()

        # Air Dash
        if (
                self.kh.poll(self.keymap['airDash'])
        ):  #and self.playerObj.getAirborneFlag() == True and self.canAirDash == True):
            self.canAirDash = False
            self.playerObj.airDash()

        # Shift-based actions
        if (self.kh.poll("lshift") and not (self.sbCollideFlag)
                and not (self.playerObj.getAirborneFlag())
                and self.canUseShift):

            # If there's another snowball already placed
            if (self.ballObj.exists() and not (self.ballObj.isRolling())):
                self.ballObj.respawn()

            # If we're rolling a snowball
            elif (self.ballObj.isRolling()):

                # Absorb snowball
                if (self.kh.poll("v")):
                    self.canUseShift = False
                    snowAmt = self.ballObj.getSnowAmount()
                    self.playerObj.addSnow(snowAmt)
                    # self.snowMeter.fillBy(snowAmt)
                    self.ballObj.destroy()

                # Go to iceball throwing mode
                elif (self.kh.poll("b")):
                    print("TODO: Ice ball throwing mode.")

                # Grow the snowball
                elif (self.kh.poll("w")):
                    self.ballObj.grow()

            # Spawn a new snowball
            elif (self.ballObj.exists() == False):
                self.ballObj.respawn()

        # If the player is not pressing shift
        else:
            if (self.ballObj.isRolling()):
                self.ballObj.dropBall()

        base.win.movePointer(0, 400, 300)

        # So updating the stats is VERY expensive.
        if (self.debugNode.isHidden() == False):
            self.updateStats()

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Various tests concerning the player flags and collisions.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def doPlayerTests(self):

        # Player's position
        plPos = self.playerObj.getPosition()
        px = plPos.getX()
        py = plPos.getY()
        pz = plPos.getZ()

        # Raycast directly down for terrain steepness
        rayYetiA = Point3(px, py, pz)
        rayYetiB = Point3(px, py, pz - 300)
        self.downRayTest = self.worldBullet.rayTestClosest(
            rayYetiA, rayYetiB).getHitNormal()
        rx = self.downRayTest.getX()
        ry = self.downRayTest.getY()
        rz = self.downRayTest.getZ()
        self.terrSteepness = 1.0 - rz

        # Redo collision flags later
        objCollisionFlag = False

        # Snow/Ice height adjust
        self.playerObj.updateTerrain()

        # Collision: Player x Objects
        for i in xrange(0, self.colObjectCount):
            if (self.colObj.didCollide(self.playerNP.node(),
                                       self.colObjects[i].AINode)):
                objCollisionFlag = True
                self.playerObj.setAirborneFlag(False)
                self.canAirDash = True
                self.playerObj.setFactor(1, 1, 1)

        # Collision: Player x Snowball
        if (self.ballObj.exists() and self.colObj.didCollide(
                self.playerNP.node(), self.ballObj.getRigidbody())):
            self.sbCollideFlag = True
            self.playerObj.setAirborneFlag(False)
            self.playerObj.setFactor(1, 1, 1)
        else:
            self.sbCollideFlag = False

        # Collision: Player x Terrain
        if (self.colObj.didCollide(self.playerNP.node(), self.heightMap)):
            if (self.playerObj.getAirborneFlag()):
                self.audioMgr.playSFX("snowCrunch01")
            self.playerObj.setAirborneFlag(False)
            self.canAirDash = True
            self.playerObj.setFactor(1, 1, 1)
            objCollisionFlag = False

        # Collision: Player x Death Zone
        # if(pz - 7 <= self.deathHeight or (self.colObj.didCollide(self.playerNP.node(), self.deathZone.node()))):
        if (self.colObj.didCollide(self.playerNP.node(),
                                   self.deathZone.node())):
            print("Player confirmed #REKT")
            self.playerObj.respawn()

        # Out of bounds checking
        if (abs(px) > 254 or abs(py) > 254):
            print("Player out of bounds!")
            self.playerObj.respawn()

        # Snap to terrain if... something. I need to restructure this. Don't read it.
        if (not (self.playerObj.getAirborneFlag()) and not (self.sbCollideFlag)
                and not (objCollisionFlag)):
            z = self.getTerrainHeight(Point3(px, py, pz))
            self.playerObj.snapToTerrain(z)
            # self.playerObj.snapToTerrain(th, self.hmHeight)

        # Collision: Player x Snowflakes
        for i in xrange(0, self.snowflakeCount):
            if (self.snowflakes[i].exists() and self.colObj.didCollide(
                    self.playerNP.node(), self.snowflakes[i].getNode())):
                self.snowflakes[i].destroy()
                self.snowflakeCounter.increment()
                self.snowCount += 1

        self.snowMeter.updateSnow(self.playerObj)

        #Check if there is a "next" level. If there is, load it. Otherwise display end game screen.
        if (self.snowCount >= self.snowflakeCount):
            file_path = "../maps/map" + str(self.mapID +
                                            1) + "/map" + str(self.mapID +
                                                              1) + ".yetimap"
            if os.path.lexists(file_path):

                self.snowCount = 0
                self.snowflakeCount = 0
                self.snowflakeCounter.setValue(0)
                self.snowflakeCounter.setState(2)

                #Loading Screen
                self.transition.fadeScreen(0.7)
                self.loadingText = OnscreenText("Loading...",
                                                1,
                                                fg=(1, 1, 1, 0),
                                                pos=(0, 0),
                                                align=TextNode.ACenter,
                                                scale=.07,
                                                mayChange=1)
                base.graphicsEngine.renderFrame()
                base.graphicsEngine.renderFrame()
                base.graphicsEngine.renderFrame()
                base.graphicsEngine.renderFrame()
                self.transition.noFade()

                #destroy objects
                self.worldBullet.removeRigidBody(self.heightMap)
                self.hmTerrainNP.removeNode()
                self.objNP.removeNode()
                self.treeNP.removeNode()
                self.rockNP.removeNode()
                self.rock2NP.removeNode()
                self.rock3NP.removeNode()
                # self.caveNP.removeNode()
                # self.planeFrontNP.removeNode()
                # self.planeWingNP.removeNode()
                self.hmNP.removeNode()
                if (int(self.mapID) == 1):
                    self.ropeBridge.AIChar.setPos(-200, -300, -200)
                    # self.ropeBridge.AIChar.removeNode()
                    self.planeFront.AIChar.removeNode()
                    self.planeTail.AIChar.setPos(-200, -200, -200)
                    # self.planeTail.AIChar.removeNode()
                    self.caveNew.AIChar.setPos(-1000, -1000, -1000)
                    self.caveModel.AIChar.removeNode()
                    #Added More Props here!
                    self.boulder = SMCollide("../res/models/rock_3.egg",
                                             self.worldBullet, self.worldObj,
                                             Point3(117, 123, 17), 15,
                                             Vec3(0, 0, 0))
                elif (int(self.mapID) == 2):
                    self.boulder.AIChar.setPos(-222, -222, -222)
                    self.caveNew.AIChar.setScale(150)
                    self.caveNew.AIChar.setPos(-50, 95, -50)
                    # self.skybox.setScale(600)
                    # self.caveNew.setH(0)
                    # self.boulder.removeNode()

                self.mapID += 1
                print self.mapID
                # EX: maps/map-1/map-1.yetimap
                metaFile = open(
                    "../maps/map" + str(self.mapID) + "/map" +
                    str(self.mapID) + ".yetimap", 'r')
                metaLines = metaFile.readlines()
                lineCount = len(metaLines)
                self.snowflakeCount = lineCount - 2

                # First Line: Player's starting position
                # EX: 50,50,50 (NO SPACES)
                playerLine = metaLines[0]
                playerPosList = playerLine.split(",")
                playerInitX = int(playerPosList[0])
                playerInitY = int(playerPosList[1])
                playerInitZ = int(playerPosList[2])
                self.playerObj.playerNP.setPos(playerInitX, playerInitY,
                                               playerInitZ)
                self.playerObj.startX = playerInitX
                self.playerObj.startY = playerInitY
                self.playerObj.startZ = playerInitZ

                # 2nd Line: Deathzone Height
                # ONE INTEGER
                self.deathHeight = int(metaLines[1])

                self.snowflakePositions = []
                print("Snowflake Count: " + str(self.snowflakeCount))
                for i in xrange(0, self.snowflakeCount):
                    sfline = metaLines[i + 2]
                    sfList = sfline.split(",")
                    sfx = int(sfList[0])
                    sfy = int(sfList[1])
                    sfz = int(sfList[2])
                    self.snowflakePositions.append(Point3(sfx, sfy, sfz))
                    print("New snowflake to add: (" + str(sfx) + "," +
                          str(sfy) + "," + str(sfz) + ")")
                self.snowflakeCounter.setMaxValue(self.snowflakeCount)

                #load new map
                self.mapName = str(self.mapID)
                self.heightMap = self.setupHeightmap(self.mapName)
                self.deathZone = self.setupDeathzone(self.deathHeight)

                self.loadingText.cleanup()
            else:
                taskMgr.remove('UpdateTask')
                self.endImage = OnscreenImage(
                    image="../res/icons/endgame1.png",
                    pos=(0.0, 0.0, 0.0),
                    scale=(1.35, 2, 1))

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Update the debug text.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def updateStats(self):
        pos = self.playerObj.getPosition()
        x = pos.getX()
        y = pos.getY()
        z = pos.getZ()
        vel = self.playerObj.getVelocity()
        vx = str(round(vel.getX(), 1))
        vy = str(round(vel.getY(), 1))
        vz = str(round(vel.getZ(), 1))
        sx = str(round(x, 1))
        sy = str(round(y, 1))
        sz = str(round(z, 1))
        rx = str(round(self.downRayTest.getX(), 2))
        ry = str(round(self.downRayTest.getY(), 2))
        rz = str(round(self.terrSteepness, 2))
        fric = str(round(self.playerObj.getFriction(), 2))
        ip = str(round(self.playerObj.getIceCoefficient(), 2))
        sp = str(round(self.playerObj.getSnowCoefficient(), 2))
        tHeight = str(round(self.getTerrainHeight(Point3(x, y, z)), 1))
        self.textObj.editText("yetiPos",
                              "Position: (" + sx + ", " + sy + ", " + sz + ")")
        self.textObj.editText("yetiVel",
                              "Velocity: (" + vx + ", " + vy + ", " + vz + ")")
        self.textObj.editText("yetiFric", "Friction: " + fric)
        self.textObj.editText("onIce", "Ice(%): " + ip)
        self.textObj.editText("onSnow", "Snow(%): " + sp)
        self.textObj.editText("terrHeight", "T Height: " + tHeight)
        self.textObj.editText("terrSteepness", "Steepness: " + rz)

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # throw Snowball
    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    def throw(self):
        self.throwing = True
        size = self.ballObj.getSize()
        #zoom camera and grab pos you wish to throw
        self.camObj.aimMode()
        taskMgr.add(self.controlCamera, "camera-task")
        rotation = self.camObj.getH()
        pitch = self.camObj.getP()
        self.ballObj.throwBall(size, pitch, rotation)
        #fix camera
        #self.throwing = False

    #------------------------------------------------------------------------------------------------------------------------------------------------------------
    # Update the world. Called every frame.
    #------------------------------------------------------------------------------------------------------------------------------------------------------------

    def update(self, task):
        dt = globalClock.getDt()
        self.worldBullet.doPhysics(dt)
        # self.goat1.AIUpdate()
        # self.goat2.AIUpdate()
        self.playerMove()
        return task.cont
class Terrain(object):
    def __init__(self, main, base, render, type = "heightMap"):
        if type == "heightMap":
            self.terrainFromHeightMap(main)
        elif type == "model":
            self.terrainFromModel(main)

        # Plane
        shape = BulletPlaneShape(Vec3(0, 0, 1), 1)
        universeNode = BulletRigidBodyNode('UniverseNode')
        universeNode.notifyCollisions(True)
        universeNode.addShape(shape)
        np = self.parentNodePath.attachNewNode(universeNode)
        np.setPos(0, 0, -150)
        np.hide()
        main.world.attachRigidBody(universeNode)

        self.parentNodePath.reparentTo(main.worldNP)
        self.hf = self.rigidNodePath.node() # To enable/disable debug visualisation
        # Sky Dome
        universeBackground = UniverseBackground()

    def terrainFromModel(self, main):
        self.parentNodePath = NodePath("FloorNodePath")
        self.parentNodePath.setPos(0, 0, -1)
        self.parentNodePath.setScale(2.0, 2.0, 1.0)
        # self.parentNodePath.setP(90)

        self.loadModelAndTexture()
        self.setupCollisionMeshAndRigidNodeFromModel()

        main.world.attachRigidBody(self.rigidNodePath.node())

    def loadModelAndTexture(self, path={"model": "models/map", "texture": "models/tex/floor.jpg"}):
        self.floorModel = loader.loadModel(path["model"])
        # floor_tex = loader.loadTexture(path["texture"])
        # self.floorModel.setTexture(floor_tex)
        self.parentNodePath.attachNewNode(self.floorModel.node())

    def setupCollisionMeshAndRigidNodeFromModel(self):
        mesh = BulletTriangleMesh()
        for geomNP in self.floorModel.findAllMatches('**/+GeomNode'):
            geomNode = geomNP.node()
            ts = geomNP.getTransform(self.floorModel)
            for geom in geomNode.getGeoms():
                mesh.addGeom(geom, ts)

        shape = BulletTriangleMeshShape(mesh, dynamic=False)
        self.rigidNode = BulletRigidBodyNode('Floor')
        self.rigidNode.notifyCollisions(False)

        self.rigidNodePath = self.parentNodePath.attachNewNode(self.rigidNode)
        self.rigidNodePath.node().addShape(shape)
        self.rigidNodePath.setScale(12, 12, 1.5)
        self.rigidNodePath.setCollideMask(BitMask32.allOn())
        self.rigidNodePath.node().notifyCollisions(False)

    def toggleHeightfield(self):
        self.hf.setDebugEnabled(not self.hf.isDebugEnabled())

    def terrainFromHeightMap(self, main):
        self.parentNodePath = NodePath("FloorNodePath")
        self.parentNodePath.setPos(0, 0, -2)
        self.parentNodePath.setScale(5, 5, 0.75)
        # Heightfield (static)
        height = 8.0

        img = PNMImage(Filename('models/elevation.png'))
        xdim = img.getXSize()
        ydim = img.getYSize()
        shape = BulletHeightfieldShape(img, height, ZUp)
        shape.setUseDiamondSubdivision(True)
        self.rigidNode = BulletRigidBodyNode('Heightfield')
        self.rigidNode.notifyCollisions(False)
        self.rigidNodePath = self.parentNodePath.attachNewNode(self.rigidNode)
        self.rigidNodePath.node().addShape(shape)
        self.rigidNodePath.setPos(0, 0, 0)
        self.rigidNodePath.setCollideMask(BitMask32.allOn())
        self.rigidNodePath.node().notifyCollisions(False)

        main.world.attachRigidBody(self.rigidNodePath.node())

        self.hf = self.rigidNodePath.node() # To enable/disable debug visualisation

        self.terrain = GeoMipTerrain('terrain')
        self.terrain.setHeightfield(img)

        self.terrain.setBlockSize(32)
        self.terrain.setNear(50)
        self.terrain.setFar(100)
        self.terrain.setFocalPoint(base.camera)

        rootNP = self.terrain.getRoot()
        rootNP.reparentTo(self.parentNodePath)
        rootNP.setSz(8.0)

        offset = img.getXSize() / 2.0 - 0.5
        rootNP.setPos(-offset, -offset, -height / 2.0)

        self.terrain.generate()

        # Apply texture
        diffuseTexture = loader.loadTexture(Filename('models/diffuseMap.jpg'))
        diffuseTexture.setWrapU(Texture.WMRepeat)
        diffuseTexture.setWrapV(Texture.WMRepeat)
        rootNP.setTexture(diffuseTexture)

        # Normal map
        texStage = TextureStage('texStageNormal')
        texStage.setMode(TextureStage.MNormal)
        normalTexture = loader.loadTexture(Filename('models/normalMap.jpg'))
        rootNP.setTexture(texStage, normalTexture)

        # Glow map
        texStage = TextureStage('texStageNormal')
        texStage.setMode(TextureStage.MGlow)
        glowTexture = loader.loadTexture(Filename('models/glowMap.jpg'))
        rootNP.setTexture(texStage, glowTexture)
Example #7
0
    def generate(self):
        '''(Re)generate the entire terrain erasing any current changes'''
        factor = self.blockSize * self.chunkSize
        #print "Factor:", factor
        for terrain in self.terrains:
            terrain.getRoot().removeNode()
        self.terrains = []
        # Breaking master heightmap into subimages
        heightmaps = []
        self.xchunks = (self.heightfield.getXSize() - 1) / factor
        self.ychunks = (self.heightfield.getYSize() - 1) / factor
        #print "X,Y chunks:", self.xchunks, self.ychunks
        n = 0
        for y in range(0, self.ychunks):
            for x in range(0, self.xchunks):
                heightmap = PNMImage(factor + 1, factor + 1)
                heightmap.copySubImage(self.heightfield,
                                       0,
                                       0,
                                       xfrom=x * factor,
                                       yfrom=y * factor)
                heightmaps.append(heightmap)
                n += 1

        # Generate GeoMipTerrains
        n = 0
        y = self.ychunks - 1
        x = 0
        for heightmap in heightmaps:
            terrain = GeoMipTerrain(str(n))
            terrain.setHeightfield(heightmap)
            terrain.setBruteforce(self.bruteForce)
            terrain.setBlockSize(self.blockSize)
            terrain.generate()
            self.terrains.append(terrain)
            root = terrain.getRoot()
            root.reparentTo(self.root)
            root.setPos(n % self.xchunks * factor, (y) * factor, 0)

            # In order to texture span properly we need to reiterate through every vertex
            # and redefine the uv coordinates based on our size, not the subGeoMipTerrain's
            root = terrain.getRoot()
            children = root.getChildren()
            for child in children:
                geomNode = child.node()
                for i in range(geomNode.getNumGeoms()):
                    geom = geomNode.modifyGeom(i)
                    vdata = geom.modifyVertexData()
                    texcoord = GeomVertexWriter(vdata, 'texcoord')
                    vertex = GeomVertexReader(vdata, 'vertex')
                    while not vertex.isAtEnd():
                        v = vertex.getData3f()
                        t = texcoord.setData2f(
                            (v[0] + self.blockSize / 2 + self.blockSize * x) /
                            (self.xsize - 1),
                            (v[1] + self.blockSize / 2 + self.blockSize * y) /
                            (self.ysize - 1))
            x += 1
            if x >= self.xchunks:
                x = 0
                y -= 1
            n += 1
Example #8
0
class Game(DirectObject):
    def __init__(self):
        base.setBackgroundColor(0.1, 0.1, 0.8, 1)
        base.setFrameRateMeter(True)

        base.cam.setPos(0, -20, 4)
        base.cam.lookAt(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
        alightNP = render.attachNewNode(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.setDirection(Vec3(1, 1, -1))
        dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attachNewNode(dlight)

        render.clearLight()
        render.setLight(alightNP)
        render.setLight(dlightNP)

        # Input
        self.accept('escape', self.doExit)
        self.accept('r', self.doReset)
        self.accept('f1', self.toggleWireframe)
        self.accept('f2', self.toggleTexture)
        self.accept('f3', self.toggleDebug)
        self.accept('f5', self.doScreenshot)

        self.accept('x', self.toggleHeightfield)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('turnLeft', 'q')
        inputState.watchWithModifiers('turnRight', 'e')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def doExit(self):
        self.cleanup()
        sys.exit(1)

    def doReset(self):
        self.cleanup()
        self.setup()

    def toggleWireframe(self):
        base.toggleWireframe()

    def toggleTexture(self):
        base.toggleTexture()

    def toggleDebug(self):
        if self.debugNP.isHidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def doScreenshot(self):
        base.screenshot('Bullet')

    def toggleHeightfield(self):
        self.hf.setDebugEnabled(not self.hf.isDebugEnabled())

    # ____TASK___

    def processInput(self, dt):
        force = Vec3(0, 0, 0)
        torque = Vec3(0, 0, 0)

        if inputState.isSet('forward'): force.setY(1.0)
        if inputState.isSet('reverse'): force.setY(-1.0)
        if inputState.isSet('left'): force.setX(-1.0)
        if inputState.isSet('right'): force.setX(1.0)
        if inputState.isSet('turnLeft'): torque.setZ(1.0)
        if inputState.isSet('turnRight'): torque.setZ(-1.0)

        force *= 30.0
        torque *= 10.0

        self.boxNP.node().setActive(True)
        self.boxNP.node().applyCentralForce(force)
        self.boxNP.node().applyTorque(torque)

    def update(self, task):
        dt = globalClock.getDt()

        self.processInput(dt)
        self.world.doPhysics(dt, 10, 0.008)

        self.terrain.update()

        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.removeNode()

    def setup(self):
        self.worldNP = render.attachNewNode('World')

        # World
        self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug'))
        self.debugNP.show()
        self.debugNP.node().showNormals(True)

        self.world = BulletWorld()
        self.world.setGravity(Vec3(0, 0, -9.81))
        self.world.setDebugNode(self.debugNP.node())

        # Box (dynamic)
        shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))

        np = self.worldNP.attachNewNode(BulletRigidBodyNode('Box'))
        np.node().setMass(1.0)
        np.node().addShape(shape)
        np.setPos(0, 0, 4)
        np.setCollideMask(BitMask32.allOn())

        self.world.attachRigidBody(np.node())

        self.boxNP = np  # For applying force & torque

        visualNP = loader.loadModel('models/box.egg')
        visualNP.clearModelNodes()
        visualNP.reparentTo(self.boxNP)

        # Heightfield (static)
        height = 8.0

        img = PNMImage(Filename('models/elevation.png'))
        shape = BulletHeightfieldShape(img, height, ZUp)
        shape.setUseDiamondSubdivision(True)

        np = self.worldNP.attachNewNode(BulletRigidBodyNode('Heightfield'))
        np.node().addShape(shape)
        np.setPos(0, 0, 0)
        np.setCollideMask(BitMask32.allOn())

        self.world.attachRigidBody(np.node())

        self.hf = np.node()  # To enable/disable debug visualisation

        self.terrain = GeoMipTerrain('terrain')
        self.terrain.setHeightfield(img)

        self.terrain.setBlockSize(32)
        self.terrain.setNear(50)
        self.terrain.setFar(100)
        self.terrain.setFocalPoint(base.camera)

        rootNP = self.terrain.getRoot()
        rootNP.reparentTo(render)
        rootNP.setSz(8.0)

        offset = img.getXSize() / 2.0 - 0.5
        rootNP.setPos(-offset, -offset, -height / 2.0)

        self.terrain.generate()
class SMWorld(DirectObject):

	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Constructor
	# (Game state, Map name, Height of death plane)
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def __init__(self, mapID, tObj, aObj):

		self.mapID = mapID
		
		# EX: maps/map-1/map-1.yetimap
		metaFile = open("../maps/map" + str(self.mapID) + "/map" + str(self.mapID) + ".yetimap", 'r')
		metaLines = metaFile.readlines()
		lineCount = len(metaLines)
		self.snowflakeCount = lineCount - 2
		self.snowCount = 0
		
		# First Line: Player's starting position
		# EX: 50,50,50 (NO SPACES)
		playerLine = metaLines[0]
		playerPosList = playerLine.split(",")
		playerInitX = int(playerPosList[0])
		playerInitY = int(playerPosList[1])
		playerInitZ = int(playerPosList[2])
		self.playerStart = Point3(playerInitX, playerInitY, playerInitZ)
		
		# 2nd Line: Deathzone Height
		# ONE INTEGER
		self.deathHeight = int(metaLines[1])
		
		# Get dem snowflakes
		self.snowflakePositions = []
		print("Snowflake Count: " + str(self.snowflakeCount))
		for i in xrange(0, self.snowflakeCount):
			sfline = metaLines[i+2]
			sfList = sfline.split(",")
			sfx = int(sfList[0])
			sfy = int(sfList[1])
			sfz = int(sfList[2])
			self.snowflakePositions.append(Point3(sfx, sfy, sfz))
			print("New snowflake to add: (" + str(sfx) + "," + str(sfy) + "," + str(sfz) + ")")

		#load in controls
		ctrlFl = open("ctrConfig.txt")
		#will skip n lines where [n,]
		#makes a list of controls
		self.keymap = eval(ctrlFl.read())
		#close file
		ctrlFl.close()
		
		# Create new instances of our various objects
		self.mapName = str(mapID)
		self.audioMgr = aObj
		self.worldObj = self.setupWorld()
		self.heightMap = self.setupHeightmap(self.mapName)
		self.deathZone = self.setupDeathzone(self.deathHeight)
		self.debugNode = self.setupDebug()	
		
		# Player Init
		self.playerObj = SMPlayer(self.worldBullet, self.worldObj, self, self.playerStart, self.audioMgr)
		self.playerNP = self.playerObj.getNodePath()
		self.playerNP.setH(180);
		self.canUseShift = True
		self.canAirDash = True
		
		# Snowball Init
		self.ballObj = SMBall(self.worldBullet, self.worldObj, self.playerObj, self.playerNP)
		self.sbCollideFlag = False
		self.ballNP = self.ballObj.getNodePath()
		
		# Key Handler
		self.kh = SMKeyHandler()
		self.lastMousePos = self.kh.getMouse()
		
		# Collision Handler
		self.colObj = self.setupCollisionHandler()
		
		# Lighting
		self.ligObj = SMLighting(Vec4(.4, .4, .4, 1), Vec3(-5, -5, -5), Vec4(2.0, 2.0, 2.0, 1.0))
		
		# Camera
		self.camObj = SMCamera(self.playerObj, self.worldBullet, self.worldObj)
		self.cameraControl = False

		# GUI
		self.GUI = SMGUI()
		self.snowflakeCounter = SMGUICounter("snowflake", self.snowflakeCount) # Replace 3 with # of snowflakes in level.
		self.snowMeter = SMGUIMeter(100)
		self.GUI.addElement("snowflake", self.snowflakeCounter)
		self.GUI.addElement("snowMeter", self.snowMeter)
		
		#Snowy Outside
		# base.enableParticles()
		# self.p = ParticleEffect()
		# self.p.cleanup()
		# self.p = ParticleEffect()
		# self.p.loadConfig('snow.ptf')        
		# self.p.start(self.camObj.getNodePath())
		# self.p.setPos(0.00, 0.500, 0.000)

		# AI
		# self.goat1 = SMAI("../res/models/goat.egg", 75.0, self.worldBullet, self.worldObj, -70, -95, 5)
		# self.goat1.setBehavior("flee", self.playerNP)
		# self.goat2 = SMAI("../res/models/goat.egg", 75.0, self.worldBullet, self.worldObj, -80, -83, 5)
		# self.goat2.setBehavior("flee", self.playerNP)
		# print("AI Initialized")
		
		# Debug Text
		self.textObj = tObj
		self.textObj.addText("yetiPos", "Position: ")
		self.textObj.addText("yetiVel", "Velocity: ")
		self.textObj.addText("yetiFric", "Friction: ")
		self.textObj.addText("onIce", "Ice(%): ")
		self.textObj.addText("onSnow", "Snow(%): ")
		self.textObj.addText("terrHeight", "T Height: ")
		self.textObj.addText("terrSteepness", "Steepness: ")
		
		# Pause screen transition
		self.transition = Transitions(loader)

		# Method-based keybindings
		# self.accept('b', self.spawnBall)
		self.accept('escape', base.userExit)
		self.accept('enter', self.pauseUnpause)
		self.accept('f1', self.toggleDebug)
		
		self.accept('lshift-up', self.enableShiftActions)
		self.accept('mouse1', self.enableCameraControl)
		self.accept('mouse1-up', self.disableCameraControl)
		self.accept('wheel_up', self.camObj.zoomIn)
		self.accept('wheel_down', self.camObj.zoomOut)
		
		self.pauseUnpause()
		
		# Disable the mouse
		base.disableMouse()
		props = WindowProperties()
		props.setCursorHidden(True)
		base.win.requestProperties(props)
		
		# Uncomment this to see everything being rendered.
		self.printSceneGraph()
		
		# Play the BGM
		self.audioMgr.playBGM("snowmanWind")
		
		# Skybox formed
		skybox = loader.loadModel("../res/models/skybox.egg")
		# skybox.set_two_sided(true)
		skybox.setScale(500)
		skybox.setPos(0, 0, -450)
		skybox.reparentTo(render)
		
		mountain = loader.loadModel("../res/models/mountain.egg")
		mountain.reparentTo(render)
		mountain.setPos(650,800,20)
		mountain.setScale(120)
		
		self.colObjects = []
		
		self.caveNew = SMCollide("../res/models/cave_new.egg", self.worldBullet, self.worldObj, Point3(-50, 95, -13), 11, Vec3(0,0,0))
		self.colObjects.append(self.caveNew)
		
		self.planeFront = SMCollide("../res/models/plane_front", self.worldBullet, self.worldObj, Point3(190, -100, -15), 8, Vec3(190,0,30))
		self.colObjects.append(self.planeFront)
		
		self.caveModel = SMCollide("../res/models/cave_tunnel.egg", self.worldBullet, self.worldObj, Point3(233, 68, 32), 4, Vec3(135,180,0))
		self.colObjects.append(self.caveModel)
		
		self.planeTail = SMCollide("../res/models/plane_tail.egg", self.worldBullet, self.worldObj, Point3(-40, -130, -7), 10, Vec3(230,0,0))
		self.colObjects.append(self.planeTail)
		
		self.ropeBridge = SMCollide("../res/models/rope_bridge.egg", self.worldBullet, self.worldObj, Point3(180, 115, 30), 6, Vec3(50,0,0))
		self.colObjects.append(self.ropeBridge)
		
		self.colObjectCount = len(self.colObjects)
		
		print("World initialized.")


	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Enables the camera to be rotated by moving the mouse horizontally.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def enableCameraControl(self):
		self.cameraControl = True
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Disables the camera control.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def disableCameraControl(self):
		self.cameraControl = False
		
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Enables the use of shift actions again.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def enableShiftActions(self):
		self.canUseShift = True
		
	def disableShiftActions(self):
		self.canUseShift = False
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Respawns the yeti's snowball.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
		
	def spawnBall(self):
		if(not(self.playerObj.getAirborneFlag())):
			self.ballObj.respawn()
		
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Toggles the pause screen
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def pauseUnpause(self):
		if taskMgr.hasTaskNamed('UpdateTask'):
			taskMgr.remove('UpdateTask')
			self.transition.fadeScreen(0.5)
		else:
			taskMgr.add(self.update, 'UpdateTask')
			self.transition.noFade()
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Sets up the world and returns a NodePath of the BulletWorld
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def setupWorld(self):
		self.worldBullet = BulletWorld()
		self.worldBullet.setGravity(Vec3(0, 0, -GRAVITY))
		self.terrSteepness = -1
		wNP = render.attachNewNode('WorldNode')
		
		self.audioMgr.loadSFX("snowCrunch01")
		self.audioMgr.loadBGM("snowmanWind")
		
		return wNP
		
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Prints all nodes that are a child of render.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def printSceneGraph(self):
		print(render.ls())
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Initializes and returns a DebugNode NodePath.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def setupDebug(self):
		debug = BulletDebugNode()
		debug.showWireframe(False) # Yeah, don't set this to true unless you want to emulate an 80's computer running Crysis on Ultra settings.
		debug.showConstraints(True)
		debug.showBoundingBoxes(True) # This is the main use I have for it.
		debug.showNormals(True)
		debugNP = render.attachNewNode(debug)
		self.worldBullet.setDebugNode(debugNP.node())
		debugNP.hide()
		return debugNP
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Initializes and returns a BulletRigidBodyNode of the terrain, which loads the map with the specified name.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def setupHeightmap(self, name):
		
		# Automatically generate a heightmap mesh from a monochrome image.
		self.hmHeight = 120
		hmPath = "../maps/map" + name + "/map" + name + "-h.png"
		imPath = "../maps/map" + name + "/map" + name + "-i.png"
		smPath = "../maps/map" + name + "/map" + name + "-s.png"
		scmPath = "../maps/map" + name + "/map" + name + "-sc.png"
		print(hmPath)
		print(imPath)
		print(smPath)
		print(scmPath)
		hmImg = PNMImage(Filename(hmPath))
		hmShape = BulletHeightfieldShape(hmImg, self.hmHeight, ZUp)
		hmNode = BulletRigidBodyNode('Terrain')
		hmNode.addShape(hmShape)
		hmNode.setMass(0)
		self.hmNP = render.attachNewNode(hmNode)
		self.worldBullet.attachRigidBody(hmNode)
		self.hmOffset = hmImg.getXSize() / 2.0 - 0.5
		self.hmTerrain = GeoMipTerrain('gmTerrain')
		self.hmTerrain.setHeightfield(hmImg)
		
		# Optimizations and fixes
		self.hmTerrain.setBruteforce(True) # I don't think this is actually needed. 
		self.hmTerrain.setMinLevel(3) # THIS is what triangulates the terrain.
		self.hmTerrain.setBlockSize(128)  # This does a pretty good job of raising FPS.
		# Level-of-detail (not yet working)
		# self.hmTerrain.setNear(40)
		# self.hmTerrain.setFar(200)
		
		self.hmTerrain.generate()
		
		self.hmTerrainNP = self.hmTerrain.getRoot()
		self.hmTerrainNP.setSz(self.hmHeight)
		self.hmTerrainNP.setPos(-self.hmOffset, -self.hmOffset, -self.hmHeight / 2.0)
		self.hmTerrainNP.flattenStrong() # This only reduces the number of nodes; nothing to do with polys.
		self.hmTerrainNP.analyze()

		# Here begins the scenery mapping
		treeModel = loader.loadModel("../res/models/tree_1.egg")
		rockModel = loader.loadModel("../res/models/rock_1.egg")
		rock2Model = loader.loadModel("../res/models/rock_2.egg")
		rock3Model = loader.loadModel("../res/models/rock_3.egg")
		# caveModel = loader.loadModel("../res/models/cave_new.egg")
		# planeFrontModel = loader.loadModel("../res/models/plane_front.egg")
		# planeWingModel = loader.loadModel("../res/models/plane_wing.egg")
		texpk = loader.loadTexture(scmPath).peek()
		
		# GameObject nodepath for flattening
		self.objNP = render.attachNewNode("gameObjects")
		self.treeNP = self.objNP.attachNewNode("goTrees")
		self.rockNP = self.objNP.attachNewNode("goRocks")
		self.rock2NP = self.objNP.attachNewNode("goRocks2")
		self.rock3NP = self.objNP.attachNewNode("goRocks3")
		# self.caveNP = self.objNP.attachNewNode("goCave")
		# self.planeFrontNP = self.objNP.attachNewNode("goPlaneFront")
		# self.planeWingNP = self.objNP.attachNewNode("goPlaneWing")
		
		for i in range(0, texpk.getXSize()):
			for j in range(0, texpk.getYSize()):
				color = VBase4(0, 0, 0, 0)
				texpk.lookup(color, float(i) / texpk.getXSize(), float(j) / texpk.getYSize())
				if(int(color.getX() * 255.0) == 255.0):
					newTree = self.treeNP.attachNewNode("treeNode")
					treeModel.instanceTo(newTree)
					newTree.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
					# newTree.setScale(randint(0,4))
					newTree.setScale(2)
					
				if(int(color.getX() * 255.0) == 128):
					newRock = self.rockNP.attachNewNode("newRock")
					newRock.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
					rockModel.instanceTo(newRock)
					
				if(int(color.getX() * 255.0) == 77):
					newRock2 = self.rock2NP.attachNewNode("newRock2")
					newRock2.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
					rock2Model.instanceTo(newRock2)
					
				if(int(color.getX() * 255.0) == 102):
					newRock3 = self.rock3NP.attachNewNode("newRock3")
					newRock3.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
					rock3Model.instanceTo(newRock3)
					
				# if(int(color.getX() * 255.0) == 64):
					# newCave = self.caveNP.attachNewNode("newCave")
					# newCave.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
					# newCave.setScale(5)
					# newCave.setP(180)
					# caveModel.instanceTo(newCave)
				
				# if(int(color.getX() * 255.0) == 191):
					# newPlaneFront = self.planeFrontNP.attachNewNode("newPlaneFront")
					# newPlaneFront.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
					# newPlaneFront.setScale(6)
					# planeFrontModel.instanceTo(newPlaneFront)
					
				# if(int(color.getX() * 255.0) == 179):
					# newPlaneWing = self.planeWingNP.attachNewNode("newPlaneWing")
					# newPlaneWing.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2)
					# newPlaneWing.setScale(6)
					# newPlaneWing.setH(250)
					# newPlaneWing.setR(180)
					# newPlaneWing.setP(135)
					# planeWingModel.instanceTo(newPlaneWing)

		self.snowflakes = []
		
		for i in xrange(0, self.snowflakeCount):
			print("Call " + str(i))
			sf = SMCollect(self.worldBullet, self.worldObj, self.snowflakePositions[i])
			self.snowflakes.append(sf)
					
		# render.flattenStrong()
		self.hmTerrainNP.reparentTo(render)
		
		# Here begins the attribute mapping
		ts = TextureStage("stage-alpha")
		ts.setSort(0)
		ts.setPriority(1)
		ts.setMode(TextureStage.MReplace)
		ts.setSavedResult(True)
		self.hmTerrainNP.setTexture(ts, loader.loadTexture(imPath, smPath))

		ts = TextureStage("stage-stone")
		ts.setSort(1)
		ts.setPriority(1)
		ts.setMode(TextureStage.MReplace)
		self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/stone_tex.png"))
		self.hmTerrainNP.setTexScale(ts, 32, 32)

		ts = TextureStage("stage-ice")
		ts.setSort(2)
		ts.setPriority(1)
		ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor,
						 TextureStage.CSPrevious, TextureStage.COSrcColor,
						 TextureStage.CSLastSavedResult, TextureStage.COSrcColor)
		self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/ice_tex.png"))
		self.hmTerrainNP.setTexScale(ts, 32, 32)

		ts = TextureStage("stage-snow")
		ts.setSort(3)
		ts.setPriority(0)
		ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor,
						 TextureStage.CSPrevious, TextureStage.COSrcColor,
						 TextureStage.CSLastSavedResult, TextureStage.COSrcAlpha)
		self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/snow_tex_1.png"))
		self.hmTerrainNP.setTexScale(ts, 32, 32)

		# print(self.snowflakes)
		
		return hmNode
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Sets up and returns the death zone plane (returns its NodePath) with the specified height.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def setupDeathzone(self, height):
		planeShape = BulletPlaneShape(Vec3(0, 0, 1), 1)
		planeNode = BulletRigidBodyNode('DeathZone')
		planeNode.addShape(planeShape)
		planeNP = render.attachNewNode(planeNode)
		planeNP.setPos(0, 0, height)
		self.worldBullet.attachRigidBody(planeNode)
		return planeNP
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Sets up and returns the collision handler.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def setupCollisionHandler(self):
		colHand = SMCollisionHandler(self.worldBullet)
		return colHand
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Toggles showing bounding boxes.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def toggleDebug(self):
		if self.debugNode.isHidden():
			self.debugNode.show()
		else:
			self.debugNode.hide()
	
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Returns the terrain height of the nearest vertical descending raycast from the passed Point3.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def getTerrainHeight(self, pos):
		result = 0
		x = pos.getX()
		y = pos.getY()
		z = pos.getZ()
		rayTerrA = Point3(x, y, z)
		rayTerrB = Point3(x, y, z - 256)
		rayTest = self.worldBullet.rayTestClosest(rayTerrA, rayTerrB)
		
		rayNode = rayTest.getNode()
		if (rayTest.hasHit()):
			rayPos = rayTest.getHitPos()
			result = rayPos.getZ()
		else:
			self.playerObj.respawn()
		return result
		# return self.hmTerrain.get_elevation(x + self.hmOffset, y + self.hmOffset) * self.hmHeight
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Handles player movement
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def playerMove(self):
	
		# Go through the collision and flag tests, and update them
		self.doPlayerTests()
		
		# Rotation and camera movement
		if self.kh.poll(self.keymap['Left']):
			self.playerObj.turn(True)
		elif self.kh.poll(self.keymap['Right']):
			self.playerObj.turn(False)
		elif(self.cameraControl):
			newMousePos = self.kh.getMouse()
			mx = newMousePos.getX()
			self.camObj.rotateCamera(mx)
		
		self.camObj.calculatePosition()
		
		# Movement
		if self.kh.poll(self.keymap['Forward']):
			self.playerObj.move(True)
			self.camObj.rotateTowards(90)
		elif self.kh.poll(self.keymap['Back']):

			self.playerObj.move(False)
		else:
			self.playerObj.stop()

		# Jump
		if(self.kh.poll(self.keymap['Space']) and self.terrSteepness < 0.25): #and not(self.ballObj.isRolling())):
			self.playerObj.jump()
		else:
			self.playerObj.resetJump()
		
		# Air Dash
		if(self.kh.poll(self.keymap['airDash'])): #and self.playerObj.getAirborneFlag() == True and self.canAirDash == True):
			self.canAirDash = False
			self.playerObj.airDash()
		
		# Shift-based actions
		if(self.kh.poll("lshift") and not(self.sbCollideFlag) and not(self.playerObj.getAirborneFlag()) and self.canUseShift):
		
			# If there's another snowball already placed
			if(self.ballObj.exists() and not(self.ballObj.isRolling())):
				self.ballObj.respawn()
				
			# If we're rolling a snowball
			elif(self.ballObj.isRolling()):
			
				# Absorb snowball
				if(self.kh.poll("v")):
					self.canUseShift = False
					snowAmt = self.ballObj.getSnowAmount()
					self.playerObj.addSnow(snowAmt)
					# self.snowMeter.fillBy(snowAmt)
					self.ballObj.destroy()
					
				# Go to iceball throwing mode
				elif(self.kh.poll("b")):
					print("TODO: Ice ball throwing mode.")
					
				# Grow the snowball
				elif(self.kh.poll("w")):
					self.ballObj.grow()
					
			# Spawn a new snowball
			elif(self.ballObj.exists() == False):
				self.ballObj.respawn()
				
		# If the player is not pressing shift
		else:
			if(self.ballObj.isRolling()):
				self.ballObj.dropBall()

		base.win.movePointer(0, 400, 300)
		
		# So updating the stats is VERY expensive.
		if (self.debugNode.isHidden() == False):
			self.updateStats()
	
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Various tests concerning the player flags and collisions.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def doPlayerTests(self):
		
		# Player's position
		plPos = self.playerObj.getPosition()
		px = plPos.getX()
		py = plPos.getY()
		pz = plPos.getZ()
		
		# Raycast directly down for terrain steepness
		rayYetiA = Point3(px, py, pz)
		rayYetiB = Point3(px, py, pz - 300)
		self.downRayTest = self.worldBullet.rayTestClosest(rayYetiA, rayYetiB).getHitNormal()
		rx = self.downRayTest.getX()
		ry = self.downRayTest.getY()
		rz = self.downRayTest.getZ()
		self.terrSteepness = 1.0 - rz

		# Redo collision flags later
		objCollisionFlag = False
		
		# Snow/Ice height adjust
		self.playerObj.updateTerrain()
		
		# Collision: Player x Objects
		for i in xrange(0, self.colObjectCount):
			if(self.colObj.didCollide(self.playerNP.node(), self.colObjects[i].AINode)):
				objCollisionFlag = True
				self.playerObj.setAirborneFlag(False)
				self.canAirDash = True
				self.playerObj.setFactor(1,1,1)
		
		# Collision: Player x Snowball
		if(self.ballObj.exists() and self.colObj.didCollide(self.playerNP.node(), self.ballObj.getRigidbody())):
			self.sbCollideFlag = True
			self.playerObj.setAirborneFlag(False)
			self.playerObj.setFactor(1, 1, 1)
		else:
			self.sbCollideFlag = False
		
		# Collision: Player x Terrain
		if(self.colObj.didCollide(self.playerNP.node(), self.heightMap)):
			if(self.playerObj.getAirborneFlag()):
				self.audioMgr.playSFX("snowCrunch01")
			self.playerObj.setAirborneFlag(False)
			self.canAirDash = True
			self.playerObj.setFactor(1, 1, 1)
			objCollisionFlag = False
			
		# Collision: Player x Death Zone
		# if(pz - 7 <= self.deathHeight or (self.colObj.didCollide(self.playerNP.node(), self.deathZone.node()))):
		if(self.colObj.didCollide(self.playerNP.node(), self.deathZone.node())):
			print("Player confirmed #REKT")
			self.playerObj.respawn()
		
		# Out of bounds checking
		if(abs(px) > 254 or abs(py) > 254):
			print("Player out of bounds!")
			self.playerObj.respawn()
		
		# Snap to terrain if... something. I need to restructure this. Don't read it.
		if(not(self.playerObj.getAirborneFlag()) and not(self.sbCollideFlag) and not(objCollisionFlag)):
			z = self.getTerrainHeight(Point3(px, py, pz))
			self.playerObj.snapToTerrain(z)
			# self.playerObj.snapToTerrain(th, self.hmHeight)
		
		# Collision: Player x Snowflakes
		for i in xrange(0, self.snowflakeCount):
			if(self.snowflakes[i].exists() and self.colObj.didCollide(self.playerNP.node(), self.snowflakes[i].getNode())):
				self.snowflakes[i].destroy()
				self.snowflakeCounter.increment()
				self.snowCount += 1
			
		self.snowMeter.updateSnow(self.playerObj)
		
		#Check if there is a "next" level. If there is, load it. Otherwise display end game screen.
		if(self.snowCount >= self.snowflakeCount):
			file_path="../maps/map" + str(self.mapID+1) + "/map" + str(self.mapID+1) + ".yetimap"
			if  os.path.lexists(file_path):
			
				self.snowCount = 0
				self.snowflakeCount = 0
				self.snowflakeCounter.setValue(0)
				self.snowflakeCounter.setState(2)
				
				#Loading Screen
				self.transition.fadeScreen(0.7)	
				self.loadingText=OnscreenText("Loading...",1,fg=(1,1,1,0),pos=(0,0),align=TextNode.ACenter,scale=.07,mayChange=1)
				base.graphicsEngine.renderFrame() 
				base.graphicsEngine.renderFrame() 
				base.graphicsEngine.renderFrame() 
				base.graphicsEngine.renderFrame()
				self.transition.noFade()
				
				#destroy objects
				self.worldBullet.removeRigidBody(self.heightMap)
				self.hmTerrainNP.removeNode()
				self.objNP.removeNode()
				self.treeNP.removeNode()
				self.rockNP.removeNode()
				self.rock2NP.removeNode()
				self.rock3NP.removeNode()
				# self.caveNP.removeNode()
				# self.planeFrontNP.removeNode()
				# self.planeWingNP.removeNode()
				self.hmNP.removeNode()
				if(int(self.mapID) == 1):
					self.ropeBridge.AIChar.setPos(-200,-300,-200)
					# self.ropeBridge.AIChar.removeNode()
					self.planeFront.AIChar.removeNode()
					self.planeTail.AIChar.setPos(-200,-200,-200)
					# self.planeTail.AIChar.removeNode()
					self.caveNew.AIChar.setPos(-1000,-1000,-1000);
					self.caveModel.AIChar.removeNode()
					#Added More Props here!
					self.boulder = SMCollide("../res/models/rock_3.egg", self.worldBullet, self.worldObj, Point3(117, 123, 17), 15, Vec3(0,0,0))
				elif(int(self.mapID) == 2):
					self.boulder.AIChar.setPos(-222,-222,-222)
					self.caveNew.AIChar.setScale(150)
					self.caveNew.AIChar.setPos(-50, 95, -50)
					# self.skybox.setScale(600)
					# self.caveNew.setH(0)
					# self.boulder.removeNode()
			
				self.mapID += 1
				print self.mapID
				# EX: maps/map-1/map-1.yetimap
				metaFile = open("../maps/map" + str(self.mapID) + "/map" + str(self.mapID) + ".yetimap", 'r')
				metaLines = metaFile.readlines()
				lineCount = len(metaLines)
				self.snowflakeCount = lineCount - 2
			
				# First Line: Player's starting position
				# EX: 50,50,50 (NO SPACES)
				playerLine = metaLines[0]
				playerPosList = playerLine.split(",")
				playerInitX = int(playerPosList[0])
				playerInitY = int(playerPosList[1])
				playerInitZ = int(playerPosList[2])
				self.playerObj.playerNP.setPos(playerInitX, playerInitY, playerInitZ)
				self.playerObj.startX = playerInitX
				self.playerObj.startY = playerInitY
				self.playerObj.startZ = playerInitZ
			
				# 2nd Line: Deathzone Height
				# ONE INTEGER
				self.deathHeight = int(metaLines[1])
			
				
				self.snowflakePositions = []
				print("Snowflake Count: " + str(self.snowflakeCount))
				for i in xrange(0, self.snowflakeCount):
					sfline = metaLines[i+2]
					sfList = sfline.split(",")
					sfx = int(sfList[0])
					sfy = int(sfList[1])
					sfz = int(sfList[2])
					self.snowflakePositions.append(Point3(sfx, sfy, sfz))
					print("New snowflake to add: (" + str(sfx) + "," + str(sfy) + "," + str(sfz) + ")")
				self.snowflakeCounter.setMaxValue(self.snowflakeCount)
				
				#load new map
				self.mapName = str(self.mapID)
				self.heightMap = self.setupHeightmap(self.mapName)
				self.deathZone = self.setupDeathzone(self.deathHeight)
					
				
				self.loadingText.cleanup() 
			else:
				taskMgr.remove('UpdateTask')
				self.endImage=OnscreenImage(image = "../res/icons/endgame1.png", pos = (0.0, 0.0, 0.0), scale = (1.35, 2, 1))
				
		
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Update the debug text.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def updateStats(self):
		pos = self.playerObj.getPosition()
		x = pos.getX()
		y = pos.getY()
		z = pos.getZ()
		vel = self.playerObj.getVelocity()
		vx = str(round(vel.getX(), 1))
		vy = str(round(vel.getY(), 1))
		vz = str(round(vel.getZ(), 1))
		sx = str(round(x, 1))
		sy = str(round(y, 1))
		sz = str(round(z, 1))
		rx = str(round(self.downRayTest.getX(), 2))
		ry = str(round(self.downRayTest.getY(), 2))
		rz = str(round(self.terrSteepness, 2))
		fric = str(round(self.playerObj.getFriction(), 2))
		ip = str(round(self.playerObj.getIceCoefficient(), 2))
		sp = str(round(self.playerObj.getSnowCoefficient(), 2))
		tHeight = str(round(self.getTerrainHeight(Point3(x, y, z)), 1))
		self.textObj.editText("yetiPos", "Position: (" + sx + ", " + sy + ", " + sz + ")")
		self.textObj.editText("yetiVel", "Velocity: (" + vx + ", " + vy + ", " + vz + ")")
		self.textObj.editText("yetiFric", "Friction: " + fric)
		self.textObj.editText("onIce", "Ice(%): " + ip)
		self.textObj.editText("onSnow", "Snow(%): " + sp)
		self.textObj.editText("terrHeight", "T Height: " + tHeight)
		self.textObj.editText("terrSteepness", "Steepness: " + rz)

	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# throw Snowball
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	def throw(self):
		self.throwing = True
		size = self.ballObj.getSize()
		#zoom camera and grab pos you wish to throw
		self.camObj.aimMode()
		taskMgr.add(self.controlCamera, "camera-task")
		rotation = self.camObj.getH()
		pitch =self.camObj.getP()
		self.ballObj.throwBall(size, pitch, rotation)
		#fix camera
		#self.throwing = False
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	# Update the world. Called every frame.
	#------------------------------------------------------------------------------------------------------------------------------------------------------------
	
	def update(self, task):
		dt = globalClock.getDt()
		self.worldBullet.doPhysics(dt)
		# self.goat1.AIUpdate()
		# self.goat2.AIUpdate()
		self.playerMove()
		return task.cont
Example #10
0
class Terrain():

    def __init__(self, _heightField):

    	texture = loader.loadTexture("ground_tex.png")
        self.zScale = 45

        self.terrain = GeoMipTerrain("BasicTerrain")
        self.terrain.setHeightfield(_heightField)

        # Dynamic settings?
        self.terrain.setBlockSize(16)
        self.terrain.setNear(20)
        self.terrain.setFar(100)
        self.terrain.setFocalPoint(base.camera)

        # Settings
        self.terrain.getRoot().setSz(self.zScale)
        self.terrain.getRoot().setTexture(texture)
        self.terrain.getRoot().reparentTo(render)
        self.terrain.generate()

        self.terrainSize = (self.terrain.heightfield().getReadXSize(), self.terrain.heightfield().getReadYSize())
        print "Terrain Size:", self.terrainSize
        taskMgr.add(self.terrainTask, "TerrainTask")

        self.skydome = loader.loadModel("Skydome")
        self.skydome.setDepthTest(False)
        self.skydome.setAttrib(CullBinAttrib.make("skydomeBin", 1000))
        self.skydome.reparentTo(camera)
        self.skydome.setScale(2)
        self.skydome.setPos(0, 0, -0.5)
        self.skydome.setCollideMask(BitMask32.allOff())
        taskMgr.add(self.skydomeTask, "paperplanet_skydome")

        # Add some fancy fog
        self.fog = Fog("Fog Name")
        self.fog.setColor(0.4,0.2,0.3)
        self.fog.setExpDensity(0.015)
        render.setFog(self.fog)

        # Some Test light
        dlight = DirectionalLight("dlight")
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(0, -60, 0)
        render.setLight(dlnp)


        # Add basic blacksmith hut
        tmp = loader.loadModel("blacksmith_hut")
        tmp.reparentTo(render)
        tmp.setPos(164.054, 340.92, 11.3384)

    def skydomeTask(self, task):
        self.skydome.setHpr(render, 0,0,0)
        return task.cont

    def terrainTask(self, task):
        # tmp
        self.terrain.update()
        return task.cont
Example #11
0
class Game(DirectObject):

  def __init__(self):
    base.setBackgroundColor(0.1, 0.1, 0.8, 1)
    base.setFrameRateMeter(True)

    base.cam.setPos(0, -20, 4)
    base.cam.lookAt(0, 0, 0)

    # Light
    alight = AmbientLight('ambientLight')
    alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
    alightNP = render.attachNewNode(alight)

    dlight = DirectionalLight('directionalLight')
    dlight.setDirection(Vec3(1, 1, -1))
    dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))
    dlightNP = render.attachNewNode(dlight)

    render.clearLight()
    render.setLight(alightNP)
    render.setLight(dlightNP)

    # Input
    self.accept('escape', self.doExit)
    self.accept('r', self.doReset)
    self.accept('f1', self.toggleWireframe)
    self.accept('f2', self.toggleTexture)
    self.accept('f3', self.toggleDebug)
    self.accept('f5', self.doScreenshot)

    self.accept('x', self.toggleHeightfield)

    inputState.watchWithModifiers('forward', 'w')
    inputState.watchWithModifiers('left', 'a')
    inputState.watchWithModifiers('reverse', 's')
    inputState.watchWithModifiers('right', 'd')
    inputState.watchWithModifiers('turnLeft', 'q')
    inputState.watchWithModifiers('turnRight', 'e')

    # Task
    taskMgr.add(self.update, 'updateWorld')

    # Physics
    self.setup()

  # _____HANDLER_____

  def doExit(self):
    self.cleanup()
    sys.exit(1)

  def doReset(self):
    self.cleanup()
    self.setup()

  def toggleWireframe(self):
    base.toggleWireframe()

  def toggleTexture(self):
    base.toggleTexture()

  def toggleDebug(self):
    if self.debugNP.isHidden():
      self.debugNP.show()
    else:
      self.debugNP.hide()

  def doScreenshot(self):
    base.screenshot('Bullet')

  def toggleHeightfield(self):
    self.hf.setDebugEnabled(not self.hf.isDebugEnabled())

  # ____TASK___

  def processInput(self, dt):
    force = Vec3(0, 0, 0)
    torque = Vec3(0, 0, 0)

    if inputState.isSet('forward'): force.setY( 1.0)
    if inputState.isSet('reverse'): force.setY(-1.0)
    if inputState.isSet('left'):    force.setX(-1.0)
    if inputState.isSet('right'):   force.setX( 1.0)
    if inputState.isSet('turnLeft'):  torque.setZ( 1.0)
    if inputState.isSet('turnRight'): torque.setZ(-1.0)

    force *= 30.0
    torque *= 10.0

    self.boxNP.node().setActive(True)
    self.boxNP.node().applyCentralForce(force)
    self.boxNP.node().applyTorque(torque)

  def update(self, task):
    dt = globalClock.getDt()

    self.processInput(dt)
    self.world.doPhysics(dt, 10, 0.008)

    self.terrain.update()

    return task.cont

  def cleanup(self):
    self.world = None
    self.worldNP.removeNode()

  def setup(self):
    self.worldNP = render.attachNewNode('World')

    # World
    self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug'))
    self.debugNP.show()
    self.debugNP.node().showNormals(True)

    self.world = BulletWorld()
    self.world.setGravity(Vec3(0, 0, -9.81))
    self.world.setDebugNode(self.debugNP.node())

    # Box (dynamic)
    shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))

    np = self.worldNP.attachNewNode(BulletRigidBodyNode('Box'))
    np.node().setMass(1.0)
    np.node().addShape(shape)
    np.setPos(0, 0, 4)
    np.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(np.node())

    self.boxNP = np # For applying force & torque


    visualNP = loader.loadModel('models/box.egg')
    visualNP.clearModelNodes()
    visualNP.reparentTo(self.boxNP)

    # Heightfield (static)
    height = 8.0

    img = PNMImage(Filename('models/elevation.png'))
    shape = BulletHeightfieldShape(img, height, ZUp)
    shape.setUseDiamondSubdivision(True)

    np = self.worldNP.attachNewNode(BulletRigidBodyNode('Heightfield'))
    np.node().addShape(shape)
    np.setPos(0, 0, 0)
    np.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(np.node())

    self.hf = np.node() # To enable/disable debug visualisation

    self.terrain = GeoMipTerrain('terrain')
    self.terrain.setHeightfield(img)
 
    self.terrain.setBlockSize(32)
    self.terrain.setNear(50)
    self.terrain.setFar(100)
    self.terrain.setFocalPoint(base.camera)
 
    rootNP = self.terrain.getRoot()
    rootNP.reparentTo(render)
    rootNP.setSz(8.0)

    offset = img.getXSize() / 2.0 - 0.5
    rootNP.setPos(-offset, -offset, -height / 2.0)
 
    self.terrain.generate()
Example #12
0
class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        # Load the environment model.
        self.setup_environment()
        #self.scene = self.loader.loadModel("models/environment")
        # Reparent the model to render.
        #self.scene.reparentTo(self.render)
        # Apply scale and position transforms on the model.
        #self.scene.setScale(0.25, 0.25, 0.25)
        #self.scene.setPos(-8, 42, 0)

        # Needed for camera image
        self.dr = self.camNode.getDisplayRegion(0)

        # Needed for camera depth image
        winprops = WindowProperties.size(self.win.getXSize(),
                                         self.win.getYSize())
        fbprops = FrameBufferProperties()
        fbprops.setDepthBits(1)
        self.depthBuffer = self.graphicsEngine.makeOutput(
            self.pipe, "depth buffer", -2, fbprops, winprops,
            GraphicsPipe.BFRefuseWindow, self.win.getGsg(), self.win)
        self.depthTex = Texture()
        self.depthTex.setFormat(Texture.FDepthComponent)
        self.depthBuffer.addRenderTexture(self.depthTex,
                                          GraphicsOutput.RTMCopyRam,
                                          GraphicsOutput.RTPDepth)
        lens = self.cam.node().getLens()
        lens.setFov(90.0, 90.0)
        # the near and far clipping distances can be changed if desired
        # lens.setNear(5.0)
        # lens.setFar(500.0)
        self.depthCam = self.makeCamera(self.depthBuffer,
                                        lens=lens,
                                        scene=self.render)
        self.depthCam.reparentTo(self.cam)

        # TODO: Scene is rendered twice: once for rgb and once for depth image.
        # How can both images be obtained in one rendering pass?
        self.render.setAntialias(AntialiasAttrib.MAuto)

    def setup_environment(self):
        # encapsulate some stuff

        # set up ambient lighting
        self.alight = AmbientLight('alight')
        self.alight.setColor(VBase4(0.1, 0.1, 0.1, 1))
        self.alnp = self.render.attachNewNode(self.alight)
        self.render.setLight(self.alnp)

        # set up a point light
        self.plight = PointLight('plight')
        self.plight.setColor(VBase4(0.8, 0.8, 0.8, 1))
        self.plnp = self.render.attachNewNode(self.plight)
        self.plnp.setPos(0, 0, 100)
        self.render.setLight(self.plnp)

        # set up terrain model
        self.terr_material = Material()
        self.terr_material.setShininess(1.0)
        self.terr_material.setAmbient(VBase4(0, 0, 0, 0))
        self.terr_material.setDiffuse(VBase4(1, 1, 1, 1))
        self.terr_material.setEmission(VBase4(0, 0, 0, 0))
        self.terr_material.setSpecular(VBase4(0, 0, 0, 0))

        # general scaling
        self.trrHorzSc = 4.0
        self.trrVertSc = 4.0  # was 4.0

        # Create sky
        #terrctr = self.trrHorzSc*65.0
        #self.setup_skybox(terrctr,800.0,2.0,0.3)

        self.skysphere = self.loader.loadModel("sky-forest/SkySphere.bam")
        self.skysphere.setBin('background', 1)
        self.skysphere.setDepthWrite(0)
        self.skysphere.reparentTo(self.render)

        # Load some textures
        self.grsTxtSc = 5
        self.numTreeTexts = 7

        # ground texture
        self.txtGrass = self.loader.loadTexture('tex/ground005.png')
        self.txtGrass.setWrapU(Texture.WM_mirror)
        self.txtGrass.setWrapV(Texture.WM_mirror)
        self.txtGrass.setMagfilter(Texture.FTLinear)
        self.txtGrass.setMinfilter(Texture.FTLinearMipmapLinear)

        # set up terrain texture stages
        self.TS1 = TextureStage('terrtext')
        self.TS1.setSort(0)
        self.TS1.setMode(TextureStage.MReplace)

        # Set up the GeoMipTerrain
        self.terrain = GeoMipTerrain("myDynamicTerrain")
        img = PNMImage(Filename('tex/bowl_height_map.png'))
        self.terrain.setHeightfield(img)
        self.terrain.setBruteforce(0)
        self.terrain.setAutoFlatten(GeoMipTerrain.AFMMedium)

        # Set terrain properties
        self.terrain.setBlockSize(32)
        self.terrain.setNear(50)
        self.terrain.setFar(500)
        self.terrain.setFocalPoint(self.camera)

        # Store the root NodePath for convenience
        self.root = self.terrain.getRoot()
        self.root.clearTexture()
        self.root.setTwoSided(0)
        self.root.setCollideMask(BitMask32.bit(0))
        self.root.setSz(self.trrVertSc)
        self.root.setSx(self.trrHorzSc)
        self.root.setSy(self.trrHorzSc)
        self.root.setMaterial(self.terr_material)
        self.root.setTexture(self.TS1, self.txtGrass)
        self.root.setTexScale(self.TS1, self.grsTxtSc, self.grsTxtSc)
        offset = 0.5 * img.getXSize() * self.trrHorzSc - 0.5
        self.root.setPos(-offset, -offset, 0)

        self.terrain.generate()
        self.root.reparentTo(self.render)

        # load tree billboards
        self.txtTreeBillBoards = []
        for a in range(self.numTreeTexts):
            fstr = 'trees/tree' + '%03d' % (a + 991)
            self.txtTreeBillBoards.append( \
                self.loader.loadTexture(fstr + '-color.png', fstr + '-opacity.png'))
            self.txtTreeBillBoards[a].setMinfilter(
                Texture.FTLinearMipmapLinear)

        #self.placePlantOnTerrain('trees',300,0,20,20,self.trrHorzSc,self.trrVertSc, \
        #    self.numTreeTexts,self.txtTreeBillBoards,'scene-def/trees.txt')
        self.setup_house()
        self.setup_vehicle()

        self.taskMgr.add(self.skysphereTask, "SkySphere Task")

    def setup_house(self):
        # place farmhouse on terrain
        self.house = ModelNode('house1')
        self.loadModelOntoTerrain(self.render, self.terrain, self.house, 43.0,
                                  0.275, 0.0, 0.0, self.trrHorzSc,
                                  self.trrVertSc, 'models/FarmHouse',
                                  Vec3(0, 0, 0),
                                  Point3(-12.0567, -29.1724, 0.0837742),
                                  Point3(12.2229, 21.1915, 21.3668))

    def setup_vehicle(self):
        # place HMMWV on terrain
        self.hmmwv = ModelNode('hmmwv1')
        self.loadModelOntoTerrain(self.render, self.terrain, self.hmmwv, 33.0,
                                  1.0, 20.0, 24.0, self.trrHorzSc,
                                  self.trrVertSc, 'models/hmmwv',
                                  Vec3(0, -90, 0),
                                  Point3(-1.21273, -2.49153, -1.10753),
                                  Point3(1.21273, 2.49153, 1.10753))

    def setup_skybox(self,
                     terrctr=645.0,
                     boxsz=1000.0,
                     aspect=1.0,
                     uplift=0.0):
        vsz = boxsz / aspect
        self.bckgtx = []
        self.bckgtx.append(self.loader.loadTexture('sky/Back2.png'))
        self.bckgtx.append(self.loader.loadTexture('sky/Right2.png'))
        self.bckgtx.append(self.loader.loadTexture('sky/Front2.png'))
        self.bckgtx.append(self.loader.loadTexture('sky/Left2.png'))
        self.bckgtx.append(self.loader.loadTexture('sky/Up.png'))
        for a in range(4):
            self.bckg = CardMaker('bkcard')
            lr = Point3(0.5 * boxsz, 0.5 * boxsz, -0.5 * vsz)
            ur = Point3(0.5 * boxsz, 0.5 * boxsz, 0.5 * vsz)
            ul = Point3(-0.5 * boxsz, 0.5 * boxsz, 0.5 * vsz)
            ll = Point3(-0.5 * boxsz, 0.5 * boxsz, -0.5 * vsz)
            self.bckg.setFrame(ll, lr, ur, ul)
            self.bckg.setHasNormals(0)
            self.bckg.setHasUvs(1)
            #self.bckg.setUvRange(self.bckgtx[a])
            bkcrd = self.render.attachNewNode(self.bckg.generate())
            bkcrd.setTexture(self.bckgtx[a])
            self.bckgtx[a].setWrapU(Texture.WMClamp)
            self.bckgtx[a].setWrapV(Texture.WMClamp)
            bkcrd.setLightOff()
            bkcrd.setFogOff()
            bkcrd.setHpr(90.0 * a, 0, 0)
            cz = 0.5 * boxsz * uplift
            #print 'set card at:', terrctr,terrctr,cz, ' with points: ', lr,ur,ul,ll
            bkcrd.setPos(terrctr, terrctr, cz)
            self.top = CardMaker('bkcard')
            lr = Point3(0.5 * boxsz, -0.5 * boxsz, 0)
            ur = Point3(0.5 * boxsz, 0.5 * boxsz, 0)
            ul = Point3(-0.5 * boxsz, 0.5 * boxsz, 0)
            ll = Point3(-0.5 * boxsz, -0.5 * boxsz, 0)
            self.top.setFrame(ll, lr, ur, ul)
            self.top.setHasNormals(0)
            self.top.setHasUvs(1)
            #self.top.setUvRange(self.bckgtx[4])
            bkcrd = self.render.attachNewNode(self.bckg.generate())
            bkcrd.setTexture(self.bckgtx[4])
            self.bckgtx[4].setWrapU(Texture.WMClamp)
            self.bckgtx[4].setWrapV(Texture.WMClamp)
            bkcrd.setLightOff()
            bkcrd.setFogOff()
            bkcrd.setHpr(0, 90, 90)
            bkcrd.setPos(terrctr, terrctr, 0.5 * vsz + 0.5 * boxsz * uplift)

    def placePlantOnTerrain(self, itemStr, itemCnt, Mode, typItemWidth,
                            typItemHeight, trrHorzSc, trrVertSc, numTxtTypes,
                            txtList, planFileName):
        # Billboarding plants
        crd = CardMaker('mycard')
        crd.setColor(0.5, 0.5, 0.5, 1)
        ll = Point3(-0.5 * typItemWidth, 0, 0)
        lr = Point3(0.5 * typItemWidth, 0, 0)
        ur = Point3(0.5 * typItemWidth, 0, typItemHeight)
        ul = Point3(-0.5 * typItemWidth, 0, typItemHeight)
        crd.setFrame(ll, lr, ur, ul)
        crd.setHasNormals(False)
        crd.setHasUvs(True)
        # generate/save/load locations
        try:
            plan_data_fp = open(planFileName, 'r')
            item_list = []
            for line in plan_data_fp:
                toks = line.split(',')
                px = float(toks[0].strip(' '))
                py = float(toks[1].strip(' '))
                ang = float(toks[2].strip(' '))
                dht = float(toks[3].strip(' '))
                scl = float(toks[4].strip(' '))
                idx = int(toks[5].strip(' '))
                item_list.append((px, py, ang, dht, scl, idx))
            plan_data_fp.close()
            print 'loaded ', itemStr, ' data file of size:', len(item_list)
        except IOError:
            # generate list and try to save
            item_list = []
            for a in range(itemCnt):
                px = random.randrange(-self.trrHorzSc * 64,
                                      self.trrHorzSc * 64)
                py = random.randrange(-self.trrHorzSc * 64,
                                      self.trrHorzSc * 64)
                ang = 180 * random.random()
                dht = 0.0
                scl = 0.75 + 0.25 * (random.random() + random.random())
                idx = random.randrange(0, numTxtTypes)
                item_list.append([px, py, ang, dht, scl, idx])
            try:
                plan_data_fp = open(planFileName, 'w')
                for c in item_list:
                    print >> plan_data_fp, c[0], ',', c[1], ',', c[2], ',', c[
                        3], ',', c[4], ',', c[5]
                plan_data_fp.close()
                print 'saved ', itemStr, ' data of size: ', len(item_list)
            except IOError:
                print 'unable to store ', itemStr, ' data of size: ', len(
                    item_list)
        # define each plant
        for c in item_list:
            px = c[0]
            py = c[1]
            ang = c[2]
            dht = c[3]
            scl = c[4]
            idx = c[5]
            if idx >= numTxtTypes:
                idx = 0
            if Mode > 0:
                for b in range(Mode):
                    crdNP = self.render.attachNewNode(crd.generate())
                    crdNP.setTexture(txtList[idx])
                    crdNP.setScale(scl)
                    crdNP.setTwoSided(True)
                    ht = self.terrain.getElevation(px / trrHorzSc,
                                                   py / trrHorzSc)
                    crdNP.setPos(px, py, ht * trrVertSc + dht)
                    crdNP.setHpr(ang + (180 / Mode) * b, 0, 0)
                    crdNP.setTransparency(TransparencyAttrib.MAlpha)
                    crdNP.setLightOff()
            else:
                # set up item as defined
                crd.setUvRange(txtList[idx])
                crdNP = self.render.attachNewNode(crd.generate())
                crdNP.setBillboardAxis()
                crdNP.setTexture(txtList[idx])
                crdNP.setScale(scl)
                ht = self.terrain.getElevation(px / trrHorzSc, py / trrHorzSc)
                crdNP.setPos(px, py, ht * trrVertSc)
                crdNP.setTransparency(TransparencyAttrib.MAlpha)
                crdNP.setLightOff()

    def loadModelOntoTerrain(self, render_node, terr_obj, model_obj, hdg, scl,
                             xctr, yctr, terr_horz_sc, terr_vert_sc,
                             model_path, rotA, minP, maxP):
        # load model onto terrain
        hdg_rads = hdg * math.pi / 180.0
        model_obj = self.loader.loadModel(model_path)
        rotAll = rotA
        rotAll.setX(rotAll.getX() + hdg)
        model_obj.setHpr(rotA)
        model_obj.setLightOff()
        # if model changes, these will have to be recomputed
        # minP = Point3(0,0,0)
        # maxP = Point3(0,0,0)
        # model_obj.calcTightBounds(minP,maxP)
        print minP
        print maxP
        htl = []
        maxzofs = -1000.0
        for xi in [minP[0], maxP[0]]:
            for yi in [minP[1], maxP[1]]:
                tx = xctr + scl * xi * math.cos(hdg_rads)
                ty = yctr + scl * yi * math.sin(hdg_rads)
                tht = self.terrain.getElevation(tx / terr_horz_sc,
                                                ty / terr_horz_sc)
                print 'tx=', tx, ', ty=', ty, ', tht=', tht
                htl.append(tht * terr_vert_sc - minP.getZ())
        for hi in htl:
            if hi > maxzofs:
                maxzofs = hi
        print maxzofs
        model_obj.setPos(xctr, yctr, maxzofs)
        model_obj.setHpr(rotAll)
        model_obj.setScale(scl)
        model_obj.reparentTo(render_node)
        return maxzofs, minP, maxP

    def get_camera_image(self, requested_format=None):
        """
        Returns the camera's image, which is of type uint8 and has values
        between 0 and 255.
        The 'requested_format' argument should specify in which order the
        components of the image must be. For example, valid format strings are
        "RGBA" and "BGRA". By default, Panda's internal format "BGRA" is used,
        in which case no data is copied over.
        """
        tex = self.dr.getScreenshot()
        if requested_format is None:
            data = tex.getRamImage()
        else:
            data = tex.getRamImageAs(requested_format)
        image = np.frombuffer(
            data.get_data(),
            np.uint8)  # use data.get_data() instead of data in python 2
        image.shape = (tex.getYSize(), tex.getXSize(), tex.getNumComponents())
        image = np.flipud(image)
        return image

    def get_camera_depth_image(self):
        """
        Returns the camera's depth image, which is of type float32 and has
        values between 0.0 and 1.0.
        """
        data = self.depthTex.getRamImage()
        depth_image = np.frombuffer(data.get_data(), np.float32)
        depth_image.shape = (self.depthTex.getYSize(),
                             self.depthTex.getXSize(),
                             self.depthTex.getNumComponents())
        depth_image = np.flipud(depth_image)
        '''
        
        Surface position can be inferred by calculating backward from the
        depth buffer. Each pixel on the screen represents a ray from the
        camera into the scene, and the depth value in the pixel indicates a
        distance along the ray. Because of this, it is not actually necessary
        to store surface position explicitly - it is only necessary to store
        depth values. Of course, OpenGL does that for free.

        So the framebuffer now needs to store surface normal, diffuse color,
        and depth value (to infer surface position). In practice, most
        ordinary framebuffers can only store color and depth - they don't have
        any place to store a third value. So we need to use a special
        offscreen buffer with an "auxiliary" bitplane. The auxiliary bitplane
        stores the surface normal.

        So then, there's the final postprocessing pass. This involves
        combining the diffuse color texture, the surface normal texture, the
        depth texture, and the light parameters into a final rendered output.
        The light parameters are passed into the postprocessing shader as
        constants, not as textures.

        If there are a lot of lights, things get interesting. You use one
        postprocessing pass per light. Each pass only needs to scan those
        framebuffer pixels that are actually in range of the light in
        question. To traverse only the pixels that are affected by the light,
        just render the illuminated area's convex bounding volume.

        The shader to store the diffuse color and surface normal is trivial.
        But the final postprocessing shader is a little complicated. What
        makes it tricky is that it needs to regenerate the original surface
        position from the screen position and depth value. The math for that
        deserves some explanation.

        We need to take a clip-space coordinate and depth-buffer value
        (ClipX,ClipY,ClipZ,ClipW) and unproject it back to a view-space
        (ViewX,ViewY,ViewZ) coordinate. Lighting is then done in view-space.

        Okay, so here's the math. Panda uses the projection matrix to
        transform view-space into clip-space. But in practice, the projection
        matrix for a perspective camera always contains four nonzero
        constants, and they're always in the same place:
            
        -- here are the non-zero elements of the projection matrix --
        
        A	0	0	0
        0	0	B	1
        0	C	0	0
        0	0	D	0
        
        -- precompute these from above projection matrix --
        '''
        proj = self.cam.node().getLens().getProjectionMat()
        proj_x = 0.5 * proj.getCell(3, 2) / proj.getCell(0, 0)
        proj_y = 0.5 * proj.getCell(3, 2)
        proj_z = 0.5 * proj.getCell(3, 2) / proj.getCell(2, 1)
        proj_w = -0.5 - 0.5 * proj.getCell(1, 2)
        '''
        -- now for each pixel compute viewpoint coordinates --
        
        viewx = (screenx * projx) / (depth + projw)
        viewy = (1 * projy) / (depth + projw)
        viewz = (screeny * projz) / (depth + projw)
        '''
        grid = np.mgrid[0:depth_image.shape[0], 0:depth_image.shape[1]]
        ygrid = np.float32(np.squeeze(
            grid[0, :, :])) / float(depth_image.shape[0] - 1)
        ygrid -= 0.5
        xgrid = np.float32(np.squeeze(
            grid[1, :, :])) / float(depth_image.shape[1] - 1)
        xgrid -= 0.5
        xview = 2.0 * xgrid * proj_x
        zview = 2.0 * ygrid * proj_z
        denom = np.squeeze(depth_image) + proj_w
        xview = xview / denom
        yview = proj_y / denom
        zview = zview / denom
        sqrng = xview**2 + yview**2 + zview**2
        range_image = np.sqrt(sqrng)
        range_image_1 = np.expand_dims(range_image, axis=2)

        return depth_image, range_image_1

    def compute_sample_pattern(self, limg_shape, res_factor):
        # assume velocity is XYZ and we are looking +X up and towards -Z
        pattern = []
        lens = self.cam.node().getLens()
        sx = self.win.getXSize()
        sy = self.win.getYSize()
        ifov_vert = 2.0 * math.tan(
            0.5 * math.radians(lens.getVfov())) / float(sy - 1)
        ifov_horz = 2.0 * math.tan(
            0.5 * math.radians(lens.getHfov())) / float(sx - 1)
        #ifov_vert = lens.getVfov() / float(sy-1)
        #ifov_horz = lens.getHfov() / float(sy-1)
        for ldr_row in range(limg_shape[0]):
            theta = -10.0 - 41.33 * (
                float(ldr_row) / float(limg_shape[0] - 1) - 0.5)
            for ldr_col in range(limg_shape[1]):
                psi = 60.0 * (float(ldr_col) / float(limg_shape[1] - 1) - 0.5)
                cpsi = math.cos(math.radians(psi))
                vert_ang = theta / cpsi
                img_row_flt = (0.5 * float(sy - 1) -
                               (math.tan(math.radians(vert_ang)) / ifov_vert))
                #img_row_flt = 0.5*(sy-1) - (vert_ang / ifov_vert)
                if img_row_flt < 0:
                    print('img_row_flt=%f' % img_row_flt)
                    img_row_flt = 0.0
                if img_row_flt >= sy:
                    print('img_row_flt=%f' % img_row_flt)
                    img_row_flt = float(sy - 1)
                img_col_flt = (0.5 * float(sx - 1) +
                               (math.tan(math.radians(psi)) / ifov_horz))
                #img_col_flt = 0.5*(sx-1) + (psi / ifov_horz)
                if img_col_flt < 0:
                    print('img_col_flt=%f' % img_col_flt)
                    img_col_flt = 0.0
                if img_col_flt >= sx:
                    print('img_col_flt=%f' % img_col_flt)
                    img_col_flt = float(sx - 1)
                pattern.append((ldr_row, ldr_col, img_row_flt, img_col_flt))
        return pattern

    def find_sorted_ladar_returns(self, rangearr, intensarr, ks_m):
        my_range = rangearr.copy()
        my_inten = intensarr.copy()
        '''
        pixels data is organized by:
           [0] starting range of this return
           [1] ending range of this return
           [2] peak range of this return
           [3] total intensity of this return
        '''
        int_mult = len(my_inten)
        pixels = map(
            list,
            zip(my_range.tolist(), my_range.tolist(), my_range.tolist(),
                my_inten.tolist()))
        spix = sorted(pixels, key=lambda x: x[0])
        done = False
        while not done:
            mxpi = len(spix)
            if mxpi > 2:
                mindel = 1e20
                mnidx = None
                for pidx in range(mxpi - 1):
                    rdel = spix[pidx + 1][0] - spix[pidx][1]
                    # must be within ks_m meters in range to merge
                    if (rdel < ks_m) and (rdel < mindel):
                        mindel = rdel
                        mnidx = pidx
                # merge best two returns
                if mnidx is not None:
                    # new range span for testing against neighbors
                    spix[mnidx][1] = spix[mnidx + 1][1]
                    # new peak range is range of max contributor
                    if spix[mnidx + 1][3] > spix[mnidx][3]:
                        spix[mnidx][2] = spix[mnidx + 1][2]
                    # intensity of return is sum of contributors
                    spix[mnidx][3] += spix[mnidx + 1][3]
                    # remove one of the two merged
                    del spix[mnidx + 1]
                else:
                    done = True
            else:
                done = True
        # now eliminate all but max and last returns
        max_idx = None
        max_val = 0.0
        for ci, pix in enumerate(spix):
            if pix[3] > max_val:
                max_val = pix[3] / int_mult
                max_idx = ci
        # if they are the same, return only one
        if spix[-1][3] >= spix[max_idx][3]:
            return [spix[-1]]
        else:
            return [spix[max_idx], spix[-1]]

    def sample_range_image(self, rng_img, int_img, limg_shape, vel_cam, pps,
                           ldr_err, pattern):
        # depth image is set up as 512 x 512 and is 62.5 degrees vertical FOV
        # the center row is vertical, but we want to sample from the
        # region corresponding to HDL-32 FOV: from +10 to -30 degrees
        detailed_sensor_model = False
        fwd_vel = vel_cam[1]
        beam_div = 0.002
        lens = self.cam.node().getLens()
        #sx = self.win.getXSize()
        sy = self.win.getYSize()
        ifov_vert = 2.0 * math.tan(
            0.5 * math.radians(lens.getVfov())) / float(sy - 1)
        #ifov_horz = 2.0*math.tan(0.5*math.radians(lens.getHfov()))/float(sx-1)
        #ifov = math.radians(self.cam.node().getLens().getVfov() / self.win.getYSize())
        sigma = beam_div / ifov_vert
        hs = int(2.0 * sigma + 1.0)
        gprof = gauss_kern(sigma, hs, normalize=False)
        rimg = np.zeros(limg_shape, dtype=np.float32)
        iimg = np.zeros(limg_shape, dtype=np.float32)
        margin = 10.0

        for pidx, relation in enumerate(pattern):

            # get the usual scan pattern sample
            ldr_row, ldr_col, img_row_flt, img_col_flt = relation

            if ((img_row_flt > -margin) and (img_col_flt > -margin)
                    and (img_row_flt < rng_img.shape[0] + margin)
                    and (img_col_flt < rng_img.shape[1] + margin)):

                # within reasonable distance from image limits
                img_row = int(round(img_row_flt))
                img_col = int(round(img_col_flt))

                # motion compensation
                trng = np.float32(rng_img[img_row, img_col])
                if trng > 0.0:
                    # TODO: change this back to False
                    done = True
                    ic = 0
                    while not done:
                        old_trng = trng
                        del_row = pidx * fwd_vel / (ifov_vert * trng * pps)
                        if (abs(del_row) > 1e-1) and (ic < 10):
                            img_row_f = img_row_flt + del_row
                            img_row = int(round(img_row_f))
                            trng = np.float32(rng_img[img_row, img_col])
                            ic += 1
                            if abs(trng - old_trng) < 0.5:
                                done = True
                        else:
                            done = True

                    # simple sensor processing: just sample from large images
                    rimg[ldr_row, ldr_col] = np.float32(rng_img[img_row,
                                                                img_col])
                    iimg[ldr_row, ldr_col] = np.float32(int_img[img_row,
                                                                img_col])

                    if detailed_sensor_model:
                        # detailed model subsamples whole beam width
                        gpatch = copy_patch_centered((img_row, img_col), hs,
                                                     int_img, 0.0)
                        gpatch = np.float32(gpatch)
                        gpatch *= gprof
                        rpatch = copy_patch_centered((img_row, img_col), hs,
                                                     rng_img, 0.0)
                        rpatch = np.squeeze(rpatch)
                        valid = rpatch > 1e-3
                        if np.count_nonzero(valid) > 0:
                            rpatch_ts = rpatch[valid]
                            gpatch_ts = gpatch[valid]
                            returns = self.find_sorted_ladar_returns(
                                rpatch_ts, gpatch_ts, 2.5)
                            # for now we just take first return
                            rimg[ldr_row, ldr_col] = returns[0][2]
                            iimg[ldr_row, ldr_col] = returns[0][3]
                else:
                    rimg[ldr_row, ldr_col] = 0.0
                    iimg[ldr_row, ldr_col] = np.float32(int_img[img_row,
                                                                img_col])

        rimg += ldr_err * np.random.standard_normal(rimg.shape)
        return rimg, iimg

    def skysphereTask(self, task):
        if self.base is not None:
            self.skysphere.setPos(self.base.camera, 0, 0, 0)
            self.terrain.generate()
        return task.cont
class TerrainCell(DirectObject):
    def __init__(self):
        self.settings = {}

    def configure(self, name, heightmap, texture, posx, posy):
        self.settings["name"] = name
        self.settings["heightmap"] = heightmap
        self.settings["texture"] = texture
        self.settings["x"] = posx
        self.settings["y"] = posy

    def create(self):
        self.test_texture = base.loader.loadTexture(self.settings["texture"])

        self.terrain = GeoMipTerrain(self.settings["name"])
        self.terrain.setHeightfield(self.settings["heightmap"])

        # Set terrain properties
        self.terrain.setBruteforce(False)
        self.terrain.setBlockSize(32)
        self.terrain.setNear(40)
        self.terrain.setFar(100)
        #self.terrain.setMinLevel(16)
        self.terrain.setFocalPoint(base.camera)
        self.terrain.setBorderStitching(True)

        self.terrain.getRoot().setSz(300)
        self.terrain.getRoot().setSx(Globals.TERRAIN_MULT)
        self.terrain.getRoot().setSy(Globals.TERRAIN_MULT)
        self.terrain.getRoot().setPos((self.settings["x"]*512)*Globals.TERRAIN_MULT, \
                  (self.settings["y"]*512)*Globals.TERRAIN_MULT, 0)
        self.terrain.getRoot().setTexture(self.test_texture)
        self.terrain.generate()

        #self.fast_cols(16, 16)
        #self.generate_collisions()
        #self.ode_cols()

    def ode_cols(self):
        world = OdeWorld()
        world.setGravity(0, 0, -9)
        world.initSurfaceTable(1)
        world.setSurfaceEntry(0, 0, 150, 0.0, 9.1, 0.9, 0.00001, 0.0, 0.002)

        # Create a space and add a contactgroup to it to add the contact joints
        space = OdeSimpleSpace()
        space.setAutoCollideWorld(world)
        contactgroup = OdeJointGroup()
        space.setAutoCollideJointGroup(contactgroup)
        space.autoCollide()

        #try ODE for collisions
        t_trimesh = OdeTriMeshData(self.terrain.getRoot(), True)
        t_geom = OdeTriMeshGeom(space, t_trimesh)

    def fast_cols(self, x, y):
        #simpler, and faster
        return (self.terrain.getElevation(x, y), self.terrain.getNormal(x, y))

    def generate_collisions(self):
        #try panda's collisions
        print("generating collisions...")
        x = 512
        y = 512
        while x:
            z = self.terrain.getElevation(x, y)
            cap = CollisionCapsule(0, 0, 1, 1)
            self.collision_node = base.render.attachNewNode(
                CollisionNode('cap1'))
            self.collision_node.node().addSolid(cap)
            #self.collision_node.show()
            #self.accept('into-cap1', self.hanev)
            #self.accept('out-cap1', self.hanev)
            self.collision_node.setPos(x, y, z * 300)
            x -= 16
            y = 512
            while y:
                z = self.terrain.getElevation(x, y)
                cap = CollisionCapsule(0, 0, 0, 0, 0, 1, 1)
                self.collision_node = base.render.attachNewNode(
                    CollisionNode('cap1'))
                self.collision_node.node().addSolid(cap)
                self.collision_node.show()
                #self.accept('into-cap1', self.hanev)
                #self.accept('out-cap1', self.hanev)
                self.collision_node.setPos(x, y, z * 300)
                y -= 16

        base.cTrav.addCollider(self.collision_node, base.mchandler)

        self.collision_node.setPos(10, 0, -3)

    def json_encode(self):
        with open("terrains.json", "a") as write_file:
            json.dump(self.settings, write_file, indent=4)
            write_file.write("\n")

    def json_decode(self, name):
        with open("terrains.json", "r") as read_file:
            terrains = json.load(read_file)
            try:
                self.settings = terrains[name]
            except KeyError:
                print("Key not found in json: " + name)
                return (False)
            else:
                return (True)

    def bam_encode(self):
        self.terrain.getRoot().writeBamFile(self.settings["name"])
Example #14
0
class environment(DirectObject):
    def __init__(self, *args, **kwargs):
        super(environment, self).__init__()

        self.sky = loader.loadModel(
            'models/environmentModels/sceneModels/sky/skydome2.egg')

        self.modelList = []

        self.terrain = GeoMipTerrain('terrain')

    def setupPhysics(self, **kwargs):
        self.barn = sceneModel(
            modelName='models/environmentModels/sceneModels/New folder.egg',
            world=kwargs['world'],
            dynamic=False)
        self.modelList.append(self.barn)
        self.barn.model.setScale(.14)
        self.barn.nodePath.setPos(8, -5, -1.2)
        self.barn.nodePath.setScale(.4)
        self.barn.model.setZ(self.barn.nodePath.getZ())
        self.mainNp = kwargs['world'].attachNewNode(
            BulletRigidBodyNode('Heightfield'))
        self.debugNP = kwargs['world'].attachNewNode(BulletDebugNode('Debug'))

        self.crate = sceneModel(
            modelName='models/environmentModels/sceneModels/crate.egg',
            world=kwargs['world'],
            dynamic=True)
        self.crate.nodePath.setScale(.06)
        self.modelList.append(self.crate)

        self.crate.nodePath.setPos(self.barn.nodePath, (-4, -3, -.9))
        self.crate.model.setPos(self.crate.nodePath, (15.8, 5.6, -1.9))
        self.crate.model.setScale(1.2)
        self.debugNP.show()
        self.debugNP.node().showNormals(True)
        height = 10.0

        skytexture = loader.loadTexture(
            'models/environmentModels/sceneModels/sky/tex/skydome.png')
        self.sky.setTexture(skytexture)
        self.sky.reparentTo(kwargs['world'])

        img = PNMImage(
            Filename(
                'models/environmentModels/eartharena/tex/terrainHeight.png'))
        shape = BulletHeightfieldShape(img, height, ZUp)
        shape.setUseDiamondSubdivision(True)

        self.mainNp.node().addShape(shape)

        self.mainNp.setPos(0, 0, .01)
        self.mainNp.setScale(.340)
        self.mainNp.setCollideMask(kwargs['mask'])

        self.terrain.setHeightfield(
            Filename(
                'models/environmentModels/eartharena/tex/terrainHeight.png'))
        self.terrain.setBlockSize(64)
        self.terrain.setNear(50)
        self.terrain.setFar(100)
        self.terrain.setFocalPoint(base.camera)

        rootNp = self.terrain.getRoot()
        rootNp.reparentTo(render)
        rootNp.setSz(15)

        texture = loader.loadTexture(
            'models/environmentModels/eartharena/tex/nova_TX.jpg')
        rootNp.setTexture(texture)

        offset = img.getXSize() / 2.0 - 0.25
        rootNp.setPos(-offset, -offset, -height / 2.0)
        self.terrain.generate()
Example #15
0
class Terrain:
    folder = os.path.dirname(os.path.abspath(__file__))
    subfolder = "/Maps/"
    file = "simple.jpg"
    filepath = folder + subfolder + file

    def __init__(self):
        fn = Filename.fromOsSpecific(self.filepath)
        self.terrain = GeoMipTerrain("mySimpleTerrain")
        self.terrain.setHeightfield("Entities/Maps/heightmap.png")
        self.terrain.getRoot().setSz(40)
        #terrain.setBruteforce(True)
        self.terrain.getRoot().reparentTo(render)

        # Set terrain properties
        self.terrain.setBlockSize(16)
        self.terrain.setNear(500)
        self.terrain.setFar(100)
        self.terrain.setFocalPoint(base.camera)

        # Store the root NodePath for convenience
        root = self.terrain.getRoot()
        root.reparentTo(render)

        # some tinkering
        """
        # tell renderer to repeat texture when reading over the edge.
        texGrass.setWrapU(Texture.WM_repeat)
        texGrass.setWrapV(Texture.WM_repeat)
        # apply mipmapping: tell renderer how to handle multiple texture pixels being rendered t a single screen pixel (makes textures 30% larger in GPU mem.)
        texGrass.setMinfilter(SamplerState.FT_linear_mipmap_linear)
        """
        self.terrain.generate()
        """
        new attempt to include blend mapping:
        """
        # determine terrain size
        self.heightmap = self.terrain.heightfield()
        if self.heightmap.getXSize() > self.heightmap.getYSize():
            self.size = self.heightmap.getXSize() - 1
        else:
            self.size = self.heightmap.getYSize() - 1
        self.xsize = self.heightmap.getXSize() - 1
        self.ysize = self.heightmap.getYSize() - 1

        # Set multi texture
        # Source http://www.panda3d.org/phpbb2/viewtopic.php?t=4536
        self.generateSurfaceTextures()

        # load a blend texture from file:
        self.blendTexture = loader.loadTexture("Entities/Maps/blendMap.png")

        self.blendTS = TextureStage('blend')
        self.blendTS.setSort(0)
        self.blendTS.setPriority(1)
        # apply textures to the terrain and connect custom shader for blend mapping:
        self.setSurfaceTextures()

        # Add a task to keep updating the terrain (for changing terrain, or synamic resolution)
        def updateTask(task):
            self.terrain.update()
            return task.cont

        taskMgr.add(updateTask, "update")

        # this is where we load the textures to be assigned to the terrain
    def generateSurfaceTextures(self):
        # Textureize
        self.grassTexture = loader.loadTexture("Entities/Maps/grassy2.png")
        self.grassTexture.setWrapU(Texture.WMRepeat)
        self.grassTexture.setWrapV(Texture.WMRepeat)
        self.grassTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear)
        self.grassTexture.setAnisotropicDegree(8)
        self.grassTS = TextureStage('grass')
        self.grassTS.setSort(
            1)  # sorting order is relevent for assigning textures to the four

        self.rockTexture = loader.loadTexture("Entities/Maps/simple.jpg")
        self.rockTexture.setWrapU(Texture.WMRepeat)
        self.rockTexture.setWrapV(Texture.WMRepeat)
        self.rockTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear)
        #self.grassTexture.setAnisotropicDegree(8)
        self.rockTS = TextureStage('rock')
        self.rockTS.setSort(2)
        # self.rockTS.setCombineRgb(TextureStage.CMAdd, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor)

        self.sandTexture = loader.loadTexture("Entities/Maps/stars.png")
        self.sandTexture.setWrapU(Texture.WMRepeat)
        self.sandTexture.setWrapV(Texture.WMRepeat)
        self.sandTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear)
        #self.sandTexture.setAnisotropicDegree(8)
        self.sandTS = TextureStage('sand')
        self.sandTS.setSort(3)
        self.sandTS.setPriority(5)  # TODO: figure out what this is for...

        self.snowTexture = loader.loadTexture("Entities/Maps/grass.png")
        self.snowTexture.setWrapU(Texture.WMRepeat)
        self.snowTexture.setWrapV(Texture.WMRepeat)
        self.snowTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear)
        #self.snowTexture.setAnisotropicDegree(8)
        self.snowTS = TextureStage('snow')
        self.snowTS.setSort(4)
        self.snowTS.setPriority(0)

        # a background (or rather freground?) texture that will be present independently from the blend map (consider removal)
        self.overlayTexture = loader.loadTexture("Entities/Maps/heightmap.png")
        self.overlayTexture.setWrapU(Texture.WMRepeat)
        self.overlayTexture.setWrapV(Texture.WMRepeat)
        self.overlayTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear)
        #self.overlayTexture.setAnisotropicDegree(8)
        self.overlayTS = TextureStage('overlay')
        self.overlayTS.setSort(5)
        self.overlayTS.setPriority(10)

    # this is where we assign loaded textures to be blended in the shader.
    def setSurfaceTextures(self):
        self.ownerview = False
        root = self.terrain.getRoot()
        root.clearTexture()
        #self.terrain.setTextureMap()
        root.setTexture(
            self.blendTS, self.snowTexture
        )  # this texture determines where the other textures are visible

        root.setTexture(self.grassTS, self.snowTexture)
        #root.setTexScale(self.grassTS, self.size*5, self.size*5) # I try to make the texture 20 times smaller then the blend map...

        root.setTexture(self.rockTS, self.snowTexture)  #rockTexture
        #root.setTexScale(self.rockTS, self.size*5, self.size*5)

        root.setTexture(self.sandTS, self.snowTexture)  #sandTexture
        #root.setTexScale(self.sandTS, self.size*5, self.size*5)

        root.setTexture(self.snowTS, self.snowTexture)  #snowTexture
        #root.setTexScale(self.snowTS, self.size*5, self.size*5)

        #(consider removal)
        root.setTexture(self.overlayTS, self.overlayTexture)  #overlayTexture
        #root.setTexScale(self.overlayTS, self.xsize, self.ysize)

        root.setShaderInput('size', self.xsize, self.ysize, self.size,
                            self.size)
        root.setShader(loader.loadShader('Entities/Maps/terrainblender.sha'))
Example #16
0
class Simulation(ShowBase):
    def __init__(self):

        # Heightfield (static)
        self.height = 38.0

        ShowBase.__init__(self)
        base.setBackgroundColor(0.1, 0.1, 0.8, 1)
        base.setFrameRateMeter(True)

        base.cam.setPos(0, -150, 200)
        base.cam.lookAt(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
        alightNP = render.attachNewNode(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.setDirection(Vec3(1, 1, -1))
        dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attachNewNode(dlight)

        render.clearLight()
        render.setLight(alightNP)
        render.setLight(dlightNP)

        # Input
        self.accept('escape', self.doExit)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('backward', 'x')
        inputState.watchWithModifiers('right', 'd')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def doExit(self):
        self.cleanup()
        sys.exit(1)

    # ____TASK___

    def processInput(self, dt):
        for vehicle in self.controlVehicles:
            engineForce = 0.0
            brakeForce = 0.0

            if inputState.isSet('forward'):
                engineForce = 1000.0
                brakeForce = 0.0

            if inputState.isSet('backward'):
                engineForce = -1000.0
                brakeForce = 0.0

            if inputState.isSet('reverse'):
                engineForce = 0.0
                brakeForce = 100.0

            if inputState.isSet('left'):
                vehicle.setAngle(True, dt)

            if inputState.isSet('right'):
                vehicle.setAngle(False, dt)

            # Apply engine and brake to rear wheels
            vehicle.setEngineForce(engineForce)
            vehicle.setBrakeForce(brakeForce)

            #print(vehicle.getAngle())

    def update(self, task):
        dt = globalClock.getDt()

        self.processInput(dt)
        self.world.doPhysics(dt, 10, 0.008)

        self.terrain.update()

        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.removeNode()

    def setup(self):
        self.worldNP = render.attachNewNode('World')

        # World
        self.world = BulletWorld()
        self.world.setGravity(Vec3(0, 0, -9.81))

        #height map
        # Filename:
        # small ->  'Maps/HeightMapSmall.png'
        # big   ->  'Maps/HeightMapBig.png'
        img = PNMImage(Filename('Maps/HeightMapSmall.png'))
        shape = BulletHeightfieldShape(img, self.height, ZUp)
        shape.setUseDiamondSubdivision(True)

        np = self.worldNP.attachNewNode(BulletRigidBodyNode('Heightfield'))
        np.node().addShape(shape)
        np.setPos(0, 0, 0)
        np.setCollideMask(BitMask32.allOn())
        self.world.attachRigidBody(np.node())

        #adding Texture
        #setColorMap:
        #small ->   'Maps/TextureMapSmall.jpg'
        #big   ->   'Maps/TextureMapBig.jpg'
        self.terrain = GeoMipTerrain('terrain')
        self.terrain.setHeightfield(img)
        self.terrain.setColorMap('Maps/TextureMapSmall.jpg')
        self.terrain.setBruteforce(True)  # level of detail

        self.terrain.setBlockSize(32)
        self.terrain.setNear(50)
        self.terrain.setFar(100)
        self.terrain.setFocalPoint(base.camera)

        rootNP = self.terrain.getRoot()
        rootNP.reparentTo(render)
        rootNP.setSz(self.height)

        offset = img.getXSize() / 2.0 - 0.5
        rootNP.setPos(-offset, -offset, -self.height / 2.0)

        self.makeMapBorders(offset)
        self.terrain.generate()

        # creating vehicles
        #controlled vehicles
        self.controlVehicles = []
        self.controlVehicles.append(
            Vehicle(0, 00, 40, "B", self.worldNP, self.world))

        #vehicles goint to a specific point
        #self.squareVeh = Vehicle(0, 50, 40, "G", self.worldNP, self.world)
        #thread.start_new_thread(self.goSquare, (self.squareVeh, 100))

        #vehicles following user
        #self.followVehicles = []
        #self.followVehicles.append(Vehicle(-offset+10, -offset+10, 40, "R", self.worldNP, self.world))
        #self.followVehicles.append(Vehicle(offset-10, offset-10, 60, "R", self.worldNP, self.world))
        #for veh in self.followVehicles:
        #    thread.start_new_thread(follow, (veh, self.controlVehicles[0]))

        #vehicles for hill climbing
        self.hillVehicles = []
        self.hillVehicles.append(
            Vehicle(-offset + 10, -offset + 10, 40, "R", self.worldNP,
                    self.world))
        self.hillVehicles.append(
            Vehicle(offset - 10, offset - 10, 60, "R", self.worldNP,
                    self.world))
        for veh in self.hillVehicles:
            thread.start_new_thread(blindClimb, (veh, ))

    #function that navigates a vehicle to go in a square
    def goSquare(self, vehicle, size):
        while (True):
            goTo([size, size], vehicle)
            goTo([size, -size], vehicle)
            goTo([-size, -size], vehicle)
            goTo([-size, size], vehicle)

    #Borders around the map that vehicles won't fall from terrain
    def makeMapBorders(self, offset):
        plane1 = BulletPlaneShape(Vec3(1, 0, 0), 0)
        np = self.worldNP.attachNewNode(BulletRigidBodyNode('border1'))
        np.node().addShape(plane1)
        np.setPos(-offset, -offset, -self.height / 2.0)
        np.setCollideMask(BitMask32.allOn())
        self.world.attachRigidBody(np.node())
        plane2 = BulletPlaneShape(Vec3(0, 1, 0), 0)
        np = self.worldNP.attachNewNode(BulletRigidBodyNode('border2'))
        np.node().addShape(plane2)
        np.setPos(-offset, -offset, -self.height / 2.0)
        np.setCollideMask(BitMask32.allOn())
        self.world.attachRigidBody(np.node())
        plane3 = BulletPlaneShape(Vec3(0, -1, 0), 0)
        np = self.worldNP.attachNewNode(BulletRigidBodyNode('border3'))
        np.node().addShape(plane3)
        np.setPos(offset, offset, self.height / 2.0)
        np.setCollideMask(BitMask32.allOn())
        self.world.attachRigidBody(np.node())
        plane4 = BulletPlaneShape(Vec3(-1, 0, 0), 0)
        np = self.worldNP.attachNewNode(BulletRigidBodyNode('border4'))
        np.node().addShape(plane4)
        np.setPos(offset, offset, self.height / 2.0)
        np.setCollideMask(BitMask32.allOn())
        self.world.attachRigidBody(np.node())

    #getting height of map at some point
    def getHeight(self):
        line = CollisionLine(ox, oy, oz, dx, dy, dz)