feature: Improve device quirks support
This commit is contained in:
parent
79c7846ecd
commit
ad451ac014
6 changed files with 50 additions and 23 deletions
|
@ -39,11 +39,11 @@ From there, you need to follow all the below steps if applicable to your current
|
||||||
|
|
||||||
1. First, you need to build the native version of raylib. To do that, go inside the `modules/raylib-python-cffi/raylib-c` directory.
|
1. First, you need to build the native version of raylib. To do that, go inside the `modules/raylib-python-cffi/raylib-c` directory.
|
||||||
2. Then, make the build directories and go into them: `mkdir -p build/out; cd build`
|
2. Then, make the build directories and go into them: `mkdir -p build/out; cd build`
|
||||||
3. Configure raylib: `cmake -DCUSTOMIZE_BUILD=ON -DSUPPORT_FILEFORMAT_JPG=ON -DSUPPORT_FILEFORMAT_FLAC=ON -DWITH_PIC=ON -DCMAKE_BUILD_TYPE=Release -DPLATFORM=DRM -DENABLE_WAYLAND_DRM_LEASING=ON -DSUPPORT_CLIPBOARD_IMAGE=ON -DCMAKE_INSTALL_PREFIX:PATH=$PWD/out ..`
|
3. Configure raylib: `cmake -DCUSTOMIZE_BUILD=ON -DSUPPORT_FILEFORMAT_JPG=ON -DSUPPORT_FILEFORMAT_FLAC=ON -DWITH_PIC=ON -DCMAKE_BUILD_TYPE=Release -DPLATFORM=DRM -DENABLE_WAYLAND_DRM_LEASING=ON -DSUPPORT_CLIPBOARD_IMAGE=ON -DBUILD_EXAMPLES=OFF -DSUPPORT_SSH_KEYBOARD_RPI=OFF -DDISABLE_EVDEV_INPUT=ON -DCMAKE_INSTALL_PREFIX:PATH=$PWD/out ..`
|
||||||
4. Finally, build and install raylib: `make install -j$(nproc)`
|
4. Finally, build and install raylib: `make install -j$(nproc)`
|
||||||
5. After that, you need to build the Python bindings. To do that, go to the `modules/raylib-python-cffi` directory. Assuming you did everything correctly, you should be able to go 2 directories back (`../..`) to get there.
|
5. After that, you need to build the Python bindings. To do that, go to the `modules/raylib-python-cffi` directory. Assuming you did everything correctly, you should be able to go 2 directories back (`../..`) to get there.
|
||||||
6. If you're on normal Linux and are not using Nix, do this command to build the package: `PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PWD/raylib-c/build/out/lib64/pkgconfig/" ENABLE_WAYLAND_DRM_LEASING=YES RAYLIB_PLATFORM=DRM python3 setup.py bdist_wheel`
|
6. If you're on normal Linux and are not using Nix, do this command to build the package: `PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PWD/raylib-c/build/out/lib64/pkgconfig/" ENABLE_WAYLAND_DRM_LEASING=YES RAYLIB_PLATFORM=DRM python3 setup.py bdist_wheel`
|
||||||
7. If you are using Nix/NixOS, do this command to build the package: `PKG_CONFIG_PATH_FOR_TARGET="$PKG_CONFIG_PATH_FOR_TARGET:$PWD/raylib-c/build/out/lib64/pkgconfig/" ENABLE_WAYLAND_DRM_LEASING=YES RAYLIB_PLATFORM=DRM python3 setup.py bdist_wheel; pip install dist/*.whl`
|
7. If you are using Nix/NixOS, do this command to build the package: `PKG_CONFIG_PATH_FOR_TARGET="$PKG_CONFIG_PATH_FOR_TARGET:$PWD/raylib-c/build/out/lib64/pkgconfig/" ENABLE_WAYLAND_DRM_LEASING=YES RAYLIB_PLATFORM=DRM python3 setup.py bdist_wheel`
|
||||||
8. Finally, install the package: `pip install dist/*.whl`
|
8. Finally, install the package: `pip install dist/*.whl`
|
||||||
|
|
||||||
### Building `PyEvdi` (Linux)
|
### Building `PyEvdi` (Linux)
|
||||||
|
|
|
@ -4,9 +4,10 @@ from dataclasses import dataclass
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class EvdiDisplaySpec:
|
class UnrealXRDisplayMetadata:
|
||||||
edid: bytes
|
edid: bytes
|
||||||
device_vendor: str
|
device_vendor: str
|
||||||
|
device_quirks: dict[str, str | int]
|
||||||
max_width: int
|
max_width: int
|
||||||
max_height: int
|
max_height: int
|
||||||
max_refresh_rate: int
|
max_refresh_rate: int
|
||||||
|
|
|
@ -2,13 +2,13 @@ import subprocess
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from libunreal.supported_devices import supported_devices
|
from libunreal.supported_devices import supported_devices
|
||||||
from libunreal.edid import EvdiDisplaySpec
|
from libunreal.edid import UnrealXRDisplayMetadata
|
||||||
import pyedid
|
import pyedid
|
||||||
|
|
||||||
def upload_new_device_edid(display_spec: EvdiDisplaySpec, edid: bytes | bytearray):
|
def upload_new_device_edid(display_spec: UnrealXRDisplayMetadata, edid: bytes | bytearray):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def fetch_xr_glass_edid(allow_unsupported_devices) -> EvdiDisplaySpec:
|
def fetch_xr_glass_edid(allow_unsupported_devices) -> UnrealXRDisplayMetadata:
|
||||||
# Scan for all VGA devices and their IDs
|
# Scan for all VGA devices and their IDs
|
||||||
pci_device_comand = subprocess.run(["lspci"], capture_output=True)
|
pci_device_comand = subprocess.run(["lspci"], capture_output=True)
|
||||||
|
|
||||||
|
@ -72,11 +72,11 @@ def fetch_xr_glass_edid(allow_unsupported_devices) -> EvdiDisplaySpec:
|
||||||
|
|
||||||
max_refresh = int(manufacturer_supported_devices[edid.name]["max_refresh"])
|
max_refresh = int(manufacturer_supported_devices[edid.name]["max_refresh"])
|
||||||
|
|
||||||
return EvdiDisplaySpec(raw_edid_file, edid.manufacturer_pnp_id, max_width, max_height, max_refresh, card_device, monitor.replace(f"{card_device}-", ""))
|
return UnrealXRDisplayMetadata(raw_edid_file, edid.manufacturer_pnp_id, manufacturer_supported_devices[edid.name], max_width, max_height, max_refresh, card_device, monitor.replace(f"{card_device}-", ""))
|
||||||
|
|
||||||
raise ValueError("Could not find supported device. Check if the device is plugged in. If it is plugged in and working correctly, check the README or open an issue.")
|
raise ValueError("Could not find supported device. Check if the device is plugged in. If it is plugged in and working correctly, check the README or open an issue.")
|
||||||
|
|
||||||
def upload_edid_firmware(display: EvdiDisplaySpec, fw: bytes | bytearray):
|
def upload_edid_firmware(display: UnrealXRDisplayMetadata, fw: bytes | bytearray):
|
||||||
if display.linux_drm_connector == "" or display.linux_drm_card == "":
|
if display.linux_drm_connector == "" or display.linux_drm_card == "":
|
||||||
raise ValueError("Linux DRM connector and/or Linux DRM card not specified!")
|
raise ValueError("Linux DRM connector and/or Linux DRM card not specified!")
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,9 @@ supported_devices: dict[str, dict[str, dict[str, str | int]]] = {
|
||||||
"Air": {
|
"Air": {
|
||||||
"max_width": 1920,
|
"max_width": 1920,
|
||||||
"max_height": 1080,
|
"max_height": 1080,
|
||||||
"max_refresh": 120
|
"max_refresh": 120,
|
||||||
|
"sensor_init_delay": 10,
|
||||||
|
"z_vector_disabled": True,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
main.py
11
main.py
|
@ -1,9 +1,14 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from sys import platform
|
from sys import platform
|
||||||
|
import logging
|
||||||
import atexit
|
import atexit
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
# Silence pyray init messages
|
||||||
|
raylib_python_logger = logging.getLogger("raylib")
|
||||||
|
raylib_python_logger.setLevel(logging.ERROR)
|
||||||
|
|
||||||
from platformdirs import user_data_dir, user_config_dir
|
from platformdirs import user_data_dir, user_config_dir
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
import PyEvdi
|
import PyEvdi
|
||||||
|
@ -16,6 +21,7 @@ import libunreal
|
||||||
|
|
||||||
default_configuration: dict[str, str | int] = {
|
default_configuration: dict[str, str | int] = {
|
||||||
"display_angle": 45,
|
"display_angle": 45,
|
||||||
|
"display_pixel_spacing": 45,
|
||||||
"display_count": 3,
|
"display_count": 3,
|
||||||
"allow_unsupported_devices": False,
|
"allow_unsupported_devices": False,
|
||||||
"allow_unsupported_vendors": False,
|
"allow_unsupported_vendors": False,
|
||||||
|
@ -106,7 +112,7 @@ def main():
|
||||||
|
|
||||||
# Get the display EDID
|
# Get the display EDID
|
||||||
logger.info("Attempting to read display EDID file")
|
logger.info("Attempting to read display EDID file")
|
||||||
edid: libunreal.EvdiDisplaySpec | None = None
|
edid: libunreal.UnrealXRDisplayMetadata | None = None
|
||||||
|
|
||||||
if configuration["override_default_edid"] or configuration["allow_unsupported_vendors"]:
|
if configuration["override_default_edid"] or configuration["allow_unsupported_vendors"]:
|
||||||
# We need to parse it to get the maximum width, height, and refresh rate for EVDI's calculations
|
# We need to parse it to get the maximum width, height, and refresh rate for EVDI's calculations
|
||||||
|
@ -134,7 +140,7 @@ def main():
|
||||||
if max_refresh == 0:
|
if max_refresh == 0:
|
||||||
raise ValueError("Could not determine maximum refresh rate from EDID file, and the refresh rate overrides aren't set!")
|
raise ValueError("Could not determine maximum refresh rate from EDID file, and the refresh rate overrides aren't set!")
|
||||||
|
|
||||||
edid = libunreal.EvdiDisplaySpec(edid_file, parsed_edid_file.name if parsed_edid_file.name else "", max_width, max_height, max_refresh, "", "")
|
edid = libunreal.UnrealXRDisplayMetadata(edid_file, parsed_edid_file.name if parsed_edid_file.name else "", {}, max_width, max_height, max_refresh, "", "")
|
||||||
else:
|
else:
|
||||||
edid = libunreal.fetch_xr_glass_edid(configuration["allow_unsupported_devices"])
|
edid = libunreal.fetch_xr_glass_edid(configuration["allow_unsupported_devices"])
|
||||||
|
|
||||||
|
@ -176,6 +182,7 @@ def main():
|
||||||
|
|
||||||
logger.info("Initialized displays. Entering rendering loop")
|
logger.info("Initialized displays. Entering rendering loop")
|
||||||
render_loop(edid, cards)
|
render_loop(edid, cards)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("Welcome to UnrealXR!\n")
|
print("Welcome to UnrealXR!\n")
|
||||||
main()
|
main()
|
||||||
|
|
41
render.py
41
render.py
|
@ -1,11 +1,11 @@
|
||||||
from time import sleep
|
import time
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
import PyEvdi
|
import PyEvdi
|
||||||
import pyray
|
import pyray
|
||||||
|
|
||||||
from libunreal import EvdiDisplaySpec, MCUCallbackWrapper, start_mcu_event_listener
|
from libunreal import UnrealXRDisplayMetadata, MCUCallbackWrapper, start_mcu_event_listener
|
||||||
|
|
||||||
previous_pitch = 0.0
|
previous_pitch = 0.0
|
||||||
previous_yaw = 0.0
|
previous_yaw = 0.0
|
||||||
|
@ -64,7 +64,7 @@ def text_message(message: str):
|
||||||
def stub_brightness_function(brightness: int):
|
def stub_brightness_function(brightness: int):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def render_loop(display_metadata: EvdiDisplaySpec, cards: list[PyEvdi.Card]):
|
def render_loop(display_metadata: UnrealXRDisplayMetadata, cards: list[PyEvdi.Card]):
|
||||||
logger.info("Starting sensor event listener")
|
logger.info("Starting sensor event listener")
|
||||||
|
|
||||||
mcu_callbacks = MCUCallbackWrapper(roll_callback, pitch_callback, yaw_callback, text_message, stub_brightness_function, stub_brightness_function)
|
mcu_callbacks = MCUCallbackWrapper(roll_callback, pitch_callback, yaw_callback, text_message, stub_brightness_function, stub_brightness_function)
|
||||||
|
@ -73,7 +73,7 @@ def render_loop(display_metadata: EvdiDisplaySpec, cards: list[PyEvdi.Card]):
|
||||||
logger.info("Beginning sensor initialization. Awaiting first sensor update")
|
logger.info("Beginning sensor initialization. Awaiting first sensor update")
|
||||||
|
|
||||||
while (not has_gotten_pitch_callback_before) or (not has_gotten_yaw_callback_before) or (not has_gotten_roll_callback_before):
|
while (not has_gotten_pitch_callback_before) or (not has_gotten_yaw_callback_before) or (not has_gotten_roll_callback_before):
|
||||||
sleep(0.01)
|
time.sleep(0.01)
|
||||||
|
|
||||||
logger.info("Initialized sensors")
|
logger.info("Initialized sensors")
|
||||||
|
|
||||||
|
@ -89,17 +89,34 @@ def render_loop(display_metadata: EvdiDisplaySpec, cards: list[PyEvdi.Card]):
|
||||||
movement_vector = pyray.Vector3()
|
movement_vector = pyray.Vector3()
|
||||||
look_vector = pyray.Vector3()
|
look_vector = pyray.Vector3()
|
||||||
|
|
||||||
logger.error("QUIRK: Waiting 10 seconds before reading sensors due to sensor drift bugs")
|
has_z_vector_disabled_quirk = False
|
||||||
sleep(10)
|
has_sensor_init_delay_quirk = False
|
||||||
logger.error("Continuing...")
|
sensor_init_start_time = time.time()
|
||||||
|
|
||||||
|
if "z_vector_disabled" in display_metadata.device_quirks:
|
||||||
|
logger.warning("QUIRK: The Z vector has been disabled for your specific device")
|
||||||
|
has_z_vector_disabled_quirk = True
|
||||||
|
|
||||||
|
if "sensor_init_delay" in display_metadata.device_quirks:
|
||||||
|
logger.warning(f"QUIRK: Waiting {str(display_metadata.device_quirks["sensor_init_delay"])} second(s) before reading sensors")
|
||||||
|
logger.warning("|| MOVEMENT WILL NOT BE OPERATIONAL DURING THIS TIME. ||")
|
||||||
|
sensor_init_start_time = time.time()
|
||||||
|
has_sensor_init_delay_quirk = True
|
||||||
|
|
||||||
while not pyray.window_should_close():
|
while not pyray.window_should_close():
|
||||||
look_vector.x = (current_yaw-previous_yaw)*6.5
|
if has_sensor_init_delay_quirk:
|
||||||
look_vector.y = (current_pitch-previous_pitch)*6.5
|
if time.time() - sensor_init_start_time >= int(display_metadata.device_quirks["sensor_init_delay"]):
|
||||||
# the Z vector is more trouble than its worth so it just doesn't get accounted for...
|
# Unset the quirk state
|
||||||
#look_vector.z = (current_roll-previous_roll)*6.5
|
logger.info("Movement is now enabled.")
|
||||||
|
has_sensor_init_delay_quirk = False
|
||||||
|
else:
|
||||||
|
look_vector.x = (current_yaw-previous_yaw)*6.5
|
||||||
|
look_vector.y = (current_pitch-previous_pitch)*6.5
|
||||||
|
|
||||||
pyray.update_camera_pro(camera, movement_vector, look_vector, 0.0)
|
if not has_z_vector_disabled_quirk:
|
||||||
|
look_vector.z = (current_roll-previous_roll)*6.5
|
||||||
|
|
||||||
|
pyray.update_camera_pro(camera, movement_vector, look_vector, 0.0)
|
||||||
|
|
||||||
pyray.begin_drawing()
|
pyray.begin_drawing()
|
||||||
pyray.clear_background(pyray.BLACK)
|
pyray.clear_background(pyray.BLACK)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue