Added rotation logic to the renderer to enable the use of Interpolated Facings.

This commit is contained in:
AspectInteractive2
2022-06-07 22:11:51 +02:00
committed by Matthias Mailänder
parent e060d6eb05
commit a1a50d6c98
11 changed files with 223 additions and 42 deletions

View File

@@ -108,6 +108,7 @@ namespace OpenRA.Mods.Common.Graphics
int ISpriteSequence.Length => throw exception;
int ISpriteSequence.Stride => throw exception;
int ISpriteSequence.Facings => throw exception;
int ISpriteSequence.InterpolatedFacings => throw exception;
int ISpriteSequence.Tick => throw exception;
int ISpriteSequence.ZOffset => throw exception;
int ISpriteSequence.ShadowStart => throw exception;
@@ -118,6 +119,7 @@ namespace OpenRA.Mods.Common.Graphics
float ISpriteSequence.Scale => throw exception;
Sprite ISpriteSequence.GetSprite(int frame) { throw exception; }
Sprite ISpriteSequence.GetSprite(int frame, WAngle facing) { throw exception; }
(Sprite, WAngle) ISpriteSequence.GetSpriteWithRotation(int frame, WAngle facing) { throw exception; }
Sprite ISpriteSequence.GetShadow(int frame, WAngle facing) { throw exception; }
float ISpriteSequence.GetAlpha(int frame) { throw exception; }
}
@@ -167,6 +169,11 @@ namespace OpenRA.Mods.Common.Graphics
int ISpriteSequence.Facings => facings;
protected int facings;
[Desc("The amount of directions the unit faces. Use negative values to rotate counter-clockwise.")]
static readonly SpriteSequenceField<int> InterpolatedFacings = new SpriteSequenceField<int>(nameof(InterpolatedFacings), 1);
int ISpriteSequence.InterpolatedFacings => interpolatedFacings;
protected int interpolatedFacings;
[Desc("Time (in milliseconds at default game speed) to wait until playing the next frame in the animation.")]
static readonly SpriteSequenceField<int> Tick = new SpriteSequenceField<int>(nameof(Tick), 40);
int ISpriteSequence.Tick => tick;
@@ -305,6 +312,11 @@ namespace OpenRA.Mods.Common.Graphics
var zRamp = LoadField(d, ZRamp);
facings = LoadField(d, Facings);
interpolatedFacings = LoadField(d, nameof(InterpolatedFacings), -1);
if (interpolatedFacings != -1 && (interpolatedFacings <= 1 || interpolatedFacings <= Math.Abs(facings) || interpolatedFacings > 1024
|| !Exts.IsPowerOf2(interpolatedFacings)))
throw new YamlException($"InterpolatedFacings must be greater than Facings, within the range of 2 to 1024, and a power of 2.");
if (facings < 0)
{
reverseFacings = true;
@@ -531,6 +543,17 @@ namespace OpenRA.Mods.Common.Graphics
return GetSprite(start, frame, facing);
}
public (Sprite, WAngle) GetSpriteWithRotation(int frame, WAngle facing)
{
var rotation = WAngle.Zero;
// Note: Error checking is not done here as it is done on load
if (interpolatedFacings != -1)
rotation = Util.GetInterpolatedFacing(facing, Math.Abs(facings), interpolatedFacings);
return (GetSprite(start, frame, facing), rotation);
}
public Sprite GetShadow(int frame, WAngle facing)
{
return shadowStart >= 0 ? GetSprite(shadowStart, frame, facing) : null;

View File

@@ -29,7 +29,8 @@ namespace OpenRA.Mods.Common.Traits
throw new InvalidOperationException("Actor " + ai.Name + " is missing sequence to quantize facings from.");
var rsi = ai.TraitInfo<RenderSpritesInfo>();
return sequenceProvider.GetSequence(rsi.GetImage(ai, race), Sequence).Facings;
var seq = sequenceProvider.GetSequence(rsi.GetImage(ai, race), Sequence);
return seq.InterpolatedFacings == -1 ? seq.Facings : seq.InterpolatedFacings;
}
public override object Create(ActorInitializer init) { return new QuantizeFacingsFromSequence(this); }

View File

@@ -67,11 +67,28 @@ namespace OpenRA.Mods.Common
/// </summary>
public static int IndexFacing(WAngle facing, int numFrames)
{
// 1024 here is the max angle, so we divide the max angle by the total number of facings (numFrames)
var step = 1024 / numFrames;
var a = (facing.Angle + step / 2) & 1023;
return a / step;
}
/// <summary>
/// Returns the remainder angle after rounding to the nearest whole step / facing
/// </summary>
public static WAngle AngleDiffToStep(WAngle facing, int numFrames)
{
var step = 1024 / numFrames;
var a = (facing.Angle + step / 2) & 1023;
return new WAngle(a % step - step / 2);
}
public static WAngle GetInterpolatedFacing(WAngle facing, int facings, int interpolatedFacings)
{
var step = 1024 / interpolatedFacings;
return new WAngle(AngleDiffToStep(facing, facings).Angle / step * step);
}
/// <summary>Rounds the given facing value to the nearest quantized step.</summary>
public static WAngle QuantizeFacing(WAngle facing, int steps)
{