Move the generic UI code in the renderer crate to a separate crate
This commit is contained in:
parent
e09b447d0d
commit
ad0691c146
|
@ -271,6 +271,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -514,6 +515,7 @@ dependencies = [
|
||||||
"pathfinder_gpu 0.1.0",
|
"pathfinder_gpu 0.1.0",
|
||||||
"pathfinder_renderer 0.1.0",
|
"pathfinder_renderer 0.1.0",
|
||||||
"pathfinder_svg 0.1.0",
|
"pathfinder_svg 0.1.0",
|
||||||
|
"pathfinder_ui 0.1.0",
|
||||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sdl2 0.32.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -562,6 +564,7 @@ dependencies = [
|
||||||
"pathfinder_geometry 0.3.0",
|
"pathfinder_geometry 0.3.0",
|
||||||
"pathfinder_gpu 0.1.0",
|
"pathfinder_gpu 0.1.0",
|
||||||
"pathfinder_simd 0.3.0",
|
"pathfinder_simd 0.3.0",
|
||||||
|
"pathfinder_ui 0.1.0",
|
||||||
"quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -586,6 +589,15 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathfinder_ui"
|
name = "pathfinder_ui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pathfinder_geometry 0.3.0",
|
||||||
|
"pathfinder_gpu 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]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
|
|
|
@ -32,3 +32,6 @@ path = "../../renderer"
|
||||||
|
|
||||||
[dependencies.pathfinder_svg]
|
[dependencies.pathfinder_svg]
|
||||||
path = "../../svg"
|
path = "../../svg"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_ui]
|
||||||
|
path = "../../ui"
|
||||||
|
|
|
@ -19,13 +19,13 @@ 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_geometry::color::ColorU;
|
||||||
use pathfinder_gl::GLDevice;
|
use pathfinder_gl::GLDevice;
|
||||||
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, Resources};
|
use pathfinder_gpu::{DepthFunc, DepthState, Device, Primitive, RenderState, Resources};
|
||||||
use pathfinder_gpu::{StencilFunc, StencilState, UniformData};
|
use pathfinder_gpu::{StencilFunc, StencilState, UniformData};
|
||||||
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
|
use pathfinder_renderer::builder::{RenderOptions, RenderTransform, SceneBuilder};
|
||||||
use pathfinder_renderer::gpu::renderer::Renderer;
|
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||||
use pathfinder_renderer::gpu_data::BuiltScene;
|
use pathfinder_renderer::gpu_data::BuiltScene;
|
||||||
use pathfinder_renderer::paint::ColorU;
|
|
||||||
use pathfinder_renderer::post::{DEFRINGING_KERNEL_CORE_GRAPHICS, STEM_DARKENING_FACTORS};
|
use pathfinder_renderer::post::{DEFRINGING_KERNEL_CORE_GRAPHICS, STEM_DARKENING_FACTORS};
|
||||||
use pathfinder_renderer::scene::Scene;
|
use pathfinder_renderer::scene::Scene;
|
||||||
use pathfinder_renderer::z_buffer::ZBuffer;
|
use pathfinder_renderer::z_buffer::ZBuffer;
|
||||||
|
|
|
@ -12,9 +12,10 @@ use crate::Options;
|
||||||
use nfd::Response;
|
use nfd::Response;
|
||||||
use pathfinder_geometry::basic::point::Point2DI32;
|
use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
use pathfinder_geometry::basic::rect::RectI32;
|
use pathfinder_geometry::basic::rect::RectI32;
|
||||||
|
use pathfinder_geometry::color::ColorU;
|
||||||
use pathfinder_gpu::{Device, Resources};
|
use pathfinder_gpu::{Device, Resources};
|
||||||
use pathfinder_renderer::gpu::debug::{DebugUI, PADDING, TEXT_COLOR, WINDOW_COLOR};
|
use pathfinder_renderer::gpu::debug::DebugUI;
|
||||||
use pathfinder_renderer::paint::ColorU;
|
use pathfinder_ui::{PADDING, TEXT_COLOR, WINDOW_COLOR};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -120,7 +121,7 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
debug_ui: &mut DebugUI<D>,
|
debug_ui: &mut DebugUI<D>,
|
||||||
event: &mut UIEvent,
|
event: &mut UIEvent,
|
||||||
action: &mut UIAction) {
|
action: &mut UIAction) {
|
||||||
let bottom = debug_ui.framebuffer_size().y() - PADDING;
|
let bottom = debug_ui.ui.framebuffer_size().y() - PADDING;
|
||||||
|
|
||||||
// Draw effects button.
|
// Draw effects button.
|
||||||
let effects_button_position = Point2DI32::new(PADDING, bottom - BUTTON_HEIGHT);
|
let effects_button_position = Point2DI32::new(PADDING, bottom - BUTTON_HEIGHT);
|
||||||
|
@ -218,9 +219,9 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bottom = debug_ui.framebuffer_size().y() - PADDING;
|
let bottom = debug_ui.ui.framebuffer_size().y() - PADDING;
|
||||||
let effects_panel_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_PANEL_HEIGHT);
|
let effects_panel_y = bottom - (BUTTON_HEIGHT + PADDING + EFFECTS_PANEL_HEIGHT);
|
||||||
debug_ui.draw_solid_rounded_rect(device,
|
debug_ui.ui.draw_solid_rounded_rect(device,
|
||||||
RectI32::new(Point2DI32::new(PADDING, effects_panel_y),
|
RectI32::new(Point2DI32::new(PADDING, effects_panel_y),
|
||||||
Point2DI32::new(EFFECTS_PANEL_WIDTH,
|
Point2DI32::new(EFFECTS_PANEL_WIDTH,
|
||||||
EFFECTS_PANEL_HEIGHT)),
|
EFFECTS_PANEL_HEIGHT)),
|
||||||
|
@ -262,11 +263,11 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bottom = debug_ui.framebuffer_size().y() - PADDING;
|
let bottom = debug_ui.ui.framebuffer_size().y() - PADDING;
|
||||||
let rotate_panel_y = bottom - (BUTTON_HEIGHT + PADDING + ROTATE_PANEL_HEIGHT);
|
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_origin = Point2DI32::new(ROTATE_PANEL_X, rotate_panel_y);
|
||||||
let rotate_panel_size = Point2DI32::new(ROTATE_PANEL_WIDTH, ROTATE_PANEL_HEIGHT);
|
let rotate_panel_size = Point2DI32::new(ROTATE_PANEL_WIDTH, ROTATE_PANEL_HEIGHT);
|
||||||
debug_ui.draw_solid_rounded_rect(device,
|
debug_ui.ui.draw_solid_rounded_rect(device,
|
||||||
RectI32::new(rotate_panel_origin, rotate_panel_size),
|
RectI32::new(rotate_panel_origin, rotate_panel_size),
|
||||||
WINDOW_COLOR);
|
WINDOW_COLOR);
|
||||||
|
|
||||||
|
@ -283,13 +284,13 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
let slider_track_rect =
|
let slider_track_rect =
|
||||||
RectI32::new(Point2DI32::new(widget_x, slider_track_y),
|
RectI32::new(Point2DI32::new(widget_x, slider_track_y),
|
||||||
Point2DI32::new(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT));
|
Point2DI32::new(SLIDER_WIDTH, SLIDER_TRACK_HEIGHT));
|
||||||
debug_ui.draw_rect_outline(device, slider_track_rect, TEXT_COLOR);
|
debug_ui.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_x = widget_x + self.rotation - SLIDER_KNOB_WIDTH / 2;
|
||||||
let slider_knob_rect =
|
let slider_knob_rect =
|
||||||
RectI32::new(Point2DI32::new(slider_knob_x, widget_y),
|
RectI32::new(Point2DI32::new(slider_knob_x, widget_y),
|
||||||
Point2DI32::new(SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT));
|
Point2DI32::new(SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT));
|
||||||
debug_ui.draw_solid_rect(device, slider_knob_rect, TEXT_COLOR);
|
debug_ui.ui.draw_solid_rect(device, slider_knob_rect, TEXT_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_button(&self,
|
fn draw_button(&self,
|
||||||
|
@ -300,9 +301,9 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
texture: &D::Texture)
|
texture: &D::Texture)
|
||||||
-> bool {
|
-> bool {
|
||||||
let button_rect = RectI32::new(origin, Point2DI32::new(BUTTON_WIDTH, BUTTON_HEIGHT));
|
let button_rect = RectI32::new(origin, Point2DI32::new(BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||||
debug_ui.draw_solid_rounded_rect(device, button_rect, WINDOW_COLOR);
|
debug_ui.ui.draw_solid_rounded_rect(device, button_rect, WINDOW_COLOR);
|
||||||
debug_ui.draw_rounded_rect_outline(device, button_rect, OUTLINE_COLOR);
|
debug_ui.ui.draw_rounded_rect_outline(device, button_rect, OUTLINE_COLOR);
|
||||||
debug_ui.draw_texture(device,
|
debug_ui.ui.draw_texture(device,
|
||||||
origin + Point2DI32::new(PADDING, PADDING),
|
origin + Point2DI32::new(PADDING, PADDING),
|
||||||
texture,
|
texture,
|
||||||
BUTTON_ICON_COLOR);
|
BUTTON_ICON_COLOR);
|
||||||
|
@ -320,7 +321,7 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
-> bool {
|
-> bool {
|
||||||
let text_x = PADDING * 2;
|
let text_x = PADDING * 2;
|
||||||
let text_y = window_y + PADDING + BUTTON_TEXT_OFFSET + (BUTTON_HEIGHT + PADDING) * index;
|
let text_y = window_y + PADDING + BUTTON_TEXT_OFFSET + (BUTTON_HEIGHT + PADDING) * index;
|
||||||
debug_ui.draw_text(device, text, Point2DI32::new(text_x, text_y), false);
|
debug_ui.ui.draw_text(device, text, Point2DI32::new(text_x, text_y), false);
|
||||||
|
|
||||||
let switch_x = PADDING + EFFECTS_PANEL_WIDTH - (SWITCH_SIZE + PADDING);
|
let switch_x = PADDING + EFFECTS_PANEL_WIDTH - (SWITCH_SIZE + PADDING);
|
||||||
let switch_y = window_y + PADDING + (BUTTON_HEIGHT + PADDING) * index;
|
let switch_y = window_y + PADDING + (BUTTON_HEIGHT + PADDING) * index;
|
||||||
|
@ -344,17 +345,20 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
-> bool {
|
-> bool {
|
||||||
value = self.draw_switch(device, 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 off_size = debug_ui.ui.measure_text(off_text);
|
||||||
let on_size = debug_ui.measure_text(on_text);
|
let on_size = debug_ui.ui.measure_text(on_text);
|
||||||
let off_offset = SWITCH_HALF_SIZE / 2 - off_size / 2;
|
let off_offset = SWITCH_HALF_SIZE / 2 - off_size / 2;
|
||||||
let on_offset = SWITCH_HALF_SIZE + SWITCH_HALF_SIZE / 2 - on_size / 2;
|
let on_offset = SWITCH_HALF_SIZE + SWITCH_HALF_SIZE / 2 - on_size / 2;
|
||||||
let text_top = BUTTON_TEXT_OFFSET;
|
let text_top = BUTTON_TEXT_OFFSET;
|
||||||
|
|
||||||
debug_ui.draw_text(device,
|
debug_ui.ui.draw_text(device,
|
||||||
off_text,
|
off_text,
|
||||||
origin + Point2DI32::new(off_offset, text_top),
|
origin + Point2DI32::new(off_offset, text_top),
|
||||||
!value);
|
!value);
|
||||||
debug_ui.draw_text(device, on_text, origin + Point2DI32::new(on_offset, text_top), value);
|
debug_ui.ui.draw_text(device,
|
||||||
|
on_text,
|
||||||
|
origin + Point2DI32::new(on_offset, text_top),
|
||||||
|
value);
|
||||||
|
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
@ -377,11 +381,11 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
let off_color = if !value { WINDOW_COLOR } else { TEXT_COLOR };
|
let off_color = if !value { WINDOW_COLOR } else { TEXT_COLOR };
|
||||||
let on_color = if value { WINDOW_COLOR } else { TEXT_COLOR };
|
let on_color = if value { WINDOW_COLOR } else { TEXT_COLOR };
|
||||||
|
|
||||||
debug_ui.draw_texture(device,
|
debug_ui.ui.draw_texture(device,
|
||||||
origin + Point2DI32::new(off_offset, PADDING),
|
origin + Point2DI32::new(off_offset, PADDING),
|
||||||
off_texture,
|
off_texture,
|
||||||
off_color);
|
off_color);
|
||||||
debug_ui.draw_texture(device,
|
debug_ui.ui.draw_texture(device,
|
||||||
origin + Point2DI32::new(on_offset, PADDING),
|
origin + Point2DI32::new(on_offset, PADDING),
|
||||||
on_texture,
|
on_texture,
|
||||||
on_color);
|
on_color);
|
||||||
|
@ -401,17 +405,17 @@ impl<D> DemoUI<D> where D: Device {
|
||||||
value = !value;
|
value = !value;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_ui.draw_solid_rounded_rect(device, widget_rect, WINDOW_COLOR);
|
debug_ui.ui.draw_solid_rounded_rect(device, widget_rect, WINDOW_COLOR);
|
||||||
debug_ui.draw_rounded_rect_outline(device, widget_rect, OUTLINE_COLOR);
|
debug_ui.ui.draw_rounded_rect_outline(device, widget_rect, OUTLINE_COLOR);
|
||||||
|
|
||||||
let highlight_size = Point2DI32::new(SWITCH_HALF_SIZE, BUTTON_HEIGHT);
|
let highlight_size = Point2DI32::new(SWITCH_HALF_SIZE, BUTTON_HEIGHT);
|
||||||
if !value {
|
if !value {
|
||||||
debug_ui.draw_solid_rounded_rect(device,
|
debug_ui.ui.draw_solid_rounded_rect(device,
|
||||||
RectI32::new(origin, highlight_size),
|
RectI32::new(origin, highlight_size),
|
||||||
TEXT_COLOR);
|
TEXT_COLOR);
|
||||||
} else {
|
} else {
|
||||||
let x_offset = SWITCH_HALF_SIZE + 1;
|
let x_offset = SWITCH_HALF_SIZE + 1;
|
||||||
debug_ui.draw_solid_rounded_rect(device,
|
debug_ui.ui.draw_solid_rounded_rect(device,
|
||||||
RectI32::new(origin + Point2DI32::new(x_offset, 0),
|
RectI32::new(origin + Point2DI32::new(x_offset, 0),
|
||||||
highlight_size),
|
highlight_size),
|
||||||
TEXT_COLOR);
|
TEXT_COLOR);
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
// pathfinder/geometry/src/color.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.
|
||||||
|
|
||||||
|
use pathfinder_simd::default::F32x4;
|
||||||
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||||||
|
pub struct ColorU {
|
||||||
|
pub r: u8,
|
||||||
|
pub g: u8,
|
||||||
|
pub b: u8,
|
||||||
|
pub a: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorU {
|
||||||
|
#[inline]
|
||||||
|
pub fn black() -> ColorU {
|
||||||
|
ColorU {
|
||||||
|
r: 0,
|
||||||
|
g: 0,
|
||||||
|
b: 0,
|
||||||
|
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 {
|
||||||
|
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
|
if self.a == 255 {
|
||||||
|
write!(formatter, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)
|
||||||
|
} else {
|
||||||
|
write!(formatter,
|
||||||
|
"rgba({}, {}, {}, {})",
|
||||||
|
self.r,
|
||||||
|
self.g,
|
||||||
|
self.b,
|
||||||
|
self.a as f32 / 255.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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]
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ extern crate bitflags;
|
||||||
|
|
||||||
pub mod basic;
|
pub mod basic;
|
||||||
pub mod clip;
|
pub mod clip;
|
||||||
|
pub mod color;
|
||||||
pub mod monotonic;
|
pub mod monotonic;
|
||||||
pub mod orientation;
|
pub mod orientation;
|
||||||
pub mod outline;
|
pub mod outline;
|
||||||
|
|
|
@ -23,5 +23,8 @@ path = "../gpu"
|
||||||
[dependencies.pathfinder_simd]
|
[dependencies.pathfinder_simd]
|
||||||
path = "../simd"
|
path = "../simd"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_ui]
|
||||||
|
path = "../ui"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = "0.7"
|
quickcheck = "0.7"
|
||||||
|
|
|
@ -16,92 +16,23 @@
|
||||||
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
||||||
|
|
||||||
use crate::gpu_data::Stats;
|
use crate::gpu_data::Stats;
|
||||||
use crate::paint::ColorU;
|
|
||||||
use pathfinder_geometry::basic::point::Point2DI32;
|
use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
use pathfinder_geometry::basic::rect::RectI32;
|
use pathfinder_geometry::basic::rect::RectI32;
|
||||||
use pathfinder_gpu::{BlendState, BufferTarget, BufferUploadMode, Device, Primitive, RenderState};
|
use pathfinder_gpu::{Device, Resources};
|
||||||
use pathfinder_gpu::{Resources, UniformData, VertexAttrType};
|
use pathfinder_ui::{PADDING, UI, WINDOW_COLOR};
|
||||||
use pathfinder_simd::default::F32x4;
|
use std::collections::VecDeque;
|
||||||
use serde_json;
|
|
||||||
use std::collections::{HashMap, VecDeque};
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::BufReader;
|
|
||||||
use std::ops::{Add, Div};
|
use std::ops::{Add, Div};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
const SAMPLE_BUFFER_SIZE: usize = 60;
|
const SAMPLE_BUFFER_SIZE: usize = 60;
|
||||||
|
|
||||||
const DEBUG_TEXTURE_VERTEX_SIZE: usize = 8;
|
|
||||||
const DEBUG_SOLID_VERTEX_SIZE: usize = 4;
|
|
||||||
|
|
||||||
pub const PADDING: i32 = 12;
|
|
||||||
|
|
||||||
pub static TEXT_COLOR: ColorU = ColorU { r: 255, g: 255, b: 255, a: 255 };
|
|
||||||
pub static WINDOW_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 - 90 };
|
|
||||||
|
|
||||||
static INVERTED_TEXT_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 };
|
|
||||||
|
|
||||||
const PERF_WINDOW_WIDTH: i32 = 375;
|
const PERF_WINDOW_WIDTH: i32 = 375;
|
||||||
const PERF_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 6 + PADDING + 2;
|
const PERF_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 6 + PADDING + 2;
|
||||||
const FONT_ASCENT: i32 = 28;
|
const FONT_ASCENT: i32 = 28;
|
||||||
const LINE_HEIGHT: i32 = 42;
|
const LINE_HEIGHT: i32 = 42;
|
||||||
|
|
||||||
static FONT_JSON_FILENAME: &'static str = "debug-font.json";
|
|
||||||
static FONT_PNG_NAME: &'static str = "debug-font";
|
|
||||||
|
|
||||||
static CORNER_FILL_PNG_NAME: &'static str = "debug-corner-fill";
|
|
||||||
static CORNER_OUTLINE_PNG_NAME: &'static str = "debug-corner-outline";
|
|
||||||
|
|
||||||
static QUAD_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3];
|
|
||||||
static RECT_LINE_INDICES: [u32; 8] = [0, 1, 1, 2, 2, 3, 3, 0];
|
|
||||||
static OUTLINE_RECT_LINE_INDICES: [u32; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct DebugFont {
|
|
||||||
name: String,
|
|
||||||
size: i32,
|
|
||||||
bold: bool,
|
|
||||||
italic: bool,
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
characters: HashMap<char, DebugCharacter>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct DebugCharacter {
|
|
||||||
x: i32,
|
|
||||||
y: i32,
|
|
||||||
width: i32,
|
|
||||||
height: i32,
|
|
||||||
#[serde(rename = "originX")]
|
|
||||||
origin_x: i32,
|
|
||||||
#[serde(rename = "originY")]
|
|
||||||
origin_y: i32,
|
|
||||||
advance: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DebugFont {
|
|
||||||
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<D> where D: Device {
|
pub struct DebugUI<D> where D: Device {
|
||||||
framebuffer_size: Point2DI32,
|
pub ui: UI<D>,
|
||||||
|
|
||||||
texture_program: DebugTextureProgram<D>,
|
|
||||||
texture_vertex_array: DebugTextureVertexArray<D>,
|
|
||||||
font: DebugFont,
|
|
||||||
solid_program: DebugSolidProgram<D>,
|
|
||||||
solid_vertex_array: DebugSolidVertexArray<D>,
|
|
||||||
|
|
||||||
font_texture: D::Texture,
|
|
||||||
corner_fill_texture: D::Texture,
|
|
||||||
corner_outline_texture: D::Texture,
|
|
||||||
|
|
||||||
cpu_samples: SampleBuffer<CPUSample>,
|
cpu_samples: SampleBuffer<CPUSample>,
|
||||||
gpu_samples: SampleBuffer<GPUSample>,
|
gpu_samples: SampleBuffer<GPUSample>,
|
||||||
|
@ -109,42 +40,8 @@ pub struct DebugUI<D> where D: Device {
|
||||||
|
|
||||||
impl<D> DebugUI<D> where D: Device {
|
impl<D> DebugUI<D> where D: Device {
|
||||||
pub fn new(device: &D, resources: &Resources, framebuffer_size: Point2DI32) -> DebugUI<D> {
|
pub fn new(device: &D, resources: &Resources, framebuffer_size: Point2DI32) -> DebugUI<D> {
|
||||||
let texture_program = DebugTextureProgram::new(device, resources);
|
let ui = UI::new(device, resources, framebuffer_size);
|
||||||
let texture_vertex_array = DebugTextureVertexArray::new(device, &texture_program);
|
DebugUI { ui, cpu_samples: SampleBuffer::new(), gpu_samples: SampleBuffer::new() }
|
||||||
let font = DebugFont::load(resources);
|
|
||||||
|
|
||||||
let solid_program = DebugSolidProgram::new(device, resources);
|
|
||||||
let solid_vertex_array = DebugSolidVertexArray::new(device, &solid_program);
|
|
||||||
|
|
||||||
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,
|
|
||||||
|
|
||||||
texture_program,
|
|
||||||
texture_vertex_array,
|
|
||||||
font,
|
|
||||||
solid_program,
|
|
||||||
solid_vertex_array,
|
|
||||||
|
|
||||||
font_texture,
|
|
||||||
corner_fill_texture,
|
|
||||||
corner_outline_texture,
|
|
||||||
|
|
||||||
cpu_samples: SampleBuffer::new(),
|
|
||||||
gpu_samples: SampleBuffer::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn framebuffer_size(&self) -> Point2DI32 {
|
|
||||||
self.framebuffer_size
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_framebuffer_size(&mut self, window_size: Point2DI32) {
|
|
||||||
self.framebuffer_size = window_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_sample(&mut self,
|
pub fn add_sample(&mut self,
|
||||||
|
@ -159,461 +56,44 @@ impl<D> DebugUI<D> where D: Device {
|
||||||
|
|
||||||
pub fn draw(&self, device: &D) {
|
pub fn draw(&self, device: &D) {
|
||||||
// Draw performance window.
|
// Draw performance window.
|
||||||
let bottom = self.framebuffer_size.y() - PADDING;
|
let framebuffer_size = self.ui.framebuffer_size();
|
||||||
|
let bottom = framebuffer_size.y() - PADDING;
|
||||||
let window_rect = RectI32::new(
|
let window_rect = RectI32::new(
|
||||||
Point2DI32::new(self.framebuffer_size.x() - PADDING - PERF_WINDOW_WIDTH,
|
Point2DI32::new(framebuffer_size.x() - PADDING - PERF_WINDOW_WIDTH,
|
||||||
bottom - PERF_WINDOW_HEIGHT),
|
bottom - PERF_WINDOW_HEIGHT),
|
||||||
Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT));
|
Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT));
|
||||||
self.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR);
|
self.ui.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR);
|
||||||
let origin = window_rect.origin() + Point2DI32::new(PADDING, PADDING + FONT_ASCENT);
|
let origin = window_rect.origin() + Point2DI32::new(PADDING, PADDING + FONT_ASCENT);
|
||||||
|
|
||||||
let mean_cpu_sample = self.cpu_samples.mean();
|
let mean_cpu_sample = self.cpu_samples.mean();
|
||||||
self.draw_text(device,
|
self.ui.draw_text(device,
|
||||||
&format!("Objects: {}", mean_cpu_sample.stats.object_count),
|
&format!("Objects: {}", mean_cpu_sample.stats.object_count),
|
||||||
origin,
|
origin,
|
||||||
false);
|
false);
|
||||||
self.draw_text(device,
|
self.ui.draw_text(device,
|
||||||
&format!("Solid Tiles: {}", mean_cpu_sample.stats.solid_tile_count),
|
&format!("Solid Tiles: {}", mean_cpu_sample.stats.solid_tile_count),
|
||||||
origin + Point2DI32::new(0, LINE_HEIGHT * 1),
|
origin + Point2DI32::new(0, LINE_HEIGHT * 1),
|
||||||
false);
|
false);
|
||||||
self.draw_text(device,
|
self.ui.draw_text(device,
|
||||||
&format!("Mask Tiles: {}", mean_cpu_sample.stats.mask_tile_count),
|
&format!("Mask Tiles: {}", mean_cpu_sample.stats.mask_tile_count),
|
||||||
origin + Point2DI32::new(0, LINE_HEIGHT * 2),
|
origin + Point2DI32::new(0, LINE_HEIGHT * 2),
|
||||||
false);
|
false);
|
||||||
self.draw_text(device,
|
self.ui.draw_text(device,
|
||||||
&format!("Fills: {}", mean_cpu_sample.stats.fill_count),
|
&format!("Fills: {}", mean_cpu_sample.stats.fill_count),
|
||||||
origin + Point2DI32::new(0, LINE_HEIGHT * 3),
|
origin + Point2DI32::new(0, LINE_HEIGHT * 3),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
self.draw_text(device,
|
self.ui.draw_text(device,
|
||||||
&format!("CPU Time: {:.3} ms", duration_to_ms(mean_cpu_sample.elapsed)),
|
&format!("CPU Time: {:.3} ms", duration_to_ms(mean_cpu_sample.elapsed)),
|
||||||
origin + Point2DI32::new(0, LINE_HEIGHT * 4),
|
origin + Point2DI32::new(0, LINE_HEIGHT * 4),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
let mean_gpu_sample = self.gpu_samples.mean();
|
let mean_gpu_sample = self.gpu_samples.mean();
|
||||||
self.draw_text(device,
|
self.ui.draw_text(device,
|
||||||
&format!("GPU Time: {:.3} ms", duration_to_ms(mean_gpu_sample.elapsed)),
|
&format!("GPU Time: {:.3} ms", duration_to_ms(mean_gpu_sample.elapsed)),
|
||||||
origin + Point2DI32::new(0, LINE_HEIGHT * 5),
|
origin + Point2DI32::new(0, LINE_HEIGHT * 5),
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
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, device: &D, rect: RectI32, color: ColorU) {
|
|
||||||
self.draw_rect(device, rect, color, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_rect(&self, device: &D, rect: RectI32, color: ColorU, filled: bool) {
|
|
||||||
let vertex_data = [
|
|
||||||
DebugSolidVertex::new(rect.origin()),
|
|
||||||
DebugSolidVertex::new(rect.upper_right()),
|
|
||||||
DebugSolidVertex::new(rect.lower_right()),
|
|
||||||
DebugSolidVertex::new(rect.lower_left()),
|
|
||||||
];
|
|
||||||
|
|
||||||
if filled {
|
|
||||||
self.draw_solid_rects_with_vertex_data(device,
|
|
||||||
&vertex_data,
|
|
||||||
&QUAD_INDICES,
|
|
||||||
color,
|
|
||||||
true);
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
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()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
let mut index_data = Vec::with_capacity(char_count * 6);
|
|
||||||
for mut character in string.chars() {
|
|
||||||
if !self.font.characters.contains_key(&character) {
|
|
||||||
character = '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
let info = &self.font.characters[&character];
|
|
||||||
let position_rect =
|
|
||||||
RectI32::new(Point2DI32::new(next.x() - info.origin_x, next.y() - info.origin_y),
|
|
||||||
Point2DI32::new(info.width as i32, info.height as i32));
|
|
||||||
let tex_coord_rect = RectI32::new(Point2DI32::new(info.x, info.y),
|
|
||||||
Point2DI32::new(info.width, info.height));
|
|
||||||
let first_vertex_index = vertex_data.len();
|
|
||||||
vertex_data.extend_from_slice(&[
|
|
||||||
DebugTextureVertex::new(position_rect.origin(), tex_coord_rect.origin()),
|
|
||||||
DebugTextureVertex::new(position_rect.upper_right(), tex_coord_rect.upper_right()),
|
|
||||||
DebugTextureVertex::new(position_rect.lower_right(), tex_coord_rect.lower_right()),
|
|
||||||
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
|
||||||
]);
|
|
||||||
index_data.extend(QUAD_INDICES.iter().map(|&i| i + first_vertex_index as u32));
|
|
||||||
|
|
||||||
let next_x = next.x() + info.advance;
|
|
||||||
next.set_x(next_x);
|
|
||||||
}
|
|
||||||
|
|
||||||
let color = if invert { INVERTED_TEXT_COLOR } else { TEXT_COLOR };
|
|
||||||
self.draw_texture_with_vertex_data(device,
|
|
||||||
&vertex_data,
|
|
||||||
&index_data,
|
|
||||||
&self.font_texture,
|
|
||||||
color);
|
|
||||||
}
|
|
||||||
|
|
||||||
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()),
|
|
||||||
DebugTextureVertex::new(position_rect.lower_right(), tex_coord_rect.lower_right()),
|
|
||||||
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
|
||||||
];
|
|
||||||
|
|
||||||
self.draw_texture_with_vertex_data(device, &vertex_data, &QUAD_INDICES, texture, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn measure_text(&self, string: &str) -> i32 {
|
|
||||||
let mut next = 0;
|
|
||||||
for mut character in string.chars() {
|
|
||||||
if !self.font.characters.contains_key(&character) {
|
|
||||||
character = '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
let info = &self.font.characters[&character];
|
|
||||||
next += info.advance;
|
|
||||||
}
|
|
||||||
next
|
|
||||||
}
|
|
||||||
|
|
||||||
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(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());
|
|
||||||
let solid_rect_left = RectI32::from_points(corner_rects.upper_left.lower_left(),
|
|
||||||
corner_rects.lower_left.upper_right());
|
|
||||||
let solid_rect_right = RectI32::from_points(corner_rects.upper_right.lower_left(),
|
|
||||||
corner_rects.lower_right.upper_right());
|
|
||||||
let vertex_data = vec![
|
|
||||||
DebugSolidVertex::new(solid_rect_mid.origin()),
|
|
||||||
DebugSolidVertex::new(solid_rect_mid.upper_right()),
|
|
||||||
DebugSolidVertex::new(solid_rect_mid.lower_right()),
|
|
||||||
DebugSolidVertex::new(solid_rect_mid.lower_left()),
|
|
||||||
|
|
||||||
DebugSolidVertex::new(solid_rect_left.origin()),
|
|
||||||
DebugSolidVertex::new(solid_rect_left.upper_right()),
|
|
||||||
DebugSolidVertex::new(solid_rect_left.lower_right()),
|
|
||||||
DebugSolidVertex::new(solid_rect_left.lower_left()),
|
|
||||||
|
|
||||||
DebugSolidVertex::new(solid_rect_right.origin()),
|
|
||||||
DebugSolidVertex::new(solid_rect_right.upper_right()),
|
|
||||||
DebugSolidVertex::new(solid_rect_right.lower_right()),
|
|
||||||
DebugSolidVertex::new(solid_rect_right.lower_left()),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut index_data = Vec::with_capacity(18);
|
|
||||||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 0));
|
|
||||||
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(device,
|
|
||||||
&vertex_data,
|
|
||||||
&index_data[0..18],
|
|
||||||
color,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(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()),
|
|
||||||
DebugSolidVertex::new(corner_rects.upper_right.origin()),
|
|
||||||
DebugSolidVertex::new(corner_rects.upper_right.lower_right()),
|
|
||||||
DebugSolidVertex::new(corner_rects.lower_right.upper_right()),
|
|
||||||
DebugSolidVertex::new(corner_rects.lower_left.lower_right()),
|
|
||||||
DebugSolidVertex::new(corner_rects.lower_right.lower_left()),
|
|
||||||
DebugSolidVertex::new(corner_rects.upper_left.lower_left()),
|
|
||||||
DebugSolidVertex::new(corner_rects.lower_left.origin()),
|
|
||||||
];
|
|
||||||
|
|
||||||
let index_data = &OUTLINE_RECT_LINE_INDICES;
|
|
||||||
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: &D::Texture,
|
|
||||||
corner_rects: &CornerRects) {
|
|
||||||
let corner_size = device.texture_size(&texture);
|
|
||||||
let tex_coord_rect = RectI32::new(Point2DI32::default(), corner_size);
|
|
||||||
|
|
||||||
let vertex_data = vec![
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.upper_left.origin(), tex_coord_rect.origin()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.upper_left.upper_right(), tex_coord_rect.upper_right()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.upper_left.lower_right(), tex_coord_rect.lower_right()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.upper_left.lower_left(), tex_coord_rect.lower_left()),
|
|
||||||
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.upper_right.origin(), tex_coord_rect.lower_left()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.upper_right.upper_right(), tex_coord_rect.origin()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.upper_right.lower_right(), tex_coord_rect.upper_right()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.upper_right.lower_left(), tex_coord_rect.lower_right()),
|
|
||||||
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.lower_left.origin(), tex_coord_rect.upper_right()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.lower_left.upper_right(), tex_coord_rect.lower_right()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.lower_left.lower_right(), tex_coord_rect.lower_left()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.lower_left.lower_left(), tex_coord_rect.origin()),
|
|
||||||
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.lower_right.origin(), tex_coord_rect.lower_right()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.lower_right.upper_right(), tex_coord_rect.lower_left()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.lower_right.lower_right(), tex_coord_rect.origin()),
|
|
||||||
DebugTextureVertex::new(
|
|
||||||
corner_rects.lower_right.lower_left(), tex_coord_rect.upper_right()),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut index_data = Vec::with_capacity(24);
|
|
||||||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 0));
|
|
||||||
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 4));
|
|
||||||
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(device, &vertex_data, &index_data, texture, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
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: &D::Texture,
|
|
||||||
color: ColorU) {
|
|
||||||
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);
|
|
||||||
|
|
||||||
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<D> where D: Device {
|
|
||||||
vertex_array: D::VertexArray,
|
|
||||||
vertex_buffer: D::Buffer,
|
|
||||||
index_buffer: D::Buffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
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);
|
|
||||||
device.configure_float_vertex_attr(&tex_coord_attr,
|
|
||||||
2,
|
|
||||||
VertexAttrType::U16,
|
|
||||||
false,
|
|
||||||
DEBUG_TEXTURE_VERTEX_SIZE,
|
|
||||||
4,
|
|
||||||
0);
|
|
||||||
|
|
||||||
DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DebugSolidVertexArray<D> where D: Device {
|
|
||||||
vertex_array: D::VertexArray,
|
|
||||||
vertex_buffer: D::Buffer,
|
|
||||||
index_buffer: D::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();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
texture_size_uniform,
|
|
||||||
texture_uniform,
|
|
||||||
color_uniform,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DebugSolidProgram<D> where D: Device {
|
|
||||||
program: D::Program,
|
|
||||||
framebuffer_size_uniform: D::Uniform,
|
|
||||||
color_uniform: D::Uniform,
|
|
||||||
}
|
|
||||||
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[repr(C)]
|
|
||||||
struct DebugTextureVertex {
|
|
||||||
position_x: i16,
|
|
||||||
position_y: i16,
|
|
||||||
tex_coord_x: u16,
|
|
||||||
tex_coord_y: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DebugTextureVertex {
|
|
||||||
fn new(position: Point2DI32, tex_coord: Point2DI32) -> DebugTextureVertex {
|
|
||||||
DebugTextureVertex {
|
|
||||||
position_x: position.x() as i16,
|
|
||||||
position_y: position.y() as i16,
|
|
||||||
tex_coord_x: tex_coord.x() as u16,
|
|
||||||
tex_coord_y: tex_coord.y() as u16,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[repr(C)]
|
|
||||||
struct DebugSolidVertex {
|
|
||||||
position_x: i16,
|
|
||||||
position_y: i16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DebugSolidVertex {
|
|
||||||
fn new(position: Point2DI32) -> DebugSolidVertex {
|
|
||||||
DebugSolidVertex { position_x: position.x() as i16, position_y: position.y() as i16 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SampleBuffer<S> where S: Add<S, Output=S> + Div<u32, Output=S> + Clone + Default {
|
struct SampleBuffer<S> where S: Add<S, Output=S> + Div<u32, Output=S> + Clone + Default {
|
||||||
|
@ -646,11 +126,6 @@ impl<S> SampleBuffer<S> where S: Add<S, Output=S> + Div<u32, Output=S> + Clone +
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)]
|
#[derive(Clone, Default)]
|
||||||
struct CPUSample {
|
struct CPUSample {
|
||||||
elapsed: Duration,
|
elapsed: Duration,
|
||||||
|
@ -709,22 +184,3 @@ impl Div<u32> for GPUSample {
|
||||||
fn duration_to_ms(time: Duration) -> f64 {
|
fn duration_to_ms(time: Duration) -> f64 {
|
||||||
time.as_secs() as f64 * 1000.0 + time.subsec_nanos() as f64 / 1000000.0
|
time.as_secs() as f64 * 1000.0 + time.subsec_nanos() as f64 / 1000000.0
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CornerRects {
|
|
||||||
upper_left: RectI32,
|
|
||||||
upper_right: RectI32,
|
|
||||||
lower_left: RectI32,
|
|
||||||
lower_right: RectI32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CornerRects {
|
|
||||||
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),
|
|
||||||
lower_left: RectI32::new(rect.lower_left() - Point2DI32::new(0, size.y()), size),
|
|
||||||
lower_right: RectI32::new(rect.lower_right() - size, size),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,10 +10,11 @@
|
||||||
|
|
||||||
use crate::gpu::debug::DebugUI;
|
use crate::gpu::debug::DebugUI;
|
||||||
use crate::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
|
use crate::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
|
||||||
use crate::paint::{ColorU, ObjectShader};
|
use crate::paint::ObjectShader;
|
||||||
use crate::post::DefringingKernel;
|
use crate::post::DefringingKernel;
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use pathfinder_geometry::basic::point::{Point2DI32, Point3DF32};
|
use pathfinder_geometry::basic::point::{Point2DI32, Point3DF32};
|
||||||
|
use pathfinder_geometry::color::ColorU;
|
||||||
use pathfinder_gpu::{BlendState, BufferTarget, BufferUploadMode, DepthFunc, DepthState, Device};
|
use pathfinder_gpu::{BlendState, BufferTarget, BufferUploadMode, DepthFunc, DepthState, Device};
|
||||||
use pathfinder_gpu::{Primitive, RenderState, Resources, StencilFunc, StencilState, TextureFormat};
|
use pathfinder_gpu::{Primitive, RenderState, Resources, StencilFunc, StencilState, TextureFormat};
|
||||||
use pathfinder_gpu::{UniformData, VertexAttrType};
|
use pathfinder_gpu::{UniformData, VertexAttrType};
|
||||||
|
@ -193,7 +194,7 @@ impl<D> Renderer<D> where D: Device {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: Point2DI32) {
|
pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: Point2DI32) {
|
||||||
self.main_framebuffer_size = new_framebuffer_size;
|
self.main_framebuffer_size = new_framebuffer_size;
|
||||||
self.debug_ui.set_framebuffer_size(new_framebuffer_size);
|
self.debug_ui.ui.set_framebuffer_size(new_framebuffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
|
|
||||||
//! How a path is to be filled.
|
//! How a path is to be filled.
|
||||||
|
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_geometry::color::ColorU;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Paint {
|
pub struct Paint {
|
||||||
|
@ -21,72 +20,6 @@ pub struct Paint {
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub struct PaintId(pub u16);
|
pub struct PaintId(pub u16);
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
|
|
||||||
pub struct ColorU {
|
|
||||||
pub r: u8,
|
|
||||||
pub g: u8,
|
|
||||||
pub b: u8,
|
|
||||||
pub a: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ColorU {
|
|
||||||
#[inline]
|
|
||||||
pub fn black() -> ColorU {
|
|
||||||
ColorU {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
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 {
|
|
||||||
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
|
||||||
if self.a == 255 {
|
|
||||||
write!(formatter, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)
|
|
||||||
} else {
|
|
||||||
write!(formatter,
|
|
||||||
"rgba({}, {}, {}, {})",
|
|
||||||
self.r,
|
|
||||||
self.g,
|
|
||||||
self.b,
|
|
||||||
self.a as f32 / 255.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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);
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,11 @@ use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
use pathfinder_geometry::basic::point::Point2DF32;
|
||||||
use pathfinder_geometry::basic::rect::RectF32;
|
use pathfinder_geometry::basic::rect::RectF32;
|
||||||
use pathfinder_geometry::basic::transform2d::{Transform2DF32, Transform2DF32PathIter};
|
use pathfinder_geometry::basic::transform2d::{Transform2DF32, Transform2DF32PathIter};
|
||||||
|
use pathfinder_geometry::color::ColorU;
|
||||||
use pathfinder_geometry::outline::Outline;
|
use pathfinder_geometry::outline::Outline;
|
||||||
use pathfinder_geometry::segment::{Segment, SegmentFlags};
|
use pathfinder_geometry::segment::{Segment, SegmentFlags};
|
||||||
use pathfinder_geometry::stroke::OutlineStrokeToFill;
|
use pathfinder_geometry::stroke::OutlineStrokeToFill;
|
||||||
use pathfinder_renderer::paint::{ColorU, Paint};
|
use pathfinder_renderer::paint::Paint;
|
||||||
use pathfinder_renderer::scene::{PathObject, PathObjectKind, Scene};
|
use pathfinder_renderer::scene::{PathObject, PathObjectKind, Scene};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use usvg::{Color as SvgColor, Node, NodeExt, NodeKind, Paint as UsvgPaint};
|
use usvg::{Color as SvgColor, Node, NodeExt, NodeKind, Paint as UsvgPaint};
|
||||||
|
|
|
@ -3,3 +3,21 @@ name = "pathfinder_ui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
[dependencies.hashbrown]
|
||||||
|
version = "0.1"
|
||||||
|
features = ["serde"]
|
||||||
|
|
||||||
|
[dependencies.pathfinder_geometry]
|
||||||
|
path = "../geometry"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_gpu]
|
||||||
|
path = "../gpu"
|
||||||
|
|
||||||
|
[dependencies.pathfinder_simd]
|
||||||
|
path = "../simd"
|
||||||
|
|
576
ui/src/lib.rs
576
ui/src/lib.rs
|
@ -1 +1,577 @@
|
||||||
|
// pathfinder/ui/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.
|
||||||
|
|
||||||
|
//! A minimal immediate mode UI, for debugging.
|
||||||
|
//!
|
||||||
|
//! This can be used in your own applications as an ultra-minimal lightweight
|
||||||
|
//! alternative to dear imgui, Conrod, etc.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
|
use pathfinder_geometry::basic::rect::RectI32;
|
||||||
|
use pathfinder_geometry::color::ColorU;
|
||||||
|
use pathfinder_gpu::{BlendState, BufferTarget, BufferUploadMode, Device, Primitive, RenderState};
|
||||||
|
use pathfinder_gpu::{Resources, UniformData, VertexAttrType};
|
||||||
|
use pathfinder_simd::default::F32x4;
|
||||||
|
use serde_json;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
const DEBUG_TEXTURE_VERTEX_SIZE: usize = 8;
|
||||||
|
const DEBUG_SOLID_VERTEX_SIZE: usize = 4;
|
||||||
|
|
||||||
|
pub const PADDING: i32 = 12;
|
||||||
|
|
||||||
|
pub static TEXT_COLOR: ColorU = ColorU { r: 255, g: 255, b: 255, a: 255 };
|
||||||
|
pub static WINDOW_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 - 90 };
|
||||||
|
|
||||||
|
static INVERTED_TEXT_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 };
|
||||||
|
|
||||||
|
static FONT_JSON_FILENAME: &'static str = "debug-font.json";
|
||||||
|
static FONT_PNG_NAME: &'static str = "debug-font";
|
||||||
|
|
||||||
|
static CORNER_FILL_PNG_NAME: &'static str = "debug-corner-fill";
|
||||||
|
static CORNER_OUTLINE_PNG_NAME: &'static str = "debug-corner-outline";
|
||||||
|
|
||||||
|
static QUAD_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3];
|
||||||
|
static RECT_LINE_INDICES: [u32; 8] = [0, 1, 1, 2, 2, 3, 3, 0];
|
||||||
|
static OUTLINE_RECT_LINE_INDICES: [u32; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct DebugFont {
|
||||||
|
name: String,
|
||||||
|
size: i32,
|
||||||
|
bold: bool,
|
||||||
|
italic: bool,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
characters: HashMap<char, DebugCharacter>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct DebugCharacter {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
#[serde(rename = "originX")]
|
||||||
|
origin_x: i32,
|
||||||
|
#[serde(rename = "originY")]
|
||||||
|
origin_y: i32,
|
||||||
|
advance: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugFont {
|
||||||
|
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 UI<D> where D: Device {
|
||||||
|
framebuffer_size: Point2DI32,
|
||||||
|
|
||||||
|
texture_program: DebugTextureProgram<D>,
|
||||||
|
texture_vertex_array: DebugTextureVertexArray<D>,
|
||||||
|
solid_program: DebugSolidProgram<D>,
|
||||||
|
solid_vertex_array: DebugSolidVertexArray<D>,
|
||||||
|
font: DebugFont,
|
||||||
|
|
||||||
|
font_texture: D::Texture,
|
||||||
|
corner_fill_texture: D::Texture,
|
||||||
|
corner_outline_texture: D::Texture,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> UI<D> where D: Device {
|
||||||
|
pub fn new(device: &D, resources: &Resources, framebuffer_size: Point2DI32) -> UI<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, resources);
|
||||||
|
let solid_vertex_array = DebugSolidVertexArray::new(device, &solid_program);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
UI {
|
||||||
|
framebuffer_size,
|
||||||
|
|
||||||
|
texture_program,
|
||||||
|
texture_vertex_array,
|
||||||
|
font,
|
||||||
|
solid_program,
|
||||||
|
solid_vertex_array,
|
||||||
|
|
||||||
|
font_texture,
|
||||||
|
corner_fill_texture,
|
||||||
|
corner_outline_texture,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn framebuffer_size(&self) -> Point2DI32 {
|
||||||
|
self.framebuffer_size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_framebuffer_size(&mut self, window_size: Point2DI32) {
|
||||||
|
self.framebuffer_size = window_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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, device: &D, rect: RectI32, color: ColorU) {
|
||||||
|
self.draw_rect(device, rect, color, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_rect(&self, device: &D, rect: RectI32, color: ColorU, filled: bool) {
|
||||||
|
let vertex_data = [
|
||||||
|
DebugSolidVertex::new(rect.origin()),
|
||||||
|
DebugSolidVertex::new(rect.upper_right()),
|
||||||
|
DebugSolidVertex::new(rect.lower_right()),
|
||||||
|
DebugSolidVertex::new(rect.lower_left()),
|
||||||
|
];
|
||||||
|
|
||||||
|
if filled {
|
||||||
|
self.draw_solid_rects_with_vertex_data(device,
|
||||||
|
&vertex_data,
|
||||||
|
&QUAD_INDICES,
|
||||||
|
color,
|
||||||
|
true);
|
||||||
|
} else {
|
||||||
|
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) {
|
||||||
|
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()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
let mut index_data = Vec::with_capacity(char_count * 6);
|
||||||
|
for mut character in string.chars() {
|
||||||
|
if !self.font.characters.contains_key(&character) {
|
||||||
|
character = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
let info = &self.font.characters[&character];
|
||||||
|
let position_rect =
|
||||||
|
RectI32::new(Point2DI32::new(next.x() - info.origin_x, next.y() - info.origin_y),
|
||||||
|
Point2DI32::new(info.width as i32, info.height as i32));
|
||||||
|
let tex_coord_rect = RectI32::new(Point2DI32::new(info.x, info.y),
|
||||||
|
Point2DI32::new(info.width, info.height));
|
||||||
|
let first_vertex_index = vertex_data.len();
|
||||||
|
vertex_data.extend_from_slice(&[
|
||||||
|
DebugTextureVertex::new(position_rect.origin(), tex_coord_rect.origin()),
|
||||||
|
DebugTextureVertex::new(position_rect.upper_right(), tex_coord_rect.upper_right()),
|
||||||
|
DebugTextureVertex::new(position_rect.lower_right(), tex_coord_rect.lower_right()),
|
||||||
|
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
||||||
|
]);
|
||||||
|
index_data.extend(QUAD_INDICES.iter().map(|&i| i + first_vertex_index as u32));
|
||||||
|
|
||||||
|
let next_x = next.x() + info.advance;
|
||||||
|
next.set_x(next_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
let color = if invert { INVERTED_TEXT_COLOR } else { TEXT_COLOR };
|
||||||
|
self.draw_texture_with_vertex_data(device,
|
||||||
|
&vertex_data,
|
||||||
|
&index_data,
|
||||||
|
&self.font_texture,
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
|
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()),
|
||||||
|
DebugTextureVertex::new(position_rect.lower_right(), tex_coord_rect.lower_right()),
|
||||||
|
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
|
||||||
|
];
|
||||||
|
|
||||||
|
self.draw_texture_with_vertex_data(device, &vertex_data, &QUAD_INDICES, texture, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn measure_text(&self, string: &str) -> i32 {
|
||||||
|
let mut next = 0;
|
||||||
|
for mut character in string.chars() {
|
||||||
|
if !self.font.characters.contains_key(&character) {
|
||||||
|
character = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
let info = &self.font.characters[&character];
|
||||||
|
next += info.advance;
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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());
|
||||||
|
let solid_rect_left = RectI32::from_points(corner_rects.upper_left.lower_left(),
|
||||||
|
corner_rects.lower_left.upper_right());
|
||||||
|
let solid_rect_right = RectI32::from_points(corner_rects.upper_right.lower_left(),
|
||||||
|
corner_rects.lower_right.upper_right());
|
||||||
|
let vertex_data = vec![
|
||||||
|
DebugSolidVertex::new(solid_rect_mid.origin()),
|
||||||
|
DebugSolidVertex::new(solid_rect_mid.upper_right()),
|
||||||
|
DebugSolidVertex::new(solid_rect_mid.lower_right()),
|
||||||
|
DebugSolidVertex::new(solid_rect_mid.lower_left()),
|
||||||
|
|
||||||
|
DebugSolidVertex::new(solid_rect_left.origin()),
|
||||||
|
DebugSolidVertex::new(solid_rect_left.upper_right()),
|
||||||
|
DebugSolidVertex::new(solid_rect_left.lower_right()),
|
||||||
|
DebugSolidVertex::new(solid_rect_left.lower_left()),
|
||||||
|
|
||||||
|
DebugSolidVertex::new(solid_rect_right.origin()),
|
||||||
|
DebugSolidVertex::new(solid_rect_right.upper_right()),
|
||||||
|
DebugSolidVertex::new(solid_rect_right.lower_right()),
|
||||||
|
DebugSolidVertex::new(solid_rect_right.lower_left()),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut index_data = Vec::with_capacity(18);
|
||||||
|
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 0));
|
||||||
|
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(device,
|
||||||
|
&vertex_data,
|
||||||
|
&index_data[0..18],
|
||||||
|
color,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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()),
|
||||||
|
DebugSolidVertex::new(corner_rects.upper_right.origin()),
|
||||||
|
DebugSolidVertex::new(corner_rects.upper_right.lower_right()),
|
||||||
|
DebugSolidVertex::new(corner_rects.lower_right.upper_right()),
|
||||||
|
DebugSolidVertex::new(corner_rects.lower_left.lower_right()),
|
||||||
|
DebugSolidVertex::new(corner_rects.lower_right.lower_left()),
|
||||||
|
DebugSolidVertex::new(corner_rects.upper_left.lower_left()),
|
||||||
|
DebugSolidVertex::new(corner_rects.lower_left.origin()),
|
||||||
|
];
|
||||||
|
|
||||||
|
let index_data = &OUTLINE_RECT_LINE_INDICES;
|
||||||
|
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: &D::Texture,
|
||||||
|
corner_rects: &CornerRects) {
|
||||||
|
let corner_size = device.texture_size(&texture);
|
||||||
|
let tex_coord_rect = RectI32::new(Point2DI32::default(), corner_size);
|
||||||
|
|
||||||
|
let vertex_data = vec![
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.upper_left.origin(), tex_coord_rect.origin()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.upper_left.upper_right(), tex_coord_rect.upper_right()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.upper_left.lower_right(), tex_coord_rect.lower_right()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.upper_left.lower_left(), tex_coord_rect.lower_left()),
|
||||||
|
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.upper_right.origin(), tex_coord_rect.lower_left()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.upper_right.upper_right(), tex_coord_rect.origin()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.upper_right.lower_right(), tex_coord_rect.upper_right()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.upper_right.lower_left(), tex_coord_rect.lower_right()),
|
||||||
|
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.lower_left.origin(), tex_coord_rect.upper_right()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.lower_left.upper_right(), tex_coord_rect.lower_right()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.lower_left.lower_right(), tex_coord_rect.lower_left()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.lower_left.lower_left(), tex_coord_rect.origin()),
|
||||||
|
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.lower_right.origin(), tex_coord_rect.lower_right()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.lower_right.upper_right(), tex_coord_rect.lower_left()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.lower_right.lower_right(), tex_coord_rect.origin()),
|
||||||
|
DebugTextureVertex::new(
|
||||||
|
corner_rects.lower_right.lower_left(), tex_coord_rect.upper_right()),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut index_data = Vec::with_capacity(24);
|
||||||
|
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 0));
|
||||||
|
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 4));
|
||||||
|
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(device, &vertex_data, &index_data, texture, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
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: &D::Texture,
|
||||||
|
color: ColorU) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
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 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
texture_size_uniform,
|
||||||
|
texture_uniform,
|
||||||
|
color_uniform,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DebugTextureVertexArray<D> where D: Device {
|
||||||
|
vertex_array: D::VertexArray,
|
||||||
|
vertex_buffer: D::Buffer,
|
||||||
|
index_buffer: D::Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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);
|
||||||
|
device.configure_float_vertex_attr(&tex_coord_attr,
|
||||||
|
2,
|
||||||
|
VertexAttrType::U16,
|
||||||
|
false,
|
||||||
|
DEBUG_TEXTURE_VERTEX_SIZE,
|
||||||
|
4,
|
||||||
|
0);
|
||||||
|
|
||||||
|
DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DebugSolidVertexArray<D> where D: Device {
|
||||||
|
vertex_array: D::VertexArray,
|
||||||
|
vertex_buffer: D::Buffer,
|
||||||
|
index_buffer: D::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();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DebugSolidProgram<D> where D: Device {
|
||||||
|
program: D::Program,
|
||||||
|
framebuffer_size_uniform: D::Uniform,
|
||||||
|
color_uniform: D::Uniform,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct DebugTextureVertex {
|
||||||
|
position_x: i16,
|
||||||
|
position_y: i16,
|
||||||
|
tex_coord_x: u16,
|
||||||
|
tex_coord_y: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugTextureVertex {
|
||||||
|
fn new(position: Point2DI32, tex_coord: Point2DI32) -> DebugTextureVertex {
|
||||||
|
DebugTextureVertex {
|
||||||
|
position_x: position.x() as i16,
|
||||||
|
position_y: position.y() as i16,
|
||||||
|
tex_coord_x: tex_coord.x() as u16,
|
||||||
|
tex_coord_y: tex_coord.y() as u16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct DebugSolidVertex {
|
||||||
|
position_x: i16,
|
||||||
|
position_y: i16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugSolidVertex {
|
||||||
|
fn new(position: Point2DI32) -> DebugSolidVertex {
|
||||||
|
DebugSolidVertex { position_x: position.x() as i16, position_y: position.y() as i16 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CornerRects {
|
||||||
|
upper_left: RectI32,
|
||||||
|
upper_right: RectI32,
|
||||||
|
lower_left: RectI32,
|
||||||
|
lower_right: RectI32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CornerRects {
|
||||||
|
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),
|
||||||
|
lower_left: RectI32::new(rect.lower_left() - Point2DI32::new(0, size.y()), size),
|
||||||
|
lower_right: RectI32::new(rect.lower_right() - size, size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue