| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- use glutin::GlContext;
- use glutin;
- use program::ProgramId;
- use std::ffi::CStr;
- use std::mem;
-
- pub(crate) mod gl {
- #![allow(unknown_lints)]
- #![allow(clippy)]
- pub use self::Gles2 as Gl;
- include!(concat!(env!("OUT_DIR"), "/gles_bindings.rs"));
- }
-
- #[derive(Clone, Copy, Debug, Eq, PartialEq)]
- pub struct TextureUnit(u32);
-
- impl TextureUnit {
- pub fn index(&self) -> u32 {
- self.0
- }
- }
-
- #[derive(Clone)]
- pub struct Context {
- pub(crate) gl: gl::Gl,
- active_texture_unit: TextureUnit,
- next_free_texture_unit: TextureUnit,
- active_program: ProgramId,
- }
-
- impl ::std::fmt::Debug for Context {
- fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
- let version = unsafe {
- let data = CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
- String::from_utf8(data).unwrap_or_else(|_| "".into())
- };
- write!(f, "Context {{ version: {:?} }}", version)
- }
- }
-
- macro_rules! check_gl_errors {
- ($cx:expr) => (
- $cx.check_errors(file!(), line!());
- )
- }
-
- impl Context {
- pub fn from_gl_window(window: &glutin::GlWindow) -> Context {
- let gl = gl::Gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
- let cx = Context {
- gl,
- /// Initial active texture unit is supposed to be GL_TEXTURE0
- active_texture_unit: TextureUnit(0),
- next_free_texture_unit: TextureUnit(0),
- active_program: ProgramId::invalid(),
- };
-
- // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
- // not OpenGL ES 2.0 compatible, but are required for rendering with a core context.
- if cx.gl.BindVertexArray.is_loaded() {
- unsafe {
- let mut vao = mem::uninitialized();
- cx.gl.GenVertexArrays(1, &mut vao);
- cx.gl.BindVertexArray(vao);
- }
- }
-
- info!("OpenGL version: {}", cx.gl_version());
- debug!("MAX_TEXTURE_SIZE: {}", cx.max_texture_size());
-
- cx
- }
-
- pub fn gl_version(&self) -> String {
- unsafe {
- let data = CStr::from_ptr(self.gl.GetString(gl::VERSION) as *const _).to_bytes().to_vec();
- String::from_utf8(data).unwrap_or_else(|_| "".into())
- }
- }
-
- pub fn max_texture_size(&self) -> i32 {
- unsafe {
- let mut size = 0;
- self.gl.GetIntegerv(gl::MAX_TEXTURE_SIZE, &mut size as *mut _);
- size
- }
- }
-
- pub fn check_errors(&self, file: &str, line: u32) {
- let mut fail = false;
-
- loop {
- match unsafe { self.gl.GetError() } {
- gl::NO_ERROR => break,
- gl::INVALID_VALUE => {
- error!("{}:{}, invalid value error", file, line);
- fail = true;
- },
- gl::INVALID_ENUM => {
- error!("{}:{}, invalid enum error", file, line);
- fail = true;
- },
- gl::INVALID_OPERATION => {
- error!("{}:{}, invalid operation error", file, line);
- fail = true;
- },
- gl::INVALID_FRAMEBUFFER_OPERATION => {
- error!("{}:{}, invalid framebuffer operation error", file, line);
- fail = true;
- },
- gl::OUT_OF_MEMORY => {
- error!("{}:{}, out of memory error", file, line);
- fail = true;
- },
- x => {
- error!("{}:{}, unknown error {}", file, line, x);
- fail = true;
- },
- }
- }
-
- if fail {
- panic!("OpenGL error");
- }
- }
-
- pub fn clear_color(&self, color: (f32, f32, f32, f32)) {
- unsafe {
- self.gl.ClearColor(color.0, color.1, color.2, color.3);
- self.gl.Clear(gl::COLOR_BUFFER_BIT);
- }
- }
-
- pub fn set_viewport(&self, x: i32, y: i32, width: u32, height: u32) {
- unsafe {
- self.gl.Viewport(
- x,
- y,
- width as gl::types::GLsizei,
- height as gl::types::GLsizei,
- );
- }
- }
-
- pub fn set_active_texture_unit(&mut self, unit: TextureUnit) {
- if unit != self.active_texture_unit {
- unsafe {
- self.gl.ActiveTexture(gl::TEXTURE0 + unit.0);
- }
- self.active_texture_unit = unit;
- }
- }
-
- pub fn occupy_free_texture_unit(&mut self) -> TextureUnit {
- let tu = self.next_free_texture_unit;
-
- //TODO check against max number of texture units
- //TODO add a way to free texture units
- self.next_free_texture_unit = TextureUnit(self.next_free_texture_unit.0 + 1);
-
- tu
- }
-
- pub fn use_program(&mut self, prog: ProgramId) {
- if prog != self.active_program {
- unsafe {
- self.gl.UseProgram(prog.index());
- }
- self.active_program = prog;
- }
- }
- }
|