merge upstream
This commit is contained in:
		@ -80,6 +80,7 @@ extern class Krom {
 | 
				
			|||||||
	static function unloadImage(image: kha.Image): Void;
 | 
						static function unloadImage(image: kha.Image): Void;
 | 
				
			||||||
	static function loadSound(file: String): Dynamic;
 | 
						static function loadSound(file: String): Dynamic;
 | 
				
			||||||
	static function writeAudioBuffer(buffer: js.lib.ArrayBuffer, samples: Int): Void;
 | 
						static function writeAudioBuffer(buffer: js.lib.ArrayBuffer, samples: Int): Void;
 | 
				
			||||||
 | 
						static function getSamplesPerSecond(): Int;
 | 
				
			||||||
	static function loadBlob(file: String): js.lib.ArrayBuffer;
 | 
						static function loadBlob(file: String): js.lib.ArrayBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static function init(title: String, width: Int, height: Int, samplesPerPixel: Int, vSync: Bool, windowMode: Int, windowFeatures: Int, kromApi: Int): Void;
 | 
						static function init(title: String, width: Int, height: Int, samplesPerPixel: Int, vSync: Bool, windowMode: Int, windowFeatures: Int, kromApi: Int): Void;
 | 
				
			||||||
@ -115,6 +116,7 @@ extern class Krom {
 | 
				
			|||||||
	static function screenDpi(): Int;
 | 
						static function screenDpi(): Int;
 | 
				
			||||||
	static function systemId(): String;
 | 
						static function systemId(): String;
 | 
				
			||||||
	static function requestShutdown(): Void;
 | 
						static function requestShutdown(): Void;
 | 
				
			||||||
 | 
						static function displayFrequency(): Int;
 | 
				
			||||||
	static function displayCount(): Int;
 | 
						static function displayCount(): Int;
 | 
				
			||||||
	static function displayWidth(index: Int): Int;
 | 
						static function displayWidth(index: Int): Int;
 | 
				
			||||||
	static function displayHeight(index: Int): Int;
 | 
						static function displayHeight(index: Int): Int;
 | 
				
			||||||
 | 
				
			|||||||
@ -79,7 +79,7 @@ class Display {
 | 
				
			|||||||
	public var frequency(get, never): Int;
 | 
						public var frequency(get, never): Int;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function get_frequency(): Int {
 | 
						function get_frequency(): Int {
 | 
				
			||||||
		return 60;
 | 
							return Krom.displayFrequency();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public var pixelsPerInch(get, never): Int;
 | 
						public var pixelsPerInch(get, never): Int;
 | 
				
			||||||
 | 
				
			|||||||
@ -171,8 +171,9 @@ class SystemImpl {
 | 
				
			|||||||
		Krom.setGamepadAxisCallback(gamepadAxisCallback);
 | 
							Krom.setGamepadAxisCallback(gamepadAxisCallback);
 | 
				
			||||||
		Krom.setGamepadButtonCallback(gamepadButtonCallback);
 | 
							Krom.setGamepadButtonCallback(gamepadButtonCallback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		kha.audio2.Audio._init();
 | 
							kha.audio2.Audio.samplesPerSecond = Krom.getSamplesPerSecond();
 | 
				
			||||||
		kha.audio1.Audio._init();
 | 
							kha.audio1.Audio._init();
 | 
				
			||||||
 | 
							kha.audio2.Audio._init();
 | 
				
			||||||
		Krom.setAudioCallback(audioCallback);
 | 
							Krom.setAudioCallback(audioCallback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Scheduler.start();
 | 
							Scheduler.start();
 | 
				
			||||||
@ -207,7 +208,7 @@ class SystemImpl {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static function getRefreshRate(): Int {
 | 
						public static function getRefreshRate(): Int {
 | 
				
			||||||
		return 60;
 | 
							return Krom.displayFrequency();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static function getSystemId(): String {
 | 
						public static function getSystemId(): String {
 | 
				
			||||||
 | 
				
			|||||||
@ -10,8 +10,7 @@ class Audio {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	public static function _init() {
 | 
						public static function _init() {
 | 
				
			||||||
		var bufferSize = 1024 * 2;
 | 
							var bufferSize = 1024 * 2;
 | 
				
			||||||
		buffer = new Buffer(bufferSize * 4, 2, 44100);
 | 
							buffer = new Buffer(bufferSize * 4, 2, samplesPerSecond);
 | 
				
			||||||
		Audio.samplesPerSecond = 44100;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static function _callCallback(samples: Int): Void {
 | 
						public static function _callCallback(samples: Int): Void {
 | 
				
			||||||
@ -32,11 +31,11 @@ class Audio {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static function _readSample(): Float {
 | 
						public static function _readSample(): FastFloat {
 | 
				
			||||||
		if (buffer == null)
 | 
							if (buffer == null)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		var value = buffer.data.get(buffer.readLocation);
 | 
							var value = buffer.data.get(buffer.readLocation);
 | 
				
			||||||
		buffer.readLocation += 1;
 | 
							++buffer.readLocation;
 | 
				
			||||||
		if (buffer.readLocation >= buffer.size) {
 | 
							if (buffer.readLocation >= buffer.size) {
 | 
				
			||||||
			buffer.readLocation = 0;
 | 
								buffer.readLocation = 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,7 @@ class Graphics implements kha.graphics4.Graphics {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function refreshRate(): Int {
 | 
						public function refreshRate(): Int {
 | 
				
			||||||
		return 60;
 | 
							return Krom.displayFrequency();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function clear(?color: Color, ?depth: Float, ?stencil: Int): Void {
 | 
						public function clear(?color: Color, ?depth: Float, ?stencil: Int): Void {
 | 
				
			||||||
 | 
				
			|||||||
@ -51,7 +51,7 @@ class Scheduler {
 | 
				
			|||||||
	static var vsync: Bool;
 | 
						static var vsync: Bool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Html5 target can update display frequency after some delay
 | 
						// Html5 target can update display frequency after some delay
 | 
				
			||||||
	#if kha_html5
 | 
						#if (kha_html5 || kha_debug_html5)
 | 
				
			||||||
	static var onedifhz(get, never): Float;
 | 
						static var onedifhz(get, never): Float;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static inline function get_onedifhz(): Float {
 | 
						static inline function get_onedifhz(): Float {
 | 
				
			||||||
@ -97,7 +97,7 @@ class Scheduler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	public static function start(restartTimers: Bool = false): Void {
 | 
						public static function start(restartTimers: Bool = false): Void {
 | 
				
			||||||
		vsync = Window.get(0).vSynced;
 | 
							vsync = Window.get(0).vSynced;
 | 
				
			||||||
		#if !kha_html5
 | 
							#if !(kha_html5 || kha_debug_html5)
 | 
				
			||||||
		var hz = Display.primary != null ? Display.primary.frequency : 60;
 | 
							var hz = Display.primary != null ? Display.primary.frequency : 60;
 | 
				
			||||||
		if (hz >= 57 && hz <= 63)
 | 
							if (hz >= 57 && hz <= 63)
 | 
				
			||||||
			hz = 60;
 | 
								hz = 60;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								Krom/Krom.exe
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Krom/Krom.exe
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@ -310,9 +310,9 @@ class LeenkxAddonPreferences(AddonPreferences):
 | 
				
			|||||||
        layout.label(text="Welcome to Leenkx!")
 | 
					        layout.label(text="Welcome to Leenkx!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Compare version Blender and Leenkx (major, minor)
 | 
					        # Compare version Blender and Leenkx (major, minor)
 | 
				
			||||||
        if bpy.app.version[0] != 4 or bpy.app.version[1] != 2:
 | 
					        if bpy.app.version[:2] not in [(4, 4), (4, 2), (3, 6), (3, 3)]:
 | 
				
			||||||
            box = layout.box().column()
 | 
					            box = layout.box().column()
 | 
				
			||||||
            box.label(text="Warning: For Leenkx to work correctly, use a Blender LTS version such as 4.2 | 3.6 | 3.3")
 | 
					            box.label(text="Warning: For Leenkx to work correctly, use a Blender LTS version")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        layout.prop(self, "sdk_path")
 | 
					        layout.prop(self, "sdk_path")
 | 
				
			||||||
        sdk_path = get_sdk_path(context)
 | 
					        sdk_path = get_sdk_path(context)
 | 
				
			||||||
 | 
				
			|||||||
@ -51,6 +51,7 @@ class ParticleSystem {
 | 
				
			|||||||
		seed = pref.seed;
 | 
							seed = pref.seed;
 | 
				
			||||||
		particles = [];
 | 
							particles = [];
 | 
				
			||||||
		ready = false;
 | 
							ready = false;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		Data.getParticle(sceneName, pref.particle, function(b: ParticleData) {
 | 
							Data.getParticle(sceneName, pref.particle, function(b: ParticleData) {
 | 
				
			||||||
			data = b;
 | 
								data = b;
 | 
				
			||||||
			r = data.raw;
 | 
								r = data.raw;
 | 
				
			||||||
@ -70,7 +71,13 @@ class ParticleSystem {
 | 
				
			|||||||
			lifetime = r.lifetime / frameRate;
 | 
								lifetime = r.lifetime / frameRate;
 | 
				
			||||||
			animtime = (r.frame_end - r.frame_start) / frameRate;
 | 
								animtime = (r.frame_end - r.frame_start) / frameRate;
 | 
				
			||||||
			spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate;
 | 
								spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate;
 | 
				
			||||||
			for (i in 0...r.count) particles.push(new Particle(i));
 | 
					
 | 
				
			||||||
 | 
								for (i in 0...r.count) {
 | 
				
			||||||
 | 
									var particle = new Particle(i);
 | 
				
			||||||
 | 
									particle.sr = 1 - Math.random() * r.size_random;
 | 
				
			||||||
 | 
									particles.push(particle);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ready = true;
 | 
								ready = true;
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -108,7 +115,7 @@ class ParticleSystem {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Animate
 | 
							// Animate
 | 
				
			||||||
		time += Time.realDelta * speed;
 | 
							time += Time.delta * speed;
 | 
				
			||||||
		lap = Std.int(time / animtime);
 | 
							lap = Std.int(time / animtime);
 | 
				
			||||||
		lapTime = time - lap * animtime;
 | 
							lapTime = time - lap * animtime;
 | 
				
			||||||
		count = Std.int(lapTime / spawnRate);
 | 
							count = Std.int(lapTime / spawnRate);
 | 
				
			||||||
@ -143,7 +150,7 @@ class ParticleSystem {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function setupGeomGpu(object: MeshObject, owner: MeshObject) {
 | 
						function setupGeomGpu(object: MeshObject, owner: MeshObject) {
 | 
				
			||||||
		var instancedData = new Float32Array(particles.length * 3);
 | 
							var instancedData = new Float32Array(particles.length * 6);
 | 
				
			||||||
		var i = 0;
 | 
							var i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var normFactor = 1 / 32767; // pa.values are not normalized
 | 
							var normFactor = 1 / 32767; // pa.values are not normalized
 | 
				
			||||||
@ -162,6 +169,10 @@ class ParticleSystem {
 | 
				
			|||||||
					instancedData.set(i, pa.values[j * pa.size    ] * normFactor * scaleFactor.x); i++;
 | 
										instancedData.set(i, pa.values[j * pa.size    ] * normFactor * scaleFactor.x); i++;
 | 
				
			||||||
					instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
 | 
										instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
 | 
				
			||||||
					instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
 | 
										instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case 1: // Face
 | 
								case 1: // Face
 | 
				
			||||||
@ -185,6 +196,10 @@ class ParticleSystem {
 | 
				
			|||||||
					instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
 | 
										instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
 | 
				
			||||||
					instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
 | 
										instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
 | 
				
			||||||
					instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
 | 
										instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case 2: // Volume
 | 
								case 2: // Volume
 | 
				
			||||||
@ -195,9 +210,13 @@ class ParticleSystem {
 | 
				
			|||||||
					instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.x); i++;
 | 
										instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.x); i++;
 | 
				
			||||||
					instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
 | 
										instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
 | 
				
			||||||
					instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
 | 
										instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
 | 
										instancedData.set(i, p.sr); i++;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		object.data.geom.setupInstanced(instancedData, 1, Usage.StaticUsage);
 | 
							object.data.geom.setupInstanced(instancedData, 3, Usage.StaticUsage);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function fhash(n: Int): Float {
 | 
						function fhash(n: Int): Float {
 | 
				
			||||||
@ -236,9 +255,10 @@ class ParticleSystem {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Particle {
 | 
					class Particle {
 | 
				
			||||||
	public var i: Int;
 | 
						public var i: Int;
 | 
				
			||||||
	public var x = 0.0;
 | 
						public var px = 0.0;
 | 
				
			||||||
	public var y = 0.0;
 | 
						public var py = 0.0;
 | 
				
			||||||
	public var z = 0.0;
 | 
						public var pz = 0.0;
 | 
				
			||||||
 | 
						public var sr = 1.0; // Size random
 | 
				
			||||||
	public var cameraDistance: Float;
 | 
						public var cameraDistance: Float;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function new(i: Int) {
 | 
						public function new(i: Int) {
 | 
				
			||||||
 | 
				
			|||||||
@ -2,9 +2,11 @@ package leenkx.logicnode;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import iron.object.Object;
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if lnx_physics
 | 
					#if lnx_bullet
 | 
				
			||||||
import leenkx.trait.physics.PhysicsConstraint;
 | 
					import leenkx.trait.physics.PhysicsConstraint;
 | 
				
			||||||
import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintType;
 | 
					import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintType;
 | 
				
			||||||
 | 
					#elseif lnx_oimo
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AddPhysicsConstraintNode extends LogicNode {
 | 
					class AddPhysicsConstraintNode extends LogicNode {
 | 
				
			||||||
@ -25,7 +27,7 @@ class AddPhysicsConstraintNode extends LogicNode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (pivotObject == null || rb1 == null || rb2 == null) return;
 | 
							if (pivotObject == null || rb1 == null || rb2 == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if lnx_physics
 | 
					#if lnx_bullet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var disableCollisions: Bool = inputs[4].get();
 | 
							var disableCollisions: Bool = inputs[4].get();
 | 
				
			||||||
		var breakable: Bool = inputs[5].get();
 | 
							var breakable: Bool = inputs[5].get();
 | 
				
			||||||
@ -108,6 +110,8 @@ class AddPhysicsConstraintNode extends LogicNode {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			pivotObject.addTrait(con);
 | 
								pivotObject.addTrait(con);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					#elseif lnx_oimo
 | 
				
			||||||
 | 
					// TODO
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
		runOutput(0);
 | 
							runOutput(0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ import iron.object.Object;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if lnx_physics
 | 
					#if lnx_physics
 | 
				
			||||||
import leenkx.trait.physics.RigidBody;
 | 
					import leenkx.trait.physics.RigidBody;
 | 
				
			||||||
import leenkx.trait.physics.bullet.RigidBody.Shape;
 | 
					import leenkx.trait.physics.RigidBody.Shape;
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										26
									
								
								leenkx/Sources/leenkx/logicnode/ArrayIndexListNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								leenkx/Sources/leenkx/logicnode/ArrayIndexListNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ArrayIndexListNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
							var array: Array<Dynamic> = inputs[0].get();
 | 
				
			||||||
 | 
							array = array.map(item -> Std.string(item));
 | 
				
			||||||
 | 
							var value: Dynamic = inputs[1].get();
 | 
				
			||||||
 | 
							var from: Int = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var arrayList: Array<Int> = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var index: Int = array.indexOf(Std.string(value), from);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while(index != -1){
 | 
				
			||||||
 | 
								arrayList.push(index);
 | 
				
			||||||
 | 
								index = array.indexOf(Std.string(value), index+1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return arrayList;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
package leenkx.logicnode;
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if lnx_physics
 | 
					#if lnx_physics
 | 
				
			||||||
import leenkx.trait.physics.bullet.PhysicsWorld;
 | 
					import leenkx.trait.physics.PhysicsWorld;
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
import leenkx.trait.navigation.Navigation;
 | 
					import leenkx.trait.navigation.Navigation;
 | 
				
			||||||
import iron.object.Object;
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
package leenkx.logicnode;
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if lnx_physics
 | 
					#if lnx_physics
 | 
				
			||||||
import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintAxis;
 | 
					import leenkx.trait.physics.PhysicsConstraint.ConstraintAxis;
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PhysicsConstraintNode extends LogicNode {
 | 
					class PhysicsConstraintNode extends LogicNode {
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,10 @@ class KinematicCharacterController extends iron.Trait { public function new() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	typedef KinematicCharacterController = leenkx.trait.physics.bullet.KinematicCharacterController;
 | 
						typedef KinematicCharacterController = leenkx.trait.physics.bullet.KinematicCharacterController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						typedef KinematicCharacterController = leenkx.trait.physics.oimo.KinematicCharacterController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#end
 | 
						#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
 | 
				
			|||||||
@ -3,17 +3,16 @@ package leenkx.trait.physics;
 | 
				
			|||||||
#if (!lnx_physics)
 | 
					#if (!lnx_physics)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PhysicsConstraint extends iron.Trait { public function new() { super(); } }
 | 
					class PhysicsConstraint extends iron.Trait { public function new() { super(); } }
 | 
				
			||||||
 | 
					@:enum abstract ConstraintAxis(Int) from Int to Int { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#if lnx_bullet
 | 
						#if lnx_bullet
 | 
				
			||||||
 | 
					 | 
				
			||||||
	typedef PhysicsConstraint = leenkx.trait.physics.bullet.PhysicsConstraint;
 | 
						typedef PhysicsConstraint = leenkx.trait.physics.bullet.PhysicsConstraint;
 | 
				
			||||||
 | 
						typedef ConstraintAxis = leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintAxis;
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
 | 
					 | 
				
			||||||
	typedef PhysicsConstraint = leenkx.trait.physics.oimo.PhysicsConstraint;
 | 
						typedef PhysicsConstraint = leenkx.trait.physics.oimo.PhysicsConstraint;
 | 
				
			||||||
 | 
						typedef ConstraintAxis = leenkx.trait.physics.oimo.PhysicsConstraint.ConstraintAxis;
 | 
				
			||||||
	#end
 | 
						#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ package leenkx.trait.physics;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if (!lnx_physics)
 | 
					#if (!lnx_physics)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Hit { }
 | 
				
			||||||
class PhysicsWorld extends iron.Trait { public function new() { super(); } }
 | 
					class PhysicsWorld extends iron.Trait { public function new() { super(); } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
@ -9,11 +10,11 @@ class PhysicsWorld extends iron.Trait { public function new() { super(); } }
 | 
				
			|||||||
	#if lnx_bullet
 | 
						#if lnx_bullet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	typedef PhysicsWorld = leenkx.trait.physics.bullet.PhysicsWorld;
 | 
						typedef PhysicsWorld = leenkx.trait.physics.bullet.PhysicsWorld;
 | 
				
			||||||
 | 
						typedef Hit = leenkx.trait.physics.bullet.PhysicsWorld.Hit;
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	typedef PhysicsWorld = leenkx.trait.physics.oimo.PhysicsWorld;
 | 
						typedef PhysicsWorld = leenkx.trait.physics.oimo.PhysicsWorld;
 | 
				
			||||||
 | 
						typedef Hit = leenkx.trait.physics.oimo.PhysicsWorld.Hit;
 | 
				
			||||||
	#end
 | 
						#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
 | 
				
			|||||||
@ -3,16 +3,19 @@ package leenkx.trait.physics;
 | 
				
			|||||||
#if (!lnx_physics)
 | 
					#if (!lnx_physics)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RigidBody extends iron.Trait { public function new() { super(); } }
 | 
					class RigidBody extends iron.Trait { public function new() { super(); } }
 | 
				
			||||||
 | 
					@:enum abstract Shape(Int) from Int to Int { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#if lnx_bullet
 | 
						#if lnx_bullet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	typedef RigidBody = leenkx.trait.physics.bullet.RigidBody;
 | 
						typedef RigidBody = leenkx.trait.physics.bullet.RigidBody;
 | 
				
			||||||
 | 
						typedef Shape = leenkx.trait.physics.bullet.RigidBody.Shape;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	typedef RigidBody = leenkx.trait.physics.oimo.RigidBody;
 | 
						typedef RigidBody = leenkx.trait.physics.oimo.RigidBody;
 | 
				
			||||||
 | 
						typedef Shape = leenkx.trait.physics.oimo.RigidBody.Shape;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	#end
 | 
						#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,8 @@
 | 
				
			|||||||
package leenkx.trait.physics.bullet;
 | 
					package leenkx.trait.physics.bullet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if lnx_bullet
 | 
				
			||||||
 | 
					import leenkx.trait.physics.bullet.PhysicsWorld.DebugDrawMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bullet.Bt.Vector3;
 | 
					import bullet.Bt.Vector3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import kha.FastFloat;
 | 
					import kha.FastFloat;
 | 
				
			||||||
@ -18,15 +21,21 @@ class DebugDrawHelper {
 | 
				
			|||||||
	static inline var contactPointNormalColor = 0xffffffff;
 | 
						static inline var contactPointNormalColor = 0xffffffff;
 | 
				
			||||||
	static inline var contactPointDrawLifetime = true;
 | 
						static inline var contactPointDrawLifetime = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						final rayCastColor: Vec4 = new Vec4(0.0, 1.0, 0.0);
 | 
				
			||||||
 | 
						final rayCastHitColor: Vec4 = new Vec4(1.0, 0.0, 0.0);
 | 
				
			||||||
 | 
						final rayCastHitPointColor: Vec4 = new Vec4(1.0, 1.0, 0.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	final physicsWorld: PhysicsWorld;
 | 
						final physicsWorld: PhysicsWorld;
 | 
				
			||||||
	final lines: Array<LineData> = [];
 | 
						final lines: Array<LineData> = [];
 | 
				
			||||||
	final texts: Array<TextData> = [];
 | 
						final texts: Array<TextData> = [];
 | 
				
			||||||
	var font: kha.Font = null;
 | 
						var font: kha.Font = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var debugMode: PhysicsWorld.DebugDrawMode = NoDebug;
 | 
						var rayCasts:Array<TRayCastData> = [];
 | 
				
			||||||
 | 
						var debugDrawMode: DebugDrawMode = NoDebug;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function new(physicsWorld: PhysicsWorld) {
 | 
						public function new(physicsWorld: PhysicsWorld, debugDrawMode: DebugDrawMode) {
 | 
				
			||||||
		this.physicsWorld = physicsWorld;
 | 
							this.physicsWorld = physicsWorld;
 | 
				
			||||||
 | 
							this.debugDrawMode = debugDrawMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#if lnx_ui
 | 
							#if lnx_ui
 | 
				
			||||||
		iron.data.Data.getFont(Canvas.defaultFontName, function(defaultFont: kha.Font) {
 | 
							iron.data.Data.getFont(Canvas.defaultFontName, function(defaultFont: kha.Font) {
 | 
				
			||||||
@ -35,6 +44,11 @@ class DebugDrawHelper {
 | 
				
			|||||||
		#end
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		iron.App.notifyOnRender2D(onRender);
 | 
							iron.App.notifyOnRender2D(onRender);
 | 
				
			||||||
 | 
							if (debugDrawMode & DrawRayCast != 0) {
 | 
				
			||||||
 | 
								iron.App.notifyOnUpdate(function () {
 | 
				
			||||||
 | 
									rayCasts.resize(0);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function drawLine(from: bullet.Bt.Vector3, to: bullet.Bt.Vector3, color: bullet.Bt.Vector3) {
 | 
						public function drawLine(from: bullet.Bt.Vector3, to: bullet.Bt.Vector3, color: bullet.Bt.Vector3) {
 | 
				
			||||||
@ -63,25 +77,6 @@ class DebugDrawHelper {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Draws raycast in its own function because 
 | 
					 | 
				
			||||||
	// something is conflicting with the btVector3 and JS pointer wrapping
 | 
					 | 
				
			||||||
	public function drawRayCast(fx:FastFloat, fy:FastFloat, fz:FastFloat, tx:FastFloat, ty:FastFloat, tz:FastFloat, r:FastFloat, g:FastFloat, b:FastFloat) {
 | 
					 | 
				
			||||||
		final fromScreenSpace = worldToScreenFast(new Vec4(fx, fy, fz, 1.0));
 | 
					 | 
				
			||||||
		final toScreenSpace = worldToScreenFast(new Vec4(tx, ty, tz, 1.0));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// TO DO: May still go off screen sides.
 | 
					 | 
				
			||||||
		if (fromScreenSpace.w == 1 || toScreenSpace.w == 1) {
 | 
					 | 
				
			||||||
			final color = kha.Color.fromFloats(r, g, b, 1.0);
 | 
					 | 
				
			||||||
			lines.push({
 | 
					 | 
				
			||||||
				fromX: fromScreenSpace.x,
 | 
					 | 
				
			||||||
				fromY: fromScreenSpace.y,
 | 
					 | 
				
			||||||
				toX: toScreenSpace.x,
 | 
					 | 
				
			||||||
				toY: toScreenSpace.y,
 | 
					 | 
				
			||||||
				color: color
 | 
					 | 
				
			||||||
			});
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public function drawContactPoint(pointOnB: Vector3, normalOnB: Vector3, distance: kha.FastFloat, lifeTime: Int, color: Vector3) {
 | 
						public function drawContactPoint(pointOnB: Vector3, normalOnB: Vector3, distance: kha.FastFloat, lifeTime: Int, color: Vector3) {
 | 
				
			||||||
		#if js
 | 
							#if js
 | 
				
			||||||
			pointOnB = js.Syntax.code("Ammo.wrapPointer({0}, Ammo.btVector3)", pointOnB);
 | 
								pointOnB = js.Syntax.code("Ammo.wrapPointer({0}, Ammo.btVector3)", pointOnB);
 | 
				
			||||||
@ -126,7 +121,62 @@ class DebugDrawHelper {
 | 
				
			|||||||
					x: contactPointScreenSpace.x,
 | 
										x: contactPointScreenSpace.x,
 | 
				
			||||||
					y: contactPointScreenSpace.y,
 | 
										y: contactPointScreenSpace.y,
 | 
				
			||||||
					color: color,
 | 
										color: color,
 | 
				
			||||||
					text: Std.string(lifeTime),
 | 
										text: Std.string(lifeTime), // lifeTime: number of frames the contact point existed
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function rayCast(rayCastData:TRayCastData) {
 | 
				
			||||||
 | 
							rayCasts.push(rayCastData);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						function drawRayCast(f: Vec4, t: Vec4, hit: Bool) {
 | 
				
			||||||
 | 
							final from = worldToScreenFast(f.clone());
 | 
				
			||||||
 | 
							final to = worldToScreenFast(t.clone());
 | 
				
			||||||
 | 
							var c: kha.Color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (from.w == 1 && to.w == 1) {
 | 
				
			||||||
 | 
								if (hit) c = kha.Color.fromFloats(rayCastHitColor.x, rayCastHitColor.y, rayCastHitColor.z);
 | 
				
			||||||
 | 
								else c = kha.Color.fromFloats(rayCastColor.x, rayCastColor.y, rayCastColor.z);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								lines.push({
 | 
				
			||||||
 | 
									fromX: from.x,
 | 
				
			||||||
 | 
									fromY: from.y,
 | 
				
			||||||
 | 
									toX: to.x,
 | 
				
			||||||
 | 
									toY: to.y,
 | 
				
			||||||
 | 
									color: c
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						function drawHitPoint(hp: Vec4) {
 | 
				
			||||||
 | 
							final hitPoint = worldToScreenFast(hp.clone());
 | 
				
			||||||
 | 
							final c = kha.Color.fromFloats(rayCastHitPointColor.x, rayCastHitPointColor.y, rayCastHitPointColor.z);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (hitPoint.w == 1) {
 | 
				
			||||||
 | 
								lines.push({
 | 
				
			||||||
 | 
									fromX: hitPoint.x - contactPointSizePx,
 | 
				
			||||||
 | 
									fromY: hitPoint.y - contactPointSizePx,
 | 
				
			||||||
 | 
									toX: hitPoint.x + contactPointSizePx,
 | 
				
			||||||
 | 
									toY: hitPoint.y + contactPointSizePx,
 | 
				
			||||||
 | 
									color: c
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								lines.push({
 | 
				
			||||||
 | 
									fromX: hitPoint.x - contactPointSizePx,
 | 
				
			||||||
 | 
									fromY: hitPoint.y + contactPointSizePx,
 | 
				
			||||||
 | 
									toX: hitPoint.x + contactPointSizePx,
 | 
				
			||||||
 | 
									toY: hitPoint.y - contactPointSizePx,
 | 
				
			||||||
 | 
									color: c
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (font != null) {
 | 
				
			||||||
 | 
									texts.push({
 | 
				
			||||||
 | 
										x: hitPoint.x,
 | 
				
			||||||
 | 
										y: hitPoint.y,
 | 
				
			||||||
 | 
										color: c,
 | 
				
			||||||
 | 
										text: 'RAYCAST HIT'
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -155,13 +205,13 @@ class DebugDrawHelper {
 | 
				
			|||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function setDebugMode(debugMode: PhysicsWorld.DebugDrawMode) {
 | 
						public function setDebugMode(debugDrawMode: DebugDrawMode) {
 | 
				
			||||||
		this.debugMode = debugMode;
 | 
							this.debugDrawMode = debugDrawMode;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function getDebugMode(): PhysicsWorld.DebugDrawMode {
 | 
						public function getDebugMode(): DebugDrawMode {
 | 
				
			||||||
		#if js
 | 
							#if js
 | 
				
			||||||
			return debugMode;
 | 
								return debugDrawMode;
 | 
				
			||||||
		#elseif hl
 | 
							#elseif hl
 | 
				
			||||||
			return physicsWorld.getDebugDrawMode();
 | 
								return physicsWorld.getDebugDrawMode();
 | 
				
			||||||
		#else
 | 
							#else
 | 
				
			||||||
@ -170,7 +220,7 @@ class DebugDrawHelper {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function onRender(g: kha.graphics2.Graphics) {
 | 
						function onRender(g: kha.graphics2.Graphics) {
 | 
				
			||||||
		if (getDebugMode() == NoDebug && !physicsWorld.drawRaycasts) {
 | 
							if (getDebugMode() == NoDebug) {
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -179,7 +229,9 @@ class DebugDrawHelper {
 | 
				
			|||||||
		// will cause Bullet to call the btIDebugDraw callbacks), but this way
 | 
							// will cause Bullet to call the btIDebugDraw callbacks), but this way
 | 
				
			||||||
		// we can ensure that--within a frame--the function will not be called
 | 
							// we can ensure that--within a frame--the function will not be called
 | 
				
			||||||
		// before some user-specific physics update, which would result in a
 | 
							// before some user-specific physics update, which would result in a
 | 
				
			||||||
		// one-frame drawing delay...
 | 
							// one-frame drawing delay... Ideally we would ensure that debugDrawWorld()
 | 
				
			||||||
 | 
							// is called when all other (late) update callbacks are already executed...
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		physicsWorld.world.debugDrawWorld();
 | 
							physicsWorld.world.debugDrawWorld();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		g.opacity = 1.0;
 | 
							g.opacity = 1.0;
 | 
				
			||||||
@ -199,6 +251,17 @@ class DebugDrawHelper {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			texts.resize(0);
 | 
								texts.resize(0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if (debugDrawMode & DrawRayCast != 0) {
 | 
				
			||||||
 | 
								for (rayCastData in rayCasts) {
 | 
				
			||||||
 | 
									if (rayCastData.hasHit) {
 | 
				
			||||||
 | 
										drawRayCast(rayCastData.from, rayCastData.hitPoint, true);
 | 
				
			||||||
 | 
										drawHitPoint(rayCastData.hitPoint);
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										drawRayCast(rayCastData.from, rayCastData.to, false);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@ -241,3 +304,14 @@ class TextData {
 | 
				
			|||||||
	public var color: kha.Color;
 | 
						public var color: kha.Color;
 | 
				
			||||||
	public var text: String;
 | 
						public var text: String;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@:structInit
 | 
				
			||||||
 | 
					typedef TRayCastData = {
 | 
				
			||||||
 | 
						var from: Vec4;
 | 
				
			||||||
 | 
						var to: Vec4;
 | 
				
			||||||
 | 
						var hasHit: Bool;
 | 
				
			||||||
 | 
						@:optional var hitPoint: Vec4;
 | 
				
			||||||
 | 
						@:optional var hitNormal: Vec4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#end
 | 
				
			||||||
@ -71,7 +71,6 @@ class PhysicsWorld extends Trait {
 | 
				
			|||||||
	public var convexHitPointWorld = new Vec4();
 | 
						public var convexHitPointWorld = new Vec4();
 | 
				
			||||||
	public var convexHitNormalWorld = new Vec4();
 | 
						public var convexHitNormalWorld = new Vec4();
 | 
				
			||||||
	var pairCache: Bool = false;
 | 
						var pairCache: Bool = false;
 | 
				
			||||||
	public var drawRaycasts: Bool = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static var nullvec = true;
 | 
						static var nullvec = true;
 | 
				
			||||||
	static var vec1: bullet.Bt.Vector3 = null;
 | 
						static var vec1: bullet.Bt.Vector3 = null;
 | 
				
			||||||
@ -102,7 +101,7 @@ class PhysicsWorld extends Trait {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function new(timeScale = 1.0, maxSteps = 10, solverIterations = 10, debugDrawMode: DebugDrawMode = NoDebug, drawRaycasts: Bool = false) {
 | 
						public function new(timeScale = 1.0, maxSteps = 10, solverIterations = 10, debugDrawMode: DebugDrawMode = NoDebug) {
 | 
				
			||||||
		super();
 | 
							super();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (nullvec) {
 | 
							if (nullvec) {
 | 
				
			||||||
@ -121,7 +120,6 @@ class PhysicsWorld extends Trait {
 | 
				
			|||||||
		this.timeScale = timeScale;
 | 
							this.timeScale = timeScale;
 | 
				
			||||||
		this.maxSteps = maxSteps;
 | 
							this.maxSteps = maxSteps;
 | 
				
			||||||
		this.solverIterations = solverIterations;
 | 
							this.solverIterations = solverIterations;
 | 
				
			||||||
		this.drawRaycasts = drawRaycasts;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// First scene
 | 
							// First scene
 | 
				
			||||||
		if (active == null) {
 | 
							if (active == null) {
 | 
				
			||||||
@ -408,14 +406,6 @@ class PhysicsWorld extends Trait {
 | 
				
			|||||||
		var worldDyn: bullet.Bt.DynamicsWorld = world;
 | 
							var worldDyn: bullet.Bt.DynamicsWorld = world;
 | 
				
			||||||
		var worldCol: bullet.Bt.CollisionWorld = worldDyn;
 | 
							var worldCol: bullet.Bt.CollisionWorld = worldDyn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (this.drawRaycasts && this.debugDrawHelper != null) {
 | 
					 | 
				
			||||||
			this.debugDrawHelper.drawRayCast(
 | 
					 | 
				
			||||||
				rayFrom.x(), rayFrom.y(), rayFrom.z(), 
 | 
					 | 
				
			||||||
				rayTo.x(),   rayTo.y(),   rayTo.z(),   
 | 
					 | 
				
			||||||
				0.73, 0.341, 1.0 
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		worldCol.rayTest(rayFrom, rayTo, rayCallback);
 | 
							worldCol.rayTest(rayFrom, rayTo, rayCallback);
 | 
				
			||||||
		var rb: RigidBody = null;
 | 
							var rb: RigidBody = null;
 | 
				
			||||||
		var hitInfo: Hit = null;
 | 
							var hitInfo: Hit = null;
 | 
				
			||||||
@ -441,6 +431,16 @@ class PhysicsWorld extends Trait {
 | 
				
			|||||||
			#end
 | 
								#end
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getDebugDrawMode() & DrawRayCast != 0) {
 | 
				
			||||||
 | 
								debugDrawHelper.rayCast({
 | 
				
			||||||
 | 
									from: from,
 | 
				
			||||||
 | 
									to: to,
 | 
				
			||||||
 | 
									hasHit: rc.hasHit(),
 | 
				
			||||||
 | 
									hitPoint: hitPointWorld,
 | 
				
			||||||
 | 
									hitNormal: hitNormalWorld
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#if js
 | 
							#if js
 | 
				
			||||||
		bullet.Bt.Ammo.destroy(rayCallback);
 | 
							bullet.Bt.Ammo.destroy(rayCallback);
 | 
				
			||||||
		#else
 | 
							#else
 | 
				
			||||||
@ -519,22 +519,14 @@ class PhysicsWorld extends Trait {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	public function setDebugDrawMode(debugDrawMode: DebugDrawMode) {
 | 
						public function setDebugDrawMode(debugDrawMode: DebugDrawMode) {
 | 
				
			||||||
		if (debugDrawHelper == null) {
 | 
							if (debugDrawHelper == null) {
 | 
				
			||||||
			// Initialize if helper is null AND (standard debug mode is requested OR our custom raycast drawing is requested)
 | 
								if (debugDrawMode == NoDebug) {
 | 
				
			||||||
			if (debugDrawMode != NoDebug || this.drawRaycasts) {
 | 
					 | 
				
			||||||
				initDebugDrawing();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			else {
 | 
					 | 
				
			||||||
				// Helper is null and no debug drawing needed, so exit
 | 
					 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								initDebugDrawing(debugDrawMode);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// If we reached here, the helper is initialized (or was already)
 | 
					 | 
				
			||||||
		// Now set the standard Bullet debug mode on the actual drawer
 | 
					 | 
				
			||||||
		#if js
 | 
							#if js
 | 
				
			||||||
			// Ensure drawer exists before setting mode (might have just been initialized)
 | 
								world.getDebugDrawer().setDebugMode(debugDrawMode);
 | 
				
			||||||
			var drawer = world.getDebugDrawer();
 | 
					 | 
				
			||||||
			if (drawer != null) drawer.setDebugMode(debugDrawMode);
 | 
					 | 
				
			||||||
		#elseif hl
 | 
							#elseif hl
 | 
				
			||||||
			hlDebugDrawer_setDebugMode(debugDrawMode);
 | 
								hlDebugDrawer_setDebugMode(debugDrawMode);
 | 
				
			||||||
		#end
 | 
							#end
 | 
				
			||||||
@ -554,8 +546,8 @@ class PhysicsWorld extends Trait {
 | 
				
			|||||||
		#end
 | 
							#end
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function initDebugDrawing() {
 | 
						function initDebugDrawing(debugDrawMode: DebugDrawMode) {
 | 
				
			||||||
		debugDrawHelper = new DebugDrawHelper(this);
 | 
							debugDrawHelper = new DebugDrawHelper(this, debugDrawMode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#if js
 | 
							#if js
 | 
				
			||||||
			final drawer = new bullet.Bt.DebugDrawer();
 | 
								final drawer = new bullet.Bt.DebugDrawer();
 | 
				
			||||||
@ -691,6 +683,8 @@ enum abstract DebugDrawMode(Int) from Int to Int {
 | 
				
			|||||||
	 **/
 | 
						 **/
 | 
				
			||||||
	var DrawFrames = 1 << 15;
 | 
						var DrawFrames = 1 << 15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var DrawRayCast = 1 << 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@:op(~A) public inline function bitwiseNegate(): DebugDrawMode {
 | 
						@:op(~A) public inline function bitwiseNegate(): DebugDrawMode {
 | 
				
			||||||
		return ~this;
 | 
							return ~this;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							@ -324,6 +324,20 @@ class LeenkxExporter:
 | 
				
			|||||||
    def export_object_transform(self, bobject: bpy.types.Object, o):
 | 
					    def export_object_transform(self, bobject: bpy.types.Object, o):
 | 
				
			||||||
        wrd = bpy.data.worlds['Lnx']
 | 
					        wrd = bpy.data.worlds['Lnx']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # HACK: In Blender 4.2.x, each camera must be selected to ensure its matrix is correctly assigned
 | 
				
			||||||
 | 
					        if bpy.app.version >= (4, 2, 0) and bobject.type == 'CAMERA' and bobject.users_scene:
 | 
				
			||||||
 | 
					            current_scene = bpy.context.window.scene
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bpy.context.window.scene = bobject.users_scene[0]
 | 
				
			||||||
 | 
					            bpy.context.view_layer.update()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bobject.select_set(True)
 | 
				
			||||||
 | 
					            bpy.context.view_layer.update()
 | 
				
			||||||
 | 
					            bobject.select_set(False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bpy.context.window.scene = current_scene
 | 
				
			||||||
 | 
					            bpy.context.view_layer.update()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Static transform
 | 
					        # Static transform
 | 
				
			||||||
        o['transform'] = {'values': LeenkxExporter.write_matrix(bobject.matrix_local)}
 | 
					        o['transform'] = {'values': LeenkxExporter.write_matrix(bobject.matrix_local)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1552,8 +1566,7 @@ class LeenkxExporter:
 | 
				
			|||||||
                        log.error(e.message)
 | 
					                        log.error(e.message)
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        # Assume it was caused because of encountering n-gons
 | 
					                        # Assume it was caused because of encountering n-gons
 | 
				
			||||||
                        log.error(f"""object {bobject.name} contains n-gons in its mesh, so it's impossible to compute tanget space for normal mapping.
 | 
					                        log.error(f"""object {bobject.name} contains n-gons in its mesh, so it's impossible to compute tanget space for normal mapping. Make sure the mesh only has tris/quads.""")
 | 
				
			||||||
Make sure the mesh only has tris/quads.""")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                tangdata = np.empty(num_verts * 3, dtype='<f4')
 | 
					                tangdata = np.empty(num_verts * 3, dtype='<f4')
 | 
				
			||||||
        if has_col:
 | 
					        if has_col:
 | 
				
			||||||
@ -3026,16 +3039,16 @@ Make sure the mesh only has tris/quads.""")
 | 
				
			|||||||
            if rbw is not None and rbw.enabled:
 | 
					            if rbw is not None and rbw.enabled:
 | 
				
			||||||
                out_trait['parameters'] = [str(rbw.time_scale), str(rbw.substeps_per_frame), str(rbw.solver_iterations)]
 | 
					                out_trait['parameters'] = [str(rbw.time_scale), str(rbw.substeps_per_frame), str(rbw.solver_iterations)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if phys_pkg == 'bullet':
 | 
					                if phys_pkg == 'bullet' or phys_pkg == 'oimo':
 | 
				
			||||||
                    debug_draw_mode = 1 if wrd.lnx_bullet_dbg_draw_wireframe else 0
 | 
					                    debug_draw_mode = 1 if wrd.lnx_physics_dbg_draw_wireframe else 0
 | 
				
			||||||
                    debug_draw_mode |= 2 if wrd.lnx_bullet_dbg_draw_aabb else 0
 | 
					                    debug_draw_mode |= 2 if wrd.lnx_physics_dbg_draw_aabb else 0
 | 
				
			||||||
                    debug_draw_mode |= 8 if wrd.lnx_bullet_dbg_draw_contact_points else 0
 | 
					                    debug_draw_mode |= 8 if wrd.lnx_physics_dbg_draw_contact_points else 0
 | 
				
			||||||
                    debug_draw_mode |= 2048 if wrd.lnx_bullet_dbg_draw_constraints else 0
 | 
					                    debug_draw_mode |= 2048 if wrd.lnx_physics_dbg_draw_constraints else 0
 | 
				
			||||||
                    debug_draw_mode |= 4096 if wrd.lnx_bullet_dbg_draw_constraint_limits else 0
 | 
					                    debug_draw_mode |= 4096 if wrd.lnx_physics_dbg_draw_constraint_limits else 0
 | 
				
			||||||
                    debug_draw_mode |= 16384 if wrd.lnx_bullet_dbg_draw_normals else 0
 | 
					                    debug_draw_mode |= 16384 if wrd.lnx_physics_dbg_draw_normals else 0
 | 
				
			||||||
                    debug_draw_mode |= 32768 if wrd.lnx_bullet_dbg_draw_axis_gizmo else 0
 | 
					                    debug_draw_mode |= 32768 if wrd.lnx_physics_dbg_draw_axis_gizmo else 0
 | 
				
			||||||
 | 
					                    debug_draw_mode |= 65536 if wrd.lnx_physics_dbg_draw_raycast else 0
 | 
				
			||||||
                    out_trait['parameters'].append(str(debug_draw_mode))
 | 
					                    out_trait['parameters'].append(str(debug_draw_mode))
 | 
				
			||||||
                    out_trait['parameters'].append(str(wrd.lnx_bullet_dbg_draw_raycast).lower())
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.output['traits'].append(out_trait)
 | 
					            self.output['traits'].append(out_trait)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								leenkx/blender/lnx/logicnode/array/LN_array_index_list.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								leenkx/blender/lnx/logicnode/array/LN_array_index_list.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					from lnx.logicnode.lnx_nodes import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ArrayIndexNode(LnxLogicTreeNode):
 | 
				
			||||||
 | 
					    """Returns the array index list of the given value as an array."""
 | 
				
			||||||
 | 
					    bl_idname = 'LNArrayIndexListNode'
 | 
				
			||||||
 | 
					    bl_label = 'Array Index List'
 | 
				
			||||||
 | 
					    lnx_version = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def lnx_init(self, context):
 | 
				
			||||||
 | 
					        self.add_input('LnxNodeSocketArray', 'Array')
 | 
				
			||||||
 | 
					        self.add_input('LnxDynamicSocket', 'Value')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.add_output('LnxNodeSocketArray', 'Array')
 | 
				
			||||||
@ -170,32 +170,64 @@ vec3 random3(const vec3 c) {
 | 
				
			|||||||
    r.y = fract(512.0 * j);
 | 
					    r.y = fract(512.0 * j);
 | 
				
			||||||
    return r - 0.5;
 | 
					    return r - 0.5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
float tex_musgrave_f(const vec3 p) {
 | 
					
 | 
				
			||||||
 | 
					float noise_tex(const vec3 p) {
 | 
				
			||||||
    const float F3 = 0.3333333;
 | 
					    const float F3 = 0.3333333;
 | 
				
			||||||
    const float G3 = 0.1666667;
 | 
					    const float G3 = 0.1666667;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vec3 s = floor(p + dot(p, vec3(F3)));
 | 
					    vec3 s = floor(p + dot(p, vec3(F3)));
 | 
				
			||||||
    vec3 x = p - s + dot(s, vec3(G3));
 | 
					    vec3 x = p - s + dot(s, vec3(G3));
 | 
				
			||||||
    vec3 e = step(vec3(0.0), x - x.yzx);
 | 
					    vec3 e = step(vec3(0.0), x - x.yzx);
 | 
				
			||||||
    vec3 i1 = e * (1.0 - e.zxy);
 | 
					    vec3 i1 = e * (1.0 - e.zxy);
 | 
				
			||||||
    vec3 i2 = 1.0 - e.zxy * (1.0 - e);
 | 
					    vec3 i2 = 1.0 - e.zxy * (1.0 - e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vec3 x1 = x - i1 + G3;
 | 
					    vec3 x1 = x - i1 + G3;
 | 
				
			||||||
    vec3 x2 = x - i2 + 2.0 * G3;
 | 
					    vec3 x2 = x - i2 + 2.0 * G3;
 | 
				
			||||||
    vec3 x3 = x - 1.0 + 3.0 * G3;
 | 
					    vec3 x3 = x - 1.0 + 3.0 * G3;
 | 
				
			||||||
    vec4 w, d;
 | 
					
 | 
				
			||||||
    w.x = dot(x, x);
 | 
					    vec4 w;
 | 
				
			||||||
    w.y = dot(x1, x1);
 | 
					    w.x = max(0.6 - dot(x, x), 0.0);
 | 
				
			||||||
    w.z = dot(x2, x2);
 | 
					    w.y = max(0.6 - dot(x1, x1), 0.0);
 | 
				
			||||||
    w.w = dot(x3, x3);
 | 
					    w.z = max(0.6 - dot(x2, x2), 0.0);
 | 
				
			||||||
    w = max(0.6 - w, 0.0);
 | 
					    w.w = max(0.6 - dot(x3, x3), 0.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    w = w * w;
 | 
				
			||||||
 | 
					    w = w * w;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vec4 d;
 | 
				
			||||||
    d.x = dot(random3(s), x);
 | 
					    d.x = dot(random3(s), x);
 | 
				
			||||||
    d.y = dot(random3(s + i1), x1);
 | 
					    d.y = dot(random3(s + i1), x1);
 | 
				
			||||||
    d.z = dot(random3(s + i2), x2);
 | 
					    d.z = dot(random3(s + i2), x2);
 | 
				
			||||||
    d.w = dot(random3(s + 1.0), x3);
 | 
					    d.w = dot(random3(s + 1.0), x3);
 | 
				
			||||||
    w *= w;
 | 
					
 | 
				
			||||||
    w *= w;
 | 
					 | 
				
			||||||
    d *= w;
 | 
					    d *= w;
 | 
				
			||||||
    return clamp(dot(d, vec4(52.0)), 0.0, 1.0);
 | 
					    return clamp(dot(d, vec4(52.0)), 0.0, 1.0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float tex_musgrave_f(const vec3 p, float detail, float distortion) {
 | 
				
			||||||
 | 
					    // Apply distortion to the input coordinates smoothly with noise_tex
 | 
				
			||||||
 | 
					    vec3 distorted_p = p + distortion * vec3(
 | 
				
			||||||
 | 
					        noise_tex(p + vec3(5.2, 1.3, 7.1)),
 | 
				
			||||||
 | 
					        noise_tex(p + vec3(1.7, 9.2, 3.8)),
 | 
				
			||||||
 | 
					        noise_tex(p + vec3(8.3, 2.8, 4.5))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    float value = 0.0;
 | 
				
			||||||
 | 
					    float amplitude = 1.0;
 | 
				
			||||||
 | 
					    float frequency = 1.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Use 'detail' as number of octaves, clamped between 1 and 8
 | 
				
			||||||
 | 
					    int octaves = int(clamp(detail, 1.0, 8.0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < octaves; i++) {
 | 
				
			||||||
 | 
					        value += amplitude * noise_tex(distorted_p * frequency);
 | 
				
			||||||
 | 
					        frequency *= 2.0;
 | 
				
			||||||
 | 
					        amplitude *= 0.5;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return clamp(value, 0.0, 1.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# col: the incoming color
 | 
					# col: the incoming color
 | 
				
			||||||
 | 
				
			|||||||
@ -254,10 +254,10 @@ if bpy.app.version < (4, 1, 0):
 | 
				
			|||||||
            co = 'bposition'
 | 
					            co = 'bposition'
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        scale = c.parse_value_input(node.inputs['Scale'])
 | 
					        scale = c.parse_value_input(node.inputs['Scale'])
 | 
				
			||||||
        # detail = c.parse_value_input(node.inputs[2])
 | 
					        detail = c.parse_value_input(node.inputs[3])
 | 
				
			||||||
        # distortion = c.parse_value_input(node.inputs[3])
 | 
					        distortion = c.parse_value_input(node.inputs[4])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        res = f'tex_musgrave_f({co} * {scale} * 0.5)'
 | 
					        res = f'tex_musgrave_f({co} * {scale} * 0.5, {detail}, {distortion})'
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -278,11 +278,11 @@ def parse_tex_noise(node: bpy.types.ShaderNodeTexNoise, out_socket: bpy.types.No
 | 
				
			|||||||
    distortion = c.parse_value_input(node.inputs[5])
 | 
					    distortion = c.parse_value_input(node.inputs[5])
 | 
				
			||||||
    if bpy.app.version >= (4, 1, 0):
 | 
					    if bpy.app.version >= (4, 1, 0):
 | 
				
			||||||
        if node.noise_type == "FBM":
 | 
					        if node.noise_type == "FBM":
 | 
				
			||||||
            if out_socket == node.outputs[1]:
 | 
					 | 
				
			||||||
            state.curshader.add_function(c_functions.str_tex_musgrave)
 | 
					            state.curshader.add_function(c_functions.str_tex_musgrave)
 | 
				
			||||||
                res = 'vec3(tex_musgrave_f({0} * {1}), tex_musgrave_f({0} * {1} + 120.0), tex_musgrave_f({0} * {1} + 168.0))'.format(co, scale, detail, distortion)
 | 
					            if out_socket == node.outputs[1]:
 | 
				
			||||||
 | 
					                res = 'vec3(tex_musgrave_f({0} * {1}, {2}, {3}), tex_musgrave_f({0} * {1} + 120.0, {2}, {3}), tex_musgrave_f({0} * {1} + 168.0, {2}, {3}))'.format(co, scale, detail, distortion)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                res = f'tex_musgrave_f({co} * {scale} * 1.0)'
 | 
					                res = f'tex_musgrave_f({co} * {scale} * 1.0, {detail}, {distortion})'
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            if out_socket == node.outputs[1]:
 | 
					            if out_socket == node.outputs[1]:
 | 
				
			||||||
                res = 'vec3(tex_noise({0} * {1},{2},{3}), tex_noise({0} * {1} + 120.0,{2},{3}), tex_noise({0} * {1} + 168.0,{2},{3}))'.format(co, scale, detail, distortion)
 | 
					                res = 'vec3(tex_noise({0} * {1},{2},{3}), tex_noise({0} * {1} + 120.0,{2},{3}), tex_noise({0} * {1} + 168.0,{2},{3}))'.format(co, scale, detail, distortion)
 | 
				
			||||||
 | 
				
			|||||||
@ -86,7 +86,7 @@ def write(vert, particle_info=None, shadowmap=False):
 | 
				
			|||||||
        vert.write('p_fade = sin(min((p_age / 2) * 3.141592, 3.141592));')
 | 
					        vert.write('p_fade = sin(min((p_age / 2) * 3.141592, 3.141592));')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if out_index:
 | 
					    if out_index:
 | 
				
			||||||
        vert.add_out('float p_index');
 | 
					        vert.add_out('float p_index')
 | 
				
			||||||
        vert.write('p_index = gl_InstanceID;')
 | 
					        vert.write('p_index = gl_InstanceID;')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def write_tilesheet(vert):
 | 
					def write_tilesheet(vert):
 | 
				
			||||||
 | 
				
			|||||||
@ -209,7 +209,8 @@ def make_instancing_and_skinning(mat: Material, mat_users: Dict[Material, List[O
 | 
				
			|||||||
                    global_elems.append({'name': 'ipos', 'data': 'float3'})
 | 
					                    global_elems.append({'name': 'ipos', 'data': 'float3'})
 | 
				
			||||||
                    if 'Rot' in inst:
 | 
					                    if 'Rot' in inst:
 | 
				
			||||||
                        global_elems.append({'name': 'irot', 'data': 'float3'})
 | 
					                        global_elems.append({'name': 'irot', 'data': 'float3'})
 | 
				
			||||||
                    if 'Scale' in inst:
 | 
					                    #HACK: checking `mat.arm_particle_flag` to force appending 'iscl' to the particle's vertex shader
 | 
				
			||||||
 | 
					                    if 'Scale' in inst or mat.arm_particle_flag:
 | 
				
			||||||
                        global_elems.append({'name': 'iscl', 'data': 'float3'})
 | 
					                        global_elems.append({'name': 'iscl', 'data': 'float3'})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            elif inst == 'Off':
 | 
					            elif inst == 'Off':
 | 
				
			||||||
 | 
				
			|||||||
@ -77,6 +77,25 @@ class LNX_MT_NodeAddOverride(bpy.types.Menu):
 | 
				
			|||||||
                layout.separator()
 | 
					                layout.separator()
 | 
				
			||||||
                layout.menu(f'LNX_MT_{INTERNAL_GROUPS_MENU_ID}_menu', text=internal_groups_menu_class.bl_label, icon='OUTLINER_OB_GROUP_INSTANCE')
 | 
					                layout.menu(f'LNX_MT_{INTERNAL_GROUPS_MENU_ID}_menu', text=internal_groups_menu_class.bl_label, icon='OUTLINER_OB_GROUP_INSTANCE')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        elif context.space_data.tree_type == 'ShaderNodeTree':
 | 
				
			||||||
 | 
					            # TO DO - Recursively gather nodes and draw them to menu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            LNX_MT_NodeAddOverride.overridden_draw(self, context)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            layout = self.layout
 | 
				
			||||||
 | 
					            layout.separator()
 | 
				
			||||||
 | 
					            layout.separator()
 | 
				
			||||||
 | 
					            col = layout.column()
 | 
				
			||||||
 | 
					            col.label(text="Custom")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            shader_data_op = col.operator("node.add_node", text="Shader Data")
 | 
				
			||||||
 | 
					            shader_data_op.type = "LnxShaderDataNode"
 | 
				
			||||||
 | 
					            shader_data_op.use_transform = True
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            particle_op = col.operator("node.add_node", text="Custom Particle")
 | 
				
			||||||
 | 
					            particle_op.type = "LnxCustomParticleNode"
 | 
				
			||||||
 | 
					            particle_op.use_transform = True
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            LNX_MT_NodeAddOverride.overridden_draw(self, context)
 | 
					            LNX_MT_NodeAddOverride.overridden_draw(self, context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -197,38 +197,38 @@ def init_properties():
 | 
				
			|||||||
        items=[('Bullet', 'Bullet', 'Bullet'),
 | 
					        items=[('Bullet', 'Bullet', 'Bullet'),
 | 
				
			||||||
               ('Oimo', 'Oimo', 'Oimo')],
 | 
					               ('Oimo', 'Oimo', 'Oimo')],
 | 
				
			||||||
        name="Physics Engine", default='Bullet', update=assets.invalidate_compiler_cache)
 | 
					        name="Physics Engine", default='Bullet', update=assets.invalidate_compiler_cache)
 | 
				
			||||||
    bpy.types.World.lnx_bullet_dbg_draw_wireframe = BoolProperty(
 | 
					    bpy.types.World.lnx_physics_dbg_draw_wireframe = BoolProperty(
 | 
				
			||||||
        name="Collider Wireframes", default=False,
 | 
					        name="Collider Wireframes", default=False,
 | 
				
			||||||
        description="Draw wireframes of the physics collider meshes and suspensions of raycast vehicle simulations"
 | 
					        description="Draw wireframes of the physics collider meshes and suspensions of raycast vehicle simulations"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    bpy.types.World.lnx_bullet_dbg_draw_raycast = BoolProperty(
 | 
					    bpy.types.World.lnx_physics_dbg_draw_raycast = BoolProperty(
 | 
				
			||||||
        name="Trace Raycast", default=False,
 | 
					        name="Raycasts", default=False,
 | 
				
			||||||
        description="Draw raycasts to trace the results"
 | 
					        description="Draw raycasts to trace the results"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    bpy.types.World.lnx_bullet_dbg_draw_aabb = BoolProperty(
 | 
					    bpy.types.World.lnx_physics_dbg_draw_aabb = BoolProperty(
 | 
				
			||||||
        name="Axis-aligned Minimum Bounding Boxes", default=False,
 | 
					        name="Axis-aligned Minimum Bounding Boxes", default=False,
 | 
				
			||||||
        description="Draw axis-aligned minimum bounding boxes (AABBs) of the physics collider meshes"
 | 
					        description="Draw axis-aligned minimum bounding boxes (AABBs) of the physics collider meshes"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    bpy.types.World.lnx_bullet_dbg_draw_contact_points = BoolProperty(
 | 
					    bpy.types.World.lnx_physics_dbg_draw_contact_points = BoolProperty(
 | 
				
			||||||
        name="Contact Points", default=False,
 | 
					        name="Contact Points", default=False,
 | 
				
			||||||
        description="Visualize contact points of multiple colliders"
 | 
					        description="Visualize contact points of multiple colliders"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    bpy.types.World.lnx_bullet_dbg_draw_constraints = BoolProperty(
 | 
					    bpy.types.World.lnx_physics_dbg_draw_constraints = BoolProperty(
 | 
				
			||||||
        name="Constraints", default=False,
 | 
					        name="Constraints", default=False,
 | 
				
			||||||
        description="Draw axis gizmos for important constraint points"
 | 
					        description="Draw axis gizmos for important constraint points"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    bpy.types.World.lnx_bullet_dbg_draw_constraint_limits = BoolProperty(
 | 
					    bpy.types.World.lnx_physics_dbg_draw_constraint_limits = BoolProperty(
 | 
				
			||||||
        name="Constraint Limits", default=False,
 | 
					        name="Constraint Limits", default=False,
 | 
				
			||||||
        description="Draw additional constraint information such as distance or angle limits"
 | 
					        description="Draw additional constraint information such as distance or angle limits"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    bpy.types.World.lnx_bullet_dbg_draw_normals = BoolProperty(
 | 
					    bpy.types.World.lnx_physics_dbg_draw_normals = BoolProperty(
 | 
				
			||||||
        name="Face Normals", default=False,
 | 
					        name="Face Normals", default=False,
 | 
				
			||||||
        description=(
 | 
					        description=(
 | 
				
			||||||
            "Draw the normal vectors of the triangles of the physics collider meshes."
 | 
					            "Draw the normal vectors of the triangles of the physics collider meshes."
 | 
				
			||||||
            " This only works for mesh collision shapes"
 | 
					            " This only works with Bullet physics, for mesh collision shapes"
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    bpy.types.World.lnx_bullet_dbg_draw_axis_gizmo = BoolProperty(
 | 
					    bpy.types.World.lnx_physics_dbg_draw_axis_gizmo = BoolProperty(
 | 
				
			||||||
        name="Axis Gizmos", default=False,
 | 
					        name="Axis Gizmos", default=False,
 | 
				
			||||||
        description=(
 | 
					        description=(
 | 
				
			||||||
            "Draw a small axis gizmo at the origin of the collision shape."
 | 
					            "Draw a small axis gizmo at the origin of the collision shape."
 | 
				
			||||||
 | 
				
			|||||||
@ -1907,7 +1907,7 @@ class LNX_PT_RenderPathPostProcessPanel(bpy.types.Panel):
 | 
				
			|||||||
        col.prop(rpdat, "rp_bloom")
 | 
					        col.prop(rpdat, "rp_bloom")
 | 
				
			||||||
        _col = col.column()
 | 
					        _col = col.column()
 | 
				
			||||||
        _col.enabled = rpdat.rp_bloom
 | 
					        _col.enabled = rpdat.rp_bloom
 | 
				
			||||||
        if bpy.app.version <= (4, 2, 4):
 | 
					        if bpy.app.version < (4, 3, 0):
 | 
				
			||||||
            _col.prop(rpdat, 'lnx_bloom_follow_blender')
 | 
					            _col.prop(rpdat, 'lnx_bloom_follow_blender')
 | 
				
			||||||
            if not rpdat.lnx_bloom_follow_blender:
 | 
					            if not rpdat.lnx_bloom_follow_blender:
 | 
				
			||||||
                _col.prop(rpdat, 'lnx_bloom_threshold')
 | 
					                _col.prop(rpdat, 'lnx_bloom_threshold')
 | 
				
			||||||
@ -2749,20 +2749,20 @@ class LNX_PT_BulletDebugDrawingPanel(bpy.types.Panel):
 | 
				
			|||||||
        layout.use_property_decorate = False
 | 
					        layout.use_property_decorate = False
 | 
				
			||||||
        wrd = bpy.data.worlds['Lnx']
 | 
					        wrd = bpy.data.worlds['Lnx']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if wrd.lnx_physics_engine != 'Bullet':
 | 
					        if wrd.lnx_physics_engine != 'Bullet' and wrd.lnx_physics_engine != 'Oimo':
 | 
				
			||||||
            row = layout.row()
 | 
					            row = layout.row()
 | 
				
			||||||
            row.alert = True
 | 
					            row.alert = True
 | 
				
			||||||
            row.label(text="Physics debug drawing is only supported for the Bullet physics engine")
 | 
					            row.label(text="Physics debug drawing is only supported for the Bullet and Oimo physics engines")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        col = layout.column(align=False)
 | 
					        col = layout.column(align=False)
 | 
				
			||||||
        col.prop(wrd, "lnx_bullet_dbg_draw_wireframe")
 | 
					        col.prop(wrd, "lnx_physics_dbg_draw_wireframe")
 | 
				
			||||||
        col.prop(wrd, "lnx_bullet_dbg_draw_raycast")
 | 
					        col.prop(wrd, "lnx_physics_dbg_draw_raycast")
 | 
				
			||||||
        col.prop(wrd, "lnx_bullet_dbg_draw_aabb")
 | 
					        col.prop(wrd, "lnx_physics_dbg_draw_aabb")
 | 
				
			||||||
        col.prop(wrd, "lnx_bullet_dbg_draw_contact_points")
 | 
					        col.prop(wrd, "lnx_physics_dbg_draw_contact_points")
 | 
				
			||||||
        col.prop(wrd, "lnx_bullet_dbg_draw_constraints")
 | 
					        col.prop(wrd, "lnx_physics_dbg_draw_constraints")
 | 
				
			||||||
        col.prop(wrd, "lnx_bullet_dbg_draw_constraint_limits")
 | 
					        col.prop(wrd, "lnx_physics_dbg_draw_constraint_limits")
 | 
				
			||||||
        col.prop(wrd, "lnx_bullet_dbg_draw_normals")
 | 
					        col.prop(wrd, "lnx_physics_dbg_draw_normals")
 | 
				
			||||||
        col.prop(wrd, "lnx_bullet_dbg_draw_axis_gizmo")
 | 
					        col.prop(wrd, "lnx_physics_dbg_draw_axis_gizmo")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def draw_custom_node_menu(self, context):
 | 
					def draw_custom_node_menu(self, context):
 | 
				
			||||||
    """Extension of the node context menu.
 | 
					    """Extension of the node context menu.
 | 
				
			||||||
 | 
				
			|||||||
@ -828,8 +828,8 @@ def check_blender_version(op: bpy.types.Operator):
 | 
				
			|||||||
    """Check whether the Blender version is supported by Leenkx,
 | 
					    """Check whether the Blender version is supported by Leenkx,
 | 
				
			||||||
    if not, report in UI.
 | 
					    if not, report in UI.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    if bpy.app.version[0] != 4 or bpy.app.version[1] != 2:
 | 
					    if bpy.app.version[:2] not in [(4, 4), (4, 2), (3, 6), (3, 3)]:
 | 
				
			||||||
        op.report({'INFO'}, 'INFO: For Leenkx to work correctly, use a Blender LTS version such as 4.2 | 3.6 | 3.3')
 | 
					        op.report({'INFO'}, 'INFO: For Leenkx to work correctly, use a Blender LTS version')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check_saved(self):
 | 
					def check_saved(self):
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user