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