Example #1
0
        /// <summary>
        /// Loads a DDS texture from an input stream.
        /// </summary>
        public static Texture2DInfo LoadDDSTexture(Stream inputStream, bool flipVertically = false)
        {
            using (var reader = new UnityBinaryReader(inputStream))
            {
                // Check the magic string.
                var magicString = reader.ReadBytes(4);
                if (!StringUtils.Equals(magicString, "DDS "))
                {
                    throw new FileFormatException("Invalid DDS file magic string: \"" + System.Text.Encoding.ASCII.GetString(magicString) + "\".");
                }

                // Deserialize the DDS file header.
                var header = new DDSHeader();
                header.Deserialize(reader);

                // Figure out the texture format and load the texture data.
                bool          hasMipmaps;
                uint          DDSMipmapLevelCount;
                TextureFormat textureFormat;
                int           bytesPerPixel;
                byte[]        textureData;
                ExtractDDSTextureFormatAndData(header, reader, out hasMipmaps, out DDSMipmapLevelCount, out textureFormat, out bytesPerPixel, out textureData);

                // Post-process the texture to generate missing mipmaps and possibly flip it vertically.
                PostProcessDDSTexture((int)header.dwWidth, (int)header.dwHeight, bytesPerPixel, hasMipmaps, (int)DDSMipmapLevelCount, textureData, flipVertically);

                return(new Texture2DInfo((int)header.dwWidth, (int)header.dwHeight, textureFormat, hasMipmaps, textureData));
            }
        }
Example #2
0
        /// <summary>
        /// Extracts a DDS file's texture format and pixel data.
        /// </summary>
        private static void ExtractDDSTextureFormatAndData(DDSHeader header, UnityBinaryReader reader, out bool hasMipmaps, out uint DDSMipmapLevelCount, out TextureFormat textureFormat, out int bytesPerPixel, out byte[] textureData)
        {
            hasMipmaps = Utils.ContainsBitFlags(header.dwCaps, (uint)DDSCaps.Mipmap);

            // Non-mipmapped textures still have one mipmap level: the texture itself.
            DDSMipmapLevelCount = hasMipmaps ? header.dwMipMapCount : 1;

            // If the DDS file contains uncompressed data.
            if (Utils.ContainsBitFlags(header.pixelFormat.flags, (uint)DDSPixelFormatFlags.RGB))
            {
                // some permutation of RGB
                if (!Utils.ContainsBitFlags(header.pixelFormat.flags, (uint)DDSPixelFormatFlags.AlphaPixels))
                {
                    throw new NotImplementedException("Unsupported DDS file pixel format.");
                }
                // some permutation of RGBA
                else
                {
                    // There should be 32 bits per pixel.
                    if (header.pixelFormat.RGBBitCount != 32)
                    {
                        throw new FileFormatException("Invalid DDS file pixel format.");
                    }

                    // BGRA32
                    if ((header.pixelFormat.BBitMask == 0x000000FF) && (header.pixelFormat.GBitMask == 0x0000FF00) && (header.pixelFormat.RBitMask == 0x00FF0000) && (header.pixelFormat.ABitMask == 0xFF000000))
                    {
                        textureFormat = TextureFormat.BGRA32;
                        bytesPerPixel = 4;
                    }
                    // ARGB32
                    else if ((header.pixelFormat.ABitMask == 0x000000FF) && (header.pixelFormat.RBitMask == 0x0000FF00) && (header.pixelFormat.GBitMask == 0x00FF0000) && (header.pixelFormat.BBitMask == 0xFF000000))
                    {
                        textureFormat = TextureFormat.ARGB32;
                        bytesPerPixel = 4;
                    }
                    else
                    {
                        throw new NotImplementedException("Unsupported DDS file pixel format.");
                    }

                    if (!hasMipmaps)
                    {
                        textureData = new byte[header.dwPitchOrLinearSize * header.dwHeight];
                    }
                    else
                    {
                        // Create a data buffer to hold all mipmap levels down to 1x1.
                        textureData = new byte[TextureUtils.CalculateMipMappedTextureDataSize((int)header.dwWidth, (int)header.dwHeight, bytesPerPixel)];
                    }

                    reader.ReadRestOfBytes(textureData, 0);
                }
            }
            else if (StringUtils.Equals(header.pixelFormat.fourCC, "DXT1"))
            {
                textureFormat = TextureFormat.ARGB32;
                bytesPerPixel = 4;

                var compressedTextureData = reader.ReadRestOfBytes();
                textureData = DecodeDXT1ToARGB(compressedTextureData, header.dwWidth, header.dwHeight, header.pixelFormat, DDSMipmapLevelCount);
            }
            else if (StringUtils.Equals(header.pixelFormat.fourCC, "DXT3"))
            {
                textureFormat = TextureFormat.ARGB32;
                bytesPerPixel = 4;

                var compressedTextureData = reader.ReadRestOfBytes();
                textureData = DecodeDXT3ToARGB(compressedTextureData, header.dwWidth, header.dwHeight, header.pixelFormat, DDSMipmapLevelCount);
            }
            else if (StringUtils.Equals(header.pixelFormat.fourCC, "DXT5"))
            {
                textureFormat = TextureFormat.ARGB32;
                bytesPerPixel = 4;

                var compressedTextureData = reader.ReadRestOfBytes();
                textureData = DecodeDXT5ToARGB(compressedTextureData, header.dwWidth, header.dwHeight, header.pixelFormat, DDSMipmapLevelCount);
            }
            else
            {
                throw new NotImplementedException("Unsupported DDS file pixel format.");
            }
        }
Example #3
0
		/// <summary>
		/// Extracts a DDS file's texture format and pixel data.
		/// </summary>
		private static void ExtractDDSTextureFormatAndData(DDSHeader header, UnityBinaryReader reader, out bool hasMipmaps, out uint DDSMipmapLevelCount, out TextureFormat textureFormat, out int bytesPerPixel, out byte[] textureData)
		{
			hasMipmaps = Utils.ContainsBitFlags(header.dwCaps, (uint)DDSCaps.Mipmap);

			// Non-mipmapped textures still have one mipmap level: the texture itself.
			DDSMipmapLevelCount = hasMipmaps ? header.dwMipMapCount : 1;

			// If the DDS file contains uncompressed data.
			if(Utils.ContainsBitFlags(header.pixelFormat.flags, (uint)DDSPixelFormatFlags.RGB))
			{
				// some permutation of RGB
				if(!Utils.ContainsBitFlags(header.pixelFormat.flags, (uint)DDSPixelFormatFlags.AlphaPixels))
				{
					throw new NotImplementedException("Unsupported DDS file pixel format.");
				}
				// some permutation of RGBA
				else
				{
					// There should be 32 bits per pixel.
					if(header.pixelFormat.RGBBitCount != 32)
					{
						throw new FileFormatException("Invalid DDS file pixel format.");
					}

					// BGRA32
					if((header.pixelFormat.BBitMask == 0x000000FF) && (header.pixelFormat.GBitMask == 0x0000FF00) && (header.pixelFormat.RBitMask == 0x00FF0000) && (header.pixelFormat.ABitMask == 0xFF000000))
					{
						textureFormat = TextureFormat.BGRA32;
						bytesPerPixel = 4;
					}
					// ARGB32
					else if((header.pixelFormat.ABitMask == 0x000000FF) && (header.pixelFormat.RBitMask == 0x0000FF00) && (header.pixelFormat.GBitMask == 0x00FF0000) && (header.pixelFormat.BBitMask == 0xFF000000))
					{
						textureFormat = TextureFormat.ARGB32;
						bytesPerPixel = 4;
					}
					else
					{
						throw new NotImplementedException("Unsupported DDS file pixel format.");
					}

					if(!hasMipmaps)
					{
						textureData = new byte[header.dwPitchOrLinearSize * header.dwHeight];
					}
					else
					{
						// Create a data buffer to hold all mipmap levels down to 1x1.
						textureData = new byte[TextureUtils.CalculateMipMappedTextureDataSize((int)header.dwWidth, (int)header.dwHeight, bytesPerPixel)];
					}
					
					reader.ReadRestOfBytes(textureData, 0);
				}
			}
			else if(StringUtils.Equals(header.pixelFormat.fourCC, "DXT1"))
			{
				textureFormat = TextureFormat.ARGB32;
				bytesPerPixel = 4;

				var compressedTextureData = reader.ReadRestOfBytes();
				textureData = DecodeDXT1ToARGB(compressedTextureData, header.dwWidth, header.dwHeight, header.pixelFormat, DDSMipmapLevelCount);
			}
			else if(StringUtils.Equals(header.pixelFormat.fourCC, "DXT3"))
			{
				textureFormat = TextureFormat.ARGB32;
				bytesPerPixel = 4;

				var compressedTextureData = reader.ReadRestOfBytes();
				textureData = DecodeDXT3ToARGB(compressedTextureData, header.dwWidth, header.dwHeight, header.pixelFormat, DDSMipmapLevelCount);
			}
			else if(StringUtils.Equals(header.pixelFormat.fourCC, "DXT5"))
			{
				textureFormat = TextureFormat.ARGB32;
				bytesPerPixel = 4;

				var compressedTextureData = reader.ReadRestOfBytes();
				textureData = DecodeDXT5ToARGB(compressedTextureData, header.dwWidth, header.dwHeight, header.pixelFormat, DDSMipmapLevelCount);
			}
			else
			{
				throw new NotImplementedException("Unsupported DDS file pixel format.");
			}
		}
Example #4
0
		/// <summary>
		/// Loads a DDS texture from an input stream.
		/// </summary>
		public static Texture2DInfo LoadDDSTexture(Stream inputStream, bool flipVertically = false)
		{
			using(var reader = new UnityBinaryReader(inputStream))
			{
				// Check the magic string.
				var magicString = reader.ReadBytes(4);
				if(!StringUtils.Equals(magicString, "DDS "))
				{
					throw new FileFormatException("Invalid DDS file magic string: \"" + System.Text.Encoding.ASCII.GetString(magicString) + "\".");
				}

				// Deserialize the DDS file header.
				var header = new DDSHeader();
				header.Deserialize(reader);

				// Figure out the texture format and load the texture data.
				bool hasMipmaps;
				uint DDSMipmapLevelCount;
				TextureFormat textureFormat;
				int bytesPerPixel;
				byte[] textureData;
				ExtractDDSTextureFormatAndData(header, reader, out hasMipmaps, out DDSMipmapLevelCount, out textureFormat, out bytesPerPixel, out textureData);

				// Post-process the texture to generate missing mipmaps and possibly flip it vertically.
				PostProcessDDSTexture((int)header.dwWidth, (int)header.dwHeight, bytesPerPixel, hasMipmaps, (int)DDSMipmapLevelCount, textureData, flipVertically);

				return new Texture2DInfo((int)header.dwWidth, (int)header.dwHeight, textureFormat, hasMipmaps, textureData);
			}
		}