ImGuiVrPanelSmokeTest.kt
src/jvmMain/kotlin/afield/examples/four/ImGuiVrPanelSmokeTest.kt · 76 lines
package afield.examples.four
import afield.graphics.vulkan.Renderer
import afield.graphics.vulkan.targets.SideBySideStereoTarget
import afield.graphics.vulkan.util.Window
import afield.math.linalg.Vector3f
import kotlin.math.abs
FIELD_TEST id: examples.four.imgui-vr-panel-smoke requiresDisplay: true runner: jvm-main entrypoint: afield.examples.four.ImGuiVrPanelSmokeTest timeoutSec: 60 expect: stdout: - "ImGuiVrPanelSmokeTest ok"
class ImGuiVrPanelSmokeTest
End-to-end smoke for the ImGui-as-a-VR-panel pipeline: builds the ImGui -> RTT -> stereo-quad -> side-by-side pipeline exactly as ImGuiVrPanelDemo, renders a warm-up of frames on a real Vulkan window with the mock controller aimed at the panel centre, and asserts the controller ray -> quad hit-test round-trips to panel-centre UV.
This is the desktop (non-headset) path: the packed side-by-side image is what OpenXR copies into the eye swapchains on Windows/Linux (SideBySideStereoTarget.openXR == null here, since OpenXR natives are excluded on macOS). The assertion is on the raycast math + the fact that the whole per-eye render graph builds and runs without error; it does not depend on window compositing.
companion object
fun main(args: Array<String>)
body — 42 lines, from line 34
@JvmStatic
fun main(args: Array<String>) {
val window = Window("ImGui VR Panel Smoke Test")
val renderer = Renderer(window)
val sbs = SideBySideStereoTarget(renderer)
val demo = ImGuiVrPanelDemo(window, renderer, sbs)
try {
demo.build()
val frames = 60
repeat(frames) {
window.pollEvents()
demo.aimControllerAtPanelCentre()
renderer.render()
if (window.shouldClose()) return@repeat
}
require(demo.hitActive) {
"Controller ray never hit the panel after $frames frames"
}
require(abs(demo.hitU - 0.5f) < 0.02f && abs(demo.hitV - 0.5f) < 0.02f) {
"Centre-aimed ray expected UV (0.5, 0.5), got (${demo.hitU}, ${demo.hitV})"
}
val hit = requireNotNull(demo.lastHitWorld) { "No world hit recorded" }
val expected = Vector3f(0f, 0f, 1.5f)
require(hit.distance(expected) < 0.05f) {
"Expected world hit near $expected, got $hit"
}
println(
"ImGuiVrPanelSmokeTest ok: hitUV=(%.3f, %.3f) hitWorld=(%.3f, %.3f, %.3f)"
.format(demo.hitU, demo.hitV, hit.x, hit.y, hit.z)
)
} finally {
demo.cleanup()
renderer.cleanup()
window.cleanup()
}
}
}
}