globject_rs/
pipeline.rs

1
2use crate::prelude::*;
3use std::{
4	any::Any,
5	collections::BTreeMap,
6	ffi::c_void,
7	fmt::{self, Debug, Formatter},
8	marker::PhantomData,
9	mem::{size_of, align_of},
10	ptr::null,
11	rc::Rc,
12};
13
14/// The trait that the struct of vertices or instances must implement
15pub trait VertexType: Copy + Clone + Sized + Default + Debug + Iterable {}
16impl<T> VertexType for T where T: Copy + Clone + Sized + Default + Debug + Iterable {}
17
18/// Use this macro to convert your struct into `VertexType`
19#[macro_export]
20macro_rules! derive_vertex_type {
21	($item: item) => {
22		#[derive(Iterable, Default, Debug, Clone, Copy)]
23		$item
24	};
25}
26
27/// The pipeline is used to draw a mesh with a shader to a framebuffer.
28pub struct Pipeline<V: VertexType, I: VertexType> {
29	pub glcore: Rc<GLCore>,
30	name: u32,
31	pub mesh: Rc<dyn GenericMeshWithMaterial>,
32	pub shader: Rc<Shader>,
33	vertex_stride: usize,
34	instance_stride: usize,
35	_phantom_vertex_type: PhantomData<V>,
36	_phantom_instance_type: PhantomData<I>,
37}
38
39/// The data type described in the OpenGL way.
40#[derive(Debug, Clone, Copy)]
41struct DataGlType {
42	data_type: u32,
43	size: u32,
44	rows: u32,
45}
46
47/// The binding state of the pipeline
48#[derive(Debug)]
49pub struct PipelineBind<'a, V: VertexType, I: VertexType> {
50	pub pipeline: &'a Pipeline<V, I>,
51}
52
53impl DataGlType {
54	/// Does this data type use integers as the basic component type
55	fn is_integer(&self) -> bool {
56		matches!(self.data_type, GL_BYTE | GL_SHORT | GL_INT | GL_UNSIGNED_BYTE | GL_UNSIGNED_SHORT | GL_UNSIGNED_INT)
57	}
58
59	/// Does this data type use `double` as the basic component type
60	fn is_double(&self) -> bool {
61		matches!(self.data_type, GL_DOUBLE)
62	}
63
64	/// The size in bytes of this data type
65	fn size_in_bytes(&self) -> usize {
66		match self.data_type {
67			GL_BYTE | GL_UNSIGNED_BYTE => (self.size as usize) * self.rows as usize,
68			GL_SHORT | GL_UNSIGNED_SHORT | GL_HALF_FLOAT => 2usize * self.size as usize * self.rows as usize,
69			GL_INT | GL_UNSIGNED_INT | GL_FLOAT => 4usize * self.size as usize * self.rows as usize,
70			GL_DOUBLE => 8usize * self.size as usize * self.rows as usize,
71			other => panic!("Invalid `data_type` ({other})"),
72		}
73	}
74}
75
76impl<V: VertexType, I: VertexType> Pipeline<V, I> {
77	/// Get the internal name
78	pub fn get_name(&self) -> u32 {
79		self.name
80	}
81
82	/// Create a new pipeline
83	pub fn new(glcore: Rc<GLCore>, mesh: Rc<dyn GenericMeshWithMaterial>, shader: Rc<Shader>) -> Self {
84		let mut name: u32 = 0;
85		glcore.glGenVertexArrays(1, &mut name as *mut u32);
86		let mut ret = Self {
87			glcore,
88			name,
89			mesh,
90			shader,
91			vertex_stride: size_of::<V>(),
92			instance_stride: size_of::<I>(),
93			_phantom_vertex_type: PhantomData,
94			_phantom_instance_type: PhantomData,
95		};
96		ret.establish_pipeline();
97		ret
98	}
99
100	/// Establish the pipeline by describing the vertex/instance data and the shader attrib inputs to the VAO.
101	fn establish_pipeline(&mut self) {
102		let program = self.shader.use_program();
103		let active_attribs = self.shader.get_active_attribs().unwrap();
104		let bind = self.bind();
105
106		let vb_bind = self.mesh.get_vertex_buffer().bind();
107		self.describe::<V>(&active_attribs, 0);
108		vb_bind.unbind();
109
110		if let Some(ib) = self.mesh.get_instance_buffer() {
111			let ib_bind = ib.bind();
112			self.describe::<I>(&active_attribs, 1);
113			ib_bind.unbind();
114		}
115
116		bind.unbind();
117		program.unuse();
118	}
119
120	/// Describe a `VertexType` to a VAO
121	fn describe<T: VertexType>(&self, active_attribs: &BTreeMap<String, ShaderInputVarType>, v_a_d: u32) {
122		let instance = T::default();
123		let stride = size_of::<T>();
124		let alignment = align_of::<T>();
125		let mut cur_offset: usize = 0;
126		for (field_name, field_value) in instance.iter() {
127			let typename = Self::get_typename_of_vertex_struct_member(field_value);
128			let datainfo = Self::get_vertex_struct_member_gltype(typename);
129			if let Some(attrib_type) = active_attribs.get(field_name) {
130				let (p_size, p_rows) = attrib_type.get_size_and_rows();
131				if p_size != datainfo.size || p_rows != datainfo.rows {
132					panic!("The size and rows of the shader attrib is {p_size}x{p_rows}, but the given member of the vertex struct is {}x{}", datainfo.size, datainfo.rows);
133				}
134				let location = self.shader.get_attrib_location(field_name);
135				if location >= 0 {
136					let location = location as u32;
137					for row in 0..datainfo.rows {
138						let location = location + row;
139						let do_normalize = if field_name.contains("normalized") && field_name.contains("_") {
140							1
141						} else {
142							0
143						};
144						let ptr_param = cur_offset as *const c_void;
145						self.glcore.glEnableVertexAttribArray(location);
146						if attrib_type.is_float()	{self.glcore.glVertexAttribPointer (location, p_size as i32, attrib_type.get_base_type() as u32, do_normalize, stride as i32, ptr_param)} else
147						if attrib_type.is_integer()	{self.glcore.glVertexAttribIPointer(location, p_size as i32, attrib_type.get_base_type() as u32, stride as i32, ptr_param)} else
148						if attrib_type.is_double()	{self.glcore.glVertexAttribLPointer(location, p_size as i32, attrib_type.get_base_type() as u32, stride as i32, ptr_param)} else
149						{panic!("Unknown data type of the attrib `{} {field_name}`", attrib_type.get_type())}
150						self.glcore.glVertexAttribDivisor(location, v_a_d);
151					}
152				} else {
153					eprintln!("Attrib `{typename} {field_name}` is active, but can't get its location.");
154				}
155			} else {
156				eprintln!("Attrib `{typename} {field_name}` is not active.");
157			}
158			cur_offset += datainfo.size_in_bytes();
159			cur_offset = ((cur_offset - 1) / alignment + 1) * alignment;
160		}
161	}
162
163	/// Bind the pipeline for drawing
164	pub fn bind<'a>(&'a self) -> PipelineBind<'a, V, I> {
165		PipelineBind::new(self)
166	}
167
168	/// Parse the type name of the `VertexType` struct members, and return a `DataGlType`.
169	fn get_vertex_struct_member_gltype(member_type: &str) -> DataGlType {
170		match member_type {
171			"i8" => DataGlType{data_type: GL_BYTE, size: 1, rows: 1},
172			"i16" => DataGlType{data_type: GL_SHORT, size: 1, rows: 1},
173			"i32" => DataGlType{data_type: GL_INT, size: 1, rows: 1},
174			"u8" => DataGlType{data_type: GL_UNSIGNED_BYTE, size: 1, rows: 1},
175			"u16" => DataGlType{data_type: GL_UNSIGNED_SHORT, size: 1, rows: 1},
176			"u32" => DataGlType{data_type: GL_UNSIGNED_INT, size: 1, rows: 1},
177			"f16" => DataGlType{data_type: GL_HALF_FLOAT, size: 1, rows: 1},
178			"f32" => DataGlType{data_type: GL_FLOAT, size: 1, rows: 1},
179			"f64" => DataGlType{data_type: GL_DOUBLE, size: 1, rows: 1},
180			_ => {
181				if member_type.contains("vec") {
182					let data_type =
183					     if member_type.starts_with("u32") {GL_UNSIGNED_INT}
184					else if member_type.starts_with("u16") {GL_UNSIGNED_SHORT}
185					else if member_type.starts_with("u8")  {GL_UNSIGNED_BYTE}
186					else if member_type.starts_with("i32") {GL_INT}
187					else if member_type.starts_with("i16") {GL_SHORT}
188					else if member_type.starts_with("i8")  {GL_BYTE}
189					else {
190						match member_type.chars().next().unwrap() {
191							'v' => GL_FLOAT,
192							'd' => GL_DOUBLE,
193							'b' => GL_BYTE,
194							'i' => GL_INT,
195							'u' => GL_UNSIGNED_INT,
196							_ => panic!("Unsupported type of member: `{member_type}`"),
197						}
198					};
199					let size = u32::from(member_type.chars().last().unwrap()) - u32::from('0');
200					DataGlType{data_type, size, rows: 1}
201				} else if member_type.contains("mat") {
202					let data_type = if member_type.starts_with("d") {
203						GL_DOUBLE
204					} else {
205						GL_FLOAT
206					};
207					let (size, rows) =
208					     if member_type.ends_with("2x2") {(2, 2)}
209					else if member_type.ends_with("2x3") {(2, 3)}
210					else if member_type.ends_with("2x4") {(2, 4)}
211					else if member_type.ends_with("3x2") {(3, 2)}
212					else if member_type.ends_with("3x3") {(3, 3)}
213					else if member_type.ends_with("3x4") {(3, 4)}
214					else if member_type.ends_with("4x2") {(4, 2)}
215					else if member_type.ends_with("4x3") {(4, 3)}
216					else if member_type.ends_with("4x4") {(4, 4)}
217					else {
218						match member_type.chars().last().unwrap() {
219							'2' => (2, 2),
220							'3' => (3, 3),
221							'4' => (4, 4),
222							_ => panic!("Unsupported type of member: `{member_type}`"),
223						}
224					};
225					DataGlType{data_type, size, rows}
226				} else if member_type.contains("quat") {
227					let data_type = if member_type.starts_with("d") {
228						GL_DOUBLE
229					} else {
230						GL_FLOAT
231					};
232					DataGlType{data_type, size: 4, rows: 1}
233				} else {
234					panic!("Unsupported type of member: `{member_type}`")
235				}
236			}
237		}
238	}
239
240	/// Get the exact type of the struct member by the member instance
241	pub fn get_typename_of_vertex_struct_member(data: &dyn Any) -> &str {
242		     if data.is::<u8>() {"u8"}
243		else if data.is::<u16>() {"u16"}
244		else if data.is::<u32>() {"u32"}
245		else if data.is::<i8>() {"i8"}
246		else if data.is::<i16>() {"i16"}
247		else if data.is::<i32>() {"i32"}
248		else if data.is::<f16>() {"f16"}
249		else if data.is::<f32>() {"f32"}
250		else if data.is::<f64>() {"f64"}
251		else if data.is::<Vec1>() {"vec1"}
252		else if data.is::<Vec2>() {"vec2"}
253		else if data.is::<Vec3>() {"vec3"}
254		else if data.is::<Vec4>() {"vec4"}
255		else if data.is::<DVec1>() {"dvec1"}
256		else if data.is::<DVec2>() {"dvec2"}
257		else if data.is::<DVec3>() {"dvec3"}
258		else if data.is::<DVec4>() {"dvec4"}
259		else if data.is::<BVec1>() {"bvec1"}
260		else if data.is::<BVec2>() {"bvec2"}
261		else if data.is::<BVec3>() {"bvec3"}
262		else if data.is::<BVec4>() {"bvec4"}
263		else if data.is::<IVec1>() {"ivec1"}
264		else if data.is::<IVec2>() {"ivec2"}
265		else if data.is::<IVec3>() {"ivec3"}
266		else if data.is::<IVec4>() {"ivec4"}
267		else if data.is::<I8Vec1>() {"i8vec1"}
268		else if data.is::<I8Vec2>() {"i8vec2"}
269		else if data.is::<I8Vec3>() {"i8vec3"}
270		else if data.is::<I8Vec4>() {"i8vec4"}
271		else if data.is::<I16Vec1>() {"i16vec1"}
272		else if data.is::<I16Vec2>() {"i16vec2"}
273		else if data.is::<I16Vec3>() {"i16vec3"}
274		else if data.is::<I16Vec4>() {"i16vec4"}
275		else if data.is::<I32Vec1>() {"i32vec1"}
276		else if data.is::<I32Vec2>() {"i32vec2"}
277		else if data.is::<I32Vec3>() {"i32vec3"}
278		else if data.is::<I32Vec4>() {"i32vec4"}
279		else if data.is::<UVec1>() {"uvec1"}
280		else if data.is::<UVec2>() {"uvec2"}
281		else if data.is::<UVec3>() {"uvec3"}
282		else if data.is::<UVec4>() {"uvec4"}
283		else if data.is::<U8Vec1>() {"u8vec1"}
284		else if data.is::<U8Vec2>() {"u8vec2"}
285		else if data.is::<U8Vec3>() {"u8vec3"}
286		else if data.is::<U8Vec4>() {"u8vec4"}
287		else if data.is::<U16Vec1>() {"u16vec1"}
288		else if data.is::<U16Vec2>() {"u16vec2"}
289		else if data.is::<U16Vec3>() {"u16vec3"}
290		else if data.is::<U16Vec4>() {"u16vec4"}
291		else if data.is::<U32Vec1>() {"u32vec1"}
292		else if data.is::<U32Vec2>() {"u32vec2"}
293		else if data.is::<U32Vec3>() {"u32vec3"}
294		else if data.is::<U32Vec4>() {"u32vec4"}
295		else if data.is::<Quat>() {"quat"}
296		else if data.is::<DQuat>() {"dquat"}
297		else if data.is::<Mat2>() {"mat2"}
298		else if data.is::<Mat3>() {"mat3"}
299		else if data.is::<Mat4>() {"mat4"}
300		else if data.is::<Mat2x2>() {"mat2x2"}
301		else if data.is::<Mat2x3>() {"mat2x3"}
302		else if data.is::<Mat2x4>() {"mat2x4"}
303		else if data.is::<Mat3x2>() {"mat3x2"}
304		else if data.is::<Mat3x3>() {"mat3x3"}
305		else if data.is::<Mat3x4>() {"mat3x4"}
306		else if data.is::<Mat4x2>() {"mat4x2"}
307		else if data.is::<Mat4x3>() {"mat4x3"}
308		else if data.is::<Mat4x4>() {"mat4x4"}
309		else if data.is::<DMat2>() {"dmat2"}
310		else if data.is::<DMat3>() {"dmat3"}
311		else if data.is::<DMat4>() {"dmat4"}
312		else if data.is::<DMat2x2>() {"dmat2x2"}
313		else if data.is::<DMat2x3>() {"dmat2x3"}
314		else if data.is::<DMat2x4>() {"dmat2x4"}
315		else if data.is::<DMat3x2>() {"dmat3x2"}
316		else if data.is::<DMat3x3>() {"dmat3x3"}
317		else if data.is::<DMat3x4>() {"dmat3x4"}
318		else if data.is::<DMat4x2>() {"dmat4x2"}
319		else if data.is::<DMat4x3>() {"dmat4x3"}
320		else if data.is::<DMat4x4>() {"dmat4x4"}
321		else {panic!("Unsupported type of value: {data:?}")}
322	}
323}
324
325impl<'a, V: VertexType, I: VertexType> PipelineBind<'a, V, I> {
326	/// Create a binding state of the pipeline
327	fn new(pipeline: &'a Pipeline<V, I>) -> Self {
328		pipeline.glcore.glBindVertexArray(pipeline.name);
329		Self {
330			pipeline,
331		}
332	}
333
334	/// Run the pipeline for drawing
335	pub fn draw(&self, fbo: Option<&Framebuffer>) {
336		let glcore = &self.pipeline.glcore;
337		let program = self.pipeline.shader.use_program();
338		let fbo_bind = fbo.map_or_else(
339		|| {
340			Framebuffer::default_bind(glcore);
341			None
342		},
343		|fbo| {
344			let bind = fbo.bind();
345			bind.setup(&self.pipeline.shader);
346			Some(bind)
347		});
348
349		if let Some(material) = self.pipeline.mesh.get_material() {
350			program.setup_material_uniforms(material, Some("i"), true);
351		} else {
352			let default_material = MaterialLegacy::default();
353			program.setup_material_uniforms(&default_material, Some("i"), true);
354		}
355
356		let mesh = &self.pipeline.mesh;
357		let element_buffer = mesh.get_element_buffer();
358		let e_bind = mesh.bind_element_buffer();
359
360		if let Some(command_buffer) = mesh.get_command_buffer() {
361			assert_eq!(command_buffer.get_target(), BufferTarget::DrawIndirectBuffer);
362			let c_bind = command_buffer.bind();
363			let num_commands = mesh.get_command_count();
364			if let Some(_) = element_buffer {
365				glcore.glMultiDrawElementsIndirect(mesh.get_primitive() as u32, mesh.get_element_type() as u32, null(), num_commands as i32, size_of::<DrawElementsCommand>() as i32);
366			} else {
367				glcore.glMultiDrawArraysIndirect(mesh.get_primitive() as u32, null(), num_commands as i32, size_of::<DrawArrayCommand>() as i32);
368			}
369			c_bind.unbind();
370		} else {
371			let num_vertices = mesh.get_vertex_count();
372			if let Some(_) = mesh.get_instance_buffer() {
373				let num_instances = mesh.get_instance_count();
374				if let Some(_) = element_buffer {
375					glcore.glDrawElementsInstanced(mesh.get_primitive() as u32, mesh.get_element_count() as i32, mesh.get_element_type() as u32, null(), num_instances as i32);
376				} else {
377					glcore.glDrawArraysInstanced(mesh.get_primitive() as u32, 0, num_vertices as i32, num_instances as i32);
378				}
379			} else if let Some(_) = element_buffer {
380				glcore.glDrawElements(mesh.get_primitive() as u32, mesh.get_element_count() as i32, mesh.get_element_type() as u32, null());
381			} else {
382				glcore.glDrawArrays(mesh.get_primitive() as u32, 0, num_vertices as i32);
383			}
384		}
385
386		if let Some(b) = e_bind { b.unbind() }
387		program.unuse();
388		if let Some(b) = fbo_bind { b.unbind() }
389	}
390
391	/// Explicitly unbind the VAO pipeline
392	pub fn unbind(self) {}
393}
394
395impl<'a, V: VertexType, I: VertexType> Drop for PipelineBind<'a, V, I> {
396	fn drop(&mut self) {
397		self.pipeline.glcore.glBindVertexArray(0);
398	}
399}
400
401impl<V: VertexType, I: VertexType> Drop for Pipeline<V, I> {
402	fn drop(&mut self) {
403		self.glcore.glDeleteVertexArrays(1, &self.name as *const u32);
404	}
405}
406
407impl<V: VertexType, I: VertexType> Debug for Pipeline<V, I> {
408	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
409		f.debug_struct("Pipeline")
410		.field("name", &self.name)
411		.field("mesh", &self.mesh)
412		.field("shader", &self.shader)
413		.field("vertex_stride", &self.vertex_stride)
414		.field("instance_stride", &self.instance_stride)
415		.finish()
416	}
417}
418
419derive_vertex_type! {
420	/// The unused type for you if you don't want to use the instanced mesh
421	pub struct UnusedType {}
422}