use crate::ecs::particles::components::ParticleTextureUpload;
use crate::ecs::world::World;
pub const GLOW_SLOT: u32 = 1;
pub const FLARE_SLOT: u32 = 2;
pub const SMOKE_SLOT: u32 = 3;
const SIZE: u32 = 512;
pub fn upload_vfx_textures(world: &mut World) {
upload(world, GLOW_SLOT, glow_texture());
upload(world, FLARE_SLOT, flare_texture());
upload(world, SMOKE_SLOT, smoke_texture());
}
fn upload(world: &mut World, slot: u32, rgba_data: Vec<u8>) {
world
.resources
.loading
.pending_particle_textures
.push(ParticleTextureUpload {
slot,
rgba_data,
width: SIZE,
height: SIZE,
});
}
fn build(alpha: impl Fn(f32, f32) -> f32) -> Vec<u8> {
let mut data = vec![0u8; (SIZE * SIZE * 4) as usize];
let half = SIZE as f32 * 0.5;
for y in 0..SIZE {
for x in 0..SIZE {
let nx = (x as f32 + 0.5 - half) / half;
let ny = (y as f32 + 0.5 - half) / half;
let a = alpha(nx, ny).clamp(0.0, 1.0);
let index = ((y * SIZE + x) * 4) as usize;
data[index] = 255;
data[index + 1] = 255;
data[index + 2] = 255;
data[index + 3] = (a * 255.0) as u8;
}
}
data
}
fn glow_texture() -> Vec<u8> {
build(|nx, ny| {
let distance = (nx * nx + ny * ny).sqrt();
let edge = (1.0 - distance).clamp(0.0, 1.0);
(-distance * distance * 4.5).exp() * edge * edge
})
}
fn flare_texture() -> Vec<u8> {
build(|nx, ny| {
let distance = (nx * nx + ny * ny).sqrt();
let core = (-distance * distance * 26.0).exp();
let horizontal = (-ny.abs() * 26.0).exp() * (1.0 - nx.abs()).clamp(0.0, 1.0);
let vertical = (-nx.abs() * 26.0).exp() * (1.0 - ny.abs()).clamp(0.0, 1.0);
core + (horizontal + vertical) * 0.6
})
}
fn smoke_texture() -> Vec<u8> {
build(|nx, ny| {
let distance = (nx * nx + ny * ny).sqrt();
let edge = (1.0 - distance).clamp(0.0, 1.0);
let cloud = fbm((nx * 0.5 + 0.5) * 5.0, (ny * 0.5 + 0.5) * 5.0);
edge * edge * (0.35 + 0.75 * cloud)
})
}
fn hash2(x: i32, y: i32) -> f32 {
let mut h = x
.wrapping_mul(374_761_393)
.wrapping_add(y.wrapping_mul(668_265_263));
h = (h ^ (h >> 13)).wrapping_mul(1_274_126_177);
((h ^ (h >> 16)) as u32) as f32 / u32::MAX as f32
}
fn value_noise(px: f32, py: f32) -> f32 {
let x0 = px.floor() as i32;
let y0 = py.floor() as i32;
let fx = px - x0 as f32;
let fy = py - y0 as f32;
let ux = fx * fx * (3.0 - 2.0 * fx);
let uy = fy * fy * (3.0 - 2.0 * fy);
let a = hash2(x0, y0);
let b = hash2(x0 + 1, y0);
let c = hash2(x0, y0 + 1);
let d = hash2(x0 + 1, y0 + 1);
let top = a + (b - a) * ux;
let bottom = c + (d - c) * ux;
top + (bottom - top) * uy
}
fn fbm(px: f32, py: f32) -> f32 {
let mut value = 0.0;
let mut amplitude = 0.5;
let mut frequency = 1.0;
for _ in 0..4 {
value += amplitude * value_noise(px * frequency, py * frequency);
amplitude *= 0.5;
frequency *= 2.0;
}
value
}