コード例 #1
0
ファイル: GorgonShader.cs プロジェクト: ishkang/Gorgon
        /// <summary>
        /// Function to persist the shader data to a stream as a <see cref="GorgonChunkFile{T}"/>.
        /// </summary>
        /// <param name="stream">The stream to write the data into.</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentException">Thrown when the stream is read only.</exception>
        /// <remarks>
        /// <para>
        /// This will write the shader data as <see cref="GorgonChunkFile{T}"/> formatted data into the supplied <paramref name="stream"/>. Shaders may take some time to compile, saving them to a binary
        /// format in a stream will help cut down on the time it takes to initialize an application.
        /// </para>
        /// <para>
        /// This makes use of the Gorgon <see cref="GorgonChunkFile{T}"/> format to allow flexible storage of data. The Gorgon shader format is broken into 2 chunks, both of which are available in the
        /// <see cref="GorgonShaderFactory.BinaryShaderMetaData"/>, and <see cref="GorgonShaderFactory.BinaryShaderByteCode"/> constants. The file header for the format is stored in the
        /// <see cref="GorgonShaderFactory.BinaryShaderFileHeader"/> constant.
        /// </para>
        /// <para>
        /// The file format is as follows:
        /// <list type="bullet">
        ///		<item>
        ///			<term><see cref="GorgonShaderFactory.BinaryShaderFileHeader"/></term>
        ///			<description>This describes the type of file, and the version.</description>
        ///		</item>
        ///		<item>
        ///			<term><see cref="GorgonShaderFactory.BinaryShaderMetaData"/></term>
        ///			<description>Shader metadata, such as the <see cref="Core.ShaderType"/> (<see cref="int"/>), debug flag (<see cref="bool"/>), and the entry point name (<see cref="string"/>) is stored here.</description>
        ///		</item>
        ///		<item>
        ///			<term><see cref="GorgonShaderFactory.BinaryShaderByteCode"/></term>
        ///			<description>The compiled shader byte code is stored here and is loaded as a <see cref="byte"/> array.</description>
        ///		</item>
        /// </list>
        /// </para>
        /// </remarks>
        /// <seealso cref="GorgonChunkFile{T}"/>
        /// <seealso cref="GorgonChunkFileReader"/>
        /// <seealso cref="GorgonChunkFileWriter"/>
        public void SaveToStream(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanWrite)
            {
                throw new ArgumentException(Resources.GORGFX_ERR_STREAM_WRITE_ONLY, nameof(stream));
            }

            var chunkFile = new GorgonChunkFileWriter(stream, GorgonShaderFactory.BinaryShaderFileHeader.ChunkID());

            try
            {
                GorgonBinaryWriter writer     = chunkFile.OpenChunk(GorgonShaderFactory.BinaryShaderMetaData);
                ShaderType         shaderType = ShaderType;
                writer.WriteValue(ref shaderType);
                writer.WriteValue(ref _isDebug);
                writer.Write(Name);
                chunkFile.CloseChunk();

                writer = chunkFile.OpenChunk(GorgonShaderFactory.BinaryShaderByteCode);
                writer.Write(D3DByteCode.Data);
            }
            finally
            {
                chunkFile.CloseChunk();
            }
        }
コード例 #2
0
ファイル: Program.cs プロジェクト: ishkang/Gorgon
        /// <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();
            }
        }
コード例 #3
0
        /// <summary>
        /// Function to write the font data to the stream.
        /// </summary>
        /// <param name="fontData">The font data to write.</param>
        /// <param name="stream">The stream to write into.</param>
        /// <remarks>
        /// <para>
        /// Implementors must override this method to write out the font data in the expected format.
        /// </para>
        /// </remarks>
        protected override void OnWriteFontData(GorgonFont fontData, Stream stream)
        {
            var             fontFile = new GorgonChunkFileWriter(stream, FileHeader.ChunkID());
            IGorgonFontInfo fontInfo = fontData.Info;

            try
            {
                fontFile.Open();

                GorgonBinaryWriter writer = fontFile.OpenChunk(FontInfoChunk);

                writer.Write(fontInfo.FontFamilyName);
                writer.Write(fontInfo.Size);
                writer.WriteValue(fontInfo.FontHeightMode);
                writer.WriteValue(fontInfo.FontStyle);
                writer.Write(fontInfo.DefaultCharacter);
                writer.Write(string.Join(string.Empty, fontInfo.Characters));
                writer.WriteValue(fontInfo.AntiAliasingMode);
                writer.Write(fontInfo.OutlineColor1.ToARGB());
                writer.Write(fontInfo.OutlineColor2.ToARGB());
                writer.Write(fontInfo.OutlineSize);
                writer.Write(fontInfo.PackingSpacing);
                writer.Write(fontInfo.TextureWidth);
                writer.Write(fontInfo.TextureHeight);
                writer.Write(fontInfo.UsePremultipliedTextures);
                writer.Write(fontInfo.UseKerningPairs);
                fontFile.CloseChunk();

                writer = fontFile.OpenChunk(FontHeightChunk);
                writer.Write(fontData.FontHeight);
                writer.Write(fontData.LineHeight);
                writer.Write(fontData.Ascent);
                writer.Write(fontData.Descent);
                fontFile.CloseChunk();

                if (fontInfo.Brush != null)
                {
                    writer = fontFile.OpenChunk(BrushChunk);
                    writer.Write((int)fontInfo.Brush.BrushType);
                    fontInfo.Brush.WriteBrushData(writer);
                    fontFile.CloseChunk();
                }

                if (fontInfo.UseKerningPairs)
                {
                    WriteKerningValues(fontData, fontFile);
                }
            }
            finally
            {
                fontFile.Close();
            }
        }
コード例 #4
0
 /// <summary>Function to write out the specifics of the font brush data to a file writer.</summary>
 /// <param name="writer">The writer used to write the brush data.</param>
 internal override void WriteBrushData(GorgonBinaryWriter writer)
 {
     writer.Write(Angle);
     writer.Write(ScaleAngle);
     writer.Write(GammaCorrection);
     writer.Write(Interpolation.Count);
     for (int i = 0; i < Interpolation.Count; ++i)
     {
         GorgonGlyphBrushInterpolator interp = Interpolation[i];
         writer.Write(interp.Weight);
         writer.Write(interp.Color.ToARGB());
     }
 }
コード例 #5
0
        /// <summary>
        /// Function to write out the kerning pair information for the font.
        /// </summary>
        /// <param name="fontData">The font data to write.</param>
        /// <param name="fontFile">The font file that is being persisted.</param>
        private static void WriteKerningValues(GorgonFont fontData, GorgonChunkFileWriter fontFile)
        {
            GorgonBinaryWriter writer = fontFile.OpenChunk(KernDataChunk);

            writer.Write(fontData.KerningPairs.Count);

            foreach (KeyValuePair <GorgonKerningPair, int> kerningInfo in fontData.KerningPairs)
            {
                writer.Write(kerningInfo.Key.LeftCharacter);
                writer.Write(kerningInfo.Key.RightCharacter);
                writer.Write(kerningInfo.Value);
            }

            fontFile.CloseChunk();
        }
コード例 #6
0
        /// <summary>Function to write out the specifics of the font brush data to a file writer.</summary>
        /// <param name="writer">The writer used to write the brush data.</param>
        internal override void WriteBrushData(GorgonBinaryWriter writer)
        {
            writer.Write((int)WrapMode);

            writer.Write(Points.Count);

            for (int i = 0; i < Points.Count; ++i)
            {
                writer.WriteValue(Points[i]);
            }

            writer.Write(BlendFactors.Count);

            for (int i = 0; i < BlendFactors.Count; ++i)
            {
                writer.Write(BlendFactors[i]);
            }

            writer.Write(BlendPositions.Count);

            for (int i = 0; i < BlendPositions.Count; ++i)
            {
                writer.Write(BlendPositions[i]);
            }

            writer.Write(CenterColor.ToARGB());
            writer.WriteValue(CenterPoint);
            writer.WriteValue(FocusScales);

            writer.Write(Interpolation.Count);
            for (int i = 0; i < Interpolation.Count; ++i)
            {
                GorgonGlyphBrushInterpolator interp = Interpolation[i];
                writer.Write(interp.Weight);
                writer.Write(interp.Color.ToARGB());
            }

            writer.Write(SurroundColors.Count);

            for (int i = 0; i < SurroundColors.Count; ++i)
            {
                writer.Write(SurroundColors[i].ToARGB());
            }
        }
コード例 #7
0
ファイル: GorgonNativeBuffer.cs プロジェクト: ishkang/Gorgon
        /// <summary>
        /// Function to copy the contents of this buffer into a stream.
        /// </summary>
        /// <param name="stream">The stream to write into.</param>
        /// <param name="startIndex">[Optional] The index in the buffer to start copying from.</param>
        /// <param name="count">[Optional] The maximum number of items to read from the stream.</param>
        /// <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 read only.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown when the <paramref name="startIndex"/> is less than 0.</exception>
        /// <exception cref="ArgumentException">Thrown when the <paramref name="startIndex"/> + <paramref name="count"/> are equal to or greater than the <see cref="Length"/>.</exception>
        /// <remarks>
        /// <para>
        /// If the <paramref name="count"/> parameter is ommitted, then the full length of the source buffer, minus the <paramref name="startIndex"/> is used. Ensure that there is enough space in the
        /// <paramref name="stream"/> to accomodate the amount of data required.
        /// </para>
        /// </remarks>
        /// <seealso cref="ToStream(int, int?)"/>
        public void CopyTo(Stream stream, int startIndex = 0, int?count = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            if (!stream.CanWrite)
            {
                throw new IOException(Resources.GOR_ERR_STREAM_IS_READONLY);
            }

            if (startIndex < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(startIndex), Resources.GOR_ERR_DATABUFF_OFFSET_TOO_SMALL);
            }

            if (count == null)
            {
                count = Length - startIndex;
            }


            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count), Resources.GOR_ERR_DATABUFF_SIZE_TOO_SMALL);
            }

            if (startIndex + count.Value > Length)
            {
                throw new ArgumentException(string.Format(Resources.GOR_ERR_DATABUFF_SIZE_OFFSET_TOO_LARGE, startIndex, count.Value));
            }

            using (var writer = new GorgonBinaryWriter(stream, true))
            {
                for (int i = 0; i < count.Value; ++i)
                {
                    writer.WriteValue(ref this[i + startIndex]);
                }
            }
        }
コード例 #8
0
ファイル: Program.cs プロジェクト: ishkang/Gorgon
        /// <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();
            }
        }
コード例 #9
0
ファイル: Program.cs プロジェクト: ishkang/Gorgon
        /// <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();
            }
        }
コード例 #10
0
 /// <summary>
 /// Function to write out the specifics of the font brush data to a file writer.
 /// </summary>
 /// <param name="writer">The writer used to write the brush data.</param>
 internal abstract void WriteBrushData(GorgonBinaryWriter writer);
コード例 #11
0
        /// <summary>
        /// Function to write the file to the specified path.
        /// </summary>
        /// <param name="path">Path to the file.</param>
        /// <param name="token">Token used to cancel the task.</param>
        protected override void WriteFile(string path, CancellationToken token)
        {
            // Don't allow other threads in here.
            lock (_syncLock)
            {
                _token = token;

                _tempPath = ScratchFileSystem.WriteLocation + Path.GetFileName(Path.GetTempFileName());

                // Calculate compression ratio.  9 is the max compression level for bzip 2.
                _compressionRatio = (int)System.Math.Round(Compression * 9.0f, 0, MidpointRounding.AwayFromZero);

                try
                {
                    // Build file system.
                    BuildFileSystem();

                    if (_token.IsCancellationRequested)
                    {
                        return;
                    }

                    // Turn off cancellation at this point.
                    CanCancel(false);

                    if (_token.IsCancellationRequested)
                    {
                        return;
                    }

                    // Write out our file.
                    using (var outputFile = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.Read))
                    {
                        // Combine the file system parts into a single packed file.
                        using (var writer = new GorgonBinaryWriter(outputFile, true))
                        {
                            // Write the file header.
                            writer.Write("GORPACK1.SharpZip.BZ2");

                            // Copy FAT.
                            using (var fatData = new GorgonDataStream(Encoding.UTF8.GetBytes(_fat.ToStringWithDeclaration())))
                            {
                                using (var compressData = new MemoryStream())
                                {
                                    CompressData(fatData, compressData);
                                    compressData.Position = 0;

                                    writer.Write((int)compressData.Length);
                                    compressData.CopyTo(outputFile);
                                }
                            }
                        }

                        // Copy the file data.
                        using (var fileData = File.Open(_tempPath, FileMode.Open, FileAccess.Read, FileShare.Read))
                        {
                            fileData.CopyTo(outputFile);
                        }
                    }
                }
                finally
                {
                    // Destroy the temp data file.
                    File.Delete(_tempPath);
                }
            }
        }
コード例 #12
0
 /// <summary>Function to write out the specifics of the font brush data to a file writer.</summary>
 /// <param name="writer">The writer used to write the brush data.</param>
 internal override void WriteBrushData(GorgonBinaryWriter writer)
 {
     writer.Write((int)HatchStyle);
     writer.Write(ForegroundColor.ToARGB());
     writer.Write(BackgroundColor.ToARGB());
 }
コード例 #13
0
        /// <summary>
        /// Function to persist a <see cref="IGorgonImage"/> to a stream.
        /// </summary>
        /// <param name="imageData">A <see cref="IGorgonImage"/> to persist to the stream.</param>
        /// <param name="stream">The stream that will receive the image data.</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/>, or the <paramref name="imageData"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="stream"/> is read only.</exception>
        /// <exception cref="NotSupportedException">Thrown when the image data in the stream has a pixel format that is unsupported by the codec.</exception>
        /// <remarks>
        /// <para>
        /// When persisting image data via a codec, the image must have a format that the codec can recognize. This list of supported formats is provided by the <see cref="SupportedPixelFormats"/>
        /// property. Applications may convert their image data a supported format before saving the data using a codec.
        /// </para>
        /// </remarks>
        public override void SaveToStream(IGorgonImage imageData, Stream stream)
        {
            // Ensure that we can actually read this format.  We do not perform total pixel conversion on behalf of the user, they are responsible for that.
            // We will, however, support swizzling and pixel compression (e.g. 32 -> 24 bit).
            if (Array.IndexOf(_supportedFormats, imageData.Format) == -1)
            {
                throw new NotSupportedException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, imageData.Format));
            }

            using (var writer = new GorgonBinaryWriter(stream, true))
            {
                // Write the header for the file before we dump the file contents.
                TgaHeader header = GetHeader(imageData, out TGAConversionFlags conversionFlags);

                GorgonPitchLayout destPitch;

                if ((conversionFlags & TGAConversionFlags.RGB888) == TGAConversionFlags.RGB888)
                {
                    destPitch = new GorgonPitchLayout(imageData.Width * 3, imageData.Width * 3 * imageData.Height);
                }
                else
                {
                    var formatInfo = new GorgonFormatInfo(imageData.Format);
                    destPitch = formatInfo.GetPitchForFormat(imageData.Width, imageData.Height);
                }

                GorgonPitchLayout srcPitch = imageData.Buffers[0].PitchInformation;

                // If the two pitches are equal and we have no conversion requirements, then just write out the buffer.
                if ((destPitch == srcPitch) && (conversionFlags == TGAConversionFlags.None))
                {
                    writer.WriteValue(ref header);
                    writer.WriteRange(imageData.Buffers[0].Data, count: srcPitch.SlicePitch);
                    return;
                }

                unsafe
                {
                    // Get the pointer to the first mip/array/depth level.
                    byte *srcPointer = (byte *)imageData.Buffers[0].Data;
                    var   lineBuffer = new GorgonNativeBuffer <byte>(srcPitch.RowPitch);

                    try
                    {
                        // Persist the working buffer to the stream.
                        writer.WriteValue(ref header);

                        // Write out each scan line.
                        for (int y = 0; y < imageData.Height; y++)
                        {
                            byte *destPtr = (byte *)lineBuffer;

                            if ((conversionFlags & TGAConversionFlags.RGB888) == TGAConversionFlags.RGB888)
                            {
                                ImageUtilities.Compress24BPPScanLine(srcPointer,
                                                                     srcPitch.RowPitch,
                                                                     destPtr,
                                                                     destPitch.RowPitch,
                                                                     (conversionFlags & TGAConversionFlags.Swizzle) == TGAConversionFlags.Swizzle);
                            }
                            else if ((conversionFlags & TGAConversionFlags.Swizzle) == TGAConversionFlags.Swizzle)
                            {
                                ImageUtilities.SwizzleScanline(srcPointer, srcPitch.RowPitch, destPtr, destPitch.RowPitch, imageData.Format, ImageBitFlags.None);
                            }
                            else
                            {
                                ImageUtilities.CopyScanline(srcPointer, srcPitch.RowPitch, destPtr, destPitch.RowPitch, imageData.Format, ImageBitFlags.None);
                            }

                            srcPointer += srcPitch.RowPitch;

                            writer.WriteRange(lineBuffer, count: destPitch.RowPitch);
                        }
                    }
                    finally
                    {
                        lineBuffer?.Dispose();
                    }
                }
            }
        }
コード例 #14
0
 /// <summary>Function to write out the specifics of the font brush data to a file writer.</summary>
 /// <param name="writer">The writer used to write the brush data.</param>
 internal override void WriteBrushData(GorgonBinaryWriter writer) => writer.Write(Color.ToARGB());
コード例 #15
0
        /// <summary>
        /// Function to persist image data to a stream.
        /// </summary>
        /// <param name="imageData"><see cref="GorgonLibrary.Graphics.GorgonImageData">Gorgon image data</see> to persist.</param>
        /// <param name="stream">Stream that will contain the data.</param>
        protected override void SaveToStream(GorgonImageData imageData, Stream stream)
        {
            if (imageData.Settings.Format != BufferFormat.R8G8B8A8_UIntNormal)
            {
                throw new ArgumentException(@"The image format must be R8G8B8A8_UIntNormal", "imageData");
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

                        // Send the scanline to the file.
                        writer.Write(scanLineBuffer);
                    }
                }
            }
        }
コード例 #16
0
        public void ChunkReaderWriter()
        {
            const string stringChunk = "STRSCHNK";
            const string intChunk    = "INTSCHNK";
            const string header      = "TheHeader";

            string[] strs =
            {
                "Cow",
                "Dog",
                "Cat",
                "Rabbit",
                "Duck"
            };

            int[] ints =
            {
                32,
                11,
                89,
                64,
                87,
                77,
                16,
                2,
                42
            };

            int expectedStrLength  = strs.Length;
            int expectedIntsLength = ints.Length;

            using (MemoryStream stream = new MemoryStream())
            {
                var fileWriter = new GorgonChunkFileWriter(stream, header.ChunkID());
                fileWriter.Open();

                GorgonBinaryWriter writer = fileWriter.OpenChunk(stringChunk.ChunkID());

                writer.Write(strs.Length);

                foreach (string str in strs)
                {
                    writer.Write(str);
                }

                fileWriter.CloseChunk();

                writer = fileWriter.OpenChunk(intChunk.ChunkID());

                writer.Write(ints.Length);

                foreach (int intVal in ints)
                {
                    writer.Write(intVal);
                }

                fileWriter.CloseChunk();

                fileWriter.Close();

                stream.Position = 0;

                var fileReader = new GorgonChunkFileReader(stream,
                                                           new[]
                {
                    header.ChunkID()
                });

                fileReader.Open();

                GorgonBinaryReader reader = fileReader.OpenChunk(intChunk.ChunkID());

                int numInts = reader.ReadInt32();

                Assert.AreEqual(expectedIntsLength, numInts);

                int[] intVals = new int[numInts];

                for (int i = 0; i < numInts; ++i)
                {
                    intVals[i] = reader.ReadInt32();
                }

                Assert.IsTrue(ints.SequenceEqual(intVals));

                fileReader.CloseChunk();

                reader = fileReader.OpenChunk(stringChunk.ChunkID());

                int numStrs = reader.ReadInt32();

                Assert.AreEqual(expectedStrLength, numStrs);

                string[] strVals = new string[numStrs];

                for (int i = 0; i < numStrs; ++i)
                {
                    strVals[i] = reader.ReadString();
                }

                Assert.IsTrue(strs.SequenceEqual(strVals));

                fileReader.CloseChunk();

                fileReader.Close();
            }
        }