webgl_rc/
settings.rs

1use num_enum::{IntoPrimitive, TryFromPrimitive};
2use std::cell::RefCell;
3use std::convert::TryInto;
4use std::fmt::Debug;
5use std::ops::Deref;
6use std::ops::DerefMut;
7use web_sys::{AngleInstancedArrays, WebGlRenderingContext as Context};
8
9use super::data_buffer::{ArrayBuffer, Item, ItemsBuffer};
10use super::gl::Gl;
11use super::program::Program;
12use super::texture::Texture;
13use super::texture::TextureFilter;
14use crate::depth_buffer::DepthBuffer;
15use crate::{ElementsBuffer, FrameBuffer};
16
17#[repr(u32)]
18#[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Eq)]
19pub enum BlendFunction {
20    Zero = Context::ZERO,
21    One = Context::ONE,
22    SrcColor = Context::SRC_COLOR,
23    OneMinusSrcColor = Context::ONE_MINUS_SRC_COLOR,
24    DstColor = Context::DST_COLOR,
25    OneMinusDstColor = Context::ONE_MINUS_DST_COLOR,
26    SrcAlpha = Context::SRC_ALPHA,
27    OneMinusSrcAlpha = Context::ONE_MINUS_SRC_ALPHA,
28    DstAlpha = Context::DST_ALPHA,
29    OneMinusDstAlpha = Context::ONE_MINUS_DST_ALPHA,
30    SrcAlphaSaturate = Context::SRC_ALPHA_SATURATE,
31}
32
33#[repr(u32)]
34#[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Eq)]
35pub enum CullFace {
36    Front = Context::FRONT,
37    Back = Context::BACK,
38    FrontAndBack = Context::FRONT_AND_BACK,
39}
40
41impl Default for CullFace {
42    fn default() -> Self {
43        CullFace::Back
44    }
45}
46
47#[repr(u32)]
48#[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Eq)]
49pub enum BlendEquation {
50    Add = Context::FUNC_ADD,
51    Sub = Context::FUNC_SUBTRACT,
52    RSub = Context::FUNC_REVERSE_SUBTRACT,
53}
54
55impl Default for BlendEquation {
56    fn default() -> Self {
57        BlendEquation::Add
58    }
59}
60
61#[repr(u32)]
62#[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Eq)]
63pub enum DepthFunction {
64    Never = Context::NEVER,
65    Less = Context::LESS,
66    Equal = Context::EQUAL,
67    LEqual = Context::LEQUAL,
68    Greater = Context::GREATER,
69    NotEqual = Context::NOTEQUAL,
70    GEqual = Context::GEQUAL,
71    Always = Context::ALWAYS,
72}
73
74impl Default for DepthFunction {
75    fn default() -> Self {
76        DepthFunction::Less
77    }
78}
79
80#[derive(Clone, Copy, PartialEq, Eq, Debug)]
81pub struct ColorMask(bool, bool, bool, bool);
82
83impl Default for ColorMask {
84    fn default() -> Self {
85        Self(true, true, true, true)
86    }
87}
88
89#[derive(Clone, Debug, Default)]
90pub struct SettingsCache {
91    blend: BlendSetting,
92    depth: DepthTestSetting,
93    array_buffer: ArrayBufferSetting,
94    element_buffer: ElementBufferSetting,
95    active_texture: ActiveTextureSetting,
96    textures: [Option<Texture>; 16],
97    enabled_attributes: EnabledAttributesSetting,
98    instanced_attributes: InstancedAttributesSetting,
99    program: ProgramSetting,
100    clear_color: ClearColorSetting,
101    clear_depth: ClearDepthSetting,
102    viewport: ViewportSetting,
103    depth_buffer: DepthBufferSetting,
104    frame_buffer: FrameBufferSetting,
105    blend_equation: BlendEquationSetting,
106    blend_function: BlendFunctionSetting,
107    depth_function: DepthFunction,
108    cull_face: CullFace,
109    color_mask: ColorMask,
110}
111
112pub trait Settings
113where
114    Self: PartialEq,
115    Self: Debug,
116    Self: Clone,
117{
118    fn apply<R, F: FnOnce() -> R>(&self, gl: &Gl, cache: &RefCell<SettingsCache>, callback: F)
119        -> R;
120
121    fn depth_test(self, value: bool) -> ComposedSetting<Self, DepthTestSetting> {
122        ComposedSetting(self, DepthTestSetting(value))
123    }
124
125    fn blend(self, value: bool) -> ComposedSetting<Self, BlendSetting> {
126        ComposedSetting(self, BlendSetting(value))
127    }
128
129    fn blend_equation(
130        self,
131        color: BlendEquation,
132        alpha: BlendEquation,
133    ) -> ComposedSetting<Self, BlendEquationSetting> {
134        ComposedSetting(self, BlendEquationSetting { color, alpha })
135    }
136
137    fn blend_function(
138        self,
139        src_rgb: BlendFunction,
140        dst_rgb: BlendFunction,
141        src_alpha: BlendFunction,
142        dst_alpha: BlendFunction,
143    ) -> ComposedSetting<Self, BlendFunctionSetting> {
144        ComposedSetting(
145            self,
146            BlendFunctionSetting {
147                src_rgb,
148                dst_rgb,
149                src_alpha,
150                dst_alpha,
151            },
152        )
153    }
154
155    fn depth_function(self, function: DepthFunction) -> ComposedSetting<Self, DepthFunction> {
156        ComposedSetting(self, function)
157    }
158
159    fn active_texture(self, index: u32) -> ComposedSetting<Self, ActiveTextureSetting> {
160        ComposedSetting(self, ActiveTextureSetting(index))
161    }
162
163    fn texture(self, index: u32, texture: Texture) -> ComposedSetting<Self, TextureSetting> {
164        ComposedSetting(
165            self,
166            TextureSetting {
167                index,
168                texture: Some(texture),
169            },
170        )
171    }
172
173    fn texture_list<T: IntoIterator<Item = Texture>>(
174        self,
175        textures: T,
176    ) -> ComposedSetting<Self, TextureListSetting> {
177        let mut setting: [Option<Texture>; 16] = Default::default();
178        for (i, texture) in textures.into_iter().enumerate() {
179            setting[i] = Some(texture);
180        }
181        ComposedSetting(self, TextureListSetting { textures: setting })
182    }
183
184    fn texture_filter(
185        self,
186        texture: Texture,
187        filter: TextureFilter,
188    ) -> ComposedSetting<Self, TextureFilterSetting> {
189        ComposedSetting(self, TextureFilterSetting { texture, filter })
190    }
191
192    fn array_buffer(self, array_buffer: ArrayBuffer) -> ComposedSetting<Self, ArrayBufferSetting> {
193        ComposedSetting(self, ArrayBufferSetting(Some(array_buffer)))
194    }
195
196    fn items_buffer<T: Item>(
197        self,
198        array_buffer: ItemsBuffer<T>,
199    ) -> ComposedSetting<Self, ArrayBufferSetting> {
200        ComposedSetting(self, ArrayBufferSetting(Some(array_buffer.buffer)))
201    }
202
203    fn element_buffer(
204        self,
205        element_buffer: ElementsBuffer,
206    ) -> ComposedSetting<Self, ElementBufferSetting> {
207        ComposedSetting(self, ElementBufferSetting(Some(element_buffer)))
208    }
209
210    fn enabled_attributes(
211        self,
212        attributes: &[u32],
213    ) -> ComposedSetting<Self, EnabledAttributesSetting> {
214        ComposedSetting(
215            self,
216            EnabledAttributesSetting {
217                items: attributes.into(),
218            },
219        )
220    }
221
222    fn program(self, program: Program) -> ComposedSetting<Self, ProgramSetting> {
223        ComposedSetting(
224            self,
225            ProgramSetting {
226                program: Some(program),
227            },
228        )
229    }
230
231    fn clear_color(
232        self,
233        r: f32,
234        g: f32,
235        b: f32,
236        alpha: f32,
237    ) -> ComposedSetting<Self, ClearColorSetting> {
238        ComposedSetting(
239            self,
240            ClearColorSetting {
241                color: [r, g, b, alpha],
242            },
243        )
244    }
245
246    fn clear_depth(self, value: f32) -> ComposedSetting<Self, ClearDepthSetting> {
247        ComposedSetting(self, ClearDepthSetting { value })
248    }
249
250    fn viewport(
251        self,
252        x: i32,
253        y: i32,
254        width: i32,
255        height: i32,
256    ) -> ComposedSetting<Self, ViewportSetting> {
257        ComposedSetting(
258            self,
259            ViewportSetting {
260                x,
261                y,
262                width,
263                height,
264            },
265        )
266    }
267
268    fn depth_buffer(self, buffer: DepthBuffer) -> ComposedSetting<Self, DepthBufferSetting> {
269        ComposedSetting(
270            self,
271            DepthBufferSetting {
272                buffer: Some(buffer),
273            },
274        )
275    }
276
277    fn frame_buffer(self, buffer: FrameBuffer) -> ComposedSetting<Self, FrameBufferSetting> {
278        ComposedSetting(
279            self,
280            FrameBufferSetting {
281                buffer: Some(buffer),
282            },
283        )
284    }
285
286    fn cull_face(self, cull_face: CullFace) -> ComposedSetting<Self, CullFace> {
287        ComposedSetting(self, cull_face)
288    }
289
290    fn color_mask(self, r: bool, g: bool, b: bool, a: bool) -> ComposedSetting<Self, ColorMask> {
291        ComposedSetting(self, ColorMask(r, g, b, a))
292    }
293}
294
295pub trait CachedSettings {
296    fn set(gl: &Gl, value: &Self);
297    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self;
298    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self);
299}
300
301impl<T> Settings for T
302where
303    T: PartialEq,
304    T: Debug,
305    T: Clone,
306    T: CachedSettings,
307{
308    fn apply<R, F: FnOnce() -> R>(
309        &self,
310        gl: &Gl,
311        cache: &RefCell<SettingsCache>,
312        callback: F,
313    ) -> R {
314        let old_value = Self::read_cached(&cache.borrow());
315        return if self == &old_value {
316            callback()
317        } else {
318            Self::write_cached(&mut cache.borrow_mut(), self);
319            Self::set(gl, self);
320            let result = callback();
321            Self::set(gl, &old_value);
322            Self::write_cached(&mut cache.borrow_mut(), &old_value);
323            result
324        };
325    }
326}
327
328#[derive(Default, PartialEq, Debug, Clone)]
329pub struct EmptySetting {}
330
331impl Settings for EmptySetting {
332    fn apply<R, F: FnOnce() -> R>(&self, _: &Gl, _: &RefCell<SettingsCache>, callback: F) -> R {
333        callback()
334    }
335}
336
337#[derive(Default, PartialEq, Debug, Clone)]
338pub struct ComposedSetting<S1: Settings, S2: Settings>(S1, S2);
339
340impl<S1: Settings, S2: Settings> Settings for ComposedSetting<S1, S2> {
341    fn apply<R, F: FnOnce() -> R>(
342        &self,
343        gl: &Gl,
344        cache: &RefCell<SettingsCache>,
345        callback: F,
346    ) -> R {
347        self.0
348            .apply(gl, cache, || self.1.apply(gl, cache, || callback()))
349    }
350}
351#[derive(Default, PartialEq, Debug, Clone, Copy)]
352pub struct ClearColorSetting {
353    color: [f32; 4],
354}
355
356impl CachedSettings for ClearColorSetting {
357    fn set(gl: &Gl, value: &Self) {
358        gl.context().clear_color(
359            value.color[0],
360            value.color[1],
361            value.color[2],
362            value.color[3],
363        );
364    }
365
366    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
367        cache.clear_color
368    }
369
370    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
371        cache.clear_color = *value;
372    }
373}
374
375#[derive(Default, PartialEq, Debug, Clone, Copy)]
376pub struct ClearDepthSetting {
377    value: f32,
378}
379
380impl CachedSettings for ClearDepthSetting {
381    fn set(gl: &Gl, value: &Self) {
382        gl.context().clear_depth(value.value);
383    }
384
385    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
386        cache.clear_depth
387    }
388
389    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
390        cache.clear_depth = *value;
391    }
392}
393
394#[derive(Default, PartialEq, Debug, Clone, Copy)]
395pub struct ViewportSetting {
396    pub x: i32,
397    pub y: i32,
398    pub width: i32,
399    pub height: i32,
400}
401
402impl CachedSettings for ViewportSetting {
403    fn set(gl: &Gl, value: &Self) {
404        gl.context()
405            .viewport(value.x, value.y, value.width, value.height);
406    }
407
408    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
409        cache.viewport
410    }
411
412    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
413        cache.viewport = *value;
414    }
415}
416
417#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
418pub struct ActiveTextureSetting(u32);
419
420impl CachedSettings for ActiveTextureSetting {
421    fn set(gl: &Gl, value: &Self) {
422        gl.context().active_texture(value.0 + Context::TEXTURE0);
423    }
424    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
425        cache.active_texture
426    }
427    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
428        cache.active_texture = *value;
429    }
430}
431
432#[derive(Clone, Debug, Default, PartialEq, Eq)]
433pub struct ArrayBufferSetting(Option<ArrayBuffer>);
434
435impl CachedSettings for ArrayBufferSetting {
436    fn set(gl: &Gl, value: &Self) {
437        gl.context().bind_buffer(
438            Context::ARRAY_BUFFER,
439            value.0.as_ref().map(|v| v.handle()).as_ref(),
440        );
441    }
442    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
443        cache.array_buffer.clone()
444    }
445    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
446        cache.array_buffer = value.clone();
447    }
448}
449
450#[derive(Clone, Debug, Default, PartialEq, Eq)]
451pub struct ElementBufferSetting(Option<ElementsBuffer>);
452
453impl CachedSettings for ElementBufferSetting {
454    fn set(gl: &Gl, value: &Self) {
455        gl.context().bind_buffer(
456            Context::ELEMENT_ARRAY_BUFFER,
457            value.0.as_ref().map(|v| v.handle()).as_ref(),
458        );
459    }
460    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
461        cache.element_buffer.clone()
462    }
463    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
464        cache.element_buffer = value.clone();
465    }
466}
467
468#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
469pub struct BlendSetting(bool);
470
471impl CachedSettings for BlendSetting {
472    fn set(gl: &Gl, value: &Self) {
473        if value.0 {
474            gl.context().enable(Context::BLEND)
475        } else {
476            gl.context().disable(Context::BLEND)
477        }
478    }
479    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
480        cache.blend
481    }
482    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
483        cache.blend = *value;
484    }
485}
486
487#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
488pub struct DepthTestSetting(bool);
489
490impl CachedSettings for DepthTestSetting {
491    fn set(gl: &Gl, value: &Self) {
492        if value.0 {
493            gl.context().enable(Context::DEPTH_TEST)
494        } else {
495            gl.context().disable(Context::DEPTH_TEST)
496        }
497    }
498    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
499        cache.depth
500    }
501    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
502        cache.depth = *value;
503    }
504}
505
506#[derive(Clone, Debug, Default, PartialEq, Eq)]
507pub struct TextureSetting {
508    index: u32,
509    texture: Option<Texture>,
510}
511
512impl TextureSetting {
513    pub(self) fn set_texture(gl: &Gl, index: u32, texture: Option<&Texture>) {
514        gl.apply(Gl::settings().active_texture(index), || {
515            gl.context()
516                .bind_texture(Context::TEXTURE_2D, texture.map(|texture| texture.handle()));
517        })
518    }
519}
520
521impl Settings for TextureSetting {
522    fn apply<R, F: FnOnce() -> R>(
523        &self,
524        gl: &Gl,
525        cache: &RefCell<SettingsCache>,
526        callback: F,
527    ) -> R {
528        let previous = cache.borrow().textures[self.index as usize].clone();
529        cache.borrow_mut().textures[self.index as usize] = self.texture.clone();
530        Self::set_texture(gl, self.index, self.texture.as_ref());
531        let result = callback();
532        Self::set_texture(gl, self.index, previous.as_ref());
533        cache.borrow_mut().textures[self.index as usize] = previous;
534        return result;
535    }
536}
537
538#[derive(Clone, Debug, Default, PartialEq, Eq)]
539pub struct TextureListSetting {
540    textures: [Option<Texture>; 16],
541}
542
543impl TextureListSetting {
544    pub(self) fn set_textures(
545        gl: &Gl,
546        current: &[Option<Texture>; 16],
547        target: &[Option<Texture>; 16],
548    ) {
549        for i in 0..16 {
550            if current[i] != target[i] {
551                TextureSetting::set_texture(gl, i.try_into().unwrap(), target[i].as_ref());
552            }
553        }
554    }
555}
556
557impl Settings for TextureListSetting {
558    fn apply<R, F: FnOnce() -> R>(
559        &self,
560        gl: &Gl,
561        cache: &RefCell<SettingsCache>,
562        callback: F,
563    ) -> R {
564        let previous = cache.borrow().textures.clone();
565
566        cache.borrow_mut().textures = self.textures.clone();
567        TextureListSetting::set_textures(gl, &previous, &self.textures);
568
569        let result = callback();
570
571        TextureListSetting::set_textures(gl, &self.textures, &previous);
572        cache.borrow_mut().textures = previous;
573
574        return result;
575    }
576}
577
578#[derive(Clone, Debug, PartialEq, Eq)]
579pub struct TextureFilterSetting {
580    texture: Texture,
581    filter: TextureFilter,
582}
583
584impl Settings for TextureFilterSetting {
585    fn apply<R, F: FnOnce() -> R>(&self, _: &Gl, _: &RefCell<SettingsCache>, callback: F) -> R {
586        let previous = self.texture.filter();
587        let current = self.filter;
588        self.texture.set_filter(current);
589        let result = callback();
590        self.texture.set_filter(previous);
591        return result;
592    }
593}
594
595fn array_diff<'a, T: PartialEq>(v1: &'a Vec<T>, v2: &'a Vec<T>) -> impl Iterator<Item = &'a T> {
596    v1.iter().filter(move |i| !v2.contains(i))
597}
598
599#[derive(Clone, Debug, Default, PartialEq, Eq)]
600pub struct EnabledAttributesSetting {
601    items: Vec<u32>,
602}
603
604impl Settings for EnabledAttributesSetting {
605    fn apply<R, F: FnOnce() -> R>(
606        &self,
607        gl: &Gl,
608        cache: &RefCell<SettingsCache>,
609        callback: F,
610    ) -> R {
611        let context: &Context = gl.context();
612        // get old value
613        let previous = { cache.borrow().enabled_attributes.clone() };
614
615        // set current value
616        {
617            cache.borrow_mut().enabled_attributes = self.clone();
618        }
619
620        // disable extra attributes
621        array_diff(&previous.items, &self.items).for_each(|i| {
622            context.disable_vertex_attrib_array(*i);
623        });
624
625        // enable disabled attributes
626        array_diff(&self.items, &previous.items).for_each(|i| {
627            context.enable_vertex_attrib_array(*i);
628        });
629
630        // do the stuff
631        let result = callback();
632
633        // rollback changes
634        array_diff(&previous.items, &self.items).for_each(|i| {
635            context.enable_vertex_attrib_array(*i);
636        });
637
638        array_diff(&self.items, &previous.items).for_each(|i| {
639            context.disable_vertex_attrib_array(*i);
640        });
641
642        {
643            cache.borrow_mut().enabled_attributes = previous;
644        }
645
646        return result;
647    }
648}
649
650#[derive(Clone, Debug, Default, PartialEq, Eq)]
651pub struct InstancedAttributesSetting {
652    items: Vec<u32>,
653}
654
655impl Settings for InstancedAttributesSetting {
656    fn apply<R, F: FnOnce() -> R>(
657        &self,
658        gl: &Gl,
659        cache: &RefCell<SettingsCache>,
660        callback: F,
661    ) -> R {
662        let context: &AngleInstancedArrays = gl.instanced_arrays();
663        // get old value
664        let previous = { cache.borrow().instanced_attributes.clone() };
665
666        // set current value
667        {
668            cache.borrow_mut().instanced_attributes = self.clone();
669        }
670
671        // disable instancing
672        array_diff(&previous.items, &self.items).for_each(|i| {
673            context.vertex_attrib_divisor_angle(*i, 0);
674        });
675
676        // enable instancing
677        array_diff(&self.items, &previous.items).for_each(|i| {
678            context.vertex_attrib_divisor_angle(*i, 1);
679        });
680
681        // do the stuff
682        let result = callback();
683
684        // rollback changes
685        array_diff(&previous.items, &self.items).for_each(|i| {
686            context.vertex_attrib_divisor_angle(*i, 1);
687        });
688
689        array_diff(&self.items, &previous.items).for_each(|i| {
690            context.vertex_attrib_divisor_angle(*i, 0);
691        });
692
693        {
694            cache.borrow_mut().instanced_attributes = previous;
695        }
696
697        return result;
698    }
699}
700
701#[derive(Clone, Debug, Default, PartialEq, Eq)]
702pub struct ProgramSetting {
703    program: Option<Program>,
704}
705
706impl CachedSettings for ProgramSetting {
707    fn set(gl: &Gl, value: &Self) {
708        gl.context().use_program(
709            value
710                .program
711                .as_ref()
712                .map(|program| program.handle())
713                .as_ref(),
714        );
715    }
716
717    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
718        cache.program.clone()
719    }
720
721    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
722        cache.program = value.clone();
723    }
724}
725
726#[derive(Clone, Debug, Default, PartialEq, Eq)]
727pub struct DepthBufferSetting {
728    buffer: Option<DepthBuffer>,
729}
730
731impl CachedSettings for DepthBufferSetting {
732    fn set(gl: &Gl, value: &Self) {
733        gl.context().bind_renderbuffer(
734            Context::RENDERBUFFER,
735            value.buffer.as_ref().map(|v| v.handle()),
736        );
737    }
738
739    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
740        cache.depth_buffer.clone()
741    }
742
743    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
744        cache.depth_buffer = value.clone();
745    }
746}
747
748#[derive(Clone, Debug, Default, PartialEq, Eq)]
749pub struct FrameBufferSetting {
750    buffer: Option<FrameBuffer>,
751}
752
753impl CachedSettings for FrameBufferSetting {
754    fn set(gl: &Gl, value: &Self) {
755        gl.context().bind_framebuffer(
756            Context::FRAMEBUFFER,
757            value.buffer.as_ref().map(|v| v.handle()),
758        );
759    }
760
761    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
762        cache.frame_buffer.clone()
763    }
764
765    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
766        cache.frame_buffer = value.clone();
767    }
768}
769
770#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
771pub struct BlendEquationSetting {
772    color: BlendEquation,
773    alpha: BlendEquation,
774}
775
776impl CachedSettings for BlendEquationSetting {
777    fn set(gl: &Gl, value: &Self) {
778        gl.context()
779            .blend_equation_separate(value.color.into(), value.alpha.into());
780    }
781
782    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
783        cache.blend_equation
784    }
785
786    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
787        cache.blend_equation = *value;
788    }
789}
790
791#[derive(Clone, Copy, Debug, PartialEq, Eq)]
792pub struct BlendFunctionSetting {
793    src_rgb: BlendFunction,
794    dst_rgb: BlendFunction,
795    src_alpha: BlendFunction,
796    dst_alpha: BlendFunction,
797}
798
799impl Default for BlendFunctionSetting {
800    fn default() -> Self {
801        BlendFunctionSetting {
802            src_rgb: BlendFunction::One,
803            dst_rgb: BlendFunction::Zero,
804            src_alpha: BlendFunction::One,
805            dst_alpha: BlendFunction::Zero,
806        }
807    }
808}
809
810impl CachedSettings for BlendFunctionSetting {
811    fn set(gl: &Gl, value: &Self) {
812        gl.context().blend_func_separate(
813            value.src_rgb.into(),
814            value.dst_rgb.into(),
815            value.src_alpha.into(),
816            value.dst_alpha.into(),
817        );
818    }
819
820    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
821        cache.blend_function
822    }
823
824    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
825        cache.blend_function = *value;
826    }
827}
828
829impl CachedSettings for DepthFunction {
830    fn set(gl: &Gl, value: &Self) {
831        gl.context().depth_func((*value).into());
832    }
833
834    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
835        cache.depth_function
836    }
837
838    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
839        cache.depth_function = *value;
840    }
841}
842
843impl CachedSettings for CullFace {
844    fn set(gl: &Gl, value: &Self) {
845        gl.context().cull_face((*value).into());
846    }
847
848    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
849        cache.cull_face
850    }
851
852    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
853        cache.cull_face = *value;
854    }
855}
856
857impl CachedSettings for ColorMask {
858    fn set(gl: &Gl, value: &Self) {
859        gl.context().color_mask(value.0, value.1, value.2, value.3);
860    }
861
862    fn read_cached(cache: &impl Deref<Target = SettingsCache>) -> Self {
863        cache.color_mask
864    }
865
866    fn write_cached(cache: &mut impl DerefMut<Target = SettingsCache>, value: &Self) {
867        cache.color_mask = *value;
868    }
869}