mod3d_gl/
opengl.rs

1use std::collections::HashMap;
2
3use mod3d_base::{BufferDataAccessor, BufferElementType, BufferIndexAccessor};
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!("Bind program uniform buffer {u} to the binding point {gl_uindex}");
161                gl::UniformBlockBinding(program.id(), u as u32, gl_uindex);
162            }
163            utils::check_errors().expect("Bound uniform");
164        }
165        Ok(())
166    }
167
168    //mp program_use_texture
169    /// Requires the program to be 'used'
170    fn program_use_texture(
171        &mut self,
172        program: &<Self as Gl>::Program,
173        texture_id: crate::TextureId,
174        gl_texture: &<Self as Gl>::Texture,
175    ) {
176        if let Some((u, unit)) = program.texture_uniform(texture_id) {
177            unsafe {
178                gl::ActiveTexture(gl::TEXTURE0 + unit);
179                gl::BindTexture(gl::TEXTURE_2D, gl_texture.gl_texture());
180                gl::Uniform1i(u, unit as i32);
181            }
182        }
183    }
184
185    //mp draw_primitive
186    fn draw_primitive(&mut self, vaos: &[Vao], primitive: &mod3d_base::Primitive) {
187        // (if p.vertices_index different to last)
188        // (if p.material_index ...
189        use mod3d_base::PrimitiveType::*;
190        let gl_type = match primitive.primitive_type() {
191            Points => gl::POINTS,
192            Lines => gl::LINES,
193            LineLoop => gl::LINE_LOOP,
194            LineStrip => gl::LINE_STRIP,
195            Triangles => gl::TRIANGLES,
196            TriangleFan => gl::TRIANGLE_FAN,
197            TriangleStrip => gl::TRIANGLE_STRIP,
198        };
199
200        let opt_vertices_index: Option<usize> = primitive.vertices_index().into();
201        if let Some(vertices_index) = opt_vertices_index {
202            let index_type = vaos[vertices_index].bind_vao();
203            unsafe {
204                gl::DrawElements(
205                    gl_type,
206                    primitive.index_count() as i32,
207                    index_type,
208                    primitive.byte_offset() as *const std::ffi::c_void,
209                );
210            }
211        } else {
212            unsafe {
213                gl::DrawArrays(
214                    gl_type,
215                    primitive.byte_offset() as i32,
216                    primitive.index_count() as i32,
217                );
218            }
219        }
220    }
221
222    //mp bind_vao
223    fn bind_vao(&mut self, vao: Option<&Self::Vao>) {
224        if let Some(vao) = vao {
225            vao.bind_vao();
226        } else {
227            unsafe {
228                gl::BindVertexArray(0);
229            }
230        }
231    }
232
233    //mp uniform_buffer_create
234    fn uniform_buffer_create<F: Sized>(
235        &mut self,
236        data: &[F],
237        is_dynamic: bool,
238    ) -> Result<UniformBuffer<Self>, ()> {
239        let byte_length = std::mem::size_of_val(data);
240        let mut gl = buffer::Buffer::default();
241        gl.uniform_buffer(data, is_dynamic)?;
242        Ok(UniformBuffer::new(gl, byte_length))
243    }
244
245    //mp uniform_buffer_update_data
246    fn uniform_buffer_update_data<F: std::fmt::Debug>(
247        &mut self,
248        uniform_buffer: &UniformBuffer<Self>,
249        data: &[F],
250        byte_offset: u32,
251    ) {
252        uniform_buffer
253            .gl_buffer()
254            .uniform_update_data(data, byte_offset);
255    }
256
257    //mp uniform_index_of_range
258    fn uniform_index_of_range(
259        &mut self,
260        uniform_buffer: &UniformBuffer<Self>,
261        gl_uindex: u32,
262        byte_offset: usize,
263        byte_length: usize,
264    ) {
265        let (byte_offset, byte_length) = uniform_buffer.offset_and_length(byte_offset, byte_length);
266        unsafe {
267            gl::BindBufferRange(
268                gl::UNIFORM_BUFFER,
269                gl_uindex,
270                uniform_buffer.gl_buffer().gl_buffer(),
271                byte_offset as isize,
272                byte_length as isize,
273            );
274        }
275    }
276}
277
278//ip mod3d_base::Renderable for Model3DOpenGL
279impl mod3d_base::Renderable for Model3DOpenGL {
280    type Buffer = buffer::Buffer;
281    type IndexAccessor = crate::BufferView<Self>;
282    type DataAccessor = crate::BufferView<Self>;
283    type Texture = texture::Texture;
284    type Material = crate::Material;
285    type Vertices = crate::Vertices<Self>;
286    type Descriptor = crate::Descriptor;
287
288    //mp init_buffer_desc_client
289    /// Initialize a buffer descriptor client - it will have been created using default()
290    fn init_buffer_desc_client(
291        &mut self,
292        _client: &mut Self::Descriptor,
293        _buffer_desc: &mod3d_base::BufferDescriptor<Self>,
294    ) {
295        todo!();
296    }
297
298    //mp init_buffer_data_client
299    /// Initialize a BufferData client
300    ///
301    /// This may be called multiple times for the same [BufferData]; if the
302    /// gl buffer is 0 then create, else it already exists with the same data
303    fn init_buffer_data_client(
304        &mut self,
305        client: &mut Self::Buffer,
306        buffer_data: &mod3d_base::BufferData<Self>,
307    ) {
308        if client.is_none() {
309            client.of_data(buffer_data)
310        }
311    }
312
313    //mp init_index_accessor_client
314    /// Initialize an accessor of indices
315    fn init_index_accessor_client(
316        &mut self,
317        client: &mut Self::IndexAccessor, // BufferView
318        buffer_view: &BufferIndexAccessor<Self>,
319    ) {
320        client.init_index_accessor_client(buffer_view, self);
321    }
322
323    //mp init_data_accessor_client
324    /// Initialize the client side of a BufferDataAccessor (for a particular vertex attr)
325    fn init_data_accessor_client(
326        &mut self,
327        client: &mut Self::DataAccessor, // BufferView
328        buffer_data_accessor: &BufferDataAccessor<Self>,
329    ) {
330        client.init_data_accessor_client(buffer_data_accessor, self);
331    }
332
333    //mp create_vertices_client
334    fn create_vertices_client(&mut self, vertices: &mod3d_base::Vertices<Self>) -> Self::Vertices {
335        Self::Vertices::create(vertices, self)
336    }
337
338    //mp create_texture_client
339    fn create_texture_client(&mut self, texture: &mod3d_base::Texture<Self>) -> Self::Texture {
340        eprintln!("Create texture client");
341        Self::Texture::of_texture(texture) // , self)
342    }
343
344    fn create_material_client<M>(
345        &mut self,
346        object: &mod3d_base::Object<M, Self>,
347        material: &M,
348    ) -> crate::Material
349    where
350        M: mod3d_base::Material,
351    {
352        eprintln!("Create material client");
353        crate::Material::create(self, object, material).unwrap()
354    }
355
356    //mp init_material_client
357    fn init_material_client<M: mod3d_base::Material>(
358        &mut self,
359        _client: &mut Self::Material,
360        _material: &M,
361    ) {
362    }
363
364    //zz All done
365}