class Simulator(ShowBase): def __init__(self, textboxes=({}), default_text_scale=.07, graph_objs={}): ShowBase.__init__(self) self.joys = self.devices.getDevices(InputDevice.DeviceClass.gamepad) #Attaches input devices to base for ind, joy in enumerate(self.joys): self.attachInputDevice(joy, prefix=str(ind)) #Joystick reading variable self.joystick_readings = [] #Add panda and background self.scene = self.loader.loadModel("models/environment") self.scene.reparentTo(self.render) self.scene.setScale(0.25, 0.25, 0.25) #Sets the scene position self.scene.setPos(-8, 48, 0) self.camera.setPos(-8, 48, -4) self.pandaActor = Actor("models/panda-model", {"walk": "models/panda-walk4"}) self.pandaActor.setScale(0.005, 0.005, 0.005) self.pandaActor.reparentTo(self.render) self.pandaLocation = [0, 0, 0] self.setPandaToLocation() #Lines to be rendered on the next frame self.lines = [] self.lineNodes = [] self.lineNodePaths = [] #Text boxes which will be rendered every frame #Key is a node name, value is a dict with #arguments such as text, location, and scale #Hack to keep default argument immutable and prevent bugs if type(textboxes) == tuple: self.textboxes = textboxes[0] else: self.textboxes = textboxes self.textNodes = {} self.textNodePaths = {} self.default_text_scale = default_text_scale #Geometry drawing node self.geom_node = GeomNode("drawer") self.aspect2d.attach_new_node(self.geom_node) self.text_is_active = True #If the text toggle button has been up for more than one frame self.text_button_lifted = True #If changes that need to be made on text have taken place self.text_toggled = True #Loop the animation to the one loaded in the dictionary self.pandaActor.loop("walk") #Intantiates physics engine self.physics = physics.Swerve() self.taskMgr.add(self.updateJoysticks, "updateJoysticks") self.taskMgr.add(self.walkPandaToPhysics, "walkPandaToPhysics") self.taskMgr.add(self.update2dDisplay, "update2dDisplay") self.taskMgr.add(self.toggleText, "toggleText") #Creates a graph of y vectors self.graphs = graph_objs #Adds dummy value to graph to prevent crash self.graphs["y_graph"].update(0) self.graphs["vector_graph"].update(0, 0) def walkPanda(self, task): x = self.joystick_readings[0]["axes"]["left_x"] y = self.joystick_readings[0]["axes"]["left_y"] magnitude = sqrt(x**2 + y**2) self.pandaLocation[0] += x / 7 self.pandaLocation[1] += y / 7 angle = atan2(y, x) * (180 / pi) self.setPandaToLocation() self.pandaActor.setHpr(angle + 90, 0, 0) if not self.pandaActor.getCurrentAnim() == "walk": self.pandaActor.loop("walk") else: self.pandaActor.setPlayRate(magnitude * 2, "walk") return Task.cont def walkPandaToPhysics(self, task): """ Makes panda walk based on inputs from physics enigne """ x = self.joystick_readings[0]["axes"]["left_x"] y = self.joystick_readings[0]["axes"]["left_y"] z = self.joystick_readings[0]["axes"]["right_x"] self.physics.sendControls(x, y, z) self.physics.update() self.pandaLocation[0] = self.physics.position[0] self.pandaLocation[1] = self.physics.position[1] angle = self.physics.position[2] * (180 / pi) self.setPandaToLocation() self.pandaActor.setHpr(angle + 180, 0, 0) self.graphs["y_graph"].update(self.physics.velocities["frame"][1]) magnitude = sqrt(x**2 + y**2) direction = atan2(y, x) self.graphs["vector_graph"].update(magnitude, direction) return Task.cont def setPandaToLocation(self): self.pandaActor.setPos(self.pandaLocation[0], self.pandaLocation[1], self.pandaLocation[2]) def updateJoysticks(self, task): joystick_readings = [] for joystick in self.joys: joystick_readings.append(joy.readJoystickValues(joystick)) self.joystick_readings = joystick_readings return Task.cont def update2dDisplay(self, task): """ Updates the 2d heads-up overlay """ #Removes all lines from the geometry node self.geom_node.removeAllGeoms() if self.text_is_active: frvector = "Mag: {}\nDir: {}\nTheta_acc: {}\nVel_x: {}\nVel_y: {}\nVel_t: {}\nPos: {}, {}\nRot: {}".format( round(self.physics.vectors["frame"].magnitude, 4), round(self.physics.vectors["frame"].direction, 4), round(self.physics.z_acceleration, 4), round(self.physics.velocities["frame"][0], 4), round(self.physics.velocities["frame"][1], 4), round(self.physics.z_velocity, 4), round(self.physics.position[0], 4), round(self.physics.position[1], 4), round(self.physics.position[2], 4)) self.textboxes["frvector_value"]["text"] = frvector self.lines = [] for graph_name in self.graphs: lines, strings = self.graphs[graph_name].render() #Splits the lines into pairs of points and assigns them to self.lines for line in lines: self.lines += pairPoints(line) #Clears all graph generated strings from textboxes deleted = [] for key in self.textboxes: if graph_name in key: deleted.append(key) for key in deleted: self.textboxes.pop(key) #Processes strings into textboxes for ind, val in enumerate(strings): location, string = val self.textboxes["{}_{}".format(graph_name, str(ind))] = { "location": location, "text": string } self.manageTextNodes() self.renderText() self.manageGeometry() return Task.cont def manageGeometry(self): """ Manages geometry generation """ #(Re)Renders all the lines which are in self.lines for line in self.lines: self.addLine(line) def addLine(self, points): """ Adds a line to class GeomNode from a pair of points """ #Creates objects needed to draw a geometry on the HUD #The vertex data which will define the rendered geometry vertex_data = GeomVertexData("graph", GeomVertexFormat.getV3(), Geom.UHStatic) #The object that writes vertexes the vertex data writer = GeomVertexWriter(vertex_data, "vertex") for point in points: writer.add_data3f(point[0], 0, point[1]) #Defines that this geometry represents a polyline primitive = GeomLinestrips(Geom.UHStatic) #Tells geometry how many verticies will be added(?) primitive.add_consecutive_vertices(0, 2) primitive.close_primitive() geometry = Geom(vertex_data) geometry.add_primitive(primitive) #Draws a graph on the HUD self.geom_node.add_geom(geometry) def manageTextNodes(self): deleted = [] for name in self.textboxes: if name not in self.textNodes: #If the name has not been given a textNode object, set it up self.textNodes[name] = TextNode(name) self.textNodePaths[name] = self.aspect2d.attachNewNode( self.textNodes[name]) #Checks if any textNodes no longer have their respective textbox object and should be deleted for name in self.textNodes: if name not in self.textboxes: deleted.append(name) for node in deleted: self.textNodePaths[node].removeNode() self.textNodePaths.pop(node) self.textNodes.pop(node) def renderText(self): for name in self.textboxes: if "location" in self.textboxes[name]: location = self.textboxes[name]["location"] else: location = (0, 0) if "scale" in self.textboxes[name]: scale = self.textboxes[name]["scale"] else: scale = self.default_text_scale if "text" in self.textboxes[name]: self.textNodes[name].setText(self.textboxes[name]["text"]) self.textNodePaths[name].setScale(scale) self.textNodePaths[name].setPos(location[0], 0, location[1]) def toggleText(self, task): if self.joystick_readings[0]["axes"][ "right_trigger"] >= .05 and self.text_button_lifted: self.text_is_active = not self.text_is_active self.text_toggled = False self.text_button_lifted = False elif not self.joystick_readings[0]["axes"]["right_trigger"] >= .05: self.text_button_lifted = True if not self.text_toggled: if not self.text_is_active: for path in self.textNodePaths: self.textNodePaths[path].detachNode() for path in self.lineNodePaths: path.detachNode() else: for node in self.textNodes: self.textNodePaths[node] = self.aspect2d.attachNewNode( self.textNodes[node]) for node in self.lineNodes: self.aspect2d.attachNewNode(node) return Task.cont
class Viewer(ShowBase): def __init__(self): ShowBase.__init__(self) base.setBackgroundColor(0, 0, 0) # Disable default camera control. base.disableMouse() # Set relative mode and hide the cursor: self.toggle_mouse(True) self.accept('e', lambda: self.toggle_mouse(not self.capture_mouse)) # Add an event handler to prompt for a model to load. self.accept('f', self.prompt_for_model) # Initialize the camera and add a task to control it. self.eye = Eye() self.update_camera() self.taskMgr.add(self.control_camera, "control_camera_task") self.load_default_model() self.setup_lights() def toggle_mouse(self, capture=True): win_props = WindowProperties() win_props.setCursorHidden(capture) base.win.requestProperties(win_props) self.capture_mouse = capture win_x, win_y = base.win.getXSize(), base.win.getYSize() base.win.movePointer(0, win_x // 2, win_y // 2) def update_camera(self): self.camera.setPos(*self.eye.pos) self.camera.setHpr(self.eye.yaw - 90.0, self.eye.pitch, 0) def control_camera(self, task): theta = self.eye.yaw / 180 * math.pi phi = self.eye.pitch / 180 * math.pi eye_dir = np.array([ math.cos(theta) * math.cos(phi), math.sin(theta) * math.cos(phi), math.sin(phi), ]) up_dir = np.array([0.0, 0.0, 1.0]) side_dir = np.cross(eye_dir, up_dir) # Update camera based on move_speed = 10.0 * globalClock.get_dt() if base.mouseWatcherNode.is_button_down(KeyboardButton.shift()): move_speed *= 10.0 if base.mouseWatcherNode.is_button_down(KeyboardButton.ascii_key('w')): self.eye.pos[:] += move_speed * eye_dir if base.mouseWatcherNode.is_button_down(KeyboardButton.ascii_key('s')): self.eye.pos[:] -= move_speed * eye_dir if base.mouseWatcherNode.is_button_down(KeyboardButton.ascii_key('d')): self.eye.pos[:] += move_speed * side_dir if base.mouseWatcherNode.is_button_down(KeyboardButton.ascii_key('a')): self.eye.pos[:] -= move_speed * side_dir if self.capture_mouse: view_speed = 10.0 * globalClock.get_dt() win_x, win_y = base.win.getXSize(), base.win.getYSize() cursor = base.win.getPointer(0) dx = cursor.getX() - base.win.getXSize() // 2 dy = cursor.getY() - base.win.getYSize() // 2 self.eye.yaw = (self.eye.yaw - view_speed * dx) % 360.0 self.eye.pitch = min(85.0, max(-85.0, self.eye.pitch - move_speed * dy)) base.win.movePointer(0, win_x // 2, win_y // 2) self.update_camera() return Task.cont def load_default_model(self): # Initialize the voxel geometry. t = pyskip.Tensor(shape=(3, 3, 3), val=0) t[0, 0, 0] = 1 t[1, 0, 0] = 2 t[1, 1, 0] = 1 t[1, 2, 0] = 2 # Define the color of each voxel type. config = voxels.VoxelConfig() config[0] = voxels.EmptyVoxel() config[1] = voxels.ColorVoxel(128, 0, 0) config[2] = voxels.ColorVoxel(0, 0, 128) # Map the tensor onto a mesh. mesh = voxels.to_mesh(t, config) # Load the mesh into a panda geometry node. self.model = GeomNode('mesh_node') self.model.addGeom(create_geometry_from_mesh(mesh)) render.attachNewNode(self.model) def prompt_for_model(self): # Prompt for a model to load. root = tk.Tk() root.withdraw() file_path = filedialog.askopenfilename() # Load the corresponding level into a tensor. print(f"Loading level: {file_path}") level = minecraft.PySkipMinecraftLevel.load(file_path) print(f"Generating megatensor...") tensor = level.megatensor() # Create the corresponding color config. config = voxels.VoxelConfig() config[0] = voxels.EmptyVoxel() for i in range(1, 256): r, g, b = colors.color_for_id(i) config[i] = voxels.ColorVoxel(r, g, b) # Map the tensor onto a mesh. print(f"Building geometry...") mesh = voxels.to_mesh(tensor, config) # Load the mesh into a panda geometry node. self.model.removeAllGeoms() self.model.addGeom(create_geometry_from_mesh(mesh)) print(f"Done.") def setup_lights(self): ambient_light = AmbientLight("ambient_light") ambient_light.setColor((0.3, 0.3, 0.3, 1)) directional_light = DirectionalLight("directional_light") directional_light.setDirection(LVector3(0, 8, -2.5)) directional_light.setColor((0.9, 0.8, 0.9, 1)) render.setLight(render.attachNewNode(directional_light)) render.setLight(render.attachNewNode(ambient_light))
class RobotSim(ShowBase): def __init__(self, textboxes=({}), graph_objs={}, default_text_scale=.07): ShowBase.__init__(self) self.scene = self.loader.loadModel("field_1.obj", noCache=True) # Reparent the model to render. self.scene.reparentTo(self.render) self.scene.setPos(0, 0, 0) self.insertLight("MainLight", 0, 0, 75) self.insertLight("ExtraLight1", -50, 0, 75) self.resetSim() self.robot = SwerveBot() self.robot.loadModel() self.setupCones() #Joystick setup self.joys = self.devices.getDevices(InputDevice.DeviceClass.gamepad) #Attaches input devices to base for ind, joy in enumerate(self.joys): self.attachInputDevice(joy, prefix=str(ind)) #Joystick reading variable self.joystick_readings = [] #Text boxes which will be rendered every frame #Key is a node name, value is a dict with #arguments such as text, location, and scale #Hack to keep default argument immutable and prevent bugs if type(textboxes) == tuple: self.textboxes = textboxes[0] else: self.textboxes = textboxes self.textNodes = {} self.textNodePaths = {} self.default_text_scale = default_text_scale self.text_is_active = False #If the text toggle button has been up for more than one frame self.text_button_lifted = True #If changes that need to be made on text have taken place self.text_toggled = True #Graph drawing data #Lines to be rendered on the next frame self.lines = [] self.lineNodes = [] self.lineNodePaths = [] self.graphs = graph_objs for graph in self.graphs: self.graphs[graph].dummyUpdate() #Init physics engine self.physics = physics.Swerve() #Geometry drawing node self.geom_node = GeomNode("drawer") self.aspect2d.attach_new_node(self.geom_node) #Tasks self.taskMgr.add(self.updateJoysticks, "updateJoysticks") self.taskMgr.add(self.driveRobot, "driveRobot") self.taskMgr.add(self.updateHud, "updateHud") self.taskMgr.add(self.toggleHud, "toggleHud") self.accept('r', self.reportStatus) self.accept('i', self.resetSim) self.accept('a', self.robot.toggleAutoDrive) def driveRobot(self, task): """ Task to drive the robot """ x = self.joystick_readings[0]["axes"]["left_x"] y = self.joystick_readings[0]["axes"]["left_y"] z = self.joystick_readings[0]["axes"]["right_x"] self.physics.sendControls(x, y, z) self.physics.update() self.setRobotToLocation() return Task.cont def setRobotToLocation(self): x = self.physics.position[0] y = self.physics.position[1] angle = self.physics.position[2] * (2 * pi) self.robot.setPos(x, y, angle) caster_angle_1 = self.physics.positions["brswerve"] * (180 / pi) + 90 caster_angle_2 = self.physics.positions["blswerve"] * (180 / pi) + 90 caster_angle_3 = self.physics.positions["flswerve"] * (180 / pi) + 90 caster_angle_4 = self.physics.positions["frswerve"] * (180 / pi) + 90 self.robot.setCasterAngles(caster_angle_1, caster_angle_2, caster_angle_3, caster_angle_4) wheel_angle_1 = self.physics.positions["brwheel"] / (2 * pi) wheel_angle_2 = self.physics.positions["blwheel"] / (2 * pi) wheel_angle_3 = self.physics.positions["flwheel"] / (2 * pi) wheel_angle_4 = self.physics.positions["frwheel"] / (2 * pi) self.robot.setWheelTurns(wheel_angle_1, wheel_angle_2, wheel_angle_3, wheel_angle_4) def updateJoysticks(self, task): joystick_readings = [] for joystick in self.joys: joystick_readings.append(joy.readJoystickValues(joystick)) self.joystick_readings = joystick_readings return Task.cont def updateHud(self, task): #Removes all lines from the geometry node self.geom_node.removeAllGeoms() if self.text_is_active: frvector = "Mag: {}\nDir: {}\nTheta_acc: {}\nVel_x: {}\nVel_y: {}\nVel_t: {}\nPos: {}, {}\nRot: {}".format( round(self.physics.vectors["frame"].magnitude, 4), round(self.physics.vectors["frame"].direction, 4), round(self.physics.z_acceleration, 4), round(self.physics.velocities["frame"][0], 4), round(self.physics.velocities["frame"][1], 4), round(self.physics.z_velocity, 4), round(self.physics.position[0], 4), round(self.physics.position[1], 4), round(self.physics.position[2], 4)) self.textboxes["frvector_value"]["text"] = frvector self.lines = [] for graph_name in self.graphs: lines, strings = self.graphs[graph_name].render() #Splits the lines into pairs of points and assigns them to self.lines for line in lines: self.lines += pairPoints(line) #Clears all graph generated strings from textboxes deleted = [] for key in self.textboxes: if graph_name in key: deleted.append(key) for key in deleted: self.textboxes.pop(key) #Processes strings into textboxes for ind, val in enumerate(strings): location, string = val self.textboxes["{}_{}".format(graph_name, str(ind))] = { "location": location, "text": string } self.manageTextNodes() self.renderText() self.manageGeometry() return Task.cont def toggleHud(self, task): if self.joystick_readings[0]["axes"][ "right_trigger"] >= .05 and self.text_button_lifted: self.text_is_active = not self.text_is_active self.text_toggled = False self.text_button_lifted = False elif not self.joystick_readings[0]["axes"]["right_trigger"] >= .05: self.text_button_lifted = True if not self.text_toggled: if not self.text_is_active: for path in self.textNodePaths: self.textNodePaths[path].detachNode() for path in self.lineNodePaths: path.detachNode() else: for node in self.textNodes: self.textNodePaths[node] = self.aspect2d.attachNewNode( self.textNodes[node]) for node in self.lineNodes: self.aspect2d.attachNewNode(node) return Task.cont def resetSim(self): base.disableMouse() self.resetCamPosition() self.allowMovement() def allowMovement(self): mat = Mat4(camera.getMat()) mat.invertInPlace() base.mouseInterfaceNode.setMat(mat) base.enableMouse() #self.resetCamPosition() def insertLight(self, name, x, y, z): lightball = self.loader.loadModel("lightball_1.obj", noCache=True) lightball.reparentTo(self.render) lightball.setPos(x, y, z) plight = PointLight(name) plight.setColor(VBase4(1.0, 1.0, 1.0, 1)) plnp = self.render.attachNewNode(plight) plnp.setPos(x, y, z) self.render.setLight(plnp) def setupCones(self): self.cones = [] conepos = [(20, 20), (18, 0)] for cp in conepos: c = Cones() c.loadModel() x, y = cp c.setPos(x, y) self.cones.append(c) def reportStatus(self): x = base.camera.getX() y = base.camera.getY() z = base.camera.getZ() print("Camera Position", x, y, z) h = base.camera.getH() p = base.camera.getP() r = base.camera.getR() print("Camera Angle", h, p, r) def resetCamPosition(self): self.camPos = (-28, -23, 17) self.camAngle = (-51, -17, -12) x, y, z = self.camPos h, p, r = self.camAngle base.camera.setPos(x, y, z) base.camera.setHpr(h, p, r)
class PointsSet(VisibleObject): tex = None def __init__(self, use_sprites=True, use_sizes=True, points_size=2, sprite=None, background=None, shader=None): self.gnode = GeomNode('starfield') self.use_sprites = use_sprites self.use_sizes = use_sizes self.background = background if shader is None: shader = BasicShader(lighting_model=FlatLightingModel(), point_shader=False) self.shader = shader self.reset() self.geom = self.makeGeom([], [], []) self.gnode.addGeom(self.geom) self.instance = NodePath(self.gnode) if self.use_sprites: if sprite is None: sprite = RoundDiskPointSprite() self.sprite = sprite else: self.sprite = SimplePoint(points_size) self.min_size = self.sprite.get_min_size() self.sprite.apply(self.instance) self.instance.setCollideMask(GeomNode.getDefaultCollideMask()) self.instance.node().setPythonTag('owner', self) #TODO: Should not use ModelAppearance ! self.appearance = ModelAppearance(vertex_color=True) if self.appearance is not None: self.appearance.bake() self.appearance.apply(self, self) if self.shader is not None: self.shader.apply(self, self.appearance) if self.use_sprites: self.instance.node().setBounds(OmniBoundingVolume()) self.instance.node().setFinal(True) if self.background is not None: self.instance.setBin('background', self.background) self.instance.set_depth_write(False) def jobs_done_cb(self, patch): pass def reset(self): self.points = [] self.colors = [] self.sizes = [] def add_point_scale(self, position, color, size): #Observer is at position (0, 0, 0) distance_to_obs = position.length() vector_to_obs = -position / distance_to_obs point, _, _ = self.get_real_pos_rel(position, distance_to_obs, vector_to_obs) self.points.append(point) self.colors.append(color) self.sizes.append(size) def add_point(self, position, color, size): self.points.append(position) self.colors.append(color) self.sizes.append(size) def update(self): self.update_arrays(self.points, self.colors, self.sizes) def makeGeom(self, points, colors, sizes): #format = GeomVertexFormat.getV3c4() array = GeomVertexArrayFormat() array.addColumn(InternalName.make('vertex'), 3, Geom.NTFloat32, Geom.CPoint) array.addColumn(InternalName.make('color'), 4, Geom.NTFloat32, Geom.CColor) if self.use_sizes: array.addColumn(InternalName.make('size'), 1, Geom.NTFloat32, Geom.COther) format = GeomVertexFormat() format.addArray(array) format = GeomVertexFormat.registerFormat(format) vdata = GeomVertexData('vdata', format, Geom.UH_static) vdata.unclean_set_num_rows(len(points)) self.vwriter = GeomVertexWriter(vdata, 'vertex') self.colorwriter = GeomVertexWriter(vdata, 'color') if self.use_sizes: self.sizewriter = GeomVertexWriter(vdata, 'size') geompoints = GeomPoints(Geom.UH_static) geompoints.reserve_num_vertices(len(points)) index = 0 for (point, color, size) in zip(points, colors, sizes): self.vwriter.addData3f(*point) #self.colorwriter.addData3f(color[0], color[1], color[2]) self.colorwriter.addData4f(*color) if self.use_sizes: self.sizewriter.addData1f(size) geompoints.addVertex(index) geompoints.closePrimitive() index += 1 geom = Geom(vdata) geom.addPrimitive(geompoints) return geom def update_arrays(self, points, colors, sizes): self.gnode.removeAllGeoms() self.geom = self.makeGeom(points, colors, sizes) self.gnode.addGeom(self.geom)
class LineMesh: def __init__(self, game, color=(1,1,1,1)): self.game = game self.node = GeomNode("lines") self.np = NodePath(self.node) self.np.reparentTo(self.game.render) self.np.setShaderOff() self.format = makeVertexFormat() self.vertices = [] self.lines = [] self.color = color def getNbVertices(self): return len(self.vertices) def getNbLines(self): return len(self.lines) def getRandomColor(self): return getRandomColor() ''' c1 = random.uniform(0,1) c2 = random.uniform(0,1) c3 = random.uniform(0,1) return (c1, c2, c3, 1) ''' nbVertices = property(getNbVertices) nbLines = property(getNbLines) def reset(self): self.clearMesh() self.vertices = [] self.lines = [] def clearMesh(self): #if self.np: # self.np.remove() self.node.removeAllGeoms() self.vdata = GeomVertexData ('name', self.format, Geom.UHStatic) self.vWriter = GeomVertexWriter (self.vdata, 'vertex') self.cWriter = GeomVertexWriter (self.vdata, 'color') self.geom = Geom(self.vdata) #self.node = GeomNode("lines") self.node.addGeom(self.geom) #self.np = NodePath(self.node) #self.np.reparentTo(self.game.render) def draw(self): self.clearMesh() #print "vertices : %s" % (self.vertices) for p in self.vertices: self.vWriter.addData3f(p[0], p[1], p[2]) self.cWriter.addData4f(self.color) lines = GeomLinestrips (Geom.UHStatic) for line in self.lines: lines.addVertices(line[0], line[1]) lines.closePrimitive() self.geom.addPrimitive (lines) def addLineStrip(self, pointList, closed = False): nbPts = len(pointList) if nbPts < 2: return nbV = self.nbVertices #for p in pointList: # self.vertices.append(p) self.vertices.extend(pointList) for i in range(nbPts-1): self.lines.append((nbV + i, nbV + i + 1)) if closed: self.lines.append((nbV + nbPts - 1, nbV)) def addBox(self, size, pos, rot=0): x = size[0] / 2.0 y = size[1] / 2.0 z = size[2] / 2.0 #print "drawing lines, x = %s" % (x) # base points p1 = Point3(-x,-y,-z) p2 = Point3(x,-y,-z) p3 = Point3(x,y,-z) p4 = Point3(-x,y,-z) # top points p1t = Point3(-x,-y,z) p2t = Point3(x,-y,z) p3t = Point3(x,y,z) p4t = Point3(-x,y,z) pList = [p1, p2, p3, p4, p1t, p2t, p3t, p4t] #dP = Point3(pos[0], pos[1], pos[2]) newList = translatePoints(pList, dP) newList = rotatePoints(newList, rot) self.addLineStrip(newList[0:4], True) self.addLineStrip(newList[4:8], True) for i in range(4): self.addLineStrip([newList[i], newList[i+4]], False) def addSideWall(self, pointList, dh=2.0, closed = False): nbPts = len(pointList) if nbPts < 2: return try: dh = float(dh) dh = (0, 0, dh) except: pass topPointList = translatePoints(pointList, dh) self.addLineStrip(pointList, closed) self.addLineStrip(topPointList, closed) for i in range(nbPts): p1 = pointList[i] p1t = topPointList[i] self.addLineStrip([p1, p1t]) def addThickWall(self, pointList, dh, thickness, closed, capped = False): rPointList, lPointList = getWallPoints(pointList, dh, thickness, closed, capped) if closed: self.addSideWall(rPointList, dh, True) self.addSideWall(lPointList, dh, True) else: newList = [] newList.extend(rPointList) lPointList.reverse() newList.extend(lPointList) self.addSideWall(newList, dh, True) #print "adding wall, pointList = %s" % (newList) #self.addPrism(newList, h) def addPrism(self, pointList, dh = 0, pos=(0,0,0), rot=(0,0,0), closed = True): nbPts = len(pointList) if nbPts < 3: return try: dh = float(dh) dh = (0, 0, dh) except: pass topPointList = translatePoints(pointList, dh) pointList = rotatePoints(pointList, rot) topPointList = rotatePoints(topPointList, rot) pointList = translatePoints(pointList, pos) topPointList = translatePoints(topPointList, pos) self.addLineStrip(pointList, True) self.addLineStrip(topPointList, True) for i in range(nbPts): self.addLineStrip([pointList[i], topPointList[i+nbPts]], False) def addCylinder(self, pA, pB, radius = 2.0, nbSides = 16): normalVec = pB - pA basePoints = getCirclePoints(pA, radius, normalVec, nbSides) self.addPrism(basePoints, normalVec) def addCylinderShear(self, pA, normalVec, dh, radius = 2.0, nbSides = 16, pos=(0,0,0), rot=(0,0,0), closed = True): pointList = getCirclePoints(pA, radius, normalVec, nbSides) self.addPrism(pointList, dh, pos, rot, closed)
class LineMesh: def __init__(self, game, color=(1, 1, 1, 1)): self.game = game self.node = GeomNode("lines") self.np = NodePath(self.node) self.np.reparentTo(self.game.render) self.np.setShaderOff() self.format = makeVertexFormat() self.vertices = [] self.lines = [] self.color = color def getNbVertices(self): return len(self.vertices) def getNbLines(self): return len(self.lines) def getRandomColor(self): return getRandomColor() ''' c1 = random.uniform(0,1) c2 = random.uniform(0,1) c3 = random.uniform(0,1) return (c1, c2, c3, 1) ''' nbVertices = property(getNbVertices) nbLines = property(getNbLines) def reset(self): self.clearMesh() self.vertices = [] self.lines = [] def clearMesh(self): #if self.np: # self.np.remove() self.node.removeAllGeoms() self.vdata = GeomVertexData('name', self.format, Geom.UHStatic) self.vWriter = GeomVertexWriter(self.vdata, 'vertex') self.cWriter = GeomVertexWriter(self.vdata, 'color') self.geom = Geom(self.vdata) #self.node = GeomNode("lines") self.node.addGeom(self.geom) #self.np = NodePath(self.node) #self.np.reparentTo(self.game.render) def draw(self): self.clearMesh() #print "vertices : %s" % (self.vertices) for p in self.vertices: self.vWriter.addData3f(p[0], p[1], p[2]) self.cWriter.addData4f(self.color) lines = GeomLinestrips(Geom.UHStatic) for line in self.lines: lines.addVertices(line[0], line[1]) lines.closePrimitive() self.geom.addPrimitive(lines) def addLineStrip(self, pointList, closed=False): nbPts = len(pointList) if nbPts < 2: return nbV = self.nbVertices #for p in pointList: # self.vertices.append(p) self.vertices.extend(pointList) for i in range(nbPts - 1): self.lines.append((nbV + i, nbV + i + 1)) if closed: self.lines.append((nbV + nbPts - 1, nbV)) def addBox(self, size, pos, rot=0): x = size[0] / 2.0 y = size[1] / 2.0 z = size[2] / 2.0 #print "drawing lines, x = %s" % (x) # base points p1 = Point3(-x, -y, -z) p2 = Point3(x, -y, -z) p3 = Point3(x, y, -z) p4 = Point3(-x, y, -z) # top points p1t = Point3(-x, -y, z) p2t = Point3(x, -y, z) p3t = Point3(x, y, z) p4t = Point3(-x, y, z) pList = [p1, p2, p3, p4, p1t, p2t, p3t, p4t] #dP = Point3(pos[0], pos[1], pos[2]) newList = translatePoints(pList, dP) newList = rotatePoints(newList, rot) self.addLineStrip(newList[0:4], True) self.addLineStrip(newList[4:8], True) for i in range(4): self.addLineStrip([newList[i], newList[i + 4]], False) def addSideWall(self, pointList, dh=2.0, closed=False): nbPts = len(pointList) if nbPts < 2: return try: dh = float(dh) dh = (0, 0, dh) except: pass topPointList = translatePoints(pointList, dh) self.addLineStrip(pointList, closed) self.addLineStrip(topPointList, closed) for i in range(nbPts): p1 = pointList[i] p1t = topPointList[i] self.addLineStrip([p1, p1t]) def addThickWall(self, pointList, dh, thickness, closed, capped=False): rPointList, lPointList = getWallPoints(pointList, dh, thickness, closed, capped) if closed: self.addSideWall(rPointList, dh, True) self.addSideWall(lPointList, dh, True) else: newList = [] newList.extend(rPointList) lPointList.reverse() newList.extend(lPointList) self.addSideWall(newList, dh, True) #print "adding wall, pointList = %s" % (newList) #self.addPrism(newList, h) def addPrism(self, pointList, dh=0, pos=(0, 0, 0), rot=(0, 0, 0), closed=True): nbPts = len(pointList) if nbPts < 3: return try: dh = float(dh) dh = (0, 0, dh) except: pass topPointList = translatePoints(pointList, dh) pointList = rotatePoints(pointList, rot) topPointList = rotatePoints(topPointList, rot) pointList = translatePoints(pointList, pos) topPointList = translatePoints(topPointList, pos) self.addLineStrip(pointList, True) self.addLineStrip(topPointList, True) for i in range(nbPts): self.addLineStrip([pointList[i], topPointList[i + nbPts]], False) def addCylinder(self, pA, pB, radius=2.0, nbSides=16): normalVec = pB - pA basePoints = getCirclePoints(pA, radius, normalVec, nbSides) self.addPrism(basePoints, normalVec) def addCylinderShear(self, pA, normalVec, dh, radius=2.0, nbSides=16, pos=(0, 0, 0), rot=(0, 0, 0), closed=True): pointList = getCirclePoints(pA, radius, normalVec, nbSides) self.addPrism(pointList, dh, pos, rot, closed)