Skip to content

Commit

Permalink
Added rotation logic to the renderer to enable the use of Interpolate…
Browse files Browse the repository at this point in the history
…d Facings.
  • Loading branch information
AspectInteractive2 committed May 25, 2022
1 parent 3f328a1 commit e45f209
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 44 deletions.
14 changes: 9 additions & 5 deletions OpenRA.Game/Graphics/Animation.cs
Expand Up @@ -50,37 +50,41 @@ public Animation(World world, string name, Func<WAngle> facingFunc, Func<bool> p
}

public int CurrentFrame => backwards ? CurrentSequence.Length - frame - 1 : frame;

public Sprite Image => CurrentSequence.GetSprite(CurrentFrame, facingFunc());

public IRenderable[] Render(WPos pos, in WVec offset, int zOffset, PaletteReference palette)
{
var tintModifiers = CurrentSequence.IgnoreWorldTint ? TintModifiers.IgnoreWorldTint : TintModifiers.None;
var alpha = CurrentSequence.GetAlpha(CurrentFrame);
var imageRenderable = new SpriteRenderable(Image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, CurrentSequence.Scale, alpha, float3.Ones, tintModifiers, IsDecoration);
var (image, rotation) = CurrentSequence.GetSpriteWithRotation(CurrentFrame, facingFunc());
var imageRenderable = new SpriteRenderable(image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, CurrentSequence.Scale, alpha, float3.Ones, tintModifiers, IsDecoration,
rotation);

if (CurrentSequence.ShadowStart >= 0)
{
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
var shadowRenderable = new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, CurrentSequence.Scale, 1f, float3.Ones, tintModifiers, true);
var shadowRenderable = new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, CurrentSequence.Scale, 1f, float3.Ones, tintModifiers,
true, rotation);
return new IRenderable[] { shadowRenderable, imageRenderable };
}

return new IRenderable[] { imageRenderable };
}

public IRenderable[] RenderUI(WorldRenderer wr, int2 pos, in WVec offset, int zOffset, PaletteReference palette, float scale = 1f)
public IRenderable[] RenderUI(WorldRenderer wr, int2 pos, in WVec offset, int zOffset, PaletteReference palette, float scale = 1f, float rotation = 0f)
{
scale *= CurrentSequence.Scale;
var screenOffset = (scale * wr.ScreenVectorComponents(offset)).XY.ToInt2();
var imagePos = pos + screenOffset - new int2((int)(scale * Image.Size.X / 2), (int)(scale * Image.Size.Y / 2));
var alpha = CurrentSequence.GetAlpha(CurrentFrame);
var imageRenderable = new UISpriteRenderable(Image, WPos.Zero + offset, imagePos, CurrentSequence.ZOffset + zOffset, palette, scale, alpha);
var imageRenderable = new UISpriteRenderable(Image, WPos.Zero + offset, imagePos, CurrentSequence.ZOffset + zOffset, palette, scale, alpha, rotation);

if (CurrentSequence.ShadowStart >= 0)
{
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
var shadowPos = pos - new int2((int)(scale * shadow.Size.X / 2), (int)(scale * shadow.Size.Y / 2));
var shadowRenderable = new UISpriteRenderable(shadow, WPos.Zero + offset, shadowPos, CurrentSequence.ShadowZOffset + zOffset, palette, scale);
var shadowRenderable = new UISpriteRenderable(shadow, WPos.Zero + offset, shadowPos, CurrentSequence.ShadowZOffset + zOffset, palette, scale, 1f, rotation);
return new IRenderable[] { shadowRenderable, imageRenderable };
}

Expand Down
12 changes: 6 additions & 6 deletions OpenRA.Game/Graphics/RgbaSpriteRenderer.cs
Expand Up @@ -22,28 +22,28 @@ public RgbaSpriteRenderer(SpriteRenderer parent)
this.parent = parent;
}

public void DrawSprite(Sprite s, in float3 location, in float3 scale)
public void DrawSprite(Sprite s, in float3 location, in float3 scale, float rotation = 0f)
{
if (s.Channel != TextureChannel.RGBA)
throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite.");

parent.DrawSprite(s, 0, location, scale);
parent.DrawSprite(s, 0, location, scale, rotation);
}

public void DrawSprite(Sprite s, in float3 location, float scale = 1f)
public void DrawSprite(Sprite s, in float3 location, float scale = 1f, float rotation = 0f)
{
if (s.Channel != TextureChannel.RGBA)
throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite.");

parent.DrawSprite(s, 0, location, scale);
parent.DrawSprite(s, 0, location, scale, rotation);
}

public void DrawSprite(Sprite s, in float3 location, float scale, in float3 tint, float alpha)
public void DrawSprite(Sprite s, in float3 location, float scale, in float3 tint, float alpha, float rotation = 0f)
{
if (s.Channel != TextureChannel.RGBA)
throw new InvalidOperationException("DrawRGBASprite requires a RGBA sprite.");

parent.DrawSprite(s, 0, location, scale, tint, alpha);
parent.DrawSprite(s, 0, location, scale, tint, alpha, rotation);
}

public void DrawSprite(Sprite s, in float3 a, in float3 b, in float3 c, in float3 d, in float3 tint, float alpha)
Expand Down
2 changes: 2 additions & 0 deletions OpenRA.Game/Graphics/SequenceProvider.cs
Expand Up @@ -26,6 +26,7 @@ public interface ISpriteSequence
int Length { get; }
int Stride { get; }
int Facings { get; }
int InterpolatedFacings { get; }
int Tick { get; }
int ZOffset { get; }
int ShadowStart { get; }
Expand All @@ -37,6 +38,7 @@ public interface ISpriteSequence

Sprite GetSprite(int frame);
Sprite GetSprite(int frame, WAngle facing);
(Sprite, WAngle) GetSpriteWithRotation(int frame, WAngle facing);
Sprite GetShadow(int frame, WAngle facing);
float GetAlpha(int frame);
}
Expand Down
45 changes: 35 additions & 10 deletions OpenRA.Game/Graphics/SpriteRenderable.cs
Expand Up @@ -25,19 +25,22 @@ public class SpriteRenderable : IPalettedRenderable, IModifyableRenderable, IFin
readonly int zOffset;
readonly PaletteReference palette;
readonly float scale;
readonly WAngle rotation = WAngle.Zero;
readonly float3 tint;
readonly TintModifiers tintModifiers;
readonly float alpha;
readonly bool isDecoration;

public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, float alpha, float3 tint, TintModifiers tintModifiers, bool isDecoration)
public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, float alpha,
float3 tint, TintModifiers tintModifiers, bool isDecoration, WAngle rotation)
{
this.sprite = sprite;
this.pos = pos;
this.offset = offset;
this.zOffset = zOffset;
this.palette = palette;
this.scale = scale;
this.rotation = rotation;
this.tint = tint;
this.isDecoration = isDecoration;
this.tintModifiers = tintModifiers;
Expand All @@ -50,6 +53,10 @@ public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, Palet
this.palette = null;
}

public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale, float alpha,
float3 tint, TintModifiers tintModifiers, bool isDecoration)
: this(sprite, pos, offset, zOffset, palette, scale, alpha, tint, tintModifiers, isDecoration, WAngle.Zero) { }

public WPos Pos => pos + offset;
public WVec Offset => offset;
public PaletteReference Palette => palette;
Expand All @@ -60,19 +67,34 @@ public SpriteRenderable(Sprite sprite, WPos pos, WVec offset, int zOffset, Palet
public float3 Tint => tint;
public TintModifiers TintModifiers => tintModifiers;

public IPalettedRenderable WithPalette(PaletteReference newPalette) { return new SpriteRenderable(sprite, pos, offset, zOffset, newPalette, scale, alpha, tint, tintModifiers, isDecoration); }
public IRenderable WithZOffset(int newOffset) { return new SpriteRenderable(sprite, pos, offset, newOffset, palette, scale, alpha, tint, tintModifiers, isDecoration); }
public IRenderable OffsetBy(in WVec vec) { return new SpriteRenderable(sprite, pos + vec, offset, zOffset, palette, scale, alpha, tint, tintModifiers, isDecoration); }
public IRenderable AsDecoration() { return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, alpha, tint, tintModifiers, true); }
public IPalettedRenderable WithPalette(PaletteReference newPalette)
{
return new SpriteRenderable(sprite, pos, offset, zOffset, newPalette, scale, alpha, tint, tintModifiers, isDecoration, rotation);
}

public IRenderable WithZOffset(int newOffset)
{
return new SpriteRenderable(sprite, pos, offset, newOffset, palette, scale, alpha, tint, tintModifiers, isDecoration, rotation);
}

public IRenderable OffsetBy(in WVec vec)
{
return new SpriteRenderable(sprite, pos + vec, offset, zOffset, palette, scale, alpha, tint, tintModifiers, isDecoration, rotation);
}

public IRenderable AsDecoration()
{
return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, alpha, tint, tintModifiers, true, rotation);
}

public IModifyableRenderable WithAlpha(float newAlpha)
{
return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, newAlpha, tint, tintModifiers, isDecoration);
return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, newAlpha, tint, tintModifiers, isDecoration, rotation);
}

public IModifyableRenderable WithTint(in float3 newTint, TintModifiers newTintModifiers)
{
return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, alpha, newTint, newTintModifiers, isDecoration);
return new SpriteRenderable(sprite, pos, offset, zOffset, palette, scale, alpha, newTint, newTintModifiers, isDecoration, rotation);
}

float3 ScreenPosition(WorldRenderer wr)
Expand All @@ -94,21 +116,24 @@ public void Render(WorldRenderer wr)
if ((tintModifiers & TintModifiers.ReplaceColor) != 0)
a *= -1;

wsr.DrawSprite(sprite, palette, ScreenPosition(wr), scale, t, a);
wsr.DrawSprite(sprite, palette, ScreenPosition(wr), scale, t, a, rotation.RendererRadians());
}

public void RenderDebugGeometry(WorldRenderer wr)
{
var pos = ScreenPosition(wr) + sprite.Offset;
var tl = wr.Viewport.WorldToViewPx(pos);
var br = wr.Viewport.WorldToViewPx(pos + sprite.Size);
Game.Renderer.RgbaColorRenderer.DrawRect(tl, br, 1, Color.Red);
if (rotation == WAngle.Zero)
Game.Renderer.RgbaColorRenderer.DrawRect(tl, br, 1, Color.Red);
else
Game.Renderer.RgbaColorRenderer.DrawPolygon(Util.RotateQuad(tl, br - tl, rotation.RendererRadians()), 1, Color.Red);
}

public Rectangle ScreenBounds(WorldRenderer wr)
{
var screenOffset = ScreenPosition(wr) + sprite.Offset;
return new Rectangle((int)screenOffset.X, (int)screenOffset.Y, (int)sprite.Size.X, (int)sprite.Size.Y);
return Util.BoundingRectangle(screenOffset, sprite.Size, rotation.RendererRadians());
}
}
}
25 changes: 15 additions & 10 deletions OpenRA.Game/Graphics/SpriteRenderer.cs
Expand Up @@ -126,35 +126,40 @@ float ResolveTextureIndex(Sprite s, PaletteReference pal)
return pal.TextureIndex;
}

internal void DrawSprite(Sprite s, float paletteTextureIndex, in float3 location, in float3 scale)
internal void DrawSprite(Sprite s, float paletteTextureIndex, in float3 location, in float3 scale, float rotation = 0f)
{
var samplers = SetRenderStateForSprite(s);
Util.FastCreateQuad(vertices, location + scale * s.Offset, s, samplers, paletteTextureIndex, nv, scale * s.Size, float3.Ones, 1f);
Util.FastCreateQuad(vertices, location + scale * s.Offset, s, samplers, paletteTextureIndex, nv, scale * s.Size, float3.Ones,
1f, rotation);
nv += 6;
}

internal void DrawSprite(Sprite s, float paletteTextureIndex, in float3 location, float scale)
internal void DrawSprite(Sprite s, float paletteTextureIndex, in float3 location, float scale, float rotation = 0f)
{
var samplers = SetRenderStateForSprite(s);
Util.FastCreateQuad(vertices, location + scale * s.Offset, s, samplers, paletteTextureIndex, nv, scale * s.Size, float3.Ones, 1f);
Util.FastCreateQuad(vertices, location + scale * s.Offset, s, samplers, paletteTextureIndex, nv, scale * s.Size, float3.Ones,
1f, rotation);
nv += 6;
}

public void DrawSprite(Sprite s, PaletteReference pal, in float3 location, float scale = 1f)
public void DrawSprite(Sprite s, PaletteReference pal, in float3 location, float scale = 1f, float rotation = 0f)
{
DrawSprite(s, ResolveTextureIndex(s, pal), location, scale);
DrawSprite(s, ResolveTextureIndex(s, pal), location, scale, rotation);
}

internal void DrawSprite(Sprite s, float paletteTextureIndex, in float3 location, float scale, in float3 tint, float alpha)
internal void DrawSprite(Sprite s, float paletteTextureIndex, in float3 location, float scale, in float3 tint, float alpha,
float rotation = 0f)
{
var samplers = SetRenderStateForSprite(s);
Util.FastCreateQuad(vertices, location + scale * s.Offset, s, samplers, paletteTextureIndex, nv, scale * s.Size, tint, alpha);
Util.FastCreateQuad(vertices, location + scale * s.Offset, s, samplers, paletteTextureIndex, nv, scale * s.Size, tint, alpha,
rotation);
nv += 6;
}

public void DrawSprite(Sprite s, PaletteReference pal, in float3 location, float scale, in float3 tint, float alpha)
public void DrawSprite(Sprite s, PaletteReference pal, in float3 location, float scale, in float3 tint, float alpha,
float rotation = 0f)
{
DrawSprite(s, ResolveTextureIndex(s, pal), location, scale, tint, alpha);
DrawSprite(s, ResolveTextureIndex(s, pal), location, scale, tint, alpha, rotation);
}

internal void DrawSprite(Sprite s, float paletteTextureIndex, in float3 a, in float3 b, in float3 c, in float3 d, in float3 tint, float alpha)
Expand Down
15 changes: 10 additions & 5 deletions OpenRA.Game/Graphics/UISpriteRenderable.cs
Expand Up @@ -22,8 +22,9 @@ public class UISpriteRenderable : IRenderable, IPalettedRenderable, IFinalizedRe
readonly PaletteReference palette;
readonly float scale;
readonly float alpha;
readonly float rotation = 0f;

public UISpriteRenderable(Sprite sprite, WPos effectiveWorldPos, int2 screenPos, int zOffset, PaletteReference palette, float scale = 1f, float alpha = 1f)
public UISpriteRenderable(Sprite sprite, WPos effectiveWorldPos, int2 screenPos, int zOffset, PaletteReference palette, float scale = 1f, float alpha = 1f, float rotation = 0f)
{
this.sprite = sprite;
this.effectiveWorldPos = effectiveWorldPos;
Expand All @@ -32,6 +33,7 @@ public UISpriteRenderable(Sprite sprite, WPos effectiveWorldPos, int2 screenPos,
this.palette = palette;
this.scale = scale;
this.alpha = alpha;
this.rotation = rotation;

// PERF: Remove useless palette assignments for RGBA sprites
// HACK: This is working around the fact that palettes are defined on traits rather than sequences
Expand All @@ -48,27 +50,30 @@ public UISpriteRenderable(Sprite sprite, WPos effectiveWorldPos, int2 screenPos,
public PaletteReference Palette => palette;
public int ZOffset => zOffset;

public IPalettedRenderable WithPalette(PaletteReference newPalette) { return new UISpriteRenderable(sprite, effectiveWorldPos, screenPos, zOffset, newPalette, scale, alpha); }
public IPalettedRenderable WithPalette(PaletteReference newPalette) { return new UISpriteRenderable(sprite, effectiveWorldPos, screenPos, zOffset, newPalette, scale, alpha, rotation); }
public IRenderable WithZOffset(int newOffset) { return this; }
public IRenderable OffsetBy(in WVec vec) { return this; }
public IRenderable AsDecoration() { return this; }

public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; }
public void Render(WorldRenderer wr)
{
Game.Renderer.SpriteRenderer.DrawSprite(sprite, palette, screenPos, scale, float3.Ones, alpha);
Game.Renderer.SpriteRenderer.DrawSprite(sprite, palette, screenPos, scale, float3.Ones, alpha, rotation);
}

public void RenderDebugGeometry(WorldRenderer wr)
{
var offset = screenPos + sprite.Offset.XY;
Game.Renderer.RgbaColorRenderer.DrawRect(offset, offset + sprite.Size.XY, 1, Color.Red);
if (rotation == 0f)
Game.Renderer.RgbaColorRenderer.DrawRect(offset, offset + sprite.Size.XY, 1, Color.Red);
else
Game.Renderer.RgbaColorRenderer.DrawPolygon(Util.RotateQuad(offset, sprite.Size, rotation), 1, Color.Red);
}

public Rectangle ScreenBounds(WorldRenderer wr)
{
var offset = screenPos + sprite.Offset;
return new Rectangle((int)offset.X, (int)offset.Y, (int)sprite.Size.X, (int)sprite.Size.Y);
return Util.BoundingRectangle(offset, sprite.Size, rotation);
}
}
}

0 comments on commit e45f209

Please sign in to comment.