How to load a texture from memory?

(skypitcher) #1

How to load a picture as a texture from memory directly?

What I have tired :

pub struct Picture {
    pub width: u32,
    pub height: u32,
    pub pixels: Vec<u32>, // R8_G8_B8_A8
}

pub struct WelcomeState{
    // This picture will be somehow loaded in memory 
    // once WelcomeState is instantiated.
    pic: Picture, 
}

impl SimpleState for WelcomeState {
    fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) {
        let world = data.world;
        let dimensions = world.read_resource::<ScreenDimensions>().clone();
        
        init_camera(world, &dimensions);
        init_picture(world, self.pic);
    }
}

fn init_camera(world: &mut World, dimensions: &ScreenDimensions) {
    let mut transform = Transform::default();
    transform.set_translation_xyz(
        dimensions.width()  * 0.5, 
        dimensions.height() * 0.5, 
        1.
    );

    world
        .create_entity()
        .with(Camera::standard_2d(dimensions.width(), dimensions.height()))
        .with(transform)
        .build();
}

fn init_picture(world: &mut World, pic: &Picture) {
    let texture = load_texture(world, pic);
    
    let mut transform = Transform::default();
    transform.set_translation_x(0.);
    transform.set_translation_y(0.);
    transform.set_translation_z(0.);

    world
        .create_entity()
        .with(texture.clone())
        .with(transform)
        .build();
}

fn load_texture(world: &mut World, pic: &Picture) -> Handle<Texture> {
    let loader = world.read_resource::<Loader>();
    
    let texture_builder = TextureBuilder::new()
        .with_data_width(pic.width)
        .with_data_height(pic.height)
        .with_kind(hal::image::Kind::D2(pic.width, pic.height, 1, 1))
        .with_view_kind(hal::image::ViewKind::D2)
        .with_sampler_info(default_sampler_info())
        .with_raw_data(pic.pixels, hal::format::Format::Rgba8Uint);
    
    loader.load_from_data(
        TextureData::from(texture_builder), 
        (), 
        &world.read_resource::<AssetStorage<Texture>>()
    )
}

#[inline]
fn default_sampler_info() -> hal::image::SamplerInfo {
    hal::image::SamplerInfo {
        min_filter: hal::image::Filter::Linear,
        mag_filter: hal::image::Filter::Linear,
        mip_filter: hal::image::Filter::Linear,
        wrap_mode: (
            hal::image::WrapMode::Clamp, 
            hal::image::WrapMode::Clamp, 
            hal::image::WrapMode::Clamp,
        ),
        lod_bias: 0.0.into(),
        lod_range: std::ops::Range {
            start: 0.0.into(),
            end: 1000.0.into(),
        },
        comparison: None,
        border: hal::image::PackedColor(0),
        anisotropic: hal::image::Anisotropic::Off,
    }
}
(Azriel Hoh) #2

Hiya, I have very similar code in my project, with the following differences:

// Sampler infor is just:
.with_sampler_info(SamplerInfo::new(Filter::Linear, WrapMode::Clamp))

// Pixel data is:
let pixel_data: Vec<Rgba8Srgb> = pixel_data
    .into_iter()
    .map(|[red, green, blue, alpha]| { // turn each slice of 4 colour channels into an Rgba8Srgb
        Rgba8Srgb::from(Srgba::new(red, green, blue, alpha))
    })
    .collect::<Vec<Rgba8Srgb>>();

// Then
.with_data(pixel_data);

hope that helps

3 Likes
(skypitcher) #3

Unfortunatly, it does not work. I am wondering if I have to wrap it into a SpriteRender or a SpriteSheet.

(Azriel Hoh) #4

Oh yes, one of the recent versions made that a requirement (to use SpriteRender).

1 Like
(skypitcher) #5

Yes, it finally works. Thanks a lot!

3 Likes