private void RenderAnimationPreview(RenderComposer c) { AnimatedSprite currentFileContext = _currentAsset !.Content !; SpriteAnimationFrameSource frameSource = currentFileContext.FrameSource; if (_animatedPreviewInvalidated) { var size = new Vector2(); for (var i = 0; i < frameSource.GetFrameCount(); i++) { Rectangle frameUV = frameSource.GetFrameUV(i); size.X = MathF.Max(size.X, frameUV.Width); size.Y = MathF.Max(size.Y, frameUV.Height); } if (size.X > size.Y) { size.Y = size.X; } else if (size.Y > size.X) { size.X = size.Y; } size *= 2; GLThread.ExecuteGLThreadAsync(() => { if (_animatedPreviewFb == null) { _animatedPreviewFb = new FrameBuffer(size).WithColor(); } else { _animatedPreviewFb.Resize(size, true); } }); _animatedPreviewInvalidated = false; } if (_animatedPreviewFb != null) { c.RenderToAndClear(_animatedPreviewFb); Vector2 size = _animatedPreviewFb.Size; c.RenderSprite(Vector3.Zero, size, new Color(32, 32, 32)); c.RenderLine(new Vector2(0, size.Y / 2), new Vector2(size.X, size.Y / 2), Color.White * 0.2f); c.RenderLine(new Vector2(size.X / 2, 0), new Vector2(size.X / 2, size.Y), Color.White * 0.2f); if (_animatedPreviewAnchorMode) { // Draw a shadow of the previous frame. if (_frameAnchor != 0) { _controller.GetRenderDataForFrame(_frameAnchor - 1, out Vector3 renderPosSh, out Texture textureSh, out Rectangle uvSh); renderPosSh = renderPosSh.RoundClosest(); c.RenderSprite((size / 2f).RoundClosest().ToVec3() + renderPosSh, uvSh.Size, Color.White * 0.3f, textureSh, uvSh); } _controller.GetRenderDataForFrame(_frameAnchor, out Vector3 renderPos, out Texture texture, out Rectangle uv); renderPos = renderPos.RoundClosest(); c.RenderSprite((size / 2f).RoundClosest().ToVec3() + renderPos, uv.Size, Color.White, texture, uv); } else { _controller.GetRenderData(out Vector3 renderPos, out Texture texture, out Rectangle uv); renderPos = renderPos.RoundClosest(); c.RenderSprite((size / 2f).RoundClosest().ToVec3() + renderPos, uv.Size, Color.White, texture, uv); } c.RenderTo(null); } }
private void FrameAnchorTab() { if (_currentAsset == null) { return; } _animatedPreviewAnchorMode = true; SpriteAnimationFrameSource frameSource = _currentAsset.Content.FrameSource; int frameCount = frameSource.GetFrameCount(); // Ensure data is of correct length. It's possible for it to be malformed if frames were re-detected or // user did something wacky. frameSource.FrameOrigins ??= new OriginPosition[frameCount]; if (frameSource.FrameOrigins.Length != frameCount) { Array.Resize(ref frameSource.FrameOrigins, frameCount); } frameSource.FrameOffsets ??= new Vector2[frameCount]; if (frameSource.FrameOffsets.Length != frameCount) { Array.Resize(ref frameSource.FrameOffsets, frameCount); } if (frameCount == 0) { return; } ImGui.InputInt("Zoom", ref _zoomLevel); ImGui.Text("Frame "); ImGui.SameLine(); ImGui.SetNextItemWidth(130); ImGui.InputInt("", ref _frameAnchor); ImGui.SameLine(); ImGui.Text($"/{frameCount}"); if (_frameAnchor < 0) { _frameAnchor = 0; } if (_frameAnchor > frameCount - 1) { _frameAnchor = frameCount - 1; } var anchorType = (int)frameSource.FrameOrigins[_frameAnchor]; if (ImGui.Combo("Anchor Type", ref anchorType, string.Join('\0', Enum.GetNames(typeof(OriginPosition))))) { frameSource.FrameOrigins[_frameAnchor] = (OriginPosition)anchorType; _controller.Reset(); UnsavedChanges(); } ImGui.SameLine(); if (ImGui.Button("Apply To All")) { for (var i = 0; i < frameSource.FrameOrigins.Length; i++) { frameSource.FrameOrigins[i] = (OriginPosition)anchorType; } UnsavedChanges(); } if (ImGui.InputFloat2("Additional Offset", ref frameSource.FrameOffsets[_frameAnchor])) { UnsavedChanges(); } if (_animatedPreviewFb != null) { FrameBufferTexture texture = _animatedPreviewFb.ColorAttachment; (Vector2 uv1, Vector2 uv2) = texture.GetImGuiUV(); ImGui.Image((IntPtr)texture.Pointer, texture.Size * _zoomLevel, uv1, uv2); } }
private void AnimationFrameEditor(Dictionary <string, SpriteAnimationData> anims) { AnimatedSprite currentFileContext = _currentAsset !.Content !; SpriteAnimationData selAnim = anims[_selectedAnimation]; ImGui.BeginChild("Animation", new Vector2(-1, -1), true); ImGui.Text("Frames: (Drag and Drop to rearrange)"); SpriteAnimationFrameSource frameSource = currentFileContext.FrameSource; _draggedFrame = EditorHelpers.DragAndDropList(selAnim.FrameIndices, _draggedFrame, true); if (selAnim.FrameIndices.Length == 0) { EditorHelpers.ButtonSizedHole(""); } ImGui.PushItemWidth(150); if (ImGui.InputInt("", ref _addFrameInput)) { _addFrameInput = Maths.Clamp(_addFrameInput, 0, frameSource.GetFrameCount() - 1); } ImGui.SameLine(); if (ImGui.Button("Add Frame")) { selAnim.FrameIndices = selAnim.FrameIndices.AddToArray(_addFrameInput); if (_addFrameInput < frameSource.GetFrameCount() - 2) { _addFrameInput++; } _controller.Reset(); UnsavedChanges(); } ImGui.SameLine(); ImGui.Button("Remove (Drop Here)"); if (ImGui.BeginDragDropTarget()) { ImGuiPayloadPtr dataPtr = ImGui.AcceptDragDropPayload("UNUSED"); unsafe { if ((IntPtr)dataPtr.NativePtr != IntPtr.Zero && dataPtr.IsDelivery()) { int[] indices = selAnim.FrameIndices; for (int i = _draggedFrame; i < indices.Length - 1; i++) { indices[i] = indices[i + 1]; } Array.Resize(ref selAnim.FrameIndices, selAnim.FrameIndices.Length - 1); _controller.Reset(); _draggedFrame = -1; UnsavedChanges(); } } ImGui.EndDragDropTarget(); } ImGui.PushItemWidth(150); ImGui.Text("Duration"); ImGui.SameLine(); if (ImGui.InputInt("###DurInput", ref selAnim.TimeBetweenFrames)) { _controller.Reset(); UnsavedChanges(); } ImGui.SameLine(); if (selAnim.FrameIndices.Length > 0) { ImGui.Text($"Total Duration: {selAnim.TimeBetweenFrames * selAnim.FrameIndices.Length}"); } var loopType = (int)selAnim.LoopType; if (ImGui.Combo("Loop Type", ref loopType, string.Join('\0', Enum.GetNames(typeof(AnimationLoopType))))) { selAnim.LoopType = (AnimationLoopType)loopType; _controller.Reset(); UnsavedChanges(); } }
private void FrameOrderTab() { AnimatedSprite currentFileContext = _currentAsset !.Content !; SpriteAnimationFrameSource frameSource = currentFileContext.FrameSource; var arraySource = frameSource as SpriteArrayFrameSource; var gridSource = frameSource as SpriteGridFrameSource; if (frameSource != null) { ImGui.Text($"Frames: {currentFileContext.FrameSource.GetFrameCount()}"); if (arraySource != null) { ImGui.SameLine(); ImGui.Checkbox("Show Frame Indices", ref _showFrameIdx); ImGui.SameLine(); if (ImGui.Button("Re-detect Frames")) { currentFileContext.FrameSource = new SpriteArrayFrameSource(_currentAssetTexture); UnsavedChanges(); } } if (gridSource != null) { if (ImGui.InputFloat2("FrameSize", ref gridSource.FrameSize)) { _animatedPreviewInvalidated = true; UnsavedChanges(); } if (ImGui.InputFloat2("Frame Spacing", ref gridSource.Spacing)) { _animatedPreviewInvalidated = true; UnsavedChanges(); } } } ImGui.InputInt("Zoom", ref _zoomLevel); if (arraySource != null) { ImGui.Text("Right-click on a frame to select it, and then on another frame to swap their positions."); } ImGui.BeginChild("FramePreview", new Vector2(-1, -1), true, ImGuiWindowFlags.HorizontalScrollbar); // Array source being unordered allows for frames to be reordered. if (_textureFb != null && frameSource != null) { Vector2 winPos = ImGui.GetCursorScreenPos(); FrameBufferTexture texture = _textureFb.ColorAttachment; (Vector2 uv1, Vector2 uv2) = texture.GetImGuiUV(); ImGui.Image((IntPtr)texture.Pointer, texture.Size * _zoomLevel, uv1, uv2); if (arraySource != null && arraySource.Frames != null && ImGui.IsWindowFocused() && Engine.Host.IsKeyDown(Key.MouseKeyRight)) { Vector2 mPos = ImGui.GetMousePos(); mPos -= winPos; int clickedOn = -1; for (var i = 0; i < frameSource.GetFrameCount(); i++) { Rectangle uv = frameSource.GetFrameUV(i); uv *= _zoomLevel; if (!uv.Contains(mPos)) { continue; } clickedOn = i; break; } if (clickedOn != -1) { if (_selectedFrame == -1) { _selectedFrame = clickedOn; } else { Rectangle uvSelected = frameSource.GetFrameUV(_selectedFrame); Rectangle uvNew = frameSource.GetFrameUV(clickedOn); arraySource.Frames[_selectedFrame] = uvNew; arraySource.Frames[clickedOn] = uvSelected; _selectedFrame = -1; UnsavedChanges(); } } } } ImGui.EndChild(); }
protected override bool RenderInternal(RenderComposer c) { var open = true; ImGui.SetNextWindowPos(new Vector2(0, 20), ImGuiCond.Always); ImGui.SetNextWindowSize(c.CurrentTarget.Size - new Vector2(0, 20)); ImGui.Begin(Title, ref open, ImGuiWindowFlags.MenuBar | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove); RenderImGui(); ImGui.End(); Position = Vector3.Zero; Size = c.CurrentTarget.Size; if (!open) { Parent?.RemoveChild(this); return(false); } if (_textureFb?.ColorAttachment == null) { return(true); // Disposed or uninitialized fb } if (_currentAssetTexture == null) { return(true); } _textureFb.ColorAttachment.Smooth = false; c.RenderToAndClear(_textureFb); c.RenderSprite(Vector3.Zero, _currentAssetTexture.Size, _currentAssetTexture); // Render meta overlay on the spritesheet texture. if (_currentAsset != null) { AnimatedSprite currentFileContext = _currentAsset.Content !; SpriteAnimationFrameSource frameSource = currentFileContext.FrameSource; if (frameSource != null) { for (var i = 0; i < frameSource.GetFrameCount(); i++) { Rectangle frameUv = frameSource.GetFrameUV(i); c.RenderOutline(frameUv, _selectedFrame == i ? Color.Green : Color.Red); if (_showFrameIdx && frameSource is SpriteArrayFrameSource) { Vector3 stringPos = frameUv.Position.ToVec3(); DrawableFontAtlas atlas = _debugFont.GetAtlas(20); c.RenderString(stringPos + new Vector3(1), Color.Black, i.ToString(), atlas); c.RenderString(stringPos, Color.Red, i.ToString(), atlas); } } } } c.RenderTo(null); RenderAnimationPreview(c); return(true); }