├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── error.rs ├── gl33 ├── buffer.rs ├── framebuffer.rs ├── mod.rs ├── pipeline.rs ├── shader │ ├── mod.rs │ ├── program.rs │ ├── stage.rs │ └── uniform.rs ├── tess.rs ├── tessellation.rs ├── texture.rs └── token.rs ├── lib.rs └── pixel.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | - stable 5 | - beta 6 | - nightly 7 | 8 | os: 9 | - linux 10 | - osx 11 | 12 | matrix: 13 | allow_failures: 14 | - rust: nightly 15 | - os: osx 16 | 17 | script: 18 | - rustc --version 19 | - cargo --version 20 | - cargo build --verbose 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.13.1 2 | 3 | - **Deprecated.** 4 | 5 | # 0.13 6 | 7 | - Vertices (`Vertex`) are now aligned based on what decides the Rust compiler. This is very 8 | important, especially because of the version 0.15.0 adding non-32-bit vertex components: alignment 9 | and padding is now completely handled for you and you have nothing to care about. 10 | - Changed the meaning of the semantic maps (uniforms). It is now required to provide a `Uniform` to 11 | build a new `Sem`. This is an improvement in the sense that the *unsafe* zone is restricted to the 12 | declaration of uniforms for a given program. This *unsafe* zone will be covered in a next release 13 | by a macro to make it safe. 14 | 15 | # 0.12 16 | 17 | - Support for luminance-0.15.0 (yeah, lazy changelog line, sorry :D). 18 | 19 | # 0.11 20 | 21 | - `UniformWarning::TypeMismatch` now includes the name of the uniform which type mismatches with the 22 | requested on. 23 | 24 | # 0.10 25 | 26 | - Changed the pipeline workflow by introducing `Pipe` objects. 27 | - Removed strong typing in shader programs (`Program` is now `Program`). 28 | - Removed strong typing in shader stages (`Stage` is now `Stage`). 29 | 30 | ## 0.9.1 31 | 32 | - Fixed segfault when a Tessellation with no bound buffer gets dropped. 33 | 34 | # 0.9 35 | 36 | - Added attribute-less tessellations. 37 | - Enhanced shader-related documentation. 38 | - Removed `Slot`. 39 | 40 | # 0.8 41 | 42 | - Support of texture / uniform buffer sets. 43 | 44 | ## 0.7.1 45 | 46 | # 0.7 47 | 48 | - Textures support in shaders. 49 | 50 | ## 0.6.2 51 | 52 | - Replaced some internal references to `Vec` by slices. 53 | 54 | ## 0.6.1 55 | 56 | - Fixed memory corruption in new_shader / new_program. 57 | 58 | # 0.6 59 | 60 | - Uniform warnings. 61 | 62 | ## 0.5.6 63 | 64 | - Fixed runtime reification of uniforms. 65 | 66 | ## 0.5.5 67 | 68 | - Support for runtime reification of uniforms. 69 | 70 | ## 0.5.4 71 | 72 | - Added support for getting textures’ texels. 73 | 74 | ## 0.5.3 75 | 76 | - Support for raw texture uploads. 77 | 78 | ## 0.5.2 79 | 80 | - Added documentation link. 81 | 82 | ## 0.5.1 83 | 84 | - Fixed vertex input offsets. That issue makes all prior versions fail when trying to handle 85 | multi-attributes vertices. You are very advised to upgrade to this version then. 86 | 87 | # 0.5 88 | 89 | - Fixed viewport issue. 90 | - Removed the need of **core**. 91 | - Removed `UniformName`. 92 | - Fixed the `update_textures` function regarding **luminance**. 93 | - Using `AsRef` for `update_textures`. 94 | - Adapted mipmaps as `usize`. 95 | - Panic if unknown pixel format. 96 | 97 | ## 0.4.3 98 | 99 | - Implemented `Uniform` for `Texture`. 100 | 101 | ## 0.4.2 102 | 103 | - Fixed `HasFramebuffer::free_framebuffer`. 104 | 105 | ## 0.4.1 106 | 107 | - Crate fixed because of *0.4.0* being broken then yanked. 108 | 109 | # 0.4 110 | 111 | - Implemented existential quantification for `Pipeline`. 112 | - Added travis CI support. 113 | 114 | ## 0.3.2 115 | 116 | - Added `ProgramProxy` in the export list of lib.rs. 117 | 118 | ## 0.3.1 119 | 120 | - Added `ProgramProxy` alias. 121 | 122 | # 0.3 123 | 124 | - `Program` now has its *uniform interface* tagged in the type. 125 | - Added support for `luminance-0.4.0`. 126 | 127 | ## 0.2.1 128 | 129 | - Removed `W` use from `Buffer` as it was removed in `luminance-0.3.0`. 130 | 131 | # 0.2 132 | 133 | - Added support for `luminance-0.2.0`. 134 | 135 | # 0.1 136 | 137 | - Initial revision. 138 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "luminance-gl" 3 | version = "0.13.1" 4 | license = "BSD-3-Clause" 5 | authors = ["Dimitri 'phaazon' Sabadie "] 6 | description = "Deprecated, please use luminance instead" 7 | keywords = ["stateless", "type-safe", "graphics", "luminance", "opengl"] 8 | 9 | homepage = "https://github.com/phaazon/luminance-rs" 10 | repository = "https://github.com/phaazon/luminance-rs" 11 | documentation = "https://docs.rs/luminance-gl" 12 | 13 | [badges] 14 | maintenance = { status = "deprecated" } 15 | 16 | [features] 17 | default = ["gl33"] 18 | gl33 = [] 19 | 20 | [dependencies] 21 | gl = "0.5.2" 22 | luminance = "0.16" 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Dimitri Sabadie 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Dimitri Sabadie nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This project is deprecated 2 | 3 | This crate is now deprecated. If you were using it and would like to update, please visit the page 4 | of [luminance]. 5 | 6 | > Why did this crate get deprecated? 7 | 8 | Mostly because [luminance] is now a standalone project (no backend involved). It enables the library 9 | to be more concise by narrowing its scope and provide a well-defined interface instead of a blurred 10 | set of mixins. 11 | 12 | [luminance]: https://crates.io/crates/luminance 13 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | 3 | pub fn debug_gl() { 4 | let e = unsafe { gl::GetError() }; 5 | 6 | match e { 7 | gl::NO_ERROR => println!("no error"), 8 | gl::INVALID_ENUM => println!("invalid enum"), 9 | gl::INVALID_VALUE => println!("invalid value"), 10 | gl::INVALID_OPERATION => println!("invalid operation"), 11 | gl::INVALID_FRAMEBUFFER_OPERATION => println!("invalid frameuffer operation"), 12 | gl::OUT_OF_MEMORY => println!("out of memory"), 13 | _ => println!("unknown error: {}", e) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/gl33/buffer.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use gl33::token::GL33; 4 | use luminance::buffer; 5 | use std::cmp::Ordering::*; 6 | use std::mem; 7 | use std::os::raw::c_void; 8 | use std::ptr; 9 | use std::slice; 10 | 11 | pub type Buffer = buffer::Buffer; 12 | pub type BufferSlice<'a, T> = buffer::BufferSlice<'a, GL33, T>; 13 | pub type BufferSliceMut<'a, T> = buffer::BufferSliceMut<'a, GL33, T>; 14 | 15 | #[derive(Debug, Clone, Eq, PartialEq)] 16 | pub struct GLBuffer { 17 | pub handle: GLuint, 18 | pub bytes: usize 19 | } 20 | 21 | unsafe impl buffer::HasBuffer for GL33 { 22 | type ABuffer = GLBuffer; 23 | 24 | fn new(size: usize) -> Self::ABuffer { 25 | let mut buffer: GLuint = 0; 26 | 27 | unsafe { 28 | gl::GenBuffers(1, &mut buffer); 29 | gl::BindBuffer(gl::ARRAY_BUFFER, buffer); 30 | gl::BufferData(gl::ARRAY_BUFFER, size as isize, ptr::null(), gl::STREAM_DRAW); 31 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 32 | } 33 | 34 | GLBuffer { 35 | handle: buffer, 36 | bytes: size 37 | } 38 | } 39 | 40 | fn free(buffer: &mut Self::ABuffer) { 41 | unsafe { gl::DeleteBuffers(1, &buffer.handle) } 42 | } 43 | 44 | fn write_whole(buffer: &Self::ABuffer, values: &[T]) -> Result<(), buffer::BufferError> { 45 | let bytes = values.len() * mem::size_of::(); 46 | 47 | // generate warning and recompute the proper number of bytes to copy 48 | let (warning, bytes) = match bytes.cmp(&buffer.bytes) { 49 | Less => (Some(buffer::BufferError::TooFewValues), bytes), 50 | Greater => (Some(buffer::BufferError::TooManyValues), buffer.bytes), 51 | _ => (None, bytes) 52 | }; 53 | 54 | unsafe { 55 | gl::BindBuffer(gl::ARRAY_BUFFER, buffer.handle); 56 | let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::WRITE_ONLY); 57 | 58 | ptr::copy_nonoverlapping(values.as_ptr() as *const c_void, ptr, bytes); 59 | 60 | let _ = gl::UnmapBuffer(gl::ARRAY_BUFFER); 61 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 62 | } 63 | 64 | match warning { 65 | Some(w) => Err(w), 66 | None => Ok(()) 67 | } 68 | } 69 | 70 | fn write(buffer: &Self::ABuffer, off: usize, x: T) -> Result<(), buffer::BufferError> where T: Copy { 71 | if off >= buffer.bytes { 72 | return Err(buffer::BufferError::Overflow); 73 | } 74 | 75 | unsafe { 76 | gl::BindBuffer(gl::ARRAY_BUFFER, buffer.handle); 77 | let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::WRITE_ONLY); 78 | 79 | *(ptr.offset(off as isize) as *mut T) = x; 80 | 81 | let _ = gl::UnmapBuffer(gl::ARRAY_BUFFER); 82 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 83 | } 84 | 85 | Ok(()) 86 | } 87 | 88 | fn read_whole(buffer: &Self::ABuffer, nb: usize) -> Vec where T: Copy { 89 | unsafe { 90 | gl::BindBuffer(gl::ARRAY_BUFFER, buffer.handle); 91 | let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::READ_ONLY) as *const T; 92 | 93 | let values = Vec::from(slice::from_raw_parts(ptr, nb)); 94 | 95 | let _ = gl::UnmapBuffer(gl::ARRAY_BUFFER); 96 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 97 | 98 | values 99 | } 100 | } 101 | 102 | fn read(buffer: &Self::ABuffer, off: usize) -> Option where T: Copy { 103 | if off >= buffer.bytes { 104 | return None; 105 | } 106 | 107 | unsafe { 108 | gl::BindBuffer(gl::ARRAY_BUFFER, buffer.handle); 109 | let ptr = gl::MapBuffer(gl::ARRAY_BUFFER, gl::READ_ONLY); 110 | 111 | let x = *(ptr.offset(off as isize) as *const T); 112 | 113 | let _ = gl::UnmapBuffer(gl::ARRAY_BUFFER); 114 | gl::BindBuffer(gl::ARRAY_BUFFER, 0); 115 | 116 | Some(x) 117 | } 118 | } 119 | 120 | fn map(buffer: &mut Self::ABuffer) -> *const T { 121 | unsafe { 122 | gl::BindBuffer(gl::ARRAY_BUFFER, buffer.handle); 123 | gl::MapBuffer(gl::ARRAY_BUFFER, gl::READ_ONLY) as *const T 124 | } 125 | } 126 | 127 | fn map_mut(buffer: &mut Self::ABuffer) -> *mut T { 128 | unsafe { 129 | gl::BindBuffer(gl::ARRAY_BUFFER, buffer.handle); 130 | gl::MapBuffer(gl::ARRAY_BUFFER, gl::READ_WRITE) as *mut T 131 | } 132 | } 133 | 134 | fn unmap(buffer: &mut Self::ABuffer) { 135 | unsafe { 136 | gl::BindBuffer(gl::ARRAY_BUFFER, buffer.handle); // do that to be sure we’re unmapping that buffer 137 | gl::UnmapBuffer(gl::ARRAY_BUFFER); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/gl33/framebuffer.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use gl33::texture::{GLTexture, create_texture, to_target}; 4 | use gl33::token::GL33; 5 | use luminance::framebuffer::{self, ColorSlot, DepthSlot, FramebufferError, HasFramebuffer, Result}; 6 | use luminance::texture::{Dimensionable, Layerable}; 7 | use std::default::Default; 8 | 9 | pub type Framebuffer = framebuffer::Framebuffer; 10 | 11 | pub struct GLFramebuffer { 12 | pub handle: GLuint, 13 | pub renderbuffer: Option, 14 | pub w: u32, 15 | pub h: u32, 16 | } 17 | 18 | impl HasFramebuffer for GL33 { 19 | type Framebuffer = GLFramebuffer; 20 | 21 | fn new_framebuffer(size: D::Size, mipmaps: usize) -> Result<(Self::Framebuffer, Vec, Option)> 22 | where L: Layerable, 23 | D: Dimensionable, 24 | D::Size: Copy, 25 | CS: ColorSlot, 26 | DS: DepthSlot { 27 | let mut framebuffer: GLuint = 0; 28 | let color_formats = CS::color_formats(); 29 | let depth_format = DS::depth_format(); 30 | let target = to_target(L::layering(), D::dim()); 31 | let mut textures: Vec = vec![0; color_formats.len() + if depth_format.is_some() { 1 } else { 0 }]; // FIXME: remove that (inference) 32 | let mut depth_texture: Option = None; 33 | let mut depth_renderbuffer: Option = None; 34 | 35 | unsafe { 36 | gl::GenFramebuffers(1, &mut framebuffer); 37 | 38 | gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); 39 | 40 | // generate all the required textures with the correct formats 41 | gl::GenTextures((textures.len()) as GLint, textures.as_mut_ptr()); 42 | 43 | // color textures 44 | if color_formats.is_empty() { 45 | gl::DrawBuffer(gl::NONE); 46 | } else { 47 | for (i, (format, texture)) in color_formats.iter().zip(&textures).enumerate() { 48 | gl::BindTexture(target, *texture); 49 | create_texture::(target, size, mipmaps, *format, &Default::default()).map_err(FramebufferError::TextureError)?; 50 | gl::FramebufferTexture(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + i as GLenum, *texture, 0); 51 | } 52 | 53 | // specify the list of color buffers to draw to 54 | let color_buf_nb = color_formats.len() as GLsizei; 55 | let color_buffers: Vec<_> = (gl::COLOR_ATTACHMENT0..gl::COLOR_ATTACHMENT0 + color_buf_nb as GLenum).collect(); 56 | 57 | gl::DrawBuffers(color_buf_nb, color_buffers.as_ptr()); 58 | } 59 | 60 | // depth texture, if exists 61 | if let Some(format) = depth_format { 62 | let texture = textures.pop().unwrap(); 63 | 64 | gl::BindTexture(target, texture); 65 | create_texture::(target, size, mipmaps, format, &Default::default()).map_err(FramebufferError::TextureError)?; 66 | gl::FramebufferTexture(gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT, texture, 0); 67 | 68 | depth_texture = Some(texture); 69 | } else { 70 | let mut renderbuffer: GLuint = 0; 71 | 72 | gl::GenRenderbuffers(1, &mut renderbuffer); 73 | gl::BindRenderbuffer(gl::RENDERBUFFER, renderbuffer); 74 | gl::RenderbufferStorage(gl::RENDERBUFFER, gl::DEPTH_COMPONENT32F, D::width(size) as GLsizei, D::height(size) as GLsizei); 75 | gl::BindRenderbuffer(gl::RENDERBUFFER, 0); 76 | 77 | gl::FramebufferRenderbuffer(gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT, gl::RENDERBUFFER, renderbuffer); 78 | 79 | depth_renderbuffer = Some(renderbuffer); 80 | } 81 | 82 | gl::BindTexture(target, 0); 83 | 84 | let mut gl_framebuffer = GLFramebuffer { 85 | handle: framebuffer, 86 | renderbuffer: depth_renderbuffer, 87 | w: D::width(size), 88 | h: D::height(size) 89 | }; 90 | 91 | match get_status() { 92 | Some(incomplete) => { 93 | gl::BindFramebuffer(gl::FRAMEBUFFER, 0); 94 | 95 | Self::free_framebuffer(&mut gl_framebuffer); 96 | 97 | Err(FramebufferError::Incomplete(incomplete)) 98 | }, 99 | None => { 100 | gl::BindFramebuffer(gl::FRAMEBUFFER, 0); 101 | 102 | let textures = textures.into_iter().map(|t| GLTexture::new(t, target)).collect(); 103 | let depth_texture = depth_texture.map(|t| GLTexture::new(t, target)); 104 | Ok((gl_framebuffer, textures, depth_texture)) 105 | } 106 | } 107 | } 108 | } 109 | 110 | fn free_framebuffer(framebuffer: &mut Self::Framebuffer) { 111 | unsafe { 112 | if let Some(renderbuffer) = framebuffer.renderbuffer { 113 | gl::DeleteRenderbuffers(1, &renderbuffer); 114 | } 115 | 116 | if framebuffer.handle != 0 { 117 | gl::DeleteFramebuffers(1, &framebuffer.handle); 118 | } 119 | } 120 | } 121 | 122 | fn default_framebuffer(size: D::Size) -> Self::Framebuffer 123 | where D: Dimensionable, 124 | D::Size: Copy { 125 | GLFramebuffer { 126 | handle: 0, 127 | renderbuffer: None, 128 | w: D::width(size), 129 | h: D::height(size) 130 | } 131 | } 132 | } 133 | 134 | fn get_status() -> Option { 135 | let status = unsafe { gl::CheckFramebufferStatus(gl::FRAMEBUFFER) }; 136 | 137 | match status { 138 | gl::FRAMEBUFFER_COMPLETE => None, 139 | gl::FRAMEBUFFER_UNDEFINED => Some(String::from("framebuffer undefined")), 140 | gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => Some(String::from("incomplete attachment")), 141 | gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => Some(String::from("incomplete missing attachment")), 142 | gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => Some(String::from("incomplete draw buffer")), 143 | gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => Some(String::from("incomplete read buffer")), 144 | gl::FRAMEBUFFER_UNSUPPORTED => Some(String::from("unsupported")), 145 | gl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => Some(String::from("incomplete multisample")), 146 | gl::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => Some(String::from("incomplete layer targets")), 147 | _ => Some(String::from("unknown")) 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/gl33/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod buffer; 2 | pub mod framebuffer; 3 | pub mod pipeline; 4 | pub mod shader; 5 | pub mod tess; 6 | pub mod texture; 7 | pub mod token; 8 | 9 | pub use self::buffer::{Buffer, BufferSlice, BufferSliceMut}; 10 | pub use self::framebuffer::Framebuffer; 11 | pub use self::pipeline::{Pipe, Pipeline, RenderCommand, ShadingCommand}; 12 | pub use self::shader::program::{Program, Uniform}; 13 | pub use self::shader::stage::Stage; 14 | pub use self::tess::Tess; 15 | pub use self::texture::Texture; 16 | pub use self::token::*; 17 | -------------------------------------------------------------------------------- /src/gl33/pipeline.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use gl33::token::GL33; 4 | use luminance::blending; 5 | use luminance::framebuffer::{ColorSlot, DepthSlot}; 6 | use luminance::pipeline::{self, HasPipeline}; 7 | use luminance::texture::{Dimensionable, Layerable}; 8 | 9 | use gl33::shader::program::Program; 10 | 11 | pub type Pipeline<'a, L, D, CS, DS> = pipeline::Pipeline<'a, GL33, L, D, CS, DS>; 12 | pub type Pipe<'a, T> = pipeline::Pipe<'a, GL33, T>; 13 | pub type ShadingCommand<'a> = pipeline::ShadingCommand<'a, GL33>; 14 | pub type RenderCommand<'a> = pipeline::RenderCommand<'a, GL33>; 15 | 16 | impl HasPipeline for GL33 { 17 | fn run_pipeline(cmd: &Pipeline) 18 | where L: Layerable, 19 | D: Dimensionable, 20 | D::Size: Copy, 21 | CS: ColorSlot, 22 | DS: DepthSlot { 23 | let clear_color = cmd.clear_color; 24 | 25 | unsafe { 26 | gl::BindFramebuffer(gl::FRAMEBUFFER, cmd.framebuffer.repr.handle); 27 | gl::Viewport(0, 0, cmd.framebuffer.repr.w as GLint, cmd.framebuffer.repr.h as GLint); 28 | gl::ClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]); 29 | gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT); 30 | 31 | // traverse the texture set and bind required textures 32 | for (unit, tex) in cmd.texture_set.iter().enumerate() { 33 | gl::ActiveTexture(gl::TEXTURE0 + unit as GLenum); 34 | gl::BindTexture(tex.repr.target, tex.repr.handle); 35 | } 36 | 37 | // traverse the buffer set and bind required buffers 38 | for (index, buf) in cmd.buffer_set.iter().enumerate() { 39 | gl::BindBufferBase(gl::UNIFORM_BUFFER, index as GLuint, buf.repr.handle); 40 | } 41 | } 42 | 43 | for piped_shading_cmd in &cmd.shading_commands { 44 | Self::run_shading_command(piped_shading_cmd); 45 | } 46 | } 47 | 48 | fn run_shading_command<'a>(piped: &Pipe<'a, ShadingCommand>) { 49 | let update_program = &piped.update_program; 50 | let shading_cmd = &piped.next; 51 | 52 | unsafe { gl::UseProgram(shading_cmd.program.0.id) }; 53 | 54 | update_program(&shading_cmd.program); 55 | 56 | for piped_render_cmd in &shading_cmd.render_commands { 57 | run_render_command(&shading_cmd.program, piped_render_cmd); 58 | } 59 | } 60 | } 61 | 62 | fn run_render_command<'a>(program: &Program, piped: &Pipe<'a, RenderCommand<'a>>) { 63 | let update_program = &piped.update_program; 64 | let render_cmd = &piped.next; 65 | 66 | update_program(program); 67 | 68 | set_blending(render_cmd.blending); 69 | set_depth_test(render_cmd.depth_test); 70 | 71 | for piped_tess in &render_cmd.tessellations { 72 | let tess_update_program = &piped_tess.update_program; 73 | let tess = &piped_tess.next; 74 | 75 | tess_update_program(program); 76 | 77 | (tess.repr.render)(render_cmd.rasterization_size, render_cmd.instances); 78 | } 79 | } 80 | 81 | fn set_blending(blending: Option<(blending::Equation, blending::Factor, blending::Factor)>) { 82 | match blending { 83 | Some((equation, src_factor, dest_factor)) => { 84 | unsafe { 85 | gl::Enable(gl::BLEND); 86 | gl::BlendEquation(from_blending_equation(equation)); 87 | gl::BlendFunc(from_blending_factor(src_factor), from_blending_factor(dest_factor)); 88 | } 89 | }, 90 | None => { 91 | unsafe { gl::Disable(gl::BLEND) }; 92 | } 93 | } 94 | } 95 | 96 | fn from_blending_equation(equation: blending::Equation) -> GLenum { 97 | match equation { 98 | blending::Equation::Additive => gl::FUNC_ADD, 99 | blending::Equation::Subtract => gl::FUNC_SUBTRACT, 100 | blending::Equation::ReverseSubtract => gl::FUNC_REVERSE_SUBTRACT, 101 | blending::Equation::Min => gl::MIN, 102 | blending::Equation::Max => gl::MAX 103 | } 104 | } 105 | 106 | fn from_blending_factor(factor: blending::Factor) -> GLenum { 107 | match factor { 108 | blending::Factor::One => gl::ONE, 109 | blending::Factor::Zero => gl::ZERO, 110 | blending::Factor::SrcColor => gl::SRC_COLOR, 111 | blending::Factor::SrcColorComplement => gl::ONE_MINUS_SRC_COLOR, 112 | blending::Factor::DestColor => gl::DST_COLOR, 113 | blending::Factor::DestColorComplement => gl::ONE_MINUS_DST_COLOR, 114 | blending::Factor::SrcAlpha => gl::SRC_ALPHA, 115 | blending::Factor::SrcAlphaComplement => gl::ONE_MINUS_SRC_ALPHA, 116 | blending::Factor::DstAlpha => gl::DST_ALPHA, 117 | blending::Factor::DstAlphaComplement => gl::ONE_MINUS_DST_ALPHA, 118 | blending::Factor::SrcAlphaSaturate => gl::SRC_ALPHA_SATURATE 119 | } 120 | } 121 | 122 | fn set_depth_test(test: bool) { 123 | unsafe { 124 | if test { 125 | gl::Enable(gl::DEPTH_TEST); 126 | } else { 127 | gl::Disable(gl::DEPTH_TEST); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/gl33/shader/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod program; 2 | pub mod stage; 3 | -------------------------------------------------------------------------------- /src/gl33/shader/program.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use luminance::linear::{M22, M33, M44}; 4 | use luminance::shader::program::{self, Dim, HasProgram, ProgramError, Type, Sem, SemIndex, 5 | UniformWarning}; 6 | use std::collections::HashMap; 7 | use std::ffi::CString; 8 | use std::ptr::null_mut; 9 | 10 | use gl33::token::GL33; 11 | 12 | pub type Program = program::Program; 13 | 14 | pub struct GLProgram { 15 | pub id: GLuint, // OpenGL ID 16 | uni_sem_map: HashMap, // mapping between user semantic (indexes) and OpenGL uniform locations 17 | ubo_sem_map: HashMap, // mapping between user semantic (indexes) and OpenGL uniform block indexes 18 | } 19 | 20 | impl HasProgram for GL33 { 21 | type Program = GLProgram; 22 | 23 | fn new_program(tess: Option<(&Self::AStage, &Self::AStage)>, vertex: &Self::AStage, geometry: Option<&Self::AStage>, fragment: &Self::AStage, sem_map: &[Sem]) -> Result<(Self::Program, Vec), ProgramError> { 24 | unsafe { 25 | let program = gl::CreateProgram(); 26 | 27 | if let Some((tcs, tes)) = tess { 28 | gl::AttachShader(program, *tcs); 29 | gl::AttachShader(program, *tes); 30 | } 31 | 32 | gl::AttachShader(program, *vertex); 33 | 34 | if let Some(geometry) = geometry { 35 | gl::AttachShader(program, *geometry); 36 | } 37 | 38 | gl::AttachShader(program, *fragment); 39 | 40 | gl::LinkProgram(program); 41 | 42 | let mut linked: GLint = gl::FALSE as GLint; 43 | gl::GetProgramiv(program, gl::LINK_STATUS, &mut linked); 44 | 45 | if linked == (gl::TRUE as GLint) { 46 | let mut uni_sem_map = HashMap::new(); 47 | let mut ubo_sem_map = HashMap::new(); 48 | let mut warnings = Vec::new(); 49 | 50 | for sem in sem_map { 51 | let (loc, warning) = get_uniform_location(program, sem.name(), sem.ty(), sem.dim()); 52 | 53 | match loc { 54 | Location::Uniform(location) => uni_sem_map.insert(sem.index(), location), 55 | Location::UniformBlock(index) => ubo_sem_map.insert(sem.index(), index) 56 | }; 57 | 58 | // if there’s a warning, add it to the list of warnings 59 | if let Some(warning) = warning { 60 | warnings.push(warning); 61 | } 62 | } 63 | 64 | let gl_program = GLProgram { 65 | id: program, 66 | uni_sem_map: uni_sem_map, 67 | ubo_sem_map: ubo_sem_map, 68 | }; 69 | 70 | Ok((gl_program, warnings)) 71 | } else { 72 | let mut log_len: GLint = 0; 73 | gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut log_len); 74 | 75 | let mut log: Vec = Vec::with_capacity(log_len as usize); 76 | gl::GetProgramInfoLog(program, log_len, null_mut(), log.as_mut_ptr() as *mut GLchar); 77 | 78 | gl::DeleteProgram(program); 79 | 80 | log.set_len(log_len as usize); 81 | 82 | Err(ProgramError::LinkFailed(String::from_utf8(log).unwrap())) 83 | } 84 | } 85 | } 86 | 87 | fn free_program(program: &mut Self::Program) { 88 | unsafe { gl::DeleteProgram(program.id) } 89 | } 90 | 91 | fn update_uniforms(program: &Self::Program, f: F) where F: Fn() { 92 | unsafe { gl::UseProgram(program.id) }; 93 | f(); 94 | unsafe { gl::UseProgram(0) }; 95 | } 96 | 97 | fn update1_i32(program: &Self::Program, u: SemIndex, x: i32) { 98 | assert!((u as usize) < program.uni_sem_map.len()); 99 | unsafe { gl::Uniform1i(program.uni_sem_map[&u], x) } 100 | } 101 | 102 | fn update2_i32(program: &Self::Program, u: SemIndex, v: [i32; 2]) { 103 | assert!((u as usize) < program.uni_sem_map.len()); 104 | unsafe { gl::Uniform2iv(program.uni_sem_map[&u], 1, &v as *const i32) } 105 | } 106 | 107 | fn update3_i32(program: &Self::Program, u: SemIndex, v: [i32; 3]) { 108 | assert!((u as usize) < program.uni_sem_map.len()); 109 | unsafe { gl::Uniform3iv(program.uni_sem_map[&u], 1, &v as *const i32) } 110 | } 111 | 112 | fn update4_i32(program: &Self::Program, u: SemIndex, v: [i32; 4]) { 113 | unsafe { gl::Uniform4iv(program.uni_sem_map[&u], 1, &v as *const i32) } 114 | } 115 | 116 | fn update1_slice_i32(program: &Self::Program, u: SemIndex, v: &[i32]) { 117 | assert!((u as usize) < program.uni_sem_map.len()); 118 | unsafe { gl::Uniform1iv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr()) } 119 | } 120 | 121 | fn update2_slice_i32(program: &Self::Program, u: SemIndex, v: &[[i32; 2]]) { 122 | assert!((u as usize) < program.uni_sem_map.len()); 123 | unsafe { gl::Uniform2iv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const i32) } 124 | } 125 | 126 | fn update3_slice_i32(program: &Self::Program, u: SemIndex, v: &[[i32; 3]]) { 127 | assert!((u as usize) < program.uni_sem_map.len()); 128 | unsafe { gl::Uniform3iv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const i32) } 129 | } 130 | 131 | fn update4_slice_i32(program: &Self::Program, u: SemIndex, v: &[[i32; 4]]) { 132 | assert!((u as usize) < program.uni_sem_map.len()); 133 | unsafe { gl::Uniform4iv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const i32) } 134 | } 135 | 136 | fn update1_u32(program: &Self::Program, u: SemIndex, x: u32) { 137 | assert!((u as usize) < program.uni_sem_map.len()); 138 | unsafe { gl::Uniform1ui(program.uni_sem_map[&u], x) } 139 | } 140 | 141 | fn update2_u32(program: &Self::Program, u: SemIndex, v: [u32; 2]) { 142 | assert!((u as usize) < program.uni_sem_map.len()); 143 | unsafe { gl::Uniform2uiv(program.uni_sem_map[&u], 1, &v as *const u32) } 144 | } 145 | 146 | fn update3_u32(program: &Self::Program, u: SemIndex, v: [u32; 3]) { 147 | assert!((u as usize) < program.uni_sem_map.len()); 148 | unsafe { gl::Uniform3uiv(program.uni_sem_map[&u], 1, &v as *const u32) } 149 | } 150 | 151 | fn update4_u32(program: &Self::Program, u: SemIndex, v: [u32; 4]) { 152 | assert!((u as usize) < program.uni_sem_map.len()); 153 | unsafe { gl::Uniform4uiv(program.uni_sem_map[&u], 1, &v as *const u32) } 154 | } 155 | 156 | fn update1_slice_u32(program: &Self::Program, u: SemIndex, v: &[u32]) { 157 | assert!((u as usize) < program.uni_sem_map.len()); 158 | unsafe { gl::Uniform1uiv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const u32) } 159 | } 160 | 161 | fn update2_slice_u32(program: &Self::Program, u: SemIndex, v: &[[u32; 2]]) { 162 | assert!((u as usize) < program.uni_sem_map.len()); 163 | unsafe { gl::Uniform2uiv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const u32) } 164 | } 165 | 166 | fn update3_slice_u32(program: &Self::Program, u: SemIndex, v: &[[u32; 3]]) { 167 | assert!((u as usize) < program.uni_sem_map.len()); 168 | unsafe { gl::Uniform3uiv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const u32) } 169 | } 170 | 171 | fn update4_slice_u32(program: &Self::Program, u: SemIndex, v: &[[u32; 4]]) { 172 | assert!((u as usize) < program.uni_sem_map.len()); 173 | unsafe { gl::Uniform4uiv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const u32) } 174 | } 175 | 176 | fn update1_f32(program: &Self::Program, u: SemIndex, x: f32) { 177 | assert!((u as usize) < program.uni_sem_map.len()); 178 | unsafe { gl::Uniform1f(program.uni_sem_map[&u], x) } 179 | } 180 | 181 | fn update2_f32(program: &Self::Program, u: SemIndex, v: [f32; 2]) { 182 | assert!((u as usize) < program.uni_sem_map.len()); 183 | unsafe { gl::Uniform2fv(program.uni_sem_map[&u], 1, &v as *const f32) } 184 | } 185 | 186 | fn update3_f32(program: &Self::Program, u: SemIndex, v: [f32; 3]) { 187 | assert!((u as usize) < program.uni_sem_map.len()); 188 | unsafe { gl::Uniform3fv(program.uni_sem_map[&u], 1, &v as *const f32) } 189 | } 190 | 191 | fn update4_f32(program: &Self::Program, u: SemIndex, v: [f32; 4]) { 192 | assert!((u as usize) < program.uni_sem_map.len()); 193 | unsafe { gl::Uniform4fv(program.uni_sem_map[&u], 1, &v as *const f32) } 194 | } 195 | 196 | fn update1_slice_f32(program: &Self::Program, u: SemIndex, v: &[f32]) { 197 | assert!((u as usize) < program.uni_sem_map.len()); 198 | unsafe { gl::Uniform1fv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const f32) } 199 | } 200 | 201 | fn update2_slice_f32(program: &Self::Program, u: SemIndex, v: &[[f32; 2]]) { 202 | assert!((u as usize) < program.uni_sem_map.len()); 203 | unsafe { gl::Uniform2fv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const f32) } 204 | } 205 | 206 | fn update3_slice_f32(program: &Self::Program, u: SemIndex, v: &[[f32; 3]]) { 207 | assert!((u as usize) < program.uni_sem_map.len()); 208 | unsafe { gl::Uniform3fv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const f32) } 209 | } 210 | 211 | fn update4_slice_f32(program: &Self::Program, u: SemIndex, v: &[[f32; 4]]) { 212 | assert!((u as usize) < program.uni_sem_map.len()); 213 | unsafe { gl::Uniform4fv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const f32) } 214 | } 215 | 216 | fn update22_f32(program: &Self::Program, u: SemIndex, m: M22) { 217 | assert!((u as usize) < program.uni_sem_map.len()); 218 | Self::update22_slice_f32(program, u, &[m]) 219 | } 220 | 221 | fn update33_f32(program: &Self::Program, u: SemIndex, m: M33) { 222 | assert!((u as usize) < program.uni_sem_map.len()); 223 | Self::update33_slice_f32(program, u, &[m]) 224 | } 225 | 226 | fn update44_f32(program: &Self::Program, u: SemIndex, m: M44) { 227 | assert!((u as usize) < program.uni_sem_map.len()); 228 | Self::update44_slice_f32(program, u, &[m]) 229 | } 230 | 231 | fn update22_slice_f32(program: &Self::Program, u: SemIndex, v: &[M22]) { 232 | assert!((u as usize) < program.uni_sem_map.len()); 233 | unsafe { gl::UniformMatrix2fv(program.uni_sem_map[&u], v.len() as GLsizei, gl::FALSE, v.as_ptr() as *const f32) } 234 | } 235 | 236 | fn update33_slice_f32(program: &Self::Program, u: SemIndex, v: &[M33]) { 237 | assert!((u as usize) < program.uni_sem_map.len()); 238 | unsafe { gl::UniformMatrix3fv(program.uni_sem_map[&u], v.len() as GLsizei, gl::FALSE, v.as_ptr() as *const f32) } 239 | } 240 | 241 | fn update44_slice_f32(program: &Self::Program, u: SemIndex, v: &[M44]) { 242 | assert!((u as usize) < program.uni_sem_map.len()); 243 | unsafe { gl::UniformMatrix4fv(program.uni_sem_map[&u], v.len() as GLsizei, gl::FALSE, v.as_ptr() as *const f32) } 244 | } 245 | 246 | fn update1_bool(program: &Self::Program, u: SemIndex, x: bool) { 247 | assert!((u as usize) < program.uni_sem_map.len()); 248 | unsafe { gl::Uniform1ui(program.uni_sem_map[&u], x as GLuint) } 249 | } 250 | 251 | fn update2_bool(program: &Self::Program, u: SemIndex, v: [bool; 2]) { 252 | assert!((u as usize) < program.uni_sem_map.len()); 253 | let v = [v[0] as u32, v[1] as u32]; 254 | unsafe { gl::Uniform2uiv(program.uni_sem_map[&u], 1, &v as *const u32) } 255 | } 256 | 257 | fn update3_bool(program: &Self::Program, u: SemIndex, v: [bool; 3]) { 258 | assert!((u as usize) < program.uni_sem_map.len()); 259 | let v = [v[0] as u32, v[1] as u32, v[2] as u32]; 260 | unsafe { gl::Uniform3uiv(program.uni_sem_map[&u], 1, &v as *const u32) } 261 | } 262 | 263 | fn update4_bool(program: &Self::Program, u: SemIndex, v: [bool; 4]) { 264 | assert!((u as usize) < program.uni_sem_map.len()); 265 | let v = [v[0] as u32, v[1] as u32, v[2] as u32, v[3] as u32]; 266 | unsafe { gl::Uniform4uiv(program.uni_sem_map[&u], 1, &v as *const u32) } 267 | } 268 | 269 | fn update1_slice_bool(program: &Self::Program, u: SemIndex, v: &[bool]) { 270 | assert!((u as usize) < program.uni_sem_map.len()); 271 | let v: Vec<_> = v.iter().map(|x| *x as u32).collect(); 272 | unsafe { gl::Uniform1uiv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr()) } 273 | } 274 | 275 | fn update2_slice_bool(program: &Self::Program, u: SemIndex, v: &[[bool; 2]]) { 276 | assert!((u as usize) < program.uni_sem_map.len()); 277 | let v: Vec<_> = v.iter().map(|x| [x[0] as u32, x[1] as u32]).collect(); 278 | unsafe { gl::Uniform2uiv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const u32) } 279 | } 280 | 281 | fn update3_slice_bool(program: &Self::Program, u: SemIndex, v: &[[bool; 3]]) { 282 | assert!((u as usize) < program.uni_sem_map.len()); 283 | let v: Vec<_> = v.iter().map(|x| [x[0] as u32, x[1] as u32, x[2] as u32]).collect(); 284 | unsafe { gl::Uniform3uiv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const u32) } 285 | } 286 | 287 | fn update4_slice_bool(program: &Self::Program, u: SemIndex, v: &[[bool; 4]]) { 288 | assert!((u as usize) < program.uni_sem_map.len()); 289 | let v: Vec<_> = v.iter().map(|x| [x[0] as u32, x[1] as u32, x[2] as u32, x[3] as u32]).collect(); 290 | unsafe { gl::Uniform4uiv(program.uni_sem_map[&u], v.len() as GLsizei, v.as_ptr() as *const u32) } 291 | } 292 | 293 | fn update_texture_unit(program: &Self::Program, u: SemIndex, unit: u32) { 294 | assert!((u as usize) < program.uni_sem_map.len()); 295 | unsafe { gl::Uniform1i(program.uni_sem_map[&u], unit as GLint) } 296 | } 297 | 298 | fn update_buffer_binding(program: &Self::Program, u: SemIndex, binding: u32) { 299 | assert!((u as usize) < program.ubo_sem_map.len()); 300 | unsafe { gl::UniformBlockBinding(program.id, program.ubo_sem_map[&u] as GLuint, binding as GLuint) } 301 | } 302 | } 303 | 304 | enum Location { 305 | Uniform(GLint), 306 | UniformBlock(GLint), 307 | } 308 | 309 | // Retrieve the uniform location. 310 | fn get_uniform_location(program: GLuint, name: &str, ty: Type, dim: Dim) -> (Location, Option) { 311 | let c_name = CString::new(name.as_bytes()).unwrap(); 312 | let location = if ty == Type::BufferBinding { 313 | let index = unsafe { gl::GetUniformBlockIndex(program, c_name.as_ptr() as *const GLchar) }; 314 | 315 | if index == gl::INVALID_INDEX { 316 | return (Location::UniformBlock(-1), Some(UniformWarning::Inactive(name.to_owned()))); 317 | } 318 | 319 | Location::UniformBlock(index as GLint) 320 | } else { 321 | let location = unsafe { gl::GetUniformLocation(program, c_name.as_ptr() as *const GLchar) }; 322 | 323 | if location == -1 { 324 | return (Location::Uniform(-1), Some(UniformWarning::Inactive(name.to_owned()))); 325 | } 326 | 327 | Location::Uniform(location) 328 | }; 329 | 330 | if let Some(err) = uniform_type_match(program, name, ty, dim) { 331 | return (location, Some(UniformWarning::TypeMismatch(name.to_owned(), err))); 332 | } 333 | 334 | (location, None) 335 | } 336 | 337 | // Return something if no match can be established. 338 | fn uniform_type_match(program: GLuint, name: &str, ty: Type, dim: Dim) -> Option { 339 | let mut size: GLint = 0; 340 | let mut typ: GLuint = 0; 341 | 342 | unsafe { 343 | // get the index of the uniform 344 | let mut index = 0; 345 | gl::GetUniformIndices(program, 1, [name.as_ptr() as *const i8].as_ptr(), &mut index); 346 | // get its size and type 347 | gl::GetActiveUniform(program, index, 0, null_mut(), &mut size, &mut typ, null_mut()); 348 | } 349 | 350 | // FIXME 351 | // early-return if array – we don’t support them yet 352 | if size != 1 { 353 | return None; 354 | } 355 | 356 | match (ty, dim) { 357 | (Type::Integral, Dim::Dim1) if typ != gl::INT => Some("requested int doesn't match".to_owned()), 358 | (Type::Integral, Dim::Dim2) if typ != gl::INT_VEC2 => Some("requested ivec2 doesn't match".to_owned()), 359 | (Type::Integral, Dim::Dim3) if typ != gl::INT_VEC3 => Some("requested ivec3 doesn't match".to_owned()), 360 | (Type::Integral, Dim::Dim4) if typ != gl::INT_VEC4 => Some("requested ivec4 doesn't match".to_owned()), 361 | (Type::Unsigned, Dim::Dim1) if typ != gl::UNSIGNED_INT => Some("requested uint doesn't match".to_owned()), 362 | (Type::Unsigned, Dim::Dim2) if typ != gl::UNSIGNED_INT_VEC2 => Some("requested uvec2 doesn't match".to_owned()), 363 | (Type::Unsigned, Dim::Dim3) if typ != gl::UNSIGNED_INT_VEC3 => Some("requested uvec3 doesn't match".to_owned()), 364 | (Type::Unsigned, Dim::Dim4) if typ != gl::UNSIGNED_INT_VEC4 => Some("requested uvec4 doesn't match".to_owned()), 365 | (Type::Floating, Dim::Dim1) if typ != gl::FLOAT => Some("requested float doesn't match".to_owned()), 366 | (Type::Floating, Dim::Dim2) if typ != gl::FLOAT_VEC2 => Some("requested vec2 doesn't match".to_owned()), 367 | (Type::Floating, Dim::Dim3) if typ != gl::FLOAT_VEC3 => Some("requested vec3 doesn't match".to_owned()), 368 | (Type::Floating, Dim::Dim4) if typ != gl::FLOAT_VEC4 => Some("requested vec4 doesn't match".to_owned()), 369 | (Type::Floating, Dim::Dim22) if typ != gl::FLOAT_MAT2 => Some("requested mat2 doesn't match".to_owned()), 370 | (Type::Floating, Dim::Dim33) if typ != gl::FLOAT_MAT3 => Some("requested mat3 doesn't match".to_owned()), 371 | (Type::Floating, Dim::Dim44) if typ != gl::FLOAT_MAT4 => Some("requested mat4 doesn't match".to_owned()), 372 | (Type::Boolean, Dim::Dim1) if typ != gl::BOOL => Some("requested bool doesn't match".to_owned()), 373 | (Type::Boolean, Dim::Dim2) if typ != gl::BOOL_VEC2 => Some("requested bvec2 doesn't match".to_owned()), 374 | (Type::Boolean, Dim::Dim3) if typ != gl::BOOL_VEC3 => Some("requested bvec3 doesn't match".to_owned()), 375 | (Type::Boolean, Dim::Dim4) if typ != gl::BOOL_VEC4 => Some("requested bvec4 doesn't match".to_owned()), 376 | _ => None 377 | } 378 | } 379 | 380 | pub type Uniform = program::Uniform; 381 | pub type Uniformable = program::Uniformable; 382 | -------------------------------------------------------------------------------- /src/gl33/shader/stage.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use gl33::token::GL33; 4 | use luminance::shader::stage; 5 | use luminance::shader::stage::{HasStage, StageError, Type}; 6 | use std::ffi::CString; 7 | use std::ptr::{null, null_mut}; 8 | 9 | pub type Stage = stage::Stage; 10 | 11 | impl HasStage for GL33 { 12 | type AStage = GLuint; 13 | 14 | fn new_shader(shader_type: Type, src: &str) -> Result { 15 | unsafe { 16 | let src = CString::new(glsl_pragma_src(src).as_bytes()).unwrap(); 17 | let handle = gl::CreateShader(from_shader_type(shader_type)); 18 | 19 | if handle == 0 { 20 | return Err(StageError::CompilationFailed(shader_type, String::from("unable to create shader stage"))); 21 | } 22 | 23 | gl::ShaderSource(handle, 1, [src.as_ptr()].as_ptr(), null()); 24 | gl::CompileShader(handle); 25 | 26 | let mut compiled: GLint = gl::FALSE as GLint; 27 | gl::GetShaderiv(handle, gl::COMPILE_STATUS, &mut compiled); 28 | 29 | if compiled == (gl::TRUE as GLint) { 30 | Ok(handle) 31 | } else { 32 | let mut log_len: GLint = 0; 33 | gl::GetShaderiv(handle, gl::INFO_LOG_LENGTH, &mut log_len); 34 | 35 | let mut log: Vec = Vec::with_capacity(log_len as usize); 36 | gl::GetShaderInfoLog(handle, log_len, null_mut(), log.as_mut_ptr() as *mut GLchar); 37 | 38 | gl::DeleteShader(handle); 39 | 40 | log.set_len(log_len as usize); 41 | 42 | Err(StageError::CompilationFailed(shader_type, String::from_utf8(log).unwrap())) 43 | } 44 | } 45 | } 46 | 47 | fn free_shader(shader: &mut Self::AStage) { 48 | unsafe { gl::DeleteShader(*shader) } 49 | } 50 | } 51 | 52 | // FIXME: check for GL_ARB_tessellation_shader extension if we need tessellation shaders 53 | fn from_shader_type(t: Type) -> GLenum { 54 | match t { 55 | Type::TessellationControlShader => gl::TESS_CONTROL_SHADER, 56 | Type::TessellationEvaluationShader => gl::TESS_EVALUATION_SHADER, 57 | Type::VertexShader => gl::VERTEX_SHADER, 58 | Type::GeometryShader => gl::GEOMETRY_SHADER, 59 | Type::FragmentShader => gl::FRAGMENT_SHADER 60 | } 61 | } 62 | 63 | fn glsl_pragma_src(src: &str) -> String { 64 | let mut pragma = String::from(GLSL_PRAGMA); 65 | pragma.push_str(src); 66 | 67 | pragma 68 | } 69 | 70 | const GLSL_PRAGMA: &'static str = "\ 71 | #version 330 core\n\ 72 | #extension GL_ARB_separate_shader_objects : require\n"; 73 | -------------------------------------------------------------------------------- /src/gl33/shader/uniform.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use gl33::token::GL33; 4 | use luminance::linear::*; 5 | use luminance::shader::uniform; 6 | 7 | pub type Uniform = uniform::Uniform; 8 | pub type Uniformable = uniform::Uniformable; 9 | 10 | impl uniform::HasUniform for GL33 { 11 | type U = GLint; 12 | 13 | fn update1_i32(u: &Self::U, x: i32) { 14 | unsafe { gl::Uniform1i(*u, x) } 15 | } 16 | 17 | fn update2_i32(u: &Self::U, v: [i32; 2]) { 18 | unsafe { gl::Uniform2iv(*u, 1, &v as *const i32) } 19 | } 20 | 21 | fn update3_i32(u: &Self::U, v: [i32; 3]) { 22 | unsafe { gl::Uniform3iv(*u, 1, &v as *const i32) } 23 | } 24 | 25 | fn update4_i32(u: &Self::U, v: [i32; 4]) { 26 | unsafe { gl::Uniform4iv(*u, 1, &v as *const i32) } 27 | } 28 | 29 | fn update1_slice_i32(u: &Self::U, v: &[i32]) { 30 | unsafe { gl::Uniform1iv(*u, v.len() as GLsizei, v.as_ptr()) } 31 | } 32 | 33 | fn update2_slice_i32(u: &Self::U, v: &[[i32; 2]]) { 34 | unsafe { gl::Uniform2iv(*u, v.len() as GLsizei, v.as_ptr() as *const i32) } 35 | } 36 | 37 | fn update3_slice_i32(u: &Self::U, v: &[[i32; 3]]) { 38 | unsafe { gl::Uniform3iv(*u, v.len() as GLsizei, v.as_ptr() as *const i32) } 39 | } 40 | 41 | fn update4_slice_i32(u: &Self::U, v: &[[i32; 4]]) { 42 | unsafe { gl::Uniform4iv(*u, v.len() as GLsizei, v.as_ptr() as *const i32) } 43 | } 44 | 45 | fn update1_u32(u: &Self::U, x: u32) { 46 | unsafe { gl::Uniform1ui(*u, x) } 47 | } 48 | 49 | fn update2_u32(u: &Self::U, v: [u32; 2]) { 50 | unsafe { gl::Uniform2uiv(*u, 1, &v as *const u32) } 51 | } 52 | 53 | fn update3_u32(u: &Self::U, v: [u32; 3]) { 54 | unsafe { gl::Uniform3uiv(*u, 1, &v as *const u32) } 55 | } 56 | 57 | fn update4_u32(u: &Self::U, v: [u32; 4]) { 58 | unsafe { gl::Uniform4uiv(*u, 1, &v as *const u32) } 59 | } 60 | 61 | fn update1_slice_u32(u: &Self::U, v: &[u32]) { 62 | unsafe { gl::Uniform1uiv(*u, v.len() as GLsizei, v.as_ptr() as *const u32) } 63 | } 64 | 65 | fn update2_slice_u32(u: &Self::U, v: &[[u32; 2]]) { 66 | unsafe { gl::Uniform2uiv(*u, v.len() as GLsizei, v.as_ptr() as *const u32) } 67 | } 68 | 69 | fn update3_slice_u32(u: &Self::U, v: &[[u32; 3]]) { 70 | unsafe { gl::Uniform3uiv(*u, v.len() as GLsizei, v.as_ptr() as *const u32) } 71 | } 72 | 73 | fn update4_slice_u32(u: &Self::U, v: &[[u32; 4]]) { 74 | unsafe { gl::Uniform4uiv(*u, v.len() as GLsizei, v.as_ptr() as *const u32) } 75 | } 76 | 77 | fn update1_f32(u: &Self::U, x: f32) { 78 | unsafe { gl::Uniform1f(*u, x) } 79 | } 80 | 81 | fn update2_f32(u: &Self::U, v: [f32; 2]) { 82 | unsafe { gl::Uniform2fv(*u, 1, &v as *const f32) } 83 | } 84 | 85 | fn update3_f32(u: &Self::U, v: [f32; 3]) { 86 | unsafe { gl::Uniform3fv(*u, 1, &v as *const f32) } 87 | } 88 | 89 | fn update4_f32(u: &Self::U, v: [f32; 4]) { 90 | unsafe { gl::Uniform4fv(*u, 1, &v as *const f32) } 91 | } 92 | 93 | fn update1_slice_f32(u: &Self::U, v: &[f32]) { 94 | unsafe { gl::Uniform1fv(*u, v.len() as GLsizei, v.as_ptr() as *const f32) } 95 | } 96 | 97 | fn update2_slice_f32(u: &Self::U, v: &[[f32; 2]]) { 98 | unsafe { gl::Uniform2fv(*u, v.len() as GLsizei, v.as_ptr() as *const f32) } 99 | } 100 | 101 | fn update3_slice_f32(u: &Self::U, v: &[[f32; 3]]) { 102 | unsafe { gl::Uniform3fv(*u, v.len() as GLsizei, v.as_ptr() as *const f32) } 103 | } 104 | 105 | fn update4_slice_f32(u: &Self::U, v: &[[f32; 4]]) { 106 | unsafe { gl::Uniform4fv(*u, v.len() as GLsizei, v.as_ptr() as *const f32) } 107 | } 108 | 109 | fn update22_f32(u: &Self::U, m: M22) { 110 | Self::update22_slice_f32(u, &[m]) 111 | } 112 | 113 | fn update33_f32(u: &Self::U, m: M33) { 114 | Self::update33_slice_f32(u, &[m]) 115 | } 116 | 117 | fn update44_f32(u: &Self::U, m: M44) { 118 | Self::update44_slice_f32(u, &[m]) 119 | } 120 | 121 | fn update22_slice_f32(u: &Self::U, v: &[M22]) { 122 | unsafe { gl::UniformMatrix2fv(*u, v.len() as GLsizei, gl::FALSE, v.as_ptr() as *const f32) } 123 | } 124 | 125 | fn update33_slice_f32(u: &Self::U, v: &[M33]) { 126 | unsafe { gl::UniformMatrix3fv(*u, v.len() as GLsizei, gl::FALSE, v.as_ptr() as *const f32) } 127 | } 128 | 129 | fn update44_slice_f32(u: &Self::U, v: &[M44]) { 130 | unsafe { gl::UniformMatrix4fv(*u, v.len() as GLsizei, gl::FALSE, v.as_ptr() as *const f32) } 131 | } 132 | 133 | fn update1_bool(u: &Self::U, x: bool) { 134 | unsafe { gl::Uniform1i(*u, x as GLint) } 135 | } 136 | 137 | fn update2_bool(u: &Self::U, v: [bool; 2]) { 138 | let v = [v[0] as i32, v[1] as i32]; 139 | unsafe { gl::Uniform2iv(*u, 1, &v as *const i32) } 140 | } 141 | 142 | fn update3_bool(u: &Self::U, v: [bool; 3]) { 143 | let v = [v[0] as i32, v[1] as i32, v[2] as i32]; 144 | unsafe { gl::Uniform3iv(*u, 1, &v as *const i32) } 145 | } 146 | 147 | fn update4_bool(u: &Self::U, v: [bool; 4]) { 148 | let v = [v[0] as i32, v[1] as i32, v[2] as i32, v[3] as i32]; 149 | unsafe { gl::Uniform4iv(*u, 1, &v as *const i32) } 150 | } 151 | 152 | fn update1_slice_bool(u: &Self::U, v: &[bool]) { 153 | let v: Vec<_> = v.iter().map(|x| *x as i32).collect(); 154 | unsafe { gl::Uniform1iv(*u, v.len() as GLsizei, v.as_ptr()) } 155 | } 156 | 157 | fn update2_slice_bool(u: &Self::U, v: &[[bool; 2]]) { 158 | let v: Vec<_> = v.iter().map(|x| [x[0] as i32, x[1] as i32]).collect(); 159 | unsafe { gl::Uniform2iv(*u, v.len() as GLsizei, v.as_ptr() as *const i32) } 160 | } 161 | 162 | fn update3_slice_bool(u: &Self::U, v: &[[bool; 3]]) { 163 | let v: Vec<_> = v.iter().map(|x| [x[0] as i32, x[1] as i32, x[2] as i32]).collect(); 164 | unsafe { gl::Uniform3iv(*u, v.len() as GLsizei, v.as_ptr() as *const i32) } 165 | } 166 | 167 | fn update4_slice_bool(u: &Self::U, v: &[[bool; 4]]) { 168 | let v: Vec<_> = v.iter().map(|x| [x[0] as i32, x[1] as i32, x[2] as i32, x[3] as i32]).collect(); 169 | unsafe { gl::Uniform4iv(*u, v.len() as GLsizei, v.as_ptr() as *const i32) } 170 | } 171 | 172 | fn update_textures(u: &Self::U, textures: &[&Self::ATexture]) { 173 | for (tex_unit, texture) in textures.iter().enumerate() { 174 | unsafe { 175 | gl::ActiveTexture(gl::TEXTURE0 + tex_unit as GLenum); 176 | gl::BindTexture(texture.target, texture.handle); 177 | gl::Uniform1i(*u, tex_unit as GLint); 178 | } 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/gl33/tess.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use luminance::tess::{self, HasTess, Mode}; 4 | use luminance::vertex::{Dim, Type, Vertex, VertexComponentFormat, VertexFormat}; 5 | use std::mem; 6 | use std::ptr; 7 | 8 | use gl33::buffer::{Buffer, GLBuffer}; 9 | use gl33::token::GL33; 10 | 11 | pub type Tess = tess::Tess; 12 | 13 | pub struct GLTess { 14 | // closure taking the point / line size and the number of instances to render 15 | pub render: Box, u32)>, 16 | vao: GLenum, 17 | vbo: Option, 18 | ibo: Option, 19 | vertex_format: VertexFormat, 20 | vert_nb: usize 21 | } 22 | 23 | impl HasTess for GL33 { 24 | type Tess = GLTess; 25 | 26 | fn new_tess(mode: Mode, vertices: &[T], indices: Option<&[u32]>) -> Self::Tess where T: Vertex { 27 | let mut vao: GLuint = 0; 28 | let vert_nb = vertices.len(); 29 | 30 | unsafe { 31 | gl::GenVertexArrays(1, &mut vao); 32 | 33 | gl::BindVertexArray(vao); 34 | 35 | // vertex buffer 36 | let vertex_buffer = Buffer::new(vert_nb); 37 | vertex_buffer.fill(vertices); 38 | 39 | // once the vertex buffer is filled, we get its internal representation and we leak it so that 40 | // it’s not dropped at the end of the scope 41 | let vbo = vertex_buffer.repr.clone(); 42 | mem::forget(vertex_buffer); 43 | 44 | gl::BindBuffer(gl::ARRAY_BUFFER, vbo.handle); 45 | set_vertex_pointers(&T::vertex_format()); 46 | 47 | // in case of indexed render, create the required objects 48 | if let Some(indices) = indices { 49 | let ind_nb = indices.len(); 50 | let index_buffer = Buffer::new(ind_nb); 51 | index_buffer.fill(indices); 52 | 53 | // same than vertex buffer, once the index buffer is filled, we leak it to the void 54 | let ibo = index_buffer.repr.clone(); 55 | mem::forget(index_buffer); 56 | 57 | gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ibo.handle); 58 | 59 | gl::BindVertexArray(0); 60 | 61 | GLTess { 62 | render: Box::new(move |size, instances| { 63 | gl::BindVertexArray(vao); 64 | 65 | set_point_line_size(mode, size); 66 | 67 | if instances == 1 { 68 | gl::DrawElements(opengl_mode(mode), ind_nb as GLsizei, gl::UNSIGNED_INT, ptr::null()); 69 | } else if instances > 1 { 70 | gl::DrawElementsInstanced(opengl_mode(mode), ind_nb as GLsizei, gl::UNSIGNED_INT, ptr::null(), instances as GLsizei); 71 | } else { 72 | panic!("cannot index-render 0 instance"); 73 | } 74 | }), 75 | vao: vao, 76 | vbo: Some(vbo), 77 | ibo: Some(ibo), 78 | vertex_format: T::vertex_format(), 79 | vert_nb: vert_nb 80 | } 81 | } else { 82 | gl::BindVertexArray(0); 83 | 84 | GLTess { 85 | render: Box::new(move |size, instances| { 86 | gl::BindVertexArray(vao); 87 | 88 | set_point_line_size(mode, size); 89 | 90 | if instances == 1 { 91 | gl::DrawArrays(opengl_mode(mode), 0, vert_nb as GLsizei); 92 | } else if instances > 1 { 93 | gl::DrawArraysInstanced(opengl_mode(mode), 0, vert_nb as GLsizei, instances as GLsizei); 94 | } else { 95 | panic!("cannot render 0 instance"); 96 | } 97 | }), 98 | vao: vao, 99 | vbo: Some(vbo), 100 | ibo: None, 101 | vertex_format: T::vertex_format(), 102 | vert_nb: vert_nb 103 | } 104 | } 105 | } 106 | } 107 | 108 | fn destroy_tess(tess: &mut Self::Tess) { 109 | // delete vertex array and all bound buffers 110 | unsafe { 111 | gl::DeleteVertexArrays(1, &tess.vao); 112 | 113 | if let &Some(ref vbo) = &tess.vbo { 114 | gl::DeleteBuffers(1, &vbo.handle); 115 | } 116 | 117 | if let &Some(ref ibo) = &tess.ibo { 118 | gl::DeleteBuffers(1, &ibo.handle); 119 | } 120 | } 121 | } 122 | 123 | fn attributeless(mode: Mode, vert_nb: usize) -> Self::Tess { 124 | let mut vao = 0; 125 | 126 | unsafe { 127 | gl::GenVertexArrays(1, &mut vao); 128 | 129 | gl::BindVertexArray(vao); 130 | gl::BindVertexArray(0); 131 | 132 | GLTess { 133 | render: Box::new(move |size, instances| { 134 | gl::BindVertexArray(vao); 135 | 136 | set_point_line_size(mode, size); 137 | 138 | if instances == 1 { 139 | gl::DrawArrays(opengl_mode(mode), 0, vert_nb as GLsizei); 140 | } else if instances > 1 { 141 | gl::DrawArraysInstanced(opengl_mode(mode), 0, vert_nb as GLsizei, instances as GLsizei); 142 | } else { 143 | panic!("cannot render 0 instance"); 144 | } 145 | }), 146 | vao: vao, 147 | vbo: None, 148 | ibo: None, 149 | vertex_format: Vec::new(), 150 | vert_nb: vert_nb 151 | } 152 | } 153 | } 154 | 155 | fn vertex_format(tesse: &Self::Tess) -> &VertexFormat { 156 | &tesse.vertex_format 157 | } 158 | 159 | fn get_vertex_buffer_ref_mut(tess: &mut Self::Tess) -> Option<(&mut Self::ABuffer, usize)> { 160 | let vert_nb = tess.vert_nb; 161 | tess.vbo.as_mut().map(|vbo| (vbo, vert_nb)) 162 | } 163 | } 164 | 165 | // Give OpenGL types information on the content of the VBO by setting vertex formats and pointers 166 | // to buffer memory. 167 | fn set_vertex_pointers(formats: &[VertexComponentFormat]) { 168 | let offsets = aligned_offsets(formats); 169 | let vertex_weight = offset_based_vertex_weight(formats, &offsets) as GLsizei; 170 | 171 | for (i, (format, off)) in formats.iter().zip(offsets).enumerate() { 172 | set_component_format(i as u32, vertex_weight, off, format); 173 | } 174 | } 175 | 176 | fn set_component_format(i: u32, stride: GLsizei, off: usize, f: &VertexComponentFormat) { 177 | match f.comp_type { 178 | Type::Floating => { 179 | unsafe { 180 | gl::VertexAttribPointer(i as GLuint, dim_as_size(&f.dim), opengl_sized_type(&f), gl::FALSE, stride, ptr::null::().offset(off as isize)); 181 | } 182 | }, 183 | Type::Integral | Type::Unsigned | Type::Boolean => { 184 | unsafe { 185 | gl::VertexAttribIPointer(i as GLuint, dim_as_size(&f.dim), opengl_sized_type(&f), stride, ptr::null::().offset(off as isize)); 186 | } 187 | } 188 | } 189 | 190 | unsafe { 191 | gl::EnableVertexAttribArray(i as GLuint); 192 | } 193 | } 194 | 195 | fn dim_as_size(d: &Dim) -> GLint { 196 | match *d { 197 | Dim::Dim1 => 1, 198 | Dim::Dim2 => 2, 199 | Dim::Dim3 => 3, 200 | Dim::Dim4 => 4 201 | } 202 | } 203 | 204 | fn opengl_sized_type(f: &VertexComponentFormat) -> GLenum { 205 | match (f.comp_type, f.unit_size) { 206 | (Type::Integral, 1) => gl::BYTE, 207 | (Type::Integral, 2) => gl::SHORT, 208 | (Type::Integral, 4) => gl::INT, 209 | (Type::Unsigned, 1) | (Type::Boolean, 1) => gl::UNSIGNED_BYTE, 210 | (Type::Unsigned, 2) => gl::UNSIGNED_SHORT, 211 | (Type::Unsigned, 4) => gl::UNSIGNED_INT, 212 | (Type::Floating, 4) => gl::FLOAT, 213 | _ => panic!("unsupported vertex component format: {:?}", f) 214 | } 215 | } 216 | 217 | // Compute offsets for all the vertex components according to the alignments provided. 218 | fn aligned_offsets(formats: &[VertexComponentFormat]) -> Vec { 219 | let mut offsets = Vec::with_capacity(formats.len()); 220 | let mut off = 0; 221 | 222 | // compute offsets 223 | for f in formats { 224 | off = off_align(off, f.align); // keep the current component format aligned 225 | offsets.push(off); 226 | off += component_weight(f); // increment the offset by the pratical size of the component 227 | } 228 | 229 | offsets 230 | } 231 | 232 | // Weight in bytes of a single vertex, taking into account padding so that the vertex stay correctly 233 | // aligned. 234 | fn offset_based_vertex_weight(formats: &[VertexComponentFormat], offsets: &[usize]) -> usize { 235 | if formats.is_empty() || offsets.is_empty() { 236 | return 0; 237 | } 238 | 239 | off_align(offsets[offsets.len() - 1] + component_weight(&formats[formats.len() - 1]), formats[0].align) 240 | } 241 | 242 | // Weight in bytes of a vertex component. 243 | fn component_weight(f: &VertexComponentFormat) -> usize { 244 | dim_as_size(&f.dim) as usize * f.unit_size 245 | } 246 | 247 | fn opengl_mode(mode: Mode) -> GLenum { 248 | match mode { 249 | Mode::Point => gl::POINTS, 250 | Mode::Line => gl::LINES, 251 | Mode::LineStrip => gl::LINE_STRIP, 252 | Mode::Triangle => gl::TRIANGLES, 253 | Mode::TriangleFan => gl::TRIANGLE_FAN, 254 | Mode::TriangleStrip => gl::TRIANGLE_STRIP 255 | } 256 | } 257 | 258 | fn set_point_line_size(mode: Mode, size: Option) { 259 | let computed = size.unwrap_or(1.); 260 | 261 | match mode { 262 | Mode::Point => unsafe { gl::PointSize(computed) }, 263 | Mode::Line | Mode::LineStrip => unsafe { gl::LineWidth(computed) }, 264 | _ => {} 265 | } 266 | } 267 | 268 | // Align an offset. 269 | #[inline] 270 | fn off_align(off: usize, align: usize) -> usize { 271 | let a = align - 1; 272 | (off + a) & !a 273 | } 274 | -------------------------------------------------------------------------------- /src/gl33/tessellation.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use gl33::buffer::Buffer; 4 | use gl33::token::GL33; 5 | use luminance::tessellation::{self, HasTessellation, Mode}; 6 | use luminance::vertex::{Dim, Type, Vertex, VertexComponentFormat}; 7 | use std::mem; 8 | use std::ptr; 9 | 10 | pub type Tessellation = tessellation::Tessellation; 11 | 12 | pub struct GLTess { 13 | // closure taking the point / line size and the number of instances to render 14 | pub render: Box, u32)>, 15 | vao: GLenum, 16 | buffers: Vec 17 | } 18 | 19 | impl HasTessellation for GL33 { 20 | type Tessellation = GLTess; 21 | 22 | fn new(mode: Mode, vertices: &[T], indices: Option<&[u32]>) -> Self::Tessellation where T: Vertex { 23 | let mut vao: GLuint = 0; 24 | let vert_nb = vertices.len(); 25 | 26 | unsafe { 27 | gl::GenVertexArrays(1, &mut vao); 28 | 29 | gl::BindVertexArray(vao); 30 | 31 | // vertex buffer 32 | let vertex_buffer = Buffer::new(vert_nb); 33 | vertex_buffer.fill(vertices); 34 | 35 | // once the vertex buffer is filled, we get its internal representation’s handle and we leak 36 | // it so that it’s not dropped at the end of the scope 37 | let vbo = vertex_buffer.repr.handle; 38 | mem::forget(vertex_buffer); 39 | 40 | gl::BindBuffer(gl::ARRAY_BUFFER, vbo); 41 | set_vertex_pointers(&T::vertex_format()); 42 | 43 | // in case of indexed render, create the required objects 44 | if let Some(indices) = indices { 45 | let ind_nb = indices.len(); 46 | let index_buffer = Buffer::new(ind_nb); 47 | index_buffer.fill(indices); 48 | 49 | // same than vertex buffer, once the index buffer is filled, we leak it to the void 50 | let ibo = index_buffer.repr.handle; 51 | mem::forget(index_buffer); 52 | 53 | gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ibo); 54 | 55 | gl::BindVertexArray(0); 56 | 57 | GLTess { 58 | render: Box::new(move |size, instances| { 59 | gl::BindVertexArray(vao); 60 | 61 | set_point_line_size(mode, size); 62 | 63 | if instances == 1 { 64 | gl::DrawElements(from_mode(mode), ind_nb as GLsizei, gl::UNSIGNED_INT, ptr::null()); 65 | } else if instances > 1 { 66 | gl::DrawElementsInstanced(from_mode(mode), ind_nb as GLsizei, gl::UNSIGNED_INT, ptr::null(), instances as GLsizei); 67 | } else { 68 | panic!("cannot index-render 0 instance"); 69 | } 70 | }), 71 | vao: vao, 72 | buffers: vec![vbo, ibo] 73 | } 74 | } else { 75 | gl::BindVertexArray(0); 76 | 77 | GLTess { 78 | render: Box::new(move |size, instances| { 79 | gl::BindVertexArray(vao); 80 | 81 | set_point_line_size(mode, size); 82 | 83 | if instances == 1 { 84 | gl::DrawArrays(from_mode(mode), 0, vert_nb as GLsizei); 85 | } else if instances > 1 { 86 | gl::DrawArraysInstanced(from_mode(mode), 0, vert_nb as GLsizei, instances as GLsizei); 87 | } else { 88 | panic!("cannot render 0 instance"); 89 | } 90 | }), 91 | vao: vao, 92 | buffers: vec![vbo] 93 | } 94 | } 95 | } 96 | } 97 | 98 | fn destroy(tessellation: &mut Self::Tessellation) { 99 | // delete vertex array and all bound buffers 100 | unsafe { 101 | gl::DeleteVertexArrays(1, &tessellation.vao); 102 | gl::DeleteBuffers(tessellation.buffers.len() as GLsizei, tessellation.buffers.as_ptr()); 103 | } 104 | } 105 | } 106 | 107 | fn set_vertex_pointers(formats: &[VertexComponentFormat]) { 108 | let vertex_weight = vertex_weight(formats) as GLsizei; 109 | let mut offset = 0; 110 | 111 | for (i, format) in formats.iter().enumerate() { 112 | set_component_format(i as u32, vertex_weight, offset, format); 113 | offset += component_weight(format) as u32; 114 | } 115 | } 116 | 117 | fn set_component_format(i: u32, stride: GLsizei, off: u32, cf: &VertexComponentFormat) { 118 | unsafe { 119 | gl::VertexAttribPointer(i as GLuint, from_dim(&cf.dim), from_type(&cf.component_type), gl::FALSE, stride, ptr::null().offset(off as isize)); 120 | gl::EnableVertexAttribArray(i as GLuint); 121 | } 122 | } 123 | 124 | fn from_dim(d: &Dim) -> GLint { 125 | match *d { 126 | Dim::Dim1 => 1, 127 | Dim::Dim2 => 2, 128 | Dim::Dim3 => 3, 129 | Dim::Dim4 => 4 130 | } 131 | } 132 | 133 | fn from_type(t: &Type) -> GLenum { 134 | match *t { 135 | Type::Integral | Type::Boolean => gl::INT, 136 | Type::Unsigned => gl::UNSIGNED_INT, 137 | Type::Floating => gl::FLOAT, 138 | } 139 | } 140 | 141 | fn vertex_weight(formats: &[VertexComponentFormat]) -> usize { 142 | formats.iter().fold(0, |a, f| a + component_weight(f)) 143 | } 144 | 145 | fn component_weight(f: &VertexComponentFormat) -> usize { 146 | from_dim(&f.dim) as usize * component_type_weight(&f.component_type) 147 | } 148 | 149 | fn component_type_weight(t: &Type) -> usize { 150 | match *t { 151 | Type::Integral => mem::size_of::(), 152 | Type::Unsigned => mem::size_of::(), 153 | Type::Floating => mem::size_of::(), 154 | Type::Boolean => mem::size_of::() 155 | } 156 | } 157 | 158 | fn from_mode(mode: Mode) -> GLenum { 159 | match mode { 160 | Mode::Point => gl::POINTS, 161 | Mode::Line => gl::LINES, 162 | Mode::LineStrip => gl::LINE_STRIP, 163 | Mode::Triangle => gl::TRIANGLES, 164 | Mode::TriangleFan => gl::TRIANGLE_FAN, 165 | Mode::TriangleStrip => gl::TRIANGLE_STRIP 166 | } 167 | } 168 | 169 | fn set_point_line_size(mode: Mode, size: Option) { 170 | let computed = size.unwrap_or(1.); 171 | 172 | match mode { 173 | Mode::Point => unsafe { gl::PointSize(computed) }, 174 | Mode::Line | Mode::LineStrip => unsafe { gl::LineWidth(computed) }, 175 | _ => {} 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/gl33/texture.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use gl33::token::GL33; 4 | use luminance::texture::{self, DepthComparison, Dim, Dimensionable, Filter, HasTexture, Layerable, 5 | Layering, Result, Sampler, TextureError, Wrap, dim_capacity}; 6 | use luminance::pixel::{Pixel, PixelFormat}; 7 | use pixel::{gl_pixel_format, pixel_components}; 8 | use std::mem; 9 | use std::os::raw::c_void; 10 | use std::ptr; 11 | 12 | pub type Texture = texture::Texture; 13 | 14 | // OpenGL texture representation. 15 | pub struct GLTexture { 16 | pub handle: GLuint, // handle to GPU texture object 17 | pub target: GLenum // « type » of the texture; used for bindings 18 | } 19 | 20 | impl GLTexture { 21 | pub fn new(handle: GLuint, target: GLenum) -> Self { 22 | GLTexture { 23 | handle: handle, 24 | target: target 25 | } 26 | } 27 | } 28 | 29 | impl HasTexture for GL33 { 30 | type ATexture = GLTexture; 31 | 32 | fn new_texture(size: D::Size, mipmaps: usize, sampler: &Sampler) -> Result 33 | where L: Layerable, 34 | D: Dimensionable, 35 | D::Size: Copy, 36 | P: Pixel { 37 | let mut texture = 0; 38 | let target = to_target(L::layering(), D::dim()); 39 | 40 | unsafe { 41 | gl::GenTextures(1, &mut texture); 42 | gl::BindTexture(target, texture); 43 | } 44 | 45 | create_texture::(target, size, mipmaps, P::pixel_format(), sampler)?; 46 | 47 | // FIXME: maybe we can get rid of this 48 | unsafe { 49 | gl::BindTexture(target, 0); 50 | } 51 | 52 | Ok(GLTexture::new(texture, target)) 53 | } 54 | 55 | fn free(texture: &mut Self::ATexture) { 56 | unsafe { gl::DeleteTextures(1, &texture.handle) } 57 | } 58 | 59 | fn clear_part(texture: &Self::ATexture, gen_mipmaps: bool, off: D::Offset, size: D::Size, pixel: P::Encoding) 60 | where L: Layerable, D: Dimensionable, D::Offset: Copy, D::Size: Copy, P: Pixel, P::Encoding: Copy { 61 | Self::upload_part::(texture, gen_mipmaps, off, size, &vec![pixel; dim_capacity::(size) as usize]) 62 | } 63 | 64 | fn upload_part(texture: &Self::ATexture, gen_mipmaps: bool, off: D::Offset, size: D::Size, texels: &[P::Encoding]) 65 | where L: Layerable, D::Offset: Copy, D::Size: Copy, D: Dimensionable, P: Pixel { 66 | unsafe { 67 | gl::BindTexture(texture.target, texture.handle); 68 | 69 | upload_texels::(texture.target, off, size, texels); 70 | 71 | if gen_mipmaps { 72 | gl::GenerateMipmap(texture.target); 73 | } 74 | 75 | gl::BindTexture(texture.target, 0); 76 | } 77 | } 78 | 79 | fn upload_part_raw(texture: &Self::ATexture, gen_mipmaps: bool, off: D::Offset, size: D::Size, texels: &[P::RawEncoding]) 80 | where L: Layerable, D::Offset: Copy, D::Size: Copy, D: Dimensionable, P: Pixel { 81 | unsafe { 82 | gl::BindTexture(texture.target, texture.handle); 83 | 84 | upload_texels::(texture.target, off, size, texels); 85 | 86 | if gen_mipmaps { 87 | gl::GenerateMipmap(texture.target); 88 | } 89 | 90 | gl::BindTexture(texture.target, 0); 91 | } 92 | } 93 | 94 | // FIXME: cubemaps? 95 | fn get_raw_texels

(texture: &Self::ATexture) -> Vec where P: Pixel, P::RawEncoding: Copy { 96 | let mut texels = Vec::new(); 97 | let pf = P::pixel_format(); 98 | let (format, _, ty) = gl_pixel_format(pf).unwrap(); 99 | 100 | unsafe { 101 | let mut w = 0; 102 | let mut h = 0; 103 | 104 | gl::BindTexture(texture.target, texture.handle); 105 | 106 | // retrieve the size of the texture (w and h) 107 | gl::GetTexLevelParameteriv(texture.target, 0, gl::TEXTURE_WIDTH, &mut w); 108 | gl::GetTexLevelParameteriv(texture.target, 0, gl::TEXTURE_HEIGHT, &mut h); 109 | 110 | // resize the vec to allocate enough space to host the returned texels 111 | texels.resize((w * h) as usize * pixel_components(pf), mem::uninitialized()); 112 | 113 | gl::GetTexImage(texture.target, 0, format, ty, texels.as_mut_ptr() as *mut c_void); 114 | 115 | gl::BindTexture(texture.target, 0); 116 | } 117 | 118 | texels 119 | } 120 | } 121 | 122 | pub fn create_texture(target: GLenum, size: D::Size, mipmaps: usize, pf: PixelFormat, sampler: &Sampler) -> Result<()> 123 | where L: Layerable, 124 | D: Dimensionable, 125 | D::Size: Copy { 126 | set_texture_levels(target, mipmaps); 127 | 128 | apply_sampler_to_texture(target, sampler); 129 | 130 | create_texture_storage::(size, mipmaps, pf) 131 | } 132 | 133 | pub fn to_target(l: Layering, d: Dim) -> GLenum { 134 | match l { 135 | Layering::Flat => match d { 136 | Dim::Dim1 => gl::TEXTURE_1D, 137 | Dim::Dim2 => gl::TEXTURE_2D, 138 | Dim::Dim3 => gl::TEXTURE_3D, 139 | Dim::Cubemap => gl::TEXTURE_CUBE_MAP 140 | }, 141 | Layering::Layered => match d { 142 | Dim::Dim1 => gl::TEXTURE_1D_ARRAY, 143 | Dim::Dim2 => gl::TEXTURE_2D_ARRAY, 144 | Dim::Dim3 => panic!("3D textures array not supported"), 145 | Dim::Cubemap => gl::TEXTURE_CUBE_MAP_ARRAY 146 | } 147 | } 148 | } 149 | 150 | fn create_texture_storage(size: D::Size, mipmaps: usize, pf: PixelFormat) -> Result<()> 151 | where L: Layerable, 152 | D: Dimensionable, 153 | D::Size: Copy { 154 | match gl_pixel_format(pf) { 155 | Some(glf) => { 156 | let (format, iformat, encoding) = glf; 157 | 158 | match (L::layering(), D::dim()) { 159 | // 1D texture 160 | (Layering::Flat, Dim::Dim1) => { 161 | create_texture_1d_storage(format, iformat, encoding, D::width(size), mipmaps); 162 | Ok(()) 163 | }, 164 | // 2D texture 165 | (Layering::Flat, Dim::Dim2) => { 166 | create_texture_2d_storage(format, iformat, encoding, D::width(size), D::height(size), mipmaps); 167 | Ok(()) 168 | }, 169 | // 3D texture 170 | (Layering::Flat, Dim::Dim3) => { 171 | create_texture_3d_storage(format, iformat, encoding, D::width(size), D::height(size), D::depth(size), mipmaps); 172 | Ok(()) 173 | }, 174 | // cubemap 175 | (Layering::Flat, Dim::Cubemap) => { 176 | create_cubemap_storage(format, iformat, encoding, D::width(size), mipmaps); 177 | Ok(()) 178 | }, 179 | _ => Err(TextureError::TextureStorageCreationFailed(format!("unsupported texture OpenGL pixel format: {:?}", glf))) 180 | } 181 | }, 182 | None => Err(TextureError::TextureStorageCreationFailed(format!("unsupported texture pixel format: {:?}", pf))) 183 | } 184 | } 185 | 186 | fn create_texture_1d_storage(format: GLenum, iformat: GLenum, encoding: GLenum, w: u32, mipmaps: usize) { 187 | for level in 0..mipmaps { 188 | let w = w / 2u32.pow(level as u32); 189 | 190 | unsafe { gl::TexImage1D(gl::TEXTURE_1D, level as GLint, iformat as GLint, w as GLsizei, 0, format, encoding, ptr::null()) }; 191 | } 192 | } 193 | 194 | fn create_texture_2d_storage(format: GLenum, iformat: GLenum, encoding: GLenum, w: u32, h: u32, mipmaps: usize) { 195 | for level in 0..mipmaps { 196 | let div = 2u32.pow(level as u32); 197 | let w = w / div; 198 | let h = h / div; 199 | 200 | unsafe { gl::TexImage2D(gl::TEXTURE_2D, level as GLint, iformat as GLint, w as GLsizei, h as GLsizei, 0, format, encoding, ptr::null()) }; 201 | } 202 | } 203 | 204 | fn create_texture_3d_storage(format: GLenum, iformat: GLenum, encoding: GLenum, w: u32, h: u32, d: u32, mipmaps: usize) { 205 | for level in 0..mipmaps { 206 | let div = 2u32.pow(level as u32); 207 | let w = w / div; 208 | let h = h / div; 209 | let d = d / div; 210 | 211 | unsafe { gl::TexImage3D(gl::TEXTURE_3D, level as GLint, iformat as GLint, w as GLsizei, h as GLsizei, d as GLsizei, 0, format, encoding, ptr::null()) }; 212 | } 213 | } 214 | 215 | fn create_cubemap_storage(format: GLenum, iformat: GLenum, encoding: GLenum, s: u32, mipmaps: usize) { 216 | for level in 0..mipmaps { 217 | let s = s / 2u32.pow(level as u32); 218 | 219 | unsafe { gl::TexImage2D(gl::TEXTURE_CUBE_MAP, level as GLint, iformat as GLint, s as GLsizei, s as GLsizei, 0, format, encoding, ptr::null()) }; 220 | } 221 | } 222 | 223 | fn set_texture_levels(target: GLenum, mipmaps: usize) { 224 | unsafe { 225 | gl::TexParameteri(target, gl::TEXTURE_BASE_LEVEL, 0); 226 | gl::TexParameteri(target, gl::TEXTURE_MAX_LEVEL, mipmaps as GLint - 1); 227 | } 228 | } 229 | 230 | fn apply_sampler_to_texture(target: GLenum, sampler: &Sampler) { 231 | unsafe { 232 | gl::TexParameteri(target, gl::TEXTURE_WRAP_R, from_wrap(sampler.wrap_r) as GLint); 233 | gl::TexParameteri(target, gl::TEXTURE_WRAP_S, from_wrap(sampler.wrap_s) as GLint); 234 | gl::TexParameteri(target, gl::TEXTURE_WRAP_T, from_wrap(sampler.wrap_t) as GLint); 235 | gl::TexParameteri(target, gl::TEXTURE_MIN_FILTER, from_filter(sampler.minification) as GLint); 236 | gl::TexParameteri(target, gl::TEXTURE_MAG_FILTER, from_filter(sampler.minification) as GLint); 237 | match sampler.depth_comparison { 238 | Some(fun) => { 239 | gl::TexParameteri(target, gl::TEXTURE_COMPARE_FUNC, from_depth_comparison(fun) as GLint); 240 | gl::TexParameteri(target, gl::TEXTURE_COMPARE_MODE, gl::COMPARE_REF_TO_TEXTURE as GLint); 241 | }, 242 | None => { 243 | gl::TexParameteri(target, gl::TEXTURE_COMPARE_MODE, gl::NONE as GLint); 244 | } 245 | } 246 | } 247 | } 248 | 249 | fn from_wrap(wrap: Wrap) -> GLenum { 250 | match wrap { 251 | Wrap::ClampToEdge => gl::CLAMP_TO_EDGE, 252 | Wrap::Repeat => gl::REPEAT, 253 | Wrap::MirroredRepeat => gl::MIRRORED_REPEAT 254 | } 255 | } 256 | 257 | fn from_filter(filter: Filter) -> GLenum { 258 | match filter { 259 | Filter::Nearest => gl::NEAREST, 260 | Filter::Linear => gl::LINEAR 261 | } 262 | } 263 | 264 | fn from_depth_comparison(fun: DepthComparison) -> GLenum { 265 | match fun { 266 | DepthComparison::Never => gl::NEVER, 267 | DepthComparison::Always => gl::ALWAYS, 268 | DepthComparison::Equal => gl::EQUAL, 269 | DepthComparison::NotEqual => gl::NOTEQUAL, 270 | DepthComparison::Less => gl::LESS, 271 | DepthComparison::LessOrEqual => gl::LEQUAL, 272 | DepthComparison::Greater => gl::GREATER, 273 | DepthComparison::GreaterOrEqual => gl::GEQUAL 274 | } 275 | } 276 | 277 | // Upload texels into the texture’s memory. Becareful of the type of texels you send down. 278 | fn upload_texels(target: GLenum, off: D::Offset, size: D::Size, texels: &[T]) 279 | where L: Layerable, 280 | D: Dimensionable, 281 | D::Offset: Copy, 282 | D::Size: Copy, 283 | P: Pixel { 284 | let pf = P::pixel_format(); 285 | 286 | match gl_pixel_format(pf) { 287 | Some((format, _, encoding)) => { 288 | match L::layering() { 289 | Layering::Flat => { 290 | match D::dim() { 291 | Dim::Dim1 => unsafe { gl::TexSubImage1D(target, 0, D::x_offset(off) as GLint, D::width(size) as GLsizei, format, encoding, texels.as_ptr() as *const c_void) }, 292 | Dim::Dim2 => unsafe { gl::TexSubImage2D(target, 0, D::x_offset(off) as GLint, D::y_offset(off) as GLint, D::width(size) as GLsizei, D::height(size) as GLsizei, format, encoding, texels.as_ptr() as *const c_void) }, 293 | Dim::Dim3 => unsafe { gl::TexSubImage3D(target, 0, D::x_offset(off) as GLint, D::y_offset(off) as GLint, D::z_offset(off) as GLint, D::width(size) as GLsizei, D::height(size) as GLsizei, D::depth(size) as GLsizei, format, encoding, texels.as_ptr() as *const c_void) }, 294 | Dim::Cubemap => unsafe { gl::TexSubImage3D(target, 0, D::x_offset(off) as GLint, D::y_offset(off) as GLint, (gl::TEXTURE_CUBE_MAP_POSITIVE_X + D::z_offset(off)) as GLint, D::width(size) as GLsizei, D::width(size) as GLsizei, 1, format, encoding, texels.as_ptr() as *const c_void) } 295 | } 296 | }, 297 | Layering::Layered => panic!("Layering::Layered not implemented yet") 298 | } 299 | }, 300 | None => panic!("unknown pixel format") 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /src/gl33/token.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct GL33; 3 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deprecated( 2 | since = "0.13.1", 3 | note = "Please use [luminance](https://crates.io/crates/luminance) directly." 4 | )] 5 | 6 | extern crate gl; 7 | extern crate luminance; 8 | 9 | pub mod error; 10 | mod pixel; 11 | 12 | #[cfg(not(any(feature = "gl33")))] 13 | const COMPILE_ERROR: () = "No backend selected; please select one (gl33)."; 14 | 15 | #[cfg(feature = "gl33")] 16 | pub mod gl33; 17 | -------------------------------------------------------------------------------- /src/pixel.rs: -------------------------------------------------------------------------------- 1 | use gl; 2 | use gl::types::*; 3 | use luminance::pixel::{Format, PixelFormat, Type}; 4 | 5 | // Return the format, internal sized-format and type. 6 | pub fn gl_pixel_format(pf: PixelFormat) -> Option<(GLenum, GLenum, GLenum)> { 7 | match (pf.format, pf.encoding) { 8 | (Format::RGB(8, 8, 8), Type::Unsigned) => Some((gl::RGB_INTEGER, gl::RGB8UI, gl::UNSIGNED_BYTE)), 9 | (Format::RGBA(8, 8, 8, 8), Type::Unsigned) => Some((gl::RGBA_INTEGER, gl::RGBA8UI, gl::UNSIGNED_BYTE)), 10 | (Format::RGB(32, 32, 32), Type::Floating) => Some((gl::RGB, gl::RGB32F, gl::FLOAT)), 11 | (Format::RGBA(32, 32, 32, 32), Type::Floating) => Some((gl::RGBA, gl::RGBA32F, gl::FLOAT)), 12 | (Format::Depth(32), Type::Floating) => Some((gl::DEPTH_COMPONENT, gl::DEPTH_COMPONENT32F, gl::FLOAT)), 13 | _ => panic!("unsupported pixel format") 14 | } 15 | } 16 | 17 | // Return the number of components. 18 | pub fn pixel_components(pf: PixelFormat) -> usize { 19 | match pf.format { 20 | Format::RGB(_, _, _) => 3, 21 | Format::RGBA(_, _, _, _) => 4, 22 | Format::Depth(_) => 1, 23 | _ => panic!("unsupported pixel format") 24 | } 25 | } 26 | --------------------------------------------------------------------------------