/// <summary>
 /// Function to create an array of System.Drawing.Images from a given texture.
 /// </summary>
 /// <param name="texture">Texture to evaluate.</param>
 /// <returns>A list of GDI+ images.</returns>
 public static Image[] CreateGDIImagesFromTexture(GorgonTexture texture)
 {
     using (var data = GorgonImageData.CreateFromTexture(texture))
     {
         return(CreateGDIImagesFromImageData(data));
     }
 }
Beispiel #2
0
        /// <summary>
        /// Function to initialize the texture with optional initial data.
        /// </summary>
        /// <param name="initialData">Data used to populate the image.</param>
        protected override void OnInitialize(GorgonImageData initialData)
        {
            var shaderBind = Settings.AllowShaderView ? BindFlags.ShaderResource : BindFlags.None;

            var desc = new Texture2DDescription
            {
                ArraySize         = Settings.ArrayCount,
                BindFlags         = GetBindFlags(true, false) | shaderBind,
                CpuAccessFlags    = CpuAccessFlags.None,
                Format            = Settings.AllowShaderView ? (Format)Settings.TextureFormat : (Format)Settings.Format,
                Height            = Settings.Height,
                Width             = Settings.Width,
                MipLevels         = Settings.MipCount,
                OptionFlags       = ResourceOptionFlags.None,
                SampleDescription = GorgonMultisampling.Convert(Settings.Multisampling)
            };

            Gorgon.Log.Print("{0} {1}: Creating 2D depth/stencil texture...", LoggingLevel.Verbose, GetType().Name, Name);

            // Create the texture.
            D3DResource = initialData != null
                                                          ? new Texture2D(Graphics.D3DDevice, desc, initialData.Buffers.DataBoxes)
                                              : new Texture2D(Graphics.D3DDevice, desc);

            GorgonRenderStatistics.DepthBufferCount++;
            GorgonRenderStatistics.DepthBufferSize += SizeInBytes;

            InitializeResourceViews();

            _defaultView = GetDepthStencilView(Settings.Format, 0, 0, 1, Settings.DefaultDepthStencilViewFlags);
        }
Beispiel #3
0
        /// <summary>
        /// Function to initialize the texture with optional initial data.
        /// </summary>
        /// <param name="initialData">Data used to populate the image.</param>
        protected override void OnInitialize(GorgonImageData initialData)
        {
            var desc = new D3D.Texture2DDescription
            {
                ArraySize         = Settings.ArrayCount,
                Format            = (GI.Format)Settings.Format,
                Width             = Settings.Width,
                Height            = Settings.Height,
                MipLevels         = Settings.MipCount,
                BindFlags         = GetBindFlags(false, false),
                Usage             = (D3D.ResourceUsage)Settings.Usage,
                OptionFlags       = Settings.IsTextureCube ? D3D.ResourceOptionFlags.TextureCube : D3D.ResourceOptionFlags.None,
                SampleDescription = GorgonMultisampling.Convert(Settings.Multisampling)
            };

            switch (Settings.Usage)
            {
            case BufferUsage.Staging:
                desc.CpuAccessFlags = D3D.CpuAccessFlags.Read | D3D.CpuAccessFlags.Write;
                break;

            case BufferUsage.Dynamic:
                desc.CpuAccessFlags = D3D.CpuAccessFlags.Write;
                break;

            default:
                desc.CpuAccessFlags = D3D.CpuAccessFlags.None;
                break;
            }

            D3DResource = initialData != null
                                                          ? new D3D.Texture2D(Graphics.D3DDevice, desc, initialData.Buffers.DataBoxes)
                                      : new D3D.Texture2D(Graphics.D3DDevice, desc);
        }
Beispiel #4
0
        /// <summary>
        /// Funciton to generate random noise for the effect.
        /// </summary>
        private void GenerateRandomNoise()
        {
            int    textureSize = 128;
            object parameter;

            if ((Parameters.TryGetValue("TextureSize", out parameter)) &&
                (parameter != null))
            {
                var size = (int)parameter;

                if (size > 16)
                {
                    textureSize = size;
                }
            }

            using (var image = new GorgonImageData(new GorgonTexture2DSettings
            {
                Width = textureSize,
                Height = textureSize,
                Format = BufferFormat.R8_UIntNormal,
                Usage = BufferUsage.Default
            }))
            {
                unsafe
                {
                    var dataPtr = (byte *)image.Buffers[0].Data.UnsafePointer;

                    // Write perlin noise to the texture.
                    for (int y = 0; y < textureSize; ++y)
                    {
                        for (int x = 0; x < textureSize; ++x)
                        {
                            float simplexNoise = GorgonRandom.SimplexNoise(new Vector2(x * (1.0f / _noiseFrequency), y * (1.0f / _noiseFrequency)));

                            if (simplexNoise < -0.75f)
                            {
                                simplexNoise *= -1;
                            }
                            else
                            {
                                simplexNoise *= 0.95f;
                            }

                            if (simplexNoise < 0.125f)
                            {
                                simplexNoise = 0.0f;
                            }

                            *(dataPtr++) = (byte)(simplexNoise * 255.0f);
                        }
                    }
                }

                _randomTexture = Graphics.Textures.CreateTexture <GorgonTexture2D>("Effect.OldFilm.RandomTexture", image);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Function to create a list of buffers to use.
        /// </summary>
        /// <param name="data">Data to copy/reference.</param>
        internal unsafe void CreateBuffers(byte *data)
        {
            int bufferIndex = 0;
            var formatInfo  = GorgonBufferFormatInfo.GetInfo(_image.Settings.Format);                   // Format information.

            // Allocate enough room for the array and mip levels.
            _buffers = new GorgonImageBuffer[GorgonImageData.GetDepthSliceCount(_image.Settings.Depth, _image.Settings.MipCount) * _image.Settings.ArrayCount];

            MipOffsetSize = new Tuple <int, int> [_image.Settings.MipCount * _image.Settings.ArrayCount];               // Offsets for the mip maps.
            DataBoxes     = new DX.DataBox[_image.Settings.ArrayCount * _image.Settings.MipCount];                      // Create the data boxes for textures.

            // Enumerate array indices. (For 1D and 2D only, 3D will always be 1)
            for (int array = 0; array < _image.Settings.ArrayCount; array++)
            {
                int mipWidth  = _image.Settings.Width;
                int mipHeight = _image.Settings.Height;
                int mipDepth  = _image.Settings.Depth;

                // Enumerate mip map levels.
                for (int mip = 0; mip < _image.Settings.MipCount; mip++)
                {
                    int arrayIndex       = mip + (array * _image.Settings.MipCount);
                    var pitchInformation = formatInfo.GetPitch(mipWidth, mipHeight, PitchFlags.None);

                    // Get data box for texture upload.
                    DataBoxes[arrayIndex] = new DX.DataBox(new IntPtr(data), pitchInformation.RowPitch, pitchInformation.SlicePitch);

                    // Calculate buffer offset by mip.
                    MipOffsetSize[arrayIndex] = new Tuple <int, int>(bufferIndex, mipDepth);

                    // Enumerate depth slices.
                    for (int depth = 0; depth < mipDepth; depth++)
                    {
                        // Get mip information.
                        _buffers[bufferIndex] = new GorgonImageBuffer(data, pitchInformation, mip, array, depth, mipWidth, mipHeight,
                                                                      mipDepth, _image.Settings.Format);

                        data += pitchInformation.SlicePitch;
                        bufferIndex++;
                    }

                    if (mipWidth > 1)
                    {
                        mipWidth >>= 1;
                    }
                    if (mipHeight > 1)
                    {
                        mipHeight >>= 1;
                    }
                    if (mipDepth > 1)
                    {
                        mipDepth >>= 1;
                    }
                }
            }
        }
        /// <summary>
        /// Function to create 2D Gorgon image data from a single System.Drawing.Image.
        /// </summary>
        /// <param name="wic">Windows Imaging Component interface to use.</param>
        /// <param name="image">An image to convert.</param>
        /// <param name="options">Options for conversion.</param>
        /// <returns>The converted image data.</returns>
        public static GorgonImageData Create2DImageDataFromImage(GorgonWICImage wic, Image image, GorgonGDIOptions options)
        {
            if (options.Format == BufferFormat.Unknown)
            {
                options.Format = GetBufferFormat(image.PixelFormat);
            }

            if (options.Format == BufferFormat.Unknown)
            {
                throw new GorgonException(GorgonResult.FormatNotSupported,
                                          string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, image.PixelFormat));
            }

            if (options.Width < 1)
            {
                options.Width = image.Width;
            }

            if (options.Height < 1)
            {
                options.Height = image.Height;
            }

            // Specify 0 to generate a full mip chain.
            options.MipCount = options.MipCount < 1
                                                   ? GorgonImageData.GetMaxMipCount(options.Width, options.Height)
                                                   : options.MipCount.Min(GorgonImageData.GetMaxMipCount(options.Width, options.Height));

            // Create our settings.
            var settings = new GorgonTexture2DSettings
            {
                Width      = options.Width,
                Height     = options.Height,
                MipCount   = options.MipCount,
                ArrayCount = 1,
                Format     = options.Format,
                AllowUnorderedAccessViews = options.AllowUnorderedAccess,
                ShaderViewFormat          = options.ViewFormat,
                Usage = options.Usage
            };

            // Create our image data.
            var data = new GorgonImageData(settings);

            // Using the image, convert to a WIC bitmap object.
            using (Bitmap bitmap = wic.CreateWICImageFromImage(image))
            {
                for (int mipLevel = 0; mipLevel < options.MipCount; mipLevel++)
                {
                    var buffer = data.Buffers[mipLevel];
                    wic.AddWICBitmapToImageData(bitmap, options.Filter, options.Dither, buffer, options.UseClipping);
                }
            }

            return(data);
        }
Beispiel #7
0
        /// <summary>
        /// Function to read the data from a frame.
        /// </summary>
        /// <param name="wic">WIC interface.</param>
        /// <param name="data">Image data to populate.</param>
        /// <param name="srcFormat">Source image format.</param>
        /// <param name="convertFormat">Conversion format.</param>
        /// <param name="frame">Frame containing the image data.</param>
        private void ReadFrame(GorgonWICImage wic, GorgonImageData data, Guid srcFormat, Guid convertFormat, BitmapFrameDecode frame)
        {
            var buffer = data.Buffers[0];

            // We don't need to convert, so just leave.
            if ((convertFormat == Guid.Empty) || (srcFormat == convertFormat))
            {
                frame.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch);
                return;
            }

            // Perform conversion.
            using (var converter = new FormatConverter(wic.Factory))
            {
                bool isIndexed = ((frame.PixelFormat == PixelFormat.Format8bppIndexed) ||
                                  (frame.PixelFormat == PixelFormat.Format4bppIndexed) ||
                                  (frame.PixelFormat == PixelFormat.Format2bppIndexed) ||
                                  (frame.PixelFormat == PixelFormat.Format1bppIndexed));
                Tuple <Palette, double, BitmapPaletteType> paletteInfo = null;

                try
                {
                    // If the pixel format is indexed, then retrieve a palette.
                    if (isIndexed)
                    {
                        paletteInfo = GetPaletteInfo(wic, null);
                    }

                    // If we've defined a palette for an indexed image, then copy it to a bitmap and set its palette.
                    if ((paletteInfo != null) && (paletteInfo.Item1 != null))
                    {
                        using (var tempBitmap = new Bitmap(wic.Factory, frame, BitmapCreateCacheOption.CacheOnDemand))
                        {
                            tempBitmap.Palette = paletteInfo.Item1;
                            converter.Initialize(tempBitmap, convertFormat, (BitmapDitherType)Dithering, paletteInfo.Item1, paletteInfo.Item2, paletteInfo.Item3);
                            converter.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch);
                        }

                        return;
                    }

                    // Only apply palettes to indexed image data.
                    converter.Initialize(frame, convertFormat, (BitmapDitherType)Dithering, null, 0.0, BitmapPaletteType.Custom);
                    converter.CopyPixels(buffer.PitchInformation.RowPitch, buffer.Data.BasePointer, buffer.PitchInformation.SlicePitch);
                }
                finally
                {
                    if ((paletteInfo != null) && (paletteInfo.Item1 != null))
                    {
                        paletteInfo.Item1.Dispose();
                    }
                }
            }
        }
        /// <summary>
        /// Function to create an array of System.Drawing.Images from an image data object.
        /// </summary>
        /// <param name="imageData">Image data to process.</param>
        /// <returns>A list of GDI+ images.</returns>
        public static Image[] CreateGDIImagesFromImageData(GorgonImageData imageData)
        {
            PixelFormat?format = GetPixelFormat(imageData.Settings.Format);

            Bitmap[] bitmaps = null;
            Image[]  images;

            if (format == null)
            {
                format = GetPixelFormat(imageData.Settings.Format);

                if (format == null)
                {
                    throw new GorgonException(GorgonResult.FormatNotSupported,
                                              string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, imageData.Settings.Format));
                }
            }

            using (var wic = new GorgonWICImage())
            {
                try
                {
                    bitmaps = wic.CreateWICBitmapsFromImageData(imageData);
                    images  = new Image[bitmaps.Length];

                    for (int i = 0; i < bitmaps.Length; i++)
                    {
                        images[i] = wic.CreateGDIImageFromWICBitmap(bitmaps[i], format.Value);
                    }
                }
                finally
                {
                    // Clean up.
                    if (bitmaps != null)
                    {
                        foreach (var bitmap in bitmaps)
                        {
                            bitmap.Dispose();
                        }
                    }
                }
            }

            return(images);
        }
Beispiel #9
0
        public void Test2ViewsSameShaderStage()
        {
            GorgonTexture2D texture = null;

            _framework.CreateTestScene(Shaders, Shaders, true);

            try
            {
                using (var data = new GorgonImageData(new GorgonTexture2DSettings
                {
                    Width = 256,
                    Height = 256,
                    ArrayCount = 1,
                    Format = BufferFormat.R8G8B8A8,
                    MipCount = 1,
                    ShaderViewFormat = BufferFormat.R8G8B8A8_Int,
                    AllowUnorderedAccessViews = false,
                    Usage = BufferUsage.Default
                }))
                {
                    for (int i = 0; i < 5000; i++)
                    {
                        data.Buffers[0].Data.Position = ((GorgonRandom.RandomInt32(0, 256) * data.Buffers[0].PitchInformation.RowPitch)
                                                         + GorgonRandom.RandomInt32(0, 256) * 4);
                        data.Buffers[0].Data.Write((int)((GorgonRandom.RandomSingle() * 2.0f - 1.0f) * (Int32.MaxValue - 2)));
                    }

                    texture = _framework.Graphics.Textures.CreateTexture <GorgonTexture2D>("Test2D", data);
                }

                GorgonTextureShaderView view = texture.GetShaderView(BufferFormat.R8G8B8A8_UIntNormal);

                _framework.Graphics.Shaders.PixelShader.Resources[0] = texture;
                _framework.Graphics.Shaders.PixelShader.Resources[1] = view;

                Assert.IsTrue(_framework.Run() == DialogResult.Yes);
            }
            finally
            {
                if (texture != null)
                {
                    texture.Dispose();
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Function to load an image from a stream.
        /// </summary>
        /// <param name="stream">Stream containing the data to load.</param>
        /// <param name="size">Size of the data to read, in bytes.</param>
        /// <returns>
        /// The image data that was in the stream.
        /// </returns>
        protected internal override GorgonImageData LoadFromStream(GorgonDataStream stream, int size)
        {
            GorgonImageData    imageData = null;
            TGAConversionFlags flags;

            if (DirectAccess.SizeOf <TGAHeader>() > size)
            {
                throw new EndOfStreamException(Resources.GORGFX_STREAM_EOF);
            }

            // Read the header information.
            IImageSettings settings = ReadHeader(stream, out flags);

            if (ArrayCount > 1)
            {
                settings.ArrayCount = ArrayCount;
            }

            try
            {
                // Create our image data structure.
                imageData = new GorgonImageData(settings);

                // Copy the data from the stream to the buffer.
                CopyImageData(stream, imageData, flags);
            }
            catch
            {
                // Clean up any memory allocated if we can't copy the image.
                if (imageData != null)
                {
                    imageData.Dispose();
                }

                throw;
            }

            return(imageData);
        }
Beispiel #11
0
        /// <summary>
        /// Function to initialize the texture with optional initial data.
        /// </summary>
        /// <param name="initialData">Data used to populate the image.</param>
        protected override void OnInitialize(GorgonImageData initialData)
        {
            if ((Settings.Format != BufferFormat.Unknown) && (Settings.TextureFormat == BufferFormat.Unknown))
            {
                Settings.TextureFormat = Settings.Format;
            }

            var desc = new D3D.Texture2DDescription
            {
                ArraySize         = Settings.ArrayCount,
                Format            = (GI.Format)Settings.TextureFormat,
                Width             = Settings.Width,
                Height            = Settings.Height,
                MipLevels         = Settings.MipCount,
                BindFlags         = GetBindFlags(false, true),
                Usage             = D3D.ResourceUsage.Default,
                CpuAccessFlags    = D3D.CpuAccessFlags.None,
                OptionFlags       = D3D.ResourceOptionFlags.None,
                SampleDescription = GorgonMultisampling.Convert(Settings.Multisampling)
            };

            Gorgon.Log.Print("{0} {1}: Creating 2D render target texture...", LoggingLevel.Verbose, GetType().Name, Name);

            // Create the texture.
            D3DResource = initialData != null
                                                          ? new D3D.Texture2D(Graphics.D3DDevice, desc, initialData.Buffers.DataBoxes)
                                                          : new D3D.Texture2D(Graphics.D3DDevice, desc);

            // Create the default render target view.
            _defaultRenderTargetView = GetRenderTargetView(Settings.Format, 0, 0, 1);

            GorgonRenderStatistics.RenderTargetCount++;
            GorgonRenderStatistics.RenderTargetSize += SizeInBytes;

            CreateDepthStencilBuffer();

            // Set default viewport.
            Viewport = new GorgonViewport(0, 0, Settings.Width, Settings.Height, 0.0f, 1.0f);
        }
Beispiel #12
0
        /// <summary>
        /// Function to create an image with initial data.
        /// </summary>
        /// <param name="initialData">Data to use when creating the image.</param>
        /// <remarks>
        /// The <paramref name="initialData" /> can be NULL (Nothing in VB.Net) IF the texture is not created with an Immutable usage flag.
        /// <para>To initialize the texture, create a new <see cref="GorgonLibrary.Graphics.GorgonImageData">GorgonImageData</see> object and fill it with image information.</para>
        /// </remarks>
        protected override void OnInitialize(GorgonImageData initialData)
        {
            var desc = new D3D.Texture3DDescription
            {
                Format      = (Format)Settings.Format,
                Width       = Settings.Width,
                Height      = Settings.Height,
                Depth       = Settings.Depth,
                MipLevels   = Settings.MipCount,
                BindFlags   = GetBindFlags(false, false),
                Usage       = (D3D.ResourceUsage)Settings.Usage,
                OptionFlags = D3D.ResourceOptionFlags.None
            };

            switch (Settings.Usage)
            {
            case BufferUsage.Staging:
                desc.CpuAccessFlags = D3D.CpuAccessFlags.Read | D3D.CpuAccessFlags.Write;
                break;

            case BufferUsage.Dynamic:
                desc.CpuAccessFlags = D3D.CpuAccessFlags.Write;
                break;

            default:
                desc.CpuAccessFlags = D3D.CpuAccessFlags.None;
                break;
            }


            if ((initialData != null) && (initialData.Buffers.Count > 0))
            {
                D3DResource = new D3D.Texture3D(Graphics.D3DDevice, desc, initialData.Buffers.DataBoxes);
            }
            else
            {
                D3DResource = new D3D.Texture3D(Graphics.D3DDevice, desc);
            }
        }
        /// <summary>
        /// Returns a collection of standard values for the data type this type converter is designed for when provided with a format context.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext" /> that provides a format context that can be used to extract additional information about the environment from which this converter is invoked. This parameter or properties of this parameter can be null.</param>
        /// <returns>
        /// A <see cref="T:System.ComponentModel.TypeConverter.StandardValuesCollection" /> that holds a standard set of valid values, or null if the data type does not support a standard set of values.
        /// </returns>
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            var          content       = (GorgonImageContent)((ContentTypeDescriptor)context.Instance).Content;
            var          formatList    = (BufferFormat[])Enum.GetValues(typeof(BufferFormat));
            BufferFormat currentFormat = content.ImageFormat;

            var formats = (from format in formatList
                           let formatInfo = GorgonBufferFormatInfo.GetInfo(format)
                                            where (!formatInfo.HasDepth) && (!formatInfo.HasStencil) &&
                                            (!formatInfo.IsTypeless) &&
                                            (!formatInfo.IsCompressed) &&
                                            (((content.ImageType == ImageType.Image1D) && (ContentObject.Graphics.VideoDevice.Supports1DTextureFormat(format)))
                                             ||
                                             ((content.ImageType == ImageType.Image2D || content.ImageType == ImageType.ImageCube) &&
                                              (ContentObject.Graphics.VideoDevice.Supports2DTextureFormat(format))) ||
                                             ((content.ImageType == ImageType.Image3D) && (ContentObject.Graphics.VideoDevice.Supports3DTextureFormat(format)))) &&
                                            (content.Codec.SupportedFormats.Any(item => item == format)) &&
                                            ((content.MipCount == 1) ||
                                             ((content.MipCount > 1) && (ContentObject.Graphics.VideoDevice.SupportsMipMaps(format))))
                                            select format);

            return(new StandardValuesCollection(GorgonImageData.CanConvertToAny(currentFormat, formats)));
        }
Beispiel #14
0
        /// <summary>
        /// Function to create a list of WIC bitmaps from Gorgon image data.
        /// </summary>
        /// <param name="data">Data to convert to the list of WIC bitmaps.</param>
        /// <returns>The list of WIC bitmaps.</returns>
        public WIC.Bitmap[] CreateWICBitmapsFromImageData(GorgonImageData data)
        {
            int  bitmapIndex  = 0;
            Guid bitmapFormat = GetGUID(data.Settings.Format);

            if (bitmapFormat == Guid.Empty)
            {
                throw new GorgonException(GorgonResult.FormatNotSupported,
                                          string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, data.Settings.Format));
            }

            // Make room for all the buffers.
            var bitmaps = new WIC.Bitmap[data.Buffers.Count];

            // Copy to the bitmap.
            foreach (var buffer in data.Buffers)
            {
                var pointer = new DX.DataRectangle(buffer.Data.BasePointer, buffer.PitchInformation.RowPitch);
                bitmaps[bitmapIndex] = new WIC.Bitmap(Factory, buffer.Width, buffer.Height, bitmapFormat, pointer, pointer.Pitch * buffer.Height);
                bitmapIndex++;
            }

            return(bitmaps);
        }
Beispiel #15
0
        /// <summary>
        /// Paints a representation of the value of an object using the specified <see cref="T:System.Drawing.Design.PaintValueEventArgs" />.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Drawing.Design.PaintValueEventArgs" /> that indicates what to paint and where to paint it.</param>
        public override void PaintValue(PaintValueEventArgs e)
        {
            var sprite = (GorgonSpriteContent)((ContentTypeDescriptor)e.Context.Instance).Content;

            if (sprite.Texture == null)
            {
                e.Graphics.DrawImage(Resources.image_missing_16x16,
                                     e.Bounds,
                                     new Rectangle(0, 0, Resources.image_missing_16x16.Width, Resources.image_missing_16x16.Height),
                                     GraphicsUnit.Pixel);
                return;
            }

            // We cannot convert block compressed images to GDI+ image types, so just put a generic icon up.
            if ((sprite.Texture.FormatInformation.IsCompressed) ||
                (!GorgonImageData.CanConvert(sprite.Texture.Settings.Format, BufferFormat.R8G8B8A8_UIntNormal)))
            {
                e.Graphics.DrawImage(Resources.open_image_16x16,
                                     e.Bounds,
                                     new Rectangle(0, 0, Resources.open_image_16x16.Width, Resources.open_image_16x16.Height),
                                     GraphicsUnit.Pixel);
                return;
            }

            // Copy the image into system memory, convert it and display it.
            using (GorgonImageData imageData = GorgonImageData.CreateFromTexture(sprite.Texture))
            {
                imageData.Resize(e.Bounds.Width, e.Bounds.Height, false, ImageFilter.Fant);
                imageData.ConvertFormat(BufferFormat.R8G8B8A8_UIntNormal);

                using (Image gdiImage = imageData.Buffers[0].ToGDIImage())
                {
                    e.Graphics.DrawImage(gdiImage, e.Bounds);
                }
            }
        }
Beispiel #16
0
        /// <summary>
        /// Function to perform the copying of image data into the buffer.
        /// </summary>
        /// <param name="stream">Stream containing the image data.</param>
        /// <param name="image">Image data.</param>
        /// <param name="conversionFlags">Flags used to convert the image.</param>
        private void CopyImageData(GorgonDataStream stream, GorgonImageData image, TGAConversionFlags conversionFlags)
        {
            var buffer     = image.Buffers[0];                  // Get the first buffer only.
            var formatInfo = GorgonBufferFormatInfo.GetInfo(image.Settings.Format);

            GorgonFormatPitch srcPitch = (conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand
                                                             ? new GorgonFormatPitch(image.Settings.Width * 3, image.Settings.Width * 3 * image.Settings.Height)
                                                             : formatInfo.GetPitch(image.Settings.Width, image.Settings.Height, PitchFlags.None);

            // Otherwise, allocate a buffer for conversion.
            var srcPtr  = (byte *)stream.PositionPointerUnsafe;
            var destPtr = (byte *)buffer.Data.UnsafePointer;

            // Adjust destination for inverted axes.
            if ((conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX)
            {
                destPtr += buffer.PitchInformation.RowPitch - formatInfo.SizeInBytes;
            }

            if ((conversionFlags & TGAConversionFlags.InvertY) != TGAConversionFlags.InvertY)
            {
                destPtr += (image.Settings.Height - 1) * buffer.PitchInformation.RowPitch;
            }

            // Get bounds of image memory.
            var   scanSize = (int)(stream.Length - stream.Position);
            byte *endScan  = (byte *)stream.PositionPointerUnsafe + scanSize;

            int opaqueLineCount = 0;

            for (int y = 0; y < image.Settings.Height; y++)
            {
                bool setOpaque;

                if ((conversionFlags & TGAConversionFlags.RLE) == TGAConversionFlags.RLE)
                {
                    setOpaque = ReadCompressed(ref srcPtr, image.Settings.Width, destPtr, endScan, image.Settings.Format, conversionFlags);
                }
                else
                {
                    setOpaque = ReadUncompressed(srcPtr, srcPitch.RowPitch, destPtr, image.Settings.Format, conversionFlags);
                    srcPtr   += srcPitch.RowPitch;
                }

                if ((setOpaque) && (SetOpaqueIfZeroAlpha))
                {
                    opaqueLineCount++;
                }

                if ((conversionFlags & TGAConversionFlags.InvertY) != TGAConversionFlags.InvertY)
                {
                    destPtr -= buffer.PitchInformation.RowPitch;
                }
                else
                {
                    destPtr += buffer.PitchInformation.RowPitch;
                }
            }

            if (opaqueLineCount != image.Settings.Height)
            {
                return;
            }

            // Set the alpha to opaque if we don't have any alpha values (i.e. alpha = 0 for all pixels).
            destPtr = (byte *)buffer.Data.UnsafePointer;
            for (int y = 0; y < image.Settings.Height; y++)
            {
                CopyScanline(destPtr, buffer.PitchInformation.RowPitch, destPtr, buffer.PitchInformation.RowPitch, image.Settings.Format, ImageBitFlags.OpaqueAlpha);
                destPtr += buffer.PitchInformation.RowPitch;
            }
        }
Beispiel #17
0
        /// <summary>
        /// Function to persist image data to a stream.
        /// </summary>
        /// <param name="imageData"><see cref="GorgonLibrary.Graphics.GorgonImageData">Gorgon image data</see> to persist.</param>
        /// <param name="stream">Stream that will contain the data.</param>
        protected override void SaveToStream(GorgonImageData imageData, Stream stream)
        {
            if (imageData.Settings.Format != BufferFormat.R8G8B8A8_UIntNormal)
            {
                throw new ArgumentException(@"The image format must be R8G8B8A8_UIntNormal", "imageData");
            }

            // First, we'll need to set up our header metadata.
            var header = new TvHeader
            {
                MagicValueData = MagicValue,
                Width          = imageData.Settings.Width,
                Height         = imageData.Settings.Height
            };

            // Write the metadata to the stream.
            using (var writer = new GorgonBinaryWriter(stream, true))
            {
                writer.WriteValue(header);

                // Now, we need to encode the image data as 1 byte for every other color component per pixel.
                // In essence, we'll be writing one channel as a byte and moving to the next pixel.
                unsafe
                {
                    // We're in unsafe land now.  Again, if you're uncomfortable with pointers, the GorgonDataStream object
                    // provides safe methods to read image data.

                    // Get the pointer to our image buffer.
                    var imagePtr = (byte *)imageData.UnsafePointer;
                    // Allocate a buffer to store our scanline before dumping to the file.
                    var scanLineBuffer = new byte[imageData.Settings.Width * 2];

                    // For each scan line in the image we'll encode the data as described above.
                    for (int y = 0; y < imageData.Settings.Height; ++y)
                    {
                        // Read 4 bytes at a time.
                        var colorPtr = (uint *)imagePtr;

                        // Reset to the beginning of the scanline buffer.
                        fixed(byte *scanLinePtr = scanLineBuffer)
                        {
                            // Need to alias the pointer because the result value in the fixed
                            // block can't be changed.
                            var scanLine = (ushort *)scanLinePtr;

                            // Loop through the scan line until we're at its end.
                            for (int x = 0; x < imageData.Settings.Width; ++x)
                            {
                                // We're assuming our image data is 4 bytes/pixel, but in real world scenarios this is dependent upon
                                // the format of the data.
                                var pixel = *(colorPtr++);

                                // Get the alpha channel for this pixel.
                                var alpha = (byte)((pixel >> 24) & 0xff);

                                // Since we encode 1 byte per color component for each pixel, we need to bump up the bit shift
                                // by 8 bits.  Once we get above 24 bits we'll start over since we're only working with 4 bytes
                                // per pixel in the destination.

                                // We determine how many bits to shift the pixel based on horizontal positioning.
                                // We assume that the image is based on 4 bytes/pixel.  In most cases this value should be
                                // determined by dividing the row pitch by the image width.

                                // Get the color component for the pixel.
                                var color = (byte)((pixel >> (8 * (x % 3))) & 0xff);

                                // Write it to the scanline.
                                // We're encoding a pixel as a single color component with its alpha channel
                                // value into an unsigned 16 bit number.
                                *(scanLine++) = (ushort)((color << 8) | alpha);
                            }
                        }

                        // Ensure that we move to the next line by the row pitch and not the amount of pixels.
                        // Some images put padding in for alignment reasons which can throw off the data offsets.
                        // Also, the width is not suitable as a pixel is often more than 1 byte.
                        imagePtr += imageData.Buffers[0].PitchInformation.RowPitch;

                        // Send the scanline to the file.
                        writer.Write(scanLineBuffer);
                    }
                }
            }
        }
Beispiel #18
0
        /// <summary>
        /// Function to load an image from a stream.
        /// </summary>
        /// <param name="stream">Stream containing the data to load.</param>
        /// <param name="size">Size of the data to read, in bytes.</param>
        /// <returns>
        /// The image data that was in the stream.
        /// </returns>
        protected internal override GorgonImageData LoadFromStream(GorgonDataStream stream, int size)
        {
            GorgonImageData result = null;

            // Get our WIC interface.
            var wrapperStream = new GorgonStreamWrapper(stream);

            using (var wic = new GorgonWICImage())
            {
                using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat))
                {
                    using (var wicStream = new WICStream(wic.Factory, wrapperStream))
                    {
                        try
                        {
                            decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand);
                        }
                        catch (SharpDXException)
                        {
                            // Repackage this exception to keep in line with our API.
                            throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                        }

                        using (var frame = decoder.GetFrame(0))
                        {
                            Guid bestFormat;
                            var  settings = ReadMetaData(wic, decoder, frame, out bestFormat);

                            if (settings.Format == BufferFormat.Unknown)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format));
                            }

                            // Create our image data.
                            try
                            {
                                _actualArrayCount = settings.ArrayCount;
                                if (ArrayCount > 0)
                                {
                                    settings.ArrayCount = ArrayCount;
                                }

                                result = new GorgonImageData(settings);

                                if ((settings.ArrayCount > 1) && (_actualArrayCount > 1))
                                {
                                    ReadFrames(wic, result, decoder);
                                }
                                else
                                {
                                    ReadFrame(wic, result, frame.PixelFormat, bestFormat, frame);
                                }

                                // If we've not read the full length of the data (WIC seems to ignore the CRC on the IEND chunk for PNG files for example),
                                // then we need to move the pointer up by however many bytes we've missed.
                                if (wrapperStream.Position < size)
                                {
                                    wrapperStream.Position = size;
                                }
                            }
                            catch
                            {
                                // If we run into a problem, dump the memory buffer.
                                if (result != null)
                                {
                                    result.Dispose();
                                }

                                throw;
                            }
                        }
                    }
                }
            }

            return(result);
        }
Beispiel #19
0
 /// <summary>
 /// Function to persist image data to a stream.
 /// </summary>
 /// <param name="imageData"><see cref="GorgonLibrary.Graphics.GorgonImageData">Gorgon image data</see> to persist.</param>
 /// <param name="stream">Stream that will contain the data.</param>
 protected internal abstract void SaveToStream(GorgonImageData imageData, Stream stream);
Beispiel #20
0
        /// <summary>
        /// Function to perform any post processing on image data.
        /// </summary>
        internal void PostProcess(GorgonImageData data)
        {
            IImageSettings destSettings = data.Settings.Clone();
            int            width        = Width > 0 ? Width : data.Settings.Width;
            int            height       = Height > 0 ? Height : data.Settings.Height;
            int            mipCount     = MipCount > 0 ? MipCount : data.Settings.MipCount;
            BufferFormat   format       = (Format != BufferFormat.Unknown) ? Format : data.Settings.Format;
            Rectangle      newSize      = Rectangle.Empty;
            int            mipStart     = 0;
            var            sourceInfo   = GorgonBufferFormatInfo.GetInfo(data.Settings.Format);
            var            destInfo     = GorgonBufferFormatInfo.GetInfo(format);

            // First, confirm whether we can perform format conversions.
            using (var wic = new GorgonWICImage())
            {
                Guid srcPixelFormat  = wic.GetGUID(data.Settings.Format);
                Guid destPixelFormat = wic.GetGUID(format);

                // Do nothing if we can't do anything with the source format.
                if (srcPixelFormat == Guid.Empty)
                {
                    return;
                }

                // Cancel conversion if we're using the same format.
                if (srcPixelFormat == destPixelFormat)
                {
                    destPixelFormat = Guid.Empty;
                }

                // Get the new size.
                if ((width != data.Settings.Width) || (height != data.Settings.Height))
                {
                    newSize = new Rectangle(0, 0, width, height);
                }

                // Set up destination buffer settings.
                destSettings.Format   = format;
                destSettings.Width    = width;
                destSettings.Height   = height;
                destSettings.MipCount = mipCount;

                // Ensure we don't go over the maximum.
                int maxMips = GorgonImageData.GetMaxMipCount(destSettings);

                if (mipCount > maxMips)
                {
                    mipCount = maxMips;
                }

                // Nothing's going to happen here, so leave.
                if ((destPixelFormat == Guid.Empty) && (newSize == Rectangle.Empty) && (mipCount == 1))
                {
                    return;
                }

                // Create our worker buffer.
                GorgonImageData destData;
                using (destData = new GorgonImageData(destSettings))
                {
                    // The first step is to convert and resize our images:
                    if ((destPixelFormat != Guid.Empty) || (newSize != Rectangle.Empty))
                    {
                        for (int array = 0; array < destSettings.ArrayCount; array++)
                        {
                            // We're not going to copy mip levels at this point, that will come in the next step.
                            for (int depth = 0; depth < destSettings.Depth; depth++)
                            {
                                // Get our source/destination buffers.
                                var sourceBuffer = data.Buffers[0, data.Settings.ImageType == ImageType.Image3D ? depth : array];
                                var destBuffer   = destData.Buffers[0, data.Settings.ImageType == ImageType.Image3D ? depth : array];

                                var dataRect = new DataRectangle(sourceBuffer.Data.BasePointer, sourceBuffer.PitchInformation.RowPitch);

                                // Create a temporary WIC bitmap to work with.
                                using (var bitmap = new Bitmap(wic.Factory, sourceBuffer.Width, sourceBuffer.Height, srcPixelFormat, dataRect, sourceBuffer.PitchInformation.SlicePitch))
                                {
                                    wic.TransformImageData(bitmap,
                                                           destBuffer.Data.BasePointer,
                                                           destBuffer.PitchInformation.RowPitch,
                                                           destBuffer.PitchInformation.SlicePitch,
                                                           destPixelFormat,
                                                           sourceInfo.IssRGB,
                                                           destInfo.IssRGB,
                                                           Dithering,
                                                           newSize,
                                                           Clip,
                                                           Filter);
                                }
                            }
                        }

                        // Adjust the mip map starting point.
                        mipStart = 1;
                    }

                    // Next, we need to build mip maps.
                    if (destSettings.MipCount > 1)
                    {
                        // The first step is to convert and resize our images:
                        for (int array = 0; array < destSettings.ArrayCount; array++)
                        {
                            int mipDepth = destSettings.Depth;

                            for (int mip = mipStart; mip < destSettings.MipCount; mip++)
                            {
                                // We're not going to copy mip levels at this point, that will come in the next step.
                                for (int depth = 0; depth < mipDepth; depth++)
                                {
                                    // Get our source/destination buffers.
                                    var sourceBuffer = destData.Buffers[0, data.Settings.ImageType == ImageType.Image3D ? (destSettings.Depth / mipDepth) * depth : array];
                                    var destBuffer   = destData.Buffers[mip, data.Settings.ImageType == ImageType.Image3D ? depth : array];

                                    var dataRect = new DataRectangle(sourceBuffer.Data.BasePointer, sourceBuffer.PitchInformation.RowPitch);

                                    // Create a temporary WIC bitmap to work with.
                                    using (var bitmap = new Bitmap(wic.Factory, sourceBuffer.Width, sourceBuffer.Height, srcPixelFormat, dataRect, sourceBuffer.PitchInformation.SlicePitch))
                                    {
                                        wic.TransformImageData(bitmap, destBuffer.Data.BasePointer, destBuffer.PitchInformation.RowPitch, destBuffer.PitchInformation.SlicePitch,
                                                               Guid.Empty, false, false, ImageDithering.None, new Rectangle(0, 0, destBuffer.Width, destBuffer.Height), false, Filter);
                                    }
                                }

                                if (mipDepth > 1)
                                {
                                    mipDepth >>= 1;
                                }
                            }
                        }
                    }

                    // Update our data.
                    data.TakeOwnership(destData);
                }
            }
        }
        /// <summary>
        /// Function to create 2D Gorgon image data from multiple single System.Drawing.Images.
        /// </summary>
        /// <param name="wic">Windows Imaging Component interface to use.</param>
        /// <param name="images">Images to convert.</param>
        /// <param name="options">Options for conversion.</param>
        /// <returns>The converted image data.</returns>
        public static GorgonImageData Create2DImageDataFromImages(GorgonWICImage wic, IList <Image> images, GorgonGDIOptions options)
        {
            if (options.Format == BufferFormat.Unknown)
            {
                options.Format = GetBufferFormat(images[0].PixelFormat);
            }

            if (options.Format == BufferFormat.Unknown)
            {
                throw new GorgonException(GorgonResult.FormatNotSupported,
                                          string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, images[0].PixelFormat));
            }

            if (images.Any(item => item.PixelFormat != images[0].PixelFormat))
            {
                throw new GorgonException(GorgonResult.CannotCreate,
                                          string.Format(Resources.GORGFX_IMAGE_MUST_BE_SAME_FORMAT, images[0].PixelFormat));
            }

            if (options.Width < 1)
            {
                options.Width = images[0].Width;
            }

            if (options.Height < 1)
            {
                options.Height = images[0].Height;
            }

            if (options.ArrayCount < 1)
            {
                options.ArrayCount = 1;
            }

            options.MipCount = options.MipCount < 1
                                                   ? 1
                                                   : options.MipCount.Min(GorgonImageData.GetMaxMipCount(options.Width, options.Height));

            // Create our settings.
            var settings = new GorgonTexture2DSettings
            {
                Width      = options.Width,
                Height     = options.Height,
                MipCount   = options.MipCount,
                ArrayCount = options.ArrayCount,
                Format     = options.Format,
                AllowUnorderedAccessViews = options.AllowUnorderedAccess,
                ShaderViewFormat          = options.ViewFormat,
                Usage = options.Usage
            };

            if ((options.ArrayCount * options.MipCount) > images.Count)
            {
                throw new GorgonException(GorgonResult.CannotCreate, Resources.GORGFX_IMAGE_MIPCOUNT_ARRAYCOUNT_TOO_LARGE);
            }

            // Create our image data.
            var data = new GorgonImageData(settings);

            for (int array = 0; array < data.Settings.ArrayCount; array++)
            {
                for (int mipLevel = 0; mipLevel < data.Settings.MipCount; mipLevel++)
                {
                    var image = images[array * data.Settings.MipCount + mipLevel];

                    if (image == null)
                    {
                        continue;
                    }

                    // Using the image, convert to a WIC bitmap object.
                    using (var bitmap = wic.CreateWICImageFromImage(image))
                    {
                        var buffer = data.Buffers[mipLevel, array];

                        wic.AddWICBitmapToImageData(bitmap, options.Filter, options.Dither, buffer, options.UseClipping);
                    }
                }
            }

            return(data);
        }
Beispiel #22
0
        /// <summary>
        /// Function to persist image data to a stream.
        /// </summary>
        /// <param name="imageData"><see cref="GorgonLibrary.Graphics.GorgonImageData">Gorgon image data</see> to persist.</param>
        /// <param name="stream">Stream that will contain the data.</param>
        protected internal override void SaveToStream(GorgonImageData imageData, Stream stream)
        {
            int frameCount = 1;

            // Wrap the stream so WIC doesn't mess up the position.
            using (var wrapperStream = new GorgonStreamWrapper(stream))
            {
                using (var wic = new GorgonWICImage())
                {
                    // Find a compatible format.
                    Guid targetFormat = wic.GetGUID(imageData.Settings.Format);

                    if (targetFormat == Guid.Empty)
                    {
                        throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, imageData.Settings.Format));
                    }

                    Guid actualFormat = targetFormat;

                    using (var encoder = new BitmapEncoder(wic.Factory, SupportedFormat))
                    {
                        try
                        {
                            encoder.Initialize(wrapperStream);
                            AddCustomMetaData(encoder, null, 0, imageData.Settings, null);
                        }
                        catch (SharpDXException)
                        {
                            // Repackage this exception to keep in line with our API.
                            throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_ENCODER, Codec));
                        }

                        using (var encoderInfo = encoder.EncoderInfo)
                        {
                            if ((imageData.Settings.ArrayCount > 1) && (CodecUseAllFrames) && (encoderInfo.IsMultiframeSupported))
                            {
                                frameCount = imageData.Settings.ArrayCount;
                            }

                            for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
                            {
                                using (var frame = new BitmapFrameEncode(encoder))
                                {
                                    var buffer = imageData.Buffers[0, frameIndex];

                                    frame.Initialize();
                                    frame.SetSize(buffer.Width, buffer.Height);
                                    frame.SetResolution(72, 72);
                                    frame.SetPixelFormat(ref actualFormat);

                                    SetFrameOptions(frame);

                                    // If the image encoder doesn't like the format we've chosen, then we'll need to convert to
                                    // the best format for the codec.
                                    if (targetFormat != actualFormat)
                                    {
                                        var rect = new DataRectangle(buffer.Data.BasePointer, buffer.PitchInformation.RowPitch);
                                        using (var bitmap = new Bitmap(wic.Factory, buffer.Width, buffer.Height, targetFormat, rect))
                                        {
                                            // If we're using a codec that supports 8 bit indexed data, then get the palette info.
                                            var paletteInfo = GetPaletteInfo(wic, bitmap);

                                            if (paletteInfo == null)
                                            {
                                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_ENCODER, Codec));
                                            }

                                            try
                                            {
                                                using (var converter = new FormatConverter(wic.Factory))
                                                {
                                                    converter.Initialize(bitmap, actualFormat, (BitmapDitherType)Dithering, paletteInfo.Item1, paletteInfo.Item2, paletteInfo.Item3);
                                                    if (paletteInfo.Item1 != null)
                                                    {
                                                        frame.Palette = paletteInfo.Item1;
                                                    }

                                                    AddCustomMetaData(encoder, frame, frameIndex, imageData.Settings, (paletteInfo.Item1 != null) ? paletteInfo.Item1.Colors : null);
                                                    frame.WriteSource(converter);
                                                }
                                            }
                                            finally
                                            {
                                                if (paletteInfo.Item1 != null)
                                                {
                                                    paletteInfo.Item1.Dispose();
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // No conversion was needed, just dump as-is.
                                        AddCustomMetaData(encoder, frame, frameIndex, imageData.Settings, null);
                                        frame.WritePixels(buffer.Height, buffer.Data.BasePointer, buffer.PitchInformation.RowPitch, buffer.PitchInformation.SlicePitch);
                                    }

                                    frame.Commit();
                                }
                            }
                        }

                        encoder.Commit();
                    }
                }
            }
        }
Beispiel #23
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GorgonImageBufferList"/> class.
 /// </summary>
 /// <param name="image">The image that owns this list.</param>
 internal GorgonImageBufferList(GorgonImageData image)
 {
     _image   = image;
     _buffers = new GorgonImageBuffer[0];
 }
Beispiel #24
0
        public void TestTextureUpdate()
        {
            float diver = 1.0f;

            var shader = _framework.Graphics.Shaders.FromMemory <GorgonPixelShader>("PS",
                                                                                    "TestPSUpdateSub",
                                                                                    Resources.TextureShaders);

            var texture = _framework.Graphics.Textures.CreateTexture("Texture",
                                                                     new GorgonTexture2DSettings
            {
                ArrayCount = 1,
                Format     = BufferFormat.R8G8B8A8_UIntNormal,
                MipCount   = 4,
                Height     = 256,
                Width      = 256,
                Usage      = BufferUsage.Default
            });

            var dynTexture = _framework.Graphics.Textures.CreateTexture("DynTexture",
                                                                        new GorgonTexture2DSettings
            {
                ArrayCount = 1,
                Format     = BufferFormat.R8G8B8A8_UIntNormal,
                MipCount   = 1,
                Height     = 256,
                Width      = 256,
                Usage      = BufferUsage.Dynamic
            });

            var imageData = GorgonImageData.CreateFromGDIImage(Resources.Glass,
                                                               ImageType.Image2D,
                                                               new GorgonGDIOptions
            {
                MipCount = 4
            });

            _framework.CreateTestScene(Shaders, Shaders, true);
            _framework.Graphics.Shaders.PixelShader.Current      = shader;
            _framework.Graphics.Shaders.PixelShader.Resources[1] = texture;

            texture.UpdateSubResource(imageData.Buffers[0],
                                      new Rectangle
            {
                Width  = 128,
                Height = 128,
                X      = 0,
                Y      = 0
            });

            texture.UpdateSubResource(imageData.Buffers[1],
                                      new Rectangle
            {
                Width  = 64,
                Height = 64,
                X      = 128,
                Y      = 0
            });

            GorgonTexture2D testIntFormat = _framework.Graphics.Textures.CreateTexture("asas",
                                                                                       new GorgonTexture2DSettings
            {
                Format = BufferFormat.R8G8B8A8_Int,
                Usage  = BufferUsage.Dynamic,
                Width  = 64,
                Height = 64
            });

            _framework.IdleFunc = () =>
            {
                _framework.Graphics.Shaders.PixelShader.Resources[2] = null;

                using (var lockData = dynTexture.Lock(BufferLockFlags.Write | BufferLockFlags.Discard))
                {
                    for (int i = 0; i < 4096; ++i)
                    {
                        int y = GorgonRandom.RandomInt32(0, imageData.Buffers[0].Height);
                        int x = GorgonRandom.RandomInt32(0, imageData.Buffers[0].Width);

                        // 95417E

                        imageData.Buffers[0].Data.Position = (y * imageData.Buffers[0].PitchInformation.RowPitch)
                                                             + (x * 4);

                        lockData.Data.Position = (y * lockData.PitchInformation.RowPitch)
                                                 + (x * dynTexture.FormatInformation.SizeInBytes);

                        var color = new GorgonColor(imageData.Buffers[0].Data.ReadInt32());

                        color = new GorgonColor(color.Red / diver, color.Green / diver, color.Blue / diver);

                        lockData.Data.Write(color.ToARGB());
                        //lockData.Data.Write(0xFF00FF00);

                        /*lockData.Data.Write(Color.FromArgb(color.ToARGB()).R);
                        *  lockData.Data.Write(Color.FromArgb(color.ToARGB()).G);
                        *  lockData.Data.Write(Color.FromArgb(color.ToARGB()).B);
                        *  lockData.Data.Write(Color.FromArgb(color.ToARGB()).A);*/
                    }
                }

                diver += 0.5f * GorgonTiming.Delta;

                if (diver > 32.0f)
                {
                    diver = 1.0f;
                }

                _framework.Graphics.Shaders.PixelShader.Resources[2] = dynTexture;

                return(false);
            };



            Assert.IsTrue(_framework.Run() == DialogResult.Yes);
        }
        /// <summary>
        /// Function to create a 3D Gorgon image data from multiple System.Drawing.Images.
        /// </summary>
        /// <param name="wic">Windows Imaging Component interface to use.</param>
        /// <param name="images">Images to convert.</param>
        /// <param name="options">Conversion options.</param>
        /// <returns>The converted image data.</returns>
        public static GorgonImageData Create3DImageDataFromImages(GorgonWICImage wic, IList <Image> images, GorgonGDIOptions options)
        {
            if (options.Format == BufferFormat.Unknown)
            {
                options.Format = GetBufferFormat(images[0].PixelFormat);
            }

            if (options.Format == BufferFormat.Unknown)
            {
                throw new GorgonException(GorgonResult.FormatNotSupported,
                                          string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, images[0].PixelFormat));
            }

            if (images.Any(item => item.PixelFormat != images[0].PixelFormat))
            {
                throw new GorgonException(GorgonResult.CannotCreate,
                                          string.Format(Resources.GORGFX_IMAGE_MUST_BE_SAME_FORMAT, images[0].PixelFormat));
            }

            if (options.Width <= 0)
            {
                options.Width = images[0].Width;
            }

            if (options.Height <= 0)
            {
                options.Height = images[0].Height;
            }

            if (options.Depth < 1)
            {
                options.Depth = 1;
            }

            options.MipCount = options.MipCount < 1
                                                   ? 1
                                                   : options.MipCount.Min(GorgonImageData.GetMaxMipCount(options.Width, options.Height,
                                                                                                         options.Depth));

            // Set the depth to the number of images if there are no mip-maps.
            if ((images.Count > 1) && (options.MipCount == 1))
            {
                options.Depth = images.Count;
            }

            // Create our settings.
            var settings = new GorgonTexture3DSettings
            {
                Width    = options.Width,
                Height   = options.Height,
                Depth    = options.Depth,
                MipCount = options.MipCount,
                Format   = options.Format,
                AllowUnorderedAccessViews = options.AllowUnorderedAccess,
                ShaderViewFormat          = options.ViewFormat,
                Usage = options.Usage
            };

            // Only volume textures that are size to a power of 2 can have mip maps.
            if ((!settings.IsPowerOfTwo) && (options.MipCount > 1))
            {
                throw new GorgonException(GorgonResult.CannotCreate, Resources.GORGFX_IMAGE_VOLUME_NOT_POWER_OF_TWO);
            }

            // Create our image data.
            var data = new GorgonImageData(settings);

            int depthMip   = options.Depth;
            int imageIndex = 0;

            for (int mipLevel = 0; mipLevel < data.Settings.MipCount; mipLevel++)
            {
                if (imageIndex >= images.Count)
                {
                    data.Dispose();
                    throw new GorgonException(GorgonResult.CannotCreate, Resources.GORGFX_IMAGE_VOLUME_MIPCOUNT_DEPTHCOUNT_TOO_LARGE);
                }

                for (int depth = 0; depth < depthMip; depth++)
                {
                    var image = images[imageIndex + depth];

                    // Skip NULL images.
                    if (image == null)
                    {
                        continue;
                    }

                    // Using the image, convert to a WIC bitmap object.
                    using (var bitmap = wic.CreateWICImageFromImage(image))
                    {
                        var buffer = data.Buffers[mipLevel, depth];
                        wic.AddWICBitmapToImageData(bitmap, options.Filter, options.Dither, buffer, options.UseClipping);
                    }
                }

                imageIndex += depthMip;

                // Decrease depth based on mip level.
                if (depthMip > 1)
                {
                    depthMip >>= 1;
                }
            }

            return(data);
        }
Beispiel #26
0
        /// <summary>
        /// Function to persist image data to a stream.
        /// </summary>
        /// <param name="imageData"><see cref="GorgonLibrary.Graphics.GorgonImageData">Gorgon image data</see> to persist.</param>
        /// <param name="stream">Stream that will contain the data.</param>
        protected internal override void SaveToStream(GorgonImageData imageData, Stream stream)
        {
            // Use a binary writer.
            using (var writer = new GorgonBinaryWriter(stream, true))
            {
                // Write the header for the file.
                TGAConversionFlags conversionFlags;
                WriteHeader(imageData.Settings, writer, out conversionFlags);

                GorgonFormatPitch pitch;
                if ((conversionFlags & TGAConversionFlags.RGB888) == TGAConversionFlags.RGB888)
                {
                    pitch = new GorgonFormatPitch(imageData.Settings.Width * 3, imageData.Settings.Width * 3 * imageData.Settings.Height);
                }
                else
                {
                    var formatInfo = GorgonBufferFormatInfo.GetInfo(imageData.Settings.Format);
                    pitch = formatInfo.GetPitch(imageData.Settings.Width, imageData.Settings.Height, PitchFlags.None);
                }

                // Get the pointer to the first mip/array/depth level.
                var srcPointer = (byte *)imageData.Buffers[0].Data.UnsafePointer;
                var srcPitch   = imageData.Buffers[0].PitchInformation;

                // If the two pitches are equal, then just write out the buffer.
                if ((pitch == srcPitch) && (conversionFlags == TGAConversionFlags.None))
                {
                    writer.Write(srcPointer, srcPitch.SlicePitch);
                    return;
                }

                // If we have to do a conversion, create a worker buffer.
                using (var convertBuffer = new GorgonDataStream(pitch.SlicePitch))
                {
                    var destPtr = (byte *)convertBuffer.UnsafePointer;

                    // Write out each scan line.
                    for (int y = 0; y < imageData.Settings.Height; y++)
                    {
                        if ((conversionFlags & TGAConversionFlags.RGB888) == TGAConversionFlags.RGB888)
                        {
                            Compress24BPPScanLine(srcPointer, srcPitch.RowPitch, destPtr, pitch.RowPitch);
                        }
                        else if ((conversionFlags & TGAConversionFlags.Swizzle) == TGAConversionFlags.Swizzle)
                        {
                            SwizzleScanline(srcPointer, srcPitch.RowPitch, destPtr, pitch.RowPitch, imageData.Settings.Format, ImageBitFlags.None);
                        }
                        else
                        {
                            CopyScanline(srcPointer, srcPitch.RowPitch, destPtr, pitch.RowPitch, imageData.Settings.Format, ImageBitFlags.None);
                        }

                        destPtr    += pitch.RowPitch;
                        srcPointer += srcPitch.RowPitch;
                    }

                    // Persist to the stream.
                    writer.Write(convertBuffer.UnsafePointer, pitch.SlicePitch);
                }
            }
        }
Beispiel #27
0
        /// <summary>
        /// Function to clip the sprite region from the texture.
        /// </summary>
        /// <param name="texture">Texture containing the image data to clip.</param>
        /// <returns>A rectangle for the sprite.  Or an empty rectangle if no sprite was selected.</returns>
        public unsafe Rectangle Clip(GorgonTexture2D texture)
        {
            GorgonImageData imageData = null;

            try
            {
                // Constrain our mouse to the texture.
                _startPoint.X = _startPoint.X.Max(0).Min(texture.Settings.Width - 1);
                _startPoint.Y = _startPoint.Y.Max(0).Min(texture.Settings.Height - 1);

                imageData = GorgonImageData.CreateFromTexture(texture);

                _stride        = imageData.Buffers[0].PitchInformation.RowPitch;
                _format        = imageData.Settings.Format;
                _bytesPerPixel = GorgonBufferFormatInfo.GetInfo(_format).SizeInBytes;
                _textureWidth  = imageData.Settings.Width;

                // Get a pointer to the buffer.
                byte *bytePtr = (byte *)imageData.UnsafePointer;

                if (IsMaskValue(bytePtr, _startPoint.X, _startPoint.Y))
                {
                    return(Rectangle.Empty);
                }

                Queue <ClipSpan> clipSpans = new Queue <ClipSpan>();

                _pixels = new bool[imageData.Settings.Width * imageData.Settings.Height];

                int left   = _startPoint.X;
                int top    = _startPoint.Y;
                int right  = left;
                int bottom = top;

                // Get the initial span from our starting point and add it to our queue.
                ClipSpan span = GetSpan(bytePtr, left, top);
                clipSpans.Enqueue(span);

                while (clipSpans.Count > 0)
                {
                    // Take the span off the queue.
                    span = clipSpans.Dequeue();

                    // Find the next vertical span above and below the current span.
                    int west  = span.Start;
                    int east  = span.End;
                    int north = span.Y - 1;
                    int south = span.Y + 1;

                    // Check each pixel between the start and end of the upper and lower spans.
                    for (int x = west; x <= east; ++x)
                    {
                        int pixelindex = _textureWidth * north + x;

                        if ((span.Y > 0) && (!IsMaskValue(bytePtr, x, north)) && (!_pixels[pixelindex]))
                        {
                            clipSpans.Enqueue(GetSpan(bytePtr, x, north));
                        }

                        pixelindex = _textureWidth * south + x;

                        if ((span.Y >= imageData.Settings.Height - 1) || (IsMaskValue(bytePtr, x, south)) || (_pixels[pixelindex]))
                        {
                            continue;
                        }

                        clipSpans.Enqueue(GetSpan(bytePtr, x, south));
                    }

                    // Update the boundaries.
                    left   = west.Min(left);
                    right  = (east + 1).Max(right);
                    top    = (north + 1).Min(top);
                    bottom = south.Max(bottom);
                }

                return(Rectangle.FromLTRB(left, top, right, bottom));
            }
            finally
            {
                if (imageData != null)
                {
                    imageData.Dispose();
                }
            }
        }
Beispiel #28
0
        /// <summary>
        /// Function to read multiple frames from a decoder that supports multiple frames.
        /// </summary>
        /// <param name="wic">WIC interface.</param>
        /// <param name="data">Image data to populate.</param>
        /// <param name="decoder">Decoder for the image.</param>
        private void ReadFrames(GorgonWICImage wic, GorgonImageData data, BitmapDecoder decoder)
        {
            Guid bestPixelFormat = wic.GetGUID(data.Settings.Format);

            // Find the best fit pixel format.
            if (bestPixelFormat == Guid.Empty)
            {
                throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, data.Settings.Format));
            }

            // Use the image array as the frames.
            int arrayCount = _actualArrayCount.Min(data.Settings.ArrayCount);

            for (int array = 0; array < arrayCount; array++)
            {
                var buffer = data.Buffers[0, array];

                // Get the frame data.
                using (var frame = decoder.GetFrame(array))
                {
                    IntPtr bufferPointer = buffer.Data.BasePointer;
                    Guid   frameFormat   = frame.PixelFormat;
                    int    frameWidth    = frame.Size.Width;
                    int    frameHeight   = frame.Size.Height;
                    var    frameOffset   = GetFrameOffset(frame);

                    // Calculate the pointer offset if we have an offset from the frame.  Only offset if we're clipping the image though.
                    if (((frameOffset.Y != 0) || (frameOffset.X != 0)) && (Clip))
                    {
                        bufferPointer = buffer.Data.BasePointer + (frameOffset.Y * buffer.PitchInformation.RowPitch) + (frameOffset.X * (buffer.PitchInformation.RowPitch / buffer.Width));
                    }

                    // Confirm that we actually need to perform clipping.
                    bool needsSizeAdjust = (frameWidth + frameOffset.X > data.Settings.Width) || (frameHeight + frameOffset.Y > data.Settings.Height);

                    // If the formats match, then we don't need to do conversion.
                    if (bestPixelFormat == frameFormat)
                    {
                        // If the width and height are the same then we can just do a straight copy into the buffer.
                        if (((frameWidth == data.Settings.Width) && (frameHeight == data.Settings.Height)) || ((!needsSizeAdjust) && (Clip)))
                        {
                            frame.CopyPixels(buffer.PitchInformation.RowPitch, bufferPointer, buffer.PitchInformation.SlicePitch);

                            continue;
                        }

                        // We need to scale the image up/down to the size of our image data.
                        if (!Clip)
                        {
                            using (var scaler = new BitmapScaler(wic.Factory))
                            {
                                scaler.Initialize(frame, data.Settings.Width, data.Settings.Height, (BitmapInterpolationMode)Filter);
                                scaler.CopyPixels(buffer.PitchInformation.RowPitch, bufferPointer, buffer.PitchInformation.SlicePitch);
                            }
                            continue;
                        }

                        using (var clipper = new BitmapClipper(wic.Factory))
                        {
                            clipper.Initialize(frame, new Rectangle(0, 0, data.Settings.Width, data.Settings.Height));
                            clipper.CopyPixels(buffer.PitchInformation.RowPitch, bufferPointer, buffer.PitchInformation.SlicePitch);
                        }

                        continue;
                    }

                    // Poop.  We need to convert this image.
                    using (var converter = new FormatConverter(wic.Factory))
                    {
                        converter.Initialize(frame,
                                             bestPixelFormat,
                                             (BitmapDitherType)Dithering,
                                             null,
                                             0.0,
                                             BitmapPaletteType.Custom);

                        if (((frameWidth == data.Settings.Width) && (frameHeight == data.Settings.Height)) ||
                            ((!needsSizeAdjust) && (Clip)))
                        {
                            converter.CopyPixels(buffer.PitchInformation.RowPitch,
                                                 bufferPointer,
                                                 buffer.PitchInformation.SlicePitch);
                            continue;
                        }

                        // And we need to scale the image.
                        if (!Clip)
                        {
                            using (var scaler = new BitmapScaler(wic.Factory))
                            {
                                scaler.Initialize(converter,
                                                  data.Settings.Width,
                                                  data.Settings.Height,
                                                  (BitmapInterpolationMode)Filter);
                                scaler.CopyPixels(buffer.PitchInformation.RowPitch,
                                                  bufferPointer,
                                                  buffer.PitchInformation.SlicePitch);
                            }

                            continue;
                        }

                        using (var clipper = new BitmapClipper(wic.Factory))
                        {
                            clipper.Initialize(frame,
                                               new Rectangle(0, 0, data.Settings.Width, data.Settings.Height));
                            clipper.CopyPixels(buffer.PitchInformation.RowPitch,
                                               bufferPointer,
                                               buffer.PitchInformation.SlicePitch);
                        }
                    }
                }
            }
        }
Beispiel #29
0
        /// <summary>
        /// Function to load an image from a stream.
        /// </summary>
        /// <param name="stream">Stream containing the data to load.</param>
        /// <param name="size">Size of the data to read, in bytes.</param>
        /// <returns>
        /// The image data that was in the stream.
        /// </returns>
        protected override GorgonImageData LoadFromStream(GorgonDataStream stream, int size)
        {
            // Read the image meta data so we'll know how large the data should be.
            IImageSettings settings = ReadMetaData(stream);

            // Calculate the expected size of the image.
            int dataSize = settings.Width * settings.Height * 2;

            if ((size - TvHeader.SizeInBytes) != dataSize)
            {
                throw new ArgumentException("The data in the stream is not the same size as the proposed image size.");
            }

            // We'll be getting into unsafe territory here for performance reasons.
            // If you're not comfortable with pointers, the stream object provides other ways of retrieving
            // the data and copying it.
            unsafe
            {
                // Create our resulting image buffer.
                var result = new GorgonImageData(settings);

                // Get pointers to our data buffers.
                var imagePtr = (byte *)result.UnsafePointer;
                var srcPtr   = (ushort *)stream.UnsafePointer;

                // Write each scanline.
                for (int y = 0; y < settings.Height; ++y)
                {
                    var destPtr = (uint *)imagePtr;

                    // Decode the pixels in the scan line for our resulting image.
                    for (int x = 0; x < settings.Width; ++x)
                    {
                        // Get our current pixel.
                        ushort pixel = *(srcPtr++);

                        // Since we encode 1 byte per color component for each pixel, we need to bump up the bit shift
                        // by 8 bits.  Once we get above 24 bits we'll start over since we're only working with 4 bytes
                        // per pixel in the destination.

                        // We determine how many bits to shift the pixel based on horizontal positioning.
                        // We assume that the image is based on 4 bytes/pixel.  In most cases this value should be
                        // determined by dividing the row pitch by the image width.

                        // Write the color by shifting the byte in the source data to the appropriate byte position.
                        var color = (uint)(((pixel >> 8) & 0xff) << (8 * (x % 3)));
                        var alpha = (uint)((pixel & 0xff) << 24);

                        *(destPtr++) = color | alpha;
                    }

                    // Ensure that we move to the next line by the row pitch and not the amount of pixels.
                    // Some images put padding in for alignment reasons which can throw off the data offsets.
                    imagePtr += result.Buffers[0].PitchInformation.RowPitch;
                }

                // Move to the end of the stream.
                stream.Position += dataSize;

                return(result);
            }
        }