internal static void CompressBC2Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting)
        {
            // Compress Alpha
            if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
            {
                // No alpha so fill with opaque alpha - has to be an alpha value, so make it so RGB is 100% visible.
                for (int i = 0; i < 8; i++)
                    destination[destPosition + i] = 0xFF;
            }
            else
            {
                int position = sourcePosition + 3;  // Only want to read alphas
                for (int i = 0; i < 8; i += 2)
                {
                    destination[destPosition + i] = (byte)((imgData[position] & 0xF0) | (imgData[position + 4] >> 4));
                    destination[destPosition + i + 1] = (byte)((imgData[position + 8] & 0xF0) | (imgData[position + 12] >> 4));

                    position += sourceLineLength;
                }
            }
            

            // Compress Colour
            CompressRGBTexel(imgData, sourcePosition, sourceLineLength, destination, destPosition + 8, false, 0f, alphaSetting);
        }
Example #2
0
        public AlphaPanel(AlphaSettings settings)
        {
            InitializeComponent();

            string stretchtttxt = "Using stretch stretches alpha values to the range [0,255].\n"
                                + "The given minimum value will be mapped onto 0 (transparent),\n"
                                + "the given maximum value onto 255 (opaque).";
            this.stretch_tt.SetToolTip(this.stretch_group,  stretchtttxt);
            this.stretch_tt.SetToolTip(this.strech_enable, stretchtttxt);
            this.stretch_tt.SetToolTip(this.min_box, stretchtttxt);
            this.stretch_tt.SetToolTip(this.min_label, stretchtttxt);
            this.stretch_tt.SetToolTip(this.max_box, stretchtttxt);
            this.stretch_tt.SetToolTip(this.max_label, stretchtttxt);

            this.settings = settings;


            // set location
            switch (settings.Location)
            {
                case AlphaLocation.START: start_radio.Checked = true; break;
                case AlphaLocation.END: end_radio.Checked = true; break;
            }

            // set stretch
            this.strech_enable.Checked = settings.Stretch;
            this.min_box.Text = settings.Minimum + "";
            this.max_box.Text = settings.Maximum + "";

            // set ignore
            this.ignore_check.Checked = settings.IgnoreAlpha;
        }
Example #3
0
        public AlphaPanel(AlphaSettings settings)
        {
            InitializeComponent();

            string stretchtttxt = "Using stretch stretches alpha values to the range [0,255].\n"
                                  + "The given minimum value will be mapped onto 0 (transparent),\n"
                                  + "the given maximum value onto 255 (opaque).";

            this.stretch_tt.SetToolTip(this.stretch_group, stretchtttxt);
            this.stretch_tt.SetToolTip(this.strech_enable, stretchtttxt);
            this.stretch_tt.SetToolTip(this.min_box, stretchtttxt);
            this.stretch_tt.SetToolTip(this.min_label, stretchtttxt);
            this.stretch_tt.SetToolTip(this.max_box, stretchtttxt);
            this.stretch_tt.SetToolTip(this.max_label, stretchtttxt);

            this.settings = settings;


            // set location
            switch (settings.Location)
            {
            case AlphaLocation.START: start_radio.Checked = true; break;

            case AlphaLocation.END: end_radio.Checked = true; break;
            }

            // set stretch
            this.strech_enable.Checked = settings.Stretch;
            this.min_box.Text          = settings.Minimum + "";
            this.max_box.Text          = settings.Maximum + "";

            // set ignore
            this.ignore_check.Checked = settings.IgnoreAlpha;
        }
        /// <summary>
        /// Saves fully formatted image in specified format to byte array.
        /// </summary>
        /// <param name="destFormatDetails">Details about destination format.</param>
        /// <param name="GenerateMips">Determines how mipmaps are handled during saving.</param>
        /// <param name="desiredMaxDimension">Maximum size for saved image. Resizes if required, but uses mipmaps if available.</param>
        /// <param name="mipToSave">Index of mipmap to save directly.</param>
        /// <param name="removeAlpha">True = Alpha removed. False = Uses threshold value and alpha values to mask RGB FOR DXT1, otherwise completely removed.</param>
        /// <returns></returns>
        public byte[] Save(ImageFormats.ImageEngineFormatDetails destFormatDetails, MipHandling GenerateMips, int desiredMaxDimension = 0, int mipToSave = 0, bool removeAlpha = true)
        {
            if (destFormatDetails.Format == ImageEngineFormat.Unknown)
            {
                throw new InvalidOperationException("Save format cannot be 'Unknown'");
            }

            AlphaSettings alphaSetting = AlphaSettings.KeepAlpha;

            if (removeAlpha)
            {
                alphaSetting = AlphaSettings.RemoveAlphaChannel;
            }
            else if (destFormatDetails.Format == ImageEngineFormat.DDS_DXT2 || destFormatDetails.Format == ImageEngineFormat.DDS_DXT4)
            {
                alphaSetting = AlphaSettings.Premultiply;
            }

            // If same format and stuff, can just return original data, or chunks of it.
            if (destFormatDetails.Format == Format)
            {
                return(AttemptSaveUsingOriginalData(destFormatDetails, GenerateMips, desiredMaxDimension, mipToSave, alphaSetting));
            }
            else
            {
                return(ImageEngine.Save(MipMaps, destFormatDetails, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave));
            }
        }
        // ATI2 3Dc
        internal static void CompressBC5Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting)
        {
            // Green: Channel 1.
            Compress8BitBlock(imgData, sourcePosition, sourceLineLength, destination, destPosition, 1, false);

            // Red: Channel 2, 8 destination offset to be after Green.
            Compress8BitBlock(imgData, sourcePosition, sourceLineLength, destination, destPosition + 8, 2, false);
        }
Example #6
0
        /// <summary>
        /// Generates alpha server settings
        /// </summary>
        /// <returns>Settings object</returns>
        public static AlphaSettings GetAlphaSettings()
        {
            var settings = new AlphaSettings();

            SetCommonSettings(settings, TestEnvironment.AlphaKeyPair.SecretSeed);
            settings.ConnectionString = "mongodb://localhost:27001/alphaDBTest?replicaSet=centaurus";
            settings.Build();
            return(settings);
        }
        public void Setup()
        {
            EnvironmentHelper.SetTestEnvironmentVariable();
            var settings = new AlphaSettings
            {
                CWD = "AppData"
            };

            Global.Setup(settings, new MongoStorage()).Wait();
        }
        public void Setup()
        {
            EnvironmentHelper.SetTestEnvironmentVariable();
            var settings = new AlphaSettings
            {
                CWD = "AppData"
            };
            var stellarProvider = new MockStellarDataProvider(settings.NetworkPassphrase, settings.HorizonUrl);

            context = new AlphaContext(settings, new MongoStorage(), stellarProvider);

            context.Init().Wait();
        }
Example #9
0
        static int WriteCompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, int blockSize, Action <byte[], int, int, byte[], int, AlphaSettings, ImageFormats.ImageEngineFormatDetails> compressor,
                                         AlphaSettings alphaSetting)
        {
            if (mipmap.Width < 4 || mipmap.Height < 4)
            {
                return(-1);
            }

            int destinationTexelCount = mipmap.Width * mipmap.Height / 16;
            int sourceLineLength      = mipmap.Width * 4 * mipmap.LoadedFormatDetails.ComponentSize;
            int numTexelsInLine       = mipmap.Width / 4;

            var mipWriter = new Action <int>(texelIndex =>
            {
                // Since this is the top corner of the first texel in a line, skip 4 pixel rows (texel = 4x4 pixels) and the number of rows down the bitmap we are already.
                int sourceLineOffset = sourceLineLength * 4 * (texelIndex / numTexelsInLine);                                                  // Length in bytes x 3 lines x texel line index (how many texel sized lines down the image are we). Index / width will truncate, so for the first texel line, it'll be < 0. For the second texel line, it'll be < 1 and > 0.

                int sourceTopLeftCorner = ((texelIndex % numTexelsInLine) * 16) * mipmap.LoadedFormatDetails.ComponentSize + sourceLineOffset; // *16 since its 4 pixels with 4 channels each. Index % numTexels will effectively reset each line.
                compressor(mipmap.Pixels, sourceTopLeftCorner, sourceLineLength, destination, mipOffset + texelIndex * blockSize, alphaSetting, mipmap.LoadedFormatDetails);
            });

            // Choose an acceleration method.
            if (ImageEngine.EnableThreading)
            {
                Parallel.For(0, destinationTexelCount, new ParallelOptions {
                    MaxDegreeOfParallelism = ImageEngine.NumThreads
                }, (mip, loopState) =>
                {
                    if (ImageEngine.IsCancellationRequested)
                    {
                        loopState.Stop();
                    }

                    mipWriter(mip);
                });
            }
            else
            {
                for (int i = 0; i < destinationTexelCount; i++)
                {
                    if (ImageEngine.IsCancellationRequested)
                    {
                        break;
                    }

                    mipWriter(i);
                }
            }

            return(mipOffset + destinationTexelCount * blockSize);
        }
Example #10
0
        internal static void CompressBC3Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting)
        {
            // Compress Alpha
            if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
            {
                // No alpha so fill with opaque alpha - has to be an alpha value, so make it so RGB is 100% visible.
                for (int i = 0; i < 8; i++)
                    destination[destPosition + i] = 0xFF;
            }
            else
                Compress8BitBlock(imgData, sourcePosition, sourceLineLength, destination, destPosition, 3, false);

            // Compress Colour
            CompressRGBTexel(imgData, sourcePosition, sourceLineLength, destination, destPosition + 8, false, 0f, alphaSetting);
        }
Example #11
0
        private AlphaSettings GetAlphaSettings()
        {
            var kp            = KeyPair.Random();
            var alphaSettings = new AlphaSettings
            {
                AlphaPort         = 5000,
                HorizonUrl        = HorizonUrl,
                NetworkPassphrase = NetworkPassphrase,
                Secret            = kp.SecretSeed,
                SyncBatchSize     = 500
            };

            alphaSettings.Build();
            return(alphaSettings);
        }
Example #12
0
        private void SetupCertificate(AlphaSettings alphaSettings)
        {
            if (alphaSettings.TlsCertificatePath == null)
            {
                return;
            }

            if (!File.Exists(alphaSettings.TlsCertificatePath))
            {
                throw new FileNotFoundException($"Failed to find a certificate \"{alphaSettings.TlsCertificatePath}\"");
            }

            UpdateCertificate(alphaSettings.TlsCertificatePath, alphaSettings.TlsCertificatePrivateKeyPath);

            ObserveCertificateChange(alphaSettings.TlsCertificatePath, alphaSettings.TlsCertificatePrivateKeyPath);
        }
Example #13
0
        public IHost CreateHost(AlphaSettings settings)
        {
            SetupCertificate(settings);
            return(Host.CreateDefaultBuilder()
                   .ConfigureLogging(logging =>
            {
                logging.ClearProviders();
                logging.AddConsole();

                if (settings.Verbose)
                {
                    logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                }
                else if (settings.Silent)
                {
                    logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Error);
                }
                else
                {
                    logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Information);
                }
            })
                   .UseNLog()
                   .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.ConfigureServices(s => s.AddSingleton(Context))
                .UseStartup <HostStartup>()
                .UseKestrel(options =>
                {
                    if (Certificate != null)
                    {
                        options.ListenAnyIP(settings.AlphaPort,
                                            listenOptions =>
                        {
                            var httpsOptions = new HttpsConnectionAdapterOptions();
                            httpsOptions.ServerCertificateSelector = (context, path) => Certificate;
                            listenOptions.UseHttps(httpsOptions);
                        });
                    }
                    else
                    {
                        options.ListenAnyIP(settings.AlphaPort);
                    }
                });
            }).Build());
        }
Example #14
0
        static void Client()
        {
            MessageHandlers.Init();

            var settings = new AlphaSettings
            {
                HorizonUrl        = "https://horizon-testnet.stellar.org",
                NetworkPassphrase = "Test SDF Network ; September 2015"
            };

            Global.Init(settings, new MongoStorage());

            UserWebSocketConnection ws = new UserWebSocketConnection(null);

            ws.EstablishConnection().Wait();

            Console.WriteLine("Type 'q' to close...");
            Console.WriteLine("Place order format: po {order-direction} {amount (will be multiplied by 10 000 000)} {price}");
            Console.WriteLine("Example: po 0 1 2");

            while (true)
            {
                try
                {
                    var line = Console.ReadLine();
                    if (line == "q")
                    {
                        break;
                    }

                    if (line.IndexOf("po") == 0)
                    {
                        var poArgs = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
                        var res    = ws.PlaceOrder(int.Parse(poArgs[1]), long.Parse(poArgs[2]) * 10_000_000, double.Parse(poArgs[3])).Result;
                        Console.WriteLine(res.Status.ToString());
                    }
                }
                catch (Exception exc)
                {
                    Console.WriteLine(exc);
                }
            }
        }
        public void Setup()
        {
            var dbName     = "testDB";
            var replicaSet = "centaurusTest";
            var dbPort     = 27001;

            MongoDBServerHelper.RunMongoDBServers(new int[] { dbPort }, replicaSet);

            var extensionsPath = ExtensionConfigGenerator.Generate(dbPort, dbName, replicaSet, banPeriod, boostFactor);

            var settings = new AlphaSettings();

            settings.ExtensionsConfigFilePath = Path.GetFullPath(extensionsPath);
            settings.ConnectionString         = $"mongodb://localhost:{dbPort}/{dbName}?replicaSet={replicaSet}";
            settings.HorizonUrl        = "https://horizon-testnet.stellar.org";
            settings.NetworkPassphrase = "Test SDF Network ; September 2015";
            settings.CWD    = "AppData";
            settings.Secret = TestEnvironment.AlphaKeyPair.SecretSeed;

            settings.Build();

            GlobalInitHelper.Setup(GlobalInitHelper.GetPredefinedClients(), GlobalInitHelper.GetPredefinedAuditors(), settings, new MongoStorage());
        }
        public void Setup()
        {
            EnvironmentHelper.SetTestEnvironmentVariable();
            var settings = new AlphaSettings
            {
                HorizonUrl        = "https://horizon-testnet.stellar.org",
                NetworkPassphrase = "Test SDF Network ; September 2015",
                CWD = "AppData"
            };

            var stellarProvider = new MockStellarDataProvider(settings.NetworkPassphrase, settings.HorizonUrl);

            context = new AlphaContext(settings, new MockStorage(), stellarProvider);
            context.Init().Wait();
            var requestsLimit = new RequestRateLimits();

            account1 = new AccountWrapper(new Models.Account
            {
                Id     = 1,
                Pubkey = new RawPubKey()
                {
                    Data = KeyPair.Random().PublicKey
                },
                Balances = new List <Balance>()
            }, requestsLimit);

            account1.Account.CreateBalance(0);
            account1.Account.GetBalance(0).UpdateBalance(10000000000);

            account1.Account.CreateBalance(1);
            account1.Account.GetBalance(1).UpdateBalance(10000000000);

            account2 = new AccountWrapper(new Models.Account
            {
                Id     = 2,
                Pubkey = new RawPubKey()
                {
                    Data = KeyPair.Random().PublicKey
                },
                Balances = new List <Balance>()
            }, requestsLimit);

            account2.Account.CreateBalance(0);
            account2.Account.GetBalance(0).UpdateBalance(10000000000);

            account2.Account.CreateBalance(1);
            account2.Account.GetBalance(1).UpdateBalance(10000000000);
            context.Setup(new Snapshot
            {
                Accounts = new List <AccountWrapper> {
                    account1, account2
                },
                Apex     = 0,
                TxCursor = 1,
                Orders   = new List <Order>(),
                Settings = new ConstellationSettings
                {
                    Vault  = KeyPair.Random().PublicKey,
                    Assets = new List <AssetSettings> {
                        new AssetSettings {
                            Id = 1, Code = "X", Issuer = new RawPubKey()
                        }
                    },
                    RequestRateLimits = new RequestRateLimits {
                        HourLimit = 1000, MinuteLimit = 100
                    }
                },
            }).Wait();
        }
Example #17
0
 // ATI1
 internal static void CompressBC4Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting)
 {
     Compress8BitBlock(imgData, sourcePosition, sourceLineLength, destination, destPosition, 2, false);
 }
Example #18
0
        internal static byte[] Save(List<MipMap> mipMaps, ImageEngineFormat saveFormat, AlphaSettings alphaSetting, List<uint> customMasks = null)
        {
            // Set compressor for Block Compressed textures
            Action<byte[], int, int, byte[], int, AlphaSettings> compressor = null;

            bool needCheckSize = saveFormat.ToString().Contains("DXT") || saveFormat.ToString().Contains("ATI");

            switch (saveFormat)
            {
                case ImageEngineFormat.DDS_ATI1:
                    compressor = DDS_Encoders.CompressBC4Block;
                    break;
                case ImageEngineFormat.DDS_ATI2_3Dc:
                    compressor = DDS_Encoders.CompressBC5Block;
                    break;
                case ImageEngineFormat.DDS_DX10:
                    Debugger.Break();
                    break; // TODO: NOT SUPPORTED YET. DX10
                case ImageEngineFormat.DDS_DXT1:
                    compressor = DDS_Encoders.CompressBC1Block;
                    break;
                case ImageEngineFormat.DDS_DXT2:
                case ImageEngineFormat.DDS_DXT3:
                    compressor = DDS_Encoders.CompressBC2Block;
                    break;
                case ImageEngineFormat.DDS_DXT4:
                case ImageEngineFormat.DDS_DXT5:
                    compressor = DDS_Encoders.CompressBC3Block;
                    break;
            }

            int height = mipMaps[0].Height;
            int width = mipMaps[0].Width;

            if (needCheckSize && !CheckSize_DXT(width, height))
                throw new InvalidOperationException($"DXT compression formats require dimensions to be multiples of 4. Got: {width}x{height}.");

            int fullSize = GetCompressedSizeOfImage(mipMaps.Count, saveFormat, width, height);
            // +1 to get the full size, not just the offset of the last mip.
            //int fullSize = GetMipOffset(mipMaps.Count + 1, saveFormat, mipMaps[0].Width, mipMaps[0].Height);

            byte[] destination = new byte[fullSize];

            // Create header and write to destination
            DDS_Header header = new DDS_Header(mipMaps.Count, height, width, saveFormat, customMasks);
            header.WriteToArray(destination, 0);

            int blockSize = ImageFormats.GetBlockSize(saveFormat);

            if (ImageFormats.IsBlockCompressed(saveFormat))
            {
                int mipOffset = 128;
                foreach (MipMap mipmap in mipMaps)
                    mipOffset = WriteCompressedMipMap(destination, mipOffset, mipmap, blockSize, compressor, alphaSetting);
            }
            else
            {
                // UNCOMPRESSED
                var action = new Action<int>(mipIndex =>
                {
                    if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
                    {
                        // Remove alpha by setting AMask = 0
                        var ddspf = header.ddspf;
                        ddspf.dwABitMask = 0;
                        header.ddspf = ddspf;
                    }

                    // Get MipOffset
                    int offset = GetMipOffset(mipIndex, saveFormat, width, height);

                    WriteUncompressedMipMap(destination, offset, mipMaps[mipIndex], saveFormat, header.ddspf);
                });

                if (ImageEngine.EnableThreading)
                    Parallel.For(0, mipMaps.Count, new ParallelOptions { MaxDegreeOfParallelism = ImageEngine.NumThreads }, action);
                else
                    for (int i = 0; i < mipMaps.Count; i++)
                        action(i);
            }

            return destination;
        }
Example #19
0
        public void Setup()
        {
            EnvironmentHelper.SetTestEnvironmentVariable();
            var settings = new AlphaSettings
            {
                HorizonUrl        = "https://horizon-testnet.stellar.org",
                NetworkPassphrase = "Test SDF Network ; September 2015",
                CWD = "AppData"
            };

            Global.Setup(settings, new MockStorage()).Wait();

            var account1 = new Models.Account()
            {
                Id     = 1,
                Pubkey = new RawPubKey()
                {
                    Data = KeyPair.Random().PublicKey
                },
                Balances = new List <Balance>()
            };

            account1.CreateBalance(0);
            account1.GetBalance(0).UpdateBalance(10000000000);
            account1.CreateBalance(1);
            account1.GetBalance(1).UpdateBalance(10000000000);

            var account2 = new Models.Account()
            {
                Id     = 2,
                Pubkey = new RawPubKey()
                {
                    Data = KeyPair.Random().PublicKey
                },
                Balances = new List <Balance>()
            };

            account2.CreateBalance(0);
            account2.GetBalance(0).UpdateBalance(10000000000);
            account2.CreateBalance(1);
            account2.GetBalance(1).UpdateBalance(10000000000);

            Global.Setup(new Snapshot
            {
                Accounts = new List <Models.Account> {
                    account1, account2
                },
                Apex     = 0,
                TxCursor = 1,
                Orders   = new List <Order>(),
                Settings = new ConstellationSettings
                {
                    Vault  = KeyPair.Random().PublicKey,
                    Assets = new List <AssetSettings> {
                        new AssetSettings {
                            Id = 1, Code = "X", Issuer = new RawPubKey()
                        }
                    },
                    RequestRateLimits = new RequestRateLimits {
                        HourLimit = 1000, MinuteLimit = 100
                    }
                },
            }).Wait();

            this.account1 = Global.AccountStorage.GetAccount(account1.Id);
            this.account2 = Global.AccountStorage.GetAccount(account2.Id);
        }
Example #20
0
 // ATI1
 internal static void CompressBC4Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting, DDSFormatDetails formatDetails)
 {
     Compress8BitBlock(imgData, sourcePosition, sourceLineLength, destination, destPosition, 2, false, formatDetails);
 }
        internal static void CompressBC3Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting, ImageFormats.ImageEngineFormatDetails formatDetails)
        {
            // Compress Alpha
            if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
            {
                // No alpha so fill with opaque alpha - has to be an alpha value, so make it so RGB is 100% visible.
                for (int i = 0; i < 8; i++)
                {
                    destination[destPosition + i] = 0xFF;
                }
            }
            else
            {
                Compress8BitBlock(imgData, sourcePosition, sourceLineLength, destination, destPosition, 3, false, formatDetails);
            }

            // Compress Colour
            CompressRGBTexel(imgData, sourcePosition, sourceLineLength, destination, destPosition + 8, false, 0f, alphaSetting, formatDetails);
        }
        internal static void CompressRGBTexel(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, bool isDXT1, double alphaRef, AlphaSettings alphaSetting, DDSFormatDetails formatDetails)
        {
            int uSteps = 4;

            bool premultiply = alphaSetting == AlphaSettings.Premultiply;

            // Read texel
            RGBColor[] sourceTexel = new RGBColor[16];
            int        position    = sourcePosition;
            int        count       = 0;

            for (int i = 1; i <= 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    sourceTexel[count++] = ReadColorFromTexel(imgData, position, premultiply, formatDetails);
                    position            += 4 * formatDetails.ComponentSize;
                }

                position = sourcePosition + sourceLineLength * i;
            }


            // TODO replace RGBColor with a SIMD vector for speed. Test difference between vector4 and vector<T>, might not be better.

            // Determine if texel is fully and entirely transparent. If so, can set to white and continue.
            if (isDXT1)
            {
                uSteps = CheckDXT1TexelFullTransparency(sourceTexel, destination, destPosition, alphaRef);
                if (uSteps == -1)
                {
                    return;
                }
            }

            RGBColor[] Color = new RGBColor[16];

            // Some kind of color adjustment. Not sure what it does, especially if it wasn't dithering...
            DoColorFixErrorCorrection(Color, sourceTexel);


            // Palette colors
            RGBColor ColorA, ColorB, ColorC, ColorD;

            ColorA = new RGBColor();
            ColorB = new RGBColor();
            ColorC = new RGBColor();
            ColorD = new RGBColor();

            // OPTIMISER
            RGBColor[] minmax = OptimiseRGB(Color, uSteps);
            ColorA = minmax[0];
            ColorB = minmax[1];

            // Create interstitial colors?
            ColorC.r = ColorA.r * LuminanceInv.r;
            ColorC.g = ColorA.g * LuminanceInv.g;
            ColorC.b = ColorA.b * LuminanceInv.b;

            ColorD.r = ColorB.r * LuminanceInv.r;
            ColorD.g = ColorB.g * LuminanceInv.g;
            ColorD.b = ColorB.b * LuminanceInv.b;


            // Yeah...dunno
            uint wColorA = Encode565(ColorC);
            uint wColorB = Encode565(ColorD);

            // Min max are equal - only interpolate 4 interstitial colors
            if (uSteps == 4 && wColorA == wColorB)
            {
                var c2 = BitConverter.GetBytes(wColorA);
                var c1 = BitConverter.GetBytes(wColorB);  ///////////////////// MIN MAX

                destination[destPosition]     = c2[0];
                destination[destPosition + 1] = c2[1];

                destination[destPosition + 2] = c1[0];
                destination[destPosition + 3] = c1[1];
                return;
            }

            // Interpolate 6 colors or something
            ColorC = Decode565(wColorA);
            ColorD = Decode565(wColorB);

            ColorA.r = ColorC.r * Luminance.r;
            ColorA.g = ColorC.g * Luminance.g;
            ColorA.b = ColorC.b * Luminance.b;

            ColorB.r = ColorD.r * Luminance.r;
            ColorB.g = ColorD.g * Luminance.g;
            ColorB.b = ColorD.b * Luminance.b;


            var step = DoSomethingWithPalette(uSteps, wColorA, wColorB, ColorA, ColorB);

            // Calculating color direction apparently
            RGBColor Dir = new RGBColor()
            {
                r = step[1].r - step[0].r,
                g = step[1].g - step[0].g,
                b = step[1].b - step[0].b
            };
            float fscale = (wColorA != wColorB) ? ((uSteps - 1) / (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b)) : 0.0f;

            Dir.r *= fscale;
            Dir.g *= fscale;
            Dir.b *= fscale;

            // Encoding colors apparently
            uint dw = DoOtherColorFixErrorCorrection(sourceTexel, uSteps, alphaRef, step, Dir);

            uint Min = (uSteps == 3) == (wColorA <= wColorB) ? wColorA : wColorB;
            uint Max = (uSteps == 3) == (wColorA <= wColorB) ? wColorB : wColorA;

            var color1 = BitConverter.GetBytes(Min);
            var color2 = BitConverter.GetBytes(Max);

            destination[destPosition]     = color1[0];
            destination[destPosition + 1] = color1[1];

            destination[destPosition + 2] = color2[0];
            destination[destPosition + 3] = color2[1];

            var indicies = BitConverter.GetBytes(dw);

            destination[destPosition + 4] = indicies[0];
            destination[destPosition + 5] = indicies[1];
            destination[destPosition + 6] = indicies[2];
            destination[destPosition + 7] = indicies[3];
        }
        /// <summary>
        /// Not exactly sure what this does or why.
        /// </summary>
        static void DoColourFixErrorCorrection(RGBColour[] Colour, byte[] imgData, int sourcePosition, int sourceLineLength, AlphaSettings alphaSetting)
        {
            RGBColour[] Error = new RGBColour[16];
            for (int i = 0; i < 4; i++)
            {
                int position = sourcePosition + sourceLineLength * i;

                for (int j = 0; j < 4; j++)
                {
                    int index = (i << 2) + j;
                    RGBColour current = ReadColourFromTexel(imgData, position, alphaSetting == AlphaSettings.Premultiply);

                    if (true)  // Dither
                    {
                        // Adjust for accumulated error
                        // This works by figuring out the error between the current pixel colour and the adjusted colour? Dunno what the adjustment is. Looks like a 5:6:5 range adaptation
                        // Then, this error is distributed across the "next" few pixels and not the previous.
                        current.r += Error[index].r;
                        current.g += Error[index].g;
                        current.b += Error[index].b;
                    }

                    // 5:6:5 range adaptation?
                    Colour[index].r = (int)(current.r * 31f + .5f) * (1f / 31f);
                    Colour[index].g = (int)(current.g * 63f + .5f) * (1f / 63f);
                    Colour[index].b = (int)(current.b * 31f + .5f) * (1f / 31f);

                    DoSomeDithering(current, index, Colour, index, Error);

                    Colour[index].r *= Luminance.r;
                    Colour[index].g *= Luminance.g;
                    Colour[index].b *= Luminance.b;

                    position += 4;
                }
            }
        }
        internal static void CompressRGBTexel(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, bool isDXT1, double alphaRef, AlphaSettings alphaSetting)
        {
            int uSteps = 4;

            // Determine if texel is fully and entirely transparent. If so, can set to white and continue.
            if (isDXT1)
            {
                uSteps = CheckDXT1TexelFullTransparency(imgData, sourcePosition, sourceLineLength, destination, destPosition, alphaSetting, alphaRef);
                if (uSteps == -1)
                    return;
            }

            RGBColour[] Colour = new RGBColour[16];

            // Some kind of colour adjustment. Not sure what it does, especially if it wasn't dithering...
            DoColourFixErrorCorrection(Colour, imgData, sourcePosition, sourceLineLength, alphaSetting);

            // Palette colours
            RGBColour ColourA, ColourB, ColourC, ColourD;
            ColourA = new RGBColour();
            ColourB = new RGBColour();
            ColourC = new RGBColour();
            ColourD = new RGBColour();

            // OPTIMISER
            RGBColour[] minmax = OptimiseRGB(Colour, uSteps);
            ColourA = minmax[0];
            ColourB = minmax[1];

            // Create interstitial colours?
            ColourC.r = ColourA.r * LuminanceInv.r;
            ColourC.g = ColourA.g * LuminanceInv.g;
            ColourC.b = ColourA.b * LuminanceInv.b;

            ColourD.r = ColourB.r * LuminanceInv.r;
            ColourD.g = ColourB.g * LuminanceInv.g;
            ColourD.b = ColourB.b * LuminanceInv.b;

            // Yeah...dunno
            uint wColourA = Encode565(ColourC);
            uint wColourB = Encode565(ColourD);

            // Min max are equal - only interpolate 4 interstitial colours
            if (uSteps == 4 && wColourA == wColourB)
            {
                var c2 = BitConverter.GetBytes(wColourA);
                var c1 = BitConverter.GetBytes(wColourB);  ///////////////////// MIN MAX

                destination[destPosition] = c2[0];
                destination[destPosition + 1] = c2[1];

                destination[destPosition + 2] = c1[0];
                destination[destPosition + 3] = c1[1];
                return;
            }

            // Interpolate 6 colours or something
            ColourC = Decode565(wColourA);
            ColourD = Decode565(wColourB);

            ColourA.r = ColourC.r * Luminance.r;
            ColourA.g = ColourC.g * Luminance.g;
            ColourA.b = ColourC.b * Luminance.b;

            ColourB.r = ColourD.r * Luminance.r;
            ColourB.g = ColourD.g * Luminance.g;
            ColourB.b = ColourD.b * Luminance.b;

            var step = DoSomethingWithPalette(uSteps, wColourA, wColourB, ColourA, ColourB);

            // Calculating colour direction apparently
            RGBColour Dir = new RGBColour()
            {
                r = step[1].r - step[0].r,
                g = step[1].g - step[0].g,
                b = step[1].b - step[0].b
            };
            float fscale = (wColourA != wColourB) ? ((uSteps - 1) / (Dir.r * Dir.r + Dir.g * Dir.g + Dir.b * Dir.b)) : 0.0f;
            Dir.r *= fscale;
            Dir.g *= fscale;
            Dir.b *= fscale;

            // Encoding colours apparently
            uint dw = DoOtherColourFixErrorCorrection(imgData, sourcePosition, sourceLineLength, uSteps, alphaRef, alphaSetting, step, Dir);

            uint Min = (uSteps == 3) == (wColourA <= wColourB) ? wColourA : wColourB;
            uint Max = (uSteps == 3) == (wColourA <= wColourB) ? wColourB : wColourA;

            var colour1 = BitConverter.GetBytes(Min);
            var colour2 = BitConverter.GetBytes(Max);

            destination[destPosition] = colour1[0];
            destination[destPosition + 1] = colour1[1];

            destination[destPosition + 2] = colour2[0];
            destination[destPosition + 3] = colour2[1];

            var indicies = BitConverter.GetBytes(dw);
            destination[destPosition + 4] = indicies[0];
            destination[destPosition + 5] = indicies[1];
            destination[destPosition + 6] = indicies[2];
            destination[destPosition + 7] = indicies[3];
        }
 internal static void CompressBC7Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting, ImageFormats.ImageEngineFormatDetails formatDetails)
 {
     BC7.CompressBC7Block(imgData, sourcePosition, sourceLineLength, destination, destPosition);
 }
 internal static void CompressBC1Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting, ImageFormats.ImageEngineFormatDetails formatDetails)
 {
     CompressRGBTexel(imgData, sourcePosition, sourceLineLength, destination, destPosition, true, (alphaSetting == AlphaSettings.RemoveAlphaChannel ? 0 : DXT1AlphaThreshold), alphaSetting, formatDetails);
 }
Example #27
0
        internal static byte[] Save(List <MipMap> mipMaps, ImageFormats.ImageEngineFormatDetails destFormatDetails, AlphaSettings alphaSetting)
        {
            // Set compressor for Block Compressed textures
            Action <byte[], int, int, byte[], int, AlphaSettings, ImageFormats.ImageEngineFormatDetails> compressor = destFormatDetails.BlockEncoder;

            bool needCheckSize = destFormatDetails.IsBlockCompressed;

            int height = mipMaps[0].Height;
            int width  = mipMaps[0].Width;

            if (needCheckSize && !CheckSize_DXT(width, height))
            {
                throw new InvalidOperationException($"DXT compression formats require dimensions to be multiples of 4. Got: {width}x{height}.");
            }

            // Create header and write to destination
            DDS_Header header = new DDS_Header(mipMaps.Count, height, width, destFormatDetails.Format, destFormatDetails.DX10Format);

            int headerLength = destFormatDetails.HeaderSize;

            int fullSize = GetCompressedSizeOfImage(mipMaps.Count, destFormatDetails, width, height);

            /*if (destFormatDetails.ComponentSize != 1)
             *  fullSize += (fullSize - headerLength) * destFormatDetails.ComponentSize;*/// Size adjustment for destination to allow for different component sizes.

            byte[] destination = new byte[fullSize];
            header.WriteToArray(destination, 0);

            int blockSize = destFormatDetails.BlockSize;

            if (destFormatDetails.IsBlockCompressed)
            {
                int mipOffset = headerLength;
                foreach (MipMap mipmap in mipMaps)
                {
                    if (ImageEngine.IsCancellationRequested)
                    {
                        break;
                    }

                    var temp = WriteCompressedMipMap(destination, mipOffset, mipmap, blockSize, compressor, alphaSetting);
                    if (temp != -1)  // When dimensions too low.
                    {
                        mipOffset = temp;
                    }
                }
            }
            else
            {
                // UNCOMPRESSED
                var action = new Action <int>(mipIndex =>
                {
                    if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
                    {
                        // Remove alpha by setting AMask = 0
                        var ddspf        = header.ddspf;
                        ddspf.dwABitMask = 0;
                        header.ddspf     = ddspf;
                    }

                    // Get MipOffset
                    int offset = GetMipOffset(mipIndex, destFormatDetails, width, height);

                    WriteUncompressedMipMap(destination, offset, mipMaps[mipIndex], destFormatDetails, header.ddspf);
                });

                if (ImageEngine.EnableThreading)
                {
                    Parallel.For(0, mipMaps.Count, new ParallelOptions {
                        MaxDegreeOfParallelism = ImageEngine.NumThreads
                    }, (mip, loopState) =>
                    {
                        if (ImageEngine.IsCancellationRequested)
                        {
                            loopState.Stop();
                        }

                        action(mip);
                    });
                }
                else
                {
                    for (int i = 0; i < mipMaps.Count; i++)
                    {
                        if (ImageEngine.IsCancellationRequested)
                        {
                            break;
                        }

                        action(i);
                    }
                }
            }

            return(ImageEngine.IsCancellationRequested ? null : destination);
        }
        internal static void CompressBC2Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting, ImageFormats.ImageEngineFormatDetails formatDetails)
        {
            // Compress Alpha
            if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
            {
                // No alpha so fill with opaque alpha - has to be an alpha value, so make it so RGB is 100% visible.
                for (int i = 0; i < 8; i++)
                {
                    destination[destPosition + i] = 0xFF;
                }
            }
            else
            {
                int position = sourcePosition + 3;  // Only want to read alphas
                for (int i = 0; i < 8; i += 2)
                {
                    destination[destPosition + i]     = (byte)((imgData[position] & 0xF0) | (imgData[position + 4] >> 4));
                    destination[destPosition + i + 1] = (byte)((imgData[position + 8] & 0xF0) | (imgData[position + 12] >> 4));

                    position += sourceLineLength;
                }
            }


            // Compress Colour
            CompressRGBTexel(imgData, sourcePosition, sourceLineLength, destination, destPosition + 8, false, 0f, alphaSetting, formatDetails);
        }
Example #29
0
        static int WriteCompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, int blockSize, Action<byte[], int, int, byte[], int, AlphaSettings> compressor, AlphaSettings alphaSetting)
        {
            int destinationTexelCount = mipmap.Width * mipmap.Height / 16;
            int sourceLineLength = mipmap.Width * 4;
            int numTexelsInLine = mipmap.Width / 4;

            var mipWriter = new Action<int>(texelIndex =>
            {
                // Since this is the top corner of the first texel in a line, skip 4 pixel rows (texel = 4x4 pixels) and the number of rows down the bitmap we are already.
                int sourceLineOffset = sourceLineLength * 4 * (texelIndex / numTexelsInLine);  // Length in bytes x 3 lines x texel line index (how many texel sized lines down the image are we). Index / width will truncate, so for the first texel line, it'll be < 0. For the second texel line, it'll be < 1 and > 0.

                int sourceTopLeftCorner = ((texelIndex % numTexelsInLine) * 16) + sourceLineOffset; // *16 since its 4 pixels with 4 channels each. Index % numTexels will effectively reset each line.
                compressor(mipmap.Pixels, sourceTopLeftCorner, sourceLineLength, destination, mipOffset + texelIndex * blockSize, alphaSetting);
            });

            // Choose an acceleration method.
            if (ImageEngine.EnableGPUAcceleration)
                Debugger.Break();
            else if (ImageEngine.EnableThreading)
                Parallel.For(0, destinationTexelCount, new ParallelOptions { MaxDegreeOfParallelism = ImageEngine.NumThreads }, mipWriter);
            else
                for (int i = 0; i < destinationTexelCount; i++)
                    mipWriter(i);

            return mipOffset + destinationTexelCount * blockSize;
        }
        // ATI2 3Dc
        internal static void CompressBC5Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting, ImageFormats.ImageEngineFormatDetails formatDetails)
        {
            // Green: Channel 1.
            Compress8BitBlock(imgData, sourcePosition, sourceLineLength, destination, destPosition, 1, false, formatDetails);

            // Red: Channel 0, 8 destination offset to be after Green.
            Compress8BitBlock(imgData, sourcePosition, sourceLineLength, destination, destPosition + 8, 2, false, formatDetails);
        }
Example #31
0
        internal static byte[] SaveWithCodecs(byte[] imageData, ImageEngineFormat format, int width, int height, AlphaSettings alphaSetting)
        {
            var image = UsefulThings.WPF.Images.CreateWriteableBitmap(imageData, width, height);

            image.Freeze();
            BitmapFrame frame = null;

            if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
            {
                frame = BitmapFrame.Create(new FormatConvertedBitmap(image, PixelFormats.Bgr32, image.Palette, 0));
            }
            else if (format == ImageEngineFormat.BMP || format == ImageEngineFormat.PNG)
            {
                // Check if there's any alpha.
                bool anyAlpha = false;
                for (int i = 3; i < imageData.Length; i += 4)
                {
                    if (imageData[i] != 255)
                    {
                        anyAlpha = true;
                        break;
                    }
                }

                if (!anyAlpha)
                {
                    frame = BitmapFrame.Create(new FormatConvertedBitmap(image, PixelFormats.Bgr32, image.Palette, 0));
                }
            }
            else
            {
                frame = BitmapFrame.Create(image);
            }

            frame.Freeze();

            // KFreon: Choose encoder based on desired format.
            BitmapEncoder encoder            = null;
            int           estimatedImageSize = 0;

            int estimateHeaderSize = 1024;

            switch (format)
            {
            case ImageEngineFormat.BMP:
                encoder            = new BmpBitmapEncoder();
                estimatedImageSize = estimateHeaderSize + width * height * 4;      // Fairly good estimation
                break;

            case ImageEngineFormat.JPG:
                encoder = new JpegBitmapEncoder();
                ((JpegBitmapEncoder)encoder).QualityLevel = JPGCompressionSetting;
                estimatedImageSize = estimateHeaderSize + width * height / 6;      // Estimation
                break;

            case ImageEngineFormat.PNG:
                encoder            = new PngBitmapEncoder();
                estimatedImageSize = estimateHeaderSize + width * height / 2;      // Estimation
                break;

            case ImageEngineFormat.GIF:
                encoder            = new GifBitmapEncoder();
                estimatedImageSize = estimateHeaderSize + width * height / 5;      // Estimation
                break;

            case ImageEngineFormat.TIF:
                encoder            = new TiffBitmapEncoder();
                estimatedImageSize = estimateHeaderSize + width * height;     // Esimation
                break;

            default:
                throw new InvalidOperationException($"Unable to encode format: {format} using Windows 8.1 Codecs.");
            }

            encoder.Frames.Add(frame);
            using (MemoryStream ms = new MemoryStream(estimatedImageSize))  // Big enough to reduce memory copying.
            {
                encoder.Save(ms);
                return(ms.ToArray());
            }
        }
        /// <summary>
        /// Save mipmaps as given format to stream.
        /// </summary>
        /// <param name="MipMaps">List of Mips to save.</param>
        /// <param name="mipChoice">Determines how to handle mipmaps.</param>
        /// <param name="maxDimension">Maximum value for either image dimension.</param>
        /// <param name="alphaSetting">Determines how to handle alpha.</param>
        /// <param name="mipToSave">0 based index on which mipmap to make top of saved image.</param>
        /// <param name="destFormatDetails">Details about the destination format.</param>
        /// <returns>True on success.</returns>
        internal static byte[] Save(List <MipMap> MipMaps, ImageFormats.ImageEngineFormatDetails destFormatDetails, MipHandling mipChoice, AlphaSettings alphaSetting, int maxDimension = 0, int mipToSave = 0)
        {
            List <MipMap> newMips = new List <MipMap>(MipMaps);

            int width  = newMips[0].Width;
            int height = newMips[0].Height;

            if ((destFormatDetails.IsMippable && mipChoice == MipHandling.GenerateNew) || (destFormatDetails.IsMippable && newMips.Count == 1 && mipChoice == MipHandling.Default))
            {
                DDSGeneral.BuildMipMaps(newMips);
            }

            // KFreon: Resize if asked
            if (maxDimension != 0 && maxDimension < width && maxDimension < height)
            {
                if (!UsefulThings.General.IsPowerOfTwo(maxDimension))
                {
                    throw new ArgumentException($"{nameof(maxDimension)} must be a power of 2. Got {nameof(maxDimension)} = {maxDimension}");
                }

                // KFreon: Check if there's a mipmap suitable, removes all larger mipmaps
                var validMipmap = newMips.Where(img => (img.Width == maxDimension && img.Height <= maxDimension) || (img.Height == maxDimension && img.Width <= maxDimension));  // Check if a mip dimension is maxDimension and that the other dimension is equal or smaller
                if (validMipmap?.Count() != 0)
                {
                    int index = newMips.IndexOf(validMipmap.First());
                    newMips.RemoveRange(0, index);
                }
                else
                {
                    // KFreon: Get the amount the image needs to be scaled. Find largest dimension and get it's scale.
                    double scale = maxDimension * 1d / (width > height ? width : height);

                    // KFreon: No mip. Resize.
                    newMips[0] = Resize(newMips[0], scale);
                }
            }

            // KFreon: Ensure we have a power of two for dimensions FOR DDS ONLY
            TestDDSMipSize(newMips, destFormatDetails, width, height, out double fixXScale, out double fixYScale, mipChoice);

            if (fixXScale != 0 || fixYScale != 0 || mipChoice == MipHandling.KeepTopOnly)
            {
                DestroyMipMaps(newMips, mipToSave);
            }

            if ((fixXScale != 0 || fixXScale != 0) && destFormatDetails.IsMippable && mipChoice != MipHandling.KeepTopOnly)
            {
                DDSGeneral.BuildMipMaps(newMips);
            }


            byte[] destination = null;
            if (destFormatDetails.IsDDS)
            {
                destination = DDSGeneral.Save(newMips, destFormatDetails, alphaSetting);
            }
            else
            {
                // KFreon: Try saving with built in codecs
                var mip = newMips[0];


                // Fix formatting
                byte[] newPixels = new byte[mip.Width * mip.Height * 4];
                for (int i = 0, j = 0; i < newPixels.Length; i++, j += mip.LoadedFormatDetails.ComponentSize)
                {
                    newPixels[i] = mip.LoadedFormatDetails.ReadByte(mip.Pixels, j);
                }

                destination = WIC_Codecs.SaveWithCodecs(newPixels, destFormatDetails.Format, mip.Width, mip.Height, alphaSetting);
            }

            return(destination);
        }
        byte[] AttemptSaveUsingOriginalData(ImageFormats.ImageEngineFormatDetails destFormatDetails, MipHandling GenerateMips, int desiredMaxDimension, int mipToSave, AlphaSettings alphaSetting)
        {
            int        start      = 0;
            int        destStart  = 0;
            int        length     = OriginalData.Length;
            int        newWidth   = Width;
            int        newHeight  = Height;
            DDS_Header tempHeader = null;

            byte[] data             = null;
            byte[] tempOriginalData = OriginalData;

            if (destFormatDetails.IsDDS)
            {
                destStart = destFormatDetails.HeaderSize;
                start     = destStart;

                int mipCount = 0;

                if (mipToSave != 0)
                {
                    mipCount  = 1;
                    newWidth  = MipMaps[mipToSave].Width;
                    newHeight = MipMaps[mipToSave].Height;

                    start  = ImageFormats.GetCompressedSize(mipToSave, destFormatDetails, Width, Height);
                    length = ImageFormats.GetCompressedSize(1, destFormatDetails, newWidth, newHeight);
                }
                else if (desiredMaxDimension != 0 && desiredMaxDimension < Width && desiredMaxDimension < Height)
                {
                    int index = MipMaps.FindIndex(t => t.Width < desiredMaxDimension && t.Height < desiredMaxDimension);

                    // If none found, do a proper save and see what happens.
                    if (index == -1)
                    {
                        return(ImageEngine.Save(MipMaps, destFormatDetails, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave));
                    }

                    mipCount -= index;
                    newWidth  = MipMaps[index].Width;
                    newHeight = MipMaps[index].Height;

                    start  = ImageFormats.GetCompressedSize(index, destFormatDetails, Width, Height);
                    length = ImageFormats.GetCompressedSize(mipCount, destFormatDetails, newWidth, newHeight);
                }
                else
                {
                    if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
                    {
                        // Can't edit alpha directly in premultiplied formats. Not easily anyway.
                        if (destFormatDetails.IsPremultipliedFormat)
                        {
                            return(ImageEngine.Save(MipMaps, destFormatDetails, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave));
                        }


                        // DDS Formats only
                        switch (destFormatDetails.Format)
                        {
                        // Excluded cos they have no true alpha
                        case ImageEngineFormat.DDS_A8:
                        case ImageEngineFormat.DDS_A8L8:
                        case ImageEngineFormat.DDS_ATI1:
                        case ImageEngineFormat.DDS_ATI2_3Dc:
                        case ImageEngineFormat.DDS_V8U8:
                        case ImageEngineFormat.DDS_G16_R16:
                        case ImageEngineFormat.DDS_G8_L8:
                        case ImageEngineFormat.DDS_R5G6B5:
                        case ImageEngineFormat.DDS_RGB_8:
                        case ImageEngineFormat.DDS_DXT1:
                            break;

                        // Exluded cos they're alpha isn't easily edited
                        case ImageEngineFormat.DDS_DXT2:
                        case ImageEngineFormat.DDS_DXT4:
                            break;

                        // Excluded cos they're currently unsupported
                        case ImageEngineFormat.DDS_CUSTOM:
                        case ImageEngineFormat.DDS_DX10:
                        case ImageEngineFormat.DDS_ARGB_4:
                            break;

                        case ImageEngineFormat.DDS_ABGR_8:
                        case ImageEngineFormat.DDS_ARGB_32F:
                        case ImageEngineFormat.DDS_ARGB_8:
                        case ImageEngineFormat.DDS_DXT3:
                        case ImageEngineFormat.DDS_DXT5:
                            tempOriginalData = new byte[OriginalData.Length];
                            Array.Copy(OriginalData, tempOriginalData, OriginalData.Length);

                            // Edit alpha values
                            int    alphaStart = 128;
                            int    alphaJump  = 0;
                            byte[] alphaBlock = null;
                            if (destFormatDetails.IsBlockCompressed)
                            {
                                alphaJump  = 16;
                                alphaBlock = new byte[8];
                                for (int i = 0; i < 8; i++)
                                {
                                    alphaBlock[i] = 255;
                                }
                            }
                            else
                            {
                                alphaJump  = destFormatDetails.ComponentSize * 4;
                                alphaBlock = new byte[destFormatDetails.ComponentSize];

                                switch (destFormatDetails.ComponentSize)
                                {
                                case 1:
                                    alphaBlock[0] = 255;
                                    break;

                                case 2:
                                    alphaBlock = BitConverter.GetBytes(ushort.MaxValue);
                                    break;

                                case 4:
                                    alphaBlock = BitConverter.GetBytes(1f);
                                    break;
                                }
                            }

                            for (int i = alphaStart; i < OriginalData.Length; i += alphaJump)
                            {
                                Array.Copy(alphaBlock, 0, tempOriginalData, i, alphaBlock.Length);
                            }

                            break;
                        }
                    }


                    switch (GenerateMips)
                    {
                    case MipHandling.KeepExisting:
                        mipCount = NumMipMaps;
                        break;

                    case MipHandling.Default:
                        if (NumMipMaps > 1)
                        {
                            mipCount = NumMipMaps;
                        }
                        else
                        {
                            goto case MipHandling.GenerateNew;      // Eww goto...
                        }
                        break;

                    case MipHandling.GenerateNew:
                        ImageEngine.DestroyMipMaps(MipMaps);
                        ImageEngine.TestDDSMipSize(MipMaps, destFormatDetails, Width, Height, out double fixXScale, out double fixYScale, GenerateMips);

                        // Wrong sizing, so can't use original data anyway.
                        if (fixXScale != 0 || fixYScale != 0)
                        {
                            return(ImageEngine.Save(MipMaps, destFormatDetails, GenerateMips, alphaSetting, desiredMaxDimension, mipToSave));
                        }


                        mipCount = DDSGeneral.BuildMipMaps(MipMaps);

                        // Compress mipmaps excl top
                        byte[] formattedMips = DDSGeneral.Save(MipMaps.GetRange(1, MipMaps.Count - 1), destFormatDetails, alphaSetting);
                        if (formattedMips == null)
                        {
                            return(null);
                        }

                        // Get top mip size and create destination array
                        length = ImageFormats.GetCompressedSize(0, destFormatDetails, newWidth, newHeight);     // Should be the length of the top mipmap.
                        data   = new byte[formattedMips.Length + length];

                        // Copy smaller mips to destination
                        Array.Copy(formattedMips, destFormatDetails.HeaderSize, data, length, formattedMips.Length - destFormatDetails.HeaderSize);
                        break;

                    case MipHandling.KeepTopOnly:
                        mipCount = 1;
                        length   = ImageFormats.GetCompressedSize(1, destFormatDetails, newWidth, newHeight);
                        break;
                    }
                }

                // Header
                tempHeader = new DDS_Header(mipCount, newHeight, newWidth, destFormatDetails.Format, destFormatDetails.DX10Format);
            }

            // Use existing array, otherwise create one.
            data = data ?? new byte[length];
            Array.Copy(tempOriginalData, start, data, destStart, length - destStart);

            // Write header if existing (DDS Only)
            if (tempHeader != null)
            {
                tempHeader.WriteToArray(data, 0);
            }

            return(data);
        }
        static int CheckDXT1TexelFullTransparency(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting, double alphaRef)
        {
            int uColourKey = 0;
            int position = sourcePosition;

            // Alpha stuff
            for (int i = 1; i <= 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    RGBColour colour = ReadColourFromTexel(imgData, position, alphaSetting == AlphaSettings.Premultiply);
                    if (colour.a < alphaRef)
                        uColourKey++;
                    position += 4;
                }

                position = sourcePosition + sourceLineLength * i;
            }

            if (uColourKey == 16)
            {
                // Entire texel is transparent

                for (int i = 0; i < 8; i++)
                    destination[destPosition + i] = byte.MaxValue;

                return -1;
            }

            return uColourKey > 0 ? 3 : 4;
        }
Example #35
0
        internal static byte[] SaveWithCodecs(byte[] imageData, ImageEngineFormat format, int width, int height, AlphaSettings alphaSetting)
        {
            var image = UsefulThings.WPF.Images.CreateWriteableBitmap(imageData, width, height);
            image.Freeze();
            BitmapFrame frame = null;

            if (alphaSetting == AlphaSettings.RemoveAlphaChannel)
                frame = BitmapFrame.Create(new FormatConvertedBitmap(image, PixelFormats.Bgr32, image.Palette, 0));
            else
                frame = BitmapFrame.Create(image);

            frame.Freeze();

            // KFreon: Choose encoder based on desired format.
            BitmapEncoder encoder = null;
            int estimatedImageSize = 0;

            int estimateHeaderSize = 1024;
            switch (format)
            {
                case ImageEngineFormat.BMP:
                    encoder = new BmpBitmapEncoder();
                    estimatedImageSize = estimateHeaderSize + width * height * 4;  // Fairly good estimation
                    break;
                case ImageEngineFormat.JPG:
                    encoder = new JpegBitmapEncoder();
                    ((JpegBitmapEncoder)encoder).QualityLevel = JPGCompressionSetting;
                    estimatedImageSize = estimateHeaderSize + width * height / 6;  // Estimation
                    break;
                case ImageEngineFormat.PNG:
                    encoder = new PngBitmapEncoder();
                    estimatedImageSize = estimateHeaderSize + width * height / 2;  // Estimation
                    break;
                case ImageEngineFormat.GIF:
                    encoder = new GifBitmapEncoder();
                    estimatedImageSize = estimateHeaderSize + width * height / 5;  // Estimation
                    break;
                case ImageEngineFormat.TIF:
                    encoder = new TiffBitmapEncoder();
                    estimatedImageSize = estimateHeaderSize + width * height; // Esimation
                    break;
                default:
                    throw new InvalidOperationException($"Unable to encode format: {format} using Windows 8.1 Codecs.");
            }

            encoder.Frames.Add(frame);
            using (MemoryStream ms = new MemoryStream(estimatedImageSize))  // Big enough to reduce memory copying.
            {
                encoder.Save(ms);
                return ms.ToArray();
            }
        }
        static uint DoOtherColourFixErrorCorrection(byte[] imgData, int sourcePosition, int sourceLineLength, int uSteps, double alphaRef, AlphaSettings alphaSetting, RGBColour[] step, RGBColour Dir)
        {
            uint dw = 0;
            RGBColour[] Error = new RGBColour[16];

            uint[] psteps = uSteps == 3 ? psteps3 : psteps4;

            for (int i = 0; i < 4; i++)
            {
                int position = sourcePosition + sourceLineLength * i;

                for (int j = 0; j < 4; j++)
                {

                    int index = (i << 2) + j;
                    RGBColour current = ReadColourFromTexel(imgData, position, alphaSetting == AlphaSettings.Premultiply);

                    if ((uSteps == 3) && (current.a < alphaRef))
                    {
                        dw = (uint)((3 << 30) | (dw >> 2));
                        continue;
                    }

                    current.r *= Luminance.r;
                    current.g *= Luminance.g;
                    current.b *= Luminance.b;

                    if (true) // dither
                    {
                        // Error again
                        current.r += Error[index].r;
                        current.g += Error[index].g;
                        current.b += Error[index].b;
                    }

                    float fdot = (current.r - step[0].r) * Dir.r + (current.g - step[0].g) * Dir.g + (current.b - step[0].b) * Dir.b;

                    uint iStep = 0;
                    if (fdot <= 0f)
                        iStep = 0;
                    else if (fdot >= (uSteps - 1))
                        iStep = 1;
                    else
                        iStep = psteps[(int)(fdot + .5f)];

                    dw = (iStep << 30) | (dw >> 2);   // THIS  IS THE MAGIC here. This is the "list" of indicies. Somehow...

                    DoSomeDithering(current, index, step, (int)iStep, Error);

                    position += 4;
                }
            }

            return dw;
        }
Example #37
0
        static byte SignedAdjustment = 128;  // KFreon: This is for adjusting out of signed land.  This gets removed on load and re-added on save.

        #region Compressed
        internal static void CompressBC1Block(byte[] imgData, int sourcePosition, int sourceLineLength, byte[] destination, int destPosition, AlphaSettings alphaSetting)
        {
            CompressRGBTexel(imgData, sourcePosition, sourceLineLength, destination, destPosition, true, (alphaSetting == AlphaSettings.RemoveAlphaChannel ? 0 : DXT1AlphaThreshold), alphaSetting);
        }