def line_intersection( segment_1_point_1: core.Point2, segment_1_point_2: core.Point2, segment_2_point_1: core.Point2, segment_2_point_2: core.Point2, ): segment_1_diff = segment_1_point_1 - segment_1_point_2 segment_2_diff = segment_2_point_1 - segment_2_point_2 x_diff = core.Vec2(segment_1_diff.x, segment_2_diff.x) y_diff = core.Vec2(segment_1_diff.y, segment_2_diff.y) divisor = determinant(x_diff, y_diff) if divisor == 0: raise ValueError("Lines do not intersect") det = core.Vec2( determinant(segment_1_point_1, segment_1_point_2), determinant(segment_2_point_1, segment_2_point_2), ) x = determinant(det, x_diff) / divisor y = determinant(det, y_diff) / divisor return core.Point2(x, y)
def get_child_aabb(self): hbb = self.bb / 2 return [ AABB(self.origin + core.Vec2(-hbb.x, hbb.y), hbb), AABB(self.origin + core.Vec2(hbb.x, hbb.y), hbb), AABB(self.origin + core.Vec2(-hbb.x, -hbb.y), hbb), AABB(self.origin + core.Vec2(hbb.x, -hbb.y), hbb) ]
def camera_update(self, task): '''This function is a task run each frame, it controls the camera movement/rotation/zoom''' #dt is 'delta time' - how much time elapsed since the last time the task ran #we will use it to keep the motion independent from the framerate dt = globalClock.get_dt() #we'll be tracking the mouse #first we need to check if the cursor is in the window if self.mouseWatcherNode.has_mouse(): #let's see where the mouse cursor is now mouse_pos = self.mouseWatcherNode.get_mouse() #let's see how much it moved from last time, or if this is the first frame if self.last_mouse_pos is None: self.last_mouse_pos = p3d.Vec2(mouse_pos) return task.again mouse_delta = mouse_pos - self.last_mouse_pos #and let's remember where it is this frame so we can #check next frame where it was self.last_mouse_pos = p3d.Vec2(mouse_pos) #camera zoom if self.zoom != 0.0: #let's see how far the camera is from the pivot point distance = self.camera.get_distance(self.camera_node) #we don't want it to be too close nor to far away if (distance > self.zoom_limit[0] and self.zoom > 0.0) or \ (distance < self.zoom_limit[1] and self.zoom < 0.0): #move the camera away or closer to the pivot point #we do that by moving the camera relative to itself self.camera.set_y(self.camera, self.zoom * dt * self.camera_zoom_speed) if self.zoom >= 0.0: self.zoom -= dt * self.camera_zoom_damping else: self.zoom += dt * self.camera_zoom_damping else: self.zoom = 0.0 if self.key_down['rotate']: h = self.camera_node.get_h( ) - mouse_delta.x * self.camera_rotation_speed self.camera_node.set_h(h) p = self.camera_gimbal.get_p( ) - mouse_delta.y * self.camera_rotation_speed p = min(max(p, self.camera_p_limit.x), self.camera_p_limit.y) self.camera_gimbal.set_p(p) if self.key_down['relative_move']: pos = p3d.Vec3(mouse_delta.x, 0, mouse_delta.y) pos = self.camera_node.get_pos( self.camera) - pos * self.camera_move_speed self.camera_node.set_pos(self.camera, pos) elif self.key_down['move']: pos = p3d.Vec3(mouse_delta.x, mouse_delta.y, 0) self.camera_node.set_pos(self.camera_node, pos * self.camera_move_speed) return task.again
def update(self, dt): if self.mwn.has_mouse(): mouse_delta = core.Vec2(self.mwn.get_mouse_x(), self.mwn.get_mouse_y()) self.focus_offset.set_x(mouse_delta.x * common.MX_MAX) self.focus_offset.set_z(mouse_delta.y * common.MY_MAX) f_pos = self.focus_offset.get_pos(self.root) z_diff = f_pos.z + common.Z_OFFSET - self.cam_z self.dummy.set_pos(f_pos) h = util.clamp_angle(self.dummy.get_h()) t = util.clamp_angle(self.follow.get_h() - h) * dt self.dummy.set_h(h + t * common.TURN_RATE) x, y, z = self.z_dummy.get_pos(self.root) z_diff += self.sample_z(x, y) - z if z_diff < 0: z_diff = max(common.Z_RATE * -dt, z_diff) else: z_diff = min(common.Z_RATE * dt, z_diff) self.cam_z = common.Z_OFFSET + z_diff self.cam.set_pos(self.root, self.dummy.get_pos()) self.cam.set_y(self.dummy, common.Y_OFFSET) self.cam.set_z(self.dummy, self.cam_z) self.cam.look_at(f_pos + common.FOCUS_POINT)
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 __init__(self, p, r, callback=None, ghost=False): if p.get_num_components() > 2: p = p.xy self.point = p self.r = r self.aabb = util.AABB(p, core.Vec2(r)) self.callback = callback self.ghost = ghost
def snap_to_angular_grid_2d(self, direction: core.Vec2): theta = math.atan2(direction.y, direction.x) theta = self.snap_to_angular_grid(math.degrees(theta)) cos_theta = math.cos(math.radians(theta)) sin_theta = math.sin(math.radians(theta)) return core.Vec2(cos_theta, sin_theta)
def woods(self): self.setup_fns(noise_type=common.WN_TYPE, cell_distance_func=common.WN_DIST_FUNC, cell_return_type=common.WN_RET_TYPE, fractal_octaves=common.WN_FRACTAL_OCT) c = self.fns.genAsGrid(self.terrain_grid)[0] c = c[:common.T_XY, :common.T_XY] c = (common.W_CELL_TYPE_COUNT - 1) / (c.max() - c.min()) * (c - c.min()) self.fns.cell.returnType = fns.CellularReturnType.Distance2Div b = self.fns.genAsGrid(self.terrain_grid)[0] b = b[:common.T_XY, :common.T_XY] b = 1 / (b.max() - b.min()) * (b - b.min()) b = b**2 > common.W_BOUND_CLIP fltr = np.zeros(c.shape) wood_cells = random.sample(range(common.W_CELL_TYPE_COUNT), common.W_WOOD_CELL_COUNT) for i in wood_cells: gt = c >= i lt = c < i + 1 f = gt * lt fltr[f] = 1 fltr[b] = 0 fltr[sdf.circle(fltr.shape, 120)] = 0 obelisk_circle = sdf.circle((30, 30), 15) obelisk_coordinates = [(825, 825)] for i in range(3): while True: cx, cy = 500, 500 while 400 < cx < 600 or 400 < cy < 600: cx, cy = np.random.randint(150, 950, 2) ok = True for x, y in obelisk_coordinates: d = (core.Vec2(x, y) - core.Vec2(cx, cy)).length() if d < 140: ok = False if ok: if np.sum(fltr[cy - 15:cy + 15, cx - 15:cx + 15]) > 300: obelisk_coordinates.append((cx, cy)) break for x, y in obelisk_coordinates: fltr[y - 15:y + 15, x - 15:x + 15][obelisk_circle] = 0 # Image.fromarray((fltr * 255).astype(np.uint8)).show() # Image.fromarray((b * 255).astype(np.uint8)).show() return fltr, b, obelisk_coordinates[1:]
def __init__(self, vid, point, color=core.Vec4(1), texcoord=core.Vec2(0)): self._vid = vid self._point = point self._color = color self._texcoord = texcoord self._trs = [] self._normal = None self._tangent = core.Vec3(0) self._bitangent = core.Vec3(0)
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 floor_slope_direction(self) -> core.Vec2: point_2d_x = self.origin_2d + core.Point2(1, 0) point_2d_y = self.origin_2d + core.Point2(0, 1) x_z = self.floor_z_at_point(point_2d_x) y_z = self.floor_z_at_point(point_2d_y) theta_x = -math.atan2(x_z - self.floor_z, 1) theta_y = math.atan2(y_z - self.floor_z, 1) return core.Vec2(math.degrees(theta_x), math.degrees(theta_y))
def place_devils_tower(self): self.devils_tower = self.render.attach_new_node( shape.ShapeGen().elliptic_cone(a=(240, 70), b=(200, 80), h=250, max_seg_len=20.0, exp=2.5, top_xy=(40, -20), color=core.Vec4( 0.717, 0.635, 0.558, 1), nac=False)) h = random.randint(0, 360) self.collision.add(collision.CollisionCircle( core.Vec2(0), 230, )) self.devils_tower.set_h(h) z = [] for x in (-220, 0, 220): for y in (-220, 0, 220): z.append(self.sample_terrain_z(x, y)) self.devils_tower.set_z(min(z) - 5) self.noise.setup_fns(noise_type=fns.NoiseType.Value, ) y, x = common.DT_TEX_SHAPE c = fns.empty_coords(y * x) c[0, :] = np.tile( np.cos(np.linspace(-np.pi, np.pi, x, False)) * common.DT_XY_RADIUS, y) c[1, :] = np.tile( np.sin(np.linspace(-np.pi, np.pi, x, False)) * common.DT_XY_RADIUS, y) c[2, :] = np.repeat( np.linspace(-np.pi, np.pi, x, False) * common.DT_Z_RADIUS, y) a = self.noise.fns.genFromCoords(c).reshape((y, x)) normal_map = util.sobel(a, 0.15) # Image.fromarray(normal_map).show() tex = self.loader.load_texture('rock.jpg') ts = core.TextureStage('ts') tex.set_wrap_u(core.Texture.WM_clamp) tex.set_wrap_v(core.Texture.WM_clamp) self.devils_tower.set_texture(ts, tex) self.devils_tower.set_tex_scale(ts, 1) tex = core.Texture('dt_normal_map') tex.setup_2d_texture(y, x, core.Texture.T_unsigned_byte, core.Texture.F_rgb) tex.set_ram_image_as(normal_map, 'RGB') tex.set_wrap_u(core.Texture.WM_clamp) tex.set_wrap_v(core.Texture.WM_clamp) ts = core.TextureStage('ts') ts.set_mode(core.TextureStage.M_normal) tex.reload() self.devils_tower.set_texture(ts, tex)
def _get_texture_coordinates( self, texture_size: core.Vec2, peg: float, point_1_bottom: float, point_1_top: float, point_2_bottom: float, point_2_top: float, ): x_repeat = self.x_repeat x_panning = self.x_panning y_panning = self.y_panning y_offset = (point_1_bottom - peg) * self.y_repeat uv_1 = core.Vec2( x_panning / texture_size.x, (y_panning + y_offset) / texture_size.y, ) y_offset = (point_1_top - peg) * self.y_repeat uv_2 = core.Vec2( x_panning / texture_size.x, (y_panning + y_offset) / texture_size.y, ) y_offset = (point_2_top - peg) * self.y_repeat uv_3 = core.Vec2( (x_panning + x_repeat) / texture_size.x, (y_panning + y_offset) / texture_size.y, ) y_offset = (point_2_bottom - peg) * self.y_repeat uv_4 = core.Vec2( (x_panning + x_repeat) / texture_size.x, (y_panning + y_offset) / texture_size.y, ) return uv_1, uv_2, uv_3, uv_4
def __init__(self): System.__init__(self) self.last_ptr = None base.win.request_properties(core.WindowProperties(mouse_mode=core.WindowProperties.M_confined)) self._control_mode = 'mouse' self._current_vec = core.Vec2(0) self._speed_target = 0.0 self.accept('switch-mouse-controls', self.ensure_control_mode, ['mouse', True]) self.accept('switch-gamepad-controls', self.ensure_control_mode, ['gamepad', True])
def add_vertex(self, point, color=core.Vec4(1), texcoord=core.Vec2(0)): # type: (core.Vec3, core.Vec4, core.Vec2) -> int """ Return unique vertex id, inserting a new one only if necessary. Args: point: color: texcoord: """ if point not in self._pts: self._pts[point] = Point(point, self) return self._pts[point].add_vertex(color, texcoord)
def stone_circle(r, num_stones): node_path = core.NodePath('stone_circle') rot = node_path.attach_new_node('rot') d = rot.attach_new_node('d') d.set_y(r) c = 2 * pi * r / 2 * 3 length = c / num_stones / 2 for i in range(num_stones): rot.set_h(300 / num_stones * i - 30) p = d.get_pos(node_path) s = stone(core.Vec2(length / 2, length)) s.reparent_to(node_path) s.set_pos(p) return node_path
def generate_part(model, bounds, hskew, scale_start, scale_end, hue): np = core.NodePath('track part') model.copy_to(np) np.set_shader(ROAD_SHADER) np.set_shader_input('i_hskew', hskew) np.set_shader_input('i_ymax', bounds.mmax.y) np.set_shader_input('i_scale', core.Vec2(scale_start, scale_end)) np.set_shader_input('i_len', bounds.hlen * 2) np.set_shader_input('i_hue', hue) np.set_shader_input('i_zmax', bounds.mmax.z) np.set_shader_input('i_height', bounds.mmax.z - bounds.mmin.z) np.set_shader_input('i_shade', SH_Z_SHADE_COLOR) np.set_shader_input('i_shade_exp', SH_Z_SHADE_EXP) return np
def size_inside_square_for_texture(texture: core.Texture, square_size: float): width = texture.get_x_size() height = texture.get_y_size() if width < 1 or height < 1: return None if width > height: frame_height = (height / width) * square_size frame_width = square_size else: frame_height = square_size frame_width = (width / height) * square_size return core.Vec2(frame_width, frame_height)
def __init__(self, p, a, b, h_offset=0, callback=None, ghost=False): if p.get_num_components() > 2: p = p.xy self.point = p self.a, self.b, self.h_offset = a, b, h_offset self.a_sq, self.b_sq = a**2, b**2 self.sin = sin(radians(h_offset)) self.cos = cos(radians(h_offset)) self.inv_sin = sin(radians(-h_offset)) self.inv_cos = cos(radians(-h_offset)) x = a * self.cos - b * self.sin y = b * self.cos + a * self.sin self.aabb = util.AABB(p, core.Vec2(abs(x), abs(y))) self.callback = callback self.ghost = ghost
def side_of_line( point: core.Point2, line_point_1: core.Point2, line_point_3: core.Point2, tolerance=0.0, ): line_direction = line_point_3 - line_point_1 orthogonal = core.Vec2(line_direction.y, -line_direction.x) relative_point = point - line_point_1 direction = orthogonal.dot(relative_point) if direction > tolerance: return 1 elif direction < -tolerance: return -1 return 0
def process_input(self, input, dt, level): if self.locked: return if input.get_action('interact'): self.do_action() move_x = input.get_axis('move-horizontal') move_y = input.get_axis('move-vertical') if move_x: self.speed += move_x * self.acceleration * dt self.face(move_x) elif self.speed > 0: self.speed = max(0, self.speed - self.deceleration * dt) elif self.speed < 0: self.speed = min(0, self.speed + self.deceleration * dt) delta = core.Vec2(0, 0) if move_y: delta.y = move_y * dt * MOVE_Y_SPEED if self.speed != 0: if self.speed > self.max_speed: self.speed = self.max_speed elif self.speed < -self.max_speed: self.speed = -self.max_speed delta.x = self.speed * dt pos_changed = True self.move_control.set_play_rate(self.speed * self.facing * 4.0) if not self.move_control.playing: self.move_control.loop(False) self.move_sfx.play() elif self.move_control.playing: self.move_control.stop() self.move_sfx.stop() if delta.length_squared() > 0: old_pos = self.model.get_pos() new_pos = level.adjust_move(old_pos.xy, delta) self.model.set_pos(core.LPoint3(new_pos, old_pos.z))
def _set_display_size(self, tile: int): sprite_size = self._size_for_tile(tile) if self.is_floor: y_scale = sprite_size.y z_scale = sprite_size.x else: y_scale = sprite_size.x z_scale = sprite_size.y self._sprite_collision.set_scale(sprite_size.x, y_scale, z_scale) texture_scale = core.Vec2(-1, 1) if self._sprite.sprite.stat.xflip: texture_scale.x = 1 if self._sprite.sprite.stat.yflip: texture_scale.y = -1 self._sprite_collision.set_tex_scale(core.TextureStage.get_default(), texture_scale)
def insert(self, point, data): if not self.aabb.intersect(point): raise ValueError('point is outside the bounding box') if not isinstance(point, AABB): aabb = AABB(point, core.Vec2(0)) else: aabb = point qe = QuadTree.insert_node(QuadElement(point, data, aabb)) chk_nodes = [self.root] while chk_nodes: chk_node = QuadTree.nodes[chk_nodes.pop()] if chk_node.is_leaf_node: chk_node.leafs.append(qe) continue if chk_node.children[0] is None: for i, aabb in enumerate(chk_node.aabb.get_child_aabb()): chk_node.children[i] = QuadTree.insert_node( QuadNode(aabb, chk_node.depth - 1, self.max_leaf_nodes)) # new_qes += chk_node.leafs + qes[qei:] # chk_node.leafs.clear() chk_nodes += [nid for nid in chk_node.children.values()]
def _floor_slope_direction(self): if self._sector is None: return core.Vec2(0, 0) return self._sector.floor_slope_direction()
def __init__(self, point, data, aabb=None): self.point = point self.data = data self.aabb = aabb or AABB(point, core.Vec2(0))
def optimize_geom(gnode, gi): state = gnode.get_geom_state(gi) changed = False if gnode.get_geom(gi).bounds_type != core.BoundingVolume.BT_box: gnode.modify_geom(gi).bounds_type = core.BoundingVolume.BT_box changed = True tex_attrib = state.get_attrib(core.TextureAttrib) if not tex_attrib or tex_attrib.get_num_on_stages() == 0: # Nothing to optimize. return changed stage = tex_attrib.get_on_stage(0) tex = tex_attrib.get_on_texture(stage) if tex.wrap_u == core.SamplerState.WM_repeat: tex.wrap_u = core.SamplerState.WM_clamp changed = True if tex.wrap_v == core.SamplerState.WM_repeat: tex.wrap_v = core.SamplerState.WM_clamp changed = True img = core.PNMImage() img.set_color_space(core.CS_sRGB) tex.store(img) # Does the image have alpha? transp = state.get_attrib(core.TransparencyAttrib) if not img.has_alpha(): if transp and transp.mode != core.TransparencyAttrib.M_off: print(f"{tex.name}: turning off TransparencyAttrib") state = state.set_attrib( core.TransparencyAttrib.make(core.TransparencyAttrib.M_off)) gnode.set_geom_state(gi, state) return True else: # Nothing else to do. return changed # Crop the image. width, height = img.size crop_l = 0 for x in range(width): if any(img.get_alpha_val(x, y) > 0 for y in range(height)): crop_l = x break crop_r = width for x in reversed(range(crop_l, width)): if any(img.get_alpha_val(x, y) > 0 for y in range(height)): crop_r = x + 1 break crop_t = 0 for y in range(height): if any(img.get_alpha_val(x, y) > 0 for x in range(crop_l, crop_r)): crop_t = y break crop_b = height for y in reversed(range(crop_t, height)): if any(img.get_alpha_val(x, y) > 0 for x in range(crop_l, crop_r)): crop_b = y + 1 break # No cropping to be done. Is the image fully opaque, perhaps? if crop_l == 0 and crop_r == width and crop_t == 0 and crop_b == height: if is_image_fully_opaque(img): print(f"{tex.name}: fully opaque, removing alpha channel") img.remove_alpha() tex.load(img) tex.format = core.Texture.F_srgb tex.wrap_u = core.SamplerState.WM_clamp tex.wrap_v = core.SamplerState.WM_clamp tex.wrap_w = core.SamplerState.WM_clamp if transp and transp.mode != core.TransparencyAttrib.M_off: state = state.set_attrib( core.TransparencyAttrib.make( core.TransparencyAttrib.M_off)) gnode.set_geom_state(gi, state) return True # Premultiply alpha for higher-quality blending. transp = state.get_attrib(core.TransparencyAttrib) if transp and transp.mode == core.TransparencyAttrib.M_alpha: img.premultiply_alpha() prev_format = tex.format prev_sampler = core.SamplerState(tex.default_sampler) tex.load(img) tex.default_sampler = prev_sampler tex.format = prev_format # Check if this has binary alpha. if is_image_alpha_binary(img): print(f"{tex.name}: premultiplying alpha and setting to binary") state = state.set_attrib( core.TransparencyAttrib.make(core.TransparencyAttrib.M_binary)) else: print(f"{tex.name}: premultiplying alpha and setting to dual") #XXX there is no M_premultiplied_dual; this will have to suffice. state = state.set_attrib( core.TransparencyAttrib.make(core.TransparencyAttrib.M_dual)) gnode.set_geom_state(gi, state) changed = True # Make sure that the crop region is power-of-two, because why not. crop_w = crop_r - crop_l #pad_x = core.Texture.up_to_power_2(crop_w) - crop_w #pad_l = pad_x // 2 #pad_r = pad_x - pad_l #crop_l -= pad_l #crop_r += pad_r #if crop_l < 0: # crop_r += -crop_l # crop_l = 0 #crop_w = crop_r - crop_l #assert core.Texture.up_to_power_2(crop_w) == crop_w crop_h = crop_b - crop_t #pad_y = core.Texture.up_to_power_2(crop_h) - crop_h #pad_t = pad_y // 2 #pad_b = pad_y - pad_t #crop_t -= pad_t #crop_b += pad_b #crop_h = crop_b - crop_t #if crop_t < 0: # crop_b += -crop_t # crop_t = 0 #assert core.Texture.up_to_power_2(crop_h) == crop_h # Make sure the cropped region isn't bigger than the original image. if crop_w * crop_h >= width * height: print( f"{tex.name}: no need to crop, {width}×{height} is already its optimal size" ) return changed print( f"{tex.name}: cropping to a {crop_w}×{crop_h} region starting at {crop_l}×{crop_t}" ) new_img = core.PNMImage(crop_w, crop_h, img.num_channels, img.maxval, color_space=core.CS_sRGB) new_img.fill(0, 0, 0) if new_img.has_alpha(): new_img.alpha_fill(0) new_img.copy_sub_image(img, 0, 0, crop_l, crop_t, crop_w, crop_h) prev_sampler = core.SamplerState(tex.default_sampler) if is_image_fully_opaque(new_img): print(f"{tex.name}: fully opaque after crop, removing alpha channel") new_img.remove_alpha() tex.load(new_img) tex.format = core.Texture.F_srgb else: prev_format = tex.format tex.load(new_img) tex.format = prev_format tex.default_sampler = prev_sampler if crop_w < width: tex.wrap_u = core.SamplerState.WM_border_color elif tex.wrap_u == core.SamplerState.WM_repeat: tex.wrap_u = core.SamplerState.WM_clamp if crop_h < height: tex.wrap_v = core.SamplerState.WM_border_color elif tex.wrap_v == core.SamplerState.WM_repeat: tex.wrap_v = core.SamplerState.WM_clamp tex.border_color = (0, 0, 0, 0) assert tex.x_size == crop_w assert tex.y_size == crop_h # Now we need to either move the vertices or transform the UVs in order to # compensate for the cropped image. uv_pos = core.Vec2(crop_l / (width - 1.0), (height - crop_b) / (height - 1.0)) uv_scale = core.Vec2((crop_w - 1.0) / (width - 1.0), (crop_h - 1.0) / (height - 1.0)) vertex_data = gnode.modify_geom(gi).modify_vertex_data() uv_to_vtx = {} vtx_reader = core.GeomVertexReader(vertex_data, 'vertex') uv_reader = core.GeomVertexReader(vertex_data, stage.texcoord_name) while not vtx_reader.is_at_end() and not uv_reader.is_at_end(): uv = uv_reader.get_data2() vtx = core.LPoint3(vtx_reader.get_data3()) uv_to_vtx[tuple(uv)] = vtx vtx_reader = None uv_reader = None if (0, 0) in uv_to_vtx and (1, 1) in uv_to_vtx: # Crop the card itself, making it smaller, reducing overdraw. card_pos = uv_to_vtx[(0, 0)] card_size = uv_to_vtx[(1, 1)] - uv_to_vtx[(0, 0)] rewriter = core.GeomVertexRewriter(vertex_data, 'vertex') uv_reader = core.GeomVertexReader(vertex_data, stage.texcoord_name) while not rewriter.is_at_end() and not uv_reader.is_at_end(): vtx = rewriter.get_data3() uv = core.Point2(uv_reader.get_data2()) uv.componentwise_mult(uv_scale) uv += uv_pos rewriter.set_data3(uv[0] * card_size[0] + card_pos[0], uv[1] * card_size[1] + card_pos[1], vtx.z) rewriter = None # We can remove transparency if we cropped it to the opaque part. if tex.format == core.Texture.F_srgb: print("Removing transparency") state = state.set_attrib( core.TransparencyAttrib.make(core.TransparencyAttrib.M_off)) gnode.set_geom_state(gi, state) else: # Transform the UVs. rewriter = core.GeomVertexRewriter( gnode.modify_geom(gi).modify_vertex_data(), stage.get_texcoord_name()) while not rewriter.is_at_end(): uv = core.Point2(rewriter.get_data2()) uv -= uv_pos uv.x /= uv_scale.x uv.y /= uv_scale.y rewriter.set_data2(uv) rewriter = None return True
def intersect_line(self, point: core.Point3, direction: core.Vec3) -> core.Point2: direction_2d = core.Vec2(direction.x, direction.y) return self.line_segment.intersect_line(point.xy, direction_2d)
def _camera_scale(self): film_size = self._camera.lens.get_film_size() scale = self._camera.camera.get_scale() return core.Vec2(film_size.x * scale.x, film_size.y * scale.y)
def update(self, entities_by_filter): if base.paused: return for entity in entities_by_filter['movable']: obj = entity[TerrainObject] component = obj.terrain[Terrain] while obj.position[0] < 0: obj.position = (obj.position[0] + component.size, obj.position[1], obj.position[2]) while obj.position[1] < 0: obj.position = (obj.position[0], obj.position[1] + component.size, obj.position[2]) while obj.position[0] > component.size: obj.position = (obj.position[0] - component.size, obj.position[1], obj.position[2]) while obj.position[1] > component.size: obj.position = (obj.position[0], obj.position[1] - component.size, obj.position[2]) pos = obj.position res = component.resolution col = core.LColor() component._peeker.lookup_bilinear( col, (pos[0] * component._scale.x) % 1.0, (pos[1] * component._scale.y) % 1.0, ) height = col.w * component._scale.z obj._root.set_pos(pos[0], pos[1], pos[2] + height) obj._root.get_child(0).set_scale(obj.scale) obj._root.set_h(obj.direction) #obj._root.set_texture_off(10) if entity._uid.name == "player": #haack t = 0 if Speed in entity: speed = entity[Speed] if speed.max is not None: #t = (speed.current - speed.min) / (speed.max - speed.min) t = speed.current / speed.max obj.terrain[Terrain]._grass_root.set_shader_input( "player", pos[0], pos[1], t) wspos = base.cam.get_pos(render).xy peeker = component._wind_map.peek() wind_coord = core.Vec2( pos[0], pos[1]) * component._scale[0] * 4 + core.Vec2( globalClock.frame_time * 0.06, 0) wind = core.LColor() peeker.lookup(wind, wind_coord.x, wind_coord.y) #wind = max(1.0 - wind.x - 0.5, 0.0) + 0.5 wind = abs(1.0 - wind.x - 0.5) + 0.5 component._wind_sound.set_play_rate(wind * 2 + 0.5) component._wind_sound.set_volume(max(0, wind - 0.35))