Implemented more of TextureSprite

+ added texture modification functions
+ added texture offset support
This commit is contained in:
Steins7 2022-08-18 22:07:33 +02:00
parent 3a7799bc76
commit 330a93fac8
7 changed files with 224 additions and 78 deletions

View File

@ -69,8 +69,8 @@ impl Canvas {
} }
//--Create functions-- //--Create functions--
pub fn create_texture_sprite(&mut self, _size: Size) -> TextureSprite { pub fn create_texture_sprite(&mut self, size: Size) -> TextureSprite {
TextureSprite::create(self.default_texture.clone()) TextureSprite::create(self.default_texture.clone(), size)
} }
pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite { pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite {

View File

@ -15,7 +15,10 @@ mod renderer;
use utils::Size; use utils::Size;
pub fn run_canvas<S: 'static + Sized, A: 'static + Application<S>>(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::{ use winit::{
event_loop::EventLoop, event_loop::EventLoop,
window::WindowBuilder, window::WindowBuilder,

View File

@ -1,3 +1,6 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use canvas::{ use canvas::{
Application, Application,
Canvas, Canvas,
@ -8,6 +11,7 @@ use canvas::{
use std::{ use std::{
rc::Rc, rc::Rc,
cell::RefCell, cell::RefCell,
time::Instant,
}; };
fn setup_logger() -> Result<(), fern::InitError> { fn setup_logger() -> Result<(), fern::InitError> {
@ -39,6 +43,9 @@ fn setup_logger() -> Result<(), fern::InitError> {
struct ExampleState { struct ExampleState {
pub texture: Texture, pub texture: Texture,
pub tex_sprite: TextureSprite, pub tex_sprite: TextureSprite,
pub sub_sprite: TextureSprite,
pub last_instant: Instant,
pub last_offset: u32,
} }
struct ExampleApp {} struct ExampleApp {}
@ -55,13 +62,21 @@ impl Application<ExampleState> for ExampleApp {
.unwrap(); .unwrap();
let mut tex_sprite = canvas.create_texture_sprite(Size {w: 20, h: 20}); let mut tex_sprite = canvas.create_texture_sprite(Size {w: 20, h: 20});
tex_sprite.set_texture(texture.clone(), Some(Position {x: 0, y: 0})); tex_sprite.set_texture(texture.clone(), Some(Position {x: 0, y: 0}));
let mut sub_sprite = canvas.create_texture_sprite(Size {w: 350, h: 427});
sub_sprite.set_texture(texture.clone(), Some(Position {x: 350, y: 0}));
canvas.clear(); canvas.clear();
canvas.update(); canvas.update();
let last_instant = Instant::now();
Ok(ExampleState { Ok(ExampleState {
texture, texture,
tex_sprite, tex_sprite,
sub_sprite,
last_instant,
last_offset: 0,
}) })
} }
@ -73,6 +88,17 @@ impl Application<ExampleState> for ExampleApp {
shape::{Shape, Rectangle}, shape::{Shape, Rectangle},
}; };
let now = Instant::now();
let elapsed = now.duration_since(state.last_instant).as_millis();
state.last_instant = now;
debug!("frame time: {}ms", elapsed);
//state.sub_sprite.for_each(|pix| unsafe {pix.flat = pix.flat.wrapping_add(1);});
state.last_offset += 1;
state.sub_sprite.set_texture(state.texture.clone(),
Some(Position {x: state.last_offset, y: 0}));
// inputs // inputs
//if canvas.key_pressed(Key::A) { //if canvas.key_pressed(Key::A) {
// unimplemented!(); // unimplemented!();
@ -126,8 +152,10 @@ impl Application<ExampleState> for ExampleApp {
//txt_sprite.set_alpha(255); //txt_sprite.set_alpha(255);
//txt_sprite.set_scale(0.5); //txt_sprite.set_scale(0.5);
//canvas.draw(&txt_sprite); //canvas.draw(&txt_sprite);
canvas.draw(&state.tex_sprite); canvas.draw(&state.tex_sprite);
canvas.draw(&state.sub_sprite);
canvas.update(); canvas.update();
Ok(()) Ok(())

View File

@ -208,9 +208,40 @@ impl WgpuRenderer {
multiview: None, multiview: None,
}) })
}; };
let texture_quad = GpuMesh::create(&device, &TEXTURE_QUAD); let texture_quad = {
let quad_mesh = GpuMesh::create(&device, &QUAD); let mesh = Mesh {
vertices: vec![
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: vec![
0, 1, 2,
0, 2, 3,
],
};
GpuMesh::create(&device, &mesh)
};
let quad_mesh = {
let mesh = Mesh {
vertices: vec![
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: vec![
0, 1, 2,
0, 2, 3,
],
};
GpuMesh::create(&device, &mesh)
};
let output = Some(surface.get_current_texture() let output = Some(surface.get_current_texture()
.map_err(|_| "Failed to create SurfaceTexture")?); .map_err(|_| "Failed to create SurfaceTexture")?);
@ -250,14 +281,18 @@ impl WgpuRenderer {
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
match sprite.render_data() { match sprite.render_data() {
RenderData::Texture (texture) => { RenderData::Texture ((mesh, texture)) => {
let mut texture = texture.borrow_mut(); let mut texture = texture.borrow_mut();
if texture.is_synced() == false { if texture.is_synced == false {
texture.update(&mut self.queue); texture.update(&mut self.queue);
} }
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { //TODO avoid recreating buffers every time
let gpu_mesh = GpuMesh::create(&self.device, &mesh);
let mut encoder = self.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"), label: Some("Render Encoder"),
}); });
@ -267,18 +302,16 @@ impl WgpuRenderer {
view: &view, view: &view,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Load, load: wgpu::LoadOp::Load, store: true, },
store: true,
},
})], })],
depth_stencil_attachment: None, depth_stencil_attachment: None,
}); });
render_pass.set_pipeline(&self.texture_render_pipeline); render_pass.set_pipeline(&self.texture_render_pipeline);
render_pass.set_vertex_buffer(0, self.texture_quad.vertex_buffer.slice(..)); render_pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
render_pass.set_index_buffer(self.texture_quad.index_buffer.slice(..), render_pass.set_index_buffer(gpu_mesh.index_buffer.slice(..),
wgpu::IndexFormat::Uint16); wgpu::IndexFormat::Uint16);
render_pass.set_bind_group(0, texture.bind_group(), &[]); render_pass.set_bind_group(0, &texture.bind_group, &[]);
render_pass.draw_indexed(0..self.texture_quad.index_number, 0, 0..1); render_pass.draw_indexed(0..self.texture_quad.index_number, 0, 0..1);
drop(render_pass); drop(render_pass);
@ -372,7 +405,7 @@ impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
let vertex_buffer = device.create_buffer_init( let vertex_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor { &wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"), label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(mesh.vertices), contents: bytemuck::cast_slice(&mesh.vertices),
usage: wgpu::BufferUsages::VERTEX, usage: wgpu::BufferUsages::VERTEX,
} }
); );
@ -380,7 +413,7 @@ impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
let index_buffer = device.create_buffer_init( let index_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor { &wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"), label: Some("Index Buffer"),
contents: bytemuck::cast_slice(mesh.indices), contents: bytemuck::cast_slice(&mesh.indices),
usage: wgpu::BufferUsages::INDEX, usage: wgpu::BufferUsages::INDEX,
} }
); );
@ -395,7 +428,7 @@ impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
} }
pub enum RenderData<'a> { pub enum RenderData<'a> {
Texture (&'a Rc<RefCell<GpuTexture>>), Texture ((&'a Mesh<TextureVertex>, &'a Rc<RefCell<GpuTexture>>)),
Shape (&'a GpuMesh<ColorVertex>), Shape (&'a GpuMesh<ColorVertex>),
} }
@ -442,36 +475,36 @@ impl ColorVertex {
} }
} }
pub struct Mesh<'a, V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> { pub struct Mesh<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
pub vertices: &'a[V], pub vertices: Vec<V>,
pub indices: &'a[u16], pub indices: Vec<u16>,
} }
pub const TEXTURE_QUAD: Mesh<'static, TextureVertex> = Mesh { //pub const TEXTURE_QUAD: Mesh<TextureVertex> = Mesh {
vertices: &[ // vertices: [
TextureVertex { position: [0.0, 0.0], tex_coords: [0.0, 1.0] }, // 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, 0.0], tex_coords: [1.0, 1.0] },
TextureVertex { position: [1.0, 1.0], tex_coords: [1.0, 0.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] }, // TextureVertex { position: [0.0, 1.0], tex_coords: [0.0, 0.0] },
], // ],
indices: &[ // indices: [
0, 1, 2, // 0, 1, 2,
0, 2, 3, // 0, 2, 3,
], // ],
}; //};
//
const QUAD: Mesh<'static, ColorVertex> = Mesh { //const QUAD: Mesh<ColorVertex> = Mesh {
vertices: &[ // vertices: [
ColorVertex { position: [0.0, 0.0], color: [1.0, 0.0, 0.0] }, // 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, 0.0], color: [0.0, 1.0, 0.0] },
ColorVertex { position: [1.0, 1.0], color: [0.0, 0.0, 1.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] }, // ColorVertex { position: [0.0, 1.0], color: [0.5, 0.5, 0.5] },
], // ],
indices: &[ // indices: [
0, 1, 2, // 0, 1, 2,
0, 2, 3, // 0, 2, 3,
], // ],
}; //};
impl From<Pixel> for wgpu::Color { impl From<Pixel> for wgpu::Color {

View File

@ -2,7 +2,7 @@
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use crate::{ use crate::{
renderer::{GpuMesh, RenderData}, renderer::{Mesh, RenderData, TextureVertex},
shape::Shape, shape::Shape,
texture::Texture, texture::Texture,
utils::{Pixel, Position, Size}, utils::{Pixel, Position, Size},
@ -31,38 +31,91 @@ pub struct TextureSprite {
position: Position, position: Position,
scale: f32, scale: f32,
matrix: Matrix4<f32>, matrix: Matrix4<f32>,
mesh: Mesh<TextureVertex>,
texture: Texture, texture: Texture,
texture_offset: Position,
texture_size: Size,
} }
impl TextureSprite { impl TextureSprite {
pub fn create(texture: Texture) -> Self { pub fn create(texture: Texture, size: Size) -> Self {
let position = Position::default(); let position = Position::origin();
let scale = 1.0; let scale = 1.0;
let matrix = Matrix4::from_scale(scale) + Matrix4::from_translation(position.into()); let matrix = Matrix4::from_scale(scale) + Matrix4::from_translation(position.into());
let mesh = Mesh {
vertices: vec![
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: vec![
0, 1, 2,
0, 2, 3,
],
};
Self { Self {
position, position,
scale, scale,
matrix, matrix,
mesh,
texture, texture,
texture_offset: position,
texture_size: size,
} }
} }
pub fn set_texture(&mut self, texture: Texture, _offset: Option<Position>) { pub fn set_texture(&mut self, texture: Texture, offset: Option<Position>) {
// update texture
self.texture = texture; self.texture = texture;
let size = self.texture.get_size();
// compute normalized coordinates
self.texture_offset = offset.unwrap_or(Position::origin());
let x_size = self.texture_size.w as f32 / size.w as f32;
let y_size = self.texture_size.h as f32 / size.h as f32;
let x_offset = self.texture_offset.x as f32 / size.w as f32;
let y_offset = self.texture_offset.y as f32 / size.h as f32;
// generate new sprite mesh
self.mesh = Mesh {
vertices: vec![
TextureVertex {
position: [0.0, 0.0],
tex_coords: [x_offset , y_offset + y_size],
},
TextureVertex {
position: [1.0, 0.0],
tex_coords: [x_offset + x_size, y_offset + y_size],
},
TextureVertex {
position: [1.0, 1.0],
tex_coords: [x_offset + x_size, y_offset ],
},
TextureVertex {
position: [0.0, 1.0],
tex_coords: [x_offset , y_offset ],
},
],
indices: vec![
0, 1, 2,
0, 2, 3,
],
};
} }
pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) { pub fn set_pixel(&mut self, pos: Position, pix: Pixel) {
todo!(); //TODO check pos ?
self.texture.set_pixel(self.texture_offset + pos, pix);
} }
pub fn iter(&self) -> Iter<'_, Pixel> { pub fn for_each<F: FnMut(&mut Pixel)>(&mut self, func: F) {
todo!(); //TODO check pos ?
} self.texture.for_each_in_area(func, self.texture_offset, self.texture_size);
pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> {
todo!();
} }
} }
@ -85,7 +138,7 @@ impl Sprite for TextureSprite {
} }
fn render_data(&self) -> RenderData { fn render_data(&self) -> RenderData {
RenderData::Texture (&self.texture.gpu_texture()) RenderData::Texture ((&self.mesh, &self.texture.gpu_texture()))
} }
} }

View File

@ -42,9 +42,9 @@ impl GpuTexture {
let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler( let sampler = device.create_sampler(
&wgpu::SamplerDescriptor { &wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::Repeat,
address_mode_w: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Linear, mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Nearest, min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::FilterMode::Nearest, mipmap_filter: wgpu::FilterMode::Nearest,
@ -78,14 +78,6 @@ impl GpuTexture {
} }
} }
pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.bind_group
}
pub fn is_synced(&self) -> bool {
self.is_synced
}
pub fn update(&mut self, queue: &wgpu::Queue) { pub fn update(&mut self, queue: &wgpu::Queue) {
queue.write_texture( queue.write_texture(
@ -123,21 +115,47 @@ impl Texture {
} }
} }
pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) { pub fn set_pixel(&mut self, pos: Position, pix: Pixel) {
todo!();
//TODO check pos ?
let mut gpu_texture = self.gpu_texture.borrow_mut();
let width = gpu_texture.size.w;
gpu_texture.buffer[(pos.x + pos.y*width) as usize] = pix;
gpu_texture.is_synced = false;
} }
pub fn iter(&self) -> Iter<'_, Pixel> { pub fn for_each<F: FnMut(&mut Pixel)>(&mut self, mut func: F) {
todo!();
let mut gpu_texture = self.gpu_texture.borrow_mut();
for pix in &mut gpu_texture.buffer {
func(pix);
}
gpu_texture.is_synced = false;
} }
pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> { pub fn for_each_in_area<F: FnMut(&mut Pixel)>(&mut self,
todo!(); mut func: F,
offset: Position,
size: Size)
{
//TODO check offset and pos ?
let mut gpu_texture = self.gpu_texture.borrow_mut();
let width = gpu_texture.size.w;
for x in offset.x..(offset.x + size.w) {
for y in offset.y..(offset.y + size.h) {
func(&mut gpu_texture.buffer[(x + y*width) as usize]);
}
}
gpu_texture.is_synced = false;
} }
pub fn gpu_texture(&self) -> &Rc<RefCell<GpuTexture>> { pub fn gpu_texture(&self) -> &Rc<RefCell<GpuTexture>> {
//TODO improve that //TODO improve that
&self.gpu_texture &self.gpu_texture
} }
pub fn get_size(&self) -> Size {
self.gpu_texture.borrow().size
}
} }

View File

@ -14,7 +14,7 @@ pub struct Position {
impl Position { impl Position {
pub fn default() -> Self { pub fn origin() -> Self {
Position { Position {
x: 0, x: 0,
y: 0, y: 0,
@ -29,6 +29,17 @@ impl From<Position> for Vector3<f32> {
} }
} }
impl std::ops::Add for Position {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Position {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
//--Size struct------------------------------------------------------------------------------------- //--Size struct-------------------------------------------------------------------------------------
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Size { pub struct Size {
@ -80,7 +91,7 @@ pub struct Rgba {
#[derive(Copy, Clone, bytemuck::Zeroable)] #[derive(Copy, Clone, bytemuck::Zeroable)]
pub union Pixel { pub union Pixel {
flat: u32, pub flat: u32,
rgba: Rgba, rgba: Rgba,
} }