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"
|
||||
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)",
|
||||
"pathfinder_demo 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -521,6 +510,24 @@ dependencies = [
|
|||
"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]]
|
||||
name = "pathfinder_geometry"
|
||||
version = "0.3.0"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"demo",
|
||||
"demo/common",
|
||||
"demo/native",
|
||||
"geometry",
|
||||
"gl",
|
||||
"renderer",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "demo"
|
||||
name = "pathfinder_demo"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
|
@ -15,13 +15,13 @@ sdl2 = "0.32"
|
|||
usvg = "0.4"
|
||||
|
||||
[dependencies.pathfinder_geometry]
|
||||
path = "../geometry"
|
||||
path = "../../geometry"
|
||||
|
||||
[dependencies.pathfinder_gl]
|
||||
path = "../gl"
|
||||
path = "../../gl"
|
||||
|
||||
[dependencies.pathfinder_renderer]
|
||||
path = "../renderer"
|
||||
path = "../../renderer"
|
||||
|
||||
[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.
|
||||
//
|
||||
|
@ -19,7 +19,7 @@ use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32};
|
|||
use pathfinder_geometry::basic::rect::RectF32;
|
||||
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
||||
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::renderer::Renderer;
|
||||
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
|
||||
|
@ -46,7 +46,7 @@ use usvg::{Options as UsvgOptions, Tree};
|
|||
#[global_allocator]
|
||||
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_HEIGHT: u32 = 800;
|
||||
|
@ -71,11 +71,7 @@ const GRIDLINE_COUNT: u8 = 10;
|
|||
|
||||
mod ui;
|
||||
|
||||
fn main() {
|
||||
DemoApp::new().run();
|
||||
}
|
||||
|
||||
struct DemoApp {
|
||||
pub struct DemoApp {
|
||||
window: Window,
|
||||
#[allow(dead_code)]
|
||||
sdl_context: Sdl,
|
||||
|
@ -105,9 +101,7 @@ struct DemoApp {
|
|||
}
|
||||
|
||||
impl DemoApp {
|
||||
fn new() -> DemoApp {
|
||||
let options = Options::get();
|
||||
|
||||
pub fn new() -> DemoApp {
|
||||
let sdl_context = sdl2::init().unwrap();
|
||||
let sdl_video = sdl_context.video().unwrap();
|
||||
|
||||
|
@ -128,19 +122,21 @@ impl DemoApp {
|
|||
|
||||
let sdl_event_pump = sdl_context.event_pump().unwrap();
|
||||
|
||||
let device = Device::new();
|
||||
let options = Options::get(&device);
|
||||
|
||||
let (window_width, _) = window.size();
|
||||
let (drawable_width, drawable_height) = window.drawable_size();
|
||||
let drawable_size = Size2D::new(drawable_width, drawable_height);
|
||||
|
||||
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());
|
||||
update_drawable_size(&window, &scene_thread_proxy);
|
||||
|
||||
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();
|
||||
let ground_program = GroundProgram::new(&device);
|
||||
let ground_solid_vertex_array =
|
||||
GroundSolidVertexArray::new(&ground_program, &renderer.quad_vertex_positions_buffer());
|
||||
let ground_line_vertex_array = GroundLineVertexArray::new(&ground_program);
|
||||
|
@ -161,18 +157,18 @@ impl DemoApp {
|
|||
mouselook_enabled: false,
|
||||
dirty: true,
|
||||
|
||||
ui: DemoUI::new(options),
|
||||
ui: DemoUI::new(&device, options),
|
||||
scene_thread_proxy,
|
||||
renderer,
|
||||
|
||||
device: DemoDevice,
|
||||
device: DemoDevice { device },
|
||||
ground_program,
|
||||
ground_solid_vertex_array,
|
||||
ground_line_vertex_array,
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&mut self) {
|
||||
pub fn run(&mut self) {
|
||||
while !self.exit {
|
||||
// Update the scene.
|
||||
self.build_scene();
|
||||
|
@ -552,7 +548,7 @@ pub struct Options {
|
|||
}
|
||||
|
||||
impl Options {
|
||||
fn get() -> Options {
|
||||
fn get(device: &Device) -> Options {
|
||||
let matches = App::new("tile-svg")
|
||||
.arg(
|
||||
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))
|
||||
.get_matches();
|
||||
|
||||
let jobs: Option<usize> = matches
|
||||
.value_of("jobs")
|
||||
.map(|string| string.parse().unwrap());
|
||||
let threed = matches.is_present("3d");
|
||||
|
||||
let input_path = match matches.value_of("INPUT") {
|
||||
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.
|
||||
|
@ -718,7 +721,10 @@ impl CameraTransform3D {
|
|||
}
|
||||
}
|
||||
|
||||
struct DemoDevice;
|
||||
struct DemoDevice {
|
||||
#[allow(dead_code)]
|
||||
device: Device,
|
||||
}
|
||||
|
||||
impl DemoDevice {
|
||||
fn clear(&self) {
|
||||
|
@ -738,8 +744,8 @@ struct GroundProgram {
|
|||
}
|
||||
|
||||
impl GroundProgram {
|
||||
fn new() -> GroundProgram {
|
||||
let program = Program::new("demo_ground");
|
||||
fn new(device: &Device) -> GroundProgram {
|
||||
let program = device.create_program("demo_ground");
|
||||
let transform_uniform = Uniform::new(&program, "Transform");
|
||||
let color_uniform = Uniform::new(&program, "Color");
|
||||
GroundProgram { program, transform_uniform, color_uniform }
|
||||
|
@ -769,6 +775,7 @@ impl GroundSolidVertexArray {
|
|||
|
||||
struct GroundLineVertexArray {
|
||||
vertex_array: VertexArray,
|
||||
#[allow(dead_code)]
|
||||
grid_vertex_positions_buffer: Buffer,
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ use pathfinder_geometry::basic::point::Point2DI32;
|
|||
use pathfinder_geometry::basic::rect::RectI32;
|
||||
use pathfinder_gl::debug::{BUTTON_HEIGHT, BUTTON_TEXT_OFFSET, BUTTON_WIDTH, DebugUI, PADDING};
|
||||
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::path::PathBuf;
|
||||
|
||||
|
@ -58,12 +58,12 @@ pub struct DemoUI {
|
|||
}
|
||||
|
||||
impl DemoUI {
|
||||
pub fn new(options: Options) -> DemoUI {
|
||||
let effects_texture = Texture::from_png(EFFECTS_PNG_NAME);
|
||||
let open_texture = Texture::from_png(OPEN_PNG_NAME);
|
||||
let rotate_texture = Texture::from_png(ROTATE_PNG_NAME);
|
||||
let zoom_in_texture = Texture::from_png(ZOOM_IN_PNG_NAME);
|
||||
let zoom_out_texture = Texture::from_png(ZOOM_OUT_PNG_NAME);
|
||||
pub fn new(device: &Device, options: Options) -> DemoUI {
|
||||
let effects_texture = device.create_texture_from_png(EFFECTS_PNG_NAME);
|
||||
let open_texture = device.create_texture_from_png(OPEN_PNG_NAME);
|
||||
let rotate_texture = device.create_texture_from_png(ROTATE_PNG_NAME);
|
||||
let zoom_in_texture = device.create_texture_from_png(ZOOM_IN_PNG_NAME);
|
||||
let zoom_out_texture = device.create_texture_from_png(ZOOM_OUT_PNG_NAME);
|
||||
|
||||
DemoUI {
|
||||
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/
|
||||
|
||||
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 gl::types::{GLfloat, GLint, GLsizei, GLuint};
|
||||
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 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 QUAD_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3];
|
||||
|
@ -82,8 +82,11 @@ struct DebugCharacter {
|
|||
}
|
||||
|
||||
impl DebugFont {
|
||||
fn load() -> DebugFont {
|
||||
serde_json::from_reader(BufReader::new(File::open(JSON_PATH).unwrap())).unwrap()
|
||||
fn load(device: &Device) -> DebugFont {
|
||||
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 {
|
||||
pub fn new(framebuffer_size: &Size2D<u32>) -> DebugUI {
|
||||
let texture_program = DebugTextureProgram::new();
|
||||
pub fn new(device: &Device, framebuffer_size: &Size2D<u32>) -> DebugUI {
|
||||
let texture_program = DebugTextureProgram::new(device);
|
||||
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);
|
||||
solid_vertex_array.index_buffer.upload(&QUAD_INDICES,
|
||||
BufferTarget::Index,
|
||||
BufferUploadMode::Static);
|
||||
|
||||
let font_texture = Texture::from_png(FONT_PNG_NAME);
|
||||
let font_texture = device.create_texture_from_png(FONT_PNG_NAME);
|
||||
|
||||
DebugUI {
|
||||
framebuffer_size: *framebuffer_size,
|
||||
|
@ -392,8 +395,8 @@ struct DebugTextureProgram {
|
|||
}
|
||||
|
||||
impl DebugTextureProgram {
|
||||
fn new() -> DebugTextureProgram {
|
||||
let program = Program::new("debug_texture");
|
||||
fn new(device: &Device) -> DebugTextureProgram {
|
||||
let program = device.create_program("debug_texture");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let texture_size_uniform = Uniform::new(&program, "TextureSize");
|
||||
let texture_uniform = Uniform::new(&program, "Texture");
|
||||
|
@ -415,8 +418,8 @@ struct DebugSolidProgram {
|
|||
}
|
||||
|
||||
impl DebugSolidProgram {
|
||||
fn new() -> DebugSolidProgram {
|
||||
let program = Program::new("debug_solid");
|
||||
fn new(device: &Device) -> DebugSolidProgram {
|
||||
let program = device.create_program("debug_solid");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let color_uniform = Uniform::new(&program, "Color");
|
||||
DebugSolidProgram { program, framebuffer_size_uniform, color_uniform }
|
||||
|
|
232
gl/src/device.rs
|
@ -12,12 +12,123 @@
|
|||
|
||||
use euclid::Size2D;
|
||||
use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
||||
use std::env;
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
use std::path::PathBuf;
|
||||
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 gl_vertex_array: GLuint,
|
||||
}
|
||||
|
@ -199,37 +310,6 @@ pub struct Program {
|
|||
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 {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
@ -242,44 +322,6 @@ struct Shader {
|
|||
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 {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
@ -340,33 +382,6 @@ impl 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) {
|
||||
unsafe {
|
||||
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.
|
||||
|
||||
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 euclid::Size2D;
|
||||
use gl::types::{GLfloat, GLint};
|
||||
|
@ -63,15 +63,15 @@ pub struct Renderer {
|
|||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn new(main_framebuffer_size: &Size2D<u32>) -> Renderer {
|
||||
let fill_program = FillProgram::new();
|
||||
let solid_tile_program = SolidTileProgram::new();
|
||||
let mask_tile_program = MaskTileProgram::new();
|
||||
pub fn new(device: &Device, main_framebuffer_size: &Size2D<u32>) -> Renderer {
|
||||
let fill_program = FillProgram::new(device);
|
||||
let solid_tile_program = SolidTileProgram::new(device);
|
||||
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 gamma_lut_texture = Texture::from_png("gamma-lut");
|
||||
let area_lut_texture = device.create_texture_from_png("area-lut");
|
||||
let gamma_lut_texture = device.create_texture_from_png("gamma-lut");
|
||||
|
||||
let quad_vertex_positions_buffer = Buffer::new();
|
||||
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,
|
||||
FILL_COLORS_TEXTURE_HEIGHT));
|
||||
|
||||
let debug_ui = DebugUI::new(main_framebuffer_size);
|
||||
let debug_ui = DebugUI::new(device, main_framebuffer_size);
|
||||
|
||||
Renderer {
|
||||
fill_program,
|
||||
|
@ -509,8 +509,8 @@ struct FillProgram {
|
|||
}
|
||||
|
||||
impl FillProgram {
|
||||
fn new() -> FillProgram {
|
||||
let program = Program::new("fill");
|
||||
fn new(device: &Device) -> FillProgram {
|
||||
let program = device.create_program("fill");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let area_lut_uniform = Uniform::new(&program, "AreaLUT");
|
||||
|
@ -528,8 +528,8 @@ struct SolidTileProgram {
|
|||
}
|
||||
|
||||
impl SolidTileProgram {
|
||||
fn new() -> SolidTileProgram {
|
||||
let program = Program::new("solid_tile");
|
||||
fn new(device: &Device) -> SolidTileProgram {
|
||||
let program = device.create_program("solid_tile");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let fill_colors_texture_uniform = Uniform::new(&program, "FillColorsTexture");
|
||||
|
@ -558,8 +558,8 @@ struct MaskTileProgram {
|
|||
}
|
||||
|
||||
impl MaskTileProgram {
|
||||
fn new() -> MaskTileProgram {
|
||||
let program = Program::new("mask_tile");
|
||||
fn new(device: &Device) -> MaskTileProgram {
|
||||
let program = device.create_program("mask_tile");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
let tile_size_uniform = Uniform::new(&program, "TileSize");
|
||||
let stencil_texture_uniform = Uniform::new(&program, "StencilTexture");
|
||||
|
@ -590,8 +590,8 @@ struct PostprocessProgram {
|
|||
}
|
||||
|
||||
impl PostprocessProgram {
|
||||
fn new() -> PostprocessProgram {
|
||||
let program = Program::new("post");
|
||||
fn new(device: &Device) -> PostprocessProgram {
|
||||
let program = device.create_program("post");
|
||||
let source_uniform = Uniform::new(&program, "Source");
|
||||
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
|
||||
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 |