├── Cargo.png ├── screenshot.png ├── assets ├── rust.png ├── rust-white.png ├── FiraSans-Regular.ttf └── LICENSE ├── .travis.yml ├── .gitignore ├── README.md ├── Cargo.toml ├── LICENSE ├── Cargo.dot ├── src ├── lib.rs └── back_end.rs └── examples ├── text_test.rs ├── colored_image_test.rs ├── nested_clipping.rs ├── draw_state.rs └── texture_wrap.rs /Cargo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/gfx_graphics/HEAD/Cargo.png -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/gfx_graphics/HEAD/screenshot.png -------------------------------------------------------------------------------- /assets/rust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/gfx_graphics/HEAD/assets/rust.png -------------------------------------------------------------------------------- /assets/rust-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/gfx_graphics/HEAD/assets/rust-white.png -------------------------------------------------------------------------------- /assets/FiraSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PistonDevelopers/gfx_graphics/HEAD/assets/FiraSans-Regular.ttf -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - nightly 5 | before_install: 6 | - wget https://www.libsdl.org/release/SDL2-2.0.5.tar.gz -O SDL2-2.0.5.tar.gz 7 | - tar -xzvf SDL2-2.0.5.tar.gz 8 | install: 9 | - (cd SDL2-2.0.5 && ./configure && make && sudo make install) 10 | script: 11 | - cargo test -v 12 | - cargo doc -v 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | *# 4 | *.o 5 | *.so 6 | *.swp 7 | *.old 8 | *.bak 9 | *.kate-swp 10 | *.dylib 11 | *.dSYM 12 | *.dll 13 | *.rlib 14 | *.dummy 15 | *.exe 16 | *-test 17 | /bin/main 18 | /bin/test-internal 19 | /bin/test-external 20 | /doc/ 21 | /target/ 22 | /build/ 23 | /.rust/ 24 | rusti.sh 25 | watch.sh 26 | !/bin/assets/ 27 | 28 | Cargo.lock 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gfx_graphics [![Build Status](https://travis-ci.org/PistonDevelopers/gfx_graphics.svg?branch=master)](https://travis-ci.org/PistonDevelopers/gfx_graphics) 2 | 3 | Maintainers: @Potpourri, @kvark, @bvssvni 4 | 5 | The implementation of a piston-graphics back-end using Gfx. 6 | 7 | [API Documentation](https://docs.rs/piston2d-gfx_graphics/) 8 | 9 | ![screenshot](./screenshot.png) 10 | 11 | ### Dependency graph 12 | 13 | ![dependencies](./Cargo.png) 14 | 15 | [How to contribute](https://github.com/PistonDevelopers/piston/blob/master/CONTRIBUTING.md) 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "piston2d-gfx_graphics" 4 | version = "0.82.0" 5 | authors = ["bvssvni "] 6 | keywords = ["graphics", "2d", "gfx", "piston"] 7 | description = "A Gfx 2D back-end for the Piston game engine" 8 | license = "MIT" 9 | readme = "README.md" 10 | repository = "https://github.com/PistonDevelopers/gfx_graphics.git" 11 | homepage = "https://github.com/PistonDevelopers/gfx_graphics" 12 | documentation = "https://docs.rs/piston2d-gfx_graphics" 13 | exclude = ["assets/*", "*.png", "Cargo.dot"] 14 | 15 | [lib] 16 | 17 | name = "gfx_graphics" 18 | 19 | 20 | [dependencies] 21 | gfx = "0.18.1" 22 | draw_state = "0.8.0" 23 | piston-shaders_graphics2d = "0.4.0" 24 | piston-gfx_texture = "0.45.0" 25 | shader_version = "0.7.0" 26 | 27 | [dependencies.piston2d-graphics] 28 | version = "0.45.0" 29 | features = ["glyph_cache_rusttype"] 30 | 31 | [dev-dependencies] 32 | pistoncore-glutin_window = "0.73.1" 33 | piston = "1.0.0" 34 | find_folder = "0.3.0" 35 | gfx_device_gl = "0.16.2" 36 | image = "0.25.1" 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 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 | -------------------------------------------------------------------------------- /Cargo.dot: -------------------------------------------------------------------------------- 1 | digraph dependencies { 2 | N0[label="piston2d-gfx_graphics"]; 3 | N1[label="pistoncore-event_loop"]; 4 | N2[label="time"]; 5 | N3[label="pistoncore-current"]; 6 | N4[label="gl_generator"]; 7 | N5[label="khronos_api"]; 8 | N6[label="gl_common"]; 9 | N7[label="xml-rs"]; 10 | N8[label="gcc"]; 11 | N9[label="pistoncore-sdl2_window"]; 12 | N10[label="sdl2"]; 13 | N11[label="pistoncore-window"]; 14 | N12[label="pistoncore-input"]; 15 | N13[label="gl"]; 16 | N14[label="shader_version"]; 17 | N15[label="vecmath"]; 18 | N16[label="piston2d-graphics"]; 19 | N17[label="read_color"]; 20 | N18[label="piston-texture"]; 21 | N19[label="gfx"]; 22 | N20[label="image"]; 23 | N21[label="piston-gfx_texture"]; 24 | N22[label="gfx_macros"]; 25 | N23[label="pistoncore-event"]; 26 | N24[label="device"]; 27 | N25[label="gfx_gl"]; 28 | N26[label="render"]; 29 | N1 -> N2[label=""]; 30 | N1 -> N3[label=""]; 31 | N4 -> N5[label=""]; 32 | N4 -> N6[label=""]; 33 | N4 -> N7[label=""]; 34 | N9 -> N10[label=""]; 35 | N9 -> N11[label=""]; 36 | N9 -> N12[label=""]; 37 | N9 -> N13[label=""]; 38 | N9 -> N14[label=""]; 39 | N16 -> N17[label=""]; 40 | N16 -> N15[label=""]; 41 | N16 -> N18[label=""]; 42 | N16 -> N3[label=""]; 43 | N0 -> N19[label=""]; 44 | N0 -> N9[label=""]; 45 | N0 -> N16[label=""]; 46 | N0 -> N20[label=""]; 47 | N0 -> N21[label=""]; 48 | N0 -> N22[label=""]; 49 | N0 -> N23[label=""]; 50 | N0 -> N14[label=""]; 51 | N24 -> N25[label=""]; 52 | N23 -> N3[label=""]; 53 | N23 -> N11[label=""]; 54 | N23 -> N12[label=""]; 55 | N23 -> N1[label=""]; 56 | N26 -> N24[label=""]; 57 | N2 -> N8[label=""]; 58 | N21 -> N19[label=""]; 59 | N21 -> N18[label=""]; 60 | N21 -> N20[label=""]; 61 | N19 -> N24[label=""]; 62 | N19 -> N22[label=""]; 63 | N19 -> N26[label=""]; 64 | N25 -> N4[label=""]; 65 | N11 -> N1[label=""]; 66 | N11 -> N3[label=""]; 67 | N11 -> N12[label=""]; 68 | N13 -> N4[label=""]; 69 | } 70 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | #![deny(unreachable_pub)] 3 | 4 | //! A [Piston 2D graphics](https://github.com/pistondevelopers/graphics) back-end using [gfx-rs](https://github.com/gfx-rs/gfx). 5 | //! 6 | //! Piston-Graphics is a generic library for 2D, part of the Piston ecosystem. 7 | //! The generic abstraction creates triangles that are sent to the back-end. 8 | //! Triangles are sent through the `Graphics` trait. 9 | //! 10 | //! ### How to use gfx_graphics 11 | //! 12 | //! If you are using the [piston_window](https://github.com/pistondevelopers/piston_window) 13 | //! library, a `Gfx2d` object is created for you. 14 | //! All you need to do is call `e.draw_2d(|c, g| { ... });` 15 | //! 16 | //! If you are not using a window wrapper, you need to create `Gfx2d` and `GfxGraphics`. 17 | //! 18 | //! 1. Create a `Gfx2d` object before the event loop 19 | //! 2. Call `Gfx2d::draw` with `args.viewport()` from the render event. 20 | //! 21 | //! Example: 22 | //! 23 | //! ```ignore 24 | //! let mut g2d = Gfx2d::new(api_version, &mut factory); 25 | //! let mut events = window.events(); 26 | //! while let Some(e) = events.next(&mut window) { 27 | //! if let Some(args) = e.render_args() { 28 | //! g2d.draw(&mut encoder, &output_color, &output_stencil, args.viewport(), |c, g| { 29 | //! ... 30 | //! } 31 | //! } 32 | //! } 33 | //! ``` 34 | //! 35 | //! For a working example, see "examples/draw_state.rs". 36 | //! 37 | //! The closure `|c, g|` passes a `Context` and `&mut GfxGraphics` object. 38 | //! `Context` contains viewport, transform and draw state information. 39 | //! 40 | //! When passing this to other functions, you usually write them as: 41 | //! 42 | //! ```ignore 43 | //! fn draw_something(c: &Context, g: &mut G) { 44 | //! ... 45 | //! } 46 | //! ``` 47 | //! 48 | //! The purpose is to make code reusable across Piston 2D back-ends. 49 | //! 50 | //! For more information, consult the documentation of Piston-Graphics. 51 | 52 | #[macro_use] 53 | extern crate gfx; 54 | extern crate draw_state; 55 | extern crate gfx_texture; 56 | extern crate graphics; 57 | extern crate shaders_graphics2d as shaders; 58 | extern crate shader_version; 59 | 60 | pub use gfx_texture::*; 61 | 62 | pub use back_end::{ Gfx2d, GfxGraphics }; 63 | // pub use glyph::Error as GlyphError; 64 | // pub use glyph::GlyphCache; 65 | 66 | /// Stores textures for text rendering. 67 | pub type GlyphCache<'a, F, R, C> = 68 | graphics::glyph_cache::rusttype::GlyphCache<'a, TextureContext, Texture>; 69 | 70 | mod back_end; 71 | -------------------------------------------------------------------------------- /examples/text_test.rs: -------------------------------------------------------------------------------- 1 | extern crate piston; 2 | extern crate graphics; 3 | extern crate gfx_graphics; 4 | extern crate gfx; 5 | extern crate gfx_device_gl; 6 | extern crate glutin_window; 7 | 8 | use glutin_window::{GlutinWindow, OpenGL}; 9 | use gfx::traits::*; 10 | use gfx::memory::Typed; 11 | use gfx::format::{DepthStencil, Formatted, Srgba8}; 12 | use std::path::Path; 13 | use piston::window::{OpenGLWindow, Window, WindowSettings}; 14 | use piston::input::{AfterRenderEvent, RenderEvent}; 15 | use piston::event_loop::{Events, EventSettings, EventLoop}; 16 | use gfx_graphics::{Gfx2d, GlyphCache, TextureSettings, TextureContext}; 17 | 18 | fn main() { 19 | let opengl = OpenGL::V3_2; 20 | let size = [500, 300]; 21 | let samples = 4; 22 | let ref mut window: GlutinWindow = 23 | WindowSettings::new("gfx_graphics: text_test", size) 24 | .exit_on_esc(true) 25 | .graphics_api(opengl) 26 | .samples(samples) 27 | .build().unwrap(); 28 | 29 | let (mut device, mut factory) = gfx_device_gl::create(|s| 30 | window.get_proc_address(s) as *const std::os::raw::c_void); 31 | 32 | let mut glyph_cache = GlyphCache::new( 33 | Path::new("assets/FiraSans-Regular.ttf"), 34 | TextureContext { 35 | factory: factory.clone(), 36 | encoder: factory.create_command_buffer().into(), 37 | }, 38 | TextureSettings::new() 39 | ).unwrap(); 40 | 41 | // Create the main color/depth targets. 42 | let draw_size = window.draw_size(); 43 | let aa = samples as gfx::texture::NumSamples; 44 | let dim = (draw_size.width as u16, draw_size.height as u16, 1, aa.into()); 45 | let color_format = ::get_format(); 46 | let depth_format = ::get_format(); 47 | let (output_color, output_stencil) = 48 | gfx_device_gl::create_main_targets_raw(dim, 49 | color_format.0, 50 | depth_format.0); 51 | let output_color = Typed::new(output_color); 52 | let output_stencil = Typed::new(output_stencil); 53 | 54 | let mut encoder = factory.create_command_buffer().into(); 55 | let mut g2d = Gfx2d::new(opengl, &mut factory); 56 | let mut events = Events::new(EventSettings::new().lazy(true)); 57 | 58 | while let Some(e) = events.next(window) { 59 | if let Some(args) = e.render_args() { 60 | g2d.draw(&mut encoder, &output_color, &output_stencil, args.viewport(), |c, g| { 61 | use graphics::*; 62 | 63 | clear([1.0; 4], g); 64 | text::Text::new_color([0.0, 0.5, 0.0, 1.0], 32).draw( 65 | "Hello gfx_graphics!", 66 | &mut glyph_cache, 67 | &DrawState::default(), 68 | c.transform.trans(10.0, 100.0), 69 | g 70 | ).unwrap(); 71 | }); 72 | 73 | // Update glyphs before rendering. 74 | glyph_cache.factory.encoder.flush(&mut device); 75 | 76 | encoder.flush(&mut device); 77 | } 78 | 79 | if let Some(_) = e.after_render_args() { 80 | device.cleanup(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /examples/colored_image_test.rs: -------------------------------------------------------------------------------- 1 | extern crate piston; 2 | extern crate graphics; 3 | extern crate gfx; 4 | extern crate gfx_graphics; 5 | extern crate glutin_window; 6 | extern crate image as im; 7 | 8 | use std::path::Path; 9 | use piston::event_loop::*; 10 | use piston::input::*; 11 | use piston::window::{OpenGLWindow, Window, WindowSettings}; 12 | use gfx::format::{DepthStencil, Formatted, Srgba8}; 13 | use gfx::memory::Typed; 14 | use gfx::Device; 15 | use gfx_graphics::*; 16 | use glutin_window::{OpenGL, GlutinWindow}; 17 | 18 | fn main() { 19 | let opengl = OpenGL::V3_2; 20 | let samples = 4; 21 | let mut window: GlutinWindow = WindowSettings::new("gfx_graphics: colored_image_test", [300, 300]) 22 | .exit_on_esc(true) 23 | .graphics_api(opengl) 24 | .samples(samples) 25 | .build() 26 | .unwrap(); 27 | let (mut device, mut factory) = 28 | gfx_device_gl::create(|s| window.get_proc_address(s) as *const std::os::raw::c_void); 29 | 30 | // Set up texture 31 | let path = Path::new("./assets/rust-white.png"); 32 | let img = match im::open(path) { 33 | Ok(img) => img, 34 | Err(e) => { 35 | panic!("Could not load '{:?}': {:?}", path.file_name().unwrap(), e); 36 | } 37 | }; 38 | let img = match img { 39 | im::DynamicImage::ImageRgba8(img) => img, 40 | x => x.to_rgba8(), 41 | }; 42 | let mut texture_context = TextureContext { 43 | factory: factory.clone(), 44 | encoder: factory.create_command_buffer().into(), 45 | }; 46 | let rust_logo = Texture::from_image(&mut texture_context, &img, &TextureSettings::new()).unwrap(); 47 | 48 | let mut encoder = factory.create_command_buffer().into(); 49 | let draw_size = window.draw_size(); 50 | let dim = ( 51 | draw_size.width as u16, 52 | draw_size.height as u16, 53 | 1, 54 | (samples as gfx::texture::NumSamples).into(), 55 | ); 56 | let color_format = ::get_format(); 57 | let depth_format = ::get_format(); 58 | let (output_color, output_stencil) = 59 | gfx_device_gl::create_main_targets_raw(dim, color_format.0, depth_format.0); 60 | let output_color = Typed::new(output_color); 61 | let output_stencil = Typed::new(output_stencil); 62 | 63 | let mut g2d = Gfx2d::new(opengl, &mut factory); 64 | let mut events = Events::new(EventSettings::new()); 65 | while let Some(e) = events.next(&mut window) { 66 | use graphics::*; 67 | 68 | if let Some(args) = e.render_args() { 69 | g2d.draw( 70 | &mut encoder, 71 | &output_color, 72 | &output_stencil, 73 | args.viewport(), 74 | |c, g| 75 | { 76 | use graphics::triangulation::{tx, ty}; 77 | 78 | let transform = c.transform.trans(0.0, 0.0); 79 | 80 | let tr = |p: [f64; 2]| [tx(transform, p[0], p[1]), ty(transform, p[0], p[1])]; 81 | 82 | clear([1.0; 4], g); 83 | Rectangle::new([1.0, 0.0, 0.0, 1.0]) 84 | .draw([0.0, 0.0, 100.0, 100.0], &c.draw_state, c.transform, g); 85 | Rectangle::new([0.0, 1.0, 0.0, 0.3]) 86 | .draw([50.0, 50.0, 100.0, 100.0], &c.draw_state, c.transform, g); 87 | g.tri_list_uv_c(&c.draw_state, &rust_logo, |f| { 88 | (f)( 89 | &[ 90 | tr([0.0, 0.0]), 91 | tr([300.0, 0.0]), 92 | tr([0.0, 300.0]), 93 | 94 | tr([300.0, 0.0]), 95 | tr([0.0, 300.0]), 96 | tr([300.0, 300.0]), 97 | ], 98 | &[ 99 | [0.0, 0.0], 100 | [1.0, 0.0], 101 | [0.0, 1.0], 102 | 103 | [1.0, 0.0], 104 | [0.0, 1.0], 105 | [1.0, 1.0], 106 | ], 107 | &[ 108 | [1.0, 0.0, 0.0, 1.0], 109 | [0.0, 1.0, 0.0, 1.0], 110 | [0.0, 0.0, 1.0, 1.0], 111 | 112 | [0.0, 00.0, 0.0, 1.0], 113 | [0.0, 00.0, 0.0, 1.0], 114 | [0.0, 00.0, 0.0, 1.0], 115 | ] 116 | ) 117 | }); 118 | }); 119 | encoder.flush(&mut device); 120 | } 121 | if let Some(_) = e.after_render_args() { 122 | device.cleanup(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /examples/nested_clipping.rs: -------------------------------------------------------------------------------- 1 | extern crate graphics; 2 | extern crate gfx_graphics; 3 | extern crate piston; 4 | extern crate glutin_window; 5 | extern crate gfx; 6 | extern crate gfx_device_gl; 7 | 8 | use glutin_window::{GlutinWindow, OpenGL}; 9 | use gfx::traits::*; 10 | use gfx::memory::Typed; 11 | use gfx::format::{DepthStencil, Formatted, Srgba8}; 12 | use piston::window::{OpenGLWindow, Window, WindowSettings}; 13 | use piston::input::{AfterRenderEvent, RenderEvent, PressEvent}; 14 | use piston::event_loop::{Events, EventSettings, EventLoop}; 15 | use gfx_graphics::Gfx2d; 16 | use graphics::draw_state::*; 17 | 18 | fn main() { 19 | let opengl = OpenGL::V3_2; 20 | let (w, h) = (640, 480); 21 | let samples = 4; 22 | let mut window: GlutinWindow = WindowSettings::new("gfx_graphics: nested_clipping", [w, h]) 23 | .exit_on_esc(true) 24 | .graphics_api(opengl) 25 | .samples(samples) 26 | .build() 27 | .unwrap(); 28 | 29 | let (mut device, mut factory) = gfx_device_gl::create(|s| 30 | window.get_proc_address(s) as *const std::os::raw::c_void); 31 | 32 | // Create the main color/depth targets. 33 | let draw_size = window.draw_size(); 34 | let aa = samples as gfx::texture::NumSamples; 35 | let dim = (draw_size.width as u16, draw_size.height as u16, 1, aa.into()); 36 | let color_format = ::get_format(); 37 | let depth_format = ::get_format(); 38 | let (output_color, output_stencil) = 39 | gfx_device_gl::create_main_targets_raw(dim, 40 | color_format.0, 41 | depth_format.0); 42 | let output_color = Typed::new(output_color); 43 | let output_stencil = Typed::new(output_stencil); 44 | 45 | let mut encoder = factory.create_command_buffer().into(); 46 | let mut g2d = Gfx2d::new(opengl, &mut factory); 47 | let mut events = Events::new(EventSettings::new().lazy(true)); 48 | 49 | let increment = DrawState::new_increment(); 50 | let inside_level1 = DrawState { 51 | blend: Some(Blend::Alpha), 52 | stencil: Some(Stencil::Inside(1)), 53 | scissor: None, 54 | }; 55 | let inside_level2 = DrawState { 56 | blend: Some(Blend::Alpha), 57 | stencil: Some(Stencil::Inside(2)), 58 | scissor: None, 59 | }; 60 | let inside_level3 = DrawState { 61 | blend: Some(Blend::Alpha), 62 | stencil: Some(Stencil::Inside(3)), 63 | scissor: None, 64 | }; 65 | let mut clip = true; 66 | while let Some(e) = events.next(&mut window) { 67 | if let Some(args) = e.render_args() { 68 | use graphics::*; 69 | 70 | g2d.draw(&mut encoder, &output_color, &output_stencil, args.viewport(), |c, g| { 71 | clear([0.8, 0.8, 0.8, 1.0], g); 72 | 73 | if clip { 74 | Rectangle::new([1.0; 4]) 75 | .draw([10.0, 10.0, 200.0, 200.0], 76 | &increment, c.transform, g); 77 | Rectangle::new([1.0, 0.0, 0.0, 1.0]) 78 | .draw([10.0, 10.0, 200.0, 200.0], 79 | &inside_level1, c.transform, g); 80 | 81 | Rectangle::new([1.0; 4]) 82 | .draw([100.0, 100.0, 200.0, 200.0], 83 | &increment, c.transform, g); 84 | Rectangle::new([0.0, 0.0, 1.0, 1.0]) 85 | .draw([100.0, 100.0, 200.0, 200.0], 86 | &inside_level2, c.transform, g); 87 | 88 | Rectangle::new([1.0; 4]) 89 | .draw([100.0, 100.0, 200.0, 200.0], 90 | &increment, c.transform, g); 91 | Rectangle::new([0.0, 1.0, 0.0, 1.0]) 92 | .draw([50.0, 50.0, 200.0, 100.0], 93 | &inside_level3, c.transform, g); 94 | } else { 95 | Rectangle::new([1.0, 0.0, 0.0, 1.0]) 96 | .draw([10.0, 10.0, 200.0, 200.0], 97 | &c.draw_state, c.transform, g); 98 | 99 | Rectangle::new([0.0, 0.0, 1.0, 1.0]) 100 | .draw([100.0, 100.0, 200.0, 200.0], 101 | &c.draw_state, c.transform, g); 102 | 103 | Rectangle::new([0.0, 1.0, 0.0, 1.0]) 104 | .draw([50.0, 50.0, 200.0, 100.0], 105 | &c.draw_state, c.transform, g); 106 | } 107 | }); 108 | 109 | encoder.flush(&mut device); 110 | } 111 | if let Some(_) = e.after_render_args() { 112 | device.cleanup(); 113 | } 114 | if e.press_args().is_some() { 115 | clip = !clip; 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /assets/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ 2 | with Reserved Font Name Fira Sans. 3 | 4 | Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ 5 | with Reserved Font Name Fira Mono. 6 | 7 | Copyright (c) 2014, Telefonica S.A. 8 | 9 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 10 | This license is copied below, and is also available with a FAQ at: 11 | http://scripts.sil.org/OFL 12 | 13 | 14 | ----------------------------------------------------------- 15 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 16 | ----------------------------------------------------------- 17 | 18 | PREAMBLE 19 | The goals of the Open Font License (OFL) are to stimulate worldwide 20 | development of collaborative font projects, to support the font creation 21 | efforts of academic and linguistic communities, and to provide a free and 22 | open framework in which fonts may be shared and improved in partnership 23 | with others. 24 | 25 | The OFL allows the licensed fonts to be used, studied, modified and 26 | redistributed freely as long as they are not sold by themselves. The 27 | fonts, including any derivative works, can be bundled, embedded, 28 | redistributed and/or sold with any software provided that any reserved 29 | names are not used by derivative works. The fonts and derivatives, 30 | however, cannot be released under any other type of license. The 31 | requirement for fonts to remain under this license does not apply 32 | to any document created using the fonts or their derivatives. 33 | 34 | DEFINITIONS 35 | "Font Software" refers to the set of files released by the Copyright 36 | Holder(s) under this license and clearly marked as such. This may 37 | include source files, build scripts and documentation. 38 | 39 | "Reserved Font Name" refers to any names specified as such after the 40 | copyright statement(s). 41 | 42 | "Original Version" refers to the collection of Font Software components as 43 | distributed by the Copyright Holder(s). 44 | 45 | "Modified Version" refers to any derivative made by adding to, deleting, 46 | or substituting -- in part or in whole -- any of the components of the 47 | Original Version, by changing formats or by porting the Font Software to a 48 | new environment. 49 | 50 | "Author" refers to any designer, engineer, programmer, technical 51 | writer or other person who contributed to the Font Software. 52 | 53 | PERMISSION & CONDITIONS 54 | Permission is hereby granted, free of charge, to any person obtaining 55 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 56 | redistribute, and sell modified and unmodified copies of the Font 57 | Software, subject to the following conditions: 58 | 59 | 1) Neither the Font Software nor any of its individual components, 60 | in Original or Modified Versions, may be sold by itself. 61 | 62 | 2) Original or Modified Versions of the Font Software may be bundled, 63 | redistributed and/or sold with any software, provided that each copy 64 | contains the above copyright notice and this license. These can be 65 | included either as stand-alone text files, human-readable headers or 66 | in the appropriate machine-readable metadata fields within text or 67 | binary files as long as those fields can be easily viewed by the user. 68 | 69 | 3) No Modified Version of the Font Software may use the Reserved Font 70 | Name(s) unless explicit written permission is granted by the corresponding 71 | Copyright Holder. This restriction only applies to the primary font name as 72 | presented to the users. 73 | 74 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 75 | Software shall not be used to promote, endorse or advertise any 76 | Modified Version, except to acknowledge the contribution(s) of the 77 | Copyright Holder(s) and the Author(s) or with their explicit written 78 | permission. 79 | 80 | 5) The Font Software, modified or unmodified, in part or in whole, 81 | must be distributed entirely under this license, and must not be 82 | distributed under any other license. The requirement for fonts to 83 | remain under this license does not apply to any document created 84 | using the Font Software. 85 | 86 | TERMINATION 87 | This license becomes null and void if any of the above conditions are 88 | not met. 89 | 90 | DISCLAIMER 91 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 92 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 93 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 94 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 95 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 96 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 97 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 98 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 99 | OTHER DEALINGS IN THE FONT SOFTWARE. 100 | -------------------------------------------------------------------------------- /examples/draw_state.rs: -------------------------------------------------------------------------------- 1 | extern crate glutin_window; 2 | extern crate piston; 3 | extern crate graphics; 4 | extern crate gfx_graphics; 5 | extern crate find_folder; 6 | extern crate gfx; 7 | extern crate gfx_device_gl; 8 | 9 | use gfx::traits::*; 10 | use gfx::format::{DepthStencil, Formatted, Srgba8}; 11 | use gfx::memory::Typed; 12 | use glutin_window::{GlutinWindow, OpenGL}; 13 | use piston::window::{OpenGLWindow, Window, WindowSettings}; 14 | use piston::event_loop::{Events, EventSettings, EventLoop}; 15 | use graphics::draw_state::Blend; 16 | use graphics::*; 17 | use piston::input::*; 18 | use gfx_graphics::{Flip, Gfx2d, Texture, TextureSettings, TextureContext}; 19 | 20 | fn main() { 21 | println!("Press A to change blending"); 22 | println!("Press S to change clip inside/out"); 23 | 24 | let opengl = OpenGL::V3_2; 25 | let samples = 4; 26 | let mut window: GlutinWindow = WindowSettings::new( 27 | "piston: draw_state", 28 | [600, 600] 29 | ) 30 | .exit_on_esc(true) 31 | .samples(samples) 32 | .graphics_api(opengl) 33 | .build() 34 | .unwrap(); 35 | 36 | let (mut device, mut factory) = gfx_device_gl::create(|s| 37 | window.get_proc_address(s) as *const std::os::raw::c_void); 38 | 39 | // Create the main color/depth targets. 40 | let draw_size = window.draw_size(); 41 | let aa = samples as gfx::texture::NumSamples; 42 | let dim = (draw_size.width as u16, draw_size.height as u16, 1, aa.into()); 43 | let color_format = ::get_format(); 44 | let depth_format = ::get_format(); 45 | let (output_color, output_stencil) = 46 | gfx_device_gl::create_main_targets_raw(dim, 47 | color_format.0, 48 | depth_format.0); 49 | let output_color = Typed::new(output_color); 50 | let output_stencil = Typed::new(output_stencil); 51 | 52 | let assets = find_folder::Search::ParentsThenKids(3, 3) 53 | .for_folder("assets").unwrap(); 54 | let blends = [Blend::Alpha, Blend::Add, Blend::Invert, Blend::Multiply, Blend::Lighter]; 55 | let mut blend = 0; 56 | let mut clip_inside = true; 57 | let mut texture_context = TextureContext { 58 | factory: factory.clone(), 59 | encoder: factory.create_command_buffer().into(), 60 | }; 61 | let rust_logo = Texture::from_path(&mut texture_context, 62 | assets.join("rust.png"), 63 | Flip::None, 64 | &TextureSettings::new()).unwrap(); 65 | 66 | let mut encoder = factory.create_command_buffer().into(); 67 | let mut g2d = Gfx2d::new(opengl, &mut factory); 68 | let mut events = Events::new(EventSettings::new().lazy(true)); 69 | while let Some(e) = events.next(&mut window) { 70 | if let Some(args) = e.render_args() { 71 | g2d.draw(&mut encoder, &output_color, &output_stencil, args.viewport(), |c, g| { 72 | clear([0.8, 0.8, 0.8, 1.0], g); 73 | Rectangle::new([1.0, 0.0, 0.0, 1.0]) 74 | .draw([0.0, 0.0, 100.0, 100.0], &c.draw_state, c.transform, g); 75 | 76 | let draw_state = c.draw_state.blend(blends[blend]); 77 | Rectangle::new([0.5, 1.0, 0.0, 0.3]) 78 | .draw([50.0, 50.0, 100.0, 100.0], &draw_state, c.transform, g); 79 | 80 | let transform = c.transform.trans(100.0, 100.0); 81 | // Clip rectangle from upper left corner. 82 | let clipped = c.draw_state.scissor([100, 100, 100, 100]); 83 | Image::new().draw(&rust_logo, &clipped, transform, g); 84 | 85 | let transform = c.transform.trans(200.0, 200.0); 86 | Ellipse::new([1.0, 0.0, 0.0, 1.0]) 87 | .draw([0.0, 0.0, 50.0, 50.0], &DrawState::new_clip(), transform, g); 88 | Image::new().draw(&rust_logo, 89 | &if clip_inside { DrawState::new_inside() } 90 | else { DrawState::new_outside() }, 91 | transform, g); 92 | }); 93 | encoder.flush(&mut device); 94 | } 95 | 96 | if let Some(_) = e.after_render_args() { 97 | device.cleanup(); 98 | } 99 | 100 | if let Some(Button::Keyboard(Key::A)) = e.press_args() { 101 | blend = (blend + 1) % blends.len(); 102 | println!("Changed blending to {:?}", blends[blend]); 103 | } 104 | 105 | if let Some(Button::Keyboard(Key::S)) = e.press_args() { 106 | clip_inside = !clip_inside; 107 | if clip_inside { 108 | println!("Changed to clip inside"); 109 | } else { 110 | println!("Changed to clip outside"); 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /examples/texture_wrap.rs: -------------------------------------------------------------------------------- 1 | extern crate gfx; 2 | extern crate gfx_graphics; 3 | extern crate glutin_window; 4 | extern crate graphics; 5 | extern crate image as im; 6 | extern crate piston; 7 | 8 | use gfx::format::{DepthStencil, Formatted, Srgba8}; 9 | use gfx::memory::Typed; 10 | use gfx_graphics::{Gfx2d, Texture, TextureContext, TextureSettings, Wrap}; 11 | use glutin_window::{GlutinWindow, OpenGL}; 12 | use piston::event_loop::*; 13 | use piston::input::*; 14 | use piston::window::{OpenGLWindow, Window, WindowSettings}; 15 | use std::path::Path; 16 | 17 | fn main() { 18 | println!("Press U to change the texture wrap mode for the u coordinate"); 19 | println!("Press V to change the texture wrap mode for the v coordinate"); 20 | 21 | let opengl = OpenGL::V3_2; 22 | let samples = 4; 23 | let (w, h) = (640, 480); 24 | let mut window: GlutinWindow = WindowSettings::new("gfx_graphics: texture_wrap", [w, h]) 25 | .exit_on_esc(true) 26 | .samples(samples) 27 | .graphics_api(opengl) 28 | .build() 29 | .unwrap(); 30 | let (mut device, mut factory) = 31 | gfx_device_gl::create(|s| window.get_proc_address(s) as *const std::os::raw::c_void); 32 | 33 | // Set up wrap modes 34 | let wrap_modes = [ 35 | Wrap::ClampToEdge, 36 | Wrap::ClampToBorder, 37 | Wrap::Repeat, 38 | Wrap::MirroredRepeat, 39 | ]; 40 | let mut ix_u = 0; 41 | let mut ix_v = 0; 42 | let mut texture_settings = TextureSettings::new(); 43 | texture_settings.set_border_color([0.0, 0.0, 0.0, 1.0]); 44 | 45 | // Set up texture 46 | let path = Path::new("./assets/rust.png"); 47 | let img = match im::open(path) { 48 | Ok(img) => img, 49 | Err(e) => { 50 | panic!("Could not load '{:?}': {:?}", path.file_name().unwrap(), e); 51 | } 52 | }; 53 | let img = match img { 54 | im::DynamicImage::ImageRgba8(img) => img, 55 | x => x.to_rgba8(), 56 | }; 57 | let mut texture_context = TextureContext { 58 | factory: factory.clone(), 59 | encoder: factory.create_command_buffer().into(), 60 | }; 61 | let mut rust_logo = Texture::from_image(&mut texture_context, &img, &texture_settings).unwrap(); 62 | 63 | let mut encoder = factory.create_command_buffer().into(); 64 | let draw_size = window.draw_size(); 65 | let dim = ( 66 | draw_size.width as u16, 67 | draw_size.height as u16, 68 | 1, 69 | (samples as gfx::texture::NumSamples).into(), 70 | ); 71 | let color_format = ::get_format(); 72 | let depth_format = ::get_format(); 73 | let (output_color, output_stencil) = 74 | gfx_device_gl::create_main_targets_raw(dim, color_format.0, depth_format.0); 75 | let output_color = Typed::new(output_color); 76 | let output_stencil = Typed::new(output_stencil); 77 | let mut g2d = Gfx2d::new(opengl, &mut factory); 78 | let mut events = Events::new(EventSettings::new().lazy(true)); 79 | while let Some(e) = events.next(&mut window) { 80 | if let Some(args) = e.render_args() { 81 | use graphics::*; 82 | g2d.draw( 83 | &mut encoder, 84 | &output_color, 85 | &output_stencil, 86 | args.viewport(), 87 | |_c, g| { 88 | clear([1.0; 4], g); 89 | let points = [[0.5, 0.5], [-0.5, 0.5], [-0.5, -0.5], [0.5, -0.5]]; 90 | // (0, 1, 2) and (0, 2, 3) 91 | let uvs = [ 92 | [4.0, 0.0], 93 | [0.0, 0.0], 94 | [0.0, 4.0], 95 | [4.0, 0.0], 96 | [0.0, 4.0], 97 | [4.0, 4.0], 98 | ]; 99 | let mut verts = [[0.0, 0.0]; 6]; 100 | let indices_points: [usize; 6] = [0, 1, 2, 0, 2, 3]; 101 | for (ixv, &ixp) in (0..6).zip(indices_points.iter()) { 102 | verts[ixv] = points[ixp]; 103 | } 104 | g.tri_list_uv(&DrawState::new_alpha(), &[1.0; 4], &rust_logo, |f| { 105 | f(&verts, &uvs) 106 | }); 107 | }, 108 | ); 109 | encoder.flush(&mut device); 110 | } 111 | 112 | if let Some(Button::Keyboard(Key::U)) = e.press_args() { 113 | ix_u = (ix_u + 1) % wrap_modes.len(); 114 | texture_settings.set_wrap_u(wrap_modes[ix_u]); 115 | rust_logo = Texture::from_image(&mut texture_context, &img, &texture_settings).unwrap(); 116 | println!( 117 | "Changed texture wrap mode for u coordinate to: {:?}", 118 | wrap_modes[ix_u] 119 | ); 120 | } 121 | 122 | if let Some(Button::Keyboard(Key::V)) = e.press_args() { 123 | ix_v = (ix_v + 1) % wrap_modes.len(); 124 | texture_settings.set_wrap_v(wrap_modes[ix_v]); 125 | rust_logo = Texture::from_image(&mut texture_context, &img, &texture_settings).unwrap(); 126 | println!( 127 | "Changed texture wrap mode for v coordinate to: {:?}", 128 | wrap_modes[ix_v] 129 | ); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/back_end.rs: -------------------------------------------------------------------------------- 1 | extern crate gfx; 2 | 3 | use graphics::{ Context, DrawState, Graphics, Viewport }; 4 | use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE; 5 | use graphics::draw_state; 6 | use graphics::color::gamma_srgb_to_linear; 7 | use Texture; 8 | use gfx::format::{DepthStencil, Srgba8}; 9 | use gfx::pso::PipelineState; 10 | use shader_version::{ OpenGL, Shaders }; 11 | use shader_version::glsl::GLSL; 12 | 13 | // The number of chunks to fill up before rendering. 14 | // Amount of memory used: `BUFFER_SIZE * CHUNKS * 4 * (2 + 4)` 15 | // `4` for bytes per f32, and `2 + 4` for position and color. 16 | const CHUNKS: usize = 100; 17 | 18 | gfx_defines! { 19 | vertex PositionFormat { 20 | pos: [f32; 2] = "pos", 21 | } 22 | 23 | vertex ColorFormat { 24 | color: [f32; 4] = "color", 25 | } 26 | 27 | vertex TexCoordsFormat { 28 | uv: [f32; 2] = "uv", 29 | } 30 | } 31 | 32 | gfx_pipeline_base!( pipe_colored { 33 | pos: gfx::VertexBuffer, 34 | color: gfx::VertexBuffer, 35 | blend_target: gfx::BlendTarget, 36 | stencil_target: gfx::StencilTarget, 37 | blend_ref: gfx::BlendRef, 38 | scissor: gfx::Scissor, 39 | }); 40 | 41 | gfx_pipeline_base!( pipe_textured { 42 | pos: gfx::VertexBuffer, 43 | uv: gfx::VertexBuffer, 44 | color: gfx::Global<[f32; 4]>, 45 | texture: gfx::TextureSampler<[f32; 4]>, 46 | blend_target: gfx::BlendTarget, 47 | stencil_target: gfx::StencilTarget, 48 | blend_ref: gfx::BlendRef, 49 | scissor: gfx::Scissor, 50 | }); 51 | 52 | gfx_pipeline_base!( pipe_textured_color { 53 | pos: gfx::VertexBuffer, 54 | uv: gfx::VertexBuffer, 55 | color: gfx::VertexBuffer, 56 | texture: gfx::TextureSampler<[f32; 4]>, 57 | blend_target: gfx::BlendTarget, 58 | stencil_target: gfx::StencilTarget, 59 | blend_ref: gfx::BlendRef, 60 | scissor: gfx::Scissor, 61 | }); 62 | 63 | // Stores one PSO per blend setting. 64 | struct PsoBlend { 65 | alpha: T, 66 | add: T, 67 | multiply: T, 68 | invert: T, 69 | none: T, 70 | lighter: T, 71 | } 72 | 73 | impl PsoBlend { 74 | fn blend(&mut self, blend: Option) -> &mut T { 75 | use graphics::draw_state::Blend; 76 | 77 | match blend { 78 | Some(Blend::Alpha) => &mut self.alpha, 79 | Some(Blend::Add) => &mut self.add, 80 | Some(Blend::Multiply) => &mut self.multiply, 81 | Some(Blend::Invert) => &mut self.invert, 82 | Some(Blend::Lighter) => &mut self.lighter, 83 | None => &mut self.none, 84 | } 85 | } 86 | } 87 | 88 | // Stores one `PsoBlend` per clip setting. 89 | struct PsoStencil { 90 | none: PsoBlend, 91 | clip: PsoBlend, 92 | inside: PsoBlend, 93 | outside: PsoBlend, 94 | increment: PsoBlend, 95 | } 96 | 97 | impl PsoStencil { 98 | fn new(factory: &mut Fact, f: F) -> PsoStencil 99 | where F: Fn( 100 | &mut Fact, 101 | gfx::state::Blend, 102 | gfx::state::Stencil, 103 | gfx::state::ColorMask 104 | ) -> T 105 | { 106 | use gfx::state::{Blend, BlendChannel, Comparison, Equation, Factor, 107 | Stencil, StencilOp}; 108 | use gfx::preset::blend; 109 | 110 | let stencil = Stencil::new(Comparison::Always, 0, 111 | (StencilOp::Keep, StencilOp::Keep, StencilOp::Keep)); 112 | let stencil_clip = Stencil::new(Comparison::Never, 255, 113 | (StencilOp::Replace, StencilOp::Keep, StencilOp::Keep)); 114 | let stencil_inside = Stencil::new(Comparison::Equal, 255, 115 | (StencilOp::Keep, StencilOp::Keep, StencilOp::Keep)); 116 | let stencil_outside = Stencil::new(Comparison::NotEqual, 255, 117 | (StencilOp::Keep, StencilOp::Keep, StencilOp::Keep)); 118 | let stencil_increment = Stencil::new(Comparison::Never, 255, 119 | (StencilOp::IncrementClamp, StencilOp::Keep, StencilOp::Keep)); 120 | 121 | // Channel color masks. 122 | let mask_all = gfx::state::ColorMask::all(); 123 | let mask_none = gfx::state::ColorMask::empty(); 124 | 125 | // Fake disabled blending using the same pipeline. 126 | let no_blend = Blend { 127 | color: BlendChannel { 128 | equation: Equation::Add, 129 | source: Factor::One, 130 | destination: Factor::Zero, 131 | }, 132 | alpha: BlendChannel { 133 | equation: Equation::Add, 134 | source: Factor::One, 135 | destination: Factor::Zero, 136 | }, 137 | }; 138 | 139 | use gfx::state::BlendValue; 140 | 141 | const BLEND_LIGHTER: Blend = Blend { 142 | color: BlendChannel { 143 | equation: Equation::Add, 144 | source: Factor::ZeroPlus(BlendValue::SourceAlpha), 145 | destination: Factor::One, 146 | }, 147 | alpha: BlendChannel { 148 | equation: Equation::Add, 149 | source: Factor::Zero, 150 | destination: Factor::One, 151 | }, 152 | }; 153 | 154 | PsoStencil { 155 | none: PsoBlend { 156 | alpha: f(factory, blend::ALPHA, stencil, mask_all), 157 | add: f(factory, blend::ADD, stencil, mask_all), 158 | multiply: f(factory, blend::MULTIPLY, stencil, mask_all), 159 | invert: f(factory, blend::INVERT, stencil, mask_all), 160 | lighter: f(factory, BLEND_LIGHTER, stencil, mask_all), 161 | none: f(factory, no_blend, stencil, mask_all), 162 | }, 163 | clip: PsoBlend { 164 | alpha: f(factory, blend::ALPHA, stencil_clip, mask_none), 165 | add: f(factory, blend::ADD, stencil_clip, mask_none), 166 | multiply: f(factory, blend::MULTIPLY, stencil_clip, mask_none), 167 | invert: f(factory, blend::INVERT, stencil_clip, mask_none), 168 | lighter: f(factory, BLEND_LIGHTER, stencil_clip, mask_none), 169 | none: f(factory, no_blend, stencil_clip, mask_none), 170 | }, 171 | inside: PsoBlend { 172 | alpha: f(factory, blend::ALPHA, stencil_inside, mask_all), 173 | add: f(factory, blend::ADD, stencil_inside, mask_all), 174 | multiply: f(factory, blend::MULTIPLY, stencil_inside, mask_all), 175 | invert: f(factory, blend::INVERT, stencil_inside, mask_all), 176 | lighter: f(factory, BLEND_LIGHTER, stencil_inside, mask_all), 177 | none: f(factory, no_blend, stencil_inside, mask_all), 178 | }, 179 | outside: PsoBlend { 180 | alpha: f(factory, blend::ALPHA, stencil_outside, mask_all), 181 | add: f(factory, blend::ADD, stencil_outside, mask_all), 182 | multiply: f(factory, blend::MULTIPLY, stencil_outside, mask_all), 183 | invert: f(factory, blend::INVERT, stencil_outside, mask_all), 184 | lighter: f(factory, BLEND_LIGHTER, stencil_outside, mask_all), 185 | none: f(factory, no_blend, stencil_outside, mask_all), 186 | }, 187 | increment: PsoBlend { 188 | alpha: f(factory, blend::ALPHA, stencil_increment, mask_all), 189 | add: f(factory, blend::ADD, stencil_increment, mask_all), 190 | multiply: f(factory, blend::MULTIPLY, stencil_increment, mask_all), 191 | invert: f(factory, blend::INVERT, stencil_increment, mask_all), 192 | lighter: f(factory, BLEND_LIGHTER, stencil_increment, mask_all), 193 | none: f(factory, no_blend, stencil_increment, mask_all), 194 | }, 195 | } 196 | } 197 | 198 | // Returns a PSO and stencil reference given a stencil and blend setting. 199 | fn stencil_blend( 200 | &mut self, 201 | stencil: Option, 202 | blend: Option 203 | ) -> (&mut T, u8) { 204 | use graphics::draw_state::Stencil; 205 | 206 | match stencil { 207 | None => (self.none.blend(blend), 0), 208 | Some(Stencil::Clip(val)) => (self.clip.blend(blend), val), 209 | Some(Stencil::Inside(val)) => (self.inside.blend(blend), val), 210 | Some(Stencil::Outside(val)) => (self.outside.blend(blend), val), 211 | Some(Stencil::Increment) => (self.increment.blend(blend), 0), 212 | } 213 | } 214 | } 215 | 216 | /// The data used for drawing 2D graphics. 217 | /// 218 | /// Stores buffers and PSO objects needed for rendering 2D graphics. 219 | pub struct Gfx2d { 220 | // The offset in vertices for colored rendering. 221 | colored_offset: usize, 222 | // The current draw state for colored rendering. 223 | colored_draw_state: DrawState, 224 | buffer_pos: gfx::handle::Buffer, 225 | buffer_color: gfx::handle::Buffer, 226 | buffer_uv: gfx::handle::Buffer, 227 | colored: PsoStencil>, 228 | textured: PsoStencil>, 229 | textured_color: PsoStencil>, 230 | } 231 | 232 | impl Gfx2d { 233 | /// Creates a new Gfx2d object. 234 | pub fn new(opengl: OpenGL, factory: &mut F) -> Self 235 | where F: gfx::Factory 236 | { 237 | use gfx::Primitive; 238 | use gfx::state::Rasterizer; 239 | use gfx::state::{Blend, Stencil}; 240 | use gfx::traits::*; 241 | use shaders::{ colored, textured, textured_color }; 242 | 243 | let glsl = opengl.to_glsl(); 244 | 245 | let colored_program = factory.link_program( 246 | Shaders::new() 247 | .set(GLSL::V1_20, colored::VERTEX_GLSL_120) 248 | .set(GLSL::V1_50, colored::VERTEX_GLSL_150_CORE) 249 | .get(glsl).unwrap(), 250 | Shaders::new() 251 | .set(GLSL::V1_20, colored::FRAGMENT_GLSL_120) 252 | .set(GLSL::V1_50, colored::FRAGMENT_GLSL_150_CORE) 253 | .get(glsl).unwrap(), 254 | ).unwrap(); 255 | 256 | let colored_pipeline = |factory: &mut F, 257 | blend_preset: Blend, 258 | stencil: Stencil, 259 | color_mask: gfx::state::ColorMask| 260 | -> PipelineState { 261 | factory.create_pipeline_from_program( 262 | &colored_program, 263 | Primitive::TriangleList, 264 | Rasterizer::new_fill(), 265 | pipe_colored::Init { 266 | pos: (), 267 | color: (), 268 | blend_target: ("o_Color", color_mask, blend_preset), 269 | stencil_target: stencil, 270 | blend_ref: (), 271 | scissor: (), 272 | } 273 | ).unwrap() 274 | }; 275 | 276 | let colored = PsoStencil::new(factory, colored_pipeline); 277 | 278 | let textured_program = factory.link_program( 279 | Shaders::new() 280 | .set(GLSL::V1_20, textured::VERTEX_GLSL_120) 281 | .set(GLSL::V1_50, textured::VERTEX_GLSL_150_CORE) 282 | .get(glsl).unwrap(), 283 | Shaders::new() 284 | .set(GLSL::V1_20, textured::FRAGMENT_GLSL_120) 285 | .set(GLSL::V1_50, textured::FRAGMENT_GLSL_150_CORE) 286 | .get(glsl).unwrap() 287 | ).unwrap(); 288 | 289 | let textured_pipeline = |factory: &mut F, 290 | blend_preset: Blend, 291 | stencil: Stencil, 292 | color_mask: gfx::state::ColorMask| 293 | -> PipelineState { 294 | factory.create_pipeline_from_program( 295 | &textured_program, 296 | Primitive::TriangleList, 297 | Rasterizer::new_fill(), 298 | pipe_textured::Init { 299 | pos: (), 300 | uv: (), 301 | color: "color", 302 | texture: "s_texture", 303 | blend_target: ("o_Color", color_mask, blend_preset), 304 | stencil_target: stencil, 305 | blend_ref: (), 306 | scissor: (), 307 | } 308 | ).unwrap() 309 | }; 310 | 311 | let textured = PsoStencil::new(factory, textured_pipeline); 312 | 313 | let textured_color_program = factory.link_program( 314 | Shaders::new() 315 | .set(GLSL::V1_20, textured_color::VERTEX_GLSL_120) 316 | .set(GLSL::V1_50, textured_color::VERTEX_GLSL_150_CORE) 317 | .get(glsl).unwrap(), 318 | Shaders::new() 319 | .set(GLSL::V1_20, textured_color::FRAGMENT_GLSL_120) 320 | .set(GLSL::V1_50, textured_color::FRAGMENT_GLSL_150_CORE) 321 | .get(glsl).unwrap() 322 | ).unwrap(); 323 | 324 | let textured_color_pipeline = |factory: &mut F, 325 | blend_preset: Blend, 326 | stencil: Stencil, 327 | color_mask: gfx::state::ColorMask| 328 | -> PipelineState { 329 | factory.create_pipeline_from_program( 330 | &textured_color_program, 331 | Primitive::TriangleList, 332 | Rasterizer::new_fill(), 333 | pipe_textured_color::Init { 334 | pos: (), 335 | uv: (), 336 | color: (), 337 | texture: "s_texture", 338 | blend_target: ("o_Color", color_mask, blend_preset), 339 | stencil_target: stencil, 340 | blend_ref: (), 341 | scissor: (), 342 | } 343 | ).unwrap() 344 | }; 345 | 346 | let textured_color = PsoStencil::new(factory, textured_color_pipeline); 347 | 348 | let buffer_pos = factory.create_buffer( 349 | BUFFER_SIZE * CHUNKS, 350 | gfx::buffer::Role::Vertex, 351 | gfx::memory::Usage::Dynamic, 352 | gfx::memory::Bind::empty() 353 | ).expect("Could not create `buffer_pos`"); 354 | let buffer_color = factory.create_buffer( 355 | BUFFER_SIZE * CHUNKS, 356 | gfx::buffer::Role::Vertex, 357 | gfx::memory::Usage::Dynamic, 358 | gfx::memory::Bind::empty() 359 | ).expect("Could not create `buffer_color`"); 360 | let buffer_uv = factory.create_buffer( 361 | BUFFER_SIZE, 362 | gfx::buffer::Role::Vertex, 363 | gfx::memory::Usage::Dynamic, 364 | gfx::memory::Bind::empty() 365 | ).expect("Could not create `buffer_uv`"); 366 | 367 | Gfx2d { 368 | colored_offset: 0, 369 | colored_draw_state: Default::default(), 370 | buffer_pos: buffer_pos, 371 | buffer_color: buffer_color, 372 | buffer_uv: buffer_uv, 373 | colored: colored, 374 | textured: textured, 375 | textured_color: textured_color, 376 | } 377 | } 378 | 379 | /// Renders graphics to a Gfx renderer. 380 | pub fn draw( 381 | &mut self, 382 | encoder: &mut gfx::Encoder, 383 | output_color: &gfx::handle::RenderTargetView, 384 | output_stencil: &gfx::handle::DepthStencilView, 385 | viewport: Viewport, 386 | f: F 387 | ) -> U 388 | where C: gfx::CommandBuffer, 389 | F: FnOnce(Context, &mut GfxGraphics) -> U 390 | { 391 | let ref mut g = GfxGraphics::new( 392 | encoder, 393 | output_color, 394 | output_stencil, 395 | self 396 | ); 397 | let c = Context::new_viewport(viewport); 398 | let res = f(c, g); 399 | if g.g2d.colored_offset > 0 { 400 | g.flush_colored(); 401 | } 402 | res 403 | } 404 | } 405 | 406 | /// Used for rendering 2D graphics. 407 | pub struct GfxGraphics<'a, R, C> 408 | where R: gfx::Resources + 'a, 409 | C: gfx::CommandBuffer + 'a, 410 | R::Buffer: 'a, 411 | R::Shader: 'a, 412 | R::Program: 'a, 413 | R::Texture: 'a, 414 | R::Sampler: 'a 415 | { 416 | /// Provide access to the `gfx::Encoder` in case a user needs to update textures for caching, 417 | /// etc. 418 | pub encoder: &'a mut gfx::Encoder, 419 | output_color: &'a gfx::handle::RenderTargetView, 420 | output_stencil: &'a gfx::handle::DepthStencilView, 421 | g2d: &'a mut Gfx2d, 422 | } 423 | 424 | impl<'a, R, C> GfxGraphics<'a, R, C> 425 | where R: gfx::Resources, 426 | C: gfx::CommandBuffer, 427 | { 428 | /// Creates a new object for rendering 2D graphics. 429 | pub fn new(encoder: &'a mut gfx::Encoder, 430 | output_color: &'a gfx::handle::RenderTargetView, 431 | output_stencil: &'a gfx::handle::DepthStencilView, 432 | g2d: &'a mut Gfx2d) -> Self { 433 | GfxGraphics { 434 | encoder: encoder, 435 | output_color: output_color, 436 | output_stencil: output_stencil, 437 | g2d: g2d, 438 | } 439 | } 440 | 441 | /// Returns true if texture has alpha channel. 442 | pub fn has_texture_alpha(&self, texture: &Texture) -> bool 443 | where R: gfx::Resources 444 | { 445 | texture.surface.get_info().format.get_alpha_stencil_bits() > 0 446 | } 447 | 448 | fn flush_colored(&mut self) { 449 | use draw_state::target::Rect; 450 | use std::u16; 451 | 452 | let &mut GfxGraphics { 453 | ref mut encoder, 454 | output_color, 455 | output_stencil, 456 | g2d: &mut Gfx2d { 457 | ref mut colored_offset, 458 | ref mut colored_draw_state, 459 | ref mut buffer_pos, 460 | ref mut buffer_color, 461 | ref mut colored, 462 | .. 463 | }, 464 | .. 465 | } = self; 466 | 467 | let (pso_colored, stencil_val) = colored.stencil_blend( 468 | colored_draw_state.stencil, 469 | colored_draw_state.blend 470 | ); 471 | 472 | let scissor = match colored_draw_state.scissor { 473 | None => Rect { x: 0, y: 0, w: u16::MAX, h: u16::MAX }, 474 | Some(r) => Rect { x: r[0] as u16, y: r[1] as u16, 475 | w: r[2] as u16, h: r[3] as u16 } 476 | }; 477 | 478 | let data = pipe_colored::Data { 479 | pos: buffer_pos.clone(), 480 | color: buffer_color.clone(), 481 | blend_target: output_color.clone(), 482 | stencil_target: (output_stencil.clone(), 483 | (stencil_val, stencil_val)), 484 | // Use white color for blend reference to make invert work. 485 | blend_ref: [1.0; 4], 486 | scissor: scissor, 487 | }; 488 | 489 | let slice = gfx::Slice { 490 | instances: None, 491 | start: 0, 492 | end: *colored_offset as u32, 493 | buffer: gfx::IndexBuffer::Auto, 494 | base_vertex: 0, 495 | }; 496 | encoder.draw(&slice, pso_colored, &data); 497 | *colored_offset = 0; 498 | } 499 | } 500 | 501 | impl<'a, R, C> Graphics for GfxGraphics<'a, R, C> 502 | where R: gfx::Resources, 503 | C: gfx::CommandBuffer, 504 | R::Buffer: 'a, 505 | R::Shader: 'a, 506 | R::Program: 'a, 507 | R::Texture: 'a, 508 | R::Sampler: 'a 509 | { 510 | type Texture = Texture; 511 | 512 | fn clear_color(&mut self, color: [f32; 4]) { 513 | let color = gamma_srgb_to_linear(color); 514 | let &mut GfxGraphics { 515 | ref mut encoder, 516 | output_color, 517 | .. 518 | } = self; 519 | encoder.clear(output_color, color); 520 | } 521 | 522 | fn clear_stencil(&mut self, value: u8) { 523 | let &mut GfxGraphics { 524 | ref mut encoder, 525 | output_stencil, 526 | .. 527 | } = self; 528 | encoder.clear_stencil(output_stencil, value); 529 | } 530 | 531 | fn tri_list( 532 | &mut self, 533 | draw_state: &DrawState, 534 | color: &[f32; 4], 535 | mut f: F 536 | ) 537 | where F: FnMut(&mut dyn FnMut(&[[f32; 2]])) 538 | { 539 | let color = gamma_srgb_to_linear(*color); 540 | 541 | // Flush when draw state changes. 542 | if &self.g2d.colored_draw_state != draw_state { 543 | self.flush_colored(); 544 | self.g2d.colored_draw_state = *draw_state; 545 | } 546 | f(&mut |vertices: &[[f32; 2]]| { 547 | let n = vertices.len(); 548 | 549 | // Render if there is not enough room. 550 | if self.g2d.colored_offset + n > BUFFER_SIZE * CHUNKS { 551 | self.flush_colored(); 552 | } 553 | 554 | { 555 | use std::slice::from_raw_parts; 556 | 557 | let &mut GfxGraphics { 558 | ref mut encoder, 559 | g2d: &mut Gfx2d { 560 | ref mut colored_offset, 561 | ref mut buffer_pos, 562 | ref mut buffer_color, 563 | .. 564 | }, 565 | .. 566 | } = self; 567 | 568 | unsafe { 569 | encoder.update_buffer( 570 | &buffer_pos, 571 | from_raw_parts( 572 | vertices.as_ptr() as *const PositionFormat, 573 | n 574 | ), 575 | *colored_offset 576 | ).unwrap(); 577 | } 578 | 579 | for i in 0..n { 580 | encoder.update_buffer(&buffer_color, &[ColorFormat { 581 | color: color 582 | }], *colored_offset + i).unwrap(); 583 | } 584 | *colored_offset += n; 585 | } 586 | }) 587 | } 588 | 589 | fn tri_list_c( 590 | &mut self, 591 | draw_state: &DrawState, 592 | mut f: F 593 | ) 594 | where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 4]])) 595 | { 596 | // Flush when draw state changes. 597 | if &self.g2d.colored_draw_state != draw_state { 598 | self.flush_colored(); 599 | self.g2d.colored_draw_state = *draw_state; 600 | } 601 | f(&mut |vertices: &[[f32; 2]], colors: &[[f32; 4]]| { 602 | let n = vertices.len(); 603 | 604 | // Render if there is not enough room. 605 | if self.g2d.colored_offset + n > BUFFER_SIZE * CHUNKS { 606 | self.flush_colored(); 607 | } 608 | 609 | { 610 | use std::slice::from_raw_parts; 611 | 612 | let &mut GfxGraphics { 613 | ref mut encoder, 614 | g2d: &mut Gfx2d { 615 | ref mut colored_offset, 616 | ref mut buffer_pos, 617 | ref mut buffer_color, 618 | .. 619 | }, 620 | .. 621 | } = self; 622 | 623 | unsafe { 624 | encoder.update_buffer( 625 | &buffer_pos, 626 | from_raw_parts( 627 | vertices.as_ptr() as *const PositionFormat, 628 | n 629 | ), 630 | *colored_offset 631 | ).unwrap(); 632 | } 633 | 634 | for (i, color) in colors.iter().enumerate() { 635 | encoder.update_buffer(&buffer_color, &[ColorFormat { 636 | color: gamma_srgb_to_linear(*color) 637 | }], *colored_offset + i).unwrap(); 638 | } 639 | *colored_offset += n; 640 | } 641 | }) 642 | } 643 | 644 | fn tri_list_uv( 645 | &mut self, 646 | draw_state: &DrawState, 647 | color: &[f32; 4], 648 | texture: &::Texture, 649 | mut f: F 650 | ) 651 | where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]])) 652 | { 653 | use draw_state::target::Rect; 654 | use std::u16; 655 | 656 | let color = gamma_srgb_to_linear(*color); 657 | if self.g2d.colored_offset > 0 { 658 | self.flush_colored(); 659 | } 660 | let &mut GfxGraphics { 661 | ref mut encoder, 662 | output_color, 663 | output_stencil, 664 | g2d: &mut Gfx2d { 665 | ref mut buffer_pos, 666 | ref mut buffer_uv, 667 | ref mut textured, 668 | .. 669 | }, 670 | .. 671 | } = self; 672 | 673 | let (pso_textured, stencil_val) = textured.stencil_blend( 674 | draw_state.stencil, 675 | draw_state.blend 676 | ); 677 | 678 | let scissor = match draw_state.scissor { 679 | None => Rect { x: 0, y: 0, w: u16::MAX, h: u16::MAX }, 680 | Some(r) => Rect { x: r[0] as u16, y: r[1] as u16, 681 | w: r[2] as u16, h: r[3] as u16 } 682 | }; 683 | 684 | let data = pipe_textured::Data { 685 | pos: buffer_pos.clone(), 686 | uv: buffer_uv.clone(), 687 | color: color, 688 | texture: (texture.view.clone(), texture.sampler.clone()), 689 | blend_target: output_color.clone(), 690 | stencil_target: (output_stencil.clone(), 691 | (stencil_val, stencil_val)), 692 | blend_ref: [1.0; 4], 693 | scissor: scissor, 694 | }; 695 | 696 | f(&mut |vertices: &[[f32; 2]], texture_coords: &[[f32; 2]]| { 697 | use std::slice::from_raw_parts; 698 | 699 | assert_eq!( 700 | vertices.len(), 701 | texture_coords.len() 702 | ); 703 | let n = vertices.len(); 704 | unsafe { 705 | encoder.update_buffer( 706 | &buffer_pos, 707 | from_raw_parts( 708 | vertices.as_ptr() as *const PositionFormat, 709 | n 710 | ), 711 | 0 712 | ).unwrap(); 713 | encoder.update_buffer( 714 | &buffer_uv, 715 | from_raw_parts( 716 | texture_coords.as_ptr() as *const TexCoordsFormat, 717 | n 718 | ), 719 | 0 720 | ).unwrap(); 721 | } 722 | 723 | let slice = gfx::Slice { 724 | instances: None, 725 | start: 0, 726 | end: n as u32, 727 | buffer: gfx::IndexBuffer::Auto, 728 | base_vertex: 0, 729 | }; 730 | encoder.draw(&slice, pso_textured, &data); 731 | }) 732 | } 733 | 734 | fn tri_list_uv_c( 735 | &mut self, 736 | draw_state: &DrawState, 737 | texture: &::Texture, 738 | mut f: F 739 | ) 740 | where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]], &[[f32; 4]])) 741 | { 742 | use draw_state::target::Rect; 743 | use std::u16; 744 | 745 | if self.g2d.colored_offset > 0 { 746 | self.flush_colored(); 747 | } 748 | let &mut GfxGraphics { 749 | ref mut encoder, 750 | output_color, 751 | output_stencil, 752 | g2d: &mut Gfx2d { 753 | ref mut buffer_pos, 754 | ref mut buffer_uv, 755 | ref mut buffer_color, 756 | ref mut textured_color, 757 | .. 758 | }, 759 | .. 760 | } = self; 761 | 762 | let (pso_textured_color, stencil_val) = textured_color.stencil_blend( 763 | draw_state.stencil, 764 | draw_state.blend 765 | ); 766 | 767 | let scissor = match draw_state.scissor { 768 | None => Rect { x: 0, y: 0, w: u16::MAX, h: u16::MAX }, 769 | Some(r) => Rect { x: r[0] as u16, y: r[1] as u16, 770 | w: r[2] as u16, h: r[3] as u16 } 771 | }; 772 | 773 | let data = pipe_textured_color::Data { 774 | pos: buffer_pos.clone(), 775 | uv: buffer_uv.clone(), 776 | color: buffer_color.clone(), 777 | texture: (texture.view.clone(), texture.sampler.clone()), 778 | blend_target: output_color.clone(), 779 | stencil_target: (output_stencil.clone(), 780 | (stencil_val, stencil_val)), 781 | blend_ref: [1.0; 4], 782 | scissor: scissor, 783 | }; 784 | 785 | f(&mut |vertices: &[[f32; 2]], texture_coords: &[[f32; 2]], colors: &[[f32; 4]]| { 786 | use std::slice::from_raw_parts; 787 | 788 | assert_eq!( 789 | vertices.len(), 790 | texture_coords.len() 791 | ); 792 | let n = vertices.len(); 793 | unsafe { 794 | encoder.update_buffer( 795 | &buffer_pos, 796 | from_raw_parts( 797 | vertices.as_ptr() as *const PositionFormat, 798 | n 799 | ), 800 | 0 801 | ).unwrap(); 802 | encoder.update_buffer( 803 | &buffer_uv, 804 | from_raw_parts( 805 | texture_coords.as_ptr() as *const TexCoordsFormat, 806 | n 807 | ), 808 | 0 809 | ).unwrap(); 810 | encoder.update_buffer( 811 | &buffer_color, 812 | from_raw_parts( 813 | colors.as_ptr() as *const ColorFormat, 814 | n 815 | ), 816 | 0 817 | ).unwrap(); 818 | } 819 | 820 | let slice = gfx::Slice { 821 | instances: None, 822 | start: 0, 823 | end: n as u32, 824 | buffer: gfx::IndexBuffer::Auto, 825 | base_vertex: 0, 826 | }; 827 | encoder.draw(&slice, pso_textured_color, &data); 828 | }) 829 | } 830 | } 831 | --------------------------------------------------------------------------------