mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
Add rustfmt.toml and enable auto formatting (Fixes #7)
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
use crate::color_palette::ColorPalette;
|
||||
use crate::window_events;
|
||||
use crate::pipeline::Pipeline;
|
||||
use crate::texture::Texture;
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use crate::layout_system::LayoutSystem;
|
||||
use crate::gui_node::GuiNode;
|
||||
use crate::layout_system::LayoutSystem;
|
||||
use crate::pipeline::Pipeline;
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use crate::texture::Texture;
|
||||
use crate::window_events;
|
||||
use futures::executor::block_on;
|
||||
use winit::event::*;
|
||||
use winit::event_loop::*;
|
||||
use winit::window::Window;
|
||||
use futures::executor::block_on;
|
||||
|
||||
pub struct Application {
|
||||
pub surface: wgpu::Surface,
|
||||
@@ -35,7 +35,8 @@ impl Application {
|
||||
compatible_surface: Some(&surface),
|
||||
},
|
||||
wgpu::BackendBit::PRIMARY,
|
||||
)).unwrap();
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Requests the device and queue from the adapter
|
||||
let requested_device = block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||
@@ -48,7 +49,7 @@ impl Application {
|
||||
|
||||
// Represents the GPU command queue, to submit CommandBuffers
|
||||
let queue = requested_device.1;
|
||||
|
||||
|
||||
// Properties for the swap chain frame buffers
|
||||
let swap_chain_descriptor = wgpu::SwapChainDescriptor {
|
||||
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
||||
@@ -70,7 +71,11 @@ impl Application {
|
||||
|
||||
// Data structure maintaining the user interface
|
||||
let gui_rect_pipeline = Pipeline::new(
|
||||
&device, swap_chain_descriptor.format, Vec::new(), &mut shader_cache, ("shaders/shader.vert", "shaders/shader.frag"),
|
||||
&device,
|
||||
swap_chain_descriptor.format,
|
||||
Vec::new(),
|
||||
&mut shader_cache,
|
||||
("shaders/shader.vert", "shaders/shader.frag"),
|
||||
);
|
||||
pipeline_cache.set("gui_rect", gui_rect_pipeline);
|
||||
|
||||
@@ -127,15 +132,13 @@ impl Application {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_gui(&mut self) {
|
||||
|
||||
}
|
||||
fn update_gui(&mut self) {}
|
||||
|
||||
// Render the queue of pipeline draw commands over the current window
|
||||
fn render(&mut self) {
|
||||
// Get a frame buffer to render on
|
||||
let frame = self.swap_chain.get_next_texture().expect("Timeout getting frame buffer texture");
|
||||
|
||||
|
||||
// Generates a render pass that commands are applied to, then generates a command buffer when finished
|
||||
let mut command_encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder") });
|
||||
|
||||
@@ -144,21 +147,19 @@ impl Application {
|
||||
|
||||
// Recording of commands while in "rendering mode" that go into a command buffer
|
||||
let mut render_pass = command_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[
|
||||
wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &frame.view,
|
||||
resolve_target: None,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color::BLACK,
|
||||
}
|
||||
],
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &frame.view,
|
||||
resolve_target: None,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color::BLACK,
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
// Prepare a variable to reuse the pipeline based on its name
|
||||
let mut pipeline_name = String::new();
|
||||
|
||||
|
||||
// Turn the queue of pipelines each into a command buffer and submit it to the render queue
|
||||
for i in 0..commands.len() {
|
||||
// If the previously set pipeline can't be reused, send the GPU the new pipeline to draw with
|
||||
@@ -179,7 +180,7 @@ impl Application {
|
||||
|
||||
// Draw call
|
||||
render_pass.draw_indexed(0..commands[i].index_count, 0, 0..1);
|
||||
};
|
||||
}
|
||||
|
||||
// Done sending render pass commands so we can give up mutation rights to command_encoder
|
||||
drop(render_pass);
|
||||
|
||||
65
src/color.rs
65
src/color.rs
@@ -13,74 +13,29 @@ impl Color {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const TRANSPARENT: Self = Color {
|
||||
r: 0.0,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 0.0,
|
||||
};
|
||||
pub const TRANSPARENT: Self = Color { r: 0.0, g: 0.0, b: 0.0, a: 0.0 };
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BLACK: Self = Color {
|
||||
r: 0.0,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 1.0,
|
||||
};
|
||||
pub const BLACK: Self = Color { r: 0.0, g: 0.0, b: 0.0, a: 1.0 };
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const WHITE: Self = Color {
|
||||
r: 1.0,
|
||||
g: 1.0,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
};
|
||||
pub const WHITE: Self = Color { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const RED: Self = Color {
|
||||
r: 1.0,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 1.0,
|
||||
};
|
||||
pub const RED: Self = Color { r: 1.0, g: 0.0, b: 0.0, a: 1.0 };
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const YELLOW: Self = Color {
|
||||
r: 1.0,
|
||||
g: 1.0,
|
||||
b: 0.0,
|
||||
a: 1.0,
|
||||
};
|
||||
pub const YELLOW: Self = Color { r: 1.0, g: 1.0, b: 0.0, a: 1.0 };
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const GREEN: Self = Color {
|
||||
r: 0.0,
|
||||
g: 1.0,
|
||||
b: 0.0,
|
||||
a: 1.0,
|
||||
};
|
||||
pub const GREEN: Self = Color { r: 0.0, g: 1.0, b: 0.0, a: 1.0 };
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const CYAN: Self = Color {
|
||||
r: 0.0,
|
||||
g: 1.0,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
};
|
||||
pub const CYAN: Self = Color { r: 0.0, g: 1.0, b: 1.0, a: 1.0 };
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const BLUE: Self = Color {
|
||||
r: 0.0,
|
||||
g: 0.0,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
};
|
||||
pub const BLUE: Self = Color { r: 0.0, g: 0.0, b: 1.0, a: 1.0 };
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const MAGENTA: Self = Color {
|
||||
r: 1.0,
|
||||
g: 0.0,
|
||||
b: 1.0,
|
||||
a: 1.0,
|
||||
};
|
||||
}
|
||||
pub const MAGENTA: Self = Color { r: 1.0, g: 0.0, b: 1.0, a: 1.0 };
|
||||
}
|
||||
|
||||
@@ -25,22 +25,22 @@ impl ColorPalette {
|
||||
#[allow(dead_code)]
|
||||
pub fn into_color_srgb(&self) -> Color {
|
||||
let grayscale = match self {
|
||||
ColorPalette::Black => 0 * 17, // #000000
|
||||
ColorPalette::NearBlack => 1 * 17, // #111111
|
||||
ColorPalette::MildBlack => 2 * 17, // #222222
|
||||
ColorPalette::DarkGray => 3 * 17, // #333333
|
||||
ColorPalette::DimGray => 4 * 17, // #444444
|
||||
ColorPalette::DullGray => 5 * 17, // #555555
|
||||
ColorPalette::LowerGray => 6 * 17, // #666666
|
||||
ColorPalette::MiddleGray => 7 * 17, // #777777
|
||||
ColorPalette::UpperGray => 8 * 17, // #888888
|
||||
ColorPalette::PaleGray => 9 * 17, // #999999
|
||||
ColorPalette::SoftGray => 10 * 17, // #aaaaaa
|
||||
ColorPalette::LightGray => 11 * 17, // #bbbbbb
|
||||
ColorPalette::Black => 0 * 17, // #000000
|
||||
ColorPalette::NearBlack => 1 * 17, // #111111
|
||||
ColorPalette::MildBlack => 2 * 17, // #222222
|
||||
ColorPalette::DarkGray => 3 * 17, // #333333
|
||||
ColorPalette::DimGray => 4 * 17, // #444444
|
||||
ColorPalette::DullGray => 5 * 17, // #555555
|
||||
ColorPalette::LowerGray => 6 * 17, // #666666
|
||||
ColorPalette::MiddleGray => 7 * 17, // #777777
|
||||
ColorPalette::UpperGray => 8 * 17, // #888888
|
||||
ColorPalette::PaleGray => 9 * 17, // #999999
|
||||
ColorPalette::SoftGray => 10 * 17, // #aaaaaa
|
||||
ColorPalette::LightGray => 11 * 17, // #bbbbbb
|
||||
ColorPalette::BrightGray => 12 * 17, // #cccccc
|
||||
ColorPalette::MildWhite => 13 * 17, // #dddddd
|
||||
ColorPalette::NearWhite => 14 * 17, // #eeeeee
|
||||
ColorPalette::White => 15 * 17, // #ffffff
|
||||
ColorPalette::MildWhite => 13 * 17, // #dddddd
|
||||
ColorPalette::NearWhite => 14 * 17, // #eeeeee
|
||||
ColorPalette::White => 15 * 17, // #ffffff
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
@@ -51,7 +51,7 @@ impl ColorPalette {
|
||||
|
||||
let rgba = match self {
|
||||
ColorPalette::Accent => (75, 121, 167, 255), // #4b79a7
|
||||
_ => (0, 0, 0, 255), // Unimplemented returns black
|
||||
_ => (0, 0, 0, 255), // Unimplemented returns black
|
||||
};
|
||||
|
||||
Color::new(rgba.0 as f32 / 255.0, rgba.1 as f32 / 255.0, rgba.2 as f32 / 255.0, rgba.3 as f32 / 255.0)
|
||||
@@ -88,4 +88,4 @@ impl ColorPalette {
|
||||
_ => panic!("Invalid color lookup of `{}` from the color palette", name_in_palette),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,4 +22,4 @@ impl DrawCommand {
|
||||
index_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,12 @@ pub struct Corners<T> {
|
||||
|
||||
impl<T> Corners<T> {
|
||||
pub fn new(top_left: T, top_right: T, bottom_right: T, bottom_left: T) -> Self {
|
||||
Self { top_left, top_right, bottom_right, bottom_left }
|
||||
Self {
|
||||
top_left,
|
||||
top_right,
|
||||
bottom_right,
|
||||
bottom_left,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use crate::draw_command::DrawCommand;
|
||||
use crate::color::Color;
|
||||
use crate::texture::Texture;
|
||||
use crate::pipeline::Pipeline;
|
||||
use crate::draw_command::DrawCommand;
|
||||
use crate::gui_attributes::*;
|
||||
use crate::pipeline::Pipeline;
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use crate::texture::Texture;
|
||||
|
||||
pub struct GuiNode {
|
||||
pub form_factor: GuiNodeUniform,
|
||||
@@ -18,7 +18,13 @@ impl GuiNode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_draw_commands_recursive(node: &rctree::Node<GuiNode>, device: &wgpu::Device, queue: &mut wgpu::Queue, pipeline_cache: &ResourceCache<Pipeline>, texture_cache: &mut ResourceCache<Texture>) -> Vec<DrawCommand> {
|
||||
pub fn build_draw_commands_recursive(
|
||||
node: &rctree::Node<GuiNode>,
|
||||
device: &wgpu::Device,
|
||||
queue: &mut wgpu::Queue,
|
||||
pipeline_cache: &ResourceCache<Pipeline>,
|
||||
texture_cache: &mut ResourceCache<Texture>,
|
||||
) -> Vec<DrawCommand> {
|
||||
let mut draw_commands: Vec<DrawCommand> = Vec::new();
|
||||
|
||||
for mut subnode in node.descendants() {
|
||||
@@ -32,19 +38,11 @@ impl GuiNode {
|
||||
}
|
||||
|
||||
pub fn build_draw_command(&mut self, device: &wgpu::Device, queue: &mut wgpu::Queue, pipeline: &Pipeline, texture_cache: &mut ResourceCache<Texture>) -> DrawCommand {
|
||||
const VERTICES: &[[f32; 2]] = &[
|
||||
[-0.5, 0.5],
|
||||
[0.5, 0.5],
|
||||
[0.5, 1.0],
|
||||
[-0.5, 1.0],
|
||||
];
|
||||
const INDICES: &[u16] = &[
|
||||
0, 1, 2,
|
||||
0, 2, 3,
|
||||
];
|
||||
const VERTICES: &[[f32; 2]] = &[[-0.5, 0.5], [0.5, 0.5], [0.5, 1.0], [-0.5, 1.0]];
|
||||
const INDICES: &[u16] = &[0, 1, 2, 0, 2, 3];
|
||||
|
||||
let bind_groups = self.build_bind_groups(device, queue, pipeline, texture_cache);
|
||||
|
||||
|
||||
// Create a draw command with the vertex data then push it to the GPU command queue
|
||||
DrawCommand::new(device, self.pipeline_name.clone(), bind_groups, VERTICES, INDICES)
|
||||
}
|
||||
@@ -57,15 +55,17 @@ impl GuiNode {
|
||||
let binding_staging_buffer = Pipeline::build_binding_staging_buffer(device, &self.form_factor);
|
||||
|
||||
// Construct the bind group for this GUI node
|
||||
let bind_group = Pipeline::build_bind_group(device, &pipeline.bind_group_layout, vec![
|
||||
Pipeline::build_binding_resource(&binding_staging_buffer),
|
||||
wgpu::BindingResource::TextureView(&texture.texture_view),
|
||||
wgpu::BindingResource::Sampler(&texture.sampler),
|
||||
]);
|
||||
|
||||
vec![
|
||||
bind_group,
|
||||
]
|
||||
let bind_group = Pipeline::build_bind_group(
|
||||
device,
|
||||
&pipeline.bind_group_layout,
|
||||
vec![
|
||||
Pipeline::build_binding_resource(&binding_staging_buffer),
|
||||
wgpu::BindingResource::TextureView(&texture.texture_view),
|
||||
wgpu::BindingResource::Sampler(&texture.sampler),
|
||||
],
|
||||
);
|
||||
|
||||
vec![bind_group]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
use crate::layout_abstract_types::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -26,7 +25,11 @@ pub struct LayoutAbstractTag {
|
||||
|
||||
impl LayoutAbstractTag {
|
||||
pub fn new(namespace: String, name: String) -> Self {
|
||||
Self { namespace, name, attributes: Vec::new() }
|
||||
Self {
|
||||
namespace,
|
||||
name,
|
||||
attributes: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_attribute(&mut self, attribute: Attribute) {
|
||||
|
||||
@@ -9,7 +9,11 @@ pub struct VariableParameter {
|
||||
|
||||
impl VariableParameter {
|
||||
pub fn new(name: String, valid_types: Vec<Vec<TypeName>>, default: Vec<TypeValue>) -> Self {
|
||||
Self { name, type_sequence_options: valid_types, type_sequence_default: default }
|
||||
Self {
|
||||
name,
|
||||
type_sequence_options: valid_types,
|
||||
type_sequence_default: default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::layout_abstract_types::*;
|
||||
use crate::layout_abstract_syntax::*;
|
||||
use crate::color_palette::ColorPalette;
|
||||
use crate::color::Color;
|
||||
use crate::color_palette::ColorPalette;
|
||||
use crate::layout_abstract_syntax::*;
|
||||
use crate::layout_abstract_types::*;
|
||||
|
||||
pub struct AttributeParser {
|
||||
capture_attribute_declaration_parameter_regex: regex::Regex,
|
||||
@@ -17,8 +17,9 @@ impl AttributeParser {
|
||||
pub fn new() -> Self {
|
||||
let capture_attribute_declaration_parameter_regex: regex::Regex = regex::Regex::new(
|
||||
// Parameter: ?: (?, ... | ...) = ?
|
||||
r"^\s*(\w*)\s*(:)\s*(\()\s*((?:(?:\w+)(?:\s*,\s*\w+)*)(?:\s*\|\s*(?:(?:\w+)(?:\s*,\s*\w+)*))*)\s*(\))\s*(=)\s*([\s\w'\[\]@%\-.`,]*?)\s*$"
|
||||
).unwrap();
|
||||
r"^\s*(\w*)\s*(:)\s*(\()\s*((?:(?:\w+)(?:\s*,\s*\w+)*)(?:\s*\|\s*(?:(?:\w+)(?:\s*,\s*\w+)*))*)\s*(\))\s*(=)\s*([\s\w'\[\]@%\-.`,]*?)\s*$",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let capture_attribute_type_sequences_regex: regex::Regex = regex::Regex::new(concat!(
|
||||
// Argument: {{?}}
|
||||
@@ -47,7 +48,8 @@ impl AttributeParser {
|
||||
r#"^\s*([Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee])\s*$|"#,
|
||||
// None: none
|
||||
r#"^\s*([Nn][Oo][Nn][Ee])\s*$"#,
|
||||
)).unwrap();
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let match_integer_regex = regex::Regex::new(r"^\s*(-?\d+)\s*$").unwrap();
|
||||
|
||||
@@ -69,15 +71,19 @@ impl AttributeParser {
|
||||
|
||||
pub fn parse_attribute_types(&self, input: &str) -> AttributeValue {
|
||||
let attribute_types = input.split(",").map(|piece| piece.trim()).collect::<Vec<&str>>();
|
||||
let list = attribute_types.iter().map(|attribute_type| self.parse_attribute_type(attribute_type)).collect::<Vec<TypeValueOrArgument>>();
|
||||
let list = attribute_types
|
||||
.iter()
|
||||
.map(|attribute_type| self.parse_attribute_type(attribute_type))
|
||||
.collect::<Vec<TypeValueOrArgument>>();
|
||||
AttributeValue::TypeValue(list)
|
||||
}
|
||||
|
||||
pub fn parse_attribute_type(&self, attribute_type: &str) -> TypeValueOrArgument {
|
||||
// Match with the regular expression
|
||||
let captures = self.capture_attribute_type_sequences_regex.captures(attribute_type).map(|captures|
|
||||
captures.iter().skip(1).flat_map(|c| c).map(|c| c.as_str()).collect::<Vec<_>>()
|
||||
);
|
||||
let captures = self
|
||||
.capture_attribute_type_sequences_regex
|
||||
.captures(attribute_type)
|
||||
.map(|captures| captures.iter().skip(1).flat_map(|c| c).map(|c| c.as_str()).collect::<Vec<_>>());
|
||||
|
||||
// Match against the captured values as a list of tokens
|
||||
let tokens = captures.as_ref().map(|c| c.as_slice());
|
||||
@@ -89,46 +95,50 @@ impl AttributeParser {
|
||||
},
|
||||
// Integer: ?
|
||||
Some([value]) if self.match_integer_regex.is_match(value) => {
|
||||
let integer = value.parse::<i64>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
let integer = value
|
||||
.parse::<i64>()
|
||||
.expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
TypeValueOrArgument::TypeValue(TypeValue::Integer(integer))
|
||||
},
|
||||
// Decimal: ?
|
||||
Some([value]) if self.match_decimal_regex.is_match(value) => {
|
||||
let decimal = value.parse::<f64>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
let decimal = value
|
||||
.parse::<f64>()
|
||||
.expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
TypeValueOrArgument::TypeValue(TypeValue::Decimal(decimal))
|
||||
},
|
||||
// AbsolutePx: px
|
||||
Some([value, px]) if px.eq_ignore_ascii_case("px") => {
|
||||
let pixels = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type`{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
let pixels = value
|
||||
.parse::<f32>()
|
||||
.expect(&format!("Invalid value `{}` specified in the attribute type`{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
TypeValueOrArgument::TypeValue(TypeValue::AbsolutePx(pixels))
|
||||
},
|
||||
// Percent: ?%
|
||||
Some([value, "%"]) => {
|
||||
let percent = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
let percent = value
|
||||
.parse::<f32>()
|
||||
.expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
TypeValueOrArgument::TypeValue(TypeValue::Percent(percent))
|
||||
},
|
||||
// PercentRemainder: ?@
|
||||
Some([value, "@"]) => {
|
||||
let percent_remainder = value.parse::<f32>().expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
let percent_remainder = value
|
||||
.parse::<f32>()
|
||||
.expect(&format!("Invalid value `{}` specified in the attribute type `{}` when parsing XML layout", value, attribute_type)[..]);
|
||||
TypeValueOrArgument::TypeValue(TypeValue::PercentRemainder(percent_remainder))
|
||||
},
|
||||
// Inner: inner
|
||||
Some([inner]) if inner.eq_ignore_ascii_case("inner") => {
|
||||
TypeValueOrArgument::TypeValue(TypeValue::Inner)
|
||||
},
|
||||
Some([inner]) if inner.eq_ignore_ascii_case("inner") => TypeValueOrArgument::TypeValue(TypeValue::Inner),
|
||||
// Width: width
|
||||
Some([width]) if width.eq_ignore_ascii_case("width") => {
|
||||
TypeValueOrArgument::TypeValue(TypeValue::Width)
|
||||
},
|
||||
Some([width]) if width.eq_ignore_ascii_case("width") => TypeValueOrArgument::TypeValue(TypeValue::Width),
|
||||
// Height: height
|
||||
Some([height]) if height.eq_ignore_ascii_case("height") => {
|
||||
TypeValueOrArgument::TypeValue(TypeValue::Height)
|
||||
},
|
||||
Some([height]) if height.eq_ignore_ascii_case("height") => TypeValueOrArgument::TypeValue(TypeValue::Height),
|
||||
// TemplateString: `? ... {{?}} ...`
|
||||
Some(["`", string, "`"]) => {
|
||||
let mut segments = Vec::<TemplateStringSegment>::new();
|
||||
let mut is_template = false;
|
||||
|
||||
|
||||
for part in self.split_by_string_templates_regex.split(string) {
|
||||
let segment = match is_template {
|
||||
true => TemplateStringSegment::String(String::from(part)),
|
||||
@@ -144,14 +154,32 @@ impl AttributeParser {
|
||||
Some(["[", color_name, "]"]) => {
|
||||
let color = match self.capture_color_name_in_palette_regex.captures(color_name) {
|
||||
Some(captures) => {
|
||||
let palette_color = captures.get(1).expect(&format!("Invalid palette color name `{}` specified in the attribute type `{}` when parsing XML layout", color_name, attribute_type)[..]).as_str();
|
||||
let palette_color = captures
|
||||
.get(1)
|
||||
.expect(
|
||||
&format!(
|
||||
"Invalid palette color name `{}` specified in the attribute type `{}` when parsing XML layout",
|
||||
color_name, attribute_type
|
||||
)[..],
|
||||
)
|
||||
.as_str();
|
||||
ColorPalette::lookup_palette_color(palette_color).into_color_srgb()
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let parsed = color_name.parse::<css_color_parser::Color>();
|
||||
let css_color = parsed.expect(&format!("Invalid CSS color name `{}` specified in the attribute type `{}` when parsing XML layout", color_name, attribute_type)[..]);
|
||||
Color::new(css_color.r as f32 / 255.0, css_color.g as f32 / 255.0, css_color.b as f32 / 255.0, css_color.a as f32 / 255.0)
|
||||
}
|
||||
let css_color = parsed.expect(
|
||||
&format!(
|
||||
"Invalid CSS color name `{}` specified in the attribute type `{}` when parsing XML layout",
|
||||
color_name, attribute_type
|
||||
)[..],
|
||||
);
|
||||
Color::new(
|
||||
css_color.r as f32 / 255.0,
|
||||
css_color.g as f32 / 255.0,
|
||||
css_color.b as f32 / 255.0,
|
||||
css_color.a as f32 / 255.0,
|
||||
)
|
||||
},
|
||||
};
|
||||
|
||||
TypeValueOrArgument::TypeValue(TypeValue::Color(color))
|
||||
@@ -162,9 +190,7 @@ impl AttributeParser {
|
||||
TypeValueOrArgument::TypeValue(TypeValue::Bool(boolean))
|
||||
},
|
||||
// None: none
|
||||
Some([none]) if none.eq_ignore_ascii_case("none") => {
|
||||
TypeValueOrArgument::TypeValue(TypeValue::None)
|
||||
},
|
||||
Some([none]) if none.eq_ignore_ascii_case("none") => TypeValueOrArgument::TypeValue(TypeValue::None),
|
||||
// Unrecognized type pattern
|
||||
_ => panic!("Invalid attribute type `{}` when parsing XML layout", attribute_type),
|
||||
}
|
||||
@@ -172,9 +198,10 @@ impl AttributeParser {
|
||||
|
||||
pub fn parse_attribute_declaration(&self, attribute_declaration: &str) -> AttributeValue {
|
||||
// Match with the regular expression
|
||||
let captures = self.capture_attribute_declaration_parameter_regex.captures(attribute_declaration).map(|captures|
|
||||
captures.iter().skip(1).flat_map(|c| c).map(|c| c.as_str()).collect::<Vec<_>>()
|
||||
);
|
||||
let captures = self
|
||||
.capture_attribute_declaration_parameter_regex
|
||||
.captures(attribute_declaration)
|
||||
.map(|captures| captures.iter().skip(1).flat_map(|c| c).map(|c| c.as_str()).collect::<Vec<_>>());
|
||||
|
||||
// Match against the captured values as a list of tokens
|
||||
let tokens = captures.as_ref().map(|c| c.as_slice());
|
||||
@@ -183,43 +210,56 @@ impl AttributeParser {
|
||||
Some([name, ":", "(", raw_types_list, ")", "=", default_value]) => {
|
||||
// Variable name bound in the parameter
|
||||
let name = String::from(*name);
|
||||
|
||||
// Split the type sequences up into a list of options separated by vertical bars
|
||||
let type_sequence_options = String::from(*raw_types_list).split("|").map(|group| {
|
||||
// Split each type sequence into individual types separated by commas
|
||||
group.split(",").map(|individual_type| {
|
||||
// Remove any whitespace around the type
|
||||
let individual_type = individual_type.trim();
|
||||
|
||||
// Return the case-insensitive TypeName enum for the individual type
|
||||
match &individual_type.to_ascii_lowercase()[..] {
|
||||
// "xml" => TypeName::Xml, // TODO
|
||||
"integer" => TypeName::Integer,
|
||||
"decimal" => TypeName::Decimal,
|
||||
"absolutepx" => TypeName::AbsolutePx,
|
||||
"percent" => TypeName::Percent,
|
||||
"percentremainder" => TypeName::PercentRemainder,
|
||||
"inner" => TypeName::Inner,
|
||||
"width" => TypeName::Width,
|
||||
"height" => TypeName::Height,
|
||||
"templatestring" => TypeName::TemplateString,
|
||||
"color" => TypeName::Color,
|
||||
"bool" => TypeName::Bool,
|
||||
"none" => TypeName::None,
|
||||
_ => panic!("Invalid type `{}` specified in the attribute type `{}` when parsing XML layout", individual_type, attribute_declaration),
|
||||
}
|
||||
}).collect::<Vec<TypeName>>()
|
||||
}).collect::<Vec<Vec<TypeName>>>();
|
||||
// Split the type sequences up into a list of options separated by vertical bars
|
||||
let type_sequence_options = String::from(*raw_types_list)
|
||||
.split("|")
|
||||
.map(|group| {
|
||||
// Split each type sequence into individual types separated by commas
|
||||
group
|
||||
.split(",")
|
||||
.map(|individual_type| {
|
||||
// Remove any whitespace around the type
|
||||
let individual_type = individual_type.trim();
|
||||
|
||||
// Return the case-insensitive TypeName enum for the individual type
|
||||
match &individual_type.to_ascii_lowercase()[..] {
|
||||
// "xml" => TypeName::Xml, // TODO
|
||||
"integer" => TypeName::Integer,
|
||||
"decimal" => TypeName::Decimal,
|
||||
"absolutepx" => TypeName::AbsolutePx,
|
||||
"percent" => TypeName::Percent,
|
||||
"percentremainder" => TypeName::PercentRemainder,
|
||||
"inner" => TypeName::Inner,
|
||||
"width" => TypeName::Width,
|
||||
"height" => TypeName::Height,
|
||||
"templatestring" => TypeName::TemplateString,
|
||||
"color" => TypeName::Color,
|
||||
"bool" => TypeName::Bool,
|
||||
"none" => TypeName::None,
|
||||
_ => panic!(
|
||||
"Invalid type `{}` specified in the attribute type `{}` when parsing XML layout",
|
||||
individual_type, attribute_declaration
|
||||
),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<TypeName>>()
|
||||
})
|
||||
.collect::<Vec<Vec<TypeName>>>();
|
||||
|
||||
// Required default value for the variable parameter if not provided
|
||||
let default_type_sequence = default_value.split(",").map(|individual_type|
|
||||
match self.parse_attribute_type(individual_type) {
|
||||
let default_type_sequence = default_value
|
||||
.split(",")
|
||||
.map(|individual_type| match self.parse_attribute_type(individual_type) {
|
||||
TypeValueOrArgument::TypeValue(type_value) => type_value,
|
||||
TypeValueOrArgument::VariableArgument(variable_value) => {
|
||||
panic!("Found the default variable value `{:?}` in the attribute declaration `{}` which only allows typed values, when parsing XML layout", variable_value, attribute_declaration);
|
||||
panic!(
|
||||
"Found the default variable value `{:?}` in the attribute declaration `{}` which only allows typed values, when parsing XML layout",
|
||||
variable_value, attribute_declaration
|
||||
);
|
||||
},
|
||||
}
|
||||
).collect::<Vec<TypeValue>>();
|
||||
})
|
||||
.collect::<Vec<TypeValue>>();
|
||||
|
||||
// Return the parameter
|
||||
AttributeValue::VariableParameter(VariableParameter::new(name, type_sequence_options, default_type_sequence))
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// pub struct LayoutDomNode {
|
||||
// pub namespace: String,
|
||||
// pub name: String,
|
||||
// pub placement:
|
||||
// pub placement:
|
||||
// // pub body: Vec<LayoutDomNode>
|
||||
// }
|
||||
|
||||
// pub struct LayoutPlacement {
|
||||
// pub width: f32,
|
||||
// pub height: f32,
|
||||
// pub x_align:
|
||||
// }
|
||||
// pub x_align:
|
||||
// }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::collections::HashSet;
|
||||
use crate::layout_abstract_syntax::*;
|
||||
use crate::layout_attribute_parser::*;
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
|
||||
pub struct LayoutSystem {
|
||||
// pub dom_tree: rctree::Node<
|
||||
@@ -38,7 +38,7 @@ impl LayoutSystem {
|
||||
|
||||
fn explore_referenced_layouts(&mut self, layout_tree_root: &rctree::Node<LayoutAbstractNode>, already_loaded_layouts: &mut HashSet<String>) {
|
||||
for child_tag in layout_tree_root.descendants() {
|
||||
match & *child_tag.borrow() {
|
||||
match &*child_tag.borrow() {
|
||||
// Tags are references to other XML layouts that should be loaded and cached
|
||||
LayoutAbstractNode::Tag(layout_abstract_tag) => {
|
||||
// Cache key in form namespace:name
|
||||
@@ -56,7 +56,7 @@ impl LayoutSystem {
|
||||
// Keep track of it being loaded to prevent duplicate work
|
||||
let key_copy = key.clone();
|
||||
already_loaded_layouts.insert(key);
|
||||
|
||||
|
||||
// Recursively explore the newly loaded layout's tags
|
||||
self.explore_referenced_layouts(&new_loaded_layout, already_loaded_layouts);
|
||||
|
||||
@@ -107,7 +107,7 @@ impl LayoutSystem {
|
||||
let mut current_opening_tag: Option<LayoutAbstractNode> = None;
|
||||
// Top-level node that is popped from the stack when the closing tag is reached at the end of the XML document
|
||||
let mut final_result: Option<rctree::Node<LayoutAbstractNode>> = None;
|
||||
|
||||
|
||||
for token in parser {
|
||||
match token.unwrap() {
|
||||
// Beginning of an opening tag (<NAMESPACE:NAME ...)
|
||||
@@ -133,7 +133,8 @@ impl LayoutSystem {
|
||||
string.push(':');
|
||||
string.push_str(slice);
|
||||
string
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
String::from(local.as_str())
|
||||
};
|
||||
// Set the value to an ordinary string slice of the given value
|
||||
@@ -212,11 +213,13 @@ impl LayoutSystem {
|
||||
xmlparser::Token::Text { text } => {
|
||||
// Trim any whitespace from around the string
|
||||
let text_string = String::from(text.as_str().trim());
|
||||
|
||||
|
||||
// If the string isn't all whitespace, append a new text node to the parent
|
||||
if !text_string.is_empty() {
|
||||
// Get the tree node which contains this text
|
||||
let parent_node = stack.last_mut().expect(&format!("Encountered text outside the root tag when parsing XML layout in file: {}", path)[..]);
|
||||
let parent_node = stack
|
||||
.last_mut()
|
||||
.expect(&format!("Encountered text outside the root tag when parsing XML layout in file: {}", path)[..]);
|
||||
|
||||
// Construct an AST text node with the provided text
|
||||
let abstract_text_node = LayoutAbstractNode::new_text(text_string);
|
||||
@@ -227,10 +230,10 @@ impl LayoutSystem {
|
||||
parent_node.append(new_tree_node);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
match final_result {
|
||||
None => panic!("Invalid syntax when parsing XML layout in file: {}", path),
|
||||
Some(tree) => Ok(tree),
|
||||
@@ -242,4 +245,4 @@ impl LayoutSystem {
|
||||
println!("{:?}", node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
src/main.rs
16
src/main.rs
@@ -1,19 +1,19 @@
|
||||
mod application;
|
||||
mod pipeline;
|
||||
mod texture;
|
||||
mod color;
|
||||
mod color_palette;
|
||||
mod resource_cache;
|
||||
mod shader_stage;
|
||||
mod draw_command;
|
||||
mod gui_node;
|
||||
mod gui_attributes;
|
||||
mod window_events;
|
||||
mod layout_system;
|
||||
mod layout_abstract_types;
|
||||
mod gui_node;
|
||||
mod layout_abstract_syntax;
|
||||
mod layout_abstract_types;
|
||||
mod layout_attribute_parser;
|
||||
mod layout_dom_node;
|
||||
mod layout_system;
|
||||
mod pipeline;
|
||||
mod resource_cache;
|
||||
mod shader_stage;
|
||||
mod texture;
|
||||
mod window_events;
|
||||
|
||||
use application::Application;
|
||||
use winit::event_loop::EventLoop;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::mem;
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use crate::shader_stage;
|
||||
use std::mem;
|
||||
|
||||
pub struct Pipeline {
|
||||
pub bind_group_layout: wgpu::BindGroupLayout,
|
||||
@@ -8,25 +8,34 @@ pub struct Pipeline {
|
||||
}
|
||||
|
||||
impl Pipeline {
|
||||
pub fn new(device: &wgpu::Device, swap_chain_color_format: wgpu::TextureFormat, extra_layouts: Vec<&wgpu::BindGroupLayout>, shader_cache: &mut ResourceCache<wgpu::ShaderModule>, shader_pair_path: (&str, &str)) -> Self {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
swap_chain_color_format: wgpu::TextureFormat,
|
||||
extra_layouts: Vec<&wgpu::BindGroupLayout>,
|
||||
shader_cache: &mut ResourceCache<wgpu::ShaderModule>,
|
||||
shader_pair_path: (&str, &str),
|
||||
) -> Self {
|
||||
// Load the vertex and fragment shaders
|
||||
let shader_pair = Pipeline::get_shader_pair(device, shader_cache, shader_pair_path);
|
||||
|
||||
// Prepare a bind group layout for the GUI element's texture and form factor data
|
||||
let bind_group_layout = Pipeline::build_bind_group_layout(device, &vec![
|
||||
wgpu::BindingType::UniformBuffer { dynamic: false },
|
||||
wgpu::BindingType::SampledTexture {
|
||||
dimension: wgpu::TextureViewDimension::D2,
|
||||
component_type: wgpu::TextureComponentType::Float,
|
||||
multisampled: false,
|
||||
},
|
||||
wgpu::BindingType::Sampler { comparison: false },
|
||||
]);
|
||||
|
||||
let bind_group_layout = Pipeline::build_bind_group_layout(
|
||||
device,
|
||||
&vec![
|
||||
wgpu::BindingType::UniformBuffer { dynamic: false },
|
||||
wgpu::BindingType::SampledTexture {
|
||||
dimension: wgpu::TextureViewDimension::D2,
|
||||
component_type: wgpu::TextureComponentType::Float,
|
||||
multisampled: false,
|
||||
},
|
||||
wgpu::BindingType::Sampler { comparison: false },
|
||||
],
|
||||
);
|
||||
|
||||
// Combine all bind group layouts
|
||||
let mut bind_group_layouts = vec![&bind_group_layout];
|
||||
bind_group_layouts.append(&mut extra_layouts.clone());
|
||||
|
||||
|
||||
// Construct the pipeline
|
||||
let render_pipeline = Pipeline::build_pipeline(device, swap_chain_color_format, bind_group_layouts, shader_pair);
|
||||
Self {
|
||||
@@ -35,7 +44,11 @@ impl Pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_shader_pair<'a>(device: &wgpu::Device, shader_cache: &'a mut ResourceCache<wgpu::ShaderModule>, shader_pair_path: (&str, &str)) -> (&'a wgpu::ShaderModule, &'a wgpu::ShaderModule) {
|
||||
pub fn get_shader_pair<'a>(
|
||||
device: &wgpu::Device,
|
||||
shader_cache: &'a mut ResourceCache<wgpu::ShaderModule>,
|
||||
shader_pair_path: (&str, &str),
|
||||
) -> (&'a wgpu::ShaderModule, &'a wgpu::ShaderModule) {
|
||||
// If uncached, construct a vertex shader loaded from its source code file
|
||||
if shader_cache.get(shader_pair_path.0).is_none() {
|
||||
let vertex_shader_module = shader_stage::compile_from_glsl(device, shader_pair_path.0, glsl_to_spirv::ShaderType::Vertex).unwrap();
|
||||
@@ -56,28 +69,31 @@ impl Pipeline {
|
||||
}
|
||||
|
||||
pub fn build_bind_group_layouts(device: &wgpu::Device, bind_group_layouts: &Vec<Vec<wgpu::BindingType>>) -> Vec<wgpu::BindGroupLayout> {
|
||||
bind_group_layouts.into_iter().map(|layout_entry| Self::build_bind_group_layout(device, layout_entry)).collect::<Vec<_>>()
|
||||
bind_group_layouts
|
||||
.into_iter()
|
||||
.map(|layout_entry| Self::build_bind_group_layout(device, layout_entry))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn build_bind_group_layout(device: &wgpu::Device, bind_group_layout: &Vec<wgpu::BindingType>) -> wgpu::BindGroupLayout {
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: None,
|
||||
bindings: bind_group_layout.into_iter().enumerate().map(|(index, binding_type)|
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
bindings: bind_group_layout
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, binding_type)| wgpu::BindGroupLayoutEntry {
|
||||
binding: index as u32,
|
||||
visibility: wgpu::ShaderStage::all(),
|
||||
ty: binding_type.clone(),
|
||||
}
|
||||
).collect::<Vec<_>>().as_slice(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn build_binding_staging_buffer<T: bytemuck::Pod>(device: &wgpu::Device, resource: &T) -> wgpu::Buffer {
|
||||
// Construct a staging buffer with the binary uniform struct data
|
||||
device.create_buffer_with_data(
|
||||
bytemuck::cast_slice(&[*resource]),
|
||||
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
|
||||
)
|
||||
device.create_buffer_with_data(bytemuck::cast_slice(&[*resource]), wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST)
|
||||
}
|
||||
|
||||
pub fn build_binding_resource(resource_buffer: &wgpu::Buffer) -> wgpu::BindingResource {
|
||||
@@ -89,12 +105,14 @@ impl Pipeline {
|
||||
}
|
||||
|
||||
pub fn build_bind_group(device: &wgpu::Device, bind_group_layout: &wgpu::BindGroupLayout, binding_resources: Vec<wgpu::BindingResource>) -> wgpu::BindGroup {
|
||||
let bindings = binding_resources.into_iter().enumerate().map(|(index, binding_resource)|
|
||||
wgpu::Binding {
|
||||
let bindings = binding_resources
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, binding_resource)| wgpu::Binding {
|
||||
binding: index as u32,
|
||||
resource: binding_resource,
|
||||
}
|
||||
).collect::<Vec<_>>();
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: bind_group_layout,
|
||||
@@ -103,11 +121,16 @@ impl Pipeline {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn build_pipeline(device: &wgpu::Device, swap_chain_color_format: wgpu::TextureFormat, bind_group_layouts: Vec<&wgpu::BindGroupLayout>, shader_pair: (&wgpu::ShaderModule, &wgpu::ShaderModule)) -> wgpu::RenderPipeline {
|
||||
pub fn build_pipeline(
|
||||
device: &wgpu::Device,
|
||||
swap_chain_color_format: wgpu::TextureFormat,
|
||||
bind_group_layouts: Vec<&wgpu::BindGroupLayout>,
|
||||
shader_pair: (&wgpu::ShaderModule, &wgpu::ShaderModule),
|
||||
) -> wgpu::RenderPipeline {
|
||||
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: bind_group_layouts.as_slice(),
|
||||
});
|
||||
|
||||
|
||||
let (vertex_shader, fragment_shader) = shader_pair;
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
layout: &render_pipeline_layout,
|
||||
|
||||
@@ -21,10 +21,7 @@ impl<T> ResourceCache<T> {
|
||||
let resources = Vec::new();
|
||||
let name_to_id = HashMap::new();
|
||||
|
||||
Self {
|
||||
resources,
|
||||
name_to_id,
|
||||
}
|
||||
Self { resources, name_to_id }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -49,4 +46,4 @@ impl<T> ResourceCache<T> {
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@ pub fn compile_from_glsl(device: &wgpu::Device, path: &str, shader_type: glsl_to
|
||||
let shader = device.create_shader_module(&compiled);
|
||||
|
||||
Ok(shader)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::fs;
|
||||
use image::GenericImageView;
|
||||
use crate::resource_cache::ResourceCache;
|
||||
use image::GenericImageView;
|
||||
use std::fs;
|
||||
|
||||
pub struct Texture {
|
||||
pub texture: wgpu::Texture,
|
||||
@@ -21,11 +21,11 @@ impl Texture {
|
||||
pub fn from_filepath(device: &wgpu::Device, queue: &mut wgpu::Queue, path: &str) -> Result<Self, failure::Error> {
|
||||
// Read the raw bytes from the specified file
|
||||
let bytes = fs::read(path)?;
|
||||
|
||||
|
||||
// Construct and return a Texture from the bytes
|
||||
Texture::from_bytes(device, queue, &bytes[..])
|
||||
}
|
||||
|
||||
|
||||
pub fn from_bytes(device: &wgpu::Device, queue: &mut wgpu::Queue, bytes: &[u8]) -> Result<Self, failure::Error> {
|
||||
// Create an image with the Image library
|
||||
let image = image::load_from_memory(bytes)?;
|
||||
@@ -67,7 +67,7 @@ impl Texture {
|
||||
offset: 0,
|
||||
bytes_per_row: 4 * dimensions.0,
|
||||
rows_per_image: dimensions.1,
|
||||
},
|
||||
},
|
||||
wgpu::TextureCopyView {
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
@@ -96,7 +96,11 @@ impl Texture {
|
||||
lod_max_clamp: 100.0,
|
||||
compare: wgpu::CompareFunction::Always,
|
||||
});
|
||||
|
||||
Ok(Self { texture, texture_view: view, sampler })
|
||||
|
||||
Ok(Self {
|
||||
texture,
|
||||
texture_view: view,
|
||||
sampler,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,16 @@ pub fn window_event(application: &mut Application, control_flow: &mut ControlFlo
|
||||
|
||||
fn keyboard_event(application: &mut Application, control_flow: &mut ControlFlow, input: &KeyboardInput) {
|
||||
match input {
|
||||
KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. } => quit(control_flow),
|
||||
KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Space), .. } => {
|
||||
KeyboardInput {
|
||||
state: ElementState::Pressed,
|
||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||
..
|
||||
} => quit(control_flow),
|
||||
KeyboardInput {
|
||||
state: ElementState::Pressed,
|
||||
virtual_keycode: Some(VirtualKeyCode::Space),
|
||||
..
|
||||
} => {
|
||||
// const VERTICES: &[[f32; 2]] = &[
|
||||
// [-0.2, 0.0],
|
||||
// [0.2, 0.0],
|
||||
|
||||
Reference in New Issue
Block a user