public void FramebufferResizing() { Runner.ExecuteAsLoop(_ => { FrameBuffer testBuffer = new FrameBuffer(new Vector2(1000, 1000)).WithColor(); RenderComposer composer = Engine.Renderer.StartFrame(); composer.RenderToAndClear(testBuffer); composer.RenderSprite(new Vector3(0, 0, 0), new Vector2(1000, 1000), Color.Red); composer.RenderTo(null); composer.RenderSprite(new Vector3(0, 0, 0), new Vector2(100, 100), Color.White, testBuffer.Texture); testBuffer.Resize(new Vector2(500, 500), true); composer.RenderToAndClear(testBuffer); composer.RenderSprite(new Vector3(0, 0, 0), new Vector2(500, 500), Color.Green); composer.RenderTo(null); composer.RenderFrameBuffer(testBuffer, new Vector2(100, 100), new Vector3(100, 0, 0)); Engine.Renderer.EndFrame(); Runner.VerifyScreenshot(ResultDb.FramebufferResizing); testBuffer.Dispose(); }).WaitOne(); }
public void TestDepthFromOtherFrameBuffer() { Runner.ExecuteAsLoop(_ => { FrameBuffer testBuffer = new FrameBuffer(Engine.Renderer.DrawBuffer.Size).WithColor().WithDepth(true); var shader = Engine.AssetLoader.Get <ShaderAsset>("Shaders/DepthTest.xml"); RenderComposer composer = Engine.Renderer.StartFrame(); composer.RenderTo(testBuffer); composer.ClearFrameBuffer(); composer.RenderSprite(new Vector3(0, 0, 10), new Vector2(100, 100), Color.Green); composer.RenderTo(null); composer.SetUseViewMatrix(false); composer.SetShader(shader.Shader); shader.Shader.SetUniformInt("depthTexture", 1); Texture.EnsureBound(testBuffer.DepthTexture.Pointer, 1); composer.RenderSprite(new Vector3(0, 0, 0), testBuffer.Texture.Size, Color.White, testBuffer.Texture); composer.SetShader(); composer.SetUseViewMatrix(true); composer.RenderSprite(new Vector3(20, 20, 15), new Vector2(100, 100), Color.Blue); composer.RenderSprite(new Vector3(10, 10, 0), new Vector2(100, 100), Color.Red); Engine.Renderer.EndFrame(); Runner.VerifyScreenshot(ResultDb.TestDepthFromOtherFrameBuffer); testBuffer.Dispose(); }).WaitOne(); }
public void Draw(RenderComposer composer) { composer.RenderToAndClear(_fbo); composer.SetUseViewMatrix(false); composer.RenderSprite(new Vector3(0, 0, 0), new Vector2(100, 100), new Color(_currentRedValue, (byte)50, (byte)50)); composer.RenderTo(null); composer.SetUseViewMatrix(true); composer.RenderSprite(new Vector3(10, -50, 0), new Vector2(100, 100), new Color(_currentRedValue, (byte)50, (byte)50)); if (_asyncSample) { if (_sampleReq == null || _sampleReq.Finished) { if (_sampleReq != null && _sampleReq.Finished) { _lastColorResult = new Color(_sampleReq.Data[0], _sampleReq.Data[1], _sampleReq.Data[2], _sampleReq.Data[3]); } _sampleReq = _fbo.SampleAsync(new Rectangle(0, 0, 1, 1), OpenGL.PixelFormat.Rgba); } } else { byte[] sampleReq = _fbo.Sample(new Rectangle(0, 0, 1, 1), OpenGL.PixelFormat.Rgba); _lastColorResult = new Color(sampleReq[0], sampleReq[1], sampleReq[2], sampleReq[3]); } composer.RenderSprite(new Vector3(-100, -50, 10), new Vector2(100, 100), _lastColorResult); }
private void RenderMouseOverTiles(RenderComposer composer) { var mouseRect = new Rectangle(Engine.Renderer.Camera.ScreenToWorld(Vector2.Zero), new Vector2(1, 1)) { Center = Engine.Renderer.Camera.ScreenToWorld(Engine.InputManager.MousePosition) }; composer.RenderOutline(new Vector3(mouseRect.Position, 10), mouseRect.Size, Color.Magenta, 2); //composer.PushModelMatrix(Matrix4x4.CreateTranslation(new Vector3(-mouseRect.Position, 0))); composer.RenderTo(_frameBuffer); _drawMemory.Clear(); quadTree.GetObjects(mouseRect, ref _drawMemory); for (var i = 0; i < _drawMemory.Count; i++) { var tile = _drawMemory[i]; var a = composer.GetBatch(); var data = a.GetData(null); data[0].Vertex = tile.Vertex0.ToVec3(); data[0].Color = new Color(50 + i, i, 0).ToUint(); data[1].Vertex = tile.Vertex1.ToVec3(); data[1].Color = new Color(i * 20, i, 0).ToUint(); data[2].Vertex = tile.Vertex2.ToVec3(); data[2].Color = new Color(i * 20, i * 20, 0).ToUint(); data[3].Vertex = tile.Vertex3.ToVec3(); data[3].Color = new Color(i, i * 20, 0).ToUint(); } composer.PushCommand(new ExecCodeCommand() { Func = () => { byte[] pixels = _frameBuffer.Sample(new Rectangle(Engine.InputManager.MousePosition, Vector2.One)); _lastMouseX = pixels[3]; _lastMouseY = pixels[2]; } }); //composer.PopModelMatrix(); composer.RenderTo(null); }
private void RenderSaveSection(RenderComposer composer) { // Saving ImGui.InputText("Name", ref _saveName, 100); ImGui.SameLine(); if (string.IsNullOrEmpty(_saveName)) { ImGui.TextDisabled("Save"); ImGui.SameLine(); ImGui.TextDisabled("SaveToFile"); } else { ImGui.SameLine(); if (ImGui.Button("SaveToFile")) { string saveName = _saveName.ToLower(); if (!saveName.Contains(".anim")) saveName += ".anim"; // Fixups if (AnimController?.MirrorXAnchors != null) { var emptyMirrorAnchors = true; for (var i = 0; i < AnimController.MirrorXAnchors.Length; i++) { if (AnimController.MirrorXAnchors[i] == Vector2.Zero) continue; emptyMirrorAnchors = false; break; } if (emptyMirrorAnchors) AnimController.MirrorXAnchors = null; } try { string saveData; // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (AnimController != null) saveData = XMLFormat.To(AnimController); else saveData = XMLFormat.To(Animation); Engine.AssetLoader.Save(Encoding.UTF8.GetBytes(saveData), saveName); } catch (Exception ex) { Engine.Log.Error(ex); } } if (ImGui.Button("Save Packed Texture")) { string saveName = _saveName.ToLower(); if (!saveName.Contains(".png")) saveName += ".png"; Rectangle[] frames = AnimController != null ? AnimController.AnimTex.Frames : Animation.Frames; var preBinnedFrames = new Rectangle[frames.Length]; Array.Copy(frames, preBinnedFrames, frames.Length); Texture spriteSheetTexture = Animation.Texture; var spacing = 2; for (var i = 0; i < frames.Length; i++) { Rectangle frame = frames[i]; frames[i] = frame.Inflate(spacing, spacing); } Vector2 totalSize = Binning.FitRectangles(frames, true); FrameBuffer texture = new FrameBuffer(totalSize).WithColor(); composer.RenderTo(texture); for (var i = 0; i < frames.Length; i++) { composer.RenderSprite(frames[i].Deflate(spacing, spacing), Color.White, spriteSheetTexture, preBinnedFrames[i]); } composer.RenderTo(null); byte[] pixelsDownload = texture.Sample(new Rectangle(0, 0, totalSize), PixelFormat.Rgba); ImageUtil.FlipImageY(pixelsDownload, (int) totalSize.Y); byte[] pngFile = PngFormat.Encode(pixelsDownload, totalSize, PixelFormat.Rgba); Engine.AssetLoader.Save(pngFile, saveName); } } }
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); } }
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); }
public void VerifyFontRendering() { var fonts = new[] { "Junction-Bold.otf", // Cff "CaslonOS.otf", // Cff 2 (covers other cases) "1980XX.ttf", // Ttf "LatoWeb-Regular.ttf", // Composite "Junction-Bold.otf", // 14 font size "Junction-Bold.otf" // 11 font size }; var names = new[] { "Junction-Bold", "CaslonOS-Regular", "1980XX", "Lato Regular", "Junction-Bold", "Junction-Bold" }; var unitsPerEm = new[] { 1000, 1000, 1024, 2000, 1000, 1000 }; int[] descender = { -250, -360, -128, -426, -250, -250 }; var ascender = new[] { 750, 840, 682, 1974, 750, 750 }; var glyphs = new[] { 270, 279, 141, 2164, 270, 270 }; string[] cachedRender = { ResultDb.EmotionCffAtlas, "", ResultDb.EmotionTtAtlas, ResultDb.EmotionCompositeAtlas, "", "" }; int[] fontSizes = { 17, 17, 17, 17, 14, 11 }; FrameBuffer b = null; for (var i = 0; i < fonts.Length; i++) { Engine.Log.Info($"Running font {fonts[i]} ({i})...", TestRunnerLogger.TestRunnerSrc); ReadOnlyMemory <byte> data = Engine.AssetLoader.Get <OtherAsset>($"Fonts/{fonts[i]}")?.Content ?? ReadOnlyMemory <byte> .Empty; var f = new Font(data); // Verify basic font data. Assert.True(f.Valid); Assert.True(f.FullName == names[i]); Assert.True(f.UnitsPerEm == unitsPerEm[i]); Assert.True(f.Descender == descender[i]); Assert.True(f.Ascender == ascender[i]); Assert.True(f.CharToGlyph.Count == glyphs[i]); // Get atlases. int fontSize = fontSizes[i]; var emotionAtlas = new StbDrawableFontAtlas(f, fontSize, false); Runner.ExecuteAsLoop(_ => { var str = ""; for (uint j = emotionAtlas.Font.FirstCharIndex; j < emotionAtlas.Font.LastCharIndex; j++) { str += (char)j; } emotionAtlas.CacheGlyphs(str); }).WaitOne(); DrawableFontAtlas packedStbAtlas = RenderFontStbPacked(data.ToArray(), fontSize, emotionAtlas.Texture.Size * 3, (int)f.LastCharIndex + 1, f, out StbTrueType.stbtt_fontinfo stbFont); // Compare glyph parsing. CompareMetricsWithStb(f, emotionAtlas, stbFont); // Compare render metrics. foreach (KeyValuePair <char, DrawableGlyph> g in emotionAtlas.Glyphs) { DrawableGlyph glyph = packedStbAtlas.Glyphs[g.Key]; Assert.Equal(glyph.XAdvance, g.Value.XAdvance); var fontGlyph = g.Value.FontGlyph; int width = (int)(MathF.Ceiling(fontGlyph.Max.X * emotionAtlas.RenderScale) - MathF.Floor(fontGlyph.Min.X * emotionAtlas.RenderScale)); int height = (int)(MathF.Ceiling(-fontGlyph.Min.Y * emotionAtlas.RenderScale) - MathF.Floor(-fontGlyph.Max.Y * emotionAtlas.RenderScale)); Assert.Equal(glyph.Width, width); Assert.Equal(glyph.Height, height); } // Check if there's a verified render. if (string.IsNullOrEmpty(cachedRender[i])) { continue; } // Compare with cached render. // ReSharper disable AccessToModifiedClosure Runner.ExecuteAsLoop(_ => { if (b == null) { b = new FrameBuffer(emotionAtlas.Texture.Size).WithColor(); } else { b.Resize(emotionAtlas.Texture.Size, true); } RenderComposer composer = Engine.Renderer.StartFrame(); composer.RenderToAndClear(b); composer.RenderSprite(Vector3.Zero, emotionAtlas.Texture.Size, Color.White, emotionAtlas.Texture); composer.RenderTo(null); Engine.Renderer.EndFrame(); Runner.VerifyScreenshot(cachedRender[i], b); }).WaitOne(); } }