Begin refactoring the demo into a shared library and a platform-specific
entry point. This will help the upcoming wasm port.
|
@ -159,18 +159,7 @@ dependencies = [
|
||||||
name = "demo"
|
name = "demo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pathfinder_demo 0.1.0",
|
||||||
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"pathfinder_geometry 0.3.0",
|
|
||||||
"pathfinder_gl 0.1.0",
|
|
||||||
"pathfinder_renderer 0.1.0",
|
|
||||||
"pathfinder_svg 0.1.0",
|
|
||||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -521,6 +510,24 @@ dependencies = [
|
||||||
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathfinder_demo"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pathfinder_geometry 0.3.0",
|
||||||
|
"pathfinder_gl 0.1.0",
|
||||||
|
"pathfinder_renderer 0.1.0",
|
||||||
|
"pathfinder_svg 0.1.0",
|
||||||
|
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathfinder_geometry"
|
name = "pathfinder_geometry"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"demo",
|
"demo/common",
|
||||||
|
"demo/native",
|
||||||
"geometry",
|
"geometry",
|
||||||
"gl",
|
"gl",
|
||||||
"renderer",
|
"renderer",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "demo"
|
name = "pathfinder_demo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
|
@ -15,13 +15,13 @@ sdl2 = "0.32"
|
||||||
usvg = "0.4"
|
usvg = "0.4"
|
||||||
|
|
||||||
[dependencies.pathfinder_geometry]
|
[dependencies.pathfinder_geometry]
|
||||||
path = "../geometry"
|
path = "../../geometry"
|
||||||
|
|
||||||
[dependencies.pathfinder_gl]
|
[dependencies.pathfinder_gl]
|
||||||
path = "../gl"
|
path = "../../gl"
|
||||||
|
|
||||||
[dependencies.pathfinder_renderer]
|
[dependencies.pathfinder_renderer]
|
||||||
path = "../renderer"
|
path = "../../renderer"
|
||||||
|
|
||||||
[dependencies.pathfinder_svg]
|
[dependencies.pathfinder_svg]
|
||||||
path = "../svg"
|
path = "../../svg"
|
|
@ -1,4 +1,4 @@
|
||||||
// pathfinder/demo/src/main.rs
|
// pathfinder/demo/common/src/lib.rs
|
||||||
//
|
//
|
||||||
// Copyright © 2019 The Pathfinder Project Developers.
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
//
|
//
|
||||||
|
@ -19,7 +19,7 @@ use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32};
|
||||||
use pathfinder_geometry::basic::rect::RectF32;
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
||||||
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
|
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
|
||||||
use pathfinder_gl::device::{Buffer, BufferTarget, BufferUploadMode, Program, Uniform};
|
use pathfinder_gl::device::{Buffer, BufferTarget, BufferUploadMode, Device, Program, Uniform};
|
||||||
use pathfinder_gl::device::{VertexArray, VertexAttr};
|
use pathfinder_gl::device::{VertexArray, VertexAttr};
|
||||||
use pathfinder_gl::renderer::Renderer;
|
use pathfinder_gl::renderer::Renderer;
|
||||||
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
|
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
|
||||||
|
@ -46,7 +46,7 @@ use usvg::{Options as UsvgOptions, Tree};
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||||
|
|
||||||
static DEFAULT_SVG_PATH: &'static str = "../resources/svg/ghostscript-tiger-big-opt.svg";
|
static DEFAULT_SVG_FILENAME: &'static str = "ghostscript-tiger-big-opt.svg";
|
||||||
|
|
||||||
const MAIN_FRAMEBUFFER_WIDTH: u32 = 1067;
|
const MAIN_FRAMEBUFFER_WIDTH: u32 = 1067;
|
||||||
const MAIN_FRAMEBUFFER_HEIGHT: u32 = 800;
|
const MAIN_FRAMEBUFFER_HEIGHT: u32 = 800;
|
||||||
|
@ -71,11 +71,7 @@ const GRIDLINE_COUNT: u8 = 10;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
fn main() {
|
pub struct DemoApp {
|
||||||
DemoApp::new().run();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DemoApp {
|
|
||||||
window: Window,
|
window: Window,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
sdl_context: Sdl,
|
sdl_context: Sdl,
|
||||||
|
@ -105,9 +101,7 @@ struct DemoApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DemoApp {
|
impl DemoApp {
|
||||||
fn new() -> DemoApp {
|
pub fn new() -> DemoApp {
|
||||||
let options = Options::get();
|
|
||||||
|
|
||||||
let sdl_context = sdl2::init().unwrap();
|
let sdl_context = sdl2::init().unwrap();
|
||||||
let sdl_video = sdl_context.video().unwrap();
|
let sdl_video = sdl_context.video().unwrap();
|
||||||
|
|
||||||
|
@ -128,19 +122,21 @@ impl DemoApp {
|
||||||
|
|
||||||
let sdl_event_pump = sdl_context.event_pump().unwrap();
|
let sdl_event_pump = sdl_context.event_pump().unwrap();
|
||||||
|
|
||||||
|
let device = Device::new();
|
||||||
|
let options = Options::get(&device);
|
||||||
|
|
||||||
let (window_width, _) = window.size();
|
let (window_width, _) = window.size();
|
||||||
let (drawable_width, drawable_height) = window.drawable_size();
|
let (drawable_width, drawable_height) = window.drawable_size();
|
||||||
let drawable_size = Size2D::new(drawable_width, drawable_height);
|
let drawable_size = Size2D::new(drawable_width, drawable_height);
|
||||||
|
|
||||||
let base_scene = load_scene(&options.input_path);
|
let base_scene = load_scene(&options.input_path);
|
||||||
let renderer = Renderer::new(&drawable_size);
|
let renderer = Renderer::new(&device, &drawable_size);
|
||||||
let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone());
|
let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone());
|
||||||
update_drawable_size(&window, &scene_thread_proxy);
|
update_drawable_size(&window, &scene_thread_proxy);
|
||||||
|
|
||||||
let camera = if options.threed { Camera::three_d() } else { Camera::two_d() };
|
let camera = if options.threed { Camera::three_d() } else { Camera::two_d() };
|
||||||
|
|
||||||
let grid_vertex_positions = create_grid_vertex_positions();
|
let ground_program = GroundProgram::new(&device);
|
||||||
let ground_program = GroundProgram::new();
|
|
||||||
let ground_solid_vertex_array =
|
let ground_solid_vertex_array =
|
||||||
GroundSolidVertexArray::new(&ground_program, &renderer.quad_vertex_positions_buffer());
|
GroundSolidVertexArray::new(&ground_program, &renderer.quad_vertex_positions_buffer());
|
||||||
let ground_line_vertex_array = GroundLineVertexArray::new(&ground_program);
|
let ground_line_vertex_array = GroundLineVertexArray::new(&ground_program);
|
||||||
|
@ -161,18 +157,18 @@ impl DemoApp {
|
||||||
mouselook_enabled: false,
|
mouselook_enabled: false,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
|
|
||||||
ui: DemoUI::new(options),
|
ui: DemoUI::new(&device, options),
|
||||||
scene_thread_proxy,
|
scene_thread_proxy,
|
||||||
renderer,
|
renderer,
|
||||||
|
|
||||||
device: DemoDevice,
|
device: DemoDevice { device },
|
||||||
ground_program,
|
ground_program,
|
||||||
ground_solid_vertex_array,
|
ground_solid_vertex_array,
|
||||||
ground_line_vertex_array,
|
ground_line_vertex_array,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
while !self.exit {
|
while !self.exit {
|
||||||
// Update the scene.
|
// Update the scene.
|
||||||
self.build_scene();
|
self.build_scene();
|
||||||
|
@ -552,7 +548,7 @@ pub struct Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
fn get() -> Options {
|
fn get(device: &Device) -> Options {
|
||||||
let matches = App::new("tile-svg")
|
let matches = App::new("tile-svg")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("jobs")
|
Arg::with_name("jobs")
|
||||||
|
@ -570,13 +566,20 @@ impl Options {
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("INPUT").help("Path to the SVG file to render").index(1))
|
.arg(Arg::with_name("INPUT").help("Path to the SVG file to render").index(1))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let jobs: Option<usize> = matches
|
let jobs: Option<usize> = matches
|
||||||
.value_of("jobs")
|
.value_of("jobs")
|
||||||
.map(|string| string.parse().unwrap());
|
.map(|string| string.parse().unwrap());
|
||||||
let threed = matches.is_present("3d");
|
let threed = matches.is_present("3d");
|
||||||
|
|
||||||
let input_path = match matches.value_of("INPUT") {
|
let input_path = match matches.value_of("INPUT") {
|
||||||
Some(path) => PathBuf::from(path),
|
Some(path) => PathBuf::from(path),
|
||||||
None => PathBuf::from(DEFAULT_SVG_PATH),
|
None => {
|
||||||
|
let mut path = device.resources_directory.clone();
|
||||||
|
path.push("svg");
|
||||||
|
path.push(DEFAULT_SVG_FILENAME);
|
||||||
|
path
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set up Rayon.
|
// Set up Rayon.
|
||||||
|
@ -718,7 +721,10 @@ impl CameraTransform3D {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DemoDevice;
|
struct DemoDevice {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
device: Device,
|
||||||
|
}
|
||||||
|
|
||||||
impl DemoDevice {
|
impl DemoDevice {
|
||||||
fn clear(&self) {
|
fn clear(&self) {
|
||||||
|
@ -738,8 +744,8 @@ struct GroundProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GroundProgram {
|
impl GroundProgram {
|
||||||
fn new() -> GroundProgram {
|
fn new(device: &Device) -> GroundProgram {
|
||||||
let program = Program::new("demo_ground");
|
let program = device.create_program("demo_ground");
|
||||||
let transform_uniform = Uniform::new(&program, "Transform");
|
let transform_uniform = Uniform::new(&program, "Transform");
|
||||||
let color_uniform = Uniform::new(&program, "Color");
|
let color_uniform = Uniform::new(&program, "Color");
|
||||||
GroundProgram { program, transform_uniform, color_uniform }
|
GroundProgram { program, transform_uniform, color_uniform }
|
||||||
|
@ -769,6 +775,7 @@ impl GroundSolidVertexArray {
|
||||||
|
|
||||||
struct GroundLineVertexArray {
|
struct GroundLineVertexArray {
|
||||||
vertex_array: VertexArray,
|
vertex_array: VertexArray,
|
||||||
|
#[allow(dead_code)]
|
||||||
grid_vertex_positions_buffer: Buffer,
|
grid_vertex_positions_buffer: Buffer,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
use pathfinder_geometry::basic::rect::RectI32;
|
use pathfinder_geometry::basic::rect::RectI32;
|
||||||
use pathfinder_gl::debug::{BUTTON_HEIGHT, BUTTON_TEXT_OFFSET, BUTTON_WIDTH, DebugUI, PADDING};
|
use pathfinder_gl::debug::{BUTTON_HEIGHT, BUTTON_TEXT_OFFSET, BUTTON_WIDTH, DebugUI, PADDING};
|
||||||
use pathfinder_gl::debug::{TEXT_COLOR, WINDOW_COLOR};
|
use pathfinder_gl::debug::{TEXT_COLOR, WINDOW_COLOR};
|
||||||
use pathfinder_gl::device::Texture;
|
use pathfinder_gl::device::{Device, Texture};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -58,12 +58,12 @@ pub struct DemoUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DemoUI {
|
impl DemoUI {
|
||||||
pub fn new(options: Options) -> DemoUI {
|
pub fn new(device: &Device, options: Options) -> DemoUI {
|
||||||
let effects_texture = Texture::from_png(EFFECTS_PNG_NAME);
|
let effects_texture = device.create_texture_from_png(EFFECTS_PNG_NAME);
|
||||||
let open_texture = Texture::from_png(OPEN_PNG_NAME);
|
let open_texture = device.create_texture_from_png(OPEN_PNG_NAME);
|
||||||
let rotate_texture = Texture::from_png(ROTATE_PNG_NAME);
|
let rotate_texture = device.create_texture_from_png(ROTATE_PNG_NAME);
|
||||||
let zoom_in_texture = Texture::from_png(ZOOM_IN_PNG_NAME);
|
let zoom_in_texture = device.create_texture_from_png(ZOOM_IN_PNG_NAME);
|
||||||
let zoom_out_texture = Texture::from_png(ZOOM_OUT_PNG_NAME);
|
let zoom_out_texture = device.create_texture_from_png(ZOOM_OUT_PNG_NAME);
|
||||||
|
|
||||||
DemoUI {
|
DemoUI {
|
||||||
effects_texture,
|
effects_texture,
|
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "demo"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[dependencies.pathfinder_demo]
|
||||||
|
path = "../common"
|
|
@ -0,0 +1,17 @@
|
||||||
|
// pathfinder/demo/native/src/main.rs
|
||||||
|
//
|
||||||
|
// Copyright © 2019 The Pathfinder Project Developers.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! A demo app for Pathfinder.
|
||||||
|
|
||||||
|
use pathfinder_demo::DemoApp;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
DemoApp::new().run();
|
||||||
|
}
|
|
@ -15,7 +15,8 @@
|
||||||
//!
|
//!
|
||||||
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
||||||
|
|
||||||
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Program, Texture, Uniform, VertexAttr};
|
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Device, Program, Texture};
|
||||||
|
use crate::device::{Uniform, VertexAttr};
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use gl::types::{GLfloat, GLint, GLsizei, GLuint};
|
use gl::types::{GLfloat, GLint, GLsizei, GLuint};
|
||||||
use gl;
|
use gl;
|
||||||
|
@ -50,8 +51,7 @@ const ICON_SIZE: i32 = 48;
|
||||||
|
|
||||||
static INVERTED_TEXT_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 };
|
static INVERTED_TEXT_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 };
|
||||||
|
|
||||||
static JSON_PATH: &'static str = "resources/debug-font.json";
|
static FONT_JSON_FILENAME: &'static str = "debug-font.json";
|
||||||
|
|
||||||
static FONT_PNG_NAME: &'static str = "debug-font";
|
static FONT_PNG_NAME: &'static str = "debug-font";
|
||||||
|
|
||||||
static QUAD_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3];
|
static QUAD_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3];
|
||||||
|
@ -82,8 +82,11 @@ struct DebugCharacter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugFont {
|
impl DebugFont {
|
||||||
fn load() -> DebugFont {
|
fn load(device: &Device) -> DebugFont {
|
||||||
serde_json::from_reader(BufReader::new(File::open(JSON_PATH).unwrap())).unwrap()
|
let mut path = device.resources_directory.clone();
|
||||||
|
path.push(FONT_JSON_FILENAME);
|
||||||
|
|
||||||
|
serde_json::from_reader(BufReader::new(File::open(path).unwrap())).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,18 +105,18 @@ pub struct DebugUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugUI {
|
impl DebugUI {
|
||||||
pub fn new(framebuffer_size: &Size2D<u32>) -> DebugUI {
|
pub fn new(device: &Device, framebuffer_size: &Size2D<u32>) -> DebugUI {
|
||||||
let texture_program = DebugTextureProgram::new();
|
let texture_program = DebugTextureProgram::new(device);
|
||||||
let texture_vertex_array = DebugTextureVertexArray::new(&texture_program);
|
let texture_vertex_array = DebugTextureVertexArray::new(&texture_program);
|
||||||
let font = DebugFont::load();
|
let font = DebugFont::load(device);
|
||||||
|
|
||||||
let solid_program = DebugSolidProgram::new();
|
let solid_program = DebugSolidProgram::new(device);
|
||||||
let solid_vertex_array = DebugSolidVertexArray::new(&solid_program);
|
let solid_vertex_array = DebugSolidVertexArray::new(&solid_program);
|
||||||
solid_vertex_array.index_buffer.upload(&QUAD_INDICES,
|
solid_vertex_array.index_buffer.upload(&QUAD_INDICES,
|
||||||
BufferTarget::Index,
|
BufferTarget::Index,
|
||||||
BufferUploadMode::Static);
|
BufferUploadMode::Static);
|
||||||
|
|
||||||
let font_texture = Texture::from_png(FONT_PNG_NAME);
|
let font_texture = device.create_texture_from_png(FONT_PNG_NAME);
|
||||||
|
|
||||||
DebugUI {
|
DebugUI {
|
||||||
framebuffer_size: *framebuffer_size,
|
framebuffer_size: *framebuffer_size,
|
||||||
|
@ -392,8 +395,8 @@ struct DebugTextureProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugTextureProgram {
|
impl DebugTextureProgram {
|
||||||
fn new() -> DebugTextureProgram {
|
fn new(device: &Device) -> DebugTextureProgram {
|
||||||
let program = Program::new("debug_texture");
|
let program = device.create_program("debug_texture");
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
let texture_size_uniform = Uniform::new(&program, "TextureSize");
|
let texture_size_uniform = Uniform::new(&program, "TextureSize");
|
||||||
let texture_uniform = Uniform::new(&program, "Texture");
|
let texture_uniform = Uniform::new(&program, "Texture");
|
||||||
|
@ -415,8 +418,8 @@ struct DebugSolidProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugSolidProgram {
|
impl DebugSolidProgram {
|
||||||
fn new() -> DebugSolidProgram {
|
fn new(device: &Device) -> DebugSolidProgram {
|
||||||
let program = Program::new("debug_solid");
|
let program = device.create_program("debug_solid");
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
let color_uniform = Uniform::new(&program, "Color");
|
let color_uniform = Uniform::new(&program, "Color");
|
||||||
DebugSolidProgram { program, framebuffer_size_uniform, color_uniform }
|
DebugSolidProgram { program, framebuffer_size_uniform, color_uniform }
|
||||||
|
|
232
gl/src/device.rs
|
@ -12,12 +12,123 @@
|
||||||
|
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
||||||
|
use std::env;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
pub struct Device {
|
||||||
|
pub resources_directory: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Device {
|
||||||
|
Device { resources_directory: locate_resources_directory() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn create_texture_from_png(&self, name: &str) -> Texture {
|
||||||
|
let mut path = self.resources_directory.clone();
|
||||||
|
path.push("textures");
|
||||||
|
path.push(format!("{}.png", name));
|
||||||
|
|
||||||
|
let image = image::open(&path).unwrap().to_luma();
|
||||||
|
|
||||||
|
let mut texture = Texture {
|
||||||
|
gl_texture: 0,
|
||||||
|
size: Size2D::new(image.width(), image.height()),
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
gl::GenTextures(1, &mut texture.gl_texture);
|
||||||
|
texture.bind(0);
|
||||||
|
gl::TexImage2D(gl::TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
gl::RED as GLint,
|
||||||
|
image.width() as GLsizei,
|
||||||
|
image.height() as GLsizei,
|
||||||
|
0,
|
||||||
|
gl::RED,
|
||||||
|
gl::UNSIGNED_BYTE,
|
||||||
|
image.as_ptr() as *const GLvoid);
|
||||||
|
}
|
||||||
|
|
||||||
|
texture.set_parameters();
|
||||||
|
texture
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_shader(&self, name: &str, kind: ShaderKind) -> Shader {
|
||||||
|
let suffix = match kind { ShaderKind::Vertex => 'v', ShaderKind::Fragment => 'f' };
|
||||||
|
let mut path = self.resources_directory.clone();
|
||||||
|
path.push("shaders");
|
||||||
|
path.push(format!("{}.{}s.glsl", name, suffix));
|
||||||
|
|
||||||
|
let mut source = vec![];
|
||||||
|
File::open(&path).unwrap().read_to_end(&mut source).unwrap();
|
||||||
|
unsafe {
|
||||||
|
let gl_shader_kind = match kind {
|
||||||
|
ShaderKind::Vertex => gl::VERTEX_SHADER,
|
||||||
|
ShaderKind::Fragment => gl::FRAGMENT_SHADER,
|
||||||
|
};
|
||||||
|
let gl_shader = gl::CreateShader(gl_shader_kind);
|
||||||
|
gl::ShaderSource(gl_shader,
|
||||||
|
1,
|
||||||
|
[source.as_ptr() as *const GLchar].as_ptr(),
|
||||||
|
[source.len() as GLint].as_ptr());
|
||||||
|
gl::CompileShader(gl_shader);
|
||||||
|
|
||||||
|
let mut compile_status = 0;
|
||||||
|
gl::GetShaderiv(gl_shader, gl::COMPILE_STATUS, &mut compile_status);
|
||||||
|
if compile_status != gl::TRUE as GLint {
|
||||||
|
let mut info_log_length = 0;
|
||||||
|
gl::GetShaderiv(gl_shader, gl::INFO_LOG_LENGTH, &mut info_log_length);
|
||||||
|
let mut info_log = vec![0; info_log_length as usize];
|
||||||
|
gl::GetShaderInfoLog(gl_shader,
|
||||||
|
info_log.len() as GLint,
|
||||||
|
ptr::null_mut(),
|
||||||
|
info_log.as_mut_ptr() as *mut GLchar);
|
||||||
|
eprintln!("Shader info log:\n{}", String::from_utf8_lossy(&info_log));
|
||||||
|
panic!("{:?} shader '{}' compilation failed", kind, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader { gl_shader }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_program(&self, name: &str) -> Program {
|
||||||
|
let vertex_shader = self.create_shader(name, ShaderKind::Vertex);
|
||||||
|
let fragment_shader = self.create_shader(name, ShaderKind::Fragment);
|
||||||
|
|
||||||
|
let gl_program;
|
||||||
|
unsafe {
|
||||||
|
gl_program = gl::CreateProgram();
|
||||||
|
gl::AttachShader(gl_program, vertex_shader.gl_shader);
|
||||||
|
gl::AttachShader(gl_program, fragment_shader.gl_shader);
|
||||||
|
gl::LinkProgram(gl_program);
|
||||||
|
|
||||||
|
let mut link_status = 0;
|
||||||
|
gl::GetProgramiv(gl_program, gl::LINK_STATUS, &mut link_status);
|
||||||
|
if link_status != gl::TRUE as GLint {
|
||||||
|
let mut info_log_length = 0;
|
||||||
|
gl::GetProgramiv(gl_program, gl::INFO_LOG_LENGTH, &mut info_log_length);
|
||||||
|
let mut info_log = vec![0; info_log_length as usize];
|
||||||
|
gl::GetProgramInfoLog(gl_program,
|
||||||
|
info_log.len() as GLint,
|
||||||
|
ptr::null_mut(),
|
||||||
|
info_log.as_mut_ptr() as *mut GLchar);
|
||||||
|
eprintln!("Program info log:\n{}", String::from_utf8_lossy(&info_log));
|
||||||
|
panic!("Program '{}' linking failed", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Program { gl_program, vertex_shader, fragment_shader }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct VertexArray {
|
pub struct VertexArray {
|
||||||
pub gl_vertex_array: GLuint,
|
pub gl_vertex_array: GLuint,
|
||||||
}
|
}
|
||||||
|
@ -199,37 +310,6 @@ pub struct Program {
|
||||||
fragment_shader: Shader,
|
fragment_shader: Shader,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Program {
|
|
||||||
pub fn new(name: &'static str) -> Program {
|
|
||||||
let vertex_shader = Shader::new(name, ShaderKind::Vertex);
|
|
||||||
let fragment_shader = Shader::new(name, ShaderKind::Fragment);
|
|
||||||
|
|
||||||
let gl_program;
|
|
||||||
unsafe {
|
|
||||||
gl_program = gl::CreateProgram();
|
|
||||||
gl::AttachShader(gl_program, vertex_shader.gl_shader);
|
|
||||||
gl::AttachShader(gl_program, fragment_shader.gl_shader);
|
|
||||||
gl::LinkProgram(gl_program);
|
|
||||||
|
|
||||||
let mut link_status = 0;
|
|
||||||
gl::GetProgramiv(gl_program, gl::LINK_STATUS, &mut link_status);
|
|
||||||
if link_status != gl::TRUE as GLint {
|
|
||||||
let mut info_log_length = 0;
|
|
||||||
gl::GetProgramiv(gl_program, gl::INFO_LOG_LENGTH, &mut info_log_length);
|
|
||||||
let mut info_log = vec![0; info_log_length as usize];
|
|
||||||
gl::GetProgramInfoLog(gl_program,
|
|
||||||
info_log.len() as GLint,
|
|
||||||
ptr::null_mut(),
|
|
||||||
info_log.as_mut_ptr() as *mut GLchar);
|
|
||||||
eprintln!("Program info log:\n{}", String::from_utf8_lossy(&info_log));
|
|
||||||
panic!("Program '{}' linking failed", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Program { gl_program, vertex_shader, fragment_shader }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Program {
|
impl Drop for Program {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -242,44 +322,6 @@ struct Shader {
|
||||||
gl_shader: GLuint,
|
gl_shader: GLuint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shader {
|
|
||||||
fn new(name: &str, kind: ShaderKind) -> Shader {
|
|
||||||
let suffix = match kind { ShaderKind::Vertex => 'v', ShaderKind::Fragment => 'f' };
|
|
||||||
// FIXME(pcwalton): Put the shaders somewhere else. Maybe compile them in?
|
|
||||||
let path = format!("shaders/{}.{}s.glsl", name, suffix);
|
|
||||||
let mut source = vec![];
|
|
||||||
File::open(&path).unwrap().read_to_end(&mut source).unwrap();
|
|
||||||
unsafe {
|
|
||||||
let gl_shader_kind = match kind {
|
|
||||||
ShaderKind::Vertex => gl::VERTEX_SHADER,
|
|
||||||
ShaderKind::Fragment => gl::FRAGMENT_SHADER,
|
|
||||||
};
|
|
||||||
let gl_shader = gl::CreateShader(gl_shader_kind);
|
|
||||||
gl::ShaderSource(gl_shader,
|
|
||||||
1,
|
|
||||||
[source.as_ptr() as *const GLchar].as_ptr(),
|
|
||||||
[source.len() as GLint].as_ptr());
|
|
||||||
gl::CompileShader(gl_shader);
|
|
||||||
|
|
||||||
let mut compile_status = 0;
|
|
||||||
gl::GetShaderiv(gl_shader, gl::COMPILE_STATUS, &mut compile_status);
|
|
||||||
if compile_status != gl::TRUE as GLint {
|
|
||||||
let mut info_log_length = 0;
|
|
||||||
gl::GetShaderiv(gl_shader, gl::INFO_LOG_LENGTH, &mut info_log_length);
|
|
||||||
let mut info_log = vec![0; info_log_length as usize];
|
|
||||||
gl::GetShaderInfoLog(gl_shader,
|
|
||||||
info_log.len() as GLint,
|
|
||||||
ptr::null_mut(),
|
|
||||||
info_log.as_mut_ptr() as *mut GLchar);
|
|
||||||
eprintln!("Shader info log:\n{}", String::from_utf8_lossy(&info_log));
|
|
||||||
panic!("{:?} shader '{}' compilation failed", kind, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader { gl_shader }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Shader {
|
impl Drop for Shader {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -340,33 +382,6 @@ impl Texture {
|
||||||
texture
|
texture
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_png(name: &str) -> Texture {
|
|
||||||
let path = format!("resources/textures/{}.png", name);
|
|
||||||
let image = image::open(&path).unwrap().to_luma();
|
|
||||||
|
|
||||||
let mut texture = Texture {
|
|
||||||
gl_texture: 0,
|
|
||||||
size: Size2D::new(image.width(), image.height()),
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
gl::GenTextures(1, &mut texture.gl_texture);
|
|
||||||
texture.bind(0);
|
|
||||||
gl::TexImage2D(gl::TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
gl::RED as GLint,
|
|
||||||
image.width() as GLsizei,
|
|
||||||
image.height() as GLsizei,
|
|
||||||
0,
|
|
||||||
gl::RED,
|
|
||||||
gl::UNSIGNED_BYTE,
|
|
||||||
image.as_ptr() as *const GLvoid);
|
|
||||||
}
|
|
||||||
|
|
||||||
texture.set_parameters();
|
|
||||||
texture
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bind(&self, unit: u32) {
|
pub fn bind(&self, unit: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::ActiveTexture(gl::TEXTURE0 + unit);
|
gl::ActiveTexture(gl::TEXTURE0 + unit);
|
||||||
|
@ -458,3 +473,28 @@ impl TimerQuery {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(pcwalton): Do something better!
|
||||||
|
fn locate_resources_directory() -> PathBuf {
|
||||||
|
let mut parent_directory = env::current_dir().unwrap();
|
||||||
|
loop {
|
||||||
|
// So ugly :(
|
||||||
|
let mut resources_directory = parent_directory.clone();
|
||||||
|
resources_directory.push("resources");
|
||||||
|
if resources_directory.is_dir() {
|
||||||
|
let mut shaders_directory = resources_directory.clone();
|
||||||
|
let mut textures_directory = resources_directory.clone();
|
||||||
|
shaders_directory.push("shaders");
|
||||||
|
textures_directory.push("textures");
|
||||||
|
if shaders_directory.is_dir() && textures_directory.is_dir() {
|
||||||
|
return resources_directory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !parent_directory.pop() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("No suitable `resources/` directory found!");
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::debug::DebugUI;
|
use crate::debug::DebugUI;
|
||||||
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Framebuffer, Program, Texture};
|
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Device, Framebuffer, Program, Texture};
|
||||||
use crate::device::{TimerQuery, Uniform, VertexArray, VertexAttr};
|
use crate::device::{TimerQuery, Uniform, VertexArray, VertexAttr};
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use gl::types::{GLfloat, GLint};
|
use gl::types::{GLfloat, GLint};
|
||||||
|
@ -63,15 +63,15 @@ pub struct Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
pub fn new(main_framebuffer_size: &Size2D<u32>) -> Renderer {
|
pub fn new(device: &Device, main_framebuffer_size: &Size2D<u32>) -> Renderer {
|
||||||
let fill_program = FillProgram::new();
|
let fill_program = FillProgram::new(device);
|
||||||
let solid_tile_program = SolidTileProgram::new();
|
let solid_tile_program = SolidTileProgram::new(device);
|
||||||
let mask_tile_program = MaskTileProgram::new();
|
let mask_tile_program = MaskTileProgram::new(device);
|
||||||
|
|
||||||
let postprocess_program = PostprocessProgram::new();
|
let postprocess_program = PostprocessProgram::new(device);
|
||||||
|
|
||||||
let area_lut_texture = Texture::from_png("area-lut");
|
let area_lut_texture = device.create_texture_from_png("area-lut");
|
||||||
let gamma_lut_texture = Texture::from_png("gamma-lut");
|
let gamma_lut_texture = device.create_texture_from_png("gamma-lut");
|
||||||
|
|
||||||
let quad_vertex_positions_buffer = Buffer::new();
|
let quad_vertex_positions_buffer = Buffer::new();
|
||||||
quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS,
|
quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS,
|
||||||
|
@ -94,7 +94,7 @@ impl Renderer {
|
||||||
let fill_colors_texture = Texture::new_rgba(&Size2D::new(FILL_COLORS_TEXTURE_WIDTH,
|
let fill_colors_texture = Texture::new_rgba(&Size2D::new(FILL_COLORS_TEXTURE_WIDTH,
|
||||||
FILL_COLORS_TEXTURE_HEIGHT));
|
FILL_COLORS_TEXTURE_HEIGHT));
|
||||||
|
|
||||||
let debug_ui = DebugUI::new(main_framebuffer_size);
|
let debug_ui = DebugUI::new(device, main_framebuffer_size);
|
||||||
|
|
||||||
Renderer {
|
Renderer {
|
||||||
fill_program,
|
fill_program,
|
||||||
|
@ -509,8 +509,8 @@ struct FillProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FillProgram {
|
impl FillProgram {
|
||||||
fn new() -> FillProgram {
|
fn new(device: &Device) -> FillProgram {
|
||||||
let program = Program::new("fill");
|
let program = device.create_program("fill");
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||||
let area_lut_uniform = Uniform::new(&program, "AreaLUT");
|
let area_lut_uniform = Uniform::new(&program, "AreaLUT");
|
||||||
|
@ -528,8 +528,8 @@ struct SolidTileProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SolidTileProgram {
|
impl SolidTileProgram {
|
||||||
fn new() -> SolidTileProgram {
|
fn new(device: &Device) -> SolidTileProgram {
|
||||||
let program = Program::new("solid_tile");
|
let program = device.create_program("solid_tile");
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||||
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
||||||
|
@ -558,8 +558,8 @@ struct MaskTileProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaskTileProgram {
|
impl MaskTileProgram {
|
||||||
fn new() -> MaskTileProgram {
|
fn new(device: &Device) -> MaskTileProgram {
|
||||||
let program = Program::new("mask_tile");
|
let program = device.create_program("mask_tile");
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||||
let stencil_texture_uniform = Uniform::new(&program, "StencilTexture");
|
let stencil_texture_uniform = Uniform::new(&program, "StencilTexture");
|
||||||
|
@ -590,8 +590,8 @@ struct PostprocessProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PostprocessProgram {
|
impl PostprocessProgram {
|
||||||
fn new() -> PostprocessProgram {
|
fn new(device: &Device) -> PostprocessProgram {
|
||||||
let program = Program::new("post");
|
let program = device.create_program("post");
|
||||||
let source_uniform = Uniform::new(&program, "Source");
|
let source_uniform = Uniform::new(&program, "Source");
|
||||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||||
let kernel_uniform = Uniform::new(&program, "Kernel");
|
let kernel_uniform = Uniform::new(&program, "Kernel");
|
||||||
|
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 792 B After Width: | Height: | Size: 792 B |
Before Width: | Height: | Size: 546 B After Width: | Height: | Size: 546 B |
Before Width: | Height: | Size: 973 B After Width: | Height: | Size: 973 B |
Before Width: | Height: | Size: 879 B After Width: | Height: | Size: 879 B |
Before Width: | Height: | Size: 868 B After Width: | Height: | Size: 868 B |
Before Width: | Height: | Size: 388 B After Width: | Height: | Size: 388 B |