Got texture to display on quad

+ implemented Texture
* tweaked Application API
! some work need on Texture API to mask Rc<RefCell>>
This commit is contained in:
Steins7 2022-07-15 11:59:52 +02:00
parent 7c01dfab75
commit 79b86afc2a
10 changed files with 620 additions and 109 deletions

165
Cargo.lock generated
View File

@ -2,6 +2,18 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ahash"
version = "0.7.6"
@ -141,6 +153,7 @@ dependencies = [
"cgmath",
"chrono",
"fern",
"image",
"log",
"pollster",
"raw-window-handle",
@ -236,6 +249,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "colored"
version = "1.9.3"
@ -335,6 +354,15 @@ dependencies = [
"objc",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "cty"
version = "0.2.2"
@ -387,6 +415,15 @@ dependencies = [
"syn",
]
[[package]]
name = "deflate"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f"
dependencies = [
"adler32",
]
[[package]]
name = "dispatch"
version = "0.2.0"
@ -521,9 +558,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022"
[[package]]
name = "hermit-abi"
@ -546,6 +583,22 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "image"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28edd9d7bc256be2502e325ac0628bde30b7001b9b52e0abe31a1a9dc2701212"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"jpeg-decoder",
"num-iter",
"num-rational",
"num-traits",
"png",
]
[[package]]
name = "indexmap"
version = "1.9.1"
@ -553,7 +606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
"hashbrown 0.12.1",
"hashbrown 0.12.2",
]
[[package]]
@ -580,6 +633,12 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jpeg-decoder"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b"
[[package]]
name = "js-sys"
version = "0.3.58"
@ -694,6 +753,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.4"
@ -812,6 +880,28 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
@ -863,9 +953,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.12.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "parking_lot"
@ -875,7 +965,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
"parking_lot_core 0.8.5",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.3",
]
[[package]]
@ -892,6 +992,19 @@ dependencies = [
"winapi",
]
[[package]]
name = "parking_lot_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
@ -904,6 +1017,18 @@ version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "png"
version = "0.17.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba"
dependencies = [
"bitflags",
"crc32fast",
"deflate",
"miniz_oxide",
]
[[package]]
name = "pollster"
version = "0.2.5"
@ -994,9 +1119,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.137"
version = "1.0.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6"
[[package]]
name = "slotmap"
@ -1009,9 +1134,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.8.1"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]]
name = "smithay-client-toolkit"
@ -1295,15 +1420,15 @@ dependencies = [
[[package]]
name = "wgpu"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd28e7c69ffd19c02e609322e4170738ac3340e699d8adfa16f5745625e4aa8c"
checksum = "277e967bf8b7820a76852645a6bce8bbd31c32fda2042e82d8e3ea75fda8892d"
dependencies = [
"arrayvec",
"js-sys",
"log",
"naga",
"parking_lot",
"parking_lot 0.12.1",
"raw-window-handle",
"smallvec",
"wasm-bindgen",
@ -1316,9 +1441,9 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb155661d02bf104303589fbf9206fa971c80dbb6d4763e66879253bd0a072c"
checksum = "266ca6be6004fd1b2a768023b1cb0afbf7af0cbffaba19af25c5792d44e74784"
dependencies = [
"arrayvec",
"bit-vec",
@ -1329,7 +1454,7 @@ dependencies = [
"fxhash",
"log",
"naga",
"parking_lot",
"parking_lot 0.12.1",
"profiling",
"raw-window-handle",
"smallvec",
@ -1341,9 +1466,9 @@ dependencies = [
[[package]]
name = "wgpu-hal"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9f9cb367209e2ad214afa8d823348334994dc1579f4a521d53a3bc4d0848e73"
checksum = "bef50e48812c7eb958fa52d28a912f8b77c96453ebab21c72b01cdda61d3e65d"
dependencies = [
"android_system_properties",
"arrayvec",
@ -1366,7 +1491,7 @@ dependencies = [
"metal",
"naga",
"objc",
"parking_lot",
"parking_lot 0.12.1",
"profiling",
"range-alloc",
"raw-window-handle",
@ -1482,7 +1607,7 @@ dependencies = [
"ndk-glue",
"ndk-sys",
"objc",
"parking_lot",
"parking_lot 0.11.2",
"percent-encoding",
"raw-window-handle",
"smithay-client-toolkit",

View File

@ -22,3 +22,8 @@ raw-window-handle = "^0.4.3"
wgpu = "^0.13.0"
bytemuck = { version = "1.4", features = [ "derive" ] }
[dependencies.image]
version = "^0.24.2"
default-features = false
features = ["png", "jpeg"]

BIN
assets/camel.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -17,11 +17,11 @@ use std::{
};
//--Application trait-------------------------------------------------------------------------------
pub trait Application {
pub trait Application<S> {
fn init(&mut self, canvas: &mut Canvas) -> Result<(), &'static str>;
fn init(canvas: &mut Canvas) -> Result<S, &'static str>;
fn tick(&mut self, canvas: &mut Canvas) -> Result<(), &'static str>;
fn tick(state: &mut S, canvas: &mut Canvas) -> Result<(), &'static str>;
}
//--Canvas struct-----------------------------------------------------------------------------------
@ -35,7 +35,8 @@ impl Canvas {
pub async fn create<W: HasRawWindowHandle>(window: &W, size: Size)
-> Result<Canvas, &'static str>
{
let renderer = WgpuRenderer::create(window, size).await?;
let mut renderer = WgpuRenderer::create(window, size).await?;
renderer.clear(Color::WHITE);
Ok(Self {
renderer,
@ -63,18 +64,54 @@ impl Canvas {
}
pub fn create_texture_from_file(&mut self,
_pos: Position,
_file: &'static str,
file: &'static str,
_offset: Option<Position>,
_size: Option<Size>,
_background: Option<Pixel>)
-> Result<Rc<RefCell<Texture>>, &'static str>
{
use image::{
io::Reader,
GenericImageView,
};
let img = Reader::open(file)
.map_err(|_| "Failed to open file")?
.decode()
.map_err(|_| "Failed to decode picture")?;
let rgba = img.to_rgba8();
let img_size = {
let dimensions = img.dimensions();
Size {
w: dimensions.0,
h: dimensions.1,
}
};
Ok(Rc::new(RefCell::new(
self.renderer.create_texture(&rgba, img_size)
)))
}
pub fn create_texture_from_bytes(&mut self,
_buf: &[u8],
_offset: Option<Position>,
_size: Option<Size>,
_background: Option<Pixel>)
-> Rc<RefCell<Texture>>
{
unimplemented!();
todo!()
// Rc::new(RefCell::new(
// self.renderer.create_texture_from_bytes(pos, buf, background).unwrap()
// ))
}
//--Output functions--
pub fn draw<S: Sprite>(&mut self, sprite: &S) {
// pub fn draw<S: Sprite>(&mut self, sprite: &S) {
pub fn draw(&mut self, texture: &Texture) {
//update texture
self.renderer.render(sprite);
self.renderer.render(texture);
}
pub fn set_clear_color(&mut self, color: Pixel) {
@ -86,7 +123,7 @@ impl Canvas {
}
pub fn clear(&mut self) {
todo!();
self.renderer.clear(self.clear_color);
}
//--Input functions--

View File

@ -15,7 +15,7 @@ mod renderer;
use utils::Size;
pub fn run_canvas<A: 'static + Application>(title: &'static str, size: Size, mut app: A) -> ! {
pub fn run_canvas<S: 'static + Sized, A: 'static + Application<S>>(title: &'static str, size: Size, mut app: A) -> ! {
use winit::{
event_loop::EventLoop,
window::WindowBuilder,
@ -35,7 +35,7 @@ pub fn run_canvas<A: 'static + Application>(title: &'static str, size: Size, mut
let mut canvas = Canvas::create(&window, size.into()).block_on().unwrap();
// init application
app.init(&mut canvas).unwrap();
let mut state = A::init(&mut canvas).unwrap();
canvas.update();
window.set_visible(true);
@ -66,9 +66,10 @@ pub fn run_canvas<A: 'static + Application>(title: &'static str, size: Size, mut
},
Event::MainEventsCleared => {
let _ = app.tick(&mut canvas);
},
let _ = A::tick(&mut state, &mut canvas);
},
Event::RedrawRequested(_) => {
canvas.clear();
let _ = canvas.update();
},

View File

@ -1,4 +1,13 @@
use canvas::{Application, Canvas};
use canvas::{
Application,
Canvas,
texture::Texture,
};
use std::{
rc::Rc,
cell::RefCell,
};
fn setup_logger() -> Result<(), fern::InitError> {
use fern::colors::{Color, ColoredLevelConfig};
@ -26,15 +35,28 @@ fn setup_logger() -> Result<(), fern::InitError> {
Ok(())
}
struct ExampleState {
pub texture: Rc<RefCell<Texture>>,
}
struct ExampleApp {}
impl Application for ExampleApp {
impl Application<ExampleState> for ExampleApp {
fn init(&mut self, _canvas: &mut Canvas) -> Result<(), &'static str> {
Ok(())
fn init(canvas: &mut Canvas) -> Result<ExampleState, &'static str> {
let texture = canvas.create_texture_from_file("assets/camel.jpg", None, None, None)
.unwrap();
canvas.clear();
canvas.update();
Ok(ExampleState {
texture,
})
}
fn tick(&mut self, canvas: &mut Canvas) -> Result<(), &'static str> {
fn tick(state: &mut ExampleState, canvas: &mut Canvas) -> Result<(), &'static str> {
use canvas::{
io::Key,
sprite::Sprite,
@ -103,7 +125,7 @@ impl Application for ExampleApp {
//txt_sprite.set_alpha(255);
//txt_sprite.set_scale(0.5);
//canvas.draw(&txt_sprite);
canvas.draw(&state.texture.borrow());
canvas.update();
Ok(())

View File

@ -6,9 +6,12 @@ use wgpu;
use crate::{
sprite::Sprite,
utils::Size,
texture::Texture,
utils::{Pixel, Position, Size},
};
use std::marker::PhantomData;
//--Renderer struct---------------------------------------------------------------------------------
pub struct WgpuRenderer {
surface: wgpu::Surface,
@ -16,8 +19,12 @@ pub struct WgpuRenderer {
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
size: Size,
render_pipeline: wgpu::RenderPipeline,
quad_mesh: GpuMesh,
texture_bind_group_layout: wgpu::BindGroupLayout,
texture_render_pipeline: wgpu::RenderPipeline,
shape_render_pipeline: wgpu::RenderPipeline,
texture_quad: GpuMesh<TextureVertex>,
quad_mesh: GpuMesh<ColorVertex>, //TODO temporary, to be moved to shapes.rs
output: Option<wgpu::SurfaceTexture>,
}
impl WgpuRenderer {
@ -61,27 +68,52 @@ impl WgpuRenderer {
};
surface.configure(&device, &config);
let render_pipeline = {
let texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
// This should match the filterable field of the
// corresponding Texture entry above.
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
label: Some("texture_bind_group_layout"),
});
let texture_render_pipeline = {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("shape shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shape.wgsl").into()),
label: Some("texture shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/texture.wgsl").into()),
});
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("shape render pipeline layout"),
bind_group_layouts: &[],
label: Some("texture render pipeline layout"),
bind_group_layouts: &[&texture_bind_group_layout],
push_constant_ranges: &[],
});
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("shape render pipeline"),
label: Some("texture render pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[
Vertex::desc(),
TextureVertex::desc(),
],
},
fragment: Some(wgpu::FragmentState {
@ -117,43 +149,99 @@ impl WgpuRenderer {
})
};
let shape_render_pipeline = {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("shape shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/shape.wgsl").into()),
});
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("shape render pipeline layout"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("shape render pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[
ColorVertex::desc(),
],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
// Setting this to anything other than Fill requires
// Features::NON_FILL_POLYGON_MODE
polygon_mode: wgpu::PolygonMode::Fill,
// Requires Features::DEPTH_CLIP_CONTROL
unclipped_depth: false,
// Requires Features::CONSERVATIVE_RASTERIZATION
conservative: false,
},
depth_stencil: None,
// multisampling, we don't need it
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
})
};
let texture_quad = GpuMesh::create(&device, &TEXTURE_QUAD);
let quad_mesh = GpuMesh::create(&device, &QUAD);
let output = Some(surface.get_current_texture()
.map_err(|_| "Failed to create SurfaceTexture")?);
Ok(Self {
surface,
device,
queue,
config,
size,
render_pipeline,
texture_bind_group_layout,
texture_render_pipeline,
shape_render_pipeline,
texture_quad,
quad_mesh,
output,
})
}
pub fn render<S: Sprite>(&mut self, _sprite: &S) {
unimplemented!();
pub fn create_texture(&mut self, buf: &[u8], size: Size)
-> Texture
{
Texture::create(&self.device, &self.queue, &self.texture_bind_group_layout, buf, size)
}
pub fn resize(&mut self, size: Size) {
if size.w == 0 || size.h == 0 {
panic!("window has zero as at least one of its dimensions");
}
self.size = size;
self.config.width = size.w;
self.config.height = size.h;
self.surface.configure(&self.device, &self.config);
}
// pub fn render<S: Sprite>(&mut self, _sprite: &S) {
pub fn render(&mut self, texture: &Texture) {
pub fn present(&mut self) {
let output = self.surface.get_current_texture()
.map_err(|err| match err {
wgpu::SurfaceError::Lost => {
warn!("Lost surface, trying resizing");
self.resize(self.size);
self.surface.get_current_texture()
},
_ => Err(err)
}).unwrap();
let output = match &self.output {
Some(out) => out,
None => {
self.create_output();
&self.output.as_ref().unwrap()
},
};
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
@ -167,39 +255,102 @@ impl WgpuRenderer {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.1,
g: 0.2,
b: 0.3,
a: 1.0,
}),
load: wgpu::LoadOp::Load,
store: true,
},
})],
depth_stencil_attachment: None,
});
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_vertex_buffer(0, self.quad_mesh.vertex_buffer.slice(..));
render_pass.set_index_buffer(self.quad_mesh.index_buffer.slice(..),
render_pass.set_pipeline(&self.texture_render_pipeline);
render_pass.set_vertex_buffer(0, self.texture_quad.vertex_buffer.slice(..));
render_pass.set_index_buffer(self.texture_quad.index_buffer.slice(..),
wgpu::IndexFormat::Uint16);
render_pass.draw_indexed(0..self.quad_mesh.index_number, 0, 0..1);
render_pass.set_bind_group(0, texture.bind_group(), &[]);
render_pass.draw_indexed(0..self.texture_quad.index_number, 0, 0..1);
}
self.queue.submit(std::iter::once(encoder.finish()));
output.present();
}
pub fn clear(&mut self, color: Pixel) {
let output = match &self.output {
Some(out) => out,
None => {
self.create_output();
&self.output.as_ref().unwrap()
},
};
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Clear Encoder"),
});
{
let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Clear Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(color.into()),
store: true,
},
})],
depth_stencil_attachment: None,
});
}
self.queue.submit(std::iter::once(encoder.finish()));
}
pub fn resize(&mut self, size: Size) {
if size.w == 0 || size.h == 0 {
panic!("window has zero as at least one of its dimensions");
}
self.size = size;
self.config.width = size.w;
self.config.height = size.h;
self.surface.configure(&self.device, &self.config);
}
pub fn present(&mut self) {
match self.output.take() {
Some(out) => out.present(),
None => {
}//nothing to do
}
}
fn create_output(&mut self) {
self.output = Some(
self.surface.get_current_texture()
.map_err(|err| match err {
wgpu::SurfaceError::Lost => {
warn!("Lost surface, trying resizing");
self.resize(self.size);
self.surface.get_current_texture()
},
_ => Err(err)
}).unwrap()
);
}
}
struct GpuMesh {
struct GpuMesh<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer,
index_number: u32,
phantom: PhantomData<V>, //keep track of wich type of vertex is used
}
impl GpuMesh {
impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
pub fn create(device: &wgpu::Device, mesh: &Mesh) -> Self {
fn create(device: &wgpu::Device, mesh: &Mesh<V>) -> Self {
use wgpu::util::DeviceExt;
let vertex_buffer = device.create_buffer_init(
@ -222,6 +373,7 @@ impl GpuMesh {
vertex_buffer,
index_buffer,
index_number: mesh.indices.len() as u32,
phantom: PhantomData,
}
}
}
@ -229,40 +381,87 @@ impl GpuMesh {
//--Renderer struct utils---------------------------------------------------------------------------
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct Vertex {
struct TextureVertex {
pub position: [f32; 2],
pub color: [f32; 3],
pub tex_coords: [f32; 2],
}
// lib.rs
impl Vertex {
impl TextureVertex {
const ATTRIBS: [wgpu::VertexAttribute; 2] =
wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x3];
wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2];
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
array_stride: std::mem::size_of::<TextureVertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &Self::ATTRIBS,
}
}
}
struct Mesh<'a> {
pub vertices: &'a[Vertex],
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct ColorVertex {
pub position: [f32; 2],
pub color: [f32; 3],
}
impl ColorVertex {
const ATTRIBS: [wgpu::VertexAttribute; 2] =
wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x3];
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<ColorVertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &Self::ATTRIBS,
}
}
}
struct Mesh<'a, V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
pub vertices: &'a[V],
pub indices: &'a[u16],
}
const QUAD: Mesh<'static> = Mesh {
const TEXTURE_QUAD: Mesh<'static, TextureVertex> = Mesh {
vertices: &[
Vertex { position: [0.0, 0.0], color: [1.0, 0.0, 0.0] },
Vertex { position: [1.0, 0.0], color: [0.0, 1.0, 0.0] },
Vertex { position: [1.0, 1.0], color: [0.0, 0.0, 1.0] },
Vertex { position: [0.0, 1.0], color: [0.5, 0.5, 0.5] },
TextureVertex { position: [0.0, 0.0], tex_coords: [0.0, 1.0] },
TextureVertex { position: [1.0, 0.0], tex_coords: [1.0, 1.0] },
TextureVertex { position: [1.0, 1.0], tex_coords: [1.0, 0.0] },
TextureVertex { position: [0.0, 1.0], tex_coords: [0.0, 0.0] },
],
indices: &[
0, 1, 2,
0, 2, 3,
],
};
const QUAD: Mesh<'static, ColorVertex> = Mesh {
vertices: &[
ColorVertex { position: [0.0, 0.0], color: [1.0, 0.0, 0.0] },
ColorVertex { position: [1.0, 0.0], color: [0.0, 1.0, 0.0] },
ColorVertex { position: [1.0, 1.0], color: [0.0, 0.0, 1.0] },
ColorVertex { position: [0.0, 1.0], color: [0.5, 0.5, 0.5] },
],
indices: &[
0, 1, 2,
0, 2, 3,
],
};
impl From<Pixel> for wgpu::Color {
fn from(pix: Pixel) -> Self {
let rgba = pix.to_rgba();
Self {
r: (rgba.r as f64) / 255.0,
g: (rgba.g as f64) / 255.0,
b: (rgba.b as f64) / 255.0,
a: (rgba.a as f64) / 255.0,
}
}
}

33
src/shaders/texture.wgsl Normal file
View File

@ -0,0 +1,33 @@
// Vertex shader
struct VertexInput {
@location(0) position: vec2<f32>,
@location(1) tex_coords: vec2<f32>,
}
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) tex_coords: vec2<f32>,
}
@vertex
fn vs_main(model: VertexInput) -> VertexOutput {
var out: VertexOutput;
out.tex_coords = model.tex_coords;
out.clip_position = vec4<f32>(model.position, 0.0, 1.0);
return out;
}
// Fragment shader
@group(0) @binding(0)
var t_diffuse: texture_2d<f32>;
@group(0)@binding(1)
var s_diffuse: sampler;
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
}

View File

@ -1,15 +1,91 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use crate::utils::{Pixel, Position};
use crate::utils::{Pixel, Position, Size};
use std::slice::{Iter, IterMut};
//--Texture struct----------------------------------------------------------------------------------
pub struct Texture {}
pub struct Texture {
texture: wgpu::Texture,
bind_group: wgpu::BindGroup,
}
impl Texture {
pub fn create(device: &wgpu::Device,
queue: &wgpu::Queue,
layout: &wgpu::BindGroupLayout,
buf: &[u8],
buf_size: Size)
-> Self
{
let size = wgpu::Extent3d {
width: buf_size.w,
height: buf_size.h,
depth_or_array_layers: 1,
};
let texture = device.create_texture(
&wgpu::TextureDescriptor {
label: None,
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
}
);
queue.write_texture(
wgpu::ImageCopyTexture {
aspect: wgpu::TextureAspect::All,
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
},
&buf,
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: std::num::NonZeroU32::new(4 * buf_size.w),
rows_per_image: std::num::NonZeroU32::new(buf_size.h),
},
size,
);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(
&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
}
);
let bind_group = device.create_bind_group(
&wgpu::BindGroupDescriptor {
layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&sampler),
}
],
label: Some("diffuse_bind_group"),
}
);
Self { texture, bind_group }
}
pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) {
unimplemented!();
}
@ -21,5 +97,9 @@ impl Texture {
pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> {
unimplemented!();
}
pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.bind_group
}
}

View File

@ -39,13 +39,14 @@ impl From<winit::dpi::PhysicalSize<u32>> for Size {
//--Pixel struct------------------------------------------------------------------------------------
#[derive(Copy, Clone)]
struct Rgba {
r: u8,
g: u8,
b: u8,
a: u8,
pub struct Rgba {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
#[derive(Copy, Clone)]
pub union Pixel {
flat: u32,
rgba: Rgba,
@ -58,6 +59,10 @@ impl Pixel {
rgba: Rgba{r, g, b, a: 255},
}
}
pub fn to_rgba(&self) -> Rgba {
unsafe { self.rgba }
}
}
//--Color values------------------------------------------------------------------------------------
@ -65,8 +70,12 @@ impl Pixel {
pub struct Color;
impl Color {
pub const WHITE: Pixel = Pixel {flat: 0x000000ff};
pub const BLACK: Pixel = Pixel {flat: 0xffffffff};
pub const NONE: Pixel = Pixel {flat: 0x00000000};
pub const WHITE: Pixel = Pixel {flat: 0xffffffff};
pub const BLACK: Pixel = Pixel {flat: 0x000000ff};
pub const RED: Pixel = Pixel {flat: 0xff0000ff};
pub const GREEN: Pixel = Pixel {flat: 0x00ff00ff};
pub const BLUE: Pixel = Pixel {flat: 0x0000ffff};
}