private Stream buildDdsImage(int mipMapIndex, out FileFormat imageFormat)
        {
            DomainPropertyByteValue formatProp = PropertyHeader.GetProperty("Format").FirstOrDefault()?.Value as DomainPropertyByteValue;

            imageFormat = FileFormat.Unknown;

            if (formatProp == null)
            {
                return(null);
            }

            string format = formatProp.PropertyString;

            DomainMipMap mipMap = MipMaps[mipMapIndex];

            imageFormat = DdsPixelFormat.ParseFileFormat(format);

            DdsHeader ddsHeader = new DdsHeader(new DdsSaveConfig(imageFormat, 0, 0, false, false), mipMap.Width, mipMap.Height);

            MemoryStream stream = new MemoryStream();

            BinaryWriter writer = new BinaryWriter(stream);

            ddsHeader.Write(writer);

            stream.Write(mipMap.ImageData, 0, mipMap.ImageData.Length);

            stream.Flush();

            stream.Position = 0;

            return(stream);
        }
Example #2
0
    public static unsafe bool RgbaBytesToDds(byte[] rgba, int width, int height, out byte[] ddsData)
    {
        var header = new DdsHeader()
        {
            Caps1       = DdsHeader.DdsCaps1.Complex | DdsHeader.DdsCaps1.Texture | DdsHeader.DdsCaps1.MipMap,
            Depth       = 1,
            Flags       = DdsHeader.DdsFlags.Required | DdsHeader.DdsFlags.Pitch | DdsHeader.DdsFlags.MipMapCount,
            Height      = height,
            Width       = width,
            PixelFormat = new PixelFormat()
            {
                Flags       = PixelFormat.FormatFlags.AlphaPixels | PixelFormat.FormatFlags.RGB,
                FourCC      = 0,
                BBitMask    = 0x000000FF,
                GBitMask    = 0x0000FF00,
                RBitMask    = 0x00FF0000,
                ABitMask    = 0xFF000000,
                Size        = 32,
                RgbBitCount = 32,
            },
        };

        ddsData = new byte[4 + DdsHeader.Size + rgba.Length];
        header.Write(ddsData, 0);
        rgba.CopyTo(ddsData, DdsHeader.Size + 4);
        for (var i = 0; i < rgba.Length; i += 4)
        {
            (ddsData[DdsHeader.Size + i], ddsData[DdsHeader.Size + i + 2])
                = (ddsData[DdsHeader.Size + i + 2], ddsData[DdsHeader.Size + i]);
        }

        return(true);
    }
Example #3
0
        private Stream buildDdsImage(int mipMapIndex)
        {
            MipMap    mipMap    = maps[mipMapIndex];
            DdsHeader ddsHeader = new DdsHeader(new DdsSaveConfig(parsedImageFormat, 0, 0, false, false), mipMap.sizeX, mipMap.sizeY);

            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);

            ddsHeader.Write(writer);
            writer.Write(mipMap.uncompressedData);
            writer.Flush();
            writer.BaseStream.Position = 0;

            return(stream);
        }
Example #4
0
        private Stream buildDdsImage(int mipMapIndex, out FileFormat imageFormat)
        {
            MipMap mipMap = maps[mipMapIndex];

            imageFormat = GetFormat();
            DdsHeader ddsHeader = new DdsHeader(new DdsSaveConfig(imageFormat, 0, 0, false, false), mipMap.sizeX, mipMap.sizeY);

            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);

            ddsHeader.Write(writer);
            stream.Write(mipMap.uncompressedData, 0, mipMap.uncompressedData.Length);
            stream.Flush();
            stream.Position = 0;

            return(stream);
        }
        internal void Save(TextureCollection textures, Stream output, ProgressEventHandler progressCallback)
        {
            DdsHeader header = new DdsHeader(this.width, this.height, this.arraySize, this.mipLevels, this.format);

            output.WriteUInt32(DdsMagic);
            header.Write(output);

            double progressTotal = this.arraySize * this.mipLevels;

            for (int i = 0; i < this.arraySize; ++i)
            {
                int startIndex = i * this.mipLevels;

                for (int j = 0; j < this.mipLevels; ++j)
                {
                    int index = startIndex + j;

                    WritePixelData(textures[index].Surface, output);

                    progressCallback?.Invoke(this, new ProgressEventArgs((index / progressTotal) * 100.0, true));
                }
            }
        }
Example #6
0
        //////////////////////////////////////////////

        public static void WriteFile(Stream output, DDSTextureTools.DDSImage image)
        {
            DdsHeader header = new DdsHeader();

            // For non-compressed textures, we need pixel width.
            //int pixelWidth = 0;

            // Identify if we're a compressed image
            bool isCompressed =
                image.Format == DDSTextureTools.DDSImage.FormatEnum.DXT1 ||
                image.Format == DDSTextureTools.DDSImage.FormatEnum.DXT3 ||
                image.Format == DDSTextureTools.DDSImage.FormatEnum.DXT5 ||
                image.Format == DDSTextureTools.DDSImage.FormatEnum.BC5;

            int width  = image.Surfaces[0].Size.X;
            int height = image.Surfaces[0].Size.Y;

            //// Compute mip map count..
            int mipCount  = image.Cubemap ? image.Surfaces.Length / 6 : image.Surfaces.Length;
            int mipWidth  = width;           // surface.Width;
            int mipHeight = height;          // surface.Height;

            // Populate bulk of our DdsHeader
            header.m_size        = header.Size();
            header.m_headerFlags = (uint)(DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_TEXTURE);

            if (isCompressed)
            {
                header.m_headerFlags |= (uint)(DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_LINEARSIZE);
            }
            else
            {
                header.m_headerFlags |= (uint)(DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_PITCH);
            }

            if (mipCount > 1)
            {
                header.m_headerFlags |= (uint)(DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_MIPMAP);
            }

            header.m_height = (uint)height;          // surface.Height;
            header.m_width  = (uint)width;           // surface.Width;

            if (isCompressed)
            {
                // Compresssed textures have the linear flag set.So pitchOrLinearSize
                // needs to contain the entire size of the DXT block.
                int blockCount = ((width + 3) / 4) * ((height + 3) / 4);
                int blockSize  = (image.Format == DDSTextureTools.DDSImage.FormatEnum.DXT1) ? 8 : 16;
                header.m_pitchOrLinearSize = (uint)(blockCount * blockSize);
            }
            else
            {
                int pixelWidth = 0;

                // Non-compressed textures have the pitch flag set. So pitchOrLinearSize
                // needs to contain the row pitch of the main image. DWORD aligned too.
                switch (image.Format)
                {
                case DDSTextureTools.DDSImage.FormatEnum.A8R8G8B8:
                case DDSTextureTools.DDSImage.FormatEnum.X8R8G8B8:
                case DDSTextureTools.DDSImage.FormatEnum.A8B8G8R8:
                case DDSTextureTools.DDSImage.FormatEnum.X8B8G8R8:
                    pixelWidth = 4;                    // 32bpp
                    break;

                case DDSTextureTools.DDSImage.FormatEnum.A1R5G5B5:
                case DDSTextureTools.DDSImage.FormatEnum.A4R4G4B4:
                case DDSTextureTools.DDSImage.FormatEnum.R5G6B5:
                    pixelWidth = 2;                    // 16bpp
                    break;

                case DDSTextureTools.DDSImage.FormatEnum.R8G8B8:
                    pixelWidth = 3;                    // 24bpp
                    break;

                case DDSTextureTools.DDSImage.FormatEnum.R16G16B16A16:
                    pixelWidth = 8;                    // 64bpp
                    break;
                }

                // Compute row pitch
                header.m_pitchOrLinearSize = (uint)((int)header.m_width * pixelWidth);

                ////#if	APPLY_PITCH_ALIGNMENT
                //// Align to DWORD, if we need to.. (see notes about pitch alignment all over this code)
                //header.m_pitchOrLinearSize = (uint)( ( (int)header.m_pitchOrLinearSize + 3 ) & ( ~3 ) );
                ////#endif	//APPLY_PITCH_ALIGNMENT
            }

            header.m_depth        = 0;
            header.m_mipMapCount  = (mipCount == 1) ? 0 : (uint)mipCount;
            header.m_reserved1_0  = 0;
            header.m_reserved1_1  = 0;
            header.m_reserved1_2  = 0;
            header.m_reserved1_3  = 0;
            header.m_reserved1_4  = 0;
            header.m_reserved1_5  = 0;
            header.m_reserved1_6  = 0;
            header.m_reserved1_7  = 0;
            header.m_reserved1_8  = 0;
            header.m_reserved1_9  = 0;
            header.m_reserved1_10 = 0;

            // Populate our DdsPixelFormat object
            header.m_pixelFormat.Initialise(image.Format);

            // Populate miscellanous header flags
            header.m_surfaceFlags = (uint)DdsHeader.SurfaceFlags.DDS_SURFACE_FLAGS_TEXTURE;

            if (mipCount > 1)
            {
                header.m_surfaceFlags |= (uint)DdsHeader.SurfaceFlags.DDS_SURFACE_FLAGS_MIPMAP;
            }
            if (image.Cubemap)
            {
                header.m_surfaceFlags |= (uint)DdsHeader.SurfaceFlags.DDS_SURFACE_FLAGS_CUBEMAP;
            }

            header.m_cubemapFlags = image.Cubemap ? (uint)DdsHeader.CubemapFlags.DDS_CUBEMAP_ALLFACES : 0;
            header.m_reserved2_0  = 0;
            header.m_reserved2_1  = 0;
            header.m_reserved2_2  = 0;

            // Write out our DDS tag
            Utility.WriteUInt32(output, 0x20534444);               // 'DDS '

            // Write out the header
            header.Write(output);

            //DDSSquish.SquishFlags squishFlags = /*ddsToken.*/GetSquishFlags( fileFormat );

            //// Our output data array will be sized as necessary
            //byte[] outputData;

            // Reset our mip width & height variables...
            mipWidth  = width;           // surface.Width;
            mipHeight = height;          // surface.Height;

            //// Figure out how much total work each mip map is
            //Size[] writeSizes = new Size[ mipCount ];
            //int[] mipPixels = new int[ mipCount ];
            //int[] pixelsCompleted = new int[ mipCount ]; // # pixels completed once we have reached this mip
            //long totalPixels = 0;
            //for( int mipLoop = 0; mipLoop < mipCount; mipLoop++ )
            //{
            //   Size writeSize = new Size( ( mipWidth > 0 ) ? mipWidth : 1, ( mipHeight > 0 ) ? mipHeight : 1 );
            //   writeSizes[ mipLoop ] = writeSize;

            //   int thisMipPixels = writeSize.Width * writeSize.Height;
            //   mipPixels[ mipLoop ] = thisMipPixels;

            //   if( mipLoop == 0 )
            //   {
            //      pixelsCompleted[ mipLoop ] = 0;
            //   }
            //   else
            //   {
            //      pixelsCompleted[ mipLoop ] = pixelsCompleted[ mipLoop - 1 ] + mipPixels[ mipLoop - 1 ];
            //   }

            //   totalPixels += thisMipPixels;
            //   mipWidth /= 2;
            //   mipHeight /= 2;
            //}

            //mipWidth = width;// surface.Width;
            //mipHeight = height;// surface.Height;

            for (int nSurface = 0; nSurface < image.Surfaces.Length; nSurface++)
            //for( int mipLoop = 0; mipLoop < mipCount; mipLoop++ )
            {
                DDSTextureTools.DDSImage.Surface surface = image.Surfaces[nSurface];
                //TextureTools.DDSImage.Surface surface = image.Surfaces[ mipLoop ];

                //Size writeSize = writeSizes[ mipLoop ];
                //Surface writeSurface = new Surface( writeSize );

                //if( mipLoop == 0 )
                //{
                //   // No point resampling the first level.. it's got exactly what we want.
                //   writeSurface = surface;
                //}
                //else
                //{
                //   // I'd love to have a UI component to select what kind of resampling, but
                //   // there's hardly any space for custom UI stuff in the Save Dialog. And I'm
                //   // not having any scrollbars in there..!
                //   // Also, note that each mip level is formed from the main level, to reduce
                //   // compounded errors when generating mips.
                //   writeSurface.SuperSamplingFitSurface( surface );
                //}

                //DdsSquish.ProgressFn progressFn =
                //    delegate( int workDone, int workTotal )
                //    {
                //       long thisMipPixelsDone = workDone * (long)mipWidth;
                //       long previousMipsPixelsDone = pixelsCompleted[ mipLoop ];
                //       double progress = (double)( (double)thisMipPixelsDone + (double)previousMipsPixelsDone ) / (double)totalPixels;
                //       progressCallback( this, new ProgressEventArgs( 100.0 * progress ) );
                //    };

                //if( ( /*ddsToken.m_*/fileFormat >= DdsFileFormat.DDS_FORMAT_DXT1 ) &&
                //   ( /*ddsToken.m_*/fileFormat <= DdsFileFormat.DDS_FORMAT_DXT5 ) )
                //{
                //   outputData = DDSSquish.CompressImage( writeSurface, squishFlags/*,
                //      ( progressCallback == null ) ? null : progressFn*/
                //                                                         );
                //}
                //else
                //{
                //   Trace.Assert( false );

                //               int mipPitch = pixelWidth * writeSurface.Width;

                //               // From the DDS documents I read, I'd expected the pitch of each mip level to be
                //               // DWORD aligned. As it happens, that's not the case. Re-aligning the pitch of
                //               // each level results in later mips getting sheared as the pitch is incorrect.
                //               // So, the following line is intentionally optional. Maybe the documentation
                //               // is referring to the pitch when accessing the mip directly.. who knows.
                //               //
                //               // Infact, all the talk of non-compressed textures having DWORD alignment of pitch
                //               // seems to be bollocks.. If I apply alignment, then they fail to load in 3rd Party
                //               // or Microsoft DDS viewing applications.
                //               //

                //#if	APPLY_PITCH_ALIGNMENT
                //               mipPitch = ( mipPitch + 3 ) & ( ~3 );
                //#endif // APPLY_PITCH_ALIGNMENT

                //               outputData = new byte[ mipPitch * writeSurface.Height ];
                //               outputData.Initialize();

                //               for( int y = 0; y < writeSurface.Height; y++ )
                //               {
                //                  for( int x = 0; x < writeSurface.Width; x++ )
                //                  {
                //                     // Get colour from surface
                //                     ColorBgra pixelColour = writeSurface.GetPoint( x, y );
                //                     uint pixelData = 0;

                //                     switch( ddsToken.m_fileFormat )
                //                     {
                //                     case DdsFileFormat.DDS_FORMAT_A8R8G8B8:
                //                        {
                //                           pixelData = ( (uint)pixelColour.A << 24 ) |
                //                                    ( (uint)pixelColour.R << 16 ) |
                //                                    ( (uint)pixelColour.G << 8 ) |
                //                                    ( (uint)pixelColour.B << 0 );
                //                           break;
                //                        }

                //                     case DdsFileFormat.DDS_FORMAT_X8R8G8B8:
                //                        {
                //                           pixelData = ( (uint)pixelColour.R << 16 ) |
                //                                    ( (uint)pixelColour.G << 8 ) |
                //                                    ( (uint)pixelColour.B << 0 );
                //                           break;
                //                        }

                //                     case DdsFileFormat.DDS_FORMAT_A8B8G8R8:
                //                        {
                //                           pixelData = ( (uint)pixelColour.A << 24 ) |
                //                                    ( (uint)pixelColour.B << 16 ) |
                //                                    ( (uint)pixelColour.G << 8 ) |
                //                                    ( (uint)pixelColour.R << 0 );
                //                           break;
                //                        }

                //                     case DdsFileFormat.DDS_FORMAT_X8B8G8R8:
                //                        {
                //                           pixelData = ( (uint)pixelColour.B << 16 ) |
                //                                    ( (uint)pixelColour.G << 8 ) |
                //                                    ( (uint)pixelColour.R << 0 );
                //                           break;
                //                        }

                //                     case DdsFileFormat.DDS_FORMAT_A1R5G5B5:
                //                        {
                //                           pixelData = ( (uint)( ( pixelColour.A != 0 ) ? 1 : 0 ) << 15 ) |
                //                                    ( (uint)( pixelColour.R >> 3 ) << 10 ) |
                //                                    ( (uint)( pixelColour.G >> 3 ) << 5 ) |
                //                                    ( (uint)( pixelColour.B >> 3 ) << 0 );
                //                           break;
                //                        }

                //                     case DdsFileFormat.DDS_FORMAT_A4R4G4B4:
                //                        {
                //                           pixelData = ( (uint)( pixelColour.A >> 4 ) << 12 ) |
                //                                    ( (uint)( pixelColour.R >> 4 ) << 8 ) |
                //                                    ( (uint)( pixelColour.G >> 4 ) << 4 ) |
                //                                    ( (uint)( pixelColour.B >> 4 ) << 0 );
                //                           break;
                //                        }

                //                     case DdsFileFormat.DDS_FORMAT_R8G8B8:
                //                        {
                //                           pixelData = ( (uint)pixelColour.R << 16 ) |
                //                                    ( (uint)pixelColour.G << 8 ) |
                //                                    ( (uint)pixelColour.B << 0 );
                //                           break;
                //                        }

                //                     case DdsFileFormat.DDS_FORMAT_R5G6B5:
                //                        {
                //                           pixelData = ( (uint)( pixelColour.R >> 3 ) << 11 ) |
                //                                    ( (uint)( pixelColour.G >> 2 ) << 5 ) |
                //                                    ( (uint)( pixelColour.B >> 3 ) << 0 );
                //                           break;
                //                        }
                //                     }

                //                     // pixelData contains our target data.. so now set the pixel bytes
                //                     int pixelOffset = ( y * mipPitch ) + ( x * pixelWidth );
                //                     for( int loop = 0; loop < pixelWidth; loop++ )
                //                     {
                //                        outputData[ pixelOffset + loop ] = (byte)( ( pixelData >> ( 8 * loop ) ) & 0xff );
                //                     }
                //                  }

                //                  if( progressCallback != null )
                //                  {
                //                     long thisMipPixelsDone = ( y + 1 ) * (long)mipWidth;
                //                     long previousMipsPixelsDone = pixelsCompleted[ mipLoop ];
                //                     double progress = (double)( (double)thisMipPixelsDone + (double)previousMipsPixelsDone ) / (double)totalPixels;
                //                     progressCallback( this, new ProgressEventArgs( 100.0 * progress ) );
                //                  }
                //               }
                //}

                // Write the data for this mip level out..
                output.Write(surface.Data, 0, surface.Data.Length);
                //output.Write( outputData, 0, outputData.GetLength( 0 ) );

                //mipWidth = mipWidth / 2;
                //mipHeight = mipHeight / 2;
            }
        }