embedded-graphics / tinytga

A no_std TGA library for embedded applications.
https://crates.io/crates/tinytga
Apache License 2.0
6 stars 1 forks source link

Make `from_slice()` const? #20

Open mlund opened 6 months ago

mlund commented 6 months ago

Description of the problem/feature request/other

I'm experimenting with embedded-graphics on a very restricted system with only 40 kB available RAM, and while it does work with primitives like circles, fonts etc., using tinytga, the size grows up to 80 kB bytes or so while loading a 2 kB file. I therefore wonder if fn from_slice() could be made const so that image processing is done at compile-time? I realise that this could be an elaborate task due to the limitations of constant expressions.

rfuest commented 6 months ago

I don't think that will be possible, but I also don't think that this is your problem. I'm pretty sure I've successfully used tinytga on a microcontroller with 8 kB of RAM in the past.

Can you provide a bit more information about the system, like what architecture/controller you are working with? Or can you even make the code that you use to draw the image and an example image available?

mlund commented 6 months ago

Thanks for the quick reply. It could be that it's the rust compiler that does something unexpected. The target is a a Commodore 64 8-bit computer using llvm-mos/rust-mos. I'll shortly push the display driver to a crate with instructions how to run this (which involves Docker due to the special toolchain).

rfuest commented 6 months ago

Now that's an interesting project, I'm happy to help with that. I had never expected to use any Rust code I've written to run on my C64, but I'll definitely try it when we get this working.

mlund commented 6 months ago

Sounds great - here's preview of what I have so far ;-)

https://github.com/embedded-graphics/tinytga/assets/3248398/07f29486-9954-4d07-ada0-2f316ab70aa8

mlund commented 6 months ago

The retro-display display driver is out: https://crates.io/crates/retro-display

rfuest commented 6 months ago

I had some permission problems with using Podman to run the development container, which made development a little inconvenient, but after some tinkering I was able to display an image using the ImageRaw type from embedded-graphics:

https://github.com/embedded-graphics/tinytga/assets/226123/5097249a-68aa-498d-b39c-4a3b0ef39251

Here is the code I used to display the image:

#[start]
fn _main(_argc: isize, _argv: *const *const u8) -> isize {
    let mut display = PetsciiDisplay {};
    display.set_border_color(VicIIPalette::Black);
    display.clear(VicIIPalette::Black).unwrap();

    let data = include_bytes!("../eg-logo.raw");
    let image = ImageRawLE::new(data, 20);
    Image::new(&image, Point::new(10, 0))
        .draw(&mut display)
        .unwrap();
    loop {}
}

The generated binary is 1730 bytes with 250 bytes taken up by the image.

There are some minor tweaks which I had to make in the library to get this working. I'll open a PR for these changes when I've sorted out my permission issues. I've also added a set_border_color method to make the demo look nicer.

The data file was created by a small external program, which uses tinytga and e-g's Framebuffer. The code was just a quick hack and is very inflexible with many hardcoded values. A real implementation could map the RGB colors in an image to their closest C64 palette entry.

fn main() {
    let logo_data = include_bytes!("../assets/eg-logo.tga");
    let logo = Tga::<Gray4>::from_slice(logo_data).unwrap();

    let mut fb =
        Framebuffer::<Gray4, _, LittleEndian, 20, 25, { buffer_size::<Gray4>(20, 25) }>::new();
    Image::new(&logo, Point::zero()).draw(&mut fb).unwrap();

    for p in fb.bounding_box().points() {
        let c = fb.pixel(p).unwrap();

        let c64_c = match c.into_storage() {
            8 => 6,
            15 => 14,
            _ => 0,
        };

        fb.set_pixel(p, Gray4::new(c64_c));
    }

    std::fs::write("/tmp/eg-logo.raw", fb.data()).unwrap();
}
mlund commented 6 months ago

This is great, and 2K is not bad at all. Yes, I started looking into conversion from RGB by calculating the color difference and realised that this can be done in many ways. There are crates available, but I didn't continue investigating.