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#[derive(Debug)]
22pub struct Model3DOpenGL {}
23
24impl Default for Model3DOpenGL {
26 fn default() -> Self {
27 Self::new()
28 }
29}
30
31impl Model3DOpenGL {
33 pub fn new() -> Self {
34 Self {}
35 }
36
37 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
68impl Gl for Model3DOpenGL {
70 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 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 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 fn vao_create_from_indices(&mut self, indices: &crate::IndexBuffer<Self>) -> Result<Vao, ()> {
112 Vao::create_from_indices(self, indices)
113 }
114
115 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 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 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 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 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 fn draw_primitive(&mut self, vaos: &[Vao], primitive: &mod3d_base::Primitive) {
187 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 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 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 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 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
278impl 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 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 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 fn init_index_accessor_client(
316 &mut self,
317 client: &mut Self::IndexAccessor, buffer_view: &BufferIndexAccessor<Self>,
319 ) {
320 client.init_index_accessor_client(buffer_view, self);
321 }
322
323 fn init_data_accessor_client(
326 &mut self,
327 client: &mut Self::DataAccessor, buffer_data_accessor: &BufferDataAccessor<Self>,
329 ) {
330 client.init_data_accessor_client(buffer_data_accessor, self);
331 }
332
333 fn create_vertices_client(&mut self, vertices: &mod3d_base::Vertices<Self>) -> Self::Vertices {
335 Self::Vertices::create(vertices, self)
336 }
337
338 fn create_texture_client(&mut self, texture: &mod3d_base::Texture<Self>) -> Self::Texture {
340 eprintln!("Create texture client");
341 Self::Texture::of_texture(texture) }
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 fn init_material_client<M: mod3d_base::Material>(
358 &mut self,
359 _client: &mut Self::Material,
360 _material: &M,
361 ) {
362 }
363
364 }