Compare commits
3 Commits
0a637f22fc
...
0ec78da7b5
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ec78da7b5 | |||
| b327996d89 | |||
| dcb596806c |
@ -28,7 +28,7 @@ pub trait Application<S> {
|
|||||||
//--Canvas struct-----------------------------------------------------------------------------------
|
//--Canvas struct-----------------------------------------------------------------------------------
|
||||||
pub struct Canvas {
|
pub struct Canvas {
|
||||||
default_texture: TextureHandle,
|
default_texture: TextureHandle,
|
||||||
clear_color: Pixel,
|
clear_color: Color,
|
||||||
|
|
||||||
renderer: WgpuRenderer,
|
renderer: WgpuRenderer,
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ impl Canvas {
|
|||||||
sprite.render(&mut self.renderer);
|
sprite.render(&mut self.renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_clear_color(&mut self, color: Pixel) {
|
pub fn set_clear_color(&mut self, color: Color) {
|
||||||
self.clear_color = color;
|
self.clear_color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
src/main.rs
29
src/main.rs
@ -55,8 +55,8 @@ 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::{
|
use canvas::{
|
||||||
utils::Size,
|
utils::{Size, Color},
|
||||||
sprite::Sprite,
|
sprite::{Sprite, Center},
|
||||||
};
|
};
|
||||||
|
|
||||||
//// 20 x 20 sprite of a picture
|
//// 20 x 20 sprite of a picture
|
||||||
@ -64,23 +64,24 @@ impl Application<ExampleState> for ExampleApp {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let mut tex_sprite = canvas.create_texture_sprite(Size {w: 1280, h: 720});
|
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_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_center(Center::BotLeft);
|
||||||
tex_sprite.set_position(Position {x: 0, y: 0});
|
tex_sprite.set_position(Position {x: 0, y: 0});
|
||||||
|
|
||||||
let mut sub_sprite = canvas.create_texture_sprite(Size {w: 100, h: 100});
|
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_texture(texture.clone(), Some(Position {x: 0, y: 0}), 1.0);
|
||||||
sub_sprite.set_position(Position {x: 0, y: 0});
|
sub_sprite.set_position(Position {x: 100, y: 100});
|
||||||
sub_sprite.set_scale(2.0);
|
sub_sprite.set_scale(2.0);
|
||||||
|
|
||||||
let mut sub_sprite2 = canvas.create_texture_sprite(Size {w: 200, h: 200});
|
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_texture(texture.clone(), Some(Position {x: 100, y: 0}), 1.0);
|
||||||
sub_sprite2.set_center(Position {x:100, y:100});
|
sub_sprite2.set_center(Center::Custom(Position {x:100, y:100}));
|
||||||
sub_sprite2.set_rotation(0.0);
|
sub_sprite2.set_rotation(0.0);
|
||||||
sub_sprite2.set_position(Position {x: 0, y: 0});
|
sub_sprite2.set_position(Position {x: 100, y: 100});
|
||||||
|
|
||||||
let mut txt_sprite = canvas.create_text_sprite("00", Size {w: 100, h: 100}, 22.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_center(Center::BotLeft);
|
||||||
txt_sprite.set_position(Position {x:100, y:100});
|
txt_sprite.set_position(Position {x:100, y:100});
|
||||||
|
txt_sprite.set_bg_color(Color::WHITE);
|
||||||
txt_sprite.set_scale(1.0);
|
txt_sprite.set_scale(1.0);
|
||||||
|
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
@ -115,13 +116,13 @@ impl Application<ExampleState> for ExampleApp {
|
|||||||
state.frame_counter += 1;
|
state.frame_counter += 1;
|
||||||
if state.frame_counter >= 60 {
|
if state.frame_counter >= 60 {
|
||||||
state.frame_counter = 0;
|
state.frame_counter = 0;
|
||||||
// state.txt_sprite.set_text(&format!("{}", elapsed));
|
state.txt_sprite.set_text(&format!("{}", elapsed));
|
||||||
// state.txt_sprite.set_text_size(elapsed as f32);
|
state.txt_sprite.set_text_size(elapsed as f32);
|
||||||
}
|
}
|
||||||
match state.frame_counter {
|
match state.frame_counter {
|
||||||
0 => state.txt_sprite.set_color(Color::RED),
|
0 => state.txt_sprite.set_fg_color(Color::RED),
|
||||||
20 => state.txt_sprite.set_color(Color::BLUE),
|
20 => state.txt_sprite.set_fg_color(Color::BLUE),
|
||||||
40 => state.txt_sprite.set_color(Color::GREEN),
|
40 => state.txt_sprite.set_fg_color(Color::GREEN),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
//state.sub_sprite.for_each(|pix| unsafe {pix.flat = pix.flat.wrapping_add(1);});
|
//state.sub_sprite.for_each(|pix| unsafe {pix.flat = pix.flat.wrapping_add(1);});
|
||||||
@ -134,8 +135,8 @@ impl Application<ExampleState> for ExampleApp {
|
|||||||
state.tex_sprite.set_texture(state.texture.clone(), None, state.last_rot/100.0);
|
state.tex_sprite.set_texture(state.texture.clone(), None, state.last_rot/100.0);
|
||||||
// state.sub_sprite.set_texture(state.texture.clone(),
|
// state.sub_sprite.set_texture(state.texture.clone(),
|
||||||
// Some(Position {x: state.last_offset, y: 0}), 1.0);
|
// Some(Position {x: state.last_offset, y: 0}), 1.0);
|
||||||
state.sub_sprite.set_position(state.last_pos);
|
// state.sub_sprite.set_position(state.last_pos);
|
||||||
state.sub_sprite2.set_position(state.last_pos);
|
// state.sub_sprite2.set_position(state.last_pos);
|
||||||
state.sub_sprite.set_rotation(state.last_rot);
|
state.sub_sprite.set_rotation(state.last_rot);
|
||||||
state.sub_sprite2.set_rotation(state.last_rot + 45.0);
|
state.sub_sprite2.set_rotation(state.last_rot + 45.0);
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use log::{debug, error, info, trace, warn};
|
|||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::HasRawWindowHandle;
|
||||||
use wgpu;
|
use wgpu;
|
||||||
|
|
||||||
use crate::utils::{Pixel, Size};
|
use crate::utils::{Color, Size};
|
||||||
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ impl WgpuRenderer {
|
|||||||
self.surface_size
|
self.surface_size
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self, color: Pixel) {
|
pub fn clear(&mut self, color: Color) {
|
||||||
|
|
||||||
let view = self.create_texture_view();
|
let view = self.create_texture_view();
|
||||||
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
@ -225,16 +225,23 @@ impl WgpuRenderer {
|
|||||||
|
|
||||||
//--Renderer struct utils---------------------------------------------------------------------------
|
//--Renderer struct utils---------------------------------------------------------------------------
|
||||||
|
|
||||||
impl From<Pixel> for wgpu::Color {
|
//impl From<Pixel> for wgpu::Color {
|
||||||
|
//
|
||||||
|
// fn from(value: Pixel) -> Self {
|
||||||
|
// Self {
|
||||||
|
// r: f64::from(value.r) / 255.0,
|
||||||
|
// g: f64::from(value.g) / 255.0,
|
||||||
|
// b: f64::from(value.b) / 255.0,
|
||||||
|
// a: f64::from(value.a) / 255.0,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
fn from(pix: Pixel) -> Self {
|
impl From<Color> for wgpu::Color {
|
||||||
let rgba = pix.to_rgba();
|
|
||||||
Self {
|
fn from(value: Color) -> Self {
|
||||||
r: (rgba.r as f64) / 255.0,
|
value.into_wgpu_color()
|
||||||
g: (rgba.g as f64) / 255.0,
|
}
|
||||||
b: (rgba.b as f64) / 255.0,
|
|
||||||
a: (rgba.a as f64) / 255.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,16 @@ use crate::{
|
|||||||
|
|
||||||
//--External imports--------------------------------------------------------------------------------
|
//--External imports--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//--Center enum-------------------------------------------------------------------------------------
|
||||||
|
pub enum Center {
|
||||||
|
Geometric,
|
||||||
|
TopLeft,
|
||||||
|
TopRight,
|
||||||
|
BotLeft,
|
||||||
|
BotRight,
|
||||||
|
Custom(Position),
|
||||||
|
}
|
||||||
|
|
||||||
//--Sprite trait------------------------------------------------------------------------------------
|
//--Sprite trait------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// The interface for everything that can be rendered by the engine.
|
/// The interface for everything that can be rendered by the engine.
|
||||||
@ -31,7 +41,7 @@ pub trait Sprite {
|
|||||||
fn set_position(&mut self, position: Position);
|
fn set_position(&mut self, position: Position);
|
||||||
|
|
||||||
/// Sets the center of the [`Sprite`] for rotations as well as translations
|
/// Sets the center of the [`Sprite`] for rotations as well as translations
|
||||||
fn set_center(&mut self, center: Position);
|
fn set_center(&mut self, center: Center);
|
||||||
|
|
||||||
/// Sets the rotation of the [`Sprite`] on the screen
|
/// Sets the rotation of the [`Sprite`] on the screen
|
||||||
fn set_rotation(&mut self, rotation: f32);
|
fn set_rotation(&mut self, rotation: f32);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use log::{debug, error, info, trace, warn};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
renderer::WgpuRenderer,
|
renderer::WgpuRenderer,
|
||||||
sprite::Sprite,
|
sprite::{Sprite, Center},
|
||||||
shape::Shape,
|
shape::Shape,
|
||||||
utils::{Pixel, Position, Size},
|
utils::{Pixel, Position, Size},
|
||||||
};
|
};
|
||||||
@ -39,7 +39,7 @@ impl Sprite for ShapeSprite {
|
|||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_center(&mut self, _center: Position) {
|
fn set_center(&mut self, _center: Center) {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use log::{debug, error, info, trace, warn};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
renderer::WgpuRenderer,
|
renderer::WgpuRenderer,
|
||||||
sprite::Sprite,
|
sprite::{Sprite, Center},
|
||||||
utils::{Pixel, Color, Position, Size},
|
utils::{Pixel, Color, Position, Size},
|
||||||
};
|
};
|
||||||
use super::TextureSprite;
|
use super::TextureSprite;
|
||||||
@ -18,7 +18,8 @@ pub struct TextSprite {
|
|||||||
|
|
||||||
text: String,
|
text: String,
|
||||||
text_size: f32,
|
text_size: f32,
|
||||||
text_color: Pixel,
|
fg_color: Color,
|
||||||
|
bg_color: Color,
|
||||||
|
|
||||||
font: fontdue::Font,
|
font: fontdue::Font,
|
||||||
layout: fontdue::layout::Layout,
|
layout: fontdue::layout::Layout,
|
||||||
@ -41,29 +42,8 @@ impl TextSprite {
|
|||||||
layout.append(&[&font], &TextStyle::new(text, text_size, 0));
|
layout.append(&[&font], &TextStyle::new(text, text_size, 0));
|
||||||
|
|
||||||
//draw text to the texture
|
//draw text to the texture
|
||||||
let mut raw_texture : Vec::<Pixel>
|
let raw_texture : Vec::<Pixel>
|
||||||
= vec![Color::NONE; (size.h * size.w).try_into().unwrap()];
|
= vec![Color::NONE.into(); (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
|
//create the texture
|
||||||
let texture = Texture::create(renderer, bytemuck::cast_slice(&raw_texture), size);
|
let texture = Texture::create(renderer, bytemuck::cast_slice(&raw_texture), size);
|
||||||
@ -75,10 +55,11 @@ impl TextSprite {
|
|||||||
texture_sprite,
|
texture_sprite,
|
||||||
text: text.to_string(),
|
text: text.to_string(),
|
||||||
text_size,
|
text_size,
|
||||||
text_color: Color::BLACK,
|
fg_color: Color::BLACK,
|
||||||
|
bg_color: Color::NONE,
|
||||||
font,
|
font,
|
||||||
layout,
|
layout,
|
||||||
text_generation_needed: false,
|
text_generation_needed: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,9 +73,18 @@ impl TextSprite {
|
|||||||
self.text_generation_needed = true;
|
self.text_generation_needed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_color(&mut self, color: Pixel) {
|
pub fn set_fg_color(&mut self, color: Color) {
|
||||||
self.text_color = color;
|
if self.fg_color != color {
|
||||||
self.text_generation_needed = true;
|
self.fg_color = color;
|
||||||
|
self.text_generation_needed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_bg_color(&mut self, color: Color) {
|
||||||
|
if self.bg_color != color {
|
||||||
|
self.bg_color = color;
|
||||||
|
self.text_generation_needed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_text(&mut self) {
|
fn generate_text(&mut self) {
|
||||||
@ -104,7 +94,7 @@ impl TextSprite {
|
|||||||
&fontdue::layout::TextStyle::new(&self.text, self.text_size, 0));
|
&fontdue::layout::TextStyle::new(&self.text, self.text_size, 0));
|
||||||
|
|
||||||
let size = self.texture_sprite.get_size();
|
let size = self.texture_sprite.get_size();
|
||||||
self.texture_sprite.fill(Color::NONE);
|
self.texture_sprite.fill(self.bg_color.into());
|
||||||
|
|
||||||
//draw each glyph at the corresponding position on the texture
|
//draw each glyph at the corresponding position on the texture
|
||||||
for glyph in self.layout.glyphs() {
|
for glyph in self.layout.glyphs() {
|
||||||
@ -122,12 +112,15 @@ impl TextSprite {
|
|||||||
for x in 0..std::cmp::min(glyph.width, size_w - glyph_x) {
|
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) {
|
for y in 0..std::cmp::min(glyph.height, size_h - glyph_y) {
|
||||||
|
|
||||||
|
self.fg_color.set_alpha(bitmap[x + y * glyph.width]);
|
||||||
|
|
||||||
self.texture_sprite.set_pixel(
|
self.texture_sprite.set_pixel(
|
||||||
Position {
|
Position {
|
||||||
x: (glyph_x + x) as i32,
|
x: (glyph_x + x) as i32,
|
||||||
y: (glyph_y + y) as i32,
|
y: (glyph_y + y) as i32,
|
||||||
},
|
},
|
||||||
self.text_color.with_alpha(bitmap[x + y * glyph.width])
|
|
||||||
|
Color::alpha_blend(&self.fg_color, &self.bg_color).into()
|
||||||
);
|
);
|
||||||
} } } }
|
} } } }
|
||||||
}
|
}
|
||||||
@ -149,7 +142,7 @@ impl Sprite for TextSprite {
|
|||||||
self.texture_sprite.set_position(position);
|
self.texture_sprite.set_position(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_center(&mut self, center: Position) {
|
fn set_center(&mut self, center: Center) {
|
||||||
self.texture_sprite.set_center(center);
|
self.texture_sprite.set_center(center);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use log::{debug, error, info, trace, warn};
|
|||||||
|
|
||||||
//--Internal imports--------------------------------------------------------------------------------
|
//--Internal imports--------------------------------------------------------------------------------
|
||||||
|
|
||||||
use super::Sprite;
|
use super::{Sprite, Center};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
texture::TextureHandle,
|
texture::TextureHandle,
|
||||||
@ -148,8 +148,28 @@ impl Sprite for TextureSprite {
|
|||||||
self.matrix.set_position(position);
|
self.matrix.set_position(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_center(&mut self, center: Position) {
|
fn set_center(&mut self, center: Center) {
|
||||||
self.matrix.set_center(center);
|
let center_pos = match center {
|
||||||
|
Center::Geometric => Position {x: 0, y: 0},
|
||||||
|
Center::TopLeft => Position {
|
||||||
|
x: -(self.inner_size.w as i32) / 2,
|
||||||
|
y: (self.inner_size.h as i32) / 2
|
||||||
|
},
|
||||||
|
Center::TopRight => Position {
|
||||||
|
x: (self.inner_size.w as i32) / 2,
|
||||||
|
y: (self.inner_size.h as i32) / 2
|
||||||
|
},
|
||||||
|
Center::BotLeft => Position {
|
||||||
|
x: -(self.inner_size.w as i32) / 2,
|
||||||
|
y: -(self.inner_size.h as i32) / 2
|
||||||
|
},
|
||||||
|
Center::BotRight => Position {
|
||||||
|
x: (self.inner_size.w as i32) / 2,
|
||||||
|
y: -(self.inner_size.h as i32) / 2
|
||||||
|
},
|
||||||
|
Center::Custom(pos) => pos,
|
||||||
|
};
|
||||||
|
self.matrix.set_center(center_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_rotation(&mut self, rotation: f32) {
|
fn set_rotation(&mut self, rotation: f32) {
|
||||||
|
|||||||
133
src/utils.rs
133
src/utils.rs
@ -105,57 +105,110 @@ impl From<Size> for Vector2<f32> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--Pixel struct------------------------------------------------------------------------------------
|
//--Pixel struct------------------------------------------------------------------------------------
|
||||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
#[repr(packed, C)]
|
||||||
#[repr(C)]
|
#[derive(Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
pub struct Rgba {
|
pub struct Pixel {
|
||||||
pub r: u8,
|
pub r: u8,
|
||||||
pub g: u8,
|
pub g: u8,
|
||||||
pub b: u8,
|
pub b: u8,
|
||||||
pub a: u8,
|
pub a: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, bytemuck::Zeroable)]
|
impl From<Color> for Pixel {
|
||||||
pub union Pixel {
|
|
||||||
pub flat: u32,
|
|
||||||
rgba: Rgba,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl bytemuck::Pod for Pixel {}
|
fn from(value: Color) -> Self {
|
||||||
|
value.into_pixel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Pixel {
|
impl Pixel {
|
||||||
|
|
||||||
pub fn rgb(r: u8, g: u8, b: u8) -> Pixel {
|
pub const fn from_hex(hex: u32) -> Self {
|
||||||
Pixel {
|
let bytes = hex.to_be_bytes();
|
||||||
rgba: Rgba{r, g, b, a: 255},
|
Self { r: bytes[0], g: bytes[1], b: bytes[2], a: bytes[3] }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--Color values------------------------------------------------------------------------------------
|
//--Color values------------------------------------------------------------------------------------
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct Color;
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub struct Color {
|
||||||
impl Color {
|
r: f32,
|
||||||
pub const NONE: Pixel = Pixel {flat: 0x00000000};
|
g: f32,
|
||||||
pub const WHITE: Pixel = Pixel {flat: 0xffffffff};
|
b: f32,
|
||||||
pub const BLACK: Pixel = Pixel {flat: 0xff000000};
|
a: f32,
|
||||||
pub const RED: Pixel = Pixel {flat: 0xff0000ff};
|
|
||||||
pub const GREEN: Pixel = Pixel {flat: 0xff00ff00};
|
|
||||||
pub const BLUE: Pixel = Pixel {flat: 0xffff0000};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Pixel> for Color {
|
||||||
|
|
||||||
|
fn from(value: Pixel) -> Self {
|
||||||
|
Self {
|
||||||
|
r: f32::from(value.r) / 255.0,
|
||||||
|
g: f32::from(value.g) / 255.0,
|
||||||
|
b: f32::from(value.b) / 255.0,
|
||||||
|
a: f32::from(value.a) / 255.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Color {
|
||||||
|
|
||||||
|
pub fn set_alpha(&mut self, a: u8) {
|
||||||
|
self.a = f32::from(a) / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||||
|
Pixel { r, g, b, a: 255 }.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||||
|
Pixel { r, g, b, a }.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_hex(hex: u32) -> Self {
|
||||||
|
Pixel::from_hex(hex).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_pixel(self) -> Pixel {
|
||||||
|
//unsafe block is used here for "to_int_unchecked" since the struct's invariant garentees
|
||||||
|
//that the values are within [0.0, 1.0], meaning we won't ever overflow an u8
|
||||||
|
unsafe {
|
||||||
|
Pixel {
|
||||||
|
r: self.r.to_int_unchecked::<u8>() * 255,
|
||||||
|
g: self.g.to_int_unchecked::<u8>() * 255,
|
||||||
|
b: self.b.to_int_unchecked::<u8>() * 255,
|
||||||
|
a: self.a.to_int_unchecked::<u8>() * 255,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_wgpu_color(self) -> wgpu::Color {
|
||||||
|
wgpu::Color {
|
||||||
|
r: f64::from(self.r),
|
||||||
|
g: f64::from(self.g),
|
||||||
|
b: f64::from(self.b),
|
||||||
|
a: f64::from(self.a),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alpha_blend(&self, other: &Self) -> Self {
|
||||||
|
//apply alpha compisting's "over" operator, see
|
||||||
|
//[https://en.wikipedia.org/wiki/Alpha_compositing] for more detail
|
||||||
|
let a = self.a + other.a * (1.0 - self.a);
|
||||||
|
Self {
|
||||||
|
r: (self.r * self.a + other.r * other.a * (1.0 - self.a)) / a,
|
||||||
|
g: (self.g * self.a + other.g * other.a * (1.0 - self.a)) / a,
|
||||||
|
b: (self.b * self.a + other.b * other.a * (1.0 - self.a)) / a,
|
||||||
|
a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const NONE: Self = Self {r: 0.0, g: 0.0, b: 0.0, a: 0.0};
|
||||||
|
pub const WHITE: Self = Self {r: 1.0, g: 1.0, b: 1.0, a: 1.0};
|
||||||
|
pub const BLACK: Self = Self {r: 0.0, g: 0.0, b: 0.0, a: 1.0};
|
||||||
|
pub const RED: Self = Self {r: 1.0, g: 0.0, b: 0.0, a: 1.0};
|
||||||
|
pub const GREEN: Self = Self {r: 0.0, g: 1.0, b: 0.0, a: 1.0};
|
||||||
|
pub const BLUE: Self = Self {r: 0.0, g: 0.0, b: 1.0, a: 1.0};
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user