From 9b676895438e069187de7d99a43336f4677d8f66 Mon Sep 17 00:00:00 2001 From: Peter Li Date: Wed, 7 May 2025 15:08:07 -0700 Subject: [PATCH] ported all shaders needed for papyrus UI --- build.zig | 1 + build.zig.zon | 1 + engine/backlog.zig | 2 +- engine/modulelist.zig | 2 +- engine/papyrus/src/papyrus.zig | 190 +++++++------ engine/papyrus/tests/testing.zig | 18 +- engine/rend/shaders/meshes.vert.hlsl | 2 +- engine/ui/build.zig | 47 ++++ engine/ui/build.zig.zon | 15 + engine/ui/shaders/fragmentHelpers.hlsli | 46 ++++ engine/ui/shaders/rect.frag.hlsl | 117 ++++++++ engine/ui/shaders/rect.frag.json | 137 +++++++++ engine/ui/shaders/rect.vert.hlsl | 52 ++++ engine/ui/shaders/rect.vert.json | 145 ++++++++++ engine/ui/shaders/rect_shared.hlsli | 20 ++ engine/ui/shaders/text.frag.hlsl | 73 +++++ engine/ui/shaders/text.frag.json | 112 ++++++++ engine/ui/shaders/text.vert.hlsl | 42 +++ engine/ui/shaders/text.vert.json | 125 +++++++++ engine/ui/shaders/text_shared.hlsli | 14 + engine/ui/src/sgpu/embedded/quad.obj | 14 + engine/ui/src/sgpu/papyrusSgpu.zig | 115 ++++++++ engine/ui/src/ui.zig | 38 +++ engine/ui/tests/test.zig | 1 + engine/ui/tests/tests.zig | 7 + .../content/_shaders/dxil/meshes.vert.dxil | Bin 6408 -> 6536 bytes projects/content/_shaders/dxil/rect.frag.dxil | Bin 0 -> 6284 bytes projects/content/_shaders/dxil/rect.vert.dxil | Bin 0 -> 5060 bytes projects/content/_shaders/dxil/text.frag.dxil | Bin 0 -> 5952 bytes projects/content/_shaders/dxil/text.vert.dxil | Bin 0 -> 5004 bytes projects/content/_shaders/msl/meshes.vert.msl | 2 +- projects/content/_shaders/msl/rect.frag.msl | 259 ++++++++++++++++++ projects/content/_shaders/msl/rect.vert.msl | 59 ++++ projects/content/_shaders/msl/text.frag.msl | 100 +++++++ projects/content/_shaders/msl/text.vert.msl | 53 ++++ projects/content/_shaders/spv/meshes.vert.spv | Bin 2332 -> 2488 bytes projects/content/_shaders/spv/rect.frag.spv | Bin 0 -> 6316 bytes projects/content/_shaders/spv/rect.vert.spv | Bin 0 -> 3100 bytes projects/content/_shaders/spv/text.frag.spv | Bin 0 -> 4432 bytes projects/content/_shaders/spv/text.vert.spv | Bin 0 -> 2080 bytes projects/sampleGame/main.zig | 3 + tools/scripts/cookShaders.py | 2 + 42 files changed, 1730 insertions(+), 84 deletions(-) create mode 100644 engine/ui/build.zig create mode 100644 engine/ui/build.zig.zon create mode 100644 engine/ui/shaders/fragmentHelpers.hlsli create mode 100644 engine/ui/shaders/rect.frag.hlsl create mode 100644 engine/ui/shaders/rect.frag.json create mode 100644 engine/ui/shaders/rect.vert.hlsl create mode 100644 engine/ui/shaders/rect.vert.json create mode 100644 engine/ui/shaders/rect_shared.hlsli create mode 100644 engine/ui/shaders/text.frag.hlsl create mode 100644 engine/ui/shaders/text.frag.json create mode 100644 engine/ui/shaders/text.vert.hlsl create mode 100644 engine/ui/shaders/text.vert.json create mode 100644 engine/ui/shaders/text_shared.hlsli create mode 100644 engine/ui/src/sgpu/embedded/quad.obj create mode 100644 engine/ui/src/sgpu/papyrusSgpu.zig create mode 100644 engine/ui/src/ui.zig create mode 100644 engine/ui/tests/test.zig create mode 100644 engine/ui/tests/tests.zig create mode 100644 projects/content/_shaders/dxil/rect.frag.dxil create mode 100644 projects/content/_shaders/dxil/rect.vert.dxil create mode 100644 projects/content/_shaders/dxil/text.frag.dxil create mode 100644 projects/content/_shaders/dxil/text.vert.dxil create mode 100644 projects/content/_shaders/msl/rect.frag.msl create mode 100644 projects/content/_shaders/msl/rect.vert.msl create mode 100644 projects/content/_shaders/msl/text.frag.msl create mode 100644 projects/content/_shaders/msl/text.vert.msl create mode 100644 projects/content/_shaders/spv/rect.frag.spv create mode 100644 projects/content/_shaders/spv/rect.vert.spv create mode 100644 projects/content/_shaders/spv/text.frag.spv create mode 100644 projects/content/_shaders/spv/text.vert.spv diff --git a/build.zig b/build.zig index 1f180ad..67cd029 100644 --- a/build.zig +++ b/build.zig @@ -23,6 +23,7 @@ const engineDepList = [_][]const u8{ "rend", "imgui", "physics", + "ui", }; const BuildSystem = @This(); diff --git a/build.zig.zon b/build.zig.zon index 6eaa93f..11a6742 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -9,6 +9,7 @@ .physics = .{ .path = "engine/physics" }, .platform = .{ .path = "engine/platform" }, .imgui = .{ .path = "engine/imgui" }, + .ui = .{ .path = "engine/ui" }, .rend = .{.path = "engine/rend" }, .SpirvReflect = .{ .path = "lib/spirv-reflect-zig" }, .ozz = .{ .path = "lib/ozz" }, diff --git a/engine/backlog.zig b/engine/backlog.zig index 8842d7b..1280953 100644 --- a/engine/backlog.zig +++ b/engine/backlog.zig @@ -5,7 +5,7 @@ pub const rend = @import("rend"); pub const audio = @import("audio"); // pub const graphics = @import("graphics"); // pub const vkImgui = @import("vkImgui"); -// pub const ui = @import("ui"); +pub const ui = @import("ui"); pub const papyrus = @import("papyrus"); pub const physics = @import("physics"); pub const imgui = @import("imgui"); diff --git a/engine/modulelist.zig b/engine/modulelist.zig index 4bda2af..bf51a60 100644 --- a/engine/modulelist.zig +++ b/engine/modulelist.zig @@ -7,8 +7,8 @@ pub const list = [_][]const u8{ "rend", "imgui", + "ui", // to be implemented // "graphics", - // "ui", // "vkImgui", }; diff --git a/engine/papyrus/src/papyrus.zig b/engine/papyrus/src/papyrus.zig index 163cf7e..068d922 100644 --- a/engine/papyrus/src/papyrus.zig +++ b/engine/papyrus/src/papyrus.zig @@ -100,9 +100,6 @@ pub const NodeHandle = core.IndexPoolHandle; // // =================================== /Document: How should the layout engine work =========================== -pub var gContext: *Context = undefined; -pub var gIsInitialized: bool = false; - pub const AnchorNode = enum { // zig fmt: off Free, // Anchored to 0,0 absolute on the screen @@ -279,22 +276,123 @@ pub const HorizontalLayoutInfo = struct { horizontalChildSize: f32 = 0, }; -pub const Context = struct { - backingAllocator: std.mem.Allocator, +pub const FontCache = struct { allocator: std.mem.Allocator, - nodes: IndexPool(Node), - fonts: std.AutoHashMap(u32, Font), + fonts: std.AutoHashMapUnmanaged(u32, Font), + defaultFont: Font, defaultMonoFont: Font, defaultBitmapFont: Font, + + pub fn create(allocator: std.mem.Allocator) !*@This() { + const self = try allocator.create(@This()); + + const defaultFontName: []const u8 = "default"; + const defaultMonoName: []const u8 = "monospace"; + const defaultBitmapFontName: []const u8 = "bitmap"; + + self.* = .{ + .allocator = allocator, + .fonts = .{}, + .defaultFont = Font{ + .name = Name.fromUtf8(defaultFontName), + .atlas = try allocator.create(FontAtlas), + }, + .defaultMonoFont = Font{ + .name = Name.fromUtf8(defaultMonoName), + .atlas = try allocator.create(FontAtlas), + }, + .defaultBitmapFont = Font{ + .name = Name.fromUtf8(defaultBitmapFontName), + .atlas = try allocator.create(FontAtlas), + }, + }; + + self.defaultFont.atlas.* = try FontAtlas.initDefaultFont(allocator, 64); + try self.installFontAtlas(self.defaultFont.name.utf8(), self.defaultFont.atlas); + + self.defaultMonoFont.atlas.* = try FontAtlas.initMonoFont(allocator, 64); + try self.installFontAtlas(self.defaultMonoFont.name.utf8(), self.defaultMonoFont.atlas); + + // this is a 16 px sized default font + self.defaultBitmapFont.atlas.* = try FontAtlas.initDefaultBitmapFont(allocator, 16); + try self.installFontAtlas(self.defaultBitmapFont.name.utf8(), self.defaultBitmapFont.atlas); + + // difference between asserts and assertf is asserts is not recoverable, + // instantly crashes. + asserts( + self.defaultBitmapFont.atlas.atlasBuffer != null, + "expected atlas buffer to be valid {any}", + .{self.defaultBitmapFont.atlas.atlasBuffer}, + @src().fn_name, + ); + + return self; + } + + pub fn installFontAtlas(self: *@This(), fontName: []const u8, atlas: *FontAtlas) !void { + var name = Name.fromUtf8(fontName); + try self.fonts.put(self.allocator, name.handle(), .{ .atlas = atlas, .name = name }); + } + + pub fn destroy(self: *@This()) void { + var iter = self.fonts.iterator(); + while (iter.next()) |i| { + i.value_ptr.atlas.deinit(); + self.allocator.destroy(i.value_ptr.atlas); + } + + self.fonts.deinit(self.allocator); + self.allocator.destroy(self); + } +}; + +pub const PapyrusRuntime = struct { + allocator: std.mem.Allocator, + fontCache: *FontCache, + + pub fn create(allocator: std.mem.Allocator) !*@This() { + const self = try allocator.create(@This()); + + self.* = .{ + .allocator = allocator, + .fontCache = try FontCache.create(allocator), + }; + + return self; + } + + pub fn addContext(self: *@This()) !*Context { + const rv = try Context.create(self.allocator, self); + + return rv; + } + + pub fn destroy(self: *@This()) void { + self.fontCache.destroy(); + self.allocator.destroy(self); + } +}; + +pub const Context = struct { + nodes: IndexPool(Node), + + allocator: std.mem.Allocator, + extent: Vector2i = .{ .x = 1920, .y = 1080 }, currentCursorPosition: Vector2f = .{}, styleStack: std.ArrayListUnmanaged(NodeStyle) = .{}, resolvedStyle: NodeStyle = .{}, + defaultFont: Font, + defaultMonoFont: Font, + defaultBitmapFont: Font, + mousePick: Layout, + fontCache: *FontCache, + events: Event, textEntry: *TextEntrySystem, @@ -340,32 +438,19 @@ pub const Context = struct { } } - pub fn create(backingAllocator: std.mem.Allocator) !*@This() { - const defaultFontName: []const u8 = "default"; - const defaultMonoName: []const u8 = "monospace"; - const defaultBitmapFontName: []const u8 = "bitmap"; - + pub fn create(backingAllocator: std.mem.Allocator, ctx: *PapyrusRuntime) !*@This() { var self = try backingAllocator.create(@This()); var allocator = backingAllocator; self.* = .{ .allocator = allocator, - .backingAllocator = allocator, .nodes = IndexPool(Node).init(allocator), - .fonts = std.AutoHashMap(u32, Font).init(allocator), .events = Event.init(allocator), - .defaultFont = Font{ - .name = Name.fromUtf8(defaultFontName), - .atlas = try allocator.create(FontAtlas), - }, - .defaultMonoFont = Font{ - .name = Name.fromUtf8(defaultMonoName), - .atlas = try allocator.create(FontAtlas), - }, - .defaultBitmapFont = Font{ - .name = Name.fromUtf8(defaultBitmapFontName), - .atlas = try allocator.create(FontAtlas), - }, + .fontCache = ctx.fontCache, + .defaultFont = ctx.fontCache.defaultFont, + .defaultMonoFont = ctx.fontCache.defaultMonoFont, + .defaultBitmapFont = ctx.fontCache.defaultBitmapFont, + .textEntry = try TextEntrySystem.create(self, allocator), ._drawOrder = DrawOrderList.init(allocator), ._layout = .{}, @@ -380,25 +465,6 @@ pub const Context = struct { try self.debugText.append(textBuffer); } - self.defaultFont.atlas.* = try FontAtlas.initDefaultFont(allocator, 64); - try self.installFontAtlas(self.defaultFont.name.utf8(), self.defaultFont.atlas); - - self.defaultMonoFont.atlas.* = try FontAtlas.initMonoFont(allocator, 64); - try self.installFontAtlas(self.defaultMonoFont.name.utf8(), self.defaultMonoFont.atlas); - - // this is a 16 px sized default font - self.defaultBitmapFont.atlas.* = try FontAtlas.initDefaultBitmapFont(allocator, 16); - try self.installFontAtlas(self.defaultBitmapFont.name.utf8(), self.defaultBitmapFont.atlas); - - // difference between asserts and assertf is asserts is not recoverable, - // instantly crashes. - asserts( - self.defaultBitmapFont.atlas.atlasBuffer != null, - "expected atlas buffer to be valid {any}", - .{self.defaultBitmapFont.atlas.atlasBuffer}, - @src().fn_name, - ); - // constructing the root node _ = try self.nodes.new(.{ .text = MakeText("root"), @@ -437,13 +503,6 @@ pub const Context = struct { self.textEntry.destroy(); - var iter = self.fonts.iterator(); - while (iter.next()) |i| { - i.value_ptr.atlas.deinit(); - self.allocator.destroy(i.value_ptr.atlas); - } - - self.fonts.deinit(); self.nodes.deinit(); self.events.deinit(); self._drawOrder.deinit(); @@ -458,12 +517,7 @@ pub const Context = struct { self.allocator.free(text); } self.debugText.deinit(); - self.backingAllocator.destroy(self); - } - - pub fn installFontAtlas(self: *@This(), fontName: []const u8, atlas: *FontAtlas) !void { - var name = Name.fromUtf8(fontName); - try self.fonts.put(name.handle(), .{ .atlas = atlas, .name = name }); + self.allocator.destroy(self); } pub fn fetchPanel(self: *@This(), handle: NodeHandle) ?*NodeProperty_Panel { @@ -1128,7 +1182,7 @@ pub const Context = struct { var yOffset: f32 = sizePerLine; const width = defaultHeight / 2 * 120; - const fontHash = self.defaultMonoFont.atlas.rendererHash; + const fontHash = self.fontCache.defaultMonoFont.atlas.rendererHash; try self.mousePick.addMousePickInfo(&self, drawList); @@ -1245,24 +1299,6 @@ pub const Context = struct { } }; -pub fn getContext() *Context { - return gContext; -} - -pub fn initialize(allocator: std.mem.Allocator) !*Context { - try assertf(gIsInitialized == false, "Unable to initialize Papyrus, already initialized", .{}); - core.ui_log("Papyrus initialized here's some stats:", .{}); - core.ui_log(" - DrawListCommand size: {d}", .{@sizeOf(DrawList)}); - core.ui_log(" - Node size: {d}", .{@sizeOf(Node)}); - gIsInitialized = true; - gContext = try Context.create(allocator); - return gContext; -} - -pub fn deinitialize() void { - gContext.deinit(); -} - pub const Module = core.ModuleDescription{ .name = "papyrus", .enabledByDefault = true, diff --git a/engine/papyrus/tests/testing.zig b/engine/papyrus/tests/testing.zig index d056cd1..30d8fa9 100644 --- a/engine/papyrus/tests/testing.zig +++ b/engine/papyrus/tests/testing.zig @@ -31,7 +31,10 @@ const IndexPool = core.IndexPool; // ======================== unit tests for papyrus ========================== test "hierarchy test" { - const ctx = try PapyrusContext.create(std.testing.allocator); + const runtime = try papyrus.PapyrusRuntime.create(std.testing.allocator); + defer runtime.destroy(); + + const ctx = try runtime.addContext(); defer ctx.deinit(); std.debug.print( @@ -79,7 +82,10 @@ test "hierarchy test" { } test "Testing a fullscreen render" { - const ctx = try PapyrusContext.create(std.testing.allocator); + const runtime = try papyrus.PapyrusRuntime.create(std.testing.allocator); + defer runtime.destroy(); + + const ctx = try runtime.addContext(); defer ctx.deinit(); var rend = try BmpRenderer.init(std.testing.allocator, ctx, ctx.extent); @@ -147,9 +153,15 @@ test "Testing a fullscreen render" { } test "Testing a render" { - const ctx = try PapyrusContext.create(std.testing.allocator); + const runtime = try papyrus.PapyrusRuntime.create(std.testing.allocator); + defer runtime.destroy(); + + const ctx = try runtime.addContext(); defer ctx.deinit(); + const ctx2 = try runtime.addContext(); + defer ctx2.deinit(); + var rend = try BmpRenderer.init(std.testing.allocator, ctx, ctx.extent); rend.baseColor = ColorRGBA8.fromHex(0x888888ff); defer rend.deinit(); diff --git a/engine/rend/shaders/meshes.vert.hlsl b/engine/rend/shaders/meshes.vert.hlsl index 7760044..7331023 100644 --- a/engine/rend/shaders/meshes.vert.hlsl +++ b/engine/rend/shaders/meshes.vert.hlsl @@ -57,7 +57,7 @@ Output main(Input input) float4 WorldPos = mul(scene[input.Instance].Model, pos); output.Position = mul(ViewProjection, mul(scene[input.Instance].Model, pos)); output.WorldPos = WorldPos.xyz; - output.Normal = input.Normal; + output.Normal = mul(scene[input.Instance].Model, float4(input.Normal, 1.0)).xyz; output.DirectionalShadowFragPos = mul(ShadowMapProjection, WorldPos); output.Instance = input.Instance; diff --git a/engine/ui/build.zig b/engine/ui/build.zig new file mode 100644 index 0000000..c951af3 --- /dev/null +++ b/engine/ui/build.zig @@ -0,0 +1,47 @@ +const std = @import("std"); +const sdl3 = @import("sdl3"); + +const dependencyList = [_][]const u8{ + "core", + "platform", + "rend", + "papyrus", + "sdl3", +}; + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const mod = b.addModule("ui", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("src/ui.zig"), + }); + + for (dependencyList) |depName| { + const dep = b.dependency(depName, .{ .target = target, .optimize = optimize }); + const dep_mod = dep.module(depName); + mod.addImport(depName, dep_mod); + } + + // shaders + sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "rect.vert", b.path("shaders/rect.vert.json")); + sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "rect.frag", b.path("shaders/rect.frag.json")); + + sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "text.vert", b.path("shaders/text.vert.json")); + sdl3.shaderDefintion(b, mod, "../../lib/sdl3", optimize, "text.frag", b.path("shaders/text.frag.json")); + + // ========== tests ========== + const tests = b.addTest(.{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("tests/tests.zig"), + }); + const test_step = b.step("test", "run unit tests for ui"); + + tests.root_module.addImport("ui", mod); + const runArtifact = b.addRunArtifact(tests); + test_step.dependOn(&runArtifact.step); + b.installArtifact(tests); +} diff --git a/engine/ui/build.zig.zon b/engine/ui/build.zig.zon new file mode 100644 index 0000000..1895ffe --- /dev/null +++ b/engine/ui/build.zig.zon @@ -0,0 +1,15 @@ +.{ + .name = .ui, + .version = "0.0.0", + .dependencies = .{ + .core = .{ .path = "../core" }, + .platform = .{ .path = "../platform" }, + .papyrus = .{ .path = "../papyrus" }, + .rend = .{ .path = "../rend" }, + .sdl3 = .{ .path = "../../lib/sdl3" }, + }, + .paths = .{ + "", + }, + .fingerprint = 0x27ff46b0db01e0ab, +} diff --git a/engine/ui/shaders/fragmentHelpers.hlsli b/engine/ui/shaders/fragmentHelpers.hlsli new file mode 100644 index 0000000..776a37b --- /dev/null +++ b/engine/ui/shaders/fragmentHelpers.hlsli @@ -0,0 +1,46 @@ +bool somewhatEqual(float left, float right) +{ + return distance(left, right) < 1.0; +} + +float median(float r, float g, float b) +{ + return max(min(r, g), min(max(r, g), b)); +} + +float contour(float dist, float edge, float width) { + return clamp(smoothstep(edge - width, edge + width, dist), 0.0, 1.0); +} + +float getSample( + Texture2D SampleTexture, + SamplerState Sampler, + float2 texCoord, + float edge, + float width +) { + return contour( SampleTexture.Sample(Sampler, texCoord).r, edge, width); +} + +bool scissor(float2 position, float2 topleft, float2 size) +{ + if(position.x >= topleft.x && position.x <= topleft.x + size.x && + position.y >= topleft.y && position.y <= topleft.y + size.y ) + { + return true; + } + + return false; +} + +bool rect(float2 position, float2 topleft, float2 size) +{ + if(position.x >= topleft.x && position.x <= topleft.x + size.x && + position.y >= topleft.y && position.y <= topleft.y + size.y ) + { + return true; + } + + return false; +} + diff --git a/engine/ui/shaders/rect.frag.hlsl b/engine/ui/shaders/rect.frag.hlsl new file mode 100644 index 0000000..07d7759 --- /dev/null +++ b/engine/ui/shaders/rect.frag.hlsl @@ -0,0 +1,117 @@ +#include "rect_shared.hlsli" +#include "fragmentHelpers.hlsli" + +struct PSOut{ + float4 Color: SV_Target0; +}; + +Texture2D Texture0 : register(t0, space2); +SamplerState Sampler0 : register(s0, space2); + +PSOut main( + float4 Color : TEXCOORD0, + float2 UV : TEXCOORD1, + float2 pixelPosition: TEXCOORD2, + uint Instance: TEXCOORD3 +) { + Scene s = scene[Instance]; + PSOut o; + + // check to discard topleft + float3 color = Color.xyz; + float alpha = s.alpha; + uint usesImage = s.flags & 1; + float4 rounding = s.rounding; + float borderWidth = s.borderWidth; + float2 imageSize = s.imageSize; + + + if(pixelPosition.x < rounding.x && pixelPosition.y < rounding.y) + { + float dist = distance(pixelPosition, float2(rounding.x, rounding.x)); + if(dist > (rounding.x )) + { + discard; + } + else if(somewhatEqual(dist, rounding.x)) + { + color = s.edgeColor.xyz; + alpha = s.edgeColor.w; + } + } + + // top right + if(pixelPosition.x > imageSize.x - rounding.y && pixelPosition.y < rounding.y ) + { + float dist = distance(pixelPosition, float2(imageSize.x - rounding.y, rounding.y)); + if(dist > rounding.y) + { + discard; + } + else if(somewhatEqual(dist, rounding.y)) + { + color = s.edgeColor.xyz; + alpha = s.edgeColor.w; + } + } + + // bottom Left + if(pixelPosition.x < rounding.x && pixelPosition.y > imageSize.y - rounding.y) + { + float dist = distance(pixelPosition, float2(rounding.x, imageSize.y - rounding.y)); + if(dist > rounding.y) + { + discard; + } + else if(somewhatEqual(dist, rounding.y)) + { + color = s.edgeColor.xyz; + alpha = s.edgeColor.w; + } + } + + // bottom right + if(pixelPosition.x > imageSize.x - rounding.a && imageSize.y - pixelPosition.y < rounding.a ) + { + float dist = distance(pixelPosition, float2(imageSize.x - rounding.x, imageSize.y - rounding.y)); + if(dist > rounding.y) + { + discard; + } + else if(somewhatEqual(dist, rounding.y)) + { + color = s.edgeColor.xyz; + alpha = s.edgeColor.w; + } + } + + // check to discard topright + + // determine border colors + + if( pixelPosition.x < borderWidth + || pixelPosition.x > imageSize.x - borderWidth + || pixelPosition.y < borderWidth + || pixelPosition.y > imageSize.y - borderWidth + ) + { + color = s.edgeColor.xyz; + alpha = s.edgeColor.w; + } + + // scale the color + if(usesImage > 0) + { + // vec4 sampledColor = texture(tex, float2(texCoord.x, 1 - texCoord.y)); + float4 sampledColor = Texture0.Sample(Sampler0, float2(UV.x, 1 - UV.y)); + o.Color = float4(sampledColor.rgb, sampledColor.a * alpha); + } + else + { + o.Color = float4(pow(color, 2.2), alpha); + } + + return o; +} + + diff --git a/engine/ui/shaders/rect.frag.json b/engine/ui/shaders/rect.frag.json new file mode 100644 index 0000000..ecd3f0c --- /dev/null +++ b/engine/ui/shaders/rect.frag.json @@ -0,0 +1,137 @@ +{ + "entryPoints" : [ + { + "name" : "main", + "mode" : "frag" + } + ], + "types" : { + "_9" : { + "name" : "Scene", + "members" : [ + { + "name" : "imagePosition", + "type" : "vec2", + "offset" : 0 + }, + { + "name" : "imageSize", + "type" : "vec2", + "offset" : 8 + }, + { + "name" : "anchorPoint", + "type" : "vec2", + "offset" : 16 + }, + { + "name" : "scale", + "type" : "vec2", + "offset" : 24 + }, + { + "name" : "alpha", + "type" : "float", + "offset" : 32 + }, + { + "name" : "borderWidth", + "type" : "float", + "offset" : 36 + }, + { + "name" : "flags", + "type" : "uint", + "offset" : 40 + }, + { + "name" : "baseColor", + "type" : "vec4", + "offset" : 48 + }, + { + "name" : "rounding", + "type" : "vec4", + "offset" : 64 + }, + { + "name" : "edgeColor", + "type" : "vec4", + "offset" : 80 + } + ] + }, + "_8" : { + "name" : "type.StructuredBuffer.Scene", + "members" : [ + { + "name" : "_m0", + "type" : "_9", + "array" : [ + 0 + ], + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 96 + } + ] + } + }, + "inputs" : [ + { + "type" : "vec4", + "name" : "in.var.TEXCOORD0", + "location" : 0 + }, + { + "type" : "vec2", + "name" : "in.var.TEXCOORD1", + "location" : 1 + }, + { + "type" : "vec2", + "name" : "in.var.TEXCOORD2", + "location" : 2 + }, + { + "type" : "uint", + "name" : "in.var.TEXCOORD3", + "location" : 3 + } + ], + "outputs" : [ + { + "type" : "vec4", + "name" : "out.var.SV_Target0", + "location" : 0 + } + ], + "separate_images" : [ + { + "type" : "texture2D", + "name" : "Texture0", + "set" : 2, + "binding" : 0 + } + ], + "separate_samplers" : [ + { + "type" : "sampler", + "name" : "Sampler0", + "set" : 2, + "binding" : 0 + } + ], + "ssbos" : [ + { + "type" : "_8", + "name" : "scene", + "readonly" : true, + "block_size" : 0, + "set" : 0, + "binding" : 0 + } + ] +} \ No newline at end of file diff --git a/engine/ui/shaders/rect.vert.hlsl b/engine/ui/shaders/rect.vert.hlsl new file mode 100644 index 0000000..3b77234 --- /dev/null +++ b/engine/ui/shaders/rect.vert.hlsl @@ -0,0 +1,52 @@ + +#include "rect_shared.hlsli" + +struct Input +{ + float3 Position : TEXCOORD0; + float3 Normal : TEXCOORD1; + float4 Color : TEXCOORD2; + float2 UV : TEXCOORD3; + uint Bones : TEXCOORD4; + uint weights : TEXCOORD5; + + uint Instance : SV_InstanceID; +}; + +struct VertexOut +{ + float4 Color : TEXCOORD0; + float2 UV : TEXCOORD1; + float2 pixelPosition: TEXCOORD2; + uint Instance: TEXCOORD3; + + float4 Position : SV_Position; +}; + +VertexOut main(Input v) +{ + VertexOut o; + + Scene s = scene[v.Instance]; + + float2 finalSize = (s.imageSize / Extents); + //float zLevel = objectBuffer.objects[gl_BaseInstance].zLevel; + + float2 finalPos = ((s.imagePosition / Extents) * 2 - 1) - s.anchorPoint * finalSize * s.scale; + + o.Color = s.baseColor; + + float4 fp = float4( + finalPos.x + ( v.Position.x * finalSize.x * s.scale.x), + finalPos.y + (-v.Position.y * finalSize.y * s.scale.y), + v.Position.z, 1.0 + ); + + o.Position = fp; + o.UV = float2(1 - v.UV.x, v.UV.y); + o.pixelPosition = (v.Position.xy - s.anchorPoint) / 2 * s.imageSize; + o.pixelPosition.y = s.imageSize.y - o.pixelPosition.y; + o.Instance = v.Instance; + + return o; +} diff --git a/engine/ui/shaders/rect.vert.json b/engine/ui/shaders/rect.vert.json new file mode 100644 index 0000000..0b736a6 --- /dev/null +++ b/engine/ui/shaders/rect.vert.json @@ -0,0 +1,145 @@ +{ + "entryPoints" : [ + { + "name" : "main", + "mode" : "vert" + } + ], + "types" : { + "_11" : { + "name" : "Scene", + "members" : [ + { + "name" : "imagePosition", + "type" : "vec2", + "offset" : 0 + }, + { + "name" : "imageSize", + "type" : "vec2", + "offset" : 8 + }, + { + "name" : "anchorPoint", + "type" : "vec2", + "offset" : 16 + }, + { + "name" : "scale", + "type" : "vec2", + "offset" : 24 + }, + { + "name" : "alpha", + "type" : "float", + "offset" : 32 + }, + { + "name" : "borderWidth", + "type" : "float", + "offset" : 36 + }, + { + "name" : "flags", + "type" : "uint", + "offset" : 40 + }, + { + "name" : "baseColor", + "type" : "vec4", + "offset" : 48 + }, + { + "name" : "rounding", + "type" : "vec4", + "offset" : 64 + }, + { + "name" : "edgeColor", + "type" : "vec4", + "offset" : 80 + } + ] + }, + "_10" : { + "name" : "type.StructuredBuffer.Scene", + "members" : [ + { + "name" : "_m0", + "type" : "_11", + "array" : [ + 0 + ], + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 96 + } + ] + }, + "_13" : { + "name" : "type.Uniforms", + "members" : [ + { + "name" : "Extents", + "type" : "vec2", + "offset" : 0 + } + ] + } + }, + "inputs" : [ + { + "type" : "vec3", + "name" : "in.var.TEXCOORD0", + "location" : 0 + }, + { + "type" : "vec2", + "name" : "in.var.TEXCOORD3", + "location" : 3 + } + ], + "outputs" : [ + { + "type" : "vec4", + "name" : "out.var.TEXCOORD0", + "location" : 0 + }, + { + "type" : "vec2", + "name" : "out.var.TEXCOORD1", + "location" : 1 + }, + { + "type" : "vec2", + "name" : "out.var.TEXCOORD2", + "location" : 2 + }, + { + "type" : "uint", + "name" : "out.var.TEXCOORD3", + "location" : 3 + } + ], + "ssbos" : [ + { + "type" : "_10", + "name" : "scene", + "readonly" : true, + "block_size" : 0, + "set" : 0, + "binding" : 0 + } + ], + "ubos" : [ + { + "type" : "_13", + "name" : "type.Uniforms", + "block_size" : 8, + "set" : 1, + "binding" : 0 + } + ] +} \ No newline at end of file diff --git a/engine/ui/shaders/rect_shared.hlsli b/engine/ui/shaders/rect_shared.hlsli new file mode 100644 index 0000000..3b810ac --- /dev/null +++ b/engine/ui/shaders/rect_shared.hlsli @@ -0,0 +1,20 @@ +struct Scene +{ + float2 imagePosition; + float2 imageSize; + float2 anchorPoint; + float2 scale; + float alpha; + float borderWidth; + uint flags; + float4 baseColor; + float4 rounding; + float4 edgeColor; +}; + +StructuredBuffer scene: register(t0, space0); + +cbuffer Uniforms : register(b0, space1) +{ + float2 Extents; +}; diff --git a/engine/ui/shaders/text.frag.hlsl b/engine/ui/shaders/text.frag.hlsl new file mode 100644 index 0000000..1c89153 --- /dev/null +++ b/engine/ui/shaders/text.frag.hlsl @@ -0,0 +1,73 @@ + +#include "text_shared.hlsli" +#include "fragmentHelpers.hlsli" + +Texture2D Texture0 : register(t0, space2); +SamplerState Sampler0 : register(s0, space2); + +float4 main( + float4 Color : TEXCOORD0, + float2 UV : TEXCOORD1, + float2 pixelPosition: TEXCOORD2, + uint Instance: TEXCOORD3 +) :SV_Target0 +{ + float4 o; + + // vec4 tex = texture(tex, texCoord); + + float4 tex = Texture0.Sample(Sampler0, UV); + uint isSdf = fontBuffer[Instance].isSdf; + float2 position = fontBuffer[Instance].position; + float2 size = fontBuffer[Instance].size; + + if(!scissor(pixelPosition, position, size)) + { + discard; + } + + if(isSdf == 1) + { + float dist = tex.r; + float width = fwidth(dist); + float4 textColor = clamp(Color, 0.0, 1.0); + float outerEdge = 1.0f - (120.0f / 255.0f); + + float alpha = contour(dist, outerEdge, width); + + float dscale = 0.354; // half of 1/sqrt2; you can play with this + float2 uv = UV.xy; + float2 duv = dscale * (ddx(uv) + ddy(uv)); + float4 box = float4(uv - duv, uv + duv); + + float asum = getSample(Texture0, Sampler0, box.xy, outerEdge, width) + + getSample(Texture0, Sampler0, box.zw, outerEdge, width) + + getSample(Texture0, Sampler0, box.xw, outerEdge, width) + + getSample(Texture0, Sampler0, box.zy, outerEdge, width); + + // weighted average, with 4 extra points having 0.5 weight each, + // so 1 + 0.5*4 = 3 is the divisor + alpha = (alpha + 0.5 * asum) / 3.0; + + textColor = float4(Color.xyz, alpha);//textColor.* alpha); + textColor.xyz = pow(textColor.xyz, 2.2); // gamma correction + + // Premultiplied alpha output. + o = textColor; + } + else { + float alpha = 1.0; + float gray = dot(Color.xyz, float3(0.2126, 0.7152, 0.0722)); + o = float4(Color.xyz , pow(tex.x / gray, 1/(2.2)) );//textColor.* alpha); + //outFragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + + /* debug test. + if(!rect(pixelPosition, position, size)) + { + outFragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + */ + + return o; +} diff --git a/engine/ui/shaders/text.frag.json b/engine/ui/shaders/text.frag.json new file mode 100644 index 0000000..221c949 --- /dev/null +++ b/engine/ui/shaders/text.frag.json @@ -0,0 +1,112 @@ +{ + "entryPoints" : [ + { + "name" : "main", + "mode" : "frag" + } + ], + "types" : { + "_9" : { + "name" : "FontInfo", + "members" : [ + { + "name" : "position", + "type" : "vec2", + "offset" : 0 + }, + { + "name" : "size", + "type" : "float", + "offset" : 8 + }, + { + "name" : "isSdf", + "type" : "uint", + "offset" : 12 + }, + { + "name" : "pad0", + "type" : "uint", + "offset" : 16 + }, + { + "name" : "pad2", + "type" : "vec2", + "offset" : 20 + } + ] + }, + "_8" : { + "name" : "type.StructuredBuffer.FontInfo", + "members" : [ + { + "name" : "_m0", + "type" : "_9", + "array" : [ + 0 + ], + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 32 + } + ] + } + }, + "inputs" : [ + { + "type" : "vec4", + "name" : "in.var.TEXCOORD0", + "location" : 0 + }, + { + "type" : "vec2", + "name" : "in.var.TEXCOORD1", + "location" : 1 + }, + { + "type" : "vec2", + "name" : "in.var.TEXCOORD2", + "location" : 2 + }, + { + "type" : "uint", + "name" : "in.var.TEXCOORD3", + "location" : 3 + } + ], + "outputs" : [ + { + "type" : "vec4", + "name" : "out.var.SV_Target0", + "location" : 0 + } + ], + "separate_images" : [ + { + "type" : "texture2D", + "name" : "Texture0", + "set" : 2, + "binding" : 0 + } + ], + "separate_samplers" : [ + { + "type" : "sampler", + "name" : "Sampler0", + "set" : 2, + "binding" : 0 + } + ], + "ssbos" : [ + { + "type" : "_8", + "name" : "fontBuffer", + "readonly" : true, + "block_size" : 0, + "set" : 0, + "binding" : 0 + } + ] +} \ No newline at end of file diff --git a/engine/ui/shaders/text.vert.hlsl b/engine/ui/shaders/text.vert.hlsl new file mode 100644 index 0000000..2455f28 --- /dev/null +++ b/engine/ui/shaders/text.vert.hlsl @@ -0,0 +1,42 @@ + +#include "text_shared.hlsli" + +struct VSOut +{ + float4 Color : TEXCOORD0; + float2 UV : TEXCOORD1; + float2 pixelPosition: TEXCOORD2; + uint Instance: TEXCOORD3; + + float4 Position : SV_Position; +}; + +struct Input +{ + float3 Position : TEXCOORD0; + float3 Normal : TEXCOORD1; + float4 Color : TEXCOORD2; + float2 UV : TEXCOORD3; + uint Bones : TEXCOORD4; + uint weights : TEXCOORD5; + + uint Instance : SV_InstanceID; +}; + +VSOut main(Input v) +{ + FontInfo s = fontBuffer[v.Instance]; + VSOut o; + + float2 t = v.Position.xy + s.position; + o.pixelPosition = t; + + //gl_Position = vec4(( (v.Position.xy + pos) / PushConstants.extent) * 2 + vec2(-1.0f, -1.0f), v.Position.z, 1.0); + o.Position = float4((t / Extents) * 2 + float2(-1.0f, -1.0f), v.Position.z, 1.0); + + o.UV = v.UV; + o.Color = v.Color; + o.Instance = v.Instance; + + return o; +} diff --git a/engine/ui/shaders/text.vert.json b/engine/ui/shaders/text.vert.json new file mode 100644 index 0000000..64e5405 --- /dev/null +++ b/engine/ui/shaders/text.vert.json @@ -0,0 +1,125 @@ +{ + "entryPoints" : [ + { + "name" : "main", + "mode" : "vert" + } + ], + "types" : { + "_12" : { + "name" : "FontInfo", + "members" : [ + { + "name" : "position", + "type" : "vec2", + "offset" : 0 + }, + { + "name" : "size", + "type" : "float", + "offset" : 8 + }, + { + "name" : "isSdf", + "type" : "uint", + "offset" : 12 + }, + { + "name" : "pad0", + "type" : "uint", + "offset" : 16 + }, + { + "name" : "pad2", + "type" : "vec2", + "offset" : 20 + } + ] + }, + "_11" : { + "name" : "type.StructuredBuffer.FontInfo", + "members" : [ + { + "name" : "_m0", + "type" : "_12", + "array" : [ + 0 + ], + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 32 + } + ] + }, + "_14" : { + "name" : "type.Uniforms", + "members" : [ + { + "name" : "Extents", + "type" : "vec2", + "offset" : 0 + } + ] + } + }, + "inputs" : [ + { + "type" : "vec3", + "name" : "in.var.TEXCOORD0", + "location" : 0 + }, + { + "type" : "vec4", + "name" : "in.var.TEXCOORD2", + "location" : 2 + }, + { + "type" : "vec2", + "name" : "in.var.TEXCOORD3", + "location" : 3 + } + ], + "outputs" : [ + { + "type" : "vec4", + "name" : "out.var.TEXCOORD0", + "location" : 0 + }, + { + "type" : "vec2", + "name" : "out.var.TEXCOORD1", + "location" : 1 + }, + { + "type" : "vec2", + "name" : "out.var.TEXCOORD2", + "location" : 2 + }, + { + "type" : "uint", + "name" : "out.var.TEXCOORD3", + "location" : 3 + } + ], + "ssbos" : [ + { + "type" : "_11", + "name" : "fontBuffer", + "readonly" : true, + "block_size" : 0, + "set" : 0, + "binding" : 0 + } + ], + "ubos" : [ + { + "type" : "_14", + "name" : "type.Uniforms", + "block_size" : 8, + "set" : 1, + "binding" : 0 + } + ] +} \ No newline at end of file diff --git a/engine/ui/shaders/text_shared.hlsli b/engine/ui/shaders/text_shared.hlsli new file mode 100644 index 0000000..e7f37c5 --- /dev/null +++ b/engine/ui/shaders/text_shared.hlsli @@ -0,0 +1,14 @@ +struct FontInfo { + float2 position; // 8 bytes alignment 0 + float size; // 8 bytes alignment 8 + uint isSdf; // 4 bytes 16 + uint pad0; // 4 bytes + float2 pad2; // 8 bytes +}; + +StructuredBuffer fontBuffer: register(t0, space0); + +cbuffer Uniforms : register(b0, space1) +{ + float2 Extents; +}; diff --git a/engine/ui/src/sgpu/embedded/quad.obj b/engine/ui/src/sgpu/embedded/quad.obj new file mode 100644 index 0000000..d95bad4 --- /dev/null +++ b/engine/ui/src/sgpu/embedded/quad.obj @@ -0,0 +1,14 @@ +# Blender 4.4.3 +# www.blender.org +o Plane +v -1.000000 1.000000 0.000000 +v 1.000000 1.000000 0.000000 +v -1.000000 -1.000000 0.000000 +v 1.000000 -1.000000 0.000000 +vn 0.0000 1.0000 0.0000 +vt 0.000000 0.000000 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +s 0 +f 1/1/1 2/2/1 4/3/1 3/4/1 diff --git a/engine/ui/src/sgpu/papyrusSgpu.zig b/engine/ui/src/sgpu/papyrusSgpu.zig new file mode 100644 index 0000000..837f52f --- /dev/null +++ b/engine/ui/src/sgpu/papyrusSgpu.zig @@ -0,0 +1,115 @@ +pub const papyrus = @import("papyrus"); +const core = @import("core"); +const rend = @import("rend"); +const std = @import("std"); +const sdl = @import("sdl3"); +const gpu = sdl.gpu; + +allocator: std.mem.Allocator, +runtime: *papyrus.PapyrusRuntime, +screenContext: *papyrus.Context, + +quadMesh: ?rend.IndexedMesh = null, +quadMeshName: core.Name, + +stringArena: std.heap.ArenaAllocator, +drawList: papyrus.DrawList, +first: bool = true, + +rectPipeline: *gpu.GPUGraphicsPipeline = undefined, +// textPipeline: *gpu.GPUGraphicsPipeline = undefined, + +pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + +pub fn create(allocator: std.mem.Allocator) !*@This() { + const self: *@This() = try allocator.create(@This()); + core.engine_logs("UI module started"); + + self.* = .{ + .allocator = allocator, + .screenContext = undefined, + .runtime = try papyrus.PapyrusRuntime.create(allocator), + .stringArena = std.heap.ArenaAllocator.init(allocator), + .quadMeshName = core.MakeName("m_screenPlane"), + .drawList = papyrus.DrawList.init(allocator), + }; + + self.screenContext = try self.runtime.addContext(); + + return self; +} + +pub fn setup(self: *@This()) !void { + core.graphics_log("imgui startup", .{}); + try rend.registerRendererObject(@This(), self); +} + +pub fn destroy(self: *@This()) void { + self.screenContext.destroy(); + self.runtime.destroy(); + self.allocator.destroy(self); +} + +pub fn createTextPipeline() !void {} + +pub fn createRectPipeline(self: *@This()) !void { + const ctx = rend.context(); + const vertex = try ctx.loadShader("rect.vert", rect_vert.LoadArgs); + const fragment = try ctx.loadShader("rect.frag", rect_frag.LoadArgs); + + var pci = std.mem.zeroes(gpu.GPUGraphicsPipelineCreateInfo); + pci.vertex_shader = vertex; + pci.fragment_shader = fragment; + + var attributes = try ctx.generateVertexAttributeList(); + defer attributes.deinit(); + + pci.vertex_input_state = .{ + .num_vertex_buffers = 1, + .vertex_buffer_descriptions = &[_]gpu.GPUVertexBufferDescription{ + .{ .slot = 0, .pitch = @sizeOf(rend.MeshVertex), .input_rate = .vertexinputrateVertex, .instance_step_rate = 0 }, + }, + .num_vertex_attributes = @intCast(attributes.items.len), + .vertex_attributes = @ptrCast(attributes.items.ptr), + }; + + pci.target_info.num_color_targets = 1; + pci.target_info.color_target_descriptions = &[_]gpu.GPUColorTargetDescription{ + .{ + .format = ctx.swapchainTargetFormat, + .blend_state = std.mem.zeroes(gpu.GPUColorTargetBlendState), + }, + }; + + pci.rasterizer_state.fill_mode = .fillmodeFill; + self.rectPipeline = ctx.device.createGPUGraphicsPipeline(&pci); +} + +pub fn postRender(p: *anyopaque, cmd: *gpu.GPUCommandBuffer) void { + const self: *@This() = @ptrCast(@alignCast(p)); + + if (self.quadMesh == null) { + self.quadMesh = rend.getMeshByName(&self.quadMeshName); + } + + self.drawToTarget(self.screenContext, rend.context().state.swapchainTargetTexture.?); + + _ = cmd; +} + +pub fn drawToTarget(self: *@This(), ctx: *papyrus.Context, targetTexture: *gpu.GPUTexture) void { + _ = targetTexture; + + ctx.makeDrawList(&self.drawList, &self.stringArena) catch return; + + if (self.first) { + self.first = false; + + for (self.drawList.items) |item| { + core.engine_log("{any}", .{item}); + } + } +} + +pub const rect_frag = @import("rect.frag"); +pub const rect_vert = @import("rect.vert"); diff --git a/engine/ui/src/ui.zig b/engine/ui/src/ui.zig new file mode 100644 index 0000000..e9bf207 --- /dev/null +++ b/engine/ui/src/ui.zig @@ -0,0 +1,38 @@ +const std = @import("std"); +pub const core = @import("core"); +pub const api = @import("cimgui"); +const rend = @import("rend"); + +pub const papyrus = @import("papyrus"); + +pub const Module: core.ModuleDescription = .{ + .name = "ui", + .enabledByDefault = true, +}; + +pub const PapyrusIntegration = @import("sgpu/papyrusSgpu.zig"); + +var gIntegration: *PapyrusIntegration = undefined; + +pub fn start_module(comptime programSpec: anytype, args: anytype, allocator: std.mem.Allocator) !void { + _ = args; + _ = programSpec; + + gIntegration = try PapyrusIntegration.create(allocator); + try gIntegration.setup(); + // gImgui = try rend.createRendererObject(Impl); + // try gImgui.setup(); +} + +// gets the main context under gIntegration +pub fn context() *papyrus.Context { + return gIntegration.screenContext; +} + +pub fn runtime() *PapyrusIntegration { + return gIntegration; +} + +pub fn shutdown_module(allocator: std.mem.Allocator) void { + _ = allocator; +} diff --git a/engine/ui/tests/test.zig b/engine/ui/tests/test.zig new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/engine/ui/tests/test.zig @@ -0,0 +1 @@ + diff --git a/engine/ui/tests/tests.zig b/engine/ui/tests/tests.zig new file mode 100644 index 0000000..ccc9e79 --- /dev/null +++ b/engine/ui/tests/tests.zig @@ -0,0 +1,7 @@ +const ui = @import("ui"); +const std = @import("std"); + +test "lmfao" { + std.testing.refAllDecls(ui.PapyrusIntegration); + std.debug.print("ref all decls", .{}); +} diff --git a/projects/content/_shaders/dxil/meshes.vert.dxil b/projects/content/_shaders/dxil/meshes.vert.dxil index 3e1902c54dccac8ee0029988a0370893601452d8..d8cdacf5ac7538477a724b3c2a94afcff11182e9 100644 GIT binary patch delta 1769 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 K4D-M<2mLoHz{=17 literal 0 HcmV?d00001 diff --git a/projects/content/_shaders/dxil/rect.vert.dxil b/projects/content/_shaders/dxil/rect.vert.dxil new file mode 100644 index 0000000000000000000000000000000000000000..1bc9fecd10a26390540e13ceb4816eb7ed4d708d GIT binary patch literal 5060 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 r=v7Il4uczAvnqVd=gLH|UYP*A@l;F979VEBXHG literal 0 HcmV?d00001 diff --git a/projects/content/_shaders/dxil/text.frag.dxil b/projects/content/_shaders/dxil/text.frag.dxil new file mode 100644 index 0000000000000000000000000000000000000000..a6e91a84b2596eac313bd72c3f0ae849909e02d3 GIT binary patch literal 5952 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 +#include + +using namespace metal; + +struct Scene +{ + float2 imagePosition; + float2 _imageSize; + float2 anchorPoint; + float2 scale; + float alpha; + float borderWidth; + uint flags; + float4 baseColor; + float4 rounding; + float4 edgeColor; +}; + +struct type_StructuredBuffer_Scene +{ + Scene _m0[1]; +}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD0 [[user(locn0)]]; + float2 in_var_TEXCOORD1 [[user(locn1)]]; + float2 in_var_TEXCOORD2 [[user(locn2)]]; + uint in_var_TEXCOORD3 [[user(locn3)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_Scene& scene [[buffer(4294967295)]], texture2d Texture0 [[texture(0)]], sampler Sampler0 [[sampler(0)]]) +{ + main0_out out = {}; + bool _73 = in.in_var_TEXCOORD2.x < scene._m0[in.in_var_TEXCOORD3].rounding.x; + bool _80; + if (_73) + { + _80 = in.in_var_TEXCOORD2.y < scene._m0[in.in_var_TEXCOORD3].rounding.y; + } + else + { + _80 = false; + } + float _97; + float3 _98; + if (_80) + { + float _84 = distance(in.in_var_TEXCOORD2, float2(scene._m0[in.in_var_TEXCOORD3].rounding.x)); + float _95; + float3 _96; + if (_84 > scene._m0[in.in_var_TEXCOORD3].rounding.x) + { + discard_fragment(); + } + else + { + if (abs(_84 - scene._m0[in.in_var_TEXCOORD3].rounding.x) < 1.0) + { + _95 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w; + _96 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz; + } + else + { + _95 = scene._m0[in.in_var_TEXCOORD3].alpha; + _96 = in.in_var_TEXCOORD0.xyz; + } + } + _97 = _95; + _98 = _96; + } + else + { + _97 = scene._m0[in.in_var_TEXCOORD3].alpha; + _98 = in.in_var_TEXCOORD0.xyz; + } + float _101 = scene._m0[in.in_var_TEXCOORD3]._imageSize.x - scene._m0[in.in_var_TEXCOORD3].rounding.y; + bool _108; + if (in.in_var_TEXCOORD2.x > _101) + { + _108 = in.in_var_TEXCOORD2.y < scene._m0[in.in_var_TEXCOORD3].rounding.y; + } + else + { + _108 = false; + } + float _125; + float3 _126; + if (_108) + { + float _112 = distance(in.in_var_TEXCOORD2, float2(_101, scene._m0[in.in_var_TEXCOORD3].rounding.y)); + float _123; + float3 _124; + if (_112 > scene._m0[in.in_var_TEXCOORD3].rounding.y) + { + discard_fragment(); + } + else + { + if (abs(_112 - scene._m0[in.in_var_TEXCOORD3].rounding.y) < 1.0) + { + _123 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w; + _124 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz; + } + else + { + _123 = _97; + _124 = _98; + } + } + _125 = _123; + _126 = _124; + } + else + { + _125 = _97; + _126 = _98; + } + bool _134; + if (_73) + { + _134 = in.in_var_TEXCOORD2.y > (scene._m0[in.in_var_TEXCOORD3]._imageSize.y - scene._m0[in.in_var_TEXCOORD3].rounding.y); + } + else + { + _134 = false; + } + float _153; + float3 _154; + if (_134) + { + float _140 = distance(in.in_var_TEXCOORD2, float2(scene._m0[in.in_var_TEXCOORD3].rounding.x, scene._m0[in.in_var_TEXCOORD3]._imageSize.y - scene._m0[in.in_var_TEXCOORD3].rounding.y)); + float _151; + float3 _152; + if (_140 > scene._m0[in.in_var_TEXCOORD3].rounding.y) + { + discard_fragment(); + } + else + { + if (abs(_140 - scene._m0[in.in_var_TEXCOORD3].rounding.y) < 1.0) + { + _151 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w; + _152 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz; + } + else + { + _151 = _125; + _152 = _126; + } + } + _153 = _151; + _154 = _152; + } + else + { + _153 = _125; + _154 = _126; + } + bool _165; + if (in.in_var_TEXCOORD2.x > (scene._m0[in.in_var_TEXCOORD3]._imageSize.x - scene._m0[in.in_var_TEXCOORD3].rounding.w)) + { + _165 = (scene._m0[in.in_var_TEXCOORD3]._imageSize.y - in.in_var_TEXCOORD2.y) < scene._m0[in.in_var_TEXCOORD3].rounding.w; + } + else + { + _165 = false; + } + float _185; + float3 _186; + if (_165) + { + float _172 = distance(in.in_var_TEXCOORD2, float2(scene._m0[in.in_var_TEXCOORD3]._imageSize.x - scene._m0[in.in_var_TEXCOORD3].rounding.x, scene._m0[in.in_var_TEXCOORD3]._imageSize.y - scene._m0[in.in_var_TEXCOORD3].rounding.y)); + float _183; + float3 _184; + if (_172 > scene._m0[in.in_var_TEXCOORD3].rounding.y) + { + discard_fragment(); + } + else + { + if (abs(_172 - scene._m0[in.in_var_TEXCOORD3].rounding.y) < 1.0) + { + _183 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w; + _184 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz; + } + else + { + _183 = _153; + _184 = _154; + } + } + _185 = _183; + _186 = _184; + } + else + { + _185 = _153; + _186 = _154; + } + bool _193; + if (!(in.in_var_TEXCOORD2.x < scene._m0[in.in_var_TEXCOORD3].borderWidth)) + { + _193 = in.in_var_TEXCOORD2.x > (scene._m0[in.in_var_TEXCOORD3]._imageSize.x - scene._m0[in.in_var_TEXCOORD3].borderWidth); + } + else + { + _193 = true; + } + bool _200; + if (!_193) + { + _200 = in.in_var_TEXCOORD2.y < scene._m0[in.in_var_TEXCOORD3].borderWidth; + } + else + { + _200 = true; + } + bool _209; + if (!_200) + { + _209 = in.in_var_TEXCOORD2.y > (scene._m0[in.in_var_TEXCOORD3]._imageSize.y - scene._m0[in.in_var_TEXCOORD3].borderWidth); + } + else + { + _209 = true; + } + float _214; + float3 _215; + if (_209) + { + _214 = scene._m0[in.in_var_TEXCOORD3].edgeColor.w; + _215 = scene._m0[in.in_var_TEXCOORD3].edgeColor.xyz; + } + else + { + _214 = _185; + _215 = _186; + } + float4 _241; + if ((scene._m0[in.in_var_TEXCOORD3].flags & 1u) > 0u) + { + float4 _229 = Texture0.sample(Sampler0, float2(in.in_var_TEXCOORD1.x, 1.0 - in.in_var_TEXCOORD1.y)); + _241 = float4(_229.xyz, _229.w * _214); + } + else + { + _241 = float4(powr(_215, float3(2.2000000476837158203125)), _214); + } + out.out_var_SV_Target0 = _241; + return out; +} + diff --git a/projects/content/_shaders/msl/rect.vert.msl b/projects/content/_shaders/msl/rect.vert.msl new file mode 100644 index 0000000..23538c3 --- /dev/null +++ b/projects/content/_shaders/msl/rect.vert.msl @@ -0,0 +1,59 @@ +#include +#include + +using namespace metal; + +struct Scene +{ + float2 imagePosition; + float2 _imageSize; + float2 anchorPoint; + float2 scale; + float alpha; + float borderWidth; + uint flags; + float4 baseColor; + float4 rounding; + float4 edgeColor; +}; + +struct type_StructuredBuffer_Scene +{ + Scene _m0[1]; +}; + +struct type_Uniforms +{ + float2 Extents; +}; + +struct main0_out +{ + float4 out_var_TEXCOORD0 [[user(locn0)]]; + float2 out_var_TEXCOORD1 [[user(locn1)]]; + float2 out_var_TEXCOORD2 [[user(locn2)]]; + uint out_var_TEXCOORD3 [[user(locn3)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float3 in_var_TEXCOORD0 [[attribute(0)]]; + float2 in_var_TEXCOORD3 [[attribute(3)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_Scene& scene [[buffer(1)]], uint gl_InstanceIndex [[instance_id]]) +{ + main0_out out = {}; + float2 _63 = scene._m0[gl_InstanceIndex]._imageSize / Uniforms.Extents; + float2 _69 = (((scene._m0[gl_InstanceIndex].imagePosition / Uniforms.Extents) * 2.0) - float2(1.0)) - ((scene._m0[gl_InstanceIndex].anchorPoint * _63) * scene._m0[gl_InstanceIndex].scale); + float2 _99 = ((in.in_var_TEXCOORD0.xy - scene._m0[gl_InstanceIndex].anchorPoint) * float2(0.5)) * scene._m0[gl_InstanceIndex]._imageSize; + _99.y = scene._m0[gl_InstanceIndex]._imageSize.y - _99.y; + out.out_var_TEXCOORD0 = scene._m0[gl_InstanceIndex].baseColor; + out.out_var_TEXCOORD1 = float2(1.0 - in.in_var_TEXCOORD3.x, in.in_var_TEXCOORD3.y); + out.out_var_TEXCOORD2 = _99; + out.out_var_TEXCOORD3 = gl_InstanceIndex; + out.gl_Position = float4(_69.x + ((in.in_var_TEXCOORD0.x * _63.x) * scene._m0[gl_InstanceIndex].scale.x), _69.y + (((-in.in_var_TEXCOORD0.y) * _63.y) * scene._m0[gl_InstanceIndex].scale.y), in.in_var_TEXCOORD0.z, 1.0); + return out; +} + diff --git a/projects/content/_shaders/msl/text.frag.msl b/projects/content/_shaders/msl/text.frag.msl new file mode 100644 index 0000000..2aec7dc --- /dev/null +++ b/projects/content/_shaders/msl/text.frag.msl @@ -0,0 +1,100 @@ +#include +#include + +using namespace metal; + +struct FontInfo +{ + float2 position; + float size; + uint isSdf; + uint pad0; + packed_float2 pad2; + char _m0_final_padding[4]; +}; + +struct type_StructuredBuffer_FontInfo +{ + FontInfo _m0[1]; +}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD0 [[user(locn0)]]; + float2 in_var_TEXCOORD1 [[user(locn1)]]; + float2 in_var_TEXCOORD2 [[user(locn2)]]; + uint in_var_TEXCOORD3 [[user(locn3)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_FontInfo& fontBuffer [[buffer(4294967295)]], texture2d Texture0 [[texture(0)]], sampler Sampler0 [[sampler(0)]]) +{ + main0_out out = {}; + float4 _64 = Texture0.sample(Sampler0, in.in_var_TEXCOORD1); + bool _99; + do + { + bool _81; + if (in.in_var_TEXCOORD2.x >= fontBuffer._m0[in.in_var_TEXCOORD3].position.x) + { + _81 = in.in_var_TEXCOORD2.x <= (fontBuffer._m0[in.in_var_TEXCOORD3].position.x + fontBuffer._m0[in.in_var_TEXCOORD3].size); + } + else + { + _81 = false; + } + bool _88; + if (_81) + { + _88 = in.in_var_TEXCOORD2.y >= fontBuffer._m0[in.in_var_TEXCOORD3].position.y; + } + else + { + _88 = false; + } + bool _96; + if (_88) + { + _96 = in.in_var_TEXCOORD2.y <= (fontBuffer._m0[in.in_var_TEXCOORD3].position.y + fontBuffer._m0[in.in_var_TEXCOORD3].size); + } + else + { + _96 = false; + } + if (_96) + { + _99 = true; + break; + } + _99 = false; + break; + } while(false); + if (!_99) + { + discard_fragment(); + } + float4 _170; + if (fontBuffer._m0[in.in_var_TEXCOORD3].isSdf == 1u) + { + float _107 = _64.x; + float _108 = fwidth(_107); + float _109 = 0.529411792755126953125 - _108; + float _110 = 0.529411792755126953125 + _108; + float2 _116 = (dfdx(in.in_var_TEXCOORD1) + dfdy(in.in_var_TEXCOORD1)) * 0.3540000021457672119140625; + float4 _123 = float4(in.in_var_TEXCOORD1 - _116, in.in_var_TEXCOORD1 + _116); + float4 _157 = float4(in.in_var_TEXCOORD0.xyz, (fast::clamp(smoothstep(_109, _110, _107), 0.0, 1.0) + (0.5 * (((fast::clamp(smoothstep(_109, _110, Texture0.sample(Sampler0, _123.xy).x), 0.0, 1.0) + fast::clamp(smoothstep(_109, _110, Texture0.sample(Sampler0, _123.zw).x), 0.0, 1.0)) + fast::clamp(smoothstep(_109, _110, Texture0.sample(Sampler0, _123.xw).x), 0.0, 1.0)) + fast::clamp(smoothstep(_109, _110, Texture0.sample(Sampler0, _123.zy).x), 0.0, 1.0)))) * 0.3333333432674407958984375); + float3 _159 = powr(_157.xyz, float3(2.2000000476837158203125)); + _170 = float4(_159.x, _159.y, _159.z, _157.w); + } + else + { + _170 = float4(in.in_var_TEXCOORD0.xyz, powr(_64.x / dot(in.in_var_TEXCOORD0.xyz, float3(0.2125999927520751953125, 0.715200006961822509765625, 0.072200000286102294921875)), 0.4545454680919647216796875)); + } + out.out_var_SV_Target0 = _170; + return out; +} + diff --git a/projects/content/_shaders/msl/text.vert.msl b/projects/content/_shaders/msl/text.vert.msl new file mode 100644 index 0000000..090e1cc --- /dev/null +++ b/projects/content/_shaders/msl/text.vert.msl @@ -0,0 +1,53 @@ +#include +#include + +using namespace metal; + +struct FontInfo +{ + float2 position; + float size; + uint isSdf; + uint pad0; + packed_float2 pad2; + char _m0_final_padding[4]; +}; + +struct type_StructuredBuffer_FontInfo +{ + FontInfo _m0[1]; +}; + +struct type_Uniforms +{ + float2 Extents; +}; + +struct main0_out +{ + float4 out_var_TEXCOORD0 [[user(locn0)]]; + float2 out_var_TEXCOORD1 [[user(locn1)]]; + float2 out_var_TEXCOORD2 [[user(locn2)]]; + uint out_var_TEXCOORD3 [[user(locn3)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float3 in_var_TEXCOORD0 [[attribute(0)]]; + float4 in_var_TEXCOORD2 [[attribute(2)]]; + float2 in_var_TEXCOORD3 [[attribute(3)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniforms [[buffer(0)]], const device type_StructuredBuffer_FontInfo& fontBuffer [[buffer(1)]], uint gl_InstanceIndex [[instance_id]]) +{ + main0_out out = {}; + float2 _51 = in.in_var_TEXCOORD0.xy + fontBuffer._m0[gl_InstanceIndex].position; + out.out_var_TEXCOORD0 = in.in_var_TEXCOORD2; + out.out_var_TEXCOORD1 = in.in_var_TEXCOORD3; + out.out_var_TEXCOORD2 = _51; + out.out_var_TEXCOORD3 = gl_InstanceIndex; + out.gl_Position = float4(((_51 / Uniforms.Extents) * 2.0) + float2(-1.0), in.in_var_TEXCOORD0.z, 1.0); + return out; +} + diff --git a/projects/content/_shaders/spv/meshes.vert.spv b/projects/content/_shaders/spv/meshes.vert.spv index 954489e4a3d7042f5d11273a0c131d20dbe7a300..93410fd2a38cf660ec4c549d0bd8fbc7d093909a 100644 GIT binary patch delta 255 zcmXwzy$*sv5QIn2a298bKVV^Zg^8W9Q$YlJz!$Q#HKFw-?0f|u$<7(WZSrMyXK#1! zIeX7-7`O-+0GOb9*}J)=7-GfxKz5|X2n*_wY>C2qC+6}r@4dA50&0T@2{j{{*L(Gs zpdyDk8w6~b|Y^)$7BOe4qYoCUjT^3fY_FSg+T&HTLUpjd;$Y2 hgE)}30b*kyww|2Ism!YdWZ5w=GjM`rCQs#51_15x3JCxJ diff --git a/projects/content/_shaders/spv/rect.frag.spv b/projects/content/_shaders/spv/rect.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..7e0c98c94130dcf632369293b1f7e45c0e4618f6 GIT binary patch literal 6316 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 Jr`>K!{s&D*%S-?O literal 0 HcmV?d00001 diff --git a/projects/content/_shaders/spv/text.frag.spv b/projects/content/_shaders/spv/text.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..ecf737d7bdf8c1eeabeedd01649b717d68e0da42 GIT binary patch literal 4432 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