-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c7ff2a5
commit f8d4d07
Showing
11 changed files
with
509 additions
and
18 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,286 @@ | ||
// Copied and modified from osu-framework | ||
|
||
using System; | ||
using osu.Framework.Graphics.Primitives; | ||
using osu.Framework.Graphics.Textures; | ||
using osuTK; | ||
using osu.Framework.Graphics.Shaders; | ||
using osu.Framework.Allocation; | ||
using System.Collections.Generic; | ||
using osu.Framework.Caching; | ||
using osuTK.Graphics; | ||
using osuTK.Graphics.ES30; | ||
|
||
namespace osu.Framework.Graphics.Lines { // BUG lines freak out | ||
public partial class VariableWidthPath : Drawable, IBufferedDrawable { | ||
public IShader RoundedTextureShader { get; private set; } | ||
public IShader TextureShader { get; private set; } | ||
private IShader pathShader; | ||
|
||
public VariableWidthPath () { | ||
AutoSizeAxes = Axes.Both; | ||
} | ||
|
||
[BackgroundDependencyLoader] | ||
private void load ( ShaderManager shaders ) { | ||
RoundedTextureShader = shaders.Load( VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED ); | ||
TextureShader = shaders.Load( VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE ); | ||
pathShader = shaders.Load( VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE ); | ||
} | ||
|
||
private readonly List<Vector2> vertices = new List<Vector2>(); | ||
|
||
public IReadOnlyList<Vector2> Vertices { | ||
get => vertices; | ||
set { | ||
vertices.Clear(); | ||
vertices.AddRange( value ); | ||
|
||
vertexBoundsCache.Invalidate(); | ||
segmentsCache.Invalidate(); | ||
|
||
Invalidate( Invalidation.DrawSize ); | ||
} | ||
} | ||
|
||
private float startPathRadius = 10f; | ||
private float endPathRadius = 10f; | ||
|
||
/// <summary> | ||
/// How wide this path is on each side of the line. | ||
/// </summary> | ||
/// <remarks> | ||
/// The actual width of the path is twice the PathRadius. | ||
/// </remarks> | ||
public float StartPathRadius { | ||
get => startPathRadius; | ||
set { | ||
if ( startPathRadius == value ) return; | ||
|
||
startPathRadius = value; | ||
|
||
vertexBoundsCache.Invalidate(); | ||
segmentsCache.Invalidate(); | ||
|
||
Invalidate( Invalidation.DrawSize ); | ||
} | ||
} | ||
public float EndPathRadius { | ||
get => endPathRadius; | ||
set { | ||
if ( endPathRadius == value ) return; | ||
|
||
endPathRadius = value; | ||
|
||
vertexBoundsCache.Invalidate(); | ||
segmentsCache.Invalidate(); | ||
|
||
Invalidate( Invalidation.DrawSize ); | ||
} | ||
} | ||
/// <summary> | ||
/// Path radius at t c <0;1> | ||
/// </summary> | ||
public float PathRadiusAt ( float t ) | ||
=> startPathRadius + ( endPathRadius - startPathRadius ) * t; | ||
private float RadiusAtVertice ( int vertice ) | ||
=> PathRadiusAt( vertice / (float)( vertices.Count - 1 ) ); | ||
|
||
public override Axes RelativeSizeAxes { | ||
get => base.RelativeSizeAxes; | ||
set { | ||
if ( ( AutoSizeAxes & value ) != 0 ) | ||
throw new InvalidOperationException( "No axis can be relatively sized and automatically sized at the same time." ); | ||
|
||
base.RelativeSizeAxes = value; | ||
} | ||
} | ||
|
||
private Axes autoSizeAxes; | ||
|
||
/// <summary> | ||
/// Controls which <see cref="Axes"/> are automatically sized w.r.t. the bounds of the vertices. | ||
/// It is not allowed to manually set <see cref="Size"/> (or <see cref="Width"/> / <see cref="Height"/>) | ||
/// on any <see cref="Axes"/> which are automatically sized. | ||
/// </summary> | ||
public virtual Axes AutoSizeAxes { | ||
get => autoSizeAxes; | ||
set { | ||
if ( value == autoSizeAxes ) | ||
return; | ||
|
||
if ( ( RelativeSizeAxes & value ) != 0 ) | ||
throw new InvalidOperationException( "No axis can be relatively sized and automatically sized at the same time." ); | ||
|
||
autoSizeAxes = value; | ||
OnSizingChanged(); | ||
} | ||
} | ||
|
||
public override float Width { | ||
get { | ||
if ( AutoSizeAxes.HasFlag( Axes.X ) ) | ||
return base.Width = vertexBounds.Width; | ||
|
||
return base.Width; | ||
} | ||
set { | ||
if ( ( AutoSizeAxes & Axes.X ) != 0 ) | ||
throw new InvalidOperationException( $"The width of a {nameof( Path )} with {nameof( AutoSizeAxes )} can not be set manually." ); | ||
|
||
base.Width = value; | ||
} | ||
} | ||
|
||
public override float Height { | ||
get { | ||
if ( AutoSizeAxes.HasFlag( Axes.Y ) ) | ||
return base.Height = vertexBounds.Height; | ||
|
||
return base.Height; | ||
} | ||
set { | ||
if ( ( AutoSizeAxes & Axes.Y ) != 0 ) | ||
throw new InvalidOperationException( $"The height of a {nameof( Path )} with {nameof( AutoSizeAxes )} can not be set manually." ); | ||
|
||
base.Height = value; | ||
} | ||
} | ||
|
||
public override Vector2 Size { | ||
get { | ||
if ( AutoSizeAxes != Axes.None ) | ||
return base.Size = vertexBounds.Size; | ||
|
||
return base.Size; | ||
} | ||
set { | ||
if ( ( AutoSizeAxes & Axes.Both ) != 0 ) | ||
throw new InvalidOperationException( $"The Size of a {nameof( Path )} with {nameof( AutoSizeAxes )} can not be set manually." ); | ||
|
||
base.Size = value; | ||
} | ||
} | ||
|
||
private readonly Cached<RectangleF> vertexBoundsCache = new Cached<RectangleF>(); | ||
|
||
private RectangleF vertexBounds { | ||
get { | ||
if ( vertexBoundsCache.IsValid ) | ||
return vertexBoundsCache.Value; | ||
|
||
if ( vertices.Count > 0 ) { | ||
float minX = 0; | ||
float minY = 0; | ||
float maxX = 0; | ||
float maxY = 0; | ||
|
||
int i = 0; | ||
|
||
foreach ( var v in vertices ) { | ||
var pathRadius = RadiusAtVertice( i++ ); | ||
|
||
minX = Math.Min( minX, v.X - pathRadius ); | ||
minY = Math.Min( minY, v.Y - pathRadius ); | ||
maxX = Math.Max( maxX, v.X + pathRadius ); | ||
maxY = Math.Max( maxY, v.Y + pathRadius ); | ||
} | ||
|
||
return vertexBoundsCache.Value = new RectangleF( minX, minY, maxX - minX, maxY - minY ); | ||
} | ||
|
||
return vertexBoundsCache.Value = new RectangleF( 0, 0, 0, 0 ); | ||
} | ||
} | ||
|
||
public override bool ReceivePositionalInputAt ( Vector2 screenSpacePos ) { | ||
var localPos = ToLocalSpace( screenSpacePos ); | ||
|
||
int i = 0; | ||
foreach ( var t in segments ) { | ||
var radius = RadiusAtVertice( i++ ); | ||
if ( t.DistanceSquaredToPoint( localPos ) <= radius * radius ) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
public Vector2 PositionInBoundingBox ( Vector2 pos ) => pos - vertexBounds.TopLeft; | ||
|
||
public void ClearVertices () { | ||
if ( vertices.Count == 0 ) | ||
return; | ||
|
||
vertices.Clear(); | ||
|
||
vertexBoundsCache.Invalidate(); | ||
segmentsCache.Invalidate(); | ||
|
||
Invalidate( Invalidation.DrawSize ); | ||
} | ||
|
||
public void AddVertex ( Vector2 pos ) { | ||
vertices.Add( pos ); | ||
|
||
vertexBoundsCache.Invalidate(); | ||
segmentsCache.Invalidate(); | ||
|
||
Invalidate( Invalidation.DrawSize ); | ||
} | ||
|
||
private readonly List<Line> segmentsBacking = new List<Line>(); | ||
private readonly Cached segmentsCache = new Cached(); | ||
private List<Line> segments => segmentsCache.IsValid ? segmentsBacking : generateSegments(); | ||
|
||
private List<Line> generateSegments () { | ||
segmentsBacking.Clear(); | ||
|
||
if ( vertices.Count > 1 ) { | ||
Vector2 offset = vertexBounds.TopLeft; | ||
for ( int i = 0; i < vertices.Count - 1; ++i ) | ||
segmentsBacking.Add( new Line( vertices[ i ] - offset, vertices[ i + 1 ] - offset ) ); | ||
} | ||
|
||
segmentsCache.Validate(); | ||
return segmentsBacking; | ||
} | ||
|
||
private Texture texture; | ||
|
||
protected Texture Texture { | ||
get => texture ?? Texture.WhitePixel; | ||
set { | ||
if ( texture == value ) | ||
return; | ||
|
||
texture?.Dispose(); | ||
texture = value; | ||
|
||
Invalidate( Invalidation.DrawNode ); | ||
} | ||
} | ||
|
||
public DrawColourInfo? FrameBufferDrawColour => base.DrawColourInfo; | ||
|
||
public Vector2 FrameBufferScale { get; } = Vector2.One; | ||
|
||
// The path should not receive the true colour to avoid colour doubling when the frame-buffer is rendered to the back-buffer. | ||
public override DrawColourInfo DrawColourInfo => new DrawColourInfo( Color4.White, base.DrawColourInfo.Blending ); | ||
|
||
public Color4 BackgroundColour => new Color4( 0, 0, 0, 0 ); | ||
|
||
private readonly BufferedDrawNodeSharedData sharedData = new BufferedDrawNodeSharedData( new[] { RenderbufferInternalFormat.DepthComponent16 } ); | ||
|
||
protected override DrawNode CreateDrawNode () => new BufferedDrawNode( this, new VariableWidthPathDrawNode( this ), sharedData ); | ||
|
||
protected override void Dispose ( bool isDisposing ) { | ||
base.Dispose( isDisposing ); | ||
|
||
texture?.Dispose(); | ||
texture = null; | ||
|
||
sharedData.Dispose(); | ||
} | ||
} | ||
} |
Oops, something went wrong.