canselcik/libremarkable

Make libfreetype submodule

PaulBatchelor opened this issue · 3 comments

I notice that there is a hard-coded git clone command in the Makefile, which seems a bit out of place to me.

Would it make any sense to make this a submodule instead?

That way, you could clone it automatically (and just once) with "git submodule init && git submodule update".

PS: I can make this a PR.

Yeah, definitely that would be a good idea. Any help is appreciated.

Note that with the Rust implementation, it looks like it will be much more expedient to get to a stage where we can plug into an already established UI framework. rusttype for instance got everything about text rendering bootstrapped really nicely.

I will add some photos and videos tomorrow with the new rust-poc. It is basically 99.5% the way there in terms of matching the xochitl I/O latency and this is end to end.

Cool! That's good to know. I've never written a line of Rust before, but that may convince me to learn it. What's it like setting up a cross-compiler environment with Rust?

For the time being, the low-level C stuff is good enough for me now. I definitely want to be able to poke at things and learn about some of the guts.

@PaulBatchelor It is actually really straightforward to set it up, and I definitely would recommend it.

Assuming you have the arm-linux-gnueabihf toolchain already installed and you have arm-linux-gnueabihf-gcc in your $PATH, just add the following to your ~/.cargo/config:

[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
ar = "arm-linux-gnueabihf-ar"

Run rustup target add armv7-unknown-linux-gnueabihf to download the toolchain and the std crate for the architecture.

After that you can simply cd into rust-poc and run cargo build --release --target=armv7-unknown-linux-gnueabihf.

You'll have the executable under ./target/armv7-unknown-linux-gnueabihf/release/rust-poc.

The reason why I am recommending this is because the c-implementation already has missing features at this point. Translation from multitouch and Wacom Digitizer coordinates to eInk display coordinates would be one of the first to come to mind.

Aside from that, rusttype is providing a lot of text rendering features out of the box while libfreetype is leaving a lot of the work to us, and the implementation we have in place actually quite hacky, using the letter T to adjust the horizontal and vertical positioning of glyphs etc.

On the other hand, the Rust implementation is moving forward. Here is what an example application would look like (from https://github.com/canselcik/RemarkableFramebuffer/blob/master/rust-implementation/rust-poc/src/main.rs):

// Takes callback functions as arguments
// They are called with the event and the &mut framebuffer
let mut app = uix::ApplicationContext::new(
  on_button_press,
  on_wacom_input,
  on_touch,
);

// Clear the screen
app.clear(true);

// A rudimentary way to declare a scene and layout
app.draw_elements(&vec![
        UIElement::Text {
            text: "Remarkable Tablet".to_owned(),
            y: 200, x: 100,
            scale: 100,
            refresh: UIConstraintRefresh::NoRefresh
        },
        UIElement::Image {
            img: image::load_from_memory(include_bytes!("../rustlang.bmp")).unwrap(),
            y: 10, x: 900,
            refresh: UIConstraintRefresh::Refresh },
        UIElement::Text {
            text: "Current Waveform: ".to_owned(),
            y: 350, x: 120,
            scale: 65, refresh: UIConstraintRefresh::NoRefresh
        },
        UIElement::Text {
            text: "Current Dither Mode: ".to_owned(),
            y: 410, x: 120,
            scale: 65,
            refresh: UIConstraintRefresh::NoRefresh
        },
        UIElement::Text {
            text: "Current Quant: ".to_owned(),
            y: 470, x: 120,
            scale: 65,
            refresh: UIConstraintRefresh::RefreshAndWait
        },
]);

// Get a &mut to the framebuffer object, exposing many convenience functions
let fb = app.get_framebuffer();
let clock_thread = std::thread::spawn(move || {
  loop_print_time(fb, 100, 100, 65);
});

// Blocking call to process events from digitizer + touchscreen + physical buttons
app.dispatch_events(4096, 1024);
clock_thread.join().unwrap();

And even the events are unpacked properly:

pub enum WacomEvent {
    InstrumentChange { pen: WacomPen, state: bool },
    Hover { y: u16, x: u16, distance: u16, tilt_x: u16, tilt_y: u16 },
    Draw { y: u16, x: u16, pressure: u16, tilt_x: u16, tilt_y: u16 },
    Unknown,
}