Files
2025-05-07 15:07:44 +08:00

281 lines
9.4 KiB
C#

using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using Random = UnityEngine.Random;
// Shapes © Freya Holmér - https://twitter.com/FreyaHolmer/
// Website & Documentation - https://acegikmo.com/shapes/
namespace Shapes {
public class AboutWindow : EditorWindow {
class Center : IDisposable {
public Center() => Noot();
public void Dispose() => Noot();
static void Noot() => GUILayout.Label( GUIContent.none, GUILayout.ExpandWidth( true ) );
}
class CenterVertical : IDisposable {
public CenterVertical() => Noot();
public void Dispose() => Noot();
static void Noot() => GUILayout.Label( GUIContent.none, GUILayout.ExpandHeight( true ) );
}
class Doot {
public Doot( float angOffset, float angSpeed, float radialOffset ) {
this.angOffset = angOffset;
this.angSpeed = angSpeed;
this.radialOffset = radialOffset;
}
public float angOffset;
public float angSpeed;
public float radialOffset;
public Vector2 pos;
}
const float DOOT_MAX_RADIUS = 0.95f;
static Doot[] doots;
static Color colMain = new Color( 1, 1, 1, 1f );
static Color colFade = new Color( 0f, 0.1f, 0.1f, 0f );
static Color colF15 = new Color( 1f, 0.0666666f, 0.333333f, 1f );
GUIStyle labelStyle;
GUIStyle LabelStyle => labelStyle ?? ( labelStyle = new GUIStyle( GUI.skin.label ) { active = { textColor = Color.white }, normal = { textColor = Color.white } } );
GUIStyle linkStyle;
GUIStyle LinkStyle => linkStyle ?? ( linkStyle = new GUIStyle( LabelStyle ) { hover = { textColor = colF15 } } );
GUIStyle titleStyle;
GUIStyle TitleStyle => titleStyle ?? ( titleStyle = new GUIStyle( EditorStyles.boldLabel ) { fontSize = 26, alignment = TextAnchor.MiddleCenter, active = { textColor = Color.white }, normal = { textColor = Color.white } } );
GUIStyle labelCentered;
GUIStyle LabelCentered => labelCentered ?? ( labelCentered = new GUIStyle( GUI.skin.label ) { alignment = TextAnchor.MiddleCenter, active = { textColor = Color.white }, normal = { textColor = Color.white } } );
[NonSerialized] string newVersionAvailable = null;
[NonSerialized] UnityWebRequest req;
bool WebRequestHasErrors {
get {
#if UNITY_2020_1_OR_NEWER
return req.result == UnityWebRequest.Result.ProtocolError || req.result == UnityWebRequest.Result.ConnectionError;
#else
return req.isHttpError || req.isNetworkError;
#endif
}
}
void OnEnable() {
req = UnityWebRequest.Get( ShapesInfo.LINK_LATEST_VERSION );
req.SendWebRequest();
const int count = 16;
doots = new Doot[count];
for( int i = 0; i < count; i++ ) {
const float maxSpeed = 0.3f;
const float minSpeed = 0.1f;
float speed = Random.Range( minSpeed, maxSpeed ) * Mathf.Sign( Random.value - 0.5f );
doots[i] = new Doot( Random.value * ShapesMath.TAU, speed, Random.Range( 0.5f, DOOT_MAX_RADIUS ) );
}
EditorApplication.update += Update;
}
void OnDisable() => EditorApplication.update -= Update;
void Update() {
if( req != null && req.isDone ) {
if( WebRequestHasErrors == false ) {
OnReceiveLatestVersion( req.downloadHandler.text );
req.Dispose();
req = null;
} else if( WebRequestHasErrors ) {
Debug.LogWarning( $"Shapes failed to check for updates. Reason: {req.error}" );
req.Dispose();
req = null;
}
}
Repaint();
}
void OnReceiveLatestVersion( string latestVersion ) {
int[] GetVersionNums( string str ) => str.Split( '.' ).Select( int.Parse ).ToArray();
int[] latest = GetVersionNums( latestVersion );
int[] current = GetVersionNums( ShapesInfo.Version );
newVersionAvailable = null;
for( int i = 0; i < 3; i++ ) {
if( current[i] > latest[i] )
return; // local version is newer somehow. you're probably freya. or a hacker >:I
if( latest[i] > current[i] ) {
newVersionAvailable = latestVersion;
return;
}
}
}
void OnGUI() {
if( Event.current.type == EventType.Repaint )
DrawShapes();
DrawText();
if( Event.current.type == EventType.MouseDown ) {
GUI.FocusControl( null );
Repaint();
}
}
void DrawText() {
using( new CenterVertical() ) {
GUI.color = colMain;
if( newVersionAvailable != null ) {
using( ShapesUI.Horizontal ) {
using( new Center() ) {
float t = (float)EditorApplication.timeSinceStartup;
float wave = ShapesMath.SmoothCos01( Mathf.PingPong( t, 0.5f ) * 2 );
wave = Mathf.Lerp( 0.5f, 1f, wave );
GUI.color = Color.Lerp( Color.white, colF15, wave );
LinkLabel( newVersionAvailable + " now available", ShapesInfo.LINK_CHANGELOG );
GUI.color = Color.white;
}
}
}
GUILayout.Label( $"Shapes {ShapesInfo.Version}", TitleStyle );
using( ShapesUI.Horizontal ) {
using( new Center() ) {
int year = Mathf.Max( DateTime.Now.Year, 2020 ); // just in case your computer clock is wonky~
GUILayout.Label( $"© {year}", LabelStyle, GUILayout.ExpandWidth( false ) );
LinkLabel( "Freya Holmér", ShapesInfo.LINK_TWITTER );
}
}
GUI.color = Color.white;
GUILayout.Space( 8 );
GUILayout.Label( "made possible thanks to\nthe wonderful supporters on", LabelCentered, GUILayout.ExpandWidth( true ) );
using( ShapesUI.Horizontal ) {
using( new Center() ) {
LinkLabel( "Patreon", ShapesInfo.LINK_PATREON );
}
}
GUI.color = colF15;
GUILayout.Label( "♥", TitleStyle, GUILayout.ExpandWidth( true ) );
GUI.color = Color.white;
}
}
float mouseDootT = 0f;
void DrawShapes() {
Vector2 center = position.size / 2;
float fitRadius = Mathf.Min( position.width, position.height ) / 2 - 8;
// set doot positions
float t = (float)EditorApplication.timeSinceStartup / 2;
foreach( Doot doot in doots ) {
float ang = doot.angSpeed * t * ShapesMath.TAU + doot.angOffset;
Vector2 dir = ShapesMath.AngToDir( ang );
doot.pos = dir * ( fitRadius * doot.radialOffset );
}
// mouse doot~
Vector2 mouseRawPos = Event.current.mousePosition - center;
float maxRadius = fitRadius * DOOT_MAX_RADIUS;
Vector2 mouseTargetPos = Vector2.ClampMagnitude( mouseRawPos, maxRadius );
doots[0].pos = Vector2.Lerp( doots[0].pos, mouseTargetPos, mouseDootT );
bool mouseOver = mouseOverWindow == this;
mouseDootT = Mathf.Lerp( mouseDootT, mouseOver ? 1f : 0f, 0.05f );
Draw.Push(); // save state
Draw.ResetAllDrawStates();
// draw setup
Draw.Matrix = Matrix4x4.TRS( new Vector3( center.x, center.y, 1f ), Quaternion.identity, Vector3.one );
Draw.BlendMode = ShapesBlendMode.Transparent;
Draw.RadiusSpace = ThicknessSpace.Meters;
Draw.ThicknessSpace = ThicknessSpace.Meters;
Draw.LineGeometry = LineGeometry.Flat2D;
Draw.LineEndCaps = LineEndCap.Round;
// Drawing
Draw.Ring( Vector3.zero, fitRadius, fitRadius * 0.1f, DiscColors.Radial( Color.black, new Color( 0, 0, 0, 0 ) ) );
Draw.Disc( Vector3.zero, fitRadius, Color.black );
// edge noodles
const int noodCount = 64;
for( int i = 0; i < noodCount; i++ ) {
float tDir = i / ( (float)noodCount );
float tAng = ShapesMath.TAU * tDir;
Vector2 dir = ShapesMath.AngToDir( tAng );
if( Mathf.Abs( dir.y ) > 0.75f )
continue;
Vector2 root = dir * fitRadius;
float distToNearest = float.MaxValue;
for( int j = 0; j < doots.Length; j++ )
distToNearest = Mathf.Min( distToNearest, Vector2.Distance( doots[j].pos, root ) );
float distMod = Mathf.InverseLerp( fitRadius * 0.5f, fitRadius * 0.1f, distToNearest );
float noodMaxOffset = fitRadius * ( 1 + 0.1f * distMod );
Draw.Line( root, dir * noodMaxOffset, fitRadius * Mathf.Lerp( 0.07f, 0.04f, distMod ) );
}
// ring
Draw.Ring( Vector3.zero, fitRadius, fitRadius * 0.0125f, colMain );
// connecting lines
for( int i = 0; i < doots.Length; i++ ) {
Vector2 a = doots[i].pos;
for( int j = i; j < doots.Length; j++ ) {
Vector2 b = doots[j].pos;
float dist = Vector2.Distance( a, b );
float rangeValue = Mathf.InverseLerp( fitRadius * 1f, fitRadius * 0.02f, dist );
if( rangeValue > 0 ) {
Color col = Color.Lerp( colFade, colMain, rangeValue );
Draw.Line( a, b, fitRadius * 0.015f * rangeValue, LineEndCap.Round, col );
}
}
}
// doots~
foreach( Doot doot in doots ) {
Draw.BlendMode = ShapesBlendMode.Transparent;
Draw.Disc( doot.pos, fitRadius * 0.025f, Color.black );
Draw.Disc( doot.pos, fitRadius * 0.015f, colMain );
Draw.BlendMode = ShapesBlendMode.Additive;
Color innerColor = colMain;
innerColor.a = 0.25f;
Color outerColor = Color.clear;
Draw.Disc( doot.pos, fitRadius * 0.18f, DiscColors.Radial( innerColor, outerColor ) );
}
Draw.BlendMode = ShapesBlendMode.Multiplicative;
Draw.Disc( Vector3.zero, fitRadius * 0.5f, DiscColors.Radial( Color.black, Color.clear ) );
Draw.Pop(); // restore state
}
void LinkLabel( string label, string url ) {
GUIContent content = new GUIContent( label );
if( GUILayout.Button( content, LinkStyle, GUILayout.ExpandWidth( false ) ) )
Application.OpenURL( url );
Rect r = GUILayoutUtility.GetLastRect();
EditorGUIUtility.AddCursorRect( r, MouseCursor.Link );
Handles.BeginGUI();
Color c = GUI.color;
c.a = 0.5f;
Handles.color = c;
float y = r.yMax - 1;
float margin = 2;
Handles.DrawLine( new Vector3( r.xMin + margin, y ), new Vector3( r.xMax - margin, y ) );
Handles.color = Color.white;
Handles.EndGUI();
}
}
}