Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
 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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
 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
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
 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:]
Ejemplo n.º 9
0
 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)
Ejemplo n.º 10
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
Ejemplo n.º 11
0
    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))
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
    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])
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
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
Ejemplo n.º 18
0
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)
Ejemplo n.º 19
0
 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
Ejemplo n.º 20
0
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
Ejemplo n.º 21
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))
Ejemplo n.º 22
0
    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)
Ejemplo n.º 23
0
 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()]
Ejemplo n.º 24
0
 def _floor_slope_direction(self):
     if self._sector is None:
         return core.Vec2(0, 0)
     return self._sector.floor_slope_direction()
Ejemplo n.º 25
0
 def __init__(self, point, data, aabb=None):
     self.point = point
     self.data = data
     self.aabb = aabb or AABB(point, core.Vec2(0))
Ejemplo n.º 26
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
Ejemplo n.º 27
0
 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)
Ejemplo n.º 28
0
 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)
Ejemplo n.º 29
0
    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))