diff --git a/OpenRA.Game/Graphics/Sheet.cs b/OpenRA.Game/Graphics/Sheet.cs
index 0c56c15bb2..2cb7643afd 100644
--- a/OpenRA.Game/Graphics/Sheet.cs
+++ b/OpenRA.Game/Graphics/Sheet.cs
@@ -49,15 +49,9 @@ namespace OpenRA.Graphics
using (var bitmap = (Bitmap)Image.FromStream(stream))
{
Size = bitmap.Size;
+ data = new byte[4 * Size.Width * Size.Height];
- var dataStride = 4 * Size.Width;
- data = new byte[dataStride * Size.Height];
-
- var bd = bitmap.LockBits(bitmap.Bounds(),
- ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
- for (var y = 0; y < Size.Height; y++)
- Marshal.Copy(IntPtr.Add(bd.Scan0, y * bd.Stride), data, y * dataStride, dataStride);
- bitmap.UnlockBits(bd);
+ Util.FastCopyIntoSprite(new Sprite(this, bitmap.Bounds(), TextureChannel.Red), bitmap);
}
ReleaseBuffer();
diff --git a/OpenRA.Game/Graphics/SpriteFont.cs b/OpenRA.Game/Graphics/SpriteFont.cs
index 8a3c8857c3..804c633b63 100644
--- a/OpenRA.Game/Graphics/SpriteFont.cs
+++ b/OpenRA.Game/Graphics/SpriteFont.cs
@@ -114,6 +114,7 @@ namespace OpenRA.Graphics
// A new bitmap is generated each time this property is accessed, so we do need to dispose it.
using (var bitmap = face.Glyph.Bitmap)
+ {
unsafe
{
var p = (byte*)bitmap.Buffer;
@@ -123,18 +124,23 @@ namespace OpenRA.Graphics
for (var j = 0; j < s.Size.Y; j++)
{
for (var i = 0; i < s.Size.X; i++)
+ {
if (p[i] != 0)
{
var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left);
- dest[q] = c.Second.B;
- dest[q + 1] = c.Second.G;
- dest[q + 2] = c.Second.R;
- dest[q + 3] = p[i];
+ var pmc = Util.PremultiplyAlpha(Color.FromArgb(p[i], c.Second));
+
+ dest[q] = pmc.B;
+ dest[q + 1] = pmc.G;
+ dest[q + 2] = pmc.R;
+ dest[q + 3] = pmc.A;
}
+ }
p += bitmap.Pitch;
}
}
+ }
s.Sheet.CommitBufferedData();
diff --git a/OpenRA.Game/Graphics/Util.cs b/OpenRA.Game/Graphics/Util.cs
index e64c452e80..166f117cea 100644
--- a/OpenRA.Game/Graphics/Util.cs
+++ b/OpenRA.Game/Graphics/Util.cs
@@ -73,18 +73,37 @@ namespace OpenRA.Graphics
try
{
- var data = dest.Sheet.GetData();
- var dataStride = dest.Sheet.Size.Width * 4;
- var x = dest.Bounds.Left * 4;
- var width = dest.Bounds.Width * 4;
- var y = dest.Bounds.Top;
+ var destData = dest.Sheet.GetData();
+ var destStride = dest.Sheet.Size.Width;
+ var width = dest.Bounds.Width;
var height = dest.Bounds.Height;
- var bd = src.LockBits(src.Bounds(),
- ImageLockMode.ReadWrite, src.PixelFormat);
- for (var row = 0; row < height; row++)
- Marshal.Copy(IntPtr.Add(bd.Scan0, row * bd.Stride), data, (y + row) * dataStride + x, width);
- src.UnlockBits(bd);
+ var srcData = src.LockBits(src.Bounds(),
+ ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
+
+ unsafe
+ {
+ var c = (int*)srcData.Scan0;
+
+ // Cast the data to an int array so we can copy the src data directly
+ fixed (byte* bd = &destData[0])
+ {
+ var data = (int*)bd;
+ var x = dest.Bounds.Left;
+ var y = dest.Bounds.Top;
+
+ for (var j = 0; j < height; j++)
+ {
+ for (var i = 0; i < width; i++)
+ {
+ var cc = Color.FromArgb(*(c + (j * srcData.Stride >> 2) + i));
+ data[(y + j) * destStride + x + i] = PremultiplyAlpha(cc).ToArgb();
+ }
+ }
+ }
+ }
+
+ src.UnlockBits(srcData);
}
finally
{
@@ -93,6 +112,12 @@ namespace OpenRA.Graphics
}
}
+ public static Color PremultiplyAlpha(Color c)
+ {
+ var a = c.A / 255f;
+ return Color.FromArgb(c.A, (byte)(c.R * a + 0.5f), (byte)(c.G * a + 0.5f), (byte)(c.B * a + 0.5f));
+ }
+
public static float[] IdentityMatrix()
{
return Exts.MakeArray(16, j => (j % 5 == 0) ? 1.0f : 0);
diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index cc1b29a043..a7ddefc2a4 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -643,6 +643,7 @@
+
diff --git a/OpenRA.Mods.Common/Traits/World/PaletteFromPaletteWithAlpha.cs b/OpenRA.Mods.Common/Traits/World/PaletteFromPaletteWithAlpha.cs
new file mode 100644
index 0000000000..b6b9de1027
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/World/PaletteFromPaletteWithAlpha.cs
@@ -0,0 +1,76 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2015 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.Collections.Generic;
+using System.Drawing;
+using OpenRA.Graphics;
+using OpenRA.Mods.Common.Traits;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.D2k.Traits
+{
+ [Desc("Create a palette by applying alpha transparency to another palette.")]
+ class PaletteFromPaletteWithAlphaInfo : ITraitInfo
+ {
+ [Desc("Internal palette name")]
+ public readonly string Name = null;
+
+ [Desc("The name of the palette to base off.")]
+ public readonly string BasePalette = null;
+
+ [Desc("Allow palette modifiers to change the palette.")]
+ public readonly bool AllowModifiers = true;
+
+ [Desc("Alpha component that is applied to the base palette.")]
+ public readonly float Alpha = 1.0f;
+
+ [Desc("Premultiply color by the alpha component.")]
+ public readonly bool Premultiply = true;
+
+ public object Create(ActorInitializer init) { return new PaletteFromPaletteWithAlpha(this); }
+ }
+
+ class PaletteFromPaletteWithAlpha : ILoadsPalettes, IProvidesAssetBrowserPalettes
+ {
+ readonly PaletteFromPaletteWithAlphaInfo info;
+
+ public PaletteFromPaletteWithAlpha(PaletteFromPaletteWithAlphaInfo info) { this.info = info; }
+
+ public void LoadPalettes(WorldRenderer wr)
+ {
+ var remap = new AlphaPaletteRemap(info.Alpha, info.Premultiply);
+ wr.AddPalette(info.Name, new ImmutablePalette(wr.Palette(info.BasePalette).Palette, remap), info.AllowModifiers);
+ }
+
+ public IEnumerable PaletteNames { get { yield return info.Name; } }
+ }
+
+ class AlphaPaletteRemap : IPaletteRemap
+ {
+ readonly float alpha;
+ readonly bool premultiply;
+
+ public AlphaPaletteRemap(float alpha, bool premultiply)
+ {
+ this.alpha = alpha;
+ this.premultiply = premultiply;
+ }
+
+ public Color GetRemappedColor(Color original, int index)
+ {
+ var a = (int)(original.A * alpha).Clamp(0, 255);
+ var r = premultiply ? (int)(alpha * original.R + 0.5f).Clamp(0, 255) : original.R;
+ var g = premultiply ? (int)(alpha * original.G + 0.5f).Clamp(0, 255) : original.G;
+ var b = premultiply ? (int)(alpha * original.B + 0.5f).Clamp(0, 255) : original.B;
+
+ return Color.FromArgb(a, r, g, b);
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/Traits/World/PaletteFromRGBA.cs b/OpenRA.Mods.Common/Traits/World/PaletteFromRGBA.cs
index 055ee5944a..ecdf275618 100644
--- a/OpenRA.Mods.Common/Traits/World/PaletteFromRGBA.cs
+++ b/OpenRA.Mods.Common/Traits/World/PaletteFromRGBA.cs
@@ -8,6 +8,7 @@
*/
#endregion
+using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -50,7 +51,11 @@ namespace OpenRA.Mods.Common.Traits
if (info.Tileset != null && info.Tileset.ToLowerInvariant() != world.Map.Tileset.ToLowerInvariant())
return;
- var c = (uint)((info.A << 24) | (info.R << 16) | (info.G << 8) | info.B);
+ var a = info.A / 255f;
+ var r = (int)(a * info.R + 0.5f).Clamp(0, 255);
+ var g = (int)(a * info.G + 0.5f).Clamp(0, 255);
+ var b = (int)(a * info.B + 0.5f).Clamp(0, 255);
+ var c = (uint)Color.FromArgb(info.A, r, g, b).ToArgb();
wr.AddPalette(info.Name, new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => (i == 0) ? 0 : c)), info.AllowModifiers);
}
}
diff --git a/OpenRA.Mods.Common/Traits/World/ShroudPalette.cs b/OpenRA.Mods.Common/Traits/World/ShroudPalette.cs
index eca4002cbb..98810c6be1 100644
--- a/OpenRA.Mods.Common/Traits/World/ShroudPalette.cs
+++ b/OpenRA.Mods.Common/Traits/World/ShroudPalette.cs
@@ -42,8 +42,8 @@ namespace OpenRA.Mods.Common.Traits
static readonly Color[] Fog = new[]
{
- Color.Transparent, Color.Green,
- Color.Blue, Color.Yellow,
+ Color.FromArgb(0, 0, 0, 0),
+ Color.Green, Color.Blue, Color.Yellow,
Color.FromArgb(128, 0, 0, 0),
Color.FromArgb(96, 0, 0, 0),
Color.FromArgb(64, 0, 0, 0),
@@ -52,8 +52,8 @@ namespace OpenRA.Mods.Common.Traits
static readonly Color[] Shroud = new[]
{
- Color.Transparent, Color.Green,
- Color.Blue, Color.Yellow,
+ Color.FromArgb(0, 0, 0, 0),
+ Color.Green, Color.Blue, Color.Yellow,
Color.Black,
Color.FromArgb(160, 0, 0, 0),
Color.FromArgb(128, 0, 0, 0),
diff --git a/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs b/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs
index b9b1c9142f..691ba5b972 100755
--- a/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs
+++ b/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs
@@ -259,7 +259,7 @@ namespace OpenRA.Renderer.Sdl2
case BlendMode.Alpha:
GL.Enable(EnableCap.Blend);
ErrorHandler.CheckGlError();
- GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
+ GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
break;
case BlendMode.Additive:
GL.Enable(EnableCap.Blend);
diff --git a/mods/d2k/rules/palettes.yaml b/mods/d2k/rules/palettes.yaml
index fca79be2d3..c6b67f8d35 100644
--- a/mods/d2k/rules/palettes.yaml
+++ b/mods/d2k/rules/palettes.yaml
@@ -49,6 +49,14 @@
G: 0
B: 0
A: 180
+ PaletteFromPaletteWithAlpha@effect75alpha:
+ Name: effect75alpha
+ BasePalette: effect
+ Alpha: 0.75
+ PaletteFromPaletteWithAlpha@effect50alpha:
+ Name: effect50alpha
+ BasePalette: effect
+ Alpha: 0.5
PaletteFromScaledPalette@starportlights:
Name: starportlights
BasePalette: d2k
diff --git a/mods/d2k/rules/vehicles.yaml b/mods/d2k/rules/vehicles.yaml
index 1c178d084d..cb4e740af6 100644
--- a/mods/d2k/rules/vehicles.yaml
+++ b/mods/d2k/rules/vehicles.yaml
@@ -81,6 +81,7 @@ harvester:
LeavesHusk:
HuskActor: Harvester.Husk
WithHarvestAnimation:
+ Palette: effect50alpha
AttractsWorms:
Intensity: 700
diff --git a/mods/d2k/sequences/misc.yaml b/mods/d2k/sequences/misc.yaml
index 6cfa4c58fa..7952651246 100644
--- a/mods/d2k/sequences/misc.yaml
+++ b/mods/d2k/sequences/misc.yaml
@@ -71,30 +71,24 @@ small_trail:
Start: 3735
Length: 4
Tick: 80
- BlendMode: SoftAdditive
small_trail2:
idle: DATA.R8
Start: 3540
Length: 4
Tick: 80
- BlendMode: SoftAdditive
bazooka_trail:
idle: DATA.R8
Start: 3381
Length: 4
Tick: 80
- BlendMode: Translucency
- Alpha: 0.75
bazooka_trail2:
idle: DATA.R8
Start: 3544
Length: 4
Tick: 80
- BlendMode: Translucency
- Alpha: 0.75
deviator_trail:
idle: DATA.R8
diff --git a/mods/d2k/sequences/vehicles.yaml b/mods/d2k/sequences/vehicles.yaml
index 9b2357e6f5..75bab9d93b 100644
--- a/mods/d2k/sequences/vehicles.yaml
+++ b/mods/d2k/sequences/vehicles.yaml
@@ -23,7 +23,6 @@ harvester:
Tick: 80
ZOffset: 1
BlendMode: Multiply
- Alpha: 0.5
dock: DATA.R8
Start: 3370
Length: 10
diff --git a/mods/d2k/weapons.yaml b/mods/d2k/weapons.yaml
index f041ede50a..107f3f76d8 100644
--- a/mods/d2k/weapons.yaml
+++ b/mods/d2k/weapons.yaml
@@ -34,6 +34,7 @@ Bazooka:
Image: RPG
RateOfTurn: 5
Trail: bazooka_trail
+ TrailPalette: effect75alpha
TrailInterval: 1
RangeLimit: 35
Warhead@1Dam: SpreadDamage
@@ -193,6 +194,7 @@ QuadRockets:
Image: RPG
RateOfTurn: 10
Trail: bazooka_trail2
+ TrailPalette: effect75alpha
TrailInterval: 1
Speed: 256
RangeLimit: 40
diff --git a/mods/ts/rules/palettes.yaml b/mods/ts/rules/palettes.yaml
index bc35356e18..013ae575cf 100644
--- a/mods/ts/rules/palettes.yaml
+++ b/mods/ts/rules/palettes.yaml
@@ -73,6 +73,10 @@
G: 0
B: 0
A: 180
+ PaletteFromPaletteWithAlpha@placebuilding:
+ Name: placebuilding
+ BasePalette: ra
+ Alpha: 0.75
TSShroudPalette@shroud:
Type: Shroud
VoxelNormalsPalette@normals:
diff --git a/mods/ts/rules/player.yaml b/mods/ts/rules/player.yaml
index 10d090501d..65af07b43e 100644
--- a/mods/ts/rules/player.yaml
+++ b/mods/ts/rules/player.yaml
@@ -30,7 +30,7 @@ Player:
LowPowerSlowdown: 3
SpeedUp: True
PlaceBuilding:
- Palette: ra
+ Palette: placebuilding
SupportPowerManager:
ScriptTriggers:
MissionObjectives:
diff --git a/mods/ts/sequences/misc.yaml b/mods/ts/sequences/misc.yaml
index 678e141e28..9d23320193 100644
--- a/mods/ts/sequences/misc.yaml
+++ b/mods/ts/sequences/misc.yaml
@@ -1,8 +1,6 @@
overlay:
Defaults: place
Offset: 0, -12
- BlendMode: Translucency
- Alpha: 0.75
build-valid-snow:
build-valid-temperat:
build-invalid:
@@ -114,10 +112,10 @@ explosion:
Length: *
building: twlt070
ionring: ring1
- BlendMode: SoftAdditive
+ BlendMode: Additive
Tick: 120
pulse_explosion: pulsefx2
- BlendMode: SoftAdditive
+ BlendMode: Additive
Tick: 80
small_watersplash: h2o_exp2
large_watersplash: h2o_exp1