1use {
4 crate::{
5 color::Format,
6 shader::{ShaderData, SlotNumbers},
7 state::State,
8 },
9 std::marker::PhantomData,
10};
11
12#[derive(Clone, Copy, Default)]
14pub enum Blend {
15 #[default]
16 None,
17 Replace,
18 Alpha,
19}
20
21impl Blend {
22 fn wgpu(self) -> Option<wgpu::BlendState> {
23 match self {
24 Self::None => None,
25 Self::Replace => Some(wgpu::BlendState::REPLACE),
26 Self::Alpha => Some(wgpu::BlendState::ALPHA_BLENDING),
27 }
28 }
29}
30
31#[derive(Clone, Copy, Default)]
33pub enum Topology {
34 PointList,
35 LineList,
36 LineStrip,
37 #[default]
38 TriangleList,
39 TriangleStrip,
40}
41
42impl Topology {
43 fn wgpu(self) -> wgpu::PrimitiveTopology {
44 match self {
45 Self::PointList => wgpu::PrimitiveTopology::PointList,
46 Self::LineList => wgpu::PrimitiveTopology::LineList,
47 Self::LineStrip => wgpu::PrimitiveTopology::LineStrip,
48 Self::TriangleList => wgpu::PrimitiveTopology::TriangleList,
49 Self::TriangleStrip => wgpu::PrimitiveTopology::TriangleStrip,
50 }
51 }
52}
53
54#[derive(Clone, Copy, Default)]
56pub enum Polygon {
57 #[default]
58 Fill,
59 #[cfg(not(target_family = "wasm"))]
60 Line,
61 #[cfg(not(target_family = "wasm"))]
62 Point,
63}
64
65impl Polygon {
66 fn wgpu(self) -> wgpu::PolygonMode {
67 match self {
68 Self::Fill => wgpu::PolygonMode::Fill,
69 #[cfg(not(target_family = "wasm"))]
70 Self::Line => wgpu::PolygonMode::Line,
71 #[cfg(not(target_family = "wasm"))]
72 Self::Point => wgpu::PolygonMode::Point,
73 }
74 }
75}
76
77#[derive(Clone, Copy, Default)]
79pub enum Depth {
80 #[default]
81 None,
82 Noop,
83 Less,
84 Greater,
85}
86
87#[derive(Clone, Copy, Default)]
91pub struct Config {
92 pub format: Format,
93 pub blend: Blend,
94 pub topology: Topology,
95 pub polygon: Polygon,
96 pub depth: Depth,
97}
98
99impl From<Format> for Config {
100 fn from(format: Format) -> Self {
101 Self {
102 format,
103 ..Default::default()
104 }
105 }
106}
107
108pub struct Layer<I> {
112 slots: SlotNumbers,
113 depth: Depth,
114 format: Format,
115 render: wgpu::RenderPipeline,
116 inp: PhantomData<I>,
117}
118
119impl<I> Layer<I> {
120 pub(crate) fn new(state: &State, shader: &ShaderData, conf: Config) -> Self {
121 let Config {
122 format,
123 blend,
124 topology,
125 polygon,
126 depth,
127 } = conf;
128
129 let targets = [Some(wgpu::ColorTargetState {
130 format: format.wgpu(),
131 blend: blend.wgpu(),
132 write_mask: wgpu::ColorWrites::ALL,
133 })];
134
135 let module = shader.module();
136 let buffers = shader.vertex_buffers();
137 let topology = topology.wgpu();
138 let desc = wgpu::RenderPipelineDescriptor {
139 label: None,
140 layout: Some(shader.layout()),
141 vertex: wgpu::VertexState {
142 module,
143 entry_point: Some("vs"),
144 compilation_options: wgpu::PipelineCompilationOptions::default(),
145 buffers: &buffers,
146 },
147 primitive: wgpu::PrimitiveState {
148 topology,
149 strip_index_format: topology.is_strip().then_some(wgpu::IndexFormat::Uint32),
150 cull_mode: Some(wgpu::Face::Back),
151 polygon_mode: polygon.wgpu(),
152 ..Default::default()
153 },
154 depth_stencil: match depth {
155 Depth::None => None,
156 Depth::Noop => Some(wgpu::CompareFunction::Always),
157 Depth::Less => Some(wgpu::CompareFunction::Less),
158 Depth::Greater => Some(wgpu::CompareFunction::Greater),
159 }
160 .map(|depth_compare| wgpu::DepthStencilState {
161 format: Format::Depth.wgpu(),
162 depth_write_enabled: Some(true),
163 depth_compare: Some(depth_compare),
164 stencil: wgpu::StencilState::default(),
165 bias: wgpu::DepthBiasState::default(),
166 }),
167 multisample: wgpu::MultisampleState::default(),
168 fragment: Some(wgpu::FragmentState {
169 module,
170 entry_point: Some("fs"),
171 compilation_options: wgpu::PipelineCompilationOptions::default(),
172 targets: &targets,
173 }),
174 multiview_mask: None,
175 cache: None,
176 };
177
178 let render = state.device().create_render_pipeline(&desc);
179
180 Self {
181 slots: shader.slots(),
182 depth,
183 format,
184 render,
185 inp: PhantomData,
186 }
187 }
188
189 pub(crate) fn slots(&self) -> SlotNumbers {
190 self.slots
191 }
192
193 pub fn depth(&self) -> bool {
195 !matches!(self.depth, Depth::None)
196 }
197
198 pub fn format(&self) -> Format {
200 self.format
201 }
202
203 pub(crate) fn render(&self) -> &wgpu::RenderPipeline {
204 &self.render
205 }
206}