1

I have an object that, in order to be constructed, needs other objects:

[image] -> needed to construct -> [texture] -> needed to construct -> [sprite]

The problem is that I need to swap the image in the texture in order to create a visual effect. I have this code:

extern crate sfml;

use sfml::graphics::{Color, Image, RenderTarget, RenderWindow, Sprite, Texture};
use sfml::window::{Event, Key, Style};

const WIDTH: u32 = 1024;
const HEIGHT: u32 = 768;

fn main() {
    let mut window = RenderWindow::new(
        (WIDTH, HEIGHT),
        "Custom drawable",
        Style::CLOSE,
        &Default::default(),
    );

    let mut image = Image::from_color(WIDTH, HEIGHT, &Color::BLUE).unwrap();
    let mut texture = Texture::from_image(&image).unwrap();
    let sprite_canvas = Sprite::with_texture(&texture);

    let mut x: u32 = 0;

    loop {
        while let Some(event) = window.poll_event() {
            match event {
                Event::Closed
                | Event::KeyPressed {
                    code: Key::Escape, ..
                } => return,
                _ => {}
            }
        }
        x += 1;
        image.set_pixel(x, x, &Color::YELLOW);
        texture.update_from_image(&image, 0, 0);
        window.draw(&sprite_canvas);
        window.display()
    }
}

This is the error I have when "cargo run" the example

error[E0502]: cannot borrow `texture` as mutable because it is also borrowed as immutable
  --> src/main.rs:35:9
   |
19 |     let sprite_canvas = Sprite::with_texture(&texture);
   |                                               ------- immutable borrow occurs here
...
35 |         texture.update_from_image(&image, 0, 0);
   |         ^^^^^^^ mutable borrow occurs here
...
39 | }
   | - immutable borrow ends here

Copying or cloning the texture or image should be avoided due to performance considerations; cloning big images can lead to performance degradation.

I made it work with this code, but not sure if it's the best solution, since I'm recreating the texture in every frame.

extern crate sfml;
use sfml::graphics::{Color, RenderTarget, RenderWindow, Sprite, Texture, Image, Transformable, Text, Font};
use sfml::window::{Event, Key, Style};

const WIDTH: u32 = 1024;
const HEIGHT: u32 = 768;

fn main() {
    let mut window = RenderWindow::new(
        (WIDTH, HEIGHT),
        "Custom drawable",
        Style::CLOSE,
        &Default::default(),
    );
    window.set_vertical_sync_enabled(true);

    let mut image_canvas = Image::from_color(WIDTH, HEIGHT, &Color::BLACK).unwrap();

    let mut x: f32 = 0.0;
    let mut y: f32 = 0.0;
    let mut image_swap = false;

    loop {
        while let Some(event) = window.poll_event() {
            match event {
                Event::Closed
                | Event::KeyPressed {
                    code: Key::Escape, ..
                } => return,
                _ => {}
            }
        }
        if Key::Left.is_pressed() {
            x -= 1.0;
        }

        if Key::Right.is_pressed() {
            x += 1.0;
        }

        if Key::Up.is_pressed() {
            y -= 1.0;
        }

        if Key::Down.is_pressed() {
            y += 1.0;
        }

        image_canvas.set_pixel(x as u32, y as u32, &Color::YELLOW);
        let texture_3 = Texture::from_image(&image_canvas).unwrap();
        let sprite_canvas = Sprite::with_texture(&texture_3);

        image_swap = !image_swap;

        window.clear(&Color::BLACK);
        window.draw(&sprite_canvas);
        window.display()
    }
}
Werem
  • 534
  • 2
  • 5
  • 16
  • Can you swap thoses lines? – hellow Dec 14 '18 at 11:43
  • Hi. Sorry I don’t understand. Swap wich lines and with which purpose? For readability or as a solution? – Werem Dec 14 '18 at 12:12
  • Possible duplicate of [How to represent shared mutable state?](https://stackoverflow.com/questions/28418584/how-to-represent-shared-mutable-state) – trent Dec 14 '18 at 12:18
  • 1
    As a solution. If you swap the last two lines `texture` can call it's mutable function before it's getting borrowed as immutable a line beforehand. – hellow Dec 14 '18 at 12:21
  • Tl;dr the duplicate: Use RefCell (or RwLock/Mutex for cross-thread sharing). You might even be able to get away with Cell or Atomics depending on what exactly `update` needs to do – trent Dec 14 '18 at 12:24
  • I see. Regarding swapping the lines as a solution, that can be done but it will not work for what I need. Sadly, the code I posted is a simplified version of the real one. The texture need to be updated inside a loop, swapping between image and image2 in every frame. So even if I use a different image order, it will not work in the next cycle. I'll test the reference to the duplicated question in a few hours and I'll post the result. Thanks. – Werem Dec 14 '18 at 12:28
  • @Werem then it is not a [MCVE](https://stackoverflow.com/help/mcve). Please try to provide one! – hellow Dec 14 '18 at 12:47
  • 1
    @Werem Maybe you should avoid updating the texture in the loop, Please try: Create 2 textures for 2 images and create empty `Sprite(Sprite::new())`, set the proper texture in the `loop( if ... sprite.setTexture(...) `, then draw the sprite. – Ömer Erden Dec 14 '18 at 12:58
  • @hellow I updated the original post to provide a MCVE. – Werem Dec 14 '18 at 14:00
  • recreating the texture worked, but not sure that this is the best solution. This is the code I got working: – Werem Dec 18 '18 at 22:51

0 Answers0