Skip to main content

coffee/graphics/backend_gfx/
triangle.rs

1use 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}