From e4803cfddfb3de984143e6f3eb9888892ee4546d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 14 Feb 2019 18:53:02 -0800 Subject: [PATCH] Add some ground to the 3D scene, no depth buffer yet --- demo/resources/textures/demo-rotate.png | Bin 0 -> 973 bytes demo/resources/textures/demo-zoom-in.png | Bin 0 -> 879 bytes demo/resources/textures/demo-zoom-out.png | Bin 0 -> 868 bytes demo/shaders/demo_ground.fs.glsl | 21 ++ demo/shaders/demo_ground.vs.glsl | 21 ++ demo/src/main.rs | 434 +++++++++++++++------- geometry/src/basic/point.rs | 11 +- geometry/src/basic/transform3d.rs | 16 +- gl/src/device.rs | 24 ++ gl/src/renderer.rs | 93 ++--- renderer/src/paint.rs | 31 ++ 11 files changed, 458 insertions(+), 193 deletions(-) create mode 100644 demo/resources/textures/demo-rotate.png create mode 100644 demo/resources/textures/demo-zoom-in.png create mode 100644 demo/resources/textures/demo-zoom-out.png create mode 100644 demo/shaders/demo_ground.fs.glsl create mode 100644 demo/shaders/demo_ground.vs.glsl diff --git a/demo/resources/textures/demo-rotate.png b/demo/resources/textures/demo-rotate.png new file mode 100644 index 0000000000000000000000000000000000000000..f3b5a173adc9995464f51ae7db26a3273bf99789 GIT binary patch literal 973 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F!lvNA9* zFct^7J29*~C-ahlfk7eJBgmJ5p-PQ`p`nF=;THn~L&FOOhEf9thF1v;3|2E37{m+a z>pu*R=0bNR%A2(175*`?1|Csx3FuL2;<)J&z-;&JrbIx9 zz|pn}S~-}ASMQ!5+x z)Gjf)Kb67pb1eIUv*n@=Gk&gP>@dnV2=U|+@Yw(1R2U-DT4lxCcHzI_^xaWMy-6uYSTV%(Z27?1TxD^Ce zyC=y-ycSOI5v|}`Q}V^|fTVasZ)|EYo9VODe}W!N_S$Fd_&-p*q4)OUtQyuVJBG5h zns=u-i|1r0E>lkt*|zi7)TkBvUAHdpHMF11Ad%d+Rp7I;OWvx}aSUvs)n=VPTV@qr ziMzwZc15IW()Q&`7*2~G5D%Xpwk$w>>EA!E%o@f{tb!*7iWO&x-EIa$Npu*n+l~>N6 zWBkBq(c12;^H^|+nv(OSJ5792$!05mZ+Cezuj7vRM9JhcPS^Oi2P|}I<@)>k7jLk` zygD7Z{u>Mo45}rr5hW>!C8<`)MX8A;sSHL2hL*YpM!JSZA%>P#Mut{K7TN{|Rt5$& zaji>HH00)|WTsW(*1*ebE6KpXpaHU>xGdc&DX}!lvNA9* zFct^7J29*~C-ahlfk7eJBgmJ5p-PQ`p`nF=;THn~L&FOOhEf9thF1v;3|2E37{m+a z>7}8R3q}bBlXGaz5DmMe43bNC|CVVroT3~TSY}hWecaSwZMzc6Sjhpq7${1Hob_s z@A@RbrOfq7@2a}I=q0NAnD(gJ+cA~jdZz2ZUcos>OrgFlI6?Tu7T14DAJ(xHcGo8C z>z#RCX+N(GOVt6^?_V3-&rMfVic`I_X`=+=Uzz0J>((E2)A?j>n_VYALt7yET<^x} zB+E92*%cuze_ZCQTQ0QQck=#snzi;9|ZeO8zW?g8MhB zO^uNhVX_zV#3m9i~VB+`%aiXFx+ssB3PdB_yO_j-&oGq%Srq*SJLW; zKP~WaPi~&4i_kcTIw1Y=^7e`7#LX@T3Q(yXd4(< z85js^DS=WRLPKtTN@iLmZVd_Lv(7UxFlc~mC@xF4N=htF)h#W`WJt@*Nww0~*DuK} j(9caw&rHtNjWkb<%JK~JD>CN_0Ht?NS3j3^P6!lvNA9* zFct^7J29*~C-ahlfk7eJBgmJ5p-PQ`p`nF=;THn~L&FOOhEf9thF1v;3|2E37{m+a z>Tq%UOvD*A)Mjz(Nv|2jTIeB7H$?24pOOPYu1?Hpy4&w zqeJOmP=)iHi}woazc+2MKY6s`eOlf9b8qji^9TqC2$*UVna?syX_KB(u3)8>60dcM zs?v3(OX3rilg~t6op9@i(1(dnesQe{dmG&#Rlva$Jmddj#R7&atBn3j{FriZ$2Cra z*rR9MXV&xQF#0~2_}8>?dYKN_p?LK-$%{=Ht_j`Qowok!t?#LIH$R@4&k(Fx_WCqBAL_N`p{sN0C~OMBX8h6Y|ydGQICb$4rOe{#N7 z^rSjYszG-ZzaH~~d5ZqB7NI+&{ zVPIfTEpd$~Nl7e8wMs5ZO)N=eFfuT-)HN{DH8c(}FtRc-wlXl*HZZU&O-#>B&eqi} a&+>~fG0uzsFMb`A$UR;CT-G@yGywpH8&xX+ literal 0 HcmV?d00001 diff --git a/demo/shaders/demo_ground.fs.glsl b/demo/shaders/demo_ground.fs.glsl new file mode 100644 index 00000000..04f056bb --- /dev/null +++ b/demo/shaders/demo_ground.fs.glsl @@ -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 or the MIT license +// , 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; +} diff --git a/demo/shaders/demo_ground.vs.glsl b/demo/shaders/demo_ground.vs.glsl new file mode 100644 index 00000000..d6a593ba --- /dev/null +++ b/demo/shaders/demo_ground.vs.glsl @@ -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 or the MIT license +// , 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); +} diff --git a/demo/src/main.rs b/demo/src/main.rs index 34d6c1f8..91b9c1b7 100644 --- a/demo/src/main.rs +++ b/demo/src/main.rs @@ -13,11 +13,14 @@ use crate::ui::{DemoUI, UIAction, UIEvent}; use clap::{App, Arg}; use euclid::Size2D; +use gl::types::GLsizei; use jemallocator; use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32}; use pathfinder_geometry::basic::rect::RectF32; use pathfinder_geometry::basic::transform2d::Transform2DF32; use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32}; +use pathfinder_gl::device::{Buffer, BufferTarget, BufferUploadMode, Program, Uniform}; +use pathfinder_gl::device::{VertexArray, VertexAttr}; use pathfinder_gl::renderer::Renderer; use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder}; 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. 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 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; @@ -90,6 +97,11 @@ struct DemoApp { ui: DemoUI, scene_thread_proxy: SceneThreadProxy, renderer: Renderer, + + device: DemoDevice, + ground_program: GroundProgram, + ground_solid_vertex_array: GroundSolidVertexArray, + ground_line_vertex_array: GroundLineVertexArray, } impl DemoApp { @@ -121,11 +133,18 @@ impl DemoApp { let drawable_size = Size2D::new(drawable_width, drawable_height); let base_scene = load_scene(&options.input_path); + let renderer = Renderer::new(&drawable_size); let scene_thread_proxy = SceneThreadProxy::new(base_scene, options.clone()); update_drawable_size(&window, &scene_thread_proxy); let camera = if options.threed { Camera::three_d() } else { Camera::two_d() }; + let grid_vertex_positions = create_grid_vertex_positions(); + let ground_program = GroundProgram::new(); + let ground_solid_vertex_array = + GroundSolidVertexArray::new(&ground_program, &renderer.quad_vertex_positions_buffer()); + let ground_line_vertex_array = GroundLineVertexArray::new(&ground_program); + DemoApp { window, sdl_context, @@ -144,7 +163,12 @@ impl DemoApp { ui: DemoUI::new(options), 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) { 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 { - Camera::ThreeD { ref mut position, velocity, yaw, pitch } => { - let rotation = Transform3DF32::from_rotation(-yaw, -pitch, 0.0); - - if !velocity.is_zero() { - *position = *position + rotation.transform_point(velocity); + Camera::ThreeD { ref mut transform, ref mut velocity } => { + if transform.offset(*velocity) { self.dirty = 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)) + RenderTransform::Perspective(transform.to_perspective(drawable_size, true)) } Camera::TwoD(transform) => RenderTransform::Transform2D(transform), }; @@ -242,10 +249,9 @@ impl DemoApp { ui_event = UIEvent::MouseDown(point); } Event::MouseMotion { xrel, yrel, .. } if self.mouselook_enabled => { - if let Camera::ThreeD { ref mut yaw, ref mut pitch, .. } = - self.camera { - *yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED; - *pitch -= yrel as f32 * MOUSELOOK_ROTATION_SPEED; + if let Camera::ThreeD { ref mut transform, .. } = self.camera { + transform.yaw += xrel as f32 * MOUSELOOK_ROTATION_SPEED; + transform.pitch += yrel as f32 * MOUSELOOK_ROTATION_SPEED; self.dirty = true; } } @@ -315,105 +321,155 @@ impl DemoApp { fn draw_scene(&mut self, render_msg: SceneToMainMsg, mut ui_event: UIEvent) { let SceneToMainMsg::Render { built_scene, tile_time } = render_msg; - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - gl::ClearColor(BACKGROUND_COLOR.r as f32 / 255.0, - 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); + self.device.clear(); + self.draw_environment(); + self.render_vector_scene(&built_scene); - if self.ui.gamma_correction_effect_enabled { - self.renderer.enable_gamma_correction(BACKGROUND_COLOR); - } else { - self.renderer.disable_gamma_correction(); + 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); + 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; } - - 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); - - 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); - } + UIEvent::MouseDragged { relative_position, .. } => { + if let Camera::TwoD(ref mut transform) = self.camera { + *transform = transform.post_translate(relative_position.to_f32()); } } - - // 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.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 { @@ -598,7 +654,7 @@ fn center_of_window(window: &Window) -> Point2DF32 { enum Camera { TwoD(Transform2DF32), - ThreeD { position: Point3DF32, velocity: Point3DF32, yaw: f32, pitch: f32 }, + ThreeD { transform: CameraTransform3D, velocity: Point3DF32 }, } impl Camera { @@ -607,15 +663,143 @@ impl Camera { } fn three_d() -> Camera { - Camera::ThreeD { - 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, - } + Camera::ThreeD { transform: CameraTransform3D::new(), velocity: Point3DF32::default() } } fn is_3d(&self) -> bool { 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 +} diff --git a/geometry/src/basic/point.rs b/geometry/src/basic/point.rs index 531ed1b6..f485244f 100644 --- a/geometry/src/basic/point.rs +++ b/geometry/src/basic/point.rs @@ -232,7 +232,7 @@ impl Sub for Point2DI32 { } /// 3D homogeneous points. -#[derive(Clone, Copy, Debug, PartialEq, Default)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Point3DF32(pub F32x4); impl Point3DF32 { @@ -350,3 +350,12 @@ impl Mul for Point3DF32 { 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) + } +} diff --git a/geometry/src/basic/transform3d.rs b/geometry/src/basic/transform3d.rs index 513f7602..a70ac149 100644 --- a/geometry/src/basic/transform3d.rs +++ b/geometry/src/basic/transform3d.rs @@ -22,6 +22,7 @@ use std::ops::{Add, Neg}; /// /// In column-major order. #[derive(Clone, Copy, Debug, PartialEq)] +#[repr(C)] pub struct Transform3DF32 { c0: F32x4, c1: F32x4, @@ -64,6 +65,11 @@ impl Transform3DF32 { 0.0, 0.0, 0.0, 1.0) } + #[inline] + pub fn from_uniform_scale(factor: f32) -> Transform3DF32 { + Transform3DF32::from_scale(factor, factor, factor) + } + #[inline] pub fn from_translation(x: f32, y: f32, z: f32) -> Transform3DF32 { Transform3DF32::row_major(1.0, 0.0, 0.0, x, @@ -229,6 +235,11 @@ impl Transform3DF32 { self.c2.approx_eq(other.c2, 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 for Matrix2x2F32 { @@ -261,7 +272,10 @@ impl Perspective { #[inline] 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 size_scale = Point2DF32::new(window_size.width * 0.5, window_size.height * 0.5); (point + Point2DF32::splat(1.0)) * size_scale diff --git a/gl/src/device.rs b/gl/src/device.rs index 03eacdfa..e22428d9 100644 --- a/gl/src/device.rs +++ b/gl/src/device.rs @@ -18,6 +18,30 @@ use std::io::Read; use std::mem; 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 { attr: GLuint, } diff --git a/gl/src/renderer.rs b/gl/src/renderer.rs index feb514d0..cd95a858 100644 --- a/gl/src/renderer.rs +++ b/gl/src/renderer.rs @@ -10,9 +10,9 @@ use crate::debug::DebugUI; 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 gl::types::{GLfloat, GLint, GLuint}; +use gl::types::{GLfloat, GLint}; use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive}; use pathfinder_renderer::paint::{ColorU, ObjectShader}; use pathfinder_renderer::post::DefringingKernel; @@ -39,7 +39,6 @@ pub struct Renderer { solid_tile_program: SolidTileProgram, mask_tile_program: MaskTileProgram, area_lut_texture: Texture, - #[allow(dead_code)] quad_vertex_positions_buffer: Buffer, fill_vertex_array: FillVertexArray, mask_tile_vertex_array: MaskTileVertexArray, @@ -186,6 +185,11 @@ impl Renderer { 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]) { 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]; @@ -221,7 +225,7 @@ impl Renderer { gl::ClearColor(0.0, 0.0, 0.0, 0.0); 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::Uniform2f(self.fill_program.framebuffer_size_uniform.location, MASK_FRAMEBUFFER_WIDTH as GLfloat, @@ -244,7 +248,7 @@ impl Renderer { self.bind_draw_framebuffer(); 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::Uniform2f(self.mask_tile_program.framebuffer_size_uniform.location, self.main_framebuffer_size.width as GLfloat, @@ -275,7 +279,7 @@ impl Renderer { self.bind_draw_framebuffer(); 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::Uniform2f(self.solid_tile_program.framebuffer_size_uniform.location, self.main_framebuffer_size.width as GLfloat, @@ -300,7 +304,7 @@ impl Renderer { gl::BindFramebuffer(gl::FRAMEBUFFER, 0); 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::Uniform2f(self.postprocess_program.framebuffer_size_uniform.location, self.main_framebuffer_size.width as GLfloat, @@ -406,14 +410,13 @@ struct PostprocessOptions { } struct FillVertexArray { - gl_vertex_array: GLuint, + vertex_array: VertexArray, vertex_buffer: Buffer, } impl FillVertexArray { fn new(fill_program: &FillProgram, quad_vertex_positions_buffer: &Buffer) -> FillVertexArray { - let vertex_buffer = Buffer::new(); - let mut gl_vertex_array = 0; + let (vertex_array, vertex_buffer) = (VertexArray::new(), Buffer::new()); unsafe { let tess_coord_attr = VertexAttr::new(&fill_program.program, "TessCoord"); 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 tile_index_attr = VertexAttr::new(&fill_program.program, "TileIndex"); - gl::GenVertexArrays(1, &mut gl_vertex_array); - gl::BindVertexArray(gl_vertex_array); + gl::BindVertexArray(vertex_array.gl_vertex_array); gl::UseProgram(fill_program.program.gl_program); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer); 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); } - FillVertexArray { gl_vertex_array, vertex_buffer } - } -} - -impl Drop for FillVertexArray { - #[inline] - fn drop(&mut self) { - unsafe { - gl::DeleteVertexArrays(1, &mut self.gl_vertex_array); - } + FillVertexArray { vertex_array, vertex_buffer } } } struct MaskTileVertexArray { - gl_vertex_array: GLuint, + vertex_array: VertexArray, vertex_buffer: Buffer, } impl MaskTileVertexArray { fn new(mask_tile_program: &MaskTileProgram, quad_vertex_positions_buffer: &Buffer) -> MaskTileVertexArray { - let vertex_buffer = Buffer::new(); - let mut gl_vertex_array = 0; + let (vertex_array, vertex_buffer) = (VertexArray::new(), Buffer::new()); unsafe { let tess_coord_attr = VertexAttr::new(&mask_tile_program.program, "TessCoord"); 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 // Radeon driver bug. - gl::GenVertexArrays(1, &mut gl_vertex_array); - gl::BindVertexArray(gl_vertex_array); + gl::BindVertexArray(vertex_array.gl_vertex_array); gl::UseProgram(mask_tile_program.program.gl_program); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer); 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); } - MaskTileVertexArray { gl_vertex_array, vertex_buffer } - } -} - -impl Drop for MaskTileVertexArray { - #[inline] - fn drop(&mut self) { - unsafe { - gl::DeleteVertexArrays(1, &mut self.gl_vertex_array); - } + MaskTileVertexArray { vertex_array, vertex_buffer } } } struct SolidTileVertexArray { - gl_vertex_array: GLuint, + vertex_array: VertexArray, vertex_buffer: Buffer, } impl SolidTileVertexArray { fn new(solid_tile_program: &SolidTileProgram, quad_vertex_positions_buffer: &Buffer) -> SolidTileVertexArray { - let vertex_buffer = Buffer::new(); - let mut gl_vertex_array = 0; + let (vertex_array, vertex_buffer) = (VertexArray::new(), Buffer::new()); unsafe { let tess_coord_attr = VertexAttr::new(&solid_tile_program.program, "TessCoord"); 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 // Radeon driver bug. - gl::GenVertexArrays(1, &mut gl_vertex_array); - gl::BindVertexArray(gl_vertex_array); + gl::BindVertexArray(vertex_array.gl_vertex_array); gl::UseProgram(solid_tile_program.program.gl_program); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer); 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); } - SolidTileVertexArray { gl_vertex_array, vertex_buffer } - } -} - -impl Drop for SolidTileVertexArray { - #[inline] - fn drop(&mut self) { - unsafe { - gl::DeleteVertexArrays(1, &mut self.gl_vertex_array); - } + SolidTileVertexArray { vertex_array, vertex_buffer } } } @@ -638,32 +609,22 @@ impl PostprocessProgram { } struct PostprocessVertexArray { - gl_vertex_array: GLuint, + vertex_array: VertexArray, } impl PostprocessVertexArray { fn new(postprocess_program: &PostprocessProgram, quad_vertex_positions_buffer: &Buffer) -> PostprocessVertexArray { - let mut gl_vertex_array = 0; + let vertex_array = VertexArray::new(); unsafe { let position_attr = VertexAttr::new(&postprocess_program.program, "Position"); - gl::GenVertexArrays(1, &mut gl_vertex_array); - gl::BindVertexArray(gl_vertex_array); + gl::BindVertexArray(vertex_array.gl_vertex_array); gl::UseProgram(postprocess_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); } - PostprocessVertexArray { gl_vertex_array } - } -} - -impl Drop for PostprocessVertexArray { - #[inline] - fn drop(&mut self) { - unsafe { - gl::DeleteVertexArrays(1, &mut self.gl_vertex_array); - } + PostprocessVertexArray { vertex_array } } } diff --git a/renderer/src/paint.rs b/renderer/src/paint.rs index 0c30a167..6c8b72cd 100644 --- a/renderer/src/paint.rs +++ b/renderer/src/paint.rs @@ -10,6 +10,7 @@ //! How a path is to be filled. +use pathfinder_simd::default::F32x4; use std::fmt::{self, Debug, Formatter}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -38,6 +39,12 @@ impl ColorU { 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 { @@ -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)] pub struct ShaderId(pub u16);