| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  | package iron.object; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import haxe.ds.Vector; | 
					
						
							|  |  |  | import kha.graphics4.Graphics; | 
					
						
							|  |  |  | import kha.graphics4.PipelineState; | 
					
						
							|  |  |  | import iron.math.Vec4; | 
					
						
							|  |  |  | import iron.math.Mat4; | 
					
						
							|  |  |  | import iron.data.MeshData; | 
					
						
							|  |  |  | import iron.data.MaterialData; | 
					
						
							|  |  |  | import iron.data.ShaderData; | 
					
						
							|  |  |  | import iron.data.SceneFormat; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MeshObject extends Object { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public var data: MeshData = null; | 
					
						
							|  |  |  | 	public var materials: Vector<MaterialData>; | 
					
						
							|  |  |  | 	public var materialIndex = 0; | 
					
						
							|  |  |  | 	public var depthRead(default, null) = false; | 
					
						
							|  |  |  | 	#if lnx_particles | 
					
						
							|  |  |  | 	public var particleSystems: Array<ParticleSystem> = null; // Particle owner | 
					
						
							|  |  |  | 	public var particleChildren: Array<MeshObject> = null; | 
					
						
							|  |  |  | 	public var particleOwner: MeshObject = null; // Particle object | 
					
						
							|  |  |  | 	public var particleIndex = -1; | 
					
						
							| 
									
										
										
										
											2025-05-22 22:00:56 +00:00
										 |  |  | 	public var render_emitter = true; | 
					
						
							| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  | 	#end | 
					
						
							|  |  |  | 	public var cameraDistance: Float; | 
					
						
							|  |  |  | 	public var screenSize = 0.0; | 
					
						
							|  |  |  | 	public var frustumCulling = true; | 
					
						
							|  |  |  | 	public var activeTilesheet: Tilesheet = null; | 
					
						
							|  |  |  | 	public var tilesheets: Array<Tilesheet> = null; | 
					
						
							|  |  |  | 	public var skip_context: String = null; // Do not draw this context | 
					
						
							|  |  |  | 	public var force_context: String = null; // Draw only this context | 
					
						
							|  |  |  | 	static var lastPipeline: PipelineState = null; | 
					
						
							|  |  |  | 	#if lnx_morph_target | 
					
						
							|  |  |  | 	public var morphTarget: MorphTarget = null; | 
					
						
							|  |  |  | 	#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#if lnx_veloc | 
					
						
							|  |  |  | 	public var prevMatrix = Mat4.identity(); | 
					
						
							|  |  |  | 	#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function new(data: MeshData, materials: Vector<MaterialData>) { | 
					
						
							|  |  |  | 		super(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this.materials = materials; | 
					
						
							|  |  |  | 		setData(data); | 
					
						
							|  |  |  | 		Scene.active.meshes.push(this); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function setData(data: MeshData) { | 
					
						
							|  |  |  | 		this.data = data; | 
					
						
							|  |  |  | 		data.refcount++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		#if (!lnx_batch) | 
					
						
							|  |  |  | 		data.geom.build(); | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Scale-up packed (-1,1) mesh coords | 
					
						
							|  |  |  | 		transform.scaleWorld = data.scalePos; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#if lnx_batch | 
					
						
							|  |  |  | 	@:allow(iron.Scene) | 
					
						
							|  |  |  | 	function batch(isLod: Bool) { | 
					
						
							|  |  |  | 		var batched = Scene.active.meshBatch.addMesh(this, isLod); | 
					
						
							|  |  |  | 		if (!batched) data.geom.build(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	override public function remove() { | 
					
						
							|  |  |  | 		#if lnx_batch | 
					
						
							|  |  |  | 		Scene.active.meshBatch.removeMesh(this); | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 		#if lnx_particles | 
					
						
							|  |  |  | 		if (particleChildren != null) { | 
					
						
							|  |  |  | 			for (c in particleChildren) c.remove(); | 
					
						
							|  |  |  | 			particleChildren = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (particleSystems != null) { | 
					
						
							|  |  |  | 			for (psys in particleSystems) psys.remove(); | 
					
						
							|  |  |  | 			particleSystems = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 		if (activeTilesheet != null) activeTilesheet.remove(); | 
					
						
							|  |  |  | 		if (tilesheets != null) for (ts in tilesheets) { ts.remove(); } | 
					
						
							|  |  |  | 		if (Scene.active != null) Scene.active.meshes.remove(this); | 
					
						
							|  |  |  | 		data.refcount--; | 
					
						
							|  |  |  | 		super.remove(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	override public function setupAnimation(oactions: Array<TSceneFormat> = null) { | 
					
						
							|  |  |  | 		#if lnx_skin | 
					
						
							|  |  |  | 		var hasAction = parent != null && parent.raw != null && parent.raw.bone_actions != null; | 
					
						
							|  |  |  | 		if (hasAction) { | 
					
						
							|  |  |  | 			var armatureUid = parent.uid; | 
					
						
							|  |  |  | 			animation = getBoneAnimation(armatureUid); | 
					
						
							|  |  |  | 			if (animation == null) animation = new BoneAnimation(armatureUid, parent); | 
					
						
							|  |  |  | 			if (data.isSkinned) cast(animation, BoneAnimation).setSkin(this); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 		super.setupAnimation(oactions); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#if lnx_morph_target | 
					
						
							|  |  |  | 	override public function setupMorphTargets() { | 
					
						
							|  |  |  | 		if (data.raw.morph_target != null) { | 
					
						
							|  |  |  | 			morphTarget = new MorphTarget(data.raw.morph_target); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#if lnx_particles | 
					
						
							|  |  |  | 	public function setupParticleSystem(sceneName: String, pref: TParticleReference) { | 
					
						
							|  |  |  | 		if (particleSystems == null) particleSystems = []; | 
					
						
							|  |  |  | 		var psys = new ParticleSystem(sceneName, pref); | 
					
						
							|  |  |  | 		particleSystems.push(psys); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function setupTilesheet(sceneName: String, tilesheet_ref: String, tilesheet_action_ref: String) { | 
					
						
							|  |  |  | 		activeTilesheet = new Tilesheet(sceneName, tilesheet_ref, tilesheet_action_ref); | 
					
						
							|  |  |  | 		if(tilesheets == null) tilesheets = new Array<Tilesheet>(); | 
					
						
							|  |  |  | 		tilesheets.push(activeTilesheet); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function setActiveTilesheet(sceneName: String, tilesheet_ref: String, tilesheet_action_ref: String) { | 
					
						
							|  |  |  | 		var set = false; | 
					
						
							|  |  |  | 		// Check if tilesheet already created | 
					
						
							|  |  |  | 		if (tilesheets != null) { | 
					
						
							|  |  |  | 			for (ts in tilesheets) { | 
					
						
							|  |  |  | 				if (ts.raw.name == tilesheet_ref) { | 
					
						
							|  |  |  | 					activeTilesheet = ts; | 
					
						
							|  |  |  | 					activeTilesheet.play(tilesheet_action_ref); | 
					
						
							|  |  |  | 					set = true; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// If not already created | 
					
						
							|  |  |  | 		if (!set) { | 
					
						
							|  |  |  | 			setupTilesheet(sceneName, tilesheet_ref, tilesheet_action_ref); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inline function isLodMaterial(): Bool { | 
					
						
							|  |  |  | 		return (raw != null && raw.lod_material != null && raw.lod_material == true); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function setCulled(isShadow: Bool, b: Bool): Bool { | 
					
						
							|  |  |  | 		isShadow ? culledShadow = b : culledMesh = b; | 
					
						
							|  |  |  | 		culled = culledMesh && culledShadow; | 
					
						
							|  |  |  | 		#if lnx_debug | 
					
						
							|  |  |  | 		if (b) RenderPath.culled++; | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 		return b; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function cullMaterial(context: String): Bool { | 
					
						
							|  |  |  | 		// Skip render if material does not contain current context | 
					
						
							|  |  |  | 		var mats = materials; | 
					
						
							|  |  |  | 		if (!isLodMaterial() && !validContext(mats, context)) return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var isShadow = context == "shadowmap"; | 
					
						
							|  |  |  | 		if (!visibleMesh && !isShadow) return setCulled(isShadow, true); | 
					
						
							|  |  |  | 		if (!visibleShadow && isShadow) return setCulled(isShadow, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (skip_context == context) return setCulled(isShadow, true); | 
					
						
							|  |  |  | 		if (force_context != null && force_context != context) return setCulled(isShadow, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return setCulled(isShadow, false); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function cullMesh(context: String, camera: CameraObject, light: LightObject): Bool { | 
					
						
							|  |  |  | 		if (camera == null) return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (camera.data.raw.frustum_culling && frustumCulling) { | 
					
						
							|  |  |  | 			// Scale radius for skinned mesh and particle system | 
					
						
							|  |  |  | 			// TODO: define skin & particle bounds | 
					
						
							|  |  |  | 			var radiusScale = data.isSkinned ? 2.0 : 1.0; | 
					
						
							|  |  |  | 			#if lnx_particles | 
					
						
							|  |  |  | 			// particleSystems for update, particleOwner for render | 
					
						
							|  |  |  | 			if (particleSystems != null || particleOwner != null) radiusScale *= 1000; | 
					
						
							|  |  |  | 			#end | 
					
						
							|  |  |  | 			if (context == "voxel") radiusScale *= 100; | 
					
						
							|  |  |  | 			if (data.geom.instanced) radiusScale *= 100; | 
					
						
							|  |  |  | 			var isShadow = context == "shadowmap"; | 
					
						
							|  |  |  | 			var frustumPlanes = isShadow ? light.frustumPlanes : camera.frustumPlanes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (isShadow && light.data.raw.type != "sun") { // Non-sun light bounds intersect camera frustum | 
					
						
							|  |  |  | 				light.transform.radius = light.data.raw.far_plane; | 
					
						
							|  |  |  | 				if (!CameraObject.sphereInFrustum(camera.frustumPlanes, light.transform)) { | 
					
						
							|  |  |  | 					return setCulled(isShadow, true); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!CameraObject.sphereInFrustum(frustumPlanes, transform, radiusScale)) { | 
					
						
							|  |  |  | 				return setCulled(isShadow, true); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		culled = false; | 
					
						
							|  |  |  | 		return culled; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function skipContext(context: String, mat: MaterialData): Bool { | 
					
						
							|  |  |  | 		if (mat.raw.skip_context != null && | 
					
						
							|  |  |  | 			mat.raw.skip_context == context) { | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function getContexts(context: String, materials: Vector<MaterialData>, materialContexts: Array<MaterialContext>, shaderContexts: Array<ShaderContext>) { | 
					
						
							|  |  |  | 		for (mat in materials) { | 
					
						
							|  |  |  | 			var found = false; | 
					
						
							|  |  |  | 			for (i in 0...mat.raw.contexts.length) { | 
					
						
							|  |  |  | 				if (mat.raw.contexts[i].name.substr(0, context.length) == context) { | 
					
						
							|  |  |  | 					materialContexts.push(mat.contexts[i]); | 
					
						
							|  |  |  | 					shaderContexts.push(mat.shader.getContext(context)); | 
					
						
							|  |  |  | 					found = true; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (!found) { | 
					
						
							|  |  |  | 				materialContexts.push(null); | 
					
						
							|  |  |  | 				shaderContexts.push(null); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public function render(g: Graphics, context: String, bindParams: Array<String>) { | 
					
						
							|  |  |  | 		if (data == null || !data.geom.ready) return; // Data not yet streamed | 
					
						
							|  |  |  | 		if (!visible) return; // Skip render if object is hidden | 
					
						
							|  |  |  | 		if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return; | 
					
						
							|  |  |  | 		var meshContext = raw != null ? context == "mesh" : false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		#if lnx_particles | 
					
						
							|  |  |  | 		if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner | 
					
						
							|  |  |  | 		if (particleSystems != null && meshContext) { | 
					
						
							|  |  |  | 			if (particleChildren == null) { | 
					
						
							|  |  |  | 				particleChildren = []; | 
					
						
							|  |  |  | 				for (psys in particleSystems) { | 
					
						
							|  |  |  | 					// var c: MeshObject = cast Scene.active.getChild(psys.data.raw.instance_object); | 
					
						
							|  |  |  | 					Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) { | 
					
						
							|  |  |  | 						if (o != null) { | 
					
						
							|  |  |  | 							var c: MeshObject = cast o; | 
					
						
							|  |  |  | 							particleChildren.push(c); | 
					
						
							|  |  |  | 							c.particleOwner = this; | 
					
						
							|  |  |  | 							c.particleIndex = particleChildren.length - 1; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for (i in 0...particleSystems.length) { | 
					
						
							|  |  |  | 				particleSystems[i].update(particleChildren[i], this); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-05-22 22:00:56 +00:00
										 |  |  | 		if (particleSystems != null && particleSystems.length > 0 && !render_emitter) return; | 
					
						
							|  |  |  |         if (particleSystems == null && cullMaterial(context)) return; | 
					
						
							|  |  |  |         #else | 
					
						
							|  |  |  |         if (cullMaterial(context)) return; | 
					
						
							| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  | 		#end | 
					
						
							|  |  |  | 		// Get lod | 
					
						
							|  |  |  | 		var mats = materials; | 
					
						
							|  |  |  | 		var lod = this; | 
					
						
							|  |  |  | 		if (raw != null && raw.lods != null && raw.lods.length > 0) { | 
					
						
							|  |  |  | 			computeScreenSize(Scene.active.camera); | 
					
						
							|  |  |  | 			initLods(); | 
					
						
							|  |  |  | 			if (context == "voxel") { | 
					
						
							|  |  |  | 				// Voxelize using the lowest lod | 
					
						
							|  |  |  | 				lod = cast lods[lods.length - 1]; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				// Select lod | 
					
						
							|  |  |  | 				for (i in 0...raw.lods.length) { | 
					
						
							|  |  |  | 					// Lod found | 
					
						
							|  |  |  | 					if (screenSize > raw.lods[i].screen_size) break; | 
					
						
							|  |  |  | 					lod = cast lods[i]; | 
					
						
							|  |  |  | 					if (isLodMaterial()) mats = lod.materials; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (lod == null) return; // Empty object | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		#if lnx_debug | 
					
						
							|  |  |  | 		else computeScreenSize(Scene.active.camera); | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 		if (isLodMaterial() && !validContext(mats, context)) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Get context | 
					
						
							|  |  |  | 		var materialContexts: Array<MaterialContext> = []; | 
					
						
							|  |  |  | 		var shaderContexts: Array<ShaderContext> = []; | 
					
						
							|  |  |  | 		getContexts(context, mats, materialContexts, shaderContexts); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Uniforms.posUnpack = data.scalePos; | 
					
						
							|  |  |  | 		Uniforms.texUnpack = data.scaleTex; | 
					
						
							|  |  |  | 		transform.update(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Render mesh | 
					
						
							|  |  |  | 		var ldata = lod.data; | 
					
						
							|  |  |  | 		for (i in 0...ldata.geom.indexBuffers.length) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var mi = ldata.geom.materialIndices[i]; | 
					
						
							|  |  |  | 			if (shaderContexts.length <= mi || shaderContexts[mi] == null) continue; | 
					
						
							|  |  |  | 			materialIndex = mi; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Check context skip | 
					
						
							|  |  |  | 			if (materials.length > mi && skipContext(context, materials[mi])) continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var scontext = shaderContexts[mi]; | 
					
						
							|  |  |  | 			if (scontext == null) continue; | 
					
						
							|  |  |  | 			var elems = scontext.raw.vertex_elements; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Uniforms | 
					
						
							|  |  |  | 			if (scontext.pipeState != lastPipeline) { | 
					
						
							|  |  |  | 				g.setPipeline(scontext.pipeState); | 
					
						
							|  |  |  | 				lastPipeline = scontext.pipeState; | 
					
						
							|  |  |  | 				// Uniforms.setContextConstants(g, scontext, bindParams); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			Uniforms.setContextConstants(g, scontext, bindParams); // | 
					
						
							|  |  |  | 			Uniforms.setObjectConstants(g, scontext, this); | 
					
						
							|  |  |  | 			if (materialContexts.length > mi) { | 
					
						
							|  |  |  | 				Uniforms.setMaterialConstants(g, scontext, materialContexts[mi]); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// VB / IB | 
					
						
							|  |  |  | 			#if lnx_deinterleaved | 
					
						
							|  |  |  | 			g.setVertexBuffers(ldata.geom.get(elems)); | 
					
						
							|  |  |  | 			#else | 
					
						
							|  |  |  | 			if (ldata.geom.instancedVB != null) { | 
					
						
							|  |  |  | 				g.setVertexBuffers([ldata.geom.get(elems), ldata.geom.instancedVB]); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				g.setVertexBuffer(ldata.geom.get(elems)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			g.setIndexBuffer(ldata.geom.indexBuffers[i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Draw | 
					
						
							|  |  |  | 			if (ldata.geom.instanced) { | 
					
						
							|  |  |  | 				g.drawIndexedVerticesInstanced(ldata.geom.instanceCount, ldata.geom.start, ldata.geom.count); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				g.drawIndexedVertices(ldata.geom.start, ldata.geom.count); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		#if lnx_debug | 
					
						
							|  |  |  | 		var isShadow = context == "shadowmap"; | 
					
						
							|  |  |  | 		if (meshContext) RenderPath.numTrisMesh += ldata.geom.numTris; | 
					
						
							|  |  |  | 		else if (isShadow) RenderPath.numTrisShadow += ldata.geom.numTris; | 
					
						
							|  |  |  | 		RenderPath.drawCalls++; | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		#if lnx_veloc | 
					
						
							|  |  |  | 		prevMatrix.setFrom(transform.worldUnpack); | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function validContext(mats: Vector<MaterialData>, context: String): Bool { | 
					
						
							|  |  |  | 		for (mat in mats) if (mat.getContext(context) != null) return true; | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public inline function computeCameraDistance(camX: Float, camY: Float, camZ: Float) { | 
					
						
							|  |  |  | 		// Render path mesh sorting | 
					
						
							|  |  |  | 		cameraDistance = Vec4.distancef(camX, camY, camZ, transform.worldx(), transform.worldy(), transform.worldz()); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public inline function computeDepthRead() { | 
					
						
							|  |  |  | 		#if rp_depth_texture | 
					
						
							|  |  |  | 		depthRead = false; | 
					
						
							|  |  |  | 		for (material in materials) { | 
					
						
							|  |  |  | 			for (context in material.contexts) { | 
					
						
							|  |  |  | 				if (context.raw.depth_read == true) { | 
					
						
							|  |  |  | 					depthRead = true; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		#end | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public inline function computeScreenSize(camera: CameraObject) { | 
					
						
							|  |  |  | 		// Approx.. | 
					
						
							|  |  |  | 		// var rp = camera.renderPath; | 
					
						
							|  |  |  | 		// var screenVolume = rp.currentW * rp.currentH; | 
					
						
							|  |  |  | 		var tr = transform; | 
					
						
							|  |  |  | 		var volume = tr.dim.x * tr.dim.y * tr.dim.z; | 
					
						
							|  |  |  | 		screenSize = volume * (1.0 / cameraDistance); | 
					
						
							|  |  |  | 		screenSize = screenSize > 1.0 ? 1.0 : screenSize; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inline function initLods() { | 
					
						
							|  |  |  | 		if (lods == null) { | 
					
						
							|  |  |  | 			lods = []; | 
					
						
							|  |  |  | 			for (l in raw.lods) { | 
					
						
							|  |  |  | 				if (l.object_ref == "") lods.push(null); // Empty | 
					
						
							|  |  |  | 				else lods.push(Scene.active.getChild(l.object_ref)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |