Started implementing TextureSprite

* reworked Texture API
+ implemented basic TextureSprite functions
* minor modifications
This commit is contained in:
Steins7 2022-07-20 23:54:41 +02:00
parent 79b86afc2a
commit 3a7799bc76
6 changed files with 255 additions and 111 deletions

View File

@ -28,6 +28,7 @@ pub trait Application<S> {
pub struct Canvas { pub struct Canvas {
renderer: WgpuRenderer, renderer: WgpuRenderer,
clear_color: Pixel, clear_color: Pixel,
default_texture: Texture,
} }
impl Canvas { impl Canvas {
@ -38,15 +39,38 @@ impl Canvas {
let mut renderer = WgpuRenderer::create(window, size).await?; let mut renderer = WgpuRenderer::create(window, size).await?;
renderer.clear(Color::WHITE); renderer.clear(Color::WHITE);
let default_texture = {
use image::{
io::Reader,
GenericImageView,
};
let img = Reader::open("assets/camel.jpg")
.map_err(|_| "Failed to open default texture")?
.decode()
.map_err(|_| "Failed to decode default texture")?;
let rgba = img.to_rgba8();
let img_size = {
let dimensions = img.dimensions();
Size {
w: dimensions.0,
h: dimensions.1,
}
};
Texture::create(renderer.create_gpu_texture(&rgba, img_size))
};
Ok(Self { Ok(Self {
renderer, renderer,
clear_color: Color::WHITE, clear_color: Color::WHITE,
default_texture,
}) })
} }
//--Create functions-- //--Create functions--
pub fn create_texture_sprite(&mut self, _size: Size, _scale: f32) -> TextureSprite { pub fn create_texture_sprite(&mut self, _size: Size) -> TextureSprite {
unimplemented!(); TextureSprite::create(self.default_texture.clone())
} }
pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite { pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite {
@ -68,7 +92,7 @@ impl Canvas {
_offset: Option<Position>, _offset: Option<Position>,
_size: Option<Size>, _size: Option<Size>,
_background: Option<Pixel>) _background: Option<Pixel>)
-> Result<Rc<RefCell<Texture>>, &'static str> -> Result<Texture, &'static str>
{ {
use image::{ use image::{
io::Reader, io::Reader,
@ -88,9 +112,7 @@ impl Canvas {
} }
}; };
Ok(Rc::new(RefCell::new( Ok(Texture::create(self.renderer.create_gpu_texture(&rgba, img_size)))
self.renderer.create_texture(&rgba, img_size)
)))
} }
pub fn create_texture_from_bytes(&mut self, pub fn create_texture_from_bytes(&mut self,
@ -107,11 +129,10 @@ impl Canvas {
} }
//--Output functions-- //--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 //update texture
self.renderer.render(texture); self.renderer.render(sprite);
} }
pub fn set_clear_color(&mut self, color: Pixel) { pub fn set_clear_color(&mut self, color: Pixel) {

View File

@ -2,6 +2,7 @@ use canvas::{
Application, Application,
Canvas, Canvas,
texture::Texture, texture::Texture,
sprite::TextureSprite,
}; };
use std::{ use std::{
@ -36,7 +37,8 @@ fn setup_logger() -> Result<(), fern::InitError> {
} }
struct ExampleState { struct ExampleState {
pub texture: Rc<RefCell<Texture>>, pub texture: Texture,
pub tex_sprite: TextureSprite,
} }
struct ExampleApp {} struct ExampleApp {}
@ -44,15 +46,22 @@ struct ExampleApp {}
impl Application<ExampleState> for ExampleApp { impl Application<ExampleState> for ExampleApp {
fn init(canvas: &mut Canvas) -> Result<ExampleState, &'static str> { fn init(canvas: &mut Canvas) -> Result<ExampleState, &'static str> {
use canvas::{
utils::{Position, Size},
};
//// 20 x 20 sprite of a picture
let texture = canvas.create_texture_from_file("assets/camel.jpg", None, None, None) let texture = canvas.create_texture_from_file("assets/camel.jpg", None, None, None)
.unwrap(); .unwrap();
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}));
canvas.clear(); canvas.clear();
canvas.update(); canvas.update();
Ok(ExampleState { Ok(ExampleState {
texture, texture,
tex_sprite,
}) })
} }
@ -95,15 +104,7 @@ impl Application<ExampleState> for ExampleApp {
//bas_sprite.set_color(Color::WHITE); //bas_sprite.set_color(Color::WHITE);
//canvas.draw(&bas_sprite); //canvas.draw(&bas_sprite);
//// 20 x 20 sprite of a picture
//let texture = canvas.create_texture_from_file(
// Position {x: 0, y: 0},
// "texture.png",
// Some(Color::WHITE)
//);
//let mut pix_sprite = canvas.create_texture_sprite(Size {w: 20, h: 20}, 1.0);
//pix_sprite.set_texture(texture, Some(Position {x: 0, y: 0}));
//canvas.draw(&pix_sprite);
//// scaled sprite of a manually drawed texture //// scaled sprite of a manually drawed texture
//let texture = canvas.create_texture(Size {w: 20, h: 20}, Some(Color::WHITE)); //let texture = canvas.create_texture(Size {w: 20, h: 20}, Some(Color::WHITE));
@ -125,7 +126,8 @@ 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.texture.borrow());
canvas.draw(&state.tex_sprite);
canvas.update(); canvas.update();
Ok(()) Ok(())

View File

@ -6,11 +6,15 @@ use wgpu;
use crate::{ use crate::{
sprite::Sprite, sprite::Sprite,
texture::Texture, texture::{GpuTexture, Texture},
utils::{Pixel, Position, Size}, utils::{Pixel, Position, Size},
}; };
use std::marker::PhantomData; use std::{
marker::PhantomData,
rc::Rc,
cell::RefCell,
};
//--Renderer struct--------------------------------------------------------------------------------- //--Renderer struct---------------------------------------------------------------------------------
pub struct WgpuRenderer { pub struct WgpuRenderer {
@ -37,7 +41,7 @@ impl WgpuRenderer {
} }
let instance = wgpu::Instance::new(wgpu::Backends::all()); let instance = wgpu::Instance::new(wgpu::Backends::all());
let surface = unsafe { instance.create_surface(window) }; let surface = unsafe { instance.create_surface(window) };
let adapter = instance.request_adapter( let adapter = instance.request_adapter(
&wgpu::RequestAdapterOptions { &wgpu::RequestAdapterOptions {
//for now, integrated GPU is enough, may be revised later //for now, integrated GPU is enough, may be revised later
@ -226,14 +230,13 @@ impl WgpuRenderer {
}) })
} }
pub fn create_texture(&mut self, buf: &[u8], size: Size) pub fn create_gpu_texture(&mut self, buf: &[u8], size: Size)
-> Texture -> GpuTexture
{ {
Texture::create(&self.device, &self.queue, &self.texture_bind_group_layout, buf, size) GpuTexture::create(&self.device, &self.texture_bind_group_layout, buf, size)
} }
// pub fn render<S: Sprite>(&mut self, _sprite: &S) { pub fn render<S: Sprite>(&mut self, sprite: &S) {
pub fn render(&mut self, texture: &Texture) {
let output = match &self.output { let output = match &self.output {
Some(out) => out, Some(out) => out,
@ -243,34 +246,47 @@ impl WgpuRenderer {
}, },
}; };
//TODO move that to output struct ?
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{ match sprite.render_data() {
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { RenderData::Texture (texture) => {
label: Some("Render Pass"), let mut texture = texture.borrow_mut();
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
})],
depth_stencil_attachment: None,
});
render_pass.set_pipeline(&self.texture_render_pipeline); if texture.is_synced() == false {
render_pass.set_vertex_buffer(0, self.texture_quad.vertex_buffer.slice(..)); texture.update(&mut self.queue);
render_pass.set_index_buffer(self.texture_quad.index_buffer.slice(..), }
wgpu::IndexFormat::Uint16);
render_pass.set_bind_group(0, texture.bind_group(), &[]); let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
render_pass.draw_indexed(0..self.texture_quad.index_number, 0, 0..1); label: Some("Render Encoder"),
});
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
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(..),
wgpu::IndexFormat::Uint16);
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);
self.queue.submit(std::iter::once(encoder.finish()));
},
_ => (),
} }
self.queue.submit(std::iter::once(encoder.finish()));
} }
pub fn clear(&mut self, color: Pixel) { pub fn clear(&mut self, color: Pixel) {
@ -340,7 +356,7 @@ impl WgpuRenderer {
} }
} }
struct GpuMesh<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> { pub struct GpuMesh<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
vertex_buffer: wgpu::Buffer, vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer,
index_number: u32, index_number: u32,
@ -378,10 +394,15 @@ impl<V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> GpuMesh<V> {
} }
} }
pub enum RenderData<'a> {
Texture (&'a Rc<RefCell<GpuTexture>>),
Shape (&'a GpuMesh<ColorVertex>),
}
//--Renderer struct utils--------------------------------------------------------------------------- //--Renderer struct utils---------------------------------------------------------------------------
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct TextureVertex { pub struct TextureVertex {
pub position: [f32; 2], pub position: [f32; 2],
pub tex_coords: [f32; 2], pub tex_coords: [f32; 2],
} }
@ -402,7 +423,7 @@ impl TextureVertex {
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct ColorVertex { pub struct ColorVertex {
pub position: [f32; 2], pub position: [f32; 2],
pub color: [f32; 3], pub color: [f32; 3],
} }
@ -421,12 +442,12 @@ impl ColorVertex {
} }
} }
struct Mesh<'a, V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> { pub struct Mesh<'a, V: Copy + Clone + bytemuck::Pod + bytemuck::Zeroable> {
pub vertices: &'a[V], pub vertices: &'a[V],
pub indices: &'a[u16], pub indices: &'a[u16],
} }
const TEXTURE_QUAD: Mesh<'static, TextureVertex> = Mesh { pub const TEXTURE_QUAD: Mesh<'static, 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] },

View File

@ -2,6 +2,7 @@
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use crate::{ use crate::{
renderer::{GpuMesh, RenderData},
shape::Shape, shape::Shape,
texture::Texture, texture::Texture,
utils::{Pixel, Position, Size}, utils::{Pixel, Position, Size},
@ -22,31 +23,46 @@ pub trait Sprite {
fn set_rotation(&mut self, rot: f32); fn set_rotation(&mut self, rot: f32);
fn set_alpha(&mut self, alpha: u8); fn set_alpha(&mut self, alpha: u8);
fn set_scale(&mut self, scale: f32); fn set_scale(&mut self, scale: f32);
fn render_data(&self) -> RenderData;
} }
//--TextureSprite struct---------------------------------------------------------------------------- //--TextureSprite struct----------------------------------------------------------------------------
pub struct TextureSprite { pub struct TextureSprite {
matrix: Matrix4<f32>, position: Position,
size: Size, scale: f32,
texture: Rc<RefCell<Texture>>, matrix: Matrix4<f32>,
texture: Texture,
} }
impl TextureSprite { impl TextureSprite {
pub fn set_texture(&mut self, _texture: Rc<RefCell<Texture>>, _offset: Option<Position>) { pub fn create(texture: Texture) -> Self {
unimplemented!();
let position = Position::default();
let scale = 1.0;
let matrix = Matrix4::from_scale(scale) + Matrix4::from_translation(position.into());
Self {
position,
scale,
matrix,
texture,
}
}
pub fn set_texture(&mut self, texture: Texture, _offset: Option<Position>) {
self.texture = texture;
} }
pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) { pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) {
unimplemented!(); todo!();
} }
pub fn iter(&self) -> Iter<'_, Pixel> { pub fn iter(&self) -> Iter<'_, Pixel> {
unimplemented!(); todo!();
} }
pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> { pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> {
unimplemented!(); todo!();
} }
} }
@ -67,6 +83,10 @@ impl Sprite for TextureSprite {
fn set_scale(&mut self, _scale: f32) { fn set_scale(&mut self, _scale: f32) {
unimplemented!(); unimplemented!();
} }
fn render_data(&self) -> RenderData {
RenderData::Texture (&self.texture.gpu_texture())
}
} }
//--TextSprite struct------------------------------------------------------------------------------- //--TextSprite struct-------------------------------------------------------------------------------
@ -104,6 +124,10 @@ impl Sprite for TextSprite {
fn set_scale(&mut self, _scale: f32) { fn set_scale(&mut self, _scale: f32) {
unimplemented!(); unimplemented!();
} }
fn render_data(&self) -> RenderData {
todo!();
}
} }
//--ShapeSprite struct------------------------------------------------------------------------------- //--ShapeSprite struct-------------------------------------------------------------------------------
@ -141,5 +165,9 @@ impl Sprite for ShapeSprite {
fn set_scale(&mut self, _scale: f32) { fn set_scale(&mut self, _scale: f32) {
unimplemented!(); unimplemented!();
} }
fn render_data(&self) -> RenderData {
todo!();
}
} }

View File

@ -3,32 +3,34 @@ use log::{debug, error, info, trace, warn};
use crate::utils::{Pixel, Position, Size}; use crate::utils::{Pixel, Position, Size};
use std::slice::{Iter, IterMut}; use std::{
slice::{Iter, IterMut},
rc::Rc,
cell::RefCell,
};
//--Texture struct---------------------------------------------------------------------------------- //--GpuTexture struct-------------------------------------------------------------------------------
pub struct Texture { pub struct GpuTexture {
texture: wgpu::Texture, pub texture: wgpu::Texture,
bind_group: wgpu::BindGroup, pub bind_group: wgpu::BindGroup,
pub buffer: Vec<Pixel>,
pub size: Size,
pub is_synced: bool,
} }
impl Texture { impl GpuTexture {
pub fn create(device: &wgpu::Device, pub fn create(device: &wgpu::Device,
queue: &wgpu::Queue,
layout: &wgpu::BindGroupLayout, layout: &wgpu::BindGroupLayout,
buf: &[u8], buffer: &[u8],
buf_size: Size) size: Size)
-> Self -> Self
{ {
let size = wgpu::Extent3d {
width: buf_size.w,
height: buf_size.h,
depth_or_array_layers: 1,
};
let texture = device.create_texture( let texture = device.create_texture(
&wgpu::TextureDescriptor { &wgpu::TextureDescriptor {
label: None, label: None,
size, size: size.into(),
mip_level_count: 1, mip_level_count: 1,
sample_count: 1, sample_count: 1,
dimension: wgpu::TextureDimension::D2, dimension: wgpu::TextureDimension::D2,
@ -37,22 +39,6 @@ impl Texture {
} }
); );
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 view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler( let sampler = device.create_sampler(
&wgpu::SamplerDescriptor { &wgpu::SamplerDescriptor {
@ -79,27 +65,79 @@ impl Texture {
resource: wgpu::BindingResource::Sampler(&sampler), resource: wgpu::BindingResource::Sampler(&sampler),
} }
], ],
label: Some("diffuse_bind_group"), label: Some("texture_bind_group"),
} }
); );
Self { texture, bind_group } Self {
} texture,
bind_group,
pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) { buffer: Vec::from(bytemuck::cast_slice(buffer)),
unimplemented!(); size,
} is_synced: false,
}
pub fn iter(&self) -> Iter<'_, Pixel> {
unimplemented!();
}
pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> {
unimplemented!();
} }
pub fn bind_group(&self) -> &wgpu::BindGroup { pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.bind_group &self.bind_group
} }
pub fn is_synced(&self) -> bool {
self.is_synced
}
pub fn update(&mut self, queue: &wgpu::Queue) {
queue.write_texture(
wgpu::ImageCopyTexture {
aspect: wgpu::TextureAspect::All,
texture: &self.texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
},
bytemuck::cast_slice(&self.buffer),
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: std::num::NonZeroU32::new(4 * self.size.w),
rows_per_image: std::num::NonZeroU32::new(self.size.h),
},
self.size.into(),
);
self.is_synced = true;
}
}
//--Texture struct----------------------------------------------------------------------------------
#[derive(Clone)]
pub struct Texture {
gpu_texture: Rc<RefCell<GpuTexture>>,
}
impl Texture {
pub fn create(gpu_texture: GpuTexture) -> Self {
Self {
gpu_texture: Rc::new(RefCell::new(gpu_texture)),
}
}
pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) {
todo!();
}
pub fn iter(&self) -> Iter<'_, Pixel> {
todo!();
}
pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> {
todo!();
}
pub fn gpu_texture(&self) -> &Rc<RefCell<GpuTexture>> {
//TODO improve that
&self.gpu_texture
}
} }

View File

@ -3,12 +3,32 @@ use log::{debug, error, info, trace, warn};
use winit; use winit;
use cgmath::Vector3;
//--Position struct--------------------------------------------------------------------------------- //--Position struct---------------------------------------------------------------------------------
#[derive(Copy, Clone)]
pub struct Position { pub struct Position {
pub x: u32, pub x: u32,
pub y: u32, pub y: u32,
} }
impl Position {
pub fn default() -> Self {
Position {
x: 0,
y: 0,
}
}
}
impl From<Position> for Vector3<f32> {
fn from(pos: Position) -> Self {
Self::new(pos.x as f32, pos.y as f32, 0.0)
}
}
//--Size struct------------------------------------------------------------------------------------- //--Size struct-------------------------------------------------------------------------------------
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Size { pub struct Size {
@ -27,6 +47,17 @@ impl From<Size> for winit::dpi::Size {
} }
} }
impl From<Size> for wgpu::Extent3d {
fn from(size: Size) -> Self {
wgpu::Extent3d {
width: size.w,
height: size.h,
depth_or_array_layers: 1,
}
}
}
impl From<winit::dpi::PhysicalSize<u32>> for Size { impl From<winit::dpi::PhysicalSize<u32>> for Size {
fn from(size: winit::dpi::PhysicalSize<u32>) -> Self { fn from(size: winit::dpi::PhysicalSize<u32>) -> Self {
@ -38,7 +69,8 @@ impl From<winit::dpi::PhysicalSize<u32>> for Size {
} }
//--Pixel struct------------------------------------------------------------------------------------ //--Pixel struct------------------------------------------------------------------------------------
#[derive(Copy, Clone)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
pub struct Rgba { pub struct Rgba {
pub r: u8, pub r: u8,
pub g: u8, pub g: u8,
@ -46,12 +78,14 @@ pub struct Rgba {
pub a: u8, pub a: u8,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone, bytemuck::Zeroable)]
pub union Pixel { pub union Pixel {
flat: u32, flat: u32,
rgba: Rgba, rgba: Rgba,
} }
unsafe impl bytemuck::Pod for Pixel {}
impl Pixel { impl Pixel {
pub fn rgb(r: u8, g: u8, b: u8) -> Pixel { pub fn rgb(r: u8, g: u8, b: u8) -> Pixel {