protected void FitChildInPixelBox(Control child, UIBox2i pixelBox) { var topLeft = pixelBox.TopLeft / UIScale; var bottomRight = pixelBox.BottomRight / UIScale; FitChildInBox(child, new UIBox2(topLeft, bottomRight)); }
/// <summary> /// Blit an image into another, with the specified offset. /// </summary> /// <param name="source">The image to copy data from.</param> /// <param name="sourceRect">The sub section of <see cref="source"/> that will be copied.</param> /// <param name="destinationOffset"> /// The offset into <see cref="destination"/> that data will be copied into. /// </param> /// <param name="destination">The image to copy to.</param> /// <typeparam name="T">The type of pixel stored in the images.</typeparam> public static void Blit <T>(this Image <T> source, UIBox2i sourceRect, Image <T> destination, Vector2i destinationOffset) where T : struct, IPixel <T> { // TODO: Bounds checks. var srcSpan = source.GetPixelSpan(); var dstSpan = destination.GetPixelSpan(); var srcWidth = source.Width; var dstWidth = destination.Width; var(ox, oy) = destinationOffset; for (var y = 0; y < sourceRect.Height; y++) { var sourceRowOffset = srcWidth * (y + sourceRect.Top) + sourceRect.Left; var destRowOffset = dstWidth * (y + oy) + ox; for (var x = 0; x < sourceRect.Width; x++) { var pixel = srcSpan[x + sourceRowOffset]; dstSpan[x + destRowOffset] = pixel; } } }
public HandsGui() { IoCManager.InjectDependencies(this); _handR = new UIBox2i(0, 0, BoxSize, BoxSize); _handL = _handR.Translated((BoxSize + BoxSpacing, 0)); MouseFilter = MouseFilterMode.Stop; TextureHandLeft = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_l.png"); TextureHandRight = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_r.png"); TextureHandActive = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_active.png"); TexturesCooldownOverlay = new Texture[CooldownLevels]; for (var i = 0; i < CooldownLevels; i++) { TexturesCooldownOverlay[i] = _resourceCache.GetTexture($"/Textures/UserInterface/Inventory/cooldown-{i}.png"); } AddChild(new TextureRect { MouseFilter = MouseFilterMode.Ignore, Texture = TextureHandLeft, Size = _handL.Size, Position = _handL.TopLeft, TextureScale = (2, 2) });
/// <summary> /// Blit an image into another, with the specified offset. /// </summary> /// <param name="source">The image to copy data from.</param> /// <param name="sourceRect">The sub section of <see cref="source"/> that will be copied.</param> /// <param name="destinationOffset"> /// The offset into <see cref="destination"/> that data will be copied into. /// </param> /// <param name="destination">The image to copy to.</param> /// <typeparam name="T">The type of pixel stored in the images.</typeparam> public static void Blit <T>(this Image <T> source, UIBox2i sourceRect, Image <T> destination, Vector2i destinationOffset) where T : unmanaged, IPixel <T> { // TODO: Bounds checks. Blit(source.GetPixelSpan(), source.Width, sourceRect, destination, destinationOffset); }
private void OnPostDrawUIRoot(PostDrawUIRootEventArgs eventArgs) { if (SelectedControl == null || eventArgs.Root != SelectedControl.Root) { return; } var rect = UIBox2i.FromDimensions(SelectedControl.GlobalPixelPosition, SelectedControl.PixelSize); eventArgs.DrawingHandle.DrawRect(rect, Color.Cyan.WithAlpha(0.35f)); }
protected override void Draw(DrawingHandleScreen handle) { base.Draw(handle); handle.UseShader(Shader); var leftOffset = 2 * HealthBarScale; var box = new UIBox2i( leftOffset, -2 + 2 * HealthBarScale, leftOffset + (int)(XPixelDiff * Ratio * UIScale), -2); handle.DrawRect(box, Color); }
public static void Blit <T>(this ReadOnlySpan <T> source, int sourceWidth, UIBox2i sourceRect, Image <T> destination, Vector2i destinationOffset) where T : unmanaged, IPixel <T> { var dstSpan = destination.GetPixelSpan(); var dstWidth = destination.Width; var srcHeight = sourceRect.Height; var srcWidth = sourceRect.Width; var(ox, oy) = destinationOffset; for (var y = 0; y < srcHeight; y++) { var sourceRowOffset = sourceWidth * (y + sourceRect.Top) + sourceRect.Left; var destRowOffset = dstWidth * (y + oy) + ox; var srcRow = source[sourceRowOffset..(sourceRowOffset + srcWidth)];
public static void Blit <T>(this ReadOnlySpan <T> source, int sourceWidth, UIBox2i sourceRect, Image <T> destination, Vector2i destinationOffset) where T : unmanaged, IPixel <T> { var dstSpan = destination.GetPixelSpan(); var dstWidth = destination.Width; var(ox, oy) = destinationOffset; for (var y = 0; y < sourceRect.Height; y++) { var sourceRowOffset = sourceWidth * (y + sourceRect.Top) + sourceRect.Left; var destRowOffset = dstWidth * (y + oy) + ox; for (var x = 0; x < sourceRect.Width; x++) { var pixel = source[x + sourceRowOffset]; dstSpan[x + destRowOffset] = pixel; } } }
public HandsGui() { IoCManager.InjectDependencies(this); ToolTip = _loc.GetString("Your hands"); _handR = new UIBox2i(0, 0, BoxSize, BoxSize); _handL = _handR.Translated((BoxSize + BoxSpacing, 0)); MouseFilter = MouseFilterMode.Stop; TextureHandLeft = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_l.png"); TextureHandRight = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_r.png"); TextureHandActive = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_active.png"); AddChild(new TextureRect { MouseFilter = MouseFilterMode.Ignore, Texture = TextureHandLeft, Size = _handL.Size, Position = _handL.TopLeft, TextureScale = (2, 2) });
protected override void Initialize() { base.Initialize(); var resMgr = IoCManager.Resolve <IResourceCache>(); var handsBoxTexture = resMgr.GetResource <TextureResource>("/Textures/UserInterface/handsbox.png"); handBox = new StyleBoxTexture() { Texture = handsBoxTexture, }; handBox.SetPatchMargin(StyleBox.Margin.All, 6); inactiveHandBox = new StyleBoxTexture(handBox) { Modulate = _inactiveColor, }; SetMarginsPreset(LayoutPreset.CenterBottom); SetAnchorPreset(LayoutPreset.CenterBottom); _handL = new UIBox2i(0, 0, BOX_SIZE, BOX_SIZE); _handR = _handL.Translated(new Vector2i(BOX_SIZE + BOX_SPACING, 0)); MouseFilter = MouseFilterMode.Stop; LeftSpriteView = new SpriteView { MouseFilter = MouseFilterMode.Ignore }; AddChild(LeftSpriteView); LeftSpriteView.Size = _handL.Size; LeftSpriteView.Position = _handL.TopLeft; RightSpriteView = new SpriteView { MouseFilter = MouseFilterMode.Ignore }; AddChild(RightSpriteView); RightSpriteView.Size = _handR.Size; RightSpriteView.Position = _handR.TopLeft; }
protected override void Initialize() { base.Initialize(); var _resMgr = IoCManager.Resolve <IResourceCache>(); var handsBoxTexture = _resMgr.GetResource <TextureResource>("/Textures/UserInterface/handsbox.png"); handBox = new StyleBoxTexture() { Texture = handsBoxTexture, }; handBox.SetMargin(StyleBox.Margin.All, 6); inactiveHandBox = new StyleBoxTexture(handBox) { Modulate = _inactiveColor, }; SetMarginsPreset(LayoutPreset.CenterBottom); SetAnchorPreset(LayoutPreset.CenterBottom); handL = new UIBox2i(0, 0, BOX_SIZE, BOX_SIZE); handR = handL.Translated(new Vector2i(BOX_SIZE + BOX_SPACING, 0)); SS14.Shared.Log.Logger.Debug($"{handL}, {handR}"); MouseFilter = MouseFilterMode.Stop; }
protected override void LayoutUpdateOverride() { var separation = (int)(ActualSeparation * UIScale); // Step one: figure out the sizes of all our children and whether they want to stretch. var sizeList = new List <(Control control, int minSize, int finalSize, bool stretch)>(ChildCount); var totalStretchRatio = 0f; // Amount of space not available for stretching. var stretchMin = 0; foreach (var child in Children) { if (!child.Visible) { continue; } var(minX, minY) = child.CombinedPixelMinimumSize; int minSize; bool stretch; if (Vertical) { minSize = minY; stretch = (child.SizeFlagsVertical & SizeFlags.Expand) == SizeFlags.Expand; } else { minSize = minX; stretch = (child.SizeFlagsHorizontal & SizeFlags.Expand) == SizeFlags.Expand; } if (!stretch) { stretchMin += minSize; } else { totalStretchRatio += child.SizeFlagsStretchRatio; } sizeList.Add((child, minSize, minSize, stretch)); } var stretchMax = Vertical ? PixelHeight : PixelWidth; stretchMax -= separation * (ChildCount - 1); // This is the amount of space allocated for stretchable children. var stretchAvail = Math.Max(0, stretchMax - stretchMin); // Step two: figure out which that want to stretch need to suck it, // because due to their stretch ratio they would be smaller than minSize. // Treat those as non-stretching. for (var i = 0; i < sizeList.Count; i++) { var(control, minSize, _, stretch) = sizeList[i]; if (!stretch) { continue; } var share = (int)(stretchAvail * (control.SizeFlagsStretchRatio / totalStretchRatio)); if (share < minSize) { sizeList[i] = (control, minSize, minSize, false); stretchAvail -= minSize; totalStretchRatio -= control.SizeFlagsStretchRatio; } } // Step three: allocate space for all the stretchable children. var stretchingAtAll = false; for (var i = 0; i < sizeList.Count; i++) { var(control, minSize, _, stretch) = sizeList[i]; if (!stretch) { continue; } stretchingAtAll = true; var share = (int)(stretchAvail * (control.SizeFlagsStretchRatio / totalStretchRatio)); sizeList[i] = (control, minSize, share, false); } // Step four: actually lay them out one by one. var offset = 0; if (!stretchingAtAll) { switch (Align) { case AlignMode.Begin: break; case AlignMode.Center: offset = stretchAvail / 2; break; case AlignMode.End: offset = stretchAvail; break; default: throw new ArgumentOutOfRangeException(); } } var first = true; foreach (var(control, _, size, _) in sizeList) { if (!first) { offset += separation; } first = false; UIBox2i targetBox; if (Vertical) { targetBox = new UIBox2i(0, offset, PixelWidth, offset + size); } else { targetBox = new UIBox2i(offset, 0, offset + size, PixelHeight); } FitChildInPixelBox(control, targetBox); offset += size; } }
protected override Vector2 ArrangeOverride(Vector2 finalSize) { var separation = (int)(ActualSeparation * UIScale); #region Scroll var cHeight = _totalHeight; var vBarSize = _vScrollBar.DesiredSize.X; var(sWidth, sHeight) = finalSize; try { // Suppress events to avoid weird recursion. _suppressScrollValueChanged = true; if (sHeight < cHeight) { sWidth -= vBarSize; } if (sHeight < cHeight) { _vScrollBar.Visible = true; _vScrollBar.Page = sHeight; _vScrollBar.MaxValue = cHeight; } else { _vScrollBar.Visible = false; } } finally { _suppressScrollValueChanged = false; } if (_vScrollBar.Visible) { _vScrollBar.Arrange(UIBox2.FromDimensions(Vector2.Zero, finalSize)); } #endregion #region Rebuild Children /* * Example: * * var _itemHeight = 32; * var separation = 3; * 32 | 32 | Control.Size.Y 0 * 35 | 3 | Padding * 67 | 32 | Control.Size.Y 1 * 70 | 3 | Padding * 102 | 32 | Control.Size.Y 2 * 105 | 3 | Padding * 137 | 32 | Control.Size.Y 3 * * If viewport height is 60 * visible should be 2 items (start = 0, end = 1) * * scroll.Y = 11 * visible should be 3 items (start = 0, end = 2) * * start expected: 11 (item: 0) * var start = (int) (scroll.Y * * if (scroll == 32) then { start = 1 } * var start = (int) (scroll.Y + separation / (_itemHeight + separation)); * var start = (int) (32 + 3 / (32 + 3)); * var start = (int) (35 / 35); * var start = (int) (1); * * scroll = 0, height = 36 * if (scroll + height == 36) then { end = 2 } * var end = (int) Math.Ceiling(scroll.Y + height / (_itemHeight + separation)); * var end = (int) Math.Ceiling(0 + 36 / (32 + 3)); * var end = (int) Math.Ceiling(36 / 35); * var end = (int) Math.Ceiling(1.02857); * var end = (int) 2; * */ var scroll = GetScrollValue(); var oldTopIndex = _topIndex; _topIndex = (int)((scroll.Y + separation) / (_itemHeight + separation)); if (_topIndex != oldTopIndex) { _updateChildren = true; } var oldBottomIndex = _bottomIndex; _bottomIndex = (int)Math.Ceiling((scroll.Y + Height) / (_itemHeight + separation)); _bottomIndex = Math.Min(_bottomIndex, _count); if (_bottomIndex != oldBottomIndex) { _updateChildren = true; } // When scrolling only rebuild visible list when a new item should be visible if (_updateChildren) { _updateChildren = false; foreach (var child in Children.ToArray()) { if (child == _vScrollBar) { continue; } RemoveChild(child); } if (_entityUids != null) { for (var i = _topIndex; i < _bottomIndex; i++) { var entity = _entityUids[i]; var button = new EntityContainerButton(entity); button.OnPressed += OnItemPressed; GenerateItem?.Invoke(entity, button); AddChild(button); } } _vScrollBar.SetPositionLast(); } #endregion #region Layout Children // Use pixel position var pixelWidth = (int)(sWidth * UIScale); var offset = (int)-((scroll.Y - _topIndex * (_itemHeight + separation)) * UIScale); var first = true; foreach (var child in Children) { if (child == _vScrollBar) { continue; } if (!first) { offset += separation; } first = false; var size = child.DesiredPixelSize.Y; var targetBox = new UIBox2i(0, offset, pixelWidth, offset + size); child.ArrangePixel(targetBox); offset += size; } #endregion return(finalSize); }
public override void Load(IResourceCache cache, ResourcePath path) { var manifestPath = path / "meta.json"; string manifestContents; using (var manifestFile = cache.ContentFileRead(manifestPath)) using (var reader = new StreamReader(manifestFile)) { manifestContents = reader.ReadToEnd(); } #if DEBUG if (RSISchema != null) { var errors = RSISchema.Validate(manifestContents); if (errors.Count != 0) { Logger.Error($"Unable to load RSI from '{path}', {errors.Count} errors:"); foreach (var error in errors) { Logger.Error("{0}", error.ToString()); } throw new RSILoadException($"{errors.Count} errors while loading RSI. See console."); } } #endif // Ok schema validated just fine. var manifestJson = JObject.Parse(manifestContents); var toAtlas = new List <(Image <Rgba32> src, Texture[][] output, int[][] indices, int totalFrameCount)>(); var metaData = ParseMetaData(manifestJson); var frameSize = metaData.Size; var rsi = new RSI(frameSize); // Do every state. foreach (var stateObject in metaData.States) { // Load image from disk. var texPath = path / (stateObject.StateId + ".png"); var image = Image.Load(cache.ContentFileRead(texPath)); var sheetSize = new Vector2i(image.Width, image.Height); if (sheetSize.X % frameSize.X != 0 || sheetSize.Y % frameSize.Y != 0) { throw new RSILoadException("State image size is not a multiple of the icon size."); } // Load all frames into a list so we can operate on it more sanely. var frameCount = stateObject.Delays.Sum(delayList => delayList.Length); var(foldedDelays, foldedIndices) = FoldDelays(stateObject.Delays); var textures = new Texture[foldedIndices.Length][]; for (var i = 0; i < textures.Length; i++) { textures[i] = new Texture[foldedIndices[0].Length]; } var state = new RSI.State(frameSize, stateObject.StateId, stateObject.DirType, foldedDelays, textures); rsi.AddState(state); toAtlas.Add((image, textures, foldedIndices, frameCount)); } // Poorly hacked in texture atlas support here. { var totalFrameCount = toAtlas.Sum(p => p.totalFrameCount); // Generate atlas. var dimensionX = (int)MathF.Ceiling(MathF.Sqrt(totalFrameCount)); var dimensionY = (int)MathF.Ceiling((float)totalFrameCount / dimensionX); using var sheet = new Image <Rgba32>(dimensionX * frameSize.X, dimensionY * frameSize.Y); var sheetIndex = 0; foreach (var(src, _, _, frameCount) in toAtlas) { // Blit all the frames over. for (var i = 0; i < frameCount; i++) { var srcWidth = (src.Width / frameSize.X); var srcColumn = i % srcWidth; var srcRow = i / srcWidth; var srcPos = (srcColumn * frameSize.X, srcRow *frameSize.Y); var sheetColumn = (sheetIndex + i) % dimensionX; var sheetRow = (sheetIndex + i) / dimensionX; var sheetPos = (sheetColumn * frameSize.X, sheetRow *frameSize.Y); var srcBox = UIBox2i.FromDimensions(srcPos, frameSize); src.Blit(srcBox, sheet, sheetPos); } sheetIndex += frameCount; } // Load atlas. var texture = Texture.LoadFromImage(sheet, path.ToString()); var sheetOffset = 0; foreach (var(src, output, indices, frameCount) in toAtlas) { for (var i = 0; i < indices.Length; i++) { var dirIndices = indices[i]; var dirOutput = output[i]; for (var j = 0; j < dirIndices.Length; j++) { var index = sheetOffset + dirIndices[j]; var sheetColumn = index % dimensionX; var sheetRow = index / dimensionX; var sheetPos = (sheetColumn * frameSize.X, sheetRow *frameSize.Y); dirOutput[j] = new AtlasTexture(texture, UIBox2.FromDimensions(sheetPos, frameSize)); } } sheetOffset += frameCount; } } foreach (var(image, _, _, _) in toAtlas) { image.Dispose(); } RSI = rsi; }
private static void _render(IRenderHandle renderHandle, Control control, Vector2i position, Color modulate, UIBox2i?scissorBox) { if (!control.Visible) { return; } // Manual clip test with scissor region as optimization. var controlBox = UIBox2i.FromDimensions(position, control.PixelSize); if (scissorBox != null) { var clipMargin = control.RectDrawClipMargin; var clipTestBox = new UIBox2i(controlBox.Left - clipMargin, controlBox.Top - clipMargin, controlBox.Right + clipMargin, controlBox.Bottom + clipMargin); if (!scissorBox.Value.Intersects(clipTestBox)) { return; } } var handle = renderHandle.DrawingHandleScreen; handle.SetTransform(position, Angle.Zero, Vector2.One); modulate *= control.Modulate; handle.Modulate = modulate * control.ActualModulateSelf; var clip = control.RectClipContent; var scissorRegion = scissorBox; if (clip) { scissorRegion = controlBox; if (scissorBox != null) { // Make the final scissor region a sub region of scissorBox var s = scissorBox.Value; var result = s.Intersection(scissorRegion.Value); if (result == null) { // Uhm... No intersection so... don't draw anything at all? return; } scissorRegion = result.Value; } renderHandle.SetScissor(scissorRegion); } control.DrawInternal(renderHandle); foreach (var child in control.Children) { _render(renderHandle, child, position + child.PixelPosition, modulate, scissorRegion); } if (clip) { renderHandle.SetScissor(scissorBox); } }
public void Render() { // Basic pre-render busywork. // Clear screen to black. ClearFramebuffer(Color.Black); // Update shared UBOs. _updateUniformConstants(); _setSpace(CurrentSpace.ScreenSpace); // Short path to render only the splash. if (_drawingSplash) { _drawSplash(_renderHandle); _flushRenderHandle(_renderHandle); _window.SwapBuffers(); return; } void RenderOverlays(OverlaySpace space) { using (DebugGroup($"Overlays: {space}")) { foreach (var overlay in _overlayManager.AllOverlays .Where(o => o.Space == space) .OrderBy(o => o.ZIndex)) { overlay.ClydeRender(_renderHandle); } _flushRenderHandle(_renderHandle); } } if (!_lite) { RenderOverlays(OverlaySpace.ScreenSpaceBelowWorld); _setSpace(CurrentSpace.WorldSpace); using (DebugGroup("Lights")) { _drawLights(); } using (DebugGroup("Grids")) { _drawGrids(); } using (DebugGroup("Entities")) { var entityList = new List <SpriteComponent>(100); var map = _eyeManager.CurrentMap; foreach (var entity in _entityManager.GetEntities()) { if (!entity.Transform.IsMapTransform || entity.Transform.MapID != map || !entity.TryGetComponent(out SpriteComponent sprite) || !sprite.Visible) { continue; } entityList.Add(sprite); } entityList.Sort((a, b) => { var cmp = ((int)a.DrawDepth).CompareTo((int)b.DrawDepth); if (cmp != 0) { return(cmp); } cmp = a.RenderOrder.CompareTo(b.RenderOrder); if (cmp != 0) { return(cmp); } return(a.Owner.Uid.CompareTo(b.Owner.Uid)); }); foreach (var sprite in entityList) { Vector2i roundedPos = default; if (sprite.PostShader != null) { _renderHandle.UseRenderTarget(EntityPostRenderTarget); _renderHandle.Clear(new Color()); // Calculate viewport so that the entity thinks it's drawing to the same position, // which is necessary for light application, // but it's ACTUALLY drawing into the center of the render target. var spritePos = sprite.Owner.Transform.WorldPosition; var screenPos = _eyeManager.WorldToScreen(spritePos); var(roundedX, roundedY) = roundedPos = (Vector2i)screenPos; var flippedPos = new Vector2i(roundedX, ScreenSize.Y - roundedY); flippedPos -= EntityPostRenderTarget.Size / 2; _renderHandle.Viewport(Box2i.FromDimensions(-flippedPos, ScreenSize)); } sprite.OpenGLRender(_renderHandle.DrawingHandleWorld); if (sprite.PostShader != null) { _renderHandle.UseRenderTarget(null); _renderHandle.Viewport(Box2i.FromDimensions(Vector2i.Zero, ScreenSize)); _renderHandle.UseShader(sprite.PostShader); _renderHandle.SetSpace(CurrentSpace.ScreenSpace); _renderHandle.SetModelTransform(Matrix3.Identity); var rounded = roundedPos - EntityPostRenderTarget.Size / 2; var box = UIBox2i.FromDimensions(rounded, EntityPostRenderTarget.Size); _renderHandle.DrawTexture(EntityPostRenderTarget.Texture, box.BottomLeft, box.TopRight, Color.White, null, 0); _renderHandle.SetSpace(CurrentSpace.WorldSpace); _renderHandle.UseShader(null); } } _flushRenderHandle(_renderHandle); } RenderOverlays(OverlaySpace.WorldSpace); _lightingReady = false; _setSpace(CurrentSpace.ScreenSpace); RenderOverlays(OverlaySpace.ScreenSpace); } using (DebugGroup("UI")) { _userInterfaceManager.Render(_renderHandle); _flushRenderHandle(_renderHandle); } // And finally, swap those buffers! _window.SwapBuffers(); }
internal static Vector2i ClampSubRegion(Vector2i size, UIBox2i?subRegionSpecified) { return(subRegionSpecified == null ? size : UIBox2i.FromDimensions(Vector2i.Zero, size).Intersection(subRegionSpecified.Value)?.Size ?? default); }
public void Render() { _debugStats.Reset(); // Basic pre-render busywork. // Clear screen to black. ClearFramebuffer(Color.Black); // Update shared UBOs. _updateUniformConstants(); _setSpace(CurrentSpace.ScreenSpace); // Short path to render only the splash. if (_drawingSplash) { _drawSplash(_renderHandle); _flushRenderHandle(_renderHandle); _window.SwapBuffers(); return; } void RenderOverlays(OverlaySpace space) { using (DebugGroup($"Overlays: {space}")) { foreach (var overlay in _overlayManager.AllOverlays .Where(o => o.Space == space) .OrderBy(o => o.ZIndex)) { overlay.ClydeRender(_renderHandle); } _flushRenderHandle(_renderHandle); } } if (!_lite) { RenderOverlays(OverlaySpace.ScreenSpaceBelowWorld); _setSpace(CurrentSpace.WorldSpace); // Calculate world-space AABB for camera, to cull off-screen things. var eye = _eyeManager.CurrentEye; var worldBounds = Box2.CenteredAround(eye.Position.Position, _screenSize / EyeManager.PIXELSPERMETER * eye.Zoom); using (DebugGroup("Lights")) { _drawLights(worldBounds); } using (DebugGroup("Grids")) { _drawGrids(worldBounds); } using (DebugGroup("Entities")) { _sortingSpritesList.Clear(); var map = _eyeManager.CurrentMap; // So we could calculate the correct size of the entities based on the contents of their sprite... // Or we can just assume that no entity is larger than 10x10 and get a stupid easy check. // TODO: Make this check more accurate. var widerBounds = worldBounds.Enlarged(5); foreach (var sprite in _componentManager.GetAllComponents <SpriteComponent>()) { var entity = sprite.Owner; if (!entity.Transform.IsMapTransform || entity.Transform.MapID != map || !widerBounds.Contains(entity.Transform.WorldPosition) || !sprite.Visible) { continue; } _sortingSpritesList.Add(sprite); } _sortingSpritesList.Sort((a, b) => { var cmp = ((int)a.DrawDepth).CompareTo((int)b.DrawDepth); if (cmp != 0) { return(cmp); } cmp = a.RenderOrder.CompareTo(b.RenderOrder); if (cmp != 0) { return(cmp); } return(a.Owner.Uid.CompareTo(b.Owner.Uid)); }); foreach (var sprite in _sortingSpritesList) { Vector2i roundedPos = default; if (sprite.PostShader != null) { _renderHandle.UseRenderTarget(EntityPostRenderTarget); _renderHandle.Clear(new Color()); // Calculate viewport so that the entity thinks it's drawing to the same position, // which is necessary for light application, // but it's ACTUALLY drawing into the center of the render target. var spritePos = sprite.Owner.Transform.WorldPosition; var screenPos = _eyeManager.WorldToScreen(spritePos); var(roundedX, roundedY) = roundedPos = (Vector2i)screenPos; var flippedPos = new Vector2i(roundedX, ScreenSize.Y - roundedY); flippedPos -= EntityPostRenderTarget.Size / 2; _renderHandle.Viewport(Box2i.FromDimensions(-flippedPos, ScreenSize)); } sprite.OpenGLRender(_renderHandle.DrawingHandleWorld); if (sprite.PostShader != null) { _renderHandle.UseRenderTarget(null); _renderHandle.Viewport(Box2i.FromDimensions(Vector2i.Zero, ScreenSize)); _renderHandle.UseShader(sprite.PostShader); _renderHandle.SetSpace(CurrentSpace.ScreenSpace); _renderHandle.SetModelTransform(Matrix3.Identity); var rounded = roundedPos - EntityPostRenderTarget.Size / 2; var box = UIBox2i.FromDimensions(rounded, EntityPostRenderTarget.Size); _renderHandle.DrawTexture(EntityPostRenderTarget.Texture, box.BottomLeft, box.TopRight, Color.White, null, 0); _renderHandle.SetSpace(CurrentSpace.WorldSpace); _renderHandle.UseShader(null); } } _flushRenderHandle(_renderHandle); } RenderOverlays(OverlaySpace.WorldSpace); _lightingReady = false; _setSpace(CurrentSpace.ScreenSpace); RenderOverlays(OverlaySpace.ScreenSpace); } using (DebugGroup("UI")) { _userInterfaceManager.Render(_renderHandle); _flushRenderHandle(_renderHandle); } // And finally, swap those buffers! _window.SwapBuffers(); }
protected override void FrameUpdate(FrameEventArgs args) { if (!VisibleInTree) { return; } var stringBuilder = new StringBuilder(); var mouseScreenPos = _inputManager.MouseScreenPosition; var screenSize = _displayManager.ScreenSize; MapCoordinates mouseWorldMap; EntityCoordinates mouseGridPos; TileRef tile; mouseWorldMap = _eyeManager.ScreenToMap(mouseScreenPos); if (_mapManager.TryFindGridAt(mouseWorldMap, out var mouseGrid)) { mouseGridPos = mouseGrid.MapToGrid(mouseWorldMap); tile = mouseGrid.GetTileRef(mouseGridPos); } else { mouseGridPos = new EntityCoordinates(_mapManager.GetMapEntityId(mouseWorldMap.MapId), mouseWorldMap.Position); tile = new TileRef(mouseWorldMap.MapId, GridId.Invalid, mouseGridPos.ToVector2i(_entityManager, _mapManager), Tile.Empty); } var controlHovered = UserInterfaceManager.CurrentlyHovered; stringBuilder.AppendFormat(@"Positioning Debug: Screen Size: {0} Mouse Pos: Screen: {1} {2} {3} {4} GUI: {5}", screenSize, mouseScreenPos, mouseWorldMap, mouseGridPos, tile, controlHovered); stringBuilder.AppendLine("\nAttached Entity:"); if (_playerManager.LocalPlayer?.ControlledEntity == null) { stringBuilder.AppendLine("No attached entity."); } else { var entityTransform = _playerManager.LocalPlayer.ControlledEntity.Transform; var playerWorldOffset = entityTransform.MapPosition; var playerScreen = _eyeManager.WorldToScreen(playerWorldOffset.Position); var playerCoordinates = _playerManager.LocalPlayer.ControlledEntity.Transform.Coordinates; stringBuilder.AppendFormat(@" Screen: {0} {1} {2} EntId: {3} GridID: {4}", playerScreen, playerWorldOffset, playerCoordinates, entityTransform.Owner.Uid, entityTransform.GridID); } if (controlHovered != null) { _uiBox = UIBox2i.FromDimensions(controlHovered.GlobalPixelPosition, controlHovered.PixelSize); } _contents.Text = stringBuilder.ToString(); MinimumSizeChanged(); }