mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0d241e551 | ||
|
|
33a6934582 | ||
|
|
f237a8bbbc | ||
|
|
4bc775c01c | ||
|
|
93b4d81505 | ||
|
|
0afb85a09e | ||
|
|
7b9315cea4 | ||
|
|
dc3af45096 |
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -41,14 +42,14 @@ namespace Robust.Client.Debugging
|
||||
|
||||
_debugColliders = value;
|
||||
|
||||
if (value)
|
||||
if (value && !_overlayManager.HasOverlay<PhysicsOverlay>())
|
||||
{
|
||||
_overlayManager.AddOverlay(new PhysicsOverlay(_componentManager, _eyeManager,
|
||||
_prototypeManager, _inputManager, _physicsManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
_overlayManager.RemoveOverlay(nameof(PhysicsOverlay));
|
||||
_overlayManager.RemoveOverlay<PhysicsOverlay>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,13 +67,13 @@ namespace Robust.Client.Debugging
|
||||
|
||||
_debugPositions = value;
|
||||
|
||||
if (value)
|
||||
if (value && !_overlayManager.HasOverlay<EntityPositionOverlay>())
|
||||
{
|
||||
_overlayManager.AddOverlay(new EntityPositionOverlay(_entityManager, _eyeManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
_overlayManager.RemoveOverlay(nameof(EntityPositionOverlay));
|
||||
_overlayManager.RemoveOverlay<EntityPositionOverlay>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,8 +92,8 @@ namespace Robust.Client.Debugging
|
||||
private Vector2 _hoverStartScreen = Vector2.Zero;
|
||||
private List<IPhysBody> _hoverBodies = new();
|
||||
|
||||
|
||||
public PhysicsOverlay(IComponentManager compMan, IEyeManager eyeMan, IPrototypeManager protoMan, IInputManager inputManager, IPhysicsManager physicsManager)
|
||||
: base(nameof(PhysicsOverlay))
|
||||
{
|
||||
_componentManager = compMan;
|
||||
_eyeManager = eyeMan;
|
||||
@@ -265,7 +266,7 @@ namespace Robust.Client.Debugging
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
public EntityPositionOverlay(IEntityManager entityManager, IEyeManager eyeManager) : base(nameof(EntityPositionOverlay))
|
||||
public EntityPositionOverlay(IEntityManager entityManager, IEyeManager eyeManager)
|
||||
{
|
||||
_entityManager = entityManager;
|
||||
_eyeManager = eyeManager;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Robust.Client.Debugging
|
||||
@@ -38,13 +39,13 @@ namespace Robust.Client.Debugging
|
||||
|
||||
_debugDrawRays = value;
|
||||
|
||||
if (value)
|
||||
if (value && !_overlayManager.HasOverlay<DebugDrawRayOverlay>())
|
||||
{
|
||||
_overlayManager.AddOverlay(new DebugDrawRayOverlay(this));
|
||||
}
|
||||
else
|
||||
{
|
||||
_overlayManager.RemoveOverlay(nameof(DebugDrawRayOverlay));
|
||||
_overlayManager.RemoveOverlay<DebugDrawRayOverlay>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +82,7 @@ namespace Robust.Client.Debugging
|
||||
private readonly DebugDrawingManager _owner;
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
public DebugDrawRayOverlay(DebugDrawingManager owner) : base(nameof(DebugDrawRayOverlay))
|
||||
public DebugDrawRayOverlay(DebugDrawingManager owner)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
using System;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -55,7 +56,7 @@ namespace Robust.Client.Debugging
|
||||
IoCManager.Resolve<IOverlayManager>().AddOverlay(new PhysicsDebugOverlay(this));
|
||||
|
||||
if (value == PhysicsDebugFlags.None)
|
||||
IoCManager.Resolve<IOverlayManager>().RemoveOverlay(nameof(PhysicsDebugOverlay));
|
||||
IoCManager.Resolve<IOverlayManager>().RemoveOverlay(typeof(PhysicsDebugOverlay));
|
||||
|
||||
_flags = value;
|
||||
}
|
||||
@@ -119,7 +120,7 @@ namespace Robust.Client.Debugging
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
public PhysicsDebugOverlay(DebugPhysicsSystem system) : base(nameof(PhysicsDebugOverlay))
|
||||
public PhysicsDebugOverlay(DebugPhysicsSystem system)
|
||||
{
|
||||
_physics = system;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Enums;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
@@ -42,7 +43,7 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
overlayManager.RemoveOverlay("EffectSystem");
|
||||
overlayManager.RemoveOverlay(typeof(EffectOverlay));
|
||||
}
|
||||
|
||||
public void CreateEffect(EffectSystemMessage message)
|
||||
@@ -329,7 +330,6 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
private readonly IPlayerManager _playerManager;
|
||||
|
||||
public override bool AlwaysDirty => true;
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
private readonly ShaderInstance _unshadedShader;
|
||||
@@ -337,8 +337,7 @@ namespace Robust.Client.GameObjects
|
||||
private readonly IMapManager _mapManager;
|
||||
private readonly IEntityManager _entityManager;
|
||||
|
||||
public EffectOverlay(EffectSystem owner, IPrototypeManager protoMan, IMapManager mapMan, IPlayerManager playerMan, IEntityManager entityManager) : base(
|
||||
"EffectSystem")
|
||||
public EffectOverlay(EffectSystem owner, IPrototypeManager protoMan, IMapManager mapMan, IPlayerManager playerMan, IEntityManager entityManager)
|
||||
{
|
||||
_owner = owner;
|
||||
_unshadedShader = protoMan.Index<ShaderPrototype>("unshaded").Instance();
|
||||
|
||||
@@ -3,6 +3,7 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -33,7 +34,7 @@ namespace Robust.Client.GameStates
|
||||
private readonly int _lineHeight;
|
||||
private readonly List<NetEntity> _netEnts = new();
|
||||
|
||||
public NetEntityOverlay() : base(nameof(NetEntityOverlay))
|
||||
public NetEntityOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
var cache = IoCManager.Resolve<IResourceCache>();
|
||||
@@ -179,11 +180,10 @@ namespace Robust.Client.GameStates
|
||||
return Color.Green; // Entity in PVS, but not updated recently.
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override void DisposeBehavior()
|
||||
{
|
||||
_gameStateManager.GameStateApplied -= HandleGameStateApplied;
|
||||
|
||||
base.Dispose(disposing);
|
||||
base.DisposeBehavior();
|
||||
}
|
||||
|
||||
private static void DrawString(DrawingHandleScreen handle, Font font, Vector2 pos, string str, Color textColor)
|
||||
@@ -238,14 +238,14 @@ namespace Robust.Client.GameStates
|
||||
var bValue = iValue > 0;
|
||||
var overlayMan = IoCManager.Resolve<IOverlayManager>();
|
||||
|
||||
if(bValue && !overlayMan.HasOverlay(nameof(NetEntityOverlay)))
|
||||
if(bValue && !overlayMan.HasOverlay(typeof(NetEntityOverlay)))
|
||||
{
|
||||
overlayMan.AddOverlay(new NetEntityOverlay());
|
||||
shell.WriteLine("Enabled network entity report overlay.");
|
||||
}
|
||||
else if(!bValue && overlayMan.HasOverlay(nameof(NetEntityOverlay)))
|
||||
else if(!bValue && overlayMan.HasOverlay(typeof(NetEntityOverlay)))
|
||||
{
|
||||
overlayMan.RemoveOverlay(nameof(NetEntityOverlay));
|
||||
overlayMan.RemoveOverlay(typeof(NetEntityOverlay));
|
||||
shell.WriteLine("Disabled network entity report overlay.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -34,7 +36,7 @@ namespace Robust.Client.GameStates
|
||||
|
||||
private readonly List<(GameTick Tick, int Payload, int lag, int interp)> _history = new(HistorySize+10);
|
||||
|
||||
public NetGraphOverlay() : base(nameof(NetGraphOverlay))
|
||||
public NetGraphOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
var cache = IoCManager.Resolve<IResourceCache>();
|
||||
@@ -142,11 +144,11 @@ namespace Robust.Client.GameStates
|
||||
DrawString((DrawingHandleScreen)handle, _font, new Vector2(leftMargin, height + LowerGraphOffset), $"{_gameStateManager.CurrentBufferSize.ToString()} states");
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
protected override void DisposeBehavior()
|
||||
{
|
||||
_gameStateManager.GameStateApplied -= HandleGameStateApplied;
|
||||
|
||||
base.Dispose(disposing);
|
||||
base.DisposeBehavior();
|
||||
}
|
||||
|
||||
private void DrawString(DrawingHandleScreen handle, Font font, Vector2 pos, string str)
|
||||
@@ -183,14 +185,14 @@ namespace Robust.Client.GameStates
|
||||
var bValue = iValue > 0;
|
||||
var overlayMan = IoCManager.Resolve<IOverlayManager>();
|
||||
|
||||
if(bValue && !overlayMan.HasOverlay(nameof(NetGraphOverlay)))
|
||||
if(bValue && !overlayMan.HasOverlay(typeof(NetGraphOverlay)))
|
||||
{
|
||||
overlayMan.AddOverlay(new NetGraphOverlay());
|
||||
shell.WriteLine("Enabled network overlay.");
|
||||
}
|
||||
else if(overlayMan.HasOverlay(nameof(NetGraphOverlay)))
|
||||
else if(overlayMan.HasOverlay(typeof(NetGraphOverlay)))
|
||||
{
|
||||
overlayMan.RemoveOverlay(nameof(NetGraphOverlay));
|
||||
overlayMan.RemoveOverlay(typeof(NetGraphOverlay));
|
||||
shell.WriteLine("Disabled network overlay.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -5,6 +6,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Client.GameStates
|
||||
@@ -18,7 +20,7 @@ namespace Robust.Client.GameStates
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
private readonly ShaderInstance _shader;
|
||||
|
||||
public NetInterpOverlay() : base(nameof(NetInterpOverlay))
|
||||
public NetInterpOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _prototypeManager.Index<ShaderPrototype>("unshaded").Instance();
|
||||
@@ -85,14 +87,14 @@ namespace Robust.Client.GameStates
|
||||
var bValue = iValue > 0;
|
||||
var overlayMan = IoCManager.Resolve<IOverlayManager>();
|
||||
|
||||
if (bValue && !overlayMan.HasOverlay(nameof(NetInterpOverlay)))
|
||||
if (bValue && !overlayMan.HasOverlay<NetInterpOverlay>())
|
||||
{
|
||||
overlayMan.AddOverlay(new NetInterpOverlay());
|
||||
shell.WriteLine("Enabled network interp overlay.");
|
||||
}
|
||||
else if (overlayMan.HasOverlay(nameof(NetInterpOverlay)))
|
||||
else if (overlayMan.HasOverlay<NetInterpOverlay>())
|
||||
{
|
||||
overlayMan.RemoveOverlay(nameof(NetInterpOverlay));
|
||||
overlayMan.RemoveOverlay<NetInterpOverlay>();
|
||||
shell.WriteLine("Disabled network interp overlay.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using JetBrains.Annotations;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using OpenToolkit.Graphics.OpenGL4;
|
||||
using Robust.Shared.Enums;
|
||||
|
||||
namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
@@ -68,8 +70,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
RenderOverlays(OverlaySpace.ScreenSpaceBelowWorld);
|
||||
|
||||
_mainViewport.Eye = _eyeManager.CurrentEye;
|
||||
RenderViewport(_mainViewport);
|
||||
|
||||
RenderViewport(_mainViewport); //Worldspace overlays are rendered here.
|
||||
{
|
||||
var handle = _renderHandle.DrawingHandleScreen;
|
||||
var tex = _mainViewport.RenderTarget.Texture;
|
||||
@@ -107,25 +108,67 @@ namespace Robust.Client.Graphics.Clyde
|
||||
list.Add(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
list.Sort(OverlayComparer.Instance);
|
||||
|
||||
foreach (var overlay in list)
|
||||
{
|
||||
overlay.ClydeRender(_renderHandle, space);
|
||||
}
|
||||
|
||||
FlushRenderQueue();
|
||||
list.Sort(OverlayComparer.Instance);
|
||||
foreach (var overlay in list) {
|
||||
if (overlay.RequestScreenTexture) {
|
||||
FlushRenderQueue();
|
||||
UpdateOverlayScreenTexture(space, _mainViewport.RenderTarget);
|
||||
}
|
||||
if (overlay.OverwriteTargetFrameBuffer()) {
|
||||
ClearFramebuffer(default);
|
||||
}
|
||||
overlay.ClydeRender(_renderHandle, space);
|
||||
FlushRenderQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEntitiesAndWorldOverlay(Viewport viewport, Box2 worldBounds)
|
||||
private ClydeTexture? ScreenBufferTexture;
|
||||
private GLHandle screenBufferHandle;
|
||||
private Vector2 lastFrameSize;
|
||||
/// <summary>
|
||||
/// Sends SCREEN_TEXTURE to all overlays in the given OverlaySpace that request it.
|
||||
/// </summary>
|
||||
private bool UpdateOverlayScreenTexture(OverlaySpace space, RenderTexture texture) {
|
||||
//This currently does NOT consider viewports and just grabs the current screen framebuffer. This will need to be improved upon in the future.
|
||||
List<Overlay> oTargets = new List<Overlay>();
|
||||
foreach (var overlay in _overlayManager.AllOverlays) {
|
||||
if (overlay.RequestScreenTexture && overlay.Space == space) {
|
||||
oTargets.Add(overlay);
|
||||
}
|
||||
}
|
||||
if (oTargets.Count > 0 && ScreenBufferTexture != null) {
|
||||
if (lastFrameSize != _framebufferSize) {
|
||||
GL.BindTexture(TextureTarget.Texture2D, screenBufferHandle.Handle);
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Srgb8Alpha8, _framebufferSize.X, _framebufferSize.Y, 0,
|
||||
PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
|
||||
}
|
||||
lastFrameSize = _framebufferSize;
|
||||
CopyRenderTextureToTexture(texture, ScreenBufferTexture);
|
||||
foreach (Overlay overlay in oTargets) {
|
||||
overlay.ScreenTexture = ScreenBufferTexture;
|
||||
}
|
||||
oTargets.Clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void DrawEntities(Viewport viewport, Box2 worldBounds)
|
||||
{
|
||||
if (_eyeManager.CurrentMap == MapId.Nullspace || !_mapManager.HasMapEntity(_eyeManager.CurrentMap))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RenderOverlays(OverlaySpace.WorldSpaceBelowEntities);
|
||||
|
||||
var screenSize = viewport.Size;
|
||||
|
||||
// So we could calculate the correct size of the entities based on the contents of their sprite...
|
||||
@@ -267,14 +310,6 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
_drawingSpriteList.Clear();
|
||||
FlushRenderQueue();
|
||||
|
||||
// Cleanup remainders
|
||||
foreach (var overlay in worldOverlays)
|
||||
{
|
||||
overlay.ClydeRender(_renderHandle, OverlaySpace.WorldSpace);
|
||||
}
|
||||
|
||||
FlushRenderQueue();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
@@ -368,12 +403,21 @@ namespace Robust.Client.Graphics.Clyde
|
||||
// We will also render worldspace overlays here so we can do them under / above entities as necessary
|
||||
using (DebugGroup("Entities"))
|
||||
{
|
||||
DrawEntitiesAndWorldOverlay(viewport, worldBounds);
|
||||
DrawEntities(viewport, worldBounds);
|
||||
}
|
||||
|
||||
RenderOverlays(OverlaySpace.WorldSpaceBelowFOV);
|
||||
|
||||
if (_lightManager.Enabled && _lightManager.DrawHardFov && eye.DrawFov)
|
||||
{
|
||||
GL.Clear(ClearBufferMask.StencilBufferBit);
|
||||
GL.Enable(EnableCap.StencilTest);
|
||||
GL.StencilOp(OpenToolkit.Graphics.OpenGL4.StencilOp.Keep, OpenToolkit.Graphics.OpenGL4.StencilOp.Keep, OpenToolkit.Graphics.OpenGL4.StencilOp.Replace);
|
||||
GL.StencilFunc(StencilFunction.Always, 1, 0xFF);
|
||||
GL.StencilMask(0xFF);
|
||||
ApplyFovToBuffer(viewport, eye);
|
||||
GL.StencilMask(0x00);
|
||||
GL.Disable(EnableCap.StencilTest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,6 +445,14 @@ namespace Robust.Client.Graphics.Clyde
|
||||
viewport.WallBleedIntermediateRenderTarget2.Texture,
|
||||
UIBox2.FromDimensions(Vector2.Zero, ScreenSize), new Color(1, 1, 1, 0.5f));
|
||||
}
|
||||
|
||||
|
||||
RenderOverlays(OverlaySpace.WorldSpace);
|
||||
|
||||
GL.StencilFunc(StencilFunction.Notequal, 1, 0xFF);
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
RenderOverlays(OverlaySpace.WorldSpaceFOVStencil);
|
||||
GL.Disable(EnableCap.StencilTest);
|
||||
}
|
||||
|
||||
PopRenderStateFull(state);
|
||||
|
||||
@@ -5,6 +5,7 @@ using OpenToolkit.Graphics.OpenGL4;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using ES20 = OpenToolkit.Graphics.ES20;
|
||||
|
||||
namespace Robust.Client.Graphics.Clyde
|
||||
@@ -31,6 +32,27 @@ namespace Robust.Client.Graphics.Clyde
|
||||
CheckGlError();
|
||||
GL.BindTexture(TextureTarget.Texture2D, glHandle.Handle);
|
||||
CheckGlError();
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
}
|
||||
|
||||
private void CopyRenderTextureToTexture(RenderTexture source, ClydeTexture target) {
|
||||
LoadedRenderTarget sourceLoaded = RtToLoaded(source);
|
||||
bool pause = sourceLoaded != _currentBoundRenderTarget;
|
||||
FullStoredRendererState? store = null;
|
||||
if (pause) {
|
||||
store = PushRenderStateFull();
|
||||
BindRenderTargetFull(source);
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, _loadedTextures[target.TextureId].OpenGLObject.Handle);
|
||||
CheckGlError();
|
||||
GL.CopyTexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, 0, 0, _framebufferSize.X, _framebufferSize.Y);
|
||||
CheckGlError();
|
||||
|
||||
if (pause && store != null) {
|
||||
PopRenderStateFull((FullStoredRendererState)store);
|
||||
}
|
||||
}
|
||||
|
||||
private static long EstPixelSize(PixelInternalFormat format)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@@ -280,7 +280,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush the render handle, processing and re-pooling all the command lists.
|
||||
/// Flushes the render handle, processing and re-pooling all the command lists.
|
||||
/// </summary>
|
||||
private void FlushRenderQueue()
|
||||
{
|
||||
@@ -371,6 +371,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
program.Use();
|
||||
|
||||
int textureUnitVal = 0;
|
||||
// Assign shader parameters to uniform since they may be dirty.
|
||||
foreach (var (name, value) in instance.Parameters)
|
||||
{
|
||||
@@ -413,6 +414,15 @@ namespace Robust.Client.Graphics.Clyde
|
||||
case Matrix4 matrix4:
|
||||
program.SetUniform(name, matrix4);
|
||||
break;
|
||||
case ClydeTexture clydeTexture:
|
||||
//It's important to start at Texture6 here since DrawCommandBatch uses Texture0 and Texture1 immediately after calling this
|
||||
//function! If passing in textures as uniforms ever stops working it might be since someone made it use all the way up to Texture6 too.
|
||||
//Might change this in the future?
|
||||
TextureUnit cTarget = TextureUnit.Texture6+textureUnitVal;
|
||||
SetTexture(cTarget, ((ClydeTexture)clydeTexture).TextureId);
|
||||
program.SetUniformTexture(name, cTarget);
|
||||
textureUnitVal++;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Unable to handle shader parameter {name}: {value}");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -428,7 +428,8 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
private protected override void SetParameterImpl(string name, Texture value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var data = Parent._shaderInstances[Handle];
|
||||
data.Parameters[name] = value;
|
||||
}
|
||||
|
||||
private protected override void SetStencilOpImpl(StencilOp op)
|
||||
|
||||
@@ -56,19 +56,19 @@ namespace Robust.Client.Graphics.Clyde
|
||||
{
|
||||
// Disable sRGB so stuff doesn't get interpreter wrong.
|
||||
actualParams.Srgb = false;
|
||||
var img = ApplyA8Swizzle((Image<A8>) (object) image);
|
||||
using var img = ApplyA8Swizzle((Image<A8>) (object) image);
|
||||
return LoadTextureFromImage(img, name, loadParams);
|
||||
}
|
||||
|
||||
if (pixelType == typeof(L8) && !actualParams.Srgb)
|
||||
{
|
||||
var img = ApplyL8Swizzle((Image<L8>) (object) image);
|
||||
using var img = ApplyL8Swizzle((Image<L8>) (object) image);
|
||||
return LoadTextureFromImage(img, name, loadParams);
|
||||
}
|
||||
}
|
||||
|
||||
// Flip image because OpenGL reads images upside down.
|
||||
var copy = FlipClone(image);
|
||||
using var copy = FlipClone(image);
|
||||
|
||||
var texture = CreateBaseTextureInternal<T>(image.Width, image.Height, actualParams, name);
|
||||
|
||||
|
||||
@@ -315,6 +315,11 @@ namespace Robust.Client.Graphics.Clyde
|
||||
UniformConstantsUBO = new GLUniformBuffer<UniformConstants>(this, BindingIndexUniformConstants, nameof(UniformConstantsUBO));
|
||||
|
||||
CreateMainViewport();
|
||||
|
||||
screenBufferHandle = new GLHandle(GL.GenTexture());
|
||||
GL.BindTexture(TextureTarget.Texture2D, screenBufferHandle.Handle);
|
||||
ApplySampleParameters(TextureSampleParameters.Default);
|
||||
ScreenBufferTexture = GenTexture(screenBufferHandle, _framebufferSize, true, null, TexturePixelType.Rgba32);
|
||||
}
|
||||
|
||||
private void CreateMainViewport()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using OpenToolkit.Graphics.OpenGL4;
|
||||
|
||||
@@ -1,22 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Client.Graphics
|
||||
{
|
||||
|
||||
[PublicAPI]
|
||||
public interface IOverlayManager
|
||||
{
|
||||
void AddOverlay(Overlay overlay);
|
||||
void RemoveOverlay(string id);
|
||||
bool HasOverlay(string id);
|
||||
bool AddOverlay(Overlay overlay);
|
||||
|
||||
Overlay GetOverlay(string id);
|
||||
T GetOverlay<T>(string id) where T : Overlay;
|
||||
bool RemoveOverlay(Overlay overlay);
|
||||
bool RemoveOverlay(Type overlayClass);
|
||||
bool RemoveOverlay<T>() where T : Overlay;
|
||||
|
||||
bool TryGetOverlay(string id, [NotNullWhen(true)] out Overlay? overlay);
|
||||
bool TryGetOverlay<T>(string id, [NotNullWhen(true)] out T? overlay) where T : Overlay;
|
||||
bool TryGetOverlay(Type overlayClass, out Overlay? overlay);
|
||||
bool TryGetOverlay<T>(out T? overlay) where T : Overlay;
|
||||
|
||||
Overlay GetOverlay(Type overlayClass);
|
||||
T GetOverlay<T>() where T : Overlay;
|
||||
|
||||
bool HasOverlay(Type overlayClass);
|
||||
bool HasOverlay<T>() where T : Overlay;
|
||||
|
||||
IEnumerable<Overlay> AllOverlays { get; }
|
||||
}
|
||||
|
||||
@@ -1,65 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.IoC;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Enums;
|
||||
using System;
|
||||
|
||||
namespace Robust.Client.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// An overlay is used for fullscreen drawing in the game, for example parallax.
|
||||
/// An overlay is used for fullscreen drawing in the game. This can range from drawing parallax to a full screen shader.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public abstract class Overlay
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The ID of this overlay. This is used to identify it inside the <see cref="IOverlayManager"/>.
|
||||
/// Determines when this overlay is drawn in the rendering queue.
|
||||
/// </summary>
|
||||
public string ID { get; }
|
||||
|
||||
public virtual bool AlwaysDirty => false;
|
||||
public bool IsDirty => AlwaysDirty || _isDirty;
|
||||
public bool Drawing { get; private set; }
|
||||
|
||||
public virtual OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
|
||||
/// <summary>
|
||||
/// If set to true, <see cref="ScreenTexture"/> will be set to the current frame (at the moment before the overlay is rendered). This can be costly to performance, but
|
||||
/// some shaders will require it as a passed in uniform to operate.
|
||||
/// </summary>
|
||||
public virtual bool RequestScreenTexture => false;
|
||||
|
||||
/// <summary>
|
||||
/// If <see cref="RequestScreenTexture"> is true, then this will be set to the texture corresponding to the current frame. If false, it will always be null.
|
||||
/// </summary>
|
||||
public Texture? ScreenTexture = null;
|
||||
|
||||
/// <summary>
|
||||
/// Overlays on the same OverlaySpace will be drawn from lowest ZIndex to highest ZIndex. As an example, ZIndex -1 will be drawn before ZIndex 2.
|
||||
/// This value is 0 by default. Overlays with same ZIndex will be drawn in an random order.
|
||||
/// </summary>
|
||||
public int? ZIndex { get; set; }
|
||||
|
||||
protected IOverlayManager OverlayManager { get; }
|
||||
|
||||
public int? ZIndex { get; set; }
|
||||
private bool Disposed = false;
|
||||
|
||||
public virtual bool SubHandlesUseMainShader { get; } = true;
|
||||
|
||||
private bool _isDirty = true;
|
||||
|
||||
private readonly List<DrawingHandleBase> TempHandles = new();
|
||||
|
||||
private bool Disposed;
|
||||
|
||||
protected Overlay(string id)
|
||||
public Overlay()
|
||||
{
|
||||
OverlayManager = IoCManager.Resolve<IOverlayManager>();
|
||||
ID = id;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dispose(true);
|
||||
Disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~Overlay()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
/// <summary>
|
||||
/// If this function returns true, the target framebuffer will be wiped before applying this overlay to it.
|
||||
/// </summary>
|
||||
public virtual bool OverwriteTargetFrameBuffer(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,50 +58,34 @@ namespace Robust.Client.Graphics
|
||||
/// <param name="currentSpace">Current space that is being drawn. This function is called for every space that was set up in initialization.</param>
|
||||
protected abstract void Draw(DrawingHandleBase handle, OverlaySpace currentSpace);
|
||||
|
||||
public void Dirty()
|
||||
{
|
||||
_isDirty = true;
|
||||
protected internal virtual void FrameUpdate(FrameEventArgs args) { }
|
||||
|
||||
~Overlay() {
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
if (Disposed)
|
||||
return;
|
||||
else
|
||||
DisposeBehavior();
|
||||
}
|
||||
|
||||
protected virtual void DisposeBehavior(){
|
||||
Disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected internal virtual void FrameUpdate(FrameEventArgs args) { }
|
||||
|
||||
internal void ClydeRender(IRenderHandle renderHandle, OverlaySpace currentSpace)
|
||||
{
|
||||
DrawingHandleBase handle;
|
||||
if (currentSpace == OverlaySpace.WorldSpace)
|
||||
handle = renderHandle.DrawingHandleWorld;
|
||||
else
|
||||
if (currentSpace == OverlaySpace.ScreenSpace || currentSpace == OverlaySpace.ScreenSpaceBelowWorld)
|
||||
handle = renderHandle.DrawingHandleScreen;
|
||||
else
|
||||
handle = renderHandle.DrawingHandleWorld;
|
||||
|
||||
Draw(handle, currentSpace);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines in which canvas layers an overlay gets drawn.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum OverlaySpace : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for matching bit flags.
|
||||
/// </summary>
|
||||
None = 0b0000,
|
||||
|
||||
/// <summary>
|
||||
/// This overlay will be drawn in the UI root, thus being in screen space.
|
||||
/// </summary>
|
||||
ScreenSpace = 0b0001,
|
||||
|
||||
/// <summary>
|
||||
/// This overlay will be drawn in the world root, thus being in world space.
|
||||
/// </summary>
|
||||
WorldSpace = 0b0010,
|
||||
|
||||
/// <summary>
|
||||
/// Drawn in screen coordinates, but behind the world.
|
||||
/// </summary>
|
||||
ScreenSpaceBelowWorld = 0b0100,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Client.Graphics
|
||||
{
|
||||
internal class OverlayManager : IOverlayManagerInternal
|
||||
{
|
||||
private readonly Dictionary<string, Overlay> _overlays = new();
|
||||
private readonly Dictionary<Type, Overlay> _overlays = new Dictionary<Type, Overlay>();
|
||||
public IEnumerable<Overlay> AllOverlays => _overlays.Values;
|
||||
|
||||
public void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
@@ -17,59 +19,80 @@ namespace Robust.Client.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
public void AddOverlay(Overlay overlay)
|
||||
public bool AddOverlay(Overlay overlay)
|
||||
{
|
||||
if (_overlays.ContainsKey(overlay.ID))
|
||||
{
|
||||
throw new InvalidOperationException($"We already have an overlay with ID '{overlay.ID}'");
|
||||
if(_overlays.ContainsKey(overlay.GetType()))
|
||||
return false;
|
||||
_overlays.Add(overlay.GetType(), overlay);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public bool RemoveOverlay(Type overlayClass)
|
||||
{
|
||||
if(!overlayClass.IsSubclassOf(typeof(Overlay))){
|
||||
Logger.Error("RemoveOverlay was called with arg: " + overlayClass.ToString() + ", which is not a subclass of Overlay!");
|
||||
return false;
|
||||
}
|
||||
|
||||
_overlays.Add(overlay.ID, overlay);
|
||||
return _overlays.Remove(overlayClass);
|
||||
}
|
||||
|
||||
public Overlay GetOverlay(string id)
|
||||
{
|
||||
return _overlays[id];
|
||||
public bool RemoveOverlay<T>() where T : Overlay{
|
||||
return RemoveOverlay(typeof(T));
|
||||
}
|
||||
|
||||
public T GetOverlay<T>(string id) where T : Overlay
|
||||
{
|
||||
return (T) GetOverlay(id);
|
||||
public bool RemoveOverlay(Overlay overlay) {
|
||||
return _overlays.Remove(overlay.GetType());
|
||||
}
|
||||
|
||||
public bool HasOverlay(string id)
|
||||
{
|
||||
return _overlays.ContainsKey(id);
|
||||
}
|
||||
|
||||
public void RemoveOverlay(string id)
|
||||
|
||||
|
||||
|
||||
public bool TryGetOverlay(Type overlayClass, [NotNullWhen(true)] out Overlay? overlay)
|
||||
{
|
||||
if (!_overlays.TryGetValue(id, out var overlay))
|
||||
{
|
||||
return;
|
||||
overlay = null;
|
||||
if (!overlayClass.IsSubclassOf(typeof(Overlay))){
|
||||
Logger.Error("TryGetOverlay was called with arg: " + overlayClass.ToString() + ", which is not a subclass of Overlay!");
|
||||
return false;
|
||||
}
|
||||
|
||||
overlay.Dispose();
|
||||
_overlays.Remove(id);
|
||||
return _overlays.TryGetValue(overlayClass, out overlay);
|
||||
}
|
||||
|
||||
public bool TryGetOverlay(string id, [NotNullWhen(true)] out Overlay? overlay)
|
||||
{
|
||||
return _overlays.TryGetValue(id, out overlay);
|
||||
}
|
||||
|
||||
public bool TryGetOverlay<T>(string id, [NotNullWhen(true)] out T? overlay) where T : Overlay
|
||||
{
|
||||
if (_overlays.TryGetValue(id, out var value))
|
||||
{
|
||||
overlay = (T) value;
|
||||
public bool TryGetOverlay<T>([NotNullWhen(true)] out T? overlay) where T : Overlay {
|
||||
overlay = null;
|
||||
if(_overlays.TryGetValue(typeof(T), out Overlay? toReturn)){
|
||||
overlay = (T)toReturn;
|
||||
return true;
|
||||
}
|
||||
|
||||
overlay = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<Overlay> AllOverlays => _overlays.Values;
|
||||
|
||||
|
||||
|
||||
public Overlay GetOverlay(Type overlayClass) {
|
||||
return _overlays[overlayClass];
|
||||
}
|
||||
|
||||
public T GetOverlay<T>() where T : Overlay {
|
||||
return (T)_overlays[typeof(T)];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public bool HasOverlay(Type overlayClass) {
|
||||
if (!overlayClass.IsSubclassOf(typeof(Overlay)))
|
||||
Logger.Error("HasOverlay was called with arg: " + overlayClass.ToString() + ", which is not a subclass of Overlay!");
|
||||
return _overlays.Remove(overlayClass);
|
||||
}
|
||||
|
||||
public bool HasOverlay<T>() where T : Overlay {
|
||||
return _overlays.Remove(typeof(T));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ namespace Robust.Client.Graphics
|
||||
public sealed class State : IRsiStateLike
|
||||
{
|
||||
// List of delays for the frame to reach the next frame.
|
||||
private readonly float[] Delays;
|
||||
public readonly float[] Delays;
|
||||
|
||||
// 2D array for the texture to use for each animation frame at each direction.
|
||||
private readonly Texture[][] Icons;
|
||||
public readonly Texture[][] Icons;
|
||||
|
||||
internal State(Vector2i size, StateId stateId, DirectionType direction, float[] delays, Texture[][] icons)
|
||||
{
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "RSI Image Format Validation Schema V1",
|
||||
"description": "Robust Station Image",
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
"size": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"x": {"type": "integer", "minimum": 1},
|
||||
"y": {"type": "integer", "minimum": 1}
|
||||
},
|
||||
"required": ["x","y"]
|
||||
},
|
||||
"directions": {
|
||||
"type": "integer",
|
||||
"enum": [1,4,8]
|
||||
},
|
||||
"state": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"flags": {"type": "object"}, //To be de-serialized as a Dictionary
|
||||
"directions": {"$ref": "#/definitions/directions"},
|
||||
"delays": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {"type": "number", "minimum": 0, "exclusiveMinimum": true} //number == float
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["name"] //'delays' is marked as optional in the spec
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"version": {"type": "integer", "minimum": 1, "maximum": 1},
|
||||
"size": {"$ref": "#/definitions/size"},
|
||||
"states": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/definitions/state"},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": ["version","size","states"]
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -67,7 +68,7 @@ namespace Robust.Client.Physics
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
IoCManager.Resolve<IOverlayManager>().RemoveOverlay(nameof(PhysicsIslandOverlay));
|
||||
IoCManager.Resolve<IOverlayManager>().RemoveOverlay(typeof(PhysicsIslandOverlay));
|
||||
}
|
||||
|
||||
private void HandleIslandSolveMessage(IslandSolveMessage message)
|
||||
@@ -94,7 +95,7 @@ namespace Robust.Client.Physics
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
public PhysicsIslandOverlay() : base(nameof(PhysicsIslandOverlay))
|
||||
public PhysicsIslandOverlay()
|
||||
{
|
||||
_islandSystem = EntitySystem.Get<DebugPhysicsIslandSystem>();
|
||||
_eyeManager = IoCManager.Resolve<IEyeManager>();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Client.Graphics;
|
||||
|
||||
|
||||
namespace Robust.Client.Placement
|
||||
{
|
||||
public partial class PlacementManager
|
||||
@@ -7,10 +9,9 @@ namespace Robust.Client.Placement
|
||||
internal class PlacementOverlay : Overlay
|
||||
{
|
||||
private readonly PlacementManager _manager;
|
||||
public override bool AlwaysDirty => true;
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
public PlacementOverlay(PlacementManager manager) : base("placement")
|
||||
public PlacementOverlay(PlacementManager manager)
|
||||
{
|
||||
_manager = manager;
|
||||
ZIndex = 100;
|
||||
|
||||
@@ -2,17 +2,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
#if DEBUG
|
||||
using NJsonSchema;
|
||||
#endif
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
@@ -24,6 +19,14 @@ namespace Robust.Client.ResourceManagement
|
||||
/// </summary>
|
||||
public sealed class RSIResource : BaseResource
|
||||
{
|
||||
private static readonly float[] OneArray = {1};
|
||||
|
||||
private static readonly JsonSerializerOptions SerializerOptions =
|
||||
new JsonSerializerOptions(JsonSerializerDefaults.Web)
|
||||
{
|
||||
AllowTrailingCommas = true
|
||||
};
|
||||
|
||||
public RSI RSI { get; private set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
@@ -38,64 +41,36 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
public override void Load(IResourceCache cache, ResourcePath path)
|
||||
{
|
||||
var manifestPath = path / "meta.json";
|
||||
string manifestContents;
|
||||
var metadata = LoadRsiMetadata(cache, path);
|
||||
|
||||
using (var manifestFile = cache.ContentFileRead(manifestPath))
|
||||
using (var reader = new StreamReader(manifestFile))
|
||||
{
|
||||
manifestContents = reader.ReadToEnd();
|
||||
}
|
||||
var stateCount = metadata.States.Length;
|
||||
var toAtlas = new StateReg[stateCount];
|
||||
|
||||
#if DEBUG
|
||||
if (RSISchema != null)
|
||||
{
|
||||
var errors = RSISchema.Validate(manifestContents);
|
||||
if (errors.Count != 0)
|
||||
{
|
||||
Logger.Error($"Unable to load RSI from '{path}', {errors.Count} errors:");
|
||||
|
||||
foreach (var error in errors)
|
||||
{
|
||||
Logger.Error("{0}", error.ToString());
|
||||
}
|
||||
|
||||
throw new RSILoadException($"{errors.Count} errors while loading RSI. See console.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ok schema validated just fine.
|
||||
var manifestJson = JObject.Parse(manifestContents);
|
||||
|
||||
var toAtlas = new List<(Image<Rgba32> src, Texture[][] output, int[][] indices, Vector2i[][] offsets, int totalFrameCount)>();
|
||||
|
||||
var metaData = ParseMetaData(manifestJson);
|
||||
var frameSize = metaData.Size;
|
||||
var frameSize = metadata.Size;
|
||||
var rsi = new RSI(frameSize, path);
|
||||
|
||||
var callbackOffsets = new Dictionary<RSI.StateId, Vector2i[][]>();
|
||||
var callbackOffsets = new Dictionary<RSI.StateId, Vector2i[][]>(stateCount);
|
||||
|
||||
// Do every state.
|
||||
foreach (var stateObject in metaData.States)
|
||||
for (var index = 0; index < metadata.States.Length; index++)
|
||||
{
|
||||
ref var reg = ref toAtlas[index];
|
||||
|
||||
var stateObject = metadata.States[index];
|
||||
// Load image from disk.
|
||||
var texPath = path / (stateObject.StateId + ".png");
|
||||
var stream = cache.ContentFileRead(texPath);
|
||||
Image<Rgba32> image;
|
||||
using (stream)
|
||||
using (var stream = cache.ContentFileRead(texPath))
|
||||
{
|
||||
image = Image.Load<Rgba32>(stream);
|
||||
reg.Src = Image.Load<Rgba32>(stream);
|
||||
}
|
||||
var sheetSize = new Vector2i(image.Width, image.Height);
|
||||
|
||||
if (sheetSize.X % frameSize.X != 0 || sheetSize.Y % frameSize.Y != 0)
|
||||
if (reg.Src.Width % frameSize.X != 0 || reg.Src.Height % frameSize.Y != 0)
|
||||
{
|
||||
throw new RSILoadException("State image size is not a multiple of the icon size.");
|
||||
}
|
||||
|
||||
// Load all frames into a list so we can operate on it more sanely.
|
||||
var frameCount = stateObject.Delays.Sum(delayList => delayList.Length);
|
||||
reg.TotalFrameCount = stateObject.Delays.Sum(delayList => delayList.Length);
|
||||
|
||||
var (foldedDelays, foldedIndices) = FoldDelays(stateObject.Delays);
|
||||
|
||||
@@ -108,15 +83,18 @@ namespace Robust.Client.ResourceManagement
|
||||
callbackOffset[i] = new Vector2i[foldedIndices[0].Length];
|
||||
}
|
||||
|
||||
reg.Output = textures;
|
||||
reg.Indices = foldedIndices;
|
||||
reg.Offsets = callbackOffset;
|
||||
|
||||
var state = new RSI.State(frameSize, stateObject.StateId, stateObject.DirType, foldedDelays, textures);
|
||||
rsi.AddState(state);
|
||||
|
||||
toAtlas.Add((image, textures, foldedIndices, callbackOffset, frameCount));
|
||||
callbackOffsets[stateObject.StateId] = callbackOffset;
|
||||
}
|
||||
|
||||
// Poorly hacked in texture atlas support here.
|
||||
var totalFrameCount = toAtlas.Sum(p => p.totalFrameCount);
|
||||
var totalFrameCount = toAtlas.Sum(p => p.TotalFrameCount);
|
||||
|
||||
// Generate atlas.
|
||||
var dimensionX = (int) MathF.Ceiling(MathF.Sqrt(totalFrameCount));
|
||||
@@ -125,12 +103,13 @@ namespace Robust.Client.ResourceManagement
|
||||
using var sheet = new Image<Rgba32>(dimensionX * frameSize.X, dimensionY * frameSize.Y);
|
||||
|
||||
var sheetIndex = 0;
|
||||
foreach (var (src, _, _, _, frameCount) in toAtlas)
|
||||
for (var index = 0; index < toAtlas.Length; index++)
|
||||
{
|
||||
ref var reg = ref toAtlas[index];
|
||||
// Blit all the frames over.
|
||||
for (var i = 0; i < frameCount; i++)
|
||||
for (var i = 0; i < reg.TotalFrameCount; i++)
|
||||
{
|
||||
var srcWidth = (src.Width / frameSize.X);
|
||||
var srcWidth = (reg.Src.Width / frameSize.X);
|
||||
var srcColumn = i % srcWidth;
|
||||
var srcRow = i / srcWidth;
|
||||
var srcPos = (srcColumn * frameSize.X, srcRow * frameSize.Y);
|
||||
@@ -141,23 +120,24 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
var srcBox = UIBox2i.FromDimensions(srcPos, frameSize);
|
||||
|
||||
src.Blit(srcBox, sheet, sheetPos);
|
||||
reg.Src.Blit(srcBox, sheet, sheetPos);
|
||||
}
|
||||
|
||||
sheetIndex += frameCount;
|
||||
sheetIndex += reg.TotalFrameCount;
|
||||
}
|
||||
|
||||
// Load atlas.
|
||||
var texture = Texture.LoadFromImage(sheet, path.ToString());
|
||||
|
||||
var sheetOffset = 0;
|
||||
foreach (var (_, output, indices, offsets, frameCount) in toAtlas)
|
||||
for (var toAtlasIndex = 0; toAtlasIndex < toAtlas.Length; toAtlasIndex++)
|
||||
{
|
||||
for (var i = 0; i < indices.Length; i++)
|
||||
ref var reg = ref toAtlas[toAtlasIndex];
|
||||
for (var i = 0; i < reg.Indices.Length; i++)
|
||||
{
|
||||
var dirIndices = indices[i];
|
||||
var dirOutput = output[i];
|
||||
var dirOffsets = offsets[i];
|
||||
var dirIndices = reg.Indices[i];
|
||||
var dirOutput = reg.Output[i];
|
||||
var dirOffsets = reg.Offsets[i];
|
||||
|
||||
for (var j = 0; j < dirIndices.Length; j++)
|
||||
{
|
||||
@@ -172,12 +152,13 @@ namespace Robust.Client.ResourceManagement
|
||||
}
|
||||
}
|
||||
|
||||
sheetOffset += frameCount;
|
||||
sheetOffset += reg.TotalFrameCount;
|
||||
}
|
||||
|
||||
foreach (var (image, _, _, _, _) in toAtlas)
|
||||
for (var i = 0; i < toAtlas.Length; i++)
|
||||
{
|
||||
image.Dispose();
|
||||
ref var reg = ref toAtlas[i];
|
||||
reg.Src.Dispose();
|
||||
}
|
||||
|
||||
RSI = rsi;
|
||||
@@ -188,6 +169,90 @@ namespace Robust.Client.ResourceManagement
|
||||
}
|
||||
}
|
||||
|
||||
private static RsiMetadata LoadRsiMetadata(IResourceCache cache, ResourcePath path)
|
||||
{
|
||||
var manifestPath = path / "meta.json";
|
||||
string manifestContents;
|
||||
|
||||
using (var manifestFile = cache.ContentFileRead(manifestPath))
|
||||
using (var reader = new StreamReader(manifestFile))
|
||||
{
|
||||
manifestContents = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
// Ok schema validated just fine.
|
||||
var manifestJson = JsonSerializer.Deserialize<RsiJsonMetadata>(manifestContents, SerializerOptions);
|
||||
|
||||
if (manifestJson == null)
|
||||
throw new RSILoadException("Manifest JSON was null!");
|
||||
|
||||
var size = manifestJson.Size;
|
||||
var states = new StateMetadata[manifestJson.States.Length];
|
||||
|
||||
for (var stateI = 0; stateI < manifestJson.States.Length; stateI++)
|
||||
{
|
||||
var stateObject = manifestJson.States[stateI];
|
||||
var stateName = stateObject.Name;
|
||||
RSI.State.DirectionType directions;
|
||||
int dirValue;
|
||||
|
||||
if (stateObject.Directions is { } dirVal)
|
||||
{
|
||||
dirValue = dirVal;
|
||||
directions = dirVal switch
|
||||
{
|
||||
1 => RSI.State.DirectionType.Dir1,
|
||||
4 => RSI.State.DirectionType.Dir4,
|
||||
8 => RSI.State.DirectionType.Dir8,
|
||||
_ => throw new RSILoadException($"Invalid direction: {dirValue} expected 1, 4 or 8")
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
dirValue = 1;
|
||||
directions = RSI.State.DirectionType.Dir1;
|
||||
}
|
||||
|
||||
// We can ignore selectors and flags for now,
|
||||
// because they're not used yet!
|
||||
|
||||
// Get the lists of delays.
|
||||
float[][] delays;
|
||||
if (stateObject.Delays != null)
|
||||
{
|
||||
delays = stateObject.Delays;
|
||||
|
||||
if (delays.Length != dirValue)
|
||||
{
|
||||
throw new RSILoadException(
|
||||
"DirectionsdirectionFramesList count does not match amount of delays specified.");
|
||||
}
|
||||
|
||||
for (var i = 0; i < delays.Length; i++)
|
||||
{
|
||||
var delayList = delays[i];
|
||||
if (delayList.Length == 0)
|
||||
{
|
||||
delays[i] = OneArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delays = new float[dirValue][];
|
||||
// No delays specified, default to 1 frame per dir.
|
||||
for (var i = 0; i < dirValue; i++)
|
||||
{
|
||||
delays[i] = OneArray;
|
||||
}
|
||||
}
|
||||
|
||||
states[stateI] = new StateMetadata(new RSI.StateId(stateName), directions, delays);
|
||||
}
|
||||
|
||||
return new RsiMetadata(size, states);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Folds a per-directional sets of animation delays
|
||||
/// into an equivalent set of animation delays and indices that works for every direction.
|
||||
@@ -336,109 +401,25 @@ namespace Robust.Client.ResourceManagement
|
||||
return (floatDelays, arrayIndices);
|
||||
}
|
||||
|
||||
internal static RsiMetadata ParseMetaData(JObject manifestJson)
|
||||
private struct StateReg
|
||||
{
|
||||
var size = manifestJson["size"]!.ToObject<Vector2i>();
|
||||
var states = new List<StateMetadata>();
|
||||
|
||||
foreach (var stateObject in manifestJson["states"]!.Cast<JObject>())
|
||||
{
|
||||
var stateName = stateObject["name"]!.ToObject<string>()!;
|
||||
RSI.State.DirectionType directions;
|
||||
int dirValue;
|
||||
|
||||
if (stateObject.TryGetValue("directions", out var dirJToken))
|
||||
{
|
||||
dirValue= dirJToken.ToObject<int>();
|
||||
directions = dirValue switch
|
||||
{
|
||||
1 => RSI.State.DirectionType.Dir1,
|
||||
4 => RSI.State.DirectionType.Dir4,
|
||||
8 => RSI.State.DirectionType.Dir8,
|
||||
_ => throw new RSILoadException($"Invalid direction: {dirValue} expected 1, 4 or 8")
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
dirValue = 1;
|
||||
directions = RSI.State.DirectionType.Dir1;
|
||||
}
|
||||
|
||||
// We can ignore selectors and flags for now,
|
||||
// because they're not used yet!
|
||||
|
||||
// Get the lists of delays.
|
||||
float[][] delays;
|
||||
if (stateObject.TryGetValue("delays", out var delayToken))
|
||||
{
|
||||
delays = delayToken.ToObject<float[][]>()!;
|
||||
|
||||
if (delays.Length != dirValue)
|
||||
{
|
||||
throw new RSILoadException(
|
||||
"DirectionsdirectionFramesList count does not match amount of delays specified.");
|
||||
}
|
||||
|
||||
for (var i = 0; i < delays.Length; i++)
|
||||
{
|
||||
var delayList = delays[i];
|
||||
if (delayList.Length == 0)
|
||||
{
|
||||
delays[i] = new float[] {1};
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delays = new float[dirValue][];
|
||||
// No delays specified, default to 1 frame per dir.
|
||||
for (var i = 0; i < dirValue; i++)
|
||||
{
|
||||
delays[i] = new float[] {1};
|
||||
}
|
||||
}
|
||||
|
||||
states.Add(new StateMetadata(new RSI.StateId(stateName), directions, delays));
|
||||
}
|
||||
|
||||
return new RsiMetadata(size, states);
|
||||
public Image<Rgba32> Src;
|
||||
public Texture[][] Output;
|
||||
public int[][] Indices;
|
||||
public Vector2i[][] Offsets;
|
||||
public int TotalFrameCount;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
private static readonly JsonSchema? RSISchema = GetSchema();
|
||||
|
||||
private static JsonSchema? GetSchema()
|
||||
{
|
||||
try
|
||||
{
|
||||
string schema;
|
||||
using (var schemaStream = Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceStream("Robust.Client.Graphics.RSI.RSISchema.json")!)
|
||||
using (var schemaReader = new StreamReader(schemaStream))
|
||||
{
|
||||
schema = schemaReader.ReadToEnd();
|
||||
}
|
||||
|
||||
return JsonSchema.FromJsonAsync(schema).Result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.Console.WriteLine("Failed to load RSI JSON Schema!\n{0}", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal sealed class RsiMetadata
|
||||
{
|
||||
public RsiMetadata(Vector2i size, List<StateMetadata> states)
|
||||
public RsiMetadata(Vector2i size, StateMetadata[] states)
|
||||
{
|
||||
Size = size;
|
||||
States = states;
|
||||
}
|
||||
|
||||
public Vector2i Size { get; }
|
||||
public List<StateMetadata> States { get; }
|
||||
public StateMetadata[] States { get; }
|
||||
}
|
||||
|
||||
internal sealed class StateMetadata
|
||||
@@ -466,6 +447,17 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
public float[][] Delays { get; }
|
||||
}
|
||||
|
||||
// To be directly deserialized.
|
||||
[UsedImplicitly]
|
||||
private sealed record RsiJsonMetadata(Vector2i Size, StateJsonMetadata[] States)
|
||||
{
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
private sealed record StateJsonMetadata(string Name, int? Directions, float[][]? Delays)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.3.0" PrivateAssets="All" />
|
||||
<PackageReference Include="nfluidsynth" Version="0.3.1" />
|
||||
<PackageReference Include="NJsonSchema" Version="10.3.8" />
|
||||
<PackageReference Include="NVorbis" Version="0.10.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.3" />
|
||||
@@ -39,9 +38,6 @@
|
||||
<ProjectReference Include="..\Robust.Shared\Robust.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Graphics\RSI\RSISchema.json" Condition="'$(Configuration)' == 'Debug'">
|
||||
<LogicalName>Robust.Client.Graphics.RSI.RSISchema.json</LogicalName>
|
||||
</EmbeddedResource>
|
||||
|
||||
<EmbeddedResource Include="Graphics\Clyde\Shaders\*" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
@@ -67,6 +67,7 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
|
||||
Title = Loc.GetString("Entity Spawn Panel");
|
||||
|
||||
|
||||
SetSize = (250, 300);
|
||||
MinSize = (250, 200);
|
||||
|
||||
|
||||
@@ -42,19 +42,20 @@ namespace Robust.Client.Utility
|
||||
{
|
||||
var dstSpan = destination.GetPixelSpan();
|
||||
var dstWidth = destination.Width;
|
||||
var srcHeight = sourceRect.Height;
|
||||
var srcWidth = sourceRect.Width;
|
||||
|
||||
var (ox, oy) = destinationOffset;
|
||||
|
||||
for (var y = 0; y < sourceRect.Height; y++)
|
||||
for (var y = 0; y < srcHeight; y++)
|
||||
{
|
||||
var sourceRowOffset = sourceWidth * (y + sourceRect.Top) + sourceRect.Left;
|
||||
var destRowOffset = dstWidth * (y + oy) + ox;
|
||||
|
||||
for (var x = 0; x < sourceRect.Width; x++)
|
||||
{
|
||||
var pixel = source[x + sourceRowOffset];
|
||||
dstSpan[x + destRowOffset] = pixel;
|
||||
}
|
||||
var srcRow = source[sourceRowOffset..(sourceRowOffset + srcWidth)];
|
||||
var dstRow = dstSpan[destRowOffset..(destRowOffset + srcWidth)];
|
||||
|
||||
srcRow.CopyTo(dstRow);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
@@ -41,6 +41,40 @@ namespace Robust.Client.Utility
|
||||
return specifier.RsiStateLike().Default;
|
||||
}
|
||||
|
||||
public static float[] FrameDelays(this SpriteSpecifier specifier) {
|
||||
var resc = IoCManager.Resolve<IResourceCache>();
|
||||
switch (specifier) {
|
||||
case SpriteSpecifier.Rsi rsi:
|
||||
if (resc.TryGetResource<RSIResource>(SpriteComponent.TextureRoot / rsi.RsiPath, out var theRsi)) {
|
||||
if (theRsi.RSI.TryGetState(rsi.RsiState, out var state)) {
|
||||
return state.Delays;
|
||||
}
|
||||
}
|
||||
Logger.Error("Failed to load RSI {0}", rsi.RsiPath);
|
||||
return new float[0];
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static Texture[] FrameArr(this SpriteSpecifier specifier) {
|
||||
var resc = IoCManager.Resolve<IResourceCache>();
|
||||
switch (specifier) {
|
||||
case SpriteSpecifier.Rsi rsi:
|
||||
if (resc.TryGetResource<RSIResource>(SpriteComponent.TextureRoot / rsi.RsiPath, out var theRsi)) {
|
||||
if (theRsi.RSI.TryGetState(rsi.RsiState, out var state)) {
|
||||
return state.Icons[0];
|
||||
}
|
||||
}
|
||||
Logger.Error("Failed to load RSI {0}", rsi.RsiPath);
|
||||
return new Texture[0];
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static IDirectionalTextureProvider DirFrame0(this SpriteSpecifier specifier)
|
||||
{
|
||||
return specifier.RsiStateLike();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
@@ -16,12 +17,12 @@ namespace Robust.Shared.Maths
|
||||
/// <summary>
|
||||
/// The X component of the Vector2i.
|
||||
/// </summary>
|
||||
public int X;
|
||||
[JsonInclude] public int X;
|
||||
|
||||
/// <summary>
|
||||
/// The Y component of the Vector2i.
|
||||
/// </summary>
|
||||
public int Y;
|
||||
[JsonInclude] public int Y;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a vector from its coordinates.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Robust.Shared.Maths
|
||||
@@ -12,12 +13,12 @@ namespace Robust.Shared.Maths
|
||||
/// <summary>
|
||||
/// The X component of the Vector2i.
|
||||
/// </summary>
|
||||
public uint X;
|
||||
[JsonInclude] public uint X;
|
||||
|
||||
/// <summary>
|
||||
/// The Y component of the Vector2i.
|
||||
/// </summary>
|
||||
public uint Y;
|
||||
[JsonInclude] public uint Y;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a vector from its coordinates.
|
||||
|
||||
@@ -372,8 +372,9 @@ namespace Robust.Shared
|
||||
|
||||
// - Maximums
|
||||
// Squared
|
||||
// 35 m/s, AKA half a tile per frame allowed. Divide this by frametime to get units per second.
|
||||
public static readonly CVarDef<float> MaxLinVelocity =
|
||||
CVarDef.Create("physics.maxlinvelocity", 4.0f);
|
||||
CVarDef.Create("physics.maxlinvelocity", 0.56f);
|
||||
|
||||
// Squared
|
||||
public static readonly CVarDef<float> MaxAngVelocity =
|
||||
|
||||
47
Robust.Shared/Enums/OverlaySpaces.cs
Normal file
47
Robust.Shared/Enums/OverlaySpaces.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Robust.Shared.Enums {
|
||||
/// <summary>
|
||||
/// Determines in which canvas layers an overlay gets drawn.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum OverlaySpace {
|
||||
/// <summary>
|
||||
/// Used for matching bit flags.
|
||||
/// </summary>
|
||||
None = 0b000000,
|
||||
|
||||
/// <summary>
|
||||
/// This overlay will be drawn in screen coordinates in the UI space above the world.
|
||||
/// </summary>
|
||||
ScreenSpace = 0b000001,
|
||||
|
||||
/// <summary>
|
||||
/// This overlay will be drawn directly above normal worldspace, but a stencil equivalent to the FOV will be applied.
|
||||
/// You likely want to use <see cref="WorldSpaceBelowFOV"/>. This space should only be used if you fully understand why you need this.
|
||||
/// </summary>
|
||||
WorldSpaceFOVStencil = 0b000010,
|
||||
|
||||
/// <summary>
|
||||
/// This overlay will be drawn above entities, lighting, and FOV.
|
||||
/// </summary>
|
||||
WorldSpace = 0b000100,
|
||||
|
||||
/// <summary>
|
||||
/// This overlay will be drawn beneath FOV; above lighting and entities.
|
||||
/// </summary>
|
||||
WorldSpaceBelowFOV = 0b001000,
|
||||
|
||||
/// <summary>
|
||||
/// This overlay will be drawn beneath entities, lighting, and FOV; above grids.
|
||||
/// </summary>
|
||||
WorldSpaceBelowEntities = 0b010000,
|
||||
|
||||
/// <summary>
|
||||
/// This overlay will be drawn in screen coordinates behind the world.
|
||||
/// </summary>
|
||||
ScreenSpaceBelowWorld = 0b100000,
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,7 @@ namespace Robust.Shared.GameObjects
|
||||
if (_bodyType == value)
|
||||
return;
|
||||
|
||||
var oldAnchored = _bodyType == BodyType.Static;
|
||||
_bodyType = value;
|
||||
|
||||
ResetMassData();
|
||||
@@ -120,8 +121,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
RegenerateContacts();
|
||||
|
||||
var oldAnchored = _bodyType == BodyType.Static;
|
||||
var anchored = _bodyType == BodyType.Static;
|
||||
var anchored = value == BodyType.Static;
|
||||
|
||||
if (oldAnchored != anchored)
|
||||
{
|
||||
|
||||
@@ -241,7 +241,7 @@ namespace Robust.Shared.GameObjects
|
||||
{
|
||||
if (!_parent.IsValid())
|
||||
{
|
||||
DebugTools.Assert("Tried to move root node.");
|
||||
DebugTools.Assert("Parent is invalid while attempting to set WorldPosition - did you try to move root node?");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -531,11 +531,13 @@ namespace Robust.Shared.Physics.Dynamics
|
||||
var body = _stack[--stackCount];
|
||||
_island.Add(body);
|
||||
_islandSet.Add(body);
|
||||
body.Awake = true;
|
||||
|
||||
// Static bodies don't propagate islands
|
||||
if (body.BodyType == BodyType.Static) continue;
|
||||
|
||||
// As static bodies can never be awake (unlike Farseer) we'll set this after the check.
|
||||
body.Awake = true;
|
||||
|
||||
for (var contactEdge = body.ContactEdges; contactEdge != null; contactEdge = contactEdge.Next)
|
||||
{
|
||||
var contact = contactEdge.Contact!;
|
||||
|
||||
Reference in New Issue
Block a user