Skip to main content

proof_engine/deferred/
mod.rs

1//! Deferred rendering subsystem for the Proof Engine.
2//!
3//! This module implements a full deferred rendering pipeline with:
4//! - G-Buffer management with configurable attachments
5//! - Multi-pass deferred rendering (depth pre-pass, geometry, lighting, forward, post-process)
6//! - PBR material system with instancing support
7//! - Anti-aliasing (FXAA, TAA, MSAA, CAS sharpening)
8
9pub mod gbuffer;
10pub mod pipeline;
11pub mod materials;
12pub mod antialiasing;
13
14// Re-export primary types for convenience.
15pub use gbuffer::{
16    GBuffer, GBufferLayout, GBufferAttachment, GBufferAttachmentFormat,
17    GBufferDebugView, GBufferDebugChannel, GBufferStats, MrtConfig, ClearValue,
18};
19pub use pipeline::{
20    DeferredPipeline, DepthPrePass, GeometryPass, LightingPass, ForwardPass,
21    PostProcessPass, HdrFramebuffer, ExposureController, ExposureMode,
22    RenderQueue, RenderBucket, RenderItem, SortMode,
23};
24pub use materials::{
25    PbrMaterial, MaterialInstance, MaterialLibrary, MaterialSortKey,
26    InstanceData, MaterialPreset, MaterialPresets,
27};
28pub use antialiasing::{
29    AntiAliasingMode, FxaaPass, FxaaQuality, TaaPass, TaaConfig,
30    MsaaConfig, MsaaSampleCount, SharpeningPass, CasConfig,
31};
32
33/// Identifier for a render target texture slot.
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35pub struct TextureSlot(pub u32);
36
37/// Identifier for a framebuffer object in the deferred pipeline.
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
39pub struct FramebufferId(pub u32);
40
41/// Viewport dimensions used throughout the deferred pipeline.
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct Viewport {
44    pub x: i32,
45    pub y: i32,
46    pub width: u32,
47    pub height: u32,
48}
49
50impl Viewport {
51    pub fn new(width: u32, height: u32) -> Self {
52        Self { x: 0, y: 0, width, height }
53    }
54
55    pub fn aspect_ratio(&self) -> f32 {
56        if self.height == 0 {
57            1.0
58        } else {
59            self.width as f32 / self.height as f32
60        }
61    }
62
63    pub fn pixel_count(&self) -> u64 {
64        self.width as u64 * self.height as u64
65    }
66}
67
68impl Default for Viewport {
69    fn default() -> Self {
70        Self { x: 0, y: 0, width: 1920, height: 1080 }
71    }
72}
73
74/// Common 4x4 matrix type used in the deferred pipeline (column-major).
75#[derive(Debug, Clone, Copy)]
76pub struct Mat4 {
77    pub cols: [[f32; 4]; 4],
78}
79
80impl Mat4 {
81    pub const IDENTITY: Self = Self {
82        cols: [
83            [1.0, 0.0, 0.0, 0.0],
84            [0.0, 1.0, 0.0, 0.0],
85            [0.0, 0.0, 1.0, 0.0],
86            [0.0, 0.0, 0.0, 1.0],
87        ],
88    };
89
90    pub fn from_cols(c0: [f32; 4], c1: [f32; 4], c2: [f32; 4], c3: [f32; 4]) -> Self {
91        Self { cols: [c0, c1, c2, c3] }
92    }
93
94    pub fn mul_mat4(&self, rhs: &Mat4) -> Mat4 {
95        let mut result = [[0.0f32; 4]; 4];
96        for col in 0..4 {
97            for row in 0..4 {
98                let mut sum = 0.0f32;
99                for k in 0..4 {
100                    sum += self.cols[k][row] * rhs.cols[col][k];
101                }
102                result[col][row] = sum;
103            }
104        }
105        Mat4 { cols: result }
106    }
107
108    pub fn mul_vec4(&self, v: [f32; 4]) -> [f32; 4] {
109        let mut result = [0.0f32; 4];
110        for row in 0..4 {
111            for col in 0..4 {
112                result[row] += self.cols[col][row] * v[col];
113            }
114        }
115        result
116    }
117
118    pub fn transpose(&self) -> Mat4 {
119        let mut result = [[0.0f32; 4]; 4];
120        for i in 0..4 {
121            for j in 0..4 {
122                result[i][j] = self.cols[j][i];
123            }
124        }
125        Mat4 { cols: result }
126    }
127
128    pub fn perspective(fov_y_rad: f32, aspect: f32, near: f32, far: f32) -> Self {
129        let f = 1.0 / (fov_y_rad * 0.5).tan();
130        let nf = 1.0 / (near - far);
131        Self {
132            cols: [
133                [f / aspect, 0.0, 0.0, 0.0],
134                [0.0, f, 0.0, 0.0],
135                [0.0, 0.0, (far + near) * nf, -1.0],
136                [0.0, 0.0, 2.0 * far * near * nf, 0.0],
137            ],
138        }
139    }
140
141    pub fn look_at(eye: [f32; 3], center: [f32; 3], up: [f32; 3]) -> Self {
142        let f = vec3_normalize([
143            center[0] - eye[0],
144            center[1] - eye[1],
145            center[2] - eye[2],
146        ]);
147        let s = vec3_normalize(vec3_cross(f, up));
148        let u = vec3_cross(s, f);
149        Self {
150            cols: [
151                [s[0], u[0], -f[0], 0.0],
152                [s[1], u[1], -f[1], 0.0],
153                [s[2], u[2], -f[2], 0.0],
154                [
155                    -vec3_dot(s, eye),
156                    -vec3_dot(u, eye),
157                    vec3_dot(f, eye),
158                    1.0,
159                ],
160            ],
161        }
162    }
163}
164
165impl Default for Mat4 {
166    fn default() -> Self {
167        Self::IDENTITY
168    }
169}
170
171/// 3-component vector helper functions.
172pub fn vec3_dot(a: [f32; 3], b: [f32; 3]) -> f32 {
173    a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
174}
175
176pub fn vec3_cross(a: [f32; 3], b: [f32; 3]) -> [f32; 3] {
177    [
178        a[1] * b[2] - a[2] * b[1],
179        a[2] * b[0] - a[0] * b[2],
180        a[0] * b[1] - a[1] * b[0],
181    ]
182}
183
184pub fn vec3_normalize(v: [f32; 3]) -> [f32; 3] {
185    let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
186    if len < 1e-10 {
187        [0.0, 0.0, 0.0]
188    } else {
189        [v[0] / len, v[1] / len, v[2] / len]
190    }
191}
192
193pub fn vec3_sub(a: [f32; 3], b: [f32; 3]) -> [f32; 3] {
194    [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
195}
196
197pub fn vec3_add(a: [f32; 3], b: [f32; 3]) -> [f32; 3] {
198    [a[0] + b[0], a[1] + b[1], a[2] + b[2]]
199}
200
201pub fn vec3_scale(v: [f32; 3], s: f32) -> [f32; 3] {
202    [v[0] * s, v[1] * s, v[2] * s]
203}
204
205pub fn vec3_length(v: [f32; 3]) -> f32 {
206    (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt()
207}
208
209pub fn vec3_lerp(a: [f32; 3], b: [f32; 3], t: f32) -> [f32; 3] {
210    [
211        a[0] + (b[0] - a[0]) * t,
212        a[1] + (b[1] - a[1]) * t,
213        a[2] + (b[2] - a[2]) * t,
214    ]
215}
216
217/// Clamp a float to [min, max].
218pub fn clampf(x: f32, min: f32, max: f32) -> f32 {
219    if x < min { min } else if x > max { max } else { x }
220}
221
222/// Linear interpolation.
223pub fn lerpf(a: f32, b: f32, t: f32) -> f32 {
224    a + (b - a) * t
225}
226
227/// Saturate to [0, 1].
228pub fn saturate(x: f32) -> f32 {
229    clampf(x, 0.0, 1.0)
230}
231
232/// Smoothstep interpolation.
233pub fn smoothstep(edge0: f32, edge1: f32, x: f32) -> f32 {
234    let t = saturate((x - edge0) / (edge1 - edge0));
235    t * t * (3.0 - 2.0 * t)
236}