Pause menu 3 (#3663)

* Add TextureFlags
* Add TextureFlags.PremultipliedAlpha in text block and webpanel textures
* Add BlendMode.PremultipliedAlpha
* Add panel to PauseModal
This commit is contained in:
Garry Newman
2025-12-23 15:11:25 +00:00
committed by GitHub
parent 677282f1cd
commit 675f55005e
11 changed files with 157 additions and 34 deletions

View File

@@ -32,6 +32,11 @@ public partial class Texture : Resource, IDisposable
public override bool IsValid => native.IsValid;
/// <summary>
/// Flags providing hints about this texture
/// </summary>
public TextureFlags Flags { get; set; } = TextureFlags.None;
/// <summary>
/// Private constructor, use <see cref="FromNative(ITexture)"/>
/// </summary>
@@ -304,3 +309,16 @@ public partial class Texture : Resource, IDisposable
IsLoaded = true;
}
}
/// <summary>
/// Flags providing hints about a texture
/// </summary>
public enum TextureFlags
{
None = 0,
/// <summary>
/// Hint that this texture has pre-multiplied alpha
/// </summary>
PremultipliedAlpha = 1 << 0,
}

View File

@@ -13,13 +13,18 @@
// Screen = 2,
// Overlay = 3,
// Darken = 4,
Lighten = 2, // 5
// ColorDodge = 6,
// ColorBurn = 7,
// HardLight = 8,
// SoftLight = 9,
// Difference = 10,
// Exclusion = 11,
Lighten = 2,
PremultipliedAlpha = 3,
// 5
// ColorDodge = 6,
// ColorBurn = 7,
// HardLight = 8,
// SoftLight = 9,
// Difference = 10,
// Exclusion = 11,
}
}

View File

@@ -1,4 +1,5 @@
using System.Web;
using Microsoft.AspNetCore.Components;
using System.Web;
namespace Sandbox.UI;
@@ -12,7 +13,7 @@ public class WebPanel : Panel
/// </summary>
public WebSurface Surface { get; private set; }
[Parameter]
public string Url
{
get => Surface.Url;
@@ -52,6 +53,8 @@ public class WebPanel : Panel
.WithName( "WebPanel" )
.Finish();
sufaceTexture.Flags |= TextureFlags.PremultipliedAlpha;
Style.SetBackgroundImage( sufaceTexture );
}

View File

@@ -157,12 +157,17 @@ internal sealed class TextBlock : IDisposable
if ( color.a <= 0 ) return;
var bm = renderer.OverrideBlendMode;
if ( bm == BlendMode.Normal && Texture.Flags.Contains( TextureFlags.PremultipliedAlpha ) )
bm = BlendMode.PremultipliedAlpha;
textAttr.Set( "BoxPosition", textrect.Position );
textAttr.Set( "BoxSize", textrect.Size );
textAttr.Set( "TextureIndex", Texture.Index );
textAttr.Set( "SamplerIndex", SamplerState.GetBindlessIndex( new SamplerState() { Filter = TextFilter } ) );
textAttr.SetComboEnum( "D_BLENDMODE", renderer.OverrideBlendMode );
textAttr.SetComboEnum( "D_BLENDMODE", bm );
Graphics.DrawQuad( textrect.Floor(), Material.UI.Text, color, textAttr );
}
@@ -543,7 +548,7 @@ internal sealed class TextBlock : IDisposable
using var perfScope = Performance.Scope( "TextBlock.RebuildTexture" );
using ( var bitmap = new SKBitmap( width, height, SKColorType.Bgra8888, SKAlphaType.Unpremul ) )
using ( var bitmap = new SKBitmap( width, height, SKColorType.Bgra8888, SKAlphaType.Premul ) )
using ( var canvas = new SKCanvas( bitmap ) )
{
var o = new Topten.RichTextKit.TextPaintOptions
@@ -599,6 +604,8 @@ internal sealed class TextBlock : IDisposable
.WithData( bitmap.GetPixels(), width * height * bitmap.BytesPerPixel )
.WithDynamicUsage()
.Finish();
Texture.Flags |= TextureFlags.PremultipliedAlpha;
}
}

View File

@@ -1,5 +1,4 @@
using Sandbox.Rendering;
using System.Runtime.InteropServices;
namespace Sandbox.UI;
@@ -70,7 +69,12 @@ public partial class Panel
if ( bgBlendMode == BlendMode.Normal || ComputedStyle.BackgroundImage == null )
{
bgAttribs.SetComboEnum( "D_BLENDMODE", renderer.OverrideBlendMode );
BlendMode bm = bgBlendMode;
if ( bm == BlendMode.Normal && (ComputedStyle.BackgroundImage?.Flags.Contains( TextureFlags.PremultipliedAlpha ) ?? false) )
bm = BlendMode.PremultipliedAlpha;
bgAttribs.SetComboEnum( "D_BLENDMODE", bm );
bgAttribs.Set( "Texture", ComputedStyle.BackgroundImage );
Graphics.DrawQuad( rect, Material.UI.Box, color, bgAttribs );
}

View File

@@ -4,9 +4,9 @@
// Blend Modes (https://web.dev/learn/css/blend-modes/)
// I only filled in what I needed. A job for someone else - garry
//
DynamicCombo( D_BLENDMODE, 0..2, Sys( ALL ) );
DynamicCombo( D_BLENDMODE, 0..3, Sys( ALL ) );
// Alpha Blend
// Alpha Blend (standard)
#if D_BLENDMODE == 0
RenderState( BlendEnable, true );
RenderState( SrcBlend, SRC_ALPHA );
@@ -15,18 +15,34 @@ DynamicCombo( D_BLENDMODE, 0..2, Sys( ALL ) );
RenderState( SrcBlendAlpha, ONE );
RenderState( DstBlendAlpha, INV_SRC_ALPHA );
RenderState( BlendOpAlpha, ADD );
// Multiply
#elif D_BLENDMODE == 1
RenderState( BlendEnable, true );
RenderState( SrcBlend, DEST_COLOR );
RenderState( DstBlend, INV_SRC_ALPHA );
RenderState( DstBlend, ZERO );
RenderState( BlendOp, ADD );
RenderState( SrcBlendAlpha, ONE );
RenderState( DstBlendAlpha, ONE );
// Lighten
RenderState( DstBlendAlpha, ZERO );
RenderState( BlendOpAlpha, ADD );
// Lighten / Additive
#elif D_BLENDMODE == 2
RenderState( BlendEnable, true );
RenderState( SrcBlend, SRC_ALPHA );
RenderState( DstBlend, ONE );
RenderState( BlendOp, ADD );
RenderState( SrcBlendAlpha, ONE );
RenderState( DstBlendAlpha, ONE );
#endif
RenderState( BlendOpAlpha, ADD );
// Premultiplied Alpha
#elif D_BLENDMODE == 3
RenderState( BlendEnable, true );
RenderState( SrcBlend, ONE );
RenderState( DstBlend, INV_SRC_ALPHA );
RenderState( BlendOp, ADD );
RenderState( SrcBlendAlpha, ONE );
RenderState( DstBlendAlpha, INV_SRC_ALPHA );
RenderState( BlendOpAlpha, ADD );
#endif

View File

@@ -329,10 +329,18 @@ PS
}
vImage.xyz = SrgbGammaToLinear( vImage.xyz );
vImage *= bgTint;
#if ( D_BLENDMODE == 3 ) // PREMULIPLIED
vImage.rgb *= bgTint.rgb;
vImage *= bgTint.a;
#else
vImage *= bgTint;
#endif
vBox.rgb = lerp( vBox.rgb, vImage.rgb, saturate( vImage.a + ( 1 - vBox.a ) ) );
vBox.a = max( vBox.a, vImage.a );
}
o.vColor = vBox;

View File

@@ -96,16 +96,13 @@ PS
Texture2D tex = GetBindlessTexture2D( TextureIndex + 1 );
float4 vColor = tex.SampleBias( sampler, vTexCoord, mipBias );
float flAlphaScale = 1.0f;
float lum = saturate(dot( float3(0.30, 0.59, 0.11), vColor.rgb ) - 0.2);
float alpha = vColor.a;
alpha = pow(alpha, 0.6 + (lum) * 3 );
vColor.a = alpha * flAlphaScale;
o.vColor = vColor;
o.vColor.a *= i.vColor.a;
#if ( D_BLENDMODE == 3 )
o.vColor *= i.vColor.a;
#else
o.vColor.a *= i.vColor.a;
#endif
// Apply fog only on world panels
#if D_WORLDPANEL

View File

@@ -10,6 +10,8 @@ public class ModalSystem : IModalSystem
List<BaseModal> OpenModals = new List<BaseModal>();
PauseModal _pauseModal;
public ModalSystem()
{
Instance = this;
@@ -17,6 +19,9 @@ public class ModalSystem : IModalSystem
public bool HasModalsOpen()
{
if ( IsPauseMenuOpen )
return true;
return OpenModals.Any( x => x.WantsMouseInput() );
}
@@ -167,8 +172,16 @@ public class ModalSystem : IModalSystem
return;
}
var modal = new PauseModal();
Push( modal );
_pauseModal = MenuOverlay.Instance.Children.OfType<PauseModal>().FirstOrDefault();
if ( _pauseModal != null )
{
_pauseModal.ToggleClass( "hidden" );
return;
}
_pauseModal = new PauseModal();
MenuOverlay.Instance.AddChild( _pauseModal );
}
public void Player( SteamId steamid, string page = "" )
@@ -190,6 +203,6 @@ public class ModalSystem : IModalSystem
Push( new WorkshopPublishModal { Options = options } );
}
public bool IsModalOpen => OpenModals.Any();
public bool IsPauseMenuOpen => OpenModals.OfType<PauseModal>().Any();
public bool IsModalOpen => HasModalsOpen();
public bool IsPauseMenuOpen => _pauseModal.IsValid() && _pauseModal.IsPauseMenuOpen();
}

View File

@@ -20,7 +20,14 @@
</div>
<div class="right">
@{
var ident = game?.FullIdent.Split('#')[0] ?? "unknown/unknown";
var url = $"https://sbox.game/game/pause/{ident}";
//var url = $"https://localhost:44338/game/pause/{ident}";
<WebPanel class="browser" Url="@url"></WebPanel>
}
</div>
</div>
@@ -108,4 +115,36 @@
StateHasChanged();
}
}
public override void Tick()
{
base.Tick();
CheckForDelete();
}
bool CheckForDelete()
{
if (MenuUtility.GamePackage == null)
{
Delete();
return true;
}
if (MenuUtility.GamePackage?.Ident != game?.Ident)
{
Delete();
return true;
}
return false;
}
public bool IsPauseMenuOpen()
{
if (CheckForDelete() )
return false;
return !HasClass( "hidden" );
}
}

View File

@@ -17,6 +17,12 @@ PauseModal.modal
padding: 4rem;
gap: 2rem;
}
&.hidden
{
opacity: 0;
pointer-events: none;
}
}
@@ -151,4 +157,11 @@ PauseModal .tiles-container
flex-grow: 1;
overflow: hidden;
}
}
.browser
{
flex-grow: 1;
width: 100%;
height: 100%;
}