示例#1
0
    def _updateDebugNode(self):
        """ Internal method to generate new debug geometry. """
        mainNode = NodePath("DebugNodeInner")
        mainNode.setPos(self.position)
        lineNode = mainNode.attachNewNode("lines")

        inner = Globals.loader.loadModel("box")
        inner.setPos(-0.5, -0.5, 0.6)
        inner.flattenStrong()
        inner.reparentTo(mainNode)

        # Generate outer circles
        points1 = []
        points2 = []
        points3 = []
        for i in range(self.visualizationNumSteps + 1):
            angle = float(i) / float(
                self.visualizationNumSteps) * math.pi * 2.0
            points1.append(Vec3(0, math.sin(angle), math.cos(angle)))
            points2.append(Vec3(math.sin(angle), math.cos(angle), 0))
            points3.append(Vec3(math.sin(angle), 0, math.cos(angle)))

        self._createDebugLine(points1, False).reparentTo(lineNode)
        self._createDebugLine(points2, False).reparentTo(lineNode)
        self._createDebugLine(points3, False).reparentTo(lineNode)

        lineNode.setScale(self.radius)
        mainNode.flattenStrong()
        self.debugNode.node().removeAllChildren()
        mainNode.reparentTo(self.debugNode)
示例#2
0
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
示例#3
0
 def getStatic(self):
     """
     this makes a flattened version of the tree for faster rendering...
     """
     np = NodePath(self.node().copySubgraph())
     np.flattenStrong()
     return np
示例#4
0
    def _updateDebugNode(self):
        """ Internal method to generate new debug geometry. """
        mainNode = NodePath("DebugNodeInner")
        mainNode.setPos(self.position)
        lineNode = mainNode.attachNewNode("lines")

        inner = Globals.loader.loadModel("box")
        inner.setPos(-0.5, -0.5, 0.6)
        inner.flattenStrong()
        inner.reparentTo(mainNode)

        # Generate outer circles
        points1 = []
        points2 = []
        points3 = []
        for i in range(self.visualizationNumSteps + 1):
            angle = float(
                i) / float(self.visualizationNumSteps) * math.pi * 2.0
            points1.append(Vec3(0, math.sin(angle), math.cos(angle)))
            points2.append(Vec3(math.sin(angle), math.cos(angle), 0))
            points3.append(Vec3(math.sin(angle), 0, math.cos(angle)))

        self._createDebugLine(points1, False).reparentTo(lineNode)
        self._createDebugLine(points2, False).reparentTo(lineNode)
        self._createDebugLine(points3, False).reparentTo(lineNode)

        lineNode.setScale(self.radius)
        mainNode.flattenStrong()
        self.debugNode.node().removeAllChildren()
        mainNode.reparentTo(self.debugNode)
示例#5
0
def changeModel(newmodel):
    tempParent=NodePath('')
    newModel=loader.loadModel(newmodel)
    newModel.findAllMatches('**/+GeomNode').reparentTo(tempParent)
    tempParent.setScale(1.5/tempParent.getBounds().getRadius())
    tempParent.setPos(-tempParent.getBounds().getCenter())
    tempParent.flattenStrong()
    tempParent.find('**/+GeomNode').node().replaceNode(model.node())
示例#6
0
def DisplacementUVSphere(radius,
                         heightmap,
                         scale,
                         rings=5,
                         sectors=5,
                         inv_texture_u=False,
                         inv_texture_v=True):
    data = EggData()
    pool = EggVertexPool('pool')
    vertices = []
    data.addChild(pool)
    R = 1. / (rings)
    S = 1. / (sectors)
    for r in range(0, rings + 1):
        for s in range(0, sectors + 1):
            cos_s = cos(2 * pi * s * S + pi)
            sin_s = sin(2 * pi * s * S + pi)
            sin_r = sin(pi * r * R)
            cos_r = cos(pi * r * R)
            x = cos_s * sin_r
            y = sin_s * sin_r
            z = cos_r
            vertex = EggVertex()
            u = s * S
            v = r * R
            height = radius + heightmap.get_height_uv(u, v) * scale
            vertex.setPos(LPoint3d(x * height, y * height, z * height))
            if inv_texture_v:
                v = 1.0 - v
            if inv_texture_u:
                u = 1.0 - u
            vertex.setUv(LPoint2d(u, v))
            pool.addVertex(vertex)
            vertices.append(vertex)

    index = 0
    for r in range(0, rings):
        for s in range(0, sectors):
            poly = EggPolygon()
            data.addChild(poly)
            poly.addVertex(vertices[index + sectors + 1])
            poly.addVertex(vertices[index])
            poly.addVertex(vertices[index + sectors])

            poly = EggPolygon()
            data.addChild(poly)
            poly.addVertex(vertices[index + sectors + 1])
            poly.addVertex(vertices[index + 1])
            poly.addVertex(vertices[index])
            index += 1
    data.removeUnusedVertices(True)
    data.recomputeVertexNormals(45)
    data.recomputeTangentBinormal(GlobPattern(""))
    node = loadEggData(data)
    path = NodePath(node)
    path.flattenStrong()
    return path
 def addToon(self, toon, tX, tY):
     marker = NodePath('toon_marker-%i' % toon.doId)
     marker.reparentTo(self)
     self._getToonMarker(toon).copyTo(marker)
     marker.setColor(toon.style.getHeadColor())
     if toon.isLocal():
         marker.setScale(0.07)
     else:
         marker.setScale(0.05)
     marker.flattenStrong()
     marker.setPos(*self.gui2pos(*self.tile2gui(tX, tY)))
     self._toon2marker[toon] = marker
示例#8
0
文件: MazeMapGui.py 项目: nate97/src
 def addToon(self, toon, tX, tY):
     marker = NodePath('toon_marker-%i' % toon.doId)
     marker.reparentTo(self)
     self._getToonMarker(toon).copyTo(marker)
     marker.setColor(toon.style.getHeadColor())
     if toon.isLocal():
         marker.setScale(0.07)
     else:
         marker.setScale(0.05)
     marker.flattenStrong()
     marker.setPos(*self.gui2pos(*self.tile2gui(tX, tY)))
     self._toon2marker[toon] = marker
示例#9
0
 def addToon(self, toon):
     marker = NodePath('toon_marker-%i' % toon.doId)
     marker.reparentTo(self)
     self._getToonMarker(toon).copyTo(marker)
     marker.setColor(toon.style.getHeadColor())
     if toon.isLocal():
         marker.setScale(Globals.Gui.LocalMarkerScale)
         marker.setBin('fixed', 10)
     else:
         marker.setScale(Globals.Gui.MarkerScale)
         marker.setBin('fixed', 5)
     marker.flattenStrong()
     self._toonMarkers[toon] = marker
示例#10
0
class SkyBox(object):
    def __init__(self, modelPath, scale=1.0):
        self._nodePath = NodePath('skybox')
        self._nodePath.setPos((0, 0, 0))
        self._scale = scale

        m = base.assetManager.loadModel(modelPath)
        m.reparentTo(self._nodePath)
        self._nodePath.setScale(self._scale)

        self._nodePath.flattenStrong()
        self._nodePath.setLightOff(True)
        self._nodePath.setShaderOff()
        self._nodePath.setDepthWrite(False)

    @property
    def nodePath(self):
        return self._nodePath
示例#11
0
class SkyBox(object):
  
  def __init__(self, modelPath, scale=1.0):
    self._nodePath = NodePath('skybox')
    self._nodePath.setPos((0,0,0))
    self._scale = scale
    
    m = base.assetManager.loadModel(modelPath)
    m.reparentTo(self._nodePath)
    self._nodePath.setScale(self._scale)
      
    self._nodePath.flattenStrong()
    self._nodePath.setLightOff(True)
    self._nodePath.setShaderOff()
    self._nodePath.setDepthWrite(False)
      
  @property
  def nodePath(self):
    return self._nodePath
示例#12
0
class GuiCard:
    def __init__(self, width, height, border_size, pos, hugpos, color):
        self.hugpos = hugpos
        self.width = width
        self.height = height
        self.border_size = border_size
        self.pos = pos
        self.node = NodePath("guicard")
        self.frame_node = NodePath("frame")
        cm = CardMaker("cm_left")
        cm.setFrame(0, width, 0, height)
        n = self.frame_node.attachNewNode(cm.generate())
        n.setPos(0, 0, 0)
        self.frame_node.setColor(color)
        self.frame_node.flattenStrong()
        self.frame_node.reparentTo(self.node)
        self.frame_node.setTransparency(1)
        
        self.node.reparentTo(aspect2d)#@UndefinedVariable
        self.redraw()
    
    def setTexture(self, tex):
        self.frame_node.setTexture(tex)
    
    def redraw(self):
        if self.hugpos == "topleft":
            p = base.a2dTopLeft.getPos()#@UndefinedVariable
            p.setZ(p.getZ() - self.height)
        elif self.hugpos == "topright":
            p = base.a2dTopRight.getPos()#@UndefinedVariable
            p.setZ(p.getZ() - self.height)
        elif self.hugpos == "bottomleft":
            p = base.a2dBottomLeft.getPos()#@UndefinedVariable
            p.setX(p.getX() + 0.107)
            p.setZ(p.getZ())
        elif self.hugpos == None:
            p = self.pos
        self.node.setPos(p)
    
    def removeNode(self):
        self.node.removeNode()
示例#13
0
def makeChunkNode(chunk, texture):
    """
    Function that creates a NodePath containing a chunk from a block array
    
    chunk: Block array
    texture: Texture map to use
    """
    geom = GeomNode("chunk")
    for x in range(16):
        for y in range(16):
            for z in range(16):
                btype = chunk[x][y][z]
                if not btype in Blocks:
                    btype = 2 # Unknown
                if Blocks[btype]["visible"]:
                    makeCube(geom, float(x), float(y), float(z), 
                             texpos=Blocks[btype]["texcoords"])
    chunk = NodePath(geom)
    chunk.setTexture(texture)
    chunk.flattenStrong()
    return chunk
示例#14
0
 def flatten_animated_tiles(self, group_node):
     # FIXME: hard to read: get_child() everywhere
     # Makes a new node for each frame using all its tiles
     # flatten the s*** out of the node and add to a new SequenceNode.
     tiles = group_node.get_children()
     flattened_sequence = SequenceNode(tiles[0].name)
     for a, animation in enumerate(tiles[0].node().get_children()):
         for f, frame in enumerate(animation.get_child(0).get_children()):
             combined_frame = NodePath("frame " + str(f))
             for tile in tiles:
                 new_np = NodePath("frame")
                 new_np.set_pos(tile.get_pos())
                 animation = tile.node().get_child(a).get_child(0)
                 new_np.attach_new_node(animation.get_child(f))
                 new_np.reparent_to(combined_frame)
             combined_frame.flattenStrong()
             flattened_sequence.add_child(combined_frame.node())
     framerate = animation.get_frame_rate()
     flattened_sequence.set_frame_rate(framerate)
     flattened_sequence.loop(True)
     return NodePath(flattened_sequence)
示例#15
0
def getBam(mesh, filename):
    scene_members = pandacore.getSceneMembers(mesh)
    
    rotateNode = GeomNode("rotater")
    rotatePath = NodePath(rotateNode)
    matrix = numpy.identity(4)
    if mesh.assetInfo.upaxis == collada.asset.UP_AXIS.X_UP:
        r = collada.scene.RotateTransform(0,1,0,90)
        matrix = r.matrix
    elif mesh.assetInfo.upaxis == collada.asset.UP_AXIS.Y_UP:
        r = collada.scene.RotateTransform(1,0,0,90)
        matrix = r.matrix
    rotatePath.setMat(Mat4(*matrix.T.flatten().tolist()))
    
    for geom, renderstate, mat4 in scene_members:
        node = GeomNode("primitive")
        node.addGeom(geom)
        if renderstate is not None:
            node.setGeomState(0, renderstate)
        geomPath = rotatePath.attachNewNode(node)
        geomPath.setMat(mat4)

    rotatePath.flattenStrong()
    wrappedNode = pandacore.centerAndScale(rotatePath)
    
    model_name = filename.replace('/', '_')
    wrappedNode.setName(model_name)
    
    bam_temp = tempfile.mktemp(suffix = model_name + '.bam')
    wrappedNode.writeBamFile(bam_temp)
    
    bam_f = open(bam_temp, 'rb')
    bam_data = bam_f.read()
    bam_f.close()
    
    os.remove(bam_temp)
    
    return bam_data
示例#16
0
def flattenReallyStrong(n):
    """
    force the passed nodepath into a single geomNode, then flattens the
    geomNode to minimize geomCount.
    
    In many cases, flattenStrong is not enough, and for good reason.
    This code ignores all potential issues and forces it into one node.
    It will alwayse do so.
    
    RenderStates are preserved, transformes are applied, but tags,
    special node classes and any other such data is all lost.
    
    This modifies the passed NodePath as a side effect and returns the
    new NodePath.
    """
    # make sure all the transforms are applied to the geoms
    n.flattenLight()
    # make GeomNode to store results in.
    g=GeomNode("flat_"+n.getName())
    g.setState(n.getState())
    
    # a little helper to process GeomNodes since we need it in 2 places
    def f(c):
        rs=c.getState(n)
        gg=c.node()
        for i in xrange(gg.getNumGeoms()):
            g.addGeom(gg.modifyGeom(i),rs.compose(gg.getGeomState(i)))
    
    # special case this node being a GeomNode so we don't skips its geoms.
    if n.node().isGeomNode(): f(n)
    # proccess all GeomNodes
    for c in n.findAllMatches('**/+GeomNode'): f(c)
       
    nn=NodePath(g)
    nn.setMat(n.getMat())
    # merge geoms
    nn.flattenStrong()
    return nn
示例#17
0
def getBam(mesh, filename):
    scene_members = pandacore.getSceneMembers(mesh)
    
    rotateNode = GeomNode("rotater")
    rotatePath = NodePath(rotateNode)
    matrix = numpy.identity(4)
    if mesh.assetInfo.upaxis == collada.asset.UP_AXIS.X_UP:
        r = collada.scene.RotateTransform(0,1,0,90)
        matrix = r.matrix
    elif mesh.assetInfo.upaxis == collada.asset.UP_AXIS.Y_UP:
        r = collada.scene.RotateTransform(1,0,0,90)
        matrix = r.matrix
    rotatePath.setMat(Mat4(*matrix.T.flatten().tolist()))
    
    for geom, renderstate, mat4 in scene_members:
        node = GeomNode("primitive")
        node.addGeom(geom)
        if renderstate is not None:
            node.setGeomState(0, renderstate)
        geomPath = rotatePath.attachNewNode(node)
        geomPath.setMat(mat4)

    rotatePath.flattenStrong()
    wrappedNode = pandacore.centerAndScale(rotatePath)
    
    model_name = filename.replace('/', '_')
    wrappedNode.setName(model_name)
    
    bam_temp = tempfile.mktemp(suffix = model_name + '.bam')
    wrappedNode.writeBamFile(bam_temp)
    
    bam_f = open(bam_temp, 'rb')
    bam_data = bam_f.read()
    bam_f.close()
    
    os.remove(bam_temp)
    
    return bam_data
示例#18
0
def makeChunkNode(chunk, texture):
    """
    Function that creates a NodePath containing a chunk from a block array
    
    chunk: Block array
    texture: Texture map to use
    """
    geom = GeomNode("chunk")
    for x in range(16):
        for y in range(16):
            for z in range(16):
                btype = chunk[x][y][z]
                if not btype in Blocks:
                    btype = 2  # Unknown
                if Blocks[btype]["visible"]:
                    makeCube(geom,
                             float(x),
                             float(y),
                             float(z),
                             texpos=Blocks[btype]["texcoords"])
    chunk = NodePath(geom)
    chunk.setTexture(texture)
    chunk.flattenStrong()
    return chunk
示例#19
0
    def _updateDebugNode(self):
        # self.debug("updating debug node")

        mainNode = NodePath("DebugNodeInner")
        mainNode.setPos(self.position)

        # inner = loader.loadModel("Assets/Visualisation/Lamp")
        # inner.setPos(-0.5, -0.5, 0.0)
        # inner.setScale(0.5)
        # inner.setColorScale(Vec4(1,1,0,1))
        # inner.reparentTo(mainNode)

        lineNode = mainNode.attachNewNode("lines")

        # Outer circles
        points1 = []
        points2 = []
        points3 = []
        for i in xrange(self.visualizationNumSteps + 1):
            angle = float(i) / float(
                self.visualizationNumSteps) * math.pi * 2.0
            points1.append(Vec3(0, math.sin(angle), math.cos(angle)))
            points2.append(Vec3(math.sin(angle), math.cos(angle), 0))
            points3.append(Vec3(math.sin(angle), 0, math.cos(angle)))

        self._createDebugLine(points1, False).reparentTo(lineNode)
        self._createDebugLine(points2, False).reparentTo(lineNode)
        self._createDebugLine(points3, False).reparentTo(lineNode)

        lineNode.setScale(self.radius)
        # mainNode.setHpr(self.rotation)

        mainNode.flattenStrong()

        self.debugNode.node().removeAllChildren()
        mainNode.reparentTo(self.debugNode)
示例#20
0
class Block(Element, BlockDefault):
    """
    Abstract class of Block,
    BlockSocket: a part of previous block connecting this block

    <----------------------------------------------
    road_2_end <---------------------- road_2_start
    <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>
    road_1_start ----------------------> road_1_end
    ---------------------------------------------->
    BlockSocket = tuple(road_1, road_2)

    When single-direction block created, road_2 in block socket is useless.
    But it's helpful when a town is created.
    """
    def __init__(self, block_index: int, pre_block_socket: BlockSocket,
                 global_network: RoadNetwork, random_seed):
        super(Block, self).__init__(random_seed)
        # block information
        assert self.ID is not None, "Each Block must has its unique ID When define Block"
        assert len(self.ID) == 1, "Block ID must be a character "
        assert self.SOCKET_NUM is not None, "The number of Socket should be specified when define a new block"
        if block_index == 0:
            from pgdrive.scene_creator.blocks import FirstBlock
            assert isinstance(
                self, FirstBlock), "only first block can use block index 0"
        elif block_index < 0:
            logging.debug("It is recommended that block index should > 1")
        self._block_name = str(block_index) + self.ID
        self.block_index = block_index
        self.number_of_sample_trial = 0

        # each block contains its own road network and a global network
        self._global_network = global_network
        self.block_network = RoadNetwork()

        # used to spawn npc
        self._respawn_roads = []

        # own sockets, one block derives from a socket, but will have more sockets to connect other blocks
        self._sockets = OrderedDict()

        # used to connect previous blocks, save its info here
        self.pre_block_socket = pre_block_socket
        self.pre_block_socket_index = pre_block_socket.index

        # a bounding box used to improve efficiency x_min, x_max, y_min, y_max
        self.bounding_box = None

        # used to create this block, but for first block it is nonsense
        if block_index != 0:
            self.positive_lanes = self.pre_block_socket.positive_road.get_lanes(
                self._global_network)
            self.negative_lanes = self.pre_block_socket.negative_road.get_lanes(
                self._global_network)
            self.positive_lane_num = len(self.positive_lanes)
            self.negative_lane_num = len(self.negative_lanes)
            self.positive_basic_lane = self.positive_lanes[
                -1]  # most right or outside lane is the basic lane
            self.negative_basic_lane = self.negative_lanes[
                -1]  # most right or outside lane is the basic lane
            self.lane_width = self.positive_basic_lane.width_at(0)

        if self.render:
            # render pre-load
            self.road_texture = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sci", "color.jpg"))
            self.road_texture.setMinfilter(
                SamplerState.FT_linear_mipmap_linear)
            self.road_texture.setAnisotropicDegree(8)
            self.road_normal = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sci", "normal.jpg"))
            self.ts_color = TextureStage("color")
            self.ts_normal = TextureStage("normal")
            self.side_texture = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sidewalk", "color.png"))
            self.side_texture.setMinfilter(
                SamplerState.FT_linear_mipmap_linear)
            self.side_texture.setAnisotropicDegree(8)
            self.side_normal = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sidewalk", "normal.png"))
            self.sidewalk = self.loader.loadModel(
                AssetLoader.file_path("models", "box.bam"))

    def construct_block(self,
                        root_render_np: NodePath,
                        pg_physics_world: PGPhysicsWorld,
                        extra_config: Dict = None) -> bool:
        """
        Randomly Construct a block, if overlap return False
        """
        self.set_config(self.PARAMETER_SPACE.sample())
        if extra_config:
            self.set_config(extra_config)
        success = self._sample_topology()
        self._create_in_world()
        self.attach_to_pg_world(root_render_np, pg_physics_world)
        return success

    def destruct_block(self, pg_physics_world: PGPhysicsWorld):
        self._clear_topology()
        self.detach_from_pg_world(pg_physics_world)
        self.node_path.removeNode()
        self.dynamic_nodes.clear()
        self.static_nodes.clear()

    def _sample_topology(self) -> bool:
        """
        Sample a new topology, clear the previous settings at first
        """
        self.number_of_sample_trial += 1
        self._clear_topology()
        no_cross = self._try_plug_into_previous_block()
        self._global_network.add(self.block_network)

        return no_cross

    def construct_from_config(self, config: Dict, root_render_np: NodePath,
                              pg_physics_world: PGPhysicsWorld):
        assert set(config.keys()) == self.PARAMETER_SPACE.parameters, \
            "Make sure the parameters' name are as same as what defined in pg_space.py"
        self.set_config(config)
        success = self._sample_topology()
        self._create_in_world()
        self.attach_to_pg_world(root_render_np, pg_physics_world)
        return success

    def get_socket(self, index: Union[str, int]) -> BlockSocket:
        if isinstance(index, int):
            if index < 0 or index >= len(self._sockets):
                raise ValueError("Socket of {}: index out of range".format(
                    self.class_name))
            socket_index = list(self._sockets)[index]
        else:
            assert index.startswith(self._block_name)
            socket_index = index
        assert socket_index in self._sockets, (socket_index,
                                               self._sockets.keys())
        return self._sockets[socket_index]

    def add_respawn_roads(self, respawn_roads: Union[List[Road], Road]):
        """
        Use this to add spawn roads instead of modifying the list directly
        """
        if isinstance(respawn_roads, List):
            for road in respawn_roads:
                self._add_one_respawn_road(road)
        elif isinstance(respawn_roads, Road):
            self._add_one_respawn_road(respawn_roads)
        else:
            raise ValueError("Only accept List[Road] or Road in this func")

    def get_respawn_roads(self):
        return self._respawn_roads

    def get_respawn_lanes(self):
        """
        return a 2-dim array [[]] to keep the lane index
        """
        ret = []
        for road in self._respawn_roads:
            lanes = road.get_lanes(self.block_network)
            ret.append(lanes)
        return ret

    def add_sockets(self, sockets: Union[List[BlockSocket], BlockSocket]):
        """
        Use this to add sockets instead of modifying the list directly
        """
        if isinstance(sockets, BlockSocket):
            self._add_one_socket(sockets)
        elif isinstance(sockets, List):
            for socket in sockets:
                self._add_one_socket(socket)

    def set_part_idx(self, x):
        """
        It is necessary to divide block to some parts in complex block and give them unique id according to part idx
        """
        self.PART_IDX = x
        self.ROAD_IDX = 0  # clear the road idx when create new part

    def add_road_node(self):
        """
        Call me to get a new node name of this block.
        It is more accurate and recommended to use road_node() to get a node name
        """
        self.ROAD_IDX += 1
        return self.road_node(self.PART_IDX, self.ROAD_IDX - 1)

    def road_node(self, part_idx: int, road_idx: int) -> str:
        """
        return standard road node name
        """
        return self.node(self.block_index, part_idx, road_idx)

    @classmethod
    def node(cls, block_idx: int, part_idx: int, road_idx: int) -> str:
        return str(block_idx) + cls.ID + str(part_idx) + cls.DASH + str(
            road_idx) + cls.DASH

    def _add_one_socket(self, socket: BlockSocket):
        assert isinstance(
            socket, BlockSocket), "Socket list only accept BlockSocket Type"
        if socket.index is not None and not socket.index.startswith(
                self._block_name):
            logging.warning(
                "The adding socket has index {}, which is not started with this block name {}. This is dangerous! "
                "Current block has sockets: {}.".format(
                    socket.index, self._block_name, self.get_socket_indices()))
        if socket.index is None:
            # if this socket is self block socket
            socket.set_index(self._block_name, len(self._sockets))
        self._sockets[socket.index] = socket

    def _add_one_respawn_road(self, respawn_road: Road):
        assert isinstance(respawn_road,
                          Road), "Spawn roads list only accept Road Type"
        self._respawn_roads.append(respawn_road)

    def _clear_topology(self):
        self._global_network -= self.block_network
        self.block_network.graph.clear()
        self.PART_IDX = 0
        self.ROAD_IDX = 0
        self._respawn_roads.clear()
        self._sockets.clear()

    def _try_plug_into_previous_block(self) -> bool:
        """
        Try to plug this Block to previous block's socket, return True for success, False for road cross
        """
        raise NotImplementedError

    """------------------------------------- For Render and Physics Calculation ---------------------------------- """

    def _create_in_world(self):
        """
        Create NodePath and Geom node to perform both collision detection and render
        """
        self.lane_line_node_path = NodePath(
            RigidBodyCombiner(self._block_name + "_lane_line"))
        self.sidewalk_node_path = NodePath(
            RigidBodyCombiner(self._block_name + "_sidewalk"))
        self.lane_node_path = NodePath(
            RigidBodyCombiner(self._block_name + "_lane"))
        self.lane_vis_node_path = NodePath(
            RigidBodyCombiner(self._block_name + "_lane_vis"))
        graph = self.block_network.graph
        for _from, to_dict in graph.items():
            for _to, lanes in to_dict.items():
                self._add_lane_surface(_from, _to, lanes)
                for _id, l in enumerate(lanes):
                    line_color = l.line_color
                    self._add_lane(l, _id, line_color)
        self.lane_line_node_path.flattenStrong()
        self.lane_line_node_path.node().collect()

        self.sidewalk_node_path.flattenStrong()
        self.sidewalk_node_path.node().collect()
        self.sidewalk_node_path.hide(CamMask.ScreenshotCam)

        # only bodies reparent to this node
        self.lane_node_path.flattenStrong()
        self.lane_node_path.node().collect()

        self.lane_vis_node_path.flattenStrong()
        self.lane_vis_node_path.node().collect()
        self.lane_vis_node_path.hide(CamMask.DepthCam | CamMask.ScreenshotCam)

        self.node_path = NodePath(self._block_name)
        self.node_path.hide(CamMask.Shadow)

        self.sidewalk_node_path.reparentTo(self.node_path)
        self.lane_line_node_path.reparentTo(self.node_path)
        self.lane_node_path.reparentTo(self.node_path)
        self.lane_vis_node_path.reparentTo(self.node_path)

        self.bounding_box = self.block_network.get_bounding_box()

    def _add_lane(self, lane: AbstractLane, lane_id: int, colors: List[Vec4]):
        parent_np = self.lane_line_node_path
        lane_width = lane.width_at(0)
        for k, i in enumerate([-1, 1]):
            line_color = colors[k]
            if lane.line_types[k] == LineType.NONE or (lane_id != 0
                                                       and k == 0):
                if isinstance(lane, StraightLane):
                    continue
                elif isinstance(
                        lane, CircularLane) and lane.radius != lane_width / 2:
                    # for ramp render
                    continue
            if lane.line_types[k] == LineType.CONTINUOUS or lane.line_types[
                    k] == LineType.SIDE:
                if isinstance(lane, StraightLane):
                    lane_start = lane.position(0, i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = lane.position(lane.length / 2, i * lane_width / 2)
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k])
                elif isinstance(lane, CircularLane):
                    segment_num = int(lane.length /
                                      Block.CIRCULAR_SEGMENT_LENGTH)
                    for segment in range(segment_num):
                        lane_start = lane.position(
                            segment * Block.CIRCULAR_SEGMENT_LENGTH,
                            i * lane_width / 2)
                        lane_end = lane.position(
                            (segment + 1) * Block.CIRCULAR_SEGMENT_LENGTH,
                            i * lane_width / 2)
                        middle = (lane_start + lane_end) / 2

                        self._add_lane_line2bullet(lane_start, lane_end,
                                                   middle, parent_np,
                                                   line_color,
                                                   lane.line_types[k])
                    # for last part
                    lane_start = lane.position(
                        segment_num * Block.CIRCULAR_SEGMENT_LENGTH,
                        i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = (lane_start + lane_end) / 2
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k])

                if lane.line_types[k] == LineType.SIDE:
                    radius = lane.radius if isinstance(lane,
                                                       CircularLane) else 0.0
                    segment_num = int(lane.length / Block.SIDEWALK_LENGTH)
                    for segment in range(segment_num):
                        lane_start = lane.position(
                            segment * Block.SIDEWALK_LENGTH,
                            i * lane_width / 2)
                        lane_end = lane.position(
                            (segment + 1) * Block.SIDEWALK_LENGTH,
                            i * lane_width / 2)
                        middle = (lane_start + lane_end) / 2
                        self._add_sidewalk2bullet(lane_start, lane_end, middle,
                                                  radius, lane.direction)
                    # for last part
                    lane_start = lane.position(
                        segment_num * Block.SIDEWALK_LENGTH,
                        i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = (lane_start + lane_end) / 2
                    if norm(lane_start[0] - lane_end[0],
                            lane_start[1] - lane_end[1]) > 1e-1:
                        self._add_sidewalk2bullet(lane_start, lane_end, middle,
                                                  radius, lane.direction)

            elif lane.line_types[k] == LineType.BROKEN:
                straight = True if isinstance(lane, StraightLane) else False
                segment_num = int(lane.length / (2 * Block.STRIPE_LENGTH))
                for segment in range(segment_num):
                    lane_start = lane.position(
                        segment * Block.STRIPE_LENGTH * 2, i * lane_width / 2)
                    lane_end = lane.position(
                        segment * Block.STRIPE_LENGTH * 2 +
                        Block.STRIPE_LENGTH, i * lane_width / 2)
                    middle = lane.position(
                        segment * Block.STRIPE_LENGTH * 2 +
                        Block.STRIPE_LENGTH / 2, i * lane_width / 2)

                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k], straight)

                lane_start = lane.position(
                    segment_num * Block.STRIPE_LENGTH * 2, i * lane_width / 2)
                lane_end = lane.position(lane.length + Block.STRIPE_LENGTH,
                                         i * lane_width / 2)
                middle = (lane_end[0] + lane_start[0]) / 2, (lane_end[1] +
                                                             lane_start[1]) / 2
                if not straight:
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k], straight)

                if straight:
                    lane_start = lane.position(0, i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = lane.position(lane.length / 2, i * lane_width / 2)
                    self._add_box_body(lane_start, lane_end, middle, parent_np,
                                       lane.line_types[k], line_color)

    def _add_box_body(self, lane_start, lane_end, middle, parent_np: NodePath,
                      line_type, line_color):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        if LineType.prohibit(line_type):
            node_name = BodyName.White_continuous_line if line_color == LineColor.GREY else BodyName.Yellow_continuous_line
        else:
            node_name = BodyName.Broken_line
        body_node = BulletGhostNode(node_name)
        body_node.set_active(False)
        body_node.setKinematic(False)
        body_node.setStatic(True)
        body_np = parent_np.attachNewNode(body_node)
        shape = BulletBoxShape(
            Vec3(length / 2, Block.LANE_LINE_WIDTH / 2,
                 Block.LANE_LINE_GHOST_HEIGHT))
        body_np.node().addShape(shape)
        mask = Block.CONTINUOUS_COLLISION_MASK if line_type != LineType.BROKEN else Block.BROKEN_COLLISION_MASK
        body_np.node().setIntoCollideMask(BitMask32.bit(mask))
        self.static_nodes.append(body_np.node())

        body_np.setPos(panda_position(middle,
                                      Block.LANE_LINE_GHOST_HEIGHT / 2))
        direction_v = lane_end - lane_start
        theta = -numpy.arctan2(direction_v[1], direction_v[0])
        body_np.setQuat(
            LQuaternionf(numpy.cos(theta / 2), 0, 0, numpy.sin(theta / 2)))

    def _add_lane_line2bullet(self,
                              lane_start,
                              lane_end,
                              middle,
                              parent_np: NodePath,
                              color: Vec4,
                              line_type: LineType,
                              straight_stripe=False):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        if length <= 0:
            return
        if LineType.prohibit(line_type):
            node_name = BodyName.White_continuous_line if color == LineColor.GREY else BodyName.Yellow_continuous_line
        else:
            node_name = BodyName.Broken_line

        # add bullet body for it
        if straight_stripe:
            body_np = parent_np.attachNewNode(node_name)
        else:
            body_node = BulletGhostNode(node_name)
            body_node.set_active(False)
            body_node.setKinematic(False)
            body_node.setStatic(True)
            body_np = parent_np.attachNewNode(body_node)
            # its scale will change by setScale
            body_height = Block.LANE_LINE_GHOST_HEIGHT
            shape = BulletBoxShape(
                Vec3(length / 2 if line_type != LineType.BROKEN else length,
                     Block.LANE_LINE_WIDTH / 2, body_height))
            body_np.node().addShape(shape)
            mask = Block.CONTINUOUS_COLLISION_MASK if line_type != LineType.BROKEN else Block.BROKEN_COLLISION_MASK
            body_np.node().setIntoCollideMask(BitMask32.bit(mask))
            self.static_nodes.append(body_np.node())

        # position and heading
        body_np.setPos(panda_position(middle,
                                      Block.LANE_LINE_GHOST_HEIGHT / 2))
        direction_v = lane_end - lane_start
        theta = -numpy.arctan2(direction_v[1], direction_v[0])
        body_np.setQuat(
            LQuaternionf(numpy.cos(theta / 2), 0, 0, numpy.sin(theta / 2)))

        if self.render:
            # For visualization
            lane_line = self.loader.loadModel(
                AssetLoader.file_path("models", "box.bam"))
            lane_line.setScale(length, Block.LANE_LINE_WIDTH,
                               Block.LANE_LINE_THICKNESS)
            lane_line.setPos(Vec3(0, 0 - Block.LANE_LINE_GHOST_HEIGHT / 2))
            lane_line.reparentTo(body_np)
            body_np.set_color(color)

    def _add_sidewalk2bullet(self,
                             lane_start,
                             lane_end,
                             middle,
                             radius=0.0,
                             direction=0):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        body_node = BulletRigidBodyNode(BodyName.Sidewalk)
        body_node.set_active(False)
        body_node.setKinematic(False)
        body_node.setStatic(True)
        side_np = self.sidewalk_node_path.attachNewNode(body_node)
        shape = BulletBoxShape(Vec3(1 / 2, 1 / 2, 1 / 2))
        body_node.addShape(shape)
        body_node.setIntoCollideMask(
            BitMask32.bit(self.CONTINUOUS_COLLISION_MASK))
        self.dynamic_nodes.append(body_node)

        if radius == 0:
            factor = 1
        else:
            if direction == 1:
                factor = (1 - self.SIDEWALK_LINE_DIST / radius)
            else:
                factor = (1 + self.SIDEWALK_WIDTH / radius) * (
                    1 + self.SIDEWALK_LINE_DIST / radius)
        direction_v = lane_end - lane_start
        vertical_v = PGVector(
            (-direction_v[1], direction_v[0])) / norm(*direction_v)
        middle += vertical_v * (self.SIDEWALK_WIDTH / 2 +
                                self.SIDEWALK_LINE_DIST)
        side_np.setPos(panda_position(middle, 0))
        theta = -numpy.arctan2(direction_v[1], direction_v[0])
        side_np.setQuat(
            LQuaternionf(numpy.cos(theta / 2), 0, 0, numpy.sin(theta / 2)))
        side_np.setScale(
            length * factor, self.SIDEWALK_WIDTH,
            self.SIDEWALK_THICKNESS * (1 + 0.1 * numpy.random.rand()))
        if self.render:
            side_np.setTexture(self.ts_color, self.side_texture)
            self.sidewalk.instanceTo(side_np)

    def _add_lane_surface(self, from_: str, to_: str, lanes: List):
        """
        Add the land surface to world, this surface will record the lane information, like index
        :param from_: From node
        :param to_: To Node
        :param lanes: All lanes of this road
        :return: None
        """

        # decoration only has vis properties
        need_body = False if (from_, to_) == (Decoration.start,
                                              Decoration.end) else True
        if isinstance(lanes[0], StraightLane):
            for index, lane in enumerate(lanes):
                middle = lane.position(lane.length / 2, 0)
                end = lane.position(lane.length, 0)
                direction_v = end - middle
                theta = -numpy.arctan2(direction_v[1], direction_v[0])
                width = lane.width_at(0) + self.SIDEWALK_LINE_DIST * 2
                length = lane.length
                self._add_lane2bullet(middle, width, length, theta, lane,
                                      (from_, to_, index))
        else:
            for index, lane in enumerate(lanes):
                segment_num = int(lane.length / self.CIRCULAR_SEGMENT_LENGTH)
                for i in range(segment_num):
                    middle = lane.position(
                        lane.length * (i + .5) / segment_num, 0)
                    end = lane.position(lane.length * (i + 1) / segment_num, 0)
                    direction_v = end - middle
                    theta = -numpy.arctan2(direction_v[1], direction_v[0])
                    width = lane.width_at(0) + self.SIDEWALK_LINE_DIST * 2
                    length = lane.length
                    self._add_lane2bullet(middle, width,
                                          length * 1.3 / segment_num, theta,
                                          lane, (from_, to_, index))

    def _add_lane2bullet(self, middle, width, length, theta,
                         lane: Union[StraightLane, CircularLane], lane_index):
        """
        Add lane visualization and body for it
        :param middle: Middle point
        :param width: Lane width
        :param length: Segment length
        :param theta: Rotate theta
        :param lane: Lane info
        :return: None
        """
        segment_np = NodePath(LaneNode(BodyName.Lane, lane, lane_index))
        segment_node = segment_np.node()
        segment_node.set_active(False)
        segment_node.setKinematic(False)
        segment_node.setStatic(True)
        shape = BulletBoxShape(Vec3(length / 2, 0.1, width / 2))
        segment_node.addShape(shape)
        self.static_nodes.append(segment_node)
        segment_np.setPos(panda_position(middle, -0.1))
        segment_np.setQuat(
            LQuaternionf(
                numpy.cos(theta / 2) * numpy.cos(-numpy.pi / 4),
                numpy.cos(theta / 2) * numpy.sin(-numpy.pi / 4),
                -numpy.sin(theta / 2) * numpy.cos(-numpy.pi / 4),
                numpy.sin(theta / 2) * numpy.cos(-numpy.pi / 4)))
        segment_np.reparentTo(self.lane_node_path)
        if self.render:
            cm = CardMaker('card')
            cm.setFrame(-length / 2, length / 2, -width / 2, width / 2)
            cm.setHasNormals(True)
            cm.setUvRange((0, 0), (length / 20, width / 10))
            card = self.lane_vis_node_path.attachNewNode(cm.generate())
            card.setPos(
                panda_position(middle,
                               numpy.random.rand() * 0.01 - 0.01))

            card.setQuat(
                LQuaternionf(
                    numpy.cos(theta / 2) * numpy.cos(-numpy.pi / 4),
                    numpy.cos(theta / 2) * numpy.sin(-numpy.pi / 4),
                    -numpy.sin(theta / 2) * numpy.cos(-numpy.pi / 4),
                    numpy.sin(theta / 2) * numpy.cos(-numpy.pi / 4)))
            card.setTransparency(TransparencyAttrib.MMultisample)
            card.setTexture(self.ts_color, self.road_texture)

    @staticmethod
    def create_socket_from_positive_road(road: Road) -> BlockSocket:
        """
        We usually create road from positive road, thus this func can get socket easily.
        Note: it is not recommended to generate socket from negative road
        """
        assert road.start_node[0] != Road.NEGATIVE_DIR and road.end_node[0] != Road.NEGATIVE_DIR, \
            "Socket can only be created from positive road"
        positive_road = Road(road.start_node, road.end_node)
        return BlockSocket(positive_road, -positive_road)

    def get_socket_indices(self):
        return list(self._sockets.keys())

    def get_socket_list(self):
        return list(self._sockets.values())
示例#21
0
class BaseBlock(BaseObject, DrivableAreaProperty):
    """
    Block is a driving area consisting of several roads
    Note: overriding the _sample() function to fill block_network/respawn_roads in subclass
    Call Block.construct_block() to add it to world
    """

    ID = "B"

    def __init__(self,
                 block_index: int,
                 global_network: RoadNetwork,
                 random_seed,
                 ignore_intersection_checking=False):
        super(BaseBlock, self).__init__(str(block_index) + self.ID,
                                        random_seed,
                                        escape_random_seed_assertion=True)
        # block information
        assert self.ID is not None, "Each Block must has its unique ID When define Block"
        assert len(self.ID) == 1, "Block ID must be a character "

        self.block_index = block_index
        self.ignore_intersection_checking = ignore_intersection_checking

        # each block contains its own road network and a global network
        self._global_network = global_network
        self.block_network = RoadNetwork()

        # a bounding box used to improve efficiency x_min, x_max, y_min, y_max
        self.bounding_box = None

        # used to spawn npc
        self._respawn_roads = []
        self._block_objects = None

        if self.render:
            # render pre-load
            self.road_texture = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sci", "color.jpg"))
            self.road_texture.setMinfilter(
                SamplerState.FT_linear_mipmap_linear)
            self.road_texture.setAnisotropicDegree(8)
            self.road_normal = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sci", "normal.jpg"))
            self.ts_color = TextureStage("color")
            self.ts_normal = TextureStage("normal")
            self.side_texture = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sidewalk", "color.png"))
            self.side_texture.setMinfilter(
                SamplerState.FT_linear_mipmap_linear)
            self.side_texture.setAnisotropicDegree(8)
            self.side_normal = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sidewalk", "normal.png"))
            self.sidewalk = self.loader.loadModel(
                AssetLoader.file_path("models", "box.bam"))

    def _sample_topology(self) -> bool:
        """
        Sample a new topology to fill self.block_network
        """
        raise NotImplementedError

    def construct_block(self,
                        root_render_np: NodePath,
                        physics_world: PhysicsWorld,
                        extra_config: Dict = None,
                        no_same_node=True) -> bool:
        """
        Randomly Construct a block, if overlap return False
        """
        self.sample_parameters()
        self.origin = NodePath(self.name)
        self._block_objects = []
        if extra_config:
            assert set(extra_config.keys()).issubset(self.PARAMETER_SPACE.parameters), \
                "Make sure the parameters' name are as same as what defined in pg_space.py"
            raw_config = self.get_config()
            raw_config.update(extra_config)
            self.update_config(raw_config)
        self._clear_topology()
        success = self._sample_topology()
        self._global_network.add(self.block_network, no_same_node)
        self._create_in_world()
        self.attach_to_world(root_render_np, physics_world)
        return success

    def destruct_block(self, physics_world: PhysicsWorld):
        self._clear_topology()
        self.detach_from_world(physics_world)
        self.origin.removeNode()
        self.dynamic_nodes.clear()
        self.static_nodes.clear()
        for obj in self._block_objects:
            obj.destroy()
        self._block_objects = None

    def construct_from_config(self, config: Dict, root_render_np: NodePath,
                              physics_world: PhysicsWorld):
        success = self.construct_block(root_render_np, physics_world, config)
        return success

    def get_respawn_roads(self):
        return self._respawn_roads

    def get_respawn_lanes(self):
        """
        return a 2-dim array [[]] to keep the lane index
        """
        ret = []
        for road in self._respawn_roads:
            lanes = road.get_lanes(self.block_network)
            ret.append(lanes)
        return ret

    def get_intermediate_spawn_lanes(self):
        """Return all lanes that can be used to generate spawn intermediate vehicles."""
        raise NotImplementedError()

    def _add_one_respawn_road(self, respawn_road: Road):
        assert isinstance(respawn_road,
                          Road), "Spawn roads list only accept Road Type"
        self._respawn_roads.append(respawn_road)

    def _clear_topology(self):
        self._global_network -= self.block_network
        self.block_network.graph.clear()
        self.PART_IDX = 0
        self.ROAD_IDX = 0
        self._respawn_roads.clear()

    """------------------------------------- For Render and Physics Calculation ---------------------------------- """

    def _create_in_world(self):
        """
        Create NodePath and Geom node to perform both collision detection and render
        """
        self.lane_line_node_path = NodePath(
            RigidBodyCombiner(self.name + "_lane_line"))
        self.sidewalk_node_path = NodePath(
            RigidBodyCombiner(self.name + "_sidewalk"))
        self.lane_node_path = NodePath(RigidBodyCombiner(self.name + "_lane"))
        self.lane_vis_node_path = NodePath(
            RigidBodyCombiner(self.name + "_lane_vis"))
        graph = self.block_network.graph
        for _from, to_dict in graph.items():
            for _to, lanes in to_dict.items():
                self._add_lane_surface(_from, _to, lanes)
                for _id, l in enumerate(lanes):
                    line_color = l.line_color
                    self._add_lane(l, _id, line_color)
        self.lane_line_node_path.flattenStrong()
        self.lane_line_node_path.node().collect()

        self.sidewalk_node_path.flattenStrong()
        self.sidewalk_node_path.node().collect()
        self.sidewalk_node_path.hide(CamMask.ScreenshotCam)

        # only bodies reparent to this node
        self.lane_node_path.flattenStrong()
        self.lane_node_path.node().collect()

        self.lane_vis_node_path.flattenStrong()
        self.lane_vis_node_path.node().collect()
        self.lane_vis_node_path.hide(CamMask.DepthCam | CamMask.ScreenshotCam)

        self.origin.hide(CamMask.Shadow)

        self.sidewalk_node_path.reparentTo(self.origin)
        self.lane_line_node_path.reparentTo(self.origin)
        self.lane_node_path.reparentTo(self.origin)
        self.lane_vis_node_path.reparentTo(self.origin)

        self.bounding_box = self.block_network.get_bounding_box()

    def _add_pgdrive_lanes(self, lane, lane_id, lane_width, colors, parent_np):
        # for pgdrive structure
        for k, i in enumerate([-1, 1]):
            line_color = colors[k]
            if lane.line_types[k] == LineType.NONE or (lane_id != 0
                                                       and k == 0):
                if isinstance(lane, StraightLane):
                    continue
                elif isinstance(
                        lane, CircularLane) and lane.radius != lane_width / 2:
                    # for ramp render
                    continue
            if lane.line_types[k] == LineType.CONTINUOUS or lane.line_types[
                    k] == LineType.SIDE:
                if isinstance(lane, StraightLane):
                    lane_start = lane.position(0, i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = lane.position(lane.length / 2, i * lane_width / 2)
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k])
                elif isinstance(lane, CircularLane):
                    segment_num = int(
                        lane.length /
                        DrivableAreaProperty.CIRCULAR_SEGMENT_LENGTH)
                    for segment in range(segment_num):
                        lane_start = lane.position(
                            segment *
                            DrivableAreaProperty.CIRCULAR_SEGMENT_LENGTH,
                            i * lane_width / 2)
                        lane_end = lane.position(
                            (segment + 1) *
                            DrivableAreaProperty.CIRCULAR_SEGMENT_LENGTH,
                            i * lane_width / 2)
                        middle = (lane_start + lane_end) / 2

                        self._add_lane_line2bullet(lane_start, lane_end,
                                                   middle, parent_np,
                                                   line_color,
                                                   lane.line_types[k])
                    # for last part
                    lane_start = lane.position(
                        segment_num *
                        DrivableAreaProperty.CIRCULAR_SEGMENT_LENGTH,
                        i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = (lane_start + lane_end) / 2
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k])

                if lane.line_types[k] == LineType.SIDE:
                    radius = lane.radius if isinstance(lane,
                                                       CircularLane) else 0.0
                    segment_num = int(lane.length /
                                      DrivableAreaProperty.SIDEWALK_LENGTH)
                    for segment in range(segment_num):
                        lane_start = lane.position(
                            segment * DrivableAreaProperty.SIDEWALK_LENGTH,
                            i * lane_width / 2)
                        lane_end = lane.position(
                            (segment + 1) *
                            DrivableAreaProperty.SIDEWALK_LENGTH,
                            i * lane_width / 2)
                        middle = (lane_start + lane_end) / 2
                        self._add_sidewalk2bullet(lane_start, lane_end, middle,
                                                  radius, lane.direction)
                    # for last part
                    lane_start = lane.position(
                        segment_num * DrivableAreaProperty.SIDEWALK_LENGTH,
                        i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = (lane_start + lane_end) / 2
                    if norm(lane_start[0] - lane_end[0],
                            lane_start[1] - lane_end[1]) > 1e-1:
                        self._add_sidewalk2bullet(lane_start, lane_end, middle,
                                                  radius, lane.direction)

            elif lane.line_types[k] == LineType.BROKEN:
                straight = True if isinstance(lane, StraightLane) else False
                segment_num = int(lane.length /
                                  (2 * DrivableAreaProperty.STRIPE_LENGTH))
                for segment in range(segment_num):
                    lane_start = lane.position(
                        segment * DrivableAreaProperty.STRIPE_LENGTH * 2,
                        i * lane_width / 2)
                    lane_end = lane.position(
                        segment * DrivableAreaProperty.STRIPE_LENGTH * 2 +
                        DrivableAreaProperty.STRIPE_LENGTH, i * lane_width / 2)
                    middle = lane.position(
                        segment * DrivableAreaProperty.STRIPE_LENGTH * 2 +
                        DrivableAreaProperty.STRIPE_LENGTH / 2,
                        i * lane_width / 2)

                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k], straight)

                lane_start = lane.position(
                    segment_num * DrivableAreaProperty.STRIPE_LENGTH * 2,
                    i * lane_width / 2)
                lane_end = lane.position(
                    lane.length + DrivableAreaProperty.STRIPE_LENGTH,
                    i * lane_width / 2)
                middle = (lane_end[0] + lane_start[0]) / 2, (lane_end[1] +
                                                             lane_start[1]) / 2
                if not straight:
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k], straight)
                if straight:
                    lane_start = lane.position(0, i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = lane.position(lane.length / 2, i * lane_width / 2)
                    self._add_box_body(lane_start, lane_end, middle, parent_np,
                                       lane.line_types[k], line_color)

    def _add_lane(self, lane: AbstractLane, lane_id: int, colors: List[Vec4]):
        parent_np = self.lane_line_node_path
        lane_width = lane.width_at(0)
        if isinstance(lane, CircularLane) or isinstance(lane, StraightLane):
            self._add_pgdrive_lanes(lane, lane_id, lane_width, colors,
                                    parent_np)
        elif isinstance(lane, WayPointLane):
            for c, i in enumerate([-1, 1]):
                line_color = colors[c]
                acc_length = 0
                if lane.line_types[c] != LineType.NONE:
                    for segment in lane.segment_property:
                        lane_start = lane.position(acc_length,
                                                   i * lane_width / 2)
                        acc_length += segment["length"]
                        lane_end = lane.position(acc_length,
                                                 i * lane_width / 2)
                        middle = (lane_start + lane_end) / 2
                        self._add_lane_line2bullet(lane_start, lane_end,
                                                   middle, parent_np,
                                                   line_color,
                                                   lane.line_types[c])

    def _add_box_body(self, lane_start, lane_end, middle, parent_np: NodePath,
                      line_type, line_color):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        if LineType.prohibit(line_type):
            node_name = BodyName.White_continuous_line if line_color == LineColor.GREY else BodyName.Yellow_continuous_line
        else:
            node_name = BodyName.Broken_line
        body_node = BulletGhostNode(node_name)
        body_node.set_active(False)
        body_node.setKinematic(False)
        body_node.setStatic(True)
        body_np = parent_np.attachNewNode(body_node)
        shape = BulletBoxShape(
            Vec3(length / 2, DrivableAreaProperty.LANE_LINE_WIDTH / 2,
                 DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT))
        body_np.node().addShape(shape)
        mask = DrivableAreaProperty.CONTINUOUS_COLLISION_MASK if line_type != LineType.BROKEN else DrivableAreaProperty.BROKEN_COLLISION_MASK
        body_np.node().setIntoCollideMask(mask)
        self.static_nodes.append(body_np.node())

        body_np.setPos(
            panda_position(middle,
                           DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT / 2))
        direction_v = lane_end - lane_start
        # theta = -numpy.arctan2(direction_v[1], direction_v[0])
        theta = -math.atan2(direction_v[1], direction_v[0])

        body_np.setQuat(
            LQuaternionf(math.cos(theta / 2), 0, 0, math.sin(theta / 2)))

    def _add_lane_line2bullet(self,
                              lane_start,
                              lane_end,
                              middle,
                              parent_np: NodePath,
                              color: Vec4,
                              line_type: LineType,
                              straight_stripe=False):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        if length <= 0:
            return
        if LineType.prohibit(line_type):
            node_name = BodyName.White_continuous_line if color == LineColor.GREY else BodyName.Yellow_continuous_line
        else:
            node_name = BodyName.Broken_line

        # add bullet body for it
        if straight_stripe:
            body_np = parent_np.attachNewNode(node_name)
        else:
            body_node = BulletGhostNode(node_name)
            body_node.set_active(False)
            body_node.setKinematic(False)
            body_node.setStatic(True)
            body_np = parent_np.attachNewNode(body_node)
            # its scale will change by setScale
            body_height = DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT
            shape = BulletBoxShape(
                Vec3(length / 2 if line_type != LineType.BROKEN else length,
                     DrivableAreaProperty.LANE_LINE_WIDTH / 2, body_height))
            body_np.node().addShape(shape)
            mask = DrivableAreaProperty.CONTINUOUS_COLLISION_MASK if line_type != LineType.BROKEN else DrivableAreaProperty.BROKEN_COLLISION_MASK
            body_np.node().setIntoCollideMask(mask)
            self.static_nodes.append(body_np.node())

        # position and heading
        body_np.setPos(
            panda_position(middle,
                           DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT / 2))
        direction_v = lane_end - lane_start
        # theta = -numpy.arctan2(direction_v[1], direction_v[0])
        theta = -math.atan2(direction_v[1], direction_v[0])
        body_np.setQuat(
            LQuaternionf(math.cos(theta / 2), 0, 0, math.sin(theta / 2)))

        if self.render:
            # For visualization
            lane_line = self.loader.loadModel(
                AssetLoader.file_path("models", "box.bam"))
            lane_line.setScale(length, DrivableAreaProperty.LANE_LINE_WIDTH,
                               DrivableAreaProperty.LANE_LINE_THICKNESS)
            lane_line.setPos(
                Vec3(0, 0 - DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT / 2))
            lane_line.reparentTo(body_np)
            body_np.set_color(color)

    def _add_sidewalk2bullet(self,
                             lane_start,
                             lane_end,
                             middle,
                             radius=0.0,
                             direction=0):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        body_node = BulletRigidBodyNode(BodyName.Sidewalk)
        body_node.setKinematic(False)
        body_node.setStatic(True)
        side_np = self.sidewalk_node_path.attachNewNode(body_node)
        shape = BulletBoxShape(Vec3(1 / 2, 1 / 2, 1 / 2))
        body_node.addShape(shape)
        body_node.setIntoCollideMask(self.SIDEWALK_COLLISION_MASK)
        self.dynamic_nodes.append(body_node)

        if radius == 0:
            factor = 1
        else:
            if direction == 1:
                factor = (1 - self.SIDEWALK_LINE_DIST / radius)
            else:
                factor = (1 + self.SIDEWALK_WIDTH / radius) * (
                    1 + self.SIDEWALK_LINE_DIST / radius)
        direction_v = lane_end - lane_start
        vertical_v = Vector(
            (-direction_v[1], direction_v[0])) / norm(*direction_v)
        middle += vertical_v * (self.SIDEWALK_WIDTH / 2 +
                                self.SIDEWALK_LINE_DIST)
        side_np.setPos(panda_position(middle, 0))
        theta = -math.atan2(direction_v[1], direction_v[0])
        side_np.setQuat(
            LQuaternionf(math.cos(theta / 2), 0, 0, math.sin(theta / 2)))
        side_np.setScale(
            length * factor, self.SIDEWALK_WIDTH,
            self.SIDEWALK_THICKNESS * (1 + 0.1 * np.random.rand()))
        if self.render:
            side_np.setTexture(self.ts_color, self.side_texture)
            self.sidewalk.instanceTo(side_np)

    def _add_lane_surface(self, from_: str, to_: str, lanes: List):
        """
        Add the land surface to world, this surface will record the lane information, like index
        :param from_: From node
        :param to_: To Node
        :param lanes: All lanes of this road
        """

        if isinstance(lanes[0], StraightLane):
            for index, lane in enumerate(lanes):
                middle = lane.position(lane.length / 2, 0)
                end = lane.position(lane.length, 0)
                direction_v = end - middle
                theta = -math.atan2(direction_v[1], direction_v[0])
                width = lane.width_at(0) + self.SIDEWALK_LINE_DIST * 2
                length = lane.length
                self._add_lane2bullet(middle, width, length, theta, lane,
                                      (from_, to_, index))
        elif isinstance(lanes[0], CircularLane):
            for index, lane in enumerate(lanes):
                segment_num = int(lane.length / self.CIRCULAR_SEGMENT_LENGTH)
                for i in range(segment_num):
                    middle = lane.position(
                        lane.length * (i + .5) / segment_num, 0)
                    end = lane.position(lane.length * (i + 1) / segment_num, 0)
                    direction_v = end - middle
                    theta = -math.atan2(direction_v[1], direction_v[0])
                    width = lane.width_at(0) + self.SIDEWALK_LINE_DIST * 2
                    length = lane.length
                    self._add_lane2bullet(middle, width,
                                          length * 1.3 / segment_num, theta,
                                          lane, (from_, to_, index))
        elif isinstance(lanes[0], WayPointLane):
            for index, lane in enumerate(lanes):
                for segment in lane.segment_property:
                    lane_start = segment["start_point"]
                    lane_end = segment["end_point"]
                    middle = (lane_start + lane_end) / 2
                    direction_v = lane_end - middle
                    theta = -math.atan2(direction_v[1], direction_v[0])
                    width = lane.width_at(0)
                    length = segment["length"]
                    self._add_lane2bullet(middle, width, length, theta, lane,
                                          (from_, to_, index))

    def _add_lane2bullet(self, middle, width, length, theta,
                         lane: Union[StraightLane, CircularLane], lane_index):
        """
        Add lane visualization and body for it
        :param middle: Middle point
        :param width: Lane width
        :param length: Segment length
        :param theta: Rotate theta
        :param lane: Lane info
        :return: None
        """
        length += 0.1
        lane.index = lane_index
        segment_np = NodePath(BaseRigidBodyNode(lane, BodyName.Lane))
        segment_node = segment_np.node()
        segment_node.set_active(False)
        segment_node.setKinematic(False)
        segment_node.setStatic(True)
        shape = BulletBoxShape(Vec3(length / 2, 0.1, width / 2))
        segment_node.addShape(shape)
        self.static_nodes.append(segment_node)
        segment_np.setPos(panda_position(middle, -0.1))
        segment_np.setQuat(
            LQuaternionf(
                math.cos(theta / 2) * math.cos(-math.pi / 4),
                math.cos(theta / 2) * math.sin(-math.pi / 4),
                -math.sin(theta / 2) * math.cos(-math.pi / 4),
                math.sin(theta / 2) * math.cos(-math.pi / 4)))
        segment_np.reparentTo(self.lane_node_path)
        if self.render:
            cm = CardMaker('card')
            cm.setFrame(-length / 2, length / 2, -width / 2, width / 2)
            cm.setHasNormals(True)
            cm.setUvRange((0, 0), (length / 20, width / 10))
            card = self.lane_vis_node_path.attachNewNode(cm.generate())
            card.setPos(panda_position(middle, np.random.rand() * 0.01 - 0.01))

            card.setQuat(
                LQuaternionf(
                    math.cos(theta / 2) * math.cos(-math.pi / 4),
                    math.cos(theta / 2) * math.sin(-math.pi / 4),
                    -math.sin(theta / 2) * math.cos(-math.pi / 4),
                    math.sin(theta / 2) * math.cos(-math.pi / 4)))
            card.setTransparency(TransparencyAttrib.MMultisample)
            card.setTexture(self.ts_color, self.road_texture)

    def add_body(self, physics_body):
        raise DeprecationWarning(
            "Different from common objects like vehicle/traffic sign, Block has several bodies!"
            "Therefore, you should create BulletBody and then add them to self.dynamics_nodes "
            "manually. See in construct() method")
示例#22
0
def load_into_bamfile(meshdata, subfiles, model):
    """Uses pycollada and panda3d to load meshdata and subfiles and
    write out to a bam file on disk"""

    if os.path.isfile(model.bam_file):
        print 'returning cached bam file'
        return model.bam_file

    mesh = load_mesh(meshdata, subfiles)
    model_name = model.model_json['full_path'].replace('/', '_')

    if model.model_type == 'progressive' and model.model_subtype == 'full':
        progressive_stream = model.model_json['metadata']['types'][
            'progressive'].get('progressive_stream')
        if progressive_stream is not None:
            print 'LOADING PROGRESSIVE STREAM'
            data = model.prog_data
            try:
                mesh = add_back_pm.add_back_pm(mesh, StringIO(data), 100)
                print '-----'
                print 'SUCCESSFULLY ADDED BACK PM'
                print '-----'
            except:
                f = open(model.bam_file, 'w')
                f.close()
                raise

    print 'loading into bamfile', model_name, mesh
    scene_members = pandacore.getSceneMembers(mesh)
    print 'got scene members', model_name, mesh

    rotateNode = GeomNode("rotater")
    rotatePath = NodePath(rotateNode)
    matrix = numpy.identity(4)
    if mesh.assetInfo.upaxis == collada.asset.UP_AXIS.X_UP:
        r = collada.scene.RotateTransform(0, 1, 0, 90)
        matrix = r.matrix
    elif mesh.assetInfo.upaxis == collada.asset.UP_AXIS.Y_UP:
        r = collada.scene.RotateTransform(1, 0, 0, 90)
        matrix = r.matrix
    rotatePath.setMat(Mat4(*matrix.T.flatten().tolist()))

    for geom, renderstate, mat4 in scene_members:
        node = GeomNode("primitive")
        node.addGeom(geom)
        if renderstate is not None:
            node.setGeomState(0, renderstate)
        geomPath = rotatePath.attachNewNode(node)
        geomPath.setMat(mat4)

    print 'created np', model_name, mesh

    if model.model_type != 'optimized_unflattened' and model.model_type != 'progressive':
        print 'ABOUT TO FLATTEN'
        rotatePath.flattenStrong()
        print 'DONE FLATTENING'

    print 'flattened', model_name, mesh

    wrappedNode = pandacore.centerAndScale(rotatePath)
    wrappedNode.setName(model_name)

    wrappedNode.writeBamFile(model.bam_file)
    print 'saved', model_name, mesh
    wrappedNode = None

    return model.bam_file
示例#23
0
class Zone():

    def __init__(self, world, name, basedir):
        self.world = world
        self.name = name
        self.basedir = basedir
        self.load_complete = 0
        
        self.world.consoleOut('zone initializing: '+self.name)
            
        # store the in memory WLDFile objects that make uo the zone for direct access
        self.wld_containers = {}        # and as a directory
        self.zone_wld_container = None
        self.obj1_wld_container = None
        self.obj2_wld_container = None
        self.chr_wld_container  = None
    
        # init our texture manager
        self.tm = TextureManager()

        # init our model manager
        self.mm = ModelManager(self)
        
        self.nulltex = Texture()  # create dummy exture object for use in non textured polys

        
        self.rootNode = NodePath(PandaNode("zone_root"))
        self.rootNode.reparentTo(render)
        
        self.delta_t = 0
        
    # This currently only updates the direct zone sprites
    def update(self):
        if self.load_complete != 1:
            return
            
        # print 'update delta_t:', globalClock.getDt()
        self.delta_t += globalClock.getDt()
        if self.delta_t > 0.2:
            self.delta_t = 0
            for container in self.wld_containers:
                  for sprite in self.wld_containers[container].animated_sprites:
                      sprite.update()
        
    # build the main zone geometry mesh
    def prepareZoneMesh(self):
        wld_container = self.wld_containers['zone']
        wld_obj = wld_container.wld_file_obj
        
        # load the 0x36 bsp region fragments (sub meshes): all these meshes together
        # make up the main zone geometry
        for f in wld_obj.fragments.values():
            if f.type == 0x36:
                # print 'adding fragment_36 to main zone mesh'
                # f.dump()
                m = Mesh(self.name)
                m.buildFromFragment(f, wld_container)
                m.root.reparentTo(self.rootNode)        # "hang" the mesh under our root node

        
    # ---------------------------------------------------------------------             
    # create the SPRITE objects: these can reference a single texture or
    # a list of them (for animated textures like water, lava etc.)
    # we need to step through all entries of the 0x31 list fragment for the zone
    # We store the SPRITEs using their index within the 0x31 fragments list as the key
    # because this is exactly how the meshes (0x36 fragments) reference them
    # The lists them selves are keyed by the 0x31 fragmemts id (=index in the diskfile)
    def loadSpriteList(self, wld_container, f31):
    
        wld = wld_container.wld_file_obj
        wld_container.sprite_list[f31.id] = {}
        sprite_list = wld_container.sprite_list[f31.id]
        
        idx = 0
        for ref30 in f31.nameRefs:
            sprite_error = 0
            sprite = None
            # print ref30
            f30 = wld.getFragment(ref30)
            # f30.dump()

            material_name = wld.getName(f30.nameRef)
            
            # Note on TRANSPARENCY: as far as I can tell so far, bit 2 in the params1 field of f30
            # is the "semi-transparent" indicator used for all types of water surfaces for the old
            # zones (pre POP? Seems to not work like this in zones like POV for example anymore)
            # lets go by this theory anyway for now
            '''
            if f30.params1 & 0x00000004:
                print 'SEMI TRANSPARENT MATERIAL:'
                f30.dump()
            '''    
            # print 'looking up 0x05 fragment with id_plus_1:', f30.frag05Ref
            
            # Note that there are frag05Refs inside some 0x30 fragments with value <=0 
            # these named references seem to point directly to 0x03 texture fragments
            # instead of the usual indirection chain  0x05->0x04->0x03
            # in some instances these point nowhere meaningful at all though. Need to catch all these
            frag = wld.getFragment(f30.frag05Ref)
            if frag != None:
                if frag.type == 0x03:    # this is a direct 0x03 ref (see note above)
                    f03 = frag
                    texfile_name = f03.names[0]                   
                    tx = self.tm.getTexture(texfile_name)
                    if tx != None:
                        # we dont have a sprite def (0x04) for these, so we use the material (0x30) name
                        sprite = Sprite(material_name, idx, f30.params1, self.tm)
                        sprite.addTexture(texfile_name, tx) 
                    else:
                        sprite_error = 1
                        print 'Error in Sprite:', material_name, 'Texture not found:', texfile_name                        
                elif frag.type == 0x05: # this is the "normal" indirection chain 0x30->0x05->0x04->0x03
                    f05 = frag
                    # f05.dump()
                    f04 = wld.getFragment(f05.frag04Ref)
                    # f04.dump()

                    name = wld.getName(f04.nameRef)
                    sprite = Sprite(name, idx, f30.params1, self.tm)
                    sprite.setAnimDelay(f04.params2)
                    
                    for f03ref in  f04.frag03Refs:
                        f03 = wld.getFragment(f03ref)
                        # f03.dump()
                        # NOTE that this assumes the zone 0x03 fragments only ever reference one single texture
                        texfile_name = f03.names[0]
                        tx = self.tm.getTexture(texfile_name)
                        if tx != None:
                            sprite.addTexture(texfile_name, tx) 
                        else:
                            sprite_error = 1
                            print 'Error in Sprite:', name, 'Texure not found:', texfile_name
                else:
                    # This is the "does point nowhere meaningful at all" case
                    # infact the reference points back to the same fragment (circular)
                    # This type of 0x30 fragment seems  to only have been used for zone boundary polygons
                    # in the original EQ classic zones 
                    # Note that we create a sprite with just a dummy texture in it for these
                    
                    # sprite_error = 1
                    print 'Warning : Non standard material:%s. Texture ref in 0x30 frag is not type 0x5 or 0x3 but 0x%x' % (material_name, frag.type)
                    # print 'F30 DUMP:'
                    # f30.dump()
                    # print 'Referenced Fragment DUMP:'
                    # frag.dump()
                    
                    # this will be a sprite with just the dummy nulltex textures
                    # we need this so that transparent zonewalls in the very old classic zones work
                    # newer zones have actually textured ("collide.dds") zone walls
                    sprite = Sprite(material_name, idx, f30.params1, self.tm)
                    sprite.addTexture('nulltexture', self.nulltex)
            else:
                sprite_error = 1
                print 'Error in Sprite: could not resolve frag05ref:%i in 0x30 fragment:%i' % (f30.frag05Ref, f30.id)

            if sprite_error != 1:   # only add error free sprites
                # sprite.dump()
                # new style sprite list
                sprite_list[idx] = sprite
                if sprite.anim_delay != 0:
                    print("Adding animated sprite to master list " + sprite.name)
                    wld_container.animated_sprites.append(sprite)
                
            idx += 1    # need to increment regardless of whether we stored or not
                        # so that the index lookup using the refs in the 0x36's works
    
        
        
    # preloadWldTextures actually does quite a bit more than just preloading texture files
    # the main task of this code is to generate our SPRITES
    # Params
    # wld_container is a WldContainer object
    def preloadWldTextures(self, wld_container):
        self.world.consoleOut('preloading textures for container: '+ wld_container.name)
        wld = wld_container.wld_file_obj  # the in memory wld file
        
        # loop over all 0x03 fragments and PRELOAD all referenced texture files from the s3d
        f31 = None
        f31_list = []
        for f in wld.fragments.values():
            if f.type == 0x03:
                # f.dump()
                
                # NOTE
                # in VERSION 2 WLD zones (ex. povalor, postorms) I've found texture names
                # that have three parameters prepended like this for example: 1, 4, 0, POVSNOWDET01.DDS
                # no idea yet as to what these mean but in order to be able to load the texture from 
                # the s3d container we need to strip this stuff
                for name in f.names:
                    i = name.rfind(',')
                    if i != -1:
                        # See NOTE above
                        print 'parametrized texture name found:%s wld version:0x%x' % (name, self.wldZone.version)
                        name = name[i+1:].strip()
            
                    self.tm.loadTexture(name.lower(), wld_container)
                    
            # need to store the 0x31 texture lists        
            if f.type == 0x31:
                f31_list.append(f)
                
        # not all wld files define sprites
        if len(f31_list) == 0:
            return
        
        for f31 in f31_list:
            self.loadSpriteList(wld_container, f31)
            #print("Loaded sprites got this many: " + str(len(wld_container.animated_sprites)))
        
        
    # preload the textures/sprites for all loaded containers
    def preloadTextures(self):
        # self.preloadWldTextures(self.zone_wld_container)
        for wld_obj in self.wld_containers.values():
            self.preloadWldTextures(wld_obj)
    
            
    # We let Panda3D "flatten" the plethora of GEOMs we created from the original bsp tree
    # ==> this process creates a complete new NodePath->GeomNode tree from our original
    # In order to implement texture animation and transparency we need to map the new Geom's textures
    # back to our Sprites so we can change texture assignments and transparency on a Geom level in 
    # the new structure
    
    # Remap the Textures in use for the main Zone Geometry
    def remapTextures(self):
        # -------------------------------------------------------------------------------------
        # ANIMATED TEXTURE SETUP AND TRANSPARENCY FOR ZONE GEOMETRY (NOT PLACEABLES etc!)
        # trying to evaluate the scene graph structure under our root node here
        # since flattenStrong() totally changes the structure of our scene from how we 
        # originally created it, we need to find a way to:
        #   - get a the geoms that the flatten process has produced
        #   - find their textures
        #   - map those back to our sprites
        #   - and finally set up the update process for texture animations based on the above
        # 
        # NOTE this code will fail if there is more than one sprite useing a single texture!
        # Not encountered this yet though.
            
        self.world.consoleOut('setting up animated textures for zone geometry')        
        for child in self.rootNode.getChildren():
            # print child
            geom_node = child.node()
            for geom_number in range(0, geom_node.getNumGeoms()):
                geom_render_state = geom_node.getGeomState(geom_number)              
                attr = geom_render_state.getAttrib(26)  # attrib 26 is the texture attribute (hope this is static)
                if attr != None:
                    # print attr
                    tex = attr.getTexture()

                    # print tex       # BINGO! now we have the texture for this GEOM, lets find the sprite
                    sprite = self.zone_wld_container.findSpriteUsing(tex)
                    if sprite != None:
                        # print sprite
                        
                        # set general texture alpha based tansparency for masked textures
                        # if sprite.masked == 1:
                        #     child.setTransparency(TransparencyAttrib.MAlpha)

                        if sprite.transparent == 1 or sprite.masked == 1:
                            # EXPERIMENTAL TRANSPARENCY SUPPORT ###############
                            # This is for semi-transparent polygons (water surfaces etc) 
                            # we implement the transparency via the alpha component of the GEOM's ColorAttrib
                            ta = TransparencyAttrib.make(TransparencyAttrib.MAlpha)
                            geom_render_state = geom_render_state.setAttrib(ta, 1)  # potentialy needs passing "int override" (=1?) as second param
                            
                            if not sprite.masked == 1:
                                ca = ColorAttrib.makeFlat(Vec4(1, 1, 1, sprite.alpha))
                                geom_render_state = geom_render_state.setAttrib(ca, 1)  # potentialy needs passing "int override" (=1?) as second param
                            
                            geom_node.setGeomState(geom_number, geom_render_state)
                            # #####################################################
    
                        if sprite.anim_delay > 0:
                            # ANIMATED SPRITE
                            # sprite.addAnimGeomRenderState((geom_node, geom_number, geom_render_state))
                            sprite.addAnimGeomRenderState((geom_node, geom_number, geom_render_state))

                    else:
                        print 'could not find sprite for geom node, node texture cant be animated'
        
        
        
    # load up everything related to this zone
    def load(self):
        
        # ---- ZONE GEOMETRY ----
        
        # load main zone s3d
        s3dfile_name = self.name+'.s3d'
        self.world.consoleOut('zone loading zone s3dfile: ' + s3dfile_name)
        
        s3d = S3DFile(self.basedir+self.name)
        if s3d.load() != 0:
            self.world.consoleOut( 'ERROR loading s3dfile:' + self.basedir+s3dfile_name)
            return -1
            
        # s3d.dumpListing()
        
        # load main zone wld
        wldZone = WLDFile(self.name)
        # wldZone.setDumpList([0x14, 0x15])
        wldZone.load(s3d)
        self.zone_wld_container = WLDContainer('zone', self, wldZone, s3d)
        self.wld_containers['zone'] = self.zone_wld_container

        # load the objects.wld file from the same container
        # this basically consists of 0x15 model references for putting all placeables in place
        wldZoneObj = WLDFile('objects')
        # wldZoneObj.setDumpList([0x14, 0x15])
        wldZoneObj.load(s3d)
        self.zone_obj_wld_container = WLDContainer('zone_obj', self, wldZoneObj, s3d)
        self.wld_containers['zone_obj'] = self.zone_obj_wld_container

        # ---- placeables definitions ------------------------------------
        
        s3dfile_name = self.name+'_obj.s3d'
        print '-------------------------------------------------------------------------------------'
        self.world.consoleOut('zone loading placeable objects s3dfile: ' + s3dfile_name)
        
        s3d = S3DFile(self.basedir+self.name+'_obj')
        if s3d.load() == 0:
            # s3d.dumpListing()
            wldObj1 = WLDFile(self.name+'_obj')
            wldObj1.setDumpList([0x14, 0x13, 0x12, 0x11, 0x10])
            wldObj1.load(s3d)
            self.obj1_wld_container = WLDContainer('obj', self, wldObj1, s3d)
            self.wld_containers['obj1'] = self.obj1_wld_container
        else:
            self.world.consoleOut( 'zone object 1 s3dfile does not exist:' + self.basedir+s3dfile_name)
        
        s3dfile_name = self.name+'_2_obj.s3d'
        print '-------------------------------------------------------------------------------------'
        self.world.consoleOut('zone loading placeable objects 2 s3dfile: ' + s3dfile_name)
        
        s3d = S3DFile(self.basedir+self.name+'_2_obj')
        if s3d.load() == 0:
            # s3d.dumpListing()
            wldObj2 = WLDFile(self.name+'_2_obj')
            # wldObj2.setDumpList([0x14, 0x15, 0x2D, 0x36])
            wldObj2.load(s3d)
            self.obj2_wld_container = WLDContainer('obj', self, wldObj2, s3d)
            self.wld_containers['obj2'] = self.obj2_wld_container
        else:
            self.world.consoleOut( 'zone object 2 s3dfile does not exist:' + self.basedir+s3dfile_name)
        
        s3dfile_name = self.name+'_chr.s3d'
        print '-------------------------------------------------------------------------------------'
        self.world.consoleOut('zone loading character s3dfile: ' + s3dfile_name)
        
        s3d = S3DFile(self.basedir+self.name+'_chr')
        if s3d.load() == 0:
            # s3d.dumpListing()
            wldChr = WLDFile(self.name+'_chr')
            # wldChr.setDumpList([0x14, 0x15, 0x2D, 0x36])
            wldChr.load(s3d)
            self.chr_wld_container = WLDContainer('chr', self, wldChr, s3d)
            self.wld_containers['chr'] = self.chr_wld_container
        else:
            self.world.consoleOut( 'zone character s3dfile does not exist:' + self.basedir+s3dfile_name)
        
        # --- TEXTURES ----
        self.world.consoleOut('preloading textures')
        self.preloadTextures()
        
        # ---- Generate main Zone Geometry ----
        self.world.consoleOut( 'preparing zone mesh')
        self.prepareZoneMesh()
        
        # let Panda3D attempt to flatten the zone geometry (reduce the excessive
        # Geom count resulting from the layout of the .wld zone data as a huge
        # bunch of tiny bsp regions)
        self.world.consoleOut('flattening zone mesh geom tree')        
        
        # self.rootNode.ls()
        self.rootNode.flattenStrong()    
        self.rootNode.ls()

        # texture->sprite remapping after the flatten above
        self.remapTextures()
                    
        # COLLISION:
        # The following makes the complete zone base geometry eligible for collisions
        # this is of course extremely inefficient. TODO: at some point we need to use the
        # bsp structures already provided in the wld file to optimize whats in our scene graph
        # and also to build a more intelligent collision system
        self.rootNode.setCollideMask(BitMask32.bit(0)) 

        # ---- load MODELS and spawn placeables -----------------------
        
        # go through all the 0x15 refs and create empty model "shells"
        # for every unique entry
        self.world.consoleOut( 'loading placeables models')
        self.mm.loadPlaceables(wldZoneObj)
        # self.rootNode.ls()
        
            
        print 'zone load complete'
        self.load_complete = 1
        
        return 0
示例#24
0
class TileMap():
    def __init__(self, tileMap=None):
        self.np = NodePath("TileMap")
        self._tileModel = base.loader.loadModel(MODEL_FILE_PATH)
        self._tileTexture = base.loader.loadTexture(TEXTURE_PATH)
        self._tileModel.setTexture(self._tileTexture)
        self._tileMap = dict()
        self._tileMap2D = None
        self._generateMap(
            tileMap)  # Create our map and fill np with real geometry.
        self._tileModel.clearModelNodes()  # Mandatory processing of the model
        self.np.flattenStrong()  # Used to optimize rendering.
        self.np.reparentTo(render)  # Start rendering this map

    def _generateMap(self, tileMap=None):
        """
            Generates a new map (or a given one) for rendering.
            Optionally takes in a flat string representation (Use in networking)
        """
        if tileMap == None:
            # Create 2d list dungeon with pybsp:
            newDungeon = pybsp.generateDungeon2DList((100, 100), (20, 20))
            self._tileMap2D = newDungeon
        else:
            tileMap = convertDungeonFromString(tileMap, 100)
            self._tileMap2D = tileMap
            newDungeon = tileMap
        # Use the output to fill our tileMap dict.
        for row in range(len(newDungeon)):
            for col in range(len(newDungeon[row])):
                # Values hold whether the tile is a floor or not,
                #  what creatures or blocking objects it holds
                #  and what items occupy the space.
                self._tileMap[Point2D(row,
                                      col)] = [newDungeon[row][col], [], []]
                if newDungeon[row][
                        col] == 1:  # Create tile models along the way
                    placeholder = self.np.attachNewNode("Tile(%s,%s)"\
                        %(row, col))
                    placeholder.setPos(row * TILE_SIZE, col * TILE_SIZE, 1)
                    self._tileModel.instanceTo(placeholder)

    def isFloor(self, coords):
        """
            Returns whether the given Point2D is a valid tile in the tileMap
        """
        if coords in self._tileMap.keys():
            if self._tileMap[coords][0] == 1:
                return True
        return False

    def isTileOccupied(self, coords):
        """
            Returns whether the tile at Point2D coords is occupied or exists.
            If the tile is free and exists, this returns False.
        """
        # Check if tile is a floor:
        if self.isFloor(coords):
            # Check if the tile is free of characters/obstructions:
            tile = self._tileMap[coords]
            if len(tile[1]) == 0:
                return False  # Tile exists and free!
        return True  # Tile doesn't exist at this spot or is occupied.

    def getTileMap(self):
        return self._tileMap

    def getCreatureAtPos(self, coords):
        """
            Returns the first creature object found at coords, if there are any.
            If there are no creatures at the specified coords, returns None.
        """
        if self.isFloor(coords) and self.isTileOccupied(coords):
            creaturesList = self._tileMap[coords][1]
            for obj in creaturesList:
                if isinstance(obj, Creature):
                    return obj
        # Automatically returns None

    def updateObjectLocation(self, node, oldLocation, newLocation):
        """
            Finds the node at old location and moves it to newLocation.
        """
        if node in self._tileMap[oldLocation][1]:
            self._tileMap[oldLocation][1].remove(node)
        self._tileMap[newLocation][1].append(node)

    def spawnObject(self, node, newLocation):
        self._tileMap[newLocation][1].append(node)

    def spawnItem(self, item, newLocation):
        self._tileMap[newLocation][2].append(item)

    def pickupItem(self, item):
        self._tileMap[item.getGridPosition()][2].remove(item)

    def getItemsAtPosition(self, position):
        """ Returns the list of items at a given position """
        return self._tileMap[position][2]

    def despawnCreature(self, creature):
        """ Removes the creature from this tileMap """
        self._tileMap[creature.getGridPosition()][1].remove(creature)

    def getCharactersAroundPoint(self, point, reach):
        """
            Returns any creatures around point within range.
        """
        creatureList = list()
        tilesToSearch = getAreaTiles(point, self, reach)
        for tile in tilesToSearch:
            creature = self.getCreatureAtPos(tile)
            if creature:
                creatureList.append(creature)
        return creatureList

    def findAdjacentOpenSpaces(self, point):
        """
            Returns points around point that are empty floors.
        """
        openSpaces = list()
        tilesToSearch = getAreaTiles(point, self, 1)
        for tile in tilesToSearch:
            creature = self.getCreatureAtPos(tile)
            if not creature:
                openSpaces.append(tile)
        return openSpaces

    def getTileMapStr(self):
        """
            Used to send map layout across the network. Essentially flattens the
             2D list into a string of 0s and 1s.
        """
        newString = "".join(
            str(tile) for row in self._tileMap2D for tile in row)
        return newString

    def getRandomFloor(self):
        """
            Picks a random floor from the dict.
            Assumes the dungeon has been initialized.
        """
        validKeys = []
        for key in self._tileMap.keys():
            if self._tileMap[key][0] == 1:
                validKeys.append(key)
        return validKeys[random.randint(0,
                                        len(validKeys) -
                                        1)]  # Random inclusive

    def getRandomEmptyFloor(self):
        """
            Picks a random empty floor from the dict.
            Assumes the dungeon has been initialized.
        """
        validKeys = []
        for key in self._tileMap.keys():
            if self._tileMap[key][0] == 1 and len(self._tileMap[key][1]) == 0:
                validKeys.append(key)
        return validKeys[random.randint(0,
                                        len(validKeys) -
                                        1)]  # Random inclusive
示例#25
0
class Zone():
    def __init__(self, world, name, basedir):
        self.world = world
        self.name = name
        self.basedir = basedir
        self.load_complete = 0

        self.world.consoleOut('zone initializing: ' + self.name)

        # store the in memory WLDFile objects that make uo the zone for direct access
        self.wld_containers = {}  # and as a directory
        self.zone_wld_container = None
        self.obj1_wld_container = None
        self.obj2_wld_container = None
        self.chr_wld_container = None

        # init our texture manager
        self.tm = TextureManager()

        # init our model manager
        self.mm = ModelManager(self)

        self.nulltex = Texture(
        )  # create dummy exture object for use in non textured polys

        self.rootNode = NodePath(PandaNode("zone_root"))
        self.rootNode.reparentTo(render)

        self.delta_t = 0

    # This currently only updates the direct zone sprites
    def update(self):
        if self.load_complete != 1:
            return

        # print 'update delta_t:', globalClock.getDt()
        self.delta_t += globalClock.getDt()
        if self.delta_t > 0.2:
            self.delta_t = 0
            for container in self.wld_containers:
                for sprite in self.wld_containers[container].animated_sprites:
                    sprite.update()

    # build the main zone geometry mesh
    def prepareZoneMesh(self):
        wld_container = self.wld_containers['zone']
        wld_obj = wld_container.wld_file_obj

        # load the 0x36 bsp region fragments (sub meshes): all these meshes together
        # make up the main zone geometry
        for f in wld_obj.fragments.values():
            if f.type == 0x36:
                # print 'adding fragment_36 to main zone mesh'
                # f.dump()
                m = Mesh(self.name)
                m.buildFromFragment(f, wld_container)
                m.root.reparentTo(
                    self.rootNode)  # "hang" the mesh under our root node

    # ---------------------------------------------------------------------
    # create the SPRITE objects: these can reference a single texture or
    # a list of them (for animated textures like water, lava etc.)
    # we need to step through all entries of the 0x31 list fragment for the zone
    # We store the SPRITEs using their index within the 0x31 fragments list as the key
    # because this is exactly how the meshes (0x36 fragments) reference them
    # The lists them selves are keyed by the 0x31 fragmemts id (=index in the diskfile)
    def loadSpriteList(self, wld_container, f31):

        wld = wld_container.wld_file_obj
        wld_container.sprite_list[f31.id] = {}
        sprite_list = wld_container.sprite_list[f31.id]

        idx = 0
        for ref30 in f31.nameRefs:
            sprite_error = 0
            sprite = None
            # print ref30
            f30 = wld.getFragment(ref30)
            # f30.dump()

            material_name = wld.getName(f30.nameRef)

            # Note on TRANSPARENCY: as far as I can tell so far, bit 2 in the params1 field of f30
            # is the "semi-transparent" indicator used for all types of water surfaces for the old
            # zones (pre POP? Seems to not work like this in zones like POV for example anymore)
            # lets go by this theory anyway for now
            '''
            if f30.params1 & 0x00000004:
                print 'SEMI TRANSPARENT MATERIAL:'
                f30.dump()
            '''
            # print 'looking up 0x05 fragment with id_plus_1:', f30.frag05Ref

            # Note that there are frag05Refs inside some 0x30 fragments with value <=0
            # these named references seem to point directly to 0x03 texture fragments
            # instead of the usual indirection chain  0x05->0x04->0x03
            # in some instances these point nowhere meaningful at all though. Need to catch all these
            frag = wld.getFragment(f30.frag05Ref)
            if frag != None:
                if frag.type == 0x03:  # this is a direct 0x03 ref (see note above)
                    f03 = frag
                    texfile_name = f03.names[0]
                    tx = self.tm.getTexture(texfile_name)
                    if tx != None:
                        # we dont have a sprite def (0x04) for these, so we use the material (0x30) name
                        sprite = Sprite(material_name, idx, f30.params1,
                                        self.tm)
                        sprite.addTexture(texfile_name, tx)
                    else:
                        sprite_error = 1
                        print 'Error in Sprite:', material_name, 'Texture not found:', texfile_name
                elif frag.type == 0x05:  # this is the "normal" indirection chain 0x30->0x05->0x04->0x03
                    f05 = frag
                    # f05.dump()
                    f04 = wld.getFragment(f05.frag04Ref)
                    # f04.dump()

                    name = wld.getName(f04.nameRef)
                    sprite = Sprite(name, idx, f30.params1, self.tm)
                    sprite.setAnimDelay(f04.params2)

                    for f03ref in f04.frag03Refs:
                        f03 = wld.getFragment(f03ref)
                        # f03.dump()
                        # NOTE that this assumes the zone 0x03 fragments only ever reference one single texture
                        texfile_name = f03.names[0]
                        tx = self.tm.getTexture(texfile_name)
                        if tx != None:
                            sprite.addTexture(texfile_name, tx)
                        else:
                            sprite_error = 1
                            print 'Error in Sprite:', name, 'Texure not found:', texfile_name
                else:
                    # This is the "does point nowhere meaningful at all" case
                    # infact the reference points back to the same fragment (circular)
                    # This type of 0x30 fragment seems  to only have been used for zone boundary polygons
                    # in the original EQ classic zones
                    # Note that we create a sprite with just a dummy texture in it for these

                    # sprite_error = 1
                    print 'Warning : Non standard material:%s. Texture ref in 0x30 frag is not type 0x5 or 0x3 but 0x%x' % (
                        material_name, frag.type)
                    # print 'F30 DUMP:'
                    # f30.dump()
                    # print 'Referenced Fragment DUMP:'
                    # frag.dump()

                    # this will be a sprite with just the dummy nulltex textures
                    # we need this so that transparent zonewalls in the very old classic zones work
                    # newer zones have actually textured ("collide.dds") zone walls
                    sprite = Sprite(material_name, idx, f30.params1, self.tm)
                    sprite.addTexture('nulltexture', self.nulltex)
            else:
                sprite_error = 1
                print 'Error in Sprite: could not resolve frag05ref:%i in 0x30 fragment:%i' % (
                    f30.frag05Ref, f30.id)

            if sprite_error != 1:  # only add error free sprites
                # sprite.dump()
                # new style sprite list
                sprite_list[idx] = sprite
                if sprite.anim_delay != 0:
                    print("Adding animated sprite to master list " +
                          sprite.name)
                    wld_container.animated_sprites.append(sprite)

            idx += 1  # need to increment regardless of whether we stored or not
            # so that the index lookup using the refs in the 0x36's works

    # preloadWldTextures actually does quite a bit more than just preloading texture files
    # the main task of this code is to generate our SPRITES
    # Params
    # wld_container is a WldContainer object
    def preloadWldTextures(self, wld_container):
        self.world.consoleOut('preloading textures for container: ' +
                              wld_container.name)
        wld = wld_container.wld_file_obj  # the in memory wld file

        # loop over all 0x03 fragments and PRELOAD all referenced texture files from the s3d
        f31 = None
        f31_list = []
        for f in wld.fragments.values():
            if f.type == 0x03:
                # f.dump()

                # NOTE
                # in VERSION 2 WLD zones (ex. povalor, postorms) I've found texture names
                # that have three parameters prepended like this for example: 1, 4, 0, POVSNOWDET01.DDS
                # no idea yet as to what these mean but in order to be able to load the texture from
                # the s3d container we need to strip this stuff
                for name in f.names:
                    i = name.rfind(',')
                    if i != -1:
                        # See NOTE above
                        print 'parametrized texture name found:%s wld version:0x%x' % (
                            name, self.wldZone.version)
                        name = name[i + 1:].strip()

                    self.tm.loadTexture(name.lower(), wld_container)

            # need to store the 0x31 texture lists
            if f.type == 0x31:
                f31_list.append(f)

        # not all wld files define sprites
        if len(f31_list) == 0:
            return

        for f31 in f31_list:
            self.loadSpriteList(wld_container, f31)
            #print("Loaded sprites got this many: " + str(len(wld_container.animated_sprites)))

    # preload the textures/sprites for all loaded containers
    def preloadTextures(self):
        # self.preloadWldTextures(self.zone_wld_container)
        for wld_obj in self.wld_containers.values():
            self.preloadWldTextures(wld_obj)

    # We let Panda3D "flatten" the plethora of GEOMs we created from the original bsp tree
    # ==> this process creates a complete new NodePath->GeomNode tree from our original
    # In order to implement texture animation and transparency we need to map the new Geom's textures
    # back to our Sprites so we can change texture assignments and transparency on a Geom level in
    # the new structure

    # Remap the Textures in use for the main Zone Geometry
    def remapTextures(self):
        # -------------------------------------------------------------------------------------
        # ANIMATED TEXTURE SETUP AND TRANSPARENCY FOR ZONE GEOMETRY (NOT PLACEABLES etc!)
        # trying to evaluate the scene graph structure under our root node here
        # since flattenStrong() totally changes the structure of our scene from how we
        # originally created it, we need to find a way to:
        #   - get a the geoms that the flatten process has produced
        #   - find their textures
        #   - map those back to our sprites
        #   - and finally set up the update process for texture animations based on the above
        #
        # NOTE this code will fail if there is more than one sprite useing a single texture!
        # Not encountered this yet though.

        self.world.consoleOut('setting up animated textures for zone geometry')
        for child in self.rootNode.getChildren():
            # print child
            geom_node = child.node()
            for geom_number in range(0, geom_node.getNumGeoms()):
                geom_render_state = geom_node.getGeomState(geom_number)
                attr = geom_render_state.getAttrib(
                    26
                )  # attrib 26 is the texture attribute (hope this is static)
                if attr != None:
                    # print attr
                    tex = attr.getTexture()

                    # print tex       # BINGO! now we have the texture for this GEOM, lets find the sprite
                    sprite = self.zone_wld_container.findSpriteUsing(tex)
                    if sprite != None:
                        # print sprite

                        # set general texture alpha based tansparency for masked textures
                        # if sprite.masked == 1:
                        #     child.setTransparency(TransparencyAttrib.MAlpha)

                        if sprite.transparent == 1 or sprite.masked == 1:
                            # EXPERIMENTAL TRANSPARENCY SUPPORT ###############
                            # This is for semi-transparent polygons (water surfaces etc)
                            # we implement the transparency via the alpha component of the GEOM's ColorAttrib
                            ta = TransparencyAttrib.make(
                                TransparencyAttrib.MAlpha)
                            geom_render_state = geom_render_state.setAttrib(
                                ta, 1
                            )  # potentialy needs passing "int override" (=1?) as second param

                            if not sprite.masked == 1:
                                ca = ColorAttrib.makeFlat(
                                    Vec4(1, 1, 1, sprite.alpha))
                                geom_render_state = geom_render_state.setAttrib(
                                    ca, 1
                                )  # potentialy needs passing "int override" (=1?) as second param

                            geom_node.setGeomState(geom_number,
                                                   geom_render_state)
                            # #####################################################

                        if sprite.anim_delay > 0:
                            # ANIMATED SPRITE
                            # sprite.addAnimGeomRenderState((geom_node, geom_number, geom_render_state))
                            sprite.addAnimGeomRenderState(
                                (geom_node, geom_number, geom_render_state))

                    else:
                        print 'could not find sprite for geom node, node texture cant be animated'

    # load up everything related to this zone
    def load(self):

        # ---- ZONE GEOMETRY ----

        # load main zone s3d
        s3dfile_name = self.name + '.s3d'
        self.world.consoleOut('zone loading zone s3dfile: ' + s3dfile_name)

        s3d = S3DFile(self.basedir + self.name)
        if s3d.load() != 0:
            self.world.consoleOut('ERROR loading s3dfile:' + self.basedir +
                                  s3dfile_name)
            return -1

        # s3d.dumpListing()

        # load main zone wld
        wldZone = WLDFile(self.name)
        # wldZone.setDumpList([0x14, 0x15])
        wldZone.load(s3d)
        self.zone_wld_container = WLDContainer('zone', self, wldZone, s3d)
        self.wld_containers['zone'] = self.zone_wld_container

        # load the objects.wld file from the same container
        # this basically consists of 0x15 model references for putting all placeables in place
        wldZoneObj = WLDFile('objects')
        # wldZoneObj.setDumpList([0x14, 0x15])
        wldZoneObj.load(s3d)
        self.zone_obj_wld_container = WLDContainer('zone_obj', self,
                                                   wldZoneObj, s3d)
        self.wld_containers['zone_obj'] = self.zone_obj_wld_container

        # ---- placeables definitions ------------------------------------

        s3dfile_name = self.name + '_obj.s3d'
        print '-------------------------------------------------------------------------------------'
        self.world.consoleOut('zone loading placeable objects s3dfile: ' +
                              s3dfile_name)

        s3d = S3DFile(self.basedir + self.name + '_obj')
        if s3d.load() == 0:
            # s3d.dumpListing()
            wldObj1 = WLDFile(self.name + '_obj')
            wldObj1.setDumpList([0x14, 0x13, 0x12, 0x11, 0x10])
            wldObj1.load(s3d)
            self.obj1_wld_container = WLDContainer('obj', self, wldObj1, s3d)
            self.wld_containers['obj1'] = self.obj1_wld_container
        else:
            self.world.consoleOut('zone object 1 s3dfile does not exist:' +
                                  self.basedir + s3dfile_name)

        s3dfile_name = self.name + '_2_obj.s3d'
        print '-------------------------------------------------------------------------------------'
        self.world.consoleOut('zone loading placeable objects 2 s3dfile: ' +
                              s3dfile_name)

        s3d = S3DFile(self.basedir + self.name + '_2_obj')
        if s3d.load() == 0:
            # s3d.dumpListing()
            wldObj2 = WLDFile(self.name + '_2_obj')
            # wldObj2.setDumpList([0x14, 0x15, 0x2D, 0x36])
            wldObj2.load(s3d)
            self.obj2_wld_container = WLDContainer('obj', self, wldObj2, s3d)
            self.wld_containers['obj2'] = self.obj2_wld_container
        else:
            self.world.consoleOut('zone object 2 s3dfile does not exist:' +
                                  self.basedir + s3dfile_name)

        s3dfile_name = self.name + '_chr.s3d'
        print '-------------------------------------------------------------------------------------'
        self.world.consoleOut('zone loading character s3dfile: ' +
                              s3dfile_name)

        s3d = S3DFile(self.basedir + self.name + '_chr')
        if s3d.load() == 0:
            # s3d.dumpListing()
            wldChr = WLDFile(self.name + '_chr')
            # wldChr.setDumpList([0x14, 0x15, 0x2D, 0x36])
            wldChr.load(s3d)
            self.chr_wld_container = WLDContainer('chr', self, wldChr, s3d)
            self.wld_containers['chr'] = self.chr_wld_container
        else:
            self.world.consoleOut('zone character s3dfile does not exist:' +
                                  self.basedir + s3dfile_name)

        # --- TEXTURES ----
        self.world.consoleOut('preloading textures')
        self.preloadTextures()

        # ---- Generate main Zone Geometry ----
        self.world.consoleOut('preparing zone mesh')
        self.prepareZoneMesh()

        # let Panda3D attempt to flatten the zone geometry (reduce the excessive
        # Geom count resulting from the layout of the .wld zone data as a huge
        # bunch of tiny bsp regions)
        self.world.consoleOut('flattening zone mesh geom tree')

        # self.rootNode.ls()
        self.rootNode.flattenStrong()
        self.rootNode.ls()

        # texture->sprite remapping after the flatten above
        self.remapTextures()

        # COLLISION:
        # The following makes the complete zone base geometry eligible for collisions
        # this is of course extremely inefficient. TODO: at some point we need to use the
        # bsp structures already provided in the wld file to optimize whats in our scene graph
        # and also to build a more intelligent collision system
        self.rootNode.setCollideMask(BitMask32.bit(0))

        # ---- load MODELS and spawn placeables -----------------------

        # go through all the 0x15 refs and create empty model "shells"
        # for every unique entry
        self.world.consoleOut('loading placeables models')
        self.mm.loadPlaceables(wldZoneObj)
        # self.rootNode.ls()

        print 'zone load complete'
        self.load_complete = 1

        return 0
def load_into_bamfile(meshdata, subfiles, model):
    """Uses pycollada and panda3d to load meshdata and subfiles and
    write out to a bam file on disk"""

    if os.path.isfile(model.bam_file):
        print 'returning cached bam file'
        return model.bam_file

    mesh = load_mesh(meshdata, subfiles)
    model_name = model.model_json['full_path'].replace('/', '_')
    
    if model.model_type == 'progressive' and model.model_subtype == 'full':
        progressive_stream = model.model_json['metadata']['types']['progressive'].get('progressive_stream')
        if progressive_stream is not None:
            print 'LOADING PROGRESSIVE STREAM'
            data = model.prog_data
            try:
                mesh = add_back_pm.add_back_pm(mesh, StringIO(data), 100)
                print '-----'
                print 'SUCCESSFULLY ADDED BACK PM'
                print '-----'
            except:
                f = open(model.bam_file, 'w')
                f.close()
                raise

    print 'loading into bamfile', model_name, mesh
    scene_members = pandacore.getSceneMembers(mesh)
    print 'got scene members', model_name, mesh
    
    rotateNode = GeomNode("rotater")
    rotatePath = NodePath(rotateNode)
    matrix = numpy.identity(4)
    if mesh.assetInfo.upaxis == collada.asset.UP_AXIS.X_UP:
        r = collada.scene.RotateTransform(0,1,0,90)
        matrix = r.matrix
    elif mesh.assetInfo.upaxis == collada.asset.UP_AXIS.Y_UP:
        r = collada.scene.RotateTransform(1,0,0,90)
        matrix = r.matrix
    rotatePath.setMat(Mat4(*matrix.T.flatten().tolist()))

    for geom, renderstate, mat4 in scene_members:
        node = GeomNode("primitive")
        node.addGeom(geom)
        if renderstate is not None:
            node.setGeomState(0, renderstate)
        geomPath = rotatePath.attachNewNode(node)
        geomPath.setMat(mat4)
        
    print 'created np', model_name, mesh

    if model.model_type != 'optimized_unflattened' and model.model_type != 'progressive':
        print 'ABOUT TO FLATTEN'
        rotatePath.flattenStrong()
        print 'DONE FLATTENING'
        
    print 'flattened', model_name, mesh
    
    wrappedNode = pandacore.centerAndScale(rotatePath)
    wrappedNode.setName(model_name)

    wrappedNode.writeBamFile(model.bam_file)
    print 'saved', model_name, mesh
    wrappedNode = None
    
    return model.bam_file
示例#27
0
class CogdoMazeFactory:

    def __init__(self, randomNumGen, width, height, frameWallThickness=Globals.FrameWallThickness, cogdoMazeData=CogdoMazeData):
        self._rng = RandomNumGen(randomNumGen)
        self.width = width
        self.height = height
        self.frameWallThickness = frameWallThickness
        self._cogdoMazeData = cogdoMazeData
        self.quadrantSize = self._cogdoMazeData.QuadrantSize
        self.cellWidth = self._cogdoMazeData.QuadrantCellWidth

    def getMazeData(self):
        if not hasattr(self, '_data'):
            self._generateMazeData()
        return self._data

    def createCogdoMaze(self, flattenModel=True):
        if not hasattr(self, '_maze'):
            self._loadAndBuildMazeModel(flatten=flattenModel)
        return CogdoMaze(self._model, self._data, self.cellWidth)

    def _gatherQuadrantData(self):
        self.openBarriers = []
        barrierItems = range(Globals.TotalBarriers)
        self._rng.shuffle(barrierItems)
        for i in barrierItems[0:len(barrierItems) - Globals.NumBarriers]:
            self.openBarriers.append(i)

        self.quadrantData = []
        quadrantKeys = self._cogdoMazeData.QuadrantCollisions.keys()
        self._rng.shuffle(quadrantKeys)
        i = 0
        for y in xrange(self.height):
            for x in xrange(self.width):
                key = quadrantKeys[i]
                collTable = self._cogdoMazeData.QuadrantCollisions[key]
                angle = self._cogdoMazeData.QuadrantAngles[self._rng.randint(0, len(self._cogdoMazeData.QuadrantAngles) - 1)]
                self.quadrantData.append((key, collTable[angle], angle))
                i += 1
                if x * y >= self._cogdoMazeData.NumQuadrants:
                    i = 0

    def _generateBarrierData(self):
        data = []
        for y in xrange(self.height):
            data.append([])
            for x in xrange(self.width):
                if x == self.width - 1:
                    ax = -1
                else:
                    ax = 1
                if y == self.height - 1:
                    ay = -1
                else:
                    ay = 1
                data[y].append([ax, ay])

        dirUp = 0
        dirDown = 1
        dirLeft = 2
        dirRight = 3

        def getAvailableDirections(ax, ay, ignore=None):
            dirs = []
            if ax - 1 >= 0 and data[ay][(ax - 1)][BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirLeft)
            if ax + 1 < self.width and data[ay][ax][BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirRight)
            if ay - 1 >= 0 and data[(ay - 1)][ax][BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirDown)
            if ay + 1 < self.height and data[ay][ax][BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirUp)
            return dirs

        visited = []

        def tryVisitNeighbor(ax, ay, ad):
            if ad == dirUp:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_TOP] = 0
                ay += 1
            elif ad == dirDown:
                if data[(ay - 1)][ax] in visited:
                    return None
                visited.append(data[(ay - 1)][ax])
                data[(ay - 1)][ax][BARRIER_DATA_TOP] = 0
                ay -= 1
            elif ad == dirLeft:
                if data[ay][(ax - 1)] in visited:
                    return None
                visited.append(data[ay][(ax - 1)])
                data[ay][(ax - 1)][BARRIER_DATA_RIGHT] = 0
                ax -= 1
            elif ad == dirRight:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_RIGHT] = 0
                ax += 1
            return (ax, ay)

        def openBarriers(x, y):
            dirs = getAvailableDirections(x, y)
            for dir in dirs:
                next = tryVisitNeighbor(x, y, dir)
                if next is not None:
                    openBarriers(*next)

            return

        x = self._rng.randint(0, self.width - 1)
        y = self._rng.randint(0, self.height - 1)
        openBarriers(x, y)
        self._barrierData = data
        return

    def _generateMazeData(self):
        if not hasattr(self, 'quadrantData'):
            self._gatherQuadrantData()
        self._data = {}
        self._data['width'] = (self.width + 1) * self.frameWallThickness + self.width * self.quadrantSize
        self._data['height'] = (self.height + 1) * self.frameWallThickness + self.height * self.quadrantSize
        self._data['originX'] = int(self._data['width'] / 2)
        self._data['originY'] = int(self._data['height'] / 2)
        collisionTable = []
        horizontalWall = [ 1 for x in xrange(self._data['width']) ]
        collisionTable.append(horizontalWall)
        for i in xrange(0, len(self.quadrantData), self.width):
            for y in xrange(self.quadrantSize):
                row = [
                 1]
                for x in xrange(i, i + self.width):
                    if x == 1 and y < self.quadrantSize / 2 - 2:
                        newData = []
                        for j in self.quadrantData[x][1][y]:
                            if j == 0:
                                newData.append(2)
                            else:
                                newData.append(j + 0)

                        row += newData + [1]
                    else:
                        row += self.quadrantData[x][1][y] + [1]

                collisionTable.append(row)

            collisionTable.append(horizontalWall[:])

        barriers = Globals.MazeBarriers
        for i in xrange(len(barriers)):
            for coords in barriers[i]:
                collisionTable[coords[1]][coords[0]] = 0

        y = self._data['originY']
        for x in xrange(len(collisionTable[y])):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        x = self._data['originX']
        for y in xrange(len(collisionTable)):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        self._data['collisionTable'] = collisionTable

    def _loadAndBuildMazeModel(self, flatten=False):
        self.getMazeData()
        self._model = NodePath('CogdoMazeModel')
        levelModel = CogdoUtil.loadMazeModel('level')
        self.quadrants = []
        quadrantUnitSize = int(self.quadrantSize * self.cellWidth)
        frameActualSize = self.frameWallThickness * self.cellWidth
        size = quadrantUnitSize + frameActualSize
        halfWidth = int(self.width / 2)
        halfHeight = int(self.height / 2)
        i = 0
        for y in xrange(self.height):
            for x in xrange(self.width):
                ax = (x - halfWidth) * size
                ay = (y - halfHeight) * size
                extension = ''
                if hasattr(getBase(), 'air'):
                    extension = '.bam'
                filepath = self.quadrantData[i][0] + extension
                angle = self.quadrantData[i][2]
                m = self._createQuadrant(filepath, i, angle, quadrantUnitSize)
                m.setPos(ax, ay, 0)
                m.reparentTo(self._model)
                self.quadrants.append(m)
                i += 1

        quadrantHalfUnitSize = quadrantUnitSize * 0.5
        barrierModel = CogdoUtil.loadMazeModel('grouping_blockerDivider').find('**/divider')
        y = 3
        for x in xrange(self.width):
            if x == (self.width - 1) / 2:
                continue
            ax = (x - halfWidth) * size
            ay = (y - halfHeight) * size - quadrantHalfUnitSize - (self.cellWidth - 0.5)
            b = NodePath('barrier')
            barrierModel.instanceTo(b)
            b.setPos(ax, ay, 0)
            b.reparentTo(self._model)

        offset = self.cellWidth - 0.5
        for x in (0, 3):
            for y in xrange(self.height):
                ax = (x - halfWidth) * size - quadrantHalfUnitSize - frameActualSize + offset
                ay = (y - halfHeight) * size
                b = NodePath('barrier')
                barrierModel.instanceTo(b)
                b.setPos(ax, ay, 0)
                b.setH(90)
                b.reparentTo(self._model)

            offset -= 2.0

        barrierModel.removeNode()
        levelModel.getChildren().reparentTo(self._model)
        for np in self._model.findAllMatches('**/*lightCone*'):
            CogdoUtil.initializeLightCone(np, 'fixed', 3)

        if flatten:
            self._model.flattenStrong()
        return self._model

    def _createQuadrant(self, filepath, serialNum, angle, size):
        root = NodePath('QuadrantRoot-%i' % serialNum)
        quadrant = loader.loadModel(filepath)
        quadrant.getChildren().reparentTo(root)
        root.setH(angle)
        return root
示例#28
0
class CharSelection(DirectObject):
    notify = directNotify.newCategory('CharSelection')

    NO_TOON = "Empty Slot"
    PLAY = "Play"
    CREATE = "Create"
    TITLE = "Pick  A  Toon  To  Play"

    def __init__(self, avChooser):
        self.avChooser = avChooser
        self.choice = None
        self.charList = None
        self.charNameLabel = None
        self.charButtons = []
        self.playOrCreateButton = None
        self.deleteButton = None
        self.quitButton = None
        self.title = None
        self.stageToon = None
        self.stageToonRoot = None
        self.deleteConf = None
        self.frame = None
        self.stageFSM = ClassicFSM.ClassicFSM('StageFSM', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('loadSZ', self.enterLoadSZ, self.exitLoadSZ),
            State.State('onStage', self.enterOnStage, self.exitOnStage)
        ], 'off', 'off')
        self.stageFSM.enterInitialState()
        self.selectionFSM = ClassicFSM.ClassicFSM('CharSelection', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('character', self.enterCharSelected,
                        self.exitCharSelected),
            State.State('empty', self.enterEmptySelected,
                        self.exitEmptySelected)
        ], 'off', 'off')
        self.selectionFSM.enterInitialState()

        self.szGeom = None
        self.olc = None
        self.asyncSZLoadStatus = False
        self.isNewToon = False
        self.newToonSlot = None
        self.camIval = None
        self.stAnimSeq = None
        self.newToonAnnounceSfx = base.loadSfx(
            "phase_4/audio/sfx/King_Crab.ogg")
        self.newToonDrumrollSfx = base.loadSfx(
            "phase_5/audio/sfx/SZ_MM_drumroll.ogg")
        self.newToonRevealSfx = base.loadSfx(
            "phase_5/audio/sfx/SZ_MM_fanfare.ogg")

        self.dnaStore = DNAStorage()
        loader.loadDNAFile(self.dnaStore,
                           'phase_4/dna/pickatoon/storage_pickatoon.pdna')

    def __setupStageToon(self):
        self.stageToonRoot = render.attachNewNode('stageToonRoot')
        self.stageToon = Toon(base.cr)
        self.stageToon.setPosHpr(0, 0, 0, 0, 0, 0)
        self.stageToon.reparentTo(self.stageToonRoot)

    def cleanupStageToon(self):
        if self.stageToon != None:
            self.stageToon.disable()
            self.stageToon.delete()
            self.stageToon = None
        if self.stageToonRoot != None:
            self.stageToonRoot.removeNode()
            self.stageToonRoot = None

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def __async_loadSZTask(self, task=None):
        dnas = HOOD_ID_2_DNA[self.choice.lastHood]
        for i in xrange(len(dnas)):
            dnaFile = dnas[i]
            if i == len(dnas) - 1:
                node = loader.loadDNAFile(self.dnaStore, dnaFile)
                if node.getNumParents() == 1:
                    self.szGeom = NodePath(node.getParent(0))
                    self.szGeom.reparentTo(render)
                else:
                    self.szGeom = render.attachNewNode(node)

                # The 2D trees should not be flattened, to do that, we're going to traverse
                # the scene graph for all trees, use #wrtReparentTo(render) on them, flatten
                # the scene with #flattenStrong(), and finally #wrtReparentTo(self.szGeom)
                # the trees back to the main scene node so they get cleaned up properly.
                trees = self.szGeom.findAllMatches('**/*tree*')
                #self.szGeom.find("**/shadow").removeNode()

                #from panda3d.core import CullBinAttrib
                #self.szGeom.find("**/shadow_crack").setAttrib(CullBinAttrib.make("foreground", 10), 10)
                #shs = self.szGeom.findAllMatches("**/*shadow*")
                #for sh in shs:
                #    sh.removeNode()

                # self.szGeom.ls()

                for tree in trees:
                    tree.wrtReparentTo(render)

                self.szGeom.flattenStrong()

                for tree in trees:
                    tree.wrtReparentTo(self.szGeom)

            else:
                loader.loadDNAFile(self.dnaStore, dnaFile)

        self.olc = ZoneUtil.getOutdoorLightingConfig(self.choice.lastHood)
        self.olc.setup()
        self.olc.apply()

        CIGlobals.preRenderScene(render)

        self.asyncSZLoadStatus = True

        #base.accept('l', render.ls)

        if task:
            return task.done

    def enterLoadSZ(self):
        self.loadingDlg = Dialog.GlobalDialog("Loading...")
        self.loadingDlg.show()

        base.cr.renderFrame()
        base.cr.renderFrame()

        self.notify.info("Polling for SZ to load")
        self.asyncSZLoadStatus = False
        self.__async_loadSZTask()

        base.doNextFrame(self.stageFSM.request, ['onStage'])

    def exitLoadSZ(self):
        if hasattr(self, 'loadingDlg'):
            self.loadingDlg.cleanup()
            del self.loadingDlg

    def __changeCamFOV(self, val):
        base.camLens.setMinFov(val / (4. / 3.))

    def enterOnStage(self):
        dna = self.choice.dna
        name = self.choice.name
        self.stageToon.setName(name)
        self.stageToon.setDNAStrand(dna)
        self.stageToon.nametag.setNametagColor(
            NametagGlobals.NametagColors[NametagGlobals.CCLocal])
        self.stageToon.nametag.setActive(0)
        self.stageToon.nametag.nametag3d.request('Rollover')
        self.stageToon.nametag.unmanage(base.marginManager)
        self.stageToon.nametag.updateAll()
        self.stageToon.animFSM.request('neutral')
        self.stageToon.setPosHpr(0, 0, 0, 10, 0, 0)
        self.stageToon.show()

        dat = HOOD_STAGE_DATA[self.choice.lastHood]

        self.stageToonRoot.setPos(dat[2])
        self.stageToonRoot.setHpr(dat[3])

        camera.reparentTo(self.stageToonRoot)

        camera.setPos(dat[0])
        camera.lookAt(self.stageToonRoot, 0, 0, 3)
        startHpr = camera.getHpr()
        camera.setPos(dat[1])
        camera.lookAt(self.stageToonRoot, 0, 0, 3)
        endHpr = camera.getHpr()

        self.camIval = Parallel(
            LerpPosInterval(camera,
                            5.0,
                            dat[1] - (1.6, 0, 0),
                            dat[0] - (1.6, 0, 0),
                            blendType='easeInOut'),
            LerpQuatInterval(camera,
                             5.0,
                             hpr=endHpr,
                             startHpr=startHpr,
                             blendType='easeInOut'),
            LerpFunc(self.__changeCamFOV,
                     duration=5.0,
                     fromData=80.0,
                     toData=CIGlobals.DefaultCameraFov,
                     blendType='easeInOut'))
        if self.isNewToon:
            self.camIval.append(
                Sequence(
                    Func(self.stageToon.hide), Func(base.stopMusic),
                    SoundInterval(self.newToonAnnounceSfx,
                                  startTime=1.674,
                                  duration=4.047),
                    SoundInterval(self.newToonDrumrollSfx),
                    Func(self.stageToon.pose, 'tele',
                         self.stageToon.getNumFrames('tele')),
                    Func(self.newToonAppear), Func(self.stageToon.show),
                    SoundInterval(self.newToonRevealSfx),
                    Func(base.cr.playTheme)))
        else:
            self.camIval.append(
                Sequence(Func(self.showActionButtons),
                         Func(self.enableAllCharButtons), Wait(5.0),
                         Func(self.beginRandomAnims)))

        self.camIval.start()

    def hideActionButtons(self):
        self.playOrCreateButton.hide()
        self.deleteButton.hide()

    def showActionButtons(self):
        self.playOrCreateButton.show()
        self.deleteButton.show()

    def newToonAppear(self):
        self.stopSTAnimSeq()

        self.stAnimSeq = Sequence(
            Func(self.stageToon.animFSM.request, 'teleportIn'), Wait(2.0),
            ActorInterval(self.stageToon, 'wave'),
            Func(self.stageToon.loop, 'neutral'), Func(self.beginRandomAnims),
            Func(self.enableAllCharButtons), Func(self.showActionButtons))
        self.stAnimSeq.start()

    def stopSTAnimSeq(self):
        if self.stAnimSeq:
            self.stAnimSeq.finish()
            self.stAnimSeq = None

    def unloadSZGeom(self):
        if self.szGeom:
            self.szGeom.removeNode()
            self.szGeom = None
        if self.olc:
            self.olc.cleanup()
            self.olc = None

    def beginRandomAnims(self):
        self.stageToon.startLookAround()
        taskMgr.doMethodLater(random.uniform(*ST_ANIM_IVAL),
                              self.__doRandomSTAnim, "doRandomSTAnim")

    def __doRandomSTAnim(self, task):
        anim = random.choice(ST_RANDOM_ANIMS)

        self.stopSTAnimSeq()

        self.stageToon.stopLookAround()

        head = self.stageToon.getPart('head')

        if anim == 'read':
            self.stAnimSeq = Sequence(
                Func(self.stageToon.lerpLookAt, head, (0, -15, 0)),
                Func(self.stageToon.animFSM.request, 'openBook'), Wait(0.5),
                Func(self.stageToon.animFSM.request, 'readBook'), Wait(2.0),
                Func(self.stageToon.lerpLookAt, head, (0, 0, 0)),
                Func(self.stageToon.animFSM.request, 'closeBook'), Wait(1.75),
                Func(self.stageToon.loop, 'neutral'),
                Func(self.stageToon.startLookAround))
        else:
            self.stageToon.lerpLookAt(head, (0, 0, 0))
            self.stAnimSeq = Sequence(ActorInterval(self.stageToon, anim),
                                      Func(self.stageToon.loop, 'neutral'),
                                      Func(self.stageToon.startLookAround))

        self.stAnimSeq.start()

        task.delayTime = random.uniform(*ST_ANIM_IVAL)
        return task.again

    def endRandomAnims(self):
        taskMgr.remove("doRandomSTAnim")
        self.stopSTAnimSeq()

    def exitOnStage(self):
        self.isNewToon = False
        if self.camIval:
            self.camIval.finish()
            self.camIval = None
        self.endRandomAnims()
        self.stopSTAnimSeq()
        camera.reparentTo(render)
        camera.setPosHpr(0, 0, 0, 0, 0, 0)
        #base.transitions.fadeScreen(1.0)
        self.unloadSZGeom()
        self.stageToon.hide()

    def enterCharSelected(self):
        self.playOrCreateButton['text'] = self.PLAY
        self.playOrCreateButton['extraArgs'] = ['play']
        #aspect2d.hide()

    def exitCharSelected(self):
        self.playOrCreateButton.hide()
        self.deleteButton.hide()

    def enterEmptySelected(self):
        self.charNameLabel.setText(self.NO_TOON)
        self.playOrCreateButton['text'] = self.CREATE
        self.playOrCreateButton['extraArgs'] = ['create']
        self.playOrCreateButton.show()

    def exitEmptySelected(self):
        self.playOrCreateButton.hide()

    def __action(self, action):
        for btn in self.charButtons:
            if btn['state'] == DGG.DISABLED:
                self.slot = btn.getPythonTag('slot')
                break
        func = None
        arg = None
        doFade = True
        if action == 'delete':
            func = self.deleteToon
            arg = self.choice.avId
            doFade = False
        elif action == 'play':
            func = self.playGame
            arg = self.choice.slot
        elif action == 'create':
            func = self.enterMAT
        elif action == 'quit':
            func = sys.exit
            doFade = False
        if doFade:
            base.transitions.fadeOut(0.3)
            if arg != None:
                Sequence(Wait(0.31), Func(func, arg)).start()
            else:
                Sequence(Wait(0.31), Func(func)).start()
        else:
            if arg != None:
                func(arg)
            else:
                func()

    def playGame(self, slot):
        messenger.send("avChooseDone",
                       [self.avChooser.getAvChoiceBySlot(slot)])

    def enterMAT(self):
        messenger.send("enterMakeAToon", [self.slot])

    def deleteToon(self, avId):
        # Show a confirmation message
        self.deleteConf = Dialog.GlobalDialog(
            message='This will delete {0} forever.\n\nAre you sure?'.format(
                self.avChooser.getNameFromAvId(avId)),
            style=Dialog.YesNo,
            doneEvent='deleteConfResponse',
            extraArgs=[avId])
        self.acceptOnce('deleteConfResponse', self.__handleDeleteConfResponse)
        self.deleteConf.show()

    def __handleDeleteConfResponse(self, avId):
        doneStatus = self.deleteConf.getValue()
        if doneStatus:
            # Alright, they pressed yes. No complaining to us.
            self.avChooser.avChooseFSM.request("waitForToonDelResponse",
                                               [avId])
        else:
            self.deleteConf.cleanup()
            self.deleteConf = None

    def __handleCharButton(self, slot):
        for btn in self.charButtons:
            if btn.getPythonTag('slot') == slot:
                btn['state'] = DGG.DISABLED
            else:
                btn['state'] = DGG.NORMAL
        if self.avChooser.hasToonInSlot(slot):
            self.choice = self.avChooser.getAvChoiceBySlot(slot)
            self.selectionFSM.request('character')
            self.stageFSM.request('loadSZ')
        else:
            self.selectionFSM.request('empty')
            self.stageFSM.request('off')

    def disableAllCharButtons(self):
        for btn in self.charButtons:
            btn['state'] = DGG.DISABLED

    def enableAllCharButtons(self):
        for btn in self.charButtons:
            if not self.choice or btn.getPythonTag('slot') != self.choice.slot:
                btn['state'] = DGG.NORMAL

    def load(self, newToonSlot=None):
        self.isNewToon = newToonSlot is not None
        self.newToonSlot = newToonSlot

        base.transitions.noTransitions()

        base.cr.renderFrame()
        base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4. / 3.))

        self.__setupStageToon()

        self.title = DirectLabel(text=self.TITLE,
                                 text_font=CIGlobals.getMickeyFont(),
                                 text_fg=(1, 0.9, 0.1, 1),
                                 relief=None,
                                 text_scale=0.13,
                                 pos=(0, 0, 0.82))
        self.charNameLabel = OnscreenText(text="",
                                          font=CIGlobals.getMickeyFont(),
                                          pos=(-0.25, 0.5, 0),
                                          fg=(1, 0.9, 0.1, 1.0))
        self.charNameLabel.hide()
        self.frame = DirectFrame()
        self.frame['image'] = DGG.getDefaultDialogGeom()
        self.frame['image_color'] = CIGlobals.DialogColor
        self.frame['image_scale'] = (-0.9, -0.9, 0.8)
        self.frame['image_pos'] = (0.82, 0, -0.125)
        self.playOrCreateButton = DirectButton(
            text="",
            pos=(0.8125, 0, -0.35),
            command=self.__action,
            geom=CIGlobals.getDefaultBtnGeom(),
            text_scale=0.06,
            relief=None,
            text_pos=(0, -0.01))
        self.playOrCreateButton.hide()
        self.deleteButton = DirectButton(text="Delete",
                                         pos=(0.8125, 0, -0.45),
                                         command=self.__action,
                                         extraArgs=['delete'],
                                         geom=CIGlobals.getDefaultBtnGeom(),
                                         text_scale=0.06,
                                         relief=None,
                                         text_pos=(0, -0.01))
        self.deleteButton.hide()
        self.quitButton = DirectButton(text="Quit",
                                       pos=(-1.10, 0, -0.925),
                                       command=self.__action,
                                       extraArgs=['quit'],
                                       text_scale=0.06,
                                       geom=CIGlobals.getDefaultBtnGeom(),
                                       relief=None,
                                       text_pos=(0, -0.01))

        for slot in range(6):
            if self.avChooser.hasToonInSlot(slot):
                choice = self.avChooser.getAvChoiceBySlot(slot)
                text = choice.name
            else:
                text = self.NO_TOON
            btn = CIGlobals.makeDefaultScrolledListBtn(
                text=text,
                text_scale=0.06,
                command=self.__handleCharButton,
                extraArgs=[slot])
            btn.setPythonTag('slot', slot)
            self.charButtons.append(btn)
            btn['state'] = DGG.NORMAL

        self.charList = CIGlobals.makeDefaultScrolledList(
            pos=(0.75, 0, -0.225),
            listZorigin=-0.43,
            listFrameSizeZ=0.51,
            arrowButtonScale=0.0,
            items=self.charButtons,
            parent=self.frame)

        if self.isNewToon:
            self.__handleCharButton(self.newToonSlot)
            self.disableAllCharButtons()

    def unload(self):
        self.selectionFSM.requestFinalState()
        self.stageFSM.requestFinalState()
        self.cleanupStageToon()
        self.choice = None
        if self.frame:
            self.frame.destroy()
            self.frame = None
        if self.charButtons:
            for btn in self.charButtons:
                btn.destroy()
            self.charButtons = None
        if self.deleteConf:
            self.deleteConf.cleanup()
            self.deleteConf = None
        if self.charList:
            self.charList.destroy()
            self.charList = None
        if self.charNameLabel:
            self.charNameLabel.destroy()
            self.charNameLabel = None
        if self.playOrCreateButton:
            self.playOrCreateButton.destroy()
            self.playOrCreateButton = None
        if self.deleteButton:
            self.deleteButton.destroy()
            self.deleteButton = None
        if self.quitButton:
            self.quitButton.destroy()
            self.quitButton = None
        if self.title:
            self.title.destroy()
            self.title = None
        base.camera.setPos(0, 0, 0)
        base.camera.setHpr(0, 0, 0)
        base.transitions.noTransitions()
        del self.selectionFSM
示例#29
0
文件: CogdoMaze.py 项目: nate97/src
class CogdoMazeFactory:

    def __init__(self, randomNumGen, width, height, frameWallThickness = Globals.FrameWallThickness, cogdoMazeData = CogdoMazeData):
        self._rng = RandomNumGen(randomNumGen)
        self.width = width
        self.height = height
        self.frameWallThickness = frameWallThickness
        self._cogdoMazeData = cogdoMazeData
        self.quadrantSize = self._cogdoMazeData.QuadrantSize
        self.cellWidth = self._cogdoMazeData.QuadrantCellWidth

    def getMazeData(self):
        if not hasattr(self, '_data'):
            self._generateMazeData()
        return self._data

    def createCogdoMaze(self, flattenModel = True):
        if not hasattr(self, '_maze'):
            self._loadAndBuildMazeModel(flatten=flattenModel)
        return CogdoMaze(self._model, self._data, self.cellWidth)

    def _gatherQuadrantData(self):
        self.openBarriers = []
        barrierItems = range(Globals.TotalBarriers)
        self._rng.shuffle(barrierItems)
        for i in barrierItems[0:len(barrierItems) - Globals.NumBarriers]:
            self.openBarriers.append(i)

        self.quadrantData = []
        quadrantKeys = self._cogdoMazeData.QuadrantCollisions.keys()
        self._rng.shuffle(quadrantKeys)
        i = 0
        for y in xrange(self.height):
            for x in xrange(self.width):
                key = quadrantKeys[i]
                collTable = self._cogdoMazeData.QuadrantCollisions[key]
                angle = self._cogdoMazeData.QuadrantAngles[self._rng.randint(0, len(self._cogdoMazeData.QuadrantAngles) - 1)]
                self.quadrantData.append((key, collTable[angle], angle))
                i += 1
                if x * y >= self._cogdoMazeData.NumQuadrants:
                    i = 0

    def _generateBarrierData(self):
        data = []
        for y in xrange(self.height):
            data.append([])
            for x in xrange(self.width):
                if x == self.width - 1:
                    ax = -1
                else:
                    ax = 1
                if y == self.height - 1:
                    ay = -1
                else:
                    ay = 1
                data[y].append([ax, ay])

        dirUp = 0
        dirDown = 1
        dirLeft = 2
        dirRight = 3

        def getAvailableDirections(ax, ay, ignore = None):
            dirs = []
            if ax - 1 >= 0 and data[ay][ax - 1][BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirLeft)
            if ax + 1 < self.width and data[ay][ax][BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirRight)
            if ay - 1 >= 0 and data[ay - 1][ax][BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirDown)
            if ay + 1 < self.height and data[ay][ax][BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirUp)
            return dirs

        visited = []

        def tryVisitNeighbor(ax, ay, ad):
            if ad == dirUp:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_TOP] = 0
                ay += 1
            elif ad == dirDown:
                if data[ay - 1][ax] in visited:
                    return None
                visited.append(data[ay - 1][ax])
                data[ay - 1][ax][BARRIER_DATA_TOP] = 0
                ay -= 1
            elif ad == dirLeft:
                if data[ay][ax - 1] in visited:
                    return None
                visited.append(data[ay][ax - 1])
                data[ay][ax - 1][BARRIER_DATA_RIGHT] = 0
                ax -= 1
            elif ad == dirRight:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_RIGHT] = 0
                ax += 1
            return (ax, ay)

        def openBarriers(x, y):
            dirs = getAvailableDirections(x, y)
            for dir in dirs:
                next = tryVisitNeighbor(x, y, dir)
                if next is not None:
                    openBarriers(*next)

            return

        x = self._rng.randint(0, self.width - 1)
        y = self._rng.randint(0, self.height - 1)
        openBarriers(x, y)
        self._barrierData = data
        return

    def _generateMazeData(self):
        if not hasattr(self, 'quadrantData'):
            self._gatherQuadrantData()
        self._data = {}
        self._data['width'] = (self.width + 1) * self.frameWallThickness + self.width * self.quadrantSize
        self._data['height'] = (self.height + 1) * self.frameWallThickness + self.height * self.quadrantSize
        self._data['originX'] = int(self._data['width'] / 2)
        self._data['originY'] = int(self._data['height'] / 2)
        collisionTable = []
        horizontalWall = [ 1 for x in xrange(self._data['width']) ]
        collisionTable.append(horizontalWall)
        for i in xrange(0, len(self.quadrantData), self.width):
            for y in xrange(self.quadrantSize):
                row = [1]
                for x in xrange(i, i + self.width):
                    if x == 1 and y < self.quadrantSize / 2 - 2:
                        newData = []
                        for j in self.quadrantData[x][1][y]:
                            if j == 0:
                                newData.append(2)
                            else:
                                newData.append(j + 0)

                        row += newData + [1]
                    else:
                        row += self.quadrantData[x][1][y] + [1]

                collisionTable.append(row)

            collisionTable.append(horizontalWall[:])

        barriers = Globals.MazeBarriers
        for i in xrange(len(barriers)):
            for coords in barriers[i]:
                collisionTable[coords[1]][coords[0]] = 0

        y = self._data['originY']
        for x in xrange(len(collisionTable[y])):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        x = self._data['originX']
        for y in xrange(len(collisionTable)):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        self._data['collisionTable'] = collisionTable

    def _loadAndBuildMazeModel(self, flatten = False):
        self.getMazeData()
        self._model = NodePath('CogdoMazeModel')
        levelModel = CogdoUtil.loadMazeModel('level')
        self.quadrants = []
        quadrantUnitSize = int(self.quadrantSize * self.cellWidth)
        frameActualSize = self.frameWallThickness * self.cellWidth
        size = quadrantUnitSize + frameActualSize
        halfWidth = int(self.width / 2)
        halfHeight = int(self.height / 2)
        i = 0
        for y in xrange(self.height):
            for x in xrange(self.width):
                ax = (x - halfWidth) * size
                ay = (y - halfHeight) * size
                extension = ''
                if hasattr(getBase(), 'air'):
                    extension = '.bam'
                filepath = self.quadrantData[i][0] + extension
                angle = self.quadrantData[i][2]
                m = self._createQuadrant(filepath, i, angle, quadrantUnitSize)
                m.setPos(ax, ay, 0)
                m.reparentTo(self._model)
                self.quadrants.append(m)
                i += 1

        quadrantHalfUnitSize = quadrantUnitSize * 0.5
        barrierModel = CogdoUtil.loadMazeModel('grouping_blockerDivider').find('**/divider')
        y = 3
        for x in xrange(self.width):
            if x == (self.width - 1) / 2:
                continue
            ax = (x - halfWidth) * size
            ay = (y - halfHeight) * size - quadrantHalfUnitSize - (self.cellWidth - 0.5)
            b = NodePath('barrier')
            barrierModel.instanceTo(b)
            b.setPos(ax, ay, 0)
            b.reparentTo(self._model)

        offset = self.cellWidth - 0.5
        for x in (0, 3):
            for y in xrange(self.height):
                ax = (x - halfWidth) * size - quadrantHalfUnitSize - frameActualSize + offset
                ay = (y - halfHeight) * size
                b = NodePath('barrier')
                barrierModel.instanceTo(b)
                b.setPos(ax, ay, 0)
                b.setH(90)
                b.reparentTo(self._model)

            offset -= 2.0

        barrierModel.removeNode()
        levelModel.getChildren().reparentTo(self._model)
        for np in self._model.findAllMatches('**/*lightCone*'):
            CogdoUtil.initializeLightCone(np, 'fixed', 3)

        if flatten:
            self._model.flattenStrong()
        return self._model

    def _createQuadrant(self, filepath, serialNum, angle, size):
        root = NodePath('QuadrantRoot-%i' % serialNum)
        quadrant = loader.loadModel(filepath)
        quadrant.getChildren().reparentTo(root)
        root.setH(angle)
        return root
示例#30
0
class TerrainRenderer:
    """Render the map."""

    def __init__(self):
        """Init the class."""
        self.terrain_map = [[]]
        self.geom_node = NodePath('terrain')
        self.minimap_node = NodePath('minimap')
        self.coll_node = CollisionNode('cnode')
        self.geom_builder = GeomBuilder('floor')

    def get_tile(self, i, j):
        """Get element from terrain_map."""
        try:
            return self.terrain_map[i][j]
        except IndexError:
            return Empty()

    def create_geom(self, loader):
        """Creates self.geom_node from self.terrain_map."""
        # geom_builder = GeomBuilder('floor')
        map_size = len(self.terrain_map)
        unit_size = map_params.unit_size
        start_pos = -map_size*unit_size/2
        # colors = map_params.colors

        # geom_builder.add_rect(
        #     colors.floor,
        #     start_pos, start_pos, 0,
        #     -start_pos, -start_pos, 0
        # )
        card_maker = CardMaker("cm")
        card_maker.setFrame(
            Point3(-start_pos, -start_pos, 0),
            Point3(+start_pos, -start_pos, 0),
            Point3(+start_pos, +start_pos, 0),
            Point3(-start_pos, +start_pos, 0)
        )
        card_maker.setColor(map_params.colors.floor)

        floor_node = NodePath(card_maker.generate())
        floor_node.reparentTo(self.geom_node)
        # floor_node.setHpr(0, 90, 0)
        # floor_node.setPos(0, 0, 0)
        tex = loader.loadTexture('models/floor.png')
        floor_node.setTexture(tex, 1)
        floor_node.setTexScale(TextureStage.getDefault(), map_size, map_size)

        def get(i, j):
            return isinstance(self.get_tile(i, j), Wall)

        wall_count = 0
        for i in range(map_size-1):
            for j in range(map_size-1):
                if any([get(i, j), get(i+1, j), get(i+1, j+1), get(i, j+1)]):
                    wall_count += 1

        def callback():
            self.geom_node.clearModelNodes()
            self.geom_node.flattenStrong()

        threads = Threads(wall_count, callback)

        for i in range(map_size-1):
            for j in range(map_size-1):
                current_position = (
                    start_pos+i*unit_size,
                    start_pos+j*unit_size, 0
                )
                render_wall(
                    current_position,
                    [get(i, j), get(i+1, j),
                        get(i+1, j+1), get(i, j+1)],
                    ((i+j) & 1)+1,
                    self.geom_node,
                    loader,
                    threads
                )

    def create_collision(self):
        """Creates self.coll_node from self.terrain_map."""
        map_size = len(self.terrain_map)
        start_pos = -map_size*map_params.unit_size/2

        box_size = Vec3(
            map_params.unit_size,
            map_params.unit_size,
            map_params.height
        )

        for i in range(map_size):
            for j in range(map_size):
                current_position = Point3(
                    start_pos+i*map_params.unit_size,
                    start_pos+j*map_params.unit_size,
                    0
                )
                if isinstance(self.get_tile(i, j), Wall):
                    self.coll_node.addSolid(CollisionBox(
                        current_position,
                        current_position + box_size
                    ))

    def create_minimap(self):
        """Creates self.minimap_node from self.terrain_map."""
        map_size = len(self.terrain_map)

        for i in range(map_size):
            for j in range(map_size):
                self.get_tile(i, j).generate_map((i, j)).reparentTo(
                    self.minimap_node)