mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-13 11:20:31 +00:00
只暂存
This commit is contained in:
6
.idea/.idea.osu-framework.Desktop/.idea/copilot.data.migration.agent.xml
generated
Normal file
6
.idea/.idea.osu-framework.Desktop/.idea/copilot.data.migration.agent.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AgentMigrationStateService">
|
||||||
|
<option name="migrationStatus" value="COMPLETED" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/.idea.osu-framework.Desktop/.idea/copilot.data.migration.ask.xml
generated
Normal file
6
.idea/.idea.osu-framework.Desktop/.idea/copilot.data.migration.ask.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AskMigrationStateService">
|
||||||
|
<option name="migrationStatus" value="COMPLETED" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/.idea.osu-framework.Desktop/.idea/copilot.data.migration.ask2agent.xml
generated
Normal file
6
.idea/.idea.osu-framework.Desktop/.idea/copilot.data.migration.ask2agent.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Ask2AgentMigrationStateService">
|
||||||
|
<option name="migrationStatus" value="COMPLETED" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/.idea.osu-framework.Desktop/.idea/copilot.data.migration.edit.xml
generated
Normal file
6
.idea/.idea.osu-framework.Desktop/.idea/copilot.data.migration.edit.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="EditMigrationStateService">
|
||||||
|
<option name="migrationStatus" value="COMPLETED" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
15
.idea/.idea.osu-framework.Desktop/.idea/git_toolbox_prj.xml
generated
Normal file
15
.idea/.idea.osu-framework.Desktop/.idea/git_toolbox_prj.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GitToolBoxProjectSettings">
|
||||||
|
<option name="commitMessageIssueKeyValidationOverride">
|
||||||
|
<BoolValueOverride>
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</BoolValueOverride>
|
||||||
|
</option>
|
||||||
|
<option name="commitMessageValidationEnabledOverride">
|
||||||
|
<BoolValueOverride>
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</BoolValueOverride>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
225
Acrylic_Implementation_Notes.md
Normal file
225
Acrylic_Implementation_Notes.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
# Acrylic Container 实现说明 / Implementation Notes
|
||||||
|
|
||||||
|
## 问题分析 / Problem Analysis
|
||||||
|
|
||||||
|
### 原始需求 / Original Requirement
|
||||||
|
用户希望实现"真正的毛玻璃效果" - 即模糊容器**背后**的内容,类似于 Windows Acrylic 或 macOS 的毛玻璃效果。
|
||||||
|
|
||||||
|
The user wanted to implement a "true frosted glass effect" - blurring content **behind** the container, similar to Windows Acrylic or macOS frosted glass.
|
||||||
|
|
||||||
|
### 技术限制 / Technical Limitations
|
||||||
|
|
||||||
|
经过深入研究后发现,在 osu-framework 的当前架构下,**无法实现真正的背景模糊效果**:
|
||||||
|
|
||||||
|
After thorough research, it was discovered that **true background blur is not possible** in the current osu-framework architecture:
|
||||||
|
|
||||||
|
1. **渲染顺序 / Rendering Order**
|
||||||
|
- Framework 使用自上而下的渲染顺序 (top-to-bottom)
|
||||||
|
- 当容器被渲染时,背后的内容已经绘制到了后台缓冲区
|
||||||
|
- 没有办法"回溯"并捕获已经渲染的内容
|
||||||
|
|
||||||
|
- Framework uses top-to-bottom rendering order
|
||||||
|
- When a container is rendered, content behind it is already drawn to the backbuffer
|
||||||
|
- There's no way to "retroactively" capture already-rendered content
|
||||||
|
|
||||||
|
2. **CaptureScreenToFrameBuffer 未实现 / CaptureScreenToFrameBuffer Not Implemented**
|
||||||
|
- 发现 `IRenderer.CaptureScreenToFrameBuffer` 方法存在但未实现
|
||||||
|
- `DeferredRenderer.CaptureScreenToFrameBuffer` 只是一个 TODO 占位符
|
||||||
|
- 这个方法原本可以用来捕获当前屏幕内容,但目前不可用
|
||||||
|
|
||||||
|
- The `IRenderer.CaptureScreenToFrameBuffer` method exists but is not implemented
|
||||||
|
- `DeferredRenderer.CaptureScreenToFrameBuffer` is just a TODO placeholder
|
||||||
|
- This method could have been used to capture current screen content, but it's currently unavailable
|
||||||
|
|
||||||
|
3. **BufferedContainer 的限制 / BufferedContainer Limitations**
|
||||||
|
- `BufferedContainer` 只能模糊**自己的子元素**
|
||||||
|
- 它先将子元素渲染到帧缓冲区,然后应用模糊
|
||||||
|
- 无法访问或模糊父容器或兄弟元素的内容
|
||||||
|
|
||||||
|
- `BufferedContainer` can only blur **its own children**
|
||||||
|
- It renders children to a framebuffer first, then applies blur
|
||||||
|
- It cannot access or blur content from parent or sibling containers
|
||||||
|
|
||||||
|
## 实现方案 / Implementation Approach
|
||||||
|
|
||||||
|
### 最终方案 / Final Solution
|
||||||
|
基于技术限制,改为实现一个**视觉上接近毛玻璃效果**的容器:
|
||||||
|
|
||||||
|
Given the technical constraints, implemented a container that **visually approximates the frosted glass effect**:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public partial class AcrylicContainer : BufferedContainer
|
||||||
|
{
|
||||||
|
// 模糊一个背景层 (Blur a background layer)
|
||||||
|
private Drawable backgroundBox;
|
||||||
|
|
||||||
|
// 在上面叠加一个着色覆盖层 (Overlay a tinted layer on top)
|
||||||
|
private Drawable tintOverlay;
|
||||||
|
|
||||||
|
// 用户内容在最上层 (User content on top)
|
||||||
|
public Children { get; set; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**工作原理 / How It Works:**
|
||||||
|
|
||||||
|
1. **背景层 (Background Layer)**
|
||||||
|
- 创建一个 `Box` 作为背景 (可以是纯色或图像)
|
||||||
|
- 这个背景层会被 `BufferedContainer` 的模糊效果处理
|
||||||
|
|
||||||
|
- Creates a `Box` as background (can be solid color or image)
|
||||||
|
- This background layer is processed by `BufferedContainer`'s blur effect
|
||||||
|
|
||||||
|
2. **模糊处理 (Blur Processing)**
|
||||||
|
- 继承自 `BufferedContainer`,利用其内置的高斯模糊
|
||||||
|
- 通过 `BlurTo()` 方法应用模糊效果
|
||||||
|
|
||||||
|
- Inherits from `BufferedContainer`, leveraging its built-in Gaussian blur
|
||||||
|
- Applies blur effect via `BlurTo()` method
|
||||||
|
|
||||||
|
3. **着色覆盖 (Tint Overlay)**
|
||||||
|
- 在模糊背景上叠加一个半透明的着色层
|
||||||
|
- 模拟毛玻璃的着色效果
|
||||||
|
|
||||||
|
- Overlays a semi-transparent tinted layer on the blurred background
|
||||||
|
- Simulates the tinting effect of frosted glass
|
||||||
|
|
||||||
|
4. **用户内容 (User Content)**
|
||||||
|
- 用户添加的子元素显示在最上层
|
||||||
|
- 可以透过半透明的覆盖层看到模糊的背景
|
||||||
|
|
||||||
|
- User-added children are displayed on top
|
||||||
|
- Blurred background is visible through the semi-transparent overlay
|
||||||
|
|
||||||
|
## 使用方法 / Usage
|
||||||
|
|
||||||
|
### 基本用法 / Basic Usage
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var acrylicEffect = new AcrylicContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BlurStrength = 15f, // 模糊强度 (0-100)
|
||||||
|
TintColour = new Color4(0, 0, 0, 0.3f), // 着色 (半透明黑色)
|
||||||
|
BackgroundColour = Color4.White, // 要模糊的背景色
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SpriteText { Text = "Content" }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 属性说明 / Properties
|
||||||
|
|
||||||
|
| 属性 / Property | 说明 / Description |
|
||||||
|
|----------------|-------------------|
|
||||||
|
| `BlurStrength` | 模糊强度,值越大越模糊 (0-100) / Blur intensity, higher = more blur (0-100) |
|
||||||
|
| `TintColour` | 着色颜色,通常是半透明色 / Tint color, usually semi-transparent |
|
||||||
|
| `BackgroundColour` | 背景颜色,这个颜色会被模糊 / Background color that will be blurred |
|
||||||
|
|
||||||
|
### 视觉效果 / Visual Result
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────┐
|
||||||
|
│ 用户内容 (User Content) │ ← 清晰的文字/图像
|
||||||
|
├─────────────────────────────────┤
|
||||||
|
│ 半透明着色层 (Tint Overlay) │ ← Alpha < 1.0
|
||||||
|
├─────────────────────────────────┤
|
||||||
|
│ 模糊的背景 (Blurred Background) │ ← 高斯模糊效果
|
||||||
|
└─────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 局限性 / Limitations
|
||||||
|
|
||||||
|
1. **不是真正的背景模糊 / Not True Background Blur**
|
||||||
|
- 只模糊容器自己的背景层,不是背后的其他元素
|
||||||
|
- 要模糊的内容必须作为背景添加到容器内部
|
||||||
|
|
||||||
|
- Only blurs the container's own background layer, not elements behind it
|
||||||
|
- Content to be blurred must be added as a background inside the container
|
||||||
|
|
||||||
|
2. **性能开销 / Performance Overhead**
|
||||||
|
- 每个 `AcrylicContainer` 使用一个 `BufferedContainer`
|
||||||
|
- 模糊操作需要额外的帧缓冲区和GPU计算
|
||||||
|
- 不建议在一个场景中使用过多此效果
|
||||||
|
|
||||||
|
- Each `AcrylicContainer` uses a `BufferedContainer`
|
||||||
|
- Blur operations require additional framebuffers and GPU computation
|
||||||
|
- Not recommended to use too many instances in one scene
|
||||||
|
|
||||||
|
3. **框架限制 / Framework Limitations**
|
||||||
|
- 真正的毛玻璃效果需要 framework 级别的支持
|
||||||
|
- 需要实现 `CaptureScreenToFrameBuffer` 或类似机制
|
||||||
|
- 这超出了当前任务的范围
|
||||||
|
|
||||||
|
- True frosted glass requires framework-level support
|
||||||
|
- Would need to implement `CaptureScreenToFrameBuffer` or similar mechanism
|
||||||
|
- This is beyond the scope of the current task
|
||||||
|
|
||||||
|
## 未来改进 / Future Improvements
|
||||||
|
|
||||||
|
如果要实现真正的背景模糊,需要:
|
||||||
|
|
||||||
|
To implement true background blur, would need:
|
||||||
|
|
||||||
|
1. **实现屏幕捕获 / Implement Screen Capture**
|
||||||
|
```csharp
|
||||||
|
// 在 DeferredRenderer 中实现
|
||||||
|
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
||||||
|
{
|
||||||
|
// 将当前后台缓冲区内容复制到 frameBuffer
|
||||||
|
// Copy current backbuffer content to frameBuffer
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **渲染顺序调整 / Rendering Order Adjustment**
|
||||||
|
- 在绘制 AcrylicContainer 之前,先绘制所有背后的元素
|
||||||
|
- 捕获屏幕内容
|
||||||
|
- 应用模糊并绘制
|
||||||
|
|
||||||
|
- Draw all elements behind the AcrylicContainer first
|
||||||
|
- Capture screen content
|
||||||
|
- Apply blur and render
|
||||||
|
|
||||||
|
3. **Z-Order 支持 / Z-Order Support**
|
||||||
|
- Framework 需要支持基于深度的渲染顺序
|
||||||
|
- 或者添加特殊的"背景捕获"阶段
|
||||||
|
|
||||||
|
- Framework needs to support depth-based rendering order
|
||||||
|
- Or add a special "background capture" phase
|
||||||
|
|
||||||
|
## 测试 / Testing
|
||||||
|
|
||||||
|
运行测试场景查看效果:
|
||||||
|
|
||||||
|
Run the test scene to see the effect:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet run --project osu.Framework.Tests -- TestSceneAcrylicContainerNew
|
||||||
|
```
|
||||||
|
|
||||||
|
**预期结果 / Expected Result:**
|
||||||
|
- 看到带有模糊背景的容器
|
||||||
|
- 背景是模糊的白色/黑色
|
||||||
|
- 上面有清晰的文字
|
||||||
|
- 背后的彩色方块移动 (不会被模糊)
|
||||||
|
|
||||||
|
- See a container with blurred background
|
||||||
|
- Background is blurred white/black
|
||||||
|
- Clear text on top
|
||||||
|
- Colored boxes moving behind (not blurred)
|
||||||
|
|
||||||
|
## 结论 / Conclusion
|
||||||
|
|
||||||
|
虽然无法实现用户最初想要的"真正的毛玻璃效果"(模糊背后的内容),但当前实现提供了:
|
||||||
|
|
||||||
|
While true "frosted glass effect" (blurring content behind) is not achievable, the current implementation provides:
|
||||||
|
|
||||||
|
✅ 视觉上接近的效果 / Visually similar effect
|
||||||
|
✅ 简单易用的 API / Simple, easy-to-use API
|
||||||
|
✅ 符合 framework 架构 / Follows framework architecture
|
||||||
|
✅ 良好的性能 / Good performance
|
||||||
|
|
||||||
|
如果将来 framework 添加了背景捕获支持,可以在不改变 API 的情况下升级实现。
|
||||||
|
|
||||||
|
If the framework adds background capture support in the future, the implementation can be upgraded without changing the API.
|
||||||
85
Acrylic_Integration_Guide.cs
Normal file
85
Acrylic_Integration_Guide.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
// 完整的自动亚克力效果集成指南
|
||||||
|
|
||||||
|
/*
|
||||||
|
## 自动亚克力效果系统
|
||||||
|
|
||||||
|
这个系统让 AcrylicContainer 自动工作,无需修改 Game 类。
|
||||||
|
|
||||||
|
### 1. 在你的游戏中添加自动背景捕获组件
|
||||||
|
|
||||||
|
在你的 Game 类的 load 方法中添加:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
// ... 其他初始化代码 ...
|
||||||
|
|
||||||
|
// 添加自动背景捕获组件(只需要添加一次)
|
||||||
|
Add(new AutoBackgroundCapture());
|
||||||
|
|
||||||
|
// ... 创建你的 UI 组件 ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 在 UI 组件中使用 AcrylicContainer
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public partial class MyUIComponent : CompositeDrawable
|
||||||
|
{
|
||||||
|
private AcrylicContainer background = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
background = new AcrylicContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
TintColour = new Color4(0, 0, 0, 0.3f), // 黑色半透明
|
||||||
|
BlurStrength = 5f, // 模糊强度
|
||||||
|
};
|
||||||
|
|
||||||
|
AddInternal(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态控制效果
|
||||||
|
public void SetAcrylicEffect(float alpha, float blur)
|
||||||
|
{
|
||||||
|
background.TintColour = new Color4(0, 0, 0, alpha);
|
||||||
|
background.BlurStrength = blur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 系统如何工作
|
||||||
|
|
||||||
|
1. **AutoBackgroundCapture** 组件自动在 `UpdateAfterChildren` 中捕获屏幕内容
|
||||||
|
2. **BackgroundBufferManager** 单例管理全局背景缓冲区
|
||||||
|
3. **AcrylicContainer** 自动从管理器获取背景缓冲区并应用效果
|
||||||
|
4. 所有 AcrylicContainer 实例共享同一个背景缓冲区
|
||||||
|
|
||||||
|
### 4. 优势
|
||||||
|
|
||||||
|
- ✅ **无需修改 Game 类**:保持游戏逻辑清洁
|
||||||
|
- ✅ **自动工作**:UI 组件创建后自动获得背景虚化
|
||||||
|
- ✅ **高性能**:所有组件共享一个背景缓冲区
|
||||||
|
- ✅ **易于使用**:只需创建 AcrylicContainer 即可
|
||||||
|
|
||||||
|
### 5. 自定义选项
|
||||||
|
|
||||||
|
如果需要自定义背景缓冲区,可以手动设置:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
acrylicContainer.BackgroundBuffer = myCustomBuffer;
|
||||||
|
```
|
||||||
|
|
||||||
|
但在大多数情况下,自动系统就足够了。
|
||||||
|
*/
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
|
||||||
|
namespace osu.Framework.Graphics.Containers
|
||||||
|
{
|
||||||
|
// 这个文件只是为了展示用法,实际实现已在其他文件中
|
||||||
|
}
|
||||||
40
Integration_Example.cs
Normal file
40
Integration_Example.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// 正确的集成方式:背景缓冲区由游戏层管理
|
||||||
|
|
||||||
|
public partial class ManiaGameMode : Game
|
||||||
|
{
|
||||||
|
private IFrameBuffer? globalBackgroundBuffer;
|
||||||
|
private EzColumnBackground columnBackground = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
// 创建轨道背景
|
||||||
|
Add(columnBackground = new EzColumnBackground());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateAfterChildren()
|
||||||
|
{
|
||||||
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
|
// 在游戏层创建和管理背景缓冲区
|
||||||
|
globalBackgroundBuffer ??= Host.Renderer.CreateFrameBuffer(null, TextureFilteringMode.Linear);
|
||||||
|
|
||||||
|
// 捕获当前屏幕内容
|
||||||
|
if (Host.Renderer is Renderer concreteRenderer)
|
||||||
|
{
|
||||||
|
concreteRenderer.CaptureScreenToFrameBuffer(globalBackgroundBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置给轨道背景
|
||||||
|
columnBackground.SetBackgroundBuffer(globalBackgroundBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
// 根据游戏状态控制虚化效果
|
||||||
|
// 例如:根据谱面难度、播放状态等调整
|
||||||
|
columnBackground.SetDimLevel(0.3f, 5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework;
|
|
||||||
using osu.Framework.Platform;
|
|
||||||
|
|
||||||
namespace SampleGame.Desktop
|
|
||||||
{
|
|
||||||
public static class Program
|
|
||||||
{
|
|
||||||
[STAThread]
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
using (GameHost host = Host.GetSuitableDesktopHost(@"sample-game"))
|
|
||||||
using (Game game = new SampleGameGame())
|
|
||||||
host.Run(game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup Label="Project">
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<OutputType>WinExe</OutputType>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup Label="Project References">
|
|
||||||
<ProjectReference Include="..\osu.Framework\osu.Framework.csproj" />
|
|
||||||
<ProjectReference Include="..\SampleGame\SampleGame.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup Label="Project References">
|
|
||||||
<ProjectReference Include="..\osu.Framework\osu.Framework.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using osu.Framework;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Framework.Graphics.Rendering;
|
|
||||||
|
|
||||||
namespace SampleGame
|
|
||||||
{
|
|
||||||
public partial class SampleGameGame : Game
|
|
||||||
{
|
|
||||||
private Box backgroundBox = null!;
|
|
||||||
private AcrylicContainer acrylicContainer = null!;
|
|
||||||
private IFrameBuffer? backgroundBuffer;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
// Background
|
|
||||||
Add(backgroundBox = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Color4.Blue
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add some additional background elements
|
|
||||||
Add(new Box
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopLeft,
|
|
||||||
Origin = Anchor.TopLeft,
|
|
||||||
Size = new Vector2(100, 100),
|
|
||||||
Colour = Color4.Red
|
|
||||||
});
|
|
||||||
|
|
||||||
Add(new Box
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomRight,
|
|
||||||
Origin = Anchor.BottomRight,
|
|
||||||
Size = new Vector2(150, 150),
|
|
||||||
Colour = Color4.Green
|
|
||||||
});
|
|
||||||
|
|
||||||
// Acrylic container on top - now uses background buffer for true acrylic effect
|
|
||||||
Add(acrylicContainer = new AcrylicContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Size = new Vector2(200, 200),
|
|
||||||
TintColour = new Color4(1f, 1f, 1f, 0.5f), // Semi-transparent white
|
|
||||||
BlurStrength = 5f, // Apply blur to background
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
|
||||||
{
|
|
||||||
base.UpdateAfterChildren();
|
|
||||||
|
|
||||||
// Capture background after children are updated
|
|
||||||
if (backgroundBuffer == null)
|
|
||||||
{
|
|
||||||
backgroundBuffer = Host.Renderer.CreateFrameBuffer(null, TextureFilteringMode.Linear);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capture the current screen content as background
|
|
||||||
if (Host.Renderer is Renderer concreteRenderer)
|
|
||||||
{
|
|
||||||
concreteRenderer.CaptureScreenToFrameBuffer(backgroundBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the background buffer to the acrylic container
|
|
||||||
if (acrylicContainer != null)
|
|
||||||
{
|
|
||||||
acrylicContainer.BackgroundBuffer = backgroundBuffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
backgroundBox.Rotation += (float)Time.Elapsed / 20;
|
|
||||||
acrylicContainer.Rotation -= (float)Time.Elapsed / 15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,9 +15,7 @@
|
|||||||
"osu.Framework.Templates\\templates\\template-flappy\\FlappyDon.Game\\FlappyDon.Game.csproj",
|
"osu.Framework.Templates\\templates\\template-flappy\\FlappyDon.Game\\FlappyDon.Game.csproj",
|
||||||
"osu.Framework.Templates\\templates\\template-flappy\\FlappyDon.Resources\\FlappyDon.Resources.csproj",
|
"osu.Framework.Templates\\templates\\template-flappy\\FlappyDon.Resources\\FlappyDon.Resources.csproj",
|
||||||
"osu.Framework.Tests\\osu.Framework.Tests.csproj",
|
"osu.Framework.Tests\\osu.Framework.Tests.csproj",
|
||||||
"osu.Framework\\osu.Framework.csproj",
|
"osu.Framework\\osu.Framework.csproj"
|
||||||
"SampleGame.Desktop\\SampleGame.Desktop.csproj",
|
|
||||||
"SampleGame\\SampleGame.csproj"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,12 +5,8 @@ VisualStudioVersion = 16.0.29409.12
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework", "osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework", "osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleGame", "SampleGame\SampleGame.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework.Tests", "osu.Framework.Tests\osu.Framework.Tests.csproj", "{79803407-6F50-484F-93F5-641911EABD8A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework.Tests", "osu.Framework.Tests\osu.Framework.Tests.csproj", "{79803407-6F50-484F-93F5-641911EABD8A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleGame.Desktop", "SampleGame.Desktop\SampleGame.Desktop.csproj", "{2AD6EA6F-CD5A-4348-86F1-5E228B11617D}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework.NativeLibs", "osu.Framework.NativeLibs\osu.Framework.NativeLibs.csproj", "{F853B4BB-CB83-4169-8FD2-72EEB4A88C32}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework.NativeLibs", "osu.Framework.NativeLibs\osu.Framework.NativeLibs.csproj", "{F853B4BB-CB83-4169-8FD2-72EEB4A88C32}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework.iOS", "osu.Framework.iOS\osu.Framework.iOS.csproj", "{BBC0D18F-8595-43A6-AE61-5BF36A072CCE}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework.iOS", "osu.Framework.iOS\osu.Framework.iOS.csproj", "{BBC0D18F-8595-43A6-AE61-5BF36A072CCE}"
|
||||||
@@ -86,18 +82,10 @@ Global
|
|||||||
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{2AD6EA6F-CD5A-4348-86F1-5E228B11617D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{F853B4BB-CB83-4169-8FD2-72EEB4A88C32}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
|||||||
26
osu.Framework.Tests/Graphics/TestSceneAcrylicContainer.cs
Normal file
26
osu.Framework.Tests/Graphics/TestSceneAcrylicContainer.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
|
namespace osu.Framework.Tests.Graphics
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneAcrylicContainer : TestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestAcrylicContainerCreation()
|
||||||
|
{
|
||||||
|
AddStep("create acrylic container", () =>
|
||||||
|
{
|
||||||
|
Child = new AcrylicTestContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Framework.Tests.Visual.Containers
|
||||||
|
{
|
||||||
|
public partial class TestSceneAcrylicContainer : TestScene
|
||||||
|
{
|
||||||
|
private bool isWhiteTint = true;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(TextureStore textures)
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
// Background texture (full screen)
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Texture = textures.Get("sample-texture")
|
||||||
|
},
|
||||||
|
|
||||||
|
// Left side: Semi-transparent overlay to show original texture
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Colour4.White.Opacity(0.1f) // Very subtle overlay
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Right side: AcrylicContainer with blur effect (buffered container)
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Width = 0.5f,
|
||||||
|
Child = new AcrylicContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BlurStrength = 50f,
|
||||||
|
TintColour = Colour4.Red.Opacity(0.8f),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Labels
|
||||||
|
new SpriteText
|
||||||
|
{
|
||||||
|
Text = "Original Texture (No Blur)",
|
||||||
|
Font = FontUsage.Default.With(size: 24),
|
||||||
|
Colour = Colour4.White,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Position = new Vector2(-200, 20),
|
||||||
|
},
|
||||||
|
new SpriteText
|
||||||
|
{
|
||||||
|
Text = "AcrylicContainer (Buffered Blur)",
|
||||||
|
Font = FontUsage.Default.With(size: 24),
|
||||||
|
Colour = Colour4.White,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Position = new Vector2(200, 20),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Blur strength control
|
||||||
|
AddSliderStep("blur strength", 0f, 20f, 10f, strength =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
acrylic.BlurStrength = strength;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Tint colour controls
|
||||||
|
AddSliderStep("tint alpha", 0f, 1f, 0.8f, alpha =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
acrylic.TintColour = Colour4.White.Opacity(alpha);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddSliderStep("tint red", 0f, 1f, 1f, red =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
{
|
||||||
|
var currentColour = acrylic.TintColour;
|
||||||
|
if (currentColour.TryExtractSingleColour(out var colour))
|
||||||
|
acrylic.TintColour = new Colour4(red, colour.Linear.G, colour.Linear.B, colour.Linear.A);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddSliderStep("tint green", 0f, 1f, 1f, green =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
{
|
||||||
|
var currentColour = acrylic.TintColour;
|
||||||
|
if (currentColour.TryExtractSingleColour(out var colour))
|
||||||
|
acrylic.TintColour = new Colour4(colour.Linear.R, green, colour.Linear.B, colour.Linear.A);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddSliderStep("tint blue", 0f, 1f, 1f, blue =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
{
|
||||||
|
var currentColour = acrylic.TintColour;
|
||||||
|
if (currentColour.TryExtractSingleColour(out var colour))
|
||||||
|
acrylic.TintColour = new Colour4(colour.Linear.R, colour.Linear.G, blue, colour.Linear.A);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("toggle tint colour", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
{
|
||||||
|
isWhiteTint = !isWhiteTint;
|
||||||
|
acrylic.TintColour = isWhiteTint
|
||||||
|
? Colour4.White.Opacity(0.8f)
|
||||||
|
: Colour4.Blue.Opacity(0.8f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test different blur scenarios
|
||||||
|
AddStep("no blur", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null) acrylic.BlurStrength = 0;
|
||||||
|
});
|
||||||
|
AddStep("light blur", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null) acrylic.BlurStrength = 5;
|
||||||
|
});
|
||||||
|
AddStep("medium blur", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null) acrylic.BlurStrength = 10;
|
||||||
|
});
|
||||||
|
AddStep("heavy blur", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null) acrylic.BlurStrength = 20;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test tint scenarios
|
||||||
|
AddStep("no tint", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null) acrylic.TintColour = Colour4.White.Opacity(0);
|
||||||
|
});
|
||||||
|
AddStep("subtle tint", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null) acrylic.TintColour = Colour4.White.Opacity(0.3f);
|
||||||
|
});
|
||||||
|
AddStep("medium tint", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null) acrylic.TintColour = Colour4.White.Opacity(0.6f);
|
||||||
|
});
|
||||||
|
AddStep("strong tint", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null) acrylic.TintColour = Colour4.White.Opacity(0.9f);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Debug presets
|
||||||
|
AddStep("debug: high contrast", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
{
|
||||||
|
acrylic.BlurStrength = 15f;
|
||||||
|
acrylic.TintColour = Colour4.Red.Opacity(0.7f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("debug: subtle effect", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
{
|
||||||
|
acrylic.BlurStrength = 3f;
|
||||||
|
acrylic.TintColour = Colour4.Black.Opacity(0.2f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("debug: reset to default", () =>
|
||||||
|
{
|
||||||
|
var acrylic = Children[2] as AcrylicContainer;
|
||||||
|
if (acrylic != null)
|
||||||
|
{
|
||||||
|
acrylic.BlurStrength = 10f;
|
||||||
|
acrylic.TintColour = Colour4.White.Opacity(0.8f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,190 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Framework.Tests.Visual.Containers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 测试真正的毛玻璃效果 - 使用新重构的AcrylicContainer
|
||||||
|
/// 这个容器可以对下层的任何内容进行实时模糊,包括视频、动画等
|
||||||
|
/// </summary>
|
||||||
|
public partial class TestSceneAcrylicContainerNew : TestScene
|
||||||
|
{
|
||||||
|
private AcrylicContainer? acrylicEffect;
|
||||||
|
private Box? animatedBox;
|
||||||
|
private readonly List<Box> movingBoxes = new List<Box>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
// 创建一个彩色渐变背景层
|
||||||
|
Add(new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = ColourInfo.GradientVertical(Color4.Blue, Color4.Purple)
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加一些移动的彩色方块作为背景内容
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var box = new Box
|
||||||
|
{
|
||||||
|
Size = new Vector2(100),
|
||||||
|
Colour = new Color4(
|
||||||
|
(float)RNG.NextDouble(),
|
||||||
|
(float)RNG.NextDouble(),
|
||||||
|
(float)RNG.NextDouble(),
|
||||||
|
1f
|
||||||
|
),
|
||||||
|
Position = new Vector2(
|
||||||
|
(float)(RNG.NextDouble() * 800),
|
||||||
|
(float)(RNG.NextDouble() * 600)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Add(box);
|
||||||
|
movingBoxes.Add(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加一个持续旋转的大方块
|
||||||
|
animatedBox = new Box
|
||||||
|
{
|
||||||
|
Size = new Vector2(200),
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Colour = Color4.Yellow
|
||||||
|
};
|
||||||
|
|
||||||
|
Add(animatedBox);
|
||||||
|
|
||||||
|
// 在上面添加毛玻璃效果容器
|
||||||
|
Add(new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(100),
|
||||||
|
Child = acrylicEffect = new AcrylicContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BlurStrength = 15f,
|
||||||
|
TintColour = new Color4(0, 0, 0, 0.3f),
|
||||||
|
BackgroundColour = Color4.Black.Opacity(0.5f), // 半透明黑色背景
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
// 在毛玻璃效果上面显示一些文本
|
||||||
|
new SpriteText
|
||||||
|
{
|
||||||
|
Text = "毛玻璃效果 (Acrylic Effect)\n\n注意: 此容器模糊自己的背景层,\n不是背后的内容。\n这是 osu-framework 的限制。",
|
||||||
|
Font = FontUsage.Default.With(size: 30),
|
||||||
|
Colour = Color4.White,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Shadow = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
// 在LoadComplete后启动动画
|
||||||
|
// 让方块循环移动
|
||||||
|
foreach (var box in movingBoxes)
|
||||||
|
{
|
||||||
|
box.MoveTo(new Vector2(
|
||||||
|
(float)(RNG.NextDouble() * 800),
|
||||||
|
(float)(RNG.NextDouble() * 600)
|
||||||
|
), 3000).Then().MoveTo(new Vector2(
|
||||||
|
(float)(RNG.NextDouble() * 800),
|
||||||
|
(float)(RNG.NextDouble() * 600)
|
||||||
|
), 3000).Loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 让黄色方块持续旋转
|
||||||
|
animatedBox?.RotateTo(360, 4000).Then().RotateTo(0, 0).Loop();
|
||||||
|
|
||||||
|
// 添加控制UI
|
||||||
|
AddLabel("模糊强度 (Blur Strength)");
|
||||||
|
AddSliderStep("blur", 0f, 50f, 15f, value =>
|
||||||
|
{
|
||||||
|
if (acrylicEffect != null)
|
||||||
|
acrylicEffect.BlurStrength = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddLabel("着色透明度 (Tint Alpha)");
|
||||||
|
AddSliderStep("alpha", 0f, 1f, 0.3f, value =>
|
||||||
|
{
|
||||||
|
if (acrylicEffect != null)
|
||||||
|
{
|
||||||
|
var current = acrylicEffect.TintColour.TopLeft.Linear;
|
||||||
|
acrylicEffect.TintColour = new Color4(current.R, current.G, current.B, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddLabel("着色颜色 (Tint Color)");
|
||||||
|
AddStep("黑色 (Black)", () =>
|
||||||
|
{
|
||||||
|
if (acrylicEffect != null)
|
||||||
|
{
|
||||||
|
var alpha = acrylicEffect.TintColour.TopLeft.Linear.A;
|
||||||
|
acrylicEffect.TintColour = new Color4(0, 0, 0, alpha);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("白色 (White)", () =>
|
||||||
|
{
|
||||||
|
if (acrylicEffect != null)
|
||||||
|
{
|
||||||
|
var alpha = acrylicEffect.TintColour.TopLeft.Linear.A;
|
||||||
|
acrylicEffect.TintColour = new Color4(1, 1, 1, alpha);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("红色 (Red)", () =>
|
||||||
|
{
|
||||||
|
if (acrylicEffect != null)
|
||||||
|
{
|
||||||
|
var alpha = acrylicEffect.TintColour.TopLeft.Linear.A;
|
||||||
|
acrylicEffect.TintColour = new Color4(1, 0, 0, alpha);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("蓝色 (Blue)", () =>
|
||||||
|
{
|
||||||
|
if (acrylicEffect != null)
|
||||||
|
{
|
||||||
|
var alpha = acrylicEffect.TintColour.TopLeft.Linear.A;
|
||||||
|
acrylicEffect.TintColour = new Color4(0, 0, 1, alpha);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddLabel("效果演示 (Demos)");
|
||||||
|
AddStep("显示/隐藏毛玻璃", () =>
|
||||||
|
{
|
||||||
|
if (acrylicEffect != null)
|
||||||
|
acrylicEffect.Alpha = acrylicEffect.Alpha > 0 ? 0 : 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("脉冲动画", () =>
|
||||||
|
{
|
||||||
|
acrylicEffect?.ScaleTo(1.1f, 500, Easing.OutQuint)
|
||||||
|
.Then()
|
||||||
|
.ScaleTo(1f, 500, Easing.InQuint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,64 +1,132 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osuTK;
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Graphics.Rendering;
|
|
||||||
|
|
||||||
namespace osu.Framework.Graphics.Containers
|
namespace osu.Framework.Graphics.Containers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A container that applies an acrylic/mica effect by blurring the content behind it.
|
/// A container that applies an acrylic/frosted glass visual effect.
|
||||||
/// This creates a frosted glass-like appearance where content below the container is visible through a blur.
|
/// This is achieved by using a <see cref="BufferedContainer"/> with blur and a tinted overlay.
|
||||||
|
/// The container blurs its own background (a solid color or drawable), not content behind it.
|
||||||
|
///
|
||||||
|
/// Usage:
|
||||||
|
/// <code>
|
||||||
|
/// var acrylicEffect = new AcrylicContainer
|
||||||
|
/// {
|
||||||
|
/// RelativeSizeAxes = Axes.Both,
|
||||||
|
/// BlurStrength = 10f,
|
||||||
|
/// TintColour = new Color4(0, 0, 0, 0.3f),
|
||||||
|
/// BackgroundColour = Color4.White, // The color to blur
|
||||||
|
/// Children = new Drawable[] { /* your content */ }
|
||||||
|
/// };
|
||||||
|
/// </code>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class AcrylicContainer : BufferedContainer
|
public partial class AcrylicContainer : BufferedContainer
|
||||||
{
|
{
|
||||||
/// <summary>
|
private float blurStrength = 10f;
|
||||||
/// The strength of the blur effect applied to the background content.
|
|
||||||
/// </summary>
|
|
||||||
public float BlurStrength { get; set; } = 10f;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The background texture to blur. If null, blurs the container's children.
|
/// The strength of the blur effect.
|
||||||
|
/// Higher values create a stronger blur. Range: 0-100, typical values: 5-20.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IFrameBuffer? BackgroundBuffer { get; set; }
|
public float BlurStrength
|
||||||
|
{
|
||||||
|
get => blurStrength;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (blurStrength == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
blurStrength = value;
|
||||||
|
updateBlur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ColourInfo tintColour = ColourInfo.SingleColour(new Color4(0, 0, 0, 0.3f));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The tint colour applied over the blurred background.
|
/// The tint colour applied over the blurred background.
|
||||||
|
/// Typically a semi-transparent color like Color4(0, 0, 0, 0.3f).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color4 TintColour { get; set; } = new Color4(1f, 1f, 1f, 0.8f);
|
public new ColourInfo TintColour
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new acrylic container.
|
|
||||||
/// </summary>
|
|
||||||
public AcrylicContainer()
|
|
||||||
: base(formats: null, pixelSnapping: false, cachedFrameBuffer: false)
|
|
||||||
{
|
{
|
||||||
// Enable drawing original content with blur effect
|
get => tintColour;
|
||||||
DrawOriginal = true;
|
set
|
||||||
|
|
||||||
// Set up blur for the acrylic effect
|
|
||||||
BlurSigma = new Vector2(BlurStrength);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
// Schedule a capture of the background after the scene is fully loaded
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
{
|
||||||
// Capture the background by temporarily hiding ourselves
|
if (tintColour.Equals(value))
|
||||||
float wasAlpha = Alpha;
|
return;
|
||||||
Alpha = 0;
|
|
||||||
|
|
||||||
// Force a redraw to capture the background
|
tintColour = value;
|
||||||
Invalidate(Invalidation.DrawNode);
|
updateTint();
|
||||||
|
}
|
||||||
Alpha = wasAlpha;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawNode CreateDrawNode() => new AcrylicContainerDrawNode(this);
|
private Drawable? backgroundBox;
|
||||||
|
private Drawable? tintOverlay;
|
||||||
|
|
||||||
|
public AcrylicContainer()
|
||||||
|
: base(cachedFrameBuffer: true)
|
||||||
|
{
|
||||||
|
BackgroundColour = Color4.White; // Default white background to blur
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
// Add a background box that will be blurred
|
||||||
|
AddInternal(backgroundBox = new Shapes.Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = BackgroundColour,
|
||||||
|
Depth = float.MaxValue // Behind everything
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a tint overlay on top
|
||||||
|
AddInternal(tintOverlay = new Shapes.Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = tintColour,
|
||||||
|
Depth = float.MinValue, // In front of everything
|
||||||
|
Alpha = tintColour.TopLeft.Linear.A
|
||||||
|
});
|
||||||
|
|
||||||
|
updateBlur();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBlur()
|
||||||
|
{
|
||||||
|
if (!IsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Convert BlurStrength to sigma for the blur shader
|
||||||
|
// sigma controls the Gaussian distribution width
|
||||||
|
float sigma = Math.Max(0.5f, blurStrength * 0.5f);
|
||||||
|
this.BlurTo(new osuTK.Vector2(sigma), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTint()
|
||||||
|
{
|
||||||
|
if (tintOverlay != null)
|
||||||
|
{
|
||||||
|
tintOverlay.Colour = tintColour;
|
||||||
|
tintOverlay.Alpha = tintColour.TopLeft.Linear.A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public new Color4 BackgroundColour
|
||||||
|
{
|
||||||
|
get => base.BackgroundColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.BackgroundColour = value;
|
||||||
|
|
||||||
|
if (backgroundBox != null)
|
||||||
|
backgroundBox.Colour = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Graphics.Colour;
|
|
||||||
using osu.Framework.Graphics.Rendering;
|
|
||||||
|
|
||||||
namespace osu.Framework.Graphics.Containers
|
|
||||||
{
|
|
||||||
public partial class AcrylicContainer
|
|
||||||
{
|
|
||||||
private class AcrylicContainerDrawNode : BufferedDrawNode
|
|
||||||
{
|
|
||||||
protected new AcrylicContainer Source => (AcrylicContainer)base.Source;
|
|
||||||
|
|
||||||
public AcrylicContainerDrawNode(AcrylicContainer source)
|
|
||||||
: base(source, new CompositeDrawableDrawNode(source), new BufferedDrawNodeSharedData())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DrawContents(IRenderer renderer)
|
|
||||||
{
|
|
||||||
if (Source.BackgroundBuffer != null)
|
|
||||||
{
|
|
||||||
// Draw the background buffer directly with tint
|
|
||||||
ColourInfo finalColour = DrawColourInfo.Colour;
|
|
||||||
finalColour.ApplyChild(Source.TintColour);
|
|
||||||
|
|
||||||
renderer.DrawFrameBuffer(Source.BackgroundBuffer, DrawRectangle, finalColour);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Apply tint to the blurred content
|
|
||||||
ColourInfo finalColour = DrawColourInfo.Colour;
|
|
||||||
finalColour.ApplyChild(Source.TintColour);
|
|
||||||
|
|
||||||
renderer.DrawFrameBuffer(SharedData.CurrentEffectBuffer, DrawRectangle, finalColour);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
55
osu.Framework/Graphics/Containers/AcrylicTestContainer.cs
Normal file
55
osu.Framework/Graphics/Containers/AcrylicTestContainer.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
|
||||||
|
namespace osu.Framework.Graphics.Containers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Simple test class to verify AcrylicContainer functionality
|
||||||
|
/// </summary>
|
||||||
|
public partial class AcrylicTestContainer : Container
|
||||||
|
{
|
||||||
|
public AcrylicTestContainer()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
// Add some background content to blur
|
||||||
|
Add(new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Colour4.Red,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add text overlay
|
||||||
|
Add(new SpriteText
|
||||||
|
{
|
||||||
|
Text = "Background Content",
|
||||||
|
Font = FontUsage.Default.With(size: 24),
|
||||||
|
Colour = Colour4.White,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the acrylic container on top
|
||||||
|
Add(new AcrylicContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BlurStrength = 10f,
|
||||||
|
TintColour = Colour4.White.Opacity(0.8f),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SpriteText
|
||||||
|
{
|
||||||
|
Text = "Acrylic Effect Test",
|
||||||
|
Font = FontUsage.Default.With(size: 32),
|
||||||
|
Colour = Colour4.Black,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
osu.Framework/Graphics/Containers/AutoBackgroundCapture.cs
Normal file
40
osu.Framework/Graphics/Containers/AutoBackgroundCapture.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// 自动背景捕获组件 - 在游戏中自动管理背景缓冲区更新
|
||||||
|
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
|
||||||
|
namespace osu.Framework.Graphics.Containers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A component that automatically captures the screen background for acrylic effects.
|
||||||
|
/// Add this to your game once to enable automatic background capture for all AcrylicContainer instances.
|
||||||
|
/// </summary>
|
||||||
|
public partial class AutoBackgroundCapture : Drawable
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private IRenderer? renderer { get; set; }
|
||||||
|
|
||||||
|
private bool initialized;
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
// 初始化延迟到Update方法中进行
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
// 延迟初始化,确保在正确的线程中
|
||||||
|
if (!initialized && renderer != null)
|
||||||
|
{
|
||||||
|
BackgroundBufferManager.Instance.Initialize(renderer);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动更新背景缓冲区
|
||||||
|
BackgroundBufferManager.Instance.UpdateBackgroundBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
osu.Framework/Graphics/Containers/BackgroundBufferManager.cs
Normal file
91
osu.Framework/Graphics/Containers/BackgroundBufferManager.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// 全局背景缓冲区管理器 - 自动管理背景捕获
|
||||||
|
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
|
namespace osu.Framework.Graphics.Containers
|
||||||
|
{
|
||||||
|
public class BackgroundBufferManager
|
||||||
|
{
|
||||||
|
private static BackgroundBufferManager? instance;
|
||||||
|
private static readonly object lockObject = new object();
|
||||||
|
|
||||||
|
public static BackgroundBufferManager Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
lock (lockObject)
|
||||||
|
{
|
||||||
|
instance ??= new BackgroundBufferManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IFrameBuffer? backgroundBuffer;
|
||||||
|
private IRenderer? renderer;
|
||||||
|
private bool initialized;
|
||||||
|
|
||||||
|
// 初始化管理器(在游戏启动时调用一次)
|
||||||
|
public void Initialize(IRenderer renderer)
|
||||||
|
{
|
||||||
|
this.renderer = renderer;
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取背景缓冲区 - 如果不存在则创建
|
||||||
|
public IFrameBuffer? GetBackgroundBuffer()
|
||||||
|
{
|
||||||
|
if (backgroundBuffer == null && renderer != null)
|
||||||
|
{
|
||||||
|
backgroundBuffer = renderer.CreateFrameBuffer(null, TextureFilteringMode.Linear);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
return backgroundBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取或创建背景缓冲区(在绘制线程调用 - 延迟创建模式)
|
||||||
|
public IFrameBuffer GetOrCreateBackgroundBuffer(IRenderer renderer)
|
||||||
|
{
|
||||||
|
if (backgroundBuffer == null)
|
||||||
|
{
|
||||||
|
this.renderer = renderer;
|
||||||
|
backgroundBuffer = renderer.CreateFrameBuffer(null, TextureFilteringMode.Linear);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return backgroundBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保背景缓冲区已创建(在绘制线程安全的地方调用)
|
||||||
|
public void EnsureBackgroundBuffer()
|
||||||
|
{
|
||||||
|
if (!initialized && renderer != null)
|
||||||
|
{
|
||||||
|
backgroundBuffer ??= renderer.CreateFrameBuffer(null, TextureFilteringMode.Linear);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新背景缓冲区(在UpdateAfterChildren中调用)
|
||||||
|
public void UpdateBackgroundBuffer()
|
||||||
|
{
|
||||||
|
if (renderer is Renderer concreteRenderer && backgroundBuffer != null)
|
||||||
|
{
|
||||||
|
concreteRenderer.CaptureScreenToFrameBuffer(backgroundBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理资源
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
backgroundBuffer?.Dispose();
|
||||||
|
backgroundBuffer = null;
|
||||||
|
renderer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,9 @@
|
|||||||
using osuTK;
|
using osuTK;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Extensions.EnumExtensions;
|
using osu.Framework.Extensions.EnumExtensions;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
|
||||||
namespace osu.Framework.Graphics.Containers
|
namespace osu.Framework.Graphics.Containers
|
||||||
{
|
{
|
||||||
@@ -92,5 +94,70 @@ namespace osu.Framework.Graphics.Containers
|
|||||||
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the subtree for <see cref="ITabbableContainer"/>s and moves focus to the <see cref="ITabbableContainer"/> before/after the one currently focused.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">Container to search for valid focus targets in.</param>
|
||||||
|
/// <param name="reverse">Whether to traverse the container's children in reverse when looking for the next target.</param>
|
||||||
|
/// <param name="requireFocusedChild">
|
||||||
|
/// Determines the behaviour when the currently focused drawable isn't rooted at this container.
|
||||||
|
/// If true, then focus will not be moved.
|
||||||
|
/// If false, then focus will be moved to the first valid child.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Whether focus was moved to a new <see cref="ITabbableContainer"/>.</returns>
|
||||||
|
public static bool MoveFocusToNextTabStop(this CompositeDrawable target, bool reverse = false, bool requireFocusedChild = true)
|
||||||
|
{
|
||||||
|
var currentlyFocused = target.GetContainingInputManager()?.FocusedDrawable;
|
||||||
|
|
||||||
|
if (currentlyFocused == null && requireFocusedChild)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var focusManager = target.GetContainingFocusManager().AsNonNull();
|
||||||
|
|
||||||
|
Stack<Drawable> stack = new Stack<Drawable>();
|
||||||
|
stack.Push(target); // Extra push for circular tabbing
|
||||||
|
stack.Push(target);
|
||||||
|
|
||||||
|
// If we don't have a currently focused child we pretend we've already encountered our target child to move focus to the first valid target.
|
||||||
|
bool started = currentlyFocused == null;
|
||||||
|
|
||||||
|
while (stack.Count > 0)
|
||||||
|
{
|
||||||
|
var drawable = stack.Pop();
|
||||||
|
|
||||||
|
if (!started)
|
||||||
|
started = ReferenceEquals(drawable, currentlyFocused);
|
||||||
|
else if (drawable is ITabbableContainer tabbable && tabbable.CanBeTabbedTo && focusManager.ChangeFocus(drawable))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (drawable is CompositeDrawable composite)
|
||||||
|
{
|
||||||
|
var newChildren = composite.InternalChildren.ToList();
|
||||||
|
int bound = reverse ? newChildren.Count : 0;
|
||||||
|
|
||||||
|
if (!started)
|
||||||
|
{
|
||||||
|
// Find currently focused element, to know starting point
|
||||||
|
int index = newChildren.IndexOf(currentlyFocused);
|
||||||
|
if (index != -1)
|
||||||
|
bound = reverse ? index + 1 : index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < bound; i++)
|
||||||
|
stack.Push(newChildren[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = newChildren.Count - 1; i >= bound; i--)
|
||||||
|
stack.Push(newChildren[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
@@ -44,54 +41,8 @@ namespace osu.Framework.Graphics.Containers
|
|||||||
if (TabbableContentContainer == null || e.Key != Key.Tab)
|
if (TabbableContentContainer == null || e.Key != Key.Tab)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
moveToNextTabStop(TabbableContentContainer, e.ShiftPressed);
|
TabbableContentContainer.MoveFocusToNextTabStop(e.ShiftPressed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void moveToNextTabStop(CompositeDrawable target, bool reverse)
|
|
||||||
{
|
|
||||||
var focusManager = GetContainingFocusManager().AsNonNull();
|
|
||||||
|
|
||||||
Stack<Drawable> stack = new Stack<Drawable>();
|
|
||||||
stack.Push(target); // Extra push for circular tabbing
|
|
||||||
stack.Push(target);
|
|
||||||
|
|
||||||
bool started = false;
|
|
||||||
|
|
||||||
while (stack.Count > 0)
|
|
||||||
{
|
|
||||||
var drawable = stack.Pop();
|
|
||||||
|
|
||||||
if (!started)
|
|
||||||
started = ReferenceEquals(drawable, this);
|
|
||||||
else if (drawable is ITabbableContainer tabbable && tabbable.CanBeTabbedTo && focusManager.ChangeFocus(drawable))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (drawable is CompositeDrawable composite)
|
|
||||||
{
|
|
||||||
var newChildren = composite.InternalChildren.ToList();
|
|
||||||
int bound = reverse ? newChildren.Count : 0;
|
|
||||||
|
|
||||||
if (!started)
|
|
||||||
{
|
|
||||||
// Find self, to know starting point
|
|
||||||
int index = newChildren.IndexOf(this);
|
|
||||||
if (index != -1)
|
|
||||||
bound = reverse ? index + 1 : index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reverse)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < bound; i++)
|
|
||||||
stack.Push(newChildren[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = newChildren.Count - 1; i >= bound; i--)
|
|
||||||
stack.Push(newChildren[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,6 +267,7 @@ namespace osu.Framework.Graphics.Lines
|
|||||||
Line? segmentToDraw = null;
|
Line? segmentToDraw = null;
|
||||||
SegmentStartLocation location = SegmentStartLocation.Outside;
|
SegmentStartLocation location = SegmentStartLocation.Outside;
|
||||||
SegmentStartLocation modifiedLocation = SegmentStartLocation.Outside;
|
SegmentStartLocation modifiedLocation = SegmentStartLocation.Outside;
|
||||||
|
SegmentStartLocation nextLocation = SegmentStartLocation.End;
|
||||||
SegmentWithThickness? lastDrawnSegment = null;
|
SegmentWithThickness? lastDrawnSegment = null;
|
||||||
|
|
||||||
for (int i = 0; i < segments.Count; i++)
|
for (int i = 0; i < segments.Count; i++)
|
||||||
@@ -286,18 +287,24 @@ namespace osu.Framework.Graphics.Lines
|
|||||||
Vector2 closest = segmentToDraw.Value.At(progress);
|
Vector2 closest = segmentToDraw.Value.At(progress);
|
||||||
|
|
||||||
// Expand segment if next end point is located within a line passing through it
|
// Expand segment if next end point is located within a line passing through it
|
||||||
if (Precision.AlmostEquals(closest, segments[i].EndPoint, 0.1f))
|
if (Precision.AlmostEquals(closest, segments[i].EndPoint, 0.01f))
|
||||||
{
|
{
|
||||||
if (progress < 0)
|
if (progress < 0)
|
||||||
{
|
{
|
||||||
// expand segment backwards
|
// expand segment backwards
|
||||||
segmentToDraw = new Line(segments[i].EndPoint, segmentToDraw.Value.EndPoint);
|
segmentToDraw = new Line(segments[i].EndPoint, segmentToDraw.Value.EndPoint);
|
||||||
modifiedLocation = SegmentStartLocation.Outside;
|
modifiedLocation = SegmentStartLocation.Outside;
|
||||||
|
nextLocation = SegmentStartLocation.Start;
|
||||||
}
|
}
|
||||||
else if (progress > 1)
|
else if (progress > 1)
|
||||||
{
|
{
|
||||||
// or forward
|
// or forward
|
||||||
segmentToDraw = new Line(segmentToDraw.Value.StartPoint, segments[i].EndPoint);
|
segmentToDraw = new Line(segmentToDraw.Value.StartPoint, segments[i].EndPoint);
|
||||||
|
nextLocation = SegmentStartLocation.End;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextLocation = SegmentStartLocation.Middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // Otherwise draw the expanded segment
|
else // Otherwise draw the expanded segment
|
||||||
@@ -307,11 +314,9 @@ namespace osu.Framework.Graphics.Lines
|
|||||||
connect(s, lastDrawnSegment, texRect);
|
connect(s, lastDrawnSegment, texRect);
|
||||||
|
|
||||||
lastDrawnSegment = s;
|
lastDrawnSegment = s;
|
||||||
|
|
||||||
// Figure out at which point within currently drawn segment the new one starts
|
|
||||||
float p = progressFor(segmentToDraw.Value, segmentToDrawLength, segments[i].StartPoint);
|
|
||||||
segmentToDraw = segments[i];
|
segmentToDraw = segments[i];
|
||||||
location = modifiedLocation = Precision.AlmostEquals(p, 1f) ? SegmentStartLocation.End : Precision.AlmostEquals(p, 0f) ? SegmentStartLocation.Start : SegmentStartLocation.Middle;
|
location = modifiedLocation = nextLocation;
|
||||||
|
nextLocation = SegmentStartLocation.End;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -192,7 +192,8 @@ namespace osu.Framework.Graphics.OpenGL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer) => boundUniformBuffers[blockName] = (IGLUniformBuffer)buffer;
|
protected override void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer)
|
||||||
|
=> boundUniformBuffers[blockName] = (IGLUniformBuffer)buffer;
|
||||||
|
|
||||||
protected override bool SetTextureImplementation(INativeTexture? texture, int unit)
|
protected override bool SetTextureImplementation(INativeTexture? texture, int unit)
|
||||||
{
|
{
|
||||||
@@ -232,7 +233,8 @@ namespace osu.Framework.Graphics.OpenGL
|
|||||||
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer) =>
|
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer) =>
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, ((GLFrameBuffer?)frameBuffer)?.FrameBuffer ?? backbufferFramebuffer);
|
GL.BindFramebuffer(FramebufferTarget.Framebuffer, ((GLFrameBuffer?)frameBuffer)?.FrameBuffer ?? backbufferFramebuffer);
|
||||||
|
|
||||||
protected override void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer) => GL.DeleteFramebuffer(((GLFrameBuffer)frameBuffer).FrameBuffer);
|
protected override void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer)
|
||||||
|
=> GL.DeleteFramebuffer(((GLFrameBuffer)frameBuffer).FrameBuffer);
|
||||||
|
|
||||||
protected override void ClearImplementation(ClearInfo clearInfo)
|
protected override void ClearImplementation(ClearInfo clearInfo)
|
||||||
{
|
{
|
||||||
@@ -317,16 +319,16 @@ namespace osu.Framework.Graphics.OpenGL
|
|||||||
|
|
||||||
GL.BlendEquationSeparate(blendingParameters.RGBEquationMode, blendingParameters.AlphaEquationMode);
|
GL.BlendEquationSeparate(blendingParameters.RGBEquationMode, blendingParameters.AlphaEquationMode);
|
||||||
GL.BlendFuncSeparate(blendingParameters.SourceBlendingFactor, blendingParameters.DestinationBlendingFactor,
|
GL.BlendFuncSeparate(blendingParameters.SourceBlendingFactor, blendingParameters.DestinationBlendingFactor,
|
||||||
blendingParameters.SourceAlphaBlendingFactor, blendingParameters.DestinationAlphaBlendingFactor);
|
blendingParameters.SourceAlphaBlendingFactor, blendingParameters.DestinationAlphaBlendingFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SetBlendMaskImplementation(BlendingMask blendingMask)
|
protected override void SetBlendMaskImplementation(BlendingMask blendingMask)
|
||||||
{
|
{
|
||||||
GL.ColorMask(blendingMask.HasFlagFast(BlendingMask.Red),
|
GL.ColorMask(blendingMask.HasFlagFast(BlendingMask.Red),
|
||||||
blendingMask.HasFlagFast(BlendingMask.Green),
|
blendingMask.HasFlagFast(BlendingMask.Green),
|
||||||
blendingMask.HasFlagFast(BlendingMask.Blue),
|
blendingMask.HasFlagFast(BlendingMask.Blue),
|
||||||
blendingMask.HasFlagFast(BlendingMask.Alpha));
|
blendingMask.HasFlagFast(BlendingMask.Alpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SetViewportImplementation(RectangleI viewport) => GL.Viewport(viewport.Left, viewport.Top, viewport.Width, viewport.Height);
|
protected override void SetViewportImplementation(RectangleI viewport) => GL.Viewport(viewport.Left, viewport.Top, viewport.Width, viewport.Height);
|
||||||
@@ -375,21 +377,9 @@ namespace osu.Framework.Graphics.OpenGL
|
|||||||
|
|
||||||
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
||||||
{
|
{
|
||||||
// Bind the framebuffer and copy the current backbuffer content to it
|
frameBuffer.Bind();
|
||||||
BindFrameBuffer(frameBuffer);
|
GL.CopyTexSubImage2D(All.Texture2D, 0, 0, 0, 0, 0, frameBuffer.Texture.Width, frameBuffer.Texture.Height);
|
||||||
|
frameBuffer.Unbind();
|
||||||
var size = ((IGraphicsSurface)openGLSurface).GetDrawableSize();
|
|
||||||
|
|
||||||
// Copy from the default framebuffer (backbuffer) to the target framebuffer
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, 0); // Default framebuffer
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, ((GLFrameBuffer)frameBuffer).FrameBuffer);
|
|
||||||
|
|
||||||
GL.BlitFramebuffer(0, 0, size.Width, size.Height,
|
|
||||||
0, 0, frameBuffer.Texture.Width, frameBuffer.Texture.Height,
|
|
||||||
ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Linear);
|
|
||||||
|
|
||||||
// Reset to default framebuffer
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal override Image<Rgba32> ExtractFrameBufferData(IFrameBuffer frameBuffer)
|
protected internal override Image<Rgba32> ExtractFrameBufferData(IFrameBuffer frameBuffer)
|
||||||
@@ -429,8 +419,8 @@ namespace osu.Framework.Graphics.OpenGL
|
|||||||
return new GLShaderPart(this, name, rawData, glType, store);
|
return new GLShaderPart(this, name, rawData, glType, store);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore) =>
|
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore)
|
||||||
new GLShader(this, name, parts.Cast<GLShaderPart>().ToArray(), compilationStore);
|
=> new GLShader(this, name, parts.Cast<GLShaderPart>().ToArray(), compilationStore);
|
||||||
|
|
||||||
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear)
|
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear)
|
||||||
{
|
{
|
||||||
@@ -484,14 +474,13 @@ namespace osu.Framework.Graphics.OpenGL
|
|||||||
return new GLFrameBuffer(this, glFormats, glFilteringMode);
|
return new GLFrameBuffer(this, glFormats, glFilteringMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>() => new GLUniformBuffer<TData>(this);
|
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>()
|
||||||
|
=> new GLUniformBuffer<TData>(this);
|
||||||
|
|
||||||
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize) => new GLShaderStorageBufferObject<TData>(this, uboSize, ssboSize);
|
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize)
|
||||||
|
=> new GLShaderStorageBufferObject<TData>(this, uboSize, ssboSize);
|
||||||
|
|
||||||
protected override INativeTexture CreateNativeTexture(int width,
|
protected override INativeTexture CreateNativeTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
||||||
int height,
|
|
||||||
bool manualMipmaps = false,
|
|
||||||
TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
|
||||||
Color4? initialisationColour = null)
|
Color4? initialisationColour = null)
|
||||||
{
|
{
|
||||||
All glFilteringMode;
|
All glFilteringMode;
|
||||||
@@ -515,7 +504,8 @@ namespace osu.Framework.Graphics.OpenGL
|
|||||||
|
|
||||||
protected override INativeTexture CreateNativeVideoTexture(int width, int height) => new GLVideoTexture(this, width, height);
|
protected override INativeTexture CreateNativeVideoTexture(int width, int height) => new GLVideoTexture(this, width, height);
|
||||||
|
|
||||||
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology) => new GLLinearBatch<TVertex>(this, size, maxBuffers, topology);
|
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology)
|
||||||
|
=> new GLLinearBatch<TVertex>(this, size, maxBuffers, topology);
|
||||||
|
|
||||||
protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers) => new GLQuadBatch<TVertex>(this, size, maxBuffers);
|
protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers) => new GLQuadBatch<TVertex>(this, size, maxBuffers);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,60 +75,82 @@ namespace osu.Framework.Graphics.Rendering.Deferred
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer) => Context.EnqueueEvent(SetFrameBufferEvent.Create(this, frameBuffer));
|
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer)
|
||||||
|
=> Context.EnqueueEvent(SetFrameBufferEvent.Create(this, frameBuffer));
|
||||||
|
|
||||||
protected override void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer) => ((DeferredFrameBuffer)frameBuffer).DeleteResources();
|
protected override void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer)
|
||||||
|
=> ((DeferredFrameBuffer)frameBuffer).DeleteResources();
|
||||||
|
|
||||||
protected override void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer) => Context.EnqueueEvent(SetUniformBufferEvent.Create(this, blockName, buffer));
|
protected override void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer)
|
||||||
|
=> Context.EnqueueEvent(SetUniformBufferEvent.Create(this, blockName, buffer));
|
||||||
|
|
||||||
public override void DrawVerticesImplementation(PrimitiveTopology type, int vertexStart, int verticesCount)
|
public override void DrawVerticesImplementation(PrimitiveTopology type, int vertexStart, int verticesCount)
|
||||||
{
|
{
|
||||||
// Handled by the batch...
|
// Handled by the batch...
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ClearImplementation(ClearInfo clearInfo) => Context.EnqueueEvent(ClearEvent.Create(clearInfo));
|
protected override void ClearImplementation(ClearInfo clearInfo)
|
||||||
|
=> Context.EnqueueEvent(ClearEvent.Create(clearInfo));
|
||||||
|
|
||||||
protected override void SetScissorStateImplementation(bool enabled) => Context.EnqueueEvent(SetScissorStateEvent.Create(enabled));
|
protected override void SetScissorStateImplementation(bool enabled)
|
||||||
|
=> Context.EnqueueEvent(SetScissorStateEvent.Create(enabled));
|
||||||
|
|
||||||
protected override void SetBlendImplementation(BlendingParameters blendingParameters) => Context.EnqueueEvent(SetBlendEvent.Create(blendingParameters));
|
protected override void SetBlendImplementation(BlendingParameters blendingParameters)
|
||||||
|
=> Context.EnqueueEvent(SetBlendEvent.Create(blendingParameters));
|
||||||
|
|
||||||
protected override void SetBlendMaskImplementation(BlendingMask blendingMask) => Context.EnqueueEvent(SetBlendMaskEvent.Create(blendingMask));
|
protected override void SetBlendMaskImplementation(BlendingMask blendingMask)
|
||||||
|
=> Context.EnqueueEvent(SetBlendMaskEvent.Create(blendingMask));
|
||||||
|
|
||||||
protected override void SetViewportImplementation(RectangleI viewport) => Context.EnqueueEvent(SetViewportEvent.Create(viewport));
|
protected override void SetViewportImplementation(RectangleI viewport)
|
||||||
|
=> Context.EnqueueEvent(SetViewportEvent.Create(viewport));
|
||||||
|
|
||||||
protected override void SetScissorImplementation(RectangleI scissor) => Context.EnqueueEvent(SetScissorEvent.Create(scissor));
|
protected override void SetScissorImplementation(RectangleI scissor)
|
||||||
|
=> Context.EnqueueEvent(SetScissorEvent.Create(scissor));
|
||||||
|
|
||||||
protected override void SetDepthInfoImplementation(DepthInfo depthInfo) => Context.EnqueueEvent(SetDepthInfoEvent.Create(depthInfo));
|
protected override void SetDepthInfoImplementation(DepthInfo depthInfo)
|
||||||
|
=> Context.EnqueueEvent(SetDepthInfoEvent.Create(depthInfo));
|
||||||
|
|
||||||
protected override void SetStencilInfoImplementation(StencilInfo stencilInfo) => Context.EnqueueEvent(SetStencilInfoEvent.Create(stencilInfo));
|
protected override void SetStencilInfoImplementation(StencilInfo stencilInfo)
|
||||||
|
=> Context.EnqueueEvent(SetStencilInfoEvent.Create(stencilInfo));
|
||||||
|
|
||||||
protected override void SetShaderImplementation(IShader shader) => Context.EnqueueEvent(SetShaderEvent.Create(this, shader));
|
protected override void SetShaderImplementation(IShader shader)
|
||||||
|
=> Context.EnqueueEvent(SetShaderEvent.Create(this, shader));
|
||||||
|
|
||||||
protected override void SetUniformImplementation<T>(IUniformWithValue<T> uniform) => throw new NotSupportedException();
|
protected override void SetUniformImplementation<T>(IUniformWithValue<T> uniform)
|
||||||
|
=> throw new NotSupportedException();
|
||||||
|
|
||||||
void IVeldridRenderer.BindShader(VeldridShader shader) => BindShader(shader);
|
void IVeldridRenderer.BindShader(VeldridShader shader)
|
||||||
|
=> BindShader(shader);
|
||||||
|
|
||||||
void IVeldridRenderer.UnbindShader(VeldridShader shader) => UnbindShader(shader);
|
void IVeldridRenderer.UnbindShader(VeldridShader shader)
|
||||||
|
=> UnbindShader(shader);
|
||||||
|
|
||||||
void IVeldridRenderer.UpdateTexture<T>(Texture texture, int x, int y, int width, int height, int level, ReadOnlySpan<T> data) =>
|
void IVeldridRenderer.UpdateTexture<T>(Texture texture, int x, int y, int width, int height, int level, ReadOnlySpan<T> data)
|
||||||
Graphics.UpdateTexture(texturePool, texture, x, y, width, height, level, data);
|
=> Graphics.UpdateTexture(texturePool, texture, x, y, width, height, level, data);
|
||||||
|
|
||||||
void IVeldridRenderer.UpdateTexture(Texture texture, int x, int y, int width, int height, int level, IntPtr data, int rowLengthInBytes) =>
|
void IVeldridRenderer.UpdateTexture(Texture texture, int x, int y, int width, int height, int level, IntPtr data, int rowLengthInBytes)
|
||||||
Graphics.UpdateTexture(texturePool, texture, x, y, width, height, level, data, rowLengthInBytes);
|
=> Graphics.UpdateTexture(texturePool, texture, x, y, width, height, level, data, rowLengthInBytes);
|
||||||
|
|
||||||
void IVeldridRenderer.EnqueueTextureUpload(VeldridTexture texture) => EnqueueTextureUpload(texture);
|
void IVeldridRenderer.EnqueueTextureUpload(VeldridTexture texture)
|
||||||
|
=> EnqueueTextureUpload(texture);
|
||||||
|
|
||||||
void IVeldridRenderer.GenerateMipmaps(VeldridTexture texture) => Graphics.Commands.GenerateMipmaps(texture.GetResourceList().Single().Texture);
|
void IVeldridRenderer.GenerateMipmaps(VeldridTexture texture)
|
||||||
|
=> Graphics.Commands.GenerateMipmaps(texture.GetResourceList().Single().Texture);
|
||||||
|
|
||||||
public void RegisterUniformBufferForReset(IVeldridUniformBuffer veldridUniformBuffer) => uniformBufferResetList.Add(veldridUniformBuffer);
|
public void RegisterUniformBufferForReset(IVeldridUniformBuffer veldridUniformBuffer)
|
||||||
|
=> uniformBufferResetList.Add(veldridUniformBuffer);
|
||||||
|
|
||||||
bool IVeldridRenderer.UseStructuredBuffers => VeldridDevice.UseStructuredBuffers;
|
bool IVeldridRenderer.UseStructuredBuffers
|
||||||
|
=> VeldridDevice.UseStructuredBuffers;
|
||||||
|
|
||||||
GraphicsSurfaceType IVeldridRenderer.SurfaceType => VeldridDevice.SurfaceType;
|
GraphicsSurfaceType IVeldridRenderer.SurfaceType
|
||||||
|
=> VeldridDevice.SurfaceType;
|
||||||
|
|
||||||
public ResourceFactory Factory => VeldridDevice.Factory;
|
public ResourceFactory Factory
|
||||||
|
=> VeldridDevice.Factory;
|
||||||
|
|
||||||
public GraphicsDevice Device => VeldridDevice.Device;
|
public GraphicsDevice Device
|
||||||
|
=> VeldridDevice.Device;
|
||||||
|
|
||||||
protected internal override bool VerticalSync
|
protected internal override bool VerticalSync
|
||||||
{
|
{
|
||||||
@@ -142,30 +164,37 @@ namespace osu.Framework.Graphics.Rendering.Deferred
|
|||||||
set => VeldridDevice.AllowTearing = value;
|
set => VeldridDevice.AllowTearing = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsDepthRangeZeroToOne => VeldridDevice.IsDepthRangeZeroToOne;
|
public override bool IsDepthRangeZeroToOne
|
||||||
|
=> VeldridDevice.IsDepthRangeZeroToOne;
|
||||||
|
|
||||||
public override bool IsUvOriginTopLeft => VeldridDevice.IsUvOriginTopLeft;
|
public override bool IsUvOriginTopLeft
|
||||||
|
=> VeldridDevice.IsUvOriginTopLeft;
|
||||||
|
|
||||||
public override bool IsClipSpaceYInverted => VeldridDevice.IsClipSpaceYInverted;
|
public override bool IsClipSpaceYInverted
|
||||||
|
=> VeldridDevice.IsClipSpaceYInverted;
|
||||||
|
|
||||||
protected internal override void SwapBuffers() => VeldridDevice.SwapBuffers();
|
protected internal override void SwapBuffers()
|
||||||
|
=> VeldridDevice.SwapBuffers();
|
||||||
|
|
||||||
protected internal override void WaitUntilIdle() => VeldridDevice.WaitUntilIdle();
|
protected internal override void WaitUntilIdle()
|
||||||
|
=> VeldridDevice.WaitUntilIdle();
|
||||||
|
|
||||||
protected internal override void WaitUntilNextFrameReady() => VeldridDevice.WaitUntilNextFrameReady();
|
protected internal override void WaitUntilNextFrameReady()
|
||||||
|
=> VeldridDevice.WaitUntilNextFrameReady();
|
||||||
|
|
||||||
protected internal override void MakeCurrent() => VeldridDevice.MakeCurrent();
|
protected internal override void MakeCurrent()
|
||||||
|
=> VeldridDevice.MakeCurrent();
|
||||||
|
|
||||||
protected internal override void ClearCurrent() => VeldridDevice.ClearCurrent();
|
protected internal override void ClearCurrent()
|
||||||
|
=> VeldridDevice.ClearCurrent();
|
||||||
|
|
||||||
protected internal override Image<Rgba32> TakeScreenshot() => VeldridDevice.TakeScreenshot();
|
protected internal override Image<Rgba32> TakeScreenshot()
|
||||||
|
=> VeldridDevice.TakeScreenshot();
|
||||||
|
|
||||||
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
||||||
{
|
{
|
||||||
// For deferred renderer, we need to capture the current backbuffer content
|
// TODO: Implement screen capture for DeferredRenderer
|
||||||
// This is a simplified implementation - in practice, this would need to be
|
// This is a placeholder implementation
|
||||||
// implemented properly in the VeldridDevice or through the deferred context
|
|
||||||
throw new NotImplementedException("CaptureScreenToFrameBuffer not yet implemented for DeferredRenderer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRenderer.EnterDrawNode(DrawNode node)
|
void IRenderer.EnterDrawNode(DrawNode node)
|
||||||
@@ -174,32 +203,35 @@ namespace osu.Framework.Graphics.Rendering.Deferred
|
|||||||
Context.EnqueueEvent(DrawNodeActionEvent.Create(this, node, DrawNodeActionType.Enter));
|
Context.EnqueueEvent(DrawNodeActionEvent.Create(this, node, DrawNodeActionType.Enter));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRenderer.ExitDrawNode() => Context.EnqueueEvent(DrawNodeActionEvent.Create(this, drawNodeStack.Pop(), DrawNodeActionType.Exit));
|
void IRenderer.ExitDrawNode()
|
||||||
|
=> Context.EnqueueEvent(DrawNodeActionEvent.Create(this, drawNodeStack.Pop(), DrawNodeActionType.Exit));
|
||||||
|
|
||||||
protected override IShaderPart CreateShaderPart(IShaderStore store, string name, byte[]? rawData, ShaderPartType partType) => new VeldridShaderPart(this, rawData, partType, store);
|
protected override IShaderPart CreateShaderPart(IShaderStore store, string name, byte[]? rawData, ShaderPartType partType)
|
||||||
|
=> new VeldridShaderPart(this, rawData, partType, store);
|
||||||
|
|
||||||
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore) =>
|
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore)
|
||||||
new DeferredShader(this, new VeldridShader(this, name, parts.Cast<VeldridShaderPart>().ToArray(), compilationStore));
|
=> new DeferredShader(this, new VeldridShader(this, name, parts.Cast<VeldridShaderPart>().ToArray(), compilationStore));
|
||||||
|
|
||||||
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear) =>
|
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear)
|
||||||
new DeferredFrameBuffer(this, renderBufferFormats?.ToPixelFormats(), filteringMode.ToSamplerFilter());
|
=> new DeferredFrameBuffer(this, renderBufferFormats?.ToPixelFormats(), filteringMode.ToSamplerFilter());
|
||||||
|
|
||||||
protected override INativeTexture CreateNativeTexture(int width,
|
protected override INativeTexture CreateNativeTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
||||||
int height,
|
Color4? initialisationColour = null)
|
||||||
bool manualMipmaps = false,
|
=> new VeldridTexture(this, width, height, manualMipmaps, filteringMode.ToSamplerFilter(), initialisationColour);
|
||||||
TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
|
||||||
Color4? initialisationColour = null) =>
|
|
||||||
new VeldridTexture(this, width, height, manualMipmaps, filteringMode.ToSamplerFilter(), initialisationColour);
|
|
||||||
|
|
||||||
protected override INativeTexture CreateNativeVideoTexture(int width, int height) => new VeldridVideoTexture(this, width, height);
|
protected override INativeTexture CreateNativeVideoTexture(int width, int height)
|
||||||
|
=> new VeldridVideoTexture(this, width, height);
|
||||||
|
|
||||||
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology) =>
|
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology)
|
||||||
new DeferredVertexBatch<TVertex>(this, topology, VeldridIndexLayout.Linear);
|
=> new DeferredVertexBatch<TVertex>(this, topology, VeldridIndexLayout.Linear);
|
||||||
|
|
||||||
protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers) => new DeferredVertexBatch<TVertex>(this, PrimitiveTopology.Triangles, VeldridIndexLayout.Quad);
|
protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers)
|
||||||
|
=> new DeferredVertexBatch<TVertex>(this, PrimitiveTopology.Triangles, VeldridIndexLayout.Quad);
|
||||||
|
|
||||||
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>() => new DeferredUniformBuffer<TData>(this);
|
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>()
|
||||||
|
=> new DeferredUniformBuffer<TData>(this);
|
||||||
|
|
||||||
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize) => new DeferredShaderStorageBufferObject<TData>(this, ssboSize);
|
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize)
|
||||||
|
=> new DeferredShaderStorageBufferObject<TData>(this, ssboSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,35 +22,41 @@ namespace osu.Framework.Graphics.Rendering.Dummy
|
|||||||
public override bool IsUvOriginTopLeft => true;
|
public override bool IsUvOriginTopLeft => true;
|
||||||
public override bool IsClipSpaceYInverted => true;
|
public override bool IsClipSpaceYInverted => true;
|
||||||
|
|
||||||
protected internal override Image<Rgba32> TakeScreenshot() => new Image<Rgba32>(1, 1);
|
protected internal override Image<Rgba32> TakeScreenshot()
|
||||||
|
=> new Image<Rgba32>(1, 1);
|
||||||
|
|
||||||
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
||||||
{
|
{
|
||||||
// Dummy implementation - do nothing
|
// Dummy implementation - do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IShaderPart CreateShaderPart(IShaderStore store, string name, byte[]? rawData, ShaderPartType partType) => new DummyShaderPart();
|
protected override IShaderPart CreateShaderPart(IShaderStore store, string name, byte[]? rawData, ShaderPartType partType)
|
||||||
|
=> new DummyShaderPart();
|
||||||
|
|
||||||
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore) => new DummyShader(this);
|
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore)
|
||||||
|
=> new DummyShader(this);
|
||||||
|
|
||||||
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology) => new DummyVertexBatch<TVertex>();
|
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology topology)
|
||||||
|
=> new DummyVertexBatch<TVertex>();
|
||||||
|
|
||||||
protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers) => new DummyVertexBatch<TVertex>();
|
protected override IVertexBatch<TVertex> CreateQuadBatch<TVertex>(int size, int maxBuffers)
|
||||||
|
=> new DummyVertexBatch<TVertex>();
|
||||||
|
|
||||||
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>() => new DummyUniformBuffer<TData>();
|
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>()
|
||||||
|
=> new DummyUniformBuffer<TData>();
|
||||||
|
|
||||||
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize) => new DummyShaderStorageBufferObject<TData>(ssboSize);
|
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize)
|
||||||
|
=> new DummyShaderStorageBufferObject<TData>(ssboSize);
|
||||||
|
|
||||||
public Texture CreateTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear, WrapMode wrapModeS = WrapMode.None) =>
|
public Texture CreateTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear, WrapMode wrapModeS = WrapMode.None)
|
||||||
base.CreateTexture(width, height, manualMipmaps, filteringMode, wrapModeS, wrapModeS, null);
|
=> base.CreateTexture(width, height, manualMipmaps, filteringMode, wrapModeS, wrapModeS, null);
|
||||||
|
|
||||||
protected override INativeTexture CreateNativeTexture(int width,
|
protected override INativeTexture CreateNativeTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
||||||
int height,
|
Color4? initialisationColour = null)
|
||||||
bool manualMipmaps = false,
|
=> new DummyNativeTexture(this, width, height);
|
||||||
TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
|
||||||
Color4? initialisationColour = null) => new DummyNativeTexture(this, width, height);
|
|
||||||
|
|
||||||
protected override INativeTexture CreateNativeVideoTexture(int width, int height) => new DummyNativeTexture(this, width, height);
|
protected override INativeTexture CreateNativeVideoTexture(int width, int height)
|
||||||
|
=> new DummyNativeTexture(this, width, height);
|
||||||
|
|
||||||
protected override void Initialise(IGraphicsSurface graphicsSurface)
|
protected override void Initialise(IGraphicsSurface graphicsSurface)
|
||||||
{
|
{
|
||||||
@@ -108,7 +114,8 @@ namespace osu.Framework.Graphics.Rendering.Dummy
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool SetTextureImplementation(INativeTexture? texture, int unit) => true;
|
protected override bool SetTextureImplementation(INativeTexture? texture, int unit)
|
||||||
|
=> true;
|
||||||
|
|
||||||
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer)
|
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer)
|
||||||
{
|
{
|
||||||
@@ -134,7 +141,7 @@ namespace osu.Framework.Graphics.Rendering.Dummy
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear) =>
|
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear)
|
||||||
new DummyFrameBuffer(this);
|
=> new DummyFrameBuffer(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,8 +159,8 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
statExpensiveOperationsQueued = GlobalStatistics.Get<int>(GetType().Name, "Expensive operation queue length");
|
statExpensiveOperationsQueued = GlobalStatistics.Get<int>(GetType().Name, "Expensive operation queue length");
|
||||||
vboInUse = GlobalStatistics.Get<int>(GetType().Name, "VBOs in use");
|
vboInUse = GlobalStatistics.Get<int>(GetType().Name, "VBOs in use");
|
||||||
|
|
||||||
whitePixel = new Lazy<TextureWhitePixel>(() => new TextureAtlas(this, TextureAtlas.WHITE_PIXEL_SIZE + TextureAtlas.PADDING, TextureAtlas.WHITE_PIXEL_SIZE + TextureAtlas.PADDING, true)
|
whitePixel = new Lazy<TextureWhitePixel>(() =>
|
||||||
.WhitePixel);
|
new TextureAtlas(this, TextureAtlas.WHITE_PIXEL_SIZE + TextureAtlas.PADDING, TextureAtlas.WHITE_PIXEL_SIZE + TextureAtlas.PADDING, true).WhitePixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRenderer.Initialise(IGraphicsSurface graphicsSurface)
|
void IRenderer.Initialise(IGraphicsSurface graphicsSurface)
|
||||||
@@ -332,10 +332,6 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="frameBuffer">The framebuffer to capture to.</param>
|
/// <param name="frameBuffer">The framebuffer to capture to.</param>
|
||||||
public abstract void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer);
|
public abstract void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns an image containing the content of a framebuffer.
|
|
||||||
/// </summary>
|
|
||||||
protected internal virtual Image<Rgba32>? ExtractFrameBufferData(IFrameBuffer frameBuffer) => null;
|
protected internal virtual Image<Rgba32>? ExtractFrameBufferData(IFrameBuffer frameBuffer) => null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -370,7 +366,7 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal abstract void ClearCurrent();
|
protected internal abstract void ClearCurrent();
|
||||||
|
|
||||||
#region Clear
|
#region Clear
|
||||||
|
|
||||||
public void Clear(ClearInfo clearInfo)
|
public void Clear(ClearInfo clearInfo)
|
||||||
{
|
{
|
||||||
@@ -391,9 +387,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <param name="clearInfo">The clear parameters.</param>
|
/// <param name="clearInfo">The clear parameters.</param>
|
||||||
protected abstract void ClearImplementation(ClearInfo clearInfo);
|
protected abstract void ClearImplementation(ClearInfo clearInfo);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Blending
|
#region Blending
|
||||||
|
|
||||||
public void SetBlend(BlendingParameters blendingParameters)
|
public void SetBlend(BlendingParameters blendingParameters)
|
||||||
{
|
{
|
||||||
@@ -429,9 +425,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <param name="blendingMask">The blending mask.</param>
|
/// <param name="blendingMask">The blending mask.</param>
|
||||||
protected abstract void SetBlendMaskImplementation(BlendingMask blendingMask);
|
protected abstract void SetBlendMaskImplementation(BlendingMask blendingMask);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Viewport
|
#region Viewport
|
||||||
|
|
||||||
public void PushViewport(RectangleI viewport)
|
public void PushViewport(RectangleI viewport)
|
||||||
{
|
{
|
||||||
@@ -480,9 +476,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <param name="viewport">The viewport to use.</param>
|
/// <param name="viewport">The viewport to use.</param>
|
||||||
protected abstract void SetViewportImplementation(RectangleI viewport);
|
protected abstract void SetViewportImplementation(RectangleI viewport);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Scissor
|
#region Scissor
|
||||||
|
|
||||||
public void PushScissor(RectangleI scissor)
|
public void PushScissor(RectangleI scissor)
|
||||||
{
|
{
|
||||||
@@ -587,9 +583,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <param name="enabled">Whether scissor should be enabled.</param>
|
/// <param name="enabled">Whether scissor should be enabled.</param>
|
||||||
protected abstract void SetScissorStateImplementation(bool enabled);
|
protected abstract void SetScissorStateImplementation(bool enabled);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Projection Matrix
|
#region Projection Matrix
|
||||||
|
|
||||||
public void PushProjectionMatrix(Matrix4 matrix)
|
public void PushProjectionMatrix(Matrix4 matrix)
|
||||||
{
|
{
|
||||||
@@ -616,9 +612,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
ProjectionMatrix = matrix;
|
ProjectionMatrix = matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Masking
|
#region Masking
|
||||||
|
|
||||||
public void PushMaskingInfo(in MaskingInfo maskingInfo, bool overwritePreviousScissor = false)
|
public void PushMaskingInfo(in MaskingInfo maskingInfo, bool overwritePreviousScissor = false)
|
||||||
{
|
{
|
||||||
@@ -668,9 +664,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
globalUniformsChanged = true;
|
globalUniformsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Depth & Stencil
|
#region Depth & Stencil
|
||||||
|
|
||||||
public void PushDepthInfo(DepthInfo depthInfo)
|
public void PushDepthInfo(DepthInfo depthInfo)
|
||||||
{
|
{
|
||||||
@@ -734,9 +730,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <param name="stencilInfo">The stencil parameters to use.</param>
|
/// <param name="stencilInfo">The stencil parameters to use.</param>
|
||||||
protected abstract void SetStencilInfoImplementation(StencilInfo stencilInfo);
|
protected abstract void SetStencilInfoImplementation(StencilInfo stencilInfo);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Batches
|
#region Batches
|
||||||
|
|
||||||
internal IVertexBatch<TexturedVertex2D> DefaultQuadBatch => quadBatches.Peek();
|
internal IVertexBatch<TexturedVertex2D> DefaultQuadBatch => quadBatches.Peek();
|
||||||
|
|
||||||
@@ -794,9 +790,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
vertexBuffersInUse.RemoveAll(b => !b.InUse);
|
vertexBuffersInUse.RemoveAll(b => !b.InUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Textures
|
#region Textures
|
||||||
|
|
||||||
public bool BindTexture(Texture texture, int unit, WrapMode? wrapModeS, WrapMode? wrapModeT)
|
public bool BindTexture(Texture texture, int unit, WrapMode? wrapModeS, WrapMode? wrapModeT)
|
||||||
{
|
{
|
||||||
@@ -906,9 +902,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <returns>Whether the texture was set successfully.</returns>
|
/// <returns>Whether the texture was set successfully.</returns>
|
||||||
protected abstract bool SetTextureImplementation(INativeTexture? texture, int unit);
|
protected abstract bool SetTextureImplementation(INativeTexture? texture, int unit);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Framebuffers
|
#region Framebuffers
|
||||||
|
|
||||||
public void BindFrameBuffer(IFrameBuffer frameBuffer)
|
public void BindFrameBuffer(IFrameBuffer frameBuffer)
|
||||||
{
|
{
|
||||||
@@ -959,7 +955,7 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
|
|
||||||
protected abstract void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer);
|
protected abstract void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public void DrawVertices(PrimitiveTopology topology, int vertexStart, int verticesCount)
|
public void DrawVertices(PrimitiveTopology topology, int vertexStart, int verticesCount)
|
||||||
{
|
{
|
||||||
@@ -986,35 +982,35 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
currentMaskingInfo.MaskingRect.Bottom),
|
currentMaskingInfo.MaskingRect.Bottom),
|
||||||
BorderThickness = currentMaskingInfo.BorderThickness / currentMaskingInfo.BlendRange,
|
BorderThickness = currentMaskingInfo.BorderThickness / currentMaskingInfo.BlendRange,
|
||||||
BorderColour = currentMaskingInfo.BorderThickness > 0
|
BorderColour = currentMaskingInfo.BorderThickness > 0
|
||||||
? new Matrix4(
|
? new Matrix4(
|
||||||
// TopLeft
|
// TopLeft
|
||||||
currentMaskingInfo.BorderColour.TopLeft.SRGB.R,
|
currentMaskingInfo.BorderColour.TopLeft.SRGB.R,
|
||||||
currentMaskingInfo.BorderColour.TopLeft.SRGB.G,
|
currentMaskingInfo.BorderColour.TopLeft.SRGB.G,
|
||||||
currentMaskingInfo.BorderColour.TopLeft.SRGB.B,
|
currentMaskingInfo.BorderColour.TopLeft.SRGB.B,
|
||||||
currentMaskingInfo.BorderColour.TopLeft.SRGB.A,
|
currentMaskingInfo.BorderColour.TopLeft.SRGB.A,
|
||||||
// BottomLeft
|
// BottomLeft
|
||||||
currentMaskingInfo.BorderColour.BottomLeft.SRGB.R,
|
currentMaskingInfo.BorderColour.BottomLeft.SRGB.R,
|
||||||
currentMaskingInfo.BorderColour.BottomLeft.SRGB.G,
|
currentMaskingInfo.BorderColour.BottomLeft.SRGB.G,
|
||||||
currentMaskingInfo.BorderColour.BottomLeft.SRGB.B,
|
currentMaskingInfo.BorderColour.BottomLeft.SRGB.B,
|
||||||
currentMaskingInfo.BorderColour.BottomLeft.SRGB.A,
|
currentMaskingInfo.BorderColour.BottomLeft.SRGB.A,
|
||||||
// TopRight
|
// TopRight
|
||||||
currentMaskingInfo.BorderColour.TopRight.SRGB.R,
|
currentMaskingInfo.BorderColour.TopRight.SRGB.R,
|
||||||
currentMaskingInfo.BorderColour.TopRight.SRGB.G,
|
currentMaskingInfo.BorderColour.TopRight.SRGB.G,
|
||||||
currentMaskingInfo.BorderColour.TopRight.SRGB.B,
|
currentMaskingInfo.BorderColour.TopRight.SRGB.B,
|
||||||
currentMaskingInfo.BorderColour.TopRight.SRGB.A,
|
currentMaskingInfo.BorderColour.TopRight.SRGB.A,
|
||||||
// BottomRight
|
// BottomRight
|
||||||
currentMaskingInfo.BorderColour.BottomRight.SRGB.R,
|
currentMaskingInfo.BorderColour.BottomRight.SRGB.R,
|
||||||
currentMaskingInfo.BorderColour.BottomRight.SRGB.G,
|
currentMaskingInfo.BorderColour.BottomRight.SRGB.G,
|
||||||
currentMaskingInfo.BorderColour.BottomRight.SRGB.B,
|
currentMaskingInfo.BorderColour.BottomRight.SRGB.B,
|
||||||
currentMaskingInfo.BorderColour.BottomRight.SRGB.A)
|
currentMaskingInfo.BorderColour.BottomRight.SRGB.A)
|
||||||
: globalUniformBuffer.Data.BorderColour,
|
: globalUniformBuffer.Data.BorderColour,
|
||||||
MaskingBlendRange = currentMaskingInfo.BlendRange,
|
MaskingBlendRange = currentMaskingInfo.BlendRange,
|
||||||
AlphaExponent = currentMaskingInfo.AlphaExponent,
|
AlphaExponent = currentMaskingInfo.AlphaExponent,
|
||||||
EdgeOffset = currentMaskingInfo.EdgeOffset,
|
EdgeOffset = currentMaskingInfo.EdgeOffset,
|
||||||
DiscardInner = currentMaskingInfo.Hollow,
|
DiscardInner = currentMaskingInfo.Hollow,
|
||||||
InnerCornerRadius = currentMaskingInfo.Hollow
|
InnerCornerRadius = currentMaskingInfo.Hollow
|
||||||
? currentMaskingInfo.HollowCornerRadius
|
? currentMaskingInfo.HollowCornerRadius
|
||||||
: globalUniformBuffer.Data.InnerCornerRadius,
|
: globalUniformBuffer.Data.InnerCornerRadius,
|
||||||
WrapModeS = (int)CurrentWrapModeS,
|
WrapModeS = (int)CurrentWrapModeS,
|
||||||
WrapModeT = (int)CurrentWrapModeT
|
WrapModeT = (int)CurrentWrapModeT
|
||||||
};
|
};
|
||||||
@@ -1032,7 +1028,7 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
|
|
||||||
public abstract void DrawVerticesImplementation(PrimitiveTopology topology, int vertexStart, int verticesCount);
|
public abstract void DrawVerticesImplementation(PrimitiveTopology topology, int vertexStart, int verticesCount);
|
||||||
|
|
||||||
#region Shaders
|
#region Shaders
|
||||||
|
|
||||||
public void BindShader(IShader shader)
|
public void BindShader(IShader shader)
|
||||||
{
|
{
|
||||||
@@ -1107,9 +1103,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
|
|
||||||
protected abstract void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer);
|
protected abstract void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Factory
|
#region Factory
|
||||||
|
|
||||||
public abstract IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear);
|
public abstract IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear);
|
||||||
|
|
||||||
@@ -1163,10 +1159,7 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <param name="filteringMode">The filtering mode.</param>
|
/// <param name="filteringMode">The filtering mode.</param>
|
||||||
/// <param name="initialisationColour">The colour to initialise texture levels with (in the case of sub region initial uploads). If null, no initialisation is provided out-of-the-box.</param>
|
/// <param name="initialisationColour">The colour to initialise texture levels with (in the case of sub region initial uploads). If null, no initialisation is provided out-of-the-box.</param>
|
||||||
/// <returns>The <see cref="INativeTexture"/>.</returns>
|
/// <returns>The <see cref="INativeTexture"/>.</returns>
|
||||||
protected abstract INativeTexture CreateNativeTexture(int width,
|
protected abstract INativeTexture CreateNativeTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
||||||
int height,
|
|
||||||
bool manualMipmaps = false,
|
|
||||||
TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
|
||||||
Color4? initialisationColour = null);
|
Color4? initialisationColour = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1177,8 +1170,8 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <returns>The video <see cref="INativeTexture"/>.</returns>
|
/// <returns>The video <see cref="INativeTexture"/>.</returns>
|
||||||
protected abstract INativeTexture CreateNativeVideoTexture(int width, int height);
|
protected abstract INativeTexture CreateNativeVideoTexture(int width, int height);
|
||||||
|
|
||||||
public Texture CreateTexture(int width, int height, bool manualMipmaps, TextureFilteringMode filteringMode, WrapMode wrapModeS, WrapMode wrapModeT, Color4? initialisationColour) =>
|
public Texture CreateTexture(int width, int height, bool manualMipmaps, TextureFilteringMode filteringMode, WrapMode wrapModeS, WrapMode wrapModeT, Color4? initialisationColour)
|
||||||
CreateTexture(CreateNativeTexture(width, height, manualMipmaps, filteringMode, initialisationColour), wrapModeS, wrapModeT);
|
=> CreateTexture(CreateNativeTexture(width, height, manualMipmaps, filteringMode, initialisationColour), wrapModeS, wrapModeT);
|
||||||
|
|
||||||
public Texture CreateVideoTexture(int width, int height) => CreateTexture(CreateNativeVideoTexture(width, height));
|
public Texture CreateVideoTexture(int width, int height) => CreateTexture(CreateNativeVideoTexture(width, height));
|
||||||
|
|
||||||
@@ -1189,8 +1182,8 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
/// <param name="wrapModeS">The horizontal wrap mode of the texture.</param>
|
/// <param name="wrapModeS">The horizontal wrap mode of the texture.</param>
|
||||||
/// <param name="wrapModeT">The vertical wrap mode of the texture.</param>
|
/// <param name="wrapModeT">The vertical wrap mode of the texture.</param>
|
||||||
/// <returns>The <see cref="Texture"/>.</returns>
|
/// <returns>The <see cref="Texture"/>.</returns>
|
||||||
internal Texture CreateTexture(INativeTexture nativeTexture, WrapMode wrapModeS = WrapMode.None, WrapMode wrapModeT = WrapMode.None) =>
|
internal Texture CreateTexture(INativeTexture nativeTexture, WrapMode wrapModeS = WrapMode.None, WrapMode wrapModeT = WrapMode.None)
|
||||||
registerTexture(new Texture(nativeTexture, wrapModeS, wrapModeT));
|
=> registerTexture(new Texture(nativeTexture, wrapModeS, wrapModeT));
|
||||||
|
|
||||||
private Texture registerTexture(Texture texture)
|
private Texture registerTexture(Texture texture)
|
||||||
{
|
{
|
||||||
@@ -1199,9 +1192,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IRenderer explicit implementation
|
#region IRenderer explicit implementation
|
||||||
|
|
||||||
bool IRenderer.VerticalSync
|
bool IRenderer.VerticalSync
|
||||||
{
|
{
|
||||||
@@ -1294,9 +1287,9 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
checkValidType(field);
|
checkValidType(field);
|
||||||
|
|
||||||
if (field.FieldType == typeof(UniformMatrix3)
|
if (field.FieldType == typeof(UniformMatrix3)
|
||||||
|| field.FieldType == typeof(UniformMatrix4)
|
|| field.FieldType == typeof(UniformMatrix4)
|
||||||
|| field.FieldType == typeof(UniformVector3)
|
|| field.FieldType == typeof(UniformVector3)
|
||||||
|| field.FieldType == typeof(UniformVector4))
|
|| field.FieldType == typeof(UniformVector4))
|
||||||
{
|
{
|
||||||
checkAlignment(field, offset, 16);
|
checkAlignment(field, offset, 16);
|
||||||
}
|
}
|
||||||
@@ -1317,16 +1310,16 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
static void checkValidType(FieldInfo field)
|
static void checkValidType(FieldInfo field)
|
||||||
{
|
{
|
||||||
if (field.FieldType == typeof(UniformBool)
|
if (field.FieldType == typeof(UniformBool)
|
||||||
|| field.FieldType == typeof(UniformFloat)
|
|| field.FieldType == typeof(UniformFloat)
|
||||||
|| field.FieldType == typeof(UniformInt)
|
|| field.FieldType == typeof(UniformInt)
|
||||||
|| field.FieldType == typeof(UniformMatrix3)
|
|| field.FieldType == typeof(UniformMatrix3)
|
||||||
|| field.FieldType == typeof(UniformMatrix4)
|
|| field.FieldType == typeof(UniformMatrix4)
|
||||||
|| field.FieldType == typeof(UniformPadding4)
|
|| field.FieldType == typeof(UniformPadding4)
|
||||||
|| field.FieldType == typeof(UniformPadding8)
|
|| field.FieldType == typeof(UniformPadding8)
|
||||||
|| field.FieldType == typeof(UniformPadding12)
|
|| field.FieldType == typeof(UniformPadding12)
|
||||||
|| field.FieldType == typeof(UniformVector2)
|
|| field.FieldType == typeof(UniformVector2)
|
||||||
|| field.FieldType == typeof(UniformVector4)
|
|| field.FieldType == typeof(UniformVector4)
|
||||||
|| field.FieldType == typeof(UniformVector4))
|
|| field.FieldType == typeof(UniformVector4))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1350,18 +1343,18 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
return paddingRequired switch
|
return paddingRequired switch
|
||||||
{
|
{
|
||||||
4 => typeof(UniformPadding4),
|
4 => typeof(UniformPadding4),
|
||||||
8 => typeof(UniformPadding8),
|
8 => typeof(UniformPadding8),
|
||||||
12 => typeof(UniformPadding12),
|
12 => typeof(UniformPadding12),
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region TextureVisualiser support
|
#region TextureVisualiser support
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An event which is invoked every time a <see cref="Texture"/> is created.
|
/// An event which is invoked every time a <see cref="Texture"/> is created.
|
||||||
@@ -1376,7 +1369,7 @@ namespace osu.Framework.Graphics.Rendering
|
|||||||
|
|
||||||
Texture[] IRenderer.GetAllTextures() => allTextures.ToArray();
|
Texture[] IRenderer.GetAllTextures() => allTextures.ToArray();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private class PassthroughShaderStore : IShaderStore
|
private class PassthroughShaderStore : IShaderStore
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ namespace osu.Framework.Graphics.Shaders
|
|||||||
return cached;
|
return cached;
|
||||||
|
|
||||||
return shaderCache[(vertex, fragment)] = renderer.CreateShader(
|
return shaderCache[(vertex, fragment)] = renderer.CreateShader(
|
||||||
$"{vertex}/{fragment}",
|
$"{vertex}/{fragment}",
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
resolveShaderPart(vertex, ShaderPartType.Vertex),
|
resolveShaderPart(vertex, ShaderPartType.Vertex),
|
||||||
resolveShaderPart(fragment, ShaderPartType.Fragment)
|
resolveShaderPart(fragment, ShaderPartType.Fragment)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -54,14 +54,16 @@ namespace osu.Framework.Graphics.Shaders
|
|||||||
/// <param name="vertex">The vertex shader name.</param>
|
/// <param name="vertex">The vertex shader name.</param>
|
||||||
/// <param name="fragment">The fragment shader name.</param>
|
/// <param name="fragment">The fragment shader name.</param>
|
||||||
/// <returns>A cached <see cref="IShader"/> instance, if existing.</returns>
|
/// <returns>A cached <see cref="IShader"/> instance, if existing.</returns>
|
||||||
public virtual IShader? GetCachedShader(string vertex, string fragment) => shaderCache.TryGetValue((vertex, fragment), out IShader? shader) ? shader : null;
|
public virtual IShader? GetCachedShader(string vertex, string fragment)
|
||||||
|
=> shaderCache.TryGetValue((vertex, fragment), out IShader? shader) ? shader : null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to retrieve an already-cached shader part.
|
/// Attempts to retrieve an already-cached shader part.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the shader part.</param>
|
/// <param name="name">The name of the shader part.</param>
|
||||||
/// <returns>A cached <see cref="IShaderPart"/> instance, if existing.</returns>
|
/// <returns>A cached <see cref="IShaderPart"/> instance, if existing.</returns>
|
||||||
public virtual IShaderPart? GetCachedShaderPart(string name) => partCache.TryGetValue(name, out IShaderPart? part) ? part : null;
|
public virtual IShaderPart? GetCachedShaderPart(string name)
|
||||||
|
=> partCache.TryGetValue(name, out IShaderPart? part) ? part : null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to retrieve the raw data for a shader file.
|
/// Attempts to retrieve the raw data for a shader file.
|
||||||
@@ -114,7 +116,7 @@ namespace osu.Framework.Graphics.Shaders
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
|
|
||||||
private bool isDisposed;
|
private bool isDisposed;
|
||||||
|
|
||||||
@@ -143,7 +145,7 @@ namespace osu.Framework.Graphics.Shaders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class VertexShaderDescriptor
|
public static class VertexShaderDescriptor
|
||||||
@@ -160,6 +162,5 @@ namespace osu.Framework.Graphics.Shaders
|
|||||||
public const string BLUR = "Blur";
|
public const string BLUR = "Blur";
|
||||||
public const string GRAYSCALE = "Grayscale";
|
public const string GRAYSCALE = "Grayscale";
|
||||||
public const string VIDEO = "Video";
|
public const string VIDEO = "Video";
|
||||||
public const string ACRYLIC = "Acrylic";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,19 +40,26 @@ namespace osu.Framework.Graphics.Veldrid
|
|||||||
set => veldridDevice.AllowTearing = value;
|
set => veldridDevice.AllowTearing = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsDepthRangeZeroToOne => veldridDevice.IsDepthRangeZeroToOne;
|
public override bool IsDepthRangeZeroToOne
|
||||||
|
=> veldridDevice.IsDepthRangeZeroToOne;
|
||||||
|
|
||||||
public override bool IsUvOriginTopLeft => veldridDevice.IsUvOriginTopLeft;
|
public override bool IsUvOriginTopLeft
|
||||||
|
=> veldridDevice.IsUvOriginTopLeft;
|
||||||
|
|
||||||
public override bool IsClipSpaceYInverted => veldridDevice.IsClipSpaceYInverted;
|
public override bool IsClipSpaceYInverted
|
||||||
|
=> veldridDevice.IsClipSpaceYInverted;
|
||||||
|
|
||||||
public bool UseStructuredBuffers => veldridDevice.UseStructuredBuffers;
|
public bool UseStructuredBuffers
|
||||||
|
=> veldridDevice.UseStructuredBuffers;
|
||||||
|
|
||||||
public GraphicsDevice Device => veldridDevice.Device;
|
public GraphicsDevice Device
|
||||||
|
=> veldridDevice.Device;
|
||||||
|
|
||||||
public ResourceFactory Factory => veldridDevice.Factory;
|
public ResourceFactory Factory
|
||||||
|
=> veldridDevice.Factory;
|
||||||
|
|
||||||
public GraphicsSurfaceType SurfaceType => veldridDevice.SurfaceType;
|
public GraphicsSurfaceType SurfaceType
|
||||||
|
=> veldridDevice.SurfaceType;
|
||||||
|
|
||||||
private readonly HashSet<IVeldridUniformBuffer> uniformBufferResetList = new HashSet<IVeldridUniformBuffer>();
|
private readonly HashSet<IVeldridUniformBuffer> uniformBufferResetList = new HashSet<IVeldridUniformBuffer>();
|
||||||
|
|
||||||
@@ -100,19 +107,26 @@ namespace osu.Framework.Graphics.Veldrid
|
|||||||
graphicsPipeline.End();
|
graphicsPipeline.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal override void SwapBuffers() => veldridDevice.SwapBuffers();
|
protected internal override void SwapBuffers()
|
||||||
|
=> veldridDevice.SwapBuffers();
|
||||||
|
|
||||||
protected internal override void WaitUntilIdle() => veldridDevice.WaitUntilIdle();
|
protected internal override void WaitUntilIdle()
|
||||||
|
=> veldridDevice.WaitUntilIdle();
|
||||||
|
|
||||||
protected internal override void WaitUntilNextFrameReady() => veldridDevice.WaitUntilNextFrameReady();
|
protected internal override void WaitUntilNextFrameReady()
|
||||||
|
=> veldridDevice.WaitUntilNextFrameReady();
|
||||||
|
|
||||||
protected internal override void MakeCurrent() => veldridDevice.MakeCurrent();
|
protected internal override void MakeCurrent()
|
||||||
|
=> veldridDevice.MakeCurrent();
|
||||||
|
|
||||||
protected internal override void ClearCurrent() => veldridDevice.ClearCurrent();
|
protected internal override void ClearCurrent()
|
||||||
|
=> veldridDevice.ClearCurrent();
|
||||||
|
|
||||||
protected override void ClearImplementation(ClearInfo clearInfo) => graphicsPipeline.Clear(clearInfo);
|
protected override void ClearImplementation(ClearInfo clearInfo)
|
||||||
|
=> graphicsPipeline.Clear(clearInfo);
|
||||||
|
|
||||||
protected override void SetScissorStateImplementation(bool enabled) => graphicsPipeline.SetScissorState(enabled);
|
protected override void SetScissorStateImplementation(bool enabled)
|
||||||
|
=> graphicsPipeline.SetScissorState(enabled);
|
||||||
|
|
||||||
protected override bool SetTextureImplementation(INativeTexture? texture, int unit)
|
protected override bool SetTextureImplementation(INativeTexture? texture, int unit)
|
||||||
{
|
{
|
||||||
@@ -123,23 +137,32 @@ namespace osu.Framework.Graphics.Veldrid
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SetShaderImplementation(IShader shader) => graphicsPipeline.SetShader((VeldridShader)shader);
|
protected override void SetShaderImplementation(IShader shader)
|
||||||
|
=> graphicsPipeline.SetShader((VeldridShader)shader);
|
||||||
|
|
||||||
protected override void SetBlendImplementation(BlendingParameters blendingParameters) => graphicsPipeline.SetBlend(blendingParameters);
|
protected override void SetBlendImplementation(BlendingParameters blendingParameters)
|
||||||
|
=> graphicsPipeline.SetBlend(blendingParameters);
|
||||||
|
|
||||||
protected override void SetBlendMaskImplementation(BlendingMask blendingMask) => graphicsPipeline.SetBlendMask(blendingMask);
|
protected override void SetBlendMaskImplementation(BlendingMask blendingMask)
|
||||||
|
=> graphicsPipeline.SetBlendMask(blendingMask);
|
||||||
|
|
||||||
protected override void SetViewportImplementation(RectangleI viewport) => graphicsPipeline.SetViewport(viewport);
|
protected override void SetViewportImplementation(RectangleI viewport)
|
||||||
|
=> graphicsPipeline.SetViewport(viewport);
|
||||||
|
|
||||||
protected override void SetScissorImplementation(RectangleI scissor) => graphicsPipeline.SetScissor(scissor);
|
protected override void SetScissorImplementation(RectangleI scissor)
|
||||||
|
=> graphicsPipeline.SetScissor(scissor);
|
||||||
|
|
||||||
protected override void SetDepthInfoImplementation(DepthInfo depthInfo) => graphicsPipeline.SetDepthInfo(depthInfo);
|
protected override void SetDepthInfoImplementation(DepthInfo depthInfo)
|
||||||
|
=> graphicsPipeline.SetDepthInfo(depthInfo);
|
||||||
|
|
||||||
protected override void SetStencilInfoImplementation(StencilInfo stencilInfo) => graphicsPipeline.SetStencilInfo(stencilInfo);
|
protected override void SetStencilInfoImplementation(StencilInfo stencilInfo)
|
||||||
|
=> graphicsPipeline.SetStencilInfo(stencilInfo);
|
||||||
|
|
||||||
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer) => graphicsPipeline.SetFrameBuffer((VeldridFrameBuffer?)frameBuffer);
|
protected override void SetFrameBufferImplementation(IFrameBuffer? frameBuffer)
|
||||||
|
=> graphicsPipeline.SetFrameBuffer((VeldridFrameBuffer?)frameBuffer);
|
||||||
|
|
||||||
protected override void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer) => ((VeldridFrameBuffer)frameBuffer).DeleteResources(true);
|
protected override void DeleteFrameBufferImplementation(IFrameBuffer frameBuffer)
|
||||||
|
=> ((VeldridFrameBuffer)frameBuffer).DeleteResources(true);
|
||||||
|
|
||||||
public override void DrawVerticesImplementation(PrimitiveTopology topology, int vertexStart, int verticesCount)
|
public override void DrawVerticesImplementation(PrimitiveTopology topology, int vertexStart, int verticesCount)
|
||||||
{
|
{
|
||||||
@@ -154,13 +177,14 @@ namespace osu.Framework.Graphics.Veldrid
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void BindVertexBuffer<T>(IVeldridVertexBuffer<T> buffer)
|
public void BindVertexBuffer<T>(IVeldridVertexBuffer<T> buffer)
|
||||||
where T : unmanaged, IEquatable<T>, IVertex => graphicsPipeline.SetVertexBuffer(buffer.Buffer, VeldridVertexUtils<T>.Layout);
|
where T : unmanaged, IEquatable<T>, IVertex
|
||||||
|
=> graphicsPipeline.SetVertexBuffer(buffer.Buffer, VeldridVertexUtils<T>.Layout);
|
||||||
|
|
||||||
public void BindIndexBuffer(VeldridIndexLayout layout, int verticesCount)
|
public void BindIndexBuffer(VeldridIndexLayout layout, int verticesCount)
|
||||||
{
|
{
|
||||||
ref var indexBuffer = ref layout == VeldridIndexLayout.Quad
|
ref var indexBuffer = ref layout == VeldridIndexLayout.Quad
|
||||||
? ref quadIndexBuffer
|
? ref quadIndexBuffer
|
||||||
: ref linearIndexBuffer;
|
: ref linearIndexBuffer;
|
||||||
|
|
||||||
if (indexBuffer == null || indexBuffer.VertexCapacity < verticesCount)
|
if (indexBuffer == null || indexBuffer.VertexCapacity < verticesCount)
|
||||||
{
|
{
|
||||||
@@ -193,19 +217,20 @@ namespace osu.Framework.Graphics.Veldrid
|
|||||||
/// Checks whether the given frame buffer is currently bound.
|
/// Checks whether the given frame buffer is currently bound.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="frameBuffer">The frame buffer to check.</param>
|
/// <param name="frameBuffer">The frame buffer to check.</param>
|
||||||
public bool IsFrameBufferBound(IFrameBuffer frameBuffer) => FrameBuffer == frameBuffer;
|
public bool IsFrameBufferBound(IFrameBuffer frameBuffer)
|
||||||
|
=> FrameBuffer == frameBuffer;
|
||||||
|
|
||||||
protected internal override Image<Rgba32> TakeScreenshot() => veldridDevice.TakeScreenshot();
|
protected internal override Image<Rgba32> TakeScreenshot()
|
||||||
|
=> veldridDevice.TakeScreenshot();
|
||||||
|
|
||||||
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
public override void CaptureScreenToFrameBuffer(IFrameBuffer frameBuffer)
|
||||||
{
|
{
|
||||||
// For Veldrid renderer, we need to capture the current backbuffer content
|
// TODO: Implement screen capture for Veldrid
|
||||||
// This is a simplified implementation - in practice, this would need to be
|
// This is a placeholder implementation
|
||||||
// implemented properly in the VeldridDevice or through the graphics context
|
|
||||||
throw new NotImplementedException("CaptureScreenToFrameBuffer not yet implemented for VeldridRenderer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal override Image<Rgba32>? ExtractFrameBufferData(IFrameBuffer frameBuffer) => ExtractTexture((VeldridTexture)frameBuffer.Texture.NativeTexture);
|
protected internal override Image<Rgba32>? ExtractFrameBufferData(IFrameBuffer frameBuffer)
|
||||||
|
=> ExtractTexture((VeldridTexture)frameBuffer.Texture.NativeTexture);
|
||||||
|
|
||||||
protected internal Image<Rgba32>? ExtractTexture(VeldridTexture texture)
|
protected internal Image<Rgba32>? ExtractTexture(VeldridTexture texture)
|
||||||
{
|
{
|
||||||
@@ -245,34 +270,42 @@ namespace osu.Framework.Graphics.Veldrid
|
|||||||
/// <param name="level">The texture level.</param>
|
/// <param name="level">The texture level.</param>
|
||||||
/// <param name="data">The texture data.</param>
|
/// <param name="data">The texture data.</param>
|
||||||
/// <param name="rowLengthInBytes">The number of bytes per row of the image to read from <paramref name="data"/>.</param>
|
/// <param name="rowLengthInBytes">The number of bytes per row of the image to read from <paramref name="data"/>.</param>
|
||||||
public void UpdateTexture(global::Veldrid.Texture texture, int x, int y, int width, int height, int level, IntPtr data, int rowLengthInBytes) =>
|
public void UpdateTexture(global::Veldrid.Texture texture, int x, int y, int width, int height, int level, IntPtr data, int rowLengthInBytes)
|
||||||
bufferUpdatePipeline.UpdateTexture(stagingTexturePool, texture, x, y, width, height, level, data, rowLengthInBytes);
|
=> bufferUpdatePipeline.UpdateTexture(stagingTexturePool, texture, x, y, width, height, level, data, rowLengthInBytes);
|
||||||
|
|
||||||
protected override void SetUniformImplementation<T>(IUniformWithValue<T> uniform)
|
protected override void SetUniformImplementation<T>(IUniformWithValue<T> uniform)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer) => graphicsPipeline.AttachUniformBuffer(blockName, (IVeldridUniformBuffer)buffer);
|
protected override void SetUniformBufferImplementation(string blockName, IUniformBuffer buffer)
|
||||||
|
=> graphicsPipeline.AttachUniformBuffer(blockName, (IVeldridUniformBuffer)buffer);
|
||||||
|
|
||||||
public void RegisterUniformBufferForReset(IVeldridUniformBuffer buffer) => uniformBufferResetList.Add(buffer);
|
public void RegisterUniformBufferForReset(IVeldridUniformBuffer buffer)
|
||||||
|
=> uniformBufferResetList.Add(buffer);
|
||||||
|
|
||||||
public void GenerateMipmaps(VeldridTexture texture) => graphicsPipeline.GenerateMipmaps(texture);
|
public void GenerateMipmaps(VeldridTexture texture)
|
||||||
|
=> graphicsPipeline.GenerateMipmaps(texture);
|
||||||
|
|
||||||
public CommandList BufferUpdateCommands => bufferUpdatePipeline.Commands;
|
public CommandList BufferUpdateCommands
|
||||||
|
=> bufferUpdatePipeline.Commands;
|
||||||
|
|
||||||
void IVeldridRenderer.BindShader(VeldridShader shader) => BindShader(shader);
|
void IVeldridRenderer.BindShader(VeldridShader shader)
|
||||||
|
=> BindShader(shader);
|
||||||
|
|
||||||
void IVeldridRenderer.UnbindShader(VeldridShader shader) => UnbindShader(shader);
|
void IVeldridRenderer.UnbindShader(VeldridShader shader)
|
||||||
|
=> UnbindShader(shader);
|
||||||
|
|
||||||
void IVeldridRenderer.EnqueueTextureUpload(VeldridTexture texture) => EnqueueTextureUpload(texture);
|
void IVeldridRenderer.EnqueueTextureUpload(VeldridTexture texture)
|
||||||
|
=> EnqueueTextureUpload(texture);
|
||||||
|
|
||||||
protected override IShaderPart CreateShaderPart(IShaderStore store, string name, byte[]? rawData, ShaderPartType partType) => new VeldridShaderPart(this, rawData, partType, store);
|
protected override IShaderPart CreateShaderPart(IShaderStore store, string name, byte[]? rawData, ShaderPartType partType)
|
||||||
|
=> new VeldridShaderPart(this, rawData, partType, store);
|
||||||
|
|
||||||
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore) =>
|
protected override IShader CreateShader(string name, IShaderPart[] parts, ShaderCompilationStore compilationStore)
|
||||||
new VeldridShader(this, name, parts.Cast<VeldridShaderPart>().ToArray(), compilationStore);
|
=> new VeldridShader(this, name, parts.Cast<VeldridShaderPart>().ToArray(), compilationStore);
|
||||||
|
|
||||||
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear) =>
|
public override IFrameBuffer CreateFrameBuffer(RenderBufferFormat[]? renderBufferFormats = null, TextureFilteringMode filteringMode = TextureFilteringMode.Linear)
|
||||||
new VeldridFrameBuffer(this, renderBufferFormats?.ToPixelFormats(), filteringMode.ToSamplerFilter());
|
=> new VeldridFrameBuffer(this, renderBufferFormats?.ToPixelFormats(), filteringMode.ToSamplerFilter());
|
||||||
|
|
||||||
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology primitiveType)
|
protected override IVertexBatch<TVertex> CreateLinearBatch<TVertex>(int size, int maxBuffers, PrimitiveTopology primitiveType)
|
||||||
// maxBuffers is ignored because batches are not allowed to wrap around in Veldrid.
|
// maxBuffers is ignored because batches are not allowed to wrap around in Veldrid.
|
||||||
@@ -282,18 +315,18 @@ namespace osu.Framework.Graphics.Veldrid
|
|||||||
// maxBuffers is ignored because batches are not allowed to wrap around in Veldrid.
|
// maxBuffers is ignored because batches are not allowed to wrap around in Veldrid.
|
||||||
=> new VeldridQuadBatch<TVertex>(this, size);
|
=> new VeldridQuadBatch<TVertex>(this, size);
|
||||||
|
|
||||||
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>() => new VeldridUniformBuffer<TData>(this);
|
protected override IUniformBuffer<TData> CreateUniformBuffer<TData>()
|
||||||
|
=> new VeldridUniformBuffer<TData>(this);
|
||||||
|
|
||||||
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize) => new VeldridShaderStorageBufferObject<TData>(this, uboSize, ssboSize);
|
protected override IShaderStorageBufferObject<TData> CreateShaderStorageBufferObject<TData>(int uboSize, int ssboSize)
|
||||||
|
=> new VeldridShaderStorageBufferObject<TData>(this, uboSize, ssboSize);
|
||||||
|
|
||||||
protected override INativeTexture CreateNativeTexture(int width,
|
protected override INativeTexture CreateNativeTexture(int width, int height, bool manualMipmaps = false, TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
||||||
int height,
|
Color4? initialisationColour = null)
|
||||||
bool manualMipmaps = false,
|
=> new VeldridTexture(this, width, height, manualMipmaps, filteringMode.ToSamplerFilter(), initialisationColour);
|
||||||
TextureFilteringMode filteringMode = TextureFilteringMode.Linear,
|
|
||||||
Color4? initialisationColour = null) =>
|
|
||||||
new VeldridTexture(this, width, height, manualMipmaps, filteringMode.ToSamplerFilter(), initialisationColour);
|
|
||||||
|
|
||||||
protected override INativeTexture CreateNativeVideoTexture(int width, int height) => new VeldridVideoTexture(this, width, height);
|
protected override INativeTexture CreateNativeVideoTexture(int width, int height)
|
||||||
|
=> new VeldridVideoTexture(this, width, height);
|
||||||
|
|
||||||
internal IStagingBuffer<T> CreateStagingBuffer<T>(uint count)
|
internal IStagingBuffer<T> CreateStagingBuffer<T>(uint count)
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Input.States;
|
using osu.Framework.Input.States;
|
||||||
using osu.Framework.Lists;
|
using osu.Framework.Lists;
|
||||||
// using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Framework.Input.Bindings
|
namespace osu.Framework.Input.Bindings
|
||||||
@@ -328,8 +328,8 @@ namespace osu.Framework.Input.Bindings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (handled != null)
|
if (handled != null)
|
||||||
// Logger.Log($"Pressed ({pressed}) handled by {handled}.", LoggingTarget.Runtime, LogLevel.Debug);
|
Logger.Log($"Pressed ({pressed}) handled by {handled}.", LoggingTarget.Runtime, LogLevel.Debug);
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|||||||
61
osu.Framework/Resources/Shaders/sh_AcrylicBlur.fs
Normal file
61
osu.Framework/Resources/Shaders/sh_AcrylicBlur.fs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef ACRYLIC_BLUR_FS
|
||||||
|
#define ACRYLIC_BLUR_FS
|
||||||
|
|
||||||
|
#include "sh_Utils.h"
|
||||||
|
|
||||||
|
#undef INV_SQRT_2PI
|
||||||
|
#define INV_SQRT_2PI 0.39894
|
||||||
|
|
||||||
|
layout(location = 2) in mediump vec2 v_TexCoord;
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform m_BlurParameters
|
||||||
|
{
|
||||||
|
mediump vec2 g_TexSize;
|
||||||
|
int g_Radius;
|
||||||
|
mediump float g_Sigma;
|
||||||
|
highp vec2 g_BlurDirection;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform lowp texture2D m_Texture;
|
||||||
|
layout(set = 1, binding = 1) uniform lowp sampler m_Sampler;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 o_Colour;
|
||||||
|
|
||||||
|
mediump float computeGauss(in mediump float x, in mediump float sigma)
|
||||||
|
{
|
||||||
|
return INV_SQRT_2PI * exp(-0.5*x*x / (sigma*sigma)) / sigma;
|
||||||
|
}
|
||||||
|
|
||||||
|
lowp vec4 blur(int radius, highp vec2 direction, mediump vec2 texCoord, mediump vec2 texSize, mediump float sigma)
|
||||||
|
{
|
||||||
|
mediump vec4 sum = vec4(0.0);
|
||||||
|
mediump float totalWeight = 0.0;
|
||||||
|
|
||||||
|
// 中心像素
|
||||||
|
mediump float weight = computeGauss(0.0, sigma);
|
||||||
|
sum += texture(sampler2D(m_Texture, m_Sampler), texCoord) * weight;
|
||||||
|
totalWeight += weight;
|
||||||
|
|
||||||
|
// 对称采样 - 修复采样位置和权重
|
||||||
|
for (int i = 1; i <= radius; ++i)
|
||||||
|
{
|
||||||
|
// 使用正确的采样位置(1, 2, 3... 而不是1.5, 3.5...)
|
||||||
|
mediump float x = float(i);
|
||||||
|
weight = computeGauss(x, sigma);
|
||||||
|
sum += texture(sampler2D(m_Texture, m_Sampler), texCoord + direction * x / texSize) * weight;
|
||||||
|
sum += texture(sampler2D(m_Texture, m_Sampler), texCoord - direction * x / texSize) * weight;
|
||||||
|
totalWeight += 2.0 * weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum / totalWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
// 应用模糊
|
||||||
|
vec4 blurredColour = blur(g_Radius, g_BlurDirection, v_TexCoord, g_TexSize, g_Sigma);
|
||||||
|
|
||||||
|
o_Colour = blurredColour;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
36
osu.Framework/Resources/Shaders/sh_AcrylicBlur.vs
Normal file
36
osu.Framework/Resources/Shaders/sh_AcrylicBlur.vs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef ACRYLIC_BLUR_VS
|
||||||
|
#define ACRYLIC_BLUR_VS
|
||||||
|
|
||||||
|
#include "sh_Utils.h"
|
||||||
|
|
||||||
|
layout(location = 0) in highp vec2 m_Position;
|
||||||
|
layout(location = 1) in lowp vec4 m_Colour;
|
||||||
|
layout(location = 2) in highp vec2 m_TexCoord;
|
||||||
|
layout(location = 3) in highp vec4 m_TexRect;
|
||||||
|
layout(location = 4) in mediump vec2 m_BlendRange;
|
||||||
|
layout(location = 5) in highp float m_BackbufferDrawDepth;
|
||||||
|
|
||||||
|
layout(location = 0) out highp vec2 v_MaskingPosition;
|
||||||
|
layout(location = 1) out lowp vec4 v_Colour;
|
||||||
|
layout(location = 2) out highp vec2 v_TexCoord;
|
||||||
|
layout(location = 3) out highp vec4 v_TexRect;
|
||||||
|
layout(location = 4) out mediump vec2 v_BlendRange;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
// Transform from screen space to masking space.
|
||||||
|
highp vec3 maskingPos = g_ToMaskingSpace * vec3(m_Position, 1.0);
|
||||||
|
v_MaskingPosition = maskingPos.xy / maskingPos.z;
|
||||||
|
|
||||||
|
v_Colour = m_Colour;
|
||||||
|
v_TexCoord = m_TexCoord;
|
||||||
|
v_TexRect = m_TexRect;
|
||||||
|
v_BlendRange = m_BlendRange;
|
||||||
|
|
||||||
|
gl_Position = g_ProjMatrix * vec4(m_Position, 1.0, 1.0);
|
||||||
|
|
||||||
|
if (g_BackbufferDraw)
|
||||||
|
gl_Position.z = m_BackbufferDrawDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
152
osu.Framework/Resources/Shaders/sh_AcrylicDepthBlur.fs
Normal file
152
osu.Framework/Resources/Shaders/sh_AcrylicDepthBlur.fs
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
#ifndef ACRYLIC_DEPTH_BLUR_FS
|
||||||
|
#define ACRYLIC_DEPTH_BLUR_FS
|
||||||
|
|
||||||
|
#include "sh_Utils.h"
|
||||||
|
#include "sh_Masking.h"
|
||||||
|
|
||||||
|
#undef INV_SQRT_2PI
|
||||||
|
#define INV_SQRT_2PI 0.39894
|
||||||
|
|
||||||
|
layout(location = 0) in highp vec4 v_Colour;
|
||||||
|
layout(location = 1) in mediump vec2 v_TexCoord;
|
||||||
|
layout(location = 2) in highp vec4 v_ScreenPosition;
|
||||||
|
|
||||||
|
// 模糊参数
|
||||||
|
layout(std140, set = 0, binding = 0) uniform m_AcrylicParameters
|
||||||
|
{
|
||||||
|
mediump vec2 g_ScreenSize; // 屏幕尺寸
|
||||||
|
int g_BlurRadius; // 模糊半径
|
||||||
|
mediump float g_BlurSigma; // 高斯模糊 sigma
|
||||||
|
mediump float g_BlurStrength; // 模糊强度(0-1)
|
||||||
|
mediump float g_TintAlpha; // 着色透明度
|
||||||
|
mediump vec3 g_TintColor; // 着色颜色
|
||||||
|
highp float g_CurrentDepth; // 当前容器的深度
|
||||||
|
};
|
||||||
|
|
||||||
|
// 场景纹理(后台缓冲区)
|
||||||
|
layout(set = 1, binding = 0) uniform lowp texture2D m_SceneTexture;
|
||||||
|
layout(set = 1, binding = 1) uniform lowp sampler m_SceneSampler;
|
||||||
|
|
||||||
|
// 深度纹理
|
||||||
|
layout(set = 2, binding = 0) uniform highp texture2D m_DepthTexture;
|
||||||
|
layout(set = 2, binding = 1) uniform highp sampler m_DepthSampler;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 o_Colour;
|
||||||
|
|
||||||
|
// 计算高斯权重
|
||||||
|
mediump float computeGauss(in mediump float x, in mediump float sigma)
|
||||||
|
{
|
||||||
|
return INV_SQRT_2PI * exp(-0.5 * x * x / (sigma * sigma)) / sigma;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基于深度的采样 - 只采样比当前深度更深的像素
|
||||||
|
lowp vec4 sampleWithDepth(vec2 uv, highp float currentDepth)
|
||||||
|
{
|
||||||
|
// 采样深度值
|
||||||
|
highp float depth = texture(sampler2D(m_DepthTexture, m_DepthSampler), uv).r;
|
||||||
|
|
||||||
|
// 只有当采样点的深度大于当前深度时才采样(更深的内容)
|
||||||
|
// 在深度缓冲区中,更大的值表示更深的深度
|
||||||
|
if (depth > currentDepth)
|
||||||
|
{
|
||||||
|
return texture(sampler2D(m_SceneTexture, m_SceneSampler), uv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 如果采样点在当前层之上或同层,返回透明色
|
||||||
|
return vec4(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 双通道可分离高斯模糊(水平+垂直)
|
||||||
|
lowp vec4 applyDepthAwareBlur(vec2 screenCoord, highp float currentDepth, int radius, float sigma)
|
||||||
|
{
|
||||||
|
vec2 pixelSize = 1.0 / g_ScreenSize;
|
||||||
|
|
||||||
|
// 第一步: 水平模糊
|
||||||
|
mediump float factor = computeGauss(0.0, sigma);
|
||||||
|
mediump vec4 horizontalSum = sampleWithDepth(screenCoord, currentDepth) * factor;
|
||||||
|
mediump float totalFactor = factor;
|
||||||
|
int validSamples = 1;
|
||||||
|
|
||||||
|
for (int i = 1; i <= radius; i++)
|
||||||
|
{
|
||||||
|
factor = computeGauss(float(i), sigma);
|
||||||
|
|
||||||
|
vec4 sample1 = sampleWithDepth(screenCoord + vec2(float(i) * pixelSize.x, 0.0), currentDepth);
|
||||||
|
vec4 sample2 = sampleWithDepth(screenCoord - vec2(float(i) * pixelSize.x, 0.0), currentDepth);
|
||||||
|
|
||||||
|
// 只有当采样有效时才累加
|
||||||
|
if (sample1.a > 0.0)
|
||||||
|
{
|
||||||
|
horizontalSum += sample1 * factor;
|
||||||
|
totalFactor += factor;
|
||||||
|
validSamples++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sample2.a > 0.0)
|
||||||
|
{
|
||||||
|
horizontalSum += sample2 * factor;
|
||||||
|
totalFactor += factor;
|
||||||
|
validSamples++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 horizontalBlur = totalFactor > 0.0 ? horizontalSum / totalFactor : vec4(0.0);
|
||||||
|
|
||||||
|
// 第二步: 垂直模糊(对水平模糊的结果进行)
|
||||||
|
// 为简化,我们在fragment shader中做简化版的双通道模糊
|
||||||
|
// 实际生产环境可以用两个pass来实现更高效的可分离模糊
|
||||||
|
factor = computeGauss(0.0, sigma);
|
||||||
|
mediump vec4 finalSum = horizontalBlur * factor;
|
||||||
|
totalFactor = factor;
|
||||||
|
|
||||||
|
for (int i = 1; i <= radius; i++)
|
||||||
|
{
|
||||||
|
factor = computeGauss(float(i), sigma);
|
||||||
|
|
||||||
|
vec4 sample1 = sampleWithDepth(screenCoord + vec2(0.0, float(i) * pixelSize.y), currentDepth);
|
||||||
|
vec4 sample2 = sampleWithDepth(screenCoord - vec2(0.0, float(i) * pixelSize.y), currentDepth);
|
||||||
|
|
||||||
|
if (sample1.a > 0.0)
|
||||||
|
{
|
||||||
|
finalSum += sample1 * factor;
|
||||||
|
totalFactor += factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sample2.a > 0.0)
|
||||||
|
{
|
||||||
|
finalSum += sample2 * factor;
|
||||||
|
totalFactor += factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalFactor > 0.0 ? finalSum / totalFactor : vec4(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
// 计算屏幕空间UV坐标
|
||||||
|
vec2 screenCoord = (v_ScreenPosition.xy / v_ScreenPosition.w) * 0.5 + 0.5;
|
||||||
|
|
||||||
|
// 获取当前片段的深度
|
||||||
|
highp float currentDepth = g_CurrentDepth;
|
||||||
|
|
||||||
|
// 应用深度感知模糊
|
||||||
|
vec4 blurredColor = applyDepthAwareBlur(
|
||||||
|
screenCoord,
|
||||||
|
currentDepth,
|
||||||
|
g_BlurRadius,
|
||||||
|
g_BlurSigma
|
||||||
|
);
|
||||||
|
|
||||||
|
// 应用着色层
|
||||||
|
vec4 tintColor = vec4(g_TintColor, g_TintAlpha);
|
||||||
|
vec4 finalColor = blend(tintColor, blurredColor);
|
||||||
|
|
||||||
|
// 应用遮罩(圆角等)
|
||||||
|
vec2 wrappedCoord = wrap(v_TexCoord, v_TexRect);
|
||||||
|
o_Colour = getRoundedColor(finalColor * v_Colour, wrappedCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
25
osu.Framework/Resources/Shaders/sh_AcrylicDepthBlur.vs
Normal file
25
osu.Framework/Resources/Shaders/sh_AcrylicDepthBlur.vs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef ACRYLIC_DEPTH_BLUR_VS
|
||||||
|
#define ACRYLIC_DEPTH_BLUR_VS
|
||||||
|
|
||||||
|
#include "sh_Utils.h"
|
||||||
|
|
||||||
|
layout(location = 0) in highp vec2 m_Position;
|
||||||
|
layout(location = 1) in lowp vec4 m_Colour;
|
||||||
|
layout(location = 2) in highp vec2 m_TexCoord;
|
||||||
|
|
||||||
|
layout(location = 0) out highp vec4 v_Colour;
|
||||||
|
layout(location = 1) out highp vec2 v_TexCoord;
|
||||||
|
layout(location = 2) out highp vec4 v_ScreenPosition;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
// 传递顶点颜色和纹理坐标
|
||||||
|
v_Colour = m_Colour;
|
||||||
|
v_TexCoord = m_TexCoord;
|
||||||
|
|
||||||
|
// 计算屏幕空间位置(用于深度采样)
|
||||||
|
gl_Position = g_ProjMatrix * vec4(m_Position, 1.0, 1.0);
|
||||||
|
v_ScreenPosition = gl_Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
|
|||||||
Reference in New Issue
Block a user