@@ -3,7 +3,11 @@ mod uniforms;
33#[ cfg( target_arch = "wasm32" ) ]
44mod web;
55
6- use crate :: settings:: UserSettings ;
6+ use egui_wgpu:: wgpu as wgpu;
7+ #[ cfg( not( target_arch = "wasm32" ) ) ]
8+ use egui_wgpu:: wgpu:: naga as naga;
9+
10+ use crate :: settings:: { CustomShaderData , UserSettings } ;
711use crate :: uniforms:: { calculate_scale, Uniforms } ;
812#[ allow( unused_imports) ] // eframe::egui::ViewportCommand used on native but not web
913use eframe:: egui:: {
@@ -27,10 +31,8 @@ use wgpu::{
2731
2832static SHADER : & str = include_str ! ( "shader.wgsl" ) ;
2933
30- fn validate_shader ( equation : & str , colour : & str ) -> Result < ( ) , String > {
31- let shader_src = SHADER
32- . replace ( "REPLACE_FRACTAL_EQN" , equation)
33- . replace ( "REPLACE_COLOR" , colour) ;
34+ fn validate_shader ( options : & CustomShaderData ) -> Result < ( ) , String > {
35+ let shader_src = options. shader ( ) ;
3436
3537 let module = naga:: front:: wgsl:: Frontend :: new ( )
3638 . parse ( & shader_src)
@@ -78,7 +80,7 @@ impl FractalViewerApp {
7880 } ;
7981
8082 #[ cfg( target_arch = "wasm32" ) ]
81- if let Err ( e) = validate_shader ( & settings. equation , & settings . colour ) {
83+ if let Err ( e) = validate_shader ( & settings. shader_data ) {
8284 import_error = Some ( format ! ( "Invalid equation or colour expression: {e}" ) ) ;
8385 settings = UserSettings :: default ( ) ;
8486 }
@@ -120,12 +122,7 @@ impl FractalViewerApp {
120122
121123 let shader = device. create_shader_module ( ShaderModuleDescriptor {
122124 label : Some ( "fv_shader" ) ,
123- source : ShaderSource :: Wgsl (
124- SHADER
125- . replace ( "REPLACE_FRACTAL_EQN" , & settings. equation )
126- . replace ( "REPLACE_COLOR" , & settings. colour )
127- . into ( ) ,
128- ) ,
125+ source : ShaderSource :: Wgsl ( settings. shader_data . shader ( ) . into ( ) ) ,
129126 } ) ;
130127
131128 let pipeline_layout = device. create_pipeline_layout ( & PipelineLayoutDescriptor {
@@ -140,11 +137,13 @@ impl FractalViewerApp {
140137 vertex : VertexState {
141138 module : & shader,
142139 entry_point : "vs_main" ,
140+ compilation_options : Default :: default ( ) ,
143141 buffers : & [ ] ,
144142 } ,
145143 fragment : Some ( FragmentState {
146144 module : & shader,
147145 entry_point : "fs_main" ,
146+ compilation_options : Default :: default ( ) ,
148147 targets : & [ Some ( wgpu_render_state. target_format . into ( ) ) ] ,
149148 } ) ,
150149 primitive : PrimitiveState :: default ( ) ,
@@ -222,7 +221,7 @@ impl FractalViewerApp {
222221 uniforms,
223222 shader_recompilation_options : if self . recompile_shader {
224223 self . recompile_shader = false ;
225- Some ( ( self . settings . equation . clone ( ) , self . settings . colour . clone ( ) ) )
224+ Some ( self . settings . shader_data . clone ( ) )
226225 } else {
227226 None
228227 } ,
@@ -374,40 +373,46 @@ impl eframe::App for FractalViewerApp {
374373 . selected_text ( "Select default equation" )
375374 . show_ui ( ui, |ui| {
376375 if ui. selectable_value (
377- & mut self . settings . equation ,
376+ & mut self . settings . shader_data . equation ,
378377 "csquare(z) + c" . to_string ( ) ,
379378 "Mandelbrot set" ,
380379 ) . clicked ( ) || ui. selectable_value (
381- & mut self . settings . equation ,
380+ & mut self . settings . shader_data . equation ,
382381 "csquare(abs(z)) + c" . to_string ( ) ,
383382 "Burning ship fractal" ,
384383 ) . clicked ( ) || ui. selectable_value (
385- & mut self . settings . equation ,
384+ & mut self . settings . shader_data . equation ,
386385 "cdiv(cmul(csquare(z), z), vec2<f32>(1.0, 0.0) + z * z) + c"
387386 . to_string ( ) ,
388387 "Feather fractal" ,
389388 ) . clicked ( ) || ui. selectable_value (
390- & mut self . settings . equation ,
389+ & mut self . settings . shader_data . equation ,
391390 "csquare(vec2<f32>(z.x, -z.y)) + c" . to_string ( ) ,
392391 "Tricorn fractal" ,
393392 ) . clicked ( ) {
394393 self . recompile_shader = true ;
395394 }
396395 } ) ;
397396 ui. label ( "...Or edit it yourself!" ) ;
398- if ui. add ( TextEdit :: singleline ( & mut self . settings . equation ) . desired_width ( ui. max_rect ( ) . width ( ) ) ) . changed ( ) {
397+ if ui. add ( TextEdit :: singleline ( & mut self . settings . shader_data . equation ) . desired_width ( ui. max_rect ( ) . width ( ) ) ) . changed ( ) {
399398 self . recompile_shader = true ;
400399 } ;
401400 ui. label ( "Colour expression:" ) ;
402401 ui. horizontal ( |ui| {
403- if ui. text_edit_singleline ( & mut self . settings . colour ) . changed ( ) {
402+ if ui. text_edit_singleline ( & mut self . settings . shader_data . colour ) . changed ( ) {
404403 self . recompile_shader = true ;
405404 } ;
406405 if ui. button ( "Reset" ) . clicked ( ) {
407- self . settings . colour = "hsv_rgb(vec3(log(n + 1.0) / log(f32(uniforms.iterations) + 1.0), 0.8, 0.8))" . to_string ( ) ;
406+ self . settings . shader_data . colour = "hsv_rgb(vec3(log(n + 1.0) / log(f32(uniforms.iterations) + 1.0), 0.8, 0.8))" . to_string ( ) ;
408407 self . recompile_shader = true ;
409408 }
410409 } ) ;
410+
411+ ui. label ( "Additional code to include in shader:" ) ;
412+ if ui. add ( TextEdit :: multiline ( & mut self . settings . shader_data . additional ) . code_editor ( ) ) . changed ( ) {
413+ self . recompile_shader = true ;
414+ } ;
415+
411416 ui. checkbox ( & mut self . settings . internal_black , "Always colour inside of set black" ) ;
412417
413418 if let Some ( e) = & self . shader_error {
@@ -464,7 +469,7 @@ impl eframe::App for FractalViewerApp {
464469
465470 // Validate custom expressions
466471 if self . recompile_shader {
467- if let Err ( e) = validate_shader ( & self . settings . equation , & self . settings . colour ) {
472+ if let Err ( e) = validate_shader ( & self . settings . shader_data ) {
468473 self . shader_error = Some ( e) ;
469474 self . recompile_shader = false ;
470475 } else {
@@ -493,15 +498,10 @@ struct FvRenderer {
493498
494499impl FvRenderer {
495500 fn prepare ( & mut self , queue : & Queue , callback : & FvRenderCallback ) {
496- if let Some ( ( equation , colour ) ) = & callback. shader_recompilation_options {
501+ if let Some ( data ) = & callback. shader_recompilation_options {
497502 let shader = self . device . create_shader_module ( ShaderModuleDescriptor {
498503 label : Some ( "fv_shader" ) ,
499- source : ShaderSource :: Wgsl (
500- SHADER
501- . replace ( "REPLACE_FRACTAL_EQN" , & equation)
502- . replace ( "REPLACE_COLOR" , & colour)
503- . into ( ) ,
504- ) ,
504+ source : ShaderSource :: Wgsl ( data. shader ( ) . into ( ) ) ,
505505 } ) ;
506506
507507 let pipeline_layout = self
@@ -520,11 +520,13 @@ impl FvRenderer {
520520 vertex : VertexState {
521521 module : & shader,
522522 entry_point : "vs_main" ,
523+ compilation_options : Default :: default ( ) ,
523524 buffers : & [ ] ,
524525 } ,
525526 fragment : Some ( FragmentState {
526527 module : & shader,
527528 entry_point : "fs_main" ,
529+ compilation_options : Default :: default ( ) ,
528530 targets : & [ Some ( self . target_format . clone ( ) ) ] ,
529531 } ) ,
530532 primitive : PrimitiveState :: default ( ) ,
@@ -552,7 +554,7 @@ impl FvRenderer {
552554
553555struct FvRenderCallback {
554556 uniforms : Uniforms ,
555- shader_recompilation_options : Option < ( String , String ) > ,
557+ shader_recompilation_options : Option < CustomShaderData > ,
556558}
557559
558560impl egui_wgpu:: CallbackTrait for FvRenderCallback {
0 commit comments