diff --git a/app/config/config.go b/app/config/config.go index 307a14b..1222abf 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -6,10 +6,10 @@ import _ "embed" var InitialConfig []byte type DisplayConfig struct { - Angle *int `yaml:"angle"` - FOV *int `yaml:"fov"` - Spacing *int `yaml:"spacing"` - Count *int `yaml:"count"` + Angle *int `yaml:"angle"` + FOV *int `yaml:"fov"` + Spacing *float32 `yaml:"spacing"` + Count *int `yaml:"count"` } type AppOverrides struct { @@ -28,6 +28,10 @@ func getPtrToInt(int int) *int { return &int } +func getPtrToFloat32(float32 float32) *float32 { + return &float32 +} + func getPtrToBool(bool bool) *bool { return &bool } @@ -36,7 +40,7 @@ var DefaultConfig = &Config{ DisplayConfig: DisplayConfig{ Angle: getPtrToInt(45), FOV: getPtrToInt(45), - Spacing: getPtrToInt(1), + Spacing: getPtrToFloat32(0.5), Count: getPtrToInt(3), }, Overrides: AppOverrides{ diff --git a/app/config/default_config.yml b/app/config/default_config.yml index a367a51..4938843 100644 --- a/app/config/default_config.yml +++ b/app/config/default_config.yml @@ -9,7 +9,7 @@ display: angle: 45 # Angle of the virtual displays fov: 45 # FOV of the 3D camera - spacing: 1 # Spacing between 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/main.go b/app/main.go index 436c1ab..239c49e 100644 --- a/app/main.go +++ b/app/main.go @@ -155,7 +155,13 @@ func mainEntrypoint(context.Context, *cli.Command) error { Y2: displayMetadata.MaxHeight, } - displayBuffer := openedDevice.CreateBuffer(displayMetadata.MaxWidth, displayMetadata.MaxHeight, libevdi.StridePixelFormatRGBA32, displayRect) + displayBuffer, err := openedDevice.CreateBuffer(displayMetadata.MaxWidth, displayMetadata.MaxHeight, libevdi.StridePixelFormatRGBA32, displayRect) + + if err != nil { + log.Errorf("Failed to create buffer for display %d: %s", currentDisplay, err.Error()) + atexit.Exit(1) + return nil + } displayMetadata := &renderer.EvdiDisplayMetadata{ EvdiNode: openedDevice, diff --git a/app/renderer/renderer.go b/app/renderer/renderer.go index d1ebbf9..cfc4739 100644 --- a/app/renderer/renderer.go +++ b/app/renderer/renderer.go @@ -17,8 +17,10 @@ import ( ) type TextureModelPair struct { - Texture rl.Texture2D - Model rl.Model + Texture rl.Texture2D + Model rl.Model + CurrentAngle float32 + CurrentDisplaySpacing float32 } func findMaxVerticalSize(fovyDeg float32, distance float32) float32 { @@ -125,7 +127,8 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa rl.DisableBackfaceCulling() rl.DisableDepthTest() - coreMesh := rl.GenMeshPlane(findOptimalHorizontalRes(float32(displayMetadata.MaxHeight), float32(displayMetadata.MaxWidth), verticalSize), verticalSize, 1, 1) + horizontalSize := findOptimalHorizontalRes(float32(displayMetadata.MaxHeight), float32(displayMetadata.MaxWidth), verticalSize) + coreMesh := rl.GenMeshPlane(horizontalSize, verticalSize, 1, 1) movementVector := rl.Vector3{ X: 0.0, @@ -156,7 +159,18 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa rects := make([]*TextureModelPair, len(evdiCards)) + displayAngle := float32(*config.DisplayConfig.Angle) + displaySpacing := *config.DisplayConfig.Spacing + horizontalSize + + highestPossibleAngleOnBothSides := float32((*config.DisplayConfig.Count)-1) * displayAngle + highestPossibleDisplaySpacingOnBothSides := float32((*config.DisplayConfig.Count)-1) * displaySpacing + for i, card := range evdiCards { + currentAngle := (-highestPossibleAngleOnBothSides) + (displayAngle * float32(i+1)) + currentDisplaySpacing := (-highestPossibleDisplaySpacingOnBothSides) + (displaySpacing * float32(i+1)) + + log.Debugf("display #%d: currentAngle=%f, currentDisplaySpacing=%f", i, currentAngle, currentDisplaySpacing) + image := rl.NewImage(card.Buffer.Buffer, int32(displayMetadata.MaxWidth), int32(displayMetadata.MaxHeight), 1, rl.UncompressedR8g8b8a8) texture := rl.LoadTextureFromImage(image) @@ -165,8 +179,10 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa rl.SetMaterialTexture(model.Materials, rl.MapAlbedo, texture) rects[i] = &TextureModelPair{ - Texture: texture, - Model: model, + Texture: texture, + Model: model, + CurrentAngle: currentAngle, + CurrentDisplaySpacing: currentDisplaySpacing, } } @@ -200,13 +216,13 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa if err != nil { log.Errorf("Failed to wait for display events: %s", err.Error()) - break + continue } if ready { if err := card.EvdiNode.HandleEvents(card.EventContext); err != nil { log.Errorf("Failed to handle display events: %s", err.Error()) - break + continue } card.EvdiNode.GrabPixels(card.Rect) @@ -223,7 +239,7 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa rl.DrawModelEx( rect.Model, rl.Vector3{ - X: 0, + X: rect.CurrentDisplaySpacing, Y: verticalSize / 2, Z: 0, }, @@ -241,8 +257,6 @@ func EnterRenderLoop(config *libconfig.Config, displayMetadata *edidtools.Displa }, rl.White, ) - - break } rl.EndMode3D() diff --git a/app/renderer/struct.go b/app/renderer/struct.go index af19e77..d975d27 100644 --- a/app/renderer/struct.go +++ b/app/renderer/struct.go @@ -5,8 +5,8 @@ import ( ) type EvdiDisplayMetadata struct { - EvdiNode *libevdi.EvdiNode - Rect *libevdi.EvdiDisplayRect - Buffer *libevdi.EvdiBuffer - EventContext *libevdi.EvdiEventContext + EvdiNode *libevdi.EvdiNode + Rect *libevdi.EvdiDisplayRect + Buffer *libevdi.EvdiBuffer + EventContext *libevdi.EvdiEventContext } diff --git a/go.mod b/go.mod index aedc610..e631900 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.24.3 require ( git.terah.dev/UnrealXR/raylib-go/raylib v0.55.2-0.20250623002739-1468af2636e1 - git.terah.dev/imterah/goevdi v1.14.11-0.20250626004148-bdbef2a68ff9 github.com/anoopengineer/edidparser v0.0.0-20240602223913-86ca9ed3d2b0 github.com/charmbracelet/log v0.4.2 github.com/goccy/go-yaml v1.18.0 @@ -15,6 +14,7 @@ require ( ) require ( + git.terah.dev/imterah/goevdi/libevdi v0.1.0-evdi1.14.10 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/lipgloss v1.1.0 // indirect diff --git a/go.sum b/go.sum index aad411c..a5b5c74 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ git.terah.dev/UnrealXR/raylib-go/raylib v0.55.2-0.20250623002739-1468af2636e1 h1 git.terah.dev/UnrealXR/raylib-go/raylib v0.55.2-0.20250623002739-1468af2636e1/go.mod h1:ZRirF2UuVWSbl2ux7oyHwXcinni9msejCvtIsXbT8yY= git.terah.dev/imterah/goevdi v1.14.11-0.20250626004148-bdbef2a68ff9 h1:TYcPZ62CR3keYf/dE9KyV5X5krh+riDyZ3fnhkeSRyA= git.terah.dev/imterah/goevdi v1.14.11-0.20250626004148-bdbef2a68ff9/go.mod h1:4scjAuFakx/2gTRSeCtTNHnj1v9FdF3XiOMmWsz4FDs= +git.terah.dev/imterah/goevdi/libevdi v0.1.0-evdi1.14.10 h1:M+Wja0b6Ks3mZXMGoBs3KZXsKRRWolUelITLQ/kaIFw= +git.terah.dev/imterah/goevdi/libevdi v0.1.0-evdi1.14.10/go.mod h1:7zdodqq+tECNHTljD5l7x0PvcGglLCa+mD2eQj0vkEg= github.com/anoopengineer/edidparser v0.0.0-20240602223913-86ca9ed3d2b0 h1:rTfysyBCL7LPbq9GFpQbllvKT8vEI93lQUwksMMxHMI= github.com/anoopengineer/edidparser v0.0.0-20240602223913-86ca9ed3d2b0/go.mod h1:fEt61NePh3ZMxA+g3iC4CaGzY9lEsHRUkYJY2x0lBAw= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=