1919
2020import ctypes
2121import enum
22- import warnings
2322from typing import TYPE_CHECKING , ClassVar
2423
2524import numpy as np
2625
2726if TYPE_CHECKING :
2827 from warp ._src .codegen import Var
28+ from warp ._src .context import DeviceLike
2929
3030from warp ._src .types import array , float32 , int32 , is_array , uint8 , uint16
3131
3636class TextureFilterMode (enum .IntEnum ):
3737 """Filter modes for texture sampling."""
3838
39- #: Nearest-neighbor (point) filtering
4039 CLOSEST = 0
41- #: Bilinear/trilinear filtering
40+ """Nearest-neighbor (point) filtering."""
4241 LINEAR = 1
42+ """Bilinear/trilinear filtering."""
4343
4444
4545class TextureAddressMode (enum .IntEnum ):
4646 """Address modes for texture coordinates outside [0, 1]."""
4747
48- #: Wrap coordinates (tile the texture)
4948 WRAP = 0
50- #: Clamp coordinates to [0, 1]
49+ """Wrap coordinates (tile the texture)."""
5150 CLAMP = 1
52- #: Mirror coordinates at boundaries
51+ """Clamp coordinates to [0, 1]."""
5352 MIRROR = 2
54- #: Return 0 for coordinates outside [0, 1]
53+ """Mirror coordinates at boundaries."""
5554 BORDER = 3
55+ """Return 0 for coordinates outside [0, 1]."""
5656
5757
5858class texture2d_t (ctypes .Structure ):
@@ -111,14 +111,6 @@ class Texture:
111111 Supports uint8, uint16, and float32 data types. Integer textures are read as normalized
112112 floats in the [0, 1] range.
113113
114- Class Constants:
115- ADDRESS_WRAP (int): Wrap coordinates (tile the texture) = 0
116- ADDRESS_CLAMP (int): Clamp coordinates to [0, 1] = 1
117- ADDRESS_MIRROR (int): Mirror coordinates at boundaries = 2
118- ADDRESS_BORDER (int): Return 0 for coordinates outside [0, 1] = 3
119- FILTER_POINT (int): Nearest-neighbor filtering = 0
120- FILTER_LINEAR (int): Bilinear/trilinear filtering = 1
121-
122114 Example::
123115
124116 import warp as wp
@@ -132,15 +124,19 @@ class Texture:
132124 tex3d = wp.Texture(data_3d, device="cuda:0")
133125 """
134126
135- # Class constants for address modes (matching PR #1153 API)
136127 ADDRESS_WRAP = 0
128+ """Wrap coordinates (tile the texture)."""
137129 ADDRESS_CLAMP = 1
130+ """Clamp coordinates to [0, 1]."""
138131 ADDRESS_MIRROR = 2
132+ """Mirror coordinates at boundaries."""
139133 ADDRESS_BORDER = 3
134+ """Return 0 for coordinates outside [0, 1]."""
140135
141- # Class constants for filter modes
142136 FILTER_POINT = 0
137+ """Nearest-neighbor (point) filtering."""
143138 FILTER_LINEAR = 1
139+ """Bilinear/trilinear filtering."""
144140
145141 # Default dimensionality (None means auto-detect; subclasses override)
146142 _default_dims : int | None = None
@@ -165,32 +161,42 @@ def __init__(
165161 address_mode_v : int | None = None ,
166162 address_mode_w : int | None = None ,
167163 normalized_coords : bool = True ,
168- device = None ,
164+ device : DeviceLike = None ,
169165 dims : int | None = None ,
170166 ):
171167 """Create a texture.
172168
173169 Args:
174- data: Initial texture data as a numpy array or warp array.
175- For 2D: shape (height, width), (height, width, 2), or (height, width, 4).
176- For 3D: shape (depth, height, width), (depth, height, width, 2), or (depth, height, width, 4).
177- Supported dtypes: uint8, uint16, float32.
178- width: Texture width (required if data is None).
179- height: Texture height (required if data is None).
180- depth: Texture depth (required if data is None for 3D textures).
181- num_channels: Number of channels (1, 2, or 4). Only used if data is None. Default is 1.
182- dtype: Data type (uint8, uint16, or float32). Only used if data is None;
183- when data is provided, dtype is inferred from the data. Default is float32.
184- filter_mode: Filtering mode - FILTER_POINT (0) or FILTER_LINEAR (1). Default is LINEAR.
185- address_mode: Address mode for all axes - ADDRESS_WRAP (0), ADDRESS_CLAMP (1),
186- ADDRESS_MIRROR (2), or ADDRESS_BORDER (3). Can be a single int or tuple.
187- address_mode_u: Per-axis address mode for U. Overrides address_mode if specified.
188- address_mode_v: Per-axis address mode for V. Overrides address_mode if specified.
189- address_mode_w: Per-axis address mode for W (3D only). Overrides address_mode if specified.
190- normalized_coords: If True (default), coordinates are in [0, 1] range.
191- If False, coordinates are in texel space.
192- device: Device to create the texture on (CPU or CUDA).
193- dims: Explicit dimensionality (2 or 3). If None, auto-detected from data.
170+ data: Initial texture data as a NumPy array or Warp array.
171+ For 2D: shape ``(height, width)``, ``(height, width, 2)``,
172+ or ``(height, width, 4)``.
173+ For 3D: shape ``(depth, height, width)``,
174+ ``(depth, height, width, 2)``, or ``(depth, height, width, 4)``.
175+ Supported dtypes: ``uint8``, ``uint16``, ``float32``.
176+ width: Texture width (required if ``data`` is ``None``).
177+ height: Texture height (required if ``data`` is ``None``).
178+ depth: Texture depth (required if ``data`` is ``None`` for 3D textures).
179+ num_channels: Number of channels (1, 2, or 4). Only used when
180+ ``data`` is ``None``.
181+ dtype: Data type (``uint8``, ``uint16``, or ``float32``). Only used
182+ when ``data`` is ``None``; otherwise inferred from the data.
183+ filter_mode: Filtering mode — :attr:`FILTER_POINT` or
184+ :attr:`FILTER_LINEAR`.
185+ address_mode: Address mode for all axes —
186+ :attr:`ADDRESS_WRAP`, :attr:`ADDRESS_CLAMP`,
187+ :attr:`ADDRESS_MIRROR`, or :attr:`ADDRESS_BORDER`.
188+ Can be a single int or a tuple of per-axis values.
189+ address_mode_u: Per-axis address mode for U. Overrides
190+ ``address_mode`` if specified.
191+ address_mode_v: Per-axis address mode for V. Overrides
192+ ``address_mode`` if specified.
193+ address_mode_w: Per-axis address mode for W (3D only). Overrides
194+ ``address_mode`` if specified.
195+ normalized_coords: If ``True``, coordinates are in ``[0, 1]``
196+ range. If ``False``, coordinates are in texel space.
197+ device: Device on which to create the texture.
198+ dims: Explicit dimensionality (2 or 3). If ``None``,
199+ auto-detected from ``data``.
194200 """
195201 import warp ._src .context # noqa: PLC0415
196202
@@ -263,7 +269,7 @@ def _detect_dims(self, data, depth: int) -> int:
263269 elif is_array (data ):
264270 np_data = data .numpy ()
265271 else :
266- raise TypeError ("data must be a numpy array or warp array" )
272+ raise TypeError ("data must be a NumPy array or Warp array" )
267273
268274 ndim = np_data .ndim
269275 if ndim == 4 :
@@ -274,8 +280,10 @@ def _detect_dims(self, data, depth: int) -> int:
274280 return 3 # Last dim is not a valid channel count, so must be 3D
275281 else :
276282 # Ambiguous case: last dim could be channels (for 2D) or width (for 3D)
277- # Default to 3D since the numpy array is 3-dimensional, but warn the user
278- warnings .warn (
283+ # Default to 3D since the NumPy array is 3-dimensional, but warn the user
284+ from warp ._src .utils import warn # noqa: PLC0415
285+
286+ warn (
279287 f"Ambiguous array shape { np_data .shape } : could be interpreted as 2D texture "
280288 f"with shape (height={ np_data .shape [0 ]} , width={ np_data .shape [1 ]} , "
281289 f"channels={ np_data .shape [2 ]} ) or 3D texture with shape "
@@ -296,7 +304,7 @@ def _process_data(self, data, device):
296304 elif is_array (data ):
297305 np_data = data .numpy ()
298306 else :
299- raise TypeError ("data must be a numpy array or warp array" )
307+ raise TypeError ("data must be a NumPy array or Warp array" )
300308
301309 if not np_data .flags ["C_CONTIGUOUS" ]:
302310 np_data = np .ascontiguousarray (np_data )
@@ -566,7 +574,7 @@ def __init__(
566574 address_mode_u : int | None = None ,
567575 address_mode_v : int | None = None ,
568576 normalized_coords : bool = True ,
569- device = None ,
577+ device : DeviceLike = None ,
570578 ):
571579 super ().__init__ (
572580 data = data ,
@@ -637,7 +645,7 @@ def __init__(
637645 address_mode_v : int | None = None ,
638646 address_mode_w : int | None = None ,
639647 normalized_coords : bool = True ,
640- device = None ,
648+ device : DeviceLike = None ,
641649 ):
642650 super ().__init__ (
643651 data = data ,
0 commit comments