@@ -132,6 +132,66 @@ impl PyBlendMode {
132132 const OP_MAX : u8 = 4 ;
133133}
134134
135+ /// Configures how an image is sampled when drawn.
136+ ///
137+ /// Controls texture filtering and edge wrapping behavior.
138+ ///
139+ /// - `filter` — `Sampler.LINEAR` (smooth) or `Sampler.NEAREST` (pixelated).
140+ /// - `wrap` — `Sampler.CLAMP` (default), `Sampler.REPEAT`, or `Sampler.MIRROR`.
141+ /// Use `wrap_x`/`wrap_y` to set each axis independently.
142+ #[ pyclass]
143+ #[ derive( Clone ) ]
144+ pub struct Sampler {
145+ pub ( crate ) filter : u8 ,
146+ pub ( crate ) wrap_x : u8 ,
147+ pub ( crate ) wrap_y : u8 ,
148+ }
149+
150+ #[ pymethods]
151+ impl Sampler {
152+ #[ new]
153+ #[ pyo3( signature = ( * , filter=0 , wrap=0 , wrap_x=None , wrap_y=None ) ) ]
154+ fn new ( filter : u8 , wrap : u8 , wrap_x : Option < u8 > , wrap_y : Option < u8 > ) -> Self {
155+ Self {
156+ filter,
157+ wrap_x : wrap_x. unwrap_or ( wrap) ,
158+ wrap_y : wrap_y. unwrap_or ( wrap) ,
159+ }
160+ }
161+
162+ fn __repr__ ( & self ) -> String {
163+ let filter_name = match self . filter {
164+ 0 => "LINEAR" ,
165+ 1 => "NEAREST" ,
166+ _ => "?" ,
167+ } ;
168+ let wrap_name = |v : u8 | match v {
169+ 0 => "CLAMP" ,
170+ 1 => "REPEAT" ,
171+ 2 => "MIRROR" ,
172+ _ => "?" ,
173+ } ;
174+ format ! (
175+ "Sampler(filter={}, wrap_x={}, wrap_y={})" ,
176+ filter_name,
177+ wrap_name( self . wrap_x) ,
178+ wrap_name( self . wrap_y)
179+ )
180+ }
181+
182+ #[ classattr]
183+ const LINEAR : u8 = 0 ;
184+ #[ classattr]
185+ const NEAREST : u8 = 1 ;
186+
187+ #[ classattr]
188+ const CLAMP : u8 = 0 ;
189+ #[ classattr]
190+ const REPEAT : u8 = 1 ;
191+ #[ classattr]
192+ const MIRROR : u8 = 2 ;
193+ }
194+
135195pub use crate :: surface:: Surface ;
136196
137197#[ pyclass]
@@ -197,6 +257,20 @@ impl<'a, 'py> FromPyObject<'a, 'py> for ImageRef {
197257 }
198258}
199259
260+ #[ pymethods]
261+ impl Image {
262+ /// Applies a `Sampler` to this image, controlling filtering and wrapping.
263+ ///
264+ /// ```python
265+ /// s = Sampler(filter=Sampler.NEAREST, wrap=Sampler.REPEAT)
266+ /// img.sampler(s)
267+ /// ```
268+ fn sampler ( & self , sampler : & Sampler ) -> PyResult < ( ) > {
269+ image_set_sampler ( self . entity , sampler. filter , sampler. wrap_x , sampler. wrap_y )
270+ . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
271+ }
272+ }
273+
200274impl Drop for Image {
201275 fn drop ( & mut self ) {
202276 let _ = image_destroy ( self . entity ) ;
@@ -1073,21 +1147,6 @@ impl Graphics {
10731147 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
10741148 }
10751149
1076- pub fn texture ( & self , source : ImageRef ) -> PyResult < ( ) > {
1077- graphics_record_command ( self . entity , DrawCommand :: Texture ( source. entity ) )
1078- . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
1079- }
1080-
1081- pub fn no_texture ( & self ) -> PyResult < ( ) > {
1082- graphics_record_command ( self . entity , DrawCommand :: NoTexture )
1083- . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
1084- }
1085-
1086- pub fn texture_transform ( & self , transform : crate :: math:: PyAffine2 ) -> PyResult < ( ) > {
1087- graphics_record_command ( self . entity , DrawCommand :: TextureTransform ( transform. 0 ) )
1088- . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
1089- }
1090-
10911150 pub fn unlit ( & self ) -> PyResult < ( ) > {
10921151 graphics_record_command ( self . entity , DrawCommand :: Unlit )
10931152 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
0 commit comments