retrofire_core/render/
ctx.rs

1//! Rendering context and parameters.
2
3use core::{cell::RefCell, cmp::Ordering};
4
5use crate::math::{Color4, rgba};
6
7use super::Stats;
8
9/// Context and parameters used by the renderer.
10#[derive(Clone, Debug)]
11pub struct Context {
12    /// The color with which to fill the color buffer to clear it, if any.
13    ///
14    /// If rendered geometry always fills the entire frame, `color_clear`
15    /// can be set to `None` to avoid redundant work.
16    pub color_clear: Option<Color4>,
17
18    /// The value with which to fill the depth buffer to clear it, if any.
19    pub depth_clear: Option<f32>,
20
21    /// Whether to cull (discard) faces pointing either away from or towards
22    /// the camera.
23    ///
24    /// If all geometry drawn is "solid" meshes without holes, backfaces can
25    /// usually be culled because they are always occluded by front faces and
26    /// drawing them would be redundant.
27    pub face_cull: Option<FaceCull>,
28
29    /// Whether to sort visible faces by their depth.
30    ///
31    /// If z-buffering or other hidden surface determination method is not used,
32    /// back-to-front depth sorting can be used to ensure correct rendering
33    /// unless there is intersecting or non-orderable geometry (this is the
34    /// so-called "painter's algorithm").
35    ///
36    /// Overlapping transparent surfaces have to be drawn back-to-front to get
37    /// correct results. Rendering nontransparent geometry in front-to-back
38    /// order can improve performance by reducing overdraw.
39    pub depth_sort: Option<DepthSort>,
40
41    /// Whether to do depth testing and which predicate to use.
42    ///
43    /// If set to `Some(Ordering::Less)`, a fragment passes the depth test
44    /// *iff* `new_z < old_z` (the default). If set to `None`, depth test
45    /// is not performed. This setting has no effect if the render target
46    /// does not support z-buffering.
47    pub depth_test: Option<Ordering>,
48
49    /// Whether to write color values.
50    ///
51    /// If `false`, other fragment processing is done but there is no color
52    /// output. This setting has no effect if the render target does not
53    /// support color writes.
54    pub color_write: bool,
55
56    /// Whether to write depth values.
57    ///
58    /// If `false`, other fragment processing is done but there is no depth
59    /// output. This setting has no effect if the render target does not
60    /// support depth writes.
61    pub depth_write: bool,
62
63    /// Collecting rendering statistics.
64    pub stats: RefCell<Stats>,
65}
66
67/// Whether to sort faces front to back or back to front.
68#[derive(Copy, Clone, Debug, Eq, PartialEq)]
69pub enum DepthSort {
70    FrontToBack,
71    BackToFront,
72}
73
74/// Whether to cull front faces or backfaces.
75#[derive(Copy, Clone, Debug, Eq, PartialEq)]
76pub enum FaceCull {
77    Front,
78    Back,
79}
80
81impl Context {
82    /// Compares the reciprocal depth value `new` to `curr` and returns
83    /// whether `new` passes the depth test specified by `self.depth_test`.
84    /// If `self.depth_test` is `None`, always returns `true`.
85    #[inline]
86    pub fn depth_test(&self, new: f32, curr: f32) -> bool {
87        // Reverse comparison because we're comparing reciprocals
88        self.depth_test.is_none() || self.depth_test == curr.partial_cmp(&new)
89    }
90
91    /// Returns whether a primitive should be culled based on the current face
92    /// culling setting.
93    // TODO this could also be in Render
94    #[inline]
95    pub fn face_cull(&self, is_backface: bool) -> bool {
96        match self.face_cull {
97            Some(FaceCull::Back) if is_backface => true,
98            Some(FaceCull::Front) if !is_backface => true,
99            _ => false,
100        }
101    }
102}
103
104impl Default for Context {
105    /// Creates a rendering context with default settings.
106    ///
107    /// The default values are:
108    /// * Color clear:   Opaque black
109    /// * Depth clear:   Positive infinity
110    /// * Face culling:  Backfaces
111    /// * Depth sorting: Disabled
112    /// * Color writes:  Enabled
113    /// * Depth testing: Pass if closer
114    /// * Depth writes:  Enabled
115    fn default() -> Self {
116        Self {
117            color_clear: Some(rgba(0, 0, 0, 0xFF)),
118            depth_clear: Some(f32::INFINITY),
119            face_cull: Some(FaceCull::Back),
120            depth_sort: None,
121            color_write: true,
122            depth_test: Some(Ordering::Less),
123            depth_write: true,
124            stats: Default::default(),
125        }
126    }
127}