1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-11-22 12:58:33 +01:00

Revert scissor rectangle change since it doesn't support panels with complex transformations

Revert "Use a scissor rectangle for panels in favor of a render target, and marked UiSystem.DrawEarly and Element.DrawEarly as obsolete"

This reverts commit 3c4567e4a1.

Revert "cleaned up DrawEarly documentation references"

This reverts commit dc6c472b84.
This commit is contained in:
Ell 2022-01-30 16:32:45 +01:00
parent dc6c472b84
commit a143aef67c
6 changed files with 54 additions and 25 deletions

View file

@ -35,14 +35,12 @@ Improvements
- Avoid unnecessary panel updates by using an Epsilon comparison when scrolling children - Avoid unnecessary panel updates by using an Epsilon comparison when scrolling children
- Allow setting a default text alignment for paragraphs in UiStyle - Allow setting a default text alignment for paragraphs in UiStyle
- Made custom values of Element.Style persist when a new ui style is set - Made custom values of Element.Style persist when a new ui style is set
- Use a scissor rectangle for panels instead of a render target
Fixes Fixes
- Fixed paragraph links having incorrect hover locations when using special text alignments - Fixed paragraph links having incorrect hover locations when using special text alignments
Removals Removals
- Marked StyleProp equality members as obsolete - Marked StyleProp equality members as obsolete
- Marked UiSystem.DrawEarly and Element.DrawEarly as obsolete
### MLEM.Extended ### MLEM.Extended
Improvements Improvements

View file

@ -22,6 +22,9 @@ protected override void Update(GameTime gameTime) {
} }
protected override void Draw(GameTime gameTime) { protected override void Draw(GameTime gameTime) {
// DrawEarly needs to be called before clearing your graphics context
this.UiSystem.DrawEarly(gameTime, this.SpriteBatch);
this.GraphicsDevice.Clear(Color.CornflowerBlue); this.GraphicsDevice.Clear(Color.CornflowerBlue);
// Do your regular game drawing here // Do your regular game drawing here

View file

@ -114,6 +114,7 @@ namespace MLEM.Startup {
this.PreDraw?.Invoke(this, gameTime); this.PreDraw?.Invoke(this, gameTime);
CoroutineHandler.RaiseEvent(CoroutineEvents.PreDraw); CoroutineHandler.RaiseEvent(CoroutineEvents.PreDraw);
this.UiSystem.DrawEarly(gameTime, this.SpriteBatch);
this.DoDraw(gameTime); this.DoDraw(gameTime);
this.UiSystem.Draw(gameTime, this.SpriteBatch); this.UiSystem.Draw(gameTime, this.SpriteBatch);

View file

@ -985,7 +985,6 @@ namespace MLEM.Ui.Elements {
/// <param name="effect">The effect that is used for drawing</param> /// <param name="effect">The effect that is used for drawing</param>
/// <param name="depthStencilState">The depth stencil state that is used for drawing</param> /// <param name="depthStencilState">The depth stencil state that is used for drawing</param>
/// <param name="matrix">The transformation matrix that is used for drawing</param> /// <param name="matrix">The transformation matrix that is used for drawing</param>
[Obsolete("DrawEarly has been deprecated. There is no replacement, and all drawing code should be placed in Draw.")]
public virtual void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) { public virtual void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
foreach (var child in this.GetRelevantChildren()) { foreach (var child in this.GetRelevantChildren()) {
if (!child.IsHidden) if (!child.IsHidden)

View file

@ -13,15 +13,10 @@ namespace MLEM.Ui.Elements {
/// A panel element to be used inside of a <see cref="UiSystem"/>. /// A panel element to be used inside of a <see cref="UiSystem"/>.
/// The panel is a complex element that displays a box as a background to all of its child elements. /// The panel is a complex element that displays a box as a background to all of its child elements.
/// Additionally, a panel can be set to <see cref="scrollOverflow"/> on construction, which causes all elements that don't fit into the panel to be hidden until scrolled to using a <see cref="ScrollBar"/>. /// Additionally, a panel can be set to <see cref="scrollOverflow"/> on construction, which causes all elements that don't fit into the panel to be hidden until scrolled to using a <see cref="ScrollBar"/>.
/// As this behavior is accomplished using a <see cref="RenderTarget2D"/>, scrolling panels need to have their <see cref="DrawEarly"/> methods called using <see cref="UiSystem.DrawEarly"/>.
/// </summary> /// </summary>
public class Panel : Element { public class Panel : Element {
private static readonly RasterizerState ScissorRasterizer = new RasterizerState {
// use the default cull mode from SpriteBatch, but with scissor test enabled
CullMode = CullMode.CullCounterClockwiseFace,
ScissorTestEnable = true
};
/// <summary> /// <summary>
/// The scroll bar that this panel contains. /// The scroll bar that this panel contains.
/// This is only nonnull if <see cref="scrollOverflow"/> is true. /// This is only nonnull if <see cref="scrollOverflow"/> is true.
@ -56,6 +51,7 @@ namespace MLEM.Ui.Elements {
private readonly List<Element> relevantChildren = new List<Element>(); private readonly List<Element> relevantChildren = new List<Element>();
private readonly bool scrollOverflow; private readonly bool scrollOverflow;
private RenderTarget2D renderTarget;
private bool relevantChildrenDirty; private bool relevantChildrenDirty;
private float scrollBarChildOffset; private float scrollBarChildOffset;
@ -174,32 +170,44 @@ namespace MLEM.Ui.Elements {
public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) { public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
if (this.Texture.HasValue()) if (this.Texture.HasValue())
batch.Draw(this.Texture, this.DisplayArea, this.DrawColor.OrDefault(Color.White) * alpha, this.Scale); batch.Draw(this.Texture, this.DisplayArea, this.DrawColor.OrDefault(Color.White) * alpha, this.Scale);
// if we handle overflow, draw using a scissor rectangle // if we handle overflow, draw using the render target in DrawUnbound
if (this.scrollOverflow) { if (!this.scrollOverflow || this.renderTarget == null) {
batch.End();
batch.GraphicsDevice.ScissorRectangle = (Rectangle) this.GetInnerArea();
// do the usual draw, but with the scissor rectangle applied
batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, ScissorRasterizer, effect, matrix);
base.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, matrix); base.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, matrix);
batch.End();
batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, null, effect, matrix);
} else { } else {
base.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, matrix); // draw the actual render target (don't apply the alpha here because it's already drawn onto with alpha)
batch.Draw(this.renderTarget, this.GetRenderTargetArea(), Color.White);
} }
} }
/// <inheritdoc />
public override void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, DepthStencilState depthStencilState, Effect effect, Matrix matrix) {
this.UpdateAreaIfDirty();
if (this.scrollOverflow && this.renderTarget != null) {
// draw children onto the render target
using (batch.GraphicsDevice.WithRenderTarget(this.renderTarget)) {
batch.GraphicsDevice.Clear(Color.Transparent);
// offset children by the render target's location
var area = this.GetRenderTargetArea();
var trans = Matrix.CreateTranslation(-area.X, -area.Y, 0);
// do the usual draw, but within the render target
batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, null, effect, trans);
base.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, trans);
batch.End();
}
}
base.DrawEarly(time, batch, alpha, blendState, samplerState, depthStencilState, effect, matrix);
}
/// <inheritdoc /> /// <inheritdoc />
public override Element GetElementUnderPos(Vector2 position) { public override Element GetElementUnderPos(Vector2 position) {
// if overflow is handled, don't propagate mouse checks to hidden children // if overflow is handled, don't propagate mouse checks to hidden children
var transformed = this.TransformInverse(position); var transformed = this.TransformInverse(position);
if (this.scrollOverflow && !this.GetInnerArea().Contains(transformed)) if (this.scrollOverflow && !this.GetRenderTargetArea().Contains(transformed))
return !this.IsHidden && this.CanBeMoused && this.DisplayArea.Contains(transformed) ? this : null; return !this.IsHidden && this.CanBeMoused && this.DisplayArea.Contains(transformed) ? this : null;
return base.GetElementUnderPos(position); return base.GetElementUnderPos(position);
} }
private RectangleF GetInnerArea() { private RectangleF GetRenderTargetArea() {
var area = this.ChildPaddedArea; var area = this.ChildPaddedArea;
area.X = this.DisplayArea.X; area.X = this.DisplayArea.X;
area.Width = this.DisplayArea.Width; area.Width = this.DisplayArea.Width;
@ -250,6 +258,26 @@ namespace MLEM.Ui.Elements {
// the scroller height has the same relation to the scroll bar height as the visible area has to the total height of the panel's content // the scroller height has the same relation to the scroll bar height as the visible area has to the total height of the panel's content
var scrollerHeight = Math.Min(this.ChildPaddedArea.Height / childrenHeight / this.Scale, 1) * this.ScrollBar.Area.Height; var scrollerHeight = Math.Min(this.ChildPaddedArea.Height / childrenHeight / this.Scale, 1) * this.ScrollBar.Area.Height;
this.ScrollBar.ScrollerSize = new Vector2(this.ScrollerSize.Value.X, Math.Max(this.ScrollerSize.Value.Y, scrollerHeight)); this.ScrollBar.ScrollerSize = new Vector2(this.ScrollerSize.Value.X, Math.Max(this.ScrollerSize.Value.Y, scrollerHeight));
// update the render target
var targetArea = (Rectangle) this.GetRenderTargetArea();
if (targetArea.Width <= 0 || targetArea.Height <= 0)
return;
if (this.renderTarget == null || targetArea.Width != this.renderTarget.Width || targetArea.Height != this.renderTarget.Height) {
if (this.renderTarget != null)
this.renderTarget.Dispose();
this.renderTarget = targetArea.IsEmpty ? null : new RenderTarget2D(this.System.Game.GraphicsDevice, targetArea.Width, targetArea.Height);
this.relevantChildrenDirty = true;
}
}
/// <inheritdoc />
public override void Dispose() {
if (this.renderTarget != null) {
this.renderTarget.Dispose();
this.renderTarget = null;
}
base.Dispose();
} }
private void SetScrollBarStyle() { private void SetScrollBarStyle() {
@ -263,7 +291,7 @@ namespace MLEM.Ui.Elements {
private void ForceUpdateRelevantChildren() { private void ForceUpdateRelevantChildren() {
this.relevantChildrenDirty = false; this.relevantChildrenDirty = false;
this.relevantChildren.Clear(); this.relevantChildren.Clear();
var visible = this.GetInnerArea(); var visible = this.GetRenderTargetArea();
foreach (var child in this.SortedChildren) { foreach (var child in this.SortedChildren) {
if (child.Area.Intersects(visible)) { if (child.Area.Intersects(visible)) {
this.relevantChildren.Add(child); this.relevantChildren.Add(child);

View file

@ -264,7 +264,6 @@ namespace MLEM.Ui {
/// </summary> /// </summary>
/// <param name="time">The game's time</param> /// <param name="time">The game's time</param>
/// <param name="batch">The sprite batch to use for drawing</param> /// <param name="batch">The sprite batch to use for drawing</param>
[Obsolete("DrawEarly has been deprecated. There is no replacement, so only Draw has to be called.")]
public void DrawEarly(GameTime time, SpriteBatch batch) { public void DrawEarly(GameTime time, SpriteBatch batch) {
this.Metrics.ResetDraws(); this.Metrics.ResetDraws();
this.Stopwatch.Restart(); this.Stopwatch.Restart();
@ -281,6 +280,7 @@ namespace MLEM.Ui {
/// <summary> /// <summary>
/// Draws any <see cref="Element"/>s onto the screen. /// Draws any <see cref="Element"/>s onto the screen.
/// Note that, when using <see cref="Panel"/>s with a scroll bar, <see cref="DrawEarly"/> needs to be called as well.
/// </summary> /// </summary>
/// <param name="time">The game's time</param> /// <param name="time">The game's time</param>
/// <param name="batch">The sprite batch to use for drawing</param> /// <param name="batch">The sprite batch to use for drawing</param>