A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System;
5using osu.Framework.Allocation;
6using osu.Framework.Graphics.Containers;
7using osu.Framework.IO.Stores;
8using osu.Framework.Layout;
9using osuTK;
10using osuTK.Graphics;
11
12namespace osu.Framework.Graphics.Sprites
13{
14 /// <summary>
15 /// A sprite representing an icon.
16 /// Uses <see cref="FontStore"/> to perform character lookups.
17 /// </summary>
18 public class SpriteIcon : CompositeDrawable
19 {
20 private Sprite spriteShadow;
21 private Sprite spriteMain;
22
23 private readonly LayoutValue layout = new LayoutValue(Invalidation.Colour, conditions: (s, _) => ((SpriteIcon)s).Shadow);
24 private Container shadowVisibility;
25
26 private FontStore store;
27
28 public SpriteIcon()
29 {
30 AddLayout(layout);
31 }
32
33 [BackgroundDependencyLoader]
34 private void load(FontStore store)
35 {
36 this.store = store;
37
38 InternalChildren = new Drawable[]
39 {
40 shadowVisibility = new Container
41 {
42 Anchor = Anchor.Centre,
43 Origin = Anchor.Centre,
44 RelativeSizeAxes = Axes.Both,
45 Child = spriteShadow = new Sprite
46 {
47 Anchor = Anchor.Centre,
48 Origin = Anchor.Centre,
49 RelativeSizeAxes = Axes.Both,
50 FillMode = FillMode.Fit,
51 Y = 2,
52 Colour = new Color4(0f, 0f, 0f, 0.2f),
53 },
54 Alpha = shadow ? 1 : 0,
55 },
56 spriteMain = new Sprite
57 {
58 Anchor = Anchor.Centre,
59 Origin = Anchor.Centre,
60 RelativeSizeAxes = Axes.Both,
61 FillMode = FillMode.Fit
62 },
63 };
64
65 updateTexture();
66 }
67
68 protected override void LoadComplete()
69 {
70 base.LoadComplete();
71 updateTexture();
72 }
73
74 private IconUsage loadedIcon;
75
76 private void updateTexture()
77 {
78 var loadableIcon = icon;
79
80 if (loadableIcon.Equals(loadedIcon)) return;
81
82 var glyph = store.Get(loadableIcon.FontName, Icon.Icon);
83
84 if (glyph != null)
85 {
86 spriteMain.Texture = glyph.Texture;
87 spriteShadow.Texture = glyph.Texture;
88
89 if (Size == Vector2.Zero)
90 Size = new Vector2(glyph.Width, glyph.Height);
91 }
92
93 loadedIcon = loadableIcon;
94 }
95
96 protected override void Update()
97 {
98 if (!layout.IsValid)
99 {
100 //adjust shadow alpha based on highest component intensity to avoid muddy display of darker text.
101 //squared result for quadratic fall-off seems to give the best result.
102 var avgColour = (Color4)DrawColourInfo.Colour.AverageColour;
103
104 spriteShadow.Alpha = MathF.Pow(Math.Max(Math.Max(avgColour.R, avgColour.G), avgColour.B), 2);
105
106 layout.Validate();
107 }
108 }
109
110 private bool shadow;
111
112 public bool Shadow
113 {
114 get => shadow;
115 set
116 {
117 shadow = value;
118 if (shadowVisibility != null)
119 shadowVisibility.Alpha = value ? 1 : 0;
120 }
121 }
122
123 private IconUsage icon;
124
125 public IconUsage Icon
126 {
127 get => icon;
128 set
129 {
130 if (icon.Equals(value)) return;
131
132 icon = value;
133 if (LoadState == LoadState.Loaded)
134 updateTexture();
135 }
136 }
137 }
138}