using System; using System.Collections.Generic; using System.Linq; using System.Text; using Aiwaz.Contracts; using Aiwaz.Core; using SlimDX.Direct3D10; using Aiwaz.Resources.Attributes; namespace Aiwaz.Resources { [CreationParameters("Create an empty texture")] public class EmptyTextureParams : ICreationParams { public int Width; public int Height; public int Elements; public int MipLevels; public SlimDX.DXGI.Format Format; public ResourceUsage AccessType; public TextureInitialData InitialData; public bool RenderTarget; public int MultiSampleCount; public int MultiSampleQuality; public EmptyTextureParams() { Width = 512; Height = 512; Elements = 1; MipLevels = 1; Format = SlimDX.DXGI.Format.Unknown; AccessType = ResourceUsage.Default; InitialData = null; RenderTarget = false; MultiSampleCount = 0; MultiSampleQuality = 0; } } [CreationParameters("Load a texture from file")] public class FileTextureParams : ICreationParams { [RequiredParameter] public string FileName; public SlimDX.Direct3D10.ResourceUsage AccessType; public FileTextureParams() { AccessType = ResourceUsage.Default; } } [AiwazResource("Texture", "A placeholder of multidimensional data")] public class Texture : ShaderParameterSet, ITexture { #region ITexture Members private string bindingName = "Diffuse"; private SlimDX.Direct3D10.Resource resource; private int lockedSubResource = 0; private bool isLocked = false; private ResourceUsage accessType; private Texture() : base(3) { } public Texture(FileTextureParams descriptor) : this() { Console.WriteLine(string.Format("Creating Texture ({0})..", descriptor.FileName)); this.LoadFromFile(descriptor.FileName, descriptor.AccessType); this.WellKnownName = descriptor.FileName; } public Texture(EmptyTextureParams descriptor) : this() { this.CreateTexture(descriptor.Width, descriptor.Height, descriptor.MipLevels, descriptor.Elements, descriptor.Format, descriptor.InitialData, descriptor.AccessType, descriptor.RenderTarget, descriptor.MultiSampleCount, descriptor.MultiSampleQuality); } public string BindingName { get { return bindingName; } set { if (!string.IsNullOrEmpty(bindingName)) this.RemoveParameter(bindingName); bindingName = value;; if (!string.IsNullOrEmpty(bindingName)) this.SetParameter(bindingName, this, ParameterBindType.BindBySemantic); } } public int TextureWidth { get; protected set; } public int TextureHeight { get; protected set; } public int TextureArraySize { get; protected set; } public SlimDX.DXGI.Format TextureFormat { get; protected set; } public SlimDX.Direct3D10.ShaderResourceView ResourceView { get; protected set; } public SlimDX.Direct3D10.Texture2D Texture2D { get; protected set; } public SlimDX.DataRectangle MapTextureBuffer(SlimDX.Direct3D10.MapMode mode) { return this.MapTextureBuffer(mode, 0); } public SlimDX.DataRectangle MapTextureBuffer(SlimDX.Direct3D10.MapMode mode, int arrayElement) { if (isLocked) throw new ActionFailedException("Texture is already locked."); isLocked = true; lockedSubResource = arrayElement; return this.Texture2D.Map(arrayElement, mode, SlimDX.Direct3D10.MapFlags.None); } public void UnmapTextureBuffer() { if (!isLocked) return; isLocked = false; this.Texture2D.Unmap(lockedSubResource); } private void LoadFromFile(string fileName, SlimDX.Direct3D10.ResourceUsage accessType) { this.accessType = accessType; Engine.FileSystem.Attach(fileName, OnFileChanged); this.TextureArraySize = 0; } private void OnFileChanged(System.IO.Stream stream) { if (this.Texture2D != null) this.Texture2D.Dispose(); if (this.ResourceView != null) this.ResourceView.Dispose(); var loadInfo = SlimDX.Direct3D10.ImageLoadInformation.FromDefaults(); if (accessType == SlimDX.Direct3D10.ResourceUsage.Staging) { loadInfo.BindFlags = 0; loadInfo.Usage = SlimDX.Direct3D10.ResourceUsage.Staging; loadInfo.CpuAccessFlags = SlimDX.Direct3D10.CpuAccessFlags.Write | SlimDX.Direct3D10.CpuAccessFlags.Read; } else if (accessType == SlimDX.Direct3D10.ResourceUsage.Dynamic) { loadInfo.Usage = SlimDX.Direct3D10.ResourceUsage.Dynamic; loadInfo.CpuAccessFlags = SlimDX.Direct3D10.CpuAccessFlags.Write; } using (stream) { this.Texture2D = SlimDX.Direct3D10.Texture2D.FromStream(Engine.Device, stream, (int)stream.Length, loadInfo); resource = this.Texture2D; } if (accessType != SlimDX.Direct3D10.ResourceUsage.Staging) { var texViewDesc = new SlimDX.Direct3D10.ShaderResourceViewDescription(); texViewDesc.Format = this.Texture2D.Description.Format; texViewDesc.Dimension = SlimDX.Direct3D10.ShaderResourceViewDimension.Texture2D; texViewDesc.MostDetailedMip = 0; texViewDesc.MipLevels = this.Texture2D.Description.MipLevels; this.ResourceView = new SlimDX.Direct3D10.ShaderResourceView(Engine.Device, this.Texture2D, texViewDesc); } this.TextureWidth = this.Texture2D.Description.Width; this.TextureHeight = this.Texture2D.Description.Height; this.TextureFormat = this.Texture2D.Description.Format; } internal void CreateRenderTargetTexture(int width, int height, SlimDX.DXGI.Format format, int multiSampleCount, int multiSampleQuality) { this.CreateTexture(width, height, 1, 0, format, null, SlimDX.Direct3D10.ResourceUsage.Staging, true, multiSampleCount, multiSampleQuality); } private void DisposeInternal() { if (this.ResourceView != null) this.ResourceView.Dispose(); this.ResourceView = null; if (this.resource != null) this.resource.Dispose(); this.resource = null; this.Texture2D = null; } private void CreateTexture(int width, int height, int mipLevels, int elements, SlimDX.DXGI.Format format, TextureInitialData initialData, SlimDX.Direct3D10.ResourceUsage accessType, bool renderTarget, int multiSampleCount, int multiSampleQuality) { Console.WriteLine(string.Format("Creating Texture ({0}x{1} {2})..", width, height, format.ToString())); this.DisposeInternal(); // calculate the needed amount of mipmap levels int mipMapLevels = 1; for (int tmp = Math.Min(height, width); tmp > 1; tmp /= 2, ++mipMapLevels); mipMapLevels = Math.Max(1, Math.Min(mipMapLevels, mipLevels == 0 ? mipMapLevels : mipLevels)); // create the resource var texDesc = new SlimDX.Direct3D10.Texture2DDescription(); texDesc.Width = width; texDesc.Height = height; texDesc.MipLevels = mipMapLevels; texDesc.ArraySize = Math.Max(1, elements); texDesc.Format = format; texDesc.SampleDescription = new SlimDX.DXGI.SampleDescription(multiSampleCount, multiSampleQuality); if (accessType == SlimDX.Direct3D10.ResourceUsage.Dynamic) { texDesc.Usage = SlimDX.Direct3D10.ResourceUsage.Dynamic; texDesc.CpuAccessFlags = SlimDX.Direct3D10.CpuAccessFlags.Write; } if (accessType == SlimDX.Direct3D10.ResourceUsage.Staging) texDesc.BindFlags = ((mipMapLevels > 1 || renderTarget) ? SlimDX.Direct3D10.BindFlags.RenderTarget : SlimDX.Direct3D10.BindFlags.None) | SlimDX.Direct3D10.BindFlags.ShaderResource; if (mipMapLevels > 1) texDesc.OptionFlags = SlimDX.Direct3D10.ResourceOptionFlags.GenerateMipMaps; resource = this.Texture2D = new SlimDX.Direct3D10.Texture2D(Engine.Device, texDesc); // create the resource view when possible if (accessType != SlimDX.Direct3D10.ResourceUsage.Staging) { var texViewDesc = new SlimDX.Direct3D10.ShaderResourceViewDescription(); texViewDesc.Format = texDesc.Format; texViewDesc.ElementWidth = elements; if (elements > 0) texViewDesc.Dimension = multiSampleCount == 1 ? SlimDX.Direct3D10.ShaderResourceViewDimension.Texture2DArray : SlimDX.Direct3D10.ShaderResourceViewDimension.Texture2DMultisampledArray; else texViewDesc.Dimension = multiSampleCount == 1 ? SlimDX.Direct3D10.ShaderResourceViewDimension.Texture2D : SlimDX.Direct3D10.ShaderResourceViewDimension.Texture2DMultisampled; texViewDesc.MostDetailedMip = 0; texViewDesc.MipLevels = texDesc.MipLevels; texViewDesc.ArraySize = elements; this.ResourceView = new SlimDX.Direct3D10.ShaderResourceView(Engine.Device, resource, texViewDesc); } // finalize this.TextureWidth = width; this.TextureHeight = height; this.TextureFormat = format; this.TextureArraySize = 1; this.BindingName = this.BindingName; } #region IDisposable Members public override void Dispose() { this.DisposeInternal(); base.Dispose(); } #endregion #endregion } }