forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			234 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			234 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
| 
								 | 
							
								package iron.object;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import kha.graphics4.Graphics;
							 | 
						||
| 
								 | 
							
								import kha.graphics4.CubeMap;
							 | 
						||
| 
								 | 
							
								import iron.Scene;
							 | 
						||
| 
								 | 
							
								import iron.RenderPath;
							 | 
						||
| 
								 | 
							
								import iron.math.Mat4;
							 | 
						||
| 
								 | 
							
								import iron.math.Vec4;
							 | 
						||
| 
								 | 
							
								import iron.math.Quat;
							 | 
						||
| 
								 | 
							
								import iron.data.CameraData;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CameraObject extends Object {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public var data: CameraData;
							 | 
						||
| 
								 | 
							
									public var P: Mat4;
							 | 
						||
| 
								 | 
							
									#if lnx_taa
							 | 
						||
| 
								 | 
							
									public var noJitterP = Mat4.identity();
							 | 
						||
| 
								 | 
							
									var frame = 0;
							 | 
						||
| 
								 | 
							
									#end
							 | 
						||
| 
								 | 
							
									public var V: Mat4;
							 | 
						||
| 
								 | 
							
									public var prevV: Mat4 = null;
							 | 
						||
| 
								 | 
							
									public var VP: Mat4;
							 | 
						||
| 
								 | 
							
									public var frustumPlanes: Array<FrustumPlane> = null;
							 | 
						||
| 
								 | 
							
									public var renderTarget: kha.Image = null; // Render camera view to texture
							 | 
						||
| 
								 | 
							
									public var renderTargetCube: CubeMap = null;
							 | 
						||
| 
								 | 
							
									public var currentFace = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									static var temp = new Vec4();
							 | 
						||
| 
								 | 
							
									static var q = new Quat();
							 | 
						||
| 
								 | 
							
									static var sphereCenter = new Vec4();
							 | 
						||
| 
								 | 
							
									static var vcenter = new Vec4();
							 | 
						||
| 
								 | 
							
									static var vup = new Vec4();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function new(data: CameraData) {
							 | 
						||
| 
								 | 
							
										super();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.data = data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										buildProjection();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										V = Mat4.identity();
							 | 
						||
| 
								 | 
							
										VP = Mat4.identity();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (data.raw.frustum_culling) {
							 | 
						||
| 
								 | 
							
											frustumPlanes = [];
							 | 
						||
| 
								 | 
							
											for (i in 0...6) frustumPlanes.push(new FrustumPlane());
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Scene.active.cameras.push(this);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function buildProjection(screenAspect: Null<Float> = null) {
							 | 
						||
| 
								 | 
							
										if (data.raw.ortho != null) {
							 | 
						||
| 
								 | 
							
											P = Mat4.ortho(data.raw.ortho[0], data.raw.ortho[1], data.raw.ortho[2], data.raw.ortho[3], data.raw.near_plane, data.raw.far_plane);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											if (screenAspect == null) screenAspect = iron.App.w() / iron.App.h();
							 | 
						||
| 
								 | 
							
											var aspect = data.raw.aspect != null ? data.raw.aspect : screenAspect;
							 | 
						||
| 
								 | 
							
											P = Mat4.persp(data.raw.fov, aspect, data.raw.near_plane, data.raw.far_plane);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										#if lnx_taa
							 | 
						||
| 
								 | 
							
										noJitterP.setFrom(P);
							 | 
						||
| 
								 | 
							
										#end
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									override public function remove() {
							 | 
						||
| 
								 | 
							
										Scene.active.cameras.remove(this);
							 | 
						||
| 
								 | 
							
										// if (renderTarget != null) renderTarget.unload();
							 | 
						||
| 
								 | 
							
										// if (renderTargetCube != null) renderTargetCube.unload();
							 | 
						||
| 
								 | 
							
										super.remove();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function renderFrame(g: Graphics) {
							 | 
						||
| 
								 | 
							
										#if lnx_taa
							 | 
						||
| 
								 | 
							
										projectionJitter();
							 | 
						||
| 
								 | 
							
										#end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										buildMatrix();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										RenderPath.active.renderFrame(g);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										prevV.setFrom(V);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									#if lnx_taa
							 | 
						||
| 
								 | 
							
									function projectionJitter() {
							 | 
						||
| 
								 | 
							
										var w = RenderPath.active.currentW;
							 | 
						||
| 
								 | 
							
										var h = RenderPath.active.currentH;
							 | 
						||
| 
								 | 
							
										P.setFrom(noJitterP);
							 | 
						||
| 
								 | 
							
										var x = 0.0;
							 | 
						||
| 
								 | 
							
										var y = 0.0;
							 | 
						||
| 
								 | 
							
										if (frame % 2 == 0) {
							 | 
						||
| 
								 | 
							
											x = 0.25;
							 | 
						||
| 
								 | 
							
											y = 0.25;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											x = -0.25;
							 | 
						||
| 
								 | 
							
											y = -0.25;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										P._20 += x / w;
							 | 
						||
| 
								 | 
							
										P._21 += y / h;
							 | 
						||
| 
								 | 
							
										frame++;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									#end
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function buildMatrix() {
							 | 
						||
| 
								 | 
							
										transform.buildMatrix();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Prevent camera matrix scaling
							 | 
						||
| 
								 | 
							
										// TODO: discards position affected by scaled camera parent
							 | 
						||
| 
								 | 
							
										var sc = transform.world.getScale();
							 | 
						||
| 
								 | 
							
										if (sc.x != 1.0 || sc.y != 1.0 || sc.z != 1.0) {
							 | 
						||
| 
								 | 
							
											temp.set(1.0 / sc.x, 1.0 / sc.y, 1.0 / sc.z);
							 | 
						||
| 
								 | 
							
											transform.world.scale(temp);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										V.getInverse(transform.world);
							 | 
						||
| 
								 | 
							
										VP.multmats(P, V);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (data.raw.frustum_culling) {
							 | 
						||
| 
								 | 
							
											buildViewFrustum(VP, frustumPlanes);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// First time setting up previous V, prevents first frame flicker
							 | 
						||
| 
								 | 
							
										if (prevV == null) {
							 | 
						||
| 
								 | 
							
											prevV = Mat4.identity();
							 | 
						||
| 
								 | 
							
											prevV.setFrom(V);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function buildViewFrustum(VP: Mat4, frustumPlanes: Array<FrustumPlane>) {
							 | 
						||
| 
								 | 
							
										// Left plane
							 | 
						||
| 
								 | 
							
										frustumPlanes[0].setComponents(VP._03 + VP._00, VP._13 + VP._10, VP._23 + VP._20, VP._33 + VP._30);
							 | 
						||
| 
								 | 
							
										// Right plane
							 | 
						||
| 
								 | 
							
										frustumPlanes[1].setComponents(VP._03 - VP._00, VP._13 - VP._10, VP._23 - VP._20, VP._33 - VP._30);
							 | 
						||
| 
								 | 
							
										// Top plane
							 | 
						||
| 
								 | 
							
										frustumPlanes[2].setComponents(VP._03 - VP._01, VP._13 - VP._11, VP._23 - VP._21, VP._33 - VP._31);
							 | 
						||
| 
								 | 
							
										// Bottom plane
							 | 
						||
| 
								 | 
							
										frustumPlanes[3].setComponents(VP._03 + VP._01, VP._13 + VP._11, VP._23 + VP._21, VP._33 + VP._31);
							 | 
						||
| 
								 | 
							
										// Near plane
							 | 
						||
| 
								 | 
							
										frustumPlanes[4].setComponents(VP._02, VP._12, VP._22, VP._32);
							 | 
						||
| 
								 | 
							
										// Far plane
							 | 
						||
| 
								 | 
							
										frustumPlanes[5].setComponents(VP._03 - VP._02, VP._13 - VP._12, VP._23 - VP._22, VP._33 - VP._32);
							 | 
						||
| 
								 | 
							
										// Normalize planes
							 | 
						||
| 
								 | 
							
										for (plane in frustumPlanes) plane.normalize();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function sphereInFrustum(frustumPlanes: Array<FrustumPlane>, t: Transform, radiusScale = 1.0, offsetX = 0.0, offsetY = 0.0, offsetZ = 0.0): Bool {
							 | 
						||
| 
								 | 
							
										// Use scale when radius is changing
							 | 
						||
| 
								 | 
							
										var radius = t.radius * radiusScale;
							 | 
						||
| 
								 | 
							
										for (plane in frustumPlanes) {
							 | 
						||
| 
								 | 
							
											sphereCenter.set(t.worldx() + offsetX, t.worldy() + offsetY, t.worldz() + offsetZ);
							 | 
						||
| 
								 | 
							
											// Outside the frustum
							 | 
						||
| 
								 | 
							
											if (plane.distanceToSphere(sphereCenter, radius) + radius * 2 < 0) {
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public static function setCubeFace(m: Mat4, eye: Vec4, face: Int, flip = false) {
							 | 
						||
| 
								 | 
							
										// Set matrix to match cubemap face
							 | 
						||
| 
								 | 
							
										vcenter.setFrom(eye);
							 | 
						||
| 
								 | 
							
										var f = flip ? -1.0 : 1.0;
							 | 
						||
| 
								 | 
							
										switch (face) {
							 | 
						||
| 
								 | 
							
											case 0: // x+
							 | 
						||
| 
								 | 
							
												vcenter.addf(1.0 * f, 0.0, 0.0);
							 | 
						||
| 
								 | 
							
												vup.set(0.0, -1.0 * f, 0.0);
							 | 
						||
| 
								 | 
							
											case 1: // x-
							 | 
						||
| 
								 | 
							
												vcenter.addf(-1.0 * f, 0.0, 0.0);
							 | 
						||
| 
								 | 
							
												vup.set(0.0, -1.0 * f, 0.0);
							 | 
						||
| 
								 | 
							
											case 2: // y+
							 | 
						||
| 
								 | 
							
												vcenter.addf(0.0, 1.0 * f, 0.0);
							 | 
						||
| 
								 | 
							
												vup.set(0.0, 0.0, 1.0 * f);
							 | 
						||
| 
								 | 
							
											case 3: // y-
							 | 
						||
| 
								 | 
							
												vcenter.addf(0.0, -1.0 * f, 0.0);
							 | 
						||
| 
								 | 
							
												vup.set(0.0, 0.0, -1.0 * f);
							 | 
						||
| 
								 | 
							
											case 4: // z+
							 | 
						||
| 
								 | 
							
												vcenter.addf(0.0, 0.0, 1.0 * f);
							 | 
						||
| 
								 | 
							
												vup.set(0.0, -1.0 * f, 0.0);
							 | 
						||
| 
								 | 
							
											case 5: // z-
							 | 
						||
| 
								 | 
							
												vcenter.addf(0.0, 0.0, -1.0 * f);
							 | 
						||
| 
								 | 
							
												vup.set(0.0, -1.0 * f, 0.0);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										m.setLookAt(eye, vcenter, vup);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public inline function right(): Vec4 {
							 | 
						||
| 
								 | 
							
										return new Vec4(transform.local._00, transform.local._01, transform.local._02);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public inline function up(): Vec4 {
							 | 
						||
| 
								 | 
							
										return new Vec4(transform.local._10, transform.local._11, transform.local._12);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public inline function look(): Vec4 {
							 | 
						||
| 
								 | 
							
										return new Vec4(-transform.local._20, -transform.local._21, -transform.local._22);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public inline function rightWorld(): Vec4 {
							 | 
						||
| 
								 | 
							
										return new Vec4(transform.world._00, transform.world._01, transform.world._02);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public inline function upWorld(): Vec4 {
							 | 
						||
| 
								 | 
							
										return new Vec4(transform.world._10, transform.world._11, transform.world._12);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public inline function lookWorld(): Vec4 {
							 | 
						||
| 
								 | 
							
										return new Vec4(-transform.world._20, -transform.world._21, -transform.world._22);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class FrustumPlane {
							 | 
						||
| 
								 | 
							
									public var normal = new Vec4(1.0, 0.0, 0.0);
							 | 
						||
| 
								 | 
							
									public var constant = 0.0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function new() {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function normalize() {
							 | 
						||
| 
								 | 
							
										var inverseNormalLength = 1.0 / normal.length();
							 | 
						||
| 
								 | 
							
										normal.mult(inverseNormalLength);
							 | 
						||
| 
								 | 
							
										constant *= inverseNormalLength;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public function distanceToSphere(sphereCenter: Vec4, sphereRadius: Float): Float {
							 | 
						||
| 
								 | 
							
										return (normal.dot(sphereCenter) + constant) - sphereRadius;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									public inline function setComponents(x: Float, y: Float, z: Float, w: Float) {
							 | 
						||
| 
								 | 
							
										normal.set(x, y, z);
							 | 
						||
| 
								 | 
							
										constant = w;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |