Skip to content
Snippets Groups Projects
Unverified Commit 48ca47bd authored by John's avatar John Committed by GitHub
Browse files

Merge pull request #117 from mwbryant/main

Add support for texture atlases
parents 94606bf0 1ff238b7
No related branches found
No related tags found
No related merge requests found
assets/texture_atlas.png

10.1 KiB

...@@ -16,6 +16,7 @@ use kayak_font::KayakFont; ...@@ -16,6 +16,7 @@ use kayak_font::KayakFont;
pub mod font; pub mod font;
pub mod image; pub mod image;
mod nine_patch; mod nine_patch;
mod texture_atlas;
mod quad; mod quad;
pub struct BevyKayakUIExtractPlugin; pub struct BevyKayakUIExtractPlugin;
...@@ -79,6 +80,11 @@ pub fn extract( ...@@ -79,6 +80,11 @@ pub fn extract(
nine_patch::extract_nine_patch(&render_primitive, &image_manager, &images, dpi); nine_patch::extract_nine_patch(&render_primitive, &image_manager, &images, dpi);
extracted_quads.extend(nine_patch_quads); extracted_quads.extend(nine_patch_quads);
} }
RenderPrimitive::TextureAtlas { .. } => {
let texture_atlas_quads =
texture_atlas::extract_texture_atlas(&render_primitive, &image_manager, &images, dpi);
extracted_quads.extend(texture_atlas_quads);
}
RenderPrimitive::Clip { layout } => { RenderPrimitive::Clip { layout } => {
extracted_quads.push(ExtractQuadBundle { extracted_quads.push(ExtractQuadBundle {
extracted_quad: ExtractedQuad { extracted_quad: ExtractedQuad {
......
use crate::ImageManager;
use bevy::{
math::Vec2,
prelude::{Assets, Res},
render::{color::Color, texture::Image},
sprite::Rect,
};
use bevy_kayak_renderer::{
render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType},
Corner,
};
use kayak_core::render_primitive::RenderPrimitive;
pub fn extract_texture_atlas(
render_primitive: &RenderPrimitive,
image_manager: &Res<ImageManager>,
images: &Res<Assets<Image>>,
dpi: f32,
) -> Vec<ExtractQuadBundle> {
let mut extracted_quads = Vec::new();
let (size, position, layout, handle) = match render_primitive {
RenderPrimitive::TextureAtlas {
size,
position,
layout,
handle,
} => (size, position, layout, handle),
_ => panic!(""),
};
let image_handle = image_manager
.get_handle(handle)
.and_then(|a| Some(a.clone_weak()));
let image = images.get(image_handle.as_ref().unwrap());
if image.is_none() {
return vec![];
}
let image_size = image
.and_then(|i| {
Some(Vec2::new(
i.texture_descriptor.size.width as f32,
i.texture_descriptor.size.height as f32,
))
})
.unwrap()
* dpi;
let quad = ExtractQuadBundle {
extracted_quad: ExtractedQuad {
rect: Rect {
min: Vec2::new(layout.posx, layout.posy),
max: Vec2::new(layout.posx + layout.width, layout.posy + layout.height),
},
uv_min: Some(Vec2::new(
position.0 / image_size.x,
1.0 - ((position.1 + size.1) / image_size.y)
)),
uv_max: Some(Vec2::new(
(position.0 + size.0) / image_size.x,
1.0 - (position.1 / image_size.y),
)),
color: Color::WHITE,
vertex_index: 0,
char_id: 0,
z_index: layout.z_index,
font_handle: None,
quad_type: UIQuadType::Image,
type_index: 0,
border_radius: Corner::default(),
image: image_handle,
},
};
extracted_quads.push(quad);
extracted_quads
}
mod extract;
pub use extract::extract_texture_atlas;
use bevy::{
prelude::{App as BevyApp, AssetServer, Commands, Handle, Res, ResMut},
window::WindowDescriptor,
DefaultPlugins,
};
use kayak_core::styles::PositionType;
use kayak_ui::bevy::{BevyContext, BevyKayakUIPlugin, ImageManager, UICameraBundle};
use kayak_ui::core::{
render,
styles::{Style, StyleProp, Units},
Index,
};
use kayak_ui::widgets::{App, TextureAtlas};
fn startup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut image_manager: ResMut<ImageManager>,
) {
commands.spawn_bundle(UICameraBundle::new());
let image_handle: Handle<bevy::render::texture::Image> = asset_server.load("texture_atlas.png");
let ui_image_handle = image_manager.get(&image_handle);
//texture_atlas.png uses 16 pixel sprites and is 272x128 pixels
let tile_size = 16;
let columns = 272 / tile_size;
let rows = 128 / tile_size;
let atlas = bevy::sprite::TextureAtlas::from_grid(image_handle, bevy::prelude::Vec2::splat(tile_size as f32), columns, rows);
//The sign in the top right of the image would be index 16
let sign_index = 16;
//The flower is in the 6(-1) row and 15 collumn
let flower_index = columns * 5 + 15;
let context = BevyContext::new(|context| {
let atlas_styles = Style {
position_type: StyleProp::Value(PositionType::ParentDirected),
width: StyleProp::Value(Units::Pixels(200.0)),
height: StyleProp::Value(Units::Pixels(200.0)),
..Style::default()
};
let rect = atlas.textures[sign_index];
let sign_position = rect.min;
let sign_size = rect.max - rect.min;
let rect = atlas.textures[flower_index];
let flower_position = rect.min;
let flower_size = rect.max - rect.min;
render! {
<App>
<TextureAtlas styles={Some(atlas_styles)}
handle={ui_image_handle}
position={(sign_position.x, sign_position.y)}
tile_size={(sign_size.x, sign_size.y)}
/>
<TextureAtlas styles={Some(atlas_styles)}
handle={ui_image_handle}
position={(flower_position.x, flower_position.y)}
tile_size={(flower_size.x, flower_size.y)}
/>
</App>
}
});
commands.insert_resource(context);
}
fn main() {
BevyApp::new()
.insert_resource(WindowDescriptor {
width: 1270.0,
height: 720.0,
title: String::from("UI Example"),
..Default::default()
})
.add_plugins(DefaultPlugins)
.add_plugin(BevyKayakUIPlugin)
.add_startup_system(startup)
.run();
}
...@@ -13,6 +13,11 @@ pub enum RenderCommand { ...@@ -13,6 +13,11 @@ pub enum RenderCommand {
Image { Image {
handle: u16, handle: u16,
}, },
TextureAtlas {
position: (f32, f32),
size: (f32, f32),
handle: u16,
},
NinePatch { NinePatch {
border: Edge<f32>, border: Edge<f32>,
handle: u16, handle: u16,
......
...@@ -32,6 +32,12 @@ pub enum RenderPrimitive { ...@@ -32,6 +32,12 @@ pub enum RenderPrimitive {
layout: Rect, layout: Rect,
handle: u16, handle: u16,
}, },
TextureAtlas {
size: (f32, f32),
position: (f32, f32),
layout: Rect,
handle: u16,
},
NinePatch { NinePatch {
border: Edge<f32>, border: Edge<f32>,
layout: Rect, layout: Rect,
...@@ -47,6 +53,7 @@ impl RenderPrimitive { ...@@ -47,6 +53,7 @@ impl RenderPrimitive {
RenderPrimitive::Text { layout, .. } => *layout = new_layout, RenderPrimitive::Text { layout, .. } => *layout = new_layout,
RenderPrimitive::Image { layout, .. } => *layout = new_layout, RenderPrimitive::Image { layout, .. } => *layout = new_layout,
RenderPrimitive::NinePatch { layout, .. } => *layout = new_layout, RenderPrimitive::NinePatch { layout, .. } => *layout = new_layout,
RenderPrimitive::TextureAtlas { layout, .. } => *layout = new_layout,
_ => (), _ => (),
} }
} }
...@@ -98,6 +105,12 @@ impl From<&Style> for RenderPrimitive { ...@@ -98,6 +105,12 @@ impl From<&Style> for RenderPrimitive {
layout: Rect::default(), layout: Rect::default(),
handle, handle,
}, },
RenderCommand::TextureAtlas { handle, size, position, } => Self::TextureAtlas {
handle,
layout: Rect::default(),
size,
position,
},
RenderCommand::NinePatch { handle, border } => Self::NinePatch { RenderCommand::NinePatch { handle, border } => Self::NinePatch {
border, border,
layout: Rect::default(), layout: Rect::default(),
......
...@@ -8,6 +8,7 @@ mod if_element; ...@@ -8,6 +8,7 @@ mod if_element;
mod image; mod image;
mod inspector; mod inspector;
mod nine_patch; mod nine_patch;
mod texture_atlas;
mod on_change; mod on_change;
mod scroll; mod scroll;
mod spin_box; mod spin_box;
...@@ -26,6 +27,7 @@ pub use if_element::*; ...@@ -26,6 +27,7 @@ pub use if_element::*;
pub use image::*; pub use image::*;
pub use inspector::*; pub use inspector::*;
pub use nine_patch::*; pub use nine_patch::*;
pub use texture_atlas::*;
pub use on_change::*; pub use on_change::*;
pub use scroll::*; pub use scroll::*;
pub use spin_box::*; pub use spin_box::*;
......
use kayak_core::OnLayout;
use crate::core::{
render_command::RenderCommand,
rsx,
styles::{Style, StyleProp},
widget, Children, OnEvent, WidgetProps,
};
/// Props used by the [`NinePatch`] widget
#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
pub struct TextureAtlasProps {
/// The handle to image
pub handle: u16,
/// The position of the tile (in pixels)
pub position: (f32, f32),
/// The size of the tile (in pixels)
pub tile_size: (f32, f32),
#[prop_field(Styles)]
pub styles: Option<Style>,
#[prop_field(Children)]
pub children: Option<Children>,
#[prop_field(OnEvent)]
pub on_event: Option<OnEvent>,
#[prop_field(OnLayout)]
pub on_layout: Option<OnLayout>,
#[prop_field(Focusable)]
pub focusable: Option<bool>,
}
#[widget]
/// A widget that renders a texture atlas
/// Allows for the use of a partial square of an image such as in a sprite sheet
///
/// # Props
///
/// __Type:__ [`TextureAtlasProps`]
///
/// | Common Prop | Accepted |
/// | :---------: | :------: |
/// | `children` | ✅ |
/// | `styles` | ✅ |
/// | `on_event` | ✅ |
/// | `on_layout` | ✅ |
/// | `focusable` | ✅ |
///
pub fn TextureAtlas(props: TextureAtlasProps) {
props.styles = Some(Style {
render_command: StyleProp::Value(RenderCommand::TextureAtlas {
position: props.position,
size: props.tile_size,
handle: props.handle,
}),
..props.styles.clone().unwrap_or_default()
});
rsx! {
<>
{children}
</>
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment