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 {
renderer: WgpuRenderer,
clear_color: Pixel,
default_texture: Texture,
}
impl Canvas {
@ -38,15 +39,38 @@ impl Canvas {
let mut renderer = WgpuRenderer::create(window, size).await?;
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 {
renderer,
clear_color: Color::WHITE,
default_texture,
})
}
//--Create functions--
pub fn create_texture_sprite(&mut self, _size: Size, _scale: f32) -> TextureSprite {
unimplemented!();
pub fn create_texture_sprite(&mut self, _size: Size) -> TextureSprite {
TextureSprite::create(self.default_texture.clone())
}
pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite {
@ -68,7 +92,7 @@ impl Canvas {
_offset: Option<Position>,
_size: Option<Size>,
_background: Option<Pixel>)
-> Result<Rc<RefCell<Texture>>, &'static str>
-> Result<Texture, &'static str>
{
use image::{
io::Reader,
@ -88,9 +112,7 @@ impl Canvas {
}
};
Ok(Rc::new(RefCell::new(
self.renderer.create_texture(&rgba, img_size)
)))
Ok(Texture::create(self.renderer.create_gpu_texture(&rgba, img_size)))
}
pub fn create_texture_from_bytes(&mut self,
@ -107,11 +129,10 @@ impl Canvas {
}
//--Output functions--
// pub fn draw<S: Sprite>(&mut self, sprite: &S) {
pub fn draw(&mut self, texture: &Texture) {
pub fn draw<S: Sprite>(&mut self, sprite: &S) {
//update texture
self.renderer.render(texture);
self.renderer.render(sprite);
}
pub fn set_clear_color(&mut self, color: Pixel) {

View File

@ -2,6 +2,7 @@ use canvas::{
Application,
Canvas,
texture::Texture,
sprite::TextureSprite,
};
use std::{
@ -36,7 +37,8 @@ fn setup_logger() -> Result<(), fern::InitError> {
}
struct ExampleState {
pub texture: Rc<RefCell<Texture>>,
pub texture: Texture,
pub tex_sprite: TextureSprite,
}
struct ExampleApp {}
@ -44,15 +46,22 @@ struct ExampleApp {}
impl Application<ExampleState> for ExampleApp {
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)
.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.update();
Ok(ExampleState {
texture,
tex_sprite,
})
}
@ -95,15 +104,7 @@ impl Application<ExampleState> for ExampleApp {
//bas_sprite.set_color(Color::WHITE);
//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
//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_scale(0.5);
//canvas.draw(&txt_sprite);
canvas.draw(&state.texture.borrow());
canvas.draw(&state.tex_sprite);
canvas.update();
Ok(())

View File

@ -6,11 +6,15 @@ use wgpu;
use crate::{
sprite::Sprite,
texture::Texture,
texture::{GpuTexture, Texture},
utils::{Pixel, Position, Size},
};
use std::marker::PhantomData;
use std::{
marker::PhantomData,
rc::Rc,
cell::RefCell,
};
//--Renderer struct---------------------------------------------------------------------------------
pub struct WgpuRenderer {
@ -37,7 +41,7 @@ impl WgpuRenderer {
}
let instance = wgpu::Instance::new(wgpu::Backends::all());
let surface = unsafe { instance.create_surface(window) };
let adapter = instance.request_adapter(
&wgpu::RequestAdapterOptions {
//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)
-> Texture
pub fn create_gpu_texture(&mut self, buf: &[u8], size: Size)
-> 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(&mut self, texture: &Texture) {
pub fn render<S: Sprite>(&mut self, sprite: &S) {
let output = match &self.output {
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 mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
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,
});
match sprite.render_data() {
RenderData::Texture (texture) => {
let mut texture = texture.borrow_mut();
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);
if texture.is_synced() == false {
texture.update(&mut self.queue);
}
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
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) {
@ -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,
index_buffer: wgpu::Buffer,
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---------------------------------------------------------------------------
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct TextureVertex {
pub struct TextureVertex {
pub position: [f32; 2],
pub tex_coords: [f32; 2],
}
@ -402,7 +423,7 @@ impl TextureVertex {
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct ColorVertex {
pub struct ColorVertex {
pub position: [f32; 2],
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 indices: &'a[u16],
}
const TEXTURE_QUAD: Mesh<'static, TextureVertex> = Mesh {
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] },

View File

@ -2,6 +2,7 @@
use log::{debug, error, info, trace, warn};
use crate::{
renderer::{GpuMesh, RenderData},
shape::Shape,
texture::Texture,
utils::{Pixel, Position, Size},
@ -22,31 +23,46 @@ pub trait Sprite {
fn set_rotation(&mut self, rot: f32);
fn set_alpha(&mut self, alpha: u8);
fn set_scale(&mut self, scale: f32);
fn render_data(&self) -> RenderData;
}
//--TextureSprite struct----------------------------------------------------------------------------
pub struct TextureSprite {
matrix: Matrix4<f32>,
size: Size,
texture: Rc<RefCell<Texture>>,
position: Position,
scale: f32,
matrix: Matrix4<f32>,
texture: Texture,
}
impl TextureSprite {
pub fn set_texture(&mut self, _texture: Rc<RefCell<Texture>>, _offset: Option<Position>) {
unimplemented!();
pub fn create(texture: Texture) -> Self {
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) {
unimplemented!();
todo!();
}
pub fn iter(&self) -> Iter<'_, Pixel> {
unimplemented!();
todo!();
}
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) {
unimplemented!();
}
fn render_data(&self) -> RenderData {
RenderData::Texture (&self.texture.gpu_texture())
}
}
//--TextSprite struct-------------------------------------------------------------------------------
@ -104,6 +124,10 @@ impl Sprite for TextSprite {
fn set_scale(&mut self, _scale: f32) {
unimplemented!();
}
fn render_data(&self) -> RenderData {
todo!();
}
}
//--ShapeSprite struct-------------------------------------------------------------------------------
@ -141,5 +165,9 @@ impl Sprite for ShapeSprite {
fn set_scale(&mut self, _scale: f32) {
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 std::slice::{Iter, IterMut};
use std::{
slice::{Iter, IterMut},
rc::Rc,
cell::RefCell,
};
//--Texture struct----------------------------------------------------------------------------------
pub struct Texture {
texture: wgpu::Texture,
bind_group: wgpu::BindGroup,
//--GpuTexture struct-------------------------------------------------------------------------------
pub struct GpuTexture {
pub texture: wgpu::Texture,
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,
queue: &wgpu::Queue,
layout: &wgpu::BindGroupLayout,
buf: &[u8],
buf_size: Size)
buffer: &[u8],
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,
size: size.into(),
mip_level_count: 1,
sample_count: 1,
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 sampler = device.create_sampler(
&wgpu::SamplerDescriptor {
@ -79,27 +65,79 @@ impl Texture {
resource: wgpu::BindingResource::Sampler(&sampler),
}
],
label: Some("diffuse_bind_group"),
label: Some("texture_bind_group"),
}
);
Self { texture, bind_group }
}
pub fn set_pixel(&mut self, _pos: Position, _pix: Pixel) {
unimplemented!();
}
pub fn iter(&self) -> Iter<'_, Pixel> {
unimplemented!();
}
pub fn iter_mut(&mut self) -> IterMut<'_, Pixel> {
unimplemented!();
Self {
texture,
bind_group,
buffer: Vec::from(bytemuck::cast_slice(buffer)),
size,
is_synced: false,
}
}
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(
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 cgmath::Vector3;
//--Position struct---------------------------------------------------------------------------------
#[derive(Copy, Clone)]
pub struct Position {
pub x: 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-------------------------------------------------------------------------------------
#[derive(Copy, Clone)]
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 {
fn from(size: winit::dpi::PhysicalSize<u32>) -> Self {
@ -38,7 +69,8 @@ impl From<winit::dpi::PhysicalSize<u32>> for Size {
}
//--Pixel struct------------------------------------------------------------------------------------
#[derive(Copy, Clone)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
pub struct Rgba {
pub r: u8,
pub g: u8,
@ -46,12 +78,14 @@ pub struct Rgba {
pub a: u8,
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, bytemuck::Zeroable)]
pub union Pixel {
flat: u32,
rgba: Rgba,
}
unsafe impl bytemuck::Pod for Pixel {}
impl Pixel {
pub fn rgb(r: u8, g: u8, b: u8) -> Pixel {