11//! 2D accelerated rendering
22//!
3- //! Official C documentation: https://wiki.libsdl.org/CategoryRender
3+ //! Official C documentation: < https://wiki.libsdl.org/SDL2/ CategoryRender>
44//! # Introduction
55//!
66//! This module contains functions for 2D accelerated rendering.
@@ -55,9 +55,9 @@ use std::rc::Rc;
5555use std:: slice;
5656
5757use crate :: sys;
58- use crate :: sys:: SDL_BlendMode ;
59- use crate :: sys :: SDL_ScaleMode ;
60- use crate :: sys :: SDL_TextureAccess ;
58+ use crate :: sys:: {
59+ SDL_BlendFactor , SDL_BlendMode , SDL_BlendOperation , SDL_ScaleMode , SDL_TextureAccess ,
60+ } ;
6161
6262/// Contains the description of an error returned by SDL
6363#[ derive( Debug , Clone ) ]
@@ -133,52 +133,234 @@ pub struct RendererInfo {
133133}
134134
135135/// Blend mode for `Canvas`, `Texture` or `Surface`.
136- #[ repr( i32 ) ]
137- #[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
138- pub enum BlendMode {
139- /// no blending (replace destination with source).
140- None = SDL_BlendMode :: SDL_BLENDMODE_NONE as i32 ,
136+ #[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
137+ pub struct BlendMode ( pub SDL_BlendMode ) ;
138+
139+ impl fmt:: Debug for BlendMode {
140+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
141+ f. debug_tuple ( "BlendMode" ) . field ( & self . 0 . 0 ) . finish ( )
142+ }
143+ }
144+
145+ #[ expect( non_upper_case_globals, reason = "deprecated constants" ) ]
146+ impl BlendMode {
147+ /// No blending (replace destination with source).
148+ pub const NONE : Self = Self ( SDL_BlendMode :: SDL_BLENDMODE_NONE ) ;
149+ #[ deprecated(
150+ since = "0.39.0" ,
151+ note = "use NONE instead, this used to be an enum member"
152+ ) ]
153+ pub const None : Self = Self :: NONE ;
154+
141155 /// Alpha blending
142156 ///
143157 /// dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
144158 ///
145159 /// dstA = srcA + (dstA * (1-srcA))
146- Blend = SDL_BlendMode :: SDL_BLENDMODE_BLEND as i32 ,
160+ pub const BLEND : Self = Self ( SDL_BlendMode :: SDL_BLENDMODE_BLEND ) ;
161+ #[ deprecated(
162+ since = "0.39.0" ,
163+ note = "use BLEND instead, this used to be an enum member"
164+ ) ]
165+ pub const Blend : Self = Self :: BLEND ;
166+
147167 /// Additive blending
148168 ///
149169 /// dstRGB = (srcRGB * srcA) + dstRGB
150170 ///
151171 /// dstA = dstA (keep original alpha)
152- Add = SDL_BlendMode :: SDL_BLENDMODE_ADD as i32 ,
172+ pub const ADD : Self = Self ( SDL_BlendMode :: SDL_BLENDMODE_ADD ) ;
173+ #[ deprecated(
174+ since = "0.39.0" ,
175+ note = "use ADD instead, this used to be an enum member"
176+ ) ]
177+ pub const Add : Self = Self :: ADD ;
178+
153179 /// Color modulate
154180 ///
155181 /// dstRGB = srcRGB * dstRGB
156- Mod = SDL_BlendMode :: SDL_BLENDMODE_MOD as i32 ,
182+ pub const MOD : Self = Self ( SDL_BlendMode :: SDL_BLENDMODE_MOD ) ;
183+ #[ deprecated(
184+ since = "0.39.0" ,
185+ note = "use MOD instead, this used to be an enum member"
186+ ) ]
187+ pub const Mod : Self = Self :: MOD ;
188+
157189 /// Color multiply
158- Mul = SDL_BlendMode :: SDL_BLENDMODE_MUL as i32 ,
190+ pub const MUL : Self = Self ( SDL_BlendMode :: SDL_BLENDMODE_MUL ) ;
191+ #[ deprecated(
192+ since = "0.39.0" ,
193+ note = "use MUL instead, this used to be an enum member"
194+ ) ]
195+ pub const Mul : Self = Self :: MUL ;
196+
159197 /// Invalid blending mode (indicates error)
160- Invalid = SDL_BlendMode :: SDL_BLENDMODE_INVALID as i32 ,
161- }
198+ pub const INVALID : Self = Self ( SDL_BlendMode :: SDL_BLENDMODE_INVALID ) ;
199+ #[ deprecated(
200+ since = "0.39.0" ,
201+ note = "use INVALID instead, this used to be an enum member"
202+ ) ]
203+ pub const Invalid : Self = Self :: INVALID ;
204+ }
205+
206+ macro_rules! enum_binding {
207+ (
208+ $( #[ $meta: meta] ) *
209+ pub enum $enum: ident = $sdl_enum: ident { $(
210+ #[ $( $member_meta: meta) * ]
211+ $member: ident = $sdl_constant: ident,
212+ ) * }
213+ ) => {
214+ $( #[ $meta] ) *
215+ ///
216+ #[ doc = concat!( "SDL C API type: [`" , stringify!( $sdl_enum) , "`]." ) ]
217+ /// [`From`] implementations are provided to convert between this type and the C API type.
218+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
219+ pub enum $enum { $(
220+ $member = $sdl_enum:: $sdl_constant as isize ,
221+ ) * }
222+
223+ impl From <$sdl_enum> for $enum {
224+ fn from( value: $sdl_enum) -> Self {
225+ match value { $(
226+ $sdl_enum:: $sdl_constant => Self :: $member,
227+ ) * }
228+ }
229+ }
162230
163- impl TryFrom < u32 > for BlendMode {
164- type Error = ( ) ;
231+ impl From <$enum> for $sdl_enum {
232+ fn from( value: $enum) -> Self {
233+ match value { $(
234+ $enum:: $member => Self :: $sdl_constant,
235+ ) * }
236+ }
237+ }
238+ } ;
239+ }
165240
166- fn try_from ( n : u32 ) -> Result < Self , Self :: Error > {
167- use self :: BlendMode :: * ;
168- use crate :: sys:: SDL_BlendMode :: * ;
241+ enum_binding ! {
242+ /// The blend operation used when combining source and destination pixel components.
243+ pub enum BlendOperation = SDL_BlendOperation {
244+ /// dst + src: supported by all renderers
245+ Add = SDL_BLENDOPERATION_ADD ,
246+ /// dst - src: supported by D3D9, D3D11, OpenGL, OpenGLES
247+ Subtract = SDL_BLENDOPERATION_SUBTRACT ,
248+ /// src - dst: supported by D3D9, D3D11, OpenGL, OpenGLES
249+ RevSubtract = SDL_BLENDOPERATION_REV_SUBTRACT ,
250+ /// min(dst, src): supported by D3D9, D3D11
251+ Minimum = SDL_BLENDOPERATION_MINIMUM ,
252+ /// max(dst, src): supported by D3D9, D3D11
253+ Maximum = SDL_BLENDOPERATION_MAXIMUM ,
254+ }
255+ }
256+
257+ enum_binding ! {
258+ /// The normalized factor used to multiply pixel components.
259+ pub enum BlendFactor = SDL_BlendFactor {
260+ /// 0, 0, 0, 0
261+ Zero = SDL_BLENDFACTOR_ZERO ,
262+ /// 1, 1, 1, 1
263+ One = SDL_BLENDFACTOR_ONE ,
264+ /// srcR, srcG, srcB, srcA
265+ SrcColor = SDL_BLENDFACTOR_SRC_COLOR ,
266+ /// 1-srcR, 1-srcG, 1-srcB, 1-srcA
267+ OneMinusSrcColor = SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR ,
268+ /// srcA, srcA, srcA, srcA
269+ SrcAlpha = SDL_BLENDFACTOR_SRC_ALPHA ,
270+ /// 1-srcA, 1-srcA, 1-srcA, 1-srcA
271+ OneMinusSrcAlpha = SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA ,
272+ /// dstR, dstG, dstB, dstA
273+ DstColor = SDL_BLENDFACTOR_DST_COLOR ,
274+ /// 1-dstR, 1-dstG, 1-dstB, 1-dstA
275+ OneMinusDstColor = SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR ,
276+ /// dstA, dstA, dstA, dstA
277+ DstAlpha = SDL_BLENDFACTOR_DST_ALPHA ,
278+ /// 1-dstA, 1-dstA, 1-dstA, 1-dstA
279+ OneMinusDstAlpha = SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA ,
280+ }
281+ }
282+
283+ /// Arguments to [`SDL_ComposeCustomBlendMode`][sys::SDL_ComposeCustomBlendMode].
284+ ///
285+ /// This struct implements [`Default`] with a blend mode equivalent to [`BlendMode::NONE`].
286+ /// Struct update syntax ([Rust Book][book-struct-update], [Rust Reference][reference-struct-update]) can be used to only change a few arguments.
287+ ///
288+ /// See [`Self::compose`] for examples.
289+ ///
290+ /// [book-struct-update]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax
291+ /// [reference-struct-update]: https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax
292+ #[ derive( Debug , Clone , Copy ) ]
293+ pub struct CustomBlendMode {
294+ pub src_color_factor : BlendFactor ,
295+ pub dst_color_factor : BlendFactor ,
296+ pub color_operation : BlendOperation ,
297+ pub src_alpha_factor : BlendFactor ,
298+ pub dst_alpha_factor : BlendFactor ,
299+ pub alpha_operation : BlendOperation ,
300+ }
169301
170- match n {
171- x if x == SDL_BLENDMODE_NONE as u32 => Ok ( None ) ,
172- x if x == SDL_BLENDMODE_BLEND as u32 => Ok ( Blend ) ,
173- x if x == SDL_BLENDMODE_ADD as u32 => Ok ( Add ) ,
174- x if x == SDL_BLENDMODE_MOD as u32 => Ok ( Mod ) ,
175- x if x == SDL_BLENDMODE_MUL as u32 => Ok ( Mul ) ,
176- x if x == SDL_BLENDMODE_INVALID as u32 => Ok ( Invalid ) ,
177- _ => Err ( ( ) ) ,
302+ impl Default for CustomBlendMode {
303+ fn default ( ) -> Self {
304+ Self {
305+ src_color_factor : BlendFactor :: One ,
306+ dst_color_factor : BlendFactor :: Zero ,
307+ color_operation : BlendOperation :: Add ,
308+ src_alpha_factor : BlendFactor :: One ,
309+ dst_alpha_factor : BlendFactor :: Zero ,
310+ alpha_operation : BlendOperation :: Add ,
178311 }
179312 }
180313}
181314
315+ impl CustomBlendMode {
316+ /// Compose a custom blend mode for renderers.
317+ ///
318+ /// # Examples
319+ ///
320+ /// ```
321+ /// use sdl2::render::{BlendFactor, BlendOperation, CustomBlendMode};
322+ ///
323+ /// let no_blending = CustomBlendMode {
324+ /// src_color_factor: BlendFactor::One,
325+ /// dst_color_factor: BlendFactor::Zero,
326+ /// color_operation: BlendOperation::Add,
327+ /// src_alpha_factor: BlendFactor::One,
328+ /// dst_alpha_factor: BlendFactor::Zero,
329+ /// alpha_operation: BlendOperation::Add,
330+ /// }.compose();
331+ ///
332+ /// let ignore_alpha = CustomBlendMode {
333+ /// src_alpha_factor: BlendFactor::Zero,
334+ /// dst_alpha_factor: BlendFactor::One,
335+ /// ..Default::default()
336+ /// }.compose();
337+ /// ```
338+ ///
339+ /// See [`SDL_ComposeCustomBlendMode`][sys::SDL_ComposeCustomBlendMode].
340+ #[ doc( alias = "SDL_ComposeCustomBlendMode" ) ]
341+ pub fn compose ( self ) -> BlendMode {
342+ let Self {
343+ src_color_factor,
344+ dst_color_factor,
345+ color_operation,
346+ src_alpha_factor,
347+ dst_alpha_factor,
348+ alpha_operation,
349+ } = self ;
350+
351+ BlendMode ( unsafe {
352+ sys:: SDL_ComposeCustomBlendMode (
353+ src_color_factor. into ( ) ,
354+ dst_color_factor. into ( ) ,
355+ color_operation. into ( ) ,
356+ src_alpha_factor. into ( ) ,
357+ dst_alpha_factor. into ( ) ,
358+ alpha_operation. into ( ) ,
359+ )
360+ } )
361+ }
362+ }
363+
182364#[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
183365pub enum ScaleMode {
184366 /// nearest pixel sampling. default
@@ -1100,8 +1282,7 @@ impl<T: RenderTarget> Canvas<T> {
11001282 /// Sets the blend mode used for drawing operations (Fill and Line).
11011283 #[ doc( alias = "SDL_SetRenderDrawBlendMode" ) ]
11021284 pub fn set_blend_mode ( & mut self , blend : BlendMode ) {
1103- let ret =
1104- unsafe { sys:: SDL_SetRenderDrawBlendMode ( self . context . raw , transmute ( blend as u32 ) ) } ;
1285+ let ret = unsafe { sys:: SDL_SetRenderDrawBlendMode ( self . context . raw , blend. 0 ) } ;
11051286 // Should only fail on an invalid renderer
11061287 if ret != 0 {
11071288 panic ! ( "{}" , get_error( ) )
@@ -1117,8 +1298,7 @@ impl<T: RenderTarget> Canvas<T> {
11171298 if ret != 0 {
11181299 panic ! ( "{}" , get_error( ) )
11191300 } else {
1120- let blend = unsafe { blend. assume_init ( ) } ;
1121- BlendMode :: try_from ( blend as u32 ) . unwrap ( )
1301+ BlendMode ( unsafe { blend. assume_init ( ) } )
11221302 }
11231303 }
11241304
@@ -2543,7 +2723,7 @@ impl InternalTexture {
25432723
25442724 #[ doc( alias = "SDL_SetTextureBlendMode" ) ]
25452725 pub fn set_blend_mode ( & mut self , blend : BlendMode ) {
2546- let ret = unsafe { sys:: SDL_SetTextureBlendMode ( self . raw , transmute ( blend as u32 ) ) } ;
2726+ let ret = unsafe { sys:: SDL_SetTextureBlendMode ( self . raw , blend. 0 ) } ;
25472727
25482728 if ret != 0 {
25492729 panic ! ( "Error setting blend: {}" , get_error( ) )
@@ -2559,8 +2739,7 @@ impl InternalTexture {
25592739 if ret != 0 {
25602740 panic ! ( "{}" , get_error( ) )
25612741 } else {
2562- let blend = unsafe { blend. assume_init ( ) } ;
2563- BlendMode :: try_from ( blend as u32 ) . unwrap ( )
2742+ BlendMode ( unsafe { blend. assume_init ( ) } )
25642743 }
25652744 }
25662745
0 commit comments