3
3
use {
4
4
js_sys:: WebAssembly ,
5
5
wasm_bindgen:: { prelude:: * , JsCast } ,
6
- web_sys:: { WebGl2RenderingContext , WebGlBuffer , WebGlProgram , WebGlShader , WebGlTexture } ,
6
+ web_sys:: {
7
+ WebGl2RenderingContext , WebGlBuffer , WebGlFramebuffer , WebGlProgram , WebGlShader ,
8
+ WebGlTexture , WebGlVertexArrayObject ,
9
+ } ,
7
10
} ;
8
11
9
12
use egui:: {
@@ -22,6 +25,7 @@ pub struct WebGl2Painter {
22
25
pos_buffer : WebGlBuffer ,
23
26
tc_buffer : WebGlBuffer ,
24
27
color_buffer : WebGlBuffer ,
28
+ post_process : PostProcess ,
25
29
26
30
egui_texture : WebGlTexture ,
27
31
egui_texture_version : Option < u64 > ,
@@ -62,12 +66,12 @@ impl WebGl2Painter {
62
66
let vert_shader = compile_shader (
63
67
& gl,
64
68
Gl :: VERTEX_SHADER ,
65
- include_str ! ( "shader/vertex_300es .glsl" ) ,
69
+ include_str ! ( "shader/main_vertex_300es .glsl" ) ,
66
70
) ?;
67
71
let frag_shader = compile_shader (
68
72
& gl,
69
73
Gl :: FRAGMENT_SHADER ,
70
- include_str ! ( "shader/fragment_300es .glsl" ) ,
74
+ include_str ! ( "shader/main_fragment_300es .glsl" ) ,
71
75
) ?;
72
76
73
77
let program = link_program ( & gl, [ vert_shader, frag_shader] . iter ( ) ) ?;
@@ -76,6 +80,9 @@ impl WebGl2Painter {
76
80
let tc_buffer = gl. create_buffer ( ) . ok_or ( "failed to create tc_buffer" ) ?;
77
81
let color_buffer = gl. create_buffer ( ) . ok_or ( "failed to create color_buffer" ) ?;
78
82
83
+ let post_process =
84
+ PostProcess :: new ( gl. clone ( ) , canvas. width ( ) as i32 , canvas. height ( ) as i32 ) ?;
85
+
79
86
Ok ( WebGl2Painter {
80
87
canvas_id : canvas_id. to_owned ( ) ,
81
88
canvas,
@@ -85,6 +92,7 @@ impl WebGl2Painter {
85
92
pos_buffer,
86
93
tc_buffer,
87
94
color_buffer,
95
+ post_process,
88
96
egui_texture,
89
97
egui_texture_version : None ,
90
98
user_textures : Default :: default ( ) ,
@@ -368,8 +376,7 @@ impl crate::Painter for WebGl2Painter {
368
376
}
369
377
370
378
let mut pixels: Vec < u8 > = Vec :: with_capacity ( texture. pixels . len ( ) * 4 ) ;
371
- let font_gamma = 1.0 / 2.2 ; // HACK due to non-linear framebuffer blending.
372
- for srgba in texture. srgba_pixels ( font_gamma) {
379
+ for srgba in texture. srgba_pixels ( 1.0 ) {
373
380
pixels. push ( srgba. r ( ) ) ;
374
381
pixels. push ( srgba. g ( ) ) ;
375
382
pixels. push ( srgba. b ( ) ) ;
@@ -429,6 +436,9 @@ impl crate::Painter for WebGl2Painter {
429
436
430
437
let gl = & self . gl ;
431
438
439
+ self . post_process
440
+ . begin ( self . canvas . width ( ) as i32 , self . canvas . height ( ) as i32 ) ?;
441
+
432
442
gl. enable ( Gl :: SCISSOR_TEST ) ;
433
443
gl. disable ( Gl :: CULL_FACE ) ; // egui is not strict about winding order.
434
444
gl. enable ( Gl :: BLEND ) ;
@@ -485,8 +495,172 @@ impl crate::Painter for WebGl2Painter {
485
495
) ) ;
486
496
}
487
497
}
498
+
499
+ self . post_process . end ( ) ;
500
+
501
+ Ok ( ( ) )
502
+ }
503
+ }
504
+
505
+ /// Uses a framebuffer to render everything in linear color space and convert it back to sRGB
506
+ /// in a separate "post processing" step
507
+ struct PostProcess {
508
+ gl : Gl ,
509
+ pos_buffer : WebGlBuffer ,
510
+ index_buffer : WebGlBuffer ,
511
+ vao : WebGlVertexArrayObject ,
512
+ texture : WebGlTexture ,
513
+ texture_size : ( i32 , i32 ) ,
514
+ fbo : WebGlFramebuffer ,
515
+ program : WebGlProgram ,
516
+ }
517
+
518
+ impl PostProcess {
519
+ fn new ( gl : Gl , width : i32 , height : i32 ) -> Result < PostProcess , JsValue > {
520
+ let fbo = gl
521
+ . create_framebuffer ( )
522
+ . ok_or ( "failed to create framebuffer" ) ?;
523
+ gl. bind_framebuffer ( Gl :: FRAMEBUFFER , Some ( & fbo) ) ;
524
+
525
+ let texture = gl. create_texture ( ) . unwrap ( ) ;
526
+ gl. bind_texture ( Gl :: TEXTURE_2D , Some ( & texture) ) ;
527
+ gl. tex_parameteri ( Gl :: TEXTURE_2D , Gl :: TEXTURE_WRAP_S , Gl :: CLAMP_TO_EDGE as i32 ) ;
528
+ gl. tex_parameteri ( Gl :: TEXTURE_2D , Gl :: TEXTURE_WRAP_T , Gl :: CLAMP_TO_EDGE as i32 ) ;
529
+ gl. tex_parameteri ( Gl :: TEXTURE_2D , Gl :: TEXTURE_MIN_FILTER , Gl :: NEAREST as i32 ) ;
530
+ gl. tex_parameteri ( Gl :: TEXTURE_2D , Gl :: TEXTURE_MAG_FILTER , Gl :: NEAREST as i32 ) ;
531
+ gl. pixel_storei ( Gl :: UNPACK_ALIGNMENT , 1 ) ;
532
+ gl. tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array (
533
+ Gl :: TEXTURE_2D ,
534
+ 0 ,
535
+ Gl :: SRGB8_ALPHA8 as i32 ,
536
+ width,
537
+ height,
538
+ 0 ,
539
+ Gl :: RGBA ,
540
+ Gl :: UNSIGNED_BYTE ,
541
+ None ,
542
+ )
543
+ . unwrap ( ) ;
544
+ gl. framebuffer_texture_2d (
545
+ Gl :: FRAMEBUFFER ,
546
+ Gl :: COLOR_ATTACHMENT0 ,
547
+ Gl :: TEXTURE_2D ,
548
+ Some ( & texture) ,
549
+ 0 ,
550
+ ) ;
551
+
552
+ gl. bind_texture ( Gl :: TEXTURE_2D , None ) ;
553
+ gl. bind_framebuffer ( Gl :: FRAMEBUFFER , None ) ;
554
+
555
+ let vert_shader = compile_shader (
556
+ & gl,
557
+ Gl :: VERTEX_SHADER ,
558
+ include_str ! ( "shader/post_vertex_300es.glsl" ) ,
559
+ ) ?;
560
+ let frag_shader = compile_shader (
561
+ & gl,
562
+ Gl :: FRAGMENT_SHADER ,
563
+ include_str ! ( "shader/post_fragment_300es.glsl" ) ,
564
+ ) ?;
565
+ let program = link_program ( & gl, [ vert_shader, frag_shader] . iter ( ) ) ?;
566
+
567
+ let vao = gl. create_vertex_array ( ) . ok_or ( "failed to create vao" ) ?;
568
+ gl. bind_vertex_array ( Some ( & vao) ) ;
569
+
570
+ let positions = vec ! [ 0u8 , 0 , 1 , 0 , 0 , 1 , 1 , 1 ] ;
571
+
572
+ let indices = vec ! [ 0u8 , 1 , 2 , 1 , 2 , 3 ] ;
573
+
574
+ let pos_buffer = gl. create_buffer ( ) . ok_or ( "failed to create pos_buffer" ) ?;
575
+ gl. bind_buffer ( Gl :: ARRAY_BUFFER , Some ( & pos_buffer) ) ;
576
+ gl. buffer_data_with_u8_array ( Gl :: ARRAY_BUFFER , & positions, Gl :: STATIC_DRAW ) ;
577
+
578
+ let a_pos_loc = gl. get_attrib_location ( & program, "a_pos" ) ;
579
+ assert ! ( a_pos_loc >= 0 ) ;
580
+ gl. vertex_attrib_pointer_with_i32 ( a_pos_loc as u32 , 2 , Gl :: UNSIGNED_BYTE , false , 0 , 0 ) ;
581
+ gl. enable_vertex_attrib_array ( a_pos_loc as u32 ) ;
582
+
583
+ gl. bind_buffer ( Gl :: ARRAY_BUFFER , None ) ;
584
+
585
+ let index_buffer = gl. create_buffer ( ) . ok_or ( "failed to create index_buffer" ) ?;
586
+ gl. bind_buffer ( Gl :: ELEMENT_ARRAY_BUFFER , Some ( & index_buffer) ) ;
587
+ gl. buffer_data_with_u8_array ( Gl :: ELEMENT_ARRAY_BUFFER , & indices, Gl :: STATIC_DRAW ) ;
588
+
589
+ gl. bind_vertex_array ( None ) ;
590
+ gl. bind_buffer ( Gl :: ELEMENT_ARRAY_BUFFER , None ) ;
591
+
592
+ Ok ( PostProcess {
593
+ gl,
594
+ pos_buffer,
595
+ index_buffer,
596
+ vao,
597
+ texture,
598
+ texture_size : ( width, height) ,
599
+ fbo,
600
+ program,
601
+ } )
602
+ }
603
+
604
+ fn begin ( & mut self , width : i32 , height : i32 ) -> Result < ( ) , JsValue > {
605
+ let gl = & self . gl ;
606
+
607
+ if ( width, height) != self . texture_size {
608
+ gl. bind_texture ( Gl :: TEXTURE_2D , Some ( & self . texture ) ) ;
609
+ gl. pixel_storei ( Gl :: UNPACK_ALIGNMENT , 1 ) ;
610
+ gl. tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array (
611
+ Gl :: TEXTURE_2D ,
612
+ 0 ,
613
+ Gl :: SRGB8_ALPHA8 as i32 ,
614
+ width,
615
+ height,
616
+ 0 ,
617
+ Gl :: RGBA ,
618
+ Gl :: UNSIGNED_BYTE ,
619
+ None ,
620
+ ) ?;
621
+ gl. bind_texture ( Gl :: TEXTURE_2D , None ) ;
622
+
623
+ self . texture_size = ( width, height) ;
624
+ }
625
+
626
+ gl. bind_framebuffer ( Gl :: FRAMEBUFFER , Some ( & self . fbo ) ) ;
627
+
488
628
Ok ( ( ) )
489
629
}
630
+
631
+ fn end ( & self ) {
632
+ let gl = & self . gl ;
633
+
634
+ gl. bind_framebuffer ( Gl :: FRAMEBUFFER , None ) ;
635
+ gl. disable ( Gl :: SCISSOR_TEST ) ;
636
+
637
+ gl. use_program ( Some ( & self . program ) ) ;
638
+
639
+ gl. active_texture ( Gl :: TEXTURE0 ) ;
640
+ gl. bind_texture ( Gl :: TEXTURE_2D , Some ( & self . texture ) ) ;
641
+ let u_sampler_loc = gl. get_uniform_location ( & self . program , "u_sampler" ) . unwrap ( ) ;
642
+ gl. uniform1i ( Some ( & u_sampler_loc) , 0 ) ;
643
+
644
+ gl. bind_vertex_array ( Some ( & self . vao ) ) ;
645
+
646
+ gl. draw_elements_with_i32 ( Gl :: TRIANGLES , 6 , Gl :: UNSIGNED_BYTE , 0 ) ;
647
+
648
+ gl. bind_texture ( Gl :: TEXTURE_2D , None ) ;
649
+ gl. bind_vertex_array ( None ) ;
650
+ gl. use_program ( None ) ;
651
+ }
652
+ }
653
+
654
+ impl Drop for PostProcess {
655
+ fn drop ( & mut self ) {
656
+ let gl = & self . gl ;
657
+ gl. delete_vertex_array ( Some ( & self . vao ) ) ;
658
+ gl. delete_buffer ( Some ( & self . pos_buffer ) ) ;
659
+ gl. delete_buffer ( Some ( & self . index_buffer ) ) ;
660
+ gl. delete_program ( Some ( & self . program ) ) ;
661
+ gl. delete_framebuffer ( Some ( & self . fbo ) ) ;
662
+ gl. delete_texture ( Some ( & self . texture ) ) ;
663
+ }
490
664
}
491
665
492
666
fn compile_shader (
0 commit comments