feature: Get initial multi-display working in Go
This commit is contained in:
parent
243d595a35
commit
47e693a7b9
5 changed files with 261 additions and 35 deletions
|
@ -1,7 +1,10 @@
|
|||
package renderer
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
libconfig "git.terah.dev/UnrealXR/unrealxr/app/config"
|
||||
"git.terah.dev/UnrealXR/unrealxr/app/edidtools"
|
||||
|
@ -9,8 +12,27 @@ import (
|
|||
arcommons "git.terah.dev/UnrealXR/unrealxr/ardriver/commons"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/tebeka/atexit"
|
||||
|
||||
rl "git.terah.dev/UnrealXR/raylib-go/raylib"
|
||||
)
|
||||
|
||||
type TextureModelPair struct {
|
||||
Texture rl.Texture2D
|
||||
Model rl.Model
|
||||
}
|
||||
|
||||
func findMaxVerticalSize(fovyDeg float32, distance float32) float32 {
|
||||
fovyRad := float64(fovyDeg * math.Pi / 180.0)
|
||||
return 2 * distance * float32(math.Tan(fovyRad/2))
|
||||
}
|
||||
|
||||
func findOptimalHorizontalRes(verticalDisplayRes float32, horizontalDisplayRes float32, verticalSize float32) float32 {
|
||||
aspectRatio := horizontalDisplayRes / verticalDisplayRes
|
||||
horizontalSize := verticalSize * aspectRatio
|
||||
|
||||
return horizontalSize
|
||||
}
|
||||
|
||||
func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.DisplayMetadata, evdiCards []*EvdiDisplayMetadata) {
|
||||
log.Info("Initializing AR driver")
|
||||
headset, err := ardriver.GetDevice()
|
||||
|
@ -19,21 +41,52 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa
|
|||
log.Errorf("Failed to get device: %s", err.Error())
|
||||
atexit.Exit(1)
|
||||
}
|
||||
|
||||
log.Info("Initialized")
|
||||
|
||||
var pitch float32
|
||||
var yaw float32
|
||||
var roll float32
|
||||
var (
|
||||
currentPitch float32
|
||||
previousPitch float32
|
||||
currentYaw float32
|
||||
previousYaw float32
|
||||
currentRoll float32
|
||||
previousRoll float32
|
||||
|
||||
hasGottenPitchCallbackBefore bool
|
||||
hasGottenYawCallbackBefore bool
|
||||
hasGottenRollCallbackBefore bool
|
||||
)
|
||||
|
||||
arEventListner := &arcommons.AREventListener{
|
||||
PitchCallback: func(newPitch float32) {
|
||||
pitch = newPitch
|
||||
if !hasGottenPitchCallbackBefore {
|
||||
hasGottenPitchCallbackBefore = true
|
||||
currentPitch = newPitch
|
||||
previousPitch = newPitch
|
||||
} else {
|
||||
previousPitch = currentPitch
|
||||
currentPitch = newPitch
|
||||
}
|
||||
},
|
||||
YawCallback: func(newYaw float32) {
|
||||
yaw = newYaw
|
||||
if !hasGottenYawCallbackBefore {
|
||||
hasGottenYawCallbackBefore = true
|
||||
currentYaw = newYaw
|
||||
previousYaw = newYaw
|
||||
} else {
|
||||
previousYaw = currentYaw
|
||||
currentYaw = newYaw
|
||||
}
|
||||
},
|
||||
RollCallback: func(newRoll float32) {
|
||||
roll = newRoll
|
||||
if !hasGottenRollCallbackBefore {
|
||||
hasGottenRollCallbackBefore = true
|
||||
currentRoll = newRoll
|
||||
previousRoll = newRoll
|
||||
} else {
|
||||
previousRoll = currentRoll
|
||||
currentRoll = newRoll
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -44,8 +97,158 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa
|
|||
|
||||
headset.RegisterEventListeners(arEventListner)
|
||||
|
||||
for {
|
||||
log.Debugf("pitch: %f, yaw: %f, roll: %f", pitch, yaw, roll)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
fovY := float32(45.0)
|
||||
verticalSize := findMaxVerticalSize(fovY, 5.0)
|
||||
|
||||
camera := rl.NewCamera3D(
|
||||
rl.Vector3{
|
||||
X: 0.0,
|
||||
Y: verticalSize / 2,
|
||||
Z: 5.0,
|
||||
},
|
||||
rl.Vector3{
|
||||
X: 0.0,
|
||||
Y: verticalSize / 2,
|
||||
Z: 0.0,
|
||||
},
|
||||
rl.Vector3{
|
||||
X: 0.0,
|
||||
Y: 1.0,
|
||||
Z: 0.0,
|
||||
},
|
||||
fovY,
|
||||
rl.CameraPerspective,
|
||||
)
|
||||
|
||||
// Disable front and back face culling. It caused issues involving the entire virtual display dissappearing
|
||||
// If this issue still happens I *am* going to cry
|
||||
rl.DisableBackfaceCulling()
|
||||
rl.DisableDepthTest()
|
||||
|
||||
coreMesh := rl.GenMeshPlane(findOptimalHorizontalRes(float32(displayMetadata.MaxHeight), float32(displayMetadata.MaxWidth), verticalSize), verticalSize, 1, 1)
|
||||
|
||||
movementVector := rl.Vector3{
|
||||
X: 0.0,
|
||||
Y: 0.0,
|
||||
Z: 0.0,
|
||||
}
|
||||
|
||||
lookVector := rl.Vector3{
|
||||
X: 0.0,
|
||||
Y: 0.0,
|
||||
Z: 0.0,
|
||||
}
|
||||
|
||||
hasZVectorDisabledQuirk := false
|
||||
hasSensorInitDelayQuirk := false
|
||||
sensorInitStartTime := time.Now()
|
||||
|
||||
if displayMetadata.DeviceQuirks.ZVectorDisabled {
|
||||
log.Warn("QUIRK: The Z vector has been disabled for your specific device")
|
||||
hasZVectorDisabledQuirk = true
|
||||
}
|
||||
|
||||
if displayMetadata.DeviceQuirks.SensorInitDelay != 0 {
|
||||
log.Warnf("QUIRK: Waiting %d second(s) before reading sensors", displayMetadata.DeviceQuirks.SensorInitDelay)
|
||||
log.Warn("|| MOVEMENT WILL NOT BE OPERATIONAL DURING THIS TIME. ||")
|
||||
hasSensorInitDelayQuirk = true
|
||||
}
|
||||
|
||||
rects := make([]*TextureModelPair, len(evdiCards))
|
||||
|
||||
for i, card := range evdiCards {
|
||||
image := rl.NewImage(card.Buffer.Buffer, int32(displayMetadata.MaxWidth), int32(displayMetadata.MaxHeight), 1, rl.UncompressedR8g8b8a8)
|
||||
|
||||
texture := rl.LoadTextureFromImage(image)
|
||||
model := rl.LoadModelFromMesh(coreMesh)
|
||||
|
||||
rl.SetMaterialTexture(model.Materials, rl.MapAlbedo, texture)
|
||||
|
||||
rects[i] = &TextureModelPair{
|
||||
Texture: texture,
|
||||
Model: model,
|
||||
}
|
||||
}
|
||||
|
||||
eventTimeoutDuration := 0 * time.Millisecond
|
||||
|
||||
for !rl.WindowShouldClose() {
|
||||
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)
|
||||
}
|
||||
|
||||
rl.BeginDrawing()
|
||||
rl.ClearBackground(rl.Black)
|
||||
rl.BeginMode3D(camera)
|
||||
|
||||
for rectPos, rect := range rects {
|
||||
card := evdiCards[rectPos]
|
||||
|
||||
ready, err := card.EvdiNode.WaitUntilEventsAreReadyToHandle(eventTimeoutDuration)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Failed to wait for display events: %s", err.Error())
|
||||
break
|
||||
}
|
||||
|
||||
if ready {
|
||||
if err := card.EvdiNode.HandleEvents(card.EventContext); err != nil {
|
||||
log.Errorf("Failed to handle display events: %s", err.Error())
|
||||
break
|
||||
}
|
||||
|
||||
card.EvdiNode.GrabPixels(card.Rect)
|
||||
|
||||
pixels := unsafe.Slice(
|
||||
(*color.RGBA)(unsafe.Pointer(&card.Buffer.Buffer[0])),
|
||||
len(card.Buffer.Buffer)/4,
|
||||
)
|
||||
|
||||
rl.UpdateTexture(rect.Texture, pixels)
|
||||
card.EvdiNode.RequestUpdate(card.Buffer)
|
||||
}
|
||||
|
||||
rl.DrawModelEx(
|
||||
rect.Model,
|
||||
rl.Vector3{
|
||||
X: 0,
|
||||
Y: verticalSize / 2,
|
||||
Z: 0,
|
||||
},
|
||||
// rotate around X to make it vertical
|
||||
rl.Vector3{
|
||||
X: 1,
|
||||
Y: 0,
|
||||
Z: 0,
|
||||
},
|
||||
90,
|
||||
rl.Vector3{
|
||||
X: 1,
|
||||
Y: 1,
|
||||
Z: 1,
|
||||
},
|
||||
rl.White,
|
||||
)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
rl.EndMode3D()
|
||||
rl.EndDrawing()
|
||||
}
|
||||
|
||||
log.Info("Goodbye!")
|
||||
rl.CloseWindow()
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
package renderer
|
||||
|
||||
import "git.terah.dev/imterah/goevdi/libevdi"
|
||||
import (
|
||||
"git.terah.dev/imterah/goevdi/libevdi"
|
||||
)
|
||||
|
||||
type EvdiDisplayMetadata struct {
|
||||
EvdiNode *libevdi.EvdiNode
|
||||
Rect *libevdi.EvdiDisplayRect
|
||||
Buffer *libevdi.EvdiBuffer
|
||||
EvdiNode *libevdi.EvdiNode
|
||||
Rect *libevdi.EvdiDisplayRect
|
||||
Buffer *libevdi.EvdiBuffer
|
||||
EventContext *libevdi.EvdiEventContext
|
||||
ShouldRequestUpdate bool
|
||||
IsUpdateReady bool
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue