示例#1
0
 def __init__(self, array: Any):
     self._array = np.ascontiguousarray(array, dtype=np.uint8)
     height, width, depth = self._array.shape
     if depth != 3:
         raise TypeError(
             "Array must have RGB channels.  Shape is: %r"
             % (self._array.shape,)
         )
     self._buffer = ffi.from_buffer("TCOD_color_t[]", self._array)
     self._mipmaps = ffi.new(
         "struct TCOD_mipmap_*",
         {
             "width": width,
             "height": height,
             "fwidth": width,
             "fheight": height,
             "buf": self._buffer,
             "dirty": True,
         },
     )
     self.image_c = ffi.new(
         "TCOD_Image*",
         {
             "nb_mipmaps": 1,
             "mipmaps": self._mipmaps,
             "has_key_color": False,
         },
     )
示例#2
0
    def _get_size(self) -> Tuple[int, int]:
        """Return the (width, height) for this Image.

        Returns:
            Tuple[int, int]: The (width, height) of this Image
        """
        w = ffi.new("int *")
        h = ffi.new("int *")
        lib.TCOD_image_get_size(self.image_c, w, h)
        return w[0], h[0]
示例#3
0
def heightmap_get_minmax(hm: np.ndarray) -> Tuple[float, float]:
    """Return the min and max values of this heightmap.
    Args:
        hm (numpy.ndarray): A numpy.ndarray formatted for heightmap functions.
    Returns:
        Tuple[float, float]: The (min, max) values.
    .. deprecated:: 2.0
        Use ``hm.min()`` or ``hm.max()`` instead.
    """
    mi = ffi.new("float *")
    ma = ffi.new("float *")
    lib.TCOD_heightmap_get_minmax(_heightmap_cdata(hm), mi, ma)
    return mi[0], ma[0]
示例#4
0
def heightmap_kernel_transform(
    hm: np.ndarray,
    kernelsize: int,
    dx: Sequence[int],
    dy: Sequence[int],
    weight: Sequence[float],
    minLevel: float,
    maxLevel: float,
) -> None:
    """Apply a generic transformation on the map, so that each resulting cell
    value is the weighted sum of several neighbour cells.
    This can be used to smooth/sharpen the map.
    Args:
        hm (numpy.ndarray): A numpy.ndarray formatted for heightmap functions.
        kernelsize (int): Should be set to the length of the parameters::
                          dx, dy, and weight.
        dx (Sequence[int]): A sequence of x coorinates.
        dy (Sequence[int]): A sequence of y coorinates.
        weight (Sequence[float]): A sequence of kernelSize cells weight.
                                  The value of each neighbour cell is scaled by
                                  its corresponding weight
        minLevel (float): No transformation will apply to cells
                          below this value.
        maxLevel (float): No transformation will apply to cells
                          above this value.
    See examples below for a simple horizontal smoothing kernel :
    replace value(x,y) with
    0.33*value(x-1,y) + 0.33*value(x,y) + 0.33*value(x+1,y).
    To do this, you need a kernel of size 3
    (the sum involves 3 surrounding cells).
    The dx,dy array will contain:
    * dx=-1, dy=0 for cell (x-1, y)
    * dx=1, dy=0 for cell (x+1, y)
    * dx=0, dy=0 for cell (x, y)
    * The weight array will contain 0.33 for each cell.
    Example:
        >>> import numpy as np
        >>> heightmap = np.zeros((3, 3), dtype=np.float32)
        >>> heightmap[:,1] = 1
        >>> dx = [-1, 1, 0]
        >>> dy = [0, 0, 0]
        >>> weight = [0.33, 0.33, 0.33]
        >>> tcod.heightmap_kernel_transform(heightmap, 3, dx, dy, weight,
        ...                                 0.0, 1.0)
    """
    cdx = ffi.new("int[]", dx)
    cdy = ffi.new("int[]", dy)
    cweight = ffi.new("float[]", weight)
    lib.TCOD_heightmap_kernel_transform(
        _heightmap_cdata(hm), kernelsize, cdx, cdy, cweight, minLevel, maxLevel
    )
示例#5
0
文件: event.py 项目: alekslis/Rogue
def get() -> Iterator[Any]:
    """Return an iterator for all pending events.

    Events are processed as the iterator is consumed.  Breaking out of, or
    discarding the iterator will leave the remaining events on the event queue.
    It is also safe to call this function inside of a loop that is already
    handling events (the event iterator is reentrant.)

    Example::

        for event in tcod.event.get():
            if event.type == "QUIT":
                print(event)
                raise SystemExit()
            elif event.type == "KEYDOWN":
                print(event)
            elif event.type == "MOUSEBUTTONDOWN":
                print(event)
            elif event.type == "MOUSEMOTION":
                print(event)
            else:
                print(event)
        # For loop exits after all current events are processed.
    """
    sdl_event = ffi.new("SDL_Event*")
    while lib.SDL_PollEvent(sdl_event):
        if sdl_event.type in _SDL_TO_CLASS_TABLE:
            yield _SDL_TO_CLASS_TABLE[sdl_event.type].from_sdl_event(sdl_event)
        else:
            yield Undefined.from_sdl_event(sdl_event)
示例#6
0
def get() -> Iterator[Any]:
    """Return an iterator for all pending events.

    Events are processed as the iterator is consumed.  Breaking out of, or
    discarding the iterator will leave the remaining events on the event queue.

    Example::

        for event in tcod.event.get():
            if event.type == "QUIT":
                print(event)
                raise SystemExit()
            elif event.type == "KEYDOWN":
                print(event)
            elif event.type == "MOUSEBUTTONDOWN":
                print(event)
            elif event.type == "MOUSEMOTION":
                print(event)
            else:
                print(event)
    """
    sdl_event = ffi.new("SDL_Event*")
    while lib.SDL_PollEvent(sdl_event):
        if sdl_event.type in _SDL_TO_CLASS_TABLE:
            yield _SDL_TO_CLASS_TABLE[sdl_event.type].from_sdl_event(sdl_event)
        else:
            yield Undefined.from_sdl_event(sdl_event)
示例#7
0
def heightmap_add_voronoi(
    hm: np.ndarray,
    nbCoef: int,
    coef: Sequence[float],
    rnd: Optional[tcod.random.Random] = None,
) -> None:
    """Add values from a Voronoi diagram to the heightmap.
    Args:
        hm (numpy.ndarray): A numpy.ndarray formatted for heightmap functions.
        nbCoef (int): The diagram value is calculated from the nbCoef
                      closest sites.
        coef (Sequence[float]): The distance to each site is scaled by the
                                corresponding coef.
                                Closest site : coef[0],
                                second closest site : coef[1], ...
        rnd (Optional[Random]): A Random instance, or None.
    """
    nbPoints = len(coef)
    ccoef = ffi.new("float[]", coef)
    lib.TCOD_heightmap_add_voronoi(
        _heightmap_cdata(hm),
        nbPoints,
        nbCoef,
        ccoef,
        rnd.random_c if rnd else ffi.NULL,
    )
示例#8
0
def _pixel_to_tile(x: float, y: float) -> Tuple[float, float]:
    """Convert pixel coordinates to tile coordinates."""
    if not lib.TCOD_ctx.engine:
        return 0, 0
    xy = ffi.new("double[2]", (x, y))
    lib.TCOD_sys_pixel_to_tile(xy, xy + 1)
    return xy[0], xy[1]
示例#9
0
 def _setstate_old(self, state: Any) -> None:
     self._random = state[0]
     self.noise_c = ffi.new("struct TCOD_Noise*")
     self.noise_c.ndim = state[3]
     ffi.buffer(self.noise_c.map)[:] = state[4]
     ffi.buffer(self.noise_c.buffer)[:] = state[5]
     self.noise_c.H = state[6]
     self.noise_c.lacunarity = state[7]
     ffi.buffer(self.noise_c.exponent)[:] = state[8]
     if state[9]:
         # high change of this being prematurely garbage collected!
         self.__waveletTileData = ffi.new("float[]", 32 * 32 * 32)
         ffi.buffer(self.__waveletTileData)[:] = state[9]
     self.noise_c.noise_type = state[10]
     self._tdl_noise_c = ffi.new(
         "TDLNoise*", (self.noise_c, self.noise_c.ndim, state[1], state[2]))
示例#10
0
def recommended_size() -> Tuple[int, int]:
    """Return the recommended size of a console for the current active window.

    The return value from this function can be passed to :any:`Console`.

    This function will raise RuntimeError if libtcod has not been initialized.

    .. versionadded:: 11.8

    .. seealso::
        :any:`tcod.console_init_root`
        :any:`tcod.console_flush`
    """
    if not lib.TCOD_ctx.engine:
        raise RuntimeError("The libtcod engine was not initialized first.")
    window = lib.TCOD_sys_get_sdl_window()
    renderer = lib.TCOD_sys_get_sdl_renderer()
    with ffi.new("int[2]") as xy:
        if renderer:
            lib.SDL_GetRendererOutputSize(renderer, xy, xy + 1)
        else:  # Assume OpenGL if a renderer does not exist.
            lib.SDL_GL_GetDrawableSize(window, xy, xy + 1)
        w = max(1, xy[0] // lib.TCOD_ctx.tileset.tile_width)
        h = max(1, xy[1] // lib.TCOD_ctx.tileset.tile_height)
    return w, h
示例#11
0
 def __init__(
     self,
     dimensions: int,
     algorithm: int = 2,
     implementation: int = SIMPLE,
     hurst: float = 0.5,
     lacunarity: float = 2.0,
     octaves: float = 4,
     seed: Optional[tcod.random.Random] = None,
 ):
     if not 0 < dimensions <= 4:
         raise ValueError(
             "dimensions must be in range 0 < n <= 4, got %r"
             % (dimensions,)
         )
     self._random = seed
     _random_c = seed.random_c if seed else ffi.NULL
     self._algorithm = algorithm
     self.noise_c = ffi.gc(
         ffi.cast(
             "struct TCOD_Noise*",
             lib.TCOD_noise_new(dimensions, hurst, lacunarity, _random_c),
         ),
         lib.TCOD_noise_delete,
     )
     self._tdl_noise_c = ffi.new(
         "TDLNoise*", (self.noise_c, dimensions, 0, octaves)
     )
     self.implementation = implementation  # sanity check
示例#12
0
def recommended_size() -> Tuple[int, int]:
    """Return the recommended size of a console for the current active window.

    The return is determined from the active tileset size and active window
    size.  This result should be used create an :any:`Console` instance.

    This function will raise RuntimeError if libtcod has not been initialized.

    .. versionadded:: 11.8

    .. seealso::
        :any:`tcod.console_init_root`
        :any:`tcod.console_flush`

    .. deprecated:: 11.13
        This function does not support contexts.
        Use :any:`Context.recommended_console_size` instead.
    """
    if not lib.TCOD_ctx.engine:
        raise RuntimeError("The libtcod engine was not initialized first.")
    window = lib.TCOD_sys_get_sdl_window()
    renderer = lib.TCOD_sys_get_sdl_renderer()
    with ffi.new("int[2]") as xy:
        if renderer:
            lib.SDL_GetRendererOutputSize(renderer, xy, xy + 1)
        else:  # Assume OpenGL if a renderer does not exist.
            lib.SDL_GL_GetDrawableSize(window, xy, xy + 1)
        w = max(1, xy[0] // lib.TCOD_ctx.tileset.tile_width)
        h = max(1, xy[1] // lib.TCOD_ctx.tileset.tile_height)
    return w, h
示例#13
0
文件: context.py 项目: alekslis/Rogue
 def pixel_to_subtile(self, x: int, y: int) -> Tuple[float, float]:
     """Convert window pixel coordinates to sub-tile coordinates."""
     with ffi.new("double[2]", (x, y)) as xy:
         _check(
             lib.TCOD_context_screen_pixel_to_tile_d(
                 self._context_p, xy, xy + 1))
         return xy[0], xy[1]
示例#14
0
文件: context.py 项目: alekslis/Rogue
 def pixel_to_tile(self, x: int, y: int) -> Tuple[int, int]:
     """Convert window pixel coordinates to tile coordinates."""
     with ffi.new("int[2]", (x, y)) as xy:
         _check(
             lib.TCOD_context_screen_pixel_to_tile_i(
                 self._context_p, xy, xy + 1))
         return xy[0], xy[1]
示例#15
0
def _compile_bool_edges(edge_map: Any) -> Tuple[Any, int]:
    """Return an edge array using a boolean map."""
    edge_map = np.copy(edge_map)
    edge_center = edge_map.shape[0] // 2, edge_map.shape[1] // 2
    edge_map[edge_center] = 0
    edge_array = np.transpose(edge_map.nonzero())
    edge_array -= edge_center
    return ffi.new("int[]", list(edge_array.flat)), len(edge_array)
示例#16
0
文件: context.py 项目: alekslis/Rogue
def _handle_title(title: Optional[str]) -> Any:
    """Return title as a CFFI string.

    If title is None then return a decent default title is returned.
    """
    if title is None:
        title = os.path.basename(sys.argv[0])
    return ffi.new("char[]", title.encode("utf-8"))
示例#17
0
 def __setstate__(self, state: Any) -> None:
     """Create a new cdata object with the stored paramaters."""
     try:
         cdata = state["random_c"]
     except KeyError:  # old/deprecated format
         cdata = state["cdata"]
         del state["cdata"]
     state["random_c"] = ffi.new("mersenne_data_t*", cdata)
     self.__dict__.update(state)
示例#18
0
def get_mouse_state() -> MouseState:
    """Return the current state of the mouse.

    .. versionadded:: 9.3
    """
    xy = ffi.new("int[2]")
    buttons = lib.SDL_GetMouseState(xy, xy + 1)
    x, y = _pixel_to_tile(*xy)
    return MouseState((xy[0], xy[1]), (int(x), int(y)), buttons)
示例#19
0
def new_window(
    width: int,
    height: int,
    *,
    renderer: Optional[int] = None,
    tileset: Optional[tcod.tileset.Tileset] = None,
    vsync: bool = True,
    sdl_window_flags: Optional[int] = None,
    title: Optional[str] = None
) -> Context:
    """Create a new context with the desired pixel size.

    `width` and `height` is the desired pixel resolution of the window.

    `renderer` is the desired libtcod renderer to use.
    Typical options are :any:`tcod.context.RENDERER_OPENGL2` for a faster
    renderer or :any:`tcod.context.RENDERER_SDL2` for a reliable renderer.

    `tileset` is the font/tileset for the new context to render with.
    The fall-back tileset available from passing None is useful for
    prototyping, but will be unreliable across platforms.

    `vsync` is the Vertical Sync option for the window.  The default of True
    is recommended but you may want to use False for benchmarking purposes.

    `sdl_window_flags` is a bit-field of SDL window flags, if None is given
    then a default of :any:`tcod.context.SDL_WINDOW_RESIZABLE` is used.
    There's more info on the SDL documentation:
    https://wiki.libsdl.org/SDL_CreateWindow#Remarks

    `title` is the desired title of the window.

    After the context is created you can use
    :any:`Context.recommended_console_size` to figure out the size of the
    console for the context.
    """
    context_pp = ffi.new("TCOD_Context**")
    if renderer is None:
        renderer = RENDERER_SDL2
    if sdl_window_flags is None:
        sdl_window_flags = SDL_WINDOW_RESIZABLE
    tileset_p = _handle_tileset(tileset)
    title = _handle_title(title)
    _check_warn(
        lib.TCOD_context_new_window(
            width,
            height,
            renderer,
            tileset_p,
            vsync,
            sdl_window_flags,
            title.encode("utf-8"),
            context_pp,
        )
    )
    return Context._claim(context_pp[0])
示例#20
0
 def get_path(self, x: int, y: int) -> List[Tuple[int, int]]:
     """Return a list of (x, y) steps to reach the goal point, if possible.
     """
     lib.TCOD_dijkstra_path_set(self._path_c, x, y)
     path = []
     pointer_x = ffi.new("int[2]")
     pointer_y = pointer_x + 1
     while lib.TCOD_dijkstra_path_walk(self._path_c, pointer_x, pointer_y):
         path.append((pointer_x[0], pointer_y[0]))
     return path
示例#21
0
 def __as_cdata(self) -> Any:
     return ffi.new(
         "struct TCOD_Map*",
         (
             self.width,
             self.height,
             self.width * self.height,
             ffi.from_buffer("struct TCOD_MapCell*", self.__buffer),
         ),
     )
示例#22
0
    def __setstate__(self, state: Any) -> None:
        if isinstance(state, tuple):  # deprecated format
            return self._setstate_old(state)
        # unpack wavelet tile data if it exists
        if "_waveletTileData" in state:
            state["_waveletTileData"] = ffi.new("float[]",
                                                state["_waveletTileData"])
            state["noise_c"]["waveletTileData"] = state["_waveletTileData"]
        else:
            state["noise_c"]["waveletTileData"] = ffi.NULL

        # unpack TCOD_Noise and link to Random instance
        state["noise_c"]["rand"] = state["_random"].random_c
        state["noise_c"] = ffi.new("struct TCOD_Noise*", state["noise_c"])

        # unpack TDLNoise and link to libtcod noise
        state["_tdl_noise_c"]["noise"] = state["noise_c"]
        state["_tdl_noise_c"] = ffi.new("TDLNoise*", state["_tdl_noise_c"])
        self.__dict__.update(state)
示例#23
0
    def size(self) -> Tuple[int, int]:
        """Return the pixel (width, height) of the window.

        This attribute can be set to change the size of the window but the
        given size must be greater than (1, 1) or else an exception will be
        raised.
        """
        xy = ffi.new("int[2]")
        lib.SDL_GetWindowSize(self.p, xy, xy + 1)
        return xy[0], xy[1]
示例#24
0
    def position(self) -> Tuple[int, int]:
        """Return the (x, y) position of the window.

        This attribute can be set the move the window.
        The constants tcod.lib.SDL_WINDOWPOS_CENTERED or
        tcod.lib.SDL_WINDOWPOS_UNDEFINED can be used.
        """
        xy = ffi.new("int[2]")
        lib.SDL_GetWindowPosition(self.p, xy, xy + 1)
        return xy[0], xy[1]
示例#25
0
 def __as_cdata(self) -> Any:
     return ffi.new(
         "struct TCOD_Map*",
         (
             self.width,
             self.height,
             self.width * self.height,
             ffi.cast("struct TCOD_MapCell*", self.__buffer.ctypes.data),
         ),
     )
示例#26
0
def _export(array: np.array) -> Any:
    """Convert a NumPy array into a ctype object."""
    return ffi.new(
        "struct NArray4*",
        (
            _INT_TYPES[array.dtype.type],
            ffi.cast("void*", array.ctypes.data),
            array.shape,
            array.strides,
        ),
    )
示例#27
0
def _heightmap_cdata(array: np.ndarray) -> ffi.CData:
    """Return a new TCOD_heightmap_t instance using an array.
    Formatting is verified during this function.
    """
    if array.flags["F_CONTIGUOUS"]:
        array = array.transpose()
    if not array.flags["C_CONTIGUOUS"]:
        raise ValueError("array must be a contiguous segment.")
    if array.dtype != np.float32:
        raise ValueError("array dtype must be float32, not %r" % array.dtype)
    height, width = array.shape
    pointer = ffi.from_buffer("float *", array)
    return ffi.new("TCOD_heightmap_t *", (width, height, pointer))
示例#28
0
    def get_tcod_path_ffi(self) -> Tuple[Any, Any, Tuple[int, int]]:
        if len(self.shape) != 2:
            raise ValueError("Array must have a 2d shape, shape is %r" %
                             (self.shape, ))
        if self.dtype.type not in self._C_ARRAY_CALLBACKS:
            raise ValueError("dtype must be one of %r, dtype is %r" %
                             (self._C_ARRAY_CALLBACKS.keys(), self.dtype.type))

        array_type, callback = self._C_ARRAY_CALLBACKS[self.dtype.type]
        userdata = ffi.new(
            "struct PathCostArray*",
            (ffi.cast("char*", self.ctypes.data), self.strides),
        )
        return callback, userdata, self.shape
示例#29
0
 def _compile_rules(self) -> Any:
     """Compile this graph into a C struct array."""
     if not self._edge_rules_p:
         self._edge_rules_keep_alive = []
         rules = []
         for rule_ in self._graph.values():
             rule = rule_.copy()
             rule["edge_count"] = len(rule["edge_list"])
             # Edge rule format: [i, j, cost, ...] etc.
             edge_obj = ffi.new("int[]",
                                len(rule["edge_list"]) * (self._ndim + 1))
             edge_obj[0:len(edge_obj)] = itertools.chain(*rule["edge_list"])
             self._edge_rules_keep_alive.append(edge_obj)
             rule["edge_array"] = edge_obj
             self._edge_rules_keep_alive.append(rule["cost"])
             rule["cost"] = _export_dict(rule["cost"])
             if "condition" in rule:
                 self._edge_rules_keep_alive.append(rule["condition"])
                 rule["condition"] = _export_dict(rule["condition"])
             del rule["edge_list"]
             rules.append(rule)
         self._edge_rules_p = ffi.new("struct PathfinderRule[]", rules)
     return self._edge_rules_p, self._edge_rules_keep_alive
示例#30
0
def heightmap_get_normal(
    hm: np.ndarray, x: float, y: float, waterLevel: float
) -> Tuple[float, float, float]:
    """Return the map normal at given coordinates.
    Args:
        hm (numpy.ndarray): A numpy.ndarray formatted for heightmap functions.
        x (float): The x coordinate.
        y (float): The y coordinate.
        waterLevel (float): The heightmap is considered flat below this value.
    Returns:
        Tuple[float, float, float]: An (x, y, z) vector normal.
    """
    cn = ffi.new("float[3]")
    lib.TCOD_heightmap_get_normal(_heightmap_cdata(hm), x, y, cn, waterLevel)
    return tuple(cn)  # type: ignore