From 985bc16e31e45f1609f76dc91b979c7455e68c81 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Mon, 19 Oct 2009 18:19:43 +1300 Subject: [PATCH] palette matching tool --- OpenRa.sln | 88 ++++++++++++++++++++++++ PaletteMatch/PaletteMatch.csproj | 66 ++++++++++++++++++ PaletteMatch/Program.cs | 71 +++++++++++++++++++ PaletteMatch/Properties/AssemblyInfo.cs | 36 ++++++++++ tdbits/a10.shp | Bin 0 -> 14822 bytes tdbits/a10icnh.win | Bin 0 -> 1914 bytes tdbits/winter.pal | Bin 0 -> 768 bytes 7 files changed, 261 insertions(+) create mode 100644 PaletteMatch/PaletteMatch.csproj create mode 100644 PaletteMatch/Program.cs create mode 100644 PaletteMatch/Properties/AssemblyInfo.cs create mode 100644 tdbits/a10.shp create mode 100644 tdbits/a10icnh.win create mode 100644 tdbits/winter.pal diff --git a/OpenRa.sln b/OpenRa.sln index 1ef2b24136..39f8228def 100644 --- a/OpenRa.sln +++ b/OpenRa.sln @@ -9,28 +9,116 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRa.DataStructures", "Op EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaletteUsage", "PaletteUsage\PaletteUsage.csproj", "{54577061-E2D2-4336-90A2-A9A7106A30CD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PaletteMatch", "PaletteMatch\PaletteMatch.csproj", "{31411761-224C-4C54-A5FE-280890A70259}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug (x86)|Any CPU = Debug (x86)|Any CPU + Debug (x86)|Mixed Platforms = Debug (x86)|Mixed Platforms Debug (x86)|Win32 = Debug (x86)|Win32 + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Release (x86)|Any CPU = Release (x86)|Any CPU + Release (x86)|Mixed Platforms = Release (x86)|Mixed Platforms Release (x86)|Win32 = Release (x86)|Win32 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug (x86)|Any CPU.ActiveCfg = Debug|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug (x86)|Mixed Platforms.ActiveCfg = Debug|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug (x86)|Mixed Platforms.Build.0 = Debug|x86 {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug (x86)|Win32.ActiveCfg = Debug|x86 {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug (x86)|Win32.Build.0 = Debug|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug|Any CPU.ActiveCfg = Debug|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Debug|Win32.ActiveCfg = Debug|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release (x86)|Any CPU.ActiveCfg = Release|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release (x86)|Mixed Platforms.ActiveCfg = Release|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release (x86)|Mixed Platforms.Build.0 = Release|x86 {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release (x86)|Win32.ActiveCfg = Release|x86 {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release (x86)|Win32.Build.0 = Release|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release|Any CPU.ActiveCfg = Release|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release|Mixed Platforms.Build.0 = Release|x86 + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA}.Release|Win32.ActiveCfg = Release|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug (x86)|Any CPU.ActiveCfg = Debug|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug (x86)|Mixed Platforms.ActiveCfg = Debug|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug (x86)|Mixed Platforms.Build.0 = Debug|x86 {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug (x86)|Win32.ActiveCfg = Debug|x86 {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug (x86)|Win32.Build.0 = Debug|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug|Any CPU.ActiveCfg = Debug|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Debug|Win32.ActiveCfg = Debug|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release (x86)|Any CPU.ActiveCfg = Release|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release (x86)|Mixed Platforms.ActiveCfg = Release|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release (x86)|Mixed Platforms.Build.0 = Release|x86 {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release (x86)|Win32.ActiveCfg = Release|x86 {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release (x86)|Win32.Build.0 = Release|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release|Any CPU.ActiveCfg = Release|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release|Mixed Platforms.Build.0 = Release|x86 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633}.Release|Win32.ActiveCfg = Release|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug (x86)|Any CPU.ActiveCfg = Debug|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug (x86)|Mixed Platforms.ActiveCfg = Debug|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug (x86)|Mixed Platforms.Build.0 = Debug|x86 {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug (x86)|Win32.ActiveCfg = Debug|x86 {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug (x86)|Win32.Build.0 = Debug|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug|Any CPU.ActiveCfg = Debug|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Debug|Win32.ActiveCfg = Debug|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release (x86)|Any CPU.ActiveCfg = Release|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release (x86)|Mixed Platforms.ActiveCfg = Release|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release (x86)|Mixed Platforms.Build.0 = Release|x86 {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release (x86)|Win32.ActiveCfg = Release|x86 {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release (x86)|Win32.Build.0 = Release|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release|Any CPU.ActiveCfg = Release|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release|Mixed Platforms.Build.0 = Release|x86 + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073}.Release|Win32.ActiveCfg = Release|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug (x86)|Any CPU.ActiveCfg = Debug|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug (x86)|Mixed Platforms.ActiveCfg = Debug|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug (x86)|Mixed Platforms.Build.0 = Debug|x86 {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug (x86)|Win32.ActiveCfg = Debug|x86 {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug (x86)|Win32.Build.0 = Debug|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug|Any CPU.ActiveCfg = Debug|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Debug|Win32.ActiveCfg = Debug|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release (x86)|Any CPU.ActiveCfg = Release|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release (x86)|Mixed Platforms.ActiveCfg = Release|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release (x86)|Mixed Platforms.Build.0 = Release|x86 {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release (x86)|Win32.ActiveCfg = Release|x86 {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release (x86)|Win32.Build.0 = Release|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release|Any CPU.ActiveCfg = Release|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release|Mixed Platforms.Build.0 = Release|x86 + {54577061-E2D2-4336-90A2-A9A7106A30CD}.Release|Win32.ActiveCfg = Release|x86 + {31411761-224C-4C54-A5FE-280890A70259}.Debug (x86)|Any CPU.ActiveCfg = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug (x86)|Any CPU.Build.0 = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug (x86)|Mixed Platforms.ActiveCfg = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug (x86)|Mixed Platforms.Build.0 = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug (x86)|Win32.ActiveCfg = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug|Any CPU.Build.0 = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Debug|Win32.ActiveCfg = Debug|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release (x86)|Any CPU.ActiveCfg = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release (x86)|Any CPU.Build.0 = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release (x86)|Mixed Platforms.ActiveCfg = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release (x86)|Mixed Platforms.Build.0 = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release (x86)|Win32.ActiveCfg = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release|Any CPU.ActiveCfg = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release|Any CPU.Build.0 = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {31411761-224C-4C54-A5FE-280890A70259}.Release|Win32.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PaletteMatch/PaletteMatch.csproj b/PaletteMatch/PaletteMatch.csproj new file mode 100644 index 0000000000..4b973ee838 --- /dev/null +++ b/PaletteMatch/PaletteMatch.csproj @@ -0,0 +1,66 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {31411761-224C-4C54-A5FE-280890A70259} + Exe + Properties + PaletteMatch + PaletteMatch + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + 3.5 + + + + 3.5 + + + 3.5 + + + + + + + + + + + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA} + OpenRa.FileFormats + + + + + \ No newline at end of file diff --git a/PaletteMatch/Program.cs b/PaletteMatch/Program.cs new file mode 100644 index 0000000000..ab6ba92dee --- /dev/null +++ b/PaletteMatch/Program.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using OpenRa.FileFormats; +using System.Drawing; + +namespace PaletteMatch +{ + /* a simple little hack to work out a sane matching between TD and RA palettes (or, indeed, from RA -> RA) */ + /* usage: PaletteMatch srcpal destpal */ + + static class Program + { + static void Main(string[] args) + { + var tdPalette = WithStream(args[0], s => new Palette(s)); + var raPalette = WithStream(args[1], s => new Palette(s)); + + var ms = tdPalette.Entries().Select( + (a, i) => new + { + Src = i, + Dest = raPalette.Entries().Select( + (b, j) => new { Color = b, Index = j }) + .OrderBy(x => x.Color, new ColorDistanceComparer(a)).First().Index + }); + + foreach( var m in ms ) + Console.WriteLine("{0:x2} -> {1:x2}", m.Src, m.Dest); + } + + static IEnumerable Entries(this Palette p) + { + for (var i = 0; i < 256; i++) + yield return p.GetColor(i); + } + + static T WithStream(string filename, Func f) + { + using (var s = File.OpenRead(filename)) + return f(s); + } + } + + class ColorDistanceComparer : IComparer + { + readonly Color r; + + public ColorDistanceComparer(Color r) + { + this.r = r; + } + + float Distance(Color a) + { + var b = a.GetBrightness() - r.GetBrightness(); + var h = a.GetHue() - r.GetHue(); + var s = a.GetSaturation() - r.GetSaturation(); + + return b * b + h * h + s * s; + } + + public int Compare(Color x, Color y) + { + return Math.Sign(Distance(x) - Distance(y)); + } + } + +} diff --git a/PaletteMatch/Properties/AssemblyInfo.cs b/PaletteMatch/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..2f6ead4761 --- /dev/null +++ b/PaletteMatch/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PaletteMatch")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PaletteMatch")] +[assembly: AssemblyCopyright("Copyright © 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("eb944988-f387-46a5-bb5b-392d482df964")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tdbits/a10.shp b/tdbits/a10.shp new file mode 100644 index 0000000000000000000000000000000000000000..71b4dbd85d4cfdad376d978d9fda4e636a747d6c GIT binary patch literal 14822 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

hSG>gq;<%=rTpkwtq-0vU=#dfo)yu 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 Uw2x<|3b3Z(p@ohAvZw6{xH*7qmWp I9#Mb7e|Zy6uK)l5 literal 0 HcmV?d00001