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); } } }
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; }
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); } }
public EventFrame(BinaryReader reader, FrameGroup group) : base(reader.BaseStream) { this.reader = reader; Group = group; DescriptionBoard = group.Board; ReadInternal(reader); }
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); } } }
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); }
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); }
public void FocusOn(EventFrame frame, EventNode node) { Group = frame.Group; canvas.FocusOn(frame, node); }
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); }
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)); }
public HeaderThreadRow(FrameGroup group) { Group = group; }
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)); }
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); }