예제 #1
0
        public static unsafe void Save(
            DDSSaveInfo info,
            TextureCollection textures,
            Stream output,
            DdsProgressCallback progressCallback)
        {
            StreamIOCallbacks streamIO  = new StreamIOCallbacks(output);
            IOCallbacks       callbacks = new IOCallbacks
            {
                Read    = streamIO.Read,
                Write   = streamIO.Write,
                Seek    = streamIO.Seek,
                GetSize = streamIO.GetSize
            };

            DDSBitmapData[] bitmapData = CreateBitmapDataArray(textures, info.arraySize, info.mipLevels);

            int hr;

            unsafe
            {
                fixed(DDSBitmapData *pBitmapData = bitmapData)
                {
                    if (IntPtr.Size == 8)
                    {
                        hr = DdsIO_x64.Save(info, pBitmapData, (uint)bitmapData.Length, callbacks, progressCallback);
                    }
                    else
                    {
                        hr = DdsIO_x86.Save(info, pBitmapData, (uint)bitmapData.Length, callbacks, progressCallback);
                    }
                }
            }

            GC.KeepAlive(streamIO);
            GC.KeepAlive(callbacks);
            GC.KeepAlive(progressCallback);

            if (FAILED(hr))
            {
                if (streamIO.CallbackExceptionInfo != null)
                {
                    streamIO.CallbackExceptionInfo.Throw();
                }
                else
                {
                    switch (hr)
                    {
                    case HResult.CanceledError:
                        throw new OperationCanceledException();

                    default:
                        Marshal.ThrowExceptionForHR(hr);
                        break;
                    }
                }
            }
        }
예제 #2
0
        private static DDSBitmapData[] CreateBitmapDataArray(TextureCollection textures, int arraySize, int mipLevels)
        {
            DDSBitmapData[] array = new DDSBitmapData[textures.Count];

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

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

                    array[index] = new DDSBitmapData(textures[index].Surface);
                }
            }

            return(array);
        }
        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));
                }
            }
        }
예제 #4
0
        public static void Save(
            IServiceProvider services,
            Document input,
            Stream output,
            DdsFileFormat format,
            DdsErrorMetric errorMetric,
            BC7CompressionMode compressionMode,
            bool cubeMap,
            bool generateMipmaps,
            ResamplingAlgorithm sampling,
            Surface scratchSurface,
            ProgressEventHandler progressCallback)
        {
            using (RenderArgs args = new RenderArgs(scratchSurface))
            {
                input.Render(args, true);
            }

            DdsNative.DdsProgressCallback ddsProgress = null;
            if (progressCallback != null)
            {
                ddsProgress = (UIntPtr done, UIntPtr total) =>
                {
                    double progress = (double)done.ToUInt64() / (double)total.ToUInt64();
                    try
                    {
                        progressCallback(null, new ProgressEventArgs(progress * 100.0, true));
                        return(true);
                    }
                    catch (OperationCanceledException)
                    {
                        return(false);
                    }
                };
            }

            int  width           = scratchSurface.Width;
            int  height          = scratchSurface.Height;
            int  arraySize       = 1;
            Size?cubeMapFaceSize = null;

            if (cubeMap && IsCrossedCubeMapSize(scratchSurface))
            {
                if (width > height)
                {
                    width  /= 4;
                    height /= 3;
                }
                else
                {
                    width  /= 3;
                    height /= 4;
                }
                arraySize       = 6;
                cubeMapFaceSize = new Size(width, height);
            }

            int  mipLevels = generateMipmaps ? GetMipCount(width, height) : 1;
            bool enableHardwareAcceleration = (bool)services.GetService <ISettingsService>().GetSetting(AppSettingPaths.UI.EnableHardwareAcceleration).Value;

            DdsNative.DDSSaveInfo info = new DdsNative.DDSSaveInfo
            {
                width                      = width,
                height                     = height,
                arraySize                  = arraySize,
                mipLevels                  = mipLevels,
                format                     = format,
                errorMetric                = errorMetric,
                compressionMode            = compressionMode,
                cubeMap                    = cubeMapFaceSize.HasValue,
                enableHardwareAcceleration = enableHardwareAcceleration
            };

            using (TextureCollection textures = GetTextures(scratchSurface, cubeMapFaceSize, mipLevels, sampling))
            {
                DdsNative.Save(info, textures, output, ddsProgress);
            }
        }
예제 #5
0
        private static TextureCollection GetTextures(Surface scratchSurface, Size?cubeMapFaceSize, int mipLevels, ResamplingAlgorithm algorithm)
        {
            TextureCollection textures     = null;
            TextureCollection tempTextures = null;

            try
            {
                tempTextures = new TextureCollection(mipLevels);

                if (cubeMapFaceSize.HasValue)
                {
                    // DirectX 10+ requires DDS cube maps to have all 6 faces.
                    tempTextures.Capacity *= 6;

                    Size    faceSize       = cubeMapFaceSize.Value;
                    Point[] cubeMapOffsets = new Point[6];

                    // Split the crossed image into the individual cube map faces.
                    //
                    // The crossed image uses the same layout as the Intel® Texture Works DDS plug-in for Adobe Photoshop®
                    // (https://github.com/GameTechDev/Intel-Texture-Works-Plugin)
                    //
                    // The DirectXTex texassemble utility and Unity® both use different layouts, so there does not appear
                    // to be any common standard for a crossed image.
                    //
                    // The cube map faces in a DDS file are always ordered: +X, -X, +Y, -Y, +Z, -Z.

                    if (scratchSurface.Width > scratchSurface.Height)
                    {
                        // A horizontal crossed image uses the following layout:
                        //
                        //		  [ +Y ]
                        //	[ -X ][ +Z ][ +X ][ -Z ]
                        //		  [ -Y ]
                        //
                        cubeMapOffsets[0] = new Point(faceSize.Width * 2, faceSize.Height);  // +X
                        cubeMapOffsets[1] = new Point(0, faceSize.Height);                   // -X
                        cubeMapOffsets[2] = new Point(faceSize.Width, 0);                    // +Y
                        cubeMapOffsets[3] = new Point(faceSize.Width, faceSize.Height * 2);  // -Y
                        cubeMapOffsets[4] = new Point(faceSize.Width, faceSize.Height);      // +Z
                        cubeMapOffsets[5] = new Point(faceSize.Width * 3, faceSize.Height);  // -Z
                    }
                    else
                    {
                        // A vertical crossed image uses the following layout:
                        //
                        //		  [ +Y ]
                        //	[ -X ][ +Z ][ +X ]
                        //		  [ -Y ]
                        //		  [ -Z ]
                        //
                        cubeMapOffsets[0] = new Point(faceSize.Width * 2, faceSize.Height);  // +X
                        cubeMapOffsets[1] = new Point(0, faceSize.Height);                   // -X
                        cubeMapOffsets[2] = new Point(faceSize.Width, 0);                    // +Y
                        cubeMapOffsets[3] = new Point(faceSize.Width, faceSize.Height * 2);  // -Y
                        cubeMapOffsets[4] = new Point(faceSize.Width, faceSize.Height);      // +Z
                        cubeMapOffsets[5] = new Point(faceSize.Width, faceSize.Height * 3);  // -Z
                    }

                    for (int i = 0; i < 6; ++i)
                    {
                        Point srcStartOffset = cubeMapOffsets[i];

                        tempTextures.Add(new Texture(scratchSurface.CreateWindow(srcStartOffset.X, srcStartOffset.Y, faceSize.Width, faceSize.Height), true));

                        if (mipLevels > 1)
                        {
                            Surface cubeMapSurface = tempTextures[tempTextures.Count - 1].Surface;

                            for (int j = 1; j < mipLevels; ++j)
                            {
                                int mipWidth  = Math.Max(1, cubeMapSurface.Width >> j);
                                int mipHeight = Math.Max(1, cubeMapSurface.Height >> j);

                                tempTextures.Add(CreateMipTexture(cubeMapSurface, mipWidth, mipHeight, algorithm));
                            }
                        }
                    }
                }
                else
                {
                    tempTextures.Add(new Texture(scratchSurface, false));

                    if (mipLevels > 1)
                    {
                        for (int j = 1; j < mipLevels; ++j)
                        {
                            int mipWidth  = Math.Max(1, scratchSurface.Width >> j);
                            int mipHeight = Math.Max(1, scratchSurface.Height >> j);

                            tempTextures.Add(CreateMipTexture(scratchSurface, mipWidth, mipHeight, algorithm));
                        }
                    }
                }

                textures     = tempTextures;
                tempTextures = null;
            }
            finally
            {
                if (tempTextures != null)
                {
                    tempTextures.Dispose();
                }
            }

            return(textures);
        }
예제 #6
0
        public static unsafe void Save(
            DDSSaveInfo info,
            TextureCollection textures,
            Stream output,
            DdsProgressCallback progressCallback)
        {
            StreamIOCallbacks streamIO  = new StreamIOCallbacks(output);
            IOCallbacks       callbacks = new IOCallbacks
            {
                Read    = streamIO.Read,
                Write   = streamIO.Write,
                Seek    = streamIO.Seek,
                GetSize = streamIO.GetSize
            };

            DDSBitmapData[] bitmapData = CreateBitmapDataArray(textures, info.arraySize, info.mipLevels);

            int hr;

            unsafe
            {
                fixed(DDSBitmapData *pBitmapData = bitmapData)
                {
#if NET47
                    if (IntPtr.Size == 8)
#else
                    if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
#endif
                    {
                        hr = DdsIO_x64.Save(info, pBitmapData, (uint)bitmapData.Length, callbacks, progressCallback);
                    }
#if NET47
                    else if (IntPtr.Size == 4)
#else
                    else if (RuntimeInformation.ProcessArchitecture == Architecture.X86)
#endif
                    {
                        hr = DdsIO_x86.Save(info, pBitmapData, (uint)bitmapData.Length, callbacks, progressCallback);
                    }
                    else
                    {
                        throw new PlatformNotSupportedException();
                    }
                }
            }

            GC.KeepAlive(streamIO);
            GC.KeepAlive(callbacks);
            GC.KeepAlive(progressCallback);

            if (FAILED(hr))
            {
                if (streamIO.CallbackExceptionInfo != null)
                {
                    streamIO.CallbackExceptionInfo.Throw();
                }
                else
                {
                    switch (hr)
                    {
                    case HResult.CanceledError:
                        throw new OperationCanceledException();

                    case HResult.UnknownDdsSaveFormat:
                        throw new InvalidOperationException("The DDSFileFormat value does not map to a DXGI format.");

                    default:
                        Marshal.ThrowExceptionForHR(hr);
                        break;
                    }
                }
            }
        }