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--
pub fn create_texture_sprite(&mut self, _size: Size) -> TextureSprite {
TextureSprite::create(self.default_texture.clone())
pub fn create_texture_sprite(&mut self, size: Size) -> TextureSprite {
TextureSprite::create(self.default_texture.clone(), size)
}
pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite {

View File

@ -15,7 +15,10 @@ mod renderer;
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::{
event_loop::EventLoop,
window::WindowBuilder,

View File

@ -1,3 +1,6 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use canvas::{
Application,
Canvas,
@ -8,6 +11,7 @@ use canvas::{
use std::{
rc::Rc,
cell::RefCell,
time::Instant,
};
fn setup_logger() -> Result<(), fern::InitError> {
@ -39,6 +43,9 @@ fn setup_logger() -> Result<(), fern::InitError> {
struct ExampleState {
pub texture: Texture,
pub tex_sprite: TextureSprite,
pub sub_sprite: TextureSprite,
pub last_instant: Instant,
pub last_offset: u32,
}
struct ExampleApp {}
@ -56,12 +63,20 @@ impl Application<ExampleState> for ExampleApp {
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}));
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.update();
let last_instant = Instant::now();
Ok(ExampleState {
texture,
tex_sprite,
sub_sprite,
last_instant,
last_offset: 0,
})
}
@ -73,6 +88,17 @@ impl Application<ExampleState> for ExampleApp {
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
//if canvas.key_pressed(Key::A) {
// unimplemented!();
@ -127,7 +153,9 @@ impl Application<ExampleState> for ExampleApp {
//txt_sprite.set_scale(0.5);
//canvas.draw(&txt_sprite);
canvas.draw(&state.tex_sprite);
canvas.draw(&state.sub_sprite);
canvas.update();
Ok(())

View File

@ -209,8 +209,39 @@ impl WgpuRenderer {
})
};
let texture_quad = GpuMesh::create(&device, &TEXTURE_QUAD);
let quad_mesh = GpuMesh::create(&device, &QUAD);
let texture_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()
.map_err(|_| "Failed to create SurfaceTexture")?);
@ -250,14 +281,18 @@ impl WgpuRenderer {
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
match sprite.render_data() {
RenderData::Texture (texture) => {
RenderData::Texture ((mesh, texture)) => {
let mut texture = texture.borrow_mut();
if texture.is_synced() == false {
if texture.is_synced == false {
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"),
});
@ -267,18 +302,16 @@ impl WgpuRenderer {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
load: wgpu::LoadOp::Load, store: true, },
})],
depth_stencil_attachment: None,
});
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(..),
render_pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
render_pass.set_index_buffer(gpu_mesh.index_buffer.slice(..),
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);
drop(render_pass);
@ -372,7 +405,7 @@ impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
let vertex_buffer = device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(mesh.vertices),
contents: bytemuck::cast_slice(&mesh.vertices),
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(
&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: bytemuck::cast_slice(mesh.indices),
contents: bytemuck::cast_slice(&mesh.indices),
usage: wgpu::BufferUsages::INDEX,
}
);
@ -395,7 +428,7 @@ impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
}
pub enum RenderData<'a> {
Texture (&'a Rc<RefCell<GpuTexture>>),
Texture ((&'a Mesh<TextureVertex>, &'a Rc<RefCell<GpuTexture>>)),
Shape (&'a GpuMesh<ColorVertex>),
}
@ -442,36 +475,36 @@ impl ColorVertex {
}
}
pub struct Mesh<'a, V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
pub vertices: &'a[V],
pub indices: &'a[u16],
pub struct Mesh<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
pub vertices: Vec<V>,
pub indices: Vec<u16>,
}
pub const TEXTURE_QUAD: Mesh<'static, TextureVertex> = Mesh {
vertices: &[
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,
],
};
//pub const TEXTURE_QUAD: Mesh<TextureVertex> = Mesh {
// vertices: [
// 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<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 {

View File

@ -2,7 +2,7 @@
use log::{debug, error, info, trace, warn};
use crate::{
renderer::{GpuMesh, RenderData},
renderer::{Mesh, RenderData, TextureVertex},
shape::Shape,
texture::Texture,
utils::{Pixel, Position, Size},
@ -31,38 +31,91 @@ pub struct TextureSprite {
position: Position,
scale: f32,
matrix: Matrix4<f32>,
mesh: Mesh<TextureVertex>,
texture: Texture,
texture_offset: Position,
texture_size: Size,
}
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 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 {
position,
scale,
matrix,
mesh,
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;
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) {
todo!();
pub fn set_pixel(&mut self, pos: Position, pix: Pixel) {
//TODO check pos ?
self.texture.set_pixel(self.texture_offset + pos, pix);
}
pub fn iter(&self) -> Iter<'_, Pixel> {
todo!();
}
pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> {
todo!();
pub fn for_each<F: FnMut(&mut Pixel)>(&mut self, func: F) {
//TODO check pos ?
self.texture.for_each_in_area(func, self.texture_offset, self.texture_size);
}
}
@ -85,7 +138,7 @@ impl Sprite for TextureSprite {
}
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 sampler = device.create_sampler(
&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::Repeat,
address_mode_w: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Linear,
min_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) {
queue.write_texture(
@ -123,21 +115,47 @@ impl Texture {
}
}
pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) {
todo!();
pub fn set_pixel(&mut self, pos: Position, pix: Pixel) {
//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> {
todo!();
pub fn for_each<F: FnMut(&mut Pixel)>(&mut self, mut func: F) {
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> {
todo!();
pub fn for_each_in_area<F: FnMut(&mut Pixel)>(&mut self,
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>> {
//TODO improve that
&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 {
pub fn default() -> Self {
pub fn origin() -> Self {
Position {
x: 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-------------------------------------------------------------------------------------
#[derive(Copy, Clone)]
pub struct Size {
@ -80,7 +91,7 @@ pub struct Rgba {
#[derive(Copy, Clone, bytemuck::Zeroable)]
pub union Pixel {
flat: u32,
pub flat: u32,
rgba: Rgba,
}