Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View 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();
}
}

View 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() {}
}

View 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() {}
}

View 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() {}
}

View 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() {}
}

View 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 eyes rendering
public function GetProjectionMatrix(eye: Int): FastMatrix4 {
return null;
}
// Returns view transformation to be used for the left or right eyes 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() {}
}

View 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();
}
}