diff --git a/OpenKh.Engine/Extensions/SpriteDrawingExtensions.cs b/OpenKh.Engine/Extensions/SpriteDrawingExtensions.cs index 3aaacb5d8..e6ae78818 100644 --- a/OpenKh.Engine/Extensions/SpriteDrawingExtensions.cs +++ b/OpenKh.Engine/Extensions/SpriteDrawingExtensions.cs @@ -21,13 +21,14 @@ public static void FillRectangle(this ISpriteDrawing drawing, float x, float y, drawing.AppendSprite(new SpriteDrawingContext() .Source(0, 0, 1, 1) .Position(x, y) - .DestinationSize(width, height)); + .DestinationSize(width, height) + .Color(color)); } public static void DrawRectangle(this ISpriteDrawing drawing, float x, float y, float width, float height, ColorF color, float thickness = 1.0f) { drawing.FillRectangle(x, y, width, thickness, color); - drawing.FillRectangle(x, y + height - 1, width + width - 1, thickness, color); + drawing.FillRectangle(x, y + height - 1, width - 1, thickness, color); drawing.FillRectangle(x, y, thickness, height, color); drawing.FillRectangle(x + width - 1, y, thickness, height, color); } diff --git a/OpenKh.Game/MonoSpriteDrawing.cs b/OpenKh.Game/MonoSpriteDrawing.cs index ea063278c..2dcab3264 100644 --- a/OpenKh.Game/MonoSpriteDrawing.cs +++ b/OpenKh.Game/MonoSpriteDrawing.cs @@ -4,6 +4,7 @@ using OpenKh.Engine.Renders; using OpenKh.Game.Shaders; using OpenKh.Imaging; +using System.Linq; namespace OpenKh.Game { @@ -58,10 +59,12 @@ public MyVertex(Vector3 position, ColorF color, Vector2 textureCoordinate) // This size should be enough to pack enough 2D graphics at once private const int MaxSpriteCountPerDraw = 8000; + private static readonly byte[] WhiteBitmap = Enumerable.Range(0, 2 * 2 * sizeof(int)).Select(x => byte.MaxValue).ToArray(); private readonly GraphicsDevice _graphicsDevice; private readonly KingdomShader _shader; + private readonly Texture2D _defaultTexture; private readonly BlendState _blendState; private readonly SamplerState _samplerState; private readonly RasterizerState _rasterizerState; @@ -79,6 +82,9 @@ public MonoSpriteDrawing(GraphicsDevice graphicsDevice, KingdomShader shader) _graphicsDevice = graphicsDevice; _shader = shader; + _defaultTexture = new Texture2D(_graphicsDevice, 2, 2); + _defaultTexture.SetData(WhiteBitmap); + _blendState = BlendState.NonPremultiplied; _samplerState = new SamplerState { @@ -110,6 +116,7 @@ public MonoSpriteDrawing(GraphicsDevice graphicsDevice, KingdomShader shader) public void Dispose() { + _defaultTexture?.Dispose(); _vertexBuffer.Dispose(); _indexBuffer.Dispose(); } @@ -139,8 +146,8 @@ public void AppendSprite(SpriteDrawingContext context) var texture = (context.SpriteTexture as CSpriteTexture)?.Texture; var vertexIndex = PrepareVertices(texture); - var tw = 1.0f / texture.Width; - var th = 1.0f / texture.Height; + var tw = 1.0f / _lastTextureUsed.Width; + var th = 1.0f / _lastTextureUsed.Height; _vertices[vertexIndex + 0].Position = new Vector3(context.DestinationX, context.DestinationY, 0.0f); _vertices[vertexIndex + 0].Color = context.Color0; @@ -193,6 +200,7 @@ public void Flush() private int PrepareVertices(Texture2D texture) { + texture ??= _defaultTexture; if (_lastTextureUsed != texture) { Flush(); diff --git a/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Context.cs b/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Context.cs index 0da2f27a9..0823e4c1a 100644 --- a/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Context.cs +++ b/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Context.cs @@ -27,6 +27,7 @@ // Took from Xe.Drawing.Direct3D and transported to OpenKH under the same developer +using OpenKh.Engine.Renders; using SharpDX.D3DCompiler; using SharpDX.Direct3D; using System; @@ -41,10 +42,15 @@ namespace OpenKh.Tools.Common.Rendering public partial class SpriteDrawingDirect3D { - private CDevice _device = new CDevice(); + private static readonly byte[] WhiteBitmap = Enumerable.Range(0, 2 * 2 * sizeof(int)).Select(x => byte.MaxValue).ToArray(); + + private readonly CDevice _device; + private readonly ISpriteTexture _defaultTexture; public SpriteDrawingDirect3D() { + _device = new CDevice(); + _defaultTexture = CreateSpriteTexture(2, 2, WhiteBitmap); } public d3d.Device5 Device => _device.Device; diff --git a/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Drawing.cs b/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Drawing.cs index 44dbcc1c6..42e11c3d2 100644 --- a/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Drawing.cs +++ b/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Drawing.cs @@ -53,12 +53,12 @@ private struct Vertex public void AppendSprite(SpriteDrawingContext context) { - var width = context.SpriteTexture.Width; - var height = context.SpriteTexture.Height; + SetTextureToDraw(context.SpriteTexture); + var width = _currentTexture.Width; + var height = _currentTexture.Height; var viewport = _viewportSize; var index = RequestVertices(4); var buffer = _dataBuffer; - SetTextureToDraw(context.SpriteTexture); buffer[index++] = new Vertex() { @@ -94,15 +94,17 @@ public void AppendSprite(SpriteDrawingContext context) }; } - private CSpriteTexture _prevSurface; - private void SetTextureToDraw(ISpriteTexture surface) + private CSpriteTexture _currentTexture; + private void SetTextureToDraw(ISpriteTexture texture) { - if (_prevSurface != surface) + if (_currentTexture != texture) { Flush(); - var internalSurface = surface as CSpriteTexture; - Context.PixelShader.SetShaderResource(0, internalSurface?.ShaderResourceView); - _prevSurface = internalSurface; + + texture ??= _defaultTexture; + var internalTexture = texture as CSpriteTexture; + Context.PixelShader.SetShaderResource(0, internalTexture?.ShaderResourceView); + _currentTexture = internalTexture; } } diff --git a/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Surface.cs b/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Surface.cs index 6e47c41a0..ef948c24b 100644 --- a/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Surface.cs +++ b/OpenKh.Tools.Common/Rendering/SpriteDrawingDirect3D.Surface.cs @@ -29,6 +29,7 @@ using OpenKh.Engine.Renders; using OpenKh.Imaging; +using SharpDX.D3DCompiler; using SharpDX.IO; using System; using System.Drawing; @@ -236,18 +237,20 @@ public void Save(string filename) } } - public ISpriteTexture CreateSpriteTexture(IImageRead image) + public ISpriteTexture CreateSpriteTexture(IImageRead image) => + CreateSpriteTexture(image.Size.Width, image.Size.Height, image.ToBgra32()); + + public ISpriteTexture CreateSpriteTexture(int width, int height) { - var size = image.Size; - if (size.Width <= 0 || size.Width > 65536) - throw new ArgumentOutOfRangeException(nameof(size.Width), "Must be between 1 and 65536"); - if (size.Height <= 0 || size.Height > 65536) - throw new ArgumentOutOfRangeException(nameof(size.Height), "Must be between 1 and 65536"); + if (width <= 0 || width > 65536) + throw new ArgumentOutOfRangeException(nameof(width), "Must be between 1 and 65536"); + if (height <= 0 || height > 65536) + throw new ArgumentOutOfRangeException(nameof(height), "Must be between 1 and 65536"); var desc = new d3d.Texture2DDescription { - Width = size.Width, - Height = size.Height, + Width = width, + Height = height, MipLevels = 1, ArraySize = 1, Format = dxgi.Format.B8G8R8A8_UNorm, @@ -256,17 +259,23 @@ public ISpriteTexture CreateSpriteTexture(IImageRead image) SampleDescription = new dxgi.SampleDescription(1, 0) }; - desc.Usage = d3d.ResourceUsage.Immutable; - desc.BindFlags = d3d.BindFlags.ShaderResource; + desc.Usage = d3d.ResourceUsage.Default; + desc.BindFlags = d3d.BindFlags.ShaderResource | d3d.BindFlags.RenderTarget; - var srcDataPtr = Marshal.UnsafeAddrOfPinnedArrayElement(image.ToBgra32(), 0); - var dataSource = new SharpDX.DataRectangle(srcDataPtr, size.Width * sizeof(int)); - var texture = new d3d.Texture2D(Device, desc, new[] { dataSource }); + var texture = new d3d.Texture2D(Device, desc); var shaderResourceView = new d3d.ShaderResourceView(Device, texture); return new CSpriteTexture(texture, shaderResourceView); } - - public ISpriteTexture CreateSpriteTexture(int width, int height) + + public ISpriteTexture CreateSpriteTexture(string filename, Color[] filterColors = null) + { + var bitmap = TextureLoader.LoadBitmap(new wic.ImagingFactory2(), filename); + var texture = TextureLoader.CreateTexture2DFromBitmap(Device, bitmap, filterColors); + d3d.ShaderResourceView shaderResourceView = new d3d.ShaderResourceView(Device, texture); + return new CSpriteTexture(texture, shaderResourceView); + } + + public ISpriteTexture CreateSpriteTexture(int width, int height, byte[] data) { if (width <= 0 || width > 65536) throw new ArgumentOutOfRangeException(nameof(width), "Must be between 1 and 65536"); @@ -285,20 +294,14 @@ public ISpriteTexture CreateSpriteTexture(int width, int height) SampleDescription = new dxgi.SampleDescription(1, 0) }; - desc.Usage = d3d.ResourceUsage.Default; - desc.BindFlags = d3d.BindFlags.ShaderResource | d3d.BindFlags.RenderTarget; + desc.Usage = d3d.ResourceUsage.Immutable; + desc.BindFlags = d3d.BindFlags.ShaderResource; - var texture = new d3d.Texture2D(Device, desc); + var srcDataPtr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0); + var dataSource = new SharpDX.DataRectangle(srcDataPtr, width * sizeof(int)); + var texture = new d3d.Texture2D(Device, desc, new[] { dataSource }); var shaderResourceView = new d3d.ShaderResourceView(Device, texture); return new CSpriteTexture(texture, shaderResourceView); } - - public ISpriteTexture CreateSurface(string filename, Color[] filterColors = null) - { - var bitmap = TextureLoader.LoadBitmap(new wic.ImagingFactory2(), filename); - var texture = TextureLoader.CreateTexture2DFromBitmap(Device, bitmap, filterColors); - d3d.ShaderResourceView shaderResourceView = new d3d.ShaderResourceView(Device, texture); - return new CSpriteTexture(texture, shaderResourceView); - } - } + } }