lets try using rustfmt again ...
i unfortunately feel like i should really force myself to use rustfmt even though i very much dislike it. most rust developers seem to use it so i should probably get used to it ... however, case-in-point for me is the amount of times i used either #[rustfmt::skip] or adding a blank `//` comment to force separate lines, etc, really proves how terrible basing almost all of your formatting rules on arbitrary length thresholds really is. code formatting is far more subjective than that.
This commit is contained in:
parent
36c4cc1a41
commit
ceaefad030
|
@ -30,15 +30,13 @@ pub struct SineWaveGenerator {
|
|||
|
||||
impl SineWaveGenerator {
|
||||
pub fn new() -> Self {
|
||||
SineWaveGenerator {
|
||||
t: 0
|
||||
}
|
||||
SineWaveGenerator { t: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl AudioGenerator for SineWaveGenerator {
|
||||
fn gen_sample(&mut self, _position: usize) -> Option<u8> {
|
||||
const MAX_TIME: usize = AUDIO_FREQUENCY_22KHZ as usize * 3; // 3 seconds
|
||||
const MAX_TIME: usize = AUDIO_FREQUENCY_22KHZ as usize * 3; // 3 seconds
|
||||
if self.t < MAX_TIME {
|
||||
let sample = (self.t as f64 * 0.25).sin() * 80.0;
|
||||
self.t += 1;
|
||||
|
@ -51,7 +49,7 @@ impl AudioGenerator for SineWaveGenerator {
|
|||
|
||||
fn main() -> Result<()> {
|
||||
let config = DosLikeConfig::new();
|
||||
let mut system = SystemBuilder::new()
|
||||
let mut system = SystemBuilder::new() //
|
||||
.window_title("Audio Playback")
|
||||
.vsync(true)
|
||||
.build(config)?;
|
||||
|
@ -169,21 +167,20 @@ fn main() -> Result<()> {
|
|||
|
||||
system.res.video.print_string(
|
||||
&format!("Volume: {:2.2}", volume),
|
||||
16, 16, FontRenderOpts::Color(10), &system.res.font
|
||||
16,
|
||||
16,
|
||||
FontRenderOpts::Color(10),
|
||||
&system.res.font,
|
||||
);
|
||||
system.res.video.print_string(
|
||||
if using_queue_commands {
|
||||
"Queueing Commands"
|
||||
} else {
|
||||
"Direct Commands"
|
||||
},
|
||||
160, 16, FontRenderOpts::Color(9), &system.res.font,
|
||||
if using_queue_commands { "Queueing Commands" } else { "Direct Commands" },
|
||||
160,
|
||||
16,
|
||||
FontRenderOpts::Color(9),
|
||||
&system.res.font,
|
||||
);
|
||||
|
||||
system.res.video.print_string(
|
||||
"Audio Channels",
|
||||
16, 32, FontRenderOpts::Color(14), &system.res.font
|
||||
);
|
||||
system.res.video.print_string("Audio Channels", 16, 32, FontRenderOpts::Color(14), &system.res.font);
|
||||
|
||||
let mut y = 48;
|
||||
for index in 0..NUM_CHANNELS {
|
||||
|
@ -193,9 +190,14 @@ fn main() -> Result<()> {
|
|||
"channel {} - {} {}",
|
||||
index,
|
||||
if status.playing { "playing" } else { "not playing" },
|
||||
if status.playing { String::from(format!("{} / {}", status.position, status.size)) } else { String::new() }
|
||||
if status.playing {
|
||||
String::from(format!("{} / {}", status.position, status.size))
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
),
|
||||
16, y,
|
||||
16,
|
||||
y,
|
||||
FontRenderOpts::Color(15),
|
||||
&system.res.font,
|
||||
);
|
||||
|
|
|
@ -19,7 +19,7 @@ struct Ball {
|
|||
|
||||
fn main() -> Result<()> {
|
||||
let config = DosLikeConfig::new();
|
||||
let mut system = SystemBuilder::new()
|
||||
let mut system = SystemBuilder::new() //
|
||||
.window_title("Flying Balls!")
|
||||
.vsync(true)
|
||||
.build(config)?;
|
||||
|
@ -99,12 +99,7 @@ fn main() -> Result<()> {
|
|||
system.res.video.print_string("hello, world!", 10, 10, FontRenderOpts::Color(15), &font);
|
||||
|
||||
for i in 0..NUM_BALLS {
|
||||
system.res.video.blit(
|
||||
IndexedBlitMethod::Transparent(0),
|
||||
&sprites[balls[i].sprite],
|
||||
balls[i].x,
|
||||
balls[i].y,
|
||||
);
|
||||
system.res.video.blit(IndexedBlitMethod::Transparent(0), &sprites[balls[i].sprite], balls[i].x, balls[i].y);
|
||||
}
|
||||
|
||||
system.display()?;
|
||||
|
|
|
@ -38,7 +38,15 @@ pub enum Event {
|
|||
LeaveTrail(Vector2),
|
||||
}
|
||||
|
||||
fn new_basic_particle_entity(entities: &mut Entities, x: f32, y: f32, color: u8, lifetime: f32, angle: f32, speed: i32) {
|
||||
fn new_basic_particle_entity(
|
||||
entities: &mut Entities,
|
||||
x: f32,
|
||||
y: f32,
|
||||
color: u8,
|
||||
lifetime: f32,
|
||||
angle: f32,
|
||||
speed: i32,
|
||||
) {
|
||||
let id = entities.new_entity();
|
||||
entities.add_component(id, Particle);
|
||||
entities.add_component(id, Color(color));
|
||||
|
|
|
@ -12,7 +12,7 @@ mod states;
|
|||
|
||||
fn main() -> Result<()> {
|
||||
let config = DosLikeConfig::new();
|
||||
let system = SystemBuilder::new()
|
||||
let system = SystemBuilder::new() //
|
||||
.window_title("Flying Balls")
|
||||
.vsync(true)
|
||||
.build(config)?;
|
||||
|
|
|
@ -50,14 +50,7 @@ impl Game {
|
|||
init_event_listeners(&mut event_listeners);
|
||||
|
||||
Ok(Game {
|
||||
context: Context {
|
||||
delta: 0.0,
|
||||
system,
|
||||
font,
|
||||
sprites,
|
||||
entities,
|
||||
event_publisher,
|
||||
},
|
||||
context: Context { delta: 0.0, system, font, sprites, entities, event_publisher },
|
||||
component_systems,
|
||||
event_listeners,
|
||||
})
|
||||
|
@ -88,7 +81,13 @@ impl AppState<Game> for SimulationState {
|
|||
fn render(&mut self, _state: State, context: &mut Game) {
|
||||
context.context.system.res.video.clear(2);
|
||||
context.component_systems.render(&mut context.context);
|
||||
context.context.system.res.video.print_string("hello, world!", 10, 10, FontRenderOpts::Color(15), &context.context.font);
|
||||
context.context.system.res.video.print_string(
|
||||
"hello, world!",
|
||||
10,
|
||||
10,
|
||||
FontRenderOpts::Color(15),
|
||||
&context.context.font,
|
||||
);
|
||||
}
|
||||
|
||||
fn transition(&mut self, _state: State, _context: &mut Game) -> bool {
|
||||
|
@ -100,4 +99,4 @@ impl AppState<Game> for SimulationState {
|
|||
init_entities(&mut context.context.entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ggdt::prelude::*;
|
||||
|
||||
use crate::Core;
|
||||
use crate::entities::*;
|
||||
use crate::Core;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Event {
|
||||
|
@ -89,4 +89,4 @@ fn event_handler(event: &Event, context: &mut Core) -> bool {
|
|||
pub fn init_events(event_listener: &mut EventListeners<Event, Core>) {
|
||||
event_listener.clear();
|
||||
event_listener.add(event_handler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::rc::Rc;
|
|||
|
||||
use ggdt::prelude::*;
|
||||
|
||||
use crate::{Core, Game, TILE_HEIGHT, TILE_WIDTH, TileMap};
|
||||
use crate::{Core, Game, TileMap, TILE_HEIGHT, TILE_WIDTH};
|
||||
|
||||
pub use self::events::*;
|
||||
pub use self::systems::*;
|
||||
|
@ -46,7 +46,7 @@ impl Direction {
|
|||
1 => West,
|
||||
2 => East,
|
||||
3 => North,
|
||||
_ => panic!("unknown random direction!")
|
||||
_ => panic!("unknown random direction!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ impl SlimeColor {
|
|||
0 => Green,
|
||||
1 => Blue,
|
||||
2 => Orange,
|
||||
_ => panic!("unknown random slime color!")
|
||||
_ => panic!("unknown random slime color!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ impl PickupType {
|
|||
1 => BlueGem,
|
||||
2 => OrangeGem,
|
||||
3 => Coin,
|
||||
_ => panic!("unknown random pickup type!")
|
||||
_ => panic!("unknown random pickup type!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,12 +116,7 @@ pub struct AnimationDef {
|
|||
impl AnimationDef {
|
||||
#[inline]
|
||||
pub fn new(frames: &'static [usize], loops: bool, delay: f32, multi_direction_offset: Option<usize>) -> Self {
|
||||
AnimationDef {
|
||||
frames,
|
||||
loops,
|
||||
delay,
|
||||
multi_direction_offset,
|
||||
}
|
||||
AnimationDef { frames, loops, delay, multi_direction_offset }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +133,7 @@ impl AnimationInstance {
|
|||
#[inline]
|
||||
pub fn from(def: Rc<AnimationDef>) -> Self {
|
||||
AnimationInstance {
|
||||
def,
|
||||
def, //
|
||||
frame_index: 0,
|
||||
frame_timer: 0.0,
|
||||
complete: false,
|
||||
|
@ -174,9 +169,7 @@ pub struct Forces {
|
|||
|
||||
impl Forces {
|
||||
pub fn new() -> Self {
|
||||
Forces {
|
||||
forces: Vec::with_capacity(5),
|
||||
}
|
||||
Forces { forces: Vec::with_capacity(5) }
|
||||
}
|
||||
|
||||
pub fn current_force(&self) -> Vector2 {
|
||||
|
@ -232,7 +225,13 @@ pub struct RandomlyWalksAround {
|
|||
}
|
||||
|
||||
impl RandomlyWalksAround {
|
||||
pub fn new(min_walk_time: f32, max_walk_time: f32, chance_to_move: u32, min_cooldown: f32, max_cooldown: f32) -> Self {
|
||||
pub fn new(
|
||||
min_walk_time: f32,
|
||||
max_walk_time: f32,
|
||||
chance_to_move: u32,
|
||||
min_cooldown: f32,
|
||||
max_cooldown: f32,
|
||||
) -> Self {
|
||||
RandomlyWalksAround {
|
||||
min_walk_time,
|
||||
max_walk_time,
|
||||
|
@ -264,7 +263,7 @@ pub struct SpawnTimer {
|
|||
impl SpawnTimer {
|
||||
pub fn new(min_time: f32, max_time: f32, max_allowed: usize) -> Self {
|
||||
SpawnTimer {
|
||||
timer: 0.0,
|
||||
timer: 0.0, //
|
||||
min_time,
|
||||
max_time,
|
||||
max_allowed,
|
||||
|
@ -291,7 +290,7 @@ pub struct Pusher {
|
|||
impl Pusher {
|
||||
pub fn new() -> Self {
|
||||
Pusher {
|
||||
strength: DEFAULT_PUSH_STRENGTH,
|
||||
strength: DEFAULT_PUSH_STRENGTH, //
|
||||
push_force_dissipation: DEFAULT_PUSH_DISSIPATION,
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +337,7 @@ pub struct TimedFlicker {
|
|||
impl TimedFlicker {
|
||||
pub fn new(timer: f32, method: FlickerMethod) -> Self {
|
||||
TimedFlicker {
|
||||
timer,
|
||||
timer, //
|
||||
method,
|
||||
pre_timer: None,
|
||||
flick: true,
|
||||
|
@ -347,7 +346,7 @@ impl TimedFlicker {
|
|||
|
||||
pub fn new_with_pre_timer(timer: f32, pre_timer: f32, method: FlickerMethod) -> Self {
|
||||
TimedFlicker {
|
||||
timer,
|
||||
timer, //
|
||||
method,
|
||||
pre_timer: Some(pre_timer),
|
||||
flick: true,
|
||||
|
@ -380,7 +379,13 @@ pub struct Pickuper;
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn init_everything(context: &mut Game, map_file: &Path, min_spawn_time: f32, max_spawn_time: f32, max_slimes: usize) {
|
||||
pub fn init_everything(
|
||||
context: &mut Game,
|
||||
map_file: &Path,
|
||||
min_spawn_time: f32,
|
||||
max_spawn_time: f32,
|
||||
max_slimes: usize,
|
||||
) {
|
||||
init_entities(&mut context.core.entities);
|
||||
init_component_system(&mut context.support.component_systems);
|
||||
init_events(&mut context.support.event_listeners);
|
||||
|
@ -456,7 +461,17 @@ pub fn new_camera_entity(context: &mut Core, x: i32, y: i32) -> EntityId {
|
|||
pub fn new_slime_entity(context: &mut Core, x: i32, y: i32, direction: Direction, color: SlimeColor) -> EntityId {
|
||||
let id = context.entities.new_entity();
|
||||
|
||||
let (atlas, chance_to_move, movement_speed, min_walk_time, max_walk_time, min_walk_cooldown, max_walk_cooldown, life, hit_color) = match color {
|
||||
let (
|
||||
atlas,
|
||||
chance_to_move,
|
||||
movement_speed,
|
||||
min_walk_time,
|
||||
max_walk_time,
|
||||
min_walk_cooldown,
|
||||
max_walk_cooldown,
|
||||
life,
|
||||
hit_color,
|
||||
) = match color {
|
||||
SlimeColor::Green => (context.green_slime.clone(), 10, 8.0, 0.5, 2.0, 0.5, 5.0, 1, 11),
|
||||
SlimeColor::Blue => (context.blue_slime.clone(), 40, 12.0, 0.5, 2.0, 0.5, 3.0, 2, 13),
|
||||
SlimeColor::Orange => (context.orange_slime.clone(), 90, 24.0, 0.5, 1.0, 0.5, 2.0, 3, 9),
|
||||
|
@ -476,7 +491,10 @@ pub fn new_slime_entity(context: &mut Core, x: i32, y: i32, direction: Direction
|
|||
context.entities.add_component(id, Activity(activity));
|
||||
context.entities.add_component(id, animate_by_activity);
|
||||
context.entities.add_component(id, animation);
|
||||
context.entities.add_component(id, RandomlyWalksAround::new(min_walk_time, max_walk_time, chance_to_move, min_walk_cooldown, max_walk_cooldown));
|
||||
context.entities.add_component(
|
||||
id,
|
||||
RandomlyWalksAround::new(min_walk_time, max_walk_time, chance_to_move, min_walk_cooldown, max_walk_cooldown),
|
||||
);
|
||||
context.entities.add_component(id, MovementSpeed(movement_speed));
|
||||
context.entities.add_component(id, Pusher::new());
|
||||
context.entities.add_component(id, Pushable);
|
||||
|
@ -489,7 +507,13 @@ pub fn new_slime_entity(context: &mut Core, x: i32, y: i32, direction: Direction
|
|||
|
||||
pub fn spawn_slime_randomly(context: &mut Core) -> EntityId {
|
||||
let (x, y) = context.tilemap.get_random_spawnable_coordinates();
|
||||
let id = new_slime_entity(context, x * TILE_WIDTH as i32, y * TILE_HEIGHT as i32, Direction::new_random(), SlimeColor::new_random());
|
||||
let id = new_slime_entity(
|
||||
context,
|
||||
x * TILE_WIDTH as i32,
|
||||
y * TILE_HEIGHT as i32,
|
||||
Direction::new_random(),
|
||||
SlimeColor::new_random(),
|
||||
);
|
||||
spawn_poof_cloud(context, x * TILE_WIDTH as i32, y * TILE_HEIGHT as i32, 4, 8);
|
||||
id
|
||||
}
|
||||
|
@ -501,21 +525,21 @@ pub fn new_player_entity(context: &mut Core, x: i32, y: i32, direction: Directio
|
|||
(
|
||||
context.hero_female.clone(),
|
||||
[
|
||||
Vector2::new(-3.0, 13.0),
|
||||
Vector2::new(-3.0, 13.0), //
|
||||
Vector2::new(-14.0, 2.0),
|
||||
Vector2::new(14.0, 2.0),
|
||||
Vector2::new(3.0, -11.0)
|
||||
]
|
||||
Vector2::new(3.0, -11.0),
|
||||
],
|
||||
)
|
||||
} else {
|
||||
(
|
||||
context.hero_male.clone(),
|
||||
[
|
||||
Vector2::new(-3.0, 13.0),
|
||||
Vector2::new(-3.0, 13.0), //
|
||||
Vector2::new(-13.0, 2.0),
|
||||
Vector2::new(13.0, 2.0),
|
||||
Vector2::new(3.0, -11.0)
|
||||
]
|
||||
Vector2::new(3.0, -11.0),
|
||||
],
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -524,7 +548,7 @@ pub fn new_player_entity(context: &mut Core, x: i32, y: i32, direction: Directio
|
|||
let animation = AnimationInstance::from(animate_by_activity.0.get(&activity).unwrap().clone());
|
||||
|
||||
let weapon = Weapon {
|
||||
atlas: context.sword.clone(),
|
||||
atlas: context.sword.clone(), //
|
||||
base_index: 0,
|
||||
offsets: weapon_offsets,
|
||||
damage: 1,
|
||||
|
@ -555,7 +579,13 @@ pub fn spawn_player_randomly(context: &mut Core) -> EntityId {
|
|||
new_player_entity(context, x * TILE_WIDTH as i32, y * TILE_HEIGHT as i32, Direction::South)
|
||||
}
|
||||
|
||||
fn new_animation_effect(context: &mut Core, x: i32, y: i32, animation_def: Rc<AnimationDef>, delay_scaling_factor: Option<f32>) -> EntityId {
|
||||
fn new_animation_effect(
|
||||
context: &mut Core,
|
||||
x: i32,
|
||||
y: i32,
|
||||
animation_def: Rc<AnimationDef>,
|
||||
delay_scaling_factor: Option<f32>,
|
||||
) -> EntityId {
|
||||
let id = context.entities.new_entity();
|
||||
context.entities.add_component(id, Particle);
|
||||
context.entities.add_component(id, Position(Vector2::new(x as f32, y as f32)));
|
||||
|
@ -573,11 +603,17 @@ fn new_animation_effect(context: &mut Core, x: i32, y: i32, animation_def: Rc<An
|
|||
id
|
||||
}
|
||||
|
||||
pub fn new_poof_animation(context: &mut Core, x: i32, y: i32, variant: usize, delay_scaling_factor: Option<f32>) -> EntityId {
|
||||
pub fn new_poof_animation(
|
||||
context: &mut Core,
|
||||
x: i32,
|
||||
y: i32,
|
||||
variant: usize,
|
||||
delay_scaling_factor: Option<f32>,
|
||||
) -> EntityId {
|
||||
let def = match variant {
|
||||
0 => context.poof1_animation_def.clone(),
|
||||
1 => context.poof2_animation_def.clone(),
|
||||
_ => panic!("unknown poof animation variant")
|
||||
_ => panic!("unknown poof animation variant"),
|
||||
};
|
||||
new_animation_effect(context, x, y, def, delay_scaling_factor)
|
||||
}
|
||||
|
@ -611,15 +647,21 @@ pub fn spawn_poof_cloud(context: &mut Core, x: i32, y: i32, count: usize, radius
|
|||
for _ in 0..count {
|
||||
let x = x + rnd_value(-radius, radius);
|
||||
let y = y + rnd_value(-radius, radius);
|
||||
new_poof_animation(context, x, y, 0, match rnd_value(0, 5) {
|
||||
0 => Some(0.25),
|
||||
1 => Some(0.5),
|
||||
2 => Some(0.75),
|
||||
3 => Some(1.0),
|
||||
4 => Some(1.25),
|
||||
5 => Some(1.5),
|
||||
_ => None,
|
||||
});
|
||||
new_poof_animation(
|
||||
context,
|
||||
x,
|
||||
y,
|
||||
0,
|
||||
match rnd_value(0, 5) {
|
||||
0 => Some(0.25),
|
||||
1 => Some(0.5),
|
||||
2 => Some(0.75),
|
||||
3 => Some(1.0),
|
||||
4 => Some(1.25),
|
||||
5 => Some(1.5),
|
||||
_ => None,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -691,7 +733,7 @@ pub fn spawn_pickups_from_entity(context: &mut Core, entity: EntityId) {
|
|||
let angle = (rnd_value(0, 359) as f32).to_radians();
|
||||
let force_strength = rnd_value(0.5, 5.0);
|
||||
let force = Force {
|
||||
force: Vector2::from_angle(angle) * force_strength,
|
||||
force: Vector2::from_angle(angle) * force_strength, //
|
||||
dissipation_factor: 0.5,
|
||||
};
|
||||
let kind = PickupType::new_random();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use ggdt::prelude::*;
|
||||
|
||||
use crate::{Core, TILE_HEIGHT, TILE_WIDTH};
|
||||
use crate::entities::*;
|
||||
use crate::tilemap::*;
|
||||
use crate::{Core, TILE_HEIGHT, TILE_WIDTH};
|
||||
|
||||
pub fn remove_entity(entities: &mut Entities, entity: EntityId) {
|
||||
remove_entity_attachment(entities, entity);
|
||||
|
@ -31,7 +31,7 @@ pub fn move_entity_forward(context: &mut Core, entity: EntityId) {
|
|||
Direction::North => Vector2::UP * movement_speed.0,
|
||||
Direction::East => Vector2::RIGHT * movement_speed.0,
|
||||
Direction::West => Vector2::LEFT * movement_speed.0,
|
||||
Direction::South => Vector2::DOWN * movement_speed.0
|
||||
Direction::South => Vector2::DOWN * movement_speed.0,
|
||||
};
|
||||
|
||||
velocity.0 += movement;
|
||||
|
@ -56,7 +56,14 @@ pub fn turn_and_move_entity(context: &mut Core, entity: EntityId, direction: Dir
|
|||
move_entity_forward(context, entity);
|
||||
}
|
||||
|
||||
fn move_entity_with_collision(position: &mut Position, bounds: &Bounds, velocity: Option<&Velocity>, forces: Option<&Forces>, map: &TileMap, delta: f32) -> bool {
|
||||
fn move_entity_with_collision(
|
||||
position: &mut Position,
|
||||
bounds: &Bounds,
|
||||
velocity: Option<&Velocity>,
|
||||
forces: Option<&Forces>,
|
||||
map: &TileMap,
|
||||
delta: f32,
|
||||
) -> bool {
|
||||
const NUM_STEPS: usize = 2;
|
||||
const STEP_SCALE: f32 = 1.0 / NUM_STEPS as f32;
|
||||
|
||||
|
@ -169,12 +176,8 @@ pub fn get_attack_area_of_effect(context: &mut Core, attacker: EntityId) -> Opti
|
|||
if let Some(facing_direction) = facing_directions.get(&attacker) {
|
||||
let center_point = position.0 + weapon.offsets[facing_direction.0 as usize];
|
||||
return Some((
|
||||
Circle::new(
|
||||
center_point.x as i32 + 8,
|
||||
center_point.y as i32 + 8,
|
||||
weapon.radius_of_effect,
|
||||
),
|
||||
weapon.damage
|
||||
Circle::new(center_point.x as i32 + 8, center_point.y as i32 + 8, weapon.radius_of_effect),
|
||||
weapon.damage,
|
||||
));
|
||||
} else {
|
||||
return Some((
|
||||
|
@ -183,7 +186,7 @@ pub fn get_attack_area_of_effect(context: &mut Core, attacker: EntityId) -> Opti
|
|||
position.0.y as i32 + bound.height as i32 / 2,
|
||||
weapon.radius_of_effect,
|
||||
),
|
||||
weapon.damage
|
||||
weapon.damage,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -337,7 +340,11 @@ fn update_system_pushing(context: &mut Core) {
|
|||
|
||||
let pushable_position = positions.get(pushable_entity).unwrap();
|
||||
let pushable_bounds = bounds.get(pushable_entity).unwrap();
|
||||
let pushable_circle = Circle::new(pushable_position.0.x as i32, pushable_position.0.y as i32, pushable_bounds.radius);
|
||||
let pushable_circle = Circle::new(
|
||||
pushable_position.0.x as i32, //
|
||||
pushable_position.0.y as i32,
|
||||
pushable_bounds.radius,
|
||||
);
|
||||
|
||||
if pusher_circle.overlaps(&pushable_circle) {
|
||||
let push_direction = (pushable_position.0 - pusher_position.0).normalize();
|
||||
|
@ -371,7 +378,7 @@ fn update_system_animation(context: &mut Core) {
|
|||
animation.frame_timer += context.delta;
|
||||
|
||||
let delay = if let Some(delay_override) = animation.delay_override {
|
||||
delay_override
|
||||
delay_override //
|
||||
} else {
|
||||
animation.def.delay
|
||||
};
|
||||
|
@ -469,7 +476,10 @@ fn update_system_randomly_walk_around(context: &mut Core) {
|
|||
randomly_walk_around.cooldown_timer = 0.0;
|
||||
}
|
||||
} else if randomly_walk_around.should_start_walking() {
|
||||
randomly_walk_around.cooldown_timer = rnd_value(randomly_walk_around.min_cooldown, randomly_walk_around.max_cooldown);
|
||||
randomly_walk_around.cooldown_timer = rnd_value(
|
||||
randomly_walk_around.min_cooldown, //
|
||||
randomly_walk_around.max_cooldown,
|
||||
);
|
||||
|
||||
let direction = Direction::new_random();
|
||||
let walk_time = rnd_value(randomly_walk_around.min_walk_time, randomly_walk_around.max_walk_time);
|
||||
|
@ -674,7 +684,7 @@ fn render_system_sprites(context: &mut Core) {
|
|||
}
|
||||
FlickerMethod::Color(draw_color) => {
|
||||
blit_method = IndexedBlitMethod::TransparentSingle {
|
||||
transparent_color: 0,
|
||||
transparent_color: 0, //
|
||||
draw_color,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ use crate::states::*;
|
|||
use crate::support::*;
|
||||
use crate::tilemap::*;
|
||||
|
||||
mod states;
|
||||
mod entities;
|
||||
mod states;
|
||||
mod support;
|
||||
mod tilemap;
|
||||
|
||||
|
@ -182,17 +182,14 @@ impl Game {
|
|||
sparkles_animation_def,
|
||||
sprite_render_list: Vec::with_capacity(1024),
|
||||
},
|
||||
support: Support {
|
||||
component_systems,
|
||||
event_listeners,
|
||||
},
|
||||
support: Support { component_systems, event_listeners },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let config = DosLikeConfig::new();
|
||||
let system = SystemBuilder::new()
|
||||
let system = SystemBuilder::new() //
|
||||
.window_title("Slime Stabbing Simulator")
|
||||
.vsync(true)
|
||||
.build(config)?;
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::path::Path;
|
|||
use ggdt::prelude::*;
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::Game;
|
||||
use crate::support::*;
|
||||
use crate::Game;
|
||||
|
||||
pub struct MainMenuState {
|
||||
fade: f32,
|
||||
|
@ -13,10 +13,7 @@ pub struct MainMenuState {
|
|||
|
||||
impl MainMenuState {
|
||||
pub fn new() -> Self {
|
||||
MainMenuState {
|
||||
fade: 0.0,
|
||||
selection: 0,
|
||||
}
|
||||
MainMenuState { fade: 0.0, selection: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,10 +57,28 @@ impl AppState<Game> for MainMenuState {
|
|||
draw_window(&mut context.core.system.res.video, &context.core.ui, x, y, x + width, y + height);
|
||||
|
||||
let selection_y = y + SPACER + (self.selection as i32 * 16);
|
||||
context.core.system.res.video.print_string(">", x + SPACER, selection_y, FontRenderOpts::Color(15), &context.core.font);
|
||||
context.core.system.res.video.print_string(
|
||||
">",
|
||||
x + SPACER,
|
||||
selection_y,
|
||||
FontRenderOpts::Color(15),
|
||||
&context.core.font,
|
||||
);
|
||||
|
||||
context.core.system.res.video.print_string("Play", x + SPACER + SPACER, y + SPACER, FontRenderOpts::Color(15), &context.core.font);
|
||||
context.core.system.res.video.print_string("Quit", x + SPACER + SPACER, y + SPACER + 16, FontRenderOpts::Color(15), &context.core.font);
|
||||
context.core.system.res.video.print_string(
|
||||
"Play",
|
||||
x + SPACER + SPACER,
|
||||
y + SPACER,
|
||||
FontRenderOpts::Color(15),
|
||||
&context.core.font,
|
||||
);
|
||||
context.core.system.res.video.print_string(
|
||||
"Quit",
|
||||
x + SPACER + SPACER,
|
||||
y + SPACER + 16,
|
||||
FontRenderOpts::Color(15),
|
||||
&context.core.font,
|
||||
);
|
||||
}
|
||||
|
||||
fn transition(&mut self, state: State, context: &mut Game) -> bool {
|
||||
|
@ -98,7 +113,7 @@ pub struct GamePlayState {
|
|||
impl GamePlayState {
|
||||
pub fn new() -> Self {
|
||||
GamePlayState {
|
||||
fade: 0.0,
|
||||
fade: 0.0, //
|
||||
in_menu: false,
|
||||
selection: 0,
|
||||
}
|
||||
|
@ -172,10 +187,28 @@ impl AppState<Game> for GamePlayState {
|
|||
draw_window(&mut context.core.system.res.video, &context.core.ui, x, y, x + width, y + height);
|
||||
|
||||
let selection_y = y + SPACER + (self.selection as i32 * 16);
|
||||
context.core.system.res.video.print_string(">", x + SPACER, selection_y, FontRenderOpts::Color(15), &context.core.font);
|
||||
context.core.system.res.video.print_string(
|
||||
">",
|
||||
x + SPACER,
|
||||
selection_y,
|
||||
FontRenderOpts::Color(15),
|
||||
&context.core.font,
|
||||
);
|
||||
|
||||
context.core.system.res.video.print_string("Continue", x + SPACER + SPACER, y + SPACER, FontRenderOpts::Color(15), &context.core.font);
|
||||
context.core.system.res.video.print_string("Quit", x + SPACER + SPACER, y + SPACER + 16, FontRenderOpts::Color(15), &context.core.font);
|
||||
context.core.system.res.video.print_string(
|
||||
"Continue",
|
||||
x + SPACER + SPACER,
|
||||
y + SPACER,
|
||||
FontRenderOpts::Color(15),
|
||||
&context.core.font,
|
||||
);
|
||||
context.core.system.res.video.print_string(
|
||||
"Quit",
|
||||
x + SPACER + SPACER,
|
||||
y + SPACER + 16,
|
||||
FontRenderOpts::Color(15),
|
||||
&context.core.font,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,14 @@ pub fn load_bitmap_atlas(path: &Path) -> Result<BitmapAtlas<IndexedBitmap>> {
|
|||
Ok(atlas)
|
||||
}
|
||||
|
||||
pub fn draw_window(dest: &mut IndexedBitmap, ui: &BitmapAtlas<IndexedBitmap>, left: i32, top: i32, right: i32, bottom: i32) {
|
||||
pub fn draw_window(
|
||||
dest: &mut IndexedBitmap,
|
||||
ui: &BitmapAtlas<IndexedBitmap>,
|
||||
left: i32,
|
||||
top: i32,
|
||||
right: i32,
|
||||
bottom: i32,
|
||||
) {
|
||||
dest.filled_rect(left + 8, top + 8, right - 8, bottom - 8, 1);
|
||||
|
||||
// corners
|
||||
|
@ -60,7 +67,12 @@ pub fn update_fade_transition(state: State, fade: &mut f32, delta: f32, context:
|
|||
context.core.system.res.palette = context.core.palette.clone();
|
||||
true
|
||||
} else {
|
||||
context.core.system.res.palette.lerp(0..=255, &context.core.fade_out_palette, &context.core.palette, *fade);
|
||||
context.core.system.res.palette.lerp(
|
||||
0..=255,
|
||||
&context.core.fade_out_palette,
|
||||
&context.core.palette,
|
||||
*fade,
|
||||
);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -71,12 +83,15 @@ pub fn update_fade_transition(state: State, fade: &mut f32, delta: f32, context:
|
|||
context.core.system.res.palette = context.core.fade_out_palette.clone();
|
||||
true
|
||||
} else {
|
||||
context.core.system.res.palette.lerp(0..=255, &context.core.fade_out_palette, &context.core.palette, *fade);
|
||||
context.core.system.res.palette.lerp(
|
||||
0..=255,
|
||||
&context.core.fade_out_palette,
|
||||
&context.core.palette,
|
||||
*fade,
|
||||
);
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
true
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,13 @@ impl TileMap {
|
|||
}
|
||||
let upper = self.layers[1][index];
|
||||
if upper >= 0 {
|
||||
dest.blit_region(IndexedBlitMethod::Transparent(0), tiles.bitmap(), &tiles[upper as usize], xd, yd);
|
||||
dest.blit_region(
|
||||
IndexedBlitMethod::Transparent(0),
|
||||
tiles.bitmap(),
|
||||
&tiles[upper as usize],
|
||||
xd,
|
||||
yd,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +106,7 @@ impl TileMap {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
None => return true
|
||||
None => return true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn event_listener(event: &Event, context: &mut Core) -> bool {
|
|||
context.entities.add_component(id, Color(color));
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,16 +201,8 @@ impl App {
|
|||
let event_listeners = EventListeners::new();
|
||||
|
||||
Ok(App {
|
||||
core: Core {
|
||||
delta: 0.0,
|
||||
system,
|
||||
entities,
|
||||
event_publisher,
|
||||
},
|
||||
support: Support {
|
||||
component_systems,
|
||||
event_listeners,
|
||||
},
|
||||
core: Core { delta: 0.0, system, entities, event_publisher },
|
||||
support: Support { component_systems, event_listeners },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +211,7 @@ impl App {
|
|||
|
||||
fn main() -> Result<()> {
|
||||
let config = DosLikeConfig::new();
|
||||
let system = SystemBuilder::new()
|
||||
let system = SystemBuilder::new() //
|
||||
.window_title("Complicated Template")
|
||||
.vsync(true)
|
||||
.build(config)?;
|
||||
|
|
|
@ -4,7 +4,7 @@ use ggdt::prelude::*;
|
|||
|
||||
fn main() -> Result<()> {
|
||||
let config = DosLikeConfig::new();
|
||||
let mut system = SystemBuilder::new()
|
||||
let mut system = SystemBuilder::new() //
|
||||
.window_title("Minimal Template")
|
||||
.vsync(true)
|
||||
.build(config)?;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use criterion::{black_box, Criterion, criterion_group, criterion_main};
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
use ggdt::prelude::*;
|
||||
|
||||
|
@ -10,18 +10,12 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
let mut dest = vec![0u32; (width * height * 4) as usize].into_boxed_slice();
|
||||
let palette = Palette::new_vga_palette().unwrap();
|
||||
|
||||
c.bench_function("deindex_bitmap_pixels", |b| {
|
||||
b.iter(|| source.copy_as_argb_to(&mut dest, &palette))
|
||||
});
|
||||
c.bench_function("deindex_bitmap_pixels", |b| b.iter(|| source.copy_as_argb_to(&mut dest, &palette)));
|
||||
|
||||
c.bench_function("set_pixel", |b| {
|
||||
b.iter(|| source.set_pixel(black_box(100), black_box(100), black_box(42)))
|
||||
});
|
||||
c.bench_function("set_pixel", |b| b.iter(|| source.set_pixel(black_box(100), black_box(100), black_box(42))));
|
||||
|
||||
c.bench_function("set_pixel_unchecked", |b| {
|
||||
b.iter(|| unsafe {
|
||||
source.set_pixel_unchecked(black_box(100), black_box(100), black_box(42))
|
||||
})
|
||||
b.iter(|| unsafe { source.set_pixel_unchecked(black_box(100), black_box(100), black_box(42)) })
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::path::Path;
|
||||
|
||||
use criterion::{black_box, Criterion, criterion_group, criterion_main};
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
use ggdt::prelude::*;
|
||||
|
||||
|
@ -17,12 +17,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
|
||||
c.bench_function("blit_single_checked_solid", |b| {
|
||||
b.iter(|| {
|
||||
framebuffer.blit(
|
||||
black_box(IndexedBlitMethod::Solid),
|
||||
black_box(&solid_bmp),
|
||||
black_box(100),
|
||||
black_box(100),
|
||||
)
|
||||
framebuffer.blit(black_box(IndexedBlitMethod::Solid), black_box(&solid_bmp), black_box(100), black_box(100))
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -66,10 +61,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
c.bench_function("blit_solid_flipped_not_flipped", |b| {
|
||||
b.iter(|| {
|
||||
framebuffer.blit(
|
||||
black_box(IndexedBlitMethod::SolidFlipped {
|
||||
horizontal_flip: false,
|
||||
vertical_flip: false,
|
||||
}),
|
||||
black_box(IndexedBlitMethod::SolidFlipped { horizontal_flip: false, vertical_flip: false }),
|
||||
black_box(&solid_bmp),
|
||||
black_box(100),
|
||||
black_box(100),
|
||||
|
@ -80,10 +72,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
c.bench_function("blit_solid_flipped_horizontally", |b| {
|
||||
b.iter(|| {
|
||||
framebuffer.blit(
|
||||
black_box(IndexedBlitMethod::SolidFlipped {
|
||||
horizontal_flip: true,
|
||||
vertical_flip: false,
|
||||
}),
|
||||
black_box(IndexedBlitMethod::SolidFlipped { horizontal_flip: true, vertical_flip: false }),
|
||||
black_box(&solid_bmp),
|
||||
black_box(100),
|
||||
black_box(100),
|
||||
|
@ -94,10 +83,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
c.bench_function("blit_solid_flipped_vertically", |b| {
|
||||
b.iter(|| {
|
||||
framebuffer.blit(
|
||||
black_box(IndexedBlitMethod::SolidFlipped {
|
||||
horizontal_flip: false,
|
||||
vertical_flip: true,
|
||||
}),
|
||||
black_box(IndexedBlitMethod::SolidFlipped { horizontal_flip: false, vertical_flip: true }),
|
||||
black_box(&solid_bmp),
|
||||
black_box(100),
|
||||
black_box(100),
|
||||
|
@ -108,10 +94,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
c.bench_function("blit_solid_flipped_horizontally_and_vertically", |b| {
|
||||
b.iter(|| {
|
||||
framebuffer.blit(
|
||||
black_box(IndexedBlitMethod::SolidFlipped {
|
||||
horizontal_flip: true,
|
||||
vertical_flip: true,
|
||||
}),
|
||||
black_box(IndexedBlitMethod::SolidFlipped { horizontal_flip: true, vertical_flip: true }),
|
||||
black_box(&solid_bmp),
|
||||
black_box(100),
|
||||
black_box(100),
|
||||
|
@ -252,10 +235,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
c.bench_function("blit_transparent_single", |b| {
|
||||
b.iter(|| {
|
||||
framebuffer.blit(
|
||||
black_box(IndexedBlitMethod::TransparentSingle {
|
||||
transparent_color: 0,
|
||||
draw_color: 17,
|
||||
}),
|
||||
black_box(IndexedBlitMethod::TransparentSingle { transparent_color: 0, draw_color: 17 }),
|
||||
black_box(&trans_bmp),
|
||||
black_box(100),
|
||||
black_box(100),
|
||||
|
@ -268,10 +248,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
c.bench_function("blit_transparent_offset", |b| {
|
||||
b.iter(|| {
|
||||
framebuffer.blit(
|
||||
black_box(IndexedBlitMethod::TransparentOffset {
|
||||
transparent_color: 0,
|
||||
offset: 42,
|
||||
}),
|
||||
black_box(IndexedBlitMethod::TransparentOffset { transparent_color: 0, offset: 42 }),
|
||||
black_box(&trans_bmp),
|
||||
black_box(100),
|
||||
black_box(100),
|
||||
|
@ -425,11 +402,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
c.bench_function("blit_rotozoom", |b| {
|
||||
b.iter(|| {
|
||||
framebuffer.blit(
|
||||
black_box(IndexedBlitMethod::RotoZoom {
|
||||
angle: 73.0f32.to_radians(),
|
||||
scale_x: 1.2,
|
||||
scale_y: 0.8,
|
||||
}),
|
||||
black_box(IndexedBlitMethod::RotoZoom { angle: 73.0f32.to_radians(), scale_x: 1.2, scale_y: 0.8 }),
|
||||
black_box(&solid_bmp),
|
||||
black_box(100),
|
||||
black_box(100),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::io::Cursor;
|
||||
|
||||
use criterion::{black_box, Criterion, criterion_group, criterion_main};
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
use ggdt::prelude::*;
|
||||
|
||||
|
|
|
@ -30,10 +30,7 @@ impl AudioBuffer {
|
|||
/// Creates and returns a new, empty, [`AudioBuffer`] that will hold audio sample data in the
|
||||
/// spec/format given.
|
||||
pub fn new(spec: AudioSpec) -> Self {
|
||||
AudioBuffer {
|
||||
spec,
|
||||
data: Vec::new(),
|
||||
}
|
||||
AudioBuffer { spec, data: Vec::new() }
|
||||
}
|
||||
|
||||
/// Returns the spec of the audio sample data that this buffer contains.
|
||||
|
|
|
@ -7,8 +7,8 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|||
use sdl2::audio::AudioFormat;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::audio::AudioSpec;
|
||||
use crate::audio::buffer::AudioBuffer;
|
||||
use crate::audio::AudioSpec;
|
||||
use crate::utils::io::StreamSize;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
@ -70,10 +70,7 @@ impl WavHeader {
|
|||
pub fn read<T: ReadBytesExt>(reader: &mut T) -> Result<Self, WavError> {
|
||||
let file_chunk = SubChunkHeader::read(reader)?;
|
||||
let file_container_id = ChunkId::read(reader)?;
|
||||
Ok(WavHeader {
|
||||
file_chunk,
|
||||
file_container_id,
|
||||
})
|
||||
Ok(WavHeader { file_chunk, file_container_id })
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -98,10 +95,7 @@ struct FormatChunk {
|
|||
}
|
||||
|
||||
impl FormatChunk {
|
||||
pub fn read<T: ReadBytesExt>(
|
||||
reader: &mut T,
|
||||
chunk_header: &SubChunkHeader,
|
||||
) -> Result<Self, WavError> {
|
||||
pub fn read<T: ReadBytesExt>(reader: &mut T, chunk_header: &SubChunkHeader) -> Result<Self, WavError> {
|
||||
let compression_code = reader.read_u16::<LittleEndian>()?;
|
||||
let channels = reader.read_u16::<LittleEndian>()?;
|
||||
let frequency = reader.read_u32::<LittleEndian>()?;
|
||||
|
@ -180,9 +174,7 @@ impl DataChunk {
|
|||
buffer = vec![0u8; chunk_header.size as usize];
|
||||
reader.read_exact(&mut buffer)?;
|
||||
}
|
||||
Ok(DataChunk {
|
||||
data: buffer.into_boxed_slice(),
|
||||
})
|
||||
Ok(DataChunk { data: buffer.into_boxed_slice() })
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -200,14 +192,10 @@ impl AudioBuffer {
|
|||
|
||||
let header = WavHeader::read(reader)?;
|
||||
if header.file_chunk.chunk_id.id != *b"RIFF" {
|
||||
return Err(WavError::BadFile(String::from(
|
||||
"Unexpected RIFF chunk id, probably not a WAV file",
|
||||
)));
|
||||
return Err(WavError::BadFile(String::from("Unexpected RIFF chunk id, probably not a WAV file")));
|
||||
}
|
||||
if header.file_container_id.id != *b"WAVE" {
|
||||
return Err(WavError::BadFile(String::from(
|
||||
"Unexpected RIFF container id, probably not a WAV file",
|
||||
)));
|
||||
return Err(WavError::BadFile(String::from("Unexpected RIFF container id, probably not a WAV file")));
|
||||
}
|
||||
|
||||
// some tools like sfxr and jsfxr incorrectly calculate data sizes, seemingly using a
|
||||
|
@ -227,11 +215,9 @@ impl AudioBuffer {
|
|||
loop {
|
||||
let chunk_header = match SubChunkHeader::read(reader) {
|
||||
Ok(header) => header,
|
||||
Err(WavError::IOError(io_error))
|
||||
if io_error.kind() == io::ErrorKind::UnexpectedEof =>
|
||||
{
|
||||
break;
|
||||
}
|
||||
Err(WavError::IOError(io_error)) if io_error.kind() == io::ErrorKind::UnexpectedEof => {
|
||||
break;
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let chunk_data_position = reader.stream_position()?;
|
||||
|
@ -240,12 +226,9 @@ impl AudioBuffer {
|
|||
if chunk_header.chunk_id.id == *b"fmt " {
|
||||
format = Some(FormatChunk::read(reader, &chunk_header)?);
|
||||
if format.as_ref().unwrap().compression_code != 1 {
|
||||
return Err(WavError::BadFile(String::from(
|
||||
"Only PCM format WAV files are supported",
|
||||
)));
|
||||
return Err(WavError::BadFile(String::from("Only PCM format WAV files are supported")));
|
||||
}
|
||||
if format.as_ref().unwrap().bits_per_sample != 8 &&
|
||||
format.as_ref().unwrap().bits_per_sample != 16 {
|
||||
if format.as_ref().unwrap().bits_per_sample != 8 && format.as_ref().unwrap().bits_per_sample != 16 {
|
||||
return Err(WavError::BadFile(String::from(
|
||||
"Only 8-bit and 16-bit sample WAV files are supported",
|
||||
)));
|
||||
|
@ -256,9 +239,7 @@ impl AudioBuffer {
|
|||
|
||||
// move to the start of the next chunk (possibly skipping over the current chunk if we
|
||||
// didn't recognize it above ...)
|
||||
reader.seek(SeekFrom::Start(
|
||||
chunk_data_position + chunk_header.size as u64,
|
||||
))?;
|
||||
reader.seek(SeekFrom::Start(chunk_data_position + chunk_header.size as u64))?;
|
||||
}
|
||||
|
||||
// all done reading the file, now convert the read data into an AudioBuffer ...
|
||||
|
@ -271,7 +252,7 @@ impl AudioBuffer {
|
|||
16 => AudioFormat::S16LSB,
|
||||
// this shouldn't be able to happen given the above checks when reading the
|
||||
// "fmt" chunk
|
||||
_ => return Err(WavError::BadFile(String::from("Unsupported sample bit size.")))
|
||||
_ => return Err(WavError::BadFile(String::from("Unsupported sample bit size."))),
|
||||
};
|
||||
let spec = AudioSpec::new(format.frequency, format.channels as u8, sample_format);
|
||||
audio_buffer = AudioBuffer::new(spec);
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::ops::{Index, IndexMut};
|
|||
use sdl2::audio::AudioCallback;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::audio::{AudioGenerator, AudioSpec, NUM_CHANNELS};
|
||||
use crate::audio::buffer::AudioBuffer;
|
||||
use crate::audio::{AudioGenerator, AudioSpec, NUM_CHANNELS};
|
||||
|
||||
/// Represents a "channel" of audio playback that will be mixed together with all of the other
|
||||
/// actively playing audio channels to get the final audio playback.
|
||||
|
@ -36,10 +36,13 @@ impl std::fmt::Debug for AudioChannel {
|
|||
.field("playing", &self.playing)
|
||||
.field("loops", &self.loops)
|
||||
.field("data.len()", &self.data.len())
|
||||
.field("generator", match self.generator {
|
||||
Some(..) => &"Some(..)",
|
||||
None => &"None",
|
||||
})
|
||||
.field(
|
||||
"generator",
|
||||
match self.generator {
|
||||
Some(..) => &"Some(..)",
|
||||
None => &"None",
|
||||
},
|
||||
)
|
||||
.field("volume", &self.volume)
|
||||
.field("position", &self.position)
|
||||
.finish_non_exhaustive()
|
||||
|
@ -49,7 +52,7 @@ impl std::fmt::Debug for AudioChannel {
|
|||
impl AudioChannel {
|
||||
pub fn new() -> Self {
|
||||
AudioChannel {
|
||||
playing: false,
|
||||
playing: false, //
|
||||
loops: false,
|
||||
volume: 1.0,
|
||||
position: 0,
|
||||
|
@ -221,11 +224,7 @@ impl AudioDevice {
|
|||
for _ in 0..NUM_CHANNELS {
|
||||
channels.push(AudioChannel::new());
|
||||
}
|
||||
AudioDevice {
|
||||
spec,
|
||||
channels,
|
||||
volume: 1.0,
|
||||
}
|
||||
AudioDevice { spec, channels, volume: 1.0 }
|
||||
}
|
||||
|
||||
/// Returns the spec that this device is currently set to play. All audio to be played via
|
||||
|
@ -263,11 +262,7 @@ impl AudioDevice {
|
|||
/// playing. If a free channel is found, playback will be started by copying the buffer's
|
||||
/// contents to the channel. The index of the channel is returned. If playback was not started
|
||||
/// because no channel is free currently, then `None` is returned.
|
||||
pub fn play_buffer(
|
||||
&mut self,
|
||||
buffer: &AudioBuffer,
|
||||
loops: bool,
|
||||
) -> Result<Option<usize>, AudioDeviceError> {
|
||||
pub fn play_buffer(&mut self, buffer: &AudioBuffer, loops: bool) -> Result<Option<usize>, AudioDeviceError> {
|
||||
if *buffer.spec() != self.spec {
|
||||
Err(AudioDeviceError::AudioSpecMismatch)
|
||||
} else {
|
||||
|
@ -333,37 +328,37 @@ impl AudioDevice {
|
|||
|
||||
/// Returns an iterator of any [`AudioChannel`]s that are currently playing.
|
||||
#[inline]
|
||||
pub fn playing_channels_iter(&mut self) -> impl Iterator<Item=&AudioChannel> {
|
||||
pub fn playing_channels_iter(&mut self) -> impl Iterator<Item = &AudioChannel> {
|
||||
self.channels.iter().filter(|channel| channel.playing)
|
||||
}
|
||||
|
||||
/// Returns an iterator of mutable [`AudioChannel`]s that are currently playing.
|
||||
#[inline]
|
||||
pub fn playing_channels_iter_mut(&mut self) -> impl Iterator<Item=&mut AudioChannel> {
|
||||
pub fn playing_channels_iter_mut(&mut self) -> impl Iterator<Item = &mut AudioChannel> {
|
||||
self.channels.iter_mut().filter(|channel| channel.playing)
|
||||
}
|
||||
|
||||
/// Returns an iterator of [`AudioChannel`]s that are not currently playing.
|
||||
#[inline]
|
||||
pub fn stopped_channels_iter(&mut self) -> impl Iterator<Item=&AudioChannel> {
|
||||
pub fn stopped_channels_iter(&mut self) -> impl Iterator<Item = &AudioChannel> {
|
||||
self.channels.iter().filter(|channel| !channel.playing)
|
||||
}
|
||||
|
||||
/// Returns an iterator of mutable [`AudioChannel`]s that are not currently playing.
|
||||
#[inline]
|
||||
pub fn stopped_channels_iter_mut(&mut self) -> impl Iterator<Item=&mut AudioChannel> {
|
||||
pub fn stopped_channels_iter_mut(&mut self) -> impl Iterator<Item = &mut AudioChannel> {
|
||||
self.channels.iter_mut().filter(|channel| !channel.playing)
|
||||
}
|
||||
|
||||
/// Returns an iterator of all [`AudioChannel`]s.
|
||||
#[inline]
|
||||
pub fn channels_iter(&mut self) -> impl Iterator<Item=&AudioChannel> {
|
||||
pub fn channels_iter(&mut self) -> impl Iterator<Item = &AudioChannel> {
|
||||
self.channels.iter()
|
||||
}
|
||||
|
||||
/// Returns an iterator of all [`AudioChannel`]s as mutable references.
|
||||
#[inline]
|
||||
pub fn channels_iter_mut(&mut self) -> impl Iterator<Item=&mut AudioChannel> {
|
||||
pub fn channels_iter_mut(&mut self) -> impl Iterator<Item = &mut AudioChannel> {
|
||||
self.channels.iter_mut()
|
||||
}
|
||||
|
||||
|
|
|
@ -44,11 +44,7 @@ impl AudioSpec {
|
|||
/// * `channels`: the number of channels of the audio (e.g. 1 = mono, 2 = stereo, etc)
|
||||
/// * `format`: indicates the format of the bytes making up the audio buffer.
|
||||
pub fn new(frequency: u32, channels: u8, format: AudioFormat) -> Self {
|
||||
AudioSpec {
|
||||
frequency,
|
||||
channels,
|
||||
format,
|
||||
}
|
||||
AudioSpec { frequency, channels, format }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -98,8 +94,8 @@ pub struct Audio {
|
|||
|
||||
impl std::fmt::Debug for Audio {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Audio")
|
||||
.field("spec", &self.spec)
|
||||
f.debug_struct("Audio") //
|
||||
.field("spec", &self.spec) //
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
@ -110,34 +106,25 @@ impl Audio {
|
|||
///
|
||||
/// Ideally, you should not be creating an instance of this yourself and should just use the
|
||||
/// one provided by [`crate::system::System`].
|
||||
pub fn new(
|
||||
desired_spec: AudioSpecDesired,
|
||||
sdl_audio_subsystem: &AudioSubsystem,
|
||||
) -> Result<Self, AudioError> {
|
||||
pub fn new(desired_spec: AudioSpecDesired, sdl_audio_subsystem: &AudioSubsystem) -> Result<Self, AudioError> {
|
||||
let mut spec = None;
|
||||
let sdl_audio_device =
|
||||
match sdl_audio_subsystem.open_playback(None, &desired_spec, |opened_spec| {
|
||||
let our_spec = AudioSpec::new(
|
||||
opened_spec.freq as u32,
|
||||
opened_spec.channels,
|
||||
opened_spec.format,
|
||||
);
|
||||
spec = Some(our_spec);
|
||||
AudioDevice::new(our_spec)
|
||||
}) {
|
||||
Ok(audio_device) => audio_device,
|
||||
Err(error) => return Err(AudioError::OpenDeviceFailed(error)),
|
||||
};
|
||||
let sdl_audio_device = match sdl_audio_subsystem.open_playback(None, &desired_spec, |opened_spec| {
|
||||
let our_spec = AudioSpec::new(
|
||||
opened_spec.freq as u32, //
|
||||
opened_spec.channels, //
|
||||
opened_spec.format, //
|
||||
);
|
||||
spec = Some(our_spec);
|
||||
AudioDevice::new(our_spec)
|
||||
}) {
|
||||
Ok(audio_device) => audio_device,
|
||||
Err(error) => return Err(AudioError::OpenDeviceFailed(error)),
|
||||
};
|
||||
|
||||
if let Some(spec) = spec {
|
||||
Ok(Audio {
|
||||
spec,
|
||||
sdl_audio_device,
|
||||
})
|
||||
Ok(Audio { spec, sdl_audio_device })
|
||||
} else {
|
||||
Err(AudioError::OpenDeviceFailed(String::from(
|
||||
"Device initialization failed to set AudioSpec",
|
||||
)))
|
||||
Err(AudioError::OpenDeviceFailed(String::from("Device initialization failed to set AudioSpec")))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
pub use crate::{
|
||||
audio::*,
|
||||
audio::buffer::*,
|
||||
//
|
||||
audio::buffer::wav::*,
|
||||
audio::buffer::*,
|
||||
audio::device::*,
|
||||
audio::queue::*,
|
||||
};
|
||||
audio::*,
|
||||
};
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::audio::{Audio, AudioGenerator, AudioSpec, NUM_CHANNELS};
|
||||
use crate::audio::buffer::AudioBuffer;
|
||||
use crate::audio::device::{AudioDevice, AudioDeviceError};
|
||||
use crate::audio::{Audio, AudioGenerator, AudioSpec, NUM_CHANNELS};
|
||||
|
||||
pub enum AudioCommand {
|
||||
StopChannel(usize),
|
||||
StopAllChannels,
|
||||
PlayBuffer {
|
||||
buffer: AudioBuffer,
|
||||
buffer: AudioBuffer, //
|
||||
loops: bool,
|
||||
},
|
||||
PlayRcBuffer {
|
||||
buffer: Rc<AudioBuffer>,
|
||||
buffer: Rc<AudioBuffer>, //
|
||||
loops: bool,
|
||||
},
|
||||
PlayBufferOnChannel {
|
||||
channel: usize,
|
||||
channel: usize, //
|
||||
buffer: AudioBuffer,
|
||||
loops: bool,
|
||||
},
|
||||
PlayRcBufferOnChannel {
|
||||
channel: usize,
|
||||
channel: usize, //
|
||||
buffer: Rc<AudioBuffer>,
|
||||
loops: bool,
|
||||
},
|
||||
PlayGenerator {
|
||||
generator: Box<dyn AudioGenerator>,
|
||||
generator: Box<dyn AudioGenerator>, //
|
||||
loops: bool,
|
||||
},
|
||||
PlayGeneratorOnChannel {
|
||||
channel: usize,
|
||||
channel: usize, //
|
||||
generator: Box<dyn AudioGenerator>,
|
||||
loops: bool,
|
||||
},
|
||||
|
@ -44,38 +44,38 @@ impl std::fmt::Debug for AudioCommand {
|
|||
StopChannel(n) => write!(f, "StopChannel({})", n),
|
||||
StopAllChannels => write!(f, "StopAllChannels"),
|
||||
PlayBuffer { buffer, loops } => {
|
||||
f.debug_struct("PlayBuffer")
|
||||
f.debug_struct("PlayBuffer") //
|
||||
.field("buffer", buffer)
|
||||
.field("loops", loops)
|
||||
.finish()
|
||||
}
|
||||
PlayRcBuffer { buffer, loops } => {
|
||||
f.debug_struct("PlayRcBuffer")
|
||||
f.debug_struct("PlayRcBuffer") //
|
||||
.field("buffer", buffer)
|
||||
.field("loops", loops)
|
||||
.finish()
|
||||
}
|
||||
PlayBufferOnChannel { channel, buffer, loops } => {
|
||||
f.debug_struct("PlayBufferOnChannel")
|
||||
f.debug_struct("PlayBufferOnChannel") //
|
||||
.field("channel", channel)
|
||||
.field("buffer", buffer)
|
||||
.field("loops", loops)
|
||||
.finish()
|
||||
}
|
||||
PlayRcBufferOnChannel { channel, buffer, loops } => {
|
||||
f.debug_struct("PlayRcBufferOnChannel")
|
||||
f.debug_struct("PlayRcBufferOnChannel") //
|
||||
.field("channel", channel)
|
||||
.field("buffer", buffer)
|
||||
.field("loops", loops)
|
||||
.finish()
|
||||
}
|
||||
PlayGenerator { loops, .. } => {
|
||||
f.debug_struct("PlayGenerator")
|
||||
f.debug_struct("PlayGenerator") //
|
||||
.field("loops", loops)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
PlayGeneratorOnChannel { channel, loops, .. } => {
|
||||
f.debug_struct("PlayGeneratorOnChannel")
|
||||
f.debug_struct("PlayGeneratorOnChannel") //
|
||||
.field("channel", channel)
|
||||
.field("loops", loops)
|
||||
.finish_non_exhaustive()
|
||||
|
@ -98,10 +98,7 @@ pub struct AudioQueue {
|
|||
impl AudioQueue {
|
||||
/// Creates and returns a new [`AudioQueue`] instance.
|
||||
pub fn new(audio: &Audio) -> Self {
|
||||
AudioQueue {
|
||||
spec: audio.spec,
|
||||
commands: VecDeque::new(),
|
||||
}
|
||||
AudioQueue { spec: audio.spec, commands: VecDeque::new() }
|
||||
}
|
||||
|
||||
/// Returns the spec that this queue is currently set to play. All audio to be played via
|
||||
|
@ -130,16 +127,12 @@ impl AudioQueue {
|
|||
/// Queues a command to play a copy of the given [`AudioBuffer`]'s data. The buffer will be
|
||||
/// played on the first channel found that is not already playing. If all channels are already
|
||||
/// playing, then nothing will be done.
|
||||
pub fn play_buffer(
|
||||
&mut self,
|
||||
buffer: &AudioBuffer,
|
||||
loops: bool,
|
||||
) -> Result<(), AudioDeviceError> {
|
||||
pub fn play_buffer(&mut self, buffer: &AudioBuffer, loops: bool) -> Result<(), AudioDeviceError> {
|
||||
if *buffer.spec() != self.spec {
|
||||
Err(AudioDeviceError::AudioSpecMismatch)
|
||||
} else {
|
||||
self.commands.push_back(AudioCommand::PlayBuffer {
|
||||
buffer: buffer.clone(),
|
||||
buffer: buffer.clone(), //
|
||||
loops,
|
||||
});
|
||||
Ok(())
|
||||
|
@ -150,18 +143,11 @@ impl AudioQueue {
|
|||
/// the first channel found that is not already playing. If all channels are already playing,
|
||||
/// then nothing will be done. This method is more performant than [`AudioQueue::play_buffer`],
|
||||
/// as that method will always immediately copy the given buffer to create the queued command.
|
||||
pub fn play_buffer_rc(
|
||||
&mut self,
|
||||
buffer: Rc<AudioBuffer>,
|
||||
loops: bool,
|
||||
) -> Result<(), AudioDeviceError> {
|
||||
pub fn play_buffer_rc(&mut self, buffer: Rc<AudioBuffer>, loops: bool) -> Result<(), AudioDeviceError> {
|
||||
if *buffer.spec() != self.spec {
|
||||
Err(AudioDeviceError::AudioSpecMismatch)
|
||||
} else {
|
||||
self.commands.push_back(AudioCommand::PlayRcBuffer {
|
||||
buffer,
|
||||
loops,
|
||||
});
|
||||
self.commands.push_back(AudioCommand::PlayRcBuffer { buffer, loops });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +167,7 @@ impl AudioQueue {
|
|||
Err(AudioDeviceError::ChannelIndexOutOfRange(channel_index))
|
||||
} else {
|
||||
self.commands.push_back(AudioCommand::PlayBufferOnChannel {
|
||||
channel: channel_index,
|
||||
channel: channel_index, //
|
||||
buffer: buffer.clone(),
|
||||
loops,
|
||||
});
|
||||
|
@ -205,7 +191,7 @@ impl AudioQueue {
|
|||
Err(AudioDeviceError::ChannelIndexOutOfRange(channel_index))
|
||||
} else {
|
||||
self.commands.push_back(AudioCommand::PlayRcBufferOnChannel {
|
||||
channel: channel_index,
|
||||
channel: channel_index, //
|
||||
buffer,
|
||||
loops,
|
||||
});
|
||||
|
@ -215,11 +201,7 @@ impl AudioQueue {
|
|||
|
||||
/// Queues a command to play the given [`AudioGenerator`] on the first channel found that is
|
||||
/// not already playing. If all channels are already playing, then nothing will be done.
|
||||
pub fn play_generator(
|
||||
&mut self,
|
||||
generator: Box<dyn AudioGenerator>,
|
||||
loops: bool,
|
||||
) -> Result<(), AudioDeviceError> {
|
||||
pub fn play_generator(&mut self, generator: Box<dyn AudioGenerator>, loops: bool) -> Result<(), AudioDeviceError> {
|
||||
self.commands.push_back(AudioCommand::PlayGenerator { generator, loops });
|
||||
Ok(())
|
||||
}
|
||||
|
@ -233,7 +215,7 @@ impl AudioQueue {
|
|||
loops: bool,
|
||||
) -> Result<(), AudioDeviceError> {
|
||||
self.commands.push_back(AudioCommand::PlayGeneratorOnChannel {
|
||||
channel: channel_index,
|
||||
channel: channel_index, //
|
||||
generator,
|
||||
loops,
|
||||
});
|
||||
|
@ -286,4 +268,4 @@ impl AudioQueue {
|
|||
let mut device = audio.lock();
|
||||
self.apply_to_device(&mut device)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,11 +134,13 @@ use thiserror::Error;
|
|||
use crate::audio::device::AudioDeviceError;
|
||||
use crate::events::{EventListeners, EventPublisher};
|
||||
use crate::states::{AppState, StateError, States};
|
||||
use crate::system::{System, SystemError};
|
||||
use crate::system::res::SystemResources;
|
||||
use crate::system::{System, SystemError};
|
||||
|
||||
pub trait CoreState<SystemResType>
|
||||
where SystemResType: SystemResources {
|
||||
where
|
||||
SystemResType: SystemResources,
|
||||
{
|
||||
fn system(&self) -> &System<SystemResType>;
|
||||
fn system_mut(&mut self) -> &mut System<SystemResType>;
|
||||
|
||||
|
@ -155,14 +157,17 @@ where SystemResType: SystemResources {
|
|||
}
|
||||
|
||||
pub trait CoreStateWithEvents<SystemResType, EventType>: CoreState<SystemResType>
|
||||
where SystemResType: SystemResources {
|
||||
where
|
||||
SystemResType: SystemResources,
|
||||
{
|
||||
fn event_publisher(&mut self) -> &mut EventPublisher<EventType>;
|
||||
}
|
||||
|
||||
pub trait SupportSystems {}
|
||||
|
||||
pub trait SupportSystemsWithEvents<SystemResType, EventType>: SupportSystems
|
||||
where SystemResType: SystemResources
|
||||
where
|
||||
SystemResType: SystemResources,
|
||||
{
|
||||
type ContextType: CoreStateWithEvents<SystemResType, EventType>;
|
||||
fn event_listeners(&mut self) -> &mut EventListeners<EventType, Self::ContextType>;
|
||||
|
@ -174,7 +179,9 @@ where SystemResType: SystemResources
|
|||
}
|
||||
|
||||
pub trait AppContext<SystemResType>
|
||||
where SystemResType: SystemResources {
|
||||
where
|
||||
SystemResType: SystemResources,
|
||||
{
|
||||
type CoreType: CoreState<SystemResType>;
|
||||
type SupportType: SupportSystems;
|
||||
|
||||
|
|
|
@ -47,16 +47,12 @@ impl<T: Component> GenericComponentStore for ComponentStore<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_component_store<T: Component>(
|
||||
collection: &dyn GenericComponentStore,
|
||||
) -> &ComponentStore<T> {
|
||||
pub fn as_component_store<T: Component>(collection: &dyn GenericComponentStore) -> &ComponentStore<T> {
|
||||
collection.as_any().downcast_ref().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_component_store_mut<T: Component>(
|
||||
collection: &mut dyn GenericComponentStore,
|
||||
) -> &mut ComponentStore<T> {
|
||||
pub fn as_component_store_mut<T: Component>(collection: &mut dyn GenericComponentStore) -> &mut ComponentStore<T> {
|
||||
collection.as_any_mut().downcast_mut().unwrap()
|
||||
}
|
||||
|
||||
|
@ -83,7 +79,7 @@ impl Entities {
|
|||
/// Creates and returns a new instance of an entity manager.
|
||||
pub fn new() -> Self {
|
||||
Entities {
|
||||
entities: HashSet::new(),
|
||||
entities: HashSet::new(), //
|
||||
component_stores: HashMap::new(),
|
||||
next_id: 0,
|
||||
}
|
||||
|
@ -100,9 +96,7 @@ impl Entities {
|
|||
None
|
||||
} else {
|
||||
let type_id = TypeId::of::<T>();
|
||||
Some(as_component_store(
|
||||
self.component_stores.get(&type_id).unwrap().as_ref(),
|
||||
))
|
||||
Some(as_component_store(self.component_stores.get(&type_id).unwrap().as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,8 +106,7 @@ impl Entities {
|
|||
} else {
|
||||
let component_store = ComponentStore::<T>::new(HashMap::new());
|
||||
let type_id = TypeId::of::<T>();
|
||||
self.component_stores
|
||||
.insert(type_id, Box::new(component_store));
|
||||
self.component_stores.insert(type_id, Box::new(component_store));
|
||||
as_component_store(self.component_stores.get(&type_id).unwrap().as_ref())
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +172,7 @@ impl Entities {
|
|||
if let Some(component_store) = self.get_component_store::<T>() {
|
||||
component_store.borrow_mut().insert(entity, component);
|
||||
} else {
|
||||
self.add_component_store::<T>()
|
||||
self.add_component_store::<T>() //
|
||||
.borrow_mut()
|
||||
.insert(entity, component);
|
||||
}
|
||||
|
@ -445,7 +438,7 @@ impl<U, R> std::fmt::Debug for ComponentSystems<U, R> {
|
|||
impl<U, R> ComponentSystems<U, R> {
|
||||
pub fn new() -> Self {
|
||||
ComponentSystems {
|
||||
update_systems: Vec::new(),
|
||||
update_systems: Vec::new(), //
|
||||
render_systems: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
@ -735,10 +728,7 @@ mod tests {
|
|||
let health = healths.get_mut(&entity);
|
||||
let position = positions.get_mut(&entity);
|
||||
|
||||
println!(
|
||||
"entity {}, health: {:?}, position: {:?}",
|
||||
name.0, health, position
|
||||
);
|
||||
println!("entity {}, health: {:?}, position: {:?}", name.0, health, position);
|
||||
|
||||
if let Some(mut health) = health {
|
||||
health.0 += 5;
|
||||
|
@ -763,10 +753,7 @@ mod tests {
|
|||
|
||||
impl ComponentSystemContext {
|
||||
pub fn new(entities: Entities) -> Self {
|
||||
ComponentSystemContext {
|
||||
delta: 0.0,
|
||||
entities,
|
||||
}
|
||||
ComponentSystemContext { delta: 0.0, entities }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ pub struct EventPublisher<EventType> {
|
|||
|
||||
impl<EventType> std::fmt::Debug for EventPublisher<EventType> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("EventPublisher")
|
||||
f.debug_struct("EventPublisher") //
|
||||
.field("queue.len()", &self.queue.len())
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
|
@ -22,9 +22,7 @@ impl<EventType> std::fmt::Debug for EventPublisher<EventType> {
|
|||
|
||||
impl<EventType> EventPublisher<EventType> {
|
||||
pub fn new() -> Self {
|
||||
EventPublisher {
|
||||
queue: VecDeque::new(),
|
||||
}
|
||||
EventPublisher { queue: VecDeque::new() }
|
||||
}
|
||||
|
||||
/// Returns the number of events that have been queued.
|
||||
|
@ -78,7 +76,7 @@ impl<EventType, ContextType> std::fmt::Debug for EventListeners<EventType, Conte
|
|||
impl<EventType, ContextType> EventListeners<EventType, ContextType> {
|
||||
pub fn new() -> Self {
|
||||
EventListeners {
|
||||
listeners: Vec::new(),
|
||||
listeners: Vec::new(), //
|
||||
dispatch_queue: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +191,7 @@ mod tests {
|
|||
false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,10 +281,7 @@ mod tests {
|
|||
listeners.dispatch_queue(&mut context);
|
||||
assert!(!context.events.is_empty());
|
||||
assert_eq!(0, context.count);
|
||||
assert_eq!(
|
||||
vec![Dummy, Foobar(1), Dummy, Foobar(42)],
|
||||
context.events
|
||||
);
|
||||
assert_eq!(vec![Dummy, Foobar(1), Dummy, Foobar(42)], context.events);
|
||||
|
||||
let mut context = TestContext::new();
|
||||
assert!(context.events.is_empty());
|
||||
|
@ -303,10 +298,7 @@ mod tests {
|
|||
listeners.dispatch_queue(&mut context);
|
||||
assert!(!context.events.is_empty());
|
||||
assert_eq!(3, context.count);
|
||||
assert_eq!(
|
||||
vec![Foobar(10), Foobar(20), Dummy],
|
||||
context.events
|
||||
);
|
||||
assert_eq!(vec![Foobar(10), Foobar(20), Dummy], context.events);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -331,9 +323,6 @@ mod tests {
|
|||
listeners.dispatch_queue(&mut context);
|
||||
assert!(!context.events.is_empty());
|
||||
assert_eq!(3, context.count);
|
||||
assert_eq!(
|
||||
vec![Message("hello"), Dummy, Foobar(3)],
|
||||
context.events
|
||||
);
|
||||
assert_eq!(vec![Message("hello"), Dummy, Foobar(3)], context.events);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -255,14 +255,21 @@ pub unsafe fn per_pixel_rotozoom_blit<PixelType: Pixel>(
|
|||
// destination bitmap's center point as the origin _except_ for the final post-transform
|
||||
// offset where we instead use the source bitmap's center point to re-translate the
|
||||
// coordinates back. this is necessary because of the (potential) scale differences!
|
||||
let src_x = ((x as f32 - half_dest_width) * cos * scale_x) - ((y as f32 - half_dest_height) * sin * scale_x) + half_src_width;
|
||||
let src_y = ((x as f32 - half_dest_width) * sin * scale_y) + ((y as f32 - half_dest_height) * cos * scale_y) + half_src_height;
|
||||
let src_x = ((x as f32 - half_dest_width) * cos * scale_x)
|
||||
- ((y as f32 - half_dest_height) * sin * scale_x)
|
||||
+ half_src_width;
|
||||
let src_y = ((x as f32 - half_dest_width) * sin * scale_y)
|
||||
+ ((y as f32 - half_dest_height) * cos * scale_y)
|
||||
+ half_src_height;
|
||||
|
||||
// ensure the source x,y is in bounds, as it very well might not be depending on exactly
|
||||
// where we are inside the destination area currently. also, we're not interested in
|
||||
// wrapping of course, since we just want to draw a single instance of this source
|
||||
// bitmap.
|
||||
if src_x >= 0.0 && (src_x as i32) < (src_region.width as i32) && src_y >= 0.0 && (src_y as i32) < (src_region.height as i32) {
|
||||
if src_x >= 0.0
|
||||
&& (src_x as i32) < (src_region.width as i32)
|
||||
&& src_y >= 0.0 && (src_y as i32) < (src_region.height as i32)
|
||||
{
|
||||
let pixel = src.get_pixel_unchecked(src_x as i32 + src_region.x, src_y as i32 + src_region.y);
|
||||
|
||||
let draw_x = x + dest_x;
|
||||
|
@ -298,7 +305,13 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
vertical_flip: bool,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self,
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
*dest_pixels = *src_pixels;
|
||||
},
|
||||
|
@ -314,7 +327,11 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
transparent_color: PixelType,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = *src_pixels;
|
||||
|
@ -334,7 +351,13 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
vertical_flip: bool,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = *src_pixels;
|
||||
|
@ -353,7 +376,11 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
draw_color: PixelType,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = draw_color;
|
||||
|
@ -374,7 +401,13 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
draw_color: PixelType,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = draw_color;
|
||||
|
@ -394,7 +427,14 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
scale_y: f32,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
dest_bitmap.set_pixel(draw_x, draw_y, src_pixel);
|
||||
},
|
||||
|
@ -413,7 +453,14 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
transparent_color: PixelType,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
if transparent_color != src_pixel {
|
||||
dest_bitmap.set_pixel(draw_x, draw_y, src_pixel);
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
//!
|
||||
//! Only a subset of the most common Bitmap drawing operations will be provided here.
|
||||
|
||||
use crate::graphics::bitmap::BitmapError;
|
||||
use crate::graphics::bitmap::indexed::blit::IndexedBlitMethod;
|
||||
use crate::graphics::bitmap::indexed::IndexedBitmap;
|
||||
use crate::graphics::bitmap::rgb::blit::RgbaBlitMethod;
|
||||
use crate::graphics::bitmap::rgb::RgbaBitmap;
|
||||
use crate::graphics::bitmap::BitmapError;
|
||||
use crate::graphics::Pixel;
|
||||
use crate::math::rect::Rect;
|
||||
|
||||
|
@ -87,7 +87,7 @@ pub trait GeneralBitmap: Sized + Clone {
|
|||
src: &Self,
|
||||
src_region: &Rect,
|
||||
dest_x: i32,
|
||||
dest_y: i32
|
||||
dest_y: i32,
|
||||
);
|
||||
|
||||
fn blit(&mut self, method: GeneralBlitMethod<Self::PixelType>, src: &Self, x: i32, y: i32) {
|
||||
|
@ -165,7 +165,7 @@ impl GeneralBitmap for IndexedBitmap {
|
|||
src: &Self,
|
||||
src_region: &Rect,
|
||||
dest_x: i32,
|
||||
dest_y: i32
|
||||
dest_y: i32,
|
||||
) {
|
||||
let blit_method = match method {
|
||||
GeneralBlitMethod::Solid => IndexedBlitMethod::Solid,
|
||||
|
@ -244,7 +244,7 @@ impl GeneralBitmap for RgbaBitmap {
|
|||
src: &Self,
|
||||
src_region: &Rect,
|
||||
dest_x: i32,
|
||||
dest_y: i32
|
||||
dest_y: i32,
|
||||
) {
|
||||
let blit_method = match method {
|
||||
GeneralBlitMethod::Solid => RgbaBlitMethod::Solid,
|
||||
|
@ -252,4 +252,4 @@ impl GeneralBitmap for RgbaBitmap {
|
|||
};
|
||||
self.blit_region(blit_method, src, src_region, dest_x, dest_y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::graphics::bitmap::rgb::RgbaBitmap;
|
|||
use crate::graphics::palette::{Palette, PaletteError, PaletteFormat};
|
||||
use crate::utils::lzwgif::{lzw_decode, lzw_encode, LzwError};
|
||||
|
||||
const BITS_FOR_256_COLORS: u32 = 7; // formula is `2 ^ (bits + 1) = num_colors`
|
||||
const BITS_FOR_256_COLORS: u32 = 7; // formula is `2 ^ (bits + 1) = num_colors`
|
||||
|
||||
fn bits_to_num_colors(bits: u32) -> u32 {
|
||||
1_u32.wrapping_shl(bits + 1)
|
||||
|
@ -119,7 +119,7 @@ impl GifHeader {
|
|||
let mut version = [0u8; 3];
|
||||
reader.read_exact(&mut version)?;
|
||||
Ok(GifHeader {
|
||||
signature,
|
||||
signature, //
|
||||
version,
|
||||
screen_width: reader.read_u16::<LittleEndian>()?,
|
||||
screen_height: reader.read_u16::<LittleEndian>()?,
|
||||
|
@ -161,7 +161,7 @@ impl GifExtensionLabel {
|
|||
0x01 => Ok(PlainText),
|
||||
0xff => Ok(Application),
|
||||
0xfe => Ok(Comment),
|
||||
_ => Err(GifError::UnknownExtension(value))
|
||||
_ => Err(GifError::UnknownExtension(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ struct GraphicControlExtension {
|
|||
impl GraphicControlExtension {
|
||||
pub fn read<T: Read>(reader: &mut T) -> Result<Self, GifError> {
|
||||
Ok(GraphicControlExtension {
|
||||
block_size: reader.read_u8()?,
|
||||
block_size: reader.read_u8()?, //
|
||||
flags: reader.read_u8()?,
|
||||
delay: reader.read_u16::<LittleEndian>()?,
|
||||
transparent_color: reader.read_u8()?,
|
||||
|
@ -259,7 +259,7 @@ impl ApplicationExtension {
|
|||
let mut authentication_code = [0u8; 3];
|
||||
reader.read_exact(&mut authentication_code)?;
|
||||
Ok(ApplicationExtension {
|
||||
block_size,
|
||||
block_size, //
|
||||
identifier,
|
||||
authentication_code,
|
||||
data: read_raw_sub_block_data(reader)?,
|
||||
|
@ -283,9 +283,7 @@ struct CommentExtension {
|
|||
#[allow(dead_code)]
|
||||
impl CommentExtension {
|
||||
pub fn read<T: Read>(reader: &mut T) -> Result<Self, GifError> {
|
||||
Ok(CommentExtension {
|
||||
data: read_raw_sub_block_data(reader)?,
|
||||
})
|
||||
Ok(CommentExtension { data: read_raw_sub_block_data(reader)? })
|
||||
}
|
||||
|
||||
pub fn write<T: Write>(&self, writer: &mut T) -> Result<(), GifError> {
|
||||
|
@ -331,7 +329,7 @@ impl LocalImageDescriptor {
|
|||
|
||||
pub fn read<T: Read>(reader: &mut T) -> Result<Self, GifError> {
|
||||
Ok(LocalImageDescriptor {
|
||||
x: reader.read_u16::<LittleEndian>()?,
|
||||
x: reader.read_u16::<LittleEndian>()?, //
|
||||
y: reader.read_u16::<LittleEndian>()?,
|
||||
width: reader.read_u16::<LittleEndian>()?,
|
||||
height: reader.read_u16::<LittleEndian>()?,
|
||||
|
@ -359,11 +357,7 @@ fn load_image_section<T: ReadBytesExt>(
|
|||
let palette: Option<Palette>;
|
||||
if descriptor.has_local_color_table() {
|
||||
let num_colors = bits_to_num_colors(descriptor.local_color_table_bits() as u32) as usize;
|
||||
palette = Some(Palette::load_num_colors_from_bytes(
|
||||
reader,
|
||||
PaletteFormat::Normal,
|
||||
num_colors,
|
||||
)?);
|
||||
palette = Some(Palette::load_num_colors_from_bytes(reader, PaletteFormat::Normal, num_colors)?);
|
||||
} else {
|
||||
palette = None; // we expect that there was a global color table previously
|
||||
}
|
||||
|
@ -375,17 +369,14 @@ fn load_image_section<T: ReadBytesExt>(
|
|||
Ok((bitmap, palette))
|
||||
}
|
||||
|
||||
fn save_image_section<T: WriteBytesExt>(
|
||||
writer: &mut T,
|
||||
bitmap: &IndexedBitmap,
|
||||
) -> Result<(), GifError> {
|
||||
fn save_image_section<T: WriteBytesExt>(writer: &mut T, bitmap: &IndexedBitmap) -> Result<(), GifError> {
|
||||
writer.write_u8(IMAGE_DESCRIPTOR_SEPARATOR)?;
|
||||
let image_descriptor = LocalImageDescriptor {
|
||||
x: 0,
|
||||
x: 0, //
|
||||
y: 0,
|
||||
width: bitmap.width as u16,
|
||||
height: bitmap.height as u16,
|
||||
flags: 0, // again, we're not using local color tables, so no flags to set here
|
||||
flags: 0, // again, we're not using local color tables, so no flags to set here
|
||||
};
|
||||
image_descriptor.write(writer)?;
|
||||
|
||||
|
@ -400,9 +391,7 @@ fn save_image_section<T: WriteBytesExt>(
|
|||
}
|
||||
|
||||
impl IndexedBitmap {
|
||||
pub fn load_gif_bytes<T: ReadBytesExt>(
|
||||
reader: &mut T,
|
||||
) -> Result<(IndexedBitmap, Palette), GifError> {
|
||||
pub fn load_gif_bytes<T: ReadBytesExt>(reader: &mut T) -> Result<(IndexedBitmap, Palette), GifError> {
|
||||
let header = GifHeader::read(reader)?;
|
||||
if header.signature != *b"GIF" || header.version != *b"89a" {
|
||||
return Err(GifError::BadFile(String::from("Expected GIF89a header signature")));
|
||||
|
@ -412,11 +401,7 @@ impl IndexedBitmap {
|
|||
let mut palette: Option<Palette>;
|
||||
if header.has_global_color_table() {
|
||||
let num_colors = bits_to_num_colors(header.global_color_table_bits() as u32) as usize;
|
||||
palette = Some(Palette::load_num_colors_from_bytes(
|
||||
reader,
|
||||
PaletteFormat::Normal,
|
||||
num_colors,
|
||||
)?);
|
||||
palette = Some(Palette::load_num_colors_from_bytes(reader, PaletteFormat::Normal, num_colors)?);
|
||||
} else {
|
||||
palette = None; // we expect to find a local color table later
|
||||
}
|
||||
|
@ -468,7 +453,10 @@ impl IndexedBitmap {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(GifError::BadFile(format!("Unexpected byte found {} not a file trailer, image separator or extension introducer", current_byte)));
|
||||
return Err(GifError::BadFile(format!(
|
||||
"Unexpected byte found {} not a file trailer, image separator or extension introducer",
|
||||
current_byte
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -526,7 +514,7 @@ impl IndexedBitmap {
|
|||
writer.write_u8(EXTENSION_INTRODUCER)?;
|
||||
writer.write_u8(GifExtensionLabel::GraphicControl as u8)?;
|
||||
let graphic_control = GraphicControlExtension {
|
||||
block_size: 4,
|
||||
block_size: 4, //
|
||||
flags: 0,
|
||||
delay: 0,
|
||||
transparent_color,
|
||||
|
@ -540,12 +528,7 @@ impl IndexedBitmap {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn to_gif_file(
|
||||
&self,
|
||||
path: &Path,
|
||||
palette: &Palette,
|
||||
settings: GifSettings,
|
||||
) -> Result<(), GifError> {
|
||||
pub fn to_gif_file(&self, path: &Path, palette: &Palette, settings: GifSettings) -> Result<(), GifError> {
|
||||
let f = File::create(path)?;
|
||||
let mut writer = BufWriter::new(f);
|
||||
self.to_gif_bytes(&mut writer, palette, settings)
|
||||
|
@ -556,9 +539,7 @@ impl IndexedBitmap {
|
|||
// multi-pixel-depth support.
|
||||
|
||||
impl RgbaBitmap {
|
||||
pub fn load_gif_bytes<T: ReadBytesExt>(
|
||||
reader: &mut T,
|
||||
) -> Result<(RgbaBitmap, Palette), GifError> {
|
||||
pub fn load_gif_bytes<T: ReadBytesExt>(reader: &mut T) -> Result<(RgbaBitmap, Palette), GifError> {
|
||||
let (temp_bitmap, palette) = IndexedBitmap::load_gif_bytes(reader)?;
|
||||
let output = temp_bitmap.to_rgba(&palette);
|
||||
Ok((output, palette))
|
||||
|
@ -593,9 +574,10 @@ pub mod tests {
|
|||
|
||||
let ref_pixels = load_raw_indexed(test_file(Path::new("small.bin")).as_path())?;
|
||||
let dp2_palette = Palette::load_from_file(
|
||||
test_assets_file(Path::new("dp2.pal")).as_path(),
|
||||
test_assets_file(Path::new("dp2.pal")).as_path(), //
|
||||
PaletteFormat::Normal,
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (bmp, palette) = IndexedBitmap::load_gif_file(test_file(Path::new("small.gif")).as_path())?;
|
||||
assert_eq!(16, bmp.width());
|
||||
|
|
|
@ -9,7 +9,7 @@ use thiserror::Error;
|
|||
use crate::graphics::bitmap::indexed::IndexedBitmap;
|
||||
use crate::graphics::bitmap::rgb::RgbaBitmap;
|
||||
use crate::graphics::palette::{Palette, PaletteError, PaletteFormat};
|
||||
use crate::utils::packbits::{pack_bits, PackBitsError, unpack_bits};
|
||||
use crate::utils::packbits::{pack_bits, unpack_bits, PackBitsError};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum IffError {
|
||||
|
@ -91,11 +91,7 @@ impl FormChunkHeader {
|
|||
let chunk_id = IffId::read(reader)?;
|
||||
let size = reader.read_u32::<BigEndian>()?;
|
||||
let type_id = IffId::read(reader)?;
|
||||
Ok(FormChunkHeader {
|
||||
chunk_id,
|
||||
size,
|
||||
type_id,
|
||||
})
|
||||
Ok(FormChunkHeader { chunk_id, size, type_id })
|
||||
}
|
||||
|
||||
pub fn write<T: WriteBytesExt>(&self, writer: &mut T) -> Result<(), IffError> {
|
||||
|
@ -287,7 +283,7 @@ fn load_planar_body<T: ReadBytesExt>(reader: &mut T, bmhd: &BMHDChunk) -> Result
|
|||
// scanline, the destination pointer will contain VGA-friendly
|
||||
// "chunky pixel"-format pixel data
|
||||
merge_bitplane(
|
||||
plane,
|
||||
plane, //
|
||||
&buffer,
|
||||
bitmap.pixels_at_mut(0, y as i32).unwrap(),
|
||||
row_bytes,
|
||||
|
@ -327,7 +323,7 @@ fn write_planar_body<T: WriteBytesExt>(
|
|||
for y in 0..bitmap.height() {
|
||||
for plane in 0..(bmhd.bitplanes as u32) {
|
||||
extract_bitplane(
|
||||
plane,
|
||||
plane, //
|
||||
bitmap.pixels_at(0, y as i32).unwrap(),
|
||||
&mut buffer,
|
||||
row_bytes,
|
||||
|
@ -369,19 +365,13 @@ fn write_chunky_body<T: WriteBytesExt>(
|
|||
}
|
||||
|
||||
impl IndexedBitmap {
|
||||
pub fn load_iff_bytes<T: ReadBytesExt + Seek>(
|
||||
reader: &mut T,
|
||||
) -> Result<(IndexedBitmap, Palette), IffError> {
|
||||
pub fn load_iff_bytes<T: ReadBytesExt + Seek>(reader: &mut T) -> Result<(IndexedBitmap, Palette), IffError> {
|
||||
let form_chunk = FormChunkHeader::read(reader)?;
|
||||
if form_chunk.chunk_id.id != *b"FORM" {
|
||||
return Err(IffError::BadFile(String::from(
|
||||
"Unexpected form chunk ID, probably not an IFF file",
|
||||
)));
|
||||
return Err(IffError::BadFile(String::from("Unexpected form chunk ID, probably not an IFF file")));
|
||||
}
|
||||
if form_chunk.type_id.id != *b"ILBM" && form_chunk.type_id.id != *b"PBM " {
|
||||
return Err(IffError::BadFile(String::from(
|
||||
"Only ILBM or PBM formats are supported",
|
||||
)));
|
||||
return Err(IffError::BadFile(String::from("Only ILBM or PBM formats are supported")));
|
||||
}
|
||||
|
||||
let mut bmhd: Option<BMHDChunk> = None;
|
||||
|
@ -391,11 +381,9 @@ impl IndexedBitmap {
|
|||
loop {
|
||||
let header = match SubChunkHeader::read(reader) {
|
||||
Ok(header) => header,
|
||||
Err(IffError::IOError(io_error))
|
||||
if io_error.kind() == io::ErrorKind::UnexpectedEof =>
|
||||
{
|
||||
break;
|
||||
}
|
||||
Err(IffError::IOError(io_error)) if io_error.kind() == io::ErrorKind::UnexpectedEof => {
|
||||
break;
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let chunk_data_position = reader.stream_position()?;
|
||||
|
@ -404,18 +392,14 @@ impl IndexedBitmap {
|
|||
if header.chunk_id.id == *b"BMHD" {
|
||||
bmhd = Some(BMHDChunk::read(reader)?);
|
||||
if bmhd.as_ref().unwrap().bitplanes != 8 {
|
||||
return Err(IffError::BadFile(String::from(
|
||||
"Only 8bpp files are supported",
|
||||
)));
|
||||
return Err(IffError::BadFile(String::from("Only 8bpp files are supported")));
|
||||
}
|
||||
if bmhd.as_ref().unwrap().masking == 1 {
|
||||
return Err(IffError::BadFile(String::from("Masking is not supported")));
|
||||
}
|
||||
} else if header.chunk_id.id == *b"CMAP" {
|
||||
if header.size != 768 {
|
||||
return Err(IffError::BadFile(String::from(
|
||||
"Only 256 color files are supported",
|
||||
)));
|
||||
return Err(IffError::BadFile(String::from("Only 256 color files are supported")));
|
||||
}
|
||||
palette = Some(Palette::load_from_bytes(reader, PaletteFormat::Normal)?)
|
||||
} else if header.chunk_id.id == *b"BODY" {
|
||||
|
@ -464,22 +448,16 @@ impl IndexedBitmap {
|
|||
|
||||
let mut form_chunk = FormChunkHeader {
|
||||
chunk_id: IffId { id: *b"FORM" },
|
||||
type_id: IffId {
|
||||
id: format.type_id(),
|
||||
},
|
||||
type_id: IffId { id: format.type_id() },
|
||||
size: 0, // filled in later once we know the size
|
||||
};
|
||||
|
||||
// skip over the form chunk for now. will come back here and write it out later once we
|
||||
// know what the final size is
|
||||
writer.seek(SeekFrom::Current(
|
||||
std::mem::size_of::<FormChunkHeader>() as i64
|
||||
))?;
|
||||
writer.seek(SeekFrom::Current(std::mem::size_of::<FormChunkHeader>() as i64))?;
|
||||
|
||||
let bmhd_chunk_header = SubChunkHeader {
|
||||
chunk_id: IffId { id: *b"BMHD" },
|
||||
size: std::mem::size_of::<BMHDChunk>() as u32,
|
||||
};
|
||||
let bmhd_chunk_header =
|
||||
SubChunkHeader { chunk_id: IffId { id: *b"BMHD" }, size: std::mem::size_of::<BMHDChunk>() as u32 };
|
||||
let bmhd = BMHDChunk {
|
||||
width: self.width() as u16,
|
||||
height: self.height() as u16,
|
||||
|
@ -501,7 +479,7 @@ impl IndexedBitmap {
|
|||
|
||||
let cmap_chunk_header = SubChunkHeader {
|
||||
chunk_id: IffId { id: *b"CMAP" },
|
||||
size: 768,
|
||||
size: 768, //
|
||||
};
|
||||
cmap_chunk_header.write(writer)?;
|
||||
palette.to_bytes(writer, PaletteFormat::Normal)?;
|
||||
|
@ -515,9 +493,7 @@ impl IndexedBitmap {
|
|||
|
||||
// skip over the body chunk header for now. we will again come back here and write it out
|
||||
// later once we know what the final size again.
|
||||
writer.seek(SeekFrom::Current(
|
||||
std::mem::size_of::<SubChunkHeader>() as i64
|
||||
))?;
|
||||
writer.seek(SeekFrom::Current(std::mem::size_of::<SubChunkHeader>() as i64))?;
|
||||
|
||||
if format.chunky() {
|
||||
write_chunky_body(writer, self, &bmhd)?;
|
||||
|
@ -548,12 +524,7 @@ impl IndexedBitmap {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn to_iff_file(
|
||||
&self,
|
||||
path: &Path,
|
||||
palette: &Palette,
|
||||
format: IffFormat,
|
||||
) -> Result<(), IffError> {
|
||||
pub fn to_iff_file(&self, path: &Path, palette: &Palette, format: IffFormat) -> Result<(), IffError> {
|
||||
let f = File::create(path)?;
|
||||
let mut writer = BufWriter::new(f);
|
||||
self.to_iff_bytes(&mut writer, palette, format)
|
||||
|
@ -564,9 +535,7 @@ impl IndexedBitmap {
|
|||
// multi-pixel-depth support.
|
||||
|
||||
impl RgbaBitmap {
|
||||
pub fn load_iff_bytes<T: ReadBytesExt + Seek>(
|
||||
reader: &mut T,
|
||||
) -> Result<(RgbaBitmap, Palette), IffError> {
|
||||
pub fn load_iff_bytes<T: ReadBytesExt + Seek>(reader: &mut T) -> Result<(RgbaBitmap, Palette), IffError> {
|
||||
let (temp_bitmap, palette) = IndexedBitmap::load_iff_bytes(reader)?;
|
||||
let output = temp_bitmap.to_rgba(&palette);
|
||||
Ok((output, palette))
|
||||
|
@ -601,9 +570,10 @@ mod tests {
|
|||
|
||||
let ref_pixels = load_raw_indexed(test_file(Path::new("small.bin")).as_path())?;
|
||||
let dp2_palette = Palette::load_from_file(
|
||||
test_assets_file(Path::new("dp2.pal")).as_path(),
|
||||
PaletteFormat::Normal
|
||||
).unwrap();
|
||||
test_assets_file(Path::new("dp2.pal")).as_path(), //
|
||||
PaletteFormat::Normal,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// ILBM format
|
||||
|
||||
|
|
|
@ -68,7 +68,10 @@ pub enum IndexedBlitMethod {
|
|||
/// Same as [IndexedBlitMethod::Transparent] except that the drawn pixels have their color indices
|
||||
/// offset by the amount given. The transparent color check is not affected by the offset and
|
||||
/// is always treated as an absolute palette color index.
|
||||
TransparentOffset { transparent_color: u8, offset: u8 },
|
||||
TransparentOffset {
|
||||
transparent_color: u8,
|
||||
offset: u8,
|
||||
},
|
||||
/// Combination of [IndexedBlitMethod::TransparentFlipped] and [IndexedBlitMethod::TransparentOffset].
|
||||
TransparentFlippedOffset {
|
||||
transparent_color: u8,
|
||||
|
@ -133,7 +136,11 @@ impl IndexedBitmap {
|
|||
blend_map: Rc<BlendMap>,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
if let Some(blended_pixel) = blend_map.blend(*src_pixels, *dest_pixels) {
|
||||
*dest_pixels = blended_pixel;
|
||||
|
@ -155,7 +162,13 @@ impl IndexedBitmap {
|
|||
blend_map: Rc<BlendMap>,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
if let Some(blended_pixel) = blend_map.blend(*src_pixels, *dest_pixels) {
|
||||
*dest_pixels = blended_pixel;
|
||||
|
@ -175,7 +188,11 @@ impl IndexedBitmap {
|
|||
offset: u8,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
*dest_pixels = (*src_pixels).wrapping_add(offset);
|
||||
},
|
||||
|
@ -193,7 +210,13 @@ impl IndexedBitmap {
|
|||
offset: u8,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
*dest_pixels = (*src_pixels).wrapping_add(offset);
|
||||
},
|
||||
|
@ -210,7 +233,11 @@ impl IndexedBitmap {
|
|||
blend_map: Rc<BlendMap>,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
if let Some(blended_pixel) = blend_map.blend(*src_pixels, *dest_pixels) {
|
||||
|
@ -235,7 +262,13 @@ impl IndexedBitmap {
|
|||
blend_map: Rc<BlendMap>,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
if let Some(blended_pixel) = blend_map.blend(*src_pixels, *dest_pixels) {
|
||||
|
@ -258,7 +291,11 @@ impl IndexedBitmap {
|
|||
offset: u8,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = (*src_pixels).wrapping_add(offset);
|
||||
|
@ -279,7 +316,13 @@ impl IndexedBitmap {
|
|||
offset: u8,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = (*src_pixels).wrapping_add(offset);
|
||||
|
@ -300,7 +343,14 @@ impl IndexedBitmap {
|
|||
blend_map: Rc<BlendMap>,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
if let Some(dest_pixel) = dest_bitmap.get_pixel(draw_x, draw_y) {
|
||||
let draw_pixel = if let Some(blended_pixel) = blend_map.blend(src_pixel, dest_pixel) {
|
||||
|
@ -327,7 +377,14 @@ impl IndexedBitmap {
|
|||
blend_map: Rc<BlendMap>,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
if transparent_color != src_pixel {
|
||||
if let Some(dest_pixel) = dest_bitmap.get_pixel(draw_x, draw_y) {
|
||||
|
@ -355,7 +412,14 @@ impl IndexedBitmap {
|
|||
offset: u8,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
let src_pixel = src_pixel.wrapping_add(offset);
|
||||
dest_bitmap.set_pixel(draw_x, draw_y, src_pixel);
|
||||
|
@ -376,7 +440,14 @@ impl IndexedBitmap {
|
|||
offset: u8,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
if transparent_color != src_pixel {
|
||||
let src_pixel = src_pixel.wrapping_add(offset);
|
||||
|
@ -413,15 +484,15 @@ impl IndexedBitmap {
|
|||
RotoZoomTransparentOffset { .. } => {}
|
||||
|
||||
// set axis flip arguments
|
||||
SolidFlipped { horizontal_flip, vertical_flip, .. } |
|
||||
SolidFlippedBlended { horizontal_flip, vertical_flip, .. } |
|
||||
SolidFlippedOffset { horizontal_flip, vertical_flip, .. } |
|
||||
TransparentFlipped { horizontal_flip, vertical_flip, .. } |
|
||||
TransparentFlippedBlended { horizontal_flip, vertical_flip, .. } |
|
||||
TransparentFlippedSingle { horizontal_flip, vertical_flip, .. } |
|
||||
TransparentFlippedOffset { horizontal_flip, vertical_flip, .. } => {
|
||||
SolidFlipped { horizontal_flip, vertical_flip, .. }
|
||||
| SolidFlippedBlended { horizontal_flip, vertical_flip, .. }
|
||||
| SolidFlippedOffset { horizontal_flip, vertical_flip, .. }
|
||||
| TransparentFlipped { horizontal_flip, vertical_flip, .. }
|
||||
| TransparentFlippedBlended { horizontal_flip, vertical_flip, .. }
|
||||
| TransparentFlippedSingle { horizontal_flip, vertical_flip, .. }
|
||||
| TransparentFlippedOffset { horizontal_flip, vertical_flip, .. } => {
|
||||
if !clip_blit(
|
||||
self.clip_region(),
|
||||
self.clip_region(), //
|
||||
&mut src_region,
|
||||
&mut dest_x,
|
||||
&mut dest_y,
|
||||
|
@ -435,7 +506,7 @@ impl IndexedBitmap {
|
|||
// otherwise clip like normal!
|
||||
_ => {
|
||||
if !clip_blit(
|
||||
self.clip_region(),
|
||||
self.clip_region(), //
|
||||
&mut src_region,
|
||||
&mut dest_x,
|
||||
&mut dest_y,
|
||||
|
@ -543,9 +614,16 @@ impl IndexedBitmap {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn blit_atlas_unchecked(&mut self, method: IndexedBlitMethod, src: &BitmapAtlas<Self>, index: usize, x: i32, y: i32) {
|
||||
pub unsafe fn blit_atlas_unchecked(
|
||||
&mut self,
|
||||
method: IndexedBlitMethod,
|
||||
src: &BitmapAtlas<Self>,
|
||||
index: usize,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) {
|
||||
if let Some(src_region) = src.get(index) {
|
||||
self.blit_region_unchecked(method, src.bitmap(), &src_region, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::Path;
|
||||
|
||||
use crate::graphics::bitmap::{Bitmap, BitmapError};
|
||||
use crate::graphics::bitmap::rgb::RgbaBitmap;
|
||||
use crate::graphics::bitmap::{Bitmap, BitmapError};
|
||||
use crate::graphics::palette::Palette;
|
||||
|
||||
pub mod blit;
|
||||
|
@ -29,20 +29,14 @@ impl IndexedBitmap {
|
|||
Some("png") => {
|
||||
let (bmp, palette) = Self::load_png_file(path)?;
|
||||
Ok((bmp, palette.expect("Indexed color PNG loaded and should have returned a Palette")))
|
||||
},
|
||||
}
|
||||
Some("pcx") => Ok(Self::load_pcx_file(path)?),
|
||||
Some("gif") => Ok(Self::load_gif_file(path)?),
|
||||
Some("iff") | Some("lbm") | Some("pbm") | Some("bbm") => {
|
||||
Ok(Self::load_iff_file(path)?)
|
||||
}
|
||||
_ => Err(BitmapError::UnknownFileType(String::from(
|
||||
"Unrecognized file extension",
|
||||
))),
|
||||
Some("iff") | Some("lbm") | Some("pbm") | Some("bbm") => Ok(Self::load_iff_file(path)?),
|
||||
_ => Err(BitmapError::UnknownFileType(String::from("Unrecognized file extension"))),
|
||||
}
|
||||
} else {
|
||||
Err(BitmapError::UnknownFileType(String::from(
|
||||
"No file extension",
|
||||
)))
|
||||
Err(BitmapError::UnknownFileType(String::from("No file extension")))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,4 +67,4 @@ impl IndexedBitmap {
|
|||
self.copy_as_argb_to(output.pixels_mut(), palette);
|
||||
output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,15 @@ impl IndexedBitmap {
|
|||
#[inline]
|
||||
pub fn set_blended_pixel(&mut self, x: i32, y: i32, color: u8, blend_map: &BlendMap) {
|
||||
self.set_custom_pixel(
|
||||
x, y,
|
||||
x, //
|
||||
y,
|
||||
|dest_color| {
|
||||
if let Some(blended_color) = blend_map.blend(color, dest_color) {
|
||||
blended_color
|
||||
} else {
|
||||
color
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -26,14 +27,15 @@ impl IndexedBitmap {
|
|||
#[inline]
|
||||
pub unsafe fn set_blended_pixel_unchecked(&mut self, x: i32, y: i32, color: u8, blend_map: &BlendMap) {
|
||||
self.set_custom_pixel_unchecked(
|
||||
x, y,
|
||||
x, //
|
||||
y,
|
||||
|dest_color| {
|
||||
if let Some(blended_color) = blend_map.blend(color, dest_color) {
|
||||
blended_color
|
||||
} else {
|
||||
color
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -42,10 +44,11 @@ impl IndexedBitmap {
|
|||
pub fn blended_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: u8, blend_map: &BlendMap) {
|
||||
if let Some(blend_mapping) = blend_map.get_mapping(color) {
|
||||
self.line_custom(
|
||||
x1, y1, x2, y2,
|
||||
|dest_color| {
|
||||
blend_mapping[dest_color as usize]
|
||||
}
|
||||
x1, //
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
|dest_color| blend_mapping[dest_color as usize],
|
||||
);
|
||||
} else {
|
||||
self.line(x1, y1, x2, y2, color);
|
||||
|
@ -57,10 +60,10 @@ impl IndexedBitmap {
|
|||
pub fn blended_horiz_line(&mut self, x1: i32, x2: i32, y: i32, color: u8, blend_map: &BlendMap) {
|
||||
if let Some(blend_mapping) = blend_map.get_mapping(color) {
|
||||
self.horiz_line_custom(
|
||||
x1, x2, y,
|
||||
|dest_color| {
|
||||
blend_mapping[dest_color as usize]
|
||||
}
|
||||
x1, //
|
||||
x2,
|
||||
y,
|
||||
|dest_color| blend_mapping[dest_color as usize],
|
||||
);
|
||||
} else {
|
||||
self.horiz_line(x1, x2, y, color);
|
||||
|
@ -72,10 +75,10 @@ impl IndexedBitmap {
|
|||
pub fn blended_vert_line(&mut self, x: i32, y1: i32, y2: i32, color: u8, blend_map: &BlendMap) {
|
||||
if let Some(blend_mapping) = blend_map.get_mapping(color) {
|
||||
self.vert_line_custom(
|
||||
x, y1, y2,
|
||||
|dest_color| {
|
||||
blend_mapping[dest_color as usize]
|
||||
}
|
||||
x, //
|
||||
y1,
|
||||
y2,
|
||||
|dest_color| blend_mapping[dest_color as usize],
|
||||
);
|
||||
} else {
|
||||
self.vert_line(x, y1, y2, color);
|
||||
|
@ -89,10 +92,11 @@ impl IndexedBitmap {
|
|||
pub fn blended_rect(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: u8, blend_map: &BlendMap) {
|
||||
if let Some(blend_mapping) = blend_map.get_mapping(color) {
|
||||
self.rect_custom(
|
||||
x1, y1, x2, y2,
|
||||
|dest_color| {
|
||||
blend_mapping[dest_color as usize]
|
||||
}
|
||||
x1, //
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
|dest_color| blend_mapping[dest_color as usize],
|
||||
);
|
||||
} else {
|
||||
self.rect(x1, y1, x2, y2, color);
|
||||
|
@ -106,13 +110,14 @@ impl IndexedBitmap {
|
|||
pub fn blended_filled_rect(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: u8, blend_map: &BlendMap) {
|
||||
if let Some(blend_mapping) = blend_map.get_mapping(color) {
|
||||
self.filled_rect_custom(
|
||||
x1, y1, x2, y2,
|
||||
|dest_color| {
|
||||
blend_mapping[dest_color as usize]
|
||||
}
|
||||
x1, //
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
|dest_color| blend_mapping[dest_color as usize],
|
||||
);
|
||||
} else {
|
||||
self.filled_rect(x1, y1, x2, y2, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ pub struct Bitmap<PixelType: Pixel> {
|
|||
|
||||
impl<PixelType: Pixel> std::fmt::Debug for Bitmap<PixelType> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Bitmap")
|
||||
f.debug_struct("Bitmap") //
|
||||
.field("width", &self.width)
|
||||
.field("height", &self.height)
|
||||
.field("clip_region", &self.clip_region)
|
||||
|
@ -72,15 +72,10 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
}
|
||||
|
||||
Ok(Bitmap {
|
||||
width,
|
||||
width, //
|
||||
height,
|
||||
pixels: vec![color; (width * height) as usize].into_boxed_slice(),
|
||||
clip_region: Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width,
|
||||
height,
|
||||
},
|
||||
clip_region: Rect { x: 0, y: 0, width, height },
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -138,7 +133,7 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
#[inline]
|
||||
pub fn full_bounds(&self) -> Rect {
|
||||
Rect {
|
||||
x: 0,
|
||||
x: 0, //
|
||||
y: 0,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
|
@ -215,7 +210,7 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
pub unsafe fn pixels_at_mut_unchecked(&mut self, x: i32, y: i32) -> &mut [PixelType] {
|
||||
let offset = self.get_offset_to_xy(x, y);
|
||||
std::slice::from_raw_parts_mut(
|
||||
self.pixels.as_mut_ptr().add(offset),
|
||||
self.pixels.as_mut_ptr().add(offset), //
|
||||
self.pixels.len() - offset,
|
||||
)
|
||||
}
|
||||
|
@ -318,24 +313,8 @@ pub mod tests {
|
|||
assert_eq!(32, bmp.height());
|
||||
assert_eq!(15, bmp.right());
|
||||
assert_eq!(31, bmp.bottom());
|
||||
assert_eq!(
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 16,
|
||||
height: 32,
|
||||
},
|
||||
bmp.full_bounds()
|
||||
);
|
||||
assert_eq!(
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 16,
|
||||
height: 32,
|
||||
},
|
||||
*bmp.clip_region()
|
||||
);
|
||||
assert_eq!(Rect { x: 0, y: 0, width: 16, height: 32 }, bmp.full_bounds());
|
||||
assert_eq!(Rect { x: 0, y: 0, width: 16, height: 32 }, *bmp.clip_region());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -343,10 +322,7 @@ pub mod tests {
|
|||
let mut bmp = Bitmap::<u8>::new(8, 8).unwrap();
|
||||
bmp.pixels_mut().copy_from_slice(RAW_BMP_PIXELS);
|
||||
|
||||
assert_matches!(
|
||||
Bitmap::<u8>::from(&bmp, &Rect::new(0, 0, 16, 16)),
|
||||
Err(BitmapError::OutOfBounds)
|
||||
);
|
||||
assert_matches!(Bitmap::<u8>::from(&bmp, &Rect::new(0, 0, 16, 16)), Err(BitmapError::OutOfBounds));
|
||||
|
||||
let copy = Bitmap::<u8>::from(&bmp, &Rect::new(0, 0, 8, 8)).unwrap();
|
||||
assert_eq!(bmp.pixels(), copy.pixels());
|
||||
|
@ -382,15 +358,7 @@ pub mod tests {
|
|||
|
||||
let new_clip_region = Rect::from_coords(4, 2, 12, 6);
|
||||
bmp.set_clip_region(&new_clip_region);
|
||||
assert_eq!(
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 16,
|
||||
height: 8,
|
||||
},
|
||||
bmp.full_bounds()
|
||||
);
|
||||
assert_eq!(Rect { x: 0, y: 0, width: 16, height: 8 }, bmp.full_bounds());
|
||||
assert_eq!(new_clip_region, *bmp.clip_region());
|
||||
assert!(bmp.is_xy_visible(4, 2));
|
||||
assert!(bmp.is_xy_visible(12, 2));
|
||||
|
|
|
@ -93,11 +93,7 @@ impl PcxHeader {
|
|||
}
|
||||
}
|
||||
|
||||
fn write_pcx_data<T: WriteBytesExt>(
|
||||
writer: &mut T,
|
||||
run_count: u8,
|
||||
pixel: u8,
|
||||
) -> Result<(), PcxError> {
|
||||
fn write_pcx_data<T: WriteBytesExt>(writer: &mut T, run_count: u8, pixel: u8) -> Result<(), PcxError> {
|
||||
if (run_count > 1) || ((pixel & 0xc0) == 0xc0) {
|
||||
writer.write_u8(0xc0 | run_count)?;
|
||||
}
|
||||
|
@ -106,9 +102,7 @@ fn write_pcx_data<T: WriteBytesExt>(
|
|||
}
|
||||
|
||||
impl IndexedBitmap {
|
||||
pub fn load_pcx_bytes<T: ReadBytesExt + Seek>(
|
||||
reader: &mut T,
|
||||
) -> Result<(IndexedBitmap, Palette), PcxError> {
|
||||
pub fn load_pcx_bytes<T: ReadBytesExt + Seek>(reader: &mut T) -> Result<(IndexedBitmap, Palette), PcxError> {
|
||||
let header = PcxHeader::read(reader)?;
|
||||
|
||||
if header.manufacturer != 10 {
|
||||
|
@ -117,14 +111,10 @@ impl IndexedBitmap {
|
|||
)));
|
||||
}
|
||||
if header.version != 5 {
|
||||
return Err(PcxError::BadFile(String::from(
|
||||
"Only version 5 PCX files are supported",
|
||||
)));
|
||||
return Err(PcxError::BadFile(String::from("Only version 5 PCX files are supported")));
|
||||
}
|
||||
if header.encoding != 1 {
|
||||
return Err(PcxError::BadFile(String::from(
|
||||
"Only RLE-compressed PCX files are supported",
|
||||
)));
|
||||
return Err(PcxError::BadFile(String::from("Only RLE-compressed PCX files are supported")));
|
||||
}
|
||||
if header.bpp != 8 {
|
||||
return Err(PcxError::BadFile(String::from(
|
||||
|
@ -132,9 +122,7 @@ impl IndexedBitmap {
|
|||
)));
|
||||
}
|
||||
if header.x2 == 0 || header.y2 == 0 {
|
||||
return Err(PcxError::BadFile(String::from(
|
||||
"Invalid PCX image dimensions",
|
||||
)));
|
||||
return Err(PcxError::BadFile(String::from("Invalid PCX image dimensions")));
|
||||
}
|
||||
|
||||
// read the PCX file's pixel data into a bitmap
|
||||
|
@ -185,9 +173,7 @@ impl IndexedBitmap {
|
|||
|
||||
let palette_marker = reader.read_u8()?;
|
||||
if palette_marker != 0x0c {
|
||||
return Err(PcxError::BadFile(String::from(
|
||||
"Palette not found at end of file",
|
||||
)));
|
||||
return Err(PcxError::BadFile(String::from("Palette not found at end of file")));
|
||||
}
|
||||
|
||||
let palette = Palette::load_from_bytes(reader, PaletteFormat::Normal)?;
|
||||
|
@ -201,11 +187,7 @@ impl IndexedBitmap {
|
|||
Self::load_pcx_bytes(&mut reader)
|
||||
}
|
||||
|
||||
pub fn to_pcx_bytes<T: WriteBytesExt>(
|
||||
&self,
|
||||
writer: &mut T,
|
||||
palette: &Palette,
|
||||
) -> Result<(), PcxError> {
|
||||
pub fn to_pcx_bytes<T: WriteBytesExt>(&self, writer: &mut T, palette: &Palette) -> Result<(), PcxError> {
|
||||
let header = PcxHeader {
|
||||
manufacturer: 10,
|
||||
version: 5,
|
||||
|
@ -285,9 +267,7 @@ impl IndexedBitmap {
|
|||
// multi-pixel-depth support.
|
||||
|
||||
impl RgbaBitmap {
|
||||
pub fn load_pcx_bytes<T: ReadBytesExt + Seek>(
|
||||
reader: &mut T,
|
||||
) -> Result<(RgbaBitmap, Palette), PcxError> {
|
||||
pub fn load_pcx_bytes<T: ReadBytesExt + Seek>(reader: &mut T) -> Result<(RgbaBitmap, Palette), PcxError> {
|
||||
let (temp_bitmap, palette) = IndexedBitmap::load_pcx_bytes(reader)?;
|
||||
let output = temp_bitmap.to_rgba(&palette);
|
||||
Ok((output, palette))
|
||||
|
@ -322,9 +302,10 @@ pub mod tests {
|
|||
|
||||
let ref_pixels = load_raw_indexed(test_file(Path::new("small.bin")).as_path())?;
|
||||
let dp2_palette = Palette::load_from_file(
|
||||
test_assets_file(Path::new("dp2.pal")).as_path(),
|
||||
PaletteFormat::Normal
|
||||
).unwrap();
|
||||
test_assets_file(Path::new("dp2.pal")).as_path(), //
|
||||
PaletteFormat::Normal,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (bmp, palette) = IndexedBitmap::load_pcx_file(test_file(Path::new("small.pcx")).as_path())?;
|
||||
assert_eq!(16, bmp.width());
|
||||
|
|
|
@ -7,12 +7,12 @@ use std::path::Path;
|
|||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::graphics::bitmap::Bitmap;
|
||||
use crate::graphics::bitmap::indexed::IndexedBitmap;
|
||||
use crate::graphics::bitmap::rgb::RgbaBitmap;
|
||||
use crate::graphics::palette::Palette;
|
||||
use crate::graphics::bitmap::Bitmap;
|
||||
use crate::graphics::color::{from_argb32, from_rgb32, to_argb32, to_rgb32};
|
||||
use crate::graphics::palette::{Palette, PaletteError, PaletteFormat};
|
||||
use crate::graphics::Pixel;
|
||||
use crate::prelude::{from_argb32, from_rgb32, PaletteError, PaletteFormat, to_argb32, to_rgb32};
|
||||
use crate::utils::bytes::ReadFixedLengthByteArray;
|
||||
|
||||
const PNG_HEADER: [u8; 8] = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
|
||||
|
@ -76,7 +76,7 @@ struct ChunkHeader {
|
|||
impl ChunkHeader {
|
||||
pub fn read<T: ReadBytesExt>(reader: &mut T) -> Result<Self, PngError> {
|
||||
Ok(ChunkHeader {
|
||||
size: reader.read_u32::<BigEndian>()?,
|
||||
size: reader.read_u32::<BigEndian>()?, //
|
||||
name: reader.read_bytes()?,
|
||||
})
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ struct ImageHeaderChunk {
|
|||
impl ImageHeaderChunk {
|
||||
pub fn read<T: ReadBytesExt>(reader: &mut T) -> Result<Self, PngError> {
|
||||
Ok(ImageHeaderChunk {
|
||||
width: reader.read_u32::<BigEndian>()?,
|
||||
width: reader.read_u32::<BigEndian>()?, //
|
||||
height: reader.read_u32::<BigEndian>()?,
|
||||
bpp: reader.read_u8()?,
|
||||
format: ColorFormat::from(reader.read_u8()?)?,
|
||||
|
@ -234,7 +234,7 @@ impl ScanlineBuffer {
|
|||
// unsigned arithmetic modulo 256 *except* for the average calculation itself which must not overflow!
|
||||
let average = (a + b) / 2;
|
||||
byte.wrapping_add(average as u8)
|
||||
},
|
||||
}
|
||||
Filter::Paeth => {
|
||||
let a = if x < self.bpp { 0 } else { self.current[x - self.bpp] } as i16;
|
||||
let b = if y < 1 { 0 } else { self.previous[x] } as i16;
|
||||
|
@ -252,7 +252,7 @@ impl ScanlineBuffer {
|
|||
};
|
||||
// all of the above must not overflow. however, this last part is unsigned arithmetic modulo 256
|
||||
byte.wrapping_add(value)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,10 +307,13 @@ impl ScanlinePixelConverter<u8> for ScanlineBuffer {
|
|||
fn read_pixel(&mut self, x: usize, _palette: &Option<Palette>) -> Result<u8, PngError> {
|
||||
let offset = x * self.bpp;
|
||||
match self.format {
|
||||
ColorFormat::IndexedColor => {
|
||||
Ok(self.current[offset])
|
||||
},
|
||||
_ => return Err(PngError::BadFile(format!("Unsupported color format for this PixelReader: {:?}", self.format))),
|
||||
ColorFormat::IndexedColor => Ok(self.current[offset]),
|
||||
_ => {
|
||||
return Err(PngError::BadFile(format!(
|
||||
"Unsupported color format for this PixelReader: {:?}",
|
||||
self.format
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,8 +323,13 @@ impl ScanlinePixelConverter<u8> for ScanlineBuffer {
|
|||
ColorFormat::IndexedColor => {
|
||||
self.current[offset] = pixel;
|
||||
Ok(())
|
||||
},
|
||||
_ => return Err(PngError::BadFile(format!("Unsupported color format for this PixelReader: {:?}", self.format))),
|
||||
}
|
||||
_ => {
|
||||
return Err(PngError::BadFile(format!(
|
||||
"Unsupported color format for this PixelReader: {:?}",
|
||||
self.format
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -335,23 +343,30 @@ impl ScanlinePixelConverter<u32> for ScanlineBuffer {
|
|||
if let Some(palette) = palette {
|
||||
Ok(palette[color])
|
||||
} else {
|
||||
return Err(PngError::BadFile(String::from("No palette to map indexed-color format pixels to RGBA format destination")));
|
||||
return Err(PngError::BadFile(String::from(
|
||||
"No palette to map indexed-color format pixels to RGBA format destination",
|
||||
)));
|
||||
}
|
||||
},
|
||||
}
|
||||
ColorFormat::RGB => {
|
||||
let r = self.current[offset];
|
||||
let g = self.current[offset + 1];
|
||||
let b = self.current[offset + 2];
|
||||
Ok(to_rgb32(r, g, b))
|
||||
},
|
||||
}
|
||||
ColorFormat::RGBA => {
|
||||
let r = self.current[offset];
|
||||
let g = self.current[offset + 1];
|
||||
let b = self.current[offset + 2];
|
||||
let a = self.current[offset + 3];
|
||||
Ok(to_argb32(a, r, g, b))
|
||||
},
|
||||
_ => return Err(PngError::BadFile(format!("Unsupported color format for this PixelReader: {:?}", self.format))),
|
||||
}
|
||||
_ => {
|
||||
return Err(PngError::BadFile(format!(
|
||||
"Unsupported color format for this PixelReader: {:?}",
|
||||
self.format
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,7 +379,7 @@ impl ScanlinePixelConverter<u32> for ScanlineBuffer {
|
|||
self.current[offset + 1] = g;
|
||||
self.current[offset + 2] = b;
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
ColorFormat::RGBA => {
|
||||
let (a, r, g, b) = from_argb32(pixel);
|
||||
self.current[offset] = r;
|
||||
|
@ -372,20 +387,22 @@ impl ScanlinePixelConverter<u32> for ScanlineBuffer {
|
|||
self.current[offset + 2] = b;
|
||||
self.current[offset + 3] = a;
|
||||
Ok(())
|
||||
},
|
||||
_ => return Err(PngError::BadFile(format!("Unsupported color format for this PixelReader: {:?}", self.format))),
|
||||
}
|
||||
_ => {
|
||||
return Err(PngError::BadFile(format!(
|
||||
"Unsupported color format for this PixelReader: {:?}",
|
||||
self.format
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn load_png_bytes<Reader, PixelType>(
|
||||
reader: &mut Reader
|
||||
) -> Result<(Bitmap<PixelType>, Option<Palette>), PngError>
|
||||
fn load_png_bytes<Reader, PixelType>(reader: &mut Reader) -> Result<(Bitmap<PixelType>, Option<Palette>), PngError>
|
||||
where
|
||||
Reader: ReadBytesExt,
|
||||
PixelType: Pixel,
|
||||
ScanlineBuffer: ScanlinePixelConverter<PixelType>
|
||||
ScanlineBuffer: ScanlinePixelConverter<PixelType>,
|
||||
{
|
||||
let header: [u8; 8] = reader.read_bytes()?;
|
||||
if header != PNG_HEADER {
|
||||
|
@ -409,9 +426,10 @@ where
|
|||
if ihdr.bpp != 8 {
|
||||
return Err(PngError::BadFile(String::from("Unsupported color bit depth.")));
|
||||
}
|
||||
if ihdr.format != ColorFormat::IndexedColor
|
||||
if ihdr.format != ColorFormat::IndexedColor // .
|
||||
&& ihdr.format != ColorFormat::RGB
|
||||
&& ihdr.format != ColorFormat::RGBA {
|
||||
&& ihdr.format != ColorFormat::RGBA
|
||||
{
|
||||
return Err(PngError::BadFile(String::from("Unsupported pixel color format.")));
|
||||
}
|
||||
if ihdr.compression != 0 {
|
||||
|
@ -438,7 +456,7 @@ where
|
|||
let chunk_bytes = read_chunk_data(reader, &chunk_header)?;
|
||||
let num_colors = (chunk_header.size / 3) as usize;
|
||||
Some(Palette::load_num_colors_from_bytes(
|
||||
&mut chunk_bytes.as_slice(),
|
||||
&mut chunk_bytes.as_slice(), //
|
||||
PaletteFormat::Normal,
|
||||
num_colors,
|
||||
)?)
|
||||
|
@ -473,7 +491,9 @@ where
|
|||
scanline_buffer.read_line(&mut deflater)?;
|
||||
for x in 0..ihdr.width as usize {
|
||||
let pixel = scanline_buffer.read_pixel(x, &palette)?;
|
||||
unsafe { output.set_pixel_unchecked(x as i32, y as i32, pixel); }
|
||||
unsafe {
|
||||
output.set_pixel_unchecked(x as i32, y as i32, pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,9 +583,7 @@ where
|
|||
}
|
||||
|
||||
impl IndexedBitmap {
|
||||
pub fn load_png_bytes<T: ReadBytesExt>(
|
||||
reader: &mut T,
|
||||
) -> Result<(IndexedBitmap, Option<Palette>), PngError> {
|
||||
pub fn load_png_bytes<T: ReadBytesExt>(reader: &mut T) -> Result<(IndexedBitmap, Option<Palette>), PngError> {
|
||||
load_png_bytes(reader)
|
||||
}
|
||||
|
||||
|
@ -575,11 +593,7 @@ impl IndexedBitmap {
|
|||
Self::load_png_bytes(&mut reader)
|
||||
}
|
||||
|
||||
pub fn to_png_bytes<T: WriteBytesExt>(
|
||||
&self,
|
||||
writer: &mut T,
|
||||
palette: &Palette,
|
||||
) -> Result<(), PngError> {
|
||||
pub fn to_png_bytes<T: WriteBytesExt>(&self, writer: &mut T, palette: &Palette) -> Result<(), PngError> {
|
||||
write_png_bytes(writer, &self, ColorFormat::IndexedColor, Some(palette))
|
||||
}
|
||||
|
||||
|
@ -591,9 +605,7 @@ impl IndexedBitmap {
|
|||
}
|
||||
|
||||
impl RgbaBitmap {
|
||||
pub fn load_png_bytes<T: ReadBytesExt>(
|
||||
reader: &mut T,
|
||||
) -> Result<(RgbaBitmap, Option<Palette>), PngError> {
|
||||
pub fn load_png_bytes<T: ReadBytesExt>(reader: &mut T) -> Result<(RgbaBitmap, Option<Palette>), PngError> {
|
||||
load_png_bytes(reader)
|
||||
}
|
||||
|
||||
|
@ -603,11 +615,7 @@ impl RgbaBitmap {
|
|||
Self::load_png_bytes(&mut reader)
|
||||
}
|
||||
|
||||
pub fn to_png_bytes<T: WriteBytesExt>(
|
||||
&self,
|
||||
writer: &mut T,
|
||||
format: PngFormat,
|
||||
) -> Result<(), PngError> {
|
||||
pub fn to_png_bytes<T: WriteBytesExt>(&self, writer: &mut T, format: PngFormat) -> Result<(), PngError> {
|
||||
write_png_bytes(
|
||||
writer,
|
||||
&self,
|
||||
|
@ -619,10 +627,7 @@ impl RgbaBitmap {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn to_png_file(
|
||||
&self, path: &Path,
|
||||
format: PngFormat,
|
||||
) -> Result<(), PngError> {
|
||||
pub fn to_png_file(&self, path: &Path, format: PngFormat) -> Result<(), PngError> {
|
||||
let f = File::create(path)?;
|
||||
let mut writer = BufWriter::new(f);
|
||||
self.to_png_bytes(&mut writer, format)
|
||||
|
@ -946,4 +951,4 @@ pub mod tests {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
/// Renders a single character using the font given.
|
||||
#[inline]
|
||||
pub fn print_char<T: Font>(&mut self, ch: char, x: i32, y: i32, opts: FontRenderOpts<PixelType>, font: &T) {
|
||||
font.character(ch)
|
||||
font.character(ch) //
|
||||
.draw(self, x, y, opts);
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
swap(&mut y1, &mut y2);
|
||||
}
|
||||
let mut region = Rect {
|
||||
x: x1,
|
||||
x: x1, //
|
||||
y: y1,
|
||||
width: (x2 - x1 + 1) as u32,
|
||||
height: (y2 - y1 + 1) as u32,
|
||||
|
@ -345,7 +345,7 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
mut y1: i32,
|
||||
mut x2: i32,
|
||||
mut y2: i32,
|
||||
pixel_fn: impl Fn(PixelType) -> PixelType
|
||||
pixel_fn: impl Fn(PixelType) -> PixelType,
|
||||
) {
|
||||
// note: need to manually do all this instead of just relying on Rect::from_coords (which
|
||||
// could otherwise figure all this out for us) mainly just because we need the post-swap
|
||||
|
@ -357,7 +357,7 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
swap(&mut y1, &mut y2);
|
||||
}
|
||||
let mut region = Rect {
|
||||
x: x1,
|
||||
x: x1, //
|
||||
y: y1,
|
||||
width: (x2 - x1 + 1) as u32,
|
||||
height: (y2 - y1 + 1) as u32,
|
||||
|
@ -394,7 +394,8 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
// bottom line, only if y2 was originally within bounds
|
||||
if y2 == region.bottom() {
|
||||
unsafe {
|
||||
let dest = &mut self.pixels_at_mut_unchecked(horiz_draw_x, region.bottom())[0..horiz_draw_width as usize];
|
||||
let dest =
|
||||
&mut self.pixels_at_mut_unchecked(horiz_draw_x, region.bottom())[0..horiz_draw_width as usize];
|
||||
for pixel in dest.iter_mut() {
|
||||
*pixel = pixel_fn(*pixel);
|
||||
}
|
||||
|
@ -450,7 +451,7 @@ impl<PixelType: Pixel> Bitmap<PixelType> {
|
|||
y1: i32,
|
||||
x2: i32,
|
||||
y2: i32,
|
||||
pixel_fn: impl Fn(PixelType) -> PixelType
|
||||
pixel_fn: impl Fn(PixelType) -> PixelType,
|
||||
) {
|
||||
let mut region = Rect::from_coords(x1, y1, x2, y2);
|
||||
if region.clamp_to(&self.clip_region) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::graphics::bitmap::blit::{clip_blit, per_pixel_blit, per_pixel_flipped_blit, per_pixel_rotozoom_blit};
|
||||
use crate::graphics::bitmap::rgb::RgbaBitmap;
|
||||
use crate::graphics::bitmapatlas::BitmapAtlas;
|
||||
use crate::graphics::color::{BlendFunction, tint_argb32};
|
||||
use crate::graphics::color::{tint_argb32, BlendFunction};
|
||||
use crate::math::rect::Rect;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
|
@ -120,7 +120,11 @@ impl RgbaBitmap {
|
|||
tint_color: u32,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
*dest_pixels = tint_argb32(*src_pixels, tint_color);
|
||||
},
|
||||
|
@ -136,7 +140,11 @@ impl RgbaBitmap {
|
|||
blend: BlendFunction,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
*dest_pixels = blend.blend(*src_pixels, *dest_pixels);
|
||||
},
|
||||
|
@ -154,7 +162,13 @@ impl RgbaBitmap {
|
|||
blend: BlendFunction,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
*dest_pixels = blend.blend(*src_pixels, *dest_pixels);
|
||||
},
|
||||
|
@ -172,7 +186,13 @@ impl RgbaBitmap {
|
|||
tint_color: u32,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
*dest_pixels = tint_argb32(*src_pixels, tint_color);
|
||||
},
|
||||
|
@ -189,7 +209,11 @@ impl RgbaBitmap {
|
|||
tint_color: u32,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = tint_argb32(*src_pixels, tint_color);
|
||||
|
@ -208,7 +232,11 @@ impl RgbaBitmap {
|
|||
blend: BlendFunction,
|
||||
) {
|
||||
per_pixel_blit(
|
||||
self, src, src_region, dest_x, dest_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = blend.blend(*src_pixels, *dest_pixels);
|
||||
|
@ -229,7 +257,13 @@ impl RgbaBitmap {
|
|||
tint_color: u32,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = tint_argb32(*src_pixels, tint_color);
|
||||
|
@ -250,7 +284,13 @@ impl RgbaBitmap {
|
|||
blend: BlendFunction,
|
||||
) {
|
||||
per_pixel_flipped_blit(
|
||||
self, src, src_region, dest_x, dest_y, horizontal_flip, vertical_flip,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
horizontal_flip,
|
||||
vertical_flip,
|
||||
|src_pixels, dest_pixels| {
|
||||
if *src_pixels != transparent_color {
|
||||
*dest_pixels = blend.blend(*src_pixels, *dest_pixels);
|
||||
|
@ -271,7 +311,14 @@ impl RgbaBitmap {
|
|||
tint_color: u32,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
dest_bitmap.set_pixel(draw_x, draw_y, tint_argb32(src_pixel, tint_color));
|
||||
},
|
||||
|
@ -290,7 +337,14 @@ impl RgbaBitmap {
|
|||
blend: BlendFunction,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
if let Some(dest_pixel) = dest_bitmap.get_pixel(draw_x, draw_y) {
|
||||
dest_bitmap.set_pixel(draw_x, draw_y, blend.blend(src_pixel, dest_pixel))
|
||||
|
@ -312,7 +366,14 @@ impl RgbaBitmap {
|
|||
tint_color: u32,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
if transparent_color != src_pixel {
|
||||
dest_bitmap.set_pixel(draw_x, draw_y, tint_argb32(src_pixel, tint_color));
|
||||
|
@ -334,7 +395,14 @@ impl RgbaBitmap {
|
|||
blend: BlendFunction,
|
||||
) {
|
||||
per_pixel_rotozoom_blit(
|
||||
self, src, src_region, dest_x, dest_y, angle, scale_x, scale_y,
|
||||
self, //
|
||||
src,
|
||||
src_region,
|
||||
dest_x,
|
||||
dest_y,
|
||||
angle,
|
||||
scale_x,
|
||||
scale_y,
|
||||
|src_pixel, dest_bitmap, draw_x, draw_y| {
|
||||
if transparent_color != src_pixel {
|
||||
if let Some(dest_pixel) = dest_bitmap.get_pixel(draw_x, draw_y) {
|
||||
|
@ -364,23 +432,23 @@ impl RgbaBitmap {
|
|||
match method {
|
||||
// rotozoom blits internally clip per-pixel right now ... and regardless, the normal
|
||||
// clip_blit() function wouldn't handle a rotozoom blit destination region anyway ...
|
||||
RotoZoom { .. } => {},
|
||||
RotoZoomTinted { .. } => {},
|
||||
RotoZoomBlended { .. } => {},
|
||||
RotoZoomTransparent { .. } => {},
|
||||
RotoZoomTransparentTinted { .. } => {},
|
||||
RotoZoomTransparentBlended { .. } => {},
|
||||
RotoZoom { .. } => {}
|
||||
RotoZoomTinted { .. } => {}
|
||||
RotoZoomBlended { .. } => {}
|
||||
RotoZoomTransparent { .. } => {}
|
||||
RotoZoomTransparentTinted { .. } => {}
|
||||
RotoZoomTransparentBlended { .. } => {}
|
||||
|
||||
// set axis flip arguments
|
||||
SolidFlipped { horizontal_flip, vertical_flip, .. } |
|
||||
SolidFlippedTinted { horizontal_flip, vertical_flip, .. } |
|
||||
SolidFlippedBlended { horizontal_flip, vertical_flip, .. } |
|
||||
TransparentFlipped { horizontal_flip, vertical_flip, .. } |
|
||||
TransparentFlippedTinted { horizontal_flip, vertical_flip, .. } |
|
||||
TransparentFlippedBlended { horizontal_flip, vertical_flip, .. } |
|
||||
TransparentFlippedSingle { horizontal_flip, vertical_flip, .. } => {
|
||||
SolidFlipped { horizontal_flip, vertical_flip, .. }
|
||||
| SolidFlippedTinted { horizontal_flip, vertical_flip, .. }
|
||||
| SolidFlippedBlended { horizontal_flip, vertical_flip, .. }
|
||||
| TransparentFlipped { horizontal_flip, vertical_flip, .. }
|
||||
| TransparentFlippedTinted { horizontal_flip, vertical_flip, .. }
|
||||
| TransparentFlippedBlended { horizontal_flip, vertical_flip, .. }
|
||||
| TransparentFlippedSingle { horizontal_flip, vertical_flip, .. } => {
|
||||
if !clip_blit(
|
||||
self.clip_region(),
|
||||
self.clip_region(), //
|
||||
&mut src_region,
|
||||
&mut dest_x,
|
||||
&mut dest_y,
|
||||
|
@ -394,7 +462,7 @@ impl RgbaBitmap {
|
|||
// otherwise clip like normal!
|
||||
_ => {
|
||||
if !clip_blit(
|
||||
self.clip_region(),
|
||||
self.clip_region(), //
|
||||
&mut src_region,
|
||||
&mut dest_x,
|
||||
&mut dest_y,
|
||||
|
@ -500,7 +568,14 @@ impl RgbaBitmap {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn blit_atlas_unchecked(&mut self, method: RgbaBlitMethod, src: &BitmapAtlas<Self>, index: usize, x: i32, y: i32) {
|
||||
pub unsafe fn blit_atlas_unchecked(
|
||||
&mut self,
|
||||
method: RgbaBlitMethod,
|
||||
src: &BitmapAtlas<Self>,
|
||||
index: usize,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) {
|
||||
if let Some(src_region) = src.get(index) {
|
||||
self.blit_region_unchecked(method, src.bitmap(), &src_region, x, y);
|
||||
}
|
||||
|
|
|
@ -30,23 +30,19 @@ impl RgbaBitmap {
|
|||
Some("pcx") => {
|
||||
let (bmp, palette) = Self::load_pcx_file(path)?;
|
||||
Ok((bmp, Some(palette)))
|
||||
},
|
||||
}
|
||||
Some("gif") => {
|
||||
let (bmp, palette) = Self::load_gif_file(path)?;
|
||||
Ok((bmp, Some(palette)))
|
||||
},
|
||||
}
|
||||
Some("iff") | Some("lbm") | Some("pbm") | Some("bbm") => {
|
||||
let (bmp, palette) = Self::load_iff_file(path)?;
|
||||
Ok((bmp, Some(palette)))
|
||||
}
|
||||
_ => Err(BitmapError::UnknownFileType(String::from(
|
||||
"Unrecognized file extension",
|
||||
))),
|
||||
_ => Err(BitmapError::UnknownFileType(String::from("Unrecognized file extension"))),
|
||||
}
|
||||
} else {
|
||||
Err(BitmapError::UnknownFileType(String::from(
|
||||
"No file extension",
|
||||
)))
|
||||
Err(BitmapError::UnknownFileType(String::from("No file extension")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,9 @@ impl RgbaBitmap {
|
|||
#[inline]
|
||||
pub fn set_blended_pixel(&mut self, x: i32, y: i32, color: u32, blend: BlendFunction) {
|
||||
self.set_custom_pixel(
|
||||
x, y,
|
||||
|dest_color| {
|
||||
blend.blend(color, dest_color)
|
||||
}
|
||||
x, //
|
||||
y,
|
||||
|dest_color| blend.blend(color, dest_color),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -20,20 +19,20 @@ impl RgbaBitmap {
|
|||
#[inline]
|
||||
pub unsafe fn set_blended_pixel_unchecked(&mut self, x: i32, y: i32, color: u32, blend: BlendFunction) {
|
||||
self.set_custom_pixel_unchecked(
|
||||
x, y,
|
||||
|dest_color| {
|
||||
blend.blend(color, dest_color)
|
||||
}
|
||||
x, //
|
||||
y,
|
||||
|dest_color| blend.blend(color, dest_color),
|
||||
);
|
||||
}
|
||||
|
||||
/// Draws a line from x1,y1 to x2,y2 by blending the drawn pixels using the given blend function.
|
||||
pub fn blended_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: u32, blend: BlendFunction) {
|
||||
self.line_custom(
|
||||
x1, y1, x2, y2,
|
||||
|dest_color| {
|
||||
blend.blend(color, dest_color)
|
||||
}
|
||||
x1, //
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
|dest_color| blend.blend(color, dest_color),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -41,10 +40,10 @@ impl RgbaBitmap {
|
|||
/// blend function.
|
||||
pub fn blended_horiz_line(&mut self, x1: i32, x2: i32, y: i32, color: u32, blend: BlendFunction) {
|
||||
self.horiz_line_custom(
|
||||
x1, x2, y,
|
||||
|dest_color| {
|
||||
blend.blend(color, dest_color)
|
||||
}
|
||||
x1, //
|
||||
x2,
|
||||
y,
|
||||
|dest_color| blend.blend(color, dest_color),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -52,10 +51,10 @@ impl RgbaBitmap {
|
|||
/// function.
|
||||
pub fn blended_vert_line(&mut self, x: i32, y1: i32, y2: i32, color: u32, blend: BlendFunction) {
|
||||
self.vert_line_custom(
|
||||
x, y1, y2,
|
||||
|dest_color| {
|
||||
blend.blend(color, dest_color)
|
||||
}
|
||||
x, //
|
||||
y1,
|
||||
y2,
|
||||
|dest_color| blend.blend(color, dest_color),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -64,10 +63,11 @@ impl RgbaBitmap {
|
|||
/// The box is drawn by blending the drawn pixels using the given blend function.
|
||||
pub fn blended_rect(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: u32, blend: BlendFunction) {
|
||||
self.rect_custom(
|
||||
x1, y1, x2, y2,
|
||||
|dest_color| {
|
||||
blend.blend(color, dest_color)
|
||||
}
|
||||
x1, //
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
|dest_color| blend.blend(color, dest_color),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -76,10 +76,11 @@ impl RgbaBitmap {
|
|||
/// filled box is draw by blending the drawn pixels using the given blend function.
|
||||
pub fn blended_filled_rect(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: u32, blend: BlendFunction) {
|
||||
self.filled_rect_custom(
|
||||
x1, y1, x2, y2,
|
||||
|dest_color| {
|
||||
blend.blend(color, dest_color)
|
||||
}
|
||||
x1, //
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
|dest_color| blend.blend(color, dest_color),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ pub enum BitmapAtlasError {
|
|||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct BitmapAtlas<BitmapType>
|
||||
where
|
||||
BitmapType: GeneralBitmap
|
||||
BitmapType: GeneralBitmap,
|
||||
{
|
||||
bitmap: BitmapType,
|
||||
bounds: Rect,
|
||||
|
@ -23,12 +23,12 @@ where
|
|||
|
||||
impl<BitmapType> BitmapAtlas<BitmapType>
|
||||
where
|
||||
BitmapType: GeneralBitmap
|
||||
BitmapType: GeneralBitmap,
|
||||
{
|
||||
pub fn new(bitmap: BitmapType) -> Self {
|
||||
let bounds = bitmap.full_bounds();
|
||||
BitmapAtlas {
|
||||
bitmap,
|
||||
bitmap, //
|
||||
bounds,
|
||||
tiles: Vec::new(),
|
||||
}
|
||||
|
@ -43,11 +43,7 @@ where
|
|||
Ok(self.tiles.len() - 1)
|
||||
}
|
||||
|
||||
pub fn add_grid(
|
||||
&mut self,
|
||||
tile_width: u32,
|
||||
tile_height: u32,
|
||||
) -> Result<usize, BitmapAtlasError> {
|
||||
pub fn add_grid(&mut self, tile_width: u32, tile_height: u32) -> Result<usize, BitmapAtlasError> {
|
||||
if self.bounds.width < tile_width || self.bounds.height < tile_height {
|
||||
return Err(BitmapAtlasError::OutOfBounds);
|
||||
}
|
||||
|
@ -121,7 +117,8 @@ where
|
|||
|
||||
impl<BitmapType> Index<usize> for BitmapAtlas<BitmapType>
|
||||
where
|
||||
BitmapType: GeneralBitmap {
|
||||
BitmapType: GeneralBitmap,
|
||||
{
|
||||
type Output = Rect;
|
||||
|
||||
#[inline]
|
||||
|
@ -153,22 +150,13 @@ pub mod tests {
|
|||
assert_eq!(rect, atlas[1]);
|
||||
assert_eq!(2, atlas.len());
|
||||
|
||||
assert_matches!(
|
||||
atlas.add(Rect::new(56, 0, 16, 16)),
|
||||
Err(BitmapAtlasError::OutOfBounds)
|
||||
);
|
||||
assert_matches!(atlas.add(Rect::new(56, 0, 16, 16)), Err(BitmapAtlasError::OutOfBounds));
|
||||
assert_eq!(2, atlas.len());
|
||||
|
||||
assert_matches!(
|
||||
atlas.add(Rect::new(-8, 4, 16, 16)),
|
||||
Err(BitmapAtlasError::OutOfBounds)
|
||||
);
|
||||
assert_matches!(atlas.add(Rect::new(-8, 4, 16, 16)), Err(BitmapAtlasError::OutOfBounds));
|
||||
assert_eq!(2, atlas.len());
|
||||
|
||||
assert_matches!(
|
||||
atlas.add(Rect::new(0, 0, 128, 128)),
|
||||
Err(BitmapAtlasError::OutOfBounds)
|
||||
);
|
||||
assert_matches!(atlas.add(Rect::new(0, 0, 128, 128)), Err(BitmapAtlasError::OutOfBounds));
|
||||
assert_eq!(2, atlas.len());
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ pub struct BlendMap {
|
|||
|
||||
impl std::fmt::Debug for BlendMap {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("BlendMap")
|
||||
f.debug_struct("BlendMap") //
|
||||
.field("start_color", &self.start_color)
|
||||
.field("end_color", &self.end_color)
|
||||
.finish_non_exhaustive()
|
||||
|
@ -58,17 +58,10 @@ impl BlendMap {
|
|||
/// range only. The `start_color` and `end_color` may also be equal to create a blend map with
|
||||
/// only a single source color mapping.
|
||||
pub fn new(start_color: u8, end_color: u8) -> Self {
|
||||
let (start_color, end_color) = if start_color > end_color {
|
||||
(end_color, start_color)
|
||||
} else {
|
||||
(start_color, end_color)
|
||||
};
|
||||
let (start_color, end_color) =
|
||||
if start_color > end_color { (end_color, start_color) } else { (start_color, end_color) };
|
||||
let num_colors = (end_color - start_color) as usize + 1;
|
||||
BlendMap {
|
||||
start_color,
|
||||
end_color,
|
||||
mapping: vec![[0u8; 256]; num_colors].into_boxed_slice(),
|
||||
}
|
||||
BlendMap { start_color, end_color, mapping: vec![[0u8; 256]; num_colors].into_boxed_slice() }
|
||||
}
|
||||
|
||||
/// Creates and returns a new [`BlendMap`] with a single source color mapping which maps to
|
||||
|
@ -77,11 +70,8 @@ impl BlendMap {
|
|||
/// like a simple translucency effect. The starting color in the gradient is used as the source
|
||||
/// color mapping in the returned blend map.
|
||||
pub fn new_colorized_map(gradient_start: u8, gradient_end: u8, palette: &Palette) -> Self {
|
||||
let (gradient_start, gradient_end) = if gradient_start > gradient_end {
|
||||
(gradient_end, gradient_start)
|
||||
} else {
|
||||
(gradient_start, gradient_end)
|
||||
};
|
||||
let (gradient_start, gradient_end) =
|
||||
if gradient_start > gradient_end { (gradient_end, gradient_start) } else { (gradient_start, gradient_end) };
|
||||
let gradient_size = gradient_end - gradient_start + 1;
|
||||
let source_color = gradient_start;
|
||||
|
||||
|
@ -89,11 +79,13 @@ impl BlendMap {
|
|||
for idx in 0..=255 {
|
||||
let (r, g, b) = from_rgb32(palette[idx]);
|
||||
let lit = (luminance(r, g, b) * 255.0) as u8;
|
||||
blend_map.set_mapping(
|
||||
source_color,
|
||||
idx as u8,
|
||||
(gradient_size - 1) - (lit / (256 / gradient_size as u32) as u8) + source_color,
|
||||
).unwrap();
|
||||
blend_map
|
||||
.set_mapping(
|
||||
source_color,
|
||||
idx as u8,
|
||||
(gradient_size - 1) - (lit / (256 / gradient_size as u32) as u8) + source_color,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
blend_map
|
||||
}
|
||||
|
@ -108,11 +100,8 @@ impl BlendMap {
|
|||
palette: &Palette,
|
||||
f: impl Fn(f32, f32) -> f32,
|
||||
) -> BlendMap {
|
||||
let (gradient_start, gradient_end) = if gradient_start > gradient_end {
|
||||
(gradient_end, gradient_start)
|
||||
} else {
|
||||
(gradient_start, gradient_end)
|
||||
};
|
||||
let (gradient_start, gradient_end) =
|
||||
if gradient_start > gradient_end { (gradient_end, gradient_start) } else { (gradient_start, gradient_end) };
|
||||
let gradient_size = gradient_end - gradient_start + 1;
|
||||
|
||||
let mut blend_map = BlendMap::new(0, 255);
|
||||
|
@ -123,11 +112,13 @@ impl BlendMap {
|
|||
let (r, g, b) = from_rgb32(palette[dest_color]);
|
||||
let destination_luminance = luminance(r, g, b);
|
||||
let weight = (f(source_luminance, destination_luminance) * 255.0) as u8;
|
||||
blend_map.set_mapping(
|
||||
source_color,
|
||||
dest_color,
|
||||
(gradient_size - 1).wrapping_sub(weight / (256 / gradient_size as u32) as u8) + gradient_start,
|
||||
).unwrap();
|
||||
blend_map
|
||||
.set_mapping(
|
||||
source_color,
|
||||
dest_color,
|
||||
(gradient_size - 1).wrapping_sub(weight / (256 / gradient_size as u32) as u8) + gradient_start,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
blend_map
|
||||
|
@ -223,12 +214,19 @@ impl BlendMap {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// Sets a series of blend color mappings for the given source color and starting from a base
|
||||
/// destination color.
|
||||
pub fn set_mappings<const N: usize>(&mut self, source_color: u8, base_dest_color: u8, mappings: [u8; N]) -> Result<(), BlendMapError> {
|
||||
pub fn set_mappings<const N: usize>(
|
||||
&mut self,
|
||||
source_color: u8,
|
||||
base_dest_color: u8,
|
||||
mappings: [u8; N],
|
||||
) -> Result<(), BlendMapError> {
|
||||
if let Some(mapping) = self.get_mapping_mut(source_color) {
|
||||
assert!((base_dest_color as usize + N - 1) <= 255, "mappings array is too big for the remaining colors available");
|
||||
assert!(
|
||||
(base_dest_color as usize + N - 1) <= 255,
|
||||
"mappings array is too big for the remaining colors available"
|
||||
);
|
||||
for index in 0..N {
|
||||
mapping[index + base_dest_color as usize] = mappings[index];
|
||||
}
|
||||
|
@ -272,7 +270,7 @@ impl BlendMap {
|
|||
}
|
||||
|
||||
Ok(BlendMap {
|
||||
start_color,
|
||||
start_color, //
|
||||
end_color,
|
||||
mapping: maps.into_boxed_slice(),
|
||||
})
|
||||
|
@ -368,10 +366,7 @@ mod tests {
|
|||
mapping[0] = 217;
|
||||
assert_eq!(Some(217), blend_map.blend(17, 0));
|
||||
|
||||
assert_matches!(
|
||||
blend_map.set_mapping(64, 1, 2),
|
||||
Err(BlendMapError::InvalidSourceColor(64))
|
||||
);
|
||||
assert_matches!(blend_map.set_mapping(64, 1, 2), Err(BlendMapError::InvalidSourceColor(64)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -386,11 +381,7 @@ mod tests {
|
|||
assert_ok!(blend_map.set_mappings(2, 4, [1, 2, 3, 4, 5, 6, 7, 8]));
|
||||
|
||||
let mapping = blend_map.get_mapping(2).unwrap();
|
||||
assert_eq!(
|
||||
[0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0],
|
||||
mapping[0..16]
|
||||
);
|
||||
|
||||
assert_eq!([0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0], mapping[0..16]);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -413,4 +404,4 @@ mod tests {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ impl BlendFunction {
|
|||
TintedBlend(tint) => {
|
||||
let tinted = tint_argb32(src, *tint);
|
||||
blend_argb32(tinted, dest)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,9 +257,9 @@ fn srgb_to_linearized(color_channel: u8) -> f32 {
|
|||
|
||||
/// Calculates the given sRGB color's luminance, returned as a value between 0.0 and 1.0.
|
||||
pub fn luminance(r: u8, g: u8, b: u8) -> f32 {
|
||||
(LUMINANCE_RED * srgb_to_linearized(r)) +
|
||||
(LUMINANCE_GREEN * srgb_to_linearized(g)) +
|
||||
(LUMINANCE_BLUE * srgb_to_linearized(b))
|
||||
(LUMINANCE_RED * srgb_to_linearized(r))
|
||||
+ (LUMINANCE_GREEN * srgb_to_linearized(g))
|
||||
+ (LUMINANCE_BLUE * srgb_to_linearized(b))
|
||||
}
|
||||
|
||||
fn brightness(mut luminance: f32) -> f32 {
|
||||
|
|
|
@ -62,7 +62,7 @@ impl Character for BitmaskCharacter {
|
|||
|
||||
fn draw<PixelType>(&self, dest: &mut Bitmap<PixelType>, x: i32, y: i32, opts: FontRenderOpts<PixelType>)
|
||||
where
|
||||
PixelType: Pixel
|
||||
PixelType: Pixel,
|
||||
{
|
||||
// out of bounds check
|
||||
if ((x + self.bounds.width as i32) < dest.clip_region().x)
|
||||
|
@ -104,7 +104,7 @@ pub struct BitmaskFont {
|
|||
|
||||
impl std::fmt::Debug for BitmaskFont {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("BitmaskFont")
|
||||
f.debug_struct("BitmaskFont") //
|
||||
.field("line_height", &self.line_height)
|
||||
.field("space_width", &self.space_width)
|
||||
.field("characters.len()", &self.characters.len())
|
||||
|
@ -134,12 +134,7 @@ impl BitmaskFont {
|
|||
let character = BitmaskCharacter {
|
||||
bytes: buffer,
|
||||
// bounds are filled in below. ugh.
|
||||
bounds: Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
bounds: Rect { x: 0, y: 0, width: 0, height: 0 },
|
||||
};
|
||||
characters.push(character);
|
||||
}
|
||||
|
@ -158,7 +153,7 @@ impl BitmaskFont {
|
|||
let space_width = characters[' ' as usize].bounds.width as u8;
|
||||
|
||||
Ok(BitmaskFont {
|
||||
characters: characters.into_boxed_slice(),
|
||||
characters: characters.into_boxed_slice(), //
|
||||
line_height,
|
||||
space_width,
|
||||
})
|
||||
|
@ -208,7 +203,7 @@ impl Font for BitmaskFont {
|
|||
|
||||
fn measure<PixelType>(&self, text: &str, _opts: FontRenderOpts<PixelType>) -> (u32, u32)
|
||||
where
|
||||
PixelType: Pixel
|
||||
PixelType: Pixel,
|
||||
{
|
||||
if text.is_empty() {
|
||||
return (0, 0);
|
||||
|
|
|
@ -2,9 +2,9 @@ use num_traits::{PrimInt, Unsigned};
|
|||
|
||||
pub mod bitmap;
|
||||
pub mod bitmapatlas;
|
||||
pub mod blendmap;
|
||||
pub mod color;
|
||||
pub mod font;
|
||||
pub mod blendmap;
|
||||
pub mod palette;
|
||||
|
||||
pub mod prelude;
|
||||
|
|
|
@ -14,8 +14,8 @@ use crate::utils::abs_diff;
|
|||
const NUM_COLORS: usize = 256;
|
||||
|
||||
/// Common trait to represent a range of indexed colour values.
|
||||
pub trait ColorRange: RangeBounds<u8> + Iterator<Item=u8> {}
|
||||
impl<T> ColorRange for T where T: RangeBounds<u8> + Iterator<Item=u8> {}
|
||||
pub trait ColorRange: RangeBounds<u8> + Iterator<Item = u8> {}
|
||||
impl<T> ColorRange for T where T: RangeBounds<u8> + Iterator<Item = u8> {}
|
||||
|
||||
pub static VGA_PALETTE_BYTES: &[u8] = include_bytes!("../../assets/vga.pal");
|
||||
|
||||
|
@ -30,10 +30,7 @@ fn to_6bit(value: u8) -> u8 {
|
|||
}
|
||||
|
||||
// vga bios (0-63) format
|
||||
fn read_palette_6bit<T: ReadBytesExt>(
|
||||
reader: &mut T,
|
||||
num_colors: usize,
|
||||
) -> Result<[u32; NUM_COLORS], PaletteError> {
|
||||
fn read_palette_6bit<T: ReadBytesExt>(reader: &mut T, num_colors: usize) -> Result<[u32; NUM_COLORS], PaletteError> {
|
||||
if num_colors > NUM_COLORS {
|
||||
return Err(PaletteError::OutOfRange(num_colors));
|
||||
}
|
||||
|
@ -42,11 +39,7 @@ fn read_palette_6bit<T: ReadBytesExt>(
|
|||
let r = reader.read_u8()?;
|
||||
let g = reader.read_u8()?;
|
||||
let b = reader.read_u8()?;
|
||||
let color = to_rgb32(
|
||||
from_6bit(r),
|
||||
from_6bit(g),
|
||||
from_6bit(b)
|
||||
);
|
||||
let color = to_rgb32(from_6bit(r), from_6bit(g), from_6bit(b));
|
||||
colors[i as usize] = color;
|
||||
}
|
||||
Ok(colors)
|
||||
|
@ -70,10 +63,7 @@ fn write_palette_6bit<T: WriteBytesExt>(
|
|||
}
|
||||
|
||||
// normal (0-255) format
|
||||
fn read_palette_8bit<T: ReadBytesExt>(
|
||||
reader: &mut T,
|
||||
num_colors: usize,
|
||||
) -> Result<[u32; NUM_COLORS], PaletteError> {
|
||||
fn read_palette_8bit<T: ReadBytesExt>(reader: &mut T, num_colors: usize) -> Result<[u32; NUM_COLORS], PaletteError> {
|
||||
if num_colors > NUM_COLORS {
|
||||
return Err(PaletteError::OutOfRange(num_colors));
|
||||
}
|
||||
|
@ -131,17 +121,13 @@ pub struct Palette {
|
|||
impl Palette {
|
||||
/// Creates a new Palette with all black colors.
|
||||
pub fn new() -> Palette {
|
||||
Palette {
|
||||
colors: [0; NUM_COLORS],
|
||||
}
|
||||
Palette { colors: [0; NUM_COLORS] }
|
||||
}
|
||||
|
||||
/// Creates a new Palette with all initial colors having the RGB values specified.
|
||||
pub fn new_with_default(r: u8, g: u8, b: u8) -> Palette {
|
||||
let rgb = to_rgb32(r, g, b);
|
||||
Palette {
|
||||
colors: [rgb; NUM_COLORS],
|
||||
}
|
||||
Palette { colors: [rgb; NUM_COLORS] }
|
||||
}
|
||||
|
||||
/// Creates a new Palette, pre-loaded with the default VGA BIOS colors.
|
||||
|
@ -168,10 +154,7 @@ impl Palette {
|
|||
///
|
||||
/// * `reader`: the reader to load the palette from
|
||||
/// * `format`: the format that the palette data is expected to be in
|
||||
pub fn load_from_bytes<T: ReadBytesExt>(
|
||||
reader: &mut T,
|
||||
format: PaletteFormat,
|
||||
) -> Result<Palette, PaletteError> {
|
||||
pub fn load_from_bytes<T: ReadBytesExt>(reader: &mut T, format: PaletteFormat) -> Result<Palette, PaletteError> {
|
||||
let colors = match format {
|
||||
PaletteFormat::Vga => read_palette_6bit(reader, NUM_COLORS)?,
|
||||
PaletteFormat::Normal => read_palette_8bit(reader, NUM_COLORS)?,
|
||||
|
@ -241,11 +224,7 @@ impl Palette {
|
|||
///
|
||||
/// * `writer`: the writer to write palette data to
|
||||
/// * `format`: the format to write the palette data in
|
||||
pub fn to_bytes<T: WriteBytesExt>(
|
||||
&self,
|
||||
writer: &mut T,
|
||||
format: PaletteFormat,
|
||||
) -> Result<(), PaletteError> {
|
||||
pub fn to_bytes<T: WriteBytesExt>(&self, writer: &mut T, format: PaletteFormat) -> Result<(), PaletteError> {
|
||||
match format {
|
||||
PaletteFormat::Vga => write_palette_6bit(writer, &self.colors, NUM_COLORS),
|
||||
PaletteFormat::Normal => write_palette_8bit(writer, &self.colors, NUM_COLORS),
|
||||
|
@ -314,14 +293,7 @@ impl Palette {
|
|||
/// * `step`: the amount to "step" by towards the target RGB values
|
||||
///
|
||||
/// returns: true if the color has reached the target RGB values, false otherwise
|
||||
pub fn fade_color_toward_rgb(
|
||||
&mut self,
|
||||
color: u8,
|
||||
target_r: u8,
|
||||
target_g: u8,
|
||||
target_b: u8,
|
||||
step: u8,
|
||||
) -> bool {
|
||||
pub fn fade_color_toward_rgb(&mut self, color: u8, target_r: u8, target_g: u8, target_b: u8, step: u8) -> bool {
|
||||
let mut modified = false;
|
||||
|
||||
let (mut r, mut g, mut b) = from_rgb32(self.colors[color as usize]);
|
||||
|
@ -407,12 +379,7 @@ impl Palette {
|
|||
///
|
||||
/// returns: true if all of the colors in the range have reached the RGB values from the other
|
||||
/// target palette, false otherwise
|
||||
pub fn fade_colors_toward_palette<T: ColorRange>(
|
||||
&mut self,
|
||||
colors: T,
|
||||
palette: &Palette,
|
||||
step: u8,
|
||||
) -> bool {
|
||||
pub fn fade_colors_toward_palette<T: ColorRange>(&mut self, colors: T, palette: &Palette, step: u8) -> bool {
|
||||
let mut all_faded = true;
|
||||
for color in colors {
|
||||
let (r, g, b) = from_rgb32(palette[color]);
|
||||
|
@ -481,9 +448,7 @@ impl Palette {
|
|||
// this comparison method is using the sRGB Euclidean formula described here:
|
||||
// https://en.wikipedia.org/wiki/Color_difference
|
||||
|
||||
let distance = abs_diff(this_r, r) as u32
|
||||
+ abs_diff(this_g, g) as u32
|
||||
+ abs_diff(this_b, b) as u32;
|
||||
let distance = abs_diff(this_r, r) as u32 + abs_diff(this_g, g) as u32 + abs_diff(this_b, b) as u32;
|
||||
|
||||
if distance < closest_distance {
|
||||
closest = index as u8;
|
||||
|
@ -597,10 +562,7 @@ mod tests {
|
|||
|
||||
// vga rgb format (6-bit)
|
||||
|
||||
let palette = Palette::load_from_file(
|
||||
test_file(Path::new("vga.pal")).as_path(),
|
||||
PaletteFormat::Vga
|
||||
)?;
|
||||
let palette = Palette::load_from_file(test_file(Path::new("vga.pal")).as_path(), PaletteFormat::Vga)?;
|
||||
assert_ega_colors(&palette);
|
||||
|
||||
let save_path = tmp_dir.path().join("test_save_vga_format.pal");
|
||||
|
@ -610,10 +572,7 @@ mod tests {
|
|||
|
||||
// normal rgb format (8-bit)
|
||||
|
||||
let palette = Palette::load_from_file(
|
||||
test_file(Path::new("dp2.pal")).as_path(),
|
||||
PaletteFormat::Normal
|
||||
)?;
|
||||
let palette = Palette::load_from_file(test_file(Path::new("dp2.pal")).as_path(), PaletteFormat::Normal)?;
|
||||
|
||||
let save_path = tmp_dir.path().join("test_save_normal_format.pal");
|
||||
palette.to_file(&save_path, PaletteFormat::Normal)?;
|
||||
|
@ -629,11 +588,8 @@ mod tests {
|
|||
|
||||
// vga rgb format (6-bit)
|
||||
|
||||
let palette = Palette::load_num_colors_from_file(
|
||||
test_file(Path::new("ega_6bit.pal")).as_path(),
|
||||
PaletteFormat::Vga,
|
||||
16
|
||||
)?;
|
||||
let palette =
|
||||
Palette::load_num_colors_from_file(test_file(Path::new("ega_6bit.pal")).as_path(), PaletteFormat::Vga, 16)?;
|
||||
assert_ega_colors(&palette);
|
||||
|
||||
let save_path = tmp_dir.path().join("test_save_vga_format_16_colors.pal");
|
||||
|
@ -646,7 +602,7 @@ mod tests {
|
|||
let palette = Palette::load_num_colors_from_file(
|
||||
test_file(Path::new("ega_8bit.pal")).as_path(),
|
||||
PaletteFormat::Normal,
|
||||
16
|
||||
16,
|
||||
)?;
|
||||
|
||||
let save_path = tmp_dir.path().join("test_save_normal_format_16_colors.pal");
|
||||
|
|
|
@ -1,29 +1,21 @@
|
|||
pub use crate::graphics::{
|
||||
*,
|
||||
//
|
||||
bitmap::{
|
||||
*,
|
||||
blit::*,
|
||||
general::*,
|
||||
gif::*,
|
||||
iff::*,
|
||||
indexed::{
|
||||
*,
|
||||
blit::*,
|
||||
primitives::*,
|
||||
},
|
||||
indexed::{blit::*, primitives::*, *},
|
||||
pcx::*,
|
||||
png::*,
|
||||
primitives::*,
|
||||
rgb::{
|
||||
*,
|
||||
blit::*,
|
||||
primitives::*,
|
||||
},
|
||||
rgb::{blit::*, primitives::*, *},
|
||||
*,
|
||||
},
|
||||
bitmapatlas::*,
|
||||
blendmap::*,
|
||||
color::*,
|
||||
font::*,
|
||||
palette::*,
|
||||
*,
|
||||
};
|
||||
|
||||
|
|
|
@ -53,4 +53,4 @@ pub mod tests {
|
|||
}
|
||||
Ok(buffer.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::math::{distance_between, distance_squared_between};
|
||||
use crate::math::vector2::Vector2;
|
||||
use crate::math::{distance_between, distance_squared_between};
|
||||
|
||||
/// Represents a 2D circle, using integer center coordinates and radius.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
|
@ -38,7 +38,7 @@ impl Circle {
|
|||
let center_y = (max_y - min_y) / 2.0;
|
||||
|
||||
Some(Circle {
|
||||
x: center_x as i32,
|
||||
x: center_x as i32, //
|
||||
y: center_y as i32,
|
||||
radius: radius as u32,
|
||||
})
|
||||
|
@ -52,18 +52,15 @@ impl Circle {
|
|||
|
||||
/// Returns true if the given point is contained within the bounds of this circle.
|
||||
pub fn contains_point(&self, x: i32, y: i32) -> bool {
|
||||
let distance_squared =
|
||||
distance_squared_between(self.x as f32, self.y as f32, x as f32, y as f32);
|
||||
let distance_squared = distance_squared_between(self.x as f32, self.y as f32, x as f32, y as f32);
|
||||
let radius_squared = (self.radius * self.radius) as f32;
|
||||
distance_squared <= radius_squared
|
||||
}
|
||||
|
||||
/// Returns true if the given circle at least partially overlaps the bounds of this circle.
|
||||
pub fn overlaps(&self, other: &Circle) -> bool {
|
||||
let distance_squared =
|
||||
distance_squared_between(self.x as f32, self.y as f32, other.x as f32, other.y as f32);
|
||||
let minimum_distance_squared =
|
||||
((self.radius + other.radius) * (self.radius + other.radius)) as f32;
|
||||
let distance_squared = distance_squared_between(self.x as f32, self.y as f32, other.x as f32, other.y as f32);
|
||||
let minimum_distance_squared = ((self.radius + other.radius) * (self.radius + other.radius)) as f32;
|
||||
distance_squared <= minimum_distance_squared
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,13 @@ impl Matrix3x3 {
|
|||
pub const M32: usize = 5;
|
||||
pub const M33: usize = 8;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const IDENTITY: Matrix3x3 = Matrix3x3 {
|
||||
m: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
|
||||
m: [
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0
|
||||
],
|
||||
};
|
||||
|
||||
/// Returns a new identity matrix.
|
||||
|
@ -208,18 +213,7 @@ impl Matrix3x3 {
|
|||
|
||||
/// Sets all of the elements of this matrix.
|
||||
#[inline]
|
||||
pub fn set(
|
||||
&mut self,
|
||||
m11: f32,
|
||||
m12: f32,
|
||||
m13: f32,
|
||||
m21: f32,
|
||||
m22: f32,
|
||||
m23: f32,
|
||||
m31: f32,
|
||||
m32: f32,
|
||||
m33: f32,
|
||||
) {
|
||||
pub fn set(&mut self, m11: f32, m12: f32, m13: f32, m21: f32, m22: f32, m23: f32, m31: f32, m32: f32, m33: f32) {
|
||||
self.m[Matrix3x3::M11] = m11;
|
||||
self.m[Matrix3x3::M12] = m12;
|
||||
self.m[Matrix3x3::M13] = m13;
|
||||
|
|
|
@ -53,8 +53,8 @@ pub fn nearly_equal(a: f32, b: f32, epsilon: f32) -> bool {
|
|||
/// * `t`: the amount to interpolate between the two values, specified as a fraction
|
||||
#[inline]
|
||||
pub fn lerp<N>(a: N, b: N, t: f32) -> N
|
||||
where
|
||||
N: Copy + Add<Output=N> + Sub<Output=N> + Mul<f32, Output=N>,
|
||||
where
|
||||
N: Copy + Add<Output = N> + Sub<Output = N> + Mul<f32, Output = N>,
|
||||
{
|
||||
a + (b - a) * t
|
||||
}
|
||||
|
@ -69,8 +69,8 @@ pub fn lerp<N>(a: N, b: N, t: f32) -> N
|
|||
/// * `lerp_result`: the interpolated value between the range given
|
||||
#[inline]
|
||||
pub fn inverse_lerp<N>(a: N, b: N, lerp_result: N) -> f32
|
||||
where
|
||||
N: Copy + Sub<Output=N> + Div<N, Output=f32>,
|
||||
where
|
||||
N: Copy + Sub<Output = N> + Div<N, Output = f32>,
|
||||
{
|
||||
(lerp_result - a) / (b - a)
|
||||
}
|
||||
|
@ -84,8 +84,8 @@ pub fn inverse_lerp<N>(a: N, b: N, lerp_result: N) -> f32
|
|||
/// * `t`: the amount to interpolate between the two values, specified as a fraction
|
||||
#[inline]
|
||||
pub fn smooth_lerp<N>(a: N, b: N, t: f32) -> N
|
||||
where
|
||||
N: Copy + Add<Output=N> + Sub<Output=N> + Mul<f32, Output=N>,
|
||||
where
|
||||
N: Copy + Add<Output = N> + Sub<Output = N> + Mul<f32, Output = N>,
|
||||
{
|
||||
let t = t.clamp(0.0, 1.0);
|
||||
lerp(a, b, (t * t) * (3.0 - (2.0 * t)))
|
||||
|
@ -104,8 +104,8 @@ pub fn smooth_lerp<N>(a: N, b: N, t: f32) -> N
|
|||
/// * `new_max`: new max value (high end of range)
|
||||
#[inline]
|
||||
pub fn scale_range<N>(value: N, old_min: N, old_max: N, new_min: N, new_max: N) -> N
|
||||
where
|
||||
N: Copy + Add<Output=N> + Sub<Output=N> + Mul<Output=N> + Div<Output=N>,
|
||||
where
|
||||
N: Copy + Add<Output = N> + Sub<Output = N> + Mul<Output = N> + Div<Output = N>,
|
||||
{
|
||||
(new_max - new_min) * (value - old_min) / (old_max - old_min) + new_min
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
pub use crate::math::{
|
||||
*,
|
||||
//
|
||||
circle::*,
|
||||
matrix3x3::*,
|
||||
rect::*,
|
||||
vector2::*,
|
||||
*,
|
||||
};
|
||||
|
||||
|
|
|
@ -10,12 +10,7 @@ pub struct Rect {
|
|||
impl Rect {
|
||||
#[inline]
|
||||
pub fn new(x: i32, y: i32, width: u32, height: u32) -> Rect {
|
||||
Rect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
}
|
||||
Rect { x, y, width, height }
|
||||
}
|
||||
|
||||
/// Creates a new rect from the specified coordinates. Automatically determines if the
|
||||
|
@ -51,7 +46,7 @@ impl Rect {
|
|||
}
|
||||
|
||||
Rect {
|
||||
x,
|
||||
x, //
|
||||
y,
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
|
@ -165,21 +160,11 @@ pub mod tests {
|
|||
|
||||
#[test]
|
||||
pub fn right_and_left() {
|
||||
let rect = Rect {
|
||||
x: 5,
|
||||
y: 6,
|
||||
width: 16,
|
||||
height: 12,
|
||||
};
|
||||
let rect = Rect { x: 5, y: 6, width: 16, height: 12 };
|
||||
assert_eq!(20, rect.right());
|
||||
assert_eq!(17, rect.bottom());
|
||||
|
||||
let rect = Rect {
|
||||
x: -11,
|
||||
y: -25,
|
||||
width: 16,
|
||||
height: 12,
|
||||
};
|
||||
let rect = Rect { x: -11, y: -25, width: 16, height: 12 };
|
||||
assert_eq!(4, rect.right());
|
||||
assert_eq!(-14, rect.bottom());
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use crate::math::{angle_between, angle_to_direction, nearly_equal, NearlyEqual};
|
||||
use crate::math::matrix3x3::Matrix3x3;
|
||||
use crate::math::{angle_between, angle_to_direction, nearly_equal, NearlyEqual};
|
||||
|
||||
/// Represents a 2D vector and provides common methods for vector math.
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
|
@ -68,7 +68,7 @@ impl Vector2 {
|
|||
pub fn normalize(&self) -> Vector2 {
|
||||
let inverse_length = 1.0 / self.length();
|
||||
Vector2 {
|
||||
x: self.x * inverse_length,
|
||||
x: self.x * inverse_length, //
|
||||
y: self.y * inverse_length,
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ impl Neg for Vector2 {
|
|||
#[inline]
|
||||
fn neg(self) -> Self::Output {
|
||||
Vector2 {
|
||||
x: -self.x,
|
||||
x: -self.x, //
|
||||
y: -self.y,
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ impl Add for Vector2 {
|
|||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Vector2 {
|
||||
x: self.x + rhs.x,
|
||||
x: self.x + rhs.x, //
|
||||
y: self.y + rhs.y,
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ impl Sub for Vector2 {
|
|||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Vector2 {
|
||||
x: self.x - rhs.x,
|
||||
x: self.x - rhs.x, //
|
||||
y: self.y - rhs.y,
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ impl Mul for Vector2 {
|
|||
#[inline]
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
Vector2 {
|
||||
x: self.x * rhs.x,
|
||||
x: self.x * rhs.x, //
|
||||
y: self.y * rhs.y,
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ impl Div for Vector2 {
|
|||
#[inline]
|
||||
fn div(self, rhs: Self) -> Self::Output {
|
||||
Vector2 {
|
||||
x: self.x / rhs.x,
|
||||
x: self.x / rhs.x, //
|
||||
y: self.y / rhs.y,
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ impl Mul<f32> for Vector2 {
|
|||
#[inline]
|
||||
fn mul(self, rhs: f32) -> Self::Output {
|
||||
Vector2 {
|
||||
x: self.x * rhs,
|
||||
x: self.x * rhs, //
|
||||
y: self.y * rhs,
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ impl Div<f32> for Vector2 {
|
|||
#[inline]
|
||||
fn div(self, rhs: f32) -> Self::Output {
|
||||
Vector2 {
|
||||
x: self.x / rhs,
|
||||
x: self.x / rhs, //
|
||||
y: self.y / rhs,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pub use crate::{
|
||||
*,
|
||||
//
|
||||
audio::prelude::*,
|
||||
base::*,
|
||||
entities::*,
|
||||
|
@ -9,10 +9,8 @@ pub use crate::{
|
|||
states::*,
|
||||
system::{
|
||||
prelude::*,
|
||||
res::{
|
||||
dos_like::*,
|
||||
standard::*,
|
||||
},
|
||||
res::{dos_like::*, standard::*},
|
||||
},
|
||||
utils::prelude::*,
|
||||
*,
|
||||
};
|
||||
|
|
|
@ -81,7 +81,7 @@ impl<ContextType> std::fmt::Debug for StateContainer<ContextType> {
|
|||
impl<ContextType> StateContainer<ContextType> {
|
||||
pub fn new(state: Box<dyn AppState<ContextType>>) -> Self {
|
||||
StateContainer {
|
||||
current_state: State::Dead,
|
||||
current_state: State::Dead, //
|
||||
pending_state_change: None,
|
||||
state,
|
||||
}
|
||||
|
@ -133,9 +133,7 @@ impl<ContextType> StateContainer<ContextType> {
|
|||
self.change_state(State::TransitionIn, context);
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
Err(StateError::AppStateInvalidState(self.current_state))
|
||||
}
|
||||
_ => Err(StateError::AppStateInvalidState(self.current_state)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,13 +183,16 @@ pub struct States<ContextType> {
|
|||
|
||||
impl<ContextType> std::fmt::Debug for States<ContextType> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("States")
|
||||
f.debug_struct("States") //
|
||||
.field("states", &self.states)
|
||||
.field("command", &self.command)
|
||||
.field("pending_state", match self.pending_state {
|
||||
Some(..) => &"Some(..)",
|
||||
None => &"None",
|
||||
})
|
||||
.field(
|
||||
"pending_state",
|
||||
match self.pending_state {
|
||||
Some(..) => &"Some(..)",
|
||||
None => &"None",
|
||||
},
|
||||
)
|
||||
.field("pop_count", &self.pop_count)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
|
@ -200,7 +201,7 @@ impl<ContextType> std::fmt::Debug for States<ContextType> {
|
|||
impl<ContextType> States<ContextType> {
|
||||
pub fn new() -> Self {
|
||||
States {
|
||||
states: VecDeque::new(),
|
||||
states: VecDeque::new(), //
|
||||
command: None,
|
||||
pending_state: None,
|
||||
pop_count: None,
|
||||
|
@ -400,8 +401,12 @@ impl<ContextType> States<ContextType> {
|
|||
// state has indicated it is done transitioning, so we can switch it to whatever
|
||||
// it was transitioning to
|
||||
match to {
|
||||
TransitionTo::Paused => { state.pending_pause(); }
|
||||
TransitionTo::Dead => { state.pending_kill(); }
|
||||
TransitionTo::Paused => {
|
||||
state.pending_pause();
|
||||
}
|
||||
TransitionTo::Dead => {
|
||||
state.pending_kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -444,7 +449,6 @@ impl<ContextType> States<ContextType> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use claim::*;
|
||||
|
@ -465,9 +469,7 @@ mod tests {
|
|||
|
||||
impl TestContext {
|
||||
pub fn new() -> Self {
|
||||
TestContext {
|
||||
log: Vec::new()
|
||||
}
|
||||
TestContext { log: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn log(&mut self, entry: LogEntry) {
|
||||
|
@ -490,7 +492,7 @@ mod tests {
|
|||
impl TestState {
|
||||
pub fn new(id: u32) -> Self {
|
||||
TestState {
|
||||
id,
|
||||
id, //
|
||||
counter: 0,
|
||||
transition_length: 0,
|
||||
}
|
||||
|
@ -498,7 +500,7 @@ mod tests {
|
|||
|
||||
pub fn new_with_transition_length(id: u32, transition_length: u32) -> Self {
|
||||
TestState {
|
||||
id,
|
||||
id, //
|
||||
counter: 0,
|
||||
transition_length,
|
||||
}
|
||||
|
@ -562,7 +564,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, Pending, Dead),
|
||||
StateChange(FOO, Pending, Dead), //
|
||||
StateChange(FOO, TransitionIn, Pending),
|
||||
Transition(FOO, TransitionIn),
|
||||
Update(FOO, TransitionIn),
|
||||
|
@ -574,7 +576,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, Active, TransitionIn),
|
||||
StateChange(FOO, Active, TransitionIn), //
|
||||
Update(FOO, Active),
|
||||
Render(FOO, Active),
|
||||
]
|
||||
|
@ -588,7 +590,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(FOO, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
Update(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -623,7 +625,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, Pending, Dead),
|
||||
StateChange(FOO, Pending, Dead), //
|
||||
StateChange(FOO, TransitionIn, Pending),
|
||||
Transition(FOO, TransitionIn),
|
||||
Update(FOO, TransitionIn),
|
||||
|
@ -636,7 +638,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Transition(FOO, TransitionIn),
|
||||
Transition(FOO, TransitionIn), //
|
||||
Update(FOO, TransitionIn),
|
||||
Render(FOO, TransitionIn),
|
||||
]
|
||||
|
@ -647,7 +649,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, Active, TransitionIn),
|
||||
StateChange(FOO, Active, TransitionIn), //
|
||||
Update(FOO, Active),
|
||||
Render(FOO, Active),
|
||||
]
|
||||
|
@ -661,7 +663,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(FOO, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
Update(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -673,7 +675,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Transition(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
Transition(FOO, TransitionOut(TransitionTo::Dead)), //
|
||||
Update(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
]
|
||||
|
@ -710,7 +712,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Pending, Dead),
|
||||
StateChange(FIRST, Pending, Dead), //
|
||||
StateChange(FIRST, TransitionIn, Pending),
|
||||
Transition(FIRST, TransitionIn),
|
||||
Update(FIRST, TransitionIn),
|
||||
|
@ -722,7 +724,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Active, TransitionIn),
|
||||
StateChange(FIRST, Active, TransitionIn), //
|
||||
Update(FIRST, Active),
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
|
@ -737,7 +739,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Paused), Active),
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Paused), Active), //
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Update(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
|
@ -749,7 +751,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Paused, TransitionOut(TransitionTo::Paused)),
|
||||
StateChange(FIRST, Paused, TransitionOut(TransitionTo::Paused)), //
|
||||
StateChange(SECOND, Pending, Dead),
|
||||
StateChange(SECOND, TransitionIn, Pending),
|
||||
Transition(SECOND, TransitionIn),
|
||||
|
@ -762,7 +764,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Active, TransitionIn),
|
||||
StateChange(SECOND, Active, TransitionIn), //
|
||||
Update(SECOND, Active),
|
||||
Render(SECOND, Active),
|
||||
]
|
||||
|
@ -777,7 +779,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Update(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Render(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -789,7 +791,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Dead, TransitionOut(TransitionTo::Dead)),
|
||||
StateChange(SECOND, Dead, TransitionOut(TransitionTo::Dead)), //
|
||||
StateChange(FIRST, Resume, Paused),
|
||||
StateChange(FIRST, TransitionIn, Resume),
|
||||
Transition(FIRST, TransitionIn),
|
||||
|
@ -802,7 +804,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Active, TransitionIn),
|
||||
StateChange(FIRST, Active, TransitionIn), //
|
||||
Update(FIRST, Active),
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
|
@ -817,7 +819,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Update(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -854,7 +856,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Pending, Dead),
|
||||
StateChange(FIRST, Pending, Dead), //
|
||||
StateChange(FIRST, TransitionIn, Pending),
|
||||
Transition(FIRST, TransitionIn),
|
||||
Update(FIRST, TransitionIn),
|
||||
|
@ -867,7 +869,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Transition(FIRST, TransitionIn),
|
||||
Transition(FIRST, TransitionIn), //
|
||||
Update(FIRST, TransitionIn),
|
||||
Render(FIRST, TransitionIn),
|
||||
]
|
||||
|
@ -878,7 +880,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Active, TransitionIn),
|
||||
StateChange(FIRST, Active, TransitionIn), //
|
||||
Update(FIRST, Active),
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
|
@ -894,7 +896,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Paused), Active),
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Paused), Active), //
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Update(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
|
@ -906,7 +908,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Paused)), //
|
||||
Update(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
]
|
||||
|
@ -917,7 +919,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Paused, TransitionOut(TransitionTo::Paused)),
|
||||
StateChange(FIRST, Paused, TransitionOut(TransitionTo::Paused)), //
|
||||
StateChange(SECOND, Pending, Dead),
|
||||
StateChange(SECOND, TransitionIn, Pending),
|
||||
Transition(SECOND, TransitionIn),
|
||||
|
@ -931,7 +933,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Transition(SECOND, TransitionIn),
|
||||
Transition(SECOND, TransitionIn), //
|
||||
Update(SECOND, TransitionIn),
|
||||
Render(SECOND, TransitionIn),
|
||||
]
|
||||
|
@ -942,7 +944,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Active, TransitionIn),
|
||||
StateChange(SECOND, Active, TransitionIn), //
|
||||
Update(SECOND, Active),
|
||||
Render(SECOND, Active),
|
||||
]
|
||||
|
@ -957,7 +959,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Update(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Render(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -969,7 +971,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Transition(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Transition(SECOND, TransitionOut(TransitionTo::Dead)), //
|
||||
Update(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Render(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
]
|
||||
|
@ -981,7 +983,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Dead, TransitionOut(TransitionTo::Dead)),
|
||||
StateChange(SECOND, Dead, TransitionOut(TransitionTo::Dead)), //
|
||||
StateChange(FIRST, Resume, Paused),
|
||||
StateChange(FIRST, TransitionIn, Resume),
|
||||
Transition(FIRST, TransitionIn),
|
||||
|
@ -995,7 +997,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Transition(FIRST, TransitionIn),
|
||||
Transition(FIRST, TransitionIn), //
|
||||
Update(FIRST, TransitionIn),
|
||||
Render(FIRST, TransitionIn),
|
||||
]
|
||||
|
@ -1006,7 +1008,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Active, TransitionIn),
|
||||
StateChange(FIRST, Active, TransitionIn), //
|
||||
Update(FIRST, Active),
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
|
@ -1021,7 +1023,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Update(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -1033,7 +1035,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Dead)), //
|
||||
Update(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
]
|
||||
|
@ -1070,7 +1072,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Pending, Dead),
|
||||
StateChange(FIRST, Pending, Dead), //
|
||||
StateChange(FIRST, TransitionIn, Pending),
|
||||
Transition(FIRST, TransitionIn),
|
||||
Update(FIRST, TransitionIn),
|
||||
|
@ -1082,7 +1084,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Active, TransitionIn),
|
||||
StateChange(FIRST, Active, TransitionIn), //
|
||||
Update(FIRST, Active),
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
|
@ -1097,7 +1099,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Paused), Active),
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Paused), Active), //
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Update(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
|
@ -1109,7 +1111,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Paused, TransitionOut(TransitionTo::Paused)),
|
||||
StateChange(FIRST, Paused, TransitionOut(TransitionTo::Paused)), //
|
||||
StateChange(SECOND, Pending, Dead),
|
||||
StateChange(SECOND, TransitionIn, Pending),
|
||||
Transition(SECOND, TransitionIn),
|
||||
|
@ -1122,7 +1124,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Active, TransitionIn),
|
||||
StateChange(SECOND, Active, TransitionIn), //
|
||||
Update(SECOND, Active),
|
||||
Render(SECOND, Active),
|
||||
]
|
||||
|
@ -1137,7 +1139,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Update(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Render(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -1149,7 +1151,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Dead, TransitionOut(TransitionTo::Dead)),
|
||||
StateChange(SECOND, Dead, TransitionOut(TransitionTo::Dead)), //
|
||||
StateChange(FIRST, Dead, Paused),
|
||||
]
|
||||
);
|
||||
|
@ -1161,7 +1163,6 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn swap_states() -> Result<(), StateError> {
|
||||
use LogEntry::*;
|
||||
|
@ -1182,7 +1183,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Pending, Dead),
|
||||
StateChange(FIRST, Pending, Dead), //
|
||||
StateChange(FIRST, TransitionIn, Pending),
|
||||
Transition(FIRST, TransitionIn),
|
||||
Update(FIRST, TransitionIn),
|
||||
|
@ -1194,7 +1195,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Active, TransitionIn),
|
||||
StateChange(FIRST, Active, TransitionIn), //
|
||||
Update(FIRST, Active),
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
|
@ -1209,7 +1210,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Update(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -1221,7 +1222,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Dead, TransitionOut(TransitionTo::Dead)),
|
||||
StateChange(FIRST, Dead, TransitionOut(TransitionTo::Dead)), //
|
||||
StateChange(SECOND, Pending, Dead),
|
||||
StateChange(SECOND, TransitionIn, Pending),
|
||||
Transition(SECOND, TransitionIn),
|
||||
|
@ -1234,7 +1235,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Active, TransitionIn),
|
||||
StateChange(SECOND, Active, TransitionIn), //
|
||||
Update(SECOND, Active),
|
||||
Render(SECOND, Active),
|
||||
]
|
||||
|
@ -1248,7 +1249,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Update(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Render(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -1275,7 +1276,7 @@ mod tests {
|
|||
impl SelfPushPopState {
|
||||
pub fn new(id: u32, push_after: Option<u32>, pop_after: u32) -> Self {
|
||||
SelfPushPopState {
|
||||
id,
|
||||
id, //
|
||||
counter: 0,
|
||||
push_after,
|
||||
pop_after,
|
||||
|
@ -1311,7 +1312,6 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn state_can_push_and_pop_states_itself() -> Result<(), StateError> {
|
||||
use LogEntry::*;
|
||||
|
@ -1332,7 +1332,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Pending, Dead),
|
||||
StateChange(FIRST, Pending, Dead), //
|
||||
StateChange(FIRST, TransitionIn, Pending),
|
||||
Transition(FIRST, TransitionIn),
|
||||
Update(FIRST, TransitionIn),
|
||||
|
@ -1344,7 +1344,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Active, TransitionIn),
|
||||
StateChange(FIRST, Active, TransitionIn), //
|
||||
Update(FIRST, Active),
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
|
@ -1355,7 +1355,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Update(FIRST, Active),
|
||||
Update(FIRST, Active), //
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
);
|
||||
|
@ -1366,7 +1366,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Paused), Active),
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Paused), Active), //
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Update(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Paused)),
|
||||
|
@ -1377,7 +1377,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Paused, TransitionOut(TransitionTo::Paused)),
|
||||
StateChange(FIRST, Paused, TransitionOut(TransitionTo::Paused)), //
|
||||
StateChange(SECOND, Pending, Dead),
|
||||
StateChange(SECOND, TransitionIn, Pending),
|
||||
Transition(SECOND, TransitionIn),
|
||||
|
@ -1390,7 +1390,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Active, TransitionIn),
|
||||
StateChange(SECOND, Active, TransitionIn), //
|
||||
Update(SECOND, Active),
|
||||
Render(SECOND, Active),
|
||||
]
|
||||
|
@ -1401,7 +1401,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Update(SECOND, Active),
|
||||
Update(SECOND, Active), //
|
||||
Render(SECOND, Active),
|
||||
]
|
||||
);
|
||||
|
@ -1412,7 +1412,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(SECOND, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Update(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
Render(SECOND, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -1424,7 +1424,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(SECOND, Dead, TransitionOut(TransitionTo::Dead)),
|
||||
StateChange(SECOND, Dead, TransitionOut(TransitionTo::Dead)), //
|
||||
StateChange(FIRST, Resume, Paused),
|
||||
StateChange(FIRST, TransitionIn, Resume),
|
||||
Transition(FIRST, TransitionIn),
|
||||
|
@ -1437,7 +1437,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, Active, TransitionIn),
|
||||
StateChange(FIRST, Active, TransitionIn), //
|
||||
Update(FIRST, Active),
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
|
@ -1448,7 +1448,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
Update(FIRST, Active),
|
||||
Update(FIRST, Active), //
|
||||
Render(FIRST, Active),
|
||||
]
|
||||
);
|
||||
|
@ -1459,7 +1459,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(FIRST, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Update(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FIRST, TransitionOut(TransitionTo::Dead)),
|
||||
|
@ -1494,7 +1494,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, Pending, Dead),
|
||||
StateChange(FOO, Pending, Dead), //
|
||||
StateChange(FOO, TransitionIn, Pending),
|
||||
Transition(FOO, TransitionIn),
|
||||
Update(FOO, TransitionIn),
|
||||
|
@ -1510,7 +1510,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, Active, TransitionIn),
|
||||
StateChange(FOO, Active, TransitionIn), //
|
||||
Update(FOO, Active),
|
||||
Render(FOO, Active),
|
||||
]
|
||||
|
@ -1524,7 +1524,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
context.take_log(),
|
||||
vec![
|
||||
StateChange(FOO, TransitionOut(TransitionTo::Dead), Active),
|
||||
StateChange(FOO, TransitionOut(TransitionTo::Dead), Active), //
|
||||
Transition(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
Update(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
Render(FOO, TransitionOut(TransitionTo::Dead)),
|
||||
|
|
|
@ -58,33 +58,33 @@ impl From<sdl2::event::WindowEvent> for WindowEvent {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct KeyModifiers: u16 {
|
||||
const NOMOD = 0x0000;
|
||||
const LSHIFTMOD = 0x0001;
|
||||
const RSHIFTMOD = 0x0002;
|
||||
const LCTRLMOD = 0x0040;
|
||||
const RCTRLMOD = 0x0080;
|
||||
const LALTMOD = 0x0100;
|
||||
const RALTMOD = 0x0200;
|
||||
const LGUIMOD = 0x0400;
|
||||
const RGUIMOD = 0x0800;
|
||||
const NUMMOD = 0x1000;
|
||||
const CAPSMOD = 0x2000;
|
||||
const MODEMOD = 0x4000;
|
||||
const RESERVEDMOD = 0x8000;
|
||||
}
|
||||
pub struct KeyModifiers: u16 {
|
||||
const NOMOD = 0x0000;
|
||||
const LSHIFTMOD = 0x0001;
|
||||
const RSHIFTMOD = 0x0002;
|
||||
const LCTRLMOD = 0x0040;
|
||||
const RCTRLMOD = 0x0080;
|
||||
const LALTMOD = 0x0100;
|
||||
const RALTMOD = 0x0200;
|
||||
const LGUIMOD = 0x0400;
|
||||
const RGUIMOD = 0x0800;
|
||||
const NUMMOD = 0x1000;
|
||||
const CAPSMOD = 0x2000;
|
||||
const MODEMOD = 0x4000;
|
||||
const RESERVEDMOD = 0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum KeyboardEvent {
|
||||
KeyUp {
|
||||
keycode: Option<Keycode>,
|
||||
keycode: Option<Keycode>, //
|
||||
scancode: Option<Scancode>,
|
||||
keymod: KeyModifiers,
|
||||
repeat: bool,
|
||||
},
|
||||
KeyDown {
|
||||
keycode: Option<Keycode>,
|
||||
keycode: Option<Keycode>, //
|
||||
scancode: Option<Scancode>,
|
||||
keymod: KeyModifiers,
|
||||
repeat: bool,
|
||||
|
@ -94,20 +94,20 @@ pub enum KeyboardEvent {
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum MouseEvent {
|
||||
MouseMotion {
|
||||
x: i32,
|
||||
x: i32, //
|
||||
y: i32,
|
||||
x_delta: i32,
|
||||
y_delta: i32,
|
||||
buttons: MouseButtons,
|
||||
},
|
||||
MouseButtonDown {
|
||||
x: i32,
|
||||
x: i32, //
|
||||
y: i32,
|
||||
button: MouseButton,
|
||||
clicks: u8,
|
||||
},
|
||||
MouseButtonUp {
|
||||
x: i32,
|
||||
x: i32, //
|
||||
y: i32,
|
||||
button: MouseButton,
|
||||
clicks: u8,
|
||||
|
@ -168,20 +168,10 @@ impl From<sdl2::event::Event> for SystemEvent {
|
|||
})
|
||||
}
|
||||
sdl2::event::Event::MouseButtonDown { mouse_btn, clicks, x, y, .. } => {
|
||||
SystemEvent::Mouse(MouseEvent::MouseButtonDown {
|
||||
x,
|
||||
y,
|
||||
clicks,
|
||||
button: mouse_btn.into(),
|
||||
})
|
||||
SystemEvent::Mouse(MouseEvent::MouseButtonDown { x, y, clicks, button: mouse_btn.into() })
|
||||
}
|
||||
sdl2::event::Event::MouseButtonUp { mouse_btn, clicks, x, y, .. } => {
|
||||
SystemEvent::Mouse(MouseEvent::MouseButtonUp {
|
||||
x,
|
||||
y,
|
||||
clicks,
|
||||
button: mouse_btn.into(),
|
||||
})
|
||||
SystemEvent::Mouse(MouseEvent::MouseButtonUp { x, y, clicks, button: mouse_btn.into() })
|
||||
}
|
||||
|
||||
_ => SystemEvent::Unimplemented,
|
||||
|
@ -218,9 +208,7 @@ pub struct SystemEventPump {
|
|||
|
||||
impl SystemEventPump {
|
||||
pub fn from(pump: sdl2::EventPump) -> Self {
|
||||
SystemEventPump {
|
||||
sdl_event_pump: pump,
|
||||
}
|
||||
SystemEventPump { sdl_event_pump: pump }
|
||||
}
|
||||
|
||||
/// Returns an iterator over [`SystemEvent`]s that have been generated since the last time
|
||||
|
|
|
@ -480,4 +480,4 @@ impl From<sdl2::keyboard::Keycode> for Keycode {
|
|||
sdl2::keyboard::Keycode::Sleep => Keycode::Sleep,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::system::event::{KeyboardEvent, SystemEvent, SystemEventHandler};
|
||||
use crate::system::input_devices::{ButtonState, InputDevice};
|
||||
use crate::system::input_devices::keyboard::scancodes::Scancode;
|
||||
use crate::system::input_devices::{ButtonState, InputDevice};
|
||||
|
||||
pub mod codes;
|
||||
pub mod scancodes;
|
||||
|
@ -21,9 +21,7 @@ pub struct Keyboard {
|
|||
|
||||
impl Keyboard {
|
||||
pub fn new() -> Keyboard {
|
||||
Keyboard {
|
||||
keyboard: [ButtonState::Idle; MAX_KEYS],
|
||||
}
|
||||
Keyboard { keyboard: [ButtonState::Idle; MAX_KEYS] }
|
||||
/*
|
||||
Keyboard {
|
||||
keyboard: vec![ButtonState::Idle; 256].into_boxed_slice(),
|
||||
|
@ -34,19 +32,13 @@ impl Keyboard {
|
|||
/// Returns true if the given key was just pressed or is being held down.
|
||||
#[inline]
|
||||
pub fn is_key_down(&self, scancode: Scancode) -> bool {
|
||||
matches!(
|
||||
self.keyboard[scancode as usize],
|
||||
ButtonState::Pressed | ButtonState::Held
|
||||
)
|
||||
matches!(self.keyboard[scancode as usize], ButtonState::Pressed | ButtonState::Held)
|
||||
}
|
||||
|
||||
/// Returns true if the given key was not just pressed and is not being held down.
|
||||
#[inline]
|
||||
pub fn is_key_up(&self, scancode: Scancode) -> bool {
|
||||
matches!(
|
||||
self.keyboard[scancode as usize],
|
||||
ButtonState::Released | ButtonState::Idle
|
||||
)
|
||||
matches!(self.keyboard[scancode as usize], ButtonState::Released | ButtonState::Idle)
|
||||
}
|
||||
|
||||
/// Returns true if the given key was just pressed (not being held down, yet).
|
||||
|
@ -97,4 +89,4 @@ impl SystemEventHandler for Keyboard {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -492,4 +492,4 @@ impl From<sdl2::keyboard::Scancode> for Scancode {
|
|||
sdl2::keyboard::Scancode::Num => Scancode::Num,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use bitflags::bitflags;
|
||||
|
||||
bitflags! {
|
||||
pub struct MouseButtons: u32 {
|
||||
const LEFT_BUTTON = sdl2::mouse::MouseButton::Left as u32;
|
||||
const MIDDLE_BUTTON = sdl2::mouse::MouseButton::Middle as u32;
|
||||
const RIGHT_BUTTON = sdl2::mouse::MouseButton::Right as u32;
|
||||
const X1 = sdl2::mouse::MouseButton::X1 as u32;
|
||||
const X2 = sdl2::mouse::MouseButton::X2 as u32;
|
||||
}
|
||||
pub struct MouseButtons: u32 {
|
||||
const LEFT_BUTTON = sdl2::mouse::MouseButton::Left as u32;
|
||||
const MIDDLE_BUTTON = sdl2::mouse::MouseButton::Middle as u32;
|
||||
const RIGHT_BUTTON = sdl2::mouse::MouseButton::Right as u32;
|
||||
const X1 = sdl2::mouse::MouseButton::X1 as u32;
|
||||
const X2 = sdl2::mouse::MouseButton::X2 as u32;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
|
@ -29,7 +29,7 @@ impl From<sdl2::mouse::MouseButton> for MouseButton {
|
|||
sdl2::mouse::MouseButton::Middle => MouseButton::Middle,
|
||||
sdl2::mouse::MouseButton::Right => MouseButton::Right,
|
||||
sdl2::mouse::MouseButton::X1 => MouseButton::X1,
|
||||
sdl2::mouse::MouseButton::X2 => MouseButton::X2
|
||||
sdl2::mouse::MouseButton::X2 => MouseButton::X2,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ const DEFAULT_MOUSE_CURSOR_HEIGHT: usize = 16;
|
|||
#[derive(Debug)]
|
||||
pub struct MouseCursorBitmap<BitmapType>
|
||||
where
|
||||
BitmapType: GeneralBitmap
|
||||
BitmapType: GeneralBitmap,
|
||||
{
|
||||
pub cursor: BitmapType,
|
||||
pub hotspot_x: u32,
|
||||
|
@ -22,7 +22,7 @@ where
|
|||
|
||||
pub trait DefaultMouseCursorBitmaps<BitmapType>
|
||||
where
|
||||
BitmapType: GeneralBitmap
|
||||
BitmapType: GeneralBitmap,
|
||||
{
|
||||
fn get_default() -> MouseCursorBitmap<BitmapType>;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ where
|
|||
#[derive(Debug)]
|
||||
pub struct CustomMouseCursor<BitmapType>
|
||||
where
|
||||
BitmapType: GeneralBitmap
|
||||
BitmapType: GeneralBitmap,
|
||||
{
|
||||
last_x: i32,
|
||||
last_y: i32,
|
||||
|
@ -48,14 +48,11 @@ where
|
|||
impl<BitmapType> CustomMouseCursor<BitmapType>
|
||||
where
|
||||
Self: DefaultMouseCursorBitmaps<BitmapType>,
|
||||
BitmapType: GeneralBitmap
|
||||
BitmapType: GeneralBitmap,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
let default_cursor = Self::get_default();
|
||||
let background = BitmapType::new(
|
||||
default_cursor.cursor.width(),
|
||||
default_cursor.cursor.height()
|
||||
).unwrap();
|
||||
let background = BitmapType::new(default_cursor.cursor.width(), default_cursor.cursor.height()).unwrap();
|
||||
|
||||
CustomMouseCursor {
|
||||
last_x: 0,
|
||||
|
@ -108,7 +105,13 @@ where
|
|||
/// * `cursor`: the bitmap to be used to display the mouse cursor on screen
|
||||
/// * `hotspot_x`: the "hotspot" x coordinate
|
||||
/// * `hotspot_y`: the "hotspot" y coordinate.
|
||||
pub fn set_mouse_cursor(&mut self, cursor: BitmapType, transparent_color: BitmapType::PixelType, hotspot_x: u32, hotspot_y: u32) {
|
||||
pub fn set_mouse_cursor(
|
||||
&mut self,
|
||||
cursor: BitmapType,
|
||||
transparent_color: BitmapType::PixelType,
|
||||
hotspot_x: u32,
|
||||
hotspot_y: u32,
|
||||
) {
|
||||
self.cursor = cursor;
|
||||
self.cursor_hotspot_x = hotspot_x;
|
||||
self.cursor_hotspot_y = hotspot_y;
|
||||
|
@ -134,7 +137,7 @@ where
|
|||
#[inline]
|
||||
fn get_cursor_render_position(&self) -> (i32, i32) {
|
||||
(
|
||||
self.last_x - self.cursor_hotspot_x as i32,
|
||||
self.last_x - self.cursor_hotspot_x as i32, //
|
||||
self.last_y - self.cursor_hotspot_y as i32,
|
||||
)
|
||||
}
|
||||
|
@ -167,12 +170,7 @@ where
|
|||
0,
|
||||
);
|
||||
|
||||
dest.blit(
|
||||
GeneralBlitMethod::Transparent(self.cursor_transparent_color),
|
||||
&self.cursor,
|
||||
x,
|
||||
y
|
||||
);
|
||||
dest.blit(GeneralBlitMethod::Transparent(self.cursor_transparent_color), &self.cursor, x, y);
|
||||
}
|
||||
|
||||
/// Restores the original destination bitmap contents where the mouse cursor bitmap was
|
||||
|
@ -228,10 +226,8 @@ impl DefaultMouseCursorBitmaps<IndexedBitmap> for CustomMouseCursor<IndexedBitma
|
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
];
|
||||
|
||||
let mut cursor = IndexedBitmap::new(
|
||||
DEFAULT_MOUSE_CURSOR_WIDTH as u32,
|
||||
DEFAULT_MOUSE_CURSOR_HEIGHT as u32,
|
||||
).unwrap();
|
||||
let mut cursor =
|
||||
IndexedBitmap::new(DEFAULT_MOUSE_CURSOR_WIDTH as u32, DEFAULT_MOUSE_CURSOR_HEIGHT as u32).unwrap();
|
||||
cursor.pixels_mut().copy_from_slice(&CURSOR_PIXELS);
|
||||
|
||||
MouseCursorBitmap {
|
||||
|
@ -265,10 +261,8 @@ impl DefaultMouseCursorBitmaps<RgbaBitmap> for CustomMouseCursor<RgbaBitmap> {
|
|||
0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff, 0x00000000, 0x00000000, 0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff, 0xffff00ff
|
||||
];
|
||||
|
||||
let mut cursor = RgbaBitmap::new(
|
||||
DEFAULT_MOUSE_CURSOR_WIDTH as u32,
|
||||
DEFAULT_MOUSE_CURSOR_HEIGHT as u32,
|
||||
).unwrap();
|
||||
let mut cursor =
|
||||
RgbaBitmap::new(DEFAULT_MOUSE_CURSOR_WIDTH as u32, DEFAULT_MOUSE_CURSOR_HEIGHT as u32).unwrap();
|
||||
cursor.pixels_mut().copy_from_slice(&CURSOR_PIXELS);
|
||||
|
||||
MouseCursorBitmap {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::system::event::{MouseEvent, SystemEvent, SystemEventHandler};
|
||||
use crate::system::input_devices::{ButtonState, InputDevice};
|
||||
use crate::system::input_devices::mouse::buttons::{MouseButton, MouseButtons};
|
||||
use crate::system::input_devices::{ButtonState, InputDevice};
|
||||
|
||||
pub mod buttons;
|
||||
pub mod cursor;
|
||||
|
@ -26,7 +26,7 @@ pub struct Mouse {
|
|||
impl Mouse {
|
||||
pub fn new() -> Mouse {
|
||||
Mouse {
|
||||
x: 0,
|
||||
x: 0, //
|
||||
y: 0,
|
||||
x_delta: 0,
|
||||
y_delta: 0,
|
||||
|
@ -63,19 +63,13 @@ impl Mouse {
|
|||
/// Returns true if the given button was just pressed or is being held down.
|
||||
#[inline]
|
||||
pub fn is_button_down(&self, button: usize) -> bool {
|
||||
matches!(
|
||||
self.buttons[button],
|
||||
ButtonState::Pressed | ButtonState::Held
|
||||
)
|
||||
matches!(self.buttons[button], ButtonState::Pressed | ButtonState::Held)
|
||||
}
|
||||
|
||||
/// Returns true if the given button was not just pressed and is not being held down.
|
||||
#[inline]
|
||||
pub fn is_button_up(&self, button: usize) -> bool {
|
||||
matches!(
|
||||
self.buttons[button],
|
||||
ButtonState::Released | ButtonState::Idle
|
||||
)
|
||||
matches!(self.buttons[button], ButtonState::Released | ButtonState::Idle)
|
||||
}
|
||||
|
||||
/// Returns true if the given button was just pressed (not being held down, yet).
|
||||
|
@ -125,13 +119,7 @@ impl InputDevice for Mouse {
|
|||
impl SystemEventHandler for Mouse {
|
||||
fn handle_event(&mut self, event: &SystemEvent) -> bool {
|
||||
match event {
|
||||
SystemEvent::Mouse(MouseEvent::MouseMotion {
|
||||
x,
|
||||
y,
|
||||
x_delta,
|
||||
y_delta,
|
||||
buttons,
|
||||
}) => {
|
||||
SystemEvent::Mouse(MouseEvent::MouseMotion { x, y, x_delta, y_delta, buttons }) => {
|
||||
self.x = *x;
|
||||
self.y = *y;
|
||||
self.x_delta = *x_delta;
|
||||
|
@ -155,4 +143,4 @@ impl SystemEventHandler for Mouse {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,12 +32,10 @@ fn is_x11_compositor_skipping_problematic() -> bool {
|
|||
to check for this.
|
||||
*/
|
||||
match std::env::consts::OS {
|
||||
"linux" | "freebsd" | "netbsd" | "openbsd" => {
|
||||
match std::env::var("XDG_SESSION_DESKTOP") {
|
||||
Ok(value) => value.eq_ignore_ascii_case("KDE"),
|
||||
Err(_) => false
|
||||
}
|
||||
}
|
||||
"linux" | "freebsd" | "netbsd" | "openbsd" => match std::env::var("XDG_SESSION_DESKTOP") {
|
||||
Ok(value) => value.eq_ignore_ascii_case("KDE"),
|
||||
Err(_) => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +138,6 @@ impl SystemBuilder {
|
|||
&self,
|
||||
config: ConfigType,
|
||||
) -> Result<System<ConfigType::SystemResourcesType>, SystemError> {
|
||||
|
||||
sdl2::hint::set("SDL_RENDER_VSYNC", if self.vsync { "1" } else { "0" });
|
||||
sdl2::hint::set("SDL_MOUSE_RELATIVE_SCALING", if self.relative_mouse_scaling { "1" } else { "0" });
|
||||
sdl2::hint::set("SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR", if self.skip_x11_compositor { "1" } else { "0" });
|
||||
|
@ -176,7 +173,7 @@ impl SystemBuilder {
|
|||
// SystemResources initialization
|
||||
|
||||
let mut window_builder = &mut (sdl_video_subsystem.window(
|
||||
self.window_title.as_str(),
|
||||
self.window_title.as_str(), //
|
||||
640,
|
||||
480,
|
||||
));
|
||||
|
@ -190,11 +187,7 @@ impl SystemBuilder {
|
|||
|
||||
sdl_context.mouse().show_cursor(self.show_mouse);
|
||||
|
||||
let system_resources = match config.build(
|
||||
&sdl_video_subsystem,
|
||||
&sdl_audio_subsystem,
|
||||
sdl_window
|
||||
) {
|
||||
let system_resources = match config.build(&sdl_video_subsystem, &sdl_audio_subsystem, sdl_window) {
|
||||
Ok(system_resources) => system_resources,
|
||||
Err(error) => return Err(SystemError::SystemResourcesError(error)),
|
||||
};
|
||||
|
@ -221,7 +214,9 @@ impl SystemBuilder {
|
|||
/// "virtual machine" exposed by this library.
|
||||
#[allow(dead_code)]
|
||||
pub struct System<SystemResType>
|
||||
where SystemResType: SystemResources {
|
||||
where
|
||||
SystemResType: SystemResources,
|
||||
{
|
||||
sdl_context: sdl2::Sdl,
|
||||
sdl_audio_subsystem: sdl2::AudioSubsystem,
|
||||
sdl_video_subsystem: sdl2::VideoSubsystem,
|
||||
|
@ -238,9 +233,11 @@ where SystemResType: SystemResources {
|
|||
}
|
||||
|
||||
impl<SystemResType> std::fmt::Debug for System<SystemResType>
|
||||
where SystemResType: SystemResources {
|
||||
where
|
||||
SystemResType: SystemResources,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("System")
|
||||
f.debug_struct("System") //
|
||||
.field("res", &self.res)
|
||||
.field("vsync", &self.vsync)
|
||||
.field("target_framerate", &self.target_framerate)
|
||||
|
@ -251,7 +248,9 @@ where SystemResType: SystemResources {
|
|||
}
|
||||
|
||||
impl<SystemResType> System<SystemResType>
|
||||
where SystemResType: SystemResources {
|
||||
where
|
||||
SystemResType: SystemResources,
|
||||
{
|
||||
/// Displays the current backbuffer on to the window. If a `target_framerate` is set, this will
|
||||
/// attempt to apply some timing to achieve that framerate. If V-sync is enabled, that will take
|
||||
/// priority instead. You must call this in your application's main loop to display anything on screen.
|
||||
|
|
|
@ -1,22 +1,10 @@
|
|||
pub use crate::system::{
|
||||
*,
|
||||
event::*,
|
||||
event::*, //
|
||||
input_devices::{
|
||||
keyboard::{codes::*, scancodes::*, *},
|
||||
mouse::{buttons::*, cursor::*, *},
|
||||
*,
|
||||
keyboard::{
|
||||
*,
|
||||
codes::*,
|
||||
scancodes::*,
|
||||
},
|
||||
mouse::{
|
||||
*,
|
||||
buttons::*,
|
||||
cursor::*,
|
||||
},
|
||||
},
|
||||
res::{
|
||||
*,
|
||||
// note: we are intentionally not including the `SystemResources` implementation modules here
|
||||
},
|
||||
res::*,
|
||||
*,
|
||||
};
|
||||
|
||||
|
|
|
@ -28,16 +28,16 @@
|
|||
|
||||
use byte_slice_cast::AsByteSlice;
|
||||
|
||||
use crate::audio::{Audio, TARGET_AUDIO_CHANNELS, TARGET_AUDIO_FREQUENCY};
|
||||
use crate::audio::queue::AudioQueue;
|
||||
use crate::graphics::font::BitmaskFont;
|
||||
use crate::audio::{Audio, TARGET_AUDIO_CHANNELS, TARGET_AUDIO_FREQUENCY};
|
||||
use crate::graphics::bitmap::indexed::IndexedBitmap;
|
||||
use crate::graphics::font::BitmaskFont;
|
||||
use crate::graphics::palette::Palette;
|
||||
use crate::system::event::{SystemEvent, SystemEventHandler};
|
||||
use crate::system::input_devices::InputDevice;
|
||||
use crate::system::input_devices::keyboard::Keyboard;
|
||||
use crate::system::input_devices::mouse::cursor::CustomMouseCursor;
|
||||
use crate::system::input_devices::mouse::Mouse;
|
||||
use crate::system::input_devices::InputDevice;
|
||||
use crate::system::res::{SystemResources, SystemResourcesConfig, SystemResourcesError};
|
||||
|
||||
const DEFAULT_SCREEN_WIDTH: u32 = 320;
|
||||
|
@ -113,7 +113,7 @@ impl SystemResourcesConfig for DosLikeConfig {
|
|||
sdl2::sys::SDL_RenderSetIntegerScale(
|
||||
sdl_canvas.raw(),
|
||||
if self.integer_scaling {
|
||||
sdl2::sys::SDL_bool::SDL_TRUE
|
||||
sdl2::sys::SDL_bool::SDL_TRUE //
|
||||
} else {
|
||||
sdl2::sys::SDL_bool::SDL_FALSE
|
||||
},
|
||||
|
@ -193,7 +193,7 @@ impl SystemResourcesConfig for DosLikeConfig {
|
|||
keyboard,
|
||||
mouse,
|
||||
cursor,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,17 +240,17 @@ pub struct DosLike {
|
|||
}
|
||||
|
||||
impl std::fmt::Debug for DosLike {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DosLike")
|
||||
.field("audio", &self.audio)
|
||||
.field("audio_queue", &self.audio_queue)
|
||||
.field("palette", &self.palette)
|
||||
.field("video", &self.video)
|
||||
.field("font", &self.font)
|
||||
.field("keyboard", &self.keyboard)
|
||||
.field("mouse", &self.mouse)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DosLike") //
|
||||
.field("audio", &self.audio)
|
||||
.field("audio_queue", &self.audio_queue)
|
||||
.field("palette", &self.palette)
|
||||
.field("video", &self.video)
|
||||
.field("font", &self.font)
|
||||
.field("keyboard", &self.keyboard)
|
||||
.field("mouse", &self.mouse)
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemResources for DosLike {
|
||||
|
@ -259,33 +259,33 @@ impl SystemResources for DosLike {
|
|||
|
||||
match self.audio_queue.apply(&mut self.audio) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(error) => Err(SystemResourcesError::AudioDeviceError(error))
|
||||
Err(error) => Err(SystemResourcesError::AudioDeviceError(error)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes the `video` backbuffer bitmap and `palette` and renders it to the window, up-scaled
|
||||
/// to fill the window (preserving aspect ratio of course).
|
||||
fn display(&mut self) -> Result<(), SystemResourcesError> {
|
||||
self.cursor.render(&mut self.video);
|
||||
self.cursor.render(&mut self.video);
|
||||
|
||||
// convert application framebuffer to 32-bit RGBA pixels, and then upload it to the SDL
|
||||
// texture so it will be displayed on screen
|
||||
// convert application framebuffer to 32-bit RGBA pixels, and then upload it to the SDL
|
||||
// texture so it will be displayed on screen
|
||||
|
||||
self.video.copy_as_argb_to(&mut self.texture_pixels, &self.palette);
|
||||
self.video.copy_as_argb_to(&mut self.texture_pixels, &self.palette);
|
||||
|
||||
let texture_pixels = self.texture_pixels.as_byte_slice();
|
||||
if let Err(error) = self.sdl_texture.update(None, texture_pixels, self.sdl_texture_pitch) {
|
||||
return Err(SystemResourcesError::SDLError(error.to_string()));
|
||||
}
|
||||
self.sdl_canvas.clear();
|
||||
if let Err(error) = self.sdl_canvas.copy(&self.sdl_texture, None, None) {
|
||||
return Err(SystemResourcesError::SDLError(error));
|
||||
}
|
||||
self.sdl_canvas.present();
|
||||
let texture_pixels = self.texture_pixels.as_byte_slice();
|
||||
if let Err(error) = self.sdl_texture.update(None, texture_pixels, self.sdl_texture_pitch) {
|
||||
return Err(SystemResourcesError::SDLError(error.to_string()));
|
||||
}
|
||||
self.sdl_canvas.clear();
|
||||
if let Err(error) = self.sdl_canvas.copy(&self.sdl_texture, None, None) {
|
||||
return Err(SystemResourcesError::SDLError(error));
|
||||
}
|
||||
self.sdl_canvas.present();
|
||||
|
||||
self.cursor.hide(&mut self.video);
|
||||
self.cursor.hide(&mut self.video);
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_event_state(&mut self) -> Result<(), SystemResourcesError> {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::audio::AudioError;
|
||||
use crate::audio::device::AudioDeviceError;
|
||||
use crate::audio::AudioError;
|
||||
use crate::system::event::SystemEvent;
|
||||
|
||||
pub mod dos_like;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use byte_slice_cast::AsByteSlice;
|
||||
|
||||
use crate::audio::{Audio, TARGET_AUDIO_CHANNELS, TARGET_AUDIO_FREQUENCY};
|
||||
use crate::audio::queue::AudioQueue;
|
||||
use crate::audio::{Audio, TARGET_AUDIO_CHANNELS, TARGET_AUDIO_FREQUENCY};
|
||||
use crate::graphics::bitmap::rgb::RgbaBitmap;
|
||||
use crate::graphics::font::BitmaskFont;
|
||||
use crate::system::event::{SystemEvent, SystemEventHandler};
|
||||
use crate::system::input_devices::InputDevice;
|
||||
use crate::system::input_devices::keyboard::Keyboard;
|
||||
use crate::system::input_devices::mouse::cursor::CustomMouseCursor;
|
||||
use crate::system::input_devices::mouse::Mouse;
|
||||
use crate::system::input_devices::InputDevice;
|
||||
use crate::system::res::{SystemResources, SystemResourcesConfig, SystemResourcesError};
|
||||
|
||||
const DEFAULT_SCREEN_WIDTH: u32 = 320;
|
||||
|
@ -57,7 +57,7 @@ impl SystemResourcesConfig for StandardConfig {
|
|||
self,
|
||||
_video_subsystem: &sdl2::VideoSubsystem,
|
||||
audio_subsystem: &sdl2::AudioSubsystem,
|
||||
mut window: sdl2::video::Window
|
||||
mut window: sdl2::video::Window,
|
||||
) -> Result<Self::SystemResourcesType, SystemResourcesError> {
|
||||
let texture_pixel_size = 4; // 32-bit ARGB format
|
||||
|
||||
|
@ -83,7 +83,7 @@ impl SystemResourcesConfig for StandardConfig {
|
|||
sdl2::sys::SDL_RenderSetIntegerScale(
|
||||
sdl_canvas.raw(),
|
||||
if self.integer_scaling {
|
||||
sdl2::sys::SDL_bool::SDL_TRUE
|
||||
sdl2::sys::SDL_bool::SDL_TRUE //
|
||||
} else {
|
||||
sdl2::sys::SDL_bool::SDL_FALSE
|
||||
},
|
||||
|
@ -147,7 +147,6 @@ impl SystemResourcesConfig for StandardConfig {
|
|||
mouse,
|
||||
cursor,
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +187,7 @@ pub struct Standard {
|
|||
|
||||
impl std::fmt::Debug for Standard {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Standard")
|
||||
f.debug_struct("Standard") //
|
||||
.field("audio", &self.audio)
|
||||
.field("audio_queue", &self.audio_queue)
|
||||
.field("video", &self.video)
|
||||
|
@ -205,7 +204,7 @@ impl SystemResources for Standard {
|
|||
|
||||
match self.audio_queue.apply(&mut self.audio) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(error) => Err(SystemResourcesError::AudioDeviceError(error))
|
||||
Err(error) => Err(SystemResourcesError::AudioDeviceError(error)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,4 +19,4 @@ impl<T: std::io::Read + std::io::Seek> StreamSize for T {
|
|||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,11 +199,7 @@ impl LzwBytesWriter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_code<T: WriteBytesExt>(
|
||||
&mut self,
|
||||
writer: &mut T,
|
||||
code: LzwCode,
|
||||
) -> Result<(), LzwError> {
|
||||
pub fn write_code<T: WriteBytesExt>(&mut self, writer: &mut T, code: LzwCode) -> Result<(), LzwError> {
|
||||
self.packer.push_code(code)?;
|
||||
|
||||
while let Some(byte) = self.packer.take_byte() {
|
||||
|
@ -345,10 +341,7 @@ impl LzwBytesReader {
|
|||
Ok(Some(reader.read_u8()?))
|
||||
}
|
||||
|
||||
pub fn read_code<T: ReadBytesExt>(
|
||||
&mut self,
|
||||
reader: &mut T,
|
||||
) -> Result<Option<LzwCode>, LzwError> {
|
||||
pub fn read_code<T: ReadBytesExt>(&mut self, reader: &mut T) -> Result<Option<LzwCode>, LzwError> {
|
||||
loop {
|
||||
if let Some(code) = self.unpacker.take_code() {
|
||||
return Ok(Some(code));
|
||||
|
@ -368,14 +361,10 @@ impl LzwBytesReader {
|
|||
|
||||
/// Encodes data read from the `src` using LZW (GIF-variant) compression, writing the encoded
|
||||
/// data out to `dest`. The LZW minimum code bit size is specified via `min_code_size`.
|
||||
pub fn lzw_encode<S, D>(
|
||||
src: &mut S,
|
||||
dest: &mut D,
|
||||
min_code_size: usize,
|
||||
) -> Result<(), LzwError>
|
||||
where
|
||||
S: ReadBytesExt,
|
||||
D: WriteBytesExt
|
||||
pub fn lzw_encode<S, D>(src: &mut S, dest: &mut D, min_code_size: usize) -> Result<(), LzwError>
|
||||
where
|
||||
S: ReadBytesExt,
|
||||
D: WriteBytesExt,
|
||||
{
|
||||
if !is_valid_gif_min_code_size_bits(min_code_size) {
|
||||
return Err(LzwError::UnsupportedCodeSizeBits(min_code_size));
|
||||
|
@ -414,7 +403,7 @@ pub fn lzw_encode<S, D>(
|
|||
writer.flush(dest)?;
|
||||
return Ok(());
|
||||
}
|
||||
Err(error) => return Err(LzwError::IOError(error))
|
||||
Err(error) => return Err(LzwError::IOError(error)),
|
||||
};
|
||||
|
||||
let mut buffer = vec![byte];
|
||||
|
@ -424,7 +413,7 @@ pub fn lzw_encode<S, D>(
|
|||
let byte = match src.read_u8() {
|
||||
Ok(byte) => byte,
|
||||
Err(ref error) if error.kind() == std::io::ErrorKind::UnexpectedEof => break,
|
||||
Err(error) => return Err(LzwError::IOError(error))
|
||||
Err(error) => return Err(LzwError::IOError(error)),
|
||||
};
|
||||
|
||||
// check if the table currently contains a string composed of the current buffer plus
|
||||
|
@ -447,7 +436,10 @@ pub fn lzw_encode<S, D>(
|
|||
if let Some(code) = table.get(&buffer) {
|
||||
writer.write_code(dest, *code)?;
|
||||
} else {
|
||||
return Err(LzwError::EncodingError(format!("Expected to find code in table for buffer {:?} but none was found", buffer)));
|
||||
return Err(LzwError::EncodingError(format!(
|
||||
"Expected to find code in table for buffer {:?} but none was found",
|
||||
buffer
|
||||
)));
|
||||
}
|
||||
|
||||
// bump up to the next bit size once we've seen enough codes to necessitate it ...
|
||||
|
@ -485,7 +477,10 @@ pub fn lzw_encode<S, D>(
|
|||
if let Some(code) = table.get(&buffer) {
|
||||
writer.write_code(dest, *code)?;
|
||||
} else {
|
||||
return Err(LzwError::EncodingError(format!("No matching code for buffer {:?} at end of input stream", buffer)));
|
||||
return Err(LzwError::EncodingError(format!(
|
||||
"No matching code for buffer {:?} at end of input stream",
|
||||
buffer
|
||||
)));
|
||||
}
|
||||
|
||||
writer.write_code(dest, end_of_info_code)?;
|
||||
|
@ -496,13 +491,10 @@ pub fn lzw_encode<S, D>(
|
|||
|
||||
/// Decodes data read from the `src` using LZW (GIF-variant) decompression, writing the decoded
|
||||
/// data out to `dest`.
|
||||
pub fn lzw_decode<S, D>(
|
||||
src: &mut S,
|
||||
dest: &mut D,
|
||||
) -> Result<(), LzwError>
|
||||
where
|
||||
S: ReadBytesExt,
|
||||
D: WriteBytesExt
|
||||
pub fn lzw_decode<S, D>(src: &mut S, dest: &mut D) -> Result<(), LzwError>
|
||||
where
|
||||
S: ReadBytesExt,
|
||||
D: WriteBytesExt,
|
||||
{
|
||||
let min_code_size = src.read_u8()? as usize;
|
||||
|
||||
|
@ -525,7 +517,7 @@ pub fn lzw_decode<S, D>(
|
|||
// are no codes to read (kind of a weird situation, but no real reason to error ...?)
|
||||
let mut code = match reader.read_code(src)? {
|
||||
Some(code) => code,
|
||||
None => return Ok(())
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
// the first code in the stream SHOULD be a clear code ... which we can just ignore because
|
||||
|
@ -553,7 +545,9 @@ pub fn lzw_decode<S, D>(
|
|||
|
||||
// read the next code which should actually be the first "interesting" value of the code stream
|
||||
code = match reader.read_code(src)? {
|
||||
Some(code) if code > MAX_CODE_VALUE => return Err(LzwError::EncodingError(format!("Encountered code that is too large: {}", code))),
|
||||
Some(code) if code > MAX_CODE_VALUE => {
|
||||
return Err(LzwError::EncodingError(format!("Encountered code that is too large: {}", code)))
|
||||
}
|
||||
Some(code) if code == end_of_info_code => return Ok(()),
|
||||
Some(code) => code,
|
||||
None => return Err(LzwError::EncodingError(String::from("Unexpected end of code stream"))),
|
||||
|
@ -573,7 +567,9 @@ pub fn lzw_decode<S, D>(
|
|||
'inner: loop {
|
||||
// grab the next code
|
||||
code = match reader.read_code(src)? {
|
||||
Some(code) if code > MAX_CODE_VALUE => return Err(LzwError::EncodingError(format!("Encountered code that is too large: {}", code))),
|
||||
Some(code) if code > MAX_CODE_VALUE => {
|
||||
return Err(LzwError::EncodingError(format!("Encountered code that is too large: {}", code)))
|
||||
}
|
||||
Some(code) if code == end_of_info_code => break 'outer,
|
||||
Some(code) if code == clear_code => {
|
||||
// reset the bit size and reader and then loop back to the outer loop which
|
||||
|
@ -645,19 +641,35 @@ mod tests {
|
|||
static LZW_TEST_DATA: &[LzwTestData] = &[
|
||||
LzwTestData {
|
||||
min_code_size: 2,
|
||||
packed: &[0x02, 0x16, 0x8c, 0x2d, 0x99, 0x87, 0x2a, 0x1c, 0xdc, 0x33, 0xa0, 0x02, 0x75, 0xec, 0x95, 0xfa, 0xa8, 0xde, 0x60, 0x8c, 0x04, 0x91, 0x4c, 0x01, 0x00],
|
||||
unpacked: &[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1],
|
||||
packed: &[
|
||||
0x02, 0x16, 0x8c, 0x2d, 0x99, 0x87, 0x2a, 0x1c, 0xdc, 0x33, 0xa0, 0x02, 0x75, 0xec, 0x95, 0xfa, 0xa8,
|
||||
0xde, 0x60, 0x8c, 0x04, 0x91, 0x4c, 0x01, 0x00,
|
||||
],
|
||||
unpacked: &[
|
||||
1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 0,
|
||||
0, 0, 0, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 1,
|
||||
1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
|
||||
],
|
||||
},
|
||||
LzwTestData {
|
||||
min_code_size: 4,
|
||||
packed: &[0x04, 0x21, 0x70, 0x49, 0x79, 0x6a, 0x9d, 0xcb, 0x39, 0x7b, 0xa6, 0xd6, 0x96, 0xa4, 0x3d, 0x0f, 0xd8, 0x8d, 0x64, 0xb9, 0x1d, 0x28, 0xa9, 0x2d, 0x15, 0xfa, 0xc2, 0xf1, 0x37, 0x71, 0x33, 0xc5, 0x61, 0x4b, 0x04, 0x00],
|
||||
unpacked: &[11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 11, 11, 11, 11, 14, 14, 7, 7, 7, 7, 11, 11, 11, 14, 14, 14, 14, 7, 7, 7, 11, 11, 14, 14, 15, 15, 14, 14, 7, 7, 11, 14, 14, 15, 15, 15, 15, 14, 14, 7, 7, 14, 14, 15, 15, 15, 15, 14, 14, 11, 7, 7, 14, 14, 15, 15, 14, 14, 11, 11, 7, 7, 7, 14, 14, 14, 14, 11, 11, 11, 7, 7, 7, 7, 14, 14, 11, 11, 11, 11, 7, 7, 7, 7, 7, 11, 11, 11, 11, 11],
|
||||
packed: &[
|
||||
0x04, 0x21, 0x70, 0x49, 0x79, 0x6a, 0x9d, 0xcb, 0x39, 0x7b, 0xa6, 0xd6, 0x96, 0xa4, 0x3d, 0x0f, 0xd8,
|
||||
0x8d, 0x64, 0xb9, 0x1d, 0x28, 0xa9, 0x2d, 0x15, 0xfa, 0xc2, 0xf1, 0x37, 0x71, 0x33, 0xc5, 0x61, 0x4b,
|
||||
0x04, 0x00,
|
||||
],
|
||||
unpacked: &[
|
||||
11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 11, 11, 11, 11, 14, 14, 7, 7, 7, 7, 11, 11, 11, 14, 14, 14, 14, 7,
|
||||
7, 7, 11, 11, 14, 14, 15, 15, 14, 14, 7, 7, 11, 14, 14, 15, 15, 15, 15, 14, 14, 7, 7, 14, 14, 15, 15,
|
||||
15, 15, 14, 14, 11, 7, 7, 14, 14, 15, 15, 14, 14, 11, 11, 7, 7, 7, 14, 14, 14, 14, 11, 11, 11, 7, 7, 7,
|
||||
7, 14, 14, 11, 11, 11, 11, 7, 7, 7, 7, 7, 11, 11, 11, 11, 11,
|
||||
],
|
||||
},
|
||||
LzwTestData {
|
||||
min_code_size: 8,
|
||||
packed: &[0x08, 0x0b, 0x00, 0x51, 0xfc, 0x1b, 0x28, 0x70, 0xa0, 0xc1, 0x83, 0x01, 0x01, 0x00],
|
||||
unpacked: &[0x28, 0xff, 0xff, 0xff, 0x28, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -39,4 +39,4 @@ impl<A: Any> AsAny for A {
|
|||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self as &mut dyn Any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@ enum PackMode {
|
|||
}
|
||||
|
||||
pub fn pack_bits<S, D>(src: &mut S, dest: &mut D, src_length: usize) -> Result<(), PackBitsError>
|
||||
where
|
||||
S: ReadBytesExt,
|
||||
D: WriteBytesExt,
|
||||
where
|
||||
S: ReadBytesExt,
|
||||
D: WriteBytesExt,
|
||||
{
|
||||
const MIN_RUN: usize = 3;
|
||||
const MAX_RUN: usize = 128;
|
||||
|
@ -112,14 +112,10 @@ pub fn pack_bits<S, D>(src: &mut S, dest: &mut D, src_length: usize) -> Result<(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unpack_bits<S, D>(
|
||||
src: &mut S,
|
||||
dest: &mut D,
|
||||
unpacked_length: usize,
|
||||
) -> Result<(), PackBitsError>
|
||||
where
|
||||
S: ReadBytesExt,
|
||||
D: WriteBytesExt,
|
||||
pub fn unpack_bits<S, D>(src: &mut S, dest: &mut D, unpacked_length: usize) -> Result<(), PackBitsError>
|
||||
where
|
||||
S: ReadBytesExt,
|
||||
D: WriteBytesExt,
|
||||
{
|
||||
let mut buffer = [0u8; 128];
|
||||
let mut bytes_written = 0;
|
||||
|
@ -165,23 +161,14 @@ mod tests {
|
|||
|
||||
static TEST_DATA: &[TestData] = &[
|
||||
TestData {
|
||||
packed: &[
|
||||
0xfe, 0xaa, 0x02, 0x80, 0x00, 0x2a, 0xfd, 0xaa, 0x03, 0x80, 0x00, 0x2a, 0x22, 0xf7,
|
||||
0xaa,
|
||||
],
|
||||
packed: &[0xfe, 0xaa, 0x02, 0x80, 0x00, 0x2a, 0xfd, 0xaa, 0x03, 0x80, 0x00, 0x2a, 0x22, 0xf7, 0xaa],
|
||||
unpacked: &[
|
||||
0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x2a, 0x22,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x2a, 0x22, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
],
|
||||
},
|
||||
TestData {
|
||||
packed: &[0x00, 0xaa],
|
||||
unpacked: &[0xaa],
|
||||
},
|
||||
TestData {
|
||||
packed: &[0xf9, 0xaa],
|
||||
unpacked: &[0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa],
|
||||
},
|
||||
TestData { packed: &[0x00, 0xaa], unpacked: &[0xaa] },
|
||||
TestData { packed: &[0xf9, 0xaa], unpacked: &[0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa] },
|
||||
TestData {
|
||||
packed: &[0xf9, 0xaa, 0x00, 0xbb],
|
||||
unpacked: &[0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb],
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
pub use crate::utils::{
|
||||
*,
|
||||
//
|
||||
bytes::*,
|
||||
io::*,
|
||||
lzwgif::*,
|
||||
packbits::*,
|
||||
*,
|
||||
};
|
||||
|
||||
|
|
|
@ -170,7 +170,6 @@ fn blended_pixel_drawing() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn horiz_line_drawing() {
|
||||
let (mut screen, palette) = setup();
|
||||
|
@ -752,6 +751,7 @@ fn solid_flipped_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn blended_solid_flipped_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -884,6 +884,7 @@ fn solid_offset_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn solid_flipped_offset_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1090,6 +1091,7 @@ fn blended_transparent_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn transparent_flipped_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1156,6 +1158,7 @@ fn transparent_flipped_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn blended_transparent_flipped_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1292,6 +1295,7 @@ fn transparent_offset_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn transparent_flipped_offset_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1432,6 +1436,7 @@ fn transparent_single_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn transparent_flipped_single_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1568,6 +1573,7 @@ fn rotozoom_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn blended_rotozoom_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1634,6 +1640,7 @@ fn blended_rotozoom_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn rotozoom_offset_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1702,6 +1709,7 @@ fn rotozoom_offset_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn rotozoom_transparent_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1770,6 +1778,7 @@ fn rotozoom_transparent_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn blended_rotozoom_transparent_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
@ -1799,7 +1808,13 @@ fn blended_rotozoom_transparent_blits() {
|
|||
|
||||
//////
|
||||
|
||||
let method = RotoZoomTransparentBlended { transparent_color, angle: 1.3, scale_x: 1.0, scale_y: 1.0, blend_map: blend_map.clone() };
|
||||
let method = RotoZoomTransparentBlended {
|
||||
transparent_color,
|
||||
angle: 1.3,
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
blend_map: blend_map.clone(),
|
||||
};
|
||||
|
||||
screen.blit(method.clone(), &bmp, -3, 46);
|
||||
screen.blit(method.clone(), &bmp, -4, 76);
|
||||
|
@ -1838,6 +1853,7 @@ fn blended_rotozoom_transparent_blits() {
|
|||
assert!(verify_visual(&screen, &palette, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn rotozoom_transparent_offset_blits() {
|
||||
use IndexedBlitMethod::*;
|
||||
|
|
|
@ -602,7 +602,7 @@ fn generate_bitmap_with_varied_alpha(width: i32, height: i32) -> RgbaBitmap {
|
|||
let y_third = height / 3;
|
||||
|
||||
let mut bitmap = RgbaBitmap::new(width as u32, height as u32).unwrap();
|
||||
bitmap.clear(0); // alpha=0
|
||||
bitmap.clear(0); // alpha=0
|
||||
|
||||
bitmap.filled_rect(0, 0, x_third, y_third, 0x330000aa);
|
||||
bitmap.filled_rect(x_third * 2 + 1, y_third * 2 + 1, width - 1, height - 1, 0x6600aa00);
|
||||
|
@ -901,6 +901,7 @@ fn solid_flipped_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn solid_flipped_tinted_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -967,6 +968,7 @@ fn solid_flipped_tinted_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn blended_solid_flipped_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1113,10 +1115,7 @@ fn transparent_tinted_blits() {
|
|||
let bmp21 = generate_bitmap(21, 21);
|
||||
let bmp3 = generate_bitmap(3, 3);
|
||||
|
||||
let method = TransparentTinted {
|
||||
transparent_color: to_rgb32(0, 0, 0),
|
||||
tint_color: to_argb32(127, 155, 242, 21)
|
||||
};
|
||||
let method = TransparentTinted { transparent_color: to_rgb32(0, 0, 0), tint_color: to_argb32(127, 155, 242, 21) };
|
||||
|
||||
let x = 40;
|
||||
let y = 20;
|
||||
|
@ -1241,6 +1240,7 @@ fn blended_transparent_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn transparent_flipped_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1307,6 +1307,7 @@ fn transparent_flipped_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn transparent_flipped_tinted_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1374,6 +1375,7 @@ fn transparent_flipped_tinted_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn blended_transparent_flipped_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1440,6 +1442,7 @@ fn blended_transparent_flipped_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn transparent_single_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1510,6 +1513,7 @@ fn transparent_single_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn transparent_flipped_single_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1642,6 +1646,7 @@ fn rotozoom_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn rotozoom_tinted_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1777,6 +1782,7 @@ fn blended_rotozoom_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn rotozoom_transparent_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1845,6 +1851,7 @@ fn rotozoom_transparent_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn rotozoom_transparent_tinted_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
@ -1914,6 +1921,7 @@ fn rotozoom_transparent_tinted_blits() {
|
|||
assert!(verify_visual(&screen, &path), "bitmap differs from source image: {:?}", path);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[test]
|
||||
fn blended_rotozoom_transparent_blits() {
|
||||
use RgbaBlitMethod::*;
|
||||
|
|
Loading…
Reference in a new issue