Started implementing TextureSprite
* reworked Texture API + implemented basic TextureSprite functions * minor modifications
This commit is contained in:
parent
79b86afc2a
commit
3a7799bc76
@ -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) {
|
||||
|
||||
24
src/main.rs
24
src/main.rs
@ -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(())
|
||||
|
||||
@ -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 {
|
||||
@ -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,12 +246,21 @@ impl WgpuRenderer {
|
||||
},
|
||||
};
|
||||
|
||||
//TODO move that to output struct ?
|
||||
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
match sprite.render_data() {
|
||||
RenderData::Texture (texture) => {
|
||||
let mut texture = texture.borrow_mut();
|
||||
|
||||
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 {
|
||||
@ -268,9 +280,13 @@ impl WgpuRenderer {
|
||||
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] },
|
||||
|
||||
@ -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 {
|
||||
position: Position,
|
||||
scale: f32,
|
||||
matrix: Matrix4<f32>,
|
||||
size: Size,
|
||||
texture: Rc<RefCell<Texture>>,
|
||||
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!();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
126
src/texture.rs
126
src/texture.rs
@ -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 }
|
||||
Self {
|
||||
texture,
|
||||
bind_group,
|
||||
buffer: Vec::from(bytemuck::cast_slice(buffer)),
|
||||
size,
|
||||
is_synced: false,
|
||||
}
|
||||
|
||||
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!();
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
38
src/utils.rs
38
src/utils.rs
@ -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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user