diff --git a/HACKING.md b/HACKING.md deleted file mode 100644 index 2b0e0b9..0000000 --- a/HACKING.md +++ /dev/null @@ -1,23 +0,0 @@ -# UnrealXR Development Documentation - -## Dummies and You - -The dummy/development build generally isn't recommended for use if you're developing headset or OS drivers. It's intended for development on the 3D environment itself only (ie. virtual display positioning, widgets, etc.) - -To use it, all you need to do is run the Makefile with the `dev` target: - -```bash -make dev -``` - -In the code, this mode is typically referred to as "dummy mode" (`dummy_ar.go`) or "fake mode" (ie. `patching_tools_fake_patching.go`). - -To control the X11 window, you can use the arrow keys to move the camera around. You **cannot** use the mouse due to the nature of this application. If you use the mouse for this, it would make development really difficult as you're using virtual displays and you need your mouse to interact with the desktop. - -If you're adding new headset drivers, but you still want to test in a window, you still can. It's not the dummy mode, but you can compile UnrealXR without the DRM flags (`drm drm_leasing drm_disable_input`) manually. This may differ in the future, but for now, the command is: - -```bash -cd app; go build -v -tags "headset_driver_goes_here noaudio" -o ../uxr .; cd .. -``` - -Replace `headset_driver_goes_here` with the name of your headset driver. For example, `xreal` is the Xreal driver. diff --git a/Makefile b/Makefile index d1c6536..96717c8 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,5 @@ all: build build: cd $(APP_DIR) && go build -v -tags '$(TAGS)' -o ../$(OUTPUT) . -dev: - cd $(APP_DIR) && go build -v -tags 'noaudio dummy_ar fake_edid_patching' -o ../$(OUTPUT) . - clean: rm -f $(OUTPUT) diff --git a/README.md b/README.md index 501a32b..785e5a7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,4 @@ # UnrealXR -[![Build Status](https://git.terah.dev/UnrealXR/unrealxr/actions/workflows/build.yml/badge.svg)](https://git.terah.dev/UnrealXR/unrealxr/actions) -[![GoDoc](https://godoc.org/git.terah.dev/UnrealXR/unrealxr?status.svg)](https://godoc.org/git.terah.dev/UnrealXR/unrealxr) -[![Go Report Card](https://goreportcard.com/badge/git.terah.dev/UnrealXR/unrealxr/app)](https://goreportcard.com/report/git.terah.dev/UnrealXR/unrealxr/app) -[![License](https://img.shields.io/badge/license-BSD--3--Clause-green)](https://git.terah.dev/imterah/goevdi/src/branch/main/app/LICENSE) UnrealXR is a spatial multi-display renderer for the Xreal line of devices, enabling immersive, simultaneous viewing of multiple desktops and applications in 3D space. @@ -33,7 +29,3 @@ If you're using Nix/NixOS, all you need to do is use `nix-shell` to enter the de ## Building Just run `make` in the root directory. - -## Development Guide - -See [HACKING.md](https://git.terah.dev/UnrealXR/unrealxr/src/branch/main/HACKING.md). diff --git a/app/config/config.go b/app/config/config.go index 5938650..1222abf 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -6,12 +6,10 @@ import _ "embed" var InitialConfig []byte type DisplayConfig struct { - Angle *int `yaml:"angle"` - FOV *int `yaml:"fov"` - Spacing *float32 `yaml:"spacing"` - RadiusMultiplier *float32 `yaml:"circle_radius_multiplier"` - UseCircularSpacing *bool `yaml:"use_circular_spacing"` - Count *int `yaml:"count"` + Angle *int `yaml:"angle"` + FOV *int `yaml:"fov"` + Spacing *float32 `yaml:"spacing"` + Count *int `yaml:"count"` } type AppOverrides struct { @@ -40,12 +38,10 @@ func getPtrToBool(bool bool) *bool { var DefaultConfig = &Config{ DisplayConfig: DisplayConfig{ - Angle: getPtrToInt(45), - FOV: getPtrToInt(45), - Spacing: getPtrToFloat32(0.5), - RadiusMultiplier: getPtrToFloat32(2), - UseCircularSpacing: getPtrToBool(true), - Count: getPtrToInt(3), + Angle: getPtrToInt(45), + FOV: getPtrToInt(45), + Spacing: getPtrToFloat32(0.5), + Count: getPtrToInt(3), }, Overrides: AppOverrides{ AllowUnsupportedDevices: getPtrToBool(false), diff --git a/app/config/default_config.yml b/app/config/default_config.yml index 3daeee3..4938843 100644 --- a/app/config/default_config.yml +++ b/app/config/default_config.yml @@ -9,9 +9,7 @@ display: angle: 45 # Angle of the virtual displays fov: 45 # FOV of the 3D camera - spacing: 0.5 # Raw spacing between virtual displays. Does not use circles in the layout. Purely flat plane. - circle_radius_multiplier: 2 # Multiplier for the radius of the circle used to calculate the spacing between virtual displays. "Rounded" plane of sorts. - use_circular_spacing: true # If true, uses a circular layout for the virtual displays. + spacing: 0.5 # Spacing between virtual displays count: 3 # Count of virtual displays overrides: allow_unsupported_devices: false # If true, allows unsupported devices to be used as long as they're a compatible vendor (Xreal) diff --git a/app/edidtools/bin/xreal-air-edid.bin b/app/edidtools/bin/xreal-air-edid.bin deleted file mode 100644 index ca9ea41..0000000 Binary files a/app/edidtools/bin/xreal-air-edid.bin and /dev/null differ diff --git a/app/edidtools/patching_tools_fake_patching.go b/app/edidtools/patching_tools_fake_patching.go deleted file mode 100644 index e0175d5..0000000 --- a/app/edidtools/patching_tools_fake_patching.go +++ /dev/null @@ -1,42 +0,0 @@ -//go:build fake_edid_patching -// +build fake_edid_patching - -package edidtools - -import ( - _ "embed" - "fmt" - - "github.com/charmbracelet/log" -) - -//go:embed bin/xreal-air-edid.bin -var edidFirmware []byte - -// Attempts to fetch the EDID firmware for any supported XR glasses device -func FetchXRGlassEDID(allowUnsupportedDevices bool) (*DisplayMetadata, error) { - log.Warn("Not actually fetching EDID firmware in fake patching build -- using embedded firmware") - parsedEDID, err := ParseEDID(edidFirmware, allowUnsupportedDevices) - - if err != nil { - return nil, fmt.Errorf("failed to parse embedded EDID firmware: %w", err) - } - - parsedEDID.DeviceQuirks.ZVectorDisabled = false - parsedEDID.DeviceQuirks.SensorInitDelay = 0 - parsedEDID.DeviceQuirks.UsesMouseMovement = true - - return parsedEDID, nil -} - -// Loads custom firmware for a supported XR glass device -func LoadCustomEDIDFirmware(displayMetadata *DisplayMetadata, edidFirmware []byte) error { - log.Warn("Not actually patching EDID firmware in fake patching build -- ignoring") - return nil -} - -// Unloads custom firmware for a supported XR glass device -func UnloadCustomEDIDFirmware(displayMetadata *DisplayMetadata) error { - log.Warn("Not actually unloading EDID firmware in fake patching build -- ignoring") - return nil -} diff --git a/app/edidtools/patching_tools_linux.go b/app/edidtools/patching_tools_linux.go index 7323021..cea8cbd 100644 --- a/app/edidtools/patching_tools_linux.go +++ b/app/edidtools/patching_tools_linux.go @@ -1,5 +1,5 @@ -//go:build linux && !fake_edid_patching -// +build linux,!fake_edid_patching +//go:build linux +// +build linux package edidtools diff --git a/app/edidtools/patching_tools_macos.go b/app/edidtools/patching_tools_macos.go index 625baf4..d41de0b 100644 --- a/app/edidtools/patching_tools_macos.go +++ b/app/edidtools/patching_tools_macos.go @@ -1,5 +1,5 @@ -//go:build darwin && !fake_edid_patching -// +build darwin,!fake_edid_patching +//go:build darwin +// +build darwin package edidtools diff --git a/app/edidtools/patching_tools_win.go b/app/edidtools/patching_tools_win.go index 54d2a90..e9f515f 100644 --- a/app/edidtools/patching_tools_win.go +++ b/app/edidtools/patching_tools_win.go @@ -1,5 +1,5 @@ -//go:build windows && !fake_edid_patching -// +build windows,!fake_edid_patching +//go:build windows +// +build windows package edidtools diff --git a/app/edidtools/struct.go b/app/edidtools/struct.go index e0b57d7..361c440 100644 --- a/app/edidtools/struct.go +++ b/app/edidtools/struct.go @@ -1,12 +1,11 @@ package edidtools type DisplayQuirks struct { - MaxWidth int - MaxHeight int - MaxRefreshRate int - SensorInitDelay int - ZVectorDisabled bool - UsesMouseMovement bool + MaxWidth int + MaxHeight int + MaxRefreshRate int + SensorInitDelay int + ZVectorDisabled bool } type DisplayMetadata struct { diff --git a/app/main.go b/app/main.go index f84df7a..239c49e 100644 --- a/app/main.go +++ b/app/main.go @@ -118,7 +118,7 @@ func mainEntrypoint(context.Context, *cli.Command) error { bufio.NewReader(os.Stdin).ReadBytes('\n') // Wait for Enter key press before continuing log.Info("Initializing XR headset") - rl.SetTargetFPS(int32(displayMetadata.MaxRefreshRate)) + rl.SetTargetFPS(int32(displayMetadata.MaxRefreshRate * 2)) rl.InitWindow(int32(displayMetadata.MaxWidth), int32(displayMetadata.MaxHeight), "UnrealXR") atexit.Register(func() { diff --git a/app/renderer/renderer.go b/app/renderer/renderer.go index 79cda44..b6fd79f 100644 --- a/app/renderer/renderer.go +++ b/app/renderer/renderer.go @@ -35,15 +35,6 @@ func findOptimalHorizontalRes(verticalDisplayRes float32, horizontalDisplayRes f return horizontalSize } -func findHfovFromVfov(vfovDeg, w, h float64) float64 { - vfovRad := vfovDeg * math.Pi / 180 - - ar := w / h - hfovRad := 2 * math.Atan(math.Tan(vfovRad/2)*ar) - - return hfovRad * 180 / math.Pi -} - func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.DisplayMetadata, evdiCards []*EvdiDisplayMetadata) { log.Info("Initializing AR driver") headset, err := ardriver.GetDevice() @@ -108,9 +99,7 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa headset.RegisterEventListeners(arEventListner) - fovY := float32(*config.DisplayConfig.FOV) - fovX := findHfovFromVfov(float64(fovY), float64(displayMetadata.MaxWidth), float64(displayMetadata.MaxHeight)) - + fovY := float32(45.0) verticalSize := findMaxVerticalSize(fovY, 5.0) camera := rl.NewCamera3D( @@ -136,21 +125,6 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa horizontalSize := findOptimalHorizontalRes(float32(displayMetadata.MaxHeight), float32(displayMetadata.MaxWidth), verticalSize) coreMesh := rl.GenMeshPlane(horizontalSize, verticalSize, 1, 1) - var radius float32 - - if *config.DisplayConfig.UseCircularSpacing == true { - radiusX := (horizontalSize / 2) / float32(math.Tan((float64(fovX)*math.Pi/180.0)/2)) - radiusY := (verticalSize / 2) / float32(math.Tan((float64(fovY)*math.Pi/180.0)/2)) - - if radiusY > radiusX { - radius = radiusY - } else { - radius = radiusX - } - - radius *= *config.DisplayConfig.RadiusMultiplier - } - movementVector := rl.Vector3{ X: 0.0, Y: 0.0, @@ -197,17 +171,6 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa texture := rl.LoadTextureFromImage(image) model := rl.LoadModelFromMesh(coreMesh) - // spin up/down - pitchRad := float32(-90 * rl.Deg2rad) - // spin left/right - yawRad := currentAngle * rl.Deg2rad - - rotX := rl.MatrixRotateX(pitchRad) - rotY := rl.MatrixRotateY(yawRad) - - transform := rl.MatrixMultiply(rotX, rotY) - model.Transform = transform - rl.SetMaterialTexture(model.Materials, rl.MapAlbedo, texture) rects[i] = &TextureModelPair{ @@ -221,24 +184,20 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa eventTimeoutDuration := 0 * time.Millisecond for !rl.WindowShouldClose() { - if !displayMetadata.DeviceQuirks.UsesMouseMovement { - if hasSensorInitDelayQuirk { - if time.Now().Sub(sensorInitStartTime) > time.Duration(displayMetadata.DeviceQuirks.SensorInitDelay)*time.Second { - log.Info("Movement is now enabled.") - hasSensorInitDelayQuirk = false - } - } else { - lookVector.X = (currentYaw - previousYaw) * 6.5 - lookVector.Y = -(currentPitch - previousPitch) * 6.5 - - if !hasZVectorDisabledQuirk { - lookVector.Z = (currentRoll - previousRoll) * 6.5 - } - - rl.UpdateCameraPro(&camera, movementVector, lookVector, 0) + if hasSensorInitDelayQuirk { + if time.Now().Sub(sensorInitStartTime) > time.Duration(displayMetadata.DeviceQuirks.SensorInitDelay)*time.Second { + log.Info("Movement is now enabled.") + hasSensorInitDelayQuirk = false } } else { - rl.UpdateCamera(&camera, rl.CameraFirstPerson) + lookVector.X = (currentYaw - previousYaw) * 6.5 + lookVector.Y = -(currentPitch - previousPitch) * 6.5 + + if !hasZVectorDisabledQuirk { + lookVector.Z = (currentRoll - previousRoll) * 6.5 + } + + rl.UpdateCameraPro(&camera, movementVector, lookVector, 0) } rl.BeginDrawing() @@ -272,35 +231,20 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa card.EvdiNode.RequestUpdate(card.Buffer) } - worldPos := rl.Vector3{ - X: 0, - Y: verticalSize / 2, - Z: 0, - } - - if *config.DisplayConfig.UseCircularSpacing == true { - yawRad := float32(rl.Deg2rad * rect.CurrentAngle) - - // WTF? - posX := float32(math.Sin(float64(yawRad))) * radius - posZ := -float32(math.Cos(float64(yawRad))) * radius - - worldPos.X = posX - worldPos.Z = posZ + radius - } else { - worldPos.X = rect.CurrentDisplaySpacing - } - rl.DrawModelEx( rect.Model, - worldPos, + rl.Vector3{ + X: rect.CurrentDisplaySpacing, + Y: verticalSize / 2, + Z: 0, + }, // rotate around X to make it vertical rl.Vector3{ - X: 0, + X: 1, Y: 0, Z: 0, }, - 0, + 90, rl.Vector3{ X: 1, Y: 1, diff --git a/ardriver/ardriver.go b/ardriver/ardriver.go index 51c45dd..913e40a 100644 --- a/ardriver/ardriver.go +++ b/ardriver/ardriver.go @@ -4,7 +4,6 @@ import ( "fmt" "git.terah.dev/UnrealXR/unrealxr/ardriver/commons" - "git.terah.dev/UnrealXR/unrealxr/ardriver/dummy" "git.terah.dev/UnrealXR/unrealxr/ardriver/xreal" ) @@ -20,16 +19,5 @@ func GetDevice() (commons.ARDevice, error) { return device, nil } - if dummy.IsDummyDeviceEnabled { - device, err := dummy.New() - - if err != nil { - fmt.Printf("failed to initialize dummy device: %w\n", err) - return nil, err - } - - return device, nil - } - return nil, fmt.Errorf("failed to initialize any device") } diff --git a/ardriver/dummy/dummy_ar.go b/ardriver/dummy/dummy_ar.go deleted file mode 100644 index d7bd00a..0000000 --- a/ardriver/dummy/dummy_ar.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build dummy_ar -// +build dummy_ar - -package dummy - -import ( - "git.terah.dev/UnrealXR/unrealxr/ardriver/commons" -) - -var IsDummyDeviceEnabled = true - -// Implements commons.ARDevice -type DummyDevice struct { -} - -func (device *DummyDevice) Initialize() error { - return nil -} - -func (device *DummyDevice) End() error { - return nil -} - -func (device *DummyDevice) IsPollingLibrary() bool { - return false -} - -func (device *DummyDevice) IsEventBasedLibrary() bool { - return false -} - -func (device *DummyDevice) Poll() error { - return nil -} - -func (device *DummyDevice) RegisterEventListeners(*commons.AREventListener) {} - -func New() (*DummyDevice, error) { - return &DummyDevice{}, nil -} diff --git a/ardriver/dummy/dummy_ar_disabled.go b/ardriver/dummy/dummy_ar_disabled.go deleted file mode 100644 index 8686db5..0000000 --- a/ardriver/dummy/dummy_ar_disabled.go +++ /dev/null @@ -1,42 +0,0 @@ -//go:build !dummy_ar -// +build !dummy_ar - -package dummy - -import ( - "fmt" - - "git.terah.dev/UnrealXR/unrealxr/ardriver/commons" -) - -var IsDummyDeviceEnabled = false - -// Implements commons.ARDevice -type DummyDevice struct { -} - -func (device *DummyDevice) Initialize() error { - return fmt.Errorf("dummy device is not enabled") -} - -func (device *DummyDevice) End() error { - return fmt.Errorf("dummy device is not enabled") -} - -func (device *DummyDevice) IsPollingLibrary() bool { - return false -} - -func (device *DummyDevice) IsEventBasedLibrary() bool { - return false -} - -func (device *DummyDevice) Poll() error { - return fmt.Errorf("dummy device is not enabled") -} - -func (device *DummyDevice) RegisterEventListeners(*commons.AREventListener) {} - -func New() (*DummyDevice, error) { - return nil, fmt.Errorf("dummy device is not enabled") -} diff --git a/ardriver/xreal/xrealsrc/Fusion.h b/ardriver/xreal/Fusion.h similarity index 100% rename from ardriver/xreal/xrealsrc/Fusion.h rename to ardriver/xreal/Fusion.h diff --git a/ardriver/xreal/xrealsrc/FusionAhrs.c b/ardriver/xreal/FusionAhrs.c similarity index 100% rename from ardriver/xreal/xrealsrc/FusionAhrs.c rename to ardriver/xreal/FusionAhrs.c diff --git a/ardriver/xreal/xrealsrc/FusionAhrs.h b/ardriver/xreal/FusionAhrs.h similarity index 100% rename from ardriver/xreal/xrealsrc/FusionAhrs.h rename to ardriver/xreal/FusionAhrs.h diff --git a/ardriver/xreal/xrealsrc/FusionAxes.h b/ardriver/xreal/FusionAxes.h similarity index 100% rename from ardriver/xreal/xrealsrc/FusionAxes.h rename to ardriver/xreal/FusionAxes.h diff --git a/ardriver/xreal/xrealsrc/FusionCalibration.h b/ardriver/xreal/FusionCalibration.h similarity index 100% rename from ardriver/xreal/xrealsrc/FusionCalibration.h rename to ardriver/xreal/FusionCalibration.h diff --git a/ardriver/xreal/xrealsrc/FusionCompass.c b/ardriver/xreal/FusionCompass.c similarity index 100% rename from ardriver/xreal/xrealsrc/FusionCompass.c rename to ardriver/xreal/FusionCompass.c diff --git a/ardriver/xreal/xrealsrc/FusionCompass.h b/ardriver/xreal/FusionCompass.h similarity index 100% rename from ardriver/xreal/xrealsrc/FusionCompass.h rename to ardriver/xreal/FusionCompass.h diff --git a/ardriver/xreal/xrealsrc/FusionConvention.h b/ardriver/xreal/FusionConvention.h similarity index 100% rename from ardriver/xreal/xrealsrc/FusionConvention.h rename to ardriver/xreal/FusionConvention.h diff --git a/ardriver/xreal/xrealsrc/FusionMath.h b/ardriver/xreal/FusionMath.h similarity index 100% rename from ardriver/xreal/xrealsrc/FusionMath.h rename to ardriver/xreal/FusionMath.h diff --git a/ardriver/xreal/xrealsrc/FusionOffset.c b/ardriver/xreal/FusionOffset.c similarity index 100% rename from ardriver/xreal/xrealsrc/FusionOffset.c rename to ardriver/xreal/FusionOffset.c diff --git a/ardriver/xreal/xrealsrc/FusionOffset.h b/ardriver/xreal/FusionOffset.h similarity index 100% rename from ardriver/xreal/xrealsrc/FusionOffset.h rename to ardriver/xreal/FusionOffset.h diff --git a/ardriver/xreal/xrealsrc/crc32.c b/ardriver/xreal/crc32.c similarity index 100% rename from ardriver/xreal/xrealsrc/crc32.c rename to ardriver/xreal/crc32.c diff --git a/ardriver/xreal/xrealsrc/crc32.h b/ardriver/xreal/crc32.h similarity index 100% rename from ardriver/xreal/xrealsrc/crc32.h rename to ardriver/xreal/crc32.h diff --git a/ardriver/xreal/xrealsrc/device.c b/ardriver/xreal/device.c similarity index 100% rename from ardriver/xreal/xrealsrc/device.c rename to ardriver/xreal/device.c diff --git a/ardriver/xreal/xrealsrc/device.h b/ardriver/xreal/device.h similarity index 100% rename from ardriver/xreal/xrealsrc/device.h rename to ardriver/xreal/device.h diff --git a/ardriver/xreal/xrealsrc/device_imu.c b/ardriver/xreal/device_imu.c similarity index 100% rename from ardriver/xreal/xrealsrc/device_imu.c rename to ardriver/xreal/device_imu.c diff --git a/ardriver/xreal/xrealsrc/device_imu.h b/ardriver/xreal/device_imu.h similarity index 100% rename from ardriver/xreal/xrealsrc/device_imu.h rename to ardriver/xreal/device_imu.h diff --git a/ardriver/xreal/xrealsrc/device_mcu.c b/ardriver/xreal/device_mcu.c similarity index 100% rename from ardriver/xreal/xrealsrc/device_mcu.c rename to ardriver/xreal/device_mcu.c diff --git a/ardriver/xreal/xrealsrc/device_mcu.h b/ardriver/xreal/device_mcu.h similarity index 100% rename from ardriver/xreal/xrealsrc/device_mcu.h rename to ardriver/xreal/device_mcu.h diff --git a/ardriver/xreal/xrealsrc/go_ffi.c b/ardriver/xreal/go_ffi.c similarity index 100% rename from ardriver/xreal/xrealsrc/go_ffi.c rename to ardriver/xreal/go_ffi.c diff --git a/ardriver/xreal/xrealsrc/go_ffi.h b/ardriver/xreal/go_ffi.h similarity index 100% rename from ardriver/xreal/xrealsrc/go_ffi.h rename to ardriver/xreal/go_ffi.h diff --git a/ardriver/xreal/xrealsrc/hid_ids.c b/ardriver/xreal/hid_ids.c similarity index 100% rename from ardriver/xreal/xrealsrc/hid_ids.c rename to ardriver/xreal/hid_ids.c diff --git a/ardriver/xreal/xrealsrc/hid_ids.h b/ardriver/xreal/hid_ids.h similarity index 100% rename from ardriver/xreal/xrealsrc/hid_ids.h rename to ardriver/xreal/hid_ids.h diff --git a/ardriver/xreal/xreal.go b/ardriver/xreal/xreal.go index 7e2dce4..08343b3 100644 --- a/ardriver/xreal/xreal.go +++ b/ardriver/xreal/xreal.go @@ -3,21 +3,127 @@ package xreal +// #cgo CFLAGS: -w -I./Fusion/ +// #cgo pkg-config: json-c libusb-1.0 hidapi-libusb +// #include "go_ffi.h" +// #include "device.h" +// #include "device_imu.h" +// #include "device_mcu.h" +import "C" import ( - xreal "git.terah.dev/UnrealXR/unrealxr/ardriver/xreal/xrealsrc" + "fmt" + "sync" + "time" + + "git.terah.dev/UnrealXR/unrealxr/ardriver/commons" ) -var IsXrealEnabled = true +var ( + IsXrealEnabled = true + deviceEventHandlerMutex = sync.Mutex{} + deviceEventListener *commons.AREventListener +) +//export goIMUEventHandler +func goIMUEventHandler(_ C.uint64_t, event_type C.device_imu_event_type, ahrs *C.struct_device_imu_ahrs_t) { + if deviceEventListener == nil { + return + } + + if event_type != C.DEVICE_IMU_EVENT_UPDATE { + return + } + + orientation := C.device_imu_get_orientation(ahrs) + euler := C.device_imu_get_euler(orientation) + + deviceEventListener.PitchCallback(float32(euler.pitch)) + deviceEventListener.RollCallback(float32(euler.roll)) + deviceEventListener.YawCallback(float32(euler.yaw)) +} + +// Implements commons.ARDevice type XrealDevice struct { - *xreal.XrealDevice + eventListener *commons.AREventListener + imuDevice *C.struct_device_imu_t + deviceIsOpen bool +} + +func (device *XrealDevice) Initialize() error { + if device.deviceIsOpen { + return fmt.Errorf("device is already open") + } + + device.imuDevice = &C.struct_device_imu_t{} + + // (*[0]byte) is a FUBAR way to cast a pointer to a function, but unsafe.Pointer doesn't work: + // cannot use unsafe.Pointer(_Cgo_ptr(_Cfpvar_fp_imuEventHandler)) (value of type unsafe.Pointer) as *[0]byte value in variable declaration + if C.DEVICE_IMU_ERROR_NO_ERROR != C.device_imu_open(device.imuDevice, (*[0]byte)(C.imuEventHandler)) { + return fmt.Errorf("failed to open IMU device") + } + + C.device_imu_clear(device.imuDevice) + C.device_imu_calibrate(device.imuDevice, 1000, true, true, false) + + device.deviceIsOpen = true + + // let's hope this doesn't cause race conditions + go func() { + for device.eventListener == nil { + time.Sleep(time.Millisecond * 10) + } + + for { + if !device.deviceIsOpen { + break + } + + // I'm sorry. + deviceEventHandlerMutex.Lock() + deviceEventListener = device.eventListener + status := C.device_imu_read(device.imuDevice, -1) + deviceEventHandlerMutex.Unlock() + + if status != C.DEVICE_IMU_ERROR_NO_ERROR { + break + } + } + + device.deviceIsOpen = false + C.device_imu_close(device.imuDevice) + }() + + return nil +} + +func (device *XrealDevice) End() error { + if !device.deviceIsOpen { + return fmt.Errorf("device is not open") + } + + C.device_imu_close(device.imuDevice) + device.deviceIsOpen = false + return nil +} + +func (device *XrealDevice) IsPollingLibrary() bool { + return false +} + +func (device *XrealDevice) IsEventBasedLibrary() bool { + return true +} + +func (device *XrealDevice) Poll() error { + return fmt.Errorf("not supported") +} + +func (device *XrealDevice) RegisterEventListeners(listener *commons.AREventListener) { + device.eventListener = listener } func New() (*XrealDevice, error) { - device := &XrealDevice{ - XrealDevice: &xreal.XrealDevice{}, - } - + device := &XrealDevice{} err := device.Initialize() if err != nil { diff --git a/ardriver/xreal/xrealsrc/xreal_debug_logging.go b/ardriver/xreal/xreal_debug_logging.go similarity index 100% rename from ardriver/xreal/xrealsrc/xreal_debug_logging.go rename to ardriver/xreal/xreal_debug_logging.go diff --git a/ardriver/xreal/xreal_disabled.go b/ardriver/xreal/xreal_disabled.go index e9d1372..c6ca903 100644 --- a/ardriver/xreal/xreal_disabled.go +++ b/ardriver/xreal/xreal_disabled.go @@ -35,7 +35,9 @@ func (device *XrealDevice) Poll() error { return fmt.Errorf("xreal is not enabled") } -func (device *XrealDevice) RegisterEventListeners(*commons.AREventListener) {} +func (device *XrealDevice) RegisterEventListeners(*commons.AREventListener) error { + return fmt.Errorf("xreal is not enabled") +} func New() (*XrealDevice, error) { return nil, fmt.Errorf("xreal is not enabled") diff --git a/ardriver/xreal/xrealsrc/xreal_bindings.go b/ardriver/xreal/xrealsrc/xreal_bindings.go deleted file mode 100644 index e3b435f..0000000 --- a/ardriver/xreal/xrealsrc/xreal_bindings.go +++ /dev/null @@ -1,122 +0,0 @@ -//go:build xreal -// +build xreal - -package xreal - -// #cgo CFLAGS: -w -// #cgo pkg-config: json-c libusb-1.0 hidapi-libusb -// #include "go_ffi.h" -// #include "device.h" -// #include "device_imu.h" -// #include "device_mcu.h" -import "C" -import ( - "fmt" - "sync" - "time" - - "git.terah.dev/UnrealXR/unrealxr/ardriver/commons" -) - -var ( - deviceEventHandlerMutex = sync.Mutex{} - deviceEventListener *commons.AREventListener -) - -//export goIMUEventHandler -func goIMUEventHandler(_ C.uint64_t, event_type C.device_imu_event_type, ahrs *C.struct_device_imu_ahrs_t) { - if deviceEventListener == nil { - return - } - - if event_type != C.DEVICE_IMU_EVENT_UPDATE { - return - } - - orientation := C.device_imu_get_orientation(ahrs) - euler := C.device_imu_get_euler(orientation) - - deviceEventListener.PitchCallback(float32(euler.pitch)) - deviceEventListener.RollCallback(float32(euler.roll)) - deviceEventListener.YawCallback(float32(euler.yaw)) -} - -// Implements commons.ARDevice -type XrealDevice struct { - eventListener *commons.AREventListener - imuDevice *C.struct_device_imu_t - deviceIsOpen bool -} - -func (device *XrealDevice) Initialize() error { - if device.deviceIsOpen { - return fmt.Errorf("device is already open") - } - - device.imuDevice = &C.struct_device_imu_t{} - - // (*[0]byte) is a FUBAR way to cast a pointer to a function, but unsafe.Pointer doesn't work: - // cannot use unsafe.Pointer(_Cgo_ptr(_Cfpvar_fp_imuEventHandler)) (value of type unsafe.Pointer) as *[0]byte value in variable declaration - if C.DEVICE_IMU_ERROR_NO_ERROR != C.device_imu_open(device.imuDevice, (*[0]byte)(C.imuEventHandler)) { - return fmt.Errorf("failed to open IMU device") - } - - C.device_imu_clear(device.imuDevice) - C.device_imu_calibrate(device.imuDevice, 1000, true, true, false) - - device.deviceIsOpen = true - - // let's hope this doesn't cause race conditions - go func() { - for device.eventListener == nil { - time.Sleep(time.Millisecond * 10) - } - - for { - if !device.deviceIsOpen { - break - } - - // I'm sorry. - deviceEventHandlerMutex.Lock() - deviceEventListener = device.eventListener - status := C.device_imu_read(device.imuDevice, -1) - deviceEventHandlerMutex.Unlock() - - if status != C.DEVICE_IMU_ERROR_NO_ERROR { - break - } - } - - device.deviceIsOpen = false - C.device_imu_close(device.imuDevice) - }() - - return nil -} - -func (device *XrealDevice) End() error { - if !device.deviceIsOpen { - return fmt.Errorf("device is not open") - } - - C.device_imu_close(device.imuDevice) - device.deviceIsOpen = false - return nil -} - -func (device *XrealDevice) IsPollingLibrary() bool { - return false -} - -func (device *XrealDevice) IsEventBasedLibrary() bool { - return true -} - -func (device *XrealDevice) Poll() error { - return fmt.Errorf("not supported") -} - -func (device *XrealDevice) RegisterEventListeners(listener *commons.AREventListener) { - device.eventListener = listener -} diff --git a/shell.nix b/shell.nix index 23e7db2..b1e1b78 100644 --- a/shell.nix +++ b/shell.nix @@ -27,13 +27,12 @@ xorg.libXinerama xorg.libX11 - # raylib X11 build dependencies (for dev-only non-XR builds) - libxkbcommon - # nreal driver build dependencies hidapi json_c + udev libusb1 + opencv ]; shellHook = '' @@ -41,6 +40,5 @@ mkdir -p "$PWD/data/config" "$PWD/data/data" export UNREALXR_CONFIG_PATH="$PWD/data/config" export UNREALXR_DATA_PATH="$PWD/data/data" - export UNREALXR_LOG_LEVEL="debug" ''; } diff --git a/unrealxr b/unrealxr index 5c13589..512cfa2 100755 --- a/unrealxr +++ b/unrealxr @@ -1,2 +1 @@ -#!/usr/bin/env bash sudo UNREALXR_LOG_LEVEL="$UNREALXR_LOG_LEVEL" LD_LIBRARY_PATH="$LD_LIBRARY_PATH" UNREALXR_CONFIG_PATH="$UNREALXR_CONFIG_PATH" UNREALXR_DATA_PATH="$UNREALXR_DATA_PATH" WAYLAND_DISPLAY="$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" XDG_RUNTIME_DIR="/user/run/0" ./uxr