Add some ground to the 3D scene, no depth buffer yet

This commit is contained in:
Patrick Walton 2019-02-14 18:53:02 -08:00
parent 0983812b90
commit e4803cfddf
11 changed files with 458 additions and 193 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

View File

@ -0,0 +1,21 @@
#version 330
// pathfinder/demo/resources/shaders/demo_ground.fs.glsl
//
// 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.
precision highp float;
uniform vec4 uColor;
out vec4 oFragColor;
void main() {
oFragColor = uColor;
}

View File

@ -0,0 +1,21 @@
#version 330
// pathfinder/demo/resources/shaders/demo_ground.vs.glsl
//
// 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.
precision highp float;
uniform mat4 uTransform;
in vec2 aPosition;
void main() {
gl_Position = uTransform * vec4(aPosition.x * 800.0, -30.0, aPosition.y * 800.0, 1.0);
}

View File

@ -13,11 +13,14 @@
use crate::ui::{DemoUI, UIAction, UIEvent}; use crate::ui::{DemoUI, UIAction, UIEvent};
use clap::{App, Arg}; use clap::{App, Arg};
use euclid::Size2D; use euclid::Size2D;
use gl::types::GLsizei;
use jemallocator; use jemallocator;
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32}; use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32};
use pathfinder_geometry::basic::rect::RectF32; use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::basic::transform2d::Transform2DF32; use pathfinder_geometry::basic::transform2d::Transform2DF32;
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32}; use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
use pathfinder_gl::device::{Buffer, BufferTarget, BufferUploadMode, Program, Uniform};
use pathfinder_gl::device::{VertexArray, VertexAttr};
use pathfinder_gl::renderer::Renderer; use pathfinder_gl::renderer::Renderer;
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder}; use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
use pathfinder_renderer::gpu_data::BuiltScene; use pathfinder_renderer::gpu_data::BuiltScene;
@ -56,11 +59,15 @@ const CAMERA_SCALE_SPEED_2D: f32 = 2.0;
// How much the scene is scaled when a zoom button is clicked. // How much the scene is scaled when a zoom button is clicked.
const CAMERA_ZOOM_AMOUNT_2D: f32 = 0.1; const CAMERA_ZOOM_AMOUNT_2D: f32 = 0.1;
const BACKGROUND_COLOR: ColorU = ColorU { r: 32, g: 32, b: 32, a: 255 }; const BACKGROUND_COLOR: ColorU = ColorU { r: 32, g: 32, b: 32, a: 255 };
const GROUND_SOLID_COLOR: ColorU = ColorU { r: 80, g: 80, b: 80, a: 255 };
const GROUND_LINE_COLOR: ColorU = ColorU { r: 127, g: 127, b: 127, a: 255 };
const APPROX_FONT_SIZE: f32 = 16.0; const APPROX_FONT_SIZE: f32 = 16.0;
const WORLD_SCALE: f32 = 1.0 / 800.0; const WORLD_SCALE: f32 = 800.0;
const GROUND_SCALE: f32 = 2.0;
const GRIDLINE_COUNT: u8 = 10;
mod ui; mod ui;
@ -90,6 +97,11 @@ struct DemoApp {
ui: DemoUI, ui: DemoUI,
scene_thread_proxy: SceneThreadProxy, scene_thread_proxy: SceneThreadProxy,
renderer: Renderer, renderer: Renderer,
device: DemoDevice,
ground_program: GroundProgram,
ground_solid_vertex_array: GroundSolidVertexArray,
ground_line_vertex_array: GroundLineVertexArray,
} }
impl DemoApp { impl DemoApp {
@ -121,11 +133,18 @@ impl DemoApp {
let drawable_size = Size2D::new(drawable_width, drawable_height); let drawable_size = Size2D::new(drawable_width, drawable_height);
let base_scene = load_scene(&options.input_path); let base_scene = load_scene(&options.input_path);
let renderer = Renderer::new(&drawable_size);
let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone()); let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone());
update_drawable_size(&window, &scene_thread_proxy); update_drawable_size(&window, &scene_thread_proxy);
let camera = if options.threed { Camera::three_d() } else { Camera::two_d() }; let camera = if options.threed { Camera::three_d() } else { Camera::two_d() };
let grid_vertex_positions = create_grid_vertex_positions();
let ground_program = GroundProgram::new();
let ground_solid_vertex_array =
GroundSolidVertexArray::new(&ground_program, &renderer.quad_vertex_positions_buffer());
let ground_line_vertex_array = GroundLineVertexArray::new(&ground_program);
DemoApp { DemoApp {
window, window,
sdl_context, sdl_context,
@ -144,7 +163,12 @@ impl DemoApp {
ui: DemoUI::new(options), ui: DemoUI::new(options),
scene_thread_proxy, scene_thread_proxy,
renderer: Renderer::new(&drawable_size), renderer,
device: DemoDevice,
ground_program,
ground_solid_vertex_array,
ground_line_vertex_array,
} }
} }
@ -165,31 +189,14 @@ impl DemoApp {
fn build_scene(&mut self) { fn build_scene(&mut self) {
let (drawable_width, drawable_height) = self.window.drawable_size(); let (drawable_width, drawable_height) = self.window.drawable_size();
let drawable_size = Size2D::new(drawable_width, drawable_height); let drawable_size = Point2DI32::new(drawable_width as i32, drawable_height as i32);
let render_transform = match self.camera { let render_transform = match self.camera {
Camera::ThreeD { ref mut position, velocity, yaw, pitch } => { Camera::ThreeD { ref mut transform, ref mut velocity } => {
let rotation = Transform3DF32::from_rotation(-yaw, -pitch, 0.0); if transform.offset(*velocity) {
if !velocity.is_zero() {
*position = *position + rotation.transform_point(velocity);
self.dirty = true; self.dirty = true;
} }
RenderTransform::Perspective(transform.to_perspective(drawable_size, true))
let aspect = drawable_size.width as f32 / drawable_size.height as f32;
let mut transform =
Transform3DF32::from_perspective(FRAC_PI_4, aspect, 0.025, 100.0);
transform = transform.post_mul(&Transform3DF32::from_scale(WORLD_SCALE,
WORLD_SCALE,
WORLD_SCALE));
transform = transform.post_mul(&Transform3DF32::from_rotation(yaw, pitch, 0.0));
let translation = position.scale(-1.0);
transform = transform.post_mul(&Transform3DF32::from_translation(translation.x(),
translation.y(),
translation.z()));
RenderTransform::Perspective(Perspective::new(&transform, &drawable_size))
} }
Camera::TwoD(transform) => RenderTransform::Transform2D(transform), Camera::TwoD(transform) => RenderTransform::Transform2D(transform),
}; };
@ -242,10 +249,9 @@ impl DemoApp {
ui_event = UIEvent::MouseDown(point); ui_event = UIEvent::MouseDown(point);
} }
Event::MouseMotion { xrel, yrel, .. } if self.mouselook_enabled => { Event::MouseMotion { xrel, yrel, .. } if self.mouselook_enabled => {
if let Camera::ThreeD { ref mut yaw, ref mut pitch, .. } = if let Camera::ThreeD { ref mut transform, .. } = self.camera {
self.camera { transform.yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED;
*yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED; transform.pitch += yrel as f32 * MOUSELOOK_ROTATION_SPEED;
*pitch -= yrel as f32 * MOUSELOOK_ROTATION_SPEED;
self.dirty = true; self.dirty = true;
} }
} }
@ -315,105 +321,155 @@ impl DemoApp {
fn draw_scene(&mut self, render_msg: SceneToMainMsg, mut ui_event: UIEvent) { fn draw_scene(&mut self, render_msg: SceneToMainMsg, mut ui_event: UIEvent) {
let SceneToMainMsg::Render { built_scene, tile_time } = render_msg; let SceneToMainMsg::Render { built_scene, tile_time } = render_msg;
unsafe { self.device.clear();
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); self.draw_environment();
gl::ClearColor(BACKGROUND_COLOR.r as f32 / 255.0, self.render_vector_scene(&built_scene);
BACKGROUND_COLOR.g as f32 / 255.0,
BACKGROUND_COLOR.b as f32 / 255.0,
BACKGROUND_COLOR.a as f32 / 255.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
if self.ui.gamma_correction_effect_enabled { let rendering_time = self.renderer.shift_timer_query();
self.renderer.enable_gamma_correction(BACKGROUND_COLOR); self.renderer.debug_ui.add_sample(tile_time, rendering_time);
} else { self.renderer.debug_ui.draw();
self.renderer.disable_gamma_correction();
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.handle_ui_action(&mut ui_action);
// Switch camera mode (2D/3D) if requested.
//
// FIXME(pcwalton): This mess should really be an MVC setup.
match (&self.camera, self.ui.threed_enabled) {
(&Camera::TwoD { .. }, true) => self.camera = Camera::three_d(),
(&Camera::ThreeD { .. }, false) => self.camera = Camera::two_d(),
_ => {}
}
match ui_event {
UIEvent::MouseDown(_) if self.camera.is_3d() => {
// If nothing handled the mouse-down event, toggle mouselook.
self.mouselook_enabled = !self.mouselook_enabled;
} }
UIEvent::MouseDragged { relative_position, .. } => {
if self.ui.subpixel_aa_effect_enabled { if let Camera::TwoD(ref mut transform) = self.camera {
self.renderer.enable_subpixel_aa(&DEFRINGING_KERNEL_CORE_GRAPHICS); *transform = transform.post_translate(relative_position.to_f32());
} else {
self.renderer.disable_subpixel_aa();
}
self.renderer.render_scene(&built_scene);
let rendering_time = self.renderer.shift_timer_query();
self.renderer.debug_ui.add_sample(tile_time, rendering_time);
self.renderer.debug_ui.draw();
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);
// Handle UI actions.
match ui_action {
UIAction::None => {}
UIAction::OpenFile(path) => {
let scene = load_scene(&path);
self.scene_thread_proxy.load_scene(scene);
update_drawable_size(&self.window, &self.scene_thread_proxy);
self.dirty = true;
}
UIAction::ZoomIn => {
if let Camera::TwoD(ref mut transform) = self.camera {
let scale = Point2DF32::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D);
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_scale(scale)
.post_translate(center);
self.dirty = true;
}
}
UIAction::ZoomOut => {
if let Camera::TwoD(ref mut transform) = self.camera {
let scale = Point2DF32::splat(1.0 - CAMERA_ZOOM_AMOUNT_2D);
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_scale(scale)
.post_translate(center);
self.dirty = true;
}
}
UIAction::Rotate(theta) => {
if let Camera::TwoD(ref mut transform) = self.camera {
let old_rotation = transform.rotation();
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_rotate(theta - old_rotation)
.post_translate(center);
}
} }
} }
_ => {}
// Switch camera mode (2D/3D) if requested.
//
// FIXME(pcwalton): This mess should really be an MVC setup.
match (&self.camera, self.ui.threed_enabled) {
(&Camera::TwoD { .. }, true) => self.camera = Camera::three_d(),
(&Camera::ThreeD { .. }, false) => self.camera = Camera::two_d(),
_ => {}
}
match ui_event {
UIEvent::MouseDown(_) if self.camera.is_3d() => {
// If nothing handled the mouse-down event, toggle mouselook.
self.mouselook_enabled = !self.mouselook_enabled;
}
UIEvent::MouseDragged { relative_position, .. } => {
if let Camera::TwoD(ref mut transform) = self.camera {
*transform = transform.post_translate(relative_position.to_f32());
}
}
_ => {}
}
} }
self.window.gl_swap_window(); self.window.gl_swap_window();
self.frame_counter += 1; self.frame_counter += 1;
} }
fn draw_environment(&self) {
let transform = match self.camera {
Camera::TwoD(..) => return,
Camera::ThreeD { ref transform, .. } => *transform,
};
let (drawable_width, drawable_height) = self.window.drawable_size();
let drawable_size = Point2DI32::new(drawable_width as i32, drawable_height as i32);
let perspective = transform.to_perspective(drawable_size, false);
unsafe {
let mut transform = perspective.transform;
transform =
transform.post_mul(&Transform3DF32::from_scale(GROUND_SCALE, 1.0, GROUND_SCALE));
gl::BindVertexArray(self.ground_solid_vertex_array.vertex_array.gl_vertex_array);
gl::UseProgram(self.ground_program.program.gl_program);
gl::UniformMatrix4fv(self.ground_program.transform_uniform.location,
1,
gl::FALSE,
transform.as_ptr());
let color = GROUND_SOLID_COLOR.to_f32();
gl::Uniform4f(self.ground_program.color_uniform.location,
color.r(),
color.g(),
color.b(),
color.a());
gl::Disable(gl::BLEND);
gl::DrawArrays(gl::TRIANGLE_FAN, 0, 4);
let mut transform = perspective.transform;
let gridline_scale = GROUND_SCALE / GRIDLINE_COUNT as f32;
transform = transform.post_mul(&Transform3DF32::from_scale(gridline_scale,
1.0,
gridline_scale));
gl::BindVertexArray(self.ground_line_vertex_array.vertex_array.gl_vertex_array);
gl::UseProgram(self.ground_program.program.gl_program);
gl::UniformMatrix4fv(self.ground_program.transform_uniform.location,
1,
gl::FALSE,
transform.as_ptr());
let color = GROUND_LINE_COLOR.to_f32();
gl::Uniform4f(self.ground_program.color_uniform.location,
color.r(),
color.g(),
color.b(),
color.a());
gl::Disable(gl::BLEND);
gl::DrawArrays(gl::LINES, 0, (GRIDLINE_COUNT as GLsizei + 1) * 4);
}
}
fn render_vector_scene(&mut self, built_scene: &BuiltScene) {
if self.ui.gamma_correction_effect_enabled {
self.renderer.enable_gamma_correction(BACKGROUND_COLOR);
} else {
self.renderer.disable_gamma_correction();
}
if self.ui.subpixel_aa_effect_enabled {
self.renderer.enable_subpixel_aa(&DEFRINGING_KERNEL_CORE_GRAPHICS);
} else {
self.renderer.disable_subpixel_aa();
}
self.renderer.render_scene(&built_scene);
}
fn handle_ui_action(&mut self, ui_action: &mut UIAction) {
match ui_action {
UIAction::None => {}
UIAction::OpenFile(ref path) => {
let scene = load_scene(&path);
self.scene_thread_proxy.load_scene(scene);
update_drawable_size(&self.window, &self.scene_thread_proxy);
self.dirty = true;
}
UIAction::ZoomIn => {
if let Camera::TwoD(ref mut transform) = self.camera {
let scale = Point2DF32::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D);
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_scale(scale)
.post_translate(center);
self.dirty = true;
}
}
UIAction::ZoomOut => {
if let Camera::TwoD(ref mut transform) = self.camera {
let scale = Point2DF32::splat(1.0 - CAMERA_ZOOM_AMOUNT_2D);
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_scale(scale)
.post_translate(center);
self.dirty = true;
}
}
UIAction::Rotate(theta) => {
if let Camera::TwoD(ref mut transform) = self.camera {
let old_rotation = transform.rotation();
let center = center_of_window(&self.window);
*transform = transform.post_translate(-center)
.post_rotate(*theta - old_rotation)
.post_translate(center);
}
}
}
}
} }
struct SceneThreadProxy { struct SceneThreadProxy {
@ -598,7 +654,7 @@ fn center_of_window(window: &Window) -> Point2DF32 {
enum Camera { enum Camera {
TwoD(Transform2DF32), TwoD(Transform2DF32),
ThreeD { position: Point3DF32, velocity: Point3DF32, yaw: f32, pitch: f32 }, ThreeD { transform: CameraTransform3D, velocity: Point3DF32 },
} }
impl Camera { impl Camera {
@ -607,15 +663,143 @@ impl Camera {
} }
fn three_d() -> Camera { fn three_d() -> Camera {
Camera::ThreeD { Camera::ThreeD { transform: CameraTransform3D::new(), velocity: Point3DF32::default() }
position: Point3DF32::new(500.0, 500.0, 3000.0, 1.0),
velocity: Point3DF32::new(0.0, 0.0, 0.0, 1.0),
yaw: 0.0,
pitch: 0.0,
}
} }
fn is_3d(&self) -> bool { fn is_3d(&self) -> bool {
match *self { Camera::ThreeD { .. } => true, Camera::TwoD { .. } => false } match *self { Camera::ThreeD { .. } => true, Camera::TwoD { .. } => false }
} }
} }
#[derive(Clone, Copy)]
struct CameraTransform3D {
position: Point3DF32,
yaw: f32,
pitch: f32,
}
impl CameraTransform3D {
fn new() -> CameraTransform3D {
CameraTransform3D {
position: Point3DF32::new(500.0, 500.0, 3000.0, 1.0),
yaw: 0.0,
pitch: 0.0,
}
}
fn offset(&mut self, vector: Point3DF32) -> bool {
let update = !vector.is_zero();
if update {
let rotation = Transform3DF32::from_rotation(-self.yaw, -self.pitch, 0.0);
self.position = self.position + rotation.transform_point(vector);
}
update
}
fn to_perspective(&self, drawable_size: Point2DI32, flip_y: bool) -> Perspective {
let aspect = drawable_size.x() as f32 / drawable_size.y() as f32;
let mut transform = Transform3DF32::from_perspective(FRAC_PI_4, aspect, 0.025, 100.0);
let scale_inv = 1.0 / WORLD_SCALE;
transform = transform.post_mul(&Transform3DF32::from_rotation(self.yaw, self.pitch, 0.0));
transform = transform.post_mul(&Transform3DF32::from_uniform_scale(scale_inv));
transform = transform.post_mul(&Transform3DF32::from_translation(-self.position.x(),
-self.position.y(),
-self.position.z()));
if flip_y {
transform = transform.post_mul(&Transform3DF32::from_scale(1.0, -1.0, 1.0));
transform =
transform.post_mul(&Transform3DF32::from_translation(0.0, -WORLD_SCALE, 0.0));
}
let drawable_size = Size2D::new(drawable_size.x() as u32, drawable_size.y() as u32);
Perspective::new(&transform, &drawable_size)
}
}
struct DemoDevice;
impl DemoDevice {
fn clear(&self) {
let color = BACKGROUND_COLOR.to_f32();
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::ClearColor(color.r(), color.g(), color.b(), color.a());
gl::Clear(gl::COLOR_BUFFER_BIT);
}
}
}
struct GroundProgram {
program: Program,
transform_uniform: Uniform,
color_uniform: Uniform,
}
impl GroundProgram {
fn new() -> GroundProgram {
let program = Program::new("demo_ground");
let transform_uniform = Uniform::new(&program, "Transform");
let color_uniform = Uniform::new(&program, "Color");
GroundProgram { program, transform_uniform, color_uniform }
}
}
struct GroundSolidVertexArray {
vertex_array: VertexArray,
}
impl GroundSolidVertexArray {
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");
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);
}
GroundSolidVertexArray { vertex_array }
}
}
struct GroundLineVertexArray {
vertex_array: VertexArray,
grid_vertex_positions_buffer: Buffer,
}
impl GroundLineVertexArray {
fn new(ground_program: &GroundProgram) -> GroundLineVertexArray {
let grid_vertex_positions_buffer = Buffer::new();
grid_vertex_positions_buffer.upload(&create_grid_vertex_positions(),
BufferTarget::Vertex,
BufferUploadMode::Static);
let vertex_array = VertexArray::new();
unsafe {
let position_attr = VertexAttr::new(&ground_program.program, "Position");
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);
}
GroundLineVertexArray { vertex_array, grid_vertex_positions_buffer }
}
}
fn create_grid_vertex_positions() -> Vec<(u8, u8)> {
let mut positions = vec![];
for index in 0..(GRIDLINE_COUNT + 1) {
positions.extend_from_slice(&[
(0, index), (GRIDLINE_COUNT, index),
(index, 0), (index, GRIDLINE_COUNT),
]);
}
positions
}

View File

@ -232,7 +232,7 @@ impl Sub<Point2DI32> for Point2DI32 {
} }
/// 3D homogeneous points. /// 3D homogeneous points.
#[derive(Clone, Copy, Debug, PartialEq, Default)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Point3DF32(pub F32x4); pub struct Point3DF32(pub F32x4);
impl Point3DF32 { impl Point3DF32 {
@ -350,3 +350,12 @@ impl Mul<Point3DF32> for Point3DF32 {
Point3DF32(self.0 * other.0) Point3DF32(self.0 * other.0)
} }
} }
impl Default for Point3DF32 {
#[inline]
fn default() -> Point3DF32 {
let mut point = F32x4::default();
point.set_w(1.0);
Point3DF32(point)
}
}

View File

@ -22,6 +22,7 @@ use std::ops::{Add, Neg};
/// ///
/// In column-major order. /// In column-major order.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
pub struct Transform3DF32 { pub struct Transform3DF32 {
c0: F32x4, c0: F32x4,
c1: F32x4, c1: F32x4,
@ -64,6 +65,11 @@ impl Transform3DF32 {
0.0, 0.0, 0.0, 1.0) 0.0, 0.0, 0.0, 1.0)
} }
#[inline]
pub fn from_uniform_scale(factor: f32) -> Transform3DF32 {
Transform3DF32::from_scale(factor, factor, factor)
}
#[inline] #[inline]
pub fn from_translation(x: f32, y: f32, z: f32) -> Transform3DF32 { pub fn from_translation(x: f32, y: f32, z: f32) -> Transform3DF32 {
Transform3DF32::row_major(1.0, 0.0, 0.0, x, Transform3DF32::row_major(1.0, 0.0, 0.0, x,
@ -229,6 +235,11 @@ impl Transform3DF32 {
self.c2.approx_eq(other.c2, epsilon) && self.c2.approx_eq(other.c2, epsilon) &&
self.c3.approx_eq(other.c3, epsilon) self.c3.approx_eq(other.c3, epsilon)
} }
#[inline]
pub fn as_ptr(&self) -> *const f32 {
(&self.c0) as *const F32x4 as *const f32
}
} }
impl Add<Matrix2x2F32> for Matrix2x2F32 { impl Add<Matrix2x2F32> for Matrix2x2F32 {
@ -261,7 +272,10 @@ impl Perspective {
#[inline] #[inline]
pub fn transform_point_2d(&self, point: &Point2DF32) -> Point2DF32 { pub fn transform_point_2d(&self, point: &Point2DF32) -> Point2DF32 {
let point = self.transform.transform_point(point.to_3d()).perspective_divide().to_2d(); let point = self.transform
.transform_point(point.to_3d())
.perspective_divide()
.to_2d() * Point2DF32::new(1.0, -1.0);
let window_size = self.window_size.to_f32(); let window_size = self.window_size.to_f32();
let size_scale = Point2DF32::new(window_size.width * 0.5, window_size.height * 0.5); let size_scale = Point2DF32::new(window_size.width * 0.5, window_size.height * 0.5);
(point + Point2DF32::splat(1.0)) * size_scale (point + Point2DF32::splat(1.0)) * size_scale

View File

@ -18,6 +18,30 @@ use std::io::Read;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
pub struct VertexArray {
pub gl_vertex_array: GLuint,
}
impl Drop for VertexArray {
#[inline]
fn drop(&mut self) {
unsafe {
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
}
}
}
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 VertexAttr {
attr: GLuint, attr: GLuint,
} }

View File

@ -10,9 +10,9 @@
use crate::debug::DebugUI; use crate::debug::DebugUI;
use crate::device::{Buffer, BufferTarget, BufferUploadMode, Framebuffer, Program, Texture}; use crate::device::{Buffer, BufferTarget, BufferUploadMode, Framebuffer, Program, Texture};
use crate::device::{TimerQuery, Uniform, VertexAttr}; use crate::device::{TimerQuery, Uniform, VertexArray, VertexAttr};
use euclid::Size2D; use euclid::Size2D;
use gl::types::{GLfloat, GLint, GLuint}; use gl::types::{GLfloat, GLint};
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive}; use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
use pathfinder_renderer::paint::{ColorU, ObjectShader}; use pathfinder_renderer::paint::{ColorU, ObjectShader};
use pathfinder_renderer::post::DefringingKernel; use pathfinder_renderer::post::DefringingKernel;
@ -39,7 +39,6 @@ pub struct Renderer {
solid_tile_program: SolidTileProgram, solid_tile_program: SolidTileProgram,
mask_tile_program: MaskTileProgram, mask_tile_program: MaskTileProgram,
area_lut_texture: Texture, area_lut_texture: Texture,
#[allow(dead_code)]
quad_vertex_positions_buffer: Buffer, quad_vertex_positions_buffer: Buffer,
fill_vertex_array: FillVertexArray, fill_vertex_array: FillVertexArray,
mask_tile_vertex_array: MaskTileVertexArray, mask_tile_vertex_array: MaskTileVertexArray,
@ -186,6 +185,11 @@ impl Renderer {
self.postprocess_options.gamma_correction_bg_color = Some(bg_color); self.postprocess_options.gamma_correction_bg_color = Some(bg_color);
} }
#[inline]
pub fn quad_vertex_positions_buffer(&self) -> &Buffer {
&self.quad_vertex_positions_buffer
}
fn upload_shaders(&mut self, shaders: &[ObjectShader]) { fn upload_shaders(&mut self, shaders: &[ObjectShader]) {
let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT); let size = Size2D::new(FILL_COLORS_TEXTURE_WIDTH, FILL_COLORS_TEXTURE_HEIGHT);
let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4]; let mut fill_colors = vec![0; size.width as usize * size.height as usize * 4];
@ -221,7 +225,7 @@ impl Renderer {
gl::ClearColor(0.0, 0.0, 0.0, 0.0); gl::ClearColor(0.0, 0.0, 0.0, 0.0);
gl::Clear(gl::COLOR_BUFFER_BIT); gl::Clear(gl::COLOR_BUFFER_BIT);
gl::BindVertexArray(self.fill_vertex_array.gl_vertex_array); gl::BindVertexArray(self.fill_vertex_array.vertex_array.gl_vertex_array);
gl::UseProgram(self.fill_program.program.gl_program); gl::UseProgram(self.fill_program.program.gl_program);
gl::Uniform2f(self.fill_program.framebuffer_size_uniform.location, gl::Uniform2f(self.fill_program.framebuffer_size_uniform.location,
MASK_FRAMEBUFFER_WIDTH as GLfloat, MASK_FRAMEBUFFER_WIDTH as GLfloat,
@ -244,7 +248,7 @@ impl Renderer {
self.bind_draw_framebuffer(); self.bind_draw_framebuffer();
self.set_main_viewport(); self.set_main_viewport();
gl::BindVertexArray(self.mask_tile_vertex_array.gl_vertex_array); gl::BindVertexArray(self.mask_tile_vertex_array.vertex_array.gl_vertex_array);
gl::UseProgram(self.mask_tile_program.program.gl_program); gl::UseProgram(self.mask_tile_program.program.gl_program);
gl::Uniform2f(self.mask_tile_program.framebuffer_size_uniform.location, gl::Uniform2f(self.mask_tile_program.framebuffer_size_uniform.location,
self.main_framebuffer_size.width as GLfloat, self.main_framebuffer_size.width as GLfloat,
@ -275,7 +279,7 @@ impl Renderer {
self.bind_draw_framebuffer(); self.bind_draw_framebuffer();
self.set_main_viewport(); self.set_main_viewport();
gl::BindVertexArray(self.solid_tile_vertex_array.gl_vertex_array); gl::BindVertexArray(self.solid_tile_vertex_array.vertex_array.gl_vertex_array);
gl::UseProgram(self.solid_tile_program.program.gl_program); gl::UseProgram(self.solid_tile_program.program.gl_program);
gl::Uniform2f(self.solid_tile_program.framebuffer_size_uniform.location, gl::Uniform2f(self.solid_tile_program.framebuffer_size_uniform.location,
self.main_framebuffer_size.width as GLfloat, self.main_framebuffer_size.width as GLfloat,
@ -300,7 +304,7 @@ impl Renderer {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
self.set_main_viewport(); self.set_main_viewport();
gl::BindVertexArray(self.postprocess_vertex_array.gl_vertex_array); gl::BindVertexArray(self.postprocess_vertex_array.vertex_array.gl_vertex_array);
gl::UseProgram(self.postprocess_program.program.gl_program); gl::UseProgram(self.postprocess_program.program.gl_program);
gl::Uniform2f(self.postprocess_program.framebuffer_size_uniform.location, gl::Uniform2f(self.postprocess_program.framebuffer_size_uniform.location,
self.main_framebuffer_size.width as GLfloat, self.main_framebuffer_size.width as GLfloat,
@ -406,14 +410,13 @@ struct PostprocessOptions {
} }
struct FillVertexArray { struct FillVertexArray {
gl_vertex_array: GLuint, vertex_array: VertexArray,
vertex_buffer: Buffer, vertex_buffer: Buffer,
} }
impl FillVertexArray { impl FillVertexArray {
fn new(fill_program: &FillProgram, quad_vertex_positions_buffer: &Buffer) -> FillVertexArray { fn new(fill_program: &FillProgram, quad_vertex_positions_buffer: &Buffer) -> FillVertexArray {
let vertex_buffer = Buffer::new(); let (vertex_array, vertex_buffer) = (VertexArray::new(), Buffer::new());
let mut gl_vertex_array = 0;
unsafe { unsafe {
let tess_coord_attr = VertexAttr::new(&fill_program.program, "TessCoord"); let tess_coord_attr = VertexAttr::new(&fill_program.program, "TessCoord");
let from_px_attr = VertexAttr::new(&fill_program.program, "FromPx"); let from_px_attr = VertexAttr::new(&fill_program.program, "FromPx");
@ -422,8 +425,7 @@ impl FillVertexArray {
let to_subpx_attr = VertexAttr::new(&fill_program.program, "ToSubpx"); let to_subpx_attr = VertexAttr::new(&fill_program.program, "ToSubpx");
let tile_index_attr = VertexAttr::new(&fill_program.program, "TileIndex"); let tile_index_attr = VertexAttr::new(&fill_program.program, "TileIndex");
gl::GenVertexArrays(1, &mut gl_vertex_array); gl::BindVertexArray(vertex_array.gl_vertex_array);
gl::BindVertexArray(gl_vertex_array);
gl::UseProgram(fill_program.program.gl_program); gl::UseProgram(fill_program.program.gl_program);
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0); tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
@ -435,29 +437,19 @@ impl FillVertexArray {
tile_index_attr.configure_int(1, gl::UNSIGNED_SHORT, FILL_INSTANCE_SIZE, 6, 1); tile_index_attr.configure_int(1, gl::UNSIGNED_SHORT, FILL_INSTANCE_SIZE, 6, 1);
} }
FillVertexArray { gl_vertex_array, vertex_buffer } FillVertexArray { vertex_array, vertex_buffer }
}
}
impl Drop for FillVertexArray {
#[inline]
fn drop(&mut self) {
unsafe {
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
}
} }
} }
struct MaskTileVertexArray { struct MaskTileVertexArray {
gl_vertex_array: GLuint, vertex_array: VertexArray,
vertex_buffer: Buffer, vertex_buffer: Buffer,
} }
impl MaskTileVertexArray { impl MaskTileVertexArray {
fn new(mask_tile_program: &MaskTileProgram, quad_vertex_positions_buffer: &Buffer) fn new(mask_tile_program: &MaskTileProgram, quad_vertex_positions_buffer: &Buffer)
-> MaskTileVertexArray { -> MaskTileVertexArray {
let vertex_buffer = Buffer::new(); let (vertex_array, vertex_buffer) = (VertexArray::new(), Buffer::new());
let mut gl_vertex_array = 0;
unsafe { unsafe {
let tess_coord_attr = VertexAttr::new(&mask_tile_program.program, "TessCoord"); let tess_coord_attr = VertexAttr::new(&mask_tile_program.program, "TessCoord");
let tile_origin_attr = VertexAttr::new(&mask_tile_program.program, "TileOrigin"); let tile_origin_attr = VertexAttr::new(&mask_tile_program.program, "TileOrigin");
@ -466,8 +458,7 @@ impl MaskTileVertexArray {
// NB: The object must be of type short, not unsigned short, to work around a macOS // NB: The object must be of type short, not unsigned short, to work around a macOS
// Radeon driver bug. // Radeon driver bug.
gl::GenVertexArrays(1, &mut gl_vertex_array); gl::BindVertexArray(vertex_array.gl_vertex_array);
gl::BindVertexArray(gl_vertex_array);
gl::UseProgram(mask_tile_program.program.gl_program); gl::UseProgram(mask_tile_program.program.gl_program);
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0); tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
@ -477,29 +468,19 @@ impl MaskTileVertexArray {
object_attr.configure_int(2, gl::SHORT, MASK_TILE_INSTANCE_SIZE, 6, 1); object_attr.configure_int(2, gl::SHORT, MASK_TILE_INSTANCE_SIZE, 6, 1);
} }
MaskTileVertexArray { gl_vertex_array, vertex_buffer } MaskTileVertexArray { vertex_array, vertex_buffer }
}
}
impl Drop for MaskTileVertexArray {
#[inline]
fn drop(&mut self) {
unsafe {
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
}
} }
} }
struct SolidTileVertexArray { struct SolidTileVertexArray {
gl_vertex_array: GLuint, vertex_array: VertexArray,
vertex_buffer: Buffer, vertex_buffer: Buffer,
} }
impl SolidTileVertexArray { impl SolidTileVertexArray {
fn new(solid_tile_program: &SolidTileProgram, quad_vertex_positions_buffer: &Buffer) fn new(solid_tile_program: &SolidTileProgram, quad_vertex_positions_buffer: &Buffer)
-> SolidTileVertexArray { -> SolidTileVertexArray {
let vertex_buffer = Buffer::new(); let (vertex_array, vertex_buffer) = (VertexArray::new(), Buffer::new());
let mut gl_vertex_array = 0;
unsafe { unsafe {
let tess_coord_attr = VertexAttr::new(&solid_tile_program.program, "TessCoord"); let tess_coord_attr = VertexAttr::new(&solid_tile_program.program, "TessCoord");
let tile_origin_attr = VertexAttr::new(&solid_tile_program.program, "TileOrigin"); let tile_origin_attr = VertexAttr::new(&solid_tile_program.program, "TileOrigin");
@ -507,8 +488,7 @@ impl SolidTileVertexArray {
// NB: The object must be of type short, not unsigned short, to work around a macOS // NB: The object must be of type short, not unsigned short, to work around a macOS
// Radeon driver bug. // Radeon driver bug.
gl::GenVertexArrays(1, &mut gl_vertex_array); gl::BindVertexArray(vertex_array.gl_vertex_array);
gl::BindVertexArray(gl_vertex_array);
gl::UseProgram(solid_tile_program.program.gl_program); gl::UseProgram(solid_tile_program.program.gl_program);
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0); tess_coord_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
@ -517,16 +497,7 @@ impl SolidTileVertexArray {
object_attr.configure_int(1, gl::SHORT, SOLID_TILE_INSTANCE_SIZE, 4, 1); object_attr.configure_int(1, gl::SHORT, SOLID_TILE_INSTANCE_SIZE, 4, 1);
} }
SolidTileVertexArray { gl_vertex_array, vertex_buffer } SolidTileVertexArray { vertex_array, vertex_buffer }
}
}
impl Drop for SolidTileVertexArray {
#[inline]
fn drop(&mut self) {
unsafe {
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
}
} }
} }
@ -638,32 +609,22 @@ impl PostprocessProgram {
} }
struct PostprocessVertexArray { struct PostprocessVertexArray {
gl_vertex_array: GLuint, vertex_array: VertexArray,
} }
impl PostprocessVertexArray { impl PostprocessVertexArray {
fn new(postprocess_program: &PostprocessProgram, quad_vertex_positions_buffer: &Buffer) fn new(postprocess_program: &PostprocessProgram, quad_vertex_positions_buffer: &Buffer)
-> PostprocessVertexArray { -> PostprocessVertexArray {
let mut gl_vertex_array = 0; let vertex_array = VertexArray::new();
unsafe { unsafe {
let position_attr = VertexAttr::new(&postprocess_program.program, "Position"); let position_attr = VertexAttr::new(&postprocess_program.program, "Position");
gl::GenVertexArrays(1, &mut gl_vertex_array); gl::BindVertexArray(vertex_array.gl_vertex_array);
gl::BindVertexArray(gl_vertex_array);
gl::UseProgram(postprocess_program.program.gl_program); gl::UseProgram(postprocess_program.program.gl_program);
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
position_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0); position_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0);
} }
PostprocessVertexArray { gl_vertex_array } PostprocessVertexArray { vertex_array }
}
}
impl Drop for PostprocessVertexArray {
#[inline]
fn drop(&mut self) {
unsafe {
gl::DeleteVertexArrays(1, &mut self.gl_vertex_array);
}
} }
} }

View File

@ -10,6 +10,7 @@
//! How a path is to be filled. //! How a path is to be filled.
use pathfinder_simd::default::F32x4;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@ -38,6 +39,12 @@ impl ColorU {
a: 255, a: 255,
} }
} }
#[inline]
pub fn to_f32(&self) -> ColorF {
let color = F32x4::new(self.r as f32, self.g as f32, self.b as f32, self.a as f32);
ColorF(color * F32x4::splat(1.0 / 255.0))
}
} }
impl Debug for ColorU { impl Debug for ColorU {
@ -55,6 +62,30 @@ impl Debug for ColorU {
} }
} }
#[derive(Clone, Copy)]
pub struct ColorF(pub F32x4);
impl ColorF {
#[inline]
pub fn r(&self) -> f32 {
self.0[0]
}
#[inline]
pub fn g(&self) -> f32 {
self.0[1]
}
#[inline]
pub fn b(&self) -> f32 {
self.0[2]
}
#[inline]
pub fn a(&self) -> f32 {
self.0[3]
}
}
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct ShaderId(pub u16); pub struct ShaderId(pub u16);