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 3e1902c..d8cdacf 100644 Binary files a/projects/content/_shaders/dxil/meshes.vert.dxil and b/projects/content/_shaders/dxil/meshes.vert.dxil differ diff --git a/projects/content/_shaders/dxil/rect.frag.dxil b/projects/content/_shaders/dxil/rect.frag.dxil new file mode 100644 index 0000000..443d97d Binary files /dev/null and b/projects/content/_shaders/dxil/rect.frag.dxil differ diff --git a/projects/content/_shaders/dxil/rect.vert.dxil b/projects/content/_shaders/dxil/rect.vert.dxil new file mode 100644 index 0000000..1bc9fec Binary files /dev/null and b/projects/content/_shaders/dxil/rect.vert.dxil differ diff --git a/projects/content/_shaders/dxil/text.frag.dxil b/projects/content/_shaders/dxil/text.frag.dxil new file mode 100644 index 0000000..a6e91a8 Binary files /dev/null and b/projects/content/_shaders/dxil/text.frag.dxil differ diff --git a/projects/content/_shaders/dxil/text.vert.dxil b/projects/content/_shaders/dxil/text.vert.dxil new file mode 100644 index 0000000..baacf9b Binary files /dev/null and b/projects/content/_shaders/dxil/text.vert.dxil differ diff --git a/projects/content/_shaders/msl/meshes.vert.msl b/projects/content/_shaders/msl/meshes.vert.msl index f98d6ae..43a33c8 100644 --- a/projects/content/_shaders/msl/meshes.vert.msl +++ b/projects/content/_shaders/msl/meshes.vert.msl @@ -48,7 +48,7 @@ vertex main0_out main0(main0_in in [[stage_in]], constant type_Uniforms& Uniform float4 _51 = scene._m0[gl_InstanceIndex].Model * _48; out.out_var_TEXCOORD0 = in.in_var_TEXCOORD3; out.out_var_TEXCOORD1 = _51.xyz; - out.out_var_TEXCOORD2 = in.in_var_TEXCOORD1; + out.out_var_TEXCOORD2 = (scene._m0[gl_InstanceIndex].Model * float4(in.in_var_TEXCOORD1, 1.0)).xyz; out.out_var_TEXCOORD3 = Uniforms.ShadowMapProjection * _51; out.out_var_TEXCOORD4 = gl_InstanceIndex; out.gl_Position = Uniforms.ViewProjection * (scene._m0[gl_InstanceIndex].Model * _48); diff --git a/projects/content/_shaders/msl/rect.frag.msl b/projects/content/_shaders/msl/rect.frag.msl new file mode 100644 index 0000000..e38b4ac --- /dev/null +++ b/projects/content/_shaders/msl/rect.frag.msl @@ -0,0 +1,259 @@ +#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 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 954489e..93410fd 100644 Binary files a/projects/content/_shaders/spv/meshes.vert.spv and b/projects/content/_shaders/spv/meshes.vert.spv differ diff --git a/projects/content/_shaders/spv/rect.frag.spv b/projects/content/_shaders/spv/rect.frag.spv new file mode 100644 index 0000000..7e0c98c Binary files /dev/null and b/projects/content/_shaders/spv/rect.frag.spv differ diff --git a/projects/content/_shaders/spv/rect.vert.spv b/projects/content/_shaders/spv/rect.vert.spv new file mode 100644 index 0000000..7fcf962 Binary files /dev/null and b/projects/content/_shaders/spv/rect.vert.spv differ diff --git a/projects/content/_shaders/spv/text.frag.spv b/projects/content/_shaders/spv/text.frag.spv new file mode 100644 index 0000000..ecf737d Binary files /dev/null and b/projects/content/_shaders/spv/text.frag.spv differ diff --git a/projects/content/_shaders/spv/text.vert.spv b/projects/content/_shaders/spv/text.vert.spv new file mode 100644 index 0000000..d51ea4c Binary files /dev/null and b/projects/content/_shaders/spv/text.vert.spv differ diff --git a/projects/sampleGame/main.zig b/projects/sampleGame/main.zig index 24428c6..5a3c0f0 100644 --- a/projects/sampleGame/main.zig +++ b/projects/sampleGame/main.zig @@ -110,6 +110,8 @@ pub fn prepare(self: *@This()) !void { try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas); try self.objectSpawner.addSpawnFunction("empire", @import("empire.zig")); + ui.context().drawDebug = true; + try assets.loadList(assetReferences); self.videoplayer = try VideoPlayer.create(self.allocator); try self.videoplayer.startPlayback("LAPWING2.ogv"); @@ -380,3 +382,4 @@ const ig = backlog.imgui.api; const rend = backlog.rend; const script = core.script; const tracy = core.tracy; +const ui = backlog.ui; diff --git a/tools/scripts/cookShaders.py b/tools/scripts/cookShaders.py index 0acc15f..ace7992 100644 --- a/tools/scripts/cookShaders.py +++ b/tools/scripts/cookShaders.py @@ -83,6 +83,8 @@ def cookList(inputFiles): outdir = os.path.join(cookedRoot, fmt[0]) for f in inputFiles: basefile = f[:-5] + if 'vert' not in basefile and '' + outfile = os.path.abspath(os.path.join(outdir, os.path.basename(basefile) + '.' + fmt[0] )) os.makedirs(os.path.dirname(outfile), exist_ok=True) cmd = [shadercross, f] + fmt[1] + [ '-o', outfile ]