예제 #1
0
 public AssemblerResource <T> Merge(AssemblerResource <T> resource, AssemblerResource <T> layer, SkeletonType skeletonType, Overlay overlay = null)
 {
     // If we need to keep track of individual layers,
     // have the canvas store their metadata in a list
     ImageTools.Merge(resource, layer, skeletonType, overlay);
     if (!resource.IsEmpty)
     {
         resource.Definition.Merge(layer.Definition);
     }
     return(resource);
 }
예제 #2
0
        public void CleanupLayers(AssemblerResource <T> res, SkeletonType skeletonType)
        {
            if (skeletonType == SkeletonType.Anchors)
            {
                ImageTools.ExtractAnchors(res.Data);
            }

            if (res.SplitLayers != null && res.SplitLayers.Any())
            {
                foreach (var layer in res.SplitLayers)
                {
                    ImageTools.Merge(res.Data, layer.image, 0, 0, layer.Anchor.X, layer.Anchor.Y);
                }
            }
        }
예제 #3
0
        public AssemblerResource <T> Assemble(List <AssemblerResource <T> > resources,
                                              SkeletonType skeletonType,
                                              Overlay overlay     = null,
                                              ObjectType mainType = ObjectType.na,
                                              Dictionary <PixelInfo, PixelInfo> palette = null)
        {
            var useAnchors = skeletonType == SkeletonType.Anchors;

            if (overlay != null || skeletonType == SkeletonType.Anchors)
            {
                var width  = !useAnchors ? overlay.Width : resources.Max(r => r.Data.Width);
                var height = !useAnchors ? overlay.Height : resources.Max(r => r.Data.Height);
                var canvas = ImageTools.BlankCanvas(width, height);
                resources.Insert(0, AssemblerResource <T> .Canvas(canvas));
            }
            var assembled = resources.Aggregate((res, next) => Merge(res, next, skeletonType, overlay));

            CleanupLayers(assembled, skeletonType);

            // TODO, IMPORTANT - this somehow breaks the loader's definitions!
            // It replaces the type in the original resource definition
            if (mainType != ObjectType.na)
            {
                assembled.Definition.ObjectType = mainType;
            }

            assembled.Data   = ImageTools.Trim(assembled.Data);
            assembled.Colors = ImageTools.ColorInfo(assembled.Data);

            if (palette != null)
            {
                ImageTools.ApplyPalette(assembled.Data, palette);
            }

            assembled.Data.Apply();

            return(assembled);
        }
예제 #4
0
        //TODO cleanup this, not readable and does too many things. Split up the methods by skeleton type and by overlay (with overlay/without)
        public void Merge(AssemblerResource <T> canvas, AssemblerResource <T> layer, SkeletonType skeletonType, Overlay overlay)
        {
            var newParts = new List <(ImgPoint point, IImage <T> Image, bool isPattern)>();

            if (overlay != null && overlay.SourceType.ToObjectType() != layer.Definition.ObjectType)
            {
                // Each overlay color will tell us how many parts we need,
                // i.e. if there are N overlay point for color X, then we need N parts
                // If the resource has multiple images, use those, otherwise just use one image multiple times.
                var offSets = overlay.Points[OverlayColorRef[layer.Definition.ObjectType]].Cast <ImgPoint>().ToList();

                if (offSets.Count > 1 && layer.Definition.Meta.CannotDuplicate)
                {
                    ImgPoint newOffset;
                    if (offSets.Count > 2)
                    {
                        newOffset = offSets.PickRandom();
                    }
                    else
                    {
                        newOffset = new ImgPoint((offSets[0].X + offSets[1].X) / 2, (offSets[0].Y + offSets[1].Y) / 2);
                    }

                    offSets = new List <ImgPoint>()
                    {
                        newOffset
                    };
                }

                // "00FF26" & "FF00E5" are the default anchor colors - just an arbitrary choice. Change if needed.
                // TODO rewrite this, see anchor system overlay in garbler todo
                var anchorInUse = skeletonType == SkeletonType.Overlay ? AnchorOverlay : AnchorSkeleton;

                if (!layer.Definition.Meta.IsSet)
                {
                    var anchor = layer.Definition.Meta.MainAnchor
                                 ?? ExtractAnchor(layer.Data, anchorInUse);

                    for (int i = 0; i < offSets.Count; i++)
                    {
                        AddPart(offSets[i], anchor, layer.Data, i > offSets.Count / 2);
                    }
                }
                else
                {
                    // TODO rewrite with new anchor system
                    throw new NotImplementedException("currently disabled, re-enable when needed & after anchor system overhaul");
                    //var imagesAndAnchors = layer.AdditionalImages.Select(t =>
                    //    new {
                    //        anchor = ExtractAnchor(t, anchorInUse),
                    //        image = t
                    //    }).ToArray();
                    //for (int i = 0, j = 0; i < offSets.Count; i++, j++)
                    //{
                    //    if (j >= imagesAndAnchors.Length)
                    //        j = 0;

                    //    var item = imagesAndAnchors[j];
                    //    AddPart(offSets[i], item.anchor, item.image, i >= offSets.Count / 2);
                    //}
                }

                // PastSplit: At the moment we only allow to split a layer in two halves. Improve this if needed.
                void AddPart(ImgPoint offset, ImgPoint anchor, IImage <T> image, bool PastSplit)
                {
                    var offsetAnchor = new ImgPoint(offset.X - anchor.X, offset.Y - anchor.Y);

                    if (PastSplit && layer.Instruction.DepthSplit > 0)
                    {
                        canvas.SplitLayers.Add(new SplitLayer <T>()
                        {
                            Anchor = offsetAnchor,
                            image  = image,
                            Queue  = layer.Instruction.DepthSplit
                        });
                    }
                    else
                    {
                        newParts.Add((offsetAnchor, image, layer.Instruction.IsPattern));
                    }
                }
            }
            else if (skeletonType == SkeletonType.Anchors)
            {
                // TODO rewrite with new anchor system
                if (canvas.IsEmpty)
                {
                    newParts.Add((new ImgPoint(
                                      canvas.Data.Width / 2 - layer.Data.Width / 2,
                                      canvas.Data.Height - layer.Data.Height),
                                  layer.Data,
                                  false));
                }
                else
                {
                    var layerAnchor  = layer.Definition.Meta.MainAnchor ?? ExtractAnchor(layer.Data, AnchorOverlay);
                    var canvasAnchor = canvas.Definition.Meta.MainAnchor ?? ExtractAnchor(canvas.Data, AnchorOverlay);
                    var offsetAnchor = new ImgPoint(canvasAnchor.X - layerAnchor.X, canvasAnchor.Y - layerAnchor.Y, RestrictedPoints);
                    newParts.Add((offsetAnchor, layer.Data, layer.Instruction.IsPattern));
                }
            }
            else
            {
                newParts.Add((new ImgPoint(0, 0), layer.Data, layer.Instruction.IsPattern));
            }

            if (canvas.SplitLayers != null && canvas.SplitLayers.Any())
            {
                var insertions = canvas.SplitLayers
                                 .Where(l => l.Queue == 0);
                // Split layers out of the queue come out first
                newParts.InsertRange(0, insertions.Select(l => (l.Anchor, l.image, false)));
                canvas.SplitLayers = canvas.SplitLayers.Except(insertions).ToList();

                foreach (var splitLayer in canvas.SplitLayers)
                {
                    splitLayer.Queue--;
                }
            }

            foreach (var part in newParts)
            {
                Merge(canvas.Data, part.Image, 0, 0, part.point.X, part.point.Y, part.isPattern);
                canvas.IsEmpty = false;
            }
        }
예제 #5
0
        public AssemblerResource <T> Assemble(Instructions instructions)
        {
            var     resources = new List <AssemblerResource <T> >();
            Overlay overlay   = null;

            foreach (var instructionLayer in instructions)
            {
                // This goes through the current layer ie new List<Enum>() { Shape.round, ObjectType.vase }
                var props = instructionLayer.Types.Select(l =>
                                                          new
                {
                    propInfo = ResourceDefinition.DefinitionPropInfo.SingleOrDefault(
                        p => p.PropertyType == l.GetType()),
                    value = l
                }
                                                          );

                // Then loops through all the resources definitions until it finds one
                // that has ALL the required properties set as described.
                // If we end up with a lot of assets, have the loader create indexes for individual properties in a definition.
                var definitions = Loader.TypeResourceDefinitions.Where(d => props
                                                                       .All(p => Equals(p.propInfo.GetValue(d), p.value)))
                                  .ToList();

                var definition = string.IsNullOrEmpty(instructionLayer.SubType) ?
                                 definitions.PickRandom() :
                                 definitions.Where(d => d.SubTypes.Contains(instructionLayer.SubType)).ToList().PickRandom();

                if (instructions.UseOnce)
                {
                    Loader.TypeResourceDefinitions.Remove(definition);
                }

                AssemblerResource <T> resource;

                if (!definition.Meta.IsSet)
                {
                    resource = new AssemblerResource <T>(definition,
                                                         ImageTools.BytesToImage(Loader.LoadImageByName(definition.Meta.ResourceName)),
                                                         instructionLayer);
                }
                else
                {
                    resource = new AssemblerResource <T>(definition,
                                                         definition.Meta.ResourceNames.Select(r =>
                                                                                              ImageTools.BytesToImage(Loader.LoadImageByName(r))).ToList(),
                                                         instructionLayer);
                }

                resources.Add(resource);


                if (instructionLayer.HasOverlay)
                {
                    overlay = definition.Meta.Overlay;
                    // deprecated, remove
                    //var overlayBytes = _loader.GetMatchingOverlay(definition.Meta.ResourceName);
                    //overlay = _imageTools.ReadOverlayData(overlayBytes, definition.ObjectType);
                }
            }

            //TODO all these parameters are stupid, fix it
            return(Assemble(resources, instructions.SkeletonType, overlay, instructions.MainType, instructions.Palette));
        }