diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000..6e2e244
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,13 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "csharpier": {
+ "version": "1.3.0",
+ "commands": [
+ "csharpier"
+ ],
+ "rollForward": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/.csharpierignore b/.csharpierignore
new file mode 100644
index 0000000..ae5e493
--- /dev/null
+++ b/.csharpierignore
@@ -0,0 +1,6 @@
+# only format our own code
+Cafe-Shader-Studio/
+
+# Build artifacts
+**/bin/
+**/obj/
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..4dce82c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,30 @@
+# autonormalize, and checkout as native
+* text=auto
+
+# these will break with crlf
+*.sh text eol=lf
+*.nix text eol=lf
+*.lock text eol=lf
+
+# These are binaries
+*.dll binary
+*.exe binary
+*.pdb binary
+*.so binary
+*.dylib binary
+*.zip binary
+*.dds binary
+*.png binary
+*.jpg binary
+*.jpeg binary
+*.bmp binary
+*.tif binary
+*.ico binary
+*.ttf binary
+*.otf binary
+*.wav binary
+*.ogg binary
+*.bin binary
+*.bfres binary
+*.szs binary
+*.sarc binary
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..756130a
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,38 @@
+name: Build
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: windows-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Restore
+ run: dotnet restore PlayerViewer/PlayerViewer.csproj
+
+ - name: Publish
+ run: >
+ dotnet publish PlayerViewer/PlayerViewer.csproj
+ -c Release
+ -r win-x64
+ --self-contained true
+ -p:PublishSingleFile=true
+ -o publish
+
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: PlayerViewer-win-x64
+ path: publish
+ if-no-files-found: error
diff --git a/.gitignore b/.gitignore
index 9e74ff8..db0a0ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,12 @@
bin/
obj/
+# nix
+result
+result-*
+.direnv/
+# dotnet publish output / local nuget cache
+publish/
+.nuget/
.vs/
.vscode/
.cursor/
diff --git a/Cafe-Shader-Studio/AGraphicsLibrary/AGraphicsLibrary.csproj b/Cafe-Shader-Studio/AGraphicsLibrary/AGraphicsLibrary.csproj
index 3f4682b..b2b0052 100644
--- a/Cafe-Shader-Studio/AGraphicsLibrary/AGraphicsLibrary.csproj
+++ b/Cafe-Shader-Studio/AGraphicsLibrary/AGraphicsLibrary.csproj
@@ -1,7 +1,7 @@
- netstandard2.1
+ net10.0
AnyCPU;x86
@@ -22,13 +22,13 @@
-
+
-
+
..\CafeShaderStudio\Lib\AampLibraryCSharp.dll
@@ -36,9 +36,7 @@
..\BfresEditor\Lib\BfresLibrary.dll
-
- ..\CafeShaderStudio\Lib\OpenTK.dll
-
+
..\CafeShaderStudio\Lib\Syroot.BinaryData.dll
@@ -49,5 +47,5 @@
..\CafeShaderStudio\Lib\Toolbox.Core.dll
-
-
\ No newline at end of file
+
+
diff --git a/Cafe-Shader-Studio/BfresEditor/Bfres/Render/SPL3/HoianNXRender.cs b/Cafe-Shader-Studio/BfresEditor/Bfres/Render/SPL3/HoianNXRender.cs
index 10decbb..eeb7813 100644
--- a/Cafe-Shader-Studio/BfresEditor/Bfres/Render/SPL3/HoianNXRender.cs
+++ b/Cafe-Shader-Studio/BfresEditor/Bfres/Render/SPL3/HoianNXRender.cs
@@ -448,7 +448,7 @@ public override void ReloadRenderState(BfresMeshAsset mesh)
mesh.Pass = Pass.TRANSPARENT;
//Materials that sample the game framebuffer (gsys_enable_color_buffer=1)
- //must render in the transparent pass so the pipeline can capture the
+ //must render in the transparent pass so the pipeline can capture the
//framebuffer between passes.
bool usesFramebuffer =
(mat.ShaderOptions.TryGetValue("gsys_enable_color_buffer", out string ecb) && ecb == "1");
@@ -967,9 +967,9 @@ public static void InitTextures()
if (WhiteTexture != null)
return;
- WhiteTexture = GLTexture2D.FromBitmap(Resources.white);
- BlackTexture = GLTexture2D.FromBitmap(Resources.black);
- WhiteArrayTexture = GLTexture2DArray.FromBitmap(Resources.white);
+ WhiteTexture = GLTexture2D.FromRgba(new byte[] { 255, 255, 255, 255 }, 1, 1);
+ BlackTexture = GLTexture2D.FromRgba(new byte[] { 0, 0, 0, 255 }, 1, 1);
+ WhiteArrayTexture = GLTexture2DArray.FromRgba(new byte[] { 255, 255, 255, 255 }, 1, 1);
CubemapTexture = GLTextureCube.FromDDS(new DDS(new MemoryStream(Resources.CubemapLightmap)));
BrdfTexture = GLTexture2D.FromGeneric(new DDS(new MemoryStream(Resources.brdf)), new ImageParameters());
FlipTextureY(BrdfTexture);
diff --git a/Cafe-Shader-Studio/BfresEditor/BfresEditor.csproj b/Cafe-Shader-Studio/BfresEditor/BfresEditor.csproj
index 2be1392..7e4a653 100644
--- a/Cafe-Shader-Studio/BfresEditor/BfresEditor.csproj
+++ b/Cafe-Shader-Studio/BfresEditor/BfresEditor.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net10.0
AnyCPU;x64;x86
BfresEditor
@@ -30,8 +30,11 @@
-
+
+
+
+
@@ -54,9 +57,7 @@
..\CafeShaderStudio\Lib\LZ4.Frame.dll
-
- ..\CafeShaderStudio\Lib\OpenTK.dll
-
+
..\CafeShaderStudio\Lib\Ryujinx.Common.dll
@@ -78,9 +79,6 @@
..\CafeShaderStudio\Lib\TrackStudioLibrary.dll
-
- ..\CafeShaderStudio\Lib\ZstdNet.dll
-
diff --git a/Cafe-Shader-Studio/BfresEditor/Lib/BfresLibrary.pdb b/Cafe-Shader-Studio/BfresEditor/Lib/BfresLibrary.pdb
deleted file mode 100644
index 0d2e4dd..0000000
Binary files a/Cafe-Shader-Studio/BfresEditor/Lib/BfresLibrary.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/BfresEditor/Lib/BfshaLibrary.pdb b/Cafe-Shader-Studio/BfresEditor/Lib/BfshaLibrary.pdb
deleted file mode 100644
index a4bcf69..0000000
Binary files a/Cafe-Shader-Studio/BfresEditor/Lib/BfshaLibrary.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/BfresEditor/Zstb/ZSTB.cs b/Cafe-Shader-Studio/BfresEditor/Zstb/ZSTB.cs
index 82068a4..c0aafea 100644
--- a/Cafe-Shader-Studio/BfresEditor/Zstb/ZSTB.cs
+++ b/Cafe-Shader-Studio/BfresEditor/Zstb/ZSTB.cs
@@ -40,23 +40,23 @@ public Stream Compress(Stream stream)
public static byte[] SDecompress(byte[] b)
{
- using (var decompressor = new ZstdNet.Decompressor())
+ using (var decompressor = new ZstdSharp.Decompressor())
{
- return decompressor.Unwrap(b);
+ return decompressor.Unwrap(b).ToArray();
}
}
public static byte[] SDecompress(byte[] b, int MaxDecompressedSize)
{
- using (var decompressor = new ZstdNet.Decompressor())
+ using (var decompressor = new ZstdSharp.Decompressor())
{
- return decompressor.Unwrap(b, MaxDecompressedSize);
+ return decompressor.Unwrap(b, MaxDecompressedSize).ToArray();
}
}
public static byte[] SCompress(byte[] b)
{
- using (var compressor = new ZstdNet.Compressor())
+ using (var compressor = new ZstdSharp.Compressor())
{
- return compressor.Wrap(b);
+ return compressor.Wrap(b).ToArray();
}
}
}
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/CafeShaderStudio.csproj b/Cafe-Shader-Studio/CafeShaderStudio/CafeShaderStudio.csproj
index 51cb219..320772a 100644
--- a/Cafe-Shader-Studio/CafeShaderStudio/CafeShaderStudio.csproj
+++ b/Cafe-Shader-Studio/CafeShaderStudio/CafeShaderStudio.csproj
@@ -3,7 +3,7 @@
Exe
- net6.0
+ net10.0
true
AnyCPU;x64;x86
@@ -38,9 +38,7 @@
False
Lib\ImGui.NET.dll
-
- Lib\OpenTK.dll
-
+
Lib\OpenTK.GLControl.dll
@@ -56,9 +54,6 @@
Lib\TrackStudioLibrary.dll
-
- Lib\ZstdNet.dll
-
@@ -272,6 +267,9 @@
+
+
@@ -419,12 +417,6 @@
PreserveNewest
-
- PreserveNewest
-
-
- PreserveNewest
-
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/AampLibraryCSharp.pdb b/Cafe-Shader-Studio/CafeShaderStudio/Lib/AampLibraryCSharp.pdb
deleted file mode 100644
index 64e6b08..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/AampLibraryCSharp.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/ByamlExt.pdb b/Cafe-Shader-Studio/CafeShaderStudio/Lib/ByamlExt.pdb
deleted file mode 100644
index e2e264a..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/ByamlExt.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/ImGui.NET.pdb b/Cafe-Shader-Studio/CafeShaderStudio/Lib/ImGui.NET.pdb
deleted file mode 100644
index 115c518..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/ImGui.NET.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/OpenTK.dll b/Cafe-Shader-Studio/CafeShaderStudio/Lib/OpenTK.dll
deleted file mode 100644
index 806e370..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/OpenTK.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/OpenTK.zip b/Cafe-Shader-Studio/CafeShaderStudio/Lib/OpenTK.zip
deleted file mode 100644
index 7b8d9f7..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/OpenTK.zip and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/Ryujinx.Common.pdb b/Cafe-Shader-Studio/CafeShaderStudio/Lib/Ryujinx.Common.pdb
deleted file mode 100644
index 6846f7e..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/Ryujinx.Common.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/Ryujinx.Graphics.Shader.pdb b/Cafe-Shader-Studio/CafeShaderStudio/Lib/Ryujinx.Graphics.Shader.pdb
deleted file mode 100644
index 4a0632f..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/Ryujinx.Graphics.Shader.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/SharpYaml.dll b/Cafe-Shader-Studio/CafeShaderStudio/Lib/SharpYaml.dll
deleted file mode 100644
index 8ed6dba..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/SharpYaml.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/Toolbox.Core.pdb b/Cafe-Shader-Studio/CafeShaderStudio/Lib/Toolbox.Core.pdb
deleted file mode 100644
index e7b4fae..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/Toolbox.Core.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/Toolbox.Core.zip b/Cafe-Shader-Studio/CafeShaderStudio/Lib/Toolbox.Core.zip
deleted file mode 100644
index df0e4b1..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/Toolbox.Core.zip and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/TrackStudioLibrary.pdb b/Cafe-Shader-Studio/CafeShaderStudio/Lib/TrackStudioLibrary.pdb
deleted file mode 100644
index e826439..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/TrackStudioLibrary.pdb and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/Lib/ZstdNet.dll b/Cafe-Shader-Studio/CafeShaderStudio/Lib/ZstdNet.dll
deleted file mode 100644
index fa01c89..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/Lib/ZstdNet.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/cimgui32.dll b/Cafe-Shader-Studio/CafeShaderStudio/cimgui32.dll
deleted file mode 100644
index 77c87e0..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/cimgui32.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/debug_test_out.png b/Cafe-Shader-Studio/CafeShaderStudio/debug_test_out.png
deleted file mode 100644
index ae4ab4f..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/debug_test_out.png and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/tinyfiledialogs32.dll b/Cafe-Shader-Studio/CafeShaderStudio/tinyfiledialogs32.dll
deleted file mode 100644
index 161b042..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/tinyfiledialogs32.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/tinyfiledialogs64.dll b/Cafe-Shader-Studio/CafeShaderStudio/tinyfiledialogs64.dll
deleted file mode 100644
index 3c4b6e7..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/tinyfiledialogs64.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/x64/libzstd.dll b/Cafe-Shader-Studio/CafeShaderStudio/x64/libzstd.dll
deleted file mode 100644
index a836692..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/x64/libzstd.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/x86/cimgui.win-x86.dll b/Cafe-Shader-Studio/CafeShaderStudio/x86/cimgui.win-x86.dll
deleted file mode 100644
index 77c87e0..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/x86/cimgui.win-x86.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeShaderStudio/x86/libzstd.dll b/Cafe-Shader-Studio/CafeShaderStudio/x86/libzstd.dll
deleted file mode 100644
index 3ec45c6..0000000
Binary files a/Cafe-Shader-Studio/CafeShaderStudio/x86/libzstd.dll and /dev/null differ
diff --git a/Cafe-Shader-Studio/CafeStudio.UI/CafeStudio.UI.csproj b/Cafe-Shader-Studio/CafeStudio.UI/CafeStudio.UI.csproj
index 83f350a..e84555b 100644
--- a/Cafe-Shader-Studio/CafeStudio.UI/CafeStudio.UI.csproj
+++ b/Cafe-Shader-Studio/CafeStudio.UI/CafeStudio.UI.csproj
@@ -1,7 +1,7 @@
- netstandard2.1
+ net10.0
AnyCPU;x86
true
@@ -23,14 +23,15 @@
-
+
+
-
+
..\CafeShaderStudio\Lib\CurveEditorLibrary.dll
@@ -38,18 +39,13 @@
..\CafeShaderStudio\Lib\ImGui.NET.dll
-
- ..\CafeShaderStudio\Lib\OpenTK.dll
-
+
..\CafeShaderStudio\Lib\Syroot.BinaryData.dll
..\CafeShaderStudio\Lib\Syroot.Maths.dll
-
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
-
..\CafeShaderStudio\Lib\Toolbox.Core.dll
@@ -57,4 +53,4 @@
..\CafeShaderStudio\Lib\TrackStudioLibrary.dll
-
\ No newline at end of file
+
diff --git a/Cafe-Shader-Studio/GLFrameworkEngine/GLFrameworkEngine.csproj b/Cafe-Shader-Studio/GLFrameworkEngine/GLFrameworkEngine.csproj
index 2d66ab8..0a3c075 100644
--- a/Cafe-Shader-Studio/GLFrameworkEngine/GLFrameworkEngine.csproj
+++ b/Cafe-Shader-Studio/GLFrameworkEngine/GLFrameworkEngine.csproj
@@ -1,7 +1,7 @@
- netstandard2.1
+ net10.0
AnyCPU;x64;x86
@@ -22,16 +22,15 @@
-
+
+
-
+
-
- ..\CafeShaderStudio\Lib\OpenTK.dll
-
+
..\CafeShaderStudio\Lib\Toolbox.Core.dll
-
-
\ No newline at end of file
+
+
diff --git a/Cafe-Shader-Studio/GLFrameworkEngine/Objects/Texture/GLTexture2D.cs b/Cafe-Shader-Studio/GLFrameworkEngine/Objects/Texture/GLTexture2D.cs
index fa2eb9c..5ba643d 100644
--- a/Cafe-Shader-Studio/GLFrameworkEngine/Objects/Texture/GLTexture2D.cs
+++ b/Cafe-Shader-Studio/GLFrameworkEngine/Objects/Texture/GLTexture2D.cs
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using OpenTK.Graphics.OpenGL;
using System.Drawing;
using Toolbox.Core;
@@ -91,14 +89,25 @@ public static GLTexture2D FromGeneric(STGenericTexture texture, ImageParameters
return glTexture;
}
+ //Decodes an encoded image (PNG/JPEG/...) to RGBA and uploads it with ImageSharp.
public static GLTexture2D FromBitmap(byte[] imageFile)
{
- Bitmap image = (Bitmap)Bitmap.FromStream(new System.IO.MemoryStream(imageFile));
+ using var image = SixLabors.ImageSharp.Image.Load(imageFile);
+ byte[] rgba = new byte[image.Width * image.Height * 4];
+ image.CopyPixelDataTo(rgba);
+ return FromRgba(rgba, image.Width, image.Height);
+ }
+ public static GLTexture2D FromRgba(byte[] rgba, int width, int height)
+ {
GLTexture2D texture = new GLTexture2D();
texture.Target = TextureTarget.Texture2D;
- texture.Width = image.Width; texture.Height = image.Height;
- texture.LoadImage(image);
+ texture.Width = width; texture.Height = height;
+ texture.Bind();
+ GL.TexImage2D(texture.Target, 0, PixelInternalFormat.Rgba, width, height, 0,
+ PixelFormat.Rgba, PixelType.UnsignedByte, rgba);
+ GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
+ texture.Unbind();
return texture;
}
diff --git a/Cafe-Shader-Studio/GLFrameworkEngine/Objects/Texture/GLTexture2DArray.cs b/Cafe-Shader-Studio/GLFrameworkEngine/Objects/Texture/GLTexture2DArray.cs
index dc8a08c..0d0ba44 100644
--- a/Cafe-Shader-Studio/GLFrameworkEngine/Objects/Texture/GLTexture2DArray.cs
+++ b/Cafe-Shader-Studio/GLFrameworkEngine/Objects/Texture/GLTexture2DArray.cs
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using OpenTK.Graphics.OpenGL;
using System.Drawing;
using Toolbox.Core;
@@ -133,30 +131,6 @@ private static byte[] FlipHorizontal(int Width, int Height, byte[] Input)
return FlippedOutput;
}
- private static byte[] FlipVertical(int Width, int Height, byte[] Input)
- {
- byte[] FlippedOutput = new byte[Width * Height * 4];
-
- int Stride = Width * 4;
- for (int Y = 0; Y < Height; Y++)
- {
- int IOffs = Stride * Y;
- int OOffs = Stride * (Height - 1 - Y);
-
- for (int X = 0; X < Width; X++)
- {
- FlippedOutput[OOffs + 0] = Input[IOffs + 0];
- FlippedOutput[OOffs + 1] = Input[IOffs + 1];
- FlippedOutput[OOffs + 2] = Input[IOffs + 2];
- FlippedOutput[OOffs + 3] = Input[IOffs + 3];
-
- IOffs += 4;
- OOffs += 4;
- }
- }
- return FlippedOutput;
- }
-
public static GLTexture2DArray FromDDS(DDS[] dds, bool flipY = false)
{
GLTexture2DArray texture = new GLTexture2DArray();
@@ -217,6 +191,18 @@ public static GLTexture2DArray FromBitmap(Bitmap image)
return texture;
}
+ public static GLTexture2DArray FromRgba(byte[] rgba, int width, int height)
+ {
+ GLTexture2DArray texture = new GLTexture2DArray();
+ texture.Width = width; texture.Height = height;
+ texture.Bind();
+ GL.TexImage3D(texture.Target, 0, PixelInternalFormat.Rgba, width, height, 1, 0,
+ OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, rgba);
+ GL.GenerateMipmap(GenerateMipmapTarget.Texture2DArray);
+ texture.Unbind();
+ return texture;
+ }
+
public static GLTexture2DArray FromRawData(int width, int height, TexFormat format, byte[] data)
{
GLTexture2DArray texture = new GLTexture2DArray();
diff --git a/Cafe-Shader-Studio/RedStarLibrary/RedStarLibrary.csproj b/Cafe-Shader-Studio/RedStarLibrary/RedStarLibrary.csproj
index 9792fbd..1c92abb 100644
--- a/Cafe-Shader-Studio/RedStarLibrary/RedStarLibrary.csproj
+++ b/Cafe-Shader-Studio/RedStarLibrary/RedStarLibrary.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net10.0
AnyCPU;x86
@@ -25,9 +25,7 @@
..\CafeShaderStudio\Lib\ImGui.NET.dll
-
- ..\CafeShaderStudio\Lib\OpenTK.dll
-
+
..\CafeShaderStudio\Lib\Syroot.BinaryData.dll
diff --git a/PlayerViewer/Core/AppConfig.cs b/PlayerViewer/Core/AppConfig.cs
index 1561f73..628cdd6 100644
--- a/PlayerViewer/Core/AppConfig.cs
+++ b/PlayerViewer/Core/AppConfig.cs
@@ -4,7 +4,36 @@
namespace PlayerViewer.Core
{
-
+ ///
+ /// Composited export/viewport background. Part of so it travels
+ /// with a preset (a preset captures the whole look: gear, colors, and background).
+ ///
+ public class BackgroundConfig
+ {
+ public int Mode; //0 Transparent, 1 Color, 2 Image
+ public float[] Color = { 0f, 1f, 0f }; //Color mode; green reproduces the old greenscreen
+ public string ImagePath = "";
+ public int ScaleMode; //0 Fill, 1 Fit, 2 Stretch
+ public float Zoom = 1f;
+ public float OffsetX;
+ public float OffsetY;
+ public bool Tile;
+ public int TileX = 1;
+ public int TileY = 1;
+
+ //Clamp user-supplied (preset/settings) values into valid ranges.
+ public void Normalize()
+ {
+ Mode = System.Math.Clamp(Mode, 0, 2);
+ ScaleMode = System.Math.Clamp(ScaleMode, 0, 2);
+ if (Color == null || Color.Length < 3)
+ Color = new[] { 0f, 1f, 0f };
+ ImagePath ??= "";
+ TileX = System.Math.Max(1, TileX);
+ TileY = System.Math.Max(1, TileY);
+ }
+ }
+
public class PlayerConfig
{
public int PlayerType;
@@ -32,11 +61,13 @@ public class PlayerConfig
public float[] CustomAlpha = { 0.925f, 0.243f, 0.549f };
public float[] CustomBravo = { 0.196f, 0.855f, 0.302f };
public float[] CustomCharlie = { 0.980f, 0.769f, 0.196f };
- }
+ //Composited export/viewport background, saved and loaded with the preset.
+ public BackgroundConfig Background = new();
+ }
///
- /// Persisted app configuration (romfs path etc). Stored next to the executable.
+ /// Persisted app configuration (romfs paths etc). Stored in the per-user data folder.
///
public class AppConfig
{
@@ -47,9 +78,37 @@ public class AppConfig
public int WindowWidth = 1600;
public int WindowHeight = 900;
+ //--- Export/capture settings (configured in the Settings window)
+ //Trim fully-transparent deadspace off exported frames. Uses the transparent
+ //render as an alpha oracle, so it also crops greenscreen MP4s.
+ public bool TrimDeadspace = false;
+
+ //Extra pixels of transparent margin kept around the content bounding box.
+ public int TrimMarginPx = 0;
+
+ //WebP encode quality: 100 = lossless (bit-exact), below = lossy (smaller/faster).
+ public int WebpQuality = 100;
+
+ //Export supersample factor (1-8). Exports render internally at this multiple of the
+ //capture size; with trim on, the crop keeps that internal resolution so a loosely
+ //framed subject still exports sharp. VRAM and temp-disk use scale with the square.
+ public int ExportSupersample = 1;
+
+ //Physics warm-up: plays the animation (/ first animation in the sequence) through
+ //this many extra times before recording starts without capturing. Physics reset
+ //whenever an animation loads, so frame 0 has a twitch each time the exported
+ //WebP/WebM loops. A warm-up lets the sim settle first. 0 = disabled.
+ public int PrerollLoops = 1;
+
+ //--- Capture-panel selections (persisted so they stick between runs)
+ public int CaptureResIndex = 2; //index into the resolution dropdown
+ public int ExportFormat = 0; //0 PNG, 1 MP4, 2 WebP, 3 WebM
+ public int ExportFps = 60;
+ public int AnimMode = 0; //0 Single, 1 Sequence
+
public PlayerConfig Player = new();
- static string FilePath => Path.Combine(AppContext.BaseDirectory, "playerviewer_config.json");
+ static string FilePath => Path.Combine(AppPaths.DataDir, "settings.json");
public static AppConfig Load()
{
@@ -57,10 +116,14 @@ public static AppConfig Load()
{
if (File.Exists(FilePath))
{
- var config = JsonConvert.DeserializeObject(File.ReadAllText(FilePath)) ?? new AppConfig();
+ var config =
+ JsonConvert.DeserializeObject(File.ReadAllText(FilePath))
+ ?? new AppConfig();
//Guard against corrupt/zero sizes (e.g. saved while minimized).
- if (config.WindowWidth < 200) config.WindowWidth = 1600;
- if (config.WindowHeight < 200) config.WindowHeight = 900;
+ if (config.WindowWidth < 200)
+ config.WindowWidth = 1600;
+ if (config.WindowHeight < 200)
+ config.WindowHeight = 900;
return config;
}
}
diff --git a/PlayerViewer/Core/AppPaths.cs b/PlayerViewer/Core/AppPaths.cs
new file mode 100644
index 0000000..7fa584a
--- /dev/null
+++ b/PlayerViewer/Core/AppPaths.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace PlayerViewer.Core
+{
+ ///
+ /// Per-user data directory, created on first access: %APPDATA%\PlayerViewer on Windows,
+ /// ~/.config/PlayerViewer on Linux/macOS. Holds settings.json and an optional bundled ffmpeg.
+ ///
+ public static class AppPaths
+ {
+ public static string DataDir { get; } = CreateDataDir();
+
+ static string CreateDataDir()
+ {
+ string dir = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ "PlayerViewer"
+ );
+ Directory.CreateDirectory(dir);
+ return dir;
+ }
+
+ /// Opens the data directory in the OS file browser.
+ public static void OpenDataDir()
+ {
+ try
+ {
+ if (OperatingSystem.IsWindows())
+ Process.Start(
+ new ProcessStartInfo { FileName = DataDir, UseShellExecute = true }
+ );
+ else if (OperatingSystem.IsMacOS())
+ Process.Start("open", DataDir);
+ else
+ Process.Start("xdg-open", DataDir);
+ }
+ catch { }
+ }
+ }
+}
diff --git a/PlayerViewer/Core/Formats/Byml.cs b/PlayerViewer/Core/Formats/Byml.cs
index f7c4b66..062b471 100644
--- a/PlayerViewer/Core/Formats/Byml.cs
+++ b/PlayerViewer/Core/Formats/Byml.cs
@@ -36,7 +36,9 @@ public Byml(byte[] data)
}
uint ReadU32(int offset) => BitConverter.ToUInt32(_data, offset);
- uint ReadU24(int offset) => (uint)(_data[offset] | (_data[offset + 1] << 8) | (_data[offset + 2] << 16));
+
+ uint ReadU24(int offset) =>
+ (uint)(_data[offset] | (_data[offset + 1] << 8) | (_data[offset + 2] << 16));
string[] ReadStringTable(uint offset)
{
@@ -47,7 +49,8 @@ string[] ReadStringTable(uint offset)
{
uint strOff = offset + ReadU32((int)(offset + 4 + i * 4));
int end = (int)strOff;
- while (_data[end] != 0) end++;
+ while (_data[end] != 0)
+ end++;
result[i] = Encoding.UTF8.GetString(_data, (int)strOff, end - (int)strOff);
}
return result;
@@ -57,17 +60,28 @@ object ReadNode(byte type, uint valueOrOffset)
{
switch (type)
{
- case 0xA0: return _strings[ReadU32((int)valueOrOffset)];
- case 0xC0: return ReadArray(valueOrOffset);
- case 0xC1: return ReadHash(valueOrOffset);
- case 0xD0: return ReadU32((int)valueOrOffset) != 0;
- case 0xD1: return BitConverter.ToInt32(_data, (int)valueOrOffset);
- case 0xD2: return BitConverter.ToSingle(_data, (int)valueOrOffset);
- case 0xD3: return ReadU32((int)valueOrOffset);
- case 0xD4: return BitConverter.ToInt64(_data, (int)ReadU32((int)valueOrOffset));
- case 0xD5: return BitConverter.ToUInt64(_data, (int)ReadU32((int)valueOrOffset));
- case 0xD6: return BitConverter.ToDouble(_data, (int)ReadU32((int)valueOrOffset));
- case 0xFF: return null;
+ case 0xA0:
+ return _strings[ReadU32((int)valueOrOffset)];
+ case 0xC0:
+ return ReadArray(valueOrOffset);
+ case 0xC1:
+ return ReadHash(valueOrOffset);
+ case 0xD0:
+ return ReadU32((int)valueOrOffset) != 0;
+ case 0xD1:
+ return BitConverter.ToInt32(_data, (int)valueOrOffset);
+ case 0xD2:
+ return BitConverter.ToSingle(_data, (int)valueOrOffset);
+ case 0xD3:
+ return ReadU32((int)valueOrOffset);
+ case 0xD4:
+ return BitConverter.ToInt64(_data, (int)ReadU32((int)valueOrOffset));
+ case 0xD5:
+ return BitConverter.ToUInt64(_data, (int)ReadU32((int)valueOrOffset));
+ case 0xD6:
+ return BitConverter.ToDouble(_data, (int)ReadU32((int)valueOrOffset));
+ case 0xFF:
+ return null;
default:
throw new NotSupportedException($"BYML node type 0x{type:X2} not supported.");
}
@@ -116,26 +130,53 @@ Dictionary ReadHash(uint offset)
#region typed access helpers
- public static Dictionary AsHash(object node) => node as Dictionary;
+ public static Dictionary AsHash(object node) =>
+ node as Dictionary;
+
public static List