Implement TS-style terrain lighting.
This commit is contained in:
@@ -442,6 +442,7 @@ namespace OpenRA
|
|||||||
PerfHistory.Items["render_world"].HasNormalTick = false;
|
PerfHistory.Items["render_world"].HasNormalTick = false;
|
||||||
PerfHistory.Items["render_widgets"].HasNormalTick = false;
|
PerfHistory.Items["render_widgets"].HasNormalTick = false;
|
||||||
PerfHistory.Items["render_flip"].HasNormalTick = false;
|
PerfHistory.Items["render_flip"].HasNormalTick = false;
|
||||||
|
PerfHistory.Items["terrain_lighting"].HasNormalTick = false;
|
||||||
|
|
||||||
JoinLocal();
|
JoinLocal();
|
||||||
|
|
||||||
@@ -706,6 +707,7 @@ namespace OpenRA
|
|||||||
PerfHistory.Items["render_world"].Tick();
|
PerfHistory.Items["render_world"].Tick();
|
||||||
PerfHistory.Items["render_widgets"].Tick();
|
PerfHistory.Items["render_widgets"].Tick();
|
||||||
PerfHistory.Items["render_flip"].Tick();
|
PerfHistory.Items["render_flip"].Tick();
|
||||||
|
PerfHistory.Items["terrain_lighting"].Tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Loop()
|
static void Loop()
|
||||||
|
|||||||
@@ -75,7 +75,13 @@ namespace OpenRA.Graphics
|
|||||||
if (ignoreWorldTint)
|
if (ignoreWorldTint)
|
||||||
wsr.DrawSprite(sprite, ScreenPosition(wr), palette, scale * sprite.Size);
|
wsr.DrawSprite(sprite, ScreenPosition(wr), palette, scale * sprite.Size);
|
||||||
else
|
else
|
||||||
wsr.DrawSpriteWithTint(sprite, ScreenPosition(wr), palette, scale * sprite.Size, tint);
|
{
|
||||||
|
var t = tint;
|
||||||
|
if (wr.TerrainLighting != null)
|
||||||
|
t *= wr.TerrainLighting.TintAt(pos);
|
||||||
|
|
||||||
|
wsr.DrawSpriteWithTint(sprite, ScreenPosition(wr), palette, scale * sprite.Size, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenderDebugGeometry(WorldRenderer wr)
|
public void RenderDebugGeometry(WorldRenderer wr)
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ namespace OpenRA.Graphics
|
|||||||
{
|
{
|
||||||
public sealed class TerrainSpriteLayer : IDisposable
|
public sealed class TerrainSpriteLayer : IDisposable
|
||||||
{
|
{
|
||||||
|
static readonly int[] CornerVertexMap = { 0, 1, 2, 2, 3, 0 };
|
||||||
|
|
||||||
public readonly Sheet Sheet;
|
public readonly Sheet Sheet;
|
||||||
public readonly BlendMode BlendMode;
|
public readonly BlendMode BlendMode;
|
||||||
|
|
||||||
@@ -25,6 +27,7 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
readonly IVertexBuffer<Vertex> vertexBuffer;
|
readonly IVertexBuffer<Vertex> vertexBuffer;
|
||||||
readonly Vertex[] vertices;
|
readonly Vertex[] vertices;
|
||||||
|
readonly bool[] ignoreTint;
|
||||||
readonly HashSet<int> dirtyRows = new HashSet<int>();
|
readonly HashSet<int> dirtyRows = new HashSet<int>();
|
||||||
readonly int rowStride;
|
readonly int rowStride;
|
||||||
readonly bool restrictToBounds;
|
readonly bool restrictToBounds;
|
||||||
@@ -50,6 +53,12 @@ namespace OpenRA.Graphics
|
|||||||
emptySprite = new Sprite(sheet, Rectangle.Empty, TextureChannel.Alpha);
|
emptySprite = new Sprite(sheet, Rectangle.Empty, TextureChannel.Alpha);
|
||||||
|
|
||||||
wr.PaletteInvalidated += UpdatePaletteIndices;
|
wr.PaletteInvalidated += UpdatePaletteIndices;
|
||||||
|
|
||||||
|
if (wr.TerrainLighting != null)
|
||||||
|
{
|
||||||
|
ignoreTint = new bool[rowStride * map.MapSize.Y];
|
||||||
|
wr.TerrainLighting.CellChanged += UpdateTint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdatePaletteIndices()
|
void UpdatePaletteIndices()
|
||||||
@@ -59,7 +68,7 @@ namespace OpenRA.Graphics
|
|||||||
for (var i = 0; i < vertices.Length; i++)
|
for (var i = 0; i < vertices.Length; i++)
|
||||||
{
|
{
|
||||||
var v = vertices[i];
|
var v = vertices[i];
|
||||||
vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, new float3(v.R, v.G, v.B));
|
vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, v.R, v.G, v.B);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var row = 0; row < map.MapSize.Y; row++)
|
for (var row = 0; row < map.MapSize.Y; row++)
|
||||||
@@ -68,15 +77,15 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public void Clear(CPos cell)
|
public void Clear(CPos cell)
|
||||||
{
|
{
|
||||||
Update(cell, null);
|
Update(cell, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(CPos cell, ISpriteSequence sequence, int frame)
|
public void Update(CPos cell, ISpriteSequence sequence, int frame)
|
||||||
{
|
{
|
||||||
Update(cell, sequence.GetSprite(frame));
|
Update(cell, sequence.GetSprite(frame), sequence.IgnoreWorldTint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(CPos cell, Sprite sprite)
|
public void Update(CPos cell, Sprite sprite, bool ignoreTint)
|
||||||
{
|
{
|
||||||
var xyz = float3.Zero;
|
var xyz = float3.Zero;
|
||||||
if (sprite != null)
|
if (sprite != null)
|
||||||
@@ -85,10 +94,50 @@ namespace OpenRA.Graphics
|
|||||||
xyz = worldRenderer.Screen3DPosition(cellOrigin) + sprite.Offset - 0.5f * sprite.Size;
|
xyz = worldRenderer.Screen3DPosition(cellOrigin) + sprite.Offset - 0.5f * sprite.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Update(cell.ToMPos(map.Grid.Type), sprite, xyz);
|
Update(cell.ToMPos(map.Grid.Type), sprite, xyz, ignoreTint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(MPos uv, Sprite sprite, float3 pos)
|
void UpdateTint(MPos uv)
|
||||||
|
{
|
||||||
|
var offset = rowStride * uv.V + 6 * uv.U;
|
||||||
|
if (ignoreTint[offset])
|
||||||
|
{
|
||||||
|
var noTint = float3.Ones;
|
||||||
|
for (var i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
var v = vertices[offset + i];
|
||||||
|
vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, noTint);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the terrain tint to vary linearly across the cell to smooth out the staircase effect
|
||||||
|
// This is done by sampling the lighting the corners of the sprite, even though those pixels are
|
||||||
|
// transparent for isometric tiles
|
||||||
|
var tl = worldRenderer.TerrainLighting;
|
||||||
|
var pos = map.CenterOfCell(uv.ToCPos(map));
|
||||||
|
var step = map.Grid.Type == MapGridType.RectangularIsometric ? 724 : 512;
|
||||||
|
var weights = new[]
|
||||||
|
{
|
||||||
|
tl.TintAt(pos + new WVec(-step, -step, 0)),
|
||||||
|
tl.TintAt(pos + new WVec(step, -step, 0)),
|
||||||
|
tl.TintAt(pos + new WVec(step, step, 0)),
|
||||||
|
tl.TintAt(pos + new WVec(-step, step, 0))
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply tint directly to the underlying vertices
|
||||||
|
// This saves us from having to re-query the sprite information, which has not changed
|
||||||
|
for (var i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
var v = vertices[offset + i];
|
||||||
|
vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, palette.TextureIndex, v.C, weights[CornerVertexMap[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
dirtyRows.Add(uv.V);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(MPos uv, Sprite sprite, float3 pos, bool ignoreTint)
|
||||||
{
|
{
|
||||||
if (sprite != null)
|
if (sprite != null)
|
||||||
{
|
{
|
||||||
@@ -108,6 +157,12 @@ namespace OpenRA.Graphics
|
|||||||
var offset = rowStride * uv.V + 6 * uv.U;
|
var offset = rowStride * uv.V + 6 * uv.U;
|
||||||
Util.FastCreateQuad(vertices, pos, sprite, int2.Zero, palette.TextureIndex, offset, sprite.Size, float3.Ones);
|
Util.FastCreateQuad(vertices, pos, sprite, int2.Zero, palette.TextureIndex, offset, sprite.Size, float3.Ones);
|
||||||
|
|
||||||
|
if (worldRenderer.TerrainLighting != null)
|
||||||
|
{
|
||||||
|
this.ignoreTint[offset] = ignoreTint;
|
||||||
|
UpdateTint(uv);
|
||||||
|
}
|
||||||
|
|
||||||
dirtyRows.Add(uv.V);
|
dirtyRows.Add(uv.V);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,6 +204,9 @@ namespace OpenRA.Graphics
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
worldRenderer.PaletteInvalidated -= UpdatePaletteIndices;
|
worldRenderer.PaletteInvalidated -= UpdatePaletteIndices;
|
||||||
|
if (worldRenderer.TerrainLighting != null)
|
||||||
|
worldRenderer.TerrainLighting.CellChanged -= UpdateTint;
|
||||||
|
|
||||||
vertexBuffer.Dispose();
|
vertexBuffer.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace OpenRA.Graphics
|
|||||||
public readonly World World;
|
public readonly World World;
|
||||||
public readonly Theater Theater;
|
public readonly Theater Theater;
|
||||||
public Viewport Viewport { get; private set; }
|
public Viewport Viewport { get; private set; }
|
||||||
|
public readonly ITerrainLighting TerrainLighting;
|
||||||
|
|
||||||
public event Action PaletteInvalidated = null;
|
public event Action PaletteInvalidated = null;
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ namespace OpenRA.Graphics
|
|||||||
palette.Initialize();
|
palette.Initialize();
|
||||||
|
|
||||||
Theater = new Theater(world.Map.Rules.TileSet);
|
Theater = new Theater(world.Map.Rules.TileSet);
|
||||||
|
TerrainLighting = world.WorldActor.TraitOrDefault<ITerrainLighting>();
|
||||||
terrainRenderer = world.WorldActor.TraitOrDefault<IRenderTerrain>();
|
terrainRenderer = world.WorldActor.TraitOrDefault<IRenderTerrain>();
|
||||||
|
|
||||||
debugVis = Exts.Lazy(() => world.WorldActor.TraitOrDefault<DebugVisualizations>());
|
debugVis = Exts.Lazy(() => world.WorldActor.TraitOrDefault<DebugVisualizations>());
|
||||||
|
|||||||
@@ -394,6 +394,13 @@ namespace OpenRA.Traits
|
|||||||
[RequireExplicitImplementation]
|
[RequireExplicitImplementation]
|
||||||
public interface IRenderTerrain { void RenderTerrain(WorldRenderer wr, Viewport viewport); }
|
public interface IRenderTerrain { void RenderTerrain(WorldRenderer wr, Viewport viewport); }
|
||||||
|
|
||||||
|
[RequireExplicitImplementation]
|
||||||
|
public interface ITerrainLighting
|
||||||
|
{
|
||||||
|
event Action<MPos> CellChanged;
|
||||||
|
float3 TintAt(WPos pos);
|
||||||
|
}
|
||||||
|
|
||||||
public interface IRenderAboveShroud
|
public interface IRenderAboveShroud
|
||||||
{
|
{
|
||||||
IEnumerable<IRenderable> RenderAboveShroud(Actor self, WorldRenderer wr);
|
IEnumerable<IRenderable> RenderAboveShroud(Actor self, WorldRenderer wr);
|
||||||
|
|||||||
@@ -144,9 +144,12 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
var sd = shadowOrigin + psb[3];
|
var sd = shadowOrigin + psb[3];
|
||||||
|
|
||||||
var wrsr = Game.Renderer.WorldRgbaSpriteRenderer;
|
var wrsr = Game.Renderer.WorldRgbaSpriteRenderer;
|
||||||
var ti = model.tint;
|
var t = model.tint;
|
||||||
wrsr.DrawSpriteWithTint(renderProxy.ShadowSprite, sa, sb, sc, sd, ti);
|
if (wr.TerrainLighting != null)
|
||||||
wrsr.DrawSpriteWithTint(renderProxy.Sprite, pxOrigin - 0.5f * renderProxy.Sprite.Size, renderProxy.Sprite.Size, ti);
|
t *= wr.TerrainLighting.TintAt(model.pos);
|
||||||
|
|
||||||
|
wrsr.DrawSpriteWithTint(renderProxy.ShadowSprite, sa, sb, sc, sd, t);
|
||||||
|
wrsr.DrawSpriteWithTint(renderProxy.Sprite, pxOrigin - 0.5f * renderProxy.Sprite.Size, renderProxy.Sprite.Size, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenderDebugGeometry(WorldRenderer wr)
|
public void RenderDebugGeometry(WorldRenderer wr)
|
||||||
|
|||||||
67
OpenRA.Mods.Common/Traits/TerrainLightSource.cs
Normal file
67
OpenRA.Mods.Common/Traits/TerrainLightSource.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2020 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, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.Traits
|
||||||
|
{
|
||||||
|
[Desc("Adds a localized circular light centered on the actor to the world's TerrainLightSource trait.")]
|
||||||
|
public class TerrainLightSourceInfo : TraitInfo, INotifyEditorPlacementInfo, IRulesetLoaded, ILobbyCustomRulesIgnore
|
||||||
|
{
|
||||||
|
public readonly WDist Range = WDist.FromCells(10);
|
||||||
|
public readonly float Intensity = 0;
|
||||||
|
public readonly float RedTint = 0;
|
||||||
|
public readonly float GreenTint = 0;
|
||||||
|
public readonly float BlueTint = 0;
|
||||||
|
|
||||||
|
object INotifyEditorPlacementInfo.AddedToEditor(EditorActorPreview preview, World editorWorld)
|
||||||
|
{
|
||||||
|
var tint = new float3(RedTint, GreenTint, BlueTint);
|
||||||
|
return editorWorld.WorldActor.Trait<TerrainLighting>().AddLightSource(preview.CenterPosition, Range, Intensity, tint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void INotifyEditorPlacementInfo.RemovedFromEditor(EditorActorPreview preview, World editorWorld, object data)
|
||||||
|
{
|
||||||
|
editorWorld.WorldActor.Trait<TerrainLighting>().RemoveLightSource((int)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RulesetLoaded(Ruleset rules, ActorInfo ai)
|
||||||
|
{
|
||||||
|
if (!rules.Actors["world"].HasTraitInfo<TerrainLightingInfo>())
|
||||||
|
throw new YamlException("TerrainLightSource can only be used with the world TerrainLighting trait.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object Create(ActorInitializer init) { return new TerrainLightSource(init.Self, this); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class TerrainLightSource : INotifyAddedToWorld, INotifyRemovedFromWorld
|
||||||
|
{
|
||||||
|
readonly TerrainLightSourceInfo info;
|
||||||
|
readonly TerrainLighting terrainLighting;
|
||||||
|
int lightingToken = -1;
|
||||||
|
|
||||||
|
public TerrainLightSource(Actor self, TerrainLightSourceInfo info)
|
||||||
|
{
|
||||||
|
this.info = info;
|
||||||
|
terrainLighting = self.World.WorldActor.Trait<TerrainLighting>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void INotifyAddedToWorld.AddedToWorld(Actor self)
|
||||||
|
{
|
||||||
|
lightingToken = terrainLighting.AddLightSource(self.CenterPosition, info.Range, info.Intensity, new float3(info.RedTint, info.GreenTint, info.BlueTint));
|
||||||
|
}
|
||||||
|
|
||||||
|
void INotifyRemovedFromWorld.RemovedFromWorld(Actor self)
|
||||||
|
{
|
||||||
|
terrainLighting.RemoveLightSource(lightingToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
141
OpenRA.Mods.Common/Traits/TerrainLighting.cs
Normal file
141
OpenRA.Mods.Common/Traits/TerrainLighting.cs
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2020 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, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using OpenRA.Primitives;
|
||||||
|
using OpenRA.Support;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.Traits
|
||||||
|
{
|
||||||
|
[Desc("Add to the world actor to apply a global lighting tint and allow actors using the TerrainLightSource to add localised lighting.")]
|
||||||
|
public class TerrainLightingInfo : TraitInfo, ILobbyCustomRulesIgnore
|
||||||
|
{
|
||||||
|
public readonly float Intensity = 1;
|
||||||
|
public readonly float HeightStep = 0;
|
||||||
|
public readonly float RedTint = 1;
|
||||||
|
public readonly float GreenTint = 1;
|
||||||
|
public readonly float BlueTint = 1;
|
||||||
|
|
||||||
|
[Desc("Size of light source partition bins (cells)")]
|
||||||
|
public readonly int BinSize = 10;
|
||||||
|
|
||||||
|
public override object Create(ActorInitializer init) { return new TerrainLighting(init.World, this); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class TerrainLighting : ITerrainLighting
|
||||||
|
{
|
||||||
|
class LightSource
|
||||||
|
{
|
||||||
|
public readonly WPos Pos;
|
||||||
|
public readonly CPos Cell;
|
||||||
|
public readonly WDist Range;
|
||||||
|
public readonly float Intensity;
|
||||||
|
public readonly float3 Tint;
|
||||||
|
|
||||||
|
public LightSource(WPos pos, CPos cell, WDist range, float intensity, float3 tint)
|
||||||
|
{
|
||||||
|
Pos = pos;
|
||||||
|
Cell = cell;
|
||||||
|
Range = range;
|
||||||
|
Intensity = intensity;
|
||||||
|
Tint = tint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly TerrainLightingInfo info;
|
||||||
|
readonly Map map;
|
||||||
|
readonly Dictionary<int, LightSource> lightSources = new Dictionary<int, LightSource>();
|
||||||
|
readonly SpatiallyPartitioned<LightSource> partitionedLightSources;
|
||||||
|
readonly float3 globalTint;
|
||||||
|
int nextLightSourceToken = 1;
|
||||||
|
|
||||||
|
public event Action<MPos> CellChanged = null;
|
||||||
|
|
||||||
|
public TerrainLighting(World world, TerrainLightingInfo info)
|
||||||
|
{
|
||||||
|
this.info = info;
|
||||||
|
map = world.Map;
|
||||||
|
globalTint = new float3(info.RedTint, info.GreenTint, info.BlueTint);
|
||||||
|
|
||||||
|
var cellSize = map.Grid.Type == MapGridType.RectangularIsometric ? 1448 : 1024;
|
||||||
|
partitionedLightSources = new SpatiallyPartitioned<LightSource>(
|
||||||
|
(map.MapSize.X + 1) * cellSize,
|
||||||
|
(map.MapSize.Y + 1) * cellSize,
|
||||||
|
info.BinSize * cellSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle Bounds(LightSource source)
|
||||||
|
{
|
||||||
|
var c = source.Pos;
|
||||||
|
var r = source.Range.Length;
|
||||||
|
return new Rectangle(c.X - r, c.Y - r, 2 * r, 2 * r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int AddLightSource(WPos pos, WDist range, float intensity, float3 tint)
|
||||||
|
{
|
||||||
|
var token = nextLightSourceToken++;
|
||||||
|
var source = new LightSource(pos, map.CellContaining(pos), range, intensity, tint);
|
||||||
|
var bounds = Bounds(source);
|
||||||
|
lightSources.Add(token, source);
|
||||||
|
partitionedLightSources.Add(source, bounds);
|
||||||
|
|
||||||
|
if (CellChanged != null)
|
||||||
|
foreach (var c in map.FindTilesInCircle(source.Cell, (source.Range.Length + 1023) / 1024))
|
||||||
|
CellChanged(c.ToMPos(map));
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveLightSource(int token)
|
||||||
|
{
|
||||||
|
LightSource source;
|
||||||
|
if (!lightSources.TryGetValue(token, out source))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lightSources.Remove(token);
|
||||||
|
partitionedLightSources.Remove(source);
|
||||||
|
if (CellChanged != null)
|
||||||
|
foreach (var c in map.FindTilesInCircle(source.Cell, (source.Range.Length + 1023) / 1024))
|
||||||
|
CellChanged(c.ToMPos(map));
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 ITerrainLighting.TintAt(WPos pos)
|
||||||
|
{
|
||||||
|
using (new PerfSample("terrain_lighting"))
|
||||||
|
{
|
||||||
|
var uv = map.CellContaining(pos).ToMPos(map);
|
||||||
|
var tint = globalTint;
|
||||||
|
if (!map.Height.Contains(uv))
|
||||||
|
return tint;
|
||||||
|
|
||||||
|
var intensity = info.Intensity + info.HeightStep * map.Height[uv];
|
||||||
|
if (lightSources.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var source in partitionedLightSources.At(new int2(pos.X, pos.Y)))
|
||||||
|
{
|
||||||
|
var range = source.Range.Length;
|
||||||
|
var distance = (source.Pos - pos).Length;
|
||||||
|
if (distance > range)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var falloff = (range - distance) * 1f / range;
|
||||||
|
intensity += falloff * source.Intensity;
|
||||||
|
tint += falloff * source.Tint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intensity * tint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -292,8 +292,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (fogSprite != null)
|
if (fogSprite != null)
|
||||||
fogPos += fogSprite.Offset - 0.5f * fogSprite.Size;
|
fogPos += fogSprite.Offset - 0.5f * fogSprite.Size;
|
||||||
|
|
||||||
shroudLayer.Update(uv, shroudSprite, shroudPos);
|
shroudLayer.Update(uv, shroudSprite, shroudPos, true);
|
||||||
fogLayer.Update(uv, fogSprite, fogPos);
|
fogLayer.Update(uv, fogSprite, fogPos, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
var sprite = theater.TileSprite(tile);
|
var sprite = theater.TileSprite(tile);
|
||||||
foreach (var kv in spriteLayers)
|
foreach (var kv in spriteLayers)
|
||||||
kv.Value.Update(cell, palette == kv.Key ? sprite : null);
|
kv.Value.Update(cell, palette == kv.Key ? sprite : null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRenderTerrain.RenderTerrain(WorldRenderer wr, Viewport viewport)
|
void IRenderTerrain.RenderTerrain(WorldRenderer wr, Viewport viewport)
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ namespace OpenRA.Mods.D2k.Traits
|
|||||||
// Terrain tiles define their origin at the topleft
|
// Terrain tiles define their origin at the topleft
|
||||||
var s = theater.TileSprite(tile.Value);
|
var s = theater.TileSprite(tile.Value);
|
||||||
var ss = new Sprite(s.Sheet, s.Bounds, s.ZRamp, float2.Zero, s.Channel, s.BlendMode);
|
var ss = new Sprite(s.Sheet, s.Bounds, s.ZRamp, float2.Zero, s.Channel, s.BlendMode);
|
||||||
render.Update(kv.Key, ss);
|
render.Update(kv.Key, ss, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
render.Clear(kv.Key);
|
render.Clear(kv.Key);
|
||||||
|
|||||||
Reference in New Issue
Block a user