Beispiel #1
0
        public static Block Encode(List <RGB> colors)
        {
            // regular case: just try our best to compress and minimise Error
            var bestsolns = new SolutionSet();

            foreach (var flip in new[] { false, true })
            {
                var pixels = new[] { 0, 1 }.Select(i => colors.Where((c, j) => (j / (flip ? 2 : 8)) % 2 == i).ToArray()).ToArray();
                foreach (var diff in new[] { false, true }) // let's again just assume no diff
                {
                    var solns = new Solution[2];
                    var limit = diff ? 32 : 16;

                    int i;
                    for (i = 0; i < 2; i++)
                    {
                        var errorThreshold = bestsolns.TotalError;
                        if (i == 1)
                        {
                            errorThreshold -= solns[0].Error;
                        }
                        var opt = new Optimizer(pixels[i], limit, errorThreshold);
                        if (i == 1 && diff)
                        {
                            opt._baseColor = solns[0].BlockColor;
                            if (!opt.ComputeDeltas(-4, -3, -2, -1, 0, 1, 2, 3))
                            {
                                break;
                            }
                        }
                        else
                        {
                            if (!opt.ComputeDeltas(-4, -3, -2, -1, 0, 1, 2, 3, 4))
                            {
                                break;
                            }

                            // Fix fairly arbitrary/unrefined thresholds that control how far away to scan for potentially better solutions.
                            if (opt._bestSln.Error > 9000)
                            {
                                if (opt._bestSln.Error > 18000)
                                {
                                    opt.ComputeDeltas(-8, -7, -6, -5, 5, 6, 7, 8);
                                }
                                else
                                {
                                    opt.ComputeDeltas(-5, 5);
                                }
                            }
                        }
                        if (opt._bestSln.Error >= errorThreshold)
                        {
                            break;
                        }
                        solns[i] = opt._bestSln;
                    }

                    if (i != 2)
                    {
                        continue;
                    }

                    var solnset = new SolutionSet(flip, diff, solns[0], solns[1]);
                    if (solnset.TotalError < bestsolns.TotalError)
                    {
                        bestsolns = solnset;
                    }
                }
            }
            return(bestsolns.ToBlock());
        }
Beispiel #2
0
        // TODO: This is currently still very brute-forcey. Can be improved in the future
        public static bool RepackEtc1CompressedBlock(List <RGB> colors, out Block block)
        {
            foreach (var flip in new[] { false, true })
            {
                var allpixels0 = colors.Where((c, j) => (j / (flip ? 2 : 8)) % 2 == 0).ToArray();
                var pixels0    = allpixels0.Distinct().ToArray();
                if (pixels0.Length > 4)
                {
                    continue;
                }

                var allpixels1 = colors.Where((c, j) => (j / (flip ? 2 : 8)) % 2 == 1).ToArray();
                var pixels1    = allpixels1.Distinct().ToArray();
                if (pixels1.Length > 4)
                {
                    continue;
                }

                foreach (var diff in new[] { false, true })
                {
                    if (!diff)
                    {
                        var tables0 = Enumerable.Range(0, 8).Where(i => pixels0.All(c => _lookup16[i][c.R] && _lookup16[i][c.G] && _lookup16[i][c.B])).ToList();
                        if (!tables0.Any())
                        {
                            continue;
                        }
                        var tables1 = Enumerable.Range(0, 8).Where(i => pixels1.All(c => _lookup16[i][c.R] && _lookup16[i][c.G] && _lookup16[i][c.B])).ToList();
                        if (!tables1.Any())
                        {
                            continue;
                        }

                        var      opt0  = new Optimizer(allpixels0, 16, 1);
                        Solution soln0 = null;
                        foreach (var ti in tables0)
                        {
                            var rs = Enumerable.Range(0, 16).Where(a => pixels0.All(c => _lookup16big[ti][a].Contains(c.R))).ToArray();
                            var gs = Enumerable.Range(0, 16).Where(a => pixels0.All(c => _lookup16big[ti][a].Contains(c.G))).ToArray();
                            var bs = Enumerable.Range(0, 16).Where(a => pixels0.All(c => _lookup16big[ti][a].Contains(c.B))).ToArray();
                            soln0 = opt0.FindExactMatches(from r in rs from g in gs from b in bs select new RGB(r, g, b), Constants.Modifiers[ti]).FirstOrDefault();
                            if (soln0 != null)
                            {
                                break;
                            }
                        }
                        if (soln0 == null)
                        {
                            continue;
                        }

                        var opt1 = new Optimizer(allpixels1, 16, 1);
                        foreach (var ti in tables1)
                        {
                            var rs    = Enumerable.Range(0, 16).Where(a => pixels1.All(c => _lookup16big[ti][a].Contains(c.R))).ToArray();
                            var gs    = Enumerable.Range(0, 16).Where(a => pixels1.All(c => _lookup16big[ti][a].Contains(c.G))).ToArray();
                            var bs    = Enumerable.Range(0, 16).Where(a => pixels1.All(c => _lookup16big[ti][a].Contains(c.B))).ToArray();
                            var soln1 = opt1.FindExactMatches(from r in rs from g in gs from b in bs select new RGB(r, g, b), Constants.Modifiers[ti]).FirstOrDefault();
                            if (soln1 != null)
                            {
                                block = new SolutionSet(flip, false, soln0, soln1).ToBlock();
                                return(true);
                            }
                        }
                    }
                    else
                    {
                        var tables0 = Enumerable.Range(0, 8).Where(i => pixels0.All(c => _lookup32[i][c.R] && _lookup32[i][c.G] && _lookup32[i][c.B])).ToList();
                        if (!tables0.Any())
                        {
                            continue;
                        }
                        var tables1 = Enumerable.Range(0, 8).Where(i => pixels1.All(c => _lookup32[i][c.R] && _lookup32[i][c.G] && _lookup32[i][c.B])).ToList();
                        if (!tables1.Any())
                        {
                            continue;
                        }

                        var opt0   = new Optimizer(allpixels0, 32, 1);
                        var solns0 = new List <Solution>();
                        foreach (var ti in tables0)
                        {
                            var rs = Enumerable.Range(0, 32).Where(a => pixels0.All(c => _lookup32big[ti][a].Contains(c.R))).ToArray();
                            var gs = Enumerable.Range(0, 32).Where(a => pixels0.All(c => _lookup32big[ti][a].Contains(c.G))).ToArray();
                            var bs = Enumerable.Range(0, 32).Where(a => pixels0.All(c => _lookup32big[ti][a].Contains(c.B))).ToArray();
                            solns0.AddRange(opt0.FindExactMatches(from r in rs from g in gs from b in bs select new RGB(r, g, b), Constants.Modifiers[ti]));
                        }
                        if (!solns0.Any())
                        {
                            continue;
                        }

                        var opt1 = new Optimizer(allpixels1, 32, 1);
                        foreach (var ti in tables1)
                        {
                            var rs = Enumerable.Range(0, 32).Where(a => pixels1.All(c => _lookup32big[ti][a].Contains(c.R))).ToArray();
                            var gs = Enumerable.Range(0, 32).Where(a => pixels1.All(c => _lookup32big[ti][a].Contains(c.G))).ToArray();
                            var bs = Enumerable.Range(0, 32).Where(a => pixels1.All(c => _lookup32big[ti][a].Contains(c.B))).ToArray();
                            foreach (var soln0 in solns0)
                            {
                                var q = (from r in rs
                                         let dr = r - soln0.BlockColor.R
                                                  where dr >= -4 && dr < 4
                                                  from g in gs
                                                  let dg = g - soln0.BlockColor.G
                                                           where dg >= -4 && dg < 4
                                                           from b in bs
                                                           let db = b - soln0.BlockColor.B
                                                                    where db >= -4 && db < 4
                                                                    select new RGB(r, g, b));
                                var soln1 = opt1.FindExactMatches(q, Constants.Modifiers[ti]).FirstOrDefault();
                                if (soln1 != null)
                                {
                                    block = new SolutionSet(flip, true, soln0, soln1).ToBlock();
                                    return(true);
                                }
                            }
                        }
                    }
                }
            }

            block = new Block();
            return(false);
        }