-
- BrandonReinhart
- Posts: 29
- Joined:
Custom Unity SpriteAtlas control.
I'm attempting to override Image to provide support for Unity sprite atlases.
The inline usage looks like this:
The backing xaml is mostly empty:
And when I update the sprite the method is:
No matter what I provide for the viewbox I see the entire image. I have confirmed the ImageBrush is working, just that the Viewbox isn't being respected.
What am I missing?
Ah! I figure the mistake is in the assignment of .ImageSource. Not sure how to use the whole ImageBrush.
The inline usage looks like this:
Code: Select all
<local:AtlasImageExt Atlas="WheatAtlas" Region="farm_wheat_01_lvl1" Width="64" Height="64" />Code: Select all
<Image
x:Class="ArchitectOfRuin.AtlasImageExt"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ArchitectOfRuin"
xmlns:noesis="clr-namespace:NoesisGUI">
</Image>Code: Select all
private void UpdateSprite()
{
if (!_spriteAtlas)
return;
if (string.IsNullOrEmpty(Region))
return;
_sprite = _spriteAtlas.GetSprite(Region);
if (!_sprite)
{
Debug.LogError($"Sprite '{Region}' not found in Atlas '{Atlas}'");
return;
}
// Get the sprite texture rect (in pixels).
var spriteRect = _sprite.textureRect;
// var atlasWidth = _sprite.texture.width;
// var atlasHeight = _sprite.texture.height;
// Convert pixel-based rect to normalized UV coordinates.
var x = spriteRect.x;
var y = spriteRect.y;
var width = spriteRect.width;
var height = spriteRect.height;
Source = new ImageBrush
{
ImageSource = new TextureSource(_sprite.texture),
Viewbox = new Rect(x, y, width, height),
ViewboxUnits = BrushMappingMode.Absolute,
TileMode = TileMode.None,
Stretch = Stretch.None
}.ImageSource;
}
What am I missing?
Ah! I figure the mistake is in the assignment of .ImageSource. Not sure how to use the whole ImageBrush.
-
- BrandonReinhart
- Posts: 29
- Joined:
Re: Custom Unity SpriteAtlas control.
I figured it out. I needed to have a UserControl that contained an ImageBrush:
The XAML:
The usage:
Excellent!
Code: Select all
using Noesis;
using UnityEngine;
using UnityEngine.U2D;
using Rect = Noesis.Rect;
namespace ArchitectOfRuin
{
public class AtlasImageExt : UserControl
{
private SpriteAtlas _spriteAtlas;
private Sprite _sprite;
private ImageBrush _imageBrush;
public static readonly DependencyProperty AtlasProperty =
DependencyProperty.Register(
"Atlas",
typeof(string),
typeof(AtlasImageExt),
new PropertyMetadata(null, OnAtlasChanged));
public string Atlas
{
get => (string) GetValue(AtlasProperty);
set => SetValue(AtlasProperty, value);
}
public static readonly DependencyProperty RegionProperty =
DependencyProperty.Register(
"Region",
typeof(string),
typeof(AtlasImageExt),
new PropertyMetadata(null, OnRegionChanged));
public string Region
{
get => (string) GetValue(RegionProperty);
set => SetValue(RegionProperty, value);
}
public AtlasImageExt()
{
InitializeComponent();
}
private void InitializeComponent()
{
NoesisUnity.LoadComponent(this);
LoadAtlas();
UpdateSprite();
}
private static void OnAtlasChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((AtlasImageExt) d).LoadAtlas();
((AtlasImageExt) d).UpdateSprite();
}
private static void OnRegionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((AtlasImageExt) d).UpdateSprite();
}
private void LoadAtlas()
{
if (string.IsNullOrEmpty(Atlas))
return;
_spriteAtlas = AssetStorage<SpriteAtlas>.Get(Atlas);
}
private void UpdateSprite()
{
if (!_spriteAtlas)
return;
if (string.IsNullOrEmpty(Region))
return;
_sprite = _spriteAtlas.GetSprite(Region);
if (!_sprite)
{
Debug.LogError($"Sprite '{Region}' not found in Atlas '{Atlas}'");
return;
}
if (_imageBrush == null)
_imageBrush = new ImageBrush();
var spriteRect = _sprite.textureRect;
var atlasWidth = _sprite.texture.width;
var atlasHeight = _sprite.texture.height;
var x = spriteRect.x;
var y = spriteRect.y;
var width = spriteRect.width;
var height = spriteRect.height;
var flippedY = atlasHeight - y - height;
_imageBrush.ImageSource = new TextureSource(_sprite.texture);
_imageBrush.Viewbox = new Rect(x, flippedY, width, height);
_imageBrush.ViewboxUnits = BrushMappingMode.Absolute;
_imageBrush.TileMode = TileMode.None;
_imageBrush.Stretch = Stretch.None;
var rect = FindName("AtlasImageRect") as Rectangle;
if (rect != null)
rect.Fill = _imageBrush;
}
}
}
Code: Select all
<UserControl
x:Class="ArchitectOfRuin.AtlasImageExt"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ArchitectOfRuin"
xmlns:noesis="clr-namespace:NoesisGUI">
<Rectangle x:Name="AtlasImageRect">
<Rectangle.Fill>
<ImageBrush x:Name="AtlasBrush" />
</Rectangle.Fill>
</Rectangle>
</UserControl>
Code: Select all
<local:AtlasImageExt Atlas="WheatAtlas" Region="farm_wheat_01_lvl1" Width="64" Height="64" />
Re: Custom Unity SpriteAtlas control.
Hey Brandon, sprites (and atlases) are natively supported in our plugin. Have you tried that?
-
- BrandonReinhart
- Posts: 29
- Joined:
Re: Custom Unity SpriteAtlas control.
What's an example? Thanks!
-
- BrandonReinhart
- Posts: 29
- Joined:
Re: Custom Unity SpriteAtlas control.
I see that sprites can be registered with the TextureProvider. How do I get an IconSource from that in code?
Ah! I see, I got this working. I was overthinking it (again). Thank you.
Ah! I see, I got this working. I was overthinking it (again). Thank you.
-
-
sfernandez
Site Admin
- Posts: 3363
- Joined:
Re: Custom Unity SpriteAtlas control.
Our Inventory example uses an Sprite Atlas for showing the inventory icons.
Thanks for the update, I'm going to mark this as solved then.
Thanks for the update, I'm going to mark this as solved then.
Who is online
Users browsing this forum: Bing [Bot] and 3 guests