def generateWorld(self, heightmap, tiles, cities, container): self.heightmap = heightmap self.terrain = PagedGeoMipTerrain("surface") #self.terrain = GeoMipTerrain("surface") self.terrain.setHeightfield(self.heightmap) #self.terrain.setFocalPoint(base.camera) self.terrain.setBruteforce(True) self.terrain.setBlockSize(64) self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) #root.setSz(100) self.terrain.setSz(100) messenger.send('makePickable', [root]) 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() self.generateWaterMap() self.generateOwnerTexture(tiles, cities) #self.terrain.makeTextureMap() colormap = PNMImage(heightmap.getXSize() - 1, heightmap.getYSize() - 1) colormap.addAlpha() slopemap = self.terrain.makeSlopeImage() for x in range(0, colormap.getXSize()): for y in range(0, colormap.getYSize()): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if heightmap.getGrayVal(x, y) < 200: colormap.setAlpha(x, y, 0) else: colormap.setAlpha(x, y, 1) # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data if heightmap.getGrayVal(x, y) < 62: colormap.setBlue(x, y, 1) # Rock elif slopemap.getGrayVal(x, y) > 170: colormap.setRed(x, y, 1) else: colormap.setGreen(x, y, 1) self.colorTexture = Texture() self.colorTexture.load(colormap) self.colorTS = TextureStage('color') self.colorTS.setSort(0) self.colorTS.setPriority(1) self.setSurfaceTextures() self.generateWater(2) taskMgr.add(self.updateTerrain, "updateTerrain") print "Done with terrain generation" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) self.terrain.getRoot().analyze() self.accept("h", self.switchWater)
def generateWorld(self, heightmap, tiles, cities, container): self.heightmap = heightmap self.terrain = PagedGeoMipTerrain("surface") #self.terrain = GeoMipTerrain("surface") self.terrain.setHeightfield(self.heightmap) #self.terrain.setFocalPoint(base.camera) self.terrain.setBruteforce(True) self.terrain.setBlockSize(64) self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) #root.setSz(100) self.terrain.setSz(100) messenger.send('makePickable', [root]) 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() self.generateWaterMap() self.generateOwnerTexture(tiles, cities) #self.terrain.makeTextureMap() colormap = PNMImage(heightmap.getXSize()-1, heightmap.getYSize()-1) colormap.addAlpha() slopemap = self.terrain.makeSlopeImage() for x in range(0, colormap.getXSize()): for y in range(0, colormap.getYSize()): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if heightmap.getGrayVal(x, y) < 200: colormap.setAlpha(x, y, 0) else: colormap.setAlpha(x, y, 1) # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data if heightmap.getGrayVal(x,y) < 62: colormap.setBlue(x, y, 1) # Rock elif slopemap.getGrayVal(x, y) > 170: colormap.setRed(x, y, 1) else: colormap.setGreen(x, y, 1) self.colorTexture = Texture() self.colorTexture.load(colormap) self.colorTS = TextureStage('color') self.colorTS.setSort(0) self.colorTS.setPriority(1) self.setSurfaceTextures() self.generateWater(2) taskMgr.add(self.updateTerrain, "updateTerrain") print "Done with terrain generation" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) self.terrain.getRoot().analyze() self.accept("h", self.switchWater)
class TerrainManager(DirectObject.DirectObject): def __init__(self): self.accept("mouse1", self.lclick) self.waterType = 2 self.water = None self.citycolors = {0: VBase3D(1, 1, 1)} self.accept('generateRegion', self.generateWorld) self.accept('regenerateRegion', self.regenerateWorld) self.accept("regionView_normal", self.setSurfaceTextures) self.accept("regionView_owners", self.setOwnerTextures) self.accept("regionView_foundNew", self.regionViewFound) self.accept("updateRegion", self.updateRegion) self.accept("enterCityView", self.enterCity) # View: 0, region, # cityid self.view = 0 self.ownerview = False def lclick(self): cell = picker.getMouseCell() print "Cell:", cell blockCoords = self.terrain.getBlockFromPos(cell[0], cell[1]) block = self.terrain.getBlockNodePath(blockCoords[0], blockCoords[1]) print "Block coords:", blockCoords print "NodePath:", block print "Elevation:", self.terrain.getElevation(cell[0], cell[1]) if not self.view: messenger.send("clickForCity", [cell]) def switchWater(self): print "Switch Water" self.waterType += 1 if self.waterType > 2: self.waterType = 0 self.generateWater(self.waterType) def generateWorld(self, heightmap, tiles, cities, container): self.heightmap = heightmap self.terrain = PagedGeoMipTerrain("surface") #self.terrain = GeoMipTerrain("surface") self.terrain.setHeightfield(self.heightmap) #self.terrain.setFocalPoint(base.camera) self.terrain.setBruteforce(True) self.terrain.setBlockSize(64) self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) #root.setSz(100) self.terrain.setSz(100) messenger.send('makePickable', [root]) 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() self.generateWaterMap() self.generateOwnerTexture(tiles, cities) #self.terrain.makeTextureMap() colormap = PNMImage(heightmap.getXSize() - 1, heightmap.getYSize() - 1) colormap.addAlpha() slopemap = self.terrain.makeSlopeImage() for x in range(0, colormap.getXSize()): for y in range(0, colormap.getYSize()): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if heightmap.getGrayVal(x, y) < 200: colormap.setAlpha(x, y, 0) else: colormap.setAlpha(x, y, 1) # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data if heightmap.getGrayVal(x, y) < 62: colormap.setBlue(x, y, 1) # Rock elif slopemap.getGrayVal(x, y) > 170: colormap.setRed(x, y, 1) else: colormap.setGreen(x, y, 1) self.colorTexture = Texture() self.colorTexture.load(colormap) self.colorTS = TextureStage('color') self.colorTS.setSort(0) self.colorTS.setPriority(1) self.setSurfaceTextures() self.generateWater(2) taskMgr.add(self.updateTerrain, "updateTerrain") print "Done with terrain generation" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) self.terrain.getRoot().analyze() self.accept("h", self.switchWater) def regenerateWorld(self): '''Regenerates world, often upon city exit.''' self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) self.terrain.setSz(100) messenger.send('makePickable', [root]) # Set multi texture # Source http://www.panda3d.org/phpbb2/viewtopic.php?t=4536 #self.generateSurfaceTextures() self.generateWaterMap() self.setSurfaceTextures() self.generateWater(2) print "Done with terrain regeneration" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) def generateWaterMap(self): ''' Iterate through every pix of color map. This will be very slow so until faster method is developed, use sparingly getXSize returns pixels length starting with 1, subtract 1 for obvious reasons We also slip in checking for the water card size, which should only change when the color map does ''' print "GenerateWaterMap" self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax = -1, 0, -1, 0 for x in range(0, self.heightmap.getXSize() - 1): for y in range(0, self.heightmap.getYSize() - 1): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if self.heightmap.getGrayVal(x, y) < 62: # Water card dimensions here # Y axis flipped from texture space to world space if self.waterXMin == -1 or x < self.waterXMin: self.waterXMin = x if not self.waterYMax: self.waterYMax = y if y < self.waterYMax: self.waterYMax = y if x > self.waterXMax: self.waterXMax = x if y > self.waterYMin: self.waterYMin = y # Transform y coords self.waterYMin = self.size - 64 - self.waterYMin self.waterYMax = self.size - 64 - self.waterYMax def generateOwnerTexture(self, tiles, cities): '''Generates a simple colored texture to be applied to the city info region overlay. Due to different coordinate systems (terrain org bottom left, texture top left) some conversions are needed, Also creates and sends a citylabels dict for the region view ''' self.citymap = PNMImage(self.xsize, self.ysize) citylabels = cities scratch = {} # Setup for city labels for ident in cities: scratch[ident] = [] # conversion for y axis ycon = [] s = self.ysize - 1 for y in range(self.ysize): ycon.append(s) s -= 1 for ident, city in cities.items(): if ident not in self.citycolors: self.citycolors[ident] = VBase3D(random.random(), random.random(), random.random()) for tile in tiles: self.citymap.setXel(tile.coords[0], ycon[tile.coords[1]], self.citycolors[tile.cityid]) # Scratch for labeling if tile.cityid: scratch[tile.cityid].append((tile.coords[0], tile.coords[1])) for ident, values in scratch.items(): xsum = 0 ysum = 0 n = 0 for coords in values: xsum += coords[0] ysum += coords[1] n += 1 xavg = xsum / n yavg = ysum / n print "Elevation:", self.terrain.getElevation(xavg, yavg) z = self.terrain.getElevation(xavg, yavg) * 100 citylabels[ident]["position"] = (xavg, yavg, z + 15) print "Citylabels:", citylabels messenger.send("updateCityLabels", [citylabels, self.terrain]) def generateSurfaceTextures(self): # Textureize self.grassTexture = loader.loadTexture("Textures/grass.png") self.grassTS = TextureStage('grass') self.grassTS.setSort(1) self.rockTexture = loader.loadTexture("Textures/rock.jpg") 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("Textures/sand.jpg") self.sandTS = TextureStage('sand') self.sandTS.setSort(3) self.sandTS.setPriority(5) self.snowTexture = loader.loadTexture("Textures/ice.png") self.snowTS = TextureStage('snow') self.snowTS.setSort(4) self.snowTS.setPriority(0) # Grid for city placement and guide and stuff self.gridTexture = loader.loadTexture("Textures/grid.png") self.gridTexture.setWrapU(Texture.WMRepeat) self.gridTexture.setWrapV(Texture.WMRepeat) self.gridTS = TextureStage('grid') self.gridTS.setSort(5) self.gridTS.setPriority(10) def enterCity(self, ident, city, position, tiles): '''Identifies which terrain blocks city belogs to and disables those that are not A lot of uneeded for loops in here. Will need to find a better way later.''' #root = self.terrain.getRoot() children = [] for terrain in self.terrain.terrains: root = terrain.getRoot() children += root.getChildren() keepBlocks = [] # Reset water dimentions self.waterXMin = 0 self.waterXMax = 0 self.waterYMin = 0 self.waterYMax = 0 for tile in tiles: blockCoords = self.terrain.getBlockFromPos(tile.coords[0], tile.coords[1]) block = self.terrain.getBlockNodePath(blockCoords[0], blockCoords[1]) if block not in keepBlocks: keepBlocks.append(block) if self.heightmap.getGrayVal(tile.coords[0], self.size - tile.coords[1]) < 62: # Water card dimensions here # Y axis flipped from texture space to world space if not self.waterXMin: self.waterXMin = tile.coords[0] if not self.waterYMin: self.waterYMin = tile.coords[1] if tile.coords[1] > self.waterYMax: self.waterYMax = tile.coords[1] if tile.coords[0] > self.waterXMax: self.waterXMax = tile.coords[0] if tile.coords[0] < self.waterXMin: self.waterXMin = tile.coords[0] if tile.coords[1] < self.waterYMin: self.waterYMin = tile.coords[1] for child in children: if child not in keepBlocks: child.detachNode() self.view = ident self.generateWater(2) def newTerrainOverlay(self, task): root = self.terrain.getRoot() position = picker.getMouseCell() if position: # Check to make sure we do not go out of bounds if position[0] < 32: position = (32, position[1]) elif position[0] > self.xsize - 32: position = (self.xsize - 32, position[1]) if position[1] < 32: position = (position[0], 32) elif position[1] > self.ysize - 32: position = (position[0], self.size - 32) root.setTexOffset(self.tileTS, -(position[0] - 32) / 64, -(position[1] - 32) / 64) return task.cont def regionViewFound(self): '''Gui for founding a new city!''' self.setOwnerTextures() root = self.terrain.getRoot() task = taskMgr.add(self.newTerrainOverlay, "newTerrainOverlay") tileTexture = loader.loadTexture("Textures/tile.png") tileTexture.setWrapU(Texture.WMClamp) tileTexture.setWrapV(Texture.WMClamp) self.tileTS = TextureStage('tile') self.tileTS.setSort(6) self.tileTS.setMode(TextureStage.MDecal) #self.tileTS.setColor(Vec4(1,0,1,1)) root.setTexture(self.tileTS, tileTexture) root.setTexScale(self.tileTS, self.terrain.xchunks, self.terrain.ychunks) self.acceptOnce("mouse1", self.regionViewFound2) self.acceptOnce("escape", self.cancelRegionViewFound) def regionViewFound2(self): '''Grabs cell location for founding. The texture coordinate is used as the mouse may enter an out of bounds area. ''' root = self.terrain.getRoot() root_position = root.getTexOffset(self.tileTS) # We offset the position of the texture, so we will now put the origin of the new city not on mouse cursor but the "bottom left" of it. Just need to add 32 to get other edge position = [ int(abs(root_position[0] * 64)), int(abs(root_position[1] * 64)) ] self.cancelRegionViewFound() messenger.send("found_city_name", [position]) def cancelRegionViewFound(self): taskMgr.remove("newTerrainOverlay") root = self.terrain.getRoot() root.clearTexture(self.tileTS) # Restore original mouse function self.accept("mouse1", self.lclick) messenger.send("showRegionGUI") def setSurfaceTextures(self): self.ownerview = False root = self.terrain.getRoot() root.clearTexture() #self.terrain.setTextureMap() root.setTexture(self.colorTS, self.colorTexture) root.setTexture(self.grassTS, self.grassTexture) root.setTexScale(self.grassTS, self.size / 8, self.size / 8) root.setTexture(self.rockTS, self.rockTexture) root.setTexScale(self.rockTS, self.size / 8, self.size / 8) root.setTexture(self.sandTS, self.sandTexture) root.setTexScale(self.sandTS, self.size / 8, self.size / 8) root.setTexture(self.snowTS, self.snowTexture) root.setTexScale(self.snowTS, self.size / 8, self.size / 8) root.setTexture(self.gridTS, self.gridTexture) root.setTexScale(self.gridTS, self.xsize, self.ysize) root.setShaderInput('size', self.xsize, self.ysize, self.size, self.size) root.setShader(loader.loadShader('Shaders/terraintexture.sha')) def setOwnerTextures(self): self.ownerview = True root = self.terrain.getRoot() root.clearShader() root.clearTexture() cityTexture = Texture() cityTexture.load(self.citymap) cityTS = TextureStage('citymap') cityTS.setSort(0) root.setTexture(self.gridTS, self.gridTexture) root.setTexScale(self.gridTS, self.terrain.xchunks, self.terrain.ychunks) root.setTexture(cityTS, cityTexture, 1) def updateRegion(self, heightmap, tiles, cities): self.generateOwnerTexture(tiles, cities) if self.ownerview: self.setOwnerTextures() def updateTerrain(self, task): '''Updates terrain and water''' self.terrain.update() # Water if self.waterType is 2: pos = base.camera.getPos() render.setShaderInput('time', task.time) mc = base.camera.getMat() self.water.changeCameraPos(pos, mc) self.water.changeCameraPos(pos, mc) #print "Render diagnostics" #render.analyze() #base.cTrav.showCollisions(render) return task.cont def generateWater(self, style): print "Generate Water:", self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax '''Generates water style 0: blue card style 1: reflective card style 2: reflective card with shaders ''' self.waterHeight = 22.0 if self.water: self.water.removeNode() if style is 0: cm = CardMaker("water") #cm.setFrame(-1, 1, -1, 1) cm.setFrame(self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax) cm.setColor(0, 0, 1, 0.9) self.water = render.attachNewNode(cm.generate()) if self.waterYMax > self.waterXMax: size = self.waterYMax else: size = self.waterXMax self.water.lookAt(0, 0, -1) self.water.setZ(self.waterHeight) messenger.send('makePickable', [self.water]) elif style is 1: # From Prosoft's super awesome terrain demo cm = CardMaker("water") #cm.setFrame(-1, 1, -1, 1) cm.setFrame(self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax) self.water = render.attachNewNode(cm.generate()) if self.waterYMax > self.waterXMax: size = self.waterYMax else: size = self.waterXMax #self.water.setScale(size) self.water.lookAt(0, 0, -1) self.water.setZ(self.waterHeight) self.water.setShaderOff(1) self.water.setLightOff(1) self.water.setAlphaScale(0.5) self.water.setTransparency(TransparencyAttrib.MAlpha) wbuffer = base.win.makeTextureBuffer("water", 512, 512) wbuffer.setClearColorActive(True) wbuffer.setClearColor(base.win.getClearColor()) self.wcamera = base.makeCamera(wbuffer) self.wcamera.reparentTo(render) self.wcamera.node().setLens(base.camLens) self.wcamera.node().setCameraMask(BitMask32.bit(1)) self.water.hide(BitMask32.bit(1)) wtexture = wbuffer.getTexture() wtexture.setWrapU(Texture.WMClamp) wtexture.setWrapV(Texture.WMClamp) wtexture.setMinfilter(Texture.FTLinearMipmapLinear) self.wplane = Plane(Vec3(0, 0, 1), Point3(0, 0, self.water.getZ())) wplanenp = render.attachNewNode(PlaneNode("water", self.wplane)) tmpnp = NodePath("StateInitializer") tmpnp.setClipPlane(wplanenp) tmpnp.setAttrib(CullFaceAttrib.makeReverse()) self.wcamera.node().setInitialState(tmpnp.getState()) self.water.projectTexture(TextureStage("reflection"), wtexture, self.wcamera) messenger.send('makePickable', [self.water]) elif style is 2: # From Clcheung just as super awesome demomaster self.water_level = Vec4(0.0, 0.0, self.waterHeight, 1.0) self.water = water.WaterNode(self.waterXMin, self.waterYMin, self.waterXMax, self.waterYMax, self.water_level.getZ()) self.water.setStandardControl() self.water.changeParams(None) wl = self.water_level wl.setZ(wl.getZ() - 0.05) #root.setShaderInput('waterlevel', self.water_level) render.setShaderInput('time', 0) messenger.send('makePickable', [self.water.waterNP])
class TerrainManager(DirectObject.DirectObject): def __init__(self): self.accept("mouse1", self.lclick) self.waterType = 2 self.water = None self.citycolors = {0: VBase3D(1, 1, 1)} self.accept('generateRegion', self.generateWorld) self.accept('regenerateRegion', self.regenerateWorld) self.accept("regionView_normal", self.setSurfaceTextures) self.accept("regionView_owners", self.setOwnerTextures) self.accept("regionView_foundNew", self.regionViewFound) self.accept("updateRegion", self.updateRegion) self.accept("enterCityView", self.enterCity) # View: 0, region, # cityid self.view = 0 self.ownerview = False def lclick(self): cell = picker.getMouseCell() print "Cell:", cell blockCoords = self.terrain.getBlockFromPos(cell[0], cell[1]) block = self.terrain.getBlockNodePath(blockCoords[0], blockCoords[1]) print "Block coords:", blockCoords print "NodePath:", block print "Elevation:", self.terrain.getElevation(cell[0], cell[1]) if not self.view: messenger.send("clickForCity", [cell]) def switchWater(self): print "Switch Water" self.waterType += 1 if self.waterType > 2: self.waterType = 0 self.generateWater(self.waterType) def generateWorld(self, heightmap, tiles, cities, container): self.heightmap = heightmap self.terrain = PagedGeoMipTerrain("surface") #self.terrain = GeoMipTerrain("surface") self.terrain.setHeightfield(self.heightmap) #self.terrain.setFocalPoint(base.camera) self.terrain.setBruteforce(True) self.terrain.setBlockSize(64) self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) #root.setSz(100) self.terrain.setSz(100) messenger.send('makePickable', [root]) 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() self.generateWaterMap() self.generateOwnerTexture(tiles, cities) #self.terrain.makeTextureMap() colormap = PNMImage(heightmap.getXSize()-1, heightmap.getYSize()-1) colormap.addAlpha() slopemap = self.terrain.makeSlopeImage() for x in range(0, colormap.getXSize()): for y in range(0, colormap.getYSize()): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if heightmap.getGrayVal(x, y) < 200: colormap.setAlpha(x, y, 0) else: colormap.setAlpha(x, y, 1) # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data if heightmap.getGrayVal(x,y) < 62: colormap.setBlue(x, y, 1) # Rock elif slopemap.getGrayVal(x, y) > 170: colormap.setRed(x, y, 1) else: colormap.setGreen(x, y, 1) self.colorTexture = Texture() self.colorTexture.load(colormap) self.colorTS = TextureStage('color') self.colorTS.setSort(0) self.colorTS.setPriority(1) self.setSurfaceTextures() self.generateWater(2) taskMgr.add(self.updateTerrain, "updateTerrain") print "Done with terrain generation" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) self.terrain.getRoot().analyze() self.accept("h", self.switchWater) def regenerateWorld(self): '''Regenerates world, often upon city exit.''' self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) self.terrain.setSz(100) messenger.send('makePickable', [root]) # Set multi texture # Source http://www.panda3d.org/phpbb2/viewtopic.php?t=4536 #self.generateSurfaceTextures() self.generateWaterMap() self.setSurfaceTextures() self.generateWater(2) print "Done with terrain regeneration" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) def generateWaterMap(self): ''' Iterate through every pix of color map. This will be very slow so until faster method is developed, use sparingly getXSize returns pixels length starting with 1, subtract 1 for obvious reasons We also slip in checking for the water card size, which should only change when the color map does ''' print "GenerateWaterMap" self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax = -1,0,-1,0 for x in range(0, self.heightmap.getXSize()-1): for y in range(0, self.heightmap.getYSize()-1): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if self.heightmap.getGrayVal(x,y) < 62: # Water card dimensions here # Y axis flipped from texture space to world space if self.waterXMin == -1 or x < self.waterXMin: self.waterXMin = x if not self.waterYMax: self.waterYMax = y if y < self.waterYMax: self.waterYMax = y if x > self.waterXMax: self.waterXMax = x if y > self.waterYMin: self.waterYMin = y # Transform y coords self.waterYMin = self.size-64 - self.waterYMin self.waterYMax = self.size-64 - self.waterYMax def generateOwnerTexture(self, tiles, cities): '''Generates a simple colored texture to be applied to the city info region overlay. Due to different coordinate systems (terrain org bottom left, texture top left) some conversions are needed, Also creates and sends a citylabels dict for the region view ''' self.citymap = PNMImage(self.xsize, self.ysize) citylabels = cities scratch = {} # Setup for city labels for ident in cities: scratch[ident] = [] # conversion for y axis ycon = [] s = self.ysize - 1 for y in range(self.ysize): ycon.append(s) s -= 1 for ident, city in cities.items(): if ident not in self.citycolors: self.citycolors[ident] = VBase3D(random.random(), random.random(), random.random()) for tile in tiles: self.citymap.setXel(tile.coords[0], ycon[tile.coords[1]], self.citycolors[tile.cityid]) # Scratch for labeling if tile.cityid: scratch[tile.cityid].append((tile.coords[0], tile.coords[1])) for ident, values in scratch.items(): xsum = 0 ysum = 0 n = 0 for coords in values: xsum += coords[0] ysum += coords[1] n += 1 xavg = xsum/n yavg = ysum/n print "Elevation:", self.terrain.getElevation(xavg, yavg) z = self.terrain.getElevation(xavg, yavg)*100 citylabels[ident]["position"] = (xavg, yavg, z+15) print "Citylabels:", citylabels messenger.send("updateCityLabels", [citylabels, self.terrain]) def generateSurfaceTextures(self): # Textureize self.grassTexture = loader.loadTexture("Textures/grass.png") self.grassTS = TextureStage('grass') self.grassTS.setSort(1) self.rockTexture = loader.loadTexture("Textures/rock.jpg") 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("Textures/sand.jpg") self.sandTS = TextureStage('sand') self.sandTS.setSort(3) self.sandTS.setPriority(5) self.snowTexture = loader.loadTexture("Textures/ice.png") self.snowTS = TextureStage('snow') self.snowTS.setSort(4) self.snowTS.setPriority(0) # Grid for city placement and guide and stuff self.gridTexture = loader.loadTexture("Textures/grid.png") self.gridTexture.setWrapU(Texture.WMRepeat) self.gridTexture.setWrapV(Texture.WMRepeat) self.gridTS = TextureStage('grid') self.gridTS.setSort(5) self.gridTS.setPriority(10) def enterCity(self, ident, city, position, tiles): '''Identifies which terrain blocks city belogs to and disables those that are not A lot of uneeded for loops in here. Will need to find a better way later.''' #root = self.terrain.getRoot() children = [] for terrain in self.terrain.terrains: root = terrain.getRoot() children += root.getChildren() keepBlocks = [] # Reset water dimentions self.waterXMin = 0 self.waterXMax = 0 self.waterYMin = 0 self.waterYMax = 0 for tile in tiles: blockCoords = self.terrain.getBlockFromPos(tile.coords[0], tile.coords[1]) block = self.terrain.getBlockNodePath(blockCoords[0], blockCoords[1]) if block not in keepBlocks: keepBlocks.append(block) if self.heightmap.getGrayVal(tile.coords[0], self.size-tile.coords[1]) < 62: # Water card dimensions here # Y axis flipped from texture space to world space if not self.waterXMin: self.waterXMin = tile.coords[0] if not self.waterYMin: self.waterYMin = tile.coords[1] if tile.coords[1] > self.waterYMax: self.waterYMax = tile.coords[1] if tile.coords[0] > self.waterXMax: self.waterXMax = tile.coords[0] if tile.coords[0] < self.waterXMin: self.waterXMin = tile.coords[0] if tile.coords[1] < self.waterYMin: self.waterYMin = tile.coords[1] for child in children: if child not in keepBlocks: child.detachNode() self.view = ident self.generateWater(2) def newTerrainOverlay(self, task): root = self.terrain.getRoot() position = picker.getMouseCell() if position: # Check to make sure we do not go out of bounds if position[0] < 32: position = (32, position[1]) elif position[0] > self.xsize-32: position = (self.xsize-32, position[1]) if position[1] < 32: position = (position[0], 32) elif position [1] > self.ysize-32: position = (position[0], self.size-32) root.setTexOffset(self.tileTS, -(position[0]-32)/64, -(position[1]-32)/64) return task.cont def regionViewFound(self): '''Gui for founding a new city!''' self.setOwnerTextures() root = self.terrain.getRoot() task = taskMgr.add(self.newTerrainOverlay, "newTerrainOverlay") tileTexture = loader.loadTexture("Textures/tile.png") tileTexture.setWrapU(Texture.WMClamp) tileTexture.setWrapV(Texture.WMClamp) self.tileTS = TextureStage('tile') self.tileTS.setSort(6) self.tileTS.setMode(TextureStage.MDecal) #self.tileTS.setColor(Vec4(1,0,1,1)) root.setTexture(self.tileTS, tileTexture) root.setTexScale(self.tileTS, self.terrain.xchunks, self.terrain.ychunks) self.acceptOnce("mouse1", self.regionViewFound2) self.acceptOnce("escape", self.cancelRegionViewFound) def regionViewFound2(self): '''Grabs cell location for founding. The texture coordinate is used as the mouse may enter an out of bounds area. ''' root = self.terrain.getRoot() root_position = root.getTexOffset(self.tileTS) # We offset the position of the texture, so we will now put the origin of the new city not on mouse cursor but the "bottom left" of it. Just need to add 32 to get other edge position = [int(abs(root_position[0]*64)), int(abs(root_position[1]*64))] self.cancelRegionViewFound() messenger.send("found_city_name", [position]) def cancelRegionViewFound(self): taskMgr.remove("newTerrainOverlay") root = self.terrain.getRoot() root.clearTexture(self.tileTS) # Restore original mouse function self.accept("mouse1", self.lclick) messenger.send("showRegionGUI") def setSurfaceTextures(self): self.ownerview = False root = self.terrain.getRoot() root.clearTexture() #self.terrain.setTextureMap() root.setTexture( self.colorTS, self.colorTexture ) root.setTexture( self.grassTS, self.grassTexture ) root.setTexScale(self.grassTS, self.size/8, self.size/8) root.setTexture( self.rockTS, self.rockTexture ) root.setTexScale(self.rockTS, self.size/8, self.size/8) root.setTexture( self.sandTS, self.sandTexture) root.setTexScale(self.sandTS, self.size/8, self.size/8) root.setTexture( self.snowTS, self.snowTexture ) root.setTexScale(self.snowTS, self.size/8, self.size/8) root.setTexture( self.gridTS, self.gridTexture ) root.setTexScale(self.gridTS, self.xsize, self.ysize) root.setShaderInput('size', self.xsize, self.ysize, self.size, self.size) root.setShader(loader.loadShader('Shaders/terraintexture.sha')) def setOwnerTextures(self): self.ownerview = True root = self.terrain.getRoot() root.clearShader() root.clearTexture() cityTexture = Texture() cityTexture.load(self.citymap) cityTS = TextureStage('citymap') cityTS.setSort(0) root.setTexture( self.gridTS, self.gridTexture ) root.setTexScale(self.gridTS, self.terrain.xchunks, self.terrain.ychunks) root.setTexture(cityTS, cityTexture, 1) def updateRegion(self, heightmap, tiles, cities): self.generateOwnerTexture(tiles, cities) if self.ownerview: self.setOwnerTextures() def updateTerrain(self, task): '''Updates terrain and water''' self.terrain.update() # Water if self.waterType is 2: pos = base.camera.getPos() render.setShaderInput('time', task.time) mc = base.camera.getMat( ) self.water.changeCameraPos(pos,mc) self.water.changeCameraPos(pos,mc) #print "Render diagnostics" #render.analyze() #base.cTrav.showCollisions(render) return task.cont def generateWater(self, style): print "Generate Water:", self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax '''Generates water style 0: blue card style 1: reflective card style 2: reflective card with shaders ''' self.waterHeight = 22.0 if self.water: self.water.removeNode() if style is 0: cm = CardMaker("water") #cm.setFrame(-1, 1, -1, 1) cm.setFrame(self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax) cm.setColor(0, 0, 1, 0.9) self.water = render.attachNewNode(cm.generate()) if self.waterYMax > self.waterXMax: size = self.waterYMax else: size = self.waterXMax self.water.lookAt(0, 0, -1) self.water.setZ(self.waterHeight) messenger.send('makePickable', [self.water]) elif style is 1: # From Prosoft's super awesome terrain demo cm = CardMaker("water") #cm.setFrame(-1, 1, -1, 1) cm.setFrame(self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax) self.water = render.attachNewNode(cm.generate()) if self.waterYMax > self.waterXMax: size = self.waterYMax else: size = self.waterXMax #self.water.setScale(size) self.water.lookAt(0, 0, -1) self.water.setZ(self.waterHeight) self.water.setShaderOff(1) self.water.setLightOff(1) self.water.setAlphaScale(0.5) self.water.setTransparency(TransparencyAttrib.MAlpha) wbuffer = base.win.makeTextureBuffer("water", 512, 512) wbuffer.setClearColorActive(True) wbuffer.setClearColor(base.win.getClearColor()) self.wcamera = base.makeCamera(wbuffer) self.wcamera.reparentTo(render) self.wcamera.node().setLens(base.camLens) self.wcamera.node().setCameraMask(BitMask32.bit(1)) self.water.hide(BitMask32.bit(1)) wtexture = wbuffer.getTexture() wtexture.setWrapU(Texture.WMClamp) wtexture.setWrapV(Texture.WMClamp) wtexture.setMinfilter(Texture.FTLinearMipmapLinear) self.wplane = Plane(Vec3(0, 0, 1), Point3(0, 0, self.water.getZ())) wplanenp = render.attachNewNode(PlaneNode("water", self.wplane)) tmpnp = NodePath("StateInitializer") tmpnp.setClipPlane(wplanenp) tmpnp.setAttrib(CullFaceAttrib.makeReverse()) self.wcamera.node().setInitialState(tmpnp.getState()) self.water.projectTexture(TextureStage("reflection"), wtexture, self.wcamera) messenger.send('makePickable', [self.water]) elif style is 2: # From Clcheung just as super awesome demomaster self.water_level = Vec4(0.0, 0.0, self.waterHeight, 1.0) self.water = water.WaterNode(self.waterXMin, self.waterYMin, self.waterXMax, self.waterYMax, self.water_level.getZ()) self.water.setStandardControl() self.water.changeParams(None) wl=self.water_level wl.setZ(wl.getZ()-0.05) #root.setShaderInput('waterlevel', self.water_level) render.setShaderInput('time', 0) messenger.send('makePickable', [self.water.waterNP])