Update Files
This commit is contained in:
15
Kha/Sources/kha/vr/Pose.hx
Normal file
15
Kha/Sources/kha/vr/Pose.hx
Normal file
@ -0,0 +1,15 @@
|
||||
package kha.vr;
|
||||
|
||||
import kha.math.Quaternion;
|
||||
import kha.math.Vector3;
|
||||
|
||||
// Position and orientation together.
|
||||
class Pose {
|
||||
public var Orientation: Quaternion;
|
||||
public var Position: Vector3;
|
||||
|
||||
public function new() {
|
||||
Orientation = new Quaternion();
|
||||
Position = new Vector3();
|
||||
}
|
||||
}
|
16
Kha/Sources/kha/vr/PoseState.hx
Normal file
16
Kha/Sources/kha/vr/PoseState.hx
Normal file
@ -0,0 +1,16 @@
|
||||
package kha.vr;
|
||||
|
||||
import kha.math.Vector3;
|
||||
|
||||
// Full pose (rigid body) configuration with first and second derivatives.
|
||||
class PoseState {
|
||||
public var Pose: Pose;
|
||||
|
||||
public var AngularVelocity: Vector3;
|
||||
public var LinearVelocity: Vector3;
|
||||
public var AngularAcceleration: Vector3;
|
||||
public var LinearAcceleration: Vector3;
|
||||
public var TimeInSeconds: Float; // Absolute time of this state sample.
|
||||
|
||||
public function new() {}
|
||||
}
|
20
Kha/Sources/kha/vr/SensorState.hx
Normal file
20
Kha/Sources/kha/vr/SensorState.hx
Normal file
@ -0,0 +1,20 @@
|
||||
package kha.vr;
|
||||
|
||||
// State of the sensor at a given absolute time.
|
||||
class SensorState {
|
||||
// Predicted pose configuration at requested absolute time.
|
||||
// One can determine the time difference between predicted and actual
|
||||
// readings by comparing ovrPoseState.TimeInSeconds.
|
||||
public var Predicted: PoseState;
|
||||
|
||||
// Actual recorded pose configuration based on the sensor sample at a
|
||||
// moment closest to the requested time.
|
||||
public var Recorded: PoseState;
|
||||
|
||||
// Sensor temperature reading, in degrees Celsius, as sample time.
|
||||
public var Temperature: Float;
|
||||
// Sensor status described by ovrStatusBits.
|
||||
public var Status: Int;
|
||||
|
||||
public function new() {}
|
||||
}
|
38
Kha/Sources/kha/vr/TimeWarpImage.hx
Normal file
38
Kha/Sources/kha/vr/TimeWarpImage.hx
Normal file
@ -0,0 +1,38 @@
|
||||
package kha.vr;
|
||||
|
||||
import kha.Image;
|
||||
import kha.math.Matrix4;
|
||||
|
||||
class TimeWarpImage {
|
||||
// If TexId == 0, this image is disabled.
|
||||
// Most applications will have the overlay image
|
||||
// disabled.
|
||||
//
|
||||
// Because OpenGL ES doesn't support clampToBorder,
|
||||
// it is the application's responsibility to make sure
|
||||
// that all mip levels of the texture have a black border
|
||||
// that will show up when time warp pushes the texture partially
|
||||
// off screen.
|
||||
//
|
||||
// Overlap textures will only show through where alpha on the
|
||||
// primary texture is not 1.0, so they do not require a border.
|
||||
// unsigned TexId;
|
||||
public var Image: Image;
|
||||
|
||||
// Experimental separate R/G/B cube maps
|
||||
// unsigned PlanarTexId[3];
|
||||
// Points on the screen are mapped by a distortion correction
|
||||
// function into ( TanX, TanY, 1, 1 ) vectors that are transformed
|
||||
// by this matrix to get ( S, T, Q, _ ) vectors that are looked
|
||||
// up with texture2dproj() to get texels.
|
||||
public var TexCoordsFromTanAngles: Matrix4;
|
||||
|
||||
// The sensor state for which ModelViewMatrix is correct.
|
||||
// It is ok to update the orientation for each eye, which
|
||||
// can help minimize black edge pull-in, but the position
|
||||
// must remain the same for both eyes, or the position would
|
||||
// seem to judder "backwards in time" if a frame is dropped.
|
||||
public var Pose: PoseState;
|
||||
|
||||
public function new() {}
|
||||
}
|
46
Kha/Sources/kha/vr/TimeWarpParms.hx
Normal file
46
Kha/Sources/kha/vr/TimeWarpParms.hx
Normal file
@ -0,0 +1,46 @@
|
||||
package kha.vr;
|
||||
|
||||
class TimeWarpParms {
|
||||
/*TimeWarpParms() : SwapOptions( 0 ),
|
||||
MinimumVsyncs( 1 ),
|
||||
PreScheduleSeconds( 0.014f ),
|
||||
WarpProgram( WP_SIMPLE ),
|
||||
ProgramParms(),
|
||||
DebugGraphMode( DEBUG_PERF_OFF ),
|
||||
DebugGraphValue( DEBUG_VALUE_DRAW )
|
||||
{
|
||||
for ( int i = 0; i < 4; i++ ) { // this should be unnecessary, remove?
|
||||
for ( int j = 0; j < 4; j++ ) {
|
||||
ExternalVelocity.M[i][j] = ( i == j ) ? 1.0f : 0.0f;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
public var LeftImage: TimeWarpImage;
|
||||
public var RightImage: TimeWarpImage;
|
||||
|
||||
public var LeftOverlay: TimeWarpImage;
|
||||
public var RightOverlay: TimeWarpImage;
|
||||
|
||||
// static const int MAX_WARP_EYES = 2;
|
||||
// static const int MAX_WARP_IMAGES = 2; // 0 = world, 1 = overlay screen
|
||||
// TimeWarpImage Images[MAX_WARP_EYES][MAX_WARP_IMAGES];
|
||||
// public var SwapOptions: Int;
|
||||
// WarpSwap will not return until at least this many vsyncs have
|
||||
// passed since the previous WarpSwap returned.
|
||||
// Setting to 2 will reduce power consumption and may make animation
|
||||
// more regular for applications that can't hold full frame rate.
|
||||
// public var MinimumVsyncs: Int;
|
||||
// Time in seconds to start drawing before each slice.
|
||||
// Clamped at 0.014 high and 0.002 low, but the very low
|
||||
// values will usually result in screen tearing.
|
||||
// public var PreScheduleSeconds: Float;
|
||||
// Which program to run with these images.
|
||||
// warpProgram_t WarpProgram;
|
||||
// Program-specific tuning values.
|
||||
// float ProgramParms[4];
|
||||
// Controls the collection and display of timing data.
|
||||
// debugPerfMode_t DebugGraphMode;
|
||||
// debugPerfValue_t DebugGraphValue;
|
||||
|
||||
public function new() {}
|
||||
}
|
63
Kha/Sources/kha/vr/VrInterface.hx
Normal file
63
Kha/Sources/kha/vr/VrInterface.hx
Normal file
@ -0,0 +1,63 @@
|
||||
package kha.vr;
|
||||
|
||||
import kha.math.FastMatrix4;
|
||||
|
||||
class VrInterface {
|
||||
public static var instance: VrInterface;
|
||||
|
||||
// Returns the current sensor state
|
||||
public function GetSensorState(): SensorState {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Returns the predicted sensor state at the specified time
|
||||
public function GetPredictedSensorState(time: Float): SensorState {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Sends a black image to the warp swap thread
|
||||
public function WarpSwapBlack(): Void {}
|
||||
|
||||
// Sends the Oculus loading symbol to the warp swap thread
|
||||
public function WarpSwapLoadingIcon(): Void {}
|
||||
|
||||
// Sends the set of images to the warp swap thread
|
||||
public function WarpSwap(parms: TimeWarpParms): Void {}
|
||||
|
||||
// Return true if VR displays are presenting
|
||||
public function IsPresenting(): Bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if any VR devices connected to the computer are available
|
||||
public function IsVrEnabled(): Bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This returns the time that the TimeWarp thread uses
|
||||
// Since it is created from the library's vsync counting code, we should use this
|
||||
public function GetTimeInSeconds(): Float {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Returns projection to be used for the left or right eye’s rendering
|
||||
public function GetProjectionMatrix(eye: Int): FastMatrix4 {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Returns view transformation to be used for the left or right eye’s rendering
|
||||
public function GetViewMatrix(eye: Int): FastMatrix4 {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Browsers will only allow to enter WebVR if requestPresent is called in response to user interaction.
|
||||
public function onVRRequestPresent(): Void {}
|
||||
|
||||
// Exit WebVR
|
||||
public function onVRExitPresent(): Void {}
|
||||
|
||||
// Reset position and orientation
|
||||
public function onResetPose(): Void {}
|
||||
|
||||
function new() {}
|
||||
}
|
286
Kha/Sources/kha/vr/VrInterfaceEmulated.hx
Normal file
286
Kha/Sources/kha/vr/VrInterfaceEmulated.hx
Normal file
@ -0,0 +1,286 @@
|
||||
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();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user