1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System;
13 using System.Collections.Generic;
14 using System.IO;
15 using OpenRA.Primitives;
16 
17 namespace OpenRA.Graphics
18 {
19 	public interface IPalette
20 	{
21 		uint this[int index] { get; }
CopyToArray(Array destination, int destinationOffset)22 		void CopyToArray(Array destination, int destinationOffset);
23 	}
24 
GetRemappedColor(Color original, int index)25 	public interface IPaletteRemap { Color GetRemappedColor(Color original, int index); }
26 
27 	public static class Palette
28 	{
29 		public const int Size = 256;
30 
GetColor(this IPalette palette, int index)31 		public static Color GetColor(this IPalette palette, int index)
32 		{
33 			return Color.FromArgb((int)palette[index]);
34 		}
35 
AsReadOnly(this IPalette palette)36 		public static IPalette AsReadOnly(this IPalette palette)
37 		{
38 			if (palette is ImmutablePalette)
39 				return palette;
40 			return new ReadOnlyPalette(palette);
41 		}
42 
43 		class ReadOnlyPalette : IPalette
44 		{
45 			IPalette palette;
ReadOnlyPalette(IPalette palette)46 			public ReadOnlyPalette(IPalette palette) { this.palette = palette; }
47 			public uint this[int index] { get { return palette[index]; } }
CopyToArray(Array destination, int destinationOffset)48 			public void CopyToArray(Array destination, int destinationOffset)
49 			{
50 				palette.CopyToArray(destination, destinationOffset);
51 			}
52 		}
53 	}
54 
55 	public class ImmutablePalette : IPalette
56 	{
57 		readonly uint[] colors = new uint[Palette.Size];
58 
59 		public uint this[int index]
60 		{
61 			get { return colors[index]; }
62 		}
63 
CopyToArray(Array destination, int destinationOffset)64 		public void CopyToArray(Array destination, int destinationOffset)
65 		{
66 			Buffer.BlockCopy(colors, 0, destination, destinationOffset * 4, Palette.Size * 4);
67 		}
68 
ImmutablePalette(string filename, int[] remap)69 		public ImmutablePalette(string filename, int[] remap)
70 		{
71 			using (var s = File.OpenRead(filename))
72 				LoadFromStream(s, remap);
73 		}
74 
ImmutablePalette(Stream s, int[] remapShadow)75 		public ImmutablePalette(Stream s, int[] remapShadow)
76 		{
77 			LoadFromStream(s, remapShadow);
78 		}
79 
LoadFromStream(Stream s, int[] remapShadow)80 		void LoadFromStream(Stream s, int[] remapShadow)
81 		{
82 			using (var reader = new BinaryReader(s))
83 				for (var i = 0; i < Palette.Size; i++)
84 				{
85 					var r = (byte)(reader.ReadByte() << 2);
86 					var g = (byte)(reader.ReadByte() << 2);
87 					var b = (byte)(reader.ReadByte() << 2);
88 
89 					// Replicate high bits into the (currently zero) low bits.
90 					r |= (byte)(r >> 6);
91 					g |= (byte)(g >> 6);
92 					b |= (byte)(b >> 6);
93 
94 					colors[i] = (uint)((255 << 24) | (r << 16) | (g << 8) | b);
95 				}
96 
97 			colors[0] = 0; // Convert black background to transparency.
98 			foreach (var i in remapShadow)
99 				colors[i] = 140u << 24;
100 		}
101 
ImmutablePalette(IPalette p, IPaletteRemap r)102 		public ImmutablePalette(IPalette p, IPaletteRemap r)
103 			: this(p)
104 		{
105 			for (var i = 0; i < Palette.Size; i++)
106 				colors[i] = (uint)r.GetRemappedColor(this.GetColor(i), i).ToArgb();
107 		}
108 
ImmutablePalette(IPalette p)109 		public ImmutablePalette(IPalette p)
110 		{
111 			for (int i = 0; i < Palette.Size; i++)
112 				colors[i] = p[i];
113 		}
114 
ImmutablePalette(IEnumerable<uint> sourceColors)115 		public ImmutablePalette(IEnumerable<uint> sourceColors)
116 		{
117 			var i = 0;
118 			foreach (var sourceColor in sourceColors)
119 				colors[i++] = sourceColor;
120 		}
121 	}
122 
123 	public class MutablePalette : IPalette
124 	{
125 		readonly uint[] colors = new uint[Palette.Size];
126 
127 		public uint this[int index]
128 		{
129 			get { return colors[index]; }
130 			set { colors[index] = value; }
131 		}
132 
CopyToArray(Array destination, int destinationOffset)133 		public void CopyToArray(Array destination, int destinationOffset)
134 		{
135 			Buffer.BlockCopy(colors, 0, destination, destinationOffset * 4, Palette.Size * 4);
136 		}
137 
MutablePalette(IPalette p)138 		public MutablePalette(IPalette p)
139 		{
140 			SetFromPalette(p);
141 		}
142 
SetColor(int index, Color color)143 		public void SetColor(int index, Color color)
144 		{
145 			colors[index] = (uint)color.ToArgb();
146 		}
147 
SetFromPalette(IPalette p)148 		public void SetFromPalette(IPalette p)
149 		{
150 			p.CopyToArray(colors, 0);
151 		}
152 
ApplyRemap(IPaletteRemap r)153 		public void ApplyRemap(IPaletteRemap r)
154 		{
155 			for (var i = 0; i < Palette.Size; i++)
156 				colors[i] = (uint)r.GetRemappedColor(this.GetColor(i), i).ToArgb();
157 		}
158 	}
159 }
160