Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Managed texture loading #3297

Merged
merged 64 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
f8cd5f4
add types from proposal
jprochazk Sep 4, 2023
aad9978
add load methods on `egui::Context`
jprochazk Sep 4, 2023
a94b17f
implement loaders from proposal in `egui_extras`
jprochazk Sep 4, 2023
ec79d88
impl `From<Vec2>` for `SizeHint`
jprochazk Sep 4, 2023
1934fba
re-export `SizeHint` from `egui` root
jprochazk Sep 4, 2023
5b113d5
rework `svg` example to use new managed `Image`
jprochazk Sep 4, 2023
c1443b9
split loaders into separate files + add logging
jprochazk Sep 4, 2023
f6efd05
add `log_trace`
jprochazk Sep 4, 2023
652432a
clean up `RetainedImage` from `svg` example
jprochazk Sep 4, 2023
015dc84
refactor ehttp loader response to bytes mapping
jprochazk Sep 4, 2023
80dd53c
remove spammy trace
jprochazk Sep 4, 2023
eceeda8
load images even without extension
jprochazk Sep 4, 2023
022d5a0
fix lints
jprochazk Sep 4, 2023
6819ea3
remove unused imports
jprochazk Sep 4, 2023
d954175
use `Image2` in `download_image`
jprochazk Sep 4, 2023
9ae51a2
use `visuals.error_fg_color` in `Image2` error state
jprochazk Sep 4, 2023
aea252d
update lockfile
jprochazk Sep 4, 2023
c2ecc34
use `Arc<ColorImage>` in `ImageData` + add `forget` API
jprochazk Sep 4, 2023
52f3529
add `ui.image2`
jprochazk Sep 4, 2023
08951f1
add byte size query api
jprochazk Sep 4, 2023
41b074c
use iterators to sum loader byte sizes
jprochazk Sep 4, 2023
6b0a653
add static image loading
jprochazk Sep 4, 2023
3fc03c3
use static image in `svg` example
jprochazk Sep 4, 2023
78f2d93
small refactor of `Image2::ui` texture loading code
jprochazk Sep 4, 2023
4080b8f
add `ImageFit` to size images properly
jprochazk Sep 4, 2023
2584fa8
remove println calls
jprochazk Sep 4, 2023
3182c9d
add bad image load to `download_image` example
jprochazk Sep 4, 2023
ae0c6c1
add loader file extension support tests
jprochazk Sep 4, 2023
4cfec50
fix lint errors in `loaders`
jprochazk Sep 4, 2023
a10a88c
remove unused `poll-promise` dependency
jprochazk Sep 4, 2023
a8ae600
add some docs to `Image2`
jprochazk Sep 4, 2023
08cb30b
add some docs to `egui_extras::loaders::install`
jprochazk Sep 4, 2023
2c8be3c
explain `loaders::install` in examples
jprochazk Sep 4, 2023
808e249
fix lint
jprochazk Sep 5, 2023
1d9a7ed
upgrade `ehttp` to `0.3` for some crates
jprochazk Sep 5, 2023
d109db4
Remove some unused dependencies
emilk Sep 5, 2023
9544b02
Remove unnecessary context clone
emilk Sep 5, 2023
3f194cc
Turn on the `log` create feature of egui_extras in all examples
emilk Sep 5, 2023
2962067
Merge branch 'master' into improved-texture-loading
emilk Sep 5, 2023
0dbaef0
rename `forget` and document it
jprochazk Sep 5, 2023
f6104b9
derive `Debug` on `SizeHint`
jprochazk Sep 5, 2023
1bfd26e
round when converting SizeHint from vec2
jprochazk Sep 5, 2023
2a687b7
add `load` module docs
jprochazk Sep 5, 2023
817b956
docstring `add_loader` methods
jprochazk Sep 5, 2023
b733a58
expose + document `load_include_bytes`
jprochazk Sep 5, 2023
1aacf42
cache texture handles in `DefaultTextureLoader`
jprochazk Sep 5, 2023
356d7ef
add `image2` doctest + further document `Image2`
jprochazk Sep 5, 2023
0d28132
use `Default` for default `Image2` options
jprochazk Sep 5, 2023
afa3ef3
update `image2` doc comment
jprochazk Sep 5, 2023
a3c890d
mention immediate-mode safety
jprochazk Sep 5, 2023
f975d83
more fit calculation into inherent impl
jprochazk Sep 5, 2023
98ddf02
add hover text on spinner
jprochazk Sep 5, 2023
2736cb5
add `all-loaders` feature
jprochazk Sep 5, 2023
ef71ea2
clarify `egui_extras::loaders::install` behavior
jprochazk Sep 5, 2023
76b5e74
explain how to enable image formats
jprochazk Sep 5, 2023
30f0e0f
properly format `uri`
jprochazk Sep 5, 2023
c84e9ab
use `thread::Builder` instead of `spawn`
jprochazk Sep 5, 2023
d21e74e
use eq op instead of `matches`
jprochazk Sep 5, 2023
59cd614
inline `From<Arc<ColorImage>>` for `ImageData`
jprochazk Sep 5, 2023
4206355
allow non-`'static` bytes + `forget` in `DefaultTextureLoader`
jprochazk Sep 6, 2023
f0e9733
sort features
jprochazk Sep 6, 2023
049122f
change `ehttp` feature to `http`
jprochazk Sep 6, 2023
c8a8074
update `Image2` docs
jprochazk Sep 6, 2023
ef7e946
refactor loader cache type
jprochazk Sep 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

155 changes: 155 additions & 0 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ struct ContextImpl {
is_accesskit_enabled: bool,
#[cfg(feature = "accesskit")]
accesskit_node_classes: accesskit::NodeClassSet,

loaders: load::Loaders,
}

impl ContextImpl {
Expand Down Expand Up @@ -1901,6 +1903,159 @@ impl Context {
}
}

/// ## Image loading
impl Context {
/// Associate some static bytes with a `uri`.
///
/// The same `uri` may be passed to [`Ui::image2`] later to load the bytes as an image.
pub fn include_static_bytes(&self, uri: &'static str, bytes: &'static [u8]) {
self.read(|ctx| ctx.loaders.include.insert_static(uri, bytes));
}

/// Associate some bytes with a `uri`.
///
/// The same `uri` may be passed to [`Ui::image2`] later to load the bytes as an image.
pub fn include_bytes(&self, uri: &'static str, bytes: impl Into<Arc<[u8]>>) {
jprochazk marked this conversation as resolved.
Show resolved Hide resolved
self.read(|ctx| ctx.loaders.include.insert_shared(uri, bytes));
}

/// Append an entry onto the chain of bytes loaders.
///
/// See [`load`] for more information.
pub fn add_bytes_loader(&self, loader: Arc<dyn load::BytesLoader + Send + Sync + 'static>) {
self.write(|ctx| ctx.loaders.bytes.push(loader));
}

/// Append an entry onto the chain of image loaders.
///
/// See [`load`] for more information.
pub fn add_image_loader(&self, loader: Arc<dyn load::ImageLoader + Send + Sync + 'static>) {
self.write(|ctx| ctx.loaders.image.push(loader));
}

/// Append an entry onto the chain of texture loaders.
///
/// See [`load`] for more information.
pub fn add_texture_loader(&self, loader: Arc<dyn load::TextureLoader + Send + Sync + 'static>) {
self.write(|ctx| ctx.loaders.texture.push(loader));
}

/// Release all memory and textures related to the given image URI.
///
/// If you attempt to load the image again, it will be reloaded from scratch.
pub fn forget_image(&self, uri: &str) {
self.write(|ctx| {
use crate::load::BytesLoader as _;

ctx.loaders.include.forget(uri);

for loader in &ctx.loaders.bytes {
loader.forget(uri);
}

for loader in &ctx.loaders.image {
loader.forget(uri);
}

for loader in &ctx.loaders.texture {
loader.forget(uri);
}
});
}

/// Try loading the bytes from the given uri using any available bytes loaders.
///
/// Loaders are expected to cache results, so that this call is immediate-mode safe.
///
/// This calls the loaders one by one in the order in which they were registered.
/// If a loader returns [`LoadError::NotSupported`][not_supported],
/// then the next loader is called. This process repeats until all loaders have
/// been exhausted, at which point this returns [`LoadError::NotSupported`][not_supported].
///
/// # Errors
/// This may fail with:
/// - [`LoadError::NotSupported`][not_supported] if none of the registered loaders support loading the given `uri`.
/// - [`LoadError::Custom`][custom] if one of the loaders _does_ support loading the `uri`, but the loading process failed.
///
/// [not_supported]: crate::load::LoadError::NotSupported
/// [custom]: crate::load::LoadError::Custom
pub fn try_load_bytes(&self, uri: &str) -> load::BytesLoadResult {
self.read(|this| {
for loader in &this.loaders.bytes {
match loader.load(self, uri) {
Err(load::LoadError::NotSupported) => continue,
result => return result,
}
}

Err(load::LoadError::NotSupported)
})
}

/// Try loading the image from the given uri using any available image loaders.
///
/// Loaders are expected to cache results, so that this call is immediate-mode safe.
///
/// This calls the loaders one by one in the order in which they were registered.
/// If a loader returns [`LoadError::NotSupported`][not_supported],
/// then the next loader is called. This process repeats until all loaders have
/// been exhausted, at which point this returns [`LoadError::NotSupported`][not_supported].
///
/// # Errors
/// This may fail with:
/// - [`LoadError::NotSupported`][not_supported] if none of the registered loaders support loading the given `uri`.
/// - [`LoadError::Custom`][custom] if one of the loaders _does_ support loading the `uri`, but the loading process failed.
///
/// [not_supported]: crate::load::LoadError::NotSupported
/// [custom]: crate::load::LoadError::Custom
pub fn try_load_image(&self, uri: &str, size_hint: load::SizeHint) -> load::ImageLoadResult {
self.read(|this| {
for loader in &this.loaders.image {
match loader.load(self, uri, size_hint) {
Err(load::LoadError::NotSupported) => continue,
result => return result,
}
}

Err(load::LoadError::NotSupported)
})
}

/// Try loading the texture from the given uri using any available texture loaders.
///
/// Loaders are expected to cache results, so that this call is immediate-mode safe.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

We should consider how we can alert the user of methods that aren't immediate safe, most notably the old Context::load_texture. Adding a ⚠️ Not immediate-mode safe warning to them might be a start, but perhaps we could also add it to their name somehow. load_texture_sync or something.

///
/// This calls the loaders one by one in the order in which they were registered.
/// If a loader returns [`LoadError::NotSupported`][not_supported],
/// then the next loader is called. This process repeats until all loaders have
/// been exhausted, at which point this returns [`LoadError::NotSupported`][not_supported].
///
/// # Errors
/// This may fail with:
/// - [`LoadError::NotSupported`][not_supported] if none of the registered loaders support loading the given `uri`.
/// - [`LoadError::Custom`][custom] if one of the loaders _does_ support loading the `uri`, but the loading process failed.
///
/// [not_supported]: crate::load::LoadError::NotSupported
/// [custom]: crate::load::LoadError::Custom
pub fn try_load_texture(
jprochazk marked this conversation as resolved.
Show resolved Hide resolved
&self,
uri: &str,
texture_options: TextureOptions,
size_hint: load::SizeHint,
) -> load::TextureLoadResult {
self.read(|this| {
for loader in &this.loaders.texture {
match loader.load(self, uri, texture_options, size_hint) {
Err(load::LoadError::NotSupported) => continue,
result => return result,
}
}

Err(load::LoadError::NotSupported)
})
}
}

#[test]
fn context_impl_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
Expand Down
2 changes: 2 additions & 0 deletions crates/egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ mod input_state;
pub mod introspection;
pub mod layers;
mod layout;
pub mod load;
mod memory;
pub mod menu;
pub mod os;
Expand Down Expand Up @@ -370,6 +371,7 @@ pub use {
input_state::{InputState, MultiTouchInfo, PointerState},
layers::{LayerId, Order},
layout::*,
load::SizeHint,
memory::{Memory, Options},
painter::Painter,
response::{InnerResponse, Response},
Expand Down
Loading
Loading