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