4 Commits

906 changed files with 2150 additions and 7110 deletions

2
.gitattributes vendored
View File

@ -1,2 +0,0 @@
*.hdr binary
blender/lnx/props.py ident

3
.gitignore vendored
View File

@ -1,3 +0,0 @@
__pycache__/
*.pyc
*.DS_Store

View File

@ -80,7 +80,6 @@ extern class Krom {
static function unloadImage(image: kha.Image): Void;
static function loadSound(file: String): Dynamic;
static function writeAudioBuffer(buffer: js.lib.ArrayBuffer, samples: Int): Void;
static function getSamplesPerSecond(): Int;
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;
@ -116,7 +115,6 @@ extern class Krom {
static function screenDpi(): Int;
static function systemId(): String;
static function requestShutdown(): Void;
static function displayFrequency(): Int;
static function displayCount(): Int;
static function displayWidth(index: Int): Int;
static function displayHeight(index: Int): Int;

View File

@ -79,7 +79,7 @@ class Display {
public var frequency(get, never): Int;
function get_frequency(): Int {
return Krom.displayFrequency();
return 60;
}
public var pixelsPerInch(get, never): Int;

View File

@ -1,344 +1,343 @@
package kha;
import kha.graphics4.TextureFormat;
import kha.input.Gamepad;
import kha.input.Keyboard;
import kha.input.Mouse;
import kha.input.MouseImpl;
import kha.input.Pen;
import kha.input.Surface;
import kha.System;
import haxe.ds.Vector;
class SystemImpl {
static var start: Float;
static var framebuffer: Framebuffer;
static var keyboard: Keyboard;
static var mouse: Mouse;
static var pen: Pen;
static var maxGamepads: Int = 4;
static var gamepads: Array<Gamepad>;
static var mouseLockListeners: Array<Void->Void> = [];
static function renderCallback(): Void {
Scheduler.executeFrame();
System.render([framebuffer]);
}
static function dropFilesCallback(filePath: String): Void {
System.dropFiles(filePath);
}
static function copyCallback(): String {
if (System.copyListener != null) {
return System.copyListener();
}
else {
return null;
}
}
static function cutCallback(): String {
if (System.cutListener != null) {
return System.cutListener();
}
else {
return null;
}
}
static function pasteCallback(data: String): Void {
if (System.pasteListener != null) {
System.pasteListener(data);
}
}
static function foregroundCallback(): Void {
System.foreground();
}
static function resumeCallback(): Void {
System.resume();
}
static function pauseCallback(): Void {
System.pause();
}
static function backgroundCallback(): Void {
System.background();
}
static function shutdownCallback(): Void {
System.shutdown();
}
static function keyboardDownCallback(code: Int): Void {
keyboard.sendDownEvent(cast code);
}
static function keyboardUpCallback(code: Int): Void {
keyboard.sendUpEvent(cast code);
}
static function keyboardPressCallback(charCode: Int): Void {
keyboard.sendPressEvent(String.fromCharCode(charCode));
}
static function mouseDownCallback(button: Int, x: Int, y: Int): Void {
mouse.sendDownEvent(0, button, x, y);
}
static function mouseUpCallback(button: Int, x: Int, y: Int): Void {
mouse.sendUpEvent(0, button, x, y);
}
static function mouseMoveCallback(x: Int, y: Int, mx: Int, my: Int): Void {
mouse.sendMoveEvent(0, x, y, mx, my);
}
static function mouseWheelCallback(delta: Int): Void {
mouse.sendWheelEvent(0, delta);
}
static function penDownCallback(x: Int, y: Int, pressure: Float): Void {
pen.sendDownEvent(0, x, y, pressure);
}
static function penUpCallback(x: Int, y: Int, pressure: Float): Void {
pen.sendUpEvent(0, x, y, pressure);
}
static function penMoveCallback(x: Int, y: Int, pressure: Float): Void {
pen.sendMoveEvent(0, x, y, pressure);
}
static function gamepadAxisCallback(gamepad: Int, axis: Int, value: Float): Void {
gamepads[gamepad].sendAxisEvent(axis, value);
}
static function gamepadButtonCallback(gamepad: Int, button: Int, value: Float): Void {
gamepads[gamepad].sendButtonEvent(button, value);
}
static function audioCallback(samples: Int): Void {
kha.audio2.Audio._callCallback(samples);
var buffer = @:privateAccess kha.audio2.Audio.buffer;
Krom.writeAudioBuffer(buffer.data.buffer, samples);
}
public static function init(options: SystemOptions, callback: Window->Void): Void {
Krom.init(options.title, options.width, options.height, options.framebuffer.samplesPerPixel, options.framebuffer.verticalSync,
cast options.window.mode, options.window.windowFeatures, Krom.KROM_API);
start = Krom.getTime();
haxe.Log.trace = function(v: Dynamic, ?infos: haxe.PosInfos) {
var message = haxe.Log.formatOutput(v, infos);
Krom.log(message);
};
new Window(0);
Scheduler.init();
Shaders.init();
var g4 = new kha.krom.Graphics();
framebuffer = new Framebuffer(0, null, null, g4);
framebuffer.init(new kha.graphics2.Graphics1(framebuffer), new kha.graphics4.Graphics2(framebuffer), g4);
Krom.setCallback(renderCallback);
Krom.setDropFilesCallback(dropFilesCallback);
Krom.setCutCopyPasteCallback(cutCallback, copyCallback, pasteCallback);
Krom.setApplicationStateCallback(foregroundCallback, resumeCallback, pauseCallback, backgroundCallback, shutdownCallback);
keyboard = new Keyboard();
mouse = new MouseImpl();
pen = new Pen();
gamepads = new Array<Gamepad>();
for (i in 0...maxGamepads) {
gamepads[i] = new Gamepad(i);
}
Krom.setKeyboardDownCallback(keyboardDownCallback);
Krom.setKeyboardUpCallback(keyboardUpCallback);
Krom.setKeyboardPressCallback(keyboardPressCallback);
Krom.setMouseDownCallback(mouseDownCallback);
Krom.setMouseUpCallback(mouseUpCallback);
Krom.setMouseMoveCallback(mouseMoveCallback);
Krom.setMouseWheelCallback(mouseWheelCallback);
Krom.setPenDownCallback(penDownCallback);
Krom.setPenUpCallback(penUpCallback);
Krom.setPenMoveCallback(penMoveCallback);
Krom.setGamepadAxisCallback(gamepadAxisCallback);
Krom.setGamepadButtonCallback(gamepadButtonCallback);
kha.audio2.Audio.samplesPerSecond = Krom.getSamplesPerSecond();
kha.audio1.Audio._init();
kha.audio2.Audio._init();
Krom.setAudioCallback(audioCallback);
Scheduler.start();
callback(Window.get(0));
}
public static function initEx(title: String, options: Array<WindowOptions>, windowCallback: Int->Void, callback: Void->Void): Void {}
static function translateWindowMode(value: Null<WindowMode>): Int {
if (value == null) {
return 0;
}
return switch (value) {
case Windowed: 0;
case Fullscreen: 1;
case ExclusiveFullscreen: 2;
}
}
public static function getScreenRotation(): ScreenRotation {
return ScreenRotation.RotationNone;
}
public static function getTime(): Float {
return Krom.getTime() - start;
}
public static function getVsync(): Bool {
return true;
}
public static function getRefreshRate(): Int {
return Krom.displayFrequency();
}
public static function getSystemId(): String {
return Krom.systemId();
}
public static function vibrate(ms: Int): Void {
// TODO: Implement
}
public static function getLanguage(): String {
return "en"; // TODO: Implement
}
public static function requestShutdown(): Bool {
Krom.requestShutdown();
return true;
}
public static function getMouse(num: Int): Mouse {
return mouse;
}
public static function getPen(num: Int): Pen {
return pen;
}
public static function getKeyboard(num: Int): Keyboard {
return keyboard;
}
public static function lockMouse(): Void {
if (!isMouseLocked()) {
Krom.lockMouse();
for (listener in mouseLockListeners) {
listener();
}
}
}
public static function unlockMouse(): Void {
if (isMouseLocked()) {
Krom.unlockMouse();
for (listener in mouseLockListeners) {
listener();
}
}
}
public static function canLockMouse(): Bool {
return Krom.canLockMouse();
}
public static function isMouseLocked(): Bool {
return Krom.isMouseLocked();
}
public static function notifyOfMouseLockChange(func: Void->Void, error: Void->Void): Void {
if (canLockMouse() && func != null) {
mouseLockListeners.push(func);
}
}
public static function removeFromMouseLockChange(func: Void->Void, error: Void->Void): Void {
if (canLockMouse() && func != null) {
mouseLockListeners.remove(func);
}
}
public static function hideSystemCursor(): Void {
Krom.showMouse(false);
}
public static function showSystemCursor(): Void {
Krom.showMouse(true);
}
static function unload(): Void {}
public static function canSwitchFullscreen(): Bool {
return false;
}
public static function isFullscreen(): Bool {
return false;
}
public static function requestFullscreen(): Void {}
public static function exitFullscreen(): Void {}
public static function notifyOfFullscreenChange(func: Void->Void, error: Void->Void): Void {}
public static function removeFromFullscreenChange(func: Void->Void, error: Void->Void): Void {}
public static function changeResolution(width: Int, height: Int): Void {}
public static function setKeepScreenOn(on: Bool): Void {}
public static function loadUrl(url: String): Void {}
public static function getGamepadId(index: Int): String {
return "unknown";
}
public static function getGamepadVendor(index: Int): String {
return "unknown";
}
public static function setGamepadRumble(index: Int, leftAmount: Float, rightAmount: Float): Void {}
public static function safeZone(): Float {
return 1.0;
}
public static function login(): Void {}
public static function automaticSafeZone(): Bool {
return true;
}
public static function setSafeZone(value: Float): Void {}
public static function unlockAchievement(id: Int): Void {}
public static function waitingForLogin(): Bool {
return false;
}
public static function disallowUserChange(): Void {}
public static function allowUserChange(): Void {}
}
package kha;
import kha.graphics4.TextureFormat;
import kha.input.Gamepad;
import kha.input.Keyboard;
import kha.input.Mouse;
import kha.input.MouseImpl;
import kha.input.Pen;
import kha.input.Surface;
import kha.System;
import haxe.ds.Vector;
class SystemImpl {
static var start: Float;
static var framebuffer: Framebuffer;
static var keyboard: Keyboard;
static var mouse: Mouse;
static var pen: Pen;
static var maxGamepads: Int = 4;
static var gamepads: Array<Gamepad>;
static var mouseLockListeners: Array<Void->Void> = [];
static function renderCallback(): Void {
Scheduler.executeFrame();
System.render([framebuffer]);
}
static function dropFilesCallback(filePath: String): Void {
System.dropFiles(filePath);
}
static function copyCallback(): String {
if (System.copyListener != null) {
return System.copyListener();
}
else {
return null;
}
}
static function cutCallback(): String {
if (System.cutListener != null) {
return System.cutListener();
}
else {
return null;
}
}
static function pasteCallback(data: String): Void {
if (System.pasteListener != null) {
System.pasteListener(data);
}
}
static function foregroundCallback(): Void {
System.foreground();
}
static function resumeCallback(): Void {
System.resume();
}
static function pauseCallback(): Void {
System.pause();
}
static function backgroundCallback(): Void {
System.background();
}
static function shutdownCallback(): Void {
System.shutdown();
}
static function keyboardDownCallback(code: Int): Void {
keyboard.sendDownEvent(cast code);
}
static function keyboardUpCallback(code: Int): Void {
keyboard.sendUpEvent(cast code);
}
static function keyboardPressCallback(charCode: Int): Void {
keyboard.sendPressEvent(String.fromCharCode(charCode));
}
static function mouseDownCallback(button: Int, x: Int, y: Int): Void {
mouse.sendDownEvent(0, button, x, y);
}
static function mouseUpCallback(button: Int, x: Int, y: Int): Void {
mouse.sendUpEvent(0, button, x, y);
}
static function mouseMoveCallback(x: Int, y: Int, mx: Int, my: Int): Void {
mouse.sendMoveEvent(0, x, y, mx, my);
}
static function mouseWheelCallback(delta: Int): Void {
mouse.sendWheelEvent(0, delta);
}
static function penDownCallback(x: Int, y: Int, pressure: Float): Void {
pen.sendDownEvent(0, x, y, pressure);
}
static function penUpCallback(x: Int, y: Int, pressure: Float): Void {
pen.sendUpEvent(0, x, y, pressure);
}
static function penMoveCallback(x: Int, y: Int, pressure: Float): Void {
pen.sendMoveEvent(0, x, y, pressure);
}
static function gamepadAxisCallback(gamepad: Int, axis: Int, value: Float): Void {
gamepads[gamepad].sendAxisEvent(axis, value);
}
static function gamepadButtonCallback(gamepad: Int, button: Int, value: Float): Void {
gamepads[gamepad].sendButtonEvent(button, value);
}
static function audioCallback(samples: Int): Void {
kha.audio2.Audio._callCallback(samples);
var buffer = @:privateAccess kha.audio2.Audio.buffer;
Krom.writeAudioBuffer(buffer.data.buffer, samples);
}
public static function init(options: SystemOptions, callback: Window->Void): Void {
Krom.init(options.title, options.width, options.height, options.framebuffer.samplesPerPixel, options.framebuffer.verticalSync,
cast options.window.mode, options.window.windowFeatures, Krom.KROM_API);
start = Krom.getTime();
haxe.Log.trace = function(v: Dynamic, ?infos: haxe.PosInfos) {
var message = haxe.Log.formatOutput(v, infos);
Krom.log(message);
};
new Window(0);
Scheduler.init();
Shaders.init();
var g4 = new kha.krom.Graphics();
framebuffer = new Framebuffer(0, null, null, g4);
framebuffer.init(new kha.graphics2.Graphics1(framebuffer), new kha.graphics4.Graphics2(framebuffer), g4);
Krom.setCallback(renderCallback);
Krom.setDropFilesCallback(dropFilesCallback);
Krom.setCutCopyPasteCallback(cutCallback, copyCallback, pasteCallback);
Krom.setApplicationStateCallback(foregroundCallback, resumeCallback, pauseCallback, backgroundCallback, shutdownCallback);
keyboard = new Keyboard();
mouse = new MouseImpl();
pen = new Pen();
gamepads = new Array<Gamepad>();
for (i in 0...maxGamepads) {
gamepads[i] = new Gamepad(i);
}
Krom.setKeyboardDownCallback(keyboardDownCallback);
Krom.setKeyboardUpCallback(keyboardUpCallback);
Krom.setKeyboardPressCallback(keyboardPressCallback);
Krom.setMouseDownCallback(mouseDownCallback);
Krom.setMouseUpCallback(mouseUpCallback);
Krom.setMouseMoveCallback(mouseMoveCallback);
Krom.setMouseWheelCallback(mouseWheelCallback);
Krom.setPenDownCallback(penDownCallback);
Krom.setPenUpCallback(penUpCallback);
Krom.setPenMoveCallback(penMoveCallback);
Krom.setGamepadAxisCallback(gamepadAxisCallback);
Krom.setGamepadButtonCallback(gamepadButtonCallback);
kha.audio2.Audio._init();
kha.audio1.Audio._init();
Krom.setAudioCallback(audioCallback);
Scheduler.start();
callback(Window.get(0));
}
public static function initEx(title: String, options: Array<WindowOptions>, windowCallback: Int->Void, callback: Void->Void): Void {}
static function translateWindowMode(value: Null<WindowMode>): Int {
if (value == null) {
return 0;
}
return switch (value) {
case Windowed: 0;
case Fullscreen: 1;
case ExclusiveFullscreen: 2;
}
}
public static function getScreenRotation(): ScreenRotation {
return ScreenRotation.RotationNone;
}
public static function getTime(): Float {
return Krom.getTime() - start;
}
public static function getVsync(): Bool {
return true;
}
public static function getRefreshRate(): Int {
return 60;
}
public static function getSystemId(): String {
return Krom.systemId();
}
public static function vibrate(ms: Int): Void {
// TODO: Implement
}
public static function getLanguage(): String {
return "en"; // TODO: Implement
}
public static function requestShutdown(): Bool {
Krom.requestShutdown();
return true;
}
public static function getMouse(num: Int): Mouse {
return mouse;
}
public static function getPen(num: Int): Pen {
return pen;
}
public static function getKeyboard(num: Int): Keyboard {
return keyboard;
}
public static function lockMouse(): Void {
if (!isMouseLocked()) {
Krom.lockMouse();
for (listener in mouseLockListeners) {
listener();
}
}
}
public static function unlockMouse(): Void {
if (isMouseLocked()) {
Krom.unlockMouse();
for (listener in mouseLockListeners) {
listener();
}
}
}
public static function canLockMouse(): Bool {
return Krom.canLockMouse();
}
public static function isMouseLocked(): Bool {
return Krom.isMouseLocked();
}
public static function notifyOfMouseLockChange(func: Void->Void, error: Void->Void): Void {
if (canLockMouse() && func != null) {
mouseLockListeners.push(func);
}
}
public static function removeFromMouseLockChange(func: Void->Void, error: Void->Void): Void {
if (canLockMouse() && func != null) {
mouseLockListeners.remove(func);
}
}
public static function hideSystemCursor(): Void {
Krom.showMouse(false);
}
public static function showSystemCursor(): Void {
Krom.showMouse(true);
}
static function unload(): Void {}
public static function canSwitchFullscreen(): Bool {
return false;
}
public static function isFullscreen(): Bool {
return false;
}
public static function requestFullscreen(): Void {}
public static function exitFullscreen(): Void {}
public static function notifyOfFullscreenChange(func: Void->Void, error: Void->Void): Void {}
public static function removeFromFullscreenChange(func: Void->Void, error: Void->Void): Void {}
public static function changeResolution(width: Int, height: Int): Void {}
public static function setKeepScreenOn(on: Bool): Void {}
public static function loadUrl(url: String): Void {}
public static function getGamepadId(index: Int): String {
return "unknown";
}
public static function getGamepadVendor(index: Int): String {
return "unknown";
}
public static function setGamepadRumble(index: Int, leftAmount: Float, rightAmount: Float): Void {}
public static function safeZone(): Float {
return 1.0;
}
public static function login(): Void {}
public static function automaticSafeZone(): Bool {
return true;
}
public static function setSafeZone(value: Float): Void {}
public static function unlockAchievement(id: Int): Void {}
public static function waitingForLogin(): Bool {
return false;
}
public static function disallowUserChange(): Void {}
public static function allowUserChange(): Void {}
}

View File

@ -1,56 +1,57 @@
package kha.audio2;
import kha.Sound;
import kha.internal.IntBox;
class Audio {
public static var disableGcInteractions = false;
static var intBox: IntBox = new IntBox(0);
static var buffer: Buffer;
public static function _init() {
var bufferSize = 1024 * 2;
buffer = new Buffer(bufferSize * 4, 2, samplesPerSecond);
}
public static function _callCallback(samples: Int): Void {
if (buffer == null)
return;
if (audioCallback != null) {
intBox.value = samples;
audioCallback(intBox, buffer);
}
else {
for (i in 0...samples) {
buffer.data.set(buffer.writeLocation, 0);
buffer.writeLocation += 1;
if (buffer.writeLocation >= buffer.size) {
buffer.writeLocation = 0;
}
}
}
}
public static function _readSample(): FastFloat {
if (buffer == null)
return 0;
var value = buffer.data.get(buffer.readLocation);
++buffer.readLocation;
if (buffer.readLocation >= buffer.size) {
buffer.readLocation = 0;
}
return value;
}
public static var samplesPerSecond: Int;
public static var audioCallback: IntBox->Buffer->Void;
public static function play(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel {
return null;
}
public static function stream(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel {
return null;
}
}
package kha.audio2;
import kha.Sound;
import kha.internal.IntBox;
class Audio {
public static var disableGcInteractions = false;
static var intBox: IntBox = new IntBox(0);
static var buffer: Buffer;
public static function _init() {
var bufferSize = 1024 * 2;
buffer = new Buffer(bufferSize * 4, 2, 44100);
Audio.samplesPerSecond = 44100;
}
public static function _callCallback(samples: Int): Void {
if (buffer == null)
return;
if (audioCallback != null) {
intBox.value = samples;
audioCallback(intBox, buffer);
}
else {
for (i in 0...samples) {
buffer.data.set(buffer.writeLocation, 0);
buffer.writeLocation += 1;
if (buffer.writeLocation >= buffer.size) {
buffer.writeLocation = 0;
}
}
}
}
public static function _readSample(): Float {
if (buffer == null)
return 0;
var value = buffer.data.get(buffer.readLocation);
buffer.readLocation += 1;
if (buffer.readLocation >= buffer.size) {
buffer.readLocation = 0;
}
return value;
}
public static var samplesPerSecond: Int;
public static var audioCallback: IntBox->Buffer->Void;
public static function play(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel {
return null;
}
public static function stream(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel {
return null;
}
}

View File

@ -59,7 +59,7 @@ class Graphics implements kha.graphics4.Graphics {
}
public function refreshRate(): Int {
return Krom.displayFrequency();
return 60;
}
public function clear(?color: Color, ?depth: Float, ?stencil: Int): Void {

File diff suppressed because it is too large Load Diff

BIN
Krom/Krom

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,12 +2,10 @@
-cp ../Kha/Backends/Krom
-cp ../leenkx/Sources
-cp ../iron/Sources
-cp ../lib/aura/Sources
-cp ../lib/haxebullet/Sources
-cp ../lib/haxerecast/Sources
-cp ../lib/zui/Sources
--macro include('iron', true, null, ['../iron/Sources'])
--macro include('aura', true, null, ['../lib/aura/Sources'])
--macro include('haxebullet', true, null, ['../lib/haxebullet/Sources'])
--macro include('haxerecast', true, null, ['../lib/haxerecast/Sources'])
--macro include('leenkx', true, ['leenkx.network'], ['../leenkx/Sources','../iron/Sources'])

View File

@ -310,9 +310,9 @@ class LeenkxAddonPreferences(AddonPreferences):
layout.label(text="Welcome to Leenkx!")
# Compare version Blender and Leenkx (major, minor)
if bpy.app.version[:2] not in [(4, 4), (4, 2), (3, 6), (3, 3)]:
if bpy.app.version[0] != 4 or bpy.app.version[1] != 2:
box = layout.box().column()
box.label(text="Warning: For Leenkx to work correctly, use a Blender LTS version")
box.label(text="Warning: For Leenkx to work correctly, use a Blender LTS version such as 4.2 | 3.6 | 3.3")
layout.prop(self, "sdk_path")
sdk_path = get_sdk_path(context)

View File

@ -3,10 +3,6 @@
#include "compiled.inc"
#ifdef _CPostprocess
uniform vec4 PPComp17;
#endif
uniform sampler2D tex;
uniform vec2 dir;
uniform vec2 screenSize;
@ -49,12 +45,6 @@ void main() {
res += factor * col;
}
#ifdef _CPostprocess
vec3 AirColor = vec3(PPComp17.x, PPComp17.y, PPComp17.z);
#else
vec3 AirColor = volumAirColor;
#endif
res /= sumfactor;
fragColor = vec4(AirColor * res, 1.0);
fragColor = vec4(volumAirColor * res, 1.0);
}

View File

@ -19,11 +19,6 @@
{
"name": "screenSize",
"link": "_screenSize"
},
{
"name": "PPComp17",
"link": "_PPComp17",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],

View File

@ -5,7 +5,7 @@
uniform sampler2D tex;
#ifdef _CPostprocess
uniform vec4 PPComp13;
uniform vec3 PPComp13;
#endif
in vec2 texCoord;
@ -43,17 +43,13 @@ void main() {
#ifdef _CPostprocess
float max_distort = PPComp13.x;
int num_iter = int(PPComp13.y);
int CAType = int(PPComp13.z);
int on = int(PPComp13.w);
#else
float max_distort = compoChromaticStrength;
int num_iter = compoChromaticSamples;
int CAType = compoChromaticType;
int on = 1;
#endif
// Spectral
if (CAType == 1) {
if (compoChromaticType == 1) {
float reci_num_iter_f = 1.0 / float(num_iter);
vec2 resolution = vec2(1,1);
@ -68,7 +64,7 @@ void main() {
sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t));
}
if (on == 1) fragColor = sumcol / sumw; else fragColor = texture(tex, texCoord);
fragColor = sumcol / sumw;
}
// Simple
@ -77,7 +73,6 @@ void main() {
col.x = texture(tex, texCoord + ((vec2(0.0, 1.0) * max_distort) / vec2(1000.0))).x;
col.y = texture(tex, texCoord + ((vec2(-0.85, -0.5) * max_distort) / vec2(1000.0))).y;
col.z = texture(tex, texCoord + ((vec2(0.85, -0.5) * max_distort) / vec2(1000.0))).z;
if (on == 1) fragColor = vec4(col.x, col.y, col.z, fragColor.w);
else fragColor = texture(tex, texCoord);
fragColor = vec4(col.x, col.y, col.z, fragColor.w);
}
}

View File

@ -4,6 +4,6 @@ in vec2 texCoord;
out vec4 fragColor;
void main() {
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
gl_FragDepth = 1.0;
fragColor = vec4(0.0,0.0,0.0,1.0);
gl_FragDepth = 0.0;
}

View File

@ -4,5 +4,5 @@ in vec2 texCoord;
out vec4 fragColor;
void main() {
gl_FragDepth = 1.0;
gl_FragDepth = 0.0;
}

View File

@ -62,11 +62,8 @@ uniform vec3 PPComp5;
uniform vec3 PPComp6;
uniform vec3 PPComp7;
uniform vec3 PPComp8;
uniform vec3 PPComp11;
uniform vec3 PPComp14;
uniform vec4 PPComp15;
uniform vec4 PPComp16;
uniform vec4 PPComp18;
#endif
// #ifdef _CPos
@ -109,16 +106,6 @@ in vec2 texCoord;
out vec4 fragColor;
#ifdef _CFog
#ifdef _CPostprocess
vec3 FogColor = vec3(PPComp18.x, PPComp18.y, PPComp18.z);
float FogAmountA = PPComp18.w;
float FogAmountB = PPComp11.z;
#else
vec3 FogColor = compoFogColor;
float FogAmountA = compoFogAmountA;
float FogAmountB = compoFogAmountB;
#endif
// const vec3 compoFogColor = vec3(0.5, 0.6, 0.7);
// const float compoFogAmountA = 1.0; // b = 0.01
// const float compoFogAmountB = 1.0; // c = 0.1
@ -131,8 +118,8 @@ out vec4 fragColor;
// }
vec3 applyFog(vec3 rgb, float distance) {
// float fogAmount = 1.0 - exp(-distance * compoFogAmountA);
float fogAmount = 1.0 - exp(-distance * (FogAmountA / 100));
return mix(rgb, FogColor, fogAmount);
float fogAmount = 1.0 - exp(-distance * (compoFogAmountA / 100));
return mix(rgb, compoFogColor, fogAmount);
}
#endif
@ -144,7 +131,7 @@ float ConvertEV100ToExposure(float EV100) {
return 1/0.8 * exp2(-EV100);
}
float ComputeEV(float avgLuminance) {
const float sqAperture = PPComp1.x * PPComp1.x;
const float sqAperture = PPComp1[0].x * PPComp1.x;
const float shutterTime = 1.0 / PPComp1.y;
const float ISO = PPComp1.z;
const float EC = PPComp2.x;
@ -362,22 +349,16 @@ void main() {
#ifdef _CSharpen
#ifdef _CPostprocess
float strengthSharpen = PPComp14.y;
vec3 SharpenColor = vec3(PPComp16.x, PPComp16.y, PPComp16.z);
float SharpenSize = PPComp16.w;
float strengthSharpen = PPComp14.y;
#else
float strengthSharpen = compoSharpenStrength;
vec3 SharpenColor = compoSharpenColor;
float SharpenSize = compoSharpenSize;
#endif
vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * SharpenSize, 0.0).rgb;
vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * SharpenSize, 0.0).rgb;
vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * SharpenSize, 0.0).rgb;
vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * SharpenSize, 0.0).rgb;
vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * 1.5, 0.0).rgb;
vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * 1.5, 0.0).rgb;
vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * 1.5, 0.0).rgb;
vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * 1.5, 0.0).rgb;
vec3 colavg = (col1 + col2 + col3 + col4) * 0.25;
float edgeMagnitude = length(fragColor.rgb - colavg);
fragColor.rgb = mix(fragColor.rgb, SharpenColor, min(edgeMagnitude * strengthSharpen * 2.0, 1.0));
fragColor.rgb += (fragColor.rgb - colavg) * strengthSharpen;
#endif
#ifdef _CFog
@ -426,11 +407,7 @@ void main() {
#endif
#ifdef _CExposure
#ifdef _CPostprocess
fragColor.rgb+=fragColor.rgb*PPComp8.x;
#else
fragColor.rgb+= fragColor.rgb*compoExposureStrength;
#endif
fragColor.rgb += fragColor.rgb * compoExposureStrength;
#endif
#ifdef _CPostprocess
@ -438,13 +415,8 @@ void main() {
#endif
#ifdef _AutoExposure
#ifdef _CPostprocess
float AEStrength = PPComp8.y;
#else
float AEStrength = autoExposureStrength;
#endif
float expo = 2.0 - clamp(length(textureLod(histogram, vec2(0.5, 0.5), 0).rgb), 0.0, 1.0);
fragColor.rgb *= pow(expo, AEStrength * 2.0);
fragColor.rgb *= pow(expo, autoExposureStrength * 2.0);
#endif
// Clamp color to get rid of INF values that don't work for the tone mapping below
@ -508,7 +480,9 @@ fragColor.rgb = min(fragColor.rgb, 65504 * 0.5);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
} else if (PPComp4.x == 10){
fragColor.rgb = tonemapAgXFull(fragColor.rgb);
} //else { fragColor.rgb = vec3(0,1,0); //ERROR}
} else {
fragColor.rgb = vec3(0,1,0); //ERROR
}
#endif
#else

View File

@ -235,16 +235,6 @@
"name": "PPComp15",
"link": "_PPComp15",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp16",
"link": "_PPComp16",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp18",
"link": "_PPComp18",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],

View File

@ -2,12 +2,10 @@
#include "compiled.inc"
#include "std/gbuffer.glsl"
#ifdef _Clusters
#include "std/clusters.glsl"
#endif
#ifdef _Irr
#include "std/shirr.glsl"
#endif
#ifdef _SSS
#include "std/sss.glsl"
#endif
@ -15,9 +13,26 @@
#include "std/ssrs.glsl"
#endif
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
// Environment map
uniform float envmapStrength;
#ifdef _Irr
uniform vec4 shirr[7];
uniform float ambientIntensity;
#include "std/shirr.glsl"
#endif
#include "std/environment_sample.glsl"
#include "std/light.glsl"
// Gbuffer
//uniform sampler2D depthtex; // Raw depth
uniform sampler2D gbufferD; // Depth (cheap)
uniform sampler2D gbuffer0; // Normal/Metal
uniform sampler2D gbuffer1; // Albedo
uniform vec2 cameraProj;
uniform vec3 eye;
uniform vec3 eyeLook;
uniform mat4 invVP;
#ifdef _gbuffer2
uniform sampler2D gbuffer2;
@ -39,10 +54,6 @@ uniform sampler3D voxelsSDF;
uniform float clipmaps[10 * voxelgiClipmapCount];
#endif
uniform float envmapStrength;
#ifdef _Irr
uniform vec4 shirr[7];
#endif
#ifdef _Brdf
uniform sampler2D senvmapBrdf;
#endif
@ -62,11 +73,6 @@ uniform sampler2D ssaotex;
uniform vec2 lightPlane;
#endif
#ifdef _SSRS
//!uniform mat4 VP;
uniform mat4 invVP;
#endif
#ifdef _LightIES
//!uniform sampler2D texIES;
#endif
@ -96,10 +102,6 @@ uniform mat4 invVP;
#endif
#endif
uniform vec2 cameraProj;
uniform vec3 eye;
uniform vec3 eyeLook;
#ifdef _Clusters
uniform vec4 lightsArray[maxLights * 3];
#ifdef _Spot
@ -201,6 +203,7 @@ in vec3 viewRay;
out vec4 fragColor;
void main() {
fragColor = vec4(0.0);
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid
vec3 n;
@ -215,13 +218,22 @@ void main() {
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ
vec2 occspec = unpackFloat2(g1.a);
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
vec3 f0 = surfaceF0(g1.rgb, metallic);
vec3 envl = vec3(0.0);
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec3 v = normalize(eye - p);
float dotNV = max(dot(n, v), 0.0);
// world-space position:
float rawDepth = textureLod(gbufferD, texCoord, 0.0).r;
float clipZ = rawDepth * 2.0 - 1.0; // depth -> clip-space
vec4 clipPos = vec4(texCoord * 2.0 - 1.0, clipZ, 1.0);
vec4 worldPos = invVP * clipPos;
vec3 p = worldPos.xyz / worldPos.w;
vec3 v = normalize(eye - p);
float dotNV = max(dot(n, v), 0.0);
// view-space vector for reflection
vec3 viewPos = getPosView(viewRay, rawDepth, cameraProj);
vec3 viewDir = normalize(-viewPos);
#ifdef _gbuffer2
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
@ -235,24 +247,17 @@ void main() {
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
#endif
// Envmap
#ifdef _Irr
// Sample ambient diffuse lighting
vec3 ambient = sampleDiffuseEnvironment(n);
vec3 envl = shIrradiance(n, shirr);
#ifdef _gbuffer2
if (g2.b >= 0.5) {
ambient = vec3(0.0); // Mask it if g2 says this surface wants no ambient lighting
}
#endif
#ifdef _gbuffer2
if (g2.b < 0.5) {
envl = envl;
} else {
envl = vec3(0.0);
}
#endif
#ifdef _EnvTex
envl /= PI;
#endif
#else
vec3 envl = vec3(0.0);
fragColor.rgb += ambient * ambientIntensity;
#endif
#ifdef _Rad
@ -295,28 +300,37 @@ void main() {
envl.rgb *= textureLod(voxels_ao, texCoord, 0.0).r;
#endif
// if voxel GI isn't enabled, we fall back to SSR (SSR also processes indirect)
#ifndef _VoxelGI
fragColor.rgb = envl;
fragColor.rgb += envl;
#ifndef _SSR
// if SSR is disabled, we fallback to simple environment texture
vec3 fallbackEnvColor = sampleSpecularEnvironment(reflect(viewDir, n), roughness);
fragColor.rgb += fallbackEnvColor;
#endif
#endif
// Show voxels
// vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99);
// vec3 direction = vec3(0.0, 0.0, -1.0);
// vec4 color = vec4(0.0f);
// for(uint step = 0; step < 400 && color.a < 0.99f; ++step) {
// vec3 point = origin + 0.005 * step * direction;
// color += (1.0f - color.a) * textureLod(voxels, point * 0.5 + 0.5, 0);
// }
// fragColor.rgb += color.rgb;
// Show SSAO
// fragColor.rgb = texture(ssaotex, texCoord).rrr;
// show voxel GI
#ifdef _VoxelGI
// Show voxels
vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99);
vec3 direction = vec3(0.0, 0.0, -1.0);
vec4 color = vec4(0.0f);
for(uint step = 0; step < 400 && color.a < 0.99f; ++step) {
vec3 point = origin + 0.005 * step * direction;
color += (1.0f - color.a) * textureLod(voxels, point * 0.5 + 0.5, 0);
}
fragColor.rgb += color.rgb;
#endif
// show SSAO
#ifdef _SSAO
// #ifdef _RTGI
// fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb;
// #else
fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
// #endif
fragColor.rgb = texture(ssaotex, texCoord).rrr;
// #ifdef _RTGI
// fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb;
// #else
fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
// #endif
#endif
#ifdef _EmissionShadeless
@ -464,7 +478,8 @@ void main() {
#endif
#ifdef _Clusters
float viewz = linearize(depth * 0.5 + 0.5, cameraProj);
// compute depth for clustering: use the view-space Z component (linearized depth)
float viewz = viewPos.z;
int clusterI = getClusterI(texCoord, viewz, cameraPlane);
int numLights = int(texelFetch(clustersData, ivec2(clusterI, 0), 0).r * 255);
@ -508,6 +523,7 @@ void main() {
#ifdef _MicroShadowing
, occspec.x
#endif
// TODO: Cleanup. Probably broken
#ifdef _SSRS
, gbufferD, invVP, eye
#endif

View File

@ -49,10 +49,6 @@
"link": "$brdf.png",
"ifdef": ["_Brdf"]
},
{
"name": "cameraProj",
"link": "_cameraPlaneProj"
},
{
"name": "envmapStrength",
"link": "_envmapStrength"

View File

@ -2,22 +2,13 @@
#include "compiled.inc"
#ifdef _CPostprocess
uniform vec3 PPComp8;
#endif
uniform sampler2D tex;
in vec2 texCoord;
out vec4 fragColor;
void main() {
#ifdef _CPostprocess
fragColor.a = 0.01 * PPComp8.z;
#else
fragColor.a = 0.01 * autoExposureSpeed;
#endif
fragColor.a = 0.01 * autoExposureSpeed;
fragColor.rgb = textureLod(tex, vec2(0.5, 0.5), 0.0).rgb +
textureLod(tex, vec2(0.2, 0.2), 0.0).rgb +
textureLod(tex, vec2(0.8, 0.2), 0.0).rgb +

View File

@ -8,13 +8,7 @@
"blend_source": "source_alpha",
"blend_destination": "inverse_source_alpha",
"blend_operation": "add",
"links": [
{
"name": "PPComp8",
"link": "_PPComp8",
"ifdef": ["_CPostprocess"]
}
],
"links": [],
"texture_params": [],
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "histogram_pass.frag.glsl"

View File

@ -23,8 +23,9 @@ void main() {
// fullscreen triangle: http://de.slideshare.net/DevCentralAMD/vertex-shader-tricks-bill-bilodeau
// gl_Position = vec4((gl_VertexID % 2) * 4.0 - 1.0, (gl_VertexID / 2) * 4.0 - 1.0, 0.0, 1.0);
// NDC (at the back of cube)
vec4 v = vec4(pos.x, pos.y, 1.0, 1.0);
// For reverse-Z, the “far” plane lives at NDC z = 0
vec4 ndcFar = vec4(pos.x, pos.y, 0.0, 1.0);
vec4 v = invVP * ndcFar;
v = vec4(invVP * v);
v.xyz /= v.w;
viewRay = v.xyz - eye;

View File

@ -19,8 +19,9 @@ void main() {
gl_Position = vec4(pos.xy, 0.0, 1.0);
// NDC (at the back of cube)
vec4 v = vec4(pos.x, pos.y, 1.0, 1.0);
v = vec4(invP * v);
// For reverse-Z, far plane sits at NDC z = 0
vec4 clip = vec4(pos.x, pos.y, 0.0, 1.0);
vec4 v = invP * clip;
// reconstruct a viewspace direction
viewRay = vec3(v.xy / v.z, 1.0);
}

View File

@ -1,21 +1,35 @@
// TODO: Integrate with Blender UI
// TODO: Option to disable cone tracing
#version 450
#include "compiled.inc"
#include "std/math.glsl"
#include "std/gbuffer.glsl"
uniform sampler2D tex;
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; // Normal, roughness
uniform sampler2D gbuffer1; // basecol, spec
uniform mat4 P;
uniform mat3 V3;
uniform vec2 cameraProj;
#ifdef _CPostprocess
uniform vec3 PPComp9;
uniform vec3 PPComp10;
// Environment map
uniform float envmapStrength;
#ifdef _Irr
uniform vec4 shirr[7];
uniform float ambientIntensity;
#include "std/shirr.glsl"
#endif
#include "std/environment_sample.glsl"
uniform sampler2D tex; // Environment map
//uniform sampler2D depthtex; // Full Depth buffer
uniform sampler2D gbufferD; // Cheap Depth buffer
uniform sampler2D gbuffer0; // Normal, roughness
uniform sampler2D gbuffer1; // Base color, spec
uniform mat4 P; // Projection matrix
uniform mat3 V3; // View matrix
uniform vec2 cameraProj; // Camera projection params
uniform vec2 invScreenSize; // (1.0/width, 1.0/height)
const float ssrPrecision = 0.0; // 0.0 - 100.0 (user slider control)
//const float rayThickness = 0.1; // TODO: Adds some thickness to prevent gaps
uniform int ssrConetraceMode = 2; // 0 = no weighting, 1 = light, 2 = strong
const int ssrConetraceTaps = 18; // Number of taps (higher = more precision)
in vec3 viewRay;
in vec2 texCoord;
@ -24,98 +38,214 @@ out vec4 fragColor;
vec3 hitCoord;
float depth;
const int numBinarySearchSteps = 7;
const int maxSteps = int(ceil(1.0 / ssrRayStep) * ssrSearchDist);
const int baseBinarySearchSteps = 10; // Parameterize?
const int baseMaxSteps = int(ceil(1.0 / ssrRayStep) * ssrSearchDist);
int dynamicBinarySearchSteps() {
return int(mix(7.0, 20.0, clamp(ssrPrecision / 100.0, 0.0, 1.0)));
}
int dynamicMaxSteps() {
return int(mix(float(baseMaxSteps), 300.0, clamp(ssrPrecision / 100.0, 0.0, 1.0)));
}
vec2 getProjectedCoord(const vec3 hit) {
vec4 projectedCoord = P * vec4(hit, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
#ifdef _InvY
projectedCoord.y = 1.0 - projectedCoord.y;
#endif
return projectedCoord.xy;
vec4 clip = P * vec4(hit, 1.0);
vec2 uv = clip.xy / clip.w;
uv = uv * 0.5 + 0.5;
#ifdef _InvY
uv.y = 1.0 - uv.y;
#endif
uv = clamp(uv, 0.0, 1.0);
uv += invScreenSize * 0.5; // half-pixel offset
return uv;
}
float getDeltaDepth(const vec3 hit) {
depth = textureLod(gbufferD, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0;
vec3 viewPos = getPosView(viewRay, depth, cameraProj);
return viewPos.z - hit.z;
vec2 screenUV = getProjectedCoord(hit);
float raw = textureLod(gbufferD, screenUV, 0.0).r;
float sampledDepth = raw * 2.0 - 1.0;
float linearSampledDepth = linearize(sampledDepth, cameraProj);
return linearSampledDepth - hit.z;
}
vec4 binarySearch(vec3 dir) {
float ddepth;
for (int i = 0; i < numBinarySearchSteps; i++) {
dir *= 0.5;
hitCoord -= dir;
ddepth = getDeltaDepth(hitCoord);
if (ddepth < 0.0) hitCoord += dir;
}
// Ugly discard of hits too far away
#ifdef _CPostprocess
if (abs(ddepth) > PPComp9.z / 500) return vec4(0.0);
#else
if (abs(ddepth) > ssrSearchDist / 500) return vec4(0.0);
#endif
return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
float ddepth;
for (int i = 0; i < dynamicBinarySearchSteps(); i++) {
dir *= 0.5;
hitCoord -= dir;
ddepth = getDeltaDepth(hitCoord);
if (ddepth < 0.0) hitCoord += dir;
}
vec2 projectedCoord = getProjectedCoord(hitCoord);
float pixelSize = length(fwidth(projectedCoord)) * 0.5;
float epsilon = max(pixelSize * 10.0, 0.01);
if (abs(ddepth) > epsilon) return vec4(0.0);
hitCoord.xy = clamp(projectedCoord, 0.0, 1.0);
return vec4(projectedCoord, 0.0, 1.0);
}
vec4 rayCast(vec3 dir) {
#ifdef _CPostprocess
dir *= PPComp9.x;
#else
dir *= ssrRayStep;
#endif
for (int i = 0; i < maxSteps; i++) {
hitCoord += dir;
if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
vec4 rayCast(vec3 dir, float roughness) {
vec3 stepDir = normalize(dir);
// Apply small jitter if high precision
if (ssrPrecision > 80.0 && roughness > 0.05) {
stepDir = normalize(stepDir + vec3(rand2(texCoord), 0.0) * 0.01);
}
return vec4(0.0);
float distance = length(hitCoord - viewRay);
float stepDivisor = mix(100.0, 300.0, clamp(ssrPrecision / 100.0, 0.0, 1.0));
float stepSize = max(0.01, distance / stepDivisor);
float maxStepSize = 0.1;
for (int i = 0; i < dynamicMaxSteps(); i++) {
hitCoord += stepDir * stepSize;
vec2 projCoord = getProjectedCoord(hitCoord);
float sampledDepth = textureLod(gbufferD, projCoord, 0.0).r;
float depthTolerance = fwidth(sampledDepth) * 2.0; // Dynamic tolerance
if (getDeltaDepth(hitCoord) > depthTolerance) {
return binarySearch(stepDir);
}
stepSize = min(stepSize * 1.1, maxStepSize);
}
return vec4(0.0);
}
vec3 coneTraceApprox(vec3 reflDir, float roughness) {
vec3 result = vec3(0.0);
float totalWeight = 0.0;
float randAngle = hash12(texCoord) * 6.2831853;
mat2 rot = mat2(cos(randAngle), -sin(randAngle), sin(randAngle), cos(randAngle));
float coneSpread = roughness * 0.5; // widen based on roughness
for (int i = 0; i < ssrConetraceTaps; ++i) {
float angle = float(i) / float(ssrConetraceTaps) * 6.2831853;
vec2 offset = rot * vec2(cos(angle), sin(angle)) * coneSpread;
vec3 sampleDir = normalize(reflDir + vec3(offset, 0.0));
float weight = 1.0;
if (ssrConetraceMode == 1) {
weight = pow(max(dot(reflDir, sampleDir), 0.0), 2.0); // Light cosine lobe
}
else if (ssrConetraceMode == 2) {
weight = pow(max(dot(reflDir, sampleDir), 0.0), 8.0); // Strong GGX lobe
}
// Approximate sampling by using tex at reflection direction
vec2 envUV = envMapEquirect(sampleDir);
vec3 sampleColor = textureLod(tex, envUV, 0.0).rgb;
result += sampleColor * weight;
totalWeight += weight;
}
return result / max(totalWeight, 0.0001);
}
vec3 tangentSpaceGGX(vec3 N, float roughness) {
float a = roughness * roughness;
float phi = rand(texCoord) * 6.2831853;
float cosTheta = sqrt((1.0 - rand(texCoord)) / (1.0 + (a * a - 1.0) * rand(texCoord)));
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
vec3 T = normalize(cross(N, vec3(0.0, 1.0, 0.0)));
if (length(T) < 0.01) T = normalize(cross(N, vec3(1.0, 0.0, 0.0)));
vec3 B = cross(N, T);
return normalize(T * cos(phi) * sinTheta + B * sin(phi) * sinTheta + N * cosTheta);
}
void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = unpackFloat(g0.b).y;
if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; }
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; }
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = unpackFloat(g0.b).y;
if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; }
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
if (d == 1.0) { fragColor.rgb = vec3(0.0); return; }
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; }
vec2 enc = g0.rg;
vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y);
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
n = normalize(n);
// sample raw depth, bail if empty
float dRaw = textureLod(gbufferD, texCoord, 0.0).r;
if (dRaw == 0.0) { fragColor.rgb = vec3(0.0); return; }
// convert to NDC z before reconstructing
float d = dRaw * 2.0 - 1.0;
vec3 viewNormal = V3 * n;
vec3 viewPos = getPosView(viewRay, d, cameraProj);
vec3 reflected = reflect(viewPos, viewNormal);
hitCoord = viewPos;
vec3 n = decode_oct(g0.rg);
vec3 viewNormal = V3 * n;
viewNormal = normalize(mix(viewNormal, normalize(-viewRay), 0.05)); // slightly bias the normal toward the view direction at glancing angles
vec3 viewPos = getPosView(viewRay, d, cameraProj);
vec3 viewDir = normalize(-viewPos);
vec3 idealReflection = reflect(normalize(viewPos), viewNormal);
hitCoord = viewPos;
#ifdef _CPostprocess
vec3 dir = reflected * (1.0 - rand(texCoord) * PPComp10.y * roughness) * 2.0;
// Apply GGX importance sampling in tangent space
vec3 jitteredDir = tangentSpaceGGX(viewNormal, roughness);
// Blend based on roughness (0 = perfect mirror, 1 = fully scattered)
vec3 dir = normalize(mix(idealReflection, jitteredDir, roughness));
vec4 coords = rayCast(dir, roughness);
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0);
float reflectivity = 1.0 - roughness;
#ifdef _CPostprocess
// Postprocess mode intensity calculation...
#else
vec3 dir = reflected * (1.0 - rand(texCoord) * ssrJitter * roughness) * 2.0;
float intensity = 0.0;
if (coords.w > 0.0) {
// Ray hit in screen-space
intensity = pow(reflectivity, ssrFalloffExp) * screenEdgeFactor *
clamp(-idealReflection.z, 0.0, 1.0) *
clamp((ssrSearchDist - length(viewPos - hitCoord)) * (1.0 / ssrSearchDist), 0.0, 1.0);
}
else if (roughness < 0.7) {
// Ray miss, roughness low enough: do cone trace approximation
vec3 coneColor = coneTraceApprox(idealReflection, roughness);
vec3 envCol = sampleSpecularEnvironment(idealReflection, roughness);
coneColor = clamp(coneColor, 0.0, 1.0);
envCol = clamp(envCol, 0.0, 1.0);
vec3 finalColor = mix(envCol, mix(envCol, coneColor, intensity), coords.w);
fragColor.rgb = finalColor * 0.5; // match previous intensity scaling
return;
}
else {
// Ray miss, roughness too high: fallback to environment map
vec3 fallbackEnvColor = sampleSpecularEnvironment(reflect(viewDir, n), roughness);
fragColor.rgb = fallbackEnvColor;
return;
}
#endif
// * max(ssrMinRayStep, -viewPos.z)
vec4 coords = rayCast(dir);
vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb; // SSR reflection
vec3 envCol = textureLod(tex, texCoord, 0.0).rgb; // Background environment
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0);
float reflectivity = 1.0 - roughness;
#ifdef _CPostprocess
float intensity = pow(reflectivity, PPComp10.x) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * clamp((PPComp9.z - length(viewPos - hitCoord)) * (1.0 / PPComp9.z), 0.0, 1.0) * coords.w;
#else
float intensity = pow(reflectivity, ssrFalloffExp) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * clamp((ssrSearchDist - length(viewPos - hitCoord)) * (1.0 / ssrSearchDist), 0.0, 1.0) * coords.w;
#endif
intensity = clamp(intensity, 0.0, 1.0);
vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb;
intensity = clamp(intensity, 0.0, 1.0);
reflCol = clamp(reflCol, 0.0, 1.0);
fragColor.rgb = reflCol * intensity * 0.5;
}
envCol = clamp(envCol, 0.0, 1.0);
// Roughness-based fade (smoothstep)
float roughFade = smoothstep(0.2, 0.7, roughness);
float ssrVisibility = coords.w * (1.0 - roughFade);
// Blend SSR
vec3 finalColor = mix(envCol, reflCol, ssrVisibility);
fragColor.rgb = finalColor;
}

View File

@ -4,6 +4,7 @@
"name": "ssr_pass",
"depth_write": false,
"compare_mode": "always",
"blend_mode": "replace",
"cull_mode": "none",
"links": [
{
@ -23,14 +24,12 @@
"link": "_cameraPlaneProj"
},
{
"name": "PPComp9",
"link": "_PPComp9",
"ifdef": ["_CPostprocess"]
"name": "coneTraceMode",
"link": "_coneTraceMode"
},
{
"name": "PPComp10",
"link": "_PPComp10",
"ifdef": ["_CPostprocess"]
"name": "coneTraceTapCount",
"link": "_coneTraceTapCount"
}
],
"texture_params": [],

View File

@ -1,8 +1,10 @@
#ifndef _BRDF_GLSL_
#define _BRDF_GLSL_
// http://xlgames-inc.github.io/posts/improvedibl/
// http://blog.selfshadow.com/publications/s2013-shading-course/
// Constants
//const float PI = 3.1415926535;
// Fresnel-Schlick with optimized exponential approximation
vec3 f_schlick(const vec3 f0, const float vh) {
return f0 + (1.0 - f0) * exp2((-5.55473 * vh - 6.98316) * vh);
}
@ -11,82 +13,11 @@ float v_smithschlick(const float nl, const float nv, const float a) {
return 1.0 / ((nl * (1.0 - a) + a) * (nv * (1.0 - a) + a));
}
//Uncorrelated masking/shadowing (info below) function
//Because it is uncorrelated, G1(NdotL, a) gives us shadowing, and G1(NdotV, a) gives us masking function.
//Approximation from: https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf
float g1_approx(const float NdotX, const float alpha)
{
return (2.0 * NdotX) * (1.0 / (NdotX * (2.0 - alpha) + alpha));
}
//Uncorrelated masking-shadowing function
//Approximation from: https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf
float g2_approx(const float NdotL, const float NdotV, const float alpha)
{
vec2 helper = (2.0 * vec2(NdotL, NdotV)) * (1.0 / (vec2(NdotL, NdotV) * (2.0 - alpha) + alpha));
return max(helper.x * helper.y, 0.0); //This can go negative, let's fix that
}
float d_ggx(const float nh, const float a) {
float a2 = a * a;
float denom = nh * nh * (a2 - 1.0) + 1.0;
denom = max(denom * denom, 0.00006103515625 /* 2^-14 = smallest possible half float value, prevent div by zero */);
return a2 * (1.0 / 3.1415926535) / denom;
}
vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
float a = roughness * roughness;
return d_ggx(nh, a) * g2_approx(nl, nv, a) * f_schlick(f0, vh) / max(4.0 * nv, 1e-5); //NdotL cancels out later
}
// John Hable - Optimizing GGX Shaders
// http://filmicworlds.com/blog/optimizing-ggx-shaders-with-dotlh/
vec3 specularBRDFb(const vec3 f0, const float roughness, const float dotNL, const float dotNH, const float dotLH) {
// D
const float pi = 3.1415926535;
float alpha = roughness * roughness;
float alphaSqr = alpha * alpha;
float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0;
float D = alphaSqr / (pi * denom * denom);
// F
const float F_a = 1.0;
float F_b = pow(1.0 - dotLH, 5.0);
// V
float vis;
float k = alpha / 2.0;
float k2 = k * k;
float invK2 = 1.0 - k2;
vis = 1.0 / (dotLH * dotLH * invK2 + k2);
vec2 FV_helper = vec2((F_a - F_b) * vis, F_b * vis);
vec3 FV = f0 * FV_helper.x + FV_helper.y;
vec3 specular = clamp(dotNL, 0.0, 1.0) * D * FV;
return specular / 4.0; // TODO: get rid of / 4.0
}
vec3 orenNayarDiffuseBRDF(const vec3 albedo, const float roughness, const float nv, const float nl, const float vh) {
float a = roughness * roughness;
float s = a;
float s2 = s * s;
float vl = 2.0 * vh * vh - 1.0; // Double angle identity
float Cosri = vl - nv * nl;
float C1 = 1.0 - 0.5 * s2 / (s2 + 0.33);
float test = 1.0;
if (Cosri >= 0.0) test = (1.0 / (max(nl, nv)));
float C2 = 0.45 * s2 / (s2 + 0.09) * Cosri * test;
return albedo * max(0.0, nl) * (C1 + C2) * (1.0 + roughness * 0.5);
}
vec3 lambertDiffuseBRDF(const vec3 albedo, const float nl) {
return albedo * nl;
}
vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
return mix(baseColor, vec3(0.0), metalness);
}
vec3 surfaceF0(const vec3 baseColor, const float metalness) {
return mix(vec3(0.04), baseColor, metalness);
denom = max(denom * denom, 2e-6);
return a2 / (PI * denom);
}
float getMipFromRoughness(const float roughness, const float numMipmaps) {
@ -94,47 +25,64 @@ float getMipFromRoughness(const float roughness, const float numMipmaps) {
return roughness * numMipmaps;
}
float wardSpecular(vec3 N, vec3 H, float dotNL, float dotNV, float dotNH, vec3 fiberDirection, float shinyParallel, float shinyPerpendicular) {
if(dotNL < 0.0 || dotNV < 0.0) {
return 0.0;
}
// fiberDirection - parse from rotation
// shinyParallel - roughness
// shinyPerpendicular - anisotropy
vec3 specularBRDF(vec3 N, vec3 V, vec3 L, vec3 F0, float roughness)
{
vec3 H = normalize(V + L);
vec3 fiberParallel = normalize(fiberDirection);
vec3 fiberPerpendicular = normalize(cross(N, fiberDirection));
float dotXH = dot(fiberParallel, H);
float dotYH = dot(fiberPerpendicular, H);
const float PI = 3.1415926535;
float coeff = sqrt(dotNL/dotNV) / (4.0 * PI * shinyParallel * shinyPerpendicular);
float theta = (pow(dotXH/shinyParallel, 2.0) + pow(dotYH/shinyPerpendicular, 2.0)) / (1.0 + dotNH);
return clamp(coeff * exp(-2.0 * theta), 0.0, 1.0);
float NdotL = max(dot(N, L), 0.0);
float NdotV = max(dot(N, V), 0.0);
float NdotH = max(dot(N, H), 0.0);
float VdotH = max(dot(V, H), 0.0);
float alpha = roughness * roughness;
float D = d_ggx(NdotH, alpha);
float k = alpha / 2.0;
float G_V = NdotV / (NdotV * (1.0 - k) + k + 1e-5);
float G_L = NdotL / (NdotL * (1.0 - k) + k + 1e-5);
float G = G_V * G_L;
vec3 F = f_schlick(F0, VdotH);
return F * D * G / max(4.0 * NdotL * NdotV, 1e-5);
}
// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
// vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV) {
// const vec4 c0 = { -1, -0.0275, -0.572, 0.022 };
// const vec4 c1 = { 1, 0.0425, 1.04, -0.04 };
// vec4 r = Roughness * c0 + c1;
// float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
// vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
// return SpecularColor * AB.x + AB.y;
// }
// float EnvBRDFApproxNonmetal(float Roughness, float NoV) {
// // Same as EnvBRDFApprox( 0.04, Roughness, NoV )
// const vec2 c0 = { -1, -0.0275 };
// const vec2 c1 = { 1, 0.0425 };
// vec2 r = Roughness * c0 + c1;
// return min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
// }
float D_Approx(const float Roughness, const float RoL) {
float a = Roughness * Roughness;
float a2 = a * a;
float rcp_a2 = 1.0 / a2;//rcp(a2);
// 0.5 / ln(2), 0.275 / ln(2)
float c = 0.72134752 * rcp_a2 + 0.39674113;
return rcp_a2 * exp2( c * RoL - c );
vec3 burleyDiffuseBRDF(vec3 N, vec3 V, vec3 L, vec3 albedo, float roughness)
{
float NdotL = max(dot(N, L), 0.0);
float NdotV = max(dot(N, V), 0.0);
float LdotH = max(dot(L, normalize(L + V)), 0.0);
float FD90 = 0.5 + 2.0 * LdotH * LdotH * roughness;
float FL = pow(1.0 - NdotL, 5.0);
float FV = pow(1.0 - NdotV, 5.0);
float diffuse = (1.0 + (FD90 - 1.0) * FL) * (1.0 + (FD90 - 1.0) * FV);
return albedo * (1.0 / PI) * diffuse * NdotL;
}
// Energy-conserving material albedo (fades out for metals)
vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
return baseColor * (1.0 - metalness);
}
// Metal-aware F0 blending
vec3 surfaceF0(vec3 baseColor, float metalness) {
return mix(vec3(0.04), baseColor, metalness);
}
// LUT-based approximation of IBL BRDF (Unreal-style)
vec2 EnvBRDFApprox(float Roughness, float NoV) {
const vec4 c0 = vec4(-1, -0.0275, -0.572, 0.022);
const vec4 c1 = vec4(1, 0.0425, 1.04, -0.04);
vec4 r = Roughness * c0 + c1;
float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
return vec2(-1.04, 1.04) * a004 + r.zw;
}
vec3 IBLSpecularApprox(vec3 specColor, float roughness, float NoV) {
vec2 brdf = EnvBRDFApprox(roughness, NoV);
return specColor * brdf.x + brdf.y;
}
#endif

View File

@ -97,9 +97,9 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
vec3 aniso_direction = -dir;
vec3 face_offset = vec3(
aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4.0 : 5.0
aniso_direction.x > 0.0 ? 0 : 1,
aniso_direction.y > 0.0 ? 2 : 3,
aniso_direction.z > 0.0 ? 4 : 5
) / (6 + DIFFUSE_CONE_COUNT);
vec3 direction_weight = abs(dir);
@ -201,9 +201,9 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
vec3 aniso_direction = -dir;
vec3 face_offset = vec3(
aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4.0 : 5.0
aniso_direction.x > 0.0 ? 0 : 1,
aniso_direction.y > 0.0 ? 2 : 3,
aniso_direction.z > 0.0 ? 4 : 5
) / (6 + DIFFUSE_CONE_COUNT);
vec3 direction_weight = abs(dir);
@ -272,9 +272,9 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
vec3 aniso_direction = -dir;
vec3 face_offset = vec3(
aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4.0 : 5.0
aniso_direction.x > 0.0 ? 0 : 1,
aniso_direction.y > 0.0 ? 2 : 3,
aniso_direction.z > 0.0 ? 4 : 5
) / (6 + DIFFUSE_CONE_COUNT);
vec3 direction_weight = abs(dir);
float coneCoefficient = 2.0 * tan(aperture * 0.5);

View File

@ -0,0 +1,28 @@
#ifndef _ENVIRONMENT_SAMPLE_GLSL_
#define _ENVIRONMENT_SAMPLE_GLSL_
// Sample diffuse ambient environment lighting (irradiance)
vec3 sampleDiffuseEnvironment(vec3 normal) {
#ifdef _Irr
vec3 envl = shIrradiance(normal, shirr);
#ifdef _EnvTex
envl /= PI;
#endif
return envl;
#else
return vec3(0.0);
#endif
}
// Sample specular environment reflection (skybox or cubemap)
vec3 sampleSpecularEnvironment(vec3 viewDir, float roughness) {
#ifdef _EnvTex
return textureLod(texEnvironment, viewDir, roughness * 8.0).rgb;
#else
return vec3(0.0);
#endif
}
#endif

View File

@ -1,5 +1,6 @@
#ifndef _GBUFFER_GLSL_
#define _GBUFFER_GLSL_
#include "std/math.glsl"
vec2 octahedronWrap(const vec2 v) {
return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0));
@ -13,23 +14,17 @@ vec3 getNor(const vec2 enc) {
return n;
}
vec3 getPosView(const vec3 viewRay, const float depth, const vec2 cameraProj) {
float linearDepth = cameraProj.y / (cameraProj.x - depth);
//float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
return viewRay * linearDepth;
vec3 getPosView(const vec3 viewRay, float depth, vec2 cameraProj) {
return viewRay * linearize(depth, cameraProj);
}
vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
// eyeLook, viewRay should be normalized
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float viewZDist = dot(eyeLook, viewRay);
vec3 wposition = eye + viewRay * (linearDepth / viewZDist);
return wposition;
vec3 getPos(const vec3 eye, mat3 invV, const vec3 viewRay, float depth, vec2 cameraProj) {
vec3 pVS = viewRay * linearize(depth, cameraProj);
return eye + invV * pVS; // invV == inverse of view-rotation
}
vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
// eyeLook, viewRay should be normalized
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float linearDepth = linearize(depth, cameraProj);
float viewZDist = dot(eyeLook, viewRay);
vec3 wposition = viewRay * (linearDepth / viewZDist);
return wposition;
@ -47,30 +42,34 @@ vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) {
return pos.xyz;
}
#if defined(HLSL) || defined(METAL)
vec3 getPosView2(const mat4 invP, const float depth, vec2 coord) {
coord.y = 1.0 - coord.y;
#else
vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) {
#endif
//#if defined(HLSL) || defined(METAL)
//vec3 getPosView2(const mat4 invP, const float depth, vec2 coord) {
// coord.y = 1.0 - coord.y;
//#else
vec3 getPosView2(mat4 invP, float depth, vec2 coord) {
vec4 clip = vec4(coord * 2.0 - 1.0, depth, 1.0);
vec4 view = invP * clip;
return view.xyz / view.w;
//#endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invP * pos;
pos.xyz /= pos.w;
return pos.xyz;
}
#if defined(HLSL) || defined(METAL)
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, vec2 coord) {
coord.y = 1.0 - coord.y;
#else
// Reconstruct view-space position from inverse View×Proj
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec2 coord) {
vec2 uv = coord;
#if defined(HLSL) || defined(METAL)
uv.y = 1.0 - uv.y;
#endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invVP * pos;
pos.xyz /= pos.w;
return pos.xyz - eye;
vec4 clip = vec4(uv * 2.0 - 1.0, depth, 1.0);
vec4 world = invVP * clip;
world.xyz /= world.w;
return world.xyz - eye;
}
// Updated to support separate roughness/metalness storage
float packFloat(const float f1, const float f2) {
return floor(f1 * 100.0) + min(f2, 1.0 - 1.0 / 100.0);
}
@ -80,7 +79,6 @@ vec2 unpackFloat(const float f) {
}
float packFloat2(const float f1, const float f2) {
// Higher f1 = less precise f2
return floor(f1 * 255.0) + min(f2, 1.0 - 1.0 / 100.0);
}
@ -101,24 +99,21 @@ vec3 decodeRGBM(const vec4 rgbm) {
return rgbm.rgb * rgbm.a * maxRange;
}
vec2 signNotZero(vec2 v)
{
vec2 signNotZero(vec2 v) {
return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
}
vec2 encode_oct(vec3 v)
{
// Project the sphere onto the octahedron, and then onto the xy plane
vec2 encode_oct(vec3 v) {
vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z)));
// Reflect the folds of the lower hemisphere over the diagonals
return (v.z <= 0.0) ? ((1.0 - abs(p.yx)) * signNotZero(p)) : p;
}
vec3 decode_oct(vec2 e)
{
vec3 decode_oct(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
if (v.z < 0) v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);
return normalize(v);
if (v.z < 0.0) {
v.xy = (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0));
}
return normalize(v);
}
uint encNor(vec3 n) {
@ -147,9 +142,6 @@ vec3 decNor(uint val) {
return normal;
}
/**
Packs a float in [0, 1] and an integer in [0..15] into a single 16 bit float value.
**/
float packFloatInt16(const float f, const uint i) {
const uint numBitFloat = 12;
const float maxValFloat = float((1 << numBitFloat) - 1);
@ -165,9 +157,8 @@ void unpackFloatInt16(const float val, out float f, out uint i) {
const float maxValFloat = float((1 << numBitFloat) - 1);
const uint bitsValue = uint(val);
i = bitsValue >> numBitFloat;
f = (bitsValue & ~(0xF << numBitFloat)) / maxValFloat;
}
#endif
#endif

View File

@ -1,239 +1,241 @@
#ifndef _LIGHT_GLSL_
#define _LIGHT_GLSL_
#include "compiled.inc"
#include "std/brdf.glsl"
#include "std/math.glsl"
#ifdef _ShadowMap
#include "std/shadows.glsl"
#endif
#ifdef _VoxelShadow
#include "std/conetrace.glsl"
//!uniform sampler2D voxels_shadows;
#endif
#ifdef _LTC
#include "std/ltc.glsl"
#endif
#ifdef _LightIES
#include "std/ies.glsl"
#endif
#ifdef _SSRS
#include "std/ssrs.glsl"
#endif
#ifdef _Spot
#include "std/light_common.glsl"
#endif
#ifdef _ShadowMap
#ifdef _SinglePoint
#ifdef _Spot
#ifndef _LTC
uniform sampler2DShadow shadowMapSpot[1];
uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1];
#endif
#else
uniform samplerCubeShadow shadowMapPoint[1];
uniform samplerCube shadowMapPointTransparent[1];
uniform vec2 lightProj;
#endif
#endif
#ifdef _Clusters
#ifdef _SingleAtlas
//!uniform sampler2DShadow shadowMapAtlas;
//!uniform sampler2D shadowMapAtlasTransparent;
#endif
uniform vec2 lightProj;
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasPoint;
uniform sampler2D shadowMapAtlasPointTransparent;
#endif
#else
uniform samplerCubeShadow shadowMapPoint[4];
uniform samplerCube shadowMapPointTransparent[4];
#endif
#ifdef _Spot
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasSpot;
uniform sampler2D shadowMapAtlasSpotTransparent;
#endif
#else
uniform sampler2DShadow shadowMapSpot[4];
uniform sampler2D shadowMapSpotTransparent[4];
#endif
uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif
#endif
#endif
#ifdef _LTC
uniform vec3 lightArea0;
uniform vec3 lightArea1;
uniform vec3 lightArea2;
uniform vec3 lightArea3;
uniform sampler2D sltcMat;
uniform sampler2D sltcMag;
#ifdef _ShadowMap
#ifndef _Spot
#ifdef _SinglePoint
uniform sampler2DShadow shadowMapSpot[1];
uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1];
#endif
#ifdef _Clusters
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif
#endif
#endif
#endif
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
const vec3 albedo, const float rough, const float spec, const vec3 f0
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow, bool transparent
#endif
#ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
#ifdef _VoxelShadow
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount]
#endif
#ifdef _MicroShadowing
, float occ
#endif
#ifdef _SSRS
, sampler2D gbufferD, mat4 invVP, vec3 eye
#endif
) {
vec3 ld = lp - p;
vec3 l = normalize(ld);
vec3 h = normalize(v + l);
float dotNH = max(0.0, dot(n, h));
float dotVH = max(0.0, dot(v, h));
float dotNL = max(0.0, dot(n, l));
#ifdef _LTC
float theta = acos(dotNV);
vec2 tuv = vec2(rough, theta / (0.5 * PI));
tuv = tuv * LUT_SCALE + LUT_BIAS;
vec4 t = textureLod(sltcMat, tuv, 0.0);
mat3 invM = mat3(
vec3(1.0, 0.0, t.y),
vec3(0.0, t.z, 0.0),
vec3(t.w, 0.0, t.x));
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
#else
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
#endif
direct *= attenuate(distance(p, lp));
direct *= lightCol;
#ifdef _MicroShadowing
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
#endif
#ifdef _SSRS
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
#endif
#ifdef _VoxelShadow
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy).r) * voxelgiShad;
#endif
#ifdef _LTC
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
#endif
}
#endif
return direct;
#endif
#ifdef _Spot
if (isSpot) {
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
#ifdef _ShadowMapAtlas
direct *= shadowTest(
#ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
, lPos.xyz / lPos.w, bias, transparent
);
#else
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
#endif
#endif
}
#endif
return direct;
}
#endif
#ifdef _LightIES
direct *= iesAttenuation(-l);
#endif
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
#ifndef _Spot
direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
#endif
#endif
#ifdef _Clusters
#ifdef _ShadowMapAtlas
direct *= PCFFakeCube(
#ifndef _SingleAtlas
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
, ld, -l, bias, lightProj, n, index, transparent
);
#else
if (index == 0) direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], shadowMapPointTransparent[1], ld, -l, bias, lightProj, n, transparent);
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], shadowMapPointTransparent[2], ld, -l, bias, lightProj, n, transparent);
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], shadowMapPointTransparent[3], ld, -l, bias, lightProj, n, transparent);
#endif
#endif
}
#endif
return direct;
}
#endif
#ifndef _LIGHT_GLSL_
#define _LIGHT_GLSL_
#include "compiled.inc"
#include "std/brdf.glsl"
#include "std/math.glsl"
#ifdef _ShadowMap
#include "std/shadows.glsl"
#endif
#ifdef _VoxelShadow
#include "std/conetrace.glsl"
//!uniform sampler2D voxels_shadows;
#endif
#ifdef _LTC
#include "std/ltc.glsl"
#endif
#ifdef _LightIES
#include "std/ies.glsl"
#endif
#ifdef _SSRS
#include "std/ssrs.glsl"
#endif
#ifdef _Spot
#include "std/light_common.glsl"
#endif
#ifdef _ShadowMap
#ifdef _SinglePoint
#ifdef _Spot
#ifndef _LTC
uniform sampler2DShadow shadowMapSpot[1];
uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1];
#endif
#else
uniform samplerCubeShadow shadowMapPoint[1];
uniform samplerCube shadowMapPointTransparent[1];
uniform vec2 lightProj;
#endif
#endif
#ifdef _Clusters
#ifdef _SingleAtlas
//!uniform sampler2DShadow shadowMapAtlas;
//!uniform sampler2D shadowMapAtlasTransparent;
#endif
uniform vec2 lightProj;
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasPoint;
uniform sampler2D shadowMapAtlasPointTransparent;
#endif
#else
uniform samplerCubeShadow shadowMapPoint[4];
uniform samplerCube shadowMapPointTransparent[4];
#endif
#ifdef _Spot
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasSpot;
uniform sampler2D shadowMapAtlasSpotTransparent;
#endif
#else
uniform sampler2DShadow shadowMapSpot[4];
uniform sampler2D shadowMapSpotTransparent[4];
#endif
uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif
#endif
#endif
#ifdef _LTC
uniform vec3 lightArea0;
uniform vec3 lightArea1;
uniform vec3 lightArea2;
uniform vec3 lightArea3;
uniform sampler2D sltcMat;
uniform sampler2D sltcMag;
#ifdef _ShadowMap
#ifndef _Spot
#ifdef _SinglePoint
uniform sampler2DShadow shadowMapSpot[1];
uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1];
#endif
#ifdef _Clusters
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif
#endif
#endif
#endif
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
const vec3 albedo, const float rough, const float spec, const vec3 f0
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow, bool transparent
#endif
#ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
#ifdef _VoxelShadow
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount]
#endif
#ifdef _MicroShadowing
, float occ
#endif
#ifdef _SSRS
, sampler2D gbufferD, mat4 invVP, vec3 eye
#endif
) {
vec3 ld = lp - p;
vec3 l = normalize(ld);
vec3 h = normalize(v + l);
float dotNH = max(0.0, dot(n, h));
float dotVH = max(0.0, dot(v, h));
float dotNL = max(0.0, dot(n, l));
#ifdef _LTC
float theta = acos(dotNV);
vec2 tuv = vec2(rough, theta / (0.5 * PI));
tuv = tuv * LUT_SCALE + LUT_BIAS;
vec4 t = textureLod(sltcMat, tuv, 0.0);
mat3 invM = mat3(
vec3(1.0, 0.0, t.y),
vec3(0.0, t.z, 0.0),
vec3(t.w, 0.0, t.x));
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
#else
vec3 F0 = surfaceF0(albedo, spec); // spec used as the metalness value
vec3 direct = burleyDiffuseBRDF(n, v, l, albedo, rough) * (1.0 - spec) +
specularBRDF(n, v, l, f0, rough) * spec;
#endif
direct *= attenuate(distance(p, lp));
direct *= lightCol;
#ifdef _MicroShadowing
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
#endif
#ifdef _SSRS
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
#endif
#ifdef _VoxelShadow
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy).r) * voxelgiShad;
#endif
#ifdef _LTC
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
#endif
}
#endif
return direct;
#endif
#ifdef _Spot
if (isSpot) {
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
#ifdef _ShadowMapAtlas
direct *= shadowTest(
#ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
, lPos.xyz / lPos.w, bias, transparent
);
#else
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
#endif
#endif
}
#endif
return direct;
}
#endif
#ifdef _LightIES
direct *= iesAttenuation(-l);
#endif
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
#ifndef _Spot
direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
#endif
#endif
#ifdef _Clusters
#ifdef _ShadowMapAtlas
direct *= PCFFakeCube(
#ifndef _SingleAtlas
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
, ld, -l, bias, lightProj, n, index, transparent
);
#else
if (index == 0) direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], shadowMapPointTransparent[1], ld, -l, bias, lightProj, n, transparent);
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], shadowMapPointTransparent[2], ld, -l, bias, lightProj, n, transparent);
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], shadowMapPointTransparent[3], ld, -l, bias, lightProj, n, transparent);
#endif
#endif
}
#endif
return direct;
}
#endif

View File

@ -7,6 +7,12 @@ float hash(const vec2 p) {
return fract(sin(h) * 43758.5453123);
}
float hash12(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
vec2 envMapEquirect(const vec3 normal) {
const float PI = 3.1415926535;
const float PI2 = PI * 2.0;
@ -27,9 +33,9 @@ vec2 rand2(const vec2 coord) {
return vec2(noiseX, noiseY);
}
float linearize(const float depth, vec2 cameraProj) {
// to viewz
return cameraProj.y / (depth - cameraProj.x);
float linearize(float depth, vec2 cameraProj) {
return cameraProj.y / (cameraProj.x - max(depth, 1e-6));
//return cameraProj.y / (cameraProj.x - depth);
}
float attenuate(const float dist) {

View File

@ -11,8 +11,6 @@ vec3 uncharted2Tonemap(const vec3 x) {
vec3 tonemapUncharted2(const vec3 color) {
const float W = 11.2;
const float exposureBias = 2.0;
// TODO - Find out why black world value of 0.0,0.0,0.0 turns to white pixels
if (dot(color, color) < 0.001) return vec3(0.001);
vec3 curr = uncharted2Tonemap(exposureBias * color);
vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
return curr * whiteScale;

View File

@ -11,11 +11,6 @@
#include "std/light_common.glsl"
#endif
#ifdef _CPostprocess
uniform vec3 PPComp11;
uniform vec4 PPComp17;
#endif
uniform sampler2D gbufferD;
uniform sampler2D snoise;
@ -92,13 +87,7 @@ out float fragColor;
const float tScat = 0.08;
const float tAbs = 0.0;
const float tExt = tScat + tAbs;
#ifdef _CPostprocess
float stepLen = 1.0 / int(PPComp11.y);
float AirTurbidity = PPComp17.w;
#else
const float stepLen = 1.0 / volumSteps;
float AirTurbidity = volumAirTurbidity;
#endif
const float stepLen = 1.0 / volumSteps;
const float lighting = 0.4;
void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatteredLightAmount, float stepLenWorld, vec3 viewVecNorm) {
@ -173,5 +162,5 @@ void main() {
rayStep(curPos, curOpticalDepth, scatteredLightAmount, stepLenWorld, viewVecNorm);
}
fragColor = scatteredLightAmount * AirTurbidity;
fragColor = scatteredLightAmount * volumAirTurbidity;
}

View File

@ -140,16 +140,6 @@
"link": "_biasLightWorldViewProjectionMatrixSpot3",
"ifndef": ["_ShadowMapAtlas"],
"ifdef": ["_Spot", "_ShadowMap"]
},
{
"name": "PPComp11",
"link": "_PPComp11",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp17",
"link": "_PPComp17",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],

View File

@ -12,7 +12,6 @@ class App {
static var traitInits: Array<Void->Void> = [];
static var traitUpdates: Array<Void->Void> = [];
static var traitLateUpdates: Array<Void->Void> = [];
static var traitFixedUpdates: Array<Void->Void> = [];
static var traitRenders: Array<kha.graphics4.Graphics->Void> = [];
static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = [];
public static var framebuffer: kha.Framebuffer;
@ -24,8 +23,6 @@ class App {
public static var renderPathTime: Float;
public static var endFrameCallbacks: Array<Void->Void> = [];
#end
static var last = 0.0;
static var time = 0.0;
static var lastw = -1;
static var lasth = -1;
public static var onResize: Void->Void = null;
@ -37,14 +34,13 @@ class App {
function new(done: Void->Void) {
done();
kha.System.notifyOnFrames(render);
kha.Scheduler.addTimeTask(update, 0, iron.system.Time.step);
kha.Scheduler.addTimeTask(update, 0, iron.system.Time.delta);
}
public static function reset() {
traitInits = [];
traitUpdates = [];
traitLateUpdates = [];
traitFixedUpdates = [];
traitRenders = [];
traitRenders2D = [];
if (onResets != null) for (f in onResets) f();
@ -52,24 +48,6 @@ class App {
static function update() {
if (Scene.active == null || !Scene.active.ready) return;
iron.system.Time.update();
if (lastw == -1) {
lastw = App.w();
lasth = App.h();
}
if (lastw != App.w() || lasth != App.h()) {
if (onResize != null) onResize();
else {
if (Scene.active != null && Scene.active.camera != null) {
Scene.active.camera.buildProjection();
}
}
}
lastw = App.w();
lasth = App.h();
if (pauseUpdates) return;
#if lnx_debug
@ -78,14 +56,6 @@ class App {
Scene.active.updateFrame();
time += iron.system.Time.delta;
while (time >= iron.system.Time.fixedStep) {
for (f in traitFixedUpdates) f();
time -= iron.system.Time.fixedStep;
}
var i = 0;
var l = traitUpdates.length;
while (i < l) {
@ -114,13 +84,29 @@ class App {
for (cb in endFrameCallbacks) cb();
updateTime = kha.Scheduler.realTime() - startTime;
#end
// Rebuild projection on window resize
if (lastw == -1) {
lastw = App.w();
lasth = App.h();
}
if (lastw != App.w() || lasth != App.h()) {
if (onResize != null) onResize();
else {
if (Scene.active != null && Scene.active.camera != null) {
Scene.active.camera.buildProjection();
}
}
}
lastw = App.w();
lasth = App.h();
}
static function render(frames: Array<kha.Framebuffer>) {
var frame = frames[0];
framebuffer = frame;
iron.system.Time.render();
iron.system.Time.update();
if (Scene.active == null || !Scene.active.ready) {
render2D(frame);
@ -186,14 +172,6 @@ class App {
traitLateUpdates.remove(f);
}
public static function notifyOnFixedUpdate(f: Void->Void) {
traitFixedUpdates.push(f);
}
public static function removeFixedUpdate(f: Void->Void) {
traitFixedUpdates.remove(f);
}
public static function notifyOnRender(f: kha.graphics4.Graphics->Void) {
traitRenders.push(f);
}

View File

@ -518,44 +518,12 @@ class RenderPath {
return Reflect.field(kha.Shaders, handle + "_comp");
}
#if lnx_vr
public function drawStereo(drawMeshes: Void->Void) {
var vr = kha.vr.VrInterface.instance;
var appw = iron.App.w();
var apph = iron.App.h();
var halfw = Std.int(appw / 2);
var g = currentG;
if (vr != null && vr.IsPresenting()) {
// Left eye
Scene.active.camera.V.setFrom(Scene.active.camera.leftV);
Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
g.viewport(0, 0, halfw, apph);
drawMeshes();
// Right eye
begin(g, additionalTargets);
Scene.active.camera.V.setFrom(Scene.active.camera.rightV);
Scene.active.camera.P.self = vr.GetProjectionMatrix(1);
g.viewport(halfw, 0, halfw, apph);
drawMeshes();
}
else { // Simulate
Scene.active.camera.buildProjection(halfw / apph);
// Left eye
g.viewport(0, 0, halfw, apph);
drawMeshes();
// Right eye
begin(g, additionalTargets);
Scene.active.camera.transform.move(Scene.active.camera.right(), 0.032);
Scene.active.camera.buildMatrix();
g.viewport(halfw, 0, halfw, apph);
drawMeshes();
Scene.active.camera.transform.move(Scene.active.camera.right(), -0.032);
Scene.active.camera.buildMatrix();
#if (kha_krom && lnx_vr)
public function drawStereo(drawMeshes: Int->Void) {
for (eye in 0...2) {
Krom.vrBeginRender(eye);
drawMeshes(eye);
Krom.vrEndRender(eye);
}
}
#end

View File

@ -775,7 +775,6 @@ class Scene {
// Attach particle systems
#if lnx_particles
if (o.particle_refs != null) {
cast(object, MeshObject).render_emitter = o.render_emitter;
for (ref in o.particle_refs) cast(object, MeshObject).setupParticleSystem(sceneName, ref);
}
#end
@ -783,11 +782,6 @@ class Scene {
if (o.tilesheet_ref != null) {
cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref);
}
if (o.camera_list != null){
cast(object, MeshObject).cameraList = o.camera_list;
}
returnObject(object, o, done);
});
}
@ -887,12 +881,8 @@ class Scene {
var ptype: String = t.props[i * 3 + 1];
var pval: Dynamic = t.props[i * 3 + 2];
if (StringTools.endsWith(ptype, "Object") && pval != "" && pval != null) {
if (StringTools.endsWith(ptype, "Object") && pval != "") {
Reflect.setProperty(traitInst, pname, Scene.active.getChild(pval));
} else if (ptype == "TSceneFormat" && pval != "") {
Data.getSceneRaw(pval, function (r: TSceneFormat) {
Reflect.setProperty(traitInst, pname, r);
});
}
else {
switch (ptype) {

View File

@ -16,7 +16,6 @@ class Trait {
var _remove: Array<Void->Void> = null;
var _update: Array<Void->Void> = null;
var _lateUpdate: Array<Void->Void> = null;
var _fixedUpdate: Array<Void->Void> = null;
var _render: Array<kha.graphics4.Graphics->Void> = null;
var _render2D: Array<kha.graphics2.Graphics->Void> = null;
@ -88,23 +87,6 @@ class Trait {
App.removeLateUpdate(f);
}
/**
Add fixed game logic handler.
**/
public function notifyOnFixedUpdate(f: Void->Void) {
if (_fixedUpdate == null) _fixedUpdate = [];
_fixedUpdate.push(f);
App.notifyOnFixedUpdate(f);
}
/**
Remove fixed game logic handler.
**/
public function removeFixedUpdate(f: Void->Void) {
_fixedUpdate.remove(f);
App.removeFixedUpdate(f);
}
/**
Add render handler.
**/

View File

@ -392,8 +392,6 @@ typedef TParticleData = {
#end
public var name: String;
public var type: Int; // 0 - Emitter, Hair
public var auto_start: Bool;
public var is_unique: Bool;
public var loop: Bool;
public var count: Int;
public var frame_start: FastFloat;
@ -441,7 +439,6 @@ typedef TObj = {
@:optional public var traits: Array<TTrait>;
@:optional public var properties: Array<TProperty>;
@:optional public var vertex_groups: Array<TVertex_groups>;
@:optional public var camera_list: Array<String>;
@:optional public var constraints: Array<TConstraint>;
@:optional public var dimensions: Float32Array; // Geometry objects
@:optional public var object_actions: Array<String>;

View File

@ -1,50 +0,0 @@
/*
* format - Haxe File Formats
*
* BMP File Format
* Copyright (C) 2007-2009 Trevor McCauley, Baluta Cristian (hx port) & Robert Sköld (format conversion)
*
* Copyright (c) 2009, The Haxe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package iron.format.bmp;
typedef Data = {
var header : iron.format.bmp.Header;
var pixels : haxe.io.Bytes;
#if (haxe_ver < 4)
var colorTable : Null<haxe.io.Bytes>;
#else
var ?colorTable : haxe.io.Bytes;
#end
}
typedef Header = {
var width : Int; // real width (in pixels)
var height : Int; // real height (in pixels)
var paddedStride : Int; // number of bytes in a stride (including padding)
var topToBottom : Bool; // whether the bitmap is stored top to bottom
var bpp : Int; // bits per pixel
var dataLength : Int; // equal to `paddedStride` * `height`
var compression : Int; // which compression is being used, 0 for no compression
}

View File

@ -1,122 +0,0 @@
/*
* format - Haxe File Formats
*
* BMP File Format
* Copyright (C) 2007-2009 Robert Sköld
*
* Copyright (c) 2009, The Haxe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package iron.format.bmp;
import iron.format.bmp.Data;
class Reader {
var input : haxe.io.Input;
public function new( i ) {
input = i;
}
/**
* Only supports uncompressed 24bpp bitmaps (the most common format).
*
* The returned bytes in `Data.pixels` will be in BGR order, and with padding (if present).
*
* @see https://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx
* @see https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header
*/
public function read() : format.bmp.Data {
// Read Header
for (b in ["B".code, "M".code]) {
if (input.readByte() != b) throw "Invalid header";
}
var fileSize = input.readInt32();
input.readInt32(); // Reserved
var offset = input.readInt32();
// Read InfoHeader
var infoHeaderSize = input.readInt32(); // InfoHeader size
if (infoHeaderSize != 40) {
throw 'Info headers with size $infoHeaderSize not supported.';
}
var width = input.readInt32(); // Image width (actual, not padded)
var height = input.readInt32(); // Image height
var numPlanes = input.readInt16(); // Number of planes
var bits = input.readInt16(); // Bits per pixel
var compression = input.readInt32(); // Compression type
var dataLength = input.readInt32(); // Image data size (includes padding!)
input.readInt32(); // Horizontal resolution
input.readInt32(); // Vertical resolution
var colorsUsed = input.readInt32(); // Colors used (0 when uncompressed)
input.readInt32(); // Important colors (0 when uncompressed)
// If there's no compression, the dataLength may be 0
if ( compression == 0 && dataLength == 0 ) dataLength = fileSize - offset;
var bytesRead = 54; // total read above
var colorTable : haxe.io.Bytes = null;
if ( bits <= 8 ) {
if ( colorsUsed == 0 ) {
colorsUsed = Tools.getNumColorsForBitDepth(bits);
}
var colorTableLength = 4 * colorsUsed;
colorTable = haxe.io.Bytes.alloc( colorTableLength );
input.readFullBytes( colorTable, 0, colorTableLength );
bytesRead += colorTableLength;
}
input.read( offset - bytesRead );
var p = haxe.io.Bytes.alloc( dataLength );
// Read Raster Data
var paddedStride = Tools.computePaddedStride(width, bits);
var topToBottom = false;
if ( height < 0 ) { // if bitmap is stored top to bottom
topToBottom = true;
height = -height;
}
input.readFullBytes(p, 0, dataLength);
return {
header: {
width: width,
height: height,
paddedStride: paddedStride,
topToBottom: topToBottom,
bpp: bits,
dataLength: dataLength,
compression: compression
},
pixels: p,
colorTable: colorTable
}
}
}

View File

@ -1,256 +0,0 @@
/*
* format - Haxe File Formats
*
* BMP File Format
* Copyright (C) 2007-2009 Trevor McCauley, Baluta Cristian (hx port) & Robert Sköld (format conversion)
*
* Copyright (c) 2009, The Haxe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package iron.format.bmp;
class Tools {
// a r g b
static var ARGB_MAP(default, never):Array<Int> = [0, 1, 2, 3];
static var BGRA_MAP(default, never):Array<Int> = [3, 2, 1, 0];
static var COLOR_SIZE(default, never):Int = 4;
/**
Extract BMP pixel data (24bpp in BGR format) and expands it to BGRA, removing any padding in the process.
**/
inline static public function extractBGRA( bmp : iron.format.bmp.Data ) : haxe.io.Bytes {
return _extract32(bmp, BGRA_MAP, 0xFF);
}
/**
Extract BMP pixel data (24bpp in BGR format) and converts it to ARGB.
**/
inline static public function extractARGB( bmp : iron.format.bmp.Data ) : haxe.io.Bytes {
return _extract32(bmp, ARGB_MAP, 0xFF);
}
/**
Creates BMP data from bytes in BGRA format for each pixel.
**/
inline static public function buildFromBGRA( width : Int, height : Int, srcBytes : haxe.io.Bytes, topToBottom : Bool = false ) : Data {
return _buildFrom32(width, height, srcBytes, BGRA_MAP, topToBottom);
}
/**
Creates BMP data from bytes in ARGB format for each pixel.
**/
inline static public function buildFromARGB( width : Int, height : Int, srcBytes : haxe.io.Bytes, topToBottom : Bool = false ) : Data {
return _buildFrom32(width, height, srcBytes, ARGB_MAP, topToBottom);
}
inline static public function computePaddedStride(width:Int, bpp:Int):Int {
return ((((width * bpp) + 31) & ~31) >> 3);
}
/**
* Gets number of colors for indexed palettes
*/
inline static public function getNumColorsForBitDepth(bpp:Int):Int {
return switch (bpp) {
case 1: 2;
case 4: 16;
case 8: 256;
case 16: 65536;
default: throw 'Unsupported bpp $bpp';
}
}
// `channelMap` contains indices to map into ARGB (f.e. the mapping for ARGB is [0,1,2,3], while for BGRA is [3,2,1,0])
static function _extract32( bmp : iron.format.bmp.Data, channelMap : Array<Int>, alpha : Int = 0xFF) : haxe.io.Bytes {
var srcBytes = bmp.pixels;
var dstLen = bmp.header.width * bmp.header.height * 4;
var dstBytes = haxe.io.Bytes.alloc( dstLen );
var srcPaddedStride = bmp.header.paddedStride;
var yDir = -1;
var dstPos = 0;
var srcPos = srcPaddedStride * (bmp.header.height - 1);
if ( bmp.header.topToBottom ) {
yDir = 1;
srcPos = 0;
}
if ( bmp.header.bpp < 8 || bmp.header.bpp == 16 ) {
throw 'bpp ${bmp.header.bpp} not supported';
}
var colorTable:haxe.io.Bytes = null;
if ( bmp.header.bpp <= 8 ) {
var colorTableLength = getNumColorsForBitDepth(bmp.header.bpp);
colorTable = haxe.io.Bytes.alloc(colorTableLength * COLOR_SIZE);
var definedColorTableLength = Std.int( bmp.colorTable.length / COLOR_SIZE );
for( i in 0...definedColorTableLength ) {
var b = bmp.colorTable.get( i * COLOR_SIZE);
var g = bmp.colorTable.get( i * COLOR_SIZE + 1);
var r = bmp.colorTable.get( i * COLOR_SIZE + 2);
colorTable.set(i * COLOR_SIZE + channelMap[0], alpha);
colorTable.set(i * COLOR_SIZE + channelMap[1], r);
colorTable.set(i * COLOR_SIZE + channelMap[2], g);
colorTable.set(i * COLOR_SIZE + channelMap[3], b);
}
// We want to have the table the full length in case indices outside the range are present
colorTable.fill(definedColorTableLength, colorTableLength - definedColorTableLength, 0);
for( i in definedColorTableLength...colorTableLength ) {
colorTable.set(i * COLOR_SIZE + channelMap[0], alpha);
}
}
switch bmp.header.compression {
case 0:
while( dstPos < dstLen ) {
for( i in 0...bmp.header.width ) {
if (bmp.header.bpp == 8) {
var currentSrcPos = srcPos + i;
var index = srcBytes.get(currentSrcPos);
dstBytes.blit( dstPos, colorTable, index * COLOR_SIZE, COLOR_SIZE );
} else if (bmp.header.bpp == 24) {
var currentSrcPos = srcPos + i * 3;
var b = srcBytes.get(currentSrcPos);
var g = srcBytes.get(currentSrcPos + 1);
var r = srcBytes.get(currentSrcPos + 2);
dstBytes.set(dstPos + channelMap[0], alpha);
dstBytes.set(dstPos + channelMap[1], r);
dstBytes.set(dstPos + channelMap[2], g);
dstBytes.set(dstPos + channelMap[3], b);
} else if (bmp.header.bpp == 32) {
var currentSrcPos = srcPos + i * 4;
var b = srcBytes.get(currentSrcPos);
var g = srcBytes.get(currentSrcPos + 1);
var r = srcBytes.get(currentSrcPos + 2);
dstBytes.set(dstPos + channelMap[0], alpha);
dstBytes.set(dstPos + channelMap[1], r);
dstBytes.set(dstPos + channelMap[2], g);
dstBytes.set(dstPos + channelMap[3], b);
}
dstPos += 4;
}
srcPos += yDir * srcPaddedStride;
}
case 1:
srcPos = 0;
var x = 0;
var y = bmp.header.topToBottom ? 0 : bmp.header.height - 1;
while( srcPos < bmp.header.dataLength ) {
var count = srcBytes.get(srcPos++);
var index = srcBytes.get(srcPos++);
if ( count == 0 ) {
if ( index == 0 ) {
x = 0;
y += yDir;
} else if ( index == 1 ) {
break;
} else if ( index == 2 ) {
x += srcBytes.get(srcPos++);
y += srcBytes.get(srcPos++);
} else {
count = index;
for( i in 0...count ) {
index = srcBytes.get(srcPos++);
dstBytes.blit( COLOR_SIZE * ((x+i) + y * bmp.header.width), colorTable, index * COLOR_SIZE, COLOR_SIZE );
}
if (srcPos % 2 != 0) srcPos++;
x += count;
}
} else {
for( i in 0...count ) {
dstBytes.blit( COLOR_SIZE * ((x+i) + y * bmp.header.width), colorTable, index * COLOR_SIZE, COLOR_SIZE );
}
x += count;
}
}
default:
throw 'compression ${bmp.header.compression} not supported';
}
return dstBytes;
}
// `channelMap` contains indices to map into ARGB (f.e. the mapping for ARGB is [0,1,2,3], while for BGRA is [3,2,1,0])
static function _buildFrom32( width : Int, height : Int, srcBytes : haxe.io.Bytes, channelMap : Array<Int>, topToBottom : Bool = false ) : Data {
var bpp = 24;
var paddedStride = computePaddedStride(width, bpp);
var bytesBGR = haxe.io.Bytes.alloc(paddedStride * height);
var topToBottom = topToBottom;
var dataLength = bytesBGR.length;
var dstStride = width * 3;
var srcLen = width * height * 4;
var yDir = -1;
var dstPos = dataLength - paddedStride;
var srcPos = 0;
if ( topToBottom ) {
yDir = 1;
dstPos = 0;
}
while( srcPos < srcLen ) {
var i = dstPos;
while( i < dstPos + dstStride ) {
var r = srcBytes.get(srcPos + channelMap[1]);
var g = srcBytes.get(srcPos + channelMap[2]);
var b = srcBytes.get(srcPos + channelMap[3]);
bytesBGR.set(i++, b);
bytesBGR.set(i++, g);
bytesBGR.set(i++, r);
srcPos += 4;
}
dstPos += yDir * paddedStride;
}
return {
header: {
width: width,
height: height,
paddedStride: paddedStride,
topToBottom: topToBottom,
bpp: bpp,
dataLength: dataLength,
compression: 0
},
pixels: bytesBGR,
colorTable: null
}
}
}

View File

@ -1,74 +0,0 @@
/*
* format - Haxe File Formats
*
* BMP File Format
* Copyright (C) 2007-2009 Robert Sköld
*
* Copyright (c) 2009, The Haxe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package iron.format.bmp;
import iron.format.bmp.Data;
class Writer {
static var DATA_OFFSET : Int = 0x36;
var output : haxe.io.Output;
public function new(o) {
output = o;
}
/**
* Specs: http://s223767089.online.de/en/file-format-bmp
*/
public function write( bmp : Data ) {
// Write Header (14 bytes)
output.writeString( "BM" ); // Signature
output.writeInt32(bmp.pixels.length + DATA_OFFSET ); // FileSize
output.writeInt32( 0 ); // Reserved
output.writeInt32( DATA_OFFSET ); // Offset
// Write InfoHeader (40 bytes)
output.writeInt32( 40 ); // InfoHeader size
output.writeInt32( bmp.header.width ); // Image width
var height = bmp.header.height;
if (bmp.header.topToBottom) height = -height;
output.writeInt32( height ); // Image height
output.writeInt16( 1 ); // Number of planes
output.writeInt16( 24 ); // Bits per pixel (24bit RGB)
output.writeInt32( 0 ); // Compression type (no compression)
output.writeInt32( bmp.header.dataLength ); // Image data size (0 when uncompressed)
output.writeInt32( 0x2e30 ); // Horizontal resolution
output.writeInt32( 0x2e30 ); // Vertical resolution
output.writeInt32( 0 ); // Colors used (0 when uncompressed)
output.writeInt32( 0 ); // Important colors (0 when uncompressed)
// Write Raster Data
output.write(bmp.pixels);
}
}

View File

@ -159,17 +159,9 @@ class Animation {
if(markerEvents.get(sampler) != null){
for (i in 0...anim.marker_frames.length) {
if (frameIndex == anim.marker_frames[i]) {
var markerAct = markerEvents.get(sampler);
var ar = markerAct.get(anim.marker_names[i]);
var marketAct = markerEvents.get(sampler);
var ar = marketAct.get(anim.marker_names[i]);
if (ar != null) for (f in ar) f();
} else {
for (j in 0...(frameIndex - lastFrameIndex)) {
if (lastFrameIndex + j + 1 == anim.marker_frames[i]) {
var markerAct = markerEvents.get(sampler);
var ar = markerAct.get(anim.marker_names[i]);
if (ar != null) for (f in ar) f();
}
}
}
}
lastFrameIndex = frameIndex;

View File

@ -30,22 +30,12 @@ class CameraObject extends Object {
static var sphereCenter = new Vec4();
static var vcenter = new Vec4();
static var vup = new Vec4();
#if lnx_vr
var helpMat = Mat4.identity();
public var leftV = Mat4.identity();
public var rightV = Mat4.identity();
#end
public function new(data: CameraData) {
super();
this.data = data;
#if lnx_vr
iron.system.VR.initButton();
#end
buildProjection();
V = Mat4.identity();
@ -127,26 +117,6 @@ class CameraObject extends Object {
V.getInverse(transform.world);
VP.multmats(P, V);
#if lnx_vr
var vr = kha.vr.VrInterface.instance;
if (vr != null && vr.IsPresenting()) {
leftV.setFrom(V);
helpMat.self = vr.GetViewMatrix(0);
leftV.multmat(helpMat);
rightV.setFrom(V);
helpMat.self = vr.GetViewMatrix(1);
rightV.multmat(helpMat);
}
else {
leftV.setFrom(V);
}
VP.multmats(P, leftV);
#else
VP.multmats(P, V);
#end
if (data.raw.frustum_culling) {
buildViewFrustum(VP, frustumPlanes);
}

View File

@ -155,13 +155,8 @@ class LightObject extends Object {
}
public function setCascade(camera: CameraObject, cascade: Int) {
#if lnx_vr
m.setFrom(camera.leftV);
#else
m.setFrom(camera.V);
#end
#if lnx_csm
if (camSlicedP == null) {
camSlicedP = [];

View File

@ -21,10 +21,8 @@ class MeshObject extends Object {
public var particleChildren: Array<MeshObject> = null;
public var particleOwner: MeshObject = null; // Particle object
public var particleIndex = -1;
public var render_emitter = true;
#end
public var cameraDistance: Float;
public var cameraList: Array<String> = null;
public var screenSize = 0.0;
public var frustumCulling = true;
public var activeTilesheet: Tilesheet = null;
@ -236,8 +234,6 @@ class MeshObject extends Object {
if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
var meshContext = raw != null ? context == "mesh" : false;
if (cameraList != null && cameraList.indexOf(Scene.active.camera.name) < 0) return;
#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) {
@ -248,7 +244,6 @@ class MeshObject extends Object {
Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
if (o != null) {
var c: MeshObject = cast o;
c.cameraList = this.cameraList;
particleChildren.push(c);
c.particleOwner = this;
c.particleIndex = particleChildren.length - 1;
@ -260,11 +255,11 @@ class MeshObject extends Object {
particleSystems[i].update(particleChildren[i], this);
}
}
if (particleSystems != null && particleSystems.length > 0 && !render_emitter) return;
if (particleSystems == null && cullMaterial(context)) return;
#else
if (cullMaterial(context)) return;
if (particleSystems != null && particleSystems.length > 0 && !raw.render_emitter) return;
#end
if (cullMaterial(context)) return;
// Get lod
var mats = materials;
var lod = this;

View File

@ -172,10 +172,6 @@ class Object {
for (f in t._init) App.removeInit(f);
t._init = null;
}
if (t._fixedUpdate != null) {
for (f in t._fixedUpdate) App.removeFixedUpdate(f);
t._fixedUpdate = null;
}
if (t._update != null) {
for (f in t._update) App.removeUpdate(f);
t._update = null;

View File

@ -2,7 +2,6 @@ package iron.object;
#if lnx_particles
import kha.FastFloat;
import kha.graphics4.Usage;
import kha.arrays.Float32Array;
import iron.data.Data;
@ -17,12 +16,10 @@ import iron.math.Vec4;
class ParticleSystem {
public var data: ParticleData;
public var speed = 1.0;
var currentSpeed = 0.0;
var particles: Array<Particle>;
var ready: Bool;
var frameRate = 24;
var lifetime = 0.0;
var looptime = 0.0;
var animtime = 0.0;
var time = 0.0;
var spawnRate = 0.0;
@ -49,16 +46,11 @@ class ParticleSystem {
var ownerLoc = new Vec4();
var ownerRot = new Quat();
var ownerScl = new Vec4();
var random = 0.0;
public function new(sceneName: String, pref: TParticleReference) {
seed = pref.seed;
currentSpeed = speed;
speed = 0;
particles = [];
ready = false;
Data.getParticle(sceneName, pref.particle, function(b: ParticleData) {
data = b;
r = data.raw;
@ -72,61 +64,27 @@ class ParticleSystem {
gy = 0;
gz = -9.81 * r.weight_gravity;
}
alignx = r.object_align_factor[0];
aligny = r.object_align_factor[1];
alignz = r.object_align_factor[2];
looptime = (r.frame_end - r.frame_start) / frameRate;
alignx = r.object_align_factor[0] / 2;
aligny = r.object_align_factor[1] / 2;
alignz = r.object_align_factor[2] / 2;
lifetime = r.lifetime / frameRate;
animtime = r.loop ? looptime : looptime + lifetime;
animtime = (r.frame_end - r.frame_start) / 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) particles.push(new Particle(i));
ready = true;
if (r.auto_start){
start();
}
});
}
public function start() {
if (r.is_unique) random = Math.random();
lifetime = r.lifetime / frameRate;
time = 0;
lap = 0;
lapTime = 0;
speed = currentSpeed;
}
public function pause() {
speed = 0;
lifetime = 0;
}
public function resume() {
lifetime = r.lifetime / frameRate;
speed = currentSpeed;
}
// TODO: interrupt smoothly
public function stop() {
end();
}
function end() {
lifetime = 0;
speed = 0;
lap = 0;
}
public function update(object: MeshObject, owner: MeshObject) {
if (!ready || object == null || speed == 0.0) return;
if (iron.App.pauseUpdates) return;
var prevLap = lap;
// Copy owner world transform but discard scale
owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl);
@ -150,21 +108,17 @@ class ParticleSystem {
}
// Animate
time += Time.renderDelta * speed; // realDelta to renderDelta
time += Time.realDelta * speed;
lap = Std.int(time / animtime);
lapTime = time - lap * animtime;
count = Std.int(lapTime / spawnRate);
if (lap > prevLap && !r.loop) {
end();
}
updateGpu(object, owner);
}
public function getData(): Mat4 {
var hair = r.type == 1;
m._00 = animtime;
m._00 = r.loop ? animtime : -animtime;
m._01 = hair ? 1 / particles.length : spawnRate;
m._02 = hair ? 1 : lifetime;
m._03 = particles.length;
@ -172,9 +126,9 @@ class ParticleSystem {
m._11 = hair ? 0 : aligny;
m._12 = hair ? 0 : alignz;
m._13 = hair ? 0 : r.factor_random;
m._20 = hair ? 0 : gx;
m._21 = hair ? 0 : gy;
m._22 = hair ? 0 : gz;
m._20 = hair ? 0 : gx * r.mass;
m._21 = hair ? 0 : gy * r.mass;
m._22 = hair ? 0 : gz * r.mass;
m._23 = hair ? 0 : r.lifetime_random;
m._30 = tilesx;
m._31 = tilesy;
@ -183,18 +137,6 @@ class ParticleSystem {
return m;
}
public function getSizeRandom(): FastFloat {
return r.size_random;
}
public function getRandom(): FastFloat {
return random;
}
public function getSize(): FastFloat {
return r.particle_size;
}
function updateGpu(object: MeshObject, owner: MeshObject) {
if (!object.data.geom.instanced) setupGeomGpu(object, owner);
// GPU particles transform is attached to owner object
@ -294,11 +236,9 @@ class ParticleSystem {
class Particle {
public var i: Int;
public var x = 0.0;
public var y = 0.0;
public var z = 0.0;
public var cameraDistance: Float;
public function new(i: Int) {

View File

@ -80,7 +80,7 @@ class Tilesheet {
function update() {
if (!ready || paused || action.start >= action.end) return;
time += Time.renderDelta;
time += Time.realDelta;
var frameTime = 1 / raw.framerate;
var framesToAdvance = 0;

View File

@ -1109,26 +1109,6 @@ class Uniforms {
case "_texUnpack": {
f = texUnpack != null ? texUnpack : 1.0;
}
#if lnx_particles
case "_particleSizeRandom": {
var mo = cast(object, MeshObject);
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
f = mo.particleOwner.particleSystems[mo.particleIndex].getSizeRandom();
}
}
case "_particleRandom": {
var mo = cast(object, MeshObject);
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
f = mo.particleOwner.particleSystems[mo.particleIndex].getRandom();
}
}
case "_particleSize": {
var mo = cast(object, MeshObject);
if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
f = mo.particleOwner.particleSystems[mo.particleIndex].getSize();
}
}
#end
}
if (f == null && externalFloatLinks != null) {

View File

@ -1,58 +1,37 @@
package iron.system;
class Time {
public static var scale = 1.0;
static var frequency: Null<Int> = null;
static function initFrequency() {
frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
}
public static var step(get, never): Float;
static function get_step(): Float {
if (frequency == null) initFrequency();
return 1 / frequency;
}
static var _fixedStep: Null<Float> = 1/60;
public static var fixedStep(get, never): Float;
static function get_fixedStep(): Float {
return _fixedStep;
}
public static function initFixedStep(value: Float = 1 / 60) {
_fixedStep = value;
}
static var lastTime = 0.0;
static var _delta = 0.0;
public static var scale = 1.0;
public static var delta(get, never): Float;
static function get_delta(): Float {
return _delta;
if (frequency == null) initFrequency();
return (1 / frequency) * scale;
}
static var lastRenderTime = 0.0;
static var _renderDelta = 0.0;
public static var renderDelta(get, never): Float;
static function get_renderDelta(): Float {
return _renderDelta;
}
static var last = 0.0;
public static var realDelta = 0.0;
public static inline function time(): Float {
return kha.Scheduler.time();
}
public static inline function realTime(): Float {
return kha.Scheduler.realTime();
}
public static function update() {
_delta = realTime() - lastTime;
lastTime = realTime();
static var frequency: Null<Int> = null;
static function initFrequency() {
frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
}
public static function render() {
_renderDelta = realTime() - lastRenderTime;
lastRenderTime = realTime();
public static function update() {
realDelta = realTime() - last;
last = realTime();
}
}

View File

@ -1,52 +0,0 @@
package iron.system;
import iron.math.Mat4;
#if lnx_vr
class VR {
static var undistortionMatrix: Mat4 = null;
public function new() {}
public static function getUndistortionMatrix(): Mat4 {
if (undistortionMatrix == null) {
undistortionMatrix = Mat4.identity();
}
return undistortionMatrix;
}
public static function getMaxRadiusSq(): Float {
return 0.0;
}
public static function initButton() {
function vrDownListener(index: Int, x: Float, y: Float) {
var vr = kha.vr.VrInterface.instance;
if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
var w: Float = iron.App.w();
var h: Float = iron.App.h();
if (x < w - 150 || y < h - 150) return;
vr.onVRRequestPresent();
}
function vrRender2D(g: kha.graphics2.Graphics) {
var vr = kha.vr.VrInterface.instance;
if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
var w: Float = iron.App.w();
var h: Float = iron.App.h();
g.color = 0xffff0000;
g.fillRect(w - 150, h - 150, 140, 140);
}
kha.input.Mouse.get().notify(vrDownListener, null, null, null);
iron.App.notifyOnRender2D(vrRender2D);
var vr = kha.vr.VrInterface.instance; // Straight to VR (Oculus Carmel)
if (vr != null && vr.IsVrEnabled()) {
vr.onVRRequestPresent();
}
}
}
#end

View File

@ -20,7 +20,6 @@ class Config {
var path = iron.data.Data.dataPath + "config.lnx";
var bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw));
#if kha_krom
if (iron.data.Data.dataPath == '') path = Krom.getFilesLocation() + "/config.lnx";
Krom.fileSaveBytes(path, bytes.getData());
#elseif kha_kore
sys.io.File.saveBytes(path, bytes);
@ -48,7 +47,6 @@ typedef TConfig = {
@:optional var rp_ssr: Null<Bool>;
@:optional var rp_ssrefr: Null<Bool>;
@:optional var rp_bloom: Null<Bool>;
@:optional var rp_chromatic_aberration: Null<Bool>;
@:optional var rp_motionblur: Null<Bool>;
@:optional var rp_gi: Null<Bool>; // voxelao
@:optional var rp_dynres: Null<Bool>; // dynamic resolution scaling

View File

@ -1,99 +0,0 @@
package leenkx.logicnode;
import iron.data.SceneFormat.TSceneFormat;
import iron.data.Data;
import iron.object.Object;
class AddParticleToObjectNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
#if lnx_particles
if (property0 == 'Scene Active'){
var objFrom: Object = inputs[1].get();
var slot: Int = inputs[2].get();
var objTo: Object = inputs[3].get();
if (objFrom == null || objTo == null) return;
var mobjFrom = cast(objFrom, iron.object.MeshObject);
var psys = mobjFrom.particleSystems != null ? mobjFrom.particleSystems[slot] :
mobjFrom.particleOwner != null && mobjFrom.particleOwner.particleSystems != null ? mobjFrom.particleOwner.particleSystems[slot] : null;
if (psys == null) return;
var mobjTo = cast(objTo, iron.object.MeshObject);
mobjTo.setupParticleSystem(iron.Scene.active.raw.name, {name: 'LnxPS', seed: 0, particle: @:privateAccess psys.r.name});
mobjTo.render_emitter = inputs[4].get();
iron.Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
if (o != null) {
var c: iron.object.MeshObject = cast o;
if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
mobjTo.particleChildren.push(c);
c.particleOwner = mobjTo;
c.particleIndex = mobjTo.particleChildren.length - 1;
}
});
var oslot: Int = mobjTo.particleSystems.length-1;
var opsys = mobjTo.particleSystems[oslot];
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
} else {
var sceneName: String = inputs[1].get();
var objectName: String = inputs[2].get();
var slot: Int = inputs[3].get();
var mobjTo: Object = inputs[4].get();
var mobjTo = cast(mobjTo, iron.object.MeshObject);
#if lnx_json
sceneName += ".json";
#elseif lnx_compress
sceneName += ".lz4";
#end
Data.getSceneRaw(sceneName, (rawScene: TSceneFormat) -> {
for (obj in rawScene.objects) {
if (obj.name == objectName) {
mobjTo.setupParticleSystem(sceneName, obj.particle_refs[slot]);
mobjTo.render_emitter = inputs[5].get();
iron.Scene.active.spawnObject(rawScene.particle_datas[slot].instance_object, null, function(o: Object) {
if (o != null) {
var c: iron.object.MeshObject = cast o;
if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
mobjTo.particleChildren.push(c);
c.particleOwner = mobjTo;
c.particleIndex = mobjTo.particleChildren.length - 1;
}
}, true, rawScene);
var oslot: Int = mobjTo.particleSystems.length-1;
var opsys = mobjTo.particleSystems[oslot];
@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
break;
}
}
});
}
#end
runOutput(0);
}
}

View File

@ -2,11 +2,9 @@ package leenkx.logicnode;
import iron.object.Object;
#if lnx_bullet
#if lnx_physics
import leenkx.trait.physics.PhysicsConstraint;
import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintType;
#elseif lnx_oimo
// TODO
#end
class AddPhysicsConstraintNode extends LogicNode {
@ -27,7 +25,7 @@ class AddPhysicsConstraintNode extends LogicNode {
if (pivotObject == null || rb1 == null || rb2 == null) return;
#if lnx_bullet
#if lnx_physics
var disableCollisions: Bool = inputs[4].get();
var breakable: Bool = inputs[5].get();
@ -110,8 +108,6 @@ class AddPhysicsConstraintNode extends LogicNode {
}
pivotObject.addTrait(con);
}
#elseif lnx_oimo
// TODO
#end
runOutput(0);
}

View File

@ -4,7 +4,7 @@ import iron.object.Object;
#if lnx_physics
import leenkx.trait.physics.RigidBody;
import leenkx.trait.physics.RigidBody.Shape;
import leenkx.trait.physics.bullet.RigidBody.Shape;
#end

View File

@ -1,26 +0,0 @@
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;
}
}

View File

@ -1,16 +0,0 @@
package leenkx.logicnode;
class AutoExposureGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
return switch (from) {
case 0: leenkx.renderpath.Postprocess.auto_exposure_uniforms[0];
case 1: leenkx.renderpath.Postprocess.auto_exposure_uniforms[1];
default: 0.0;
}
}
}

View File

@ -1,15 +0,0 @@
package leenkx.logicnode;
class AutoExposureSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
leenkx.renderpath.Postprocess.auto_exposure_uniforms[0] = inputs[1].get();
leenkx.renderpath.Postprocess.auto_exposure_uniforms[1] = inputs[2].get();
runOutput(0);
}
}

View File

@ -1,49 +1,26 @@
package leenkx.logicnode;
class CameraSetNode extends LogicNode {
public var property0: String;
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
switch (property0) {
case 'F-stop':
leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
case 'Shutter Time':
leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[1].get();//Camera: Shutter time
case 'ISO':
leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[1].get();//Camera: ISO
case 'Exposure Compensation':
leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[1].get();//Camera: Exposure Compensation
case 'Fisheye Distortion':
leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[1].get();//Fisheye Distortion
case 'Auto Focus':
leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[1].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
case 'DoF Distance':
leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[1].get();//DoF Distance
case 'DoF Length':
leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[1].get();//DoF Focal Length mm
case 'DoF F-Stop':
leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[1].get();//DoF F-Stop
case 'Tonemapping':
leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[1].get();//Tonemapping Method
case 'Distort':
leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[1].get();//Distort
case 'Film Grain':
leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[1].get();//Film Grain
case 'Sharpen':
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[1].get();//Sharpen
case 'Vignette':
leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[1].get();//Vignette
case 'Exposure':
leenkx.renderpath.Postprocess.exposure_uniforms[0] = inputs[1].get();//Exposure
default:
null;
}
leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[2].get();//Camera: Shutter time
leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[3].get();//Camera: ISO
leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[4].get();//Camera: Exposure Compensation
leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[5].get();//Fisheye Distortion
leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[6].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[7].get();//DoF Distance
leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[8].get();//DoF Focal Length mm
leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[9].get();//DoF F-Stop
leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[10].get();//Tonemapping Method
leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[11].get();//Distort
leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[12].get();//Film Grain
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[13].get();//Sharpen
leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[14].get();//Vignette
runOutput(0);
}

View File

@ -10,7 +10,6 @@ class ChromaticAberrationGetNode extends LogicNode {
return switch (from) {
case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0];
case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1];
case 2: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2];
default: 0.0;
}
}

View File

@ -10,7 +10,6 @@ class ChromaticAberrationSetNode extends LogicNode {
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0] = inputs[1].get();
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get();
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2] = inputs[3].get();
runOutput(0);
}

View File

@ -2,9 +2,6 @@ package leenkx.logicnode;
import iron.Scene;
import iron.object.CameraObject;
import iron.math.Vec4;
import iron.math.Quat;
import leenkx.math.Helper;
import leenkx.renderpath.RenderPathCreator;
@ -30,19 +27,11 @@ class DrawCameraTextureNode extends LogicNode {
final c = inputs[2].get();
assert(Error, Std.isOfType(c, CameraObject), "Camera must be a camera object!");
cam = cast(c, CameraObject);
rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h(),
kha.graphics4.TextureFormat.RGBA32,
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h());
assert(Error, mo.materials[matSlot].contexts[0].textures != null, 'Object "${mo.name}" has no diffuse texture to render to');
mo.materials[matSlot].contexts[0].textures[0] = rt; // Override diffuse texture
final n = inputs[5].get();
for (i => node in mo.materials[matSlot].contexts[0].raw.bind_textures){
if (node.name == n){
mo.materials[matSlot].contexts[0].textures[i] = rt; // Override diffuse texture
break;
}
}
tree.notifyOnRender(render);
runOutput(0);
@ -59,20 +48,8 @@ class DrawCameraTextureNode extends LogicNode {
iron.Scene.active.camera = cam;
cam.renderTarget = rt;
#if kha_html5
var q: Quat = new Quat();
q.fromAxisAngle(new Vec4(0, 0, 1, 1), Helper.degToRad(180));
cam.transform.rot.mult(q);
cam.transform.buildMatrix();
#end
cam.renderFrame(g);
#if kha_html5
cam.transform.rot.mult(q);
cam.transform.buildMatrix();
#end
cam.renderTarget = oldRT;
iron.Scene.active.camera = sceneCam;
}

View File

@ -99,6 +99,8 @@ class DrawImageSequenceNode extends LogicNode {
final colorVec = inputs[4].get();
g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
trace(currentImgIdx);
g.drawScaledImage(images[currentImgIdx], inputs[5].get(), inputs[6].get(), inputs[7].get(), inputs[8].get());
}
}

View File

@ -62,7 +62,7 @@ class DrawStringNode extends LogicNode {
override function get(from: Int): Dynamic {
return from == 1 ? RenderToTexture.g.font.width(RenderToTexture.g.fontSize, string) : RenderToTexture.g.font.height(RenderToTexture.g.fontSize);
return from == 1 ? RenderToTexture.g.font.height(RenderToTexture.g.fontSize) : RenderToTexture.g.font.width(RenderToTexture.g.fontSize, string);
}
}

View File

@ -1,59 +0,0 @@
package leenkx.logicnode;
import iron.math.Vec4;
import kha.Image;
import kha.Color;
import leenkx.renderpath.RenderToTexture;
class DrawSubImageNode extends LogicNode {
var img: Image;
var lastImgName = "";
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
RenderToTexture.ensure2DContext("DrawImageNode");
final imgName: String = inputs[1].get();
final colorVec: Vec4 = inputs[2].get();
final anchorH: Int = inputs[3].get();
final anchorV: Int = inputs[4].get();
final x: Float = inputs[5].get();
final y: Float = inputs[6].get();
final width: Float = inputs[7].get();
final height: Float = inputs[8].get();
final sx: Float = inputs[9].get();
final sy: Float = inputs[10].get();
final swidth: Float = inputs[11].get();
final sheight: Float = inputs[12].get();
final angle: Float = inputs[13].get();
final drawx = x - 0.5 * width * anchorH;
final drawy = y - 0.5 * height * anchorV;
final sdrawx = sx - 0.5 * swidth * anchorH;
final sdrawy = sy - 0.5 * sheight * anchorV;
RenderToTexture.g.rotate(angle, x, y);
if (imgName != lastImgName) {
// Load new image
lastImgName = imgName;
iron.data.Data.getImage(imgName, (image: Image) -> {
img = image;
});
}
if (img == null) {
runOutput(0);
return;
}
RenderToTexture.g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
RenderToTexture.g.drawScaledSubImage(img, sdrawx, sdrawy, swidth, sheight, drawx, drawy, width, height);
RenderToTexture.g.rotate(-angle, x, y);
runOutput(0);
}
}

View File

@ -1,17 +0,0 @@
package leenkx.logicnode;
import aura.Aura;
import aura.Types;
class GetAudioPositionNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var audio = inputs[0].get();
if (audio == null || audio.channel == null) return 0.0;
return audio.channel.floatPosition / audio.channel.sampleRate;
}
}

View File

@ -1,19 +0,0 @@
package leenkx.logicnode;
import iron.object.MeshObject;
import iron.object.CameraObject;
class GetCameraRenderFilterNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var mo: MeshObject = cast inputs[0].get();
if (mo == null) return null;
return mo.cameraList;
}
}

View File

@ -8,7 +8,7 @@ class GetFPSNode extends LogicNode {
override function get(from: Int): Dynamic {
if (from == 0) {
var fps = Math.round(1 / iron.system.Time.renderDelta);
var fps = Math.round(1 / iron.system.Time.realDelta);
if ((fps == Math.POSITIVE_INFINITY) || (fps == Math.NEGATIVE_INFINITY) || (Math.isNaN(fps))) {
return 0;
}

View File

@ -1,72 +0,0 @@
package leenkx.logicnode;
import iron.object.Object;
class GetParticleDataNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var object: Object = inputs[0].get();
var slot: Int = inputs[1].get();
if (object == null) return null;
#if lnx_particles
var mo = cast(object, iron.object.MeshObject);
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;
if (psys == null) return null;
return switch (from) {
case 0:
@:privateAccess psys.r.name;
case 1:
@:privateAccess psys.r.particle_size;
case 2:
@:privateAccess psys.r.frame_start;
case 3:
@:privateAccess psys.r.frame_end;
case 4:
@:privateAccess psys.lifetime;
case 5:
@:privateAccess psys.r.lifetime;
case 6:
@:privateAccess psys.r.emit_from;
case 7:
@:privateAccess psys.r.auto_start;
case 8:
@:privateAccess psys.r.is_unique;
case 9:
@:privateAccess psys.r.loop;
case 10:
new iron.math.Vec3(@:privateAccess psys.alignx, @:privateAccess psys.aligny, @:privateAccess psys.alignz);
case 11:
@:privateAccess psys.r.factor_random;
case 12:
new iron.math.Vec3(@:privateAccess psys.gx, @:privateAccess psys.gy, @:privateAccess psys.gz);
case 13:
@:privateAccess psys.r.weight_gravity;
case 14:
psys.speed;
case 15:
@:privateAccess psys.time;
case 16:
@:privateAccess psys.lap;
case 17:
@:privateAccess psys.lapTime;
case 18:
@:privateAccess psys.count;
default:
null;
}
#end
return null;
}
}

View File

@ -1,38 +0,0 @@
package leenkx.logicnode;
import iron.object.Object;
class GetParticleNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var object: Object = inputs[0].get();
if (object == null) return null;
#if lnx_particles
var mo = cast(object, iron.object.MeshObject);
switch (from) {
case 0:
var names: Array<String> = [];
if (mo.particleSystems != null)
for (psys in mo.particleSystems)
names.push(@:privateAccess psys.r.name);
return names;
case 1:
return mo.particleSystems != null ? mo.particleSystems.length : 0;
case 2:
return mo.render_emitter;
default:
null;
}
#end
return null;
}
}

View File

@ -1,33 +0,0 @@
package leenkx.logicnode;
#if lnx_audio
import iron.object.SpeakerObject;
import kha.audio1.AudioChannel;
#end
class GetPositionSpeakerNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
#if lnx_audio
var object: SpeakerObject = cast(inputs[0].get(), SpeakerObject);
if (object == null || object.sound == null) return 0.0;
if (object.channels.length == 0) return 0.0;
var channel = object.channels[0];
var position = 0.0;
if (channel != null) {
position = @:privateAccess channel.get_position();
}
return position;
#else
return 0.0;
#end
}
}

View File

@ -1,12 +1,26 @@
package leenkx.logicnode;
import iron.object.Object;
import iron.math.Vec4;
class GetWorldNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
return iron.Scene.active.raw.world_ref;
var object: Object = inputs[0].get();
if (object == null) return null;
return switch (property0) {
case "Right": object.transform.world.right();
case "Look": object.transform.world.look();
case "Up": object.transform.world.up();
default: null;
}
}
}
}

View File

@ -1,26 +0,0 @@
package leenkx.logicnode;
import iron.object.Object;
import iron.math.Vec4;
class GetWorldOrientationNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var object: Object = inputs[0].get();
if (object == null) return null;
return switch (property0) {
case "Right": object.transform.world.right();
case "Look": object.transform.world.look();
case "Up": object.transform.world.up();
default: null;
}
}
}

View File

@ -1,7 +1,7 @@
package leenkx.logicnode;
#if lnx_physics
import leenkx.trait.physics.PhysicsWorld;
import leenkx.trait.physics.bullet.PhysicsWorld;
#end
import leenkx.trait.navigation.Navigation;
import iron.object.Object;

View File

@ -1,233 +0,0 @@
package leenkx.logicnode;
import iron.math.Vec4;
import iron.system.Input;
import iron.object.Object;
import kha.System;
import kha.FastFloat;
/**
* MouseLookNode - FPS-style mouse look camera controller
*
* This node provides smooth, resolution-independent mouse look functionality for
* first-person perspective controls. It supports separate body and head objects,
* allowing for realistic FPS camera movement where the body rotates horizontally
* and the head/camera rotates vertically.
*
* Key Features:
* - Resolution-adaptive scaling for consistent feel across different screen sizes
* - Configurable axis orientations (X, Y, Z as front)
* - Optional mouse cursor locking and hiding
* - Invertible X/Y axes
* - Rotation capping/limiting for both horizontal and vertical movement
* - Smoothing support for smoother camera movement
* - Physics integration with automatic rigid body synchronization
* - Support for both local and world space head rotation
*/
class MouseLookNode extends LogicNode {
// Configuration properties (set from Blender node interface)
public var property0: String; // Front axis: "X", "Y", or "Z"
public var property1: Bool; // Hide Locked: auto-lock mouse cursor
public var property2: Bool; // Invert X: invert horizontal mouse movement
public var property3: Bool; // Invert Y: invert vertical mouse movement
public var property4: Bool; // Cap Left/Right: limit horizontal rotation
public var property5: Bool; // Cap Up/Down: limit vertical rotation
public var property6: Bool; // Head Local Space: use local space for head rotation
// Smoothing state variables - maintain previous frame values for interpolation
var smoothX: Float = 0.0; // Smoothed horizontal mouse delta
var smoothY: Float = 0.0; // Smoothed vertical mouse delta
// Rotation limits (in radians)
var maxHorizontal: Float = Math.PI; // Maximum horizontal rotation (180 degrees)
var maxVertical: Float = Math.PI / 2; // Maximum vertical rotation (90 degrees)
// Current rotation tracking for capping calculations
var currentHorizontal: Float = 0.0; // Accumulated horizontal rotation
var currentVertical: Float = 0.0; // Accumulated vertical rotation
// Resolution scaling reference - base resolution for consistent sensitivity
var baseResolutionWidth: Float = 1920.0;
// Sensitivity scaling constants
static inline var BASE_SCALE: Float = 1500.0; // Base sensitivity scale factor
static var RADIAN_SCALING_FACTOR: Float = Math.PI * 50.0 / 180.0; // Degrees to radians conversion with sensitivity scaling
public function new(tree: LogicTree) {
super(tree);
}
/**
* Main execution function called every frame when the node is active
*
* Input connections:
* [0] - Action trigger (not used in current implementation)
* [1] - Body Object: the main object that rotates horizontally
* [2] - Head Object: optional object that rotates vertically (typically camera)
* [3] - Sensitivity: mouse sensitivity multiplier
* [4] - Smoothing: movement smoothing factor (0.0 = no smoothing, 0.99 = maximum smoothing)
*/
override function run(from: Int) {
// Get input values from connected nodes
var bodyObject: Object = inputs[1].get();
var headObject: Object = inputs[2].get();
var sensitivity: FastFloat = inputs[3].get();
var smoothing: FastFloat = inputs[4].get();
// Early exit if no body object is provided
if (bodyObject == null) {
runOutput(0);
return;
}
// Get mouse input state
var mouse = Input.getMouse();
// Handle automatic mouse cursor locking for FPS controls
if (property1) {
if (mouse.started() && !mouse.locked) {
mouse.lock(); // Center and hide cursor, enable unlimited movement
}
}
// Only process mouse look when cursor is locked or mouse button is held
// This prevents unwanted camera movement when UI elements are being used
if (!mouse.locked && !mouse.down()) {
runOutput(0);
return;
}
// Get raw mouse movement delta (pixels moved since last frame)
var deltaX: Float = mouse.movementX;
var deltaY: Float = mouse.movementY;
// Apply axis inversion if configured
if (property2) deltaX = -deltaX; // Invert horizontal movement
if (property3) deltaY = -deltaY; // Invert vertical movement
// Calculate resolution-adaptive scaling to maintain consistent sensitivity
// across different screen resolutions. Higher resolutions will have proportionally
// higher scaling to compensate for increased pixel density.
var resolutionMultiplier: Float = System.windowWidth() / baseResolutionWidth;
// Apply movement smoothing if enabled
// This creates a weighted average between current and previous movement values
// to reduce jittery camera movement, especially useful for low framerates
if (smoothing > 0.0) {
var smoothingFactor: Float = Math.min(smoothing, 0.99); // Cap smoothing to prevent complete freeze
smoothX = smoothX * smoothingFactor + deltaX * (1.0 - smoothingFactor);
smoothY = smoothY * smoothingFactor + deltaY * (1.0 - smoothingFactor);
deltaX = smoothX;
deltaY = smoothY;
}
// Define rotation axes based on the configured front axis
// These determine which 3D axes are used for horizontal and vertical rotation
var horizontalAxis = new Vec4(); // Axis for left/right body rotation
var verticalAxis = new Vec4(); // Axis for up/down head rotation
switch (property0) {
case "X": // X-axis forward (e.g., for side-scrolling or specific orientations)
horizontalAxis.set(0, 0, 1); // Z-axis for horizontal rotation
verticalAxis.set(0, 1, 0); // Y-axis for vertical rotation
case "Y": // Y-axis forward (most common for 3D games)
#if lnx_yaxisup
// Y-up coordinate system (Blender default)
horizontalAxis.set(0, 0, 1); // Z-axis for horizontal rotation
verticalAxis.set(1, 0, 0); // X-axis for vertical rotation
#else
// Z-up coordinate system
horizontalAxis.set(0, 0, 1); // Z-axis for horizontal rotation
verticalAxis.set(1, 0, 0); // X-axis for vertical rotation
#end
case "Z": // Z-axis forward (top-down or specific orientations)
horizontalAxis.set(0, 1, 0); // Y-axis for horizontal rotation
verticalAxis.set(1, 0, 0); // X-axis for vertical rotation
}
// Calculate final sensitivity scaling combining base scale and resolution adaptation
var finalScale: Float = BASE_SCALE * resolutionMultiplier;
// Apply user-defined sensitivity multiplier
deltaX *= sensitivity;
deltaY *= sensitivity;
// Convert pixel movement to rotation angles (radians)
// Negative values ensure natural movement direction (moving mouse right rotates right)
var horizontalRotation: Float = (-deltaX / finalScale) * RADIAN_SCALING_FACTOR;
var verticalRotation: Float = (-deltaY / finalScale) * RADIAN_SCALING_FACTOR;
// Apply horizontal rotation capping if enabled
// This prevents the character from rotating beyond specified limits
if (property4) {
currentHorizontal += horizontalRotation;
// Clamp rotation to maximum horizontal range and adjust current frame rotation
if (currentHorizontal > maxHorizontal) {
horizontalRotation -= (currentHorizontal - maxHorizontal);
currentHorizontal = maxHorizontal;
} else if (currentHorizontal < -maxHorizontal) {
horizontalRotation -= (currentHorizontal + maxHorizontal);
currentHorizontal = -maxHorizontal;
}
}
// Apply vertical rotation capping if enabled
// This prevents looking too far up or down (like human neck limitations)
if (property5) {
currentVertical += verticalRotation;
// Clamp rotation to maximum vertical range and adjust current frame rotation
if (currentVertical > maxVertical) {
verticalRotation -= (currentVertical - maxVertical);
currentVertical = maxVertical;
} else if (currentVertical < -maxVertical) {
verticalRotation -= (currentVertical + maxVertical);
currentVertical = -maxVertical;
}
}
// Apply horizontal rotation to body object (character turning left/right)
if (horizontalRotation != 0.0) {
bodyObject.transform.rotate(horizontalAxis, horizontalRotation);
// Synchronize physics rigid body if present
// This ensures physics simulation stays in sync with visual transform
#if lnx_physics
var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
if (rigidBody != null) rigidBody.syncTransform();
#end
}
// Apply vertical rotation to head object (camera looking up/down)
if (headObject != null && verticalRotation != 0.0) {
if (property6) {
// Local space rotation - recommended when head is a child of body
// This prevents gimbal lock and rotation inheritance issues
headObject.transform.rotate(verticalAxis, verticalRotation);
} else {
// World space rotation - uses head object's current right vector
// More accurate for independent head objects but can cause issues with parenting
var headVerticalAxis = headObject.transform.world.right();
headObject.transform.rotate(headVerticalAxis, verticalRotation);
}
// Synchronize head physics rigid body if present
#if lnx_physics
var headRigidBody = headObject.getTrait(leenkx.trait.physics.RigidBody);
if (headRigidBody != null) headRigidBody.syncTransform();
#end
} else if (headObject == null && verticalRotation != 0.0) {
// Fallback: if no separate head object, apply vertical rotation to body
// This creates a simpler single-object camera control
bodyObject.transform.rotate(verticalAxis, verticalRotation);
// Synchronize body physics rigid body
#if lnx_physics
var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
if (rigidBody != null) rigidBody.syncTransform();
#end
}
// Continue to next connected node in the logic tree
runOutput(0);
}
}

View File

@ -1,23 +0,0 @@
package leenkx.logicnode;
class OnceNode extends LogicNode {
var triggered:Bool = false;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
if(from == 1){
triggered = false;
return;
}
if (!triggered) {
triggered = true;
runOutput(0);
}
}
}

View File

@ -1,7 +1,7 @@
package leenkx.logicnode;
#if lnx_physics
import leenkx.trait.physics.PhysicsConstraint.ConstraintAxis;
import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintAxis;
#end
class PhysicsConstraintNode extends LogicNode {

View File

@ -9,38 +9,19 @@ import iron.Scene;
class PlayAnimationTreeNode extends LogicNode {
var object: Object;
var action: Dynamic;
var init: Bool = false;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
object = inputs[1].get();
action = inputs[2].get();
var object: Object = inputs[1].get();
var action: Dynamic = inputs[2].get();
assert(Error, object != null, "The object input not be null");
init = true;
tree.notifyOnUpdate(playAnim);
// TO DO: Investigate AnimAction get and PlayAnimationTree notifiers
}
function playAnim() {
if (init = false) return;
init = false;
tree.removeUpdate(playAnim);
var animation = object.animation;
if(animation == null) {
#if lnx_skin
animation = object.getBoneAnimation(object.uid);
if (animation == null) {
tree.notifyOnUpdate(playAnim);
init = true;
return;
}
cast(animation, BoneAnimation).setAnimationLoop(function f(mats) {
action(mats);
});
@ -51,6 +32,7 @@ class PlayAnimationTreeNode extends LogicNode {
action(mats);
});
}
runOutput(0);
}
}

View File

@ -18,6 +18,7 @@ class ProbabilisticOutputNode extends LogicNode {
}
if (sum > 1){
trace(sum);
for (p in 0...probs.length)
probs[p] /= sum;
}

View File

@ -1,64 +0,0 @@
package leenkx.logicnode;
import iron.object.Object;
class RemoveParticleFromObjectNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
#if lnx_particles
var object: Object = inputs[1].get();
if (object == null) return;
var mo = cast(object, iron.object.MeshObject);
if (mo.particleSystems == null) return;
if (property0 == 'All'){
mo.particleSystems = null;
for (c in mo.particleChildren) c.remove();
mo.particleChildren = null;
mo.particleOwner = null;
mo.render_emitter = true;
}
else {
var slot: Int = -1;
if (property0 == 'Name'){
var name: String = inputs[2].get();
for (i => psys in mo.particleSystems){
if (@:privateAccess psys.r.name == name){ slot = i; break; }
}
}
else slot = inputs[2].get();
if (mo.particleSystems.length > slot){
for (i in slot+1...mo.particleSystems.length){
var mi = cast(mo.particleChildren[i], iron.object.MeshObject);
mi.particleIndex = mi.particleIndex - 1;
}
mo.particleSystems.splice(slot, 1);
mo.particleChildren[slot].remove();
mo.particleChildren.splice(slot, 1);
}
if (slot == 0){
mo.particleSystems = null;
mo.particleChildren = null;
mo.particleOwner = null;
mo.render_emitter = true;
}
}
#end
runOutput(0);
}
}

View File

@ -1,16 +0,0 @@
package leenkx.logicnode;
class ResolutionGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
return switch (from) {
case 0: leenkx.renderpath.Postprocess.resolution_uniforms[0];
case 1: leenkx.renderpath.Postprocess.resolution_uniforms[1];
default: 0;
}
}
}

View File

@ -1,33 +0,0 @@
package leenkx.logicnode;
import kha.graphics4.TextureFilter;
class ResolutionSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
var size: Int = inputs[1].get();
var filter: Int = inputs[2].get();
#if rp_resolution_filter
if (filter == 0)
iron.object.Uniforms.defaultFilter = TextureFilter.LinearFilter;
else
iron.object.Uniforms.defaultFilter = TextureFilter.PointFilter;
leenkx.renderpath.Postprocess.resolution_uniforms[0] = size;
leenkx.renderpath.Postprocess.resolution_uniforms[1] = filter;
var npath = leenkx.renderpath.RenderPathCreator.get();
var world = iron.Scene.active.raw.world_ref;
npath.loadShader("shader_datas/World_" + world + "/World_" + world);
iron.RenderPath.setActive(npath);
#end
runOutput(0);
}
}

View File

@ -20,8 +20,6 @@ class RpConfigNode extends LogicNode {
on ? leenkx.data.Config.raw.rp_ssrefr = true : leenkx.data.Config.raw.rp_ssrefr = false;
case "Bloom":
on ? leenkx.data.Config.raw.rp_bloom = true : leenkx.data.Config.raw.rp_bloom = false;
case "CA":
on ? leenkx.data.Config.raw.rp_chromatic_aberration = true : leenkx.data.Config.raw.rp_chromatic_aberration = false;
case "GI":
on ? leenkx.data.Config.raw.rp_gi = true : leenkx.data.Config.raw.rp_gi = false;
case "Motion Blur":

View File

@ -1,23 +0,0 @@
package leenkx.logicnode;
import aura.Aura;
import aura.Types;
class SetAudioPositionNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
var audio = inputs[1].get();
if (audio == null) return;
var positionInSeconds:Float = inputs[2].get();
if (positionInSeconds < 0.0) positionInSeconds = 0.0;
audio.channel.floatPosition = positionInSeconds * audio.channel.sampleRate;
runOutput(0);
}
}

View File

@ -1,38 +0,0 @@
package leenkx.logicnode;
import iron.object.MeshObject;
import iron.object.CameraObject;
class SetCameraRenderFilterNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
var mo: MeshObject = cast inputs[1].get();
var camera: CameraObject = inputs[2].get();
assert(Error, Std.isOfType(camera, CameraObject), "Camera must be a camera object!");
if (camera == null || mo == null) return;
if (property0 == 'Add'){
if (mo.cameraList == null || mo.cameraList.indexOf(camera.name) == -1){
if (mo.cameraList == null) mo.cameraList = [];
mo.cameraList.push(camera.name);
}
}
else{
if (mo.cameraList != null){
mo.cameraList.remove(camera.name);
if (mo.cameraList.length == 0)
mo.cameraList = null;
}
}
runOutput(0);
}
}

View File

@ -1,21 +0,0 @@
package leenkx.logicnode;
import iron.object.LightObject;
class SetLightShadowNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
var light: LightObject = inputs[1].get();
var shadow: Bool = inputs[2].get();
if (light == null) return;
light.data.raw.cast_shadow = shadow;
runOutput(0);
}
}

View File

@ -1,206 +0,0 @@
package leenkx.logicnode;
import iron.math.Vec4;
import iron.math.Quat;
import iron.math.Mat4;
import iron.object.Object;
class SetLookAtRotationNode extends LogicNode {
public var property0: String; // Axis to align
public var property1: String; // Use vector for target (true/false)
public var property2: String; // Use vector for source (true/false)
public var property3: String; // Damping value (backward compatibility, now input socket)
public var property4: String; // Disable rotation on aligning axis (true/false)
public var property5: String; // Use local space (true/false)
// Store the calculated rotation for output
var calculatedRotation: Quat = null;
// Store the previous rotation for smooth interpolation
var previousRotation: Quat = null;
public function new(tree: LogicTree) {
super(tree);
previousRotation = new Quat();
}
override function run(from: Int): Void {
// Determine if we're using a vector or an object as source
var useSourceVector: Bool = property2 == "true";
var objectToUse: Object = null;
var objectLoc: Vec4 = null;
if (useSourceVector) {
// Use tree.object as the object to rotate
objectToUse = tree.object;
if (objectToUse == null) {
runOutput(0);
return;
}
// Get the source location directly
objectLoc = inputs[1].get();
if (objectLoc == null) {
runOutput(0);
return;
}
} else {
// Get the source object (or fallback to tree.object)
objectToUse = (inputs.length > 1 && inputs[1] != null) ? inputs[1].get() : tree.object;
if (objectToUse == null) {
runOutput(0);
return;
}
// Get source object's WORLD position (important for child objects)
objectLoc = new Vec4(objectToUse.transform.worldx(), objectToUse.transform.worldy(), objectToUse.transform.worldz());
}
// Determine if we're using a vector or an object as target
var useTargetVector: Bool = property1 == "true";
var targetLoc: Vec4 = null;
if (useTargetVector) {
// Get the target location directly
targetLoc = inputs[2].get();
if (targetLoc == null) {
runOutput(0);
return;
}
} else {
// Get the target object
var targetObject: Object = inputs[2].get();
if (targetObject == null) {
runOutput(0);
return;
}
// Get target object's WORLD position (important for child objects)
targetLoc = new Vec4(targetObject.transform.worldx(), targetObject.transform.worldy(), targetObject.transform.worldz());
}
// Calculate direction to target
var direction = new Vec4(
targetLoc.x - objectLoc.x,
targetLoc.y - objectLoc.y,
targetLoc.z - objectLoc.z
);
direction.normalize();
// Calculate target rotation based on selected axis
calculatedRotation = new Quat();
switch (property0) {
case "X":
calculatedRotation.fromTo(new Vec4(1, 0, 0), direction);
case "-X":
calculatedRotation.fromTo(new Vec4(-1, 0, 0), direction);
case "Y":
calculatedRotation.fromTo(new Vec4(0, 1, 0), direction);
case "-Y":
calculatedRotation.fromTo(new Vec4(0, -1, 0), direction);
case "Z":
calculatedRotation.fromTo(new Vec4(0, 0, 1), direction);
case "-Z":
calculatedRotation.fromTo(new Vec4(0, 0, -1), direction);
}
// If disable rotation on aligning axis is enabled, constrain the target rotation
if (property4 == "true") {
// Apply constraint to the target rotation BEFORE damping to avoid jiggling
var eulerAngles = calculatedRotation.toEulerOrdered("XYZ");
// Set the rotation around the selected axis to 0
switch (property0) {
case "X", "-X":
eulerAngles.x = 0.0;
case "Y", "-Y":
eulerAngles.y = 0.0;
case "Z", "-Z":
eulerAngles.z = 0.0;
}
// Convert back to quaternion
calculatedRotation.fromEulerOrdered(eulerAngles, "XYZ");
}
// Convert world rotation to local rotation if local space is enabled and object has a parent
var targetRotation = new Quat();
if (property5 == "true" && objectToUse.parent != null) {
// Get parent's world rotation
var parentWorldLoc = new Vec4();
var parentWorldRot = new Quat();
var parentWorldScale = new Vec4();
objectToUse.parent.transform.world.decompose(parentWorldLoc, parentWorldRot, parentWorldScale);
// Convert world rotation to local space by removing parent's rotation influence
// local_rotation = inverse(parent_world_rotation) * world_rotation
var invParentRot = new Quat().setFrom(parentWorldRot);
invParentRot.x = -invParentRot.x;
invParentRot.y = -invParentRot.y;
invParentRot.z = -invParentRot.z;
targetRotation.multquats(invParentRot, calculatedRotation);
} else {
// No local space conversion needed, use world rotation directly
targetRotation.setFrom(calculatedRotation);
}
// Apply rotation with damping
var dampingValue: Float = 0.0;
// Try to get damping from input socket first (index 3), fallback to property
if (inputs.length > 3 && inputs[3] != null) {
var dampingInput: Dynamic = inputs[3].get();
if (dampingInput != null) {
dampingValue = dampingInput;
}
} else {
// Fallback to property for backward compatibility
dampingValue = Std.parseFloat(property3);
}
if (dampingValue > 0.0) {
// Create a fixed interpolation rate that never reaches exactly 1.0
// Higher damping = slower rotation (smaller step)
var step = Math.max(0.001, (1.0 - dampingValue) * 0.2); // 0.001 to 0.2 range
// Get current local rotation as quaternion
var currentLocalRot = new Quat().setFrom(objectToUse.transform.rot);
// Calculate the difference between current and target rotation
var diffQuat = new Quat();
// q1 * inverse(q2) gives the rotation from q2 to q1
var invCurrent = new Quat().setFrom(currentLocalRot);
invCurrent.x = -invCurrent.x;
invCurrent.y = -invCurrent.y;
invCurrent.z = -invCurrent.z;
diffQuat.multquats(targetRotation, invCurrent);
// Convert to axis-angle representation
var axis = new Vec4();
var angle = diffQuat.toAxisAngle(axis);
// Apply only a portion of this rotation (step)
var partialAngle = angle * step;
// Create partial rotation quaternion
var partialRot = new Quat().fromAxisAngle(axis, partialAngle);
// Apply this partial rotation to current local rotation
var newLocalRot = new Quat();
newLocalRot.multquats(partialRot, currentLocalRot);
// Apply the new local rotation
objectToUse.transform.rot.setFrom(newLocalRot);
} else {
// No damping, apply instant rotation
objectToUse.transform.rot.setFrom(targetRotation);
}
objectToUse.transform.buildMatrix();
runOutput(0);
}
// No output sockets needed - this node only performs actions
}

View File

@ -1,55 +0,0 @@
package leenkx.logicnode;
import iron.object.MeshObject;
import iron.data.MaterialData;
class SetMaterialTextureFilterNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
var object: MeshObject = inputs[1].get();
var mat: MaterialData = inputs[2].get();
var slot: Int = inputs[3].get();
var name: String = inputs[4].get();
var filter: Int = inputs[5].get();
if (object == null) return;
if (slot >= object.materials.length) return;
var mo = cast(object, iron.object.MeshObject);
for (i => node in mo.materials[slot].contexts[0].raw.bind_textures)
if (node.name == name){
var moImgt = mo.materials[slot].contexts[0].raw.bind_textures[i];
switch(filter){
case 0: //Linear
moImgt.min_filter = null;
moImgt.mag_filter = null;
moImgt.mipmap_filter = null;
moImgt.generate_mipmaps = null;
case 1: //Closest
moImgt.min_filter = 'point';
moImgt.mag_filter = 'point';
moImgt.mipmap_filter = null;
moImgt.generate_mipmaps = null;
case 2: //Cubic
moImgt.min_filter = null;
moImgt.mag_filter = null;
moImgt.mipmap_filter = 'linear';
moImgt.generate_mipmaps = true;
case 3: //Smart
moImgt.min_filter = 'anisotropic';
moImgt.mag_filter = null;
moImgt.mipmap_filter = 'linear';
moImgt.generate_mipmaps = true;
}
break;
}
runOutput(0);
}
}

View File

@ -1,74 +0,0 @@
package leenkx.logicnode;
import iron.object.Object;
import iron.math.Vec4;
import iron.math.Mat4;
import iron.system.Time;
class SetObjectDelayedLocationNode extends LogicNode {
public var use_local_space: Bool = false;
private var initialOffset: Vec4 = null;
private var targetPos: Vec4 = new Vec4();
private var currentPos: Vec4 = new Vec4();
private var deltaVec: Vec4 = new Vec4();
private var tempVec: Vec4 = new Vec4();
private var lastParent: Object = null;
private var invParentMatrix: Mat4 = null;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
var follower: Object = inputs[1].get();
var target: Object = inputs[2].get();
var delay: Float = inputs[3].get();
if (follower == null || target == null) return runOutput(0);
if (initialOffset == null) {
initialOffset = new Vec4();
var followerPos = follower.transform.world.getLoc();
var targetPos = target.transform.world.getLoc();
initialOffset.setFrom(followerPos);
initialOffset.sub(targetPos);
}
targetPos.setFrom(target.transform.world.getLoc());
currentPos.setFrom(follower.transform.world.getLoc());
tempVec.setFrom(targetPos).add(initialOffset);
deltaVec.setFrom(tempVec).sub(currentPos);
if (deltaVec.length() < 0.001 && delay < 0.01) {
runOutput(0);
return;
}
if (delay == 0.0) {
currentPos.setFrom(tempVec);
} else {
var smoothFactor = Math.exp(-Time.delta / Math.max(0.0001, delay));
currentPos.x = tempVec.x + (currentPos.x - tempVec.x) * smoothFactor;
currentPos.y = tempVec.y + (currentPos.y - tempVec.y) * smoothFactor;
currentPos.z = tempVec.z + (currentPos.z - tempVec.z) * smoothFactor;
}
if (use_local_space && follower.parent != null) {
if (follower.parent != lastParent || invParentMatrix == null) {
lastParent = follower.parent;
invParentMatrix = Mat4.identity();
invParentMatrix.getInverse(follower.parent.transform.world);
}
tempVec.setFrom(currentPos);
tempVec.applymat(invParentMatrix);
follower.transform.loc.set(tempVec.x, tempVec.y, tempVec.z);
} else {
follower.transform.loc.set(currentPos.x, currentPos.y, currentPos.z);
}
follower.transform.buildMatrix();
runOutput(0);
}
}

View File

@ -1,81 +0,0 @@
package leenkx.logicnode;
import iron.object.Object;
class SetParticleDataNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
#if lnx_particles
var object: Object = inputs[1].get();
var slot: Int = inputs[2].get();
if (object == null) return;
var mo = cast(object, iron.object.MeshObject);
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null; if (psys == null) return;
switch (property0) {
case 'Particle Size':
@:privateAccess psys.r.particle_size = inputs[3].get();
case 'Frame Start':
@:privateAccess psys.r.frame_start = inputs[3].get();
@:privateAccess psys.animtime = (@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.frameRate;
@:privateAccess psys.spawnRate = ((@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.count) / @:privateAccess psys.frameRate;
case 'Frame End':
@:privateAccess psys.r.frame_end = inputs[3].get();
@:privateAccess psys.animtime = (@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.frameRate;
@:privateAccess psys.spawnRate = ((@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.count) / @:privateAccess psys.frameRate;
case 'Lifetime':
@:privateAccess psys.lifetime = inputs[3].get() / @:privateAccess psys.frameRate;
case 'Lifetime Random':
@:privateAccess psys.r.lifetime_random = inputs[3].get();
case 'Emit From':
var emit_from: Int = inputs[3].get();
if (emit_from == 0 || emit_from == 1 || emit_from == 2) {
@:privateAccess psys.r.emit_from = emit_from;
@:privateAccess psys.setupGeomGpu(mo.particleChildren != null ? mo.particleChildren[slot] : cast(iron.Scene.active.getChild(@:privateAccess psys.data.raw.instance_object), iron.object.MeshObject), mo);
}
case 'Auto Start':
@:privateAccess psys.r.auto_start = inputs[3].get();
case 'Is Unique':
@:privateAccess psys.r.is_unique = inputs[3].get();
case 'Loop':
@:privateAccess psys.r.loop = inputs[3].get();
case 'Velocity':
var vel: iron.math.Vec3 = inputs[3].get();
@:privateAccess psys.alignx = vel.x;
@:privateAccess psys.aligny = vel.y;
@:privateAccess psys.alignz = vel.z;
case 'Velocity Random':
@:privateAccess psys.r.factor_random = inputs[3].get();
case 'Weight Gravity':
@:privateAccess psys.r.weight_gravity = inputs[3].get();
if (iron.Scene.active.raw.gravity != null) {
@:privateAccess psys.gx = iron.Scene.active.raw.gravity[0] * @:privateAccess psys.r.weight_gravity;
@:privateAccess psys.gy = iron.Scene.active.raw.gravity[1] * @:privateAccess psys.r.weight_gravity;
@:privateAccess psys.gz = iron.Scene.active.raw.gravity[2] * @:privateAccess psys.r.weight_gravity;
}
else {
@:privateAccess psys.gx = 0;
@:privateAccess psys.gy = 0;
@:privateAccess psys.gz = -9.81 * @:privateAccess psys.r.weight_gravity;
}
case 'Speed':
psys.speed = inputs[3].get();
default:
null;
}
#end
runOutput(0);
}
}

View File

@ -1,23 +0,0 @@
package leenkx.logicnode;
import iron.object.Object;
class SetParticleRenderEmitterNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
#if lnx_particles
var object: Object = inputs[1].get();
if (object == null) return;
cast(object, iron.object.MeshObject).render_emitter = inputs[2].get();
#end
runOutput(0);
}
}

View File

@ -11,16 +11,13 @@ class SetParticleSpeedNode extends LogicNode {
override function run(from: Int) {
#if lnx_particles
var object: Object = inputs[1].get();
var slot: Int = inputs[2].get();
var speed: Float = inputs[3].get();
var speed: Float = inputs[2].get();
if (object == null) return;
var mo = cast(object, iron.object.MeshObject);
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;
if (psys == null) return;
var psys = mo.particleSystems.length > 0 ? mo.particleSystems[0] : null;
if (psys == null) mo.particleOwner.particleSystems[0];
psys.speed = speed;

View File

@ -1,39 +0,0 @@
package leenkx.logicnode;
#if lnx_audio
import iron.object.SpeakerObject;
import kha.audio1.AudioChannel;
import iron.system.Audio;
#end
class SetPositionSpeakerNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
#if lnx_audio
var object: SpeakerObject = cast(inputs[1].get(), SpeakerObject);
if (object == null || object.sound == null) return;
var positionInSeconds:Float = inputs[2].get();
if (positionInSeconds < 0) positionInSeconds = 0;
var volume = object.data.volume;
var loop = object.data.loop;
var stream = object.data.stream;
object.stop();
var channel = Audio.play(object.sound, loop, stream);
if (channel != null) {
object.channels.push(channel);
channel.volume = volume;
@:privateAccess channel.set_position(positionInSeconds);
}
#end
runOutput(0);
}
}

View File

@ -1,40 +0,0 @@
package leenkx.logicnode;
class SetWorldNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
var world: String = inputs[1].get();
if (world != null){
//check if world shader data exists
var file: String = 'World_'+world+'_data';
#if lnx_json
file += ".json";
#elseif lnx_compress
file += ".lz4";
#else
file += '.lnx';
#end
var exists: Bool = false;
iron.data.Data.getBlob(file, function(b: kha.Blob) {
if (b != null) exists = true;
});
assert(Error, exists == true, "World must be either associated to a scene or have fake user");
iron.Scene.active.raw.world_ref = world;
var npath = leenkx.renderpath.RenderPathCreator.get();
npath.loadShader("shader_datas/World_" + world + "/World_" + world);
iron.RenderPath.setActive(npath);
}
runOutput(0);
}
}

View File

@ -1,17 +0,0 @@
package leenkx.logicnode;
class SharpenGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
return switch (from) {
case 0: leenkx.renderpath.Postprocess.sharpen_uniforms[0];
case 1: leenkx.renderpath.Postprocess.sharpen_uniforms[1][0];
case 2: leenkx.renderpath.Postprocess.camera_uniforms[12];
default: 0.0;
}
}
}

Some files were not shown because too many files have changed in this diff Show More