From dd7323faf0b65b71b380fc2b05927608eda4c674 Mon Sep 17 00:00:00 2001 From: zivoy Date: Fri, 28 Jun 2024 17:13:31 -0400 Subject: [PATCH 01/44] changed signiture on extern funcs --- libs/zopenvr/src/common.zig | 11 +++++------ libs/zopenvr/src/openvr.zig | 14 +++++++------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index c6b856e6c..2497dd5cf 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -672,8 +672,9 @@ pub const InitErrorCode = enum(i32) { } }; -extern fn VR_GetVRInitErrorAsSymbol(InitErrorCode) callconv(.C) [*c]u8; -extern fn VR_GetVRInitErrorAsEnglishDescription(InitErrorCode) callconv(.C) [*c]u8; +extern "openvr_api" fn VR_GetVRInitErrorAsSymbol(InitErrorCode) callconv(.C) [*c]const u8; +extern "openvr_api" fn VR_GetVRInitErrorAsEnglishDescription(InitErrorCode) callconv(.C) [*c]const u8; +extern "openvr_api" fn VR_GetGenericInterface([*c]const u8, *InitErrorCode) callconv(.C) ?*isize; test "init error have english descriptions" { try std.testing.expectEqualStrings("No Error (0)", InitErrorCode.none.asEnglishDescription()); @@ -683,13 +684,11 @@ pub fn getFunctionTable(comptime T: type, comptime version: []const u8) InitErro const interface_name: [*c]const u8 = "FnTable:" ++ version; var init_error: InitErrorCode = .none; - const function_table: *T = @ptrCast(VR_GetGenericInterface(interface_name, &init_error)); + const function_table_ptr = VR_GetGenericInterface(interface_name, &init_error); try init_error.maybe(); - return function_table; + return @ptrCast(function_table_ptr.?); } -extern fn VR_GetGenericInterface([*c]const u8, *InitErrorCode) callconv(.C) *isize; - pub const Quad = extern struct { corners: [4]Vector3, }; diff --git a/libs/zopenvr/src/openvr.zig b/libs/zopenvr/src/openvr.zig index 0f7577574..23d38b3b0 100644 --- a/libs/zopenvr/src/openvr.zig +++ b/libs/zopenvr/src/openvr.zig @@ -6,8 +6,8 @@ const Self = @This(); pub fn init(application_type: ApplicationType) common.InitError!Self { var init_error: common.InitErrorCode = .none; - _ = VR_InitInternal(&init_error, application_type); - try init_error.maybe(); + _ = VR_InitInternal(&init_error, application_type) orelse + try init_error.maybe(); return .{}; } @@ -28,18 +28,18 @@ pub const ApplicationType = enum(i32) { room_view = 13, max = 14, }; -extern fn VR_InitInternal(*common.InitErrorCode, ApplicationType) callconv(.C) *isize; + +extern "openvr_api" fn VR_InitInternal(*common.InitErrorCode, ApplicationType) callconv(.C) ?*isize; +extern "openvr_api" fn VR_ShutdownInternal() callconv(.C) void; +extern "openvr_api" fn VR_IsHmdPresent() callconv(.C) bool; +extern "openvr_api" fn VR_IsRuntimeInstalled() callconv(.C) bool; pub fn deinit(_: Self) void { VR_ShutdownInternal(); } -extern fn VR_ShutdownInternal() callconv(.C) void; pub const isHmdPresent = VR_IsHmdPresent; -extern fn VR_IsHmdPresent() callconv(.C) bool; - pub const isRuntimeInstalled = VR_IsRuntimeInstalled; -extern fn VR_IsRuntimeInstalled() callconv(.C) bool; pub fn system(_: Self) common.InitError!System { return try System.init(); From 7f68f4d77d2489d188b7208b1eb8c1c3a2039099 Mon Sep 17 00:00:00 2001 From: zivoy Date: Fri, 28 Jun 2024 18:40:24 -0400 Subject: [PATCH 02/44] made example work --- libs/zopenvr/README.md | 13 ++++++++----- libs/zopenvr/build.zig | 7 ++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index 63c350bdd..9c66da3b0 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -18,15 +18,15 @@ pub fn build(b: *std.Build) !void { const exe = b.addExecutable(.{ ... }); const zopenvr = b.dependency("zopenvr", .{}); - const zopenvr_path = zopenvr.path("").getPath(b); - exe.root_module.addImport("zopenvr", zopenvr.module("zopenvr")); - try @import("zopenvr").addLibraryPathsTo(exe, zopenvr_path); + exe.linkLibC(); + @import("zopenvr").addLibraryPathsTo(exe); @import("zopenvr").linkOpenvr(exe); - try @import("zopenvr").installOpenvr(&exe.step, options.target.result, .bin, zopenvr_path); + @import("zopenvr").installOpenvr(&exe.step, exe.rootModuleTarget(), .bin); } ``` + Now in your code you may import and use `zopenvr`: @@ -42,7 +42,7 @@ pub fn main() !void { const system = try openvr.system(); - const name = try app.system.allocTrackedDevicePropertyString(allocator, OpenVR.hmd, .tracking_system_name); + const name = try system.allocTrackedDevicePropertyString(allocator, OpenVR.hmd, .tracking_system_name); defer allocator.free(name); ... @@ -76,3 +76,6 @@ pub fn main() !void { | SpatialAnchors | | | System | ✅ | | TrackedCamera | | + +## todo +generate bindings from original json diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index 0c84c5b54..ed15b1fa6 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -4,6 +4,7 @@ pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); + // todo move to options so that it wont require if not requested const zwin32 = b.dependency("zwin32", .{ .target = target, }); @@ -23,6 +24,7 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, }); + tests.linkLibC(); addLibraryPathsTo(tests); addRPathsTo(tests); linkOpenVR(tests); @@ -41,11 +43,6 @@ pub fn build(b: *std.Build) void { } } -// in future zig version e342433 -pub fn pathResolve(b: *std.Build, paths: []const []const u8) []u8 { - return std.fs.path.resolve(b.allocator, paths) catch @panic("OOM"); -} - pub fn addLibraryPathsTo(compile_step: *std.Build.Step.Compile) void { const b = compile_step.step.owner; const target = compile_step.rootModuleTarget(); From 52d90f2db8b8579d0db4ea0c161c9959f310c1d1 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 29 Jun 2024 16:21:14 -0400 Subject: [PATCH 03/44] refactored some stuff --- libs/zopenvr/README.md | 5 +- libs/zopenvr/build.zig | 147 +++++++++++++++++++---------------------- 2 files changed, 70 insertions(+), 82 deletions(-) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index 9c66da3b0..46a49b976 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -20,10 +20,9 @@ pub fn build(b: *std.Build) !void { const zopenvr = b.dependency("zopenvr", .{}); exe.root_module.addImport("zopenvr", zopenvr.module("zopenvr")); - exe.linkLibC(); @import("zopenvr").addLibraryPathsTo(exe); - @import("zopenvr").linkOpenvr(exe); - @import("zopenvr").installOpenvr(&exe.step, exe.rootModuleTarget(), .bin); + @import("zopenvr").linkOpenVR(exe); + @import("zopenvr").installOpenVR(&exe.step, exe.rootModuleTarget(), .bin); } ``` diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index ed15b1fa6..2555b02ac 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -8,13 +8,33 @@ pub fn build(b: *std.Build) void { const zwin32 = b.dependency("zwin32", .{ .target = target, }); - _ = b.addModule("root", .{ + const mod = b.addModule("root", .{ .root_source_file = b.path("src/openvr.zig"), .imports = &.{ .{ .name = "zwin32", .module = zwin32.module("root") }, }, + .target = target, + .optimize = optimize, }); + // if (!target.result.cpu.arch.isX86()) @panic("unsupported target architecture"); + + mod.link_libc = true; + // mod.addLibraryPath(b.path(switch (target.result.os.tag) { + // .windows => "libs/openvr/lib/win64", + // .linux => "libs/openvr/lib/linux64", + // else => @panic("unsupported target os"), + // })); + + // mod.addIncludePath(b.path("libs/openvr/headers")); + // mod.addRPath(b.path(switch (target.result.os.tag) { + // .windows => "libs/openvr/bin/win64", + // .linux => "libs/openvr/bin/linux64", + // else => @panic("unsupported target os"), + // })); + + // mod.linkSystemLibrary("openvr_api", .{ .needed = true }); + { const unit_tests = b.step("test", "Run zopenvr tests"); { @@ -24,7 +44,7 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, }); - tests.linkLibC(); + tests.root_module.addImport("openvr", mod); addLibraryPathsTo(tests); addRPathsTo(tests); linkOpenVR(tests); @@ -47,60 +67,43 @@ pub fn addLibraryPathsTo(compile_step: *std.Build.Step.Compile) void { const b = compile_step.step.owner; const target = compile_step.rootModuleTarget(); const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - switch (target.os.tag) { - .windows => { - if (target.cpu.arch.isX86()) { - compile_step.addLibraryPath(.{ - .cwd_relative = b.pathJoin( - &.{ source_path_prefix, "libs/openvr/lib/win64" }, - ), - }); - } - }, - .linux => { - if (target.cpu.arch.isX86()) { - compile_step.addLibraryPath(.{ - .cwd_relative = b.pathJoin( - &.{ source_path_prefix, "libs/openvr/lib/linux64" }, - ), - }); - } - }, - else => {}, - } + + if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + compile_step.addLibraryPath(.{ + .cwd_relative = b.pathJoin(&.{ + source_path_prefix, + switch (target.os.tag) { + .windows => "libs/openvr/lib/win64", + .linux => "libs/openvr/lib/linux64", + else => @panic("unsupported target os"), + }, + }), + }); } pub fn addRPathsTo(compile_step: *std.Build.Step.Compile) void { const b = compile_step.step.owner; const target = compile_step.rootModuleTarget(); const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - switch (target.os.tag) { - .windows => { - if (target.cpu.arch.isX86()) { - compile_step.addRPath(.{ - .cwd_relative = b.pathJoin( - &.{ source_path_prefix, "libs/openvr/bin/win64" }, - ), - }); - } - }, - .linux => { - if (target.cpu.arch.isX86()) { - compile_step.addRPath(.{ - .cwd_relative = b.pathJoin( - &.{ source_path_prefix, "libs/openvr/bin/linux64" }, - ), - }); - } - }, - else => {}, - } + + if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + compile_step.addRPath(.{ + .cwd_relative = b.pathJoin(&.{ + source_path_prefix, switch (target.os.tag) { + .windows => "libs/openvr/bin/win64", + .linux => "libs/openvr/bin/linux64", + else => @panic("unsupported target os"), + }, + }), + }); } pub fn linkOpenVR(compile_step: *std.Build.Step.Compile) void { switch (compile_step.rootModuleTarget().os.tag) { - .windows, .linux => { - compile_step.linkSystemLibrary("openvr_api"); + .windows => compile_step.linkSystemLibrary("openvr_api"), + .linux => { + compile_step.root_module.linkSystemLibrary("openvr_api", .{ .needed = true }); + compile_step.root_module.addRPathSpecial("$ORIGIN"); }, else => {}, } @@ -111,39 +114,25 @@ pub fn installOpenVR( target: std.Target, install_dir: std.Build.InstallDir, ) void { + if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + const b = step.owner; const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - switch (target.os.tag) { - .windows => { - if (target.cpu.arch.isX86()) { - step.dependOn( - &b.addInstallFileWithDir( - .{ - .cwd_relative = b.pathJoin( - &.{ source_path_prefix, "libs/openvr/bin/win64/openvr_api.dll" }, - ), - }, - install_dir, - "openvr_api.dll", - ).step, - ); - } - }, - .linux => { - if (target.cpu.arch.isX86()) { - step.dependOn( - &b.addInstallFileWithDir( - .{ - .cwd_relative = b.pathJoin( - &.{ source_path_prefix, "libs/openvr/bin/linux64/libopenvr_api.so" }, - ), - }, - install_dir, - "libopenvr_api.so.0", - ).step, - ); - } - }, - else => {}, - } + step.dependOn(switch (target.os.tag) { + .windows => &b.addInstallFileWithDir( + .{ + .cwd_relative = b.pathJoin(&.{ source_path_prefix, "libs/openvr/bin/win64/openvr_api.dll" }), + }, + install_dir, + "openvr_api.dll", + ).step, + .linux => &b.addInstallFileWithDir( + .{ + .cwd_relative = b.pathJoin(&.{ source_path_prefix, "libs/openvr/bin/linux64/libopenvr_api.so" }), + }, + install_dir, + "libopenvr_api.so", + ).step, + else => @panic("unsupported target os"), + }); } From ba9c3125ed61fe253a66edad6ab08ad86bb5306e Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 29 Jun 2024 20:20:43 -0400 Subject: [PATCH 04/44] add lazy render modules --- libs/zopenvr/README.md | 18 +++++++++++++ libs/zopenvr/build.zig | 48 +++++++++++++++------------------ libs/zopenvr/build.zig.zon | 5 +++- libs/zopenvr/src/common.zig | 8 ++++-- samples/openvr_test/build.zig | 1 + samples/simple_openvr/build.zig | 1 + 6 files changed, 52 insertions(+), 29 deletions(-) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index 46a49b976..97cd3228e 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -48,6 +48,13 @@ pub fn main() !void { } ``` +For better types on render structs enable the corrosponding options when importing the dependancy and make sure that the lib is present in the libs folder +```zig + const zopenvr = b.dependency("zopenvr", .{ + .d3d12 = true, // requires zwin32 + }); +``` + ## Implementation progress | Interface | Status | @@ -76,5 +83,16 @@ pub fn main() !void { | System | ✅ | | TrackedCamera | | +### Compositor supported renderers +| Renderer | Handle type | Zig handle name | Support | +|--------------------|-----------------------|---------------------------------|:-------:| +| DirectX 11 (d3d11) | ID3D11Texture2D | zwin32.d3d11.ITexture2D | | +| OpenGL | | | | +| Vulkan | VRVulkanTextureData_t | | | +| IOSurface | | | | +| DirectX 12 (d3d12) | D3D12TextureData_t | zopenvr.common.D3D12TextureData | ✅ | +| DXGI | | | | +| Metal | | | | + ## todo generate bindings from original json diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index 2555b02ac..95514117e 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -4,36 +4,32 @@ pub fn build(b: *std.Build) void { const optimize = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); - // todo move to options so that it wont require if not requested - const zwin32 = b.dependency("zwin32", .{ - .target = target, - }); const mod = b.addModule("root", .{ .root_source_file = b.path("src/openvr.zig"), - .imports = &.{ - .{ .name = "zwin32", .module = zwin32.module("root") }, - }, .target = target, .optimize = optimize, + .link_libc = true, }); - // if (!target.result.cpu.arch.isX86()) @panic("unsupported target architecture"); - - mod.link_libc = true; - // mod.addLibraryPath(b.path(switch (target.result.os.tag) { - // .windows => "libs/openvr/lib/win64", - // .linux => "libs/openvr/lib/linux64", - // else => @panic("unsupported target os"), - // })); - - // mod.addIncludePath(b.path("libs/openvr/headers")); - // mod.addRPath(b.path(switch (target.result.os.tag) { - // .windows => "libs/openvr/bin/win64", - // .linux => "libs/openvr/bin/linux64", - // else => @panic("unsupported target os"), - // })); + var backends = struct { + d3d12: bool = false, + // valken: bool = false, + // opengl: bool = false, + }{}; + + // b.systemIntegrationOption("d3d12", .{}) + if (b.option(bool, "d3d12", "Enable Direct3D 12 backend") orelse false) { + backends.d3d12 = true; + if (b.lazyDependency("zwin32", .{ .target = target })) |zwin32| { + mod.addImport("zwin32", zwin32.module("root")); + } + } - // mod.linkSystemLibrary("openvr_api", .{ .needed = true }); + const options = b.addOptions(); + inline for (@typeInfo(@TypeOf(backends)).Struct.fields) |field| { + options.addOption(field.type, field.name, @field(backends, field.name)); + } + mod.addOptions("rendermodesConfig", options); { const unit_tests = b.step("test", "Run zopenvr tests"); @@ -68,7 +64,7 @@ pub fn addLibraryPathsTo(compile_step: *std.Build.Step.Compile) void { const target = compile_step.rootModuleTarget(); const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + if (target.cpu.arch != .x86_64) @panic("unsupported target architecture"); compile_step.addLibraryPath(.{ .cwd_relative = b.pathJoin(&.{ source_path_prefix, @@ -86,7 +82,7 @@ pub fn addRPathsTo(compile_step: *std.Build.Step.Compile) void { const target = compile_step.rootModuleTarget(); const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + if (target.cpu.arch != .x86_64) @panic("unsupported target architecture"); compile_step.addRPath(.{ .cwd_relative = b.pathJoin(&.{ source_path_prefix, switch (target.os.tag) { @@ -114,7 +110,7 @@ pub fn installOpenVR( target: std.Target, install_dir: std.Build.InstallDir, ) void { - if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + if (target.cpu.arch != .x86_64) @panic("unsupported target architecture"); const b = step.owner; const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; diff --git a/libs/zopenvr/build.zig.zon b/libs/zopenvr/build.zig.zon index 62fba8a68..e6355f7ac 100644 --- a/libs/zopenvr/build.zig.zon +++ b/libs/zopenvr/build.zig.zon @@ -9,6 +9,9 @@ "README.md", }, .dependencies = .{ - .zwin32 = .{ .path = "../zwin32" }, + .zwin32 = .{ + .path = "../zwin32", + .lazy = true, + }, }, } diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 2497dd5cf..ae68ab390 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -1,6 +1,10 @@ const std = @import("std"); -const zwin32 = @import("zwin32"); -const d3d12 = zwin32.d3d12; +const config = @import("rendermodesConfig"); + +const d3d12 = if (config.d3d12) @import("zwin32").d3d12 else struct { + ICommandQueue: type = anyopaque, + IResource: type = anyopaque, +}{}; const root = @This(); diff --git a/samples/openvr_test/build.zig b/samples/openvr_test/build.zig index 7dab43e7f..55e86ce07 100644 --- a/samples/openvr_test/build.zig +++ b/samples/openvr_test/build.zig @@ -42,6 +42,7 @@ pub fn build(b: *std.Build, options: Options) *std.Build.Step.Compile { const zopenvr = b.dependency("zopenvr", .{ .target = options.target, + .d3d12 = false, // -- optional, the d3d12 parts are unused here }); exe.root_module.addImport("zopenvr", zopenvr.module("root")); diff --git a/samples/simple_openvr/build.zig b/samples/simple_openvr/build.zig index d5c3b394a..4c1375f04 100644 --- a/samples/simple_openvr/build.zig +++ b/samples/simple_openvr/build.zig @@ -48,6 +48,7 @@ pub fn build(b: *std.Build, options: Options) *std.Build.Step.Compile { const zopenvr = b.dependency("zopenvr", .{ .target = options.target, + .d3d12 = true, }); exe.root_module.addImport("zopenvr", zopenvr.module("root")); From afb01904deee2b44db09d91c20212d090cf8141a Mon Sep 17 00:00:00 2001 From: zivoy Date: Sun, 30 Jun 2024 12:01:23 -0400 Subject: [PATCH 05/44] spell check and small error in readme --- libs/zopenvr/README.md | 4 ++-- libs/zopenvr/src/common.zig | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index 97cd3228e..0f6436d11 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -18,7 +18,7 @@ pub fn build(b: *std.Build) !void { const exe = b.addExecutable(.{ ... }); const zopenvr = b.dependency("zopenvr", .{}); - exe.root_module.addImport("zopenvr", zopenvr.module("zopenvr")); + exe.root_module.addImport("zopenvr", zopenvr.module("root")); @import("zopenvr").addLibraryPathsTo(exe); @import("zopenvr").linkOpenVR(exe); @@ -48,7 +48,7 @@ pub fn main() !void { } ``` -For better types on render structs enable the corrosponding options when importing the dependancy and make sure that the lib is present in the libs folder +For better types on render structs, enable the corresponding options when importing the dependency and ensure that the lib is present in the libs folder. ```zig const zopenvr = b.dependency("zopenvr", .{ .d3d12 = true, // requires zwin32 diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index ae68ab390..91d3c2800 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -2,9 +2,9 @@ const std = @import("std"); const config = @import("rendermodesConfig"); const d3d12 = if (config.d3d12) @import("zwin32").d3d12 else struct { - ICommandQueue: type = anyopaque, - IResource: type = anyopaque, -}{}; + pub const ICommandQueue = anyopaque; + pub const IResource = anyopaque; +}; const root = @This(); From 3e219d26d17244cac41e81934cead3ab697bf387 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sun, 30 Jun 2024 21:25:10 -0400 Subject: [PATCH 06/44] start of overlay implementation --- libs/zopenvr/src/common.zig | 264 +++++++++++++++++++++- libs/zopenvr/src/openvr.zig | 5 + libs/zopenvr/src/overlay.zig | 423 +++++++++++++++++++++++++++++++++++ 3 files changed, 687 insertions(+), 5 deletions(-) create mode 100644 libs/zopenvr/src/overlay.zig diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 91d3c2800..a4b63b60b 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -713,14 +713,17 @@ pub const Matrix44 = extern struct { m: [4][4]f32, }; +pub const Rect2 = extern struct { + top_left: Vector2, + bottom_right: Vector2, +}; + pub const TrackingUniverseOrigin = enum(i32) { seated = 0, standing = 1, raw_and_uncalibrated = 2, }; -pub const max_tracked_device_count: usize = 64; - pub const TrackingResult = enum(i32) { uninitialized = 1, calibrating_in_progress = 100, @@ -732,6 +735,9 @@ pub const TrackingResult = enum(i32) { pub const TrackedDeviceIndex = u32; pub const hmd: TrackedDeviceIndex = 0; +pub const max_tracked_device_count: usize = 64; +pub const other_tracked_device_index: TrackedDeviceIndex = 0xFFFFFFFE; +pub const invalid_tracked_device_index: TrackedDeviceIndex = 0xFFFFFFFF; pub const TrackedDevicePose = extern struct { device_to_absolute_tracking: Matrix34, @@ -2142,7 +2148,7 @@ pub const EventNotification = extern struct { // which EventType? notification_id: u32, }; pub const EventOverlay = extern struct { - overlay_handle: u64, + overlay_handle: u64, // OverlayHandle device_path: u64, memory_block_id: u64, cursor_index: u32, @@ -2153,7 +2159,7 @@ pub const EventStatus = extern struct { // which EventType? pub const EventKeyboard = extern struct { new_input: [8]u8, user_value: u64, - overlay_handle: u64, + overlay_handle: u64, // OverlayHandle }; pub const EventIpd = extern struct { ipd_meters: f32, @@ -2191,7 +2197,7 @@ pub const EventApplicationLaunch = extern struct { // which EventType? }; pub const EventEditingCameraSurface = extern struct { - overlay_handle: u64, + overlay_handle: u64, // OverlayHandle visual_mode: u32, }; pub const EventMessageOverlay = extern struct { // which EventType? @@ -2627,3 +2633,251 @@ pub const FilePaths = struct { return paths.toOwnedSlice(); } }; + +pub const OverlayHandle = u64; +pub const overlay_handle_invalid: OverlayHandle = 0; + +pub const OverlayError = error{ + UnknownOverlay, + InvalidHandle, + PermissionDenied, + OverlayLimitExceeded, + WrongVisibilityType, + KeyTooLong, + NameTooLong, + KeyInUse, + WrongTransformType, + InvalidTrackedDevice, + InvalidParameter, + ThumbnailCantBeDestroyed, + ArrayTooSmall, + RequestFailed, + InvalidTexture, + UnableToLoadFile, + KeyboardAlreadyInUse, + NoNeighbor, + TooManyMaskPrimitives, + BadMaskPrimitive, + TextureAlreadyLocked, + TextureLockCapacityReached, + TextureNotLocked, + TimedOut, +}; + +pub const OverlayErrorCode = enum(i32) { + none = 0, + unknown_overlay = 10, + invalid_handle = 11, + permission_denied = 12, + overlay_limit_exceeded = 13, + wrong_visibility_type = 14, + key_too_long = 15, + name_too_long = 16, + key_in_use = 17, + wrong_transform_type = 18, + invalid_tracked_device = 19, + invalid_parameter = 20, + thumbnail_cant_be_destroyed = 21, + array_too_small = 22, + request_failed = 23, + invalid_texture = 24, + unable_to_load_file = 25, + keyboard_already_in_use = 26, + no_neighbor = 27, + too_many_mask_primitives = 29, + bad_mask_primitive = 30, + texture_already_locked = 31, + texture_lock_capacity_reached = 32, + texture_not_locked = 33, + timed_out = 34, + + pub fn maybe(overlay_error: OverlayErrorCode) OverlayError!void { + return switch (overlay_error) { + .none => {}, + .unknown_overlay => OverlayError.UnknownOverlay, + .invalid_handle => OverlayError.InvalidHandle, + .permission_denied => OverlayError.PermissionDenied, + .overlay_limit_exceeded => OverlayError.OverlayLimitExceeded, + .wrong_visibility_type => OverlayError.WrongVisibilityType, + .key_too_long => OverlayError.KeyTooLong, + .name_too_long => OverlayError.NameTooLong, + .key_in_use => OverlayError.KeyInUse, + .wrong_transform_type => OverlayError.WrongTransformType, + .invalid_tracked_device => OverlayError.InvalidTrackedDevice, + .invalid_parameter => OverlayError.InvalidParameter, + .thumbnail_cant_be_destroyed => OverlayError.ThumbnailCantBeDestroyed, + .array_too_small => OverlayError.ArrayTooSmall, + .request_failed => OverlayError.RequestFailed, + .invalid_texture => OverlayError.InvalidTexture, + .unable_to_load_file => OverlayError.UnableToLoadFile, + .keyboard_already_in_use => OverlayError.KeyboardAlreadyInUse, + .no_neighbor => OverlayError.NoNeighbor, + .too_many_mask_primitives => OverlayError.TooManyMaskPrimitives, + .bad_mask_primitive => OverlayError.BadMaskPrimitive, + .texture_already_locked => OverlayError.TextureAlreadyLocked, + .texture_lock_capacity_reached => OverlayError.TextureLockCapacityReached, + .texture_not_locked => OverlayError.TextureNotLocked, + .timed_out => OverlayError.TimedOut, + }; + } +}; + +pub const OverlayFlags = packed struct(u32) { + _padding: u3 = 0, + no_dashboard_tab: bool = false, + __padding: u2 = 0, + + send_vr_discrete_scroll_events: bool = false, + send_vr_touchpad_events: bool = false, + show_touch_pad_scroll_wheel: bool = false, + transfer_ownership_to_internal_process: bool = false, + + side_by_side_parallel: bool = false, // Texture is left/right + side_by_side_crossed: bool = false, // Texture is crossed and right/left + + panorama: bool = false, // Texture is a panorama + stereo_panorama: bool = false, // Texture is a stereo panorama + + sort_with_non_scene_overlays: bool = false, + visible_in_dashboard: bool = false, + make_overlays_interactive_if_visible: bool = false, + send_vr_smooth_scroll_events: bool = false, + protected_content: bool = false, + hide_laser_intersection: bool = false, + wants_modal_behavior: bool = false, + is_premultiplied: bool = false, + ignore_texture_alpha: bool = false, + enable_control_bar: bool = false, + enable_control_bar_keyboard: bool = false, + enable_control_bar_close: bool = false, + reserved: bool = false, + enable_click_stabilization: bool = false, + multi_cursor: bool = false, + ___padding: u3 = 0, + + pub const Enum = enum(u32) { + NoDashboardTab = @bitCast(OverlayFlags{ .no_dashboard_tab = true }), + SendVRDiscreteScrollEvents = @bitCast(OverlayFlags{ .send_vr_discrete_scroll_events = true }), + SendVRTouchpadEvents = @bitCast(OverlayFlags{ .send_vr_touchpad_events = true }), + ShowTouchPadScrollWheel = @bitCast(OverlayFlags{ .show_touch_pad_scroll_wheel = true }), + TransferOwnershipToInternalProcess = @bitCast(OverlayFlags{ .transfer_ownership_to_internal_process = true }), + SideBySide_Parallel = @bitCast(OverlayFlags{ .side_by_side_parallel = true }), + SideBySide_Crossed = @bitCast(OverlayFlags{ .side_by_side_crossed = true }), + Panorama = @bitCast(OverlayFlags{ .panorama = true }), + StereoPanorama = @bitCast(OverlayFlags{ .stereo_panorama = true }), + SortWithNonSceneOverlays = @bitCast(OverlayFlags{ .sort_with_non_scene_overlays = true }), + VisibleInDashboard = @bitCast(OverlayFlags{ .visible_in_dashboard = true }), + MakeOverlaysInteractiveIfVisible = @bitCast(OverlayFlags{ .make_overlays_interactive_if_visible = true }), + SendVRSmoothScrollEvents = @bitCast(OverlayFlags{ .send_vr_smooth_scroll_events = true }), + ProtectedContent = @bitCast(OverlayFlags{ .protected_content = true }), + HideLaserIntersection = @bitCast(OverlayFlags{ .hide_laser_intersection = true }), + WantsModalBehavior = @bitCast(OverlayFlags{ .wants_modal_behavior = true }), + IsPremultiplied = @bitCast(OverlayFlags{ .is_premultiplied = true }), + IgnoreTextureAlpha = @bitCast(OverlayFlags{ .ignore_texture_alpha = true }), + EnableControlBar = @bitCast(OverlayFlags{ .enable_control_bar = true }), + EnableControlBarKeyboard = @bitCast(OverlayFlags{ .enable_control_bar_keyboard = true }), + EnableControlBarClose = @bitCast(OverlayFlags{ .enable_control_bar_close = true }), + Reserved = @bitCast(OverlayFlags{ .reserved = true }), + EnableClickStabilization = @bitCast(OverlayFlags{ .enable_click_stabilization = true }), + MultiCursor = @bitCast(OverlayFlags{ .multi_cursor = true }), + + _, + }; +}; + +test "make sure bits are in the correct place" { + const expect = std.testing.expect; + try expect(@as(u32, @bitCast(OverlayFlags{ .no_dashboard_tab = true })) == 1 << 3); + try expect(@as(u32, @bitCast(OverlayFlags{ .multi_cursor = true })) == 1 << 28); + try expect(@as(u32, @bitCast(OverlayFlags{ .protected_content = true })) == 1 << 18); + try expect(@as(u32, @bitCast(OverlayFlags{ .send_vr_discrete_scroll_events = true })) == 1 << 6); +} + +pub const OverlayTransformType = enum(i32) { + Invalid = -1, + Absolute = 0, + TrackedDeviceRelative = 1, + //SystemOverlay = 2, // Deleted from the SDK. + TrackedComponent = 3, + Cursor = 4, + DashboardTab = 5, + DashboardThumb = 6, + Mountable = 7, + Projection = 8, + Subview = 9, +}; + +pub const OverlayProjection = RawProjection; // order is left right top bottom + +pub const OverlayInputMethod = enum(i32) { + None = 0, // No input events will be generated automatically for this overlay + Mouse = 1, // Tracked controllers will get mouse events automatically + // DualAnalog = 2, // No longer supported +}; + +pub const OverlayIntersectionParams = extern struct { + source: Vector3, + direction: Vector3, + origin: TrackingUniverseOrigin, +}; + +pub const OverlayIntersectionResults = extern struct { + point: Vector3, + normal: Vector3, + uvs: Vector2, + distance: f32, +}; + +pub const OverlayIntersectionMaskPrimitive_Data = extern union { + rectangle: IntersectionMaskRectangle, + circle: IntersectionMaskCircle, +}; + +pub const OverlayIntersectionMaskPrimitiveType = enum(i32) { + rectangle, + circle, +}; + +pub const IntersectionMaskRectangle = struct { + top_left_x: f32, + top_left_y: f32, + width: f32, + height: f32, +}; + +pub const IntersectionMaskCircle = struct { + center_x: f32, + center_y: f32, + radius: f32, +}; + +pub const OverlayIntersectionMaskPrimitive = extern struct { + primitive_type: OverlayIntersectionMaskPrimitiveType, + primitive: OverlayIntersectionMaskPrimitive_Data, +}; + +pub const KeyboardFlags = packed struct(u32) { + // Makes the keyboard send key events immediately instead of accumulating a buffer */ + Minimal: bool = false, + // Makes the keyboard take all focus and dismiss when clicking off the panel */ + Modal: bool = false, + // Shows arrow keys on the keyboard when in minimal mode. Buffered (non-minimal) mode always has them. In minimal + // mode, when arrow keys are pressed, they send ANSI escape sequences (e.g. "\x1b[D" for left arrow). + ShowArrowKeys: bool = false, + // Shows the hide keyboard button instead of a Done button. The Done key sends a VREvent_KeyboardDone when + // clicked. Hide only sends the Closed event. + HideDoneKey: bool = false, + + // _padding: u28 = 0, +}; + +pub const GamepadTextInputMode = enum(i32) { + normal = 0, + password = 1, + submit = 2, +}; + +pub const GamepadTextInputLineMode = enum(i32) { + single_line = 0, + multiple_lines = 1, +}; diff --git a/libs/zopenvr/src/openvr.zig b/libs/zopenvr/src/openvr.zig index 23d38b3b0..61cff4949 100644 --- a/libs/zopenvr/src/openvr.zig +++ b/libs/zopenvr/src/openvr.zig @@ -65,6 +65,10 @@ pub fn renderModels(_: Self) common.InitError!RenderModels { return try RenderModels.init(); } +pub fn overlay(_: Self) common.InitError!Overlay { + return try Overlay.init(); +} + pub usingnamespace @import("common.zig"); pub const System = @import("system.zig"); pub const Chaperone = @import("chaperone.zig"); @@ -72,3 +76,4 @@ pub const Compositor = @import("compositor.zig"); pub const Applications = @import("applications.zig"); pub const Input = @import("input.zig"); pub const RenderModels = @import("render_models.zig"); +pub const Overlay = @import("overlay.zig"); diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig new file mode 100644 index 000000000..28cf5248d --- /dev/null +++ b/libs/zopenvr/src/overlay.zig @@ -0,0 +1,423 @@ +const std = @import("std"); + +const common = @import("common.zig"); + +function_table: *FunctionTable, + +const Self = @This(); + +const version = "IVROverlay_027"; +pub fn init() common.InitError!Self { + return .{ + .function_table = try common.getFunctionTable(FunctionTable, version), + }; +} + +pub fn findOverlay() void { + @compileError("not implemented"); +} + +pub fn createOverlay() void { + @compileError("not implemented"); +} + +pub fn destroyOverlay() void { + @compileError("not implemented"); +} + +pub fn getOverlayKey() void { + @compileError("not implemented"); +} + +pub fn getOverlayName() void { + @compileError("not implemented"); +} + +pub fn setOverlayName() void { + @compileError("not implemented"); +} + +pub fn getOverlayImageData() void { + @compileError("not implemented"); +} + +pub fn getOverlayErrorNameFromEnum() void { + @compileError("not implemented"); +} + +pub fn setOverlayRenderingPid() void { + @compileError("not implemented"); +} + +pub fn getOverlayRenderingPid() void { + @compileError("not implemented"); +} + +pub fn setOverlayFlag() void { + @compileError("not implemented"); +} + +pub fn getOverlayFlag() void { + @compileError("not implemented"); +} + +pub fn getOverlayFlags() void { + @compileError("not implemented"); +} + +pub fn setOverlayColor() void { + @compileError("not implemented"); +} + +pub fn getOverlayColor() void { + @compileError("not implemented"); +} + +pub fn setOverlayAlpha() void { + @compileError("not implemented"); +} + +pub fn getOverlayAlpha() void { + @compileError("not implemented"); +} + +pub fn setOverlayTexelAspect() void { + @compileError("not implemented"); +} + +pub fn getOverlayTexelAspect() void { + @compileError("not implemented"); +} + +pub fn setOverlaySortOrder() void { + @compileError("not implemented"); +} + +pub fn getOverlaySortOrder() void { + @compileError("not implemented"); +} + +pub fn setOverlayWidthInMeters() void { + @compileError("not implemented"); +} + +pub fn getOverlayWidthInMeters() void { + @compileError("not implemented"); +} + +pub fn setOverlayCurvature() void { + @compileError("not implemented"); +} + +pub fn getOverlayCurvature() void { + @compileError("not implemented"); +} + +pub fn setOverlayPreCurvePitch() void { + @compileError("not implemented"); +} + +pub fn getOverlayPreCurvePitch() void { + @compileError("not implemented"); +} + +pub fn setOverlayTextureColorSpace() void { + @compileError("not implemented"); +} + +pub fn getOverlayTextureColorSpace() void { + @compileError("not implemented"); +} + +pub fn setOverlayTextureBounds() void { + @compileError("not implemented"); +} + +pub fn getOverlayTextureBounds() void { + @compileError("not implemented"); +} + +pub fn getOverlayTransformType() void { + @compileError("not implemented"); +} + +pub fn setOverlayTransformAbsolute() void { + @compileError("not implemented"); +} + +pub fn getOverlayTransformAbsolute() void { + @compileError("not implemented"); +} + +pub fn setOverlayTransformTrackedDeviceRelative() void { + @compileError("not implemented"); +} + +pub fn getOverlayTransformTrackedDeviceRelative() void { + @compileError("not implemented"); +} + +pub fn setOverlayTransformTrackedDeviceComponent() void { + @compileError("not implemented"); +} + +pub fn getOverlayTransformTrackedDeviceComponent() void { + @compileError("not implemented"); +} + +pub fn setOverlayTransformCursor() void { + @compileError("not implemented"); +} + +pub fn getOverlayTransformCursor() void { + @compileError("not implemented"); +} + +pub fn setOverlayTransformProjection() void { + @compileError("not implemented"); +} + +pub fn showOverlay() void { + @compileError("not implemented"); +} + +pub fn hideOverlay() void { + @compileError("not implemented"); +} + +pub fn isOverlayVisible() void { + @compileError("not implemented"); +} + +pub fn getTransformForOverlayCoordinates() void { + @compileError("not implemented"); +} + +pub fn waitFrameSync() void { + @compileError("not implemented"); +} + +pub fn pollNextOverlayEvent() void { + @compileError("not implemented"); +} + +pub fn getOverlayInputMethod() void { + @compileError("not implemented"); +} + +pub fn setOverlayInputMethod() void { + @compileError("not implemented"); +} + +pub fn getOverlayMouseScale() void { + @compileError("not implemented"); +} + +pub fn setOverlayMouseScale() void { + @compileError("not implemented"); +} + +pub fn computeOverlayIntersection() void { + @compileError("not implemented"); +} + +pub fn isHoverTargetOverlay() void { + @compileError("not implemented"); +} + +pub fn setOverlayIntersectionMask() void { + @compileError("not implemented"); +} + +pub fn triggerLaserMouseHapticVibration() void { + @compileError("not implemented"); +} + +pub fn setOverlayCursor() void { + @compileError("not implemented"); +} + +pub fn setOverlayCursorPositionOverride() void { + @compileError("not implemented"); +} + +pub fn clearOverlayCursorPositionOverride() void { + @compileError("not implemented"); +} + +pub fn setOverlayTexture() void { + @compileError("not implemented"); +} + +pub fn clearOverlayTexture() void { + @compileError("not implemented"); +} + +pub fn setOverlayRaw() void { + @compileError("not implemented"); +} + +pub fn setOverlayFromFile() void { + @compileError("not implemented"); +} + +pub fn getOverlayTexture() void { + @compileError("not implemented"); +} + +pub fn releaseNativeOverlayHandle() void { + @compileError("not implemented"); +} + +pub fn getOverlayTextureSize() void { + @compileError("not implemented"); +} + +pub fn createDashboardOverlay() void { + @compileError("not implemented"); +} + +pub fn isDashboardVisible() void { + @compileError("not implemented"); +} + +pub fn isActiveDashboardOverlay() void { + @compileError("not implemented"); +} + +pub fn setDashboardOverlaySceneProcess() void { + @compileError("not implemented"); +} + +pub fn getDashboardOverlaySceneProcess() void { + @compileError("not implemented"); +} + +pub fn showDashboard() void { + @compileError("not implemented"); +} + +pub fn getPrimaryDashboardDevice() void { + @compileError("not implemented"); +} + +pub fn showKeyboard() void { + @compileError("not implemented"); +} + +pub fn showKeyboardForOverlay() void { + @compileError("not implemented"); +} + +pub fn getKeyboardText() void { + @compileError("not implemented"); +} + +pub fn hideKeyboard() void { + @compileError("not implemented"); +} + +pub fn setKeyboardTransformAbsolute() void { + @compileError("not implemented"); +} + +pub fn setKeyboardPositionForOverlay() void { + @compileError("not implemented"); +} + +pub fn showMessageOverlay() void { + @compileError("not implemented"); +} + +pub fn closeMessageOverlay() void { + @compileError("not implemented"); +} + +const FunctionTable = extern struct { + FindOverlay: *const fn ([*c]const u8, *common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + CreateOverlay: *const fn ([*c]const u8, [*c]const u8, *common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + DestroyOverlay: *const fn (common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + GetOverlayKey: *const fn (common.OverlayHandle, [*c]const u8, u32, *common.OverlayErrorCode) callconv(.C) u32, + GetOverlayName: *const fn (common.OverlayHandle, [*c]const u8, u32, *common.OverlayErrorCode) callconv(.C) u32, + SetOverlayName: *const fn (common.OverlayHandle, [*c]const u8) callconv(.C) common.OverlayErrorCode, + GetOverlayImageData: *const fn (common.OverlayHandle, anyopaque, u32, *u32, *u32) callconv(.C) common.OverlayErrorCode, + GetOverlayErrorNameFromEnum: *const fn (common.OverlayErrorCode) callconv(.C) [*c]const u8, + + SetOverlayRenderingPid: *const fn (common.OverlayHandle, u32) callconv(.C) common.OverlayErrorCode, + GetOverlayRenderingPid: *const fn (common.OverlayHandle) callconv(.C) u32, + SetOverlayFlag: *const fn (common.OverlayHandle, common.OverlayFlags.Enum, bool) callconv(.C) common.OverlayErrorCode, + GetOverlayFlag: *const fn (common.OverlayHandle, common.OverlayFlags.Enum, *bool) callconv(.C) common.OverlayErrorCode, + GetOverlayFlags: *const fn (common.OverlayHandle, *common.OverlayFlags) callconv(.C) common.OverlayErrorCode, + SetOverlayColor: *const fn (common.OverlayHandle, f32, f32, f32) callconv(.C) common.OverlayErrorCode, + GetOverlayColor: *const fn (common.OverlayHandle, *f32, *f32, *f32) callconv(.C) common.OverlayErrorCode, + SetOverlayAlpha: *const fn (common.OverlayHandle, f32) callconv(.C) common.OverlayErrorCode, + GetOverlayAlpha: *const fn (common.OverlayHandle, *f32) callconv(.C) common.OverlayErrorCode, + SetOverlayTexelAspect: *const fn (common.OverlayHandle, f32) callconv(.C) common.OverlayErrorCode, + GetOverlayTexelAspect: *const fn (common.OverlayHandle, *f32) callconv(.C) common.OverlayErrorCode, + SetOverlaySortOrder: *const fn (common.OverlayHandle, u32) callconv(.C) common.OverlayErrorCode, + GetOverlaySortOrder: *const fn (common.OverlayHandle, *u32) callconv(.C) common.OverlayErrorCode, + SetOverlayWidthInMeters: *const fn (common.OverlayHandle, f32) callconv(.C) common.OverlayErrorCode, + GetOverlayWidthInMeters: *const fn (common.OverlayHandle, *f32) callconv(.C) common.OverlayErrorCode, + SetOverlayCurvature: *const fn (common.OverlayHandle, f32) callconv(.C) common.OverlayErrorCode, + GetOverlayCurvature: *const fn (common.OverlayHandle, *f32) callconv(.C) common.OverlayErrorCode, + SetOverlayPreCurvePitch: *const fn (common.OverlayHandle, f32) callconv(.C) common.OverlayErrorCode, + GetOverlayPreCurvePitch: *const fn (common.OverlayHandle, *f32) callconv(.C) common.OverlayErrorCode, + SetOverlayTextureColorSpace: *const fn (common.OverlayHandle, common.ColorSpace) callconv(.C) common.OverlayErrorCode, + GetOverlayTextureColorSpace: *const fn (common.OverlayHandle, *common.ColorSpace) callconv(.C) common.OverlayErrorCode, + SetOverlayTextureBounds: *const fn (common.OverlayHandle, *const common.TextureBounds) callconv(.C) common.OverlayErrorCode, + GetOverlayTextureBounds: *const fn (common.OverlayHandle, *common.TextureBounds) callconv(.C) common.OverlayErrorCode, + GetOverlayTransformType: *const fn (common.OverlayHandle, *common.OverlayTransformType) callconv(.C) common.OverlayErrorCode, + SetOverlayTransformAbsolute: *const fn (common.OverlayHandle, common.TrackingUniverseOrigin, *const common.Matrix34) callconv(.C) common.OverlayErrorCode, + GetOverlayTransformAbsolute: *const fn (common.OverlayHandle, *common.TrackingUniverseOrigin, *common.Matrix34) callconv(.C) common.OverlayErrorCode, + SetOverlayTransformTrackedDeviceRelative: *const fn (common.OverlayHandle, common.TrackedDeviceIndex, *const common.Matrix34) callconv(.C) common.OverlayErrorCode, + GetOverlayTransformTrackedDeviceRelative: *const fn (common.OverlayHandle, *common.TrackedDeviceIndex, *common.Matrix34) callconv(.C) common.OverlayErrorCode, + SetOverlayTransformTrackedDeviceComponent: *const fn (common.OverlayHandle, common.TrackedDeviceIndex, [*c]const u8) callconv(.C) common.OverlayErrorCode, + GetOverlayTransformTrackedDeviceComponent: *const fn (common.OverlayHandle, *common.TrackedDeviceIndex, [*c]const u8, u32) callconv(.C) common.OverlayErrorCode, + SetOverlayTransformCursor: *const fn (common.OverlayHandle, *const common.Vector2) callconv(.C) common.OverlayErrorCode, + GetOverlayTransformCursor: *const fn (common.OverlayHandle, *common.Vector2) callconv(.C) common.OverlayErrorCode, + SetOverlayTransformProjection: *const fn (common.OverlayHandle, common.TrackingUniverseOrigin, *const common.Matrix34, *const common.OverlayProjection, common.Eye) callconv(.C) common.OverlayErrorCode, + ShowOverlay: *const fn (common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + HideOverlay: *const fn (common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + IsOverlayVisible: *const fn (common.OverlayHandle) callconv(.C) bool, + GetTransformForOverlayCoordinates: *const fn (common.OverlayHandle, common.TrackingUniverseOrigin, common.Vector2, *common.Matrix34) callconv(.C) common.OverlayErrorCode, + WaitFrameSync: *const fn (u32) callconv(.C) common.OverlayErrorCode, + + PollNextOverlayEvent: *const fn (common.OverlayHandle, *common.Event, u32) callconv(.C) bool, + GetOverlayInputMethod: *const fn (common.OverlayHandle, *common.OverlayInputMethod) callconv(.C) common.OverlayErrorCode, + SetOverlayInputMethod: *const fn (common.OverlayHandle, common.OverlayInputMethod) callconv(.C) common.OverlayErrorCode, + GetOverlayMouseScale: *const fn (common.OverlayHandle, *common.Vector2) callconv(.C) common.OverlayErrorCode, + SetOverlayMouseScale: *const fn (common.OverlayHandle, *const common.Vector2) callconv(.C) common.OverlayErrorCode, + ComputeOverlayIntersection: *const fn (common.OverlayHandle, *const common.OverlayIntersectionParams, *common.OverlayIntersectionResults) callconv(.C) bool, + IsHoverTargetOverlay: *const fn (common.OverlayHandle) callconv(.C) bool, + SetOverlayIntersectionMask: *const fn (common.OverlayHandle, *common.OverlayIntersectionMaskPrimitive, u32, u32) callconv(.C) common.OverlayErrorCode, + TriggerLaserMouseHapticVibration: *const fn (common.OverlayHandle, f32, f32, f32) callconv(.C) common.OverlayErrorCode, + SetOverlayCursor: *const fn (common.OverlayHandle, common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + SetOverlayCursorPositionOverride: *const fn (common.OverlayHandle, *const common.Vector2) callconv(.C) common.OverlayErrorCode, + ClearOverlayCursorPositionOverride: *const fn (common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + + SetOverlayTexture: *const fn (common.OverlayHandle, *const common.Texture) callconv(.C) common.OverlayErrorCode, + ClearOverlayTexture: *const fn (common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + SetOverlayRaw: *const fn (common.OverlayHandle, anyopaque, u32, u32, u32) callconv(.C) common.OverlayErrorCode, + SetOverlayFromFile: *const fn (common.OverlayHandle, [*c]const u8) callconv(.C) common.OverlayErrorCode, + GetOverlayTexture: *const fn (common.OverlayHandle, *anyopaque, anyopaque, *u32, *u32, *u32, *common.TextureType, *common.ColorSpace, *common.TextureBounds) callconv(.C) common.OverlayErrorCode, + ReleaseNativeOverlayHandle: *const fn (common.OverlayHandle, anyopaque) callconv(.C) common.OverlayErrorCode, + GetOverlayTextureSize: *const fn (common.OverlayHandle, *u32, *u32) callconv(.C) common.OverlayErrorCode, + + CreateDashboardOverlay: *const fn ([*c]const u8, [*c]const u8, *common.OverlayHandle, *common.OverlayHandle) callconv(.C) common.OverlayErrorCode, + IsDashboardVisible: *const fn () callconv(.C) bool, + IsActiveDashboardOverlay: *const fn (common.OverlayHandle) callconv(.C) bool, + SetDashboardOverlaySceneProcess: *const fn (common.OverlayHandle, u32) callconv(.C) common.OverlayErrorCode, + GetDashboardOverlaySceneProcess: *const fn (common.OverlayHandle, *u32) callconv(.C) common.OverlayErrorCode, + ShowDashboard: *const fn ([*c]const u8) callconv(.C) common.OverlayErrorCode, + GetPrimaryDashboardDevice: *const fn () callconv(.C) common.TrackedDeviceIndex, + + ShowKeyboard: *const fn (common.GamepadTextInputMode, common.GamepadTextInputLineMode, common.KeyboardFlags, [*c]const u8, u32, [*c]const u8, u64) callconv(.C) common.OverlayErrorCode, + ShowKeyboardForOverlay: *const fn (common.OverlayHandle, common.GamepadTextInputMode, common.GamepadTextInputLineMode, common.KeyboardFlags, [*c]const u8, u32, [*c]const u8, u64) callconv(.C) common.OverlayErrorCode, + GetKeyboardText: *const fn ([*c]const u8, u32) callconv(.C) u32, + HideKeyboard: *const fn () callconv(.C) void, + SetKeyboardTransformAbsolute: *const fn (common.TrackingUniverseOrigin, *const common.Matrix34) callconv(.C) void, + SetKeyboardPositionForOverlay: *const fn (common.OverlayHandle, common.Rect2) callconv(.C) void, + + ShowMessageOverlay: *const fn ([*c]const u8, [*c]const u8, [*c]const u8, ?[*c]const u8, ?[*c]const u8, ?[*c]const u8) callconv(.C) void, + CloseMessageOverlay: *const fn () callconv(.C) void, +}; From 8e1e33c2f8ab3d0eeb97d8eee910f20403df8df2 Mon Sep 17 00:00:00 2001 From: zivoy Date: Mon, 1 Jul 2024 08:45:18 -0400 Subject: [PATCH 07/44] start implementing minimal example --- libs/zopenvr/src/common.zig | 8 +- libs/zopenvr/src/overlay.zig | 179 ++++++++++++++++++----------------- 2 files changed, 95 insertions(+), 92 deletions(-) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index a4b63b60b..cb5ad7771 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -2785,7 +2785,7 @@ pub const OverlayFlags = packed struct(u32) { }; }; -test "make sure bits are in the correct place" { +test "overlay flag bits are in the correct place" { const expect = std.testing.expect; try expect(@as(u32, @bitCast(OverlayFlags{ .no_dashboard_tab = true })) == 1 << 3); try expect(@as(u32, @bitCast(OverlayFlags{ .multi_cursor = true })) == 1 << 28); @@ -2838,14 +2838,14 @@ pub const OverlayIntersectionMaskPrimitiveType = enum(i32) { circle, }; -pub const IntersectionMaskRectangle = struct { +pub const IntersectionMaskRectangle = extern struct { top_left_x: f32, top_left_y: f32, width: f32, height: f32, }; -pub const IntersectionMaskCircle = struct { +pub const IntersectionMaskCircle = extern struct { center_x: f32, center_y: f32, radius: f32, @@ -2868,7 +2868,7 @@ pub const KeyboardFlags = packed struct(u32) { // clicked. Hide only sends the Closed event. HideDoneKey: bool = false, - // _padding: u28 = 0, + _padding: u28 = 0, }; pub const GamepadTextInputMode = enum(i32) { diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 28cf5248d..d7bf8d9c2 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -13,323 +13,326 @@ pub fn init() common.InitError!Self { }; } -pub fn findOverlay() void { +pub fn findOverlay(_: Self) void { @compileError("not implemented"); } -pub fn createOverlay() void { - @compileError("not implemented"); +pub fn createOverlay(self: Self, overlay_key: [:0]const u8, overlay_name: [:0]const u8) common.OverlayError!common.OverlayHandle { + var handle: common.OverlayHandle = undefined; + const overlay_error = self.function_table.CreateOverlay(overlay_key.ptr, overlay_name.ptr, &handle); + try overlay_error.maybe(); + return handle; } -pub fn destroyOverlay() void { +pub fn destroyOverlay(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayKey() void { +pub fn getOverlayKey(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayName() void { +pub fn getOverlayName(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayName() void { +pub fn setOverlayName(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayImageData() void { +pub fn getOverlayImageData(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayErrorNameFromEnum() void { +pub fn getOverlayErrorNameFromEnum(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayRenderingPid() void { +pub fn setOverlayRenderingPid(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayRenderingPid() void { +pub fn getOverlayRenderingPid(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayFlag() void { +pub fn setOverlayFlag(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayFlag() void { +pub fn getOverlayFlag(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayFlags() void { +pub fn getOverlayFlags(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayColor() void { - @compileError("not implemented"); +pub fn setOverlayColor(self: Self, overlay_handle: common.OverlayHandle, red: f32, green: f32, blue: f32) common.OverlayError!void { + try self.function_table.SetOverlayColor(overlay_handle, red, green, blue).maybe(); } -pub fn getOverlayColor() void { +pub fn getOverlayColor(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayAlpha() void { +pub fn setOverlayAlpha(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayAlpha() void { +pub fn getOverlayAlpha(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTexelAspect() void { +pub fn setOverlayTexelAspect(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTexelAspect() void { +pub fn getOverlayTexelAspect(_: Self) void { @compileError("not implemented"); } -pub fn setOverlaySortOrder() void { +pub fn setOverlaySortOrder(_: Self) void { @compileError("not implemented"); } -pub fn getOverlaySortOrder() void { +pub fn getOverlaySortOrder(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayWidthInMeters() void { - @compileError("not implemented"); +pub fn setOverlayWidthInMeters(self: Self, overlay_handle: common.OverlayHandle, width_in_meters: f32) common.OverlayError!void { + try self.function_table.SetOverlayWidthInMeters(overlay_handle, width_in_meters).maybe(); } -pub fn getOverlayWidthInMeters() void { +pub fn getOverlayWidthInMeters(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayCurvature() void { +pub fn setOverlayCurvature(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayCurvature() void { +pub fn getOverlayCurvature(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayPreCurvePitch() void { +pub fn setOverlayPreCurvePitch(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayPreCurvePitch() void { +pub fn getOverlayPreCurvePitch(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTextureColorSpace() void { +pub fn setOverlayTextureColorSpace(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTextureColorSpace() void { +pub fn getOverlayTextureColorSpace(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTextureBounds() void { +pub fn setOverlayTextureBounds(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTextureBounds() void { +pub fn getOverlayTextureBounds(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTransformType() void { +pub fn getOverlayTransformType(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTransformAbsolute() void { +pub fn setOverlayTransformAbsolute(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTransformAbsolute() void { +pub fn getOverlayTransformAbsolute(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTransformTrackedDeviceRelative() void { +pub fn setOverlayTransformTrackedDeviceRelative(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTransformTrackedDeviceRelative() void { +pub fn getOverlayTransformTrackedDeviceRelative(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTransformTrackedDeviceComponent() void { +pub fn setOverlayTransformTrackedDeviceComponent(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTransformTrackedDeviceComponent() void { +pub fn getOverlayTransformTrackedDeviceComponent(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTransformCursor() void { +pub fn setOverlayTransformCursor(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTransformCursor() void { +pub fn getOverlayTransformCursor(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTransformProjection() void { +pub fn setOverlayTransformProjection(_: Self) void { @compileError("not implemented"); } -pub fn showOverlay() void { +pub fn showOverlay(_: Self) void { @compileError("not implemented"); } -pub fn hideOverlay() void { +pub fn hideOverlay(_: Self) void { @compileError("not implemented"); } -pub fn isOverlayVisible() void { +pub fn isOverlayVisible(_: Self) void { @compileError("not implemented"); } -pub fn getTransformForOverlayCoordinates() void { +pub fn getTransformForOverlayCoordinates(_: Self) void { @compileError("not implemented"); } -pub fn waitFrameSync() void { +pub fn waitFrameSync(_: Self) void { @compileError("not implemented"); } -pub fn pollNextOverlayEvent() void { +pub fn pollNextOverlayEvent(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayInputMethod() void { +pub fn getOverlayInputMethod(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayInputMethod() void { +pub fn setOverlayInputMethod(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayMouseScale() void { +pub fn getOverlayMouseScale(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayMouseScale() void { +pub fn setOverlayMouseScale(_: Self) void { @compileError("not implemented"); } -pub fn computeOverlayIntersection() void { +pub fn computeOverlayIntersection(_: Self) void { @compileError("not implemented"); } -pub fn isHoverTargetOverlay() void { +pub fn isHoverTargetOverlay(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayIntersectionMask() void { +pub fn setOverlayIntersectionMask(_: Self) void { @compileError("not implemented"); } -pub fn triggerLaserMouseHapticVibration() void { +pub fn triggerLaserMouseHapticVibration(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayCursor() void { +pub fn setOverlayCursor(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayCursorPositionOverride() void { +pub fn setOverlayCursorPositionOverride(_: Self) void { @compileError("not implemented"); } -pub fn clearOverlayCursorPositionOverride() void { +pub fn clearOverlayCursorPositionOverride(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTexture() void { +pub fn setOverlayTexture(_: Self) void { @compileError("not implemented"); } -pub fn clearOverlayTexture() void { +pub fn clearOverlayTexture(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayRaw() void { +pub fn setOverlayRaw(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayFromFile() void { +pub fn setOverlayFromFile(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTexture() void { +pub fn getOverlayTexture(_: Self) void { @compileError("not implemented"); } -pub fn releaseNativeOverlayHandle() void { +pub fn releaseNativeOverlayHandle(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayTextureSize() void { +pub fn getOverlayTextureSize(_: Self) void { @compileError("not implemented"); } -pub fn createDashboardOverlay() void { +pub fn createDashboardOverlay(_: Self) void { @compileError("not implemented"); } -pub fn isDashboardVisible() void { +pub fn isDashboardVisible(_: Self) void { @compileError("not implemented"); } -pub fn isActiveDashboardOverlay() void { +pub fn isActiveDashboardOverlay(_: Self) void { @compileError("not implemented"); } -pub fn setDashboardOverlaySceneProcess() void { +pub fn setDashboardOverlaySceneProcess(_: Self) void { @compileError("not implemented"); } -pub fn getDashboardOverlaySceneProcess() void { +pub fn getDashboardOverlaySceneProcess(_: Self) void { @compileError("not implemented"); } -pub fn showDashboard() void { +pub fn showDashboard(_: Self) void { @compileError("not implemented"); } -pub fn getPrimaryDashboardDevice() void { +pub fn getPrimaryDashboardDevice(_: Self) void { @compileError("not implemented"); } -pub fn showKeyboard() void { +pub fn showKeyboard(_: Self) void { @compileError("not implemented"); } -pub fn showKeyboardForOverlay() void { +pub fn showKeyboardForOverlay(_: Self) void { @compileError("not implemented"); } -pub fn getKeyboardText() void { +pub fn getKeyboardText(_: Self) void { @compileError("not implemented"); } -pub fn hideKeyboard() void { +pub fn hideKeyboard(_: Self) void { @compileError("not implemented"); } -pub fn setKeyboardTransformAbsolute() void { +pub fn setKeyboardTransformAbsolute(_: Self) void { @compileError("not implemented"); } -pub fn setKeyboardPositionForOverlay() void { +pub fn setKeyboardPositionForOverlay(_: Self) void { @compileError("not implemented"); } -pub fn showMessageOverlay() void { +pub fn showMessageOverlay(_: Self) void { @compileError("not implemented"); } -pub fn closeMessageOverlay() void { +pub fn closeMessageOverlay(_: Self) void { @compileError("not implemented"); } @@ -340,7 +343,7 @@ const FunctionTable = extern struct { GetOverlayKey: *const fn (common.OverlayHandle, [*c]const u8, u32, *common.OverlayErrorCode) callconv(.C) u32, GetOverlayName: *const fn (common.OverlayHandle, [*c]const u8, u32, *common.OverlayErrorCode) callconv(.C) u32, SetOverlayName: *const fn (common.OverlayHandle, [*c]const u8) callconv(.C) common.OverlayErrorCode, - GetOverlayImageData: *const fn (common.OverlayHandle, anyopaque, u32, *u32, *u32) callconv(.C) common.OverlayErrorCode, + GetOverlayImageData: *const fn (common.OverlayHandle, ?*anyopaque, u32, *u32, *u32) callconv(.C) common.OverlayErrorCode, GetOverlayErrorNameFromEnum: *const fn (common.OverlayErrorCode) callconv(.C) [*c]const u8, SetOverlayRenderingPid: *const fn (common.OverlayHandle, u32) callconv(.C) common.OverlayErrorCode, @@ -397,10 +400,10 @@ const FunctionTable = extern struct { SetOverlayTexture: *const fn (common.OverlayHandle, *const common.Texture) callconv(.C) common.OverlayErrorCode, ClearOverlayTexture: *const fn (common.OverlayHandle) callconv(.C) common.OverlayErrorCode, - SetOverlayRaw: *const fn (common.OverlayHandle, anyopaque, u32, u32, u32) callconv(.C) common.OverlayErrorCode, + SetOverlayRaw: *const fn (common.OverlayHandle, ?*anyopaque, u32, u32, u32) callconv(.C) common.OverlayErrorCode, SetOverlayFromFile: *const fn (common.OverlayHandle, [*c]const u8) callconv(.C) common.OverlayErrorCode, - GetOverlayTexture: *const fn (common.OverlayHandle, *anyopaque, anyopaque, *u32, *u32, *u32, *common.TextureType, *common.ColorSpace, *common.TextureBounds) callconv(.C) common.OverlayErrorCode, - ReleaseNativeOverlayHandle: *const fn (common.OverlayHandle, anyopaque) callconv(.C) common.OverlayErrorCode, + GetOverlayTexture: *const fn (common.OverlayHandle, *?*anyopaque, ?*anyopaque, *u32, *u32, *u32, *common.TextureType, *common.ColorSpace, *common.TextureBounds) callconv(.C) common.OverlayErrorCode, + ReleaseNativeOverlayHandle: *const fn (common.OverlayHandle, ?*anyopaque) callconv(.C) common.OverlayErrorCode, GetOverlayTextureSize: *const fn (common.OverlayHandle, *u32, *u32) callconv(.C) common.OverlayErrorCode, CreateDashboardOverlay: *const fn ([*c]const u8, [*c]const u8, *common.OverlayHandle, *common.OverlayHandle) callconv(.C) common.OverlayErrorCode, @@ -418,6 +421,6 @@ const FunctionTable = extern struct { SetKeyboardTransformAbsolute: *const fn (common.TrackingUniverseOrigin, *const common.Matrix34) callconv(.C) void, SetKeyboardPositionForOverlay: *const fn (common.OverlayHandle, common.Rect2) callconv(.C) void, - ShowMessageOverlay: *const fn ([*c]const u8, [*c]const u8, [*c]const u8, ?[*c]const u8, ?[*c]const u8, ?[*c]const u8) callconv(.C) void, + ShowMessageOverlay: *const fn ([*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8) callconv(.C) void, CloseMessageOverlay: *const fn () callconv(.C) void, }; From f0f9c28150f1717594b936f2dcdc1711438c05d1 Mon Sep 17 00:00:00 2001 From: zivoy Date: Mon, 1 Jul 2024 10:20:18 -0400 Subject: [PATCH 08/44] minimal implementation for mango --- libs/zopenvr/src/common.zig | 9 ++++++--- libs/zopenvr/src/overlay.zig | 25 +++++++++++++++---------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index cb5ad7771..89c56f55c 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -724,6 +724,8 @@ pub const TrackingUniverseOrigin = enum(i32) { raw_and_uncalibrated = 2, }; +pub const max_tracked_device_count: usize = 64; + pub const TrackingResult = enum(i32) { uninitialized = 1, calibrating_in_progress = 100, @@ -735,9 +737,10 @@ pub const TrackingResult = enum(i32) { pub const TrackedDeviceIndex = u32; pub const hmd: TrackedDeviceIndex = 0; -pub const max_tracked_device_count: usize = 64; -pub const other_tracked_device_index: TrackedDeviceIndex = 0xFFFFFFFE; -pub const invalid_tracked_device_index: TrackedDeviceIndex = 0xFFFFFFFF; + +pub const tracked_device_index_hmd: TrackedDeviceIndex = hmd; // a copy that is more similar to the capi +pub const tracked_device_index_other: TrackedDeviceIndex = 0xFFFFFFFE; +pub const tracked_device_index_invalid: TrackedDeviceIndex = 0xFFFFFFFF; pub const TrackedDevicePose = extern struct { device_to_absolute_tracking: Matrix34, diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index d7bf8d9c2..39ff2435a 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -132,8 +132,8 @@ pub fn getOverlayTextureColorSpace(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTextureBounds(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayTextureBounds(self: Self, overlay_handle: common.OverlayHandle, overlay_texture_bounds: common.TextureBounds) common.OverlayError!void { + try self.function_table.SetOverlayTextureBounds(overlay_handle, &overlay_texture_bounds).maybe(); } pub fn getOverlayTextureBounds(_: Self) void { @@ -152,8 +152,8 @@ pub fn getOverlayTransformAbsolute(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTransformTrackedDeviceRelative(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayTransformTrackedDeviceRelative(self: Self, overlay_handle: common.OverlayHandle, tracked_device: common.TrackedDeviceIndex, tracked_device_to_overlay_transform: common.Matrix34) common.OverlayError!void { + try self.function_table.SetOverlayTransformTrackedDeviceRelative(overlay_handle, tracked_device, &tracked_device_to_overlay_transform).maybe(); } pub fn getOverlayTransformTrackedDeviceRelative(_: Self) void { @@ -180,8 +180,8 @@ pub fn setOverlayTransformProjection(_: Self) void { @compileError("not implemented"); } -pub fn showOverlay(_: Self) void { - @compileError("not implemented"); +pub fn showOverlay(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { + try self.function_table.ShowOverlay(overlay_handle).maybe(); } pub fn hideOverlay(_: Self) void { @@ -200,8 +200,12 @@ pub fn waitFrameSync(_: Self) void { @compileError("not implemented"); } -pub fn pollNextOverlayEvent(_: Self) void { - @compileError("not implemented"); +pub fn pollNextOverlayEvent(self: Self, overlay_handle: common.OverlayHandle) ?common.Event { + var event: common.Event = undefined; + if (self.function_table.PollNextOverlayEvent(overlay_handle, &event, @sizeOf(common.Event))) { + return event; + } + return null; } pub fn getOverlayInputMethod(_: Self) void { @@ -256,8 +260,9 @@ pub fn clearOverlayTexture(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayRaw(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayRaw(self: Self, comptime T: type, overlay_handle: common.OverlayHandle, buffer: [*]T, width: u32, height: u32, bytes_per_pixel: u32) common.OverlayError!void { + std.debug.assert(@typeInfo(T) == .Int); + try self.function_table.SetOverlayRaw(overlay_handle, buffer, width, height, bytes_per_pixel).maybe(); } pub fn setOverlayFromFile(_: Self) void { From d5b37845dbe08444cab3799a063f2a002df3a1f6 Mon Sep 17 00:00:00 2001 From: zivoy Date: Mon, 1 Jul 2024 13:39:52 -0400 Subject: [PATCH 09/44] add some types --- libs/zopenvr/src/common.zig | 52 ++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 89c56f55c..ea9c96b7b 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -2125,12 +2125,12 @@ pub const EventReserved = extern struct { reserved5: u64, }; pub const EventController = extern struct { - button: u32, + button: ButtonId, }; pub const EventMouse = extern struct { x: f32, y: f32, - button: u32, + button: VRMouseButton, cursor_index: u32, }; pub const EventScroll = extern struct { @@ -2151,18 +2151,18 @@ pub const EventNotification = extern struct { // which EventType? notification_id: u32, }; pub const EventOverlay = extern struct { - overlay_handle: u64, // OverlayHandle + overlay_handle: OverlayHandle, device_path: u64, memory_block_id: u64, cursor_index: u32, }; -pub const EventStatus = extern struct { // which EventType? - status_state: u32, +pub const EventStatus = extern struct { + status_state: VRState, }; pub const EventKeyboard = extern struct { - new_input: [8]u8, - user_value: u64, - overlay_handle: u64, // OverlayHandle + new_input: [8]u8, // 7 bytes of utf8 + null + user_value: u64, // caller specified opaque token + overlay_handle: OverlayHandle, }; pub const EventIpd = extern struct { ipd_meters: f32, @@ -2200,11 +2200,11 @@ pub const EventApplicationLaunch = extern struct { // which EventType? }; pub const EventEditingCameraSurface = extern struct { - overlay_handle: u64, // OverlayHandle + overlay_handle: OverlayHandle, visual_mode: u32, }; pub const EventMessageOverlay = extern struct { // which EventType? - response: u32, + response: MessageOverlayResponse, }; pub const PropertyContainerHandle = u64; pub const EventProperty = extern struct { @@ -2369,6 +2369,18 @@ pub const FirmwareErrorCode = enum(i32) { } }; +pub const VRState = enum(u32) { + undefined = -1, + off = 0, + searching = 1, + searching_alert = 2, + ready = 3, + ready_alert = 4, + not_ready = 5, + standby = 6, + ready_alert_low = 7, +}; + pub const EventType = enum(i32) { none = 0, tracked_device_activated = 100, @@ -2783,8 +2795,6 @@ pub const OverlayFlags = packed struct(u32) { Reserved = @bitCast(OverlayFlags{ .reserved = true }), EnableClickStabilization = @bitCast(OverlayFlags{ .enable_click_stabilization = true }), MultiCursor = @bitCast(OverlayFlags{ .multi_cursor = true }), - - _, }; }; @@ -2884,3 +2894,21 @@ pub const GamepadTextInputLineMode = enum(i32) { single_line = 0, multiple_lines = 1, }; + +pub const MessageOverlayResponse = enum(u32) { + button_press_0 = 0, + button_press_1 = 1, + button_press_2 = 2, + button_press_3 = 3, + couldnt_find_system_overlay = 4, + couldnt_find_or_create_client_overlay = 5, + application_quit = 6, +}; + +pub const VRMouseButton = packed struct(u32) { + Left: bool = false, + Right: bool = false, + Middle: bool = false, + + _padding: u29 = 0, +}; From 12207d4d75dde51092c05fbb324b4e9e3ddf25e3 Mon Sep 17 00:00:00 2001 From: zivoy Date: Mon, 1 Jul 2024 16:56:58 -0400 Subject: [PATCH 10/44] implemented more functions --- libs/zopenvr/src/overlay.zig | 332 ++++++++++++++++++++++++++--------- 1 file changed, 245 insertions(+), 87 deletions(-) diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 39ff2435a..707aa79a4 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -13,8 +13,11 @@ pub fn init() common.InitError!Self { }; } -pub fn findOverlay(_: Self) void { - @compileError("not implemented"); +pub fn findOverlay(self: Self, overlay_key: [:0]const u8) common.OverlayError!common.OverlayHandle { + var handle: common.OverlayHandle = undefined; + const overlay_error = self.function_table.FindOverlay(overlay_key.ptr, &handle); + try overlay_error.maybe(); + return handle; } pub fn createOverlay(self: Self, overlay_key: [:0]const u8, overlay_name: [:0]const u8) common.OverlayError!common.OverlayHandle { @@ -24,28 +27,60 @@ pub fn createOverlay(self: Self, overlay_key: [:0]const u8, overlay_name: [:0]co return handle; } -pub fn destroyOverlay(_: Self) void { - @compileError("not implemented"); +pub fn destroyOverlay(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { + try self.function_table.DestroyOverlay(overlay_handle).maybe(); } -pub fn getOverlayKey(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayKey(self: Self, allocator: std.mem.Allocator, overlay_handle: common.OverlayHandle) (common.OverlayError || error{OutOfMemory})![:0]u8 { + var error_code: common.OverlayErrorCode = undefined; + const buffer_length = self.function_table.GetOverlayKey(overlay_handle, null, 0, &error_code); + try error_code.maybe(); + if (buffer_length == 0) { + return allocator.allocSentinel(u8, 0, 0); + } + + const buffer = try allocator.allocSentinel(u8, buffer_length - 1, 0); + errdefer allocator.free(buffer); + + if (buffer.len > 0) { + error_code = undefined; + _ = self.function_table.GetOverlayKey(overlay_handle, buffer.ptr, buffer_length, &error_code); + try error_code.maybe(); + } + + return buffer; } -pub fn getOverlayName(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayName(self: Self, allocator: std.mem.Allocator, overlay_handle: common.OverlayHandle) (common.OverlayError || error{OutOfMemory})![:0]u8 { + var error_code: common.OverlayErrorCode = undefined; + const buffer_length = self.function_table.GetOverlayName(overlay_handle, null, 0, &error_code); + try error_code.maybe(); + if (buffer_length == 0) { + return allocator.allocSentinel(u8, 0, 0); + } + + const buffer = try allocator.allocSentinel(u8, buffer_length - 1, 0); + errdefer allocator.free(buffer); + + if (buffer.len > 0) { + error_code = undefined; + _ = self.function_table.GetOverlayName(overlay_handle, buffer.ptr, buffer_length, &error_code); + try error_code.maybe(); + } + + return buffer; } -pub fn setOverlayName(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayName(self: Self, overlay_handle: common.OverlayHandle, name: [:0]const u8) common.OverlayError!void { + try self.function_table.SetOverlayName(overlay_handle, name.ptr).maybe(); } pub fn getOverlayImageData(_: Self) void { @compileError("not implemented"); } -pub fn getOverlayErrorNameFromEnum(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayErrorNameFromEnum(self: Self, overlay_error: common.OverlayErrorCode) [:0]const u8 { + return std.mem.span(self.function_table.GetOverlayErrorNameFromEnum(overlay_error)); } pub fn setOverlayRenderingPid(_: Self) void { @@ -152,7 +187,12 @@ pub fn getOverlayTransformAbsolute(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTransformTrackedDeviceRelative(self: Self, overlay_handle: common.OverlayHandle, tracked_device: common.TrackedDeviceIndex, tracked_device_to_overlay_transform: common.Matrix34) common.OverlayError!void { +pub fn setOverlayTransformTrackedDeviceRelative( + self: Self, + overlay_handle: common.OverlayHandle, + tracked_device: common.TrackedDeviceIndex, + tracked_device_to_overlay_transform: common.Matrix34, +) common.OverlayError!void { try self.function_table.SetOverlayTransformTrackedDeviceRelative(overlay_handle, tracked_device, &tracked_device_to_overlay_transform).maybe(); } @@ -184,8 +224,8 @@ pub fn showOverlay(self: Self, overlay_handle: common.OverlayHandle) common.Over try self.function_table.ShowOverlay(overlay_handle).maybe(); } -pub fn hideOverlay(_: Self) void { - @compileError("not implemented"); +pub fn hideOverlay(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { + try self.function_table.HideOverlay(overlay_handle).maybe(); } pub fn isOverlayVisible(_: Self) void { @@ -208,145 +248,263 @@ pub fn pollNextOverlayEvent(self: Self, overlay_handle: common.OverlayHandle) ?c return null; } -pub fn getOverlayInputMethod(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayInputMethod(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!common.OverlayInputMethod { + var input_method: common.OverlayInputMethod = undefined; + try self.function_table.GetOverlayInputMethod(overlay_handle, &input_method).maybe(); + return input_method; } -pub fn setOverlayInputMethod(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayInputMethod(self: Self, overlay_handle: common.OverlayHandle, input_method: common.OverlayInputMethod) common.OverlayError!void { + try self.function_table.SetOverlayInputMethod(overlay_handle, input_method).maybe(); } -pub fn getOverlayMouseScale(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayMouseScale(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!common.Vector2 { + var mouse_scale: common.Vector2 = undefined; + try self.function_table.GetOverlayMouseScale(overlay_handle, &mouse_scale).maybe(); + return mouse_scale; } -pub fn setOverlayMouseScale(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayMouseScale(self: Self, overlay_handle: common.OverlayHandle, mouse_scale: common.Vector2) common.OverlayError!void { + try self.function_table.SetOverlayMouseScale(overlay_handle, &mouse_scale).maybe(); } -pub fn computeOverlayIntersection(_: Self) void { - @compileError("not implemented"); +pub fn computeOverlayIntersection(self: Self, overlay_handle: common.OverlayHandle, params: common.OverlayIntersectionParams) ?common.OverlayIntersectionResults { + var results: common.OverlayIntersectionResults = undefined; + if (self.function_table.ComputeOverlayIntersection(overlay_handle, ¶ms, &results)) { + return results; + } + return null; } -pub fn isHoverTargetOverlay(_: Self) void { - @compileError("not implemented"); +pub fn isHoverTargetOverlay(self: Self, overlay_handle: common.OverlayHandle) bool { + return self.function_table.IsHoverTargetOverlay(overlay_handle); } -pub fn setOverlayIntersectionMask(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayIntersectionMask(self: Self, overlay_handle: common.OverlayHandle, mask_primitives: []common.OverlayIntersectionMaskPrimitive) common.OverlayError!void { + const err = self.function_table.SetOverlayIntersectionMask( + overlay_handle, + mask_primitives.ptr, + mask_primitives.len, + @sizeOf(common.OverlayIntersectionMaskPrimitive), + ); + try err.maybe(); } -pub fn triggerLaserMouseHapticVibration(_: Self) void { - @compileError("not implemented"); +pub fn triggerLaserMouseHapticVibration(self: Self, overlay_handle: common.OverlayError, duration_seconds: f32, frequency: f32, amplitude: f32) common.OverlayError!void { + try self.function_table.TriggerLaserMouseHapticVibration(overlay_handle, duration_seconds, frequency, amplitude).maybe(); } -pub fn setOverlayCursor(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayCursor(self: Self, overlay_handle: common.OverlayHandle, cursor_handle: common.OverlayHandle) common.OverlayError!void { + try self.function_table.SetOverlayCursor(overlay_handle, cursor_handle).maybe(); } -pub fn setOverlayCursorPositionOverride(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayCursorPositionOverride(self: Self, overlay_handle: common.OverlayHandle, cursor: common.Vector2) common.OverlayError!void { + try self.function_table.SetOverlayCursorPositionOverride(overlay_handle, cursor.ptr).maybe(); } -pub fn clearOverlayCursorPositionOverride(_: Self) void { - @compileError("not implemented"); +pub fn clearOverlayCursorPositionOverride(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { + try self.function_table.ClearOverlayCursorPositionOverride(overlay_handle).maybe(); } -pub fn setOverlayTexture(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayTexture(self: Self, overlay_handle: common.OverlayHandle, texture: common.Texture) common.OverlayError!void { + try self.function_table.SetOverlayTexture(overlay_handle, texture.ptr).maybe(); } -pub fn clearOverlayTexture(_: Self) void { - @compileError("not implemented"); +pub fn clearOverlayTexture(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { + try self.function_table.ClearOverlayTexture(overlay_handle).maybe(); } -pub fn setOverlayRaw(self: Self, comptime T: type, overlay_handle: common.OverlayHandle, buffer: [*]T, width: u32, height: u32, bytes_per_pixel: u32) common.OverlayError!void { - std.debug.assert(@typeInfo(T) == .Int); +pub fn setOverlayRaw( + self: Self, + comptime T: type, + overlay_handle: common.OverlayHandle, + buffer: [*]T, + width: u32, + height: u32, + bytes_per_pixel: u32, +) common.OverlayError!void { + comptime { + const type_info = @typeInfo(T); + if (type_info == .Int) { + if (type_info.Int.bits % 8 != 0) { + @compileError("int needs to be a whole number of bytes"); + } + } else if (type_info == .Struct) { + if (type_info.Struct.layout != .@"packed") { + @compileError("struct needs to be packed"); + } + if (type_info.Struct.backing_integer % 8 != 0) { + @compileError("struct needs to be a whole number of bytes big"); + } + } else { + @compileError("type '" ++ @typeName(T) ++ "' is not allowed here"); + } + } try self.function_table.SetOverlayRaw(overlay_handle, buffer, width, height, bytes_per_pixel).maybe(); } -pub fn setOverlayFromFile(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayFromFile(self: Self, overlay_handle: common.OverlayHandle, file_path: [:0]const u8) common.OverlayError!void { + try self.function_table.SetOverlayFromFile(overlay_handle, file_path.ptr).maybe(); } -pub fn getOverlayTexture(_: Self) void { +pub fn getOverlayTexture(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct {} { + _ = self; + _ = overlay_handle; @compileError("not implemented"); } -pub fn releaseNativeOverlayHandle(_: Self) void { - @compileError("not implemented"); +pub fn releaseNativeOverlayHandle(self: Self, overlay_handle: common.OverlayHandle, native_texture_handle: anyopaque) common.OverlayError!void { + try self.function_table.ReleaseNativeOverlayHandle(overlay_handle, native_texture_handle).maybe(); } -pub fn getOverlayTextureSize(_: Self) void { - @compileError("not implemented"); -} +pub fn getOverlayTextureSize(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct { width: u32, height: u32 } { + var width: u32 = undefined; + var height: u32 = undefined; + try self.function_table.GetOverlayTextureSize(overlay_handle, &width, &height).maybe(); -pub fn createDashboardOverlay(_: Self) void { - @compileError("not implemented"); + return .{ + .width = width, + .height = height, + }; } -pub fn isDashboardVisible(_: Self) void { - @compileError("not implemented"); +pub fn createDashboardOverlay(self: Self, overlay_key: [:0]const u8, overlay_friendly_name: [:0]const u8) common.OverlayError!struct { + overlay_handle: common.OverlayHandle, + thumbail_handle: common.OverlayHandle, +} { + var overlay_handle: common.OverlayHandle = undefined; + var thumbail_handle: common.OverlayHandle = undefined; + const err = self.function_table.CreateDashboardOverlay(overlay_key.ptr, overlay_friendly_name.ptr, &overlay_handle, &thumbail_handle); + try err.maybe(); + + return .{ + .overlay_handle = overlay_handle, + .thumbnail_handle = overlay_handle, + }; } -pub fn isActiveDashboardOverlay(_: Self) void { - @compileError("not implemented"); +pub fn isDashboardVisible(self: Self) bool { + return self.function_table.IsDashboardVisible(); } -pub fn setDashboardOverlaySceneProcess(_: Self) void { - @compileError("not implemented"); +pub fn isActiveDashboardOverlay(self: Self, overlay_handle: common.OverlayHandle) bool { + return self.function_table.IsActiveDashboardOverlay(overlay_handle); } -pub fn getDashboardOverlaySceneProcess(_: Self) void { - @compileError("not implemented"); +pub fn setDashboardOverlaySceneProcess(self: Self, overlay_handle: common.OverlayHandle, process_id: u32) common.OverlayError!void { + try self.function_table.SetDashboardOverlaySceneProcess(overlay_handle, process_id).maybe(); } -pub fn showDashboard(_: Self) void { - @compileError("not implemented"); +pub fn getDashboardOverlaySceneProcess(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!u32 { + var process_id: u32 = undefined; + try self.function_table.GetDashboardOverlaySceneProcess(overlay_handle, &process_id).maybe(); + return process_id; } -pub fn getPrimaryDashboardDevice(_: Self) void { - @compileError("not implemented"); +pub fn showDashboard(self: Self, overlay_to_show: [:0]const u8) void { + self.function_table.ShowDashboard(overlay_to_show.ptr); } -pub fn showKeyboard(_: Self) void { - @compileError("not implemented"); +pub fn getPrimaryDashboardDevice(self: Self) common.TrackedDeviceIndex { + return self.function_table.GetPrimaryDashboardDevice(); } -pub fn showKeyboardForOverlay(_: Self) void { - @compileError("not implemented"); +pub fn showKeyboard( + self: Self, + input_mode: common.GamepadTextInputMode, + line_input_more: common.GamepadTextInputLineMode, + flags: common.KeyboardFlags, + description: [:0]const u8, + max_characters: u32, + existing_text: [:0]const u8, + user_value: u64, +) common.OverlayError!void { + const err = self.function_table.ShowKeyboard( + input_mode, + line_input_more, + flags, + description.ptr, + max_characters, + existing_text.ptr, + user_value, + ); + try err.maybe(); } -pub fn getKeyboardText(_: Self) void { - @compileError("not implemented"); +pub fn showKeyboardForOverlay( + self: Self, + overlay_handle: common.OverlayHandle, + input_mode: common.GamepadTextInputMode, + line_input_more: common.GamepadTextInputLineMode, + flags: common.KeyboardFlags, + description: [:0]const u8, + max_characters: u32, + existing_text: [:0]const u8, + user_value: u64, +) common.OverlayError!void { + const err = self.function_table.ShowKeyboardForOverlay( + overlay_handle, + input_mode, + line_input_more, + flags, + description.ptr, + max_characters, + existing_text.ptr, + user_value, + ); + try err.maybe(); } -pub fn hideKeyboard(_: Self) void { - @compileError("not implemented"); +// todo check if max length is the same as max chars from above or one off +pub fn getKeyboardText(self: Self, allocator: std.mem.Allocator, max_length: u32) error{OutOfMemory}![:0]u8 { + const buffer = try allocator.allocSentinel(u8, max_length - 1, 0); + const size = self.function_table.GetKeyboardText(buffer.ptr, max_length); + _ = size; + + return buffer; } -pub fn setKeyboardTransformAbsolute(_: Self) void { - @compileError("not implemented"); +pub fn hideKeyboard(self: Self) void { + self.function_table.HideKeyboard(); } -pub fn setKeyboardPositionForOverlay(_: Self) void { - @compileError("not implemented"); +pub fn setKeyboardTransformAbsolute(self: Self, tracking_origin: common.TrackingUniverseOrigin, tracking_origin_to_keyboard_transform: common.Matrix34) void { + self.function_table.SetKeyboardTransformAbsolute(tracking_origin, &tracking_origin_to_keyboard_transform); } -pub fn showMessageOverlay(_: Self) void { - @compileError("not implemented"); +pub fn setKeyboardPositionForOverlay(self: Self, overlay_handle: common.OverlayHandle, avoid_rect: common.Rect2) void { + self.function_table.SetKeyboardPositionForOverlay(overlay_handle, avoid_rect); } -pub fn closeMessageOverlay(_: Self) void { - @compileError("not implemented"); +pub fn showMessageOverlay( + self: Self, + text: [:0]const u8, + caption: [:0]const u8, + button0_text: [:0]const u8, + button1_text: ?[:0]const u8, + button2_text: ?[:0]const u8, + button3_text: ?[:0]const u8, +) common.MessageOverlayResponse { + return self.function_table.ShowMessageOverlay( + text.ptr, + caption.ptr, + button0_text.ptr, + if (button1_text) |str| str.ptr else null, + if (button2_text) |str| str.ptr else null, + if (button3_text) |str| str.ptr else null, + ); +} + +pub fn closeMessageOverlay(self: Self) void { + self.function_table.CloseMessageOverlay(); } const FunctionTable = extern struct { FindOverlay: *const fn ([*c]const u8, *common.OverlayHandle) callconv(.C) common.OverlayErrorCode, CreateOverlay: *const fn ([*c]const u8, [*c]const u8, *common.OverlayHandle) callconv(.C) common.OverlayErrorCode, DestroyOverlay: *const fn (common.OverlayHandle) callconv(.C) common.OverlayErrorCode, - GetOverlayKey: *const fn (common.OverlayHandle, [*c]const u8, u32, *common.OverlayErrorCode) callconv(.C) u32, - GetOverlayName: *const fn (common.OverlayHandle, [*c]const u8, u32, *common.OverlayErrorCode) callconv(.C) u32, + GetOverlayKey: *const fn (common.OverlayHandle, [*c]u8, u32, *common.OverlayErrorCode) callconv(.C) u32, + GetOverlayName: *const fn (common.OverlayHandle, [*c]u8, u32, *common.OverlayErrorCode) callconv(.C) u32, SetOverlayName: *const fn (common.OverlayHandle, [*c]const u8) callconv(.C) common.OverlayErrorCode, GetOverlayImageData: *const fn (common.OverlayHandle, ?*anyopaque, u32, *u32, *u32) callconv(.C) common.OverlayErrorCode, GetOverlayErrorNameFromEnum: *const fn (common.OverlayErrorCode) callconv(.C) [*c]const u8, @@ -397,7 +555,7 @@ const FunctionTable = extern struct { SetOverlayMouseScale: *const fn (common.OverlayHandle, *const common.Vector2) callconv(.C) common.OverlayErrorCode, ComputeOverlayIntersection: *const fn (common.OverlayHandle, *const common.OverlayIntersectionParams, *common.OverlayIntersectionResults) callconv(.C) bool, IsHoverTargetOverlay: *const fn (common.OverlayHandle) callconv(.C) bool, - SetOverlayIntersectionMask: *const fn (common.OverlayHandle, *common.OverlayIntersectionMaskPrimitive, u32, u32) callconv(.C) common.OverlayErrorCode, + SetOverlayIntersectionMask: *const fn (common.OverlayHandle, [*c]common.OverlayIntersectionMaskPrimitive, u32, u32) callconv(.C) common.OverlayErrorCode, TriggerLaserMouseHapticVibration: *const fn (common.OverlayHandle, f32, f32, f32) callconv(.C) common.OverlayErrorCode, SetOverlayCursor: *const fn (common.OverlayHandle, common.OverlayHandle) callconv(.C) common.OverlayErrorCode, SetOverlayCursorPositionOverride: *const fn (common.OverlayHandle, *const common.Vector2) callconv(.C) common.OverlayErrorCode, @@ -416,16 +574,16 @@ const FunctionTable = extern struct { IsActiveDashboardOverlay: *const fn (common.OverlayHandle) callconv(.C) bool, SetDashboardOverlaySceneProcess: *const fn (common.OverlayHandle, u32) callconv(.C) common.OverlayErrorCode, GetDashboardOverlaySceneProcess: *const fn (common.OverlayHandle, *u32) callconv(.C) common.OverlayErrorCode, - ShowDashboard: *const fn ([*c]const u8) callconv(.C) common.OverlayErrorCode, + ShowDashboard: *const fn ([*c]const u8) callconv(.C) void, GetPrimaryDashboardDevice: *const fn () callconv(.C) common.TrackedDeviceIndex, ShowKeyboard: *const fn (common.GamepadTextInputMode, common.GamepadTextInputLineMode, common.KeyboardFlags, [*c]const u8, u32, [*c]const u8, u64) callconv(.C) common.OverlayErrorCode, ShowKeyboardForOverlay: *const fn (common.OverlayHandle, common.GamepadTextInputMode, common.GamepadTextInputLineMode, common.KeyboardFlags, [*c]const u8, u32, [*c]const u8, u64) callconv(.C) common.OverlayErrorCode, - GetKeyboardText: *const fn ([*c]const u8, u32) callconv(.C) u32, + GetKeyboardText: *const fn ([*c]u8, u32) callconv(.C) u32, HideKeyboard: *const fn () callconv(.C) void, SetKeyboardTransformAbsolute: *const fn (common.TrackingUniverseOrigin, *const common.Matrix34) callconv(.C) void, SetKeyboardPositionForOverlay: *const fn (common.OverlayHandle, common.Rect2) callconv(.C) void, - ShowMessageOverlay: *const fn ([*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8) callconv(.C) void, + ShowMessageOverlay: *const fn ([*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8, [*c]const u8) callconv(.C) common.MessageOverlayResponse, CloseMessageOverlay: *const fn () callconv(.C) void, }; From 849366d642fb759cfc33577e36d5e98774362464 Mon Sep 17 00:00:00 2001 From: zivoy Date: Mon, 1 Jul 2024 17:59:35 -0400 Subject: [PATCH 11/44] return errors instead of trying them --- libs/zopenvr/src/overlay.zig | 85 +++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 707aa79a4..eca8cf4f6 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -28,7 +28,7 @@ pub fn createOverlay(self: Self, overlay_key: [:0]const u8, overlay_name: [:0]co } pub fn destroyOverlay(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { - try self.function_table.DestroyOverlay(overlay_handle).maybe(); + return self.function_table.DestroyOverlay(overlay_handle).maybe(); } pub fn getOverlayKey(self: Self, allocator: std.mem.Allocator, overlay_handle: common.OverlayHandle) (common.OverlayError || error{OutOfMemory})![:0]u8 { @@ -72,7 +72,7 @@ pub fn getOverlayName(self: Self, allocator: std.mem.Allocator, overlay_handle: } pub fn setOverlayName(self: Self, overlay_handle: common.OverlayHandle, name: [:0]const u8) common.OverlayError!void { - try self.function_table.SetOverlayName(overlay_handle, name.ptr).maybe(); + return self.function_table.SetOverlayName(overlay_handle, name.ptr).maybe(); } pub fn getOverlayImageData(_: Self) void { @@ -83,12 +83,12 @@ pub fn getOverlayErrorNameFromEnum(self: Self, overlay_error: common.OverlayErro return std.mem.span(self.function_table.GetOverlayErrorNameFromEnum(overlay_error)); } -pub fn setOverlayRenderingPid(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayRenderingPid(self: Self, overlay_handle: common.OverlayHandle, pid: u32) common.OverlayError!void { + return self.function_table.SetOverlayRenderingPid(overlay_handle, pid).maybe(); } -pub fn getOverlayRenderingPid(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayRenderingPid(self: Self, overlay_handle: common.OverlayHandle) u32 { + return self.function_table.GetOverlayRenderingPid(overlay_handle); } pub fn setOverlayFlag(_: Self) void { @@ -104,7 +104,7 @@ pub fn getOverlayFlags(_: Self) void { } pub fn setOverlayColor(self: Self, overlay_handle: common.OverlayHandle, red: f32, green: f32, blue: f32) common.OverlayError!void { - try self.function_table.SetOverlayColor(overlay_handle, red, green, blue).maybe(); + return self.function_table.SetOverlayColor(overlay_handle, red, green, blue).maybe(); } pub fn getOverlayColor(_: Self) void { @@ -136,7 +136,7 @@ pub fn getOverlaySortOrder(_: Self) void { } pub fn setOverlayWidthInMeters(self: Self, overlay_handle: common.OverlayHandle, width_in_meters: f32) common.OverlayError!void { - try self.function_table.SetOverlayWidthInMeters(overlay_handle, width_in_meters).maybe(); + return self.function_table.SetOverlayWidthInMeters(overlay_handle, width_in_meters).maybe(); } pub fn getOverlayWidthInMeters(_: Self) void { @@ -168,7 +168,7 @@ pub fn getOverlayTextureColorSpace(_: Self) void { } pub fn setOverlayTextureBounds(self: Self, overlay_handle: common.OverlayHandle, overlay_texture_bounds: common.TextureBounds) common.OverlayError!void { - try self.function_table.SetOverlayTextureBounds(overlay_handle, &overlay_texture_bounds).maybe(); + return self.function_table.SetOverlayTextureBounds(overlay_handle, &overlay_texture_bounds).maybe(); } pub fn getOverlayTextureBounds(_: Self) void { @@ -193,7 +193,12 @@ pub fn setOverlayTransformTrackedDeviceRelative( tracked_device: common.TrackedDeviceIndex, tracked_device_to_overlay_transform: common.Matrix34, ) common.OverlayError!void { - try self.function_table.SetOverlayTransformTrackedDeviceRelative(overlay_handle, tracked_device, &tracked_device_to_overlay_transform).maybe(); + const err = self.function_table.SetOverlayTransformTrackedDeviceRelative( + overlay_handle, + tracked_device, + &tracked_device_to_overlay_transform, + ); + return err.maybe(); } pub fn getOverlayTransformTrackedDeviceRelative(_: Self) void { @@ -221,11 +226,11 @@ pub fn setOverlayTransformProjection(_: Self) void { } pub fn showOverlay(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { - try self.function_table.ShowOverlay(overlay_handle).maybe(); + return self.function_table.ShowOverlay(overlay_handle).maybe(); } pub fn hideOverlay(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { - try self.function_table.HideOverlay(overlay_handle).maybe(); + return self.function_table.HideOverlay(overlay_handle).maybe(); } pub fn isOverlayVisible(_: Self) void { @@ -254,8 +259,12 @@ pub fn getOverlayInputMethod(self: Self, overlay_handle: common.OverlayHandle) c return input_method; } -pub fn setOverlayInputMethod(self: Self, overlay_handle: common.OverlayHandle, input_method: common.OverlayInputMethod) common.OverlayError!void { - try self.function_table.SetOverlayInputMethod(overlay_handle, input_method).maybe(); +pub fn setOverlayInputMethod( + self: Self, + overlay_handle: common.OverlayHandle, + input_method: common.OverlayInputMethod, +) common.OverlayError!void { + return self.function_table.SetOverlayInputMethod(overlay_handle, input_method).maybe(); } pub fn getOverlayMouseScale(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!common.Vector2 { @@ -265,10 +274,14 @@ pub fn getOverlayMouseScale(self: Self, overlay_handle: common.OverlayHandle) co } pub fn setOverlayMouseScale(self: Self, overlay_handle: common.OverlayHandle, mouse_scale: common.Vector2) common.OverlayError!void { - try self.function_table.SetOverlayMouseScale(overlay_handle, &mouse_scale).maybe(); + return self.function_table.SetOverlayMouseScale(overlay_handle, &mouse_scale).maybe(); } -pub fn computeOverlayIntersection(self: Self, overlay_handle: common.OverlayHandle, params: common.OverlayIntersectionParams) ?common.OverlayIntersectionResults { +pub fn computeOverlayIntersection( + self: Self, + overlay_handle: common.OverlayHandle, + params: common.OverlayIntersectionParams, +) ?common.OverlayIntersectionResults { var results: common.OverlayIntersectionResults = undefined; if (self.function_table.ComputeOverlayIntersection(overlay_handle, ¶ms, &results)) { return results; @@ -280,38 +293,48 @@ pub fn isHoverTargetOverlay(self: Self, overlay_handle: common.OverlayHandle) bo return self.function_table.IsHoverTargetOverlay(overlay_handle); } -pub fn setOverlayIntersectionMask(self: Self, overlay_handle: common.OverlayHandle, mask_primitives: []common.OverlayIntersectionMaskPrimitive) common.OverlayError!void { +pub fn setOverlayIntersectionMask( + self: Self, + overlay_handle: common.OverlayHandle, + mask_primitives: []common.OverlayIntersectionMaskPrimitive, +) common.OverlayError!void { const err = self.function_table.SetOverlayIntersectionMask( overlay_handle, mask_primitives.ptr, mask_primitives.len, @sizeOf(common.OverlayIntersectionMaskPrimitive), ); - try err.maybe(); + return err.maybe(); } -pub fn triggerLaserMouseHapticVibration(self: Self, overlay_handle: common.OverlayError, duration_seconds: f32, frequency: f32, amplitude: f32) common.OverlayError!void { - try self.function_table.TriggerLaserMouseHapticVibration(overlay_handle, duration_seconds, frequency, amplitude).maybe(); +pub fn triggerLaserMouseHapticVibration( + self: Self, + overlay_handle: common.OverlayError, + duration_seconds: f32, + frequency: f32, + amplitude: f32, +) common.OverlayError!void { + return self.function_table.TriggerLaserMouseHapticVibration(overlay_handle, duration_seconds, frequency, amplitude).maybe(); } pub fn setOverlayCursor(self: Self, overlay_handle: common.OverlayHandle, cursor_handle: common.OverlayHandle) common.OverlayError!void { - try self.function_table.SetOverlayCursor(overlay_handle, cursor_handle).maybe(); + return self.function_table.SetOverlayCursor(overlay_handle, cursor_handle).maybe(); } pub fn setOverlayCursorPositionOverride(self: Self, overlay_handle: common.OverlayHandle, cursor: common.Vector2) common.OverlayError!void { - try self.function_table.SetOverlayCursorPositionOverride(overlay_handle, cursor.ptr).maybe(); + return self.function_table.SetOverlayCursorPositionOverride(overlay_handle, cursor.ptr).maybe(); } pub fn clearOverlayCursorPositionOverride(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { - try self.function_table.ClearOverlayCursorPositionOverride(overlay_handle).maybe(); + return self.function_table.ClearOverlayCursorPositionOverride(overlay_handle).maybe(); } pub fn setOverlayTexture(self: Self, overlay_handle: common.OverlayHandle, texture: common.Texture) common.OverlayError!void { - try self.function_table.SetOverlayTexture(overlay_handle, texture.ptr).maybe(); + return self.function_table.SetOverlayTexture(overlay_handle, texture.ptr).maybe(); } pub fn clearOverlayTexture(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { - try self.function_table.ClearOverlayTexture(overlay_handle).maybe(); + return self.function_table.ClearOverlayTexture(overlay_handle).maybe(); } pub fn setOverlayRaw( @@ -340,11 +363,11 @@ pub fn setOverlayRaw( @compileError("type '" ++ @typeName(T) ++ "' is not allowed here"); } } - try self.function_table.SetOverlayRaw(overlay_handle, buffer, width, height, bytes_per_pixel).maybe(); + return self.function_table.SetOverlayRaw(overlay_handle, buffer, width, height, bytes_per_pixel).maybe(); } pub fn setOverlayFromFile(self: Self, overlay_handle: common.OverlayHandle, file_path: [:0]const u8) common.OverlayError!void { - try self.function_table.SetOverlayFromFile(overlay_handle, file_path.ptr).maybe(); + return self.function_table.SetOverlayFromFile(overlay_handle, file_path.ptr).maybe(); } pub fn getOverlayTexture(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct {} { @@ -354,7 +377,7 @@ pub fn getOverlayTexture(self: Self, overlay_handle: common.OverlayHandle) commo } pub fn releaseNativeOverlayHandle(self: Self, overlay_handle: common.OverlayHandle, native_texture_handle: anyopaque) common.OverlayError!void { - try self.function_table.ReleaseNativeOverlayHandle(overlay_handle, native_texture_handle).maybe(); + return self.function_table.ReleaseNativeOverlayHandle(overlay_handle, native_texture_handle).maybe(); } pub fn getOverlayTextureSize(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct { width: u32, height: u32 } { @@ -392,7 +415,7 @@ pub fn isActiveDashboardOverlay(self: Self, overlay_handle: common.OverlayHandle } pub fn setDashboardOverlaySceneProcess(self: Self, overlay_handle: common.OverlayHandle, process_id: u32) common.OverlayError!void { - try self.function_table.SetDashboardOverlaySceneProcess(overlay_handle, process_id).maybe(); + return self.function_table.SetDashboardOverlaySceneProcess(overlay_handle, process_id).maybe(); } pub fn getDashboardOverlaySceneProcess(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!u32 { @@ -428,7 +451,7 @@ pub fn showKeyboard( existing_text.ptr, user_value, ); - try err.maybe(); + return err.maybe(); } pub fn showKeyboardForOverlay( @@ -452,7 +475,7 @@ pub fn showKeyboardForOverlay( existing_text.ptr, user_value, ); - try err.maybe(); + return err.maybe(); } // todo check if max length is the same as max chars from above or one off From 6653008d187acdc3a3502b1325b4e05f85b0323d Mon Sep 17 00:00:00 2001 From: zivoy Date: Mon, 1 Jul 2024 19:56:56 -0400 Subject: [PATCH 12/44] implemented even more functions --- libs/zopenvr/src/overlay.zig | 213 +++++++++++++++++++++++++---------- 1 file changed, 155 insertions(+), 58 deletions(-) diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index eca8cf4f6..83c9fdd7e 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -91,100 +91,159 @@ pub fn getOverlayRenderingPid(self: Self, overlay_handle: common.OverlayHandle) return self.function_table.GetOverlayRenderingPid(overlay_handle); } -pub fn setOverlayFlag(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayFlag(self: Self, overlay_handle: common.OverlayHandle, flag: common.OverlayFlags.Enum, enabled: bool) common.OverlayError!void { + return self.function_table.SetOverlayFlag(overlay_handle, flag, enabled).maybe(); } -pub fn getOverlayFlag(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayFlag(self: Self, overlay_handle: common.OverlayHandle, flag: common.OverlayFlags.Enum) common.OverlayError!bool { + var enabled: bool = undefined; + try self.function_table.GetOverlayFlag(overlay_handle, flag, &enabled).maybe(); + return enabled; } -pub fn getOverlayFlags(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayFlags(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!common.OverlayFlags { + var flags: common.OverlayFlags = undefined; + try self.function_table.GetOverlayFlags(overlay_handle, &flags).maybe(); + return flags; } pub fn setOverlayColor(self: Self, overlay_handle: common.OverlayHandle, red: f32, green: f32, blue: f32) common.OverlayError!void { return self.function_table.SetOverlayColor(overlay_handle, red, green, blue).maybe(); } -pub fn getOverlayColor(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayColor(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct { red: f32, green: f32, blue: f32 } { + var red: f32 = undefined; + var green: f32 = undefined; + var blue: f32 = undefined; + try self.function_table.GetOverlayColor(overlay_handle, &red, &green, &blue).maybe(); + + return .{ + .red = red, + .green = green, + .blue = blue, + }; } -pub fn setOverlayAlpha(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayAlpha(self: Self, overlay_handle: common.OverlayHandle, alpha: f32) common.OverlayError!void { + return self.function_table.SetOverlayAlpha(overlay_handle, alpha).maybe(); } -pub fn getOverlayAlpha(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayAlpha(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { + var alpha: f32 = undefined; + try self.function_table.GetOverlayAlpha(overlay_handle, &alpha); + return alpha; } -pub fn setOverlayTexelAspect(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayTexelAspect(self: Self, overlay_handle: common.OverlayHandle, texel_aspect: f32) common.OverlayError!void { + return self.function_table.SetOverlayTexelAspect(overlay_handle, texel_aspect).maybe(); } -pub fn getOverlayTexelAspect(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayTexelAspect(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { + var texel_aspect: f32 = undefined; + try self.function_table.GetOverlayTexelAspect(overlay_handle, &texel_aspect).maybe(); + return texel_aspect; } -pub fn setOverlaySortOrder(_: Self) void { - @compileError("not implemented"); +pub fn setOverlaySortOrder(self: Self, overlay_handle: common.OverlayHandle, sort_order: u32) common.OverlayError!void { + return self.function_table.SetOverlaySortOrder(overlay_handle, sort_order).maybe(); } -pub fn getOverlaySortOrder(_: Self) void { - @compileError("not implemented"); +pub fn getOverlaySortOrder(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!u32 { + var sort_order: u32 = undefined; + try self.function_table.GetOverlaySortOrder(overlay_handle, &sort_order); + return sort_order; } pub fn setOverlayWidthInMeters(self: Self, overlay_handle: common.OverlayHandle, width_in_meters: f32) common.OverlayError!void { return self.function_table.SetOverlayWidthInMeters(overlay_handle, width_in_meters).maybe(); } -pub fn getOverlayWidthInMeters(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayWidthInMeters(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { + var width_in_meters: f32 = undefined; + try self.function_table.GetOverlayWidthInMeters(overlay_handle, &width_in_meters).maybe(); + return width_in_meters; } -pub fn setOverlayCurvature(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayCurvature(self: Self, overlay_handle: common.OverlayHandle, curvature: f32) common.OverlayError!void { + return self.function_table.SetOverlayCurvature(overlay_handle, curvature).maybe(); } -pub fn getOverlayCurvature(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayCurvatureRadius(self: Self, overlay_handle: common.OverlayHandle, radius: f32) common.OverlayError!void { + const width = try self.getOverlayWidthInMeters(overlay_handle); + const curvature = width / (2 * std.math.pi * radius); + return self.setOverlayCurvature(overlay_handle, curvature); } -pub fn setOverlayPreCurvePitch(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayCurvature(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { + var curvature: f32 = undefined; + try self.function_table.GetOverlayCurvature(overlay_handle, &curvature).maybe(); + return curvature; } -pub fn getOverlayPreCurvePitch(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayCurvatureRadius(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { + const width = try self.getOverlayWidthInMeters(overlay_handle); + const curvature = try self.getOverlayCurvature(overlay_handle); + const radius = width / (2 * std.math.pi * curvature); + return radius; } -pub fn setOverlayTextureColorSpace(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayPreCurvePitch(self: Self, overlay_handle: common.OverlayHandle, radians: f32) common.OverlayError!void { + return self.function_table.SetOverlayPreCurvePitch(overlay_handle, radians).maybe(); } -pub fn getOverlayTextureColorSpace(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayPreCurvePitch(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { + var radians: f32 = undefined; + try self.function_table.GetOverlayPreCurvePitch(overlay_handle, &radians).maybe(); + return radians; +} + +pub fn setOverlayTextureColorSpace(self: Self, overlay_handle: common.OverlayHandle, texture_color_space: common.ColorSpace) common.OverlayError!void { + return self.function_table.SetOverlayTextureColorSpace(overlay_handle, texture_color_space).maybe(); +} + +pub fn getOverlayTextureColorSpace(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!common.ColorSpace { + var texture_color_space: common.ColorSpace = undefined; + try self.function_table.GetOverlayTextureColorSpace(overlay_handle, &texture_color_space).maybe(); + return texture_color_space; } pub fn setOverlayTextureBounds(self: Self, overlay_handle: common.OverlayHandle, overlay_texture_bounds: common.TextureBounds) common.OverlayError!void { return self.function_table.SetOverlayTextureBounds(overlay_handle, &overlay_texture_bounds).maybe(); } -pub fn getOverlayTextureBounds(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayTextureBounds(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!common.TextureBounds { + var overlay_texture_bounds: common.TextureBounds = undefined; + try self.function_table.GetOverlayTextureBounds(overlay_handle, &overlay_texture_bounds).maybe(); + return overlay_texture_bounds; } -pub fn getOverlayTransformType(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayTransformType(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!common.OverlayTransformType { + var transform_type: common.OverlayTransformType = undefined; + try self.function_table.GetOverlayTransformType(overlay_handle, &transform_type).maybe(); + return transform_type; } -pub fn setOverlayTransformAbsolute(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayTransformAbsolute( + self: Self, + overlay_handle: common.OverlayHandle, + tracking_origin: common.TrackingUniverseOrigin, + tracking_origin_to_overlay_transform: common.Matrix34, +) common.OverlayError!void { + return self.function_table.SetOverlayTransformAbsolute(overlay_handle, tracking_origin, tracking_origin_to_overlay_transform).maybe(); } -pub fn getOverlayTransformAbsolute(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayTransformAbsolute(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct { + tracking_origin: common.TrackingUniverseOrigin, + tracking_origin_to_overlay_transform: common.Matrix34, +} { + var tracking_origin: common.TrackingUniverseOrigin = undefined; + var tracking_origin_to_overlay_transform: common.Matrix34 = undefined; + try self.function_table.GetOverlayTransformAbsolute(overlay_handle, &tracking_origin, &tracking_origin_to_overlay_transform).maybe(); + + return .{ + .tracking_origin = tracking_origin, + .tracking_origin_to_overlay_transform = tracking_origin_to_overlay_transform, + }; } pub fn setOverlayTransformTrackedDeviceRelative( @@ -201,28 +260,59 @@ pub fn setOverlayTransformTrackedDeviceRelative( return err.maybe(); } -pub fn getOverlayTransformTrackedDeviceRelative(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayTransformTrackedDeviceRelative(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct { + tracked_device: common.TrackedDeviceIndex, + tracked_device_to_overlay_transform: common.Matrix34, +} { + var tracked_device: common.TrackedDeviceIndex = undefined; + var tracked_device_to_overlay_transform: common.Matrix34 = undefined; + const err = self.function_table.GetOverlayTransformTrackedDeviceRelative(overlay_handle, &tracked_device, &tracked_device_to_overlay_transform); + try err.maybe(); + + return .{ + .tracked_device = tracked_device, + .tracked_device_to_overlay_transform = tracked_device_to_overlay_transform, + }; } -pub fn setOverlayTransformTrackedDeviceComponent(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayTransformTrackedDeviceComponent( + self: Self, + overlay_handle: common.OverlayHandle, + device_index: common.TrackedDeviceIndex, + component_name: [:0]const u8, +) common.OverlayError!void { + return self.function_table.SetOverlayTransformTrackedDeviceComponent(overlay_handle, device_index, component_name.ptr); } pub fn getOverlayTransformTrackedDeviceComponent(_: Self) void { @compileError("not implemented"); } -pub fn setOverlayTransformCursor(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayTransformCursor(self: Self, overlay_handle: common.OverlayHandle, hotspot: common.Vector2) common.OverlayError!void { + return self.function_table.SetOverlayTransformCursor(overlay_handle, &hotspot).maybe(); } -pub fn getOverlayTransformCursor(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayTransformCursor(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!common.Vector2 { + var hotspot: common.Vector2 = undefined; + try self.function_table.GetOverlayTransformCursor(overlay_handle, &hotspot).maybe(); + return hotspot; } -pub fn setOverlayTransformProjection(_: Self) void { - @compileError("not implemented"); +pub fn setOverlayTransformProjection( + self: Self, + overlay_handle: common.OverlayHandle, + tracking_origin: common.TrackingUniverseOrigin, + tracking_origin_to_overlay_transform: common.Matrix34, + projection: common.OverlayProjection, + eye: common.Eye, +) common.OverlayError!void { + return self.function_table.SetOverlayTransformProjection( + overlay_handle, + tracking_origin, + &tracking_origin_to_overlay_transform, + &projection, + eye, + ).maybe(); } pub fn showOverlay(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { @@ -233,16 +323,23 @@ pub fn hideOverlay(self: Self, overlay_handle: common.OverlayHandle) common.Over return self.function_table.HideOverlay(overlay_handle).maybe(); } -pub fn isOverlayVisible(_: Self) void { - @compileError("not implemented"); +pub fn isOverlayVisible(self: Self, overlay_handle: common.OverlayHandle) bool { + return self.function_table.IsOverlayVisible(overlay_handle); } -pub fn getTransformForOverlayCoordinates(_: Self) void { - @compileError("not implemented"); +pub fn getTransformForOverlayCoordinates( + self: Self, + overlay_handle: common.OverlayHandle, + tracking_origin: common.TrackingUniverseOrigin, + coordinates_in_overlay: common.Vector2, +) common.OverlayError!common.Matrix34 { + var transform: common.Matrix34 = undefined; + try self.function_table.GetTransformForOverlayCoordinates(overlay_handle, tracking_origin, coordinates_in_overlay, &transform).maybe(); + return transform; } -pub fn waitFrameSync(_: Self) void { - @compileError("not implemented"); +pub fn waitFrameSync(self: Self, timeout_ms: u32) common.OverlayError!void { + return self.function_table.WaitFrameSync(timeout_ms).maybe(); } pub fn pollNextOverlayEvent(self: Self, overlay_handle: common.OverlayHandle) ?common.Event { From 09f62c6e56d0df06fb76a5502b0499e474901a41 Mon Sep 17 00:00:00 2001 From: zivoy Date: Mon, 1 Jul 2024 22:43:05 -0400 Subject: [PATCH 13/44] raw image type --- libs/zopenvr/src/overlay.zig | 120 ++++++++++++++++++++++++++++++----- 1 file changed, 103 insertions(+), 17 deletions(-) diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 83c9fdd7e..fad9cd0f2 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -75,8 +75,90 @@ pub fn setOverlayName(self: Self, overlay_handle: common.OverlayHandle, name: [: return self.function_table.SetOverlayName(overlay_handle, name.ptr).maybe(); } -pub fn getOverlayImageData(_: Self) void { - @compileError("not implemented"); +pub fn RawImage(comptime T: type, comptime bytes_per_pixel: u32) type { + comptime { + switch (@typeInfo(T)) { + .Int => |Int| if (Int.bits % 8 != 0) @compileError("type needs to be a whole number of bytes"), + .Struct => |Struct| { + if (Struct.layout != .@"packed") @compileError("struct needs to be packed"); + if (@typeInfo(Struct.backing_integer.?).Int.bits != 8 * bytes_per_pixel) + @compileError("struct has to be 1 pixel big (u" ++ 8 * bytes_per_pixel ++ ")"); + }, + else => @compileError("type '" ++ @typeName(T) ++ "' is not allowed here"), + } + } + const is_struct = comptime @typeInfo(T) == .Struct; + const type_bytes: u16 = comptime switch (@typeInfo(T)) { + .Struct => |Struct| @typeInfo(Struct.backing_integer.?).Int.bits / 8, + .Int => |Int| Int.bits / 8, + else => unreachable, + }; + + return struct { + const Sself = @This(); + allocator: std.mem.Allocator, + + width: u32, + height: u32, + bytes_per_pixel: u32, + + data: ?[]T = null, + + pub fn init(allocator: std.mem.Allocator) !Sself { + var image = Sself{ + .width = 0, + .height = 0, + .bytes_per_pixel = bytes_per_pixel, + + .allocator = allocator, + }; + try image.makeData(); + return image; + } + pub fn deinit(self: Sself) void { + if (self.data == null) return; + self.allocator.free(self.data.?); + } + pub fn makeData(self: Sself) !void { + std.debug.assert(self.bytes_per_pixel > 0); + std.debug.assert(self.bytes_per_pixel >= type_bytes); + if (is_struct) std.debug.assert(self.bytes_per_pixel == bytes_per_pixel); + std.debug.assert(self.bytes_per_pixel % type_bytes == 0); + + self.deinit(); + self.data = try self.allocator.alloc(T, self.width * self.height * self.bytes_per_pixel); + } + pub fn getData(self: Sself) []T { + return self.data.?; + } + }; +} + +pub fn getOverlayImageData( + self: Self, + allocator: std.mem.Allocator, + comptime ArrayT: type, + overlay_handle: common.OverlayHandle, +) common.OverlayError!RawImage(ArrayT, 4) { + var image = try RawImage(ArrayT, 4).init(allocator); + var err = self.function_table.GetOverlayImageData(overlay_handle, null, 0, &image.width, &image.height).maybe(); + if (err != common.OverlayError.ArrayTooSmall) return err; + + try image.makeData(); + errdefer image.deinit(); + + if (image.getData().len > 0) { + err = self.function_table.GetOverlayImageData( + overlay_handle, + image.getData().ptr, + @sizeOf(ArrayT) * image.getData().len, + &image.width, + &image.height, + ); + try err.maybe(); + } + + return image; } pub fn getOverlayErrorNameFromEnum(self: Self, overlay_error: common.OverlayErrorCode) [:0]const u8 { @@ -284,8 +366,10 @@ pub fn setOverlayTransformTrackedDeviceComponent( return self.function_table.SetOverlayTransformTrackedDeviceComponent(overlay_handle, device_index, component_name.ptr); } -pub fn getOverlayTransformTrackedDeviceComponent(_: Self) void { - @compileError("not implemented"); +pub fn getOverlayTransformTrackedDeviceComponent(self: Self, overlay_handle: common.OverlayHandle, out_component_name_buffer: [:0]u8) common.OverlayError!common.TrackedDeviceIndex { + var tracked_device: common.TrackedDeviceIndex = undefined; + try self.function_table.GetOverlayTransformTrackedDeviceComponent(overlay_handle, &tracked_device, out_component_name_buffer.ptr, out_component_name_buffer.len); + return tracked_device; } pub fn setOverlayTransformCursor(self: Self, overlay_handle: common.OverlayHandle, hotspot: common.Vector2) common.OverlayError!void { @@ -446,23 +530,25 @@ pub fn setOverlayRaw( comptime { const type_info = @typeInfo(T); if (type_info == .Int) { - if (type_info.Int.bits % 8 != 0) { - @compileError("int needs to be a whole number of bytes"); - } + if (type_info.Int.bits % 8 != 0) @compileError("int needs to be a whole number of bytes"); } else if (type_info == .Struct) { - if (type_info.Struct.layout != .@"packed") { - @compileError("struct needs to be packed"); - } - if (type_info.Struct.backing_integer % 8 != 0) { - @compileError("struct needs to be a whole number of bytes big"); - } - } else { - @compileError("type '" ++ @typeName(T) ++ "' is not allowed here"); - } + if (type_info.Struct.layout != .@"packed") @compileError("struct needs to be packed"); + if (@typeInfo(type_info.Struct.backing_integer.?).Int.bits % 8 != 0) @compileError("struct needs to be a whole number of bytes big"); + } else @compileError("type '" ++ @typeName(T) ++ "' is not allowed here"); } return self.function_table.SetOverlayRaw(overlay_handle, buffer, width, height, bytes_per_pixel).maybe(); } +pub fn setOverlayRawFromRawImage( + self: Self, + comptime T: type, + comptime bytes_per_pixel: u32, + overlay_handle: common.OverlayHandle, + image: RawImage(T, bytes_per_pixel), +) common.OverlayError!void { + self.setOverlayRaw(T, overlay_handle, image.getData(), image.width, image.height, image.bytes_per_pixel); +} + pub fn setOverlayFromFile(self: Self, overlay_handle: common.OverlayHandle, file_path: [:0]const u8) common.OverlayError!void { return self.function_table.SetOverlayFromFile(overlay_handle, file_path.ptr).maybe(); } @@ -658,7 +744,7 @@ const FunctionTable = extern struct { SetOverlayTransformTrackedDeviceRelative: *const fn (common.OverlayHandle, common.TrackedDeviceIndex, *const common.Matrix34) callconv(.C) common.OverlayErrorCode, GetOverlayTransformTrackedDeviceRelative: *const fn (common.OverlayHandle, *common.TrackedDeviceIndex, *common.Matrix34) callconv(.C) common.OverlayErrorCode, SetOverlayTransformTrackedDeviceComponent: *const fn (common.OverlayHandle, common.TrackedDeviceIndex, [*c]const u8) callconv(.C) common.OverlayErrorCode, - GetOverlayTransformTrackedDeviceComponent: *const fn (common.OverlayHandle, *common.TrackedDeviceIndex, [*c]const u8, u32) callconv(.C) common.OverlayErrorCode, + GetOverlayTransformTrackedDeviceComponent: *const fn (common.OverlayHandle, *common.TrackedDeviceIndex, [*c]u8, u32) callconv(.C) common.OverlayErrorCode, SetOverlayTransformCursor: *const fn (common.OverlayHandle, *const common.Vector2) callconv(.C) common.OverlayErrorCode, GetOverlayTransformCursor: *const fn (common.OverlayHandle, *common.Vector2) callconv(.C) common.OverlayErrorCode, SetOverlayTransformProjection: *const fn (common.OverlayHandle, common.TrackingUniverseOrigin, *const common.Matrix34, *const common.OverlayProjection, common.Eye) callconv(.C) common.OverlayErrorCode, From f49a113426762a19874591f8ac52f20136dc1d91 Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 00:23:16 -0400 Subject: [PATCH 14/44] small fix --- libs/zopenvr/src/common.zig | 2 +- libs/zopenvr/src/overlay.zig | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index ea9c96b7b..4c6f0fac6 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -2369,7 +2369,7 @@ pub const FirmwareErrorCode = enum(i32) { } }; -pub const VRState = enum(u32) { +pub const VRState = enum(i32) { undefined = -1, off = 0, searching = 1, diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index fad9cd0f2..166f9480d 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -102,13 +102,14 @@ pub fn RawImage(comptime T: type, comptime bytes_per_pixel: u32) type { height: u32, bytes_per_pixel: u32, - data: ?[]T = null, + data: []T, pub fn init(allocator: std.mem.Allocator) !Sself { var image = Sself{ .width = 0, .height = 0, .bytes_per_pixel = bytes_per_pixel, + .data = undefined, .allocator = allocator, }; @@ -117,7 +118,7 @@ pub fn RawImage(comptime T: type, comptime bytes_per_pixel: u32) type { } pub fn deinit(self: Sself) void { if (self.data == null) return; - self.allocator.free(self.data.?); + self.allocator.free(self.data); } pub fn makeData(self: Sself) !void { std.debug.assert(self.bytes_per_pixel > 0); @@ -128,9 +129,6 @@ pub fn RawImage(comptime T: type, comptime bytes_per_pixel: u32) type { self.deinit(); self.data = try self.allocator.alloc(T, self.width * self.height * self.bytes_per_pixel); } - pub fn getData(self: Sself) []T { - return self.data.?; - } }; } @@ -147,11 +145,11 @@ pub fn getOverlayImageData( try image.makeData(); errdefer image.deinit(); - if (image.getData().len > 0) { + if (image.data.len > 0) { err = self.function_table.GetOverlayImageData( overlay_handle, - image.getData().ptr, - @sizeOf(ArrayT) * image.getData().len, + image.data.ptr, + @sizeOf(ArrayT) * image.data.len, &image.width, &image.height, ); @@ -546,7 +544,7 @@ pub fn setOverlayRawFromRawImage( overlay_handle: common.OverlayHandle, image: RawImage(T, bytes_per_pixel), ) common.OverlayError!void { - self.setOverlayRaw(T, overlay_handle, image.getData(), image.width, image.height, image.bytes_per_pixel); + self.setOverlayRaw(T, overlay_handle, image.data, image.width, image.height, image.bytes_per_pixel); } pub fn setOverlayFromFile(self: Self, overlay_handle: common.OverlayHandle, file_path: [:0]const u8) common.OverlayError!void { From afd3c42839256ee99f86a3f861a37f6eef27c6bf Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 09:20:31 -0400 Subject: [PATCH 15/44] add functions to get string descriptions from err --- libs/zopenvr/src/applications.zig | 3 ++ libs/zopenvr/src/common.zig | 78 ++++++++++++++++++++++++++++++ libs/zopenvr/src/overlay.zig | 3 ++ libs/zopenvr/src/render_models.zig | 3 ++ libs/zopenvr/src/system.zig | 3 ++ 5 files changed, 90 insertions(+) diff --git a/libs/zopenvr/src/applications.zig b/libs/zopenvr/src/applications.zig index 3d88e8d73..48fa701c0 100644 --- a/libs/zopenvr/src/applications.zig +++ b/libs/zopenvr/src/applications.zig @@ -102,6 +102,9 @@ pub fn getApplicationProcessId(self: Self, app_key: [:0]const u8) common.Applica pub fn getApplicationsErrorNameFromEnum(self: Self, error_code: common.ApplicationErrorCode) [:0]const u8 { return std.mem.span(self.function_table.GetApplicationsErrorNameFromEnum(error_code)); } +pub fn getApplicationsErrorNameFromError(self: Self, application_error: common.ApplicationError) [:0]const u8 { + return self.getApplicationsErrorNameFromEnum(common.ApplicationErrorCode.fromError(application_error)); +} pub fn getApplicationProperty(self: Self, comptime T: type, app_key: [:0]const u8, property: common.ApplicationProperty.fromType(T)) common.ApplicationError!T { var error_code: common.ApplicationErrorCode = undefined; diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 4c6f0fac6..a7bb76a98 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -446,6 +446,14 @@ pub const InitErrorCode = enum(i32) { steam_installation_not_found = 2000, last_error = 2001, + pub fn fromError(err: InitError) InitErrorCode { + return switch (err) { + inline else => |e| comptime for (std.meta.tags(InitErrorCode)) |tag| { + if (tag.maybe() == e) break tag; + } else unreachable, + }; + } + pub fn maybe(init_error: InitErrorCode) InitError!void { return switch (init_error) { .none => {}, @@ -676,6 +684,13 @@ pub const InitErrorCode = enum(i32) { } }; +pub fn initErrorAsSymbol(init_error: InitError) [:0]const u8 { + return InitErrorCode.fromError(init_error).asSymbol(); +} +pub fn initErrorAsEnglishDescription(init_error: InitError) [:0]const u8 { + return InitErrorCode.fromError(init_error).asEnglishDescription(); +} + extern "openvr_api" fn VR_GetVRInitErrorAsSymbol(InitErrorCode) callconv(.C) [*c]const u8; extern "openvr_api" fn VR_GetVRInitErrorAsEnglishDescription(InitErrorCode) callconv(.C) [*c]const u8; extern "openvr_api" fn VR_GetGenericInterface([*c]const u8, *InitErrorCode) callconv(.C) ?*isize; @@ -860,6 +875,14 @@ pub const ApplicationErrorCode = enum(i32) { not_implemented = 300, // Fcn is not implemented in current interface + pub fn fromError(err: ApplicationError) ApplicationErrorCode { + return switch (err) { + inline else => |e| comptime for (std.meta.tags(ApplicationErrorCode)) |tag| { + if (tag.maybe() == e) break tag; + } else unreachable, + }; + } + pub fn maybe(error_code: ApplicationErrorCode) ApplicationError!void { return switch (error_code) { .none => {}, @@ -1051,6 +1074,14 @@ pub const CompositorErrorCode = enum(i32) { invalid_bounds = 109, already_set = 110, + pub fn fromError(err: CompositorError) CompositorErrorCode { + return switch (err) { + inline else => |e| comptime for (std.meta.tags(CompositorErrorCode)) |tag| { + if (tag.maybe() == e) break tag; + } else unreachable, + }; + } + pub fn maybe(compositor_error: CompositorErrorCode) CompositorError!void { return switch (compositor_error) { .none => {}, @@ -1280,6 +1311,14 @@ pub const InputErrorCode = enum(i32) { permission_denied = 19, invalid_render_model = 20, + pub fn fromError(err: InputError) InputErrorCode { + return switch (err) { + inline else => |e| comptime for (std.meta.tags(InputErrorCode)) |tag| { + if (tag.maybe() == e) break tag; + } else unreachable, + }; + } + pub fn maybe(error_code: InputErrorCode) InputError!void { return switch (error_code) { .none => {}, @@ -1431,6 +1470,14 @@ pub const RenderModelErrorCode = enum(i32) { not_enough_tex_coords = 308, invalid_texture = 400, + pub fn fromError(err: RenderModelError) RenderModelErrorCode { + return switch (err) { + inline else => |e| comptime for (std.meta.tags(RenderModelErrorCode)) |tag| { + if (tag.maybe() == e) break tag; + } else unreachable, + }; + } + pub fn maybe(error_code: RenderModelErrorCode) RenderModelError!void { return switch (error_code) { .none => {}, @@ -2085,6 +2132,14 @@ pub const TrackedPropertyErrorCode = enum(i32) { out_of_memory = 14, invalid_container = 15, + pub fn fromError(err: TrackedPropertyError) TrackedPropertyErrorCode { + return switch (err) { + inline else => |e| comptime for (std.meta.tags(TrackedPropertyErrorCode)) |tag| { + if (tag.maybe() == e) break tag; + } else unreachable, + }; + } + pub fn maybe(property_error: TrackedPropertyErrorCode) TrackedPropertyError!void { return switch (property_error) { .success => {}, @@ -2361,6 +2416,14 @@ pub const FirmwareErrorCode = enum(i32) { success = 1, fail = 2, + pub fn fromError(err: FirmwareError) FirmwareErrorCode { + return switch (err) { + FirmwareError.None => FirmwareErrorCode.none, + FirmwareError.Success => FirmwareErrorCode.success, + FirmwareError.Fail => FirmwareErrorCode.fail, + }; + } + pub fn maybe(firmware_error: FirmwareErrorCode) FirmwareError!void { return switch (firmware_error) { .none, .success => {}, @@ -2706,6 +2769,14 @@ pub const OverlayErrorCode = enum(i32) { texture_not_locked = 33, timed_out = 34, + pub fn fromError(err: OverlayError) OverlayErrorCode { + return switch (err) { + inline else => |e| comptime for (std.meta.tags(OverlayErrorCode)) |tag| { + if (tag.maybe() == e) break tag; + } else unreachable, + }; + } + pub fn maybe(overlay_error: OverlayErrorCode) OverlayError!void { return switch (overlay_error) { .none => {}, @@ -2737,6 +2808,13 @@ pub const OverlayErrorCode = enum(i32) { } }; +test "back to error code" { + const expectEqual = std.testing.expectEqual; + const code = OverlayErrorCode.array_too_small; + _ = code.maybe() catch |err| + try expectEqual(code, OverlayErrorCode.fromError(err)); +} + pub const OverlayFlags = packed struct(u32) { _padding: u3 = 0, no_dashboard_tab: bool = false, diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 166f9480d..bf7c0cb3d 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -162,6 +162,9 @@ pub fn getOverlayImageData( pub fn getOverlayErrorNameFromEnum(self: Self, overlay_error: common.OverlayErrorCode) [:0]const u8 { return std.mem.span(self.function_table.GetOverlayErrorNameFromEnum(overlay_error)); } +pub fn getOverlayErrorNameFromError(self: Self, overlay_error: common.OverlayError) [:0]const u8 { + return self.getOverlayErrorNameFromEnum(common.OverlayErrorCode.fromError(overlay_error)); +} pub fn setOverlayRenderingPid(self: Self, overlay_handle: common.OverlayHandle, pid: u32) common.OverlayError!void { return self.function_table.SetOverlayRenderingPid(overlay_handle, pid).maybe(); diff --git a/libs/zopenvr/src/render_models.zig b/libs/zopenvr/src/render_models.zig index 7e5744651..4af46aeef 100644 --- a/libs/zopenvr/src/render_models.zig +++ b/libs/zopenvr/src/render_models.zig @@ -164,6 +164,9 @@ pub fn allocRenderModelOriginalPath(self: Self, allocator: std.mem.Allocator, re pub fn getRenderModelErrorNameFromEnum(self: Self, error_code: common.RenderModelErrorCode) [:0]const u8 { return std.mem.span(self.function_table.GetRenderModelErrorNameFromEnum(error_code)); } +pub fn getRenderModelErrorNameFromError(self: Self, render_model_error: common.RenderModelErrorCode) [:0]const u8 { + return self.getRenderModelErrorNameFromEnum(common.RenderModelErrorCode.fromError(render_model_error)); +} const FunctionTable = extern struct { LoadRenderModel_Async: *const fn ([*c]u8, **common.ExternRenderModel) callconv(.C) common.RenderModelErrorCode, diff --git a/libs/zopenvr/src/system.zig b/libs/zopenvr/src/system.zig index 03ec57b05..a15c98f2a 100644 --- a/libs/zopenvr/src/system.zig +++ b/libs/zopenvr/src/system.zig @@ -201,6 +201,9 @@ pub fn allocTrackedDevicePropertyString(self: Self, allocator: std.mem.Allocator pub fn getPropErrorNameFromEnum(self: Self, property_error: common.TrackedPropertyErrorCode) [:0]const u8 { return std.mem.span(self.function_table.GetPropErrorNameFromEnum(property_error)); } +pub fn getPropErrorNameFromError(self: Self, property_error: common.TrackedPropertyError) [:0]const u8 { + return self.getPropErrorNameFromEnum(common.TrackedPropertyErrorCode.fromError(property_error)); +} pub fn pollNextEvent(self: Self) ?common.Event { var event: common.Event = undefined; From 4a1361f3bc660847bb6ba35460826247f0d0846b Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 09:36:39 -0400 Subject: [PATCH 16/44] set up input outputs for last func --- libs/zopenvr/src/overlay.zig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index bf7c0cb3d..3d0ac37de 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -554,9 +554,18 @@ pub fn setOverlayFromFile(self: Self, overlay_handle: common.OverlayHandle, file return self.function_table.SetOverlayFromFile(overlay_handle, file_path.ptr).maybe(); } -pub fn getOverlayTexture(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct {} { +pub fn getOverlayTexture(self: Self, overlay_handle: common.OverlayHandle, native_texture_ref: anyopaque) common.OverlayError!struct { + native_texture_handle: anyopaque, + width: u32, + height: u32, + native_format: u32, + api_type: common.TextureType, + color_space: common.ColorSpace, + texture_bounds: common.TextureBounds, +} { _ = self; _ = overlay_handle; + _ = native_texture_ref; @compileError("not implemented"); } From 64944a8deac59acf813ca1b96b855c60de8ecf41 Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 12:03:21 -0400 Subject: [PATCH 17/44] fix depth error --- libs/zopenvr/src/common.zig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index a7bb76a98..993508253 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -449,6 +449,7 @@ pub const InitErrorCode = enum(i32) { pub fn fromError(err: InitError) InitErrorCode { return switch (err) { inline else => |e| comptime for (std.meta.tags(InitErrorCode)) |tag| { + @setEvalBranchQuota(50000); if (tag.maybe() == e) break tag; } else unreachable, }; @@ -691,6 +692,13 @@ pub fn initErrorAsEnglishDescription(init_error: InitError) [:0]const u8 { return InitErrorCode.fromError(init_error).asEnglishDescription(); } +test "depth error" { + const err = InitError.InitHmdNotFound; + const sym = initErrorAsSymbol(err); + try std.testing.expect(sym.len > 0); + // std.debug.print("{s}\n", .{sym}); +} + extern "openvr_api" fn VR_GetVRInitErrorAsSymbol(InitErrorCode) callconv(.C) [*c]const u8; extern "openvr_api" fn VR_GetVRInitErrorAsEnglishDescription(InitErrorCode) callconv(.C) [*c]const u8; extern "openvr_api" fn VR_GetGenericInterface([*c]const u8, *InitErrorCode) callconv(.C) ?*isize; From e80bcd8ffc5b4b436216bdb80a0a1dcf639dea69 Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 14:20:40 -0400 Subject: [PATCH 18/44] last function and no anyopaques --- libs/zopenvr/build.zig | 10 +++++++- libs/zopenvr/src/common.zig | 7 ++--- libs/zopenvr/src/overlay.zig | 47 +++++++++++++++++++++++++++++----- libs/zopenvr/src/renderers.zig | 12 +++++++++ 4 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 libs/zopenvr/src/renderers.zig diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index 95514117e..3cf355a67 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -12,14 +12,22 @@ pub fn build(b: *std.Build) void { }); var backends = struct { + d3d11: bool = false, d3d12: bool = false, // valken: bool = false, // opengl: bool = false, }{}; - // b.systemIntegrationOption("d3d12", .{}) + var need_zwin32 = false; if (b.option(bool, "d3d12", "Enable Direct3D 12 backend") orelse false) { backends.d3d12 = true; + need_zwin32 = true; + } + if (b.option(bool, "d3d11", "Enable Direct3D 11 backend") orelse false) { + backends.d3d11 = true; + need_zwin32 = true; + } + if (need_zwin32) { if (b.lazyDependency("zwin32", .{ .target = target })) |zwin32| { mod.addImport("zwin32", zwin32.module("root")); } diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 993508253..222a4b428 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -1,10 +1,7 @@ const std = @import("std"); -const config = @import("rendermodesConfig"); -const d3d12 = if (config.d3d12) @import("zwin32").d3d12 else struct { - pub const ICommandQueue = anyopaque; - pub const IResource = anyopaque; -}; +const renderers = @import("renderers.zig"); +const d3d12 = renderers.d3d12; const root = @This(); diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 3d0ac37de..96ea2cf76 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -1,6 +1,7 @@ const std = @import("std"); const common = @import("common.zig"); +const d3d11 = @import("renderers.zig").d3d11; function_table: *FunctionTable, @@ -549,13 +550,17 @@ pub fn setOverlayRawFromRawImage( ) common.OverlayError!void { self.setOverlayRaw(T, overlay_handle, image.data, image.width, image.height, image.bytes_per_pixel); } +pub fn setOverlayRawFromRawImageU8(self: Self, overlay_handle: common.OverlayHandle, image: RawImage(u8, 4)) common.OverlayError!void { + return self.setOverlayRawFromRawImage(u8, 4, overlay_handle, image); +} pub fn setOverlayFromFile(self: Self, overlay_handle: common.OverlayHandle, file_path: [:0]const u8) common.OverlayError!void { return self.function_table.SetOverlayFromFile(overlay_handle, file_path.ptr).maybe(); } -pub fn getOverlayTexture(self: Self, overlay_handle: common.OverlayHandle, native_texture_ref: anyopaque) common.OverlayError!struct { - native_texture_handle: anyopaque, +// todo make typeing accomedate more engines rather then just what was in the docs +pub fn getOverlayTextureD3D11(self: Self, overlay_handle: common.OverlayHandle, native_texture_ref: *d3d11.IResource) common.OverlayError!struct { + native_texture_handle: *d3d11.IShaderResourceView, width: u32, height: u32, native_format: u32, @@ -563,13 +568,41 @@ pub fn getOverlayTexture(self: Self, overlay_handle: common.OverlayHandle, nativ color_space: common.ColorSpace, texture_bounds: common.TextureBounds, } { - _ = self; - _ = overlay_handle; - _ = native_texture_ref; - @compileError("not implemented"); + comptime if (@import("builtin").os.tag != .windows) @compileError("can't guarantee it works, so disabling"); + + var native_texture_handle: *d3d11.IShaderResourceView = undefined; + var width: u32 = undefined; + var height: u32 = undefined; + var native_format: u32 = undefined; + var api_type: common.TextureType = undefined; + var color_space: common.ColorSpace = undefined; + var texture_bounds: common.TextureBounds = undefined; + + const err = self.function_table.GetOverlayTexture( + overlay_handle, + &native_texture_handle, + native_texture_ref, + &width, + &height, + &native_format, + &api_type, + &color_space, + &texture_bounds, + ); + + try err.maybe(); + return .{ + .native_texture_handle = native_texture_handle.?, + .width = width, + .height = height, + .native_format = native_format, + .api_type = api_type, + .color_space = color_space, + .texture_bounds = texture_bounds, + }; } -pub fn releaseNativeOverlayHandle(self: Self, overlay_handle: common.OverlayHandle, native_texture_handle: anyopaque) common.OverlayError!void { +pub fn releaseNativeOverlayHandleD3D11(self: Self, overlay_handle: common.OverlayHandle, native_texture_handle: *d3d11.IShaderResourceView) common.OverlayError!void { return self.function_table.ReleaseNativeOverlayHandle(overlay_handle, native_texture_handle).maybe(); } diff --git a/libs/zopenvr/src/renderers.zig b/libs/zopenvr/src/renderers.zig new file mode 100644 index 000000000..730b4f062 --- /dev/null +++ b/libs/zopenvr/src/renderers.zig @@ -0,0 +1,12 @@ +const config = @import("rendermodesConfig"); + +pub const d3d12 = if (config.d3d12) @import("zwin32").d3d12 else struct { + pub const ICommandQueue = anyopaque; + pub const IResource = anyopaque; +}; + +pub const d3d11 = if (config.d3d11) @import("zwin32").d3d11 else struct { + pub const IShaderResourceView = anyopaque; + pub const IResource = anyopaque; + pub const ITexture2D = anyopaque; +}; From a1d3976d10fbd75f95d65d3c1f02637314b18889 Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 15:05:46 -0400 Subject: [PATCH 19/44] move raw image to common --- libs/zopenvr/src/common.zig | 57 +++++++++++++++++++++++++++++++ libs/zopenvr/src/overlay.zig | 65 +++--------------------------------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 222a4b428..e3e18eb04 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -2995,3 +2995,60 @@ pub const VRMouseButton = packed struct(u32) { _padding: u29 = 0, }; + +pub fn RawImage(comptime T: type, comptime bytes_per_pixel: u32) type { + comptime { + switch (@typeInfo(T)) { + .Int => |Int| if (Int.bits % 8 != 0) @compileError("type needs to be a whole number of bytes"), + .Struct => |Struct| { + if (Struct.layout != .@"packed") @compileError("struct needs to be packed"); + if (@typeInfo(Struct.backing_integer.?).Int.bits != 8 * bytes_per_pixel) + @compileError("struct has to be 1 pixel big (u" ++ 8 * bytes_per_pixel ++ ")"); + }, + else => @compileError("type '" ++ @typeName(T) ++ "' is not allowed here"), + } + } + const is_struct = comptime @typeInfo(T) == .Struct; + const type_bytes: u16 = comptime switch (@typeInfo(T)) { + .Struct => |Struct| @typeInfo(Struct.backing_integer.?).Int.bits / 8, + .Int => |Int| Int.bits / 8, + else => unreachable, + }; + + return struct { + const Sself = @This(); + allocator: std.mem.Allocator, + + width: u32, + height: u32, + bytes_per_pixel: u32, + + data: []T, + + pub fn init(allocator: std.mem.Allocator) !Sself { + var image = Sself{ + .width = 0, + .height = 0, + .bytes_per_pixel = bytes_per_pixel, + .data = undefined, + + .allocator = allocator, + }; + try image.makeData(); + return image; + } + pub fn deinit(self: Sself) void { + if (self.data == null) return; + self.allocator.free(self.data); + } + pub fn makeData(self: Sself) !void { + std.debug.assert(self.bytes_per_pixel > 0); + std.debug.assert(self.bytes_per_pixel >= type_bytes); + if (is_struct) std.debug.assert(self.bytes_per_pixel == bytes_per_pixel); + std.debug.assert(self.bytes_per_pixel % type_bytes == 0); + + self.deinit(); + self.data = try self.allocator.alloc(T, self.width * self.height * self.bytes_per_pixel); + } + }; +} diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 96ea2cf76..09bf0916a 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -76,70 +76,13 @@ pub fn setOverlayName(self: Self, overlay_handle: common.OverlayHandle, name: [: return self.function_table.SetOverlayName(overlay_handle, name.ptr).maybe(); } -pub fn RawImage(comptime T: type, comptime bytes_per_pixel: u32) type { - comptime { - switch (@typeInfo(T)) { - .Int => |Int| if (Int.bits % 8 != 0) @compileError("type needs to be a whole number of bytes"), - .Struct => |Struct| { - if (Struct.layout != .@"packed") @compileError("struct needs to be packed"); - if (@typeInfo(Struct.backing_integer.?).Int.bits != 8 * bytes_per_pixel) - @compileError("struct has to be 1 pixel big (u" ++ 8 * bytes_per_pixel ++ ")"); - }, - else => @compileError("type '" ++ @typeName(T) ++ "' is not allowed here"), - } - } - const is_struct = comptime @typeInfo(T) == .Struct; - const type_bytes: u16 = comptime switch (@typeInfo(T)) { - .Struct => |Struct| @typeInfo(Struct.backing_integer.?).Int.bits / 8, - .Int => |Int| Int.bits / 8, - else => unreachable, - }; - - return struct { - const Sself = @This(); - allocator: std.mem.Allocator, - - width: u32, - height: u32, - bytes_per_pixel: u32, - - data: []T, - - pub fn init(allocator: std.mem.Allocator) !Sself { - var image = Sself{ - .width = 0, - .height = 0, - .bytes_per_pixel = bytes_per_pixel, - .data = undefined, - - .allocator = allocator, - }; - try image.makeData(); - return image; - } - pub fn deinit(self: Sself) void { - if (self.data == null) return; - self.allocator.free(self.data); - } - pub fn makeData(self: Sself) !void { - std.debug.assert(self.bytes_per_pixel > 0); - std.debug.assert(self.bytes_per_pixel >= type_bytes); - if (is_struct) std.debug.assert(self.bytes_per_pixel == bytes_per_pixel); - std.debug.assert(self.bytes_per_pixel % type_bytes == 0); - - self.deinit(); - self.data = try self.allocator.alloc(T, self.width * self.height * self.bytes_per_pixel); - } - }; -} - pub fn getOverlayImageData( self: Self, allocator: std.mem.Allocator, comptime ArrayT: type, overlay_handle: common.OverlayHandle, -) common.OverlayError!RawImage(ArrayT, 4) { - var image = try RawImage(ArrayT, 4).init(allocator); +) common.OverlayError!common.RawImage(ArrayT, 4) { + var image = try common.RawImage(ArrayT, 4).init(allocator); var err = self.function_table.GetOverlayImageData(overlay_handle, null, 0, &image.width, &image.height).maybe(); if (err != common.OverlayError.ArrayTooSmall) return err; @@ -546,11 +489,11 @@ pub fn setOverlayRawFromRawImage( comptime T: type, comptime bytes_per_pixel: u32, overlay_handle: common.OverlayHandle, - image: RawImage(T, bytes_per_pixel), + image: common.RawImage(T, bytes_per_pixel), ) common.OverlayError!void { self.setOverlayRaw(T, overlay_handle, image.data, image.width, image.height, image.bytes_per_pixel); } -pub fn setOverlayRawFromRawImageU8(self: Self, overlay_handle: common.OverlayHandle, image: RawImage(u8, 4)) common.OverlayError!void { +pub fn setOverlayRawFromRawImageU8(self: Self, overlay_handle: common.OverlayHandle, image: common.RawImage(u8, 4)) common.OverlayError!void { return self.setOverlayRawFromRawImage(u8, 4, overlay_handle, image); } From 1f0dca1cb870b4fbf70bd49daff0c1a0e35ba25f Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 18:33:02 -0400 Subject: [PATCH 20/44] add d3d11 functions needs testing --- libs/zopenvr/README.md | 6 +++--- libs/zopenvr/src/compositor.zig | 19 ++++++++++++++++--- libs/zopenvr/src/render_models.zig | 24 ++++++++++++++++++++---- libs/zopenvr/src/renderers.zig | 1 + 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index 0f6436d11..d6810e00b 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -63,7 +63,7 @@ For better types on render structs, enable the corresponding options when import | BlockQueue | | | Chaperone | ✅ | | ChaperoneSetup | | -| Compositor | ✅
(d3d12 only) | +| Compositor | ✅
(see bellow) | | Debug | | | DriverManager | | | ExtendedDisplay | | @@ -71,7 +71,7 @@ For better types on render structs, enable the corresponding options when import | Input | ✅ | | IOBuffer | | | Notifications | | -| Overlay | | +| Overlay | ✅ | | OverlayView | | | Paths | | | Properties | | @@ -86,7 +86,7 @@ For better types on render structs, enable the corresponding options when import ### Compositor supported renderers | Renderer | Handle type | Zig handle name | Support | |--------------------|-----------------------|---------------------------------|:-------:| -| DirectX 11 (d3d11) | ID3D11Texture2D | zwin32.d3d11.ITexture2D | | +| DirectX 11 (d3d11) | ID3D11Texture2D | zwin32.d3d11.ITexture2D | ✅ | | OpenGL | | | | | Vulkan | VRVulkanTextureData_t | | | | IOSurface | | | | diff --git a/libs/zopenvr/src/compositor.zig b/libs/zopenvr/src/compositor.zig index 913ab48ff..deee35a0b 100644 --- a/libs/zopenvr/src/compositor.zig +++ b/libs/zopenvr/src/compositor.zig @@ -1,6 +1,9 @@ const std = @import("std"); const common = @import("common.zig"); +const renderers = @import("renderers.zig"); + +const d3d11 = renderers.d3d11; function_table: *FunctionTable, @@ -254,6 +257,17 @@ pub fn allocPosesForFrame(self: Self, allocator: std.mem.Allocator, pose_predict return poses; } +pub fn getMirrorTextureD3D11(self: Self, eye: common.Eye, d3d11_resource_or_device: *d3d11.IResource) common.CompositorError!*d3d11.IShaderResourceView { + var d3d11_shader_resource_view: ?*d3d11.IShaderResourceView = undefined; + const err = self.function_table.GetMirrorTextureD3D11(eye, d3d11_resource_or_device, &d3d11_shader_resource_view); + try err.maybe(); + return d3d11_shader_resource_view.?; +} + +pub fn releaseMirrorTextureD3D11(self: Self, d3d11_shader_resource_view: *d3d11.IShaderResourceView) void { + self.function_table.ReleaseMirrorTextureD3D11(d3d11_shader_resource_view); +} + const FunctionTable = extern struct { SetTrackingSpace: *const fn (common.TrackingUniverseOrigin) callconv(.C) void, GetTrackingSpace: *const fn () callconv(.C) common.TrackingUniverseOrigin, @@ -290,9 +304,8 @@ const FunctionTable = extern struct { ForceReconnectProcess: *const fn () callconv(.C) void, SuspendRendering: *const fn (bool) callconv(.C) void, - // skip over d3d11 - GetMirrorTextureD3D11: usize, - ReleaseMirrorTextureD3D11: usize, + GetMirrorTextureD3D11: *const fn (common.Eye, ?*anyopaque, *?*d3d11.IShaderResourceView) callconv(.C) common.CompositorErrorCode, + ReleaseMirrorTextureD3D11: *const fn (?*d3d11.IShaderResourceView) callconv(.C) void, // skip over opengl GetMirrorTextureGL: usize, diff --git a/libs/zopenvr/src/render_models.zig b/libs/zopenvr/src/render_models.zig index 4af46aeef..736bfda43 100644 --- a/libs/zopenvr/src/render_models.zig +++ b/libs/zopenvr/src/render_models.zig @@ -1,6 +1,9 @@ const std = @import("std"); const common = @import("common.zig"); +const renderers = @import("renderers.zig"); + +const d3d11 = renderers.d3d11; function_table: *FunctionTable, @@ -168,16 +171,29 @@ pub fn getRenderModelErrorNameFromError(self: Self, render_model_error: common.R return self.getRenderModelErrorNameFromEnum(common.RenderModelErrorCode.fromError(render_model_error)); } +pub fn loadTextureD3D11_Async(self: Self, texture_id: common.TextureID, device: *d3d11.IDevice) common.RenderModelError!*d3d11.ITexture2D { + var texture2d: ?*d3d11.ITexture2D = undefined; + try self.function_table.LoadTextureD3D11_Async(texture_id, device, &texture2d).maybe(); + return texture2d.?; +} + +pub fn loadIntoTextureD3D11_Async(self: Self, texture_id: common.TextureID, destination_texture: *d3d11.ITexture2D) common.RenderModelError!void { + try self.function_table.LoadIntoTextureD3D11_Async(texture_id, destination_texture).maybe(); +} + +pub fn freeTextureD3D11(self: Self, texture2d: *d3d11.ITexture2D) void { + self.function_table.FreeTextureD3D11(texture2d); +} + const FunctionTable = extern struct { LoadRenderModel_Async: *const fn ([*c]u8, **common.ExternRenderModel) callconv(.C) common.RenderModelErrorCode, FreeRenderModel: *const fn (*common.ExternRenderModel) callconv(.C) void, LoadTexture_Async: *const fn (common.TextureID, **common.RenderModel.TextureMap) callconv(.C) common.RenderModelErrorCode, FreeTexture: *const fn (*common.RenderModel.TextureMap) callconv(.C) void, - // skip d3d11 - LoadTextureD3D11_Async: *const fn (common.TextureID, ?*anyopaque, [*c]?*anyopaque) callconv(.C) common.RenderModelErrorCode, - LoadIntoTextureD3D11_Async: *const fn (common.TextureID, ?*anyopaque) callconv(.C) common.RenderModelErrorCode, - FreeTextureD3D11: *const fn (?*anyopaque) callconv(.C) void, + LoadTextureD3D11_Async: *const fn (common.TextureID, ?*d3d11.IDevice, *?*d3d11.ITexture2D) callconv(.C) common.RenderModelErrorCode, + LoadIntoTextureD3D11_Async: *const fn (common.TextureID, ?*d3d11.ITexture2D) callconv(.C) common.RenderModelErrorCode, + FreeTextureD3D11: *const fn (?*d3d11.ITexture2D) callconv(.C) void, GetRenderModelName: *const fn (u32, [*c]u8, u32) callconv(.C) u32, GetRenderModelCount: *const fn () callconv(.C) u32, diff --git a/libs/zopenvr/src/renderers.zig b/libs/zopenvr/src/renderers.zig index 730b4f062..e42e006d6 100644 --- a/libs/zopenvr/src/renderers.zig +++ b/libs/zopenvr/src/renderers.zig @@ -9,4 +9,5 @@ pub const d3d11 = if (config.d3d11) @import("zwin32").d3d11 else struct { pub const IShaderResourceView = anyopaque; pub const IResource = anyopaque; pub const ITexture2D = anyopaque; + pub const IDevice = anyopaque; }; From 78bf8ba0df5b64ad103a1bf845f6c8f778f58be2 Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 18:33:39 -0400 Subject: [PATCH 21/44] more sensible time unit --- libs/zopenvr/src/render_models.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/zopenvr/src/render_models.zig b/libs/zopenvr/src/render_models.zig index 736bfda43..5408d6c3e 100644 --- a/libs/zopenvr/src/render_models.zig +++ b/libs/zopenvr/src/render_models.zig @@ -16,7 +16,7 @@ pub fn init() common.InitError!Self { } pub fn loadRenderModel(self: Self, render_model_name: [:0]const u8) common.RenderModelError!common.RenderModel { - while (true) : (std.time.sleep(10_000_000)) { + while (true) : (std.time.sleep(10 * std.time.ns_per_ms)) { return self.loadRenderModelAsync(render_model_name) catch |err| switch (err) { error.Loading => continue, else => return err, @@ -38,7 +38,7 @@ pub fn freeRenderModel(self: Self, render_model: common.RenderModel) void { } pub fn loadTexture(self: Self, texture_id: common.TextureID) common.RenderModelError!*common.RenderModel.TextureMap { - while (true) : (std.time.sleep(10_000_000)) { + while (true) : (std.time.sleep(10 * std.time.ns_per_ms)) { return self.loadTextureAsync(texture_id) catch |err| switch (err) { error.Loading => continue, else => return err, From 2c0ad947e3f72f22ad100ef1b269576a2a7f2fab Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 19:41:44 -0400 Subject: [PATCH 22/44] mango --- build.zig | 1 + samples/openvr_mango/README.md | 6 ++ samples/openvr_mango/build.zig | 30 ++++++++ samples/openvr_mango/src/openvr_mango.zig | 84 +++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 samples/openvr_mango/README.md create mode 100644 samples/openvr_mango/build.zig create mode 100644 samples/openvr_mango/src/openvr_mango.zig diff --git a/build.zig b/build.zig index fb46eb505..cee58c03b 100644 --- a/build.zig +++ b/build.zig @@ -128,6 +128,7 @@ const samples_cross_platform = struct { pub const minimal_glfw_gl = @import("samples/minimal_glfw_gl/build.zig"); pub const minimal_sdl_gl = @import("samples/minimal_sdl_gl/build.zig"); pub const minimal_zgui_glfw_gl = @import("samples/minimal_zgui_glfw_gl/build.zig"); + pub const openvr_mango = @import("samples/openvr_mango/build.zig"); pub usingnamespace struct { // WebGPU samples pub const audio_experiments_wgpu = @import("samples/audio_experiments_wgpu/build.zig"); diff --git a/samples/openvr_mango/README.md b/samples/openvr_mango/README.md new file mode 100644 index 000000000..777e79c17 --- /dev/null +++ b/samples/openvr_mango/README.md @@ -0,0 +1,6 @@ +## openvr mango + +dead simple mango overlay test +inspired by [battery_monitor_overlay.c](https://gist.github.com/cnlohr/6e452dc6cc2df7f48d5ade66059358d9) + +![image](screenshot.png) diff --git a/samples/openvr_mango/build.zig b/samples/openvr_mango/build.zig new file mode 100644 index 000000000..7333211ae --- /dev/null +++ b/samples/openvr_mango/build.zig @@ -0,0 +1,30 @@ +const std = @import("std"); + +const Options = @import("../../build.zig").Options; + +const demo_name = "openvr_mango"; + +pub fn build(b: *std.Build, options: Options) *std.Build.Step.Compile { + const cwd_path = b.pathJoin(&.{ "samples", demo_name }); + const src_path = b.pathJoin(&.{ cwd_path, "src" }); + const exe = b.addExecutable(.{ + .name = demo_name, + .root_source_file = b.path(b.pathJoin(&.{ src_path, demo_name ++ ".zig" })), + .target = options.target, + .optimize = options.optimize, + }); + + const zopenvr = b.dependency("zopenvr", .{ + .target = options.target, + }); + exe.root_module.addImport("zopenvr", zopenvr.module("root")); + + @import("zopenvr").addLibraryPathsTo(exe); + @import("zopenvr").linkOpenVR(exe); + @import("zopenvr").installOpenVR(&exe.step, options.target.result, .bin); + + const exe_options = b.addOptions(); + exe.root_module.addOptions("build_options", exe_options); + + return exe; +} diff --git a/samples/openvr_mango/src/openvr_mango.zig b/samples/openvr_mango/src/openvr_mango.zig new file mode 100644 index 000000000..3bf805234 --- /dev/null +++ b/samples/openvr_mango/src/openvr_mango.zig @@ -0,0 +1,84 @@ +const std = @import("std"); +const OpenVR = @import("zopenvr"); + +pub fn main() !void { + const stdout = std.io.getStdOut().writer(); + const stderr = std.io.getStdErr().writer(); + + var alloc = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer alloc.deinit(); + const allocator = alloc.allocator(); + + const width = 128; + const height = 128; + + try stdout.print("start\n", .{}); + + const openvr = OpenVR.init(.overlay) catch |err| { + const errDesc = OpenVR.initErrorAsEnglishDescription(err); + const errSym = OpenVR.initErrorAsSymbol(err); + try stderr.print("Error! Could not initialize OpenVR: {s} ({s})\n", .{ errDesc, errSym }); + std.process.exit(1); + }; + defer openvr.deinit(); + + const system = try openvr.system(); + const overlay = try openvr.overlay(); + + try stdout.print("initing overlay\n", .{}); + const overlayID = try overlay.createOverlay("mangotest-overlay", "mango square overlay"); + try overlay.setOverlayWidthInMeters(overlayID, 0.1); + try overlay.setOverlayColor(overlayID, 1, 0.8, 0.7); + + try overlay.setOverlayTextureBounds(overlayID, .{ + .u_min = 1, + .v_min = 0, + .u_max = 0, + .v_max = 1, + }); + try overlay.showOverlay(overlayID); + + { + var mango = try allocator.alloc(u8, width * height * 4); + for (0..height) |y| { + for (0..width) |x| { + mango[(x + y * width) * 4 + 0] = @as(u8, @intCast(x)) * 2; + mango[(x + y * width) * 4 + 1] = @as(u8, @intCast(y)) * 2; + mango[(x + y * width) * 4 + 2] = 0; + mango[(x + y * width) * 4 + 3] = 255; + } + } + + try overlay.setOverlayRaw(u8, overlayID, mango.ptr, width, height, 4); + } + + var overlay_associated = false; + while (true) { + defer std.time.sleep(50 * std.time.ns_per_ms); + + if (overlay_associated) { + _ = overlay.pollNextOverlayEvent(overlayID); + continue; + } + + const index = system.getTrackedDeviceIndexForControllerRole(.left_hand); + if (index == OpenVR.tracked_device_index_invalid or index == OpenVR.hmd) { + try stdout.print("couldn't find a left controller to attach the overlay to", .{}); + continue; + } + + var transform = std.mem.zeroes(OpenVR.Matrix34); + transform.m[1][1] = 1; + transform.m[0][2] = 1; + transform.m[2][0] = 1; + + overlay.setOverlayTransformTrackedDeviceRelative(overlayID, index, transform) catch |err| { + try stderr.print("Error connecting the mango to the device: {s}\n", .{overlay.getOverlayErrorNameFromError(err)}); + continue; + }; + + try stdout.print("Successfully associated your mango to the tracked device ({d} {x:0>8}).\n", .{ index, overlayID }); + + overlay_associated = true; + } +} From 6facd77d8fef55314efb5ecf17795080a2b76580 Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 21:26:26 -0400 Subject: [PATCH 23/44] add 32bit targets --- libs/zopenvr/build.zig | 80 +++++++++++++------ .../libs/openvr/bin/linux32/libopenvr_api.so | 3 + .../libs/openvr/bin/win32/openvr_api.dll | 3 + .../libs/openvr/lib/linux32/libopenvr_api.so | 3 + .../libs/openvr/lib/win32/openvr_api.lib | 3 + 5 files changed, 67 insertions(+), 25 deletions(-) create mode 100755 libs/zopenvr/libs/openvr/bin/linux32/libopenvr_api.so create mode 100644 libs/zopenvr/libs/openvr/bin/win32/openvr_api.dll create mode 100755 libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so create mode 100644 libs/zopenvr/libs/openvr/lib/win32/openvr_api.lib diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index 3cf355a67..ae027abed 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -72,16 +72,25 @@ pub fn addLibraryPathsTo(compile_step: *std.Build.Step.Compile) void { const target = compile_step.rootModuleTarget(); const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - if (target.cpu.arch != .x86_64) @panic("unsupported target architecture"); + if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + const arch = target.cpu.arch; + const path: []const u8 = switch (target.os.tag) { + .windows => switch (arch) { + .x86_64 => "libs/openvr/lib/win64", + .x86 => "libs/openvr/lib/win32", + else => unreachable, + }, + .linux => switch (arch) { + .x86_64 => "libs/openvr/lib/linux64", + .x86 => "libs/openvr/lib/linux32", + else => unreachable, + }, + else => null, + } orelse @panic("unsupported target os"); + // compile_step.step.fail() todo + compile_step.addLibraryPath(.{ - .cwd_relative = b.pathJoin(&.{ - source_path_prefix, - switch (target.os.tag) { - .windows => "libs/openvr/lib/win64", - .linux => "libs/openvr/lib/linux64", - else => @panic("unsupported target os"), - }, - }), + .cwd_relative = b.pathJoin(&.{ source_path_prefix, path }), }); } @@ -90,15 +99,24 @@ pub fn addRPathsTo(compile_step: *std.Build.Step.Compile) void { const target = compile_step.rootModuleTarget(); const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - if (target.cpu.arch != .x86_64) @panic("unsupported target architecture"); + if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + const arch = target.cpu.arch; + const path: []const u8 = switch (target.os.tag) { + .windows => switch (arch) { + .x86_64 => "libs/openvr/bin/win64", + .x86 => "libs/openvr/bin/win32", + else => unreachable, + }, + .linux => switch (arch) { + .x86_64 => "libs/openvr/bin/linux64", + .x86 => "libs/openvr/bin/linux32", + else => unreachable, + }, + else => null, + } orelse @panic("unsupported target os"); + compile_step.addRPath(.{ - .cwd_relative = b.pathJoin(&.{ - source_path_prefix, switch (target.os.tag) { - .windows => "libs/openvr/bin/win64", - .linux => "libs/openvr/bin/linux64", - else => @panic("unsupported target os"), - }, - }), + .cwd_relative = b.pathJoin(&.{ source_path_prefix, path }), }); } @@ -118,25 +136,37 @@ pub fn installOpenVR( target: std.Target, install_dir: std.Build.InstallDir, ) void { - if (target.cpu.arch != .x86_64) @panic("unsupported target architecture"); + if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); const b = step.owner; const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; + + const arch = target.cpu.arch; + const path: []const u8 = switch (target.os.tag) { + .windows => switch (arch) { + .x86_64 => "libs/openvr/bin/win64/openvr_api.dll", + .x86 => "libs/openvr/bin/win32/openvr_api.dll", + else => unreachable, + }, + .linux => switch (arch) { + .x86_64 => "libs/openvr/bin/linux64/libopenvr_api.so", + .x86 => "libs/openvr/bin/linux32/libopenvr_api.so", + else => unreachable, + }, + else => null, + } orelse @panic("unsupported target os"); + step.dependOn(switch (target.os.tag) { .windows => &b.addInstallFileWithDir( - .{ - .cwd_relative = b.pathJoin(&.{ source_path_prefix, "libs/openvr/bin/win64/openvr_api.dll" }), - }, + .{ .cwd_relative = b.pathJoin(&.{ source_path_prefix, path }) }, install_dir, "openvr_api.dll", ).step, .linux => &b.addInstallFileWithDir( - .{ - .cwd_relative = b.pathJoin(&.{ source_path_prefix, "libs/openvr/bin/linux64/libopenvr_api.so" }), - }, + .{ .cwd_relative = b.pathJoin(&.{ source_path_prefix, path }) }, install_dir, "libopenvr_api.so", ).step, - else => @panic("unsupported target os"), + else => unreachable, }); } diff --git a/libs/zopenvr/libs/openvr/bin/linux32/libopenvr_api.so b/libs/zopenvr/libs/openvr/bin/linux32/libopenvr_api.so new file mode 100755 index 000000000..2188c7e2f --- /dev/null +++ b/libs/zopenvr/libs/openvr/bin/linux32/libopenvr_api.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:194c845574ce7d99b98153cc596114e55ab64986822e00cbc3be12929f5d6b0c +size 1768140 diff --git a/libs/zopenvr/libs/openvr/bin/win32/openvr_api.dll b/libs/zopenvr/libs/openvr/bin/win32/openvr_api.dll new file mode 100644 index 000000000..740e1ec34 --- /dev/null +++ b/libs/zopenvr/libs/openvr/bin/win32/openvr_api.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6654420118ee78799985ed4b3961975d40b8482c85c4db1d28faab43416f33ba +size 629568 diff --git a/libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so b/libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so new file mode 100755 index 000000000..618cf05c3 --- /dev/null +++ b/libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79bcd0b9a1fb1e857adc748f4c170f48b311b14a27b5d5b6210d5e39d47824b2 +size 5877704 diff --git a/libs/zopenvr/libs/openvr/lib/win32/openvr_api.lib b/libs/zopenvr/libs/openvr/lib/win32/openvr_api.lib new file mode 100644 index 000000000..bdbf64572 --- /dev/null +++ b/libs/zopenvr/libs/openvr/lib/win32/openvr_api.lib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ec5921313d97eb88d7fb98371e31cc0eb73f792266f8ea4ef387031fe0d3a3d +size 5578 From cde710bfc705ed280fee0cc0b84f0cced7858ef0 Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 22:03:01 -0400 Subject: [PATCH 24/44] image --- samples/openvr_mango/screenshot.png | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 samples/openvr_mango/screenshot.png diff --git a/samples/openvr_mango/screenshot.png b/samples/openvr_mango/screenshot.png new file mode 100644 index 000000000..49acbd540 --- /dev/null +++ b/samples/openvr_mango/screenshot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c642b61f794351831b4de1c8fcec8a0def78a360761b2784ff79338ed58798a +size 594097 From 90cae4159125ae1bca1d4b99751046e8577d84e3 Mon Sep 17 00:00:00 2001 From: zivoy Date: Tue, 2 Jul 2024 22:17:06 -0400 Subject: [PATCH 25/44] add option to readme --- libs/zopenvr/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index d6810e00b..fd2599124 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -51,6 +51,7 @@ pub fn main() !void { For better types on render structs, enable the corresponding options when importing the dependency and ensure that the lib is present in the libs folder. ```zig const zopenvr = b.dependency("zopenvr", .{ + .d3d11 = true, // requires zwin32 .d3d12 = true, // requires zwin32 }); ``` From 54582bcb0f4be8e8d4c1d0b431c9d1a2e6a1f401 Mon Sep 17 00:00:00 2001 From: zivoy Date: Wed, 3 Jul 2024 07:34:03 -0400 Subject: [PATCH 26/44] doc comments --- libs/zopenvr/README.md | 3 +- libs/zopenvr/src/common.zig | 80 +++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index fd2599124..27050a536 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -96,4 +96,5 @@ For better types on render structs, enable the corresponding options when import | Metal | | | | ## todo -generate bindings from original json +- generate bindings from original json +- maybe get doc comments from openvr.h diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index e3e18eb04..03699bfed 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -856,29 +856,41 @@ pub const ApplicationError = error{ pub const ApplicationErrorCode = enum(i32) { none = 0, - app_key_already_exists = 100, // Only one application can use any given key - no_manifest = 101, // the running application does not have a manifest - no_application = 102, // No application is running + /// Only one application can use any given key + app_key_already_exists = 100, + /// the running application does not have a manifest + no_manifest = 101, + /// No application is running + no_application = 102, invalid_index = 103, - unknown_application = 104, // the application could not be found - ipc_failed = 105, // An IPC failure caused the request to fail + /// the application could not be found + unknown_application = 104, + /// An IPC failure caused the request to fail + ipc_failed = 105, application_already_running = 106, invalid_manifest = 107, invalid_application = 108, - launch_failed = 109, // the process didn't start - application_already_starting = 110, // the system was already starting the same application - launch_in_progress = 111, // The system was already starting a different application + /// the process didn't start + launch_failed = 109, + /// the system was already starting the same application + application_already_starting = 110, + /// The system was already starting a different application + launch_in_progress = 111, old_application_quitting = 112, transition_aborted = 113, - is_template = 114, // error when you try to call LaunchApplication() on a template type app (use LaunchTemplateApplication) + /// error when you try to call LaunchApplication() on a template type app (use LaunchTemplateApplication) + is_template = 114, steam_vr_is_exiting = 115, - buffer_too_small = 200, // The provided buffer was too small to fit the requested data - property_not_set = 201, // The requested property was not set + /// The provided buffer was too small to fit the requested data + buffer_too_small = 200, + /// The requested property was not set + property_not_set = 201, unknown_property = 202, invalid_parameter = 203, - not_implemented = 300, // Fcn is not implemented in current interface + /// Fcn is not implemented in current interface + not_implemented = 300, pub fn fromError(err: ApplicationError) ApplicationErrorCode { return switch (err) { @@ -2220,8 +2232,10 @@ pub const EventStatus = extern struct { status_state: VRState, }; pub const EventKeyboard = extern struct { - new_input: [8]u8, // 7 bytes of utf8 + null - user_value: u64, // caller specified opaque token + /// 7 bytes of utf8 + null + new_input: [8]u8, + /// caller specified opaque token + user_value: u64, overlay_handle: OverlayHandle, }; pub const EventIpd = extern struct { @@ -2830,11 +2844,15 @@ pub const OverlayFlags = packed struct(u32) { show_touch_pad_scroll_wheel: bool = false, transfer_ownership_to_internal_process: bool = false, - side_by_side_parallel: bool = false, // Texture is left/right - side_by_side_crossed: bool = false, // Texture is crossed and right/left + /// Texture is left/right + side_by_side_parallel: bool = false, + /// Texture is crossed and right/left + side_by_side_crossed: bool = false, - panorama: bool = false, // Texture is a panorama - stereo_panorama: bool = false, // Texture is a stereo panorama + /// Texture is a panorama + panorama: bool = false, + /// Texture is a stereo panorama + stereo_panorama: bool = false, sort_with_non_scene_overlays: bool = false, visible_in_dashboard: bool = false, @@ -2906,8 +2924,10 @@ pub const OverlayTransformType = enum(i32) { pub const OverlayProjection = RawProjection; // order is left right top bottom pub const OverlayInputMethod = enum(i32) { - None = 0, // No input events will be generated automatically for this overlay - Mouse = 1, // Tracked controllers will get mouse events automatically + /// No input events will be generated automatically for this overlay + None = 0, + /// Tracked controllers will get mouse events automatically + Mouse = 1, // DualAnalog = 2, // No longer supported }; @@ -2953,16 +2973,16 @@ pub const OverlayIntersectionMaskPrimitive = extern struct { }; pub const KeyboardFlags = packed struct(u32) { - // Makes the keyboard send key events immediately instead of accumulating a buffer */ - Minimal: bool = false, - // Makes the keyboard take all focus and dismiss when clicking off the panel */ - Modal: bool = false, - // Shows arrow keys on the keyboard when in minimal mode. Buffered (non-minimal) mode always has them. In minimal - // mode, when arrow keys are pressed, they send ANSI escape sequences (e.g. "\x1b[D" for left arrow). - ShowArrowKeys: bool = false, - // Shows the hide keyboard button instead of a Done button. The Done key sends a VREvent_KeyboardDone when - // clicked. Hide only sends the Closed event. - HideDoneKey: bool = false, + /// Makes the keyboard send key events immediately instead of accumulating a buffer + minimal: bool = false, + /// Makes the keyboard take all focus and dismiss when clicking off the panel + modal: bool = false, + /// Shows arrow keys on the keyboard when in minimal mode. Buffered (non-minimal) mode always has them. In minimal + /// mode, when arrow keys are pressed, they send ANSI escape sequences (e.g. "\x1b[D" for left arrow). + show_arrow_keys: bool = false, + /// Shows the hide keyboard button instead of a Done button. The Done key sends a Event.keyboard_done when + /// clicked. Hide only sends the Closed event. + hide_done_key: bool = false, _padding: u28 = 0, }; From 1bbd7e77966ec758b814eda837e37c606d4c163d Mon Sep 17 00:00:00 2001 From: zivoy Date: Wed, 3 Jul 2024 10:25:47 -0400 Subject: [PATCH 27/44] test all files --- libs/zopenvr/build.zig | 2 +- libs/zopenvr/src/tests.zig | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 libs/zopenvr/src/tests.zig diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index ae027abed..e5a600807 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -44,7 +44,7 @@ pub fn build(b: *std.Build) void { { const tests = b.addTest(.{ .name = "openvr-tests", - .root_source_file = b.path("src/openvr.zig"), + .root_source_file = b.path("src/tests.zig"), .target = target, .optimize = optimize, }); diff --git a/libs/zopenvr/src/tests.zig b/libs/zopenvr/src/tests.zig new file mode 100644 index 000000000..87912e2c3 --- /dev/null +++ b/libs/zopenvr/src/tests.zig @@ -0,0 +1,12 @@ +comptime { + _ = @import("applications.zig"); + _ = @import("chaperone.zig"); + _ = @import("common.zig"); + _ = @import("compositor.zig"); + _ = @import("input.zig"); + _ = @import("openvr.zig"); + _ = @import("overlay.zig"); + _ = @import("render_models.zig"); + _ = @import("renderers.zig"); + _ = @import("system.zig"); +} From 64fa8937584a95523b8292dc1f5385f14200dab2 Mon Sep 17 00:00:00 2001 From: zivoy Date: Wed, 3 Jul 2024 12:32:42 -0400 Subject: [PATCH 28/44] coordnate system --- libs/zopenvr/src/common.zig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 03699bfed..c6c7a4c25 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -725,6 +725,11 @@ pub const Vector4 = extern struct { v: [4]f32, }; +/// right-handed system +/// +y is up +/// +x is to the right +/// -z is forward +/// Distance unit is in meters pub const Matrix34 = extern struct { m: [3][4]f32, }; @@ -733,6 +738,10 @@ pub const Matrix44 = extern struct { m: [4][4]f32, }; +pub const Matrix33 = extern struct { + m: [3][3]f32, +}; + pub const Rect2 = extern struct { top_left: Vector2, bottom_right: Vector2, From a153c4131054c8b394f9a66c2d7f8b6febefbbdd Mon Sep 17 00:00:00 2001 From: zivoy Date: Wed, 3 Jul 2024 13:30:55 -0400 Subject: [PATCH 29/44] dont panic --- libs/zopenvr/build.zig | 45 +++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index e5a600807..862aa82b1 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -67,12 +67,33 @@ pub fn build(b: *std.Build) void { } } +fn testSuportedTarget(step: *std.Build.Step, target: std.Target) error{ OutOfMemory, MakeFailed }!void { + const supportedArch = switch (target.cpu.arch) { + .x86, .x86_64 => true, + else => false, + }; + const supportedOs = switch (target.os.tag) { + .windows, .linux => true, + else => false, + }; + if (supportedOs and supportedArch) return; + + return step.fail("zopenvr does not support building for {s}{s}{s}{s}{s}", .{ + if (!supportedArch and supportedOs) "the " else "", + if (!supportedArch) @tagName(target.cpu.arch) else "", + if (!supportedArch and supportedOs) " platform" else "", + if (!supportedArch and !supportedOs) " " else "", + if (!supportedOs) @tagName(target.os.tag) else "", + }); +} + pub fn addLibraryPathsTo(compile_step: *std.Build.Step.Compile) void { const b = compile_step.step.owner; const target = compile_step.rootModuleTarget(); const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + testSuportedTarget(&compile_step.step, target) catch return; + const arch = target.cpu.arch; const path: []const u8 = switch (target.os.tag) { .windows => switch (arch) { @@ -85,9 +106,8 @@ pub fn addLibraryPathsTo(compile_step: *std.Build.Step.Compile) void { .x86 => "libs/openvr/lib/linux32", else => unreachable, }, - else => null, - } orelse @panic("unsupported target os"); - // compile_step.step.fail() todo + else => unreachable, + }; compile_step.addLibraryPath(.{ .cwd_relative = b.pathJoin(&.{ source_path_prefix, path }), @@ -99,7 +119,8 @@ pub fn addRPathsTo(compile_step: *std.Build.Step.Compile) void { const target = compile_step.rootModuleTarget(); const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; - if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + testSuportedTarget(&compile_step.step, target) catch return; + const arch = target.cpu.arch; const path: []const u8 = switch (target.os.tag) { .windows => switch (arch) { @@ -112,8 +133,8 @@ pub fn addRPathsTo(compile_step: *std.Build.Step.Compile) void { .x86 => "libs/openvr/bin/linux32", else => unreachable, }, - else => null, - } orelse @panic("unsupported target os"); + else => unreachable, + }; compile_step.addRPath(.{ .cwd_relative = b.pathJoin(&.{ source_path_prefix, path }), @@ -121,13 +142,15 @@ pub fn addRPathsTo(compile_step: *std.Build.Step.Compile) void { } pub fn linkOpenVR(compile_step: *std.Build.Step.Compile) void { + testSuportedTarget(&compile_step.step, compile_step.rootModuleTarget()) catch return; + switch (compile_step.rootModuleTarget().os.tag) { .windows => compile_step.linkSystemLibrary("openvr_api"), .linux => { compile_step.root_module.linkSystemLibrary("openvr_api", .{ .needed = true }); compile_step.root_module.addRPathSpecial("$ORIGIN"); }, - else => {}, + else => unreachable, } } @@ -136,7 +159,7 @@ pub fn installOpenVR( target: std.Target, install_dir: std.Build.InstallDir, ) void { - if (!target.cpu.arch.isX86()) @panic("unsupported target architecture"); + testSuportedTarget(step, target) catch return; const b = step.owner; const source_path_prefix = comptime std.fs.path.dirname(@src().file) orelse "."; @@ -153,8 +176,8 @@ pub fn installOpenVR( .x86 => "libs/openvr/bin/linux32/libopenvr_api.so", else => unreachable, }, - else => null, - } orelse @panic("unsupported target os"); + else => unreachable, + }; step.dependOn(switch (target.os.tag) { .windows => &b.addInstallFileWithDir( From 6c9c528277be520a83ca332459034b5a5859bc07 Mon Sep 17 00:00:00 2001 From: zivoy Date: Fri, 26 Jul 2024 13:57:05 -0400 Subject: [PATCH 30/44] added checks and doc comments --- libs/zopenvr/src/overlay.zig | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 09bf0916a..8ec523c08 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -191,22 +191,28 @@ pub fn getOverlayWidthInMeters(self: Self, overlay_handle: common.OverlayHandle) return width_in_meters; } +/// Use to draw overlay as a curved surface. Curvature is a percentage from [0..1] where 1 is a fully closed cylinder and 0 is a flat plane. pub fn setOverlayCurvature(self: Self, overlay_handle: common.OverlayHandle, curvature: f32) common.OverlayError!void { + std.debug.assert(0 <= curvature and curvature <= 1); return self.function_table.SetOverlayCurvature(overlay_handle, curvature).maybe(); } +/// Use to draw overlay as a curved surface. Radius is in meters and is based on the screen width. pub fn setOverlayCurvatureRadius(self: Self, overlay_handle: common.OverlayHandle, radius: f32) common.OverlayError!void { + std.debug.assert(0 < radius and radius <= 2 * std.math.pi); const width = try self.getOverlayWidthInMeters(overlay_handle); const curvature = width / (2 * std.math.pi * radius); return self.setOverlayCurvature(overlay_handle, curvature); } +/// returns overlay curvature. Curvature is a percentage from (0..1] where 1 is a fully closed cylinder. pub fn getOverlayCurvature(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { var curvature: f32 = undefined; try self.function_table.GetOverlayCurvature(overlay_handle, &curvature).maybe(); return curvature; } +/// returns overlay curve radius in meters pub fn getOverlayCurvatureRadius(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { const width = try self.getOverlayWidthInMeters(overlay_handle); const curvature = try self.getOverlayCurvature(overlay_handle); @@ -214,10 +220,13 @@ pub fn getOverlayCurvatureRadius(self: Self, overlay_handle: common.OverlayHandl return radius; } +/// Sets the pitch angle (in radians) of the overlay before curvature is applied -- to form a fan or disk. pub fn setOverlayPreCurvePitch(self: Self, overlay_handle: common.OverlayHandle, radians: f32) common.OverlayError!void { + std.debug.assert(0 <= radians and radians <= 2 * std.math.pi); return self.function_table.SetOverlayPreCurvePitch(overlay_handle, radians).maybe(); } +/// returns overlay pre-curve angle in radians pub fn getOverlayPreCurvePitch(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!f32 { var radians: f32 = undefined; try self.function_table.GetOverlayPreCurvePitch(overlay_handle, &radians).maybe(); @@ -367,6 +376,10 @@ pub fn getTransformForOverlayCoordinates( return transform; } +/// This function will block until the top of each frame, and can therefore be used to synchronize with the runtime's update rate. +/// +/// Note: In non-async mode, some signals may be dropped due to scene app performance, so passing a timeout of 1000/refresh rate +/// may be useful depending on the overlay app's desired behavior. pub fn waitFrameSync(self: Self, timeout_ms: u32) common.OverlayError!void { return self.function_table.WaitFrameSync(timeout_ms).maybe(); } @@ -501,7 +514,7 @@ pub fn setOverlayFromFile(self: Self, overlay_handle: common.OverlayHandle, file return self.function_table.SetOverlayFromFile(overlay_handle, file_path.ptr).maybe(); } -// todo make typeing accomedate more engines rather then just what was in the docs +// TODO: make typeing accomedate more engines rather then just what was in the docs pub fn getOverlayTextureD3D11(self: Self, overlay_handle: common.OverlayHandle, native_texture_ref: *d3d11.IResource) common.OverlayError!struct { native_texture_handle: *d3d11.IShaderResourceView, width: u32, @@ -647,7 +660,7 @@ pub fn showKeyboardForOverlay( return err.maybe(); } -// todo check if max length is the same as max chars from above or one off +// TODO: check if max length is the same as max chars from above or one off pub fn getKeyboardText(self: Self, allocator: std.mem.Allocator, max_length: u32) error{OutOfMemory}![:0]u8 { const buffer = try allocator.allocSentinel(u8, max_length - 1, 0); const size = self.function_table.GetKeyboardText(buffer.ptr, max_length); From a9db2c1e75cc331f84375015c6c010a9a8d827a5 Mon Sep 17 00:00:00 2001 From: zivoy Date: Fri, 26 Jul 2024 17:34:56 -0400 Subject: [PATCH 31/44] typo --- libs/zopenvr/README.md | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index 27050a536..95e501b0f 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -58,31 +58,31 @@ For better types on render structs, enable the corresponding options when import ## Implementation progress -| Interface | Status | -| --------------- | :-----------------: | -| Applications | ✅ | -| BlockQueue | | -| Chaperone | ✅ | -| ChaperoneSetup | | -| Compositor | ✅
(see bellow) | -| Debug | | -| DriverManager | | -| ExtendedDisplay | | -| HeadsetView | | -| Input | ✅ | -| IOBuffer | | -| Notifications | | -| Overlay | ✅ | -| OverlayView | | -| Paths | | -| Properties | | -| RenderModels | ✅ | -| Resources | | -| Screenshots | | -| Settings | | -| SpatialAnchors | | -| System | ✅ | -| TrackedCamera | | +| Interface | Status | +| --------------- | :----------------: | +| Applications | ✅ | +| BlockQueue | | +| Chaperone | ✅ | +| ChaperoneSetup | | +| Compositor | ✅
(see below) | +| Debug | | +| DriverManager | | +| ExtendedDisplay | | +| HeadsetView | | +| Input | ✅ | +| IOBuffer | | +| Notifications | | +| Overlay | ✅ | +| OverlayView | | +| Paths | | +| Properties | | +| RenderModels | ✅ | +| Resources | | +| Screenshots | | +| Settings | | +| SpatialAnchors | | +| System | ✅ | +| TrackedCamera | | ### Compositor supported renderers | Renderer | Handle type | Zig handle name | Support | From 317728e3846d9a0a38978edffc6ae0a3d0ea79a4 Mon Sep 17 00:00:00 2001 From: zivoy Date: Fri, 26 Jul 2024 22:19:25 -0400 Subject: [PATCH 32/44] simple green overlay --- build.zig | 1 + libs/zopenvr/src/overlay.zig | 2 +- samples/openvr_mango/build.zig | 3 - samples/openvr_overlay/README.md | 5 + samples/openvr_overlay/build.zig | 47 +++++++ samples/openvr_overlay/src/openvr_overlay.zig | 127 ++++++++++++++++++ 6 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 samples/openvr_overlay/README.md create mode 100644 samples/openvr_overlay/build.zig create mode 100644 samples/openvr_overlay/src/openvr_overlay.zig diff --git a/build.zig b/build.zig index cee58c03b..96704562a 100644 --- a/build.zig +++ b/build.zig @@ -129,6 +129,7 @@ const samples_cross_platform = struct { pub const minimal_sdl_gl = @import("samples/minimal_sdl_gl/build.zig"); pub const minimal_zgui_glfw_gl = @import("samples/minimal_zgui_glfw_gl/build.zig"); pub const openvr_mango = @import("samples/openvr_mango/build.zig"); + pub const openvr_overlay = @import("samples/openvr_overlay/build.zig"); pub usingnamespace struct { // WebGPU samples pub const audio_experiments_wgpu = @import("samples/audio_experiments_wgpu/build.zig"); diff --git a/libs/zopenvr/src/overlay.zig b/libs/zopenvr/src/overlay.zig index 8ec523c08..0328b0b83 100644 --- a/libs/zopenvr/src/overlay.zig +++ b/libs/zopenvr/src/overlay.zig @@ -469,7 +469,7 @@ pub fn clearOverlayCursorPositionOverride(self: Self, overlay_handle: common.Ove } pub fn setOverlayTexture(self: Self, overlay_handle: common.OverlayHandle, texture: common.Texture) common.OverlayError!void { - return self.function_table.SetOverlayTexture(overlay_handle, texture.ptr).maybe(); + return self.function_table.SetOverlayTexture(overlay_handle, &texture).maybe(); } pub fn clearOverlayTexture(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!void { diff --git a/samples/openvr_mango/build.zig b/samples/openvr_mango/build.zig index 7333211ae..eb69900e9 100644 --- a/samples/openvr_mango/build.zig +++ b/samples/openvr_mango/build.zig @@ -23,8 +23,5 @@ pub fn build(b: *std.Build, options: Options) *std.Build.Step.Compile { @import("zopenvr").linkOpenVR(exe); @import("zopenvr").installOpenVR(&exe.step, options.target.result, .bin); - const exe_options = b.addOptions(); - exe.root_module.addOptions("build_options", exe_options); - return exe; } diff --git a/samples/openvr_overlay/README.md b/samples/openvr_overlay/README.md new file mode 100644 index 000000000..62451ab01 --- /dev/null +++ b/samples/openvr_overlay/README.md @@ -0,0 +1,5 @@ +## openvr overlay exmaple + +simple overlay example + +![image](screenshot.png) diff --git a/samples/openvr_overlay/build.zig b/samples/openvr_overlay/build.zig new file mode 100644 index 000000000..918642981 --- /dev/null +++ b/samples/openvr_overlay/build.zig @@ -0,0 +1,47 @@ +const std = @import("std"); + +const Options = @import("../../build.zig").Options; + +const demo_name = "openvr_overlay"; + +pub fn build(b: *std.Build, options: Options) *std.Build.Step.Compile { + const cwd_path = b.pathJoin(&.{ "samples", demo_name }); + const src_path = b.pathJoin(&.{ cwd_path, "src" }); + const exe = b.addExecutable(.{ + .name = demo_name, + .root_source_file = b.path(b.pathJoin(&.{ src_path, demo_name ++ ".zig" })), + .target = options.target, + .optimize = options.optimize, + }); + + const zopenvr = b.dependency("zopenvr", .{ + .target = options.target, + }); + exe.root_module.addImport("zopenvr", zopenvr.module("root")); + + @import("zopenvr").addLibraryPathsTo(exe); + @import("zopenvr").linkOpenVR(exe); + @import("zopenvr").installOpenVR(&exe.step, options.target.result, .bin); + + @import("system_sdk").addLibraryPathsTo(exe); + + const zglfw = b.dependency("zglfw", .{ + .target = options.target, + }); + exe.root_module.addImport("zglfw", zglfw.module("root")); + exe.linkLibrary(zglfw.artifact("glfw")); + + const zopengl = b.dependency("zopengl", .{ + .target = options.target, + }); + exe.root_module.addImport("zopengl", zopengl.module("root")); + + const zgui = b.dependency("zgui", .{ + .target = options.target, + .backend = .glfw_opengl3, + }); + exe.root_module.addImport("zgui", zgui.module("root")); + exe.linkLibrary(zgui.artifact("imgui")); + + return exe; +} diff --git a/samples/openvr_overlay/src/openvr_overlay.zig b/samples/openvr_overlay/src/openvr_overlay.zig new file mode 100644 index 000000000..2ce706cfc --- /dev/null +++ b/samples/openvr_overlay/src/openvr_overlay.zig @@ -0,0 +1,127 @@ +const std = @import("std"); +const glfw = @import("zglfw"); +const zopengl = @import("zopengl"); +const zopenvr = @import("zopenvr"); + +const gl_major = 4; +const gl_minor = 0; + +const width = 512; +const height = 512; +const overlayWidth = 0.25; // meters +const fps = 10; + +pub fn main() !void { + // var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + // defer arena.deinit(); + // const allocator = arena.allocator(); + + try glfw.init(); + defer glfw.terminate(); + + glfw.windowHintTyped(.context_version_major, gl_major); + glfw.windowHintTyped(.context_version_minor, gl_minor); + glfw.windowHintTyped(.opengl_profile, .opengl_core_profile); + glfw.windowHintTyped(.opengl_forward_compat, true); + glfw.windowHintTyped(.client_api, .opengl_api); + // glfw.windowHintTyped(.doublebuffer, .opengl_api); + glfw.windowHintTyped(.visible, false); + + const window = try glfw.Window.create(600, 600, "zig-gamedev: openvr_overlay", null); + defer window.destroy(); + + glfw.makeContextCurrent(window); + + try zopengl.loadCoreProfile(glfw.getProcAddress, gl_major, gl_minor); + const gl = zopengl.bindings; + glfw.swapInterval(1); + + const openvr = zopenvr.init(.overlay) catch |err| { + const errDesc = zopenvr.initErrorAsEnglishDescription(err); + const errSym = zopenvr.initErrorAsSymbol(err); + std.log.err("Could not initialize OpenVR: {s} ({s})\n", .{ errDesc, errSym }); + std.process.exit(1); + }; + defer openvr.deinit(); + + const system = try openvr.system(); + const overlay = try openvr.overlay(); + + const overlayID = try overlay.createOverlay("zopenvr-overlay", "test overlay with zgui"); + try overlay.setOverlayWidthInMeters(overlayID, overlayWidth); + try overlay.setOverlayColor(overlayID, 0.3, 0.8, 0.9); + try overlay.setOverlayTextureBounds(overlayID, .{ + .u_min = 1, + .v_min = 0, + .u_max = 0, + .v_max = 1, + }); + + try overlay.showOverlay(overlayID); + + var overlayTexture: gl.Uint = undefined; + { + gl.genTextures(1, &overlayTexture); + gl.bindTexture(gl.TEXTURE_2D, overlayTexture); + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + + // var junkData = try allocator.alloc(u8, width * height * 4); + // defer allocator.free(junkData); + // @memset(&junkData, 255); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + } + + var overlay_associated = false; + while (!window.shouldClose()) { + glfw.pollEvents(); + + gl.clearBufferfv(gl.COLOR, 0, &[_]f32{ 0.2, 0.6, 0.4, 1.0 }); + + /////// + + if (!overlay_associated) blk: { + const index = system.getTrackedDeviceIndexForControllerRole(.left_hand); + if (index == zopenvr.tracked_device_index_invalid or index == zopenvr.hmd) { + std.log.warn("couldn't find a left controller to attach the overlay to", .{}); + break :blk; + } + + var transform = std.mem.zeroes(zopenvr.Matrix34); + transform.m[0][0] = 1; + transform.m[1][2] = 1; + transform.m[2][1] = 1; + + transform.m[2][3] = -0.1; + + overlay.setOverlayTransformTrackedDeviceRelative(overlayID, index, transform) catch |err| { + std.log.err("Error connecting the overlay to the device: {s}\n", .{overlay.getOverlayErrorNameFromError(err)}); + break :blk; + }; + + std.log.info("Successfully associated the overlay to the tracked device ({d} {x:0>8}).\n", .{ index, overlayID }); + + overlay_associated = true; + } + + gl.bindTexture(gl.TEXTURE_2D, overlayTexture); + gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, width, height, 0); + + try overlay.setOverlayTexture(overlayID, .{ + .handle = @ptrFromInt(overlayTexture), + .color_space = .auto, + .texture_type = .opengl, + }); + + if (overlay_associated) { + while (overlay.pollNextOverlayEvent(overlayID)) |event| { + _ = event; + } + } + + // window.swapBuffers(); + + try overlay.waitFrameSync(1000 / fps); + } +} From 5e04f18a85730c15317037d5adfb438c9f42e023 Mon Sep 17 00:00:00 2001 From: zivoy Date: Fri, 26 Jul 2024 23:43:02 -0400 Subject: [PATCH 33/44] opengl support and vulkan functions --- libs/zopenvr/README.md | 2 +- libs/zopenvr/build.zig | 8 +++- libs/zopenvr/build.zig.zon | 4 ++ libs/zopenvr/src/common.zig | 30 +++++++++++++ libs/zopenvr/src/compositor.zig | 74 +++++++++++++++++++++++++++++---- libs/zopenvr/src/renderers.zig | 11 +++++ 6 files changed, 119 insertions(+), 10 deletions(-) diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index 95e501b0f..2a6875fb4 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -88,7 +88,7 @@ For better types on render structs, enable the corresponding options when import | Renderer | Handle type | Zig handle name | Support | |--------------------|-----------------------|---------------------------------|:-------:| | DirectX 11 (d3d11) | ID3D11Texture2D | zwin32.d3d11.ITexture2D | ✅ | -| OpenGL | | | | +| OpenGL | GLUint \| buffer name | zopengl.bindings.Uint | ✅ | | Vulkan | VRVulkanTextureData_t | | | | IOSurface | | | | | DirectX 12 (d3d12) | D3D12TextureData_t | zopenvr.common.D3D12TextureData | ✅ | diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index 862aa82b1..6a53158e5 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -15,7 +15,7 @@ pub fn build(b: *std.Build) void { d3d11: bool = false, d3d12: bool = false, // valken: bool = false, - // opengl: bool = false, + opengl: bool = false, }{}; var need_zwin32 = false; @@ -32,6 +32,12 @@ pub fn build(b: *std.Build) void { mod.addImport("zwin32", zwin32.module("root")); } } + if (b.option(bool, "opengl", "Enable OpenGL backend") orelse false) { + backends.opengl = true; + if (b.lazyDependency("zopengl", .{})) |zopengl| { + mod.addImport("zopengl", zopengl.module("root")); + } + } const options = b.addOptions(); inline for (@typeInfo(@TypeOf(backends)).Struct.fields) |field| { diff --git a/libs/zopenvr/build.zig.zon b/libs/zopenvr/build.zig.zon index e6355f7ac..c779253ba 100644 --- a/libs/zopenvr/build.zig.zon +++ b/libs/zopenvr/build.zig.zon @@ -13,5 +13,9 @@ .path = "../zwin32", .lazy = true, }, + .zopengl = .{ + .path = "../zopengl", + .lazy = true, + }, }, } diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index c6c7a4c25..2b83b5258 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -781,13 +781,24 @@ pub const TrackedDevicePose = extern struct { }; pub const TextureType = enum(i32) { + ///Handle has been invalidated invalid = -1, + ///Handle is an ID3D11Texture directx = 0, + ///Handle is an OpenGL texture name or an OpenGL render buffer name, depending on submit flags opengl = 1, + ///Handle is a pointer to a VulkanTextureData structure vulkan = 2, + ///Handle is a macOS cross-process-sharable IOSurfaceRef, deprecated in favor of TextureType.metal on supported platforms iosurface = 3, + ///Handle is a pointer to a D3D12TextureData_t structure directx12 = 4, + ///Handle is a HANDLE DXGI share handle, only supported for Overlay render targets. + ///this texture is used directly by our renderer, so only perform atomic (copyresource or resolve) on it dxgi_shared_handle = 5, + ///Handle is a MTLTexture conforming to the MTLSharedTexture protocol. Textures submitted to zopenvr.compositor.submit which + ///are of type MTLTextureType2DArray assume layer 0 is the left eye texture (zopenvr.Eye.left), layer 1 is the right + ///eye texture (zopenvr.Eye.right) metal = 6, reserved = 7, }; @@ -3081,3 +3092,22 @@ pub fn RawImage(comptime T: type, comptime bytes_per_pixel: u32) type { } }; } + +pub const GLSharedTextureHandle = *const anyopaque; + +pub const VulkanTextureData = extern struct { + image: u64, + device: renderers.vulkan.VkDevice, + physical_device: renderers.vulkan.VkPhysicalDevice, + instance: renderers.vulkan.VkInstance, + queue: renderers.vulkan.VkQueue, + queue_family_index: u32, + width: u32, + height: u32, + format: u32, + sample_count: u32, +}; +pub const VRVulkanTextureArrayData = extern struct { + array_index: u32, + array_size: u32, +}; diff --git a/libs/zopenvr/src/compositor.zig b/libs/zopenvr/src/compositor.zig index deee35a0b..1385a51e1 100644 --- a/libs/zopenvr/src/compositor.zig +++ b/libs/zopenvr/src/compositor.zig @@ -268,6 +268,66 @@ pub fn releaseMirrorTextureD3D11(self: Self, d3d11_shader_resource_view: *d3d11. self.function_table.ReleaseMirrorTextureD3D11(d3d11_shader_resource_view); } +pub fn getMirrorTextureGL(self: Self, eye: common.Eye) common.CompositorError!struct { + texture_id: renderers.opengl.Uint, + shared_texture_handle: common.GLSharedTextureHandle, +} { + var texture_id: renderers.opengl.Uint = undefined; + var shared_texture_handle: common.GLSharedTextureHandle = undefined; + self.function_table.GetMirrorTextureGL(eye, &texture_id, &shared_texture_handle); + + return .{ + .texture_id = texture_id, + .shared_texture_handle = shared_texture_handle, + }; +} + +pub fn releaseSharedGLTexture(self: Self, texture_id: renderers.opengl.Uint, shared_texture_handle: common.GLSharedTextureHangle) bool { + self.function_table.ReleaseSharedGLTexture(texture_id, shared_texture_handle); +} + +pub fn lockGLSharedTextureForAccess(self: Self, shared_texture_handle: common.GLSharedTextureHangle) void { + self.function_table.LockGLSharedTextureForAccess(shared_texture_handle); +} + +pub fn unlockGLSharedTextureForAccess(self: Self, shared_texture_handle: common.GLSharedTextureHangle) void { + self.function_table.UnlockGLSharedTextureForAccess(shared_texture_handle); +} + +/// The string will be a space separated list of required instance extensions to enable in VkCreateInstance +pub fn getVulkanInstanceExtensionsRequired(self: Self, allocator: std.mem.Allocator) [:0]u8 { + const buffer_length = self.function_table.GetVulkanInstanceExtensionsRequired(null, 0); + if (buffer_length == 0) { + return allocator.allocSentinel(u8, 0, 0); + } + + const buffer = try allocator.allocSentinel(u8, buffer_length - 1, 0); + errdefer allocator.free(buffer); + + if (buffer.len > 0) { + _ = self.function_table.GetVulkanInstanceExtensionsRequired(buffer.ptr, buffer_length); + } + + return buffer; +} + +/// The string will be a space separated list of required device extensions to enable in VkCreateDevice +pub fn getVulkanDeviceExtensionsRequired(self: Self, allocator: std.mem.Allocator, physical_device: renderers.vulkan.VkPhysicalDevice) [:0]u8 { + const buffer_length = self.function_table.GetVulkanDeviceExtensionsRequired(&physical_device, null, 0); + if (buffer_length == 0) { + return allocator.allocSentinel(u8, 0, 0); + } + + const buffer = try allocator.allocSentinel(u8, buffer_length - 1, 0); + errdefer allocator.free(buffer); + + if (buffer.len > 0) { + _ = self.function_table.GetVulkanDeviceExtensionsRequired(physical_device, buffer.ptr, buffer_length); + } + + return buffer; +} + const FunctionTable = extern struct { SetTrackingSpace: *const fn (common.TrackingUniverseOrigin) callconv(.C) void, GetTrackingSpace: *const fn () callconv(.C) common.TrackingUniverseOrigin, @@ -307,15 +367,13 @@ const FunctionTable = extern struct { GetMirrorTextureD3D11: *const fn (common.Eye, ?*anyopaque, *?*d3d11.IShaderResourceView) callconv(.C) common.CompositorErrorCode, ReleaseMirrorTextureD3D11: *const fn (?*d3d11.IShaderResourceView) callconv(.C) void, - // skip over opengl - GetMirrorTextureGL: usize, - ReleaseSharedGLTexture: usize, - LockGLSharedTextureForAccess: usize, - UnlockGLSharedTextureForAccess: usize, + GetMirrorTextureGL: *const fn (common.Eye, *renderers.opengl.Uint, *common.GLSharedTextureHangle) callconv(.C) common.CompositorErrorCode, + ReleaseSharedGLTexture: *const fn (renderers.opengl.Uint, common.GLSharedTextureHangle) callconv(.C) bool, + LockGLSharedTextureForAccess: *const fn (common.GLSharedTextureHangle) callconv(.C) void, + UnlockGLSharedTextureForAccess: *const fn (common.GLSharedTextureHangle) callconv(.C) void, - // skip over vulkan - GetVulkanInstanceExtensionsRequired: usize, - GetVulkanDeviceExtensionsRequired: usize, + GetVulkanInstanceExtensionsRequired: *const fn ([*c]u8, u32) callconv(.C) u32, + GetVulkanDeviceExtensionsRequired: *const fn (?*renderers.vulkan.VkPhysicalDevice, [*c]u8, u32) callconv(.C) u32, SetExplicitTimingMode: *const fn (common.TimingMode) callconv(.C) void, SubmitExplicitTimingData: *const fn () callconv(.C) common.CompositorErrorCode, diff --git a/libs/zopenvr/src/renderers.zig b/libs/zopenvr/src/renderers.zig index e42e006d6..2299186bd 100644 --- a/libs/zopenvr/src/renderers.zig +++ b/libs/zopenvr/src/renderers.zig @@ -11,3 +11,14 @@ pub const d3d11 = if (config.d3d11) @import("zwin32").d3d11 else struct { pub const ITexture2D = anyopaque; pub const IDevice = anyopaque; }; + +pub const opengl = if (config.opengl) @import("zopengl").bindings else struct { + pub const Uint = c_uint; +}; + +pub const vulkan = struct { //if (config.vulkan) @import("vulkan") else struct { + pub const VkPhysicalDevice = anyopaque; + pub const VkDevice = anyopaque; + pub const VkInstance = anyopaque; + pub const VkQueue = anyopaque; +}; From 01385d9717fba0639178e2d11fdab679b05ac199 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 27 Jul 2024 09:49:40 -0400 Subject: [PATCH 34/44] more doc comments --- libs/zopenvr/src/common.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 2b83b5258..9ec1376fd 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -1178,8 +1178,11 @@ pub const SubmitFlags = packed struct(i32) { }; pub const ColorSpace = enum(i32) { + ///Assumes 'gamma' for 8-bit per component formats, otherwise 'linear'. This mirrors the DXGI formats which have _SRGB variants. auto = 0, + ///Texture data can be displayed directly on the display without any conversion (a.k.a. display native format). gamma = 1, + ///Same as gamma but has been converted to a linear representation using DXGI's sRGB conversion algorithm. linear = 2, }; pub const D3D12TextureData = extern struct { From 16885f1e9e4051824831fa87c69c00ef15097ab7 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 27 Jul 2024 09:50:38 -0400 Subject: [PATCH 35/44] dont die on timeout --- samples/openvr_overlay/src/openvr_overlay.zig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/samples/openvr_overlay/src/openvr_overlay.zig b/samples/openvr_overlay/src/openvr_overlay.zig index 2ce706cfc..f9fc8dd04 100644 --- a/samples/openvr_overlay/src/openvr_overlay.zig +++ b/samples/openvr_overlay/src/openvr_overlay.zig @@ -93,7 +93,7 @@ pub fn main() !void { transform.m[1][2] = 1; transform.m[2][1] = 1; - transform.m[2][3] = -0.1; + transform.m[2][3] = -0.12; overlay.setOverlayTransformTrackedDeviceRelative(overlayID, index, transform) catch |err| { std.log.err("Error connecting the overlay to the device: {s}\n", .{overlay.getOverlayErrorNameFromError(err)}); @@ -122,6 +122,9 @@ pub fn main() !void { // window.swapBuffers(); - try overlay.waitFrameSync(1000 / fps); + overlay.waitFrameSync(1000 / fps) catch |err| switch (err) { + zopenvr.OverlayError.TimedOut => std.time.sleep(200 * std.time.ns_per_ms), + else => return err, + }; } } From dd4ef3e672150f8e56e6993eb78d229b16da7358 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 27 Jul 2024 10:26:41 -0400 Subject: [PATCH 36/44] more docs --- libs/zopenvr/src/common.zig | 70 +++++++++++++++++++++++++++++++++---- libs/zopenvr/src/openvr.zig | 16 +++++++++ 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 9ec1376fd..706a2be3c 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -816,11 +816,17 @@ pub const Color = extern struct { }; pub const TrackedControllerRole = enum(i32) { + ///Invalid value for controller type invalid = 0, + ///Tracked device associated with the left hand left_hand = 1, + ///Tracked device associated with the right hand right_hand = 2, + ///Tracked device is opting out of left/right hand selection opt_out = 3, + ///Tracked device is a treadmill or other locomotion device treadmill = 4, + ///Tracked device is a stylus stylus = 5, const max = TrackedControllerRole.stylus; }; @@ -840,7 +846,9 @@ pub const Quaternionf = extern struct { pub const InputValueHandle = u64; pub const ControllerAxis = extern struct { + ///Ranges from -1.0 to 1.0 for joysticks and track pads. Ranges from 0.0 to 1.0 for triggers were 0 is fully released. x: f32, + ///Ranges from -1.0 to 1.0 for joysticks and track pads. Is always 0.0 for triggers. y: f32, }; pub const ControllerState = extern struct { @@ -1613,20 +1621,34 @@ pub const DistortionCoordinates = extern struct { }; pub const TrackedDeviceClass = enum(i32) { + ///the ID was not valid. invalid = 0, + ///Head-Mounted Displays hmd = 1, + ///Tracked controllers controller = 2, + ///Generic trackers, similar to controllers generic_tracker = 3, + ///Camera and base stations that serve as tracking reference points tracking_reference = 4, + ///Accessories that aren't necessarily tracked themselves, but may redirect video output from other tracked devices display_redirect = 5, max = 6, }; +///user_interaction_timeout means the device is in the process of timing out. +///InUse = ( user_interaction || user_interaction_timeout ) +///EventType.tracked_device_user_interaction_started fires when the devices transitions from standby -> user_interaction or idle -> user_interaction. +///EventType.tracked_device_user_interaction_ended fires when the devices transitions from user_interaction_timeout -> idle pub const DeviceActivityLevel = enum(i32) { unknown = -1, + ///No activity for the last 10 seconds idle = 0, + ///Activity (movement or prox sensor) is happening now user_interaction = 1, + ///No activity for the last 0.5 seconds user_interaction_timeout = 2, + ///Idle for at least 5 seconds (configurable in Settings -> Power Management) standby = 3, idle_timeout = 4, }; @@ -2859,41 +2881,77 @@ test "back to error code" { pub const OverlayFlags = packed struct(u32) { _padding: u3 = 0, + ///Set this flag on a dashboard overlay to prevent a tab from showing up for that overlay no_dashboard_tab: bool = false, __padding: u2 = 0, + ///When this is set the overlay will receive EventType.scroll_discrete events like a mouse wheel. + ///Requires mouse input mode. send_vr_discrete_scroll_events: bool = false, + ///Indicates that the overlay would like to receive send_vr_touchpad_events: bool = false, + + ///If set this will render a vertical scroll wheel on the primary controller, + ///only needed if not using OverlayFlags.send_vr_scroll_events (smooth or discrete) but you still want to represent a scroll wheel show_touch_pad_scroll_wheel: bool = false, + ///If this is set ownership and render access to the overlay are transferred + ///to the new scene process on a call to openvr.Applications.launchInternalProcess transfer_ownership_to_internal_process: bool = false, - /// Texture is left/right + ///If set, renders 50% of the texture in each eye, side by side + ///Texture is left/right side_by_side_parallel: bool = false, - /// Texture is crossed and right/left + ///Texture is crossed and right/left side_by_side_crossed: bool = false, - /// Texture is a panorama + ///Texture is a panorama panorama: bool = false, - /// Texture is a stereo panorama + ///Texture is a stereo panorama stereo_panorama: bool = false, + ///If this is set on an overlay owned by the scene application that overlay + ///will be sorted with the "Other" overlays on top of all other scene overlays sort_with_non_scene_overlays: bool = false, + ///If set, the overlay will be shown in the dashboard, otherwise it will be hidden. visible_in_dashboard: bool = false, + ///If this is set and the overlay's input method is not none, the system-wide laser mouse + ///mode will be activated whenever this overlay is visible. make_overlays_interactive_if_visible: bool = false, + ///If this is set the overlay will receive smooth EventType.scroll_smooth that emulate trackpad scrolling. + ///Requires mouse input mode. send_vr_smooth_scroll_events: bool = false, + ///If this is set, the overlay texture will be protected content, preventing unauthorized reads. protected_content: bool = false, + ///If this is set, the laser mouse splat will not be drawn over this overlay. The overlay will + ///be responsible for drawing its own "cursor". hide_laser_intersection: bool = false, + ///If this is set, clicking away from the overlay will cause it to receive a EventType.modal_cancel event. + ///This is ignored for dashboard overlays. wants_modal_behavior: bool = false, + ///If this is set, alpha composition assumes the texture is pre-multiplied is_premultiplied: bool = false, + ///If this is set, the alpha values of the overlay texture will be ignored ignore_texture_alpha: bool = false, + ///If this is set, this overlay will have a control bar drawn underneath of it in the dashboard. enable_control_bar: bool = false, + ///If this is set, the overlay control bar will provide a button to toggle the keyboard. enable_control_bar_keyboard: bool = false, + ///If this is set, the overlay control bar will provide a "close" button which will send a + ///EventType.overlay_closed event to the overlay when pressed. Applications that use this flag are responsible + ///for responding to the event with something that approximates "closing" behavior, such as destroying their + ///overlay and/or shutting down their application. enable_control_bar_close: bool = false, + ///Do not use reserved: bool = false, + ///If this is set, click stabilization will be applied to the laser interaction so that clicks more reliably + ///trigger on the user's intended target enable_click_stabilization: bool = false, + ///If this is set, laser mouse pointer events may be sent for the secondary laser. These events will have + ///cursorIndex set to 0 for the primary laser and 1 for the secondary. multi_cursor: bool = false, ___padding: u3 = 0, + ///See comments on struct pub const Enum = enum(u32) { NoDashboardTab = @bitCast(OverlayFlags{ .no_dashboard_tab = true }), SendVRDiscreteScrollEvents = @bitCast(OverlayFlags{ .send_vr_discrete_scroll_events = true }), @@ -2947,9 +3005,9 @@ pub const OverlayTransformType = enum(i32) { pub const OverlayProjection = RawProjection; // order is left right top bottom pub const OverlayInputMethod = enum(i32) { - /// No input events will be generated automatically for this overlay + ///No input events will be generated automatically for this overlay None = 0, - /// Tracked controllers will get mouse events automatically + ///Tracked controllers will get mouse events automatically Mouse = 1, // DualAnalog = 2, // No longer supported }; diff --git a/libs/zopenvr/src/openvr.zig b/libs/zopenvr/src/openvr.zig index 61cff4949..7d1d7dcb0 100644 --- a/libs/zopenvr/src/openvr.zig +++ b/libs/zopenvr/src/openvr.zig @@ -12,19 +12,35 @@ pub fn init(application_type: ApplicationType) common.InitError!Self { } pub const ApplicationType = enum(i32) { + ///Some other kind of application that isn't covered by the other entries other = 0, + ///Application will submit 3D frames scene = 1, + ///Application only interacts with overlays overlay = 2, + ///Application should not start SteamVR if it's not already running, and should not + ///keep it running if everything else quits. background = 3, + ///Init should not try to load any drivers. The application needs access to utility + ///interfaces (like openvr.Settings and openvr.Applications) but not hardware. utility = 4, + ///Reserved for vrmonitor vr_monitor = 5, + ///Reserved for Steam steam_watchdog = 6, + ///reserved for vrstartup bootstrapper = 7, + ///reserved for vrwebhelper web_helper = 8, + ///reserved for openxr (created instance, but not session yet) open_xr_instance = 9, + ///reserved for openxr (started session) open_xr_scene = 10, + ///reserved for openxr (started overlay session) open_xr_overlay = 11, + ///reserved for the vrprismhost process prism = 12, + ///reserved for the RoomView process room_view = 13, max = 14, }; From f0eddaebee34905499ee382238ed4decf97dacc2 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 27 Jul 2024 13:54:35 -0400 Subject: [PATCH 37/44] qol --- samples/openvr_overlay/src/openvr_overlay.zig | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/samples/openvr_overlay/src/openvr_overlay.zig b/samples/openvr_overlay/src/openvr_overlay.zig index f9fc8dd04..45a22e4fc 100644 --- a/samples/openvr_overlay/src/openvr_overlay.zig +++ b/samples/openvr_overlay/src/openvr_overlay.zig @@ -12,10 +12,6 @@ const overlayWidth = 0.25; // meters const fps = 10; pub fn main() !void { - // var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - // defer arena.deinit(); - // const allocator = arena.allocator(); - try glfw.init(); defer glfw.terminate(); @@ -36,11 +32,24 @@ pub fn main() !void { const gl = zopengl.bindings; glfw.swapInterval(1); - const openvr = zopenvr.init(.overlay) catch |err| { - const errDesc = zopenvr.initErrorAsEnglishDescription(err); - const errSym = zopenvr.initErrorAsSymbol(err); - std.log.err("Could not initialize OpenVR: {s} ({s})\n", .{ errDesc, errSym }); - std.process.exit(1); + const openvr = openvr: { + // if wireless headset not connected then retry till its present + while (true) { + const openvr = zopenvr.init(.overlay) catch |err| { + const errDesc = zopenvr.initErrorAsEnglishDescription(err); + const errSym = zopenvr.initErrorAsSymbol(err); + std.log.err("Could not initialize OpenVR: {s} ({s})\n", .{ errDesc, errSym }); + + switch (err) { + zopenvr.InitError.DriverWirelessHmdNotConnected => { + std.time.sleep(2 * std.time.ns_per_s); + continue; + }, + else => std.process.exit(1), + } + }; + break :openvr openvr; + } }; defer openvr.deinit(); @@ -67,9 +76,6 @@ pub fn main() !void { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - // var junkData = try allocator.alloc(u8, width * height * 4); - // defer allocator.free(junkData); - // @memset(&junkData, 255); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); } From 8c31ccfad1b9e3fb05a930e5b15a871f3af359d0 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 27 Jul 2024 14:23:06 -0400 Subject: [PATCH 38/44] move doc comments to enum --- libs/zopenvr/src/common.zig | 79 +++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 706a2be3c..8b27b2302 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -2879,103 +2879,104 @@ test "back to error code" { try expectEqual(code, OverlayErrorCode.fromError(err)); } +///See comments in enum pub const OverlayFlags = packed struct(u32) { _padding: u3 = 0, - ///Set this flag on a dashboard overlay to prevent a tab from showing up for that overlay no_dashboard_tab: bool = false, __padding: u2 = 0, - ///When this is set the overlay will receive EventType.scroll_discrete events like a mouse wheel. - ///Requires mouse input mode. send_vr_discrete_scroll_events: bool = false, - ///Indicates that the overlay would like to receive send_vr_touchpad_events: bool = false, - ///If set this will render a vertical scroll wheel on the primary controller, - ///only needed if not using OverlayFlags.send_vr_scroll_events (smooth or discrete) but you still want to represent a scroll wheel show_touch_pad_scroll_wheel: bool = false, - ///If this is set ownership and render access to the overlay are transferred - ///to the new scene process on a call to openvr.Applications.launchInternalProcess transfer_ownership_to_internal_process: bool = false, - ///If set, renders 50% of the texture in each eye, side by side - ///Texture is left/right side_by_side_parallel: bool = false, - ///Texture is crossed and right/left side_by_side_crossed: bool = false, - ///Texture is a panorama panorama: bool = false, - ///Texture is a stereo panorama stereo_panorama: bool = false, - ///If this is set on an overlay owned by the scene application that overlay - ///will be sorted with the "Other" overlays on top of all other scene overlays sort_with_non_scene_overlays: bool = false, - ///If set, the overlay will be shown in the dashboard, otherwise it will be hidden. visible_in_dashboard: bool = false, - ///If this is set and the overlay's input method is not none, the system-wide laser mouse - ///mode will be activated whenever this overlay is visible. make_overlays_interactive_if_visible: bool = false, - ///If this is set the overlay will receive smooth EventType.scroll_smooth that emulate trackpad scrolling. - ///Requires mouse input mode. send_vr_smooth_scroll_events: bool = false, - ///If this is set, the overlay texture will be protected content, preventing unauthorized reads. protected_content: bool = false, - ///If this is set, the laser mouse splat will not be drawn over this overlay. The overlay will - ///be responsible for drawing its own "cursor". hide_laser_intersection: bool = false, - ///If this is set, clicking away from the overlay will cause it to receive a EventType.modal_cancel event. - ///This is ignored for dashboard overlays. wants_modal_behavior: bool = false, - ///If this is set, alpha composition assumes the texture is pre-multiplied is_premultiplied: bool = false, - ///If this is set, the alpha values of the overlay texture will be ignored ignore_texture_alpha: bool = false, - ///If this is set, this overlay will have a control bar drawn underneath of it in the dashboard. enable_control_bar: bool = false, - ///If this is set, the overlay control bar will provide a button to toggle the keyboard. enable_control_bar_keyboard: bool = false, - ///If this is set, the overlay control bar will provide a "close" button which will send a - ///EventType.overlay_closed event to the overlay when pressed. Applications that use this flag are responsible - ///for responding to the event with something that approximates "closing" behavior, such as destroying their - ///overlay and/or shutting down their application. enable_control_bar_close: bool = false, - ///Do not use reserved: bool = false, - ///If this is set, click stabilization will be applied to the laser interaction so that clicks more reliably - ///trigger on the user's intended target enable_click_stabilization: bool = false, - ///If this is set, laser mouse pointer events may be sent for the secondary laser. These events will have - ///cursorIndex set to 0 for the primary laser and 1 for the secondary. multi_cursor: bool = false, ___padding: u3 = 0, - ///See comments on struct pub const Enum = enum(u32) { + ///Set this flag on a dashboard overlay to prevent a tab from showing up for that overlay NoDashboardTab = @bitCast(OverlayFlags{ .no_dashboard_tab = true }), + ///When this is set the overlay will receive EventType.scroll_discrete events like a mouse wheel. + ///Requires mouse input mode. SendVRDiscreteScrollEvents = @bitCast(OverlayFlags{ .send_vr_discrete_scroll_events = true }), + ///Indicates that the overlay would like to receive touchpad events (EventData.touch_pad_move). SendVRTouchpadEvents = @bitCast(OverlayFlags{ .send_vr_touchpad_events = true }), + ///If set this will render a vertical scroll wheel on the primary controller, + ///only needed if not using OverlayFlags.send_vr_scroll_events (smooth or discrete) but you still want to represent a scroll wheel ShowTouchPadScrollWheel = @bitCast(OverlayFlags{ .show_touch_pad_scroll_wheel = true }), + ///If this is set ownership and render access to the overlay are transferred + ///to the new scene process on a call to openvr.Applications.launchInternalProcess TransferOwnershipToInternalProcess = @bitCast(OverlayFlags{ .transfer_ownership_to_internal_process = true }), + ///If set, renders 50% of the texture in each eye, side by side + ///Texture is left/right SideBySide_Parallel = @bitCast(OverlayFlags{ .side_by_side_parallel = true }), + ///If set, renders 50% of the texture in each eye, side by side + ///Texture is crossed and right/left SideBySide_Crossed = @bitCast(OverlayFlags{ .side_by_side_crossed = true }), + ///Texture is a panorama Panorama = @bitCast(OverlayFlags{ .panorama = true }), + ///Texture is a stereo panorama StereoPanorama = @bitCast(OverlayFlags{ .stereo_panorama = true }), + ///If this is set on an overlay owned by the scene application that overlay + ///will be sorted with the "Other" overlays on top of all other scene overlays SortWithNonSceneOverlays = @bitCast(OverlayFlags{ .sort_with_non_scene_overlays = true }), + ///If set, the overlay will be shown in the dashboard, otherwise it will be hidden. VisibleInDashboard = @bitCast(OverlayFlags{ .visible_in_dashboard = true }), + ///If this is set and the overlay's input method is not none, the system-wide laser mouse + ///mode will be activated whenever this overlay is visible. MakeOverlaysInteractiveIfVisible = @bitCast(OverlayFlags{ .make_overlays_interactive_if_visible = true }), + ///If this is set the overlay will receive smooth EventType.scroll_smooth that emulate trackpad scrolling. + ///Requires mouse input mode. SendVRSmoothScrollEvents = @bitCast(OverlayFlags{ .send_vr_smooth_scroll_events = true }), + ///If this is set, the overlay texture will be protected content, preventing unauthorized reads. ProtectedContent = @bitCast(OverlayFlags{ .protected_content = true }), + ///If this is set, the laser mouse splat will not be drawn over this overlay. The overlay will + ///be responsible for drawing its own "cursor". HideLaserIntersection = @bitCast(OverlayFlags{ .hide_laser_intersection = true }), + ///If this is set, clicking away from the overlay will cause it to receive a EventType.modal_cancel event. + ///This is ignored for dashboard overlays. WantsModalBehavior = @bitCast(OverlayFlags{ .wants_modal_behavior = true }), + ///If this is set, alpha composition assumes the texture is pre-multiplied IsPremultiplied = @bitCast(OverlayFlags{ .is_premultiplied = true }), + ///If this is set, the alpha values of the overlay texture will be ignored IgnoreTextureAlpha = @bitCast(OverlayFlags{ .ignore_texture_alpha = true }), + ///If this is set, this overlay will have a control bar drawn underneath of it in the dashboard. EnableControlBar = @bitCast(OverlayFlags{ .enable_control_bar = true }), + ///If this is set, the overlay control bar will provide a button to toggle the keyboard. EnableControlBarKeyboard = @bitCast(OverlayFlags{ .enable_control_bar_keyboard = true }), + ///If this is set, the overlay control bar will provide a "close" button which will send a + ///EventType.overlay_closed event to the overlay when pressed. Applications that use this flag are responsible + ///for responding to the event with something that approximates "closing" behavior, such as destroying their + ///overlay and/or shutting down their application. EnableControlBarClose = @bitCast(OverlayFlags{ .enable_control_bar_close = true }), + ///Do not use Reserved = @bitCast(OverlayFlags{ .reserved = true }), + ///If this is set, click stabilization will be applied to the laser interaction so that clicks more reliably + ///trigger on the user's intended target EnableClickStabilization = @bitCast(OverlayFlags{ .enable_click_stabilization = true }), + ///If this is set, laser mouse pointer events may be sent for the secondary laser. These events will have + ///cursorIndex set to 0 for the primary laser and 1 for the secondary. MultiCursor = @bitCast(OverlayFlags{ .multi_cursor = true }), }; }; From 915804673013a903cbf8da41187cb80c09bf4915 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 27 Jul 2024 17:00:40 -0400 Subject: [PATCH 39/44] partially working zgui implementation --- samples/openvr_overlay/src/openvr_overlay.zig | 72 ++++++++++++++----- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/samples/openvr_overlay/src/openvr_overlay.zig b/samples/openvr_overlay/src/openvr_overlay.zig index 45a22e4fc..1f12e66ed 100644 --- a/samples/openvr_overlay/src/openvr_overlay.zig +++ b/samples/openvr_overlay/src/openvr_overlay.zig @@ -1,5 +1,6 @@ const std = @import("std"); const glfw = @import("zglfw"); +const zgui = @import("zgui"); const zopengl = @import("zopengl"); const zopenvr = @import("zopenvr"); @@ -20,17 +21,26 @@ pub fn main() !void { glfw.windowHintTyped(.opengl_profile, .opengl_core_profile); glfw.windowHintTyped(.opengl_forward_compat, true); glfw.windowHintTyped(.client_api, .opengl_api); - // glfw.windowHintTyped(.doublebuffer, .opengl_api); glfw.windowHintTyped(.visible, false); const window = try glfw.Window.create(600, 600, "zig-gamedev: openvr_overlay", null); defer window.destroy(); glfw.makeContextCurrent(window); + glfw.swapInterval(1); try zopengl.loadCoreProfile(glfw.getProcAddress, gl_major, gl_minor); const gl = zopengl.bindings; - glfw.swapInterval(1); + + var alloc = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer alloc.deinit(); + const allocator = alloc.allocator(); + + zgui.init(allocator); + defer zgui.deinit(); + + zgui.backend.init(window); + defer zgui.backend.deinit(); const openvr = openvr: { // if wireless headset not connected then retry till its present @@ -65,26 +75,58 @@ pub fn main() !void { .u_max = 0, .v_max = 1, }); + try overlay.setOverlayFlag(overlayID, .MakeOverlaysInteractiveIfVisible, true); + try overlay.setOverlayInputMethod(overlayID, .Mouse); try overlay.showOverlay(overlayID); var overlayTexture: gl.Uint = undefined; - { - gl.genTextures(1, &overlayTexture); - gl.bindTexture(gl.TEXTURE_2D, overlayTexture); + gl.genTextures(1, &overlayTexture); + gl.bindTexture(gl.TEXTURE_2D, overlayTexture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - } + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); var overlay_associated = false; while (!window.shouldClose()) { glfw.pollEvents(); + if (overlay_associated) { + while (overlay.pollNextOverlayEvent(overlayID)) |event| switch (event.event_type) { + .mouse_move => zgui.io.addMousePositionEvent(width * event.data.mouse.x, height * event.data.mouse.y), + .mouse_button_down, .mouse_button_up => { + zgui.io.addMousePositionEvent(width * event.data.mouse.x, height * event.data.mouse.y); + // std.log.debug("mouse x {d} y {d}\n", .{ width * event.data.mouse.x, height * event.data.mouse.y }); + zgui.io.addMouseButtonEvent(.left, event.data.mouse.button.Left); + zgui.io.addMouseButtonEvent(.right, event.data.mouse.button.Right); + zgui.io.addMouseButtonEvent(.middle, event.data.mouse.button.Middle); + }, + .focus_leave => zgui.io.addFocusEvent(false), + .focus_enter => zgui.io.addFocusEvent(true), + else => {}, + }; + } gl.clearBufferfv(gl.COLOR, 0, &[_]f32{ 0.2, 0.6, 0.4, 1.0 }); + zgui.backend.newFrame(width, height); + + // Set the starting window position and size to custom values + zgui.setNextWindowPos(.{ .x = 20.0, .y = 20.0, .cond = .first_use_ever }); + zgui.setNextWindowSize(.{ .w = -1.0, .h = -1.0, .cond = .first_use_ever }); + + if (zgui.begin("My window", .{})) { + if (zgui.button("Press me!", .{ .w = 200.0 })) { + std.debug.print("Button pressed\n", .{}); + } + } + zgui.end(); + + zgui.backend.draw(); + /////// if (!overlay_associated) blk: { @@ -95,9 +137,9 @@ pub fn main() !void { } var transform = std.mem.zeroes(zopenvr.Matrix34); - transform.m[0][0] = 1; + transform.m[0][0] = -1; transform.m[1][2] = 1; - transform.m[2][1] = 1; + transform.m[2][1] = -1; transform.m[2][3] = -0.12; @@ -120,14 +162,6 @@ pub fn main() !void { .texture_type = .opengl, }); - if (overlay_associated) { - while (overlay.pollNextOverlayEvent(overlayID)) |event| { - _ = event; - } - } - - // window.swapBuffers(); - overlay.waitFrameSync(1000 / fps) catch |err| switch (err) { zopenvr.OverlayError.TimedOut => std.time.sleep(200 * std.time.ns_per_ms), else => return err, From 0f1b226e7996e0ca7209dbd8d0a0bd6d351a9845 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 27 Jul 2024 20:06:01 -0400 Subject: [PATCH 40/44] added doc comments to make events easier to use --- libs/zopenvr/src/common.zig | 120 ++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 8b27b2302..59695c265 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -979,10 +979,15 @@ pub const AppKeys = struct { } }; pub const SceneApplicationState = enum(i32) { + ///Scene Application is not running none = 0, + ///Scene Application is starting starting = 1, + ///Scene Application is quitting quitting = 2, + ///Scene Application is running, and submitting frames, a custom skybox, or a visible overlay running = 3, + ///Scene Application is running, but not drawing anything waiting = 4, }; @@ -2510,6 +2515,7 @@ pub const VRState = enum(i32) { pub const EventType = enum(i32) { none = 0, + tracked_device_activated = 100, tracked_device_deactivated = 101, tracked_device_updated = 102, @@ -2526,88 +2532,167 @@ pub const EventType = enum(i32) { wireless_reconnect = 113, reserved_01 = 114, reserved_02 = 115, + + ///data is controller button_press = 200, + ///data is controller button_unpress = 201, + ///data is controller button_touch = 202, + ///data is controller button_untouch = 203, + + ///Sent to overlays with the (???) modal_cancel = 257, + + ///data is mouse mouse_move = 300, + ///data is mouse mouse_button_down = 301, + ///data is mouse mouse_button_up = 302, + ///data is overlay focus_enter = 303, + ///data is overlay focus_leave = 304, + ///data is scroll scroll_discrete = 305, + ///data is mouse touch_pad_move = 306, + ///data is overlay, global event overlay_focus_changed = 307, reload_overlays = 308, + ///data is scroll scroll_smooth = 309, + ///data is mouse lock_mouse_position = 310, + ///data is mouse unlock_mouse_position = 311, + + ///data is process DEPRECATED input_focus_captured = 400, + ///data is process DEPRECATED input_focus_released = 401, + ///data is process - The App actually drawing the scene changed (usually to or from the compositor) scene_application_changed = 404, + ///data is process input_focus_changed = 406, + ///data is process scene_application_using_wrong_graphics_adapter = 408, + ///data is process - The App that action binds reloaded for action_binding_reloaded = 409, + + ///Sent to the scene application to request hiding render models temporarily hide_render_models = 410, + ///Sent to the scene application to request restoring render model visibility show_render_models = 411, + + ///No data; but query openvr.Applications.getSceneApplicationState(); scene_application_state_changed = 412, + + ///data is process - Called when the scene app's pipe has been closed. scene_app_pipe_disconnected = 413, + console_opened = 420, console_closed = 421, + + ///Indicates that an overlay is now visible to someone and should be rendering normally. Reflects openvr.Overlay.isOverlayVisible() becoming true. overlay_shown = 500, + ///Indicates that an overlay is no longer visible to someone and doesn't need to render frames. Reflects openvr.Overlay.isOverlayVisible() becoming false. overlay_hidden = 501, dashboard_activated = 502, dashboard_deactivated = 503, + ///Sent to the overlay manager - data is overlay dashboard_requested = 505, + ///Send to the overlay manager reset_dashboard = 506, + ///Sent to overlays when a SetOverlayRaw or SetOverlayFromFile call finishes loading image_loaded = 508, + ///Sent to keyboard renderer in the dashboard to invoke it show_keyboard = 509, + ///Sent to keyboard renderer in the dashboard to hide it hide_keyboard = 510, + ///Sent to an overlay when openvr.Overlay.setFocusOverlay is called on it overlay_gamepad_focus_gained = 511, + ///Send to an overlay when it previously had focus and openvr.Overlay.setFocusOverlay is called on something else overlay_gamepad_focus_lost = 512, overlay_shared_texture_changed = 513, + ///Screenshot button combo was pressed, Dashboard should request a screenshot screenshot_triggered = 516, + ///Sent to overlays when a openvr.Overlay.setOverlayRaw or openvr.Overlay.setOverlayfromFile fails to load image_failed = 517, dashboard_overlay_created = 518, switch_gamepad_focus = 519, + + //screenshot api + ///Sent by vrclient application to compositor to take a screenshot request_screenshot = 520, + ///Sent by compositor to the application that the screenshot has been taken screenshot_taken = 521, + ///Sent by compositor to the application that the screenshot failed to be taken screenshot_failed = 522, + ///Sent by compositor to the dashboard that a completed screenshot was submitted submit_screenshot_to_dashboard = 523, + ///Sent by compositor to the dashboard that a completed screenshot was submitted screenshot_progress_to_dashboard = 524, + primary_dashboard_device_changed = 525, + ///Sent by compositor whenever room-view is enabled room_view_shown = 526, + ///Sent by compositor whenever room-view is disabled room_view_hidden = 527, + ///data is showUi show_ui = 528, + ///data is showDevTools show_dev_tools = 529, desktop_view_updating = 530, desktop_view_ready = 531, + start_dashboard = 532, elevate_prism = 533, + overlay_closed = 534, + + ///Sent when a dashboard thumbnail image changes dashboard_thumb_changed = 535, + + ///Sent when any known desktop related overlay is visible desktop_might_be_visible = 536, + ///Sent when all known desktop related overlays are hidden desktop_might_be_hidden = 537, + notification_shown = 600, notification_hidden = 601, notification_begin_interaction = 602, notification_destroyed = 603, + + ///data is process quit = 700, + ///data is process process_quit = 701, + ///data is process quit_acknowledged = 703, + ///The driver has requested that SteamVR shut down driver_requested_quit = 704, + ///A driver or other component wants the user to restart SteamVR restart_requested = 705, invalidate_swap_texture_sets = 706, + + ///this will never happen with the new chaperone system chaperone_data_has_changed = 800, chaperone_universe_has_changed = 801, + ///this will never happen with the new chaperone system chaperone_temp_data_has_changed = 802, chaperone_settings_have_changed = 803, seated_zero_pose_reset = 804, + ///Sent when the process needs to reload any cached data it retrieved from openvr.Chaperone chaperone_flush_cache = 805, + ///Triggered by openvr.ChaperoneSetup.roomSetupStarting chaperone_room_setup_starting = 806, + ///Triggered by openvr.ChaperoneSetup.commitWorkingCopy chaperone_room_setup_finished = 807, standing_zero_pose_reset = 808, + audio_settings_have_changed = 820, background_setting_has_changed = 850, camera_settings_have_changed = 851, @@ -2632,24 +2717,36 @@ pub const EventType = enum(i32) { windows_mr_section_setting_changed = 870, other_section_setting_changed = 871, any_driver_settings_changed = 872, + status_update = 900, + web_interface_install_driver_completed = 950, + mc_image_updated = 1000, + firmware_update_started = 1100, firmware_update_finished = 1101, + + ///DEPRECATED: Sent only to the overlay it closed for, or globally if it was closed for a scene app keyboard_closed = 1200, keyboard_char_input = 1201, + ///Sent when DONE button clicked on keyboard keyboard_done = 1202, + ///Sent globally when the keyboard is opened. data.keyboard.overlay_handle is who it was opened for (scene app if openvr.overlay_handle_invalid) keyboard_opened_global = 1203, + ///Sent globally when the keyboard is opened. data.keyboard.overlay_handle is who it was opened for (scene app if openvr.overlay_handle_invalid) keyboard_closed_global = 1204, + application_list_updated = 1303, application_mime_type_load = 1304, process_connected = 1306, process_disconnected = 1307, + compositor_chaperone_bounds_shown = 1410, compositor_chaperone_bounds_hidden = 1411, compositor_display_disconnected = 1412, compositor_display_reconnected = 1413, + ///data is hdcpError compositor_hdcp_error = 1414, compositor_application_not_responding = 1415, compositor_application_resumed = 1416, @@ -2657,36 +2754,59 @@ pub const EventType = enum(i32) { compositor_display_mode_not_supported = 1418, compositor_stage_override_ready = 1419, compositor_request_disconnect_reconnect = 1420, + tracked_camera_start_video_stream = 1500, tracked_camera_stop_video_stream = 1501, tracked_camera_pause_video_stream = 1502, tracked_camera_resume_video_stream = 1503, tracked_camera_editing_surface = 1550, + performance_test_enable_capture = 1600, performance_test_disable_capture = 1601, performance_test_fidelity_level = 1602, + message_overlay_closed = 1650, message_overlay_close_requested = 1651, + + ///data is hapticVibration input_haptic_vibration = 1700, + ///data is inputBinding input_binding_load_failed = 1701, + ///data is inputBinding input_binding_load_successful = 1702, + ///no data input_action_manifest_reloaded = 1703, + ///data is actionManifest input_action_manifest_load_failed = 1704, + ///data is progressUpdate input_progress_update = 1705, input_tracker_activated = 1706, input_bindings_updated = 1707, input_binding_subscription_changed = 1708, + + ///data is spatialAnchor. broadcast spatial_anchors_pose_updated = 1800, + ///data is spatialAnchor. broadcast spatial_anchors_descriptor_updated = 1801, + ///data is spatialAnchor. sent to specific driver spatial_anchors_request_pose_update = 1802, + ///data is spatialAnchor. sent to specific driver spatial_anchors_request_descriptor_update = 1803, + + ///user or system initiated generation of a system report. broadcast system_report_started = 1900, + + ///data is process monitor_show_headset_view = 2000, + ///data is process monitor_hide_headset_view = 2001, + audio_set_speakers_volume = 2100, audio_set_speakers_mute = 2101, audio_set_microphone_volume = 2102, audio_set_microphone_mute = 2103, + + // vendor spesific area vendor_specific_reserved_start = 10000, vendor_specific_reserved_end = 19999, From 032e51643d72d77d5834af6e3b02201105584f18 Mon Sep 17 00:00:00 2001 From: zivoy Date: Sat, 27 Jul 2024 20:33:58 -0400 Subject: [PATCH 41/44] fix mouse up --- samples/openvr_overlay/src/openvr_overlay.zig | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/samples/openvr_overlay/src/openvr_overlay.zig b/samples/openvr_overlay/src/openvr_overlay.zig index 1f12e66ed..ae333bf0a 100644 --- a/samples/openvr_overlay/src/openvr_overlay.zig +++ b/samples/openvr_overlay/src/openvr_overlay.zig @@ -84,8 +84,6 @@ pub fn main() !void { gl.genTextures(1, &overlayTexture); gl.bindTexture(gl.TEXTURE_2D, overlayTexture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); @@ -99,10 +97,9 @@ pub fn main() !void { .mouse_move => zgui.io.addMousePositionEvent(width * event.data.mouse.x, height * event.data.mouse.y), .mouse_button_down, .mouse_button_up => { zgui.io.addMousePositionEvent(width * event.data.mouse.x, height * event.data.mouse.y); - // std.log.debug("mouse x {d} y {d}\n", .{ width * event.data.mouse.x, height * event.data.mouse.y }); - zgui.io.addMouseButtonEvent(.left, event.data.mouse.button.Left); - zgui.io.addMouseButtonEvent(.right, event.data.mouse.button.Right); - zgui.io.addMouseButtonEvent(.middle, event.data.mouse.button.Middle); + if (event.data.mouse.button.Left) zgui.io.addMouseButtonEvent(.left, event.event_type == .mouse_button_down); + if (event.data.mouse.button.Middle) zgui.io.addMouseButtonEvent(.middle, event.event_type == .mouse_button_down); + if (event.data.mouse.button.Right) zgui.io.addMouseButtonEvent(.right, event.event_type == .mouse_button_down); }, .focus_leave => zgui.io.addFocusEvent(false), .focus_enter => zgui.io.addFocusEvent(true), From b9cc1e225dc7bdcf99fd4643ea786cf7244440fb Mon Sep 17 00:00:00 2001 From: zivoy Date: Sun, 28 Jul 2024 11:05:20 -0400 Subject: [PATCH 42/44] removed openvr sdk version 1.23.7 for linux target --- libs/zopenvr/build.zig | 11 ++++++----- libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so | 3 --- libs/zopenvr/libs/openvr/lib/linux64/libopenvr_api.so | 3 --- 3 files changed, 6 insertions(+), 11 deletions(-) delete mode 100755 libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so delete mode 100644 libs/zopenvr/libs/openvr/lib/linux64/libopenvr_api.so diff --git a/libs/zopenvr/build.zig b/libs/zopenvr/build.zig index 6a53158e5..cfe774539 100644 --- a/libs/zopenvr/build.zig +++ b/libs/zopenvr/build.zig @@ -73,7 +73,7 @@ pub fn build(b: *std.Build) void { } } -fn testSuportedTarget(step: *std.Build.Step, target: std.Target) error{ OutOfMemory, MakeFailed }!void { +fn testSuportedTarget(step: *std.Build.Step, target: std.Target) error{MakeFailed}!void { const supportedArch = switch (target.cpu.arch) { .x86, .x86_64 => true, else => false, @@ -84,13 +84,14 @@ fn testSuportedTarget(step: *std.Build.Step, target: std.Target) error{ OutOfMem }; if (supportedOs and supportedArch) return; - return step.fail("zopenvr does not support building for {s}{s}{s}{s}{s}", .{ + if (step.fail("zopenvr does not support building for {s}{s}{s}{s}{s}", .{ if (!supportedArch and supportedOs) "the " else "", if (!supportedArch) @tagName(target.cpu.arch) else "", if (!supportedArch and supportedOs) " platform" else "", if (!supportedArch and !supportedOs) " " else "", if (!supportedOs) @tagName(target.os.tag) else "", - }); + }) == error.OutOfMemory) @panic("OOM"); + return error.MakeFailed; } pub fn addLibraryPathsTo(compile_step: *std.Build.Step.Compile) void { @@ -108,8 +109,8 @@ pub fn addLibraryPathsTo(compile_step: *std.Build.Step.Compile) void { else => unreachable, }, .linux => switch (arch) { - .x86_64 => "libs/openvr/lib/linux64", - .x86 => "libs/openvr/lib/linux32", + .x86_64 => "libs/openvr/bin/linux64", + .x86 => "libs/openvr/bin/linux32", else => unreachable, }, else => unreachable, diff --git a/libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so b/libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so deleted file mode 100755 index 618cf05c3..000000000 --- a/libs/zopenvr/libs/openvr/lib/linux32/libopenvr_api.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:79bcd0b9a1fb1e857adc748f4c170f48b311b14a27b5d5b6210d5e39d47824b2 -size 5877704 diff --git a/libs/zopenvr/libs/openvr/lib/linux64/libopenvr_api.so b/libs/zopenvr/libs/openvr/lib/linux64/libopenvr_api.so deleted file mode 100644 index 2fd5eb3ff..000000000 --- a/libs/zopenvr/libs/openvr/lib/linux64/libopenvr_api.so +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d3697118056241ee008b5b632fe3e27ac9d712f5a7c73feb3cb877b09b07baa3 -size 6963816 From a4fa35876b6bd90cc4d4563d6173adb4c7e09c3e Mon Sep 17 00:00:00 2001 From: zivoy Date: Sun, 28 Jul 2024 15:22:03 -0400 Subject: [PATCH 43/44] added OverlayView --- libs/zopenvr/README.md | 2 +- libs/zopenvr/src/common.zig | 32 ++++++++++++++++++++++++ libs/zopenvr/src/openvr.zig | 5 ++++ libs/zopenvr/src/overlay_view.zig | 41 +++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 libs/zopenvr/src/overlay_view.zig diff --git a/libs/zopenvr/README.md b/libs/zopenvr/README.md index 2a6875fb4..a0044164f 100644 --- a/libs/zopenvr/README.md +++ b/libs/zopenvr/README.md @@ -73,7 +73,7 @@ For better types on render structs, enable the corresponding options when import | IOBuffer | | | Notifications | | | Overlay | ✅ | -| OverlayView | | +| OverlayView | ✅ | | Paths | | | Properties | | | RenderModels | ✅ | diff --git a/libs/zopenvr/src/common.zig b/libs/zopenvr/src/common.zig index 59695c265..e6d9f3d0b 100644 --- a/libs/zopenvr/src/common.zig +++ b/libs/zopenvr/src/common.zig @@ -2,6 +2,7 @@ const std = @import("std"); const renderers = @import("renderers.zig"); const d3d12 = renderers.d3d12; +const vulkan = renderers.vulkan; const root = @This(); @@ -2931,6 +2932,7 @@ pub const OverlayErrorCode = enum(i32) { unknown_overlay = 10, invalid_handle = 11, permission_denied = 12, + ///No more overlays could be created because the maximum number already exist overlay_limit_exceeded = 13, wrong_visibility_type = 14, key_too_long = 15, @@ -3293,3 +3295,33 @@ pub const VRVulkanTextureArrayData = extern struct { array_index: u32, array_size: u32, }; + +// can't call it OverlayView since the name will conflict in openvr.zig +pub const VROverlayView = extern struct { + overlay_handle: OverlayHandle, + texture: Texture, + texture_bounds: TextureBounds, +}; + +pub const DeviceType = enum(i32) { + ///Invalid handle + invalid = -1, + ///Handle is an ID3D11Device + directX11 = 0, + ///Handle is a pointer to a openvr.VulkanDevice structure + vulkan = 1, +}; + +pub const VulkanDevice = extern struct { + instance: vulkan.VkInstance, + device: vulkan.VkDevice, + physical_device: vulkan.VkPhysicalDevice, + queue: vulkan.VkQueue, + queue_family_index: u32, +}; + +pub const NativeDevice = extern struct { + ///See DeviceType definition + handle: *const anyopaque, + type: DeviceType, +}; diff --git a/libs/zopenvr/src/openvr.zig b/libs/zopenvr/src/openvr.zig index 7d1d7dcb0..530dc0a3c 100644 --- a/libs/zopenvr/src/openvr.zig +++ b/libs/zopenvr/src/openvr.zig @@ -85,6 +85,10 @@ pub fn overlay(_: Self) common.InitError!Overlay { return try Overlay.init(); } +pub fn overlayView(_: Self) common.InitError!Overlay { + return try OverlayView.init(); +} + pub usingnamespace @import("common.zig"); pub const System = @import("system.zig"); pub const Chaperone = @import("chaperone.zig"); @@ -93,3 +97,4 @@ pub const Applications = @import("applications.zig"); pub const Input = @import("input.zig"); pub const RenderModels = @import("render_models.zig"); pub const Overlay = @import("overlay.zig"); +pub const OverlayView = @import("overlay_view.zig"); diff --git a/libs/zopenvr/src/overlay_view.zig b/libs/zopenvr/src/overlay_view.zig new file mode 100644 index 000000000..2a628b239 --- /dev/null +++ b/libs/zopenvr/src/overlay_view.zig @@ -0,0 +1,41 @@ +const std = @import("std"); + +const common = @import("common.zig"); + +function_table: *FunctionTable, + +const Self = @This(); + +const version = "IVROverlayView_003"; +pub fn init() common.InitError!Self { + return .{ + .function_table = try common.getFunctionTable(FunctionTable, version), + }; +} + +pub fn acquireOverlayView(self: Self, overlay_handle: common.OverlayHandle) common.OverlayError!struct { native_device: common.NativeDevice, overlay_view: common.VROverlayView } { + var overlay_view: common.VROverlayView = undefined; + var native_device: common.NativeDevice = undefined; // pretty sure this is an output + const err = self.function_table.AcquireOverlayView(overlay_handle, &native_device, &overlay_view, @sizeOf(common.VROverlayView)); + try err.maybe(); + return .{ .native_device = native_device, .overlay_view = overlay_view }; +} + +pub fn releaseOverlayView(self: Self, overlay_view: *common.VROverlayView) common.OverlayError!void { + try self.function_table.ReleaseOverlayView(overlay_view).maybe(); +} + +pub fn postOverlayEvent(self: Self, overlay_handle: common.OverlayHandle, event: *const common.Event) void { + self.function_table.PostOverlayEvent(overlay_handle, event); +} + +pub fn isViewingPermitted(self: Self, overlay_handle: common.OverlayHandle) bool { + return self.function_table.IsViewingPermitted(overlay_handle); +} + +const FunctionTable = extern struct { + AcquireOverlayView: *const fn (common.OverlayHandle, *common.NativeDevice, *common.VROverlayView, u32) callconv(.C) common.OverlayErrorCode, + ReleaseOverlayView: *const fn (*common.VROverlayView) callconv(.C) common.OverlayErrorCode, + PostOverlayEvent: *const fn (common.OverlayHandle, *const common.Event) callconv(.C) void, + IsViewingPermitted: *const fn (common.OverlayHandle) callconv(.C) bool, +}; From d27ff9fac003960e6a6c883baa4c24d8c5e5992e Mon Sep 17 00:00:00 2001 From: zivoy Date: Mon, 29 Jul 2024 10:02:24 -0400 Subject: [PATCH 44/44] house --- samples/openvr_overlay/src/openvr_overlay.zig | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/samples/openvr_overlay/src/openvr_overlay.zig b/samples/openvr_overlay/src/openvr_overlay.zig index ae333bf0a..f7f30b374 100644 --- a/samples/openvr_overlay/src/openvr_overlay.zig +++ b/samples/openvr_overlay/src/openvr_overlay.zig @@ -94,15 +94,15 @@ pub fn main() !void { glfw.pollEvents(); if (overlay_associated) { while (overlay.pollNextOverlayEvent(overlayID)) |event| switch (event.event_type) { - .mouse_move => zgui.io.addMousePositionEvent(width * event.data.mouse.x, height * event.data.mouse.y), - .mouse_button_down, .mouse_button_up => { - zgui.io.addMousePositionEvent(width * event.data.mouse.x, height * event.data.mouse.y); - if (event.data.mouse.button.Left) zgui.io.addMouseButtonEvent(.left, event.event_type == .mouse_button_down); - if (event.data.mouse.button.Middle) zgui.io.addMouseButtonEvent(.middle, event.event_type == .mouse_button_down); - if (event.data.mouse.button.Right) zgui.io.addMouseButtonEvent(.right, event.event_type == .mouse_button_down); + .mouse_move, .mouse_button_down, .mouse_button_up => { + const mouse = event.data.mouse; + zgui.io.addMousePositionEvent(width * mouse.x, height * mouse.y); + if (mouse.button.Left) zgui.io.addMouseButtonEvent(.left, event.event_type == .mouse_button_down); + if (mouse.button.Middle) zgui.io.addMouseButtonEvent(.middle, event.event_type == .mouse_button_down); + if (mouse.button.Right) zgui.io.addMouseButtonEvent(.right, event.event_type == .mouse_button_down); }, - .focus_leave => zgui.io.addFocusEvent(false), - .focus_enter => zgui.io.addFocusEvent(true), + .focus_leave => if (event.data.overlay.overlay_handle == overlayID) zgui.io.addFocusEvent(false), + .focus_enter => if (event.data.overlay.overlay_handle == overlayID) zgui.io.addFocusEvent(true), else => {}, }; } @@ -115,13 +115,49 @@ pub fn main() !void { zgui.setNextWindowPos(.{ .x = 20.0, .y = 20.0, .cond = .first_use_ever }); zgui.setNextWindowSize(.{ .w = -1.0, .h = -1.0, .cond = .first_use_ever }); - if (zgui.begin("My window", .{})) { + if (zgui.begin("Overlay window", .{})) { if (zgui.button("Press me!", .{ .w = 200.0 })) { std.debug.print("Button pressed\n", .{}); } } zgui.end(); + { + const draw_list = zgui.getBackgroundDrawList(); + draw_list.pushClipRect(.{ .pmin = .{ 0, 0 }, .pmax = .{ width, height } }); + + // house with a continus line + { + const color: u32 = 0xD4FFE9FF; //zgui.colorConvertFloat3ToU32([_]f32{ 0.8, 1, 0.9 }); + var cord: [2]f32 = .{ 20, height - 20 }; + var next_cord: [2]f32 = .{ width - 20, height - 20 }; + draw_list.addLine(.{ .p1 = cord, .p2 = next_cord, .col = color, .thickness = 5.0 }); + cord = next_cord; + next_cord = .{ width - 20, 150 }; + draw_list.addLine(.{ .p1 = cord, .p2 = next_cord, .col = color, .thickness = 5.0 }); + cord = next_cord; + next_cord = .{ 20, height - 20 }; + draw_list.addLine(.{ .p1 = cord, .p2 = next_cord, .col = color, .thickness = 5.0 }); + cord = next_cord; + next_cord = .{ 20, 150 }; + draw_list.addLine(.{ .p1 = cord, .p2 = next_cord, .col = color, .thickness = 5.0 }); + cord = next_cord; + next_cord = .{ @divFloor(width, 2), 20 }; + draw_list.addLine(.{ .p1 = cord, .p2 = next_cord, .col = color, .thickness = 5.0 }); + cord = next_cord; + next_cord = .{ width - 20, 150 }; + draw_list.addLine(.{ .p1 = cord, .p2 = next_cord, .col = color, .thickness = 5.0 }); + cord = next_cord; + next_cord = .{ 20, 150 }; + draw_list.addLine(.{ .p1 = cord, .p2 = next_cord, .col = color, .thickness = 5.0 }); + cord = next_cord; + next_cord = .{ width - 20, height - 20 }; + draw_list.addLine(.{ .p1 = cord, .p2 = next_cord, .col = color, .thickness = 5.0 }); + } + + draw_list.popClipRect(); + } + zgui.backend.draw(); ///////