Skip to content

Commit

Permalink
Merge branch 'bleed' into rv-engine
Browse files Browse the repository at this point in the history
  • Loading branch information
MustaphaTR committed Dec 15, 2023
2 parents db809a8 + 6c56ea4 commit 495fc22
Show file tree
Hide file tree
Showing 23 changed files with 168 additions and 58 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ jobs:
cd wiki
git config --local user.email "[email protected]"
git config --local user.name "GitHub Actions"
git status
git diff-index --quiet HEAD || \
(
git add --all && \
Expand Down Expand Up @@ -140,6 +141,7 @@ jobs:
cd docs
git config --local user.email "[email protected]"
git config --local user.name "GitHub Actions"
git status
git diff-index --quiet HEAD || \
(
git add api/*.md && \
Expand Down
10 changes: 1 addition & 9 deletions OpenRA.Game/Graphics/WorldRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public sealed class WorldRenderer : IDisposable
readonly List<IRenderable> renderablesBuffer = new();
readonly IRenderer[] renderers;
readonly IRenderPostProcessPass[] postProcessPasses;
readonly ITexture postProcessTexture;

internal WorldRenderer(ModData modData, World world)
{
Expand Down Expand Up @@ -75,8 +74,6 @@ internal WorldRenderer(ModData modData, World world)
debugVis = Exts.Lazy(() => world.WorldActor.TraitOrDefault<DebugVisualizations>());

postProcessPasses = world.WorldActor.TraitsImplementing<IRenderPostProcessPass>().ToArray();
if (postProcessPasses.Length > 0)
postProcessTexture = Game.Renderer.Context.CreateTexture();
}

public void BeginFrame()
Expand Down Expand Up @@ -323,18 +320,13 @@ public void Draw()

void ApplyPostProcessing(PostProcessPassType type)
{
var size = Game.Renderer.WorldFrameBufferSize;
var rect = new Rectangle(0, 0, size.Width, size.Height);
foreach (var pass in postProcessPasses)
{
if (pass.Type != type || !pass.Enabled)
continue;

// Make a copy of the world texture to avoid reading and writing on the same buffer
Game.Renderer.Flush();
postProcessTexture.SetDataFromReadBuffer(rect);
Game.Renderer.Flush();
pass.Draw(this, postProcessTexture);
pass.Draw(this);
}
}

Expand Down
8 changes: 4 additions & 4 deletions OpenRA.Game/MiniYaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,6 @@ static List<MiniYamlNode> FromLines(IEnumerable<ReadOnlyMemory<char>> lines, str
}
}

if (parsedLines.Count > 0 && parsedLines[^1].Level < level - 1)
throw new YamlException($"Bad indent in miniyaml at {location}");

// Extract key, value, comment from line as `<key>: <value>#<comment>`
// The # character is allowed in the value if escaped (\#).
// Leading and trailing whitespace is always trimmed from keys.
Expand All @@ -282,7 +279,7 @@ static List<MiniYamlNode> FromLines(IEnumerable<ReadOnlyMemory<char>> lines, str
if (commentStart < 0 && line[i] == '#' && (i == 0 || line[i - 1] != '\\'))
{
commentStart = i + 1;
if (commentStart <= keyLength)
if (i <= keyStart + keyLength)
keyLength = i - keyStart;
else
valueLength = i - valueStart;
Expand Down Expand Up @@ -320,6 +317,9 @@ static List<MiniYamlNode> FromLines(IEnumerable<ReadOnlyMemory<char>> lines, str

if (!key.IsEmpty || !discardCommentsAndWhitespace)
{
if (parsedLines.Count > 0 && parsedLines[^1].Level < level - 1)
throw new YamlException($"Bad indent in miniyaml at {location}");

while (parsedLines.Count > 0 && parsedLines[^1].Level > level)
BuildCompletedSubNode(level);

Expand Down
14 changes: 14 additions & 0 deletions OpenRA.Game/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ enum RenderType { None, World, UI }
readonly IVertexBuffer<Vertex> tempVertexBuffer;
readonly IIndexBuffer quadIndexBuffer;
readonly Stack<Rectangle> scissorState = new();
readonly ITexture worldBufferSnapshot;

IFrameBuffer screenBuffer;
Sprite screenSprite;
Expand All @@ -60,6 +61,15 @@ enum RenderType { None, World, UI }
public Size WorldFrameBufferSize => worldSheet.Size;
public int WorldDownscaleFactor { get; private set; } = 1;

/// <summary>
/// Copies and returns the currently rendered world state as a temporary texture.
/// </summary>
public ITexture WorldBufferSnapshot()
{
worldBufferSnapshot.SetDataFromReadBuffer(new Rectangle(int2.Zero, worldSheet.Size));
return worldBufferSnapshot;
}

SheetBuilder fontSheetBuilder;
readonly IPlatform platform;

Expand Down Expand Up @@ -98,6 +108,7 @@ public Renderer(IPlatform platform, GraphicSettings graphicSettings)

tempVertexBuffer = Context.CreateVertexBuffer<Vertex>(TempVertexBufferSize);
quadIndexBuffer = Context.CreateIndexBuffer(Util.CreateQuadIndices(TempIndexBufferSize / 6));
worldBufferSnapshot = Context.CreateTexture();
}

static Size GetResolution(GraphicSettings graphicsSettings)
Expand Down Expand Up @@ -523,6 +534,9 @@ public void SaveScreenshot(string path)

public void Dispose()
{
worldBuffer.Dispose();
screenBuffer.Dispose();
worldBufferSnapshot.Dispose();
tempVertexBuffer.Dispose();
quadIndexBuffer.Dispose();
fontSheetBuilder?.Dispose();
Expand Down
2 changes: 1 addition & 1 deletion OpenRA.Game/Traits/TraitsInterfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ public interface IRenderPostProcessPass
{
PostProcessPassType Type { get; }
bool Enabled { get; }
void Draw(WorldRenderer wr, ITexture worldTexture);
void Draw(WorldRenderer wr);
}

[Flags]
Expand Down
4 changes: 2 additions & 2 deletions OpenRA.Mods.Cnc/Traits/World/ChronoVortexRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void DrawVortex(float3 pos, int frame)
PostProcessPassType IRenderPostProcessPass.Type => PostProcessPassType.AfterWorld;
bool IRenderPostProcessPass.Enabled => vortices.Count > 0;

void IRenderPostProcessPass.Draw(WorldRenderer wr, ITexture worldTexture)
void IRenderPostProcessPass.Draw(WorldRenderer wr)
{
var scroll = wr.Viewport.TopLeft;
var size = renderer.WorldFrameBufferSize;
Expand All @@ -94,7 +94,7 @@ void IRenderPostProcessPass.Draw(WorldRenderer wr, ITexture worldTexture)
shader.SetVec("Scroll", scroll.X, scroll.Y);
shader.SetVec("p1", width, height);
shader.SetVec("p2", -1, -1);
shader.SetTexture("WorldTexture", worldTexture);
shader.SetTexture("WorldTexture", Game.Renderer.WorldBufferSnapshot());
shader.SetTexture("VortexTexture", vortexSheet.GetTexture());
shader.PrepareRender();
foreach (var (pos, frame) in vortices)
Expand Down
15 changes: 11 additions & 4 deletions OpenRA.Mods.Common/Lint/CheckActors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,24 @@

using System;
using System.Linq;
using OpenRA.Scripting;

namespace OpenRA.Mods.Common.Lint
{
public class CheckActors : ILintMapPass
{
public void Run(Action<string> emitError, Action<string> emitWarning, ModData modData, Map map)
{
var actorTypes = map.ActorDefinitions.Select(a => a.Value.Value);
foreach (var actor in actorTypes)
if (!map.Rules.Actors.Keys.Contains(actor.ToLowerInvariant()))
emitError($"Actor `{actor}` is not defined by any rule.");
var scriptBindings = Game.ModData.ObjectCreator.GetTypesImplementing<ScriptGlobal>().Select(t => Utility.GetCustomAttributes<ScriptGlobalAttribute>(t, true)[0].Name).ToHashSet();
foreach (var actor in map.ActorDefinitions)
{
var name = actor.Value.Value;
if (!map.Rules.Actors.ContainsKey(name.ToLowerInvariant()))
emitError($"Actor `{name}` is not defined by any rule.");

if (scriptBindings.Contains(actor.Key))
emitError($"Named actor `{actor.Key}` conflicts with a script global of the same name. Consider renaming the actor.");
}
}
}
}
6 changes: 6 additions & 0 deletions OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public class HarvesterAttackNotifierInfo : TraitInfo
[Desc("Length of time (in ticks) to display a location ping in the minimap.")]
public readonly int RadarPingDuration = 250;

[Desc("Exclude damage types (defined on the warheads) that trigger Notification.")]
public readonly BitSet<DamageType> ExludeDamageTypes = default;

[NotificationReference("Speech")]
[Desc("Speech notification type to play.")]
public readonly string Notification = "HarvesterAttack";
Expand Down Expand Up @@ -54,6 +57,9 @@ public HarvesterAttackNotifier(Actor self, HarvesterAttackNotifierInfo info)

void INotifyDamage.Damaged(Actor self, AttackInfo e)
{
if (!info.ExludeDamageTypes.IsEmpty && e.Damage.DamageTypes.Overlaps(info.ExludeDamageTypes))
return;

// Don't track self-damage
if (e.Attacker != null && e.Attacker.Owner == self.Owner)
return;
Expand Down
4 changes: 2 additions & 2 deletions OpenRA.Mods.Common/Traits/World/RenderPostProcessPassBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ protected RenderPostProcessPassBase(string name, PostProcessPassType type)

PostProcessPassType IRenderPostProcessPass.Type => type;
bool IRenderPostProcessPass.Enabled => Enabled;
void IRenderPostProcessPass.Draw(WorldRenderer wr, ITexture worldTexture)
void IRenderPostProcessPass.Draw(WorldRenderer wr)
{
shader.SetTexture("WorldTexture", worldTexture);
shader.SetTexture("WorldTexture", Game.Renderer.WorldBufferSnapshot());
PrepareRender(wr, shader);
shader.PrepareRender();
renderer.DrawBatch(buffer, shader, 0, 6, PrimitiveType.TriangleList);
Expand Down
73 changes: 60 additions & 13 deletions OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits
{
[Desc("Adds a particle-based overlay.")]
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
public class WeatherOverlayInfo : TraitInfo, ILobbyCustomRulesIgnore
public class WeatherOverlayInfo : ConditionalTraitInfo, ILobbyCustomRulesIgnore
{
[Desc("Average number of particles per 100x100 px square.")]
public readonly int ParticleDensityFactor = 8;
Expand Down Expand Up @@ -69,10 +69,19 @@ public class WeatherOverlayInfo : TraitInfo, ILobbyCustomRulesIgnore
[Desc("Works only with line enabled and can be used to fade out the tail of the line like a contrail.")]
public readonly byte LineTailAlphaValue = 200;

[Desc("Time to fade out once the trait becomes disabled.")]
public readonly int FadeOutTicks = 1000;

[Desc("Time to fade in once the trait becomes enabled.")]
public readonly int FadeInTicks = 1000;

[Desc("Percentage of the initial particle when enabled and the game start.")]
public readonly int InitialParticlePercentage = 100;

public override object Create(ActorInitializer init) { return new WeatherOverlay(init.World, this); }
}

public class WeatherOverlay : ITick, IRenderAboveWorld, INotifyViewportZoomExtentsChanged
public class WeatherOverlay : ConditionalTrait<WeatherOverlayInfo>, ITick, IRenderAboveWorld, INotifyViewportZoomExtentsChanged
{
readonly struct Particle
{
Expand Down Expand Up @@ -133,23 +142,29 @@ public Particle(in Particle source, float2 pos, int swingDirection, float swingO
}
}

readonly WeatherOverlayInfo info;
readonly World world;
readonly int fadeInTick;
readonly int fadeOutTick;

float windStrength;
int targetWindStrengthIndex;
long windUpdateCountdown;
Particle[] particles;
Size viewportSize;
long lastRender;
bool initialTick = true;
int fadingInTick;
int fadingOutTick;

public WeatherOverlay(World world, WeatherOverlayInfo info)
: base(info)
{
this.info = info;
this.world = world;
targetWindStrengthIndex = info.ChangingWindLevel ? world.LocalRandom.Next(info.WindLevels.Length) : 0;
windUpdateCountdown = world.LocalRandom.Next(info.WindTick[0], info.WindTick[1]);
windStrength = info.WindLevels[targetWindStrengthIndex];
fadeInTick = info.FadeInTicks > 0 ? info.FadeInTicks : 1;
fadeOutTick = info.FadeOutTicks > 0 ? info.FadeOutTicks : 1;
}

void INotifyViewportZoomExtentsChanged.ViewportZoomExtentsChanged(float minZoom, float maxZoom)
Expand All @@ -159,30 +174,60 @@ void INotifyViewportZoomExtentsChanged.ViewportZoomExtentsChanged(float minZoom,
viewportSize = new Size(s.X, s.Y);

// Randomly distribute particles within the initial viewport
var particleCount = viewportSize.Width * viewportSize.Height * info.ParticleDensityFactor / 10000;
var particleCount = viewportSize.Width * viewportSize.Height * Info.ParticleDensityFactor / 10000;
particles = new Particle[particleCount];
var rect = new Rectangle(int2.Zero, viewportSize);
for (var i = 0; i < particles.Length; i++)
particles[i] = new Particle(info, world.LocalRandom, rect);
particles[i] = new Particle(Info, world.LocalRandom, rect);
}

protected override void TraitEnabled(Actor self)
{
if (!initialTick)
fadingInTick = (fadeOutTick - fadingOutTick) * 1000 * fadeInTick / fadeOutTick / 1000;
}

protected override void TraitDisabled(Actor self)
{
if (!initialTick)
fadingOutTick = (fadeInTick - fadingInTick) * 1000 * fadeOutTick / fadeInTick / 1000;
}

void ITick.Tick(Actor self)
{
if (!info.ChangingWindLevel || info.WindLevels.Length == 1)
if (initialTick)
{
initialTick = false;
var initialPercentage = Exts.Clamp(Info.InitialParticlePercentage, 0, 100);
if (IsTraitDisabled)
fadingOutTick = fadeOutTick * (100 - initialPercentage) / 100;
else
fadingInTick = fadeInTick * initialPercentage / 100;
}

if (IsTraitDisabled)
{
if (fadingOutTick < fadeOutTick)
fadingOutTick++;
}
else if (fadingInTick < fadeInTick)
fadingInTick++;

if (!Info.ChangingWindLevel || Info.WindLevels.Length == 1)
return;

if (--windUpdateCountdown <= 0)
{
windUpdateCountdown = self.World.LocalRandom.Next(info.WindTick[0], info.WindTick[1]);
windUpdateCountdown = self.World.LocalRandom.Next(Info.WindTick[0], Info.WindTick[1]);
if (targetWindStrengthIndex > 0 && self.World.LocalRandom.Next(2) == 1)
targetWindStrengthIndex--;
else if (targetWindStrengthIndex < info.WindLevels.Length - 1)
else if (targetWindStrengthIndex < Info.WindLevels.Length - 1)
targetWindStrengthIndex++;
}

// Fading the wind in little steps towards the TargetWindOffset
var targetWindLevel = info.WindLevels[targetWindStrengthIndex];
if (info.InstantWindChanges)
var targetWindLevel = Info.WindLevels[targetWindStrengthIndex];
if (Info.InstantWindChanges)
windStrength = targetWindLevel;
else if (Math.Abs(windStrength - targetWindLevel) > 0.01f)
{
Expand All @@ -205,7 +250,9 @@ void IRenderAboveWorld.RenderAboveWorld(Actor self, WorldRenderer wr)
var tickFraction = Math.Min((runtime - lastRender) * 1f / world.Timestep, 1);
lastRender = runtime;

for (var i = 0; i < particles.Length; i++)
var spawnNum = particles.Length * (IsTraitDisabled ? (fadeOutTick - fadingOutTick) * 1000 / fadeOutTick : fadingInTick * 1000 / fadeInTick) / 1000;

for (var i = 0; i < spawnNum; i++)
{
// Simulate wind and gravity effects on the particle
var p = particles[i];
Expand Down Expand Up @@ -238,7 +285,7 @@ void IRenderAboveWorld.RenderAboveWorld(Actor self, WorldRenderer wr)
// Render the particle
// We must provide a z coordinate to stop the GL near and far Z limits from culling the geometry
var a = new float3(p.Pos.X, p.Pos.Y, p.Pos.Y);
if (info.UseSquares)
if (Info.UseSquares)
{
var b = a + new float2(p.Size, p.Size);
wcr.FillRect(a, b, p.Color);
Expand Down
Loading

0 comments on commit 495fc22

Please sign in to comment.