Client LuaCsForBarotrauma
GUIImage.cs
1 using Microsoft.Xna.Framework;
2 using Microsoft.Xna.Framework.Graphics;
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Threading.Tasks;
7 
8 namespace Barotrauma
9 {
10  public class GUIImage : GUIComponent
11  {
12  //paths of the textures that are being loaded asynchronously
13  private static readonly List<string> activeTextureLoads = new List<string>();
14 
15  private static bool loadingTextures;
16 
17  public static bool LoadingTextures
18  {
19  get
20  {
21  return loadingTextures;
22  }
23  }
24 
25  public float Rotation;
26 
27  private Sprite sprite;
28 
29  private Rectangle sourceRect;
30 
31  private bool crop;
32 
33  private readonly bool scaleToFit;
34 
35  private bool lazyLoaded, loading;
36 
37  public bool LoadAsynchronously;
38 
39  public bool Crop
40  {
41  get
42  {
43  return crop;
44  }
45  }
46 
47  public void SetCrop(bool state, bool center = true)
48  {
49  crop = state;
50  if (crop && sprite != null)
51  {
52  sourceRect.Width = Math.Min(sprite.SourceRect.Width, (int)(Rect.Width / Scale));
53  sourceRect.Height = Math.Min(sprite.SourceRect.Height, (int)(Rect.Height / Scale));
54 
55  if (center)
56  {
57  sourceRect.X = (sprite.SourceRect.Width - sourceRect.Width) / 2;
58  sourceRect.Y = (sprite.SourceRect.Height - sourceRect.Height) / 2;
59  }
60 
61  origin = sourceRect.Size.ToVector2() / 2;
62  }
63  else
64  {
65  origin = sprite == null ? Vector2.Zero : sprite.size / 2;
66  }
67  }
68 
69  private Vector2 origin;
70 
71  public float Scale
72  {
73  get;
74  set;
75  }
76 
78  {
79  get { return sourceRect; }
80  set { sourceRect = value; }
81  }
82 
83  public Sprite Sprite
84  {
85  get { return sprite; }
86  set
87  {
88  if (sprite == value) { return; }
89  sprite = value;
90  sourceRect = value == null ? Rectangle.Empty : value.SourceRect;
91  origin = value == null ? Vector2.Zero : value.size / 2;
92  if (scaleToFit) { RecalculateScale(); }
93  }
94  }
95 
97 
98  public ComponentState? OverrideState = null;
99 
100  public GUIImage(RectTransform rectT, string style, bool scaleToFit = false)
101  : this(rectT, null, null, scaleToFit, style)
102  {
103  }
104 
105  public GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect = null, bool scaleToFit = false)
106  : this(rectT, sprite, sourceRect, scaleToFit, null)
107  {
108  }
109 
110  private GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect, bool scaleToFit, string style) : base(style, rectT)
111  {
112  this.scaleToFit = scaleToFit;
113  Sprite = sprite;
114  if (sourceRect.HasValue)
115  {
116  this.sourceRect = sourceRect.Value;
117  }
118  else
119  {
120  this.sourceRect = sprite == null ? Rectangle.Empty : sprite.SourceRect;
121  }
122  if (style == null)
123  {
125  }
126  if (!scaleToFit)
127  {
128  Scale = 1.0f;
129  }
130  else
131  {
132  if (Sprite != null && !Sprite.LazyLoad)
133  {
134  rectT.SizeChanged += RecalculateScale;
135  }
136  }
137  Enabled = true;
138  }
139 
140  protected override void Draw(SpriteBatch spriteBatch)
141  {
142  if (!Visible || loading) { return; }
143 
144  if (Parent != null) { State = Parent.State; }
145  if (OverrideState != null) { State = OverrideState.Value; }
146 
147  if (Sprite != null && Sprite.LazyLoad && !lazyLoaded)
148  {
149  if (LoadAsynchronously)
150  {
151  loadingTextures = true;
152  loading = true;
153  TaskPool.Add("LoadTextureAsync",
154  LoadTextureAsync(), task =>
155  {
156  if (task.Exception != null)
157  {
158  var innerMost = task.Exception.GetInnermost();
159  DebugConsole.ThrowError($"Failed to load \"{Sprite.FilePath}\"", innerMost);
160  }
161  loading = false;
162  lazyLoaded = true;
163  RectTransform.SizeChanged += RecalculateScale;
164  RecalculateScale();
165  });
166  return;
167  }
168  else
169  {
171  RectTransform.SizeChanged += RecalculateScale;
172  RecalculateScale();
173  lazyLoaded = true;
174  }
175  }
176 
177  Color currentColor = GetColor(State);
178 
179  if (BlendState != null)
180  {
181  spriteBatch.End();
182  spriteBatch.Begin(blendState: BlendState, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
183  }
184 
185  var style = Style;
186  if (style != null)
187  {
188  foreach (UISprite uiSprite in style.Sprites[State])
189  {
190  if (Math.Abs(Rotation) > float.Epsilon)
191  {
192  float scale = Math.Min(Rect.Width / uiSprite.Sprite.size.X, Rect.Height / uiSprite.Sprite.size.Y);
193  spriteBatch.Draw(uiSprite.Sprite.Texture, Rect.Center.ToVector2(), uiSprite.Sprite.SourceRect, currentColor * (currentColor.A / 255.0f), Rotation, uiSprite.Sprite.size / 2,
194  Scale * scale, SpriteEffects, 0.0f);
195  }
196  else
197  {
198  uiSprite.Draw(spriteBatch, Rect, currentColor * (currentColor.A / 255.0f), SpriteEffects);
199  }
200  }
201  }
202  else if (sprite?.Texture is { IsDisposed: false })
203  {
204  spriteBatch.Draw(sprite.Texture, new Vector2(Rect.X + Rect.Width / 2.0f, Rect.Y + Rect.Height / 2.0f), sourceRect, currentColor * (currentColor.A / 255.0f), Rotation, origin,
205  Scale, SpriteEffects, 0.0f);
206  }
207 
208  if (BlendState != null)
209  {
210  spriteBatch.End();
211  spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
212  }
213  }
214 
215  private void RecalculateScale()
216  {
217  if (sourceRect == Rectangle.Empty && sprite != null)
218  {
219  sourceRect = sprite.SourceRect;
220  }
221 
222  Scale = sprite == null || sprite.SourceRect.Width == 0 || sprite.SourceRect.Height == 0 ?
223  1.0f :
224  Math.Min(RectTransform.Rect.Width / (float)sprite.SourceRect.Width, RectTransform.Rect.Height / (float)sprite.SourceRect.Height);
225  }
226 
227  private async Task<bool> LoadTextureAsync()
228  {
229  await Task.Yield();
230  bool wait = true;
231  {
232  //if another GUIImage is already loading the same texture, wait for it to finish
233  while (wait)
234  {
235  await Task.Delay(5);
236  lock (activeTextureLoads)
237  {
238  wait = activeTextureLoads.Contains(Sprite.FullPath);
239  }
240  }
241  }
242  try
243  {
244  lock (activeTextureLoads)
245  {
246  activeTextureLoads.Add(Sprite.FullPath);
247  }
248  await Sprite.LazyLoadAsync();
249  }
250  finally
251  {
252  DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
253  while (!Sprite.Loaded && DateTime.Now < timeOut)
254  {
255  await Task.Delay(5);
256  }
257  lock (activeTextureLoads)
258  {
259  activeTextureLoads.Remove(Sprite.FullPath);
260  loadingTextures = activeTextureLoads.Count > 0;
261  }
262  }
263  return true;
264  }
265  }
266 }
virtual ComponentState State
virtual Color GetColor(ComponentState state)
virtual Rectangle Rect
GUIComponentStyle Style
RectTransform RectTransform
SpriteEffects SpriteEffects
void SetCrop(bool state, bool center=true)
Definition: GUIImage.cs:47
ComponentState? OverrideState
Definition: GUIImage.cs:98
BlendState BlendState
Definition: GUIImage.cs:96
bool LoadAsynchronously
Definition: GUIImage.cs:37
Sprite?? Sprite
Definition: GUIImage.cs:84
GUIImage(RectTransform rectT, string style, bool scaleToFit=false)
Definition: GUIImage.cs:100
override void Draw(SpriteBatch spriteBatch)
Definition: GUIImage.cs:140
static bool LoadingTextures
Definition: GUIImage.cs:18
Rectangle SourceRect
Definition: GUIImage.cs:78
GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect=null, bool scaleToFit=false)
Definition: GUIImage.cs:105
static RasterizerState ScissorTestEnable
Definition: GameMain.cs:195
void Draw(SpriteBatch spriteBatch, RectangleF rect, Color color, SpriteEffects spriteEffects=SpriteEffects.None, Vector2? uvOffset=null)