How to super-impose images?

The frame-buffer coordinates are larger than the image1 and image2. So they need to be wrapped around. I was instructed to cast my coordinate to a signed integer and use rem_euclid for this, but I am not sure how to continue. Like adding the pixels together, I am not sure how to approach that for example.

It should combine the images like shown here:

Code

const WIDTH: usize = 900;
const HEIGHT: usize = 900;

struct Image {
    width: usize,
    height: usize,
    buffer: Vec<u32>,
}

impl Image {
    fn load(filename: &str) -> Image {
        let image =
            lodepng::decode32_file(&filename).expect(&format!("Couldn't load {}", &filename));
        Image {
            width: image.width,
            height: image.height,
            buffer: image
                .buffer
                .iter()
                .map(|color| {
                    return u32::from_le_bytes([color.b, color.g, color.r, color.a]);
                })
                .collect(),
        }
    }
}

fn main() {
    let image1 = Image::load("mainframe1.png");
    let image2 = Image::load("mainframe2.png");

    let mut window = minifb::Window::new(
        "Rotating images",
        WIDTH as usize,
        HEIGHT as usize,
        minifb::WindowOptions {
            resize: false,
            topmost: true,
            borderless: true,
            none: true,
            transparency: true,
            scale: minifb::Scale::X1,
            ..minifb::WindowOptions::default()
        },
    )
    .expect("Unable to create window");

    let mut buffer = vec![0u32; (WIDTH * HEIGHT) as usize];

    let mut mode = 2;
    let mut fps_time = std::time::Instant::now();
    let mut fps_count = 0;


    while window.is_open() && !window.is_key_down(minifb::Key::Escape) {

        if window.is_key_pressed(minifb::Key::Space, minifb::KeyRepeat::No) {
            mode = (mode + 1) % 3;
        }

  
        if mode == 0 {
            window.update_with_buffer(&image1.buffer, image1.width, image1.height).unwrap();
        } else if mode == 1 {
            let mut new_buffer: Vec<u32> = image1.buffer.to_vec();
            let brightness = 0.25;
            
            for pixel in new_buffer.iter_mut() {
                let [blue, green, red, alpha] = pixel.to_ne_bytes();
                *pixel = u32::from_ne_bytes([set_pixel_value(brightness, blue), set_pixel_value(brightness, green), set_pixel_value(brightness, red), alpha]);
            }
            window.update_with_buffer(&new_buffer, image1.width, image1.height).unwrap();
        } else if mode == 2 {
            // TODO: Fill and super impose both images. Decrease both images their brightness to 50%
            let mut new_buffer = vec![0u32; (WIDTH * HEIGHT) as usize];
            let image1_buffer: Vec<u32> = image1.buffer.to_vec();
            let image2_buffer: Vec<u32> = image2.buffer.to_vec();  
            let brightness = 0.5; 
          
            for (index, pixel) in new_buffer.iter_mut().enumerate() {
                 let [blue, green, red, alpha] = image1_buffer[index].to_ne_bytes();
                 *pixel = u32::from_ne_bytes([set_pixel_value(brightness, blue), set_pixel_value(brightness, green), set_pixel_value(brightness, red), set_pixel_value(brightness, alpha)]);
                 buffer[index] = *pixel;
                 
                let [blue, green, red, alpha] = image2_buffer[index].to_ne_bytes();
                *pixel = u32::from_ne_bytes([set_pixel_value(brightness, blue), set_pixel_value(brightness, green), set_pixel_value(brightness, red), set_pixel_value(brightness, alpha)]);
                buffer[index+1] = *pixel; 
            }
            window.update_with_buffer(&new_buffer, WIDTH as usize, HEIGHT as usize).unwrap(
        } else {

        }

 
        let now = std::time::Instant::now();
        let duration = (now - fps_time).as_secs_f32();
        fps_count += 1;
        if duration >= 0.33 {
            println!("{} fps", (fps_count as f32 / duration).round() as u32);
            fps_time = now;
            fps_count = 0;
        }
    }
}

fn set_pixel_value(factor: f32, pixel_color: u8) -> u8 {
    let pixel_color = (pixel_color as f32 * factor) as u8;
    pixel_color
}

Output

ailed to create server-side surface decoration: Missing

thread 'main' (107369) panicked at src/main.rs:94:62:
index out of bounds: the len is 225920 but the index is 225920
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: queue 0x5892c89e13e0 destroyed while proxies still attached:
  wl_surface#15 still attached
  wl_shm_pool#14 still attached
  xdg_toplevel#13 still attached
  xdg_surface#12 still attached
  xdg_wm_base#11 still attached
  wl_buffer#10 still attached
  wl_shm_pool#9 still attached
  wl_surface#8 still attached
  wl_shm#7 still attached
  wl_compositor#6 still attached
  wl_pointer#5 still attached
  wl_keyboard#4 still attached
  wl_seat#3 still attached
  wl_registry#2 still attached

in order to calculate the texture coordinates, you need the frame coordinates, which is a 2D grid, but here:

you are iterating the buffer as a 1D array.

to iterate the buffer as a 2D image, you can use nested loops:

for y in 0..HEIGHT {
    for x in 0..WIDTH {
        // sample image 1
        // for positive integers, the euclidean remainder is the same as the `%` operator
        let x1 = x % image1.width;
        let y1 = y % image1.height;
        let color1 = image1.buffer[y1 * image1.width + x1];

        // sample image 2
        let x2 = x % image2.width;
        let y2 = y % image2.height;
        let color2 = image2.buffer[y2 * image2.width + x2];

        // blend the two colors use whatever formula you want
        let final_color = blend(color1, color2);

        // write back to frame buffer
        new_buffer[y * WIDTH + x] = final_color;
    }
}

fn blend(c1: u32, c2: u32) -> u32 {
    todo!()
}

Thank you, makes sense!

My blend function for those interested:

fn blend(mut color1: u32, mut color2: u32, brightness: f32) -> u32 {
    let [blue_c1, green_c1, red_c1, alpha_c1] = color1.to_ne_bytes();
    color1 = u32::from_ne_bytes([
        set_pixel_value(brightness, blue_c1),
        set_pixel_value(brightness, green_c1),
        set_pixel_value(brightness, red_c1),
        set_pixel_value(brightness, alpha_c1),
    ]);

    let [blue_c2, green_c2, red_c2, alpha_c2] = color2.to_ne_bytes();
    color2 = u32::from_ne_bytes([
        set_pixel_value(brightness, blue_c2),
        set_pixel_value(brightness, green_c2),
        set_pixel_value(brightness, red_c2),
        set_pixel_value(brightness, alpha_c2),
    ]);
    
    let final_color = u32::from_ne_bytes([
        ((blue_c1 as u16 + blue_c2 as u16) / 2) as u8,
        ((green_c1 as u16 + green_c2 as u16) / 2) as u8,
        ((red_c1 as u16 + red_c2 as u16) / 2) as u8,
        ((alpha_c1 as u16 + alpha_c2 as u16) / 2) as u8,
    ]);
   
    final_color
}