mod3d_gl/
opengl.rs

1use std::collections::HashMap;
2
3use mod3d_base::{BufferDataAccessor, BufferElementType, BufferIndexAccessor, VertexAttr};
4
5use crate::{Gl, GlProgram, GlShaderType, Mat4, PipelineDesc, UniformBuffer};
6
7mod shader;
8pub mod utils;
9pub use shader::Shader;
10mod program;
11pub use program::Program;
12
13mod buffer;
14mod texture;
15
16mod vao;
17use vao::Vao;
18
19//a Model3DOpenGL
20//tp Model3DOpenGL
21#[derive(Debug)]
22pub struct Model3DOpenGL {}
23
24//ip Default for Model3DOpenGL
25impl Default for Model3DOpenGL {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31//ip Model3DOpenGL
32impl Model3DOpenGL {
33    pub fn new() -> Self {
34        Self {}
35    }
36
37    //fp compile_and_link_program
38    /// Create a program from a list of compiled shaders
39    pub fn compile_and_link_program(
40        &self,
41        vertex_src: String,
42        fragment_src: String,
43        named_attrs: Vec<(String, mod3d_base::VertexAttr)>,
44        named_uniforms: Vec<(String, crate::UniformId)>,
45        named_uniform_buffers: HashMap<String, usize>,
46        named_textures: Vec<(String, crate::TextureId, usize)>,
47    ) -> Result<<Self as Gl>::Program, String> {
48        let vert_shader = Shader::compile(&vertex_src, GlShaderType::Vertex)?;
49        let frag_shader = Shader::compile(&fragment_src, GlShaderType::Fragment)?;
50
51        let mut program = Program::link_program(&[&vert_shader, &frag_shader])?;
52        for (name, attr) in named_attrs {
53            program.add_attr_name(&name, attr)?;
54        }
55        for (name, uniform) in named_uniforms {
56            program.add_uniform_name(&name, uniform)?;
57        }
58        for (name, uniform) in named_uniform_buffers {
59            program.add_uniform_buffer_name(&name, uniform)?;
60        }
61        for (name, texture_id, unit) in named_textures {
62            program.add_uniform_texture_name(&name, texture_id, unit)?;
63        }
64        Ok(program)
65    }
66}
67
68//ip Gl for Model3DOpenGL
69impl Gl for Model3DOpenGL {
70    // type Id = u32;
71    // type Shader = Shader;
72    type Program = Program;
73    type Buffer = buffer::Buffer;
74    type Vao = vao::Vao;
75    type Texture = texture::Texture;
76    type PipelineDesc<'a> = PipelineDesc;
77
78    fn create_pipeline<F: Fn(&str) -> Result<String, String>>(
79        &mut self,
80        read_src: &F,
81        pipeline_desc: Box<Self::PipelineDesc<'_>>,
82    ) -> Result<Self::Program, String> {
83        let compile_and_link_program = |v_src, f_src, na, nu, nub, nt| {
84            self.compile_and_link_program(v_src, f_src, na, nu, nub, nt)
85        };
86        pipeline_desc.compile(read_src, &compile_and_link_program)
87    }
88
89    //mp use_program
90    /// Use the program
91    fn use_program(&self, program: Option<&Self::Program>) {
92        if let Some(program) = program {
93            program.set_used();
94        } else {
95            unsafe {
96                gl::UseProgram(0);
97            }
98        }
99    }
100
101    //mp init_buffer_of_indices
102    fn init_buffer_of_indices(
103        &mut self,
104        buffer: &mut <Self as Gl>::Buffer,
105        view: &BufferIndexAccessor<Self>,
106    ) {
107        buffer.of_indices(view);
108    }
109
110    //mp vao_create_from_indices
111    fn vao_create_from_indices(&mut self, indices: &crate::IndexBuffer<Self>) -> Result<Vao, ()> {
112        Vao::create_from_indices(self, indices)
113    }
114
115    //mp buffer_bind_to_vao_attr
116    fn buffer_bind_to_vao_attr(
117        &mut self,
118        buffer: &<Self as Gl>::Buffer,
119        attr_id: &<Program as GlProgram>::GlAttrId,
120        count: u32,
121        ele_type: BufferElementType,
122        byte_offset: u32,
123        stride: u32,
124    ) {
125        buffer.bind_to_vao_attr(*attr_id, count, ele_type, byte_offset, stride);
126    }
127
128    //mp program_set_uniform_mat4
129    fn program_set_uniform_mat4(&mut self, program: &Program, id: crate::UniformId, mat4: &Mat4) {
130        if let Some(u) = program.uniform(id) {
131            unsafe {
132                gl::UniformMatrix4fv(u, 1, gl::FALSE, mat4.as_ptr());
133            }
134        }
135    }
136
137    //fp program_set_uniform_floats_4
138    fn program_set_uniform_floats_4(
139        &mut self,
140        program: &Self::Program,
141        id: crate::UniformId,
142        floats: &[f32],
143    ) {
144        if let Some(u) = program.uniform(id) {
145            unsafe {
146                gl::Uniform4fv(u, (floats.len() / 4) as i32, floats.as_ptr());
147            }
148        }
149    }
150
151    //mp program_bind_uniform_index
152    fn program_bind_uniform_index(
153        &mut self,
154        program: &<Self as Gl>::Program,
155        uniform_buffer_id: usize,
156        gl_uindex: u32,
157    ) -> Result<(), ()> {
158        if let Some(u) = program.uniform(crate::UniformId::Buffer(uniform_buffer_id as u8)) {
159            unsafe {
160                println!(
161                    "Bind program uniform buffer {} to the binding point {}",
162                    u, gl_uindex
163                );
164                gl::UniformBlockBinding(program.id(), u as u32, gl_uindex);
165            }
166            utils::check_errors().expect("Bound uniform");
167        }
168        Ok(())
169    }
170
171    //mp program_use_texture
172    /// Requires the program to be 'used'
173    fn program_use_texture(
174        &mut self,
175        program: &<Self as Gl>::Program,
176        texture_id: crate::TextureId,
177        gl_texture: &<Self as Gl>::Texture,
178    ) {
179        if let Some((u, unit)) = program.texture_uniform(texture_id) {
180            unsafe {
181                gl::ActiveTexture(gl::TEXTURE0 + unit);
182                gl::BindTexture(gl::TEXTURE_2D, gl_texture.gl_texture());
183                gl::Uniform1i(u as i32, unit as i32);
184            }
185        }
186    }
187
188    //mp draw_primitive
189    fn draw_primitive(&mut self, vaos: &[Vao], primitive: &mod3d_base::Primitive) {
190        // (if p.vertices_index different to last)
191        // (if p.material_index ...
192        use mod3d_base::PrimitiveType::*;
193        let gl_type = match primitive.primitive_type() {
194            Points => gl::POINTS,
195            Lines => gl::LINES,
196            LineLoop => gl::LINE_LOOP,
197            LineStrip => gl::LINE_STRIP,
198            Triangles => gl::TRIANGLES,
199            TriangleFan => gl::TRIANGLE_FAN,
200            TriangleStrip => gl::TRIANGLE_STRIP,
201        };
202
203        let opt_vertices_index: Option<usize> = primitive.vertices_index().into();
204        if let Some(vertices_index) = opt_vertices_index {
205            let index_type = vaos[vertices_index].bind_vao();
206            unsafe {
207                gl::DrawElements(
208                    gl_type,
209                    primitive.index_count() as i32,
210                    index_type,
211                    primitive.byte_offset() as *const std::ffi::c_void,
212                );
213            }
214        } else {
215            unsafe {
216                gl::DrawArrays(
217                    gl_type,
218                    primitive.byte_offset() as i32,
219                    primitive.index_count() as i32,
220                );
221            }
222        }
223    }
224
225    //mp bind_vao
226    fn bind_vao(&mut self, vao: Option<&Self::Vao>) {
227        if let Some(vao) = vao {
228            vao.bind_vao();
229        } else {
230            unsafe {
231                gl::BindVertexArray(0);
232            }
233        }
234    }
235
236    //mp uniform_buffer_create
237    fn uniform_buffer_create<F: Sized>(
238        &mut self,
239        data: &[F],
240        is_dynamic: bool,
241    ) -> Result<UniformBuffer<Self>, ()> {
242        let byte_length = std::mem::size_of_val(data);
243        let mut gl = buffer::Buffer::default();
244        gl.uniform_buffer(data, is_dynamic)?;
245        Ok(UniformBuffer::new(gl, byte_length))
246    }
247
248    //mp uniform_buffer_update_data
249    fn uniform_buffer_update_data<F: std::fmt::Debug>(
250        &mut self,
251        uniform_buffer: &UniformBuffer<Self>,
252        data: &[F],
253        byte_offset: u32,
254    ) {
255        uniform_buffer
256            .gl_buffer()
257            .uniform_update_data(data, byte_offset);
258    }
259
260    //mp uniform_index_of_range
261    fn uniform_index_of_range(
262        &mut self,
263        uniform_buffer: &UniformBuffer<Self>,
264        gl_uindex: u32,
265        byte_offset: usize,
266        byte_length: usize,
267    ) {
268        let (byte_offset, byte_length) = uniform_buffer.offset_and_length(byte_offset, byte_length);
269        unsafe {
270            gl::BindBufferRange(
271                gl::UNIFORM_BUFFER,
272                gl_uindex,
273                uniform_buffer.gl_buffer().gl_buffer(),
274                byte_offset as isize,
275                byte_length as isize,
276            );
277        }
278    }
279}
280
281//ip mod3d_base::Renderable for Model3DOpenGL
282impl mod3d_base::Renderable for Model3DOpenGL {
283    type Buffer = buffer::Buffer;
284    type IndexAccessor = crate::BufferView<Self>;
285    type DataAccessor = crate::BufferView<Self>;
286    type Texture = texture::Texture;
287    type Material = crate::Material;
288    type Vertices = crate::Vertices<Self>;
289    type Descriptor = crate::Descriptor;
290
291    //mp init_buffer_desc_client
292    /// Initialize a buffer descriptor client - it will have been created using default()
293    fn init_buffer_desc_client(
294        &mut self,
295        _client: &mut Self::Descriptor,
296        _buffer_desc: &mod3d_base::BufferDescriptor<Self>,
297    ) {
298        todo!();
299    }
300
301    //mp init_buffer_data_client
302    /// Initialize a BufferData client
303    ///
304    /// This may be called multiple times for the same [BufferData]; if the
305    /// gl buffer is 0 then create, else it already exists with the same data
306    fn init_buffer_data_client(
307        &mut self,
308        client: &mut Self::Buffer,
309        buffer_data: &mod3d_base::BufferData<Self>,
310    ) {
311        if client.is_none() {
312            client.of_data(buffer_data)
313        }
314    }
315
316    //mp init_index_accessor_client
317    /// Initialize an accessor of indices
318    fn init_index_accessor_client(
319        &mut self,
320        client: &mut Self::IndexAccessor,
321        buffer_view: &BufferIndexAccessor<Self>,
322    ) {
323        client.init_index_accessor_client(buffer_view, self);
324    }
325
326    //mp init_buffer_view_client
327    /// Initialize a buffer view client
328    fn init_buffer_view_client(
329        &mut self,
330        client: &mut Self::DataAccessor,
331        buffer_view: &BufferDataAccessor<Self>,
332        attr: VertexAttr,
333    ) {
334        client.init_buffer_view_client(buffer_view, attr, self);
335    }
336
337    //mp create_vertices_client
338    fn create_vertices_client(&mut self, vertices: &mod3d_base::Vertices<Self>) -> Self::Vertices {
339        Self::Vertices::create(vertices, self)
340    }
341
342    //mp create_texture_client
343    fn create_texture_client(&mut self, texture: &mod3d_base::Texture<Self>) -> Self::Texture {
344        eprintln!("Create texture client");
345        Self::Texture::of_texture(texture) // , self)
346    }
347
348    fn create_material_client<M>(
349        &mut self,
350        object: &mod3d_base::Object<M, Self>,
351        material: &M,
352    ) -> crate::Material
353    where
354        M: mod3d_base::Material,
355    {
356        eprintln!("Create material client");
357        crate::Material::create(self, object, material).unwrap()
358    }
359
360    //mp init_material_client
361    fn init_material_client<M: mod3d_base::Material>(
362        &mut self,
363        _client: &mut Self::Material,
364        _material: &M,
365    ) {
366    }
367
368    //zz All done
369}