sprite icon indicating copy to clipboard operation
sprite copied to clipboard

Add clipping window to sprite

Open xaviershay opened this issue 9 years ago • 3 comments

I'd like to set a window rectangle such that the parts of sprites that are outside of it. This is supported by underlying graphics library, I'm just not sure how it should all tie together.

  1. Is it possible to affect the clipping window of the sprite from outside the Sprite.draw() function?
  2. Is this a per-sprite option or per-scene? per-scene works for my use case but per-sprite more flexible. sprite.set_clip(Rectangle::new())?
  3. Another way I've missed?

Links:

  • Sprite draw code. that appears to hard code default_draw_state().
  • (Piston examples demo](https://github.com/PistonDevelopers/piston-examples/blob/master/src/draw_state.rs) with raw graphics.

xaviershay avatar Sep 20 '15 21:09 xaviershay

Perhaps the scene should have a method with a callback to draw the sprites. This way you could change the clipping for the whole scene or for each individual sprite.

bvssvni avatar Sep 20 '15 21:09 bvssvni

Anyone working on this? I think I'm going to give it a shot, since I prefer to load and reuse one spritesheet rather than split it into multiple images. I also think this is a common enough practice to warrant adding this as a feature.

edit: For my use case (and what I think is the most common one), I think it might be more elegant to load the asset into an ImageBuffer, use GenericImage::sub_image to create references to image clips, and then load those into Texture instances that in turn get loaded into Sprite instances. Then for things like animation, just vary the visibility of sub-sprites in order to animate them. I think I'm going to experiment with this before I try to modify the library. Even if we do end up needing the feature, I think I'll be better informed after this attempt.

edit2: This is indeed the route I ended up going. For anyone else looking to follow this approach, here is what I ended up doing:

let (width, height) = (800, 600);

// load image asset
let assets = find_folder::Search::ParentsThenKids(3, 3)
    .for_folder("assets")
    .unwrap();
let mut spritesheet = image::open(assets.join("roguelikeChar_transparent.png"))
    .unwrap()
    .to_rgba();

// set up the window
let opengl = OpenGL::V3_2;
let mut window: PistonWindow =
    WindowSettings::new("roguelike", (width, height))
    .exit_on_esc(true)
    .opengl(opengl)
    .build()
    .unwrap();

// set up character sprite
let char_img = {
    let tile_size = 16;
    let margin = 1;
    let (x, y, w, h) = (0, 6 * (tile_size + margin), tile_size, tile_size);
    spritesheet.sub_image(x, y, w, h).to_image()
};
let char_tex = Rc::new(Texture::from_image(
        &mut window.factory,
        &char_img,
        &TextureSettings::new()
    ).unwrap());
let mut char_sprite = Sprite::from_texture(char_tex.clone());
char_sprite.set_position(width as f64 / 2.0, height as f64 / 2.0);

// set up scene
let mut scene = Scene::new();
let id = scene.add_child(char_sprite);

axelmagn avatar Jan 10 '17 23:01 axelmagn

I added the above PR (#146) as an attempted solution for this. I figured it might be more efficient than the method implemented by @axelmagn, as it doesn't load as many textures into memory. This comes at the loss of versatility for playing around with the visibility of multiple loaded layers, though, so both implementations might have some utility. Any eyes on the PR would be appreciated!

BedfordWest avatar Mar 06 '17 02:03 BedfordWest