Git Product home page Git Product logo

glyphon's People

Contributors

azurice avatar c-u avatar coastalwhite avatar daslixou avatar dunxen avatar eggshark avatar genusistimelord avatar grovesnl avatar hecrj avatar ids1024 avatar jengamon avatar julianbraha avatar lukaskalbertodt avatar ppakalns avatar xlambein avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

glyphon's Issues

Out of memory error when max_texture_dimension_2d isn't limited

The hello-world example uses wgpu::Limits::downlevel_defaults(), which creates a set of limits with max_texture_dimension_2d set to 2048. In my wgpu application, I'm using wgpu::Limits::downlevel_webgl2_defaults().using_resolution(adapter.limits()) which is what many of the wgpu examples use. This results in a max_texture_dimension_2d of 32,768.

When the texture atlas is initialized against this device, it attempts to allocate a 32kx32k texture which is 4 gigs with the SrgbUnorm texture format. This causes an out of memory error on my machine.

I can of course restrict my limits further, but it seems like TextAtlas shouldn't be attempting to create the largest possible texture. Ideally it would start small and dynamically grow as needed. However, I know that's really complicated, so as an alternative, perhaps allow the developer a way to specify the atlas size explicitly?

How is clipping handled?

I'm pretty sure I'm obtuse:

I'm looking at the hello-world.rs file and can't figure out how to unclip the text in the buffer. Changing the width and height parameters don't change the clipping, only the size of the spawned window.

Is there a default setting somewhere I'm unable to grasp? I've tried looking through both cosmic-text's and glyphon's docs to no avail.

Any help would be appreciated!

Fix interpretation of sRGB colors from cosmic-text Attrs as linear

You can test this by setting default_color in the hello-world example to #5fafff for example, and then taking a screenshot of the resulting window. You will measure #a4d8ff instead, which means that the default_color is being interpreted as though it is in the linear color space instead of sRGB.

cosmic-text intends for the colors used to be sRGB, and glyphon should also interpret them that way, doing any conversions necessary inside of glyphon.

wgpu 13 support

Hey, I like that this is using the latest shader format. You might want to add this to Cargo.toml or make mention of it:

[patch.crates-io]
wgpu = { git = "https://github.com/gfx-rs/wgpu" }

Crate isn't updated on crates.io

I have tried using glyphon in a project with wgpu 0.18.0, but it appears that the crate still depends on wgpu 0.16.3, breaking a lot of things. I have seen the update wgpu to 0.18 commit, but this change doesn't seem to have landed at https://crates.io/crates/glyphon yet (And not on my end either).
I apologize if this is intentional, but it seems strange to me. Thank you!

Consider handling transformations

Consider handling scale, shear, rotation, etc., at least for typical 2D use cases

Also related to #3 because pixel snapping wouldn't work well depending on the transformation.

Improve API ergonomics

It's a bit difficult to organize fonts/layouts and pass them to renderer.

Consider some other way to handle fonts, layouts, etc., possibly wrapping all of fontdue to remove fontdue from the public API.

Consider adding a changelog and/or use GitHub releases

If I'm not mistaken, there is currently no changelog for this crate. This makes it really hard to update from one version to the next, or even just check what version works with a specific version of wgpu. Adding a changelog would be great, thanks!

Subpixel positioning and antialiasing

Currently we snap to the nearest pixel so kind of avoid this.

We probably want to have a strategy for handling subpixel positioning and AA generally. This can be difficult with glyphs because we might need to generate multiple glyphs for various subpixel positions.

Text atlas pipeline sample count

I have a render pass with MSAA enabled and would like to render text in this pass. Would you be willing to accept a PR to set the sample count as part of the atlas’ new function? Is there any reason not to do render text to an MSAA target?

Convert mouse position to line, character in window event?

Hi,

I was wondering if there was a way to obtain (line, character) information from a rendered text area in a window? I can't think of another way to highlight words using the cursor, for example.

What would it take for such a calculation to be done?

Thanks.

Feature Request - C API

Would it be feasible to provide a C API of glyphon so it can be easily used by libraries outside Rust?

If its feasible and acceptable, then with some guidance I'm potentially willing to put time into this effort

get dimensions of rendered text

Hello!

I want to get the size of the rendered text rather than the whole buffer dimensions, because I'm setting it to the whole width of the window (probably shouldn't do that(?)), but if there is a way to measure the text with a function or something that would solve a couple of issues I'm having

can this be done in this crate or cosmic-text?

Sharing atlas between multiple text renderers

Ideally we could have an easy way to have multiple text renderers that share the same atlas to avoid extra texture allocations and share glyphs when possible.

We could do this by passing the atlas to prepare, sharing internally, etc. Alternatively we could share a text renderer between all layers, and the text renderer could model layers directly somehow.

WASM browser support?

Hey there, Im working on an IDE and running the example code in this repo, I get an error in the browser:

panicked at /Users/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cosmic-text-0.10.0/src/shape.rs:217:33: no default font found

What is the best way to deal with loading fonts for Glyphon in the browser?

Thanks :)

TextArea buffer reference field

At the moment text area holds reference for a buffer. This create lifetimes issues when storing text areas somewhere.
Are there any ways to change this API?
Because at the moment it is hard to organize text area storage, and the only usable option is to recreate text areas on every redraw call.

Depth component of a TextArea

I'm looking to migrate from wgpu_glyph to Glyphon, but I'm getting stuck on one thing: I can't define a text area's depth value.

In wgpu_glyph I could do something like this:

 let section = Section {
                screen_position: pos,
                bounds: size,
                text: vec![Text::new(text)
                    .with_color([c[0], c[1], c[2], 1.0])
                    .with_scale(appearance.font_size)
                    .with_z(z_order.calculate_position())],
                layout: Layout::default_wrap(),
            };

where with_z would decide the Z written into the depth buffer, a must when doing a UI.

I've seen prepare_with_depth but I do not think that lets me set a depth value per textarea ?

Example panics on large window size

When I run the example on my machine I get this panic:

~2/Projects/Crates/glyphon> cargo run --example hello-world
    Finished dev [unoptimized + debuginfo] target(s) in 0.07s
     Running `target/debug/examples/hello-world`
thread 'main' panicked at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.3/src/backend/wgpu_core.rs:724:18:
Error in Surface::configure: Validation Error

Caused by:
    `Surface` width and height must be within the maximum supported texture size. Requested was (1276, 2119), maximum extent is 2048.

stack backtrace:
   0: rust_begin_unwind
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
   2: wgpu::backend::wgpu_core::ContextWgpuCore::handle_error_fatal
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.3/src/backend/wgpu_core.rs:283:9
   3: <wgpu::backend::wgpu_core::ContextWgpuCore as wgpu::context::Context>::surface_configure
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.3/src/backend/wgpu_core.rs:724:13
   4: <T as wgpu::context::DynContext>::surface_configure
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.3/src/context.rs:2124:9
   5: wgpu::Surface::configure
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.19.3/src/lib.rs:4818:9
   6: hello_world::run::{{closure}}::{{closure}}
             at ./examples/hello-world.rs:94:25
   7: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:294:13
   8: winit::platform_impl::platform::x11::EventLoop<T>::drain_events::{{closure}}
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/x11/mod.rs:636:25
   9: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:294:13
  10: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:294:13
  11: winit::platform_impl::platform::x11::event_processor::EventProcessor<T>::configure_notify
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/x11/event_processor.rs:778:13
  12: winit::platform_impl::platform::x11::event_processor::EventProcessor<T>::process_xevent
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/x11/event_processor.rs:169:38
  13: winit::platform_impl::platform::x11::event_processor::EventProcessor<T>::process_event
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/x11/event_processor.rs:80:9
  14: winit::platform_impl::platform::x11::EventLoop<T>::drain_events
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/x11/mod.rs:626:13
  15: winit::platform_impl::platform::x11::EventLoop<T>::single_iteration
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/x11/mod.rs:557:9
  16: winit::platform_impl::platform::x11::EventLoop<T>::pump_events
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/x11/mod.rs:441:13
  17: winit::platform_impl::platform::x11::EventLoop<T>::run_on_demand
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/x11/mod.rs:408:19
  18: winit::platform_impl::platform::EventLoop<T>::run_on_demand
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/mod.rs:829:56
  19: winit::platform_impl::platform::EventLoop<T>::run
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/platform_impl/linux/mod.rs:822:9
  20: winit::event_loop::EventLoop<T>::run
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.14/src/event_loop.rs:249:9
  21: hello_world::run::{{closure}}
             at ./examples/hello-world.rs:83:5
  22: pollster::block_on
             at /home/rukai/.cargo/registry/src/index.crates.io-6f17d22bba15001f/pollster-0.3.0/src/lib.rs:128:15
  23: hello_world::main
             at ./examples/hello-world.rs:21:5
  24: core::ops::function::FnOnce::call_once
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

My machine is running arch linux with i3 wm.
Since its using i3, the example automatically fills up the entire monitor height when launched.
Even for non-i3 users, they could trigger this issue by resizing the window to fill more of their monitor.

Integration with application

Hi!

I'm making an application with a custom WGPU renderer (I'm still learning), and I tried to integrate glyphon with it, but it doesn't render anything, even when I comment out my renderer and pass the render pass to the text renderer, it still doesn't render anything to the window

relevant code:

    pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
        let output = self.surface.get_current_texture()?;

        let view = output
            .texture
            .create_view(&wgpu::TextureViewDescriptor::default());

        let mut encoder = self
            .device
            .create_command_encoder(&wgpu::CommandEncoderDescriptor {
                label: Some("Render Encoder"),
            });

        {
            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                label: Some("Render Pass"),
                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                    view: &view,
                    resolve_target: None,
                    ops: wgpu::Operations {
                        load: wgpu::LoadOp::Clear(wgpu::Color {
                            r: 0.1,
                            g: 0.2,
                            b: 0.3,
                            a: 1.0,
                        }),
                        store: true,
                    },
                })],
                depth_stencil_attachment: None,
            });

            // my renderer
            self.renderer
                .render(&mut render_pass, self.painter.meshes());

            // glyphon renderer
            self.text_renderer.render(&mut render_pass).unwrap();
        }

        // submit will accept anything that implements IntoIter
        self.queue.submit(std::iter::once(encoder.finish()));
        output.present();

        self.text_renderer.trim();

        Ok(())
    }
pub struct TextRenderer {
    pub buffer: glyphon::Buffer,
    pub renderer: glyphon::TextRenderer,
    pub cache: SwashCache,
    pub font_system: glyphon::FontSystem,
    pub atlas: glyphon::TextAtlas,
}

impl TextRenderer {
    pub fn prepare(
        &mut self,
        device: &wgpu::Device,
        queue: &wgpu::Queue,
        width: u32,
        height: u32,
    ) -> Result<(), wgpu::SurfaceError> {
        self.renderer
            .prepare(
                device,
                queue,
                &mut self.font_system,
                &mut self.atlas,
                Resolution { width, height },
                [TextArea {
                    buffer: &self.buffer,
                    left: 0.0,
                    top: 0.0,
                    scale: 1.0,
                    bounds: TextBounds {
                        left: 1000,
                        top: 1000,
                        right: 1000,
                        bottom: 1000,
                    },
                    default_color: glyphon::Color::rgb(255, 255, 255),
                }],
                &mut self.cache,
            )
            .unwrap();
        Ok(())
    }

    pub fn render<'rp>(
        &'rp self,
        render_pass: &mut wgpu::RenderPass<'rp>,
    ) -> Result<(), crate::Error> {
        self.renderer.render(&self.atlas, render_pass)?;

        Ok(())
    }

    pub fn trim(&mut self) {
        self.atlas.trim();
    }
}

if more context is needed I will be happy to provide it :)

Handle text overflow

Handle text overflow outside of layouts through culling and clipping.

Culling:

  • We could cull on the CPU, e.g. if all or any glyph's vertex is outside the layout then we could skip it
    • We could also clip on the CPU at this point if we want, see note below

Clipping:

  • When one layout is used per render, clipping with scissor could be handled outside of glyphon or by glyphon setting the scissor
  • When multiple layouts are used, we'd probably need to handle clipping through shader discard or clip on the CPU (e.g. clip the vertices and sample the glyph from the remaining area)

Some Source Suggestions.

So in small or large projects it does tend to be a good Idea to split structure and data types into their own parts. This makes certain things Easier to find and can improve readability and Adaptability. Keeping most of everything in a Single file generally is a huge turn off to programmers who are willing to help as it makes it harder to find Certain things. This is just a Suggestion not really a Must do.

TextAtlas and Text Renderer can be split into their own files. The major Data structures at the top Could either Stay since they are small or be moved into a single separate file to remove code form the lib.rs. Some internal Changes Could also be split into Functions as well and just made inlined, which can make Code easier to read if the function names Make sense for what it does.

Splitting up the Code can also help later on with new Feature Additions to this library. Anyways What do you think?

OOM with large font size

Rendering a short string with a large font size and large TextArea.scale (still small in 4k monitors) causes AtlasFull.

Relaxing the texture limit to x4, TextAtlas keeps growing until OOM.

let mut limits = wgpu::Limits::default();
limits.max_texture_dimension_2d = 8192 * 4;
let mut buffer =
    glyphon::Buffer::new(&mut font_system, glyphon::Metrics::new(30.0, 42.0));
buffer.set_size(&mut font_system, 600.0, 500.0);
buffer.set_text(
    &mut font_system,
    " πŸ¦… glyphon 🦁\nThe text x y z",
    glyphon::Attrs::new().family(glyphon::Family::SansSerif),
    glyphon::Shaping::Advanced,
);
buffer.shape_until_scroll(&mut font_system);
text_renderer.prepare(
    device,
    queue,
    &mut font_system,
    &mut atlas,
    glyphon::Resolution {
        width: 800,
        height: 600,
    },
    [glyphon::TextArea {
        buffer: &buffer,
        left: 100.0,
        top: 100.0,
        scale: 10.0,
        bounds: glyphon::TextBounds {
            left: 100,
            top: 100,
            right: 600,
            bottom: 600,
        },
        default_color: glyphon::Color::rgb(0, 0, 0),
    }],
    &mut cache,
)
.unwrap();
text_renderer.render(&atlas, &mut render_pass).unwrap();
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:474] content_type = Color
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:475] did_grow = true
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:130] self.size = 26880
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:131] self.max_texture_dimension_2d = 32768

[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:474] content_type = Color
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:475] did_grow = true
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:130] self.size = 27136
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:131] self.max_texture_dimension_2d = 32768

[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:474] content_type = Color
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:475] did_grow = true
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:130] self.size = 27392
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:131] self.max_texture_dimension_2d = 32768

thread 'main' panicked at .cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.17.1/src/backend/direct.rs:3056:5:
wgpu error: Validation Error

Caused by:
    In Device::create_texture
      note: label = `glyphon atlas`
    Not enough memory left

But then reducing TextArea.scale from 10 to 5 renders fine with only size=256.
Why does scale=10 use x100 more memory than scale=5?

[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:130] self.size = 256
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:131] self.max_texture_dimension_2d = 32768
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:474] content_type = Color
[.cargo/git/checkouts/glyphon-bce1d8fb6a1f7cb1/9e25714/src/text_atlas.rs:475] did_grow = true

Center Text

How would I center the text in for example the middle of my window?

I currently do

let x = self.size.width / 2;
        let y = self.size.height / 2;

        self.text_renderer
            .prepare(
                &self.device,
                &self.queue,
                &mut self.font_system,
                &mut self.atlas,
                Resolution {
                    width: self.size.width,
                    height: self.size.height,
                },
                [TextArea {
                    buffer: &self.buffer,
                    left: x as f32,
                    top: y as f32,
                    scale: 1.0,
                    bounds: TextBounds {
                        left: x as i32,
                        top: y as i32,
                        right: self.size.width as i32,
                        bottom: self.size.height as i32,
                    },
                    default_color: glyphon::Color::rgb(0, 0, 0),
                }],
                &mut self.cache,
            )
            .unwrap();

But that does it with a offset. Now i would need something like the worlds famous translate(-50%) css trick...
But I can't seem to find any API to get the size of the text. Also the TextBounds API is kinda weird because provides extra left and top values which are absolute so I need to pass the left and top in there as well...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.