Remove lights component reference (#4316)

This commit is contained in:
metalgearsloth
2023-09-11 19:17:28 +10:00
committed by GitHub
parent 8ce3a03136
commit 25007a743f
68 changed files with 704 additions and 609 deletions

View File

@@ -2,11 +2,13 @@ using Robust.Client.GameObjects;
using Robust.Shared.ComponentTrees;
using Robust.Shared.GameObjects;
using Robust.Shared.Physics;
using Robust.Shared.ViewVariables;
namespace Robust.Client.ComponentTrees;
[RegisterComponent]
public sealed partial class LightTreeComponent: Component, IComponentTreeComponent<PointLightComponent>
{
[ViewVariables]
public DynamicTree<ComponentTreeEntry<PointLightComponent>> Tree { get; set; } = default!;
}

View File

@@ -1,85 +0,0 @@
using Robust.Client.Graphics;
using Robust.Shared.Animations;
using Robust.Shared.ComponentTrees;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Robust.Client.GameObjects
{
[RegisterComponent]
[ComponentReference(typeof(SharedPointLightComponent))]
public sealed partial class PointLightComponent : SharedPointLightComponent, IComponentTreeEntry<PointLightComponent>
{
public EntityUid? TreeUid { get; set; }
public DynamicTree<ComponentTreeEntry<PointLightComponent>>? Tree { get; set; }
public bool AddToTree => Enabled && !ContainerOccluded;
public bool TreeUpdateQueued { get; set; }
[ViewVariables(VVAccess.ReadWrite)]
[Animatable]
public override Color Color
{
get => _color;
set => base.Color = value;
}
[Access(typeof(PointLightSystem))]
public bool ContainerOccluded;
/// <summary>
/// Determines if the light mask should automatically rotate with the entity. (like a flashlight)
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public bool MaskAutoRotate
{
get => _maskAutoRotate;
set => _maskAutoRotate = value;
}
/// <summary>
/// Local rotation of the light mask around the center origin
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[Animatable]
public Angle Rotation
{
get => _rotation;
set => _rotation = value;
}
/// <summary>
/// The resource path to the mask texture the light will use.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public string? MaskPath
{
get => _maskPath;
set
{
if (_maskPath?.Equals(value) != false) return;
_maskPath = value;
EntitySystem.Get<PointLightSystem>().UpdateMask(this);
}
}
/// <summary>
/// Set a mask texture that will be applied to the light while rendering.
/// The mask's red channel will be linearly multiplied.p
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public Texture? Mask { get; set; }
[DataField("autoRot")]
private bool _maskAutoRotate;
private Angle _rotation;
[DataField("mask")]
internal string? _maskPath;
}
}

View File

@@ -0,0 +1,38 @@
using Robust.Client.Graphics;
using Robust.Shared.ComponentTrees;
using Robust.Shared.GameObjects;
using Robust.Shared.Physics;
using Robust.Shared.ViewVariables;
namespace Robust.Client.GameObjects;
[RegisterComponent]
public sealed partial class PointLightComponent : SharedPointLightComponent, IComponentTreeEntry<PointLightComponent>
{
#region Component Tree
/// <inheritdoc />
[ViewVariables]
public EntityUid? TreeUid { get; set; }
/// <inheritdoc />
[ViewVariables]
public DynamicTree<ComponentTreeEntry<PointLightComponent>>? Tree { get; set; }
/// <inheritdoc />
[ViewVariables]
public bool AddToTree => Enabled && !ContainerOccluded;
/// <inheritdoc />
[ViewVariables]
public bool TreeUpdateQueued { get; set; }
#endregion
/// <summary>
/// Set a mask texture that will be applied to the light while rendering.
/// The mask's red channel will be linearly multiplied.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
internal Texture? Mask;
}

View File

@@ -1,5 +1,7 @@
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Shared.Graphics;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.Maths;
namespace Robust.Client.GameObjects
@@ -24,7 +26,7 @@ namespace Robust.Client.GameObjects
int AnimationFrame { get; }
bool AutoAnimated { get; set; }
RSI.State.Direction EffectiveDirection(Angle worldRotation);
RsiDirection EffectiveDirection(Angle worldRotation);
/// <summary>
/// Layer size in pixels.

View File

@@ -12,6 +12,8 @@ using Robust.Shared;
using Robust.Shared.Animations;
using Robust.Shared.ComponentTrees;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
@@ -26,8 +28,8 @@ using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Robust.Client.ComponentTrees.SpriteTreeSystem;
using DrawDepthTag = Robust.Shared.GameObjects.DrawDepth;
using RSIDirection = Robust.Client.Graphics.RSI.State.Direction;
using static Robust.Shared.Serialization.TypeSerializers.Implementations.SpriteSpecifierSerializer;
using Direction = Robust.Shared.Maths.Direction;
namespace Robust.Client.GameObjects
{
@@ -1347,11 +1349,11 @@ namespace Robust.Client.GameObjects
state = GetFallbackState(resourceCache);
}
return state.Directions switch
return state.RsiDirections switch
{
RSI.State.DirectionType.Dir1 => 1,
RSI.State.DirectionType.Dir4 => 4,
RSI.State.DirectionType.Dir8 => 8,
RsiDirectionType.Dir1 => 1,
RsiDirectionType.Dir4 => 4,
RsiDirectionType.Dir8 => 8,
_ => throw new ArgumentOutOfRangeException()
};
}
@@ -1389,7 +1391,7 @@ namespace Robust.Client.GameObjects
builder.AppendFormat(
"vis/depth/scl/rot/ofs/col/norot/override/dir: {0}/{1}/{2}/{3}/{4}/{5}/{6}/{8}/{7}\n",
Visible, DrawDepth, Scale, Rotation, Offset,
Color, NoRotation, entities.GetComponent<TransformComponent>(Owner).WorldRotation.ToRsiDirection(RSI.State.DirectionType.Dir8),
Color, NoRotation, entities.GetComponent<TransformComponent>(Owner).WorldRotation.ToRsiDirection(RsiDirectionType.Dir8),
DirectionOverride
);
@@ -1689,7 +1691,7 @@ namespace Robust.Client.GameObjects
int ISpriteLayer.AnimationFrame => AnimationFrame;
public RSIDirection EffectiveDirection(Angle worldRotation)
public RsiDirection EffectiveDirection(Angle worldRotation)
{
if (State == default)
{
@@ -1710,23 +1712,23 @@ namespace Robust.Client.GameObjects
return default;
}
public RSIDirection EffectiveDirection(RSI.State state, Angle worldRotation,
public RsiDirection EffectiveDirection(RSI.State state, Angle worldRotation,
Direction? overrideDirection)
{
if (state.Directions == RSI.State.DirectionType.Dir1)
if (state.RsiDirections == RsiDirectionType.Dir1)
{
return RSIDirection.South;
return RsiDirection.South;
}
else
{
RSIDirection dir;
RsiDirection dir;
if (overrideDirection != null)
{
dir = overrideDirection.Value.Convert(state.Directions);
dir = overrideDirection.Value.Convert(state.RsiDirections);
}
else
{
dir = worldRotation.ToRsiDirection(state.Directions);
dir = worldRotation.ToRsiDirection(state.RsiDirections);
}
return dir.OffsetRsiDir(DirOffset);
@@ -1882,20 +1884,20 @@ namespace Robust.Client.GameObjects
else if (_parent.SnapCardinals && (!_parent.GranularLayersRendering || RenderingStrategy == LayerRenderingStrategy.UseSpriteStrategy)
|| _parent.GranularLayersRendering && RenderingStrategy == LayerRenderingStrategy.SnapToCardinals)
{
DebugTools.Assert(_actualState == null || _actualState.Directions == RSI.State.DirectionType.Dir1);
DebugTools.Assert(_actualState == null || _actualState.RsiDirections == RsiDirectionType.Dir1);
size = new Vector2(longestSide, longestSide);
}
else
{
// Build the bounding box based on how many directions the sprite has
size = (_actualState?.Directions) switch
size = (_actualState?.RsiDirections) switch
{
// If we have four cardinal directions, take the longest side of our texture and square it, then turn that into our bounding box.
// This accounts for all possible rotations.
RSI.State.DirectionType.Dir4 => new Vector2(longestSide, longestSide),
RsiDirectionType.Dir4 => new Vector2(longestSide, longestSide),
// If we have eight directions, find the maximum length of the texture (accounting for rotation), then square it to make
RSI.State.DirectionType.Dir8 => new Vector2(longestRotatedSide, longestRotatedSide),
RsiDirectionType.Dir8 => new Vector2(longestRotatedSide, longestRotatedSide),
// If we have only one direction or an invalid RSI state, create a simple bounding box with the size of the texture.
_ => textureSize
@@ -1929,9 +1931,9 @@ namespace Robust.Client.GameObjects
/// Given the apparent rotation of an entity on screen (world + eye rotation), get layer's matrix for drawing &
/// relevant RSI direction.
/// </summary>
public void GetLayerDrawMatrix(RSIDirection dir, out Matrix3 layerDrawMatrix)
public void GetLayerDrawMatrix(RsiDirection dir, out Matrix3 layerDrawMatrix)
{
if (_parent.NoRotation || dir == RSIDirection.South)
if (_parent.NoRotation || dir == RsiDirection.South)
layerDrawMatrix = LocalMatrix;
else
{
@@ -1956,11 +1958,11 @@ namespace Robust.Client.GameObjects
/// Converts an angle (between 0 and 2pi) to an RSI direction. This will slightly bias the angle to avoid flickering for
/// 4-directional sprites.
/// </summary>
public static RSIDirection GetDirection(RSI.State.DirectionType dirType, Angle angle)
public static RsiDirection GetDirection(RsiDirectionType dirType, Angle angle)
{
if (dirType == RSI.State.DirectionType.Dir1)
return RSIDirection.South;
else if (dirType == RSI.State.DirectionType.Dir8)
if (dirType == RsiDirectionType.Dir1)
return RsiDirection.South;
else if (dirType == RsiDirectionType.Dir8)
return angle.GetDir().Convert(dirType);
// For 4-directional sprites, as entities are often moving & facing diagonally, we will slightly bias the
@@ -1973,10 +1975,10 @@ namespace Robust.Client.GameObjects
return ((int)Math.Round(modTheta / MathHelper.PiOver2) % 4) switch
{
0 => RSIDirection.South,
1 => RSIDirection.East,
2 => RSIDirection.North,
_ => RSIDirection.West,
0 => RsiDirection.South,
1 => RsiDirection.East,
2 => RsiDirection.North,
_ => RsiDirection.West,
};
}
@@ -1988,7 +1990,7 @@ namespace Robust.Client.GameObjects
if (!Visible || Blank)
return;
var dir = _actualState == null ? RSIDirection.South : GetDirection(_actualState.Directions, angle);
var dir = _actualState == null ? RsiDirection.South : GetDirection(_actualState.RsiDirections, angle);
// Set the drawing transform for this layer
GetLayerDrawMatrix(dir, out var layerMatrix);
@@ -1998,7 +2000,7 @@ namespace Robust.Client.GameObjects
// The direction used to draw the sprite can differ from the one that the angle would naively suggest,
// due to direction overrides or offsets.
if (overrideDirection != null && _actualState != null)
dir = overrideDirection.Value.Convert(_actualState.Directions);
dir = overrideDirection.Value.Convert(_actualState.RsiDirections);
dir = dir.OffsetRsiDir(DirOffset);
// Get the correct directional texture from the state, and draw it!
@@ -2021,7 +2023,7 @@ namespace Robust.Client.GameObjects
drawingHandle.UseShader(null);
}
private Texture GetRenderTexture(RSI.State? state, RSIDirection dir)
private Texture GetRenderTexture(RSI.State? state, RsiDirection dir)
{
if (state == null)
return Texture ?? _parent.resourceCache.GetFallback<TextureResource>().Texture;

View File

@@ -1,6 +1,8 @@
using System.Diagnostics.CodeAnalysis;
using Robust.Client.ComponentTrees;
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
@@ -15,59 +17,108 @@ namespace Robust.Client.GameObjects
{
base.Initialize();
SubscribeLocalEvent<PointLightComponent, ComponentInit>(HandleInit);
SubscribeLocalEvent<PointLightComponent, ComponentHandleState>(OnLightHandleState);
}
private void OnLightHandleState(EntityUid uid, PointLightComponent component, ref ComponentHandleState args)
{
if (args.Current is not PointLightComponentState state)
return;
component.Enabled = state.Enabled;
component.Offset = state.Offset;
component.Softness = state.Softness;
component.CastShadows = state.CastShadows;
component.Energy = state.Energy;
component.Radius = state.Radius;
component.Color = state.Color;
}
public override SharedPointLightComponent EnsureLight(EntityUid uid)
{
return EnsureComp<PointLightComponent>(uid);
}
public override bool ResolveLight(EntityUid uid, [NotNullWhen(true)] ref SharedPointLightComponent? component)
{
if (TryComp<PointLightComponent>(uid, out var comp))
{
component = comp;
return true;
}
component = null;
return false;
}
public override bool TryGetLight(EntityUid uid, [NotNullWhen(true)] out SharedPointLightComponent? component)
{
if (TryComp<PointLightComponent>(uid, out var comp))
{
component = comp;
return true;
}
component = null;
return false;
}
public override bool RemoveLightDeferred(EntityUid uid)
{
return RemCompDeferred<PointLightComponent>(uid);
}
private void HandleInit(EntityUid uid, PointLightComponent component, ComponentInit args)
{
UpdateMask(component);
SetMask(component.MaskPath, component);
}
internal void UpdateMask(PointLightComponent component)
public void SetMask(string? maskPath, PointLightComponent component)
{
if (component._maskPath is not null)
component.Mask = _resourceCache.GetResource<TextureResource>(component._maskPath);
if (maskPath is not null)
component.Mask = _resourceCache.GetResource<TextureResource>(maskPath);
else
component.Mask = null;
}
#region Setters
public void SetContainerOccluded(EntityUid uid, bool occluded, PointLightComponent? comp = null)
public void SetContainerOccluded(EntityUid uid, bool occluded, SharedPointLightComponent? comp = null)
{
if (!Resolve(uid, ref comp) || occluded == comp.ContainerOccluded)
if (!ResolveLight(uid, ref comp) || occluded == comp.ContainerOccluded || comp is not PointLightComponent clientComp)
return;
comp.ContainerOccluded = occluded;
Dirty(uid, comp);
if (comp.Enabled)
_lightTree.QueueTreeUpdate(uid, comp);
_lightTree.QueueTreeUpdate(uid, clientComp);
}
public override void SetEnabled(EntityUid uid, bool enabled, SharedPointLightComponent? comp = null)
{
if (!Resolve(uid, ref comp) || enabled == comp.Enabled)
if (!ResolveLight(uid, ref comp) || enabled == comp.Enabled || comp is not PointLightComponent clientComp)
return;
comp._enabled = enabled;
comp.Enabled = enabled;
RaiseLocalEvent(uid, new PointLightToggleEvent(comp.Enabled));
Dirty(uid, comp);
var cast = (PointLightComponent)comp;
if (!cast.ContainerOccluded)
_lightTree.QueueTreeUpdate(uid, cast);
if (!comp.ContainerOccluded)
_lightTree.QueueTreeUpdate(uid, clientComp);
}
public override void SetRadius(EntityUid uid, float radius, SharedPointLightComponent? comp = null)
{
if (!Resolve(uid, ref comp) || MathHelper.CloseToPercent(radius, comp.Radius))
if (!ResolveLight(uid, ref comp) || MathHelper.CloseToPercent(radius, comp.Radius) ||
comp is not PointLightComponent clientComp)
return;
comp._radius = radius;
comp.Radius = radius;
Dirty(uid, comp);
var cast = (PointLightComponent)comp;
if (cast.TreeUid != null)
_lightTree.QueueTreeUpdate(uid, cast);
if (clientComp.TreeUid != null)
_lightTree.QueueTreeUpdate(uid, clientComp);
}
#endregion
}

View File

@@ -4,6 +4,7 @@ using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.Utility;
using Robust.Shared.Graphics;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations;

View File

@@ -1,4 +1,5 @@
using JetBrains.Annotations;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.Utility;

View File

@@ -3,6 +3,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using OpenToolkit.Graphics.OpenGL4;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using ES20 = OpenToolkit.Graphics.ES20;

View File

@@ -19,6 +19,7 @@ using Robust.Client.ComponentTrees;
using Robust.Shared.Graphics;
using static Robust.Shared.GameObjects.OccluderComponent;
using Robust.Shared.Utility;
using TextureWrapMode = Robust.Shared.Graphics.TextureWrapMode;
using Vector4 = Robust.Shared.Maths.Vector4;
namespace Robust.Client.Graphics.Clyde

View File

@@ -5,6 +5,7 @@ using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using OpenToolkit.Graphics.OpenGL4;
using Robust.Shared.Graphics;
namespace Robust.Client.Graphics.Clyde
{

View File

@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using OpenToolkit.Graphics.OpenGL4;
using Robust.Shared.Graphics;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Utility;

View File

@@ -6,6 +6,7 @@ using System.Numerics;
using System.Text;
using OpenToolkit.Graphics.OpenGL4;
using Robust.Client.ResourceManagement;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;

View File

@@ -8,6 +8,8 @@ using System.Runtime.InteropServices;
using System.Threading;
using OpenToolkit.Graphics.OpenGL4;
using Robust.Client.Utility;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using SixLabors.ImageSharp;
@@ -17,6 +19,7 @@ using OGLTextureWrapMode = OpenToolkit.Graphics.OpenGL.TextureWrapMode;
using PIF = OpenToolkit.Graphics.OpenGL4.PixelInternalFormat;
using PF = OpenToolkit.Graphics.OpenGL4.PixelFormat;
using PT = OpenToolkit.Graphics.OpenGL4.PixelType;
using TextureWrapMode = Robust.Shared.Graphics.TextureWrapMode;
namespace Robust.Client.Graphics.Clyde
{

View File

@@ -12,6 +12,7 @@ using Robust.Client.UserInterface;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
@@ -21,6 +22,7 @@ using Robust.Shared.Timing;
using SixLabors.ImageSharp;
using Color = Robust.Shared.Maths.Color;
using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute;
using TextureWrapMode = Robust.Shared.Graphics.TextureWrapMode;
namespace Robust.Client.Graphics.Clyde
{

View File

@@ -1,9 +0,0 @@
namespace Robust.Client.Graphics
{
internal enum ClydeStockTexture : byte
{
White,
Black,
Transparent
}
}

View File

@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
namespace Robust.Client.Graphics

View File

@@ -3,6 +3,7 @@ using System.Numerics;
using System.Text;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
namespace Robust.Client.Graphics
@@ -154,7 +155,7 @@ namespace Robust.Client.Graphics
Vector2 scale,
Angle? worldRot,
Angle eyeRotation = default,
Direction? overrideDirection = null,
Shared.Maths.Direction? overrideDirection = null,
SpriteComponent? sprite = null,
TransformComponent? xform = null,
SharedTransformSystem? xformSystem = null);

View File

@@ -1,4 +1,5 @@
using System.Numerics;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
namespace Robust.Client.Graphics

View File

@@ -1,5 +1,6 @@
using System;
using System.Numerics;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.Utility;

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Text;
using JetBrains.Annotations;
using Robust.Client.Utility;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using SharpFont;

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Numerics;
using System.Threading.Tasks;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Robust.Client.Input;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared.Graphics;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;

View File

@@ -1,4 +1,4 @@
using Robust.Shared.Maths;
using Robust.Shared.Maths;
namespace Robust.Client.Graphics
{

View File

@@ -1,5 +1,6 @@
using System.IO;
using System.Text;
using Robust.Shared.Graphics;
namespace Robust.Client.Graphics
{

View File

@@ -37,7 +37,7 @@ namespace Robust.Client.Graphics
Vector2 scale,
Angle? worldRot,
Angle eyeRotation = default,
Direction? overrideDirection = null,
Shared.Maths.Direction? overrideDirection = null,
SpriteComponent? sprite = null,
TransformComponent? xform = null,
SharedTransformSystem? xformSystem = null);

View File

@@ -1,3 +1,5 @@
using Robust.Shared.Graphics;
namespace Robust.Client.Graphics
{
/// <summary>

View File

@@ -1,12 +1,14 @@
namespace Robust.Client.Graphics
using Robust.Shared.Graphics.RSI;
namespace Robust.Client.Graphics
{
public interface IRsiStateLike : IDirectionalTextureProvider
{
RSI.State.DirectionType Directions { get; }
RsiDirectionType RsiDirections { get; }
bool IsAnimated { get; }
int AnimationFrameCount { get; }
float GetDelay(int frame);
Texture GetFrame(RSI.State.Direction dir, int frame);
Texture GetFrame(RsiDirection dir, int frame);
}
}

View File

@@ -3,6 +3,7 @@ using JetBrains.Annotations;
using Robust.Shared.Timing;
using Robust.Shared.Enums;
using System;
using Robust.Shared.Graphics;
namespace Robust.Client.Graphics
{

View File

@@ -1,6 +1,8 @@
using System;
using System.Linq;
using Robust.Client.Utility;
using Robust.Shared.Graphics;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
@@ -25,7 +27,7 @@ namespace Robust.Client.Graphics
// 2D array for the texture to use for each animation frame at each direction.
public readonly Texture[][] Icons;
internal State(Vector2i size, RSI rsi, StateId stateId, DirectionType direction, float[] delays, Texture[][] icons)
internal State(Vector2i size, RSI rsi, StateId stateId, RsiDirectionType rsiDirection, float[] delays, Texture[][] icons)
{
DebugTools.Assert(size.X > 0);
DebugTools.Assert(size.Y > 0);
@@ -34,7 +36,7 @@ namespace Robust.Client.Graphics
Size = size;
RSI = rsi;
StateId = stateId;
Directions = direction;
RsiDirections = rsiDirection;
Delays = delays;
TotalDelay = delays.Sum();
Icons = icons;
@@ -63,7 +65,7 @@ namespace Robust.Client.Graphics
/// <summary>
/// How many directions this state has.
/// </summary>
public DirectionType Directions { get; }
public RsiDirectionType RsiDirections { get; }
/// <summary>
/// The first frame of the "south" direction.
@@ -90,14 +92,14 @@ namespace Robust.Client.Graphics
int IRsiStateLike.AnimationFrameCount => DelayCount;
public Texture GetFrame(Direction direction, int frame)
public Texture GetFrame(RsiDirection rsiDirection, int frame)
{
return Icons[(int) direction][frame];
return Icons[(int) rsiDirection][frame];
}
public Texture[] GetFrames(Direction direction)
public Texture[] GetFrames(RsiDirection rsiDirection)
{
return Icons[(int) direction];
return Icons[(int) rsiDirection];
}
/// <summary>
@@ -124,52 +126,12 @@ namespace Robust.Client.Graphics
Texture IDirectionalTextureProvider.TextureFor(Shared.Maths.Direction dir)
{
if (Directions == DirectionType.Dir1)
if (RsiDirections == RsiDirectionType.Dir1)
{
return Frame0;
}
return GetFrame(dir.Convert(Directions), 0);
}
/// <summary>
/// Specifies which types of directions an RSI state has.
/// </summary>
public enum DirectionType : byte
{
/// <summary>
/// A single direction, namely South.
/// </summary>
Dir1,
/// <summary>
/// 4 cardinal directions.
/// </summary>
Dir4,
/// <summary>
/// 4 cardinal + 4 diagonal directions.
/// </summary>
Dir8,
}
/// <summary>
/// Specifies a direction in an RSI state.
/// </summary>
/// <remarks>
/// Value of the enum here matches the index used to store it in the icons array. If this ever changes, then
/// <see cref="GameObjects.SpriteComponent.Layer._rsiDirectionMatrices"/> also needs to be updated.
/// </remarks>
public enum Direction : byte
{
South = 0,
North = 1,
East = 2,
West = 3,
SouthEast = 4,
SouthWest = 5,
NorthEast = 6,
NorthWest = 7,
return GetFrame(dir.Convert(RsiDirections), 0);
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Numerics;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;

View File

@@ -1,233 +1,112 @@
using System;
using System.IO;
using JetBrains.Annotations;
using Robust.Shared.Graphics;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using YamlDotNet.RepresentationModel;
using Color = Robust.Shared.Maths.Color;
namespace Robust.Client.Graphics
namespace Robust.Client.Graphics;
/// <summary>
/// Contains a texture used for drawing things.
/// </summary>
[PublicAPI]
public abstract class Texture : IRsiStateLike
{
/// <summary>
/// Contains a texture used for drawing things.
/// The width of the texture, in pixels.
/// </summary>
[PublicAPI]
public abstract class Texture : IRsiStateLike
public int Width => Size.X;
/// <summary>
/// The height of the texture, in pixels.
/// </summary>
public int Height => Size.Y;
/// <summary>
/// The size of the texture, in pixels.
/// </summary>
public Vector2i Size { get; /*protected set;*/ }
public Color this[int x, int y] => this.GetPixel(x, y);
protected Texture(Vector2i size)
{
/// <summary>
/// The width of the texture, in pixels.
/// </summary>
public int Width => Size.X;
Size = size;
}
/// <summary>
/// The height of the texture, in pixels.
/// </summary>
public int Height => Size.Y;
Texture IDirectionalTextureProvider.Default => this;
/// <summary>
/// The size of the texture, in pixels.
/// </summary>
public Vector2i Size { get; /*protected set;*/ }
Texture IDirectionalTextureProvider.TextureFor(Direction dir)
{
return this;
}
public Color this[int x, int y] => this.GetPixel(x, y);
RsiDirectionType IRsiStateLike.RsiDirections => RsiDirectionType.Dir1;
bool IRsiStateLike.IsAnimated => false;
int IRsiStateLike.AnimationFrameCount => 0;
protected Texture(Vector2i size)
{
Size = size;
}
float IRsiStateLike.GetDelay(int frame)
{
if (frame != 0)
throw new IndexOutOfRangeException();
public static Texture Transparent =>
IoCManager.Resolve<IClydeInternal>().GetStockTexture(ClydeStockTexture.Transparent);
return 0;
}
public static Texture White =>
IoCManager.Resolve<IClydeInternal>().GetStockTexture(ClydeStockTexture.White);
Texture IRsiStateLike.GetFrame(RsiDirection dir, int frame)
{
if (frame != 0)
throw new IndexOutOfRangeException();
public static Texture Black =>
IoCManager.Resolve<IClydeInternal>().GetStockTexture(ClydeStockTexture.Black);
return this;
}
/// <summary>
/// Loads a new texture an existing image.
/// </summary>
/// <param name="image">The image to load.</param>
/// <param name="name">The "name" of this texture. This can be referred to later to aid debugging.</param>
/// <param name="loadParameters">
/// Parameters that influence the loading of textures.
/// Defaults to <see cref="TextureLoadParameters.Default"/> if <c>null</c>.
/// </param>
/// <typeparam name="T">The type of pixels of the image. At the moment, images must be <see cref="Rgba32"/>.</typeparam>
public static Texture LoadFromImage<T>(Image<T> image, string? name = null,
TextureLoadParameters? loadParameters = null) where T : unmanaged, IPixel<T>
{
var manager = IoCManager.Resolve<IClyde>();
return manager.LoadTextureFromImage(image, name, loadParameters);
}
public abstract Color GetPixel(int x, int y);
/// <summary>
/// Loads an image from a stream containing PNG data.
/// </summary>
/// <param name="stream">The stream to load the image from.</param>
/// <param name="name">The "name" of this texture. This can be referred to later to aid debugging.</param>
/// <param name="loadParameters">
/// Parameters that influence the loading of textures.
/// Defaults to <see cref="TextureLoadParameters.Default"/> if <c>null</c>.
/// </param>
public static Texture LoadFromPNGStream(Stream stream, string? name = null,
TextureLoadParameters? loadParameters = null)
{
var manager = IoCManager.Resolve<IClyde>();
return manager.LoadTextureFromPNGStream(stream, name, loadParameters);
}
public static Texture Transparent =>
IoCManager.Resolve<IClydeInternal>().GetStockTexture(ClydeStockTexture.Transparent);
Texture IDirectionalTextureProvider.Default => this;
public static Texture White =>
IoCManager.Resolve<IClydeInternal>().GetStockTexture(ClydeStockTexture.White);
Texture IDirectionalTextureProvider.TextureFor(Direction dir)
{
return this;
}
public static Texture Black =>
IoCManager.Resolve<IClydeInternal>().GetStockTexture(ClydeStockTexture.Black);
RSI.State.DirectionType IRsiStateLike.Directions => RSI.State.DirectionType.Dir1;
bool IRsiStateLike.IsAnimated => false;
int IRsiStateLike.AnimationFrameCount => 0;
float IRsiStateLike.GetDelay(int frame)
{
if (frame != 0)
throw new IndexOutOfRangeException();
return 0;
}
Texture IRsiStateLike.GetFrame(RSI.State.Direction dir, int frame)
{
if (frame != 0)
throw new IndexOutOfRangeException();
return this;
}
public abstract Color GetPixel(int x, int y);
/// <summary>
/// Loads a new texture an existing image.
/// </summary>
/// <param name="image">The image to load.</param>
/// <param name="name">The "name" of this texture. This can be referred to later to aid debugging.</param>
/// <param name="loadParameters">
/// Parameters that influence the loading of textures.
/// Defaults to <see cref="Robust.Client.Graphics.TextureLoadParameters.Default"/> if <c>null</c>.
/// </param>
/// <typeparam name="T">The type of pixels of the image. At the moment, images must be <see cref="Rgba32"/>.</typeparam>
public static Texture LoadFromImage<T>(Image<T> image, string? name = null,
TextureLoadParameters? loadParameters = null) where T : unmanaged, IPixel<T>
{
var manager = IoCManager.Resolve<IClyde>();
return manager.LoadTextureFromImage(image, name, loadParameters);
}
/// <summary>
/// Flags for loading of textures.
/// Loads an image from a stream containing PNG data.
/// </summary>
[PublicAPI]
public struct TextureLoadParameters
/// <param name="stream">The stream to load the image from.</param>
/// <param name="name">The "name" of this texture. This can be referred to later to aid debugging.</param>
/// <param name="loadParameters">
/// Parameters that influence the loading of textures.
/// Defaults to <see cref="Robust.Client.Graphics.TextureLoadParameters.Default"/> if <c>null</c>.
/// </param>
public static Texture LoadFromPNGStream(Stream stream, string? name = null,
TextureLoadParameters? loadParameters = null)
{
/// <summary>
/// The default sampling parameters for the texture.
/// </summary>
public TextureSampleParameters SampleParameters { get; set; }
/// <summary>
/// If true, the image data will be treated as sRGB.
/// </summary>
public bool Srgb { get; set; }
public static TextureLoadParameters FromYaml(YamlMappingNode yaml)
{
var loadParams = Default;
if (yaml.TryGetNode("sample", out YamlMappingNode? sampleNode))
{
loadParams.SampleParameters = TextureSampleParameters.FromYaml(sampleNode);
}
if (yaml.TryGetNode("srgb", out var srgb))
{
loadParams.Srgb = srgb.AsBool();
}
return loadParams;
}
public static readonly TextureLoadParameters Default = new()
{
SampleParameters = TextureSampleParameters.Default,
Srgb = true
};
}
/// <summary>
/// Sample flags for textures.
/// These are separate from <see cref="TextureLoadParameters"/>,
/// because it is possible to create "proxies" to existing textures
/// with different sampling parameters than the base texture.
/// </summary>
[PublicAPI]
public struct TextureSampleParameters
{
// NOTE: If somebody is gonna add support for 3D/1D textures, change this doc comment.
// See the note on this page for why: https://www.khronos.org/opengl/wiki/Sampler_Object#Filtering
/// <summary>
/// If true, use bi-linear texture filtering if the texture cannot be rendered 1:1
/// </summary>
public bool Filter { get; set; }
/// <summary>
/// Controls how to wrap the texture if texture coordinates outside 0-1 are accessed.
/// </summary>
public TextureWrapMode WrapMode { get; set; }
public static TextureSampleParameters FromYaml(YamlMappingNode node)
{
var wrap = TextureWrapMode.None;
var filter = false;
if (node.TryGetNode("filter", out var filterNode))
{
filter = filterNode.AsBool();
}
if (node.TryGetNode("wrap", out var wrapNode))
{
switch (wrapNode.AsString())
{
case "none":
wrap = TextureWrapMode.None;
break;
case "repeat":
wrap = TextureWrapMode.Repeat;
break;
case "mirrored_repeat":
wrap = TextureWrapMode.MirroredRepeat;
break;
default:
throw new ArgumentException("Not a valid wrap mode.");
}
}
return new TextureSampleParameters {Filter = filter, WrapMode = wrap};
}
public static readonly TextureSampleParameters Default = new()
{
Filter = false,
WrapMode = TextureWrapMode.None
};
}
/// <summary>
/// Controls behavior when reading texture coordinates outside 0-1, which usually wraps the texture somehow.
/// </summary>
[PublicAPI]
public enum TextureWrapMode : byte
{
/// <summary>
/// Do not wrap, instead clamp to edge.
/// </summary>
None = 0,
/// <summary>
/// Repeat the texture.
/// </summary>
Repeat,
/// <summary>
/// Repeat the texture mirrored.
/// </summary>
MirroredRepeat,
var manager = IoCManager.Resolve<IClyde>();
return manager.LoadTextureFromPNGStream(stream, name, loadParameters);
}
}

View File

@@ -8,6 +8,7 @@ using Robust.Client.ResourceManagement;
using Robust.Client.Utility;
using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Shared.Graphics;
using Robust.Shared.Map;
using Robust.Shared.Maths;

View File

@@ -6,6 +6,7 @@ using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Direction = Robust.Shared.Maths.Direction;
namespace Robust.Client.Map;

View File

@@ -8,6 +8,7 @@ using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.IoC;
@@ -20,6 +21,7 @@ using Robust.Shared.Reflection;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using Robust.Shared.Log;
using Direction = Robust.Shared.Maths.Direction;
namespace Robust.Client.Placement
{

View File

@@ -7,6 +7,7 @@ using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using Robust.Client.Graphics;
using Robust.Client.Utility;
using Robust.Shared.Graphics;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Resources;
@@ -116,9 +118,9 @@ namespace Robust.Client.ResourceManagement
var dirType = stateObject.DirCount switch
{
1 => RSI.State.DirectionType.Dir1,
4 => RSI.State.DirectionType.Dir4,
8 => RSI.State.DirectionType.Dir8,
1 => RsiDirectionType.Dir1,
4 => RsiDirectionType.Dir4,
8 => RsiDirectionType.Dir8,
_ => throw new InvalidOperationException()
};

View File

@@ -1,6 +1,7 @@
using System.IO;
using System.Threading;
using Robust.Client.Graphics;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;

View File

@@ -55,9 +55,6 @@
<RobustLinkAssemblies Include="TerraFX.Interop.Windows" />
<RobustLinkAssemblies Include="OpenToolkit.Graphics" />
</ItemGroup>
<ItemGroup>
<Folder Include="GameObjects\Components\Eye\" />
</ItemGroup>
<Import Project="..\MSBuild\Robust.Properties.targets" />

View File

@@ -7,6 +7,7 @@ using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Enums;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;

View File

@@ -1,5 +1,7 @@
using Robust.Client.Graphics;
using Robust.Client.Utility;
using Robust.Shared.Graphics;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.IoC;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -21,7 +23,7 @@ namespace Robust.Client.UserInterface.Controls
/// </summary>
public TextureRect DisplayRect { get; }
public RSI.State.Direction RsiDirection { get; } = RSI.State.Direction.South;
public RsiDirection RsiDirection { get; } = RsiDirection.South;
public AnimatedTextureRect()
{

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Shared.Graphics;
using Robust.Shared.Input;
using Robust.Shared.Maths;
using Timer = Robust.Shared.Timing.Timer;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
namespace Robust.Client.UserInterface.Controls

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BoxContainer;

View File

@@ -7,6 +7,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using Direction = Robust.Shared.Maths.Direction;
namespace Robust.Client.UserInterface.Controls
{

View File

@@ -2,6 +2,7 @@
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;

View File

@@ -2,6 +2,7 @@
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Maths;

View File

@@ -3,6 +3,7 @@ using System.Numerics;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;

View File

@@ -2,6 +2,7 @@
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Graphics;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.StylesheetHelpers;

View File

@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;

View File

@@ -1,39 +1,40 @@
using System;
using Robust.Client.Graphics;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.Maths;
using static Robust.Client.GameObjects.SpriteComponent;
using RSIDirection = Robust.Client.Graphics.RSI.State.Direction;
using Direction = Robust.Shared.Maths.Direction;
namespace Robust.Client.Utility
{
public static class DirExt
{
public static Direction Convert(this RSIDirection dir)
public static Direction Convert(this RsiDirection dir)
{
switch (dir)
{
case RSIDirection.South:
case RsiDirection.South:
return Direction.South;
case RSIDirection.North:
case RsiDirection.North:
return Direction.North;
case RSIDirection.East:
case RsiDirection.East:
return Direction.East;
case RSIDirection.West:
case RsiDirection.West:
return Direction.West;
case RSIDirection.SouthEast:
case RsiDirection.SouthEast:
return Direction.SouthEast;
case RSIDirection.SouthWest:
case RsiDirection.SouthWest:
return Direction.SouthWest;
case RSIDirection.NorthEast:
case RsiDirection.NorthEast:
return Direction.NorthEast;
case RSIDirection.NorthWest:
case RsiDirection.NorthWest:
return Direction.NorthWest;
}
@@ -46,54 +47,54 @@ namespace Robust.Client.Utility
/// <param name="dir">The direction to round</param>
/// <returns><paramref name="dir"/> if it's a cardinal direction, otherwise either north or
/// south.</returns>
public static RSIDirection RoundToCardinal(this RSIDirection dir)
public static RsiDirection RoundToCardinal(this RsiDirection dir)
{
switch (dir)
{
case RSIDirection.NorthEast:
case RSIDirection.NorthWest:
return RSIDirection.North;
case RsiDirection.NorthEast:
case RsiDirection.NorthWest:
return RsiDirection.North;
case RSIDirection.SouthEast:
case RSIDirection.SouthWest:
return RSIDirection.South;
case RsiDirection.SouthEast:
case RsiDirection.SouthWest:
return RsiDirection.South;
default:
return dir;
}
}
public static RSIDirection Convert(this Direction dir, RSI.State.DirectionType type)
public static RsiDirection Convert(this Direction dir, RsiDirectionType type)
{
if (type == RSI.State.DirectionType.Dir1)
return RSIDirection.South;
if (type == RsiDirectionType.Dir1)
return RsiDirection.South;
switch (dir)
{
case Direction.North:
return RSIDirection.North;
return RsiDirection.North;
case Direction.South:
return RSIDirection.South;
return RsiDirection.South;
case Direction.East:
return RSIDirection.East;
return RsiDirection.East;
case Direction.West:
return RSIDirection.West;
return RsiDirection.West;
}
var rsiDir = dir switch
{
Direction.SouthEast => RSIDirection.SouthEast,
Direction.SouthWest => RSIDirection.SouthWest,
Direction.NorthEast => RSIDirection.NorthEast,
Direction.NorthWest => RSIDirection.NorthWest,
Direction.SouthEast => RsiDirection.SouthEast,
Direction.SouthWest => RsiDirection.SouthWest,
Direction.NorthEast => RsiDirection.NorthEast,
Direction.NorthWest => RsiDirection.NorthWest,
_ => throw new ArgumentException($"Unknown dir: {dir}.", nameof(dir))
};
// Round down to a four-way direction if appropriate.
if (type == RSI.State.DirectionType.Dir4)
if (type == RsiDirectionType.Dir4)
{
return RoundToCardinal(rsiDir);
}
@@ -111,18 +112,18 @@ namespace Robust.Client.Utility
return (Direction)(((int)dir + 1) % 8);
}
public static RSIDirection ToRsiDirection(this Angle angle, RSI.State.DirectionType type)
public static RsiDirection ToRsiDirection(this Angle angle, RsiDirectionType type)
{
return type switch
{
RSI.State.DirectionType.Dir1 => RSIDirection.South,
RSI.State.DirectionType.Dir4 => angle.GetCardinalDir().Convert(type),
RSI.State.DirectionType.Dir8 => angle.GetDir().Convert(type),
RsiDirectionType.Dir1 => RsiDirection.South,
RsiDirectionType.Dir4 => angle.GetCardinalDir().Convert(type),
RsiDirectionType.Dir8 => angle.GetDir().Convert(type),
_ => throw new ArgumentOutOfRangeException($"Unknown rsi direction type: {type}.", nameof(type))
};
}
public static RSIDirection OffsetRsiDir(this RSIDirection dir, DirectionOffset offset)
public static RsiDirection OffsetRsiDir(this RsiDirection dir, DirectionOffset offset)
{
// There is probably a better way to do this.
// Eh.
@@ -136,32 +137,32 @@ namespace Robust.Client.Utility
case DirectionOffset.Clockwise:
return dir switch
{
RSIDirection.North => RSIDirection.East,
RSIDirection.East => RSIDirection.South,
RSIDirection.South => RSIDirection.West,
RSIDirection.West => RSIDirection.North,
RsiDirection.North => RsiDirection.East,
RsiDirection.East => RsiDirection.South,
RsiDirection.South => RsiDirection.West,
RsiDirection.West => RsiDirection.North,
_ => throw new NotImplementedException()
};
case DirectionOffset.CounterClockwise:
return dir switch
{
RSIDirection.North => RSIDirection.West,
RSIDirection.East => RSIDirection.North,
RSIDirection.South => RSIDirection.East,
RSIDirection.West => RSIDirection.South,
RsiDirection.North => RsiDirection.West,
RsiDirection.East => RsiDirection.North,
RsiDirection.South => RsiDirection.East,
RsiDirection.West => RsiDirection.South,
_ => throw new NotImplementedException()
};
case DirectionOffset.Flip:
switch (dir)
{
case RSIDirection.North:
return RSIDirection.South;
case RSIDirection.East:
return RSIDirection.West;
case RSIDirection.South:
return RSIDirection.North;
case RSIDirection.West:
return RSIDirection.East;
case RsiDirection.North:
return RsiDirection.South;
case RsiDirection.East:
return RsiDirection.West;
case RsiDirection.South:
return RsiDirection.North;
case RsiDirection.West:
return RsiDirection.East;
default:
throw new NotImplementedException();
}

View File

@@ -3,6 +3,7 @@ using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Prototypes;

View File

@@ -1,8 +0,0 @@
using Robust.Shared.GameObjects;
namespace Robust.Server.GameObjects
{
[RegisterComponent]
[ComponentReference(typeof(SharedPointLightComponent))]
public sealed partial class PointLightComponent : SharedPointLightComponent {}
}

View File

@@ -0,0 +1,9 @@
using Robust.Shared.GameObjects;
namespace Robust.Server.GameObjects;
[RegisterComponent]
public sealed partial class PointLightComponent : SharedPointLightComponent
{
}

View File

@@ -1,9 +1,62 @@
using System.Diagnostics.CodeAnalysis;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
namespace Robust.Server.GameObjects
namespace Robust.Server.GameObjects;
public sealed class PointLightSystem : SharedPointLightSystem
{
public sealed class PointLightSystem : SharedPointLightSystem
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PointLightComponent, ComponentGetState>(OnLightGetState);
}
private void OnLightGetState(EntityUid uid, PointLightComponent component, ref ComponentGetState args)
{
args.State = new PointLightComponentState()
{
Color = component.Color,
Enabled = component.Enabled,
Energy = component.Energy,
Offset = component.Offset,
Radius = component.Radius,
Softness = component.Softness,
CastShadows = component.CastShadows,
};
}
public override SharedPointLightComponent EnsureLight(EntityUid uid)
{
return EnsureComp<PointLightComponent>(uid);
}
public override bool ResolveLight(EntityUid uid, [NotNullWhen(true)] ref SharedPointLightComponent? component)
{
if (TryComp<PointLightComponent>(uid, out var comp))
{
component = comp;
return true;
}
component = null;
return false;
}
public override bool TryGetLight(EntityUid uid, [NotNullWhen(true)] out SharedPointLightComponent? component)
{
if (TryComp<PointLightComponent>(uid, out var comp))
{
component = comp;
return true;
}
component = null;
return false;
}
public override bool RemoveLightDeferred(EntityUid uid)
{
return RemCompDeferred<PointLightComponent>(uid);
}
}

View File

@@ -1,33 +1,24 @@
using System;
using System;
using System.Numerics;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
namespace Robust.Shared.GameObjects
namespace Robust.Shared.GameObjects;
[Serializable, NetSerializable]
public sealed class PointLightComponentState : ComponentState
{
[Serializable, NetSerializable]
public sealed class PointLightComponentState : ComponentState
{
public readonly Color Color;
public Color Color;
public readonly float Energy;
public float Energy;
public readonly float Softness;
public readonly bool Enabled;
public readonly bool CastShadows;
public float Softness;
public readonly float Radius;
public readonly Vector2 Offset;
public bool CastShadows;
public PointLightComponentState(bool enabled, Color color, float radius, Vector2 offset, float energy, float softness, bool castShadows)
{
Enabled = enabled;
Color = color;
Radius = radius;
Offset = offset;
Energy = energy;
Softness = softness;
CastShadows = castShadows;
}
}
public bool Enabled;
public float Radius;
public Vector2 Offset;
}

View File

@@ -1,121 +1,77 @@
using Robust.Shared.Animations;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using System;
using System.Numerics;
namespace Robust.Shared.GameObjects
{
[NetworkedComponent]
[NetworkedComponent, Access(typeof(SharedPointLightSystem))]
public abstract partial class SharedPointLightComponent : Component
{
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
[DataField("color")]
protected Color _color = Color.White;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("color"), AutoNetworkedField]
[Animatable]
public Color Color { get; set; } = Color.White;
/// <summary>
/// Offset from the center of the entity.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("offset")]
protected Vector2 _offset = Vector2.Zero;
[Access(Other = AccessPermissions.ReadWriteExecute)]
public Vector2 Offset = Vector2.Zero;
[DataField("energy")]
private float _energy = 1f;
[DataField("softness")]
private float _softness = 1f;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("energy"), AutoNetworkedField]
[Animatable]
public float Energy { get; set; } = 1f;
[DataField("softness"), AutoNetworkedField, Animatable]
public float Softness { get; set; } = 1f;
/// <summary>
/// Whether this pointlight should cast shadows
/// </summary>
[DataField("castShadows")]
[DataField("castShadows"), AutoNetworkedField]
public bool CastShadows = true;
[Access(typeof(SharedPointLightSystem))]
[DataField("enabled")]
public bool _enabled = true;
[ViewVariables(VVAccess.ReadWrite)]
[Animatable] // please somebody ECS animations
public bool Enabled
{
get => _enabled;
[Obsolete("Use the system's setter")]
set => _sysMan.GetEntitySystem<SharedPointLightSystem>().SetEnabled(Owner, value, this);
}
[ViewVariables(VVAccess.ReadWrite)]
public virtual Color Color
{
get => _color;
set
{
if (_color.Equals(value)) return;
_color = value;
Dirty();
}
}
[Animatable]
public bool Enabled { get; set; } = true;
/// <summary>
/// How far the light projects.
/// </summary>
[DataField("radius")]
[Access(typeof(SharedPointLightSystem))]
public float _radius = 5f;
[ViewVariables(VVAccess.ReadWrite)]
[Animatable] // please somebody ECS animations
public float Radius
{
get => _radius;
[Obsolete("Use the system's setter")]
set => _sysMan.GetEntitySystem<SharedPointLightSystem>().SetRadius(Owner, value, this);
}
[ViewVariables(VVAccess.ReadWrite)]
public Vector2 Offset
{
get => _offset;
set
{
if (_offset.EqualsApprox(value)) return;
_offset = value;
Dirty();
}
}
[ViewVariables(VVAccess.ReadWrite)]
[Animatable]
public float Energy
{
get => _energy;
set
{
if (_energy.Equals(value)) return;
_energy = value;
Dirty();
}
}
public float Radius { get; set; } = 5f;
[ViewVariables]
public bool ContainerOccluded;
/// <summary>
/// Soft shadow strength multiplier.
/// Has no effect if soft shadows are not enabled.
/// Determines if the light mask should automatically rotate with the entity. (like a flashlight)
/// </summary>
[ViewVariables(VVAccess.ReadWrite)] [DataField("autoRot")]
public bool MaskAutoRotate;
/// <summary>
/// Local rotation of the light mask around the center origin
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[Animatable]
public float Softness
{
get => _softness;
set
{
if (_softness.Equals(value)) return;
_softness = value;
Dirty();
}
}
public Angle Rotation { get; set; }
/// <summary>
/// The resource path to the mask texture the light will use.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("mask")]
public string? MaskPath;
}
public sealed class PointLightToggleEvent : EntityEventArgs

View File

@@ -1,52 +1,70 @@
using Robust.Shared.GameStates;
using System.Diagnostics.CodeAnalysis;
using Robust.Shared.Maths;
namespace Robust.Shared.GameObjects
namespace Robust.Shared.GameObjects;
public abstract class SharedPointLightSystem : EntitySystem
{
public abstract class SharedPointLightSystem : EntitySystem
public abstract SharedPointLightComponent EnsureLight(EntityUid uid);
public abstract bool ResolveLight(EntityUid uid, [NotNullWhen(true)] ref SharedPointLightComponent? component);
public abstract bool TryGetLight(EntityUid uid, [NotNullWhen(true)] out SharedPointLightComponent? component);
public abstract bool RemoveLightDeferred(EntityUid uid);
public void SetCastShadows(EntityUid uid, bool value, SharedPointLightComponent? comp = null)
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SharedPointLightComponent, ComponentGetState>(GetCompState);
SubscribeLocalEvent<SharedPointLightComponent, ComponentHandleState>(HandleCompState);
}
if (!ResolveLight(uid, ref comp) || value == comp.CastShadows)
return;
private void GetCompState(EntityUid uid, SharedPointLightComponent component, ref ComponentGetState args)
{
args.State = new PointLightComponentState(component.Enabled, component.Color, component.Radius, component.Offset, component.Energy, component.Softness, component.CastShadows);
}
comp.CastShadows = value;
Dirty(uid, comp);
}
private void HandleCompState(EntityUid uid, SharedPointLightComponent component, ref ComponentHandleState args)
{
if (args.Current is not PointLightComponentState newState) return;
public void SetColor(EntityUid uid, Color value, SharedPointLightComponent? comp = null)
{
if (!ResolveLight(uid, ref comp) || value == comp.Color)
return;
SetEnabled(uid, newState.Enabled, component);
SetRadius(uid, newState.Radius, component);
component.Offset = newState.Offset;
component.Color = newState.Color;
component.Energy = newState.Energy;
component.Softness = newState.Softness;
component.CastShadows = newState.CastShadows;
}
comp.Color = value;
Dirty(uid, comp);
}
public virtual void SetEnabled(EntityUid uid, bool enabled, SharedPointLightComponent? comp = null)
{
if (!Resolve(uid, ref comp) || enabled == comp.Enabled)
return;
public virtual void SetEnabled(EntityUid uid, bool enabled, SharedPointLightComponent? comp = null)
{
if (!ResolveLight(uid, ref comp) || enabled == comp.Enabled)
return;
comp._enabled = enabled;
RaiseLocalEvent(uid, new PointLightToggleEvent(comp.Enabled));
Dirty(uid, comp);
}
comp.Enabled = enabled;
RaiseLocalEvent(uid, new PointLightToggleEvent(comp.Enabled));
Dirty(uid, comp);
}
public virtual void SetRadius(EntityUid uid, float radius, SharedPointLightComponent? comp = null)
{
if (!Resolve(uid, ref comp) || MathHelper.CloseToPercent(comp.Radius, radius))
return;
public void SetEnergy(EntityUid uid, float value, SharedPointLightComponent? comp = null)
{
if (!ResolveLight(uid, ref comp) || MathHelper.CloseToPercent(comp.Energy, value))
return;
comp._radius = radius;
Dirty(uid, comp);
}
comp.Energy = value;
Dirty(uid, comp);
}
public virtual void SetRadius(EntityUid uid, float radius, SharedPointLightComponent? comp = null)
{
if (!ResolveLight(uid, ref comp) || MathHelper.CloseToPercent(comp.Radius, radius))
return;
comp.Radius = radius;
Dirty(uid, comp);
}
public void SetSoftness(EntityUid uid, float value, SharedPointLightComponent? comp = null)
{
if (!ResolveLight(uid, ref comp) || MathHelper.CloseToPercent(comp.Softness, value))
return;
comp.Softness = value;
Dirty(uid, comp);
}
}

View File

@@ -0,0 +1,9 @@
namespace Robust.Shared.Graphics
{
public enum ClydeStockTexture : byte
{
White,
Black,
Transparent
}
}

View File

@@ -0,0 +1,20 @@
namespace Robust.Shared.Graphics.RSI;
/// <summary>
/// Specifies a direction in an RSI state.
/// </summary>
/// <remarks>
/// Value of the enum here matches the index used to store it in the icons array. If this ever changes, then
/// <see cref="Robust.Client.GameObjects.SpriteComponent.Layer._rsiDirectionMatrices"/> also needs to be updated.
/// </remarks>
public enum RsiDirection : byte
{
South = 0,
North = 1,
East = 2,
West = 3,
SouthEast = 4,
SouthWest = 5,
NorthEast = 6,
NorthWest = 7,
}

View File

@@ -0,0 +1,22 @@
namespace Robust.Shared.Graphics.RSI;
/// <summary>
/// Specifies which types of directions an RSI state has.
/// </summary>
public enum RsiDirectionType : byte
{
/// <summary>
/// A single direction, namely South.
/// </summary>
Dir1,
/// <summary>
/// 4 cardinal directions.
/// </summary>
Dir4,
/// <summary>
/// 4 cardinal + 4 diagonal directions.
/// </summary>
Dir8,
}

View File

@@ -0,0 +1,44 @@
using JetBrains.Annotations;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Graphics;
/// <summary>
/// Flags for loading of textures.
/// </summary>
[PublicAPI]
public struct TextureLoadParameters
{
/// <summary>
/// The default sampling parameters for the texture.
/// </summary>
public TextureSampleParameters SampleParameters { get; set; }
/// <summary>
/// If true, the image data will be treated as sRGB.
/// </summary>
public bool Srgb { get; set; }
public static TextureLoadParameters FromYaml(YamlMappingNode yaml)
{
var loadParams = Default;
if (yaml.TryGetNode("sample", out YamlMappingNode? sampleNode))
{
loadParams.SampleParameters = TextureSampleParameters.FromYaml(sampleNode);
}
if (yaml.TryGetNode("srgb", out var srgb))
{
loadParams.Srgb = srgb.AsBool();
}
return loadParams;
}
public static readonly TextureLoadParameters Default = new()
{
SampleParameters = TextureSampleParameters.Default,
Srgb = true
};
}

View File

@@ -0,0 +1,65 @@
using System;
using JetBrains.Annotations;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Graphics;
/// <summary>
/// Sample flags for textures.
/// These are separate from <see cref="TextureLoadParameters"/>,
/// because it is possible to create "proxies" to existing textures
/// with different sampling parameters than the base texture.
/// </summary>
[PublicAPI]
public struct TextureSampleParameters
{
// NOTE: If somebody is gonna add support for 3D/1D textures, change this doc comment.
// See the note on this page for why: https://www.khronos.org/opengl/wiki/Sampler_Object#Filtering
/// <summary>
/// If true, use bi-linear texture filtering if the texture cannot be rendered 1:1
/// </summary>
public bool Filter { get; set; }
/// <summary>
/// Controls how to wrap the texture if texture coordinates outside 0-1 are accessed.
/// </summary>
public TextureWrapMode WrapMode { get; set; }
public static TextureSampleParameters FromYaml(YamlMappingNode node)
{
var wrap = TextureWrapMode.None;
var filter = false;
if (node.TryGetNode("filter", out var filterNode))
{
filter = filterNode.AsBool();
}
if (node.TryGetNode("wrap", out var wrapNode))
{
switch (wrapNode.AsString())
{
case "none":
wrap = TextureWrapMode.None;
break;
case "repeat":
wrap = TextureWrapMode.Repeat;
break;
case "mirrored_repeat":
wrap = TextureWrapMode.MirroredRepeat;
break;
default:
throw new ArgumentException("Not a valid wrap mode.");
}
}
return new TextureSampleParameters {Filter = filter, WrapMode = wrap};
}
public static readonly TextureSampleParameters Default = new()
{
Filter = false,
WrapMode = TextureWrapMode.None
};
}

View File

@@ -0,0 +1,26 @@
using JetBrains.Annotations;
namespace Robust.Shared.Graphics
{
/// <summary>
/// Controls behavior when reading texture coordinates outside 0-1, which usually wraps the texture somehow.
/// </summary>
[PublicAPI]
public enum TextureWrapMode : byte
{
/// <summary>
/// Do not wrap, instead clamp to edge.
/// </summary>
None = 0,
/// <summary>
/// Repeat the texture.
/// </summary>
Repeat,
/// <summary>
/// Repeat the texture mirrored.
/// </summary>
MirroredRepeat,
}
}

View File

@@ -1,6 +1,7 @@
using System.IO;
using NUnit.Framework;
using Robust.Client.Graphics;
using Robust.Shared.Graphics;
using YamlDotNet.RepresentationModel;
namespace Robust.UnitTesting.Client.Graphics

View File

@@ -58,7 +58,7 @@ namespace Robust.UnitTesting.Shared.Prototypes
Assert.That(prototype.Components, Contains.Key("PointLight"));
});
var componentData = prototype.Components["PointLight"].Component as PointLightComponent;
var componentData = prototype.Components["PointLight"].Component as SharedPointLightComponent;
Assert.That(componentData!.NetSyncEnabled, Is.EqualTo(false));
}