Files
aibis-dream/Assets/Shapes/Scripts/Runtime/Immediate Mode/Draw.cs
T
2025-05-07 15:07:44 +08:00

526 lines
22 KiB
C#

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using UnityEngine;
using TMPro;
#if SHAPES_URP
using UnityEngine.Rendering.Universal;
#elif SHAPES_HDRP
using UnityEngine.Rendering.HighDefinition;
#else
using UnityEngine.Rendering;
#endif
// Shapes © Freya Holmér - https://twitter.com/FreyaHolmer/
// Website & Documentation - https://acegikmo.com/shapes/
namespace Shapes {
/// <summary>The primary class in Shapes for all functionality to draw in immediate mode</summary>
public static partial class Draw {
const MethodImplOptions INLINE = MethodImplOptions.AggressiveInlining;
/// <summary><para>Creates a DrawCommand for drawing in immediate mode.</para>
/// <para>Example usage:</para>
/// <para>using(Draw.Command(Camera.main)){ Draw.Line( a, b, Color.red ); }</para></summary>
/// <param name="cam">The camera to draw in</param>
/// <param name="cameraEvent">When during the render this command should execute</param>
#if SHAPES_URP
public static DrawCommand Command( Camera cam, RenderPassEvent cameraEvent = RenderPassEvent.BeforeRenderingPostProcessing ) => ObjectPool<DrawCommand>.Alloc().Initialize( cam, cameraEvent );
#elif SHAPES_HDRP
public static DrawCommand Command( Camera cam, CustomPassInjectionPoint cameraEvent = CustomPassInjectionPoint.BeforePostProcess ) => ObjectPool<DrawCommand>.Alloc().Initialize( cam, cameraEvent );
#else
public static DrawCommand Command( Camera cam, CameraEvent cameraEvent = CameraEvent.BeforeImageEffects ) => ObjectPool<DrawCommand>.Alloc().Initialize( cam, cameraEvent );
#endif
static MpbLine2D mpbLine = new MpbLine2D();
[OvldGenCallTarget] static void Line_Internal( [OvldDefault( nameof(LineEndCaps) )] LineEndCap endCaps,
[OvldDefault( nameof(ThicknessSpace) )] ThicknessSpace thicknessSpace,
Vector3 start,
Vector3 end,
[OvldDefault( nameof(Color) )] Color colorStart,
[OvldDefault( nameof(Color) )] Color colorEnd,
[OvldDefault( nameof(Thickness) )] float thickness ) {
using( new IMDrawer(
metaMpb: mpbLine,
sourceMat: ShapesMaterialUtils.GetLineMat( Draw.LineGeometry, endCaps )[Draw.BlendMode],
sourceMesh: ShapesMeshUtils.GetLineMesh( Draw.LineGeometry, endCaps, DetailLevel ) ) ) {
MetaMpb.ApplyDashSettings( mpbLine, thickness );
mpbLine.color.Add( colorStart.ColorSpaceAdjusted() );
mpbLine.colorEnd.Add( colorEnd.ColorSpaceAdjusted() );
mpbLine.pointStart.Add( start );
mpbLine.pointEnd.Add( end );
mpbLine.thickness.Add( thickness );
mpbLine.alignment.Add( (float)Draw.LineGeometry ); // this is redundant for 3D lines, but, that's okay, fixing that makes things messier
mpbLine.thicknessSpace.Add( (float)thicknessSpace );
mpbLine.scaleMode.Add( (float)ScaleMode );
}
}
static MpbPolyline2D mpbPolyline = new MpbPolyline2D(); // they can use the same mpb structure
static MpbPolyline2D mpbPolylineJoins = new MpbPolyline2D();
[OvldGenCallTarget] static void Polyline_Internal( PolylinePath path,
[OvldDefault( "false" )] bool closed,
[OvldDefault( nameof(PolylineGeometry) )] PolylineGeometry geometry,
[OvldDefault( nameof(PolylineJoins) )] PolylineJoins joins,
[OvldDefault( nameof(Thickness) )] float thickness,
[OvldDefault( nameof(ThicknessSpace) )] ThicknessSpace thicknessSpace,
[OvldDefault( nameof(Color) )] Color color ) {
if( path.EnsureMeshIsReadyToRender( closed, joins, out Mesh mesh ) == false )
return; // no points defined in the mesh
switch( path.Count ) {
case 0:
Debug.LogWarning( "Tried to draw polyline with no points" );
return;
case 1:
Debug.LogWarning( "Tried to draw polyline with only one point" );
return;
}
void ApplyToMpb( MpbPolyline2D mpb ) {
mpb.thickness.Add( thickness );
mpb.thicknessSpace.Add( (int)thicknessSpace );
mpb.color.Add( color.ColorSpaceAdjusted() );
mpb.alignment.Add( (int)geometry );
mpb.scaleMode.Add( (int)ScaleMode );
}
if( DrawCommand.IsAddingDrawCommandsToBuffer ) // mark as used by this command to prevent destroy in dispose
path.RegisterToCommandBuffer( DrawCommand.CurrentWritingCommandBuffer );
using( new IMDrawer( mpbPolyline, ShapesMaterialUtils.GetPolylineMat( joins )[Draw.BlendMode], mesh, 0 ) )
ApplyToMpb( mpbPolyline );
if( joins.HasJoinMesh() ) {
using( new IMDrawer( mpbPolylineJoins, ShapesMaterialUtils.GetPolylineJoinsMat( joins )[Draw.BlendMode], mesh, 1 ) )
ApplyToMpb( mpbPolylineJoins );
}
}
static MpbPolygon mpbPolygon = new MpbPolygon();
[OvldGenCallTarget] static void Polygon_Internal( PolygonPath path,
[OvldDefault( nameof(PolygonTriangulation) )] PolygonTriangulation triangulation,
[OvldDefault( nameof(Color) )] Color color ) {
if( path.EnsureMeshIsReadyToRender( triangulation, out Mesh mesh ) == false )
return; // no points defined in the mesh
switch( path.Count ) {
case 0:
Debug.LogWarning( "Tried to draw polygon with no points" );
return;
case 1:
Debug.LogWarning( "Tried to draw polygon with only one point" );
return;
case 2:
Debug.LogWarning( "Tried to draw polygon with only two points" );
return;
}
if( DrawCommand.IsAddingDrawCommandsToBuffer ) // mark as used by this command to prevent destroy in dispose
path.RegisterToCommandBuffer( DrawCommand.CurrentWritingCommandBuffer );
using( new IMDrawer( mpbPolygon, ShapesMaterialUtils.matPolygon[Draw.BlendMode], mesh ) ) {
MetaMpb.ApplyColorOrFill( mpbPolygon, color );
}
}
[OvldGenCallTarget] [MethodImpl( INLINE )]
static void Disc_Internal( [OvldDefault( nameof(Radius) )] float radius,
[OvldDefault( nameof(Color) )] DiscColors colors ) {
DiscCore( false, false, radius, 0f, colors );
}
[OvldGenCallTarget] [MethodImpl( INLINE )]
static void Ring_Internal( [OvldDefault( nameof(Radius) )] float radius,
[OvldDefault( nameof(Thickness) )] float thickness,
[OvldDefault( nameof(Color) )] DiscColors colors ) {
DiscCore( true, false, radius, thickness, colors );
}
[OvldGenCallTarget] [MethodImpl( INLINE )]
static void Pie_Internal( [OvldDefault( nameof(Radius) )] float radius,
[OvldDefault( nameof(Color) )] DiscColors colors,
float angleRadStart,
float angleRadEnd ) {
DiscCore( false, true, radius, 0f, colors, angleRadStart, angleRadEnd );
}
[OvldGenCallTarget] [MethodImpl( INLINE )]
static void Arc_Internal( [OvldDefault( nameof(Radius) )] float radius,
[OvldDefault( nameof(Thickness) )] float thickness,
[OvldDefault( nameof(Color) )] DiscColors colors,
float angleRadStart,
float angleRadEnd,
[OvldDefault( nameof(ArcEndCap) + "." + nameof(ArcEndCap.None) )] ArcEndCap endCaps ) {
DiscCore( true, true, radius, thickness, colors, angleRadStart, angleRadEnd, endCaps );
}
static readonly MpbDisc mpbDisc = new MpbDisc();
static void DiscCore( bool hollow, bool sector, float radius, float thickness, DiscColors colors, float angleRadStart = 0f, float angleRadEnd = 0f, ArcEndCap arcEndCaps = ArcEndCap.None ) {
if( sector && Mathf.Abs( angleRadEnd - angleRadStart ) < 0.0001f )
return;
using( new IMDrawer( mpbDisc, ShapesMaterialUtils.GetDiscMaterial( hollow, sector )[Draw.BlendMode], ShapesMeshUtils.QuadMesh[0] ) ) {
MetaMpb.ApplyDashSettings( mpbDisc, thickness );
mpbDisc.radius.Add( radius );
mpbDisc.radiusSpace.Add( (int)Draw.RadiusSpace );
mpbDisc.alignment.Add( (int)Draw.DiscGeometry );
mpbDisc.thicknessSpace.Add( (int)Draw.ThicknessSpace );
mpbDisc.thickness.Add( thickness );
mpbDisc.scaleMode.Add( (int)ScaleMode );
mpbDisc.angleStart.Add( angleRadStart );
mpbDisc.angleEnd.Add( angleRadEnd );
mpbDisc.roundCaps.Add( (int)arcEndCaps );
mpbDisc.color.Add( colors.innerStart.ColorSpaceAdjusted() );
mpbDisc.colorOuterStart.Add( colors.outerStart.ColorSpaceAdjusted() );
mpbDisc.colorInnerEnd.Add( colors.innerEnd.ColorSpaceAdjusted() );
mpbDisc.colorOuterEnd.Add( colors.outerEnd.ColorSpaceAdjusted() );
}
}
static readonly MpbRegularPolygon mpbRegularPolygon = new MpbRegularPolygon();
[OvldGenCallTarget] static void RegularPolygon_Internal( [OvldDefault( nameof(RegularPolygonSideCount) )] int sideCount,
[OvldDefault( nameof(Radius) )] float radius,
[OvldDefault( nameof(Thickness) )] float thickness,
[OvldDefault( nameof(Color) )] Color color,
bool hollow,
[OvldDefault( "0f" )] float roundness,
[OvldDefault( "0f" )] float angle ) {
using( new IMDrawer( mpbRegularPolygon, ShapesMaterialUtils.matRegularPolygon[Draw.BlendMode], ShapesMeshUtils.QuadMesh[0] ) ) {
MetaMpb.ApplyColorOrFill( mpbRegularPolygon, color );
MetaMpb.ApplyDashSettings( mpbRegularPolygon, thickness );
mpbRegularPolygon.radius.Add( radius );
mpbRegularPolygon.radiusSpace.Add( (int)Draw.RadiusSpace );
mpbRegularPolygon.alignment.Add( (int)Draw.RegularPolygonGeometry );
mpbRegularPolygon.sides.Add( Mathf.Max( 3, sideCount ) );
mpbRegularPolygon.angle.Add( angle );
mpbRegularPolygon.roundness.Add( roundness );
mpbRegularPolygon.hollow.Add( hollow.AsInt() );
mpbRegularPolygon.thicknessSpace.Add( (int)Draw.ThicknessSpace );
mpbRegularPolygon.thickness.Add( thickness );
mpbRegularPolygon.scaleMode.Add( (int)ScaleMode );
}
}
static readonly MpbRect mpbRect = new MpbRect();
[OvldGenCallTarget] static void Rectangle_Internal( [OvldDefault( nameof(BlendMode) )] ShapesBlendMode blendMode,
[OvldDefault( "false" )] bool hollow,
Rect rect,
[OvldDefault( nameof(Color) )] Color color,
[OvldDefault( nameof(Thickness) )] float thickness,
[OvldDefault( "default" )] Vector4 cornerRadii ) {
bool rounded = ShapesMath.MaxComp( cornerRadii ) >= 0.0001f;
// positive vibes only
if( rect.width < 0 ) rect.x -= rect.width *= -1;
if( rect.height < 0 ) rect.y -= rect.height *= -1;
using( new IMDrawer( mpbRect, ShapesMaterialUtils.GetRectMaterial( hollow, rounded )[blendMode], ShapesMeshUtils.QuadMesh[0] ) ) {
MetaMpb.ApplyColorOrFill( mpbRect, color );
MetaMpb.ApplyDashSettings( mpbRect, thickness );
mpbRect.rect.Add( rect.ToVector4() );
mpbRect.cornerRadii.Add( cornerRadii );
mpbRect.thickness.Add( thickness );
mpbRect.thicknessSpace.Add( (int)Draw.ThicknessSpace );
mpbRect.scaleMode.Add( (int)ScaleMode );
}
}
static MpbTriangle mpbTriangle = new MpbTriangle();
[OvldGenCallTarget] static void Triangle_Internal( Vector3 a,
Vector3 b,
Vector3 c,
bool hollow,
[OvldDefault( nameof(Thickness) )] float thickness,
[OvldDefault( "0f" )] float roundness,
[OvldDefault( nameof(Color) )] Color colorA,
[OvldDefault( nameof(Color) )] Color colorB,
[OvldDefault( nameof(Color) )] Color colorC ) {
using( new IMDrawer( mpbTriangle, ShapesMaterialUtils.matTriangle[Draw.BlendMode], ShapesMeshUtils.TriangleMesh[0] ) ) {
MetaMpb.ApplyDashSettings( mpbTriangle, thickness );
mpbTriangle.a.Add( a );
mpbTriangle.b.Add( b );
mpbTriangle.c.Add( c );
mpbTriangle.color.Add( colorA.ColorSpaceAdjusted() );
mpbTriangle.colorB.Add( colorB.ColorSpaceAdjusted() );
mpbTriangle.colorC.Add( colorC.ColorSpaceAdjusted() );
mpbTriangle.roundness.Add( roundness );
mpbTriangle.hollow.Add( hollow.AsInt() );
mpbTriangle.thicknessSpace.Add( (int)Draw.ThicknessSpace );
mpbTriangle.thickness.Add( thickness );
mpbTriangle.scaleMode.Add( (int)ScaleMode );
}
}
static MpbQuad mpbQuad = new MpbQuad();
[OvldGenCallTarget] static void Quad_Internal( Vector3 a,
Vector3 b,
Vector3 c,
[OvldDefault( "a + ( c - b )" )] Vector3 d,
[OvldDefault( nameof(Color) )] Color colorA,
[OvldDefault( nameof(Color) )] Color colorB,
[OvldDefault( nameof(Color) )] Color colorC,
[OvldDefault( nameof(Color) )] Color colorD ) {
using( new IMDrawer( mpbQuad, ShapesMaterialUtils.matQuad[Draw.BlendMode], ShapesMeshUtils.QuadMesh[0] ) ) {
mpbQuad.a.Add( a );
mpbQuad.b.Add( b );
mpbQuad.c.Add( c );
mpbQuad.d.Add( d );
mpbQuad.color.Add( colorA.ColorSpaceAdjusted() );
mpbQuad.colorB.Add( colorB.ColorSpaceAdjusted() );
mpbQuad.colorC.Add( colorC.ColorSpaceAdjusted() );
mpbQuad.colorD.Add( colorD.ColorSpaceAdjusted() );
}
}
static readonly MpbSphere metaMpbSphere = new MpbSphere();
[OvldGenCallTarget] static void Sphere_Internal( [OvldDefault( nameof(Radius) )] float radius,
[OvldDefault( nameof(Color) )] Color color ) {
using( new IMDrawer( metaMpbSphere, ShapesMaterialUtils.matSphere[Draw.BlendMode], ShapesMeshUtils.SphereMesh[(int)DetailLevel] ) ) {
metaMpbSphere.color.Add( color.ColorSpaceAdjusted() );
metaMpbSphere.radius.Add( radius );
metaMpbSphere.radiusSpace.Add( (float)Draw.RadiusSpace );
}
}
static readonly MpbCone mpbCone = new MpbCone();
[OvldGenCallTarget] static void Cone_Internal( float radius,
float length,
[OvldDefault( "true" )] bool fillCap,
[OvldDefault( nameof(Color) )] Color color ) {
Mesh mesh = fillCap ? ShapesMeshUtils.ConeMesh[(int)DetailLevel] : ShapesMeshUtils.ConeMeshUncapped[(int)DetailLevel];
using( new IMDrawer( mpbCone, ShapesMaterialUtils.matCone[Draw.BlendMode], mesh ) ) {
mpbCone.color.Add( color.ColorSpaceAdjusted() );
mpbCone.radius.Add( radius );
mpbCone.length.Add( length );
mpbCone.sizeSpace.Add( (float)Draw.SizeSpace );
}
}
static readonly MpbCuboid mpbCuboid = new MpbCuboid();
[OvldGenCallTarget] static void Cuboid_Internal( Vector3 size,
[OvldDefault( nameof(Color) )] Color color ) {
using( new IMDrawer( mpbCuboid, ShapesMaterialUtils.matCuboid[Draw.BlendMode], ShapesMeshUtils.CuboidMesh[0] ) ) {
mpbCuboid.color.Add( color.ColorSpaceAdjusted() );
mpbCuboid.size.Add( size );
mpbCuboid.sizeSpace.Add( (float)Draw.SizeSpace );
}
}
static MpbTorus mpbTorus = new MpbTorus();
[OvldGenCallTarget] static void Torus_Internal( float radius,
float thickness,
[OvldDefault( "0" )] float angleRadStart,
[OvldDefault( nameof(ShapesMath) + ".TAU" )] float angleRadEnd,
[OvldDefault( nameof(Color) )] Color color ) {
if( thickness < 0.0001f )
return;
if( radius < 0.00001f ) {
ThicknessSpace cached = Draw.RadiusSpace;
Draw.RadiusSpace = Draw.ThicknessSpace;
Sphere( thickness / 2, color );
Draw.RadiusSpace = cached;
return;
}
using( new IMDrawer( mpbTorus, ShapesMaterialUtils.matTorus[Draw.BlendMode], ShapesMeshUtils.TorusMesh[(int)DetailLevel] ) ) {
mpbTorus.color.Add( color.ColorSpaceAdjusted() );
mpbTorus.radius.Add( radius );
mpbTorus.thickness.Add( thickness );
mpbTorus.radiusSpace.Add( (int)Draw.RadiusSpace );
mpbTorus.thicknessSpace.Add( (int)Draw.ThicknessSpace );
mpbTorus.scaleMode.Add( (int)Draw.ScaleMode );
mpbTorus.angleStart.Add( angleRadStart );
mpbTorus.angleEnd.Add( angleRadEnd );
}
}
static MpbText mpbText = new MpbText();
[OvldGenCallTarget] static void TextRect_Internal( string content,
[OvldDefault( "null" )] TextElement element,
Rect rect,
[OvldDefault( nameof(Font) )] TMP_FontAsset font,
[OvldDefault( nameof(FontSize) )] float fontSize,
[OvldDefault( nameof(TextAlign) )] TextAlign align,
[OvldDefault( nameof(Color) )] Color color ) {
PushMatrix();
Translate( rect.x, rect.y );
Text_Internal( true, content, element, pivot: default, rect.size, font, fontSize, align, color );
PopMatrix();
}
[OvldGenCallTarget] static void Text_Internal( bool isRect,
string content,
[OvldDefault( "null" )] TextElement element,
[OvldDefault( "default" )] Vector2 pivot, // ignored for simple text
[OvldDefault( "default" )] Vector2 size, // ignored for simple text
[OvldDefault( nameof(Font) )] TMP_FontAsset font,
[OvldDefault( nameof(FontSize) )] float fontSize,
[OvldDefault( nameof(TextAlign) )] TextAlign align,
[OvldDefault( nameof(Color) )] Color color ) {
int id;
TextMeshPro tmp;
IMDrawer.DrawType drawType;
if( element == null ) {
id = TextElement.GetNextId(); // auto-pooling
tmp = ShapesTextPool.Instance.AllocateElement( id );
drawType = IMDrawer.DrawType.TextPooledAuto;
} else {
id = element.id;
tmp = element.Tmp;
drawType = IMDrawer.DrawType.TextPooledPersistent;
}
ApplyTextValuesToInstance( tmp, isRect, content, font, fontSize, align, pivot, size, color );
Text_Internal( tmp, drawType, id );
}
delegate void OnPreRenderTmpDelegate( TextMeshPro tmp );
static OnPreRenderTmpDelegate onPreRenderTmp;
static OnPreRenderTmpDelegate OnPreRenderTmp {
get {
if( onPreRenderTmp == null ) {
MethodInfo method = typeof(TextMeshPro).GetMethod( "OnPreRenderObject", BindingFlags.Instance | BindingFlags.NonPublic );
onPreRenderTmp = (OnPreRenderTmpDelegate)method.CreateDelegate( typeof(OnPreRenderTmpDelegate) );
}
return onPreRenderTmp;
}
}
static void ApplyTextValuesToInstance( TextMeshPro tmp, bool isRect, string content, TMP_FontAsset font, float fontSize, TextAlign align, Vector2 pivot, Vector2 size, Color color ) {
// globals
tmp.fontStyle = FontStyle;
tmp.characterSpacing = TextCharacterSpacing;
tmp.wordSpacing = TextWordSpacing;
tmp.lineSpacing = TextLineSpacing;
tmp.paragraphSpacing = TextParagraphSpacing;
tmp.margin = TextMargins;
// overrides
tmp.font = font;
tmp.color = color;
tmp.fontSize = fontSize;
tmp.alignment = align.GetTMPAlignment();
tmp.text = content;
// positioning & wrapping
if( isRect ) {
tmp.enableWordWrapping = TextWrap;
tmp.overflowMode = TextOverflow;
tmp.rectTransform.pivot = pivot;
tmp.rectTransform.sizeDelta = size;
} else {
// when we're drawing text without a rectangle, we just always overflow and ignore pivots/sizing/wrapping
tmp.enableWordWrapping = false;
tmp.overflowMode = TextOverflowModes.Overflow;
// tmp.rectTransform.pivot not set, since pivot is ignored when size = 0 anyway
tmp.rectTransform.sizeDelta = default;
}
tmp.rectTransform.position = Matrix.GetColumn( 3 );
tmp.rectTransform.rotation = Matrix.rotation;
// set dirty
OnPreRenderTmp.Invoke( tmp ); // calls OnPreRenderObject. Ensures the mesh is up to date
// tmp.ForceMeshUpdate(); // alternatively, call this, but this always updates, even when the text doesn't change
}
static void Text_Internal( TextMeshPro tmp, IMDrawer.DrawType drawType, int disposeId = -1 ) {
// todo: something fucky happens sometimes when fallback fonts are the only things in town
using( new IMDrawer( mpbText, tmp.fontSharedMaterial, tmp.mesh, drawType: drawType, allowInstancing: false, textAutoDisposeId: disposeId ) ) {
// will draw on dispose
}
// ensure child renderers are disabled
for( int i = 0; i < tmp.transform.childCount; i++ ) {
// todo: optimize by caching some refs fam
TMP_SubMesh sm = tmp.transform.GetChild( i ).GetComponent<TMP_SubMesh>();
sm.renderer.enabled = false; // :>
}
// ;-;
if( tmp.textInfo.materialCount > 1 ) {
// we have fallback fonts so GreaT!! let's just draw everything because fuck me
for( int i = 0; i < tmp.transform.childCount; i++ ) {
TMP_SubMesh sm = tmp.transform.GetChild( i ).GetComponent<TMP_SubMesh>();
sm.renderer.enabled = false; // :>
if( sm.sharedMaterial == null )
continue; // cursed but ok
using( new IMDrawer( mpbText, sm.sharedMaterial, sm.mesh, drawType: drawType, allowInstancing: false ) ) {
// will draw on dispose
}
}
}
}
static MpbTexture mpbTexture = new MpbTexture();
[OvldGenCallTarget] static void Texture_Internal( Texture texture, Rect rect, Rect uvs, [OvldDefault( nameof(Color) )] Color color ) {
Material mat = ShapesMaterialUtils.matTexture[BlendMode];
using( new IMDrawer( mpbTexture, mat, ShapesMeshUtils.QuadMesh[0], allowInstancing: false ) ) {
mpbTexture.textures.Add( texture );
mpbTexture.color.Add( color.ColorSpaceAdjusted() );
mpbTexture.rect.Add( rect.ToVector4() );
mpbTexture.uvs.Add( uvs.ToVector4() );
}
}
[MethodImpl( INLINE )] static void Texture_Placement_Internal(
Texture texture,
(Rect rect, Rect uvs) placement,
Color color ) {
Texture_Internal( texture, placement.rect, placement.uvs, color );
}
[MethodImpl( INLINE )] [OvldGenCallTarget] static void Texture_RectFill_Internal(
Texture texture,
Rect rect,
[OvldDefault( nameof(TextureFillMode) + "." + nameof(TextureFillMode.ScaleToFit) )]
TextureFillMode fillMode,
[OvldDefault( nameof(Color) )] Color color ) {
Texture_Placement_Internal( texture, TexturePlacement.Fit( texture, rect, fillMode ), color );
}
[MethodImpl( INLINE )] [OvldGenCallTarget] static void Texture_PosSize_Internal(
Texture texture,
Vector2 center,
float size,
[OvldDefault( nameof(TextureSizeMode) + "." + nameof(TextureSizeMode.LongestSide) )]
TextureSizeMode sizeMode,
[OvldDefault( nameof(Color) )] Color color ) {
Texture_Placement_Internal( texture, TexturePlacement.Size( texture, center, size, sizeMode ), color );
}
}
// these are used by CodegenDrawOverloads
[AttributeUsage( AttributeTargets.Method )]
internal class OvldGenCallTarget : Attribute {}
[AttributeUsage( AttributeTargets.Parameter )]
internal class OvldDefault : Attribute {
public string @default;
public OvldDefault( string @default ) => this.@default = @default;
}
}