summary refs log tree commit diff
path: root/src/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig96
1 files changed, 83 insertions, 13 deletions
diff --git a/src/main.zig b/src/main.zig
index add48ae..249d7c7 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -16,23 +16,93 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with zeal.  If not, see <https://www.gnu.org/licenses/>.
 
+const al = @import("al.zig");
 const alc = @import("alc.zig");
+const expect = std.testing.expect;
+const eql = std.meta.eql;
+const std = @import("std");
 
-pub fn init(device_name: [*c]const u8) !void {
-    const device = try alc.openDevice(device_name);
-    const context = try alc.createContext(device, null);
-    try alc.makeContextCurrent(context);
+pub const Device = struct {
+    pimpl: *alc.Device,
+
+    pub fn init(name: ?[]const u8) alc.Error!Device {
+        return Device{ .pimpl = try alc.openDevice(name) };
+    }
+
+    pub fn deinit(self: Device) alc.Error!void {
+        try alc.closeDevice(self.pimpl);
+    }
+};
+
+pub const Context = struct {
+    pimpl: *alc.Context,
+    device: Device,
+
+    pub fn init(device: Device, attributes: [:0]const i32) alc.Error!Context {
+        return Context {
+            .pimpl = try alc.createContext(device.pimpl, attributes),
+            .device = device,
+        };
+    }
+
+    pub fn deinit(self: Context) alc.Error!void {
+        try alc.makeContextCurrent(null);
+        try alc.destroyContext(self.pimpl);
+    }
+};
+
+pub fn useContext(context: ?Context) alc.Error!void {
+    try alc.makeContextCurrent(if (context == null) null else context.?.pimpl);
+}
+pub fn currentContext() alc.Error!?Context {
+    if (alc.getCurrentContext()) |pimpl|
+        return Context {
+            .pimpl = pimpl,
+            .device = Device { .pimpl = try alc.getContextsDevice(pimpl) },
+        };
+    return null;
 }
 
-pub fn deinit() !void {
-    const context = alc.getCurrentContext();
-    const device = try alc.getContextsDevice(context);
-    try alc.makeContextCurrent(null);
-    try alc.destroyContext(context);
-    try alc.closeDevice(device);
+fn checkContext(context: Context) !void {
+    if (context.pimpl != alc.getCurrentContext())
+        return error.UncurrentContext;
 }
 
-test {
-    try init(null);
-    try deinit();
+pub const Listener = struct {
+    context: Context,
+
+    pub fn setPosition(self: Listener, position: [3]f32) !void {
+        try checkContext(self.context);
+        al.listener.setFloatVector(al.POSITION, &position);
+    }
+
+    pub fn setOrientation(self: Listener, at: [3]f32, up: [3]f32) !void {
+        try checkContext(self.context);
+        al.listener.setFloatVector(al.ORIENTATION, &[_]f32 {
+            at[0], at[1], at[2],
+            up[0], up[1], up[2],
+        });
+    }
+};
+
+test "temporary" {
+    const device = try Device.init("OpenAL Soft");
+    defer device.deinit() catch unreachable;
+    const context = try Context.init(device, &.{ alc.HRTF, alc.TRUE });
+    defer context.deinit() catch unreachable;
+
+    try expect(null == try currentContext());
+    if (checkContext(context)) |_| unreachable else |err| switch (err) {
+        error.UncurrentContext => {},
+    }
+
+    try useContext(context);
+    const current_context = (try currentContext()).?;
+    try expect(eql(current_context, context));
+    try expect(eql(current_context.device, device));
+    try checkContext(context);
+
+    const listener = Listener{ .context = context };
+    try listener.setPosition(.{ 0, 0, 0 });
+    try listener.setOrientation(.{ 0, 0, 0 }, .{ 0, 0, 0 });
 }