def __init__(self, name, inclination, baseDimension): #public props self.baseDimension = baseDimension tex = loader.loadTexture(resourceManager.getResource(name) + '.png') xscaled = tex.getOrigFileXSize() / self.baseDimension yscaled = tex.getOrigFileYSize() / self.baseDimension cm = CardMaker("unscrollobject") cm.setFrame(0, xscaled, 0, yscaled) ts = TextureStage('ts') ts.setMode(TextureStage.MDecal) uvscroll = UvScrollNode("uvscrollnode", 1, 0.0, 0.0, 0.0) uvscroll.addChild(cm.generate()) self.node = NodePath(uvscroll) self.node.setTwoSided(True) self.node.setX((-xscaled / 2) + 0.5) self.node.setP(-(360 - int(inclination))) self.node.setTexture(tex) self.node.setTransparency(TransparencyAttrib.MAlpha) self.node.reparentTo(render)
def fillTextureStages(self, nodePath): """ Prepares all materials of a given nodepath to have at least the 4 default textures in the correct order: [diffuse, normal, specular, roughness] """ emptyDiffuseTex = loader.loadTexture("Data/Textures/EmptyDiffuseTexture.png") emptyNormalTex = loader.loadTexture("Data/Textures/EmptyNormalTexture.png") emptySpecularTex = loader.loadTexture("Data/Textures/EmptySpecularTexture.png") emptyRoughnessTex = loader.loadTexture("Data/Textures/EmptyRoughnessTexture.png") textureOrder = [emptyDiffuseTex, emptyNormalTex, emptySpecularTex, emptyRoughnessTex] textureSorts = [0, 10, 20, 30] # Prepare the textures for tex in textureOrder: tex.setMinfilter(SamplerState.FTLinear) tex.setMagfilter(SamplerState.FTLinear) tex.setFormat(Texture.FRgba) # Iterate over all geom nodes for np in nodePath.findAllMatches("**/+GeomNode"): # Check how many texture stages the nodepath already has stages = np.findAllTextureStages() numStages = len(stages) # Fill the texture stages up for i in xrange(numStages, 4): stage = TextureStage("DefaultTexStage" + str(i)) stage.setSort(textureSorts[i]) stage.setMode(TextureStage.CMModulate) stage.setColor(Vec4(0, 0, 0, 1)) np.setTexture(stage, textureOrder[i])
def splatting(node, first, second, stencil, scale=None, offset=None): """Apply a texture splatting to the provided NodePath. """ # Apply the first texture. ts1 = TextureStage("stage-first") ts1.setSort(0) ts1.setMode(TextureStage.MReplace) ts1.setSavedResult(True) node.setTexture(ts1, first) # Apply the second texture. ts2 = TextureStage("stage-second") ts2.setSort(1) ts2.setMode(TextureStage.MReplace) node.setTexture(ts2, second) # Apply the stencil. ts3 = TextureStage("stage-stencil") ts3.setSort(2) ts3.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) node.setTexture(ts3, stencil) if scale: node.setTexScale(ts3, scale, scale) if offset is not None: node.setTexOffset(ts1, *offset) node.setTexOffset(ts2, *offset) node.setTexOffset(ts3, *offset)
def _gen_flowers(self, surf_mod, angle, side): """Generate texture flowers. Args: surf_mod (panda3d.core.NodePath): Surface model. angle (int): Surface model angle. side (str): Surface model side. """ for i in range(random.randint(0, 3)): ts = TextureStage("ts_flower{}".format(str(i))) ts.setMode(TextureStage.MDecal) tex = loader.loadTexture( # noqa: F821 "just_tex/flower{}.png".format(str(random.randint(1, 5)))) tex.setWrapU(Texture.WMClamp) tex.setWrapV(Texture.WMClamp) surf_mod.setTexture(ts, tex) surf_mod.setTexPos( ts, random.randint(*FLOWER_RANGES[(angle, side)]["u"]), random.randint(*FLOWER_RANGES[(angle, side)]["v"]), 0, ) surf_mod.setTexScale(ts, 20, 20)
def apply_splatted_textures(self, tile: NodePath, first_tex, second_tex, stencil_tex): # first = self.load("textures/sand_tex_1.png") # second = self.load("textures/grass_tex_1.png") # third = self.load("textures/water_tex_1.png") # stencil = self.load("textures/stencil_tex_1.png") # stencil_2 = self.load("textures/stencil_tex_2.png") # # normal = self.load("textures/sea-normal.jpg") # normal = self.loader.load_texture("textures/layingrock-n.jpg") # Apply the first texture. ts1 = TextureStage("stage-first") ts1.setSort(0) ts1.setMode(TextureStage.MReplace) ts1.setSavedResult(True) tile.setTexture(ts1, first_tex) # Apply the second texture. ts2 = TextureStage("stage-second") ts2.setSort(1) ts2.setMode(TextureStage.MReplace) tile.setTexture(ts2, second_tex) ts3 = TextureStage("stage-stencil") ts3.setSort(2) ts3.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) ts3.setSavedResult(True) tile.setTexture(ts3, stencil_tex)
def makeSprite(name, texture, scale, add = False): from panda3d.core import (GeomVertexFormat, GeomVertexData, GeomEnums, InternalName, GeomVertexWriter, GeomPoints, Geom, GeomNode, NodePath, TextureStage, TexGenAttrib, BoundingSphere) format = GeomVertexFormat.getV3() data = GeomVertexData(name + "_data", format, GeomEnums.UHStatic) writer = GeomVertexWriter(data, InternalName.getVertex()) writer.addData3f((0, 0, 0)) primitive = GeomPoints(GeomEnums.UHStatic) primitive.addVertex(0) primitive.closePrimitive() geom = Geom(data) geom.addPrimitive(primitive) geomNode = GeomNode(name) geomNode.addGeom(geom) np = NodePath(geomNode) np.setLightOff(1) np.setMaterialOff(1) np.setRenderModePerspective(True) ts = TextureStage('sprite') if add: ts.setMode(TextureStage.MAdd) np.setTexture(ts, texture) np.setTexGen(ts, TexGenAttrib.MPointSprite) np.setDepthWrite(False) np.setDepthOffset(1) np.setTransparency(True) np.node().setBounds(BoundingSphere((0, 0, 0), 1)) np.node().setFinal(True) np.flattenStrong() np.setScale(scale) return np
class water(): def __init__(self, render, loader, location, sizeX, sizeY): self.water = loader.loadModel( 'assets/environment/arctic/nature/water.bam') self.water.setPos(location) self.water.setSx(sizeX) self.water.setSy(sizeY) self.newTS = TextureStage('ts') self.normal_TS = TextureStage('normal') self.normal_TS.setMode(TextureStage.MNormal) self.water.setTexture( self.newTS, loader.loadTexture( 'assets/environment/arctic/nature/textures/water_colormap.jpg') ) self.water.setTexScale(self.newTS, 80) self.water.setTexture( self.normal_TS, loader.loadTexture( 'assets/environment/arctic/nature/textures/water_normalmap.jpg' )) self.water.setTexScale(self.normal_TS, 80) self.water.setShaderAuto() ambiet = AmbientLight('ambient') ambiet.setColor((0.2, 0.2, 0.2, 1)) alight = self.water.attachNewNode(ambiet) self.water.setLight(alight) self.water.reparentTo(render) self.skybox = loader.loadModel( "assets/environment/arctic/nature/skybox.bam") self.skybox.setPos(location) self.skybox.setScale(2000)
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)
def applyNoGlow(np): global NoGlowTS global NoGlowTex if not NoGlowTS: NoGlowTS = TextureStage('noglow') NoGlowTS.setMode(TextureStage.MGlow) if not NoGlowTex: NoGlowTex = loader.loadTexture("phase_3/maps/black.png") np.setTexture(NoGlowTS, NoGlowTex)
def addTexture(stage,path): tex=loader.loadTexture(path) tex.setWrapU(Texture.WMRepeat) tex.setWrapV(Texture.WMRepeat) s=str(stage) TS=model.findTextureStage(s) if not TS: TS=TextureStage(s) TS.setMode(TSmode[stage-2]) TS.setSort(stage-1) model.setTexture(TS,tex)
def create16To9LogoCard(logoPath, tsName): cm = CardMaker("fade") scale = abs(base.a2dLeft) / 1.7776 cm.setFrame(-1, 1, -1 * scale, 1 * scale) logo = NodePath(cm.generate()) logo.setTransparency(TransparencyAttrib.MAlpha) logoTex = loader.loadTexture(logoPath) logoTs = TextureStage(tsName) logoTs.setMode(TextureStage.MReplace) logo.setTexture(logoTs, logoTex) logo.setBin("fixed", 5000) logo.reparentTo(render2d) logo.hide() return logo
def initSwitchSigns(self): self.switchSigns = [] for i in range(11): cm = CardMaker('card%d'%i) cm.setColor(0,0,0,0) cm.setFrame(-0.5, 0.5, -0.5, 0.5) card = self.level.attachNewNode(cm.generate()) card.setAttrib(TransparencyAttrib.make(TransparencyAttrib.M_alpha)) tex = loader.loadTexture('%d.png'%i) ts = TextureStage('ts') ts.setMode(TextureStage.MReplace) card.setTexture(ts, tex) card.setEffect(BillboardEffect.makePointEye()) card.hide() self.switchSigns.append(card)
def on_pick(self): if not self._update_pick_ray(): return # traverse scene graph and determine nearest selection (if pickable) self.pick_traverser.traverse(self.board_renderer.base.render) self.pick_queue.sortEntries() if not self.pick_queue.getNumEntries(): return node = self.pick_queue.getEntry(0).getIntoNodePath().findNetTag('pickable') if node.isEmpty() or node.getTag('pickable') == 'False': return # add some color ts = TextureStage('ts') ts.setMode(TextureStage.MModulate) colors = list(Game.player_colors) colors.remove('white') node.setTexture(ts, self.board_renderer.tileset.load_texture('textures/player%s.png' % random.choice(colors).capitalize()))
def createFadeableImage(img, tsName, big=False): cm = CardMaker("FadableCard") cm.setFrame(-1, 1, -1, 1) image = NodePath(cm.generate()) image.setTransparency(TransparencyAttrib.MAlpha) imageTex = loader.loadTexture(img) imageTs = TextureStage(tsName) imageTs.setMode(TextureStage.MReplace) image.setTexture(imageTs, imageTex) image.reparentTo(render2d) if big: image.setScale(0.75) else: image.setScale(0.5) image.setPos(0, 0, 0.25) image.hide() return image
def __create_terrain(self): terrain = GeoMipTerrain("Terrain") terrain.setHeightfield(self.__texture_path(self.__scene.get("scene", "heightmap"))) terrain.getRoot().reparentTo(self.render) terrain.generate() terrain.getRoot().setSx(1000.0 / 512) terrain.getRoot().setSy(1000.0 / 512) terrain.getRoot().setSz(74) terrain.getRoot().setPos(-500, -500, 0) black = self.loader.loadTexture(self.__texture_path(self.__scene.get("terrain", "black"))) black.setMinfilter(Texture.FTLinearMipmapNearest) ts = TextureStage("stage-first") ts.setSort(0) ts.setMode(TextureStage.MReplace) ts.setSavedResult(True) terrain.getRoot().setTexture(ts, black) terrain.getRoot().setTexScale(ts, 250, 250) white = self.loader.loadTexture(self.__texture_path(self.__scene.get("terrain", "white"))) white.setMinfilter(Texture.FTLinearMipmapNearest) ts = TextureStage("stage-second") ts.setSort(1) ts.setMode(TextureStage.MReplace) terrain.getRoot().setTexture(ts, white) terrain.getRoot().setTexScale(ts, 250, 250) stencil = self.loader.loadTexture(self.__texture_path(self.__scene.get("scene", "stencil"))) ts = TextureStage("stage-stencil") ts.setSort(2) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) terrain.getRoot().setTexture(ts, stencil) ts = TextureStage("stage-vertexcolour") ts.setSort(3) ts.setCombineRgb(TextureStage.CMModulate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSPrimaryColor, TextureStage.COSrcColor) terrain.getRoot().setTexture(ts, "final")
def makeRenderState(material = None, diffuseTexture=None, normalTexture=None, glowTexture=None): n = NodePath("n") if not material: material = makeMaterial((0,0,0,1), (1,1,1,1), (0.01,0.01,0.01,1), 1, (1,1,1,1)) n.setMaterial(material) if diffuseTexture: tsDiffuse = TextureStage('diffuse') tsDiffuse.setMode(TextureStage.MModulate) n.setTexture(tsDiffuse, diffuseTexture) if glowTexture: tsGlow = TextureStage('glow') tsGlow.setMode(TextureStage.MGlow) n.setTexture(tsGlow, glowTexture) if normalTexture: tsNormal = TextureStage('normal') tsNormal.setMode(TextureStage.MNormal) n.setTexture(tsNormal, normalTexture) # weird bugs :| #n.setTransparency(True) #n.setColorOff() return n.getState()
def makeRenderState(material=None, diffuseTexture=None, normalTexture=None, glowTexture=None): n = NodePath("n") if not material: material = makeMaterial((0, 0, 0, 1), (1, 1, 1, 1), (0.01, 0.01, 0.01, 1), 1, (1, 1, 1, 1)) n.setMaterial(material) if diffuseTexture: tsDiffuse = TextureStage('diffuse') tsDiffuse.setMode(TextureStage.MModulate) n.setTexture(tsDiffuse, diffuseTexture) if glowTexture: tsGlow = TextureStage('glow') tsGlow.setMode(TextureStage.MGlow) n.setTexture(tsGlow, glowTexture) if normalTexture: tsNormal = TextureStage('normal') tsNormal.setMode(TextureStage.MNormal) n.setTexture(tsNormal, normalTexture) # weird bugs :| #n.setTransparency(True) #n.setColorOff() return n.getState()
def __init__(self, bulletWorld): self.sky = SkyDome() # model used as collision mesh collisionModel = loader.loadModel('models/walledTrack') # model used as display model model = loader.loadModel('models/FullTrack') tex = loader.loadTexture("models/tex/Main.png") ts = TextureStage('ts') ts.setMode(TextureStage.MBlend) model.setTexture(ts, tex, 2) #model.setTexScale(ts, 70) # renders track from two camera views model.setTwoSided(True) mesh = BulletTriangleMesh() for geomNP in collisionModel.findAllMatches('**/+GeomNode'): geomNode = geomNP.node() ts = geomNP.getTransform(collisionModel) for geom in geomNode.getGeoms(): mesh.addGeom(geom, ts) shape = BulletTriangleMeshShape(mesh, dynamic=False) self.rigidNode = BulletRigidBodyNode('Track') self.rigidNode.notifyCollisions(False) np = render.attachNewNode(self.rigidNode) np.node().addShape(shape) model.reparentTo(np) np.setScale(70) np.setPos(0, 0, -5) np.setCollideMask(BitMask32(0xf0)) np.node().notifyCollisions(False) bulletWorld.attachRigidBody(np.node()) self.hf = np.node() # To enable/disable debug visualisation
def set_ranking(self): items = game.logic.season.logic.ranking.logic.ranking.items() sorted_ranking = reversed(sorted(items, key=lambda el: el[1])) txt = OnscreenText(text=_('Ranking'), scale=.1, pos=(0, .3), font=self.font, fg=self.text_bg) self.widgets += [txt] for i, car in enumerate(sorted_ranking): idx, name, _car, skills = next(driver for driver in self.props.drivers if driver[3] == car[0]) is_car = car[0] == self.props.car_path txt = OnscreenText(text=str(car[1]) + ' ' + name, align=TextNode.A_left, scale=.072, pos=(-.2, .1 - i * .16), font=self.font, fg=self.text_fg if is_car else self.text_bg) self.widgets += [txt] img = OnscreenImage(self.props.cars_path % car[0], pos=(-.36, 1, .12 - i * .16), scale=.074) self.widgets += [img] with open(eng.curr_path + 'yyagl/assets/shaders/filter.vert') as ffilter: vert = ffilter.read() with open(eng.curr_path + 'yyagl/assets/shaders/drv_car.frag') as ffilter: frag = ffilter.read() shader = Shader.make(Shader.SL_GLSL, vert, frag) img.setShader(shader) img.setTransparency(True) ts = TextureStage('ts') ts.setMode(TextureStage.MDecal) txt_path = self.props.drivers_path % idx img.setTexture(ts, loader.loadTexture(txt_path))
class Node: def __init__(self, np, reflectiveness): self.nodePath = np self.stage = TextureStage(self.nodePath.getName() + "-cubemap_stage") self.stage.setPriority(1) self.stage.setMode(TextureStage.MModulate) self.stage.setColor( VBase4(reflectiveness, reflectiveness, reflectiveness, 1.0)) self.nodePath.setTexGen(self.stage, TexGenAttrib.MWorldCubeMap) self.currentCube = None def clearCurrentCube(self): if self.currentCube: if self.nodePath and not self.nodePath.isEmpty(): #self.nodePath.clearTexProjector(self.stage) self.nodePath.clearTexture(self.stage) self.currentCube = None def setCurrentCube(self, cube): self.clearCurrentCube() self.currentCube = cube if self.nodePath and not self.nodePath.isEmpty(): #self.nodePath.setTexProjector(self.stage, self.currentCube.projector, self.nodePath) self.nodePath.setTexture(self.stage, self.currentCube.cubeTex) def cleanup(self): self.clearCurrentCube() if self.nodePath and not self.nodePath.isEmpty(): self.nodePath.clearTexGen(self.stage) self.nodePath = None self.stage = None
def __init__(self, name, bodyDB): Body.__init__(self, name, bodyDB) self.mesh.reparentTo(render) self.spectral = bodyDB['spectral'] # We use the data from the spectral database to properly color our star. color = colorDatabase[self.spectral] self.mesh.setColor(color[0]/255.0,color[1]/255.0,color[2]/255.0,1) # We will use a point light to cast our main light self.light = self.mesh.attachNewNode( PointLight( "sunPointLight" ) ) # Color is set by spectral type. THIS IS NOT PROPER BLACKBODY! self.light.node().setColor( Vec4(color[0]/255.0,color[1]/255.0,color[2]/255.0,1) ) # Attenuation controls how the light fades with distance. The numbers are # The three values represent the three constants (constant, linear, and # quadratic) in the internal lighting equation. The higher the numbers the # shorter the light goes. #self.light.node().setAttenuation( Vec3( .1, 0.04, 0.0 ) ) texture1 = loader.loadTexture('sun_1k_tex.jpg') ts1 = TextureStage('textures1') ts1.setMode(TextureStage.MGlow) self.mesh.setTexture(ts1, texture1) render.setLight( self.light ) starlights.append(self.light)
def render_level(map): from direct.showbase.Loader import Loader tex=Loader("foo").loadTexture("BrickOldSharp0215_2_thumbhuge.jpg") nor=Loader("foo").loadTexture("BrickOldSharp0215_2_thumbhuge-n.jpg") ts = TextureStage('ts') ts.setMode(TextureStage.MNormal) myMaterial = Material() myMaterial.setShininess(0.0) myMaterial.setAmbient(Vec4(0,0,0,1)) myMaterial.setEmission(Vec4(0.0,0.0,0.0,1)) myMaterial.setDiffuse(Vec4(0.2,0.2,0.2,1)) myMaterial.setSpecular(Vec4(0.5,0.5,0.5,1)) level_node = NodePath("level") for i in range(0,22,1): x = i * 2.0 for j in range(0,22,1): y = j * 2.0 hideset = set() cell = map[i][j] if cell.north == OPEN: hideset.add(2) if cell.west == OPEN: hideset.add(3) if cell.south == OPEN: hideset.add(0) if cell.east == OPEN: hideset.add(1) xcube = makeCube(inverse=True, hide=hideset) cube = NodePath(xcube) cube.setTexture(tex) cube.setTexture(ts,nor) cube.reparentTo(level_node) cube.setPos(x, y, 0 ) #cube.setMaterial(myMaterial) return level_node
def set_grid(self): txt = OnscreenText(text=_('Starting grid'), scale=.1, pos=(-1.0, .3), font=self.font, fg=self.text_bg) self.widgets += [txt] for i, car in enumerate(self.props.grid): idx, name, _car, skills = next(driver for driver in self.props.drivers if driver[3] == car) is_car = car == self.props.car_path txt = OnscreenText(text=str(i + 1) + '. ' + name, align=TextNode.A_left, scale=.072, pos=(-1.28, .1 - i * .16), font=self.font, fg=self.text_fg if is_car else self.text_bg) self.widgets += [txt] img = OnscreenImage(self.props.cars_path % car, pos=(-1.42, 1, .12 - i * .16), scale=.074) self.widgets += [img] with open(eng.curr_path + 'yyagl/assets/shaders/filter.vert') as ffilter: vert = ffilter.read() with open(eng.curr_path + 'yyagl/assets/shaders/drv_car.frag') as f: frag = f.read() shader = Shader.make(Shader.SL_GLSL, vert, frag) img.setShader(shader) img.setTransparency(True) ts = TextureStage('ts') ts.setMode(TextureStage.MDecal) txt_path = self.props.drivers_path % idx img.setTexture(ts, loader.loadTexture(txt_path))
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
def generateNode(self): self.destroy() self.node = NodePath('gameobjectnode') self.node.setTwoSided(True) self.node.reparentTo(self.parent.node) if self.properties['avoidable'] == True: self.node.setTag("avoidable", 'true') else: self.node.setTag("avoidable", 'false') #setting scripting part self.node.setTag("onWalked", self.onWalked) self.node.setTag("onPicked", self.onPicked) #set unique id self.node.setTag("id", self.properties['id']) tex = loader.loadTexture(resourceManager.getResource(self.properties['url'])+'.png') tex.setWrapV(Texture.WM_clamp) tex.setWrapU(Texture.WM_clamp) #this is true pixel art #change to FTLinear for linear interpolation between pixel colors tex.setMagfilter(Texture.FTNearest) tex.setMinfilter(Texture.FTNearest) xorig = tex.getOrigFileXSize() / self.baseDimension yorig = tex.getOrigFileYSize() / self.baseDimension xscaled = (tex.getOrigFileXSize() / self.baseDimension) * self.properties['scale'] yscaled = (tex.getOrigFileYSize() / self.baseDimension) * self.properties['scale'] self.node.setTag("xscaled", str(xscaled)) self.node.setTag("yscaled", str(yscaled)) cm = CardMaker("tileobject") cm.setFrame(0,xorig,0,yorig) ts = TextureStage('ts') ts.setMode(TextureStage.MDecal) # distinguish between 3d collisions (for objects with an height and sensible self.properties['inclination']) # and 2d collisions for plain sprites if self.properties['walkable'] == 'false': if self.properties['collisionmode'] == "3d": #must handle differently objects which are small and big if xscaled < 1: self.collisionTube = CollisionBox(LPoint3f(0.5 - xscaled/2 - self.properties['offsetwidth'],0,0),LPoint3f(0.5 + xscaled/2 + self.properties['offsetwidth'],0.1,0.3 + self.properties['offsetheight'])) if xscaled >= 1: self.collisionTube = CollisionBox(LPoint3f(0 - self.properties['offsetwidth'],0,0),LPoint3f(xscaled + self.properties['offsetwidth'],0.1,0.3 + self.properties['offsetheight'])) self.collisionNode = CollisionNode('objectSphere') self.collisionNode.addSolid(self.collisionTube) self.collisionNodeNp = self.node.attachNewNode(self.collisionNode) self.collisionNodeNp.setX(self.properties['offsethorizontal']) self.collisionNodeNp.setZ(self.properties['offsetvertical']) self.collisionNodeNp.setX(self.collisionNodeNp.getX()+self.properties['offsetcollisionh']) self.collisionNodeNp.setZ(self.collisionNodeNp.getZ()+self.properties['offsetcollisionv']+0.1) if main.editormode: self.collisionNodeNp.show() elif self.properties['collisionmode'] == "2d": #must handle differently objects which are small and big if xscaled < 1: self.collisionTube = CollisionBox(LPoint3f(0.5 - xscaled/2 - self.properties['offsetwidth'],0,0),LPoint3f(0.5 + xscaled/2 + self.properties['offsetwidth'],yscaled + self.properties['offsetheight'],0.3)) if xscaled >= 1: self.collisionTube = CollisionBox(LPoint3f(0 - self.properties['offsetwidth'],0,0),LPoint3f(xscaled + self.properties['offsetwidth'],yscaled + self.properties['offsetheight'],0.3)) self.collisionNode = CollisionNode('objectSphere') self.collisionNode.addSolid(self.collisionTube) self.collisionNodeNp = self.node.attachNewNode(self.collisionNode) self.collisionNodeNp.setP(-(270-int(self.properties['inclination']))) self.collisionNodeNp.setX(self.properties['offsethorizontal']) self.collisionNodeNp.setZ(self.properties['offsetvertical']) self.collisionNodeNp.setX(self.collisionNodeNp.getX()+self.properties['offsetcollisionh']) self.collisionNodeNp.setZ(self.collisionNodeNp.getZ()+self.properties['offsetcollisionv']+0.1) if main.editormode: self.collisionNodeNp.show() geomnode = NodePath(cm.generate()) if geomnode.node().isGeomNode(): vdata = geomnode.node().modifyGeom(0).modifyVertexData() writer = GeomVertexWriter(vdata, 'vertex') reader = GeomVertexReader(vdata, 'vertex') ''' this part apply rotation flattening to the perspective view by modifying directly structure vertices ''' i = 0 #counter while not reader.isAtEnd(): v = reader.getData3f() x = v[0] y = v[1] z = v[2] newx = x newy = y newz = z if self.properties['rotation'] == -90.0: if i == 0: newx = math.fabs(math.cos(math.radians(self.properties['inclination']))) * z newz = 0 ssen = math.fabs(math.sin(math.radians(self.properties['inclination']))) * z sparsen = math.fabs(math.sin(math.radians(self.properties['inclination']))) * ssen spercos = math.fabs(math.cos(math.radians(self.properties['inclination']))) * ssen newy -= spercos newz += sparsen if i == 2: newx += math.fabs(math.cos(math.radians(self.properties['inclination']))) * z newz = 0 ssen = math.fabs(math.sin(math.radians(self.properties['inclination']))) * z sparsen = math.fabs(math.sin(math.radians(self.properties['inclination']))) * ssen spercos = math.fabs(math.cos(math.radians(self.properties['inclination']))) * ssen newy -= spercos newz += sparsen writer.setData3f(newx, newy, newz) i += 1 #increase vertex counter if xscaled >= 1: geomnode.setX(0) if xscaled < 1: geomnode.setX(0.5 - xscaled/2) geomnode.setScale(self.properties['scale']) geomnode.setX(geomnode.getX()+self.properties['offsethorizontal']) geomnode.setZ(geomnode.getZ()+self.properties['offsetvertical']) geomnode.setY(-self.properties['elevation']) geomnode.setP(int(self.properties['inclination'])-360) geomnode.setTexture(tex) geomnode.setTransparency(TransparencyAttrib.MAlpha) geomnode.reparentTo(self.node) self.node.setR(self.properties['rotation'])
def show(self, race_ranking, lap_times, drivers, player_car_name): track = self.props.track_path self.result_frm = DirectFrame(frameColor=(.8, .8, .8, .64), frameSize=(-2, 2, -1, 1)) laps = len(lap_times) text_bg = self.props.menu_args.text_bg pars = {'scale': .1, 'fg': text_bg, 'font': self.props.menu_args.font} # ref into race self.__res_txts = [ OnscreenText(str(round(lap_times[i], 2)), pos=(0, .47 - .2 * (i + 1)), **pars) for i in range(laps) ] self.__res_txts += [OnscreenText(_('LAP'), pos=(-.6, .6), **pars)] self.__res_txts += [OnscreenText(_('TIME'), pos=(0, .6), **pars)] self.__res_txts += [ OnscreenText(_('RANKING'), pos=(.5, .6), align=TextNode.A_left, **pars) ] self.__res_txts += [ OnscreenText(str(i), pos=(-.6, .47 - .2 * i), **pars) for i in range(1, 4) ] race_ranking_sorted = sorted(race_ranking.items(), key=lambda x: x[1]) race_ranking_sorted = reversed([el[0] for el in race_ranking_sorted]) for i, car in enumerate(race_ranking_sorted): carinfo = next(drv for drv in drivers if drv[3] == car) idx, name, skills, _car = carinfo is_car = car == player_car_name fgc = self.props.menu_args.text_fg if is_car else text_bg txt = OnscreenText(text=str(i + 1) + '. ' + name, align=TextNode.A_left, scale=.072, pos=(.68, .44 - .16 * (i + 1)), font=self.props.menu_args.font, fg=fgc) img = OnscreenImage(self.props.cars_imgs % car, pos=(.58, 1, .47 - (i + 1) * .16), scale=.074) with open(eng.curr_path + 'yyagl/assets/shaders/filter.vert') as f: vert = f.read() with open(eng.curr_path + 'yyagl/assets/shaders/drv_car.frag') as f: frag = f.read() shader = Shader.make(Shader.SL_GLSL, vert, frag) img.setShader(shader) img.setTransparency(True) ts = TextureStage('ts') ts.setMode(TextureStage.MDecal) txt_path = self.props.drivers_imgs % idx img.setTexture(ts, loader.loadTexture(txt_path)) self.__res_txts += [txt, img] self.__res_txts += [ OnscreenText(_('share:'), pos=(-.1, -.82), align=TextNode.A_right, **pars) ] self.__buttons = [] curr_time = min(game.player_car.logic.lap_times or [0]) facebook_url = self.props.share_urls[0] #TODO: find a way to share the time on Facebook twitter_url = self.props.share_urls[1] twitter_url = twitter_url.format(time=round(curr_time, 2), track=track) plus_url = self.props.share_urls[2] #TODO: find a way to share the time on Google Plus tumblr_url = self.props.share_urls[3] #TODO: find a way to share the time on Tumblr sites = [('facebook', facebook_url), ('twitter', twitter_url), ('google_plus', plus_url), ('tumblr', tumblr_url)] self.__buttons += [ ImageButton(scale=.078, pos=(.02 + i * .18, 1, -.79), frameColor=(0, 0, 0, 0), image=self.props.share_imgs % site[0], command=eng.open_browser, extraArgs=[site[1]], rolloverSound=self.props.menu_args.rollover, clickSound=self.props.menu_args.click) for i, site in enumerate(sites) ] def step(): self.notify('on_race_step', race_ranking) self.destroy() Subject.destroy(self) cont_btn = DirectButton(text=_('Continue'), pos=(0, 1, -.6), command=step, **self.props.menu_args.btn_args) self.__buttons += [cont_btn]
class Typist(object): TARGETS = { 'paper': { 'model': 'paper', 'textureRoot': 'Front', 'scale': Point3(0.85, 0.85, 1), 'hpr' : Point3(0, 0, 0), } } def __init__(self, base, typewriterNP, underDeskClip, sounds): self.base = base self.sounds = sounds self.underDeskClip = underDeskClip self.typeIndex = 0 self.typewriterNP = typewriterNP self.rollerAssemblyNP = typewriterNP.find("**/roller assembly") assert self.rollerAssemblyNP self.rollerNP = typewriterNP.find("**/roller") assert self.rollerNP self.carriageNP = typewriterNP.find("**/carriage") assert self.carriageNP self.baseCarriagePos = self.carriageNP.getPos() self.carriageBounds = self.carriageNP.getTightBounds() self.font = base.loader.loadFont('Harting.ttf', pointSize=32) self.pnmFont = PNMTextMaker(self.font) self.fontCharSize, _, _ = fonts.measureFont(self.pnmFont, 32) print "font char size: ",self.fontCharSize self.pixelsPerLine = int(round(self.pnmFont.getLineHeight())) self.target = None """ panda3d.core.NodePath """ self.targetRoot = None """ panda3d.core.NodePath """ self.paperY = 0.0 """ range from 0 to 1 """ self.paperX = 0.0 """ range from 0 to 1 """ self.createRollerBase() self.tex = None self.texImage = None self.setupTexture() self.scheduler = Scheduler() task = self.base.taskMgr.add(self.tick, 'timerTask') task.setDelay(0.01) def tick(self, task): self.scheduler.tick(globalClock.getRealTime()) return task.cont def setupTexture(self): """ This is the overlay/decal/etc. which contains the typed characters. The texture size and the font size are currently tied together. :return: """ self.texImage = PNMImage(1024, 1024) self.texImage.addAlpha() self.texImage.fill(1.0) self.texImage.alphaFill(1.0) self.tex = Texture('typing') self.tex.setMagfilter(Texture.FTLinear) self.tex.setMinfilter(Texture.FTLinear) self.typingStage = TextureStage('typing') self.typingStage.setMode(TextureStage.MModulate) self.tex.load(self.texImage) # ensure we can quickly update subimages self.tex.setKeepRamImage(True) # temp for drawing chars self.chImage = PNMImage(*self.fontCharSize) def drawCharacter(self, ch, px, py): """ Draw a character onto the texture :param ch: :param px: paperX :param py: paperY :return: the paper-relative size of the character """ h = self.fontCharSize[1] if ch != ' ': # position -> pixel, applying margins x = int(self.tex.getXSize() * (px * 0.8 + 0.1)) y = int(self.tex.getYSize() * (py * 0.8 + 0.1)) # always draw onto the paper, to capture # incremental character overstrikes self.pnmFont.generateInto(ch, self.texImage, x, y) if False: #print ch,"to",x,y,"w=",g.getWidth() self.tex.load(self.texImage) else: # copy an area (presumably) encompassing the character g = self.pnmFont.getGlyph(ord(ch)) cx, cy = self.fontCharSize # a glyph is minimally sized and "moves around" in its text box # (think ' vs. ,), so it has been drawn somewhere relative to # the 'x' and 'y' we wanted. x += g.getLeft() y -= g.getTop() self.chImage.copySubImage( self.texImage, 0, 0, # from x, y, # to cx, cy # size ) self.tex.loadSubImage(self.chImage, x, y) # toggle for a typewriter that uses non-proportional spacing #w = self.paperCharWidth(g.getWidth()) w = self.paperCharWidth() else: w = self.paperCharWidth() return w, h def start(self): self.target = None self.setTarget('paper') self.hookKeyboard() def createRollerBase(self): """ The paper moves such that it is tangent to the roller. This nodepath keeps a coordinate space relative to that, so that the paper can be positioned from (0,0,0) to (0,0,1) to "roll" it along the roller. """ bb = self.rollerNP.getTightBounds() #self.rollerNP.showTightBounds() self.paperRollerBase = self.rollerAssemblyNP.attachNewNode('rollerBase') self.paperRollerBase.setHpr(0, -20, 0) print "roller:",bb rad = abs(bb[0].y - bb[1].y) / 2 center = Vec3(-(bb[0].x+bb[1].x)/2 - 0.03, (bb[0].y-bb[1].y)/2, (bb[0].z+bb[1].z)/2) self.paperRollerBase.setPos(center) def setTarget(self, name): if self.target: self.target.removeNode() # load and transform the model target = self.TARGETS[name] self.target = self.base.loader.loadModel(target['model']) #self.target.setScale(target['scale']) self.target.setHpr(target['hpr']) # put it in the world self.target.reparentTo(self.paperRollerBase) rbb = self.rollerNP.getTightBounds() tbb = self.target.getTightBounds() rs = (rbb[1] - rbb[0]) ts = (tbb[1] - tbb[0]) self.target.setScale(rs.x / ts.x, 1, 1) # apply the texture self.targetRoot = self.target if 'textureRoot' in target: self.targetRoot = self.target.find("**/" + target['textureRoot']) assert self.targetRoot self.targetRoot.setTexture(self.typingStage, self.tex) #self.setupTargetClip() # reset self.paperX = self.paperY = 0. newPos = self.calcPaperPos(self.paperY) self.target.setPos(newPos) self.moveCarriage() def setupTargetClip(self): """ The target is fed in to the typewriter but until we invent "geom curling", it shouldn't be visible under the typewriter under the desk. The @underDeskClip node has a world-relative bounding box, which we can convert to the target-relative bounding box, and pass to a shader that can clip the nodes. """ shader = Shader.make( Shader.SLGLSL, """ #version 120 attribute vec4 p3d_MultiTexCoord0; attribute vec4 p3d_MultiTexCoord1; void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_TexCoord[0] = p3d_MultiTexCoord0; gl_TexCoord[1] = p3d_MultiTexCoord1; } """, """ #version 120 uniform sampler2D baseTex; uniform sampler2D charTex; const vec4 zero = vec4(0, 0, 0, 0); const vec4 one = vec4(1, 1, 1, 1); const vec4 half = vec4(0.5, 0.5, 0.5, 0); void main() { vec4 baseColor = texture2D(baseTex, gl_TexCoord[0].st); vec4 typeColor = texture2D(charTex, gl_TexCoord[1].st); gl_FragColor = baseColor * typeColor; }""" ) self.target.setShader(shader) baseTex = self.targetRoot.getTexture() print "Base Texture:",baseTex self.target.setShaderInput("baseTex", baseTex) self.target.setShaderInput("charTex", self.tex) def hookKeyboard(self): """ Hook events so we can respond to keypresses. """ self.base.buttonThrowers[0].node().setKeystrokeEvent('keystroke') self.base.accept('keystroke', self.schedTypeCharacter) self.base.accept('backspace', self.schedBackspace) self.base.accept('arrow_up', lambda: self.schedAdjustPaper(-5)) self.base.accept('arrow_up-repeat', lambda: self.schedAdjustPaper(-1)) self.base.accept('arrow_down', lambda:self.schedAdjustPaper(5)) self.base.accept('arrow_down-repeat', lambda:self.schedAdjustPaper(1)) self.base.accept('arrow_left', lambda: self.schedAdjustCarriage(-1)) self.base.accept('arrow_left-repeat', lambda: self.schedAdjustCarriage(-1)) self.base.accept('arrow_right', lambda:self.schedAdjustCarriage(1)) self.base.accept('arrow_right-repeat', lambda:self.schedAdjustCarriage(1)) def paperCharWidth(self, pixels=None): if not pixels: pixels = self.fontCharSize[0] return float(pixels) / self.tex.getXSize() def paperLineHeight(self): return float(self.fontCharSize[1] * 1.2) / self.tex.getYSize() def schedScroll(self): if self.scheduler.isQueueEmpty(): self.schedRollPaper(1) self.schedResetCarriage() def schedBackspace(self): if self.scheduler.isQueueEmpty(): def doit(): if self.paperX > 0: self.schedAdjustCarriage(-1) self.scheduler.schedule(0.01, doit) def createMoveCarriageInterval(self, newX, curX=None): if curX is None: curX = self.paperX here = self.calcCarriage(curX) there = self.calcCarriage(newX) posInterval = LerpPosInterval( self.carriageNP, abs(newX - curX), there, startPos = here, blendType='easeIn') posInterval.setDoneEvent('carriageReset') def isReset(): self.paperX = newX self.base.acceptOnce('carriageReset', isReset) return posInterval def schedResetCarriage(self): if self.paperX > 0.1: self.sounds['pullback'].play() invl = self.createMoveCarriageInterval(0) self.scheduler.scheduleInterval(0, invl) def calcCarriage(self, paperX): """ Calculate where the carriage should be offset based on the position on the paper :param paperX: 0...1 :return: pos for self.carriageNP """ x = (0.5 - paperX) * 0.69 * 0.8 + 0.01 bb = self.carriageBounds return self.baseCarriagePos + Point3(x * (bb[1].x-bb[0].x), 0, 0) def moveCarriage(self): pos = self.calcCarriage(self.paperX) self.carriageNP.setPos(pos) def schedMoveCarriage(self, curX, newX): if self.scheduler.isQueueEmpty(): #self.scheduler.schedule(0.1, self.moveCarriage) invl = self.createMoveCarriageInterval(newX, curX=curX) invl.start() def schedAdjustCarriage(self, bx): if self.scheduler.isQueueEmpty(): def doit(): self.paperX = max(0.0, min(1.0, self.paperX + bx * self.paperCharWidth())) self.moveCarriage() self.scheduler.schedule(0.1, doit) def calcPaperPos(self, paperY): # center over roller, peek out a little z = paperY * 0.8 - 0.5 + 0.175 bb = self.target.getTightBounds() return Point3(-0.5, 0, z * (bb[1].z-bb[0].z)) def createMovePaperInterval(self, newY): here = self.calcPaperPos(self.paperY) there = self.calcPaperPos(newY) posInterval = LerpPosInterval( self.target, abs(newY - self.paperY), there, startPos = here, blendType='easeInOut') posInterval.setDoneEvent('scrollDone') def isDone(): self.paperY = newY self.base.acceptOnce('scrollDone', isDone) return posInterval def schedAdjustPaper(self, by): if self.scheduler.isQueueEmpty(): def doit(): self.schedRollPaper(by) self.scheduler.schedule(0.1, doit) def schedRollPaper(self, by): """ Position the paper such that @percent of it is rolled over roller :param percent: :return: """ def doit(): self.sounds['scroll'].play() newY = min(1.0, max(0.0, self.paperY + self.paperLineHeight() * by)) invl = self.createMovePaperInterval(newY) invl.start() self.scheduler.schedule(0.1, doit) def schedTypeCharacter(self, keyname): # filter for visibility if ord(keyname) == 13: self.schedScroll() elif ord(keyname) >= 32 and ord(keyname) != 127: if self.scheduler.isQueueEmpty(): curX, curY = self.paperX, self.paperY self.typeCharacter(keyname, curX, curY) def typeCharacter(self, ch, curX, curY): newX = curX w, h = self.drawCharacter(ch, curX, curY) newX += w if ch != ' ': # alternate typing sound #self.typeIndex = (self.typeIndex+1) % 3 self.typeIndex = random.randint(0, 2) self.sounds['type' + str(self.typeIndex+1)].play() else: self.sounds['advance'].play() if newX >= 1: self.sounds['bell'].play() newX = 1 self.schedMoveCarriage(self.paperX, newX) # move first, to avoid overtype self.paperX = newX
def addTextureStage(texId, texMode, texAttr, tex): if tex: ts = TextureStage(texId) ts.setMode(texMode) texAttr = texAttr.addOnStage(ts, tex) return texAttr
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 GTile(GEntity): def __init__(self,conf): self.p3dobject=self.gmap.tile_matrix_node.attachNewNode('tile_'+str(conf['eid'])) self.p3dobject.setTransparency(TransparencyAttrib.MAlpha) #self.test_sphere=loader.loadModel('data/models/test_sphere.egg') #self.test_sphere.reparentTo(self.p3dobject) GEntity.__init__(self,conf) self.x,self.y=x,y=conf['x'],conf['y'] self.p3dobject.setTag('x',str(x)) self.p3dobject.setTag('y',str(y)) self.p3dobject.setPythonTag('ref',self) #half of a tile side t=self.gmap.tile_matrix_node.getScale()[0]/2. self.p3dobject.setPos(self.gmap.tile_matrix_node,(-self.gmap.resx/2.+x+t)*2.,(y-self.gmap.resy/2.+t)*2.,0) #preload texture holder quad self.quad=GTile.resources['quad']() self.quad.setTransparency(TransparencyAttrib.MAlpha) #self.quad.reparentTo(self.p3dobject) self.quad.reparentTo(self.gmap.tiles_quads_node) self.quad.setPos(self.p3dobject.getPos()) self.quad.hide() #pid of the player that owns the tile self.pawner=None self.ts_pawn=TextureStage('ts_pawn') self.ts_pawn.setMode(TextureStage.MReplace) self.ts_pawn.setSort(2) #selection self.is_selected=False self.ts_selected=TextureStage('ts_selected') self.ts_selected.setMode(TextureStage.MReplace) self.ts_selected.setSort(3) #highlight self.is_highlighted=False self.ts_highlighted=TextureStage('ts_highlighted') self.ts_highlighted.setMode(TextureStage.MDecal) self.ts_highlighted.setSort(4) def __repr__(self): return 'GTile{eid:'+str(self.eid)+'\n\ x/y:'+str(self.x)+'/'+str(self.y)+'\n\ pawner:'+str(self.pawner)+'\n\ selected:'+str(self.is_selected)+'\n\ highlighted:'+str(self.is_highlighted)+'\n\ }' def __str__(self): return self.__repr__() @staticmethod def load_resources(): #dict of texture GTile.resources={ 'quad':lambda:loader.loadModel('data/models/tiles/tile.egg'), } GTile.textures={ 'highlighted':loader.loadTexture('data/models/tiles/tile.highlighted.tex.png'), 'selected':loader.loadTexture('data/models/tiles/tile.selected.tex.png'), 'pawn-0':loader.loadTexture('data/models/tiles/tile.pawned.black.tex.png'), 'pawn-1':loader.loadTexture('data/models/tiles/tile.pawned.white.tex.png'), } @property def left_tile(self): '''property getter''' if self.x>0:return self.gmap.tile_matrix[self.x-1][self.y] return None @property def lower_tile(self): '''property getter''' if self.y>0:return self.gmap.tile_matrix[self.x][self.y-1] return None @property def right_tile(self): '''property getter''' if self.x<self.gmap.resx-1:return self.gmap.tile_matrix[self.x+1][self.y] return None @property def upper_tile(self): '''property getter''' if self.y<self.gmap.resy-1:return self.gmap.tile_matrix[self.x][self.y+1] return None @property def neighbors(self): '''property getter''' return filter(lambda t:t!=None,[self.left_tile,self.lower_tile,self.right_tile,self.upper_tile]) @property def wall(self): ''' returns a list of all tiles that form a wall connected to this tile. a tile with no pawner doesn't belong to any wall. ''' if self.pawner==None: return [] wall=[] fringe=[self] visited={} while len(fringe): t=fringe.pop(0) if t.pawner==self.pawner: wall.append(t) visited[t]=1 fringe.extend([n for n in t.neighbors if n.pawner==self.pawner and n not in visited]) def change_pawner(self,data): #out('tile '+str(self.eid)+' set to '+str(data['owner'])) if self.pawner!=data['pawner']: self.pawner=data['pawner'] if self.pawner==None: self.quad.clearTexture(self.ts_pawn) if not (self.is_selected or self.is_highlighted): self.quad.hide() else: self.quad.setTexture(self.ts_pawn,self.textures['pawn-'+str(self.pawner)]) self.quad.show() def set_highlighted(self): #out('tile.eid='+str(self.eid)) self.is_highlighted=True self.quad.show() self.quad.setTexture(self.ts_highlighted,self.textures['highlighted']) def unset_highlighted(self): self.is_highlighted=False self.quad.clearTexture(self.ts_highlighted) if not (self.is_selected or self.pawner!=None): self.quad.hide() def set_selected(self): self.is_selected=True self.quad.show() self.quad.setTexture(self.ts_selected,self.textures['selected']) def unset_selected(self): self.is_selected=False self.quad.clearTexture(self.ts_selected) if not (self.is_highlighted or self.pawner!=None): self.quad.hide() @property def center_pos(self): return self.p3dobject.getPos()
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
def load(self): Entity.load(self) self.setPos(self.cEntity.getOrigin()) self.setHpr(self.cEntity.getAngles()) self.setColorScale(self.getEntityValueColor("_light") * 2, 1) self.hide(CIGlobals.ShadowCameraBitmask) beamAndHalo = loader.loadModel("phase_14/models/misc/light_beam_and_halo.bam") # Blend between halo and beam spotlightroot = self.attachNewNode('spotlightRoot') spotlightroot.setP(90) self.spotlight = beamAndHalo.find("**/beam") self.spotlight.setBillboardAxis() self.spotlight.reparentTo(spotlightroot) self.spotlight.setDepthWrite(False) ts = TextureStage('spotlight') ts.setMode(TextureStage.MAdd) state = self.spotlight.node().getGeomState(0) attr = TextureAttrib.make() attr = attr.addOnStage(ts, loader.loadTexture("phase_14/maps/glow_test02.png"), 1) state = state.setAttrib(attr) self.spotlight.node().setGeomState(0, state) self.halo = CIGlobals.makeSprite( "halo", loader.loadTexture("phase_14/maps/light_glow03.png"), 5, True) self.halo.reparentTo(self) beamAndHalo.removeNode() self.spotlightLength = self.getEntityValueFloat("SpotlightLength") / 16.0 self.spotlightWidth = self.getEntityValueFloat("SpotlightWidth") / 16.0 entPos = self.getPos() spotDir = self.getQuat().getForward() # User specified a max length, but clip that length so the spot effect doesn't appear to go through a floor or wall traceEnd = entPos + (spotDir * self.spotlightLength) endPos = self.bspLoader.clipLine(entPos, traceEnd) realLength = (endPos - entPos).length() self.spotlight.setSz(realLength) self.spotlight.setSx(self.spotlightWidth) self.spotlightDir = spotDir self.negSpotlightDir = -self.spotlightDir # Full beam, no halo self.setBeamHaloFactor(1.0) self.reparentTo(render) # Only update the spotlight if the object passes the Cull test. self.node().setFinal(True) clbk = CallbackNode('point_spotlight_callback') clbk.setCullCallback(CallbackObject.make(self.__spotlightThink)) clbk.setBounds(BoundingSphere((0, 0, 0), 0)) self.callback = self.attachNewNode(clbk) self.callback.hide(CIGlobals.ReflectionCameraBitmask) self.callback.hide(CIGlobals.ShadowCameraBitmask)
def enterIntro(self): helper.hide_cursor() cm = CardMaker("fade") cm.setFrameFullscreenQuad() self.gfLogo = NodePath(cm.generate()) self.gfLogo.setTransparency(TransparencyAttrib.MAlpha) gfLogotex = loader.loadTexture('GrimFangLogo.png') gfLogots = TextureStage('gfLogoTS') gfLogots.setMode(TextureStage.MReplace) self.gfLogo.setTexture(gfLogots, gfLogotex) self.gfLogo.setY(-50) self.gfLogo.reparentTo(render2d) self.gfLogo.hide() self.pandaLogo = NodePath(cm.generate()) self.pandaLogo.setTransparency(TransparencyAttrib.MAlpha) pandaLogotex = loader.loadTexture('Panda3DLogo.png') pandaLogots = TextureStage('pandaLogoTS') pandaLogots.setMode(TextureStage.MReplace) self.pandaLogo.setTexture(pandaLogots, pandaLogotex) self.pandaLogo.setY(-50) self.pandaLogo.reparentTo(render2d) self.pandaLogo.hide() gfFadeInInterval = LerpColorScaleInterval( self.gfLogo, 2, LVecBase4f(0.0,0.0,0.0,1.0), LVecBase4f(0.0,0.0,0.0,0.0)) gfFadeOutInterval = LerpColorScaleInterval( self.gfLogo, 2, LVecBase4f(0.0,0.0,0.0,0.0), LVecBase4f(0.0,0.0,0.0,1.0)) p3dFadeInInterval = LerpColorScaleInterval( self.pandaLogo, 2, LVecBase4f(0.0,0.0,0.0,1.0), LVecBase4f(0.0,0.0,0.0,0.0)) p3dFadeOutInterval = LerpColorScaleInterval( self.pandaLogo, 2, LVecBase4f(0.0,0.0,0.0,0.0), LVecBase4f(0.0,0.0,0.0,1.0)) self.fadeInOut = Sequence( Func(self.pandaLogo.show), p3dFadeInInterval, Wait(1.0), p3dFadeOutInterval, Wait(0.5), Func(self.pandaLogo.hide), Func(self.gfLogo.show), gfFadeInInterval, Wait(1.0), gfFadeOutInterval, Wait(0.5), Func(self.gfLogo.hide), Func(self.request, "Menu"), Func(helper.show_cursor), name="fadeInOut") self.fadeInOut.start()
class GUnit(GEntity): def __init__(self,conf): GEntity.__init__(self,conf) self.p3dobject.reparentTo(self.gmap.units_node) self.p3dobject.setTransparency(TransparencyAttrib.MAlpha) #to be put under condition for non pickable units (bonuses npc for instance) self.p3dobject.setTag('GUnit-pickable','1') self.p3dobject.setPos(self.gmap.root.find('**/tile_'+str(conf['tileid'])),0,0,0) #supposedly already a float, but will screw up if not, so just making sure. self.move_speed=float(conf['move_speed']) self.path=[] self.popout_when_move_over=False self.pid=conf['pid'] #highlight self.ts_highlighted=TextureStage('ts_highlighted') self.ts_highlighted.setMode(TextureStage.MDecal) self.ts_highlighted.setSort(2) #highlight self.ts_selected=TextureStage('ts_selected') self.ts_selected.setMode(TextureStage.MDecal) self.ts_selected.setSort(3) @staticmethod def load_resources(): GUnit.textures={ 'highlighted':loader.loadTexture('data/models/highlighted.tex.png'), 'selected':loader.loadTexture('data/models/selected.tex.png'), } def dispose(self): '''del method''' GEntity.dispose(self) self.popout_sequence.finish() del self.popout_sequence def add_path(self,data): ''' adds tile to pass by. ''' #check for data completeness if not 'path' in data: out('WARNING in GUnit.add_path: incomplete data:\n'+str(data)) return elif not isinstance(data['path'],list): out('WARNING in GUnit.add_path: invalid data:\n'+str(data)) return #data considered valid self.path.extend([self.instances[eid] for eid in data['path']]) if not self.update_move in update_list: update_list.append(self.update_move) #out('GUnit.add_path:'+str(data)) def finish_move_to(self,data): '''triggered by server side unit, to indicate the need to popout at end of move.''' out('GUnit.finish_move_to()'+str(data)) if self.update_move in update_list: self.popout_when_move_over=True else: self.popout() def popout(self): '''sets up the popout animation at end of unit's mission''' scale=self.p3dobject.scaleInterval(.5,(.1,.1,.1)) finish=Func(lambda:dispose_list.append(self)) self.popout_sequence=Sequence(scale,finish) self.popout_sequence.start() def set_highlighted(self): self.p3dobject.setTexture(self.ts_highlighted,self.textures['highlighted']) def unset_highlighted(self): self.p3dobject.clearTexture(self.ts_highlighted) def set_selected(self): self.p3dobject.setTexture(self.ts_selected,self.textures['selected']) def unset_selected(self): self.p3dobject.clearTexture(self.ts_selected) def update_move(self): '''called every frame during while a move.''' if len(self.path)==0: out('WARNING in GUnit.update_move: path is empty, but method still called. removing it.') update_list.remove(self.update_move) return if not hasattr(self,'move_interval'): #start moving #first 3 args=model,duration,pos, the duration=1/... is relative to server side tile side size self.move_interval=LerpPosInterval(self.p3dobject, (1/(self.move_speed*ConfigVariableDouble('clock-frame-rate').getValue())), self.path[0].p3dobject.getPos(), name='interval_unit_move_'+str(self.eid) ) self.p3dobject.lookAt(self.path[0].p3dobject.getPos()) self.p3dobject.loop('run') self.move_interval.start() else: #is move ~over ? #t=self.move_interval.getT() #d=self.move_interval.getDuration() #d=d-t d=dist3(self.p3dobject,self.path[0].p3dobject) #out('client '+str(t*100./d)+'%') #arrived if d<self.move_speed: #out('client '+str(self.path[0].eid)+'@'+str(self.frame_no)) self.p3dobject.setPos(self.path[0].p3dobject,0,0,0) self.path.pop(0) if len(self.path)==0: self.p3dobject.stop() self.move_interval.finish() del self.move_interval update_list.remove(self.update_move) if self.popout_when_move_over: self.popout() else: #first 3 args=model,duration,pos self.move_interval.finish() self.move_interval=LerpPosInterval(self.p3dobject, (1/(self.move_speed*ConfigVariableDouble('clock-frame-rate').getValue())), self.path[0].p3dobject.getPos(), name='interval_unit_move_'+str(self.eid) ) self.p3dobject.lookAt(self.path[0].p3dobject.getPos()) self.move_interval.start()
class PlayerBase(DirectObject): def __init__(self): # Player Model setup self.player = Actor("Player", {"Run":"Player-Run", "Sidestep":"Player-Sidestep", "Idle":"Player-Idle"}) self.player.setBlend(frameBlend = True) self.player.setPos(0, 0, 0) self.player.pose("Idle", 0) self.player.reparentTo(render) self.player.hide() self.footstep = base.audio3d.loadSfx('footstep.ogg') self.footstep.setLoop(True) base.audio3d.attachSoundToObject(self.footstep, self.player) # Create a brush to paint on the texture splat = PNMImage("../data/Splat.png") self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1) CamMask = BitMask32.bit(0) AvBufMask = BitMask32.bit(1) self.avbuf = None if base.win: self.avbufTex = Texture('avbuf') self.avbuf = base.win.makeTextureBuffer('avbuf', 256, 256, self.avbufTex, True) cam = Camera('avbuf') cam.setLens(base.camNode.getLens()) self.avbufCam = base.cam.attachNewNode(cam) dr = self.avbuf.makeDisplayRegion() dr.setCamera(self.avbufCam) self.avbuf.setActive(False) self.avbuf.setClearColor((1, 0, 0, 1)) cam.setCameraMask(AvBufMask) base.camNode.setCameraMask(CamMask) # avbuf renders everything it sees with the gradient texture. tex = loader.loadTexture('gradient.png') np = NodePath('np') np.setTexture(tex, 100) np.setColor((1, 1, 1, 1), 100) np.setColorScaleOff(100) np.setTransparency(TransparencyAttrib.MNone, 100) np.setLightOff(100) cam.setInitialState(np.getState()) #render.hide(AvBufMask) # Setup a texture stage to paint on the player self.paintTs = TextureStage('paintTs') self.paintTs.setMode(TextureStage.MDecal) self.paintTs.setSort(10) self.paintTs.setPriority(10) self.tex = Texture('paint_av_%s'%id(self)) # Setup a PNMImage that will hold the paintable texture of the player self.imageSizeX = 64 self.imageSizeY = 64 self.p = PNMImage(self.imageSizeX, self.imageSizeY, 4) self.p.fill(1) self.p.alphaFill(0) self.tex.load(self.p) self.tex.setWrapU(self.tex.WMClamp) self.tex.setWrapV(self.tex.WMClamp) # Apply the paintable texture to the avatar self.player.setTexture(self.paintTs, self.tex) # team self.playerTeam = "" # A lable that will display the players team self.lblTeam = DirectLabel( scale = 1, pos = (0, 0, 3), frameColor = (0, 0, 0, 0), text = "TEAM", text_align = TextNode.ACenter, text_fg = (0,0,0,1)) self.lblTeam.reparentTo(self.player) self.lblTeam.setBillboardPointEye() # basic player values self.maxHits = 3 self.currentHits = 0 self.isOut = False self.TorsorControl = self.player.controlJoint(None,"modelRoot","Torsor") # setup the collision detection # wall and object collision self.playerSphere = CollisionSphere(0, 0, 1, 1) self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision%d"%id(self))) self.playerCollision.node().addSolid(self.playerSphere) base.pusher.addCollider(self.playerCollision, self.player) base.cTrav.addCollider(self.playerCollision, base.pusher) # foot (walk) collision self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision%d"%id(self))) self.playerFootRay.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -1)) self.playerFootRay.node().setIntoCollideMask(0) self.lifter = CollisionHandlerFloor() self.lifter.addCollider(self.playerFootRay, self.player) base.cTrav.addCollider(self.playerFootRay, self.lifter) # Player weapon setup self.gunAttach = self.player.exposeJoint(None, "modelRoot", "WeaponSlot_R") self.color = LPoint3f(1, 1, 1) self.gun = Gun(id(self)) self.gun.reparentTo(self.gunAttach) self.gun.hide() self.gun.setColor(self.color) self.hud = None # Player controls setup self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} # screen sizes self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 self.mouseSpeedX = 0.1 self.mouseSpeedY = 0.1 # AI controllable variables self.AIP = 0.0 self.AIH = 0.0 self.movespeed = 5.0 self.userControlled = False self.accept("Bulet-hit-playerCollision%d" % id(self), self.hit) self.accept("window-event", self.recalcAspectRatio) def runBase(self): self.player.show() self.gun.show() taskMgr.add(self.move, "moveTask%d"%id(self), priority=-4) def stopBase(self): taskMgr.remove("moveTask%d"%id(self)) self.ignoreAll() self.gun.remove() self.footstep.stop() base.audio3d.detachSound(self.footstep) self.player.delete() def setKey(self, key, value): self.keyMap[key] = value def setPos(self, pos): self.player.setPos(pos) def setColor(self, color=LPoint3f(0,0,0)): self.color = color self.gun.setColor(color) c = (color[0], color[1], color[2], 1.0) self.lblTeam["text_fg"] = c def setTeam(self, team): self.playerTeam = team self.lblTeam["text"] = team def shoot(self, shotVec=None): self.gun.shoot(shotVec) if self.hud != None: self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition) def reload(self): self.gun.reload() if self.hud != None: self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition) def recalcAspectRatio(self, window): self.winXhalf = window.getXSize() / 2 self.winYhalf = window.getYSize() / 2 def hit(self, entry, color): self.currentHits += 1 # Create a brush to paint on the texture splat = PNMImage("../data/Splat.png") splat = splat * LColorf(color[0], color[1], color[2], 1.0) self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1) self.paintAvatar(entry) if self.currentHits >= self.maxHits: base.messenger.send("GameOver-player%d" % id(self)) self.isOut = True def __paint(self, s, t): """ Paints a point on the avatar at texture coordinates (s, t). """ x = (s * self.p.getXSize()) y = ((1.0 - t) * self.p.getYSize()) # Draw in color directly on the avatar p1 = PNMPainter(self.p) p1.setPen(self.colorBrush) p1.drawPoint(x, y) self.tex.load(self.p) self.tex.setWrapU(self.tex.WMClamp) self.tex.setWrapV(self.tex.WMClamp) self.paintDirty = True def paintAvatar(self, entry): """ Paints onto an avatar. Returns true on success, false on failure (because there are no avatar pixels under the mouse, for instance). """ # First, we have to render the avatar in its false-color # image, to determine which part of its texture is under the # mouse. if not self.avbuf: return False #mpos = base.mouseWatcherNode.getMouse() mpos = entry.getSurfacePoint(self.player) ppos = entry.getSurfacePoint(render) self.player.showThrough(BitMask32.bit(1)) self.avbuf.setActive(True) base.graphicsEngine.renderFrame() self.player.show(BitMask32.bit(1)) self.avbuf.setActive(False) # Now we have the rendered image in self.avbufTex. if not self.avbufTex.hasRamImage(): print "Weird, no image in avbufTex." return False p = PNMImage() self.avbufTex.store(p) ix = int((1 + mpos.getX()) * p.getXSize() * 0.5) iy = int((1 - mpos.getY()) * p.getYSize() * 0.5) x = 1 if ix >= 0 and ix < p.getXSize() and iy >= 0 and iy < p.getYSize(): s = p.getBlue(ix, iy) t = p.getGreen(ix, iy) x = p.getRed(ix, iy) if x > 0.5: # Off the avatar. return False # At point (s, t) on the avatar's map. self.__paint(s, t) return True def move(self, task): if self is None: return task.done if self.userControlled: if not base.mouseWatcherNode.hasMouse(): return task.cont self.pointer = base.win.getPointer(0) mouseX = self.pointer.getX() mouseY = self.pointer.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): p = self.TorsorControl.getP() + (mouseY - self.winYhalf) * self.mouseSpeedY if p <-80: p = -80 elif p > 90: p = 90 self.TorsorControl.setP(p) h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX if h <-360: h = 360 elif h > 360: h = -360 self.player.setH(h) else: self.TorsorControl.setP(self.AIP) self.player.setH(self.AIH) forward = self.keyMap["forward"] != 0 backward = self.keyMap["backward"] != 0 if self.keyMap["left"] != 0: if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward): self.player.loop("Sidestep") self.player.setPlayRate(5, "Sidestep") self.player.setX(self.player, self.movespeed * globalClock.getDt()) elif self.keyMap["right"] != 0: if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward): self.player.loop("Sidestep") self.player.setPlayRate(5, "Sidestep") self.player.setX(self.player, -self.movespeed * globalClock.getDt()) else: self.player.stop("Sidestep") if forward: if self.player.getCurrentAnim() != "Run": self.player.loop("Run") self.player.setPlayRate(5, "Run") self.player.setY(self.player, -self.movespeed * globalClock.getDt()) elif backward: if self.player.getCurrentAnim() != "Run": self.player.loop("Run") self.player.setPlayRate(-5, "Run") self.player.setY(self.player, self.movespeed * globalClock.getDt()) else: self.player.stop("Run") if not (self.keyMap["left"] or self.keyMap["right"] or self.keyMap["forward"] or self.keyMap["backward"] or self.player.getCurrentAnim() == "Idle"): self.player.loop("Idle") self.footstep.stop() else: self.footstep.play() return task.cont
def applyGlow(np, glowTex): ts = TextureStage("glow") ts.setMode(TextureStage.MGlow) np.setTexture(ts, glowTex)
def generateNode(self): self.destroy() self.node = NodePath('gameobjectnode') self.node.setTwoSided(True) self.node.reparentTo(self.parent.node) if self.properties['avoidable'] == True: self.node.setTag("avoidable", 'true') else: self.node.setTag("avoidable", 'false') #setting scripting part self.node.setTag("onWalked", self.onWalked) self.node.setTag("onPicked", self.onPicked) #set unique id self.node.setTag("id", self.properties['id']) tex = loader.loadTexture(resourceManager.getResource(self.properties['url'])+'.png') tex.setWrapV(Texture.WM_clamp) tex.setWrapU(Texture.WM_clamp) #this is true pixel art #change to FTLinear for linear interpolation between pixel colors tex.setMagfilter(Texture.FTNearest) tex.setMinfilter(Texture.FTNearest) xorig = tex.getOrigFileXSize() / self.baseDimension yorig = tex.getOrigFileYSize() / self.baseDimension xscaled = (tex.getOrigFileXSize() / self.baseDimension) * self.properties['scale'] yscaled = (tex.getOrigFileYSize() / self.baseDimension) * self.properties['scale'] self.node.setTag("xscaled", str(xscaled)) self.node.setTag("yscaled", str(yscaled)) cm = CardMaker("tileobject") cm.setFrame(0,xorig,0,yorig) ts = TextureStage('ts') ts.setMode(TextureStage.MDecal) # distinguish between 3d collisions (for objects with an height and sensible self.properties['inclination']) # and 2d collisions for plain sprites if self.properties['walkable'] == 'false': if self.properties['collisionmode'] == "3d": #must handle differently objects which are small and big if xscaled < 1: self.collisionTube = CollisionBox(LPoint3f(0.5 - xscaled/2 - self.properties['offsetwidth'],0,0),LPoint3f(0.5 + xscaled/2 + self.properties['offsetwidth'],0.1,0.3 + self.properties['offsetheight'])) if xscaled >= 1: self.collisionTube = CollisionBox(LPoint3f(0 - self.properties['offsetwidth'],0,0),LPoint3f(xscaled + self.properties['offsetwidth'],0.1,0.3 + self.properties['offsetheight'])) self.collisionNode = CollisionNode('objectSphere') self.collisionNode.addSolid(self.collisionTube) self.collisionNodeNp = self.node.attachNewNode(self.collisionNode) self.collisionNodeNp.setX(self.properties['offsethorizontal']) self.collisionNodeNp.setZ(self.properties['offsetvertical']) self.collisionNodeNp.setX(self.collisionNodeNp.getX()+self.properties['offsetcollisionh']) self.collisionNodeNp.setZ(self.collisionNodeNp.getZ()+self.properties['offsetcollisionv']+0.1) if main.editormode: self.collisionNodeNp.show() elif self.properties['collisionmode'] == "2d": #must handle differently objects which are small and big if xscaled < 1: self.collisionTube = CollisionBox(LPoint3f(0.5 - xscaled/2,0,0),LPoint3f(0.5 + xscaled/2,yscaled,0.3)) if xscaled >= 1: self.collisionTube = CollisionBox(LPoint3f(0,0,0),LPoint3f(xscaled,yscaled,0.3)) self.collisionNode = CollisionNode('objectSphere') self.collisionNode.addSolid(self.collisionTube) self.collisionNodeNp = self.node.attachNewNode(self.collisionNode) self.collisionNodeNp.setP(-(270-int(self.properties['inclination']))) self.collisionNodeNp.setX(self.properties['offsethorizontal']) self.collisionNodeNp.setZ(self.properties['offsetvertical']) self.collisionNodeNp.setX(self.collisionNodeNp.getX()+self.properties['offsetcollisionh']) self.collisionNodeNp.setZ(self.collisionNodeNp.getZ()+self.properties['offsetcollisionv']+0.1) if main.editormode: self.collisionNodeNp.show() geomnode = NodePath(cm.generate()) if xscaled >= 1: geomnode.setX(0) if xscaled < 1: geomnode.setX(0.5 - xscaled/2) geomnode.setScale(self.properties['scale']) geomnode.setX(geomnode.getX()+self.properties['offsethorizontal']) geomnode.setZ(geomnode.getZ()+self.properties['offsetvertical']) geomnode.setY(-self.properties['elevation']) geomnode.setP(-(360-int(self.properties['inclination']))) geomnode.setTexture(tex) geomnode.setTransparency(TransparencyAttrib.MAlpha) geomnode.reparentTo(self.node)
def generateNode(self, name, DB, parentNode): log.debug("Setting up " + name) bodyEntity = sandbox.createEntity() component = CelestialComponent() if DB["type"] == "solid": body = Body(name) elif DB["type"] == "moon": body = Body(name) body.kind = "moon" elif DB["type"] == "star": body = Star(name) body.absoluteM = DB["absolute magnitude"] body.spectral = DB["spectral"] elif DB["type"] == "barycenter": body = BaryCenter(name) component.kind = TYPES[DB["type"]] if DB["type"] != "barycenter": component.mass = DB["mass"] body.radius = DB["radius"] body.rotation = DB["rotation"] if "orbit" in DB: component.orbit = DB["orbit"] body.period = DB["period"] # body.setPos(self.get2DBodyPosition(component, universals.day)) component.truePos = self.get2DBodyPosition(component, universals.day) if name == "Earth": # universals.spawn = component.truePos + LPoint3d(0, 6671, 0) universals.spawn = component.truePos + LPoint3d(6671, 0, 0) if parentNode == universals.solarSystemRoot: universals.defaultSOIid = bodyEntity.id component.soi = 0 elif DB["type"] != "star" or DB["type"] != "barycenter": component.soi = self.getSOI(component.mass, self.bodies[0].mass, component.orbit["a"]) body.type = DB["type"] body.reparentTo(parentNode) component.nodePath = body self.bodies.append(component) bodyEntity.addComponent(component) if universals.runClient and DB["type"] == "star": component = graphicsComponents.RenderComponent() # component.mesh = NodePath(name) # self.sphere.copyTo(component.mesh) # component.mesh = shapeGenerator.Sphere(body.radius, 128, name) component.mesh = shapeGenerator.Sphere(body.radius, 64, name) # component.mesh.setScale(body.radius) component.mesh.reparentTo(sandbox.base.render) sandbox.send("makePickable", [component.mesh]) # texture = sandbox.base.loader.loadTexture('planets/' + DB['texture']) # texture.setMinfilter(Texture.FTLinearMipmapLinear) # ts1 = TextureStage('textures1') # ts1.setMode(TextureStage.MGlow) # component.mesh.setTexture(ts1, texture) # component.mesh.setTexture(texture, 1) component.light = component.mesh.attachNewNode(PointLight("sunPointLight")) component.light.node().setColor(Vec4(1, 1, 1, 1)) sandbox.base.render.setLight(component.light) bodyEntity.addComponent(component) # Shader test componentStar = graphicsComponents.StarRender() componentStar.noise_texture = Texture("noise") componentStar.noise_texture.setup2dTexture() img = PNMImage(1024, 1024) for y in range(1024): for x in range(1024): img.setXel(x, y, componentStar.noise.noise(x, y)) # print componentStar.noise.noise(x, y) componentStar.noise_texture.load(img) # componentStar.noise_texture.write('test.png') # component.mesh.setTexture(componentStar.noise_texture, 1) texture = sandbox.base.loader.loadTexture("planets/" + DB["texture"]) ts1 = TextureStage("textures1") ts1.setMode(TextureStage.MGlow) component.mesh.setTexture(ts1, componentStar.noise_texture) # component.mesh.setTexture(ts1, texture) component.mesh.setShaderInput("time", universals.get_day_in_seconds()) shaders = Shader.load(Shader.SLGLSL, "vortexVertex.glsl", "starFrag.glsl") component.mesh.setShader(shaders) sandbox.send("makePickable", [component.mesh]) if universals.runClient and (DB["type"] == "solid" or DB["type"] == "moon"): component = graphicsComponents.RenderComponent() # component.mesh = shapeGenerator.Sphere(body.radius, 128, name) # component.mesh = shapeGenerator.Sphere(body.radius, 64, name) component.mesh = surface_mesh.make_planet(name=name, scale=body.radius) # sandbox.send('makePickable', [component.mesh]) sandbox.send("makePickable", [component.mesh.node_path]) # component.mesh.setScale(body.radius) component.mesh.reparent_to(sandbox.base.render) # Doing world text text = TextNode("node name") text.setText(name) # textNodePath = component.mesh.attachNewNode(text) textNodePath = component.mesh.node_path.attachNewNode(text) textNodePath.setScale(0.07) component.mesh.set_textures(DB["texture"], night_path=DB["night"], gloss_path=DB["spec"]) component.mesh.set_ambient(1, 1, 1, 1) component.mesh.set_diffuse(1, 1, 1, 1) component.mesh.set_specular(1, 1, 1, 1) component.mesh.set_shininess(100) """if '#' in DB['texture']: component.mesh.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldPosition) component.mesh.setTexProjector(TextureStage.getDefault(), sandbox.base.render, component.mesh) component.mesh.setTexScale(TextureStage.getDefault(), 1, 1, -1) component.mesh.setTexHpr(TextureStage.getDefault(), 90, -18, 90) #self.mesh.setHpr(0, 90, 0) texture = loader.loadCubeMap('planets/' + DB['texture']) else: texture = sandbox.base.loader.loadTexture('planets/' + DB['texture']) #texture.setMinfilter(Texture.FTLinearMipmapLinear) component.mesh.setTexture(texture, 1)""" """if "atmosphere" in DB: component.atmosphere = shapeGenerator.Sphere(-1, 128) component.atmosphere.reparentTo(render) component.atmosphere.setScale(body.radius * 1.025) outerRadius = component.atmosphere.getScale().getX() scale = 1 / (outerRadius - component.body.getScale().getX()) component.atmosphere.setShaderInput("fOuterRadius", outerRadius) component.atmosphere.setShaderInput("fInnerRadius", component.mesh.getScale().getX()) component.atmosphere.setShaderInput("fOuterRadius2", outerRadius * outerRadius) component.atmosphere.setShaderInput("fInnerRadius2", component.mesh.getScale().getX() * component.mesh.getScale().getX()) component.atmosphere.setShaderInput("fKr4PI", 0.000055 * 4 * 3.14159) component.atmosphere.setShaderInput("fKm4PI", 0.000015 * 4 * 3.14159) component.atmosphere.setShaderInput("fScale", scale) component.atmosphere.setShaderInput("fScaleDepth", 0.25) component.atmosphere.setShaderInput("fScaleOverScaleDepth", scale / 0.25) # Currently hard coded in shader component.atmosphere.setShaderInput("fSamples", 10.0) component.atmosphere.setShaderInput("nSamples", 10) # These do sunsets and sky colors # Brightness of sun ESun = 15 # Reyleight Scattering (Main sky colors) component.atmosphere.setShaderInput("fKrESun", 0.000055 * ESun) # Mie Scattering -- Haze and sun halos component.atmosphere.setShaderInput("fKmESun", 0.000015 * ESun) # Color of sun component.atmosphere.setShaderInput("v3InvWavelength", 1.0 / math.pow(0.650, 4), 1.0 / math.pow(0.570, 4), 1.0 / math.pow(0.465, 4)) #component.atmosphere.setShader(Shader.load("atmo.cg"))""" bodyEntity.addComponent(component) log.info(name + " set Up") if "bodies" in DB: for bodyName, bodyDB in DB["bodies"].items(): self.generateNode(bodyName, bodyDB, body)
def __init__(self): """Start the app.""" self.base = ShowBase() self.base.disableMouse() filters = CommonFilters(self.base.win, self.base.cam) filters.setBloom(blend=(0, 0, 0, 1)) self.base.render.setShaderAuto( BitMask32.allOn() & ~BitMask32.bit(Shader.BitAutoShaderGlow)) ts = TextureStage('ts') ts.setMode(TextureStage.MGlow) tex = self.base.loader.loadTexture('models/black.png') self.base.render.setTexture(ts, tex) self.terrain = Terrain(self.base.render, self.base.loader) minimap_size = 200 self.minimap = Minimap( self.base.win.makeDisplayRegion( 1 - minimap_size / self.base.win.getProperties().getXSize(), 1, 1 - minimap_size / self.base.win.getProperties().getYSize(), 1)) self.minimap.node_path.reparentTo(self.base.render) # self.light_nodes = self.set_lights() self.set_fog() self.key_state = dict.fromkeys(Object.values(config.key_map.character), False) self.set_key_state_handler() self.game_state = "pause" self.toggle_pause() self.selection = Selection(self.base.loader, self.terrain.geom_node) self.selection_text = OnscreenText( mayChange=True, scale=0.07, align=TextNode.ALeft, pos=(0.02 - self.base.getAspectRatio(), 1 - 0.07)) self.timer_text = OnscreenText(mayChange=True, scale=0.07, align=TextNode.ALeft, pos=(0.02 - self.base.getAspectRatio(), -1 + 0.02 + 0.07)) self.enemies = set() self.base.accept(config.key_map.utility.pause, self.toggle_pause) self.base.accept( "q", lambda: self.selection.advance_tower(self.base.loader)) self.base.accept("mouse1", self.player_click) self.base.cam.node().setCameraMask(BitMask32.bit(0)) self.base.setBackgroundColor(*config.map_params.colors.sky) self.player = Player() self.base.taskMgr.add(lambda task: self.terrain.start_up(), "start up") self.mouse_pos = (0.0, 0.0) self.base.taskMgr.add(self.move_player_task, "move_player_task") self.base.taskMgr.add(self.move_enemies_task, "move_enemies_task") self.base.taskMgr.add(self.player_select_task, "player_select_task") self.base.taskMgr.add(self.tower_task, "tower_task") self.base.taskMgr.add(self.check_end_game, "check_end_game_task") rand = Random() rand.seed(config.map_params.seed) self.base.taskMgr.doMethodLater(1, self.clock_task, 'clock_task', extraArgs=[rand]) self.rounds = 0 self.coin = 40
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])
def __init__(self, args): # Instance variables self.camPos = Vec3(0, 0, 0) self.faceVec = Vec2(0, 0) self.velocity = 0 self.episodeCounter = 0 self.episodeFrameCounter = 0 self.historyFrameCounter = 0 self.deviationCounter = 0 self.accSignal = 0 self.turnSignal = 0 self.signalGameFeedback = Event() self.signalPlayerReady = Event() self.lock = Lock() self.bufferFeedback = bytearray() self.signalShutdown = Event() self.recordVideo = args['record'] # Panda3D-related initialization # Car-view Camera base.camLens.setNear(0.05) base.camLens.setFov(70) # A fixed, top-view Camera _ = Camera("top_cam") topCam = render.attachNewNode(_) topCam.setName("top_cam") topCam.setPos(0, 0, 40) topCam.setHpr(0, -90, 0) dr = base.camNode.getDisplayRegion(0) dr.setActive(0) window = dr.getWindow() drTop = window.makeDisplayRegion(0.5, 1, 0, 0.5) drTop.setSort(dr.getSort()) drTop.setCamera(topCam) self.drCar = window.makeDisplayRegion(0, 0.5, 0.5, 1) self.drCar.setSort(dr.getSort()) self.drCar.setCamera(base.cam) # BulletWorld world = BulletWorld() world.setGravity(Vec3(0, 0, 0)) props = WindowProperties() props.setSize(1024, 768) base.win.requestProperties(props) # Floor shapeGround = BulletPlaneShape(Vec3(0, 0, 1), 0.1) nodeGround = BulletRigidBodyNode('Ground') nodeGround.addShape(shapeGround) npGround = render.attachNewNode(nodeGround) npGround.setPos(0, 0, -2) world.attachRigidBody(nodeGround) cmGround = CardMaker("Ground") cmGround.setFrame(-10, 10, -10, 10); npGroundTex = render.attachNewNode(cmGround.generate()) npGroundTex.reparentTo(npGround) ts = TextureStage("ts") ts.setMode(TextureStage.M_modulate) groundTexture = loader.loadTexture(args['map']) npGroundTex.setP(270) npGroundTex.setTexScale(ts, 1, 1) npGround.setTexture(ts, groundTexture) # Car shapeBox = BulletBoxShape(Vec3(0.5, 0.5, 0.5)) nodeBox = BulletRigidBodyNode('Box') nodeBox.setMass(1.0) nodeBox.addShape(shapeBox) self.npBox = render.attachNewNode(nodeBox) self.npBox.setPos(self.camPos) world.attachRigidBody(nodeBox) modelBox = loader.loadModel('models/box.egg') modelBox.flattenLight() modelBox.setScale(0.5) modelBox.reparentTo(self.npBox)
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
class Typist(object): TARGETS = { 'paper': { 'model': 'paper', 'textureRoot': 'Front', 'scale': Point3(0.85, 0.85, 1), 'hpr': Point3(0, 0, 0), } } def __init__(self, base, typewriterNP, underDeskClip, sounds): self.base = base self.sounds = sounds self.underDeskClip = underDeskClip self.typeIndex = 0 self.typewriterNP = typewriterNP self.rollerAssemblyNP = typewriterNP.find("**/roller assembly") assert self.rollerAssemblyNP self.rollerNP = typewriterNP.find("**/roller") assert self.rollerNP self.carriageNP = typewriterNP.find("**/carriage") assert self.carriageNP self.baseCarriagePos = self.carriageNP.getPos() self.carriageBounds = self.carriageNP.getTightBounds() self.font = base.loader.loadFont('Harting.ttf', pointSize=32) self.pnmFont = PNMTextMaker(self.font) self.fontCharSize, _, _ = fonts.measureFont(self.pnmFont, 32) print "font char size: ", self.fontCharSize self.pixelsPerLine = int(round(self.pnmFont.getLineHeight())) self.target = None """ panda3d.core.NodePath """ self.targetRoot = None """ panda3d.core.NodePath """ self.paperY = 0.0 """ range from 0 to 1 """ self.paperX = 0.0 """ range from 0 to 1 """ self.createRollerBase() self.tex = None self.texImage = None self.setupTexture() self.scheduler = Scheduler() task = self.base.taskMgr.add(self.tick, 'timerTask') task.setDelay(0.01) def tick(self, task): self.scheduler.tick(globalClock.getRealTime()) return task.cont def setupTexture(self): """ This is the overlay/decal/etc. which contains the typed characters. The texture size and the font size are currently tied together. :return: """ self.texImage = PNMImage(1024, 1024) self.texImage.addAlpha() self.texImage.fill(1.0) self.texImage.alphaFill(1.0) self.tex = Texture('typing') self.tex.setMagfilter(Texture.FTLinear) self.tex.setMinfilter(Texture.FTLinear) self.typingStage = TextureStage('typing') self.typingStage.setMode(TextureStage.MModulate) self.tex.load(self.texImage) # ensure we can quickly update subimages self.tex.setKeepRamImage(True) # temp for drawing chars self.chImage = PNMImage(*self.fontCharSize) def drawCharacter(self, ch, px, py): """ Draw a character onto the texture :param ch: :param px: paperX :param py: paperY :return: the paper-relative size of the character """ h = self.fontCharSize[1] if ch != ' ': # position -> pixel, applying margins x = int(self.tex.getXSize() * (px * 0.8 + 0.1)) y = int(self.tex.getYSize() * (py * 0.8 + 0.1)) # always draw onto the paper, to capture # incremental character overstrikes self.pnmFont.generateInto(ch, self.texImage, x, y) if False: #print ch,"to",x,y,"w=",g.getWidth() self.tex.load(self.texImage) else: # copy an area (presumably) encompassing the character g = self.pnmFont.getGlyph(ord(ch)) cx, cy = self.fontCharSize # a glyph is minimally sized and "moves around" in its text box # (think ' vs. ,), so it has been drawn somewhere relative to # the 'x' and 'y' we wanted. x += g.getLeft() y -= g.getTop() self.chImage.copySubImage( self.texImage, 0, 0, # from x, y, # to cx, cy # size ) self.tex.loadSubImage(self.chImage, x, y) # toggle for a typewriter that uses non-proportional spacing #w = self.paperCharWidth(g.getWidth()) w = self.paperCharWidth() else: w = self.paperCharWidth() return w, h def start(self): self.target = None self.setTarget('paper') self.hookKeyboard() def createRollerBase(self): """ The paper moves such that it is tangent to the roller. This nodepath keeps a coordinate space relative to that, so that the paper can be positioned from (0,0,0) to (0,0,1) to "roll" it along the roller. """ bb = self.rollerNP.getTightBounds() #self.rollerNP.showTightBounds() self.paperRollerBase = self.rollerAssemblyNP.attachNewNode( 'rollerBase') self.paperRollerBase.setHpr(0, -20, 0) print "roller:", bb rad = abs(bb[0].y - bb[1].y) / 2 center = Vec3(-(bb[0].x + bb[1].x) / 2 - 0.03, (bb[0].y - bb[1].y) / 2, (bb[0].z + bb[1].z) / 2) self.paperRollerBase.setPos(center) def setTarget(self, name): if self.target: self.target.removeNode() # load and transform the model target = self.TARGETS[name] self.target = self.base.loader.loadModel(target['model']) #self.target.setScale(target['scale']) self.target.setHpr(target['hpr']) # put it in the world self.target.reparentTo(self.paperRollerBase) rbb = self.rollerNP.getTightBounds() tbb = self.target.getTightBounds() rs = (rbb[1] - rbb[0]) ts = (tbb[1] - tbb[0]) self.target.setScale(rs.x / ts.x, 1, 1) # apply the texture self.targetRoot = self.target if 'textureRoot' in target: self.targetRoot = self.target.find("**/" + target['textureRoot']) assert self.targetRoot self.targetRoot.setTexture(self.typingStage, self.tex) #self.setupTargetClip() # reset self.paperX = self.paperY = 0. newPos = self.calcPaperPos(self.paperY) self.target.setPos(newPos) self.moveCarriage() def setupTargetClip(self): """ The target is fed in to the typewriter but until we invent "geom curling", it shouldn't be visible under the typewriter under the desk. The @underDeskClip node has a world-relative bounding box, which we can convert to the target-relative bounding box, and pass to a shader that can clip the nodes. """ shader = Shader.make( Shader.SLGLSL, """ #version 120 attribute vec4 p3d_MultiTexCoord0; attribute vec4 p3d_MultiTexCoord1; void main() { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_TexCoord[0] = p3d_MultiTexCoord0; gl_TexCoord[1] = p3d_MultiTexCoord1; } """, """ #version 120 uniform sampler2D baseTex; uniform sampler2D charTex; const vec4 zero = vec4(0, 0, 0, 0); const vec4 one = vec4(1, 1, 1, 1); const vec4 half = vec4(0.5, 0.5, 0.5, 0); void main() { vec4 baseColor = texture2D(baseTex, gl_TexCoord[0].st); vec4 typeColor = texture2D(charTex, gl_TexCoord[1].st); gl_FragColor = baseColor * typeColor; }""") self.target.setShader(shader) baseTex = self.targetRoot.getTexture() print "Base Texture:", baseTex self.target.setShaderInput("baseTex", baseTex) self.target.setShaderInput("charTex", self.tex) def hookKeyboard(self): """ Hook events so we can respond to keypresses. """ self.base.buttonThrowers[0].node().setKeystrokeEvent('keystroke') self.base.accept('keystroke', self.schedTypeCharacter) self.base.accept('backspace', self.schedBackspace) self.base.accept('arrow_up', lambda: self.schedAdjustPaper(-5)) self.base.accept('arrow_up-repeat', lambda: self.schedAdjustPaper(-1)) self.base.accept('arrow_down', lambda: self.schedAdjustPaper(5)) self.base.accept('arrow_down-repeat', lambda: self.schedAdjustPaper(1)) self.base.accept('arrow_left', lambda: self.schedAdjustCarriage(-1)) self.base.accept('arrow_left-repeat', lambda: self.schedAdjustCarriage(-1)) self.base.accept('arrow_right', lambda: self.schedAdjustCarriage(1)) self.base.accept('arrow_right-repeat', lambda: self.schedAdjustCarriage(1)) def paperCharWidth(self, pixels=None): if not pixels: pixels = self.fontCharSize[0] return float(pixels) / self.tex.getXSize() def paperLineHeight(self): return float(self.fontCharSize[1] * 1.2) / self.tex.getYSize() def schedScroll(self): if self.scheduler.isQueueEmpty(): self.schedRollPaper(1) self.schedResetCarriage() def schedBackspace(self): if self.scheduler.isQueueEmpty(): def doit(): if self.paperX > 0: self.schedAdjustCarriage(-1) self.scheduler.schedule(0.01, doit) def createMoveCarriageInterval(self, newX, curX=None): if curX is None: curX = self.paperX here = self.calcCarriage(curX) there = self.calcCarriage(newX) posInterval = LerpPosInterval(self.carriageNP, abs(newX - curX), there, startPos=here, blendType='easeIn') posInterval.setDoneEvent('carriageReset') def isReset(): self.paperX = newX self.base.acceptOnce('carriageReset', isReset) return posInterval def schedResetCarriage(self): if self.paperX > 0.1: self.sounds['pullback'].play() invl = self.createMoveCarriageInterval(0) self.scheduler.scheduleInterval(0, invl) def calcCarriage(self, paperX): """ Calculate where the carriage should be offset based on the position on the paper :param paperX: 0...1 :return: pos for self.carriageNP """ x = (0.5 - paperX) * 0.69 * 0.8 + 0.01 bb = self.carriageBounds return self.baseCarriagePos + Point3(x * (bb[1].x - bb[0].x), 0, 0) def moveCarriage(self): pos = self.calcCarriage(self.paperX) self.carriageNP.setPos(pos) def schedMoveCarriage(self, curX, newX): if self.scheduler.isQueueEmpty(): #self.scheduler.schedule(0.1, self.moveCarriage) invl = self.createMoveCarriageInterval(newX, curX=curX) invl.start() def schedAdjustCarriage(self, bx): if self.scheduler.isQueueEmpty(): def doit(): self.paperX = max( 0.0, min(1.0, self.paperX + bx * self.paperCharWidth())) self.moveCarriage() self.scheduler.schedule(0.1, doit) def calcPaperPos(self, paperY): # center over roller, peek out a little z = paperY * 0.8 - 0.5 + 0.175 bb = self.target.getTightBounds() return Point3(-0.5, 0, z * (bb[1].z - bb[0].z)) def createMovePaperInterval(self, newY): here = self.calcPaperPos(self.paperY) there = self.calcPaperPos(newY) posInterval = LerpPosInterval(self.target, abs(newY - self.paperY), there, startPos=here, blendType='easeInOut') posInterval.setDoneEvent('scrollDone') def isDone(): self.paperY = newY self.base.acceptOnce('scrollDone', isDone) return posInterval def schedAdjustPaper(self, by): if self.scheduler.isQueueEmpty(): def doit(): self.schedRollPaper(by) self.scheduler.schedule(0.1, doit) def schedRollPaper(self, by): """ Position the paper such that @percent of it is rolled over roller :param percent: :return: """ def doit(): self.sounds['scroll'].play() newY = min(1.0, max(0.0, self.paperY + self.paperLineHeight() * by)) invl = self.createMovePaperInterval(newY) invl.start() self.scheduler.schedule(0.1, doit) def schedTypeCharacter(self, keyname): # filter for visibility if ord(keyname) == 13: self.schedScroll() elif ord(keyname) >= 32 and ord(keyname) != 127: if self.scheduler.isQueueEmpty(): curX, curY = self.paperX, self.paperY self.typeCharacter(keyname, curX, curY) def typeCharacter(self, ch, curX, curY): newX = curX w, h = self.drawCharacter(ch, curX, curY) newX += w if ch != ' ': # alternate typing sound #self.typeIndex = (self.typeIndex+1) % 3 self.typeIndex = random.randint(0, 2) self.sounds['type' + str(self.typeIndex + 1)].play() else: self.sounds['advance'].play() if newX >= 1: self.sounds['bell'].play() newX = 1 self.schedMoveCarriage(self.paperX, newX) # move first, to avoid overtype self.paperX = newX
def __init__(self, name, bodyDB, isAtmo=False): '''We pass the name to the BaseObject, bodyDB will have vital info for us!''' NodePath.__init__(self, name) # Becuase the C++ Nodepath functins will not return any of these additions, we need a way to call our python extensions when using the C++ functions # Panda provides such a mechanism using the set/getPythonTag function. NodePath.setPythonTag(self, 'subclass', self) self.reparentTo(render) self.setPos(0, 0, 0) self.cubemap = False # Set up grpahic components self.mesh = loader.loadModel("planet_sphere") self.mesh.setShaderAuto() self.atmo = None if '#' in bodyDB['texture']: self.cubemap = True if self.cubemap: self.mesh.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldPosition) self.mesh.setTexProjector(TextureStage.getDefault(), render, self.mesh) self.mesh.setTexScale(TextureStage.getDefault(), 1, 1, -1) self.mesh.setTexHpr(TextureStage.getDefault(), 90, -18, 90) texture = loader.loadCubeMap(bodyDB['texture']) else: texture = loader.loadTexture(bodyDB['texture']) texture.setMinfilter(Texture.FTLinearMipmapLinear) self.mesh.setTexture(texture, 1) if "spec" in bodyDB: sts = TextureStage('spec texture stage') sts.setMode(TextureStage.MGloss) stexture = loader.loadTexture(bodyDB['spec']) self.mesh.setTexture(sts, stexture) if "glow" in bodyDB: gts = TextureStage('glow texture stage') gts.setMode(TextureStage.MGlow) gtexture = loader.loadTexture(bodyDB['glow']) self.mesh.setTexture(gts, gtexture) self.mesh.reparentTo(render) #Atmo! if isAtmo: #self.atmo = loader.loadModel("planet_sphere") self.atmo = loader.loadModel("solar_sky_sphere") self.atmo.reparentTo(render) self.atmo.setScale(1.025) outerRadius = self.atmo.getScale().getX() scale = 1/(outerRadius - self.mesh.getScale().getX()) self.atmo.setShaderInput("fOuterRadius", outerRadius) self.atmo.setShaderInput("fInnerRadius", self.mesh.getScale().getX()) self.atmo.setShaderInput("fOuterRadius2", outerRadius * outerRadius) self.atmo.setShaderInput("fInnerRadius2", self.mesh.getScale().getX() * self.mesh.getScale().getX()) self.atmo.setShaderInput("fKr4PI", 0.000055 * 4 * 3.14159) self.atmo.setShaderInput("fKm4PI", 0.000015 * 4 * 3.14159) self.atmo.setShaderInput("fScale", scale) self.atmo.setShaderInput("fScaleDepth", 0.5) self.atmo.setShaderInput("fScaleOverScaleDepth", scale/0.5) # Currently hardcoded in shader self.atmo.setShaderInput("fSamples", 10.0) self.atmo.setShaderInput("nSamples", 10) # These do sunsets and sky colors # Brightness of sun ESun = 15 # Reyleight Scattering (Main sky colors) self.atmo.setShaderInput("fKrESun", 0.000055 * ESun) # Mie Scattering -- Haze and sun halos self.atmo.setShaderInput("fKmESun", 0.000015 * ESun) # Color of sun self.atmo.setShaderInput("v3InvWavelength", 1.0 / math.pow(0.650, 4), 1.0 / math.pow(0.570, 4), 1.0 / math.pow(0.465, 4)) self.atmo.setShaderInput("v3CameraPos", base.camera.getPos().getX(), base.camera.getPos().getY(), base.camera.getPos().getZ()) # Light vector from center of planet. #lightv = light.getPos() lightv = base.bodies[0].mesh.getPos() lightdir = lightv / lightv.length() self.atmo.setShaderInput("v3LightPos", lightdir[0], lightdir[1], lightdir[2]) self.atmo.setShaderInput("fCameraHeight", base.camera.getPos().length()) self.atmo.setShaderInput("fCameraHeight2", base.camera.getPos().length()*base.camera.getPos().length()) self.atmo.setShaderInput("g", 0.90) self.atmo.setShaderInput("g2", 0.81) self.atmo.setShaderInput("float", 2) # All black #atmoShader = Shader.load(Shader.SLGLSL, "atmovertexshader.glsl", "atmofragmentshader.glsl") # None visible #atmoShader = Shader.load(Shader.SLGLSL, "SkyFromSpace.vert", "SkyFromSpace.frag") atmoShader = Shader.load("atmo.cg") self.atmo.setShader(atmoShader) # Initiate visual self.updateVisual(Task) taskMgr.add(self.updateVisual, 'planetRendering') self.setupRotation()