├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── assets ├── FiraSans-Regular.ttf ├── rust-white.png └── rust.png ├── examples ├── colored_image_test.rs ├── draw_state.rs ├── image_test.rs ├── text_test.rs └── texture_wrap.rs └── src ├── back_end.rs ├── draw_state.rs ├── glium_texture.rs ├── lib.rs └── window.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | before_install: 3 | - wget https://www.libsdl.org/release/SDL2-2.0.5.tar.gz -O SDL2-2.0.5.tar.gz 4 | - tar -xzvf SDL2-2.0.5.tar.gz 5 | install: 6 | - (cd SDL2-2.0.5 && ./configure && make && sudo make install) 7 | script: 8 | - cargo test -v 9 | - cargo doc -v 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "piston2d-glium_graphics" 3 | version = "0.95.0" 4 | authors = [ 5 | "Eduard Bopp ", 6 | "bvssvni " 7 | ] 8 | keywords = ["graphics", "2d", "glium", "piston"] 9 | description = "A Glium 2D back-end for the Piston game engine" 10 | license = "MIT" 11 | repository = "https://github.com/PistonDevelopers/glium_graphics.git" 12 | homepage = "https://github.com/PistonDevelopers/glium_graphics" 13 | documentation = "https://docs.rs/piston2d-glium_graphics" 14 | exclude = ["assets/*"] 15 | 16 | [lib] 17 | name = "glium_graphics" 18 | 19 | [features] 20 | default = ["glium_window", "image", "check_current_window"] 21 | glium_window = ["piston", "pistoncore-glutin_window"] 22 | check_current_window = [] 23 | 24 | [dependencies.glium] 25 | version = "0.26.0" 26 | default_features = false 27 | 28 | [dependencies] 29 | image = { version = "0.25.1", optional = true } 30 | piston-shaders_graphics2d = "0.4.0" 31 | piston-texture = "0.9.0" 32 | piston = { version = "1.0.0", optional = true } 33 | shader_version = "0.7.0" 34 | pistoncore-glutin_window = { version = "0.72.0", optional = true } 35 | 36 | [dependencies.piston2d-graphics] 37 | version = "0.44.0" 38 | features = ["glyph_cache_rusttype"] 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 PistonDevelopers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # glium_graphics [![Build Status](https://travis-ci.org/PistonDevelopers/glium_graphics.svg?branch=master)](https://travis-ci.org/PistonDevelopers/glium_graphics) 2 | A Glium 2D back-end for the Piston game engine 3 | -------------------------------------------------------------------------------- /assets/FiraSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/glium_graphics/a8afd4b03627a288742d630c854ce7827488cf4f/assets/FiraSans-Regular.ttf -------------------------------------------------------------------------------- /assets/rust-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/glium_graphics/a8afd4b03627a288742d630c854ce7827488cf4f/assets/rust-white.png -------------------------------------------------------------------------------- /assets/rust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/glium_graphics/a8afd4b03627a288742d630c854ce7827488cf4f/assets/rust.png -------------------------------------------------------------------------------- /examples/colored_image_test.rs: -------------------------------------------------------------------------------- 1 | extern crate glium; 2 | extern crate glium_graphics; 3 | extern crate graphics; 4 | extern crate image; 5 | extern crate piston; 6 | 7 | use glium_graphics::{Flip, Glium2d, GliumWindow, OpenGL, Texture, TextureSettings}; 8 | use piston::event_loop::EventLoop; 9 | use piston::input::RenderEvent; 10 | use piston::window::WindowSettings; 11 | 12 | fn main() { 13 | let opengl = OpenGL::V3_2; 14 | let (w, h) = (300, 300); 15 | let ref mut window: GliumWindow = WindowSettings::new("glium_graphics: colored_image_test", [w, h]) 16 | .exit_on_esc(true) 17 | .graphics_api(opengl) 18 | .build() 19 | .unwrap(); 20 | 21 | let rust_logo = Texture::from_path( 22 | window, 23 | "assets/rust-white.png", 24 | Flip::None, 25 | &TextureSettings::new(), 26 | ) 27 | .unwrap(); 28 | 29 | let mut g2d = Glium2d::new(opengl, window); 30 | window.set_lazy(true); 31 | while let Some(e) = window.next() { 32 | use graphics::*; 33 | 34 | if let Some(args) = e.render_args() { 35 | let mut target = window.draw(); 36 | g2d.draw(&mut target, args.viewport(), |c, g| { 37 | use graphics::triangulation::{tx, ty}; 38 | 39 | let transform = c.transform.trans(0.0, 0.0); 40 | 41 | let tr = |p: [f64; 2]| [tx(transform, p[0], p[1]), ty(transform, p[0], p[1])]; 42 | 43 | clear(color::WHITE, g); 44 | Rectangle::new([1.0, 0.0, 0.0, 1.0]) 45 | .draw([0.0, 0.0, 100.0, 100.0], &c.draw_state, c.transform, g); 46 | Rectangle::new([0.0, 1.0, 0.0, 0.3]) 47 | .draw([50.0, 50.0, 100.0, 100.0], &c.draw_state, c.transform, g); 48 | g.tri_list_uv_c(&c.draw_state, &rust_logo, |f| { 49 | (f)( 50 | &[ 51 | tr([0.0, 0.0]), 52 | tr([300.0, 0.0]), 53 | tr([0.0, 300.0]), 54 | 55 | tr([300.0, 0.0]), 56 | tr([0.0, 300.0]), 57 | tr([300.0, 300.0]), 58 | ], 59 | &[ 60 | [0.0, 0.0], 61 | [1.0, 0.0], 62 | [0.0, 1.0], 63 | 64 | [1.0, 0.0], 65 | [0.0, 1.0], 66 | [1.0, 1.0], 67 | ], 68 | &[ 69 | [1.0, 0.0, 0.0, 1.0], 70 | [0.0, 1.0, 0.0, 1.0], 71 | [0.0, 0.0, 1.0, 1.0], 72 | 73 | [0.0, 00.0, 0.0, 1.0], 74 | [0.0, 00.0, 0.0, 1.0], 75 | [0.0, 00.0, 0.0, 1.0], 76 | ] 77 | ) 78 | }); 79 | }); 80 | target.finish().unwrap(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /examples/draw_state.rs: -------------------------------------------------------------------------------- 1 | extern crate glium_graphics; 2 | extern crate graphics; 3 | extern crate piston; 4 | 5 | use glium_graphics::{Flip, Glium2d, GliumWindow, OpenGL, Texture, TextureSettings}; 6 | use graphics::draw_state::Blend; 7 | use piston::event_loop::EventLoop; 8 | use piston::input::*; 9 | use piston::window::WindowSettings; 10 | 11 | fn main() { 12 | println!("Press A to change blending"); 13 | println!("Press S to change clip inside/out"); 14 | 15 | let opengl = OpenGL::V3_2; 16 | let (w, h) = (640, 480); 17 | let ref mut window: GliumWindow = WindowSettings::new("glium_graphics: image_test", [w, h]) 18 | .exit_on_esc(true) 19 | .graphics_api(opengl) 20 | .build() 21 | .unwrap(); 22 | 23 | let mut blend = Blend::Alpha; 24 | let mut clip_inside = true; 25 | let rust_logo = Texture::from_path( 26 | window, 27 | "assets/rust.png", 28 | Flip::None, 29 | &TextureSettings::new(), 30 | ) 31 | .unwrap(); 32 | 33 | let mut g2d = Glium2d::new(opengl, window); 34 | window.set_lazy(true); 35 | while let Some(e) = window.next() { 36 | if let Some(args) = e.render_args() { 37 | use graphics::*; 38 | 39 | let mut target = window.draw(); 40 | g2d.draw(&mut target, args.viewport(), |c, g| { 41 | clear([0.8, 0.8, 0.8, 1.0], g); 42 | g.clear_stencil(0); 43 | Rectangle::new([1.0, 0.0, 0.0, 1.0]).draw( 44 | [0.0, 0.0, 100.0, 100.0], 45 | &c.draw_state, 46 | c.transform, 47 | g, 48 | ); 49 | 50 | let draw_state = c.draw_state.blend(blend); 51 | Rectangle::new([0.5, 1.0, 0.0, 0.3]).draw( 52 | [50.0, 50.0, 100.0, 100.0], 53 | &draw_state, 54 | c.transform, 55 | g, 56 | ); 57 | 58 | let transform = c.transform.trans(100.0, 100.0); 59 | // Compute clip rectangle from upper left corner. 60 | let (clip_x, clip_y, clip_w, clip_h) = (100, 100, 100, 100); 61 | let (clip_x, clip_y, clip_w, clip_h) = ( 62 | clip_x, 63 | c.viewport.unwrap().draw_size[1] - clip_y - clip_h, 64 | clip_w, 65 | clip_h, 66 | ); 67 | let clipped = c.draw_state.scissor([clip_x, clip_y, clip_w, clip_h]); 68 | Image::new().draw(&rust_logo, &clipped, transform, g); 69 | 70 | let transform = c.transform.trans(200.0, 200.0); 71 | Ellipse::new([1.0, 0.0, 0.0, 1.0]).draw( 72 | [0.0, 0.0, 50.0, 50.0], 73 | &DrawState::new_clip(), 74 | transform, 75 | g, 76 | ); 77 | Image::new().draw( 78 | &rust_logo, 79 | &(if clip_inside { 80 | DrawState::new_inside() 81 | } else { 82 | DrawState::new_outside() 83 | }), 84 | transform, 85 | g, 86 | ); 87 | }); 88 | 89 | target.finish().unwrap(); 90 | } 91 | 92 | if let Some(Button::Keyboard(Key::A)) = e.press_args() { 93 | blend = match blend { 94 | Blend::Alpha => Blend::Add, 95 | Blend::Add => Blend::Multiply, 96 | Blend::Multiply => Blend::Invert, 97 | Blend::Invert => Blend::Lighter, 98 | Blend::Lighter => Blend::Alpha, 99 | }; 100 | println!("Changed blending to {:?}", blend); 101 | } 102 | 103 | if let Some(Button::Keyboard(Key::S)) = e.press_args() { 104 | clip_inside = !clip_inside; 105 | if clip_inside { 106 | println!("Changed to clip inside"); 107 | } else { 108 | println!("Changed to clip outside"); 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /examples/image_test.rs: -------------------------------------------------------------------------------- 1 | extern crate glium; 2 | extern crate glium_graphics; 3 | extern crate graphics; 4 | extern crate image; 5 | extern crate piston; 6 | 7 | use glium_graphics::{Flip, Glium2d, GliumWindow, OpenGL, Texture, TextureSettings}; 8 | use piston::event_loop::EventLoop; 9 | use piston::input::RenderEvent; 10 | use piston::window::WindowSettings; 11 | 12 | fn main() { 13 | let opengl = OpenGL::V3_2; 14 | let (w, h) = (300, 300); 15 | let ref mut window: GliumWindow = WindowSettings::new("glium_graphics: image_test", [w, h]) 16 | .exit_on_esc(true) 17 | .graphics_api(opengl) 18 | .build() 19 | .unwrap(); 20 | 21 | let rust_logo = Texture::from_path( 22 | window, 23 | "assets/rust.png", 24 | Flip::None, 25 | &TextureSettings::new(), 26 | ) 27 | .unwrap(); 28 | 29 | let mut g2d = Glium2d::new(opengl, window); 30 | window.set_lazy(true); 31 | while let Some(e) = window.next() { 32 | use graphics::*; 33 | 34 | if let Some(args) = e.render_args() { 35 | let mut target = window.draw(); 36 | g2d.draw(&mut target, args.viewport(), |c, g| { 37 | clear(color::WHITE, g); 38 | rectangle( 39 | [1.0, 0.0, 0.0, 1.0], 40 | [0.0, 0.0, 100.0, 100.0], 41 | c.transform, 42 | g, 43 | ); 44 | rectangle( 45 | [0.0, 1.0, 0.0, 0.3], 46 | [50.0, 50.0, 100.0, 100.0], 47 | c.transform, 48 | g, 49 | ); 50 | image(&rust_logo, c.transform.trans(100.0, 100.0), g); 51 | }); 52 | target.finish().unwrap(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/text_test.rs: -------------------------------------------------------------------------------- 1 | extern crate glium_graphics; 2 | extern crate graphics; 3 | extern crate piston; 4 | 5 | use glium_graphics::{Glium2d, GliumWindow, GlyphCache, OpenGL, TextureSettings}; 6 | use piston::event_loop::EventLoop; 7 | use piston::input::RenderEvent; 8 | use piston::window::WindowSettings; 9 | use std::path::Path; 10 | 11 | fn main() { 12 | let opengl = OpenGL::V3_2; 13 | let size = [500, 300]; 14 | let ref mut window: GliumWindow = WindowSettings::new("gfx_graphics: text_test", size) 15 | .exit_on_esc(true) 16 | .graphics_api(opengl) 17 | .build() 18 | .unwrap(); 19 | 20 | let mut glyph_cache = GlyphCache::new( 21 | Path::new("assets/FiraSans-Regular.ttf"), 22 | window.clone(), 23 | TextureSettings::new(), 24 | ) 25 | .unwrap(); 26 | 27 | let mut g2d = Glium2d::new(opengl, window); 28 | window.set_lazy(true); 29 | while let Some(e) = window.next() { 30 | if let Some(args) = e.render_args() { 31 | let mut target = window.draw(); 32 | g2d.draw(&mut target, args.viewport(), |c, g| { 33 | use graphics::*; 34 | 35 | clear([1.0; 4], g); 36 | text::Text::new_color([0.0, 0.5, 0.0, 1.0], 32) 37 | .draw( 38 | "Hello glium_graphics!", 39 | &mut glyph_cache, 40 | &DrawState::default(), 41 | c.transform.trans(10.0, 100.0), 42 | g, 43 | ) 44 | .unwrap(); 45 | }); 46 | target.finish().unwrap(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/texture_wrap.rs: -------------------------------------------------------------------------------- 1 | extern crate glium; 2 | extern crate glium_graphics; 3 | extern crate graphics; 4 | extern crate image as im; 5 | extern crate piston; 6 | 7 | use glium_graphics::{Flip, Glium2d, GliumWindow, OpenGL, Texture, TextureSettings, Wrap}; 8 | use piston::event_loop::EventLoop; 9 | use piston::input::{Button, Key, PressEvent, RenderEvent}; 10 | use piston::window::WindowSettings; 11 | 12 | fn main() { 13 | println!("Press U to change the texture wrap mode for the u coordinate"); 14 | println!("Press V to change the texture wrap mode for the v coordinate"); 15 | 16 | let opengl = OpenGL::V3_2; 17 | let (w, h) = (600, 600); 18 | let mut window: GliumWindow = WindowSettings::new("glium_graphics: texture_wrap", [w, h]) 19 | .exit_on_esc(true) 20 | .graphics_api(opengl) 21 | .build() 22 | .unwrap(); 23 | window.set_lazy(true); 24 | 25 | // Set up wrap modes 26 | let wrap_modes = [ 27 | Wrap::ClampToEdge, 28 | Wrap::ClampToBorder, 29 | Wrap::Repeat, 30 | Wrap::MirroredRepeat, 31 | ]; 32 | let mut ix_u = 0; 33 | let mut ix_v = 0; 34 | let mut texture_settings = TextureSettings::new(); 35 | texture_settings.set_border_color([0.0, 0.0, 0.0, 1.0]); 36 | 37 | let mut rust_logo = Texture::from_path( 38 | &mut window, 39 | "assets/rust.png", 40 | Flip::None, 41 | &texture_settings, 42 | ) 43 | .unwrap(); 44 | 45 | let mut g2d = Glium2d::new(opengl, &mut window); 46 | while let Some(e) = window.next() { 47 | if let Some(args) = e.render_args() { 48 | use graphics::*; 49 | let mut target = window.draw(); 50 | g2d.draw(&mut target, args.viewport(), |_c, g| { 51 | clear([1.0; 4], g); 52 | let points = [[0.5, 0.5], [-0.5, 0.5], [-0.5, -0.5], [0.5, -0.5]]; 53 | // (0, 1, 2) and (0, 2, 3) 54 | let uvs = [ 55 | [4.0, 0.0], 56 | [0.0, 0.0], 57 | [0.0, 4.0], 58 | [4.0, 0.0], 59 | [0.0, 4.0], 60 | [4.0, 4.0], 61 | ]; 62 | let mut verts = [[0.0, 0.0]; 6]; 63 | let indices_points: [usize; 6] = [0, 1, 2, 0, 2, 3]; 64 | for (ixv, &ixp) in (0..6).zip((&indices_points).into_iter()) { 65 | verts[ixv] = points[ixp]; 66 | } 67 | g.tri_list_uv(&DrawState::new_alpha(), &[1.0; 4], &rust_logo, |f| { 68 | f(&verts, &uvs) 69 | }); 70 | }); 71 | target.finish().unwrap(); 72 | } 73 | 74 | if let Some(Button::Keyboard(Key::U)) = e.press_args() { 75 | ix_u = (ix_u + 1) % wrap_modes.len(); 76 | texture_settings.set_wrap_u(wrap_modes[ix_u]); 77 | rust_logo = Texture::from_path( 78 | &mut window, 79 | "assets/rust.png", 80 | Flip::None, 81 | &texture_settings, 82 | ) 83 | .unwrap(); 84 | println!( 85 | "Changed texture wrap mode for u coordinate to: {:?}", 86 | wrap_modes[ix_u] 87 | ); 88 | } 89 | 90 | if let Some(Button::Keyboard(Key::V)) = e.press_args() { 91 | ix_v = (ix_v + 1) % wrap_modes.len(); 92 | texture_settings.set_wrap_v(wrap_modes[ix_v]); 93 | rust_logo = Texture::from_path( 94 | &mut window, 95 | "assets/rust.png", 96 | Flip::None, 97 | &texture_settings, 98 | ) 99 | .unwrap(); 100 | println!( 101 | "Changed texture wrap mode for v coordinate to: {:?}", 102 | wrap_modes[ix_v] 103 | ); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/back_end.rs: -------------------------------------------------------------------------------- 1 | use glium::backend::Facade; 2 | use glium::index::{NoIndices, PrimitiveType}; 3 | use glium::{Frame, Program, Surface, VertexBuffer}; 4 | use graphics::color::gamma_srgb_to_linear; 5 | use graphics::{self, DrawState, Graphics, Viewport}; 6 | use shader_version::glsl::GLSL; 7 | use shader_version::{OpenGL, Shaders}; 8 | use Texture; 9 | 10 | use draw_state; 11 | 12 | const CHUNKS: usize = 100; 13 | 14 | #[derive(Copy, Clone)] 15 | struct PlainVertex { 16 | color: [f32; 4], 17 | pos: [f32; 2], 18 | } 19 | 20 | implement_vertex!(PlainVertex, color, pos); 21 | 22 | #[derive(Copy, Clone)] 23 | struct TexturedVertex { 24 | pos: [f32; 2], 25 | uv: [f32; 2], 26 | } 27 | 28 | implement_vertex!(TexturedVertex, pos, uv); 29 | 30 | #[derive(Copy, Clone)] 31 | struct TexturedColorVertex { 32 | pos: [f32; 2], 33 | uv: [f32; 2], 34 | color: [f32; 4], 35 | } 36 | 37 | implement_vertex!(TexturedColorVertex, pos, uv, color); 38 | 39 | /// The resources needed for rendering 2D. 40 | pub struct Glium2d { 41 | // The offset in vertices for colored rendering. 42 | colored_offset: usize, 43 | // The current draw state for colored rendering. 44 | colored_draw_state: DrawState, 45 | plain_buffer: VertexBuffer, 46 | textured_buffer: VertexBuffer, 47 | textured_color_buffer: VertexBuffer, 48 | shader_texture_color: Program, 49 | shader_texture: Program, 50 | shader_color: Program, 51 | } 52 | 53 | impl Glium2d { 54 | /// Creates a new `Glium2d`. 55 | pub fn new(opengl: OpenGL, window: &W) -> Glium2d 56 | where 57 | W: Facade, 58 | { 59 | use shaders::{colored, textured, textured_color}; 60 | 61 | let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) }; 62 | let glsl = opengl.to_glsl(); 63 | 64 | let plain_buffer = 65 | VertexBuffer::empty_dynamic(window, CHUNKS * graphics::BACK_END_MAX_VERTEX_COUNT) 66 | .unwrap(); 67 | Glium2d { 68 | colored_offset: 0, 69 | colored_draw_state: Default::default(), 70 | plain_buffer: plain_buffer, 71 | textured_buffer: VertexBuffer::empty_dynamic( 72 | window, 73 | graphics::BACK_END_MAX_VERTEX_COUNT, 74 | ) 75 | .unwrap(), 76 | textured_color_buffer: VertexBuffer::empty_dynamic( 77 | window, 78 | graphics::BACK_END_MAX_VERTEX_COUNT, 79 | ) 80 | .unwrap(), 81 | shader_texture_color: Program::from_source( 82 | window, 83 | Shaders::new() 84 | .set(GLSL::V1_20, src(textured_color::VERTEX_GLSL_120)) 85 | .set(GLSL::V1_50, src(textured_color::VERTEX_GLSL_150_CORE)) 86 | .get(glsl) 87 | .unwrap(), 88 | Shaders::new() 89 | .set(GLSL::V1_20, src(textured_color::FRAGMENT_GLSL_120)) 90 | .set(GLSL::V1_50, src(textured_color::FRAGMENT_GLSL_150_CORE)) 91 | .get(glsl) 92 | .unwrap(), 93 | None, 94 | ) 95 | .ok() 96 | .expect("failed to initialize textured color shader"), 97 | shader_texture: Program::from_source( 98 | window, 99 | Shaders::new() 100 | .set(GLSL::V1_20, src(textured::VERTEX_GLSL_120)) 101 | .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE)) 102 | .get(glsl) 103 | .unwrap(), 104 | Shaders::new() 105 | .set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120)) 106 | .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE)) 107 | .get(glsl) 108 | .unwrap(), 109 | None, 110 | ) 111 | .ok() 112 | .expect("failed to initialize textured shader"), 113 | shader_color: Program::from_source( 114 | window, 115 | Shaders::new() 116 | .set(GLSL::V1_20, src(colored::VERTEX_GLSL_120)) 117 | .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE)) 118 | .get(glsl) 119 | .unwrap(), 120 | Shaders::new() 121 | .set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120)) 122 | .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE)) 123 | .get(glsl) 124 | .unwrap(), 125 | None, 126 | ) 127 | .ok() 128 | .expect("failed to initialize colored shader"), 129 | } 130 | } 131 | 132 | /// Renders 2D graphics. 133 | pub fn draw(&mut self, target: &mut Frame, viewport: Viewport, f: F) -> U 134 | where 135 | F: FnOnce(graphics::Context, &mut GliumGraphics) -> U, 136 | { 137 | use graphics::Context; 138 | 139 | let ref mut g = GliumGraphics::new(self, target); 140 | let c = Context::new_viewport(viewport); 141 | let res = f(c, g); 142 | if g.system.colored_offset > 0 { 143 | g.flush_colored(); 144 | } 145 | res 146 | } 147 | } 148 | 149 | /// Graphics back-end. 150 | pub struct GliumGraphics<'d, 's, S: 's> { 151 | system: &'d mut Glium2d, 152 | surface: &'s mut S, 153 | } 154 | 155 | impl<'d, 's, S: Surface> GliumGraphics<'d, 's, S> { 156 | /// Creates a new graphics object. 157 | pub fn new(system: &'d mut Glium2d, surface: &'s mut S) -> GliumGraphics<'d, 's, S> { 158 | GliumGraphics { 159 | system: system, 160 | surface: surface, 161 | } 162 | } 163 | 164 | fn flush_colored(&mut self) { 165 | let slice = self 166 | .system 167 | .plain_buffer 168 | .slice(0..self.system.colored_offset) 169 | .unwrap(); 170 | 171 | self.surface 172 | .draw( 173 | slice, 174 | &NoIndices(PrimitiveType::TrianglesList), 175 | &self.system.shader_color, 176 | &uniform! {}, 177 | &draw_state::convert_draw_state(&self.system.colored_draw_state), 178 | ) 179 | .ok() 180 | .expect("failed to draw triangle list"); 181 | 182 | self.system.colored_offset = 0; 183 | self.system.plain_buffer.invalidate(); 184 | } 185 | } 186 | 187 | /// Implemented by all graphics back-ends. 188 | impl<'d, 's, S: Surface> Graphics for GliumGraphics<'d, 's, S> { 189 | type Texture = Texture; 190 | 191 | /// Clears background with a color. 192 | fn clear_color(&mut self, color: [f32; 4]) { 193 | let color = gamma_srgb_to_linear(color); 194 | let (r, g, b, a) = (color[0], color[1], color[2], color[3]); 195 | self.surface.clear_color(r, g, b, a); 196 | } 197 | 198 | fn clear_stencil(&mut self, value: u8) { 199 | self.surface.clear_stencil(value as i32); 200 | } 201 | 202 | /// Renders list of 2d triangles. 203 | fn tri_list(&mut self, draw_state: &DrawState, color: &[f32; 4], mut f: F) 204 | where 205 | F: FnMut(&mut dyn FnMut(&[[f32; 2]])), 206 | { 207 | let color = gamma_srgb_to_linear(*color); 208 | // Flush when draw state changes. 209 | if &self.system.colored_draw_state != draw_state { 210 | self.flush_colored(); 211 | self.system.colored_draw_state = *draw_state; 212 | } 213 | f(&mut |vertices: &[[f32; 2]]| { 214 | let n = vertices.len(); 215 | if self.system.colored_offset + n > CHUNKS * graphics::BACK_END_MAX_VERTEX_COUNT { 216 | self.flush_colored(); 217 | } 218 | let slice = self 219 | .system 220 | .plain_buffer 221 | .slice(self.system.colored_offset..self.system.colored_offset + n) 222 | .unwrap(); 223 | slice.write({ 224 | &(0..n) 225 | .map(|i| PlainVertex { 226 | color: color, 227 | pos: vertices[i], 228 | }) 229 | .collect::>() 230 | }); 231 | self.system.colored_offset += n; 232 | }) 233 | } 234 | 235 | fn tri_list_c(&mut self, draw_state: &DrawState, mut f: F) 236 | where 237 | F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 4]])), 238 | { 239 | // Flush when draw state changes. 240 | if &self.system.colored_draw_state != draw_state { 241 | self.flush_colored(); 242 | self.system.colored_draw_state = *draw_state; 243 | } 244 | f(&mut |vertices: &[[f32; 2]], colors: &[[f32; 4]]| { 245 | let n = vertices.len(); 246 | if self.system.colored_offset + n > CHUNKS * graphics::BACK_END_MAX_VERTEX_COUNT { 247 | self.flush_colored(); 248 | } 249 | let slice = self 250 | .system 251 | .plain_buffer 252 | .slice(self.system.colored_offset..self.system.colored_offset + n) 253 | .unwrap(); 254 | slice.write({ 255 | &(0..n) 256 | .map(|i| PlainVertex { 257 | color: gamma_srgb_to_linear(colors[i]), 258 | pos: vertices[i], 259 | }) 260 | .collect::>() 261 | }); 262 | self.system.colored_offset += n; 263 | }) 264 | } 265 | 266 | /// Renders list of 2d triangles. 267 | /// 268 | /// A texture coordinate is assigned per vertex. 269 | /// The texture coordinates refers to the current texture. 270 | fn tri_list_uv( 271 | &mut self, 272 | draw_state: &DrawState, 273 | color: &[f32; 4], 274 | texture: &Texture, 275 | mut f: F, 276 | ) where 277 | F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]])), 278 | { 279 | use glium::uniforms::{Sampler, SamplerWrapFunction}; 280 | use std::cmp::min; 281 | 282 | let mut sampler = Sampler::new(&texture.0); 283 | sampler.1.wrap_function = (texture.1[0], texture.1[1], SamplerWrapFunction::Clamp); 284 | 285 | let color = gamma_srgb_to_linear(*color); 286 | if self.system.colored_offset > 0 { 287 | self.flush_colored(); 288 | } 289 | f(&mut |vertices: &[[f32; 2]], texture_coords: &[[f32; 2]]| { 290 | let len = min(vertices.len(), texture_coords.len()); 291 | 292 | self.system.textured_buffer.invalidate(); 293 | let slice = self.system.textured_buffer.slice(0..len).unwrap(); 294 | 295 | slice.write({ 296 | &(0..len) 297 | .map(|i| TexturedVertex { 298 | pos: vertices[i], 299 | // FIXME: The `1.0 - ...` is because of a wrong convention 300 | uv: [texture_coords[i][0], 1.0 - texture_coords[i][1]], 301 | }) 302 | .collect::>() 303 | }); 304 | 305 | self.surface 306 | .draw( 307 | slice, 308 | &NoIndices(PrimitiveType::TrianglesList), 309 | &self.system.shader_texture, 310 | &uniform! { 311 | color: color, 312 | s_texture: sampler 313 | }, 314 | &draw_state::convert_draw_state(draw_state), 315 | ) 316 | .ok() 317 | .expect("failed to draw triangle list"); 318 | }) 319 | } 320 | 321 | fn tri_list_uv_c( 322 | &mut self, 323 | draw_state: &DrawState, 324 | texture: &Texture, 325 | mut f: F, 326 | ) where 327 | F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]], &[[f32; 4]])), 328 | { 329 | use glium::uniforms::{Sampler, SamplerWrapFunction}; 330 | use std::cmp::min; 331 | 332 | let mut sampler = Sampler::new(&texture.0); 333 | sampler.1.wrap_function = (texture.1[0], texture.1[1], SamplerWrapFunction::Clamp); 334 | 335 | if self.system.colored_offset > 0 { 336 | self.flush_colored(); 337 | } 338 | f(&mut |vertices: &[[f32; 2]], texture_coords: &[[f32; 2]], colors: &[[f32; 4]]| { 339 | let len = min(min(vertices.len(), texture_coords.len()), colors.len()); 340 | 341 | self.system.textured_color_buffer.invalidate(); 342 | let slice = self.system.textured_color_buffer.slice(0..len).unwrap(); 343 | 344 | slice.write({ 345 | &(0..len) 346 | .map(|i| TexturedColorVertex { 347 | pos: vertices[i], 348 | // FIXME: The `1.0 - ...` is because of a wrong convention 349 | uv: [texture_coords[i][0], 1.0 - texture_coords[i][1]], 350 | color: gamma_srgb_to_linear(colors[i]), 351 | }) 352 | .collect::>() 353 | }); 354 | 355 | self.surface 356 | .draw( 357 | slice, 358 | &NoIndices(PrimitiveType::TrianglesList), 359 | &self.system.shader_texture_color, 360 | &uniform! { 361 | s_texture: sampler 362 | }, 363 | &draw_state::convert_draw_state(draw_state), 364 | ) 365 | .ok() 366 | .expect("failed to draw triangle list"); 367 | }) 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /src/draw_state.rs: -------------------------------------------------------------------------------- 1 | use glium; 2 | use graphics::draw_state; 3 | 4 | pub fn convert_draw_state( 5 | draw_state: &draw_state::DrawState, 6 | ) -> glium::draw_parameters::DrawParameters<'static> { 7 | glium::draw_parameters::DrawParameters { 8 | blend: convert_blend(draw_state.blend), 9 | scissor: convert_scissor(draw_state.scissor), 10 | stencil: convert_stencil(draw_state.stencil), 11 | // polygon_mode: use default (Fill) 12 | // We don't override Graphics::line, so no need to set line_width. 13 | // Always draw triangles, whether they are facing clockwise or counterclockwise. 14 | backface_culling: glium::draw_parameters::BackfaceCullingMode::CullingDisabled, 15 | ..Default::default() 16 | } 17 | } 18 | 19 | pub fn convert_scissor(rect: Option<[u32; 4]>) -> Option { 20 | rect.map(|rect| { 21 | // scissor: [x, y, w, h] 22 | glium::Rect { 23 | left: rect[0] as u32, 24 | bottom: rect[1] as u32, 25 | width: rect[2] as u32, 26 | height: rect[3] as u32, 27 | } 28 | }) 29 | } 30 | 31 | pub fn convert_stencil(stencil: Option) -> glium::draw_parameters::Stencil { 32 | use glium::{StencilOperation, StencilTest}; 33 | use graphics::draw_state::Stencil; 34 | 35 | match stencil { 36 | None => Default::default(), 37 | Some(stencil) => { 38 | let (stencil_test, stencil_test_fail_operation, reference_value) = { 39 | match stencil { 40 | Stencil::Clip(val) => (StencilTest::AlwaysFail, StencilOperation::Replace, val), 41 | Stencil::Inside(val) => ( 42 | StencilTest::IfEqual { mask: 255 }, 43 | StencilOperation::Keep, 44 | val, 45 | ), 46 | Stencil::Outside(val) => ( 47 | StencilTest::IfNotEqual { mask: 255 }, 48 | StencilOperation::Keep, 49 | val, 50 | ), 51 | Stencil::Increment => (StencilTest::AlwaysFail, StencilOperation::Increment, 0), 52 | } 53 | }; 54 | 55 | // Use triangles for stencil operations, whether they are 56 | // facing clockwise or counterclockwise. 57 | glium::draw_parameters::Stencil { 58 | // Clockwise side. 59 | test_clockwise: stencil_test, 60 | reference_value_clockwise: reference_value as i32, 61 | write_mask_clockwise: 255, 62 | fail_operation_clockwise: stencil_test_fail_operation, 63 | pass_depth_fail_operation_clockwise: StencilOperation::Keep, 64 | depth_pass_operation_clockwise: StencilOperation::Keep, 65 | // Counter clockwise side. 66 | test_counter_clockwise: stencil_test, 67 | reference_value_counter_clockwise: reference_value as i32, 68 | write_mask_counter_clockwise: 255, 69 | fail_operation_counter_clockwise: stencil_test_fail_operation, 70 | pass_depth_fail_operation_counter_clockwise: StencilOperation::Keep, 71 | depth_pass_operation_counter_clockwise: StencilOperation::Keep, 72 | } 73 | } 74 | } 75 | } 76 | 77 | pub fn convert_blend(blend: Option) -> glium::Blend { 78 | use glium::{BlendingFunction, LinearBlendingFactor}; 79 | use graphics::draw_state::Blend; 80 | 81 | match blend { 82 | None => Default::default(), 83 | Some(blend) => { 84 | match blend { 85 | // What we need is different from glium::Blend::alpha_blending(), 86 | // so we have to construct this manually. 87 | Blend::Alpha => glium::Blend { 88 | color: BlendingFunction::Addition { 89 | source: LinearBlendingFactor::SourceAlpha, 90 | destination: LinearBlendingFactor::OneMinusSourceAlpha, 91 | }, 92 | alpha: BlendingFunction::Addition { 93 | source: LinearBlendingFactor::One, 94 | destination: LinearBlendingFactor::One, 95 | }, 96 | constant_value: (0.0, 0.0, 0.0, 0.0), 97 | }, 98 | Blend::Lighter => glium::Blend { 99 | color: BlendingFunction::Addition { 100 | source: LinearBlendingFactor::SourceAlpha, 101 | destination: LinearBlendingFactor::One, 102 | }, 103 | alpha: BlendingFunction::Addition { 104 | source: LinearBlendingFactor::Zero, 105 | destination: LinearBlendingFactor::One, 106 | }, 107 | constant_value: (0.0, 0.0, 0.0, 0.0), 108 | }, 109 | Blend::Add => glium::Blend { 110 | color: BlendingFunction::Addition { 111 | source: LinearBlendingFactor::One, 112 | destination: LinearBlendingFactor::One, 113 | }, 114 | alpha: BlendingFunction::Addition { 115 | source: LinearBlendingFactor::One, 116 | destination: LinearBlendingFactor::One, 117 | }, 118 | constant_value: (0.0, 0.0, 0.0, 0.0), 119 | }, 120 | Blend::Multiply => glium::Blend { 121 | color: BlendingFunction::Addition { 122 | source: LinearBlendingFactor::DestinationColor, 123 | destination: LinearBlendingFactor::Zero, 124 | }, 125 | alpha: BlendingFunction::Addition { 126 | source: LinearBlendingFactor::DestinationAlpha, 127 | destination: LinearBlendingFactor::Zero, 128 | }, 129 | constant_value: (0.0, 0.0, 0.0, 0.0), 130 | }, 131 | Blend::Invert => glium::Blend { 132 | color: BlendingFunction::Subtraction { 133 | source: LinearBlendingFactor::ConstantColor, 134 | destination: LinearBlendingFactor::SourceColor, 135 | }, 136 | alpha: BlendingFunction::Addition { 137 | source: LinearBlendingFactor::Zero, 138 | destination: LinearBlendingFactor::One, 139 | }, 140 | constant_value: (1.0, 1.0, 1.0, 1.0), 141 | }, 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/glium_texture.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "image")] 2 | extern crate image; 3 | 4 | #[cfg(feature = "image")] 5 | use std::path::Path; 6 | 7 | #[cfg(feature = "image")] 8 | use self::image::{DynamicImage, RgbaImage}; 9 | use glium::backend::Facade; 10 | use glium::texture::srgb_texture2d::SrgbTexture2d; 11 | use glium::texture::{RawImage2d, TextureCreationError}; 12 | use glium::uniforms::SamplerWrapFunction; 13 | use graphics::ImageSize; 14 | use texture::{self, CreateTexture, Format, TextureOp, TextureSettings, UpdateTexture}; 15 | 16 | /// Flip settings. 17 | #[derive(Clone, Copy, PartialEq, Eq)] 18 | pub enum Flip { 19 | /// Does not flip. 20 | None, 21 | /// Flips image vertically. 22 | Vertical, 23 | } 24 | 25 | /// Wrapper for 2D texture. 26 | pub struct Texture(pub SrgbTexture2d, pub [SamplerWrapFunction; 2]); 27 | 28 | impl Texture { 29 | /// Creates a new `Texture`. 30 | pub fn new(texture: SrgbTexture2d) -> Texture { 31 | Texture(texture, [SamplerWrapFunction::Clamp; 2]) 32 | } 33 | 34 | /// Returns empty texture. 35 | pub fn empty(factory: &mut F) -> Result 36 | where 37 | F: Facade, 38 | { 39 | CreateTexture::create( 40 | factory, 41 | Format::Rgba8, 42 | &[0u8; 4], 43 | [1, 1], 44 | &TextureSettings::new(), 45 | ) 46 | } 47 | 48 | /// Creates a texture from path. 49 | #[cfg(feature = "image")] 50 | pub fn from_path( 51 | factory: &mut F, 52 | path: P, 53 | flip: Flip, 54 | settings: &TextureSettings, 55 | ) -> Result 56 | where 57 | F: Facade, 58 | P: AsRef, 59 | { 60 | let img = image::open(path).map_err(|e| e.to_string())?; 61 | 62 | let img = match img { 63 | DynamicImage::ImageRgba8(img) => img, 64 | img => img.to_rgba8(), 65 | }; 66 | 67 | let img = if flip == Flip::Vertical { 68 | image::imageops::flip_vertical(&img) 69 | } else { 70 | img 71 | }; 72 | 73 | Texture::from_image(factory, &img, settings).map_err(|e| format!("{:?}", e)) 74 | } 75 | 76 | /// Creates a texture from image. 77 | #[cfg(feature = "image")] 78 | pub fn from_image( 79 | factory: &mut F, 80 | img: &RgbaImage, 81 | settings: &TextureSettings, 82 | ) -> Result 83 | where 84 | F: Facade, 85 | { 86 | let (width, height) = img.dimensions(); 87 | CreateTexture::create(factory, Format::Rgba8, img, [width, height], settings) 88 | } 89 | 90 | /// Creates texture from memory alpha. 91 | pub fn from_memory_alpha( 92 | factory: &mut F, 93 | buffer: &[u8], 94 | width: u32, 95 | height: u32, 96 | settings: &TextureSettings, 97 | ) -> Result 98 | where 99 | F: Facade, 100 | { 101 | if width == 0 || height == 0 { 102 | return Texture::empty(factory); 103 | } 104 | 105 | let size = [width, height]; 106 | let buffer = texture::ops::alpha_to_rgba8(buffer, size); 107 | CreateTexture::create(factory, Format::Rgba8, &buffer, size, settings) 108 | } 109 | 110 | /// Updates texture with an image. 111 | #[cfg(feature = "image")] 112 | pub fn update( 113 | &mut self, 114 | factory: &mut F, 115 | img: &RgbaImage, 116 | ) -> Result<(), TextureCreationError> 117 | where 118 | F: Facade, 119 | { 120 | let (width, height) = img.dimensions(); 121 | UpdateTexture::update(self, factory, Format::Rgba8, img, [0, 0], [width, height]) 122 | } 123 | } 124 | 125 | impl ImageSize for Texture { 126 | fn get_size(&self) -> (u32, u32) { 127 | let ref tex = self.0; 128 | (tex.get_width(), tex.get_height().unwrap()) 129 | } 130 | } 131 | 132 | impl TextureOp for Texture { 133 | type Error = TextureCreationError; 134 | } 135 | 136 | impl CreateTexture for Texture 137 | where 138 | F: Facade, 139 | { 140 | fn create>( 141 | factory: &mut F, 142 | _format: Format, 143 | memory: &[u8], 144 | size: S, 145 | settings: &TextureSettings, 146 | ) -> Result { 147 | use texture::Wrap; 148 | let size = size.into(); 149 | 150 | let f = |wrap| match wrap { 151 | Wrap::ClampToEdge => SamplerWrapFunction::Clamp, 152 | Wrap::Repeat => SamplerWrapFunction::Repeat, 153 | Wrap::MirroredRepeat => SamplerWrapFunction::Mirror, 154 | Wrap::ClampToBorder => SamplerWrapFunction::BorderClamp, 155 | }; 156 | 157 | let wrap_u = f(settings.get_wrap_u()); 158 | let wrap_v = f(settings.get_wrap_v()); 159 | Ok(Texture( 160 | SrgbTexture2d::new( 161 | factory, 162 | RawImage2d::from_raw_rgba_reversed(memory, (size[0], size[1])) 163 | )?, 164 | [wrap_u, wrap_v], 165 | )) 166 | } 167 | } 168 | 169 | impl UpdateTexture for Texture 170 | where 171 | F: Facade, 172 | { 173 | #[allow(unused_variables)] 174 | fn update, S: Into<[u32; 2]>>( 175 | &mut self, 176 | factory: &mut F, 177 | _format: Format, 178 | memory: &[u8], 179 | offset: O, 180 | size: S, 181 | ) -> Result<(), Self::Error> { 182 | use glium::Rect; 183 | 184 | let offset = offset.into(); 185 | let size = size.into(); 186 | let (_, h) = self.get_size(); 187 | self.0.write( 188 | Rect { 189 | left: offset[0], 190 | bottom: h - offset[1] - size[1], 191 | width: size[0], 192 | height: size[1], 193 | }, 194 | RawImage2d::from_raw_rgba_reversed(memory, (size[0], size[1])), 195 | ); 196 | Ok(()) 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | 3 | //! A Piston 2D graphics back-end using Glium. 4 | 5 | #[macro_use(uniform, implement_vertex)] 6 | extern crate glium; 7 | extern crate graphics; 8 | extern crate shader_version; 9 | extern crate shaders_graphics2d as shaders; 10 | extern crate texture; 11 | 12 | pub use shader_version::OpenGL; 13 | 14 | #[cfg(feature = "glium_window")] 15 | pub use window::GliumWindow; 16 | 17 | /// Stores textures for text rendering. 18 | pub type GlyphCache<'a, F> = graphics::glyph_cache::rusttype::GlyphCache<'a, F, Texture>; 19 | 20 | pub use back_end::{Glium2d, GliumGraphics}; 21 | pub use glium_texture::{Flip, Texture}; 22 | pub use texture::*; 23 | 24 | mod back_end; 25 | mod draw_state; 26 | mod glium_texture; 27 | #[cfg(feature = "glium_window")] 28 | mod window; 29 | -------------------------------------------------------------------------------- /src/window.rs: -------------------------------------------------------------------------------- 1 | extern crate glutin_window; 2 | extern crate piston; 3 | 4 | use self::glutin_window::GlutinWindow; 5 | use self::piston::event_loop::{EventLoop, EventSettings, Events}; 6 | use self::piston::input::Event; 7 | use self::piston::window::{ 8 | AdvancedWindow, BuildFromWindowSettings, OpenGLWindow, Position, Size, Window, WindowSettings, 9 | }; 10 | use glium::backend::{Backend, Context, Facade}; 11 | use glium::{Frame, IncompatibleOpenGl, SwapBuffersError}; 12 | use std::cell::RefCell; 13 | use std::error::Error; 14 | use std::ops::Deref; 15 | use std::os::raw::c_void; 16 | use std::rc::Rc; 17 | use std::time::Duration; 18 | 19 | #[derive(Clone)] 20 | struct Wrapper(Rc>); 21 | 22 | /// A window struct for glium. 23 | pub struct GliumWindow { 24 | /// Window. 25 | pub window: Rc>, 26 | /// Glium context. 27 | pub context: Rc, 28 | /// Event loop state. 29 | pub events: Events, 30 | } 31 | 32 | impl Deref for GliumWindow { 33 | type Target = Context; 34 | 35 | fn deref(&self) -> &Context { 36 | &self.context 37 | } 38 | } 39 | 40 | impl Clone for GliumWindow { 41 | fn clone(&self) -> GliumWindow { 42 | GliumWindow { 43 | window: self.window.clone(), 44 | context: self.context.clone(), 45 | events: self.events.clone(), 46 | } 47 | } 48 | } 49 | 50 | impl BuildFromWindowSettings for GliumWindow 51 | where 52 | W: 'static + Window + OpenGLWindow + BuildFromWindowSettings, 53 | { 54 | fn build_from_window_settings(settings: &WindowSettings) -> Result, Box> { 55 | let window: W = settings.clone().build()?; 56 | GliumWindow::new(&Rc::new(RefCell::new(window))).map_err(|err| err.into()) 57 | } 58 | } 59 | 60 | impl GliumWindow 61 | where 62 | W: OpenGLWindow + 'static, 63 | { 64 | /// Creates new GliumWindow. 65 | pub fn new(window: &Rc>) -> Result { 66 | unsafe { 67 | let check_current = cfg!(feature = "check_current_window"); 68 | Context::new(Wrapper(window.clone()), check_current, Default::default()) 69 | } 70 | .map(|context| GliumWindow { 71 | window: window.clone(), 72 | context: context, 73 | events: Events::new(EventSettings::new()).swap_buffers(false), 74 | }) 75 | } 76 | 77 | /// Returns new frame. 78 | pub fn draw(&self) -> Frame { 79 | Frame::new( 80 | self.context.clone(), 81 | self.context.get_framebuffer_dimensions(), 82 | ) 83 | } 84 | 85 | /// Returns next event. 86 | pub fn next(&mut self) -> Option { 87 | self.events.next(&mut *self.window.borrow_mut()) 88 | } 89 | } 90 | 91 | impl Facade for GliumWindow { 92 | fn get_context(&self) -> &Rc { 93 | &self.context 94 | } 95 | } 96 | 97 | unsafe impl Backend for Wrapper 98 | where 99 | W: OpenGLWindow, 100 | { 101 | fn swap_buffers(&self) -> Result<(), SwapBuffersError> { 102 | self.0.borrow_mut().swap_buffers(); 103 | Ok(()) 104 | } 105 | 106 | unsafe fn get_proc_address(&self, proc_name: &str) -> *const c_void { 107 | self.0.borrow_mut().get_proc_address(proc_name) as *const c_void 108 | } 109 | 110 | fn get_framebuffer_dimensions(&self) -> (u32, u32) { 111 | let size = self.0.borrow().draw_size(); 112 | (size.width as u32, size.height as u32) 113 | } 114 | 115 | fn is_current(&self) -> bool { 116 | self.0.borrow().is_current() 117 | } 118 | 119 | unsafe fn make_current(&self) { 120 | self.0.borrow_mut().make_current() 121 | } 122 | } 123 | 124 | impl Window for GliumWindow 125 | where 126 | W: Window, 127 | { 128 | fn should_close(&self) -> bool { 129 | self.window.borrow().should_close() 130 | } 131 | fn set_should_close(&mut self, value: bool) { 132 | self.window.borrow_mut().set_should_close(value) 133 | } 134 | fn size(&self) -> Size { 135 | self.window.borrow().size() 136 | } 137 | fn draw_size(&self) -> Size { 138 | self.window.borrow().draw_size() 139 | } 140 | fn swap_buffers(&mut self) { 141 | self.window.borrow_mut().swap_buffers() 142 | } 143 | fn poll_event(&mut self) -> Option { 144 | Window::poll_event(&mut *self.window.borrow_mut()) 145 | } 146 | fn wait_event(&mut self) -> Event { 147 | Window::wait_event(&mut *self.window.borrow_mut()) 148 | } 149 | fn wait_event_timeout(&mut self, duration: Duration) -> Option { 150 | let mut window = self.window.borrow_mut(); 151 | Window::wait_event_timeout(&mut *window, duration) 152 | } 153 | } 154 | 155 | impl AdvancedWindow for GliumWindow 156 | where 157 | W: AdvancedWindow, 158 | { 159 | fn get_title(&self) -> String { 160 | self.window.borrow().get_title() 161 | } 162 | fn set_title(&mut self, title: String) { 163 | self.window.borrow_mut().set_title(title) 164 | } 165 | fn get_automatic_close(&self) -> bool { 166 | self.window.borrow().get_automatic_close() 167 | } 168 | fn set_automatic_close(&mut self, value: bool) { 169 | self.window.borrow_mut().set_automatic_close(value); 170 | } 171 | fn get_exit_on_esc(&self) -> bool { 172 | self.window.borrow().get_exit_on_esc() 173 | } 174 | fn set_exit_on_esc(&mut self, value: bool) { 175 | self.window.borrow_mut().set_exit_on_esc(value) 176 | } 177 | fn set_capture_cursor(&mut self, value: bool) { 178 | self.window.borrow_mut().set_capture_cursor(value) 179 | } 180 | fn show(&mut self) { 181 | self.window.borrow_mut().show() 182 | } 183 | fn hide(&mut self) { 184 | self.window.borrow_mut().show() 185 | } 186 | fn get_position(&self) -> Option { 187 | self.window.borrow().get_position() 188 | } 189 | fn set_position>(&mut self, pos: P) { 190 | self.window.borrow_mut().set_position(pos); 191 | } 192 | fn set_size>(&mut self, size: S) { 193 | self.window.borrow_mut().set_size(size) 194 | } 195 | } 196 | 197 | impl EventLoop for GliumWindow { 198 | fn get_event_settings(&self) -> EventSettings { 199 | self.events.get_event_settings() 200 | } 201 | 202 | fn set_event_settings(&mut self, settings: EventSettings) { 203 | self.events.set_event_settings(settings); 204 | } 205 | } 206 | --------------------------------------------------------------------------------