Fix UI texture atlas with offset (#13620)

# Objective

- Fixes #11219 

## Solution

- Scaling calculations use texture dimensions instead of layout
dimensions.

## Testing

- Did you test these changes? If so, how?

All UI examples look fine.

- How can other people (reviewers) test your changes? Is there anything
specific they need to know?

Example in #11219

## Migration Guide

```diff
let ui_node = ExtractedUiNode {
                    stack_index,
                    transform,
                    color,
                    rect,
                    image,
-                   atlas_size: Some(atlas_size * scale_factor),      
+                   atlas_scaling: Some(Vec2::splat(scale_factor)),
                    clip,
                    flip_x,
                    flip_y,
                    camera_entity,
                    border,
                    border_radius,
                    node_type,
                },
```

```diff
let computed_slices = ComputedTextureSlices {
    slices,
-    image_size,
}
```
This commit is contained in:
s-puig 2024-07-30 17:31:58 +02:00 committed by GitHub
parent d722fef23d
commit ba09f35474
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 27 deletions

View File

@ -163,7 +163,7 @@ pub struct ExtractedUiNode {
pub color: LinearRgba,
pub rect: Rect,
pub image: AssetId<Image>,
pub atlas_size: Option<Vec2>,
pub atlas_scaling: Option<Vec2>,
pub clip: Option<Rect>,
pub flip_x: bool,
pub flip_y: bool,
@ -278,7 +278,7 @@ pub fn extract_uinode_background_colors(
},
clip: clip.map(|clip| clip.clip),
image: AssetId::default(),
atlas_size: None,
atlas_scaling: None,
flip_x: false,
flip_y: false,
camera_entity,
@ -351,19 +351,17 @@ pub fn extract_uinode_images(
continue;
}
let (rect, atlas_size) = match atlas {
let (rect, atlas_scaling) = match atlas {
Some(atlas) => {
let Some(layout) = texture_atlases.get(&atlas.layout) else {
// Atlas not present in assets resource (should this warn the user?)
continue;
};
let mut atlas_rect = layout.textures[atlas.index].as_rect();
let mut atlas_size = layout.size.as_vec2();
let scale = uinode.size() / atlas_rect.size();
atlas_rect.min *= scale;
atlas_rect.max *= scale;
atlas_size *= scale;
(atlas_rect, Some(atlas_size))
let atlas_scaling = uinode.size() / atlas_rect.size();
atlas_rect.min *= atlas_scaling;
atlas_rect.max *= atlas_scaling;
(atlas_rect, Some(atlas_scaling))
}
None => (
Rect {
@ -420,7 +418,7 @@ pub fn extract_uinode_images(
rect,
clip: clip.map(|clip| clip.clip),
image: image.texture.id(),
atlas_size,
atlas_scaling,
flip_x: image.flip_x,
flip_y: image.flip_y,
camera_entity,
@ -598,7 +596,7 @@ pub fn extract_uinode_borders(
..Default::default()
},
image,
atlas_size: None,
atlas_scaling: None,
clip: clip.map(|clip| clip.clip),
flip_x: false,
flip_y: false,
@ -691,7 +689,7 @@ pub fn extract_uinode_outlines(
..Default::default()
},
image,
atlas_size: None,
atlas_scaling: None,
clip: maybe_clip.map(|clip| clip.clip),
flip_x: false,
flip_y: false,
@ -873,7 +871,7 @@ pub fn extract_uinode_text(
color,
rect,
image: atlas_info.texture.id(),
atlas_size: Some(atlas.size.as_vec2() * inverse_scale_factor),
atlas_scaling: Some(Vec2::splat(inverse_scale_factor)),
clip: clip.map(|clip| clip.clip),
flip_x: false,
flip_y: false,
@ -1175,7 +1173,14 @@ pub fn prepare_uinodes(
let uvs = if flags == shader_flags::UNTEXTURED {
[Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y]
} else {
let atlas_extent = extracted_uinode.atlas_size.unwrap_or(uinode_rect.max);
let image = gpu_images
.get(extracted_uinode.image)
.expect("Image was checked during batching and should still exist");
// Rescale atlases. This is done here because we need texture data that might not be available in Extract.
let atlas_extent = extracted_uinode
.atlas_scaling
.map(|scaling| image.size.as_vec2() * scaling)
.unwrap_or(uinode_rect.max);
if extracted_uinode.flip_x {
std::mem::swap(&mut uinode_rect.max.x, &mut uinode_rect.min.x);
positions_diff[0].x *= -1.;

View File

@ -18,7 +18,6 @@ use crate::{CalculatedClip, ExtractedUiNode, Node, NodeType, UiImage};
#[derive(Debug, Clone, Component)]
pub struct ComputedTextureSlices {
slices: Vec<TextureSlice>,
image_size: Vec2,
}
impl ComputedTextureSlices {
@ -56,7 +55,6 @@ impl ComputedTextureSlices {
let mut rect = slice.texture_rect;
rect.min *= scale;
rect.max *= scale;
let atlas_size = Some(self.image_size * scale);
ExtractedUiNode {
stack_index: node.stack_index,
color: image.color.into(),
@ -65,7 +63,7 @@ impl ComputedTextureSlices {
flip_x,
flip_y,
image: image.texture.id(),
atlas_size,
atlas_scaling: Some(scale),
clip: clip.map(|clip| clip.clip),
camera_entity,
border: [0.; 4],
@ -99,13 +97,10 @@ fn compute_texture_slices(
atlas: Option<&TextureAtlas>,
atlas_layouts: &Assets<TextureAtlasLayout>,
) -> Option<ComputedTextureSlices> {
let (image_size, texture_rect) = match atlas {
let texture_rect = match atlas {
Some(a) => {
let layout = atlas_layouts.get(&a.layout)?;
(
layout.size.as_vec2(),
layout.textures.get(a.index)?.as_rect(),
)
layout.textures.get(a.index)?.as_rect()
}
None => {
let image = images.get(&image_handle.texture)?;
@ -113,11 +108,10 @@ fn compute_texture_slices(
image.texture_descriptor.size.width as f32,
image.texture_descriptor.size.height as f32,
);
let rect = Rect {
Rect {
min: Vec2::ZERO,
max: size,
};
(size, rect)
}
}
};
let slices = match scale_mode {
@ -135,7 +129,7 @@ fn compute_texture_slices(
slice.tiled(*stretch_value, (*tile_x, *tile_y))
}
};
Some(ComputedTextureSlices { slices, image_size })
Some(ComputedTextureSlices { slices })
}
/// System reacting to added or modified [`Image`] handles, and recompute sprite slices

View File

@ -50,7 +50,8 @@ fn setup(
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
) {
let texture_handle = asset_server.load("textures/fantasy_ui_borders/border_sheet.png");
let atlas_layout = TextureAtlasLayout::from_grid(UVec2::new(50, 50), 6, 6, None, None);
let atlas_layout =
TextureAtlasLayout::from_grid(UVec2::new(50, 50), 6, 6, Some(UVec2::splat(2)), None);
let atlas_layout_handle = texture_atlases.add(atlas_layout);
let slicer = TextureSlicer {