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#[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!(
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 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 fn draw_primitive(&mut self, vaos: &[Vao], primitive: &mod3d_base::Primitive) {
190 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 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 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 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 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
281impl 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 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 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 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 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 fn create_vertices_client(&mut self, vertices: &mod3d_base::Vertices<Self>) -> Self::Vertices {
339 Self::Vertices::create(vertices, self)
340 }
341
342 fn create_texture_client(&mut self, texture: &mod3d_base::Texture<Self>) -> Self::Texture {
344 eprintln!("Create texture client");
345 Self::Texture::of_texture(texture) }
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 fn init_material_client<M: mod3d_base::Material>(
362 &mut self,
363 _client: &mut Self::Material,
364 _material: &M,
365 ) {
366 }
367
368 }