Merge pull request #6084 from pchote/renderpreview

Improve actor preview rendering
This commit is contained in:
Matthias Mailänder
2014-08-03 12:51:21 +02:00
30 changed files with 469 additions and 155 deletions

View File

@@ -8,56 +8,76 @@
*/
#endregion
using System;
namespace OpenRA.Traits
{
public class BodyOrientationInfo : ITraitInfo, IBodyOrientationInfo
{
[Desc("Number of facings for gameplay calculations. -1 indiciates auto-detection from sequence")]
[Desc("Number of facings for gameplay calculations. -1 indicates auto-detection from another trait")]
public readonly int QuantizedFacings = -1;
[Desc("Camera pitch for rotation calculations")]
public readonly WAngle CameraPitch = WAngle.FromDegrees(40);
public WVec LocalToWorld(WVec vec)
{
// RA's 2d perspective doesn't correspond to an orthonormal 3D
// coordinate system, so fudge the y axis to make things look good
return new WVec(vec.Y, -CameraPitch.Sin() * vec.X / 1024, vec.Z);
}
public WRot QuantizeOrientation(WRot orientation, int facings)
{
// Quantization disabled
if (facings == 0)
return orientation;
// Map yaw to the closest facing
var facing = Util.QuantizeFacing(orientation.Yaw.Angle / 4, facings) * (256 / facings);
// Roll and pitch are always zero if yaw is quantized
return new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing));
}
public object Create(ActorInitializer init) { return new BodyOrientation(init.self, this); }
}
public class BodyOrientation : IBodyOrientation
{
[Sync] public int QuantizedFacings { get; private set; }
BodyOrientationInfo info;
readonly BodyOrientationInfo info;
readonly Lazy<int> quantizedFacings;
[Sync] public int QuantizedFacings { get { return quantizedFacings.Value; } }
public BodyOrientation(Actor self, BodyOrientationInfo info)
{
this.info = info;
if (info.QuantizedFacings > 0)
QuantizedFacings = info.QuantizedFacings;
quantizedFacings = Exts.Lazy(() =>
{
// Override value is set
if (info.QuantizedFacings >= 0)
return info.QuantizedFacings;
var qboi = self.Info.Traits.GetOrDefault<IQuantizeBodyOrientationInfo>();
if (qboi == null)
throw new InvalidOperationException("Actor type '" + self.Info.Name + "' does not define a quantized body orientation.");
return qboi.QuantizedBodyFacings(self.World.Map.SequenceProvider, self.Info);
});
}
public WAngle CameraPitch { get { return info.CameraPitch; } }
public WVec LocalToWorld(WVec vec)
{
// RA's 2d perspective doesn't correspond to an orthonormal 3D
// coordinate system, so fudge the y axis to make things look good
return new WVec(vec.Y, -info.CameraPitch.Sin()*vec.X/1024, vec.Z);
return info.LocalToWorld(vec);
}
public WRot QuantizeOrientation(Actor self, WRot orientation)
{
// Quantization disabled
if (QuantizedFacings == 0)
return orientation;
// Map yaw to the closest facing
var facing = Util.QuantizeFacing(orientation.Yaw.Angle / 4, QuantizedFacings) * (256 / QuantizedFacings);
// Roll and pitch are always zero if yaw is quantized
return new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing));
}
public void SetAutodetectedFacings(int facings)
{
if (info.QuantizedFacings < 0)
QuantizedFacings = facings;
return info.QuantizeOrientation(orientation, quantizedFacings.Value);
}
}
}

View File

@@ -227,15 +227,22 @@ namespace OpenRA.Traits
public interface IRenderShroud { void RenderShroud(WorldRenderer wr, Shroud shroud); }
public interface IPostRenderSelection { IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr); }
public interface IBodyOrientation
{
WAngle CameraPitch { get; }
int QuantizedFacings { get; }
WVec LocalToWorld(WVec vec);
WRot QuantizeOrientation(Actor self, WRot orientation);
void SetAutodetectedFacings(int facings);
}
public interface IBodyOrientationInfo : ITraitInfo { }
public interface IBodyOrientationInfo : ITraitInfo
{
WVec LocalToWorld(WVec vec);
WRot QuantizeOrientation(WRot orientation, int facings);
}
public interface IQuantizeBodyOrientationInfo { int QuantizedBodyFacings(SequenceProvider sequenceProvider, ActorInfo ai); }
public interface ITargetableInfo
{

View File

@@ -14,7 +14,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
class RenderGunboatInfo : RenderSpritesInfo, Requires<IBodyOrientationInfo>
class RenderGunboatInfo : RenderSpritesInfo, IQuantizeBodyOrientationInfo, Requires<IBodyOrientationInfo>
{
[Desc("Turreted 'Turret' key to display")]
public readonly string Turret = "primary";
@@ -25,6 +25,11 @@ namespace OpenRA.Mods.RA.Render
public readonly string WakeRightSequence = "wake-right";
public override object Create(ActorInitializer init) { return new RenderGunboat(init.self, this); }
public int QuantizedBodyFacings(SequenceProvider sequenceProvider, ActorInfo ai)
{
return 2;
}
}
class RenderGunboat : RenderSprites, INotifyDamageStateChanged
@@ -54,8 +59,6 @@ namespace OpenRA.Mods.RA.Render
var rightWake = new Animation(self.World, name);
rightWake.Play(info.WakeRightSequence);
Add(info.WakeRightSequence, new AnimationWithOffset(rightWake, null, () => facing.Facing <= 128, -87));
self.Trait<IBodyOrientation>().SetAutodetectedFacings(2);
}
public void DamageStateChanged(Actor self, AttackInfo e)

View File

@@ -0,0 +1,45 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Primitives;
namespace OpenRA.Mods.RA.Graphics
{
public interface IActorPreview
{
void Tick();
IEnumerable<IRenderable> Render(WorldRenderer wr, WPos pos);
}
public class ActorPreviewInitializer
{
public readonly ActorInfo Actor;
public readonly Player Owner;
public readonly WorldRenderer WorldRenderer;
public World World { get { return WorldRenderer.world; } }
readonly TypeDictionary dict;
public ActorPreviewInitializer(ActorInfo actor, Player owner, WorldRenderer worldRenderer, TypeDictionary dict)
{
Actor = actor;
Owner = owner;
WorldRenderer = worldRenderer;
this.dict = dict;
}
public T Get<T>() where T : IActorInit { return dict.Get<T>(); }
public U Get<T, U>() where T : IActorInit<U> { return dict.Get<T>().Value(World); }
public bool Contains<T>() where T : IActorInit { return dict.Contains<T>(); }
}
}

View File

@@ -0,0 +1,42 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Primitives;
namespace OpenRA.Mods.RA.Graphics
{
public class SpriteActorPreview : IActorPreview
{
readonly Animation animation;
readonly WVec offset;
readonly int zOffset;
readonly PaletteReference pr;
readonly float scale;
public SpriteActorPreview(Animation animation, WVec offset, int zOffset, PaletteReference pr, float scale)
{
this.animation = animation;
this.offset = offset;
this.zOffset = zOffset;
this.pr = pr;
this.scale = scale;
}
public void Tick() { animation.Tick(); }
public IEnumerable<IRenderable> Render(WorldRenderer wr, WPos pos)
{
return animation.Render(pos, offset, zOffset, pr, scale);
}
}
}

View File

@@ -0,0 +1,58 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Render;
using OpenRA.Primitives;
namespace OpenRA.Mods.RA.Graphics
{
public class VoxelPreview : IActorPreview
{
readonly VoxelAnimation[] components;
readonly RenderVoxelsInfo rvi;
readonly WRot lightSource;
readonly WRot camera;
readonly PaletteReference colorPalette;
readonly PaletteReference normalsPalette;
readonly PaletteReference shadowPalette;
readonly WVec offset;
readonly int zOffset;
public VoxelPreview(VoxelAnimation[] components, WVec offset, int zOffset, RenderVoxelsInfo rvi, WAngle cameraPitch,
PaletteReference colorPalette, PaletteReference normalsPalette, PaletteReference shadowPalette)
{
this.components = components;
this.rvi = rvi;
lightSource = new WRot(WAngle.Zero,new WAngle(256) - rvi.LightPitch, rvi.LightYaw);
camera = new WRot(WAngle.Zero, cameraPitch - new WAngle(256), new WAngle(256));
this.colorPalette = colorPalette;
this.normalsPalette = normalsPalette;
this.shadowPalette = shadowPalette;
this.offset = offset;
this.zOffset = zOffset;
}
public void Tick() { /* not supported */ }
public IEnumerable<IRenderable> Render(WorldRenderer wr, WPos pos)
{
yield return new VoxelRenderable(components, pos + offset, zOffset, camera, rvi.Scale,
lightSource, rvi.LightAmbientColor, rvi.LightDiffuseColor,
colorPalette, normalsPalette, shadowPalette);
}
}
}

View File

@@ -545,6 +545,9 @@
<Compile Include="Widgets\LabelWithTooltipWidget.cs" />
<Compile Include="ProductionQueueFromSelection.cs" />
<Compile Include="Scripting\Global\MediaGlobal.cs" />
<Compile Include="Graphics\ActorPreview.cs" />
<Compile Include="Graphics\SpriteActorPreview.cs" />
<Compile Include="Graphics\VoxelActorPreview.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">

View File

@@ -13,8 +13,10 @@ using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Primitives;
namespace OpenRA.Mods.RA.Orders
{
@@ -23,8 +25,8 @@ namespace OpenRA.Mods.RA.Orders
readonly Actor Producer;
readonly string Building;
readonly BuildingInfo BuildingInfo;
IActorPreview[] preview;
IEnumerable<IRenderable> preview;
Sprite buildOk, buildBlocked;
bool initialized = false;
@@ -79,7 +81,15 @@ namespace OpenRA.Mods.RA.Orders
}
}
public void Tick(World world) {}
public void Tick(World world)
{
if (preview == null)
return;
foreach (var p in preview)
p.Tick();
}
public IEnumerable<IRenderable> Render(WorldRenderer wr, World world) { yield break; }
public IEnumerable<IRenderable> RenderAfterWorld(WorldRenderer wr, World world)
{
@@ -108,23 +118,22 @@ namespace OpenRA.Mods.RA.Orders
{
if (!initialized)
{
var rbi = rules.Actors[Building].Traits.GetOrDefault<RenderBuildingInfo>();
if (rbi == null)
preview = new IRenderable[0];
else
{
var palette = rbi.Palette ?? (Producer.Owner != null ?
rbi.PlayerPalette + Producer.Owner.InternalName : null);
preview = rbi.RenderPreview(world, rules.Actors[Building], wr.Palette(palette));
}
var init = new ActorPreviewInitializer(rules.Actors[Building], Producer.Owner, wr, new TypeDictionary());
preview = rules.Actors[Building].Traits.WithInterface<IRenderActorPreviewInfo>()
.SelectMany(rpi => rpi.RenderPreview(init))
.ToArray();
initialized = true;
}
var offset = world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(world, BuildingInfo) - WPos.Zero;
foreach (var r in preview)
yield return r.OffsetBy(offset);
var comparer = new RenderableComparer(wr);
var offset = world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(world, BuildingInfo);
var previewRenderables = preview
.SelectMany(p => p.Render(wr, offset))
.OrderBy(r => r, comparer);
foreach (var r in previewRenderables)
yield return r;
var res = world.WorldActor.Trait<ResourceLayer>();
var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft);

View File

@@ -49,8 +49,6 @@ namespace OpenRA.Mods.RA.Render
this.info = info;
DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle"));
self.Trait<IBodyOrientation>().SetAutodetectedFacings(DefaultAnimation.CurrentSequence.Facings);
}
public virtual void BuildingComplete(Actor self)

View File

@@ -9,7 +9,10 @@
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
@@ -17,6 +20,18 @@ namespace OpenRA.Mods.RA.Render
class RenderBuildingTurretedInfo : RenderBuildingInfo, Requires<TurretedInfo>
{
public override object Create(ActorInitializer init) { return new RenderBuildingTurreted(init, this); }
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var t = init.Actor.Traits.WithInterface<TurretedInfo>()
.FirstOrDefault();
// Show the correct turret facing
var anim = new Animation(init.World, image, () => t.InitialFacing);
anim.PlayRepeating("idle");
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
}
}
class RenderBuildingTurreted : RenderBuilding

View File

@@ -8,7 +8,10 @@
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
@@ -19,6 +22,15 @@ namespace OpenRA.Mods.RA.Render
public readonly string Sequence = "idle";
public override object Create(ActorInitializer init) { return new RenderBuildingWall(init, this); }
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
// Show a static frame instead of animating all of the wall states
var anim = new Animation(init.World, image, () => 0);
anim.PlayFetchIndex("idle", () => 0);
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
}
}
class RenderBuildingWall : RenderBuilding, INotifyAddedToWorld, INotifyRemovedFromWorld

View File

@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
@@ -20,19 +21,18 @@ namespace OpenRA.Mods.RA.Render
{
public override object Create(ActorInitializer init) { return new RenderBuildingWarFactory(init, this); }
/* get around unverifiability */
IEnumerable<IRenderable> BaseBuildingPreview(World world, ActorInfo building, PaletteReference pr)
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
return base.RenderPreview(world, building, pr);
}
foreach (var orig in base.RenderPreviewSprites(init, rs, image, facings, p))
yield return orig;
public override IEnumerable<IRenderable> RenderPreview(World world, ActorInfo building, PaletteReference pr)
{
var p = BaseBuildingPreview(world, building, pr);
var anim = new Animation(world, RenderSprites.GetImage(building), () => 0);
// Show additional roof overlay
var anim = new Animation(init.World, image, () => 0);
anim.PlayRepeating("idle-top");
return p.Concat(anim.Render(WPos.Zero, WVec.Zero, 0, pr, Scale));
var bi = init.Actor.Traits.Get<BuildingInfo>();
var offset = FootprintUtils.CenterOffset(init.World, bi).Y + 512;
yield return new SpriteActorPreview(anim, WVec.Zero, offset, p, rs.Scale);
}
}

View File

@@ -8,7 +8,11 @@
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.RA.Effects;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
@@ -25,6 +29,23 @@ namespace OpenRA.Mods.RA.Render
public readonly string[] StandAnimations = { "stand" };
public override object Create(ActorInitializer init) { return new RenderInfantry(init.self, this); }
public override IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var facing = 0;
var ifacing = init.Actor.Traits.GetOrDefault<IFacingInfo>();
if (ifacing != null)
facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : ifacing.GetInitialFacing();
var anim = new Animation(init.World, image, () => facing);
anim.PlayRepeating(StandAnimations.First());
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
}
public override int QuantizedBodyFacings(SequenceProvider sequenceProvider, ActorInfo ai)
{
return sequenceProvider.GetSequence(RenderSprites.GetImage(ai), StandAnimations.First()).Facings;
}
}
public class RenderInfantry : RenderSimple, INotifyAttack, INotifyKilled, INotifyIdle
@@ -64,8 +85,6 @@ namespace OpenRA.Mods.RA.Render
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
State = AnimationState.Waiting;
move = self.Trait<IMove>();
self.Trait<IBodyOrientation>().SetAutodetectedFacings(DefaultAnimation.CurrentSequence.Facings);
}
public void Attacking(Actor self, Target target)

View File

@@ -11,20 +11,28 @@
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
public class RenderSimpleInfo : RenderSpritesInfo, ILegacyEditorRenderInfo, Requires<IBodyOrientationInfo>
public class RenderSimpleInfo : RenderSpritesInfo, IRenderActorPreviewSpritesInfo, IQuantizeBodyOrientationInfo, ILegacyEditorRenderInfo, Requires<IBodyOrientationInfo>
{
public override object Create(ActorInitializer init) { return new RenderSimple(init.self); }
public virtual IEnumerable<IRenderable> RenderPreview(World world, ActorInfo ai, PaletteReference pr)
public virtual IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var anim = new Animation(world, RenderSimple.GetImage(ai), () => 0);
anim.PlayRepeating("idle");
var ifacing = init.Actor.Traits.GetOrDefault<IFacingInfo>();
var facing = ifacing != null ? init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : ifacing.GetInitialFacing() : 0;
return anim.Render(WPos.Zero, WVec.Zero, 0, pr, Scale);
var anim = new Animation(init.World, image, () => facing);
anim.PlayRepeating("idle");
yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale);
}
public virtual int QuantizedBodyFacings(SequenceProvider sequenceProvider, ActorInfo ai)
{
return sequenceProvider.GetSequence(RenderSprites.GetImage(ai), "idle").Facings;
}
public string EditorPalette { get { return Palette; } }
@@ -46,7 +54,6 @@ namespace OpenRA.Mods.RA.Render
: this(self, MakeFacingFunc(self))
{
DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle"));
self.Trait<IBodyOrientation>().SetAutodetectedFacings(DefaultAnimation.CurrentSequence.Facings);
}
public int2 SelectionSize(Actor self) { return AutoSelectionSize(self); }

View File

@@ -12,12 +12,15 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
using OpenRA.Primitives;
namespace OpenRA.Mods.RA.Render
{
public class RenderSpritesInfo : ITraitInfo
public interface IRenderActorPreviewSpritesInfo { IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p); }
public class RenderSpritesInfo : IRenderActorPreviewInfo, ITraitInfo
{
[Desc("Defaults to the actor name.")]
public readonly string Image = null;
@@ -30,6 +33,23 @@ namespace OpenRA.Mods.RA.Render
public readonly float Scale = 1f;
public virtual object Create(ActorInitializer init) { return new RenderSprites(init.self); }
public IEnumerable<IActorPreview> RenderPreview(ActorPreviewInitializer init)
{
var sequenceProvider = init.World.Map.SequenceProvider;
var image = RenderSprites.GetImage(init.Actor);
var palette = init.WorldRenderer.Palette(Palette ?? (init.Owner != null ? PlayerPalette + init.Owner.InternalName : null));
var facings = 0;
var body = init.Actor.Traits.GetOrDefault<BodyOrientationInfo>();
if (body != null)
facings = body.QuantizedFacings == -1 ? init.Actor.Traits.Get<IQuantizeBodyOrientationInfo>().QuantizedBodyFacings(sequenceProvider, init.Actor) : body.QuantizedFacings;
foreach (var spi in init.Actor.Traits.WithInterface<IRenderActorPreviewSpritesInfo>())
foreach (var preview in spi.RenderPreviewSprites(init, this, image, facings, palette))
yield return preview;
}
}
public class RenderSprites : IRender, ITick, INotifyOwnerChanged, INotifyEffectiveOwnerChanged
@@ -89,7 +109,7 @@ namespace OpenRA.Mods.RA.Render
public static string GetImage(ActorInfo actor)
{
var Info = actor.Traits.Get<RenderSpritesInfo>();
return Info.Image ?? actor.Name;
return (Info.Image ?? actor.Name).ToLowerInvariant();
}
public string GetImage(Actor self)

View File

@@ -9,13 +9,16 @@
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
public class RenderVoxelsInfo : ITraitInfo, Requires<IBodyOrientationInfo>
public interface IRenderActorPreviewVoxelsInfo { IEnumerable<VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p); }
public class RenderVoxelsInfo : ITraitInfo, IRenderActorPreviewInfo, Requires<IBodyOrientationInfo>
{
[Desc("Defaults to the actor name.")]
public readonly string Image = null;
@@ -34,7 +37,27 @@ namespace OpenRA.Mods.RA.Render
public readonly WAngle LightYaw = WAngle.FromDegrees(240);
public readonly float[] LightAmbientColor = new float[] {0.6f, 0.6f, 0.6f};
public readonly float[] LightDiffuseColor = new float[] {0.4f, 0.4f, 0.4f};
public virtual object Create(ActorInitializer init) { return new RenderVoxels(init.self, this); }
public virtual IEnumerable<IActorPreview> RenderPreview(ActorPreviewInitializer init)
{
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
var sequenceProvider = init.World.Map.SequenceProvider;
var image = Image ?? init.Actor.Name;
var facings = body.QuantizedFacings == -1 ? init.Actor.Traits.Get<IQuantizeBodyOrientationInfo>().QuantizedBodyFacings(sequenceProvider, init.Actor) : body.QuantizedFacings;
var palette = init.WorldRenderer.Palette(Palette ?? (init.Owner != null ? PlayerPalette + init.Owner.InternalName : null));
var facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
var orientation = WRot.FromFacing(facing);
var components = init.Actor.Traits.WithInterface<IRenderActorPreviewVoxelsInfo>()
.SelectMany(rvpi => rvpi.RenderPreviewVoxels(init, this, image, orientation, facings, palette))
.ToArray();
yield return new VoxelPreview(components, WVec.Zero, 0, this, body.CameraPitch, palette,
init.WorldRenderer.Palette(NormalsPalette), init.WorldRenderer.Palette("shadow"));
}
}
public class RenderVoxels : IRender, INotifyOwnerChanged

View File

@@ -8,15 +8,17 @@
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
[Desc("Renders a decorative animation on units and buildings.")]
public class WithIdleOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<IBodyOrientationInfo>
public class WithIdleOverlayInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<IBodyOrientationInfo>
{
[Desc("Sequence name to use")]
public readonly string Sequence = "idle-overlay";
@@ -33,6 +35,18 @@ namespace OpenRA.Mods.RA.Render
public readonly bool PauseOnLowPower = false;
public object Create(ActorInitializer init) { return new WithIdleOverlay(init.self, this); }
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
var facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
var anim = new Animation(init.World, image, () => facing);
anim.PlayRepeating(Sequence);
var orientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)), facings);
var offset = body.LocalToWorld(Offset.Rotate(orientation));
yield return new SpriteActorPreview(anim, offset, offset.Y + offset.Z + 1, p, rs.Scale);
}
}
public class WithIdleOverlay : INotifyDamageStateChanged, INotifyBuildComplete, INotifySold

View File

@@ -8,13 +8,16 @@
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
[Desc("Displays a helicopter rotor overlay.")]
public class WithRotorInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<IBodyOrientationInfo>
public class WithRotorInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<IBodyOrientationInfo>
{
[Desc("Sequence name to use when flying")]
public readonly string Sequence = "rotor";
@@ -29,6 +32,18 @@ namespace OpenRA.Mods.RA.Render
public readonly string Id = "rotor";
public object Create(ActorInitializer init) { return new WithRotor(init.self, this); }
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
var facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0;
var anim = new Animation(init.World, image, () => facing);
anim.PlayRepeating(Sequence);
var orientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)), facings);
var offset = body.LocalToWorld(Offset.Rotate(orientation));
yield return new SpriteActorPreview(anim, offset, offset.Y + offset.Z + 1, p, rs.Scale);
}
}
public class WithRotor : ITick

View File

@@ -11,12 +11,13 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
[Desc("Renders barrels for units with the Turreted trait.")]
class WithTurretInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<TurretedInfo>, Requires<IBodyOrientationInfo>
class WithTurretInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<TurretedInfo>, Requires<IBodyOrientationInfo>
{
[Desc("Sequence name to use")]
public readonly string Sequence = "turret";
@@ -31,6 +32,20 @@ namespace OpenRA.Mods.RA.Render
public readonly bool Recoils = true;
public object Create(ActorInitializer init) { return new WithTurret(init.self, this); }
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
var t = init.Actor.Traits.WithInterface<TurretedInfo>()
.First(tt => tt.Turret == Turret);
var anim = new Animation(init.World, image, () => t.InitialFacing);
anim.Play(Sequence);
var orientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(t.InitialFacing)), facings);
var offset = body.LocalToWorld(t.Offset.Rotate(orientation));
yield return new SpriteActorPreview(anim, offset, offset.Y + offset.Z + 1, p, rs.Scale);
}
}
class WithTurret : ITick

View File

@@ -11,11 +11,12 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
public class WithVoxelBarrelInfo : ITraitInfo, Requires<RenderVoxelsInfo>
public class WithVoxelBarrelInfo : ITraitInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>
{
[Desc("Voxel sequence name to use")]
public readonly string Sequence = "barrel";
@@ -25,6 +26,22 @@ namespace OpenRA.Mods.RA.Render
public readonly WVec LocalOffset = WVec.Zero;
public object Create(ActorInitializer init) { return new WithVoxelBarrel(init.self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
{
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
var armament = init.Actor.Traits.WithInterface<ArmamentInfo>()
.First(a => a.Name == Armament);
var t = init.Actor.Traits.WithInterface<TurretedInfo>()
.First(tt => tt.Turret == armament.Turret);
var voxel = VoxelProvider.GetVoxel(image, Sequence);
var turretOrientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(t.InitialFacing) - orientation.Yaw), facings);
var turretOffset = body.LocalToWorld(t.Offset.Rotate(orientation));
yield return new VoxelAnimation(voxel, () => turretOffset, () => new [] { turretOrientation, orientation },
() => false, () => 0);
}
}
public class WithVoxelBarrel

16
OpenRA.Mods.RA/Render/WithVoxelBody.cs Executable file → Normal file
View File

@@ -9,18 +9,32 @@
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
[Desc("Also returns a default selection size that is calculated automatically from the voxel dimensions.")]
public class WithVoxelBodyInfo : ITraitInfo, Requires<RenderVoxelsInfo>
public class WithVoxelBodyInfo : ITraitInfo, IQuantizeBodyOrientationInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>
{
public readonly string Sequence = "idle";
public object Create(ActorInitializer init) { return new WithVoxelBody(init.self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
{
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
var voxel = VoxelProvider.GetVoxel(image, "idle");
var bodyOrientation = new[] { body.QuantizeOrientation(orientation, facings) };
yield return new VoxelAnimation(voxel, () => WVec.Zero,
() => bodyOrientation,
() => false, () => 0);
}
public int QuantizedBodyFacings(SequenceProvider sequenceProvider, ActorInfo ai) { return 0; }
}
public class WithVoxelBody : IAutoSelectionSize

View File

@@ -11,11 +11,12 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
public class WithVoxelTurretInfo : ITraitInfo, Requires<RenderVoxelsInfo>
public class WithVoxelTurretInfo : ITraitInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>, Requires<TurretedInfo>
{
[Desc("Voxel sequence name to use")]
public readonly string Sequence = "turret";
@@ -24,6 +25,20 @@ namespace OpenRA.Mods.RA.Render
public readonly string Turret = "primary";
public object Create(ActorInitializer init) { return new WithVoxelTurret(init.self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
{
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
var t = init.Actor.Traits.WithInterface<TurretedInfo>()
.First(tt => tt.Turret == Turret);
var voxel = VoxelProvider.GetVoxel(image, Sequence);
var turretOffset = body.LocalToWorld(t.Offset.Rotate(orientation));
var turretBodyOrientation = new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(t.InitialFacing) - orientation.Yaw);
var turretOrientation = new[] { turretBodyOrientation, body.QuantizeOrientation(orientation, facings) };
yield return new VoxelAnimation(voxel, () => turretOffset, () => turretOrientation, () => false, () => 0);
}
}
public class WithVoxelTurret

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
@@ -50,4 +51,5 @@ namespace OpenRA.Mods.RA
public interface INotifyTransform { void BeforeTransform(Actor self); void OnTransform(Actor self); void AfterTransform(Actor toActor); }
public interface INotifyAttack { void Attacking(Actor self, Target target, Armament a, Barrel barrel); }
public interface INotifyChat { bool OnChat(string from, string message); }
public interface IRenderActorPreviewInfo { IEnumerable<IActorPreview> RenderPreview(ActorPreviewInitializer init); }
}

View File

@@ -12,11 +12,12 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
public class WithVoxelUnloadBodyInfo : ITraitInfo, Requires<RenderVoxelsInfo>
public class WithVoxelUnloadBodyInfo : ITraitInfo, IQuantizeBodyOrientationInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>
{
[Desc("Voxel sequence name to use when docked to a refinery.")]
public readonly string UnloadSequence = "unload";
@@ -25,6 +26,17 @@ namespace OpenRA.Mods.RA.Render
public readonly string IdleSequence = "idle";
public object Create(ActorInitializer init) { return new WithVoxelUnloadBody(init.self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
{
var body = init.Actor.Traits.Get<BodyOrientationInfo>();
var voxel = VoxelProvider.GetVoxel(image, "idle");
yield return new VoxelAnimation(voxel, () => WVec.Zero,
() => new[]{ body.QuantizeOrientation(orientation, facings) },
() => false, () => 0);
}
public int QuantizedBodyFacings(SequenceProvider sequenceProvider, ActorInfo ai) { return 0; }
}
public class WithVoxelUnloadBody : IAutoSelectionSize

View File

@@ -15,10 +15,12 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
public class WithVoxelWalkerBodyInfo : ITraitInfo, Requires<RenderVoxelsInfo>, Requires<IMoveInfo>
public class WithVoxelWalkerBodyInfo : ITraitInfo, IQuantizeBodyOrientationInfo, Requires<RenderVoxelsInfo>, Requires<IMoveInfo>
{
public readonly int TickRate = 5;
public object Create(ActorInitializer init) { return new WithVoxelWalkerBody(init.self, this); }
public int QuantizedBodyFacings(SequenceProvider sequenceProvider, ActorInfo ai) { return 0; }
}
public class WithVoxelWalkerBody : IAutoSelectionSize, ITick

View File

@@ -25,8 +25,6 @@ REFA:
Inherits: ^REFINERY
Buildable:
Owner: atreides
RenderBuildingWarFactory:
Image: REFA
BARRA:
Inherits: ^BARRACKS
@@ -76,15 +74,11 @@ LIGHTA:
Inherits: ^LIGHT
Buildable:
Owner: atreides
RenderBuildingWarFactory:
Image: LIGHTA
HEAVYA:
Inherits: ^HEAVY
Buildable:
Owner: atreides
RenderBuildingWarFactory:
Image: HEAVYA
RADARA:
Inherits: ^RADAR

View File

@@ -25,8 +25,6 @@ REFH:
Inherits: ^REFINERY
Buildable:
Owner: harkonnen
RenderBuildingWarFactory:
Image: REFH
BARRH:
Inherits: ^BARRACKS
@@ -53,15 +51,11 @@ LIGHTH:
Inherits: ^LIGHT
Buildable:
Owner: harkonnen
RenderBuildingWarFactory:
Image: LIGHTH
HEAVYH:
Inherits: ^HEAVY
Buildable:
Owner: harkonnen
RenderBuildingWarFactory:
Image: HEAVYH
RADARH:
Inherits: ^RADAR

View File

@@ -25,8 +25,6 @@ REFO:
Inherits: ^REFINERY
Buildable:
Owner: ordos
RenderBuildingWarFactory:
Image: REFO
BARRO:
Inherits: ^BARRACKS
@@ -52,15 +50,11 @@ LIGHTO:
Inherits: ^LIGHT
Buildable:
Owner: ordos
RenderBuildingWarFactory:
Image: LIGHTO
HEAVYO:
Inherits: ^HEAVY
Buildable:
Owner: ordos
RenderBuildingWarFactory:
Image: HEAVYO
RADARO:
Inherits: ^RADAR

View File

@@ -173,7 +173,6 @@ CONCRETEB:
Type: Wood
RevealsShroud:
Range: 6c0
-RenderBuilding:
OreRefinery:
DockOffset: 2,1
DockAngle: 160
@@ -195,6 +194,8 @@ CONCRETEB:
Sequence: smoke
Power:
Amount: -30
WithIdleOverlay@TOP:
Sequence: idle-top
^SILO:
Inherits: ^Building
@@ -251,7 +252,6 @@ CONCRETEB:
Type: Wood
RevealsShroud:
Range: 4c0
-RenderBuilding:
RallyPoint:
RallyPoint: 2,2
Exit@1:
@@ -265,6 +265,8 @@ CONCRETEB:
Prerequisite: Light
WithProductionOverlay@WELDING:
Sequence: production-welding
WithIdleOverlay@TOP:
Sequence: idle-top
Power:
Amount: -20
@@ -291,7 +293,6 @@ CONCRETEB:
Type: Wood
RevealsShroud:
Range: 4c0
-RenderBuilding:
RallyPoint:
RallyPoint: 0,3
Exit@1:
@@ -305,6 +306,8 @@ CONCRETEB:
Prerequisite: Heavy
WithProductionOverlay@WELDING:
Sequence: production-welding
WithIdleOverlay@TOP:
Sequence: idle-top
Power:
Amount: -30
@@ -724,8 +727,6 @@ PALACEC:
HEAVYC:
Inherits: ^HEAVY
-Buildable:
RenderBuildingWarFactory:
Image: HEAVYC
CONYARD:
Tooltip:

View File

@@ -693,14 +693,6 @@ lighta:
damaged-idle: DATA
Start: 2673
Offset: -48,64
build-top: DATA
Start: 2674
Length: 1
Offset: -48,64
damaged-build-top: DATA
Start: 2675
Length: 1
Offset: -48,64
idle-top: DATA
Start: 2674
Offset: -48,64
@@ -742,14 +734,6 @@ heavya:
damaged-idle: DATA
Start: 2518
Offset: -48,80
build-top: DATA
Start: 2519
Length: 1
Offset: -48,80
damaged-build-top: DATA
Start: 2520
Length: 1
Offset: -48,80
idle-top: DATA
Start: 2519
Offset: -48,80
@@ -1104,14 +1088,6 @@ lighth:
damaged-idle: DATA
Start: 2833
Offset: -48,64
build-top: DATA
Start: 2834
Length: 1
Offset: -48,64
damaged-build-top: DATA
Start: 2835
Length: 1
Offset: -48,64
idle-top: DATA
Start: 2834
Offset: -48,64
@@ -1153,14 +1129,6 @@ heavyh:
damaged-idle: DATA
Start: 2678
Offset: -48,80
build-top: DATA
Start: 2679
Length: 1
Offset: -48,80
damaged-build-top: DATA
Start: 2680
Length: 1
Offset: -48,80
idle-top: DATA
Start: 2679
Offset: -48,80
@@ -1508,14 +1476,6 @@ lighto:
damaged-idle: DATA
Start: 2993
Offset: -48,64
build-top: DATA
Start: 2994
Length: 1
Offset: -48,64
damaged-build-top: DATA
Start: 2995
Length: 1
Offset: -48,64
idle-top: DATA
Start: 2994
Offset: -48,64
@@ -1557,14 +1517,6 @@ heavyo:
damaged-idle: DATA
Start: 2838
Offset: -48,80
build-top: DATA
Start: 2839
Length: 1
Offset: -48,80
damaged-build-top: DATA
Start: 2840
Length: 1
Offset: -48,80
idle-top: DATA
Start: 2839
Offset: -48,80
@@ -1677,14 +1629,6 @@ heavyc: # TODO: unused
damaged-idle: DATA
Start: 3001
Offset: -48,64
build-top: DATA
Start: 3002
Length: 1
Offset: -48,64
damaged-build-top: DATA
Start: 3003
Length: 1
Offset: -48,64
idle-top: DATA
Start: 3002
Offset: -48,64