(d9829ac) v0.9.4.0

This commit is contained in:
Regalis
2019-10-24 18:05:42 +02:00
parent 9aa12bcac2
commit b39922a074
319 changed files with 12516 additions and 6815 deletions
@@ -0,0 +1,142 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using SpriteParams = Barotrauma.RagdollParams.SpriteParams;
namespace Barotrauma
{
class DecorativeSprite : ISerializableEntity
{
public string Name => $"Decorative Sprite";
public Dictionary<string, SerializableProperty> SerializableProperties { get; set; }
public Sprite Sprite { get; private set; }
public enum AnimationType
{
None,
Sine,
Noise
}
[Serialize("0,0", true), Editable]
public Vector2 Offset { get; private set; }
[Serialize(AnimationType.None, false), Editable]
public AnimationType OffsetAnim { get; private set; }
[Serialize(0.0f, true), Editable]
public float OffsetAnimSpeed { get; private set; }
private float rotationSpeedRadians;
[Serialize(0.0f, true), Editable]
public float RotationSpeed
{
get
{
return MathHelper.ToDegrees(rotationSpeedRadians);
}
private set
{
rotationSpeedRadians = MathHelper.ToRadians(value);
}
}
[Serialize(0.0f, true), Editable]
public float Rotation { get; private set; }
[Serialize(AnimationType.None, false), Editable]
public AnimationType RotationAnim { get; private set; }
/// <summary>
/// If > 0, only one sprite of the same group is used (chosen randomly)
/// </summary>
[Serialize(0, false, description: "If > 0, only one sprite of the same group is used (chosen randomly)"), Editable(ReadOnly = true)]
public int RandomGroupID { get; private set; }
/// <summary>
/// The sprite is only drawn if these conditions are fulfilled
/// </summary>
internal List<PropertyConditional> IsActiveConditionals { get; private set; } = new List<PropertyConditional>();
/// <summary>
/// The sprite is only animated if these conditions are fulfilled
/// </summary>
internal List<PropertyConditional> AnimationConditionals { get; private set; } = new List<PropertyConditional>();
public DecorativeSprite(XElement element, string path = "", string file = "", bool lazyLoad = false)
{
Sprite = new Sprite(element, path, file, lazyLoad: lazyLoad);
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
foreach (XElement subElement in element.Elements())
{
List<PropertyConditional> conditionalList = null;
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "conditional":
case "isactiveconditional":
conditionalList = IsActiveConditionals;
break;
case "animationconditional":
conditionalList = AnimationConditionals;
break;
default:
continue;
}
foreach (XAttribute attribute in subElement.Attributes())
{
if (attribute.Name.ToString().ToLowerInvariant() == "targetitemcomponent") { continue; }
conditionalList.Add(new PropertyConditional(attribute));
}
}
}
public Vector2 GetOffset(ref float offsetState)
{
if (OffsetAnimSpeed <= 0.0f)
{
return Offset;
}
switch (OffsetAnim)
{
case AnimationType.Sine:
offsetState = offsetState % (MathHelper.TwoPi / OffsetAnimSpeed);
return Offset * (float)Math.Sin(offsetState * OffsetAnimSpeed);
case AnimationType.Noise:
offsetState = offsetState % (1.0f / (OffsetAnimSpeed * 0.1f));
float t = offsetState * 0.1f * OffsetAnimSpeed;
return new Vector2(
Offset.X * (PerlinNoise.GetPerlin(t, t) - 0.5f),
Offset.Y * (PerlinNoise.GetPerlin(t + 0.5f, t + 0.5f) - 0.5f));
default:
return Offset;
}
}
public float GetRotation(ref float rotationState)
{
if (rotationSpeedRadians <= 0.0f)
{
return Rotation;
}
switch (OffsetAnim)
{
case AnimationType.Sine:
rotationState = rotationState % (MathHelper.TwoPi / rotationSpeedRadians);
return Rotation * (float)Math.Sin(rotationState * rotationSpeedRadians);
case AnimationType.Noise:
rotationState = rotationState % (1.0f / rotationSpeedRadians);
return Rotation * PerlinNoise.GetPerlin(rotationState * rotationSpeedRadians, rotationState * rotationSpeedRadians);
default:
return rotationState * rotationSpeedRadians;
}
}
public void Remove()
{
Sprite?.Remove();
Sprite = null;
}
}
}
@@ -8,13 +8,12 @@ namespace Barotrauma.SpriteDeformations
{
class CustomDeformationParams : SpriteDeformationParams
{
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f,
ToolTip = "How fast the deformation \"oscillates\" back and forth. " +
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f),
Serialize(0.0f, true, description: "How fast the deformation \"oscillates\" back and forth. " +
"For example, if the sprite is stretched up, setting this value above zero would make it do a wave-like movement up and down.")]
public override float Frequency { get; set; } = 1;
[Serialize(1.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f,
ToolTip = "The \"strength\" of the deformation.")]
[Serialize(1.0f, true, description: "The \"strength\" of the deformation."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
public float Amplitude { get; set; }
public CustomDeformationParams(XElement element) : base(element)
@@ -26,7 +25,7 @@ namespace Barotrauma.SpriteDeformations
{
private List<Vector2[]> deformRows = new List<Vector2[]>();
private CustomDeformationParams CustomDeformationParams => deformationParams as CustomDeformationParams;
private CustomDeformationParams CustomDeformationParams => Params as CustomDeformationParams;
public override float Phase
{
@@ -116,11 +115,12 @@ namespace Barotrauma.SpriteDeformations
multiplier = CustomDeformationParams.Frequency <= 0.0f ?
CustomDeformationParams.Amplitude :
(float)Math.Sin(phase) * CustomDeformationParams.Amplitude;
multiplier *= Params.Strength;
}
public override void Update(float deltaTime)
{
if (!deformationParams.UseMovementSine)
if (!Params.UseMovementSine)
{
phase += deltaTime * CustomDeformationParams.Frequency;
phase %= MathHelper.TwoPi;
@@ -31,7 +31,7 @@ namespace Barotrauma.SpriteDeformations
private Vector2[,] deformation;
private InflateParams InflateParams => deformationParams as InflateParams;
private InflateParams InflateParams => Params as InflateParams;
public Inflate(XElement element) : base(element, new InflateParams(element))
{
@@ -58,11 +58,12 @@ namespace Barotrauma.SpriteDeformations
{
deformation = this.deformation;
multiplier = InflateParams.Frequency <= 0.0f ? InflateParams.Scale : (float)(Math.Sin(phase) + 1.0f) / 2.0f * InflateParams.Scale;
multiplier *= Params.Strength;
}
public override void Update(float deltaTime)
{
if (!deformationParams.UseMovementSine)
if (!Params.UseMovementSine)
{
phase += deltaTime * InflateParams.Frequency;
phase %= MathHelper.TwoPi;
@@ -21,7 +21,7 @@ namespace Barotrauma.SpriteDeformations
public float BendRight
{
get { return bendRight; }
set { bendRight = MathHelper.Clamp(value, -maxRotation, maxRotation); }
set { bendRight = MathHelper.Clamp(value, -MaxRotationInRadians, MaxRotationInRadians); }
}
//the pivot point to rotate the right side around
public Vector2 BendRightRefPos = new Vector2(1.0f, 0.5f);
@@ -30,7 +30,7 @@ namespace Barotrauma.SpriteDeformations
public float BendLeft
{
get { return bendLeft; }
set { bendLeft = MathHelper.Clamp(value, -maxRotation, maxRotation); }
set { bendLeft = MathHelper.Clamp(value, -MaxRotationInRadians, MaxRotationInRadians); }
}
public Vector2 BendLeftRefPos = new Vector2(0.0f, 0.5f);
@@ -38,7 +38,7 @@ namespace Barotrauma.SpriteDeformations
public float BendUp
{
get { return bendUp; }
set { bendUp = MathHelper.Clamp(value, -maxRotation, maxRotation); }
set { bendUp = MathHelper.Clamp(value, -MaxRotationInRadians, MaxRotationInRadians); }
}
public Vector2 BendUpRefPos = new Vector2(0.5f, 0.0f);
@@ -46,18 +46,15 @@ namespace Barotrauma.SpriteDeformations
public float BendDown
{
get { return bendDown; }
set { bendDown = MathHelper.Clamp(value, -maxRotation, maxRotation); }
set { bendDown = MathHelper.Clamp(value, -MaxRotationInRadians, MaxRotationInRadians); }
}
public Vector2 BendDownRefPos = new Vector2(0.5f, 1.0f);
public Vector2 Scale = Vector2.Zero;
private float maxRotation;
private float MaxRotationInRadians => MathHelper.ToRadians(Params.MaxRotation);
public JointBendDeformation(XElement element) : base(element, new JointBendDeformationParams(element))
{
maxRotation = MathHelper.ToRadians(element == null ? 90.0f : element.GetAttributeFloat("maxrotation", 90.0f));
}
public JointBendDeformation(XElement element) : base(element, new JointBendDeformationParams(element)) { }
protected override void GetDeformation(out Vector2[,] deformation, out float multiplier)
{
@@ -80,7 +77,7 @@ namespace Barotrauma.SpriteDeformations
{
float strength = 1.0f - normalizedPos.X;//(1.0f - Math.Max(normalizedPos.X - BendLeftRefPos.X, 0.0f) / (1.0f - BendLeftRefPos.X));
strength = Math.Max((strength - 0.5f) * 2.0f, 0.0f);
Vector2 rotatedP = RotatePointAroundTarget(normalizedPos, BendLeftRefPos, BendLeft * strength);
Vector2 rotatedP = RotatePointAroundTarget(normalizedPos, BendLeftRefPos, BendLeft * strength * Params.Strength);
Vector2 offset = rotatedP - normalizedPos;
offset.X *= Scale.Y / Scale.X;
Deformation[x, y] += offset;
@@ -89,7 +86,7 @@ namespace Barotrauma.SpriteDeformations
{
float strength = normalizedPos.X;//(1.0f - Math.Max(BendRightRefPos.X - normalizedPos.X, 0.0f) / (BendRightRefPos.X));
strength = Math.Max((strength - 0.5f) * 2.0f, 0.0f);
Vector2 rotatedP = RotatePointAroundTarget(normalizedPos, BendRightRefPos, BendRight * strength);
Vector2 rotatedP = RotatePointAroundTarget(normalizedPos, BendRightRefPos, BendRight * strength * Params.Strength);
Vector2 offset = rotatedP - normalizedPos;
offset.X *= Scale.Y / Scale.X;
Deformation[x, y] += offset;
@@ -99,7 +96,7 @@ namespace Barotrauma.SpriteDeformations
{
float strength = 1.0f - normalizedPos.Y;//(1.0f - Math.Max(normalizedPos.Y - BendUpRefPos.Y, 0.0f) / (1.0f - BendUpRefPos.Y));
strength = Math.Max((strength - 0.5f) * 2.0f, 0.0f);
Vector2 rotatedP = RotatePointAroundTarget(normalizedPos, BendUpRefPos, BendUp * strength);
Vector2 rotatedP = RotatePointAroundTarget(normalizedPos, BendUpRefPos, BendUp * strength * Params.Strength);
Vector2 offset = rotatedP - normalizedPos;
offset.Y *= Scale.X / Scale.Y;
Deformation[x, y] += offset;
@@ -108,7 +105,7 @@ namespace Barotrauma.SpriteDeformations
{
float strength = normalizedPos.Y;//(1.0f - Math.Max(BendDownRefPos.Y - normalizedPos.Y, 0.0f) / (BendDownRefPos.Y));
strength = Math.Max((strength - 0.5f) * 2.0f, 0.0f);
Vector2 rotatedP = RotatePointAroundTarget(normalizedPos, BendDownRefPos, BendDown * strength);
Vector2 rotatedP = RotatePointAroundTarget(normalizedPos, BendDownRefPos, BendDown * strength * Params.Strength);
Vector2 offset = rotatedP - normalizedPos;
offset.Y *= Scale.X / Scale.Y;
Deformation[x, y] += offset;
@@ -5,16 +5,13 @@ namespace Barotrauma.SpriteDeformations
{
class NoiseDeformationParams : SpriteDeformationParams
{
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f,
ToolTip = "The frequency of the noise.")]
[Serialize(0.0f, true, description: "The frequency of the noise."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
public override float Frequency { get; set; }
[Serialize(1.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f,
ToolTip = "How much the noise distorts the sprite.")]
[Serialize(1.0f, true, description: "How much the noise distorts the sprite."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f, DecimalCount = 2, ValueStep = 0.01f)]
public float Amplitude { get; set; }
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f,
ToolTip = "How fast the noise changes.")]
[Serialize(0.0f, true, description: "How fast the noise changes."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f, DecimalCount = 2, ValueStep = 0.01f)]
public float ChangeSpeed { get; set; }
public NoiseDeformationParams(XElement element) : base(element)
@@ -24,7 +21,7 @@ namespace Barotrauma.SpriteDeformations
class NoiseDeformation : SpriteDeformation
{
private NoiseDeformationParams NoiseDeformationParams => deformationParams as NoiseDeformationParams;
private NoiseDeformationParams NoiseDeformationParams => Params as NoiseDeformationParams;
private float phase;
@@ -53,7 +50,7 @@ namespace Barotrauma.SpriteDeformations
protected override void GetDeformation(out Vector2[,] deformation, out float multiplier)
{
deformation = Deformation;
multiplier = NoiseDeformationParams.Amplitude;
multiplier = NoiseDeformationParams.Amplitude * Params.Strength;
}
public override void Update(float deltaTime)
@@ -10,30 +10,26 @@ namespace Barotrauma.SpriteDeformations
/// 0 = no falloff, the entire sprite is stretched
/// 1 = stretching the center of the sprite has no effect at the edges
/// </summary>
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f,
ToolTip = "0 = no falloff, the entire sprite is stretched, 1 = stretching the center of the sprite has no effect at the edges.")]
[Serialize(0.0f, true, description: "0 = no falloff, the entire sprite is stretched, 1 = stretching the center of the sprite has no effect at the edges."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f)]
public float Falloff { get; set; }
/// <summary>
/// Maximum stretch per vertex (1 = the size of the sprite)
/// </summary>
[Serialize(1.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f,
ToolTip = "Maximum stretch per vertex (1 = the size of the sprite)")]
[Serialize(1.0f, true, description: "Maximum stretch per vertex (1 = the size of the sprite)"), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
public float MaxDeformation { get; set; }
/// <summary>
/// How fast the sprite reacts to being stretched
/// </summary>
[Serialize(1.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f,
ToolTip = "How fast the sprite reacts to being stretched")]
[Serialize(1.0f, true, description: "How fast the sprite reacts to being stretched"), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
public float ReactionSpeed { get; set; }
/// <summary>
/// How fast the sprite returns back to normal after stretching ends
/// </summary>
[Serialize(0.1f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f,
ToolTip = "How fast the sprite returns back to normal after stretching ends")]
[Serialize(0.1f, true, description: "How fast the sprite returns back to normal after stretching ends"), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
public float RecoverSpeed { get; set; }
public PositionalDeformationParams(XElement element) : base(element)
@@ -52,7 +48,7 @@ namespace Barotrauma.SpriteDeformations
public ReactionType Type;
private PositionalDeformationParams positionalDeformationParams => DeformationParams as PositionalDeformationParams;
private PositionalDeformationParams positionalDeformationParams => Params as PositionalDeformationParams;
public PositionalDeformation(XElement element) : base(element, new PositionalDeformationParams(element))
{
@@ -14,7 +14,7 @@ namespace Barotrauma.SpriteDeformations
/// A positive value means that this deformation is or could be used for multiple sprites.
/// This behaviour is not automatic, and has to be implemented for any particular case separately (currently only used in Limbs).
/// </summary>
[Serialize(-1, true)]
[Serialize(-1, true), Editable]
public int Sync
{
get;
@@ -35,18 +35,24 @@ namespace Barotrauma.SpriteDeformations
set;
}
public string Name => GetType().Name;
public string Name => $"Deformation ({TypeName})";
[Serialize(false, true)]
[Serialize(1.0f, true), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2, ValueStep = 0.01f)]
public float Strength { get; private set; }
[Serialize(90f, true), Editable(MinValueFloat = 0, MaxValueFloat = 90)]
public float MaxRotation { get; private set; }
[Serialize(false, true), Editable]
public bool UseMovementSine { get; set; }
[Serialize(false, true)]
[Serialize(false, true), Editable]
public bool StopWhenHostIsDead { get; set; }
/// <summary>
/// Only used if UseMovementSine is enabled. Multiplier for Pi.
/// </summary>
[Serialize(0f, true)]
[Serialize(0f, true), Editable]
public float SineOffset { get; set; }
public virtual float Frequency { get; set; } = 1;
@@ -54,7 +60,7 @@ namespace Barotrauma.SpriteDeformations
public Dictionary<string, SerializableProperty> SerializableProperties
{
get;
private set;
set;
}
/// <summary>
@@ -97,7 +103,7 @@ namespace Barotrauma.SpriteDeformations
protected Vector2[,] Deformation { get; private set; }
protected SpriteDeformationParams deformationParams;
public SpriteDeformationParams Params { get; set; }
private static readonly string[] deformationTypes = new string[] { "Inflate", "Custom", "Noise", "BendJoint", "ReactToTriggerers" };
public static IEnumerable<string> DeformationTypes
@@ -107,19 +113,13 @@ namespace Barotrauma.SpriteDeformations
public Point Resolution
{
get { return deformationParams.Resolution; }
get { return Params.Resolution; }
set { SetResolution(value); }
}
public SpriteDeformationParams DeformationParams
{
get { return deformationParams; }
set { deformationParams = value; }
}
public string TypeName => Params.TypeName;
public string TypeName => deformationParams.TypeName;
public int Sync => deformationParams.Sync;
public int Sync => Params.Sync;
public static SpriteDeformation Load(string deformationType, string parentDebugName)
{
@@ -174,22 +174,22 @@ namespace Barotrauma.SpriteDeformations
if (newDeformation != null)
{
newDeformation.deformationParams.TypeName = typeName;
newDeformation.Params.TypeName = typeName;
}
return newDeformation;
}
protected SpriteDeformation(XElement element, SpriteDeformationParams deformationParams)
{
this.deformationParams = deformationParams;
this.Params = deformationParams;
SerializableProperty.DeserializeProperties(deformationParams, element);
Deformation = new Vector2[deformationParams.Resolution.X, deformationParams.Resolution.Y];
}
public void SetResolution(Point resolution)
{
deformationParams.Resolution = resolution;
Deformation = new Vector2[deformationParams.Resolution.X, deformationParams.Resolution.Y];
Params.Resolution = resolution;
Deformation = new Vector2[Params.Resolution.X, Params.Resolution.Y];
}
protected abstract void GetDeformation(out Vector2[,] deformation, out float multiplier);
@@ -200,10 +200,10 @@ namespace Barotrauma.SpriteDeformations
{
foreach (SpriteDeformation animation in animations)
{
if (animation.deformationParams.Resolution.X != animation.Deformation.GetLength(0) ||
animation.deformationParams.Resolution.Y != animation.Deformation.GetLength(1))
if (animation.Params.Resolution.X != animation.Deformation.GetLength(0) ||
animation.Params.Resolution.Y != animation.Deformation.GetLength(1))
{
animation.Deformation = new Vector2[animation.deformationParams.Resolution.X, animation.deformationParams.Resolution.Y];
animation.Deformation = new Vector2[animation.Params.Resolution.X, animation.Params.Resolution.Y];
}
}
@@ -224,7 +224,7 @@ namespace Barotrauma.SpriteDeformations
{
for (int y = 0; y < resolution.Y; y++)
{
switch (animation.deformationParams.BlendMode)
switch (animation.Params.BlendMode)
{
case DeformationBlendMode.Override:
deformation[x,y] = animDeformation[x,y] * scale * multiplier;
@@ -244,7 +244,7 @@ namespace Barotrauma.SpriteDeformations
public virtual void Save(XElement element)
{
SerializableProperty.SerializeProperties(deformationParams, element);
SerializableProperty.SerializeProperties(Params, element);
}
}
}
@@ -267,7 +267,7 @@ namespace Barotrauma
Matrix.CreateTranslation(pos);
}
public void Draw(Camera cam, Vector3 pos, Vector2 origin, float rotate, Vector2 scale, Color color, bool flip = false)
public void Draw(Camera cam, Vector3 pos, Vector2 origin, float rotate, Vector2 scale, Color color, bool flip = false, bool mirror = false)
{
if (Sprite.Texture == null) { return; }
if (!initialized) { Init(); }
@@ -291,6 +291,10 @@ namespace Barotrauma
effect.Parameters["deformArray"].SetValue(deformAmount);
effect.Parameters["deformArrayWidth"].SetValue(deformArrayWidth);
effect.Parameters["deformArrayHeight"].SetValue(deformArrayHeight);
if (mirror)
{
flip = !flip;
}
effect.Parameters["uvTopLeft"].SetValue(flip ? uvTopLeftFlipped : uvTopLeft);
effect.Parameters["uvBottomRight"].SetValue(flip ? uvBottomRightFlipped : uvBottomRight);
effect.GraphicsDevice.SetVertexBuffer(flip ? flippedVertexBuffer : vertexBuffer);
@@ -368,7 +372,7 @@ namespace Barotrauma
foreach (SpriteDeformation deformation in deformations)
{
var deformEditor = new SerializableEntityEditor(container.RectTransform, deformation.DeformationParams, false, true);
var deformEditor = new SerializableEntityEditor(container.RectTransform, deformation.Params, false, true);
deformEditor.RectTransform.MinSize = new Point(deformEditor.Rect.Width, deformEditor.Rect.Height);
}
@@ -9,8 +9,9 @@ namespace Barotrauma
{
public partial class Sprite
{
protected Texture2D texture;
private bool cannotBeLoaded;
protected Texture2D texture;
public Texture2D Texture
{
get
@@ -56,7 +57,7 @@ namespace Barotrauma
public void EnsureLazyLoaded()
{
if (!lazyLoad || texture != null) { return; }
if (!lazyLoad || texture != null || cannotBeLoaded) { return; }
Vector4 sourceVector = Vector4.Zero;
bool temp2 = false;
@@ -74,6 +75,10 @@ namespace Barotrauma
if (s == this) { continue; }
if (s.FullPath == FullPath && s.texture != null) { s.texture = texture; }
}
if (texture == null)
{
cannotBeLoaded = true;
}
}
public void ReloadTexture(bool updateAllSprites = false) => ReloadTexture(updateAllSprites ? LoadedSprites.Where(s => s.Texture == texture) : new Sprite[] { this });
@@ -93,10 +98,8 @@ namespace Barotrauma
sourceRect = new Rectangle(0, 0, texture.Width, texture.Height);
}
public static Texture2D LoadTexture(string file, bool preMultiplyAlpha = true)
{
if (string.IsNullOrWhiteSpace(file))
{
Texture2D t = null;
@@ -109,7 +112,7 @@ namespace Barotrauma
file = Path.GetFullPath(file);
foreach (Sprite s in list)
{
if (s.FullPath == file && s.texture != null) { return s.texture; }
if (s.FullPath == file && s.texture != null && !s.texture.IsDisposed) { return s.texture; }
}
if (File.Exists(file))