bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.36k stars 3.59k forks source link

Panic when attempting to render text with specific font #1254

Closed luke-biel closed 3 years ago

luke-biel commented 3 years ago

Bevy version

0.4 and master

Operating system & version

Mac OS Big Sur 11.1

What you did

Copied ui/button example, changed font to airstrip four (http://www.vicfieger.com/~font/techno.html). Ran example.

What you expected to happen

Example displayed button that changes text on hover and press.

What actually happened

On 0.4 game crashed when hovered a button.

thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 8', /Users/lukaszbiel/.cargo/registry/src/github.com-1ecc6299db9ec823/ab_glyph_rasterizer-0.1.4/src/raster.rs:140:17
stack backtrace:
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::panic_bounds_check
   3: <usize as core::slice::index::SliceIndex<[T]>>::index_mut
   4: core::slice::index::<impl core::ops::index::IndexMut<I> for [T]>::index_mut
   5: <alloc::vec::Vec<T,A> as core::ops::index::IndexMut<I>>::index_mut
   6: ab_glyph_rasterizer::raster::Rasterizer::draw_line
   7: ab_glyph_rasterizer::raster::Rasterizer::draw_quad
   8: ab_glyph::outlined::OutlinedGlyph::draw::{{closure}}
   9: core::iter::traits::iterator::Iterator::fold
  10: ab_glyph::outlined::OutlinedGlyph::draw
  11: bevy_text::font::Font::get_outlined_glyph_texture
  12: bevy_text::font_atlas_set::FontAtlasSet::add_glyph_to_atlas
  13: bevy_text::glyph_brush::GlyphBrush::process_glyphs::{{closure}}
  14: core::option::Option<T>::unwrap_or_else
  15: bevy_text::glyph_brush::GlyphBrush::process_glyphs
  16: bevy_text::pipeline::TextPipeline<ID>::queue_text
  17: bevy_ui::widget::text::add_text_to_pipeline
  18: bevy_ui::widget::text::text_system
  19: core::ops::function::Fn::call
  20: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &F>::call_mut
  21: <Func as bevy_ecs::system::into_system::IntoSystem<(A,B,C,D,E,F,G),bevy_ecs::system::into_system::FuncSystem<Out>>>::system::{{closure}}
  22: <alloc::boxed::Box<F,A> as core::ops::function::FnMut<Args>>::call_mut
  23: <bevy_ecs::system::into_system::FuncSystem<Out> as bevy_ecs::system::system::System>::run_unsafe
  24: bevy_ecs::schedule::stage_executor::ParallelSystemStageExecutor::run_systems::{{closure}}::{{closure}}
  25: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
  26: async_executor::Executor::spawn::{{closure}}
  27: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
  28: async_task::raw::RawTask<F,T,S>::run
  29: async_task::runnable::Runnable::run
  30: async_executor::Executor::try_tick
  31: bevy_tasks::task_pool::TaskPool::scope
  32: bevy_ecs::schedule::stage_executor::ParallelSystemStageExecutor::run_systems
  33: <bevy_ecs::schedule::stage_executor::ParallelSystemStageExecutor as bevy_ecs::schedule::stage_executor::SystemStageExecutor>::execute_stage
  34: bevy_ecs::schedule::stage::SystemStage::run_once
  35: <bevy_ecs::schedule::stage::SystemStage as bevy_ecs::schedule::stage::Stage>::run
  36: bevy_ecs::schedule::Schedule::run_once
  37: <bevy_ecs::schedule::Schedule as bevy_ecs::schedule::stage::Stage>::run
  38: bevy_ecs::schedule::Schedule::initialize_and_run
  39: bevy_app::app::App::update
  40: bevy_winit::winit_runner::{{closure}}
  41: <alloc::boxed::Box<F,A> as core::ops::function::FnMut<Args>>::call_mut
  42: <winit::platform_impl::platform::app_state::EventLoopHandler<T> as winit::platform_impl::platform::app_state::EventHandler>::handle_nonuser_event
  43: winit::platform_impl::platform::app_state::Handler::handle_nonuser_event
  44: winit::platform_impl::platform::app_state::AppState::cleared
  45: winit::platform_impl::platform::observer::control_flow_end_handler
  46: <unknown>
  47: <unknown>
  48: <unknown>
  49: <unknown>
  50: <unknown>
  51: <unknown>
  52: <unknown>
  53: <unknown>
  54: <unknown>
  55: <unknown>
  56: <() as objc::message::MessageArguments>::invoke
  57: objc::message::platform::send_unverified
  58: winit::platform_impl::platform::event_loop::EventLoop<T>::run_return
  59: winit::platform_impl::platform::event_loop::EventLoop<T>::run
  60: winit::event_loop::EventLoop<T>::run
  61: bevy_winit::run
  62: bevy_winit::winit_runner
  63: core::ops::function::Fn::call
  64: <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call
  65: bevy_app::app::App::run
  66: bevy_app::app_builder::AppBuilder::run
  67: game::main
             at ./src/main.rs:5:5
  68: core::ops::function::FnOnce::call_once
             at /Users/lukaszbiel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

On master game did not crash, just letter v in word hover was not displayed.

Additional information

Seems like there's issue in displaying letter v in this particular font. Some work must've been done since release of 0.4, because master is at least not panicking, but desired goal is to have font render properly. Uppercase V is being displayed.

tigregalis commented 3 years ago

So, I've done a bit of research.

It looks like it's trying to access an index (i.e. write to a pixel) outside the bounding box, so there's an index out of bounds error.

I cloned ab_glyph, downloaded your font, and was able to reproduce the panic, taking bevy out of the equation.

The issue itself probably needs to be handled upstream by ab_glyph (ab_glyph_rasterizer to be exact).

I've found the following issues which are similar to your bevy-0.4.0 and bevy-master respectively. https://github.com/alexheretic/ab-glyph/issues/21 https://github.com/alexheretic/ab-glyph/issues/26

The reason it's outside the bounding box is that the bounding box for the 'v' glyph appears to have dimensions of 0 width and 0 height.

I've traced it back to ttf_parser::glyf::outline_impl which is ultimately just reading binary data.

I cloned ttf_parser and put some dbg!()s in there. Below is for the character 'v' (glyph id = 89):

glyf_table
[src\tables\glyf.rs:560] &range = 7060..7128
[src\tables\glyf.rs:562] &glyph_data = [    
    0,      # -> 
    1,      # -> number of contours = 1
    0,      # --->
    0,      # ---> x_min = 0
    0,      # ----->
    0,      # -----> y_min = 0
    0,      # ------->
    0,      # -------> x_max = 0
    0,      # --------->
    0,      # ---------> y_max = 0
    0,
    15,
    0,
    0,
# ...
]
[src\tables\glyf.rs:606] rect = Rect {
    x_min: 0,
    y_min: 0,
    x_max: 0,
    y_max: 0,
}

By contrast, this is 'w' (glyph id = 90)

glyf_table
[src\tables\glyf.rs:560] &range = 7128..7212
[src\tables\glyf.rs:562] &glyph_data = [    
    0,      # -> 
    1,      # -> number of contours = 1
    0,      # --->
    0,      # ---> x_min = 0
    255,    # ----->
    254,    # -----> y_min = -2
    6,      # ------->
    164,    # -------> x_max = 1700
    5,      # --------->
    20,     # ---------> y_max = 1300
    0,
    28,
    0,
    0,
# ...
]
[src\tables\glyf.rs:606] rect = Rect {
    x_min: 0,
    y_min: -2,
    x_max: 1700,
    y_max: 1300,
}
[examples\outline-glyph.rs:34] bbox = Rect {
    x_min: 0,
    y_min: -2,
    x_max: 1700,
    y_max: 1300,
}

So, it could be that the font itself is corrupt, as it's showing a zero sized bounding box for 'v'. Other text rendering engines handle it fine, so perhaps they have a fallback, or don't use the encoded bounding box, or something like that.

The subpixel work (the biggest/only? difference between bevy 0.4.0 and master) seems to hide this panic for some reason (but still renders nothing). I think it's because it now produces a non-zero-sized bounding box (0 width, 1 high).

The curves themselves seem to be fine, as I tested it with Lyon and successfully rendered a 'v'. image

tigregalis commented 3 years ago

ab_glyph is putting a (work-around) fix in, however, the underlying issue is that the font itself is malformed.

See https://github.com/alexheretic/ab-glyph/issues/29 and https://github.com/RazrFalcon/ttf-parser/issues/49

luke-biel commented 3 years ago

Ye, I'm not shocked that font may be malformed, I dug it up from depths of web. I'll use something else right now till fix is in master.

Thank you very much for swift response and reaction :)

alice-i-cecile commented 3 years ago

The dependency has been updated; closing :) See: https://github.com/alexheretic/ab-glyph/issues/29#issuecomment-764993286