/// <summary>
        /// Function to load the texture information.
        /// </summary>
        /// <param name="reader">The reader containing the texture information.</param>
        /// <param name="overrideTexture">The texture to assign to the sprite instead of the texture associated with the name stored in the file.</param>
        /// <param name="textureOffset">The texture transform offset.</param>
        /// <param name="textureScale">The texture transform scale.</param>
        /// <param name="textureArrayIndex">The texture array index.</param>
        /// <returns>The texture attached to the sprite.</returns>
        private GorgonTexture2DView LoadTexture(GorgonBinaryReader reader, GorgonTexture2DView overrideTexture, out DX.Vector2 textureOffset, out DX.Vector2 textureScale, out int textureArrayIndex)
        {
            // Write out as much info about the texture as we can so we can look it up based on these values when loading.
            string textureName = reader.ReadString();

            textureOffset     = DX.Vector2.Zero;
            textureScale      = DX.Vector2.One;
            textureArrayIndex = 0;

            if (string.IsNullOrWhiteSpace(textureName))
            {
                return(null);
            }

            reader.ReadValue(out textureOffset);
            reader.ReadValue(out textureScale);
            reader.ReadValue(out textureArrayIndex);
            reader.ReadValue(out int textureWidth);
            reader.ReadValue(out int textureHeight);
            reader.ReadValue(out BufferFormat textureFormat);
            reader.ReadValue(out int textureArrayCount);
            reader.ReadValue(out int textureMipCount);

            GorgonTexture2D texture = null;

            // Locate the texture resource.
            if (overrideTexture == null)
            {
                texture = Renderer.Graphics.LocateResourcesByName <GorgonTexture2D>(textureName)
                          .FirstOrDefault(item => item.Width == textureWidth &&
                                          item.Height == textureHeight &&
                                          item.Format == textureFormat &&
                                          item.ArrayCount == textureArrayCount &&
                                          item.MipLevels == textureMipCount);

                if (texture == null)
                {
                    textureOffset     = DX.Vector2.Zero;
                    textureScale      = DX.Vector2.One;
                    textureArrayIndex = 0;
                    return(null);
                }
            }

            reader.ReadValue(out int viewArrayIndex);
            reader.ReadValue(out int viewArrayCount);
            reader.ReadValue(out int viewMipSlice);
            reader.ReadValue(out int viewMipCount);
            reader.ReadValue(out BufferFormat viewFormat);

            return(overrideTexture ?? texture.GetShaderResourceView(viewFormat, viewMipSlice, viewMipCount, viewArrayIndex, viewArrayCount));
        }
Пример #2
0
        /// <summary>
        /// Function to change the texture pointed at by this glyph.
        /// </summary>
        /// <param name="texture">The texture to assign to the glyph.</param>
        /// <param name="glyphCoordinates">The coordinates of the glyph on the texture, in pixels.</param>
        /// <param name="outlineCoordinates">The coordinates of the glyph outline on the texture, in pixels.</param>
        /// <param name="textureArrayIndex">The array index on the 2D texture array to use for this glyph.</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="texture"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="texture"/> is not a 2D texture.
        /// <para>-or-</para>
        /// <para>Thrown if the <paramref name="texture"/> format is not <see cref="BufferFormat.R8G8B8A8_UNorm"/>, <see cref="BufferFormat.R8G8B8A8_UNorm_SRgb"/>, <see cref="BufferFormat.B8G8R8A8_UNorm"/> or
        /// <see cref="BufferFormat.B8G8R8A8_UNorm_SRgb"/>.</para>
        /// </exception>
        /// <remarks>
        /// <para>
        /// This allows an application to point a glyph at a new <see cref="GorgonTexture2D"/> for custom bitmap glyphs, or allows the region on the texture that contains the glyph to be modified. This
        /// allows applications to create custom characters in fonts that the font generation code cannot produce.
        /// </para>
        /// <para>
        /// Currently any custom texture/coordinates are not persisted when the font is saved.  This may change in a future release of Gorgon.
        /// </para>
        /// <para>
        /// If the <see cref="GorgonFont"/> for this glyph does not have an outline, then the <paramref name="outlineCoordinates"/> should be set to empty.
        /// </para>
        /// </remarks>
        public void UpdateTexture(GorgonTexture2D texture, DX.Rectangle glyphCoordinates, DX.Rectangle outlineCoordinates, int textureArrayIndex)
        {
            if (texture == null)
            {
                throw new ArgumentNullException(nameof(texture));
            }

            if ((texture == TextureView?.Texture) &&
                (glyphCoordinates == GlyphCoordinates) &&
                (outlineCoordinates == OutlineCoordinates) &&
                (TextureIndex == textureArrayIndex))
            {
                return;
            }

            if (texture != TextureView?.Texture)
            {
                if ((texture.Format != BufferFormat.R8G8B8A8_UNorm) &&
                    (texture.Format != BufferFormat.R8G8B8A8_UNorm_SRgb) &&
                    (texture.Format != BufferFormat.B8G8R8A8_UNorm) &&
                    (texture.Format != BufferFormat.B8G8R8A8_UNorm_SRgb))
                {
                    throw new ArgumentException(Resources.GORGFX_ERR_GLYPH_TEXTURE_FORMAT_INVALID, nameof(texture));
                }

                TextureView = texture.GetShaderResourceView();
            }

            // Ensure that this index is valid.
            textureArrayIndex = textureArrayIndex.Max(0).Min(TextureView?.Texture.ArrayCount - 1 ?? 0);

            TextureIndex       = textureArrayIndex;
            GlyphCoordinates   = glyphCoordinates;
            OutlineCoordinates = outlineCoordinates;
            TextureCoordinates = texture.ToTexel(glyphCoordinates);

            if (OutlineCoordinates.IsEmpty)
            {
                return;
            }

            OutlineTextureCoordinates = texture.ToTexel(outlineCoordinates);
        }
Пример #3
0
        /// <summary>
        /// Function to load a texture from a file.
        /// </summary>
        /// <param name="graphics">The graphics interface that will own the texture.</param>
        /// <param name="filePath">The path to the file.</param>
        /// <param name="codec">The codec that is used to decode the the data in the stream.</param>
        /// <param name="options">[Optional] Options used to further define the texture.</param>
        /// <returns>A new <see cref="GorgonTexture2DView"/></returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, <paramref name="filePath"/>, or the <paramref name="codec"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="filePath"/> parameter is empty.</exception>
        /// <remarks>
        /// <para>
        /// This will load an <see cref="IGorgonImage"/> from a file on disk and put it into a <see cref="GorgonTexture2D"/> object and return a <see cref="GorgonTexture2DView"/>.
        /// </para>
        /// <para>
        /// If specified, the <paramref name="options"/>parameter will define how Gorgon and shaders should handle the texture.  The <see cref="GorgonTextureLoadOptions"/> type contains the following:
        /// <list type="bullet">
        ///		<item>
        ///			<term>Binding</term>
        ///			<description>When defined, will indicate the <see cref="TextureBinding"/> that defines how the texture will be bound to the graphics pipeline. If it is omitted, then the binding will be
        ///         <see cref="TextureBinding.ShaderResource"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Usage</term>
        ///			<description>When defined, will indicate the preferred usage for the texture. If it is omitted, then the usage will be set to <see cref="ResourceUsage.Default"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Multisample info</term>
        ///			<description>When defined (i.e. not <b>null</b>), defines the multisampling to apply to the texture. If omitted, then the default is <see cref="GorgonMultisampleInfo.NoMultiSampling"/>.</description>
        ///		</item>
        ///		<item>
        ///		    <term>ConvertToPremultipliedAlpha</term>
        ///		    <description>Converts the image to premultiplied alpha before uploading the image data to the texture.</description>
        ///		</item>
        /// </list>
        /// </para>
        /// <para>
        /// Since the <see cref="GorgonTexture2D"/> created by this method is linked to the <see cref="GorgonTexture2DView"/> returned, disposal of either one will dispose of the other on your behalf. If
        /// the user created a <see cref="GorgonTexture2DView"/> from the <see cref="GorgonTexture2D.GetShaderResourceView"/> method on the <see cref="GorgonTexture2D"/>, then it's assumed the user knows
        /// what they are doing and will handle the disposal of the texture and view on their own.
        /// </para>
        /// </remarks>
        public static GorgonTexture2DView FromFile(GorgonGraphics graphics, string filePath, IGorgonImageCodec codec, GorgonTexture2DLoadOptions options = null)
        {
            if (graphics == null)
            {
                throw new ArgumentNullException(nameof(graphics));
            }

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

            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentEmptyException(nameof(filePath));
            }

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

            using (IGorgonImage image = codec.LoadFromFile(filePath))
            {
                if (options == null)
                {
                    options = new GorgonTexture2DLoadOptions
                    {
                        Name          = Path.GetFileNameWithoutExtension(filePath),
                        Usage         = ResourceUsage.Default,
                        Binding       = TextureBinding.ShaderResource,
                        IsTextureCube = image.ImageType == ImageType.ImageCube
                    };
                }
                GorgonTexture2D     texture = image.ToTexture2D(graphics, options);
                GorgonTexture2DView view    = texture.GetShaderResourceView();
                view.OwnsResource = true;
                return(view);
            }
        }
Пример #4
0
        /// <summary>
        /// Function to load a texture from a <see cref="Stream"/>.
        /// </summary>
        /// <param name="graphics">The graphics interface that will own the texture.</param>
        /// <param name="stream">The stream containing the texture image data.</param>
        /// <param name="codec">The codec that is used to decode the the data in the stream.</param>
        /// <param name="size">[Optional] The size of the image in the stream, in bytes.</param>
        /// <param name="options">[Optional] Options used to further define the texture.</param>
        /// <returns>A new <see cref="GorgonTexture2DView"/></returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, <paramref name="stream"/>, or the <paramref name="codec"/> parameter is <b>null</b>.</exception>
        /// <exception cref="IOException">Thrown if the <paramref name="stream"/> is write only.</exception>
        /// <exception cref="EndOfStreamException">Thrown if reading the image would move beyond the end of the <paramref name="stream"/>.</exception>
        /// <remarks>
        /// <para>
        /// This will load an <see cref="IGorgonImage"/> from a <paramref name="stream"/> and put it into a <see cref="GorgonTexture2D"/> object and return a <see cref="GorgonTexture2DView"/>.
        /// </para>
        /// <para>
        /// If the <paramref name="size"/> option is specified, then the method will read from the stream up to that number of bytes, so it is up to the user to provide an accurate size. If it is omitted
        /// then the <c>stream length - stream position</c> is used as the total size.
        /// </para>
        /// <para>
        /// If specified, the <paramref name="options"/>parameter will define how Gorgon and shaders should handle the texture.  The <see cref="GorgonTextureLoadOptions"/> type contains the following:
        /// <list type="bullet">
        ///		<item>
        ///			<term>Binding</term>
        ///			<description>When defined, will indicate the <see cref="TextureBinding"/> that defines how the texture will be bound to the graphics pipeline. If it is omitted, then the binding will be
        ///         <see cref="TextureBinding.ShaderResource"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Usage</term>
        ///			<description>When defined, will indicate the preferred usage for the texture. If it is omitted, then the usage will be set to <see cref="ResourceUsage.Default"/>.</description>
        ///		</item>
        ///		<item>
        ///			<term>Multisample info</term>
        ///			<description>When defined (i.e. not <b>null</b>), defines the multisampling to apply to the texture. If omitted, then the default is <see cref="GorgonMultisampleInfo.NoMultiSampling"/>.</description>
        ///		</item>
        ///		<item>
        ///		    <term>ConvertToPremultipliedAlpha</term>
        ///		    <description>Converts the image to premultiplied alpha before uploading the image data to the texture.</description>
        ///		</item>
        /// </list>
        /// </para>
        /// <para>
        /// Since the <see cref="GorgonTexture2D"/> created by this method is linked to the <see cref="GorgonTexture2DView"/> returned, disposal of either one will dispose of the other on your behalf. If
        /// the user created a <see cref="GorgonTexture2DView"/> from the <see cref="GorgonTexture2D.GetShaderResourceView"/> method on the <see cref="GorgonTexture2D"/>, then it's assumed the user knows
        /// what they are doing and will handle the disposal of the texture and view on their own.
        /// </para>
        /// </remarks>
        public static GorgonTexture2DView FromStream(GorgonGraphics graphics, Stream stream, IGorgonImageCodec codec, long?size = null, GorgonTexture2DLoadOptions options = null)
        {
            if (graphics == null)
            {
                throw new ArgumentNullException(nameof(graphics));
            }

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

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

            if (!stream.CanRead)
            {
                throw new IOException(Resources.GORGFX_ERR_STREAM_WRITE_ONLY);
            }

            if (size == null)
            {
                size = stream.Length - stream.Position;
            }

            if ((stream.Length - stream.Position) < size)
            {
                throw new EndOfStreamException();
            }

            using (IGorgonImage image = codec.LoadFromStream(stream, size))
            {
                GorgonTexture2D     texture = image.ToTexture2D(graphics, options);
                GorgonTexture2DView view    = texture.GetShaderResourceView();
                view.OwnsResource = true;
                return(view);
            }
        }
Пример #5
0
        /// <summary>
        /// Function to load a version 1.x Gorgon sprite.
        /// </summary>
        /// <param name="graphics">The graphics interface used to create states.</param>
        /// <param name="reader">Binary reader to use to read in the data.</param>
        /// <param name="overrideTexture">The texture to assign to the sprite instead of the texture associated with the name stored in the file.</param>
        /// <returns>The sprite from the stream data.</returns>
        private static GorgonSprite LoadSprite(GorgonGraphics graphics, GorgonBinaryReader reader, GorgonTexture2DView overrideTexture)
        {
            Version version;
            string  imageName = string.Empty;

            string headerVersion = reader.ReadString();

            if ((!headerVersion.StartsWith("GORSPR", StringComparison.OrdinalIgnoreCase)) ||
                (headerVersion.Length < 7) ||
                (headerVersion.Length > 9))
            {
                throw new GorgonException(GorgonResult.CannotRead, Resources.GOR2DIO_ERR_INVALID_HEADER);
            }

            var sprite = new GorgonSprite();

            // Get the version information.
            switch (headerVersion.ToUpperInvariant())
            {
            case "GORSPR1":
                version = new Version(1, 0);
                break;

            case "GORSPR1.1":
                version = new Version(1, 1);
                break;

            case "GORSPR1.2":
                version = new Version(1, 2);
                break;

            default:
                throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOR2DIO_ERR_VERSION_MISMATCH, headerVersion));
            }

            // We don't need the sprite name.
            reader.ReadString();

            // Find out if we have an image.
            if (reader.ReadBoolean())
            {
                bool isRenderTarget = reader.ReadBoolean();

                imageName = reader.ReadString();

                // We won't be supporting reading render targets from sprites in this version.
                if (isRenderTarget)
                {
                    // Skip the target data.
                    reader.ReadInt32();
                    reader.ReadInt32();
                    reader.ReadInt32();
                    reader.ReadBoolean();
                    reader.ReadBoolean();
                }
            }

            // We don't use "inherited" values anymore.  But we need them because
            // the file doesn't include inherited data.
            bool InheritAlphaMaskFunction     = reader.ReadBoolean();
            bool InheritAlphaMaskValue        = reader.ReadBoolean();
            bool InheritBlending              = reader.ReadBoolean();
            bool InheritHorizontalWrapping    = reader.ReadBoolean();
            bool InheritSmoothing             = reader.ReadBoolean();
            bool InheritStencilCompare        = reader.ReadBoolean();
            bool InheritStencilEnabled        = reader.ReadBoolean();
            bool InheritStencilFailOperation  = reader.ReadBoolean();
            bool InheritStencilMask           = reader.ReadBoolean();
            bool InheritStencilPassOperation  = reader.ReadBoolean();
            bool InheritStencilReference      = reader.ReadBoolean();
            bool InheritStencilZFailOperation = reader.ReadBoolean();
            bool InheritVerticalWrapping      = reader.ReadBoolean();
            bool InheritDepthBias             = true;
            bool InheritDepthTestFunction     = true;
            bool InheritDepthWriteEnabled     = true;

            // Get version 1.1 fields.
            if ((version.Major == 1) && (version.Minor >= 1))
            {
                InheritDepthBias         = reader.ReadBoolean();
                InheritDepthTestFunction = reader.ReadBoolean();
                InheritDepthWriteEnabled = reader.ReadBoolean();
            }

            // Get the size of the sprite.
            sprite.Size = new DX.Size2F(reader.ReadSingle(), reader.ReadSingle());

            // Older versions of the sprite object used pixel space for their texture coordinates.  We will have to
            // fix up these coordinates into texture space once we have a texture loaded.  At this point, there's no guarantee
            // that the texture was loaded safely, so we'll have to defer it until later.
            // Also, older versions used the size the determine the area on the texture to cover.  So use the size to
            // get the texture bounds.
            var textureOffset = new DX.Vector2(reader.ReadSingle(), reader.ReadSingle());

            // Read the anchor.
            // Gorgon v3 anchors are relative, so we need to convert them based on our sprite size.
            sprite.Anchor = new DX.Vector2(reader.ReadSingle() / sprite.Size.Width, reader.ReadSingle() / sprite.Size.Height);

            // Get vertex offsets.
            sprite.CornerOffsets.UpperLeft  = new DX.Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);
            sprite.CornerOffsets.UpperRight = new DX.Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);
            sprite.CornerOffsets.LowerRight = new DX.Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);
            sprite.CornerOffsets.LowerLeft  = new DX.Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);

            // Get vertex colors.
            sprite.CornerColors.UpperLeft  = new GorgonColor(reader.ReadInt32());
            sprite.CornerColors.UpperRight = new GorgonColor(reader.ReadInt32());
            sprite.CornerColors.LowerLeft  = new GorgonColor(reader.ReadInt32());
            sprite.CornerColors.LowerRight = new GorgonColor(reader.ReadInt32());

            // Skip shader information.  Version 1.0 had shader information attached to the sprite.
            if ((version.Major == 1) && (version.Minor < 1))
            {
                if (reader.ReadBoolean())
                {
                    reader.ReadString();
                    reader.ReadBoolean();
                    if (reader.ReadBoolean())
                    {
                        reader.ReadString();
                    }
                }
            }

            // We no longer have an alpha mask function.
            if (!InheritAlphaMaskFunction)
            {
                reader.ReadInt32();
            }

            if (!InheritAlphaMaskValue)
            {
                // Direct 3D 9 used a value from 0..255 for alpha masking, we use
                // a scalar value so convert to a scalar.
                sprite.AlphaTest = new GorgonRangeF(0.0f, reader.ReadInt32() / 255.0f);
            }

            // Set the blending mode.
            if (!InheritBlending)
            {
                // Skip the blending mode.  We don't use it per-sprite.
                reader.ReadInt32();
                reader.ReadInt32();
                reader.ReadInt32();
            }

            // Get alpha blending mode.
            if ((version.Major == 1) && (version.Minor >= 2))
            {
                // Skip the blending mode information.  We don't use it per-sprite.
                reader.ReadInt32();
                reader.ReadInt32();
            }

            TextureWrap  hWrap         = TextureWrap.Clamp;
            TextureWrap  vWrap         = TextureWrap.Clamp;
            SampleFilter filter        = SampleFilter.MinMagMipLinear;
            GorgonColor  samplerBorder = GorgonColor.White;

            // Get horizontal wrapping mode.
            if (!InheritHorizontalWrapping)
            {
                hWrap = ConvertImageAddressToTextureAddress(reader.ReadInt32());
            }

            // Get smoothing mode.
            if (!InheritSmoothing)
            {
                filter = ConvertSmoothingToFilter(reader.ReadInt32());
            }

            // Get stencil stuff.
            if (!InheritStencilCompare)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilEnabled)
            {
                // We don't enable stencil in the same way anymore, so skip this value.
                reader.ReadBoolean();
            }
            if (!InheritStencilFailOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilMask)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilPassOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilReference)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilZFailOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }

            // Get vertical wrapping mode.
            if (!InheritVerticalWrapping)
            {
                vWrap = ConvertImageAddressToTextureAddress(reader.ReadInt32());
            }

            // Get depth info.
            if ((version.Major == 1) && (version.Minor >= 1))
            {
                if (!InheritDepthBias)
                {
                    // Depth bias values are quite different on D3D9 than they are on D3D11, so skip this.
                    reader.ReadSingle();
                }
                if (!InheritDepthTestFunction)
                {
                    // We don't use depth/stencil info per sprite anymore.
                    reader.ReadInt32();
                }
                if (!InheritDepthWriteEnabled)
                {
                    // We don't use depth/stencil info per sprite anymore.
                    reader.ReadBoolean();
                }

                samplerBorder = new GorgonColor(reader.ReadInt32());

                // The border in the older version defaults to black.  To make it more performant, reverse this value to white.
                if (samplerBorder == GorgonColor.Black)
                {
                    samplerBorder = GorgonColor.White;
                }
            }

            // Get flipped flags.
            sprite.HorizontalFlip = reader.ReadBoolean();
            sprite.VerticalFlip   = reader.ReadBoolean();

            GorgonTexture2DView textureView;

            // Bind the texture (if we have one bound to this sprite) if it's already loaded, otherwise defer it.
            if ((!string.IsNullOrEmpty(imageName)) && (overrideTexture == null))
            {
                GorgonTexture2D texture = graphics.LocateResourcesByName <GorgonTexture2D>(imageName).FirstOrDefault();
                textureView = texture?.GetShaderResourceView();
            }
            else
            {
                textureView = overrideTexture;
            }

            // If we cannot load the image, then fall back to the standard coordinates.
            if (textureView == null)
            {
                sprite.TextureRegion = new DX.RectangleF(0, 0, 1, 1);
            }
            else
            {
                sprite.TextureRegion = new DX.RectangleF(textureOffset.X / textureView.Width,
                                                         textureOffset.Y / textureView.Height,
                                                         sprite.Size.Width / textureView.Width,
                                                         sprite.Size.Height / textureView.Height);
                sprite.TextureSampler = CreateSamplerState(graphics, filter, samplerBorder, hWrap, vWrap);
            }

            sprite.Texture = textureView;

            return(sprite);
        }
Пример #6
0
        /// <summary>
        /// Function to read a texture from the JSON data.
        /// </summary>
        /// <param name="reader">The JSON reader to use.</param>
        /// <param name="textureName">The name of the texture.</param>
        /// <returns></returns>
        public GorgonTexture2DView ReadTexture(JsonReader reader, out string textureName)
        {
            textureName = string.Empty;

            if ((reader.TokenType != JsonToken.StartObject) ||
                (_graphics == null))
            {
                return(null);
            }

            int?         texWidth       = null;
            int?         texHeight      = null;
            int?         texMipCount    = null;
            int?         texArrayCount  = null;
            BufferFormat?texFormat      = null;
            int?         viewMipStart   = null;
            int?         viewMipCount   = null;
            int?         viewArrayStart = null;
            int?         viewArrayCount = null;
            BufferFormat?viewFormat     = null;

            while ((reader.Read()) && (reader.TokenType != JsonToken.EndObject))
            {
                if (reader.TokenType != JsonToken.PropertyName)
                {
                    continue;
                }

                switch (reader.Value.ToString())
                {
                case "name":
                    textureName = reader.ReadAsString();
                    break;

                case "texWidth":
                    texWidth = reader.ReadAsInt32();
                    break;

                case "texHeight":
                    texHeight = reader.ReadAsInt32();
                    break;

                case "texFormat":
                    texFormat = (BufferFormat?)reader.ReadAsInt32();
                    break;

                case "texArrayCount":
                    texArrayCount = reader.ReadAsInt32();
                    break;

                case "texMipCount":
                    texMipCount = reader.ReadAsInt32();
                    break;

                case "arrayStart":
                    viewArrayStart = reader.ReadAsInt32();
                    break;

                case "arrayCount":
                    viewArrayCount = reader.ReadAsInt32();
                    break;

                case "mipStart":
                    viewMipStart = reader.ReadAsInt32();
                    break;

                case "mipCount":
                    viewMipCount = reader.ReadAsInt32();
                    break;

                case "format":
                    viewFormat = (BufferFormat?)reader.ReadAsInt32();
                    break;
                }
            }

            if ((string.IsNullOrWhiteSpace(textureName)) ||
                (texWidth == null) ||
                (texHeight == null) ||
                (texFormat == null) ||
                (texArrayCount == null) ||
                (texMipCount == null) ||
                (viewArrayStart == null) ||
                (viewArrayCount == null) ||
                (viewMipStart == null) ||
                (viewMipCount == null) ||
                (viewFormat == null))
            {
                if (string.IsNullOrWhiteSpace(textureName))
                {
                    _graphics?.Log.Print("Attempted to load a texture from JSON data, but texture was not in memory and name is unknown, or JSON texture data is not in the correct format.",
                                         LoggingLevel.Verbose);
                }

                return(null);
            }

            if (_override != null)
            {
                return(_override);
            }

            GorgonTexture2D texture = _graphics?.LocateResourcesByName <GorgonTexture2D>(textureName)
                                      .FirstOrDefault(item => (item.Width == texWidth) &&
                                                      (item.Height == texHeight) &&
                                                      (item.Format == texFormat) &&
                                                      (item.MipLevels == texMipCount) &&
                                                      (item.ArrayCount == texArrayCount));

            return(texture?.GetShaderResourceView(viewFormat.Value, viewMipStart.Value, viewMipCount.Value, viewArrayStart.Value, viewArrayCount.Value));
        }
Пример #7
0
        /// <summary>
        /// Function to load a version 1.x Gorgon sprite.
        /// </summary>
        /// <param name="graphics">The graphics interface used to create states.</param>
        /// <param name="reader">Binary reader to use to read in the data.</param>
        /// <param name="overrideTexture">The texture to assign to the sprite instead of the texture associated with the name stored in the file.</param>
        /// <returns>The sprite from the stream data.</returns>
        private static GorgonSprite LoadSprite(GorgonGraphics graphics, GorgonChunkReader reader, GorgonTexture2DView overrideTexture)
        {
            var sprite = new GorgonSprite();

            if (!reader.HasChunk(FileHeader))
            {
                throw new GorgonException(GorgonResult.CannotRead, Resources.GOR2DIO_ERR_INVALID_HEADER);
            }

            reader.Begin(FileHeader);
            reader.Begin(SpriteDataChunk);

            sprite.Anchor = reader.Read <DX.Vector2>();
            sprite.Size   = reader.Read <DX.Size2F>();
            sprite.Anchor = new DX.Vector2(sprite.Anchor.X / sprite.Size.Width, sprite.Anchor.Y / sprite.Size.Height);

            sprite.HorizontalFlip = reader.ReadBoolean();
            sprite.VerticalFlip   = reader.ReadBoolean();

            // Read vertex colors.
            sprite.CornerColors.UpperLeft  = reader.Read <GorgonColor>();
            sprite.CornerColors.UpperRight = reader.Read <GorgonColor>();
            sprite.CornerColors.LowerLeft  = reader.Read <GorgonColor>();
            sprite.CornerColors.LowerRight = reader.Read <GorgonColor>();

            // Write vertex offsets.
            sprite.CornerOffsets.UpperLeft  = new DX.Vector3(reader.Read <DX.Vector2>(), 0);
            sprite.CornerOffsets.UpperRight = new DX.Vector3(reader.Read <DX.Vector2>(), 0);
            sprite.CornerOffsets.LowerLeft  = new DX.Vector3(reader.Read <DX.Vector2>(), 0);
            sprite.CornerOffsets.LowerRight = new DX.Vector3(reader.Read <DX.Vector2>(), 0);

            reader.End();

            // Read rendering information.
            reader.Begin(RenderDataChunk);

            // Culling mode is not per-sprite anymore.
            reader.SkipBytes(Unsafe.SizeOf <CullingMode>());
            sprite.AlphaTest = reader.Read <GorgonRangeF>();

            // Blending values are not per-sprite anymore.
            // Depth/stencil values are not per-sprite anymore.
            reader.SkipBytes(91);
            reader.End();

            // Read texture information.
            reader.Begin(TextureDataChunk);
            GorgonColor borderColor = reader.Read <GorgonColor>();

            TextureWrap         hWrap       = ConvertV2TextureWrapToTextureAddress(reader.Read <int>());
            TextureWrap         vWrap       = ConvertV2TextureWrapToTextureAddress(reader.Read <int>());
            SampleFilter        filter      = ConvertV2TextureFilterToFilter(reader.Read <TextureFilter>());
            string              textureName = reader.ReadString();
            GorgonTexture2DView textureView;

            // Bind the texture (if we have one bound to this sprite) if it's already loaded, otherwise defer it.
            if ((!string.IsNullOrEmpty(textureName)) && (overrideTexture == null))
            {
                GorgonTexture2D texture = graphics.LocateResourcesByName <GorgonTexture2D>(textureName).FirstOrDefault();

                // If we used the editor build to sprite, the path to the texture is stored in the name instead of just the name.
                // So let's try and strip out the path information and extension and try again.
                if (texture == null)
                {
                    textureName = Path.GetFileNameWithoutExtension(textureName);
                    texture     = graphics.LocateResourcesByName <GorgonTexture2D>(textureName).FirstOrDefault();
                }

                textureView = texture?.GetShaderResourceView();
            }
            else
            {
                textureView = overrideTexture;
            }

            sprite.TextureRegion = reader.ReadRectangleF();

            if (textureView != null)
            {
                // V2 used black transparent by default, so convert it to our default so we can keep from creating unnecessary states.
                if (borderColor == GorgonColor.BlackTransparent)
                {
                    borderColor = GorgonColor.White;
                }

                sprite.Texture        = textureView;
                sprite.TextureSampler = CreateSamplerState(graphics, filter, borderColor, hWrap, vWrap);
            }

            reader.End();
            reader.End();

            return(sprite);
        }
Пример #8
0
        /// <summary>
        /// Function to load a sprite from the editor file system.
        /// </summary>
        /// <param name="fileSystem">The file system containing the editor data.</param>
        /// <param name="renderer">The current renderer.</param>
        /// <param name="path">The path to the sprite.</param>
        /// <param name="textureUsage">[Optional] The intended usage for the texture.</param>
        /// <param name="spriteCodecs">[Optional] A list of additonal codecs used to read sprite data.</param>
        /// <param name="imageCodecs">[Optional] A list of additonal codecs used to read image data.</param>
        /// <param name="overrideTexture">[Optional] A texture view to use instead of loading the texture from the file system.</param>
        /// <returns>A new <see cref="GorgonSprite"/>, along with its associated texture.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="fileSystem"/>, <paramref name="renderer"/>, or the <paramref name="path"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="path"/> parameter is empty.</exception>
        /// <exception cref="GorgonException">Thrown if the file system isn't a Gorgon Editor file system, or the file could not be read.</exception>
        /// <remarks>
        /// <para>
        /// This method will load a sprite from a Gorgon Editor file system mounted as a <see cref="IGorgonFileSystem"/>.
        /// </para>
        /// <para>
        /// The <paramref name="spriteCodecs"/> parameter is used to allow custom sprite codecs to be used when loading data (assuming the sprite data was generated using one of the codecs supplied). This
        /// allows a user to create a custom sprite codec plug in and use that to read sprite data.  The <paramref name="imageCodecs"/> is used in exactly the same way, but only for image data.
        /// </para>
        /// <para>
        /// Providing the <paramref name="overrideTexture"/> will skip the texture loading and use the texture passed in.  In this case, the texture return value will be <b>null</b> as it is assumed the
        /// user already knows about the texture resource and is managing the lifetime of the texture elsewhere.
        /// </para>
        /// <para>
        /// When the method returns, it returns a tuple containing the sprite that was loaded, and the associated texture resource for the sprite. If the texture could not be loaded for any reason,
        /// and the <paramref name="overrideTexture"/> parameter is <b>null</b>, then the texture return value will be <b>null</b>, and no texture will be assigned to the sprite.
        /// </para>
        /// <para>
        /// <h2>Technical info</h2>
        /// <para>
        /// Plug ins must generate the following metadata for the files in the editor file system.
        /// </para>
        /// <para>
        /// The sprite file metadata must have the following attributes: <c>Type</c> with a value of "Sprite", and <c>SpriteCodec</c>, and its associated texture must have a dependency type of <c>Image</c> or else the sprite will not load.
        /// </para>
        /// <para>
        /// The associated texture file metadata must have the following attributes: <c>Type</c> with a value of "Image", and <c>ImageCodec</c> or the texure will not load.
        /// </para>
        /// </para>
        /// <para>
        /// <note type="important">
        /// <para>
        /// <b>Regarding textures:</b> This method will load the associated texture for the sprite into memory, and will do its best to only load that texture one time. When the texture is loaded, it will
        /// remain resident until Gorgon is shut down (typically when the application shuts down). In many cases, this is not ideal, so users must dispose of the <see cref="GorgonTexture2D"/> returned by
        /// this method if unloading the texture data is desired (e.g. a level changes and new graphics need to be loaded).
        /// </para>
        /// </note>
        /// </para>
        /// </remarks>
        public static (GorgonSprite sprite, GorgonTexture2D texture) LoadSprite(this IGorgonFileSystem fileSystem, Gorgon2D renderer, string path, ResourceUsage textureUsage = ResourceUsage.Default, IReadOnlyList <IGorgonSpriteCodec> spriteCodecs = null, IReadOnlyList <IGorgonImageCodec> imageCodecs = null, GorgonTexture2DView overrideTexture = null)
        {
            if (fileSystem == null)
            {
                throw new ArgumentNullException(nameof(fileSystem));
            }

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

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

            if (string.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentEmptyException(nameof(path));
            }

            IProjectMetadata metaData = fileSystem.GetMetadata();

            if (!metaData.ProjectItems.TryGetValue(path, out ProjectItemMetadata fileMetadata))
            {
                throw new FileNotFoundException(string.Format(Resources.GOREDIT_ERR_FILE_NOT_FOUND, path));
            }

            IReadOnlyDictionary <string, IGorgonSpriteCodec> supportedSpriteCodecs = GetSpriteCodecs(renderer, spriteCodecs);
            IReadOnlyDictionary <string, IGorgonImageCodec>  supportedImageCodecs  = GetImageCodecs(imageCodecs);

            if ((!fileMetadata.Attributes.TryGetValue(CommonEditorConstants.ContentTypeAttr, out string contentType)) ||
                (!string.Equals(contentType, CommonEditorContentTypes.SpriteType, StringComparison.OrdinalIgnoreCase)))
            {
                throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOREDIT_ERR_NOT_SPRITE, path));
            }

            if (!fileMetadata.Attributes.TryGetValue("SpriteCodec", out string codecTypeName))
            {
                throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOREDIT_ERR_UNSUPPORTED_CODEC, string.Empty));
            }

            if (!supportedSpriteCodecs.TryGetValue(codecTypeName, out IGorgonSpriteCodec spriteCodec))
            {
                throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOREDIT_ERR_UNSUPPORTED_CODEC, codecTypeName));
            }

            IGorgonVirtualFile file = fileSystem.GetFile(path);

            if (file == null)
            {
                throw new FileNotFoundException(string.Format(Resources.GOREDIT_ERR_FILE_NOT_FOUND, path));
            }

            GorgonTexture2D texture = null;

            if (overrideTexture == null)
            {
                if (fileMetadata.DependsOn.TryGetValue(CommonEditorContentTypes.ImageType, out string imagePath))
                {
                    texture         = GetTexture(renderer.Graphics, fileSystem, metaData, imagePath, textureUsage, supportedImageCodecs);
                    overrideTexture = texture.GetShaderResourceView();
                }
            }

            using (Stream stream = file.OpenStream())
            {
                return(spriteCodec.FromStream(stream, overrideTexture, (int)file.Size), texture);
            }
        }