Ejemplo n.º 1
0
        public FrameGroup Clone()
        {
            FrameGroup group = new FrameGroup();
            group.Width = this.Width;
            group.Height = this.Height;
            group.Layers = this.Layers;
            group.Frames = this.Frames;
            group.PatternX = this.PatternX;
            group.PatternY = this.PatternY;
            group.PatternZ = this.PatternZ;
            group.ExactSize = this.ExactSize;
            group.SpriteIDs = (uint[])this.SpriteIDs.Clone();
            group.AnimationMode = this.AnimationMode;
            group.LoopCount = this.LoopCount;
            group.StartFrame = this.StartFrame;

            if (this.Frames > 1)
            {
                group.IsAnimation = true;
                group.FrameDurations = new FrameDuration[this.Frames];

                for (int i = 0; i < this.Frames; i++)
                {
                    group.FrameDurations[i] = this.FrameDurations[i].Clone();
                }
            }

            return group;
        }
		// Internal set clip, reset all 
		void SetClip(tk2dSpriteAnimationClip clip)
		{
			if (this.clip != clip)
			{
				// reset stuff
				this.clip = clip;

				timelineEditor.Reset();

				if (!repeatPlayAnimation) playAnimation = false;
				this.Animator.Stop();

				// build frame groups
				if (clip != null)
				{
					if (CheckValidClip(clip)) {
						// check if clip is valid?
						frameGroups.Clear();
						tk2dSpriteCollectionData lastSc = null;
						int lastSpriteId = -1;
						FrameGroup frameGroup = null;
						for (int i = 0; i < clip.frames.Length; ++i)
						{
							tk2dSpriteAnimationFrame f = clip.frames[i];
							if (f.spriteCollection != lastSc || f.spriteId != lastSpriteId)
							{
								if (frameGroup != null) frameGroups.Add(frameGroup);
								frameGroup = new FrameGroup();
								frameGroup.spriteCollection = f.spriteCollection;
								frameGroup.spriteId = f.spriteId;
							}
							lastSc = f.spriteCollection;
							lastSpriteId = f.spriteId;
							frameGroup.frames.Add(f);
						}
						if (frameGroup != null) frameGroups.Add(frameGroup);

						// Select first frame group
						if (frameGroups.Count > 0) {
							timelineEditor.CurrentState.selectedFrame = 0;
						}
					}
				}
			}
		}
        // Internal set clip, reset all
        void SetClip(tk2dSpriteAnimationClip clip)
        {
            if (this.clip != clip)
            {
                // reset stuff
                this.clip = clip;

                timelineEditor.Reset();

                if (!repeatPlayAnimation) playAnimation = false;
                this.Sprite.Stop();

                // build frame groups
                if (clip != null)
                {
                    frameGroups.Clear();
                    tk2dSpriteCollectionData lastSc = null;
                    int lastSpriteId = -1;
                    FrameGroup frameGroup = null;
                    for (int i = 0; i < clip.frames.Length; ++i)
                    {
                        tk2dSpriteAnimationFrame f = clip.frames[i];
                        if (f.spriteCollection != lastSc || f.spriteId != lastSpriteId)
                        {
                            if (frameGroup != null) frameGroups.Add(frameGroup);
                            frameGroup = new FrameGroup();
                            frameGroup.spriteCollection = f.spriteCollection;
                            frameGroup.spriteId = f.spriteId;
                        }
                        lastSc = f.spriteCollection;
                        lastSpriteId = f.spriteId;
                        frameGroup.frames.Add(f);
                    }
                    if (frameGroup != null) frameGroups.Add(frameGroup);
                }
            }
        }
Ejemplo n.º 4
0
 public static FrameGroup Create()
 {
     FrameGroup group = new FrameGroup();
     group.Width = 1;
     group.Height = 1;
     group.Layers = 1;
     group.Frames = 1;
     group.PatternX = 1;
     group.PatternY = 1;
     group.PatternZ = 1;
     group.ExactSize = 32;
     group.SpriteIDs = new uint[1];
     group.IsAnimation = false;
     group.AnimationMode = AnimationMode.Asynchronous;
     group.LoopCount = 0;
     group.StartFrame = 0;
     group.FrameDurations = null;
     return group;
 }
Ejemplo n.º 5
0
        public EventsThreadRow(FrameGroup group, ThreadDescription desc, ThreadData data)
        {
            Description = desc;
            EventData   = data;
            Group       = group;
            MaxDepth    = 1;
            IsExpanded  = true;

            List <EventNode> rootCategories = new List <EventNode>();
            List <EventNode> nodesToProcess = new List <EventNode>();

            foreach (EventFrame frame in data.Events)
            {
                // Fill holes in timeline from regular events (not categories)
                // ------------------------------------------------------------------------------------------------------
                const double thresholdMs = 0.1;

                EventTree categoriesTree = frame.CategoriesTree;
                rootCategories.Clear();
                foreach (EventNode node in frame.CategoriesTree.Children)
                {
                    rootCategories.Add(node);
                }

                if (rootCategories.Count != 0)
                {
                    nodesToProcess.Clear();
                    foreach (EventNode node in frame.Root.Children)
                    {
                        nodesToProcess.Add(node);
                    }

                    while (nodesToProcess.Count > 0)
                    {
                        EventNode node = nodesToProcess[0];
                        nodesToProcess.RemoveAt(0);

                        bool nodeIntersectWithCategories = false;

                        foreach (EventNode categoryNode in rootCategories)
                        {
                            // drop nodes less than thresholdMs ms
                            if (node.Entry.Duration < thresholdMs)
                            {
                                nodeIntersectWithCategories = true;
                                break;
                            }

                            // node is entirely inside the categoryNode
                            if (node.Entry.Start >= categoryNode.Entry.Start && node.Entry.Finish <= categoryNode.Entry.Finish)
                            {
                                nodeIntersectWithCategories = true;
                                break;
                            }

                            // node is partially inside the categoryNode
                            if (node.Entry.Intersect(categoryNode.Entry))
                            {
                                foreach (EventNode tmp in node.Children)
                                {
                                    nodesToProcess.Add(tmp);
                                }

                                nodeIntersectWithCategories = true;
                                break;
                            }
                        }

                        if (nodeIntersectWithCategories == false && node.Entry.Duration >= thresholdMs)
                        {
                            // node is not intersect with any categoryNode (add to category tree)
                            EventNode fakeCategoryNode = new EventNode(frame.CategoriesTree, node.Entry);

                            node.Entry.SetOverrideColor(GenerateColorFromString(node.Entry.Description.FullName));

                            rootCategories.Add(fakeCategoryNode);
                            frame.CategoriesTree.Children.Add(fakeCategoryNode);
                        }
                    }
                }
                // ------------------------------------------------------------------------------------------------------

                MaxDepth = Math.Max(GetTree(frame).Depth, MaxDepth);
            }
        }
Ejemplo n.º 6
0
    public EventFrame(BinaryReader reader, FrameGroup group) : base(reader.BaseStream)
    {
      this.reader = reader;
			Group = group;
			DescriptionBoard = group.Board;
      ReadInternal(reader);
    }
Ejemplo n.º 7
0
        void InitThreadList(FrameGroup group, List <RowRange> rows)
        {
            ThreadList.Children.Clear();

            if (group == null)
            {
                return;
            }

            int rowIndex = 0;

            ThreadList.RowDefinitions.Clear();
            ThreadList.Margin = new Thickness(0, ThreadCanvas.HeaderHeight, 3, 1);

            for (int i = 1; i < ThreadList.ColumnDefinitions.Count; ++i)
            {
                ThreadList.ColumnDefinitions[i].SetBinding(ColumnDefinition.WidthProperty, new Binding("TimeWidth")
                {
                    Source = canvas
                });
            }

            Label workHeader = new Label()
            {
                Content = "Work(ms)", Margin = new Thickness(0, -2 * ThreadCanvas.HeaderHeight, 0, 0), ClipToBounds = false, FontSize = 12, FontWeight = FontWeights.Bold, VerticalAlignment = VerticalAlignment.Top
            };
            Label waitHeader = new Label()
            {
                Content = "Wait(ms)", Margin = new Thickness(0, -2 * ThreadCanvas.HeaderHeight, 0, 0), ClipToBounds = false, FontSize = 12, FontWeight = FontWeights.Bold, VerticalAlignment = VerticalAlignment.Top
            };

            Grid.SetColumn(workHeader, 1);
            Grid.SetRow(workHeader, 0);
            Grid.SetColumn(waitHeader, 2);
            Grid.SetRow(waitHeader, 0);

            ThreadList.Children.Add(workHeader);
            ThreadList.Children.Add(waitHeader);

            for (int threadIndex = 0; threadIndex < Math.Min(rows.Count, group.Board.Threads.Count); ++threadIndex)
            {
                RowRange range = rows[threadIndex];


                if (range.MaxDepth > 0 && group.Threads[threadIndex].Events.Count > 0)
                {
                    ThreadList.RowDefinitions.Add(new RowDefinition());

                    Thickness margin = new Thickness(3, 0, 0, ThreadCanvas.SpaceHeight);

                    Label labelName = new Label()
                    {
                        Content = group.Board.Threads[threadIndex].Name, Margin = margin, Padding = new Thickness(), FontWeight = FontWeights.Bold, Height = range.Height, VerticalContentAlignment = VerticalAlignment.Center
                    };

                    Label labelWork = new Label()
                    {
                        Margin = margin, Padding = new Thickness(), Height = range.Height, VerticalContentAlignment = VerticalAlignment.Center, DataContext = range, ContentStringFormat = "{0:0.00}"
                    };
                    Label labelWait = new Label()
                    {
                        Margin = margin, Padding = new Thickness(), Height = range.Height, VerticalContentAlignment = VerticalAlignment.Center, DataContext = range, ContentStringFormat = "{0:0.00}"
                    };

                    labelWork.SetBinding(Label.ContentProperty, new Binding("WorkTime")
                    {
                        Source = range
                    });
                    labelWait.SetBinding(Label.ContentProperty, new Binding("WaitTime")
                    {
                        Source = range
                    });

                    Grid.SetRow(labelName, rowIndex);
                    Grid.SetColumn(labelName, 0);

                    Grid.SetRow(labelWork, rowIndex);
                    Grid.SetColumn(labelWork, 1);

                    Grid.SetRow(labelWait, rowIndex);
                    Grid.SetColumn(labelWait, 2);

                    if (rowIndex++ % 2 == 0)
                    {
                        labelName.Background = ThreadCanvas.AlternativeBackgroundColor;
                        labelWork.Background = ThreadCanvas.AlternativeBackgroundColor;
                        labelWait.Background = ThreadCanvas.AlternativeBackgroundColor;
                    }

                    ThreadList.Children.Add(labelName);
                    ThreadList.Children.Add(labelWork);
                    ThreadList.Children.Add(labelWait);
                }
            }
        }
Ejemplo n.º 8
0
        void InitThreadList(FrameGroup group)
        {
            rows.Clear();
            id2row.Clear();

            ThreadList.RowDefinitions.Clear();
            ThreadList.Children.Clear();

            if (group == null)
            {
                return;
            }

            rows.Add(new HeaderThreadRow(group)
            {
                GradientTop    = Colors.LightGray,
                GradientBottom = Colors.Gray,
                SplitLines     = Colors.White,
                TextColor      = Colors.Black
            });

            for (int i = 0; i < Math.Min(group.Board.Threads.Count, group.Threads.Count); ++i)
            {
                ThreadDescription thread = group.Board.Threads[i];
                ThreadData        data   = group.Threads[i];

                bool threadHasData = false;
                if ((data.Callstacks != null && data.Callstacks.Count > 3) ||
                    /*(data.Sync != null && data.Sync.Intervals.Count > 0) || */
                    (data.Events != null && data.Events.Count > 0))

                {
                    threadHasData = true;
                }

                if (threadHasData)
                {
                    EventsThreadRow row = new EventsThreadRow(group, thread, data);
                    rows.Add(row);
                    id2row.Add(i, row);

                    row.EventNodeHover    += Row_EventNodeHover;
                    row.EventNodeSelected += Row_EventNodeSelected;
                }
            }

            scroll.TimeSlice = group.Board.TimeSlice;
            scroll.Height    = 0.0;
            scroll.Width     = surface.ActualWidth * RenderSettings.dpiScaleX;
            rows.ForEach(row => scroll.Height += row.Height);

            rows.ForEach(row => row.BuildMesh(surface, scroll));

            ThreadList.Margin = new Thickness(0, 0, 3, 0);

            if (BackgroundMesh != null)
            {
                BackgroundMesh.Dispose();
            }

            DynamicMesh backgroundBuilder = surface.CreateMesh();

            double offset = 0.0;

            for (int threadIndex = 0; threadIndex < rows.Count; ++threadIndex)
            {
                ThreadRow row = rows[threadIndex];
                row.Offset = offset;

                ThreadList.RowDefinitions.Add(new RowDefinition());

                Thickness margin = new Thickness(0, 0, 0, 0);

                Label labelName = new Label()
                {
                    Content = row.Name, Margin = margin, Padding = new Thickness(), FontWeight = FontWeights.Bold, Height = row.Height / RenderSettings.dpiScaleY, VerticalContentAlignment = VerticalAlignment.Center
                };

                Grid.SetRow(labelName, threadIndex);

                if (threadIndex % 2 == 1)
                {
                    labelName.Background = AlternativeBackground;
                    backgroundBuilder.AddRect(new Rect(0.0, offset / scroll.Height, 1.0, row.Height / scroll.Height), AlternativeBackground.Color);
                }

                ThreadList.Children.Add(labelName);
                offset += row.Height;
            }

            BackgroundMesh = backgroundBuilder.Freeze(surface.RenderDevice);
        }
Ejemplo n.º 9
0
        ThreadData GenerateSamplingThread(FrameGroup group, ThreadData thread)
        {
            List <Entry>      entries = new List <Entry>();
            List <Entry>      stack   = new List <Entry>();
            List <EventFrame> frames  = new List <EventFrame>();

            Callstack current = new Callstack();

            for (int csIndex = 0; csIndex < thread.Callstacks.Count; ++csIndex)
            {
                Callstack callstack = thread.Callstacks[csIndex];

                if (current.Start == callstack.Start)
                {
                    continue;
                }

                int matchCount = 0;

                for (int i = 0; i < Math.Min(current.Count, callstack.Count); ++i, ++matchCount)
                {
                    if (current[i].Name != callstack[i].Name)
                    {
                        break;
                    }
                }

                for (int i = matchCount; i < stack.Count; ++i)
                {
                    stack[i].Finish = callstack.Start;
                }

                stack.RemoveRange(matchCount, stack.Count - matchCount);

                if (stack.Count == 0 && matchCount > 0)
                {
                    FrameHeader h = new FrameHeader()
                    {
                        Start  = entries.Min(e => e.Start),
                        Finish = entries.Max(e => e.Finish),
                    };

                    frames.Add(new EventFrame(h, entries, group));
                    entries.Clear();
                }

                for (int i = matchCount; i < callstack.Count; ++i)
                {
                    Entry entry = new Entry(new EventDescription(callstack[i].Name), callstack.Start, long.MaxValue);
                    entries.Add(entry);
                    stack.Add(entry);
                }

                current = callstack;
            }

            foreach (Entry e in stack)
            {
                e.Finish = current.Start;
            }


            FrameHeader header = new FrameHeader()
            {
                Start  = thread.Callstacks.First().Start,
                Finish = thread.Callstacks.Last().Start,
            };

            frames.Add(new EventFrame(header, entries, group));
            ThreadData result = new ThreadData(null)
            {
                Events = frames
            };

            return(result);
        }
Ejemplo n.º 10
0
 public void FocusOn(EventFrame frame, EventNode node)
 {
     Group = frame.Group;
     canvas.FocusOn(frame, node);
 }
Ejemplo n.º 11
0
        public static ChartRow GenerateCoreChart(FrameGroup group)
        {
            if (group.Synchronization == null || group.Synchronization.Events.Count == 0)
            {
                return(null);
            }

            group.Synchronization.Events.Sort();

            int eventsCount = group.Synchronization.Events.Count;

            List <Tick> timestamps = new List <Tick>(eventsCount);

            ChartRow.Entry currProcess = new ChartRow.Entry(eventsCount)
            {
                Fill = Colors.LimeGreen, Name = "Current Process"
            };
            ChartRow.Entry otherProcess = new ChartRow.Entry(eventsCount)
            {
                Fill = Colors.Tomato, Name = "Other Process"
            };

            List <bool> isCoreInUse = new List <bool>(group.Board.CPUCoreCount);

            int currCores  = 0;
            int otherCores = 0;

            foreach (SyncEvent ev in group.Synchronization.Events)
            {
                ProcessGroup prevGroup = GetProcessGroup(group, ev.OldThreadID);
                ProcessGroup currGroup = GetProcessGroup(group, ev.NewThreadID);

                while (isCoreInUse.Count <= ev.CPUID)
                {
                    isCoreInUse.Add(false);
                }

                if ((prevGroup != currGroup) || !isCoreInUse[ev.CPUID])
                {
                    timestamps.Add(ev.Timestamp);

                    if (isCoreInUse[ev.CPUID])
                    {
                        switch (prevGroup)
                        {
                        case ProcessGroup.CurrentProcess:
                            --currCores;
                            break;

                        case ProcessGroup.OtherProcess:
                            --otherCores;
                            break;
                        }
                    }

                    isCoreInUse[ev.CPUID] = true;
                    switch (currGroup)
                    {
                    case ProcessGroup.CurrentProcess:
                        ++currCores;
                        break;

                    case ProcessGroup.OtherProcess:
                        ++otherCores;
                        break;
                    }

                    currProcess.Values.Add((double)currCores);
                    otherProcess.Values.Add((double)otherCores);
                }
            }

            ChartRow chart = new ChartRow("CPU", timestamps, new List <ChartRow.Entry>()
            {
                currProcess, otherProcess
            }, isCoreInUse.Count);

            return(chart);
        }
Ejemplo n.º 12
0
        List <EventsThreadRow> GenerateThreadRows(FrameGroup group)
        {
            id2row.Clear();

            List <EventsThreadRow> eventThreads = new List <EventsThreadRow>();

            for (int i = 0; i < Math.Min(group.Board.Threads.Count, group.Threads.Count); ++i)
            {
                ThreadData        data   = group.Threads[i];
                ThreadDescription thread = data.Description;

                if (thread.IsIdle)
                {
                    continue;
                }

                bool threadHasData = false;
                if (data.Events != null)
                {
                    double duration = 0.0;
                    foreach (EventFrame frame in data.Events)
                    {
                        duration += frame.Duration;
                        if (duration > MIN_THREAD_ACCUMULATED_DURATION)
                        {
                            threadHasData = true;
                            break;
                        }
                    }
                }

                if (thread.Origin == ThreadDescription.Source.Core)
                {
                    threadHasData = true;
                }

                if (threadHasData)
                {
                    EventsThreadRow row = new EventsThreadRow(group, thread, data, Settings);
                    eventThreads.Add(row);

                    id2row.Add(row.Description.ThreadIndex, row);
                    row.EventNodeHover    += Row_EventNodeHover;
                    row.EventNodeSelected += Row_EventNodeSelected;
                }

                if (GenerateSamplingThreads && data.Callstacks != null && data.Callstacks.Count > 3)
                {
                    ThreadData      samplingData = GenerateSamplingThread(group, data);
                    EventsThreadRow row          = new EventsThreadRow(group, new ThreadDescription()
                    {
                        Name = thread.Name + " [Sampling]", Origin = ThreadDescription.Source.Sampling
                    }, samplingData, Settings);
                    eventThreads.Add(row);
                    row.EventNodeHover    += Row_EventNodeHover;
                    row.EventNodeSelected += Row_EventNodeSelected;
                }
            }

            return(SortRows(eventThreads));
        }
Ejemplo n.º 13
0
 public HeaderThreadRow(FrameGroup group)
 {
     Group = group;
 }
Ejemplo n.º 14
0
        public SpriteSheet GetSpriteSheet(FrameGroupType groupType, OutfitData outfitData)
        {
            SpriteSheet rawSpriteSheet = this.GetSpriteSheet(groupType);

            FrameGroup group = this.ThingType.GetFrameGroup(groupType);

            if (group.Layers < 2)
            {
                return(rawSpriteSheet);
            }

            outfitData = outfitData == null ? OUTFIT_DATA : outfitData;

            int    totalX                   = group.PatternZ * group.PatternX * group.Layers;
            int    totalY                   = group.Frames * group.PatternY;
            int    bitmapWidth              = (totalX * group.Width) * Sprite.DefaultSize;
            int    bitmapHeight             = (totalY * group.Height) * Sprite.DefaultSize;
            int    pixelsWidth              = group.Width * Sprite.DefaultSize;
            int    pixelsHeight             = group.Height * Sprite.DefaultSize;
            Bitmap grayBitmap               = new Bitmap(bitmapWidth, bitmapHeight, PixelFormat.Format32bppArgb);
            Bitmap blendBitmap              = new Bitmap(bitmapWidth, bitmapHeight, PixelFormat.Format32bppArgb);
            Bitmap bitmap                   = new Bitmap(bitmapWidth, bitmapHeight, PixelFormat.Format32bppArgb);
            Dictionary <int, Rect> rectList = new Dictionary <int, Rect>();

            for (int f = 0; f < group.Frames; f++)
            {
                for (int z = 0; z < group.PatternZ; z++)
                {
                    for (int x = 0; x < group.PatternX; x++)
                    {
                        int index = (((f % group.Frames * group.PatternZ + z) * group.PatternY) * group.PatternX + x) * group.Layers;
                        rectList[index] = new Rect((z * group.PatternX + x) * pixelsWidth, f * pixelsHeight, pixelsWidth, pixelsHeight);
                    }
                }
            }

            BitmapLocker grayLocker   = new BitmapLocker(grayBitmap);
            BitmapLocker blendLocker  = new BitmapLocker(blendBitmap);
            BitmapLocker bitmapLocker = new BitmapLocker(bitmap);

            grayLocker.LockBits();
            blendLocker.LockBits();
            bitmapLocker.LockBits();

            for (int y = 0; y < group.PatternY; y++)
            {
                if (y == 0 || (outfitData.Addons & 1 << (y - 1)) != 0)
                {
                    for (int f = 0; f < group.Frames; f++)
                    {
                        for (int z = 0; z < group.PatternZ; z++)
                        {
                            for (int x = 0; x < group.PatternX; x++)
                            {
                                // gets gray bitmap
                                int  i     = (((f % group.Frames * group.PatternZ + z) * group.PatternY + y) * group.PatternX + x) * group.Layers;
                                Rect rect  = rawSpriteSheet.RectList[i];
                                int  rx    = rect.X;
                                int  ry    = rect.Y;
                                int  rw    = rect.Width;
                                int  rh    = rect.Height;
                                int  index = (((f * group.PatternZ + z) * group.PatternY) * group.PatternX + x) * group.Layers;
                                rect = rectList[index];
                                int px = rect.X;
                                int py = rect.Y;
                                grayLocker.CopyPixels(rawSpriteSheet.Bitmap, rx, ry, rw, rh, px, py);

                                // gets blend bitmap
                                i++;
                                rect = rawSpriteSheet.RectList[i];
                                rx   = rect.X;
                                ry   = rect.Y;
                                rw   = rect.Width;
                                rh   = rect.Height;
                                blendLocker.CopyPixels(rawSpriteSheet.Bitmap, rx, ry, rw, rh, px, py);
                            }
                        }
                    }

                    bitmapLocker.ColorizePixels(grayLocker.Pixels, blendLocker.Pixels, outfitData.Head, outfitData.Body, outfitData.Legs, outfitData.Feet);
                }
            }

            grayLocker.UnlockBits();
            grayLocker.Dispose();
            blendLocker.UnlockBits();
            blendLocker.Dispose();
            bitmapLocker.UnlockBits();
            bitmapLocker.Dispose();
            grayBitmap.Dispose();
            blendBitmap.Dispose();
            return(new SpriteSheet(bitmap, rectList));
        }
Ejemplo n.º 15
0
        public Bitmap GetObjectImage(ushort id, Direction direction, OutfitData data, bool mount)
        {
            ThingType thing = this.Things.GetThing(id, ThingCategory.Outfit);

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

            FrameGroup group = thing.GetFrameGroup(FrameGroupType.Default);

            if (group.Layers < 2)
            {
                return(this.GetObjectImage(id, ThingCategory.Outfit, FrameGroupType.Default));
            }

            int    width       = Sprite.DefaultSize * group.Width;
            int    height      = Sprite.DefaultSize * group.Height;
            Bitmap grayBitmap  = new Bitmap(width, height, PixelFormat.Format32bppArgb);
            Bitmap blendBitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
            Bitmap bitmap      = new Bitmap(width, height, PixelFormat.Format32bppArgb);

            BitmapLocker grayLocker   = new BitmapLocker(grayBitmap);
            BitmapLocker blendLocker  = new BitmapLocker(blendBitmap);
            BitmapLocker bitmapLocker = new BitmapLocker(bitmap);

            grayLocker.LockBits();
            blendLocker.LockBits();
            bitmapLocker.LockBits();

            byte x = (byte)((byte)direction % group.PatternX);
            byte z = mount && group.PatternZ > 1 ? (byte)1 : (byte)0;

            for (int y = 0; y < group.PatternY; y++)
            {
                if (y == 0 || (data.Addons & 1 << (y - 1)) != 0)
                {
                    for (byte w = 0; w < group.Width; w++)
                    {
                        for (byte h = 0; h < group.Height; h++)
                        {
                            int  index    = group.GetSpriteIndex(w, h, 0, x, y, z, 0);
                            uint spriteId = group.SpriteIDs[index];
                            int  px       = (group.Width - w - 1) * Sprite.DefaultSize;
                            int  py       = (group.Height - h - 1) * Sprite.DefaultSize;
                            grayLocker.CopyPixels(this.Sprites.GetSpriteBitmap(spriteId), px, py);

                            index    = group.GetSpriteIndex(w, h, 1, x, y, z, 0);
                            spriteId = group.SpriteIDs[index];
                            blendLocker.CopyPixels(this.Sprites.GetSpriteBitmap(spriteId), px, py);
                        }
                    }

                    bitmapLocker.ColorizePixels(grayLocker.Pixels, blendLocker.Pixels, data.Head, data.Body, data.Legs, data.Feet);
                }
            }

            grayLocker.UnlockBits();
            grayLocker.Dispose();
            blendLocker.UnlockBits();
            blendLocker.Dispose();
            bitmapLocker.UnlockBits();
            bitmapLocker.Dispose();
            grayBitmap.Dispose();
            blendBitmap.Dispose();
            return(bitmap);
        }