using SharpDX; using SharpDX.Direct3D11; using VoidwalkerEngine.Framework.Interfaces; using VoidwalkerEngine.Framework.Logic; namespace VoidwalkerEngine.Framework.DirectX.Rendering { public class BrushVolume : GameEntity, IDrawable { private int _width; private int _height; private int _depth; public int Width { get { return _width; } set { _width = value; Resize(_width, _height, _depth); } } public int Height { get { return _height; } set { _height = value; Resize(_width, _height, _depth); } } public int Depth { get { return _depth; } set { _depth = value; Resize(_width, _height, _depth); } } public Material Tileset { get; set; } public Device Device; public Rectangle NorthFaceGraphic; public Rectangle SouthFaceGraphic; public Rectangle WestFaceGraphic; public Rectangle EastFaceGraphic; public Rectangle TopFaceGraphic; public Rectangle BottomFaceGraphic; // 36 Vertices maximum private int _drawCount; private VertexBufferBinding _buffer; private const float _stride = 16; private CubeFaceVisibility _faces; public CubeFaceVisibility Faces { get { return _faces; } set { _faces = value; Rebuild(); } } public BrushVolume(Device device, Material diffuseMaterial, int width, int height, int depth, CubeFaceVisibility faceVisibility, Rectangle northRectangle, Rectangle eastRectangle, Rectangle southRectangle, Rectangle westRectangle, Rectangle topRectangle, Rectangle bottomRectangle) { this.Device = device; this._width = width; this._height = height; this._depth = depth; this._faces = faceVisibility; this.Tileset = diffuseMaterial; UpdateFaceGraphics( northRectangle, eastRectangle, southRectangle, westRectangle, topRectangle, bottomRectangle); Rebuild(); } public void UpdateFaceGraphics(Rectangle northRectangle, Rectangle eastRectangle, Rectangle southRectangle, Rectangle westRectangle, Rectangle topRectangle, Rectangle bottomRectangle) { this.NorthFaceGraphic = northRectangle; this.SouthFaceGraphic = southRectangle; this.WestFaceGraphic = westRectangle; this.EastFaceGraphic = eastRectangle; this.TopFaceGraphic = topRectangle; this.BottomFaceGraphic = bottomRectangle; } public void Resize(int width, int height, int depth) { this._width = width; this._height = height; this._depth = depth; Rebuild(); } private int CountVisibleFaces() { int value = (int)Faces; value -= ((value >> 1) & 1431655765); value = (value & 858993459) + ((value >> 2) & 858993459); int count = ((value + (value >> 4) & 252645135) * 16843009) >> 24; return count; } public void CalculateTextureCoordinates(Rectangle textureRectangle, out float x, out float y, out float width, out float height) { x = textureRectangle.X / (float)this.Tileset.Width; y = textureRectangle.Y / (float)this.Tileset.Height; width = textureRectangle.Right / (float)this.Tileset.Width; height = textureRectangle.Bottom / (float)this.Tileset.Height; } public void Rebuild() { if(Faces == CubeFaceVisibility.None) { return; } Vertex[] vertices = new Vertex[CountVisibleFaces() * 6]; float width = _stride * this.Width; float height = _stride * this.Height; float depth = _stride * this.Depth; int index = 0; // Generate North Face if (this.Faces.HasFlag(CubeFaceVisibility.North)) { Vector3 normal = new Vector3(0, 0, -1); CalculateTextureCoordinates( this.NorthFaceGraphic, out float uvX, out float uvY, out float uvWidth, out float uvHeight); vertices[index++] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(width, height, -depth), new Vector2(uvX, uvY), normal); vertices[index++] = new Vertex(new Vector3(width, -height, -depth), new Vector2(uvX, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(uvWidth, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(width, -height, -depth), new Vector2(uvX, uvHeight), normal); } // Generate East Face if (this.Faces.HasFlag(CubeFaceVisibility.East)) { Vector3 normal = new Vector3(1, 0, 0); CalculateTextureCoordinates( this.EastFaceGraphic, out float uvX, out float uvY, out float uvWidth, out float uvHeight); vertices[index++] = new Vertex(new Vector3(width, -height, depth), new Vector2(uvX, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(width, -height, -depth), new Vector2(uvWidth, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(width, height, -depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(width, height, -depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(width, height, depth), new Vector2(uvX, uvY), normal); vertices[index++] = new Vertex(new Vector3(width, -height, depth), new Vector2(uvX, uvHeight), normal); } // Generate South Face if (this.Faces.HasFlag(CubeFaceVisibility.South)) { Vector3 normal = new Vector3(0, 0, 1); CalculateTextureCoordinates( this.SouthFaceGraphic, out float uvX, out float uvY, out float uvWidth, out float uvHeight); vertices[index++] = new Vertex(new Vector3(width, height, depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(-width, height, depth), new Vector2(uvX, uvY), normal); vertices[index++] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvX, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvX, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(width, -height, depth), new Vector2(uvWidth, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(width, height, depth), new Vector2(uvWidth, uvY), normal); } // Generate West Face if (this.Faces.HasFlag(CubeFaceVisibility.West)) { Vector3 normal = new Vector3(-1, 0, 0); CalculateTextureCoordinates( this.WestFaceGraphic, out float uvX, out float uvY, out float uvWidth, out float uvHeight); vertices[index++] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(uvX, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvWidth, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(-width, height, depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(-width, height, depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvX, uvY), normal); vertices[index++] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(uvX, uvHeight), normal); } // Generate Top Face if (this.Faces.HasFlag(CubeFaceVisibility.Top)) { Vector3 normal = new Vector3(0, 1, 0); CalculateTextureCoordinates( this.TopFaceGraphic, out float uvX, out float uvY, out float uvWidth, out float uvHeight); vertices[index++] = new Vertex(new Vector3(width, height, depth), new Vector2(uvWidth, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(-width, height, depth), new Vector2(uvX, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvX, uvY), normal); vertices[index++] = new Vertex(new Vector3(-width, height, -depth), new Vector2(uvX, uvY), normal); vertices[index++] = new Vertex(new Vector3(width, height, -depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(width, height, depth), new Vector2(uvWidth, uvHeight), normal); } // Generate Bottom Face if (this.Faces.HasFlag(CubeFaceVisibility.Bottom)) { Vector3 normal = new Vector3(0, -1, 0); CalculateTextureCoordinates( this.BottomFaceGraphic, out float uvX, out float uvY, out float uvWidth, out float uvHeight); vertices[index++] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvWidth, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(width, -height, depth), new Vector2(uvX, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(width, -height, -depth), new Vector2(uvX, uvY), normal); vertices[index++] = new Vertex(new Vector3(-width, -height, depth), new Vector2(uvWidth, uvHeight), normal); vertices[index++] = new Vertex(new Vector3(-width, -height, -depth), new Vector2(uvWidth, uvY), normal); vertices[index++] = new Vertex(new Vector3(width, -height, -depth), new Vector2(uvX, uvY), normal); } if (this._buffer.Buffer != null) { this._buffer.Buffer.Dispose(); } this._drawCount = vertices.Length; Buffer vertexBuffer = Buffer.Create(Device, BindFlags.VertexBuffer, vertices); const int vertexSizeInBytes = 32; // Precalculated this._buffer = new VertexBufferBinding(vertexBuffer, vertexSizeInBytes, 0); } public void Draw(DeviceContext context) { if(Faces == CubeFaceVisibility.None) { return; } context.InputAssembler.SetVertexBuffers(0, this._buffer); if (Tileset != null) { context.PixelShader.SetShaderResource(0, Tileset.ResourceView); //context.PixelShader.SetSampler(0, DiffuseMaterial.SamplerState); } context.Draw(_drawCount, 0); } } }