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