def __init__(self, this_room, this_door, conn_room=None, conn_door=None): self.this_door = this_door self.this_room = this_room self.conn_door = conn_door self.conn_room = conn_room self.hinge = self.this_door.attach_new_node('hinge') self.hinge.set_h(180) self.outside_in = self.hinge.attach_new_node('lookin_in') self.buff = None self._active = False self.deactivate() self._collision_quad = core.CollisionPolygon( core.Point3(0.75, 0, 0), core.Point3(-0.75, 0, 0), core.Point3(-0.75, 0, 2.5), core.Point3(0.75, 0, 2.5)) cnode = core.CollisionNode( f'{self.this_room.name}_{self.this_door.name}') cnode.add_solid(self._collision_quad) cnode.set_from_collide_mask(core.CollideMask.all_off()) cnode.set_into_collide_mask(0x2) self.collider = self.this_door.attach_new_node(cnode) self.collider.set_pos(self.this_door, (0, 0.05, 0)) self.collider.set_hpr(self.this_door, (0, 0, 0)) #self.collider.show() self.collider.set_collide_mask(core.BitMask32(0x2))
def floor_plane(self): point_1_2d = self.origin_2d point_2_2d = core.Point2(point_1_2d.x + 1, point_1_2d.y) point_3_2d = core.Point2(point_1_2d.x, point_1_2d.y + 1) return plane.Plane( core.Point3(point_1_2d.x, point_1_2d.y, self.floor_z_at_point(point_1_2d)), core.Point3(point_2_2d.x, point_2_2d.y, self.floor_z_at_point(point_2_2d)), core.Point3(point_3_2d.x, point_3_2d.y, self.floor_z_at_point(point_3_2d)), )
def get_above_draw_offset(self) -> typing.Optional[core.Vec3]: if self._sector_below_floor is None: return None point_2d = self.min_point() below_point_2d = self._sector_below_floor.min_point() point = core.Point3(point_2d.x, point_2d.y, self.floor_z) below_point = core.Point3( below_point_2d.x, below_point_2d.y, self._sector_below_floor.ceiling_z ) return point - below_point
def intersect_line(self, point: core.Point3, direction: core.Vec3) -> core.Point2: sprite_position = self.origin sprite_plane = plane.Plane( sprite_position, core.Point3(sprite_position.x + 1, sprite_position.y, sprite_position.z), core.Point3(sprite_position.x, sprite_position.y + 1, sprite_position.z), ) intersection = sprite_plane.intersect_line(point, direction) if intersection is not None: return intersection.xy
def update( self, current_point: core.Point2, drawing_points: typing.List[core.Point2], insert: bool, ): self.clear_debug() segments = core.LineSegs() segments.set_thickness(4) points = drawing_points if current_point is not None: points = points + [current_point] if not points: return second_points = points[1:] if insert: second_points += points[:1] walls = zip(points, second_points) for point_1, point_2 in walls: point_3d_1 = core.Point3(point_1.x, point_1.y, self._floor_z_at_point(point_1)) segments.draw_to(point_3d_1) point_3d = core.Point3(point_1.x, point_1.y, self._ceiling_z_at_point(point_1)) segments.draw_to(point_3d) point_3d = core.Point3(point_2.x, point_2.y, self._ceiling_z_at_point(point_2)) segments.draw_to(point_3d) point_3d = core.Point3(point_2.x, point_2.y, self._floor_z_at_point(point_2)) segments.draw_to(point_3d) segments.draw_to(point_3d_1) debug_view_node = segments.create("draw_debug") self._debug_view = self._camera_collection.scene.attach_new_node( debug_view_node) self._debug_view.set_depth_write(False) self._debug_view.set_depth_test(False) self._debug_view.set_bin("fixed", constants.FRONT_MOST)
def __init__(self, width, height, depth): self.forms = {f.name: f for f in load_forms()} Block.FORMS = self.forms self.width = width self.height = height self.depth = depth self.size = core.Point3(self.width, self.height, self.depth) self.midpoint = core.Point3(self.width // 2, self.height // 2, self.depth // 2) self.blocks = {coords: None for coords in self.grid()} self.notify = directNotify.newCategory('world') messenger.accept('console-command', self, self.command)
def get_part_at_point(self, point: core.Point3): if self.is_facing or self.is_directional: if self.is_directional: if not self.segment.point_on_line(point.xy): return None if point.z <= self.z_at_bottom and point.z >= self.z_at_top: return self._name return None relative_point = point - self.position theta_radians = math.radians(self.theta) relative_point = core.Point3( math.cos(theta_radians) * relative_point.x - math.sin(theta_radians) * relative_point.y, math.sin(theta_radians) * relative_point.x + math.cos(theta_radians) * relative_point.y, relative_point.z, ) half_size = self.size / 2 if (relative_point.x >= -half_size.x and relative_point.x <= half_size.x and relative_point.y >= -half_size.y and relative_point.y <= half_size.y and round(relative_point.z) == 0): return self._name return None
def get_objects(self): result: typing.List[highlight_details] = [] hit = core.Point3(self._start.x, self._start.y, 0) for sector in self._sectors: highlight_count = 0 for wall in sector.walls: if self._point_in_marquee(wall.point_1): if self._point_in_marquee(wall.point_2): part = wall.default_part else: part = f"{wall.vertex_part_name}_highlight" highlight = highlight_details.HighlightDetails( wall, part, hit) highlight_count += 1 result.append(highlight) if highlight_count == len(sector.walls): highlight = highlight_details.HighlightDetails( sector, sector.default_part, hit) result.append(highlight) for sprite in sector.sprites: if self._point_in_marquee(sprite.origin_2d): highlight = highlight_details.HighlightDetails( sprite, sprite.default_part, hit) result.append(highlight) return result
def _find_highlight(self, current_highlight: highlight_details.HighlightDetails): if self._editor.builder_sector is None: start_sector = self._editor.sectors.sectors[0] else: start_sector = self._editor.builder_sector highlighted_sector = point_sector_finder.PointSectorFinder( self._position, self._editor.sectors.sectors, start_sector).get_new_sector() closest_distance = self._vertex_offset if highlighted_sector is None: closest_highlight: map_objects.EmptyObject = None for sector in self._editor.sectors.sectors: hit_z = sector.floor_z_at_point(self._position) hit = core.Point3(self._position.x, self._position.y, hit_z) highlight, new_distance = self._find_highlight_in_sector( closest_distance, sector, hit) if highlight is not None and new_distance < closest_distance: closest_distance = new_distance closest_highlight = highlight return closest_highlight hit = self._get_hit(highlighted_sector) highlight, _ = self._find_highlight_in_sector(closest_distance, highlighted_sector, hit) if highlight is not None: return highlight return highlight_details.HighlightDetails( highlighted_sector, map_objects.EditorSector.FLOOR_PART, hit)
def toggle_button(self): self.toggle_state = not self.toggle_state parallel = [] for x, y in self.toggle_tiles: type = self.level.get_tile(x, y) tile = self.tiles[(x, y)] spatial = self.component_for_entity(tile, components.Spatial) pos = core.Point3(spatial.path.get_pos()) if type.is_passable(1, self.toggle_state): pos.y = y pos.z = 0.0 parallel.append( spatial.path.hprInterval(0.75, (0, 0, 0), blendType='easeInOut')) parallel.append( spatial.path.posInterval(0.75, pos, blendType='easeInOut')) else: pos.y = y - 0.5 pos.z = -0.5 parallel.append( spatial.path.hprInterval(0.75, (0, 90, 0), blendType='easeInOut')) parallel.append( spatial.path.posInterval(0.75, pos, blendType='easeInOut')) return Parallel(*parallel).start()
def update( self, snapper: grid_snapper.GridSnapper, position: core.Point3, sector: map_objects.EditorSector, ): snapped_hit_2d = snapper.snap_to_grid_2d(position.xy) if sector is None: snapped_z = 0.0 slope = core.Vec2(0, 0) else: snapped_z = sector.floor_z_at_point(snapped_hit_2d) slope = sector.floor_slope_direction() snapped_hit = core.Point3(snapped_hit_2d.x, snapped_hit_2d.y, snapped_z) shapes.align_grid_to_angle(self._camera_collection.scene, self._small_grid, snapper.grid_size, slope) shapes.align_grid_to_angle(self._camera_collection.scene, self._big_grid, self._LARGE_GRID_SIZE, slope) self._vertical_grid.set_scale(snapper.grid_size) self._small_grid.set_pos(snapped_hit) self._vertical_grid.set_pos(snapped_hit) big_snap_x = editor.snap_to_grid(snapped_hit.x, self._LARGE_GRID_SIZE) big_snap_y = editor.snap_to_grid(snapped_hit.y, self._LARGE_GRID_SIZE) self._big_grid.set_pos(big_snap_x, big_snap_y, snapped_hit.z)
def intersect_line(self, point: core.Point3, direction: core.Vec3) -> core.Point2: if self.is_facing: direction_2d = core.Vec2(direction.x, direction.y) orthogonal = core.Vec2(direction_2d.y, -direction_2d.x) orthogonal.normalize() half_width = self.size.x / 2 orthogonal *= half_width return segment.Segment(self.position_2d + orthogonal, self.position_2d - orthogonal).intersect_line( point.xy, direction_2d) elif self.is_floor: sprite_position = self.position sprite_direction = self.get_direction() sprite_plane = plane.Plane( sprite_position, core.Point3(sprite_position.x + 1, sprite_position.y, sprite_position.z), core.Point3(sprite_position.x, sprite_position.y + 1, sprite_position.z), ) intersection = sprite_plane.intersect_line(point, direction) if intersection is not None: return intersection.xy else: sprite_position = self.position sprite_direction = self.get_orthogonal() sprite_plane = plane.Plane( sprite_position, core.Point3( sprite_position.x + sprite_direction.x, sprite_position.y + sprite_direction.y, sprite_position.z, ), core.Point3(sprite_position.x, sprite_position.y, sprite_position.z - 1), ) intersection = sprite_plane.intersect_line(point, direction) if intersection is not None: return intersection.xy
def _move_selection_marquee(self, total_delta: core.Vec2, delta: core.Vec2): self._clear_marquee_display() self._marquee_end = self._marquee_start + total_delta start, end = self._get_marquee() card_maker = core.CardMaker("marquee") card_maker.set_frame( core.Point3(start.x, start.y, -constants.REALLY_BIG_NUMBER), core.Point3(start.x, end.y, -constants.REALLY_BIG_NUMBER), core.Point3(end.x, end.y, -constants.REALLY_BIG_NUMBER), core.Point3(end.x, start.y, -constants.REALLY_BIG_NUMBER), ) card_maker.set_color(1, 1, 0, 0.5) marquee_node = card_maker.generate() self._marquee_display: core.NodePath = ( self._camera_collection.scene.attach_new_node(marquee_node)) self._marquee_display.set_transparency(True)
def _get_marquee(self): start_2d = core.Point3() far = core.Point3() self._camera.lens.extrude(self._marquee_start, start_2d, far) end_2d = core.Point3() far = core.Point3() self._camera.lens.extrude(self._marquee_end, end_2d, far) start = self._camera_collection.scene.get_relative_point( self._camera.camera, start_2d) end = self._camera_collection.scene.get_relative_point( self._camera.camera, end_2d) left = min(start.x, end.x) right = max(start.x, end.x) bottom = min(start.y, end.y) top = max(start.y, end.y) return core.Point2(left, bottom), core.Point2(right, top)
def _project_point(self, point: core.Point2) -> core.Point3: point_3d = core.Point3(point.x + self._sector_offset.x, point.y + self._sector_offset.y, 0) result = self._transformation_matrix.xform_point_general(point_3d) if result.z >= WallBunch.ABSOLUTE_MAX_Z: if result.x > 0: result.x = -constants.REALLY_BIG_NUMBER else: result.x = constants.REALLY_BIG_NUMBER return result
def _extrude_mouse_to_scene_transform(self, check_buttons=False): if not self._mouse_watcher.has_mouse(): return None, None if check_buttons and any( self._mouse_watcher.is_button_down(button) for button in clicker.Clicker.ALL_MOUSE_BUTTONS): return None, None mouse = self._mouse_watcher.get_mouse() source = core.Point3() target = core.Point3() self._camera.lens.extrude(mouse, source, target) source = self._camera_collection.scene.get_relative_point( self._camera.camera, source) target = self._camera_collection.scene.get_relative_point( self._camera.camera, target) return source, target
def setup_geometry(self, all_geometry: sector_geometry.SectorGeometry): self._clear_display() self._display = shapes.make_circle(all_geometry.display, core.Point3(0, 0, 0), self._RADIUS, 12) self._display.set_pos(self.origin) if self.get_type() == marker_constants.AXIS_MARKER_TAG: self._display.set_color(1, 0, 1, 0.5) else: self._display.set_color(0, 0, 1, 0.5) self._display.set_transparency(True) self._display.set_name(self._name) self._needs_geometry_reset = False
def set_selected_objects( self, objects_to_select: typing.List[empty_object.EmptyObject] ): hit_position = core.Point3(0, 0, 0) if self._highlighted is not None: hit_position = self._highlighted.hit_position self._selected = [ highlight_details.HighlightDetails(map_object, part, hit_position) for map_object in objects_to_select for part in map_object.get_all_parts() ] self.update_selected_target_view()
def finishLoadingForrest(self, models): # This function is used as callback to loader.loadModel, and called # when all of the models have finished loading. # Attach the models to the scene graph. minLimit, maxLimit = models[0].getTightBounds() dimensions = p3dc.Point3(maxLimit - minLimit) compList = [dimensions.getX(), dimensions.getY(), dimensions.getZ()] for model in models: model.reparentTo(self.forest) model.setPos(model.getPos()[0], model.getPos()[1], model.getPos()[2] - 1) model.setScale(1 / max(compList) * 150)
def _draw_debug_clip(self, colour, left: float, right: float): depth = 0.95 builder_pos = self._camera_collection.get_builder_position() screen_left = core.Point3(left, 0, depth) left_3d = self._inverse_transformation_matrix.xform_point_general( screen_left) left_3d.z = builder_pos.z screen_right = core.Point3(right, 0, depth) right_3d = self._inverse_transformation_matrix.xform_point_general( screen_right) right_3d.z = builder_pos.z z_offset = core.Vec3(0, 0, -1024) self._clip_card_maker.set_frame( left_3d - z_offset, right_3d - z_offset, right_3d + z_offset, left_3d + z_offset, ) self._clip_card_maker.set_color(*colour, 0.5) self._clip_view.attach_new_node(self._clip_card_maker.generate())
def move(self, move_delta: core.Vec3, snapper: grid_snapper.GridSnapper): move_delta_2d = snapper.snap_to_grid_2d(move_delta.xy) for wall, start_point in zip(self._sector.walls, self._wall_start_points): new_position = start_point + move_delta_2d for sub_wall in wall.all_walls_at_point_1(): sub_wall.teleport_point_1_to(new_position) for sprite, start_point in zip(self._sector.sprites, self._sprite_start_points): new_position = core.Point3( start_point.x + move_delta_2d.x, start_point.y + move_delta_2d.y, start_point.z, ) sprite.move_to(new_position)
def _hit_3d_and_squared_distance_from_hit_2d( self, intersection_2d: core.Point2, point: core.Point3, normal_2d_length: float, normal: core.Vec3, ): line_portion = (intersection_2d - point.xy).length() / normal_2d_length hit = core.Point3( intersection_2d.x, intersection_2d.y, point.z + normal.z * line_portion ) above_floor = hit.z <= self._sector.floor_z_at_point(intersection_2d) below_ceiling = hit.z >= self._sector.ceiling_z_at_point(intersection_2d) if above_floor and below_ceiling: return hit, (hit - point).length_squared() return None, None
def __init__( self, start_sector: EditorSector, camera_collection: cameras.Cameras, clipping_debug: core.NodePath, sector_offset=core.Point3(0, 0, 0), ): self._start_sector = start_sector self._clip_buffer = numpy.array([WallBunch.ABSOLUTE_MAX_Z] * self._CLIP_WIDTH).astype("float32") self._camera_collection = camera_collection self._transformation_matrix = ( core.Mat4.translate_mat(-sector_offset.x, -sector_offset.y, 0) * self._camera_collection.get_clipping_transform()) self._visible_sectors: typing.Set[EditorSector] = set() self._sector_offset = sector_offset self._clipping_debug = clipping_debug if constants.PORTALS_DEBUGGING_ENABLED: self._inverse_transformation_matrix = core.Mat4() self._inverse_transformation_matrix.invert_from( self._transformation_matrix) self._clip_view: core.NodePath = self._clipping_debug.attach_new_node( "clip_view") self._clip_view.set_transparency(True) self._clip_view.set_bin("fixed", constants.FRONT_MOST) self._clip_card_maker = core.CardMaker("clip_view") self._clip_buffer_colours = numpy.array( [[0, 0, 0]] * self._CLIP_WIDTH).astype("float32") self._debug_colour_index = 0 self._debug_geometry_node = core.GeomNode("clipper") self._debug_geometry: core.NodePath = self._clipping_debug.attach_new_node( self._debug_geometry_node) self._debug_geometry.set_depth_write(False) self._debug_geometry.set_depth_test(False) self._debug_geometry.set_bin("fixed", constants.FRONT_MOST) self._debug_geometry.set_transparency(True) inverse_projection = core.Mat4().invert_from( self._transformation_matrix)
def get_part_at_point(self, point: core.Point3): relative_point = point - self.origin theta_radians = math.radians(self.theta) relative_point = core.Point3( math.cos(theta_radians) * relative_point.x - math.sin(theta_radians) * relative_point.y, math.sin(theta_radians) * relative_point.x + math.cos(theta_radians) * relative_point.y, relative_point.z, ) half_size = self.size / 2 if (relative_point.x >= -half_size.x and relative_point.x <= half_size.x and relative_point.y >= -half_size.y and relative_point.y <= half_size.y and round(relative_point.z) == 0): return self._name return None
def __init__(self, graphicsInterface): ShowBase.__init__(self) # This is available as a global, but pylint gives an undefined-variable # warning if we use it that way. Looking at # https://www.panda3d.org/manual/index.php/ShowBase # I would have thought we could reference it as either # self.globalClock, direct.showbase.ShowBase.globalClock, or possibly # direct.showbase.globalClock, but none of those seems to work. To # avoid the pylint warnings, create self.globalClock manually. self.globalClock = ClockObject.getGlobalClock() self.graphicsInterface = graphicsInterface # Mapping from gids to entities. self.entities = {} # Set up event handling. self.mouseState = {} self.keys = {} self.setupEventHandlers() # Set up camera control. self.cameraHolder = self.render.attachNewNode('CameraHolder') self.cameraHolder.setPos(0, 0, 100) self.prevCameraHpr = (0, -80, 0) self.usingCustomCamera = True self.setCameraCustom() self.prevMousePos = None self.selectionBox = None self.selectionBoxNode = None self.selectionBoxOrigin = None # TODO[#3]: Magic numbers bad. self.resourceDisplay = OnscreenText(pos=(-0.98, .9), align=TextNode.ALeft, mayChange=True) # Define the ground plane by a normal (+z) and a point (the origin). self.groundPlane = core.Plane(core.Vec3(0, 0, 1), core.Point3(0, 0, 0)) self.graphicsInterface.graphicsReady(self)
def setup_lights(self): '''Adds lights to the scene ''' # ambient self.ambient_light = self.render.attach_new_node(p3d.AmbientLight('ambient')) self.ambient_light.node().set_color((0.1, 0.1, 0.1, 1.0)) self.render.set_light(self.ambient_light) # directional self.dir_light = self.render.attach_new_node(p3d.DirectionalLight('directional')) self.dir_light.node().set_color((0.1, 0.1, 0.25, 1.0)) self.dir_light.node().set_direction(p3d.Vec3(0.2,0.4,-1.0)) self.render.set_light(self.dir_light) # spot self.spot_light = self.render.attach_new_node(p3d.Spotlight('spot')) self.spot_light.node().set_color((1.0, 1.0, 1.0, 1.0)) self.spot_light.node().set_shadow_caster(True, 1024, 1024) self.spot_light.node().get_lens().set_near_far(0.1, 20.0) self.spot_light.node().get_lens().set_fov(25) self.spot_light.node().set_exponent(120.0) self.spot_light.set_pos(-8, 0, 8) self.spot_light.look_at(p3d.Point3(3,-3,0)) self.render.set_light(self.spot_light)
def __init__(self, graphicsInterface, backend, gameState): ShowBase.__init__(self) self.graphicsInterface = graphicsInterface self.backend = backend self.gameState = gameState self.groundNodes = None self.firstTick = True # This is available as a global, but pylint gives an undefined-variable # warning if we use it that way. Looking at # https://www.panda3d.org/manual/index.php/ShowBase # I would have thought we could reference it as either # self.globalClock, direct.showbase.ShowBase.globalClock, or possibly # direct.showbase.globalClock, but none of those seems to work. To # avoid the pylint warnings, create self.globalClock manually. self.globalClock = ClockObject.getGlobalClock() # Set up event handling. self.mouseState = {} self.keys = {} self.setupEventHandlers() # Set up camera control. self.cameraHolder = self.render.attachNewNode('CameraHolder') self.cameraHolder.setPos(0, 0, 100) self.prevCameraHpr = (0, -80, 0) self.usingCustomCamera = True self.setCameraCustom() self.prevMousePos = None self.selectionBox = None self.selectionBoxNode = None self.selectionBoxOrigin = None # Define the ground plane by a normal (+z) and a point (the origin). self.groundPlane = core.Plane(core.Vec3(0, 0, 1), core.Point3(0, 0, 0)) graphicsInterface.graphicsReady(self)
def start_drawing( self, editor: map_editor.MapEditor, sector: map_objects.EditorSector, hit_point: core.Point3, insert: bool, ): self._editor = editor self._sector = sector if insert and self._sector is not None: for editor_wall in self._sector.walls: distance_to_wall = editor_wall.line_segment.get_point_distance( hit_point.xy) if (distance_to_wall is not None and distance_to_wall < self._editor.snapper.grid_size): insert = False projected_point = editor_wall.line_segment.project_point( hit_point.xy) hit_point.x = projected_point.x hit_point.y = projected_point.y break self._insert = insert position_2d = self._editor.snapper.snap_to_grid_2d(hit_point.xy) if not self._insert: point_neat_wall = self._point_near_wall(hit_point.xy) if point_neat_wall is not None: position_2d = point_neat_wall self._current_point = position_2d self._points[:] = [self._current_point] grid_position = core.Point3(position_2d.x, position_2d.y, self._floor_z_at_point(position_2d)) self._display.start_drawing(self._sector, grid_position, self._editor.snapper) self._update_debug_display()
def update_move_debug_2d( self, start_position: core.Point2, new_position: core.Point2, height: float ): start = core.Point3(start_position.x, start_position.y, height) end = core.Point3(new_position.x, new_position.y, height) self.update_move_debug(start, end)
def gotModel(self, mdl, filename, context): self.currentLoadContext = None if not mdl or mdl.isEmpty(): context.createNextAsset() return # If there's no geomnode, there is no model! if mdl.find("**/+GeomNode").isEmpty(): context.createNextAsset() return mdl.reparentTo(self.render) # Determine a good offset point to take the thumbnail snapshot mins = core.Point3() maxs = core.Point3() mdl.calcTightBounds(mins, maxs) size = maxs - mins center = (mins + maxs) / 2.0 # Choose the longest axis as the radius radius = size.length() / 2 fov = self.lens.getFov() distance = (radius / float(math.tan(core.deg2Rad(min(fov[0], fov[1]) / 2.0)))) # Ensure the far plane is far enough back to see the entire object. idealFarPlane = distance + radius * 1.5 self.lens.setFar(max(self.lens.getDefaultFar(), idealFarPlane)) # And that the near plane is far enough forward. idealNearPlane = distance - radius self.lens.setNear(min(self.lens.getDefaultNear(), idealNearPlane)) self.camera.setPos(center + self.camera.getQuat().xform(core.Vec3.forward() * -distance)) # Render the model to the back buffer self.buffer.setActive(True) base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() # Fetch the pixels into a PNMImage image = core.PNMImage() self.buffer.getScreenshot(image) self.buffer.setActive(False) mdl.removeNode() # Store the pixels in a QPixmap qimage = QtGui.QImage(image.getXSize(), image.getYSize(), QtGui.QImage.Format_RGB888) for x in range(image.getXSize()): for y in range(image.getYSize()): col = CIGlobals.vec3LinearToGamma(image.getXelA(x, y)) qimage.setPixelColor( x, y, QtGui.QColor(int(col[0] * 255), int(col[1] * 255), int(col[2] * 255), int(col[3] * 255))) pixmap = QtGui.QPixmap.fromImage(qimage) icon = QtGui.QIcon(pixmap) self.modelThumbnails[filename] = icon context.addAssetItem(icon, filename) context.createNextAsset()