Beispiel #1
0
        /// <summary>
        /// Function to read uncompressed TGA scanline data.
        /// </summary>
        /// <param name="reader">The reader used to read in the data from the source stream.</param>
        /// <param name="width">Image width.</param>
        /// <param name="dest">Destination buffer pointner</param>
        /// <param name="format">Format of the destination buffer.</param>
        /// <param name="conversionFlags">Flags used for conversion.</param>
        private unsafe bool ReadCompressed(GorgonBinaryReader reader, int width, byte *dest, BufferFormat format, TGAConversionFlags conversionFlags)
        {
            bool setOpaque      = true;
            bool flipHorizontal = (conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX;
            bool expand         = (conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand;

            for (int x = 0; x < width;)
            {
                if (reader.BaseStream.Position >= reader.BaseStream.Length)
                {
                    throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
                }

                byte rleBlock = reader.ReadByte();
                int  size     = (rleBlock & 0x7F) + 1;
                if ((rleBlock & 0x80) != 0)
                {
                    if (!DecodeRleEncodedRun(reader, ref dest, ref x, size, width, expand, flipHorizontal, format))
                    {
                        setOpaque = false;
                    }
                    continue;
                }

                if (!DecodeUncompressedRun(reader, ref dest, ref x, size, width, expand, flipHorizontal, format))
                {
                    setOpaque = false;
                }
            }

            return(setOpaque);
        }
Beispiel #2
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);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Function to write an array of value types to a stream using the GorgonBinaryWriter and reading it back again using the GorgonBinaryReader.
        /// </summary>
        /// <param name="stream">The stream that will receive the data.</param>
        private static void WriteArrayValues(MemoryStream stream)
        {
            stream.Position = 0;

            var writer = new GorgonBinaryWriter(stream, true);
            var reader = new GorgonBinaryReader(stream, true);

            try
            {
                var expected = new SomeTestData[3];

                for (int i = 1; i < 4; ++i)
                {
                    expected[i - 1] = new SomeTestData
                    {
                        Value1 = i,
                        Value2 = System.Math.PI * i,
                        Value3 = (short)(i & 2)
                    };
                }

                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Writing/Reading an array of value types to a memory stream.");
                Console.ForegroundColor = ConsoleColor.White;

                writer.WriteRange(expected);

                stream.Position = 0;

                var actual = new SomeTestData[4];
                reader.ReadRange(actual, 1);

                for (int i = 1; i < 4; ++i)
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.Write($"[{i - 1}] ");
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine($"int32 Value1 = {expected[i - 1].Value1}: {actual[i].Value1 == expected[i - 1].Value1}");
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.Write($"[{i - 1}] ");
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine($"double Value2 = {expected[i - 1].Value2:0.00000}: {actual[i].Value2.EqualsEpsilon(expected[i - 1].Value2)}");
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.Write($"[{i - 1}] ");
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine($"int16 Value3 = {expected[i - 1].Value3}: {actual[i].Value3 == expected[i - 1].Value3}");
                }

                stream.Position = 0;
            }
            finally
            {
                writer.Dispose();
                reader.Dispose();
            }
        }
Beispiel #4
0
        /// <summary>
        /// Function to determine if this codec can read the file or not.
        /// </summary>
        /// <param name="stream">Stream used to read the file information.</param>
        /// <returns>
        /// TRUE if the codec can read the file, FALSE if not.
        /// </returns>
        /// <remarks>
        /// This is the method we'll use to determine if the data in the stream can actually be read by our codec.  Typically this is done by a "magic number" consisting of a set of bytes
        /// that identify the data as the type we're expecting.  To retrieve the magic number we'll read in the meta data for the image, which may not seem efficient, but it gives us the
        /// ability to also check to ensure that the image stream contains enough information about the image to actually load it by comparing the size of the meta data in the stream with
        /// the required meta data size.
        /// <para>
        /// When overloading this method, the implementor should remember to reset the stream position back to the original position when they are done reading the data.  Failure to do so
        /// may cause undesirable results.
        /// </para>
        /// </remarks>
        /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception>
        /// <exception cref="System.IO.IOException">Thrown when the <paramref name="stream"/> is write-only or if the stream cannot perform seek operations.</exception>
        /// <exception cref="System.IO.EndOfStreamException">Thrown when an attempt to read beyond the end of the stream is made.</exception>
        public override bool IsReadable(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (!stream.CanRead)
            {
                throw new IOException("The stream is write only.");
            }

            if (!stream.CanSeek)
            {
                throw new IOException("Stream cannot perform seek operations.");
            }

            if (stream.Position + TvHeader.SizeInBytes >= stream.Length)
            {
                throw new EndOfStreamException();
            }

            // Remember the stream position.
            // If we fail to do this then the stream will be offset when we return and could cause corruption.
            long position             = stream.Position;
            GorgonBinaryReader reader = null;

            try
            {
                // Using the GorgonBinaryReader, we can pull in the data we need.
                reader = new GorgonBinaryReader(stream, true);

                // Retrieve our magic number.
                var header = reader.ReadValue <TvHeader>();

                // Ensure that the image size is valid and that the magic numbers match up.
                return(header.Width > 0 && header.Height > 0 && header.MagicValueData == MagicValue);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Dispose();
                }

                // Restore the stream to its original placement.
                stream.Position = position;
            }
        }
Beispiel #5
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);
                    }
                }
            }
Beispiel #6
0
        /// <summary>
        /// Function to copy the contents of a stream into a <see cref="GorgonNativeBuffer{T}"/>.
        /// </summary>
        /// <typeparam name="T">The type of value in the buffer. Must be an unmanaged value type.</typeparam>
        /// <param name="stream">The stream to read from.</param>
        /// <param name="count">[Optional] The maximum number of items to read from the stream.</param>
        /// <returns>A <see cref="GorgonNativeBuffer{T}"/> containing the contents of the stream.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is <b>null</b>.</exception>
        /// <exception cref="EndOfStreamException">Thrown when the <paramref name="stream"/> is at its end.</exception>
        /// <exception cref="IOException">Thrown when the <paramref name="stream"/> is write only.</exception>
        public static GorgonNativeBuffer <T> ToNativeBuffer <T>(this Stream stream, int?count = null)
            where T : unmanaged
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (stream.Position == stream.Length)
            {
                throw new EndOfStreamException();
            }

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

            int typeSize = Unsafe.SizeOf <T>();

            if (count == null)
            {
                if (typeSize == 1)
                {
                    count = (int)(stream.Length - stream.Position);
                }
                else
                {
                    count = (int)((stream.Length - stream.Position) / typeSize);
                }
            }

            var result = new GorgonNativeBuffer <T>(count.Value);

            using (var reader = new GorgonBinaryReader(stream, true))
            {
                for (int i = 0; i < count.Value; ++i)
                {
                    if (stream.Position + typeSize >= stream.Length)
                    {
                        break;
                    }

                    reader.ReadValue(out result[i]);
                }
            }

            return(result);
        }
Beispiel #7
0
        /// <summary>
        /// Function to enumerate the files and directories for a mount point.
        /// </summary>
        /// <param name="physicalMountPoint">Mount point being enumerated.</param>
        /// <param name="mountPoint">Directory to hold the sub directories and files.</param>
        /// <param name="physicalDirectories">A list of directories in the physical file system (formatted to the virtual file system).</param>
        /// <param name="physicalFiles">A list of files in the physical file system (formatted to the virtual file system).</param>
        protected override void Enumerate(string physicalMountPoint, GorgonFileSystemDirectory mountPoint,
                                          out string[] physicalDirectories, out PhysicalFileInfo[] physicalFiles)
        {
            using (var reader = new GorgonBinaryReader(File.Open(physicalMountPoint, FileMode.Open, FileAccess.Read, FileShare.Read), false))
            {
                // Skip the header.
                reader.ReadString();

                int indexLength = reader.ReadInt32();

                byte[] indexData = Decompress(reader.ReadBytes(indexLength));
                string xmlData   = Encoding.UTF8.GetString(indexData);

                ParseIndexXML(physicalMountPoint, mountPoint, XDocument.Parse(xmlData, LoadOptions.None),
                              reader.BaseStream.Position, out physicalDirectories, out physicalFiles);
            }
        }
        /// <summary>
        /// Function to enumerate the files and directories from a physical location and map it to a virtual location.
        /// </summary>
        /// <param name="physicalLocation">The physical location containing files and directories to enumerate.</param>
        /// <param name="mountPoint">A <see cref="IGorgonVirtualDirectory"/> that the directories and files from the physical file system will be mounted into.</param>
        /// <returns>A <see cref="GorgonPhysicalFileSystemData"/> object containing information about the directories and files contained within the physical file system.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="physicalLocation"/>, or the <paramref name="mountPoint"/> parameters are <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="physicalLocation"/> parameter is empty.</exception>
        /// <remarks>
        /// <para>
        /// This will return a <see cref="GorgonPhysicalFileSystemData"/> representing the paths to directories and <see cref="IGorgonPhysicalFileInfo"/> objects under the virtual file system. Each file
        /// system file and directory is mapped from its <paramref name="physicalLocation"/> on the physical file system to a <paramref name="mountPoint"/> on the virtual file system. For example, if the
        /// mount point is set to <c>/MyMount/</c>, and the physical location of a file is <c>c:\SourceFileSystem\MyDirectory\MyTextFile.txt</c>, then the returned value should be
        /// <c>/MyMount/MyDirectory/MyTextFile.txt</c>.
        /// </para>
        /// <para>
        /// Implementors of a <see cref="GorgonFileSystemProvider"/> plug in can override this method to read the list of files from another type of file system, like a Zip file.
        /// </para>
        /// <para>
        /// Implementors of a <see cref="GorgonFileSystemProvider"/> should override this method to read the list of directories and files from another type of file system, like a Zip file.
        /// The default functionality will only enumerate directories and files from the operating system file system.
        /// </para>
        /// </remarks>
        protected override GorgonPhysicalFileSystemData OnEnumerate(string physicalLocation, IGorgonVirtualDirectory mountPoint)
        {
            using (var reader = new GorgonBinaryReader(File.Open(physicalLocation, FileMode.Open, FileAccess.Read, FileShare.Read)))
            {
                // Skip the header.
                reader.ReadString();

                int indexLength = reader.ReadInt32();

                byte[] indexData = Decompress(reader.ReadBytes(indexLength));
                string xmlData   = Encoding.UTF8.GetString(indexData);
                var    index     = XDocument.Parse(xmlData, LoadOptions.None);

                return(new GorgonPhysicalFileSystemData(EnumerateDirectories(index, mountPoint),
                                                        EnumerateFiles(index, reader.BaseStream.Position, physicalLocation, mountPoint)));
            }
        }
        /// <summary>Function to read back the specifics of the font brush data from a file reader.</summary>
        /// <param name="reader">The reader used to read the brush data.</param>
        internal override void ReadBrushData(GorgonBinaryReader reader)
        {
            WrapMode = (GlyphBrushWrapMode)reader.ReadInt32();
            int count = reader.ReadInt32();

            Points.Clear();
            for (int i = 0; i < count; ++i)
            {
                Points.Add(reader.ReadValue <DX.Vector2>());
            }

            BlendFactors.Clear();
            count = reader.ReadInt32();
            for (int i = 0; i < count; ++i)
            {
                BlendFactors.Add(reader.ReadSingle());
            }

            BlendPositions.Clear();
            count = reader.ReadInt32();
            for (int i = 0; i < count; ++i)
            {
                BlendPositions.Add(reader.ReadSingle());
            }

            CenterColor = new GorgonColor(reader.ReadInt32());
            CenterPoint = reader.ReadValue <DX.Vector2>();
            FocusScales = reader.ReadValue <DX.Vector2>();

            count = reader.ReadInt32();
            Interpolation.Clear();

            for (int i = 0; i < count; ++i)
            {
                Interpolation.Add(new GorgonGlyphBrushInterpolator(reader.ReadSingle(), new GorgonColor(reader.ReadInt32())));
            }

            count = reader.ReadInt32();
            SurroundColors.Clear();

            for (int i = 0; i < count; ++i)
            {
                SurroundColors.Add(new GorgonColor(reader.ReadInt32()));
            }
        }
        /// <summary>
        /// Function to determine if a physical file system can be read by this provider.
        /// </summary>
        /// <param name="physicalPath">Path to the packed file containing the file system.</param>
        /// <returns><b>true</b> if the provider can read the packed file, <b>false</b> if not.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="physicalPath"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="physicalPath"/> parameter is an empty string.</exception>
        /// <remarks>
        /// <para>
        /// This will test a physical file system (e.g. a Zip file) to see if the provider can open it or not. If used with a directory on an operating system file system, this method should always return
        /// <b>false</b>.
        /// </para>
        /// <para>
        /// When used with a <see cref="IGorgonFileSystemProvider"/> that supports a non operating system based physical file system, such as the <see cref="GorgonFileSystemRamDiskProvider"/>, then this
        /// method should compare the <paramref name="physicalPath"/> with its <see cref="IGorgonFileSystemProvider.Prefix"/> to ensure that the <see cref="IGorgonFileSystem"/> requesting the provider is using the correct provider.
        /// </para>
        /// <para>
        /// Implementors of a <see cref="GorgonFileSystemProvider"/> should override this method to determine if a packed file can be read by reading the header of the file specified in <paramref name="physicalPath"/>.
        /// </para>
        /// </remarks>
        protected override bool OnCanReadFile(string physicalPath)
        {
            string header;

            using (var reader = new GorgonBinaryReader(File.Open(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read)))
            {
                // If the length of the stream is less or equal to the header size, it's unlikely that we can read this file.
                if (reader.BaseStream.Length <= GorPackHeader.Length)
                {
                    return(false);
                }

                reader.ReadByte();
                header = new string(reader.ReadChars(GorPackHeader.Length));
            }

            return(string.Equals(header, GorPackHeader));
        }
Beispiel #11
0
        /// <summary>
        /// Function to read the kerning pairs for the font, if they exist.
        /// </summary>
        /// <param name="fontFile">Font file to read.</param>
        private static Dictionary <GorgonKerningPair, int> ReadKernPairs(GorgonChunkFileReader fontFile)
        {
            var result = new Dictionary <GorgonKerningPair, int>();
            GorgonBinaryReader reader = fontFile.OpenChunk(KernDataChunk);

            // Read optional kerning information.
            int kernCount = reader.ReadInt32();

            for (int i = 0; i < kernCount; ++i)
            {
                var kernPair = new GorgonKerningPair(reader.ReadChar(), reader.ReadChar());
                result[kernPair] = reader.ReadInt32();
            }

            fontFile.CloseChunk();

            return(result);
        }
        /// <summary>Function to read back the specifics of the font brush data from a file reader.</summary>
        /// <param name="reader">The reader used to read the brush data.</param>
        internal override void ReadBrushData(GorgonBinaryReader reader)
        {
            Angle           = reader.ReadSingle();
            ScaleAngle      = reader.ReadBoolean();
            GammaCorrection = reader.ReadBoolean();

            int interpCount = reader.ReadInt32();

            if (interpCount == 0)
            {
                return;
            }

            Interpolation.Clear();

            for (int i = 0; i < interpCount; ++i)
            {
                Interpolation.Add(new GorgonGlyphBrushInterpolator(reader.ReadSingle(), new GorgonColor(reader.ReadInt32())));
            }
        }
Beispiel #13
0
        /// <summary>
        /// Function to read the meta data for the image.
        /// </summary>
        /// <param name="stream">Stream containing the image data.</param>
        /// <returns>An image settings object containing information about the image.</returns>
        private static IImageSettings ReadMetaData(Stream stream)
        {
            if (!stream.CanRead)
            {
                throw new ArgumentException(@"Stream is write only.", "stream");
            }

            if (stream.Position + TvHeader.SizeInBytes >= stream.Length)
            {
                throw new EndOfStreamException();
            }

            // We only support 2D images with the tv format.
            var      settings = new GorgonTexture2DSettings();
            TvHeader header;

            // Load the header for the image.
            using (var reader = new GorgonBinaryReader(stream, true))
            {
                header = reader.ReadValue <TvHeader>();
            }

            // Ensure we've got the correct data.
            if (header.MagicValueData != MagicValue)
            {
                throw new ArgumentException(@"The image data is not a tv image.", "stream");
            }

            // Ensure the width/height are valid.
            if ((header.Width < 0) ||
                (header.Height < 0))
            {
                throw new ArgumentException(@"The image in this stream has an invalid width/height.", "stream");
            }

            settings.Width  = header.Width;
            settings.Height = header.Height;
            settings.Format = BufferFormat.R8G8B8A8_UIntNormal;

            return(settings);
        }
Beispiel #14
0
        /// <summary>
        /// Function to read the meta data for image data within a stream.
        /// </summary>
        /// <param name="stream">The stream containing the metadata to read.</param>
        /// <returns>
        /// The image meta data as a <see cref="IGorgonImageInfo"/> value.
        /// </returns>
        /// <exception cref="IOException">Thrown when the <paramref name="stream"/> is write-only or if the stream cannot perform seek operations.
        /// <para>-or-</para>
        /// <para>Thrown if the file is corrupt or can't be read by the codec.</para>
        /// </exception>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is <b>null</b>.</exception>
        /// <exception cref="IOException">Thrown when the <paramref name="stream"/> is write-only or if the stream cannot perform seek operations.</exception>
        /// <exception cref="EndOfStreamException">Thrown when an attempt to read beyond the end of the stream is made.</exception>
        /// <remarks>
        /// <para>
        /// Ensure that the file can be read by calling the <see cref="IsReadable"/> method prior to calling this method.
        /// </para>
        /// </remarks>
        /// <seealso cref="IsReadable"/>
        public override IGorgonImageInfo GetMetaData(Stream stream)
        {
            int  headerSize = Unsafe.SizeOf <TgaHeader>();
            long position   = 0;


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

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

            if (!stream.CanSeek)
            {
                throw new IOException(Resources.GORIMG_ERR_STREAM_CANNOT_SEEK);
            }

            if (stream.Length - stream.Position < sizeof(uint) + headerSize)
            {
                throw new EndOfStreamException();
            }

            GorgonBinaryReader reader = null;

            try
            {
                position = stream.Position;
                reader   = new GorgonBinaryReader(stream, true);
                return(ReadHeader(reader, out _));
            }
            finally
            {
                stream.Position = position;
                reader?.Dispose();
            }
        }
Beispiel #15
0
        /// <summary>
        /// Function to determine if a file can be read by this provider.
        /// </summary>
        /// <param name="physicalPath">Path to the file containing the file system.</param>
        /// <returns>
        /// TRUE if the provider can read the packed file, FALSE if not.
        /// </returns>
        /// <remarks>This method is applicable to packed files only.
        /// <para>Implementors must use this method to determine if a packed file can be read by reading the header of the file.</para>
        /// </remarks>
        /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="physicalPath"/> parameter is NULL (Nothing in VB.Net).</exception>
        /// <exception cref="System.ArgumentException">Thrown when the <paramref name="physicalPath"/> parameter is an empty string.</exception>
        public override bool CanReadFile(string physicalPath)
        {
            string header;

            if (physicalPath == null)
            {
                throw new ArgumentNullException("physicalPath");
            }

            if (string.IsNullOrWhiteSpace(physicalPath))
            {
                throw new ArgumentException(Resources.GORFS_PARAMETER_MUST_NOT_BE_EMPTY, "physicalPath");
            }

            using (var reader = new GorgonBinaryReader(File.Open(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read), false))
            {
                reader.ReadByte();
                header = new string(reader.ReadChars(GorgonGorPackPlugIn.GorPackHeader.Length));
            }

            return(string.Equals(header, GorgonGorPackPlugIn.GorPackHeader));
        }
Beispiel #16
0
        /// <summary>
        /// Function to determine if this codec can read the font data within the stream or not.
        /// </summary>
        /// <param name="stream">The stream that is used to read the font data.</param>
        /// <returns><b>true</b> if the codec can read the file, <b>false</b> if not.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is <b>null</b>.</exception>
        /// <exception cref="IOException">Thrown when the <paramref name="stream"/> is write-only or if the stream cannot perform seek operations.</exception>
        /// <exception cref="EndOfStreamException">Thrown when an attempt to read beyond the end of the stream is made.</exception>
        /// <remarks>
        /// <para>
        /// Implementors should ensure that the stream position is restored prior to exiting this method. Failure to do so may cause problems when reading the data from the stream.
        /// </para>
        /// </remarks>
        public override bool IsReadable(Stream stream)
        {
            ulong fileHeaderID = FileHeader.ChunkID();

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

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

            if (!stream.CanSeek)
            {
                throw new IOException(Resources.GORGFX_ERR_STREAM_NO_SEEK);
            }

            if (stream.Length - stream.Position < FileHeader.Length)
            {
                return(false);
            }

            long position = stream.Position;
            var  reader   = new GorgonBinaryReader(stream, true);

            try
            {
                ulong fileData = reader.ReadUInt64();
                return(fileData == fileHeaderID);
            }
            finally
            {
                reader.Dispose();
                stream.Position = position;
            }
        }
Beispiel #17
0
        /// <summary>
        /// Function to write the contents pointed at by an unsafe pointer to a stream using the GorgonBinaryWriter and reading it back again using the GorgonBinaryReader.
        /// </summary>
        /// <param name="stream">The stream that will receive the data.</param>
        private static unsafe void WritePointer(MemoryStream stream)
        {
            stream.Position = 0;
            var writer = new GorgonBinaryWriter(stream, true);
            var reader = new GorgonBinaryReader(stream, true);

            try
            {
                var data = new SomeTestData
                {
                    Value1 = 1,
                    Value2 = 2.1,
                    Value3 = 3
                };

                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Writing/Reading pointer to memory into a memory stream.");
                Console.ForegroundColor = ConsoleColor.White;

                writer.Write(&data, Unsafe.SizeOf <SomeTestData>());

                stream.Position = 0;

                SomeTestData readData = default;
                reader.Read(&readData, Unsafe.SizeOf <SomeTestData>());

                Console.WriteLine($"int32 Value1 = 1: {readData.Value1 == 1}");
                Console.WriteLine($"double Value2 = 2.1: {readData.Value2.EqualsEpsilon(2.1)}");
                Console.WriteLine($"int16 Value3 = 3: {readData.Value3 == 3}");

                stream.Position = 0;
            }
            finally
            {
                writer.Dispose();
                reader.Dispose();
            }
        }
Beispiel #18
0
        /// <summary>
        /// Function to read the chunk containing the font information.
        /// </summary>
        /// <param name="fontFile">The chunk file reader containing the font data.</param>
        /// <param name="name">Used defined name for the font.</param>
        /// <returns>A new <seealso cref="IGorgonFontInfo"/> containing information about the font.</returns>
        private static GorgonFontInfo GetFontInfo(GorgonChunkFileReader fontFile, string name)
        {
            GorgonBinaryReader reader = fontFile.OpenChunk(FontInfoChunk);
            var info = new GorgonFontInfo(reader.ReadString(), reader.ReadSingle(), reader.ReadValue <FontHeightMode>(), name)
            {
                FontStyle                = reader.ReadValue <FontStyle>(),
                DefaultCharacter         = reader.ReadChar(),
                Characters               = reader.ReadString(),
                AntiAliasingMode         = reader.ReadValue <FontAntiAliasMode>(),
                OutlineColor1            = new GorgonColor(reader.ReadInt32()),
                OutlineColor2            = new GorgonColor(reader.ReadInt32()),
                OutlineSize              = reader.ReadInt32(),
                PackingSpacing           = reader.ReadInt32(),
                TextureWidth             = reader.ReadInt32(),
                TextureHeight            = reader.ReadInt32(),
                UsePremultipliedTextures = reader.ReadValue <bool>(),
                UseKerningPairs          = reader.ReadBoolean()
            };

            fontFile.CloseChunk();

            return(info);
        }
Beispiel #19
0
        /// <summary>
        /// Function to write the contents of a value type to a stream using the GorgonBinaryWriter and reading it back again using the GorgonBinaryReader.
        /// </summary>
        /// <param name="stream">The stream that will receive the data.</param>
        private static void WriteByRefValueType(MemoryStream stream)
        {
            stream.Position = 0;
            var writer = new GorgonBinaryWriter(stream, true);
            var reader = new GorgonBinaryReader(stream, true);

            try
            {
                var data = new SomeTestData
                {
                    Value1 = 1234,
                    Value2 = 3.1459,
                    Value3 = 42
                };

                Console.ForegroundColor = ConsoleColor.Cyan;
                Console.WriteLine("Writing/Reading a value type to a memory stream.");
                Console.ForegroundColor = ConsoleColor.White;

                writer.WriteValue(ref data);

                stream.Position = 0;

                reader.ReadValue(out SomeTestData readData);

                Console.WriteLine($"int32 Value1 = 1234: {readData.Value1 == 1234}");
                Console.WriteLine($"double Value2 = 3.1459: {readData.Value2.EqualsEpsilon(3.1459)}");
                Console.WriteLine($"int16 Value3 = 42: {readData.Value3 == 42}");

                stream.Position = 0;
            }
            finally
            {
                writer.Dispose();
                reader.Dispose();
            }
        }
Beispiel #20
0
        /// <summary>
        /// Function to read in the TGA header from a stream.
        /// </summary>
        /// <param name="reader">The reader used to read the stream containing the data.</param>
        /// <param name="conversionFlags">Flags for conversion.</param>
        /// <returns>New image settings.</returns>
        private static IGorgonImageInfo ReadHeader(GorgonBinaryReader reader, out TGAConversionFlags conversionFlags)
        {
            conversionFlags = TGAConversionFlags.None;

            // Get the header for the file.
            TgaHeader header = reader.ReadValue <TgaHeader>();

            if ((header.ColorMapType != 0) || (header.ColorMapLength != 0) ||
                (header.Width <= 0) || (header.Height <= 0) ||
                ((header.Descriptor & TgaDescriptor.Interleaved2Way) == TgaDescriptor.Interleaved2Way) ||
                ((header.Descriptor & TgaDescriptor.Interleaved4Way) == TgaDescriptor.Interleaved4Way))
            {
                throw new NotSupportedException(Resources.GORIMG_ERR_TGA_TYPE_NOT_SUPPORTED);
            }

            BufferFormat pixelFormat = BufferFormat.Unknown;

            switch (header.ImageType)
            {
            case TgaImageType.TrueColor:
            case TgaImageType.TrueColorRLE:
                switch (header.BPP)
                {
                case 16:
                    pixelFormat = BufferFormat.B5G5R5A1_UNorm;
                    break;

                case 24:
                case 32:
                    pixelFormat = BufferFormat.R8G8B8A8_UNorm;
                    if (header.BPP == 24)
                    {
                        conversionFlags |= TGAConversionFlags.Expand;
                    }
                    break;
                }

                if (header.ImageType == TgaImageType.TrueColorRLE)
                {
                    conversionFlags |= TGAConversionFlags.RLE;
                }
                break;

            case TgaImageType.BlackAndWhite:
            case TgaImageType.BlackAndWhiteRLE:
                if (header.BPP == 8)
                {
                    pixelFormat = BufferFormat.R8_UNorm;
                }
                else
                {
                    throw new IOException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, header.ImageType));
                }

                if (header.ImageType == TgaImageType.BlackAndWhiteRLE)
                {
                    conversionFlags |= TGAConversionFlags.RLE;
                }
                break;

            default:
                throw new IOException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, header.ImageType));
            }

            var settings = new GorgonImageInfo(ImageType.Image2D, pixelFormat)
            {
                MipCount   = 1,
                ArrayCount = 1,
                Width      = header.Width,
                Height     = header.Height
            };

            if ((header.Descriptor & TgaDescriptor.InvertX) == TgaDescriptor.InvertX)
            {
                conversionFlags |= TGAConversionFlags.InvertX;
            }

            if ((header.Descriptor & TgaDescriptor.InvertY) == TgaDescriptor.InvertY)
            {
                conversionFlags |= TGAConversionFlags.InvertY;
            }

            if (header.IDLength <= 0)
            {
                return(settings);
            }

            // Skip these bytes.
            for (int i = 0; i < header.IDLength; i++)
            {
                reader.ReadByte();
            }

            return(settings);
        }
Beispiel #21
0
        /// <summary>
        /// Function to decode an uncompressed run of pixel data.
        /// </summary>
        /// <param name="reader">The reader used to read the data in the stream.</param>
        /// <param name="dest">The destination buffer pointer.</param>
        /// <param name="x">The current horizontal position in the scanline.</param>
        /// <param name="runLength">The size of the run, in pixels.</param>
        /// <param name="width">The total width of the run.</param>
        /// <param name="expand"><b>true</b> to expand a 24bpp scanline to 32bpp, or <b>false</b> if no expansion is needed.</param>
        /// <param name="flipHorizontal"><b>true</b> to decode the pixels from right to left, or <b>false</b> to decode from left to right.</param>
        /// <param name="format">The pixel format.</param>
        /// <returns><b>true</b> if the run contains entirely transparent pixels, or <b>false</b> if not.</returns>
        private unsafe bool DecodeRleEncodedRun(GorgonBinaryReader reader, ref byte *dest, ref int x, int runLength, int width, bool expand, bool flipHorizontal, BufferFormat format)
        {
            bool result = true;

            switch (format)
            {
            case BufferFormat.R8_UNorm:
                for (; runLength > 0; --runLength, ++x)
                {
                    if (x >= width)
                    {
                        throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
                    }

                    if (!flipHorizontal)
                    {
                        *(dest++) = reader.ReadByte();
                    }
                    else
                    {
                        *(dest--) = reader.ReadByte();
                    }
                }
                break;

            case BufferFormat.B5G5R5A1_UNorm:
            {
                ushort *destPtr = (ushort *)dest;
                ushort  pixel   = reader.ReadUInt16();

                if ((pixel & 0x8000) != 0)
                {
                    result = false;
                }

                for (; runLength > 0; runLength--, ++x)
                {
                    if (x >= width)
                    {
                        throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
                    }

                    if (!flipHorizontal)
                    {
                        *(destPtr++) = pixel;
                    }
                    else
                    {
                        *(destPtr--) = pixel;
                    }
                }

                dest = (byte *)destPtr;
            }
                return(result);

            case BufferFormat.R8G8B8A8_UNorm:
            {
                uint pixel;

                // Do expansion.
                if (expand)
                {
                    pixel  = (uint)((reader.ReadByte() << 16) | (reader.ReadByte() << 8) | reader.ReadByte() | 0xFF000000);
                    result = false;
                }
                else
                {
                    pixel = reader.ReadUInt32();

                    if ((pixel & 0xFF000000) != 0)
                    {
                        result = false;
                    }
                }

                uint *destPtr = (uint *)dest;

                for (; runLength > 0; --runLength, ++x)
                {
                    if (x >= width)
                    {
                        throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
                    }

                    if (!flipHorizontal)
                    {
                        *(destPtr++) = pixel;
                    }
                    else
                    {
                        *(destPtr--) = pixel;
                    }
                }

                dest = (byte *)destPtr;
            }
                return(result);
            }

            return(false);
        }
Beispiel #22
0
        /// <summary>
        /// Function to read the renderable data from a stream.
        /// </summary>
        /// <param name="stream">Open file stream containing the renderable data.</param>
        /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream" /> parameter is NULL (Nothing in VB.Net).</exception>
        /// <exception cref="System.IO.IOException">Thrown when the stream parameter is not opened for reading data.</exception>
        /// <exception cref="GorgonLibrary.GorgonException">Thrown when the data in the stream does not contain valid renderable data, or contains a newer version of the renderable than Gorgon can handle.</exception>
        void IPersistedRenderable.Load(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

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

            GorgonChunkReader chunk = null;

            // Read the sprite in.
            try
            {
                chunk = new GorgonChunkReader(stream);

                if (!chunk.HasChunk(FileHeader))
                {
                    // The old format doesn't use the chunker.
                    chunk.Dispose();
                    chunk = null;

                    // Check to see if it's an older version of the Gorgon sprite data.
                    using (var oldReader = new GorgonBinaryReader(stream, true))
                    {
                        GorgonV1SpriteReader.LoadSprite(this, oldReader);

                        return;
                    }
                }

                // Read in the file header.
                chunk.Begin(FileHeader);

                chunk.Begin("SPRTDATA");
                Anchor         = chunk.Read <Vector2>();
                Size           = chunk.Read <Vector2>();
                HorizontalFlip = chunk.ReadBoolean();
                VerticalFlip   = chunk.ReadBoolean();

                // Read vertex colors.
                for (int i = 0; i < Vertices.Length; i++)
                {
                    Vertices[i].Color = chunk.Read <GorgonColor>();
                }

                // Write vertex offsets.
                chunk.ReadRange(_offsets);
                chunk.End();

                // Read rendering information.
                chunk.Begin("RNDRDATA");
                CullingMode                               = chunk.Read <CullingMode>();
                AlphaTestValues                           = chunk.Read <GorgonRangeF>();
                Blending.AlphaOperation                   = chunk.Read <BlendOperation>();
                Blending.BlendOperation                   = chunk.Read <BlendOperation>();
                Blending.BlendFactor                      = chunk.Read <GorgonColor>();
                Blending.DestinationAlphaBlend            = chunk.Read <BlendType>();
                Blending.DestinationBlend                 = chunk.Read <BlendType>();
                Blending.SourceAlphaBlend                 = chunk.Read <BlendType>();
                Blending.SourceBlend                      = chunk.Read <BlendType>();
                Blending.WriteMask                        = chunk.Read <ColorWriteMaskFlags>();
                DepthStencil.BackFace.ComparisonOperator  = chunk.Read <ComparisonOperator>();
                DepthStencil.BackFace.DepthFailOperation  = chunk.Read <StencilOperation>();
                DepthStencil.BackFace.FailOperation       = chunk.Read <StencilOperation>();
                DepthStencil.BackFace.PassOperation       = chunk.Read <StencilOperation>();
                DepthStencil.FrontFace.ComparisonOperator = chunk.Read <ComparisonOperator>();
                DepthStencil.FrontFace.DepthFailOperation = chunk.Read <StencilOperation>();
                DepthStencil.FrontFace.FailOperation      = chunk.Read <StencilOperation>();
                DepthStencil.FrontFace.PassOperation      = chunk.Read <StencilOperation>();
                DepthStencil.DepthBias                    = chunk.ReadInt32();
                DepthStencil.DepthComparison              = chunk.Read <ComparisonOperator>();
                DepthStencil.StencilReference             = chunk.ReadInt32();
                DepthStencil.IsDepthWriteEnabled          = chunk.ReadBoolean();
                DepthStencil.StencilReadMask              = chunk.ReadByte();
                DepthStencil.StencilReadMask              = chunk.ReadByte();
                chunk.End();

                // Read collider information.
                if (chunk.HasChunk("COLLIDER"))
                {
                    chunk.Begin("COLLIDER");
                    Type colliderType = Type.GetType(chunk.ReadString());
                    Debug.Assert(colliderType != null, "Collider is NULL!!");
                    var collider = (Gorgon2DCollider)Activator.CreateInstance(colliderType);
                    collider.ReadFromChunk(chunk);
                    chunk.End();
                }

                // Read texture information.
                chunk.Begin("TXTRDATA");
                TextureSampler.BorderColor        = chunk.Read <GorgonColor>();
                TextureSampler.HorizontalWrapping = chunk.Read <TextureAddressing>();
                TextureSampler.VerticalWrapping   = chunk.Read <TextureAddressing>();
                TextureSampler.TextureFilter      = chunk.Read <TextureFilter>();
                DeferredTextureName = chunk.ReadString();
                TextureRegion       = chunk.ReadRectangleF();
            }
            finally
            {
                if (chunk != null)
                {
                    chunk.Dispose();
                }
            }
        }
 /// <summary>Function to read back the specifics of the font brush data from a file reader.</summary>
 /// <param name="reader">The reader used to read the brush data.</param>
 internal override void ReadBrushData(GorgonBinaryReader reader)
 {
     HatchStyle      = (GlyphBrushHatchStyle)reader.ReadInt32();
     ForegroundColor = new GorgonColor(reader.ReadInt32());
     BackgroundColor = new GorgonColor(reader.ReadInt32());
 }
 /// <summary>Function to read back the specifics of the font brush data from a file reader.</summary>
 /// <param name="reader">The reader used to read the brush data.</param>
 internal override void ReadBrushData(GorgonBinaryReader reader) => Color = new GorgonColor(reader.ReadInt32());
Beispiel #25
0
        /// <summary>
        /// Function to decode an uncompressed run of pixel data.
        /// </summary>
        /// <param name="reader">The reader used to read the data from the stream.</param>
        /// <param name="dest">The destination buffer pointer.</param>
        /// <param name="x">The current horizontal position in the scanline.</param>
        /// <param name="runLength">The size of the run, in pixels.</param>
        /// <param name="width">The total width of the run.</param>
        /// <param name="expand"><b>true</b> to expand a 24bpp scanline to 32bpp, or <b>false</b> if no expansion is needed.</param>
        /// <param name="flipHorizontal"><b>true</b> to decode the pixels from right to left, or <b>false</b> to decode from left to right.</param>
        /// <param name="format">The pixel format.</param>
        /// <returns><b>true</b> if the run contains entirely transparent pixels, or <b>false</b> if not.</returns>
        private unsafe bool DecodeUncompressedRun(GorgonBinaryReader reader, ref byte *dest, ref int x, int runLength, int width, bool expand, bool flipHorizontal, BufferFormat format)
        {
            bool result = true;

            switch (format)
            {
            case BufferFormat.R8_UNorm:
                for (; runLength > 0; --runLength, ++x)
                {
                    if (x >= width)
                    {
                        throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
                    }

                    if (!flipHorizontal)
                    {
                        *(dest++) = reader.ReadByte();
                    }
                    else
                    {
                        *(dest--) = reader.ReadByte();
                    }
                }
                break;

            case BufferFormat.B5G5R5A1_UNorm:
            {
                ushort *destPtr = (ushort *)dest;

                for (; runLength > 0; runLength--, ++x)
                {
                    if (x >= width)
                    {
                        throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
                    }

                    ushort pixel = reader.ReadUInt16();

                    if ((pixel & 0x8000) != 0)
                    {
                        result = false;
                    }

                    if (!flipHorizontal)
                    {
                        *(destPtr++) = pixel;
                    }
                    else
                    {
                        *(destPtr--) = pixel;
                    }
                }

                // Send the updated destination address back to the calling function.
                // This is kind of ugly, but too lazy to make it nice.
                dest = (byte *)destPtr;
            }
                return(result);

            case BufferFormat.R8G8B8A8_UNorm:
            {
                uint *destPtr = (uint *)dest;

                for (; runLength > 0; --runLength, ++x)
                {
                    if (x >= width)
                    {
                        throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
                    }

                    uint pixel;

                    if (expand)
                    {
                        pixel  = (uint)((reader.ReadByte() << 16) | (reader.ReadByte() << 8) | reader.ReadByte() | 0xFF000000);
                        result = false;
                    }
                    else
                    {
                        pixel = reader.ReadUInt32();

                        if ((pixel & 0xFF000000) != 0)
                        {
                            result = false;
                        }
                    }

                    if (!flipHorizontal)
                    {
                        *(destPtr++) = pixel;
                    }
                    else
                    {
                        *(destPtr--) = pixel;
                    }
                }

                // Send the updated destination address back to the calling function.
                // This is kind of ugly, but too lazy to make it nice.
                dest = (byte *)destPtr;
            }
                return(result);
            }

            return(false);
        }
Beispiel #26
0
        /// <summary>
        /// Function to determine if this codec can read the image data within the stream or not.
        /// </summary>
        /// <param name="stream">The stream that is used to read the image data.</param>
        /// <returns><b>true</b> if the codec can read the file, <b>false</b> if not.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is <b>null</b>.</exception>
        /// <exception cref="IOException">Thrown when the <paramref name="stream"/> is write-only or if the stream cannot perform seek operations.</exception>
        public override bool IsReadable(Stream stream)
        {
            TgaHeader header;
            long      position = 0;

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

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

            if (!stream.CanSeek)
            {
                throw new IOException(Resources.GORIMG_ERR_STREAM_CANNOT_SEEK);
            }

            if (stream.Length - stream.Position < Unsafe.SizeOf <TgaHeader>())
            {
                return(false);
            }

            try
            {
                position = stream.Position;
                var reader = new GorgonBinaryReader(stream, true);
                header = reader.ReadValue <TgaHeader>();
            }
            finally
            {
                stream.Position = position;
            }

            if ((header.ColorMapType != 0) || (header.ColorMapLength != 0))
            {
                return(false);
            }

            if ((header.Descriptor & (TgaDescriptor.Interleaved2Way | TgaDescriptor.Interleaved4Way)) != 0)
            {
                return(false);
            }

            if ((header.Width <= 0) || (header.Height <= 0))
            {
                return(false);
            }

#pragma warning disable IDE0046 // Convert to conditional expression
            if ((header.ImageType != TgaImageType.TrueColor) && (header.ImageType != TgaImageType.TrueColorRLE) &&
                (header.ImageType != TgaImageType.BlackAndWhite) && (header.ImageType != TgaImageType.BlackAndWhiteRLE))
            {
                return(false);
            }
#pragma warning restore IDE0046 // Convert to conditional expression

            return(((header.ImageType != TgaImageType.BlackAndWhite) && (header.ImageType != TgaImageType.BlackAndWhiteRLE)) ||
                   (header.BPP == 8));
        }
Beispiel #27
0
        /// <summary>
        /// Function to load a version 1.x Gorgon sprite.
        /// </summary>
        /// <param name="sprite">Sprite to fill in with data.</param>
        /// <param name="reader">Binary reader to use to read in the data.</param>
        public static void LoadSprite(GorgonSprite sprite, GorgonBinaryReader reader)
        {
            Version version;
            string  imageName = string.Empty;

            sprite.IsV1Sprite = true;

            reader.BaseStream.Position = 0;

            string headerVersion = reader.ReadString();

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

            // 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, Resources.GOR2D_SPRITE_CANNOT_READ_V1_SPRITE);
            }

            // 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 Vector2(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 Vector2(reader.ReadSingle(), reader.ReadSingle());

            sprite.TextureOffset = textureOffset;
            sprite.TextureSize   = sprite.Size;

            // Read the anchor.
            sprite.Anchor = new Vector2(reader.ReadSingle(), reader.ReadSingle());

            // Get vertex offsets.
            sprite.SetCornerOffset(RectangleCorner.UpperLeft, new Vector2(reader.ReadSingle(), reader.ReadSingle()));
            sprite.SetCornerOffset(RectangleCorner.UpperRight, new Vector2(reader.ReadSingle(), reader.ReadSingle()));
            sprite.SetCornerOffset(RectangleCorner.LowerRight, new Vector2(reader.ReadSingle(), reader.ReadSingle()));
            sprite.SetCornerOffset(RectangleCorner.LowerLeft, new Vector2(reader.ReadSingle(), reader.ReadSingle()));

            // Get vertex colors.
            sprite.SetCornerColor(RectangleCorner.UpperLeft, new GorgonColor(reader.ReadInt32()));
            sprite.SetCornerColor(RectangleCorner.UpperRight, new GorgonColor(reader.ReadInt32()));
            sprite.SetCornerColor(RectangleCorner.LowerLeft, new GorgonColor(reader.ReadInt32()));
            sprite.SetCornerColor(RectangleCorner.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.AlphaTestValues = new GorgonRangeF(0.0f, reader.ReadInt32() / 255.0f);
            }

            // Set the blending mode.
            if (!InheritBlending)
            {
                sprite.Blending.SourceBlend      = ConvertBlendOpToBlendType(reader.ReadInt32());
                sprite.Blending.DestinationBlend = ConvertBlendOpToBlendType(reader.ReadInt32());
                // Skip the blending mode, this gets detected automatically now.
                reader.ReadInt32();
            }

            // Get alpha blending mode.
            if ((version.Major == 1) && (version.Minor >= 2))
            {
                sprite.Blending.DestinationAlphaBlend = ConvertBlendOpToBlendType(reader.ReadInt32());
                sprite.Blending.SourceAlphaBlend      = ConvertBlendOpToBlendType(reader.ReadInt32());
            }

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

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

            // Get stencil stuff.
            if (!InheritStencilCompare)
            {
                sprite.DepthStencil.FrontFace.ComparisonOperator = ConvertCompare(reader.ReadInt32());
            }
            if (!InheritStencilEnabled)
            {
                // We don't enable stencil in the same way anymore, so skip this value.
                reader.ReadBoolean();
            }
            if (!InheritStencilFailOperation)
            {
                sprite.DepthStencil.FrontFace.FailOperation = ConvertStencilOp(reader.ReadInt32());
            }
            if (!InheritStencilMask)
            {
                sprite.DepthStencil.StencilReadMask = (byte)(reader.ReadInt32() & 0xFF);
            }
            if (!InheritStencilPassOperation)
            {
                sprite.DepthStencil.FrontFace.PassOperation = ConvertStencilOp(reader.ReadInt32());
            }
            if (!InheritStencilReference)
            {
                sprite.DepthStencil.StencilReference = reader.ReadInt32();
            }
            if (!InheritStencilZFailOperation)
            {
                sprite.DepthStencil.FrontFace.DepthFailOperation = ConvertStencilOp(reader.ReadInt32());
            }

            // Get vertical wrapping mode.
            if (!InheritVerticalWrapping)
            {
                sprite.TextureSampler.VerticalWrapping = 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)
                {
                    sprite.DepthStencil.DepthComparison = ConvertCompare(reader.ReadInt32());
                }
                if (!InheritDepthWriteEnabled)
                {
                    sprite.DepthStencil.IsDepthWriteEnabled = reader.ReadBoolean();
                }

                sprite.TextureSampler.BorderColor = new GorgonColor(reader.ReadInt32());
            }

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

            // Bind the texture (if we have one bound to this sprite) if it's already loaded, otherwise defer it.
            if (string.IsNullOrEmpty(imageName))
            {
                return;
            }

            sprite.DeferredTextureName = imageName;
        }
Beispiel #28
0
        /// <summary>
        /// Function to load the font data, with the specified size, from a stream.
        /// </summary>
        /// <param name="name">The name to assign to the font.</param>
        /// <param name="stream">The stream containing the font data.</param>
        /// <returns>A new <seealso cref="GorgonFont"/>, or, an existing font from the <seealso cref="GorgonFontFactory"/> cache.</returns>
        protected override GorgonFont OnLoadFromStream(string name, Stream stream)
        {
            var fontFile = new GorgonChunkFileReader(stream,
                                                     new[]
            {
                FileHeader.ChunkID()
            });
            GorgonFontInfo fontInfo = null;


            try
            {
                fontFile.Open();

                fontInfo = GetFontInfo(fontFile, name);

                // If the font is already loaded, then just reuse it.
                if (Factory.HasFont(fontInfo))
                {
                    return(Factory.GetFont(fontInfo));
                }

                GorgonBinaryReader reader = fontFile.OpenChunk(FontHeightChunk);

                // Read in information about the font height.
                float fontHeight = reader.ReadSingle();
                float lineHeight = reader.ReadSingle();
                float ascent     = reader.ReadSingle();
                float descent    = reader.ReadSingle();
                fontFile.CloseChunk();

                if (fontFile.Chunks.Contains(BrushChunk))
                {
                    reader = fontFile.OpenChunk(BrushChunk);
                    var brushType = (GlyphBrushType)reader.ReadInt32();

                    switch (brushType)
                    {
                    case GlyphBrushType.Hatched:
                        fontInfo.Brush = new GorgonGlyphHatchBrush();
                        break;

                    case GlyphBrushType.LinearGradient:
                        fontInfo.Brush = new GorgonGlyphLinearGradientBrush();
                        break;

                    case GlyphBrushType.PathGradient:
                        fontInfo.Brush = new GorgonGlyphPathGradientBrush();
                        break;

                    case GlyphBrushType.Texture:
                        fontInfo.Brush = new GorgonGlyphTextureBrush();
                        break;

                    default:
                        fontInfo.Brush = new GorgonGlyphSolidBrush();
                        break;
                    }

                    fontInfo.Brush.ReadBrushData(reader);
                    fontFile.CloseChunk();
                }
                else
                {
                    fontInfo.Brush = new GorgonGlyphSolidBrush();
                }

                // If this font has kerning data, then load that in.
                IReadOnlyDictionary <GorgonKerningPair, int> kerningPairs = null;

                if (fontFile.Chunks.Contains(KernDataChunk))
                {
                    kerningPairs = ReadKernPairs(fontFile);
                }

                return(Factory.GetFont(fontInfo));
            }
            finally
            {
                var brush = fontInfo?.Brush as IDisposable;
                brush?.Dispose();
                fontFile.Close();
            }
        }
Beispiel #29
0
 /// <summary>
 /// Function to read back the specifics of the font brush data from a file reader.
 /// </summary>
 /// <param name="reader">The reader used to read the brush data.</param>
 internal abstract void ReadBrushData(GorgonBinaryReader reader);
Beispiel #30
0
        /// <summary>
        /// Function to perform the copying of image data into the buffer.
        /// </summary>
        /// <param name="reader">A reader used to read the data from the source stream.</param>
        /// <param name="image">Image data.</param>
        /// <param name="conversionFlags">Flags used to convert the image.</param>
        private void CopyImageData(GorgonBinaryReader reader, IGorgonImage image, TGAConversionFlags conversionFlags)
        {
            // TGA only supports 1 array level, and 1 mip level, so we only need to get the first buffer.
            IGorgonImageBuffer buffer = image.Buffers[0];

            // Determine how large a row is, in bytes.
            var formatInfo = new GorgonFormatInfo(image.Format);

            GorgonPitchLayout srcPitch = (conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand
                                             ? new GorgonPitchLayout(image.Width * 3, image.Width * 3 * image.Height)
                                             : formatInfo.GetPitchForFormat(image.Width, image.Height);

            unsafe
            {
                // Otherwise, allocate a buffer for conversion.
                byte *destPtr = (byte *)buffer.Data;

                // 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.Height - 1) * buffer.PitchInformation.RowPitch;
                }

                // Used to counter the number of lines to force as opaque.
                int opaqueLineCount = 0;
                // The buffer used to hold an uncompressed scanline.
                GorgonNativeBuffer <byte> lineBuffer = null;

                try
                {
                    for (int y = 0; y < image.Height; y++)
                    {
                        // Indicates that the scanline has an alpha of 0 for the entire run.
                        bool lineHasZeroAlpha;

                        if ((conversionFlags & TGAConversionFlags.RLE) == TGAConversionFlags.RLE)
                        {
                            lineHasZeroAlpha = ReadCompressed(reader, image.Width, destPtr, image.Format, conversionFlags);
                        }
                        else
                        {
                            // Read the current scanline into memory.
                            if (lineBuffer == null)
                            {
                                lineBuffer = new GorgonNativeBuffer <byte>(srcPitch.RowPitch);
                            }

                            reader.ReadRange(lineBuffer, count: srcPitch.RowPitch);

                            lineHasZeroAlpha = ReadUncompressed((byte *)lineBuffer, srcPitch.RowPitch, destPtr, image.Format, conversionFlags);
                        }

                        if ((lineHasZeroAlpha) && ((conversionFlags & TGAConversionFlags.SetOpaqueAlpha) == TGAConversionFlags.SetOpaqueAlpha))
                        {
                            opaqueLineCount++;
                        }

                        // The components of the pixel data in a TGA file need swizzling for 32 bit.
                        if (formatInfo.BitDepth == 32)
                        {
                            ImageUtilities.SwizzleScanline(destPtr,
                                                           buffer.PitchInformation.RowPitch,
                                                           destPtr,
                                                           buffer.PitchInformation.RowPitch,
                                                           image.Format,
                                                           ImageBitFlags.None);
                        }

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

                if (opaqueLineCount != image.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;
                for (int y = 0; y < image.Height; y++)
                {
                    ImageUtilities.CopyScanline(destPtr,
                                                buffer.PitchInformation.RowPitch,
                                                destPtr,
                                                buffer.PitchInformation.RowPitch,
                                                image.Format,
                                                ImageBitFlags.OpaqueAlpha);
                    destPtr += buffer.PitchInformation.RowPitch;
                }
            }
        }