Example #1
0
 protected override void Dispose(bool disposing)
 {
     Utilities.Dispose(ref _prefilteredCubeMap);
     Utilities.Dispose(ref _cubeMapRtv);
     Utilities.Dispose(ref _rasterizerState);
     base.Dispose(disposing);
 }
Example #2
0
        private void Update(EvaluationContext context)
        {
            if (!Gradients.IsConnected)
            {
                return;
            }

            var gradientsCount = Gradients.CollectedInputs.Count;

            if (gradientsCount == 0)
            {
                return;
            }

            const int sampleCount         = 256;
            const int entrySizeInBytes    = sizeof(float) * 4;
            const int gradientSizeInBytes = sampleCount * entrySizeInBytes;
            int       bufferSizeInBytes   = gradientsCount * gradientSizeInBytes;

            using (var dataStream = new DataStream(bufferSizeInBytes, true, true))
            {
                var texDesc = new Texture2DDescription()
                {
                    Width             = sampleCount,
                    Height            = gradientsCount,
                    ArraySize         = 1,
                    BindFlags         = BindFlags.ShaderResource,
                    Usage             = ResourceUsage.Default,
                    MipLevels         = 1,
                    CpuAccessFlags    = CpuAccessFlags.None,
                    Format            = Format.R32G32B32A32_Float,
                    SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
                };

                foreach (var gradientsInput in Gradients.CollectedInputs)
                {
                    var gradient = gradientsInput.GetValue(context);
                    if (gradient == null)
                    {
                        dataStream.Seek(gradientSizeInBytes, SeekOrigin.Current);
                        continue;
                    }

                    for (var sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
                    {
                        var sampledColor = gradient.Sample((float)sampleIndex / sampleCount);
                        dataStream.Write(sampledColor.X);
                        dataStream.Write(sampledColor.Y);
                        dataStream.Write(sampledColor.Z);
                        dataStream.Write(sampledColor.W);
                    }
                }
                //Curves.DirtyFlag.Clear();

                dataStream.Position = 0;
                var dataRectangles = new DataRectangle[] { new DataRectangle(dataStream.DataPointer, gradientSizeInBytes) };
                Utilities.Dispose(ref GradientsTexture.Value);
                GradientsTexture.Value = new Texture2D(ResourceManager.Instance().Device, texDesc, dataRectangles);
            }
        }
Example #3
0
        private void Update(EvaluationContext context)
        {
            // Parameters
            var parameterBufferContent = new PbrMaterialParams
            {
                BaseColor     = BaseColor.GetValue(context),
                EmissiveColor = EmissiveColor.GetValue(context),
                Roughness     = Roughness.GetValue(context),
                Specular      = Specular.GetValue(context),
                Metal         = Metal.GetValue(context)
            };

            ResourceManager.Instance().SetupConstBuffer(parameterBufferContent, ref _parameterBuffer);

            // Textures
            var resourceManager = ResourceManager.Instance();
            var device          = resourceManager.Device;

            Utilities.Dispose(ref _baseColorMapSrv);
            var tex = BaseColorMap.GetValue(context) ?? PbrContextSettings.WhitePixelTexture;

            _baseColorMapSrv = new ShaderResourceView(device, tex);
            context.PbrMaterialTextures.AlbedoColorMap = _baseColorMapSrv;

            Utilities.Dispose(ref _normalMapSrv);
            var tex2 = NormalMap.GetValue(context) ?? PbrContextSettings.NormalFallbackTexture;

            _normalMapSrv = new ShaderResourceView(device, tex2);
            context.PbrMaterialTextures.NormalMap = _normalMapSrv;

            Utilities.Dispose(ref _rsmoMapSrv);
            var tex3 = RoughnessSpecularMetallicOcclusionMap.GetValue(context) ?? PbrContextSettings.RsmoFallbackTexture;

            _rsmoMapSrv = new ShaderResourceView(device, tex3);
            context.PbrMaterialTextures.RoughnessSpecularMetallicOcclusionMap = _rsmoMapSrv;

            Utilities.Dispose(ref _emissiveColorMapSrv);
            var tex4 = EmissiveColorMap.GetValue(context) ?? PbrContextSettings.WhitePixelTexture;

            _emissiveColorMapSrv = new ShaderResourceView(device, tex4);
            context.PbrMaterialTextures.EmissiveColorMap = _emissiveColorMapSrv;

            var previousParameters = context.PbrMaterialParams;

            context.PbrMaterialParams = _parameterBuffer;


            SubTree.GetValue(context);
            context.PbrMaterialParams = previousParameters;
        }
Example #4
0
        private void Update(EvaluationContext context)
        {
            var filePath         = Filepath.GetValue(context);
            var filterCharacters = FilterCharacters.GetValue(context);
            var brightnessTable  = SortAsciiLetters(filePath, filterCharacters);

            if (brightnessTable == null)
            {
                return;
            }

            //Log.Debug("Generating texture");

            var       sampleCount       = brightnessTable.Length;
            const int entrySizeInBytes  = sizeof(float);
            var       listSizeInBytes   = sampleCount * entrySizeInBytes;
            var       bufferSizeInBytes = 1 * listSizeInBytes;

            using (var dataStream = new DataStream(bufferSizeInBytes, true, true))
            {
                var texDesc = new Texture2DDescription()
                {
                    Width             = sampleCount,
                    Height            = 1,
                    ArraySize         = 1,
                    BindFlags         = BindFlags.ShaderResource,
                    Usage             = ResourceUsage.Default,
                    MipLevels         = 1,
                    CpuAccessFlags    = CpuAccessFlags.None,
                    Format            = Format.R32_Float,
                    SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
                };

                var filterOutFactor = (256f - filterCharCount) / 256;
                for (var sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
                {
                    var index = (int)(sampleIndex * filterOutFactor).Clamp(0, sampleCount);
                    dataStream.Write((float)brightnessTable[index].Index / 256f);
                }

                dataStream.Position = 0;
                var dataRectangles = new DataRectangle[] { new DataRectangle(dataStream.DataPointer, listSizeInBytes) };
                Utilities.Dispose(ref MappingTexture.Value);

                MappingTexture.Value = new Texture2D(ResourceManager.Instance().Device, texDesc, dataRectangles);
            }
        }
Example #5
0
        private void Update(EvaluationContext context)
        {
            var param     = Params.GetCollectedTypedInputs();
            int arraySize = (param.Count / 4 + (param.Count % 4 == 0 ? 0 : 1)) * 4; // always 16byte slices for alignment
            var array     = new float[arraySize];

            if (array.Length == 0)
            {
                return;
            }

            for (int i = 0; i < param.Count; i++)
            {
                array[i] = param[i].GetValue(context);
            }

            Params.DirtyFlag.Clear();

            var resourceManager = ResourceManager.Instance();
            var device          = resourceManager.Device;

            var size = sizeof(float) * array.Length;

            using (var data = new DataStream(size, true, true))
            {
                data.WriteRange(array);
                data.Position = 0;

                if (Buffer.Value == null || Buffer.Value.Description.SizeInBytes != size)
                {
                    Utilities.Dispose(ref Buffer.Value);
                    var bufferDesc = new BufferDescription
                    {
                        Usage       = ResourceUsage.Default,
                        SizeInBytes = size,
                        BindFlags   = BindFlags.ConstantBuffer
                    };
                    Buffer.Value = new Buffer(device, data, bufferDesc);
                }
                else
                {
                    device.ImmediateContext.UpdateSubresource(new DataBox(data.DataPointer, 0, 0), Buffer.Value, 0);
                }
            }

            Buffer.Value.DebugName = nameof(FloatsToBuffer);
        }
Example #6
0
        private void Restore(EvaluationContext context)
        {
            var deviceContext = ResourceManager.Instance().Device.ImmediateContext;

            deviceContext.Rasterizer.SetViewports(_prevViewports, _prevViewports.Length);
            deviceContext.OutputMerger.BlendState = _prevBlendState;

            // Vertex shader
            var vsStage = deviceContext.VertexShader;

            vsStage.Set(_prevVertexShader);
            vsStage.SetConstantBuffers(0, _prevVsConstantBuffers.Length, _prevVsConstantBuffers);
            vsStage.SetShaderResources(0, _prevVsShaderResourceViews.Length, _prevVsShaderResourceViews);
            Utilities.Dispose(ref _prevVertexShader);

            // Vertex shader
            var gsStage = deviceContext.GeometryShader;

            gsStage.Set(_prevGeometryShader);
            gsStage.SetConstantBuffers(0, _prevGsConstantBuffers.Length, _prevGsConstantBuffers);
            gsStage.SetShaderResources(0, _prevGsShaderResourceViews.Length, _prevGsShaderResourceViews);
            Utilities.Dispose(ref _prevGeometryShader);

            // Pixel shader
            var psStage = deviceContext.PixelShader;

            psStage.Set(_prevPixelShader);
            psStage.SetConstantBuffers(0, _prevPsConstantBuffers.Length, _prevPsConstantBuffers);
            psStage.SetShaderResources(0, _prevPsShaderResourceViews.Length, _prevPsShaderResourceViews);
            psStage.SetSamplers(0, _prevPsSamplerStates.Length, _prevPsSamplerStates);
            Utilities.Dispose(ref _prevPixelShader);

            //deviceContext.OutputMerger.SetTargets(_previousRtv, null);

            if (_prevRenderTargetViews.Length > 0)
            {
                deviceContext.OutputMerger.SetRenderTargets(_prevDepthStencilView, _prevRenderTargetViews);
            }

            foreach (var rtv in _prevRenderTargetViews)
            {
                rtv?.Dispose();
            }

            Utilities.Dispose(ref _prevDepthStencilView);
        }
Example #7
0
        private float EdgeDf(SharpDX.Vector2 g, float a)
        {
            float df;

            if ((g.X == 0) || (g.Y == 0))
            {
                // Either A) gu or gv are zero, or B) both
                df = 0.5f - a; // Linear approximation is A) correct or B) a fair guess
            }
            else
            {
                float gradientLength = (float)Math.Sqrt(g.X * g.X + g.Y * g.Y);
                if (gradientLength > 0.0)
                {
                    g.X = g.X / gradientLength;
                    g.Y = g.Y / gradientLength;
                }

                g.X = Math.Abs(g.X);
                g.Y = Math.Abs(g.Y);
                if (g.X < g.Y)
                {
                    Utilities.Swap(ref g.X, ref g.Y);
                }

                float a1 = 0.5f * g.Y / g.X;
                if (a < a1)
                {
                    // 0 <= a < a1
                    df = 0.5f * (g.X + g.Y) - (float)Math.Sqrt(2.0f * g.X * g.Y * a);
                }
                else if (a < (1.0 - a1))
                {
                    // a1 <= a <= 1-a1
                    df = (0.5f - a) * g.X;
                }
                else
                {
                    // 1-a1 < a <= 1
                    df = -0.5f * (g.X + g.Y) + (float)Math.Sqrt(2.0f * g.X * g.Y * (1.0f - a));
                }
            }

            return(df);
        }
Example #8
0
 protected override void Dispose(bool disposing)
 {
     Utilities.Dispose(ref _queryTimeStampDisjoint);
     Utilities.Dispose(ref _queryTimeStampFrameBegin);
     Utilities.Dispose(ref _queryTimeStampFrameEnd);
 }
Example #9
0
        private void Update(EvaluationContext context)
        {
            var updateLive = UpdateLive.GetValue(context);

            if (_updatedOnce && !updateLive)
            {
                FilteredCubeMap.Value = _prefilteredCubeMap;
                return;
            }

            var exposure = Exposure.GetValue(context);

            //ConstantBuffers.GetValues(ref _constantBuffers, context);
            ShaderResources.GetValues(ref _shaderResourceViews, context);
            SamplerStates.GetValues(ref _samplerStates, context);

            var vs = VertexShader.GetValue(context);
            var gs = GeometryShader.GetValue(context);

            if (CubeMap.IsConnected && CubeMap.DirtyFlag.IsDirty)
            {
                //Log.Debug("Dirty");
            }

            var cubeMapSrc = CubeMap.GetValue(context); // Needs to be checked for null!

            if (cubeMapSrc == null)
            {
                FilteredCubeMap.Value = null;
                return;
            }

            var device        = ResourceManager.Instance().Device;
            var deviceContext = device.ImmediateContext;

            // Vertex shader stage
            var vsStage = deviceContext.VertexShader;

            _prevVsConstantBuffers     = vsStage.GetConstantBuffers(0, 1);
            _prevVsShaderResourceViews = vsStage.GetShaderResources(0, _shaderResourceViews.Length);
            _prevVertexShader          = vsStage.Get();

            if (vs == null)
            {
                Log.Warning($"{nameof(_SpecularPrefilter)} requires valid vertex shader", SymbolChildId);
                return;
            }
            vsStage.Set(vs);
            vsStage.SetShaderResources(0, _shaderResourceViews.Length, _shaderResourceViews);

            // Geometry shader stage
            var gsStage = deviceContext.GeometryShader;

            _prevGsConstantBuffers     = gsStage.GetConstantBuffers(0, 1);
            _prevGsShaderResourceViews = gsStage.GetShaderResources(0, _shaderResourceViews.Length);
            _prevGeometryShader        = gsStage.Get();

            if (gs == null)
            {
                Log.Warning($"{nameof(_SpecularPrefilter)} requires valid geometry shader", SymbolChildId);
                return;
            }

            gsStage.Set(gs);
            gsStage.SetShaderResources(0, _shaderResourceViews.Length, _shaderResourceViews);

            // Pixel shader stage
            var psStage = deviceContext.PixelShader;

            _prevPixelShader           = psStage.Get();
            _prevPsConstantBuffers     = psStage.GetConstantBuffers(0, 1);
            _prevPsShaderResourceViews = psStage.GetShaderResources(0, _shaderResourceViews.Length);
            _prevPsSamplerStates       = psStage.GetSamplers(0, _samplerStates.Length);

            var ps = PixelShader.GetValue(context);

            if (ps == null)
            {
                Log.Warning($"{nameof(_SpecularPrefilter)} requires valid pixel shader", SymbolChildId);
                return;
            }
            psStage.Set(ps);
            psStage.SetShaderResources(0, _shaderResourceViews.Length, _shaderResourceViews);
            psStage.SetSamplers(0, _samplerStates);


            // if (_prefilteredCubeMap != null && !Changed)
            // {
            //     context.Image = _prefilteredCubeMap;
            //     return context;
            // }

            Vector2 cubeMapSize = new Vector2(cubeMapSrc.Description.Width, cubeMapSrc.Description.Height);
            // Log.Debug($"source size: {cubeMapSrc.Description.Width} num mips in src: {cubeMapSrc.Description.MipLevels}");

            // if ( _prefilteredCubeMap == null )
            // {
            var cubeMapDesc = new Texture2DDescription
            {
                BindFlags         = BindFlags.ShaderResource | BindFlags.RenderTarget,
                Format            = cubeMapSrc.Description.Format,
                Width             = (int)cubeMapSize.X,
                Height            = (int)cubeMapSize.Y,
                MipLevels         = cubeMapSrc.Description.MipLevels,
                SampleDescription = cubeMapSrc.Description.SampleDescription,
                Usage             = ResourceUsage.Default,
                OptionFlags       = ResourceOptionFlags.TextureCube | ResourceOptionFlags.GenerateMipMaps,
                CpuAccessFlags    = CpuAccessFlags.None,
                ArraySize         = 6
            };

            Utilities.Dispose(ref _prefilteredCubeMap);
            try
            {
                _prefilteredCubeMap = new Texture2D(device, cubeMapDesc);
            }
            catch (SharpDXException e)
            {
                Log.Debug($"can't create CubeMap target {e.Message}");
                return;
            }

            var rastDesc = new RasterizerStateDescription
            {
                FillMode           = FillMode.Solid,
                CullMode           = CullMode.None,
                IsDepthClipEnabled = false
            };

            _rasterizerState = new RasterizerState(device, rastDesc);

            // Input Assembler
            var previousTopology = device.ImmediateContext.InputAssembler.PrimitiveTopology;

            device.ImmediateContext.InputAssembler.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList;

            _prevBlendState = device.ImmediateContext.OutputMerger.GetBlendState(out _prevBlendFactor, out _prevSampleMask);
            device.ImmediateContext.OutputMerger.BlendState        = DefaultRenderingStates.DisabledBlendState;
            device.ImmediateContext.OutputMerger.DepthStencilState = DefaultRenderingStates.DisabledDepthStencilState;

            _prevRenderTargetViews = device.ImmediateContext.OutputMerger.GetRenderTargets(1);
            device.ImmediateContext.OutputMerger.GetRenderTargets(out _prevDepthStencilView);

            var rtvDesc = new RenderTargetViewDescription()
            {
                Dimension      = RenderTargetViewDimension.Texture2DArray,
                Format         = cubeMapSrc.Description.Format,
                Texture2DArray = new RenderTargetViewDescription.Texture2DArrayResource()
                {
                    ArraySize       = 6,
                    FirstArraySlice = 0,
                    MipSlice        = 0
                }
            };

            int size = _prefilteredCubeMap.Description.Width;

            _prevViewports = device.ImmediateContext.Rasterizer.GetViewports <RawViewportF>();

            device.ImmediateContext.Rasterizer.State = _rasterizerState;

            int numMipLevels = _prefilteredCubeMap.Description.MipLevels;
            int mipSlice     = 0;

            while (mipSlice < numMipLevels)
            {
                // Log.Debug($"Update mipmap level {mipSlice} size: {size}");
                var viewport = new RawViewportF {
                    X = 0, Y = 0, Width = size, Height = size, MinDepth = 0, MaxDepth = 1
                };
                device.ImmediateContext.Rasterizer.SetViewports(new[] { viewport });


                Utilities.Dispose(ref _cubeMapRtv);
                rtvDesc.Texture2DArray.MipSlice = mipSlice;
                _cubeMapRtv = new RenderTargetView(device, _prefilteredCubeMap, rtvDesc);
                device.ImmediateContext.OutputMerger.SetTargets(_cubeMapRtv, null);

                var roughness = (float)mipSlice / (_prefilteredCubeMap.Description.MipLevels - 1);

                // Is this required?
                if (_settingsBuffer != null)
                {
                    Utilities.Dispose(ref _settingsBuffer);
                }

                for (int i = 0; i < _samplingParameters.Length; ++i)
                {
                    int indexToUse = -1;
                    if (Math.Abs(roughness - _samplingParameters[i].roughness) < 0.001f)
                    {
                        indexToUse = i;
                    }

                    if (indexToUse == -1 && roughness < _samplingParameters[i].roughness)
                    {
                        indexToUse = i - 1;
                    }

                    if (indexToUse != -1)
                    {
                        var parameterData = _samplingParameters[indexToUse];
                        parameterData.roughness = roughness;
                        parameterData.exposure  = exposure;
                        ResourceManager.Instance().SetupConstBuffer(parameterData, ref _settingsBuffer);
                        break;
                    }
                }

                var constantBuffers = new[] { _settingsBuffer };
                psStage.SetConstantBuffers(0, 1, constantBuffers);
                vsStage.SetConstantBuffers(0, 1, constantBuffers);
                gsStage.SetConstantBuffers(0, 1, constantBuffers);

                device.ImmediateContext.Draw(3, 0);
                size /= 2;
                ++mipSlice;
            }

            FilteredCubeMap.Value = _prefilteredCubeMap;
            Utilities.Dispose(ref _cubeMapRtv);

            //device.ImmediateContext.InputAssembler.PrimitiveTopology = previousTopology;
            Restore(context);
            _updatedOnce = true;
        }
Example #10
0
        private void Update(EvaluationContext context)
        {
            _curves.Clear();
            if (Curves.IsConnected)
            {
                foreach (var curveInput in Curves.CollectedInputs)
                {
                    var curve = curveInput.GetValue(context);
                    if (curve == null)
                    {
                        continue;
                    }

                    _curves.Add(curve);
                }
            }
            else
            {
                if (Curves.Value != null)
                {
                    _curves.Add(Curves.Value);
                }
            }

            var curveCount = _curves.Count;

            if (curveCount == 0)
            {
                return;
            }

            const int sampleCount       = 256;
            const int entrySizeInBytes  = sizeof(float);
            const int curveSizeInBytes  = sampleCount * entrySizeInBytes;
            int       bufferSizeInBytes = curveCount * curveSizeInBytes;

            using (var dataStream = new DataStream(bufferSizeInBytes, true, true))
            {
                var texDesc = new Texture2DDescription()
                {
                    Width             = sampleCount,
                    Height            = curveCount,
                    ArraySize         = 1,
                    BindFlags         = BindFlags.ShaderResource,
                    Usage             = ResourceUsage.Default,
                    MipLevels         = 1,
                    CpuAccessFlags    = CpuAccessFlags.None,
                    Format            = Format.R32_Float,
                    SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
                };

                foreach (var curve in _curves)
                {
                    // var curve = curveInput.GetValue(context);
                    // if (curve == null)
                    // {
                    //     dataStream.Seek(curveSizeInBytes, SeekOrigin.Current);
                    //     continue;
                    // }

                    for (var sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
                    {
                        dataStream.Write((float)curve.GetSampledValue((float)sampleIndex / sampleCount));
                    }
                }
                //Curves.DirtyFlag.Clear();

                dataStream.Position = 0;
                var dataRectangles = new DataRectangle[] { new DataRectangle(dataStream.DataPointer, curveSizeInBytes) };
                Utilities.Dispose(ref CurveTexture.Value);
                CurveTexture.Value = new Texture2D(ResourceManager.Instance().Device, texDesc, dataRectangles);
            }
        }
Example #11
0
        private void Update(EvaluationContext context)
        {
            if (!Values.IsConnected)
            {
                return;
            }

            var values = Values.GetValue(context);

            if (values == null || values.Count == 0)
            {
                return;
            }


            int rangeStart = RangeStart.GetValue(context).Clamp(0, values.Count - 1);
            int rangeEnd   = RangeEnd.GetValue(context).Clamp(0, values.Count - 1);

            float gain = Gain.GetValue(context);
            float pow  = Pow.GetValue(context);

            if (Math.Abs(pow) < 0.001f)
            {
                return;
            }


            if (rangeEnd < rangeStart)
            {
                var tmp = rangeEnd;
                rangeEnd   = rangeStart;
                rangeStart = tmp;
            }

            int sampleCount       = (rangeEnd - rangeStart) + 1;
            int entrySizeInBytes  = sizeof(float);
            int listSizeInBytes   = sampleCount * entrySizeInBytes;
            int bufferSizeInBytes = 1 * listSizeInBytes;


            using (var dataStream = new DataStream(bufferSizeInBytes, true, true))
            {
                var texDesc = new Texture2DDescription()
                {
                    Width             = sampleCount,
                    Height            = 1,
                    ArraySize         = 1,
                    BindFlags         = BindFlags.ShaderResource,
                    Usage             = ResourceUsage.Default,
                    MipLevels         = 1,
                    CpuAccessFlags    = CpuAccessFlags.None,
                    Format            = Format.R32_Float,
                    SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
                };

                //foreach (var curveInput in Curves.CollectedInputs)
                //{
                // var curve = curveInput.GetValue(context);
                // if (curve == null)
                // {
                //     dataStream.Seek(curveSizeInBytes, SeekOrigin.Current);
                //     continue;
                // }

                for (var sampleIndex = rangeStart; sampleIndex <= rangeEnd; sampleIndex++)
                {
                    //dataStream.Write((float)curve.GetSampledValue((float)sampleIndex / sampleCount));
                    float v = (float)Math.Pow(values[sampleIndex] * gain, pow);
                    dataStream.Write(v);
                }
                //}
                //Curves.DirtyFlag.Clear();

                dataStream.Position = 0;
                var dataRectangles = new DataRectangle[] { new DataRectangle(dataStream.DataPointer, listSizeInBytes) };
                Utilities.Dispose(ref CurveTexture.Value);
                CurveTexture.Value = new Texture2D(ResourceManager.Instance().Device, texDesc, dataRectangles);
            }
        }
Example #12
0
        private void Update(EvaluationContext context)
        {
            var image    = InputImage.GetValue(context);
            var imageSrv = InputImageSrv.GetValue(context);

            if (image == null)
            {
                Log.Debug("input not completet");
                return;
            }

            var d3DDevice        = ResourceManager.Instance().Device;
            var immediateContext = d3DDevice.ImmediateContext;

            if (_imageWithCPUAccess == null ||
                _imageWithCPUAccess.Description.Format != image.Description.Format ||
                _imageWithCPUAccess.Description.Width != image.Description.Width ||
                _imageWithCPUAccess.Description.Height != image.Description.Height ||
                _imageWithCPUAccess.Description.MipLevels != image.Description.MipLevels)
            {
                var desc = new Texture2DDescription()
                {
                    BindFlags         = BindFlags.None,
                    Format            = image.Description.Format,
                    Width             = image.Description.Width,
                    Height            = image.Description.Height,
                    MipLevels         = image.Description.MipLevels,
                    SampleDescription = new SampleDescription(1, 0),
                    Usage             = ResourceUsage.Staging,
                    OptionFlags       = ResourceOptionFlags.None,
                    CpuAccessFlags    = CpuAccessFlags.Read,
                    ArraySize         = 1
                };
                Utilities.Dispose(ref _imageWithCPUAccess);
                _imageWithCPUAccess = new Texture2D(d3DDevice, desc);
            }

            if (_distanceFieldImage == null ||
                _distanceFieldImage.Description.Format != image.Description.Format ||
                _distanceFieldImage.Description.Width != image.Description.Width ||
                _distanceFieldImage.Description.Height != image.Description.Height ||
                _distanceFieldImage.Description.MipLevels != image.Description.MipLevels)
            {
                var desc = new Texture2DDescription()
                {
                    BindFlags         = BindFlags.ShaderResource,
                    Format            = image.Description.Format,
                    Width             = image.Description.Width,
                    Height            = image.Description.Height,
                    MipLevels         = 1,
                    SampleDescription = new SampleDescription(1, 0),
                    Usage             = ResourceUsage.Dynamic,
                    OptionFlags       = ResourceOptionFlags.None,
                    CpuAccessFlags    = CpuAccessFlags.Write,
                    ArraySize         = 1
                };
                Utilities.Dispose(ref _distanceFieldImage);
                _distanceFieldImage = new Texture2D(d3DDevice, desc);
            }

            // if (Changed)
            {
                immediateContext.CopyResource(image, _imageWithCPUAccess);
                int width  = image.Description.Width;
                int height = image.Description.Height;

                if (_data == null || _data.Length != width * height)
                {
                    _data      = new float[width * height];
                    _xDist     = new short[width * height];
                    _yDist     = new short[width * height];
                    _gradients = new SharpDX.Vector2[width * height];
                }

                DataStream sourceStream;
                var        sourceDataBox =
                    immediateContext.MapSubresource(_imageWithCPUAccess, 0, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None, out sourceStream);

                // Convert img into float (data)
                using (sourceStream)
                {
                    sourceStream.Position = 0;
                    float minValue = 255, maxValue = -255;
                    for (int y = 0; y < height; ++y)
                    {
                        for (int x = 0; x < width; ++x)
                        {
                            var   color = new Color4(sourceStream.Read <Int32>());
                            float v     = color.Red;
                            _data[y * width + x] = v;
                            if (v > maxValue)
                            {
                                maxValue = v;
                            }
                            if (v < minValue)
                            {
                                minValue = v;
                            }
                        }

                        sourceStream.Position += sourceDataBox.RowPitch - width * 4;
                    }

                    // Rescale image levels between 0 and 1
                    for (int i = 0; i < width * height; ++i)
                    {
                        _data[i] = (_data[i] - minValue) / maxValue;
                    }

                    // transform background (black pixels)
                    ComputeGradient(_data, width, height);
                    var outside = Edtaa3(_data, height, width);

                    // transform forground (white pixels)
                    for (int i = 0; i < width * height; ++i)
                    {
                        _data[i] = 1 - _data[i]; // invert input
                    }
                    ComputeGradient(_data, width, height);
                    var inside = Edtaa3(_data, height, width);

                    // write resulting distance field to target texture
                    DataStream destinationStream;
                    var        destinationDataBox = immediateContext.MapSubresource(_distanceFieldImage, 0, 0, MapMode.WriteDiscard,
                                                                                    SharpDX.Direct3D11.MapFlags.None, out destinationStream);
                    using (destinationStream)
                    {
                        sourceStream.Position      = 0;
                        destinationStream.Position = 0;
                        for (int y = 0; y < height; y++)
                        {
                            for (int x = 0; x < width; x++)
                            {
                                int i = y * width + x;
                                // distmap = outside - inside; % Bipolar distance field
                                var color = new Color4(sourceStream.Read <Int32>());
                                outside[i] = MathUtils.Clamp(128.0f + (outside[i] - inside[i]) * 16.0f, 0.0f, 255.0f);
                                //color.Alpha = (255 - (byte) outside[i])/255.0f;
                                float f = (255 - (byte)outside[i]) / 255.0f;
                                color.Red   = f;
                                color.Blue  = f;
                                color.Green = f;
                                float alpha = 1 - _data[i];
                                {
                                    // do alpha dilatation
                                    const int range = 1;
                                    int       xs    = Math.Max(x - range, 0);
                                    int       xe    = Math.Min(x + range, width - 1);
                                    int       ys    = Math.Max(y - range, 0);
                                    int       ye    = Math.Min(y + range, height - 1);
                                    for (int yy = ys; yy <= ye; yy++)
                                    {
                                        for (int xx = xs; xx <= xe; xx++)
                                        {
                                            alpha = Math.Max(alpha, 1 - _data[yy * width + xx]);
                                        }
                                    }
                                }

                                color.Alpha = alpha;// * 0.8f; // > 0.0f ? 0.5f : 0;

                                destinationStream.Write(color.ToRgba());
                            }

                            destinationStream.Position += destinationDataBox.RowPitch - width * 4;
                        }

                        immediateContext.UnmapSubresource(_distanceFieldImage, 0);
                    }

                    immediateContext.UnmapSubresource(_imageWithCPUAccess, 0);
                }

                // Changed = false;
            }

            Output.Value = _distanceFieldImage;
        }