WIP: Factor out GL code
This commit is contained in:
parent
64b480fe32
commit
ae450b063e
|
@ -511,6 +511,7 @@ dependencies = [
|
|||
"nfd 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_geometry 0.3.0",
|
||||
"pathfinder_gl 0.1.0",
|
||||
"pathfinder_gpu 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)",
|
||||
|
@ -537,12 +538,23 @@ dependencies = [
|
|||
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_geometry 0.3.0",
|
||||
"pathfinder_gpu 0.1.0",
|
||||
"pathfinder_renderer 0.1.0",
|
||||
"pathfinder_simd 0.3.0",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_gpu"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pathfinder_geometry 0.3.0",
|
||||
"pathfinder_simd 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_renderer"
|
||||
version = "0.1.0"
|
||||
|
@ -570,6 +582,10 @@ dependencies = [
|
|||
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinder_ui"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.7.24"
|
||||
|
@ -1045,10 +1061,6 @@ name = "ucd-util"
|
|||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ui"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.2.1"
|
||||
|
|
|
@ -4,6 +4,7 @@ members = [
|
|||
"demo/native",
|
||||
"geometry",
|
||||
"gl",
|
||||
"gpu",
|
||||
"renderer",
|
||||
"simd",
|
||||
"svg",
|
||||
|
|
|
@ -24,6 +24,9 @@ path = "../../geometry"
|
|||
[dependencies.pathfinder_gl]
|
||||
path = "../../gl"
|
||||
|
||||
[dependencies.pathfinder_gpu]
|
||||
path = "../../gpu"
|
||||
|
||||
[dependencies.pathfinder_renderer]
|
||||
path = "../../renderer"
|
||||
|
||||
|
|
|
@ -11,11 +11,9 @@
|
|||
//! GPU rendering code specifically for the demo.
|
||||
|
||||
use crate::GRIDLINE_COUNT;
|
||||
use gl::types::{GLsizei, GLvoid};
|
||||
use pathfinder_gl::device::{Buffer, BufferTarget, BufferUploadMode, Device, Program, Uniform};
|
||||
use pathfinder_gl::device::{VertexArray, VertexAttr};
|
||||
use pathfinder_renderer::paint::ColorU;
|
||||
use pathfinder_gpu::{BufferTarget, BufferUploadMode, Device, Resources, VertexAttrType};
|
||||
|
||||
/*
|
||||
pub struct DemoDevice {
|
||||
#[allow(dead_code)]
|
||||
device: Device,
|
||||
|
@ -62,65 +60,67 @@ impl DemoDevice {
|
|||
pixels
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub struct GroundProgram {
|
||||
pub program: Program,
|
||||
pub transform_uniform: Uniform,
|
||||
pub color_uniform: Uniform,
|
||||
pub struct GroundProgram<D> where D: Device {
|
||||
pub program: D::Program,
|
||||
pub transform_uniform: D::Uniform,
|
||||
pub color_uniform: D::Uniform,
|
||||
}
|
||||
|
||||
impl GroundProgram {
|
||||
pub 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");
|
||||
impl<D> GroundProgram<D> where D: Device {
|
||||
pub fn new(device: &D, resources: &Resources) -> GroundProgram<D> {
|
||||
let program = device.create_program(resources, "demo_ground");
|
||||
let transform_uniform = device.get_uniform(&program, "Transform");
|
||||
let color_uniform = device.get_uniform(&program, "Color");
|
||||
GroundProgram { program, transform_uniform, color_uniform }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GroundSolidVertexArray {
|
||||
pub vertex_array: VertexArray,
|
||||
pub struct GroundSolidVertexArray<D> where D: Device {
|
||||
pub vertex_array: D::VertexArray,
|
||||
}
|
||||
|
||||
impl GroundSolidVertexArray {
|
||||
pub fn new(ground_program: &GroundProgram, quad_vertex_positions_buffer: &Buffer)
|
||||
-> GroundSolidVertexArray {
|
||||
let vertex_array = VertexArray::new();
|
||||
unsafe {
|
||||
let position_attr = VertexAttr::new(&ground_program.program, "Position");
|
||||
impl<D> GroundSolidVertexArray<D> where D: Device {
|
||||
pub fn new(device: &D,
|
||||
ground_program: &GroundProgram<D>,
|
||||
quad_vertex_positions_buffer: &D::Buffer)
|
||||
-> GroundSolidVertexArray<D> {
|
||||
let vertex_array = device.create_vertex_array();
|
||||
|
||||
gl::BindVertexArray(vertex_array.gl_vertex_array);
|
||||
gl::UseProgram(ground_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
|
||||
position_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||
}
|
||||
let position_attr = device.get_vertex_attr(&ground_program.program, "Position");
|
||||
|
||||
device.bind_vertex_array(&vertex_array);
|
||||
device.use_program(&ground_program.program);
|
||||
device.bind_buffer(quad_vertex_positions_buffer, BufferTarget::Vertex);
|
||||
device.configure_float_vertex_attr(&position_attr, 2, VertexAttrType::U8, false, 0, 0, 0);
|
||||
|
||||
GroundSolidVertexArray { vertex_array }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GroundLineVertexArray {
|
||||
pub vertex_array: VertexArray,
|
||||
pub struct GroundLineVertexArray<D> where D: Device {
|
||||
pub vertex_array: D::VertexArray,
|
||||
#[allow(dead_code)]
|
||||
grid_vertex_positions_buffer: Buffer,
|
||||
grid_vertex_positions_buffer: D::Buffer,
|
||||
}
|
||||
|
||||
impl GroundLineVertexArray {
|
||||
pub fn new(ground_program: &GroundProgram) -> GroundLineVertexArray {
|
||||
let grid_vertex_positions_buffer = Buffer::new();
|
||||
grid_vertex_positions_buffer.upload(&create_grid_vertex_positions(),
|
||||
impl<D> GroundLineVertexArray<D> where D: Device {
|
||||
pub fn new(device: &D, ground_program: &GroundProgram<D>) -> GroundLineVertexArray<D> {
|
||||
let grid_vertex_positions_buffer = device.create_buffer();
|
||||
device.upload_to_buffer(&grid_vertex_positions_buffer,
|
||||
&create_grid_vertex_positions(),
|
||||
BufferTarget::Vertex,
|
||||
BufferUploadMode::Static);
|
||||
|
||||
let vertex_array = VertexArray::new();
|
||||
unsafe {
|
||||
let position_attr = VertexAttr::new(&ground_program.program, "Position");
|
||||
let vertex_array = device.create_vertex_array();
|
||||
|
||||
gl::BindVertexArray(vertex_array.gl_vertex_array);
|
||||
gl::UseProgram(ground_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, grid_vertex_positions_buffer.gl_buffer);
|
||||
position_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
|
||||
}
|
||||
let position_attr = device.get_vertex_attr(&ground_program.program, "Position");
|
||||
|
||||
device.bind_vertex_array(&vertex_array);
|
||||
device.use_program(&ground_program.program);
|
||||
device.bind_buffer(&grid_vertex_positions_buffer, BufferTarget::Vertex);
|
||||
device.configure_float_vertex_attr(&position_attr, 2, VertexAttrType::U8, false, 0, 0, 0);
|
||||
|
||||
GroundLineVertexArray { vertex_array, grid_vertex_positions_buffer }
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
//! A demo app for Pathfinder.
|
||||
|
||||
use crate::device::{DemoDevice, GroundLineVertexArray, GroundProgram, GroundSolidVertexArray};
|
||||
use crate::device::{GroundLineVertexArray, GroundProgram, GroundSolidVertexArray};
|
||||
use crate::ui::{DemoUI, UIAction, UIEvent};
|
||||
use clap::{App, Arg};
|
||||
use gl::types::GLsizei;
|
||||
|
@ -20,8 +20,9 @@ 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::Device;
|
||||
use pathfinder_gl::device::GLDevice;
|
||||
use pathfinder_gl::renderer::Renderer;
|
||||
use pathfinder_gpu::{Device, Resources};
|
||||
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
|
||||
use pathfinder_renderer::gpu_data::BuiltScene;
|
||||
use pathfinder_renderer::paint::ColorU;
|
||||
|
@ -96,14 +97,13 @@ pub struct DemoApp {
|
|||
mouselook_enabled: bool,
|
||||
dirty: bool,
|
||||
|
||||
ui: DemoUI,
|
||||
ui: DemoUI<GLDevice>,
|
||||
scene_thread_proxy: SceneThreadProxy,
|
||||
renderer: Renderer,
|
||||
renderer: Renderer<GLDevice>,
|
||||
|
||||
device: DemoDevice,
|
||||
ground_program: GroundProgram,
|
||||
ground_solid_vertex_array: GroundSolidVertexArray,
|
||||
ground_line_vertex_array: GroundLineVertexArray,
|
||||
ground_program: GroundProgram<GLDevice>,
|
||||
ground_solid_vertex_array: GroundSolidVertexArray<GLDevice>,
|
||||
ground_line_vertex_array: GroundLineVertexArray<GLDevice>,
|
||||
}
|
||||
|
||||
impl DemoApp {
|
||||
|
@ -130,8 +130,9 @@ impl DemoApp {
|
|||
|
||||
let sdl_event_pump = sdl_context.event_pump().unwrap();
|
||||
|
||||
let device = Device::new();
|
||||
let options = Options::get(&device);
|
||||
let device = GLDevice::new();
|
||||
let resources = Resources::locate();
|
||||
let options = Options::get(&resources);
|
||||
|
||||
let (window_width, _) = window.size();
|
||||
let (drawable_width, drawable_height) = window.drawable_size();
|
||||
|
@ -139,7 +140,7 @@ impl DemoApp {
|
|||
|
||||
let base_scene = load_scene(&options.input_path);
|
||||
let scene_view_box = base_scene.view_box;
|
||||
let renderer = Renderer::new(&device, drawable_size);
|
||||
let renderer = Renderer::new(device, &resources, drawable_size);
|
||||
let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone());
|
||||
update_drawable_size(&window, &scene_thread_proxy);
|
||||
|
||||
|
@ -149,10 +150,15 @@ impl DemoApp {
|
|||
Camera::new_2d(scene_view_box, drawable_size)
|
||||
};
|
||||
|
||||
let ground_program = GroundProgram::new(&device);
|
||||
let ground_program = GroundProgram::new(&renderer.device, &resources);
|
||||
let ground_solid_vertex_array =
|
||||
GroundSolidVertexArray::new(&ground_program, &renderer.quad_vertex_positions_buffer());
|
||||
let ground_line_vertex_array = GroundLineVertexArray::new(&ground_program);
|
||||
GroundSolidVertexArray::new(&renderer.device,
|
||||
&ground_program,
|
||||
&renderer.quad_vertex_positions_buffer());
|
||||
let ground_line_vertex_array = GroundLineVertexArray::new(&renderer.device,
|
||||
&ground_program);
|
||||
|
||||
let ui = DemoUI::new(&renderer.device, &resources, options);
|
||||
|
||||
DemoApp {
|
||||
window,
|
||||
|
@ -173,11 +179,10 @@ impl DemoApp {
|
|||
mouselook_enabled: false,
|
||||
dirty: true,
|
||||
|
||||
ui: DemoUI::new(&device, options),
|
||||
ui,
|
||||
scene_thread_proxy,
|
||||
renderer,
|
||||
|
||||
device: DemoDevice::new(device),
|
||||
ground_program,
|
||||
ground_solid_vertex_array,
|
||||
ground_line_vertex_array,
|
||||
|
@ -342,7 +347,7 @@ impl DemoApp {
|
|||
tile_time,
|
||||
} = render_msg;
|
||||
|
||||
self.device.clear(self.background_color());
|
||||
self.renderer.device.clear(Some(self.background_color().to_f32().0), Some(1.0), Some(0));
|
||||
self.draw_environment(&render_transform);
|
||||
self.render_vector_scene(&built_scene);
|
||||
|
||||
|
@ -353,14 +358,17 @@ impl DemoApp {
|
|||
let rendering_time = self.renderer.shift_timer_query();
|
||||
let stats = built_scene.stats();
|
||||
self.renderer.debug_ui.add_sample(stats, tile_time, rendering_time);
|
||||
self.renderer.debug_ui.draw();
|
||||
self.renderer.debug_ui.draw(&self.renderer.device);
|
||||
|
||||
if !ui_event.is_none() {
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
let mut ui_action = UIAction::None;
|
||||
self.ui.update(&mut self.renderer.debug_ui, &mut ui_event, &mut ui_action);
|
||||
self.ui.update(&self.renderer.device,
|
||||
&mut self.renderer.debug_ui,
|
||||
&mut ui_event,
|
||||
&mut ui_action);
|
||||
self.handle_ui_action(&mut ui_action);
|
||||
|
||||
// Switch camera mode (2D/3D) if requested.
|
||||
|
@ -548,7 +556,8 @@ impl DemoApp {
|
|||
fn take_screenshot(&mut self) {
|
||||
let screenshot_path = self.pending_screenshot_path.take().unwrap();
|
||||
let (drawable_width, drawable_height) = self.window.drawable_size();
|
||||
let pixels = self.device.readback_pixels(drawable_width, drawable_height);
|
||||
let drawable_size = Point2DI32::new(drawable_width as i32, drawable_height as i32);
|
||||
let pixels = self.renderer.device.read_pixels_from_default_framebuffer(drawable_size);
|
||||
image::save_buffer(screenshot_path,
|
||||
&pixels,
|
||||
drawable_width,
|
||||
|
@ -644,7 +653,7 @@ pub struct Options {
|
|||
}
|
||||
|
||||
impl Options {
|
||||
fn get(device: &Device) -> Options {
|
||||
fn get(resources: &Resources) -> Options {
|
||||
let matches = App::new("tile-svg")
|
||||
.arg(
|
||||
Arg::with_name("jobs")
|
||||
|
@ -666,7 +675,7 @@ impl Options {
|
|||
let input_path = match matches.value_of("INPUT") {
|
||||
Some(path) => PathBuf::from(path),
|
||||
None => {
|
||||
let mut path = device.resources_directory.clone();
|
||||
let mut path = resources.resources_directory.clone();
|
||||
path.push("svg");
|
||||
path.push(DEFAULT_SVG_FILENAME);
|
||||
path
|
||||
|
|
|
@ -13,7 +13,7 @@ use nfd::Response;
|
|||
use pathfinder_geometry::basic::point::Point2DI32;
|
||||
use pathfinder_geometry::basic::rect::RectI32;
|
||||
use pathfinder_gl::debug::{DebugUI, PADDING, TEXT_COLOR, WINDOW_COLOR};
|
||||
use pathfinder_gl::device::{Device, Texture};
|
||||
use pathfinder_gpu::{Device, Resources};
|
||||
use pathfinder_renderer::paint::ColorU;
|
||||
use std::f32::consts::PI;
|
||||
use std::path::PathBuf;
|
||||
|
@ -57,15 +57,15 @@ static BG_LIGHT_PNG_NAME: &'static str = "demo-bg-light";
|
|||
static BG_DARK_PNG_NAME: &'static str = "demo-bg-dark";
|
||||
static SCREENSHOT_PNG_NAME: &'static str = "demo-screenshot";
|
||||
|
||||
pub struct DemoUI {
|
||||
effects_texture: Texture,
|
||||
open_texture: Texture,
|
||||
rotate_texture: Texture,
|
||||
zoom_in_texture: Texture,
|
||||
zoom_out_texture: Texture,
|
||||
bg_light_texture: Texture,
|
||||
bg_dark_texture: Texture,
|
||||
screenshot_texture: Texture,
|
||||
pub struct DemoUI<D> where D: Device {
|
||||
effects_texture: D::Texture,
|
||||
open_texture: D::Texture,
|
||||
rotate_texture: D::Texture,
|
||||
zoom_in_texture: D::Texture,
|
||||
zoom_out_texture: D::Texture,
|
||||
bg_light_texture: D::Texture,
|
||||
bg_dark_texture: D::Texture,
|
||||
screenshot_texture: D::Texture,
|
||||
|
||||
effects_panel_visible: bool,
|
||||
rotate_panel_visible: bool,
|
||||
|
@ -78,16 +78,16 @@ pub struct DemoUI {
|
|||
pub rotation: i32,
|
||||
}
|
||||
|
||||
impl DemoUI {
|
||||
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);
|
||||
let bg_light_texture = device.create_texture_from_png(BG_LIGHT_PNG_NAME);
|
||||
let bg_dark_texture = device.create_texture_from_png(BG_DARK_PNG_NAME);
|
||||
let screenshot_texture = device.create_texture_from_png(SCREENSHOT_PNG_NAME);
|
||||
impl<D> DemoUI<D> where D: Device {
|
||||
pub fn new(device: &D, resources: &Resources, options: Options) -> DemoUI<D> {
|
||||
let effects_texture = device.create_texture_from_png(resources, EFFECTS_PNG_NAME);
|
||||
let open_texture = device.create_texture_from_png(resources, OPEN_PNG_NAME);
|
||||
let rotate_texture = device.create_texture_from_png(resources, ROTATE_PNG_NAME);
|
||||
let zoom_in_texture = device.create_texture_from_png(resources, ZOOM_IN_PNG_NAME);
|
||||
let zoom_out_texture = device.create_texture_from_png(resources, ZOOM_OUT_PNG_NAME);
|
||||
let bg_light_texture = device.create_texture_from_png(resources, BG_LIGHT_PNG_NAME);
|
||||
let bg_dark_texture = device.create_texture_from_png(resources, BG_DARK_PNG_NAME);
|
||||
let screenshot_texture = device.create_texture_from_png(resources, SCREENSHOT_PNG_NAME);
|
||||
|
||||
DemoUI {
|
||||
effects_texture,
|
||||
|
@ -115,19 +115,27 @@ impl DemoUI {
|
|||
(self.rotation as f32 / SLIDER_WIDTH as f32 * 2.0 - 1.0) * PI
|
||||
}
|
||||
|
||||
pub fn update(&mut self, debug_ui: &mut DebugUI, event: &mut UIEvent, action: &mut UIAction) {
|
||||
pub fn update(&mut self,
|
||||
device: &D,
|
||||
debug_ui: &mut DebugUI<D>,
|
||||
event: &mut UIEvent,
|
||||
action: &mut UIAction) {
|
||||
let bottom = debug_ui.framebuffer_size().y() - PADDING;
|
||||
|
||||
// Draw effects button.
|
||||
let effects_button_position = Point2DI32::new(PADDING, bottom - BUTTON_HEIGHT);
|
||||
if self.draw_button(debug_ui, event, effects_button_position, &self.effects_texture) {
|
||||
if self.draw_button(device,
|
||||
debug_ui,
|
||||
event,
|
||||
effects_button_position,
|
||||
&self.effects_texture) {
|
||||
self.effects_panel_visible = !self.effects_panel_visible;
|
||||
}
|
||||
|
||||
// Draw open button.
|
||||
let lower_button_y = bottom - BUTTON_HEIGHT;
|
||||
let open_button_position = Point2DI32::new(OPEN_BUTTON_X, lower_button_y);
|
||||
if self.draw_button(debug_ui, event, open_button_position, &self.open_texture) {
|
||||
if self.draw_button(device, debug_ui, event, open_button_position, &self.open_texture) {
|
||||
if let Ok(Response::Okay(file)) = nfd::open_file_dialog(Some("svg"), None) {
|
||||
*action = UIAction::OpenFile(PathBuf::from(file));
|
||||
}
|
||||
|
@ -135,7 +143,8 @@ impl DemoUI {
|
|||
|
||||
// Draw screenshot button.
|
||||
let screenshot_button_position = Point2DI32::new(SCREENSHOT_BUTTON_X, lower_button_y);
|
||||
if self.draw_button(debug_ui,
|
||||
if self.draw_button(device,
|
||||
debug_ui,
|
||||
event,
|
||||
screenshot_button_position,
|
||||
&self.screenshot_texture) {
|
||||
|
@ -146,7 +155,8 @@ impl DemoUI {
|
|||
|
||||
// Draw 3D switch.
|
||||
let three_d_switch_origin = Point2DI32::new(THREE_D_SWITCH_X, lower_button_y);
|
||||
self.three_d_enabled = self.draw_text_switch(debug_ui,
|
||||
self.three_d_enabled = self.draw_text_switch(device,
|
||||
debug_ui,
|
||||
event,
|
||||
three_d_switch_origin,
|
||||
"2D",
|
||||
|
@ -155,7 +165,8 @@ impl DemoUI {
|
|||
|
||||
// Draw background switch.
|
||||
let background_switch_origin = Point2DI32::new(BACKGROUND_SWITCH_X, lower_button_y);
|
||||
self.dark_background_enabled = self.draw_image_switch(debug_ui,
|
||||
self.dark_background_enabled = self.draw_image_switch(device,
|
||||
debug_ui,
|
||||
event,
|
||||
background_switch_origin,
|
||||
&self.bg_light_texture,
|
||||
|
@ -166,19 +177,28 @@ impl DemoUI {
|
|||
if !self.three_d_enabled {
|
||||
let rotate_button_y = bottom - BUTTON_HEIGHT;
|
||||
let rotate_button_position = Point2DI32::new(ROTATE_PANEL_X, rotate_button_y);
|
||||
if self.draw_button(debug_ui, event, rotate_button_position, &self.rotate_texture) {
|
||||
if self.draw_button(device,
|
||||
debug_ui,
|
||||
event,
|
||||
rotate_button_position,
|
||||
&self.rotate_texture) {
|
||||
self.rotate_panel_visible = !self.rotate_panel_visible;
|
||||
}
|
||||
|
||||
let zoom_in_button_x = ROTATE_PANEL_X + BUTTON_WIDTH + PADDING;
|
||||
let zoom_in_button_position = Point2DI32::new(zoom_in_button_x, rotate_button_y);
|
||||
if self.draw_button(debug_ui, event, zoom_in_button_position, &self.zoom_in_texture) {
|
||||
if self.draw_button(device,
|
||||
debug_ui,
|
||||
event,
|
||||
zoom_in_button_position,
|
||||
&self.zoom_in_texture) {
|
||||
*action = UIAction::ZoomIn;
|
||||
}
|
||||
|
||||
let zoom_out_button_x = ROTATE_PANEL_X + (BUTTON_WIDTH + PADDING) * 2;
|
||||
let zoom_out_button_position = Point2DI32::new(zoom_out_button_x, rotate_button_y);
|
||||
if self.draw_button(debug_ui,
|
||||
if self.draw_button(device,
|
||||
debug_ui,
|
||||
event,
|
||||
zoom_out_button_position,
|
||||
&self.zoom_out_texture) {
|
||||
|
@ -187,40 +207,44 @@ impl DemoUI {
|
|||
}
|
||||
|
||||
// Draw effects panel, if necessary.
|
||||
self.draw_effects_panel(debug_ui, event);
|
||||
self.draw_effects_panel(device, debug_ui, event);
|
||||
|
||||
// Draw rotate panel, if necessary.
|
||||
self.draw_rotate_panel(debug_ui, event, action);
|
||||
self.draw_rotate_panel(device, debug_ui, event, action);
|
||||
}
|
||||
|
||||
fn draw_effects_panel(&mut self, debug_ui: &mut DebugUI, event: &mut UIEvent) {
|
||||
fn draw_effects_panel(&mut self, device: &D, debug_ui: &mut DebugUI<D>, event: &mut UIEvent) {
|
||||
if !self.effects_panel_visible {
|
||||
return;
|
||||
}
|
||||
|
||||
let bottom = debug_ui.framebuffer_size().y() - PADDING;
|
||||
let effects_panel_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_PANEL_HEIGHT);
|
||||
debug_ui.draw_solid_rounded_rect(RectI32::new(Point2DI32::new(PADDING, effects_panel_y),
|
||||
debug_ui.draw_solid_rounded_rect(device,
|
||||
RectI32::new(Point2DI32::new(PADDING, effects_panel_y),
|
||||
Point2DI32::new(EFFECTS_PANEL_WIDTH,
|
||||
EFFECTS_PANEL_HEIGHT)),
|
||||
WINDOW_COLOR);
|
||||
|
||||
self.gamma_correction_effect_enabled =
|
||||
self.draw_effects_switch(debug_ui,
|
||||
self.draw_effects_switch(device,
|
||||
debug_ui,
|
||||
event,
|
||||
"Gamma Correction",
|
||||
0,
|
||||
effects_panel_y,
|
||||
self.gamma_correction_effect_enabled);
|
||||
self.stem_darkening_effect_enabled =
|
||||
self.draw_effects_switch(debug_ui,
|
||||
self.draw_effects_switch(device,
|
||||
debug_ui,
|
||||
event,
|
||||
"Stem Darkening",
|
||||
1,
|
||||
effects_panel_y,
|
||||
self.stem_darkening_effect_enabled);
|
||||
self.subpixel_aa_effect_enabled =
|
||||
self.draw_effects_switch(debug_ui,
|
||||
self.draw_effects_switch(device,
|
||||
debug_ui,
|
||||
event,
|
||||
"Subpixel AA",
|
||||
2,
|
||||
|
@ -230,7 +254,8 @@ impl DemoUI {
|
|||
}
|
||||
|
||||
fn draw_rotate_panel(&mut self,
|
||||
debug_ui: &mut DebugUI,
|
||||
device: &D,
|
||||
debug_ui: &mut DebugUI<D>,
|
||||
event: &mut UIEvent,
|
||||
action: &mut UIAction) {
|
||||
if !self.rotate_panel_visible {
|
||||
|
@ -241,7 +266,8 @@ impl DemoUI {
|
|||
let rotate_panel_y = bottom - (BUTTON_HEIGHT + PADDING + ROTATE_PANEL_HEIGHT);
|
||||
let rotate_panel_origin = Point2DI32::new(ROTATE_PANEL_X, rotate_panel_y);
|
||||
let rotate_panel_size = Point2DI32::new(ROTATE_PANEL_WIDTH, ROTATE_PANEL_HEIGHT);
|
||||
debug_ui.draw_solid_rounded_rect(RectI32::new(rotate_panel_origin, rotate_panel_size),
|
||||
debug_ui.draw_solid_rounded_rect(device,
|
||||
RectI32::new(rotate_panel_origin, rotate_panel_size),
|
||||
WINDOW_COLOR);
|
||||
|
||||
let (widget_x, widget_y) = (ROTATE_PANEL_X + PADDING, rotate_panel_y + PADDING);
|
||||
|
@ -257,32 +283,35 @@ impl DemoUI {
|
|||
let slider_track_rect =
|
||||
RectI32::new(Point2DI32::new(widget_x, slider_track_y),
|
||||
Point2DI32::new(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT));
|
||||
debug_ui.draw_rect_outline(slider_track_rect, TEXT_COLOR);
|
||||
debug_ui.draw_rect_outline(device, slider_track_rect, TEXT_COLOR);
|
||||
|
||||
let slider_knob_x = widget_x + self.rotation - SLIDER_KNOB_WIDTH / 2;
|
||||
let slider_knob_rect =
|
||||
RectI32::new(Point2DI32::new(slider_knob_x, widget_y),
|
||||
Point2DI32::new(SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT));
|
||||
debug_ui.draw_solid_rect(slider_knob_rect, TEXT_COLOR);
|
||||
debug_ui.draw_solid_rect(device, slider_knob_rect, TEXT_COLOR);
|
||||
}
|
||||
|
||||
fn draw_button(&self,
|
||||
debug_ui: &mut DebugUI,
|
||||
device: &D,
|
||||
debug_ui: &mut DebugUI<D>,
|
||||
event: &mut UIEvent,
|
||||
origin: Point2DI32,
|
||||
texture: &Texture)
|
||||
texture: &D::Texture)
|
||||
-> bool {
|
||||
let button_rect = RectI32::new(origin, Point2DI32::new(BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||
debug_ui.draw_solid_rounded_rect(button_rect, WINDOW_COLOR);
|
||||
debug_ui.draw_rounded_rect_outline(button_rect, OUTLINE_COLOR);
|
||||
debug_ui.draw_texture(origin + Point2DI32::new(PADDING, PADDING),
|
||||
debug_ui.draw_solid_rounded_rect(device, button_rect, WINDOW_COLOR);
|
||||
debug_ui.draw_rounded_rect_outline(device, button_rect, OUTLINE_COLOR);
|
||||
debug_ui.draw_texture(device,
|
||||
origin + Point2DI32::new(PADDING, PADDING),
|
||||
texture,
|
||||
BUTTON_ICON_COLOR);
|
||||
event.handle_mouse_down_in_rect(button_rect).is_some()
|
||||
}
|
||||
|
||||
fn draw_effects_switch(&self,
|
||||
debug_ui: &mut DebugUI,
|
||||
device: &D,
|
||||
debug_ui: &mut DebugUI<D>,
|
||||
event: &mut UIEvent,
|
||||
text: &str,
|
||||
index: i32,
|
||||
|
@ -291,11 +320,12 @@ impl DemoUI {
|
|||
-> bool {
|
||||
let text_x = PADDING * 2;
|
||||
let text_y = window_y + PADDING + BUTTON_TEXT_OFFSET + (BUTTON_HEIGHT + PADDING) * index;
|
||||
debug_ui.draw_text(text, Point2DI32::new(text_x, text_y), false);
|
||||
debug_ui.draw_text(device, text, Point2DI32::new(text_x, text_y), false);
|
||||
|
||||
let switch_x = PADDING + EFFECTS_PANEL_WIDTH - (SWITCH_SIZE + PADDING);
|
||||
let switch_y = window_y + PADDING + (BUTTON_HEIGHT + PADDING) * index;
|
||||
self.draw_text_switch(debug_ui,
|
||||
self.draw_text_switch(device,
|
||||
debug_ui,
|
||||
event,
|
||||
Point2DI32::new(switch_x, switch_y),
|
||||
"Off",
|
||||
|
@ -304,14 +334,15 @@ impl DemoUI {
|
|||
}
|
||||
|
||||
fn draw_text_switch(&self,
|
||||
debug_ui: &mut DebugUI,
|
||||
device: &D,
|
||||
debug_ui: &mut DebugUI<D>,
|
||||
event: &mut UIEvent,
|
||||
origin: Point2DI32,
|
||||
off_text: &str,
|
||||
on_text: &str,
|
||||
mut value: bool)
|
||||
-> bool {
|
||||
value = self.draw_switch(debug_ui, event, origin, value);
|
||||
value = self.draw_switch(device, debug_ui, event, origin, value);
|
||||
|
||||
let off_size = debug_ui.measure_text(off_text);
|
||||
let on_size = debug_ui.measure_text(on_text);
|
||||
|
@ -319,32 +350,39 @@ impl DemoUI {
|
|||
let on_offset = SWITCH_HALF_SIZE + SWITCH_HALF_SIZE / 2 - on_size / 2;
|
||||
let text_top = BUTTON_TEXT_OFFSET;
|
||||
|
||||
debug_ui.draw_text(off_text, origin + Point2DI32::new(off_offset, text_top), !value);
|
||||
debug_ui.draw_text(on_text, origin + Point2DI32::new(on_offset, text_top), value);
|
||||
debug_ui.draw_text(device,
|
||||
off_text,
|
||||
origin + Point2DI32::new(off_offset, text_top),
|
||||
!value);
|
||||
debug_ui.draw_text(device, on_text, origin + Point2DI32::new(on_offset, text_top), value);
|
||||
|
||||
value
|
||||
}
|
||||
|
||||
fn draw_image_switch(&self,
|
||||
debug_ui: &mut DebugUI,
|
||||
device: &D,
|
||||
debug_ui: &mut DebugUI<D>,
|
||||
event: &mut UIEvent,
|
||||
origin: Point2DI32,
|
||||
off_texture: &Texture,
|
||||
on_texture: &Texture,
|
||||
off_texture: &D::Texture,
|
||||
on_texture: &D::Texture,
|
||||
mut value: bool)
|
||||
-> bool {
|
||||
value = self.draw_switch(debug_ui, event, origin, value);
|
||||
value = self.draw_switch(device, debug_ui, event, origin, value);
|
||||
|
||||
let off_offset = SWITCH_HALF_SIZE / 2 - off_texture.size.x() / 2;
|
||||
let on_offset = SWITCH_HALF_SIZE + SWITCH_HALF_SIZE / 2 - on_texture.size.x() / 2;
|
||||
let off_offset = SWITCH_HALF_SIZE / 2 - device.texture_size(off_texture).x() / 2;
|
||||
let on_offset = SWITCH_HALF_SIZE + SWITCH_HALF_SIZE / 2 -
|
||||
device.texture_size(on_texture).x() / 2;
|
||||
|
||||
let off_color = if !value { WINDOW_COLOR } else { TEXT_COLOR };
|
||||
let on_color = if value { WINDOW_COLOR } else { TEXT_COLOR };
|
||||
|
||||
debug_ui.draw_texture(origin + Point2DI32::new(off_offset, PADDING),
|
||||
debug_ui.draw_texture(device,
|
||||
origin + Point2DI32::new(off_offset, PADDING),
|
||||
off_texture,
|
||||
off_color);
|
||||
debug_ui.draw_texture(origin + Point2DI32::new(on_offset, PADDING),
|
||||
debug_ui.draw_texture(device,
|
||||
origin + Point2DI32::new(on_offset, PADDING),
|
||||
on_texture,
|
||||
on_color);
|
||||
|
||||
|
@ -352,7 +390,8 @@ impl DemoUI {
|
|||
}
|
||||
|
||||
fn draw_switch(&self,
|
||||
debug_ui: &mut DebugUI,
|
||||
device: &D,
|
||||
debug_ui: &mut DebugUI<D>,
|
||||
event: &mut UIEvent,
|
||||
origin: Point2DI32,
|
||||
mut value: bool)
|
||||
|
@ -362,15 +401,18 @@ impl DemoUI {
|
|||
value = !value;
|
||||
}
|
||||
|
||||
debug_ui.draw_solid_rounded_rect(widget_rect, WINDOW_COLOR);
|
||||
debug_ui.draw_rounded_rect_outline(widget_rect, OUTLINE_COLOR);
|
||||
debug_ui.draw_solid_rounded_rect(device, widget_rect, WINDOW_COLOR);
|
||||
debug_ui.draw_rounded_rect_outline(device, widget_rect, OUTLINE_COLOR);
|
||||
|
||||
let highlight_size = Point2DI32::new(SWITCH_HALF_SIZE, BUTTON_HEIGHT);
|
||||
if !value {
|
||||
debug_ui.draw_solid_rounded_rect(RectI32::new(origin, highlight_size), TEXT_COLOR);
|
||||
debug_ui.draw_solid_rounded_rect(device,
|
||||
RectI32::new(origin, highlight_size),
|
||||
TEXT_COLOR);
|
||||
} else {
|
||||
let x_offset = SWITCH_HALF_SIZE + 1;
|
||||
debug_ui.draw_solid_rounded_rect(RectI32::new(origin + Point2DI32::new(x_offset, 0),
|
||||
debug_ui.draw_solid_rounded_rect(device,
|
||||
RectI32::new(origin + Point2DI32::new(x_offset, 0),
|
||||
highlight_size),
|
||||
TEXT_COLOR);
|
||||
}
|
||||
|
|
|
@ -144,13 +144,6 @@ impl Transform3DF32 {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn transpose(&self) -> Transform3DF32 {
|
||||
let mut m = *self;
|
||||
F32x4::transpose_4x4(&mut m.c0, &mut m.c1, &mut m.c2, &mut m.c3);
|
||||
m
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Is this right, due to transposition? I think we may have to reverse the
|
||||
// two.
|
||||
//
|
||||
|
@ -384,19 +377,6 @@ mod test {
|
|||
assert_eq!(a.transform_point(p), q);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transpose() {
|
||||
let a = Transform3DF32::row_major(3.0, 1.0, 4.0, 5.0,
|
||||
9.0, 2.0, 6.0, 5.0,
|
||||
3.0, 5.0, 8.0, 9.0,
|
||||
7.0, 9.0, 3.0, 2.0);
|
||||
let b = Transform3DF32::row_major(3.0, 9.0, 3.0, 7.0,
|
||||
1.0, 2.0, 5.0, 9.0,
|
||||
4.0, 6.0, 8.0, 3.0,
|
||||
5.0, 5.0, 9.0, 2.0);
|
||||
assert_eq!(a.transpose(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inverse() {
|
||||
// Random matrix.
|
||||
|
|
|
@ -18,5 +18,11 @@ features = ["png_codec"]
|
|||
[dependencies.pathfinder_geometry]
|
||||
path = "../geometry"
|
||||
|
||||
[dependencies.pathfinder_gpu]
|
||||
path = "../gpu"
|
||||
|
||||
[dependencies.pathfinder_renderer]
|
||||
path = "../renderer"
|
||||
|
||||
[dependencies.pathfinder_simd]
|
||||
path = "../simd"
|
||||
|
|
406
gl/src/debug.rs
406
gl/src/debug.rs
|
@ -15,26 +15,24 @@
|
|||
//!
|
||||
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
||||
|
||||
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Device, Program, Texture};
|
||||
use crate::device::{Uniform, VertexAttr};
|
||||
use gl::types::{GLfloat, GLint, GLsizei, GLuint};
|
||||
use gl;
|
||||
use pathfinder_geometry::basic::point::Point2DI32;
|
||||
use pathfinder_geometry::basic::rect::RectI32;
|
||||
use pathfinder_gpu::{BlendState, BufferTarget, BufferUploadMode, Device, Primitive, RenderState};
|
||||
use pathfinder_gpu::{Resources, UniformData, VertexAttrType};
|
||||
use pathfinder_renderer::gpu_data::Stats;
|
||||
use pathfinder_renderer::paint::ColorU;
|
||||
use pathfinder_simd::default::F32x4;
|
||||
use serde_json;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::ops::{Add, Div};
|
||||
use std::ptr;
|
||||
use std::time::Duration;
|
||||
|
||||
const SAMPLE_BUFFER_SIZE: usize = 60;
|
||||
|
||||
const DEBUG_TEXTURE_VERTEX_SIZE: GLint = 8;
|
||||
const DEBUG_SOLID_VERTEX_SIZE: GLint = 4;
|
||||
const DEBUG_TEXTURE_VERTEX_SIZE: usize = 8;
|
||||
const DEBUG_SOLID_VERTEX_SIZE: usize = 4;
|
||||
|
||||
pub const PADDING: i32 = 12;
|
||||
|
||||
|
@ -84,43 +82,44 @@ struct DebugCharacter {
|
|||
}
|
||||
|
||||
impl DebugFont {
|
||||
fn load(device: &Device) -> DebugFont {
|
||||
let mut path = device.resources_directory.clone();
|
||||
fn load(resources: &Resources) -> DebugFont {
|
||||
let mut path = resources.resources_directory.clone();
|
||||
path.push(FONT_JSON_FILENAME);
|
||||
|
||||
serde_json::from_reader(BufReader::new(File::open(path).unwrap())).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DebugUI {
|
||||
pub struct DebugUI<D> where D: Device {
|
||||
framebuffer_size: Point2DI32,
|
||||
|
||||
texture_program: DebugTextureProgram,
|
||||
texture_vertex_array: DebugTextureVertexArray,
|
||||
texture_program: DebugTextureProgram<D>,
|
||||
texture_vertex_array: DebugTextureVertexArray<D>,
|
||||
font: DebugFont,
|
||||
solid_program: DebugSolidProgram,
|
||||
solid_vertex_array: DebugSolidVertexArray,
|
||||
solid_program: DebugSolidProgram<D>,
|
||||
solid_vertex_array: DebugSolidVertexArray<D>,
|
||||
|
||||
font_texture: Texture,
|
||||
corner_fill_texture: Texture,
|
||||
corner_outline_texture: Texture,
|
||||
font_texture: D::Texture,
|
||||
corner_fill_texture: D::Texture,
|
||||
corner_outline_texture: D::Texture,
|
||||
|
||||
cpu_samples: SampleBuffer<CPUSample>,
|
||||
gpu_samples: SampleBuffer<GPUSample>,
|
||||
}
|
||||
|
||||
impl DebugUI {
|
||||
pub fn new(device: &Device, framebuffer_size: Point2DI32) -> DebugUI {
|
||||
let texture_program = DebugTextureProgram::new(device);
|
||||
let texture_vertex_array = DebugTextureVertexArray::new(&texture_program);
|
||||
let font = DebugFont::load(device);
|
||||
impl<D> DebugUI<D> where D: Device {
|
||||
pub fn new(device: &D, resources: &Resources, framebuffer_size: Point2DI32) -> DebugUI<D> {
|
||||
let texture_program = DebugTextureProgram::new(device, resources);
|
||||
let texture_vertex_array = DebugTextureVertexArray::new(device, &texture_program);
|
||||
let font = DebugFont::load(resources);
|
||||
|
||||
let solid_program = DebugSolidProgram::new(device);
|
||||
let solid_vertex_array = DebugSolidVertexArray::new(&solid_program);
|
||||
let solid_program = DebugSolidProgram::new(device, resources);
|
||||
let solid_vertex_array = DebugSolidVertexArray::new(device, &solid_program);
|
||||
|
||||
let font_texture = device.create_texture_from_png(FONT_PNG_NAME);
|
||||
let corner_fill_texture = device.create_texture_from_png(CORNER_FILL_PNG_NAME);
|
||||
let corner_outline_texture = device.create_texture_from_png(CORNER_OUTLINE_PNG_NAME);
|
||||
let font_texture = device.create_texture_from_png(resources, FONT_PNG_NAME);
|
||||
let corner_fill_texture = device.create_texture_from_png(resources, CORNER_FILL_PNG_NAME);
|
||||
let corner_outline_texture = device.create_texture_from_png(resources,
|
||||
CORNER_OUTLINE_PNG_NAME);
|
||||
|
||||
DebugUI {
|
||||
framebuffer_size,
|
||||
|
@ -158,47 +157,55 @@ impl DebugUI {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self) {
|
||||
pub fn draw(&self, device: &D) {
|
||||
// Draw performance window.
|
||||
let bottom = self.framebuffer_size.y() - PADDING;
|
||||
let window_rect = RectI32::new(
|
||||
Point2DI32::new(self.framebuffer_size.x() - PADDING - PERF_WINDOW_WIDTH,
|
||||
bottom - PERF_WINDOW_HEIGHT),
|
||||
Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT));
|
||||
self.draw_solid_rounded_rect(window_rect, WINDOW_COLOR);
|
||||
self.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR);
|
||||
let origin = window_rect.origin() + Point2DI32::new(PADDING, PADDING + FONT_ASCENT);
|
||||
|
||||
let mean_cpu_sample = self.cpu_samples.mean();
|
||||
self.draw_text(&format!("Objects: {}", mean_cpu_sample.stats.object_count), origin, false);
|
||||
self.draw_text(&format!("Solid Tiles: {}", mean_cpu_sample.stats.solid_tile_count),
|
||||
self.draw_text(device,
|
||||
&format!("Objects: {}", mean_cpu_sample.stats.object_count),
|
||||
origin,
|
||||
false);
|
||||
self.draw_text(device,
|
||||
&format!("Solid Tiles: {}", mean_cpu_sample.stats.solid_tile_count),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 1),
|
||||
false);
|
||||
self.draw_text(&format!("Mask Tiles: {}", mean_cpu_sample.stats.mask_tile_count),
|
||||
self.draw_text(device,
|
||||
&format!("Mask Tiles: {}", mean_cpu_sample.stats.mask_tile_count),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 2),
|
||||
false);
|
||||
self.draw_text(&format!("Fills: {}", mean_cpu_sample.stats.fill_count),
|
||||
self.draw_text(device,
|
||||
&format!("Fills: {}", mean_cpu_sample.stats.fill_count),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 3),
|
||||
false);
|
||||
|
||||
self.draw_text(&format!("CPU Time: {:.3} ms", duration_to_ms(mean_cpu_sample.elapsed)),
|
||||
self.draw_text(device,
|
||||
&format!("CPU Time: {:.3} ms", duration_to_ms(mean_cpu_sample.elapsed)),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 4),
|
||||
false);
|
||||
|
||||
let mean_gpu_sample = self.gpu_samples.mean();
|
||||
self.draw_text(&format!("GPU Time: {:.3} ms", duration_to_ms(mean_gpu_sample.elapsed)),
|
||||
self.draw_text(device,
|
||||
&format!("GPU Time: {:.3} ms", duration_to_ms(mean_gpu_sample.elapsed)),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 5),
|
||||
false);
|
||||
}
|
||||
|
||||
pub fn draw_solid_rect(&self, rect: RectI32, color: ColorU) {
|
||||
self.draw_rect(rect, color, true);
|
||||
pub fn draw_solid_rect(&self, device: &D, rect: RectI32, color: ColorU) {
|
||||
self.draw_rect(device, rect, color, true);
|
||||
}
|
||||
|
||||
pub fn draw_rect_outline(&self, rect: RectI32, color: ColorU) {
|
||||
self.draw_rect(rect, color, false);
|
||||
pub fn draw_rect_outline(&self, device: &D, rect: RectI32, color: ColorU) {
|
||||
self.draw_rect(device, rect, color, false);
|
||||
}
|
||||
|
||||
fn draw_rect(&self, rect: RectI32, color: ColorU, filled: bool) {
|
||||
fn draw_rect(&self, device: &D, rect: RectI32, color: ColorU, filled: bool) {
|
||||
let vertex_data = [
|
||||
DebugSolidVertex::new(rect.origin()),
|
||||
DebugSolidVertex::new(rect.upper_right()),
|
||||
|
@ -207,44 +214,50 @@ impl DebugUI {
|
|||
];
|
||||
|
||||
if filled {
|
||||
self.draw_solid_rects_with_vertex_data(&vertex_data, &QUAD_INDICES, color, true);
|
||||
self.draw_solid_rects_with_vertex_data(device,
|
||||
&vertex_data,
|
||||
&QUAD_INDICES,
|
||||
color,
|
||||
true);
|
||||
} else {
|
||||
self.draw_solid_rects_with_vertex_data(&vertex_data, &RECT_LINE_INDICES, color, false);
|
||||
self.draw_solid_rects_with_vertex_data(device,
|
||||
&vertex_data,
|
||||
&RECT_LINE_INDICES,
|
||||
color,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_solid_rects_with_vertex_data(&self,
|
||||
device: &D,
|
||||
vertex_data: &[DebugSolidVertex],
|
||||
index_data: &[u32],
|
||||
color: ColorU,
|
||||
filled: bool) {
|
||||
unsafe {
|
||||
gl::BindVertexArray(self.solid_vertex_array.gl_vertex_array);
|
||||
device.bind_vertex_array(&self.solid_vertex_array.vertex_array);
|
||||
|
||||
device.upload_to_buffer(&self.solid_vertex_array.vertex_buffer,
|
||||
vertex_data,
|
||||
BufferTarget::Vertex,
|
||||
BufferUploadMode::Dynamic);
|
||||
device.upload_to_buffer(&self.solid_vertex_array.index_buffer,
|
||||
index_data,
|
||||
BufferTarget::Index,
|
||||
BufferUploadMode::Dynamic);
|
||||
|
||||
device.use_program(&self.solid_program.program);
|
||||
device.set_uniform(&self.solid_program.framebuffer_size_uniform,
|
||||
UniformData::Vec2(self.framebuffer_size.0.to_f32x4()));
|
||||
set_color_uniform(device, &self.solid_program.color_uniform, color);
|
||||
|
||||
let primitive = if filled { Primitive::Triangles } else { Primitive::Lines };
|
||||
device.draw_elements(primitive, index_data.len() as u32, &RenderState {
|
||||
blend: BlendState::RGBOneAlphaOneMinusSrcAlpha,
|
||||
..RenderState::default()
|
||||
});
|
||||
}
|
||||
|
||||
self.solid_vertex_array
|
||||
.vertex_buffer
|
||||
.upload(vertex_data, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||
self.solid_vertex_array
|
||||
.index_buffer
|
||||
.upload(index_data, BufferTarget::Index, BufferUploadMode::Dynamic);
|
||||
|
||||
unsafe {
|
||||
gl::UseProgram(self.solid_program.program.gl_program);
|
||||
gl::Uniform2f(self.solid_program.framebuffer_size_uniform.location,
|
||||
self.framebuffer_size.x() as GLfloat,
|
||||
self.framebuffer_size.y() as GLfloat);
|
||||
set_color_uniform(&self.solid_program.color_uniform, color);
|
||||
gl::BlendEquation(gl::FUNC_ADD);
|
||||
gl::BlendFunc(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
|
||||
gl::Enable(gl::BLEND);
|
||||
let primitive = if filled { gl::TRIANGLES } else { gl::LINES };
|
||||
gl::DrawElements(primitive, index_data.len() as GLint, gl::UNSIGNED_INT, ptr::null());
|
||||
gl::Disable(gl::BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_text(&self, string: &str, origin: Point2DI32, invert: bool) {
|
||||
pub fn draw_text(&self, device: &D, string: &str, origin: Point2DI32, invert: bool) {
|
||||
let mut next = origin;
|
||||
let char_count = string.chars().count();
|
||||
let mut vertex_data = Vec::with_capacity(char_count * 4);
|
||||
|
@ -274,12 +287,20 @@ impl DebugUI {
|
|||
}
|
||||
|
||||
let color = if invert { INVERTED_TEXT_COLOR } else { TEXT_COLOR };
|
||||
self.draw_texture_with_vertex_data(&vertex_data, &index_data, &self.font_texture, color);
|
||||
self.draw_texture_with_vertex_data(device,
|
||||
&vertex_data,
|
||||
&index_data,
|
||||
&self.font_texture,
|
||||
color);
|
||||
}
|
||||
|
||||
pub fn draw_texture(&self, origin: Point2DI32, texture: &Texture, color: ColorU) {
|
||||
let position_rect = RectI32::new(origin, texture.size);
|
||||
let tex_coord_rect = RectI32::new(Point2DI32::default(), texture.size);
|
||||
pub fn draw_texture(&self,
|
||||
device: &D,
|
||||
origin: Point2DI32,
|
||||
texture: &D::Texture,
|
||||
color: ColorU) {
|
||||
let position_rect = RectI32::new(origin, device.texture_size(&texture));
|
||||
let tex_coord_rect = RectI32::new(Point2DI32::default(), position_rect.size());
|
||||
let vertex_data = [
|
||||
DebugTextureVertex::new(position_rect.origin(), tex_coord_rect.origin()),
|
||||
DebugTextureVertex::new(position_rect.upper_right(), tex_coord_rect.upper_right()),
|
||||
|
@ -287,7 +308,7 @@ impl DebugUI {
|
|||
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
||||
];
|
||||
|
||||
self.draw_texture_with_vertex_data(&vertex_data, &QUAD_INDICES, texture, color);
|
||||
self.draw_texture_with_vertex_data(device, &vertex_data, &QUAD_INDICES, texture, color);
|
||||
}
|
||||
|
||||
pub fn measure_text(&self, string: &str) -> i32 {
|
||||
|
@ -303,10 +324,10 @@ impl DebugUI {
|
|||
next
|
||||
}
|
||||
|
||||
pub fn draw_solid_rounded_rect(&self, rect: RectI32, color: ColorU) {
|
||||
pub fn draw_solid_rounded_rect(&self, device: &D, rect: RectI32, color: ColorU) {
|
||||
let corner_texture = self.corner_texture(true);
|
||||
let corner_rects = CornerRects::new(rect, corner_texture);
|
||||
self.draw_rounded_rect_corners(color, corner_texture, &corner_rects);
|
||||
let corner_rects = CornerRects::new(device, rect, corner_texture);
|
||||
self.draw_rounded_rect_corners(device, color, corner_texture, &corner_rects);
|
||||
|
||||
let solid_rect_mid = RectI32::from_points(corner_rects.upper_left.upper_right(),
|
||||
corner_rects.lower_right.lower_left());
|
||||
|
@ -336,13 +357,17 @@ impl DebugUI {
|
|||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 4));
|
||||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8));
|
||||
|
||||
self.draw_solid_rects_with_vertex_data(&vertex_data, &index_data[0..18], color, true);
|
||||
self.draw_solid_rects_with_vertex_data(device,
|
||||
&vertex_data,
|
||||
&index_data[0..18],
|
||||
color,
|
||||
true);
|
||||
}
|
||||
|
||||
pub fn draw_rounded_rect_outline(&self, rect: RectI32, color: ColorU) {
|
||||
pub fn draw_rounded_rect_outline(&self, device: &D, rect: RectI32, color: ColorU) {
|
||||
let corner_texture = self.corner_texture(false);
|
||||
let corner_rects = CornerRects::new(rect, corner_texture);
|
||||
self.draw_rounded_rect_corners(color, corner_texture, &corner_rects);
|
||||
let corner_rects = CornerRects::new(device, rect, corner_texture);
|
||||
self.draw_rounded_rect_corners(device, color, corner_texture, &corner_rects);
|
||||
|
||||
let vertex_data = vec![
|
||||
DebugSolidVertex::new(corner_rects.upper_left.upper_right()),
|
||||
|
@ -356,14 +381,15 @@ impl DebugUI {
|
|||
];
|
||||
|
||||
let index_data = &OUTLINE_RECT_LINE_INDICES;
|
||||
self.draw_solid_rects_with_vertex_data(&vertex_data, index_data, color, false);
|
||||
self.draw_solid_rects_with_vertex_data(device, &vertex_data, index_data, color, false);
|
||||
}
|
||||
|
||||
fn draw_rounded_rect_corners(&self,
|
||||
device: &D,
|
||||
color: ColorU,
|
||||
texture: &Texture,
|
||||
texture: &D::Texture,
|
||||
corner_rects: &CornerRects) {
|
||||
let corner_size = texture.size;
|
||||
let corner_size = device.texture_size(&texture);
|
||||
let tex_coord_rect = RectI32::new(Point2DI32::default(), corner_size);
|
||||
|
||||
let vertex_data = vec![
|
||||
|
@ -410,151 +436,126 @@ impl DebugUI {
|
|||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8));
|
||||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 12));
|
||||
|
||||
self.draw_texture_with_vertex_data(&vertex_data, &index_data, texture, color);
|
||||
self.draw_texture_with_vertex_data(device, &vertex_data, &index_data, texture, color);
|
||||
}
|
||||
|
||||
fn corner_texture(&self, filled: bool) -> &Texture {
|
||||
fn corner_texture(&self, filled: bool) -> &D::Texture {
|
||||
if filled { &self.corner_fill_texture } else { &self.corner_outline_texture }
|
||||
}
|
||||
|
||||
fn draw_texture_with_vertex_data(&self,
|
||||
device: &D,
|
||||
vertex_data: &[DebugTextureVertex],
|
||||
index_data: &[u32],
|
||||
texture: &Texture,
|
||||
texture: &D::Texture,
|
||||
color: ColorU) {
|
||||
self.texture_vertex_array
|
||||
.vertex_buffer
|
||||
.upload(&vertex_data, BufferTarget::Vertex, BufferUploadMode::Dynamic);
|
||||
self.texture_vertex_array
|
||||
.index_buffer
|
||||
.upload(&index_data, BufferTarget::Index, BufferUploadMode::Dynamic);
|
||||
device.upload_to_buffer(&self.texture_vertex_array.vertex_buffer,
|
||||
vertex_data,
|
||||
BufferTarget::Vertex,
|
||||
BufferUploadMode::Dynamic);
|
||||
device.upload_to_buffer(&self.texture_vertex_array.index_buffer,
|
||||
index_data,
|
||||
BufferTarget::Index,
|
||||
BufferUploadMode::Dynamic);
|
||||
|
||||
unsafe {
|
||||
gl::BindVertexArray(self.texture_vertex_array.gl_vertex_array);
|
||||
gl::UseProgram(self.texture_program.program.gl_program);
|
||||
gl::Uniform2f(self.texture_program.framebuffer_size_uniform.location,
|
||||
self.framebuffer_size.x() as GLfloat,
|
||||
self.framebuffer_size.y() as GLfloat);
|
||||
gl::Uniform2f(self.texture_program.texture_size_uniform.location,
|
||||
texture.size.x() as GLfloat,
|
||||
texture.size.y() as GLfloat);
|
||||
set_color_uniform(&self.texture_program.color_uniform, color);
|
||||
texture.bind(0);
|
||||
gl::Uniform1i(self.texture_program.texture_uniform.location, 0);
|
||||
gl::BlendEquation(gl::FUNC_ADD);
|
||||
gl::BlendFunc(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
|
||||
gl::Enable(gl::BLEND);
|
||||
gl::DrawElements(gl::TRIANGLES,
|
||||
index_data.len() as GLsizei,
|
||||
gl::UNSIGNED_INT,
|
||||
ptr::null());
|
||||
gl::Disable(gl::BLEND);
|
||||
}
|
||||
device.bind_vertex_array(&self.texture_vertex_array.vertex_array);
|
||||
device.use_program(&self.texture_program.program);
|
||||
device.set_uniform(&self.texture_program.framebuffer_size_uniform,
|
||||
UniformData::Vec2(self.framebuffer_size.0.to_f32x4()));
|
||||
device.set_uniform(&self.texture_program.texture_size_uniform,
|
||||
UniformData::Vec2(device.texture_size(&texture).0.to_f32x4()));
|
||||
set_color_uniform(device, &self.texture_program.color_uniform, color);
|
||||
device.bind_texture(texture, 0);
|
||||
device.set_uniform(&self.texture_program.texture_uniform, UniformData::TextureUnit(0));
|
||||
|
||||
device.draw_elements(Primitive::Triangles, index_data.len() as u32, &RenderState {
|
||||
blend: BlendState::RGBOneAlphaOneMinusSrcAlpha,
|
||||
..RenderState::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugTextureVertexArray {
|
||||
gl_vertex_array: GLuint,
|
||||
vertex_buffer: Buffer,
|
||||
index_buffer: Buffer,
|
||||
struct DebugTextureVertexArray<D> where D: Device {
|
||||
vertex_array: D::VertexArray,
|
||||
vertex_buffer: D::Buffer,
|
||||
index_buffer: D::Buffer,
|
||||
}
|
||||
|
||||
impl DebugTextureVertexArray {
|
||||
fn new(debug_texture_program: &DebugTextureProgram) -> DebugTextureVertexArray {
|
||||
let vertex_buffer = Buffer::new();
|
||||
let index_buffer = Buffer::new();
|
||||
let mut gl_vertex_array = 0;
|
||||
unsafe {
|
||||
let position_attr = VertexAttr::new(&debug_texture_program.program, "Position");
|
||||
let tex_coord_attr = VertexAttr::new(&debug_texture_program.program, "TexCoord");
|
||||
impl<D> DebugTextureVertexArray<D> where D: Device {
|
||||
fn new(device: &D, debug_texture_program: &DebugTextureProgram<D>)
|
||||
-> DebugTextureVertexArray<D> {
|
||||
let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer());
|
||||
let vertex_array = device.create_vertex_array();
|
||||
|
||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||
gl::BindVertexArray(gl_vertex_array);
|
||||
gl::UseProgram(debug_texture_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||
position_attr.configure_float(2,
|
||||
gl::UNSIGNED_SHORT,
|
||||
let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position");
|
||||
let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord");
|
||||
|
||||
device.bind_vertex_array(&vertex_array);
|
||||
device.use_program(&debug_texture_program.program);
|
||||
device.bind_buffer(&vertex_buffer, BufferTarget::Vertex);
|
||||
device.bind_buffer(&index_buffer, BufferTarget::Index);
|
||||
device.configure_float_vertex_attr(&position_attr,
|
||||
2,
|
||||
VertexAttrType::U16,
|
||||
false,
|
||||
DEBUG_TEXTURE_VERTEX_SIZE,
|
||||
0,
|
||||
0);
|
||||
tex_coord_attr.configure_float(2,
|
||||
gl::UNSIGNED_SHORT,
|
||||
device.configure_float_vertex_attr(&tex_coord_attr,
|
||||
2,
|
||||
VertexAttrType::U16,
|
||||
false,
|
||||
DEBUG_TEXTURE_VERTEX_SIZE,
|
||||
4,
|
||||
0);
|
||||
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer.gl_buffer);
|
||||
}
|
||||
|
||||
DebugTextureVertexArray { gl_vertex_array, vertex_buffer, index_buffer }
|
||||
DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DebugTextureVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
struct DebugSolidVertexArray<D> where D: Device {
|
||||
vertex_array: D::VertexArray,
|
||||
vertex_buffer: D::Buffer,
|
||||
index_buffer: D::Buffer,
|
||||
}
|
||||
|
||||
struct DebugSolidVertexArray {
|
||||
gl_vertex_array: GLuint,
|
||||
vertex_buffer: Buffer,
|
||||
index_buffer: Buffer,
|
||||
}
|
||||
impl<D> DebugSolidVertexArray<D> where D: Device {
|
||||
fn new(device: &D, debug_solid_program: &DebugSolidProgram<D>) -> DebugSolidVertexArray<D> {
|
||||
let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer());
|
||||
let vertex_array = device.create_vertex_array();
|
||||
|
||||
impl DebugSolidVertexArray {
|
||||
fn new(debug_solid_program: &DebugSolidProgram) -> DebugSolidVertexArray {
|
||||
let vertex_buffer = Buffer::new();
|
||||
let index_buffer = Buffer::new();
|
||||
let mut gl_vertex_array = 0;
|
||||
unsafe {
|
||||
let position_attr = VertexAttr::new(&debug_solid_program.program, "Position");
|
||||
|
||||
gl::GenVertexArrays(1, &mut gl_vertex_array);
|
||||
gl::BindVertexArray(gl_vertex_array);
|
||||
gl::UseProgram(debug_solid_program.program.gl_program);
|
||||
gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer.gl_buffer);
|
||||
position_attr.configure_float(2,
|
||||
gl::UNSIGNED_SHORT,
|
||||
let position_attr = device.get_vertex_attr(&debug_solid_program.program, "Position");
|
||||
device.bind_vertex_array(&vertex_array);
|
||||
device.use_program(&debug_solid_program.program);
|
||||
device.bind_buffer(&vertex_buffer, BufferTarget::Vertex);
|
||||
device.bind_buffer(&index_buffer, BufferTarget::Index);
|
||||
device.configure_float_vertex_attr(&position_attr,
|
||||
2,
|
||||
VertexAttrType::U16,
|
||||
false,
|
||||
DEBUG_SOLID_VERTEX_SIZE,
|
||||
0,
|
||||
0);
|
||||
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer.gl_buffer);
|
||||
}
|
||||
|
||||
DebugSolidVertexArray { gl_vertex_array, vertex_buffer, index_buffer }
|
||||
DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DebugSolidVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
struct DebugTextureProgram<D> where D: Device {
|
||||
program: D::Program,
|
||||
framebuffer_size_uniform: D::Uniform,
|
||||
texture_size_uniform: D::Uniform,
|
||||
texture_uniform: D::Uniform,
|
||||
color_uniform: D::Uniform,
|
||||
}
|
||||
|
||||
struct DebugTextureProgram {
|
||||
program: Program,
|
||||
framebuffer_size_uniform: Uniform,
|
||||
texture_size_uniform: Uniform,
|
||||
texture_uniform: Uniform,
|
||||
color_uniform: Uniform,
|
||||
}
|
||||
|
||||
impl DebugTextureProgram {
|
||||
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");
|
||||
let color_uniform = Uniform::new(&program, "Color");
|
||||
impl<D> DebugTextureProgram<D> where D: Device {
|
||||
fn new(device: &D, resources: &Resources) -> DebugTextureProgram<D> {
|
||||
let program = device.create_program(resources, "debug_texture");
|
||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||
let texture_size_uniform = device.get_uniform(&program, "TextureSize");
|
||||
let texture_uniform = device.get_uniform(&program, "Texture");
|
||||
let color_uniform = device.get_uniform(&program, "Color");
|
||||
DebugTextureProgram {
|
||||
program,
|
||||
framebuffer_size_uniform,
|
||||
|
@ -565,17 +566,17 @@ impl DebugTextureProgram {
|
|||
}
|
||||
}
|
||||
|
||||
struct DebugSolidProgram {
|
||||
program: Program,
|
||||
framebuffer_size_uniform: Uniform,
|
||||
color_uniform: Uniform,
|
||||
struct DebugSolidProgram<D> where D: Device {
|
||||
program: D::Program,
|
||||
framebuffer_size_uniform: D::Uniform,
|
||||
color_uniform: D::Uniform,
|
||||
}
|
||||
|
||||
impl DebugSolidProgram {
|
||||
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");
|
||||
impl<D> DebugSolidProgram<D> where D: Device {
|
||||
fn new(device: &D, resources: &Resources) -> DebugSolidProgram<D> {
|
||||
let program = device.create_program(resources, "debug_solid");
|
||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||
let color_uniform = device.get_uniform(&program, "Color");
|
||||
DebugSolidProgram { program, framebuffer_size_uniform, color_uniform }
|
||||
}
|
||||
}
|
||||
|
@ -645,14 +646,9 @@ impl<S> SampleBuffer<S> where S: Add<S, Output=S> + Div<u32, Output=S> + Clone +
|
|||
}
|
||||
}
|
||||
|
||||
fn set_color_uniform(uniform: &Uniform, color: ColorU) {
|
||||
unsafe {
|
||||
gl::Uniform4f(uniform.location,
|
||||
color.r as f32 * (1.0 / 255.0),
|
||||
color.g as f32 * (1.0 / 255.0),
|
||||
color.b as f32 * (1.0 / 255.0),
|
||||
color.a as f32 * (1.0 / 255.0));
|
||||
}
|
||||
fn set_color_uniform<D>(device: &D, uniform: &D::Uniform, color: ColorU) where D: Device {
|
||||
let color = F32x4::new(color.r as f32, color.g as f32, color.b as f32, color.a as f32);
|
||||
device.set_uniform(uniform, UniformData::Vec4(color * F32x4::splat(1.0 / 255.0)));
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -722,8 +718,8 @@ struct CornerRects {
|
|||
}
|
||||
|
||||
impl CornerRects {
|
||||
fn new(rect: RectI32, texture: &Texture) -> CornerRects {
|
||||
let size = texture.size;
|
||||
fn new<D>(device: &D, rect: RectI32, texture: &D::Texture) -> CornerRects where D: Device {
|
||||
let size = device.texture_size(texture);
|
||||
CornerRects {
|
||||
upper_left: RectI32::new(rect.origin(), size),
|
||||
upper_right: RectI32::new(rect.upper_right() - Point2DI32::new(size.x(), 0), size),
|
||||
|
|
831
gl/src/device.rs
831
gl/src/device.rs
|
@ -1,4 +1,4 @@
|
|||
// pathfinder/demo/src/device.rs
|
||||
// pathfinder/gl/src/device.rs
|
||||
//
|
||||
// Copyright © 2019 The Pathfinder Project Developers.
|
||||
//
|
||||
|
@ -8,72 +8,175 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Minimal abstractions over GPU device capabilities.
|
||||
//! An OpenGL implementation of the device abstraction.
|
||||
|
||||
use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
||||
use gl::types::{GLboolean, GLchar, GLdouble, GLenum, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
||||
use pathfinder_geometry::basic::point::Point2DI32;
|
||||
use std::env;
|
||||
use pathfinder_gpu::{BlendState, BufferTarget, BufferUploadMode, DepthFunc, Device, Primitive};
|
||||
use pathfinder_gpu::{RenderState, ShaderKind, StencilFunc, TextureFormat};
|
||||
use pathfinder_gpu::{UniformData, VertexAttrType};
|
||||
use pathfinder_simd::default::F32x4;
|
||||
use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct Device {
|
||||
pub resources_directory: PathBuf,
|
||||
pub struct GLDevice;
|
||||
|
||||
impl GLDevice {
|
||||
#[inline]
|
||||
pub fn new() -> GLDevice { GLDevice }
|
||||
|
||||
fn set_texture_parameters(&self, texture: &GLTexture) {
|
||||
self.bind_texture(texture, 0);
|
||||
unsafe {
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
|
||||
}
|
||||
}
|
||||
|
||||
impl Device {
|
||||
#[inline]
|
||||
pub fn new() -> Device {
|
||||
Device { resources_directory: locate_resources_directory() }
|
||||
fn set_render_state(&self, render_state: &RenderState) {
|
||||
unsafe {
|
||||
// Set blend.
|
||||
match render_state.blend {
|
||||
BlendState::Off => gl::Disable(gl::BLEND),
|
||||
BlendState::RGBOneAlphaOneMinusSrcAlpha => {
|
||||
gl::BlendFuncSeparate(gl::ONE, gl::ONE_MINUS_SRC_ALPHA, gl::ONE, gl::ONE);
|
||||
gl::Enable(gl::BLEND);
|
||||
}
|
||||
BlendState::RGBOneAlphaOne => {
|
||||
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||
gl::Enable(gl::BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
#[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));
|
||||
// Set depth.
|
||||
match render_state.depth {
|
||||
None => gl::Disable(gl::DEPTH_TEST),
|
||||
Some(ref state) => {
|
||||
gl::Enable(gl::DEPTH_TEST);
|
||||
gl::DepthFunc(state.func.to_gl_depth_func());
|
||||
gl::DepthMask(state.write as GLboolean);
|
||||
}
|
||||
}
|
||||
|
||||
let image = image::open(&path).unwrap().to_luma();
|
||||
// Set stencil.
|
||||
match render_state.stencil {
|
||||
None => gl::Disable(gl::STENCIL_TEST),
|
||||
Some(ref state) => {
|
||||
gl::StencilFunc(state.func.to_gl_stencil_func(),
|
||||
state.reference as GLint,
|
||||
state.mask);
|
||||
let pass_action = if state.pass_replace { gl::REPLACE } else { gl::KEEP };
|
||||
gl::StencilOp(gl::KEEP, gl::KEEP, pass_action);
|
||||
gl::Enable(gl::STENCIL_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
let mut texture = Texture {
|
||||
gl_texture: 0,
|
||||
size: Point2DI32::new(image.width() as i32, image.height() as i32),
|
||||
};
|
||||
// Set color mask.
|
||||
let color_mask = render_state.color_mask as GLboolean;
|
||||
gl::ColorMask(color_mask, color_mask, color_mask, color_mask);
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_render_state(&self, render_state: &RenderState) {
|
||||
unsafe {
|
||||
match render_state.blend {
|
||||
BlendState::Off => {}
|
||||
BlendState::RGBOneAlphaOneMinusSrcAlpha | BlendState::RGBOneAlphaOne => {
|
||||
gl::Disable(gl::BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
if render_state.depth.is_some() {
|
||||
gl::Disable(gl::DEPTH_TEST);
|
||||
}
|
||||
|
||||
if render_state.stencil.is_some() {
|
||||
gl::Disable(gl::STENCIL_TEST);
|
||||
}
|
||||
|
||||
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for GLDevice {
|
||||
type Buffer = GLBuffer;
|
||||
type Framebuffer = GLFramebuffer;
|
||||
type Program = GLProgram;
|
||||
type Shader = GLShader;
|
||||
type Texture = GLTexture;
|
||||
type TimerQuery = GLTimerQuery;
|
||||
type Uniform = GLUniform;
|
||||
type VertexArray = GLVertexArray;
|
||||
type VertexAttr = GLVertexAttr;
|
||||
|
||||
fn create_texture(&self, format: TextureFormat, size: Point2DI32) -> GLTexture {
|
||||
let (gl_internal_format, gl_format, gl_type);
|
||||
match format {
|
||||
TextureFormat::R16F => {
|
||||
gl_internal_format = gl::R16F as GLint;
|
||||
gl_format = gl::RED;
|
||||
gl_type = gl::HALF_FLOAT;
|
||||
}
|
||||
TextureFormat::RGBA8 => {
|
||||
gl_internal_format = gl::RGBA as GLint;
|
||||
gl_format = gl::RGBA;
|
||||
gl_type = gl::UNSIGNED_BYTE;
|
||||
}
|
||||
}
|
||||
|
||||
let mut texture = GLTexture { gl_texture: 0, size };
|
||||
unsafe {
|
||||
gl::GenTextures(1, &mut texture.gl_texture);
|
||||
texture.bind(0);
|
||||
self.bind_texture(&texture, 0);
|
||||
gl::TexImage2D(gl::TEXTURE_2D,
|
||||
0,
|
||||
gl::RED as GLint,
|
||||
image.width() as GLsizei,
|
||||
image.height() as GLsizei,
|
||||
gl_internal_format,
|
||||
size.x() as GLsizei,
|
||||
size.y() as GLsizei,
|
||||
0,
|
||||
gl::RED,
|
||||
gl::UNSIGNED_BYTE,
|
||||
image.as_ptr() as *const GLvoid);
|
||||
gl_format,
|
||||
gl_type,
|
||||
ptr::null());
|
||||
}
|
||||
|
||||
texture.set_parameters();
|
||||
self.set_texture_parameters(&texture);
|
||||
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));
|
||||
fn create_texture_from_data(&self, size: Point2DI32, data: &[u8]) -> GLTexture {
|
||||
assert!(data.len() >= size.x() as usize * size.y() as usize);
|
||||
|
||||
let mut source = vec![];
|
||||
File::open(&path).unwrap().read_to_end(&mut source).unwrap();
|
||||
let mut texture = GLTexture { gl_texture: 0, size };
|
||||
unsafe {
|
||||
gl::GenTextures(1, &mut texture.gl_texture);
|
||||
self.bind_texture(&texture, 0);
|
||||
gl::TexImage2D(gl::TEXTURE_2D,
|
||||
0,
|
||||
gl::RED as GLint,
|
||||
size.x() as GLsizei,
|
||||
size.y() as GLsizei,
|
||||
0,
|
||||
gl::RED,
|
||||
gl::UNSIGNED_BYTE,
|
||||
data.as_ptr() as *const GLvoid);
|
||||
}
|
||||
|
||||
self.set_texture_parameters(&texture);
|
||||
texture
|
||||
}
|
||||
|
||||
fn create_shader_from_source(&self, name: &str, source: &[u8], kind: ShaderKind) -> GLShader {
|
||||
let gl_shader_kind = match kind {
|
||||
ShaderKind::Vertex => gl::VERTEX_SHADER,
|
||||
ShaderKind::Fragment => gl::FRAGMENT_SHADER,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let gl_shader = gl::CreateShader(gl_shader_kind);
|
||||
gl::ShaderSource(gl_shader,
|
||||
1,
|
||||
|
@ -95,14 +198,15 @@ impl Device {
|
|||
panic!("{:?} shader '{}' compilation failed", kind, name);
|
||||
}
|
||||
|
||||
Shader { gl_shader }
|
||||
GLShader { 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);
|
||||
|
||||
fn create_program_from_shaders(&self,
|
||||
name: &str,
|
||||
vertex_shader: GLShader,
|
||||
fragment_shader: GLShader)
|
||||
-> GLProgram {
|
||||
let gl_program;
|
||||
unsafe {
|
||||
gl_program = gl::CreateProgram();
|
||||
|
@ -125,15 +229,332 @@ impl Device {
|
|||
}
|
||||
}
|
||||
|
||||
Program { gl_program, vertex_shader, fragment_shader }
|
||||
GLProgram { gl_program, vertex_shader, fragment_shader }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn create_vertex_array(&self) -> GLVertexArray {
|
||||
unsafe {
|
||||
let mut array = GLVertexArray { gl_vertex_array: 0 };
|
||||
gl::GenVertexArrays(1, &mut array.gl_vertex_array);
|
||||
array
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VertexArray {
|
||||
fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> GLVertexAttr {
|
||||
let name = CString::new(format!("a{}", name)).unwrap();
|
||||
let attr = unsafe {
|
||||
gl::GetAttribLocation(program.gl_program, name.as_ptr() as *const GLchar) as GLuint
|
||||
};
|
||||
GLVertexAttr { attr }
|
||||
}
|
||||
|
||||
fn get_uniform(&self, program: &GLProgram, name: &str) -> GLUniform {
|
||||
let name = CString::new(format!("u{}", name)).unwrap();
|
||||
let location = unsafe {
|
||||
gl::GetUniformLocation(program.gl_program, name.as_ptr() as *const GLchar)
|
||||
};
|
||||
GLUniform { location }
|
||||
}
|
||||
|
||||
fn use_program(&self, program: &Self::Program) {
|
||||
unsafe {
|
||||
gl::UseProgram(program.gl_program);
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_float_vertex_attr(&self,
|
||||
attr: &GLVertexAttr,
|
||||
size: usize,
|
||||
attr_type: VertexAttrType,
|
||||
normalized: bool,
|
||||
stride: usize,
|
||||
offset: usize,
|
||||
divisor: u32) {
|
||||
unsafe {
|
||||
gl::VertexAttribPointer(attr.attr,
|
||||
size as GLint,
|
||||
attr_type.to_gl_type(),
|
||||
if normalized { gl::TRUE } else { gl::FALSE },
|
||||
stride as GLint,
|
||||
offset as *const GLvoid);
|
||||
gl::VertexAttribDivisor(attr.attr, divisor);
|
||||
gl::EnableVertexAttribArray(attr.attr);
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_int_vertex_attr(&self,
|
||||
attr: &GLVertexAttr,
|
||||
size: usize,
|
||||
attr_type: VertexAttrType,
|
||||
stride: usize,
|
||||
offset: usize,
|
||||
divisor: u32) {
|
||||
unsafe {
|
||||
gl::VertexAttribIPointer(attr.attr,
|
||||
size as GLint,
|
||||
attr_type.to_gl_type(),
|
||||
stride as GLint,
|
||||
offset as *const GLvoid);
|
||||
gl::VertexAttribDivisor(attr.attr, divisor);
|
||||
gl::EnableVertexAttribArray(attr.attr);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData) {
|
||||
unsafe {
|
||||
match data {
|
||||
UniformData::Vec2(data) => gl::Uniform2f(uniform.location, data.x(), data.y()),
|
||||
UniformData::Vec4(data) => {
|
||||
gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w());
|
||||
}
|
||||
UniformData::TextureUnit(unit) => gl::Uniform1i(uniform.location, unit as GLint),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_framebuffer(&self, texture: GLTexture) -> GLFramebuffer {
|
||||
let mut gl_framebuffer = 0;
|
||||
unsafe {
|
||||
gl::GenFramebuffers(1, &mut gl_framebuffer);
|
||||
assert_eq!(gl::GetError(), gl::NO_ERROR);
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, gl_framebuffer);
|
||||
self.bind_texture(&texture, 0);
|
||||
gl::FramebufferTexture2D(gl::FRAMEBUFFER,
|
||||
gl::COLOR_ATTACHMENT0,
|
||||
gl::TEXTURE_2D,
|
||||
texture.gl_texture,
|
||||
0);
|
||||
assert_eq!(gl::CheckFramebufferStatus(gl::FRAMEBUFFER), gl::FRAMEBUFFER_COMPLETE);
|
||||
}
|
||||
|
||||
GLFramebuffer { gl_framebuffer, texture }
|
||||
}
|
||||
|
||||
fn create_buffer(&self) -> GLBuffer {
|
||||
unsafe {
|
||||
let mut gl_buffer = 0;
|
||||
gl::GenBuffers(1, &mut gl_buffer);
|
||||
GLBuffer { gl_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
fn upload_to_buffer<T>(&self,
|
||||
buffer: &GLBuffer,
|
||||
data: &[T],
|
||||
target: BufferTarget,
|
||||
mode: BufferUploadMode) {
|
||||
let target = match target {
|
||||
BufferTarget::Vertex => gl::ARRAY_BUFFER,
|
||||
BufferTarget::Index => gl::ELEMENT_ARRAY_BUFFER,
|
||||
};
|
||||
let mode = match mode {
|
||||
BufferUploadMode::Static => gl::STATIC_DRAW,
|
||||
BufferUploadMode::Dynamic => gl::DYNAMIC_DRAW,
|
||||
};
|
||||
unsafe {
|
||||
gl::BindBuffer(target, buffer.gl_buffer);
|
||||
gl::BufferData(target,
|
||||
(data.len() * mem::size_of::<T>()) as GLsizeiptr,
|
||||
data.as_ptr() as *const GLvoid,
|
||||
mode);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture {
|
||||
&framebuffer.texture
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn texture_size(&self, texture: &Self::Texture) -> Point2DI32 {
|
||||
texture.size
|
||||
}
|
||||
|
||||
fn upload_to_texture(&self, texture: &Self::Texture, size: Point2DI32, data: &[u8]) {
|
||||
assert!(data.len() >= size.x() as usize * size.y() as usize * 4);
|
||||
unsafe {
|
||||
self.bind_texture(texture, 0);
|
||||
gl::TexImage2D(gl::TEXTURE_2D,
|
||||
0,
|
||||
gl::RGBA as GLint,
|
||||
size.x() as GLsizei,
|
||||
size.y() as GLsizei,
|
||||
0,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
data.as_ptr() as *const GLvoid);
|
||||
}
|
||||
|
||||
self.set_texture_parameters(texture);
|
||||
}
|
||||
|
||||
fn read_pixels_from_default_framebuffer(&self, size: Point2DI32) -> Vec<u8> {
|
||||
let mut pixels = vec![0; size.x() as usize * size.y() as usize * 4];
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||
gl::ReadPixels(0,
|
||||
0,
|
||||
size.x() as GLsizei,
|
||||
size.y() as GLsizei,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
pixels.as_mut_ptr() as *mut GLvoid);
|
||||
}
|
||||
|
||||
// Flip right-side-up.
|
||||
let stride = size.x() as usize * 4;
|
||||
for y in 0..(size.y() as usize / 2) {
|
||||
let (index_a, index_b) = (y * stride, (size.y() as usize - y - 1) * stride);
|
||||
for offset in 0..stride {
|
||||
pixels.swap(index_a + offset, index_b + offset);
|
||||
}
|
||||
}
|
||||
|
||||
pixels
|
||||
}
|
||||
|
||||
// TODO(pcwalton): Switch to `ColorF`!
|
||||
fn clear(&self, color: Option<F32x4>, depth: Option<f32>, stencil: Option<u8>) {
|
||||
unsafe {
|
||||
let mut flags = 0;
|
||||
if let Some(color) = color {
|
||||
gl::ClearColor(color.x(), color.y(), color.z(), color.w());
|
||||
flags |= gl::COLOR_BUFFER_BIT;
|
||||
}
|
||||
if let Some(depth) = depth {
|
||||
gl::ClearDepth(depth as GLdouble);
|
||||
flags |= gl::DEPTH_BUFFER_BIT;
|
||||
}
|
||||
if let Some(stencil) = stencil {
|
||||
gl::ClearStencil(stencil as GLint);
|
||||
flags |= gl::STENCIL_BUFFER_BIT;
|
||||
}
|
||||
if flags != 0 {
|
||||
gl::Clear(flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) {
|
||||
self.set_render_state(render_state);
|
||||
unsafe {
|
||||
gl::DrawArrays(primitive.to_gl_primitive(), 0, index_count as GLsizei);
|
||||
}
|
||||
self.reset_render_state(render_state);
|
||||
}
|
||||
|
||||
fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState) {
|
||||
self.set_render_state(render_state);
|
||||
unsafe {
|
||||
gl::DrawElements(primitive.to_gl_primitive(),
|
||||
index_count as GLsizei,
|
||||
gl::UNSIGNED_INT,
|
||||
ptr::null());
|
||||
}
|
||||
self.reset_render_state(render_state);
|
||||
}
|
||||
|
||||
fn draw_arrays_instanced(&self,
|
||||
primitive: Primitive,
|
||||
index_count: u32,
|
||||
instance_count: u32,
|
||||
render_state: &RenderState) {
|
||||
self.set_render_state(render_state);
|
||||
unsafe {
|
||||
gl::DrawArraysInstanced(primitive.to_gl_primitive(),
|
||||
0,
|
||||
index_count as GLsizei,
|
||||
instance_count as GLsizei);
|
||||
}
|
||||
self.reset_render_state(render_state);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn create_timer_query(&self) -> GLTimerQuery {
|
||||
let mut query = GLTimerQuery { gl_query: 0 };
|
||||
unsafe {
|
||||
gl::GenQueries(1, &mut query.gl_query);
|
||||
}
|
||||
query
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn begin_timer_query(&self, query: &Self::TimerQuery) {
|
||||
unsafe {
|
||||
gl::BeginQuery(gl::TIME_ELAPSED, query.gl_query);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end_timer_query(&self, _: &Self::TimerQuery) {
|
||||
unsafe {
|
||||
gl::EndQuery(gl::TIME_ELAPSED);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool {
|
||||
unsafe {
|
||||
let mut result = 0;
|
||||
gl::GetQueryObjectiv(query.gl_query, gl::QUERY_RESULT_AVAILABLE, &mut result);
|
||||
result != gl::FALSE as GLint
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration {
|
||||
unsafe {
|
||||
let mut result = 0;
|
||||
gl::GetQueryObjectui64v(query.gl_query, gl::QUERY_RESULT, &mut result);
|
||||
Duration::from_nanos(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bind_vertex_array(&self, vertex_array: &GLVertexArray) {
|
||||
unsafe {
|
||||
gl::BindVertexArray(vertex_array.gl_vertex_array);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bind_buffer(&self, buffer: &GLBuffer, target: BufferTarget) {
|
||||
unsafe {
|
||||
gl::BindBuffer(target.to_gl_target(), buffer.gl_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bind_default_framebuffer(&self, size: Point2DI32) {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||
gl::Viewport(0, 0, size.x(), size.y());
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bind_framebuffer(&self, framebuffer: &GLFramebuffer) {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.gl_framebuffer);
|
||||
gl::Viewport(0, 0, framebuffer.texture.size.x(), framebuffer.texture.size.y());
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bind_texture(&self, texture: &GLTexture, unit: u32) {
|
||||
unsafe {
|
||||
gl::ActiveTexture(gl::TEXTURE0 + unit);
|
||||
gl::BindTexture(gl::TEXTURE_2D, texture.gl_texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GLVertexArray {
|
||||
pub gl_vertex_array: GLuint,
|
||||
}
|
||||
|
||||
impl Drop for VertexArray {
|
||||
impl Drop for GLVertexArray {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
@ -142,30 +563,11 @@ impl Drop for VertexArray {
|
|||
}
|
||||
}
|
||||
|
||||
impl VertexArray {
|
||||
#[inline]
|
||||
pub fn new() -> VertexArray {
|
||||
unsafe {
|
||||
let mut array = VertexArray { gl_vertex_array: 0 };
|
||||
gl::GenVertexArrays(1, &mut array.gl_vertex_array);
|
||||
array
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VertexAttr {
|
||||
pub struct GLVertexAttr {
|
||||
attr: GLuint,
|
||||
}
|
||||
|
||||
impl VertexAttr {
|
||||
pub fn new(program: &Program, name: &str) -> VertexAttr {
|
||||
let name = CString::new(format!("a{}", name)).unwrap();
|
||||
let attr = unsafe {
|
||||
gl::GetAttribLocation(program.gl_program, name.as_ptr() as *const GLchar) as GLuint
|
||||
};
|
||||
VertexAttr { attr }
|
||||
}
|
||||
|
||||
impl GLVertexAttr {
|
||||
pub fn configure_float(&self,
|
||||
size: GLint,
|
||||
gl_type: GLuint,
|
||||
|
@ -199,37 +601,12 @@ impl VertexAttr {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Framebuffer {
|
||||
pub struct GLFramebuffer {
|
||||
pub gl_framebuffer: GLuint,
|
||||
pub texture: Texture,
|
||||
pub texture: GLTexture,
|
||||
}
|
||||
|
||||
impl Framebuffer {
|
||||
pub fn new(texture: Texture) -> Framebuffer {
|
||||
let mut gl_framebuffer = 0;
|
||||
unsafe {
|
||||
gl::GenFramebuffers(1, &mut gl_framebuffer);
|
||||
assert_eq!(gl::GetError(), gl::NO_ERROR);
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, gl_framebuffer);
|
||||
texture.bind(0);
|
||||
gl::FramebufferTexture2D(gl::FRAMEBUFFER,
|
||||
gl::COLOR_ATTACHMENT0,
|
||||
gl::TEXTURE_2D,
|
||||
texture.gl_texture,
|
||||
0);
|
||||
assert_eq!(gl::CheckFramebufferStatus(gl::FRAMEBUFFER), gl::FRAMEBUFFER_COMPLETE);
|
||||
}
|
||||
Framebuffer { gl_framebuffer, texture }
|
||||
}
|
||||
|
||||
pub fn bind(&self) {
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, self.gl_framebuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Framebuffer {
|
||||
impl Drop for GLFramebuffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteFramebuffers(1, &mut self.gl_framebuffer)
|
||||
|
@ -237,39 +614,11 @@ impl Drop for Framebuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Buffer {
|
||||
pub struct GLBuffer {
|
||||
pub gl_buffer: GLuint,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new() -> Buffer {
|
||||
unsafe {
|
||||
let mut gl_buffer = 0;
|
||||
gl::GenBuffers(1, &mut gl_buffer);
|
||||
Buffer { gl_buffer }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upload<T>(&self, data: &[T], target: BufferTarget, mode: BufferUploadMode) {
|
||||
let target = match target {
|
||||
BufferTarget::Vertex => gl::ARRAY_BUFFER,
|
||||
BufferTarget::Index => gl::ELEMENT_ARRAY_BUFFER,
|
||||
};
|
||||
let mode = match mode {
|
||||
BufferUploadMode::Static => gl::STATIC_DRAW,
|
||||
BufferUploadMode::Dynamic => gl::DYNAMIC_DRAW,
|
||||
};
|
||||
unsafe {
|
||||
gl::BindBuffer(target, self.gl_buffer);
|
||||
gl::BufferData(target,
|
||||
(data.len() * mem::size_of::<T>()) as GLsizeiptr,
|
||||
data.as_ptr() as *const GLvoid,
|
||||
mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Buffer {
|
||||
impl Drop for GLBuffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteBuffers(1, &mut self.gl_buffer)
|
||||
|
@ -277,40 +626,20 @@ impl Drop for Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum BufferTarget {
|
||||
Vertex,
|
||||
Index,
|
||||
}
|
||||
|
||||
pub enum BufferUploadMode {
|
||||
Static,
|
||||
Dynamic,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Uniform {
|
||||
pub struct GLUniform {
|
||||
pub location: GLint,
|
||||
}
|
||||
|
||||
impl Uniform {
|
||||
pub fn new(program: &Program, name: &str) -> Uniform {
|
||||
let name = CString::new(format!("u{}", name)).unwrap();
|
||||
let location = unsafe {
|
||||
gl::GetUniformLocation(program.gl_program, name.as_ptr() as *const GLchar)
|
||||
};
|
||||
Uniform { location }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Program {
|
||||
pub struct GLProgram {
|
||||
pub gl_program: GLuint,
|
||||
#[allow(dead_code)]
|
||||
vertex_shader: Shader,
|
||||
vertex_shader: GLShader,
|
||||
#[allow(dead_code)]
|
||||
fragment_shader: Shader,
|
||||
fragment_shader: GLShader,
|
||||
}
|
||||
|
||||
impl Drop for Program {
|
||||
impl Drop for GLProgram {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteProgram(self.gl_program)
|
||||
|
@ -318,11 +647,11 @@ impl Drop for Program {
|
|||
}
|
||||
}
|
||||
|
||||
struct Shader {
|
||||
pub struct GLShader {
|
||||
gl_shader: GLuint,
|
||||
}
|
||||
|
||||
impl Drop for Shader {
|
||||
impl Drop for GLShader {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
gl::DeleteShader(self.gl_shader)
|
||||
|
@ -330,99 +659,16 @@ impl Drop for Shader {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum ShaderKind {
|
||||
Vertex,
|
||||
Fragment,
|
||||
}
|
||||
|
||||
pub struct Texture {
|
||||
pub struct GLTexture {
|
||||
gl_texture: GLuint,
|
||||
pub size: Point2DI32,
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
pub fn new_r16f(size: Point2DI32) -> Texture {
|
||||
let mut texture = Texture { gl_texture: 0, size };
|
||||
unsafe {
|
||||
gl::GenTextures(1, &mut texture.gl_texture);
|
||||
texture.bind(0);
|
||||
gl::TexImage2D(gl::TEXTURE_2D,
|
||||
0,
|
||||
gl::R16F as GLint,
|
||||
size.x() as GLsizei,
|
||||
size.y() as GLsizei,
|
||||
0,
|
||||
gl::RED,
|
||||
gl::HALF_FLOAT,
|
||||
ptr::null());
|
||||
}
|
||||
|
||||
texture.set_parameters();
|
||||
texture
|
||||
}
|
||||
|
||||
pub fn new_rgba(size: Point2DI32) -> Texture {
|
||||
let mut texture = Texture { gl_texture: 0, size };
|
||||
unsafe {
|
||||
gl::GenTextures(1, &mut texture.gl_texture);
|
||||
texture.bind(0);
|
||||
gl::TexImage2D(gl::TEXTURE_2D,
|
||||
0,
|
||||
gl::RGBA as GLint,
|
||||
size.x() as GLsizei,
|
||||
size.y() as GLsizei,
|
||||
0,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
ptr::null());
|
||||
}
|
||||
|
||||
texture.set_parameters();
|
||||
texture
|
||||
}
|
||||
|
||||
pub fn bind(&self, unit: u32) {
|
||||
unsafe {
|
||||
gl::ActiveTexture(gl::TEXTURE0 + unit);
|
||||
gl::BindTexture(gl::TEXTURE_2D, self.gl_texture);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn upload_rgba(&self, size: Point2DI32, data: &[u8]) {
|
||||
assert!(data.len() >= size.x() as usize * size.y() as usize * 4);
|
||||
unsafe {
|
||||
self.bind(0);
|
||||
gl::TexImage2D(gl::TEXTURE_2D,
|
||||
0,
|
||||
gl::RGBA as GLint,
|
||||
size.x() as GLsizei,
|
||||
size.y() as GLsizei,
|
||||
0,
|
||||
gl::RGBA,
|
||||
gl::UNSIGNED_BYTE,
|
||||
data.as_ptr() as *const GLvoid);
|
||||
}
|
||||
|
||||
self.set_parameters();
|
||||
}
|
||||
|
||||
fn set_parameters(&self) {
|
||||
self.bind(0);
|
||||
unsafe {
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
|
||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TimerQuery {
|
||||
pub struct GLTimerQuery {
|
||||
gl_query: GLuint,
|
||||
}
|
||||
|
||||
impl Drop for TimerQuery {
|
||||
impl Drop for GLTimerQuery {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
@ -431,70 +677,71 @@ impl Drop for TimerQuery {
|
|||
}
|
||||
}
|
||||
|
||||
impl TimerQuery {
|
||||
#[inline]
|
||||
pub fn new() -> TimerQuery {
|
||||
let mut query = TimerQuery { gl_query: 0 };
|
||||
unsafe {
|
||||
gl::GenQueries(1, &mut query.gl_query);
|
||||
}
|
||||
query
|
||||
trait BufferTargetExt {
|
||||
fn to_gl_target(self) -> GLuint;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn begin(&self) {
|
||||
unsafe {
|
||||
gl::BeginQuery(gl::TIME_ELAPSED, self.gl_query);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end(&self) {
|
||||
unsafe {
|
||||
gl::EndQuery(gl::TIME_ELAPSED);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_available(&self) -> bool {
|
||||
unsafe {
|
||||
let mut result = 0;
|
||||
gl::GetQueryObjectiv(self.gl_query, gl::QUERY_RESULT_AVAILABLE, &mut result);
|
||||
result != gl::FALSE as GLint
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self) -> u64 {
|
||||
unsafe {
|
||||
let mut result = 0;
|
||||
gl::GetQueryObjectui64v(self.gl_query, gl::QUERY_RESULT, &mut result);
|
||||
result
|
||||
impl BufferTargetExt for BufferTarget {
|
||||
fn to_gl_target(self) -> GLuint {
|
||||
match self {
|
||||
BufferTarget::Vertex => gl::ARRAY_BUFFER,
|
||||
BufferTarget::Index => gl::ELEMENT_ARRAY_BUFFER,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
trait DepthFuncExt {
|
||||
fn to_gl_depth_func(self) -> GLenum;
|
||||
}
|
||||
|
||||
impl DepthFuncExt for DepthFunc {
|
||||
fn to_gl_depth_func(self) -> GLenum {
|
||||
match self {
|
||||
DepthFunc::Less => gl::LESS,
|
||||
DepthFunc::Always => gl::ALWAYS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !parent_directory.pop() {
|
||||
break;
|
||||
trait PrimitiveExt {
|
||||
fn to_gl_primitive(self) -> GLuint;
|
||||
}
|
||||
|
||||
impl PrimitiveExt for Primitive {
|
||||
fn to_gl_primitive(self) -> GLuint {
|
||||
match self {
|
||||
Primitive::Triangles => gl::TRIANGLES,
|
||||
Primitive::TriangleFan => gl::TRIANGLE_FAN,
|
||||
Primitive::Lines => gl::LINES,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic!("No suitable `resources/` directory found!");
|
||||
trait StencilFuncExt {
|
||||
fn to_gl_stencil_func(self) -> GLenum;
|
||||
}
|
||||
|
||||
impl StencilFuncExt for StencilFunc {
|
||||
fn to_gl_stencil_func(self) -> GLenum {
|
||||
match self {
|
||||
StencilFunc::Always => gl::ALWAYS,
|
||||
StencilFunc::Equal => gl::EQUAL,
|
||||
StencilFunc::NotEqual => gl::NOTEQUAL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait VertexAttrTypeExt {
|
||||
fn to_gl_type(self) -> GLuint;
|
||||
}
|
||||
|
||||
impl VertexAttrTypeExt for VertexAttrType {
|
||||
fn to_gl_type(self) -> GLuint {
|
||||
match self {
|
||||
VertexAttrType::F32 => gl::FLOAT,
|
||||
VertexAttrType::I16 => gl::SHORT,
|
||||
VertexAttrType::U16 => gl::UNSIGNED_SHORT,
|
||||
VertexAttrType::U8 => gl::UNSIGNED_BYTE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "pathfinder_gpu"
|
||||
version = "0.1.0"
|
||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dependencies.image]
|
||||
version = "0.21"
|
||||
default-features = false
|
||||
features = ["png_codec"]
|
||||
|
||||
[dependencies.pathfinder_geometry]
|
||||
path = "../geometry"
|
||||
|
||||
[dependencies.pathfinder_simd]
|
||||
path = "../simd"
|
|
@ -0,0 +1,266 @@
|
|||
// pathfinder/gpu/src/lib.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.
|
||||
|
||||
//! Minimal abstractions over GPU device capabilities.
|
||||
|
||||
use pathfinder_geometry::basic::point::Point2DI32;
|
||||
use pathfinder_simd::default::F32x4;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
pub trait Device {
|
||||
type Buffer;
|
||||
type Framebuffer;
|
||||
type Program;
|
||||
type Shader;
|
||||
type Texture;
|
||||
type TimerQuery;
|
||||
type Uniform;
|
||||
type VertexArray;
|
||||
type VertexAttr;
|
||||
|
||||
fn create_texture(&self, format: TextureFormat, size: Point2DI32) -> Self::Texture;
|
||||
fn create_texture_from_data(&self, size: Point2DI32, data: &[u8]) -> Self::Texture;
|
||||
fn create_shader_from_source(&self, name: &str, source: &[u8], kind: ShaderKind)
|
||||
-> Self::Shader;
|
||||
fn create_vertex_array(&self) -> Self::VertexArray;
|
||||
fn create_program_from_shaders(&self,
|
||||
name: &str,
|
||||
vertex_shader: Self::Shader,
|
||||
fragment_shader: Self::Shader)
|
||||
-> Self::Program;
|
||||
fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Self::VertexAttr;
|
||||
fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform;
|
||||
fn use_program(&self, program: &Self::Program);
|
||||
fn configure_float_vertex_attr(&self,
|
||||
attr: &Self::VertexAttr,
|
||||
size: usize,
|
||||
attr_type: VertexAttrType,
|
||||
normalized: bool,
|
||||
stride: usize,
|
||||
offset: usize,
|
||||
divisor: u32);
|
||||
fn configure_int_vertex_attr(&self,
|
||||
attr: &Self::VertexAttr,
|
||||
size: usize,
|
||||
attr_type: VertexAttrType,
|
||||
stride: usize,
|
||||
offset: usize,
|
||||
divisor: u32);
|
||||
fn set_uniform(&self, uniform: &Self::Uniform, data: UniformData);
|
||||
fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer;
|
||||
fn create_buffer(&self) -> Self::Buffer;
|
||||
fn upload_to_buffer<T>(&self,
|
||||
buffer: &Self::Buffer,
|
||||
data: &[T],
|
||||
target: BufferTarget,
|
||||
mode: BufferUploadMode);
|
||||
fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture;
|
||||
fn texture_size(&self, texture: &Self::Texture) -> Point2DI32;
|
||||
fn upload_to_texture(&self, texture: &Self::Texture, size: Point2DI32, data: &[u8]);
|
||||
fn read_pixels_from_default_framebuffer(&self, size: Point2DI32) -> Vec<u8>;
|
||||
// TODO(pcwalton): Switch to `ColorF`!
|
||||
fn clear(&self, color: Option<F32x4>, depth: Option<f32>, stencil: Option<u8>);
|
||||
fn draw_arrays(&self, primitive: Primitive, index_count: u32, render_state: &RenderState);
|
||||
fn draw_elements(&self, primitive: Primitive, index_count: u32, render_state: &RenderState);
|
||||
fn draw_arrays_instanced(&self,
|
||||
primitive: Primitive,
|
||||
index_count: u32,
|
||||
instance_count: u32,
|
||||
render_state: &RenderState);
|
||||
fn create_timer_query(&self) -> Self::TimerQuery;
|
||||
fn begin_timer_query(&self, query: &Self::TimerQuery);
|
||||
fn end_timer_query(&self, query: &Self::TimerQuery);
|
||||
fn timer_query_is_available(&self, query: &Self::TimerQuery) -> bool;
|
||||
fn get_timer_query(&self, query: &Self::TimerQuery) -> Duration;
|
||||
|
||||
// TODO(pcwalton): Go bindless...
|
||||
fn bind_vertex_array(&self, vertex_array: &Self::VertexArray);
|
||||
fn bind_buffer(&self, buffer: &Self::Buffer, target: BufferTarget);
|
||||
fn bind_default_framebuffer(&self, size: Point2DI32);
|
||||
fn bind_framebuffer(&self, framebuffer: &Self::Framebuffer);
|
||||
fn bind_texture(&self, texture: &Self::Texture, unit: u32);
|
||||
|
||||
fn create_texture_from_png(&self, resources: &Resources, name: &str) -> Self::Texture {
|
||||
let mut path = resources.resources_directory.clone();
|
||||
path.push("textures");
|
||||
path.push(format!("{}.png", name));
|
||||
|
||||
let image = image::open(&path).unwrap().to_luma();
|
||||
let size = Point2DI32::new(image.width() as i32, image.height() as i32);
|
||||
self.create_texture_from_data(size, &image)
|
||||
}
|
||||
|
||||
fn create_shader(&self, resources: &Resources, name: &str, kind: ShaderKind) -> Self::Shader {
|
||||
let suffix = match kind { ShaderKind::Vertex => 'v', ShaderKind::Fragment => 'f' };
|
||||
let mut path = resources.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();
|
||||
self.create_shader_from_source(name, &source, kind)
|
||||
}
|
||||
|
||||
fn create_program(&self, resources: &Resources, name: &str) -> Self::Program {
|
||||
let vertex_shader = self.create_shader(resources, name, ShaderKind::Vertex);
|
||||
let fragment_shader = self.create_shader(resources, name, ShaderKind::Fragment);
|
||||
self.create_program_from_shaders(name, vertex_shader, fragment_shader)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TextureFormat {
|
||||
R16F,
|
||||
RGBA8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum VertexAttrType {
|
||||
F32,
|
||||
I16,
|
||||
U16,
|
||||
U8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum BufferTarget {
|
||||
Vertex,
|
||||
Index,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum BufferUploadMode {
|
||||
Static,
|
||||
Dynamic,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum ShaderKind {
|
||||
Vertex,
|
||||
Fragment,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum UniformData {
|
||||
Vec2(F32x4),
|
||||
Vec4(F32x4),
|
||||
TextureUnit(u32),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Primitive {
|
||||
Triangles,
|
||||
TriangleFan,
|
||||
Lines,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct RenderState {
|
||||
pub blend: BlendState,
|
||||
pub depth: Option<DepthState>,
|
||||
pub stencil: Option<StencilState>,
|
||||
pub color_mask: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum BlendState {
|
||||
Off,
|
||||
RGBOneAlphaOneMinusSrcAlpha,
|
||||
RGBOneAlphaOne,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug)]
|
||||
pub struct DepthState {
|
||||
pub func: DepthFunc,
|
||||
pub write: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DepthFunc {
|
||||
Less,
|
||||
Always,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StencilState {
|
||||
pub func: StencilFunc,
|
||||
pub reference: u32,
|
||||
pub mask: u32,
|
||||
pub pass_replace: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum StencilFunc {
|
||||
Always,
|
||||
Equal,
|
||||
NotEqual,
|
||||
}
|
||||
|
||||
impl Default for BlendState {
|
||||
#[inline]
|
||||
fn default() -> BlendState {
|
||||
BlendState::Off
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StencilState {
|
||||
#[inline]
|
||||
fn default() -> StencilState {
|
||||
StencilState { func: StencilFunc::default(), reference: 0, mask: !0, pass_replace: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DepthFunc {
|
||||
#[inline]
|
||||
fn default() -> DepthFunc {
|
||||
DepthFunc::Less
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StencilFunc {
|
||||
#[inline]
|
||||
fn default() -> StencilFunc {
|
||||
StencilFunc::Always
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Resources {
|
||||
pub resources_directory: PathBuf,
|
||||
}
|
||||
|
||||
impl Resources {
|
||||
pub fn locate() -> Resources {
|
||||
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 { resources_directory };
|
||||
}
|
||||
}
|
||||
|
||||
if !parent_directory.pop() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
panic!("No suitable `resources/` directory found!");
|
||||
}
|
||||
}
|
|
@ -8,9 +8,16 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::default::{F32x4, U32x4};
|
||||
use crate::default::F32x4;
|
||||
|
||||
impl F32x4 {
|
||||
// Constructors
|
||||
|
||||
#[inline]
|
||||
pub fn from_slice(slice: &[f32]) -> F32x4 {
|
||||
F32x4::new(slice[0], slice[1], slice[2], slice[3])
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -131,11 +131,6 @@ impl F32x4 {
|
|||
F32x4([self[2], other[2], self[3], other[3]]))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn transpose4(a: &mut F32x4, b: &mut F32x4, c: &mut F32x4, d: &mut F32x4) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cross(&self, other: F32x4) -> F32x4 {
|
||||
unimplemented!()
|
||||
|
|
|
@ -1427,11 +1427,6 @@ impl F32x4 {
|
|||
unsafe { F32x4(x86_64::_mm_shuffle_ps(self.0, other.0, 0b0001_1011)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn transpose_4x4(a: &mut F32x4, b: &mut F32x4, c: &mut F32x4, d: &mut F32x4) {
|
||||
unsafe { x86_64::_MM_TRANSPOSE4_PS(&mut a.0, &mut b.0, &mut c.0, &mut d.0) }
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Move to `Point3DF32`!
|
||||
#[inline]
|
||||
pub fn cross(&self, other: F32x4) -> F32x4 {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[package]
|
||||
name = "pathfinder_ui"
|
||||
version = "0.1.0"
|
||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
edition = "2018"
|
|
@ -0,0 +1 @@
|
|||
|
Loading…
Reference in New Issue