/// <summary> /// Function to write out the DDS header to the stream. /// </summary> /// <param name="settings">Meta data for the image header.</param> /// <param name="writer">Writer interface for the stream.</param> /// <param name="conversionFlags">Flags for image conversion.</param> private void WriteHeader(IImageSettings settings, GorgonBinaryWriter writer, out TGAConversionFlags conversionFlags) { TGAHeader header = default(TGAHeader); conversionFlags = TGAConversionFlags.None; if ((settings.Width > 0xFFFF) || (settings.Height > 0xFFFF)) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_ENCODER, Codec)); } header.Width = (ushort)(settings.Width); header.Height = (ushort)(settings.Height); switch (settings.Format) { case BufferFormat.R8G8B8A8_UIntNormal: case BufferFormat.R8G8B8A8_UIntNormal_sRGB: header.ImageType = TGAImageType.TrueColor; header.BPP = 32; header.Descriptor = TGADescriptor.InvertY | TGADescriptor.RGB888A8; conversionFlags |= TGAConversionFlags.Swizzle; break; case BufferFormat.B8G8R8A8_UIntNormal: case BufferFormat.B8G8R8A8_UIntNormal_sRGB: header.ImageType = TGAImageType.TrueColor; header.BPP = 32; header.Descriptor = TGADescriptor.InvertY | TGADescriptor.RGB888A8; break; case BufferFormat.B8G8R8X8_UIntNormal: case BufferFormat.B8G8R8X8_UIntNormal_sRGB: header.ImageType = TGAImageType.TrueColor; header.BPP = 24; header.Descriptor = TGADescriptor.InvertY; conversionFlags |= TGAConversionFlags.RGB888; break; case BufferFormat.R8_UIntNormal: case BufferFormat.A8_UIntNormal: header.ImageType = TGAImageType.BlackAndWhite; header.BPP = 8; header.Descriptor = TGADescriptor.InvertY; break; case BufferFormat.B5G5R5A1_UIntNormal: header.ImageType = TGAImageType.TrueColor; header.BPP = 16; header.Descriptor = TGADescriptor.InvertY | TGADescriptor.RGB555A1; break; default: throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format)); } // Persist to stream. writer.WriteValue(header); }
/// <summary> /// Function to write out the DDS header to the stream. /// </summary> /// <param name="settings">Meta data for the image header.</param> /// <param name="conversionFlags">Flags required for image conversion.</param> /// <returns>A TGA header value, populated with the correct settings.</returns> private TgaHeader GetHeader(IGorgonImageInfo settings, out TGAConversionFlags conversionFlags) { TgaHeader header = default; conversionFlags = TGAConversionFlags.None; if ((settings.Width > 0xFFFF) || (settings.Height > 0xFFFF)) { throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec)); } header.Width = (ushort)(settings.Width); header.Height = (ushort)(settings.Height); switch (settings.Format) { case BufferFormat.R8G8B8A8_UNorm: case BufferFormat.R8G8B8A8_UNorm_SRgb: header.ImageType = TgaImageType.TrueColor; header.BPP = 32; header.Descriptor = TgaDescriptor.InvertY | TgaDescriptor.RGB888A8; conversionFlags |= TGAConversionFlags.Swizzle; break; case BufferFormat.B8G8R8A8_UNorm: case BufferFormat.B8G8R8A8_UNorm_SRgb: header.ImageType = TgaImageType.TrueColor; header.BPP = 32; header.Descriptor = TgaDescriptor.InvertY | TgaDescriptor.RGB888A8; break; case BufferFormat.B8G8R8X8_UNorm: case BufferFormat.B8G8R8X8_UNorm_SRgb: header.ImageType = TgaImageType.TrueColor; header.BPP = 24; header.Descriptor = TgaDescriptor.InvertY; conversionFlags |= TGAConversionFlags.RGB888; break; case BufferFormat.R8_UNorm: case BufferFormat.A8_UNorm: header.ImageType = TgaImageType.BlackAndWhite; header.BPP = 8; header.Descriptor = TgaDescriptor.InvertY; break; case BufferFormat.B5G5R5A1_UNorm: header.ImageType = TgaImageType.TrueColor; header.BPP = 16; header.Descriptor = TgaDescriptor.InvertY | TgaDescriptor.RGB555A1; break; default: throw new IOException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, settings.Format)); } // Persist to stream. return(header); }
/// <summary> /// Function to read uncompressed TGA scanline data. /// </summary> /// <param name="src">Pointer to the source data.</param> /// <param name="srcPitch">Pitch of the source scan line.</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 static bool ReadUncompressed(byte *src, int srcPitch, byte *dest, BufferFormat format, TGAConversionFlags conversionFlags) { bool setOpaque = true; bool flipHorizontal = (conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX; switch (format) { case BufferFormat.R8_UIntNormal: for (int x = 0; x < srcPitch; x++) { if (!flipHorizontal) { *(dest++) = *(src++); } else { *(dest--) = *(src++); } } return(false); case BufferFormat.B5G5R5A1_UIntNormal: { var destPtr = (ushort *)dest; for (int x = 0; x < srcPitch; x += 2) { var pixel = (ushort)(*(src++) | (*(src++) << 8)); if ((pixel & 0x8000) != 0) { setOpaque = false; } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } return(setOpaque); } case BufferFormat.R8G8B8A8_UIntNormal: { var destPtr = (uint *)dest; int x = 0; while (x < srcPitch) { uint pixel; // We need to expand from 24 bit. if ((conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand) { pixel = ((uint)(*(src++) << 16) | (uint)(*(src++) << 8) | (*(src++)) | 0xFF000000); setOpaque = false; x += 3; } else { uint alpha = 0; pixel = ((uint)(*(src++) << 16) | (uint)(*(src++) << 8) | (*(src++)) | alpha); alpha = (uint)(*(src++) << 24); pixel |= alpha; if (alpha != 0) { setOpaque = false; } x += 4; } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } return(setOpaque); } } return(false); }
/// <summary> /// Function to read uncompressed TGA scanline data. /// </summary> /// <param name="src">Pointer to the source data.</param> /// <param name="width">Image width.</param> /// <param name="dest">Destination buffer pointner</param> /// <param name="end">End of the scan line.</param> /// <param name="format">Format of the destination buffer.</param> /// <param name="conversionFlags">Flags used for conversion.</param> private bool ReadCompressed(ref byte *src, int width, byte *dest, byte *end, BufferFormat format, TGAConversionFlags conversionFlags) { bool setOpaque = true; bool flipHorizontal = (conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX; switch (format) { case BufferFormat.R8_UIntNormal: for (int x = 0; x < width;) { if (src >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } int size = ((*src & 0x7F) + 1); // Do a repeat run. if ((*(src++) & 0x80) != 0) { if (src >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } for (; size > 0; --size, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } if (!flipHorizontal) { *(dest++) = *src; } else { *(dest--) = *src; } } ++src; } else { if (src + size > end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } for (; size > 0; --size, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } if (!flipHorizontal) { *(dest++) = *(src++); } else { *(dest--) = *(src++); } } } } return(false); case BufferFormat.B5G5R5A1_UIntNormal: { var destPtr = (ushort *)dest; for (int x = 0; x < width;) { if (src >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } int size = ((*src & 0x7F) + 1); // Do a repeat run. if ((*(src++) & 0x80) != 0) { if ((src + 1) >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } var pixel = (ushort)(*(src++) | (*(src++) << 8)); if ((pixel & 0x8000) != 0) { setOpaque = false; } for (; size > 0; size--, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } } else { if (src + (size * 2) > end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } for (; size > 0; size--, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } var pixel = (ushort)(*(src++) | (*(src++) << 8)); if ((pixel & 0x8000) != 0) { setOpaque = false; } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } } } return(setOpaque); } case BufferFormat.R8G8B8A8_UIntNormal: { var destPtr = (uint *)dest; for (int x = 0; x < width;) { if (src >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } uint pixel; int size = (*src & 0x7F) + 1; if ((*(src++) & 0x80) != 0) { // Do expansion. if ((conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand) { if (src + 2 >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } pixel = ((uint)(*src << 16) | (uint)(*(src + 1) << 8) | (*(src + 2)) | 0xFF000000); src += 3; setOpaque = false; } else { if (src + 3 >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } pixel = ((uint)(*src << 16) | (uint)(*(src + 1) << 8) | (*(src + 2)) | (uint)(*(src + 3) << 24)); if (*(src + 3) > 0) { setOpaque = false; } src += 4; } for (; size > 0; --size, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } } else { if ((conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand) { if (src + (size * 3) > end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } } else { if (src + (size * 4) > end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } } for (; size > 0; --size, ++x) { if (x >= width) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } if ((conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand) { if (src + 2 >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } pixel = ((uint)(*src << 16) | (uint)(*(src + 1) << 8) | (*(src + 2)) | 0xFF000000); src += 3; setOpaque = false; } else { if (src + 3 >= end) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } pixel = ((uint)(*src << 16) | (uint)(*(src + 1) << 8) | (*(src + 2)) | (uint)(*(src + 3) << 24)); if (*(src + 3) > 0) { setOpaque = false; } src += 4; } if (!flipHorizontal) { *(destPtr++) = pixel; } else { *(destPtr--) = pixel; } } } } return(setOpaque); } } return(false); }
/// <summary> /// Function to read in the DDS header from a stream. /// </summary> /// <param name="stream">Stream containing the data.</param> /// <param name="conversionFlags">Flags for conversion.</param> /// <returns>New image settings.</returns> private IImageSettings ReadHeader(GorgonDataStream stream, out TGAConversionFlags conversionFlags) { IImageSettings settings = new GorgonTexture2DSettings(); conversionFlags = TGAConversionFlags.None; // Get the header for the file. var header = stream.Read <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 IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } settings.MipCount = 1; settings.ArrayCount = 1; switch (header.ImageType) { case TGAImageType.TrueColor: case TGAImageType.TrueColorRLE: switch (header.BPP) { case 16: settings.Format = BufferFormat.B5G5R5A1_UIntNormal; break; case 24: case 32: settings.Format = BufferFormat.R8G8B8A8_UIntNormal; 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) { settings.Format = BufferFormat.R8_UIntNormal; } else { throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, header.ImageType)); } if (header.ImageType == TGAImageType.BlackAndWhiteRLE) { conversionFlags |= TGAConversionFlags.RLE; } break; default: throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, header.ImageType)); } settings.Width = header.Width; settings.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++) { stream.ReadByte(); } return(settings); }
/// <summary> /// Function to perform the copying of image data into the buffer. /// </summary> /// <param name="stream">Stream containing the image data.</param> /// <param name="image">Image data.</param> /// <param name="conversionFlags">Flags used to convert the image.</param> private void CopyImageData(GorgonDataStream stream, GorgonImageData image, TGAConversionFlags conversionFlags) { var buffer = image.Buffers[0]; // Get the first buffer only. var formatInfo = GorgonBufferFormatInfo.GetInfo(image.Settings.Format); GorgonFormatPitch srcPitch = (conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand ? new GorgonFormatPitch(image.Settings.Width * 3, image.Settings.Width * 3 * image.Settings.Height) : formatInfo.GetPitch(image.Settings.Width, image.Settings.Height, PitchFlags.None); // Otherwise, allocate a buffer for conversion. var srcPtr = (byte *)stream.PositionPointerUnsafe; var destPtr = (byte *)buffer.Data.UnsafePointer; // Adjust destination for inverted axes. if ((conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX) { destPtr += buffer.PitchInformation.RowPitch - formatInfo.SizeInBytes; } if ((conversionFlags & TGAConversionFlags.InvertY) != TGAConversionFlags.InvertY) { destPtr += (image.Settings.Height - 1) * buffer.PitchInformation.RowPitch; } // Get bounds of image memory. var scanSize = (int)(stream.Length - stream.Position); byte *endScan = (byte *)stream.PositionPointerUnsafe + scanSize; int opaqueLineCount = 0; for (int y = 0; y < image.Settings.Height; y++) { bool setOpaque; if ((conversionFlags & TGAConversionFlags.RLE) == TGAConversionFlags.RLE) { setOpaque = ReadCompressed(ref srcPtr, image.Settings.Width, destPtr, endScan, image.Settings.Format, conversionFlags); } else { setOpaque = ReadUncompressed(srcPtr, srcPitch.RowPitch, destPtr, image.Settings.Format, conversionFlags); srcPtr += srcPitch.RowPitch; } if ((setOpaque) && (SetOpaqueIfZeroAlpha)) { opaqueLineCount++; } if ((conversionFlags & TGAConversionFlags.InvertY) != TGAConversionFlags.InvertY) { destPtr -= buffer.PitchInformation.RowPitch; } else { destPtr += buffer.PitchInformation.RowPitch; } } if (opaqueLineCount != image.Settings.Height) { return; } // Set the alpha to opaque if we don't have any alpha values (i.e. alpha = 0 for all pixels). destPtr = (byte *)buffer.Data.UnsafePointer; for (int y = 0; y < image.Settings.Height; y++) { CopyScanline(destPtr, buffer.PitchInformation.RowPitch, destPtr, buffer.PitchInformation.RowPitch, image.Settings.Format, ImageBitFlags.OpaqueAlpha); destPtr += buffer.PitchInformation.RowPitch; } }
/// <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; } } }
/// <summary> /// Function to read uncompressed TGA scanline data. /// </summary> /// <param name="src">The pointer to the buffer containing the source data.</param> /// <param name="srcPitch">Pitch of the source scan line.</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 static unsafe bool ReadUncompressed(byte *src, int srcPitch, byte *dest, BufferFormat format, TGAConversionFlags conversionFlags) { bool flipHorizontal = (conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX; switch (format) { case BufferFormat.R8_UNorm: case BufferFormat.B5G5R5A1_UNorm: return(ImageUtilities.CopyScanline(src, srcPitch, dest, format, flipHorizontal)); case BufferFormat.R8G8B8A8_UNorm: if ((conversionFlags & TGAConversionFlags.Expand) != TGAConversionFlags.Expand) { return(ImageUtilities.CopyScanline(src, srcPitch, dest, format, flipHorizontal)); } ImageUtilities.Expand24BPPScanLine(src, srcPitch, dest, flipHorizontal); // We're already opaque by virtue of being 24 bit. return(false); } return(false); }
/// <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); }
/// <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); }