/// <summary>Function called to initialize the effect.</summary>
        /// <remarks>Applications must implement this method to ensure that any required resources are created, and configured for the effect.</remarks>
        protected override void OnInitialize()
        {
            // Initialize the default look up table.
            using (IGorgonImage image = new GorgonImage(new GorgonImageInfo(ImageType.Image1D, BufferFormat.R8G8B8A8_UNorm)
            {
                Width = 3
            }))
            {
                image.ImageData.ReadAs <int>(0) = GorgonColor.RedPure.ToABGR();
                image.ImageData.ReadAs <int>(4) = GorgonColor.BluePure.ToABGR();
                image.ImageData.ReadAs <int>(8) = GorgonColor.GreenPure.ToABGR();

                _defaultLut = GorgonTexture1DView.CreateTexture(Graphics, new GorgonTexture1DInfo("Default Spectral LUT")
                {
                    Binding = TextureBinding.ShaderResource,
                    Usage   = ResourceUsage.Immutable,
                    Width   = 3
                }, image);
            }

            _chromeAbShader       = GorgonShaderFactory.Compile <GorgonPixelShader>(Graphics, Resources.ChromaticAberration, "ChromaticAberration", GorgonGraphics.IsDebugEnabled);
            _simpleChromeAbShader = GorgonShaderFactory.Compile <GorgonPixelShader>(Graphics, Resources.ChromaticAberration, "ChromaticAberrationSimple", GorgonGraphics.IsDebugEnabled);

            _settings = GorgonConstantBufferView.CreateConstantBuffer(Graphics, new GorgonConstantBufferInfo("Chromatic Aberration Settings Buffer")
            {
                SizeInBytes = DX.Vector4.SizeInBytes,
                Usage       = ResourceUsage.Default
            });
        }
Example #2
0
        /// <summary>
        /// Function to retrieve an image based on the current depth slice.
        /// </summary>
        /// <param name="sourceImage">The image to extract the depth slice from.</param>
        /// <param name="currentDepthSlice">The depth slice to extract.</param>
        /// <returns>A new image with the specified depth slice.</returns>
        public IGorgonImage GetDepthSliceAsImage(IGorgonImage sourceImage, int currentDepthSlice)
        {
            if (sourceImage.MipCount == 1)
            {
                return(sourceImage);
            }

            IGorgonImage result = new GorgonImage(new GorgonImageInfo(sourceImage, ImageType.Image2D)
            {
                Depth = 1
            });

            for (int mip = 0; mip < result.MipCount; ++mip)
            {
                int depthCount = sourceImage.GetDepthCount(mip);

                if (currentDepthSlice >= depthCount)
                {
                    return(result);
                }

                IGorgonImageBuffer srcBuffer  = sourceImage.Buffers[mip, currentDepthSlice];
                IGorgonImageBuffer destBuffer = result.Buffers[mip];

                srcBuffer.CopyTo(destBuffer);
            }

            return(result);
        }
Example #3
0
        /// <summary>Function to convert the specified image into a volume image.</summary>
        /// <param name="image">The image to convert.</param>
        /// <returns>The converted image.</returns>
        public IGorgonImage ConvertToVolume(IGorgonImage image)
        {
            IGorgonImage result = null;

            try
            {
                result = new GorgonImage(new GorgonImageInfo(image, ImageType.Image3D)
                {
                    ArrayCount = 1,
                    Depth      = 1
                });

                // Copy the mip levels.
                for (int i = 0; i < result.MipCount; ++i)
                {
                    image.Buffers[i].CopyTo(result.Buffers[i]);
                }
            }
            catch
            {
                result?.Dispose();
                throw;
            }

            return(result);
        }
Example #4
0
        /// <summary>
        /// Function to retrieve an image based on the current mip level.
        /// </summary>
        /// <param name="sourceImage">The image to extract the mip level from.</param>
        /// <param name="currentMipLevel">The mip level to extract.</param>
        /// <returns>A new image with the specified mip level.</returns>
        public IGorgonImage GetMipLevelAsImage(IGorgonImage sourceImage, int currentMipLevel)
        {
            if (sourceImage.MipCount == 1)
            {
                return(sourceImage);
            }

            int depthCount = 1;

            if (sourceImage.ImageType == ImageType.Image3D)
            {
                depthCount = sourceImage.GetDepthCount(currentMipLevel);
            }

            IGorgonImage result = new GorgonImage(new GorgonImageInfo(sourceImage)
            {
                Width    = sourceImage.Buffers[currentMipLevel].Width,
                Height   = sourceImage.Buffers[currentMipLevel].Height,
                Depth    = depthCount,
                MipCount = 1
            });

            for (int array = 0; array < sourceImage.ArrayCount; ++array)
            {
                for (int depth = 0; depth < result.Depth; ++depth)
                {
                    IGorgonImageBuffer srcBuffer  = sourceImage.Buffers[currentMipLevel, sourceImage.ImageType == ImageType.Image3D ? depth : array];
                    IGorgonImageBuffer destBuffer = result.Buffers[0, sourceImage.ImageType == ImageType.Image3D ? depth : array];

                    srcBuffer.CopyTo(destBuffer);
                }
            }

            return(result);
        }
Example #5
0
        /// <summary>
        /// Function to load an image from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the image data to read.</param>
        /// <param name="size">The size of the image within the stream, in bytes.</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the image data from the stream.</returns>
        /// <exception cref="GorgonException">Thrown when the image data in the stream has a pixel format that is unsupported.</exception>
        protected override IGorgonImage OnDecodeFromStream(Stream stream, long size)
        {
            if (Unsafe.SizeOf <TgaHeader>() >= size)
            {
                throw new EndOfStreamException();
            }

            using (var reader = new GorgonBinaryReader(stream, true))
            {
                IGorgonImageInfo info = ReadHeader(reader, out TGAConversionFlags flags);

                IGorgonImage image = new GorgonImage(info);

                if (DecodingOptions?.SetZeroAlphaAsOpaque ?? true)
                {
                    flags |= TGAConversionFlags.SetOpaqueAlpha;
                }

                CopyImageData(reader, image, flags);

                stream.Position = size;

                return(image);
            }
        }
        /// <summary>
        /// Function to render the image data into an 32 bit RGBA pixel format render target and then return it as the properly formatted image data.
        /// </summary>
        /// <param name="texture">The texture to render.</param>
        /// <returns>The converted image data for the texture.</returns>
        private IGorgonImage RenderImageData(GorgonTexture2DView texture)
        {
            GorgonRenderTargetView   oldRtv        = _graphics.RenderTargets[0];
            GorgonRenderTarget2DView convertTarget = null;
            GorgonTexture2DView      rtvTexture    = null;
            IGorgonImage             tempImage     = null;
            BufferFormat             targetFormat  = texture.FormatInformation.IsSRgb ? BufferFormat.R8G8B8A8_UNorm_SRgb : BufferFormat.R8G8B8A8_UNorm;

            try
            {
                IGorgonImage resultImage = new GorgonImage(new GorgonImageInfo(ImageType.Image2D, targetFormat)
                {
                    Width      = texture.Width,
                    Height     = texture.Height,
                    ArrayCount = texture.ArrayCount
                });

                convertTarget = GorgonRenderTarget2DView.CreateRenderTarget(_graphics, new GorgonTexture2DInfo(texture, "Convert_rtv")
                {
                    ArrayCount = 1,
                    MipLevels  = 1,
                    Format     = targetFormat,
                    Binding    = TextureBinding.ShaderResource
                });

                rtvTexture = convertTarget.GetShaderResourceView();

                for (int i = 0; i < texture.ArrayCount; ++i)
                {
                    convertTarget.Clear(GorgonColor.BlackTransparent);
                    _graphics.SetRenderTarget(convertTarget);
                    _renderer.Begin();
                    _renderer.DrawFilledRectangle(new DX.RectangleF(0, 0, texture.Width, texture.Height),
                                                  GorgonColor.White,
                                                  texture,
                                                  new DX.RectangleF(0, 0, 1, 1),
                                                  i);
                    _renderer.End();

                    tempImage?.Dispose();
                    tempImage = convertTarget.Texture.ToImage();
                    tempImage.Buffers[0].CopyTo(resultImage.Buffers[0, i]);
                }

                return(resultImage);
            }
            finally
            {
                tempImage?.Dispose();
                _graphics.SetRenderTarget(oldRtv);
                rtvTexture?.Dispose();
                convertTarget?.Dispose();
            }
        }
Example #7
0
        /// <summary>
        /// Function to convert a <see cref="Bitmap"/> into a <see cref="IGorgonImage"/>.
        /// </summary>
        /// <param name="bitmap">The <see cref="Bitmap"/> to convert.</param>
        /// <returns>A new <see cref="IGorgonImage"/> containing the data from the <see cref="Bitmap"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="bitmap"/> parameter is <b>null</b>.</exception>
        /// <exception cref="GorgonException">Thrown if the <paramref name="bitmap"/> is not <see cref="PixelFormat.Format32bppArgb"/>.</exception>
        /// <remarks>
        /// <para>
        /// This method will take a 2D <see cref="Bitmap"/> and copy its data into a new 2D <see cref="IGorgonImage"/>. The resulting <see cref="IGorgonImage"/> will only contain 1 array level,
        /// and no mip map levels.
        /// </para>
        /// <para>
        /// Some format conversion is performed on the <paramref name="bitmap"/> when it is imported. The format conversion will always convert to the image format of
        /// <see cref="BufferFormat.R8G8B8A8_UNorm"/>. Only the following GDI+ pixel formats are supported for conversion:
        /// <list type="bullet">
        ///     <item>
        ///         <term><see cref="PixelFormat.Format32bppArgb"/></term>
        ///     </item>
        ///     <item>
        ///         <term><see cref="PixelFormat.Format32bppPArgb"/></term>
        ///     </item>
        ///     <item>
        ///         <term><see cref="PixelFormat.Format32bppRgb"/></term>
        ///     </item>
        ///     <item>
        ///         <term><see cref="PixelFormat.Format24bppRgb"/></term>
        ///     </item>
        /// </list>
        /// If the source <paramref name="bitmap"/> does not support any of the formats on the list, then an exception will be thrown.
        /// </para>
        /// </remarks>
        public static IGorgonImage ToGorgonImage(this Bitmap bitmap)
        {
            if (bitmap == null)
            {
                throw new ArgumentNullException(nameof(bitmap));
            }

            if ((bitmap.PixelFormat != PixelFormat.Format32bppArgb) &&
                (bitmap.PixelFormat != PixelFormat.Format32bppPArgb) &&
                (bitmap.PixelFormat != PixelFormat.Format32bppRgb) &&
                (bitmap.PixelFormat != PixelFormat.Format24bppRgb))
            {
                throw new GorgonException(GorgonResult.FormatNotSupported, string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, bitmap.PixelFormat));
            }

            IGorgonImageInfo info = new GorgonImageInfo(ImageType.Image2D, BufferFormat.R8G8B8A8_UNorm)
            {
                Width  = bitmap.Width,
                Height = bitmap.Height
            };

            IGorgonImage result     = new GorgonImage(info);
            BitmapData   bitmapLock = null;

            try
            {
                bitmapLock = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);

                if ((bitmap.PixelFormat == PixelFormat.Format32bppArgb) ||
                    (bitmap.PixelFormat == PixelFormat.Format32bppPArgb) ||
                    (bitmap.PixelFormat == PixelFormat.Format32bppRgb))
                {
                    Transfer32Argb(bitmapLock, result.Buffers[0]);
                }
                else
                {
                    Transfer24Rgb(bitmapLock, result.Buffers[0]);
                }
            }
            catch
            {
                result.Dispose();
                throw;
            }
            finally
            {
                if (bitmapLock != null)
                {
                    bitmap.UnlockBits(bitmapLock);
                }
            }

            return(result);
        }
Example #8
0
        /// <summary>
        /// Function to decode an image from a <see cref="Stream"/>.
        /// </summary>
        /// <param name="stream">The stream containing the image data to read.</param>
        /// <param name="size">The size of the image within the stream, in bytes.</param>
        /// <returns>A <see cref="IGorgonImage"/> containing the image data from the stream.</returns>
        /// <exception cref="GorgonException">Thrown when the image data in the stream has a pixel format that is unsupported.</exception>
        /// <remarks>
        /// <para>
        /// A codec must implement this method in order to decode the image data.
        /// </para>
        /// </remarks>
        protected override IGorgonImage OnDecodeFromStream(Stream stream, long size)
        {
            // Read the image meta data so we'll know how large the data should be.
            IGorgonImageInfo settings = ReadMetaData(stream);

            // Calculate the expected size of the image.
            int dataSize = settings.Width * settings.Height * sizeof(ushort);

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

            // Create our resulting image buffer.
            var result = new GorgonImage(settings);

            using (var reader = new GorgonBinaryReader(stream, true))
            {
                // Write each scanline.
                for (int y = 0; y < settings.Height; ++y)
                {
                    // 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.
                    int ptrPosition = (y * result.Buffers[0].PitchInformation.RowPitch);

                    // 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 = reader.ReadUInt16();

                        // 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.
                        uint color = (uint)(((pixel >> 8) & 0xff) << (8 * (x % 3)));
                        uint alpha = (uint)((pixel & 0xff) << 24);

                        ref uint imagePixel = ref result.ImageData.ReadAs <uint>(ptrPosition);
                        imagePixel   = color | alpha;
                        ptrPosition += sizeof(uint);
                    }
                }
            }
Example #9
0
        /// <summary>
        /// Function to copy bitmap data to a texture.
        /// </summary>
        /// <param name="bitmap">Bitmap to copy.</param>
        /// <param name="image">Image to receive the data.</param>
        /// <param name="arrayIndex">The index in the bitmap array to copy from.</param>
        private unsafe void CopyBitmap(Bitmap bitmap, GorgonImage image, int arrayIndex)
        {
            BitmapData sourcePixels = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            try
            {
                int *pixels = (int *)sourcePixels.Scan0.ToPointer();

                for (int y = 0; y < bitmap.Height; y++)
                {
                    // We only need the width here, as our pointer will handle the stride by virtue of being an int.
                    int *offset = pixels + (y * bitmap.Width);

                    int destOffset = y * image.Buffers[0, arrayIndex].PitchInformation.RowPitch;
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        // The DXGI format nomenclature is a little confusing as we tend to think of the layout as being highest to
                        // lowest, but in fact, it is lowest to highest.
                        // So, we must convert to ABGR even though the DXGI format is RGBA. The memory layout is from lowest
                        // (R at byte 0) to the highest byte (A at byte 3).
                        // Thus, R is the lowest byte, and A is the highest: A(24), B(16), G(8), R(0).
                        var color = new GorgonColor(*offset);

                        if (Info.UsePremultipliedTextures)
                        {
                            // Convert to premultiplied.
                            color = new GorgonColor(color.Red * color.Alpha, color.Green * color.Alpha, color.Blue * color.Alpha, color.Alpha);
                        }

                        int *destBuffer = (int *)(Unsafe.AsPointer(ref image.Buffers[0, arrayIndex].Data[destOffset]));
                        *    destBuffer = color.ToABGR();
                        offset++;
                        destOffset += image.FormatInfo.SizeInBytes;
                    }
                }
            }
            finally
            {
                bitmap.UnlockBits(sourcePixels);
            }
        }
Example #10
0
        /// <summary>
        /// Function to convert the specified image into a 2D image.
        /// </summary>
        /// <param name="image">The image to convert.</param>
        /// <param name="isCubeMap"><b>true</b> if the image should be a cube map, or <b>false</b> if not.</param>
        /// <returns>The converted image.</returns>
        public IGorgonImage ConvertTo2D(IGorgonImage image, bool isCubeMap)
        {
            IGorgonImage result = null;

            try
            {
                var info = new GorgonImageInfo(image, isCubeMap ? ImageType.ImageCube : ImageType.Image2D)
                {
                    ArrayCount = image.ArrayCount,
                    Depth      = 1
                };

                if (isCubeMap)
                {
                    while ((info.ArrayCount % 6) != 0)
                    {
                        ++info.ArrayCount;
                    }
                }

                result = new GorgonImage(info);

                // Copy the mip levels and array indices (for cube -> 2D and 2D -> cube, 3D always has an array count of 1).
                for (int array = 0; array < image.ArrayCount; ++array)
                {
                    for (int mip = 0; mip < result.MipCount; ++mip)
                    {
                        image.Buffers[mip, array].CopyTo(result.Buffers[mip, array]);
                    }
                }
            }
            catch
            {
                result?.Dispose();
                throw;
            }

            return(result);
        }
Example #11
0
        /// <summary>
        /// Function to update the number of mip levels on an image.
        /// </summary>
        /// <param name="sourceImage">The source image to update.</param>
        /// <param name="newMipCount">The new number of mip levels for the resulting image.</param>
        /// <returns>The updated image, or the same image if no changes were made.</returns>
        public IGorgonImage ChangeMipCount(IGorgonImage sourceImage, int newMipCount)
        {
            if (sourceImage.MipCount == newMipCount)
            {
                return(sourceImage);
            }

            int maxDepth    = sourceImage.Depth;
            int minMipCount = newMipCount
                              .Min(sourceImage.MipCount)
                              .Min(GorgonImage.CalculateMaxMipCount(sourceImage.Width, sourceImage.Height, sourceImage.Depth));

            IGorgonImage result = new GorgonImage(new GorgonImageInfo(sourceImage)
            {
                MipCount = newMipCount
            });

            for (int array = 0; array < sourceImage.ArrayCount; ++array)
            {
                for (int mip = 0; mip < minMipCount; ++mip)
                {
                    for (int depth = 0; depth < maxDepth; ++depth)
                    {
                        int depthOrArray        = sourceImage.ImageType == ImageType.Image3D ? depth : array;
                        IGorgonImageBuffer src  = sourceImage.Buffers[mip, depthOrArray];
                        IGorgonImageBuffer dest = result.Buffers[mip, depthOrArray];
                        src.CopyTo(dest);
                    }

                    maxDepth >>= 1;
                    if (maxDepth < 1)
                    {
                        maxDepth = 1;
                    }
                }
            }

            return(result);
        }
Example #12
0
        /// <summary>
        /// Function to update the depth slice count for a 3D image, or the array index count for a 2D/cube image.
        /// </summary>
        /// <param name="sourceImage">The image to update.</param>
        /// <param name="arrayOrDepthCount">The new depth or array count.</param>
        /// <returns>A new image with the specified depth/array count, or the same image if no changes were made.</returns>
        public IGorgonImage ChangeArrayOrDepthCount(IGorgonImage sourceImage, int arrayOrDepthCount)
        {
            int currentArrayOrDepth = sourceImage.ImageType == ImageType.Image3D ? sourceImage.Depth : sourceImage.ArrayCount;
            int depthCount          = sourceImage.ImageType == ImageType.Image3D ? arrayOrDepthCount : 1;
            int arrayCount          = sourceImage.ImageType != ImageType.Image3D ? arrayOrDepthCount : 1;

            if (currentArrayOrDepth == arrayOrDepthCount)
            {
                return(sourceImage);
            }

            IGorgonImage newImage = new GorgonImage(new GorgonImageInfo(sourceImage)
            {
                Depth      = depthCount,
                ArrayCount = arrayCount
            });

            for (int array = 0; array < arrayCount.Min(sourceImage.ArrayCount); ++array)
            {
                for (int mip = 0; mip < sourceImage.MipCount; ++mip)
                {
                    for (int depth = 0; depth < depthCount.Min(sourceImage.GetDepthCount(mip)); ++depth)
                    {
                        IGorgonImageBuffer srcBuffer  = sourceImage.Buffers[mip, sourceImage.ImageType == ImageType.Image3D ? depth : array];
                        IGorgonImageBuffer destBuffer = newImage.Buffers[mip, sourceImage.ImageType == ImageType.Image3D ? depth : array];
                        srcBuffer.CopyTo(destBuffer);
                    }

                    depthCount >>= 1;

                    if (depthCount < 1)
                    {
                        depthCount = 1;
                    }
                }
            }

            return(newImage);
        }
Example #13
0
        /// <summary>
        /// Function to retrieve an image based on the array index.
        /// </summary>
        /// <param name="sourceImage">The image to extract the array index from.</param>
        /// <param name="currentArrayIndex">The array index to extract.</param>
        /// <returns>A new image with the specified array index.</returns>
        public IGorgonImage GetArrayIndexAsImage(IGorgonImage sourceImage, int currentArrayIndex)
        {
            if (sourceImage.ArrayCount == 1)
            {
                return(sourceImage);
            }

            IGorgonImage result = new GorgonImage(new GorgonImageInfo(sourceImage)
            {
                ArrayCount = 1
            });

            for (int mip = 0; mip < result.MipCount; ++mip)
            {
                IGorgonImageBuffer srcBuffer  = sourceImage.Buffers[mip, currentArrayIndex];
                IGorgonImageBuffer destBuffer = result.Buffers[mip, 0];

                srcBuffer.CopyTo(destBuffer);
            }

            return(result);
        }
Example #14
0
        /// <summary>
        /// Function to draw some pretty pixels into a custom image for the example.
        /// </summary>
        private void CreateCustomImage()
        {
            // Create the image at the original size.
            var sourceImage = new GorgonImage(new GorgonImageInfo(ImageType.Image2D, BufferFormat.R8G8B8A8_UNorm)
            {
                Width  = 320,
                Height = 240
            });

            // Draw something pretty...
            float width  = sourceImage.Width;
            float height = sourceImage.Height;

            for (int x = 0; x < sourceImage.Width; ++x)
            {
                float rColorFade = ((x / width) * 1.5f).Cos();

                for (int y = 0; y < sourceImage.Height; ++y)
                {
                    float bColorFade = ((y / height) * 1.5f).Sin();

                    int pixelStride = sourceImage.Buffers[0].PitchInformation.RowPitch / sourceImage.Buffers[0].Width;
                    // This is the position inside of the buffer, in bytes.
                    int position = (y * sourceImage.Buffers[0].PitchInformation.RowPitch) + (x * pixelStride);
                    var color    = new GorgonColor(rColorFade, 1.0f - rColorFade, bColorFade, 1.0f);

                    // Notice we're using ReadAs here.  This allows us to read a value as another type.  In this case, we've chosen an
                    // int32 value to represent an ARGB pixel. Because this value is a reference to the location in memory, we can assign
                    // a new value to it.
                    //
                    // Do note that the position is a byte address, and not an int address (i.e. position = 1 is 1 byte, not 1 int).
                    ref int pixel = ref sourceImage.Buffers[0].Data.ReadAs <int>(position);
                    pixel = color.ToARGB();

                    // We could easily do this as well (although this could be considered less readable):
                    //_image.Buffers[0].Data.ReadAs<int>(position) = color.ToARGB();
                }
            }
Example #15
0
        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Form.Load"></see> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            try
            {
                GorgonExample.PlugInLocationDirectory = new DirectoryInfo(Settings.Default.PlugInLocation);

                // Load the assembly.
                _assemblyCache = new GorgonMefPlugInCache(GorgonApplication.Log);

                // Create the plugin service.
                IGorgonPlugInService plugInService = new GorgonMefPlugInService(_assemblyCache);

                // Create the factory to retrieve gaming device drivers.
                var factory = new GorgonGamingDeviceDriverFactory(plugInService);

                // Create the raw input interface.
                _input = new GorgonRawInput(this, GorgonApplication.Log);

                // Get available gaming device driver plug ins.
                _assemblyCache.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, "Gorgon.Input.DirectInput.dll");
                _assemblyCache.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, "Gorgon.Input.XInput.dll");

                _drivers = factory.LoadAllDrivers();

                _joystickList = new List <IGorgonGamingDevice>();

                // Get all gaming devices from the drivers.
                foreach (IGorgonGamingDeviceDriver driver in _drivers)
                {
                    IReadOnlyList <IGorgonGamingDeviceInfo> infoList = driver.EnumerateGamingDevices(true);

                    foreach (IGorgonGamingDeviceInfo info in infoList)
                    {
                        IGorgonGamingDevice device = driver.CreateGamingDevice(info);

                        // Turn off dead zones for this example.
                        foreach (GorgonGamingDeviceAxis axis in device.Axis)
                        {
                            axis.DeadZone = GorgonRange.Empty;
                        }

                        _joystickList.Add(device);
                    }
                }

                // Create mouse.
                _mouse = new GorgonRawMouse();

                // Create the graphics interface.
                ClientSize = Settings.Default.Resolution;

                IReadOnlyList <IGorgonVideoAdapterInfo> adapters = GorgonGraphics.EnumerateAdapters();
                _graphics = new GorgonGraphics(adapters[0], log: GorgonApplication.Log);
                _screen   = new GorgonSwapChain(_graphics, this, new GorgonSwapChainInfo("INeedYourInput Swapchain")
                {
                    Width  = Settings.Default.Resolution.Width,
                    Height = Settings.Default.Resolution.Height,
                    Format = BufferFormat.R8G8B8A8_UNorm
                });
                _graphics.SetRenderTarget(_screen.RenderTargetView);

                if (!Settings.Default.IsWindowed)
                {
                    _screen.EnterFullScreen();
                }

                // For the backup image. Used to make it as large as the monitor that we're on.
                var currentScreen = Screen.FromHandle(Handle);

                // Relocate the window to the center of the screen.
                Location = new Point(currentScreen.Bounds.Left + (currentScreen.WorkingArea.Width / 2) - (ClientSize.Width / 2),
                                     currentScreen.Bounds.Top + (currentScreen.WorkingArea.Height / 2) - (ClientSize.Height / 2));


                // Create the 2D renderer.
                _2D = new Gorgon2D(_graphics);

                // Create the text font.
                var fontFactory = new GorgonFontFactory(_graphics);
                _font = fontFactory.GetFont(new GorgonFontInfo("Arial", 9.0f, FontHeightMode.Points, "Arial 9pt")
                {
                    FontStyle        = FontStyle.Bold,
                    AntiAliasingMode = FontAntiAliasMode.AntiAlias
                });

                // Create text sprite.
                _messageSprite = new GorgonTextSprite(_font, "Using mouse and keyboard (Windows Forms).")
                {
                    Color = Color.Black
                };

                // Create a back buffer.
                _backBuffer = GorgonRenderTarget2DView.CreateRenderTarget(_graphics, new GorgonTexture2DInfo("Backbuffer storage")
                {
                    Width  = _screen.Width,
                    Height = _screen.Height,
                    Format = _screen.Format
                });
                _backBuffer.Clear(Color.White);
                _backBufferView = _backBuffer.GetShaderResourceView();

                // Clear our backup image to white to match our primary screen.
                using (IGorgonImage image = new GorgonImage(new GorgonImageInfo(ImageType.Image2D, _screen.Format)
                {
                    Width = _screen.Width,
                    Height = _screen.Height,
                    Format = _screen.Format
                }))
                {
                    image.Buffers[0].Fill(0xff);
                    _backupImage = image.ToTexture2D(_graphics,
                                                     new GorgonTexture2DLoadOptions
                    {
                        Binding = TextureBinding.None,
                        Usage   = ResourceUsage.Staging
                    });
                }

                // Set gorgon events.
                _screen.BeforeSwapChainResized += BeforeSwapChainResized;
                _screen.AfterSwapChainResized  += AfterSwapChainResized;

                // Enable the mouse.
                Cursor = Cursors.Cross;
                _mouse.MouseButtonDown += MouseInput;
                _mouse.MouseMove       += MouseInput;
                _mouse.MouseWheelMove  += (sender, args) =>
                {
                    _radius += args.WheelDelta.Sign();

                    if (_radius < 2.0f)
                    {
                        _radius = 2.0f;
                    }
                    if (_radius > 10.0f)
                    {
                        _radius = 10.0f;
                    }
                };

                // Set the mouse position.
                _mouse.Position = new Point(ClientSize.Width / 2, ClientSize.Height / 2);

                _noBlending = _blendBuilder.BlendState(GorgonBlendState.NoBlending)
                              .Build();
                _inverted = _blendBuilder.BlendState(GorgonBlendState.Inverted)
                            .Build();

                // Set up blending states for our pen.
                var blendStateBuilder = new GorgonBlendStateBuilder();
                _currentBlend = _drawModulatedBlend = _blendBuilder.BlendState(blendStateBuilder
                                                                               .ResetTo(GorgonBlendState.Default)
                                                                               .DestinationBlend(alpha: Blend.One)
                                                                               .Build())
                                                      .Build();

                _drawAdditiveBlend = _blendBuilder.BlendState(blendStateBuilder
                                                              .ResetTo(GorgonBlendState.Additive)
                                                              .DestinationBlend(alpha: Blend.One)
                                                              .Build())
                                     .Build();

                _drawNoBlend = _blendBuilder.BlendState(blendStateBuilder
                                                        .ResetTo(GorgonBlendState.NoBlending)
                                                        .DestinationBlend(alpha: Blend.One)
                                                        .Build())
                               .Build();

                GorgonApplication.IdleMethod = Gorgon_Idle;
            }
            catch (ReflectionTypeLoadException refEx)
            {
                string refErr = string.Join("\n", refEx.LoaderExceptions.Select(item => item.Message));
                GorgonDialogs.ErrorBox(this, refErr);
            }
            catch (Exception ex)
            {
                GorgonExample.HandleException(ex);
                GorgonApplication.Quit();
            }
        }
Example #16
0
        private void GenerateTextures(Dictionary <Bitmap, IEnumerable <GlyphInfo> > glyphData)
        {
            var imageSettings = new GorgonImageInfo(ImageType.Image2D, BufferFormat.R8G8B8A8_UNorm)
            {
                Width  = Info.TextureWidth,
                Height = Info.TextureHeight,
                Depth  = 1
            };
            var textureSettings = new GorgonTexture2DInfo
            {
                Format          = BufferFormat.R8G8B8A8_UNorm,
                Width           = Info.TextureWidth,
                Height          = Info.TextureHeight,
                Usage           = ResourceUsage.Default,
                Binding         = TextureBinding.ShaderResource,
                IsCubeMap       = false,
                MipLevels       = 1,
                MultisampleInfo = GorgonMultisampleInfo.NoMultiSampling
            };

            GorgonImage     image       = null;
            GorgonTexture2D texture     = null;
            int             arrayIndex  = 0;
            int             bitmapCount = glyphData.Count;

            try
            {
                // We copy each bitmap into a texture array index until we've hit the max texture array size, and then
                // we move to a new texture.  This will keep our glyph textures inside of a single texture object until
                // it is absolutely necessary to change and should improve performance when rendering.
                foreach (KeyValuePair <Bitmap, IEnumerable <GlyphInfo> > glyphBitmap in glyphData)
                {
                    if ((image == null) || (arrayIndex >= Graphics.VideoAdapter.MaxTextureArrayCount))
                    {
                        textureSettings.ArrayCount = imageSettings.ArrayCount = bitmapCount.Min(Graphics.VideoAdapter.MaxTextureArrayCount);
                        arrayIndex = 0;

                        image?.Dispose();
                        image = new GorgonImage(imageSettings);

                        texture = image.ToTexture2D(Graphics, new GorgonTexture2DLoadOptions
                        {
                            Name = $"GorgonFont_{Name}_Internal_Texture_{Guid.NewGuid():N}"
                        });
                        _internalTextures.Add(texture);
                    }

                    CopyBitmap(glyphBitmap.Key, image, arrayIndex);

                    // Send to our texture.
                    texture.SetData(image.Buffers[0, arrayIndex], destArrayIndex: arrayIndex);

                    foreach (GlyphInfo info in glyphBitmap.Value)
                    {
                        info.Texture           = texture;
                        info.TextureArrayIndex = arrayIndex;
                    }

                    bitmapCount--;
                    arrayIndex++;
                }
            }
            finally
            {
                image?.Dispose();
            }
        }
Example #17
0
        /// <summary>
        /// Function to create a compatible image to use when drawing with this effect.
        /// </summary>
        /// <param name="diffuse">The diffuse map.</param>
        /// <param name="normalMap">The normal map.</param>
        /// <param name="specularMap">[Optional] The specular map.</param>
        /// <returns>A new image with the maps combined as an image array to use with the effect.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="diffuse"/>, or the <paramref name="normalMap"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentException">Thrown if any of the images passed in are not a <see cref="ImageType.Image2D"/> type.</exception>
        /// <remarks>
        /// <para>
        /// Since the lighting effect requires that textures be drawn using an array of 3 images, developers can use this helper method to create a new image based on separate images that will be suitable
        /// for rendering with this effect.
        /// </para>
        /// <para>
        /// The resulting image from this method is guaranteed to contain the correct image data, in the correct order, for use with this effect. The image can then be used in any of the
        /// texture types for rendering.
        /// </para>
        /// <para>
        /// The images passed to this method must be a 2D image type, otherwise an exception will thrown.
        /// </para>
        /// <para>
        /// All images passed to this method should be the same width, height and pixel format. Otherwise undesired artifacts may appear on the generated maps.
        /// </para>
        /// </remarks>
        /// <seealso cref="IGorgonImage"/>
        /// <seealso cref="GorgonTexture2D"/>
        /// <seealso cref="GorgonTexture2DView"/>
        public IGorgonImage CreateLightingImage(IGorgonImage diffuse, IGorgonImage normalMap, IGorgonImage specularMap = null)
        {
            if (diffuse == null)
            {
                throw new ArgumentNullException(nameof(diffuse));
            }

            if (normalMap == null)
            {
                throw new ArgumentNullException(nameof(normalMap));
            }

            if (diffuse.ImageType != ImageType.Image2D)
            {
                throw new ArgumentException(string.Format(Resources.GOR2D_ERR_2D_IMAGE_ONLY, nameof(diffuse)));
            }

            if (normalMap.ImageType != ImageType.Image2D)
            {
                throw new ArgumentException(string.Format(Resources.GOR2D_ERR_2D_IMAGE_ONLY, nameof(normalMap)));
            }

            if ((specularMap != null) && (specularMap.ImageType != ImageType.Image2D))
            {
                throw new ArgumentException(string.Format(Resources.GOR2D_ERR_2D_IMAGE_ONLY, nameof(specularMap)));
            }

            IGorgonImage result       = null;
            IGorgonImage workSpecular = specularMap?.Clone();
            IGorgonImage workDiffuse  = diffuse.Clone();
            IGorgonImage workNormal   = normalMap.Clone();

            if (workSpecular == null)
            {
                workSpecular = new GorgonImage(new GorgonImageInfo(ImageType.Image2D, diffuse.Format)
                {
                    Width  = diffuse.Width,
                    Height = diffuse.Height
                });
                workSpecular.Buffers[0].Fill(0x00);
            }

            try
            {
                // Ensure formats are the same across all array entries.
                if (workNormal.Format != workDiffuse.Format)
                {
                    workNormal.ConvertToFormat(workDiffuse.Format);
                }

                if (workSpecular.Format != workDiffuse.Format)
                {
                    workSpecular.ConvertToFormat(workDiffuse.Format);
                }

                // Ensure width and height matches.
                if ((workNormal.Width != workDiffuse.Width) || (workDiffuse.Height != workNormal.Height))
                {
                    workNormal.Resize(workDiffuse.Width, workDiffuse.Height, 1);
                }

                if ((workSpecular.Width != workDiffuse.Width) || (workSpecular.Height != workNormal.Height))
                {
                    workSpecular.Resize(workDiffuse.Width, workDiffuse.Height, 1);
                }

                var info = new GorgonImageInfo(ImageType.Image2D, diffuse.Format)
                {
                    Width      = diffuse.Width,
                    Height     = diffuse.Height,
                    ArrayCount = 3
                };

                result = new GorgonImage(info);
                workDiffuse.Buffers[0].CopyTo(result.Buffers[0, 0]);
                workSpecular.Buffers[0].CopyTo(result.Buffers[0, 1]);
                workNormal.Buffers[0].CopyTo(result.Buffers[0, 2]);

                return(result);
            }
            catch
            {
                result?.Dispose();
                throw;
            }
            finally
            {
                workDiffuse?.Dispose();
                workNormal?.Dispose();
                workSpecular.Dispose();
            }
        }