fake fog, better parallelisation
This commit is contained in:
Generated
+10
-10
@@ -2761,9 +2761,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.13"
|
version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72"
|
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
@@ -2773,7 +2773,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.11",
|
"redox_syscall 0.5.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3461,7 +3461,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.11",
|
"redox_syscall 0.5.12",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
@@ -3876,9 +3876,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.11"
|
version = "0.5.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
]
|
]
|
||||||
@@ -4011,9 +4011,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruzstd"
|
name = "ruzstd"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c581601827da5c717bfae77d7b187e54293d23d8fb6b700b4b5e9b5828a13cc3"
|
checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"twox-hash",
|
"twox-hash",
|
||||||
]
|
]
|
||||||
@@ -5404,9 +5404,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.9"
|
version = "0.7.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3"
|
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|||||||
+4
-2
@@ -1,6 +1,8 @@
|
|||||||
use bevy::input::keyboard::KeyCode;
|
use bevy::input::keyboard::KeyCode;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::constants::TILE_SIZE;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct PanningCamera {
|
pub struct PanningCamera {
|
||||||
pub pan_speed: f32,
|
pub pan_speed: f32,
|
||||||
@@ -39,7 +41,7 @@ pub fn camera_movement(
|
|||||||
pub fn spawn_panning_camera(mut commands: Commands) {
|
pub fn spawn_panning_camera(mut commands: Commands) {
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Camera2d,
|
Camera2d,
|
||||||
Transform::from_xyz(0., 0., 10.),
|
Transform::from_xyz(0., 0., 10. * TILE_SIZE),
|
||||||
PanningCamera { pan_speed: 5.0 },
|
PanningCamera { pan_speed: 15.0 },
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
+81
-52
@@ -17,10 +17,12 @@ impl Citizen {
|
|||||||
pub fn new(asset_server: &Res<AssetServer>, position: Vec3) -> Self {
|
pub fn new(asset_server: &Res<AssetServer>, position: Vec3) -> Self {
|
||||||
Citizen {
|
Citizen {
|
||||||
ambulatory: Ambulatory {
|
ambulatory: Ambulatory {
|
||||||
speed: TILE_SIZE,
|
walk_speed: 2.,
|
||||||
|
run_speed: 6.,
|
||||||
target: None,
|
target: None,
|
||||||
current_path: None,
|
current_path: None,
|
||||||
path_index: 0,
|
path_index: 0,
|
||||||
|
step_recovery: 0,
|
||||||
},
|
},
|
||||||
sprite: Sprite {
|
sprite: Sprite {
|
||||||
image: asset_server.load("dorf.png"),
|
image: asset_server.load("dorf.png"),
|
||||||
@@ -42,10 +44,12 @@ use std::{
|
|||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Ambulatory {
|
pub struct Ambulatory {
|
||||||
pub speed: f32,
|
pub walk_speed: f32,
|
||||||
|
pub run_speed: f32,
|
||||||
pub current_path: Option<Vec<Vec3>>,
|
pub current_path: Option<Vec<Vec3>>,
|
||||||
pub path_index: usize,
|
pub path_index: usize,
|
||||||
pub target: Option<Vec3>,
|
pub target: Option<Vec3>,
|
||||||
|
pub step_recovery: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
@@ -131,65 +135,92 @@ pub fn update_citizen_wandering_targets(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn citizen_movement(
|
pub fn citizen_movement(
|
||||||
mut query: Query<(&mut Ambulatory, &mut Transform, &mut Visibility)>,
|
mut query: Query<(
|
||||||
|
&mut Ambulatory,
|
||||||
|
&mut Transform,
|
||||||
|
&mut Visibility,
|
||||||
|
&mut Sprite,
|
||||||
|
)>,
|
||||||
tilemap: Res<TileMap>,
|
tilemap: Res<TileMap>,
|
||||||
z_index: Res<game::ZIndex>,
|
z_index: Res<game::ZIndex>,
|
||||||
) {
|
) {
|
||||||
for (mut ambulatory, mut transform, mut visibility) in query.iter_mut() {
|
query.par_iter_mut().for_each(
|
||||||
let current_pos = transform.translation;
|
|(mut ambulatory, mut transform, mut visibility, mut sprite)| {
|
||||||
let below_pos = Vec3::new(
|
let current_pos = transform.translation;
|
||||||
current_pos.x,
|
let below_pos = Vec3::new(
|
||||||
current_pos.y,
|
current_pos.x,
|
||||||
current_pos.z - TILE_SIZE - 0.1,
|
current_pos.y,
|
||||||
);
|
current_pos.z - TILE_SIZE - 0.1,
|
||||||
|
);
|
||||||
|
|
||||||
if !is_standable_tile(&tilemap, current_pos.as_ivec3()) {
|
if !is_standable_tile(&tilemap, current_pos.as_ivec3()) {
|
||||||
transform.translation = below_pos + Vec3::new(0.0, 0.0, 0.1);
|
transform.translation = below_pos + Vec3::new(0.0, 0.0, 0.1);
|
||||||
continue;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(target) = ambulatory.target {
|
|
||||||
// Calculate path if needed
|
|
||||||
if ambulatory.current_path.is_none() {
|
|
||||||
ambulatory.current_path = Some(calculate_path(
|
|
||||||
&tilemap,
|
|
||||||
transform.translation.as_ivec3(),
|
|
||||||
target.as_ivec3() - ivec3(0, 0, 1),
|
|
||||||
));
|
|
||||||
ambulatory.path_index = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Follow the current path
|
if let Some(target) = ambulatory.target {
|
||||||
if let Some(path) = &ambulatory.current_path {
|
// Calculate path if needed
|
||||||
if ambulatory.path_index < path.len() {
|
if ambulatory.current_path.is_none() {
|
||||||
let next_point = path[ambulatory.path_index];
|
ambulatory.current_path = Some(calculate_path(
|
||||||
|
&tilemap,
|
||||||
let direction = (next_point - transform.translation).normalize();
|
transform.translation.as_ivec3(),
|
||||||
transform.translation = next_point;
|
target.as_ivec3() - ivec3(0, 0, 1),
|
||||||
|
));
|
||||||
// Update sprite direction (only for x movement)
|
ambulatory.path_index = 0;
|
||||||
if direction.x > 0.0 {
|
}
|
||||||
transform.scale.x = PIXEL_RATIO;
|
if ambulatory.walk_speed > 0. {
|
||||||
} else if direction.x < 0.0 {
|
if ambulatory.step_recovery <= ambulatory.walk_speed as u32 {
|
||||||
transform.scale.x = -PIXEL_RATIO;
|
ambulatory.step_recovery += 1;
|
||||||
}
|
return;
|
||||||
if transform.translation.z.round() / TILE_SIZE <= z_index.0 + 1.0 {
|
|
||||||
*visibility = Visibility::Visible;
|
|
||||||
} else {
|
} else {
|
||||||
*visibility = Visibility::Hidden;
|
ambulatory.step_recovery = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we've reached the next point
|
// Follow the current path
|
||||||
if transform.translation.distance(next_point) < ambulatory.speed {
|
if let Some(path) = &ambulatory.current_path {
|
||||||
ambulatory.path_index += 1;
|
if ambulatory.path_index < path.len() {
|
||||||
|
let next_point = path[ambulatory.path_index];
|
||||||
|
|
||||||
|
let direction = (next_point - transform.translation).normalize();
|
||||||
|
transform.translation = next_point;
|
||||||
|
|
||||||
|
// Update sprite direction (only for x movement)
|
||||||
|
if direction.x > 0.0 {
|
||||||
|
transform.scale.x = PIXEL_RATIO;
|
||||||
|
} else if direction.x < 0.0 {
|
||||||
|
transform.scale.x = -PIXEL_RATIO;
|
||||||
|
}
|
||||||
|
if (z_index.0 - transform.translation.z / TILE_SIZE) / 8.0 > 1.0 {
|
||||||
|
*visibility = Visibility::Hidden;
|
||||||
|
} else {
|
||||||
|
if transform.translation.z / TILE_SIZE <= z_index.0 + 1.0 {
|
||||||
|
*visibility = Visibility::Visible;
|
||||||
|
let saturation =
|
||||||
|
((z_index.0 - transform.translation.z / TILE_SIZE) / 8.0)
|
||||||
|
.clamp(0.0, 1.0);
|
||||||
|
|
||||||
|
sprite.color =
|
||||||
|
Color::hsv(194.7, saturation, 1.0 - (saturation / 2.0));
|
||||||
|
|
||||||
|
sprite.color.set_alpha(1.0 - saturation);
|
||||||
|
} else {
|
||||||
|
*visibility = Visibility::Hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we've reached the next point
|
||||||
|
if transform.translation.distance(next_point) < TILE_SIZE {
|
||||||
|
ambulatory.path_index += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ambulatory.current_path = None;
|
||||||
|
ambulatory.target = None;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ambulatory.current_path = None;
|
|
||||||
ambulatory.target = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_standable_tile(tilemap: &TileMap, pos: IVec3) -> bool {
|
fn is_standable_tile(tilemap: &TileMap, pos: IVec3) -> bool {
|
||||||
@@ -370,12 +401,10 @@ fn reconstruct_path(came_from: HashMap<IVec3, IVec3>, mut current: IVec3) -> Vec
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_citizens(mut commands: Commands, asset_server: Res<AssetServer>) {
|
pub fn spawn_citizens(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
println!("spawning citizens");
|
|
||||||
|
|
||||||
let mut rng = rand::rng();
|
let mut rng = rand::rng();
|
||||||
|
|
||||||
// Spawn a handful of citizens
|
// Spawn a handful of citizens
|
||||||
for _ in 0..10 {
|
for _ in 0..100 {
|
||||||
let x: f32 = rng.random_range(-8.0..8.0);
|
let x: f32 = rng.random_range(-8.0..8.0);
|
||||||
let y: f32 = rng.random_range(-8.0..8.0);
|
let y: f32 = rng.random_range(-8.0..8.0);
|
||||||
let mut position = Vec3::new(x.round(), y.round(), 30.0) * TILE_SIZE;
|
let mut position = Vec3::new(x.round(), y.round(), 30.0) * TILE_SIZE;
|
||||||
|
|||||||
+13
-7
@@ -1,3 +1,5 @@
|
|||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::constants::{ITILE_SIZE, TILE_SIZE};
|
use crate::constants::{ITILE_SIZE, TILE_SIZE};
|
||||||
use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileMap};
|
use crate::tile::{FixtureTile, FloorTile, NeedsOccluded, TileMap};
|
||||||
use crate::tiles::{
|
use crate::tiles::{
|
||||||
@@ -9,7 +11,7 @@ use noise::{NoiseFn, Perlin};
|
|||||||
|
|
||||||
pub const CHUNK_SIZE: i32 = 8;
|
pub const CHUNK_SIZE: i32 = 8;
|
||||||
|
|
||||||
pub const Z_BELOW: f32 = 10.0;
|
pub const Z_BELOW: f32 = 3.0;
|
||||||
pub const Z_ABOVE: f32 = 5.0;
|
pub const Z_ABOVE: f32 = 5.0;
|
||||||
pub const Z_TOTAL: f32 = Z_ABOVE + Z_BELOW; // MAX 255 DO NOT EXCEED
|
pub const Z_TOTAL: f32 = Z_ABOVE + Z_BELOW; // MAX 255 DO NOT EXCEED
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ pub fn handle_tile_occlusion_updates(
|
|||||||
)>,
|
)>,
|
||||||
mut cwss: ResMut<CurrentWorldSpriteState>,
|
mut cwss: ResMut<CurrentWorldSpriteState>,
|
||||||
) {
|
) {
|
||||||
println!("updating tile occlusion");
|
let start = Instant::now();
|
||||||
query_set
|
query_set
|
||||||
.p0()
|
.p0()
|
||||||
.par_iter_mut()
|
.par_iter_mut()
|
||||||
@@ -77,6 +79,7 @@ pub fn handle_tile_occlusion_updates(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cwss.state = TerrainSpriteState::WaitingForRender;
|
cwss.state = TerrainSpriteState::WaitingForRender;
|
||||||
|
println!("Tile occlusion updated in {:.2?}", start.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
pub fn calculate_visibility(pos: IVec3, tilemap: &TileMap) -> [u32; 8] {
|
||||||
@@ -159,10 +162,11 @@ fn generate_chunks_from_algo(
|
|||||||
mut chunk_map: ResMut<ChunkMap>,
|
mut chunk_map: ResMut<ChunkMap>,
|
||||||
mut tilemap: ResMut<TileMap>,
|
mut tilemap: ResMut<TileMap>,
|
||||||
) {
|
) {
|
||||||
let cave_noise = Perlin::new(0);
|
let is_empty = events.is_empty();
|
||||||
|
let start = Instant::now();
|
||||||
|
|
||||||
|
let cave_noise = Perlin::new(0);
|
||||||
for event in events.read() {
|
for event in events.read() {
|
||||||
println!("Loading chunk {}", event.chunk_position);
|
|
||||||
let chunk_pos = event.chunk_position;
|
let chunk_pos = event.chunk_position;
|
||||||
if chunk_map.loaded_chunks.contains_key(&chunk_pos) {
|
if chunk_map.loaded_chunks.contains_key(&chunk_pos) {
|
||||||
continue;
|
continue;
|
||||||
@@ -273,12 +277,14 @@ fn generate_chunks_from_algo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !is_empty {
|
||||||
|
println!("Chunks loaded in {:.2?}", start.elapsed());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_initial_chunks(mut event_writer: EventWriter<LoadChunkEvent>) {
|
fn setup_initial_chunks(mut event_writer: EventWriter<LoadChunkEvent>) {
|
||||||
println!("setup_initial_chunks");
|
for x in -10..=10 {
|
||||||
for x in -3..=3 {
|
for y in -10..=10 {
|
||||||
for y in -2..=2 {
|
|
||||||
event_writer.write(LoadChunkEvent {
|
event_writer.write(LoadChunkEvent {
|
||||||
chunk_position: IVec2::new(x, y),
|
chunk_position: IVec2::new(x, y),
|
||||||
});
|
});
|
||||||
|
|||||||
+62
-45
@@ -113,6 +113,7 @@ impl Default for QuiltCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// here be dragons :(
|
||||||
pub fn build_quilted_terrain_sprites(
|
pub fn build_quilted_terrain_sprites(
|
||||||
query: Query<(&FloorTile, &Transform)>,
|
query: Query<(&FloorTile, &Transform)>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
@@ -155,9 +156,6 @@ pub fn build_quilted_terrain_sprites(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snap min/max values to tile grid - accounting for half tile on each edge
|
|
||||||
// We need to extend the boundaries by half a tile in each direction to ensure full coverage
|
|
||||||
// Don't ask, dragons.
|
|
||||||
let min_x_aligned: f32 = ((tiles.iter().map(|(pos, _)| pos.x).reduce(f32::min).unwrap()
|
let min_x_aligned: f32 = ((tiles.iter().map(|(pos, _)| pos.x).reduce(f32::min).unwrap()
|
||||||
- TILE_SIZE / 2.0)
|
- TILE_SIZE / 2.0)
|
||||||
/ TILE_SIZE)
|
/ TILE_SIZE)
|
||||||
@@ -207,23 +205,25 @@ pub fn build_quilted_terrain_sprites(
|
|||||||
let target_y = tile_y * TILE_PIXELS;
|
let target_y = tile_y * TILE_PIXELS;
|
||||||
let mut data: Vec<&[u8]> = vec![];
|
let mut data: Vec<&[u8]> = vec![];
|
||||||
|
|
||||||
if let Some(source_texture) = images.get(texture) {
|
let mut base_texture: &Image = &Default::default();
|
||||||
if let Some(_data) = &source_texture.data {
|
|
||||||
// replace this one texture push with loop
|
if let Some(_base_texture) = images.get(texture) {
|
||||||
// if the texture contains any transparent or semi-transparent pixels we should also add the tile below it (z-1)
|
if let Some(_data) = &_base_texture.data {
|
||||||
data.push(_data);
|
data.push(_data);
|
||||||
|
base_texture = _base_texture;
|
||||||
}
|
}
|
||||||
blit_texture(
|
|
||||||
data, // tile
|
|
||||||
&mut texture_data, // terrain
|
|
||||||
source_texture.size().x as u32,
|
|
||||||
source_texture.size().y as u32,
|
|
||||||
width_px,
|
|
||||||
height_px,
|
|
||||||
target_x,
|
|
||||||
target_y,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blit_texture_with_alpha(
|
||||||
|
data, // tile
|
||||||
|
&mut texture_data, // terrain
|
||||||
|
base_texture.size().x as u32,
|
||||||
|
base_texture.size().y as u32,
|
||||||
|
width_px,
|
||||||
|
height_px,
|
||||||
|
target_x,
|
||||||
|
target_y,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let quilted_texture = Image::new_fill(
|
let quilted_texture = Image::new_fill(
|
||||||
@@ -248,9 +248,9 @@ pub fn build_quilted_terrain_sprites(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Transform::from_xyz(
|
Transform::from_xyz(
|
||||||
center_x + TILE_SIZE / 2.0,
|
center_x - TILE_SIZE / 2.0,
|
||||||
center_y + TILE_SIZE / 2.0,
|
center_y - TILE_SIZE / 2.0,
|
||||||
(*z_index as f32 - Z_BELOW) * TILE_SIZE,
|
-10.0 * TILE_SIZE,
|
||||||
)
|
)
|
||||||
.with_scale(Vec3::splat(PIXEL_RATIO)),
|
.with_scale(Vec3::splat(PIXEL_RATIO)),
|
||||||
Visibility::Hidden,
|
Visibility::Hidden,
|
||||||
@@ -267,7 +267,7 @@ pub fn build_quilted_terrain_sprites(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to blit a texture onto another texture
|
// Helper function to blit a texture onto another texture
|
||||||
fn blit_texture(
|
fn blit_texture_with_alpha(
|
||||||
sources: Vec<&[u8]>,
|
sources: Vec<&[u8]>,
|
||||||
target: &mut [u8],
|
target: &mut [u8],
|
||||||
source_width: u32,
|
source_width: u32,
|
||||||
@@ -277,35 +277,52 @@ fn blit_texture(
|
|||||||
offset_x: u32,
|
offset_x: u32,
|
||||||
offset_y: u32,
|
offset_y: u32,
|
||||||
) {
|
) {
|
||||||
for y in 0..source_height {
|
for (_, source_data) in sources.iter().rev().enumerate() {
|
||||||
if y + offset_y >= target_height {
|
for y in 0..source_height {
|
||||||
continue;
|
if y + offset_y >= target_height {
|
||||||
}
|
|
||||||
for x in 0..source_width {
|
|
||||||
if x + offset_x >= target_width {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let source_idx = ((y * source_width) + x) as usize * 4;
|
for x in 0..source_width {
|
||||||
let target_idx = (((y + offset_y) * target_width) + (x + offset_x)) as usize * 4;
|
if x + offset_x >= target_width {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// New colour
|
let source_pixel_idx = ((y * source_width) + x) as usize * 4;
|
||||||
let mut r: u64 = 0;
|
let target_pixel_idx =
|
||||||
let mut g: u64 = 0;
|
(((y + offset_y) * target_width) + (x + offset_x)) as usize * 4;
|
||||||
let mut b: u64 = 0;
|
|
||||||
|
|
||||||
for source in sources.iter() {
|
let src_a = source_data[source_pixel_idx + 3];
|
||||||
r += source[source_idx] as u64;
|
|
||||||
g += source[source_idx + 1] as u64;
|
if src_a == 0 {
|
||||||
b += source[source_idx + 2] as u64;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let src_r = source_data[source_pixel_idx];
|
||||||
|
let src_g = source_data[source_pixel_idx + 1];
|
||||||
|
let src_b = source_data[source_pixel_idx + 2];
|
||||||
|
|
||||||
|
if src_a == 255 {
|
||||||
|
target[target_pixel_idx] = src_r;
|
||||||
|
target[target_pixel_idx + 1] = src_g;
|
||||||
|
target[target_pixel_idx + 2] = src_b;
|
||||||
|
target[target_pixel_idx + 3] = 255;
|
||||||
|
} else {
|
||||||
|
let dst_r = target[target_pixel_idx];
|
||||||
|
let dst_g = target[target_pixel_idx + 1];
|
||||||
|
let dst_b = target[target_pixel_idx + 2];
|
||||||
|
|
||||||
|
let alpha_factor = src_a as f32 / 255.0;
|
||||||
|
let inv_alpha = 1.0 - alpha_factor;
|
||||||
|
|
||||||
|
target[target_pixel_idx] =
|
||||||
|
(src_r as f32 * alpha_factor + dst_r as f32 * inv_alpha) as u8;
|
||||||
|
target[target_pixel_idx + 1] =
|
||||||
|
(src_g as f32 * alpha_factor + dst_g as f32 * inv_alpha) as u8;
|
||||||
|
target[target_pixel_idx + 2] =
|
||||||
|
(src_b as f32 * alpha_factor + dst_b as f32 * inv_alpha) as u8;
|
||||||
|
target[target_pixel_idx + 3] = 255;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
r /= sources.len() as u64;
|
|
||||||
g /= sources.len() as u64;
|
|
||||||
b /= sources.len() as u64;
|
|
||||||
|
|
||||||
target[target_idx] = r as u8;
|
|
||||||
target[target_idx + 1] = g as u8;
|
|
||||||
target[target_idx + 2] = b as u8;
|
|
||||||
target[target_idx + 3] = 255;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user