1use crate::core::*;
2use std::collections::HashMap;
3use std::sync::RwLock;
4
5pub struct Program {
12 context: Context,
13 id: crate::context::Program,
14 attributes: HashMap<String, u32>,
15 textures: RwLock<HashMap<String, u32>>,
16 uniforms: HashMap<String, crate::context::UniformLocation>,
17 uniform_blocks: RwLock<HashMap<String, (u32, u32)>>,
18}
19
20impl Program {
21 pub fn from_source(
25 context: &Context,
26 vertex_shader_source: &str,
27 fragment_shader_source: &str,
28 ) -> Result<Self, CoreError> {
29 unsafe {
30 let vert_shader = context
31 .create_shader(crate::context::VERTEX_SHADER)
32 .expect("Failed creating vertex shader");
33 let frag_shader = context
34 .create_shader(crate::context::FRAGMENT_SHADER)
35 .expect("Failed creating fragment shader");
36
37 let header: &str = if context.version().is_embedded {
38 "#version 300 es
39 #ifdef GL_FRAGMENT_PRECISION_HIGH
40 precision highp float;
41 precision highp int;
42 precision highp sampler2DArray;
43 precision highp sampler3D;
44 #else
45 precision mediump float;
46 precision mediump int;
47 precision mediump sampler2DArray;
48 precision mediump sampler3D;
49 #endif\n"
50 } else {
51 "#version 330 core\n"
52 };
53 let vertex_shader_source = format!("{}{}", header, vertex_shader_source);
54 let fragment_shader_source = format!("{}{}", header, fragment_shader_source);
55
56 context.shader_source(vert_shader, &vertex_shader_source);
57 context.shader_source(frag_shader, &fragment_shader_source);
58 context.compile_shader(vert_shader);
59 context.compile_shader(frag_shader);
60
61 let id = context.create_program().expect("Failed creating program");
62 context.attach_shader(id, vert_shader);
63 context.attach_shader(id, frag_shader);
64 context.link_program(id);
65
66 if !context.get_program_link_status(id) {
67 let log = context.get_shader_info_log(vert_shader);
68 if !log.is_empty() {
69 Err(shader_compilation_error(
70 "vertex",
71 log,
72 vertex_shader_source,
73 ))?;
74 }
75 let log = context.get_shader_info_log(frag_shader);
76 if !log.is_empty() {
77 Err(shader_compilation_error(
78 "fragment",
79 log,
80 fragment_shader_source,
81 ))?;
82 }
83 let log = context.get_program_info_log(id);
84 if !log.is_empty() {
85 Err(CoreError::ShaderLink(log))?;
86 }
87 Err(CoreError::ShaderCompilerError)?;
88 }
89
90 context.detach_shader(id, vert_shader);
91 context.detach_shader(id, frag_shader);
92 context.delete_shader(vert_shader);
93 context.delete_shader(frag_shader);
94
95 let num_attribs = context.get_active_attributes(id);
97 let mut attributes = HashMap::new();
98 for i in 0..num_attribs {
99 if let Some(crate::context::ActiveAttribute { name, .. }) = context
100 .get_active_attribute(id, i)
101 .filter(|a| !a.name.starts_with("gl_"))
102 {
103 if let Some(location) = context.get_attrib_location(id, &name) {
104 attributes.insert(name, location);
105 }
106 }
107 }
108
109 let num_uniforms = context.get_active_uniforms(id);
111 let mut uniforms = HashMap::new();
112 for i in 0..num_uniforms {
113 if let Some(crate::context::ActiveUniform { name, .. }) = context
114 .get_active_uniform(id, i)
115 .filter(|a| !a.name.starts_with("gl_"))
116 {
117 if let Some(location) = context.get_uniform_location(id, &name) {
118 let name = name.split('[').next().unwrap().to_string();
119 uniforms.insert(name, location);
120 }
121 }
122 }
123
124 Ok(Program {
125 context: context.clone(),
126 id,
127 attributes,
128 uniforms,
129 uniform_blocks: RwLock::new(HashMap::new()),
130 textures: RwLock::new(HashMap::new()),
131 })
132 }
133 }
134
135 pub fn use_uniform<T: UniformDataType>(&self, name: &str, data: T) {
145 let location = self.get_uniform_location(name);
146 T::send_uniform(&self.context, location, &[data]);
147 self.unuse_program();
148 }
149
150 pub fn use_uniform_if_required<T: UniformDataType>(&self, name: &str, data: T) {
154 if self.requires_uniform(name) {
155 self.use_uniform(name, data);
156 }
157 }
158
159 pub fn use_uniform_array<T: UniformDataType>(&self, name: &str, data: &[T]) {
169 let location = self.get_uniform_location(name);
170 T::send_uniform(&self.context, location, data);
171 self.unuse_program();
172 }
173
174 fn get_uniform_location(&self, name: &str) -> &crate::context::UniformLocation {
175 self.use_program();
176 self.uniforms.get(name).unwrap_or_else(|| {
177 panic!(
178 "the uniform {} is sent to the shader but not defined or never used",
179 name
180 )
181 })
182 }
183
184 pub fn use_texture(&self, name: &str, texture: &Texture2D) {
193 self.use_texture_internal(name);
194 texture.bind();
195 }
196
197 pub fn use_depth_texture(&self, name: &str, texture: &DepthTexture2D) {
206 self.use_texture_internal(name);
207 texture.bind();
208 }
209
210 pub fn use_texture_array(&self, name: &str, texture: &Texture2DArray) {
219 self.use_texture_internal(name);
220 texture.bind();
221 }
222
223 pub fn use_depth_texture_array(&self, name: &str, texture: &DepthTexture2DArray) {
232 self.use_texture_internal(name);
233 texture.bind();
234 }
235
236 pub fn use_texture_cube(&self, name: &str, texture: &TextureCubeMap) {
245 self.use_texture_internal(name);
246 texture.bind();
247 }
248
249 pub fn use_depth_texture_cube(&self, name: &str, texture: &DepthTextureCubeMap) {
258 self.use_texture_internal(name);
259 texture.bind();
260 }
261
262 pub fn use_texture_3d(&self, name: &str, texture: &Texture3D) {
271 self.use_texture_internal(name);
272 texture.bind();
273 }
274
275 pub fn use_raw_texture(&self, name: &str, target: u32, id: crate::context::Texture) {
280 self.use_texture_internal(name);
281 unsafe {
282 self.context.bind_texture(target, Some(id));
283 }
284 }
285
286 fn use_texture_internal(&self, name: &str) -> u32 {
287 if !self.textures.read().unwrap().contains_key(name) {
288 let mut map = self.textures.write().unwrap();
289 let index = map.len() as u32;
290 map.insert(name.to_owned(), index);
291 };
292 let index = *self.textures.read().unwrap().get(name).unwrap();
293 self.use_uniform(name, index as i32);
294 unsafe {
295 self.context
296 .active_texture(crate::context::TEXTURE0 + index);
297 }
298 index
299 }
300
301 pub fn use_uniform_block(&self, name: &str, buffer: &UniformBuffer) {
305 if !self.uniform_blocks.read().unwrap().contains_key(name) {
306 let mut map = self.uniform_blocks.write().unwrap();
307 let location = unsafe {
308 self.context
309 .get_uniform_block_index(self.id, name)
310 .unwrap_or_else(|| panic!("the uniform block {} is sent to the shader but not defined or never used",
311 name))
312 };
313 let index = map.len() as u32;
314 map.insert(name.to_owned(), (location, index));
315 };
316 let (location, index) = *self.uniform_blocks.read().unwrap().get(name).unwrap();
317 unsafe {
318 self.context.uniform_block_binding(self.id, location, index);
319 buffer.bind(index);
320 self.context
321 .bind_buffer(crate::context::UNIFORM_BUFFER, None);
322 }
323 }
324
325 pub fn use_vertex_attribute<T: BufferDataType>(&self, name: &str, buffer: &VertexBuffer<T>) {
335 if buffer.count() > 0 {
336 buffer.bind();
337 let loc = self.location(name);
338 unsafe {
339 self.context.bind_vertex_array(Some(self.context.vao));
340 self.context.enable_vertex_attrib_array(loc);
341 if !T::normalized()
342 && (T::data_type() == crate::context::UNSIGNED_BYTE
343 || T::data_type() == crate::context::BYTE
344 || T::data_type() == crate::context::UNSIGNED_SHORT
345 || T::data_type() == crate::context::SHORT
346 || T::data_type() == crate::context::UNSIGNED_INT
347 || T::data_type() == crate::context::INT)
348 {
349 self.context.vertex_attrib_pointer_i32(
350 loc,
351 T::size() as i32,
352 T::data_type(),
353 0,
354 0,
355 );
356 } else {
357 self.context.vertex_attrib_pointer_f32(
358 loc,
359 T::size() as i32,
360 T::data_type(),
361 T::normalized(),
362 0,
363 0,
364 );
365 }
366 self.context.vertex_attrib_divisor(loc, 0);
367 self.context.bind_buffer(crate::context::ARRAY_BUFFER, None);
368 }
369 self.unuse_program();
370 }
371 }
372
373 pub fn use_instance_attribute<T: BufferDataType>(
383 &self,
384 name: &str,
385 buffer: &InstanceBuffer<T>,
386 ) {
387 if buffer.count() > 0 {
388 buffer.bind();
389 let loc = self.location(name);
390 unsafe {
391 self.context.bind_vertex_array(Some(self.context.vao));
392 self.context.enable_vertex_attrib_array(loc);
393 if !T::normalized()
394 && (T::data_type() == crate::context::UNSIGNED_BYTE
395 || T::data_type() == crate::context::BYTE
396 || T::data_type() == crate::context::UNSIGNED_SHORT
397 || T::data_type() == crate::context::SHORT
398 || T::data_type() == crate::context::UNSIGNED_INT
399 || T::data_type() == crate::context::INT)
400 {
401 self.context.vertex_attrib_pointer_i32(
402 loc,
403 T::size() as i32,
404 T::data_type(),
405 0,
406 0,
407 );
408 } else {
409 self.context.vertex_attrib_pointer_f32(
410 loc,
411 T::size() as i32,
412 T::data_type(),
413 T::normalized(),
414 0,
415 0,
416 );
417 }
418 self.context.vertex_attrib_divisor(loc, 1);
419 self.context.bind_buffer(crate::context::ARRAY_BUFFER, None);
420 }
421 self.unuse_program();
422 }
423 }
424
425 pub fn draw_arrays(&self, render_states: RenderStates, viewport: Viewport, count: u32) {
432 self.context.set_viewport(viewport);
433 self.context.set_render_states(render_states);
434 self.use_program();
435 unsafe {
436 self.context
437 .draw_arrays(crate::context::TRIANGLES, 0, count as i32);
438 for location in self.attributes.values() {
439 self.context.disable_vertex_attrib_array(*location);
440 }
441 self.context.bind_vertex_array(None);
442 }
443 self.unuse_program();
444
445 #[cfg(debug_assertions)]
446 self.context
447 .error_check()
448 .expect("Unexpected rendering error occured")
449 }
450
451 pub fn draw_arrays_instanced(
456 &self,
457 render_states: RenderStates,
458 viewport: Viewport,
459 count: u32,
460 instance_count: u32,
461 ) {
462 self.context.set_viewport(viewport);
463 self.context.set_render_states(render_states);
464 self.use_program();
465 unsafe {
466 self.context.draw_arrays_instanced(
467 crate::context::TRIANGLES,
468 0,
469 count as i32,
470 instance_count as i32,
471 );
472 self.context
473 .bind_buffer(crate::context::ELEMENT_ARRAY_BUFFER, None);
474 for location in self.attributes.values() {
475 self.context.disable_vertex_attrib_array(*location);
476 }
477 self.context.bind_vertex_array(None);
478 }
479 self.unuse_program();
480
481 #[cfg(debug_assertions)]
482 self.context
483 .error_check()
484 .expect("Unexpected rendering error occured")
485 }
486
487 pub fn draw_elements<T: ElementBufferDataType>(
493 &self,
494 render_states: RenderStates,
495 viewport: Viewport,
496 element_buffer: &ElementBuffer<T>,
497 ) {
498 self.draw_subset_of_elements(
499 render_states,
500 viewport,
501 element_buffer,
502 0,
503 element_buffer.count() as u32,
504 )
505 }
506
507 pub fn draw_subset_of_elements<T: ElementBufferDataType>(
513 &self,
514 render_states: RenderStates,
515 viewport: Viewport,
516 element_buffer: &ElementBuffer<T>,
517 first: u32,
518 count: u32,
519 ) {
520 self.context.set_viewport(viewport);
521 self.context.set_render_states(render_states);
522 self.use_program();
523 element_buffer.bind();
524 unsafe {
525 self.context.draw_elements(
526 crate::context::TRIANGLES,
527 count as i32,
528 T::data_type(),
529 first as i32,
530 );
531 self.context
532 .bind_buffer(crate::context::ELEMENT_ARRAY_BUFFER, None);
533
534 for location in self.attributes.values() {
535 self.context.disable_vertex_attrib_array(*location);
536 }
537 self.context.bind_vertex_array(None);
538 }
539 self.unuse_program();
540
541 #[cfg(debug_assertions)]
542 self.context
543 .error_check()
544 .expect("Unexpected rendering error occured")
545 }
546
547 pub fn draw_elements_instanced<T: ElementBufferDataType>(
552 &self,
553 render_states: RenderStates,
554 viewport: Viewport,
555 element_buffer: &ElementBuffer<T>,
556 instance_count: u32,
557 ) {
558 self.draw_subset_of_elements_instanced(
559 render_states,
560 viewport,
561 element_buffer,
562 0,
563 element_buffer.count() as u32,
564 instance_count,
565 )
566 }
567
568 pub fn draw_subset_of_elements_instanced<T: ElementBufferDataType>(
573 &self,
574 render_states: RenderStates,
575 viewport: Viewport,
576 element_buffer: &ElementBuffer<T>,
577 first: u32,
578 count: u32,
579 instance_count: u32,
580 ) {
581 self.context.set_viewport(viewport);
582 self.context.set_render_states(render_states);
583 self.use_program();
584 element_buffer.bind();
585 unsafe {
586 self.context.draw_elements_instanced(
587 crate::context::TRIANGLES,
588 count as i32,
589 T::data_type(),
590 first as i32,
591 instance_count as i32,
592 );
593 self.context
594 .bind_buffer(crate::context::ELEMENT_ARRAY_BUFFER, None);
595 for location in self.attributes.values() {
596 self.context.disable_vertex_attrib_array(*location);
597 }
598 self.context.bind_vertex_array(None);
599 }
600 self.unuse_program();
601
602 #[cfg(debug_assertions)]
603 self.context
604 .error_check()
605 .expect("Unexpected rendering error occured")
606 }
607
608 pub fn requires_uniform(&self, name: &str) -> bool {
612 self.uniforms.contains_key(name)
613 }
614
615 pub fn requires_attribute(&self, name: &str) -> bool {
619 self.attributes.contains_key(name)
620 }
621
622 fn location(&self, name: &str) -> u32 {
623 self.use_program();
624 *self.attributes.get(name).unwrap_or_else(|| {
625 panic!(
626 "the attribute {} is sent to the shader but not defined or never used",
627 name
628 )
629 })
630 }
631
632 fn use_program(&self) {
633 unsafe {
634 self.context.use_program(Some(self.id));
635 }
636 }
637
638 fn unuse_program(&self) {
639 unsafe {
640 self.context.use_program(None);
641 }
642 }
643}
644
645impl Drop for Program {
646 fn drop(&mut self) {
647 unsafe {
648 self.context.delete_program(self.id);
649 }
650 }
651}
652fn shader_compilation_error(typ: &str, log: String, source: String) -> CoreError {
653 let lines: Vec<String> = source
654 .lines()
655 .enumerate()
656 .map(|(index, l)| format!("{:0>3}: {}", index + 1, l))
657 .collect();
658 CoreError::ShaderCompilation(typ.to_string(), lines.join("\n"), log)
659}