Compare commits

..

7 Commits

Author SHA1 Message Date
0a637f22fc Minor visual code's cleanup 2024-02-25 23:15:48 +01:00
c90f4a3148 Fix matrix transformation issues
This time, the issues should be fixed for good. Everything behaves as expected.
The only issue remaining is that of the text sprite not having the right size
2024-02-25 23:13:41 +01:00
d28325f2ff Add sprite center configuration
For now, the center is juste defined by coordinates in a haphazard way,
this will need a proper implementation at some point
2023-01-23 21:48:23 +01:00
b524ad07e0 Fix matrix transformation issues 2023-01-03 22:32:44 +01:00
67f802dd77 Implement text sprite main functions 2022-12-29 16:55:47 +01:00
8a2d8bcda7 Update .gitignore 2022-12-29 13:35:56 +01:00
075e8e996f Implement cpu-generated text sprite 2022-12-29 13:34:20 +01:00
17 changed files with 391 additions and 97 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
/target
*.log
*.bkp
*.perf
*.data
*.html

30
Cargo.lock generated
View File

@ -147,6 +147,7 @@ dependencies = [
"cgmath",
"chrono",
"fern",
"fontdue",
"image",
"log",
"pollster",
@ -504,6 +505,16 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "fontdue"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a62391ecb864cf12ed06b2af4eda2e609b97657950d6a8f06841b17726ab253"
dependencies = [
"hashbrown 0.11.2",
"ttf-parser",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
@ -578,7 +589,7 @@ checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a"
dependencies = [
"bitflags",
"gpu-descriptor-types",
"hashbrown",
"hashbrown 0.12.3",
]
[[package]]
@ -590,6 +601,15 @@ dependencies = [
"bitflags",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@ -666,7 +686,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
"hashbrown",
"hashbrown 0.12.3",
]
[[package]]
@ -1319,6 +1339,12 @@ dependencies = [
"serde",
]
[[package]]
name = "ttf-parser"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd"
[[package]]
name = "unicode-ident"
version = "1.0.5"

View File

@ -13,6 +13,7 @@ fern = { version = "^0.6.1", features = ["colored"] }
bitflags = "^1.3.2"
cgmath = { version = "^0.18.0", features = ["bytemuck"] }
pollster = "^0.2.5"
fontdue = "0.7.2"
# surface creation
winit = "^0.26.1"
@ -33,3 +34,6 @@ features = ["png", "jpeg"]
[patch.crates-io]
cgmath = { path = "cgmath" }
[profile.release]
debug = 1

BIN
assets/DejaVuSansMono.ttf Normal file

Binary file not shown.

View File

@ -80,8 +80,14 @@ impl Canvas {
)
}
pub fn create_text_sprite(&mut self, _size: Size, _scale: f32) -> TextSprite {
unimplemented!();
pub fn create_text_sprite(&mut self, text: &'static str, size: Size, text_size: f32)
-> TextSprite {
TextSprite::new(
text,
size,
text_size,
&self.renderer,
)
}
pub fn create_shape_sprite(&mut self) -> ShapeSprite {

View File

@ -106,7 +106,7 @@ mod tests {
message
))
})
.level(log::LevelFilter::Trace)
.level(log::LevelFilter::Debug)
.chain(std::io::stdout())
.chain(fern::log_file("output.log")?)
.apply()?;

View File

@ -5,7 +5,7 @@ use canvas::{
Application,
Canvas,
texture::TextureHandle,
sprite::TextureSprite,
sprite::{TextureSprite, TextSprite},
utils::Position,
};
@ -40,10 +40,13 @@ struct ExampleState {
pub texture: TextureHandle,
pub tex_sprite: TextureSprite,
pub sub_sprite: TextureSprite,
pub sub_sprite2: TextureSprite,
pub txt_sprite: TextSprite,
pub last_instant: Instant,
pub last_offset: u32,
pub last_pos: Position,
pub last_rot: f32,
pub frame_counter: u8,
}
struct ExampleApp {}
@ -51,16 +54,34 @@ struct ExampleApp {}
impl Application<ExampleState> for ExampleApp {
fn init(canvas: &mut Canvas) -> Result<ExampleState, &'static str> {
use canvas::utils::Size;
use canvas::{
utils::Size,
sprite::Sprite,
};
//// 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: 1280, h: 720});
tex_sprite.set_texture(texture.clone(), Some(Position {x: 0, y: 0}), 1.0);
tex_sprite.set_center(Position {x:-1280/2, y:-720/2});
tex_sprite.set_position(Position {x: 0, y: 0});
let mut sub_sprite = canvas.create_texture_sprite(Size {w: 200, h: 200});
sub_sprite.set_texture(texture.clone(), Some(Position {x: 350, y: 0}), 1.0);
let mut sub_sprite = canvas.create_texture_sprite(Size {w: 100, h: 100});
sub_sprite.set_texture(texture.clone(), Some(Position {x: 0, y: 0}), 1.0);
sub_sprite.set_position(Position {x: 0, y: 0});
sub_sprite.set_scale(2.0);
let mut sub_sprite2 = canvas.create_texture_sprite(Size {w: 200, h: 200});
sub_sprite2.set_texture(texture.clone(), Some(Position {x: 100, y: 0}), 1.0);
sub_sprite2.set_center(Position {x:100, y:100});
sub_sprite2.set_rotation(0.0);
sub_sprite2.set_position(Position {x: 0, y: 0});
let mut txt_sprite = canvas.create_text_sprite("00", Size {w: 100, h: 100}, 22.0);
txt_sprite.set_center(Position {x:0, y:0});
txt_sprite.set_position(Position {x:100, y:100});
txt_sprite.set_scale(1.0);
canvas.clear();
canvas.update();
@ -71,32 +92,54 @@ impl Application<ExampleState> for ExampleApp {
texture,
tex_sprite,
sub_sprite,
sub_sprite2,
txt_sprite,
last_instant,
last_offset: 0,
last_pos: Position::origin(),
last_pos: Position {x: 0, y: 0},
last_rot: 0.0,
frame_counter: 0,
})
}
fn tick(state: &mut ExampleState, canvas: &mut Canvas) -> Result<(), &'static str> {
use canvas::sprite::Sprite;
use canvas::{
sprite::Sprite,
utils::Color,
};
let now = Instant::now();
let elapsed = now.duration_since(state.last_instant).as_millis();
state.last_instant = now;
debug!("frame time: {}ms", elapsed);
state.frame_counter += 1;
if state.frame_counter >= 60 {
state.frame_counter = 0;
// state.txt_sprite.set_text(&format!("{}", elapsed));
// state.txt_sprite.set_text_size(elapsed as f32);
}
match state.frame_counter {
0 => state.txt_sprite.set_color(Color::RED),
20 => state.txt_sprite.set_color(Color::BLUE),
40 => state.txt_sprite.set_color(Color::GREEN),
_ => (),
}
//state.sub_sprite.for_each(|pix| unsafe {pix.flat = pix.flat.wrapping_add(1);});
state.last_offset += 1;
state.last_pos.y += 1;
// state.last_offset += 1;
//state.last_pos.x += 1;
//state.last_pos.y += 1;
state.last_rot += 1.0;
debug!("{:#?}", state.last_pos);
state.tex_sprite.set_texture(state.texture.clone(), None, state.last_rot/100.0);
state.sub_sprite.set_texture(state.texture.clone(),
Some(Position {x: state.last_offset, y: 0}), 1.0);
// state.sub_sprite.set_texture(state.texture.clone(),
// Some(Position {x: state.last_offset, y: 0}), 1.0);
state.sub_sprite.set_position(state.last_pos);
state.sub_sprite2.set_position(state.last_pos);
state.sub_sprite.set_rotation(state.last_rot);
state.sub_sprite2.set_rotation(state.last_rot + 45.0);
// state.txt_sprite.set_rotation(state.last_rot);
//state.sub_sprite.set_scale(state.last_rot/1000.0);
// inputs
@ -108,6 +151,7 @@ impl Application<ExampleState> for ExampleApp {
// unimplemented!();
//}
//
//
//match canvas.get_key_presses() {
// Key::A => unimplemented!(),
// _ => (),
@ -156,6 +200,8 @@ impl Application<ExampleState> for ExampleApp {
canvas.draw(&mut state.tex_sprite);
canvas.draw(&mut state.sub_sprite);
canvas.draw(&mut state.sub_sprite2);
canvas.draw(&mut state.txt_sprite);
canvas.update();
Ok(())

View File

@ -96,6 +96,10 @@ impl WgpuRenderer {
})
}
pub fn get_surface_size(&self) -> Size {
self.surface_size
}
pub fn clear(&mut self, color: Pixel) {
let view = self.create_texture_view();

View File

@ -16,8 +16,10 @@ pub const MATRIX_SIZE: usize = 48;//std::mem::size_of::<Matrix3<f32>>();
//--ModelMatrix struct------------------------------------------------------------------------------
pub struct ModelMatrix {
position: Position,
center: Position,
rotation: Deg<f32>,
scale: f32,
aspect_matrix: Matrix3<f32>,
uniform: Uniform<MATRIX_SIZE>,
is_synced: bool,
@ -26,19 +28,27 @@ pub struct ModelMatrix {
impl ModelMatrix {
pub fn new(renderer: &WgpuRenderer,
pos: Position,
rot: f32,
position: Position,
rotation: f32,
scale: f32)
-> Self
{
let surface_size: Vector2<f32> = renderer.get_surface_size().into();
//A factor 2 is used since the gpu coords go from -1.0 to 1.0 while the engine coords only
//go from 0 to 1
let aspect_matrix = Matrix3::from_nonuniform_scale(2.0 / surface_size.x,
2.0 / surface_size.y)
* Matrix3::from_translation(-surface_size / 2.0);
Self {
position: pos,
rotation: Deg (rot),
scale,
Self {
position,
center: Position::origin(),
rotation: Deg(rotation),
scale,
aspect_matrix,
uniform: Uniform::create(renderer, &renderer.matrix_layout),
is_synced: false,
uniform: Uniform::create(renderer, &renderer.matrix_layout),
is_synced: false,
}
}
@ -46,13 +56,8 @@ impl ModelMatrix {
Self::new(renderer, Position::origin(), 0.0, 1.0)
}
pub fn set_position(&mut self, pos: Position) {
self.position = pos;
self.is_synced = false;
}
pub fn set_rotation(&mut self, rot: f32) {
self.rotation = Deg (rot);
pub fn set_position(&mut self, position: Position) {
self.position = position;
self.is_synced = false;
}
@ -61,22 +66,37 @@ impl ModelMatrix {
self.is_synced = false;
}
pub fn set_rotation(&mut self, rotation: f32) {
self.rotation = Deg(rotation);
self.is_synced = false;
}
pub fn set_center(&mut self, center: Position) {
self.center = center;
self.is_synced = false;
}
pub fn get_uniform(&mut self) -> &mut Uniform<MATRIX_SIZE> {
use cgmath::{Basis3, Rotation3};
if self.is_synced == false {
let pos_vec = Vector2 {
x: self.position.x as f32,
y: self.position.y as f32,
};
let rotation_mat = Matrix3::from(Basis3::from_angle_z(self.rotation));
let scale_mat = Matrix3::from_scale(self.scale);
let translation_mat = Matrix3::from_translation(pos_vec);
let aspect_mat = Matrix3::from_nonuniform_scale(1.0/1280.0, 1.0/720.0);
let position = Matrix3::from_translation(self.position.into());
let scale = Matrix3::from_scale(self.scale);
let center = Matrix3::from_translation((self.center * -1.0).into());
let rotation = Matrix3::from(Basis3::from_angle_z(self.rotation));
//to be read in reverse: scale is applied first, then the center offset is applied in
//reverse, so that it lines up with the world's origin. The rotation is then applied
//around the world's origin (and ence, the center). FInally, the translation is applied
//before the aspect matrix can move use from window-space (w x h) to normalized space
//(-1.0 to 1.0)
let matrix = self.aspect_matrix * position * rotation * center * scale;
let matrix = aspect_mat * translation_mat * rotation_mat * scale_mat;
let mat_bytes: [u8; 36] = bytemuck::bytes_of(&matrix).try_into().unwrap();
//wgsl uses 16 bytes-aligned matrixes, but ours is 12 bytes-aligned. Fix that by adding
//4 paddings bytes after each 12 bytes
let mut bytes = [0; 48];
for i in 0..12 {
bytes[i] = mat_bytes[i];

View File

@ -123,7 +123,8 @@ where
}
);
let index_buffer = device.create_buffer( &wgpu_types::BufferDescriptor {
let index_buffer = device.create_buffer(
&wgpu_types::BufferDescriptor {
label: Some("Index Buffer"),
size: (I_NB * size_of::<u16>()) as u64,
usage: Usages::INDEX | Usages::COPY_DST,

View File

@ -27,19 +27,22 @@ use crate::{
/// well as the unique function necessary for it to be rendered
pub trait Sprite {
/// Set the position of the [Sprite] on the screen
fn set_position(&mut self, pos: Position);
/// Sets the position of the [`Sprite`] on the screen
fn set_position(&mut self, position: Position);
/// Set the rotation of the [Sprite] on the screen
fn set_rotation(&mut self, rot: f32);
/// Sets the center of the [`Sprite`] for rotations as well as translations
fn set_center(&mut self, center: Position);
/// Set the alpha of the [Sprite] on the screen
/// Sets the rotation of the [`Sprite`] on the screen
fn set_rotation(&mut self, rotation: f32);
/// Sets the alpha of the [`Sprite`] on the screen
fn set_alpha(&mut self, alpha: u8);
/// Set the scale of the [Sprite] on the screen
/// Sets the scale of the [`Sprite`] on the screen
fn set_scale(&mut self, scale: f32);
/// Renders the [Sprite] using the given rendering context
/// Renders the [`Sprite`] using the given rendering context
fn render(&mut self, renderer: &mut WgpuRenderer);
}

View File

@ -14,12 +14,12 @@ struct VertexOutput {
var<uniform> model_matrix: mat3x3<f32>;
@vertex
fn vs_main(model: VertexInput) -> VertexOutput {
fn vs_main(vertex: VertexInput) -> VertexOutput {
var out: VertexOutput;
out.tex_coords = model.tex_coords;
out.clip_position
= vec4<f32>(model_matrix * vec3<f32>(model.position, 1.0), 1.0);
out.tex_coords = vertex.tex_coords;
out.clip_position
= vec4<f32>(model_matrix * vec3<f32>(vertex.position, 1.0), 1.0);
return out;
}

View File

@ -35,11 +35,15 @@ impl ShapeSprite {
impl Sprite for ShapeSprite {
fn set_position(&mut self, _pos: Position) {
fn set_position(&mut self, _position: Position) {
todo!();
}
fn set_rotation(&mut self, _rot: f32) {
fn set_center(&mut self, _center: Position) {
todo!();
}
fn set_rotation(&mut self, _rotation: f32) {
todo!();
}

View File

@ -6,52 +6,174 @@ use log::{debug, error, info, trace, warn};
use crate::{
renderer::WgpuRenderer,
sprite::Sprite,
utils::{Pixel, Position, Size},
utils::{Pixel, Color, Position, Size},
};
use super::TextureSprite;
//--External imports--------------------------------------------------------------------------------
use cgmath::Matrix4;
//--TextSprite struct-------------------------------------------------------------------------------
#[allow(dead_code)]
pub struct TextSprite {
matrix: Matrix4<f32>,
size: Size,
text: &'static str, //TODO: temporary
texture_sprite: TextureSprite,
text: String,
text_size: f32,
text_color: Pixel,
font: fontdue::Font,
layout: fontdue::layout::Layout,
text_generation_needed: bool,
}
impl TextSprite {
pub fn set_text(&mut self, _text: &'static str) {
todo!();
pub fn new(text: &'static str, size: Size, text_size: f32, renderer: &WgpuRenderer) -> Self {
use crate::{
renderer::Texture,
texture::TextureHandle,
};
use fontdue::layout::{CoordinateSystem, Layout, TextStyle};
let font = Self::configure_font(text_size);
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
//configure text layout to fit sprite size, keep default settings
layout.append(&[&font], &TextStyle::new(text, text_size, 0));
//draw text to the texture
let mut raw_texture : Vec::<Pixel>
= vec![Color::NONE; (size.h * size.w).try_into().unwrap()];
//draw each glyph at the corresponding position on the texture
for glyph in layout.glyphs() {
let (_metrics, bitmap) = font.rasterize_config(glyph.key);
let glyph_x = glyph.x as usize;
let glyph_y = glyph.y as usize;
let size_w = size.w as usize;
let size_h = size.h as usize;
//only try to draw a glyph if its origin fits in the texture
if glyph_x < size_w && glyph_y < size_h {
let origin = glyph_x + size_w * glyph_y;
//glyphs that do not fit on the texture are cropped at the edge of the latter
for x in 0..std::cmp::min(glyph.width, size_w - glyph_x) {
for y in 0..std::cmp::min(glyph.height, size_h - glyph_y) {
raw_texture[origin + x + y * size_w]
= Color::BLACK.with_alpha(bitmap[x + y * glyph.width]);
} } } }
//create the texture
let texture = Texture::create(renderer, bytemuck::cast_slice(&raw_texture), size);
let texture_handle = TextureHandle::from_texture(texture);
let texture_sprite = TextureSprite::new(texture_handle, size, &renderer);
Self {
texture_sprite,
text: text.to_string(),
text_size,
text_color: Color::BLACK,
font,
layout,
text_generation_needed: false,
}
}
pub fn set_color(&mut self, _color: Pixel) {
todo!();
pub fn set_text(&mut self, text: &str) {
self.text = text.to_string();
self.text_generation_needed = true;
}
pub fn set_text_size(&mut self, text_size: f32) {
self.text_size = text_size;
self.text_generation_needed = true;
}
pub fn set_color(&mut self, color: Pixel) {
self.text_color = color;
self.text_generation_needed = true;
}
fn generate_text(&mut self) {
self.layout.clear();
self.layout.append(&[&self.font],
&fontdue::layout::TextStyle::new(&self.text, self.text_size, 0));
let size = self.texture_sprite.get_size();
self.texture_sprite.fill(Color::NONE);
//draw each glyph at the corresponding position on the texture
for glyph in self.layout.glyphs() {
let (_metrics, bitmap) = self.font.rasterize_config(glyph.key);
let glyph_x = glyph.x as usize;
let glyph_y = glyph.y as usize;
let size_w = size.w as usize;
let size_h = size.h as usize;
//only try to draw a glyph if its origin fits in the texture
if glyph_x < size_w && glyph_y < size_h {
//glyphs that do not fit on the texture are cropped at the edge of the latter
for x in 0..std::cmp::min(glyph.width, size_w - glyph_x) {
for y in 0..std::cmp::min(glyph.height, size_h - glyph_y) {
self.texture_sprite.set_pixel(
Position {
x: (glyph_x + x) as i32,
y: (glyph_y + y) as i32,
},
self.text_color.with_alpha(bitmap[x + y * glyph.width])
);
} } } }
}
fn configure_font(text_size: f32) -> fontdue::Font
{
let font = include_bytes!("../../assets/DejaVuSansMono.ttf");
let settings = fontdue::FontSettings {
scale: text_size,
..fontdue::FontSettings::default()
};
fontdue::Font::from_bytes(&font[..], settings).unwrap()
}
}
impl Sprite for TextSprite {
fn set_position(&mut self, _pos: Position) {
todo!();
fn set_position(&mut self, position: Position) {
self.texture_sprite.set_position(position);
}
fn set_rotation(&mut self, _rot: f32) {
todo!();
fn set_center(&mut self, center: Position) {
self.texture_sprite.set_center(center);
}
fn set_alpha(&mut self, _alpha: u8) {
todo!();
fn set_rotation(&mut self, rotation: f32) {
self.texture_sprite.set_rotation(rotation);
}
fn set_scale(&mut self, _scale: f32) {
todo!();
fn set_alpha(&mut self, alpha: u8) {
self.texture_sprite.set_alpha(alpha);
}
fn render(&mut self, _renderer: &mut WgpuRenderer) {
todo!();
fn set_scale(&mut self, scale: f32) {
self.texture_sprite.set_scale(scale);
}
fn render(&mut self, renderer: &mut WgpuRenderer) {
// generate text if any setting changed
if self.text_generation_needed == true {
self.generate_text();
self.text_generation_needed = false;
}
self.texture_sprite.render(renderer);
}
}

View File

@ -91,11 +91,20 @@ impl TextureSprite {
self.texture.for_each_in_area(func, self.offset, self.inner_size);
}
pub fn fill(&mut self, pixel: Pixel) {
self.texture.fill(pixel);
}
pub fn get_size(&self) -> Size {
self.texture.get_size()
}
fn update_vertices(&mut self, renderer: &WgpuRenderer) {
debug!("Updating vertices...");
let size = self.texture.get_size();
// compute normalized coordinates
let x_size = self.inner_size.w as f32 / size.w as f32 * self.scale;
let y_size = self.inner_size.h as f32 / size.h as f32 * self.scale;
@ -103,8 +112,10 @@ impl TextureSprite {
let y_offset = self.offset.y as f32 / size.h as f32;
// compute mesh size
let w = self.inner_size.w as f32;
let h = self.inner_size.h as f32;
//divide by 2 since the quad's coords go from -0.5 to 0.5
let w = self.inner_size.w as f32 / 2.0;
let h = self.inner_size.h as f32 / 2.0;
let mesh = [
TextureVertex {
@ -133,12 +144,16 @@ impl TextureSprite {
impl Sprite for TextureSprite {
fn set_position(&mut self, pos: Position) {
self.matrix.set_position(pos);
fn set_position(&mut self, position: Position) {
self.matrix.set_position(position);
}
fn set_rotation(&mut self, rot: f32) {
self.matrix.set_rotation(rot);
fn set_center(&mut self, center: Position) {
self.matrix.set_center(center);
}
fn set_rotation(&mut self, rotation: f32) {
self.matrix.set_rotation(rotation);
}
fn set_alpha(&mut self, _alpha: u8) {
@ -235,7 +250,7 @@ fn initialize_pipeline(renderer: &WgpuRenderer) -> wgpu::RenderPipeline {
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format: renderer.config.format,
blend: Some(wgpu::BlendState::REPLACE),
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
}),

View File

@ -30,7 +30,7 @@ impl TextureHandle {
//TODO check pos ?
let mut texture = self.texture.borrow_mut();
let width = texture.size.w;
let width = texture.size.w as i32;
texture.buffer[(pos.x + pos.y*width) as usize] = pix;
texture.is_synced = false;
}
@ -51,15 +51,21 @@ impl TextureHandle {
{
//TODO check offset and pos ?
let mut texture = self.texture.borrow_mut();
let width = texture.size.w;
for x in offset.x..(offset.x + size.w) {
for y in offset.y..(offset.y + size.h) {
let width = texture.size.w as i32;
for x in offset.x..(offset.x + size.w as i32) {
for y in offset.y..(offset.y + size.h as i32) {
func(&mut texture.buffer[(x + y*width) as usize]);
}
}
texture.is_synced = false;
}
pub fn fill (&mut self, pixel: Pixel) {
let mut texture = self.texture.borrow_mut();
texture.buffer.fill(pixel);
texture.is_synced = false;
}
pub fn texture(&self) -> &Rc<RefCell<Texture>> {
//TODO improve that
&self.texture
@ -70,4 +76,3 @@ impl TextureHandle {
}
}

View File

@ -3,13 +3,13 @@ use log::{debug, error, info, trace, warn};
use winit;
use cgmath::Vector3;
use cgmath::{Vector3, Vector2};
//--Position struct---------------------------------------------------------------------------------
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub struct Position {
pub x: u32,
pub y: u32,
pub x: i32,
pub y: i32,
}
impl Position {
@ -23,12 +23,19 @@ impl Position {
}
impl From<Position> for Vector3<f32> {
fn from(pos: Position) -> Self {
Self::new(pos.x as f32, pos.y as f32, 0.0)
}
}
impl From<Position> for Vector2<f32> {
fn from(pos: Position) -> Self {
Self::new(pos.x as f32, pos.y as f32)
}
}
impl std::ops::Add for Position {
type Output = Self;
@ -40,6 +47,17 @@ impl std::ops::Add for Position {
}
}
impl std::ops::Mul<f32> for Position {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Position {
x: ((self.x as f32) * rhs) as i32,
y: ((self.y as f32) * rhs) as i32,
}
}
}
//--Size struct-------------------------------------------------------------------------------------
#[derive(Copy, Clone)]
pub struct Size {
@ -52,7 +70,7 @@ impl From<Size> for winit::dpi::Size {
fn from(size: Size) -> Self {
winit::dpi::Size::Physical (
winit::dpi::PhysicalSize {
width: size.w,
width: size.w,
height: size.h,
})
}
@ -79,6 +97,13 @@ impl From<winit::dpi::PhysicalSize<u32>> for Size {
}
}
impl From<Size> for Vector2<f32> {
fn from(size: Size) -> Self {
Self::new(size.w as f32, size.h as f32)
}
}
//--Pixel struct------------------------------------------------------------------------------------
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
@ -98,13 +123,23 @@ pub union Pixel {
unsafe impl bytemuck::Pod for Pixel {}
impl Pixel {
pub fn rgb(r: u8, g: u8, b: u8) -> Pixel {
Pixel {
rgba: Rgba{r, g, b, a: 255},
}
}
pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> Pixel {
Pixel {
rgba: Rgba{r, g, b, a},
}
}
pub fn with_alpha(self, a: u8) -> Pixel {
unsafe { Pixel::rgba(self.rgba.r, self.rgba.g, self.rgba.b, a) }
}
pub fn to_rgba(&self) -> Rgba {
unsafe { self.rgba }
}
@ -117,10 +152,10 @@ pub struct Color;
impl Color {
pub const NONE: Pixel = Pixel {flat: 0x00000000};
pub const WHITE: Pixel = Pixel {flat: 0xffffffff};
pub const BLACK: Pixel = Pixel {flat: 0x000000ff};
pub const BLACK: Pixel = Pixel {flat: 0xff000000};
pub const RED: Pixel = Pixel {flat: 0xff0000ff};
pub const GREEN: Pixel = Pixel {flat: 0x00ff00ff};
pub const BLUE: Pixel = Pixel {flat: 0x0000ffff};
pub const GREEN: Pixel = Pixel {flat: 0xff00ff00};
pub const BLUE: Pixel = Pixel {flat: 0xffff0000};
}