coffee/graphics/backend_gfx/
triangle.rs1use gfx::traits::FactoryExt;
2use gfx::{self, *};
3use gfx_device_gl as gl;
4
5use super::format;
6use crate::graphics::Transformation;
7
8gfx_defines! {
9 vertex Vertex {
10 position: [f32; 2] = "a_Pos",
11 color: [f32; 4] = "a_Color",
12 }
13
14 constant Globals {
15 mvp: [[f32; 4]; 4] = "u_MVP",
16 }
17
18 pipeline pipe {
19 vertices: gfx::VertexBuffer<Vertex> = (),
20 globals: gfx::ConstantBuffer<Globals> = "Globals",
21 out: gfx::RawRenderTarget =
22 (
23 "Target0",
24 format::COLOR,
25 gfx::state::ColorMask::all(),
26 Some(gfx::preset::blend::ALPHA)
27 ),
28 }
29}
30
31pub struct Pipeline {
32 data: pipe::Data<gl::Resources>,
33 indices: gfx::handle::Buffer<gl::Resources, u32>,
34 shader: Shader,
35 globals: Globals,
36}
37
38impl Pipeline {
39 const INITIAL_BUFFER_SIZE: usize = 100_000;
40
41 pub fn new(
42 factory: &mut gl::Factory,
43 encoder: &mut gfx::Encoder<gl::Resources, gl::CommandBuffer>,
44 target: &gfx::handle::RawRenderTargetView<gl::Resources>,
45 ) -> Pipeline {
46 let vertices = factory
47 .create_buffer(
48 Self::INITIAL_BUFFER_SIZE,
49 gfx::buffer::Role::Vertex,
50 gfx::memory::Usage::Dynamic,
51 gfx::memory::Bind::SHADER_RESOURCE,
52 )
53 .expect("Vertex buffer creation");
54
55 let indices = factory
56 .create_buffer(
57 Self::INITIAL_BUFFER_SIZE,
58 gfx::buffer::Role::Index,
59 gfx::memory::Usage::Dynamic,
60 gfx::memory::Bind::empty(),
61 )
62 .expect("Index buffer creation");
63
64 let data = pipe::Data {
65 vertices,
66 globals: factory.create_constant_buffer(1),
67 out: target.clone(),
68 };
69
70 let init = pipe::Init {
71 out: (
72 "Target0",
73 format::COLOR,
74 gfx::state::ColorMask::all(),
75 Some(gfx::preset::blend::ALPHA),
76 ),
77 ..pipe::new()
78 };
79
80 let shader = Shader::new(factory, init);
81
82 let globals = Globals {
83 mvp: Transformation::identity().into(),
84 };
85
86 encoder
87 .update_buffer(&data.globals, &[globals], 0)
88 .expect("Globals initialization");
89
90 Pipeline {
91 data,
92 indices,
93 shader,
94 globals,
95 }
96 }
97
98 pub fn draw(
99 &mut self,
100 factory: &mut gl::Factory,
101 encoder: &mut gfx::Encoder<gl::Resources, gl::CommandBuffer>,
102 vertices: &[Vertex],
103 indices: &[u32],
104 transformation: &Transformation,
105 view: &gfx::handle::RawRenderTargetView<gl::Resources>,
106 ) {
107 let transformation_matrix: [[f32; 4]; 4] =
108 transformation.clone().into();
109
110 if self.globals.mvp != transformation_matrix {
111 self.globals.mvp = transformation_matrix;
112
113 encoder
114 .update_buffer(&self.data.globals, &[self.globals], 0)
115 .expect("Globals upload");
116 }
117
118 self.data.out = view.clone();
119
120 if self.data.vertices.len() < vertices.len()
121 || self.indices.len() < indices.len()
122 {
123 let vertices = factory
124 .create_buffer(
125 self.data.vertices.len(),
126 gfx::buffer::Role::Vertex,
127 gfx::memory::Usage::Dynamic,
128 gfx::memory::Bind::SHADER_RESOURCE,
129 )
130 .expect("Vertex buffer creation");
131
132 let indices = factory
133 .create_buffer(
134 indices.len(),
135 gfx::buffer::Role::Index,
136 gfx::memory::Usage::Dynamic,
137 gfx::memory::Bind::empty(),
138 )
139 .expect("Index buffer creation");
140
141 self.data.vertices = vertices;
142 self.indices = indices;
143 }
144
145 encoder
146 .update_buffer(&self.data.vertices, &vertices, 0)
147 .expect("Vertex upload");
148
149 encoder
150 .update_buffer(&self.indices, &indices, 0)
151 .expect("Index upload");
152
153 let slice = gfx::Slice {
154 start: 0,
155 end: indices.len() as u32,
156 base_vertex: 0,
157 instances: None,
158 buffer: gfx::IndexBuffer::Index32(self.indices.clone()),
159 };
160
161 encoder.draw(&slice, &self.shader.state, &self.data);
162 }
163}
164
165pub struct Shader {
166 state: gfx::pso::PipelineState<gl::Resources, pipe::Meta>,
167}
168
169impl Shader {
170 pub fn new(factory: &mut gl::Factory, init: pipe::Init<'_>) -> Shader {
171 let set = factory
172 .create_shader_set(
173 include_bytes!("shader/triangle.vert"),
174 include_bytes!("shader/triangle.frag"),
175 )
176 .expect("Shader set creation");
177
178 let rasterizer = gfx::state::Rasterizer {
179 front_face: gfx::state::FrontFace::CounterClockwise,
180 cull_face: gfx::state::CullFace::Nothing,
181 method: gfx::state::RasterMethod::Fill,
182 offset: None,
183 samples: None,
184 };
185
186 let state = factory
187 .create_pipeline_state(
188 &set,
189 Primitive::TriangleList,
190 rasterizer,
191 init,
192 )
193 .expect("Pipeline state creation");
194
195 Shader { state }
196 }
197}
198
199impl Vertex {
200 pub fn new(position: [f32; 2], color: [f32; 4]) -> Vertex {
201 Vertex { position, color }
202 }
203}