Use premultiplied alpha for all textures and blending.

This commit is contained in:
Paul Chote
2015-05-16 17:49:17 +01:00
parent 78f1e9fb2f
commit 26fd858fc7
16 changed files with 153 additions and 40 deletions

View File

@@ -49,15 +49,9 @@ namespace OpenRA.Graphics
using (var bitmap = (Bitmap)Image.FromStream(stream)) using (var bitmap = (Bitmap)Image.FromStream(stream))
{ {
Size = bitmap.Size; Size = bitmap.Size;
data = new byte[4 * Size.Width * Size.Height];
var dataStride = 4 * Size.Width; Util.FastCopyIntoSprite(new Sprite(this, bitmap.Bounds(), TextureChannel.Red), bitmap);
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);
} }
ReleaseBuffer(); ReleaseBuffer();

View File

@@ -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. // A new bitmap is generated each time this property is accessed, so we do need to dispose it.
using (var bitmap = face.Glyph.Bitmap) using (var bitmap = face.Glyph.Bitmap)
{
unsafe unsafe
{ {
var p = (byte*)bitmap.Buffer; var p = (byte*)bitmap.Buffer;
@@ -123,18 +124,23 @@ namespace OpenRA.Graphics
for (var j = 0; j < s.Size.Y; j++) for (var j = 0; j < s.Size.Y; j++)
{ {
for (var i = 0; i < s.Size.X; i++) for (var i = 0; i < s.Size.X; i++)
{
if (p[i] != 0) if (p[i] != 0)
{ {
var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left); var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left);
dest[q] = c.Second.B; var pmc = Util.PremultiplyAlpha(Color.FromArgb(p[i], c.Second));
dest[q + 1] = c.Second.G;
dest[q + 2] = c.Second.R; dest[q] = pmc.B;
dest[q + 3] = p[i]; dest[q + 1] = pmc.G;
dest[q + 2] = pmc.R;
dest[q + 3] = pmc.A;
} }
}
p += bitmap.Pitch; p += bitmap.Pitch;
} }
} }
}
s.Sheet.CommitBufferedData(); s.Sheet.CommitBufferedData();

View File

@@ -73,18 +73,37 @@ namespace OpenRA.Graphics
try try
{ {
var data = dest.Sheet.GetData(); var destData = dest.Sheet.GetData();
var dataStride = dest.Sheet.Size.Width * 4; var destStride = dest.Sheet.Size.Width;
var x = dest.Bounds.Left * 4; var width = dest.Bounds.Width;
var width = dest.Bounds.Width * 4;
var y = dest.Bounds.Top;
var height = dest.Bounds.Height; var height = dest.Bounds.Height;
var bd = src.LockBits(src.Bounds(), var srcData = src.LockBits(src.Bounds(),
ImageLockMode.ReadWrite, src.PixelFormat); ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
for (var row = 0; row < height; row++)
Marshal.Copy(IntPtr.Add(bd.Scan0, row * bd.Stride), data, (y + row) * dataStride + x, width); unsafe
src.UnlockBits(bd); {
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 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() public static float[] IdentityMatrix()
{ {
return Exts.MakeArray(16, j => (j % 5 == 0) ? 1.0f : 0); return Exts.MakeArray(16, j => (j % 5 == 0) ? 1.0f : 0);

View File

@@ -643,6 +643,7 @@
<Compile Include="Traits\World\EditorActorPreview.cs" /> <Compile Include="Traits\World\EditorActorPreview.cs" />
<Compile Include="Traits\World\EditorResourceLayer.cs" /> <Compile Include="Traits\World\EditorResourceLayer.cs" />
<Compile Include="Widgets\EditorViewportControllerWidget.cs" /> <Compile Include="Widgets\EditorViewportControllerWidget.cs" />
<Compile Include="Traits\World\PaletteFromPaletteWithAlpha.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>

View File

@@ -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<string> 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);
}
}
}

View File

@@ -8,6 +8,7 @@
*/ */
#endregion #endregion
using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
@@ -50,7 +51,11 @@ namespace OpenRA.Mods.Common.Traits
if (info.Tileset != null && info.Tileset.ToLowerInvariant() != world.Map.Tileset.ToLowerInvariant()) if (info.Tileset != null && info.Tileset.ToLowerInvariant() != world.Map.Tileset.ToLowerInvariant())
return; 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); wr.AddPalette(info.Name, new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => (i == 0) ? 0 : c)), info.AllowModifiers);
} }
} }

View File

@@ -42,8 +42,8 @@ namespace OpenRA.Mods.Common.Traits
static readonly Color[] Fog = new[] static readonly Color[] Fog = new[]
{ {
Color.Transparent, Color.Green, Color.FromArgb(0, 0, 0, 0),
Color.Blue, Color.Yellow, Color.Green, Color.Blue, Color.Yellow,
Color.FromArgb(128, 0, 0, 0), Color.FromArgb(128, 0, 0, 0),
Color.FromArgb(96, 0, 0, 0), Color.FromArgb(96, 0, 0, 0),
Color.FromArgb(64, 0, 0, 0), Color.FromArgb(64, 0, 0, 0),
@@ -52,8 +52,8 @@ namespace OpenRA.Mods.Common.Traits
static readonly Color[] Shroud = new[] static readonly Color[] Shroud = new[]
{ {
Color.Transparent, Color.Green, Color.FromArgb(0, 0, 0, 0),
Color.Blue, Color.Yellow, Color.Green, Color.Blue, Color.Yellow,
Color.Black, Color.Black,
Color.FromArgb(160, 0, 0, 0), Color.FromArgb(160, 0, 0, 0),
Color.FromArgb(128, 0, 0, 0), Color.FromArgb(128, 0, 0, 0),

View File

@@ -259,7 +259,7 @@ namespace OpenRA.Renderer.Sdl2
case BlendMode.Alpha: case BlendMode.Alpha:
GL.Enable(EnableCap.Blend); GL.Enable(EnableCap.Blend);
ErrorHandler.CheckGlError(); ErrorHandler.CheckGlError();
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);
break; break;
case BlendMode.Additive: case BlendMode.Additive:
GL.Enable(EnableCap.Blend); GL.Enable(EnableCap.Blend);

View File

@@ -49,6 +49,14 @@
G: 0 G: 0
B: 0 B: 0
A: 180 A: 180
PaletteFromPaletteWithAlpha@effect75alpha:
Name: effect75alpha
BasePalette: effect
Alpha: 0.75
PaletteFromPaletteWithAlpha@effect50alpha:
Name: effect50alpha
BasePalette: effect
Alpha: 0.5
PaletteFromScaledPalette@starportlights: PaletteFromScaledPalette@starportlights:
Name: starportlights Name: starportlights
BasePalette: d2k BasePalette: d2k

View File

@@ -81,6 +81,7 @@ harvester:
LeavesHusk: LeavesHusk:
HuskActor: Harvester.Husk HuskActor: Harvester.Husk
WithHarvestAnimation: WithHarvestAnimation:
Palette: effect50alpha
AttractsWorms: AttractsWorms:
Intensity: 700 Intensity: 700

View File

@@ -71,30 +71,24 @@ small_trail:
Start: 3735 Start: 3735
Length: 4 Length: 4
Tick: 80 Tick: 80
BlendMode: SoftAdditive
small_trail2: small_trail2:
idle: DATA.R8 idle: DATA.R8
Start: 3540 Start: 3540
Length: 4 Length: 4
Tick: 80 Tick: 80
BlendMode: SoftAdditive
bazooka_trail: bazooka_trail:
idle: DATA.R8 idle: DATA.R8
Start: 3381 Start: 3381
Length: 4 Length: 4
Tick: 80 Tick: 80
BlendMode: Translucency
Alpha: 0.75
bazooka_trail2: bazooka_trail2:
idle: DATA.R8 idle: DATA.R8
Start: 3544 Start: 3544
Length: 4 Length: 4
Tick: 80 Tick: 80
BlendMode: Translucency
Alpha: 0.75
deviator_trail: deviator_trail:
idle: DATA.R8 idle: DATA.R8

View File

@@ -23,7 +23,6 @@ harvester:
Tick: 80 Tick: 80
ZOffset: 1 ZOffset: 1
BlendMode: Multiply BlendMode: Multiply
Alpha: 0.5
dock: DATA.R8 dock: DATA.R8
Start: 3370 Start: 3370
Length: 10 Length: 10

View File

@@ -34,6 +34,7 @@ Bazooka:
Image: RPG Image: RPG
RateOfTurn: 5 RateOfTurn: 5
Trail: bazooka_trail Trail: bazooka_trail
TrailPalette: effect75alpha
TrailInterval: 1 TrailInterval: 1
RangeLimit: 35 RangeLimit: 35
Warhead@1Dam: SpreadDamage Warhead@1Dam: SpreadDamage
@@ -193,6 +194,7 @@ QuadRockets:
Image: RPG Image: RPG
RateOfTurn: 10 RateOfTurn: 10
Trail: bazooka_trail2 Trail: bazooka_trail2
TrailPalette: effect75alpha
TrailInterval: 1 TrailInterval: 1
Speed: 256 Speed: 256
RangeLimit: 40 RangeLimit: 40

View File

@@ -73,6 +73,10 @@
G: 0 G: 0
B: 0 B: 0
A: 180 A: 180
PaletteFromPaletteWithAlpha@placebuilding:
Name: placebuilding
BasePalette: ra
Alpha: 0.75
TSShroudPalette@shroud: TSShroudPalette@shroud:
Type: Shroud Type: Shroud
VoxelNormalsPalette@normals: VoxelNormalsPalette@normals:

View File

@@ -30,7 +30,7 @@ Player:
LowPowerSlowdown: 3 LowPowerSlowdown: 3
SpeedUp: True SpeedUp: True
PlaceBuilding: PlaceBuilding:
Palette: ra Palette: placebuilding
SupportPowerManager: SupportPowerManager:
ScriptTriggers: ScriptTriggers:
MissionObjectives: MissionObjectives:

View File

@@ -1,8 +1,6 @@
overlay: overlay:
Defaults: place Defaults: place
Offset: 0, -12 Offset: 0, -12
BlendMode: Translucency
Alpha: 0.75
build-valid-snow: build-valid-snow:
build-valid-temperat: build-valid-temperat:
build-invalid: build-invalid:
@@ -114,10 +112,10 @@ explosion:
Length: * Length: *
building: twlt070 building: twlt070
ionring: ring1 ionring: ring1
BlendMode: SoftAdditive BlendMode: Additive
Tick: 120 Tick: 120
pulse_explosion: pulsefx2 pulse_explosion: pulsefx2
BlendMode: SoftAdditive BlendMode: Additive
Tick: 80 Tick: 80
small_watersplash: h2o_exp2 small_watersplash: h2o_exp2
large_watersplash: h2o_exp1 large_watersplash: h2o_exp1