diff --git a/BluntDx/Enumerations.h b/BluntDx/Enumerations.h index 2c1f680cf3..494d296c0d 100644 --- a/BluntDx/Enumerations.h +++ b/BluntDx/Enumerations.h @@ -17,6 +17,7 @@ namespace BluntDirectX { namespace Direct3D Position = D3DFVF_XYZ, Normal = D3DFVF_NORMAL, Texture = D3DFVF_TEX1, + Texture2 = D3DFVF_TEX2, }; public enum class PrimitiveType diff --git a/OpenRa.FileFormats/BitmapBuilder.cs b/OpenRa.FileFormats/BitmapBuilder.cs index 7e4d1bfaba..f80370d956 100644 --- a/OpenRa.FileFormats/BitmapBuilder.cs +++ b/OpenRa.FileFormats/BitmapBuilder.cs @@ -7,12 +7,12 @@ namespace OpenRa.FileFormats { public static class BitmapBuilder { - public static Bitmap FromBytes( byte[] imageBytes, int width, int height, Palette pal ) + public static Bitmap FromBytes(byte[] imageBytes, Size size, Palette pal) { - Bitmap bitmap = new Bitmap( width, height ); - for( int x = 0 ; x < width ; x++ ) - for( int y = 0 ; y < height ; y++ ) - bitmap.SetPixel( x, y, pal.GetColor( imageBytes[ x + width * y ] ) ); + Bitmap bitmap = new Bitmap(size.Width, size.Height); + for (int x = 0; x < size.Width; x++) + for (int y = 0; y < size.Height; y++) + bitmap.SetPixel(x, y, pal.GetColor(imageBytes[x + size.Width * y])); return bitmap; } diff --git a/OpenRa.FileFormats/ShpReader.cs b/OpenRa.FileFormats/ShpReader.cs index 1387a40047..efbc39f1b7 100644 --- a/OpenRa.FileFormats/ShpReader.cs +++ b/OpenRa.FileFormats/ShpReader.cs @@ -42,6 +42,8 @@ namespace OpenRa.FileFormats public readonly ushort Width; public readonly ushort Height; + public Size Size { get { return new Size(Width, Height); } } + private readonly List headers = new List(); int recurseDepth = 0; diff --git a/OpenRa.FileFormats/Terrain.cs b/OpenRa.FileFormats/Terrain.cs index 5ff5580ee3..37d157ae50 100644 --- a/OpenRa.FileFormats/Terrain.cs +++ b/OpenRa.FileFormats/Terrain.cs @@ -16,6 +16,7 @@ namespace OpenRa.FileFormats readonly byte[] index; readonly List TileBitmaps = new List(); + public readonly List TileBitmapBytes = new List(); public Terrain( Stream stream, Palette pal ) { @@ -44,15 +45,19 @@ namespace OpenRa.FileFormats for( int i = 0 ; i < index.Length ; i++ ) { - if( index[ i ] != 255 ) + if (index[i] != 255) { - byte[] tileData = new byte[ 24 * 24 ]; - stream.Position = ImgStart + index[ i ] * 24 * 24; - stream.Read( tileData, 0, 24 * 24 ); - TileBitmaps.Add( BitmapBuilder.FromBytes( tileData, 24, 24, pal ) ); + byte[] tileData = new byte[24 * 24]; + stream.Position = ImgStart + index[i] * 24 * 24; + stream.Read(tileData, 0, 24 * 24); + TileBitmaps.Add(BitmapBuilder.FromBytes(tileData, new Size(24, 24), pal)); + TileBitmapBytes.Add(tileData); } else - TileBitmaps.Add( null ); + { + TileBitmaps.Add(null); + TileBitmapBytes.Add(null); + } } } diff --git a/OpenRa.Game/HardwarePalette.cs b/OpenRa.Game/HardwarePalette.cs index 79f89a986c..852a31c77b 100644 --- a/OpenRa.Game/HardwarePalette.cs +++ b/OpenRa.Game/HardwarePalette.cs @@ -24,7 +24,7 @@ namespace OpenRa.Game this.device = device; } - public void Resolve() + void Resolve() { const string filename = "../../../palette-cache.png"; bitmap.Save(filename); diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index 17f80d6d85..dd8412e927 100644 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -53,27 +53,25 @@ namespace OpenRa.Game if (!tileMapping.ContainsKey(tileRef)) { - Bitmap srcImage = tileSet.tiles[tileRef.tile].GetTile(tileRef.image); - SheetRectangle rect = builder.AddImage(srcImage.Size); - - using (Graphics g = Graphics.FromImage(rect.sheet.bitmap)) - g.DrawImage(srcImage, rect.origin); + SheetRectangle rect = builder.AddImage(new Size(24, 24)); + Util.CopyIntoChannel(rect.sheet.bitmap, TextureChannel.Red, + tileSet.tiles[tileRef.tile].TileBitmapBytes[tileRef.image], rect); tileMapping.Add(tileRef, rect); } } world = new World(renderer.Device); - treeCache = new TreeCache(renderer.Device, map, TileMix, pal); + treeCache = new TreeCache(renderer.Device, map, TileMix); foreach (TreeReference treeReference in map.Trees) world.Add(new Tree(treeReference, treeCache, map)); UnitSheetBuilder.Initialize(renderer.Device); - UnitSheetBuilder.AddUnit("mcv", playerPal); - UnitSheetBuilder.AddUnit("1tnk", playerPal); - UnitSheetBuilder.AddUnit("2tnk", playerPal); - UnitSheetBuilder.AddUnit("3tnk", playerPal); + UnitSheetBuilder.AddUnit("mcv"); + UnitSheetBuilder.AddUnit("1tnk"); + UnitSheetBuilder.AddUnit("2tnk"); + UnitSheetBuilder.AddUnit("3tnk"); world.Add(new Mcv(new PointF(24 * 5, 24 * 5))); } @@ -226,7 +224,7 @@ namespace OpenRa.Game hardwarePalette.AddPalette(new Palette(pal, new PaletteRemap( File.OpenRead("../../../" + remap + ".rem")))); - hardwarePalette.Resolve(); + renderer.SetPalette(hardwarePalette); return new TileSet(TileMix, TileSuffix, pal); } diff --git a/OpenRa.Game/Renderer.cs b/OpenRa.Game/Renderer.cs index 46483c0495..1fbf25b614 100644 --- a/OpenRa.Game/Renderer.cs +++ b/OpenRa.Game/Renderer.cs @@ -13,10 +13,15 @@ namespace OpenRa.Game readonly GraphicsDevice device; readonly Effect shader; - readonly IntPtr r1Handle, r2Handle, baseTextureHandle, scrollHandle; + readonly IntPtr r1Handle, r2Handle, baseTextureHandle, scrollHandle, paletteHandle; const string shaderName = "diffuse.fx"; + public void SetPalette(HardwarePalette hp) + { + shader.SetTexture(paletteHandle, hp.PaletteTexture); + } + public Renderer(Control host, Size resolution, bool windowed) { host.ClientSize = resolution; @@ -30,6 +35,7 @@ namespace OpenRa.Game scrollHandle = shader.GetHandle("Scroll"); r1Handle = shader.GetHandle("r1"); r2Handle = shader.GetHandle("r2"); + paletteHandle = shader.GetHandle("Palette"); } public GraphicsDevice Device { get { return device; } } diff --git a/OpenRa.Game/Sheet.cs b/OpenRa.Game/Sheet.cs index aa68852d16..7b34245a1c 100644 --- a/OpenRa.Game/Sheet.cs +++ b/OpenRa.Game/Sheet.cs @@ -16,6 +16,15 @@ namespace OpenRa.Game Texture texture; public Sheet(Bitmap b, GraphicsDevice d) { bitmap = b; device = d; } + + public Sheet(Size size, GraphicsDevice d) + { + bitmap = new Bitmap(size.Width, size.Height); + device = d; + + using (Graphics g = Graphics.FromImage(bitmap)) + g.FillRectangle(Brushes.Fuchsia, 0, 0, size.Width, size.Height); + } public Texture Texture { diff --git a/OpenRa.Game/TreeCache.cs b/OpenRa.Game/TreeCache.cs index 3bfdf25e0c..d2355d818f 100644 --- a/OpenRa.Game/TreeCache.cs +++ b/OpenRa.Game/TreeCache.cs @@ -13,14 +13,14 @@ namespace OpenRa.Game public readonly Sheet sh; - public TreeCache(GraphicsDevice device, Map map, Package package, Palette pal) + public TreeCache(GraphicsDevice device, Map map, Package package) { Size pageSize = new Size(1024, 512); List sheets = new List(); Provider sheetProvider = delegate { - Sheet sheet = new Sheet(new Bitmap(pageSize.Width, pageSize.Height), device); + Sheet sheet = new Sheet(pageSize, device); sheets.Add(sheet); return sheet; }; @@ -32,13 +32,11 @@ namespace OpenRa.Game if (trees.ContainsKey(r.Image)) continue; - ShpReader reader = new ShpReader(package.GetContent(r.Image + "." + map.Theater.Substring(0, 3))); - Bitmap bitmap = BitmapBuilder.FromBytes(reader[0].Image, reader.Width, reader.Height, pal); - - SheetRectangle rect = builder.AddImage(bitmap.Size); - using (Graphics g = Graphics.FromImage(rect.sheet.bitmap)) - g.DrawImage(bitmap, rect.origin); + string filename = r.Image + "." + map.Theater.Substring(0, 3); + ShpReader reader = new ShpReader(package.GetContent(filename)); + SheetRectangle rect = builder.AddImage(reader.Size); + Util.CopyIntoChannel(rect.sheet.bitmap, TextureChannel.Red, reader[0].Image, rect); trees.Add(r.Image, rect); } diff --git a/OpenRa.Game/UnitSheetBuilder.cs b/OpenRa.Game/UnitSheetBuilder.cs index 941ae6d18c..82f0123f39 100644 --- a/OpenRa.Game/UnitSheetBuilder.cs +++ b/OpenRa.Game/UnitSheetBuilder.cs @@ -20,7 +20,7 @@ namespace OpenRa.Game { Provider sheetProvider = delegate { - Sheet sheet = new Sheet(new Bitmap(pageSize.Width, pageSize.Height), device); + Sheet sheet = new Sheet(pageSize, device); sheets.Add(sheet); return sheet; }; @@ -28,17 +28,13 @@ namespace OpenRa.Game builder = new TileSheetBuilder(pageSize, sheetProvider); } - public static void AddUnit( string name, Palette pal ) + public static void AddUnit( string name ) { ShpReader reader = new ShpReader( unitsPackage.GetContent( name + ".shp" ) ); foreach( ImageHeader h in reader ) { - Bitmap bitmap = BitmapBuilder.FromBytes( h.Image, reader.Width, reader.Height, pal ); - - SheetRectangle rect = builder.AddImage( bitmap.Size ); - using( Graphics g = Graphics.FromImage( rect.sheet.bitmap ) ) - g.DrawImage( bitmap, rect.origin ); - + SheetRectangle rect = builder.AddImage(reader.Size); + Util.CopyIntoChannel(rect.sheet.bitmap, TextureChannel.Red, h.Image, rect); McvSheet.Add( rect ); } } diff --git a/OpenRa.Game/Util.cs b/OpenRa.Game/Util.cs index 655814dc20..bae229797b 100644 --- a/OpenRa.Game/Util.cs +++ b/OpenRa.Game/Util.cs @@ -13,7 +13,7 @@ namespace OpenRa.Game float u0 = (float)(s.origin.X + 0.5f) / (float)s.sheet.bitmap.Width; float u1 = (float)(s.origin.X + s.size.Width) / (float)s.sheet.bitmap.Width; - return (u > 0) ? u1 : u0;// (1 - u) * u0 + u * u1; + return (u > 0) ? u1 : u0; } public static float V(SheetRectangle s, float v) @@ -21,7 +21,7 @@ namespace OpenRa.Game float v0 = (float)(s.origin.Y + 0.5f) / (float)s.sheet.bitmap.Height; float v1 = (float)(s.origin.Y + s.size.Height) / (float)s.sheet.bitmap.Height; - return (v > 0) ? v1 : v0;// return (1 - v) * v0 + v * v1; + return (v > 0) ? v1 : v0; } public static Vertex MakeVertex(PointF o, float u, float v, SheetRectangle r) @@ -29,7 +29,8 @@ namespace OpenRa.Game float x2 = o.X + r.size.Width; float y2 = o.Y + r.size.Height; - return new Vertex(Lerp(o.X, x2, u), Lerp(o.Y, y2, v), 0, U(r, u), V(r, v)); + return new Vertex(Lerp(o.X, x2, u), Lerp(o.Y, y2, v), 0, U(r, u), V(r, v), + 0, 1); } static float Lerp(float a, float b, float t) @@ -54,5 +55,39 @@ namespace OpenRa.Game indices.Add((ushort)(offset + 3)); indices.Add((ushort)(offset + 2)); } + + public static void CopyIntoChannel(Bitmap bitmap, TextureChannel channel, byte[] src, SheetRectangle s) + { + for( int i = 0; i < s.size.Width; i++ ) + for (int j = 0; j < s.size.Height; j++) + { + Point p = new Point(s.origin.X + i, s.origin.Y + j); + byte b = src[i + s.size.Width * j]; + Color original = bitmap.GetPixel(p.X, p.Y); + bitmap.SetPixel(p.X, p.Y, ReplaceChannel(original, channel, b)); + } + } + + static Color ReplaceChannel(Color o, TextureChannel channel, byte p) + { + switch (channel) + { + case TextureChannel.Red: return Color.FromArgb(o.A, p, o.G, o.B); + case TextureChannel.Green: return Color.FromArgb(o.A, o.R, p, o.B); + case TextureChannel.Blue: return Color.FromArgb(o.A, o.R, o.G, p); + case TextureChannel.Alpha: return Color.FromArgb(p, o.R, o.G, o.B); + + default: + throw new ArgumentException(); + } + } + } + + enum TextureChannel + { + Red, + Green, + Blue, + Alpha, } } diff --git a/OpenRa.Game/Vertex.cs b/OpenRa.Game/Vertex.cs index 140025efd3..d5061e22d1 100644 --- a/OpenRa.Game/Vertex.cs +++ b/OpenRa.Game/Vertex.cs @@ -10,14 +10,18 @@ namespace OpenRa.Game struct Vertex { public float x, y, z, u, v; + public float p, c; - public Vertex(float x, float y, float z, float u, float v) + public Vertex(float x, float y, float z, float u, float v, float p, float c) { this.x = x; this.y = y; this.z = z; this.u = u; this.v = v; + + this.p = p; + this.c = c; } - public const VertexFormat Format = VertexFormat.Position | VertexFormat.Texture; + public const VertexFormat Format = VertexFormat.Position | VertexFormat.Texture2; } } diff --git a/OpenRa.TechTreeTest/Item.cs b/OpenRa.TechTreeTest/Item.cs index dee583439c..fcf4f1a25b 100644 --- a/OpenRa.TechTreeTest/Item.cs +++ b/OpenRa.TechTreeTest/Item.cs @@ -143,7 +143,7 @@ namespace OpenRa.TechTreeTest Stream s = package.GetContent(filename); ShpReader reader = new ShpReader(s); foreach (ImageHeader h in reader) - return BitmapBuilder.FromBytes(h.Image, reader.Width, reader.Height, palette); + return BitmapBuilder.FromBytes(h.Image, reader.Size, palette); return null; } diff --git a/ShpViewer/MapViewControl.cs b/ShpViewer/MapViewControl.cs index 4fcafc762d..d09c4cf4c0 100644 --- a/ShpViewer/MapViewControl.cs +++ b/ShpViewer/MapViewControl.cs @@ -92,7 +92,7 @@ namespace ShpViewer if (!TreeCache.TryGetValue(name, out ret)) { ShpReader shp = new ShpReader(TileSet.MixFile.GetContent(name + TileSuffix)); - ret = BitmapBuilder.FromBytes(shp[0].Image, shp.Width, shp.Height, pal); ; + ret = BitmapBuilder.FromBytes(shp[0].Image, shp.Size, pal); ; TreeCache.Add(name, ret); } return ret; diff --git a/ShpViewer/ShpViewForm.cs b/ShpViewer/ShpViewForm.cs index b62c7ef541..e990d4297a 100644 --- a/ShpViewer/ShpViewForm.cs +++ b/ShpViewer/ShpViewForm.cs @@ -30,7 +30,7 @@ namespace ShpViewer pal = new Palette(pal, remap); foreach( ImageHeader h in shpReader ) - bitmaps.Add( BitmapBuilder.FromBytes( h.Image, shpReader.Width, shpReader.Height, pal ) ); + bitmaps.Add( BitmapBuilder.FromBytes( h.Image, shpReader.Size, pal ) ); } else if( ext == ".tem" || ext == ".sno" || ext == ".int" ) { diff --git a/diffuse.fx b/diffuse.fx index bd61ce7f56..a3c3bf2fab 100644 --- a/diffuse.fx +++ b/diffuse.fx @@ -2,7 +2,7 @@ // Author: C. Forbes //-------------------------------------------------------- -shared texture DiffuseTexture; +shared texture DiffuseTexture, Palette; shared float2 Scroll; shared float2 r1, r2; // matrix elements @@ -18,32 +18,57 @@ sampler s_DiffuseTexture = sampler_state { AddressW = Wrap; }; +sampler s_PaletteTexture = sampler_state { + Texture = ; + MinFilter = None; + MagFilter = None; + MipFilter = None; + + AddressU = Clamp; + AddressV = Clamp; +}; + struct VertexIn { float4 Position: POSITION; float2 Tex0: TEXCOORD0; + float2 Tex1: TEXCOORD1; }; struct VertexOut { float4 Position: POSITION; - float2 Tex0: TEXCOORD0; + float3 Tex0: TEXCOORD0; + float4 ChannelMask: TEXCOORD1; }; struct FragmentIn { - float2 Tex0: TEXCOORD0; + float3 Tex0: TEXCOORD0; + float4 ChannelMask: TEXCOORD1; }; +float4 DecodeChannelMask( float x ) +{ + if (x > 0) + return (x > 0.5f) ? float4(1,0,0,0) : float4(0,1,0,0); + else + return (x <-0.5f) ? float4(0,0,0,1) : float4(0,0,1,0); +} + VertexOut Simple_vp(VertexIn v) { VertexOut o; float2 p = (v.Position.xy - Scroll.xy) * r1 + r2; o.Position = float4(p.x,p.y,0,1); - o.Tex0 = v.Tex0; + o.Tex0 = float3(v.Tex0.x, v.Tex0.y, v.Tex1.x); + o.ChannelMask = DecodeChannelMask( v.Tex1.y ); return o; } -float4 Simple_fp(FragmentIn f) : COLOR0 { - float4 color = tex2D(s_DiffuseTexture, f.Tex0); - return color; +const float2 texelOffset = float2( 0, 1.0f/32.0f ); + +float4 Palette_fp(FragmentIn f) : COLOR0 { + float4 x = tex2D(s_DiffuseTexture, f.Tex0.xy); + float2 p = float2( dot(x, f.ChannelMask), f.Tex0.z ); + return tex2D(s_PaletteTexture, p + texelOffset); } technique low_quality { @@ -53,7 +78,7 @@ technique low_quality { ZEnable = false; CullMode = None; VertexShader = compile vs_2_0 Simple_vp(); - PixelShader = compile ps_2_0 Simple_fp(); + PixelShader = compile ps_2_0 Palette_fp(); } } @@ -64,7 +89,7 @@ technique high_quality { ZEnable = false; CullMode = None; VertexShader = compile vs_2_0 Simple_vp(); - PixelShader = compile ps_2_0 Simple_fp(); + PixelShader = compile ps_2_0 Palette_fp(); SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha;