@@ -31,7 +31,8 @@ mod backend;
3131
3232use std:: marker:: PhantomData ;
3333
34- use backend:: TuiShaderBackend ;
34+ use backend:: cpu:: CpuBackend ;
35+ use backend:: { NoUserData , TuiShaderBackend } ;
3536use ratatui:: layout:: { Position , Rect } ;
3637use ratatui:: style:: { Color , Style } ;
3738use ratatui:: widgets:: StatefulWidget ;
@@ -59,17 +60,17 @@ pub struct ShaderCanvas<T> {
5960 pub character_rule : CharacterRule ,
6061 pub style_rule : StyleRule ,
6162 pub entry_point : String ,
62- _marker : PhantomData < T > ,
63+ _user_data : PhantomData < T > ,
6364}
6465
65- impl < T : TuiShaderBackend > ShaderCanvas < T > {
66+ impl < T > ShaderCanvas < T > {
6667 /// Creates a new instance of [`ShaderCanvas`].
6768 pub fn new ( ) -> Self {
6869 Self {
6970 character_rule : CharacterRule :: default ( ) ,
7071 style_rule : StyleRule :: default ( ) ,
7172 entry_point : String :: from ( "main" ) ,
72- _marker : PhantomData ,
73+ _user_data : PhantomData ,
7374 }
7475 }
7576
@@ -96,13 +97,13 @@ impl<T: TuiShaderBackend> ShaderCanvas<T> {
9697 }
9798}
9899
99- impl < T : TuiShaderBackend > Default for ShaderCanvas < T > {
100+ impl < T > Default for ShaderCanvas < T > {
100101 fn default ( ) -> Self {
101102 Self :: new ( )
102103 }
103104}
104105
105- impl < T : TuiShaderBackend > StatefulWidget for ShaderCanvas < T > {
106+ impl < T > StatefulWidget for ShaderCanvas < T > {
106107 type State = ShaderCanvasState < T > ;
107108 fn render (
108109 self ,
@@ -112,13 +113,12 @@ impl<T: TuiShaderBackend> StatefulWidget for ShaderCanvas<T> {
112113 ) {
113114 let width = area. width ;
114115 let height = area. height ;
115-
116- let raw_buffer = state. backend . execute ( width, height) ;
116+ let samples = state. backend . execute ( width, height, & state. user_data ) ;
117117
118118 for y in 0 ..height {
119119 for x in 0 ..width {
120- let index = ( y * ( width + WgpuBackend :: row_padding ( width ) ) + x) as usize ;
121- let value = raw_buffer [ index] ;
120+ let index = ( y * width + x) as usize ;
121+ let value = samples [ index] ;
122122 let position = ( x, y) ;
123123 let character = match self . character_rule {
124124 CharacterRule :: Always ( character) => character,
@@ -142,35 +142,69 @@ impl<T: TuiShaderBackend> StatefulWidget for ShaderCanvas<T> {
142142}
143143
144144/// State struct for [`ShaderCanvas`], it holds the [`TuiShaderBackend`].
145- # [ derive ( Debug , Clone , Eq , PartialEq ) ]
146- pub struct ShaderCanvasState < T : TuiShaderBackend > {
147- backend : T ,
145+ pub struct ShaderCanvasState < T > {
146+ backend : Box < dyn TuiShaderBackend < T > > ,
147+ user_data : T ,
148148}
149149
150- impl ShaderCanvasState < WgpuBackend > {
150+ impl ShaderCanvasState < NoUserData > {
151151 /// Creates a new [`ShaderCanvasState`] using [`WgpuBackend`] as it's
152152 /// [`TuiShaderBackend`].
153- pub fn wgpu (
153+ pub fn wgpu ( path_to_fragment_shader : & str , entry_point : & str ) -> Self {
154+ let backend = Box :: new ( WgpuBackend :: new ( path_to_fragment_shader, entry_point) ) ;
155+ Self {
156+ backend,
157+ user_data : NoUserData ,
158+ }
159+ }
160+ }
161+
162+ impl < T > ShaderCanvasState < T >
163+ where
164+ T : Copy + bytemuck:: Pod + bytemuck:: Zeroable ,
165+ {
166+ pub fn wgpu_with_user_data (
154167 path_to_fragment_shader : & str ,
155168 entry_point : & str ,
156- ) -> ShaderCanvasState < WgpuBackend > {
157- let backend = WgpuBackend :: new ( path_to_fragment_shader, entry_point) ;
158- ShaderCanvasState { backend }
169+ user_data : T ,
170+ ) -> Self {
171+ let backend = Box :: new ( WgpuBackend :: new ( path_to_fragment_shader, entry_point) ) ;
172+ Self { backend, user_data }
159173 }
160174}
161175
162- impl < T : TuiShaderBackend > ShaderCanvasState < T > {
163- /// Creates a new [`ShaderCanvasState`] instance by passing in the desired [`TuiShaderBackend`].
164- pub fn new ( backend : T ) -> ShaderCanvasState < T > {
165- ShaderCanvasState { backend }
176+ impl ShaderCanvasState < NoUserData > {
177+ pub fn cpu < F > ( callback : F ) -> Self
178+ where
179+ F : Fn ( u16 , u16 ) -> [ u8 ; 4 ] + ' static ,
180+ {
181+ let backend = Box :: new ( CpuBackend :: new ( callback) ) ;
182+ Self {
183+ backend,
184+ user_data : NoUserData ,
185+ }
186+ }
187+ }
188+
189+ impl < T > ShaderCanvasState < T >
190+ where
191+ T : ' static ,
192+ {
193+ pub fn cpu_with_user_data < F > ( callback : F , user_data : T ) -> Self
194+ where
195+ F : Fn ( u16 , u16 , & T ) -> [ u8 ; 4 ] + ' static ,
196+ {
197+ let backend = Box :: new ( CpuBackend :: new_with_user_data ( callback) ) ;
198+ Self { backend, user_data }
166199 }
167200}
168201
169- impl Default for ShaderCanvasState < WgpuBackend > {
202+ impl Default for ShaderCanvasState < NoUserData > {
170203 /// Creates a new [`ShaderCanvasState`] instance with a [`WgpuBackend`].
171- fn default ( ) -> ShaderCanvasState < WgpuBackend > {
204+ fn default ( ) -> Self {
172205 Self {
173- backend : WgpuBackend :: default ( ) ,
206+ backend : Box :: new ( WgpuBackend :: default ( ) ) ,
207+ user_data : NoUserData ,
174208 }
175209 }
176210}
@@ -262,14 +296,14 @@ mod tests {
262296 #[ test]
263297 fn default_wgsl_context ( ) {
264298 let mut context = WgpuBackend :: default ( ) ;
265- let raw_buffer = context. execute ( 64 , 64 ) ;
299+ let raw_buffer = context. execute ( 64 , 64 , & NoUserData ) ;
266300 assert ! ( raw_buffer. iter( ) . all( |pixel| pixel == & [ 255 , 0 , 255 , 255 ] ) ) ;
267301 }
268302
269303 #[ test]
270304 fn different_entry_points ( ) {
271305 let mut context = WgpuBackend :: new ( "src/shaders/default_fragment.wgsl" , "green" ) ;
272- let raw_buffer = context. execute ( 64 , 64 ) ;
306+ let raw_buffer = context. execute ( 64 , 64 , & NoUserData ) ;
273307 assert ! ( raw_buffer. iter( ) . all( |pixel| pixel == & [ 0 , 255 , 0 , 255 ] ) ) ;
274308 }
275309
0 commit comments