forked from LeenkxTeam/LNXSDK
287 lines
7.4 KiB
Haxe
287 lines
7.4 KiB
Haxe
|
package kha.vr;
|
||
|
|
||
|
import kha.arrays.Float32Array;
|
||
|
import kha.graphics4.FragmentShader;
|
||
|
import kha.graphics4.Graphics;
|
||
|
import kha.Framebuffer;
|
||
|
import kha.graphics4.ConstantLocation;
|
||
|
import kha.graphics4.IndexBuffer;
|
||
|
import kha.graphics4.PipelineState;
|
||
|
import kha.graphics4.TextureUnit;
|
||
|
import kha.graphics4.Usage;
|
||
|
import kha.graphics4.VertexBuffer;
|
||
|
import kha.graphics4.VertexShader;
|
||
|
import kha.graphics4.VertexStructure;
|
||
|
import kha.graphics4.VertexData;
|
||
|
import kha.input.Keyboard;
|
||
|
import kha.input.KeyCode;
|
||
|
import kha.math.FastMatrix4;
|
||
|
import kha.math.Matrix4;
|
||
|
import kha.math.Quaternion;
|
||
|
import kha.math.Vector4;
|
||
|
import kha.math.Vector3;
|
||
|
import kha.math.Vector2;
|
||
|
import kha.Shaders;
|
||
|
import kha.vr.Pose;
|
||
|
import kha.vr.PoseState;
|
||
|
import kha.vr.SensorState;
|
||
|
import kha.vr.TimeWarpParms;
|
||
|
import kha.input.Gamepad;
|
||
|
import kha.input.Mouse;
|
||
|
|
||
|
class VrInterfaceEmulated extends kha.vr.VrInterface {
|
||
|
public var framebuffer: Framebuffer;
|
||
|
|
||
|
var orientation: Quaternion;
|
||
|
|
||
|
// private var f: Float = 0.0;
|
||
|
var pitchDegrees: Float = 0.0;
|
||
|
var yawDegrees: Float = 0.0;
|
||
|
|
||
|
var pitchDelta: Float = 0.0;
|
||
|
var yawDelta: Float = 0.0;
|
||
|
|
||
|
static inline var keyboardSpeed: Float = 2.0;
|
||
|
|
||
|
static inline var mouseSpeed: Float = 0.1;
|
||
|
|
||
|
static inline var minPitchDegrees: Float = -80;
|
||
|
static inline var maxPitchDegrees: Float = 80;
|
||
|
|
||
|
function degreesToRadians(degrees: Float): Float {
|
||
|
return degrees * Math.PI / 180.0;
|
||
|
}
|
||
|
|
||
|
function updateOrientation(): Void {
|
||
|
// Update from keyboard input
|
||
|
yawDegrees += yawDelta;
|
||
|
pitchDegrees += pitchDelta;
|
||
|
|
||
|
if (pitchDegrees < minPitchDegrees)
|
||
|
pitchDegrees = minPitchDegrees;
|
||
|
if (pitchDegrees > maxPitchDegrees)
|
||
|
pitchDegrees = maxPitchDegrees;
|
||
|
|
||
|
// Compute from pitch and yaw
|
||
|
|
||
|
var pitchQuat = Quaternion.fromAxisAngle(new Vector3(1, 0, 0), degreesToRadians(pitchDegrees));
|
||
|
|
||
|
var yawQuat = Quaternion.fromAxisAngle(new Vector3(0, 1, 0), degreesToRadians(yawDegrees));
|
||
|
orientation = yawQuat.mult(pitchQuat);
|
||
|
}
|
||
|
|
||
|
function buttonEvent(button: Int, value: Float): Void {}
|
||
|
|
||
|
function axisEvent(axis: Int, value: Float): Void {}
|
||
|
|
||
|
function keyDownEvent(code: KeyCode): Void {
|
||
|
switch (code) {
|
||
|
case KeyCode.Left:
|
||
|
yawDelta = keyboardSpeed;
|
||
|
|
||
|
case KeyCode.Right:
|
||
|
yawDelta = -keyboardSpeed;
|
||
|
|
||
|
case KeyCode.Up:
|
||
|
pitchDelta = keyboardSpeed;
|
||
|
|
||
|
case KeyCode.Down:
|
||
|
pitchDelta = -keyboardSpeed;
|
||
|
|
||
|
default:
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function keyUpEvent(code: KeyCode): Void {
|
||
|
switch (code) {
|
||
|
case KeyCode.Left:
|
||
|
yawDelta = 0.0;
|
||
|
|
||
|
case KeyCode.Right:
|
||
|
yawDelta = 0.0;
|
||
|
|
||
|
case KeyCode.Up:
|
||
|
pitchDelta = 0.0;
|
||
|
|
||
|
case KeyCode.Down:
|
||
|
pitchDelta = 0.0;
|
||
|
|
||
|
default:
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var oldMouseX: Int = 0;
|
||
|
var oldMouseY: Int = 0;
|
||
|
|
||
|
function mouseMoveEvent(x: Int, y: Int, movementX: Int, movementY: Int) {
|
||
|
if (!mouseButtonDown)
|
||
|
return;
|
||
|
|
||
|
var mouseDeltaX: Int = x - oldMouseX;
|
||
|
var mouseDeltaY: Int = y - oldMouseY;
|
||
|
oldMouseX = x;
|
||
|
oldMouseY = y;
|
||
|
|
||
|
yawDegrees += mouseDeltaX * mouseSpeed;
|
||
|
pitchDegrees += mouseDeltaY * mouseSpeed;
|
||
|
|
||
|
if (pitchDegrees < minPitchDegrees)
|
||
|
pitchDegrees = minPitchDegrees;
|
||
|
if (pitchDegrees > maxPitchDegrees)
|
||
|
pitchDegrees = maxPitchDegrees;
|
||
|
}
|
||
|
|
||
|
var mouseButtonDown: Bool = false;
|
||
|
|
||
|
function mouseButtonDownEvent(button: Int, x: Int, y: Int) {
|
||
|
if (button == 0) {
|
||
|
mouseButtonDown = true;
|
||
|
oldMouseX = x;
|
||
|
oldMouseY = y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function mouseButtonUpEvent(button: Int, x: Int, y: Int) {
|
||
|
if (button == 0) {
|
||
|
mouseButtonDown = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Returns the current sensor state
|
||
|
// Returns the predicted sensor state at the specified time
|
||
|
public override function GetSensorState(): SensorState {
|
||
|
return GetPredictedSensorState(0.0);
|
||
|
}
|
||
|
|
||
|
// Returns the predicted sensor state at the specified time
|
||
|
public override function GetPredictedSensorState(time: Float): SensorState {
|
||
|
// TODO: Would be better if the interface was called independently each frame - we don't know how often this function is called.
|
||
|
updateOrientation();
|
||
|
|
||
|
var result: SensorState = new SensorState();
|
||
|
// TODO: Check values
|
||
|
result.Status = 0;
|
||
|
result.Temperature = 75;
|
||
|
result.Predicted = new PoseState();
|
||
|
result.Recorded = result.Predicted;
|
||
|
|
||
|
result.Predicted.AngularAcceleration = new Vector3();
|
||
|
result.Predicted.AngularVelocity = new Vector3();
|
||
|
result.Predicted.LinearAcceleration = new Vector3();
|
||
|
result.Predicted.LinearVelocity = new Vector3();
|
||
|
result.Predicted.TimeInSeconds = time;
|
||
|
result.Predicted.Pose = new Pose();
|
||
|
result.Predicted.Pose.Orientation = orientation;
|
||
|
result.Predicted.Pose.Position = new Vector3();
|
||
|
|
||
|
// TODO: Simulate the head movement using the mouse
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Sends a black image to the warp swap thread
|
||
|
public override function WarpSwapBlack(): Void {
|
||
|
// TODO: Implement
|
||
|
}
|
||
|
|
||
|
// Sends the Oculus loading symbol to the warp swap thread
|
||
|
public override function WarpSwapLoadingIcon(): Void {
|
||
|
// TODO: Implement
|
||
|
}
|
||
|
|
||
|
// Sends the set of images to the warp swap thread
|
||
|
public override function WarpSwap(parms: TimeWarpParms): Void {
|
||
|
var g: Graphics = framebuffer.g4;
|
||
|
g.begin();
|
||
|
g.setPipeline(pipeline);
|
||
|
g.setVertexBuffer(vb);
|
||
|
g.setIndexBuffer(ib);
|
||
|
var matrixLocation: ConstantLocation = pipeline.getConstantLocation("projectionMatrix");
|
||
|
var p: FastMatrix4 = FastMatrix4.identity();
|
||
|
g.setMatrix(matrixLocation, p);
|
||
|
var texture: TextureUnit = pipeline.getTextureUnit("tex");
|
||
|
|
||
|
g.setTexture(texture, parms.RightImage.Image);
|
||
|
g.drawIndexedVertices();
|
||
|
|
||
|
// Check for an overlay image
|
||
|
/* if (parms.LeftImage.Image != null) {
|
||
|
g.setTexture(texture, parms.RightOverlay.Image);
|
||
|
g.drawIndexedVertices();
|
||
|
}
|
||
|
*/
|
||
|
g.end();
|
||
|
}
|
||
|
|
||
|
public override function GetTimeInSeconds(): Float {
|
||
|
// TODO: Is it in seconds?
|
||
|
return System.time;
|
||
|
}
|
||
|
|
||
|
var vb: VertexBuffer;
|
||
|
var ib: IndexBuffer;
|
||
|
|
||
|
var pipeline: PipelineState;
|
||
|
|
||
|
function setVertex(a: Float32Array, index: Int, pos: Vector3, uv: Vector2, color: Vector4) {
|
||
|
var base: Int = index * 9;
|
||
|
a.set(base + 0, pos.x);
|
||
|
a.set(base + 1, pos.y);
|
||
|
a.set(base + 2, pos.z);
|
||
|
base += 3;
|
||
|
a.set(base + 0, uv.x);
|
||
|
a.set(base + 1, uv.y);
|
||
|
base += 2;
|
||
|
a.set(base + 0, color.x);
|
||
|
a.set(base + 1, color.y);
|
||
|
a.set(base + 2, color.z);
|
||
|
a.set(base + 3, color.w);
|
||
|
}
|
||
|
|
||
|
public function new() {
|
||
|
super();
|
||
|
|
||
|
Gamepad.get(0).notify(axisEvent, buttonEvent);
|
||
|
Keyboard.get(0).notify(keyDownEvent, keyUpEvent);
|
||
|
Mouse.get(0).notify(mouseButtonDownEvent, mouseButtonUpEvent, mouseMoveEvent, null);
|
||
|
|
||
|
var structure: VertexStructure = new VertexStructure();
|
||
|
|
||
|
orientation = new Quaternion();
|
||
|
updateOrientation();
|
||
|
|
||
|
structure.add("vertexPosition", VertexData.Float32_3X);
|
||
|
structure.add("vertexUV", VertexData.Float32_2X);
|
||
|
structure.add("vertexColor", VertexData.Float32_4X);
|
||
|
|
||
|
vb = new VertexBuffer(4, structure, Usage.StaticUsage);
|
||
|
var verts = vb.lock();
|
||
|
|
||
|
setVertex(verts, 0, new Vector3(-1, -1, 0), new Vector2(0, 0), new Vector4(1, 1, 1, 1));
|
||
|
setVertex(verts, 1, new Vector3(-1, 1, 0), new Vector2(0, 1), new Vector4(1, 1, 1, 1));
|
||
|
setVertex(verts, 2, new Vector3(1, -1, 0), new Vector2(1, 0), new Vector4(1, 1, 1, 1));
|
||
|
setVertex(verts, 3, new Vector3(1, 1, 0), new Vector2(1, 1), new Vector4(1, 1, 1, 1));
|
||
|
|
||
|
vb.unlock();
|
||
|
|
||
|
ib = new IndexBuffer(6, Usage.StaticUsage);
|
||
|
var indices = ib.lock();
|
||
|
|
||
|
indices[0] = 0;
|
||
|
indices[1] = 1;
|
||
|
indices[2] = 2;
|
||
|
indices[3] = 1;
|
||
|
indices[4] = 3;
|
||
|
indices[5] = 2;
|
||
|
|
||
|
ib.unlock();
|
||
|
|
||
|
pipeline = new PipelineState();
|
||
|
|
||
|
pipeline.vertexShader = Shaders.painter_image_vert;
|
||
|
pipeline.fragmentShader = Shaders.painter_image_frag;
|
||
|
pipeline.inputLayout = [structure];
|
||
|
pipeline.compile();
|
||
|
}
|
||
|
}
|